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