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