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