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