FD.io VPP  v17.07-30-g839fa73
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/ip6_neighbor.h>
43 #include <vnet/ethernet/ethernet.h> /* for ethernet_header_t */
44 #include <vnet/srp/srp.h> /* for srp_hw_interface_class */
45 #include <vppinfra/cache.h>
46 #include <vnet/fib/fib_urpf_list.h> /* for FIB uRPF check */
47 #include <vnet/fib/ip6_fib.h>
48 #include <vnet/mfib/ip6_mfib.h>
50 #include <vnet/dpo/classify_dpo.h>
51 
53 
54 /* Flag used by IOAM code. Classifier sets it pop-hop-by-hop checks it */
55 #define OI_DECAP 0x80000000
56 
57 /**
58  * @file
59  * @brief IPv6 Forwarding.
60  *
61  * This file contains the source code for IPv6 forwarding.
62  */
63 
64 void
66  vlib_node_runtime_t * node,
67  vlib_frame_t * frame,
68  vlib_rx_or_tx_t which_adj_index);
69 
72  vlib_node_runtime_t * node, vlib_frame_t * frame)
73 {
74  ip6_main_t *im = &ip6_main;
76  u32 n_left_from, n_left_to_next, *from, *to_next;
77  ip_lookup_next_t next;
78  u32 thread_index = vlib_get_thread_index ();
79 
80  from = vlib_frame_vector_args (frame);
81  n_left_from = frame->n_vectors;
82  next = node->cached_next_index;
83 
84  while (n_left_from > 0)
85  {
86  vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
87 
88  while (n_left_from >= 4 && n_left_to_next >= 2)
89  {
90  vlib_buffer_t *p0, *p1;
91  u32 pi0, pi1, lbi0, lbi1, wrong_next;
92  ip_lookup_next_t next0, next1;
93  ip6_header_t *ip0, *ip1;
94  ip6_address_t *dst_addr0, *dst_addr1;
95  u32 fib_index0, fib_index1;
96  u32 flow_hash_config0, flow_hash_config1;
97  const dpo_id_t *dpo0, *dpo1;
98  const load_balance_t *lb0, *lb1;
99 
100  /* Prefetch next iteration. */
101  {
102  vlib_buffer_t *p2, *p3;
103 
104  p2 = vlib_get_buffer (vm, from[2]);
105  p3 = vlib_get_buffer (vm, from[3]);
106 
107  vlib_prefetch_buffer_header (p2, LOAD);
108  vlib_prefetch_buffer_header (p3, LOAD);
109  CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
110  CLIB_PREFETCH (p3->data, sizeof (ip0[0]), LOAD);
111  }
112 
113  pi0 = to_next[0] = from[0];
114  pi1 = to_next[1] = from[1];
115 
116  p0 = vlib_get_buffer (vm, pi0);
117  p1 = vlib_get_buffer (vm, pi1);
118 
119  ip0 = vlib_buffer_get_current (p0);
120  ip1 = vlib_buffer_get_current (p1);
121 
122  dst_addr0 = &ip0->dst_address;
123  dst_addr1 = &ip1->dst_address;
124 
125  fib_index0 =
127  vnet_buffer (p0)->sw_if_index[VLIB_RX]);
128  fib_index1 =
130  vnet_buffer (p1)->sw_if_index[VLIB_RX]);
131 
132  fib_index0 = (vnet_buffer (p0)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
133  fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
134  fib_index1 = (vnet_buffer (p1)->sw_if_index[VLIB_TX] == (u32) ~ 0) ?
135  fib_index1 : vnet_buffer (p1)->sw_if_index[VLIB_TX];
136 
137  lbi0 = ip6_fib_table_fwding_lookup (im, fib_index0, dst_addr0);
138  lbi1 = ip6_fib_table_fwding_lookup (im, fib_index1, dst_addr1);
139 
140  lb0 = load_balance_get (lbi0);
141  lb1 = load_balance_get (lbi1);
142  ASSERT (lb0->lb_n_buckets > 0);
143  ASSERT (lb1->lb_n_buckets > 0);
144  ASSERT (is_pow2 (lb0->lb_n_buckets));
145  ASSERT (is_pow2 (lb1->lb_n_buckets));
146 
147  vnet_buffer (p0)->ip.flow_hash = vnet_buffer (p1)->ip.flow_hash = 0;
148 
149  if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
150  {
151  flow_hash_config0 = lb0->lb_hash_config;
152  vnet_buffer (p0)->ip.flow_hash =
153  ip6_compute_flow_hash (ip0, flow_hash_config0);
154  dpo0 =
156  (vnet_buffer (p0)->ip.flow_hash &
157  (lb0->lb_n_buckets_minus_1)));
158  }
159  else
160  {
161  dpo0 = load_balance_get_bucket_i (lb0, 0);
162  }
163  if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
164  {
165  flow_hash_config1 = lb1->lb_hash_config;
166  vnet_buffer (p1)->ip.flow_hash =
167  ip6_compute_flow_hash (ip1, flow_hash_config1);
168  dpo1 =
170  (vnet_buffer (p1)->ip.flow_hash &
171  (lb1->lb_n_buckets_minus_1)));
172  }
173  else
174  {
175  dpo1 = load_balance_get_bucket_i (lb1, 0);
176  }
177  next0 = dpo0->dpoi_next_node;
178  next1 = dpo1->dpoi_next_node;
179 
180  /* Only process the HBH Option Header if explicitly configured to do so */
181  if (PREDICT_FALSE
182  (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
183  {
184  next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
186  }
187  if (PREDICT_FALSE
188  (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
189  {
190  next1 = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
192  }
193  vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
194  vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
195 
197  (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
199  (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
200 
201  from += 2;
202  to_next += 2;
203  n_left_to_next -= 2;
204  n_left_from -= 2;
205 
206  wrong_next = (next0 != next) + 2 * (next1 != next);
207  if (PREDICT_FALSE (wrong_next != 0))
208  {
209  switch (wrong_next)
210  {
211  case 1:
212  /* A B A */
213  to_next[-2] = pi1;
214  to_next -= 1;
215  n_left_to_next += 1;
216  vlib_set_next_frame_buffer (vm, node, next0, pi0);
217  break;
218 
219  case 2:
220  /* A A B */
221  to_next -= 1;
222  n_left_to_next += 1;
223  vlib_set_next_frame_buffer (vm, node, next1, pi1);
224  break;
225 
226  case 3:
227  /* A B C */
228  to_next -= 2;
229  n_left_to_next += 2;
230  vlib_set_next_frame_buffer (vm, node, next0, pi0);
231  vlib_set_next_frame_buffer (vm, node, next1, pi1);
232  if (next0 == next1)
233  {
234  /* A B B */
235  vlib_put_next_frame (vm, node, next, n_left_to_next);
236  next = next1;
237  vlib_get_next_frame (vm, node, next, to_next,
238  n_left_to_next);
239  }
240  }
241  }
242  }
243 
244  while (n_left_from > 0 && n_left_to_next > 0)
245  {
246  vlib_buffer_t *p0;
247  ip6_header_t *ip0;
248  u32 pi0, lbi0;
249  ip_lookup_next_t next0;
250  load_balance_t *lb0;
251  ip6_address_t *dst_addr0;
252  u32 fib_index0, flow_hash_config0;
253  const dpo_id_t *dpo0;
254 
255  pi0 = from[0];
256  to_next[0] = pi0;
257 
258  p0 = vlib_get_buffer (vm, pi0);
259 
260  ip0 = vlib_buffer_get_current (p0);
261 
262  dst_addr0 = &ip0->dst_address;
263 
264  fib_index0 =
266  vnet_buffer (p0)->sw_if_index[VLIB_RX]);
267  fib_index0 =
268  (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
269  (u32) ~ 0) ? fib_index0 : vnet_buffer (p0)->sw_if_index[VLIB_TX];
270 
271  lbi0 = ip6_fib_table_fwding_lookup (im, fib_index0, dst_addr0);
272 
273  lb0 = load_balance_get (lbi0);
274  flow_hash_config0 = lb0->lb_hash_config;
275 
276  vnet_buffer (p0)->ip.flow_hash = 0;
277  ASSERT (lb0->lb_n_buckets > 0);
278  ASSERT (is_pow2 (lb0->lb_n_buckets));
279 
280  if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
281  {
282  flow_hash_config0 = lb0->lb_hash_config;
283  vnet_buffer (p0)->ip.flow_hash =
284  ip6_compute_flow_hash (ip0, flow_hash_config0);
285  dpo0 =
287  (vnet_buffer (p0)->ip.flow_hash &
288  (lb0->lb_n_buckets_minus_1)));
289  }
290  else
291  {
292  dpo0 = load_balance_get_bucket_i (lb0, 0);
293  }
294 
295  dpo0 = load_balance_get_bucket_i (lb0,
296  (vnet_buffer (p0)->ip.flow_hash &
297  lb0->lb_n_buckets_minus_1));
298  next0 = dpo0->dpoi_next_node;
299 
300  /* Only process the HBH Option Header if explicitly configured to do so */
301  if (PREDICT_FALSE
302  (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
303  {
304  next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
306  }
307  vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
308 
310  (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
311 
312  from += 1;
313  to_next += 1;
314  n_left_to_next -= 1;
315  n_left_from -= 1;
316 
317  if (PREDICT_FALSE (next0 != next))
318  {
319  n_left_to_next += 1;
320  vlib_put_next_frame (vm, node, next, n_left_to_next);
321  next = next0;
322  vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
323  to_next[0] = pi0;
324  to_next += 1;
325  n_left_to_next -= 1;
326  }
327  }
328 
329  vlib_put_next_frame (vm, node, next, n_left_to_next);
330  }
331 
332  if (node->flags & VLIB_NODE_FLAG_TRACE)
333  ip6_forward_next_trace (vm, node, frame, VLIB_TX);
334 
335  return frame->n_vectors;
336 }
337 
338 static void
340  ip6_main_t * im, u32 fib_index,
342 {
343  ip_lookup_main_t *lm = &im->lookup_main;
345  fib_prefix_t pfx = {
346  .fp_len = a->address_length,
347  .fp_proto = FIB_PROTOCOL_IP6,
348  .fp_addr.ip6 = *address,
349  };
350 
351  if (a->address_length < 128)
352  {
354  &pfx,
359  /* No next-hop address */
360  NULL, sw_if_index,
361  /* invalid FIB index */
362  ~0, 1,
363  /* no label stack */
365  }
366 
367  pfx.fp_len = 128;
368  if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
369  {
370  u32 classify_table_index =
371  lm->classify_table_index_by_sw_if_index[sw_if_index];
372  if (classify_table_index != (u32) ~ 0)
373  {
374  dpo_id_t dpo = DPO_INVALID;
375 
376  dpo_set (&dpo,
377  DPO_CLASSIFY,
379  classify_dpo_create (DPO_PROTO_IP6, classify_table_index));
380 
382  &pfx,
384  FIB_ENTRY_FLAG_NONE, &dpo);
385  dpo_reset (&dpo);
386  }
387  }
388 
389  fib_table_entry_update_one_path (fib_index, &pfx,
394  &pfx.fp_addr,
395  sw_if_index, ~0,
397 }
398 
399 static void
401  u32 fib_index,
402  ip6_address_t * address, u32 address_length)
403 {
404  fib_prefix_t pfx = {
405  .fp_len = address_length,
406  .fp_proto = FIB_PROTOCOL_IP6,
407  .fp_addr.ip6 = *address,
408  };
409 
410  if (pfx.fp_len < 128)
411  {
412  fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
413 
414  }
415 
416  pfx.fp_len = 128;
417  fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
418 }
419 
420 void
421 ip6_sw_interface_enable_disable (u32 sw_if_index, u32 is_enable)
422 {
423  ip6_main_t *im = &ip6_main;
424 
426 
427  /*
428  * enable/disable only on the 1<->0 transition
429  */
430  if (is_enable)
431  {
432  if (1 != ++im->ip_enabled_by_sw_if_index[sw_if_index])
433  return;
434  }
435  else
436  {
437  /* The ref count is 0 when an address is removed from an interface that has
438  * no address - this is not a ciritical error */
439  if (0 == im->ip_enabled_by_sw_if_index[sw_if_index] ||
440  0 != --im->ip_enabled_by_sw_if_index[sw_if_index])
441  return;
442  }
443 
444  vnet_feature_enable_disable ("ip6-unicast", "ip6-drop", sw_if_index,
445  !is_enable, 0, 0);
446 
447  vnet_feature_enable_disable ("ip6-multicast", "ip6-drop", sw_if_index,
448  !is_enable, 0, 0);
449 }
450 
451 /* get first interface address */
454 {
455  ip_lookup_main_t *lm = &im->lookup_main;
456  ip_interface_address_t *ia = 0;
457  ip6_address_t *result = 0;
458 
459  /* *INDENT-OFF* */
460  foreach_ip_interface_address (lm, ia, sw_if_index,
461  1 /* honor unnumbered */,
462  ({
464  result = a;
465  break;
466  }));
467  /* *INDENT-ON* */
468  return result;
469 }
470 
471 clib_error_t *
473  u32 sw_if_index,
474  ip6_address_t * address,
475  u32 address_length, u32 is_del)
476 {
477  vnet_main_t *vnm = vnet_get_main ();
478  ip6_main_t *im = &ip6_main;
479  ip_lookup_main_t *lm = &im->lookup_main;
480  clib_error_t *error;
481  u32 if_address_index;
482  ip6_address_fib_t ip6_af, *addr_fib = 0;
483 
484  vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
485  vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
486 
487  ip6_addr_fib_init (&ip6_af, address,
488  vec_elt (im->fib_index_by_sw_if_index, sw_if_index));
489  vec_add1 (addr_fib, ip6_af);
490 
491  {
492  uword elts_before = pool_elts (lm->if_address_pool);
493 
495  (lm, sw_if_index, addr_fib, address_length, is_del, &if_address_index);
496  if (error)
497  goto done;
498 
499  /* Pool did not grow: add duplicate address. */
500  if (elts_before == pool_elts (lm->if_address_pool))
501  goto done;
502  }
503 
504  ip6_sw_interface_enable_disable (sw_if_index, !is_del);
505 
506  if (is_del)
507  ip6_del_interface_routes (im, ip6_af.fib_index, address, address_length);
508  else
509  ip6_add_interface_routes (vnm, sw_if_index,
510  im, ip6_af.fib_index,
512  if_address_index));
513 
514  {
517  cb->function (im, cb->function_opaque, sw_if_index,
518  address, address_length, if_address_index, is_del);
519  }
520 
521 done:
522  vec_free (addr_fib);
523  return error;
524 }
525 
526 clib_error_t *
528 {
529  ip6_main_t *im = &ip6_main;
531  ip6_address_t *a;
532  u32 is_admin_up, fib_index;
533 
534  /* Fill in lookup tables with default table (0). */
535  vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
536 
538  lookup_main.if_address_pool_index_by_sw_if_index,
539  sw_if_index, ~0);
540 
541  is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
542 
543  fib_index = vec_elt (im->fib_index_by_sw_if_index, sw_if_index);
544 
545  /* *INDENT-OFF* */
546  foreach_ip_interface_address (&im->lookup_main, ia, sw_if_index,
547  0 /* honor unnumbered */,
548  ({
549  a = ip_interface_address_get_address (&im->lookup_main, ia);
550  if (is_admin_up)
551  ip6_add_interface_routes (vnm, sw_if_index,
552  im, fib_index,
553  ia);
554  else
555  ip6_del_interface_routes (im, fib_index,
556  a, ia->address_length);
557  }));
558  /* *INDENT-ON* */
559 
560  return 0;
561 }
562 
564 
565 /* Built-in ip6 unicast rx feature path definition */
566 /* *INDENT-OFF* */
567 VNET_FEATURE_ARC_INIT (ip6_unicast, static) =
568 {
569  .arc_name = "ip6-unicast",
570  .start_nodes = VNET_FEATURES ("ip6-input"),
571  .arc_index_ptr = &ip6_main.lookup_main.ucast_feature_arc_index,
572 };
573 
575 {
576  .arc_name = "ip6-unicast",
577  .node_name = "ip6-flow-classify",
578  .runs_before = VNET_FEATURES ("ip6-inacl"),
579 };
580 
581 VNET_FEATURE_INIT (ip6_inacl, static) =
582 {
583  .arc_name = "ip6-unicast",
584  .node_name = "ip6-inacl",
585  .runs_before = VNET_FEATURES ("ip6-policer-classify"),
586 };
587 
589 {
590  .arc_name = "ip6-unicast",
591  .node_name = "ip6-policer-classify",
592  .runs_before = VNET_FEATURES ("ipsec-input-ip6"),
593 };
594 
595 VNET_FEATURE_INIT (ip6_ipsec, static) =
596 {
597  .arc_name = "ip6-unicast",
598  .node_name = "ipsec-input-ip6",
599  .runs_before = VNET_FEATURES ("l2tp-decap"),
600 };
601 
602 VNET_FEATURE_INIT (ip6_l2tp, static) =
603 {
604  .arc_name = "ip6-unicast",
605  .node_name = "l2tp-decap",
606  .runs_before = VNET_FEATURES ("vpath-input-ip6"),
607 };
608 
609 VNET_FEATURE_INIT (ip6_vpath, static) =
610 {
611  .arc_name = "ip6-unicast",
612  .node_name = "vpath-input-ip6",
613  .runs_before = VNET_FEATURES ("ip6-vxlan-bypass"),
614 };
615 
617 {
618  .arc_name = "ip6-unicast",
619  .node_name = "ip6-vxlan-bypass",
620  .runs_before = VNET_FEATURES ("ip6-lookup"),
621 };
622 
623 VNET_FEATURE_INIT (ip6_drop, static) =
624 {
625  .arc_name = "ip6-unicast",
626  .node_name = "ip6-drop",
627  .runs_before = VNET_FEATURES ("ip6-lookup"),
628 };
629 
630 VNET_FEATURE_INIT (ip6_lookup, static) =
631 {
632  .arc_name = "ip6-unicast",
633  .node_name = "ip6-lookup",
634  .runs_before = 0, /*last feature*/
635 };
636 
637 /* Built-in ip6 multicast rx feature path definition (none now) */
638 VNET_FEATURE_ARC_INIT (ip6_multicast, static) =
639 {
640  .arc_name = "ip6-multicast",
641  .start_nodes = VNET_FEATURES ("ip6-input"),
642  .arc_index_ptr = &ip6_main.lookup_main.mcast_feature_arc_index,
643 };
644 
645 VNET_FEATURE_INIT (ip6_vpath_mc, static) = {
646  .arc_name = "ip6-multicast",
647  .node_name = "vpath-input-ip6",
648  .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
649 };
650 
651 VNET_FEATURE_INIT (ip6_drop_mc, static) = {
652  .arc_name = "ip6-multicast",
653  .node_name = "ip6-drop",
654  .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
655 };
656 
657 VNET_FEATURE_INIT (ip6_mc_lookup, static) = {
658  .arc_name = "ip6-multicast",
659  .node_name = "ip6-mfib-forward-lookup",
660  .runs_before = 0, /* last feature */
661 };
662 
663 /* Built-in ip4 tx feature path definition */
664 VNET_FEATURE_ARC_INIT (ip6_output, static) =
665 {
666  .arc_name = "ip6-output",
667  .start_nodes = VNET_FEATURES ("ip6-rewrite", "ip6-midchain"),
668  .arc_index_ptr = &ip6_main.lookup_main.output_feature_arc_index,
669 };
670 
671 VNET_FEATURE_INIT (ip6_ipsec_output, static) = {
672  .arc_name = "ip6-output",
673  .node_name = "ipsec-output-ip6",
674  .runs_before = VNET_FEATURES ("interface-output"),
675 };
676 
677 VNET_FEATURE_INIT (ip6_interface_output, static) = {
678  .arc_name = "ip6-output",
679  .node_name = "interface-output",
680  .runs_before = 0, /* not before any other features */
681 };
682 /* *INDENT-ON* */
683 
684 clib_error_t *
685 ip6_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
686 {
687  ip6_main_t *im = &ip6_main;
688 
689  vec_validate (im->fib_index_by_sw_if_index, sw_if_index);
690  vec_validate (im->mfib_index_by_sw_if_index, sw_if_index);
691 
692  if (!is_add)
693  {
694  /* Ensure that IPv6 is disabled */
695  ip6_main_t *im6 = &ip6_main;
696  ip_lookup_main_t *lm6 = &im6->lookup_main;
697  ip_interface_address_t *ia = 0;
698  ip6_address_t *address;
699  vlib_main_t *vm = vlib_get_main ();
700 
701  ip6_neighbor_sw_interface_add_del (vnm, sw_if_index, 0 /* is_add */ );
702  /* *INDENT-OFF* */
703  foreach_ip_interface_address (lm6, ia, sw_if_index, 1 /* honor unnumbered */,
704  ({
705  address = ip_interface_address_get_address (lm6, ia);
706  ip6_add_del_interface_address(vm, sw_if_index, address, ia->address_length, 1);
707  }));
708  /* *INDENT-ON* */
709  ip6_mfib_interface_enable_disable (sw_if_index, 0);
710  }
711 
712  vnet_feature_enable_disable ("ip6-unicast", "ip6-drop", sw_if_index,
713  is_add, 0, 0);
714 
715  vnet_feature_enable_disable ("ip6-multicast", "ip6-drop", sw_if_index,
716  is_add, 0, 0);
717 
718  return /* no error */ 0;
719 }
720 
722 
723 static uword
725  vlib_node_runtime_t * node, vlib_frame_t * frame)
726 {
727  return ip6_lookup_inline (vm, node, frame);
728 }
729 
730 static u8 *format_ip6_lookup_trace (u8 * s, va_list * args);
731 
732 /* *INDENT-OFF* */
734 {
735  .function = ip6_lookup,
736  .name = "ip6-lookup",
737  .vector_size = sizeof (u32),
738  .format_trace = format_ip6_lookup_trace,
739  .n_next_nodes = IP6_LOOKUP_N_NEXT,
740  .next_nodes = IP6_LOOKUP_NEXT_NODES,
741 };
742 /* *INDENT-ON* */
743 
745 
748  vlib_node_runtime_t * node, vlib_frame_t * frame)
749 {
751  u32 n_left_from, n_left_to_next, *from, *to_next;
752  ip_lookup_next_t next;
753  u32 thread_index = vlib_get_thread_index ();
754  ip6_main_t *im = &ip6_main;
755 
756  from = vlib_frame_vector_args (frame);
757  n_left_from = frame->n_vectors;
758  next = node->cached_next_index;
759 
760  if (node->flags & VLIB_NODE_FLAG_TRACE)
761  ip6_forward_next_trace (vm, node, frame, VLIB_TX);
762 
763  while (n_left_from > 0)
764  {
765  vlib_get_next_frame (vm, node, next, to_next, n_left_to_next);
766 
767 
768  while (n_left_from >= 4 && n_left_to_next >= 2)
769  {
770  ip_lookup_next_t next0, next1;
771  const load_balance_t *lb0, *lb1;
772  vlib_buffer_t *p0, *p1;
773  u32 pi0, lbi0, hc0, pi1, lbi1, hc1;
774  const ip6_header_t *ip0, *ip1;
775  const dpo_id_t *dpo0, *dpo1;
776 
777  /* Prefetch next iteration. */
778  {
779  vlib_buffer_t *p2, *p3;
780 
781  p2 = vlib_get_buffer (vm, from[2]);
782  p3 = vlib_get_buffer (vm, from[3]);
783 
784  vlib_prefetch_buffer_header (p2, STORE);
785  vlib_prefetch_buffer_header (p3, STORE);
786 
787  CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
788  CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
789  }
790 
791  pi0 = to_next[0] = from[0];
792  pi1 = to_next[1] = from[1];
793 
794  from += 2;
795  n_left_from -= 2;
796  to_next += 2;
797  n_left_to_next -= 2;
798 
799  p0 = vlib_get_buffer (vm, pi0);
800  p1 = vlib_get_buffer (vm, pi1);
801 
802  ip0 = vlib_buffer_get_current (p0);
803  ip1 = vlib_buffer_get_current (p1);
804  lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
805  lbi1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
806 
807  lb0 = load_balance_get (lbi0);
808  lb1 = load_balance_get (lbi1);
809 
810  /*
811  * this node is for via FIBs we can re-use the hash value from the
812  * to node if present.
813  * We don't want to use the same hash value at each level in the recursion
814  * graph as that would lead to polarisation
815  */
816  hc0 = hc1 = 0;
817 
818  if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
819  {
820  if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
821  {
822  hc0 = vnet_buffer (p0)->ip.flow_hash =
823  vnet_buffer (p0)->ip.flow_hash >> 1;
824  }
825  else
826  {
827  hc0 = vnet_buffer (p0)->ip.flow_hash =
829  }
830  dpo0 =
832  (hc0 &
833  lb0->lb_n_buckets_minus_1));
834  }
835  else
836  {
837  dpo0 = load_balance_get_bucket_i (lb0, 0);
838  }
839  if (PREDICT_FALSE (lb1->lb_n_buckets > 1))
840  {
841  if (PREDICT_TRUE (vnet_buffer (p1)->ip.flow_hash))
842  {
843  hc1 = vnet_buffer (p1)->ip.flow_hash =
844  vnet_buffer (p1)->ip.flow_hash >> 1;
845  }
846  else
847  {
848  hc1 = vnet_buffer (p1)->ip.flow_hash =
850  }
851  dpo1 =
853  (hc1 &
854  lb1->lb_n_buckets_minus_1));
855  }
856  else
857  {
858  dpo1 = load_balance_get_bucket_i (lb1, 0);
859  }
860 
861  next0 = dpo0->dpoi_next_node;
862  next1 = dpo1->dpoi_next_node;
863 
864  /* Only process the HBH Option Header if explicitly configured to do so */
865  if (PREDICT_FALSE
866  (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
867  {
868  next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
870  }
871  /* Only process the HBH Option Header if explicitly configured to do so */
872  if (PREDICT_FALSE
873  (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
874  {
875  next1 = (dpo_is_adj (dpo1) && im->hbh_enabled) ?
877  }
878 
879  vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
880  vnet_buffer (p1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
881 
883  (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
885  (cm, thread_index, lbi1, 1, vlib_buffer_length_in_chain (vm, p1));
886 
887  vlib_validate_buffer_enqueue_x2 (vm, node, next,
888  to_next, n_left_to_next,
889  pi0, pi1, next0, next1);
890  }
891 
892  while (n_left_from > 0 && n_left_to_next > 0)
893  {
894  ip_lookup_next_t next0;
895  const load_balance_t *lb0;
896  vlib_buffer_t *p0;
897  u32 pi0, lbi0, hc0;
898  const ip6_header_t *ip0;
899  const dpo_id_t *dpo0;
900 
901  pi0 = from[0];
902  to_next[0] = pi0;
903  from += 1;
904  to_next += 1;
905  n_left_to_next -= 1;
906  n_left_from -= 1;
907 
908  p0 = vlib_get_buffer (vm, pi0);
909 
910  ip0 = vlib_buffer_get_current (p0);
911  lbi0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
912 
913  lb0 = load_balance_get (lbi0);
914 
915  hc0 = 0;
916  if (PREDICT_FALSE (lb0->lb_n_buckets > 1))
917  {
918  if (PREDICT_TRUE (vnet_buffer (p0)->ip.flow_hash))
919  {
920  hc0 = vnet_buffer (p0)->ip.flow_hash =
921  vnet_buffer (p0)->ip.flow_hash >> 1;
922  }
923  else
924  {
925  hc0 = vnet_buffer (p0)->ip.flow_hash =
927  }
928  dpo0 =
930  (hc0 &
931  lb0->lb_n_buckets_minus_1));
932  }
933  else
934  {
935  dpo0 = load_balance_get_bucket_i (lb0, 0);
936  }
937 
938  next0 = dpo0->dpoi_next_node;
939  vnet_buffer (p0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
940 
941  /* Only process the HBH Option Header if explicitly configured to do so */
942  if (PREDICT_FALSE
943  (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
944  {
945  next0 = (dpo_is_adj (dpo0) && im->hbh_enabled) ?
947  }
948 
950  (cm, thread_index, lbi0, 1, vlib_buffer_length_in_chain (vm, p0));
951 
952  vlib_validate_buffer_enqueue_x1 (vm, node, next,
953  to_next, n_left_to_next,
954  pi0, next0);
955  }
956 
957  vlib_put_next_frame (vm, node, next, n_left_to_next);
958  }
959 
960  return frame->n_vectors;
961 }
962 
963 /* *INDENT-OFF* */
965 {
966  .function = ip6_load_balance,
967  .name = "ip6-load-balance",
968  .vector_size = sizeof (u32),
969  .sibling_of = "ip6-lookup",
970  .format_trace = format_ip6_lookup_trace,
971 };
972 /* *INDENT-ON* */
973 
975 
976 typedef struct
977 {
978  /* Adjacency taken. */
982 
983  /* Packet data, possibly *after* rewrite. */
984  u8 packet_data[128 - 1 * sizeof (u32)];
985 }
987 
988 u8 *
989 format_ip6_forward_next_trace (u8 * s, va_list * args)
990 {
991  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
992  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
993  ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
994  uword indent = format_get_indent (s);
995 
996  s = format (s, "%U%U",
997  format_white_space, indent,
998  format_ip6_header, t->packet_data, sizeof (t->packet_data));
999  return s;
1000 }
1001 
1002 static u8 *
1003 format_ip6_lookup_trace (u8 * s, va_list * args)
1004 {
1005  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1006  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1007  ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
1008  uword indent = format_get_indent (s);
1009 
1010  s = format (s, "fib %d dpo-idx %d flow hash: 0x%08x",
1011  t->fib_index, t->adj_index, t->flow_hash);
1012  s = format (s, "\n%U%U",
1013  format_white_space, indent,
1014  format_ip6_header, t->packet_data, sizeof (t->packet_data));
1015  return s;
1016 }
1017 
1018 
1019 static u8 *
1020 format_ip6_rewrite_trace (u8 * s, va_list * args)
1021 {
1022  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1023  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1024  ip6_forward_next_trace_t *t = va_arg (*args, ip6_forward_next_trace_t *);
1025  uword indent = format_get_indent (s);
1026 
1027  s = format (s, "tx_sw_if_index %d adj-idx %d : %U flow hash: 0x%08x",
1030  s = format (s, "\n%U%U",
1031  format_white_space, indent,
1033  t->adj_index, t->packet_data, sizeof (t->packet_data));
1034  return s;
1035 }
1036 
1037 /* Common trace function for all ip6-forward next nodes. */
1038 void
1040  vlib_node_runtime_t * node,
1041  vlib_frame_t * frame, vlib_rx_or_tx_t which_adj_index)
1042 {
1043  u32 *from, n_left;
1044  ip6_main_t *im = &ip6_main;
1045 
1046  n_left = frame->n_vectors;
1047  from = vlib_frame_vector_args (frame);
1048 
1049  while (n_left >= 4)
1050  {
1051  u32 bi0, bi1;
1052  vlib_buffer_t *b0, *b1;
1053  ip6_forward_next_trace_t *t0, *t1;
1054 
1055  /* Prefetch next iteration. */
1056  vlib_prefetch_buffer_with_index (vm, from[2], LOAD);
1057  vlib_prefetch_buffer_with_index (vm, from[3], LOAD);
1058 
1059  bi0 = from[0];
1060  bi1 = from[1];
1061 
1062  b0 = vlib_get_buffer (vm, bi0);
1063  b1 = vlib_get_buffer (vm, bi1);
1064 
1065  if (b0->flags & VLIB_BUFFER_IS_TRACED)
1066  {
1067  t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1068  t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1069  t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1070  t0->fib_index =
1071  (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1072  (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1074  vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1075 
1076  clib_memcpy (t0->packet_data,
1078  sizeof (t0->packet_data));
1079  }
1080  if (b1->flags & VLIB_BUFFER_IS_TRACED)
1081  {
1082  t1 = vlib_add_trace (vm, node, b1, sizeof (t1[0]));
1083  t1->adj_index = vnet_buffer (b1)->ip.adj_index[which_adj_index];
1084  t1->flow_hash = vnet_buffer (b1)->ip.flow_hash;
1085  t1->fib_index =
1086  (vnet_buffer (b1)->sw_if_index[VLIB_TX] !=
1087  (u32) ~ 0) ? vnet_buffer (b1)->sw_if_index[VLIB_TX] :
1089  vnet_buffer (b1)->sw_if_index[VLIB_RX]);
1090 
1091  clib_memcpy (t1->packet_data,
1093  sizeof (t1->packet_data));
1094  }
1095  from += 2;
1096  n_left -= 2;
1097  }
1098 
1099  while (n_left >= 1)
1100  {
1101  u32 bi0;
1102  vlib_buffer_t *b0;
1103  ip6_forward_next_trace_t *t0;
1104 
1105  bi0 = from[0];
1106 
1107  b0 = vlib_get_buffer (vm, bi0);
1108 
1109  if (b0->flags & VLIB_BUFFER_IS_TRACED)
1110  {
1111  t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
1112  t0->adj_index = vnet_buffer (b0)->ip.adj_index[which_adj_index];
1113  t0->flow_hash = vnet_buffer (b0)->ip.flow_hash;
1114  t0->fib_index =
1115  (vnet_buffer (b0)->sw_if_index[VLIB_TX] !=
1116  (u32) ~ 0) ? vnet_buffer (b0)->sw_if_index[VLIB_TX] :
1118  vnet_buffer (b0)->sw_if_index[VLIB_RX]);
1119 
1120  clib_memcpy (t0->packet_data,
1122  sizeof (t0->packet_data));
1123  }
1124  from += 1;
1125  n_left -= 1;
1126  }
1127 }
1128 
1129 static uword
1131  vlib_node_runtime_t * node,
1132  vlib_frame_t * frame, ip6_error_t error_code)
1133 {
1134  u32 *buffers = vlib_frame_vector_args (frame);
1135  uword n_packets = frame->n_vectors;
1136 
1137  vlib_error_drop_buffers (vm, node, buffers,
1138  /* stride */ 1,
1139  n_packets,
1140  /* next */ 0,
1141  ip6_input_node.index, error_code);
1142 
1143  if (node->flags & VLIB_NODE_FLAG_TRACE)
1144  ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1145 
1146  return n_packets;
1147 }
1148 
1149 static uword
1151 {
1152  return ip6_drop_or_punt (vm, node, frame, IP6_ERROR_ADJACENCY_DROP);
1153 }
1154 
1155 static uword
1157 {
1158  return ip6_drop_or_punt (vm, node, frame, IP6_ERROR_ADJACENCY_PUNT);
1159 }
1160 
1161 /* *INDENT-OFF* */
1163 {
1164  .function = ip6_drop,
1165  .name = "ip6-drop",
1166  .vector_size = sizeof (u32),
1167  .format_trace = format_ip6_forward_next_trace,
1168  .n_next_nodes = 1,
1169  .next_nodes =
1170  {
1171  [0] = "error-drop",},
1172 };
1173 /* *INDENT-ON* */
1174 
1176 
1177 /* *INDENT-OFF* */
1179 {
1180  .function = ip6_punt,
1181  .name = "ip6-punt",
1182  .vector_size = sizeof (u32),
1183  .format_trace = format_ip6_forward_next_trace,
1184  .n_next_nodes = 1,
1185  .next_nodes =
1186  {
1187  [0] = "error-punt",},
1188 };
1189 /* *INDENT-ON* */
1190 
1192 
1193 /* Compute TCP/UDP/ICMP6 checksum in software. */
1194 u16
1196  ip6_header_t * ip0, int *bogus_lengthp)
1197 {
1198  ip_csum_t sum0;
1199  u16 sum16, payload_length_host_byte_order;
1200  u32 i, n_this_buffer, n_bytes_left;
1201  u32 headers_size = sizeof (ip0[0]);
1202  void *data_this_buffer;
1203 
1204  ASSERT (bogus_lengthp);
1205  *bogus_lengthp = 0;
1206 
1207  /* Initialize checksum with ip header. */
1208  sum0 = ip0->payload_length + clib_host_to_net_u16 (ip0->protocol);
1209  payload_length_host_byte_order = clib_net_to_host_u16 (ip0->payload_length);
1210  data_this_buffer = (void *) (ip0 + 1);
1211 
1212  for (i = 0; i < ARRAY_LEN (ip0->src_address.as_uword); i++)
1213  {
1214  sum0 = ip_csum_with_carry (sum0,
1215  clib_mem_unaligned (&ip0->
1216  src_address.as_uword[i],
1217  uword));
1218  sum0 =
1219  ip_csum_with_carry (sum0,
1221  uword));
1222  }
1223 
1224  /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets)
1225  * or UDP-Ping packets */
1226  if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
1227  {
1228  u32 skip_bytes;
1229  ip6_hop_by_hop_ext_t *ext_hdr =
1230  (ip6_hop_by_hop_ext_t *) data_this_buffer;
1231 
1232  /* validate really icmp6 next */
1233  ASSERT ((ext_hdr->next_hdr == IP_PROTOCOL_ICMP6)
1234  || (ext_hdr->next_hdr == IP_PROTOCOL_UDP));
1235 
1236  skip_bytes = 8 * (1 + ext_hdr->n_data_u64s);
1237  data_this_buffer = (void *) ((u8 *) data_this_buffer + skip_bytes);
1238 
1239  payload_length_host_byte_order -= skip_bytes;
1240  headers_size += skip_bytes;
1241  }
1242 
1243  n_bytes_left = n_this_buffer = payload_length_host_byte_order;
1244  if (p0 && n_this_buffer + headers_size > p0->current_length)
1245  n_this_buffer =
1246  p0->current_length >
1247  headers_size ? p0->current_length - headers_size : 0;
1248  while (1)
1249  {
1250  sum0 = ip_incremental_checksum (sum0, data_this_buffer, n_this_buffer);
1251  n_bytes_left -= n_this_buffer;
1252  if (n_bytes_left == 0)
1253  break;
1254 
1255  if (!(p0->flags & VLIB_BUFFER_NEXT_PRESENT))
1256  {
1257  *bogus_lengthp = 1;
1258  return 0xfefe;
1259  }
1260  p0 = vlib_get_buffer (vm, p0->next_buffer);
1261  data_this_buffer = vlib_buffer_get_current (p0);
1262  n_this_buffer = p0->current_length;
1263  }
1264 
1265  sum16 = ~ip_csum_fold (sum0);
1266 
1267  return sum16;
1268 }
1269 
1270 u32
1272 {
1274  udp_header_t *udp0;
1275  u16 sum16;
1276  int bogus_length;
1277 
1278  /* some icmp packets may come with a "router alert" hop-by-hop extension header (e.g., mldv2 packets) */
1279  ASSERT (ip0->protocol == IP_PROTOCOL_TCP
1280  || ip0->protocol == IP_PROTOCOL_ICMP6
1281  || ip0->protocol == IP_PROTOCOL_UDP
1282  || ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS);
1283 
1284  udp0 = (void *) (ip0 + 1);
1285  if (ip0->protocol == IP_PROTOCOL_UDP && udp0->checksum == 0)
1286  {
1289  return p0->flags;
1290  }
1291 
1292  sum16 = ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0, &bogus_length);
1293 
1295  | ((sum16 == 0) << LOG2_IP_BUFFER_L4_CHECKSUM_CORRECT));
1296 
1297  return p0->flags;
1298 }
1299 
1300 /**
1301  * @brief returns number of links on which src is reachable.
1302  */
1303 always_inline int
1305 {
1306  const load_balance_t *lb0;
1307  index_t lbi;
1308 
1310  vnet_buffer
1311  (b)->sw_if_index[VLIB_RX],
1312  &i->src_address);
1313 
1314  lb0 = load_balance_get (lbi);
1315 
1316  return (fib_urpf_check_size (lb0->lb_urpf));
1317 }
1318 
1319 static uword
1321 {
1322  ip6_main_t *im = &ip6_main;
1323  ip_lookup_main_t *lm = &im->lookup_main;
1324  ip_local_next_t next_index;
1325  u32 *from, *to_next, n_left_from, n_left_to_next;
1326  vlib_node_runtime_t *error_node =
1328 
1329  from = vlib_frame_vector_args (frame);
1330  n_left_from = frame->n_vectors;
1331  next_index = node->cached_next_index;
1332 
1333  if (node->flags & VLIB_NODE_FLAG_TRACE)
1334  ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1335 
1336  while (n_left_from > 0)
1337  {
1338  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1339 
1340  while (n_left_from >= 4 && n_left_to_next >= 2)
1341  {
1342  vlib_buffer_t *p0, *p1;
1343  ip6_header_t *ip0, *ip1;
1344  udp_header_t *udp0, *udp1;
1345  u32 pi0, ip_len0, udp_len0, flags0, next0;
1346  u32 pi1, ip_len1, udp_len1, flags1, next1;
1347  i32 len_diff0, len_diff1;
1348  u8 error0, type0, good_l4_checksum0;
1349  u8 error1, type1, good_l4_checksum1;
1350  u32 udp_offset0, udp_offset1;
1351 
1352  pi0 = to_next[0] = from[0];
1353  pi1 = to_next[1] = from[1];
1354  from += 2;
1355  n_left_from -= 2;
1356  to_next += 2;
1357  n_left_to_next -= 2;
1358 
1359  p0 = vlib_get_buffer (vm, pi0);
1360  p1 = vlib_get_buffer (vm, pi1);
1361 
1362  ip0 = vlib_buffer_get_current (p0);
1363  ip1 = vlib_buffer_get_current (p1);
1364 
1365  vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
1366  vnet_buffer (p1)->ip.start_of_ip_header = p1->current_data;
1367 
1368  type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
1369  type1 = lm->builtin_protocol_by_ip_protocol[ip1->protocol];
1370 
1371  next0 = lm->local_next_by_ip_protocol[ip0->protocol];
1372  next1 = lm->local_next_by_ip_protocol[ip1->protocol];
1373 
1374  flags0 = p0->flags;
1375  flags1 = p1->flags;
1376 
1377  good_l4_checksum0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1378  good_l4_checksum1 = (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1379  len_diff0 = 0;
1380  len_diff1 = 0;
1381 
1382  if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p0, ip0,
1383  IP_PROTOCOL_UDP,
1384  &udp_offset0)))
1385  {
1386  udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
1387  /* Don't verify UDP checksum for packets with explicit zero checksum. */
1388  good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
1389  && udp0->checksum == 0;
1390  /* Verify UDP length. */
1391  ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1392  udp_len0 = clib_net_to_host_u16 (udp0->length);
1393  len_diff0 = ip_len0 - udp_len0;
1394  }
1395  if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p1, ip1,
1396  IP_PROTOCOL_UDP,
1397  &udp_offset1)))
1398  {
1399  udp1 = (udp_header_t *) ((u8 *) ip1 + udp_offset1);
1400  /* Don't verify UDP checksum for packets with explicit zero checksum. */
1401  good_l4_checksum1 |= type1 == IP_BUILTIN_PROTOCOL_UDP
1402  && udp1->checksum == 0;
1403  /* Verify UDP length. */
1404  ip_len1 = clib_net_to_host_u16 (ip1->payload_length);
1405  udp_len1 = clib_net_to_host_u16 (udp1->length);
1406  len_diff1 = ip_len1 - udp_len1;
1407  }
1408 
1409  good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
1410  good_l4_checksum1 |= type1 == IP_BUILTIN_PROTOCOL_UNKNOWN;
1411 
1412  len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1413  len_diff1 = type1 == IP_BUILTIN_PROTOCOL_UDP ? len_diff1 : 0;
1414 
1416  && !good_l4_checksum0
1417  && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED)))
1418  {
1419  flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
1420  good_l4_checksum0 =
1421  (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1422  }
1424  && !good_l4_checksum1
1425  && !(flags1 & IP_BUFFER_L4_CHECKSUM_COMPUTED)))
1426  {
1427  flags1 = ip6_tcp_udp_icmp_validate_checksum (vm, p1);
1428  good_l4_checksum1 =
1429  (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1430  }
1431 
1432  error0 = error1 = IP6_ERROR_UNKNOWN_PROTOCOL;
1433 
1434  error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1435  error1 = len_diff1 < 0 ? IP6_ERROR_UDP_LENGTH : error1;
1436 
1437  ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1438  IP6_ERROR_UDP_CHECKSUM);
1439  ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1440  IP6_ERROR_ICMP_CHECKSUM);
1441  error0 =
1442  (!good_l4_checksum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
1443  error1 =
1444  (!good_l4_checksum1 ? IP6_ERROR_UDP_CHECKSUM + type1 : error1);
1445 
1446  /* Drop packets from unroutable hosts. */
1447  /* If this is a neighbor solicitation (ICMP), skip source RPF check */
1448  if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1449  type0 != IP_BUILTIN_PROTOCOL_ICMP &&
1451  {
1452  error0 = (!ip6_urpf_loose_check (im, p0, ip0)
1453  ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
1454  }
1455  if (error1 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1456  type1 != IP_BUILTIN_PROTOCOL_ICMP &&
1458  {
1459  error1 = (!ip6_urpf_loose_check (im, p1, ip1)
1460  ? IP6_ERROR_SRC_LOOKUP_MISS : error1);
1461  }
1462 
1463  next0 =
1464  error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1465  next1 =
1466  error1 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
1467 
1468  p0->error = error_node->errors[error0];
1469  p1->error = error_node->errors[error1];
1470 
1471  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1472  to_next, n_left_to_next,
1473  pi0, pi1, next0, next1);
1474  }
1475 
1476  while (n_left_from > 0 && n_left_to_next > 0)
1477  {
1478  vlib_buffer_t *p0;
1479  ip6_header_t *ip0;
1480  udp_header_t *udp0;
1481  u32 pi0, ip_len0, udp_len0, flags0, next0;
1482  i32 len_diff0;
1483  u8 error0, type0, good_l4_checksum0;
1484  u32 udp_offset0;
1485 
1486  pi0 = to_next[0] = from[0];
1487  from += 1;
1488  n_left_from -= 1;
1489  to_next += 1;
1490  n_left_to_next -= 1;
1491 
1492  p0 = vlib_get_buffer (vm, pi0);
1493 
1494  ip0 = vlib_buffer_get_current (p0);
1495 
1496  vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
1497 
1498  type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
1499  next0 = lm->local_next_by_ip_protocol[ip0->protocol];
1500 
1501  flags0 = p0->flags;
1502 
1503  good_l4_checksum0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1504  len_diff0 = 0;
1505 
1506  if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p0, ip0,
1507  IP_PROTOCOL_UDP,
1508  &udp_offset0)))
1509  {
1510  udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
1511  /* Don't verify UDP checksum for packets with explicit zero checksum. */
1512  good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
1513  && udp0->checksum == 0;
1514  /* Verify UDP length. */
1515  ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1516  udp_len0 = clib_net_to_host_u16 (udp0->length);
1517  len_diff0 = ip_len0 - udp_len0;
1518  }
1519 
1520  good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
1521  len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1522 
1524  && !good_l4_checksum0
1525  && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED)))
1526  {
1527  flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
1528  good_l4_checksum0 =
1529  (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1530  }
1531 
1532  error0 = IP6_ERROR_UNKNOWN_PROTOCOL;
1533 
1534  error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1535 
1536  ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1537  IP6_ERROR_UDP_CHECKSUM);
1538  ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1539  IP6_ERROR_ICMP_CHECKSUM);
1540  error0 =
1541  (!good_l4_checksum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
1542 
1543  /* If this is a neighbor solicitation (ICMP), skip source RPF check */
1544  if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1545  type0 != IP_BUILTIN_PROTOCOL_ICMP &&
1547  {
1548  error0 = (!ip6_urpf_loose_check (im, p0, ip0)
1549  ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
1550  }
1551 
1552  next0 =
1553  error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1554 
1555  p0->error = error_node->errors[error0];
1556 
1557  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1558  to_next, n_left_to_next,
1559  pi0, next0);
1560  }
1561 
1562  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1563  }
1564 
1565  return frame->n_vectors;
1566 }
1567 
1568 /* *INDENT-OFF* */
1570 {
1571  .function = ip6_local,
1572  .name = "ip6-local",
1573  .vector_size = sizeof (u32),
1574  .format_trace = format_ip6_forward_next_trace,
1575  .n_next_nodes = IP_LOCAL_N_NEXT,
1576  .next_nodes =
1577  {
1578  [IP_LOCAL_NEXT_DROP] = "error-drop",
1579  [IP_LOCAL_NEXT_PUNT] = "error-punt",
1580  [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
1581  [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
1582  },
1583 };
1584 /* *INDENT-ON* */
1585 
1587 
1588 void
1589 ip6_register_protocol (u32 protocol, u32 node_index)
1590 {
1591  vlib_main_t *vm = vlib_get_main ();
1592  ip6_main_t *im = &ip6_main;
1593  ip_lookup_main_t *lm = &im->lookup_main;
1594 
1595  ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1596  lm->local_next_by_ip_protocol[protocol] =
1597  vlib_node_add_next (vm, ip6_local_node.index, node_index);
1598 }
1599 
1600 typedef enum
1601 {
1606 
1607 typedef enum
1608 {
1613 
1614 static uword
1616  vlib_node_runtime_t * node,
1617  vlib_frame_t * frame, int is_glean)
1618 {
1619  vnet_main_t *vnm = vnet_get_main ();
1620  ip6_main_t *im = &ip6_main;
1621  ip_lookup_main_t *lm = &im->lookup_main;
1622  u32 *from, *to_next_drop;
1623  uword n_left_from, n_left_to_next_drop;
1624  static f64 time_last_seed_change = -1e100;
1625  static u32 hash_seeds[3];
1626  static uword hash_bitmap[256 / BITS (uword)];
1627  f64 time_now;
1628  int bogus_length;
1629 
1630  if (node->flags & VLIB_NODE_FLAG_TRACE)
1631  ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1632 
1633  time_now = vlib_time_now (vm);
1634  if (time_now - time_last_seed_change > 1e-3)
1635  {
1636  uword i;
1638  sizeof (hash_seeds));
1639  for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
1640  hash_seeds[i] = r[i];
1641 
1642  /* Mark all hash keys as been not-seen before. */
1643  for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
1644  hash_bitmap[i] = 0;
1645 
1646  time_last_seed_change = time_now;
1647  }
1648 
1649  from = vlib_frame_vector_args (frame);
1650  n_left_from = frame->n_vectors;
1651 
1652  while (n_left_from > 0)
1653  {
1655  to_next_drop, n_left_to_next_drop);
1656 
1657  while (n_left_from > 0 && n_left_to_next_drop > 0)
1658  {
1659  vlib_buffer_t *p0;
1660  ip6_header_t *ip0;
1661  u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
1662  uword bm0;
1663  ip_adjacency_t *adj0;
1664  vnet_hw_interface_t *hw_if0;
1665  u32 next0;
1666 
1667  pi0 = from[0];
1668 
1669  p0 = vlib_get_buffer (vm, pi0);
1670 
1671  adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1672 
1673  ip0 = vlib_buffer_get_current (p0);
1674 
1675  adj0 = adj_get (adj_index0);
1676 
1677  if (!is_glean)
1678  {
1679  ip0->dst_address.as_u64[0] =
1680  adj0->sub_type.nbr.next_hop.ip6.as_u64[0];
1681  ip0->dst_address.as_u64[1] =
1682  adj0->sub_type.nbr.next_hop.ip6.as_u64[1];
1683  }
1684 
1685  a0 = hash_seeds[0];
1686  b0 = hash_seeds[1];
1687  c0 = hash_seeds[2];
1688 
1689  sw_if_index0 = adj0->rewrite_header.sw_if_index;
1690  vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1691 
1692  a0 ^= sw_if_index0;
1693  b0 ^= ip0->dst_address.as_u32[0];
1694  c0 ^= ip0->dst_address.as_u32[1];
1695 
1696  hash_v3_mix32 (a0, b0, c0);
1697 
1698  b0 ^= ip0->dst_address.as_u32[2];
1699  c0 ^= ip0->dst_address.as_u32[3];
1700 
1701  hash_v3_finalize32 (a0, b0, c0);
1702 
1703  c0 &= BITS (hash_bitmap) - 1;
1704  c0 = c0 / BITS (uword);
1705  m0 = (uword) 1 << (c0 % BITS (uword));
1706 
1707  bm0 = hash_bitmap[c0];
1708  drop0 = (bm0 & m0) != 0;
1709 
1710  /* Mark it as seen. */
1711  hash_bitmap[c0] = bm0 | m0;
1712 
1713  from += 1;
1714  n_left_from -= 1;
1715  to_next_drop[0] = pi0;
1716  to_next_drop += 1;
1717  n_left_to_next_drop -= 1;
1718 
1719  hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1720 
1721  /* If the interface is link-down, drop the pkt */
1722  if (!(hw_if0->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
1723  drop0 = 1;
1724 
1725  p0->error =
1728  if (drop0)
1729  continue;
1730 
1731  /*
1732  * the adj has been updated to a rewrite but the node the DPO that got
1733  * us here hasn't - yet. no big deal. we'll drop while we wait.
1734  */
1736  continue;
1737 
1738  {
1739  u32 bi0 = 0;
1740  icmp6_neighbor_solicitation_header_t *h0;
1741  vlib_buffer_t *b0;
1742 
1744  (vm, &im->discover_neighbor_packet_template, &bi0);
1745 
1746  /*
1747  * Build ethernet header.
1748  * Choose source address based on destination lookup
1749  * adjacency.
1750  */
1752  sw_if_index0,
1753  &h0->ip.src_address))
1754  {
1755  /* There is no address on the interface */
1756  p0->error =
1758  vlib_buffer_free (vm, &bi0, 1);
1759  continue;
1760  }
1761 
1762  /*
1763  * Destination address is a solicited node multicast address.
1764  * We need to fill in
1765  * the low 24 bits with low 24 bits of target's address.
1766  */
1767  h0->ip.dst_address.as_u8[13] = ip0->dst_address.as_u8[13];
1768  h0->ip.dst_address.as_u8[14] = ip0->dst_address.as_u8[14];
1769  h0->ip.dst_address.as_u8[15] = ip0->dst_address.as_u8[15];
1770 
1771  h0->neighbor.target_address = ip0->dst_address;
1772 
1773  clib_memcpy (h0->link_layer_option.ethernet_address,
1774  hw_if0->hw_address, vec_len (hw_if0->hw_address));
1775 
1776  /* $$$$ appears we need this; why is the checksum non-zero? */
1777  h0->neighbor.icmp.checksum = 0;
1778  h0->neighbor.icmp.checksum =
1779  ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h0->ip,
1780  &bogus_length);
1781 
1782  ASSERT (bogus_length == 0);
1783 
1784  vlib_buffer_copy_trace_flag (vm, p0, bi0);
1785  b0 = vlib_get_buffer (vm, bi0);
1786  vnet_buffer (b0)->sw_if_index[VLIB_TX]
1787  = vnet_buffer (p0)->sw_if_index[VLIB_TX];
1788 
1789  /* Add rewrite/encap string. */
1790  vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
1791  vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
1792 
1794 
1795  vlib_set_next_frame_buffer (vm, node, next0, bi0);
1796  }
1797  }
1798 
1800  n_left_to_next_drop);
1801  }
1802 
1803  return frame->n_vectors;
1804 }
1805 
1806 static uword
1808  vlib_node_runtime_t * node, vlib_frame_t * frame)
1809 {
1810  return (ip6_discover_neighbor_inline (vm, node, frame, 0));
1811 }
1812 
1813 static uword
1815 {
1816  return (ip6_discover_neighbor_inline (vm, node, frame, 1));
1817 }
1818 
1820  [IP6_DISCOVER_NEIGHBOR_ERROR_DROP] = "address overflow drops",
1821  [IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT] = "neighbor solicitations sent",
1823  = "no source address for ND solicitation",
1824 };
1825 
1826 /* *INDENT-OFF* */
1828 {
1829  .function = ip6_discover_neighbor,
1830  .name = "ip6-discover-neighbor",
1831  .vector_size = sizeof (u32),
1832  .format_trace = format_ip6_forward_next_trace,
1833  .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
1834  .error_strings = ip6_discover_neighbor_error_strings,
1835  .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
1836  .next_nodes =
1837  {
1838  [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "error-drop",
1839  [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
1840  },
1841 };
1842 /* *INDENT-ON* */
1843 
1844 /* *INDENT-OFF* */
1846 {
1847  .function = ip6_glean,
1848  .name = "ip6-glean",
1849  .vector_size = sizeof (u32),
1850  .format_trace = format_ip6_forward_next_trace,
1851  .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
1852  .error_strings = ip6_discover_neighbor_error_strings,
1853  .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
1854  .next_nodes =
1855  {
1856  [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "error-drop",
1857  [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
1858  },
1859 };
1860 /* *INDENT-ON* */
1861 
1862 clib_error_t *
1864 {
1865  vnet_main_t *vnm = vnet_get_main ();
1866  ip6_main_t *im = &ip6_main;
1867  icmp6_neighbor_solicitation_header_t *h;
1868  ip6_address_t *src;
1870  ip_adjacency_t *adj;
1872  vnet_sw_interface_t *si;
1873  vlib_buffer_t *b;
1874  adj_index_t ai;
1875  u32 bi = 0;
1876  int bogus_length;
1877 
1878  si = vnet_get_sw_interface (vnm, sw_if_index);
1879 
1881  {
1882  return clib_error_return (0, "%U: interface %U down",
1883  format_ip6_address, dst,
1885  sw_if_index);
1886  }
1887 
1888  src =
1889  ip6_interface_address_matching_destination (im, dst, sw_if_index, &ia);
1890  if (!src)
1891  {
1892  vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
1893  return clib_error_return
1894  (0, "no matching interface address for destination %U (interface %U)",
1895  format_ip6_address, dst,
1896  format_vnet_sw_if_index_name, vnm, sw_if_index);
1897  }
1898 
1899  h =
1902  &bi);
1903 
1904  hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1905 
1906  /* Destination address is a solicited node multicast address. We need to fill in
1907  the low 24 bits with low 24 bits of target's address. */
1908  h->ip.dst_address.as_u8[13] = dst->as_u8[13];
1909  h->ip.dst_address.as_u8[14] = dst->as_u8[14];
1910  h->ip.dst_address.as_u8[15] = dst->as_u8[15];
1911 
1912  h->ip.src_address = src[0];
1913  h->neighbor.target_address = dst[0];
1914 
1915  clib_memcpy (h->link_layer_option.ethernet_address, hi->hw_address,
1916  vec_len (hi->hw_address));
1917 
1918  h->neighbor.icmp.checksum =
1919  ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length);
1920  ASSERT (bogus_length == 0);
1921 
1922  b = vlib_get_buffer (vm, bi);
1923  vnet_buffer (b)->sw_if_index[VLIB_RX] =
1924  vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
1925 
1926  /* Add encapsulation string for software interface (e.g. ethernet header). */
1927  ip46_address_t nh = {
1928  .ip6 = *dst,
1929  };
1930 
1932  VNET_LINK_IP6, &nh, sw_if_index);
1933  adj = adj_get (ai);
1934 
1935  vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
1936  vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
1937 
1938  {
1940  u32 *to_next = vlib_frame_vector_args (f);
1941  to_next[0] = bi;
1942  f->n_vectors = 1;
1944  }
1945 
1946  adj_unlock (ai);
1947  return /* no error */ 0;
1948 }
1949 
1950 typedef enum
1951 {
1955 
1958  vlib_node_runtime_t * node,
1959  vlib_frame_t * frame,
1960  int do_counters, int is_midchain, int is_mcast)
1961 {
1962  ip_lookup_main_t *lm = &ip6_main.lookup_main;
1963  u32 *from = vlib_frame_vector_args (frame);
1964  u32 n_left_from, n_left_to_next, *to_next, next_index;
1965  vlib_node_runtime_t *error_node =
1967 
1968  n_left_from = frame->n_vectors;
1969  next_index = node->cached_next_index;
1970  u32 thread_index = vlib_get_thread_index ();
1971 
1972  while (n_left_from > 0)
1973  {
1974  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1975 
1976  while (n_left_from >= 4 && n_left_to_next >= 2)
1977  {
1978  ip_adjacency_t *adj0, *adj1;
1979  vlib_buffer_t *p0, *p1;
1980  ip6_header_t *ip0, *ip1;
1981  u32 pi0, rw_len0, next0, error0, adj_index0;
1982  u32 pi1, rw_len1, next1, error1, adj_index1;
1983  u32 tx_sw_if_index0, tx_sw_if_index1;
1984 
1985  /* Prefetch next iteration. */
1986  {
1987  vlib_buffer_t *p2, *p3;
1988 
1989  p2 = vlib_get_buffer (vm, from[2]);
1990  p3 = vlib_get_buffer (vm, from[3]);
1991 
1992  vlib_prefetch_buffer_header (p2, LOAD);
1993  vlib_prefetch_buffer_header (p3, LOAD);
1994 
1995  CLIB_PREFETCH (p2->pre_data, 32, STORE);
1996  CLIB_PREFETCH (p3->pre_data, 32, STORE);
1997 
1998  CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
1999  CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2000  }
2001 
2002  pi0 = to_next[0] = from[0];
2003  pi1 = to_next[1] = from[1];
2004 
2005  from += 2;
2006  n_left_from -= 2;
2007  to_next += 2;
2008  n_left_to_next -= 2;
2009 
2010  p0 = vlib_get_buffer (vm, pi0);
2011  p1 = vlib_get_buffer (vm, pi1);
2012 
2013  adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2014  adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
2015 
2016  ip0 = vlib_buffer_get_current (p0);
2017  ip1 = vlib_buffer_get_current (p1);
2018 
2019  error0 = error1 = IP6_ERROR_NONE;
2020  next0 = next1 = IP6_REWRITE_NEXT_DROP;
2021 
2023  {
2024  i32 hop_limit0 = ip0->hop_limit;
2025 
2026  /* Input node should have reject packets with hop limit 0. */
2027  ASSERT (ip0->hop_limit > 0);
2028 
2029  hop_limit0 -= 1;
2030 
2031  ip0->hop_limit = hop_limit0;
2032 
2033  /*
2034  * If the hop count drops below 1 when forwarding, generate
2035  * an ICMP response.
2036  */
2037  if (PREDICT_FALSE (hop_limit0 <= 0))
2038  {
2039  error0 = IP6_ERROR_TIME_EXPIRED;
2041  vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2042  icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2043  ICMP6_time_exceeded_ttl_exceeded_in_transit,
2044  0);
2045  }
2046  }
2047  else
2048  {
2050  }
2052  {
2053  i32 hop_limit1 = ip1->hop_limit;
2054 
2055  /* Input node should have reject packets with hop limit 0. */
2056  ASSERT (ip1->hop_limit > 0);
2057 
2058  hop_limit1 -= 1;
2059 
2060  ip1->hop_limit = hop_limit1;
2061 
2062  /*
2063  * If the hop count drops below 1 when forwarding, generate
2064  * an ICMP response.
2065  */
2066  if (PREDICT_FALSE (hop_limit1 <= 0))
2067  {
2068  error1 = IP6_ERROR_TIME_EXPIRED;
2070  vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2071  icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
2072  ICMP6_time_exceeded_ttl_exceeded_in_transit,
2073  0);
2074  }
2075  }
2076  else
2077  {
2079  }
2080  adj0 = adj_get (adj_index0);
2081  adj1 = adj_get (adj_index1);
2082 
2083  rw_len0 = adj0[0].rewrite_header.data_bytes;
2084  rw_len1 = adj1[0].rewrite_header.data_bytes;
2085  vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2086  vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
2087 
2088  if (do_counters)
2089  {
2092  thread_index, adj_index0, 1,
2093  vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2096  thread_index, adj_index1, 1,
2097  vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2098  }
2099 
2100  /* Check MTU of outgoing interface. */
2101  error0 =
2102  (vlib_buffer_length_in_chain (vm, p0) >
2103  adj0[0].
2104  rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2105  error0);
2106  error1 =
2107  (vlib_buffer_length_in_chain (vm, p1) >
2108  adj1[0].
2109  rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2110  error1);
2111 
2112  /* Don't adjust the buffer for hop count issue; icmp-error node
2113  * wants to see the IP headerr */
2114  if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2115  {
2116  p0->current_data -= rw_len0;
2117  p0->current_length += rw_len0;
2118 
2119  tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2120  vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2121  next0 = adj0[0].rewrite_header.next_index;
2122 
2123  if (PREDICT_FALSE
2124  (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2126  tx_sw_if_index0, &next0, p0);
2127  }
2128  if (PREDICT_TRUE (error1 == IP6_ERROR_NONE))
2129  {
2130  p1->current_data -= rw_len1;
2131  p1->current_length += rw_len1;
2132 
2133  tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2134  vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2135  next1 = adj1[0].rewrite_header.next_index;
2136 
2137  if (PREDICT_FALSE
2138  (adj1[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2140  tx_sw_if_index1, &next1, p1);
2141  }
2142 
2143  /* Guess we are only writing on simple Ethernet header. */
2144  vnet_rewrite_two_headers (adj0[0], adj1[0],
2145  ip0, ip1, sizeof (ethernet_header_t));
2146 
2147  if (is_midchain)
2148  {
2149  adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2150  adj1->sub_type.midchain.fixup_func (vm, adj1, p1);
2151  }
2152  if (is_mcast)
2153  {
2154  /*
2155  * copy bytes from the IP address into the MAC rewrite
2156  */
2157  vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
2158  vnet_fixup_one_header (adj1[0], &ip1->dst_address, ip1);
2159  }
2160 
2161  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2162  to_next, n_left_to_next,
2163  pi0, pi1, next0, next1);
2164  }
2165 
2166  while (n_left_from > 0 && n_left_to_next > 0)
2167  {
2168  ip_adjacency_t *adj0;
2169  vlib_buffer_t *p0;
2170  ip6_header_t *ip0;
2171  u32 pi0, rw_len0;
2172  u32 adj_index0, next0, error0;
2173  u32 tx_sw_if_index0;
2174 
2175  pi0 = to_next[0] = from[0];
2176 
2177  p0 = vlib_get_buffer (vm, pi0);
2178 
2179  adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2180 
2181  adj0 = adj_get (adj_index0);
2182 
2183  ip0 = vlib_buffer_get_current (p0);
2184 
2185  error0 = IP6_ERROR_NONE;
2186  next0 = IP6_REWRITE_NEXT_DROP;
2187 
2188  /* Check hop limit */
2190  {
2191  i32 hop_limit0 = ip0->hop_limit;
2192 
2193  ASSERT (ip0->hop_limit > 0);
2194 
2195  hop_limit0 -= 1;
2196 
2197  ip0->hop_limit = hop_limit0;
2198 
2199  if (PREDICT_FALSE (hop_limit0 <= 0))
2200  {
2201  /*
2202  * If the hop count drops below 1 when forwarding, generate
2203  * an ICMP response.
2204  */
2205  error0 = IP6_ERROR_TIME_EXPIRED;
2207  vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2208  icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2209  ICMP6_time_exceeded_ttl_exceeded_in_transit,
2210  0);
2211  }
2212  }
2213  else
2214  {
2216  }
2217 
2218  /* Guess we are only writing on simple Ethernet header. */
2219  vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
2220 
2221  /* Update packet buffer attributes/set output interface. */
2222  rw_len0 = adj0[0].rewrite_header.data_bytes;
2223  vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2224 
2225  if (do_counters)
2226  {
2229  thread_index, adj_index0, 1,
2230  vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2231  }
2232 
2233  /* Check MTU of outgoing interface. */
2234  error0 =
2235  (vlib_buffer_length_in_chain (vm, p0) >
2236  adj0[0].
2237  rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2238  error0);
2239 
2240  /* Don't adjust the buffer for hop count issue; icmp-error node
2241  * wants to see the IP headerr */
2242  if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2243  {
2244  p0->current_data -= rw_len0;
2245  p0->current_length += rw_len0;
2246 
2247  tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2248 
2249  vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2250  next0 = adj0[0].rewrite_header.next_index;
2251 
2252  if (PREDICT_FALSE
2253  (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
2255  tx_sw_if_index0, &next0, p0);
2256  }
2257 
2258  if (is_midchain)
2259  {
2260  adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2261  }
2262  if (is_mcast)
2263  {
2264  vnet_fixup_one_header (adj0[0], &ip0->dst_address, ip0);
2265  }
2266 
2267  p0->error = error_node->errors[error0];
2268 
2269  from += 1;
2270  n_left_from -= 1;
2271  to_next += 1;
2272  n_left_to_next -= 1;
2273 
2274  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2275  to_next, n_left_to_next,
2276  pi0, next0);
2277  }
2278 
2279  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2280  }
2281 
2282  /* Need to do trace after rewrites to pick up new packet data. */
2283  if (node->flags & VLIB_NODE_FLAG_TRACE)
2284  ip6_forward_next_trace (vm, node, frame, VLIB_TX);
2285 
2286  return frame->n_vectors;
2287 }
2288 
2289 static uword
2291  vlib_node_runtime_t * node, vlib_frame_t * frame)
2292 {
2293  if (adj_are_counters_enabled ())
2294  return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
2295  else
2296  return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
2297 }
2298 
2299 static uword
2301  vlib_node_runtime_t * node, vlib_frame_t * frame)
2302 {
2303  if (adj_are_counters_enabled ())
2304  return ip6_rewrite_inline (vm, node, frame, 1, 0, 1);
2305  else
2306  return ip6_rewrite_inline (vm, node, frame, 0, 0, 1);
2307 }
2308 
2309 static uword
2311  vlib_node_runtime_t * node, vlib_frame_t * frame)
2312 {
2313  if (adj_are_counters_enabled ())
2314  return ip6_rewrite_inline (vm, node, frame, 1, 1, 0);
2315  else
2316  return ip6_rewrite_inline (vm, node, frame, 0, 1, 0);
2317 }
2318 
2319 static uword
2321  vlib_node_runtime_t * node, vlib_frame_t * frame)
2322 {
2323  if (adj_are_counters_enabled ())
2324  return ip6_rewrite_inline (vm, node, frame, 1, 1, 1);
2325  else
2326  return ip6_rewrite_inline (vm, node, frame, 0, 1, 1);
2327 }
2328 
2329 /* *INDENT-OFF* */
2331 {
2332  .function = ip6_midchain,
2333  .name = "ip6-midchain",
2334  .vector_size = sizeof (u32),
2335  .format_trace = format_ip6_forward_next_trace,
2336  .sibling_of = "ip6-rewrite",
2337  };
2338 /* *INDENT-ON* */
2339 
2341 
2342 /* *INDENT-OFF* */
2344 {
2345  .function = ip6_rewrite,
2346  .name = "ip6-rewrite",
2347  .vector_size = sizeof (u32),
2348  .format_trace = format_ip6_rewrite_trace,
2349  .n_next_nodes = 2,
2350  .next_nodes =
2351  {
2352  [IP6_REWRITE_NEXT_DROP] = "error-drop",
2353  [IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
2354  },
2355 };
2356 /* *INDENT-ON* */
2357 
2359 
2360 /* *INDENT-OFF* */
2362 {
2363  .function = ip6_rewrite_mcast,
2364  .name = "ip6-rewrite-mcast",
2365  .vector_size = sizeof (u32),
2366  .format_trace = format_ip6_rewrite_trace,
2367  .sibling_of = "ip6-rewrite",
2368 };
2369 /* *INDENT-ON* */
2370 
2372 
2373 /* *INDENT-OFF* */
2375 {
2376  .function = ip6_mcast_midchain,
2377  .name = "ip6-mcast-midchain",
2378  .vector_size = sizeof (u32),
2379  .format_trace = format_ip6_rewrite_trace,
2380  .sibling_of = "ip6-rewrite",
2381 };
2382 /* *INDENT-ON* */
2383 
2385 
2386 /*
2387  * Hop-by-Hop handling
2388  */
2390 
2391 #define foreach_ip6_hop_by_hop_error \
2392 _(PROCESSED, "pkts with ip6 hop-by-hop options") \
2393 _(FORMAT, "incorrectly formatted hop-by-hop options") \
2394 _(UNKNOWN_OPTION, "unknown ip6 hop-by-hop options")
2395 
2396 /* *INDENT-OFF* */
2397 typedef enum
2398 {
2399 #define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym,
2401 #undef _
2404 /* *INDENT-ON* */
2405 
2406 /*
2407  * Primary h-b-h handler trace support
2408  * We work pretty hard on the problem for obvious reasons
2409  */
2410 typedef struct
2411 {
2414  u8 option_data[256];
2416 
2418 
2420 #define _(sym,string) string,
2422 #undef _
2423 };
2424 
2425 u8 *
2426 format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args)
2427 {
2428  ip6_hop_by_hop_header_t *hbh0 = va_arg (*args, ip6_hop_by_hop_header_t *);
2429  int total_len = va_arg (*args, int);
2430  ip6_hop_by_hop_option_t *opt0, *limit0;
2432  u8 type0;
2433 
2434  s = format (s, "IP6_HOP_BY_HOP: next protocol %d len %d total %d",
2435  hbh0->protocol, (hbh0->length + 1) << 3, total_len);
2436 
2437  opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2438  limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 + total_len);
2439 
2440  while (opt0 < limit0)
2441  {
2442  type0 = opt0->type;
2443  switch (type0)
2444  {
2445  case 0: /* Pad, just stop */
2446  opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0 + 1);
2447  break;
2448 
2449  default:
2450  if (hm->trace[type0])
2451  {
2452  s = (*hm->trace[type0]) (s, opt0);
2453  }
2454  else
2455  {
2456  s =
2457  format (s, "\n unrecognized option %d length %d", type0,
2458  opt0->length);
2459  }
2460  opt0 =
2461  (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2462  sizeof (ip6_hop_by_hop_option_t));
2463  break;
2464  }
2465  }
2466  return s;
2467 }
2468 
2469 static u8 *
2470 format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
2471 {
2472  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2473  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
2474  ip6_hop_by_hop_trace_t *t = va_arg (*args, ip6_hop_by_hop_trace_t *);
2476  ip6_hop_by_hop_option_t *opt0, *limit0;
2478 
2479  u8 type0;
2480 
2481  hbh0 = (ip6_hop_by_hop_header_t *) t->option_data;
2482 
2483  s = format (s, "IP6_HOP_BY_HOP: next index %d len %d traced %d",
2484  t->next_index, (hbh0->length + 1) << 3, t->trace_len);
2485 
2486  opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2487  limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0) + t->trace_len;
2488 
2489  while (opt0 < limit0)
2490  {
2491  type0 = opt0->type;
2492  switch (type0)
2493  {
2494  case 0: /* Pad, just stop */
2495  opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2496  break;
2497 
2498  default:
2499  if (hm->trace[type0])
2500  {
2501  s = (*hm->trace[type0]) (s, opt0);
2502  }
2503  else
2504  {
2505  s =
2506  format (s, "\n unrecognized option %d length %d", type0,
2507  opt0->length);
2508  }
2509  opt0 =
2510  (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2511  sizeof (ip6_hop_by_hop_option_t));
2512  break;
2513  }
2514  }
2515  return s;
2516 }
2517 
2520  ip6_header_t * ip0,
2521  ip6_hop_by_hop_header_t * hbh0,
2522  ip6_hop_by_hop_option_t * opt0,
2523  ip6_hop_by_hop_option_t * limit0, u32 * next0)
2524 {
2526  u8 type0;
2527  u8 error0 = 0;
2528 
2529  while (opt0 < limit0)
2530  {
2531  type0 = opt0->type;
2532  switch (type0)
2533  {
2534  case 0: /* Pad1 */
2535  opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2536  continue;
2537  case 1: /* PadN */
2538  break;
2539  default:
2540  if (hm->options[type0])
2541  {
2542  if ((*hm->options[type0]) (b0, ip0, opt0) < 0)
2543  {
2544  error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2545  return (error0);
2546  }
2547  }
2548  else
2549  {
2550  /* Unrecognized mandatory option, check the two high order bits */
2551  switch (opt0->type & HBH_OPTION_TYPE_HIGH_ORDER_BITS)
2552  {
2554  break;
2556  error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2557  *next0 = IP_LOOKUP_NEXT_DROP;
2558  break;
2560  error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2561  *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2562  icmp6_error_set_vnet_buffer (b0, ICMP6_parameter_problem,
2563  ICMP6_parameter_problem_unrecognized_option,
2564  (u8 *) opt0 - (u8 *) ip0);
2565  break;
2567  error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2569  {
2570  *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2572  ICMP6_parameter_problem,
2573  ICMP6_parameter_problem_unrecognized_option,
2574  (u8 *) opt0 - (u8 *) ip0);
2575  }
2576  else
2577  {
2578  *next0 = IP_LOOKUP_NEXT_DROP;
2579  }
2580  break;
2581  }
2582  return (error0);
2583  }
2584  }
2585  opt0 =
2586  (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2587  sizeof (ip6_hop_by_hop_option_t));
2588  }
2589  return (error0);
2590 }
2591 
2592 /*
2593  * Process the Hop-by-Hop Options header
2594  */
2595 static uword
2597  vlib_node_runtime_t * node, vlib_frame_t * frame)
2598 {
2599  vlib_node_runtime_t *error_node =
2600  vlib_node_get_runtime (vm, ip6_hop_by_hop_node.index);
2602  u32 n_left_from, *from, *to_next;
2603  ip_lookup_next_t next_index;
2604 
2605  from = vlib_frame_vector_args (frame);
2606  n_left_from = frame->n_vectors;
2607  next_index = node->cached_next_index;
2608 
2609  while (n_left_from > 0)
2610  {
2611  u32 n_left_to_next;
2612 
2613  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2614 
2615  while (n_left_from >= 4 && n_left_to_next >= 2)
2616  {
2617  u32 bi0, bi1;
2618  vlib_buffer_t *b0, *b1;
2619  u32 next0, next1;
2620  ip6_header_t *ip0, *ip1;
2621  ip6_hop_by_hop_header_t *hbh0, *hbh1;
2622  ip6_hop_by_hop_option_t *opt0, *limit0, *opt1, *limit1;
2623  u8 error0 = 0, error1 = 0;
2624 
2625  /* Prefetch next iteration. */
2626  {
2627  vlib_buffer_t *p2, *p3;
2628 
2629  p2 = vlib_get_buffer (vm, from[2]);
2630  p3 = vlib_get_buffer (vm, from[3]);
2631 
2632  vlib_prefetch_buffer_header (p2, LOAD);
2633  vlib_prefetch_buffer_header (p3, LOAD);
2634 
2635  CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2636  CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2637  }
2638 
2639  /* Speculatively enqueue b0, b1 to the current next frame */
2640  to_next[0] = bi0 = from[0];
2641  to_next[1] = bi1 = from[1];
2642  from += 2;
2643  to_next += 2;
2644  n_left_from -= 2;
2645  n_left_to_next -= 2;
2646 
2647  b0 = vlib_get_buffer (vm, bi0);
2648  b1 = vlib_get_buffer (vm, bi1);
2649 
2650  /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2651  u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
2652  ip_adjacency_t *adj0 = adj_get (adj_index0);
2653  u32 adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
2654  ip_adjacency_t *adj1 = adj_get (adj_index1);
2655 
2656  /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2657  next0 = adj0->lookup_next_index;
2658  next1 = adj1->lookup_next_index;
2659 
2660  ip0 = vlib_buffer_get_current (b0);
2661  ip1 = vlib_buffer_get_current (b1);
2662  hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2663  hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1);
2664  opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2665  opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
2666  limit0 =
2667  (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2668  ((hbh0->length + 1) << 3));
2669  limit1 =
2670  (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
2671  ((hbh1->length + 1) << 3));
2672 
2673  /*
2674  * Basic validity checks
2675  */
2676  if ((hbh0->length + 1) << 3 >
2677  clib_net_to_host_u16 (ip0->payload_length))
2678  {
2679  error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2680  next0 = IP_LOOKUP_NEXT_DROP;
2681  goto outdual;
2682  }
2683  /* Scan the set of h-b-h options, process ones that we understand */
2684  error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2685 
2686  if ((hbh1->length + 1) << 3 >
2687  clib_net_to_host_u16 (ip1->payload_length))
2688  {
2689  error1 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2690  next1 = IP_LOOKUP_NEXT_DROP;
2691  goto outdual;
2692  }
2693  /* Scan the set of h-b-h options, process ones that we understand */
2694  error1 = ip6_scan_hbh_options (b1, ip1, hbh1, opt1, limit1, &next1);
2695 
2696  outdual:
2697  /* Has the classifier flagged this buffer for special treatment? */
2698  if (PREDICT_FALSE
2699  ((error0 == 0)
2700  && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2701  next0 = hm->next_override;
2702 
2703  /* Has the classifier flagged this buffer for special treatment? */
2704  if (PREDICT_FALSE
2705  ((error1 == 0)
2706  && (vnet_buffer (b1)->l2_classify.opaque_index & OI_DECAP)))
2707  next1 = hm->next_override;
2708 
2709  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2710  {
2711  if (b0->flags & VLIB_BUFFER_IS_TRACED)
2712  {
2714  vlib_add_trace (vm, node, b0, sizeof (*t));
2715  u32 trace_len = (hbh0->length + 1) << 3;
2716  t->next_index = next0;
2717  /* Capture the h-b-h option verbatim */
2718  trace_len =
2719  trace_len <
2720  ARRAY_LEN (t->option_data) ? trace_len :
2721  ARRAY_LEN (t->option_data);
2722  t->trace_len = trace_len;
2723  clib_memcpy (t->option_data, hbh0, trace_len);
2724  }
2725  if (b1->flags & VLIB_BUFFER_IS_TRACED)
2726  {
2728  vlib_add_trace (vm, node, b1, sizeof (*t));
2729  u32 trace_len = (hbh1->length + 1) << 3;
2730  t->next_index = next1;
2731  /* Capture the h-b-h option verbatim */
2732  trace_len =
2733  trace_len <
2734  ARRAY_LEN (t->option_data) ? trace_len :
2735  ARRAY_LEN (t->option_data);
2736  t->trace_len = trace_len;
2737  clib_memcpy (t->option_data, hbh1, trace_len);
2738  }
2739 
2740  }
2741 
2742  b0->error = error_node->errors[error0];
2743  b1->error = error_node->errors[error1];
2744 
2745  /* verify speculative enqueue, maybe switch current next frame */
2746  vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
2747  n_left_to_next, bi0, bi1, next0,
2748  next1);
2749  }
2750 
2751  while (n_left_from > 0 && n_left_to_next > 0)
2752  {
2753  u32 bi0;
2754  vlib_buffer_t *b0;
2755  u32 next0;
2756  ip6_header_t *ip0;
2758  ip6_hop_by_hop_option_t *opt0, *limit0;
2759  u8 error0 = 0;
2760 
2761  /* Speculatively enqueue b0 to the current next frame */
2762  bi0 = from[0];
2763  to_next[0] = bi0;
2764  from += 1;
2765  to_next += 1;
2766  n_left_from -= 1;
2767  n_left_to_next -= 1;
2768 
2769  b0 = vlib_get_buffer (vm, bi0);
2770  /*
2771  * Default use the next_index from the adjacency.
2772  * A HBH option rarely redirects to a different node
2773  */
2774  u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
2775  ip_adjacency_t *adj0 = adj_get (adj_index0);
2776  next0 = adj0->lookup_next_index;
2777 
2778  ip0 = vlib_buffer_get_current (b0);
2779  hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2780  opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2781  limit0 =
2782  (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2783  ((hbh0->length + 1) << 3));
2784 
2785  /*
2786  * Basic validity checks
2787  */
2788  if ((hbh0->length + 1) << 3 >
2789  clib_net_to_host_u16 (ip0->payload_length))
2790  {
2791  error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2792  next0 = IP_LOOKUP_NEXT_DROP;
2793  goto out0;
2794  }
2795 
2796  /* Scan the set of h-b-h options, process ones that we understand */
2797  error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2798 
2799  out0:
2800  /* Has the classifier flagged this buffer for special treatment? */
2801  if (PREDICT_FALSE
2802  ((error0 == 0)
2803  && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2804  next0 = hm->next_override;
2805 
2807  {
2809  vlib_add_trace (vm, node, b0, sizeof (*t));
2810  u32 trace_len = (hbh0->length + 1) << 3;
2811  t->next_index = next0;
2812  /* Capture the h-b-h option verbatim */
2813  trace_len =
2814  trace_len <
2815  ARRAY_LEN (t->option_data) ? trace_len :
2816  ARRAY_LEN (t->option_data);
2817  t->trace_len = trace_len;
2818  clib_memcpy (t->option_data, hbh0, trace_len);
2819  }
2820 
2821  b0->error = error_node->errors[error0];
2822 
2823  /* verify speculative enqueue, maybe switch current next frame */
2824  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2825  n_left_to_next, bi0, next0);
2826  }
2827  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2828  }
2829  return frame->n_vectors;
2830 }
2831 
2832 /* *INDENT-OFF* */
2833 VLIB_REGISTER_NODE (ip6_hop_by_hop_node) =
2834 {
2835  .function = ip6_hop_by_hop,
2836  .name = "ip6-hop-by-hop",
2837  .sibling_of = "ip6-lookup",
2838  .vector_size = sizeof (u32),
2839  .format_trace = format_ip6_hop_by_hop_trace,
2840  .type = VLIB_NODE_TYPE_INTERNAL,
2841  .n_errors = ARRAY_LEN (ip6_hop_by_hop_error_strings),
2842  .error_strings = ip6_hop_by_hop_error_strings,
2843  .n_next_nodes = 0,
2844 };
2845 /* *INDENT-ON* */
2846 
2847 VLIB_NODE_FUNCTION_MULTIARCH (ip6_hop_by_hop_node, ip6_hop_by_hop);
2848 
2849 static clib_error_t *
2851 {
2853  memset (hm->options, 0, sizeof (hm->options));
2854  memset (hm->trace, 0, sizeof (hm->trace));
2856  return (0);
2857 }
2858 
2860 
2861 void
2863 {
2865 
2866  hm->next_override = next;
2867 }
2868 
2869 int
2871  int options (vlib_buffer_t * b, ip6_header_t * ip,
2872  ip6_hop_by_hop_option_t * opt),
2873  u8 * trace (u8 * s, ip6_hop_by_hop_option_t * opt))
2874 {
2875  ip6_main_t *im = &ip6_main;
2877 
2878  ASSERT (option < ARRAY_LEN (hm->options));
2879 
2880  /* Already registered */
2881  if (hm->options[option])
2882  return (-1);
2883 
2884  hm->options[option] = options;
2885  hm->trace[option] = trace;
2886 
2887  /* Set global variable */
2888  im->hbh_enabled = 1;
2889 
2890  return (0);
2891 }
2892 
2893 int
2895 {
2896  ip6_main_t *im = &ip6_main;
2898 
2899  ASSERT (option < ARRAY_LEN (hm->options));
2900 
2901  /* Not registered */
2902  if (!hm->options[option])
2903  return (-1);
2904 
2905  hm->options[option] = NULL;
2906  hm->trace[option] = NULL;
2907 
2908  /* Disable global knob if this was the last option configured */
2909  int i;
2910  bool found = false;
2911  for (i = 0; i < 256; i++)
2912  {
2913  if (hm->options[option])
2914  {
2915  found = true;
2916  break;
2917  }
2918  }
2919  if (!found)
2920  im->hbh_enabled = 0;
2921 
2922  return (0);
2923 }
2924 
2925 /* Global IP6 main. */
2927 
2928 static clib_error_t *
2930 {
2931  ip6_main_t *im = &ip6_main;
2932  clib_error_t *error;
2933  uword i;
2934 
2935  if ((error = vlib_call_init_function (vm, vnet_feature_init)))
2936  return error;
2937 
2938  for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
2939  {
2940  u32 j, i0, i1;
2941 
2942  i0 = i / 32;
2943  i1 = i % 32;
2944 
2945  for (j = 0; j < i0; j++)
2946  im->fib_masks[i].as_u32[j] = ~0;
2947 
2948  if (i1)
2949  im->fib_masks[i].as_u32[i0] =
2950  clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
2951  }
2952 
2953  ip_lookup_init (&im->lookup_main, /* is_ip6 */ 1);
2954 
2955  if (im->lookup_table_nbuckets == 0)
2957 
2959 
2960  if (im->lookup_table_size == 0)
2962 
2963  BV (clib_bihash_init) (&(im->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash),
2964  "ip6 FIB fwding table",
2967  "ip6 FIB non-fwding table",
2969 
2970  /* Create FIB with index 0 and table id of 0. */
2973 
2974  {
2975  pg_node_t *pn;
2976  pn = pg_get_node (ip6_lookup_node.index);
2978  }
2979 
2980  /* Unless explicitly configured, don't process HBH options */
2981  im->hbh_enabled = 0;
2982 
2983  {
2984  icmp6_neighbor_solicitation_header_t p;
2985 
2986  memset (&p, 0, sizeof (p));
2987 
2988  p.ip.ip_version_traffic_class_and_flow_label =
2989  clib_host_to_net_u32 (0x6 << 28);
2990  p.ip.payload_length =
2991  clib_host_to_net_u16 (sizeof (p) -
2993  (icmp6_neighbor_solicitation_header_t, neighbor));
2994  p.ip.protocol = IP_PROTOCOL_ICMP6;
2995  p.ip.hop_limit = 255;
2996  ip6_set_solicited_node_multicast_address (&p.ip.dst_address, 0);
2997 
2998  p.neighbor.icmp.type = ICMP6_neighbor_solicitation;
2999 
3000  p.link_layer_option.header.type =
3001  ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
3002  p.link_layer_option.header.n_data_u64s =
3003  sizeof (p.link_layer_option) / sizeof (u64);
3004 
3007  &p, sizeof (p),
3008  /* alloc chunk size */ 8,
3009  "ip6 neighbor discovery");
3010  }
3011 
3012  return error;
3013 }
3014 
3016 
3017 static clib_error_t *
3019  unformat_input_t * input,
3020  vlib_cli_command_t * cmd)
3021 {
3022  vnet_main_t *vnm = vnet_get_main ();
3024  clib_error_t *error = 0;
3025  u32 sw_if_index, table_id;
3026 
3027  sw_if_index = ~0;
3028 
3029  if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
3030  {
3031  error = clib_error_return (0, "unknown interface `%U'",
3032  format_unformat_error, input);
3033  goto done;
3034  }
3035 
3036  if (unformat (input, "%d", &table_id))
3037  ;
3038  else
3039  {
3040  error = clib_error_return (0, "expected table id `%U'",
3041  format_unformat_error, input);
3042  goto done;
3043  }
3044 
3045  /*
3046  * If the interface already has in IP address, then a change int
3047  * VRF is not allowed. The IP address applied must first be removed.
3048  * We do not do that automatically here, since VPP has no knowledge
3049  * of whether thoses subnets are valid in the destination VRF.
3050  */
3051  /* *INDENT-OFF* */
3053  ia, sw_if_index,
3054  1 /* honor unnumbered */,
3055  ({
3056  ip4_address_t * a;
3057 
3058  a = ip_interface_address_get_address (&ip6_main.lookup_main, ia);
3059  error = clib_error_return (0, "interface %U has address %U",
3060  format_vnet_sw_if_index_name, vnm,
3061  sw_if_index,
3062  format_ip6_address, a);
3063  goto done;
3064  }));
3065  /* *INDENT-ON* */
3066 
3067  {
3069  table_id);
3070 
3071  vec_validate (ip6_main.fib_index_by_sw_if_index, sw_if_index);
3072  ip6_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
3073 
3075  table_id);
3076 
3077  vec_validate (ip6_main.mfib_index_by_sw_if_index, sw_if_index);
3078  ip6_main.mfib_index_by_sw_if_index[sw_if_index] = fib_index;
3079  }
3080 
3081 
3082 done:
3083  return error;
3084 }
3085 
3086 /*?
3087  * Place the indicated interface into the supplied IPv6 FIB table (also known
3088  * as a VRF). If the FIB table does not exist, this command creates it. To
3089  * display the current IPv6 FIB table, use the command '<em>show ip6 fib</em>'.
3090  * FIB table will only be displayed if a route has been added to the table, or
3091  * an IP Address is assigned to an interface in the table (which adds a route
3092  * automatically).
3093  *
3094  * @note IP addresses added after setting the interface IP table are added to
3095  * the indicated FIB table. If an IP address is added prior to changing the
3096  * table then this is an error. The control plane must remove these addresses
3097  * first and then change the table. VPP will not automatically move the
3098  * addresses from the old to the new table as it does not know the validity
3099  * of such a change.
3100  *
3101  * @cliexpar
3102  * Example of how to add an interface to an IPv6 FIB table (where 2 is the table-id):
3103  * @cliexcmd{set interface ip6 table GigabitEthernet2/0/0 2}
3104  ?*/
3105 /* *INDENT-OFF* */
3106 VLIB_CLI_COMMAND (set_interface_ip6_table_command, static) =
3107 {
3108  .path = "set interface ip6 table",
3109  .function = add_del_ip6_interface_table,
3110  .short_help = "set interface ip6 table <interface> <table-id>"
3111 };
3112 /* *INDENT-ON* */
3113 
3114 void
3116  u8 * mac)
3117 {
3118  ip->as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL);
3119  /* Invert the "u" bit */
3120  ip->as_u8[8] = mac[0] ^ (1 << 1);
3121  ip->as_u8[9] = mac[1];
3122  ip->as_u8[10] = mac[2];
3123  ip->as_u8[11] = 0xFF;
3124  ip->as_u8[12] = 0xFE;
3125  ip->as_u8[13] = mac[3];
3126  ip->as_u8[14] = mac[4];
3127  ip->as_u8[15] = mac[5];
3128 }
3129 
3130 void
3132  ip6_address_t * ip)
3133 {
3134  /* Invert the previously inverted "u" bit */
3135  mac[0] = ip->as_u8[8] ^ (1 << 1);
3136  mac[1] = ip->as_u8[9];
3137  mac[2] = ip->as_u8[10];
3138  mac[3] = ip->as_u8[13];
3139  mac[4] = ip->as_u8[14];
3140  mac[5] = ip->as_u8[15];
3141 }
3142 
3143 static clib_error_t *
3145  unformat_input_t * input, vlib_cli_command_t * cmd)
3146 {
3147  u8 mac[6];
3148  ip6_address_t _a, *a = &_a;
3149 
3150  if (unformat (input, "%U", unformat_ethernet_address, mac))
3151  {
3153  vlib_cli_output (vm, "Link local address: %U", format_ip6_address, a);
3155  vlib_cli_output (vm, "Original MAC address: %U",
3157  }
3158 
3159  return 0;
3160 }
3161 
3162 /*?
3163  * This command converts the given MAC Address into an IPv6 link-local
3164  * address.
3165  *
3166  * @cliexpar
3167  * Example of how to create an IPv6 link-local address:
3168  * @cliexstart{test ip6 link 16:d9:e0:91:79:86}
3169  * Link local address: fe80::14d9:e0ff:fe91:7986
3170  * Original MAC address: 16:d9:e0:91:79:86
3171  * @cliexend
3172 ?*/
3173 /* *INDENT-OFF* */
3174 VLIB_CLI_COMMAND (test_link_command, static) =
3175 {
3176  .path = "test ip6 link",
3177  .function = test_ip6_link_command_fn,
3178  .short_help = "test ip6 link <mac-address>",
3179 };
3180 /* *INDENT-ON* */
3181 
3182 int
3183 vnet_set_ip6_flow_hash (u32 table_id, u32 flow_hash_config)
3184 {
3185  u32 fib_index;
3186 
3187  fib_index = fib_table_find (FIB_PROTOCOL_IP6, table_id);
3188 
3189  if (~0 == fib_index)
3190  return VNET_API_ERROR_NO_SUCH_FIB;
3191 
3193  flow_hash_config);
3194 
3195  return 0;
3196 }
3197 
3198 static clib_error_t *
3200  unformat_input_t * input,
3201  vlib_cli_command_t * cmd)
3202 {
3203  int matched = 0;
3204  u32 table_id = 0;
3205  u32 flow_hash_config = 0;
3206  int rv;
3207 
3208  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3209  {
3210  if (unformat (input, "table %d", &table_id))
3211  matched = 1;
3212 #define _(a,v) \
3213  else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
3215 #undef _
3216  else
3217  break;
3218  }
3219 
3220  if (matched == 0)
3221  return clib_error_return (0, "unknown input `%U'",
3222  format_unformat_error, input);
3223 
3224  rv = vnet_set_ip6_flow_hash (table_id, flow_hash_config);
3225  switch (rv)
3226  {
3227  case 0:
3228  break;
3229 
3230  case -1:
3231  return clib_error_return (0, "no such FIB table %d", table_id);
3232 
3233  default:
3234  clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3235  break;
3236  }
3237 
3238  return 0;
3239 }
3240 
3241 /*?
3242  * Configure the set of IPv6 fields used by the flow hash.
3243  *
3244  * @cliexpar
3245  * @parblock
3246  * Example of how to set the flow hash on a given table:
3247  * @cliexcmd{set ip6 flow-hash table 8 dst sport dport proto}
3248  *
3249  * Example of display the configured flow hash:
3250  * @cliexstart{show ip6 fib}
3251  * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3252  * @::/0
3253  * unicast-ip6-chain
3254  * [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
3255  * [0] [@0]: dpo-drop ip6
3256  * fe80::/10
3257  * unicast-ip6-chain
3258  * [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
3259  * [0] [@2]: dpo-receive
3260  * ff02::1/128
3261  * unicast-ip6-chain
3262  * [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
3263  * [0] [@2]: dpo-receive
3264  * ff02::2/128
3265  * unicast-ip6-chain
3266  * [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
3267  * [0] [@2]: dpo-receive
3268  * ff02::16/128
3269  * unicast-ip6-chain
3270  * [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
3271  * [0] [@2]: dpo-receive
3272  * ff02::1:ff00:0/104
3273  * unicast-ip6-chain
3274  * [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
3275  * [0] [@2]: dpo-receive
3276  * ipv6-VRF:8, fib_index 1, flow hash: dst sport dport proto
3277  * @::/0
3278  * unicast-ip6-chain
3279  * [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3280  * [0] [@0]: dpo-drop ip6
3281  * @::a:1:1:0:4/126
3282  * unicast-ip6-chain
3283  * [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
3284  * [0] [@4]: ipv6-glean: af_packet0
3285  * @::a:1:1:0:7/128
3286  * unicast-ip6-chain
3287  * [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
3288  * [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
3289  * fe80::/10
3290  * unicast-ip6-chain
3291  * [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
3292  * [0] [@2]: dpo-receive
3293  * fe80::fe:3eff:fe3e:9222/128
3294  * unicast-ip6-chain
3295  * [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
3296  * [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
3297  * ff02::1/128
3298  * unicast-ip6-chain
3299  * [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
3300  * [0] [@2]: dpo-receive
3301  * ff02::2/128
3302  * unicast-ip6-chain
3303  * [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
3304  * [0] [@2]: dpo-receive
3305  * ff02::16/128
3306  * unicast-ip6-chain
3307  * [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
3308  * [0] [@2]: dpo-receive
3309  * ff02::1:ff00:0/104
3310  * unicast-ip6-chain
3311  * [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
3312  * [0] [@2]: dpo-receive
3313  * @cliexend
3314  * @endparblock
3315 ?*/
3316 /* *INDENT-OFF* */
3317 VLIB_CLI_COMMAND (set_ip6_flow_hash_command, static) =
3318 {
3319  .path = "set ip6 flow-hash",
3320  .short_help =
3321  "set ip6 flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
3322  .function = set_ip6_flow_hash_command_fn,
3323 };
3324 /* *INDENT-ON* */
3325 
3326 static clib_error_t *
3328  unformat_input_t * input, vlib_cli_command_t * cmd)
3329 {
3330  ip6_main_t *im = &ip6_main;
3331  ip_lookup_main_t *lm = &im->lookup_main;
3332  int i;
3333 
3334  vlib_cli_output (vm, "Protocols handled by ip6_local");
3335  for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
3336  {
3338  vlib_cli_output (vm, "%d", i);
3339  }
3340  return 0;
3341 }
3342 
3343 
3344 
3345 /*?
3346  * Display the set of protocols handled by the local IPv6 stack.
3347  *
3348  * @cliexpar
3349  * Example of how to display local protocol table:
3350  * @cliexstart{show ip6 local}
3351  * Protocols handled by ip6_local
3352  * 17
3353  * 43
3354  * 58
3355  * 115
3356  * @cliexend
3357 ?*/
3358 /* *INDENT-OFF* */
3359 VLIB_CLI_COMMAND (show_ip6_local, static) =
3360 {
3361  .path = "show ip6 local",
3362  .function = show_ip6_local_command_fn,
3363  .short_help = "show ip6 local",
3364 };
3365 /* *INDENT-ON* */
3366 
3367 int
3369  u32 table_index)
3370 {
3371  vnet_main_t *vnm = vnet_get_main ();
3373  ip6_main_t *ipm = &ip6_main;
3374  ip_lookup_main_t *lm = &ipm->lookup_main;
3376  ip6_address_t *if_addr;
3377 
3378  if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3379  return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3380 
3381  if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3382  return VNET_API_ERROR_NO_SUCH_ENTRY;
3383 
3385  lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
3386 
3387  if_addr = ip6_interface_first_address (ipm, sw_if_index);
3388 
3389  if (NULL != if_addr)
3390  {
3391  fib_prefix_t pfx = {
3392  .fp_len = 128,
3393  .fp_proto = FIB_PROTOCOL_IP6,
3394  .fp_addr.ip6 = *if_addr,
3395  };
3396  u32 fib_index;
3397 
3399  sw_if_index);
3400 
3401 
3402  if (table_index != (u32) ~ 0)
3403  {
3404  dpo_id_t dpo = DPO_INVALID;
3405 
3406  dpo_set (&dpo,
3407  DPO_CLASSIFY,
3408  DPO_PROTO_IP6,
3409  classify_dpo_create (DPO_PROTO_IP6, table_index));
3410 
3412  &pfx,
3414  FIB_ENTRY_FLAG_NONE, &dpo);
3415  dpo_reset (&dpo);
3416  }
3417  else
3418  {
3419  fib_table_entry_special_remove (fib_index,
3420  &pfx, FIB_SOURCE_CLASSIFY);
3421  }
3422  }
3423 
3424  return 0;
3425 }
3426 
3427 static clib_error_t *
3429  unformat_input_t * input,
3430  vlib_cli_command_t * cmd)
3431 {
3432  u32 table_index = ~0;
3433  int table_index_set = 0;
3434  u32 sw_if_index = ~0;
3435  int rv;
3436 
3437  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3438  {
3439  if (unformat (input, "table-index %d", &table_index))
3440  table_index_set = 1;
3441  else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3442  vnet_get_main (), &sw_if_index))
3443  ;
3444  else
3445  break;
3446  }
3447 
3448  if (table_index_set == 0)
3449  return clib_error_return (0, "classify table-index must be specified");
3450 
3451  if (sw_if_index == ~0)
3452  return clib_error_return (0, "interface / subif must be specified");
3453 
3454  rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
3455 
3456  switch (rv)
3457  {
3458  case 0:
3459  break;
3460 
3461  case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3462  return clib_error_return (0, "No such interface");
3463 
3464  case VNET_API_ERROR_NO_SUCH_ENTRY:
3465  return clib_error_return (0, "No such classifier table");
3466  }
3467  return 0;
3468 }
3469 
3470 /*?
3471  * Assign a classification table to an interface. The classification
3472  * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3473  * commands. Once the table is create, use this command to filter packets
3474  * on an interface.
3475  *
3476  * @cliexpar
3477  * Example of how to assign a classification table to an interface:
3478  * @cliexcmd{set ip6 classify intfc GigabitEthernet2/0/0 table-index 1}
3479 ?*/
3480 /* *INDENT-OFF* */
3481 VLIB_CLI_COMMAND (set_ip6_classify_command, static) =
3482 {
3483  .path = "set ip6 classify",
3484  .short_help =
3485  "set ip6 classify intfc <interface> table-index <classify-idx>",
3486  .function = set_ip6_classify_command_fn,
3487 };
3488 /* *INDENT-ON* */
3489 
3490 static clib_error_t *
3492 {
3493  ip6_main_t *im = &ip6_main;
3494  uword heapsize = 0;
3495  u32 tmp;
3496  u32 nbuckets = 0;
3497 
3498  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3499  {
3500  if (unformat (input, "hash-buckets %d", &tmp))
3501  nbuckets = tmp;
3502  else if (unformat (input, "heap-size %dm", &tmp))
3503  heapsize = ((u64) tmp) << 20;
3504  else if (unformat (input, "heap-size %dM", &tmp))
3505  heapsize = ((u64) tmp) << 20;
3506  else if (unformat (input, "heap-size %dg", &tmp))
3507  heapsize = ((u64) tmp) << 30;
3508  else if (unformat (input, "heap-size %dG", &tmp))
3509  heapsize = ((u64) tmp) << 30;
3510  else
3511  return clib_error_return (0, "unknown input '%U'",
3512  format_unformat_error, input);
3513  }
3514 
3515  im->lookup_table_nbuckets = nbuckets;
3516  im->lookup_table_size = heapsize;
3517 
3518  return 0;
3519 }
3520 
3522 
3523 /*
3524  * fd.io coding-style-patch-verification: ON
3525  *
3526  * Local Variables:
3527  * eval: (c-set-style "gnu")
3528  * End:
3529  */
static uword ip6_rewrite(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip6_forward.c:2290
u8 * format_ip6_forward_next_trace(u8 *s, va_list *args)
Definition: ip6_forward.c:989
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:436
#define foreach_ip_interface_address(lm, a, sw_if_index, loop, body)
Definition: lookup.h:179
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, fib_protocol_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, 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:754
#define vnet_rewrite_one_header(rw0, p0, most_likely_size)
Definition: rewrite.h:281
u16 lb_n_buckets
number of buckets in the load-balance.
Definition: load_balance.h:88
#define HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:187
vmrglw vmrglh hi
vlib_combined_counter_main_t lbm_to_counters
Definition: load_balance.h:46
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
static u8 * format_ip6_lookup_trace(u8 *s, va_list *args)
Definition: ip6_forward.c:1003
#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.
a
Definition: bitmap.h:516
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:211
static void vlib_buffer_free(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Free buffers Frees the entire buffer chain for each buffer.
Definition: buffer_funcs.h:290
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: memory_vlib.c:1173
static uword ip6_midchain(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip6_forward.c:2310
u32 * mfib_index_by_sw_if_index
Table index indexed by software interface.
Definition: ip6.h:166
uword lookup_table_size
Definition: ip6.h:191
#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:251
static void vlib_set_next_frame_buffer(vlib_main_t *vm, vlib_node_runtime_t *node, u32 next_index, u32 buffer_index)
Definition: node_funcs.h:399
ip_interface_address_t * if_address_pool
Pool of addresses that are assigned to interfaces.
Definition: lookup.h:122
static clib_error_t * add_del_ip6_interface_table(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: ip6_forward.c:3018
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
static uword ip6_glean(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip6_forward.c:1814
static vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
struct ip_adjacency_t_::@37::@38 nbr
IP_LOOKUP_NEXT_ARP/IP_LOOKUP_NEXT_REWRITE.
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:3428
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:2519
The table that stores ALL routes learned by the DP.
Definition: ip6.h:122
#define PREDICT_TRUE(x)
Definition: clib.h:98
#define foreach_ip6_hop_by_hop_error
Definition: ip6_forward.c:2391
u8 as_u8[16]
Definition: ip6_packet.h:48
u64 as_u64[2]
Definition: ip6_packet.h:51
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:284
vlib_node_registration_t ip6_lookup_node
(constructor) VLIB_REGISTER_NODE (ip6_lookup_node)
Definition: ip6_forward.c:733
#define vnet_fixup_one_header(rw0, addr, p0)
Definition: rewrite.h:308
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:1957
static u8 * format_ip6_rewrite_trace(u8 *s, va_list *args)
Definition: ip6_forward.c:1020
#define NULL
Definition: clib.h:55
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:192
IP unicast adjacency.
Definition: adj.h:174
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:929
static void * clib_random_buffer_get_data(clib_random_buffer_t *b, uword n_bytes)
Definition: random_buffer.h:78
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:459
flow_hash_config_t lb_hash_config
the hash config to use when selecting a bucket.
Definition: load_balance.h:128
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:169
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:522
int ip6_hbh_unregister_option(u8 option)
Definition: ip6_forward.c:2894
struct _vlib_node_registration vlib_node_registration_t
static clib_error_t * ip6_config(vlib_main_t *vm, unformat_input_t *input)
Definition: ip6_forward.c:3491
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:983
#define STRUCT_OFFSET_OF(t, f)
Definition: clib.h:62
uword ip_csum_t
Definition: ip_packet.h:90
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:3144
static ip_csum_t ip_csum_with_carry(ip_csum_t sum, ip_csum_t x)
Definition: ip_packet.h:93
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:2361
union ip_adjacency_t_::@37 sub_type
#define VNET_HW_INTERFACE_FLAG_LINK_UP
Definition: interface.h:397
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:419
static char * ip6_hop_by_hop_error_strings[]
Definition: ip6_forward.c:2419
Definition: fib_entry.h:235
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:100
static uword ip6_load_balance(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip6_forward.c:747
ip6_address_t src_address
Definition: ip6_packet.h:341
u8 mcast_feature_arc_index
Feature arc indices.
Definition: lookup.h:135
#define hash_v3_mix32(a, b, c)
Definition: hash.h:530
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:1081
static uword ip6_hop_by_hop(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip6_forward.c:2596
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:350
static uword ip6_vxlan_bypass(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: decap.c:1211
VNET_FEATURE_ARC_INIT(ip6_unicast, static)
static vlib_node_registration_t ip6_drop_node
(constructor) VLIB_REGISTER_NODE (ip6_drop_node)
Definition: ip6_forward.c:1162
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_physmem_alloc, char *fmt,...)
ip6_discover_neighbor_error_t
Definition: ip6_forward.c:1607
static uword ip6_drop(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip6_forward.c:1150
vlib_packet_template_t discover_neighbor_packet_template
Definition: ip6.h:187
u32 ip6_tcp_udp_icmp_validate_checksum(vlib_main_t *vm, vlib_buffer_t *p0)
Definition: ip6_forward.c:1271
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:365
ip6_main_t ip6_main
Definition: ip6_forward.c:2926
clib_error_t * ip6_sw_interface_add_del(vnet_main_t *vnm, u32 sw_if_index, u32 is_add)
Definition: ip6_forward.c:685
#define VLIB_BUFFER_NEXT_PRESENT
Definition: buffer.h:87
static u8 * format_ip6_hop_by_hop_trace(u8 *s, va_list *args)
Definition: ip6_forward.c:2470
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:67
u8 * format_ethernet_address(u8 *s, va_list *args)
Definition: format.c:44
#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:170
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:3327
ip_csum_t ip_incremental_checksum(ip_csum_t sum, void *_data, uword n_bytes)
Definition: ip_checksum.c:43
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
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:390
#define always_inline
Definition: clib.h:84
static uword pow2_mask(uword x)
Definition: clib.h:257
#define IP_BUFFER_L4_CHECKSUM_CORRECT
Definition: buffer.h:50
static uword format_get_indent(u8 *s)
Definition: format.h:72
u16 lb_n_buckets_minus_1
number of buckets in the load-balance - 1.
Definition: load_balance.h:93
static vlib_node_registration_t ip6_mcast_midchain_node
(constructor) VLIB_REGISTER_NODE (ip6_mcast_midchain_node)
Definition: ip6_forward.c:2374
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:3199
u8 * format_white_space(u8 *s, va_list *va)
Definition: std-formats.c:113
int i32
Definition: types.h:81
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:164
#define IP6_FIB_DEFAULT_HASH_NUM_BUCKETS
Definition: ip6.h:57
Aggregrate type for a prefix.
Definition: fib_types.h:160
#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:144
unsigned long u64
Definition: types.h:89
void adj_unlock(adj_index_t adj_index)
Release a reference counting lock on the adjacency.
Definition: adj.c:229
#define LOG2_IP_BUFFER_L4_CHECKSUM_CORRECT
Definition: buffer.h:48
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:1025
u16 fp_len
The mask length.
Definition: fib_types.h:164
#define vlib_call_init_function(vm, x)
Definition: init.h:162
u8 * format_ip6_hop_by_hop_ext_hdr(u8 *s, va_list *args)
Definition: ip6_forward.c:2426
ip6_hop_by_hop_error_t
Definition: ip6_forward.c:2397
static clib_error_t * vnet_feature_init(vlib_main_t *vm)
Definition: feature.c:22
static uword ip6_discover_neighbor_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, int is_glean)
Definition: ip6_forward.c:1615
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:509
u32 lookup_table_nbuckets
Definition: ip6.h:190
Definition: fib_entry.h:233
static int ip6_src_address_for_packet(ip_lookup_main_t *lm, u32 sw_if_index, ip6_address_t *src)
Definition: ip6.h:262
u8 packet_data[128-1 *sizeof(u32)]
Definition: ip6_forward.c:984
vnet_api_error_t api_errno
Definition: vnet.h:76
The identity of a DPO is a combination of its type and its instance number/index of objects of that t...
Definition: dpo.h:152
Definition: fib_entry.h:238
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:397
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:71
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
ip6_error_t
Definition: ip6_error.h:76
ip46_address_t fp_addr
The address type is not deriveable from the fp_addr member.
Definition: fib_types.h:183
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:400
static const dpo_id_t * load_balance_get_bucket_i(const load_balance_t *lb, u32 bucket)
Definition: load_balance.h:202
vlib_node_registration_t ip6_input_node
(constructor) VLIB_REGISTER_NODE (ip6_input_node)
Definition: ip6_input.c:327
uword vlib_error_drop_buffers(vlib_main_t *vm, vlib_node_runtime_t *node, u32 *buffers, u32 next_buffer_stride, u32 n_buffers, u32 next_index, u32 drop_error_node, u32 drop_error_code)
Definition: error.c:44
struct _unformat_input_t unformat_input_t
#define IP6_FIB_DEFAULT_HASH_MEMORY_SIZE
Definition: ip6.h:58
static vlib_node_registration_t ip6_punt_node
(constructor) VLIB_REGISTER_NODE (ip6_punt_node)
Definition: ip6_forward.c:1178
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:188
int vnet_set_ip6_flow_hash(u32 table_id, u32 flow_hash_config)
Definition: ip6_forward.c:3183
static u32 ip6_compute_flow_hash(const ip6_header_t *ip, flow_hash_config_t flow_hash_config)
Definition: ip6.h:391
The FIB DPO provieds;.
Definition: load_balance.h:84
#define PREDICT_FALSE(x)
Definition: clib.h:97
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:2850
load_balance_main_t load_balance_main
The one instance of load-balance main.
Definition: load_balance.c:55
struct ip_adjacency_t_::@37::@39 midchain
IP_LOOKUP_NEXT_MIDCHAIN.
#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:216
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:366
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:2870
void clib_bihash_init(clib_bihash *h, char *name, u32 nbuckets, uword memory_size)
initialize a bounded index extensible hash table
vlib_combined_counter_main_t adjacency_counters
Adjacency packet counters.
Definition: adj.c:25
ip6_add_del_interface_address_callback_t * add_del_interface_address_callbacks
Definition: ip6.h:184
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:1039
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:113
static uword ip6_local(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip6_forward.c:1320
u32 as_u32[4]
Definition: ip6_packet.h:50
ip6_address_t fib_masks[129]
Definition: ip6.h:160
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:259
#define OI_DECAP
Definition: ip6_forward.c:55
#define VLIB_EARLY_CONFIG_FUNCTION(x, n,...)
Definition: init.h:140
Adjacency to drop this packet.
Definition: adj.h:53
static void vlib_buffer_copy_trace_flag(vlib_main_t *vm, vlib_buffer_t *b, u32 bi_target)
Definition: trace_funcs.h:134
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
#define VNET_BUFFER_LOCALLY_ORIGINATED
Definition: buffer.h:68
u16 n_vectors
Definition: node.h:345
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:185
format_function_t format_ip6_address
Definition: format.h:95
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
ip6_address_t * ip6_interface_first_address(ip6_main_t *im, u32 sw_if_index)
get first IPv6 interface address
Definition: ip6_forward.c:453
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:340
static vlib_node_registration_t ip6_local_node
(constructor) VLIB_REGISTER_NODE (ip6_local_node)
Definition: ip6_forward.c:1569
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:835
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:994
clib_error_t * ip6_sw_interface_admin_up_down(vnet_main_t *vnm, u32 sw_if_index, u32 flags)
Definition: ip6_forward.c:527
vlib_node_registration_t ip6_midchain_node
(constructor) VLIB_REGISTER_NODE (ip6_midchain_node)
Definition: ip6_forward.c:2330
#define clib_warning(format, args...)
Definition: error.h:59
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:85
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:88
clib_error_t * ip6_probe_neighbor(vlib_main_t *vm, ip6_address_t *dst, u32 sw_if_index)
Definition: ip6_forward.c:1863
This table stores the routes that are used to forward traffic.
Definition: ip6.h:115
#define clib_memcpy(a, b, c)
Definition: string.h:69
static uword ip6_drop_or_punt(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, ip6_error_t error_code)
Definition: ip6_forward.c:1130
unformat_function_t * unformat_edit
Definition: pg.h:307
void ip_lookup_init(ip_lookup_main_t *lm, u32 is_ip6)
Definition: lookup.c:192
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:238
u32 adj_index_t
An index for adjacencies.
Definition: adj_types.h:30
#define ARRAY_LEN(x)
Definition: clib.h:59
static void ip6_addr_fib_init(ip6_address_fib_t *addr_fib, ip6_address_t *address, u32 fib_index)
Definition: ip6_packet.h:98
void ip6_ethernet_mac_address_from_link_local_address(u8 *mac, ip6_address_t *ip)
Definition: ip6_forward.c:3131
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:159
vlib_combined_counter_main_t lbm_via_counters
Definition: load_balance.h:47
u8 hbh_enabled
Definition: ip6.h:205
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:72
#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:290
ip6_add_del_interface_address_function_t * function
Definition: ip6.h:102
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:460
void ip6_register_protocol(u32 protocol, u32 node_index)
Definition: ip6_forward.c:1589
#define VNET_SW_INTERFACE_FLAG_ADMIN_UP
Definition: interface.h:560
uword unformat_ethernet_address(unformat_input_t *input, va_list *args)
Definition: format.c:227
vlib_node_registration_t ip6_discover_neighbor_node
(constructor) VLIB_REGISTER_NODE (ip6_discover_neighbor_node)
Definition: ip6_forward.c:1827
#define ASSERT(truth)
index_t lb_urpf
This is the index of the uRPF list for this LB.
Definition: load_balance.h:123
unsigned int u32
Definition: types.h:88
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:2389
ip_lookup_main_t lookup_main
Definition: ip6.h:148
#define IP_BUFFER_L4_CHECKSUM_COMPUTED
Definition: buffer.h:49
void ip6_hbh_set_next_override(uword next)
Definition: ip6_forward.c:2862
static load_balance_t * load_balance_get(index_t lbi)
Definition: load_balance.h:193
#define hash_v3_finalize32(a, b, c)
Definition: hash.h:540
static uword ip6_discover_neighbor(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip6_forward.c:1807
vlib_node_registration_t ip6_glean_node
(constructor) VLIB_REGISTER_NODE (ip6_glean_node)
Definition: ip6_forward.c:1845
Classify.
Definition: fib_entry.h:44
u32 next_buffer
Next buffer for this linked-list of buffers.
Definition: buffer.h:109
vlib_node_registration_t ip6_hop_by_hop_node
(constructor) VLIB_REGISTER_NODE (ip6_hop_by_hop_node)
Definition: ip6_forward.c:2417
u32 fib_table_find_or_create_and_lock(fib_protocol_t proto, u32 table_id)
Get the index of the FIB for a Table-ID.
Definition: fib_table.c:1041
#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:201
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:260
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:3368
format_function_t format_ip6_header
Definition: format.h:98
static char * ip6_discover_neighbor_error_strings[]
Definition: ip6_forward.c:1819
Route added as a result of interface configuration.
Definition: fib_entry.h:50
ip6_fib_table_instance_t ip6_table[IP6_FIB_NUM_TABLES]
The two FIB tables; fwding and non-fwding.
Definition: ip6.h:146
#define VNET_FEATURES(...)
Definition: feature.h:368
static int ip6_locate_header(vlib_buffer_t *p0, ip6_header_t *ip0, int find_hdr_type, u32 *offset)
Definition: ip6.h:458
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:2343
static uword is_pow2(uword x)
Definition: clib.h:272
static uword ip6_mcast_midchain(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip6_forward.c:2320
u64 uword
Definition: types.h:112
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.
u8 ucast_feature_arc_index
Definition: lookup.h:136
static uword ip6_lookup_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip6_forward.c:71
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:421
Definition: defs.h:47
u32 ip6_fib_table_fwding_lookup_with_if_index(ip6_main_t *im, u32 sw_if_index, const ip6_address_t *dst)
Definition: ip6_fib.c:344
unsigned short u16
Definition: types.h:57
#define HBH_OPTION_TYPE_DISCARD_UNKNOWN
static uword ip6_address_is_multicast(ip6_address_t *a)
Definition: ip6_packet.h:145
u16 payload_length
Definition: ip6_packet.h:332
u32 mfib_table_find_or_create_and_lock(fib_protocol_t proto, u32 table_id)
Get the index of the FIB for a Table-ID.
Definition: mfib_table.c:426
index_t dpoi_index
the index of objects of that type
Definition: dpo.h:168
static void ip6_set_solicited_node_multicast_address(ip6_address_t *a, u32 id)
Definition: ip6_packet.h:168
static uword ip6_address_is_link_local_unicast(ip6_address_t *a)
Definition: ip6_packet.h:296
static uword ip6_rewrite_mcast(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip6_forward.c:2300
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:142
unsigned char u8
Definition: types.h:56
ip_lookup_next_t lookup_next_index
Next hop after ip4-lookup.
Definition: adj.h:189
Definition: fib_entry.h:234
static uword max_log2(uword x)
Definition: clib.h:228
void ip6_link_local_address_from_ethernet_mac_address(ip6_address_t *ip, u8 *mac)
Definition: ip6_forward.c:3115
static uword ip6_inacl(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip_input_acl.c:411
unformat_function_t unformat_pg_ip6_header
Definition: format.h:99
vnet_sw_interface_t * sw_interfaces
Definition: interface.h:644
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:269
#define DPO_INVALID
An initialiser for DPOs declared on the stack.
Definition: dpo.h:179
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:339
clib_error_t * ip_interface_address_add_del(ip_lookup_main_t *lm, u32 sw_if_index, void *addr_fib, u32 address_length, u32 is_del, u32 *result_if_address_index)
Definition: lookup.c:61
A collection of combined counters.
Definition: counter.h:180
#define clib_mem_unaligned(pointer, type)
Definition: types.h:155
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:1195
static uword ip6_policer_classify(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: node_funcs.c:875
void * vlib_packet_template_get_packet(vlib_main_t *vm, vlib_packet_template_t *t, u32 *bi_result)
u8 *(* trace[256])(u8 *s, ip6_hop_by_hop_option_t *opt)
Definition: ip6.h:528
#define vnet_buffer(b)
Definition: buffer.h:303
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:144
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:1304
u8 data[0]
Packet data.
Definition: buffer.h:152
#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:205
#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:454
u16 dpoi_next_node
The next VLIB node to follow.
Definition: dpo.h:164
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:196
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:526
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:472
static clib_error_t * ip6_lookup_init(vlib_main_t *vm)
Definition: ip6_forward.c:2929
u32 flags
Definition: vhost-user.h:76
#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:485
static uword ip6_lookup(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip6_forward.c:724
#define vnet_rewrite_two_headers(rw0, rw1, p0, p1, most_likely_size)
Definition: rewrite.h:286
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:74
vlib_node_registration_t ip6_load_balance_node
(constructor) VLIB_REGISTER_NODE (ip6_load_balance_node)
Definition: ip6_forward.c:964
This adjacency/interface has output features configured.
Definition: rewrite.h:57
#define BITS(x)
Definition: clib.h:58
ip6_discover_neighbor_next_t
Definition: ip6_forward.c:1600
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:680
u32 * fib_index_by_sw_if_index
Definition: ip6.h:163
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
clib_random_buffer_t random_buffer
Definition: main.h:153
Definition: pg.h:304
static u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:145
static uword ip6_punt(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ip6_forward.c:1156
static int adj_are_counters_enabled(void)
Get the global configuration option for enabling per-adj counters.
Definition: adj.h:374
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:225
ip6_address_t dst_address
Definition: ip6_packet.h:341
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
uword next_override
Definition: ip6.h:529
ip6_rewrite_next_t
Definition: ip6_forward.c:1950
static_always_inline void vnet_feature_arc_start(u8 arc, u32 sw_if_index, u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:201
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:109