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