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