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