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