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