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