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