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