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