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