FD.io VPP  v20.01-48-g3e0dafb74
Vector Packet Processing
ip6_forward.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16  * ip/ip6_forward.c: IP v6 forwarding
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39 
40 #include <vnet/vnet.h>
41 #include <vnet/ip/ip.h>
42 #include <vnet/ip/ip_frag.h>
43 #include <vnet/ip/ip6_link.h>
44 #include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
45 #include <vnet/srp/srp.h> /* for srp_hw_interface_class */
46 #include <vppinfra/cache.h>
47 #include <vnet/fib/fib_urpf_list.h> /* for FIB uRPF check */
48 #include <vnet/fib/ip6_fib.h>
49 #include <vnet/mfib/ip6_mfib.h>
51 #include <vnet/dpo/classify_dpo.h>
53 
54 #ifndef CLIB_MARCH_VARIANT
56 #endif
57 #include <vnet/ip/ip6_forward.h>
58 #include <vnet/interface_output.h>
59 
60 /* Flag used by IOAM code. Classifier sets it pop-hop-by-hop checks it */
61 #define OI_DECAP 0x80000000
62 
63 static void
66  u32 fib_index,
67  ip6_address_t * address, u32 address_length)
68 {
69  ip_lookup_main_t *lm = &im->lookup_main;
70  ip_interface_prefix_t *if_prefix;
71 
72  /* *INDENT-OFF* */
74  .prefix = {
75  .fp_len = address_length,
76  .fp_proto = FIB_PROTOCOL_IP6,
77  .fp_addr.ip6 = {
78  .as_u64 = {
79  address->as_u64[0] & im->fib_masks[address_length].as_u64[0],
80  address->as_u64[1] & im->fib_masks[address_length].as_u64[1],
81  },
82  },
83  },
84  .sw_if_index = sw_if_index,
85  };
86  /* *INDENT-ON* */
87 
88  /* If prefix already set on interface, just increment ref count & return */
89  if_prefix = ip_get_interface_prefix (lm, &key);
90  if (if_prefix)
91  {
92  if_prefix->ref_count += 1;
93  return;
94  }
95 
96  /* New prefix - allocate a pool entry, initialize it, add to the hash */
97  pool_get (lm->if_prefix_pool, if_prefix);
98  if_prefix->ref_count = 1;
99  clib_memcpy (&if_prefix->key, &key, sizeof (key));
101  if_prefix - lm->if_prefix_pool, 0 /* old value */ );
102 
103  /* length < 128 - add glean */
104  if (address_length < 128)
105  {
106  /* set the glean route for the prefix */
107  fib_table_entry_update_one_path (fib_index, &key.prefix,
112  /* No next-hop address */
113  NULL, sw_if_index,
114  /* invalid FIB index */
115  ~0, 1,
116  /* no out-label stack */
118  }
119 }
120 
121 static void
123  ip6_main_t * im, u32 fib_index,
125 {
126  ip_lookup_main_t *lm = &im->lookup_main;
128  fib_prefix_t pfx = {
129  .fp_len = a->address_length,
130  .fp_proto = FIB_PROTOCOL_IP6,
131  .fp_addr.ip6 = *address,
132  };
133 
134  /* set special routes for the prefix if needed */
135  ip6_add_interface_prefix_routes (im, sw_if_index, fib_index,
136  address, a->address_length);
137 
138  pfx.fp_len = 128;
139  if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
140  {
143  if (classify_table_index != (u32) ~ 0)
144  {
145  dpo_id_t dpo = DPO_INVALID;
146 
147  dpo_set (&dpo,
148  DPO_CLASSIFY,
150  classify_dpo_create (DPO_PROTO_IP6, classify_table_index));
151 
153  &pfx,
155  FIB_ENTRY_FLAG_NONE, &dpo);
156  dpo_reset (&dpo);
157  }
158  }
159 
160  fib_table_entry_update_one_path (fib_index, &pfx,
165  &pfx.fp_addr,
166  sw_if_index, ~0,
168 }
169 
170 static void
173  u32 fib_index,
174  ip6_address_t * address, u32 address_length)
175 {
176  ip_lookup_main_t *lm = &im->lookup_main;
177  ip_interface_prefix_t *if_prefix;
178 
179  /* *INDENT-OFF* */
181  .prefix = {
182  .fp_len = address_length,
183  .fp_proto = FIB_PROTOCOL_IP6,
184  .fp_addr.ip6 = {
185  .as_u64 = {
186  address->as_u64[0] & im->fib_masks[address_length].as_u64[0],
187  address->as_u64[1] & im->fib_masks[address_length].as_u64[1],
188  },
189  },
190  },
191  .sw_if_index = sw_if_index,
192  };
193  /* *INDENT-ON* */
194 
195  if_prefix = ip_get_interface_prefix (lm, &key);
196  if (!if_prefix)
197  {
198  clib_warning ("Prefix not found while deleting %U",
199  format_ip4_address_and_length, address, address_length);
200  return;
201  }
202 
203  /* If not deleting last intf addr in prefix, decrement ref count & return */
204  if_prefix->ref_count -= 1;
205  if (if_prefix->ref_count > 0)
206  return;
207 
208  /* length <= 128, delete glean route */
209  if (address_length <= 128)
210  {
211  /* remove glean route for prefix */
213  }
214 
215  mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */ );
216  pool_put (lm->if_prefix_pool, if_prefix);
217 }
218 
219 static void
221  u32 fib_index,
222  ip6_address_t * address, u32 address_length)
223 {
224  fib_prefix_t pfx = {
225  .fp_len = 128,
226  .fp_proto = FIB_PROTOCOL_IP6,
227  .fp_addr.ip6 = *address,
228  };
229 
230  /* delete special routes for the prefix if needed */
231  ip6_del_interface_prefix_routes (im, sw_if_index, fib_index,
232  address, address_length);
233 
234  fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
235 }
236 
237 #ifndef CLIB_MARCH_VARIANT
238 void
240 {
241  ip6_main_t *im = &ip6_main;
242 
244 
245  /*
246  * enable/disable only on the 1<->0 transition
247  */
248  if (is_enable)
249  {
250  if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
251  return;
252  }
253  else
254  {
255  /* The ref count is 0 when an address is removed from an interface that has
256  * no address - this is not a ciritical error */
257  if (0 == im->ip_enabled_by_sw_if_index[sw_if_index] ||
258  0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
259  return;
260  }
261 
262  vnet_feature_enable_disable ("ip6-unicast", "ip6-not-enabled", sw_if_index,
263  !is_enable, 0, 0);
264 
265  vnet_feature_enable_disable ("ip6-multicast", "ip6-not-enabled",
266  sw_if_index, !is_enable, 0, 0);
267 }
268 
269 /* get first interface address */
272 {
273  ip_lookup_main_t *lm = &im->lookup_main;
274  ip_interface_address_t *ia = 0;
275  ip6_address_t *result = 0;
276 
277  /* *INDENT-OFF* */
278  foreach_ip_interface_address (lm, ia, sw_if_index,
279  1 /* honor unnumbered */,
280  ({
282  result = a;
283  break;
284  }));
285  /* *INDENT-ON* */
286  return result;
287 }
288 
289 clib_error_t *
293  u32 address_length, u32 is_del)
294 {
295  vnet_main_t *vnm = vnet_get_main ();
296  ip6_main_t *im = &ip6_main;
297  ip_lookup_main_t *lm = &im->lookup_main;
298  clib_error_t *error;
299  u32 if_address_index;
300  ip6_address_fib_t ip6_af, *addr_fib = 0;
301  const ip6_address_t *ll_addr;
302 
303  /* local0 interface doesn't support IP addressing */
304  if (sw_if_index == 0)
305  {
306  return
307  clib_error_create ("local0 interface doesn't support IP addressing");
308  }
309 
310  if (ip6_address_is_link_local_unicast (address))
311  {
312  if (address_length != 128)
313  {
314  vnm->api_errno = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
315  return
317  ("prefix length of link-local address must be 128");
318  }
319  if (!is_del)
320  {
321  int rv;
322 
323  rv = ip6_set_link_local_address (sw_if_index, address);
324 
325  if (rv)
326  {
327  vnm->api_errno = rv;
328  return clib_error_create ("address not assignable");
329  }
330  }
331  else
332  {
333  ll_addr = ip6_get_link_local_address (sw_if_index);
334  if (ip6_address_is_equal (ll_addr, address))
335  {
336  vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_DELETABLE;
337  return clib_error_create ("address not deletable");
338  }
339  else
340  {
341  vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
342  return clib_error_create ("address not found");
343  }
344  }
345  }
346 
347  vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
348  vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
349 
350  ip6_addr_fib_init (&ip6_af, address,
351  vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
352  vec_add1 (addr_fib, ip6_af);
353 
354  /* *INDENT-OFF* */
355  if (!is_del)
356  {
357  /* When adding an address check that it does not conflict
358  with an existing address on any interface in this table. */
360  vnet_sw_interface_t *sif;
361 
363  ({
364  if (im->fib_index_by_sw_if_index[sw_if_index] ==
365  im->fib_index_by_sw_if_index[sif->sw_if_index])
366  {
367  foreach_ip_interface_address
368  (&im->lookup_main, ia, sif->sw_if_index,
369  0 /* honor unnumbered */ ,
370  ({
371  ip6_address_t * x =
372  ip_interface_address_get_address
373  (&im->lookup_main, ia);
374  if (ip6_destination_matches_route
375  (im, address, x, ia->address_length) ||
376  ip6_destination_matches_route (im,
377  x,
378  address,
379  address_length))
380  {
381  /* an intf may have >1 addr from the same prefix */
382  if ((sw_if_index == sif->sw_if_index) &&
383  (ia->address_length == address_length) &&
384  !ip6_address_is_equal (x, address))
385  continue;
386 
387  /* error if the length or intf was different */
388  vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
389  return
390  clib_error_create
391  ("failed to add %U which conflicts with %U for interface %U",
392  format_ip6_address_and_length, address,
393  address_length,
394  format_ip6_address_and_length, x,
395  ia->address_length,
396  format_vnet_sw_if_index_name, vnm,
397  sif->sw_if_index);
398  }
399  }));
400  }
401  }));
402  }
403  /* *INDENT-ON* */
404 
405  {
406  uword elts_before = pool_elts (lm->if_address_pool);
407 
409  (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
410  if (error)
411  goto done;
412 
413  /* Pool did not grow: add duplicate address. */
414  if (elts_before == pool_elts (lm->if_address_pool))
415  goto done;
416  }
417 
419  if (!is_del)
421 
422  /* intf addr routes are added/deleted on admin up/down */
424  {
425  if (is_del)
427  im, ip6_af.fib_index, address,
428  address_length);
429  else
431  im, ip6_af.fib_index,
432  pool_elt_at_index (lm->if_address_pool,
433  if_address_index));
434  }
435  {
437  vec_foreach (cb, im->add_del_interface_address_callbacks)
438  cb->function (im, cb->function_opaque, sw_if_index,
439  address, address_length, if_address_index, is_del);
440  }
441  if (is_del)
443 
444 done:
445  vec_free (addr_fib);
446  return error;
447 }
448 
449 #endif
450 
451 static clib_error_t *
453 {
454  ip6_main_t *im = &ip6_main;
456  ip6_address_t *a;
457  u32 is_admin_up, fib_index;
458 
459  /* Fill in lookup tables with default table (0). */
460  vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
461 
463  lookup_main.if_address_pool_index_by_sw_if_index,
464  sw_if_index, ~0);
465 
466  is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
467 
468  fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
469 
470  /* *INDENT-OFF* */
471  foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
472  0 /* honor unnumbered */,
473  ({
474  a = ip_interface_address_get_address (&im->lookup_main, ia);
475  if (is_admin_up)
476  ip6_add_interface_routes (vnm, sw_if_index,
477  im, fib_index,
478  ia);
479  else
480  ip6_del_interface_routes (sw_if_index, im, fib_index,
481  a, ia->address_length);
482  }));
483  /* *INDENT-ON* */
484 
485  return 0;
486 }
487 
489 
490 /* Built-in ip6 unicast rx feature path definition */
491 /* *INDENT-OFF* */
492 VNET_FEATURE_ARC_INIT (ip6_unicast, static) =
493 {
494  .arc_name = "ip6-unicast",
495  .start_nodes = VNET_FEATURES ("ip6-input"),
496  .last_in_arc = "ip6-lookup",
497  .arc_index_ptr = &ip6_main.lookup_main.ucast_feature_arc_index,
498 };
499 
500 VNET_FEATURE_INIT (ip6_flow_classify, static) =
501 {
502  .arc_name = "ip6-unicast",
503  .node_name = "ip6-flow-classify",
504  .runs_before = VNET_FEATURES ("ip6-inacl"),
505 };
506 
507 VNET_FEATURE_INIT (ip6_inacl, static) =
508 {
509  .arc_name = "ip6-unicast",
510  .node_name = "ip6-inacl",
511  .runs_before = VNET_FEATURES ("ip6-policer-classify"),
512 };
513 
514 VNET_FEATURE_INIT (ip6_policer_classify, static) =
515 {
516  .arc_name = "ip6-unicast",
517  .node_name = "ip6-policer-classify",
518  .runs_before = VNET_FEATURES ("ipsec6-input-feature"),
519 };
520 
521 VNET_FEATURE_INIT (ip6_ipsec, static) =
522 {
523  .arc_name = "ip6-unicast",
524  .node_name = "ipsec6-input-feature",
525  .runs_before = VNET_FEATURES ("l2tp-decap"),
526 };
527 
528 VNET_FEATURE_INIT (ip6_l2tp, static) =
529 {
530  .arc_name = "ip6-unicast",
531  .node_name = "l2tp-decap",
532  .runs_before = VNET_FEATURES ("vpath-input-ip6"),
533 };
534 
535 VNET_FEATURE_INIT (ip6_vpath, static) =
536 {
537  .arc_name = "ip6-unicast",
538  .node_name = "vpath-input-ip6",
539  .runs_before = VNET_FEATURES ("ip6-vxlan-bypass"),
540 };
541 
542 VNET_FEATURE_INIT (ip6_vxlan_bypass, static) =
543 {
544  .arc_name = "ip6-unicast",
545  .node_name = "ip6-vxlan-bypass",
546  .runs_before = VNET_FEATURES ("ip6-lookup"),
547 };
548 
549 VNET_FEATURE_INIT (ip6_not_enabled, static) =
550 {
551  .arc_name = "ip6-unicast",
552  .node_name = "ip6-not-enabled",
553  .runs_before = VNET_FEATURES ("ip6-lookup"),
554 };
555 
556 VNET_FEATURE_INIT (ip6_lookup, static) =
557 {
558  .arc_name = "ip6-unicast",
559  .node_name = "ip6-lookup",
560  .runs_before = 0, /*last feature*/
561 };
562 
563 /* Built-in ip6 multicast rx feature path definition (none now) */
564 VNET_FEATURE_ARC_INIT (ip6_multicast, static) =
565 {
566  .arc_name = "ip6-multicast",
567  .start_nodes = VNET_FEATURES ("ip6-input"),
568  .last_in_arc = "ip6-mfib-forward-lookup",
569  .arc_index_ptr = &ip6_main.lookup_main.mcast_feature_arc_index,
570 };
571 
572 VNET_FEATURE_INIT (ip6_vpath_mc, static) = {
573  .arc_name = "ip6-multicast",
574  .node_name = "vpath-input-ip6",
575  .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
576 };
577 
578 VNET_FEATURE_INIT (ip6_not_enabled_mc, static) = {
579  .arc_name = "ip6-multicast",
580  .node_name = "ip6-not-enabled",
581  .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
582 };
583 
584 VNET_FEATURE_INIT (ip6_mc_lookup, static) = {
585  .arc_name = "ip6-multicast",
586  .node_name = "ip6-mfib-forward-lookup",
587  .runs_before = 0, /* last feature */
588 };
589 
590 /* Built-in ip4 tx feature path definition */
591 VNET_FEATURE_ARC_INIT (ip6_output, static) =
592 {
593  .arc_name = "ip6-output",
594  .start_nodes = VNET_FEATURES ("ip6-rewrite", "ip6-midchain", "ip6-dvr-dpo"),
595  .last_in_arc = "interface-output",
597 };
598 
599 VNET_FEATURE_INIT (ip6_outacl, static) = {
600  .arc_name = "ip6-output",
601  .node_name = "ip6-outacl",
602  .runs_before = VNET_FEATURES ("ipsec6-output-feature"),
603 };
604 
605 VNET_FEATURE_INIT (ip6_ipsec_output, static) = {
606  .arc_name = "ip6-output",
607  .node_name = "ipsec6-output-feature",
608  .runs_before = VNET_FEATURES ("interface-output"),
609 };
610 
611 VNET_FEATURE_INIT (ip6_interface_output, static) = {
612  .arc_name = "ip6-output",
613  .node_name = "interface-output",
614  .runs_before = 0, /* not before any other features */
615 };
616 /* *INDENT-ON* */
617 
618 static clib_error_t *
620 {
621  ip6_main_t *im = &ip6_main;
622 
623  vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
624  vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
625 
626  if (!is_add)
627  {
628  /* Ensure that IPv6 is disabled */
629  ip6_main_t *im6 = &ip6_main;
630  ip_lookup_main_t *lm6 = &im6->lookup_main;
631  ip_interface_address_t *ia = 0;
633  vlib_main_t *vm = vlib_get_main ();
634 
635  vnet_sw_interface_update_unnumbered (sw_if_index, ~0, 0);
636  /* *INDENT-OFF* */
637  foreach_ip_interface_address (lm6, ia, sw_if_index, 0,
638  ({
639  address = ip_interface_address_get_address (lm6, ia);
640  ip6_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
641  }));
642  /* *INDENT-ON* */
643  ip6_mfib_interface_enable_disable (sw_if_index, 0);
644  }
645 
646  vnet_feature_enable_disable ("ip6-unicast", "ip6-not-enabled", sw_if_index,
647  is_add, 0, 0);
648 
649  vnet_feature_enable_disable ("ip6-multicast", "ip6-not-enabled",
650  sw_if_index, is_add, 0, 0);
651 
652  return /* no error */ 0;
653 }
654 
656 
660 {
661  return ip6_lookup_inline (vm, node, frame);
662 }
663 
664 static u8 *format_ip6_lookup_trace (u8 * s, va_list * args);
665 
666 /* *INDENT-OFF* */
668 {
669  .name = "ip6-lookup",
670  .vector_size = sizeof (u32),
671  .format_trace = format_ip6_lookup_trace,
672  .n_next_nodes = IP6_LOOKUP_N_NEXT,
673  .next_nodes = IP6_LOOKUP_NEXT_NODES,
674 };
675 /* *INDENT-ON* */
676 
680 {
682  u32 n_left, *from;
683  u32 thread_index = vm->thread_index;
684  ip6_main_t *im = &ip6_main;
685  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
686  u16 nexts[VLIB_FRAME_SIZE], *next;
687 
688  from = vlib_frame_vector_args (frame);
689  n_left = frame->n_vectors;
690  next = nexts;
691 
692  vlib_get_buffers (vm, from, bufs, n_left);
693 
694  while (n_left >= 4)
695  {
696  const load_balance_t *lb0, *lb1;
697  const ip6_header_t *ip0, *ip1;
698  u32 lbi0, hc0, lbi1, hc1;
699  const dpo_id_t *dpo0, *dpo1;
700 
701  /* Prefetch next iteration. */
702  {
703  vlib_prefetch_buffer_header (b[2], STORE);
704  vlib_prefetch_buffer_header (b[3], STORE);
705 
706  CLIB_PREFETCH (b[2]->data, sizeof (ip0[0]), STORE);
707  CLIB_PREFETCH (b[3]->data, sizeof (ip0[0]), STORE);
708  }
709 
710  ip0 = vlib_buffer_get_current (b[0]);
711  ip1 = vlib_buffer_get_current (b[1]);
712  lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
713  lbi1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
714 
715  lb0 = load_balance_get (lbi0);
716  lb1 = load_balance_get (lbi1);
717 
718  /*
719  * this node is for via FIBs we can re-use the hash value from the
720  * to node if present.
721  * We don't want to use the same hash value at each level in the recursion
722  * graph as that would lead to polarisation
723  */
724  hc0 = hc1 = 0;
725 
726  if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
727  {
728  if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
729  {
730  hc0 = vnet_buffer (b[0])->ip.flow_hash =
731  vnet_buffer (b[0])->ip.flow_hash >> 1;
732  }
733  else
734  {
735  hc0 = vnet_buffer (b[0])->ip.flow_hash =
737  }
739  (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
740  }
741  else
742  {
743  dpo0 = load_balance_get_bucket_i (lb0, 0);
744  }
745  if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
746  {
747  if (PREDICT_TRUE (vnet_buffer (b[1])->ip.flow_hash))
748  {
749  hc1 = vnet_buffer (b[1])->ip.flow_hash =
750  vnet_buffer (b[1])->ip.flow_hash >> 1;
751  }
752  else
753  {
754  hc1 = vnet_buffer (b[1])->ip.flow_hash =
756  }
758  (lb1, (hc1 & (lb1->lb_n_buckets_minus_1)));
759  }
760  else
761  {
762  dpo1 = load_balance_get_bucket_i (lb1, 0);
763  }
764 
765  next[0] = dpo0->dpoi_next_node;
766  next[1] = dpo1->dpoi_next_node;
767 
768  /* Only process the HBH Option Header if explicitly configured to do so */
769  if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
770  {
771  next[0] = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
773  }
774  /* Only process the HBH Option Header if explicitly configured to do so */
775  if (PREDICT_FALSE (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
776  {
777  next[1] = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
779  }
780 
781  vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
782  vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
783 
785  (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
787  (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, b[1]));
788 
789  b += 2;
790  next += 2;
791  n_left -= 2;
792  }
793 
794  while (n_left > 0)
795  {
796  const load_balance_t *lb0;
797  const ip6_header_t *ip0;
798  const dpo_id_t *dpo0;
799  u32 lbi0, hc0;
800 
801  ip0 = vlib_buffer_get_current (b[0]);
802  lbi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
803 
804  lb0 = load_balance_get (lbi0);
805 
806  hc0 = 0;
807  if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
808  {
809  if (PREDICT_TRUE (vnet_buffer (b[0])->ip.flow_hash))
810  {
811  hc0 = vnet_buffer (b[0])->ip.flow_hash =
812  vnet_buffer (b[0])->ip.flow_hash >> 1;
813  }
814  else
815  {
816  hc0 = vnet_buffer (b[0])->ip.flow_hash =
818  }
820  (lb0, (hc0 & (lb0->lb_n_buckets_minus_1)));
821  }
822  else
823  {
824  dpo0 = load_balance_get_bucket_i (lb0, 0);
825  }
826 
827  next[0] = dpo0->dpoi_next_node;
828  vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
829 
830  /* Only process the HBH Option Header if explicitly configured to do so */
831  if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
832  {
833  next[0] = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
835  }
836 
838  (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, b[0]));
839 
840  b += 1;
841  next += 1;
842  n_left -= 1;
843  }
844 
845  vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
846 
847  if (node->flags & VLIB_NODE_FLAG_TRACE)
848  ip6_forward_next_trace (vm, node, frame, VLIB_TX);
849 
850  return frame->n_vectors;
851 }
852 
853 /* *INDENT-OFF* */
855 {
856  .name = "ip6-load-balance",
857  .vector_size = sizeof (u32),
858  .sibling_of = "ip6-lookup",
859  .format_trace = format_ip6_lookup_trace,
860 };
861 /* *INDENT-ON* */
862 
863 typedef struct
864 {
865  /* Adjacency taken. */
869 
870  /* Packet data, possibly *after* rewrite. */
871  u8 packet_data[128 - 1 * sizeof (u32)];
872 }
874 
875 #ifndef CLIB_MARCH_VARIANT
876 u8 *
877 format_ip6_forward_next_trace (u8 * s, va_list * args)
878 {
879  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
880  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
881  ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
882  u32 indent = format_get_indent (s);
883 
884  s = format (s, "%U%U",
885  format_white_space, indent,
886  format_ip6_header, t->packet_data, sizeof (t->packet_data));
887  return s;
888 }
889 #endif
890 
891 static u8 *
892 format_ip6_lookup_trace (u8 * s, va_list * args)
893 {
894  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
895  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
896  ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
897  u32 indent = format_get_indent (s);
898 
899  s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
900  t->fib_index, t->adj_index, t->flow_hash);
901  s = format (s, "\n%U%U",
902  format_white_space, indent,
903  format_ip6_header, t->packet_data, sizeof (t->packet_data));
904  return s;
905 }
906 
907 
908 static u8 *
909 format_ip6_rewrite_trace (u8 * s, va_list * args)
910 {
911  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
912  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
913  ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
914  u32 indent = format_get_indent (s);
915 
916  s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x",
919  s = format (s, "\n%U%U",
920  format_white_space, indent,
922  t->packet_data, sizeof (t->packet_data));
923  return s;
924 }
925 
926 /* Common trace function for all ip6-forward next nodes. */
927 #ifndef CLIB_MARCH_VARIANT
928 void
930  vlib_node_runtime_t * node,
931  vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
932 {
933  u32 *from, n_left;
934  ip6_main_t *im = &ip6_main;
935 
936  n_left = frame->n_vectors;
937  from = vlib_frame_vector_args (frame);
938 
939  while (n_left >= 4)
940  {
941  u32 bi0, bi1;
942  vlib_buffer_t *b0, *b1;
943  ip6_forward_next_trace_t *t0, *t1;
944 
945  /* Prefetch next iteration. */
946  vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
947  vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
948 
949  bi0 = from[0];
950  bi1 = from[1];
951 
952  b0 = vlib_get_buffer (vm, bi0);
953  b1 = vlib_get_buffer (vm, bi1);
954 
955  if (b0->flags & VLIB_BUFFER_IS_TRACED)
956  {
957  t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
958  t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
959  t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
960  t0->fib_index =
961  (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
962  (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
965 
968  sizeof (t0->packet_data));
969  }
970  if (b1->flags & VLIB_BUFFER_IS_TRACED)
971  {
972  t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
973  t1->adj_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
974  t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
975  t1->fib_index =
976  (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
977  (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
980 
983  sizeof (t1->packet_data));
984  }
985  from += 2;
986  n_left -= 2;
987  }
988 
989  while (n_left >= 1)
990  {
991  u32 bi0;
992  vlib_buffer_t *b0;
993  ip6_forward_next_trace_t *t0;
994 
995  bi0 = from[0];
996 
997  b0 = vlib_get_buffer (vm, bi0);
998 
999  if (b0->flags & VLIB_BUFFER_IS_TRACED)
1000  {
1001  t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1002  t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1003  t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1004  t0->fib_index =
1005  (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1006  (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1009 
1012  sizeof (t0->packet_data));
1013  }
1014  from += 1;
1015  n_left -= 1;
1016  }
1017 }
1018 
1019 /* Compute TCP/UDP/ICMP6 checksum in software. */
1020 u16
1022  ip6_header_t * ip0, int *bogus_lengthp)
1023 {
1024  ip_csum_t sum0 = 0;
1025  u16 payload_length, payload_length_host_byte_order;
1026  u32 i;
1027  u32 headers_size = sizeof (ip0[0]);
1028  u8 *data_this_buffer;
1029  u8 next_hdr = ip0->protocol;
1030 
1031  ASSERT (bogus_lengthp);
1032  *bogus_lengthp = 0;
1033 
1034  payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
1035  data_this_buffer = (u8 *) (ip0 + 1);
1036  payload_length = ip0->payload_length;
1037 
1038  /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets)
1039  * or UDP-Ping packets */
1040  if (PREDICT_FALSE (next_hdr == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
1041  {
1042  u32 skip_bytes;
1043  ip6_hop_by_hop_ext_t *ext_hdr =
1044  (ip6_hop_by_hop_ext_t *) data_this_buffer;
1045 
1046  /* validate really icmp6 next */
1047  ASSERT ((ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
1048  || (ext_hdr->next_hdr == IP_PROTOCOL_UDP));
1049 
1050  skip_bytes = 8 * (1 + ext_hdr->n_data_u64s);
1051  data_this_buffer = (void *) ((u8 *) data_this_buffer + skip_bytes);
1052 
1053  payload_length_host_byte_order -= skip_bytes;
1054  headers_size += skip_bytes;
1055 
1056  /* pseudo-header adjustments:
1057  * exclude ext header bytes from payload length
1058  * use payload IP proto rather than ext header IP proto
1059  */
1060  payload_length = clib_host_to_net_u16 (payload_length_host_byte_order);
1061  next_hdr = ext_hdr->next_hdr;
1062  }
1063 
1064  /* Initialize checksum with ip pseudo-header. */
1065  sum0 = payload_length + clib_host_to_net_u16 (next_hdr);
1066 
1067  for (i = 0; i < ARRAY_LEN (ip0->src_address.as_uword); i++)
1068  {
1069  sum0 = ip_csum_with_carry
1070  (sum0, clib_mem_unaligned (&ip0->src_address.as_uword[i], uword));
1071  sum0 = ip_csum_with_carry
1072  (sum0, clib_mem_unaligned (&ip0->dst_address.as_uword[i], uword));
1073  }
1074 
1075  if (p0)
1076  return ip_calculate_l4_checksum (vm, p0, sum0,
1077  payload_length_host_byte_order,
1078  (u8 *) ip0, headers_size, NULL);
1079  else
1080  return ip_calculate_l4_checksum (vm, 0, sum0,
1081  payload_length_host_byte_order, NULL, 0,
1082  data_this_buffer);
1083 }
1084 
1085 u32
1087 {
1089  udp_header_t *udp0;
1090  u16 sum16;
1091  int bogus_length;
1092 
1093  /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets) */
1094  ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1095  || ip0->protocol == IP_PROTOCOL_ICMP6
1096  || ip0->protocol == IP_PROTOCOL_UDP
1097  || ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS);
1098 
1099  udp0 = (void *) (ip0 + 1);
1100  if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1101  {
1102  p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1103  | VNET_BUFFER_F_L4_CHECKSUM_CORRECT);
1104  return p0->flags;
1105  }
1106 
1107  sum16 = ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0, &bogus_length);
1108 
1109  p0->flags |= (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED
1110  | ((sum16 == 0) << VNET_BUFFER_F_LOG2_L4_CHECKSUM_CORRECT));
1111 
1112  return p0->flags;
1113 }
1114 #endif
1115 
1116 /**
1117  * @brief returns number of links on which src is reachable.
1118  */
1119 always_inline int
1121 {
1122  const load_balance_t *lb0;
1123  index_t lbi;
1124  u32 fib_index;
1125 
1126  fib_index = vec_elt (im->fib_index_by_sw_if_index,
1128  fib_index =
1129  (vnet_buffer (b)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
1130  fib_index : vnet_buffer (b)->sw_if_index[VLIB_TX];
1131 
1132  lbi = ip6_fib_table_fwding_lookup (fib_index, &i->src_address);
1133  lb0 = load_balance_get (lbi);
1134 
1135  return (fib_urpf_check_size (lb0->lb_urpf));
1136 }
1137 
1140  u32 * udp_offset0)
1141 {
1142  u32 proto0;
1143  proto0 = ip6_locate_header (p0, ip0, IP_PROTOCOL_UDP, udp_offset0);
1144  if (proto0 != IP_PROTOCOL_UDP)
1145  {
1146  proto0 = ip6_locate_header (p0, ip0, IP_PROTOCOL_TCP, udp_offset0);
1147  proto0 = (proto0 == IP_PROTOCOL_TCP) ? proto0 : 0;
1148  }
1149  return proto0;
1150 }
1151 
1152 /* *INDENT-OFF* */
1153 VNET_FEATURE_ARC_INIT (ip6_local) =
1154 {
1155  .arc_name = "ip6-local",
1156  .start_nodes = VNET_FEATURES ("ip6-local"),
1157 };
1158 /* *INDENT-ON* */
1159 
1162 {
1163 
1164  u16 payload_length_host_byte_order;
1165  u32 n_this_buffer, n_bytes_left;
1167  u32 headers_size = sizeof (ip0[0]);
1168  u8 *data_this_buffer;
1169 
1170 
1171  data_this_buffer = (u8 *) (ip0 + 1);
1172 
1173  ip6_hop_by_hop_ext_t *ext_hdr = (ip6_hop_by_hop_ext_t *) data_this_buffer;
1174 
1175  /* validate really icmp6 next */
1176 
1177  if (!(ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
1178  || (ext_hdr->next_hdr == IP_PROTOCOL_UDP))
1179  return 0;
1180 
1181 
1182  payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
1183  n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1184 
1185 
1186  u32 n_ip_bytes_this_buffer =
1187  p0->current_length - (((u8 *) ip0 - p0->data) - p0->current_data);
1188  if (n_this_buffer + headers_size > n_ip_bytes_this_buffer)
1189  {
1190  n_this_buffer = p0->current_length > headers_size ?
1191  n_ip_bytes_this_buffer - headers_size : 0;
1192  }
1193 
1194  n_bytes_left -= n_this_buffer;
1195  n_bytes_left -= p0->total_length_not_including_first_buffer;
1196 
1197  if (n_bytes_left == 0)
1198  return 0;
1199  else
1200  return 1;
1201 }
1202 
1203 
1206  vlib_frame_t * frame, int head_of_feature_arc)
1207 {
1208  ip6_main_t *im = &ip6_main;
1209  ip_lookup_main_t *lm = &im->lookup_main;
1210  u32 *from, n_left_from;
1211  vlib_node_runtime_t *error_node =
1213  u8 arc_index = vnet_feat_arc_ip6_local.feature_arc_index;
1214  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1215  u16 nexts[VLIB_FRAME_SIZE], *next;
1216 
1217  from = vlib_frame_vector_args (frame);
1218  n_left_from = frame->n_vectors;
1219 
1220  if (node->flags & VLIB_NODE_FLAG_TRACE)
1221  ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1222 
1223  vlib_get_buffers (vm, from, bufs, n_left_from);
1224  b = bufs;
1225  next = nexts;
1226 
1227  while (n_left_from > 2)
1228  {
1229  /* Prefetch next iteration. */
1230  if (n_left_from >= 6)
1231  {
1232  vlib_prefetch_buffer_header (b[4], STORE);
1233  vlib_prefetch_buffer_header (b[5], STORE);
1234  vlib_prefetch_buffer_data (b[2], LOAD);
1235  vlib_prefetch_buffer_data (b[3], LOAD);
1236  }
1237 
1238  u8 error[2];
1239  error[0] = IP6_ERROR_UNKNOWN_PROTOCOL;
1240  error[1] = IP6_ERROR_UNKNOWN_PROTOCOL;
1241 
1242  ip6_header_t *ip[2];
1243  ip[0] = vlib_buffer_get_current (b[0]);
1244  ip[1] = vlib_buffer_get_current (b[1]);
1245 
1246  if (head_of_feature_arc)
1247  {
1248  vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1249  vnet_buffer (b[1])->l3_hdr_offset = b[1]->current_data;
1250 
1251  u8 type[2];
1252  type[0] = lm->builtin_protocol_by_ip_protocol[ip[0]->protocol];
1253  type[1] = lm->builtin_protocol_by_ip_protocol[ip[1]->protocol];
1254 
1255  u32 flags[2];
1256  flags[0] = b[0]->flags;
1257  flags[1] = b[1]->flags;
1258 
1259  u32 good_l4_csum[2];
1260  good_l4_csum[0] =
1261  flags[0] & (VNET_BUFFER_F_L4_CHECKSUM_CORRECT |
1262  VNET_BUFFER_F_OFFLOAD_TCP_CKSUM |
1263  VNET_BUFFER_F_OFFLOAD_UDP_CKSUM);
1264  good_l4_csum[1] =
1265  flags[1] & (VNET_BUFFER_F_L4_CHECKSUM_CORRECT |
1266  VNET_BUFFER_F_OFFLOAD_TCP_CKSUM |
1267  VNET_BUFFER_F_OFFLOAD_UDP_CKSUM);
1268 
1269  u32 udp_offset[2] = { };
1270  u8 is_tcp_udp[2];
1271  is_tcp_udp[0] =
1272  ip6_next_proto_is_tcp_udp (b[0], ip[0], &udp_offset[0]);
1273  is_tcp_udp[1] =
1274  ip6_next_proto_is_tcp_udp (b[1], ip[1], &udp_offset[1]);
1275  i16 len_diff[2] = { 0 };
1276  if (PREDICT_TRUE (is_tcp_udp[0]))
1277  {
1278  udp_header_t *udp =
1279  (udp_header_t *) ((u8 *) ip[0] + udp_offset[0]);
1280  good_l4_csum[0] |= type[0] == IP_BUILTIN_PROTOCOL_UDP
1281  && udp->checksum == 0;
1282  /* optimistically verify UDP length. */
1283  u16 ip_len, udp_len;
1284  ip_len = clib_net_to_host_u16 (ip[0]->payload_length);
1285  udp_len = clib_net_to_host_u16 (udp->length);
1286  len_diff[0] = ip_len - udp_len;
1287  }
1288  if (PREDICT_TRUE (is_tcp_udp[1]))
1289  {
1290  udp_header_t *udp =
1291  (udp_header_t *) ((u8 *) ip[1] + udp_offset[1]);
1292  good_l4_csum[1] |= type[1] == IP_BUILTIN_PROTOCOL_UDP
1293  && udp->checksum == 0;
1294  /* optimistically verify UDP length. */
1295  u16 ip_len, udp_len;
1296  ip_len = clib_net_to_host_u16 (ip[1]->payload_length);
1297  udp_len = clib_net_to_host_u16 (udp->length);
1298  len_diff[1] = ip_len - udp_len;
1299  }
1300 
1301  good_l4_csum[0] |= type[0] == IP_BUILTIN_PROTOCOL_UNKNOWN;
1302  good_l4_csum[1] |= type[1] == IP_BUILTIN_PROTOCOL_UNKNOWN;
1303 
1304  len_diff[0] = type[0] == IP_BUILTIN_PROTOCOL_UDP ? len_diff[0] : 0;
1305  len_diff[1] = type[1] == IP_BUILTIN_PROTOCOL_UDP ? len_diff[1] : 0;
1306 
1307  u8 need_csum[2];
1308  need_csum[0] = type[0] != IP_BUILTIN_PROTOCOL_UNKNOWN
1309  && !good_l4_csum[0]
1310  && !(flags[0] & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
1311  need_csum[1] = type[1] != IP_BUILTIN_PROTOCOL_UNKNOWN
1312  && !good_l4_csum[1]
1313  && !(flags[1] & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
1314  if (PREDICT_FALSE (need_csum[0]))
1315  {
1316  flags[0] = ip6_tcp_udp_icmp_validate_checksum (vm, b[0]);
1317  good_l4_csum[0] = flags[0] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
1318  error[0] = IP6_ERROR_UNKNOWN_PROTOCOL;
1319  }
1320  else
1321  {
1322  if (ip6_tcp_udp_icmp_bad_length (vm, b[0]))
1323  error[0] = IP6_ERROR_BAD_LENGTH;
1324  }
1325  if (PREDICT_FALSE (need_csum[1]))
1326  {
1327  flags[1] = ip6_tcp_udp_icmp_validate_checksum (vm, b[1]);
1328  good_l4_csum[1] = flags[1] & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
1329  error[1] = IP6_ERROR_UNKNOWN_PROTOCOL;
1330  }
1331  else
1332  {
1333  if (ip6_tcp_udp_icmp_bad_length (vm, b[1]))
1334  error[1] = IP6_ERROR_BAD_LENGTH;
1335  }
1336 
1337 
1338  error[0] = len_diff[0] < 0 ? IP6_ERROR_UDP_LENGTH : error[0];
1339 
1340  error[1] = len_diff[1] < 0 ? IP6_ERROR_UDP_LENGTH : error[1];
1341 
1342  STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1343  IP6_ERROR_UDP_CHECKSUM,
1344  "Wrong IP6 errors constants");
1345  STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1346  IP6_ERROR_ICMP_CHECKSUM,
1347  "Wrong IP6 errors constants");
1348 
1349  error[0] =
1350  !good_l4_csum[0] ? IP6_ERROR_UDP_CHECKSUM + type[0] : error[0];
1351  error[1] =
1352  !good_l4_csum[1] ? IP6_ERROR_UDP_CHECKSUM + type[1] : error[1];
1353 
1354  /* Drop packets from unroutable hosts. */
1355  /* If this is a neighbor solicitation (ICMP), skip source RPF check */
1356  u8 unroutable[2];
1357  unroutable[0] = error[0] == IP6_ERROR_UNKNOWN_PROTOCOL
1358  && type[0] != IP_BUILTIN_PROTOCOL_ICMP
1360  unroutable[1] = error[1] == IP6_ERROR_UNKNOWN_PROTOCOL
1361  && type[1] != IP_BUILTIN_PROTOCOL_ICMP
1363  if (PREDICT_FALSE (unroutable[0]))
1364  {
1365  error[0] =
1366  !ip6_urpf_loose_check (im, b[0],
1367  ip[0]) ? IP6_ERROR_SRC_LOOKUP_MISS
1368  : error[0];
1369  }
1370  if (PREDICT_FALSE (unroutable[1]))
1371  {
1372  error[1] =
1373  !ip6_urpf_loose_check (im, b[1],
1374  ip[1]) ? IP6_ERROR_SRC_LOOKUP_MISS
1375  : error[1];
1376  }
1377 
1378  vnet_buffer (b[0])->ip.fib_index =
1379  vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1380  vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1381  vnet_buffer (b[0])->ip.fib_index;
1382  vnet_buffer (b[1])->ip.fib_index =
1383  vnet_buffer (b[1])->sw_if_index[VLIB_TX] != ~0 ?
1384  vnet_buffer (b[1])->sw_if_index[VLIB_TX] :
1385  vnet_buffer (b[1])->ip.fib_index;
1386  } /* head_of_feature_arc */
1387 
1388  next[0] = lm->local_next_by_ip_protocol[ip[0]->protocol];
1389  next[0] =
1390  error[0] != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[0];
1391  next[1] = lm->local_next_by_ip_protocol[ip[1]->protocol];
1392  next[1] =
1393  error[1] != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[1];
1394 
1395  b[0]->error = error_node->errors[0];
1396  b[1]->error = error_node->errors[1];
1397 
1398  if (head_of_feature_arc)
1399  {
1400  u8 ip6_unknown[2];
1401  ip6_unknown[0] = error[0] == (u8) IP6_ERROR_UNKNOWN_PROTOCOL;
1402  ip6_unknown[1] = error[1] == (u8) IP6_ERROR_UNKNOWN_PROTOCOL;
1403  if (PREDICT_TRUE (ip6_unknown[0]))
1404  {
1405  u32 next32 = next[0];
1406  vnet_feature_arc_start (arc_index,
1407  vnet_buffer (b[0])->sw_if_index
1408  [VLIB_RX], &next32, b[0]);
1409  next[0] = next32;
1410  }
1411  if (PREDICT_TRUE (ip6_unknown[1]))
1412  {
1413  u32 next32 = next[1];
1414  vnet_feature_arc_start (arc_index,
1415  vnet_buffer (b[1])->sw_if_index
1416  [VLIB_RX], &next32, b[1]);
1417  next[1] = next32;
1418  }
1419  }
1420 
1421  /* next */
1422  b += 2;
1423  next += 2;
1424  n_left_from -= 2;
1425  }
1426 
1427  while (n_left_from)
1428  {
1429  u8 error;
1430  error = IP6_ERROR_UNKNOWN_PROTOCOL;
1431 
1432  ip6_header_t *ip;
1433  ip = vlib_buffer_get_current (b[0]);
1434 
1435  if (head_of_feature_arc)
1436  {
1437  vnet_buffer (b[0])->l3_hdr_offset = b[0]->current_data;
1439 
1440  u32 flags = b[0]->flags;
1441  u32 good_l4_csum =
1442  flags & (VNET_BUFFER_F_L4_CHECKSUM_CORRECT |
1443  VNET_BUFFER_F_OFFLOAD_TCP_CKSUM |
1444  VNET_BUFFER_F_OFFLOAD_UDP_CKSUM);
1445 
1446  u32 udp_offset;
1447  i16 len_diff = 0;
1448  u8 is_tcp_udp = ip6_next_proto_is_tcp_udp (b[0], ip, &udp_offset);
1449  if (PREDICT_TRUE (is_tcp_udp))
1450  {
1451  udp_header_t *udp = (udp_header_t *) ((u8 *) ip + udp_offset);
1452  /* Don't verify UDP checksum for packets with explicit zero checksum. */
1453  good_l4_csum |= type == IP_BUILTIN_PROTOCOL_UDP
1454  && udp->checksum == 0;
1455  /* optimistically verify UDP length. */
1456  u16 ip_len, udp_len;
1457  ip_len = clib_net_to_host_u16 (ip->payload_length);
1458  udp_len = clib_net_to_host_u16 (udp->length);
1459  len_diff = ip_len - udp_len;
1460  }
1461 
1462  good_l4_csum |= type == IP_BUILTIN_PROTOCOL_UNKNOWN;
1463  len_diff = type == IP_BUILTIN_PROTOCOL_UDP ? len_diff : 0;
1464 
1465  u8 need_csum = type != IP_BUILTIN_PROTOCOL_UNKNOWN && !good_l4_csum
1466  && !(flags & VNET_BUFFER_F_L4_CHECKSUM_COMPUTED);
1467  if (PREDICT_FALSE (need_csum))
1468  {
1469  flags = ip6_tcp_udp_icmp_validate_checksum (vm, b[0]);
1470  good_l4_csum = flags & VNET_BUFFER_F_L4_CHECKSUM_CORRECT;
1471  error = IP6_ERROR_UNKNOWN_PROTOCOL;
1472  }
1473  else
1474  {
1475  if (ip6_tcp_udp_icmp_bad_length (vm, b[0]))
1476  error = IP6_ERROR_BAD_LENGTH;
1477  }
1478 
1479 
1480 
1481  error = len_diff < 0 ? IP6_ERROR_UDP_LENGTH : error;
1482 
1483  STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1484  IP6_ERROR_UDP_CHECKSUM,
1485  "Wrong IP6 errors constants");
1486  STATIC_ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1487  IP6_ERROR_ICMP_CHECKSUM,
1488  "Wrong IP6 errors constants");
1489 
1490  error = !good_l4_csum ? IP6_ERROR_UDP_CHECKSUM + type : error;
1491 
1492  /* Drop packets from unroutable hosts. */
1493  /* If this is a neighbor solicitation (ICMP), skip source RPF check */
1494  u8 unroutable = error == IP6_ERROR_UNKNOWN_PROTOCOL
1495  && type != IP_BUILTIN_PROTOCOL_ICMP
1497  if (PREDICT_FALSE (unroutable))
1498  {
1499  error =
1500  !ip6_urpf_loose_check (im, b[0],
1501  ip) ? IP6_ERROR_SRC_LOOKUP_MISS :
1502  error;
1503  }
1504 
1505  vnet_buffer (b[0])->ip.fib_index =
1506  vnet_buffer (b[0])->sw_if_index[VLIB_TX] != ~0 ?
1507  vnet_buffer (b[0])->sw_if_index[VLIB_TX] :
1508  vnet_buffer (b[0])->ip.fib_index;
1509  } /* head_of_feature_arc */
1510 
1511  next[0] = lm->local_next_by_ip_protocol[ip->protocol];
1512  next[0] =
1513  error != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next[0];
1514 
1515  b[0]->error = error_node->errors[0];
1516 
1517  if (head_of_feature_arc)
1518  {
1519  if (PREDICT_TRUE (error == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
1520  {
1521  u32 next32 = next[0];
1522  vnet_feature_arc_start (arc_index,
1523  vnet_buffer (b[0])->sw_if_index
1524  [VLIB_RX], &next32, b[0]);
1525  next[0] = next32;
1526  }
1527  }
1528 
1529  /* next */
1530  b += 1;
1531  next += 1;
1532  n_left_from -= 1;
1533  }
1534 
1535  vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
1536  return frame->n_vectors;
1537 }
1538 
1540  vlib_frame_t * frame)
1541 {
1542  return ip6_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1543 }
1544 
1545 /* *INDENT-OFF* */
1547 {
1548  .name = "ip6-local",
1549  .vector_size = sizeof (u32),
1550  .format_trace = format_ip6_forward_next_trace,
1551  .n_next_nodes = IP_LOCAL_N_NEXT,
1552  .next_nodes =
1553  {
1554  [IP_LOCAL_NEXT_DROP] = "ip6-drop",
1555  [IP_LOCAL_NEXT_PUNT] = "ip6-punt",
1556  [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
1557  [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
1558  [IP_LOCAL_NEXT_REASSEMBLY] = "ip6-full-reassembly",
1559  },
1560 };
1561 /* *INDENT-ON* */
1562 
1565  vlib_frame_t * frame)
1566 {
1567  return ip6_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1568 }
1569 
1570 /* *INDENT-OFF* */
1572  .name = "ip6-local-end-of-arc",
1573  .vector_size = sizeof (u32),
1574 
1575  .format_trace = format_ip6_forward_next_trace,
1576  .sibling_of = "ip6-local",
1577 };
1578 
1579 VNET_FEATURE_INIT (ip6_local_end_of_arc, static) = {
1580  .arc_name = "ip6-local",
1581  .node_name = "ip6-local-end-of-arc",
1582  .runs_before = 0, /* not before any other features */
1583 };
1584 /* *INDENT-ON* */
1585 
1586 #ifdef CLIB_MARCH_VARIANT
1588 #else
1589 void
1591 {
1592  vlib_main_t *vm = vlib_get_main ();
1593  ip6_main_t *im = &ip6_main;
1594  ip_lookup_main_t *lm = &im->lookup_main;
1595 
1596  ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1598  vlib_node_add_next (vm, ip6_local_node.index, node_index);
1599 }
1600 
1601 void
1603 {
1604  ip6_main_t *im = &ip6_main;
1605  ip_lookup_main_t *lm = &im->lookup_main;
1606 
1607  ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1609 }
1610 #endif
1611 
1612 typedef enum
1613 {
1619 
1620 /**
1621  * This bits of an IPv6 address to mask to construct a multicast
1622  * MAC address
1623  */
1624 #define IP6_MCAST_ADDR_MASK 0xffffffff
1625 
1626 always_inline void
1627 ip6_mtu_check (vlib_buffer_t * b, u16 packet_bytes,
1628  u16 adj_packet_bytes, bool is_locally_generated,
1629  u32 * next, u8 is_midchain, u32 * error)
1630 {
1631  if (adj_packet_bytes >= 1280 && packet_bytes > adj_packet_bytes)
1632  {
1633  if (is_locally_generated)
1634  {
1635  /* IP fragmentation */
1636  ip_frag_set_vnet_buffer (b, adj_packet_bytes,
1637  (is_midchain ?
1640  *next = IP6_REWRITE_NEXT_FRAGMENT;
1641  *error = IP6_ERROR_MTU_EXCEEDED;
1642  }
1643  else
1644  {
1645  *error = IP6_ERROR_MTU_EXCEEDED;
1646  icmp6_error_set_vnet_buffer (b, ICMP6_packet_too_big, 0,
1647  adj_packet_bytes);
1649  }
1650  }
1651 }
1652 
1655  vlib_node_runtime_t * node,
1656  vlib_frame_t * frame,
1657  int do_counters, int is_midchain, int is_mcast)
1658 {
1660  u32 *from = vlib_frame_vector_args (frame);
1661  u32 n_left_from, n_left_to_next, *to_next, next_index;
1662  vlib_node_runtime_t *error_node =
1664 
1665  n_left_from = frame->n_vectors;
1666  next_index = node->cached_next_index;
1667  u32 thread_index = vm->thread_index;
1668 
1669  while (n_left_from > 0)
1670  {
1671  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1672 
1673  while (n_left_from >= 4 && n_left_to_next >= 2)
1674  {
1675  const ip_adjacency_t *adj0, *adj1;
1676  vlib_buffer_t *p0, *p1;
1677  ip6_header_t *ip0, *ip1;
1678  u32 pi0, rw_len0, next0, error0, adj_index0;
1679  u32 pi1, rw_len1, next1, error1, adj_index1;
1680  u32 tx_sw_if_index0, tx_sw_if_index1;
1681  bool is_locally_originated0, is_locally_originated1;
1682 
1683  /* Prefetch next iteration. */
1684  {
1685  vlib_buffer_t *p2, *p3;
1686 
1687  p2 = vlib_get_buffer (vm, from[2]);
1688  p3 = vlib_get_buffer (vm, from[3]);
1689 
1690  vlib_prefetch_buffer_header (p2, LOAD);
1691  vlib_prefetch_buffer_header (p3, LOAD);
1692 
1693  CLIB_PREFETCH (p2->pre_data, 32, STORE);
1694  CLIB_PREFETCH (p3->pre_data, 32, STORE);
1695 
1696  CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
1697  CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
1698  }
1699 
1700  pi0 = to_next[0] = from[0];
1701  pi1 = to_next[1] = from[1];
1702 
1703  from += 2;
1704  n_left_from -= 2;
1705  to_next += 2;
1706  n_left_to_next -= 2;
1707 
1708  p0 = vlib_get_buffer (vm, pi0);
1709  p1 = vlib_get_buffer (vm, pi1);
1710 
1711  adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1712  adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
1713 
1714  ip0 = vlib_buffer_get_current (p0);
1715  ip1 = vlib_buffer_get_current (p1);
1716 
1717  error0 = error1 = IP6_ERROR_NONE;
1718  next0 = next1 = IP6_REWRITE_NEXT_DROP;
1719 
1720  is_locally_originated0 =
1721  p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
1722  if (PREDICT_TRUE (!is_locally_originated0))
1723  {
1724  i32 hop_limit0 = ip0->hop_limit;
1725 
1726  /* Input node should have reject packets with hop limit 0. */
1727  ASSERT (ip0->hop_limit > 0);
1728 
1729  hop_limit0 -= 1;
1730 
1731  ip0->hop_limit = hop_limit0;
1732 
1733  /*
1734  * If the hop count drops below 1 when forwarding, generate
1735  * an ICMP response.
1736  */
1737  if (PREDICT_FALSE (hop_limit0 <= 0))
1738  {
1739  error0 = IP6_ERROR_TIME_EXPIRED;
1741  vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1742  icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
1743  ICMP6_time_exceeded_ttl_exceeded_in_transit,
1744  0);
1745  }
1746  }
1747  else
1748  {
1749  p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
1750  }
1751  is_locally_originated1 =
1752  p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
1753  if (PREDICT_TRUE (!is_locally_originated1))
1754  {
1755  i32 hop_limit1 = ip1->hop_limit;
1756 
1757  /* Input node should have reject packets with hop limit 0. */
1758  ASSERT (ip1->hop_limit > 0);
1759 
1760  hop_limit1 -= 1;
1761 
1762  ip1->hop_limit = hop_limit1;
1763 
1764  /*
1765  * If the hop count drops below 1 when forwarding, generate
1766  * an ICMP response.
1767  */
1768  if (PREDICT_FALSE (hop_limit1 <= 0))
1769  {
1770  error1 = IP6_ERROR_TIME_EXPIRED;
1772  vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1773  icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
1774  ICMP6_time_exceeded_ttl_exceeded_in_transit,
1775  0);
1776  }
1777  }
1778  else
1779  {
1780  p1->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
1781  }
1782  adj0 = adj_get (adj_index0);
1783  adj1 = adj_get (adj_index1);
1784 
1785  rw_len0 = adj0[0].rewrite_header.data_bytes;
1786  rw_len1 = adj1[0].rewrite_header.data_bytes;
1787  vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
1788  vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
1789 
1790  if (do_counters)
1791  {
1794  thread_index, adj_index0, 1,
1795  vlib_buffer_length_in_chain (vm, p0) + rw_len0);
1798  thread_index, adj_index1, 1,
1799  vlib_buffer_length_in_chain (vm, p1) + rw_len1);
1800  }
1801 
1802  /* Check MTU of outgoing interface. */
1803  u16 ip0_len =
1804  clib_net_to_host_u16 (ip0->payload_length) +
1805  sizeof (ip6_header_t);
1806  u16 ip1_len =
1807  clib_net_to_host_u16 (ip1->payload_length) +
1808  sizeof (ip6_header_t);
1809  if (p0->flags & VNET_BUFFER_F_GSO)
1810  ip0_len = gso_mtu_sz (p0);
1811  if (p1->flags & VNET_BUFFER_F_GSO)
1812  ip1_len = gso_mtu_sz (p1);
1813 
1814 
1815 
1816  ip6_mtu_check (p0, ip0_len,
1817  adj0[0].rewrite_header.max_l3_packet_bytes,
1818  is_locally_originated0, &next0, is_midchain,
1819  &error0);
1820  ip6_mtu_check (p1, ip1_len,
1821  adj1[0].rewrite_header.max_l3_packet_bytes,
1822  is_locally_originated1, &next1, is_midchain,
1823  &error1);
1824 
1825  /* Don't adjust the buffer for hop count issue; icmp-error node
1826  * wants to see the IP header */
1827  if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
1828  {
1829  p0->current_data -= rw_len0;
1830  p0->current_length += rw_len0;
1831 
1832  tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
1833  vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
1834  next0 = adj0[0].rewrite_header.next_index;
1835 
1836  if (PREDICT_FALSE
1837  (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
1839  tx_sw_if_index0, &next0, p0);
1840  }
1841  else
1842  {
1843  p0->error = error_node->errors[error0];
1844  }
1845  if (PREDICT_TRUE (error1 == IP6_ERROR_NONE))
1846  {
1847  p1->current_data -= rw_len1;
1848  p1->current_length += rw_len1;
1849 
1850  tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
1851  vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
1852  next1 = adj1[0].rewrite_header.next_index;
1853 
1854  if (PREDICT_FALSE
1855  (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
1857  tx_sw_if_index1, &next1, p1);
1858  }
1859  else
1860  {
1861  p1->error = error_node->errors[error1];
1862  }
1863 
1864  if (is_midchain)
1865  {
1866  /* before we paint on the next header, update the L4
1867  * checksums if required, since there's no offload on a tunnel */
1868  calc_checksums (vm, p0);
1869  calc_checksums (vm, p1);
1870  }
1871 
1872  /* Guess we are only writing on simple Ethernet header. */
1873  vnet_rewrite_two_headers (adj0[0], adj1[0],
1874  ip0, ip1, sizeof (ethernet_header_t));
1875 
1876  if (is_midchain)
1877  {
1878  if (adj0->sub_type.midchain.fixup_func)
1879  adj0->sub_type.midchain.fixup_func
1880  (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
1881  if (adj1->sub_type.midchain.fixup_func)
1882  adj1->sub_type.midchain.fixup_func
1883  (vm, adj1, p1, adj1->sub_type.midchain.fixup_data);
1884  }
1885  if (is_mcast)
1886  {
1887  /*
1888  * copy bytes from the IP address into the MAC rewrite
1889  */
1891  adj0->
1892  rewrite_header.dst_mcast_offset,
1893  &ip0->dst_address.as_u32[3],
1894  (u8 *) ip0);
1896  adj1->
1897  rewrite_header.dst_mcast_offset,
1898  &ip1->dst_address.as_u32[3],
1899  (u8 *) ip1);
1900  }
1901 
1902  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1903  to_next, n_left_to_next,
1904  pi0, pi1, next0, next1);
1905  }
1906 
1907  while (n_left_from > 0 && n_left_to_next > 0)
1908  {
1909  ip_adjacency_t *adj0;
1910  vlib_buffer_t *p0;
1911  ip6_header_t *ip0;
1912  u32 pi0, rw_len0;
1913  u32 adj_index0, next0, error0;
1914  u32 tx_sw_if_index0;
1915  bool is_locally_originated0;
1916 
1917  pi0 = to_next[0] = from[0];
1918 
1919  p0 = vlib_get_buffer (vm, pi0);
1920 
1921  adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1922 
1923  adj0 = adj_get (adj_index0);
1924 
1925  ip0 = vlib_buffer_get_current (p0);
1926 
1927  error0 = IP6_ERROR_NONE;
1928  next0 = IP6_REWRITE_NEXT_DROP;
1929 
1930  /* Check hop limit */
1931  is_locally_originated0 =
1932  p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED;
1933  if (PREDICT_TRUE (!is_locally_originated0))
1934  {
1935  i32 hop_limit0 = ip0->hop_limit;
1936 
1937  ASSERT (ip0->hop_limit > 0);
1938 
1939  hop_limit0 -= 1;
1940 
1941  ip0->hop_limit = hop_limit0;
1942 
1943  if (PREDICT_FALSE (hop_limit0 <= 0))
1944  {
1945  /*
1946  * If the hop count drops below 1 when forwarding, generate
1947  * an ICMP response.
1948  */
1949  error0 = IP6_ERROR_TIME_EXPIRED;
1951  vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1952  icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
1953  ICMP6_time_exceeded_ttl_exceeded_in_transit,
1954  0);
1955  }
1956  }
1957  else
1958  {
1959  p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
1960  }
1961 
1962  if (is_midchain)
1963  {
1964  calc_checksums (vm, p0);
1965  }
1966 
1967  /* Guess we are only writing on simple Ethernet header. */
1968  vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
1969 
1970  /* Update packet buffer attributes/set output interface. */
1971  rw_len0 = adj0[0].rewrite_header.data_bytes;
1972  vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
1973 
1974  if (do_counters)
1975  {
1978  thread_index, adj_index0, 1,
1979  vlib_buffer_length_in_chain (vm, p0) + rw_len0);
1980  }
1981 
1982  /* Check MTU of outgoing interface. */
1983  u16 ip0_len =
1984  clib_net_to_host_u16 (ip0->payload_length) +
1985  sizeof (ip6_header_t);
1986  if (p0->flags & VNET_BUFFER_F_GSO)
1987  ip0_len = gso_mtu_sz (p0);
1988 
1989  ip6_mtu_check (p0, ip0_len,
1990  adj0[0].rewrite_header.max_l3_packet_bytes,
1991  is_locally_originated0, &next0, is_midchain,
1992  &error0);
1993 
1994  /* Don't adjust the buffer for hop count issue; icmp-error node
1995  * wants to see the IP header */
1996  if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
1997  {
1998  p0->current_data -= rw_len0;
1999  p0->current_length += rw_len0;
2000 
2001  tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2002 
2003  vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2004  next0 = adj0[0].rewrite_header.next_index;
2005 
2006  if (PREDICT_FALSE
2007  (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2009  tx_sw_if_index0, &next0, p0);
2010  }
2011  else
2012  {
2013  p0->error = error_node->errors[error0];
2014  }
2015 
2016  if (is_midchain)
2017  {
2018  if (adj0->sub_type.midchain.fixup_func)
2019  adj0->sub_type.midchain.fixup_func
2020  (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
2021  }
2022  if (is_mcast)
2023  {
2025  adj0->
2026  rewrite_header.dst_mcast_offset,
2027  &ip0->dst_address.as_u32[3],
2028  (u8 *) ip0);
2029  }
2030 
2031  from += 1;
2032  n_left_from -= 1;
2033  to_next += 1;
2034  n_left_to_next -= 1;
2035 
2036  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2037  to_next, n_left_to_next,
2038  pi0, next0);
2039  }
2040 
2041  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2042  }
2043 
2044  /* Need to do trace after rewrites to pick up new packet data. */
2045  if (node->flags & VLIB_NODE_FLAG_TRACE)
2046  ip6_forward_next_trace (vm, node, frame, VLIB_TX);
2047 
2048  return frame->n_vectors;
2049 }
2050 
2053  vlib_node_runtime_t * node,
2054  vlib_frame_t * frame,
2055  int do_counters, int is_midchain, int is_mcast)
2056 {
2057  return ip6_rewrite_inline_with_gso (vm, node, frame, do_counters,
2058  is_midchain, is_mcast);
2059 }
2060 
2063  vlib_frame_t * frame)
2064 {
2065  if (adj_are_counters_enabled ())
2066  return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
2067  else
2068  return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
2069 }
2070 
2073  vlib_frame_t * frame)
2074 {
2075  if (adj_are_counters_enabled ())
2076  return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
2077  else
2078  return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
2079 }
2080 
2083  vlib_frame_t * frame)
2084 {
2085  if (adj_are_counters_enabled ())
2086  return ip6_rewrite_inline (vm, node, frame, 1, 0, 1);
2087  else
2088  return ip6_rewrite_inline (vm, node, frame, 0, 0, 1);
2089 }
2090 
2093  vlib_frame_t * frame)
2094 {
2095  if (adj_are_counters_enabled ())
2096  return ip6_rewrite_inline (vm, node, frame, 1, 1, 0);
2097  else
2098  return ip6_rewrite_inline (vm, node, frame, 0, 1, 0);
2099 }
2100 
2103  vlib_frame_t * frame)
2104 {
2105  if (adj_are_counters_enabled ())
2106  return ip6_rewrite_inline (vm, node, frame, 1, 1, 1);
2107  else
2108  return ip6_rewrite_inline (vm, node, frame, 0, 1, 1);
2109 }
2110 
2111 /* *INDENT-OFF* */
2113 {
2114  .name = "ip6-midchain",
2115  .vector_size = sizeof (u32),
2116  .format_trace = format_ip6_forward_next_trace,
2117  .sibling_of = "ip6-rewrite",
2118  };
2119 
2121 {
2122  .name = "ip6-rewrite",
2123  .vector_size = sizeof (u32),
2124  .format_trace = format_ip6_rewrite_trace,
2125  .n_next_nodes = IP6_REWRITE_N_NEXT,
2126  .next_nodes =
2127  {
2128  [IP6_REWRITE_NEXT_DROP] = "ip6-drop",
2129  [IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
2130  [IP6_REWRITE_NEXT_FRAGMENT] = "ip6-frag",
2131  },
2132 };
2133 
2135  .name = "ip6-rewrite-bcast",
2136  .vector_size = sizeof (u32),
2137 
2138  .format_trace = format_ip6_rewrite_trace,
2139  .sibling_of = "ip6-rewrite",
2140 };
2141 
2143 {
2144  .name = "ip6-rewrite-mcast",
2145  .vector_size = sizeof (u32),
2146  .format_trace = format_ip6_rewrite_trace,
2147  .sibling_of = "ip6-rewrite",
2148 };
2149 
2150 
2152 {
2153  .name = "ip6-mcast-midchain",
2154  .vector_size = sizeof (u32),
2155  .format_trace = format_ip6_rewrite_trace,
2156  .sibling_of = "ip6-rewrite",
2157 };
2158 
2159 /* *INDENT-ON* */
2160 
2161 /*
2162  * Hop-by-Hop handling
2163  */
2164 #ifndef CLIB_MARCH_VARIANT
2166 #endif /* CLIB_MARCH_VARIANT */
2167 
2168 #define foreach_ip6_hop_by_hop_error \
2169 _(PROCESSED, "pkts with ip6 hop-by-hop options") \
2170 _(FORMAT, "incorrectly formatted hop-by-hop options") \
2171 _(UNKNOWN_OPTION, "unknown ip6 hop-by-hop options")
2172 
2173 /* *INDENT-OFF* */
2174 typedef enum
2175 {
2176 #define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym,
2178 #undef _
2181 /* *INDENT-ON* */
2182 
2183 /*
2184  * Primary h-b-h handler trace support
2185  * We work pretty hard on the problem for obvious reasons
2186  */
2187 typedef struct
2188 {
2191  u8 option_data[256];
2193 
2195 
2197 #define _(sym,string) string,
2199 #undef _
2200 };
2201 
2202 #ifndef CLIB_MARCH_VARIANT
2203 u8 *
2204 format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args)
2205 {
2206  ip6_hop_by_hop_header_t *hbh0 = va_arg (*args, ip6_hop_by_hop_header_t *);
2207  int total_len = va_arg (*args, int);
2208  ip6_hop_by_hop_option_t *opt0, *limit0;
2210  u8 type0;
2211 
2212  s = format (s, "IP6_HOP_BY_HOP: next protocol %d len %d total %d",
2213  hbh0->protocol, (hbh0->length + 1) << 3, total_len);
2214 
2215  opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2216  limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 + total_len);
2217 
2218  while (opt0 < limit0)
2219  {
2220  type0 = opt0->type;
2221  switch (type0)
2222  {
2223  case 0: /* Pad, just stop */
2224  opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0 + 1);
2225  break;
2226 
2227  default:
2228  if (hm->trace[type0])
2229  {
2230  s = (*hm->trace[type0]) (s, opt0);
2231  }
2232  else
2233  {
2234  s =
2235  format (s, "\n unrecognized option %d length %d", type0,
2236  opt0->length);
2237  }
2238  opt0 =
2239  (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2240  sizeof (ip6_hop_by_hop_option_t));
2241  break;
2242  }
2243  }
2244  return s;
2245 }
2246 #endif
2247 
2248 static u8 *
2249 format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
2250 {
2251  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2252  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
2253  ip6_hop_by_hop_trace_t *t = va_arg (*args, ip6_hop_by_hop_trace_t *);
2255  ip6_hop_by_hop_option_t *opt0, *limit0;
2257 
2258  u8 type0;
2259 
2260  hbh0 = (ip6_hop_by_hop_header_t *) t->option_data;
2261 
2262  s = format (s, "IP6_HOP_BY_HOP: next index %d len %d traced %d",
2263  t->next_index, (hbh0->length + 1) << 3, t->trace_len);
2264 
2265  opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2266  limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0) + t->trace_len;
2267 
2268  while (opt0 < limit0)
2269  {
2270  type0 = opt0->type;
2271  switch (type0)
2272  {
2273  case 0: /* Pad, just stop */
2274  opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2275  break;
2276 
2277  default:
2278  if (hm->trace[type0])
2279  {
2280  s = (*hm->trace[type0]) (s, opt0);
2281  }
2282  else
2283  {
2284  s =
2285  format (s, "\n unrecognized option %d length %d", type0,
2286  opt0->length);
2287  }
2288  opt0 =
2289  (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2290  sizeof (ip6_hop_by_hop_option_t));
2291  break;
2292  }
2293  }
2294  return s;
2295 }
2296 
2299  ip6_header_t * ip0,
2300  ip6_hop_by_hop_header_t * hbh0,
2301  ip6_hop_by_hop_option_t * opt0,
2302  ip6_hop_by_hop_option_t * limit0, u32 * next0)
2303 {
2305  u8 type0;
2306  u8 error0 = 0;
2307 
2308  while (opt0 < limit0)
2309  {
2310  type0 = opt0->type;
2311  switch (type0)
2312  {
2313  case 0: /* Pad1 */
2314  opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2315  continue;
2316  case 1: /* PadN */
2317  break;
2318  default:
2319  if (hm->options[type0])
2320  {
2321  if ((*hm->options[type0]) (b0, ip0, opt0) < 0)
2322  {
2323  error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2324  return (error0);
2325  }
2326  }
2327  else
2328  {
2329  /* Unrecognized mandatory option, check the two high order bits */
2330  switch (opt0->type & HBH_OPTION_TYPE_HIGH_ORDER_BITS)
2331  {
2333  break;
2335  error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2336  *next0 = IP_LOOKUP_NEXT_DROP;
2337  break;
2339  error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2340  *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2341  icmp6_error_set_vnet_buffer (b0, ICMP6_parameter_problem,
2342  ICMP6_parameter_problem_unrecognized_option,
2343  (u8 *) opt0 - (u8 *) ip0);
2344  break;
2346  error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2347  if (!ip6_address_is_multicast (&ip0->dst_address))
2348  {
2349  *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2351  ICMP6_parameter_problem,
2352  ICMP6_parameter_problem_unrecognized_option,
2353  (u8 *) opt0 - (u8 *) ip0);
2354  }
2355  else
2356  {
2357  *next0 = IP_LOOKUP_NEXT_DROP;
2358  }
2359  break;
2360  }
2361  return (error0);
2362  }
2363  }
2364  opt0 =
2365  (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2366  sizeof (ip6_hop_by_hop_option_t));
2367  }
2368  return (error0);
2369 }
2370 
2371 /*
2372  * Process the Hop-by-Hop Options header
2373  */
2374 VLIB_NODE_FN (ip6_hop_by_hop_node) (vlib_main_t * vm,
2376  vlib_frame_t * frame)
2377 {
2378  vlib_node_runtime_t *error_node =
2379  vlib_node_get_runtime (vm, ip6_hop_by_hop_node.index);
2381  u32 n_left_from, *from, *to_next;
2382  ip_lookup_next_t next_index;
2383 
2384  from = vlib_frame_vector_args (frame);
2385  n_left_from = frame->n_vectors;
2386  next_index = node->cached_next_index;
2387 
2388  while (n_left_from > 0)
2389  {
2390  u32 n_left_to_next;
2391 
2392  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2393 
2394  while (n_left_from >= 4 && n_left_to_next >= 2)
2395  {
2396  u32 bi0, bi1;
2397  vlib_buffer_t *b0, *b1;
2398  u32 next0, next1;
2399  ip6_header_t *ip0, *ip1;
2400  ip6_hop_by_hop_header_t *hbh0, *hbh1;
2401  ip6_hop_by_hop_option_t *opt0, *limit0, *opt1, *limit1;
2402  u8 error0 = 0, error1 = 0;
2403 
2404  /* Prefetch next iteration. */
2405  {
2406  vlib_buffer_t *p2, *p3;
2407 
2408  p2 = vlib_get_buffer (vm, from[2]);
2409  p3 = vlib_get_buffer (vm, from[3]);
2410 
2411  vlib_prefetch_buffer_header (p2, LOAD);
2412  vlib_prefetch_buffer_header (p3, LOAD);
2413 
2414  CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2415  CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2416  }
2417 
2418  /* Speculatively enqueue b0, b1 to the current next frame */
2419  to_next[0] = bi0 = from[0];
2420  to_next[1] = bi1 = from[1];
2421  from += 2;
2422  to_next += 2;
2423  n_left_from -= 2;
2424  n_left_to_next -= 2;
2425 
2426  b0 = vlib_get_buffer (vm, bi0);
2427  b1 = vlib_get_buffer (vm, bi1);
2428 
2429  /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2430  u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
2431  ip_adjacency_t *adj0 = adj_get (adj_index0);
2432  u32 adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
2433  ip_adjacency_t *adj1 = adj_get (adj_index1);
2434 
2435  /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2436  next0 = adj0->lookup_next_index;
2437  next1 = adj1->lookup_next_index;
2438 
2439  ip0 = vlib_buffer_get_current (b0);
2440  ip1 = vlib_buffer_get_current (b1);
2441  hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2442  hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1);
2443  opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2444  opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
2445  limit0 =
2446  (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2447  ((hbh0->length + 1) << 3));
2448  limit1 =
2449  (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
2450  ((hbh1->length + 1) << 3));
2451 
2452  /*
2453  * Basic validity checks
2454  */
2455  if ((hbh0->length + 1) << 3 >
2456  clib_net_to_host_u16 (ip0->payload_length))
2457  {
2458  error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2459  next0 = IP_LOOKUP_NEXT_DROP;
2460  goto outdual;
2461  }
2462  /* Scan the set of h-b-h options, process ones that we understand */
2463  error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2464 
2465  if ((hbh1->length + 1) << 3 >
2466  clib_net_to_host_u16 (ip1->payload_length))
2467  {
2468  error1 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2469  next1 = IP_LOOKUP_NEXT_DROP;
2470  goto outdual;
2471  }
2472  /* Scan the set of h-b-h options, process ones that we understand */
2473  error1 = ip6_scan_hbh_options (b1, ip1, hbh1, opt1, limit1, &next1);
2474 
2475  outdual:
2476  /* Has the classifier flagged this buffer for special treatment? */
2477  if (PREDICT_FALSE
2478  ((error0 == 0)
2479  && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2480  next0 = hm->next_override;
2481 
2482  /* Has the classifier flagged this buffer for special treatment? */
2483  if (PREDICT_FALSE
2484  ((error1 == 0)
2485  && (vnet_buffer (b1)->l2_classify.opaque_index & OI_DECAP)))
2486  next1 = hm->next_override;
2487 
2488  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2489  {
2490  if (b0->flags & VLIB_BUFFER_IS_TRACED)
2491  {
2493  vlib_add_trace (vm, node, b0, sizeof (*t));
2494  u32 trace_len = (hbh0->length + 1) << 3;
2495  t->next_index = next0;
2496  /* Capture the h-b-h option verbatim */
2497  trace_len =
2498  trace_len <
2499  ARRAY_LEN (t->option_data) ? trace_len :
2500  ARRAY_LEN (t->option_data);
2501  t->trace_len = trace_len;
2502  clib_memcpy_fast (t->option_data, hbh0, trace_len);
2503  }
2504  if (b1->flags & VLIB_BUFFER_IS_TRACED)
2505  {
2507  vlib_add_trace (vm, node, b1, sizeof (*t));
2508  u32 trace_len = (hbh1->length + 1) << 3;
2509  t->next_index = next1;
2510  /* Capture the h-b-h option verbatim */
2511  trace_len =
2512  trace_len <
2513  ARRAY_LEN (t->option_data) ? trace_len :
2514  ARRAY_LEN (t->option_data);
2515  t->trace_len = trace_len;
2516  clib_memcpy_fast (t->option_data, hbh1, trace_len);
2517  }
2518 
2519  }
2520 
2521  b0->error = error_node->errors[error0];
2522  b1->error = error_node->errors[error1];
2523 
2524  /* verify speculative enqueue, maybe switch current next frame */
2525  vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
2526  n_left_to_next, bi0, bi1, next0,
2527  next1);
2528  }
2529 
2530  while (n_left_from > 0 && n_left_to_next > 0)
2531  {
2532  u32 bi0;
2533  vlib_buffer_t *b0;
2534  u32 next0;
2535  ip6_header_t *ip0;
2537  ip6_hop_by_hop_option_t *opt0, *limit0;
2538  u8 error0 = 0;
2539 
2540  /* Speculatively enqueue b0 to the current next frame */
2541  bi0 = from[0];
2542  to_next[0] = bi0;
2543  from += 1;
2544  to_next += 1;
2545  n_left_from -= 1;
2546  n_left_to_next -= 1;
2547 
2548  b0 = vlib_get_buffer (vm, bi0);
2549  /*
2550  * Default use the next_index from the adjacency.
2551  * A HBH option rarely redirects to a different node
2552  */
2553  u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
2554  ip_adjacency_t *adj0 = adj_get (adj_index0);
2555  next0 = adj0->lookup_next_index;
2556 
2557  ip0 = vlib_buffer_get_current (b0);
2558  hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2559  opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2560  limit0 =
2561  (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2562  ((hbh0->length + 1) << 3));
2563 
2564  /*
2565  * Basic validity checks
2566  */
2567  if ((hbh0->length + 1) << 3 >
2568  clib_net_to_host_u16 (ip0->payload_length))
2569  {
2570  error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2571  next0 = IP_LOOKUP_NEXT_DROP;
2572  goto out0;
2573  }
2574 
2575  /* Scan the set of h-b-h options, process ones that we understand */
2576  error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2577 
2578  out0:
2579  /* Has the classifier flagged this buffer for special treatment? */
2580  if (PREDICT_FALSE
2581  ((error0 == 0)
2582  && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2583  next0 = hm->next_override;
2584 
2585  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2586  {
2588  vlib_add_trace (vm, node, b0, sizeof (*t));
2589  u32 trace_len = (hbh0->length + 1) << 3;
2590  t->next_index = next0;
2591  /* Capture the h-b-h option verbatim */
2592  trace_len =
2593  trace_len <
2594  ARRAY_LEN (t->option_data) ? trace_len :
2595  ARRAY_LEN (t->option_data);
2596  t->trace_len = trace_len;
2597  clib_memcpy_fast (t->option_data, hbh0, trace_len);
2598  }
2599 
2600  b0->error = error_node->errors[error0];
2601 
2602  /* verify speculative enqueue, maybe switch current next frame */
2603  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2604  n_left_to_next, bi0, next0);
2605  }
2606  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2607  }
2608  return frame->n_vectors;
2609 }
2610 
2611 /* *INDENT-OFF* */
2612 VLIB_REGISTER_NODE (ip6_hop_by_hop_node) =
2613 {
2614  .name = "ip6-hop-by-hop",
2615  .sibling_of = "ip6-lookup",
2616  .vector_size = sizeof (u32),
2617  .format_trace = format_ip6_hop_by_hop_trace,
2619  .n_errors = ARRAY_LEN (ip6_hop_by_hop_error_strings),
2620  .error_strings = ip6_hop_by_hop_error_strings,
2621  .n_next_nodes = 0,
2622 };
2623 /* *INDENT-ON* */
2624 
2625 static clib_error_t *
2627 {
2629  clib_memset (hm->options, 0, sizeof (hm->options));
2630  clib_memset (hm->trace, 0, sizeof (hm->trace));
2632  return (0);
2633 }
2634 
2636 
2637 #ifndef CLIB_MARCH_VARIANT
2638 void
2640 {
2642 
2643  hm->next_override = next;
2644 }
2645 
2646 int
2648  int options (vlib_buffer_t * b, ip6_header_t * ip,
2649  ip6_hop_by_hop_option_t * opt),
2650  u8 * trace (u8 * s, ip6_hop_by_hop_option_t * opt))
2651 {
2652  ip6_main_t *im = &ip6_main;
2654 
2655  ASSERT ((u32) option < ARRAY_LEN (hm->options));
2656 
2657  /* Already registered */
2658  if (hm->options[option])
2659  return (-1);
2660 
2661  hm->options[option] = options;
2662  hm->trace[option] = trace;
2663 
2664  /* Set global variable */
2665  im->hbh_enabled = 1;
2666 
2667  return (0);
2668 }
2669 
2670 int
2672 {
2673  ip6_main_t *im = &ip6_main;
2675 
2676  ASSERT ((u32) option < ARRAY_LEN (hm->options));
2677 
2678  /* Not registered */
2679  if (!hm->options[option])
2680  return (-1);
2681 
2682  hm->options[option] = NULL;
2683  hm->trace[option] = NULL;
2684 
2685  /* Disable global knob if this was the last option configured */
2686  int i;
2687  bool found = false;
2688  for (i = 0; i < 256; i++)
2689  {
2690  if (hm->options[option])
2691  {
2692  found = true;
2693  break;
2694  }
2695  }
2696  if (!found)
2697  im->hbh_enabled = 0;
2698 
2699  return (0);
2700 }
2701 
2702 /* Global IP6 main. */
2704 #endif
2705 
2706 static clib_error_t *
2708 {
2709  ip6_main_t *im = &ip6_main;
2710  clib_error_t *error;
2711  uword i;
2712 
2713  if ((error = vlib_call_init_function (vm, vnet_feature_init)))
2714  return error;
2715 
2716  for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
2717  {
2718  u32 j, i0, i1;
2719 
2720  i0 = i / 32;
2721  i1 = i % 32;
2722 
2723  for (j = 0; j < i0; j++)
2724  im->fib_masks[i].as_u32[j] = ~0;
2725 
2726  if (i1)
2727  im->fib_masks[i].as_u32[i0] =
2728  clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
2729  }
2730 
2731  ip_lookup_init (&im->lookup_main, /* is_ip6 */ 1);
2732 
2733  if (im->lookup_table_nbuckets == 0)
2735 
2737 
2738  if (im->lookup_table_size == 0)
2740 
2741  clib_bihash_init_24_8 (&(im->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash),
2742  "ip6 FIB fwding table",
2744  clib_bihash_init_24_8 (&im->ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
2745  "ip6 FIB non-fwding table",
2747  clib_bihash_init_40_8 (&im->ip6_mtable.ip6_mhash,
2748  "ip6 mFIB table",
2750 
2751  /* Create FIB with index 0 and table id of 0. */
2756 
2757  {
2758  pg_node_t *pn;
2759  pn = pg_get_node (ip6_lookup_node.index);
2761  }
2762 
2763  /* Unless explicitly configured, don't process HBH options */
2764  im->hbh_enabled = 0;
2765 
2766  return error;
2767 }
2768 
2770 
2771 #ifndef CLIB_MARCH_VARIANT
2772 int
2774 {
2775  u32 fib_index;
2776 
2777  fib_index = fib_table_find (FIB_PROTOCOL_IP6, table_id);
2778 
2779  if (~0 == fib_index)
2780  return VNET_API_ERROR_NO_SUCH_FIB;
2781 
2783  flow_hash_config);
2784 
2785  return 0;
2786 }
2787 #endif
2788 
2789 static clib_error_t *
2791  unformat_input_t * input,
2792  vlib_cli_command_t * cmd)
2793 {
2794  int matched = 0;
2795  u32 table_id = 0;
2796  u32 flow_hash_config = 0;
2797  int rv;
2798 
2799  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2800  {
2801  if (unformat (input, "table %d", &table_id))
2802  matched = 1;
2803 #define _(a,v) \
2804  else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
2806 #undef _
2807  else
2808  break;
2809  }
2810 
2811  if (matched == 0)
2812  return clib_error_return (0, "unknown input `%U'",
2813  format_unformat_error, input);
2814 
2815  rv = vnet_set_ip6_flow_hash (table_id, flow_hash_config);
2816  switch (rv)
2817  {
2818  case 0:
2819  break;
2820 
2821  case -1:
2822  return clib_error_return (0, "no such FIB table %d", table_id);
2823 
2824  default:
2825  clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2826  break;
2827  }
2828 
2829  return 0;
2830 }
2831 
2832 /*?
2833  * Configure the set of IPv6 fields used by the flow hash.
2834  *
2835  * @cliexpar
2836  * @parblock
2837  * Example of how to set the flow hash on a given table:
2838  * @cliexcmd{set ip6 flow-hash table 8 dst sport dport proto}
2839  *
2840  * Example of display the configured flow hash:
2841  * @cliexstart{show ip6 fib}
2842  * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2843  * @::/0
2844  * unicast-ip6-chain
2845  * [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
2846  * [0] [@0]: dpo-drop ip6
2847  * fe80::/10
2848  * unicast-ip6-chain
2849  * [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
2850  * [0] [@2]: dpo-receive
2851  * ff02::1/128
2852  * unicast-ip6-chain
2853  * [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
2854  * [0] [@2]: dpo-receive
2855  * ff02::2/128
2856  * unicast-ip6-chain
2857  * [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
2858  * [0] [@2]: dpo-receive
2859  * ff02::16/128
2860  * unicast-ip6-chain
2861  * [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
2862  * [0] [@2]: dpo-receive
2863  * ff02::1:ff00:0/104
2864  * unicast-ip6-chain
2865  * [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
2866  * [0] [@2]: dpo-receive
2867  * ipv6-VRF:8, fib_index 1, flow hash: dst sport dport proto
2868  * @::/0
2869  * unicast-ip6-chain
2870  * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2871  * [0] [@0]: dpo-drop ip6
2872  * @::a:1:1:0:4/126
2873  * unicast-ip6-chain
2874  * [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
2875  * [0] [@4]: ipv6-glean: af_packet0
2876  * @::a:1:1:0:7/128
2877  * unicast-ip6-chain
2878  * [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
2879  * [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
2880  * fe80::/10
2881  * unicast-ip6-chain
2882  * [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
2883  * [0] [@2]: dpo-receive
2884  * fe80::fe:3eff:fe3e:9222/128
2885  * unicast-ip6-chain
2886  * [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
2887  * [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
2888  * ff02::1/128
2889  * unicast-ip6-chain
2890  * [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
2891  * [0] [@2]: dpo-receive
2892  * ff02::2/128
2893  * unicast-ip6-chain
2894  * [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
2895  * [0] [@2]: dpo-receive
2896  * ff02::16/128
2897  * unicast-ip6-chain
2898  * [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
2899  * [0] [@2]: dpo-receive
2900  * ff02::1:ff00:0/104
2901  * unicast-ip6-chain
2902  * [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
2903  * [0] [@2]: dpo-receive
2904  * @cliexend
2905  * @endparblock
2906 ?*/
2907 /* *INDENT-OFF* */
2909 {
2910  .path = "set ip6 flow-hash",
2911  .short_help =
2912  "set ip6 flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
2913  .function = set_ip6_flow_hash_command_fn,
2914 };
2915 /* *INDENT-ON* */
2916 
2917 static clib_error_t *
2919  unformat_input_t * input, vlib_cli_command_t * cmd)
2920 {
2921  ip6_main_t *im = &ip6_main;
2922  ip_lookup_main_t *lm = &im->lookup_main;
2923  int i;
2924 
2925  vlib_cli_output (vm, "Protocols handled by ip6_local");
2926  for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
2927  {
2929  {
2930 
2931  u32 node_index = vlib_get_node (vm,
2932  ip6_local_node.index)->
2933  next_nodes[lm->local_next_by_ip_protocol[i]];
2934  vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
2935  node_index);
2936  }
2937  }
2938  return 0;
2939 }
2940 
2941 
2942 
2943 /*?
2944  * Display the set of protocols handled by the local IPv6 stack.
2945  *
2946  * @cliexpar
2947  * Example of how to display local protocol table:
2948  * @cliexstart{show ip6 local}
2949  * Protocols handled by ip6_local
2950  * 17
2951  * 43
2952  * 58
2953  * 115
2954  * @cliexend
2955 ?*/
2956 /* *INDENT-OFF* */
2958 {
2959  .path = "show ip6 local",
2960  .function = show_ip6_local_command_fn,
2961  .short_help = "show ip6 local",
2962 };
2963 /* *INDENT-ON* */
2964 
2965 #ifndef CLIB_MARCH_VARIANT
2966 int
2968  u32 table_index)
2969 {
2970  vnet_main_t *vnm = vnet_get_main ();
2972  ip6_main_t *ipm = &ip6_main;
2973  ip_lookup_main_t *lm = &ipm->lookup_main;
2975  ip6_address_t *if_addr;
2976 
2977  if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2978  return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2979 
2980  if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2981  return VNET_API_ERROR_NO_SUCH_ENTRY;
2982 
2985 
2986  if_addr = ip6_interface_first_address (ipm, sw_if_index);
2987 
2988  if (NULL != if_addr)
2989  {
2990  fib_prefix_t pfx = {
2991  .fp_len = 128,
2992  .fp_proto = FIB_PROTOCOL_IP6,
2993  .fp_addr.ip6 = *if_addr,
2994  };
2995  u32 fib_index;
2996 
2998  sw_if_index);
2999 
3000 
3001  if (table_index != (u32) ~ 0)
3002  {
3003  dpo_id_t dpo = DPO_INVALID;
3004 
3005  dpo_set (&dpo,
3006  DPO_CLASSIFY,
3007  DPO_PROTO_IP6,
3008  classify_dpo_create (DPO_PROTO_IP6, table_index));
3009 
3011  &pfx,
3013  FIB_ENTRY_FLAG_NONE, &dpo);
3014  dpo_reset (&dpo);
3015  }
3016  else
3017  {
3018  fib_table_entry_special_remove (fib_index,
3019  &pfx, FIB_SOURCE_CLASSIFY);
3020  }
3021  }
3022 
3023  return 0;
3024 }
3025 #endif
3026 
3027 static clib_error_t *
3029  unformat_input_t * input,
3030  vlib_cli_command_t * cmd)
3031 {
3032  u32 table_index = ~0;
3033  int table_index_set = 0;
3034  u32 sw_if_index = ~0;
3035  int rv;
3036 
3037  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3038  {
3039  if (unformat (input, "table-index %d", &table_index))
3040  table_index_set = 1;
3041  else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3042  vnet_get_main (), &sw_if_index))
3043  ;
3044  else
3045  break;
3046  }
3047 
3048  if (table_index_set == 0)
3049  return clib_error_return (0, "classify table-index must be specified");
3050 
3051  if (sw_if_index == ~0)
3052  return clib_error_return (0, "interface / subif must be specified");
3053 
3054  rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
3055 
3056  switch (rv)
3057  {
3058  case 0:
3059  break;
3060 
3061  case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3062  return clib_error_return (0, "No such interface");
3063 
3064  case VNET_API_ERROR_NO_SUCH_ENTRY:
3065  return clib_error_return (0, "No such classifier table");
3066  }
3067  return 0;
3068 }
3069 
3070 /*?
3071  * Assign a classification table to an interface. The classification
3072  * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3073  * commands. Once the table is create, use this command to filter packets
3074  * on an interface.
3075  *
3076  * @cliexpar
3077  * Example of how to assign a classification table to an interface:
3078  * @cliexcmd{set ip6 classify intfc GigabitEthernet2/0/0 table-index 1}
3079 ?*/
3080 /* *INDENT-OFF* */
3082 {
3083  .path = "set ip6 classify",
3084  .short_help =
3085  "set ip6 classify intfc <interface> table-index <classify-idx>",
3086  .function = set_ip6_classify_command_fn,
3087 };
3088 /* *INDENT-ON* */
3089 
3090 static clib_error_t *
3092 {
3093  ip6_main_t *im = &ip6_main;
3094  uword heapsize = 0;
3095  u32 tmp;
3096  u32 nbuckets = 0;
3097 
3098  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3099  {
3100  if (unformat (input, "hash-buckets %d", &tmp))
3101  nbuckets = tmp;
3102  else if (unformat (input, "heap-size %U",
3103  unformat_memory_size, &heapsize))
3104  ;
3105  else
3106  return clib_error_return (0, "unknown input '%U'",
3107  format_unformat_error, input);
3108  }
3109 
3110  im->lookup_table_nbuckets = nbuckets;
3111  im->lookup_table_size = heapsize;
3112 
3113  return 0;
3114 }
3115 
3117 
3118 /*
3119  * fd.io coding-style-patch-verification: ON
3120  *
3121  * Local Variables:
3122  * eval: (c-set-style "gnu")
3123  * End:
3124  */
static vlib_cli_command_t set_ip6_flow_hash_command
(constructor) VLIB_CLI_COMMAND (set_ip6_flow_hash_command)
Definition: ip6_forward.c:2908
u8 * format_ip6_forward_next_trace(u8 *s, va_list *args)
Definition: ip6_forward.c:877
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:440
#define foreach_ip_interface_address(lm, a, sw_if_index, loop, body)
Definition: lookup.h:213
#define vnet_rewrite_one_header(rw0, p0, most_likely_size)
Definition: rewrite.h:200
u16 lb_n_buckets
number of buckets in the load-balance.
Definition: load_balance.h:116
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:124
#define HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP
u32 mfib_table_find_or_create_and_lock(fib_protocol_t proto, u32 table_id, mfib_source_t src)
Get the index of the FIB for a Table-ID.
Definition: mfib_table.c:613
static uword ip6_local_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, int head_of_feature_arc)
Definition: ip6_forward.c:1205
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: vlib_api_cli.c:898
static clib_error_t * ip6_sw_interface_admin_up_down(vnet_main_t *vnm, u32 sw_if_index, u32 flags)
Definition: ip6_forward.c:452
static u8 * format_ip6_lookup_trace(u8 *s, va_list *args)
Definition: ip6_forward.c:892
#define CLIB_UNUSED(x)
Definition: clib.h:82
format_function_t format_ip_adjacency_packet_data
Definition: format.h:59
static u32 ip6_fib_table_fwding_lookup(u32 fib_index, const ip6_address_t *dst)
Definition: ip6_fib.h:67
static int fib_urpf_check_size(index_t ui)
Data-Plane function to check the size of an uRPF list, (i.e.
void ip_frag_set_vnet_buffer(vlib_buffer_t *b, u16 mtu, u8 next_index, u8 flags)
Definition: ip_frag.c:239
format_function_t format_vlib_node_name
Definition: node_funcs.h:1141
static u8 ip6_next_proto_is_tcp_udp(vlib_buffer_t *p0, ip6_header_t *ip0, u32 *udp_offset0)
Definition: ip6_forward.c:1139
a
Definition: bitmap.h:538
static void vlib_increment_combined_counter(vlib_combined_counter_main_t *cm, u32 thread_index, u32 index, u64 n_packets, u64 n_bytes)
Increment a combined counter.
Definition: counter.h:220
u32 * mfib_index_by_sw_if_index
Table index indexed by software interface.
Definition: ip6.h:198
uword lookup_table_size
Definition: ip6.h:223
#define IP6_LOOKUP_NEXT_NODES
Definition: adj.h:122
Route added as a result of interface configuration.
Definition: fib_source.h:56
int dpo_is_adj(const dpo_id_t *dpo)
Return TRUE is the DPO is any type of adjacency.
Definition: dpo.c:278
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
static clib_error_t * set_ip6_classify_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: ip6_forward.c:3028
vnet_interface_main_t interface_main
Definition: vnet.h:56
static u8 ip6_scan_hbh_options(vlib_buffer_t *b0, ip6_header_t *ip0, ip6_hop_by_hop_header_t *hbh0, ip6_hop_by_hop_option_t *opt0, ip6_hop_by_hop_option_t *limit0, u32 *next0)
Definition: ip6_forward.c:2298
The table that stores ALL routes learned by the DP.
Definition: ip6.h:135
#define PREDICT_TRUE(x)
Definition: clib.h:112
#define foreach_ip6_hop_by_hop_error
Definition: ip6_forward.c:2168
u64 as_u64[2]
Definition: ip6_packet.h:51
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:110
vlib_node_registration_t ip6_lookup_node
(constructor) VLIB_REGISTER_NODE (ip6_lookup_node)
Definition: ip6_forward.c:667
static uword ip6_rewrite_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, int do_counters, int is_midchain, int is_mcast)
Definition: ip6_forward.c:2052
#define clib_memcpy_fast(a, b, c)
Definition: string.h:81
static u8 * format_ip6_rewrite_trace(u8 *s, va_list *args)
Definition: ip6_forward.c:909
#define NULL
Definition: clib.h:58
uword mhash_unset(mhash_t *h, void *key, uword *old_value)
Definition: mhash.c:346
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
IP unicast adjacency.
Definition: adj.h:221
u32 fib_table_get_index_for_sw_if_index(fib_protocol_t proto, u32 sw_if_index)
Get the index of the FIB bound to the interface.
Definition: fib_table.c:989
flow_hash_config_t lb_hash_config
the hash config to use when selecting a bucket.
Definition: load_balance.h:161
static const dpo_id_t * load_balance_get_fwd_bucket(const load_balance_t *lb, u16 bucket)
u8 * ip_enabled_by_sw_if_index
Definition: ip6.h:201
u32 thread_index
Definition: main.h:218
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:113
u8 data[0]
Packet data.
Definition: buffer.h:181
u32 index_t
A Data-Path Object is an object that represents actions that are applied to packets are they are swit...
Definition: dpo.h:41
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:523
int ip6_hbh_unregister_option(u8 option)
Definition: ip6_forward.c:2671
int i
static clib_error_t * ip6_config(vlib_main_t *vm, unformat_input_t *input)
Definition: ip6_forward.c:3091
static uword ip6_lookup_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip6_forward.h:55
static u32 format_get_indent(u8 *s)
Definition: format.h:72
uword ip_csum_t
Definition: ip_packet.h:244
static ip_csum_t ip_csum_with_carry(ip_csum_t sum, ip_csum_t x)
Definition: ip_packet.h:247
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
unformat_function_t unformat_vnet_sw_interface
vlib_node_registration_t ip6_rewrite_mcast_node
(constructor) VLIB_REGISTER_NODE (ip6_rewrite_mcast_node)
Definition: ip6_forward.c:2142
#define VLIB_NODE_FN(node)
Definition: node.h:202
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:470
static char * ip6_hop_by_hop_error_strings[]
Definition: ip6_forward.c:2196
static uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
Definition: buffer_funcs.h:366
Definition: fib_entry.h:114
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:237
ip6_address_t src_address
Definition: ip6_packet.h:307
u8 mcast_feature_arc_index
Feature arc indices.
Definition: lookup.h:162
static uword vlib_node_add_next(vlib_main_t *vm, uword node, uword next_node)
Definition: node_funcs.h:1092
unsigned char u8
Definition: types.h:56
ip_lookup_next_t
An adjacency is a representation of an attached L3 peer.
Definition: adj.h:50
uword as_uword[16/sizeof(uword)]
Definition: ip6_packet.h:52
VNET_SW_INTERFACE_ADD_DEL_FUNCTION(ip6_sw_interface_add_del)
static pg_node_t * pg_get_node(uword node_index)
Definition: pg.h:363
#define clib_memcpy(d, s, n)
Definition: string.h:180
VNET_FEATURE_ARC_INIT(ip6_unicast, static)
fib_node_index_t fib_table_entry_update_one_path(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, dpo_proto_t next_hop_proto, const ip46_address_t *next_hop, u32 next_hop_sw_if_index, u32 next_hop_fib_index, u32 next_hop_weight, fib_mpls_label_t *next_hop_labels, fib_route_path_flags_t path_flags)
Update the entry to have just one path.
Definition: fib_table.c:805
u32 ip6_tcp_udp_icmp_validate_checksum(vlib_main_t *vm, vlib_buffer_t *p0)
Definition: ip6_forward.c:1086
u8 output_feature_arc_index
Definition: lookup.h:164
static u16 ip_calculate_l4_checksum(vlib_main_t *vm, vlib_buffer_t *p0, ip_csum_t sum0, u32 payload_length, u8 *iph, u32 ip_header_size, u8 *l4h)
Definition: ip.h:183
vl_api_ip_proto_t protocol
Definition: lb_types.api:71
vlib_rx_or_tx_t
Definition: defs.h:44
static ip_adjacency_t * adj_get(adj_index_t adj_index)
Get a pointer to an adjacency object from its index.
Definition: adj.h:431
ip6_main_t ip6_main
Definition: ip6_forward.c:2703
static u8 * format_ip6_hop_by_hop_trace(u8 *s, va_list *args)
Definition: ip6_forward.c:2249
#define static_always_inline
Definition: clib.h:99
clib_bihash_24_8_t ip6_hash
Definition: ip6.h:146
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:498
#define vlib_prefetch_buffer_with_index(vm, bi, type)
Prefetch buffer metadata by buffer index The first 64 bytes of buffer contains most header informatio...
Definition: buffer_funcs.h:440
static clib_error_t * show_ip6_local_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: ip6_forward.c:2918
vl_api_interface_index_t sw_if_index
Definition: gre.api:59
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
format_function_t format_ip_adjacency
Definition: format.h:58
void fib_table_entry_special_remove(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source)
Remove a &#39;special&#39; entry from the FIB.
Definition: fib_table.c:424
static uword pow2_mask(uword x)
Definition: clib.h:220
static uword ip6_rewrite_inline_with_gso(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, int do_counters, int is_midchain, int is_mcast)
Definition: ip6_forward.c:1654
u16 lb_n_buckets_minus_1
number of buckets in the load-balance - 1.
Definition: load_balance.h:121
vlib_node_registration_t ip6_mcast_midchain_node
(constructor) VLIB_REGISTER_NODE (ip6_mcast_midchain_node)
Definition: ip6_forward.c:2151
static clib_error_t * set_ip6_flow_hash_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: ip6_forward.c:2790
static_always_inline void calc_checksums(vlib_main_t *vm, vlib_buffer_t *b)
u8 * format_white_space(u8 *s, va_list *va)
Definition: std-formats.c:129
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:203
#define IP6_FIB_DEFAULT_HASH_NUM_BUCKETS
Definition: ip6.h:60
Aggregate type for a prefix.
Definition: fib_types.h:203
#define clib_error_return(e, args...)
Definition: error.h:99
static_always_inline u8 ip6_tcp_udp_icmp_bad_length(vlib_main_t *vm, vlib_buffer_t *p0)
Definition: ip6_forward.c:1161
union ip_adjacency_t_::@119 sub_type
unsigned int u32
Definition: types.h:88
#define clib_error_create(args...)
Definition: error.h:96
u32 fib_table_find(fib_protocol_t proto, u32 table_id)
Get the index of the FIB for a Table-ID.
Definition: fib_table.c:1097
u16 fp_len
The mask length.
Definition: fib_types.h:207
#define vlib_call_init_function(vm, x)
Definition: init.h:270
static clib_error_t * ip6_sw_interface_add_del(vnet_main_t *vnm, u32 sw_if_index, u32 is_add)
Definition: ip6_forward.c:619
#define VLIB_FRAME_SIZE
Definition: node.h:378
u8 * format_ip6_hop_by_hop_ext_hdr(u8 *s, va_list *args)
Definition: ip6_forward.c:2204
ip6_hop_by_hop_error_t
Definition: ip6_forward.c:2174
void ip6_unregister_protocol(u32 protocol)
Definition: ip6_forward.c:1602
static clib_error_t * vnet_feature_init(vlib_main_t *vm)
Definition: feature.c:51
void icmp6_error_set_vnet_buffer(vlib_buffer_t *b, u8 type, u8 code, u32 data)
Definition: icmp6.c:446
u32 lookup_table_nbuckets
Definition: ip6.h:222
Definition: fib_entry.h:112
vl_api_fib_path_type_t type
Definition: fib_types.api:123
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
vnet_api_error_t api_errno
Definition: vnet.h:78
The identity of a DPO is a combination of its type and its instance number/index of objects of that t...
Definition: dpo.h:170
Definition: fib_entry.h:117
vnet_crypto_main_t * cm
Definition: quic_crypto.c:41
static vlib_cli_command_t show_ip6_local
(constructor) VLIB_CLI_COMMAND (show_ip6_local)
Definition: ip6_forward.c:2957
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:519
vlib_node_registration_t ip6_rewrite_bcast_node
(constructor) VLIB_REGISTER_NODE (ip6_rewrite_bcast_node)
Definition: ip6_forward.c:2134
u32 * classify_table_index_by_sw_if_index
First table index to use for this interface, ~0 => none.
Definition: lookup.h:159
#define gso_mtu_sz(b)
Definition: buffer.h:477
ip46_address_t fp_addr
The address type is not deriveable from the fp_addr member.
Definition: fib_types.h:226
index_t classify_dpo_create(dpo_proto_t proto, u32 classify_table_index)
Definition: classify_dpo.c:43
static const dpo_id_t * load_balance_get_bucket_i(const load_balance_t *lb, u32 bucket)
Definition: load_balance.h:229
vlib_node_registration_t ip6_input_node
(constructor) VLIB_REGISTER_NODE (ip6_input_node)
Definition: ip6_input.c:230
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
#define IP6_FIB_DEFAULT_HASH_MEMORY_SIZE
Definition: ip6.h:61
fib_prefix_t prefix
Definition: lookup.h:91
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
int vnet_set_ip6_flow_hash(u32 table_id, u32 flow_hash_config)
Definition: ip6_forward.c:2773
static u32 ip6_compute_flow_hash(const ip6_header_t *ip, flow_hash_config_t flow_hash_config)
Definition: ip6.h:380
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:287
The FIB DPO provieds;.
Definition: load_balance.h:106
#define PREDICT_FALSE(x)
Definition: clib.h:111
u8 local_next_by_ip_protocol[256]
Table mapping ip protocol to ip[46]-local node next index.
Definition: lookup.h:177
#define always_inline
Definition: ipsec.h:28
static clib_error_t * ip6_hop_by_hop_init(vlib_main_t *vm)
Definition: ip6_forward.c:2626
vl_api_address_union_t src_address
Definition: ip_types.api:98
void vnet_sw_interface_update_unnumbered(u32 unnumbered_sw_if_index, u32 ip_sw_if_index, u8 enable)
Definition: interface.c:1547
load_balance_main_t load_balance_main
The one instance of load-balance main.
Definition: load_balance.c:56
#define vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, next0, next1)
Finish enqueueing two buffers forward in the graph.
Definition: buffer_node.h:70
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:218
static uword mhash_set(mhash_t *h, void *key, uword new_value, uword *old_value)
Definition: mhash.h:117
VNET_FEATURE_INIT(ip6_flow_classify, static)
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:338
int ip6_hbh_register_option(u8 option, int options(vlib_buffer_t *b, ip6_header_t *ip, ip6_hop_by_hop_option_t *opt), u8 *trace(u8 *s, ip6_hop_by_hop_option_t *opt))
Definition: ip6_forward.c:2647
vlib_main_t * vm
Definition: in2out_ed.c:1810
vlib_combined_counter_main_t adjacency_counters
Adjacency packet counters.
Definition: adj.c:25
void ip6_forward_next_trace(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, vlib_rx_or_tx_t which_adj_index)
Definition: ip6_forward.c:929
u8 packet_data[128 - 1 *sizeof(u32)]
Definition: ip6_forward.c:871
static void ip6_add_interface_prefix_routes(ip6_main_t *im, u32 sw_if_index, u32 fib_index, ip6_address_t *address, u32 address_length)
Definition: ip6_forward.c:64
u32 as_u32[4]
Definition: ip6_packet.h:50
ip6_address_t fib_masks[129]
Definition: ip6.h:192
u32 classify_table_index
Definition: fib_types.api:68
void ip6_mfib_interface_enable_disable(u32 sw_if_index, int is_enable)
Add/remove the interface from the accepting list of the special MFIB entries.
Definition: ip6_mfib.c:232
#define OI_DECAP
Definition: ip6_forward.c:61
#define VLIB_EARLY_CONFIG_FUNCTION(x, n,...)
Definition: init.h:226
Adjacency to drop this packet.
Definition: adj.h:53
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
#define UNFORMAT_END_OF_INPUT
Definition: format.h:145
u32 flags
Definition: vhost_user.h:141
u16 n_vectors
Definition: node.h:397
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:80
ip6_address_t * ip6_interface_first_address(ip6_main_t *im, u32 sw_if_index)
get first IPv6 interface address
Definition: ip6_forward.c:271
static_always_inline void vlib_buffer_enqueue_to_next(vlib_main_t *vm, vlib_node_runtime_t *node, u32 *buffers, u16 *nexts, uword count)
Definition: buffer_node.h:332
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:342
vlib_node_registration_t ip6_local_node
(constructor) VLIB_REGISTER_NODE (ip6_local_node)
Definition: ip6_forward.c:1546
void fib_table_entry_delete(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source)
Delete a FIB entry.
Definition: fib_table.c:886
static void ip6_del_interface_prefix_routes(ip6_main_t *im, u32 sw_if_index, u32 fib_index, ip6_address_t *address, u32 address_length)
Definition: ip6_forward.c:171
void fib_table_set_flow_hash_config(u32 fib_index, fib_protocol_t proto, flow_hash_config_t hash_config)
Set the flow hash configured used by the table.
Definition: fib_table.c:1055
vlib_node_registration_t ip6_midchain_node
(constructor) VLIB_REGISTER_NODE (ip6_midchain_node)
Definition: ip6_forward.c:2112
#define clib_warning(format, args...)
Definition: error.h:59
static vlib_node_runtime_t * vlib_node_get_runtime(vlib_main_t *vm, u32 node_index)
Get node runtime by node index.
Definition: node_funcs.h:89
This table stores the routes that are used to forward traffic.
Definition: ip6.h:128
unformat_function_t * unformat_edit
Definition: pg.h:315
#define vlib_prefetch_buffer_data(b, type)
Definition: buffer.h:204
void ip_lookup_init(ip_lookup_main_t *lm, u32 is_ip6)
Definition: lookup.c:202
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:284
#define ARRAY_LEN(x)
Definition: clib.h:62
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:456
void dpo_set(dpo_id_t *dpo, dpo_type_t type, dpo_proto_t proto, index_t index)
Set/create a DPO ID The DPO will be locked.
Definition: dpo.c:186
vlib_combined_counter_main_t lbm_via_counters
Definition: load_balance.h:47
u8 hbh_enabled
Definition: ip6.h:237
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1810
u8 builtin_protocol_by_ip_protocol[256]
IP_BUILTIN_PROTOCOL_{TCP,UDP,ICMP,OTHER} by protocol in IP header.
Definition: lookup.h:180
static void ip6_del_interface_routes(u32 sw_if_index, ip6_main_t *im, u32 fib_index, ip6_address_t *address, u32 address_length)
Definition: ip6_forward.c:220
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:152
struct _vnet_classify_main vnet_classify_main_t
Definition: vnet_classify.h:55
#define foreach_flow_hash_bit
Definition: lookup.h:72
fib_node_index_t fib_table_entry_special_dpo_add(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, const dpo_id_t *dpo)
Add a &#39;special&#39; entry to the FIB that links to the DPO passed A special entry is an entry that the FI...
Definition: fib_table.c:324
ip6_add_del_interface_address_function_t * function
Definition: ip6.h:105
signed int i32
Definition: types.h:77
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:515
void ip6_register_protocol(u32 protocol, u32 node_index)
Definition: ip6_forward.c:1590
#define ASSERT(truth)
index_t lb_urpf
This is the index of the uRPF list for this LB.
Definition: load_balance.h:156
manual_print typedef address
Definition: ip_types.api:84
u8 pre_data[VLIB_BUFFER_PRE_DATA_SIZE]
Space for inserting data before buffer start.
Definition: buffer.h:178
VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION(ip6_sw_interface_admin_up_down)
ip6_hop_by_hop_main_t ip6_hop_by_hop_main
Definition: ip6_forward.c:2165
ip_lookup_main_t lookup_main
Definition: ip6.h:180
u8 data[128]
Definition: ipsec_types.api:87
void ip6_hbh_set_next_override(uword next)
Definition: ip6_forward.c:2639
vlib_node_registration_t ip6_local_end_of_arc_node
(constructor) VLIB_REGISTER_NODE (ip6_local_end_of_arc_node)
Definition: ip6_forward.c:1571
static load_balance_t * load_balance_get(index_t lbi)
Definition: load_balance.h:220
static void ip6_addr_fib_init(ip6_address_fib_t *addr_fib, const ip6_address_t *address, u32 fib_index)
Definition: ip6_packet.h:71
u32 fib_table_find_or_create_and_lock(fib_protocol_t proto, u32 table_id, fib_source_t src)
Get the index of the FIB for a Table-ID.
Definition: fib_table.c:1156
vlib_node_registration_t ip6_hop_by_hop_node
(constructor) VLIB_REGISTER_NODE (ip6_hop_by_hop_node)
Definition: ip6_forward.c:2612
#define HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP_NOT_MCAST
vnet_classify_main_t vnet_classify_main
Definition: vnet_classify.c:29
int vnet_set_ip6_classify_intfc(vlib_main_t *vm, u32 sw_if_index, u32 table_index)
Definition: ip6_forward.c:2967
static uword ip6_address_is_link_local_unicast(const ip6_address_t *a)
Definition: ip6_packet.h:250
#define clib_mem_unaligned(pointer, type)
Definition: types.h:155
format_function_t format_ip6_header
Definition: format.h:95
static uword ip6_address_is_equal(const ip6_address_t *a, const ip6_address_t *b)
Definition: ip6_packet.h:164
static uword ip6_address_is_multicast(const ip6_address_t *a)
Definition: ip6_packet.h:118
ip6_fib_table_instance_t ip6_table[IP6_FIB_NUM_TABLES]
The two FIB tables; fwding and non-fwding.
Definition: ip6.h:173
#define VNET_FEATURES(...)
Definition: feature.h:442
static int ip6_locate_header(vlib_buffer_t *p0, ip6_header_t *ip0, int find_hdr_type, u32 *offset)
Definition: ip6.h:463
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
vlib_node_registration_t ip6_rewrite_node
(constructor) VLIB_REGISTER_NODE (ip6_rewrite_node)
Definition: ip6_forward.c:2120
static uword vnet_sw_interface_is_admin_up(vnet_main_t *vnm, u32 sw_if_index)
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
#define vec_elt(v, i)
Get vector value at index i.
typedef key
Definition: ipsec_types.api:83
struct _vlib_node_registration vlib_node_registration_t
u8 ucast_feature_arc_index
Definition: lookup.h:163
This packets needs to go to ICMP error.
Definition: adj.h:79
void ip6_sw_interface_enable_disable(u32 sw_if_index, u32 is_enable)
Definition: ip6_forward.c:239
Definition: defs.h:47
static void vnet_ip_mcast_fixup_header(u32 dst_mcast_mask, u32 dst_mcast_offset, u32 *addr, u8 *packet0)
Definition: rewrite.h:210
#define HBH_OPTION_TYPE_DISCARD_UNKNOWN
u16 payload_length
Definition: ip6_packet.h:298
index_t dpoi_index
the index of objects of that type
Definition: dpo.h:186
vl_api_address_t ip
Definition: l2.api:490
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
ip_lookup_next_t lookup_next_index
Next hop after ip4-lookup.
Definition: adj.h:236
#define STATIC_ASSERT(truth,...)
Definition: fib_entry.h:113
static uword max_log2(uword x)
Definition: clib.h:191
#define IP6_MCAST_ADDR_MASK
This bits of an IPv6 address to mask to construct a multicast MAC address.
Definition: ip6_forward.c:1624
mhash_t prefix_to_if_prefix_index
Hash table mapping prefix to index in interface prefix pool.
Definition: lookup.h:156
ip_interface_prefix_key_t key
Definition: lookup.h:99
VLIB buffer representation.
Definition: buffer.h:102
u64 uword
Definition: types.h:112
unformat_function_t unformat_pg_ip6_header
Definition: format.h:97
vnet_sw_interface_t * sw_interfaces
Definition: interface.h:854
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:244
The default route source.
Definition: fib_source.h:131
#define DPO_INVALID
An initialiser for DPOs declared on the stack.
Definition: dpo.h:197
static void ip6_add_interface_routes(vnet_main_t *vnm, u32 sw_if_index, ip6_main_t *im, u32 fib_index, ip_interface_address_t *a)
Definition: ip6_forward.c:122
clib_error_t * ip_interface_address_add_del(ip_lookup_main_t *lm, u32 sw_if_index, void *addr_fib, u32 address_length, u32 is_del, u32 *result_if_address_index)
Definition: lookup.c:61
A collection of combined counters.
Definition: counter.h:188
u16 ip6_tcp_udp_icmp_compute_checksum(vlib_main_t *vm, vlib_buffer_t *p0, ip6_header_t *ip0, int *bogus_lengthp)
Definition: ip6_forward.c:1021
unformat_function_t unformat_memory_size
Definition: format.h:296
static vlib_cli_command_t set_ip6_classify_command
(constructor) VLIB_CLI_COMMAND (set_ip6_classify_command)
Definition: ip6_forward.c:3081
ip6_mfib_table_instance_t ip6_mtable
the single MFIB table
Definition: ip6.h:178
u8 *(* trace[256])(u8 *s, ip6_hop_by_hop_option_t *opt)
Definition: ip6.h:533
#define vnet_buffer(b)
Definition: buffer.h:408
static struct option options[]
Definition: main.c:52
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
static int ip6_urpf_loose_check(ip6_main_t *im, vlib_buffer_t *b, ip6_header_t *i)
returns number of links on which src is reachable.
Definition: ip6_forward.c:1120
static vlib_node_t * vlib_get_node(vlib_main_t *vm, u32 i)
Get vlib node by index.
Definition: node_funcs.h:59
#define HBH_OPTION_TYPE_SKIP_UNKNOWN
static void ip6_mtu_check(vlib_buffer_t *b, u16 packet_bytes, u16 adj_packet_bytes, bool is_locally_generated, u32 *next, u8 is_midchain, u32 *error)
Definition: ip6_forward.c:1627
void dpo_reset(dpo_id_t *dpo)
reset a DPO ID The DPO will be unlocked.
Definition: dpo.c:232
#define vec_foreach(var, vec)
Vector iterator.
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: in2out_ed.c:1811
u16 flags
Copy of main node flags.
Definition: node.h:509
struct ip_adjacency_t_::@119::@121 midchain
IP_LOOKUP_NEXT_MIDCHAIN.
u16 dpoi_next_node
The next VLIB node to follow.
Definition: dpo.h:182
static void * ip_interface_address_get_address(ip_lookup_main_t *lm, ip_interface_address_t *a)
Definition: lookup.h:199
static u32 ip6_lookup(gid_ip6_table_t *db, u32 vni, ip_prefix_t *key)
int(* options[256])(vlib_buffer_t *b, ip6_header_t *ip, ip6_hop_by_hop_option_t *opt)
Definition: ip6.h:531
clib_error_t * ip6_add_del_interface_address(vlib_main_t *vm, u32 sw_if_index, ip6_address_t *address, u32 address_length, u32 is_del)
Definition: ip6_forward.c:290
static_always_inline void vlib_get_buffers(vlib_main_t *vm, u32 *bi, vlib_buffer_t **b, int count)
Translate array of buffer indices into buffer pointers.
Definition: buffer_funcs.h:244
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:302
static clib_error_t * ip6_lookup_init(vlib_main_t *vm)
Definition: ip6_forward.c:2707
u32 table_id
Definition: fib_types.api:118
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
Definition: vec.h:487
#define vnet_rewrite_two_headers(rw0, rw1, p0, p1, most_likely_size)
Definition: rewrite.h:204
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
u32 total_length_not_including_first_buffer
Only valid for first buffer in chain.
Definition: buffer.h:167
vlib_node_registration_t ip6_load_balance_node
(constructor) VLIB_REGISTER_NODE (ip6_load_balance_node)
Definition: ip6_forward.c:854
This adjacency/interface has output features configured.
Definition: rewrite.h:57
IPv6 Forwarding.
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:689
u32 * fib_index_by_sw_if_index
Definition: ip6.h:195
ip_interface_prefix_t * if_prefix_pool
Pool of prefixes containing addresses assigned to interfaces.
Definition: lookup.h:153
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85
#define HBH_OPTION_TYPE_HIGH_ORDER_BITS
Definition: pg.h:312
static int adj_are_counters_enabled(void)
Get the global configuration option for enabling per-adj counters.
Definition: adj.h:446
static ip_interface_prefix_t * ip_get_interface_prefix(ip_lookup_main_t *lm, ip_interface_prefix_key_t *k)
Definition: lookup.h:206
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
Definition: defs.h:46
clib_bihash_40_8_t ip6_mhash
Definition: ip6.h:160
int vnet_feature_enable_disable(const char *arc_name, const char *node_name, u32 sw_if_index, int enable_disable, void *feature_config, u32 n_feature_config_bytes)
Definition: feature.c:304
ip6_address_t dst_address
Definition: ip6_packet.h:307
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:171
uword next_override
Definition: ip6.h:534
signed short i16
Definition: types.h:46
format_function_t format_ip4_address_and_length
Definition: format.h:74
ip6_rewrite_next_t
Definition: ip6_forward.c:1612
static_always_inline void vnet_feature_arc_start(u8 arc, u32 sw_if_index, u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:282
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128