No overlapping sub-nets on any interface in the same table/VRF (VPP-943)
[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           /* TODO maybe move to lookup? */
1217           vnet_buffer (p0)->ip.fib_index =
1218             vec_elt (im->fib_index_by_sw_if_index,
1219                      vnet_buffer (p0)->sw_if_index[VLIB_RX]);
1220           vnet_buffer (p0)->ip.fib_index =
1221             (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1222              (u32) ~ 0) ? vnet_buffer (p0)->ip.
1223             fib_index : vnet_buffer (p0)->sw_if_index[VLIB_TX];
1224
1225           vnet_buffer (p1)->ip.fib_index =
1226             vec_elt (im->fib_index_by_sw_if_index,
1227                      vnet_buffer (p1)->sw_if_index[VLIB_RX]);
1228           vnet_buffer (p1)->ip.fib_index =
1229             (vnet_buffer (p1)->sw_if_index[VLIB_TX] ==
1230              (u32) ~ 0) ? vnet_buffer (p1)->ip.
1231             fib_index : vnet_buffer (p1)->sw_if_index[VLIB_TX];
1232
1233
1234         skip_checks:
1235
1236           next0 = lm->local_next_by_ip_protocol[ip0->protocol];
1237           next1 = lm->local_next_by_ip_protocol[ip1->protocol];
1238
1239           next0 =
1240             error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1241           next1 =
1242             error1 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next1;
1243
1244           p0->error = error_node->errors[error0];
1245           p1->error = error_node->errors[error1];
1246
1247           if (head_of_feature_arc)
1248             {
1249               if (PREDICT_TRUE (error0 == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
1250                 vnet_feature_arc_start (arc_index,
1251                                         vnet_buffer (p0)->sw_if_index
1252                                         [VLIB_RX], &next0, p0);
1253               if (PREDICT_TRUE (error1 == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
1254                 vnet_feature_arc_start (arc_index,
1255                                         vnet_buffer (p1)->sw_if_index
1256                                         [VLIB_RX], &next1, p1);
1257             }
1258
1259           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1260                                            to_next, n_left_to_next,
1261                                            pi0, pi1, next0, next1);
1262         }
1263
1264       while (n_left_from > 0 && n_left_to_next > 0)
1265         {
1266           vlib_buffer_t *p0;
1267           ip6_header_t *ip0;
1268           udp_header_t *udp0;
1269           u32 pi0, ip_len0, udp_len0, flags0, next0;
1270           i32 len_diff0;
1271           u8 error0, type0, good_l4_csum0;
1272           u32 udp_offset0;
1273           u8 is_tcp_udp0;
1274
1275           pi0 = to_next[0] = from[0];
1276           from += 1;
1277           n_left_from -= 1;
1278           to_next += 1;
1279           n_left_to_next -= 1;
1280
1281           error0 = IP6_ERROR_UNKNOWN_PROTOCOL;
1282
1283           p0 = vlib_get_buffer (vm, pi0);
1284           ip0 = vlib_buffer_get_current (p0);
1285
1286           if (head_of_feature_arc == 0)
1287             goto skip_check;
1288
1289           vnet_buffer (p0)->l3_hdr_offset = p0->current_data;
1290
1291           type0 = lm->builtin_protocol_by_ip_protocol[ip0->protocol];
1292           flags0 = p0->flags;
1293           is_tcp_udp0 = ip6_next_proto_is_tcp_udp (p0, ip0, &udp_offset0);
1294           good_l4_csum0 = (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT
1295                            || (flags0 & VNET_BUFFER_F_OFFLOAD_TCP_CKSUM
1296                                || flags0 & VNET_BUFFER_F_OFFLOAD_UDP_CKSUM))
1297             != 0;
1298
1299           len_diff0 = 0;
1300           if (PREDICT_TRUE (is_tcp_udp0))
1301             {
1302               udp0 = (udp_header_t *) ((u8 *) ip0 + udp_offset0);
1303               /* Don't verify UDP checksum for packets with explicit zero
1304                * checksum. */
1305               good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UDP
1306                 && udp0->checksum == 0;
1307               /* Verify UDP length. */
1308               if (is_tcp_udp0 == IP_PROTOCOL_UDP)
1309                 {
1310                   ip_len0 = clib_net_to_host_u16 (ip0->payload_length);
1311                   udp_len0 = clib_net_to_host_u16 (udp0->length);
1312                   len_diff0 = ip_len0 - udp_len0;
1313                 }
1314             }
1315
1316           good_l4_csum0 |= type0 == IP_BUILTIN_PROTOCOL_UNKNOWN;
1317           len_diff0 = type0 == IP_BUILTIN_PROTOCOL_UDP ? len_diff0 : 0;
1318
1319           if (PREDICT_FALSE (type0 != IP_BUILTIN_PROTOCOL_UNKNOWN
1320                              && !good_l4_csum0
1321                              && !(flags0 &
1322                                   VNET_BUFFER_F_L4_CHECKSUM_COMPUTED)))
1323             {
1324               flags0 = ip6_tcp_udp_icmp_validate_checksum (vm, p0);
1325               good_l4_csum0 =
1326                 (flags0 & VNET_BUFFER_F_L4_CHECKSUM_CORRECT) != 0;
1327             }
1328
1329           error0 = IP6_ERROR_UNKNOWN_PROTOCOL;
1330           error0 = len_diff0 < 0 ? IP6_ERROR_UDP_LENGTH : error0;
1331
1332           ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_UDP ==
1333                   IP6_ERROR_UDP_CHECKSUM);
1334           ASSERT (IP6_ERROR_UDP_CHECKSUM + IP_BUILTIN_PROTOCOL_ICMP ==
1335                   IP6_ERROR_ICMP_CHECKSUM);
1336           error0 = (!good_l4_csum0 ? IP6_ERROR_UDP_CHECKSUM + type0 : error0);
1337
1338           /* If this is a neighbor solicitation (ICMP), skip src RPF check */
1339           if (error0 == IP6_ERROR_UNKNOWN_PROTOCOL &&
1340               type0 != IP_BUILTIN_PROTOCOL_ICMP &&
1341               !ip6_address_is_link_local_unicast (&ip0->src_address))
1342             {
1343               error0 = (!ip6_urpf_loose_check (im, p0, ip0)
1344                         ? IP6_ERROR_SRC_LOOKUP_MISS : error0);
1345             }
1346
1347           vnet_buffer (p0)->ip.fib_index =
1348             vec_elt (im->fib_index_by_sw_if_index,
1349                      vnet_buffer (p0)->sw_if_index[VLIB_RX]);
1350           vnet_buffer (p0)->ip.fib_index =
1351             (vnet_buffer (p0)->sw_if_index[VLIB_TX] ==
1352              (u32) ~ 0) ? vnet_buffer (p0)->ip.
1353             fib_index : vnet_buffer (p0)->sw_if_index[VLIB_TX];
1354
1355         skip_check:
1356
1357           next0 = lm->local_next_by_ip_protocol[ip0->protocol];
1358           next0 =
1359             error0 != IP6_ERROR_UNKNOWN_PROTOCOL ? IP_LOCAL_NEXT_DROP : next0;
1360
1361           p0->error = error_node->errors[error0];
1362
1363           if (head_of_feature_arc)
1364             {
1365               if (PREDICT_TRUE (error0 == (u8) IP6_ERROR_UNKNOWN_PROTOCOL))
1366                 vnet_feature_arc_start (arc_index,
1367                                         vnet_buffer (p0)->sw_if_index
1368                                         [VLIB_RX], &next0, p0);
1369             }
1370
1371           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1372                                            to_next, n_left_to_next,
1373                                            pi0, next0);
1374         }
1375
1376       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1377     }
1378
1379   return frame->n_vectors;
1380 }
1381
1382 static uword
1383 ip6_local (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
1384 {
1385   return ip6_local_inline (vm, node, frame, 1 /* head of feature arc */ );
1386 }
1387
1388 /* *INDENT-OFF* */
1389 VLIB_REGISTER_NODE (ip6_local_node, static) =
1390 {
1391   .function = ip6_local,
1392   .name = "ip6-local",
1393   .vector_size = sizeof (u32),
1394   .format_trace = format_ip6_forward_next_trace,
1395   .n_next_nodes = IP_LOCAL_N_NEXT,
1396   .next_nodes =
1397   {
1398     [IP_LOCAL_NEXT_DROP] = "ip6-drop",
1399     [IP_LOCAL_NEXT_PUNT] = "ip6-punt",
1400     [IP_LOCAL_NEXT_UDP_LOOKUP] = "ip6-udp-lookup",
1401     [IP_LOCAL_NEXT_ICMP] = "ip6-icmp-input",
1402   },
1403 };
1404 /* *INDENT-ON* */
1405
1406 VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_node, ip6_local);
1407
1408
1409 static uword
1410 ip6_local_end_of_arc (vlib_main_t * vm,
1411                       vlib_node_runtime_t * node, vlib_frame_t * frame)
1412 {
1413   return ip6_local_inline (vm, node, frame, 0 /* head of feature arc */ );
1414 }
1415
1416 /* *INDENT-OFF* */
1417 VLIB_REGISTER_NODE (ip6_local_end_of_arc_node,static) = {
1418   .function = ip6_local_end_of_arc,
1419   .name = "ip6-local-end-of-arc",
1420   .vector_size = sizeof (u32),
1421
1422   .format_trace = format_ip6_forward_next_trace,
1423   .sibling_of = "ip6-local",
1424 };
1425
1426 VLIB_NODE_FUNCTION_MULTIARCH (ip6_local_end_of_arc_node, ip6_local_end_of_arc)
1427
1428 VNET_FEATURE_INIT (ip6_local_end_of_arc, static) = {
1429   .arc_name = "ip6-local",
1430   .node_name = "ip6-local-end-of-arc",
1431   .runs_before = 0, /* not before any other features */
1432 };
1433 /* *INDENT-ON* */
1434
1435 void
1436 ip6_register_protocol (u32 protocol, u32 node_index)
1437 {
1438   vlib_main_t *vm = vlib_get_main ();
1439   ip6_main_t *im = &ip6_main;
1440   ip_lookup_main_t *lm = &im->lookup_main;
1441
1442   ASSERT (protocol < ARRAY_LEN (lm->local_next_by_ip_protocol));
1443   lm->local_next_by_ip_protocol[protocol] =
1444     vlib_node_add_next (vm, ip6_local_node.index, node_index);
1445 }
1446
1447 clib_error_t *
1448 ip6_probe_neighbor (vlib_main_t * vm, ip6_address_t * dst, u32 sw_if_index)
1449 {
1450   vnet_main_t *vnm = vnet_get_main ();
1451   ip6_main_t *im = &ip6_main;
1452   icmp6_neighbor_solicitation_header_t *h;
1453   ip6_address_t *src;
1454   ip_interface_address_t *ia;
1455   ip_adjacency_t *adj;
1456   vnet_hw_interface_t *hi;
1457   vnet_sw_interface_t *si;
1458   vlib_buffer_t *b;
1459   adj_index_t ai;
1460   u32 bi = 0;
1461   int bogus_length;
1462
1463   si = vnet_get_sw_interface (vnm, sw_if_index);
1464
1465   if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
1466     {
1467       return clib_error_return (0, "%U: interface %U down",
1468                                 format_ip6_address, dst,
1469                                 format_vnet_sw_if_index_name, vnm,
1470                                 sw_if_index);
1471     }
1472
1473   src =
1474     ip6_interface_address_matching_destination (im, dst, sw_if_index, &ia);
1475   if (!src)
1476     {
1477       vnm->api_errno = VNET_API_ERROR_NO_MATCHING_INTERFACE;
1478       return clib_error_return
1479         (0, "no matching interface address for destination %U (interface %U)",
1480          format_ip6_address, dst,
1481          format_vnet_sw_if_index_name, vnm, sw_if_index);
1482     }
1483
1484   h =
1485     vlib_packet_template_get_packet (vm,
1486                                      &im->discover_neighbor_packet_template,
1487                                      &bi);
1488
1489   hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1490
1491   /* Destination address is a solicited node multicast address.  We need to fill in
1492      the low 24 bits with low 24 bits of target's address. */
1493   h->ip.dst_address.as_u8[13] = dst->as_u8[13];
1494   h->ip.dst_address.as_u8[14] = dst->as_u8[14];
1495   h->ip.dst_address.as_u8[15] = dst->as_u8[15];
1496
1497   h->ip.src_address = src[0];
1498   h->neighbor.target_address = dst[0];
1499
1500   if (PREDICT_FALSE (!hi->hw_address))
1501     {
1502       return clib_error_return (0, "%U: interface %U do not support ip probe",
1503                                 format_ip6_address, dst,
1504                                 format_vnet_sw_if_index_name, vnm,
1505                                 sw_if_index);
1506     }
1507
1508   clib_memcpy (h->link_layer_option.ethernet_address, hi->hw_address,
1509                vec_len (hi->hw_address));
1510
1511   h->neighbor.icmp.checksum =
1512     ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length);
1513   ASSERT (bogus_length == 0);
1514
1515   b = vlib_get_buffer (vm, bi);
1516   vnet_buffer (b)->sw_if_index[VLIB_RX] =
1517     vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
1518
1519   /* Add encapsulation string for software interface (e.g. ethernet header). */
1520   ip46_address_t nh = {
1521     .ip6 = *dst,
1522   };
1523
1524   ai = adj_nbr_add_or_lock (FIB_PROTOCOL_IP6,
1525                             VNET_LINK_IP6, &nh, sw_if_index);
1526   adj = adj_get (ai);
1527
1528   /* Peer has been previously resolved, retrieve glean adj instead */
1529   if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE)
1530     {
1531       adj_unlock (ai);
1532       ai = adj_glean_add_or_lock (FIB_PROTOCOL_IP6,
1533                                   VNET_LINK_IP6, sw_if_index, &nh);
1534       adj = adj_get (ai);
1535     }
1536
1537   vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
1538   vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
1539
1540   {
1541     vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
1542     u32 *to_next = vlib_frame_vector_args (f);
1543     to_next[0] = bi;
1544     f->n_vectors = 1;
1545     vlib_put_frame_to_node (vm, hi->output_node_index, f);
1546   }
1547
1548   adj_unlock (ai);
1549   return /* no error */ 0;
1550 }
1551
1552 typedef enum
1553 {
1554   IP6_REWRITE_NEXT_DROP,
1555   IP6_REWRITE_NEXT_ICMP_ERROR,
1556 } ip6_rewrite_next_t;
1557
1558 /**
1559  * This bits of an IPv6 address to mask to construct a multicast
1560  * MAC address
1561  */
1562 #define IP6_MCAST_ADDR_MASK 0xffffffff
1563
1564 always_inline uword
1565 ip6_rewrite_inline (vlib_main_t * vm,
1566                     vlib_node_runtime_t * node,
1567                     vlib_frame_t * frame,
1568                     int do_counters, int is_midchain, int is_mcast)
1569 {
1570   ip_lookup_main_t *lm = &ip6_main.lookup_main;
1571   u32 *from = vlib_frame_vector_args (frame);
1572   u32 n_left_from, n_left_to_next, *to_next, next_index;
1573   vlib_node_runtime_t *error_node =
1574     vlib_node_get_runtime (vm, ip6_input_node.index);
1575
1576   n_left_from = frame->n_vectors;
1577   next_index = node->cached_next_index;
1578   u32 thread_index = vlib_get_thread_index ();
1579
1580   while (n_left_from > 0)
1581     {
1582       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1583
1584       while (n_left_from >= 4 && n_left_to_next >= 2)
1585         {
1586           ip_adjacency_t *adj0, *adj1;
1587           vlib_buffer_t *p0, *p1;
1588           ip6_header_t *ip0, *ip1;
1589           u32 pi0, rw_len0, next0, error0, adj_index0;
1590           u32 pi1, rw_len1, next1, error1, adj_index1;
1591           u32 tx_sw_if_index0, tx_sw_if_index1;
1592
1593           /* Prefetch next iteration. */
1594           {
1595             vlib_buffer_t *p2, *p3;
1596
1597             p2 = vlib_get_buffer (vm, from[2]);
1598             p3 = vlib_get_buffer (vm, from[3]);
1599
1600             vlib_prefetch_buffer_header (p2, LOAD);
1601             vlib_prefetch_buffer_header (p3, LOAD);
1602
1603             CLIB_PREFETCH (p2->pre_data, 32, STORE);
1604             CLIB_PREFETCH (p3->pre_data, 32, STORE);
1605
1606             CLIB_PREFETCH (p2->data, sizeof (ip0[0]), STORE);
1607             CLIB_PREFETCH (p3->data, sizeof (ip0[0]), STORE);
1608           }
1609
1610           pi0 = to_next[0] = from[0];
1611           pi1 = to_next[1] = from[1];
1612
1613           from += 2;
1614           n_left_from -= 2;
1615           to_next += 2;
1616           n_left_to_next -= 2;
1617
1618           p0 = vlib_get_buffer (vm, pi0);
1619           p1 = vlib_get_buffer (vm, pi1);
1620
1621           adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
1622           adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
1623
1624           ip0 = vlib_buffer_get_current (p0);
1625           ip1 = vlib_buffer_get_current (p1);
1626
1627           error0 = error1 = IP6_ERROR_NONE;
1628           next0 = next1 = IP6_REWRITE_NEXT_DROP;
1629
1630           if (PREDICT_TRUE (!(p0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
1631             {
1632               i32 hop_limit0 = ip0->hop_limit;
1633
1634               /* Input node should have reject packets with hop limit 0. */
1635               ASSERT (ip0->hop_limit > 0);
1636
1637               hop_limit0 -= 1;
1638
1639               ip0->hop_limit = hop_limit0;
1640
1641               /*
1642                * If the hop count drops below 1 when forwarding, generate
1643                * an ICMP response.
1644                */
1645               if (PREDICT_FALSE (hop_limit0 <= 0))
1646                 {
1647                   error0 = IP6_ERROR_TIME_EXPIRED;
1648                   next0 = IP6_REWRITE_NEXT_ICMP_ERROR;
1649                   vnet_buffer (p0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1650                   icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
1651                                                ICMP6_time_exceeded_ttl_exceeded_in_transit,
1652                                                0);
1653                 }
1654             }
1655           else
1656             {
1657               p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
1658             }
1659           if (PREDICT_TRUE (!(p1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED)))
1660             {
1661               i32 hop_limit1 = ip1->hop_limit;
1662
1663               /* Input node should have reject packets with hop limit 0. */
1664               ASSERT (ip1->hop_limit > 0);
1665
1666               hop_limit1 -= 1;
1667
1668               ip1->hop_limit = hop_limit1;
1669
1670               /*
1671                * If the hop count drops below 1 when forwarding, generate
1672                * an ICMP response.
1673                */
1674               if (PREDICT_FALSE (hop_limit1 <= 0))
1675                 {
1676                   error1 = IP6_ERROR_TIME_EXPIRED;
1677                   next1 = IP6_REWRITE_NEXT_ICMP_ERROR;
1678                   vnet_buffer (p1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1679                   icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
1680                                                ICMP6_time_exceeded_ttl_exceeded_in_transit,
1681                                                0);
1682                 }
1683             }
1684           else
1685             {
1686               p1->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
1687             }
1688           adj0 = adj_get (adj_index0);
1689           adj1 = adj_get (adj_index1);
1690
1691           rw_len0 = adj0[0].rewrite_header.data_bytes;
1692           rw_len1 = adj1[0].rewrite_header.data_bytes;
1693           vnet_buffer (p0)->ip.save_rewrite_length = rw_len0;
1694           vnet_buffer (p1)->ip.save_rewrite_length = rw_len1;
1695
1696           if (do_counters)
1697             {
1698               vlib_increment_combined_counter
1699                 (&adjacency_counters,
1700                  thread_index, adj_index0, 1,
1701                  vlib_buffer_length_in_chain (vm, p0) + rw_len0);
1702               vlib_increment_combined_counter
1703                 (&adjacency_counters,
1704                  thread_index, adj_index1, 1,
1705                  vlib_buffer_length_in_chain (vm, p1) + rw_len1);
1706             }
1707
1708           /* Check MTU of outgoing interface. */
1709           error0 =
1710             (vlib_buffer_length_in_chain (vm, p0) >
1711              adj0[0].
1712              rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
1713              error0);
1714           error1 =
1715             (vlib_buffer_length_in_chain (vm, p1) >
1716              adj1[0].
1717              rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
1718              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           error0 =
1853             (vlib_buffer_length_in_chain (vm, p0) >
1854              adj0[0].
1855              rewrite_header.max_l3_packet_bytes ? IP6_ERROR_MTU_EXCEEDED :
1856              error0);
1857
1858           /* Don't adjust the buffer for hop count issue; icmp-error node
1859            * wants to see the IP headerr */
1860           if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
1861             {
1862               p0->current_data -= rw_len0;
1863               p0->current_length += rw_len0;
1864
1865               tx_sw_if_index0 = adj0[0].rewrite_header.sw_if_index;
1866
1867               vnet_buffer (p0)->sw_if_index[VLIB_TX] = tx_sw_if_index0;
1868               next0 = adj0[0].rewrite_header.next_index;
1869
1870               if (PREDICT_FALSE
1871                   (adj0[0].rewrite_header.flags & VNET_REWRITE_HAS_FEATURES))
1872                 vnet_feature_arc_start (lm->output_feature_arc_index,
1873                                         tx_sw_if_index0, &next0, p0);
1874             }
1875
1876           if (is_midchain)
1877             {
1878               adj0->sub_type.midchain.fixup_func
1879                 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
1880             }
1881           if (is_mcast)
1882             {
1883               vnet_ip_mcast_fixup_header (IP6_MCAST_ADDR_MASK,
1884                                           adj0->
1885                                           rewrite_header.dst_mcast_offset,
1886                                           &ip0->dst_address.as_u32[3],
1887                                           (u8 *) ip0);
1888             }
1889
1890           p0->error = error_node->errors[error0];
1891
1892           from += 1;
1893           n_left_from -= 1;
1894           to_next += 1;
1895           n_left_to_next -= 1;
1896
1897           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1898                                            to_next, n_left_to_next,
1899                                            pi0, next0);
1900         }
1901
1902       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1903     }
1904
1905   /* Need to do trace after rewrites to pick up new packet data. */
1906   if (node->flags & VLIB_NODE_FLAG_TRACE)
1907     ip6_forward_next_trace (vm, node, frame, VLIB_TX);
1908
1909   return frame->n_vectors;
1910 }
1911
1912 static uword
1913 ip6_rewrite (vlib_main_t * vm,
1914              vlib_node_runtime_t * node, vlib_frame_t * frame)
1915 {
1916   if (adj_are_counters_enabled ())
1917     return ip6_rewrite_inline (vm, node, frame, 1, 0, 0);
1918   else
1919     return ip6_rewrite_inline (vm, node, frame, 0, 0, 0);
1920 }
1921
1922 static uword
1923 ip6_rewrite_mcast (vlib_main_t * vm,
1924                    vlib_node_runtime_t * node, vlib_frame_t * frame)
1925 {
1926   if (adj_are_counters_enabled ())
1927     return ip6_rewrite_inline (vm, node, frame, 1, 0, 1);
1928   else
1929     return ip6_rewrite_inline (vm, node, frame, 0, 0, 1);
1930 }
1931
1932 static uword
1933 ip6_midchain (vlib_main_t * vm,
1934               vlib_node_runtime_t * node, vlib_frame_t * frame)
1935 {
1936   if (adj_are_counters_enabled ())
1937     return ip6_rewrite_inline (vm, node, frame, 1, 1, 0);
1938   else
1939     return ip6_rewrite_inline (vm, node, frame, 0, 1, 0);
1940 }
1941
1942 static uword
1943 ip6_mcast_midchain (vlib_main_t * vm,
1944                     vlib_node_runtime_t * node, vlib_frame_t * frame)
1945 {
1946   if (adj_are_counters_enabled ())
1947     return ip6_rewrite_inline (vm, node, frame, 1, 1, 1);
1948   else
1949     return ip6_rewrite_inline (vm, node, frame, 0, 1, 1);
1950 }
1951
1952 /* *INDENT-OFF* */
1953 VLIB_REGISTER_NODE (ip6_midchain_node) =
1954 {
1955   .function = ip6_midchain,
1956   .name = "ip6-midchain",
1957   .vector_size = sizeof (u32),
1958   .format_trace = format_ip6_forward_next_trace,
1959   .sibling_of = "ip6-rewrite",
1960   };
1961 /* *INDENT-ON* */
1962
1963 VLIB_NODE_FUNCTION_MULTIARCH (ip6_midchain_node, ip6_midchain);
1964
1965 /* *INDENT-OFF* */
1966 VLIB_REGISTER_NODE (ip6_rewrite_node) =
1967 {
1968   .function = ip6_rewrite,
1969   .name = "ip6-rewrite",
1970   .vector_size = sizeof (u32),
1971   .format_trace = format_ip6_rewrite_trace,
1972   .n_next_nodes = 2,
1973   .next_nodes =
1974   {
1975     [IP6_REWRITE_NEXT_DROP] = "ip6-drop",
1976     [IP6_REWRITE_NEXT_ICMP_ERROR] = "ip6-icmp-error",
1977   },
1978 };
1979 /* *INDENT-ON* */
1980
1981 VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_node, ip6_rewrite);
1982
1983 /* *INDENT-OFF* */
1984 VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
1985 {
1986   .function = ip6_rewrite_mcast,
1987   .name = "ip6-rewrite-mcast",
1988   .vector_size = sizeof (u32),
1989   .format_trace = format_ip6_rewrite_trace,
1990   .sibling_of = "ip6-rewrite",
1991 };
1992 /* *INDENT-ON* */
1993
1994 VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_mcast_node, ip6_rewrite_mcast);
1995
1996 /* *INDENT-OFF* */
1997 VLIB_REGISTER_NODE (ip6_mcast_midchain_node, static) =
1998 {
1999   .function = ip6_mcast_midchain,
2000   .name = "ip6-mcast-midchain",
2001   .vector_size = sizeof (u32),
2002   .format_trace = format_ip6_rewrite_trace,
2003   .sibling_of = "ip6-rewrite",
2004 };
2005 /* *INDENT-ON* */
2006
2007 VLIB_NODE_FUNCTION_MULTIARCH (ip6_mcast_midchain_node, ip6_mcast_midchain);
2008
2009 /*
2010  * Hop-by-Hop handling
2011  */
2012 ip6_hop_by_hop_main_t ip6_hop_by_hop_main;
2013
2014 #define foreach_ip6_hop_by_hop_error \
2015 _(PROCESSED, "pkts with ip6 hop-by-hop options") \
2016 _(FORMAT, "incorrectly formatted hop-by-hop options") \
2017 _(UNKNOWN_OPTION, "unknown ip6 hop-by-hop options")
2018
2019 /* *INDENT-OFF* */
2020 typedef enum
2021 {
2022 #define _(sym,str) IP6_HOP_BY_HOP_ERROR_##sym,
2023   foreach_ip6_hop_by_hop_error
2024 #undef _
2025   IP6_HOP_BY_HOP_N_ERROR,
2026 } ip6_hop_by_hop_error_t;
2027 /* *INDENT-ON* */
2028
2029 /*
2030  * Primary h-b-h handler trace support
2031  * We work pretty hard on the problem for obvious reasons
2032  */
2033 typedef struct
2034 {
2035   u32 next_index;
2036   u32 trace_len;
2037   u8 option_data[256];
2038 } ip6_hop_by_hop_trace_t;
2039
2040 vlib_node_registration_t ip6_hop_by_hop_node;
2041
2042 static char *ip6_hop_by_hop_error_strings[] = {
2043 #define _(sym,string) string,
2044   foreach_ip6_hop_by_hop_error
2045 #undef _
2046 };
2047
2048 u8 *
2049 format_ip6_hop_by_hop_ext_hdr (u8 * s, va_list * args)
2050 {
2051   ip6_hop_by_hop_header_t *hbh0 = va_arg (*args, ip6_hop_by_hop_header_t *);
2052   int total_len = va_arg (*args, int);
2053   ip6_hop_by_hop_option_t *opt0, *limit0;
2054   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2055   u8 type0;
2056
2057   s = format (s, "IP6_HOP_BY_HOP: next protocol %d len %d total %d",
2058               hbh0->protocol, (hbh0->length + 1) << 3, total_len);
2059
2060   opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2061   limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 + total_len);
2062
2063   while (opt0 < limit0)
2064     {
2065       type0 = opt0->type;
2066       switch (type0)
2067         {
2068         case 0:         /* Pad, just stop */
2069           opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0 + 1);
2070           break;
2071
2072         default:
2073           if (hm->trace[type0])
2074             {
2075               s = (*hm->trace[type0]) (s, opt0);
2076             }
2077           else
2078             {
2079               s =
2080                 format (s, "\n    unrecognized option %d length %d", type0,
2081                         opt0->length);
2082             }
2083           opt0 =
2084             (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2085                                          sizeof (ip6_hop_by_hop_option_t));
2086           break;
2087         }
2088     }
2089   return s;
2090 }
2091
2092 static u8 *
2093 format_ip6_hop_by_hop_trace (u8 * s, va_list * args)
2094 {
2095   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2096   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
2097   ip6_hop_by_hop_trace_t *t = va_arg (*args, ip6_hop_by_hop_trace_t *);
2098   ip6_hop_by_hop_header_t *hbh0;
2099   ip6_hop_by_hop_option_t *opt0, *limit0;
2100   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2101
2102   u8 type0;
2103
2104   hbh0 = (ip6_hop_by_hop_header_t *) t->option_data;
2105
2106   s = format (s, "IP6_HOP_BY_HOP: next index %d len %d traced %d",
2107               t->next_index, (hbh0->length + 1) << 3, t->trace_len);
2108
2109   opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2110   limit0 = (ip6_hop_by_hop_option_t *) ((u8 *) hbh0) + t->trace_len;
2111
2112   while (opt0 < limit0)
2113     {
2114       type0 = opt0->type;
2115       switch (type0)
2116         {
2117         case 0:         /* Pad, just stop */
2118           opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2119           break;
2120
2121         default:
2122           if (hm->trace[type0])
2123             {
2124               s = (*hm->trace[type0]) (s, opt0);
2125             }
2126           else
2127             {
2128               s =
2129                 format (s, "\n    unrecognized option %d length %d", type0,
2130                         opt0->length);
2131             }
2132           opt0 =
2133             (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2134                                          sizeof (ip6_hop_by_hop_option_t));
2135           break;
2136         }
2137     }
2138   return s;
2139 }
2140
2141 always_inline u8
2142 ip6_scan_hbh_options (vlib_buffer_t * b0,
2143                       ip6_header_t * ip0,
2144                       ip6_hop_by_hop_header_t * hbh0,
2145                       ip6_hop_by_hop_option_t * opt0,
2146                       ip6_hop_by_hop_option_t * limit0, u32 * next0)
2147 {
2148   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2149   u8 type0;
2150   u8 error0 = 0;
2151
2152   while (opt0 < limit0)
2153     {
2154       type0 = opt0->type;
2155       switch (type0)
2156         {
2157         case 0:         /* Pad1 */
2158           opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
2159           continue;
2160         case 1:         /* PadN */
2161           break;
2162         default:
2163           if (hm->options[type0])
2164             {
2165               if ((*hm->options[type0]) (b0, ip0, opt0) < 0)
2166                 {
2167                   error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2168                   return (error0);
2169                 }
2170             }
2171           else
2172             {
2173               /* Unrecognized mandatory option, check the two high order bits */
2174               switch (opt0->type & HBH_OPTION_TYPE_HIGH_ORDER_BITS)
2175                 {
2176                 case HBH_OPTION_TYPE_SKIP_UNKNOWN:
2177                   break;
2178                 case HBH_OPTION_TYPE_DISCARD_UNKNOWN:
2179                   error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2180                   *next0 = IP_LOOKUP_NEXT_DROP;
2181                   break;
2182                 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP:
2183                   error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2184                   *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2185                   icmp6_error_set_vnet_buffer (b0, ICMP6_parameter_problem,
2186                                                ICMP6_parameter_problem_unrecognized_option,
2187                                                (u8 *) opt0 - (u8 *) ip0);
2188                   break;
2189                 case HBH_OPTION_TYPE_DISCARD_UNKNOWN_ICMP_NOT_MCAST:
2190                   error0 = IP6_HOP_BY_HOP_ERROR_UNKNOWN_OPTION;
2191                   if (!ip6_address_is_multicast (&ip0->dst_address))
2192                     {
2193                       *next0 = IP_LOOKUP_NEXT_ICMP_ERROR;
2194                       icmp6_error_set_vnet_buffer (b0,
2195                                                    ICMP6_parameter_problem,
2196                                                    ICMP6_parameter_problem_unrecognized_option,
2197                                                    (u8 *) opt0 - (u8 *) ip0);
2198                     }
2199                   else
2200                     {
2201                       *next0 = IP_LOOKUP_NEXT_DROP;
2202                     }
2203                   break;
2204                 }
2205               return (error0);
2206             }
2207         }
2208       opt0 =
2209         (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
2210                                      sizeof (ip6_hop_by_hop_option_t));
2211     }
2212   return (error0);
2213 }
2214
2215 /*
2216  * Process the Hop-by-Hop Options header
2217  */
2218 static uword
2219 ip6_hop_by_hop (vlib_main_t * vm,
2220                 vlib_node_runtime_t * node, vlib_frame_t * frame)
2221 {
2222   vlib_node_runtime_t *error_node =
2223     vlib_node_get_runtime (vm, ip6_hop_by_hop_node.index);
2224   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2225   u32 n_left_from, *from, *to_next;
2226   ip_lookup_next_t next_index;
2227
2228   from = vlib_frame_vector_args (frame);
2229   n_left_from = frame->n_vectors;
2230   next_index = node->cached_next_index;
2231
2232   while (n_left_from > 0)
2233     {
2234       u32 n_left_to_next;
2235
2236       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2237
2238       while (n_left_from >= 4 && n_left_to_next >= 2)
2239         {
2240           u32 bi0, bi1;
2241           vlib_buffer_t *b0, *b1;
2242           u32 next0, next1;
2243           ip6_header_t *ip0, *ip1;
2244           ip6_hop_by_hop_header_t *hbh0, *hbh1;
2245           ip6_hop_by_hop_option_t *opt0, *limit0, *opt1, *limit1;
2246           u8 error0 = 0, error1 = 0;
2247
2248           /* Prefetch next iteration. */
2249           {
2250             vlib_buffer_t *p2, *p3;
2251
2252             p2 = vlib_get_buffer (vm, from[2]);
2253             p3 = vlib_get_buffer (vm, from[3]);
2254
2255             vlib_prefetch_buffer_header (p2, LOAD);
2256             vlib_prefetch_buffer_header (p3, LOAD);
2257
2258             CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2259             CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2260           }
2261
2262           /* Speculatively enqueue b0, b1 to the current next frame */
2263           to_next[0] = bi0 = from[0];
2264           to_next[1] = bi1 = from[1];
2265           from += 2;
2266           to_next += 2;
2267           n_left_from -= 2;
2268           n_left_to_next -= 2;
2269
2270           b0 = vlib_get_buffer (vm, bi0);
2271           b1 = vlib_get_buffer (vm, bi1);
2272
2273           /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2274           u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
2275           ip_adjacency_t *adj0 = adj_get (adj_index0);
2276           u32 adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
2277           ip_adjacency_t *adj1 = adj_get (adj_index1);
2278
2279           /* Default use the next_index from the adjacency. A HBH option rarely redirects to a different node */
2280           next0 = adj0->lookup_next_index;
2281           next1 = adj1->lookup_next_index;
2282
2283           ip0 = vlib_buffer_get_current (b0);
2284           ip1 = vlib_buffer_get_current (b1);
2285           hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2286           hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1);
2287           opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2288           opt1 = (ip6_hop_by_hop_option_t *) (hbh1 + 1);
2289           limit0 =
2290             (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2291                                          ((hbh0->length + 1) << 3));
2292           limit1 =
2293             (ip6_hop_by_hop_option_t *) ((u8 *) hbh1 +
2294                                          ((hbh1->length + 1) << 3));
2295
2296           /*
2297            * Basic validity checks
2298            */
2299           if ((hbh0->length + 1) << 3 >
2300               clib_net_to_host_u16 (ip0->payload_length))
2301             {
2302               error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2303               next0 = IP_LOOKUP_NEXT_DROP;
2304               goto outdual;
2305             }
2306           /* Scan the set of h-b-h options, process ones that we understand */
2307           error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2308
2309           if ((hbh1->length + 1) << 3 >
2310               clib_net_to_host_u16 (ip1->payload_length))
2311             {
2312               error1 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2313               next1 = IP_LOOKUP_NEXT_DROP;
2314               goto outdual;
2315             }
2316           /* Scan the set of h-b-h options, process ones that we understand */
2317           error1 = ip6_scan_hbh_options (b1, ip1, hbh1, opt1, limit1, &next1);
2318
2319         outdual:
2320           /* Has the classifier flagged this buffer for special treatment? */
2321           if (PREDICT_FALSE
2322               ((error0 == 0)
2323                && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2324             next0 = hm->next_override;
2325
2326           /* Has the classifier flagged this buffer for special treatment? */
2327           if (PREDICT_FALSE
2328               ((error1 == 0)
2329                && (vnet_buffer (b1)->l2_classify.opaque_index & OI_DECAP)))
2330             next1 = hm->next_override;
2331
2332           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
2333             {
2334               if (b0->flags & VLIB_BUFFER_IS_TRACED)
2335                 {
2336                   ip6_hop_by_hop_trace_t *t =
2337                     vlib_add_trace (vm, node, b0, sizeof (*t));
2338                   u32 trace_len = (hbh0->length + 1) << 3;
2339                   t->next_index = next0;
2340                   /* Capture the h-b-h option verbatim */
2341                   trace_len =
2342                     trace_len <
2343                     ARRAY_LEN (t->option_data) ? trace_len :
2344                     ARRAY_LEN (t->option_data);
2345                   t->trace_len = trace_len;
2346                   clib_memcpy (t->option_data, hbh0, trace_len);
2347                 }
2348               if (b1->flags & VLIB_BUFFER_IS_TRACED)
2349                 {
2350                   ip6_hop_by_hop_trace_t *t =
2351                     vlib_add_trace (vm, node, b1, sizeof (*t));
2352                   u32 trace_len = (hbh1->length + 1) << 3;
2353                   t->next_index = next1;
2354                   /* Capture the h-b-h option verbatim */
2355                   trace_len =
2356                     trace_len <
2357                     ARRAY_LEN (t->option_data) ? trace_len :
2358                     ARRAY_LEN (t->option_data);
2359                   t->trace_len = trace_len;
2360                   clib_memcpy (t->option_data, hbh1, trace_len);
2361                 }
2362
2363             }
2364
2365           b0->error = error_node->errors[error0];
2366           b1->error = error_node->errors[error1];
2367
2368           /* verify speculative enqueue, maybe switch current next frame */
2369           vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
2370                                            n_left_to_next, bi0, bi1, next0,
2371                                            next1);
2372         }
2373
2374       while (n_left_from > 0 && n_left_to_next > 0)
2375         {
2376           u32 bi0;
2377           vlib_buffer_t *b0;
2378           u32 next0;
2379           ip6_header_t *ip0;
2380           ip6_hop_by_hop_header_t *hbh0;
2381           ip6_hop_by_hop_option_t *opt0, *limit0;
2382           u8 error0 = 0;
2383
2384           /* Speculatively enqueue b0 to the current next frame */
2385           bi0 = from[0];
2386           to_next[0] = bi0;
2387           from += 1;
2388           to_next += 1;
2389           n_left_from -= 1;
2390           n_left_to_next -= 1;
2391
2392           b0 = vlib_get_buffer (vm, bi0);
2393           /*
2394            * Default use the next_index from the adjacency.
2395            * A HBH option rarely redirects to a different node
2396            */
2397           u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
2398           ip_adjacency_t *adj0 = adj_get (adj_index0);
2399           next0 = adj0->lookup_next_index;
2400
2401           ip0 = vlib_buffer_get_current (b0);
2402           hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
2403           opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
2404           limit0 =
2405             (ip6_hop_by_hop_option_t *) ((u8 *) hbh0 +
2406                                          ((hbh0->length + 1) << 3));
2407
2408           /*
2409            * Basic validity checks
2410            */
2411           if ((hbh0->length + 1) << 3 >
2412               clib_net_to_host_u16 (ip0->payload_length))
2413             {
2414               error0 = IP6_HOP_BY_HOP_ERROR_FORMAT;
2415               next0 = IP_LOOKUP_NEXT_DROP;
2416               goto out0;
2417             }
2418
2419           /* Scan the set of h-b-h options, process ones that we understand */
2420           error0 = ip6_scan_hbh_options (b0, ip0, hbh0, opt0, limit0, &next0);
2421
2422         out0:
2423           /* Has the classifier flagged this buffer for special treatment? */
2424           if (PREDICT_FALSE
2425               ((error0 == 0)
2426                && (vnet_buffer (b0)->l2_classify.opaque_index & OI_DECAP)))
2427             next0 = hm->next_override;
2428
2429           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2430             {
2431               ip6_hop_by_hop_trace_t *t =
2432                 vlib_add_trace (vm, node, b0, sizeof (*t));
2433               u32 trace_len = (hbh0->length + 1) << 3;
2434               t->next_index = next0;
2435               /* Capture the h-b-h option verbatim */
2436               trace_len =
2437                 trace_len <
2438                 ARRAY_LEN (t->option_data) ? trace_len :
2439                 ARRAY_LEN (t->option_data);
2440               t->trace_len = trace_len;
2441               clib_memcpy (t->option_data, hbh0, trace_len);
2442             }
2443
2444           b0->error = error_node->errors[error0];
2445
2446           /* verify speculative enqueue, maybe switch current next frame */
2447           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2448                                            n_left_to_next, bi0, next0);
2449         }
2450       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2451     }
2452   return frame->n_vectors;
2453 }
2454
2455 /* *INDENT-OFF* */
2456 VLIB_REGISTER_NODE (ip6_hop_by_hop_node) =
2457 {
2458   .function = ip6_hop_by_hop,
2459   .name = "ip6-hop-by-hop",
2460   .sibling_of = "ip6-lookup",
2461   .vector_size = sizeof (u32),
2462   .format_trace = format_ip6_hop_by_hop_trace,
2463   .type = VLIB_NODE_TYPE_INTERNAL,
2464   .n_errors = ARRAY_LEN (ip6_hop_by_hop_error_strings),
2465   .error_strings = ip6_hop_by_hop_error_strings,
2466   .n_next_nodes = 0,
2467 };
2468 /* *INDENT-ON* */
2469
2470 VLIB_NODE_FUNCTION_MULTIARCH (ip6_hop_by_hop_node, ip6_hop_by_hop);
2471
2472 static clib_error_t *
2473 ip6_hop_by_hop_init (vlib_main_t * vm)
2474 {
2475   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2476   memset (hm->options, 0, sizeof (hm->options));
2477   memset (hm->trace, 0, sizeof (hm->trace));
2478   hm->next_override = IP6_LOOKUP_NEXT_POP_HOP_BY_HOP;
2479   return (0);
2480 }
2481
2482 VLIB_INIT_FUNCTION (ip6_hop_by_hop_init);
2483
2484 void
2485 ip6_hbh_set_next_override (uword next)
2486 {
2487   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2488
2489   hm->next_override = next;
2490 }
2491
2492 int
2493 ip6_hbh_register_option (u8 option,
2494                          int options (vlib_buffer_t * b, ip6_header_t * ip,
2495                                       ip6_hop_by_hop_option_t * opt),
2496                          u8 * trace (u8 * s, ip6_hop_by_hop_option_t * opt))
2497 {
2498   ip6_main_t *im = &ip6_main;
2499   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2500
2501   ASSERT ((u32) option < ARRAY_LEN (hm->options));
2502
2503   /* Already registered */
2504   if (hm->options[option])
2505     return (-1);
2506
2507   hm->options[option] = options;
2508   hm->trace[option] = trace;
2509
2510   /* Set global variable */
2511   im->hbh_enabled = 1;
2512
2513   return (0);
2514 }
2515
2516 int
2517 ip6_hbh_unregister_option (u8 option)
2518 {
2519   ip6_main_t *im = &ip6_main;
2520   ip6_hop_by_hop_main_t *hm = &ip6_hop_by_hop_main;
2521
2522   ASSERT ((u32) option < ARRAY_LEN (hm->options));
2523
2524   /* Not registered */
2525   if (!hm->options[option])
2526     return (-1);
2527
2528   hm->options[option] = NULL;
2529   hm->trace[option] = NULL;
2530
2531   /* Disable global knob if this was the last option configured */
2532   int i;
2533   bool found = false;
2534   for (i = 0; i < 256; i++)
2535     {
2536       if (hm->options[option])
2537         {
2538           found = true;
2539           break;
2540         }
2541     }
2542   if (!found)
2543     im->hbh_enabled = 0;
2544
2545   return (0);
2546 }
2547
2548 /* Global IP6 main. */
2549 ip6_main_t ip6_main;
2550
2551 static clib_error_t *
2552 ip6_lookup_init (vlib_main_t * vm)
2553 {
2554   ip6_main_t *im = &ip6_main;
2555   clib_error_t *error;
2556   uword i;
2557
2558   if ((error = vlib_call_init_function (vm, vnet_feature_init)))
2559     return error;
2560
2561   for (i = 0; i < ARRAY_LEN (im->fib_masks); i++)
2562     {
2563       u32 j, i0, i1;
2564
2565       i0 = i / 32;
2566       i1 = i % 32;
2567
2568       for (j = 0; j < i0; j++)
2569         im->fib_masks[i].as_u32[j] = ~0;
2570
2571       if (i1)
2572         im->fib_masks[i].as_u32[i0] =
2573           clib_host_to_net_u32 (pow2_mask (i1) << (32 - i1));
2574     }
2575
2576   ip_lookup_init (&im->lookup_main, /* is_ip6 */ 1);
2577
2578   if (im->lookup_table_nbuckets == 0)
2579     im->lookup_table_nbuckets = IP6_FIB_DEFAULT_HASH_NUM_BUCKETS;
2580
2581   im->lookup_table_nbuckets = 1 << max_log2 (im->lookup_table_nbuckets);
2582
2583   if (im->lookup_table_size == 0)
2584     im->lookup_table_size = IP6_FIB_DEFAULT_HASH_MEMORY_SIZE;
2585
2586   BV (clib_bihash_init) (&(im->ip6_table[IP6_FIB_TABLE_FWDING].ip6_hash),
2587                          "ip6 FIB fwding table",
2588                          im->lookup_table_nbuckets, im->lookup_table_size);
2589   BV (clib_bihash_init) (&im->ip6_table[IP6_FIB_TABLE_NON_FWDING].ip6_hash,
2590                          "ip6 FIB non-fwding table",
2591                          im->lookup_table_nbuckets, im->lookup_table_size);
2592
2593   /* Create FIB with index 0 and table id of 0. */
2594   fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
2595                                      FIB_SOURCE_DEFAULT_ROUTE);
2596   mfib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, 0,
2597                                       MFIB_SOURCE_DEFAULT_ROUTE);
2598
2599   {
2600     pg_node_t *pn;
2601     pn = pg_get_node (ip6_lookup_node.index);
2602     pn->unformat_edit = unformat_pg_ip6_header;
2603   }
2604
2605   /* Unless explicitly configured, don't process HBH options */
2606   im->hbh_enabled = 0;
2607
2608   {
2609     icmp6_neighbor_solicitation_header_t p;
2610
2611     memset (&p, 0, sizeof (p));
2612
2613     p.ip.ip_version_traffic_class_and_flow_label =
2614       clib_host_to_net_u32 (0x6 << 28);
2615     p.ip.payload_length =
2616       clib_host_to_net_u16 (sizeof (p) -
2617                             STRUCT_OFFSET_OF
2618                             (icmp6_neighbor_solicitation_header_t, neighbor));
2619     p.ip.protocol = IP_PROTOCOL_ICMP6;
2620     p.ip.hop_limit = 255;
2621     ip6_set_solicited_node_multicast_address (&p.ip.dst_address, 0);
2622
2623     p.neighbor.icmp.type = ICMP6_neighbor_solicitation;
2624
2625     p.link_layer_option.header.type =
2626       ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
2627     p.link_layer_option.header.n_data_u64s =
2628       sizeof (p.link_layer_option) / sizeof (u64);
2629
2630     vlib_packet_template_init (vm,
2631                                &im->discover_neighbor_packet_template,
2632                                &p, sizeof (p),
2633                                /* alloc chunk size */ 8,
2634                                "ip6 neighbor discovery");
2635   }
2636
2637   return error;
2638 }
2639
2640 VLIB_INIT_FUNCTION (ip6_lookup_init);
2641
2642 void
2643 ip6_link_local_address_from_ethernet_mac_address (ip6_address_t * ip,
2644                                                   u8 * mac)
2645 {
2646   ip->as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL);
2647   /* Invert the "u" bit */
2648   ip->as_u8[8] = mac[0] ^ (1 << 1);
2649   ip->as_u8[9] = mac[1];
2650   ip->as_u8[10] = mac[2];
2651   ip->as_u8[11] = 0xFF;
2652   ip->as_u8[12] = 0xFE;
2653   ip->as_u8[13] = mac[3];
2654   ip->as_u8[14] = mac[4];
2655   ip->as_u8[15] = mac[5];
2656 }
2657
2658 void
2659 ip6_ethernet_mac_address_from_link_local_address (u8 * mac,
2660                                                   ip6_address_t * ip)
2661 {
2662   /* Invert the previously inverted "u" bit */
2663   mac[0] = ip->as_u8[8] ^ (1 << 1);
2664   mac[1] = ip->as_u8[9];
2665   mac[2] = ip->as_u8[10];
2666   mac[3] = ip->as_u8[13];
2667   mac[4] = ip->as_u8[14];
2668   mac[5] = ip->as_u8[15];
2669 }
2670
2671 static clib_error_t *
2672 test_ip6_link_command_fn (vlib_main_t * vm,
2673                           unformat_input_t * input, vlib_cli_command_t * cmd)
2674 {
2675   u8 mac[6];
2676   ip6_address_t _a, *a = &_a;
2677
2678   if (unformat (input, "%U", unformat_ethernet_address, mac))
2679     {
2680       ip6_link_local_address_from_ethernet_mac_address (a, mac);
2681       vlib_cli_output (vm, "Link local address: %U", format_ip6_address, a);
2682       ip6_ethernet_mac_address_from_link_local_address (mac, a);
2683       vlib_cli_output (vm, "Original MAC address: %U",
2684                        format_ethernet_address, mac);
2685     }
2686
2687   return 0;
2688 }
2689
2690 /*?
2691  * This command converts the given MAC Address into an IPv6 link-local
2692  * address.
2693  *
2694  * @cliexpar
2695  * Example of how to create an IPv6 link-local address:
2696  * @cliexstart{test ip6 link 16:d9:e0:91:79:86}
2697  * Link local address: fe80::14d9:e0ff:fe91:7986
2698  * Original MAC address: 16:d9:e0:91:79:86
2699  * @cliexend
2700 ?*/
2701 /* *INDENT-OFF* */
2702 VLIB_CLI_COMMAND (test_link_command, static) =
2703 {
2704   .path = "test ip6 link",
2705   .function = test_ip6_link_command_fn,
2706   .short_help = "test ip6 link <mac-address>",
2707 };
2708 /* *INDENT-ON* */
2709
2710 int
2711 vnet_set_ip6_flow_hash (u32 table_id, u32 flow_hash_config)
2712 {
2713   u32 fib_index;
2714
2715   fib_index = fib_table_find (FIB_PROTOCOL_IP6, table_id);
2716
2717   if (~0 == fib_index)
2718     return VNET_API_ERROR_NO_SUCH_FIB;
2719
2720   fib_table_set_flow_hash_config (fib_index, FIB_PROTOCOL_IP6,
2721                                   flow_hash_config);
2722
2723   return 0;
2724 }
2725
2726 static clib_error_t *
2727 set_ip6_flow_hash_command_fn (vlib_main_t * vm,
2728                               unformat_input_t * input,
2729                               vlib_cli_command_t * cmd)
2730 {
2731   int matched = 0;
2732   u32 table_id = 0;
2733   u32 flow_hash_config = 0;
2734   int rv;
2735
2736   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2737     {
2738       if (unformat (input, "table %d", &table_id))
2739         matched = 1;
2740 #define _(a,v) \
2741     else if (unformat (input, #a)) { flow_hash_config |= v; matched=1;}
2742       foreach_flow_hash_bit
2743 #undef _
2744         else
2745         break;
2746     }
2747
2748   if (matched == 0)
2749     return clib_error_return (0, "unknown input `%U'",
2750                               format_unformat_error, input);
2751
2752   rv = vnet_set_ip6_flow_hash (table_id, flow_hash_config);
2753   switch (rv)
2754     {
2755     case 0:
2756       break;
2757
2758     case -1:
2759       return clib_error_return (0, "no such FIB table %d", table_id);
2760
2761     default:
2762       clib_warning ("BUG: illegal flow hash config 0x%x", flow_hash_config);
2763       break;
2764     }
2765
2766   return 0;
2767 }
2768
2769 /*?
2770  * Configure the set of IPv6 fields used by the flow hash.
2771  *
2772  * @cliexpar
2773  * @parblock
2774  * Example of how to set the flow hash on a given table:
2775  * @cliexcmd{set ip6 flow-hash table 8 dst sport dport proto}
2776  *
2777  * Example of display the configured flow hash:
2778  * @cliexstart{show ip6 fib}
2779  * ipv6-VRF:0, fib_index 0, flow hash: src dst sport dport proto
2780  * @::/0
2781  *   unicast-ip6-chain
2782  *   [@0]: dpo-load-balance: [index:5 buckets:1 uRPF:5 to:[0:0]]
2783  *     [0] [@0]: dpo-drop ip6
2784  * fe80::/10
2785  *   unicast-ip6-chain
2786  *   [@0]: dpo-load-balance: [index:10 buckets:1 uRPF:10 to:[0:0]]
2787  *     [0] [@2]: dpo-receive
2788  * ff02::1/128
2789  *   unicast-ip6-chain
2790  *   [@0]: dpo-load-balance: [index:8 buckets:1 uRPF:8 to:[0:0]]
2791  *     [0] [@2]: dpo-receive
2792  * ff02::2/128
2793  *   unicast-ip6-chain
2794  *   [@0]: dpo-load-balance: [index:7 buckets:1 uRPF:7 to:[0:0]]
2795  *     [0] [@2]: dpo-receive
2796  * ff02::16/128
2797  *   unicast-ip6-chain
2798  *   [@0]: dpo-load-balance: [index:9 buckets:1 uRPF:9 to:[0:0]]
2799  *     [0] [@2]: dpo-receive
2800  * ff02::1:ff00:0/104
2801  *   unicast-ip6-chain
2802  *   [@0]: dpo-load-balance: [index:6 buckets:1 uRPF:6 to:[0:0]]
2803  *     [0] [@2]: dpo-receive
2804  * ipv6-VRF:8, fib_index 1, flow hash: dst sport dport proto
2805  * @::/0
2806  *   unicast-ip6-chain
2807  *   [@0]: dpo-load-balance: [index:21 buckets:1 uRPF:20 to:[0:0]]
2808  *     [0] [@0]: dpo-drop ip6
2809  * @::a:1:1:0:4/126
2810  *   unicast-ip6-chain
2811  *   [@0]: dpo-load-balance: [index:27 buckets:1 uRPF:26 to:[0:0]]
2812  *     [0] [@4]: ipv6-glean: af_packet0
2813  * @::a:1:1:0:7/128
2814  *   unicast-ip6-chain
2815  *   [@0]: dpo-load-balance: [index:28 buckets:1 uRPF:27 to:[0:0]]
2816  *     [0] [@2]: dpo-receive: @::a:1:1:0:7 on af_packet0
2817  * fe80::/10
2818  *   unicast-ip6-chain
2819  *   [@0]: dpo-load-balance: [index:26 buckets:1 uRPF:25 to:[0:0]]
2820  *     [0] [@2]: dpo-receive
2821  * fe80::fe:3eff:fe3e:9222/128
2822  *   unicast-ip6-chain
2823  *   [@0]: dpo-load-balance: [index:29 buckets:1 uRPF:28 to:[0:0]]
2824  *     [0] [@2]: dpo-receive: fe80::fe:3eff:fe3e:9222 on af_packet0
2825  * ff02::1/128
2826  *   unicast-ip6-chain
2827  *   [@0]: dpo-load-balance: [index:24 buckets:1 uRPF:23 to:[0:0]]
2828  *     [0] [@2]: dpo-receive
2829  * ff02::2/128
2830  *   unicast-ip6-chain
2831  *   [@0]: dpo-load-balance: [index:23 buckets:1 uRPF:22 to:[0:0]]
2832  *     [0] [@2]: dpo-receive
2833  * ff02::16/128
2834  *   unicast-ip6-chain
2835  *   [@0]: dpo-load-balance: [index:25 buckets:1 uRPF:24 to:[0:0]]
2836  *     [0] [@2]: dpo-receive
2837  * ff02::1:ff00:0/104
2838  *   unicast-ip6-chain
2839  *   [@0]: dpo-load-balance: [index:22 buckets:1 uRPF:21 to:[0:0]]
2840  *     [0] [@2]: dpo-receive
2841  * @cliexend
2842  * @endparblock
2843 ?*/
2844 /* *INDENT-OFF* */
2845 VLIB_CLI_COMMAND (set_ip6_flow_hash_command, static) =
2846 {
2847   .path = "set ip6 flow-hash",
2848   .short_help =
2849   "set ip6 flow-hash table <table-id> [src] [dst] [sport] [dport] [proto] [reverse]",
2850   .function = set_ip6_flow_hash_command_fn,
2851 };
2852 /* *INDENT-ON* */
2853
2854 static clib_error_t *
2855 show_ip6_local_command_fn (vlib_main_t * vm,
2856                            unformat_input_t * input, vlib_cli_command_t * cmd)
2857 {
2858   ip6_main_t *im = &ip6_main;
2859   ip_lookup_main_t *lm = &im->lookup_main;
2860   int i;
2861
2862   vlib_cli_output (vm, "Protocols handled by ip6_local");
2863   for (i = 0; i < ARRAY_LEN (lm->local_next_by_ip_protocol); i++)
2864     {
2865       if (lm->local_next_by_ip_protocol[i] != IP_LOCAL_NEXT_PUNT)
2866         {
2867
2868           u32 node_index = vlib_get_node (vm,
2869                                           ip6_local_node.index)->
2870             next_nodes[lm->local_next_by_ip_protocol[i]];
2871           vlib_cli_output (vm, "%d: %U", i, format_vlib_node_name, vm,
2872                            node_index);
2873         }
2874     }
2875   return 0;
2876 }
2877
2878
2879
2880 /*?
2881  * Display the set of protocols handled by the local IPv6 stack.
2882  *
2883  * @cliexpar
2884  * Example of how to display local protocol table:
2885  * @cliexstart{show ip6 local}
2886  * Protocols handled by ip6_local
2887  * 17
2888  * 43
2889  * 58
2890  * 115
2891  * @cliexend
2892 ?*/
2893 /* *INDENT-OFF* */
2894 VLIB_CLI_COMMAND (show_ip6_local, static) =
2895 {
2896   .path = "show ip6 local",
2897   .function = show_ip6_local_command_fn,
2898   .short_help = "show ip6 local",
2899 };
2900 /* *INDENT-ON* */
2901
2902 int
2903 vnet_set_ip6_classify_intfc (vlib_main_t * vm, u32 sw_if_index,
2904                              u32 table_index)
2905 {
2906   vnet_main_t *vnm = vnet_get_main ();
2907   vnet_interface_main_t *im = &vnm->interface_main;
2908   ip6_main_t *ipm = &ip6_main;
2909   ip_lookup_main_t *lm = &ipm->lookup_main;
2910   vnet_classify_main_t *cm = &vnet_classify_main;
2911   ip6_address_t *if_addr;
2912
2913   if (pool_is_free_index (im->sw_interfaces, sw_if_index))
2914     return VNET_API_ERROR_NO_MATCHING_INTERFACE;
2915
2916   if (table_index != ~0 && pool_is_free_index (cm->tables, table_index))
2917     return VNET_API_ERROR_NO_SUCH_ENTRY;
2918
2919   vec_validate (lm->classify_table_index_by_sw_if_index, sw_if_index);
2920   lm->classify_table_index_by_sw_if_index[sw_if_index] = table_index;
2921
2922   if_addr = ip6_interface_first_address (ipm, sw_if_index);
2923
2924   if (NULL != if_addr)
2925     {
2926       fib_prefix_t pfx = {
2927         .fp_len = 128,
2928         .fp_proto = FIB_PROTOCOL_IP6,
2929         .fp_addr.ip6 = *if_addr,
2930       };
2931       u32 fib_index;
2932
2933       fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2934                                                        sw_if_index);
2935
2936
2937       if (table_index != (u32) ~ 0)
2938         {
2939           dpo_id_t dpo = DPO_INVALID;
2940
2941           dpo_set (&dpo,
2942                    DPO_CLASSIFY,
2943                    DPO_PROTO_IP6,
2944                    classify_dpo_create (DPO_PROTO_IP6, table_index));
2945
2946           fib_table_entry_special_dpo_add (fib_index,
2947                                            &pfx,
2948                                            FIB_SOURCE_CLASSIFY,
2949                                            FIB_ENTRY_FLAG_NONE, &dpo);
2950           dpo_reset (&dpo);
2951         }
2952       else
2953         {
2954           fib_table_entry_special_remove (fib_index,
2955                                           &pfx, FIB_SOURCE_CLASSIFY);
2956         }
2957     }
2958
2959   return 0;
2960 }
2961
2962 static clib_error_t *
2963 set_ip6_classify_command_fn (vlib_main_t * vm,
2964                              unformat_input_t * input,
2965                              vlib_cli_command_t * cmd)
2966 {
2967   u32 table_index = ~0;
2968   int table_index_set = 0;
2969   u32 sw_if_index = ~0;
2970   int rv;
2971
2972   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2973     {
2974       if (unformat (input, "table-index %d", &table_index))
2975         table_index_set = 1;
2976       else if (unformat (input, "intfc %U", unformat_vnet_sw_interface,
2977                          vnet_get_main (), &sw_if_index))
2978         ;
2979       else
2980         break;
2981     }
2982
2983   if (table_index_set == 0)
2984     return clib_error_return (0, "classify table-index must be specified");
2985
2986   if (sw_if_index == ~0)
2987     return clib_error_return (0, "interface / subif must be specified");
2988
2989   rv = vnet_set_ip6_classify_intfc (vm, sw_if_index, table_index);
2990
2991   switch (rv)
2992     {
2993     case 0:
2994       break;
2995
2996     case VNET_API_ERROR_NO_MATCHING_INTERFACE:
2997       return clib_error_return (0, "No such interface");
2998
2999     case VNET_API_ERROR_NO_SUCH_ENTRY:
3000       return clib_error_return (0, "No such classifier table");
3001     }
3002   return 0;
3003 }
3004
3005 /*?
3006  * Assign a classification table to an interface. The classification
3007  * table is created using the '<em>classify table</em>' and '<em>classify session</em>'
3008  * commands. Once the table is create, use this command to filter packets
3009  * on an interface.
3010  *
3011  * @cliexpar
3012  * Example of how to assign a classification table to an interface:
3013  * @cliexcmd{set ip6 classify intfc GigabitEthernet2/0/0 table-index 1}
3014 ?*/
3015 /* *INDENT-OFF* */
3016 VLIB_CLI_COMMAND (set_ip6_classify_command, static) =
3017 {
3018   .path = "set ip6 classify",
3019   .short_help =
3020   "set ip6 classify intfc <interface> table-index <classify-idx>",
3021   .function = set_ip6_classify_command_fn,
3022 };
3023 /* *INDENT-ON* */
3024
3025 static clib_error_t *
3026 ip6_config (vlib_main_t * vm, unformat_input_t * input)
3027 {
3028   ip6_main_t *im = &ip6_main;
3029   uword heapsize = 0;
3030   u32 tmp;
3031   u32 nbuckets = 0;
3032
3033   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3034     {
3035       if (unformat (input, "hash-buckets %d", &tmp))
3036         nbuckets = tmp;
3037       else if (unformat (input, "heap-size %U",
3038                          unformat_memory_size, &heapsize))
3039         ;
3040       else
3041         return clib_error_return (0, "unknown input '%U'",
3042                                   format_unformat_error, input);
3043     }
3044
3045   im->lookup_table_nbuckets = nbuckets;
3046   im->lookup_table_size = heapsize;
3047
3048   return 0;
3049 }
3050
3051 VLIB_EARLY_CONFIG_FUNCTION (ip6_config, "ip6");
3052
3053 /*
3054  * fd.io coding-style-patch-verification: ON
3055  *
3056  * Local Variables:
3057  * eval: (c-set-style "gnu")
3058  * End:
3059  */