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