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