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