Initial commit of vpp code.
[vpp.git] / vnet / vnet / ip / ip6_neighbor.c
1 /*
2  * ip/ip6_neighbor.c: IP6 neighbor handling
3  *
4  * Copyright (c) 2010 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include <vnet/ip/ip.h>
19 #include <vnet/ethernet/ethernet.h>
20 #include <vppinfra/mhash.h>
21 #include <vppinfra/md5.h>
22
23 #if DPDK==1
24 #include <vnet/devices/dpdk/dpdk.h>
25 #endif
26
27 typedef struct {
28   ip6_address_t ip6_address;
29   u32 sw_if_index;
30   u32 pad;
31 } ip6_neighbor_key_t;
32
33 /* can't use sizeof link_layer_address, that's 8 */ 
34 #define ETHER_MAC_ADDR_LEN 6
35
36 typedef struct {
37   ip6_neighbor_key_t key;
38   u8 link_layer_address[8];
39   u64 cpu_time_last_updated;
40 } ip6_neighbor_t;
41
42 /* advertised prefix option */ 
43 typedef struct {
44   /* basic advertised information */
45   ip6_address_t prefix;
46   u8 prefix_len;
47   int adv_on_link_flag;
48   int adv_autonomous_flag;
49   u32 adv_valid_lifetime_in_secs;
50   u32 adv_pref_lifetime_in_secs;
51
52   /* advertised values are computed from these times if decrementing */
53   f64 valid_lifetime_expires;
54   f64  pref_lifetime_expires;
55  
56   /* local information */
57   int enabled;
58   int deprecated_prefix_flag;
59   int decrement_lifetime_flag; 
60
61 #define MIN_ADV_VALID_LIFETIME 7203     /* seconds */
62 #define DEF_ADV_VALID_LIFETIME  2592000
63 #define DEF_ADV_PREF_LIFETIME 604800
64
65   /* extensions are added here, mobile, DNS etc.. */
66 } ip6_radv_prefix_t;
67
68
69 typedef struct {
70   /* group information */
71   u8 type;
72   ip6_address_t mcast_address;
73   u16 num_sources;
74   ip6_address_t *mcast_source_address_pool;
75 } ip6_mldp_group_t;
76
77 /* configured router advertisement information per ipv6 interface */
78 typedef struct {
79
80   /* advertised config information, zero means unspecified  */
81   u8  curr_hop_limit;
82   int adv_managed_flag;
83   int adv_other_flag;
84   u16 adv_router_lifetime_in_sec; 
85   u32 adv_neighbor_reachable_time_in_msec;
86   u32 adv_time_in_msec_between_retransmitted_neighbor_solicitations;
87
88   /* mtu option */
89   u32 adv_link_mtu;
90   
91   /* source link layer option */
92   u8  link_layer_address[8];
93   u8  link_layer_addr_len;
94
95   /* prefix option */
96   ip6_radv_prefix_t * adv_prefixes_pool;
97
98   /* Hash table mapping address to index in interface advertised  prefix pool. */
99   mhash_t address_to_prefix_index;
100
101   /* MLDP  group information */
102   ip6_mldp_group_t  * mldp_group_pool;
103
104   /* Hash table mapping address to index in mldp address pool. */
105   mhash_t address_to_mldp_index;
106
107   /* local information */
108   u32 sw_if_index;
109   u32 fib_index;
110   int send_radv;              /* radv on/off on this interface -  set by config */
111   int cease_radv;           /* we are ceasing  to send  - set byf config */
112   int send_unicast;
113   int adv_link_layer_address;
114   int prefix_option;
115   int failed_device_check;
116   int all_routers_mcast;
117   u32 seed;
118   u64 randomizer;
119   int ref_count;
120   u32 all_nodes_adj_index;
121   u32 all_routers_adj_index;
122   u32 all_mldv2_routers_adj_index;
123   
124   /* timing information */
125 #define DEF_MAX_RADV_INTERVAL 200
126 #define DEF_MIN_RADV_INTERVAL .75 * DEF_MAX_RADV_INTERVAL
127 #define DEF_CURR_HOP_LIMIT  64
128 #define DEF_DEF_RTR_LIFETIME   3 * DEF_MAX_RADV_INTERVAL
129 #define MAX_DEF_RTR_LIFETIME   9000
130
131 #define MAX_INITIAL_RTR_ADVERT_INTERVAL   16  /* seconds */
132 #define MAX_INITIAL_RTR_ADVERTISEMENTS        3    /*transmissions */
133 #define MIN_DELAY_BETWEEN_RAS                              3  /* seconds */
134 #define MAX_DELAY_BETWEEN_RAS                    1800  /* seconds */
135 #define MAX_RA_DELAY_TIME                                          .5 /* seconds */
136
137   f64 max_radv_interval;
138   f64 min_radv_interval;
139   f64 min_delay_between_radv;
140   f64 max_delay_between_radv;
141   f64 max_rtr_default_lifetime;
142
143   f64 last_radv_time;
144   f64 last_multicast_time;
145   f64 next_multicast_time;
146
147
148   u32 initial_adverts_count;
149   f64 initial_adverts_interval; 
150   u32 initial_adverts_sent;
151
152   /* stats */
153   u32 n_advertisements_sent;
154   u32 n_solicitations_rcvd;
155   u32 n_solicitations_dropped;
156
157   /* Link local address to use (defaults to underlying physical for logical interfaces */
158   ip6_address_t link_local_address;
159   u8 link_local_prefix_len;
160
161 } ip6_radv_t;
162
163 typedef struct {
164   u32 next_index;
165   uword node_index;
166   uword type_opaque;
167   uword data;
168 } pending_resolution_t;
169
170
171 typedef struct {
172   /* Hash tables mapping name to opcode. */
173   uword * opcode_by_name;
174
175   /* lite beer "glean" adjacency handling */
176   mhash_t pending_resolutions_by_address;
177   pending_resolution_t * pending_resolutions;
178
179   u32 * neighbor_input_next_index_by_hw_if_index;
180
181   ip6_neighbor_t * neighbor_pool;
182
183   mhash_t neighbor_index_by_key;
184
185   u32 * if_radv_pool_index_by_sw_if_index;
186
187   ip6_radv_t * if_radv_pool;
188
189   /* Neighbor attack mitigation */
190   u32 limit_neighbor_cache_size;
191   u32 neighbor_delete_rotor;
192
193 } ip6_neighbor_main_t;
194
195 static ip6_neighbor_main_t ip6_neighbor_main;
196
197 static u8 * format_ip6_neighbor_ip6_entry (u8 * s, va_list * va)
198 {
199   vlib_main_t * vm = va_arg (*va, vlib_main_t *);
200   ip6_neighbor_t * n = va_arg (*va, ip6_neighbor_t *);
201   vnet_main_t * vnm = vnet_get_main();
202   vnet_sw_interface_t * si;
203
204   if (! n)
205     return format (s, "%=12s%=20s%=20s%=40s", "Time", "Address", "Link layer", "Interface");
206
207   si = vnet_get_sw_interface (vnm, n->key.sw_if_index);
208   s = format (s, "%=12U%=20U%=20U%=40U",
209               format_vlib_cpu_time, vm, n->cpu_time_last_updated,
210               format_ip6_address, &n->key.ip6_address,
211               format_ethernet_address, n->link_layer_address,
212               format_vnet_sw_interface_name, vnm, si);
213
214   return s;
215 }
216
217 static clib_error_t *
218 ip6_neighbor_sw_interface_up_down (vnet_main_t * vnm,
219                                    u32 sw_if_index,
220                                    u32 flags)
221 {
222   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
223   ip6_neighbor_t * n;
224  
225   if (! (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
226     {
227       u32 i, * to_delete = 0;
228
229       pool_foreach (n, nm->neighbor_pool, ({
230         if (n->key.sw_if_index == sw_if_index)
231           vec_add1 (to_delete, n - nm->neighbor_pool);
232       }));
233
234       for (i = 0; i < vec_len (to_delete); i++)
235         {
236           n = pool_elt_at_index (nm->neighbor_pool, to_delete[i]);
237           mhash_unset (&nm->neighbor_index_by_key, &n->key, 0);
238           pool_put (nm->neighbor_pool, n);
239         }
240
241       vec_free (to_delete);
242     }
243
244   return 0;
245 }
246
247 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_neighbor_sw_interface_up_down);
248
249 static void unset_random_neighbor_entry (void)
250 {
251   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
252   vnet_main_t * vnm = vnet_get_main();
253   vlib_main_t * vm = vnm->vlib_main;
254   ip6_neighbor_t * e;
255   u32 index;
256
257   index = pool_next_index (nm->neighbor_pool, nm->neighbor_delete_rotor);
258   nm->neighbor_delete_rotor = index;
259
260   /* Try again from elt 0, could happen if an intfc goes down */
261   if (index == ~0)
262     {
263       index = pool_next_index (nm->neighbor_pool, nm->neighbor_delete_rotor);
264       nm->neighbor_delete_rotor = index;
265     }
266
267   /* Nothing left in the pool */
268   if (index == ~0)
269     return;
270
271   e = pool_elt_at_index (nm->neighbor_pool, index);
272   
273   vnet_unset_ip6_ethernet_neighbor (vm, e->key.sw_if_index,
274                                     &e->key.ip6_address, 
275                                     e->link_layer_address,
276                                     ETHER_MAC_ADDR_LEN);
277 }
278
279 typedef struct {
280   u8 is_add;
281   u8 pad;
282   u8 link_layer_address[6];
283   u32 sw_if_index;
284   ip6_address_t addr;
285 } ip6_neighbor_set_unset_rpc_args_t;
286
287 static void ip6_neighbor_set_unset_rpc_callback 
288 ( ip6_neighbor_set_unset_rpc_args_t * a);
289
290 #if DPDK > 0
291 static void set_unset_ip6_neighbor_rpc 
292 (vlib_main_t * vm,
293  u32 sw_if_index,
294  ip6_address_t * a,
295  u8 *link_layer_addreess,
296  int is_add)
297 {
298   ip6_neighbor_set_unset_rpc_args_t args;
299   
300   args.sw_if_index = sw_if_index;
301   args.is_add = is_add;
302   memcpy (&args.addr, a, sizeof (*a));
303   memcpy (args.link_layer_address, link_layer_addreess, 6);
304   
305   vl_api_rpc_call_main_thread (ip6_neighbor_set_unset_rpc_callback,
306                                (u8 *) &args, sizeof (args));
307 }
308 #endif
309
310 int
311 vnet_set_ip6_ethernet_neighbor (vlib_main_t * vm,
312                                 u32 sw_if_index,
313                                 ip6_address_t * a,
314                                 u8 * link_layer_address,
315                                 uword n_bytes_link_layer_address)
316 {
317   vnet_main_t * vnm = vnet_get_main();
318   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
319   ip6_neighbor_key_t k;
320   ip6_neighbor_t * n;
321   ip6_main_t * im = &ip6_main;
322   uword * p;
323   u32 next_index;
324   pending_resolution_t * pr;
325
326 #if DPDK > 0
327   if (os_get_cpu_number())
328     {
329       set_unset_ip6_neighbor_rpc (vm, sw_if_index, a, link_layer_address,
330                                   1 /* set new neighbor */);
331       return 0;
332     }
333 #endif
334
335   k.sw_if_index = sw_if_index;
336   k.ip6_address = a[0];
337   k.pad = 0;
338
339   vlib_worker_thread_barrier_sync (vm);
340
341   p = mhash_get (&nm->neighbor_index_by_key, &k);
342   if (p)
343     n = pool_elt_at_index (nm->neighbor_pool, p[0]);
344   else
345     {
346       ip6_add_del_route_args_t args;
347       ip_adjacency_t adj;
348
349       memset (&adj, 0, sizeof(adj));
350       adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
351       adj.explicit_fib_index = ~0;
352
353       vnet_rewrite_for_sw_interface
354         (vnm,
355          VNET_L3_PACKET_TYPE_IP6,
356          sw_if_index,
357          ip6_rewrite_node.index,
358          link_layer_address,
359          &adj.rewrite_header,
360          sizeof (adj.rewrite_data));
361
362       args.table_index_or_table_id = im->fib_index_by_sw_if_index[sw_if_index];
363       args.flags = IP6_ROUTE_FLAG_FIB_INDEX | IP6_ROUTE_FLAG_ADD | IP6_ROUTE_FLAG_NEIGHBOR;
364       args.dst_address = a[0];
365       args.dst_address_length = 128;
366       args.adj_index = ~0;
367       args.add_adj = &adj;
368       args.n_add_adj = 1;
369
370       ip6_add_del_route (im, &args);
371       pool_get (nm->neighbor_pool, n);
372       mhash_set (&nm->neighbor_index_by_key, &k, n - nm->neighbor_pool,
373                  /* old value */ 0);
374       n->key = k;
375     }
376
377   /* Update time stamp and ethernet address. */
378   memcpy (n->link_layer_address, link_layer_address, n_bytes_link_layer_address);
379   n->cpu_time_last_updated = clib_cpu_time_now ();
380
381   /* Customer(s) waiting for this address to be resolved? */
382   p = mhash_get (&nm->pending_resolutions_by_address, a);
383   if (p == 0)
384       goto out;
385   
386   next_index = p[0];
387   
388   while (next_index != (u32)~0)
389     {
390       pr = pool_elt_at_index (nm->pending_resolutions, next_index);
391       vlib_process_signal_event (vm, pr->node_index,
392                                  pr->type_opaque, 
393                                  pr->data);
394       next_index = pr->next_index;
395       pool_put (nm->pending_resolutions, pr);
396     }
397
398   mhash_unset (&nm->pending_resolutions_by_address, a, 0);
399   
400 out:
401   vlib_worker_thread_barrier_release(vm);
402   return 0;
403 }
404
405 int
406 vnet_unset_ip6_ethernet_neighbor (vlib_main_t * vm,
407                                   u32 sw_if_index,
408                                   ip6_address_t * a,
409                                   u8 * link_layer_address,
410                                   uword n_bytes_link_layer_address)
411 {
412   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
413   ip6_neighbor_key_t k;
414   ip6_neighbor_t * n;
415   ip6_main_t * im = &ip6_main;
416   ip6_add_del_route_args_t args;
417   uword * p;
418   int rv = 0;
419
420 #if DPDK > 0
421   if (os_get_cpu_number())
422     {
423       set_unset_ip6_neighbor_rpc (vm, sw_if_index, a, link_layer_address,
424                                   0 /* unset */);
425       return 0;
426     }
427 #endif
428
429   k.sw_if_index = sw_if_index;
430   k.ip6_address = a[0];
431   k.pad = 0;
432   
433   vlib_worker_thread_barrier_sync (vm);
434   
435   p = mhash_get (&nm->neighbor_index_by_key, &k);
436   if (p == 0)
437     {
438       rv = -1;
439       goto out;
440     }
441   
442   n = pool_elt_at_index (nm->neighbor_pool, p[0]);
443   mhash_unset (&nm->neighbor_index_by_key, &n->key, 0);
444   pool_put (nm->neighbor_pool, n);
445   
446   args.table_index_or_table_id = im->fib_index_by_sw_if_index[sw_if_index];
447   args.flags = IP6_ROUTE_FLAG_FIB_INDEX | IP6_ROUTE_FLAG_DEL 
448     | IP6_ROUTE_FLAG_NEIGHBOR;
449   args.dst_address = a[0];
450   args.dst_address_length = 128;
451   args.adj_index = ~0;
452   args.add_adj = NULL;
453   args.n_add_adj = 0;
454   ip6_add_del_route (im, &args);
455  out:
456   vlib_worker_thread_barrier_release(vm);
457   return rv;
458 }
459
460 static void ip6_neighbor_set_unset_rpc_callback 
461 ( ip6_neighbor_set_unset_rpc_args_t * a)
462 {
463   vlib_main_t * vm = vlib_get_main();
464   if (a->is_add) 
465       vnet_set_ip6_ethernet_neighbor (vm, a->sw_if_index, &a->addr, 
466                                       a->link_layer_address, 6);
467   else
468     vnet_unset_ip6_ethernet_neighbor (vm, a->sw_if_index, &a->addr, 
469                                       a->link_layer_address, 6);
470 }
471
472 static int
473 ip6_neighbor_sort (void *a1, void *a2)
474 {
475   vnet_main_t * vnm = vnet_get_main();
476   ip6_neighbor_t * n1 = a1, * n2 = a2;
477   int cmp;
478   cmp = vnet_sw_interface_compare (vnm, n1->key.sw_if_index, 
479                                    n2->key.sw_if_index);
480   if (! cmp)
481     cmp = ip6_address_compare (&n1->key.ip6_address, &n2->key.ip6_address);
482   return cmp;
483 }
484
485 static clib_error_t *
486 show_ip6_neighbors (vlib_main_t * vm,
487                     unformat_input_t * input,
488                     vlib_cli_command_t * cmd)
489 {
490   vnet_main_t * vnm = vnet_get_main();
491   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
492   ip6_neighbor_t * n, * ns;
493   clib_error_t * error = 0;
494   u32 sw_if_index;
495
496   /* Filter entries by interface if given. */
497   sw_if_index = ~0;
498   (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index);
499
500   ns = 0;
501   pool_foreach (n, nm->neighbor_pool, ({ vec_add1 (ns, n[0]); }));
502   vec_sort_with_function (ns, ip6_neighbor_sort);
503   vlib_cli_output (vm, "%U", format_ip6_neighbor_ip6_entry, vm, 0);
504   vec_foreach (n, ns) {
505     if (sw_if_index != ~0 && n->key.sw_if_index != sw_if_index)
506       continue;
507     vlib_cli_output (vm, "%U", format_ip6_neighbor_ip6_entry, vm, n);
508   }
509   vec_free (ns);
510
511   return error;
512 }
513
514 VLIB_CLI_COMMAND (show_ip6_neighbors_command, static) = {
515   .path = "show ip6 neighbors",
516   .function = show_ip6_neighbors,
517   .short_help = "Show ip6 neighbors",
518 };
519
520 static clib_error_t *
521 set_ip6_neighbor (vlib_main_t * vm,
522                   unformat_input_t * input,
523                   vlib_cli_command_t * cmd)
524 {
525   vnet_main_t * vnm = vnet_get_main();
526   ip6_address_t addr;
527   u8 mac_address[6];
528   int addr_valid = 0;
529   int is_del = 0;
530   u32 sw_if_index;
531
532   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) 
533     {
534       /* intfc, ip6-address, mac-address */
535       if (unformat (input, "%U %U %U",
536                     unformat_vnet_sw_interface, vnm, &sw_if_index,
537                     unformat_ip6_address, &addr, 
538                     unformat_ethernet_address, mac_address))
539         addr_valid = 1;
540
541       else if (unformat (input, "delete") || unformat (input, "del"))
542         is_del = 1;
543       else
544         break;
545     }
546
547   if (!addr_valid)
548     return clib_error_return (0, "Missing interface, ip6 or hw address");
549   
550   if (!is_del)
551     vnet_set_ip6_ethernet_neighbor (vm, sw_if_index, &addr,
552                                     mac_address, sizeof(mac_address));
553   else
554     vnet_unset_ip6_ethernet_neighbor (vm, sw_if_index, &addr,
555                                       mac_address, sizeof(mac_address));
556   return 0;
557 }
558
559 VLIB_CLI_COMMAND (set_ip6_neighbor_command, static) = {
560   .path = "set ip6 neighbor",
561   .function = set_ip6_neighbor,
562   .short_help = "set ip6 neighbor [del] <intfc> <ip6-address> <mac-address>",
563 };
564
565 typedef enum {
566   ICMP6_NEIGHBOR_SOLICITATION_NEXT_DROP,
567   ICMP6_NEIGHBOR_SOLICITATION_NEXT_REPLY,
568   ICMP6_NEIGHBOR_SOLICITATION_N_NEXT,
569 } icmp6_neighbor_solicitation_or_advertisement_next_t;
570
571 static_always_inline uword
572 icmp6_neighbor_solicitation_or_advertisement (vlib_main_t * vm,
573                                               vlib_node_runtime_t * node,
574                                               vlib_frame_t * frame,
575                                               uword is_solicitation)
576 {
577   vnet_main_t * vnm = vnet_get_main();
578   ip6_main_t * im = &ip6_main;
579   ip_lookup_main_t * lm = &im->lookup_main;
580   uword n_packets = frame->n_vectors;
581   u32 * from, * to_next;
582   u32 n_left_from, n_left_to_next, next_index, n_advertisements_sent;
583   icmp6_neighbor_discovery_option_type_t option_type;
584   vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip6_icmp_input_node.index);
585   int bogus_length;
586
587   from = vlib_frame_vector_args (frame);
588   n_left_from = n_packets;
589   next_index = node->cached_next_index;
590   
591   if (node->flags & VLIB_NODE_FLAG_TRACE)
592     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
593                                    /* stride */ 1,
594                                    sizeof (icmp6_input_trace_t));
595
596   option_type = 
597     (is_solicitation
598      ? ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address
599      : ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address);
600   n_advertisements_sent = 0;
601
602   while (n_left_from > 0)
603     {
604       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
605
606       while (n_left_from > 0 && n_left_to_next > 0)
607         {
608           vlib_buffer_t * p0;
609           ip6_header_t * ip0;
610           icmp6_neighbor_solicitation_or_advertisement_header_t * h0;
611           icmp6_neighbor_discovery_ethernet_link_layer_address_option_t * o0;
612           u32 bi0, options_len0, sw_if_index0, next0, error0;
613           u32 ip6_sadd_link_local, ip6_sadd_unspecified;
614           int is_rewrite0;
615           u32 ni0;
616       
617           bi0 = to_next[0] = from[0];
618
619           from += 1;
620           to_next += 1;
621           n_left_from -= 1;
622           n_left_to_next -= 1;
623       
624           p0 = vlib_get_buffer (vm, bi0);
625           ip0 = vlib_buffer_get_current (p0);
626           h0 = ip6_next_header (ip0);
627           options_len0 = clib_net_to_host_u16 (ip0->payload_length) - sizeof (h0[0]);
628
629           error0 = ICMP6_ERROR_NONE;
630           sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
631           ip6_sadd_link_local = ip6_address_is_link_local_unicast(&ip0->src_address);
632           ip6_sadd_unspecified = ip6_address_is_unspecified (&ip0->src_address);
633
634           /* Check that source address is unspecified, link-local or else on-link. */
635           if (!ip6_sadd_unspecified && !ip6_sadd_link_local)
636             {
637               u32 src_adj_index0 = ip6_src_lookup_for_packet (im, p0, ip0);
638               ip_adjacency_t * adj0 = ip_get_adjacency (&im->lookup_main, src_adj_index0);
639
640               /* Allow all realistic-looking rewrite adjacencies to pass */
641               ni0 = adj0->lookup_next_index;
642               is_rewrite0 = (ni0 >= IP_LOOKUP_NEXT_ARP) &&
643                 (ni0 < IP_LOOKUP_N_NEXT);
644
645               error0 = ((adj0->rewrite_header.sw_if_index != sw_if_index0
646                          || ! is_rewrite0)
647                         ? ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_NOT_ON_LINK
648                         : error0);
649             }
650               
651           o0 = (void *) (h0 + 1);
652           o0 = ((options_len0 == 8 && o0->header.type == option_type
653                  && o0->header.n_data_u64s == 1) ? o0 : 0);
654
655           /* If src address unspecified or link local, donot learn neighbor MAC */
656           if (PREDICT_TRUE (error0 == ICMP6_ERROR_NONE && o0 != 0 && 
657                             !ip6_sadd_unspecified && !ip6_sadd_link_local)) 
658             { 
659               ip6_neighbor_main_t * nm = &ip6_neighbor_main;
660               if (nm->limit_neighbor_cache_size && 
661                   pool_elts (nm->neighbor_pool) >= nm->limit_neighbor_cache_size)
662                   unset_random_neighbor_entry();
663               vnet_set_ip6_ethernet_neighbor (
664                   vm, sw_if_index0,
665                   is_solicitation ? &ip0->src_address : &h0->target_address,
666                   o0->ethernet_address, sizeof (o0->ethernet_address));
667             }
668
669           if (is_solicitation && error0 == ICMP6_ERROR_NONE)
670             {
671               /* Check that target address is one that we know about. */
672               ip_interface_address_t * ia0;
673               ip6_address_fib_t ip6_af0;
674               void * oldheap;
675
676               ip6_addr_fib_init (&ip6_af0, &h0->target_address,
677                                  vec_elt (im->fib_index_by_sw_if_index,
678                                           sw_if_index0));
679
680               /* Gross kludge, "thank you" MJ, don't even ask */
681               oldheap = clib_mem_set_heap (clib_per_cpu_mheaps[0]);
682               ia0 = ip_get_interface_address (lm, &ip6_af0);
683               clib_mem_set_heap (oldheap);
684               error0 = ia0 == 0 ? 
685                   ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_UNKNOWN : error0;
686             }
687
688           if (is_solicitation)
689             next0 = (error0 != ICMP6_ERROR_NONE
690                      ? ICMP6_NEIGHBOR_SOLICITATION_NEXT_DROP
691                      : ICMP6_NEIGHBOR_SOLICITATION_NEXT_REPLY);
692           else
693             {
694               next0 = 0;
695               error0 = error0 == ICMP6_ERROR_NONE ? 
696                   ICMP6_ERROR_NEIGHBOR_ADVERTISEMENTS_RX : error0;
697             }
698
699           if (is_solicitation && error0 == ICMP6_ERROR_NONE)
700             {
701               vnet_sw_interface_t * sw_if0;
702               ethernet_interface_t * eth_if0;
703               ethernet_header_t *eth0;
704
705               /* dst address is either source address or the all-nodes mcast addr */                  
706               if(!ip6_sadd_unspecified)
707                   ip0->dst_address = ip0->src_address;
708               else
709                   ip6_set_reserved_multicast_address(&ip0->dst_address, 
710                                                      IP6_MULTICAST_SCOPE_link_local,
711                                                      IP6_MULTICAST_GROUP_ID_all_hosts);
712
713               ip0->src_address = h0->target_address;
714               ip0->hop_limit = 255;
715               h0->icmp.type = ICMP6_neighbor_advertisement;
716
717               sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
718               ASSERT (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
719               eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
720               if (eth_if0 && o0)
721                 {
722                   memcpy (o0->ethernet_address, eth_if0->address, 6);
723                   o0->header.type = 
724                       ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
725                 }
726
727               h0->advertisement_flags = clib_host_to_net_u32
728                 (ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED
729                  | ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE);
730
731               h0->icmp.checksum = 0;
732               h0->icmp.checksum = 
733                   ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0, 
734                                                      &bogus_length);
735               ASSERT(bogus_length == 0);
736
737               /* Reuse current MAC header, copy SMAC to DMAC and 
738                * interface MAC to SMAC */
739               vlib_buffer_reset (p0);
740               eth0 = vlib_buffer_get_current(p0);
741               memcpy(eth0->dst_address, eth0->src_address, 6);
742               memcpy(eth0->src_address, eth_if0->address, 6);
743
744               /* Setup input and output sw_if_index for packet */
745               ASSERT(vnet_buffer(p0)->sw_if_index[VLIB_RX] == sw_if_index0);
746               vnet_buffer(p0)->sw_if_index[VLIB_TX] = sw_if_index0;
747               vnet_buffer(p0)->sw_if_index[VLIB_RX] = 
748                   vnet_main.local_interface_sw_if_index;
749
750               n_advertisements_sent++;
751             }
752
753           p0->error = error_node->errors[error0];
754
755           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
756                                            to_next, n_left_to_next,
757                                            bi0, next0);
758         }
759
760       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
761     }
762
763   /* Account for advertisements sent. */
764   vlib_error_count (vm, error_node->node_index, ICMP6_ERROR_NEIGHBOR_ADVERTISEMENTS_TX, n_advertisements_sent);
765
766   return frame->n_vectors;
767 }
768
769 /* for "syslogging" - use elog for now */
770 #define foreach_log_level            \
771   _ (DEBUG, "DEBUG")                         \
772   _ (INFO, "INFORMATION")            \
773   _ (NOTICE, "NOTICE")               \
774   _ (WARNING, "WARNING")             \
775   _ (ERR, "ERROR")                                    \
776   _ (CRIT, "CRITICAL")                        \
777   _ (ALERT, "ALERT")                          \
778   _ (EMERG,  "EMERGENCY")
779
780 typedef enum {
781 #define _(f,s) LOG_##f,
782   foreach_log_level
783 #undef _
784 } log_level_t;
785
786 static char * log_level_strings[] = {
787 #define _(f,s) s,
788   foreach_log_level
789 #undef _
790 };
791
792 static  int logmask = 1 << LOG_DEBUG;
793
794 static void
795 ip6_neighbor_syslog(vlib_main_t *vm,  int priority,  char * fmt, ...)
796 {
797   /* just use elog for now */
798   u8 *what;
799   va_list va;
800
801   if( (priority > LOG_EMERG) ||
802       !(logmask & (1 << priority)))
803       return;
804
805   va_start (va, fmt);
806   if(fmt)
807     {
808       what = va_format (0, fmt, &va);
809
810       ELOG_TYPE_DECLARE (e) = {
811         .format = "ip6 nd:  (%s): %s",
812         .format_args = "T4T4",
813       };
814       struct { u32 s[2]; } * ed;
815       ed = ELOG_DATA (&vm->elog_main, e);
816       ed->s[0] = elog_string(&vm->elog_main,  log_level_strings[priority]);
817       ed->s[1] = elog_string(&vm->elog_main,  (char *)what);
818     }
819   va_end (va);
820   return;
821 }
822
823 /* ipv6 neighbor discovery - router advertisements */
824 typedef enum {
825   ICMP6_ROUTER_SOLICITATION_NEXT_DROP,
826   ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW,
827   ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX,
828   ICMP6_ROUTER_SOLICITATION_N_NEXT,
829 } icmp6_router_solicitation_or_advertisement_next_t;
830
831 static_always_inline uword
832 icmp6_router_solicitation(vlib_main_t * vm,
833                           vlib_node_runtime_t * node,
834                           vlib_frame_t * frame)
835 {
836   vnet_main_t * vnm = vnet_get_main();
837   ip6_main_t * im = &ip6_main;
838   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
839   uword n_packets = frame->n_vectors;
840   u32 * from, * to_next;
841   u32 n_left_from, n_left_to_next, next_index;
842   u32  n_advertisements_sent = 0;
843   int bogus_length;
844
845   icmp6_neighbor_discovery_option_type_t option_type;
846
847   vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip6_icmp_input_node.index);
848
849   from = vlib_frame_vector_args (frame);
850   n_left_from = n_packets;
851   next_index = node->cached_next_index;
852   
853   if (node->flags & VLIB_NODE_FLAG_TRACE)
854     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
855                                    /* stride */ 1,
856                                    sizeof (icmp6_input_trace_t));
857
858   /* source may append his LL address */
859   option_type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
860
861   while (n_left_from > 0)
862     {
863       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
864       
865       while (n_left_from > 0 && n_left_to_next > 0)
866         {
867           vlib_buffer_t * p0;
868           ip6_header_t * ip0;
869           ip6_radv_t *radv_info = 0;
870
871           icmp6_neighbor_discovery_header_t * h0;  
872           icmp6_neighbor_discovery_ethernet_link_layer_address_option_t * o0;
873           
874           u32 bi0, options_len0, sw_if_index0, next0, error0;
875           u32 is_solicitation = 1, is_dropped  = 0;
876           u32 is_unspecified, is_link_local;
877
878           bi0 = to_next[0] = from[0];
879
880           from += 1;
881           to_next += 1;
882           n_left_from -= 1;
883           n_left_to_next -= 1;
884       
885           p0 = vlib_get_buffer (vm, bi0);
886           ip0 = vlib_buffer_get_current (p0);
887           h0 = ip6_next_header (ip0);
888           options_len0 = clib_net_to_host_u16 (ip0->payload_length) - sizeof (h0[0]);
889           is_unspecified = ip6_address_is_unspecified (&ip0->src_address);
890           is_link_local = ip6_address_is_link_local_unicast (&ip0->src_address);
891
892           error0 = ICMP6_ERROR_NONE;
893           sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
894           
895           /* check if solicitation  (not from nd_timer node) */
896           if (ip6_address_is_unspecified (&ip0->dst_address))
897             is_solicitation = 0;
898
899           /* Check that source address is unspecified, link-local or else on-link. */
900           if (!is_unspecified && !is_link_local)
901             {
902               u32 src_adj_index0 = ip6_src_lookup_for_packet (im, p0, ip0);
903               ip_adjacency_t * adj0 = ip_get_adjacency (&im->lookup_main, src_adj_index0);
904
905               error0 = ((adj0->rewrite_header.sw_if_index != sw_if_index0
906                          || (adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP
907                              && adj0->lookup_next_index != IP_LOOKUP_NEXT_REWRITE))
908                         ? ICMP6_ERROR_ROUTER_SOLICITATION_SOURCE_NOT_ON_LINK
909                         : error0);
910           }
911           
912           /* check for source LL option and process */
913           o0 = (void *) (h0 + 1);
914           o0 = ((options_len0 == 8
915                  && o0->header.type == option_type
916                  && o0->header.n_data_u64s == 1)
917                 ? o0
918                 : 0);
919                       
920           /* if src address unspecified IGNORE any options */
921           if (PREDICT_TRUE (error0 == ICMP6_ERROR_NONE && o0 != 0 && 
922                             !is_unspecified && !is_link_local)) {
923               ip6_neighbor_main_t * nm = &ip6_neighbor_main;
924               if (nm->limit_neighbor_cache_size && 
925                   pool_elts (nm->neighbor_pool) >= nm->limit_neighbor_cache_size)
926                       unset_random_neighbor_entry();
927               
928               vnet_set_ip6_ethernet_neighbor (vm, sw_if_index0,
929                                               &ip0->src_address,
930                                               o0->ethernet_address,
931                                               sizeof (o0->ethernet_address));
932           }
933               
934           /* default is to drop */
935           next0 = ICMP6_ROUTER_SOLICITATION_NEXT_DROP;
936           
937           if (error0 == ICMP6_ERROR_NONE)
938             {
939               vnet_sw_interface_t * sw_if0;
940               ethernet_interface_t * eth_if0;
941               u32 adj_index0;
942
943               sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
944               ASSERT (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
945               eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
946
947               /* only support ethernet interface type for now */
948               error0 = (!eth_if0) ?  ICMP6_ERROR_ROUTER_SOLICITATION_UNSUPPORTED_INTF : error0;
949
950               if (error0 == ICMP6_ERROR_NONE)
951                 {
952                   u32 ri;
953
954                   /* adjust the sizeof the buffer to just include the ipv6 header */
955                   p0->current_length -= (options_len0 + sizeof(icmp6_neighbor_discovery_header_t));
956
957                   /* look up the radv_t information for this interface */
958                   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index0, ~0);
959
960                   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index0];
961
962                   if(ri != ~0)
963                       radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
964                         
965                   error0 = ((!radv_info) ?  ICMP6_ERROR_ROUTER_SOLICITATION_RADV_NOT_CONFIG : error0);
966
967                   if (error0 == ICMP6_ERROR_NONE)
968                     {
969                       f64 now = vlib_time_now (vm);
970
971                       /* for solicited adverts - need to rate limit */
972                       if(is_solicitation)
973                         {
974                           if( (now - radv_info->last_radv_time)  <  MIN_DELAY_BETWEEN_RAS )
975                               is_dropped = 1;
976                           else
977                             radv_info->last_radv_time = now;
978                         }
979
980                       /* send now  */
981                       icmp6_router_advertisement_header_t rh;
982
983                       rh.icmp.type = ICMP6_router_advertisement;
984                       rh.icmp.code = 0;
985                       rh.icmp.checksum = 0;
986                       
987                       rh.current_hop_limit = radv_info->curr_hop_limit;
988                       rh.router_lifetime_in_sec = clib_host_to_net_u16(radv_info->adv_router_lifetime_in_sec);
989                       rh.time_in_msec_between_retransmitted_neighbor_solicitations = 
990                         clib_host_to_net_u32(radv_info->adv_time_in_msec_between_retransmitted_neighbor_solicitations);
991                       rh.neighbor_reachable_time_in_msec = 
992                         clib_host_to_net_u32(radv_info->adv_neighbor_reachable_time_in_msec);
993                       
994                       rh.flags = (radv_info->adv_managed_flag) ? ICMP6_ROUTER_DISCOVERY_FLAG_ADDRESS_CONFIG_VIA_DHCP : 0;
995                       rh.flags |= ( (radv_info->adv_other_flag) ? ICMP6_ROUTER_DISCOVERY_FLAG_OTHER_CONFIG_VIA_DHCP : 0);
996
997
998                       u16 payload_length = sizeof(icmp6_router_advertisement_header_t);
999
1000                       vlib_buffer_add_data (vm,
1001                                             p0->free_list_index,
1002                                             bi0,
1003                                             (void *)&rh, sizeof(icmp6_router_advertisement_header_t));
1004
1005                       if(radv_info->adv_link_layer_address)
1006                         {
1007                           icmp6_neighbor_discovery_ethernet_link_layer_address_option_t h;
1008
1009                           h.header.type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
1010                           h.header.n_data_u64s = 1;
1011
1012                           /* copy ll address */
1013                           memcpy(&h.ethernet_address[0], eth_if0->address,  6);
1014
1015                           vlib_buffer_add_data (vm,
1016                                                 p0->free_list_index,
1017                                                 bi0,
1018                                                 (void *)&h, sizeof(icmp6_neighbor_discovery_ethernet_link_layer_address_option_t));
1019
1020                           payload_length += sizeof(icmp6_neighbor_discovery_ethernet_link_layer_address_option_t);
1021                         }
1022                       
1023                       /* add MTU option */
1024                       if(radv_info->adv_link_mtu)
1025                         {
1026                           icmp6_neighbor_discovery_mtu_option_t h;
1027
1028                           h.unused = 0;
1029                           h.mtu =  clib_host_to_net_u32(radv_info->adv_link_mtu);
1030                           h.header.type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_mtu;
1031                           h.header.n_data_u64s = 1;
1032                           
1033                           payload_length += sizeof( icmp6_neighbor_discovery_mtu_option_t);
1034
1035                           vlib_buffer_add_data (vm,
1036                                                 p0->free_list_index,
1037                                                 bi0,
1038                                                 (void *)&h, sizeof(icmp6_neighbor_discovery_mtu_option_t));
1039                         }
1040                       
1041                       /* add advertised prefix options  */
1042                       ip6_radv_prefix_t *pr_info; 
1043
1044                       pool_foreach (pr_info, radv_info->adv_prefixes_pool, ({
1045
1046                             if(pr_info->enabled &&
1047                                (!pr_info->decrement_lifetime_flag  || (pr_info->pref_lifetime_expires >0)))
1048                               {
1049                                 /* advertise this prefix */
1050                                 icmp6_neighbor_discovery_prefix_information_option_t h;
1051                                 
1052                                 h.header.type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_prefix_information;
1053                                 h.header.n_data_u64s  =  (sizeof(icmp6_neighbor_discovery_prefix_information_option_t) >> 3);
1054                                 
1055                                 h.dst_address_length  = pr_info->prefix_len;
1056                                 
1057                                 h.flags  = (pr_info->adv_on_link_flag) ? ICMP6_NEIGHBOR_DISCOVERY_PREFIX_INFORMATION_FLAG_ON_LINK : 0;
1058                                 h.flags |= (pr_info->adv_autonomous_flag) ?  ICMP6_NEIGHBOR_DISCOVERY_PREFIX_INFORMATION_AUTO :  0;
1059                                 
1060                                 if(radv_info->cease_radv && pr_info->deprecated_prefix_flag)
1061                                   { 
1062                                     h.valid_time = clib_host_to_net_u32(MIN_ADV_VALID_LIFETIME);
1063                                     h.preferred_time  = 0;
1064                                   }
1065                                 else
1066                                   {
1067                                     if(pr_info->decrement_lifetime_flag)
1068                                       {
1069                                         pr_info->adv_valid_lifetime_in_secs = ((pr_info->valid_lifetime_expires  > now)) ?
1070                                           (pr_info->valid_lifetime_expires  - now) : 0;
1071                                         
1072                                         pr_info->adv_pref_lifetime_in_secs = ((pr_info->pref_lifetime_expires  > now)) ?
1073                                           (pr_info->pref_lifetime_expires  - now) : 0;
1074                                       }
1075                                     
1076                                     h.valid_time = clib_host_to_net_u32(pr_info->adv_valid_lifetime_in_secs);
1077                                     h.preferred_time  = clib_host_to_net_u32(pr_info->adv_pref_lifetime_in_secs) ;
1078                                   }
1079                                 h.unused  = 0;
1080                                 
1081                                 memcpy(&h.dst_address, &pr_info->prefix,  sizeof(ip6_address_t));
1082
1083                                 payload_length += sizeof( icmp6_neighbor_discovery_prefix_information_option_t); 
1084
1085                                 vlib_buffer_add_data (vm,
1086                                                       p0->free_list_index,
1087                                                       bi0,
1088                                                       (void *)&h, sizeof(icmp6_neighbor_discovery_prefix_information_option_t));
1089
1090                               } 
1091                           }));
1092
1093                       /* add additional options before here */
1094
1095                       /* finish building the router advertisement... */
1096                       if(!is_unspecified && radv_info->send_unicast)
1097                         {
1098                           ip0->dst_address = ip0->src_address;
1099                         }
1100                       else
1101                         {                             
1102                           /* target address is all-nodes mcast addr */ 
1103                           ip6_set_reserved_multicast_address(&ip0->dst_address, 
1104                                                              IP6_MULTICAST_SCOPE_link_local,
1105                                                              IP6_MULTICAST_GROUP_ID_all_hosts);
1106                         }
1107                       
1108                       /* source address MUST be the link-local address */
1109                       ip0->src_address = radv_info->link_local_address;
1110                       
1111                       ip0->hop_limit = 255;
1112                       ip0->payload_length = clib_host_to_net_u16 (payload_length);
1113
1114                       icmp6_router_advertisement_header_t * rh0 = (icmp6_router_advertisement_header_t *)(ip0 + 1);
1115                       rh0->icmp.checksum = 
1116                           ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0, 
1117                                                              &bogus_length);
1118                       ASSERT(bogus_length == 0);
1119                       
1120                       /* setup output if and adjacency */
1121                       vnet_buffer (p0)->sw_if_index[VLIB_RX] = 
1122                         vnet_main.local_interface_sw_if_index;
1123                       
1124                       if (is_solicitation) 
1125                         {
1126                           ethernet_header_t *eth0;
1127                           /* Reuse current MAC header, copy SMAC to DMAC and 
1128                            * interface MAC to SMAC */
1129                           vlib_buffer_reset (p0);
1130                           eth0 = vlib_buffer_get_current(p0);
1131                           memcpy(eth0->dst_address, eth0->src_address, 6);
1132                           memcpy(eth0->src_address, eth_if0->address, 6);
1133                           next0 = is_dropped ? 
1134                               next0 : ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX;
1135                           vnet_buffer(p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1136                         }
1137                       else 
1138                         {
1139                           adj_index0 = radv_info->all_nodes_adj_index;
1140                           if (adj_index0 == 0)
1141                               error0 = ICMP6_ERROR_DST_LOOKUP_MISS;
1142                           else
1143                             {
1144                               ip_adjacency_t * adj0 = ip_get_adjacency (&im->lookup_main, adj_index0);
1145                               error0 = 
1146                                   ((adj0->rewrite_header.sw_if_index != sw_if_index0
1147                                     || adj0->lookup_next_index != IP_LOOKUP_NEXT_REWRITE)
1148                                    ? ICMP6_ERROR_ROUTER_SOLICITATION_DEST_UNKNOWN
1149                                    : error0);
1150                               next0 = is_dropped ? 
1151                                   next0 : ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW;
1152                               vnet_buffer (p0)->ip.adj_index[VLIB_RX] = adj_index0;
1153                            }
1154                         }
1155                       
1156                       radv_info->n_solicitations_dropped  += is_dropped;
1157                       radv_info->n_solicitations_rcvd  += is_solicitation;
1158                       
1159                       if((error0 ==  ICMP6_ERROR_NONE) && !is_dropped)
1160                         {
1161                           radv_info->n_advertisements_sent++;
1162                           n_advertisements_sent++;
1163                         }
1164                     }
1165                 }
1166             }
1167
1168           p0->error = error_node->errors[error0];
1169
1170           if(error0 != ICMP6_ERROR_NONE)
1171             vlib_error_count (vm, error_node->node_index, error0, 1);
1172           
1173           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1174                                            to_next, n_left_to_next,
1175                                            bi0, next0);
1176           
1177         }
1178       
1179       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1180     }
1181
1182   /* Account for router advertisements sent. */
1183   vlib_error_count (vm, error_node->node_index, ICMP6_ERROR_ROUTER_ADVERTISEMENTS_TX, n_advertisements_sent);
1184
1185   return frame->n_vectors;
1186 }
1187
1188  /* validate advertised info for consistancy (see RFC-4861 section 6.2.7) - log any inconsistencies, packet will always  be dropped  */
1189 static_always_inline uword
1190 icmp6_router_advertisement(vlib_main_t * vm,
1191                            vlib_node_runtime_t * node,
1192                            vlib_frame_t * frame)
1193 {
1194   vnet_main_t * vnm = vnet_get_main();
1195   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
1196   uword n_packets = frame->n_vectors;
1197   u32 * from, * to_next;
1198   u32 n_left_from, n_left_to_next, next_index;
1199   u32 n_advertisements_rcvd = 0;
1200
1201   vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip6_icmp_input_node.index);
1202
1203   from = vlib_frame_vector_args (frame);
1204   n_left_from = n_packets;
1205   next_index = node->cached_next_index;
1206   
1207   if (node->flags & VLIB_NODE_FLAG_TRACE)
1208     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
1209                                    /* stride */ 1,
1210                                    sizeof (icmp6_input_trace_t));
1211
1212   while (n_left_from > 0)
1213     {
1214       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1215       
1216       while (n_left_from > 0 && n_left_to_next > 0)
1217         {
1218           vlib_buffer_t * p0;
1219           ip6_header_t * ip0;
1220           ip6_radv_t *radv_info = 0;
1221           icmp6_router_advertisement_header_t * h0;  
1222           u32 bi0, options_len0, sw_if_index0, next0, error0;
1223
1224           bi0 = to_next[0] = from[0];
1225
1226           from += 1;
1227           to_next += 1;
1228           n_left_from -= 1;
1229           n_left_to_next -= 1;
1230       
1231           p0 = vlib_get_buffer (vm, bi0);
1232           ip0 = vlib_buffer_get_current (p0);
1233           h0 = ip6_next_header (ip0);
1234           options_len0 = clib_net_to_host_u16 (ip0->payload_length) - sizeof (h0[0]);
1235
1236           error0 = ICMP6_ERROR_NONE;
1237           sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1238
1239           /* Check that source address is link-local*/
1240           error0 = (!ip6_address_is_link_local_unicast (&ip0->src_address)) ? 
1241             ICMP6_ERROR_ROUTER_ADVERTISEMENT_SOURCE_NOT_LINK_LOCAL : error0;
1242
1243           /* default is to drop */
1244           next0 = ICMP6_ROUTER_SOLICITATION_NEXT_DROP;
1245           
1246           n_advertisements_rcvd++;
1247
1248           if (error0 == ICMP6_ERROR_NONE)
1249             {
1250               vnet_sw_interface_t * sw_if0;
1251               ethernet_interface_t * eth_if0;
1252     
1253               sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
1254               ASSERT (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
1255               eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
1256
1257               /* only support ethernet interface type for now */
1258               error0 = (!eth_if0) ?  ICMP6_ERROR_ROUTER_SOLICITATION_UNSUPPORTED_INTF : error0;
1259
1260               if (error0 == ICMP6_ERROR_NONE)
1261                 {
1262                   u32 ri;
1263
1264                   /* look up the radv_t information for this interface */
1265                   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index0, ~0);
1266
1267                   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index0];
1268
1269                   if(ri != ~0)
1270                       radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
1271                         
1272                   error0 = ((!radv_info) ?  ICMP6_ERROR_ROUTER_SOLICITATION_RADV_NOT_CONFIG : error0);
1273
1274                   if (error0 == ICMP6_ERROR_NONE)
1275                     {
1276                       /* validate advertised information */
1277                       if((h0->current_hop_limit && radv_info->curr_hop_limit) &&
1278                          (h0->current_hop_limit != radv_info->curr_hop_limit))
1279                         {
1280                           ip6_neighbor_syslog(vm,  LOG_WARNING,  
1281                                               "our AdvCurHopLimit on %U doesn't agree with %U", 
1282                                               format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1283                         }
1284
1285                       if((h0->flags &  ICMP6_ROUTER_DISCOVERY_FLAG_ADDRESS_CONFIG_VIA_DHCP)  != 
1286                          radv_info->adv_managed_flag)
1287                         {
1288                           ip6_neighbor_syslog(vm,  LOG_WARNING,  
1289                                               "our AdvManagedFlag on %U doesn't agree with %U", 
1290                                               format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1291                         }
1292
1293                       if((h0->flags &   ICMP6_ROUTER_DISCOVERY_FLAG_OTHER_CONFIG_VIA_DHCP)   != 
1294                          radv_info->adv_other_flag)
1295                         {
1296                           ip6_neighbor_syslog(vm,  LOG_WARNING,  
1297                                               "our AdvOtherConfigFlag on %U doesn't agree with %U", 
1298                                               format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1299                         }
1300
1301                       if((h0->time_in_msec_between_retransmitted_neighbor_solicitations && 
1302                           radv_info->adv_time_in_msec_between_retransmitted_neighbor_solicitations) &&
1303                          (h0->time_in_msec_between_retransmitted_neighbor_solicitations !=
1304                           clib_host_to_net_u32(radv_info->adv_time_in_msec_between_retransmitted_neighbor_solicitations)))
1305                         {
1306                           ip6_neighbor_syslog(vm,  LOG_WARNING,  
1307                                               "our AdvRetransTimer on %U doesn't agree with %U", 
1308                                               format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1309                         }
1310
1311                       if((h0->neighbor_reachable_time_in_msec && 
1312                           radv_info->adv_neighbor_reachable_time_in_msec) &&
1313                          (h0->neighbor_reachable_time_in_msec !=
1314                           clib_host_to_net_u32(radv_info->adv_neighbor_reachable_time_in_msec)))
1315                         {
1316                           ip6_neighbor_syslog(vm,  LOG_WARNING,  
1317                                               "our AdvReachableTime on %U doesn't agree with %U", 
1318                                               format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1319                         }
1320
1321                       /* check for MTU or prefix options or .. */
1322                       u8 * opt_hdr = (u8 *)(h0 + 1);
1323                       while( options_len0 > 0)
1324                         {
1325                           icmp6_neighbor_discovery_option_header_t *o0 = ( icmp6_neighbor_discovery_option_header_t *)opt_hdr;
1326                           int opt_len = o0->n_data_u64s << 3;
1327                           icmp6_neighbor_discovery_option_type_t option_type = o0->type;
1328
1329                           if(options_len0 < 2)
1330                             {
1331                               ip6_neighbor_syslog(vm,  LOG_ERR,  
1332                                                   "malformed RA packet on %U from %U", 
1333                                                   format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1334                               break;
1335                             }
1336
1337                           if(opt_len == 0)
1338                             {
1339                               ip6_neighbor_syslog(vm,  LOG_ERR,  
1340                                                   " zero length option in RA on %U from %U", 
1341                                                   format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1342                               break;
1343                             }
1344                           else if( opt_len > options_len0)
1345                             {
1346                               ip6_neighbor_syslog(vm,  LOG_ERR,  
1347                                                   "option length in RA packet  greater than total length on %U from %U", 
1348                                                   format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1349                               break;
1350                             }
1351
1352                           options_len0 -= opt_len;
1353                           opt_hdr += opt_len;
1354
1355                           switch(option_type)
1356                             {
1357                             case ICMP6_NEIGHBOR_DISCOVERY_OPTION_mtu:
1358                               {                       
1359                                 icmp6_neighbor_discovery_mtu_option_t *h =
1360                                   (icmp6_neighbor_discovery_mtu_option_t *)(o0);
1361
1362                                 if(opt_len < sizeof(*h))
1363                                   break;
1364
1365                                 if((h->mtu && radv_info->adv_link_mtu) &&
1366                                    (h->mtu != clib_host_to_net_u32(radv_info->adv_link_mtu)))
1367                                   {
1368                                     ip6_neighbor_syslog(vm,  LOG_WARNING,  
1369                                                         "our AdvLinkMTU on %U doesn't agree with %U", 
1370                                                         format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1371                                   }
1372                               }
1373                               break;
1374                               
1375                             case ICMP6_NEIGHBOR_DISCOVERY_OPTION_prefix_information:
1376                               {
1377                                 icmp6_neighbor_discovery_prefix_information_option_t *h =
1378                                   (icmp6_neighbor_discovery_prefix_information_option_t *)(o0);
1379                               
1380                                 /* validate advertised prefix options  */
1381                                 ip6_radv_prefix_t *pr_info; 
1382                                 u32 preferred, valid;
1383
1384                                 if(opt_len < sizeof(*h))
1385                                   break;
1386
1387                                 preferred =  clib_net_to_host_u32(h->preferred_time);
1388                                 valid =  clib_net_to_host_u32(h->valid_time);
1389
1390                                 /* look for matching prefix - if we our advertising it, it better be consistant */
1391                                 pool_foreach (pr_info, radv_info->adv_prefixes_pool, ({
1392                                       
1393                                       ip6_address_t mask;
1394                                       ip6_address_mask_from_width(&mask, pr_info->prefix_len);
1395
1396                                       if(pr_info->enabled &&
1397                                        (pr_info->prefix_len == h->dst_address_length) &&
1398                                          ip6_address_is_equal_masked (&pr_info->prefix,  &h->dst_address, &mask))
1399                                         {
1400                                           /* found it */
1401                                           if(!pr_info->decrement_lifetime_flag &&
1402                                              valid != pr_info->adv_valid_lifetime_in_secs)
1403                                             {
1404                                               ip6_neighbor_syslog(vm,  LOG_WARNING,  
1405                                                                   "our ADV validlifetime on  %U for %U does not  agree with %U", 
1406                                                                   format_vnet_sw_if_index_name, vnm, sw_if_index0,format_ip6_address, &pr_info->prefix, 
1407                                                                   format_ip6_address, &h->dst_address);
1408                                             }
1409                                           if(!pr_info->decrement_lifetime_flag &&
1410                                              preferred != pr_info->adv_pref_lifetime_in_secs)
1411                                             {
1412                                               ip6_neighbor_syslog(vm,  LOG_WARNING,  
1413                                                                   "our ADV preferredlifetime on  %U for %U does not  agree with %U", 
1414                                                                   format_vnet_sw_if_index_name, vnm, sw_if_index0,format_ip6_address, &pr_info->prefix, 
1415                                                                   format_ip6_address, &h->dst_address);
1416                                             }
1417                                         }
1418                                       break;
1419                                     }));
1420                                 break;
1421                               }
1422                             default:
1423                               /* skip this one */
1424                               break;
1425                             }
1426                         }
1427                     }
1428                 }
1429             }
1430
1431           p0->error = error_node->errors[error0];
1432
1433           if(error0 != ICMP6_ERROR_NONE)
1434             vlib_error_count (vm, error_node->node_index, error0, 1);
1435           
1436           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1437                                            to_next, n_left_to_next,
1438                                            bi0, next0);
1439         }
1440       
1441       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1442     }
1443
1444   /* Account for router advertisements sent. */
1445   vlib_error_count (vm, error_node->node_index, ICMP6_ERROR_ROUTER_ADVERTISEMENTS_RX, n_advertisements_rcvd);
1446
1447   return frame->n_vectors;
1448 }
1449
1450 /* create and initialize router advertisement parameters with default values for this intfc */
1451 static u32
1452 ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm,
1453                                    u32 sw_if_index,
1454                                    u32 is_add)
1455 {
1456   ip6_main_t * im = &ip6_main;
1457   ip6_neighbor_main_t * nm = &ip6_neighbor_main;  
1458   ip_lookup_main_t * lm = &im->lookup_main;
1459   ip6_radv_t * a= 0;  
1460   u32 ri = ~0;;
1461   vnet_sw_interface_t * sw_if0;
1462   ethernet_interface_t * eth_if0 = 0; 
1463
1464   /* lookup radv container  - ethernet interfaces only */
1465   sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
1466   if(sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
1467     eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
1468
1469   if(!eth_if0)
1470     return ri;
1471    
1472   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
1473   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
1474
1475   if(ri != ~0)
1476     {
1477       a = pool_elt_at_index (nm->if_radv_pool, ri);
1478
1479       if(!is_add)
1480         {
1481           u32 i, * to_delete = 0;
1482           ip6_radv_prefix_t  *p;
1483           ip6_mldp_group_t *m;
1484           
1485           /* remove adjacencies */
1486           ip_del_adjacency (lm,  a->all_nodes_adj_index); 
1487           ip_del_adjacency (lm,  a->all_routers_adj_index);           
1488           ip_del_adjacency (lm,  a->all_mldv2_routers_adj_index);             
1489           
1490           /* clean up prefix_pool */
1491           pool_foreach (p, a->adv_prefixes_pool, ({
1492                 vec_add1 (to_delete, p  -  a->adv_prefixes_pool);
1493               }));
1494           
1495           for (i = 0; i < vec_len (to_delete); i++)
1496             {
1497               p = pool_elt_at_index (a->adv_prefixes_pool, to_delete[i]);
1498               mhash_unset (&a->address_to_prefix_index, &p->prefix, 0);
1499               pool_put (a->adv_prefixes_pool, p);
1500             }
1501           
1502           vec_free (to_delete);
1503           to_delete = 0;
1504           
1505           /* clean up mldp group pool */
1506           pool_foreach (m, a->mldp_group_pool, ({
1507                 vec_add1 (to_delete, m  -  a->mldp_group_pool);
1508               }));
1509           
1510           for (i = 0; i < vec_len (to_delete); i++)
1511             {
1512               m = pool_elt_at_index (a->mldp_group_pool, to_delete[i]);
1513               mhash_unset (&a->address_to_mldp_index, &m->mcast_address, 0);
1514               pool_put (a->mldp_group_pool, m);
1515             }
1516           
1517           vec_free (to_delete);
1518           
1519           pool_put (nm->if_radv_pool,  a);
1520           nm->if_radv_pool_index_by_sw_if_index[sw_if_index] = ~0;
1521           ri = ~0;
1522         }
1523     }
1524  else
1525    {
1526      if(is_add)
1527        {
1528          vnet_hw_interface_t * hw_if0;
1529      
1530          hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index);
1531          
1532          pool_get (nm->if_radv_pool, a);
1533          
1534          ri = a - nm->if_radv_pool;
1535          nm->if_radv_pool_index_by_sw_if_index[sw_if_index] = ri;
1536          
1537          /* initialize default values (most of which are zero) */
1538          memset (a, 0, sizeof (a[0]));
1539          
1540          a->sw_if_index = sw_if_index;
1541          a->fib_index = ~0;
1542          a->max_radv_interval = DEF_MAX_RADV_INTERVAL;    
1543          a->min_radv_interval =  DEF_MIN_RADV_INTERVAL;    
1544          a->curr_hop_limit = DEF_CURR_HOP_LIMIT;                         
1545          a->adv_router_lifetime_in_sec = DEF_DEF_RTR_LIFETIME;   
1546          
1547          a->adv_link_layer_address = 1;  /* send ll address source address option */
1548          
1549          a->min_delay_between_radv = MIN_DELAY_BETWEEN_RAS;
1550          a->max_delay_between_radv = MAX_DELAY_BETWEEN_RAS;
1551          a->max_rtr_default_lifetime = MAX_DEF_RTR_LIFETIME;
1552          a->seed = random_default_seed();
1553          
1554          /* for generating random interface ids */
1555          a->randomizer = 0x1119194911191949;
1556          a->randomizer = random_u64 ((u32 *)&a->randomizer);
1557          
1558          a->initial_adverts_count = MAX_INITIAL_RTR_ADVERTISEMENTS ; 
1559          a->initial_adverts_sent = a->initial_adverts_count-1;
1560          a->initial_adverts_interval = MAX_INITIAL_RTR_ADVERT_INTERVAL;      
1561          
1562          /* deafult is to send */
1563          a->send_radv = 1;
1564          
1565          /* fill in radv_info for this interface that will be needed later */
1566          a->adv_link_mtu = hw_if0->max_l3_packet_bytes[VLIB_RX];
1567          
1568          memcpy (a->link_layer_address, eth_if0->address, 6);
1569          
1570          /* fill in default link-local address  (this may be overridden) */
1571          ip6_link_local_address_from_ethernet_address (&a->link_local_address, eth_if0->address);
1572          a->link_local_prefix_len = 64;
1573
1574          mhash_init (&a->address_to_prefix_index, sizeof (uword), sizeof (ip6_address_t));
1575          mhash_init (&a->address_to_mldp_index, sizeof (uword), sizeof (ip6_address_t)); 
1576          
1577          {
1578            ip_adjacency_t *adj;
1579            u8 link_layer_address[6] = 
1580              {0x33, 0x33, 0x00, 0x00, 0x00, IP6_MULTICAST_GROUP_ID_all_hosts};
1581            
1582            adj = ip_add_adjacency (lm, /* template */ 0, /* block size */ 1,
1583                                    &a->all_nodes_adj_index);
1584            
1585            adj->lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
1586            adj->if_address_index = ~0;
1587            
1588            vnet_rewrite_for_sw_interface
1589              (vnm,
1590               VNET_L3_PACKET_TYPE_IP6,
1591               sw_if_index,
1592               ip6_rewrite_node.index,
1593               link_layer_address,
1594               &adj->rewrite_header,
1595               sizeof (adj->rewrite_data));
1596          } 
1597          
1598          {
1599            ip_adjacency_t *adj;
1600            u8 link_layer_address[6] = 
1601              {0x33, 0x33, 0x00, 0x00, 0x00, IP6_MULTICAST_GROUP_ID_all_routers};
1602         
1603            adj = ip_add_adjacency (lm, /* template */ 0, /* block size */ 1,
1604                                    &a->all_routers_adj_index);
1605            
1606            adj->lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
1607            adj->if_address_index = ~0;
1608            
1609            vnet_rewrite_for_sw_interface
1610              (vnm,
1611               VNET_L3_PACKET_TYPE_IP6,
1612               sw_if_index,
1613               ip6_rewrite_node.index,
1614               link_layer_address,
1615               &adj->rewrite_header,
1616               sizeof (adj->rewrite_data));
1617          } 
1618          
1619          {
1620            ip_adjacency_t *adj;
1621            u8 link_layer_address[6] = 
1622              {0x33, 0x33, 0x00, 0x00, 0x00, IP6_MULTICAST_GROUP_ID_mldv2_routers};
1623            
1624            adj = ip_add_adjacency (lm, /* template */ 0, /* block size */ 1,
1625                                    &a->all_mldv2_routers_adj_index);
1626            
1627            adj->lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
1628            adj->if_address_index = ~0;
1629            
1630            vnet_rewrite_for_sw_interface
1631              (vnm,
1632               VNET_L3_PACKET_TYPE_IP6,
1633               sw_if_index,
1634               ip6_rewrite_node.index,
1635               link_layer_address,
1636               &adj->rewrite_header,
1637               sizeof (adj->rewrite_data));
1638          } 
1639          
1640          /* add multicast groups we will always be reporting  */
1641          ip6_address_t addr;
1642          ip6_mldp_group_t  *mcast_group_info;
1643          
1644          ip6_set_reserved_multicast_address (&addr,
1645                                              IP6_MULTICAST_SCOPE_link_local,
1646                                              IP6_MULTICAST_GROUP_ID_all_hosts);
1647          
1648          /* lookup  mldp info for this interface */
1649          
1650          uword * p = mhash_get (&a->address_to_mldp_index,  &addr);
1651          mcast_group_info = p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0;
1652          
1653          /* add address */
1654          if(!mcast_group_info)
1655            {
1656              /* add */
1657              u32 mi;
1658              pool_get (a->mldp_group_pool, mcast_group_info);
1659           
1660              mi = mcast_group_info - a->mldp_group_pool;
1661              mhash_set (&a->address_to_mldp_index,  &addr,  mi, /* old_value */ 0);
1662              
1663              mcast_group_info->type = 4;
1664              mcast_group_info->mcast_source_address_pool = 0;
1665              mcast_group_info->num_sources = 0;
1666              memcpy(&mcast_group_info->mcast_address, &addr, sizeof(ip6_address_t));
1667            } 
1668          
1669          ip6_set_reserved_multicast_address (&addr,
1670                                              IP6_MULTICAST_SCOPE_link_local,
1671                                              IP6_MULTICAST_GROUP_ID_all_routers);
1672          
1673          p = mhash_get (&a->address_to_mldp_index,  &addr);
1674          mcast_group_info = p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0;
1675          
1676          if(!mcast_group_info)
1677            {
1678              /* add */
1679              u32 mi;
1680              pool_get (a->mldp_group_pool, mcast_group_info);
1681              
1682              mi = mcast_group_info - a->mldp_group_pool;
1683              mhash_set (&a->address_to_mldp_index,  &addr,  mi, /* old_value */ 0);
1684              
1685              mcast_group_info->type = 4;
1686              mcast_group_info->mcast_source_address_pool = 0;
1687              mcast_group_info->num_sources = 0;
1688              memcpy(&mcast_group_info->mcast_address, &addr, sizeof(ip6_address_t));
1689            } 
1690          
1691          ip6_set_reserved_multicast_address (&addr,
1692                                              IP6_MULTICAST_SCOPE_link_local,
1693                                              IP6_MULTICAST_GROUP_ID_mldv2_routers);
1694          
1695          p = mhash_get (&a->address_to_mldp_index,  &addr);
1696          mcast_group_info = p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0;
1697          
1698          if(!mcast_group_info)
1699            {
1700              /* add */
1701              u32 mi;
1702              pool_get (a->mldp_group_pool, mcast_group_info);
1703              
1704              mi = mcast_group_info - a->mldp_group_pool;
1705              mhash_set (&a->address_to_mldp_index,  &addr,  mi, /* old_value */ 0);
1706              
1707              mcast_group_info->type = 4;
1708              mcast_group_info->mcast_source_address_pool = 0;
1709              mcast_group_info->num_sources = 0;
1710              memcpy(&mcast_group_info->mcast_address, &addr, sizeof(ip6_address_t));
1711            } 
1712        }
1713    } 
1714   return  ri;
1715 }
1716
1717 /* send an mldpv2 report  */
1718 static void
1719 ip6_neighbor_send_mldpv2_report(u32 sw_if_index)
1720 {
1721   vnet_main_t * vnm = vnet_get_main();
1722   vlib_main_t * vm = vnm->vlib_main;
1723   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
1724   vnet_sw_interface_t * sw_if0;
1725   ethernet_interface_t * eth_if0;
1726   u32 ri;
1727   int bogus_length;
1728
1729   ip6_radv_t *radv_info; 
1730   u16 payload_length;
1731   vlib_buffer_t * b0;
1732   ip6_header_t * ip0;
1733   u32 * to_next;
1734   vlib_frame_t * f;
1735   u32 bo0;
1736   u32 n_to_alloc = 1;
1737   u32 n_allocated;
1738   
1739   icmp6_multicast_listener_report_header_t *rh0;
1740   icmp6_multicast_listener_report_packet_t *rp0;
1741
1742   sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
1743   ASSERT (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
1744   eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
1745
1746   if (!eth_if0 || !vnet_sw_interface_is_admin_up (vnm, sw_if_index))
1747     return;
1748
1749   /* look up the radv_t  information for this interface */
1750   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
1751   
1752   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
1753   
1754   if(ri == ~0)
1755     return;
1756                 
1757   /* send report now - build a mldpv2 report packet  */
1758   n_allocated = vlib_buffer_alloc_from_free_list(vm, 
1759                                                  &bo0, 
1760                                                  n_to_alloc,
1761                                                  VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
1762   if (PREDICT_FALSE(n_allocated == 0))
1763     {
1764       clib_warning ("buffer allocation failure");
1765       return;
1766     }
1767
1768   b0 = vlib_get_buffer (vm, bo0);
1769
1770   /* adjust the sizeof the buffer to just include the ipv6 header */
1771   b0->current_length  = sizeof(icmp6_multicast_listener_report_packet_t);
1772
1773   payload_length = sizeof(icmp6_multicast_listener_report_header_t);
1774
1775   b0->error = ICMP6_ERROR_NONE;
1776
1777   rp0 = vlib_buffer_get_current (b0);
1778   ip0 = (ip6_header_t *)&rp0-> ip;
1779   rh0 = (icmp6_multicast_listener_report_header_t *)&rp0-> report_hdr;
1780   
1781   memset (rp0 , 0x0, sizeof (icmp6_multicast_listener_report_packet_t));
1782   
1783   ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (0x6 << 28);
1784
1785   ip0->protocol = IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS;  
1786   /* for DEBUG - vnet driver won't seem to emit router alerts */
1787   /* ip0->protocol = IP_PROTOCOL_ICMP6; */
1788   ip0->hop_limit = 1;
1789  
1790   rh0->icmp.type = ICMP6_multicast_listener_report_v2;
1791   
1792   /* source address MUST be the link-local address */
1793   radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
1794   ip0->src_address = radv_info->link_local_address;  
1795
1796   /* destination is all mldpv2 routers */
1797   ip6_set_reserved_multicast_address(&ip0->dst_address, 
1798                                      IP6_MULTICAST_SCOPE_link_local,
1799                                      IP6_MULTICAST_GROUP_ID_mldv2_routers);
1800   
1801   /* add reports here */
1802   ip6_mldp_group_t *m;
1803   int num_addr_records = 0;
1804   icmp6_multicast_address_record_t rr;
1805
1806   /* fill in the hop-by-hop extension header (router alert) info */
1807   rh0->ext_hdr.next_hdr = IP_PROTOCOL_ICMP6;
1808   rh0->ext_hdr.n_data_u64s = 0;
1809   
1810   rh0->alert.type = IP6_MLDP_ALERT_TYPE;
1811   rh0->alert.len = 2;
1812   rh0->alert.value = 0;
1813   
1814   rh0->pad.type = 1;
1815   rh0->pad.len = 0;
1816  
1817   rh0->icmp.checksum = 0;
1818
1819   pool_foreach (m, radv_info->mldp_group_pool, ({
1820
1821         rr.type = m->type;
1822         rr.aux_data_len_u32s = 0;
1823         rr.num_sources = clib_host_to_net_u16 (m->num_sources);
1824         memcpy(&rr.mcast_addr, &m->mcast_address, sizeof(ip6_address_t));
1825
1826         num_addr_records++;
1827
1828         vlib_buffer_add_data (vm,
1829                               b0->free_list_index,
1830                               bo0,
1831                               (void *)&rr, sizeof(icmp6_multicast_address_record_t));
1832         
1833         payload_length += sizeof( icmp6_multicast_address_record_t);
1834       }));
1835
1836   rh0->rsvd = 0;
1837   rh0->num_addr_records =  clib_host_to_net_u16(num_addr_records);
1838   
1839   /* update lengths */
1840   ip0->payload_length = clib_host_to_net_u16 (payload_length);
1841
1842   rh0->icmp.checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0, 
1843                                                           &bogus_length);
1844   ASSERT(bogus_length == 0);
1845
1846   /* 
1847    * OK to override w/ no regard for actual FIB, because
1848    * ip6-rewrite-local only looks at the adjacency.
1849    */
1850   vnet_buffer (b0)->sw_if_index[VLIB_RX] = 
1851     vnet_main.local_interface_sw_if_index;
1852   
1853   vnet_buffer (b0)->ip.adj_index[VLIB_RX]  = 
1854     radv_info->all_mldv2_routers_adj_index;
1855
1856   vlib_node_t * node = vlib_get_node_by_name (vm, (u8 *) "ip6-rewrite-local");
1857   
1858   f = vlib_get_frame_to_node (vm, node->index);
1859   to_next = vlib_frame_vector_args (f);
1860   to_next[0] = bo0;
1861   f->n_vectors = 1;
1862   
1863   vlib_put_frame_to_node (vm, node->index, f);
1864   return;
1865 }
1866
1867 VLIB_REGISTER_NODE (ip6_icmp_router_solicitation_node,static) = {
1868   .function = icmp6_router_solicitation,
1869   .name = "icmp6-router-solicitation",
1870
1871   .vector_size = sizeof (u32),
1872
1873   .format_trace = format_icmp6_input_trace,
1874
1875   .n_next_nodes = ICMP6_ROUTER_SOLICITATION_N_NEXT,
1876   .next_nodes = {
1877     [ICMP6_ROUTER_SOLICITATION_NEXT_DROP] = "error-drop",
1878     [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW] = "ip6-rewrite-local",
1879     [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX] = "interface-output",
1880   },
1881 };
1882
1883 /* send a RA or update the timer info etc.. */
1884 static uword
1885 ip6_neighbor_process_timer_event (vlib_main_t * vm,
1886                                            vlib_node_runtime_t * node,
1887                                            vlib_frame_t * frame)
1888 {
1889   vnet_main_t * vnm = vnet_get_main();
1890   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
1891   ip6_radv_t *radv_info; 
1892   vlib_frame_t * f = 0; 
1893   u32 n_this_frame = 0;
1894   u32 n_left_to_next;
1895   u32 * to_next;
1896   u32 bo0; 
1897   icmp6_router_solicitation_header_t * h0;
1898   vlib_buffer_t * b0;
1899   f64 now = vlib_time_now (vm);
1900
1901   /* Interface ip6 radv info list */
1902   pool_foreach (radv_info, nm->if_radv_pool, ({
1903
1904         if( !vnet_sw_interface_is_admin_up (vnm, radv_info->sw_if_index))
1905           {
1906             radv_info->initial_adverts_sent = radv_info->initial_adverts_count-1;
1907             radv_info->next_multicast_time = now;             
1908             radv_info->last_multicast_time = now;
1909             radv_info->last_radv_time = 0;      
1910             radv_info->all_routers_mcast = 0;
1911             continue;
1912           }
1913
1914         /* Make sure that we've joined the all-routers multicast group */
1915         if(!radv_info->all_routers_mcast)
1916           {
1917             /* send MDLP_REPORT_EVENT message */              
1918             ip6_neighbor_send_mldpv2_report(radv_info->sw_if_index);
1919             radv_info->all_routers_mcast = 1;
1920           }
1921
1922         /* is it time to send a multicast  RA on this interface? */
1923         if(radv_info->send_radv && (now >=  radv_info->next_multicast_time))
1924           {     
1925             u32 n_to_alloc = 1;
1926             u32 n_allocated;
1927             
1928             f64 rfn = (radv_info->max_radv_interval - radv_info->min_radv_interval) * 
1929               random_f64 (&radv_info->seed) + radv_info->min_radv_interval;
1930
1931             /* multicast send - compute next multicast send time */
1932             if( radv_info->initial_adverts_sent > 0)
1933               {
1934                 radv_info->initial_adverts_sent--;
1935                 if(rfn > radv_info-> initial_adverts_interval)
1936                   rfn =  radv_info-> initial_adverts_interval;
1937
1938                 /* check to see if we are ceasing to send */
1939                 if( radv_info->initial_adverts_sent  == 0)
1940                   if(radv_info->cease_radv)  
1941                     radv_info->send_radv = 0;
1942               }
1943             
1944             radv_info->next_multicast_time =  rfn + now;
1945             radv_info->last_multicast_time = now;
1946             
1947             /* send advert now - build a "solicted" router advert with unspecified source address */
1948             n_allocated = vlib_buffer_alloc_from_free_list(vm, 
1949                                                            &bo0, 
1950                                                            n_to_alloc,
1951                                                            VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
1952             
1953             if (PREDICT_FALSE(n_allocated == 0))
1954               {
1955                 clib_warning ("buffer allocation failure");
1956                 continue;
1957               }
1958             b0 = vlib_get_buffer (vm, bo0);
1959             b0->current_length = sizeof( icmp6_router_solicitation_header_t);
1960             b0->error = ICMP6_ERROR_NONE;
1961             vnet_buffer (b0)->sw_if_index[VLIB_RX] = radv_info->sw_if_index;
1962             
1963             h0 =  vlib_buffer_get_current (b0);
1964             
1965             memset (h0, 0, sizeof (icmp6_router_solicitation_header_t));
1966             
1967             h0->ip.ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (0x6 << 28);
1968             h0->ip.payload_length = clib_host_to_net_u16 (sizeof (icmp6_router_solicitation_header_t)
1969                                                           - STRUCT_OFFSET_OF (icmp6_router_solicitation_header_t, neighbor));
1970             h0->ip.protocol = IP_PROTOCOL_ICMP6;
1971             h0->ip.hop_limit = 255;
1972             
1973             /* set src/dst address as "unspecified" this marks this packet as internally generated rather than recieved */
1974             h0->ip.src_address.as_u64[0] = 0;
1975             h0->ip.src_address.as_u64[1] = 0;
1976             
1977             h0->ip.dst_address.as_u64[0] = 0;
1978             h0->ip.dst_address.as_u64[1] = 0;
1979             
1980             h0->neighbor.icmp.type = ICMP6_router_solicitation;
1981
1982             if (PREDICT_FALSE(f == 0))
1983               { 
1984                 f = vlib_get_frame_to_node (vm, ip6_icmp_router_solicitation_node.index);
1985                 to_next = vlib_frame_vector_args (f);
1986                 n_left_to_next = VLIB_FRAME_SIZE;
1987                 n_this_frame = 0;
1988               }
1989
1990             n_this_frame++;
1991             n_left_to_next--;
1992             to_next[0] = bo0;
1993             to_next += 1;
1994
1995             if (PREDICT_FALSE(n_left_to_next == 0)) 
1996               {
1997                 f->n_vectors = n_this_frame;
1998                 vlib_put_frame_to_node (vm, ip6_icmp_router_solicitation_node.index, f);
1999                 f = 0;
2000               }
2001           }
2002       }));
2003
2004   if (f)
2005     {
2006       ASSERT(n_this_frame);
2007       f->n_vectors = n_this_frame;
2008       vlib_put_frame_to_node (vm, ip6_icmp_router_solicitation_node.index, f);
2009     }
2010   return  0;
2011 }
2012
2013 static uword
2014 ip6_icmp_neighbor_discovery_event_process (vlib_main_t * vm,
2015                                            vlib_node_runtime_t * node,
2016                                            vlib_frame_t * frame)
2017 {
2018   uword event_type;
2019   ip6_icmp_neighbor_discovery_event_data_t * event_data;
2020
2021   /* init code here */
2022  
2023   while (1)
2024     {
2025       vlib_process_wait_for_event_or_clock (vm,  1. /* seconds */);
2026
2027       event_data = vlib_process_get_event_data (vm,  &event_type);
2028
2029       if(!event_data)
2030         {
2031           /* No events found: timer expired. */
2032           /* process interface list and send RAs as appropriate, update timer info */
2033           ip6_neighbor_process_timer_event (vm,  node,  frame); 
2034         }
2035       else
2036         {
2037           switch (event_type) {
2038
2039           case ICMP6_ND_EVENT_INIT:
2040             break;
2041    
2042           case ~0:
2043             break;
2044             
2045           default:
2046             ASSERT (0);
2047           }
2048           
2049           if (event_data)
2050             _vec_len (event_data) = 0;
2051         }
2052     }
2053   return frame->n_vectors;
2054 }
2055
2056 VLIB_REGISTER_NODE (ip6_icmp_router_advertisement_node,static) = {
2057   .function = icmp6_router_advertisement,
2058   .name = "icmp6-router-advertisement",
2059
2060   .vector_size = sizeof (u32),
2061
2062   .format_trace = format_icmp6_input_trace,
2063
2064   .n_next_nodes = 1,
2065   .next_nodes = {
2066     [0] = "error-drop",
2067   },
2068 };
2069
2070 vlib_node_registration_t ip6_icmp_neighbor_discovery_event_node = {
2071
2072   .function = ip6_icmp_neighbor_discovery_event_process,
2073   .name = "ip6-icmp-neighbor-discovery-event-process",
2074   .type = VLIB_NODE_TYPE_PROCESS,
2075 };
2076
2077 static uword
2078 icmp6_neighbor_solicitation (vlib_main_t * vm,
2079                              vlib_node_runtime_t * node,
2080                              vlib_frame_t * frame)
2081 { return icmp6_neighbor_solicitation_or_advertisement (vm, node, frame, /* is_solicitation */ 1); }
2082
2083 static uword
2084 icmp6_neighbor_advertisement (vlib_main_t * vm,
2085                               vlib_node_runtime_t * node,
2086                               vlib_frame_t * frame)
2087 { return icmp6_neighbor_solicitation_or_advertisement (vm, node, frame, /* is_solicitation */ 0); }
2088
2089 VLIB_REGISTER_NODE (ip6_icmp_neighbor_solicitation_node,static) = {
2090   .function = icmp6_neighbor_solicitation,
2091   .name = "icmp6-neighbor-solicitation",
2092
2093   .vector_size = sizeof (u32),
2094
2095   .format_trace = format_icmp6_input_trace,
2096
2097   .n_next_nodes = ICMP6_NEIGHBOR_SOLICITATION_N_NEXT,
2098   .next_nodes = {
2099     [ICMP6_NEIGHBOR_SOLICITATION_NEXT_DROP] = "error-drop",
2100     [ICMP6_NEIGHBOR_SOLICITATION_NEXT_REPLY] = "interface-output",
2101   },
2102 };
2103
2104 VLIB_REGISTER_NODE (ip6_icmp_neighbor_advertisement_node,static) = {
2105   .function = icmp6_neighbor_advertisement,
2106   .name = "icmp6-neighbor-advertisement",
2107
2108   .vector_size = sizeof (u32),
2109
2110   .format_trace = format_icmp6_input_trace,
2111
2112   .n_next_nodes = 1,
2113   .next_nodes = {
2114     [0] = "error-drop",
2115   },
2116 };
2117
2118 /* API  support functions */
2119 int
2120 ip6_neighbor_ra_config(vlib_main_t * vm, u32 sw_if_index, 
2121                        u8 surpress, u8 managed, u8 other,
2122                        u8 ll_option,  u8 send_unicast,  u8 cease, 
2123                        u8 use_lifetime,  u32 lifetime,
2124                        u32 initial_count,  u32 initial_interval,  
2125                        u32 max_interval,  u32 min_interval,
2126                        u8 is_no)
2127 {
2128   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2129   int  error;
2130   u32 ri;
2131
2132   /* look up the radv_t  information for this interface */
2133   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2134   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2135   error = (ri != ~0) ? 0 :  VNET_API_ERROR_INVALID_SW_IF_INDEX;
2136
2137   if(!error)
2138     {
2139
2140       ip6_radv_t * radv_info;
2141       radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
2142   
2143       if((max_interval != 0) && (min_interval ==0))
2144         min_interval =  .75 * max_interval;
2145
2146       max_interval  = (max_interval != 0) ? ( (is_no) ?  DEF_MAX_RADV_INTERVAL :  max_interval) :  radv_info->max_radv_interval;
2147       min_interval  = (min_interval != 0) ? ( (is_no) ?  DEF_MIN_RADV_INTERVAL :  min_interval) :  radv_info->min_radv_interval; 
2148       lifetime  = (use_lifetime != 0) ? ( (is_no) ?  DEF_DEF_RTR_LIFETIME :  lifetime) :  radv_info->adv_router_lifetime_in_sec;
2149
2150       if(lifetime)
2151         {
2152           if(lifetime  > MAX_DEF_RTR_LIFETIME)
2153             lifetime = MAX_DEF_RTR_LIFETIME;
2154           
2155           if(lifetime <= max_interval)
2156             return VNET_API_ERROR_INVALID_VALUE;
2157         }
2158       
2159       if(min_interval  != 0)
2160         {
2161           if((min_interval > .75 * max_interval) ||
2162              (min_interval  < 3))
2163             return VNET_API_ERROR_INVALID_VALUE;
2164         }
2165
2166       if((initial_count  > MAX_INITIAL_RTR_ADVERTISEMENTS) ||
2167          (initial_interval  > MAX_INITIAL_RTR_ADVERT_INTERVAL))
2168         return VNET_API_ERROR_INVALID_VALUE;
2169
2170       /* 
2171          if "flag" is set and is_no is true then restore default value else set value corresponding to "flag" 
2172          if "flag" is clear  don't change corresponding value  
2173       */
2174       radv_info->send_radv =  (surpress != 0) ? ( (is_no  != 0) ? 1 : 0 ) : radv_info->send_radv;
2175       radv_info->adv_managed_flag = ( managed  != 0) ? ( (is_no) ? 0 : 1) : radv_info->adv_managed_flag;
2176       radv_info->adv_other_flag  = (other  != 0) ? ( (is_no) ?  0: 1) : radv_info->adv_other_flag;
2177       radv_info->adv_link_layer_address = ( ll_option != 0) ? ( (is_no) ? 1 : 0) : radv_info->adv_link_layer_address;
2178       radv_info->send_unicast  = (send_unicast  != 0) ? ( (is_no) ? 0 : 1) : radv_info->send_unicast;
2179       radv_info->cease_radv = ( cease != 0) ? ( (is_no) ?  0 : 1) : radv_info->cease_radv;
2180       
2181       radv_info->min_radv_interval  =  min_interval;
2182       radv_info->max_radv_interval = max_interval;
2183       radv_info->adv_router_lifetime_in_sec = lifetime;
2184
2185       radv_info->initial_adverts_count = 
2186         (initial_count  != 0) ? ( (is_no) ?   MAX_INITIAL_RTR_ADVERTISEMENTS  :  initial_count) : radv_info->initial_adverts_count ;
2187       radv_info->initial_adverts_interval = 
2188         (initial_interval  != 0) ? ( (is_no) ?  MAX_INITIAL_RTR_ADVERT_INTERVAL  :  initial_interval) : radv_info->initial_adverts_interval;
2189
2190       /* restart */
2191       if((cease != 0) && (is_no))
2192          radv_info-> send_radv = 1;
2193
2194       radv_info->initial_adverts_sent  = radv_info->initial_adverts_count -1;
2195       radv_info->next_multicast_time =  vlib_time_now (vm);    
2196       radv_info->last_multicast_time = vlib_time_now (vm);
2197       radv_info->last_radv_time = 0;    
2198     }
2199   return(error);
2200 }
2201
2202 int
2203 ip6_neighbor_ra_prefix(vlib_main_t * vm, u32 sw_if_index,  
2204                        ip6_address_t *prefix_addr,  u8 prefix_len,
2205                        u8 use_default,  u32 val_lifetime, u32 pref_lifetime,
2206                        u8 no_advertise,  u8 off_link, u8 no_autoconfig, u8 no_onlink,
2207                        u8 is_no)
2208 {
2209   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2210   int error;
2211   
2212   u32 ri;
2213
2214   /* look up the radv_t  information for this interface */
2215   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2216   
2217   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2218
2219   error = (ri != ~0) ? 0 : VNET_API_ERROR_INVALID_SW_IF_INDEX;
2220   
2221   if(!error)
2222     {
2223       f64 now = vlib_time_now (vm);
2224       ip6_radv_t * radv_info;
2225       radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
2226
2227       /* prefix info add, delete or update */
2228       ip6_radv_prefix_t * prefix; 
2229         
2230       /* lookup  prefix info for this  address on this interface */
2231       uword * p = mhash_get (&radv_info->address_to_prefix_index,  prefix_addr);
2232       
2233       prefix = p ? pool_elt_at_index (radv_info->adv_prefixes_pool, p[0]) : 0;
2234
2235       if(is_no)
2236         {
2237           /* delete */
2238           if(!prefix)
2239             return VNET_API_ERROR_INVALID_VALUE; /* invalid prefix */
2240     
2241           if(prefix->prefix_len != prefix_len)
2242             return VNET_API_ERROR_INVALID_VALUE_2;
2243
2244           /* FIXME - Should the DP do this or the CP ?*/
2245           /* do specific delete processing here before returning */
2246           /* try to remove from routing table */
2247
2248           mhash_unset (&radv_info->address_to_prefix_index, prefix_addr,/* old_value */ 0);
2249           pool_put (radv_info->adv_prefixes_pool, prefix);
2250
2251           radv_info->initial_adverts_sent  = radv_info->initial_adverts_count -1;
2252           radv_info->next_multicast_time =  vlib_time_now (vm);    
2253           radv_info->last_multicast_time = vlib_time_now (vm);
2254           radv_info->last_radv_time = 0;        
2255           return(error);
2256         }
2257
2258       /* adding or changing */
2259       if(!prefix)
2260         {
2261           /* add */
2262           u32 pi;
2263           pool_get (radv_info->adv_prefixes_pool, prefix);
2264           pi = prefix - radv_info->adv_prefixes_pool;
2265           mhash_set (&radv_info->address_to_prefix_index,  prefix_addr,  pi, /* old_value */ 0);
2266           
2267           memset(prefix, 0x0, sizeof(ip6_radv_prefix_t));
2268           
2269           prefix->prefix_len = prefix_len;
2270           memcpy(&prefix->prefix,  prefix_addr, sizeof(ip6_address_t));
2271           
2272           /* initialize default values */
2273           prefix->adv_on_link_flag = 1;      /* L bit set */
2274           prefix->adv_autonomous_flag = 1;  /* A bit set */
2275           prefix->adv_valid_lifetime_in_secs =  DEF_ADV_VALID_LIFETIME;
2276           prefix->adv_pref_lifetime_in_secs = DEF_ADV_PREF_LIFETIME;
2277           prefix->enabled = 1;
2278           prefix->decrement_lifetime_flag = 1;
2279           prefix->deprecated_prefix_flag = 1;
2280
2281           if(off_link == 0)
2282             {
2283               /* FIXME - Should the DP do this or the CP ?*/
2284               /* insert prefix into routing table as a connected prefix */
2285             }
2286
2287           if(use_default)
2288             goto restart;
2289         }
2290       else
2291         {
2292           
2293           if(prefix->prefix_len != prefix_len)
2294             return VNET_API_ERROR_INVALID_VALUE_2;
2295
2296           if(off_link  != 0)
2297             {
2298               /* FIXME - Should the DP do this or the CP ?*/
2299               /* remove from routing table if already there */
2300             }     
2301         }
2302
2303       if((val_lifetime == ~0) || (pref_lifetime == ~0))
2304         {
2305           prefix->adv_valid_lifetime_in_secs =  ~0;
2306           prefix->adv_pref_lifetime_in_secs = ~0;
2307           prefix->decrement_lifetime_flag = 0;
2308         }
2309       else
2310         {
2311           prefix->adv_valid_lifetime_in_secs =  val_lifetime;;
2312           prefix->adv_pref_lifetime_in_secs =  pref_lifetime;
2313         }
2314       
2315       /* copy  remaining */
2316       prefix->enabled = !(no_advertise != 0);
2317       prefix->adv_on_link_flag = !((off_link != 0) || (no_onlink != 0));
2318       prefix->adv_autonomous_flag = !(no_autoconfig != 0);
2319
2320  restart:
2321       /* restart */
2322       /* fill in the expiration times  */
2323       prefix->valid_lifetime_expires = now + prefix->adv_valid_lifetime_in_secs;
2324       prefix->pref_lifetime_expires = now + prefix->adv_pref_lifetime_in_secs;
2325           
2326       radv_info->initial_adverts_sent  = radv_info->initial_adverts_count -1;
2327       radv_info->next_multicast_time =  vlib_time_now (vm);    
2328       radv_info->last_multicast_time = vlib_time_now (vm);
2329       radv_info->last_radv_time = 0;    
2330     }
2331   return(error);
2332 }
2333
2334 clib_error_t *
2335 ip6_neighbor_cmd(vlib_main_t * vm, unformat_input_t * main_input, vlib_cli_command_t * cmd)
2336 {
2337   vnet_main_t * vnm = vnet_get_main();
2338   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2339   clib_error_t * error = 0;
2340   u8 is_no = 0;
2341   u8 surpress = 0,  managed = 0,  other = 0;
2342   u8 surpress_ll_option = 0,  send_unicast = 0,  cease= 0; 
2343   u8 use_lifetime = 0;
2344   u32 sw_if_index, ra_lifetime = 0, ra_initial_count = 0, ra_initial_interval = 0;
2345   u32 ra_max_interval = 0 , ra_min_interval = 0;
2346
2347   unformat_input_t _line_input, * line_input = &_line_input;
2348   vnet_sw_interface_t * sw_if0;
2349
2350   int add_radv_info = 1;
2351   __attribute__((unused)) ip6_radv_t * radv_info = 0;
2352   ip6_address_t ip6_addr;
2353   u32 addr_len;
2354  
2355
2356   /* Get a line of input. */
2357   if (! unformat_user (main_input, unformat_line_input, line_input))
2358     return 0;
2359
2360   /* get basic radv info for this interface */
2361   if(unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2362     {
2363
2364       if (unformat_user (line_input, 
2365                          unformat_vnet_sw_interface, vnm, &sw_if_index))
2366         {
2367           u32 ri;
2368           ethernet_interface_t * eth_if0 = 0;
2369           
2370           sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
2371           if(sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
2372             eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
2373           
2374           if(!eth_if0)
2375             {
2376               error = clib_error_return (0, "Interface must be of ethernet type");
2377               goto done;
2378             }
2379           
2380           /* look up the radv_t  information for this interface */
2381           vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2382           
2383           ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2384           
2385           if(ri != ~0)
2386             {
2387               radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
2388             }
2389           else
2390             {
2391               error = clib_error_return (0, "unknown interface %U'",
2392                                          format_unformat_error, line_input);
2393               goto done;
2394             }
2395         }
2396       else
2397         {
2398           error = clib_error_return (0, "invalid interface name %U'",
2399                                      format_unformat_error, line_input);
2400           goto done;
2401         }
2402     }
2403
2404   /* get the rest of the command */
2405   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2406     {
2407       if (unformat (line_input, "no"))
2408          is_no = 1;
2409       else if(unformat (line_input, "prefix %U/%d",
2410                         unformat_ip6_address, &ip6_addr,
2411                         &addr_len))
2412         {
2413           add_radv_info = 0;
2414           break;
2415         }
2416       else if (unformat (line_input, "ra-managed-config-flag"))
2417         {
2418           managed = 1;
2419           break;
2420         }
2421       else if (unformat (line_input, "ra-other-config-flag"))
2422         {
2423           other = 1;
2424           break;
2425         }
2426       else if (unformat (line_input, "ra-surpress"))
2427         {
2428           surpress = 1;
2429           break;
2430         }
2431       else if (unformat (line_input, "ra-surpress-link-layer"))
2432         {
2433           surpress_ll_option = 1;
2434           break;
2435         }
2436       else if (unformat (line_input, "ra-send-unicast"))
2437         {
2438           send_unicast = 1;
2439           break;
2440         }
2441       else if (unformat (line_input, "ra-lifetime"))
2442         {
2443           if (!unformat (line_input, "%d", &ra_lifetime))
2444             return(error = unformat_parse_error (line_input));
2445           use_lifetime = 1;
2446           break;
2447         }  
2448       else if (unformat (line_input, "ra-initial"))
2449         {
2450           if (!unformat (line_input, "%d %d", &ra_initial_count, &ra_initial_interval))
2451             return(error = unformat_parse_error (line_input));
2452           break;
2453         }
2454       else if (unformat (line_input, "ra-interval"))
2455         {
2456           if (!unformat (line_input, "%d", &ra_max_interval))
2457             return(error = unformat_parse_error (line_input));
2458
2459           if (!unformat (line_input, "%d", &ra_min_interval))
2460             ra_min_interval = 0;
2461           break;
2462         }
2463       else if(unformat (line_input, "ra-cease"))
2464         {
2465           cease = 1;
2466           break;
2467         }
2468       else
2469         return(unformat_parse_error (line_input));
2470     }
2471
2472   if(add_radv_info)
2473     {
2474       ip6_neighbor_ra_config(vm,  sw_if_index, 
2475                              surpress, managed, other,
2476                              surpress_ll_option,  send_unicast,  cease, 
2477                              use_lifetime,  ra_lifetime,
2478                              ra_initial_count,  ra_initial_interval,  
2479                              ra_max_interval,  ra_min_interval,
2480                              is_no);
2481     }
2482   else
2483     {
2484       u32 valid_lifetime_in_secs =  0;
2485       u32 pref_lifetime_in_secs = 0;
2486       u8 use_prefix_default_values = 0;
2487       u8  no_advertise = 0;
2488       u8 off_link= 0;
2489       u8 no_autoconfig = 0;
2490       u8 no_onlink= 0;
2491
2492       /* get the rest of the command */
2493       while(unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2494         {
2495           if(unformat (line_input, "default"))
2496             {
2497               use_prefix_default_values = 1;
2498               break;
2499             }
2500           else if(unformat (line_input, "infinite"))
2501             {
2502               valid_lifetime_in_secs =  ~0;
2503               pref_lifetime_in_secs = ~0;
2504               break;
2505             }
2506           else if(unformat (line_input, "%d %d", &valid_lifetime_in_secs, 
2507                             &pref_lifetime_in_secs))
2508             break;
2509           else
2510             break;
2511         }
2512
2513
2514       /* get the rest of the command */
2515       while (!use_prefix_default_values &&
2516              unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2517         {
2518           if(unformat (line_input, "no-advertise"))
2519             no_advertise = 1;
2520           else if(unformat (line_input, "off-link"))
2521             off_link = 1;
2522           else if(unformat (line_input, "no-autoconfig"))
2523             no_autoconfig = 1;
2524           else if(unformat (line_input, "no-onlink"))
2525             no_onlink = 1;
2526           else
2527             return(unformat_parse_error (line_input));
2528         }
2529         
2530       ip6_neighbor_ra_prefix(vm, sw_if_index,  
2531                              &ip6_addr,  addr_len,
2532                              use_prefix_default_values,  
2533                              valid_lifetime_in_secs,
2534                              pref_lifetime_in_secs,
2535                              no_advertise,
2536                              off_link,
2537                              no_autoconfig,
2538                              no_onlink,
2539                              is_no);
2540     }
2541
2542   unformat_free (line_input);
2543   
2544  done:
2545   return error;
2546 }
2547
2548 static clib_error_t *
2549 show_ip6_interface_cmd (vlib_main_t * vm,
2550                     unformat_input_t * input,
2551                     vlib_cli_command_t * cmd)
2552 {
2553   vnet_main_t * vnm = vnet_get_main();
2554   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2555   clib_error_t * error = 0;
2556   u32 sw_if_index;
2557
2558   sw_if_index = ~0;
2559
2560  if (unformat_user (input, 
2561                       unformat_vnet_sw_interface, vnm, &sw_if_index))
2562     {
2563       u32 ri;
2564       
2565       /* look up the radv_t  information for this interface */
2566       vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2567       
2568       ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2569       
2570       if(ri != ~0)
2571         {
2572           ip_lookup_main_t * lm = &ip6_main.lookup_main;
2573           ip6_radv_t * radv_info;
2574           radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
2575
2576           vlib_cli_output (vm, "%U is admin %s\n", format_vnet_sw_interface_name, vnm, 
2577                            vnet_get_sw_interface (vnm, sw_if_index),
2578                            (vnet_sw_interface_is_admin_up (vnm, sw_if_index) ? "up" : "down"));
2579       
2580           u32 ai; 
2581           u32 *global_scope = 0,i;
2582           ip_interface_address_t * a;
2583
2584           vec_validate_init_empty (lm->if_address_pool_index_by_sw_if_index, sw_if_index, ~0);
2585           ai = lm->if_address_pool_index_by_sw_if_index[sw_if_index];
2586
2587           while (ai != (u32)~0)
2588             {
2589               a = pool_elt_at_index(lm->if_address_pool, ai);
2590               ip6_address_t * address = ip_interface_address_get_address (lm, a);
2591
2592               if( ip6_address_is_link_local_unicast (address))
2593                 vlib_cli_output (vm, "\tIPv6 is enabled, link-local address is %U\n", format_ip6_address, 
2594                                  address);
2595
2596               if((address->as_u8[0] & 0xe0) == 0x20)
2597                 vec_add1 (global_scope, ai);
2598
2599               ai = a->next_this_sw_interface;
2600             }
2601
2602           vlib_cli_output (vm, "\tGlobal unicast address(es):\n");
2603           for (i = 0; i < vec_len (global_scope); i++)
2604             { 
2605               a = pool_elt_at_index(lm->if_address_pool, global_scope[i]);
2606               ip6_address_t * address = ip_interface_address_get_address (lm, a);
2607               ip6_address_t mask, subnet;
2608
2609               subnet = *address;
2610               ip6_address_mask_from_width(&mask, a->address_length);
2611               ip6_address_mask(&subnet, &mask);
2612
2613               vlib_cli_output (vm, "\t\t%U, subnet is %U/%d", 
2614                                format_ip6_address, address, 
2615                                format_ip6_address,&subnet,
2616                                a->address_length);
2617             }
2618           vec_free (global_scope);
2619           vlib_cli_output (vm, "\tJoined group address(es):\n");
2620           ip6_mldp_group_t *m;
2621           pool_foreach (m, radv_info->mldp_group_pool, ({
2622                 vlib_cli_output (vm, "\t\t%U\n", format_ip6_address, &m->mcast_address);
2623               }));
2624
2625           vlib_cli_output (vm, "\tAdvertised Prefixes:\n");
2626           ip6_radv_prefix_t * p;
2627           pool_foreach (p, radv_info->adv_prefixes_pool, ({
2628                 vlib_cli_output (vm, "\t\tprefix %U,  length %d\n", 
2629                                  format_ip6_address, &p->prefix, p->prefix_len);
2630               }));
2631
2632           vlib_cli_output (vm, "\tMTU is %d\n",  radv_info->adv_link_mtu);
2633           vlib_cli_output (vm, "\tICMP error messages are unlimited\n");
2634           vlib_cli_output (vm, "\tICMP redirects are disabled\n");
2635           vlib_cli_output (vm, "\tICMP unreachables are not sent\n");
2636           vlib_cli_output (vm, "\tND DAD is disabled\n");
2637           //vlib_cli_output (vm, "\tND reachable time is %d milliseconds\n",);
2638           vlib_cli_output (vm, "\tND advertised reachable time is %d\n",
2639                            radv_info->adv_neighbor_reachable_time_in_msec);
2640           vlib_cli_output (vm, "\tND advertised retransmit interval is %d (msec)\n",
2641                            radv_info->adv_time_in_msec_between_retransmitted_neighbor_solicitations);
2642
2643           u32 ra_interval = radv_info->max_radv_interval;
2644           u32 ra_interval_min = radv_info->min_radv_interval;
2645           vlib_cli_output (vm, "\tND router advertisements are sent every %d seconds (min interval is %d)\n", 
2646                            ra_interval, ra_interval_min);
2647           vlib_cli_output (vm, "\tND router advertisements live for %d seconds\n",
2648                            radv_info->adv_router_lifetime_in_sec);
2649           vlib_cli_output (vm, "\tHosts %s stateless autoconfig for addresses\n",
2650                              (radv_info->adv_managed_flag) ? "use" :" don't use");
2651           vlib_cli_output (vm, "\tND router advertisements sent %d\n",  radv_info->n_advertisements_sent);
2652           vlib_cli_output (vm, "\tND router solicitations received %d\n",  radv_info->n_solicitations_rcvd);
2653           vlib_cli_output (vm, "\tND router solicitations dropped %d\n",  radv_info->n_solicitations_dropped);
2654         }
2655       else
2656         {
2657           error = clib_error_return (0, "Ipv6 not enabled on interface",
2658                                      format_unformat_error, input);
2659
2660         }
2661     }
2662   return error;
2663 }
2664
2665 VLIB_CLI_COMMAND (show_ip6_interface_command, static) = {
2666   .path = "show ip6 interface",
2667   .function = show_ip6_interface_cmd,
2668   .short_help = "Show ip6 interface <iface name>",
2669 };
2670
2671 clib_error_t *
2672 disable_ip6_interface(vlib_main_t * vm,
2673                       u32 sw_if_index)
2674 {
2675   clib_error_t * error = 0;
2676   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2677   u32 ri;
2678
2679   /* look up the radv_t  information for this interface */
2680   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);      
2681   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2682   
2683   /* if not created - do nothing */
2684   if(ri != ~0)
2685     {
2686       vnet_main_t * vnm = vnet_get_main();
2687       ip6_radv_t * radv_info;
2688   
2689       radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
2690
2691       /* check radv_info ref count for other ip6 addresses on this interface */
2692       if(radv_info->ref_count == 0 )
2693         {
2694           /* essentially "disables" ipv6 on this interface */
2695           error = ip6_add_del_interface_address (vm, sw_if_index,
2696                                                  &radv_info->link_local_address, 
2697                                                  radv_info->link_local_prefix_len,
2698                                                  1 /* is_del */);
2699
2700           ip6_neighbor_sw_interface_add_del (vnm, sw_if_index,  0/* is_add */);
2701         }
2702     }
2703   return error;
2704 }
2705
2706 int
2707 ip6_interface_enabled(vlib_main_t * vm,
2708                       u32 sw_if_index)
2709 {
2710     ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2711     u32 ri = ~0;
2712
2713     /* look up the radv_t  information for this interface */
2714     vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2715
2716     ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2717
2718     return ri != ~0;
2719 }
2720
2721 clib_error_t * 
2722 enable_ip6_interface(vlib_main_t * vm,
2723                     u32 sw_if_index)
2724 {
2725   clib_error_t * error = 0;
2726   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2727   u32 ri;
2728   int is_add = 1;
2729
2730   /* look up the radv_t  information for this interface */
2731   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2732       
2733   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2734   
2735   /* if not created yet */
2736   if(ri == ~0)
2737     {
2738       vnet_main_t * vnm = vnet_get_main();
2739       vnet_sw_interface_t * sw_if0;
2740  
2741       sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
2742       if(sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
2743         {
2744           ethernet_interface_t * eth_if0;
2745
2746           eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);         
2747           if(eth_if0)
2748             {
2749               /* create radv_info. for this interface.  This holds all the info needed for router adverts */
2750               ri = ip6_neighbor_sw_interface_add_del (vnm, sw_if_index, is_add);
2751
2752               if(ri != ~0)
2753                 {
2754                   ip6_radv_t * radv_info;
2755                   ip6_address_t link_local_address;
2756
2757                   radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
2758
2759                   ip6_link_local_address_from_ethernet_mac_address (&link_local_address,
2760                                                                     eth_if0->address);
2761
2762                   sw_if0 = vnet_get_sw_interface (vnm, sw_if_index);
2763                   if(sw_if0->type == VNET_SW_INTERFACE_TYPE_SUB)
2764                     {
2765                       /* make up  an interface id */
2766                       md5_context_t m;
2767                       u8 digest[16];
2768                       
2769                       link_local_address.as_u64[0] = radv_info->randomizer;
2770                       
2771                       md5_init (&m);
2772                       md5_add (&m, &link_local_address, 16);
2773                       md5_finish (&m,  digest);
2774                       
2775                       memcpy(&link_local_address, digest, 16);
2776                       
2777                       radv_info->randomizer = link_local_address.as_u64[0];
2778                       
2779                       link_local_address.as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL);
2780                       /* clear u bit */
2781                       link_local_address.as_u8[8] &= 0xfd;
2782                     }
2783                   
2784                   /* essentially "enables" ipv6 on this interface */
2785                   error = ip6_add_del_interface_address (vm, sw_if_index,
2786                                                          &link_local_address, 64 /* address width */,
2787                                                          0 /* is_del */);
2788                   
2789                   if(error)
2790                       ip6_neighbor_sw_interface_add_del (vnm, sw_if_index, !is_add);
2791                   else
2792                     {
2793                       radv_info->link_local_address =  link_local_address;
2794                       radv_info->link_local_prefix_len  = 64;
2795                     }
2796                 }
2797             } 
2798         }
2799     }
2800   return error;
2801 }
2802
2803 static clib_error_t *
2804 enable_ip6_interface_cmd (vlib_main_t * vm,
2805                     unformat_input_t * input,
2806                     vlib_cli_command_t * cmd)
2807 {
2808   vnet_main_t * vnm = vnet_get_main();
2809   clib_error_t * error = 0;
2810   u32 sw_if_index;
2811
2812   sw_if_index = ~0;
2813
2814  if (unformat_user (input, 
2815                       unformat_vnet_sw_interface, vnm, &sw_if_index))
2816     {
2817       enable_ip6_interface(vm, sw_if_index);
2818     }
2819  else
2820    {
2821      error = clib_error_return (0, "unknown interface\n'",
2822                                 format_unformat_error, input);
2823      
2824    }
2825   return error;
2826 }
2827
2828 VLIB_CLI_COMMAND (enable_ip6_interface_command, static) = {
2829   .path = "enable ip6 interface",
2830   .function = enable_ip6_interface_cmd,
2831   .short_help = "enable ip6 interface <iface name>",
2832 };
2833
2834 static clib_error_t *
2835 disable_ip6_interface_cmd (vlib_main_t * vm,
2836                     unformat_input_t * input,
2837                     vlib_cli_command_t * cmd)
2838 {
2839   vnet_main_t * vnm = vnet_get_main();
2840   clib_error_t * error = 0;
2841   u32 sw_if_index;
2842
2843   sw_if_index = ~0;
2844
2845  if (unformat_user (input, 
2846                       unformat_vnet_sw_interface, vnm, &sw_if_index))
2847     {
2848       error = disable_ip6_interface(vm, sw_if_index);
2849     }
2850  else
2851    {
2852      error = clib_error_return (0, "unknown interface\n'",
2853                                 format_unformat_error, input);
2854      
2855    }
2856   return error;
2857 }
2858
2859 VLIB_CLI_COMMAND (disable_ip6_interface_command, static) = {
2860   .path = "disable  ip6 interface",
2861   .function = disable_ip6_interface_cmd,
2862   .short_help = "disable ip6 interface <iface name>",
2863 };
2864
2865 VLIB_CLI_COMMAND (ip6_nd_command, static) = {
2866   .path = "ip6 nd",
2867   .short_help = "Set ip6 neighbor discovery parameters",
2868   .function = ip6_neighbor_cmd,
2869 };
2870
2871 clib_error_t *
2872 set_ip6_link_local_address(vlib_main_t * vm,
2873                            u32 sw_if_index,
2874                            ip6_address_t *address,
2875                            u8 address_length)
2876 {
2877   clib_error_t * error = 0;
2878   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2879   u32 ri;
2880   ip6_radv_t * radv_info;
2881   vnet_main_t * vnm = vnet_get_main();
2882
2883   if( !ip6_address_is_link_local_unicast (address))
2884     {
2885       vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_LINK_LOCAL;
2886       return(error = clib_error_return (0, "address not link-local",
2887                                         format_unformat_error));
2888     }
2889
2890   /* call enable ipv6  */
2891   enable_ip6_interface(vm, sw_if_index);
2892           
2893   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2894          
2895   if(ri != ~0)
2896     {
2897       radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
2898
2899       /* save if link local address (overwrite default) */
2900    
2901       /* delete the old one */
2902       error = ip6_add_del_interface_address (vm, sw_if_index,
2903                                              &radv_info->link_local_address,
2904                                              radv_info->link_local_prefix_len  /* address width */,
2905                                              1 /* is_del */);
2906       
2907       if(!error)
2908         {
2909           /* add the new one */
2910           error = ip6_add_del_interface_address (vm, sw_if_index,
2911                                                  address ,
2912                                                  address_length  /* address width */,
2913                                                  0/* is_del */);
2914           
2915           if(!error)
2916             {
2917               radv_info->link_local_address = *address;
2918               radv_info->link_local_prefix_len  = address_length;
2919             }
2920         }
2921     }
2922   else
2923     {
2924       vnm->api_errno = VNET_API_ERROR_IP6_NOT_ENABLED;
2925       error = clib_error_return (0, "ip6 not enabled for interface",
2926                                  format_unformat_error);
2927     }
2928   return error;
2929 }
2930   
2931 clib_error_t *
2932 set_ip6_link_local_address_cmd (vlib_main_t * vm,
2933                                 unformat_input_t * input,
2934                                 vlib_cli_command_t * cmd)
2935 {
2936   vnet_main_t * vnm = vnet_get_main();
2937   clib_error_t * error = 0;
2938   u32 sw_if_index;
2939   ip6_address_t ip6_addr;
2940   u32 addr_len = 0;
2941  
2942   if (unformat_user (input, 
2943                      unformat_vnet_sw_interface, vnm, &sw_if_index))
2944     {
2945       /* get the rest of the command */
2946       while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2947         {
2948           if(unformat (input, "%U/%d",
2949                        unformat_ip6_address, &ip6_addr,
2950                        &addr_len))
2951             break;
2952           else
2953             return(unformat_parse_error (input));
2954         }
2955     }
2956   error = set_ip6_link_local_address(vm,
2957                                      sw_if_index,
2958                                      &ip6_addr,
2959                                      addr_len);
2960   return error;
2961 }
2962
2963 VLIB_CLI_COMMAND (set_ip6_link_local_address_command, static) = {
2964   .path = "set ip6 link-local address",
2965   .short_help = "Set ip6 interface link-local address <intfc> <address.>",
2966   .function = set_ip6_link_local_address_cmd,
2967 };
2968
2969 /* callback when an interface address is added or deleted */
2970 static void
2971 ip6_neighbor_add_del_interface_address (ip6_main_t * im,
2972                                         uword opaque,
2973                                         u32 sw_if_index,
2974                                         ip6_address_t * address,
2975                                         u32 address_length,
2976                                         u32 if_address_index,
2977                                         u32 is_delete)
2978 {
2979   vnet_main_t * vnm = vnet_get_main();
2980   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2981   u32 ri;
2982   vlib_main_t * vm = vnm->vlib_main;
2983   ip6_radv_t * radv_info;
2984   ip6_address_t a;
2985   ip6_mldp_group_t  *mcast_group_info;
2986
2987   /* create solicited node multicast address for this interface adddress */
2988   ip6_set_solicited_node_multicast_address (&a, 0);
2989  
2990   a.as_u8[0xd] = address->as_u8[0xd];
2991   a.as_u8[0xe] = address->as_u8[0xe];
2992   a.as_u8[0xf] = address->as_u8[0xf];
2993   
2994   if(!is_delete)
2995     {
2996       /* try to  create radv_info - does nothing if ipv6 already enabled */
2997       enable_ip6_interface(vm, sw_if_index);
2998
2999       /* look up the radv_t  information for this interface */
3000       vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
3001       ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3002       if(ri != ~0)
3003         {
3004           /* get radv_info */
3005           radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3006
3007           /* add address */
3008           if( !ip6_address_is_link_local_unicast (address))
3009             radv_info->ref_count++;
3010
3011           /* lookup  prefix info for this  address on this interface */
3012           uword * p = mhash_get (&radv_info->address_to_mldp_index,  &a);
3013           mcast_group_info = p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0;
3014
3015           /* add -solicted node multicast address  */
3016           if(!mcast_group_info)
3017             {
3018               /* add */
3019               u32 mi;
3020               pool_get (radv_info->mldp_group_pool, mcast_group_info);
3021               
3022               mi = mcast_group_info - radv_info->mldp_group_pool;
3023               mhash_set (&radv_info->address_to_mldp_index,  &a,  mi, /* old_value */ 0);
3024               
3025               mcast_group_info->type = 4;
3026               mcast_group_info->mcast_source_address_pool = 0;
3027               mcast_group_info->num_sources = 0;
3028               memcpy(&mcast_group_info->mcast_address, &a, sizeof(ip6_address_t));
3029             } 
3030         }
3031     }
3032   else
3033     {
3034
3035       /* delete */
3036       /* look up the radv_t  information for this interface */
3037       vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
3038       ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3039       if(ri != ~0)
3040         {
3041           /* get radv_info */
3042           radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3043
3044           /* lookup  prefix info for this  address on this interface */
3045           uword * p = mhash_get (&radv_info->address_to_mldp_index,  &a);
3046           mcast_group_info = p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0;
3047           
3048           if(mcast_group_info)
3049             {
3050               mhash_unset (&radv_info->address_to_mldp_index, &a,/* old_value */ 0);
3051               pool_put (radv_info->mldp_group_pool, mcast_group_info);
3052             }
3053
3054           /* if interface up send MLDP "report" */
3055           radv_info->all_routers_mcast = 0;
3056
3057           /* add address */
3058           if( !ip6_address_is_link_local_unicast (address))
3059             radv_info->ref_count--;
3060         }
3061     }
3062 }
3063
3064 clib_error_t *ip6_set_neighbor_limit (u32 neighbor_limit)
3065 {
3066   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3067
3068   nm->limit_neighbor_cache_size = neighbor_limit;
3069   return 0;
3070 }
3071
3072 static clib_error_t * ip6_neighbor_init (vlib_main_t * vm)
3073 {
3074   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3075   ip6_main_t * im = &ip6_main;
3076  
3077   mhash_init (&nm->neighbor_index_by_key,
3078               /* value size */ sizeof (uword),
3079               /* key size */ sizeof (ip6_neighbor_key_t));
3080
3081   icmp6_register_type (vm, ICMP6_neighbor_solicitation, ip6_icmp_neighbor_solicitation_node.index);
3082   icmp6_register_type (vm, ICMP6_neighbor_advertisement, ip6_icmp_neighbor_advertisement_node.index);
3083   icmp6_register_type (vm, ICMP6_router_solicitation, ip6_icmp_router_solicitation_node.index);
3084   icmp6_register_type (vm, ICMP6_router_advertisement, ip6_icmp_router_advertisement_node.index);
3085
3086   /* handler node for ip6 neighbor discovery events and timers */
3087   vlib_register_node (vm, &ip6_icmp_neighbor_discovery_event_node);
3088
3089   /* add call backs */
3090   ip6_add_del_interface_address_callback_t cb; 
3091   memset(&cb, 0x0, sizeof(ip6_add_del_interface_address_callback_t));
3092   
3093   /* when an interface address changes... */
3094   cb.function = ip6_neighbor_add_del_interface_address;
3095   cb.function_opaque = 0;
3096   vec_add1 (im->add_del_interface_address_callbacks, cb);
3097
3098   mhash_init (&nm->pending_resolutions_by_address,
3099               /* value size */ sizeof (uword),
3100               /* key size */ sizeof (ip6_address_t));
3101
3102   /* default, configurable */
3103   nm->limit_neighbor_cache_size = 50000;
3104
3105 #if 0
3106   /* $$$$ Hack fix for today */
3107   vec_validate_init_empty 
3108       (im->discover_neighbor_next_index_by_hw_if_index, 32, 0 /* drop */);
3109 #endif
3110
3111   return 0;
3112 }
3113
3114 VLIB_INIT_FUNCTION (ip6_neighbor_init);
3115
3116
3117 void vnet_register_ip6_neighbor_resolution_event (vnet_main_t * vnm, 
3118                                                   void * address_arg,
3119                                                   uword node_index,
3120                                                   uword type_opaque,
3121                                                   uword data)
3122 {
3123   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3124   ip6_address_t * address = address_arg;
3125   uword * p;
3126   pending_resolution_t * pr;
3127   
3128   pool_get (nm->pending_resolutions, pr);
3129
3130   pr->next_index = ~0;
3131   pr->node_index = node_index;
3132   pr->type_opaque = type_opaque;
3133   pr->data = data;
3134
3135   p = mhash_get (&nm->pending_resolutions_by_address, address);
3136   if (p)
3137     {
3138       /* Insert new resolution at the head of the list */
3139       pr->next_index = p[0];
3140       mhash_unset (&nm->pending_resolutions_by_address, address, 0);
3141     }
3142   
3143   mhash_set (&nm->pending_resolutions_by_address, address, 
3144              pr - nm->pending_resolutions, 0 /* old value */);
3145 }
3146