232f72833fd619c3f9dbc32194dbee211d532bf4
[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           vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
1367           vnet_buffer (p1)->ip.start_of_ip_header = p1->current_data;
1368
1369           type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
1370           type1 = lm->builtin_protocol_by_ip_protocol[ip1->protocol];
1371
1372           next0 = lm->local_next_by_ip_protocol[ip0->protocol];
1373           next1 = lm->local_next_by_ip_protocol[ip1->protocol];
1374
1375           flags0 = p0->flags;
1376           flags1 = p1->flags;
1377
1378           good_l4_checksum0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1379           good_l4_checksum1 = (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1380           len_diff0 = 0;
1381           len_diff1 = 0;
1382
1383           /* Skip HBH local processing */
1384           if (PREDICT_FALSE
1385               (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
1386             {
1387               ip6_hop_by_hop_ext_t *ext_hdr =
1388                 (ip6_hop_by_hop_ext_t *) ip6_next_header (ip0);
1389               next0 = lm->local_next_by_ip_protocol[ext_hdr->next_hdr];
1390               type0 = lm->builtin_protocol_by_ip_protocol[ext_hdr->next_hdr];
1391             }
1392           if (PREDICT_FALSE
1393               (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
1394             {
1395               ip6_hop_by_hop_ext_t *ext_hdr =
1396                 (ip6_hop_by_hop_ext_t *) ip6_next_header (ip1);
1397               next1 = lm->local_next_by_ip_protocol[ext_hdr->next_hdr];
1398               type1 = lm->builtin_protocol_by_ip_protocol[ext_hdr->next_hdr];
1399             }
1400           if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p0, ip0,
1401                                                                   IP_PROTOCOL_UDP,
1402                                                                   &udp_offset0)))
1403             {
1404               udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
1405               /* Don't verify UDP checksum for packets with explicit zero checksum. */
1406               good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
1407                 && udp0->checksum == 0;
1408               /* Verify UDP length. */
1409               ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1410               udp_len0 = clib_net_to_host_u16 (udp0->length);
1411               len_diff0 = ip_len0 - udp_len0;
1412             }
1413           if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p1, ip1,
1414                                                                   IP_PROTOCOL_UDP,
1415                                                                   &udp_offset1)))
1416             {
1417               udp1 = (udp_header_t *) ((u8 *) ip1 + udp_offset1);
1418               /* Don't verify UDP checksum for packets with explicit zero checksum. */
1419               good_l4_checksum1 |= type1 == IP_BUILTIN_PROTOCOL_UDP
1420                 && udp1->checksum == 0;
1421               /* Verify UDP length. */
1422               ip_len1 = clib_net_to_host_u16 (ip1->payload_length);
1423               udp_len1 = clib_net_to_host_u16 (udp1->length);
1424               len_diff1 = ip_len1 - udp_len1;
1425             }
1426
1427           good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
1428           good_l4_checksum1 |= type1 == IP_BUILTIN_PROTOCOL_UNKNOWN;
1429
1430           len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1431           len_diff1 = type1 == IP_BUILTIN_PROTOCOL_UDP ? len_diff1 : 0;
1432
1433           if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
1434                              && !good_l4_checksum0
1435                              && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED)))
1436             {
1437               flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
1438               good_l4_checksum0 =
1439                 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1440             }
1441           if (PREDICT_FALSE (type1 != IP_BUILTIN_PROTOCOL_UNKNOWN
1442                              && !good_l4_checksum1
1443                              && !(flags1 & IP_BUFFER_L4_CHECKSUM_COMPUTED)))
1444             {
1445               flags1 = ip6_tcp_udp_icmp_validate_checksum (vm, p1);
1446               good_l4_checksum1 =
1447                 (flags1 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1448             }
1449
1450           error0 = error1 = IP6_ERROR_UNKNOWN_PROTOCOL;
1451
1452           error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1453           error1 = len_diff1 < 0 ? IP6_ERROR_UDP_LENGTH : error1;
1454
1455           ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1456                   IP6_ERROR_UDP_CHECKSUM);
1457           ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1458                   IP6_ERROR_ICMP_CHECKSUM);
1459           error0 =
1460             (!good_l4_checksum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
1461           error1 =
1462             (!good_l4_checksum1 ? IP6_ERROR_UDP_CHECKSUM + type1 : error1);
1463
1464           /* Drop packets from unroutable hosts. */
1465           /* If this is a neighbor solicitation (ICMP), skip source RPF check */
1466           if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1467               type0 != IP_BUILTIN_PROTOCOL_ICMP &&
1468               !ip6_address_is_link_local_unicast (&ip0->src_address))
1469             {
1470               u32 src_adj_index0 = ip6_src_lookup_for_packet (im, p0, ip0);
1471               error0 = (ADJ_INDEX_INVALID == src_adj_index0
1472                         ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
1473             }
1474           if (error1 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1475               type1 != IP_BUILTIN_PROTOCOL_ICMP &&
1476               !ip6_address_is_link_local_unicast (&ip1->src_address))
1477             {
1478               u32 src_adj_index1 = ip6_src_lookup_for_packet (im, p1, ip1);
1479               error1 = (ADJ_INDEX_INVALID == src_adj_index1
1480                         ? IP6_ERROR_SRC_LOOKUP_MISS : error1);
1481             }
1482
1483           next0 =
1484             error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1485           next1 =
1486             error1 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
1487
1488           p0->error = error_node->errors[error0];
1489           p1->error = error_node->errors[error1];
1490
1491           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1492                                            to_next, n_left_to_next,
1493                                            pi0, pi1, next0, next1);
1494         }
1495
1496       while (n_left_from > 0 && n_left_to_next > 0)
1497         {
1498           vlib_buffer_t *p0;
1499           ip6_header_t *ip0;
1500           udp_header_t *udp0;
1501           u32 pi0, ip_len0, udp_len0, flags0, next0;
1502           i32 len_diff0;
1503           u8 error0, type0, good_l4_checksum0;
1504           u32 udp_offset0;
1505
1506           pi0 = to_next[0] = from[0];
1507           from += 1;
1508           n_left_from -= 1;
1509           to_next += 1;
1510           n_left_to_next -= 1;
1511
1512           p0 = vlib_get_buffer (vm, pi0);
1513
1514           ip0 = vlib_buffer_get_current (p0);
1515
1516           vnet_buffer (p0)->ip.start_of_ip_header = p0->current_data;
1517
1518           type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
1519           next0 = lm->local_next_by_ip_protocol[ip0->protocol];
1520
1521           flags0 = p0->flags;
1522
1523           good_l4_checksum0 = (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1524           len_diff0 = 0;
1525
1526           /* Skip HBH local processing */
1527           if (PREDICT_FALSE
1528               (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
1529             {
1530               ip6_hop_by_hop_ext_t *ext_hdr =
1531                 (ip6_hop_by_hop_ext_t *) ip6_next_header (ip0);
1532               next0 = lm->local_next_by_ip_protocol[ext_hdr->next_hdr];
1533               type0 = lm->builtin_protocol_by_ip_protocol[ext_hdr->next_hdr];
1534             }
1535           if (PREDICT_TRUE (IP_PROTOCOL_UDP == ip6_locate_header (p0, ip0,
1536                                                                   IP_PROTOCOL_UDP,
1537                                                                   &udp_offset0)))
1538             {
1539               udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
1540               /* Don't verify UDP checksum for packets with explicit zero checksum. */
1541               good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
1542                 && udp0->checksum == 0;
1543               /* Verify UDP length. */
1544               ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1545               udp_len0 = clib_net_to_host_u16 (udp0->length);
1546               len_diff0 = ip_len0 - udp_len0;
1547             }
1548
1549           good_l4_checksum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
1550           len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1551
1552           if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
1553                              && !good_l4_checksum0
1554                              && !(flags0 & IP_BUFFER_L4_CHECKSUM_COMPUTED)))
1555             {
1556               flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
1557               good_l4_checksum0 =
1558                 (flags0 & IP_BUFFER_L4_CHECKSUM_CORRECT) != 0;
1559             }
1560
1561           error0 = IP6_ERROR_UNKNOWN_PROTOCOL;
1562
1563           error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1564
1565           ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1566                   IP6_ERROR_UDP_CHECKSUM);
1567           ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1568                   IP6_ERROR_ICMP_CHECKSUM);
1569           error0 =
1570             (!good_l4_checksum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
1571
1572           /* If this is a neighbor solicitation (ICMP), skip source RPF check */
1573           if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1574               type0 != IP_BUILTIN_PROTOCOL_ICMP &&
1575               !ip6_address_is_link_local_unicast (&ip0->src_address))
1576             {
1577               u32 src_adj_index0 = ip6_src_lookup_for_packet (im, p0, ip0);
1578               error0 = (ADJ_INDEX_INVALID == src_adj_index0
1579                         ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
1580             }
1581
1582           next0 =
1583             error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1584
1585           p0->error = error_node->errors[error0];
1586
1587           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1588                                            to_next, n_left_to_next,
1589                                            pi0, next0);
1590         }
1591
1592       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1593     }
1594
1595   return frame->n_vectors;
1596 }
1597
1598 /* *INDENT-OFF* */
1599 VLIB_REGISTER_NODE (ip6_local_node, static) =
1600 {
1601   .function = ip6_local,
1602   .name = "ip6-local",
1603   .vector_size = sizeof (u32),
1604   .format_trace = format_ip6_forward_next_trace,
1605   .n_next_nodes = IP_LOCAL_N_NEXT,
1606   .next_nodes =
1607   {
1608     [IP_LOCAL_NEXT_DROP] = "error-drop",
1609     [IP_LOCAL_NEXT_PUNT] = "error-punt",
1610     [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
1611     [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
1612   },
1613 };
1614 /* *INDENT-ON* */
1615
1616 VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_node, ip6_local);
1617
1618 void
1619 ip6_register_protocol (u32 protocol, u32 node_index)
1620 {
1621   vlib_main_t *vm = vlib_get_main ();
1622   ip6_main_t *im = &ip6_main;
1623   ip_lookup_main_t *lm = &im->lookup_main;
1624
1625   ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1626   lm->local_next_by_ip_protocol[protocol] =
1627     vlib_node_add_next (vm, ip6_local_node.index, node_index);
1628 }
1629
1630 typedef enum
1631 {
1632   IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
1633   IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX,
1634   IP6_DISCOVER_NEIGHBOR_N_NEXT,
1635 } ip6_discover_neighbor_next_t;
1636
1637 typedef enum
1638 {
1639   IP6_DISCOVER_NEIGHBOR_ERROR_DROP,
1640   IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT,
1641   IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS,
1642 } ip6_discover_neighbor_error_t;
1643
1644 static uword
1645 ip6_discover_neighbor_inline (vlib_main_t * vm,
1646                               vlib_node_runtime_t * node,
1647                               vlib_frame_t * frame, int is_glean)
1648 {
1649   vnet_main_t *vnm = vnet_get_main ();
1650   ip6_main_t *im = &ip6_main;
1651   ip_lookup_main_t *lm = &im->lookup_main;
1652   u32 *from, *to_next_drop;
1653   uword n_left_from, n_left_to_next_drop;
1654   static f64 time_last_seed_change = -1e100;
1655   static u32 hash_seeds[3];
1656   static uword hash_bitmap[256 / BITS (uword)];
1657   f64 time_now;
1658   int bogus_length;
1659
1660   if (node->flags & VLIB_NODE_FLAG_TRACE)
1661     ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1662
1663   time_now = vlib_time_now (vm);
1664   if (time_now - time_last_seed_change > 1e-3)
1665     {
1666       uword i;
1667       u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
1668                                             sizeof (hash_seeds));
1669       for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
1670         hash_seeds[i] = r[i];
1671
1672       /* Mark all hash keys as been not-seen before. */
1673       for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
1674         hash_bitmap[i] = 0;
1675
1676       time_last_seed_change = time_now;
1677     }
1678
1679   from = vlib_frame_vector_args (frame);
1680   n_left_from = frame->n_vectors;
1681
1682   while (n_left_from > 0)
1683     {
1684       vlib_get_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
1685                            to_next_drop, n_left_to_next_drop);
1686
1687       while (n_left_from > 0 && n_left_to_next_drop > 0)
1688         {
1689           vlib_buffer_t *p0;
1690           ip6_header_t *ip0;
1691           u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
1692           uword bm0;
1693           ip_adjacency_t *adj0;
1694           vnet_hw_interface_t *hw_if0;
1695           u32 next0;
1696
1697           pi0 = from[0];
1698
1699           p0 = vlib_get_buffer (vm, pi0);
1700
1701           adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1702
1703           ip0 = vlib_buffer_get_current (p0);
1704
1705           adj0 = ip_get_adjacency (lm, adj_index0);
1706
1707           if (!is_glean)
1708             {
1709               ip0->dst_address.as_u64[0] =
1710                 adj0->sub_type.nbr.next_hop.ip6.as_u64[0];
1711               ip0->dst_address.as_u64[1] =
1712                 adj0->sub_type.nbr.next_hop.ip6.as_u64[1];
1713             }
1714
1715           a0 = hash_seeds[0];
1716           b0 = hash_seeds[1];
1717           c0 = hash_seeds[2];
1718
1719           sw_if_index0 = adj0->rewrite_header.sw_if_index;
1720           vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1721
1722           a0 ^= sw_if_index0;
1723           b0 ^= ip0->dst_address.as_u32[0];
1724           c0 ^= ip0->dst_address.as_u32[1];
1725
1726           hash_v3_mix32 (a0, b0, c0);
1727
1728           b0 ^= ip0->dst_address.as_u32[2];
1729           c0 ^= ip0->dst_address.as_u32[3];
1730
1731           hash_v3_finalize32 (a0, b0, c0);
1732
1733           c0 &= BITS (hash_bitmap) - 1;
1734           c0 = c0 / BITS (uword);
1735           m0 = (uword) 1 << (c0 % BITS (uword));
1736
1737           bm0 = hash_bitmap[c0];
1738           drop0 = (bm0 & m0) != 0;
1739
1740           /* Mark it as seen. */
1741           hash_bitmap[c0] = bm0 | m0;
1742
1743           from += 1;
1744           n_left_from -= 1;
1745           to_next_drop[0] = pi0;
1746           to_next_drop += 1;
1747           n_left_to_next_drop -= 1;
1748
1749           hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
1750
1751           /* If the interface is link-down, drop the pkt */
1752           if (!(hw_if0->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
1753             drop0 = 1;
1754
1755           p0->error =
1756             node->errors[drop0 ? IP6_DISCOVER_NEIGHBOR_ERROR_DROP
1757                          : IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT];
1758           if (drop0)
1759             continue;
1760
1761           /*
1762            * the adj has been updated to a rewrite but the node the DPO that got
1763            * us here hasn't - yet. no big deal. we'll drop while we wait.
1764            */
1765           if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
1766             continue;
1767
1768           {
1769             u32 bi0 = 0;
1770             icmp6_neighbor_solicitation_header_t *h0;
1771             vlib_buffer_t *b0;
1772
1773             h0 = vlib_packet_template_get_packet
1774               (vm, &im->discover_neighbor_packet_template, &bi0);
1775
1776             /*
1777              * Build ethernet header.
1778              * Choose source address based on destination lookup
1779              * adjacency.
1780              */
1781             if (ip6_src_address_for_packet (lm,
1782                                             sw_if_index0,
1783                                             &h0->ip.src_address))
1784               {
1785                 /* There is no address on the interface */
1786                 p0->error =
1787                   node->errors[IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS];
1788                 vlib_buffer_free (vm, &bi0, 1);
1789                 continue;
1790               }
1791
1792             /*
1793              * Destination address is a solicited node multicast address.
1794              * We need to fill in
1795              * the low 24 bits with low 24 bits of target's address.
1796              */
1797             h0->ip.dst_address.as_u8[13] = ip0->dst_address.as_u8[13];
1798             h0->ip.dst_address.as_u8[14] = ip0->dst_address.as_u8[14];
1799             h0->ip.dst_address.as_u8[15] = ip0->dst_address.as_u8[15];
1800
1801             h0->neighbor.target_address = ip0->dst_address;
1802
1803             clib_memcpy (h0->link_layer_option.ethernet_address,
1804                          hw_if0->hw_address, vec_len (hw_if0->hw_address));
1805
1806             /* $$$$ appears we need this; why is the checksum non-zero? */
1807             h0->neighbor.icmp.checksum = 0;
1808             h0->neighbor.icmp.checksum =
1809               ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h0->ip,
1810                                                  &bogus_length);
1811
1812             ASSERT (bogus_length == 0);
1813
1814             vlib_buffer_copy_trace_flag (vm, p0, bi0);
1815             b0 = vlib_get_buffer (vm, bi0);
1816             vnet_buffer (b0)->sw_if_index[VLIB_TX]
1817               = vnet_buffer (p0)->sw_if_index[VLIB_TX];
1818
1819             /* Add rewrite/encap string. */
1820             vnet_rewrite_one_header (adj0[0], h0, sizeof (ethernet_header_t));
1821             vlib_buffer_advance (b0, -adj0->rewrite_header.data_bytes);
1822
1823             next0 = IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX;
1824
1825             vlib_set_next_frame_buffer (vm, node, next0, bi0);
1826           }
1827         }
1828
1829       vlib_put_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
1830                            n_left_to_next_drop);
1831     }
1832
1833   return frame->n_vectors;
1834 }
1835
1836 static uword
1837 ip6_discover_neighbor (vlib_main_t * vm,
1838                        vlib_node_runtime_t * node, vlib_frame_t * frame)
1839 {
1840   return (ip6_discover_neighbor_inline (vm, node, frame, 0));
1841 }
1842
1843 static uword
1844 ip6_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1845 {
1846   return (ip6_discover_neighbor_inline (vm, node, frame, 1));
1847 }
1848
1849 static char *ip6_discover_neighbor_error_strings[] = {
1850   [IP6_DISCOVER_NEIGHBOR_ERROR_DROP] = "address overflow drops",
1851   [IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT] = "neighbor solicitations sent",
1852   [IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS]
1853     = "no source address for ND solicitation",
1854 };
1855
1856 /* *INDENT-OFF* */
1857 VLIB_REGISTER_NODE (ip6_discover_neighbor_node) =
1858 {
1859   .function = ip6_discover_neighbor,
1860   .name = "ip6-discover-neighbor",
1861   .vector_size = sizeof (u32),
1862   .format_trace = format_ip6_forward_next_trace,
1863   .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
1864   .error_strings = ip6_discover_neighbor_error_strings,
1865   .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
1866   .next_nodes =
1867   {
1868     [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "error-drop",
1869     [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
1870   },
1871 };
1872 /* *INDENT-ON* */
1873
1874 /* *INDENT-OFF* */
1875 VLIB_REGISTER_NODE (ip6_glean_node) =
1876 {
1877   .function = ip6_glean,
1878   .name = "ip6-glean",
1879   .vector_size = sizeof (u32),
1880   .format_trace = format_ip6_forward_next_trace,
1881   .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
1882   .error_strings = ip6_discover_neighbor_error_strings,
1883   .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
1884   .next_nodes =
1885   {
1886     [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "error-drop",
1887     [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "interface-output",
1888   },
1889 };
1890 /* *INDENT-ON* */
1891
1892 clib_error_t *
1893 ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index)
1894 {
1895   vnet_main_t *vnm = vnet_get_main ();
1896   ip6_main_t *im = &ip6_main;
1897   icmp6_neighbor_solicitation_header_t *h;
1898   ip6_address_t *src;
1899   ip_interface_address_t *ia;
1900   ip_adjacency_t *adj;
1901   vnet_hw_interface_t *hi;
1902   vnet_sw_interface_t *si;
1903   vlib_buffer_t *b;
1904   u32 bi = 0;
1905   int bogus_length;
1906
1907   si = vnet_get_sw_interface (vnm, sw_if_index);
1908
1909   if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
1910     {
1911       return clib_error_return (0, "%U: interface %U down",
1912                                 format_ip6_address, dst,
1913                                 format_vnet_sw_if_index_name, vnm,
1914                                 sw_if_index);
1915     }
1916
1917   src =
1918     ip6_interface_address_matching_destination (im, dst, sw_if_index, &ia);
1919   if (!src)
1920     {
1921       vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
1922       return clib_error_return
1923         (0, "no matching interface address for destination %U (interface %U)",
1924          format_ip6_address, dst,
1925          format_vnet_sw_if_index_name, vnm, sw_if_index);
1926     }
1927
1928   h =
1929     vlib_packet_template_get_packet (vm,
1930                                      &im->discover_neighbor_packet_template,
1931                                      &bi);
1932
1933   hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1934
1935   /* Destination address is a solicited node multicast address.  We need to fill in
1936      the low 24 bits with low 24 bits of target's address. */
1937   h->ip.dst_address.as_u8[13] = dst->as_u8[13];
1938   h->ip.dst_address.as_u8[14] = dst->as_u8[14];
1939   h->ip.dst_address.as_u8[15] = dst->as_u8[15];
1940
1941   h->ip.src_address = src[0];
1942   h->neighbor.target_address = dst[0];
1943
1944   clib_memcpy (h->link_layer_option.ethernet_address, hi->hw_address,
1945                vec_len (hi->hw_address));
1946
1947   h->neighbor.icmp.checksum =
1948     ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length);
1949   ASSERT (bogus_length == 0);
1950
1951   b = vlib_get_buffer (vm, bi);
1952   vnet_buffer (b)->sw_if_index[VLIB_RX] =
1953     vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
1954
1955   /* Add encapsulation string for software interface (e.g. ethernet header). */
1956   adj = ip_get_adjacency (&im->lookup_main, ia->neighbor_probe_adj_index);
1957   vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
1958   vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
1959
1960   {
1961     vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
1962     u32 *to_next = vlib_frame_vector_args (f);
1963     to_next[0] = bi;
1964     f->n_vectors = 1;
1965     vlib_put_frame_to_node (vm, hi->output_node_index, f);
1966   }
1967
1968   return /* no error */ 0;
1969 }
1970
1971 typedef enum
1972 {
1973   IP6_REWRITE_NEXT_DROP,
1974   IP6_REWRITE_NEXT_ICMP_ERROR,
1975 } ip6_rewrite_next_t;
1976
1977 always_inline uword
1978 ip6_rewrite_inline (vlib_main_t * vm,
1979                     vlib_node_runtime_t * node,
1980                     vlib_frame_t * frame, int is_midchain)
1981 {
1982   ip_lookup_main_t *lm = &ip6_main.lookup_main;
1983   u32 *from = vlib_frame_vector_args (frame);
1984   u32 n_left_from, n_left_to_next, *to_next, next_index;
1985   vlib_node_runtime_t *error_node =
1986     vlib_node_get_runtime (vm, ip6_input_node.index);
1987
1988   n_left_from = frame->n_vectors;
1989   next_index = node->cached_next_index;
1990   u32 cpu_index = os_get_cpu_number ();
1991
1992   while (n_left_from > 0)
1993     {
1994       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1995
1996       while (n_left_from >= 4 && n_left_to_next >= 2)
1997         {
1998           ip_adjacency_t *adj0, *adj1;
1999           vlib_buffer_t *p0, *p1;
2000           ip6_header_t *ip0, *ip1;
2001           u32 pi0, rw_len0, next0, error0, adj_index0;
2002           u32 pi1, rw_len1, next1, error1, adj_index1;
2003           u32 tx_sw_if_index0, tx_sw_if_index1;
2004
2005           /* Prefetch next iteration. */
2006           {
2007             vlib_buffer_t *p2, *p3;
2008
2009             p2 = vlib_get_buffer (vm, from[2]);
2010             p3 = vlib_get_buffer (vm, from[3]);
2011
2012             vlib_prefetch_buffer_header (p2, LOAD);
2013             vlib_prefetch_buffer_header (p3, LOAD);
2014
2015             CLIB_PREFETCH (p2->pre_data, 32, STORE);
2016             CLIB_PREFETCH (p3->pre_data, 32, STORE);
2017
2018             CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
2019             CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
2020           }
2021
2022           pi0 = to_next[0] = from[0];
2023           pi1 = to_next[1] = from[1];
2024
2025           from += 2;
2026           n_left_from -= 2;
2027           to_next += 2;
2028           n_left_to_next -= 2;
2029
2030           p0 = vlib_get_buffer (vm, pi0);
2031           p1 = vlib_get_buffer (vm, pi1);
2032
2033           adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2034           adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
2035
2036           /* We should never rewrite a pkt using the MISS adjacency */
2037           ASSERT (adj_index0 && adj_index1);
2038
2039           ip0 = vlib_buffer_get_current (p0);
2040           ip1 = vlib_buffer_get_current (p1);
2041
2042           error0 = error1 = IP6_ERROR_NONE;
2043           next0 = next1 = IP6_REWRITE_NEXT_DROP;
2044
2045           if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
2046             {
2047               i32 hop_limit0 = ip0->hop_limit;
2048
2049               /* Input node should have reject packets with hop limit 0. */
2050               ASSERT (ip0->hop_limit > 0);
2051
2052               hop_limit0 -= 1;
2053
2054               ip0->hop_limit = hop_limit0;
2055
2056               /*
2057                * If the hop count drops below 1 when forwarding, generate
2058                * an ICMP response.
2059                */
2060               if (PREDICT_FALSE (hop_limit0 <= 0))
2061                 {
2062                   error0 = IP6_ERROR_TIME_EXPIRED;
2063                   next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2064                   vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2065                   icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2066                                                ICMP6_time_exceeded_ttl_exceeded_in_transit,
2067                                                0);
2068                 }
2069             }
2070           else
2071             {
2072               p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2073             }
2074           if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
2075             {
2076               i32 hop_limit1 = ip1->hop_limit;
2077
2078               /* Input node should have reject packets with hop limit 0. */
2079               ASSERT (ip1->hop_limit > 0);
2080
2081               hop_limit1 -= 1;
2082
2083               ip1->hop_limit = hop_limit1;
2084
2085               /*
2086                * If the hop count drops below 1 when forwarding, generate
2087                * an ICMP response.
2088                */
2089               if (PREDICT_FALSE (hop_limit1 <= 0))
2090                 {
2091                   error1 = IP6_ERROR_TIME_EXPIRED;
2092                   next1 = IP6_REWRITE_NEXT_ICMP_ERROR;
2093                   vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2094                   icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
2095                                                ICMP6_time_exceeded_ttl_exceeded_in_transit,
2096                                                0);
2097                 }
2098             }
2099           else
2100             {
2101               p1->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2102             }
2103           adj0 = ip_get_adjacency (lm, adj_index0);
2104           adj1 = ip_get_adjacency (lm, adj_index1);
2105
2106           rw_len0 = adj0[0].rewrite_header.data_bytes;
2107           rw_len1 = adj1[0].rewrite_header.data_bytes;
2108           vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2109           vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
2110
2111           vlib_increment_combined_counter
2112             (&adjacency_counters,
2113              cpu_index,
2114              adj_index0, 1, vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2115           vlib_increment_combined_counter
2116             (&adjacency_counters,
2117              cpu_index, adj_index1,
2118              1, vlib_buffer_length_in_chain (vm, p1) + rw_len1);
2119
2120           /* Check MTU of outgoing interface. */
2121           error0 =
2122             (vlib_buffer_length_in_chain (vm, p0) >
2123              adj0[0].
2124              rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2125              error0);
2126           error1 =
2127             (vlib_buffer_length_in_chain (vm, p1) >
2128              adj1[0].
2129              rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2130              error1);
2131
2132           /* Don't adjust the buffer for hop count issue; icmp-error node
2133            * wants to see the IP headerr */
2134           if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2135             {
2136               p0->current_data -= rw_len0;
2137               p0->current_length += rw_len0;
2138
2139               tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2140               vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2141               next0 = adj0[0].rewrite_header.next_index;
2142
2143               vnet_feature_arc_start (lm->output_feature_arc_index,
2144                                       tx_sw_if_index0, &next0, p0);
2145             }
2146           if (PREDICT_TRUE (error1 == IP6_ERROR_NONE))
2147             {
2148               p1->current_data -= rw_len1;
2149               p1->current_length += rw_len1;
2150
2151               tx_sw_if_index1 = adj1[0].rewrite_header.sw_if_index;
2152               vnet_buffer (p1)->sw_if_index[VLIB_TX] = tx_sw_if_index1;
2153               next1 = adj1[0].rewrite_header.next_index;
2154
2155               vnet_feature_arc_start (lm->output_feature_arc_index,
2156                                       tx_sw_if_index1, &next1, p1);
2157             }
2158
2159           /* Guess we are only writing on simple Ethernet header. */
2160           vnet_rewrite_two_headers (adj0[0], adj1[0],
2161                                     ip0, ip1, sizeof (ethernet_header_t));
2162
2163           if (is_midchain)
2164             {
2165               adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2166               adj1->sub_type.midchain.fixup_func (vm, adj1, p1);
2167             }
2168
2169           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2170                                            to_next, n_left_to_next,
2171                                            pi0, pi1, next0, next1);
2172         }
2173
2174       while (n_left_from > 0 && n_left_to_next > 0)
2175         {
2176           ip_adjacency_t *adj0;
2177           vlib_buffer_t *p0;
2178           ip6_header_t *ip0;
2179           u32 pi0, rw_len0;
2180           u32 adj_index0, next0, error0;
2181           u32 tx_sw_if_index0;
2182
2183           pi0 = to_next[0] = from[0];
2184
2185           p0 = vlib_get_buffer (vm, pi0);
2186
2187           adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
2188
2189           /* We should never rewrite a pkt using the MISS adjacency */
2190           ASSERT (adj_index0);
2191
2192           adj0 = ip_get_adjacency (lm, adj_index0);
2193
2194           ip0 = vlib_buffer_get_current (p0);
2195
2196           error0 = IP6_ERROR_NONE;
2197           next0 = IP6_REWRITE_NEXT_DROP;
2198
2199           /* Check hop limit */
2200           if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_LOCALLY_ORIGINATED)))
2201             {
2202               i32 hop_limit0 = ip0->hop_limit;
2203
2204               ASSERT (ip0->hop_limit > 0);
2205
2206               hop_limit0 -= 1;
2207
2208               ip0->hop_limit = hop_limit0;
2209
2210               if (PREDICT_FALSE (hop_limit0 <= 0))
2211                 {
2212                   /*
2213                    * If the hop count drops below 1 when forwarding, generate
2214                    * an ICMP response.
2215                    */
2216                   error0 = IP6_ERROR_TIME_EXPIRED;
2217                   next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
2218                   vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
2219                   icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
2220                                                ICMP6_time_exceeded_ttl_exceeded_in_transit,
2221                                                0);
2222                 }
2223             }
2224           else
2225             {
2226               p0->flags &= ~VNET_BUFFER_LOCALLY_ORIGINATED;
2227             }
2228
2229           /* Guess we are only writing on simple Ethernet header. */
2230           vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
2231
2232           /* Update packet buffer attributes/set output interface. */
2233           rw_len0 = adj0[0].rewrite_header.data_bytes;
2234           vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
2235
2236           vlib_increment_combined_counter
2237             (&adjacency_counters,
2238              cpu_index,
2239              adj_index0, 1, vlib_buffer_length_in_chain (vm, p0) + rw_len0);
2240
2241           /* Check MTU of outgoing interface. */
2242           error0 =
2243             (vlib_buffer_length_in_chain (vm, p0) >
2244              adj0[0].
2245              rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
2246              error0);
2247
2248           /* Don't adjust the buffer for hop count issue; icmp-error node
2249            * wants to see the IP headerr */
2250           if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
2251             {
2252               p0->current_data -= rw_len0;
2253               p0->current_length += rw_len0;
2254
2255               tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
2256
2257               vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
2258               next0 = adj0[0].rewrite_header.next_index;
2259
2260               vnet_feature_arc_start (lm->output_feature_arc_index,
2261                                       tx_sw_if_index0, &next0, p0);
2262             }
2263
2264           if (is_midchain)
2265             {
2266               adj0->sub_type.midchain.fixup_func (vm, adj0, p0);
2267             }
2268
2269           p0->error = error_node->errors[error0];
2270
2271           from += 1;
2272           n_left_from -= 1;
2273           to_next += 1;
2274           n_left_to_next -= 1;
2275
2276           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2277                                            to_next, n_left_to_next,
2278                                            pi0, next0);
2279         }
2280
2281       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2282     }
2283
2284   /* Need to do trace after rewrites to pick up new packet data. */
2285   if (node->flags & VLIB_NODE_FLAG_TRACE)
2286     ip6_forward_next_trace (vm, node, frame, VLIB_TX);
2287
2288   return frame->n_vectors;
2289 }
2290
2291 static uword
2292 ip6_rewrite (vlib_main_t * vm,
2293              vlib_node_runtime_t * node, vlib_frame_t * frame)
2294 {
2295   return ip6_rewrite_inline (vm, node, frame,
2296                              /* midchain */ 0);
2297 }
2298
2299 static uword
2300 ip6_midchain (vlib_main_t * vm,
2301               vlib_node_runtime_t * node, vlib_frame_t * frame)
2302 {
2303   return ip6_rewrite_inline (vm, node, frame,
2304                              /* midchain */ 1);
2305 }
2306
2307 /* *INDENT-OFF* */
2308 VLIB_REGISTER_NODE (ip6_midchain_node) =
2309 {
2310   .function = ip6_midchain,
2311   .name = "ip6-midchain",
2312   .vector_size = sizeof (u32),
2313   .format_trace = format_ip6_forward_next_trace,
2314   .sibling_of = "ip6-rewrite",
2315   };
2316 /* *INDENT-ON* */
2317
2318 VLIB_NODE_FUNCTION_MULTIARCH (ip6_midchain_node, ip6_midchain);
2319
2320 /* *INDENT-OFF* */
2321 VLIB_REGISTER_NODE (ip6_rewrite_node) =
2322 {
2323   .function = ip6_rewrite,
2324   .name = "ip6-rewrite",
2325   .vector_size = sizeof (u32),
2326   .format_trace = format_ip6_rewrite_trace,
2327   .n_next_nodes = 2,
2328   .next_nodes =
2329   {
2330     [IP6_REWRITE_NEXT_DROP] = "error-drop",
2331     [IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
2332   },
2333 };
2334 /* *INDENT-ON* */
2335
2336 VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_node, ip6_rewrite);
2337
2338 /*
2339  * Hop-by-Hop handling
2340  */
2341
2342 ip6_hop_by_hop_main_t ip6_hop_by_hop_main;
2343
2344 #define foreach_ip6_hop_by_hop_error \
2345 _(PROCESSED, "pkts with ip6 hop-by-hop options") \
2346 _(FORMAT, "incorrectly formatted hop-by-hop options") \
2347 _(UNKNOWN_OPTION, "unknown ip6 hop-by-hop options")
2348
2349 typedef enum
2350 {
2351 #define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym,
2352   foreach_ip6_hop_by_hop_error
2353 #undef _
2354     IP6_HOP_BY_HOP_N_ERROR,
2355 } ip6_hop_by_hop_error_t;
2356
2357 /*
2358  * Primary h-b-h handler trace support
2359  * We work pretty hard on the problem for obvious reasons
2360  */
2361 typedef struct
2362 {
2363   u32 next_index;
2364   u32 trace_len;
2365   u8 option_data[256];
2366 } ip6_hop_by_hop_trace_t;
2367
2368 vlib_node_registration_t ip6_hop_by_hop_node;
2369
2370 static char *ip6_hop_by_hop_error_strings[] = {
2371 #define _(sym,string) string,
2372   foreach_ip6_hop_by_hop_error
2373 #undef _
2374 };
2375
2376 static u8 *
2377 format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
2378 {
2379   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2380   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
2381   ip6_hop_by_hop_trace_t *t = va_arg (*args, ip6_hop_by_hop_trace_t *);
2382   ip6_hop_by_hop_header_t *hbh0;
2383   ip6_hop_by_hop_option_t *opt0, *limit0;
2384   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2385
2386   u8 type0;
2387
2388   hbh0 = (ip6_hop_by_hop_header_t *) t->option_data;
2389
2390   s = format (s, "IP6_HOP_BY_HOP: next index %d len %d traced %d",
2391               t->next_index, (hbh0->length + 1) << 3, t->trace_len);
2392
2393   opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2394   limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0) + t->trace_len;
2395
2396   while (opt0 < limit0)
2397     {
2398       type0 = opt0->type;
2399       switch (type0)
2400         {
2401         case 0:         /* Pad, just stop */
2402           opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2403           break;
2404
2405         default:
2406           if (hm->trace[type0])
2407             {
2408               s = (*hm->trace[type0]) (s, opt0);
2409             }
2410           else
2411             {
2412               s =
2413                 format (s, "\n    unrecognized option %d length %d", type0,
2414                         opt0->length);
2415             }
2416           opt0 =
2417             (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2418                                          sizeof (ip6_hop_by_hop_option_t));
2419           break;
2420         }
2421     }
2422   return s;
2423 }
2424
2425 always_inline u8
2426 ip6_scan_hbh_options (vlib_buffer_t * b0,
2427                       ip6_header_t * ip0,
2428                       ip6_hop_by_hop_header_t * hbh0,
2429                       ip6_hop_by_hop_option_t * opt0,
2430                       ip6_hop_by_hop_option_t * limit0, u32 * next0)
2431 {
2432   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2433   u8 type0;
2434   u8 error0 = 0;
2435
2436   while (opt0 < limit0)
2437     {
2438       type0 = opt0->type;
2439       switch (type0)
2440         {
2441         case 0:         /* Pad1 */
2442           opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2443           continue;
2444         case 1:         /* PadN */
2445           break;
2446         default:
2447           if (hm->options[type0])
2448             {
2449               if ((*hm->options[type0]) (b0, ip0, opt0) < 0)
2450                 {
2451                   error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2452                   return (error0);
2453                 }
2454             }
2455           else
2456             {
2457               /* Unrecognized mandatory option, check the two high order bits */
2458               switch (opt0->type & HBH_OPTION_TYPE_HIGH_ORDER_BITS)
2459                 {
2460                 case HBH_OPTION_TYPE_SKIP_UNKNOWN:
2461                   break;
2462                 case HBH_OPTION_TYPE_DISCARD_UNKNOWN:
2463                   error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2464                   *next0 = IP_LOOKUP_NEXT_DROP;
2465                   break;
2466                 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP:
2467                   error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2468                   *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2469                   icmp6_error_set_vnet_buffer (b0, ICMP6_parameter_problem,
2470                                                ICMP6_parameter_problem_unrecognized_option,
2471                                                (u8 *) opt0 - (u8 *) ip0);
2472                   break;
2473                 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP_NOT_MCAST:
2474                   error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2475                   if (!ip6_address_is_multicast (&ip0->dst_address))
2476                     {
2477                       *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2478                       icmp6_error_set_vnet_buffer (b0,
2479                                                    ICMP6_parameter_problem,
2480                                                    ICMP6_parameter_problem_unrecognized_option,
2481                                                    (u8 *) opt0 - (u8 *) ip0);
2482                     }
2483                   else
2484                     {
2485                       *next0 = IP_LOOKUP_NEXT_DROP;
2486                     }
2487                   break;
2488                 }
2489               return (error0);
2490             }
2491         }
2492       opt0 =
2493         (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2494                                      sizeof (ip6_hop_by_hop_option_t));
2495     }
2496   return (error0);
2497 }
2498
2499 /*
2500  * Process the Hop-by-Hop Options header
2501  */
2502 static uword
2503 ip6_hop_by_hop (vlib_main_t * vm,
2504                 vlib_node_runtime_t * node, vlib_frame_t * frame)
2505 {
2506   vlib_node_runtime_t *error_node =
2507     vlib_node_get_runtime (vm, ip6_hop_by_hop_node.index);
2508   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2509   u32 n_left_from, *from, *to_next;
2510   ip_lookup_next_t next_index;
2511   ip6_main_t *im = &ip6_main;
2512   ip_lookup_main_t *lm = &im->lookup_main;
2513
2514   from = vlib_frame_vector_args (frame);
2515   n_left_from = frame->n_vectors;
2516   next_index = node->cached_next_index;
2517
2518   while (n_left_from > 0)
2519     {
2520       u32 n_left_to_next;
2521
2522       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2523
2524       while (n_left_from >= 4 && n_left_to_next >= 2)
2525         {
2526           u32 bi0, bi1;
2527           vlib_buffer_t *b0, *b1;
2528           u32 next0, next1;
2529           ip6_header_t *ip0, *ip1;
2530           ip6_hop_by_hop_header_t *hbh0, *hbh1;
2531           ip6_hop_by_hop_option_t *opt0, *limit0, *opt1, *limit1;
2532           u8 error0 = 0, error1 = 0;
2533
2534           /* Prefetch next iteration. */
2535           {
2536             vlib_buffer_t *p2, *p3;
2537
2538             p2 = vlib_get_buffer (vm, from[2]);
2539             p3 = vlib_get_buffer (vm, from[3]);
2540
2541             vlib_prefetch_buffer_header (p2, LOAD);
2542             vlib_prefetch_buffer_header (p3, LOAD);
2543
2544             CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2545             CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2546           }
2547
2548           /* Speculatively enqueue b0, b1 to the current next frame */
2549           to_next[0] = bi0 = from[0];
2550           to_next[1] = bi1 = from[1];
2551           from += 2;
2552           to_next += 2;
2553           n_left_from -= 2;
2554           n_left_to_next -= 2;
2555
2556           b0 = vlib_get_buffer (vm, bi0);
2557           b1 = vlib_get_buffer (vm, bi1);
2558
2559           /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2560           u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
2561           ip_adjacency_t *adj0 = ip_get_adjacency (lm, adj_index0);
2562           u32 adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
2563           ip_adjacency_t *adj1 = ip_get_adjacency (lm, adj_index1);
2564
2565           /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2566           next0 = adj0->lookup_next_index;
2567           next1 = adj1->lookup_next_index;
2568
2569           ip0 = vlib_buffer_get_current (b0);
2570           ip1 = vlib_buffer_get_current (b1);
2571           hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2572           hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1);
2573           opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2574           opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
2575           limit0 =
2576             (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2577                                          ((hbh0->length + 1) << 3));
2578           limit1 =
2579             (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
2580                                          ((hbh1->length + 1) << 3));
2581
2582           /*
2583            * Basic validity checks
2584            */
2585           if ((hbh0->length + 1) << 3 >
2586               clib_net_to_host_u16 (ip0->payload_length))
2587             {
2588               error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2589               next0 = IP_LOOKUP_NEXT_DROP;
2590               goto outdual;
2591             }
2592           /* Scan the set of h-b-h options, process ones that we understand */
2593           error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2594
2595           if ((hbh1->length + 1) << 3 >
2596               clib_net_to_host_u16 (ip1->payload_length))
2597             {
2598               error1 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2599               next1 = IP_LOOKUP_NEXT_DROP;
2600               goto outdual;
2601             }
2602           /* Scan the set of h-b-h options, process ones that we understand */
2603           error1 = ip6_scan_hbh_options (b1, ip1, hbh1, opt1, limit1, &next1);
2604
2605         outdual:
2606           /* Has the classifier flagged this buffer for special treatment? */
2607           if (PREDICT_FALSE
2608               ((error0 == 0)
2609                && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2610             next0 = hm->next_override;
2611
2612           /* Has the classifier flagged this buffer for special treatment? */
2613           if (PREDICT_FALSE
2614               ((error1 == 0)
2615                && (vnet_buffer (b1)->l2_classify.opaque_index & OI_DECAP)))
2616             next1 = hm->next_override;
2617
2618           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2619             {
2620               if (b0->flags & VLIB_BUFFER_IS_TRACED)
2621                 {
2622                   ip6_hop_by_hop_trace_t *t =
2623                     vlib_add_trace (vm, node, b0, sizeof (*t));
2624                   u32 trace_len = (hbh0->length + 1) << 3;
2625                   t->next_index = next0;
2626                   /* Capture the h-b-h option verbatim */
2627                   trace_len =
2628                     trace_len <
2629                     ARRAY_LEN (t->option_data) ? trace_len :
2630                     ARRAY_LEN (t->option_data);
2631                   t->trace_len = trace_len;
2632                   clib_memcpy (t->option_data, hbh0, trace_len);
2633                 }
2634               if (b1->flags & VLIB_BUFFER_IS_TRACED)
2635                 {
2636                   ip6_hop_by_hop_trace_t *t =
2637                     vlib_add_trace (vm, node, b1, sizeof (*t));
2638                   u32 trace_len = (hbh1->length + 1) << 3;
2639                   t->next_index = next1;
2640                   /* Capture the h-b-h option verbatim */
2641                   trace_len =
2642                     trace_len <
2643                     ARRAY_LEN (t->option_data) ? trace_len :
2644                     ARRAY_LEN (t->option_data);
2645                   t->trace_len = trace_len;
2646                   clib_memcpy (t->option_data, hbh1, trace_len);
2647                 }
2648
2649             }
2650
2651           b0->error = error_node->errors[error0];
2652           b1->error = error_node->errors[error1];
2653
2654           /* verify speculative enqueue, maybe switch current next frame */
2655           vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
2656                                            n_left_to_next, bi0, bi1, next0,
2657                                            next1);
2658         }
2659
2660       while (n_left_from > 0 && n_left_to_next > 0)
2661         {
2662           u32 bi0;
2663           vlib_buffer_t *b0;
2664           u32 next0;
2665           ip6_header_t *ip0;
2666           ip6_hop_by_hop_header_t *hbh0;
2667           ip6_hop_by_hop_option_t *opt0, *limit0;
2668           u8 error0 = 0;
2669
2670           /* Speculatively enqueue b0 to the current next frame */
2671           bi0 = from[0];
2672           to_next[0] = bi0;
2673           from += 1;
2674           to_next += 1;
2675           n_left_from -= 1;
2676           n_left_to_next -= 1;
2677
2678           b0 = vlib_get_buffer (vm, bi0);
2679           /*
2680            * Default use the next_index from the adjacency.
2681            * A HBH option rarely redirects to a different node
2682            */
2683           u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
2684           ip_adjacency_t *adj0 = ip_get_adjacency (lm, adj_index0);
2685           next0 = adj0->lookup_next_index;
2686
2687           ip0 = vlib_buffer_get_current (b0);
2688           hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2689           opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2690           limit0 =
2691             (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2692                                          ((hbh0->length + 1) << 3));
2693
2694           /*
2695            * Basic validity checks
2696            */
2697           if ((hbh0->length + 1) << 3 >
2698               clib_net_to_host_u16 (ip0->payload_length))
2699             {
2700               error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2701               next0 = IP_LOOKUP_NEXT_DROP;
2702               goto out0;
2703             }
2704
2705           /* Scan the set of h-b-h options, process ones that we understand */
2706           error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2707
2708         out0:
2709           /* Has the classifier flagged this buffer for special treatment? */
2710           if (PREDICT_FALSE
2711               ((error0 == 0)
2712                && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2713             next0 = hm->next_override;
2714
2715           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2716             {
2717               ip6_hop_by_hop_trace_t *t =
2718                 vlib_add_trace (vm, node, b0, sizeof (*t));
2719               u32 trace_len = (hbh0->length + 1) << 3;
2720               t->next_index = next0;
2721               /* Capture the h-b-h option verbatim */
2722               trace_len =
2723                 trace_len <
2724                 ARRAY_LEN (t->option_data) ? trace_len :
2725                 ARRAY_LEN (t->option_data);
2726               t->trace_len = trace_len;
2727               clib_memcpy (t->option_data, hbh0, trace_len);
2728             }
2729
2730           b0->error = error_node->errors[error0];
2731
2732           /* verify speculative enqueue, maybe switch current next frame */
2733           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2734                                            n_left_to_next, bi0, next0);
2735         }
2736       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2737     }
2738   return frame->n_vectors;
2739 }
2740
2741 /* *INDENT-OFF* */
2742 VLIB_REGISTER_NODE (ip6_hop_by_hop_node) =
2743 {
2744   .function = ip6_hop_by_hop,
2745   .name = "ip6-hop-by-hop",
2746   .sibling_of = "ip6-lookup",
2747   .vector_size = sizeof (u32),
2748   .format_trace = format_ip6_hop_by_hop_trace,
2749   .type = VLIB_NODE_TYPE_INTERNAL,
2750   .n_errors = ARRAY_LEN (ip6_hop_by_hop_error_strings),
2751   .error_strings = ip6_hop_by_hop_error_strings,
2752   .n_next_nodes = 0,
2753 };
2754 /* *INDENT-ON* */
2755
2756 VLIB_NODE_FUNCTION_MULTIARCH (ip6_hop_by_hop_node, ip6_hop_by_hop);
2757
2758 static clib_error_t *
2759 ip6_hop_by_hop_init (vlib_main_t * vm)
2760 {
2761   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2762   memset (hm->options, 0, sizeof (hm->options));
2763   memset (hm->trace, 0, sizeof (hm->trace));
2764   hm->next_override = IP6_LOOKUP_NEXT_POP_HOP_BY_HOP;
2765   return (0);
2766 }
2767
2768 VLIB_INIT_FUNCTION (ip6_hop_by_hop_init);
2769
2770 void
2771 ip6_hbh_set_next_override (uword next)
2772 {
2773   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2774
2775   hm->next_override = next;
2776 }
2777
2778 int
2779 ip6_hbh_register_option (u8 option,
2780                          int options (vlib_buffer_t * b, ip6_header_t * ip,
2781                                       ip6_hop_by_hop_option_t * opt),
2782                          u8 * trace (u8 * s, ip6_hop_by_hop_option_t * opt))
2783 {
2784   ip6_main_t *im = &ip6_main;
2785   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2786
2787   ASSERT (option < ARRAY_LEN (hm->options));
2788
2789   /* Already registered */
2790   if (hm->options[option])
2791     return (-1);
2792
2793   hm->options[option] = options;
2794   hm->trace[option] = trace;
2795
2796   /* Set global variable */
2797   im->hbh_enabled = 1;
2798
2799   return (0);
2800 }
2801
2802 int
2803 ip6_hbh_unregister_option (u8 option)
2804 {
2805   ip6_main_t *im = &ip6_main;
2806   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2807
2808   ASSERT (option < ARRAY_LEN (hm->options));
2809
2810   /* Not registered */
2811   if (!hm->options[option])
2812     return (-1);
2813
2814   hm->options[option] = NULL;
2815   hm->trace[option] = NULL;
2816
2817   /* Disable global knob if this was the last option configured */
2818   int i;
2819   bool found = false;
2820   for (i = 0; i < 256; i++)
2821     {
2822       if (hm->options[option])
2823         {
2824           found = true;
2825           break;
2826         }
2827     }
2828   if (!found)
2829     im->hbh_enabled = 0;
2830
2831   return (0);
2832 }
2833
2834 /* Global IP6 main. */
2835 ip6_main_t ip6_main;
2836
2837 static clib_error_t *
2838 ip6_lookup_init (vlib_main_t * vm)
2839 {
2840   ip6_main_t *im = &ip6_main;
2841   clib_error_t *error;
2842   uword i;
2843
2844   if ((error = vlib_call_init_function (vm, vnet_feature_init)))
2845     return error;
2846
2847   for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
2848     {
2849       u32 j, i0, i1;
2850
2851       i0 = i / 32;
2852       i1 = i % 32;
2853
2854       for (j = 0; j < i0; j++)
2855         im->fib_masks[i].as_u32[j] = ~0;
2856
2857       if (i1)
2858         im->fib_masks[i].as_u32[i0] =
2859           clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
2860     }
2861
2862   ip_lookup_init (&im->lookup_main, /* is_ip6 */ 1);
2863
2864   if (im->lookup_table_nbuckets == 0)
2865     im->lookup_table_nbuckets = IP6_FIB_DEFAULT_HASH_NUM_BUCKETS;
2866
2867   im->lookup_table_nbuckets = 1 << max_log2 (im->lookup_table_nbuckets);
2868
2869   if (im->lookup_table_size == 0)
2870     im->lookup_table_size = IP6_FIB_DEFAULT_HASH_MEMORY_SIZE;
2871
2872   BV (clib_bihash_init) (&(im->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash),
2873                          "ip6 FIB fwding table",
2874                          im->lookup_table_nbuckets, im->lookup_table_size);
2875   BV (clib_bihash_init) (&im->ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
2876                          "ip6 FIB non-fwding table",
2877                          im->lookup_table_nbuckets, im->lookup_table_size);
2878
2879   /* Create FIB with index 0 and table id of 0. */
2880   fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0);
2881
2882   {
2883     pg_node_t *pn;
2884     pn = pg_get_node (ip6_lookup_node.index);
2885     pn->unformat_edit = unformat_pg_ip6_header;
2886   }
2887
2888   /* Unless explicitly configured, don't process HBH options */
2889   im->hbh_enabled = 0;
2890
2891   {
2892     icmp6_neighbor_solicitation_header_t p;
2893
2894     memset (&p, 0, sizeof (p));
2895
2896     p.ip.ip_version_traffic_class_and_flow_label =
2897       clib_host_to_net_u32 (0x6 << 28);
2898     p.ip.payload_length =
2899       clib_host_to_net_u16 (sizeof (p) -
2900                             STRUCT_OFFSET_OF
2901                             (icmp6_neighbor_solicitation_header_t, neighbor));
2902     p.ip.protocol = IP_PROTOCOL_ICMP6;
2903     p.ip.hop_limit = 255;
2904     ip6_set_solicited_node_multicast_address (&p.ip.dst_address, 0);
2905
2906     p.neighbor.icmp.type = ICMP6_neighbor_solicitation;
2907
2908     p.link_layer_option.header.type =
2909       ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
2910     p.link_layer_option.header.n_data_u64s =
2911       sizeof (p.link_layer_option) / sizeof (u64);
2912
2913     vlib_packet_template_init (vm,
2914                                &im->discover_neighbor_packet_template,
2915                                &p, sizeof (p),
2916                                /* alloc chunk size */ 8,
2917                                "ip6 neighbor discovery");
2918   }
2919
2920   return error;
2921 }
2922
2923 VLIB_INIT_FUNCTION (ip6_lookup_init);
2924
2925 static clib_error_t *
2926 add_del_ip6_interface_table (vlib_main_t * vm,
2927                              unformat_input_t * input,
2928                              vlib_cli_command_t * cmd)
2929 {
2930   vnet_main_t *vnm = vnet_get_main ();
2931   clib_error_t *error = 0;
2932   u32 sw_if_index, table_id;
2933
2934   sw_if_index = ~0;
2935
2936   if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
2937     {
2938       error = clib_error_return (0, "unknown interface `%U'",
2939                                  format_unformat_error, input);
2940       goto done;
2941     }
2942
2943   if (unformat (input, "%d", &table_id))
2944     ;
2945   else
2946     {
2947       error = clib_error_return (0, "expected table id `%U'",
2948                                  format_unformat_error, input);
2949       goto done;
2950     }
2951
2952   {
2953     u32 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
2954                                                        table_id);
2955
2956     vec_validate (ip6_main.fib_index_by_sw_if_index, sw_if_index);
2957     ip6_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
2958   }
2959
2960
2961 done:
2962   return error;
2963 }
2964
2965 /*?
2966  * Place the indicated interface into the supplied IPv6 FIB table (also known
2967  * as a VRF). If the FIB table does not exist, this command creates it. To
2968  * display the current IPv6 FIB table, use the command '<em>show ip6 fib</em>'.
2969  * FIB table will only be displayed if a route has been added to the table, or
2970  * an IP Address is assigned to an interface in the table (which adds a route
2971  * automatically).
2972  *
2973  * @note IP addresses added after setting the interface IP table end up in
2974  * the indicated FIB table. If the IP address is added prior to adding the
2975  * interface to the FIB table, it will NOT be part of the FIB table. Predictable
2976  * but potentially counter-intuitive results occur if you provision interface
2977  * addresses in multiple FIBs. Upon RX, packets will be processed in the last
2978  * IP table ID provisioned. It might be marginally useful to evade source RPF
2979  * drops to put an interface address into multiple FIBs.
2980  *
2981  * @cliexpar
2982  * Example of how to add an interface to an IPv6 FIB table (where 2 is the table-id):
2983  * @cliexcmd{set interface ip6 table GigabitEthernet2/0/0 2}
2984  ?*/
2985 /* *INDENT-OFF* */
2986 VLIB_CLI_COMMAND (set_interface_ip6_table_command, static) =
2987 {
2988   .path = "set interface ip6 table",
2989   .function = add_del_ip6_interface_table,
2990   .short_help = "set interface ip6 table <interface> <table-id>"
2991 };
2992 /* *INDENT-ON* */
2993
2994 void
2995 ip6_link_local_address_from_ethernet_mac_address (ip6_address_t * ip,
2996                                                   u8 * mac)
2997 {
2998   ip->as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL);
2999   /* Invert the "u" bit */
3000   ip->as_u8[8] = mac[0] ^ (1 << 1);
3001   ip->as_u8[9] = mac[1];
3002   ip->as_u8[10] = mac[2];
3003   ip->as_u8[11] = 0xFF;
3004   ip->as_u8[12] = 0xFE;
3005   ip->as_u8[13] = mac[3];
3006   ip->as_u8[14] = mac[4];
3007   ip->as_u8[15] = mac[5];
3008 }
3009
3010 void
3011 ip6_ethernet_mac_address_from_link_local_address (u8 * mac,
3012                                                   ip6_address_t * ip)
3013 {
3014   /* Invert the previously inverted "u" bit */
3015   mac[0] = ip->as_u8[8] ^ (1 << 1);
3016   mac[1] = ip->as_u8[9];
3017   mac[2] = ip->as_u8[10];
3018   mac[3] = ip->as_u8[13];
3019   mac[4] = ip->as_u8[14];
3020   mac[5] = ip->as_u8[15];
3021 }
3022
3023 static clib_error_t *
3024 test_ip6_link_command_fn (vlib_main_t * vm,
3025                           unformat_input_t * input, vlib_cli_command_t * cmd)
3026 {
3027   u8 mac[6];
3028   ip6_address_t _a, *a = &_a;
3029
3030   if (unformat (input, "%U", unformat_ethernet_address, mac))
3031     {
3032       ip6_link_local_address_from_ethernet_mac_address (a, mac);
3033       vlib_cli_output (vm, "Link local address: %U", format_ip6_address, a);
3034       ip6_ethernet_mac_address_from_link_local_address (mac, a);
3035       vlib_cli_output (vm, "Original MAC address: %U",
3036                        format_ethernet_address, mac);
3037     }
3038
3039   return 0;
3040 }
3041
3042 /*?
3043  * This command converts the given MAC Address into an IPv6 link-local
3044  * address.
3045  *
3046  * @cliexpar
3047  * Example of how to create an IPv6 link-local address:
3048  * @cliexstart{test ip6 link 16:d9:e0:91:79:86}
3049  * Link local address: fe80::14d9:e0ff:fe91:7986
3050  * Original MAC address: 16:d9:e0:91:79:86
3051  * @cliexend
3052 ?*/
3053 /* *INDENT-OFF* */
3054 VLIB_CLI_COMMAND (test_link_command, static) =
3055 {
3056   .path = "test ip6 link",
3057   .function = test_ip6_link_command_fn,
3058   .short_help = "test ip6 link <mac-address>",
3059 };
3060 /* *INDENT-ON* */
3061
3062 int
3063 vnet_set_ip6_flow_hash (u32 table_id, u32 flow_hash_config)
3064 {
3065   ip6_main_t *im6 = &ip6_main;
3066   ip6_fib_t *fib;
3067   uword *p = hash_get (im6->fib_index_by_table_id, table_id);
3068
3069   if (p == 0)
3070     return -1;
3071
3072   fib = ip6_fib_get (p[0]);
3073
3074   fib->flow_hash_config = flow_hash_config;
3075   return 1;
3076 }
3077
3078 static clib_error_t *
3079 set_ip6_flow_hash_command_fn (vlib_main_t * vm,
3080                               unformat_input_t * input,
3081                               vlib_cli_command_t * cmd)
3082 {
3083   int matched = 0;
3084   u32 table_id = 0;
3085   u32 flow_hash_config = 0;
3086   int rv;
3087
3088   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3089     {
3090       if (unformat (input, "table %d", &table_id))
3091         matched = 1;
3092 #define _(a,v) \
3093     else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
3094       foreach_flow_hash_bit
3095 #undef _
3096         else
3097         break;
3098     }
3099
3100   if (matched == 0)
3101     return clib_error_return (0, "unknown input `%U'",
3102                               format_unformat_error, input);
3103
3104   rv = vnet_set_ip6_flow_hash (table_id, flow_hash_config);
3105   switch (rv)
3106     {
3107     case 1:
3108       break;
3109
3110     case -1:
3111       return clib_error_return (0, "no such FIB table %d", table_id);
3112
3113     default:
3114       clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
3115       break;
3116     }
3117
3118   return 0;
3119 }
3120
3121 /*?
3122  * Configure the set of IPv6 fields used by the flow hash.
3123  *
3124  * @cliexpar
3125  * @parblock
3126  * Example of how to set the flow hash on a given table:
3127  * @cliexcmd{set ip6 flow-hash table 8 dst sport dport proto}
3128  *
3129  * Example of display the configured flow hash:
3130  * @cliexstart{show ip6 fib}
3131  * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
3132  * @::/0
3133  *   unicast-ip6-chain
3134  *   [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
3135  *     [0] [@0]: dpo-drop ip6
3136  * fe80::/10
3137  *   unicast-ip6-chain
3138  *   [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
3139  *     [0] [@2]: dpo-receive
3140  * ff02::1/128
3141  *   unicast-ip6-chain
3142  *   [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
3143  *     [0] [@2]: dpo-receive
3144  * ff02::2/128
3145  *   unicast-ip6-chain
3146  *   [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
3147  *     [0] [@2]: dpo-receive
3148  * ff02::16/128
3149  *   unicast-ip6-chain
3150  *   [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
3151  *     [0] [@2]: dpo-receive
3152  * ff02::1:ff00:0/104
3153  *   unicast-ip6-chain
3154  *   [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
3155  *     [0] [@2]: dpo-receive
3156  * ipv6-VRF:8, fib_index 1, flow hash: dst sport dport proto
3157  * @::/0
3158  *   unicast-ip6-chain
3159  *   [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
3160  *     [0] [@0]: dpo-drop ip6
3161  * @::a:1:1:0:4/126
3162  *   unicast-ip6-chain
3163  *   [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
3164  *     [0] [@4]: ipv6-glean: af_packet0
3165  * @::a:1:1:0:7/128
3166  *   unicast-ip6-chain
3167  *   [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
3168  *     [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
3169  * fe80::/10
3170  *   unicast-ip6-chain
3171  *   [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
3172  *     [0] [@2]: dpo-receive
3173  * fe80::fe:3eff:fe3e:9222/128
3174  *   unicast-ip6-chain
3175  *   [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
3176  *     [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
3177  * ff02::1/128
3178  *   unicast-ip6-chain
3179  *   [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
3180  *     [0] [@2]: dpo-receive
3181  * ff02::2/128
3182  *   unicast-ip6-chain
3183  *   [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
3184  *     [0] [@2]: dpo-receive
3185  * ff02::16/128
3186  *   unicast-ip6-chain
3187  *   [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
3188  *     [0] [@2]: dpo-receive
3189  * ff02::1:ff00:0/104
3190  *   unicast-ip6-chain
3191  *   [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
3192  *     [0] [@2]: dpo-receive
3193  * @cliexend
3194  * @endparblock
3195 ?*/
3196 /* *INDENT-OFF* */
3197 VLIB_CLI_COMMAND (set_ip6_flow_hash_command, static) =
3198 {
3199   .path = "set ip6 flow-hash",
3200   .short_help =
3201   "set ip6 flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
3202   .function = set_ip6_flow_hash_command_fn,
3203 };
3204 /* *INDENT-ON* */
3205
3206 static clib_error_t *
3207 show_ip6_local_command_fn (vlib_main_t * vm,
3208                            unformat_input_t * input, vlib_cli_command_t * cmd)
3209 {
3210   ip6_main_t *im = &ip6_main;
3211   ip_lookup_main_t *lm = &im->lookup_main;
3212   int i;
3213
3214   vlib_cli_output (vm, "Protocols handled by ip6_local");
3215   for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
3216     {
3217       if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
3218         vlib_cli_output (vm, "%d", i);
3219     }
3220   return 0;
3221 }
3222
3223
3224
3225 /*?
3226  * Display the set of protocols handled by the local IPv6 stack.
3227  *
3228  * @cliexpar
3229  * Example of how to display local protocol table:
3230  * @cliexstart{show ip6 local}
3231  * Protocols handled by ip6_local
3232  * 17
3233  * 43
3234  * 58
3235  * 115
3236  * @cliexend
3237 ?*/
3238 /* *INDENT-OFF* */
3239 VLIB_CLI_COMMAND (show_ip6_local, static) =
3240 {
3241   .path = "show ip6 local",
3242   .function = show_ip6_local_command_fn,
3243   .short_help = "show ip6 local",
3244 };
3245 /* *INDENT-ON* */
3246
3247 int
3248 vnet_set_ip6_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
3249                              u32 table_index)
3250 {
3251   vnet_main_t *vnm = vnet_get_main ();
3252   vnet_interface_main_t *im = &vnm->interface_main;
3253   ip6_main_t *ipm = &ip6_main;
3254   ip_lookup_main_t *lm = &ipm->lookup_main;
3255   vnet_classify_main_t *cm = &vnet_classify_main;
3256   ip6_address_t *if_addr;
3257
3258   if (pool_is_free_index (im->sw_interfaces, sw_if_index))
3259     return VNET_API_ERROR_NO_MATCHING_INTERFACE;
3260
3261   if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
3262     return VNET_API_ERROR_NO_SUCH_ENTRY;
3263
3264   vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
3265   lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
3266
3267   if_addr = ip6_interface_first_address (ipm, sw_if_index, NULL);
3268
3269   if (NULL != if_addr)
3270     {
3271       fib_prefix_t pfx = {
3272         .fp_len = 128,
3273         .fp_proto = FIB_PROTOCOL_IP6,
3274         .fp_addr.ip6 = *if_addr,
3275       };
3276       u32 fib_index;
3277
3278       fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
3279                                                        sw_if_index);
3280
3281
3282       if (table_index != (u32) ~ 0)
3283         {
3284           dpo_id_t dpo = DPO_INVALID;
3285
3286           dpo_set (&dpo,
3287                    DPO_CLASSIFY,
3288                    DPO_PROTO_IP6,
3289                    classify_dpo_create (DPO_PROTO_IP6, table_index));
3290
3291           fib_table_entry_special_dpo_add (fib_index,
3292                                            &pfx,
3293                                            FIB_SOURCE_CLASSIFY,
3294                                            FIB_ENTRY_FLAG_NONE, &dpo);
3295           dpo_reset (&dpo);
3296         }
3297       else
3298         {
3299           fib_table_entry_special_remove (fib_index,
3300                                           &pfx, FIB_SOURCE_CLASSIFY);
3301         }
3302     }
3303
3304   return 0;
3305 }
3306
3307 static clib_error_t *
3308 set_ip6_classify_command_fn (vlib_main_t * vm,
3309                              unformat_input_t * input,
3310                              vlib_cli_command_t * cmd)
3311 {
3312   u32 table_index = ~0;
3313   int table_index_set = 0;
3314   u32 sw_if_index = ~0;
3315   int rv;
3316
3317   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3318     {
3319       if (unformat (input, "table-index %d", &table_index))
3320         table_index_set = 1;
3321       else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
3322                          vnet_get_main (), &sw_if_index))
3323         ;
3324       else
3325         break;
3326     }
3327
3328   if (table_index_set == 0)
3329     return clib_error_return (0, "classify table-index must be specified");
3330
3331   if (sw_if_index == ~0)
3332     return clib_error_return (0, "interface / subif must be specified");
3333
3334   rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
3335
3336   switch (rv)
3337     {
3338     case 0:
3339       break;
3340
3341     case VNET_API_ERROR_NO_MATCHING_INTERFACE:
3342       return clib_error_return (0, "No such interface");
3343
3344     case VNET_API_ERROR_NO_SUCH_ENTRY:
3345       return clib_error_return (0, "No such classifier table");
3346     }
3347   return 0;
3348 }
3349
3350 /*?
3351  * Assign a classification table to an interface. The classification
3352  * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3353  * commands. Once the table is create, use this command to filter packets
3354  * on an interface.
3355  *
3356  * @cliexpar
3357  * Example of how to assign a classification table to an interface:
3358  * @cliexcmd{set ip6 classify intfc GigabitEthernet2/0/0 table-index 1}
3359 ?*/
3360 /* *INDENT-OFF* */
3361 VLIB_CLI_COMMAND (set_ip6_classify_command, static) =
3362 {
3363   .path = "set ip6 classify",
3364   .short_help =
3365   "set ip6 classify intfc <interface> table-index <classify-idx>",
3366   .function = set_ip6_classify_command_fn,
3367 };
3368 /* *INDENT-ON* */
3369
3370 static clib_error_t *
3371 ip6_config (vlib_main_t * vm, unformat_input_t * input)
3372 {
3373   ip6_main_t *im = &ip6_main;
3374   uword heapsize = 0;
3375   u32 tmp;
3376   u32 nbuckets = 0;
3377
3378   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3379     {
3380       if (unformat (input, "hash-buckets %d", &tmp))
3381         nbuckets = tmp;
3382       else if (unformat (input, "heap-size %dm", &tmp))
3383         heapsize = ((u64) tmp) << 20;
3384       else if (unformat (input, "heap-size %dM", &tmp))
3385         heapsize = ((u64) tmp) << 20;
3386       else if (unformat (input, "heap-size %dg", &tmp))
3387         heapsize = ((u64) tmp) << 30;
3388       else if (unformat (input, "heap-size %dG", &tmp))
3389         heapsize = ((u64) tmp) << 30;
3390       else
3391         return clib_error_return (0, "unknown input '%U'",
3392                                   format_unformat_error, input);
3393     }
3394
3395   im->lookup_table_nbuckets = nbuckets;
3396   im->lookup_table_size = heapsize;
3397
3398   return 0;
3399 }
3400
3401 VLIB_EARLY_CONFIG_FUNCTION (ip6_config, "ip6");
3402
3403 /*
3404  * fd.io coding-style-patch-verification: ON
3405  *
3406  * Local Variables:
3407  * eval: (c-set-style "gnu")
3408  * End:
3409  */