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