VPP-490: vpp crash in show ip6 neighbor
[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               clib_memcpy(eth0->src_address, eth_if0->address, 6);
1067
1068               /* Setup input and output sw_if_index for packet */
1069               ASSERT(vnet_buffer(p0)->sw_if_index[VLIB_RX] == sw_if_index0);
1070               vnet_buffer(p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1071               vnet_buffer(p0)->sw_if_index[VLIB_RX] = 
1072                   vnet_main.local_interface_sw_if_index;
1073
1074               n_advertisements_sent++;
1075             }
1076
1077           p0->error = error_node->errors[error0];
1078
1079           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1080                                            to_next, n_left_to_next,
1081                                            bi0, next0);
1082         }
1083
1084       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1085     }
1086
1087   /* Account for advertisements sent. */
1088   vlib_error_count (vm, error_node->node_index, ICMP6_ERROR_NEIGHBOR_ADVERTISEMENTS_TX, n_advertisements_sent);
1089
1090   return frame->n_vectors;
1091 }
1092
1093 /* for "syslogging" - use elog for now */
1094 #define foreach_log_level            \
1095   _ (DEBUG, "DEBUG")                         \
1096   _ (INFO, "INFORMATION")            \
1097   _ (NOTICE, "NOTICE")               \
1098   _ (WARNING, "WARNING")             \
1099   _ (ERR, "ERROR")                                    \
1100   _ (CRIT, "CRITICAL")                        \
1101   _ (ALERT, "ALERT")                          \
1102   _ (EMERG,  "EMERGENCY")
1103
1104 typedef enum {
1105 #define _(f,s) LOG_##f,
1106   foreach_log_level
1107 #undef _
1108 } log_level_t;
1109
1110 static char * log_level_strings[] = {
1111 #define _(f,s) s,
1112   foreach_log_level
1113 #undef _
1114 };
1115
1116 static  int logmask = 1 << LOG_DEBUG;
1117
1118 static void
1119 ip6_neighbor_syslog(vlib_main_t *vm,  int priority,  char * fmt, ...)
1120 {
1121   /* just use elog for now */
1122   u8 *what;
1123   va_list va;
1124
1125   if( (priority > LOG_EMERG) ||
1126       !(logmask & (1 << priority)))
1127       return;
1128
1129   va_start (va, fmt);
1130   if(fmt)
1131     {
1132       what = va_format (0, fmt, &va);
1133
1134       ELOG_TYPE_DECLARE (e) = {
1135         .format = "ip6 nd:  (%s): %s",
1136         .format_args = "T4T4",
1137       };
1138       struct { u32 s[2]; } * ed;
1139       ed = ELOG_DATA (&vm->elog_main, e);
1140       ed->s[0] = elog_string(&vm->elog_main,  log_level_strings[priority]);
1141       ed->s[1] = elog_string(&vm->elog_main,  (char *)what);
1142     }
1143   va_end (va);
1144   return;
1145 }
1146
1147 /* ipv6 neighbor discovery - router advertisements */
1148 typedef enum {
1149   ICMP6_ROUTER_SOLICITATION_NEXT_DROP,
1150   ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW,
1151   ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX,
1152   ICMP6_ROUTER_SOLICITATION_N_NEXT,
1153 } icmp6_router_solicitation_or_advertisement_next_t;
1154
1155 static_always_inline uword
1156 icmp6_router_solicitation(vlib_main_t * vm,
1157                           vlib_node_runtime_t * node,
1158                           vlib_frame_t * frame)
1159 {
1160   vnet_main_t * vnm = vnet_get_main();
1161   ip6_main_t * im = &ip6_main;
1162   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
1163   uword n_packets = frame->n_vectors;
1164   u32 * from, * to_next;
1165   u32 n_left_from, n_left_to_next, next_index;
1166   u32  n_advertisements_sent = 0;
1167   int bogus_length;
1168
1169   icmp6_neighbor_discovery_option_type_t option_type;
1170
1171   vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip6_icmp_input_node.index);
1172
1173   from = vlib_frame_vector_args (frame);
1174   n_left_from = n_packets;
1175   next_index = node->cached_next_index;
1176   
1177   if (node->flags & VLIB_NODE_FLAG_TRACE)
1178     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
1179                                    /* stride */ 1,
1180                                    sizeof (icmp6_input_trace_t));
1181
1182   /* source may append his LL address */
1183   option_type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
1184
1185   while (n_left_from > 0)
1186     {
1187       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1188       
1189       while (n_left_from > 0 && n_left_to_next > 0)
1190         {
1191           vlib_buffer_t * p0;
1192           ip6_header_t * ip0;
1193           ip6_radv_t *radv_info = 0;
1194
1195           icmp6_neighbor_discovery_header_t * h0;  
1196           icmp6_neighbor_discovery_ethernet_link_layer_address_option_t * o0;
1197           
1198           u32 bi0, options_len0, sw_if_index0, next0, error0;
1199           u32 is_solicitation = 1, is_dropped  = 0;
1200           u32 is_unspecified, is_link_local;
1201
1202           bi0 = to_next[0] = from[0];
1203
1204           from += 1;
1205           to_next += 1;
1206           n_left_from -= 1;
1207           n_left_to_next -= 1;
1208       
1209           p0 = vlib_get_buffer (vm, bi0);
1210           ip0 = vlib_buffer_get_current (p0);
1211           h0 = ip6_next_header (ip0);
1212           options_len0 = clib_net_to_host_u16 (ip0->payload_length) - sizeof (h0[0]);
1213           is_unspecified = ip6_address_is_unspecified (&ip0->src_address);
1214           is_link_local = ip6_address_is_link_local_unicast (&ip0->src_address);
1215
1216           error0 = ICMP6_ERROR_NONE;
1217           sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1218           
1219           /* check if solicitation  (not from nd_timer node) */
1220           if (ip6_address_is_unspecified (&ip0->dst_address))
1221             is_solicitation = 0;
1222
1223           /* Check that source address is unspecified, link-local or else on-link. */
1224           if (!is_unspecified && !is_link_local)
1225             {
1226               u32 src_adj_index0 = ip6_src_lookup_for_packet (im, p0, ip0);
1227
1228               if (ADJ_INDEX_INVALID != src_adj_index0)
1229                 {
1230                   ip_adjacency_t * adj0 = ip_get_adjacency (&im->lookup_main,
1231                                                             src_adj_index0);
1232
1233                   error0 = (adj0->rewrite_header.sw_if_index != sw_if_index0
1234                             ? ICMP6_ERROR_ROUTER_SOLICITATION_SOURCE_NOT_ON_LINK
1235                             : error0);
1236                 }
1237               else
1238                 {
1239                   error0 = ICMP6_ERROR_ROUTER_SOLICITATION_SOURCE_NOT_ON_LINK;
1240                 }
1241           }
1242           
1243           /* check for source LL option and process */
1244           o0 = (void *) (h0 + 1);
1245           o0 = ((options_len0 == 8
1246                  && o0->header.type == option_type
1247                  && o0->header.n_data_u64s == 1)
1248                 ? o0
1249                 : 0);
1250                       
1251           /* if src address unspecified IGNORE any options */
1252           if (PREDICT_TRUE (error0 == ICMP6_ERROR_NONE && o0 != 0 && 
1253                             !is_unspecified && !is_link_local)) {
1254               ip6_neighbor_main_t * nm = &ip6_neighbor_main;
1255               if (nm->limit_neighbor_cache_size && 
1256                   pool_elts (nm->neighbor_pool) >= nm->limit_neighbor_cache_size)
1257                       unset_random_neighbor_entry();
1258               
1259               vnet_set_ip6_ethernet_neighbor (vm, sw_if_index0,
1260                                               &ip0->src_address,
1261                                               o0->ethernet_address,
1262                                               sizeof (o0->ethernet_address), 0);
1263           }
1264               
1265           /* default is to drop */
1266           next0 = ICMP6_ROUTER_SOLICITATION_NEXT_DROP;
1267           
1268           if (error0 == ICMP6_ERROR_NONE)
1269             {
1270               vnet_sw_interface_t * sw_if0;
1271               ethernet_interface_t * eth_if0;
1272               u32 adj_index0;
1273
1274               sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
1275               ASSERT (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
1276               eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
1277
1278               /* only support ethernet interface type for now */
1279               error0 = (!eth_if0) ?  ICMP6_ERROR_ROUTER_SOLICITATION_UNSUPPORTED_INTF : error0;
1280
1281               if (error0 == ICMP6_ERROR_NONE)
1282                 {
1283                   u32 ri;
1284
1285                   /* adjust the sizeof the buffer to just include the ipv6 header */
1286                   p0->current_length -= (options_len0 + sizeof(icmp6_neighbor_discovery_header_t));
1287
1288                   /* look up the radv_t information for this interface */
1289                   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index0, ~0);
1290
1291                   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index0];
1292
1293                   if(ri != ~0)
1294                       radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
1295                         
1296                   error0 = ((!radv_info) ?  ICMP6_ERROR_ROUTER_SOLICITATION_RADV_NOT_CONFIG : error0);
1297
1298                   if (error0 == ICMP6_ERROR_NONE)
1299                     {
1300                       f64 now = vlib_time_now (vm);
1301
1302                       /* for solicited adverts - need to rate limit */
1303                       if(is_solicitation)
1304                         {
1305                           if( (now - radv_info->last_radv_time)  <  MIN_DELAY_BETWEEN_RAS )
1306                               is_dropped = 1;
1307                           else
1308                             radv_info->last_radv_time = now;
1309                         }
1310
1311                       /* send now  */
1312                       icmp6_router_advertisement_header_t rh;
1313
1314                       rh.icmp.type = ICMP6_router_advertisement;
1315                       rh.icmp.code = 0;
1316                       rh.icmp.checksum = 0;
1317                       
1318                       rh.current_hop_limit = radv_info->curr_hop_limit;
1319                       rh.router_lifetime_in_sec = clib_host_to_net_u16(radv_info->adv_router_lifetime_in_sec);
1320                       rh.time_in_msec_between_retransmitted_neighbor_solicitations = 
1321                         clib_host_to_net_u32(radv_info->adv_time_in_msec_between_retransmitted_neighbor_solicitations);
1322                       rh.neighbor_reachable_time_in_msec = 
1323                         clib_host_to_net_u32(radv_info->adv_neighbor_reachable_time_in_msec);
1324                       
1325                       rh.flags = (radv_info->adv_managed_flag) ? ICMP6_ROUTER_DISCOVERY_FLAG_ADDRESS_CONFIG_VIA_DHCP : 0;
1326                       rh.flags |= ( (radv_info->adv_other_flag) ? ICMP6_ROUTER_DISCOVERY_FLAG_OTHER_CONFIG_VIA_DHCP : 0);
1327
1328
1329                       u16 payload_length = sizeof(icmp6_router_advertisement_header_t);
1330
1331                       vlib_buffer_add_data (vm,
1332                                             p0->free_list_index,
1333                                             bi0,
1334                                             (void *)&rh, sizeof(icmp6_router_advertisement_header_t));
1335
1336                       if(radv_info->adv_link_layer_address)
1337                         {
1338                           icmp6_neighbor_discovery_ethernet_link_layer_address_option_t h;
1339
1340                           h.header.type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
1341                           h.header.n_data_u64s = 1;
1342
1343                           /* copy ll address */
1344                           clib_memcpy(&h.ethernet_address[0], eth_if0->address,  6);
1345
1346                           vlib_buffer_add_data (vm,
1347                                                 p0->free_list_index,
1348                                                 bi0,
1349                                                 (void *)&h, sizeof(icmp6_neighbor_discovery_ethernet_link_layer_address_option_t));
1350
1351                           payload_length += sizeof(icmp6_neighbor_discovery_ethernet_link_layer_address_option_t);
1352                         }
1353                       
1354                       /* add MTU option */
1355                       if(radv_info->adv_link_mtu)
1356                         {
1357                           icmp6_neighbor_discovery_mtu_option_t h;
1358
1359                           h.unused = 0;
1360                           h.mtu =  clib_host_to_net_u32(radv_info->adv_link_mtu);
1361                           h.header.type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_mtu;
1362                           h.header.n_data_u64s = 1;
1363                           
1364                           payload_length += sizeof( icmp6_neighbor_discovery_mtu_option_t);
1365
1366                           vlib_buffer_add_data (vm,
1367                                                 p0->free_list_index,
1368                                                 bi0,
1369                                                 (void *)&h, sizeof(icmp6_neighbor_discovery_mtu_option_t));
1370                         }
1371                       
1372                       /* add advertised prefix options  */
1373                       ip6_radv_prefix_t *pr_info; 
1374
1375                       pool_foreach (pr_info, radv_info->adv_prefixes_pool, ({
1376
1377                             if(pr_info->enabled &&
1378                                (!pr_info->decrement_lifetime_flag  || (pr_info->pref_lifetime_expires >0)))
1379                               {
1380                                 /* advertise this prefix */
1381                                 icmp6_neighbor_discovery_prefix_information_option_t h;
1382                                 
1383                                 h.header.type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_prefix_information;
1384                                 h.header.n_data_u64s  =  (sizeof(icmp6_neighbor_discovery_prefix_information_option_t) >> 3);
1385                                 
1386                                 h.dst_address_length  = pr_info->prefix_len;
1387                                 
1388                                 h.flags  = (pr_info->adv_on_link_flag) ? ICMP6_NEIGHBOR_DISCOVERY_PREFIX_INFORMATION_FLAG_ON_LINK : 0;
1389                                 h.flags |= (pr_info->adv_autonomous_flag) ?  ICMP6_NEIGHBOR_DISCOVERY_PREFIX_INFORMATION_AUTO :  0;
1390                                 
1391                                 if(radv_info->cease_radv && pr_info->deprecated_prefix_flag)
1392                                   { 
1393                                     h.valid_time = clib_host_to_net_u32(MIN_ADV_VALID_LIFETIME);
1394                                     h.preferred_time  = 0;
1395                                   }
1396                                 else
1397                                   {
1398                                     if(pr_info->decrement_lifetime_flag)
1399                                       {
1400                                         pr_info->adv_valid_lifetime_in_secs = ((pr_info->valid_lifetime_expires  > now)) ?
1401                                           (pr_info->valid_lifetime_expires  - now) : 0;
1402                                         
1403                                         pr_info->adv_pref_lifetime_in_secs = ((pr_info->pref_lifetime_expires  > now)) ?
1404                                           (pr_info->pref_lifetime_expires  - now) : 0;
1405                                       }
1406                                     
1407                                     h.valid_time = clib_host_to_net_u32(pr_info->adv_valid_lifetime_in_secs);
1408                                     h.preferred_time  = clib_host_to_net_u32(pr_info->adv_pref_lifetime_in_secs) ;
1409                                   }
1410                                 h.unused  = 0;
1411                                 
1412                                 clib_memcpy(&h.dst_address, &pr_info->prefix,  sizeof(ip6_address_t));
1413
1414                                 payload_length += sizeof( icmp6_neighbor_discovery_prefix_information_option_t); 
1415
1416                                 vlib_buffer_add_data (vm,
1417                                                       p0->free_list_index,
1418                                                       bi0,
1419                                                       (void *)&h, sizeof(icmp6_neighbor_discovery_prefix_information_option_t));
1420
1421                               } 
1422                           }));
1423
1424                       /* add additional options before here */
1425
1426                       /* finish building the router advertisement... */
1427                       if(!is_unspecified && radv_info->send_unicast)
1428                         {
1429                           ip0->dst_address = ip0->src_address;
1430                         }
1431                       else
1432                         {                             
1433                           /* target address is all-nodes mcast addr */ 
1434                           ip6_set_reserved_multicast_address(&ip0->dst_address, 
1435                                                              IP6_MULTICAST_SCOPE_link_local,
1436                                                              IP6_MULTICAST_GROUP_ID_all_hosts);
1437                         }
1438                       
1439                       /* source address MUST be the link-local address */
1440                       ip0->src_address = radv_info->link_local_address;
1441                       
1442                       ip0->hop_limit = 255;
1443                       ip0->payload_length = clib_host_to_net_u16 (payload_length);
1444
1445                       icmp6_router_advertisement_header_t * rh0 = (icmp6_router_advertisement_header_t *)(ip0 + 1);
1446                       rh0->icmp.checksum = 
1447                           ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0, 
1448                                                              &bogus_length);
1449                       ASSERT(bogus_length == 0);
1450                       
1451                       /* setup output if and adjacency */
1452                       vnet_buffer (p0)->sw_if_index[VLIB_RX] = 
1453                         vnet_main.local_interface_sw_if_index;
1454                       
1455                       if (is_solicitation) 
1456                         {
1457                           ethernet_header_t *eth0;
1458                           /* Reuse current MAC header, copy SMAC to DMAC and 
1459                            * interface MAC to SMAC */
1460                           vlib_buffer_reset (p0);
1461                           eth0 = vlib_buffer_get_current(p0);
1462                           clib_memcpy(eth0->dst_address, eth0->src_address, 6);
1463                           clib_memcpy(eth0->src_address, eth_if0->address, 6);
1464                           next0 = is_dropped ? 
1465                               next0 : ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX;
1466                           vnet_buffer(p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1467                         }
1468                       else 
1469                         {
1470                           adj_index0 = radv_info->all_nodes_adj_index;
1471                           if (adj_index0 == 0)
1472                               error0 = ICMP6_ERROR_DST_LOOKUP_MISS;
1473                           else
1474                             {
1475                               ip_adjacency_t * adj0 = ip_get_adjacency (&im->lookup_main, adj_index0);
1476                               error0 = 
1477                                   ((adj0->rewrite_header.sw_if_index != sw_if_index0
1478                                     || adj0->lookup_next_index != IP_LOOKUP_NEXT_REWRITE)
1479                                    ? ICMP6_ERROR_ROUTER_SOLICITATION_DEST_UNKNOWN
1480                                    : error0);
1481                               next0 = is_dropped ? 
1482                                   next0 : ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW;
1483                               vnet_buffer (p0)->ip.adj_index[VLIB_RX] = adj_index0;
1484                            }
1485                         }
1486                       
1487                       radv_info->n_solicitations_dropped  += is_dropped;
1488                       radv_info->n_solicitations_rcvd  += is_solicitation;
1489                       
1490                       if((error0 ==  ICMP6_ERROR_NONE) && !is_dropped)
1491                         {
1492                           radv_info->n_advertisements_sent++;
1493                           n_advertisements_sent++;
1494                         }
1495                     }
1496                 }
1497             }
1498
1499           p0->error = error_node->errors[error0];
1500
1501           if(error0 != ICMP6_ERROR_NONE)
1502             vlib_error_count (vm, error_node->node_index, error0, 1);
1503           
1504           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1505                                            to_next, n_left_to_next,
1506                                            bi0, next0);
1507           
1508         }
1509       
1510       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1511     }
1512
1513   /* Account for router advertisements sent. */
1514   vlib_error_count (vm, error_node->node_index, ICMP6_ERROR_ROUTER_ADVERTISEMENTS_TX, n_advertisements_sent);
1515
1516   return frame->n_vectors;
1517 }
1518
1519  /* validate advertised info for consistancy (see RFC-4861 section 6.2.7) - log any inconsistencies, packet will always  be dropped  */
1520 static_always_inline uword
1521 icmp6_router_advertisement(vlib_main_t * vm,
1522                            vlib_node_runtime_t * node,
1523                            vlib_frame_t * frame)
1524 {
1525   vnet_main_t * vnm = vnet_get_main();
1526   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
1527   uword n_packets = frame->n_vectors;
1528   u32 * from, * to_next;
1529   u32 n_left_from, n_left_to_next, next_index;
1530   u32 n_advertisements_rcvd = 0;
1531
1532   vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip6_icmp_input_node.index);
1533
1534   from = vlib_frame_vector_args (frame);
1535   n_left_from = n_packets;
1536   next_index = node->cached_next_index;
1537   
1538   if (node->flags & VLIB_NODE_FLAG_TRACE)
1539     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
1540                                    /* stride */ 1,
1541                                    sizeof (icmp6_input_trace_t));
1542
1543   while (n_left_from > 0)
1544     {
1545       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1546       
1547       while (n_left_from > 0 && n_left_to_next > 0)
1548         {
1549           vlib_buffer_t * p0;
1550           ip6_header_t * ip0;
1551           ip6_radv_t *radv_info = 0;
1552           icmp6_router_advertisement_header_t * h0;  
1553           u32 bi0, options_len0, sw_if_index0, next0, error0;
1554
1555           bi0 = to_next[0] = from[0];
1556
1557           from += 1;
1558           to_next += 1;
1559           n_left_from -= 1;
1560           n_left_to_next -= 1;
1561       
1562           p0 = vlib_get_buffer (vm, bi0);
1563           ip0 = vlib_buffer_get_current (p0);
1564           h0 = ip6_next_header (ip0);
1565           options_len0 = clib_net_to_host_u16 (ip0->payload_length) - sizeof (h0[0]);
1566
1567           error0 = ICMP6_ERROR_NONE;
1568           sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1569
1570           /* Check that source address is link-local*/
1571           error0 = (!ip6_address_is_link_local_unicast (&ip0->src_address)) ? 
1572             ICMP6_ERROR_ROUTER_ADVERTISEMENT_SOURCE_NOT_LINK_LOCAL : error0;
1573
1574           /* default is to drop */
1575           next0 = ICMP6_ROUTER_SOLICITATION_NEXT_DROP;
1576           
1577           n_advertisements_rcvd++;
1578
1579           if (error0 == ICMP6_ERROR_NONE)
1580             {
1581               vnet_sw_interface_t * sw_if0;
1582               ethernet_interface_t * eth_if0;
1583     
1584               sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
1585               ASSERT (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
1586               eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
1587
1588               /* only support ethernet interface type for now */
1589               error0 = (!eth_if0) ?  ICMP6_ERROR_ROUTER_SOLICITATION_UNSUPPORTED_INTF : error0;
1590
1591               if (error0 == ICMP6_ERROR_NONE)
1592                 {
1593                   u32 ri;
1594
1595                   /* look up the radv_t information for this interface */
1596                   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index0, ~0);
1597
1598                   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index0];
1599
1600                   if(ri != ~0)
1601                       radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
1602                         
1603                   error0 = ((!radv_info) ?  ICMP6_ERROR_ROUTER_SOLICITATION_RADV_NOT_CONFIG : error0);
1604
1605                   if (error0 == ICMP6_ERROR_NONE)
1606                     {
1607                       /* validate advertised information */
1608                       if((h0->current_hop_limit && radv_info->curr_hop_limit) &&
1609                          (h0->current_hop_limit != radv_info->curr_hop_limit))
1610                         {
1611                           ip6_neighbor_syslog(vm,  LOG_WARNING,  
1612                                               "our AdvCurHopLimit on %U doesn't agree with %U", 
1613                                               format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1614                         }
1615
1616                       if((h0->flags &  ICMP6_ROUTER_DISCOVERY_FLAG_ADDRESS_CONFIG_VIA_DHCP)  != 
1617                          radv_info->adv_managed_flag)
1618                         {
1619                           ip6_neighbor_syslog(vm,  LOG_WARNING,  
1620                                               "our AdvManagedFlag on %U doesn't agree with %U", 
1621                                               format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1622                         }
1623
1624                       if((h0->flags &   ICMP6_ROUTER_DISCOVERY_FLAG_OTHER_CONFIG_VIA_DHCP)   != 
1625                          radv_info->adv_other_flag)
1626                         {
1627                           ip6_neighbor_syslog(vm,  LOG_WARNING,  
1628                                               "our AdvOtherConfigFlag on %U doesn't agree with %U", 
1629                                               format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1630                         }
1631
1632                       if((h0->time_in_msec_between_retransmitted_neighbor_solicitations && 
1633                           radv_info->adv_time_in_msec_between_retransmitted_neighbor_solicitations) &&
1634                          (h0->time_in_msec_between_retransmitted_neighbor_solicitations !=
1635                           clib_host_to_net_u32(radv_info->adv_time_in_msec_between_retransmitted_neighbor_solicitations)))
1636                         {
1637                           ip6_neighbor_syslog(vm,  LOG_WARNING,  
1638                                               "our AdvRetransTimer on %U doesn't agree with %U", 
1639                                               format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1640                         }
1641
1642                       if((h0->neighbor_reachable_time_in_msec && 
1643                           radv_info->adv_neighbor_reachable_time_in_msec) &&
1644                          (h0->neighbor_reachable_time_in_msec !=
1645                           clib_host_to_net_u32(radv_info->adv_neighbor_reachable_time_in_msec)))
1646                         {
1647                           ip6_neighbor_syslog(vm,  LOG_WARNING,  
1648                                               "our AdvReachableTime on %U doesn't agree with %U", 
1649                                               format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1650                         }
1651
1652                       /* check for MTU or prefix options or .. */
1653                       u8 * opt_hdr = (u8 *)(h0 + 1);
1654                       while( options_len0 > 0)
1655                         {
1656                           icmp6_neighbor_discovery_option_header_t *o0 = ( icmp6_neighbor_discovery_option_header_t *)opt_hdr;
1657                           int opt_len = o0->n_data_u64s << 3;
1658                           icmp6_neighbor_discovery_option_type_t option_type = o0->type;
1659
1660                           if(options_len0 < 2)
1661                             {
1662                               ip6_neighbor_syslog(vm,  LOG_ERR,  
1663                                                   "malformed RA packet on %U from %U", 
1664                                                   format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1665                               break;
1666                             }
1667
1668                           if(opt_len == 0)
1669                             {
1670                               ip6_neighbor_syslog(vm,  LOG_ERR,  
1671                                                   " zero length option in RA on %U from %U", 
1672                                                   format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1673                               break;
1674                             }
1675                           else if( opt_len > options_len0)
1676                             {
1677                               ip6_neighbor_syslog(vm,  LOG_ERR,  
1678                                                   "option length in RA packet  greater than total length on %U from %U", 
1679                                                   format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1680                               break;
1681                             }
1682
1683                           options_len0 -= opt_len;
1684                           opt_hdr += opt_len;
1685
1686                           switch(option_type)
1687                             {
1688                             case ICMP6_NEIGHBOR_DISCOVERY_OPTION_mtu:
1689                               {                       
1690                                 icmp6_neighbor_discovery_mtu_option_t *h =
1691                                   (icmp6_neighbor_discovery_mtu_option_t *)(o0);
1692
1693                                 if(opt_len < sizeof(*h))
1694                                   break;
1695
1696                                 if((h->mtu && radv_info->adv_link_mtu) &&
1697                                    (h->mtu != clib_host_to_net_u32(radv_info->adv_link_mtu)))
1698                                   {
1699                                     ip6_neighbor_syslog(vm,  LOG_WARNING,  
1700                                                         "our AdvLinkMTU on %U doesn't agree with %U", 
1701                                                         format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1702                                   }
1703                               }
1704                               break;
1705                               
1706                             case ICMP6_NEIGHBOR_DISCOVERY_OPTION_prefix_information:
1707                               {
1708                                 icmp6_neighbor_discovery_prefix_information_option_t *h =
1709                                   (icmp6_neighbor_discovery_prefix_information_option_t *)(o0);
1710                               
1711                                 /* validate advertised prefix options  */
1712                                 ip6_radv_prefix_t *pr_info; 
1713                                 u32 preferred, valid;
1714
1715                                 if(opt_len < sizeof(*h))
1716                                   break;
1717
1718                                 preferred =  clib_net_to_host_u32(h->preferred_time);
1719                                 valid =  clib_net_to_host_u32(h->valid_time);
1720
1721                                 /* look for matching prefix - if we our advertising it, it better be consistant */
1722                                 pool_foreach (pr_info, radv_info->adv_prefixes_pool, ({
1723                                       
1724                                       ip6_address_t mask;
1725                                       ip6_address_mask_from_width(&mask, pr_info->prefix_len);
1726
1727                                       if(pr_info->enabled &&
1728                                        (pr_info->prefix_len == h->dst_address_length) &&
1729                                          ip6_address_is_equal_masked (&pr_info->prefix,  &h->dst_address, &mask))
1730                                         {
1731                                           /* found it */
1732                                           if(!pr_info->decrement_lifetime_flag &&
1733                                              valid != pr_info->adv_valid_lifetime_in_secs)
1734                                             {
1735                                               ip6_neighbor_syslog(vm,  LOG_WARNING,  
1736                                                                   "our ADV validlifetime on  %U for %U does not  agree with %U", 
1737                                                                   format_vnet_sw_if_index_name, vnm, sw_if_index0,format_ip6_address, &pr_info->prefix, 
1738                                                                   format_ip6_address, &h->dst_address);
1739                                             }
1740                                           if(!pr_info->decrement_lifetime_flag &&
1741                                              preferred != pr_info->adv_pref_lifetime_in_secs)
1742                                             {
1743                                               ip6_neighbor_syslog(vm,  LOG_WARNING,  
1744                                                                   "our ADV preferredlifetime on  %U for %U does not  agree with %U", 
1745                                                                   format_vnet_sw_if_index_name, vnm, sw_if_index0,format_ip6_address, &pr_info->prefix, 
1746                                                                   format_ip6_address, &h->dst_address);
1747                                             }
1748                                         }
1749                                       break;
1750                                     }));
1751                                 break;
1752                               }
1753                             default:
1754                               /* skip this one */
1755                               break;
1756                             }
1757                         }
1758                     }
1759                 }
1760             }
1761
1762           p0->error = error_node->errors[error0];
1763
1764           if(error0 != ICMP6_ERROR_NONE)
1765             vlib_error_count (vm, error_node->node_index, error0, 1);
1766           
1767           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1768                                            to_next, n_left_to_next,
1769                                            bi0, next0);
1770         }
1771       
1772       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1773     }
1774
1775   /* Account for router advertisements sent. */
1776   vlib_error_count (vm, error_node->node_index, ICMP6_ERROR_ROUTER_ADVERTISEMENTS_RX, n_advertisements_rcvd);
1777
1778   return frame->n_vectors;
1779 }
1780
1781 /* create and initialize router advertisement parameters with default values for this intfc */
1782 static u32
1783 ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm,
1784                                    u32 sw_if_index,
1785                                    u32 is_add)
1786 {
1787   ip6_neighbor_main_t * nm = &ip6_neighbor_main;  
1788   ip6_radv_t * a= 0;  
1789   u32 ri = ~0;
1790   vnet_sw_interface_t * sw_if0;
1791   ethernet_interface_t * eth_if0 = 0; 
1792
1793   /* lookup radv container  - ethernet interfaces only */
1794   sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
1795   if(sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
1796     eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
1797
1798   if(!eth_if0)
1799     return ri;
1800    
1801   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
1802   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
1803
1804   if(ri != ~0)
1805     {
1806       a = pool_elt_at_index (nm->if_radv_pool, ri);
1807
1808       if(!is_add)
1809         {
1810           u32 i, * to_delete = 0;
1811           ip6_radv_prefix_t  *p;
1812           ip6_mldp_group_t *m;
1813           
1814           /* remove adjacencies */
1815           adj_unlock(a->all_nodes_adj_index); 
1816           adj_unlock(a->all_routers_adj_index);       
1817           adj_unlock(a->all_mldv2_routers_adj_index);
1818           
1819           /* clean up prefix_pool */
1820           pool_foreach (p, a->adv_prefixes_pool, ({
1821                 vec_add1 (to_delete, p  -  a->adv_prefixes_pool);
1822               }));
1823           
1824           for (i = 0; i < vec_len (to_delete); i++)
1825             {
1826               p = pool_elt_at_index (a->adv_prefixes_pool, to_delete[i]);
1827               mhash_unset (&a->address_to_prefix_index, &p->prefix, 0);
1828               pool_put (a->adv_prefixes_pool, p);
1829             }
1830           
1831           vec_free (to_delete);
1832           to_delete = 0;
1833           
1834           /* clean up mldp group pool */
1835           pool_foreach (m, a->mldp_group_pool, ({
1836                 vec_add1 (to_delete, m  -  a->mldp_group_pool);
1837               }));
1838           
1839           for (i = 0; i < vec_len (to_delete); i++)
1840             {
1841               m = pool_elt_at_index (a->mldp_group_pool, to_delete[i]);
1842               mhash_unset (&a->address_to_mldp_index, &m->mcast_address, 0);
1843               pool_put (a->mldp_group_pool, m);
1844             }
1845           
1846           vec_free (to_delete);
1847           
1848           pool_put (nm->if_radv_pool,  a);
1849           nm->if_radv_pool_index_by_sw_if_index[sw_if_index] = ~0;
1850           ri = ~0;
1851           ip6_sw_interface_enable_disable(sw_if_index, 0);
1852         }
1853     }
1854  else
1855    {
1856      if(is_add)
1857        {
1858          vnet_hw_interface_t * hw_if0;
1859      
1860          ip6_sw_interface_enable_disable(sw_if_index, 1);
1861          hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index);
1862          
1863          pool_get (nm->if_radv_pool, a);
1864          
1865          ri = a - nm->if_radv_pool;
1866          nm->if_radv_pool_index_by_sw_if_index[sw_if_index] = ri;
1867          
1868          /* initialize default values (most of which are zero) */
1869          memset (a, 0, sizeof (a[0]));
1870          
1871          a->sw_if_index = sw_if_index;
1872          a->fib_index = ~0;
1873          a->max_radv_interval = DEF_MAX_RADV_INTERVAL;    
1874          a->min_radv_interval =  DEF_MIN_RADV_INTERVAL;    
1875          a->curr_hop_limit = DEF_CURR_HOP_LIMIT;                         
1876          a->adv_router_lifetime_in_sec = DEF_DEF_RTR_LIFETIME;   
1877          
1878          a->adv_link_layer_address = 1;  /* send ll address source address option */
1879          
1880          a->min_delay_between_radv = MIN_DELAY_BETWEEN_RAS;
1881          a->max_delay_between_radv = MAX_DELAY_BETWEEN_RAS;
1882          a->max_rtr_default_lifetime = MAX_DEF_RTR_LIFETIME;
1883          a->seed = random_default_seed();
1884          
1885          /* for generating random interface ids */
1886          a->randomizer = 0x1119194911191949ULL;
1887          a->randomizer = random_u64 ((u32 *)&a->randomizer);
1888          
1889          a->initial_adverts_count = MAX_INITIAL_RTR_ADVERTISEMENTS ; 
1890          a->initial_adverts_sent = a->initial_adverts_count-1;
1891          a->initial_adverts_interval = MAX_INITIAL_RTR_ADVERT_INTERVAL;      
1892          
1893          /* deafult is to send */
1894          a->send_radv = 1;
1895          
1896          /* fill in radv_info for this interface that will be needed later */
1897          a->adv_link_mtu = hw_if0->max_l3_packet_bytes[VLIB_RX];
1898          
1899          clib_memcpy (a->link_layer_address, eth_if0->address, 6);
1900          
1901          /* fill in default link-local address  (this may be overridden) */
1902          ip6_link_local_address_from_ethernet_address (&a->link_local_address, eth_if0->address);
1903          a->link_local_prefix_len = 64;
1904
1905          mhash_init (&a->address_to_prefix_index, sizeof (uword), sizeof (ip6_address_t));
1906          mhash_init (&a->address_to_mldp_index, sizeof (uword), sizeof (ip6_address_t)); 
1907          
1908          {
1909            u8 link_layer_address[6] = 
1910              {0x33, 0x33, 0x00, 0x00, 0x00, IP6_MULTICAST_GROUP_ID_all_hosts};
1911            
1912            a->all_nodes_adj_index = adj_rewrite_add_and_lock(FIB_PROTOCOL_IP6,
1913                                                              FIB_LINK_IP6,
1914                                                              sw_if_index,
1915                                                              link_layer_address);
1916          } 
1917          
1918          {
1919            u8 link_layer_address[6] = 
1920              {0x33, 0x33, 0x00, 0x00, 0x00, IP6_MULTICAST_GROUP_ID_all_routers};
1921         
1922            a->all_routers_adj_index = adj_rewrite_add_and_lock(FIB_PROTOCOL_IP6,
1923                                                                FIB_LINK_IP6,
1924                                                                sw_if_index,
1925                                                                link_layer_address);
1926          } 
1927          
1928          {
1929            u8 link_layer_address[6] = 
1930              {0x33, 0x33, 0x00, 0x00, 0x00, IP6_MULTICAST_GROUP_ID_mldv2_routers};
1931            
1932            a->all_mldv2_routers_adj_index = 
1933                adj_rewrite_add_and_lock(FIB_PROTOCOL_IP6,
1934                                         FIB_LINK_IP6,
1935                                         sw_if_index,
1936                                         link_layer_address);
1937          } 
1938          
1939          /* add multicast groups we will always be reporting  */
1940          ip6_address_t addr;
1941          ip6_mldp_group_t  *mcast_group_info;
1942          
1943          ip6_set_reserved_multicast_address (&addr,
1944                                              IP6_MULTICAST_SCOPE_link_local,
1945                                              IP6_MULTICAST_GROUP_ID_all_hosts);
1946          
1947          /* lookup  mldp info for this interface */
1948          
1949          uword * p = mhash_get (&a->address_to_mldp_index,  &addr);
1950          mcast_group_info = p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0;
1951          
1952          /* add address */
1953          if(!mcast_group_info)
1954            {
1955              /* add */
1956              u32 mi;
1957              pool_get (a->mldp_group_pool, mcast_group_info);
1958           
1959              mi = mcast_group_info - a->mldp_group_pool;
1960              mhash_set (&a->address_to_mldp_index,  &addr,  mi, /* old_value */ 0);
1961              
1962              mcast_group_info->type = 4;
1963              mcast_group_info->mcast_source_address_pool = 0;
1964              mcast_group_info->num_sources = 0;
1965              clib_memcpy(&mcast_group_info->mcast_address, &addr, sizeof(ip6_address_t));
1966            } 
1967          
1968          ip6_set_reserved_multicast_address (&addr,
1969                                              IP6_MULTICAST_SCOPE_link_local,
1970                                              IP6_MULTICAST_GROUP_ID_all_routers);
1971          
1972          p = mhash_get (&a->address_to_mldp_index,  &addr);
1973          mcast_group_info = p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0;
1974          
1975          if(!mcast_group_info)
1976            {
1977              /* add */
1978              u32 mi;
1979              pool_get (a->mldp_group_pool, mcast_group_info);
1980              
1981              mi = mcast_group_info - a->mldp_group_pool;
1982              mhash_set (&a->address_to_mldp_index,  &addr,  mi, /* old_value */ 0);
1983              
1984              mcast_group_info->type = 4;
1985              mcast_group_info->mcast_source_address_pool = 0;
1986              mcast_group_info->num_sources = 0;
1987              clib_memcpy(&mcast_group_info->mcast_address, &addr, sizeof(ip6_address_t));
1988            } 
1989          
1990          ip6_set_reserved_multicast_address (&addr,
1991                                              IP6_MULTICAST_SCOPE_link_local,
1992                                              IP6_MULTICAST_GROUP_ID_mldv2_routers);
1993          
1994          p = mhash_get (&a->address_to_mldp_index,  &addr);
1995          mcast_group_info = p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0;
1996          
1997          if(!mcast_group_info)
1998            {
1999              /* add */
2000              u32 mi;
2001              pool_get (a->mldp_group_pool, mcast_group_info);
2002              
2003              mi = mcast_group_info - a->mldp_group_pool;
2004              mhash_set (&a->address_to_mldp_index,  &addr,  mi, /* old_value */ 0);
2005              
2006              mcast_group_info->type = 4;
2007              mcast_group_info->mcast_source_address_pool = 0;
2008              mcast_group_info->num_sources = 0;
2009              clib_memcpy(&mcast_group_info->mcast_address, &addr, sizeof(ip6_address_t));
2010            } 
2011        }
2012    } 
2013   return  ri;
2014 }
2015
2016 /* send an mldpv2 report  */
2017 static void
2018 ip6_neighbor_send_mldpv2_report(u32 sw_if_index)
2019 {
2020   vnet_main_t * vnm = vnet_get_main();
2021   vlib_main_t * vm = vnm->vlib_main;
2022   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2023   vnet_sw_interface_t * sw_if0;
2024   ethernet_interface_t * eth_if0;
2025   u32 ri;
2026   int bogus_length;
2027
2028   ip6_radv_t *radv_info; 
2029   u16 payload_length;
2030   vlib_buffer_t * b0;
2031   ip6_header_t * ip0;
2032   u32 * to_next;
2033   vlib_frame_t * f;
2034   u32 bo0;
2035   u32 n_to_alloc = 1;
2036   u32 n_allocated;
2037   
2038   icmp6_multicast_listener_report_header_t *rh0;
2039   icmp6_multicast_listener_report_packet_t *rp0;
2040
2041   sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
2042   ASSERT (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
2043   eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
2044
2045   if (!eth_if0 || !vnet_sw_interface_is_admin_up (vnm, sw_if_index))
2046     return;
2047
2048   /* look up the radv_t  information for this interface */
2049   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2050   
2051   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2052   
2053   if(ri == ~0)
2054     return;
2055                 
2056   /* send report now - build a mldpv2 report packet  */
2057   n_allocated = vlib_buffer_alloc_from_free_list(vm, 
2058                                                  &bo0, 
2059                                                  n_to_alloc,
2060                                                  VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
2061   if (PREDICT_FALSE(n_allocated == 0))
2062     {
2063       clib_warning ("buffer allocation failure");
2064       return;
2065     }
2066
2067   b0 = vlib_get_buffer (vm, bo0);
2068
2069   /* adjust the sizeof the buffer to just include the ipv6 header */
2070   b0->current_length  = sizeof(icmp6_multicast_listener_report_packet_t);
2071
2072   payload_length = sizeof(icmp6_multicast_listener_report_header_t);
2073
2074   b0->error = ICMP6_ERROR_NONE;
2075
2076   rp0 = vlib_buffer_get_current (b0);
2077   ip0 = (ip6_header_t *)&rp0-> ip;
2078   rh0 = (icmp6_multicast_listener_report_header_t *)&rp0-> report_hdr;
2079   
2080   memset (rp0 , 0x0, sizeof (icmp6_multicast_listener_report_packet_t));
2081   
2082   ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (0x6 << 28);
2083
2084   ip0->protocol = IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS;  
2085   /* for DEBUG - vnet driver won't seem to emit router alerts */
2086   /* ip0->protocol = IP_PROTOCOL_ICMP6; */
2087   ip0->hop_limit = 1;
2088  
2089   rh0->icmp.type = ICMP6_multicast_listener_report_v2;
2090   
2091   /* source address MUST be the link-local address */
2092   radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
2093   ip0->src_address = radv_info->link_local_address;  
2094
2095   /* destination is all mldpv2 routers */
2096   ip6_set_reserved_multicast_address(&ip0->dst_address, 
2097                                      IP6_MULTICAST_SCOPE_link_local,
2098                                      IP6_MULTICAST_GROUP_ID_mldv2_routers);
2099   
2100   /* add reports here */
2101   ip6_mldp_group_t *m;
2102   int num_addr_records = 0;
2103   icmp6_multicast_address_record_t rr;
2104
2105   /* fill in the hop-by-hop extension header (router alert) info */
2106   rh0->ext_hdr.next_hdr = IP_PROTOCOL_ICMP6;
2107   rh0->ext_hdr.n_data_u64s = 0;
2108   
2109   rh0->alert.type = IP6_MLDP_ALERT_TYPE;
2110   rh0->alert.len = 2;
2111   rh0->alert.value = 0;
2112   
2113   rh0->pad.type = 1;
2114   rh0->pad.len = 0;
2115  
2116   rh0->icmp.checksum = 0;
2117
2118   pool_foreach (m, radv_info->mldp_group_pool, ({
2119
2120         rr.type = m->type;
2121         rr.aux_data_len_u32s = 0;
2122         rr.num_sources = clib_host_to_net_u16 (m->num_sources);
2123         clib_memcpy(&rr.mcast_addr, &m->mcast_address, sizeof(ip6_address_t));
2124
2125         num_addr_records++;
2126
2127         vlib_buffer_add_data (vm,
2128                               b0->free_list_index,
2129                               bo0,
2130                               (void *)&rr, sizeof(icmp6_multicast_address_record_t));
2131         
2132         payload_length += sizeof( icmp6_multicast_address_record_t);
2133       }));
2134
2135   rh0->rsvd = 0;
2136   rh0->num_addr_records =  clib_host_to_net_u16(num_addr_records);
2137   
2138   /* update lengths */
2139   ip0->payload_length = clib_host_to_net_u16 (payload_length);
2140
2141   rh0->icmp.checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0, 
2142                                                           &bogus_length);
2143   ASSERT(bogus_length == 0);
2144
2145   /* 
2146    * OK to override w/ no regard for actual FIB, because
2147    * ip6-rewrite-local only looks at the adjacency.
2148    */
2149   vnet_buffer (b0)->sw_if_index[VLIB_RX] = 
2150     vnet_main.local_interface_sw_if_index;
2151   
2152   vnet_buffer (b0)->ip.adj_index[VLIB_RX]  = 
2153     radv_info->all_mldv2_routers_adj_index;
2154
2155   vlib_node_t * node = vlib_get_node_by_name (vm, (u8 *) "ip6-rewrite-local");
2156   
2157   f = vlib_get_frame_to_node (vm, node->index);
2158   to_next = vlib_frame_vector_args (f);
2159   to_next[0] = bo0;
2160   f->n_vectors = 1;
2161   
2162   vlib_put_frame_to_node (vm, node->index, f);
2163   return;
2164 }
2165
2166 VLIB_REGISTER_NODE (ip6_icmp_router_solicitation_node,static) = {
2167   .function = icmp6_router_solicitation,
2168   .name = "icmp6-router-solicitation",
2169
2170   .vector_size = sizeof (u32),
2171
2172   .format_trace = format_icmp6_input_trace,
2173
2174   .n_next_nodes = ICMP6_ROUTER_SOLICITATION_N_NEXT,
2175   .next_nodes = {
2176     [ICMP6_ROUTER_SOLICITATION_NEXT_DROP] = "error-drop",
2177     [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW] = "ip6-rewrite-local",
2178     [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX] = "interface-output",
2179   },
2180 };
2181
2182 /* send a RA or update the timer info etc.. */
2183 static uword
2184 ip6_neighbor_process_timer_event (vlib_main_t * vm,
2185                                            vlib_node_runtime_t * node,
2186                                            vlib_frame_t * frame)
2187 {
2188   vnet_main_t * vnm = vnet_get_main();
2189   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2190   ip6_radv_t *radv_info; 
2191   vlib_frame_t * f = 0; 
2192   u32 n_this_frame = 0;
2193   u32 n_left_to_next = 0;
2194   u32 * to_next = 0;
2195   u32 bo0; 
2196   icmp6_router_solicitation_header_t * h0;
2197   vlib_buffer_t * b0;
2198   f64 now = vlib_time_now (vm);
2199
2200   /* Interface ip6 radv info list */
2201   pool_foreach (radv_info, nm->if_radv_pool, ({
2202
2203         if( !vnet_sw_interface_is_admin_up (vnm, radv_info->sw_if_index))
2204           {
2205             radv_info->initial_adverts_sent = radv_info->initial_adverts_count-1;
2206             radv_info->next_multicast_time = now;             
2207             radv_info->last_multicast_time = now;
2208             radv_info->last_radv_time = 0;      
2209             radv_info->all_routers_mcast = 0;
2210             continue;
2211           }
2212
2213         /* Make sure that we've joined the all-routers multicast group */
2214         if(!radv_info->all_routers_mcast)
2215           {
2216             /* send MDLP_REPORT_EVENT message */              
2217             ip6_neighbor_send_mldpv2_report(radv_info->sw_if_index);
2218             radv_info->all_routers_mcast = 1;
2219           }
2220
2221         /* is it time to send a multicast  RA on this interface? */
2222         if(radv_info->send_radv && (now >=  radv_info->next_multicast_time))
2223           {     
2224             u32 n_to_alloc = 1;
2225             u32 n_allocated;
2226             
2227             f64 rfn = (radv_info->max_radv_interval - radv_info->min_radv_interval) * 
2228               random_f64 (&radv_info->seed) + radv_info->min_radv_interval;
2229
2230             /* multicast send - compute next multicast send time */
2231             if( radv_info->initial_adverts_sent > 0)
2232               {
2233                 radv_info->initial_adverts_sent--;
2234                 if(rfn > radv_info-> initial_adverts_interval)
2235                   rfn =  radv_info-> initial_adverts_interval;
2236
2237                 /* check to see if we are ceasing to send */
2238                 if( radv_info->initial_adverts_sent  == 0)
2239                   if(radv_info->cease_radv)  
2240                     radv_info->send_radv = 0;
2241               }
2242             
2243             radv_info->next_multicast_time =  rfn + now;
2244             radv_info->last_multicast_time = now;
2245             
2246             /* send advert now - build a "solicted" router advert with unspecified source address */
2247             n_allocated = vlib_buffer_alloc_from_free_list(vm, 
2248                                                            &bo0, 
2249                                                            n_to_alloc,
2250                                                            VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
2251             
2252             if (PREDICT_FALSE(n_allocated == 0))
2253               {
2254                 clib_warning ("buffer allocation failure");
2255                 continue;
2256               }
2257             b0 = vlib_get_buffer (vm, bo0);
2258             b0->current_length = sizeof( icmp6_router_solicitation_header_t);
2259             b0->error = ICMP6_ERROR_NONE;
2260             vnet_buffer (b0)->sw_if_index[VLIB_RX] = radv_info->sw_if_index;
2261             
2262             h0 =  vlib_buffer_get_current (b0);
2263             
2264             memset (h0, 0, sizeof (icmp6_router_solicitation_header_t));
2265             
2266             h0->ip.ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (0x6 << 28);
2267             h0->ip.payload_length = clib_host_to_net_u16 (sizeof (icmp6_router_solicitation_header_t)
2268                                                           - STRUCT_OFFSET_OF (icmp6_router_solicitation_header_t, neighbor));
2269             h0->ip.protocol = IP_PROTOCOL_ICMP6;
2270             h0->ip.hop_limit = 255;
2271             
2272             /* set src/dst address as "unspecified" this marks this packet as internally generated rather than recieved */
2273             h0->ip.src_address.as_u64[0] = 0;
2274             h0->ip.src_address.as_u64[1] = 0;
2275             
2276             h0->ip.dst_address.as_u64[0] = 0;
2277             h0->ip.dst_address.as_u64[1] = 0;
2278             
2279             h0->neighbor.icmp.type = ICMP6_router_solicitation;
2280
2281             if (PREDICT_FALSE(f == 0))
2282               { 
2283                 f = vlib_get_frame_to_node (vm, ip6_icmp_router_solicitation_node.index);
2284                 to_next = vlib_frame_vector_args (f);
2285                 n_left_to_next = VLIB_FRAME_SIZE;
2286                 n_this_frame = 0;
2287               }
2288
2289             n_this_frame++;
2290             n_left_to_next--;
2291             to_next[0] = bo0;
2292             to_next += 1;
2293
2294             if (PREDICT_FALSE(n_left_to_next == 0)) 
2295               {
2296                 f->n_vectors = n_this_frame;
2297                 vlib_put_frame_to_node (vm, ip6_icmp_router_solicitation_node.index, f);
2298                 f = 0;
2299               }
2300           }
2301       }));
2302
2303   if (f)
2304     {
2305       ASSERT(n_this_frame);
2306       f->n_vectors = n_this_frame;
2307       vlib_put_frame_to_node (vm, ip6_icmp_router_solicitation_node.index, f);
2308     }
2309   return  0;
2310 }
2311
2312 static uword
2313 ip6_icmp_neighbor_discovery_event_process (vlib_main_t * vm,
2314                                            vlib_node_runtime_t * node,
2315                                            vlib_frame_t * frame)
2316 {
2317   uword event_type;
2318   ip6_icmp_neighbor_discovery_event_data_t * event_data;
2319
2320   /* init code here */
2321  
2322   while (1)
2323     {
2324       vlib_process_wait_for_event_or_clock (vm,  1. /* seconds */);
2325
2326       event_data = vlib_process_get_event_data (vm,  &event_type);
2327
2328       if(!event_data)
2329         {
2330           /* No events found: timer expired. */
2331           /* process interface list and send RAs as appropriate, update timer info */
2332           ip6_neighbor_process_timer_event (vm,  node,  frame); 
2333         }
2334       else
2335         {
2336           switch (event_type) {
2337
2338           case ICMP6_ND_EVENT_INIT:
2339             break;
2340    
2341           case ~0:
2342             break;
2343             
2344           default:
2345             ASSERT (0);
2346           }
2347           
2348           if (event_data)
2349             _vec_len (event_data) = 0;
2350         }
2351     }
2352   return frame->n_vectors;
2353 }
2354
2355 VLIB_REGISTER_NODE (ip6_icmp_router_advertisement_node,static) = {
2356   .function = icmp6_router_advertisement,
2357   .name = "icmp6-router-advertisement",
2358
2359   .vector_size = sizeof (u32),
2360
2361   .format_trace = format_icmp6_input_trace,
2362
2363   .n_next_nodes = 1,
2364   .next_nodes = {
2365     [0] = "error-drop",
2366   },
2367 };
2368
2369 vlib_node_registration_t ip6_icmp_neighbor_discovery_event_node = {
2370
2371   .function = ip6_icmp_neighbor_discovery_event_process,
2372   .name = "ip6-icmp-neighbor-discovery-event-process",
2373   .type = VLIB_NODE_TYPE_PROCESS,
2374 };
2375
2376 static uword
2377 icmp6_neighbor_solicitation (vlib_main_t * vm,
2378                              vlib_node_runtime_t * node,
2379                              vlib_frame_t * frame)
2380 { return icmp6_neighbor_solicitation_or_advertisement (vm, node, frame, /* is_solicitation */ 1); }
2381
2382 static uword
2383 icmp6_neighbor_advertisement (vlib_main_t * vm,
2384                               vlib_node_runtime_t * node,
2385                               vlib_frame_t * frame)
2386 { return icmp6_neighbor_solicitation_or_advertisement (vm, node, frame, /* is_solicitation */ 0); }
2387
2388 VLIB_REGISTER_NODE (ip6_icmp_neighbor_solicitation_node,static) = {
2389   .function = icmp6_neighbor_solicitation,
2390   .name = "icmp6-neighbor-solicitation",
2391
2392   .vector_size = sizeof (u32),
2393
2394   .format_trace = format_icmp6_input_trace,
2395
2396   .n_next_nodes = ICMP6_NEIGHBOR_SOLICITATION_N_NEXT,
2397   .next_nodes = {
2398     [ICMP6_NEIGHBOR_SOLICITATION_NEXT_DROP] = "error-drop",
2399     [ICMP6_NEIGHBOR_SOLICITATION_NEXT_REPLY] = "interface-output",
2400   },
2401 };
2402
2403 VLIB_REGISTER_NODE (ip6_icmp_neighbor_advertisement_node,static) = {
2404   .function = icmp6_neighbor_advertisement,
2405   .name = "icmp6-neighbor-advertisement",
2406
2407   .vector_size = sizeof (u32),
2408
2409   .format_trace = format_icmp6_input_trace,
2410
2411   .n_next_nodes = 1,
2412   .next_nodes = {
2413     [0] = "error-drop",
2414   },
2415 };
2416
2417 /* API  support functions */
2418 int
2419 ip6_neighbor_ra_config(vlib_main_t * vm, u32 sw_if_index, 
2420                        u8 suppress, u8 managed, u8 other,
2421                        u8 ll_option,  u8 send_unicast,  u8 cease, 
2422                        u8 use_lifetime,  u32 lifetime,
2423                        u32 initial_count,  u32 initial_interval,  
2424                        u32 max_interval,  u32 min_interval,
2425                        u8 is_no)
2426 {
2427   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2428   int  error;
2429   u32 ri;
2430
2431   /* look up the radv_t  information for this interface */
2432   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2433   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2434   error = (ri != ~0) ? 0 :  VNET_API_ERROR_INVALID_SW_IF_INDEX;
2435
2436   if(!error)
2437     {
2438
2439       ip6_radv_t * radv_info;
2440       radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
2441   
2442       if((max_interval != 0) && (min_interval ==0))
2443         min_interval =  .75 * max_interval;
2444
2445       max_interval  = (max_interval != 0) ? ( (is_no) ?  DEF_MAX_RADV_INTERVAL :  max_interval) :  radv_info->max_radv_interval;
2446       min_interval  = (min_interval != 0) ? ( (is_no) ?  DEF_MIN_RADV_INTERVAL :  min_interval) :  radv_info->min_radv_interval; 
2447       lifetime  = (use_lifetime != 0) ? ( (is_no) ?  DEF_DEF_RTR_LIFETIME :  lifetime) :  radv_info->adv_router_lifetime_in_sec;
2448
2449       if(lifetime)
2450         {
2451           if(lifetime  > MAX_DEF_RTR_LIFETIME)
2452             lifetime = MAX_DEF_RTR_LIFETIME;
2453           
2454           if(lifetime <= max_interval)
2455             return VNET_API_ERROR_INVALID_VALUE;
2456         }
2457       
2458       if(min_interval  != 0)
2459         {
2460           if((min_interval > .75 * max_interval) ||
2461              (min_interval  < 3))
2462             return VNET_API_ERROR_INVALID_VALUE;
2463         }
2464
2465       if((initial_count  > MAX_INITIAL_RTR_ADVERTISEMENTS) ||
2466          (initial_interval  > MAX_INITIAL_RTR_ADVERT_INTERVAL))
2467         return VNET_API_ERROR_INVALID_VALUE;
2468
2469       /* 
2470          if "flag" is set and is_no is true then restore default value else set value corresponding to "flag" 
2471          if "flag" is clear  don't change corresponding value  
2472       */
2473       radv_info->send_radv =  (suppress != 0) ? ( (is_no  != 0) ? 1 : 0 ) : radv_info->send_radv;
2474       radv_info->adv_managed_flag = ( managed  != 0) ? ( (is_no) ? 0 : 1) : radv_info->adv_managed_flag;
2475       radv_info->adv_other_flag  = (other  != 0) ? ( (is_no) ?  0: 1) : radv_info->adv_other_flag;
2476       radv_info->adv_link_layer_address = ( ll_option != 0) ? ( (is_no) ? 1 : 0) : radv_info->adv_link_layer_address;
2477       radv_info->send_unicast  = (send_unicast  != 0) ? ( (is_no) ? 0 : 1) : radv_info->send_unicast;
2478       radv_info->cease_radv = ( cease != 0) ? ( (is_no) ?  0 : 1) : radv_info->cease_radv;
2479       
2480       radv_info->min_radv_interval  =  min_interval;
2481       radv_info->max_radv_interval = max_interval;
2482       radv_info->adv_router_lifetime_in_sec = lifetime;
2483
2484       radv_info->initial_adverts_count = 
2485         (initial_count  != 0) ? ( (is_no) ?   MAX_INITIAL_RTR_ADVERTISEMENTS  :  initial_count) : radv_info->initial_adverts_count ;
2486       radv_info->initial_adverts_interval = 
2487         (initial_interval  != 0) ? ( (is_no) ?  MAX_INITIAL_RTR_ADVERT_INTERVAL  :  initial_interval) : radv_info->initial_adverts_interval;
2488
2489       /* restart */
2490       if((cease != 0) && (is_no))
2491          radv_info-> send_radv = 1;
2492
2493       radv_info->initial_adverts_sent  = radv_info->initial_adverts_count -1;
2494       radv_info->next_multicast_time =  vlib_time_now (vm);    
2495       radv_info->last_multicast_time = vlib_time_now (vm);
2496       radv_info->last_radv_time = 0;    
2497     }
2498   return(error);
2499 }
2500
2501 int
2502 ip6_neighbor_ra_prefix(vlib_main_t * vm, u32 sw_if_index,  
2503                        ip6_address_t *prefix_addr,  u8 prefix_len,
2504                        u8 use_default,  u32 val_lifetime, u32 pref_lifetime,
2505                        u8 no_advertise,  u8 off_link, u8 no_autoconfig, u8 no_onlink,
2506                        u8 is_no)
2507 {
2508   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2509   int error;
2510   
2511   u32 ri;
2512
2513   /* look up the radv_t  information for this interface */
2514   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2515   
2516   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2517
2518   error = (ri != ~0) ? 0 : VNET_API_ERROR_INVALID_SW_IF_INDEX;
2519   
2520   if(!error)
2521     {
2522       f64 now = vlib_time_now (vm);
2523       ip6_radv_t * radv_info;
2524       radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
2525
2526       /* prefix info add, delete or update */
2527       ip6_radv_prefix_t * prefix; 
2528         
2529       /* lookup  prefix info for this  address on this interface */
2530       uword * p = mhash_get (&radv_info->address_to_prefix_index,  prefix_addr);
2531       
2532       prefix = p ? pool_elt_at_index (radv_info->adv_prefixes_pool, p[0]) : 0;
2533
2534       if(is_no)
2535         {
2536           /* delete */
2537           if(!prefix)
2538             return VNET_API_ERROR_INVALID_VALUE; /* invalid prefix */
2539     
2540           if(prefix->prefix_len != prefix_len)
2541             return VNET_API_ERROR_INVALID_VALUE_2;
2542
2543           /* FIXME - Should the DP do this or the CP ?*/
2544           /* do specific delete processing here before returning */
2545           /* try to remove from routing table */
2546
2547           mhash_unset (&radv_info->address_to_prefix_index, prefix_addr,/* old_value */ 0);
2548           pool_put (radv_info->adv_prefixes_pool, prefix);
2549
2550           radv_info->initial_adverts_sent  = radv_info->initial_adverts_count -1;
2551           radv_info->next_multicast_time =  vlib_time_now (vm);    
2552           radv_info->last_multicast_time = vlib_time_now (vm);
2553           radv_info->last_radv_time = 0;        
2554           return(error);
2555         }
2556
2557       /* adding or changing */
2558       if(!prefix)
2559         {
2560           /* add */
2561           u32 pi;
2562           pool_get (radv_info->adv_prefixes_pool, prefix);
2563           pi = prefix - radv_info->adv_prefixes_pool;
2564           mhash_set (&radv_info->address_to_prefix_index,  prefix_addr,  pi, /* old_value */ 0);
2565           
2566           memset(prefix, 0x0, sizeof(ip6_radv_prefix_t));
2567           
2568           prefix->prefix_len = prefix_len;
2569           clib_memcpy(&prefix->prefix,  prefix_addr, sizeof(ip6_address_t));
2570           
2571           /* initialize default values */
2572           prefix->adv_on_link_flag = 1;      /* L bit set */
2573           prefix->adv_autonomous_flag = 1;  /* A bit set */
2574           prefix->adv_valid_lifetime_in_secs =  DEF_ADV_VALID_LIFETIME;
2575           prefix->adv_pref_lifetime_in_secs = DEF_ADV_PREF_LIFETIME;
2576           prefix->enabled = 1;
2577           prefix->decrement_lifetime_flag = 1;
2578           prefix->deprecated_prefix_flag = 1;
2579
2580           if(off_link == 0)
2581             {
2582               /* FIXME - Should the DP do this or the CP ?*/
2583               /* insert prefix into routing table as a connected prefix */
2584             }
2585
2586           if(use_default)
2587             goto restart;
2588         }
2589       else
2590         {
2591           
2592           if(prefix->prefix_len != prefix_len)
2593             return VNET_API_ERROR_INVALID_VALUE_2;
2594
2595           if(off_link  != 0)
2596             {
2597               /* FIXME - Should the DP do this or the CP ?*/
2598               /* remove from routing table if already there */
2599             }     
2600         }
2601
2602       if((val_lifetime == ~0) || (pref_lifetime == ~0))
2603         {
2604           prefix->adv_valid_lifetime_in_secs =  ~0;
2605           prefix->adv_pref_lifetime_in_secs = ~0;
2606           prefix->decrement_lifetime_flag = 0;
2607         }
2608       else
2609         {
2610           prefix->adv_valid_lifetime_in_secs =  val_lifetime;;
2611           prefix->adv_pref_lifetime_in_secs =  pref_lifetime;
2612         }
2613       
2614       /* copy  remaining */
2615       prefix->enabled = !(no_advertise != 0);
2616       prefix->adv_on_link_flag = !((off_link != 0) || (no_onlink != 0));
2617       prefix->adv_autonomous_flag = !(no_autoconfig != 0);
2618
2619  restart:
2620       /* restart */
2621       /* fill in the expiration times  */
2622       prefix->valid_lifetime_expires = now + prefix->adv_valid_lifetime_in_secs;
2623       prefix->pref_lifetime_expires = now + prefix->adv_pref_lifetime_in_secs;
2624           
2625       radv_info->initial_adverts_sent  = radv_info->initial_adverts_count -1;
2626       radv_info->next_multicast_time =  vlib_time_now (vm);    
2627       radv_info->last_multicast_time = vlib_time_now (vm);
2628       radv_info->last_radv_time = 0;    
2629     }
2630   return(error);
2631 }
2632
2633 clib_error_t *
2634 ip6_neighbor_cmd(vlib_main_t * vm, unformat_input_t * main_input, vlib_cli_command_t * cmd)
2635 {
2636   vnet_main_t * vnm = vnet_get_main();
2637   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2638   clib_error_t * error = 0;
2639   u8 is_no = 0;
2640   u8 suppress = 0,  managed = 0,  other = 0;
2641   u8 suppress_ll_option = 0,  send_unicast = 0,  cease= 0; 
2642   u8 use_lifetime = 0;
2643   u32 sw_if_index, ra_lifetime = 0, ra_initial_count = 0, ra_initial_interval = 0;
2644   u32 ra_max_interval = 0 , ra_min_interval = 0;
2645
2646   unformat_input_t _line_input, * line_input = &_line_input;
2647   vnet_sw_interface_t * sw_if0;
2648
2649   int add_radv_info = 1;
2650   __attribute__((unused)) ip6_radv_t * radv_info = 0;
2651   ip6_address_t ip6_addr;
2652   u32 addr_len;
2653  
2654
2655   /* Get a line of input. */
2656   if (! unformat_user (main_input, unformat_line_input, line_input))
2657     return 0;
2658
2659   /* get basic radv info for this interface */
2660   if(unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2661     {
2662
2663       if (unformat_user (line_input, 
2664                          unformat_vnet_sw_interface, vnm, &sw_if_index))
2665         {
2666           u32 ri;
2667           ethernet_interface_t * eth_if0 = 0;
2668           
2669           sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
2670           if(sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
2671             eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
2672           
2673           if(!eth_if0)
2674             {
2675               error = clib_error_return (0, "Interface must be of ethernet type");
2676               goto done;
2677             }
2678           
2679           /* look up the radv_t  information for this interface */
2680           vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2681           
2682           ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2683           
2684           if(ri != ~0)
2685             {
2686               radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
2687             }
2688           else
2689             {
2690               error = clib_error_return (0, "unknown interface %U'",
2691                                          format_unformat_error, line_input);
2692               goto done;
2693             }
2694         }
2695       else
2696         {
2697           error = clib_error_return (0, "invalid interface name %U'",
2698                                      format_unformat_error, line_input);
2699           goto done;
2700         }
2701     }
2702
2703   /* get the rest of the command */
2704   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2705     {
2706       if (unformat (line_input, "no"))
2707          is_no = 1;
2708       else if(unformat (line_input, "prefix %U/%d",
2709                         unformat_ip6_address, &ip6_addr,
2710                         &addr_len))
2711         {
2712           add_radv_info = 0;
2713           break;
2714         }
2715       else if (unformat (line_input, "ra-managed-config-flag"))
2716         {
2717           managed = 1;
2718           break;
2719         }
2720       else if (unformat (line_input, "ra-other-config-flag"))
2721         {
2722           other = 1;
2723           break;
2724         }
2725       else if (unformat (line_input, "ra-suppress") ||
2726                       unformat (line_input, "ra-surpress"))
2727         {
2728           suppress = 1;
2729           break;
2730         }
2731       else if (unformat (line_input, "ra-suppress-link-layer") ||
2732                       unformat (line_input, "ra-surpress-link-layer"))
2733         {
2734           suppress_ll_option = 1;
2735           break;
2736         }
2737       else if (unformat (line_input, "ra-send-unicast"))
2738         {
2739           send_unicast = 1;
2740           break;
2741         }
2742       else if (unformat (line_input, "ra-lifetime"))
2743         {
2744           if (!unformat (line_input, "%d", &ra_lifetime))
2745             return(error = unformat_parse_error (line_input));
2746           use_lifetime = 1;
2747           break;
2748         }  
2749       else if (unformat (line_input, "ra-initial"))
2750         {
2751           if (!unformat (line_input, "%d %d", &ra_initial_count, &ra_initial_interval))
2752             return(error = unformat_parse_error (line_input));
2753           break;
2754         }
2755       else if (unformat (line_input, "ra-interval"))
2756         {
2757           if (!unformat (line_input, "%d", &ra_max_interval))
2758             return(error = unformat_parse_error (line_input));
2759
2760           if (!unformat (line_input, "%d", &ra_min_interval))
2761             ra_min_interval = 0;
2762           break;
2763         }
2764       else if(unformat (line_input, "ra-cease"))
2765         {
2766           cease = 1;
2767           break;
2768         }
2769       else
2770         return(unformat_parse_error (line_input));
2771     }
2772
2773   if(add_radv_info)
2774     {
2775       ip6_neighbor_ra_config(vm,  sw_if_index, 
2776                              suppress, managed, other,
2777                              suppress_ll_option,  send_unicast,  cease, 
2778                              use_lifetime,  ra_lifetime,
2779                              ra_initial_count,  ra_initial_interval,  
2780                              ra_max_interval,  ra_min_interval,
2781                              is_no);
2782     }
2783   else
2784     {
2785       u32 valid_lifetime_in_secs =  0;
2786       u32 pref_lifetime_in_secs = 0;
2787       u8 use_prefix_default_values = 0;
2788       u8  no_advertise = 0;
2789       u8 off_link= 0;
2790       u8 no_autoconfig = 0;
2791       u8 no_onlink= 0;
2792
2793       /* get the rest of the command */
2794       while(unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2795         {
2796           if(unformat (line_input, "default"))
2797             {
2798               use_prefix_default_values = 1;
2799               break;
2800             }
2801           else if(unformat (line_input, "infinite"))
2802             {
2803               valid_lifetime_in_secs =  ~0;
2804               pref_lifetime_in_secs = ~0;
2805               break;
2806             }
2807           else if(unformat (line_input, "%d %d", &valid_lifetime_in_secs, 
2808                             &pref_lifetime_in_secs))
2809             break;
2810           else
2811             break;
2812         }
2813
2814
2815       /* get the rest of the command */
2816       while (!use_prefix_default_values &&
2817              unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2818         {
2819           if(unformat (line_input, "no-advertise"))
2820             no_advertise = 1;
2821           else if(unformat (line_input, "off-link"))
2822             off_link = 1;
2823           else if(unformat (line_input, "no-autoconfig"))
2824             no_autoconfig = 1;
2825           else if(unformat (line_input, "no-onlink"))
2826             no_onlink = 1;
2827           else
2828             return(unformat_parse_error (line_input));
2829         }
2830         
2831       ip6_neighbor_ra_prefix(vm, sw_if_index,  
2832                              &ip6_addr,  addr_len,
2833                              use_prefix_default_values,  
2834                              valid_lifetime_in_secs,
2835                              pref_lifetime_in_secs,
2836                              no_advertise,
2837                              off_link,
2838                              no_autoconfig,
2839                              no_onlink,
2840                              is_no);
2841     }
2842
2843   unformat_free (line_input);
2844   
2845  done:
2846   return error;
2847 }
2848
2849 static void
2850 ip6_print_addrs(vlib_main_t * vm,
2851                 u32 *addrs)
2852 {
2853   ip_lookup_main_t * lm = &ip6_main.lookup_main;
2854   u32 i;
2855
2856   for (i = 0; i < vec_len (addrs); i++)
2857     {
2858       ip_interface_address_t * a = pool_elt_at_index(lm->if_address_pool, addrs[i]);
2859       ip6_address_t * address = ip_interface_address_get_address (lm, a);
2860
2861       vlib_cli_output (vm, "\t\t%U/%d",
2862                        format_ip6_address, address,
2863                        a->address_length);
2864     }
2865 }
2866
2867 static clib_error_t *
2868 show_ip6_interface_cmd (vlib_main_t * vm,
2869                     unformat_input_t * input,
2870                     vlib_cli_command_t * cmd)
2871 {
2872   vnet_main_t * vnm = vnet_get_main();
2873   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2874   clib_error_t * error = 0;
2875   u32 sw_if_index;
2876
2877   sw_if_index = ~0;
2878
2879  if (unformat_user (input, 
2880                       unformat_vnet_sw_interface, vnm, &sw_if_index))
2881     {
2882       u32 ri;
2883       
2884       /* look up the radv_t  information for this interface */
2885       vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2886       
2887       ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2888       
2889       if(ri != ~0)
2890         {
2891           ip_lookup_main_t * lm = &ip6_main.lookup_main;
2892           ip6_radv_t * radv_info;
2893           radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
2894
2895           vlib_cli_output (vm, "%U is admin %s\n", format_vnet_sw_interface_name, vnm, 
2896                            vnet_get_sw_interface (vnm, sw_if_index),
2897                            (vnet_sw_interface_is_admin_up (vnm, sw_if_index) ? "up" : "down"));
2898       
2899           u32 ai;
2900           u32 *link_scope = 0, *global_scope = 0;
2901           u32 *local_scope = 0, *unknown_scope = 0;
2902           ip_interface_address_t * a;
2903
2904           vec_validate_init_empty (lm->if_address_pool_index_by_sw_if_index, sw_if_index, ~0);
2905           ai = lm->if_address_pool_index_by_sw_if_index[sw_if_index];
2906
2907           while (ai != (u32)~0)
2908             {
2909               a = pool_elt_at_index(lm->if_address_pool, ai);
2910               ip6_address_t * address = ip_interface_address_get_address (lm, a);
2911
2912               if (ip6_address_is_link_local_unicast (address))
2913                 vec_add1 (link_scope, ai);
2914               else if(ip6_address_is_global_unicast (address))
2915                 vec_add1 (global_scope, ai);
2916               else if(ip6_address_is_local_unicast (address))
2917                 vec_add1 (local_scope, ai);
2918               else
2919                 vec_add1 (unknown_scope, ai);
2920
2921               ai = a->next_this_sw_interface;
2922             }
2923
2924           if (vec_len (link_scope))
2925             {
2926               vlib_cli_output (vm, "\tLink-local address(es):\n");
2927               ip6_print_addrs (vm, link_scope);
2928               vec_free (link_scope);
2929             }
2930
2931           if (vec_len (local_scope))
2932             {
2933               vlib_cli_output (vm, "\tLocal unicast address(es):\n");
2934               ip6_print_addrs (vm, local_scope);
2935               vec_free (local_scope);
2936             }
2937
2938           if (vec_len (global_scope))
2939             {
2940               vlib_cli_output (vm, "\tGlobal unicast address(es):\n");
2941               ip6_print_addrs (vm, global_scope);
2942               vec_free (global_scope);
2943             }
2944
2945           if (vec_len (unknown_scope))
2946             {
2947               vlib_cli_output (vm, "\tOther-scope address(es):\n");
2948               ip6_print_addrs (vm, unknown_scope);
2949               vec_free (unknown_scope);
2950             }
2951
2952           vlib_cli_output (vm, "\tJoined group address(es):\n");
2953           ip6_mldp_group_t *m;
2954           pool_foreach (m, radv_info->mldp_group_pool, ({
2955                 vlib_cli_output (vm, "\t\t%U\n", format_ip6_address, &m->mcast_address);
2956               }));
2957
2958           vlib_cli_output (vm, "\tAdvertised Prefixes:\n");
2959           ip6_radv_prefix_t * p;
2960           pool_foreach (p, radv_info->adv_prefixes_pool, ({
2961                 vlib_cli_output (vm, "\t\tprefix %U,  length %d\n", 
2962                                  format_ip6_address, &p->prefix, p->prefix_len);
2963               }));
2964
2965           vlib_cli_output (vm, "\tMTU is %d\n",  radv_info->adv_link_mtu);
2966           vlib_cli_output (vm, "\tICMP error messages are unlimited\n");
2967           vlib_cli_output (vm, "\tICMP redirects are disabled\n");
2968           vlib_cli_output (vm, "\tICMP unreachables are not sent\n");
2969           vlib_cli_output (vm, "\tND DAD is disabled\n");
2970           //vlib_cli_output (vm, "\tND reachable time is %d milliseconds\n",);
2971           vlib_cli_output (vm, "\tND advertised reachable time is %d\n",
2972                            radv_info->adv_neighbor_reachable_time_in_msec);
2973           vlib_cli_output (vm, "\tND advertised retransmit interval is %d (msec)\n",
2974                            radv_info->adv_time_in_msec_between_retransmitted_neighbor_solicitations);
2975
2976           u32 ra_interval = radv_info->max_radv_interval;
2977           u32 ra_interval_min = radv_info->min_radv_interval;
2978           vlib_cli_output (vm, "\tND router advertisements are sent every %d seconds (min interval is %d)\n", 
2979                            ra_interval, ra_interval_min);
2980           vlib_cli_output (vm, "\tND router advertisements live for %d seconds\n",
2981                            radv_info->adv_router_lifetime_in_sec);
2982           vlib_cli_output (vm, "\tHosts %s stateless autoconfig for addresses\n",
2983                              (radv_info->adv_managed_flag) ? "use" :" don't use");
2984           vlib_cli_output (vm, "\tND router advertisements sent %d\n",  radv_info->n_advertisements_sent);
2985           vlib_cli_output (vm, "\tND router solicitations received %d\n",  radv_info->n_solicitations_rcvd);
2986           vlib_cli_output (vm, "\tND router solicitations dropped %d\n",  radv_info->n_solicitations_dropped);
2987         }
2988       else
2989         {
2990           error = clib_error_return (0, "IPv6 not enabled on interface",
2991                                      format_unformat_error, input);
2992
2993         }
2994     }
2995   return error;
2996 }
2997
2998 /*?
2999  * This command is used to display various IPv6 attributes on a given
3000  * interface.
3001  *
3002  * @cliexpar
3003  * Example of how to display IPv6 settings:
3004  * @cliexstart{show ip6 interface GigabitEthernet2/0/0}
3005  * GigabitEthernet2/0/0 is admin up
3006  *         Link-local address(es):
3007  *                 fe80::ab8/64
3008  *         Joined group address(es):
3009  *                 ff02::1
3010  *                 ff02::2
3011  *                 ff02::16
3012  *                 ff02::1:ff00:ab8
3013  *         Advertised Prefixes:
3014  *                 prefix fe80::fe:28ff:fe9c:75b3,  length 64
3015  *         MTU is 1500
3016  *         ICMP error messages are unlimited
3017  *         ICMP redirects are disabled
3018  *         ICMP unreachables are not sent
3019  *         ND DAD is disabled
3020  *         ND advertised reachable time is 0
3021  *         ND advertised retransmit interval is 0 (msec)
3022  *         ND router advertisements are sent every 200 seconds (min interval is 150)
3023  *         ND router advertisements live for 600 seconds
3024  *         Hosts use stateless autoconfig for addresses
3025  *         ND router advertisements sent 19336
3026  *         ND router solicitations received 0
3027  *         ND router solicitations dropped 0
3028  * @cliexend
3029  * Example of output if IPv6 is not enabled on the interface:
3030  * @cliexstart{show ip6 interface GigabitEthernet2/0/0}
3031  * show ip6 interface: IPv6 not enabled on interface
3032  * @cliexend
3033 ?*/
3034 /* *INDENT-OFF* */
3035 VLIB_CLI_COMMAND (show_ip6_interface_command, static) = {
3036   .path = "show ip6 interface",
3037   .function = show_ip6_interface_cmd,
3038   .short_help = "show ip6 interface <interface>",
3039 };
3040 /* *INDENT-ON* */
3041
3042 clib_error_t *
3043 disable_ip6_interface(vlib_main_t * vm,
3044                       u32 sw_if_index)
3045 {
3046   clib_error_t * error = 0;
3047   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3048   u32 ri;
3049
3050   /* look up the radv_t  information for this interface */
3051   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);      
3052   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3053   
3054   /* if not created - do nothing */
3055   if(ri != ~0)
3056     {
3057       vnet_main_t * vnm = vnet_get_main();
3058       ip6_radv_t * radv_info;
3059   
3060       radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
3061
3062       /* check radv_info ref count for other ip6 addresses on this interface */
3063       if(radv_info->ref_count == 0 )
3064         {
3065           /* essentially "disables" ipv6 on this interface */
3066           error = ip6_add_del_interface_address (vm, sw_if_index,
3067                                                  &radv_info->link_local_address, 
3068                                                  radv_info->link_local_prefix_len,
3069                                                  1 /* is_del */);
3070
3071           ip6_neighbor_sw_interface_add_del (vnm, sw_if_index,  0/* is_add */);
3072         }
3073     }
3074   return error;
3075 }
3076
3077 int
3078 ip6_interface_enabled(vlib_main_t * vm,
3079                       u32 sw_if_index)
3080 {
3081     ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3082     u32 ri = ~0;
3083
3084     /* look up the radv_t  information for this interface */
3085     vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
3086
3087     ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3088
3089     return ri != ~0;
3090 }
3091
3092 clib_error_t * 
3093 enable_ip6_interface(vlib_main_t * vm,
3094                     u32 sw_if_index)
3095 {
3096   clib_error_t * error = 0;
3097   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3098   u32 ri;
3099   int is_add = 1;
3100
3101   /* look up the radv_t  information for this interface */
3102   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
3103       
3104   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3105   
3106   /* if not created yet */
3107   if(ri == ~0)
3108     {
3109       vnet_main_t * vnm = vnet_get_main();
3110       vnet_sw_interface_t * sw_if0;
3111  
3112       sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
3113       if(sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
3114         {
3115           ethernet_interface_t * eth_if0;
3116
3117           eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);         
3118           if(eth_if0)
3119             {
3120               /* create radv_info. for this interface.  This holds all the info needed for router adverts */
3121               ri = ip6_neighbor_sw_interface_add_del (vnm, sw_if_index, is_add);
3122
3123               if(ri != ~0)
3124                 {
3125                   ip6_radv_t * radv_info;
3126                   ip6_address_t link_local_address;
3127
3128                   radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
3129
3130                   ip6_link_local_address_from_ethernet_mac_address (&link_local_address,
3131                                                                     eth_if0->address);
3132
3133                   sw_if0 = vnet_get_sw_interface (vnm, sw_if_index);
3134                   if(sw_if0->type == VNET_SW_INTERFACE_TYPE_SUB)
3135                     {
3136                       /* make up  an interface id */
3137                       md5_context_t m;
3138                       u8 digest[16];
3139                       
3140                       link_local_address.as_u64[0] = radv_info->randomizer;
3141                       
3142                       md5_init (&m);
3143                       md5_add (&m, &link_local_address, 16);
3144                       md5_finish (&m,  digest);
3145                       
3146                       clib_memcpy(&link_local_address, digest, 16);
3147                       
3148                       radv_info->randomizer = link_local_address.as_u64[0];
3149                       
3150                       link_local_address.as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL);
3151                       /* clear u bit */
3152                       link_local_address.as_u8[8] &= 0xfd;
3153                     }
3154                   
3155                   /* essentially "enables" ipv6 on this interface */
3156                   error = ip6_add_del_interface_address (vm, sw_if_index,
3157                                                          &link_local_address,
3158                                                          128 /* address width */,
3159                                                          0 /* is_del */);
3160                   
3161                   if(error)
3162                       ip6_neighbor_sw_interface_add_del (vnm, sw_if_index, !is_add);
3163                   else
3164                     {
3165                       radv_info->link_local_address =  link_local_address;
3166                       radv_info->link_local_prefix_len  = 64;
3167                     }
3168                 }
3169             } 
3170         }
3171     }
3172   return error;
3173 }
3174
3175 static clib_error_t *
3176 enable_ip6_interface_cmd (vlib_main_t * vm,
3177                     unformat_input_t * input,
3178                     vlib_cli_command_t * cmd)
3179 {
3180   vnet_main_t * vnm = vnet_get_main();
3181   clib_error_t * error = 0;
3182   u32 sw_if_index;
3183
3184   sw_if_index = ~0;
3185
3186  if (unformat_user (input, 
3187                       unformat_vnet_sw_interface, vnm, &sw_if_index))
3188     {
3189       enable_ip6_interface(vm, sw_if_index);
3190     }
3191  else
3192    {
3193      error = clib_error_return (0, "unknown interface\n'",
3194                                 format_unformat_error, input);
3195      
3196    }
3197   return error;
3198 }
3199
3200 /*?
3201  * This command is used to enable IPv6 on a given interface.
3202  *
3203  * @cliexpar
3204  * Example of how enable IPv6 on a given interface:
3205  * @cliexcmd{enable ip6 interface GigabitEthernet2/0/0}
3206 ?*/
3207 /* *INDENT-OFF* */
3208 VLIB_CLI_COMMAND (enable_ip6_interface_command, static) = {
3209   .path = "enable ip6 interface",
3210   .function = enable_ip6_interface_cmd,
3211   .short_help = "enable ip6 interface <interface>",
3212 };
3213 /* *INDENT-ON* */
3214
3215 static clib_error_t *
3216 disable_ip6_interface_cmd (vlib_main_t * vm,
3217                     unformat_input_t * input,
3218                     vlib_cli_command_t * cmd)
3219 {
3220   vnet_main_t * vnm = vnet_get_main();
3221   clib_error_t * error = 0;
3222   u32 sw_if_index;
3223
3224   sw_if_index = ~0;
3225
3226  if (unformat_user (input, 
3227                       unformat_vnet_sw_interface, vnm, &sw_if_index))
3228     {
3229       error = disable_ip6_interface(vm, sw_if_index);
3230     }
3231  else
3232    {
3233      error = clib_error_return (0, "unknown interface\n'",
3234                                 format_unformat_error, input);
3235      
3236    }
3237   return error;
3238 }
3239
3240 /*?
3241  * This command is used to disable IPv6 on a given interface.
3242  *
3243  * @cliexpar
3244  * Example of how disable IPv6 on a given interface:
3245  * @cliexcmd{disable ip6 interface GigabitEthernet2/0/0}
3246 ?*/
3247 /* *INDENT-OFF* */
3248 VLIB_CLI_COMMAND (disable_ip6_interface_command, static) = {
3249   .path = "disable ip6 interface",
3250   .function = disable_ip6_interface_cmd,
3251   .short_help = "disable ip6 interface <interface>",
3252 };
3253 /* *INDENT-ON* */
3254
3255 /*?
3256  * This command is used to configure the neighbor discovery
3257  * parameters on a given interface. Use the '<em>show ip6 interface</em>'
3258  * command to display some of the current neighbor discovery parameters
3259  * on a given interface. This command has three formats:
3260  *
3261  *
3262  * <b>Format 1 - Router Advertisement Options:</b> (Only one can be entered in a single command)
3263  *
3264  * '<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>'
3265  *
3266  * Where:
3267  *
3268  * <em>[no] ra-managed-config-flag</em> - Advertises in ICMPv6
3269  * router-advertisement messages to use stateful address
3270  * auto-configuration to obtain address information (sets the M-bit).
3271  * Default is the M-bit is not set and the '<em>no</em>' option
3272  * returns it to this default state.
3273  *
3274  * <em>[no] ra-other-config-flag</em> - Indicates in ICMPv6
3275  * router-advertisement messages that hosts use stateful auto
3276  * configuration to obtain nonaddress related information (sets
3277  * the O-bit). Default is the O-bit is not set and the '<em>no</em>'
3278  * option returns it to this default state.
3279  *
3280  * <em>[no] ra-suppress</em> - Disables sending ICMPv6 router-advertisement
3281  * messages. The '<em>no</em>' option implies to enable sending ICMPv6
3282  * router-advertisement messages.
3283  *
3284  * <em>[no] ra-suppress-link-layer</em> - Indicates not to include the
3285  * optional source link-layer address in the ICMPv6 router-advertisement
3286  * messages. Default is to include the optional source link-layer address
3287  * and the '<em>no</em>' option returns it to this default state.
3288  *
3289  * <em>[no] ra-send-unicast</em> - Use the source address of the
3290  * router-solicitation message if availiable. The default is to use
3291  * multicast address of all nodes, and the '<em>no</em>' option returns
3292  * it to this default state.
3293  *
3294  * <em>[no] ra-lifetime <lifetime></em> - Advertises the lifetime of a
3295  * default router in ICMPv6 router-advertisement messages. The range is
3296  * from 0 to 9000 seconds. '<em><lifetime></em>' must be greater than
3297  * '<em><max-interval></em>'. The default value is 600 seconds and the
3298  * '<em>no</em>' option returns it to this default value.
3299  *
3300  * <em>[no] ra-initial <cnt> <interval></em> - Number of initial ICMPv6
3301  * router-advertisement messages sent and the interval between each
3302  * message. Range for count is 1 - 3 and default is 3. Range for interval
3303  * is 1 to 16 seconds, and default is 16 seconds. The '<em>no</em>' option
3304  * returns both to their default value.
3305  *
3306  * <em>[no] ra-interval <max-interval> [<min-interval>]</em> - Configures the
3307  * interval between sending ICMPv6 router-advertisement messages. The
3308  * range for max-interval is from 4 to 200 seconds. min-interval can not
3309  * be more than 75% of max-interval. If not set, min-interval will be
3310  * set to 75% of max-interval. The range for min-interval is from 3 to
3311  * 150 seconds.  The '<em>no</em>' option returns both to their default
3312  * value.
3313  *
3314  * <em>[no] ra-cease</em> - Cease sending ICMPv6 router-advertisement messages.
3315  * The '<em>no</em>' options implies to start (or restart) sending
3316  * ICMPv6 router-advertisement messages.
3317  *
3318  *
3319  * <b>Format 2 - Prefix Options:</b>
3320  *
3321  * '<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>'
3322  *
3323  * Where:
3324  *
3325  * <em>no</em> - All additional flags are ignored and the prefix is deleted.
3326  *
3327  * <em><valid-lifetime> <pref-lifetime></em> - '<em><valid-lifetime></em>' is the
3328  * length of time in seconds during what the prefix is valid for the purpose of
3329  * on-link determination. Range is 7203 to 2592000 seconds and default is 2592000
3330  * seconds (30 days). '<em><pref-lifetime></em>' is the prefered-lifetime and is the
3331  * length of time in seconds during what addresses generated from the prefix remain
3332  * preferred. Range is 0 to 604800 seconds and default is 604800 seconds (7 days).
3333  *
3334  * <em>infinite</em> - Both '<em><valid-lifetime></em>' and '<em><<pref-lifetime></em>'
3335  * are inifinte, no timeout.
3336  *
3337  * <em>no-advertise</em> - Do not send full router address in prefix
3338  * advertisement. Default is to advertise (i.e. - This flag is off by default).
3339  *
3340  * <em>off-link</em> - Prefix is off-link, clear L-bit in packet. Default is on-link
3341  * (i.e. - This flag is off and L-bit in packet is set by default and this prefix can
3342  * be used for on-link determination). '<em>no-onlink</em>' also controls the L-bit.
3343  *
3344  * <em>no-autoconfig</em> - Do not use prefix for autoconfiguration, clear A-bit in packet.
3345  * Default is autoconfig (i.e. - This flag is off and A-bit in packet is set by default.
3346  *
3347  * <em>no-onlink</em> - Do not use prefix for onlink determination, clear L-bit in packet.
3348  * Default is on-link (i.e. - This flag is off and L-bit in packet is set by default and
3349  * this prefix can be used for on-link determination). '<em>off-link</em>' also controls
3350  * the L-bit.
3351  *
3352  *
3353  * <b>Format 3: - Default of Prefix:</b>
3354  *
3355  * '<em><b>ip6 nd <interface> [no] prefix <ip6-address>/<width> default</b></em>'
3356  *
3357  * When a new prefix is added (or existing one is being overwritten) <em>default</em>
3358  * uses default values for the prefix. If <em>no</em> is used, the <em>default</em>
3359  * is ignored and the prefix is deleted.
3360  *
3361  *
3362  * @cliexpar
3363  * Example of how set a router advertisement option:
3364  * @cliexcmd{ip6 nd GigabitEthernet2/0/0 ra-interval 100 20}
3365  * Example of how to add a prefix:
3366  * @cliexcmd{ip6 nd GigabitEthernet2/0/0 prefix fe80::fe:28ff:fe9c:75b3/64 infinite no-advertise}
3367  * Example of how to delete a prefix:
3368  * @cliexcmd{ip6 nd GigabitEthernet2/0/0 no prefix fe80::fe:28ff:fe9c:75b3/64}
3369 ?*/
3370 /* *INDENT-OFF* */
3371 VLIB_CLI_COMMAND (ip6_nd_command, static) = {
3372   .path = "ip6 nd",
3373   .short_help = "ip6 nd <interface> ...",
3374   .function = ip6_neighbor_cmd,
3375 };
3376 /* *INDENT-ON* */
3377
3378 clib_error_t *
3379 set_ip6_link_local_address(vlib_main_t * vm,
3380                            u32 sw_if_index,
3381                            ip6_address_t *address,
3382                            u8 address_length)
3383 {
3384   clib_error_t * error = 0;
3385   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3386   u32 ri;
3387   ip6_radv_t * radv_info;
3388   vnet_main_t * vnm = vnet_get_main();
3389
3390   if( !ip6_address_is_link_local_unicast (address))
3391     {
3392       vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_LINK_LOCAL;
3393       return(error = clib_error_return (0, "address not link-local",
3394                                         format_unformat_error));
3395     }
3396
3397   /* call enable ipv6  */
3398   enable_ip6_interface(vm, sw_if_index);
3399           
3400   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3401          
3402   if(ri != ~0)
3403     {
3404       radv_info = pool_elt_at_index (nm->if_radv_pool,  ri);
3405
3406       /* save if link local address (overwrite default) */
3407    
3408       /* delete the old one */
3409       error = ip6_add_del_interface_address (vm, sw_if_index,
3410                                              &radv_info->link_local_address,
3411                                              radv_info->link_local_prefix_len  /* address width */,
3412                                              1 /* is_del */);
3413       
3414       if(!error)
3415         {
3416           /* add the new one */
3417           error = ip6_add_del_interface_address (vm, sw_if_index,
3418                                                  address ,
3419                                                  address_length  /* address width */,
3420                                                  0/* is_del */);
3421           
3422           if(!error)
3423             {
3424               radv_info->link_local_address = *address;
3425               radv_info->link_local_prefix_len  = address_length;
3426             }
3427         }
3428     }
3429   else
3430     {
3431       vnm->api_errno = VNET_API_ERROR_IP6_NOT_ENABLED;
3432       error = clib_error_return (0, "ip6 not enabled for interface",
3433                                  format_unformat_error);
3434     }
3435   return error;
3436 }
3437   
3438 clib_error_t *
3439 set_ip6_link_local_address_cmd (vlib_main_t * vm,
3440                                 unformat_input_t * input,
3441                                 vlib_cli_command_t * cmd)
3442 {
3443   vnet_main_t * vnm = vnet_get_main();
3444   clib_error_t * error = 0;
3445   u32 sw_if_index;
3446   ip6_address_t ip6_addr;
3447   u32 addr_len = 0;
3448  
3449   if (unformat_user (input, 
3450                      unformat_vnet_sw_interface, vnm, &sw_if_index))
3451     {
3452       /* get the rest of the command */
3453       while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3454         {
3455           if(unformat (input, "%U/%d",
3456                        unformat_ip6_address, &ip6_addr,
3457                        &addr_len))
3458             break;
3459           else
3460             return(unformat_parse_error (input));
3461         }
3462     }
3463   error = set_ip6_link_local_address(vm,
3464                                      sw_if_index,
3465                                      &ip6_addr,
3466                                      addr_len);
3467   return error;
3468 }
3469
3470 /*?
3471  * This command is used to assign an IPv6 Link-local address to an
3472  * interface. This command will enable IPv6 on an interface if it
3473  * is not already enabled. Use the '<em>show ip6 interface</em>' command
3474  * to display the assigned Link-local address.
3475  *
3476  * @cliexpar
3477  * Example of how to assign an IPv6 Link-local address to an interface:
3478  * @cliexcmd{set ip6 link-local address GigabitEthernet2/0/0 FE80::AB8/64}
3479 ?*/
3480 /* *INDENT-OFF* */
3481 VLIB_CLI_COMMAND (set_ip6_link_local_address_command, static) = {
3482   .path = "set ip6 link-local address",
3483   .short_help = "set ip6 link-local address <interface> <ip6-address>/<width>",
3484   .function = set_ip6_link_local_address_cmd,
3485 };
3486 /* *INDENT-ON* */
3487
3488 /* callback when an interface address is added or deleted */
3489 static void
3490 ip6_neighbor_add_del_interface_address (ip6_main_t * im,
3491                                         uword opaque,
3492                                         u32 sw_if_index,
3493                                         ip6_address_t * address,
3494                                         u32 address_length,
3495                                         u32 if_address_index,
3496                                         u32 is_delete)
3497 {
3498   vnet_main_t * vnm = vnet_get_main();
3499   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3500   u32 ri;
3501   vlib_main_t * vm = vnm->vlib_main;
3502   ip6_radv_t * radv_info;
3503   ip6_address_t a;
3504   ip6_mldp_group_t  *mcast_group_info;
3505
3506   /* create solicited node multicast address for this interface adddress */
3507   ip6_set_solicited_node_multicast_address (&a, 0);
3508  
3509   a.as_u8[0xd] = address->as_u8[0xd];
3510   a.as_u8[0xe] = address->as_u8[0xe];
3511   a.as_u8[0xf] = address->as_u8[0xf];
3512   
3513   if(!is_delete)
3514     {
3515       /* try to  create radv_info - does nothing if ipv6 already enabled */
3516       enable_ip6_interface(vm, sw_if_index);
3517
3518       /* look up the radv_t  information for this interface */
3519       vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
3520       ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3521       if(ri != ~0)
3522         {
3523           /* get radv_info */
3524           radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3525
3526           /* add address */
3527           if( !ip6_address_is_link_local_unicast (address))
3528             radv_info->ref_count++;
3529
3530           /* lookup  prefix info for this  address on this interface */
3531           uword * p = mhash_get (&radv_info->address_to_mldp_index,  &a);
3532           mcast_group_info = p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0;
3533
3534           /* add -solicted node multicast address  */
3535           if(!mcast_group_info)
3536             {
3537               /* add */
3538               u32 mi;
3539               pool_get (radv_info->mldp_group_pool, mcast_group_info);
3540               
3541               mi = mcast_group_info - radv_info->mldp_group_pool;
3542               mhash_set (&radv_info->address_to_mldp_index,  &a,  mi, /* old_value */ 0);
3543               
3544               mcast_group_info->type = 4;
3545               mcast_group_info->mcast_source_address_pool = 0;
3546               mcast_group_info->num_sources = 0;
3547               clib_memcpy(&mcast_group_info->mcast_address, &a, sizeof(ip6_address_t));
3548             } 
3549         }
3550     }
3551   else
3552     {
3553
3554       /* delete */
3555       /* look up the radv_t  information for this interface */
3556       vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
3557       ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3558       if(ri != ~0)
3559         {
3560           /* get radv_info */
3561           radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3562
3563           /* lookup  prefix info for this  address on this interface */
3564           uword * p = mhash_get (&radv_info->address_to_mldp_index,  &a);
3565           mcast_group_info = p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0;
3566           
3567           if(mcast_group_info)
3568             {
3569               mhash_unset (&radv_info->address_to_mldp_index, &a,/* old_value */ 0);
3570               pool_put (radv_info->mldp_group_pool, mcast_group_info);
3571             }
3572
3573           /* if interface up send MLDP "report" */
3574           radv_info->all_routers_mcast = 0;
3575
3576           /* add address */
3577           if( !ip6_address_is_link_local_unicast (address))
3578             radv_info->ref_count--;
3579         }
3580     }
3581 }
3582
3583 clib_error_t *ip6_set_neighbor_limit (u32 neighbor_limit)
3584 {
3585   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3586
3587   nm->limit_neighbor_cache_size = neighbor_limit;
3588   return 0;
3589 }
3590
3591 static clib_error_t * ip6_neighbor_init (vlib_main_t * vm)
3592 {
3593   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3594   ip6_main_t * im = &ip6_main;
3595  
3596   mhash_init (&nm->neighbor_index_by_key,
3597               /* value size */ sizeof (uword),
3598               /* key size */ sizeof (ip6_neighbor_key_t));
3599
3600   icmp6_register_type (vm, ICMP6_neighbor_solicitation, ip6_icmp_neighbor_solicitation_node.index);
3601   icmp6_register_type (vm, ICMP6_neighbor_advertisement, ip6_icmp_neighbor_advertisement_node.index);
3602   icmp6_register_type (vm, ICMP6_router_solicitation, ip6_icmp_router_solicitation_node.index);
3603   icmp6_register_type (vm, ICMP6_router_advertisement, ip6_icmp_router_advertisement_node.index);
3604
3605   /* handler node for ip6 neighbor discovery events and timers */
3606   vlib_register_node (vm, &ip6_icmp_neighbor_discovery_event_node);
3607
3608   /* add call backs */
3609   ip6_add_del_interface_address_callback_t cb; 
3610   memset(&cb, 0x0, sizeof(ip6_add_del_interface_address_callback_t));
3611   
3612   /* when an interface address changes... */
3613   cb.function = ip6_neighbor_add_del_interface_address;
3614   cb.function_opaque = 0;
3615   vec_add1 (im->add_del_interface_address_callbacks, cb);
3616
3617   mhash_init (&nm->pending_resolutions_by_address,
3618               /* value size */ sizeof (uword),
3619               /* key size */ sizeof (ip6_address_t));
3620
3621   mhash_init (&nm->mac_changes_by_address,
3622               /* value size */ sizeof (uword),
3623               /* key size */ sizeof (ip6_address_t));
3624
3625   /* default, configurable */
3626   nm->limit_neighbor_cache_size = 50000;
3627
3628 #if 0
3629   /* $$$$ Hack fix for today */
3630   vec_validate_init_empty 
3631       (im->discover_neighbor_next_index_by_hw_if_index, 32, 0 /* drop */);
3632 #endif
3633
3634   return 0;
3635 }
3636
3637 VLIB_INIT_FUNCTION (ip6_neighbor_init);
3638
3639
3640 void vnet_register_ip6_neighbor_resolution_event (vnet_main_t * vnm, 
3641                                                   void * address_arg,
3642                                                   uword node_index,
3643                                                   uword type_opaque,
3644                                                   uword data)
3645 {
3646   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3647   ip6_address_t * address = address_arg;
3648   uword * p;
3649   pending_resolution_t * pr;
3650   
3651   pool_get (nm->pending_resolutions, pr);
3652
3653   pr->next_index = ~0;
3654   pr->node_index = node_index;
3655   pr->type_opaque = type_opaque;
3656   pr->data = data;
3657
3658   p = mhash_get (&nm->pending_resolutions_by_address, address);
3659   if (p)
3660     {
3661       /* Insert new resolution at the head of the list */
3662       pr->next_index = p[0];
3663       mhash_unset (&nm->pending_resolutions_by_address, address, 0);
3664     }
3665   
3666   mhash_set (&nm->pending_resolutions_by_address, address, 
3667              pr - nm->pending_resolutions, 0 /* old value */);
3668 }
3669
3670 int vnet_add_del_ip6_nd_change_event (vnet_main_t * vnm, 
3671                                       void * data_callback,
3672                                       u32 pid,
3673                                       void * address_arg,
3674                                       uword node_index,
3675                                       uword type_opaque,
3676                                       uword data, 
3677                                       int is_add)
3678 {
3679   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3680   ip6_address_t * address = address_arg;
3681   uword * p;
3682   pending_resolution_t * mc;
3683   void (*fp)(u32, u8 *) = data_callback;
3684   
3685   if (is_add)
3686     {
3687       pool_get (nm->mac_changes, mc);
3688
3689       mc->next_index = ~0;
3690       mc->node_index = node_index;
3691       mc->type_opaque = type_opaque;
3692       mc->data = data;
3693       mc->data_callback = data_callback;
3694       mc->pid = pid;
3695       
3696       p = mhash_get (&nm->mac_changes_by_address, address);
3697       if (p)
3698         {
3699           /* Insert new resolution at the head of the list */
3700           mc->next_index = p[0];
3701           mhash_unset (&nm->mac_changes_by_address, address, 0);
3702         }
3703       
3704       mhash_set (&nm->mac_changes_by_address, address, 
3705                  mc - nm->mac_changes, 0);
3706       return 0;
3707     }
3708   else
3709     {
3710       u32 index;
3711       pending_resolution_t * mc_last = 0;
3712
3713       p = mhash_get (&nm->mac_changes_by_address, address);
3714       if (p == 0)
3715         return VNET_API_ERROR_NO_SUCH_ENTRY;
3716
3717       index = p[0];
3718
3719       while (index != (u32)~0)
3720         {
3721           mc = pool_elt_at_index (nm->mac_changes, index);
3722           if (mc->node_index == node_index &&
3723               mc->type_opaque == type_opaque &&
3724               mc->pid == pid)
3725             {
3726               /* Clients may need to clean up pool entries, too */
3727               if (fp)
3728                 (*fp)(mc->data, 0 /* no new mac addrs */);
3729               if (index == p[0])
3730                 {
3731                   mhash_unset (&nm->mac_changes_by_address, address, 0);
3732                   if (mc->next_index != ~0)
3733                     mhash_set (&nm->mac_changes_by_address, address,
3734                                mc->next_index, 0);
3735                   pool_put (nm->mac_changes, mc);
3736                   return 0;
3737                 }
3738               else
3739                 {
3740                   ASSERT(mc_last);
3741                   mc_last->next_index = mc->next_index;
3742                   pool_put (nm->mac_changes, mc);
3743                   return 0;
3744                 }
3745             }
3746           mc_last = mc;
3747           index = mc->next_index;
3748         }
3749       
3750       return VNET_API_ERROR_NO_SUCH_ENTRY;
3751     }
3752 }
3753
3754 int vnet_ip6_nd_term (vlib_main_t * vm,
3755                       vlib_node_runtime_t * node,
3756                       vlib_buffer_t * p0,
3757                       ethernet_header_t * eth,
3758                       ip6_header_t * ip,
3759                       u32 sw_if_index,
3760                       u16 bd_index,
3761                       u8 shg)
3762 {
3763   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3764   icmp6_neighbor_solicitation_or_advertisement_header_t * ndh;
3765   pending_resolution_t * mc;
3766   uword *p;
3767
3768   ndh = ip6_next_header (ip);
3769   if (ndh->icmp.type != ICMP6_neighbor_solicitation &&
3770       ndh->icmp.type != ICMP6_neighbor_advertisement)
3771       return 0;
3772
3773   if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
3774                      (p0->flags & VLIB_BUFFER_IS_TRACED)))
3775     {
3776       u8 *t0 = vlib_add_trace (vm, node, p0,
3777                                sizeof (icmp6_input_trace_t));
3778       clib_memcpy (t0, ip, sizeof (icmp6_input_trace_t));
3779     }
3780
3781   /* Check if anyone want ND events for L2 BDs */
3782   p = mhash_get (&nm->mac_changes_by_address, &ip6a_zero);
3783   if (p && shg == 0 && /* Only SHG 0 interface which is more likely local */ 
3784       !ip6_address_is_link_local_unicast (&ip->src_address))
3785     { 
3786       u32 next_index = p[0];
3787       while (next_index != (u32)~0)
3788         {
3789           int (*fp)(u32, u8 *, u32, ip6_address_t *);
3790           int rv = 1;
3791           mc = pool_elt_at_index (nm->mac_changes, next_index);
3792           fp = mc->data_callback;
3793           /* Call the callback, return 1 to suppress dup events */
3794           if (fp) rv = (*fp)(mc->data, 
3795                              eth->src_address,
3796                              sw_if_index, 
3797                              &ip->src_address);
3798           /* Signal the resolver process */
3799           if (rv == 0)
3800              vlib_process_signal_event (vm, mc->node_index,
3801                                         mc->type_opaque, 
3802                                         mc->data);
3803           next_index = mc->next_index;
3804         }
3805     }
3806
3807   /* Check if MAC entry exsist for solicited target IP */
3808   if (ndh->icmp.type == ICMP6_neighbor_solicitation)
3809     {
3810       icmp6_neighbor_discovery_ethernet_link_layer_address_option_t * opt;
3811       l2_bridge_domain_t *bd_config;
3812       u8 * macp;
3813
3814       opt = (void *) (ndh + 1);
3815       if ((opt->header.type != 
3816            ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address) ||
3817           (opt->header.n_data_u64s != 1))
3818           return 0; /* source link layer address option not present */
3819           
3820       bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
3821       macp = (u8 *) hash_get_mem (bd_config->mac_by_ip6, &ndh->target_address);
3822       if (macp)
3823         { /* found ip-mac entry, generate eighbor advertisement response */
3824           int bogus_length;
3825           vlib_node_runtime_t * error_node = 
3826               vlib_node_get_runtime (vm, ip6_icmp_input_node.index);
3827           ip->dst_address = ip->src_address;
3828           ip->src_address = ndh->target_address;
3829           ip->hop_limit = 255;
3830           opt->header.type =
3831               ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
3832           clib_memcpy (opt->ethernet_address, macp, 6);
3833           ndh->icmp.type = ICMP6_neighbor_advertisement;
3834           ndh->advertisement_flags = clib_host_to_net_u32
3835               (ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED |
3836                ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE);
3837           ndh->icmp.checksum = 0;
3838           ndh->icmp.checksum = ip6_tcp_udp_icmp_compute_checksum(vm, p0, ip,
3839                                                                  &bogus_length);
3840           clib_memcpy(eth->dst_address, eth->src_address, 6);
3841           clib_memcpy(eth->src_address, macp, 6);
3842           vlib_error_count (vm, error_node->node_index, 
3843                             ICMP6_ERROR_NEIGHBOR_ADVERTISEMENTS_TX, 1);
3844           return 1;
3845         }
3846     }
3847
3848   return 0;
3849
3850 }
3851
3852 void
3853 ethernet_ndp_change_mac (vlib_main_t * vm, u32 sw_if_index)
3854 {
3855   ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3856   ip6_neighbor_t * n;
3857
3858   /* *INDENT-OFF* */
3859   pool_foreach (n, nm->neighbor_pool, ({
3860     if (n->key.sw_if_index == sw_if_index)
3861     {
3862         adj_nbr_walk_nh6 (sw_if_index,
3863                           &n->key.ip6_address,
3864                           ip6_nd_mk_complete_walk, n);
3865     }
3866   }));
3867   /* *INDENT-ON* */
3868 }