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