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