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