GRE tests and fixes
[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 #include <vnet/adj/adj.h>
23 #include <vnet/fib/fib_table.h>
24 #include <vnet/fib/ip6_fib.h>
25
26 #if DPDK==1
27 #include <vnet/devices/dpdk/dpdk.h>
28 #endif
29
30 /**
31  * @file
32  * @brief IPv6 Neighbor Adjacency and Neighbor Discovery.
33  *
34  * The files contains the API and CLI code for managing IPv6 neighbor
35  * adjacency tables and neighbor discovery logic.
36  */
37
38 typedef struct {
39   ip6_address_t ip6_address;
40   u32 sw_if_index;
41   u32 pad;
42 } ip6_neighbor_key_t;
43
44 /* can't use sizeof link_layer_address, that's 8 */ 
45 #define ETHER_MAC_ADDR_LEN 6
46
47 typedef struct {
48   ip6_neighbor_key_t key;
49   u8 link_layer_address[8];
50   u16 flags;
51 #define IP6_NEIGHBOR_FLAG_STATIC (1 << 0)
52 #define IP6_NEIGHBOR_FLAG_DYNAMIC  (2 << 0)
53   u64 cpu_time_last_updated;
54   fib_node_index_t fib_entry_index;
55 } ip6_neighbor_t;
56
57 /* advertised prefix option */ 
58 typedef struct {
59   /* basic advertised information */
60   ip6_address_t prefix;
61   u8 prefix_len;
62   int adv_on_link_flag;
63   int adv_autonomous_flag;
64   u32 adv_valid_lifetime_in_secs;
65   u32 adv_pref_lifetime_in_secs;
66
67   /* advertised values are computed from these times if decrementing */
68   f64 valid_lifetime_expires;
69   f64  pref_lifetime_expires;
70  
71   /* local information */
72   int enabled;
73   int deprecated_prefix_flag;
74   int decrement_lifetime_flag; 
75
76 #define MIN_ADV_VALID_LIFETIME 7203     /* seconds */
77 #define DEF_ADV_VALID_LIFETIME  2592000
78 #define DEF_ADV_PREF_LIFETIME 604800
79
80   /* extensions are added here, mobile, DNS etc.. */
81 } ip6_radv_prefix_t;
82
83
84 typedef struct {
85   /* group information */
86   u8 type;
87   ip6_address_t mcast_address;
88   u16 num_sources;
89   ip6_address_t *mcast_source_address_pool;
90 } ip6_mldp_group_t;
91
92 /* configured router advertisement information per ipv6 interface */
93 typedef struct {
94
95   /* advertised config information, zero means unspecified  */
96   u8  curr_hop_limit;
97   int adv_managed_flag;
98   int adv_other_flag;
99   u16 adv_router_lifetime_in_sec; 
100   u32 adv_neighbor_reachable_time_in_msec;
101   u32 adv_time_in_msec_between_retransmitted_neighbor_solicitations;
102
103   /* mtu option */
104   u32 adv_link_mtu;
105   
106   /* source link layer option */
107   u8  link_layer_address[8];
108   u8  link_layer_addr_len;
109
110   /* prefix option */
111   ip6_radv_prefix_t * adv_prefixes_pool;
112
113   /* Hash table mapping address to index in interface advertised  prefix pool. */
114   mhash_t address_to_prefix_index;
115
116   /* MLDP  group information */
117   ip6_mldp_group_t  * mldp_group_pool;
118
119   /* Hash table mapping address to index in mldp address pool. */
120   mhash_t address_to_mldp_index;
121
122   /* local information */
123   u32 sw_if_index;
124   u32 fib_index;
125   int send_radv;              /* radv on/off on this interface -  set by config */
126   int cease_radv;           /* we are ceasing  to send  - set byf config */
127   int send_unicast;
128   int adv_link_layer_address;
129   int prefix_option;
130   int failed_device_check;
131   int all_routers_mcast;
132   u32 seed;
133   u64 randomizer;
134   int ref_count;
135   adj_index_t all_nodes_adj_index;
136   adj_index_t all_routers_adj_index;
137   adj_index_t all_mldv2_routers_adj_index;
138   
139   /* timing information */
140 #define DEF_MAX_RADV_INTERVAL 200
141 #define DEF_MIN_RADV_INTERVAL .75 * DEF_MAX_RADV_INTERVAL
142 #define DEF_CURR_HOP_LIMIT  64
143 #define DEF_DEF_RTR_LIFETIME   3 * DEF_MAX_RADV_INTERVAL
144 #define MAX_DEF_RTR_LIFETIME   9000
145
146 #define MAX_INITIAL_RTR_ADVERT_INTERVAL   16  /* seconds */
147 #define MAX_INITIAL_RTR_ADVERTISEMENTS        3    /*transmissions */
148 #define MIN_DELAY_BETWEEN_RAS                              3  /* seconds */
149 #define MAX_DELAY_BETWEEN_RAS                    1800  /* seconds */
150 #define MAX_RA_DELAY_TIME                                          .5 /* seconds */
151
152   f64 max_radv_interval;
153   f64 min_radv_interval;
154   f64 min_delay_between_radv;
155   f64 max_delay_between_radv;
156   f64 max_rtr_default_lifetime;
157
158   f64 last_radv_time;
159   f64 last_multicast_time;
160   f64 next_multicast_time;
161
162
163   u32 initial_adverts_count;
164   f64 initial_adverts_interval; 
165   u32 initial_adverts_sent;
166
167   /* stats */
168   u32 n_advertisements_sent;
169   u32 n_solicitations_rcvd;
170   u32 n_solicitations_dropped;
171
172   /* Link local address to use (defaults to underlying physical for logical interfaces */
173   ip6_address_t link_local_address;
174   u8 link_local_prefix_len;
175
176 } ip6_radv_t;
177
178 typedef struct {
179   u32 next_index;
180   uword node_index;
181   uword type_opaque;
182   uword data;
183   /* Used for nd event notification only */
184   void * data_callback;
185   u32 pid;
186 } pending_resolution_t;
187
188
189 typedef struct {
190   /* Hash tables mapping name to opcode. */
191   uword * opcode_by_name;
192
193   /* lite beer "glean" adjacency handling */
194   mhash_t pending_resolutions_by_address;
195   pending_resolution_t * pending_resolutions;
196
197   /* Mac address change notification */
198   mhash_t mac_changes_by_address;
199   pending_resolution_t * mac_changes;
200
201   u32 * neighbor_input_next_index_by_hw_if_index;
202
203   ip6_neighbor_t * neighbor_pool;
204
205   mhash_t neighbor_index_by_key;
206
207   u32 * if_radv_pool_index_by_sw_if_index;
208
209   ip6_radv_t * if_radv_pool;
210
211   /* Neighbor attack mitigation */
212   u32 limit_neighbor_cache_size;
213   u32 neighbor_delete_rotor;
214
215 } ip6_neighbor_main_t;
216
217 static ip6_neighbor_main_t ip6_neighbor_main;
218 static ip6_address_t ip6a_zero;    /* ip6 address 0 */
219
220 static u8 * format_ip6_neighbor_ip6_entry (u8 * s, va_list * va)
221 {
222   vlib_main_t * vm = va_arg (*va, vlib_main_t *);
223   ip6_neighbor_t * n = va_arg (*va, ip6_neighbor_t *);
224   vnet_main_t * vnm = vnet_get_main();
225   vnet_sw_interface_t * si;
226   u8 * flags = 0;
227
228   if (! n)
229     return format (s, "%=12s%=20s%=6s%=20s%=40s", "Time", "Address", "Flags", "Link layer", "Interface");
230
231   if (n->flags & IP6_NEIGHBOR_FLAG_DYNAMIC)
232     flags = format(flags, "D");
233
234   if (n->flags & IP6_NEIGHBOR_FLAG_STATIC)
235     flags = format(flags, "S");
236
237   si = vnet_get_sw_interface (vnm, n->key.sw_if_index);
238   s = format (s, "%=12U%=20U%=6s%=20U%=40U",
239               format_vlib_cpu_time, vm, n->cpu_time_last_updated,
240               format_ip6_address, &n->key.ip6_address,
241               flags ? (char *)flags : "",
242               format_ethernet_address, n->link_layer_address,
243               format_vnet_sw_interface_name, vnm, si);
244
245   vec_free(flags);
246   return s;
247 }
248
249 static clib_error_t *
250 ip6_neighbor_sw_interface_up_down (vnet_main_t * vnm,
251                                    u32 sw_if_index,
252                                    u32 flags)
253 {
254   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
255   ip6_neighbor_t * n;
256  
257   if (! (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
258     {
259       u32 i, * to_delete = 0;
260
261       pool_foreach (n, nm->neighbor_pool, ({
262         if (n->key.sw_if_index == sw_if_index)
263           vec_add1 (to_delete, n - nm->neighbor_pool);
264       }));
265
266       for (i = 0; i < vec_len (to_delete); i++)
267         {
268           n = pool_elt_at_index (nm->neighbor_pool, to_delete[i]);
269           mhash_unset (&nm->neighbor_index_by_key, &n->key, 0);
270           fib_table_entry_delete_index (n->fib_entry_index,  FIB_SOURCE_ADJ);
271           pool_put (nm->neighbor_pool, n);
272         }
273
274       vec_free (to_delete);
275     }
276
277   return 0;
278 }
279
280 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_neighbor_sw_interface_up_down);
281
282 static void unset_random_neighbor_entry (void)
283 {
284   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
285   vnet_main_t * vnm = vnet_get_main();
286   vlib_main_t * vm = vnm->vlib_main;
287   ip6_neighbor_t * e;
288   u32 index;
289
290   index = pool_next_index (nm->neighbor_pool, nm->neighbor_delete_rotor);
291   nm->neighbor_delete_rotor = index;
292
293   /* Try again from elt 0, could happen if an intfc goes down */
294   if (index == ~0)
295     {
296       index = pool_next_index (nm->neighbor_pool, nm->neighbor_delete_rotor);
297       nm->neighbor_delete_rotor = index;
298     }
299
300   /* Nothing left in the pool */
301   if (index == ~0)
302     return;
303
304   e = pool_elt_at_index (nm->neighbor_pool, index);
305   
306   vnet_unset_ip6_ethernet_neighbor (vm, e->key.sw_if_index,
307                                     &e->key.ip6_address, 
308                                     e->link_layer_address,
309                                     ETHER_MAC_ADDR_LEN);
310 }
311
312 typedef struct {
313   u8 is_add;
314   u8 is_static;
315   u8 link_layer_address[6];
316   u32 sw_if_index;
317   ip6_address_t addr;
318 } ip6_neighbor_set_unset_rpc_args_t;
319
320 #if DPDK > 0
321 static void ip6_neighbor_set_unset_rpc_callback 
322 ( ip6_neighbor_set_unset_rpc_args_t * a);
323
324 static void set_unset_ip6_neighbor_rpc 
325 (vlib_main_t * vm,
326  u32 sw_if_index,
327  ip6_address_t * a,
328  u8 *link_layer_addreess,
329  int is_add, int is_static)
330 {
331   ip6_neighbor_set_unset_rpc_args_t args;
332   void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
333   
334   args.sw_if_index = sw_if_index;
335   args.is_add = is_add;
336   args.is_static = is_static;
337   clib_memcpy (&args.addr, a, sizeof (*a));
338   clib_memcpy (args.link_layer_address, link_layer_addreess, 6);
339   
340   vl_api_rpc_call_main_thread (ip6_neighbor_set_unset_rpc_callback,
341                                (u8 *) &args, sizeof (args));
342 }
343 #endif
344
345 static void
346 ip6_nbr_probe (ip_adjacency_t *adj)
347 {
348   icmp6_neighbor_solicitation_header_t * h;
349   vnet_main_t * vnm = vnet_get_main();
350   ip6_main_t * im = &ip6_main;
351   ip_interface_address_t * ia;
352   ip6_address_t * dst, *src;
353   vnet_hw_interface_t * hi;
354   vnet_sw_interface_t * si;
355   vlib_buffer_t * b;
356   int bogus_length;
357   vlib_main_t * vm;
358   u32 bi = 0;
359
360   vm = vlib_get_main();
361
362   si = vnet_get_sw_interface(vnm, adj->rewrite_header.sw_if_index);
363   dst = &adj->sub_type.nbr.next_hop.ip6;
364
365   if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
366     {
367       return;
368     }
369   src = ip6_interface_address_matching_destination(im, dst,
370                                                    adj->rewrite_header.sw_if_index,
371                                                    &ia);
372   if (! src)
373     {
374       return;
375     }
376
377   h = vlib_packet_template_get_packet(vm,
378                                       &im->discover_neighbor_packet_template,
379                                       &bi);
380
381   hi = vnet_get_sup_hw_interface(vnm, adj->rewrite_header.sw_if_index);
382
383   h->ip.dst_address.as_u8[13] = dst->as_u8[13];
384   h->ip.dst_address.as_u8[14] = dst->as_u8[14];
385   h->ip.dst_address.as_u8[15] = dst->as_u8[15];
386   h->ip.src_address = src[0];
387   h->neighbor.target_address = dst[0];
388
389   clib_memcpy (h->link_layer_option.ethernet_address,
390                hi->hw_address,
391                vec_len(hi->hw_address));
392
393   h->neighbor.icmp.checksum =
394       ip6_tcp_udp_icmp_compute_checksum(vm, 0, &h->ip, &bogus_length);
395   ASSERT(bogus_length == 0);
396
397   b = vlib_get_buffer (vm, bi);
398   vnet_buffer (b)->sw_if_index[VLIB_RX] =
399       vnet_buffer (b)->sw_if_index[VLIB_TX] =
400       adj->rewrite_header.sw_if_index;
401
402   /* Add encapsulation string for software interface (e.g. ethernet header). */
403   vnet_rewrite_one_header(adj[0], h, sizeof (ethernet_header_t));
404   vlib_buffer_advance(b, -adj->rewrite_header.data_bytes);
405
406   {
407       vlib_frame_t * f = vlib_get_frame_to_node(vm, hi->output_node_index);
408       u32 * to_next = vlib_frame_vector_args(f);
409       to_next[0] = bi;
410       f->n_vectors = 1;
411       vlib_put_frame_to_node(vm, hi->output_node_index, f);
412   }
413 }
414
415 static void
416 ip6_nd_mk_complete (adj_index_t ai, ip6_neighbor_t * nbr)
417 {
418   adj_nbr_update_rewrite (ai, ADJ_NBR_REWRITE_FLAG_COMPLETE,
419                           ethernet_build_rewrite (vnet_get_main (),
420                                                   nbr->key.sw_if_index,
421                                                   adj_get_link_type(ai),
422                                                   nbr->link_layer_address));
423 }
424
425 static void
426 ip6_nd_mk_incomplete (adj_index_t ai, ip6_neighbor_t * nbr)
427 {
428   adj_nbr_update_rewrite (
429       ai,
430       ADJ_NBR_REWRITE_FLAG_INCOMPLETE,
431       ethernet_build_rewrite (vnet_get_main (),
432                               nbr->key.sw_if_index,
433                               adj_get_link_type(ai),
434                               VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
435 }
436
437 #define IP6_NBR_MK_KEY(k, sw_if_index, addr) \
438 {                                            \
439     k.sw_if_index = sw_if_index;             \
440     k.ip6_address = *addr;                   \
441     k.pad = 0;                               \
442 }
443
444 static ip6_neighbor_t *
445 ip6_nd_find (u32 sw_if_index,
446              const ip6_address_t * addr)
447 {
448   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
449   ip6_neighbor_t * n = NULL;
450   ip6_neighbor_key_t k;
451   uword *p;
452
453   IP6_NBR_MK_KEY(k, sw_if_index, addr);
454
455   p = mhash_get (&nm->neighbor_index_by_key, &k);
456   if (p) {
457     n = pool_elt_at_index (nm->neighbor_pool, p[0]);
458   }
459
460   return (n);
461 }
462
463 static adj_walk_rc_t
464 ip6_nd_mk_complete_walk (adj_index_t ai, void *ctx)
465 {
466   ip6_neighbor_t *nbr = ctx;
467
468   ip6_nd_mk_complete (ai, nbr);
469
470   return (ADJ_WALK_RC_CONTINUE);
471 }
472
473 static adj_walk_rc_t
474 ip6_nd_mk_incomplete_walk (adj_index_t ai, void *ctx)
475 {
476   ip6_neighbor_t *nbr = ctx;
477
478   ip6_nd_mk_incomplete (ai, nbr);
479
480   return (ADJ_WALK_RC_CONTINUE);
481 }
482
483 void
484 ip6_ethernet_update_adjacency (vnet_main_t * vnm,
485                                u32 sw_if_index,
486                                u32 ai)
487 {
488   ip6_neighbor_t *nbr;
489   ip_adjacency_t *adj;
490
491   adj = adj_get (ai);
492
493   nbr = ip6_nd_find (sw_if_index, &adj->sub_type.nbr.next_hop.ip6);
494
495   if (NULL != nbr)
496     {
497       adj_nbr_walk_nh6 (sw_if_index, &nbr->key.ip6_address,
498                         ip6_nd_mk_complete_walk, nbr);
499     }
500   else
501     {
502       /*
503        * no matching ND entry.
504        * construct the rewrite required to for an ND packet, and stick
505        * that in the adj's pipe to smoke.
506        */
507       adj_nbr_update_rewrite (ai,
508                               ADJ_NBR_REWRITE_FLAG_INCOMPLETE,
509                               ethernet_build_rewrite (vnm,
510                                                       sw_if_index,
511                                                       VNET_LINK_IP6,
512                                                       VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
513
514       /*
515        * since the FIB has added this adj for a route, it makes sense it may
516        * want to forward traffic sometime soon. Let's send a speculative ND.
517        * just one. If we were to do periodically that wouldn't be bad either,
518        * but that's more code than i'm prepared to write at this time for
519        * relatively little reward.
520        */
521       ip6_nbr_probe (adj);
522     }
523 }
524
525 int
526 vnet_set_ip6_ethernet_neighbor (vlib_main_t * vm,
527                                 u32 sw_if_index,
528                                 ip6_address_t * a,
529                                 u8 * link_layer_address,
530                                 uword n_bytes_link_layer_address,
531                                 int is_static)
532 {
533   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
534   ip6_neighbor_key_t k;
535   ip6_neighbor_t * n = 0;
536   int make_new_nd_cache_entry=1;
537   uword * p;
538   u32 next_index;
539   pending_resolution_t * pr, * mc;
540
541 #if DPDK > 0
542   if (os_get_cpu_number())
543     {
544       set_unset_ip6_neighbor_rpc (vm, sw_if_index, a, link_layer_address,
545                                   1 /* set new neighbor */, is_static);
546       return 0;
547     }
548 #endif
549
550   k.sw_if_index = sw_if_index;
551   k.ip6_address = a[0];
552   k.pad = 0;
553
554   p = mhash_get (&nm->neighbor_index_by_key, &k);
555   if (p) {
556     n = pool_elt_at_index (nm->neighbor_pool, p[0]);
557     /* Refuse to over-write static neighbor entry. */
558     if (!is_static &&
559         (n->flags & IP6_NEIGHBOR_FLAG_STATIC))
560       return -2;
561     make_new_nd_cache_entry = 0;
562   }
563
564   if (make_new_nd_cache_entry) {
565       fib_prefix_t pfx = {
566           .fp_len = 128,
567           .fp_proto = FIB_PROTOCOL_IP6,
568           .fp_addr = {
569               .ip6 = k.ip6_address,
570           },
571       };
572       u32 fib_index;
573
574     pool_get (nm->neighbor_pool, n);
575     mhash_set (&nm->neighbor_index_by_key, &k, n - nm->neighbor_pool,
576                /* old value */ 0);
577     n->key = k;
578
579     clib_memcpy (n->link_layer_address,
580                  link_layer_address,
581                  n_bytes_link_layer_address);
582
583     /*
584      * create the adj-fib. the entry in the FIB table for and to the peer.
585      */
586     fib_index = ip6_main.fib_index_by_sw_if_index[n->key.sw_if_index];
587     n->fib_entry_index =
588         fib_table_entry_update_one_path(fib_index,
589                                         &pfx,
590                                         FIB_SOURCE_ADJ,
591                                         FIB_ENTRY_FLAG_NONE,
592                                         FIB_PROTOCOL_IP6,
593                                         &pfx.fp_addr,
594                                         n->key.sw_if_index,
595                                         ~0,
596                                         1,
597                                         MPLS_LABEL_INVALID,
598                                         FIB_ROUTE_PATH_FLAG_NONE);
599   }
600   else
601   {
602     /*
603      * prevent a DoS attack from the data-plane that
604      * spams us with no-op updates to the MAC address
605      */
606     if (0 == memcmp(n->link_layer_address,
607                     link_layer_address,
608                     n_bytes_link_layer_address))
609       return -1;
610
611     clib_memcpy (n->link_layer_address,
612                  link_layer_address,
613                  n_bytes_link_layer_address);
614   }
615
616   /* Update time stamp and flags. */
617   n->cpu_time_last_updated = clib_cpu_time_now ();
618   if (is_static)
619     n->flags |= IP6_NEIGHBOR_FLAG_STATIC;
620   else
621     n->flags |= IP6_NEIGHBOR_FLAG_DYNAMIC;
622
623   adj_nbr_walk_nh6 (sw_if_index,
624                     &n->key.ip6_address,
625                     ip6_nd_mk_complete_walk, n);
626
627   /* Customer(s) waiting for this address to be resolved? */
628   p = mhash_get (&nm->pending_resolutions_by_address, a);
629   if (p)
630     {
631       next_index = p[0];
632   
633       while (next_index != (u32)~0)
634         {
635           pr = pool_elt_at_index (nm->pending_resolutions, next_index);
636           vlib_process_signal_event (vm, pr->node_index,
637                                      pr->type_opaque, 
638                                      pr->data);
639           next_index = pr->next_index;
640           pool_put (nm->pending_resolutions, pr);
641         }
642
643       mhash_unset (&nm->pending_resolutions_by_address, a, 0);
644     }
645
646   /* Customer(s) requesting ND event for this address? */
647   p = mhash_get (&nm->mac_changes_by_address, a);
648   if (p)
649     {
650       next_index = p[0];
651
652       while (next_index != (u32)~0)
653         {
654           int (*fp)(u32, u8 *, u32, ip6_address_t *);
655           int rv = 1;
656           mc = pool_elt_at_index (nm->mac_changes, next_index);
657           fp = mc->data_callback;
658
659           /* Call the user's data callback, return 1 to suppress dup events */
660           if (fp)
661             rv = (*fp)(mc->data, link_layer_address, sw_if_index, &ip6a_zero);
662           /* 
663            * Signal the resolver process, as long as the user
664            * says they want to be notified
665            */
666           if (rv == 0)
667             vlib_process_signal_event (vm, mc->node_index,
668                                        mc->type_opaque, 
669                                        mc->data);
670           next_index = mc->next_index;
671         }
672     }
673
674   return 0;
675 }
676
677 int
678 vnet_unset_ip6_ethernet_neighbor (vlib_main_t * vm,
679                                   u32 sw_if_index,
680                                   ip6_address_t * a,
681                                   u8 * link_layer_address,
682                                   uword n_bytes_link_layer_address)
683 {
684   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
685   ip6_neighbor_key_t k;
686   ip6_neighbor_t * n;
687   uword * p;
688   int rv = 0;
689
690 #if DPDK > 0
691   if (os_get_cpu_number())
692     {
693       set_unset_ip6_neighbor_rpc (vm, sw_if_index, a, link_layer_address,
694                                   0 /* unset */, 0);
695       return 0;
696     }
697 #endif
698
699   k.sw_if_index = sw_if_index;
700   k.ip6_address = a[0];
701   k.pad = 0;
702   
703   p = mhash_get (&nm->neighbor_index_by_key, &k);
704   if (p == 0)
705     {
706       rv = -1;
707       goto out;
708     }
709   
710   n = pool_elt_at_index (nm->neighbor_pool, p[0]);
711
712   adj_nbr_walk_nh6 (sw_if_index,
713                     &n->key.ip6_address,
714                     ip6_nd_mk_incomplete_walk,
715                     n);
716
717   mhash_unset (&nm->neighbor_index_by_key, &n->key, 0);
718   fib_table_entry_delete_index (n->fib_entry_index,  FIB_SOURCE_ADJ);
719   pool_put (nm->neighbor_pool, n);
720   
721  out:
722   return rv;
723 }
724
725 #if DPDK > 0
726 static void ip6_neighbor_set_unset_rpc_callback 
727 ( ip6_neighbor_set_unset_rpc_args_t * a)
728 {
729   vlib_main_t * vm = vlib_get_main();
730   if (a->is_add) 
731       vnet_set_ip6_ethernet_neighbor (vm, a->sw_if_index, &a->addr, 
732                                       a->link_layer_address, 6, a->is_static);
733   else
734     vnet_unset_ip6_ethernet_neighbor (vm, a->sw_if_index, &a->addr, 
735                                       a->link_layer_address, 6);
736 }
737 #endif
738
739 static int
740 ip6_neighbor_sort (void *a1, void *a2)
741 {
742   vnet_main_t * vnm = vnet_get_main();
743   ip6_neighbor_t * n1 = a1, * n2 = a2;
744   int cmp;
745   cmp = vnet_sw_interface_compare (vnm, n1->key.sw_if_index, 
746                                    n2->key.sw_if_index);
747   if (! cmp)
748     cmp = ip6_address_compare (&n1->key.ip6_address, &n2->key.ip6_address);
749   return cmp;
750 }
751
752 static clib_error_t *
753 show_ip6_neighbors (vlib_main_t * vm,
754                     unformat_input_t * input,
755                     vlib_cli_command_t * cmd)
756 {
757   vnet_main_t * vnm = vnet_get_main();
758   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
759   ip6_neighbor_t * n, * ns;
760   clib_error_t * error = 0;
761   u32 sw_if_index;
762
763   /* Filter entries by interface if given. */
764   sw_if_index = ~0;
765   (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index);
766
767   ns = 0;
768   pool_foreach (n, nm->neighbor_pool, ({ vec_add1 (ns, n[0]); }));
769   if (ns)
770     {
771       vec_sort_with_function (ns, ip6_neighbor_sort);
772       vlib_cli_output (vm, "%U", format_ip6_neighbor_ip6_entry, vm, 0);
773       vec_foreach (n, ns) {
774         if (sw_if_index != ~0 && n->key.sw_if_index != sw_if_index)
775           continue;
776         vlib_cli_output (vm, "%U", format_ip6_neighbor_ip6_entry, vm, n);
777       }
778       vec_free (ns);
779     }
780
781   return error;
782 }
783
784 /*?
785  * This command is used to display the adjacent IPv6 hosts found via
786  * neighbor discovery. Optionally, limit the output to the specified
787  * interface.
788  *
789  * @cliexpar
790  * Example of how to display the IPv6 neighbor adjacency table:
791  * @cliexstart{show ip6 neighbors}
792  *     Time           Address       Flags     Link layer                     Interface
793  *      34.0910     ::a:1:1:0:7            02:fe:6a:07:39:6f                GigabitEthernet2/0/0
794  *     173.2916     ::b:5:1:c:2            02:fe:50:62:3a:94                GigabitEthernet2/0/0
795  *     886.6654     ::1:1:c:0:9       S    02:fe:e4:45:27:5b                GigabitEthernet3/0/0
796  * @cliexend
797  * Example of how to display the IPv6 neighbor adjacency table for given interface:
798  * @cliexstart{show ip6 neighbors GigabitEthernet2/0/0}
799  *     Time           Address       Flags     Link layer                     Interface
800  *      34.0910     ::a:1:1:0:7            02:fe:6a:07:39:6f                GigabitEthernet2/0/0
801  *     173.2916     ::b:5:1:c:2            02:fe:50:62:3a:94                GigabitEthernet2/0/0
802  * @cliexend
803 ?*/
804 /* *INDENT-OFF* */
805 VLIB_CLI_COMMAND (show_ip6_neighbors_command, static) = {
806   .path = "show ip6 neighbors",
807   .function = show_ip6_neighbors,
808   .short_help = "show ip6 neighbors [<interface>]",
809 };
810 /* *INDENT-ON* */
811
812 static clib_error_t *
813 set_ip6_neighbor (vlib_main_t * vm,
814                   unformat_input_t * input,
815                   vlib_cli_command_t * cmd)
816 {
817   vnet_main_t * vnm = vnet_get_main();
818   ip6_address_t addr;
819   u8 mac_address[6];
820   int addr_valid = 0;
821   int is_del = 0;
822   int is_static = 0;
823   u32 sw_if_index;
824
825   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) 
826     {
827       /* intfc, ip6-address, mac-address */
828       if (unformat (input, "%U %U %U",
829                     unformat_vnet_sw_interface, vnm, &sw_if_index,
830                     unformat_ip6_address, &addr, 
831                     unformat_ethernet_address, mac_address))
832         addr_valid = 1;
833
834       else if (unformat (input, "delete") || unformat (input, "del"))
835         is_del = 1;
836       else if (unformat (input, "static"))
837         is_static = 1;
838       else
839         break;
840     }
841
842   if (!addr_valid)
843     return clib_error_return (0, "Missing interface, ip6 or hw address");
844   
845   if (!is_del)
846     vnet_set_ip6_ethernet_neighbor (vm, sw_if_index, &addr,
847                                     mac_address, sizeof(mac_address), is_static);
848   else
849     vnet_unset_ip6_ethernet_neighbor (vm, sw_if_index, &addr,
850                                       mac_address, sizeof(mac_address));
851   return 0;
852 }
853
854 /*?
855  * This command is used to manually add an entry to the IPv6 neighbor
856  * adjacency table. Optionally, the entry can be added as static. It is
857  * also used to remove an entry from the table. Use the '<em>show ip6
858  * neighbors</em>' command to display all learned and manually entered entries.
859  *
860  * @cliexpar
861  * Example of how to add a static entry to the IPv6 neighbor adjacency table:
862  * @cliexcmd{set ip6 neighbor GigabitEthernet2/0/0 ::1:1:c:0:9 02:fe:e4:45:27:5b static}
863  * Example of how to delete an entry from the IPv6 neighbor adjacency table:
864  * @cliexcmd{set ip6 neighbor del GigabitEthernet2/0/0 ::1:1:c:0:9 02:fe:e4:45:27:5b}
865 ?*/
866 /* *INDENT-OFF* */
867 VLIB_CLI_COMMAND (set_ip6_neighbor_command, static) = {
868   .path = "set ip6 neighbor",
869   .function = set_ip6_neighbor,
870   .short_help = "set ip6 neighbor [del] <interface> <ip6-address> <mac-address> [static]",
871 };
872 /* *INDENT-ON* */
873
874 typedef enum {
875   ICMP6_NEIGHBOR_SOLICITATION_NEXT_DROP,
876   ICMP6_NEIGHBOR_SOLICITATION_NEXT_REPLY,
877   ICMP6_NEIGHBOR_SOLICITATION_N_NEXT,
878 } icmp6_neighbor_solicitation_or_advertisement_next_t;
879
880 static_always_inline uword
881 icmp6_neighbor_solicitation_or_advertisement (vlib_main_t * vm,
882                                               vlib_node_runtime_t * node,
883                                               vlib_frame_t * frame,
884                                               uword is_solicitation)
885 {
886   vnet_main_t * vnm = vnet_get_main();
887   ip6_main_t * im = &ip6_main;
888   uword n_packets = frame->n_vectors;
889   u32 * from, * to_next;
890   u32 n_left_from, n_left_to_next, next_index, n_advertisements_sent;
891   icmp6_neighbor_discovery_option_type_t option_type;
892   vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip6_icmp_input_node.index);
893   int bogus_length;
894
895   from = vlib_frame_vector_args (frame);
896   n_left_from = n_packets;
897   next_index = node->cached_next_index;
898   
899   if (node->flags & VLIB_NODE_FLAG_TRACE)
900     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
901                                    /* stride */ 1,
902                                    sizeof (icmp6_input_trace_t));
903
904   option_type = 
905     (is_solicitation
906      ? ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address
907      : ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address);
908   n_advertisements_sent = 0;
909
910   while (n_left_from > 0)
911     {
912       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
913
914       while (n_left_from > 0 && n_left_to_next > 0)
915         {
916           vlib_buffer_t * p0;
917           ip6_header_t * ip0;
918           icmp6_neighbor_solicitation_or_advertisement_header_t * h0;
919           icmp6_neighbor_discovery_ethernet_link_layer_address_option_t * o0;
920           u32 bi0, options_len0, sw_if_index0, next0, error0;
921           u32 ip6_sadd_link_local, ip6_sadd_unspecified;
922           int is_rewrite0;
923           u32 ni0;
924       
925           bi0 = to_next[0] = from[0];
926
927           from += 1;
928           to_next += 1;
929           n_left_from -= 1;
930           n_left_to_next -= 1;
931       
932           p0 = vlib_get_buffer (vm, bi0);
933           ip0 = vlib_buffer_get_current (p0);
934           h0 = ip6_next_header (ip0);
935           options_len0 = clib_net_to_host_u16 (ip0->payload_length) - sizeof (h0[0]);
936
937           error0 = ICMP6_ERROR_NONE;
938           sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
939           ip6_sadd_link_local = ip6_address_is_link_local_unicast(&ip0->src_address);
940           ip6_sadd_unspecified = ip6_address_is_unspecified (&ip0->src_address);
941
942           /* Check that source address is unspecified, link-local or else on-link. */
943           if (!ip6_sadd_unspecified && !ip6_sadd_link_local)
944             {
945               u32 src_adj_index0 = ip6_src_lookup_for_packet (im, p0, ip0);
946
947               if (ADJ_INDEX_INVALID != src_adj_index0)
948                 {
949                   ip_adjacency_t * adj0 = ip_get_adjacency (&im->lookup_main, src_adj_index0);
950
951                   /* Allow all realistic-looking rewrite adjacencies to pass */
952                   ni0 = adj0->lookup_next_index;
953                   is_rewrite0 = (ni0 >= IP_LOOKUP_NEXT_ARP) &&
954                       (ni0 < IP6_LOOKUP_N_NEXT);
955
956                   error0 = ((adj0->rewrite_header.sw_if_index != sw_if_index0
957                              || ! is_rewrite0)
958                             ? ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_NOT_ON_LINK
959                             : error0);
960                 }
961               else
962                 {
963                   error0 = ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_NOT_ON_LINK;
964                 }
965             }
966               
967           o0 = (void *) (h0 + 1);
968           o0 = ((options_len0 == 8 && o0->header.type == option_type
969                  && o0->header.n_data_u64s == 1) ? o0 : 0);
970
971           /* If src address unspecified or link local, donot learn neighbor MAC */
972           if (PREDICT_TRUE (error0 == ICMP6_ERROR_NONE && o0 != 0 && 
973                             !ip6_sadd_unspecified && !ip6_sadd_link_local)) 
974             { 
975               ip6_neighbor_main_t * nm = &ip6_neighbor_main;
976               if (nm->limit_neighbor_cache_size && 
977                   pool_elts (nm->neighbor_pool) >= nm->limit_neighbor_cache_size)
978                   unset_random_neighbor_entry();
979               vnet_set_ip6_ethernet_neighbor (
980                   vm, sw_if_index0,
981                   is_solicitation ? &ip0->src_address : &h0->target_address,
982                   o0->ethernet_address, sizeof (o0->ethernet_address), 0);
983             }
984
985           if (is_solicitation && error0 == ICMP6_ERROR_NONE)
986             {
987               /* Check that target address is local to this router. */
988               fib_node_index_t fei;
989               u32 fib_index;
990
991               fib_index = ip6_fib_table_get_index_for_sw_if_index(sw_if_index0);
992
993               if (~0 == fib_index)
994                 {
995                   error0 = ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_UNKNOWN;
996                 }
997               else
998                 {
999                   fei = ip6_fib_table_lookup_exact_match(fib_index,
1000                                                          &h0->target_address,
1001                                                          128);
1002
1003                   if (FIB_NODE_INDEX_INVALID == fei || 
1004                       !(FIB_ENTRY_FLAG_LOCAL &
1005                         fib_entry_get_flags_for_source(fei, FIB_SOURCE_INTERFACE)))
1006                     {
1007                       error0 = ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_UNKNOWN;
1008                     }
1009                 }
1010             }
1011
1012           if (is_solicitation)
1013             next0 = (error0 != ICMP6_ERROR_NONE
1014                      ? ICMP6_NEIGHBOR_SOLICITATION_NEXT_DROP
1015                      : ICMP6_NEIGHBOR_SOLICITATION_NEXT_REPLY);
1016           else
1017             {
1018               next0 = 0;
1019               error0 = error0 == ICMP6_ERROR_NONE ? 
1020                   ICMP6_ERROR_NEIGHBOR_ADVERTISEMENTS_RX : error0;
1021             }
1022
1023           if (is_solicitation && error0 == ICMP6_ERROR_NONE)
1024             {
1025               vnet_sw_interface_t * sw_if0;
1026               ethernet_interface_t * eth_if0;
1027               ethernet_header_t *eth0;
1028
1029               /* dst address is either source address or the all-nodes mcast addr */                  
1030               if(!ip6_sadd_unspecified)
1031                   ip0->dst_address = ip0->src_address;
1032               else
1033                   ip6_set_reserved_multicast_address(&ip0->dst_address, 
1034                                                      IP6_MULTICAST_SCOPE_link_local,
1035                                                      IP6_MULTICAST_GROUP_ID_all_hosts);
1036
1037               ip0->src_address = h0->target_address;
1038               ip0->hop_limit = 255;
1039               h0->icmp.type = ICMP6_neighbor_advertisement;
1040
1041               sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
1042               ASSERT (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
1043               eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
1044               if (eth_if0 && o0)
1045                 {
1046                   clib_memcpy (o0->ethernet_address, eth_if0->address, 6);
1047                   o0->header.type = 
1048                       ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
1049                 }
1050
1051               h0->advertisement_flags = clib_host_to_net_u32
1052                 (ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED
1053                  | ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE);
1054
1055               h0->icmp.checksum = 0;
1056               h0->icmp.checksum = 
1057                   ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0, 
1058                                                      &bogus_length);
1059               ASSERT(bogus_length == 0);
1060
1061               /* Reuse current MAC header, copy SMAC to DMAC and 
1062                * interface MAC to SMAC */
1063               vlib_buffer_advance(p0, - ethernet_buffer_header_size(p0));
1064               eth0 = vlib_buffer_get_current(p0);
1065               clib_memcpy(eth0->dst_address, eth0->src_address, 6);
1066               if (eth_if0)
1067                 clib_memcpy(eth0->src_address, eth_if0->address, 6);
1068
1069               /* Setup input and output sw_if_index for packet */
1070               ASSERT(vnet_buffer(p0)->sw_if_index[VLIB_RX] == sw_if_index0);
1071               vnet_buffer(p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1072               vnet_buffer(p0)->sw_if_index[VLIB_RX] = 
1073                   vnet_main.local_interface_sw_if_index;
1074
1075               n_advertisements_sent++;
1076             }
1077
1078           p0->error = error_node->errors[error0];
1079
1080           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1081                                            to_next, n_left_to_next,
1082                                            bi0, next0);
1083         }
1084
1085       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1086     }
1087
1088   /* Account for advertisements sent. */
1089   vlib_error_count (vm, error_node->node_index, ICMP6_ERROR_NEIGHBOR_ADVERTISEMENTS_TX, n_advertisements_sent);
1090
1091   return frame->n_vectors;
1092 }
1093
1094 /* for "syslogging" - use elog for now */
1095 #define foreach_log_level            \
1096   _ (DEBUG, "DEBUG")                         \
1097   _ (INFO, "INFORMATION")            \
1098   _ (NOTICE, "NOTICE")               \
1099   _ (WARNING, "WARNING")             \
1100   _ (ERR, "ERROR")                                    \
1101   _ (CRIT, "CRITICAL")                        \
1102   _ (ALERT, "ALERT")                          \
1103   _ (EMERG,  "EMERGENCY")
1104
1105 typedef enum {
1106 #define _(f,s) LOG_##f,
1107   foreach_log_level
1108 #undef _
1109 } log_level_t;
1110
1111 static char * log_level_strings[] = {
1112 #define _(f,s) s,
1113   foreach_log_level
1114 #undef _
1115 };
1116
1117 static  int logmask = 1 << LOG_DEBUG;
1118
1119 static void
1120 ip6_neighbor_syslog(vlib_main_t *vm,  int priority,  char * fmt, ...)
1121 {
1122   /* just use elog for now */
1123   u8 *what;
1124   va_list va;
1125
1126   if( (priority > LOG_EMERG) ||
1127       !(logmask & (1 << priority)))
1128       return;
1129
1130   va_start (va, fmt);
1131   if(fmt)
1132     {
1133       what = va_format (0, fmt, &va);
1134
1135       ELOG_TYPE_DECLARE (e) = {
1136         .format = "ip6 nd:  (%s): %s",
1137         .format_args = "T4T4",
1138       };
1139       struct { u32 s[2]; } * ed;
1140       ed = ELOG_DATA (&vm->elog_main, e);
1141       ed->s[0] = elog_string(&vm->elog_main,  log_level_strings[priority]);
1142       ed->s[1] = elog_string(&vm->elog_main,  (char *)what);
1143     }
1144   va_end (va);
1145   return;
1146 }
1147
1148 /* ipv6 neighbor discovery - router advertisements */
1149 typedef enum {
1150   ICMP6_ROUTER_SOLICITATION_NEXT_DROP,
1151   ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW,
1152   ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX,
1153   ICMP6_ROUTER_SOLICITATION_N_NEXT,
1154 } icmp6_router_solicitation_or_advertisement_next_t;
1155
1156 static_always_inline uword
1157 icmp6_router_solicitation(vlib_main_t * vm,
1158                           vlib_node_runtime_t * node,
1159                           vlib_frame_t * frame)
1160 {
1161   vnet_main_t * vnm = vnet_get_main();
1162   ip6_main_t * im = &ip6_main;
1163   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
1164   uword n_packets = frame->n_vectors;
1165   u32 * from, * to_next;
1166   u32 n_left_from, n_left_to_next, next_index;
1167   u32  n_advertisements_sent = 0;
1168   int bogus_length;
1169
1170   icmp6_neighbor_discovery_option_type_t option_type;
1171
1172   vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip6_icmp_input_node.index);
1173
1174   from = vlib_frame_vector_args (frame);
1175   n_left_from = n_packets;
1176   next_index = node->cached_next_index;
1177   
1178   if (node->flags & VLIB_NODE_FLAG_TRACE)
1179     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
1180                                    /* stride */ 1,
1181                                    sizeof (icmp6_input_trace_t));
1182
1183   /* source may append his LL address */
1184   option_type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
1185
1186   while (n_left_from > 0)
1187     {
1188       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1189       
1190       while (n_left_from > 0 && n_left_to_next > 0)
1191         {
1192           vlib_buffer_t * p0;
1193           ip6_header_t * ip0;
1194           ip6_radv_t *radv_info = 0;
1195
1196           icmp6_neighbor_discovery_header_t * h0;  
1197           icmp6_neighbor_discovery_ethernet_link_layer_address_option_t * o0;
1198           
1199           u32 bi0, options_len0, sw_if_index0, next0, error0;
1200           u32 is_solicitation = 1, is_dropped  = 0;
1201           u32 is_unspecified, is_link_local;
1202
1203           bi0 = to_next[0] = from[0];
1204
1205           from += 1;
1206           to_next += 1;
1207           n_left_from -= 1;
1208           n_left_to_next -= 1;
1209       
1210           p0 = vlib_get_buffer (vm, bi0);
1211           ip0 = vlib_buffer_get_current (p0);
1212           h0 = ip6_next_header (ip0);
1213           options_len0 = clib_net_to_host_u16 (ip0->payload_length) - sizeof (h0[0]);
1214           is_unspecified = ip6_address_is_unspecified (&ip0->src_address);
1215           is_link_local = ip6_address_is_link_local_unicast (&ip0->src_address);
1216
1217           error0 = ICMP6_ERROR_NONE;
1218           sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1219           
1220           /* check if solicitation  (not from nd_timer node) */
1221           if (ip6_address_is_unspecified (&ip0->dst_address))
1222             is_solicitation = 0;
1223
1224           /* Check that source address is unspecified, link-local or else on-link. */
1225           if (!is_unspecified && !is_link_local)
1226             {
1227               u32 src_adj_index0 = ip6_src_lookup_for_packet (im, p0, ip0);
1228
1229               if (ADJ_INDEX_INVALID != src_adj_index0)
1230                 {
1231                   ip_adjacency_t * adj0 = ip_get_adjacency (&im->lookup_main,
1232                                                             src_adj_index0);
1233
1234                   error0 = (adj0->rewrite_header.sw_if_index != sw_if_index0
1235                             ? ICMP6_ERROR_ROUTER_SOLICITATION_SOURCE_NOT_ON_LINK
1236                             : error0);
1237                 }
1238               else
1239                 {
1240                   error0 = ICMP6_ERROR_ROUTER_SOLICITATION_SOURCE_NOT_ON_LINK;
1241                 }
1242           }
1243           
1244           /* check for source LL option and process */
1245           o0 = (void *) (h0 + 1);
1246           o0 = ((options_len0 == 8
1247                  && o0->header.type == option_type
1248                  && o0->header.n_data_u64s == 1)
1249                 ? o0
1250                 : 0);
1251                       
1252           /* if src address unspecified IGNORE any options */
1253           if (PREDICT_TRUE (error0 == ICMP6_ERROR_NONE && o0 != 0 && 
1254                             !is_unspecified && !is_link_local)) {
1255               ip6_neighbor_main_t * nm = &ip6_neighbor_main;
1256               if (nm->limit_neighbor_cache_size && 
1257                   pool_elts (nm->neighbor_pool) >= nm->limit_neighbor_cache_size)
1258                       unset_random_neighbor_entry();
1259               
1260               vnet_set_ip6_ethernet_neighbor (vm, sw_if_index0,
1261                                               &ip0->src_address,
1262                                               o0->ethernet_address,
1263                                               sizeof (o0->ethernet_address), 0);
1264           }
1265               
1266           /* default is to drop */
1267           next0 = ICMP6_ROUTER_SOLICITATION_NEXT_DROP;
1268           
1269           if (error0 == ICMP6_ERROR_NONE)
1270             {
1271               vnet_sw_interface_t * sw_if0;
1272               ethernet_interface_t * eth_if0;
1273               u32 adj_index0;
1274
1275               sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
1276               ASSERT (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
1277               eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
1278
1279               /* only support ethernet interface type for now */
1280               error0 = (!eth_if0) ?  ICMP6_ERROR_ROUTER_SOLICITATION_UNSUPPORTED_INTF : error0;
1281
1282               if (error0 == ICMP6_ERROR_NONE)
1283                 {
1284                   u32 ri;
1285
1286                   /* adjust the sizeof the buffer to just include the ipv6 header */
1287                   p0->current_length -= (options_len0 + sizeof(icmp6_neighbor_discovery_header_t));
1288
1289                   /* look up the radv_t information for this interface */
1290                   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index0, ~0);
1291
1292                   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index0];
1293
1294                   if(ri != ~0)
1295                       radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
1296                         
1297                   error0 = ((!radv_info) ?  ICMP6_ERROR_ROUTER_SOLICITATION_RADV_NOT_CONFIG : error0);
1298
1299                   if (error0 == ICMP6_ERROR_NONE)
1300                     {
1301                       f64 now = vlib_time_now (vm);
1302
1303                       /* for solicited adverts - need to rate limit */
1304                       if(is_solicitation)
1305                         {
1306                           if( (now - radv_info->last_radv_time)  <  MIN_DELAY_BETWEEN_RAS )
1307                               is_dropped = 1;
1308                           else
1309                             radv_info->last_radv_time = now;
1310                         }
1311
1312                       /* send now  */
1313                       icmp6_router_advertisement_header_t rh;
1314
1315                       rh.icmp.type = ICMP6_router_advertisement;
1316                       rh.icmp.code = 0;
1317                       rh.icmp.checksum = 0;
1318                       
1319                       rh.current_hop_limit = radv_info->curr_hop_limit;
1320                       rh.router_lifetime_in_sec = clib_host_to_net_u16(radv_info->adv_router_lifetime_in_sec);
1321                       rh.time_in_msec_between_retransmitted_neighbor_solicitations = 
1322                         clib_host_to_net_u32(radv_info->adv_time_in_msec_between_retransmitted_neighbor_solicitations);
1323                       rh.neighbor_reachable_time_in_msec = 
1324                         clib_host_to_net_u32(radv_info->adv_neighbor_reachable_time_in_msec);
1325                       
1326                       rh.flags = (radv_info->adv_managed_flag) ? ICMP6_ROUTER_DISCOVERY_FLAG_ADDRESS_CONFIG_VIA_DHCP : 0;
1327                       rh.flags |= ( (radv_info->adv_other_flag) ? ICMP6_ROUTER_DISCOVERY_FLAG_OTHER_CONFIG_VIA_DHCP : 0);
1328
1329
1330                       u16 payload_length = sizeof(icmp6_router_advertisement_header_t);
1331
1332                       vlib_buffer_add_data (vm,
1333                                             p0->free_list_index,
1334                                             bi0,
1335                                             (void *)&rh, sizeof(icmp6_router_advertisement_header_t));
1336
1337                       if(radv_info->adv_link_layer_address)
1338                         {
1339                           icmp6_neighbor_discovery_ethernet_link_layer_address_option_t h;
1340
1341                           h.header.type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
1342                           h.header.n_data_u64s = 1;
1343
1344                           /* copy ll address */
1345                           clib_memcpy(&h.ethernet_address[0], eth_if0->address,  6);
1346
1347                           vlib_buffer_add_data (vm,
1348                                                 p0->free_list_index,
1349                                                 bi0,
1350                                                 (void *)&h, sizeof(icmp6_neighbor_discovery_ethernet_link_layer_address_option_t));
1351
1352                           payload_length += sizeof(icmp6_neighbor_discovery_ethernet_link_layer_address_option_t);
1353                         }
1354                       
1355                       /* add MTU option */
1356                       if(radv_info->adv_link_mtu)
1357                         {
1358                           icmp6_neighbor_discovery_mtu_option_t h;
1359
1360                           h.unused = 0;
1361                           h.mtu =  clib_host_to_net_u32(radv_info->adv_link_mtu);
1362                           h.header.type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_mtu;
1363                           h.header.n_data_u64s = 1;
1364                           
1365                           payload_length += sizeof( icmp6_neighbor_discovery_mtu_option_t);
1366
1367                           vlib_buffer_add_data (vm,
1368                                                 p0->free_list_index,
1369                                                 bi0,
1370                                                 (void *)&h, sizeof(icmp6_neighbor_discovery_mtu_option_t));
1371                         }
1372                       
1373                       /* add advertised prefix options  */
1374                       ip6_radv_prefix_t *pr_info; 
1375
1376                       pool_foreach (pr_info, radv_info->adv_prefixes_pool, ({
1377
1378                             if(pr_info->enabled &&
1379                                (!pr_info->decrement_lifetime_flag  || (pr_info->pref_lifetime_expires >0)))
1380                               {
1381                                 /* advertise this prefix */
1382                                 icmp6_neighbor_discovery_prefix_information_option_t h;
1383                                 
1384                                 h.header.type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_prefix_information;
1385                                 h.header.n_data_u64s  =  (sizeof(icmp6_neighbor_discovery_prefix_information_option_t) >> 3);
1386                                 
1387                                 h.dst_address_length  = pr_info->prefix_len;
1388                                 
1389                                 h.flags  = (pr_info->adv_on_link_flag) ? ICMP6_NEIGHBOR_DISCOVERY_PREFIX_INFORMATION_FLAG_ON_LINK : 0;
1390                                 h.flags |= (pr_info->adv_autonomous_flag) ?  ICMP6_NEIGHBOR_DISCOVERY_PREFIX_INFORMATION_AUTO :  0;
1391                                 
1392                                 if(radv_info->cease_radv && pr_info->deprecated_prefix_flag)
1393                                   { 
1394                                     h.valid_time = clib_host_to_net_u32(MIN_ADV_VALID_LIFETIME);
1395                                     h.preferred_time  = 0;
1396                                   }
1397                                 else
1398                                   {
1399                                     if(pr_info->decrement_lifetime_flag)
1400                                       {
1401                                         pr_info->adv_valid_lifetime_in_secs = ((pr_info->valid_lifetime_expires  > now)) ?
1402                                           (pr_info->valid_lifetime_expires  - now) : 0;
1403                                         
1404                                         pr_info->adv_pref_lifetime_in_secs = ((pr_info->pref_lifetime_expires  > now)) ?
1405                                           (pr_info->pref_lifetime_expires  - now) : 0;
1406                                       }
1407                                     
1408                                     h.valid_time = clib_host_to_net_u32(pr_info->adv_valid_lifetime_in_secs);
1409                                     h.preferred_time  = clib_host_to_net_u32(pr_info->adv_pref_lifetime_in_secs) ;
1410                                   }
1411                                 h.unused  = 0;
1412                                 
1413                                 clib_memcpy(&h.dst_address, &pr_info->prefix,  sizeof(ip6_address_t));
1414
1415                                 payload_length += sizeof( icmp6_neighbor_discovery_prefix_information_option_t); 
1416
1417                                 vlib_buffer_add_data (vm,
1418                                                       p0->free_list_index,
1419                                                       bi0,
1420                                                       (void *)&h, sizeof(icmp6_neighbor_discovery_prefix_information_option_t));
1421
1422                               } 
1423                           }));
1424
1425                       /* add additional options before here */
1426
1427                       /* finish building the router advertisement... */
1428                       if(!is_unspecified && radv_info->send_unicast)
1429                         {
1430                           ip0->dst_address = ip0->src_address;
1431                         }
1432                       else
1433                         {                             
1434                           /* target address is all-nodes mcast addr */ 
1435                           ip6_set_reserved_multicast_address(&ip0->dst_address, 
1436                                                              IP6_MULTICAST_SCOPE_link_local,
1437                                                              IP6_MULTICAST_GROUP_ID_all_hosts);
1438                         }
1439                       
1440                       /* source address MUST be the link-local address */
1441                       ip0->src_address = radv_info->link_local_address;
1442                       
1443                       ip0->hop_limit = 255;
1444                       ip0->payload_length = clib_host_to_net_u16 (payload_length);
1445
1446                       icmp6_router_advertisement_header_t * rh0 = (icmp6_router_advertisement_header_t *)(ip0 + 1);
1447                       rh0->icmp.checksum = 
1448                           ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0, 
1449                                                              &bogus_length);
1450                       ASSERT(bogus_length == 0);
1451                       
1452                       /* setup output if and adjacency */
1453                       vnet_buffer (p0)->sw_if_index[VLIB_RX] = 
1454                         vnet_main.local_interface_sw_if_index;
1455                       
1456                       if (is_solicitation) 
1457                         {
1458                           ethernet_header_t *eth0;
1459                           /* Reuse current MAC header, copy SMAC to DMAC and 
1460                            * interface MAC to SMAC */
1461                           vlib_buffer_reset (p0);
1462                           eth0 = vlib_buffer_get_current(p0);
1463                           clib_memcpy(eth0->dst_address, eth0->src_address, 6);
1464                           clib_memcpy(eth0->src_address, eth_if0->address, 6);
1465                           next0 = is_dropped ? 
1466                               next0 : ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX;
1467                           vnet_buffer(p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1468                         }
1469                       else 
1470                         {
1471                           adj_index0 = radv_info->all_nodes_adj_index;
1472                           if (adj_index0 == 0)
1473                               error0 = ICMP6_ERROR_DST_LOOKUP_MISS;
1474                           else
1475                             {
1476                               ip_adjacency_t * adj0 = ip_get_adjacency (&im->lookup_main, adj_index0);
1477                               error0 = 
1478                                   ((adj0->rewrite_header.sw_if_index != sw_if_index0
1479                                     || adj0->lookup_next_index != IP_LOOKUP_NEXT_REWRITE)
1480                                    ? ICMP6_ERROR_ROUTER_SOLICITATION_DEST_UNKNOWN
1481                                    : error0);
1482                               next0 = is_dropped ? 
1483                                   next0 : ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW;
1484                               vnet_buffer (p0)->ip.adj_index[VLIB_RX] = adj_index0;
1485                            }
1486                         }
1487                       
1488                       radv_info->n_solicitations_dropped  += is_dropped;
1489                       radv_info->n_solicitations_rcvd  += is_solicitation;
1490                       
1491                       if((error0 ==  ICMP6_ERROR_NONE) && !is_dropped)
1492                         {
1493                           radv_info->n_advertisements_sent++;
1494                           n_advertisements_sent++;
1495                         }
1496                     }
1497                 }
1498             }
1499
1500           p0->error = error_node->errors[error0];
1501
1502           if(error0 != ICMP6_ERROR_NONE)
1503             vlib_error_count (vm, error_node->node_index, error0, 1);
1504           
1505           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1506                                            to_next, n_left_to_next,
1507                                            bi0, next0);
1508           
1509         }
1510       
1511       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1512     }
1513
1514   /* Account for router advertisements sent. */
1515   vlib_error_count (vm, error_node->node_index, ICMP6_ERROR_ROUTER_ADVERTISEMENTS_TX, n_advertisements_sent);
1516
1517   return frame->n_vectors;
1518 }
1519
1520  /* validate advertised info for consistancy (see RFC-4861 section 6.2.7) - log any inconsistencies, packet will always  be dropped  */
1521 static_always_inline uword
1522 icmp6_router_advertisement(vlib_main_t * vm,
1523                            vlib_node_runtime_t * node,
1524                            vlib_frame_t * frame)
1525 {
1526   vnet_main_t * vnm = vnet_get_main();
1527   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
1528   uword n_packets = frame->n_vectors;
1529   u32 * from, * to_next;
1530   u32 n_left_from, n_left_to_next, next_index;
1531   u32 n_advertisements_rcvd = 0;
1532
1533   vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip6_icmp_input_node.index);
1534
1535   from = vlib_frame_vector_args (frame);
1536   n_left_from = n_packets;
1537   next_index = node->cached_next_index;
1538   
1539   if (node->flags & VLIB_NODE_FLAG_TRACE)
1540     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
1541                                    /* stride */ 1,
1542                                    sizeof (icmp6_input_trace_t));
1543
1544   while (n_left_from > 0)
1545     {
1546       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1547       
1548       while (n_left_from > 0 && n_left_to_next > 0)
1549         {
1550           vlib_buffer_t * p0;
1551           ip6_header_t * ip0;
1552           ip6_radv_t *radv_info = 0;
1553           icmp6_router_advertisement_header_t * h0;  
1554           u32 bi0, options_len0, sw_if_index0, next0, error0;
1555
1556           bi0 = to_next[0] = from[0];
1557
1558           from += 1;
1559           to_next += 1;
1560           n_left_from -= 1;
1561           n_left_to_next -= 1;
1562       
1563           p0 = vlib_get_buffer (vm, bi0);
1564           ip0 = vlib_buffer_get_current (p0);
1565           h0 = ip6_next_header (ip0);
1566           options_len0 = clib_net_to_host_u16 (ip0->payload_length) - sizeof (h0[0]);
1567
1568           error0 = ICMP6_ERROR_NONE;
1569           sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1570
1571           /* Check that source address is link-local*/
1572           error0 = (!ip6_address_is_link_local_unicast (&ip0->src_address)) ? 
1573             ICMP6_ERROR_ROUTER_ADVERTISEMENT_SOURCE_NOT_LINK_LOCAL : error0;
1574
1575           /* default is to drop */
1576           next0 = ICMP6_ROUTER_SOLICITATION_NEXT_DROP;
1577           
1578           n_advertisements_rcvd++;
1579
1580           if (error0 == ICMP6_ERROR_NONE)
1581             {
1582               vnet_sw_interface_t * sw_if0;
1583               ethernet_interface_t * eth_if0;
1584     
1585               sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
1586               ASSERT (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
1587               eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
1588
1589               /* only support ethernet interface type for now */
1590               error0 = (!eth_if0) ?  ICMP6_ERROR_ROUTER_SOLICITATION_UNSUPPORTED_INTF : error0;
1591
1592               if (error0 == ICMP6_ERROR_NONE)
1593                 {
1594                   u32 ri;
1595
1596                   /* look up the radv_t information for this interface */
1597                   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index0, ~0);
1598
1599                   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index0];
1600
1601                   if(ri != ~0)
1602                       radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
1603                         
1604                   error0 = ((!radv_info) ?  ICMP6_ERROR_ROUTER_SOLICITATION_RADV_NOT_CONFIG : error0);
1605
1606                   if (error0 == ICMP6_ERROR_NONE)
1607                     {
1608                       /* validate advertised information */
1609                       if((h0->current_hop_limit && radv_info->curr_hop_limit) &&
1610                          (h0->current_hop_limit != radv_info->curr_hop_limit))
1611                         {
1612                           ip6_neighbor_syslog(vm,  LOG_WARNING,  
1613                                               "our AdvCurHopLimit on %U doesn't agree with %U", 
1614                                               format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1615                         }
1616
1617                       if((h0->flags &  ICMP6_ROUTER_DISCOVERY_FLAG_ADDRESS_CONFIG_VIA_DHCP)  != 
1618                          radv_info->adv_managed_flag)
1619                         {
1620                           ip6_neighbor_syslog(vm,  LOG_WARNING,  
1621                                               "our AdvManagedFlag on %U doesn't agree with %U", 
1622                                               format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1623                         }
1624
1625                       if((h0->flags &   ICMP6_ROUTER_DISCOVERY_FLAG_OTHER_CONFIG_VIA_DHCP)   != 
1626                          radv_info->adv_other_flag)
1627                         {
1628                           ip6_neighbor_syslog(vm,  LOG_WARNING,  
1629                                               "our AdvOtherConfigFlag on %U doesn't agree with %U", 
1630                                               format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1631                         }
1632
1633                       if((h0->time_in_msec_between_retransmitted_neighbor_solicitations && 
1634                           radv_info->adv_time_in_msec_between_retransmitted_neighbor_solicitations) &&
1635                          (h0->time_in_msec_between_retransmitted_neighbor_solicitations !=
1636                           clib_host_to_net_u32(radv_info->adv_time_in_msec_between_retransmitted_neighbor_solicitations)))
1637                         {
1638                           ip6_neighbor_syslog(vm,  LOG_WARNING,  
1639                                               "our AdvRetransTimer on %U doesn't agree with %U", 
1640                                               format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1641                         }
1642
1643                       if((h0->neighbor_reachable_time_in_msec && 
1644                           radv_info->adv_neighbor_reachable_time_in_msec) &&
1645                          (h0->neighbor_reachable_time_in_msec !=
1646                           clib_host_to_net_u32(radv_info->adv_neighbor_reachable_time_in_msec)))
1647                         {
1648                           ip6_neighbor_syslog(vm,  LOG_WARNING,  
1649                                               "our AdvReachableTime on %U doesn't agree with %U", 
1650                                               format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1651                         }
1652
1653                       /* check for MTU or prefix options or .. */
1654                       u8 * opt_hdr = (u8 *)(h0 + 1);
1655                       while( options_len0 > 0)
1656                         {
1657                           icmp6_neighbor_discovery_option_header_t *o0 = ( icmp6_neighbor_discovery_option_header_t *)opt_hdr;
1658                           int opt_len = o0->n_data_u64s << 3;
1659                           icmp6_neighbor_discovery_option_type_t option_type = o0->type;
1660
1661                           if(options_len0 < 2)
1662                             {
1663                               ip6_neighbor_syslog(vm,  LOG_ERR,  
1664                                                   "malformed RA packet on %U from %U", 
1665                                                   format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1666                               break;
1667                             }
1668
1669                           if(opt_len == 0)
1670                             {
1671                               ip6_neighbor_syslog(vm,  LOG_ERR,  
1672                                                   " zero length option in RA on %U from %U", 
1673                                                   format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1674                               break;
1675                             }
1676                           else if( opt_len > options_len0)
1677                             {
1678                               ip6_neighbor_syslog(vm,  LOG_ERR,  
1679                                                   "option length in RA packet  greater than total length on %U from %U", 
1680                                                   format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1681                               break;
1682                             }
1683
1684                           options_len0 -= opt_len;
1685                           opt_hdr += opt_len;
1686
1687                           switch(option_type)
1688                             {
1689                             case ICMP6_NEIGHBOR_DISCOVERY_OPTION_mtu:
1690                               {                       
1691                                 icmp6_neighbor_discovery_mtu_option_t *h =
1692                                   (icmp6_neighbor_discovery_mtu_option_t *)(o0);
1693
1694                                 if(opt_len < sizeof(*h))
1695                                   break;
1696
1697                                 if((h->mtu && radv_info->adv_link_mtu) &&
1698                                    (h->mtu != clib_host_to_net_u32(radv_info->adv_link_mtu)))
1699                                   {
1700                                     ip6_neighbor_syslog(vm,  LOG_WARNING,  
1701                                                         "our AdvLinkMTU on %U doesn't agree with %U", 
1702                                                         format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1703                                   }
1704                               }
1705                               break;
1706                               
1707                             case ICMP6_NEIGHBOR_DISCOVERY_OPTION_prefix_information:
1708                               {
1709                                 icmp6_neighbor_discovery_prefix_information_option_t *h =
1710                                   (icmp6_neighbor_discovery_prefix_information_option_t *)(o0);
1711                               
1712                                 /* validate advertised prefix options  */
1713                                 ip6_radv_prefix_t *pr_info; 
1714                                 u32 preferred, valid;
1715
1716                                 if(opt_len < sizeof(*h))
1717                                   break;
1718
1719                                 preferred =  clib_net_to_host_u32(h->preferred_time);
1720                                 valid =  clib_net_to_host_u32(h->valid_time);
1721
1722                                 /* look for matching prefix - if we our advertising it, it better be consistant */
1723                                 pool_foreach (pr_info, radv_info->adv_prefixes_pool, ({
1724                                       
1725                                       ip6_address_t mask;
1726                                       ip6_address_mask_from_width(&mask, pr_info->prefix_len);
1727
1728                                       if(pr_info->enabled &&
1729                                        (pr_info->prefix_len == h->dst_address_length) &&
1730                                          ip6_address_is_equal_masked (&pr_info->prefix,  &h->dst_address, &mask))
1731                                         {
1732                                           /* found it */
1733                                           if(!pr_info->decrement_lifetime_flag &&
1734                                              valid != pr_info->adv_valid_lifetime_in_secs)
1735                                             {
1736                                               ip6_neighbor_syslog(vm,  LOG_WARNING,  
1737                                                                   "our ADV validlifetime on  %U for %U does not  agree with %U", 
1738                                                                   format_vnet_sw_if_index_name, vnm, sw_if_index0,format_ip6_address, &pr_info->prefix, 
1739                                                                   format_ip6_address, &h->dst_address);
1740                                             }
1741                                           if(!pr_info->decrement_lifetime_flag &&
1742                                              preferred != pr_info->adv_pref_lifetime_in_secs)
1743                                             {
1744                                               ip6_neighbor_syslog(vm,  LOG_WARNING,  
1745                                                                   "our ADV preferredlifetime on  %U for %U does not  agree with %U", 
1746                                                                   format_vnet_sw_if_index_name, vnm, sw_if_index0,format_ip6_address, &pr_info->prefix, 
1747                                                                   format_ip6_address, &h->dst_address);
1748                                             }
1749                                         }
1750                                       break;
1751                                     }));
1752                                 break;
1753                               }
1754                             default:
1755                               /* skip this one */
1756                               break;
1757                             }
1758                         }
1759                     }
1760                 }
1761             }
1762
1763           p0->error = error_node->errors[error0];
1764
1765           if(error0 != ICMP6_ERROR_NONE)
1766             vlib_error_count (vm, error_node->node_index, error0, 1);
1767           
1768           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1769                                            to_next, n_left_to_next,
1770                                            bi0, next0);
1771         }
1772       
1773       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1774     }
1775
1776   /* Account for router advertisements sent. */
1777   vlib_error_count (vm, error_node->node_index, ICMP6_ERROR_ROUTER_ADVERTISEMENTS_RX, n_advertisements_rcvd);
1778
1779   return frame->n_vectors;
1780 }
1781
1782 /* create and initialize router advertisement parameters with default values for this intfc */
1783 static u32
1784 ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm,
1785                                    u32 sw_if_index,
1786                                    u32 is_add)
1787 {
1788   ip6_neighbor_main_t * nm = &ip6_neighbor_main;  
1789   ip6_radv_t * a= 0;  
1790   u32 ri = ~0;
1791   vnet_sw_interface_t * sw_if0;
1792   ethernet_interface_t * eth_if0 = 0; 
1793
1794   /* lookup radv container  - ethernet interfaces only */
1795   sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
1796   if(sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
1797     eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
1798
1799   if(!eth_if0)
1800     return ri;
1801    
1802   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
1803   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
1804
1805   if(ri != ~0)
1806     {
1807       a = pool_elt_at_index (nm->if_radv_pool, ri);
1808
1809       if(!is_add)
1810         {
1811           u32 i, * to_delete = 0;
1812           ip6_radv_prefix_t  *p;
1813           ip6_mldp_group_t *m;
1814           
1815           /* remove adjacencies */
1816           adj_unlock(a->all_nodes_adj_index); 
1817           adj_unlock(a->all_routers_adj_index);       
1818           adj_unlock(a->all_mldv2_routers_adj_index);
1819           
1820           /* clean up prefix_pool */
1821           pool_foreach (p, a->adv_prefixes_pool, ({
1822                 vec_add1 (to_delete, p  -  a->adv_prefixes_pool);
1823               }));
1824           
1825           for (i = 0; i < vec_len (to_delete); i++)
1826             {
1827               p = pool_elt_at_index (a->adv_prefixes_pool, to_delete[i]);
1828               mhash_unset (&a->address_to_prefix_index, &p->prefix, 0);
1829               pool_put (a->adv_prefixes_pool, p);
1830             }
1831           
1832           vec_free (to_delete);
1833           to_delete = 0;
1834           
1835           /* clean up mldp group pool */
1836           pool_foreach (m, a->mldp_group_pool, ({
1837                 vec_add1 (to_delete, m  -  a->mldp_group_pool);
1838               }));
1839           
1840           for (i = 0; i < vec_len (to_delete); i++)
1841             {
1842               m = pool_elt_at_index (a->mldp_group_pool, to_delete[i]);
1843               mhash_unset (&a->address_to_mldp_index, &m->mcast_address, 0);
1844               pool_put (a->mldp_group_pool, m);
1845             }
1846           
1847           vec_free (to_delete);
1848           
1849           pool_put (nm->if_radv_pool,  a);
1850           nm->if_radv_pool_index_by_sw_if_index[sw_if_index] = ~0;
1851           ri = ~0;
1852         }
1853     }
1854  else
1855    {
1856      if(is_add)
1857        {
1858          vnet_hw_interface_t * hw_if0;
1859      
1860          hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index);
1861          
1862          pool_get (nm->if_radv_pool, a);
1863          
1864          ri = a - nm->if_radv_pool;
1865          nm->if_radv_pool_index_by_sw_if_index[sw_if_index] = ri;
1866          
1867          /* initialize default values (most of which are zero) */
1868          memset (a, 0, sizeof (a[0]));
1869          
1870          a->sw_if_index = sw_if_index;
1871          a->fib_index = ~0;
1872          a->max_radv_interval = DEF_MAX_RADV_INTERVAL;    
1873          a->min_radv_interval =  DEF_MIN_RADV_INTERVAL;    
1874          a->curr_hop_limit = DEF_CURR_HOP_LIMIT;                         
1875          a->adv_router_lifetime_in_sec = DEF_DEF_RTR_LIFETIME;   
1876          
1877          a->adv_link_layer_address = 1;  /* send ll address source address option */
1878          
1879          a->min_delay_between_radv = MIN_DELAY_BETWEEN_RAS;
1880          a->max_delay_between_radv = MAX_DELAY_BETWEEN_RAS;
1881          a->max_rtr_default_lifetime = MAX_DEF_RTR_LIFETIME;
1882          a->seed = (u32) clib_cpu_time_now();
1883          (void) random_u32 (&a->seed);
1884          a->randomizer = clib_cpu_time_now();
1885          (void) random_u64 (&a->randomizer);
1886          
1887          a->initial_adverts_count = MAX_INITIAL_RTR_ADVERTISEMENTS ; 
1888          a->initial_adverts_sent = a->initial_adverts_count-1;
1889          a->initial_adverts_interval = MAX_INITIAL_RTR_ADVERT_INTERVAL;      
1890          
1891          /* deafult is to send */
1892          a->send_radv = 1;
1893          
1894          /* fill in radv_info for this interface that will be needed later */
1895          a->adv_link_mtu = hw_if0->max_l3_packet_bytes[VLIB_RX];
1896          
1897          clib_memcpy (a->link_layer_address, eth_if0->address, 6);
1898          
1899          /* fill in default link-local address  (this may be overridden) */
1900          ip6_link_local_address_from_ethernet_address (&a->link_local_address, eth_if0->address);
1901          a->link_local_prefix_len = 64;
1902
1903          mhash_init (&a->address_to_prefix_index, sizeof (uword), sizeof (ip6_address_t));
1904          mhash_init (&a->address_to_mldp_index, sizeof (uword), sizeof (ip6_address_t)); 
1905          
1906          {
1907            u8 link_layer_address[6] = 
1908              {0x33, 0x33, 0x00, 0x00, 0x00, IP6_MULTICAST_GROUP_ID_all_hosts};
1909            
1910            a->all_nodes_adj_index = adj_rewrite_add_and_lock(FIB_PROTOCOL_IP6,
1911                                                              VNET_LINK_IP6,
1912                                                              sw_if_index,
1913                                                              link_layer_address);
1914          } 
1915          
1916          {
1917            u8 link_layer_address[6] = 
1918              {0x33, 0x33, 0x00, 0x00, 0x00, IP6_MULTICAST_GROUP_ID_all_routers};
1919         
1920            a->all_routers_adj_index = adj_rewrite_add_and_lock(FIB_PROTOCOL_IP6,
1921                                                                VNET_LINK_IP6,
1922                                                                sw_if_index,
1923                                                                link_layer_address);
1924          } 
1925          
1926          {
1927            u8 link_layer_address[6] = 
1928              {0x33, 0x33, 0x00, 0x00, 0x00, IP6_MULTICAST_GROUP_ID_mldv2_routers};
1929            
1930            a->all_mldv2_routers_adj_index = 
1931                adj_rewrite_add_and_lock(FIB_PROTOCOL_IP6,
1932                                         VNET_LINK_IP6,
1933                                         sw_if_index,
1934                                         link_layer_address);
1935          } 
1936          
1937          /* add multicast groups we will always be reporting  */
1938          ip6_address_t addr;
1939          ip6_mldp_group_t  *mcast_group_info;
1940          
1941          ip6_set_reserved_multicast_address (&addr,
1942                                              IP6_MULTICAST_SCOPE_link_local,
1943                                              IP6_MULTICAST_GROUP_ID_all_hosts);
1944          
1945          /* lookup  mldp info for this interface */
1946          
1947          uword * p = mhash_get (&a->address_to_mldp_index,  &addr);
1948          mcast_group_info = p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0;
1949          
1950          /* add address */
1951          if(!mcast_group_info)
1952            {
1953              /* add */
1954              u32 mi;
1955              pool_get (a->mldp_group_pool, mcast_group_info);
1956           
1957              mi = mcast_group_info - a->mldp_group_pool;
1958              mhash_set (&a->address_to_mldp_index,  &addr,  mi, /* old_value */ 0);
1959              
1960              mcast_group_info->type = 4;
1961              mcast_group_info->mcast_source_address_pool = 0;
1962              mcast_group_info->num_sources = 0;
1963              clib_memcpy(&mcast_group_info->mcast_address, &addr, sizeof(ip6_address_t));
1964            } 
1965          
1966          ip6_set_reserved_multicast_address (&addr,
1967                                              IP6_MULTICAST_SCOPE_link_local,
1968                                              IP6_MULTICAST_GROUP_ID_all_routers);
1969          
1970          p = mhash_get (&a->address_to_mldp_index,  &addr);
1971          mcast_group_info = p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0;
1972          
1973          if(!mcast_group_info)
1974            {
1975              /* add */
1976              u32 mi;
1977              pool_get (a->mldp_group_pool, mcast_group_info);
1978              
1979              mi = mcast_group_info - a->mldp_group_pool;
1980              mhash_set (&a->address_to_mldp_index,  &addr,  mi, /* old_value */ 0);
1981              
1982              mcast_group_info->type = 4;
1983              mcast_group_info->mcast_source_address_pool = 0;
1984              mcast_group_info->num_sources = 0;
1985              clib_memcpy(&mcast_group_info->mcast_address, &addr, sizeof(ip6_address_t));
1986            } 
1987          
1988          ip6_set_reserved_multicast_address (&addr,
1989                                              IP6_MULTICAST_SCOPE_link_local,
1990                                              IP6_MULTICAST_GROUP_ID_mldv2_routers);
1991          
1992          p = mhash_get (&a->address_to_mldp_index,  &addr);
1993          mcast_group_info = p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0;
1994          
1995          if(!mcast_group_info)
1996            {
1997              /* add */
1998              u32 mi;
1999              pool_get (a->mldp_group_pool, mcast_group_info);
2000              
2001              mi = mcast_group_info - a->mldp_group_pool;
2002              mhash_set (&a->address_to_mldp_index,  &addr,  mi, /* old_value */ 0);
2003              
2004              mcast_group_info->type = 4;
2005              mcast_group_info->mcast_source_address_pool = 0;
2006              mcast_group_info->num_sources = 0;
2007              clib_memcpy(&mcast_group_info->mcast_address, &addr, sizeof(ip6_address_t));
2008            } 
2009        }
2010    } 
2011   return  ri;
2012 }
2013
2014 /* send an mldpv2 report  */
2015 static void
2016 ip6_neighbor_send_mldpv2_report(u32 sw_if_index)
2017 {
2018   vnet_main_t * vnm = vnet_get_main();
2019   vlib_main_t * vm = vnm->vlib_main;
2020   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2021   vnet_sw_interface_t * sw_if0;
2022   ethernet_interface_t * eth_if0;
2023   u32 ri;
2024   int bogus_length;
2025
2026   ip6_radv_t *radv_info; 
2027   u16 payload_length;
2028   vlib_buffer_t * b0;
2029   ip6_header_t * ip0;
2030   u32 * to_next;
2031   vlib_frame_t * f;
2032   u32 bo0;
2033   u32 n_to_alloc = 1;
2034   u32 n_allocated;
2035   
2036   icmp6_multicast_listener_report_header_t *rh0;
2037   icmp6_multicast_listener_report_packet_t *rp0;
2038
2039   sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
2040   ASSERT (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
2041   eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
2042
2043   if (!eth_if0 || !vnet_sw_interface_is_admin_up (vnm, sw_if_index))
2044     return;
2045
2046   /* look up the radv_t  information for this interface */
2047   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2048   
2049   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2050   
2051   if(ri == ~0)
2052     return;
2053                 
2054   /* send report now - build a mldpv2 report packet  */
2055   n_allocated = vlib_buffer_alloc_from_free_list(vm, 
2056                                                  &bo0, 
2057                                                  n_to_alloc,
2058                                                  VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
2059   if (PREDICT_FALSE(n_allocated == 0))
2060     {
2061       clib_warning ("buffer allocation failure");
2062       return;
2063     }
2064
2065   b0 = vlib_get_buffer (vm, bo0);
2066
2067   /* adjust the sizeof the buffer to just include the ipv6 header */
2068   b0->current_length  = sizeof(icmp6_multicast_listener_report_packet_t);
2069
2070   payload_length = sizeof(icmp6_multicast_listener_report_header_t);
2071
2072   b0->error = ICMP6_ERROR_NONE;
2073
2074   rp0 = vlib_buffer_get_current (b0);
2075   ip0 = (ip6_header_t *)&rp0-> ip;
2076   rh0 = (icmp6_multicast_listener_report_header_t *)&rp0-> report_hdr;
2077   
2078   memset (rp0 , 0x0, sizeof (icmp6_multicast_listener_report_packet_t));
2079   
2080   ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (0x6 << 28);
2081
2082   ip0->protocol = IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS;  
2083   /* for DEBUG - vnet driver won't seem to emit router alerts */
2084   /* ip0->protocol = IP_PROTOCOL_ICMP6; */
2085   ip0->hop_limit = 1;
2086  
2087   rh0->icmp.type = ICMP6_multicast_listener_report_v2;
2088   
2089   /* source address MUST be the link-local address */
2090   radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
2091   ip0->src_address = radv_info->link_local_address;  
2092
2093   /* destination is all mldpv2 routers */
2094   ip6_set_reserved_multicast_address(&ip0->dst_address, 
2095                                      IP6_MULTICAST_SCOPE_link_local,
2096                                      IP6_MULTICAST_GROUP_ID_mldv2_routers);
2097   
2098   /* add reports here */
2099   ip6_mldp_group_t *m;
2100   int num_addr_records = 0;
2101   icmp6_multicast_address_record_t rr;
2102
2103   /* fill in the hop-by-hop extension header (router alert) info */
2104   rh0->ext_hdr.next_hdr = IP_PROTOCOL_ICMP6;
2105   rh0->ext_hdr.n_data_u64s = 0;
2106   
2107   rh0->alert.type = IP6_MLDP_ALERT_TYPE;
2108   rh0->alert.len = 2;
2109   rh0->alert.value = 0;
2110   
2111   rh0->pad.type = 1;
2112   rh0->pad.len = 0;
2113  
2114   rh0->icmp.checksum = 0;
2115
2116   pool_foreach (m, radv_info->mldp_group_pool, ({
2117
2118         rr.type = m->type;
2119         rr.aux_data_len_u32s = 0;
2120         rr.num_sources = clib_host_to_net_u16 (m->num_sources);
2121         clib_memcpy(&rr.mcast_addr, &m->mcast_address, sizeof(ip6_address_t));
2122
2123         num_addr_records++;
2124
2125         vlib_buffer_add_data (vm,
2126                               b0->free_list_index,
2127                               bo0,
2128                               (void *)&rr, sizeof(icmp6_multicast_address_record_t));
2129         
2130         payload_length += sizeof( icmp6_multicast_address_record_t);
2131       }));
2132
2133   rh0->rsvd = 0;
2134   rh0->num_addr_records =  clib_host_to_net_u16(num_addr_records);
2135   
2136   /* update lengths */
2137   ip0->payload_length = clib_host_to_net_u16 (payload_length);
2138
2139   rh0->icmp.checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0, 
2140                                                           &bogus_length);
2141   ASSERT(bogus_length == 0);
2142
2143   /* 
2144    * OK to override w/ no regard for actual FIB, because
2145    * ip6-rewrite-local only looks at the adjacency.
2146    */
2147   vnet_buffer (b0)->sw_if_index[VLIB_RX] = 
2148     vnet_main.local_interface_sw_if_index;
2149   
2150   vnet_buffer (b0)->ip.adj_index[VLIB_RX]  = 
2151     radv_info->all_mldv2_routers_adj_index;
2152
2153   vlib_node_t * node = vlib_get_node_by_name (vm, (u8 *) "ip6-rewrite-local");
2154   
2155   f = vlib_get_frame_to_node (vm, node->index);
2156   to_next = vlib_frame_vector_args (f);
2157   to_next[0] = bo0;
2158   f->n_vectors = 1;
2159   
2160   vlib_put_frame_to_node (vm, node->index, f);
2161   return;
2162 }
2163
2164 VLIB_REGISTER_NODE (ip6_icmp_router_solicitation_node,static) = {
2165   .function = icmp6_router_solicitation,
2166   .name = "icmp6-router-solicitation",
2167
2168   .vector_size = sizeof (u32),
2169
2170   .format_trace = format_icmp6_input_trace,
2171
2172   .n_next_nodes = ICMP6_ROUTER_SOLICITATION_N_NEXT,
2173   .next_nodes = {
2174     [ICMP6_ROUTER_SOLICITATION_NEXT_DROP] = "error-drop",
2175     [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW] = "ip6-rewrite-local",
2176     [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX] = "interface-output",
2177   },
2178 };
2179
2180 /* send a RA or update the timer info etc.. */
2181 static uword
2182 ip6_neighbor_process_timer_event (vlib_main_t * vm,
2183                                            vlib_node_runtime_t * node,
2184                                            vlib_frame_t * frame)
2185 {
2186   vnet_main_t * vnm = vnet_get_main();
2187   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2188   ip6_radv_t *radv_info; 
2189   vlib_frame_t * f = 0; 
2190   u32 n_this_frame = 0;
2191   u32 n_left_to_next = 0;
2192   u32 * to_next = 0;
2193   u32 bo0; 
2194   icmp6_router_solicitation_header_t * h0;
2195   vlib_buffer_t * b0;
2196   f64 now = vlib_time_now (vm);
2197
2198   /* Interface ip6 radv info list */
2199   pool_foreach (radv_info, nm->if_radv_pool, ({
2200
2201         if( !vnet_sw_interface_is_admin_up (vnm, radv_info->sw_if_index))
2202           {
2203             radv_info->initial_adverts_sent = radv_info->initial_adverts_count-1;
2204             radv_info->next_multicast_time = now;             
2205             radv_info->last_multicast_time = now;
2206             radv_info->last_radv_time = 0;      
2207             radv_info->all_routers_mcast = 0;
2208             continue;
2209           }
2210
2211         /* Make sure that we've joined the all-routers multicast group */
2212         if(!radv_info->all_routers_mcast)
2213           {
2214             /* send MDLP_REPORT_EVENT message */              
2215             ip6_neighbor_send_mldpv2_report(radv_info->sw_if_index);
2216             radv_info->all_routers_mcast = 1;
2217           }
2218
2219         /* is it time to send a multicast  RA on this interface? */
2220         if(radv_info->send_radv && (now >=  radv_info->next_multicast_time))
2221           {     
2222             u32 n_to_alloc = 1;
2223             u32 n_allocated;
2224             
2225             f64 rfn = (radv_info->max_radv_interval - radv_info->min_radv_interval) * 
2226               random_f64 (&radv_info->seed) + radv_info->min_radv_interval;
2227
2228             /* multicast send - compute next multicast send time */
2229             if( radv_info->initial_adverts_sent > 0)
2230               {
2231                 radv_info->initial_adverts_sent--;
2232                 if(rfn > radv_info-> initial_adverts_interval)
2233                   rfn =  radv_info-> initial_adverts_interval;
2234
2235                 /* check to see if we are ceasing to send */
2236                 if( radv_info->initial_adverts_sent  == 0)
2237                   if(radv_info->cease_radv)  
2238                     radv_info->send_radv = 0;
2239               }
2240             
2241             radv_info->next_multicast_time =  rfn + now;
2242             radv_info->last_multicast_time = now;
2243             
2244             /* send advert now - build a "solicted" router advert with unspecified source address */
2245             n_allocated = vlib_buffer_alloc_from_free_list(vm, 
2246                                                            &bo0, 
2247                                                            n_to_alloc,
2248                                                            VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
2249             
2250             if (PREDICT_FALSE(n_allocated == 0))
2251               {
2252                 clib_warning ("buffer allocation failure");
2253                 continue;
2254               }
2255             b0 = vlib_get_buffer (vm, bo0);
2256             b0->current_length = sizeof( icmp6_router_solicitation_header_t);
2257             b0->error = ICMP6_ERROR_NONE;
2258             vnet_buffer (b0)->sw_if_index[VLIB_RX] = radv_info->sw_if_index;
2259             
2260             h0 =  vlib_buffer_get_current (b0);
2261             
2262             memset (h0, 0, sizeof (icmp6_router_solicitation_header_t));
2263             
2264             h0->ip.ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (0x6 << 28);
2265             h0->ip.payload_length = clib_host_to_net_u16 (sizeof (icmp6_router_solicitation_header_t)
2266                                                           - STRUCT_OFFSET_OF (icmp6_router_solicitation_header_t, neighbor));
2267             h0->ip.protocol = IP_PROTOCOL_ICMP6;
2268             h0->ip.hop_limit = 255;
2269             
2270             /* set src/dst address as "unspecified" this marks this packet as internally generated rather than recieved */
2271             h0->ip.src_address.as_u64[0] = 0;
2272             h0->ip.src_address.as_u64[1] = 0;
2273             
2274             h0->ip.dst_address.as_u64[0] = 0;
2275             h0->ip.dst_address.as_u64[1] = 0;
2276             
2277             h0->neighbor.icmp.type = ICMP6_router_solicitation;
2278
2279             if (PREDICT_FALSE(f == 0))
2280               { 
2281                 f = vlib_get_frame_to_node (vm, ip6_icmp_router_solicitation_node.index);
2282                 to_next = vlib_frame_vector_args (f);
2283                 n_left_to_next = VLIB_FRAME_SIZE;
2284                 n_this_frame = 0;
2285               }
2286
2287             n_this_frame++;
2288             n_left_to_next--;
2289             to_next[0] = bo0;
2290             to_next += 1;
2291
2292             if (PREDICT_FALSE(n_left_to_next == 0)) 
2293               {
2294                 f->n_vectors = n_this_frame;
2295                 vlib_put_frame_to_node (vm, ip6_icmp_router_solicitation_node.index, f);
2296                 f = 0;
2297               }
2298           }
2299       }));
2300
2301   if (f)
2302     {
2303       ASSERT(n_this_frame);
2304       f->n_vectors = n_this_frame;
2305       vlib_put_frame_to_node (vm, ip6_icmp_router_solicitation_node.index, f);
2306     }
2307   return  0;
2308 }
2309
2310 static uword
2311 ip6_icmp_neighbor_discovery_event_process (vlib_main_t * vm,
2312                                            vlib_node_runtime_t * node,
2313                                            vlib_frame_t * frame)
2314 {
2315   uword event_type;
2316   ip6_icmp_neighbor_discovery_event_data_t * event_data;
2317
2318   /* init code here */
2319  
2320   while (1)
2321     {
2322       vlib_process_wait_for_event_or_clock (vm,  1. /* seconds */);
2323
2324       event_data = vlib_process_get_event_data (vm,  &event_type);
2325
2326       if(!event_data)
2327         {
2328           /* No events found: timer expired. */
2329           /* process interface list and send RAs as appropriate, update timer info */
2330           ip6_neighbor_process_timer_event (vm,  node,  frame); 
2331         }
2332       else
2333         {
2334           switch (event_type) {
2335
2336           case ICMP6_ND_EVENT_INIT:
2337             break;
2338    
2339           case ~0:
2340             break;
2341             
2342           default:
2343             ASSERT (0);
2344           }
2345           
2346           if (event_data)
2347             _vec_len (event_data) = 0;
2348         }
2349     }
2350   return frame->n_vectors;
2351 }
2352
2353 VLIB_REGISTER_NODE (ip6_icmp_router_advertisement_node,static) = {
2354   .function = icmp6_router_advertisement,
2355   .name = "icmp6-router-advertisement",
2356
2357   .vector_size = sizeof (u32),
2358
2359   .format_trace = format_icmp6_input_trace,
2360
2361   .n_next_nodes = 1,
2362   .next_nodes = {
2363     [0] = "error-drop",
2364   },
2365 };
2366
2367 vlib_node_registration_t ip6_icmp_neighbor_discovery_event_node = {
2368
2369   .function = ip6_icmp_neighbor_discovery_event_process,
2370   .name = "ip6-icmp-neighbor-discovery-event-process",
2371   .type = VLIB_NODE_TYPE_PROCESS,
2372 };
2373
2374 static uword
2375 icmp6_neighbor_solicitation (vlib_main_t * vm,
2376                              vlib_node_runtime_t * node,
2377                              vlib_frame_t * frame)
2378 { return icmp6_neighbor_solicitation_or_advertisement (vm, node, frame, /* is_solicitation */ 1); }
2379
2380 static uword
2381 icmp6_neighbor_advertisement (vlib_main_t * vm,
2382                               vlib_node_runtime_t * node,
2383                               vlib_frame_t * frame)
2384 { return icmp6_neighbor_solicitation_or_advertisement (vm, node, frame, /* is_solicitation */ 0); }
2385
2386 VLIB_REGISTER_NODE (ip6_icmp_neighbor_solicitation_node,static) = {
2387   .function = icmp6_neighbor_solicitation,
2388   .name = "icmp6-neighbor-solicitation",
2389
2390   .vector_size = sizeof (u32),
2391
2392   .format_trace = format_icmp6_input_trace,
2393
2394   .n_next_nodes = ICMP6_NEIGHBOR_SOLICITATION_N_NEXT,
2395   .next_nodes = {
2396     [ICMP6_NEIGHBOR_SOLICITATION_NEXT_DROP] = "error-drop",
2397     [ICMP6_NEIGHBOR_SOLICITATION_NEXT_REPLY] = "interface-output",
2398   },
2399 };
2400
2401 VLIB_REGISTER_NODE (ip6_icmp_neighbor_advertisement_node,static) = {
2402   .function = icmp6_neighbor_advertisement,
2403   .name = "icmp6-neighbor-advertisement",
2404
2405   .vector_size = sizeof (u32),
2406
2407   .format_trace = format_icmp6_input_trace,
2408
2409   .n_next_nodes = 1,
2410   .next_nodes = {
2411     [0] = "error-drop",
2412   },
2413 };
2414
2415 /* API  support functions */
2416 int
2417 ip6_neighbor_ra_config(vlib_main_t * vm, u32 sw_if_index, 
2418                        u8 suppress, u8 managed, u8 other,
2419                        u8 ll_option,  u8 send_unicast,  u8 cease, 
2420                        u8 use_lifetime,  u32 lifetime,
2421                        u32 initial_count,  u32 initial_interval,  
2422                        u32 max_interval,  u32 min_interval,
2423                        u8 is_no)
2424 {
2425   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2426   int  error;
2427   u32 ri;
2428
2429   /* look up the radv_t  information for this interface */
2430   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2431   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2432   error = (ri != ~0) ? 0 :  VNET_API_ERROR_INVALID_SW_IF_INDEX;
2433
2434   if(!error)
2435     {
2436
2437       ip6_radv_t * radv_info;
2438       radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
2439   
2440       if((max_interval != 0) && (min_interval ==0))
2441         min_interval =  .75 * max_interval;
2442
2443       max_interval  = (max_interval != 0) ? ( (is_no) ?  DEF_MAX_RADV_INTERVAL :  max_interval) :  radv_info->max_radv_interval;
2444       min_interval  = (min_interval != 0) ? ( (is_no) ?  DEF_MIN_RADV_INTERVAL :  min_interval) :  radv_info->min_radv_interval; 
2445       lifetime  = (use_lifetime != 0) ? ( (is_no) ?  DEF_DEF_RTR_LIFETIME :  lifetime) :  radv_info->adv_router_lifetime_in_sec;
2446
2447       if(lifetime)
2448         {
2449           if(lifetime  > MAX_DEF_RTR_LIFETIME)
2450             lifetime = MAX_DEF_RTR_LIFETIME;
2451           
2452           if(lifetime <= max_interval)
2453             return VNET_API_ERROR_INVALID_VALUE;
2454         }
2455       
2456       if(min_interval  != 0)
2457         {
2458           if((min_interval > .75 * max_interval) ||
2459              (min_interval  < 3))
2460             return VNET_API_ERROR_INVALID_VALUE;
2461         }
2462
2463       if((initial_count  > MAX_INITIAL_RTR_ADVERTISEMENTS) ||
2464          (initial_interval  > MAX_INITIAL_RTR_ADVERT_INTERVAL))
2465         return VNET_API_ERROR_INVALID_VALUE;
2466
2467       /* 
2468          if "flag" is set and is_no is true then restore default value else set value corresponding to "flag" 
2469          if "flag" is clear  don't change corresponding value  
2470       */
2471       radv_info->send_radv =  (suppress != 0) ? ( (is_no  != 0) ? 1 : 0 ) : radv_info->send_radv;
2472       radv_info->adv_managed_flag = ( managed  != 0) ? ( (is_no) ? 0 : 1) : radv_info->adv_managed_flag;
2473       radv_info->adv_other_flag  = (other  != 0) ? ( (is_no) ?  0: 1) : radv_info->adv_other_flag;
2474       radv_info->adv_link_layer_address = ( ll_option != 0) ? ( (is_no) ? 1 : 0) : radv_info->adv_link_layer_address;
2475       radv_info->send_unicast  = (send_unicast  != 0) ? ( (is_no) ? 0 : 1) : radv_info->send_unicast;
2476       radv_info->cease_radv = ( cease != 0) ? ( (is_no) ?  0 : 1) : radv_info->cease_radv;
2477       
2478       radv_info->min_radv_interval  =  min_interval;
2479       radv_info->max_radv_interval = max_interval;
2480       radv_info->adv_router_lifetime_in_sec = lifetime;
2481
2482       radv_info->initial_adverts_count = 
2483         (initial_count  != 0) ? ( (is_no) ?   MAX_INITIAL_RTR_ADVERTISEMENTS  :  initial_count) : radv_info->initial_adverts_count ;
2484       radv_info->initial_adverts_interval = 
2485         (initial_interval  != 0) ? ( (is_no) ?  MAX_INITIAL_RTR_ADVERT_INTERVAL  :  initial_interval) : radv_info->initial_adverts_interval;
2486
2487       /* restart */
2488       if((cease != 0) && (is_no))
2489          radv_info-> send_radv = 1;
2490
2491       radv_info->initial_adverts_sent  = radv_info->initial_adverts_count -1;
2492       radv_info->next_multicast_time =  vlib_time_now (vm);    
2493       radv_info->last_multicast_time = vlib_time_now (vm);
2494       radv_info->last_radv_time = 0;    
2495     }
2496   return(error);
2497 }
2498
2499 int
2500 ip6_neighbor_ra_prefix(vlib_main_t * vm, u32 sw_if_index,  
2501                        ip6_address_t *prefix_addr,  u8 prefix_len,
2502                        u8 use_default,  u32 val_lifetime, u32 pref_lifetime,
2503                        u8 no_advertise,  u8 off_link, u8 no_autoconfig, u8 no_onlink,
2504                        u8 is_no)
2505 {
2506   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2507   int error;
2508   
2509   u32 ri;
2510
2511   /* look up the radv_t  information for this interface */
2512   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2513   
2514   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2515
2516   error = (ri != ~0) ? 0 : VNET_API_ERROR_INVALID_SW_IF_INDEX;
2517   
2518   if(!error)
2519     {
2520       f64 now = vlib_time_now (vm);
2521       ip6_radv_t * radv_info;
2522       radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
2523
2524       /* prefix info add, delete or update */
2525       ip6_radv_prefix_t * prefix; 
2526         
2527       /* lookup  prefix info for this  address on this interface */
2528       uword * p = mhash_get (&radv_info->address_to_prefix_index,  prefix_addr);
2529       
2530       prefix = p ? pool_elt_at_index (radv_info->adv_prefixes_pool, p[0]) : 0;
2531
2532       if(is_no)
2533         {
2534           /* delete */
2535           if(!prefix)
2536             return VNET_API_ERROR_INVALID_VALUE; /* invalid prefix */
2537     
2538           if(prefix->prefix_len != prefix_len)
2539             return VNET_API_ERROR_INVALID_VALUE_2;
2540
2541           /* FIXME - Should the DP do this or the CP ?*/
2542           /* do specific delete processing here before returning */
2543           /* try to remove from routing table */
2544
2545           mhash_unset (&radv_info->address_to_prefix_index, prefix_addr,/* old_value */ 0);
2546           pool_put (radv_info->adv_prefixes_pool, prefix);
2547
2548           radv_info->initial_adverts_sent  = radv_info->initial_adverts_count -1;
2549           radv_info->next_multicast_time =  vlib_time_now (vm);    
2550           radv_info->last_multicast_time = vlib_time_now (vm);
2551           radv_info->last_radv_time = 0;        
2552           return(error);
2553         }
2554
2555       /* adding or changing */
2556       if(!prefix)
2557         {
2558           /* add */
2559           u32 pi;
2560           pool_get (radv_info->adv_prefixes_pool, prefix);
2561           pi = prefix - radv_info->adv_prefixes_pool;
2562           mhash_set (&radv_info->address_to_prefix_index,  prefix_addr,  pi, /* old_value */ 0);
2563           
2564           memset(prefix, 0x0, sizeof(ip6_radv_prefix_t));
2565           
2566           prefix->prefix_len = prefix_len;
2567           clib_memcpy(&prefix->prefix,  prefix_addr, sizeof(ip6_address_t));
2568           
2569           /* initialize default values */
2570           prefix->adv_on_link_flag = 1;      /* L bit set */
2571           prefix->adv_autonomous_flag = 1;  /* A bit set */
2572           prefix->adv_valid_lifetime_in_secs =  DEF_ADV_VALID_LIFETIME;
2573           prefix->adv_pref_lifetime_in_secs = DEF_ADV_PREF_LIFETIME;
2574           prefix->enabled = 1;
2575           prefix->decrement_lifetime_flag = 1;
2576           prefix->deprecated_prefix_flag = 1;
2577
2578           if(off_link == 0)
2579             {
2580               /* FIXME - Should the DP do this or the CP ?*/
2581               /* insert prefix into routing table as a connected prefix */
2582             }
2583
2584           if(use_default)
2585             goto restart;
2586         }
2587       else
2588         {
2589           
2590           if(prefix->prefix_len != prefix_len)
2591             return VNET_API_ERROR_INVALID_VALUE_2;
2592
2593           if(off_link  != 0)
2594             {
2595               /* FIXME - Should the DP do this or the CP ?*/
2596               /* remove from routing table if already there */
2597             }     
2598         }
2599
2600       if((val_lifetime == ~0) || (pref_lifetime == ~0))
2601         {
2602           prefix->adv_valid_lifetime_in_secs =  ~0;
2603           prefix->adv_pref_lifetime_in_secs = ~0;
2604           prefix->decrement_lifetime_flag = 0;
2605         }
2606       else
2607         {
2608           prefix->adv_valid_lifetime_in_secs =  val_lifetime;;
2609           prefix->adv_pref_lifetime_in_secs =  pref_lifetime;
2610         }
2611       
2612       /* copy  remaining */
2613       prefix->enabled = !(no_advertise != 0);
2614       prefix->adv_on_link_flag = !((off_link != 0) || (no_onlink != 0));
2615       prefix->adv_autonomous_flag = !(no_autoconfig != 0);
2616
2617  restart:
2618       /* restart */
2619       /* fill in the expiration times  */
2620       prefix->valid_lifetime_expires = now + prefix->adv_valid_lifetime_in_secs;
2621       prefix->pref_lifetime_expires = now + prefix->adv_pref_lifetime_in_secs;
2622           
2623       radv_info->initial_adverts_sent  = radv_info->initial_adverts_count -1;
2624       radv_info->next_multicast_time =  vlib_time_now (vm);    
2625       radv_info->last_multicast_time = vlib_time_now (vm);
2626       radv_info->last_radv_time = 0;    
2627     }
2628   return(error);
2629 }
2630
2631 clib_error_t *
2632 ip6_neighbor_cmd(vlib_main_t * vm, unformat_input_t * main_input, vlib_cli_command_t * cmd)
2633 {
2634   vnet_main_t * vnm = vnet_get_main();
2635   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2636   clib_error_t * error = 0;
2637   u8 is_no = 0;
2638   u8 suppress = 0,  managed = 0,  other = 0;
2639   u8 suppress_ll_option = 0,  send_unicast = 0,  cease= 0; 
2640   u8 use_lifetime = 0;
2641   u32 sw_if_index, ra_lifetime = 0, ra_initial_count = 0, ra_initial_interval = 0;
2642   u32 ra_max_interval = 0 , ra_min_interval = 0;
2643
2644   unformat_input_t _line_input, * line_input = &_line_input;
2645   vnet_sw_interface_t * sw_if0;
2646
2647   int add_radv_info = 1;
2648   __attribute__((unused)) ip6_radv_t * radv_info = 0;
2649   ip6_address_t ip6_addr;
2650   u32 addr_len;
2651  
2652
2653   /* Get a line of input. */
2654   if (! unformat_user (main_input, unformat_line_input, line_input))
2655     return 0;
2656
2657   /* get basic radv info for this interface */
2658   if(unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2659     {
2660
2661       if (unformat_user (line_input, 
2662                          unformat_vnet_sw_interface, vnm, &sw_if_index))
2663         {
2664           u32 ri;
2665           ethernet_interface_t * eth_if0 = 0;
2666           
2667           sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
2668           if(sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
2669             eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
2670           
2671           if(!eth_if0)
2672             {
2673               error = clib_error_return (0, "Interface must be of ethernet type");
2674               goto done;
2675             }
2676           
2677           /* look up the radv_t  information for this interface */
2678           vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2679           
2680           ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2681           
2682           if(ri != ~0)
2683             {
2684               radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
2685             }
2686           else
2687             {
2688               error = clib_error_return (0, "unknown interface %U'",
2689                                          format_unformat_error, line_input);
2690               goto done;
2691             }
2692         }
2693       else
2694         {
2695           error = clib_error_return (0, "invalid interface name %U'",
2696                                      format_unformat_error, line_input);
2697           goto done;
2698         }
2699     }
2700
2701   /* get the rest of the command */
2702   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2703     {
2704       if (unformat (line_input, "no"))
2705          is_no = 1;
2706       else if(unformat (line_input, "prefix %U/%d",
2707                         unformat_ip6_address, &ip6_addr,
2708                         &addr_len))
2709         {
2710           add_radv_info = 0;
2711           break;
2712         }
2713       else if (unformat (line_input, "ra-managed-config-flag"))
2714         {
2715           managed = 1;
2716           break;
2717         }
2718       else if (unformat (line_input, "ra-other-config-flag"))
2719         {
2720           other = 1;
2721           break;
2722         }
2723       else if (unformat (line_input, "ra-suppress") ||
2724                       unformat (line_input, "ra-surpress"))
2725         {
2726           suppress = 1;
2727           break;
2728         }
2729       else if (unformat (line_input, "ra-suppress-link-layer") ||
2730                       unformat (line_input, "ra-surpress-link-layer"))
2731         {
2732           suppress_ll_option = 1;
2733           break;
2734         }
2735       else if (unformat (line_input, "ra-send-unicast"))
2736         {
2737           send_unicast = 1;
2738           break;
2739         }
2740       else if (unformat (line_input, "ra-lifetime"))
2741         {
2742           if (!unformat (line_input, "%d", &ra_lifetime))
2743             return(error = unformat_parse_error (line_input));
2744           use_lifetime = 1;
2745           break;
2746         }  
2747       else if (unformat (line_input, "ra-initial"))
2748         {
2749           if (!unformat (line_input, "%d %d", &ra_initial_count, &ra_initial_interval))
2750             return(error = unformat_parse_error (line_input));
2751           break;
2752         }
2753       else if (unformat (line_input, "ra-interval"))
2754         {
2755           if (!unformat (line_input, "%d", &ra_max_interval))
2756             return(error = unformat_parse_error (line_input));
2757
2758           if (!unformat (line_input, "%d", &ra_min_interval))
2759             ra_min_interval = 0;
2760           break;
2761         }
2762       else if(unformat (line_input, "ra-cease"))
2763         {
2764           cease = 1;
2765           break;
2766         }
2767       else
2768         return(unformat_parse_error (line_input));
2769     }
2770
2771   if(add_radv_info)
2772     {
2773       ip6_neighbor_ra_config(vm,  sw_if_index, 
2774                              suppress, managed, other,
2775                              suppress_ll_option,  send_unicast,  cease, 
2776                              use_lifetime,  ra_lifetime,
2777                              ra_initial_count,  ra_initial_interval,  
2778                              ra_max_interval,  ra_min_interval,
2779                              is_no);
2780     }
2781   else
2782     {
2783       u32 valid_lifetime_in_secs =  0;
2784       u32 pref_lifetime_in_secs = 0;
2785       u8 use_prefix_default_values = 0;
2786       u8  no_advertise = 0;
2787       u8 off_link= 0;
2788       u8 no_autoconfig = 0;
2789       u8 no_onlink= 0;
2790
2791       /* get the rest of the command */
2792       while(unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2793         {
2794           if(unformat (line_input, "default"))
2795             {
2796               use_prefix_default_values = 1;
2797               break;
2798             }
2799           else if(unformat (line_input, "infinite"))
2800             {
2801               valid_lifetime_in_secs =  ~0;
2802               pref_lifetime_in_secs = ~0;
2803               break;
2804             }
2805           else if(unformat (line_input, "%d %d", &valid_lifetime_in_secs, 
2806                             &pref_lifetime_in_secs))
2807             break;
2808           else
2809             break;
2810         }
2811
2812
2813       /* get the rest of the command */
2814       while (!use_prefix_default_values &&
2815              unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2816         {
2817           if(unformat (line_input, "no-advertise"))
2818             no_advertise = 1;
2819           else if(unformat (line_input, "off-link"))
2820             off_link = 1;
2821           else if(unformat (line_input, "no-autoconfig"))
2822             no_autoconfig = 1;
2823           else if(unformat (line_input, "no-onlink"))
2824             no_onlink = 1;
2825           else
2826             return(unformat_parse_error (line_input));
2827         }
2828         
2829       ip6_neighbor_ra_prefix(vm, sw_if_index,  
2830                              &ip6_addr,  addr_len,
2831                              use_prefix_default_values,  
2832                              valid_lifetime_in_secs,
2833                              pref_lifetime_in_secs,
2834                              no_advertise,
2835                              off_link,
2836                              no_autoconfig,
2837                              no_onlink,
2838                              is_no);
2839     }
2840
2841   unformat_free (line_input);
2842   
2843  done:
2844   return error;
2845 }
2846
2847 static void
2848 ip6_print_addrs(vlib_main_t * vm,
2849                 u32 *addrs)
2850 {
2851   ip_lookup_main_t * lm = &ip6_main.lookup_main;
2852   u32 i;
2853
2854   for (i = 0; i < vec_len (addrs); i++)
2855     {
2856       ip_interface_address_t * a = pool_elt_at_index(lm->if_address_pool, addrs[i]);
2857       ip6_address_t * address = ip_interface_address_get_address (lm, a);
2858
2859       vlib_cli_output (vm, "\t\t%U/%d",
2860                        format_ip6_address, address,
2861                        a->address_length);
2862     }
2863 }
2864
2865 static clib_error_t *
2866 show_ip6_interface_cmd (vlib_main_t * vm,
2867                     unformat_input_t * input,
2868                     vlib_cli_command_t * cmd)
2869 {
2870   vnet_main_t * vnm = vnet_get_main();
2871   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2872   clib_error_t * error = 0;
2873   u32 sw_if_index;
2874
2875   sw_if_index = ~0;
2876
2877  if (unformat_user (input, 
2878                       unformat_vnet_sw_interface, vnm, &sw_if_index))
2879     {
2880       u32 ri;
2881       
2882       /* look up the radv_t  information for this interface */
2883       vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2884       
2885       ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2886       
2887       if(ri != ~0)
2888         {
2889           ip_lookup_main_t * lm = &ip6_main.lookup_main;
2890           ip6_radv_t * radv_info;
2891           radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
2892
2893           vlib_cli_output (vm, "%U is admin %s\n", format_vnet_sw_interface_name, vnm, 
2894                            vnet_get_sw_interface (vnm, sw_if_index),
2895                            (vnet_sw_interface_is_admin_up (vnm, sw_if_index) ? "up" : "down"));
2896       
2897           u32 ai;
2898           u32 *link_scope = 0, *global_scope = 0;
2899           u32 *local_scope = 0, *unknown_scope = 0;
2900           ip_interface_address_t * a;
2901
2902           vec_validate_init_empty (lm->if_address_pool_index_by_sw_if_index, sw_if_index, ~0);
2903           ai = lm->if_address_pool_index_by_sw_if_index[sw_if_index];
2904
2905           while (ai != (u32)~0)
2906             {
2907               a = pool_elt_at_index(lm->if_address_pool, ai);
2908               ip6_address_t * address = ip_interface_address_get_address (lm, a);
2909
2910               if (ip6_address_is_link_local_unicast (address))
2911                 vec_add1 (link_scope, ai);
2912               else if(ip6_address_is_global_unicast (address))
2913                 vec_add1 (global_scope, ai);
2914               else if(ip6_address_is_local_unicast (address))
2915                 vec_add1 (local_scope, ai);
2916               else
2917                 vec_add1 (unknown_scope, ai);
2918
2919               ai = a->next_this_sw_interface;
2920             }
2921
2922           if (vec_len (link_scope))
2923             {
2924               vlib_cli_output (vm, "\tLink-local address(es):\n");
2925               ip6_print_addrs (vm, link_scope);
2926               vec_free (link_scope);
2927             }
2928
2929           if (vec_len (local_scope))
2930             {
2931               vlib_cli_output (vm, "\tLocal unicast address(es):\n");
2932               ip6_print_addrs (vm, local_scope);
2933               vec_free (local_scope);
2934             }
2935
2936           if (vec_len (global_scope))
2937             {
2938               vlib_cli_output (vm, "\tGlobal unicast address(es):\n");
2939               ip6_print_addrs (vm, global_scope);
2940               vec_free (global_scope);
2941             }
2942
2943           if (vec_len (unknown_scope))
2944             {
2945               vlib_cli_output (vm, "\tOther-scope address(es):\n");
2946               ip6_print_addrs (vm, unknown_scope);
2947               vec_free (unknown_scope);
2948             }
2949
2950           vlib_cli_output (vm, "\tJoined group address(es):\n");
2951           ip6_mldp_group_t *m;
2952           pool_foreach (m, radv_info->mldp_group_pool, ({
2953                 vlib_cli_output (vm, "\t\t%U\n", format_ip6_address, &m->mcast_address);
2954               }));
2955
2956           vlib_cli_output (vm, "\tAdvertised Prefixes:\n");
2957           ip6_radv_prefix_t * p;
2958           pool_foreach (p, radv_info->adv_prefixes_pool, ({
2959                 vlib_cli_output (vm, "\t\tprefix %U,  length %d\n", 
2960                                  format_ip6_address, &p->prefix, p->prefix_len);
2961               }));
2962
2963           vlib_cli_output (vm, "\tMTU is %d\n",  radv_info->adv_link_mtu);
2964           vlib_cli_output (vm, "\tICMP error messages are unlimited\n");
2965           vlib_cli_output (vm, "\tICMP redirects are disabled\n");
2966           vlib_cli_output (vm, "\tICMP unreachables are not sent\n");
2967           vlib_cli_output (vm, "\tND DAD is disabled\n");
2968           //vlib_cli_output (vm, "\tND reachable time is %d milliseconds\n",);
2969           vlib_cli_output (vm, "\tND advertised reachable time is %d\n",
2970                            radv_info->adv_neighbor_reachable_time_in_msec);
2971           vlib_cli_output (vm, "\tND advertised retransmit interval is %d (msec)\n",
2972                            radv_info->adv_time_in_msec_between_retransmitted_neighbor_solicitations);
2973
2974           u32 ra_interval = radv_info->max_radv_interval;
2975           u32 ra_interval_min = radv_info->min_radv_interval;
2976           vlib_cli_output (vm, "\tND router advertisements are sent every %d seconds (min interval is %d)\n", 
2977                            ra_interval, ra_interval_min);
2978           vlib_cli_output (vm, "\tND router advertisements live for %d seconds\n",
2979                            radv_info->adv_router_lifetime_in_sec);
2980           vlib_cli_output (vm, "\tHosts %s stateless autoconfig for addresses\n",
2981                              (radv_info->adv_managed_flag) ? "use" :" don't use");
2982           vlib_cli_output (vm, "\tND router advertisements sent %d\n",  radv_info->n_advertisements_sent);
2983           vlib_cli_output (vm, "\tND router solicitations received %d\n",  radv_info->n_solicitations_rcvd);
2984           vlib_cli_output (vm, "\tND router solicitations dropped %d\n",  radv_info->n_solicitations_dropped);
2985         }
2986       else
2987         {
2988           error = clib_error_return (0, "IPv6 not enabled on interface",
2989                                      format_unformat_error, input);
2990
2991         }
2992     }
2993   return error;
2994 }
2995
2996 /*?
2997  * This command is used to display various IPv6 attributes on a given
2998  * interface.
2999  *
3000  * @cliexpar
3001  * Example of how to display IPv6 settings:
3002  * @cliexstart{show ip6 interface GigabitEthernet2/0/0}
3003  * GigabitEthernet2/0/0 is admin up
3004  *         Link-local address(es):
3005  *                 fe80::ab8/64
3006  *         Joined group address(es):
3007  *                 ff02::1
3008  *                 ff02::2
3009  *                 ff02::16
3010  *                 ff02::1:ff00:ab8
3011  *         Advertised Prefixes:
3012  *                 prefix fe80::fe:28ff:fe9c:75b3,  length 64
3013  *         MTU is 1500
3014  *         ICMP error messages are unlimited
3015  *         ICMP redirects are disabled
3016  *         ICMP unreachables are not sent
3017  *         ND DAD is disabled
3018  *         ND advertised reachable time is 0
3019  *         ND advertised retransmit interval is 0 (msec)
3020  *         ND router advertisements are sent every 200 seconds (min interval is 150)
3021  *         ND router advertisements live for 600 seconds
3022  *         Hosts use stateless autoconfig for addresses
3023  *         ND router advertisements sent 19336
3024  *         ND router solicitations received 0
3025  *         ND router solicitations dropped 0
3026  * @cliexend
3027  * Example of output if IPv6 is not enabled on the interface:
3028  * @cliexstart{show ip6 interface GigabitEthernet2/0/0}
3029  * show ip6 interface: IPv6 not enabled on interface
3030  * @cliexend
3031 ?*/
3032 /* *INDENT-OFF* */
3033 VLIB_CLI_COMMAND (show_ip6_interface_command, static) = {
3034   .path = "show ip6 interface",
3035   .function = show_ip6_interface_cmd,
3036   .short_help = "show ip6 interface <interface>",
3037 };
3038 /* *INDENT-ON* */
3039
3040 clib_error_t *
3041 disable_ip6_interface(vlib_main_t * vm,
3042                       u32 sw_if_index)
3043 {
3044   clib_error_t * error = 0;
3045   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3046   u32 ri;
3047
3048   /* look up the radv_t  information for this interface */
3049   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);      
3050   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3051   
3052   /* if not created - do nothing */
3053   if(ri != ~0)
3054     {
3055       vnet_main_t * vnm = vnet_get_main();
3056       ip6_radv_t * radv_info;
3057   
3058       radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
3059
3060       /* check radv_info ref count for other ip6 addresses on this interface */
3061       if(radv_info->ref_count == 0 )
3062         {
3063           /* essentially "disables" ipv6 on this interface */
3064           error = ip6_add_del_interface_address (vm, sw_if_index,
3065                                                  &radv_info->link_local_address, 
3066                                                  radv_info->link_local_prefix_len,
3067                                                  1 /* is_del */);
3068
3069           ip6_neighbor_sw_interface_add_del (vnm, sw_if_index,  0/* is_add */);
3070         }
3071     }
3072   return error;
3073 }
3074
3075 int
3076 ip6_interface_enabled(vlib_main_t * vm,
3077                       u32 sw_if_index)
3078 {
3079     ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3080     u32 ri = ~0;
3081
3082     /* look up the radv_t  information for this interface */
3083     vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
3084
3085     ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3086
3087     return ri != ~0;
3088 }
3089
3090 clib_error_t * 
3091 enable_ip6_interface(vlib_main_t * vm,
3092                     u32 sw_if_index)
3093 {
3094   clib_error_t * error = 0;
3095   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3096   u32 ri;
3097   int is_add = 1;
3098
3099   /* look up the radv_t  information for this interface */
3100   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
3101       
3102   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3103   
3104   /* if not created yet */
3105   if(ri == ~0)
3106     {
3107       vnet_main_t * vnm = vnet_get_main();
3108       vnet_sw_interface_t * sw_if0;
3109  
3110       sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
3111       if(sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
3112         {
3113           ethernet_interface_t * eth_if0;
3114
3115           eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);         
3116           if(eth_if0)
3117             {
3118               /* create radv_info. for this interface.  This holds all the info needed for router adverts */
3119               ri = ip6_neighbor_sw_interface_add_del (vnm, sw_if_index, is_add);
3120
3121               if(ri != ~0)
3122                 {
3123                   ip6_radv_t * radv_info;
3124                   ip6_address_t link_local_address;
3125
3126                   radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
3127
3128                   ip6_link_local_address_from_ethernet_mac_address (&link_local_address,
3129                                                                     eth_if0->address);
3130
3131                   sw_if0 = vnet_get_sw_interface (vnm, sw_if_index);
3132                   if(sw_if0->type == VNET_SW_INTERFACE_TYPE_SUB)
3133                     {
3134                       /* make up  an interface id */
3135                       md5_context_t m;
3136                       u8 digest[16];
3137                       
3138                       link_local_address.as_u64[0] = radv_info->randomizer;
3139                       
3140                       md5_init (&m);
3141                       md5_add (&m, &link_local_address, 16);
3142                       md5_finish (&m,  digest);
3143                       
3144                       clib_memcpy(&link_local_address, digest, 16);
3145                       
3146                       radv_info->randomizer = link_local_address.as_u64[0];
3147                       
3148                       link_local_address.as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL);
3149                       /* clear u bit */
3150                       link_local_address.as_u8[8] &= 0xfd;
3151                     }
3152                   
3153                   /* essentially "enables" ipv6 on this interface */
3154                   error = ip6_add_del_interface_address (vm, sw_if_index,
3155                                                          &link_local_address,
3156                                                          128 /* address width */,
3157                                                          0 /* is_del */);
3158                   
3159                   if(error)
3160                       ip6_neighbor_sw_interface_add_del (vnm, sw_if_index, !is_add);
3161                   else
3162                     {
3163                       radv_info->link_local_address =  link_local_address;
3164                       radv_info->link_local_prefix_len  = 64;
3165                     }
3166                 }
3167             } 
3168         }
3169     }
3170   return error;
3171 }
3172
3173 static clib_error_t *
3174 enable_ip6_interface_cmd (vlib_main_t * vm,
3175                     unformat_input_t * input,
3176                     vlib_cli_command_t * cmd)
3177 {
3178   vnet_main_t * vnm = vnet_get_main();
3179   clib_error_t * error = 0;
3180   u32 sw_if_index;
3181
3182   sw_if_index = ~0;
3183
3184  if (unformat_user (input, 
3185                       unformat_vnet_sw_interface, vnm, &sw_if_index))
3186     {
3187       enable_ip6_interface(vm, sw_if_index);
3188     }
3189  else
3190    {
3191      error = clib_error_return (0, "unknown interface\n'",
3192                                 format_unformat_error, input);
3193      
3194    }
3195   return error;
3196 }
3197
3198 /*?
3199  * This command is used to enable IPv6 on a given interface.
3200  *
3201  * @cliexpar
3202  * Example of how enable IPv6 on a given interface:
3203  * @cliexcmd{enable ip6 interface GigabitEthernet2/0/0}
3204 ?*/
3205 /* *INDENT-OFF* */
3206 VLIB_CLI_COMMAND (enable_ip6_interface_command, static) = {
3207   .path = "enable ip6 interface",
3208   .function = enable_ip6_interface_cmd,
3209   .short_help = "enable ip6 interface <interface>",
3210 };
3211 /* *INDENT-ON* */
3212
3213 static clib_error_t *
3214 disable_ip6_interface_cmd (vlib_main_t * vm,
3215                     unformat_input_t * input,
3216                     vlib_cli_command_t * cmd)
3217 {
3218   vnet_main_t * vnm = vnet_get_main();
3219   clib_error_t * error = 0;
3220   u32 sw_if_index;
3221
3222   sw_if_index = ~0;
3223
3224  if (unformat_user (input, 
3225                       unformat_vnet_sw_interface, vnm, &sw_if_index))
3226     {
3227       error = disable_ip6_interface(vm, sw_if_index);
3228     }
3229  else
3230    {
3231      error = clib_error_return (0, "unknown interface\n'",
3232                                 format_unformat_error, input);
3233      
3234    }
3235   return error;
3236 }
3237
3238 /*?
3239  * This command is used to disable IPv6 on a given interface.
3240  *
3241  * @cliexpar
3242  * Example of how disable IPv6 on a given interface:
3243  * @cliexcmd{disable ip6 interface GigabitEthernet2/0/0}
3244 ?*/
3245 /* *INDENT-OFF* */
3246 VLIB_CLI_COMMAND (disable_ip6_interface_command, static) = {
3247   .path = "disable ip6 interface",
3248   .function = disable_ip6_interface_cmd,
3249   .short_help = "disable ip6 interface <interface>",
3250 };
3251 /* *INDENT-ON* */
3252
3253 /*?
3254  * This command is used to configure the neighbor discovery
3255  * parameters on a given interface. Use the '<em>show ip6 interface</em>'
3256  * command to display some of the current neighbor discovery parameters
3257  * on a given interface. This command has three formats:
3258  *
3259  *
3260  * <b>Format 1 - Router Advertisement Options:</b> (Only one can be entered in a single command)
3261  *
3262  * '<em><b>ip6 nd <interface> [no] [ra-managed-config-flag] | [ra-other-config-flag] | [ra-suppress] | [ra-suppress-link-layer] | [ra-send-unicast] | [ra-lifetime <lifetime>] | [ra-initial <cnt> <interval>] | [ra-interval <max-interval> [<min-interval>]] | [ra-cease]</b></em>'
3263  *
3264  * Where:
3265  *
3266  * <em>[no] ra-managed-config-flag</em> - Advertises in ICMPv6
3267  * router-advertisement messages to use stateful address
3268  * auto-configuration to obtain address information (sets the M-bit).
3269  * Default is the M-bit is not set and the '<em>no</em>' option
3270  * returns it to this default state.
3271  *
3272  * <em>[no] ra-other-config-flag</em> - Indicates in ICMPv6
3273  * router-advertisement messages that hosts use stateful auto
3274  * configuration to obtain nonaddress related information (sets
3275  * the O-bit). Default is the O-bit is not set and the '<em>no</em>'
3276  * option returns it to this default state.
3277  *
3278  * <em>[no] ra-suppress</em> - Disables sending ICMPv6 router-advertisement
3279  * messages. The '<em>no</em>' option implies to enable sending ICMPv6
3280  * router-advertisement messages.
3281  *
3282  * <em>[no] ra-suppress-link-layer</em> - Indicates not to include the
3283  * optional source link-layer address in the ICMPv6 router-advertisement
3284  * messages. Default is to include the optional source link-layer address
3285  * and the '<em>no</em>' option returns it to this default state.
3286  *
3287  * <em>[no] ra-send-unicast</em> - Use the source address of the
3288  * router-solicitation message if availiable. The default is to use
3289  * multicast address of all nodes, and the '<em>no</em>' option returns
3290  * it to this default state.
3291  *
3292  * <em>[no] ra-lifetime <lifetime></em> - Advertises the lifetime of a
3293  * default router in ICMPv6 router-advertisement messages. The range is
3294  * from 0 to 9000 seconds. '<em><lifetime></em>' must be greater than
3295  * '<em><max-interval></em>'. The default value is 600 seconds and the
3296  * '<em>no</em>' option returns it to this default value.
3297  *
3298  * <em>[no] ra-initial <cnt> <interval></em> - Number of initial ICMPv6
3299  * router-advertisement messages sent and the interval between each
3300  * message. Range for count is 1 - 3 and default is 3. Range for interval
3301  * is 1 to 16 seconds, and default is 16 seconds. The '<em>no</em>' option
3302  * returns both to their default value.
3303  *
3304  * <em>[no] ra-interval <max-interval> [<min-interval>]</em> - Configures the
3305  * interval between sending ICMPv6 router-advertisement messages. The
3306  * range for max-interval is from 4 to 200 seconds. min-interval can not
3307  * be more than 75% of max-interval. If not set, min-interval will be
3308  * set to 75% of max-interval. The range for min-interval is from 3 to
3309  * 150 seconds.  The '<em>no</em>' option returns both to their default
3310  * value.
3311  *
3312  * <em>[no] ra-cease</em> - Cease sending ICMPv6 router-advertisement messages.
3313  * The '<em>no</em>' options implies to start (or restart) sending
3314  * ICMPv6 router-advertisement messages.
3315  *
3316  *
3317  * <b>Format 2 - Prefix Options:</b>
3318  *
3319  * '<em><b>ip6 nd <interface> [no] prefix <ip6-address>/<width> [<valid-lifetime> <pref-lifetime> | infinite] [no-advertise] [off-link] [no-autoconfig] [no-onlink]</b></em>'
3320  *
3321  * Where:
3322  *
3323  * <em>no</em> - All additional flags are ignored and the prefix is deleted.
3324  *
3325  * <em><valid-lifetime> <pref-lifetime></em> - '<em><valid-lifetime></em>' is the
3326  * length of time in seconds during what the prefix is valid for the purpose of
3327  * on-link determination. Range is 7203 to 2592000 seconds and default is 2592000
3328  * seconds (30 days). '<em><pref-lifetime></em>' is the prefered-lifetime and is the
3329  * length of time in seconds during what addresses generated from the prefix remain
3330  * preferred. Range is 0 to 604800 seconds and default is 604800 seconds (7 days).
3331  *
3332  * <em>infinite</em> - Both '<em><valid-lifetime></em>' and '<em><<pref-lifetime></em>'
3333  * are inifinte, no timeout.
3334  *
3335  * <em>no-advertise</em> - Do not send full router address in prefix
3336  * advertisement. Default is to advertise (i.e. - This flag is off by default).
3337  *
3338  * <em>off-link</em> - Prefix is off-link, clear L-bit in packet. Default is on-link
3339  * (i.e. - This flag is off and L-bit in packet is set by default and this prefix can
3340  * be used for on-link determination). '<em>no-onlink</em>' also controls the L-bit.
3341  *
3342  * <em>no-autoconfig</em> - Do not use prefix for autoconfiguration, clear A-bit in packet.
3343  * Default is autoconfig (i.e. - This flag is off and A-bit in packet is set by default.
3344  *
3345  * <em>no-onlink</em> - Do not use prefix for onlink determination, clear L-bit in packet.
3346  * Default is on-link (i.e. - This flag is off and L-bit in packet is set by default and
3347  * this prefix can be used for on-link determination). '<em>off-link</em>' also controls
3348  * the L-bit.
3349  *
3350  *
3351  * <b>Format 3: - Default of Prefix:</b>
3352  *
3353  * '<em><b>ip6 nd <interface> [no] prefix <ip6-address>/<width> default</b></em>'
3354  *
3355  * When a new prefix is added (or existing one is being overwritten) <em>default</em>
3356  * uses default values for the prefix. If <em>no</em> is used, the <em>default</em>
3357  * is ignored and the prefix is deleted.
3358  *
3359  *
3360  * @cliexpar
3361  * Example of how set a router advertisement option:
3362  * @cliexcmd{ip6 nd GigabitEthernet2/0/0 ra-interval 100 20}
3363  * Example of how to add a prefix:
3364  * @cliexcmd{ip6 nd GigabitEthernet2/0/0 prefix fe80::fe:28ff:fe9c:75b3/64 infinite no-advertise}
3365  * Example of how to delete a prefix:
3366  * @cliexcmd{ip6 nd GigabitEthernet2/0/0 no prefix fe80::fe:28ff:fe9c:75b3/64}
3367 ?*/
3368 /* *INDENT-OFF* */
3369 VLIB_CLI_COMMAND (ip6_nd_command, static) = {
3370   .path = "ip6 nd",
3371   .short_help = "ip6 nd <interface> ...",
3372   .function = ip6_neighbor_cmd,
3373 };
3374 /* *INDENT-ON* */
3375
3376 clib_error_t *
3377 set_ip6_link_local_address(vlib_main_t * vm,
3378                            u32 sw_if_index,
3379                            ip6_address_t *address,
3380                            u8 address_length)
3381 {
3382   clib_error_t * error = 0;
3383   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3384   u32 ri;
3385   ip6_radv_t * radv_info;
3386   vnet_main_t * vnm = vnet_get_main();
3387
3388   if( !ip6_address_is_link_local_unicast (address))
3389     {
3390       vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_LINK_LOCAL;
3391       return(error = clib_error_return (0, "address not link-local",
3392                                         format_unformat_error));
3393     }
3394
3395   /* call enable ipv6  */
3396   enable_ip6_interface(vm, sw_if_index);
3397           
3398   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3399          
3400   if(ri != ~0)
3401     {
3402       radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
3403
3404       /* save if link local address (overwrite default) */
3405    
3406       /* delete the old one */
3407       error = ip6_add_del_interface_address (vm, sw_if_index,
3408                                              &radv_info->link_local_address,
3409                                              radv_info->link_local_prefix_len  /* address width */,
3410                                              1 /* is_del */);
3411       
3412       if(!error)
3413         {
3414           /* add the new one */
3415           error = ip6_add_del_interface_address (vm, sw_if_index,
3416                                                  address ,
3417                                                  address_length  /* address width */,
3418                                                  0/* is_del */);
3419           
3420           if(!error)
3421             {
3422               radv_info->link_local_address = *address;
3423               radv_info->link_local_prefix_len  = address_length;
3424             }
3425         }
3426     }
3427   else
3428     {
3429       vnm->api_errno = VNET_API_ERROR_IP6_NOT_ENABLED;
3430       error = clib_error_return (0, "ip6 not enabled for interface",
3431                                  format_unformat_error);
3432     }
3433   return error;
3434 }
3435   
3436 clib_error_t *
3437 set_ip6_link_local_address_cmd (vlib_main_t * vm,
3438                                 unformat_input_t * input,
3439                                 vlib_cli_command_t * cmd)
3440 {
3441   vnet_main_t * vnm = vnet_get_main();
3442   clib_error_t * error = 0;
3443   u32 sw_if_index;
3444   ip6_address_t ip6_addr;
3445   u32 addr_len = 0;
3446  
3447   if (unformat_user (input, 
3448                      unformat_vnet_sw_interface, vnm, &sw_if_index))
3449     {
3450       /* get the rest of the command */
3451       while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3452         {
3453           if(unformat (input, "%U/%d",
3454                        unformat_ip6_address, &ip6_addr,
3455                        &addr_len))
3456             break;
3457           else
3458             return(unformat_parse_error (input));
3459         }
3460     }
3461   error = set_ip6_link_local_address(vm,
3462                                      sw_if_index,
3463                                      &ip6_addr,
3464                                      addr_len);
3465   return error;
3466 }
3467
3468 /*?
3469  * This command is used to assign an IPv6 Link-local address to an
3470  * interface. This command will enable IPv6 on an interface if it
3471  * is not already enabled. Use the '<em>show ip6 interface</em>' command
3472  * to display the assigned Link-local address.
3473  *
3474  * @cliexpar
3475  * Example of how to assign an IPv6 Link-local address to an interface:
3476  * @cliexcmd{set ip6 link-local address GigabitEthernet2/0/0 FE80::AB8/64}
3477 ?*/
3478 /* *INDENT-OFF* */
3479 VLIB_CLI_COMMAND (set_ip6_link_local_address_command, static) = {
3480   .path = "set ip6 link-local address",
3481   .short_help = "set ip6 link-local address <interface> <ip6-address>/<width>",
3482   .function = set_ip6_link_local_address_cmd,
3483 };
3484 /* *INDENT-ON* */
3485
3486 /* callback when an interface address is added or deleted */
3487 static void
3488 ip6_neighbor_add_del_interface_address (ip6_main_t * im,
3489                                         uword opaque,
3490                                         u32 sw_if_index,
3491                                         ip6_address_t * address,
3492                                         u32 address_length,
3493                                         u32 if_address_index,
3494                                         u32 is_delete)
3495 {
3496   vnet_main_t * vnm = vnet_get_main();
3497   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3498   u32 ri;
3499   vlib_main_t * vm = vnm->vlib_main;
3500   ip6_radv_t * radv_info;
3501   ip6_address_t a;
3502   ip6_mldp_group_t  *mcast_group_info;
3503
3504   /* create solicited node multicast address for this interface adddress */
3505   ip6_set_solicited_node_multicast_address (&a, 0);
3506  
3507   a.as_u8[0xd] = address->as_u8[0xd];
3508   a.as_u8[0xe] = address->as_u8[0xe];
3509   a.as_u8[0xf] = address->as_u8[0xf];
3510   
3511   if(!is_delete)
3512     {
3513       /* try to  create radv_info - does nothing if ipv6 already enabled */
3514       enable_ip6_interface(vm, sw_if_index);
3515
3516       /* look up the radv_t  information for this interface */
3517       vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
3518       ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3519       if(ri != ~0)
3520         {
3521           /* get radv_info */
3522           radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3523
3524           /* add address */
3525           if( !ip6_address_is_link_local_unicast (address))
3526             radv_info->ref_count++;
3527
3528           /* lookup  prefix info for this  address on this interface */
3529           uword * p = mhash_get (&radv_info->address_to_mldp_index,  &a);
3530           mcast_group_info = p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0;
3531
3532           /* add -solicted node multicast address  */
3533           if(!mcast_group_info)
3534             {
3535               /* add */
3536               u32 mi;
3537               pool_get (radv_info->mldp_group_pool, mcast_group_info);
3538               
3539               mi = mcast_group_info - radv_info->mldp_group_pool;
3540               mhash_set (&radv_info->address_to_mldp_index,  &a,  mi, /* old_value */ 0);
3541               
3542               mcast_group_info->type = 4;
3543               mcast_group_info->mcast_source_address_pool = 0;
3544               mcast_group_info->num_sources = 0;
3545               clib_memcpy(&mcast_group_info->mcast_address, &a, sizeof(ip6_address_t));
3546             } 
3547         }
3548     }
3549   else
3550     {
3551
3552       /* delete */
3553       /* look up the radv_t  information for this interface */
3554       vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
3555       ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3556       if(ri != ~0)
3557         {
3558           /* get radv_info */
3559           radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3560
3561           /* lookup  prefix info for this  address on this interface */
3562           uword * p = mhash_get (&radv_info->address_to_mldp_index,  &a);
3563           mcast_group_info = p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0;
3564           
3565           if(mcast_group_info)
3566             {
3567               mhash_unset (&radv_info->address_to_mldp_index, &a,/* old_value */ 0);
3568               pool_put (radv_info->mldp_group_pool, mcast_group_info);
3569             }
3570
3571           /* if interface up send MLDP "report" */
3572           radv_info->all_routers_mcast = 0;
3573
3574           /* add address */
3575           if( !ip6_address_is_link_local_unicast (address))
3576             radv_info->ref_count--;
3577         }
3578     }
3579 }
3580
3581 clib_error_t *ip6_set_neighbor_limit (u32 neighbor_limit)
3582 {
3583   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3584
3585   nm->limit_neighbor_cache_size = neighbor_limit;
3586   return 0;
3587 }
3588
3589 static clib_error_t * ip6_neighbor_init (vlib_main_t * vm)
3590 {
3591   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3592   ip6_main_t * im = &ip6_main;
3593  
3594   mhash_init (&nm->neighbor_index_by_key,
3595               /* value size */ sizeof (uword),
3596               /* key size */ sizeof (ip6_neighbor_key_t));
3597
3598   icmp6_register_type (vm, ICMP6_neighbor_solicitation, ip6_icmp_neighbor_solicitation_node.index);
3599   icmp6_register_type (vm, ICMP6_neighbor_advertisement, ip6_icmp_neighbor_advertisement_node.index);
3600   icmp6_register_type (vm, ICMP6_router_solicitation, ip6_icmp_router_solicitation_node.index);
3601   icmp6_register_type (vm, ICMP6_router_advertisement, ip6_icmp_router_advertisement_node.index);
3602
3603   /* handler node for ip6 neighbor discovery events and timers */
3604   vlib_register_node (vm, &ip6_icmp_neighbor_discovery_event_node);
3605
3606   /* add call backs */
3607   ip6_add_del_interface_address_callback_t cb; 
3608   memset(&cb, 0x0, sizeof(ip6_add_del_interface_address_callback_t));
3609   
3610   /* when an interface address changes... */
3611   cb.function = ip6_neighbor_add_del_interface_address;
3612   cb.function_opaque = 0;
3613   vec_add1 (im->add_del_interface_address_callbacks, cb);
3614
3615   mhash_init (&nm->pending_resolutions_by_address,
3616               /* value size */ sizeof (uword),
3617               /* key size */ sizeof (ip6_address_t));
3618
3619   mhash_init (&nm->mac_changes_by_address,
3620               /* value size */ sizeof (uword),
3621               /* key size */ sizeof (ip6_address_t));
3622
3623   /* default, configurable */
3624   nm->limit_neighbor_cache_size = 50000;
3625
3626 #if 0
3627   /* $$$$ Hack fix for today */
3628   vec_validate_init_empty 
3629       (im->discover_neighbor_next_index_by_hw_if_index, 32, 0 /* drop */);
3630 #endif
3631
3632   return 0;
3633 }
3634
3635 VLIB_INIT_FUNCTION (ip6_neighbor_init);
3636
3637
3638 void vnet_register_ip6_neighbor_resolution_event (vnet_main_t * vnm, 
3639                                                   void * address_arg,
3640                                                   uword node_index,
3641                                                   uword type_opaque,
3642                                                   uword data)
3643 {
3644   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3645   ip6_address_t * address = address_arg;
3646   uword * p;
3647   pending_resolution_t * pr;
3648   
3649   pool_get (nm->pending_resolutions, pr);
3650
3651   pr->next_index = ~0;
3652   pr->node_index = node_index;
3653   pr->type_opaque = type_opaque;
3654   pr->data = data;
3655
3656   p = mhash_get (&nm->pending_resolutions_by_address, address);
3657   if (p)
3658     {
3659       /* Insert new resolution at the head of the list */
3660       pr->next_index = p[0];
3661       mhash_unset (&nm->pending_resolutions_by_address, address, 0);
3662     }
3663   
3664   mhash_set (&nm->pending_resolutions_by_address, address, 
3665              pr - nm->pending_resolutions, 0 /* old value */);
3666 }
3667
3668 int vnet_add_del_ip6_nd_change_event (vnet_main_t * vnm, 
3669                                       void * data_callback,
3670                                       u32 pid,
3671                                       void * address_arg,
3672                                       uword node_index,
3673                                       uword type_opaque,
3674                                       uword data, 
3675                                       int is_add)
3676 {
3677   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3678   ip6_address_t * address = address_arg;
3679   uword * p;
3680   pending_resolution_t * mc;
3681   void (*fp)(u32, u8 *) = data_callback;
3682   
3683   if (is_add)
3684     {
3685       pool_get (nm->mac_changes, mc);
3686
3687       mc->next_index = ~0;
3688       mc->node_index = node_index;
3689       mc->type_opaque = type_opaque;
3690       mc->data = data;
3691       mc->data_callback = data_callback;
3692       mc->pid = pid;
3693       
3694       p = mhash_get (&nm->mac_changes_by_address, address);
3695       if (p)
3696         {
3697           /* Insert new resolution at the head of the list */
3698           mc->next_index = p[0];
3699           mhash_unset (&nm->mac_changes_by_address, address, 0);
3700         }
3701       
3702       mhash_set (&nm->mac_changes_by_address, address, 
3703                  mc - nm->mac_changes, 0);
3704       return 0;
3705     }
3706   else
3707     {
3708       u32 index;
3709       pending_resolution_t * mc_last = 0;
3710
3711       p = mhash_get (&nm->mac_changes_by_address, address);
3712       if (p == 0)
3713         return VNET_API_ERROR_NO_SUCH_ENTRY;
3714
3715       index = p[0];
3716
3717       while (index != (u32)~0)
3718         {
3719           mc = pool_elt_at_index (nm->mac_changes, index);
3720           if (mc->node_index == node_index &&
3721               mc->type_opaque == type_opaque &&
3722               mc->pid == pid)
3723             {
3724               /* Clients may need to clean up pool entries, too */
3725               if (fp)
3726                 (*fp)(mc->data, 0 /* no new mac addrs */);
3727               if (index == p[0])
3728                 {
3729                   mhash_unset (&nm->mac_changes_by_address, address, 0);
3730                   if (mc->next_index != ~0)
3731                     mhash_set (&nm->mac_changes_by_address, address,
3732                                mc->next_index, 0);
3733                   pool_put (nm->mac_changes, mc);
3734                   return 0;
3735                 }
3736               else
3737                 {
3738                   ASSERT(mc_last);
3739                   mc_last->next_index = mc->next_index;
3740                   pool_put (nm->mac_changes, mc);
3741                   return 0;
3742                 }
3743             }
3744           mc_last = mc;
3745           index = mc->next_index;
3746         }
3747       
3748       return VNET_API_ERROR_NO_SUCH_ENTRY;
3749     }
3750 }
3751
3752 int vnet_ip6_nd_term (vlib_main_t * vm,
3753                       vlib_node_runtime_t * node,
3754                       vlib_buffer_t * p0,
3755                       ethernet_header_t * eth,
3756                       ip6_header_t * ip,
3757                       u32 sw_if_index,
3758                       u16 bd_index,
3759                       u8 shg)
3760 {
3761   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3762   icmp6_neighbor_solicitation_or_advertisement_header_t * ndh;
3763   pending_resolution_t * mc;
3764   uword *p;
3765
3766   ndh = ip6_next_header (ip);
3767   if (ndh->icmp.type != ICMP6_neighbor_solicitation &&
3768       ndh->icmp.type != ICMP6_neighbor_advertisement)
3769       return 0;
3770
3771   if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
3772                      (p0->flags & VLIB_BUFFER_IS_TRACED)))
3773     {
3774       u8 *t0 = vlib_add_trace (vm, node, p0,
3775                                sizeof (icmp6_input_trace_t));
3776       clib_memcpy (t0, ip, sizeof (icmp6_input_trace_t));
3777     }
3778
3779   /* Check if anyone want ND events for L2 BDs */
3780   p = mhash_get (&nm->mac_changes_by_address, &ip6a_zero);
3781   if (p && shg == 0 && /* Only SHG 0 interface which is more likely local */ 
3782       !ip6_address_is_link_local_unicast (&ip->src_address))
3783     { 
3784       u32 next_index = p[0];
3785       while (next_index != (u32)~0)
3786         {
3787           int (*fp)(u32, u8 *, u32, ip6_address_t *);
3788           int rv = 1;
3789           mc = pool_elt_at_index (nm->mac_changes, next_index);
3790           fp = mc->data_callback;
3791           /* Call the callback, return 1 to suppress dup events */
3792           if (fp) rv = (*fp)(mc->data, 
3793                              eth->src_address,
3794                              sw_if_index, 
3795                              &ip->src_address);
3796           /* Signal the resolver process */
3797           if (rv == 0)
3798              vlib_process_signal_event (vm, mc->node_index,
3799                                         mc->type_opaque, 
3800                                         mc->data);
3801           next_index = mc->next_index;
3802         }
3803     }
3804
3805   /* Check if MAC entry exsist for solicited target IP */
3806   if (ndh->icmp.type == ICMP6_neighbor_solicitation)
3807     {
3808       icmp6_neighbor_discovery_ethernet_link_layer_address_option_t * opt;
3809       l2_bridge_domain_t *bd_config;
3810       u8 * macp;
3811
3812       opt = (void *) (ndh + 1);
3813       if ((opt->header.type != 
3814            ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address) ||
3815           (opt->header.n_data_u64s != 1))
3816           return 0; /* source link layer address option not present */
3817           
3818       bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
3819       macp = (u8 *) hash_get_mem (bd_config->mac_by_ip6, &ndh->target_address);
3820       if (macp)
3821         { /* found ip-mac entry, generate eighbor advertisement response */
3822           int bogus_length;
3823           vlib_node_runtime_t * error_node = 
3824               vlib_node_get_runtime (vm, ip6_icmp_input_node.index);
3825           ip->dst_address = ip->src_address;
3826           ip->src_address = ndh->target_address;
3827           ip->hop_limit = 255;
3828           opt->header.type =
3829               ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
3830           clib_memcpy (opt->ethernet_address, macp, 6);
3831           ndh->icmp.type = ICMP6_neighbor_advertisement;
3832           ndh->advertisement_flags = clib_host_to_net_u32
3833               (ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED |
3834                ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE);
3835           ndh->icmp.checksum = 0;
3836           ndh->icmp.checksum = ip6_tcp_udp_icmp_compute_checksum(vm, p0, ip,
3837                                                                  &bogus_length);
3838           clib_memcpy(eth->dst_address, eth->src_address, 6);
3839           clib_memcpy(eth->src_address, macp, 6);
3840           vlib_error_count (vm, error_node->node_index, 
3841                             ICMP6_ERROR_NEIGHBOR_ADVERTISEMENTS_TX, 1);
3842           return 1;
3843         }
3844     }
3845
3846   return 0;
3847
3848 }
3849
3850 void
3851 ethernet_ndp_change_mac (vlib_main_t * vm, u32 sw_if_index)
3852 {
3853   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3854   ip6_neighbor_t * n;
3855
3856   /* *INDENT-OFF* */
3857   pool_foreach (n, nm->neighbor_pool, ({
3858     if (n->key.sw_if_index == sw_if_index)
3859     {
3860         adj_nbr_walk_nh6 (sw_if_index,
3861                           &n->key.ip6_address,
3862                           ip6_nd_mk_complete_walk, n);
3863     }
3864   }));
3865   /* *INDENT-ON* */
3866 }