Improve IP4 ARP and IP6 ND Events Notification
[vpp.git] / src / vnet / ip / ip6_neighbor.c
1 /*
2  * ip/ip6_neighbor.c: IP6 neighbor handling
3  *
4  * Copyright (c) 2010 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include <vnet/ip/ip.h>
19 #include <vnet/ip/ip6_neighbor.h>
20 #include <vnet/ethernet/ethernet.h>
21 #include <vppinfra/mhash.h>
22 #include <vnet/adj/adj.h>
23 #include <vnet/adj/adj_mcast.h>
24 #include <vnet/fib/fib_table.h>
25 #include <vnet/fib/ip6_fib.h>
26 #include <vnet/mfib/ip6_mfib.h>
27 #include <vnet/ip/ip6_ll_table.h>
28
29 /**
30  * @file
31  * @brief IPv6 Neighbor Adjacency and Neighbor Discovery.
32  *
33  * The files contains the API and CLI code for managing IPv6 neighbor
34  * adjacency tables and neighbor discovery logic.
35  */
36
37 /* can't use sizeof link_layer_address, that's 8 */
38 #define ETHER_MAC_ADDR_LEN 6
39
40 /* advertised prefix option */
41 typedef struct
42 {
43   /* basic advertised information */
44   ip6_address_t prefix;
45   u8 prefix_len;
46   int adv_on_link_flag;
47   int adv_autonomous_flag;
48   u32 adv_valid_lifetime_in_secs;
49   u32 adv_pref_lifetime_in_secs;
50
51   /* advertised values are computed from these times if decrementing */
52   f64 valid_lifetime_expires;
53   f64 pref_lifetime_expires;
54
55   /* local information */
56   int enabled;
57   int deprecated_prefix_flag;
58   int decrement_lifetime_flag;
59
60 #define MIN_ADV_VALID_LIFETIME 7203     /* seconds */
61 #define DEF_ADV_VALID_LIFETIME  2592000
62 #define DEF_ADV_PREF_LIFETIME 604800
63
64   /* extensions are added here, mobile, DNS etc.. */
65 } ip6_radv_prefix_t;
66
67
68 typedef struct
69 {
70   /* group information */
71   u8 type;
72   ip6_address_t mcast_address;
73   u16 num_sources;
74   ip6_address_t *mcast_source_address_pool;
75 } ip6_mldp_group_t;
76
77 /* configured router advertisement information per ipv6 interface */
78 typedef struct
79 {
80
81   /* advertised config information, zero means unspecified  */
82   u8 curr_hop_limit;
83   int adv_managed_flag;
84   int adv_other_flag;
85   u16 adv_router_lifetime_in_sec;
86   u32 adv_neighbor_reachable_time_in_msec;
87   u32 adv_time_in_msec_between_retransmitted_neighbor_solicitations;
88
89   /* mtu option */
90   u32 adv_link_mtu;
91
92   /* source link layer option */
93   u8 link_layer_address[8];
94   u8 link_layer_addr_len;
95
96   /* prefix option */
97   ip6_radv_prefix_t *adv_prefixes_pool;
98
99   /* Hash table mapping address to index in interface advertised  prefix pool. */
100   mhash_t address_to_prefix_index;
101
102   /* MLDP  group information */
103   ip6_mldp_group_t *mldp_group_pool;
104
105   /* Hash table mapping address to index in mldp address pool. */
106   mhash_t address_to_mldp_index;
107
108   /* local information */
109   u32 sw_if_index;
110   int send_radv;                /* radv on/off on this interface -  set by config */
111   int cease_radv;               /* we are ceasing  to send  - set byf config */
112   int send_unicast;
113   int adv_link_layer_address;
114   int prefix_option;
115   int failed_device_check;
116   int all_routers_mcast;
117   u32 seed;
118   u64 randomizer;
119   int ref_count;
120   adj_index_t mcast_adj_index;
121
122   /* timing information */
123 #define DEF_MAX_RADV_INTERVAL 200
124 #define DEF_MIN_RADV_INTERVAL .75 * DEF_MAX_RADV_INTERVAL
125 #define DEF_CURR_HOP_LIMIT  64
126 #define DEF_DEF_RTR_LIFETIME   3 * DEF_MAX_RADV_INTERVAL
127 #define MAX_DEF_RTR_LIFETIME   9000
128
129 #define MAX_INITIAL_RTR_ADVERT_INTERVAL   16    /* seconds */
130 #define MAX_INITIAL_RTR_ADVERTISEMENTS        3 /*transmissions */
131 #define MIN_DELAY_BETWEEN_RAS                              3    /* seconds */
132 #define MAX_DELAY_BETWEEN_RAS                    1800   /* seconds */
133 #define MAX_RA_DELAY_TIME                                          .5   /* seconds */
134
135   f64 max_radv_interval;
136   f64 min_radv_interval;
137   f64 min_delay_between_radv;
138   f64 max_delay_between_radv;
139   f64 max_rtr_default_lifetime;
140
141   f64 last_radv_time;
142   f64 last_multicast_time;
143   f64 next_multicast_time;
144
145
146   u32 initial_adverts_count;
147   f64 initial_adverts_interval;
148   u32 initial_adverts_sent;
149
150   /* stats */
151   u32 n_advertisements_sent;
152   u32 n_solicitations_rcvd;
153   u32 n_solicitations_dropped;
154
155   /* Link local address to use (defaults to underlying physical for logical interfaces */
156   ip6_address_t link_local_address;
157
158   /* router solicitations sending state */
159   u8 keep_sending_rs;           /* when true then next fields are valid */
160   icmp6_send_router_solicitation_params_t params;
161   f64 sleep_interval;
162   f64 due_time;
163   u32 n_left;
164   f64 start_time;
165   vlib_buffer_t *buffer;
166 } ip6_radv_t;
167
168 typedef struct
169 {
170   u32 next_index;
171   uword node_index;
172   uword type_opaque;
173   uword data;
174   /* Used for nd event notification only */
175   void *data_callback;
176   u32 pid;
177 } pending_resolution_t;
178
179
180 typedef struct
181 {
182   /* Hash tables mapping name to opcode. */
183   uword *opcode_by_name;
184
185   /* lite beer "glean" adjacency handling */
186   mhash_t pending_resolutions_by_address;
187   pending_resolution_t *pending_resolutions;
188
189   /* Mac address change notification */
190   mhash_t mac_changes_by_address;
191   pending_resolution_t *mac_changes;
192
193   u32 *neighbor_input_next_index_by_hw_if_index;
194
195   ip6_neighbor_t *neighbor_pool;
196
197   mhash_t neighbor_index_by_key;
198
199   u32 *if_radv_pool_index_by_sw_if_index;
200
201   ip6_radv_t *if_radv_pool;
202
203   /* Neighbor attack mitigation */
204   u32 limit_neighbor_cache_size;
205   u32 neighbor_delete_rotor;
206
207   /* Wildcard nd report publisher */
208   uword wc_ip6_nd_publisher_node;
209   uword wc_ip6_nd_publisher_et;
210
211   /* Router advertisement report publisher */
212   uword ip6_ra_publisher_node;
213   uword ip6_ra_publisher_et;
214 } ip6_neighbor_main_t;
215
216 /* ipv6 neighbor discovery - timer/event types */
217 typedef enum
218 {
219   ICMP6_ND_EVENT_INIT,
220 } ip6_icmp_neighbor_discovery_event_type_t;
221
222 typedef union
223 {
224   u32 add_del_swindex;
225   struct
226   {
227     u32 up_down_swindex;
228     u32 fib_index;
229   } up_down_event;
230 } ip6_icmp_neighbor_discovery_event_data_t;
231
232 static ip6_neighbor_main_t ip6_neighbor_main;
233 ip6_neighbor_public_main_t ip6_neighbor_public_main;
234 static ip6_address_t ip6a_zero; /* ip6 address 0 */
235
236 static void wc_nd_signal_report (wc_nd_report_t * r);
237 static void ra_signal_report (ra_report_t * r);
238
239 ip6_address_t
240 ip6_neighbor_get_link_local_address (u32 sw_if_index)
241 {
242   static ip6_address_t empty_address = { {0} };
243   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
244   ip6_radv_t *radv_info;
245   u32 ri;
246
247   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
248   if (ri == ~0)
249     {
250       clib_warning ("IPv6 is not enabled for sw_if_index %d", sw_if_index);
251       return empty_address;
252     }
253   radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
254   if (radv_info == NULL)
255     {
256       clib_warning ("Internal error");
257       return empty_address;
258     }
259   return radv_info->link_local_address;
260 }
261
262 /**
263  * @brief publish wildcard arp event
264  * @param sw_if_index The interface on which the ARP entires are acted
265  */
266 static int
267 vnet_nd_wc_publish (u32 sw_if_index, u8 * mac, ip6_address_t * ip6)
268 {
269   wc_nd_report_t r = {
270     .sw_if_index = sw_if_index,
271     .ip6 = *ip6,
272   };
273   memcpy (r.mac, mac, sizeof r.mac);
274
275   void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
276   vl_api_rpc_call_main_thread (wc_nd_signal_report, (u8 *) & r, sizeof r);
277   return 0;
278 }
279
280 static void
281 wc_nd_signal_report (wc_nd_report_t * r)
282 {
283   vlib_main_t *vm = vlib_get_main ();
284   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
285   uword ni = nm->wc_ip6_nd_publisher_node;
286   uword et = nm->wc_ip6_nd_publisher_et;
287
288   if (ni == (uword) ~ 0)
289     return;
290   wc_nd_report_t *q =
291     vlib_process_signal_event_data (vm, ni, et, 1, sizeof *q);
292
293   *q = *r;
294 }
295
296 void
297 wc_nd_set_publisher_node (uword node_index, uword event_type)
298 {
299   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
300   nm->wc_ip6_nd_publisher_node = node_index;
301   nm->wc_ip6_nd_publisher_et = event_type;
302 }
303
304 static int
305 ra_publish (ra_report_t * r)
306 {
307   void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
308   vl_api_rpc_call_main_thread (ra_signal_report, (u8 *) r, sizeof *r);
309   return 0;
310 }
311
312 static void
313 ra_signal_report (ra_report_t * r)
314 {
315   vlib_main_t *vm = vlib_get_main ();
316   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
317   uword ni = nm->ip6_ra_publisher_node;
318   uword et = nm->ip6_ra_publisher_et;
319
320   if (ni == (uword) ~ 0)
321     return;
322   ra_report_t *q = vlib_process_signal_event_data (vm, ni, et, 1, sizeof *q);
323
324   *q = *r;
325 }
326
327 void
328 ra_set_publisher_node (uword node_index, uword event_type)
329 {
330   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
331   nm->ip6_ra_publisher_node = node_index;
332   nm->ip6_ra_publisher_et = event_type;
333 }
334
335 static u8 *
336 format_ip6_neighbor_ip6_entry (u8 * s, va_list * va)
337 {
338   vlib_main_t *vm = va_arg (*va, vlib_main_t *);
339   ip6_neighbor_t *n = va_arg (*va, ip6_neighbor_t *);
340   vnet_main_t *vnm = vnet_get_main ();
341   vnet_sw_interface_t *si;
342   u8 *flags = 0;
343
344   if (!n)
345     return format (s, "%=12s%=25s%=6s%=20s%=40s", "Time", "Address", "Flags",
346                    "Link layer", "Interface");
347
348   if (n->flags & IP6_NEIGHBOR_FLAG_DYNAMIC)
349     flags = format (flags, "D");
350
351   if (n->flags & IP6_NEIGHBOR_FLAG_STATIC)
352     flags = format (flags, "S");
353
354   if (n->flags & IP6_NEIGHBOR_FLAG_NO_FIB_ENTRY)
355     flags = format (flags, "N");
356
357   si = vnet_get_sw_interface (vnm, n->key.sw_if_index);
358   s = format (s, "%=12U%=25U%=6s%=20U%=40U",
359               format_vlib_time, vm, n->time_last_updated,
360               format_ip6_address, &n->key.ip6_address,
361               flags ? (char *) flags : "",
362               format_ethernet_address, n->link_layer_address,
363               format_vnet_sw_interface_name, vnm, si);
364
365   vec_free (flags);
366   return s;
367 }
368
369 static void
370 ip6_neighbor_adj_fib_remove (ip6_neighbor_t * n, u32 fib_index)
371 {
372   if (FIB_NODE_INDEX_INVALID != n->fib_entry_index)
373     {
374       if (ip6_address_is_link_local_unicast (&n->key.ip6_address))
375         {
376           ip6_ll_prefix_t pfx = {
377             .ilp_addr = n->key.ip6_address,
378             .ilp_sw_if_index = n->key.sw_if_index,
379           };
380           ip6_ll_table_entry_delete (&pfx);
381         }
382       else
383         {
384           fib_prefix_t pfx = {
385             .fp_len = 128,
386             .fp_proto = FIB_PROTOCOL_IP6,
387             .fp_addr.ip6 = n->key.ip6_address,
388           };
389           fib_table_entry_path_remove (fib_index,
390                                        &pfx,
391                                        FIB_SOURCE_ADJ,
392                                        DPO_PROTO_IP6,
393                                        &pfx.fp_addr,
394                                        n->key.sw_if_index, ~0,
395                                        1, FIB_ROUTE_PATH_FLAG_NONE);
396         }
397     }
398 }
399
400 typedef struct
401 {
402   u8 is_add;
403   u8 is_static;
404   u8 is_no_fib_entry;
405   u8 link_layer_address[6];
406   u32 sw_if_index;
407   ip6_address_t addr;
408 } ip6_neighbor_set_unset_rpc_args_t;
409
410 static void ip6_neighbor_set_unset_rpc_callback
411   (ip6_neighbor_set_unset_rpc_args_t * a);
412
413 static void set_unset_ip6_neighbor_rpc
414   (vlib_main_t * vm,
415    u32 sw_if_index,
416    ip6_address_t * a, u8 * link_layer_address, int is_add, int is_static,
417    int is_no_fib_entry)
418 {
419   ip6_neighbor_set_unset_rpc_args_t args;
420   void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
421
422   args.sw_if_index = sw_if_index;
423   args.is_add = is_add;
424   args.is_static = is_static;
425   args.is_no_fib_entry = is_no_fib_entry;
426   clib_memcpy (&args.addr, a, sizeof (*a));
427   if (NULL != link_layer_address)
428     clib_memcpy (args.link_layer_address, link_layer_address, 6);
429
430   vl_api_rpc_call_main_thread (ip6_neighbor_set_unset_rpc_callback,
431                                (u8 *) & args, sizeof (args));
432 }
433
434 static void
435 ip6_nbr_probe (ip_adjacency_t * adj)
436 {
437   icmp6_neighbor_solicitation_header_t *h;
438   vnet_main_t *vnm = vnet_get_main ();
439   ip6_main_t *im = &ip6_main;
440   ip_interface_address_t *ia;
441   ip6_address_t *dst, *src;
442   vnet_hw_interface_t *hi;
443   vnet_sw_interface_t *si;
444   vlib_buffer_t *b;
445   int bogus_length;
446   vlib_main_t *vm;
447   u32 bi = 0;
448
449   vm = vlib_get_main ();
450
451   si = vnet_get_sw_interface (vnm, adj->rewrite_header.sw_if_index);
452   dst = &adj->sub_type.nbr.next_hop.ip6;
453
454   if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
455     {
456       return;
457     }
458   src = ip6_interface_address_matching_destination (im, dst,
459                                                     adj->rewrite_header.
460                                                     sw_if_index, &ia);
461   if (!src)
462     {
463       return;
464     }
465
466   h = vlib_packet_template_get_packet (vm,
467                                        &im->discover_neighbor_packet_template,
468                                        &bi);
469   if (!h)
470     return;
471
472   hi = vnet_get_sup_hw_interface (vnm, adj->rewrite_header.sw_if_index);
473
474   h->ip.dst_address.as_u8[13] = dst->as_u8[13];
475   h->ip.dst_address.as_u8[14] = dst->as_u8[14];
476   h->ip.dst_address.as_u8[15] = dst->as_u8[15];
477   h->ip.src_address = src[0];
478   h->neighbor.target_address = dst[0];
479
480   clib_memcpy (h->link_layer_option.ethernet_address,
481                hi->hw_address, vec_len (hi->hw_address));
482
483   h->neighbor.icmp.checksum =
484     ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length);
485   ASSERT (bogus_length == 0);
486
487   b = vlib_get_buffer (vm, bi);
488   vnet_buffer (b)->sw_if_index[VLIB_RX] =
489     vnet_buffer (b)->sw_if_index[VLIB_TX] = adj->rewrite_header.sw_if_index;
490
491   /* Add encapsulation string for software interface (e.g. ethernet header). */
492   vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
493   vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
494
495   {
496     vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
497     u32 *to_next = vlib_frame_vector_args (f);
498     to_next[0] = bi;
499     f->n_vectors = 1;
500     vlib_put_frame_to_node (vm, hi->output_node_index, f);
501   }
502 }
503
504 static void
505 ip6_nd_mk_complete (adj_index_t ai, ip6_neighbor_t * nbr)
506 {
507   adj_nbr_update_rewrite (ai, ADJ_NBR_REWRITE_FLAG_COMPLETE,
508                           ethernet_build_rewrite (vnet_get_main (),
509                                                   nbr->key.sw_if_index,
510                                                   adj_get_link_type (ai),
511                                                   nbr->link_layer_address));
512 }
513
514 static void
515 ip6_nd_mk_incomplete (adj_index_t ai)
516 {
517   ip_adjacency_t *adj = adj_get (ai);
518
519   adj_nbr_update_rewrite (ai,
520                           ADJ_NBR_REWRITE_FLAG_INCOMPLETE,
521                           ethernet_build_rewrite (vnet_get_main (),
522                                                   adj->rewrite_header.
523                                                   sw_if_index,
524                                                   adj_get_link_type (ai),
525                                                   VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
526 }
527
528 #define IP6_NBR_MK_KEY(k, sw_if_index, addr) \
529 {                                            \
530     k.sw_if_index = sw_if_index;             \
531     k.ip6_address = *addr;                   \
532     k.pad = 0;                               \
533 }
534
535 static ip6_neighbor_t *
536 ip6_nd_find (u32 sw_if_index, const ip6_address_t * addr)
537 {
538   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
539   ip6_neighbor_t *n = NULL;
540   ip6_neighbor_key_t k;
541   uword *p;
542
543   IP6_NBR_MK_KEY (k, sw_if_index, addr);
544
545   p = mhash_get (&nm->neighbor_index_by_key, &k);
546   if (p)
547     {
548       n = pool_elt_at_index (nm->neighbor_pool, p[0]);
549     }
550
551   return (n);
552 }
553
554 static adj_walk_rc_t
555 ip6_nd_mk_complete_walk (adj_index_t ai, void *ctx)
556 {
557   ip6_neighbor_t *nbr = ctx;
558
559   ip6_nd_mk_complete (ai, nbr);
560
561   return (ADJ_WALK_RC_CONTINUE);
562 }
563
564 static adj_walk_rc_t
565 ip6_nd_mk_incomplete_walk (adj_index_t ai, void *ctx)
566 {
567   ip6_nd_mk_incomplete (ai);
568
569   return (ADJ_WALK_RC_CONTINUE);
570 }
571
572 static clib_error_t *
573 ip6_neighbor_sw_interface_up_down (vnet_main_t * vnm,
574                                    u32 sw_if_index, u32 flags)
575 {
576   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
577   ip6_neighbor_t *n;
578   u32 i, *to_delete = 0;
579
580   /* *INDENT-OFF* */
581   pool_foreach (n, nm->neighbor_pool,
582   ({
583     if (n->key.sw_if_index == sw_if_index)
584       vec_add1 (to_delete, n - nm->neighbor_pool);
585   }));
586   /* *INDENT-ON* */
587
588   if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
589     {
590       for (i = 0; i < vec_len (to_delete); i++)
591         {
592           n = pool_elt_at_index (nm->neighbor_pool, to_delete[i]);
593           adj_nbr_walk_nh6 (n->key.sw_if_index, &n->key.ip6_address,
594                             ip6_nd_mk_complete_walk, n);
595         }
596     }
597   else
598     {
599       for (i = 0; i < vec_len (to_delete); i++)
600         {
601           n = pool_elt_at_index (nm->neighbor_pool, to_delete[i]);
602           adj_nbr_walk_nh6 (n->key.sw_if_index, &n->key.ip6_address,
603                             ip6_nd_mk_incomplete_walk, NULL);
604           if (n->flags & IP6_NEIGHBOR_FLAG_STATIC)
605             continue;
606           ip6_neighbor_adj_fib_remove (n,
607                                        ip6_fib_table_get_index_for_sw_if_index
608                                        (n->key.sw_if_index));
609           mhash_unset (&nm->neighbor_index_by_key, &n->key, 0);
610           pool_put (nm->neighbor_pool, n);
611         }
612     }
613
614   vec_free (to_delete);
615   return 0;
616 }
617
618 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_neighbor_sw_interface_up_down);
619
620 void
621 ip6_ethernet_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
622 {
623   ip6_neighbor_t *nbr;
624   ip_adjacency_t *adj;
625
626   adj = adj_get (ai);
627
628   nbr = ip6_nd_find (sw_if_index, &adj->sub_type.nbr.next_hop.ip6);
629
630   switch (adj->lookup_next_index)
631     {
632     case IP_LOOKUP_NEXT_GLEAN:
633       adj_glean_update_rewrite (ai);
634       break;
635     case IP_LOOKUP_NEXT_ARP:
636       if (NULL != nbr)
637         {
638           adj_nbr_walk_nh6 (sw_if_index, &nbr->key.ip6_address,
639                             ip6_nd_mk_complete_walk, nbr);
640         }
641       else
642         {
643           /*
644            * no matching ND entry.
645            * construct the rewrite required to for an ND packet, and stick
646            * that in the adj's pipe to smoke.
647            */
648           adj_nbr_update_rewrite (ai,
649                                   ADJ_NBR_REWRITE_FLAG_INCOMPLETE,
650                                   ethernet_build_rewrite (vnm,
651                                                           sw_if_index,
652                                                           VNET_LINK_IP6,
653                                                           VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST));
654
655           /*
656            * since the FIB has added this adj for a route, it makes sense it may
657            * want to forward traffic sometime soon. Let's send a speculative ND.
658            * just one. If we were to do periodically that wouldn't be bad either,
659            * but that's more code than i'm prepared to write at this time for
660            * relatively little reward.
661            */
662           ip6_nbr_probe (adj);
663         }
664       break;
665     case IP_LOOKUP_NEXT_MCAST:
666       {
667         /*
668          * Construct a partial rewrite from the known ethernet mcast dest MAC
669          */
670         u8 *rewrite;
671         u8 offset;
672
673         rewrite = ethernet_build_rewrite (vnm,
674                                           sw_if_index,
675                                           adj->ia_link,
676                                           ethernet_ip6_mcast_dst_addr ());
677
678         /*
679          * Complete the remaining fields of the adj's rewrite to direct the
680          * complete of the rewrite at switch time by copying in the IP
681          * dst address's bytes.
682          * Ofset is 2 bytes into the desintation address.
683          */
684         offset = vec_len (rewrite) - 2;
685         adj_mcast_update_rewrite (ai, rewrite, offset);
686
687         break;
688       }
689     case IP_LOOKUP_NEXT_DROP:
690     case IP_LOOKUP_NEXT_PUNT:
691     case IP_LOOKUP_NEXT_LOCAL:
692     case IP_LOOKUP_NEXT_REWRITE:
693     case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
694     case IP_LOOKUP_NEXT_MIDCHAIN:
695     case IP_LOOKUP_NEXT_ICMP_ERROR:
696     case IP_LOOKUP_N_NEXT:
697       ASSERT (0);
698       break;
699     }
700 }
701
702
703 static void
704 ip6_neighbor_adj_fib_add (ip6_neighbor_t * n, u32 fib_index)
705 {
706   if (ip6_address_is_link_local_unicast (&n->key.ip6_address))
707     {
708       ip6_ll_prefix_t pfx = {
709         .ilp_addr = n->key.ip6_address,
710         .ilp_sw_if_index = n->key.sw_if_index,
711       };
712       n->fib_entry_index =
713         ip6_ll_table_entry_update (&pfx, FIB_ROUTE_PATH_FLAG_NONE);
714     }
715   else
716     {
717       fib_prefix_t pfx = {
718         .fp_len = 128,
719         .fp_proto = FIB_PROTOCOL_IP6,
720         .fp_addr.ip6 = n->key.ip6_address,
721       };
722
723       n->fib_entry_index =
724         fib_table_entry_path_add (fib_index, &pfx, FIB_SOURCE_ADJ,
725                                   FIB_ENTRY_FLAG_ATTACHED,
726                                   DPO_PROTO_IP6, &pfx.fp_addr,
727                                   n->key.sw_if_index, ~0, 1, NULL,
728                                   FIB_ROUTE_PATH_FLAG_NONE);
729     }
730 }
731
732 static ip6_neighbor_t *
733 force_reuse_neighbor_entry (void)
734 {
735   ip6_neighbor_t *n;
736   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
737   u32 count = 0;
738   u32 index = pool_next_index (nm->neighbor_pool, nm->neighbor_delete_rotor);
739   if (index == ~0)              /* Try again from elt 0 */
740     index = pool_next_index (nm->neighbor_pool, index);
741
742   /* Find a non-static random entry to free up for reuse */
743   do
744     {
745       if ((count++ == 100) || (index == ~0))
746         return NULL;            /* give up after 100 entries */
747       n = pool_elt_at_index (nm->neighbor_pool, index);
748       nm->neighbor_delete_rotor = index;
749       index = pool_next_index (nm->neighbor_pool, index);
750     }
751   while (n->flags & IP6_NEIGHBOR_FLAG_STATIC);
752
753   /* Remove ARP entry from its interface and update fib */
754   adj_nbr_walk_nh6 (n->key.sw_if_index,
755                     &n->key.ip6_address, ip6_nd_mk_incomplete_walk, NULL);
756   ip6_neighbor_adj_fib_remove
757     (n, ip6_fib_table_get_index_for_sw_if_index (n->key.sw_if_index));
758   mhash_unset (&nm->neighbor_index_by_key, &n->key, 0);
759
760   return n;
761 }
762
763 int
764 vnet_set_ip6_ethernet_neighbor (vlib_main_t * vm,
765                                 u32 sw_if_index,
766                                 ip6_address_t * a,
767                                 u8 * link_layer_address,
768                                 uword n_bytes_link_layer_address,
769                                 int is_static, int is_no_fib_entry)
770 {
771   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
772   ip6_neighbor_key_t k;
773   ip6_neighbor_t *n = 0;
774   int make_new_nd_cache_entry = 1;
775   uword *p;
776   u32 next_index;
777   pending_resolution_t *pr, *mc;
778
779   if (vlib_get_thread_index ())
780     {
781       set_unset_ip6_neighbor_rpc (vm, sw_if_index, a, link_layer_address,
782                                   1 /* set new neighbor */ , is_static,
783                                   is_no_fib_entry);
784       return 0;
785     }
786
787   k.sw_if_index = sw_if_index;
788   k.ip6_address = a[0];
789   k.pad = 0;
790
791   p = mhash_get (&nm->neighbor_index_by_key, &k);
792   if (p)
793     {
794       n = pool_elt_at_index (nm->neighbor_pool, p[0]);
795       /* Refuse to over-write static neighbor entry. */
796       if (!is_static && (n->flags & IP6_NEIGHBOR_FLAG_STATIC))
797         {
798           /* if MAC address match, still check to send event */
799           if (0 == memcmp (n->link_layer_address,
800                            link_layer_address, n_bytes_link_layer_address))
801             goto check_customers;
802           return -2;
803         }
804       make_new_nd_cache_entry = 0;
805     }
806
807   if (make_new_nd_cache_entry)
808     {
809       if (nm->limit_neighbor_cache_size &&
810           pool_elts (nm->neighbor_pool) >= nm->limit_neighbor_cache_size)
811         {
812           n = force_reuse_neighbor_entry ();
813           if (NULL == n)
814             return -2;
815         }
816       else
817         pool_get (nm->neighbor_pool, n);
818
819       mhash_set (&nm->neighbor_index_by_key, &k, n - nm->neighbor_pool,
820                  /* old value */ 0);
821       n->key = k;
822       n->fib_entry_index = FIB_NODE_INDEX_INVALID;
823
824       clib_memcpy (n->link_layer_address,
825                    link_layer_address, n_bytes_link_layer_address);
826
827       /*
828        * create the adj-fib. the entry in the FIB table for and to the peer.
829        */
830       if (!is_no_fib_entry)
831         {
832           ip6_neighbor_adj_fib_add
833             (n, ip6_fib_table_get_index_for_sw_if_index (n->key.sw_if_index));
834         }
835       else
836         {
837           n->flags |= IP6_NEIGHBOR_FLAG_NO_FIB_ENTRY;
838         }
839     }
840   else
841     {
842       /*
843        * prevent a DoS attack from the data-plane that
844        * spams us with no-op updates to the MAC address
845        */
846       if (0 == memcmp (n->link_layer_address,
847                        link_layer_address, n_bytes_link_layer_address))
848         {
849           n->time_last_updated = vlib_time_now (vm);
850           goto check_customers;
851         }
852
853       clib_memcpy (n->link_layer_address,
854                    link_layer_address, n_bytes_link_layer_address);
855     }
856
857   /* Update time stamp and flags. */
858   n->time_last_updated = vlib_time_now (vm);
859   if (is_static)
860     {
861       n->flags |= IP6_NEIGHBOR_FLAG_STATIC;
862       n->flags &= ~IP6_NEIGHBOR_FLAG_DYNAMIC;
863     }
864   else
865     {
866       n->flags |= IP6_NEIGHBOR_FLAG_DYNAMIC;
867       n->flags &= ~IP6_NEIGHBOR_FLAG_STATIC;
868     }
869
870   adj_nbr_walk_nh6 (sw_if_index,
871                     &n->key.ip6_address, ip6_nd_mk_complete_walk, n);
872
873 check_customers:
874   /* Customer(s) waiting for this address to be resolved? */
875   p = mhash_get (&nm->pending_resolutions_by_address, a);
876   if (p)
877     {
878       next_index = p[0];
879
880       while (next_index != (u32) ~ 0)
881         {
882           pr = pool_elt_at_index (nm->pending_resolutions, next_index);
883           vlib_process_signal_event (vm, pr->node_index,
884                                      pr->type_opaque, pr->data);
885           next_index = pr->next_index;
886           pool_put (nm->pending_resolutions, pr);
887         }
888
889       mhash_unset (&nm->pending_resolutions_by_address, a, 0);
890     }
891
892   /* Customer(s) requesting ND event for this address? */
893   p = mhash_get (&nm->mac_changes_by_address, a);
894   if (p)
895     {
896       next_index = p[0];
897
898       while (next_index != (u32) ~ 0)
899         {
900           int (*fp) (u32, u8 *, u32, ip6_address_t *);
901           int rv = 1;
902           mc = pool_elt_at_index (nm->mac_changes, next_index);
903           fp = mc->data_callback;
904
905           /* Call the user's data callback, return 1 to suppress dup events */
906           if (fp)
907             rv =
908               (*fp) (mc->data, link_layer_address, sw_if_index, &ip6a_zero);
909           /*
910            * Signal the resolver process, as long as the user
911            * says they want to be notified
912            */
913           if (rv == 0)
914             vlib_process_signal_event (vm, mc->node_index,
915                                        mc->type_opaque, mc->data);
916           next_index = mc->next_index;
917         }
918     }
919
920   return 0;
921 }
922
923 int
924 vnet_unset_ip6_ethernet_neighbor (vlib_main_t * vm,
925                                   u32 sw_if_index,
926                                   ip6_address_t * a,
927                                   u8 * link_layer_address,
928                                   uword n_bytes_link_layer_address)
929 {
930   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
931   ip6_neighbor_key_t k;
932   ip6_neighbor_t *n;
933   uword *p;
934   int rv = 0;
935
936   if (vlib_get_thread_index ())
937     {
938       set_unset_ip6_neighbor_rpc (vm, sw_if_index, a, link_layer_address,
939                                   0 /* unset */ , 0, 0);
940       return 0;
941     }
942
943   k.sw_if_index = sw_if_index;
944   k.ip6_address = a[0];
945   k.pad = 0;
946
947   p = mhash_get (&nm->neighbor_index_by_key, &k);
948   if (p == 0)
949     {
950       rv = -1;
951       goto out;
952     }
953
954   n = pool_elt_at_index (nm->neighbor_pool, p[0]);
955
956   adj_nbr_walk_nh6 (sw_if_index,
957                     &n->key.ip6_address, ip6_nd_mk_incomplete_walk, NULL);
958   ip6_neighbor_adj_fib_remove
959     (n, ip6_fib_table_get_index_for_sw_if_index (sw_if_index));
960
961   mhash_unset (&nm->neighbor_index_by_key, &n->key, 0);
962   pool_put (nm->neighbor_pool, n);
963
964 out:
965   return rv;
966 }
967
968 static void ip6_neighbor_set_unset_rpc_callback
969   (ip6_neighbor_set_unset_rpc_args_t * a)
970 {
971   vlib_main_t *vm = vlib_get_main ();
972   if (a->is_add)
973     vnet_set_ip6_ethernet_neighbor (vm, a->sw_if_index, &a->addr,
974                                     a->link_layer_address, 6, a->is_static,
975                                     a->is_no_fib_entry);
976   else
977     vnet_unset_ip6_ethernet_neighbor (vm, a->sw_if_index, &a->addr,
978                                       a->link_layer_address, 6);
979 }
980
981 static int
982 ip6_neighbor_sort (void *a1, void *a2)
983 {
984   vnet_main_t *vnm = vnet_get_main ();
985   ip6_neighbor_t *n1 = a1, *n2 = a2;
986   int cmp;
987   cmp = vnet_sw_interface_compare (vnm, n1->key.sw_if_index,
988                                    n2->key.sw_if_index);
989   if (!cmp)
990     cmp = ip6_address_compare (&n1->key.ip6_address, &n2->key.ip6_address);
991   return cmp;
992 }
993
994 ip6_neighbor_t *
995 ip6_neighbors_pool (void)
996 {
997   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
998   return nm->neighbor_pool;
999 }
1000
1001 ip6_neighbor_t *
1002 ip6_neighbors_entries (u32 sw_if_index)
1003 {
1004   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
1005   ip6_neighbor_t *n, *ns = 0;
1006
1007   /* *INDENT-OFF* */
1008   pool_foreach (n, nm->neighbor_pool,
1009   ({
1010     if (sw_if_index != ~0 && n->key.sw_if_index != sw_if_index)
1011       continue;
1012     vec_add1 (ns, n[0]);
1013   }));
1014   /* *INDENT-ON* */
1015
1016   if (ns)
1017     vec_sort_with_function (ns, ip6_neighbor_sort);
1018   return ns;
1019 }
1020
1021 static clib_error_t *
1022 show_ip6_neighbors (vlib_main_t * vm,
1023                     unformat_input_t * input, vlib_cli_command_t * cmd)
1024 {
1025   vnet_main_t *vnm = vnet_get_main ();
1026   ip6_neighbor_t *n, *ns;
1027   clib_error_t *error = 0;
1028   u32 sw_if_index;
1029
1030   /* Filter entries by interface if given. */
1031   sw_if_index = ~0;
1032   (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index);
1033
1034   ns = ip6_neighbors_entries (sw_if_index);
1035   if (ns)
1036     {
1037       vlib_cli_output (vm, "%U", format_ip6_neighbor_ip6_entry, vm, 0);
1038       vec_foreach (n, ns)
1039       {
1040         vlib_cli_output (vm, "%U", format_ip6_neighbor_ip6_entry, vm, n);
1041       }
1042       vec_free (ns);
1043     }
1044
1045   return error;
1046 }
1047
1048 /*?
1049  * This command is used to display the adjacent IPv6 hosts found via
1050  * neighbor discovery. Optionally, limit the output to the specified
1051  * interface.
1052  *
1053  * @cliexpar
1054  * Example of how to display the IPv6 neighbor adjacency table:
1055  * @cliexstart{show ip6 neighbors}
1056  *     Time           Address       Flags     Link layer                     Interface
1057  *      34.0910     ::a:1:1:0:7            02:fe:6a:07:39:6f                GigabitEthernet2/0/0
1058  *     173.2916     ::b:5:1:c:2            02:fe:50:62:3a:94                GigabitEthernet2/0/0
1059  *     886.6654     ::1:1:c:0:9       S    02:fe:e4:45:27:5b                GigabitEthernet3/0/0
1060  * @cliexend
1061  * Example of how to display the IPv6 neighbor adjacency table for given interface:
1062  * @cliexstart{show ip6 neighbors GigabitEthernet2/0/0}
1063  *     Time           Address       Flags     Link layer                     Interface
1064  *      34.0910     ::a:1:1:0:7            02:fe:6a:07:39:6f                GigabitEthernet2/0/0
1065  *     173.2916     ::b:5:1:c:2            02:fe:50:62:3a:94                GigabitEthernet2/0/0
1066  * @cliexend
1067 ?*/
1068 /* *INDENT-OFF* */
1069 VLIB_CLI_COMMAND (show_ip6_neighbors_command, static) = {
1070   .path = "show ip6 neighbors",
1071   .function = show_ip6_neighbors,
1072   .short_help = "show ip6 neighbors [<interface>]",
1073 };
1074 /* *INDENT-ON* */
1075
1076 static clib_error_t *
1077 set_ip6_neighbor (vlib_main_t * vm,
1078                   unformat_input_t * input, vlib_cli_command_t * cmd)
1079 {
1080   vnet_main_t *vnm = vnet_get_main ();
1081   ip6_address_t addr;
1082   u8 mac_address[6];
1083   int addr_valid = 0;
1084   int is_del = 0;
1085   int is_static = 0;
1086   int is_no_fib_entry = 0;
1087   u32 sw_if_index;
1088
1089   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1090     {
1091       /* intfc, ip6-address, mac-address */
1092       if (unformat (input, "%U %U %U",
1093                     unformat_vnet_sw_interface, vnm, &sw_if_index,
1094                     unformat_ip6_address, &addr,
1095                     unformat_ethernet_address, mac_address))
1096         addr_valid = 1;
1097
1098       else if (unformat (input, "delete") || unformat (input, "del"))
1099         is_del = 1;
1100       else if (unformat (input, "static"))
1101         is_static = 1;
1102       else if (unformat (input, "no-fib-entry"))
1103         is_no_fib_entry = 1;
1104       else
1105         break;
1106     }
1107
1108   if (!addr_valid)
1109     return clib_error_return (0, "Missing interface, ip6 or hw address");
1110
1111   if (!is_del)
1112     vnet_set_ip6_ethernet_neighbor (vm, sw_if_index, &addr,
1113                                     mac_address, sizeof (mac_address),
1114                                     is_static, is_no_fib_entry);
1115   else
1116     vnet_unset_ip6_ethernet_neighbor (vm, sw_if_index, &addr,
1117                                       mac_address, sizeof (mac_address));
1118   return 0;
1119 }
1120
1121 /*?
1122  * This command is used to manually add an entry to the IPv6 neighbor
1123  * adjacency table. Optionally, the entry can be added as static. It is
1124  * also used to remove an entry from the table. Use the '<em>show ip6
1125  * neighbors</em>' command to display all learned and manually entered entries.
1126  *
1127  * @cliexpar
1128  * Example of how to add a static entry to the IPv6 neighbor adjacency table:
1129  * @cliexcmd{set ip6 neighbor GigabitEthernet2/0/0 ::1:1:c:0:9 02:fe:e4:45:27:5b static}
1130  * Example of how to delete an entry from the IPv6 neighbor adjacency table:
1131  * @cliexcmd{set ip6 neighbor del GigabitEthernet2/0/0 ::1:1:c:0:9 02:fe:e4:45:27:5b}
1132 ?*/
1133 /* *INDENT-OFF* */
1134 VLIB_CLI_COMMAND (set_ip6_neighbor_command, static) =
1135 {
1136   .path = "set ip6 neighbor",
1137   .function = set_ip6_neighbor,
1138   .short_help = "set ip6 neighbor [del] <interface> <ip6-address> <mac-address> [static]",
1139 };
1140 /* *INDENT-ON* */
1141
1142 typedef enum
1143 {
1144   ICMP6_NEIGHBOR_SOLICITATION_NEXT_DROP,
1145   ICMP6_NEIGHBOR_SOLICITATION_NEXT_REPLY,
1146   ICMP6_NEIGHBOR_SOLICITATION_N_NEXT,
1147 } icmp6_neighbor_solicitation_or_advertisement_next_t;
1148
1149 static_always_inline uword
1150 icmp6_neighbor_solicitation_or_advertisement (vlib_main_t * vm,
1151                                               vlib_node_runtime_t * node,
1152                                               vlib_frame_t * frame,
1153                                               uword is_solicitation)
1154 {
1155   vnet_main_t *vnm = vnet_get_main ();
1156   ip6_main_t *im = &ip6_main;
1157   uword n_packets = frame->n_vectors;
1158   u32 *from, *to_next;
1159   u32 n_left_from, n_left_to_next, next_index, n_advertisements_sent;
1160   icmp6_neighbor_discovery_option_type_t option_type;
1161   vlib_node_runtime_t *error_node =
1162     vlib_node_get_runtime (vm, ip6_icmp_input_node.index);
1163   int bogus_length;
1164
1165   from = vlib_frame_vector_args (frame);
1166   n_left_from = n_packets;
1167   next_index = node->cached_next_index;
1168
1169   if (node->flags & VLIB_NODE_FLAG_TRACE)
1170     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
1171                                    /* stride */ 1,
1172                                    sizeof (icmp6_input_trace_t));
1173
1174   option_type =
1175     (is_solicitation
1176      ? ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address
1177      : ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address);
1178   n_advertisements_sent = 0;
1179
1180   while (n_left_from > 0)
1181     {
1182       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1183
1184       while (n_left_from > 0 && n_left_to_next > 0)
1185         {
1186           vlib_buffer_t *p0;
1187           ip6_header_t *ip0;
1188           icmp6_neighbor_solicitation_or_advertisement_header_t *h0;
1189           icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *o0;
1190           u32 bi0, options_len0, sw_if_index0, next0, error0;
1191           u32 ip6_sadd_link_local, ip6_sadd_unspecified;
1192           int is_rewrite0;
1193           u32 ni0;
1194
1195           bi0 = to_next[0] = from[0];
1196
1197           from += 1;
1198           to_next += 1;
1199           n_left_from -= 1;
1200           n_left_to_next -= 1;
1201
1202           p0 = vlib_get_buffer (vm, bi0);
1203           ip0 = vlib_buffer_get_current (p0);
1204           h0 = ip6_next_header (ip0);
1205           options_len0 =
1206             clib_net_to_host_u16 (ip0->payload_length) - sizeof (h0[0]);
1207
1208           error0 = ICMP6_ERROR_NONE;
1209           sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1210           ip6_sadd_link_local =
1211             ip6_address_is_link_local_unicast (&ip0->src_address);
1212           ip6_sadd_unspecified =
1213             ip6_address_is_unspecified (&ip0->src_address);
1214
1215           /* Check that source address is unspecified, link-local or else on-link. */
1216           if (!ip6_sadd_unspecified && !ip6_sadd_link_local)
1217             {
1218               u32 src_adj_index0 = ip6_src_lookup_for_packet (im, p0, ip0);
1219
1220               if (ADJ_INDEX_INVALID != src_adj_index0)
1221                 {
1222                   ip_adjacency_t *adj0 = adj_get (src_adj_index0);
1223
1224                   /* Allow all realistic-looking rewrite adjacencies to pass */
1225                   ni0 = adj0->lookup_next_index;
1226                   is_rewrite0 = (ni0 >= IP_LOOKUP_NEXT_ARP) &&
1227                     (ni0 < IP6_LOOKUP_N_NEXT);
1228
1229                   error0 = ((adj0->rewrite_header.sw_if_index != sw_if_index0
1230                              || !is_rewrite0)
1231                             ?
1232                             ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_NOT_ON_LINK
1233                             : error0);
1234                 }
1235               else
1236                 {
1237                   error0 =
1238                     ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_NOT_ON_LINK;
1239                 }
1240             }
1241
1242           o0 = (void *) (h0 + 1);
1243           o0 = ((options_len0 == 8 && o0->header.type == option_type
1244                  && o0->header.n_data_u64s == 1) ? o0 : 0);
1245
1246           /* If src address unspecified or link local, donot learn neighbor MAC */
1247           if (PREDICT_TRUE (error0 == ICMP6_ERROR_NONE && o0 != 0 &&
1248                             !ip6_sadd_unspecified))
1249             {
1250               vnet_set_ip6_ethernet_neighbor (vm, sw_if_index0,
1251                                               is_solicitation ?
1252                                               &ip0->src_address :
1253                                               &h0->target_address,
1254                                               o0->ethernet_address,
1255                                               sizeof (o0->ethernet_address),
1256                                               0, 0);
1257             }
1258
1259           if (is_solicitation && error0 == ICMP6_ERROR_NONE)
1260             {
1261               /* Check that target address is local to this router. */
1262               fib_node_index_t fei;
1263               u32 fib_index;
1264
1265               fib_index =
1266                 ip6_fib_table_get_index_for_sw_if_index (sw_if_index0);
1267
1268               if (~0 == fib_index)
1269                 {
1270                   error0 = ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_UNKNOWN;
1271                 }
1272               else
1273                 {
1274                   if (ip6_address_is_link_local_unicast (&h0->target_address))
1275                     {
1276                       fei = ip6_fib_table_lookup_exact_match
1277                         (ip6_ll_fib_get (sw_if_index0),
1278                          &h0->target_address, 128);
1279                     }
1280                   else
1281                     {
1282                       fei = ip6_fib_table_lookup_exact_match (fib_index,
1283                                                               &h0->target_address,
1284                                                               128);
1285                     }
1286
1287                   if (FIB_NODE_INDEX_INVALID == fei)
1288                     {
1289                       /* The target address is not in the FIB */
1290                       error0 =
1291                         ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_UNKNOWN;
1292                     }
1293                   else
1294                     {
1295                       if (FIB_ENTRY_FLAG_LOCAL &
1296                           fib_entry_get_flags_for_source (fei,
1297                                                           FIB_SOURCE_INTERFACE))
1298                         {
1299                           /* It's an address that belongs to one of our interfaces
1300                            * that's good. */
1301                         }
1302                       else
1303                         if (fib_entry_is_sourced
1304                             (fei, FIB_SOURCE_IP6_ND_PROXY) ||
1305                             fib_entry_is_sourced (fei, FIB_SOURCE_IP6_ND))
1306                         {
1307                           /* The address was added by IPv6 Proxy ND config.
1308                            * We should only respond to these if the NS arrived on
1309                            * the link that has a matching covering prefix */
1310                         }
1311                       else
1312                         {
1313                           error0 =
1314                             ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_UNKNOWN;
1315                         }
1316                     }
1317                 }
1318             }
1319
1320           if (is_solicitation)
1321             next0 = (error0 != ICMP6_ERROR_NONE
1322                      ? ICMP6_NEIGHBOR_SOLICITATION_NEXT_DROP
1323                      : ICMP6_NEIGHBOR_SOLICITATION_NEXT_REPLY);
1324           else
1325             {
1326               next0 = 0;
1327               error0 = error0 == ICMP6_ERROR_NONE ?
1328                 ICMP6_ERROR_NEIGHBOR_ADVERTISEMENTS_RX : error0;
1329             }
1330
1331           if (is_solicitation && error0 == ICMP6_ERROR_NONE)
1332             {
1333               vnet_sw_interface_t *sw_if0;
1334               ethernet_interface_t *eth_if0;
1335               ethernet_header_t *eth0;
1336
1337               /* dst address is either source address or the all-nodes mcast addr */
1338               if (!ip6_sadd_unspecified)
1339                 ip0->dst_address = ip0->src_address;
1340               else
1341                 ip6_set_reserved_multicast_address (&ip0->dst_address,
1342                                                     IP6_MULTICAST_SCOPE_link_local,
1343                                                     IP6_MULTICAST_GROUP_ID_all_hosts);
1344
1345               ip0->src_address = h0->target_address;
1346               ip0->hop_limit = 255;
1347               h0->icmp.type = ICMP6_neighbor_advertisement;
1348
1349               sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
1350               ASSERT (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
1351               eth_if0 =
1352                 ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
1353               if (eth_if0 && o0)
1354                 {
1355                   clib_memcpy (o0->ethernet_address, eth_if0->address, 6);
1356                   o0->header.type =
1357                     ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
1358                 }
1359
1360               h0->advertisement_flags = clib_host_to_net_u32
1361                 (ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED
1362                  | ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE);
1363
1364               h0->icmp.checksum = 0;
1365               h0->icmp.checksum =
1366                 ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0,
1367                                                    &bogus_length);
1368               ASSERT (bogus_length == 0);
1369
1370               /* Reuse current MAC header, copy SMAC to DMAC and
1371                * interface MAC to SMAC */
1372               vlib_buffer_advance (p0, -ethernet_buffer_header_size (p0));
1373               eth0 = vlib_buffer_get_current (p0);
1374               clib_memcpy (eth0->dst_address, eth0->src_address, 6);
1375               if (eth_if0)
1376                 clib_memcpy (eth0->src_address, eth_if0->address, 6);
1377
1378               /* Setup input and output sw_if_index for packet */
1379               ASSERT (vnet_buffer (p0)->sw_if_index[VLIB_RX] == sw_if_index0);
1380               vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1381               vnet_buffer (p0)->sw_if_index[VLIB_RX] =
1382                 vnet_main.local_interface_sw_if_index;
1383
1384               n_advertisements_sent++;
1385             }
1386
1387           p0->error = error_node->errors[error0];
1388
1389           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1390                                            to_next, n_left_to_next,
1391                                            bi0, next0);
1392         }
1393
1394       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1395     }
1396
1397   /* Account for advertisements sent. */
1398   vlib_error_count (vm, error_node->node_index,
1399                     ICMP6_ERROR_NEIGHBOR_ADVERTISEMENTS_TX,
1400                     n_advertisements_sent);
1401
1402   return frame->n_vectors;
1403 }
1404
1405 /* for "syslogging" - use elog for now */
1406 #define foreach_log_level            \
1407   _ (DEBUG, "DEBUG")                         \
1408   _ (INFO, "INFORMATION")            \
1409   _ (NOTICE, "NOTICE")               \
1410   _ (WARNING, "WARNING")             \
1411   _ (ERR, "ERROR")                                    \
1412   _ (CRIT, "CRITICAL")                        \
1413   _ (ALERT, "ALERT")                          \
1414   _ (EMERG,  "EMERGENCY")
1415
1416 typedef enum
1417 {
1418 #define _(f,s) LOG_##f,
1419   foreach_log_level
1420 #undef _
1421 } log_level_t;
1422
1423 static char *log_level_strings[] = {
1424 #define _(f,s) s,
1425   foreach_log_level
1426 #undef _
1427 };
1428
1429 static int logmask = 1 << LOG_DEBUG;
1430
1431 static void
1432 ip6_neighbor_syslog (vlib_main_t * vm, int priority, char *fmt, ...)
1433 {
1434   /* just use elog for now */
1435   u8 *what;
1436   va_list va;
1437
1438   if ((priority > LOG_EMERG) || !(logmask & (1 << priority)))
1439     return;
1440
1441   va_start (va, fmt);
1442   if (fmt)
1443     {
1444       what = va_format (0, fmt, &va);
1445
1446       ELOG_TYPE_DECLARE (e) =
1447       {
1448       .format = "ip6 nd:  (%s): %s",.format_args = "T4T4",};
1449       struct
1450       {
1451         u32 s[2];
1452       } *ed;
1453       ed = ELOG_DATA (&vm->elog_main, e);
1454       ed->s[0] = elog_string (&vm->elog_main, log_level_strings[priority]);
1455       ed->s[1] = elog_string (&vm->elog_main, (char *) what);
1456     }
1457   va_end (va);
1458   return;
1459 }
1460
1461 clib_error_t *
1462 call_ip6_neighbor_callbacks (void *data,
1463                              _vnet_ip6_neighbor_function_list_elt_t * elt)
1464 {
1465   clib_error_t *error = 0;
1466
1467   while (elt)
1468     {
1469       error = elt->fp (data);
1470       if (error)
1471         return error;
1472       elt = elt->next_ip6_neighbor_function;
1473     }
1474
1475   return error;
1476 }
1477
1478 /* ipv6 neighbor discovery - router advertisements */
1479 typedef enum
1480 {
1481   ICMP6_ROUTER_SOLICITATION_NEXT_DROP,
1482   ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW,
1483   ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX,
1484   ICMP6_ROUTER_SOLICITATION_N_NEXT,
1485 } icmp6_router_solicitation_or_advertisement_next_t;
1486
1487 static_always_inline uword
1488 icmp6_router_solicitation (vlib_main_t * vm,
1489                            vlib_node_runtime_t * node, vlib_frame_t * frame)
1490 {
1491   vnet_main_t *vnm = vnet_get_main ();
1492   ip6_main_t *im = &ip6_main;
1493   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
1494   uword n_packets = frame->n_vectors;
1495   u32 *from, *to_next;
1496   u32 n_left_from, n_left_to_next, next_index;
1497   u32 n_advertisements_sent = 0;
1498   int bogus_length;
1499
1500   icmp6_neighbor_discovery_option_type_t option_type;
1501
1502   vlib_node_runtime_t *error_node =
1503     vlib_node_get_runtime (vm, ip6_icmp_input_node.index);
1504
1505   from = vlib_frame_vector_args (frame);
1506   n_left_from = n_packets;
1507   next_index = node->cached_next_index;
1508
1509   if (node->flags & VLIB_NODE_FLAG_TRACE)
1510     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
1511                                    /* stride */ 1,
1512                                    sizeof (icmp6_input_trace_t));
1513
1514   /* source may append his LL address */
1515   option_type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
1516
1517   while (n_left_from > 0)
1518     {
1519       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1520
1521       while (n_left_from > 0 && n_left_to_next > 0)
1522         {
1523           vlib_buffer_t *p0;
1524           ip6_header_t *ip0;
1525           ip6_radv_t *radv_info = 0;
1526
1527           icmp6_neighbor_discovery_header_t *h0;
1528           icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *o0;
1529
1530           u32 bi0, options_len0, sw_if_index0, next0, error0;
1531           u32 is_solicitation = 1, is_dropped = 0;
1532           u32 is_unspecified, is_link_local;
1533
1534           bi0 = to_next[0] = from[0];
1535
1536           from += 1;
1537           to_next += 1;
1538           n_left_from -= 1;
1539           n_left_to_next -= 1;
1540
1541           p0 = vlib_get_buffer (vm, bi0);
1542           ip0 = vlib_buffer_get_current (p0);
1543           h0 = ip6_next_header (ip0);
1544           options_len0 =
1545             clib_net_to_host_u16 (ip0->payload_length) - sizeof (h0[0]);
1546           is_unspecified = ip6_address_is_unspecified (&ip0->src_address);
1547           is_link_local =
1548             ip6_address_is_link_local_unicast (&ip0->src_address);
1549
1550           error0 = ICMP6_ERROR_NONE;
1551           sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1552
1553           /* check if solicitation  (not from nd_timer node) */
1554           if (ip6_address_is_unspecified (&ip0->dst_address))
1555             is_solicitation = 0;
1556
1557           /* Check that source address is unspecified, link-local or else on-link. */
1558           if (!is_unspecified && !is_link_local)
1559             {
1560               u32 src_adj_index0 = ip6_src_lookup_for_packet (im, p0, ip0);
1561
1562               if (ADJ_INDEX_INVALID != src_adj_index0)
1563                 {
1564                   ip_adjacency_t *adj0 = adj_get (src_adj_index0);
1565
1566                   error0 = (adj0->rewrite_header.sw_if_index != sw_if_index0
1567                             ?
1568                             ICMP6_ERROR_ROUTER_SOLICITATION_SOURCE_NOT_ON_LINK
1569                             : error0);
1570                 }
1571               else
1572                 {
1573                   error0 = ICMP6_ERROR_ROUTER_SOLICITATION_SOURCE_NOT_ON_LINK;
1574                 }
1575             }
1576
1577           /* check for source LL option and process */
1578           o0 = (void *) (h0 + 1);
1579           o0 = ((options_len0 == 8
1580                  && o0->header.type == option_type
1581                  && o0->header.n_data_u64s == 1) ? o0 : 0);
1582
1583           /* if src address unspecified IGNORE any options */
1584           if (PREDICT_TRUE (error0 == ICMP6_ERROR_NONE && o0 != 0 &&
1585                             !is_unspecified && !is_link_local))
1586             {
1587               vnet_set_ip6_ethernet_neighbor (vm, sw_if_index0,
1588                                               &ip0->src_address,
1589                                               o0->ethernet_address,
1590                                               sizeof (o0->ethernet_address),
1591                                               0, 0);
1592             }
1593
1594           /* default is to drop */
1595           next0 = ICMP6_ROUTER_SOLICITATION_NEXT_DROP;
1596
1597           if (error0 == ICMP6_ERROR_NONE)
1598             {
1599               vnet_sw_interface_t *sw_if0;
1600               ethernet_interface_t *eth_if0;
1601               u32 adj_index0;
1602
1603               sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
1604               ASSERT (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
1605               eth_if0 =
1606                 ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
1607
1608               /* only support ethernet interface type for now */
1609               error0 =
1610                 (!eth_if0) ? ICMP6_ERROR_ROUTER_SOLICITATION_UNSUPPORTED_INTF
1611                 : error0;
1612
1613               if (error0 == ICMP6_ERROR_NONE)
1614                 {
1615                   u32 ri;
1616
1617                   /* adjust the sizeof the buffer to just include the ipv6 header */
1618                   p0->current_length -=
1619                     (options_len0 +
1620                      sizeof (icmp6_neighbor_discovery_header_t));
1621
1622                   /* look up the radv_t information for this interface */
1623                   if (vec_len (nm->if_radv_pool_index_by_sw_if_index) >
1624                       sw_if_index0)
1625                     {
1626                       ri =
1627                         nm->if_radv_pool_index_by_sw_if_index[sw_if_index0];
1628
1629                       if (ri != ~0)
1630                         radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
1631                     }
1632
1633                   error0 =
1634                     ((!radv_info) ?
1635                      ICMP6_ERROR_ROUTER_SOLICITATION_RADV_NOT_CONFIG :
1636                      error0);
1637
1638                   if (error0 == ICMP6_ERROR_NONE)
1639                     {
1640                       f64 now = vlib_time_now (vm);
1641
1642                       /* for solicited adverts - need to rate limit */
1643                       if (is_solicitation)
1644                         {
1645                           if (0 != radv_info->last_radv_time &&
1646                               (now - radv_info->last_radv_time) <
1647                               MIN_DELAY_BETWEEN_RAS)
1648                             is_dropped = 1;
1649                           else
1650                             radv_info->last_radv_time = now;
1651                         }
1652
1653                       /* send now  */
1654                       icmp6_router_advertisement_header_t rh;
1655
1656                       rh.icmp.type = ICMP6_router_advertisement;
1657                       rh.icmp.code = 0;
1658                       rh.icmp.checksum = 0;
1659
1660                       rh.current_hop_limit = radv_info->curr_hop_limit;
1661                       rh.router_lifetime_in_sec =
1662                         clib_host_to_net_u16
1663                         (radv_info->adv_router_lifetime_in_sec);
1664                       rh.
1665                         time_in_msec_between_retransmitted_neighbor_solicitations
1666                         =
1667                         clib_host_to_net_u32 (radv_info->
1668                                               adv_time_in_msec_between_retransmitted_neighbor_solicitations);
1669                       rh.neighbor_reachable_time_in_msec =
1670                         clib_host_to_net_u32 (radv_info->
1671                                               adv_neighbor_reachable_time_in_msec);
1672
1673                       rh.flags =
1674                         (radv_info->adv_managed_flag) ?
1675                         ICMP6_ROUTER_DISCOVERY_FLAG_ADDRESS_CONFIG_VIA_DHCP :
1676                         0;
1677                       rh.flags |=
1678                         ((radv_info->adv_other_flag) ?
1679                          ICMP6_ROUTER_DISCOVERY_FLAG_OTHER_CONFIG_VIA_DHCP :
1680                          0);
1681
1682
1683                       u16 payload_length =
1684                         sizeof (icmp6_router_advertisement_header_t);
1685
1686                       vlib_buffer_add_data (vm,
1687                                             vlib_buffer_get_free_list_index
1688                                             (p0), bi0, (void *) &rh,
1689                                             sizeof
1690                                             (icmp6_router_advertisement_header_t));
1691
1692                       if (radv_info->adv_link_layer_address)
1693                         {
1694                           icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
1695                             h;
1696
1697                           h.header.type =
1698                             ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
1699                           h.header.n_data_u64s = 1;
1700
1701                           /* copy ll address */
1702                           clib_memcpy (&h.ethernet_address[0],
1703                                        eth_if0->address, 6);
1704
1705                           vlib_buffer_add_data (vm,
1706                                                 vlib_buffer_get_free_list_index
1707                                                 (p0), bi0, (void *) &h,
1708                                                 sizeof
1709                                                 (icmp6_neighbor_discovery_ethernet_link_layer_address_option_t));
1710
1711                           payload_length +=
1712                             sizeof
1713                             (icmp6_neighbor_discovery_ethernet_link_layer_address_option_t);
1714                         }
1715
1716                       /* add MTU option */
1717                       if (radv_info->adv_link_mtu)
1718                         {
1719                           icmp6_neighbor_discovery_mtu_option_t h;
1720
1721                           h.unused = 0;
1722                           h.mtu =
1723                             clib_host_to_net_u32 (radv_info->adv_link_mtu);
1724                           h.header.type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_mtu;
1725                           h.header.n_data_u64s = 1;
1726
1727                           payload_length +=
1728                             sizeof (icmp6_neighbor_discovery_mtu_option_t);
1729
1730                           vlib_buffer_add_data (vm,
1731                                                 vlib_buffer_get_free_list_index
1732                                                 (p0), bi0, (void *) &h,
1733                                                 sizeof
1734                                                 (icmp6_neighbor_discovery_mtu_option_t));
1735                         }
1736
1737                       /* add advertised prefix options  */
1738                       ip6_radv_prefix_t *pr_info;
1739
1740                       /* *INDENT-OFF* */
1741                       pool_foreach (pr_info, radv_info->adv_prefixes_pool,
1742                       ({
1743                         if(pr_info->enabled &&
1744                            (!pr_info->decrement_lifetime_flag
1745                             || (pr_info->pref_lifetime_expires >0)))
1746                           {
1747                             /* advertise this prefix */
1748                             icmp6_neighbor_discovery_prefix_information_option_t h;
1749
1750                             h.header.type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_prefix_information;
1751                             h.header.n_data_u64s  =  (sizeof(icmp6_neighbor_discovery_prefix_information_option_t) >> 3);
1752
1753                             h.dst_address_length  = pr_info->prefix_len;
1754
1755                             h.flags  = (pr_info->adv_on_link_flag) ? ICMP6_NEIGHBOR_DISCOVERY_PREFIX_INFORMATION_FLAG_ON_LINK : 0;
1756                             h.flags |= (pr_info->adv_autonomous_flag) ?  ICMP6_NEIGHBOR_DISCOVERY_PREFIX_INFORMATION_AUTO :  0;
1757
1758                             if(radv_info->cease_radv && pr_info->deprecated_prefix_flag)
1759                               {
1760                                 h.valid_time = clib_host_to_net_u32(MIN_ADV_VALID_LIFETIME);
1761                                 h.preferred_time  = 0;
1762                               }
1763                             else
1764                               {
1765                                 if(pr_info->decrement_lifetime_flag)
1766                                   {
1767                                     pr_info->adv_valid_lifetime_in_secs = ((pr_info->valid_lifetime_expires  > now)) ?
1768                                       (pr_info->valid_lifetime_expires  - now) : 0;
1769
1770                                     pr_info->adv_pref_lifetime_in_secs = ((pr_info->pref_lifetime_expires  > now)) ?
1771                                       (pr_info->pref_lifetime_expires  - now) : 0;
1772                                   }
1773
1774                                 h.valid_time = clib_host_to_net_u32(pr_info->adv_valid_lifetime_in_secs);
1775                                 h.preferred_time  = clib_host_to_net_u32(pr_info->adv_pref_lifetime_in_secs) ;
1776                               }
1777                             h.unused  = 0;
1778
1779                             clib_memcpy(&h.dst_address, &pr_info->prefix,  sizeof(ip6_address_t));
1780
1781                             payload_length += sizeof( icmp6_neighbor_discovery_prefix_information_option_t);
1782
1783                             vlib_buffer_add_data (vm,
1784                                             vlib_buffer_get_free_list_index (p0),
1785                                                   bi0,
1786                                                   (void *)&h, sizeof(icmp6_neighbor_discovery_prefix_information_option_t));
1787
1788                           }
1789                       }));
1790                       /* *INDENT-ON* */
1791
1792                       /* add additional options before here */
1793
1794                       /* finish building the router advertisement... */
1795                       if (!is_unspecified && radv_info->send_unicast)
1796                         {
1797                           ip0->dst_address = ip0->src_address;
1798                         }
1799                       else
1800                         {
1801                           /* target address is all-nodes mcast addr */
1802                           ip6_set_reserved_multicast_address
1803                             (&ip0->dst_address,
1804                              IP6_MULTICAST_SCOPE_link_local,
1805                              IP6_MULTICAST_GROUP_ID_all_hosts);
1806                         }
1807
1808                       /* source address MUST be the link-local address */
1809                       ip0->src_address = radv_info->link_local_address;
1810
1811                       ip0->hop_limit = 255;
1812                       ip0->payload_length =
1813                         clib_host_to_net_u16 (payload_length);
1814
1815                       icmp6_router_advertisement_header_t *rh0 =
1816                         (icmp6_router_advertisement_header_t *) (ip0 + 1);
1817                       rh0->icmp.checksum =
1818                         ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0,
1819                                                            &bogus_length);
1820                       ASSERT (bogus_length == 0);
1821
1822                       /* setup output if and adjacency */
1823                       vnet_buffer (p0)->sw_if_index[VLIB_RX] =
1824                         vnet_main.local_interface_sw_if_index;
1825
1826                       if (is_solicitation)
1827                         {
1828                           ethernet_header_t *eth0;
1829                           /* Reuse current MAC header, copy SMAC to DMAC and
1830                            * interface MAC to SMAC */
1831                           vlib_buffer_reset (p0);
1832                           eth0 = vlib_buffer_get_current (p0);
1833                           clib_memcpy (eth0->dst_address, eth0->src_address,
1834                                        6);
1835                           clib_memcpy (eth0->src_address, eth_if0->address,
1836                                        6);
1837                           next0 =
1838                             is_dropped ? next0 :
1839                             ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX;
1840                           vnet_buffer (p0)->sw_if_index[VLIB_TX] =
1841                             sw_if_index0;
1842                         }
1843                       else
1844                         {
1845                           adj_index0 = radv_info->mcast_adj_index;
1846                           if (adj_index0 == 0)
1847                             error0 = ICMP6_ERROR_DST_LOOKUP_MISS;
1848                           else
1849                             {
1850                               next0 =
1851                                 is_dropped ? next0 :
1852                                 ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW;
1853                               vnet_buffer (p0)->ip.adj_index[VLIB_TX] =
1854                                 adj_index0;
1855                             }
1856                         }
1857                       p0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
1858
1859                       radv_info->n_solicitations_dropped += is_dropped;
1860                       radv_info->n_solicitations_rcvd += is_solicitation;
1861
1862                       if ((error0 == ICMP6_ERROR_NONE) && !is_dropped)
1863                         {
1864                           radv_info->n_advertisements_sent++;
1865                           n_advertisements_sent++;
1866                         }
1867                     }
1868                 }
1869             }
1870
1871           p0->error = error_node->errors[error0];
1872
1873           if (error0 != ICMP6_ERROR_NONE)
1874             vlib_error_count (vm, error_node->node_index, error0, 1);
1875
1876           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1877                                            to_next, n_left_to_next,
1878                                            bi0, next0);
1879
1880         }
1881
1882       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1883     }
1884
1885   /* Account for router advertisements sent. */
1886   vlib_error_count (vm, error_node->node_index,
1887                     ICMP6_ERROR_ROUTER_ADVERTISEMENTS_TX,
1888                     n_advertisements_sent);
1889
1890   return frame->n_vectors;
1891 }
1892
1893  /* validate advertised info for consistancy (see RFC-4861 section 6.2.7) - log any inconsistencies, packet will always  be dropped  */
1894 static_always_inline uword
1895 icmp6_router_advertisement (vlib_main_t * vm,
1896                             vlib_node_runtime_t * node, vlib_frame_t * frame)
1897 {
1898   vnet_main_t *vnm = vnet_get_main ();
1899   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
1900   uword n_packets = frame->n_vectors;
1901   u32 *from, *to_next;
1902   u32 n_left_from, n_left_to_next, next_index;
1903   u32 n_advertisements_rcvd = 0;
1904
1905   vlib_node_runtime_t *error_node =
1906     vlib_node_get_runtime (vm, ip6_icmp_input_node.index);
1907
1908   from = vlib_frame_vector_args (frame);
1909   n_left_from = n_packets;
1910   next_index = node->cached_next_index;
1911
1912   if (node->flags & VLIB_NODE_FLAG_TRACE)
1913     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
1914                                    /* stride */ 1,
1915                                    sizeof (icmp6_input_trace_t));
1916
1917   while (n_left_from > 0)
1918     {
1919       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1920
1921       while (n_left_from > 0 && n_left_to_next > 0)
1922         {
1923           vlib_buffer_t *p0;
1924           ip6_header_t *ip0;
1925           ip6_radv_t *radv_info = 0;
1926           icmp6_router_advertisement_header_t *h0;
1927           u32 bi0, options_len0, sw_if_index0, next0, error0;
1928
1929           bi0 = to_next[0] = from[0];
1930
1931           from += 1;
1932           to_next += 1;
1933           n_left_from -= 1;
1934           n_left_to_next -= 1;
1935
1936           p0 = vlib_get_buffer (vm, bi0);
1937           ip0 = vlib_buffer_get_current (p0);
1938           h0 = ip6_next_header (ip0);
1939           options_len0 =
1940             clib_net_to_host_u16 (ip0->payload_length) - sizeof (h0[0]);
1941
1942           error0 = ICMP6_ERROR_NONE;
1943           sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1944
1945           /* Check that source address is link-local */
1946           error0 = (!ip6_address_is_link_local_unicast (&ip0->src_address)) ?
1947             ICMP6_ERROR_ROUTER_ADVERTISEMENT_SOURCE_NOT_LINK_LOCAL : error0;
1948
1949           /* default is to drop */
1950           next0 = ICMP6_ROUTER_SOLICITATION_NEXT_DROP;
1951
1952           n_advertisements_rcvd++;
1953
1954           if (error0 == ICMP6_ERROR_NONE)
1955             {
1956               vnet_sw_interface_t *sw_if0;
1957               ethernet_interface_t *eth_if0;
1958
1959               sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
1960               ASSERT (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
1961               eth_if0 =
1962                 ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
1963
1964               /* only support ethernet interface type for now */
1965               error0 =
1966                 (!eth_if0) ? ICMP6_ERROR_ROUTER_SOLICITATION_UNSUPPORTED_INTF
1967                 : error0;
1968
1969               if (error0 == ICMP6_ERROR_NONE)
1970                 {
1971                   u32 ri;
1972
1973                   /* look up the radv_t information for this interface */
1974                   if (vec_len (nm->if_radv_pool_index_by_sw_if_index) >
1975                       sw_if_index0)
1976                     {
1977                       ri =
1978                         nm->if_radv_pool_index_by_sw_if_index[sw_if_index0];
1979
1980                       if (ri != ~0)
1981                         radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
1982                     }
1983
1984                   error0 =
1985                     ((!radv_info) ?
1986                      ICMP6_ERROR_ROUTER_SOLICITATION_RADV_NOT_CONFIG :
1987                      error0);
1988
1989                   if (error0 == ICMP6_ERROR_NONE)
1990                     {
1991                       radv_info->keep_sending_rs = 0;
1992
1993                       ra_report_t r;
1994
1995                       r.sw_if_index = sw_if_index0;
1996                       memcpy (r.router_address, &ip0->src_address, 16);
1997                       r.current_hop_limit = h0->current_hop_limit;
1998                       r.flags = h0->flags;
1999                       r.router_lifetime_in_sec =
2000                         clib_net_to_host_u16 (h0->router_lifetime_in_sec);
2001                       r.neighbor_reachable_time_in_msec =
2002                         clib_net_to_host_u32
2003                         (h0->neighbor_reachable_time_in_msec);
2004                       r.time_in_msec_between_retransmitted_neighbor_solicitations = clib_net_to_host_u32 (h0->time_in_msec_between_retransmitted_neighbor_solicitations);
2005                       r.prefixes = 0;
2006
2007                       /* validate advertised information */
2008                       if ((h0->current_hop_limit && radv_info->curr_hop_limit)
2009                           && (h0->current_hop_limit !=
2010                               radv_info->curr_hop_limit))
2011                         {
2012                           ip6_neighbor_syslog (vm, LOG_WARNING,
2013                                                "our AdvCurHopLimit on %U doesn't agree with %U",
2014                                                format_vnet_sw_if_index_name,
2015                                                vnm, sw_if_index0,
2016                                                format_ip6_address,
2017                                                &ip0->src_address);
2018                         }
2019
2020                       if ((h0->flags &
2021                            ICMP6_ROUTER_DISCOVERY_FLAG_ADDRESS_CONFIG_VIA_DHCP)
2022                           != radv_info->adv_managed_flag)
2023                         {
2024                           ip6_neighbor_syslog (vm, LOG_WARNING,
2025                                                "our AdvManagedFlag on %U doesn't agree with %U",
2026                                                format_vnet_sw_if_index_name,
2027                                                vnm, sw_if_index0,
2028                                                format_ip6_address,
2029                                                &ip0->src_address);
2030                         }
2031
2032                       if ((h0->flags &
2033                            ICMP6_ROUTER_DISCOVERY_FLAG_OTHER_CONFIG_VIA_DHCP)
2034                           != radv_info->adv_other_flag)
2035                         {
2036                           ip6_neighbor_syslog (vm, LOG_WARNING,
2037                                                "our AdvOtherConfigFlag on %U doesn't agree with %U",
2038                                                format_vnet_sw_if_index_name,
2039                                                vnm, sw_if_index0,
2040                                                format_ip6_address,
2041                                                &ip0->src_address);
2042                         }
2043
2044                       if ((h0->
2045                            time_in_msec_between_retransmitted_neighbor_solicitations
2046                            && radv_info->
2047                            adv_time_in_msec_between_retransmitted_neighbor_solicitations)
2048                           && (h0->
2049                               time_in_msec_between_retransmitted_neighbor_solicitations
2050                               !=
2051                               clib_host_to_net_u32 (radv_info->
2052                                                     adv_time_in_msec_between_retransmitted_neighbor_solicitations)))
2053                         {
2054                           ip6_neighbor_syslog (vm, LOG_WARNING,
2055                                                "our AdvRetransTimer on %U doesn't agree with %U",
2056                                                format_vnet_sw_if_index_name,
2057                                                vnm, sw_if_index0,
2058                                                format_ip6_address,
2059                                                &ip0->src_address);
2060                         }
2061
2062                       if ((h0->neighbor_reachable_time_in_msec &&
2063                            radv_info->adv_neighbor_reachable_time_in_msec) &&
2064                           (h0->neighbor_reachable_time_in_msec !=
2065                            clib_host_to_net_u32
2066                            (radv_info->adv_neighbor_reachable_time_in_msec)))
2067                         {
2068                           ip6_neighbor_syslog (vm, LOG_WARNING,
2069                                                "our AdvReachableTime on %U doesn't agree with %U",
2070                                                format_vnet_sw_if_index_name,
2071                                                vnm, sw_if_index0,
2072                                                format_ip6_address,
2073                                                &ip0->src_address);
2074                         }
2075
2076                       /* check for MTU or prefix options or .. */
2077                       u8 *opt_hdr = (u8 *) (h0 + 1);
2078                       while (options_len0 > 0)
2079                         {
2080                           icmp6_neighbor_discovery_option_header_t *o0 =
2081                             (icmp6_neighbor_discovery_option_header_t *)
2082                             opt_hdr;
2083                           int opt_len = o0->n_data_u64s << 3;
2084                           icmp6_neighbor_discovery_option_type_t option_type =
2085                             o0->type;
2086
2087                           if (options_len0 < 2)
2088                             {
2089                               ip6_neighbor_syslog (vm, LOG_ERR,
2090                                                    "malformed RA packet on %U from %U",
2091                                                    format_vnet_sw_if_index_name,
2092                                                    vnm, sw_if_index0,
2093                                                    format_ip6_address,
2094                                                    &ip0->src_address);
2095                               break;
2096                             }
2097
2098                           if (opt_len == 0)
2099                             {
2100                               ip6_neighbor_syslog (vm, LOG_ERR,
2101                                                    " zero length option in RA on %U from %U",
2102                                                    format_vnet_sw_if_index_name,
2103                                                    vnm, sw_if_index0,
2104                                                    format_ip6_address,
2105                                                    &ip0->src_address);
2106                               break;
2107                             }
2108                           else if (opt_len > options_len0)
2109                             {
2110                               ip6_neighbor_syslog (vm, LOG_ERR,
2111                                                    "option length in RA packet  greater than total length on %U from %U",
2112                                                    format_vnet_sw_if_index_name,
2113                                                    vnm, sw_if_index0,
2114                                                    format_ip6_address,
2115                                                    &ip0->src_address);
2116                               break;
2117                             }
2118
2119                           options_len0 -= opt_len;
2120                           opt_hdr += opt_len;
2121
2122                           switch (option_type)
2123                             {
2124                             case ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address:
2125                               {
2126                                 icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
2127                                   * h =
2128                                   (icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
2129                                    *) (o0);
2130
2131                                 if (opt_len < sizeof (*h))
2132                                   break;
2133
2134                                 memcpy (r.slla, h->ethernet_address, 6);
2135                               }
2136                               break;
2137
2138                             case ICMP6_NEIGHBOR_DISCOVERY_OPTION_mtu:
2139                               {
2140                                 icmp6_neighbor_discovery_mtu_option_t *h =
2141                                   (icmp6_neighbor_discovery_mtu_option_t
2142                                    *) (o0);
2143
2144                                 if (opt_len < sizeof (*h))
2145                                   break;
2146
2147                                 r.mtu = clib_net_to_host_u32 (h->mtu);
2148
2149                                 if ((h->mtu && radv_info->adv_link_mtu) &&
2150                                     (h->mtu !=
2151                                      clib_host_to_net_u32
2152                                      (radv_info->adv_link_mtu)))
2153                                   {
2154                                     ip6_neighbor_syslog (vm, LOG_WARNING,
2155                                                          "our AdvLinkMTU on %U doesn't agree with %U",
2156                                                          format_vnet_sw_if_index_name,
2157                                                          vnm, sw_if_index0,
2158                                                          format_ip6_address,
2159                                                          &ip0->src_address);
2160                                   }
2161                               }
2162                               break;
2163
2164                             case ICMP6_NEIGHBOR_DISCOVERY_OPTION_prefix_information:
2165                               {
2166                                 icmp6_neighbor_discovery_prefix_information_option_t
2167                                   * h =
2168                                   (icmp6_neighbor_discovery_prefix_information_option_t
2169                                    *) (o0);
2170
2171                                 /* validate advertised prefix options  */
2172                                 ip6_radv_prefix_t *pr_info;
2173                                 u32 preferred, valid;
2174
2175                                 if (opt_len < sizeof (*h))
2176                                   break;
2177
2178                                 vec_validate (r.prefixes,
2179                                               vec_len (r.prefixes));
2180                                 ra_report_prefix_info_t *prefix =
2181                                   vec_elt_at_index (r.prefixes,
2182                                                     vec_len (r.prefixes) - 1);
2183
2184                                 preferred =
2185                                   clib_net_to_host_u32 (h->preferred_time);
2186                                 valid = clib_net_to_host_u32 (h->valid_time);
2187
2188                                 prefix->preferred_time = preferred;
2189                                 prefix->valid_time = valid;
2190                                 prefix->flags = h->flags & 0xc0;
2191                                 prefix->dst_address_length =
2192                                   h->dst_address_length;
2193                                 prefix->dst_address = h->dst_address;
2194
2195                                 /* look for matching prefix - if we our advertising it, it better be consistant */
2196                                 /* *INDENT-OFF* */
2197                                 pool_foreach (pr_info, radv_info->adv_prefixes_pool,
2198                                 ({
2199
2200                                   ip6_address_t mask;
2201                                   ip6_address_mask_from_width(&mask, pr_info->prefix_len);
2202
2203                                   if(pr_info->enabled &&
2204                                      (pr_info->prefix_len == h->dst_address_length) &&
2205                                      ip6_address_is_equal_masked (&pr_info->prefix,  &h->dst_address, &mask))
2206                                     {
2207                                       /* found it */
2208                                       if(!pr_info->decrement_lifetime_flag &&
2209                                          valid != pr_info->adv_valid_lifetime_in_secs)
2210                                         {
2211                                           ip6_neighbor_syslog(vm,  LOG_WARNING,
2212                                                               "our ADV validlifetime on  %U for %U does not  agree with %U",
2213                                                               format_vnet_sw_if_index_name, vnm, sw_if_index0,format_ip6_address, &pr_info->prefix,
2214                                                               format_ip6_address, &h->dst_address);
2215                                         }
2216                                       if(!pr_info->decrement_lifetime_flag &&
2217                                          preferred != pr_info->adv_pref_lifetime_in_secs)
2218                                         {
2219                                           ip6_neighbor_syslog(vm,  LOG_WARNING,
2220                                                               "our ADV preferredlifetime on  %U for %U does not  agree with %U",
2221                                                               format_vnet_sw_if_index_name, vnm, sw_if_index0,format_ip6_address, &pr_info->prefix,
2222                                                               format_ip6_address, &h->dst_address);
2223                                         }
2224                                     }
2225                                   break;
2226                                 }));
2227                                 /* *INDENT-ON* */
2228                                 break;
2229                               }
2230                             default:
2231                               /* skip this one */
2232                               break;
2233                             }
2234                         }
2235                       ra_publish (&r);
2236                     }
2237                 }
2238             }
2239
2240           p0->error = error_node->errors[error0];
2241
2242           if (error0 != ICMP6_ERROR_NONE)
2243             vlib_error_count (vm, error_node->node_index, error0, 1);
2244
2245           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2246                                            to_next, n_left_to_next,
2247                                            bi0, next0);
2248         }
2249
2250       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2251     }
2252
2253   /* Account for router advertisements received. */
2254   vlib_error_count (vm, error_node->node_index,
2255                     ICMP6_ERROR_ROUTER_ADVERTISEMENTS_RX,
2256                     n_advertisements_rcvd);
2257
2258   return frame->n_vectors;
2259 }
2260
2261 static inline f64
2262 random_f64_from_to (f64 from, f64 to)
2263 {
2264   static u32 seed = 0;
2265   static u8 seed_set = 0;
2266   if (!seed_set)
2267     {
2268       seed = random_default_seed ();
2269       seed_set = 1;
2270     }
2271   return random_f64 (&seed) * (to - from) + from;
2272 }
2273
2274 static inline u8
2275 get_mac_address (u32 sw_if_index, u8 * address)
2276 {
2277   vnet_main_t *vnm = vnet_get_main ();
2278   vnet_hw_interface_t *hw_if = vnet_get_sup_hw_interface (vnm, sw_if_index);
2279   if (!hw_if->hw_address)
2280     return 1;
2281   clib_memcpy (address, hw_if->hw_address, 6);
2282   return 0;
2283 }
2284
2285 static inline vlib_buffer_t *
2286 create_buffer_for_rs (vlib_main_t * vm, ip6_radv_t * radv_info)
2287 {
2288   u32 bi0;
2289   vlib_buffer_t *p0;
2290   vlib_buffer_free_list_t *fl;
2291   icmp6_router_solicitation_header_t *rh;
2292   u16 payload_length;
2293   int bogus_length;
2294   u32 sw_if_index;
2295
2296   sw_if_index = radv_info->sw_if_index;
2297
2298   if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
2299     {
2300       clib_warning ("buffer allocation failure");
2301       return 0;
2302     }
2303
2304   p0 = vlib_get_buffer (vm, bi0);
2305   fl = vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
2306   vlib_buffer_init_for_free_list (p0, fl);
2307   VLIB_BUFFER_TRACE_TRAJECTORY_INIT (p0);
2308   p0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
2309
2310   vnet_buffer (p0)->sw_if_index[VLIB_RX] = sw_if_index;
2311   vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index;
2312
2313   vnet_buffer (p0)->ip.adj_index[VLIB_TX] = radv_info->mcast_adj_index;
2314
2315   rh = vlib_buffer_get_current (p0);
2316   p0->current_length = sizeof (*rh);
2317
2318   rh->neighbor.icmp.type = ICMP6_router_solicitation;
2319   rh->neighbor.icmp.code = 0;
2320   rh->neighbor.icmp.checksum = 0;
2321   rh->neighbor.reserved_must_be_zero = 0;
2322
2323   rh->link_layer_option.header.type =
2324     ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
2325   if (0 != get_mac_address (sw_if_index,
2326                             rh->link_layer_option.ethernet_address))
2327     {
2328       clib_warning ("interface with sw_if_index %u has no mac address",
2329                     sw_if_index);
2330       vlib_buffer_free (vm, &bi0, 1);
2331       return 0;
2332     }
2333   rh->link_layer_option.header.n_data_u64s = 1;
2334
2335   payload_length = sizeof (rh->neighbor) + sizeof (u64);
2336
2337   rh->ip.ip_version_traffic_class_and_flow_label =
2338     clib_host_to_net_u32 (0x6 << 28);
2339   rh->ip.payload_length = clib_host_to_net_u16 (payload_length);
2340   rh->ip.protocol = IP_PROTOCOL_ICMP6;
2341   rh->ip.hop_limit = 255;
2342   rh->ip.src_address = radv_info->link_local_address;
2343   /* set address ff02::2 */
2344   rh->ip.dst_address.as_u64[0] = clib_host_to_net_u64 (0xff02L << 48);
2345   rh->ip.dst_address.as_u64[1] = clib_host_to_net_u64 (2);
2346
2347   rh->neighbor.icmp.checksum = ip6_tcp_udp_icmp_compute_checksum (vm, p0,
2348                                                                   &rh->ip,
2349                                                                   &bogus_length);
2350
2351   return p0;
2352 }
2353
2354 static inline void
2355 stop_sending_rs (vlib_main_t * vm, ip6_radv_t * ra)
2356 {
2357   u32 bi0;
2358
2359   ra->keep_sending_rs = 0;
2360   if (ra->buffer)
2361     {
2362       bi0 = vlib_get_buffer_index (vm, ra->buffer);
2363       vlib_buffer_free (vm, &bi0, 1);
2364       ra->buffer = 0;
2365     }
2366 }
2367
2368 static inline bool
2369 check_send_rs (vlib_main_t * vm, ip6_radv_t * radv_info, f64 current_time,
2370                f64 * due_time)
2371 {
2372   vlib_buffer_t *p0;
2373   vlib_frame_t *f;
2374   u32 *to_next;
2375   u32 next_index;
2376   vlib_buffer_t *c0;
2377   u32 ci0;
2378
2379   icmp6_send_router_solicitation_params_t *params;
2380
2381   if (!radv_info->keep_sending_rs)
2382     return false;
2383
2384   params = &radv_info->params;
2385
2386   if (radv_info->due_time > current_time)
2387     {
2388       *due_time = radv_info->due_time;
2389       return true;
2390     }
2391
2392   p0 = radv_info->buffer;
2393
2394   next_index = ip6_rewrite_mcast_node.index;
2395
2396   c0 = vlib_buffer_copy (vm, p0);
2397   ci0 = vlib_get_buffer_index (vm, c0);
2398
2399   f = vlib_get_frame_to_node (vm, next_index);
2400   to_next = vlib_frame_vector_args (f);
2401   to_next[0] = ci0;
2402   f->n_vectors = 1;
2403   vlib_put_frame_to_node (vm, next_index, f);
2404
2405   if (params->mrc != 0 && --radv_info->n_left == 0)
2406     stop_sending_rs (vm, radv_info);
2407   else
2408     {
2409       radv_info->sleep_interval =
2410         (2 + random_f64_from_to (-0.1, 0.1)) * radv_info->sleep_interval;
2411       if (radv_info->sleep_interval > params->mrt)
2412         radv_info->sleep_interval =
2413           (1 + random_f64_from_to (-0.1, 0.1)) * params->mrt;
2414
2415       radv_info->due_time = current_time + radv_info->sleep_interval;
2416
2417       if (params->mrd != 0
2418           && current_time > radv_info->start_time + params->mrd)
2419         stop_sending_rs (vm, radv_info);
2420       else
2421         *due_time = radv_info->due_time;
2422     }
2423
2424   return radv_info->keep_sending_rs;
2425 }
2426
2427 static uword
2428 send_rs_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
2429                  vlib_frame_t * f0)
2430 {
2431   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
2432   ip6_radv_t *radv_info;
2433   uword *event_data = 0;
2434   f64 sleep_time = 1e9;
2435   f64 current_time;
2436   f64 due_time;
2437   f64 dt = 0;
2438
2439   while (true)
2440     {
2441       vlib_process_wait_for_event_or_clock (vm, sleep_time);
2442       vlib_process_get_events (vm, &event_data);
2443       vec_reset_length (event_data);
2444
2445       current_time = vlib_time_now (vm);
2446       do
2447         {
2448           due_time = current_time + 1e9;
2449         /* *INDENT-OFF* */
2450         pool_foreach (radv_info, nm->if_radv_pool,
2451         ({
2452             if (check_send_rs (vm, radv_info, current_time, &dt)
2453                 && (dt < due_time))
2454               due_time = dt;
2455         }));
2456         /* *INDENT-ON* */
2457           current_time = vlib_time_now (vm);
2458         }
2459       while (due_time < current_time);
2460
2461       sleep_time = due_time - current_time;
2462     }
2463
2464   return 0;
2465 }
2466
2467 /* *INDENT-OFF* */
2468 VLIB_REGISTER_NODE (send_rs_process_node) = {
2469     .function = send_rs_process,
2470     .type = VLIB_NODE_TYPE_PROCESS,
2471     .name = "send-rs-process",
2472 };
2473 /* *INDENT-ON* */
2474
2475 void
2476 icmp6_send_router_solicitation (vlib_main_t * vm, u32 sw_if_index, u8 stop,
2477                                 icmp6_send_router_solicitation_params_t *
2478                                 params)
2479 {
2480   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
2481   u32 rai;
2482   ip6_radv_t *ra = 0;
2483
2484   ASSERT (~0 != sw_if_index);
2485
2486   rai = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2487   ra = pool_elt_at_index (nm->if_radv_pool, rai);
2488
2489   stop_sending_rs (vm, ra);
2490
2491   if (!stop)
2492     {
2493       ra->keep_sending_rs = 1;
2494       ra->params = *params;
2495       ra->n_left = params->mrc;
2496       ra->start_time = vlib_time_now (vm);
2497       ra->sleep_interval = (1 + random_f64_from_to (-0.1, 0.1)) * params->irt;
2498       ra->due_time = 0;         /* send first packet ASAP */
2499       ra->buffer = create_buffer_for_rs (vm, ra);
2500       if (!ra->buffer)
2501         ra->keep_sending_rs = 0;
2502       else
2503         vlib_process_signal_event (vm, send_rs_process_node.index, 1, 0);
2504     }
2505 }
2506
2507 /**
2508  * @brief Add a multicast Address to the advertised MLD set
2509  */
2510 static void
2511 ip6_neighbor_add_mld_prefix (ip6_radv_t * radv_info, ip6_address_t * addr)
2512 {
2513   ip6_mldp_group_t *mcast_group_info;
2514   uword *p;
2515
2516   /* lookup  mldp info for this interface */
2517   p = mhash_get (&radv_info->address_to_mldp_index, addr);
2518   mcast_group_info =
2519     p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0;
2520
2521   /* add address */
2522   if (!mcast_group_info)
2523     {
2524       /* add */
2525       u32 mi;
2526       pool_get (radv_info->mldp_group_pool, mcast_group_info);
2527
2528       mi = mcast_group_info - radv_info->mldp_group_pool;
2529       mhash_set (&radv_info->address_to_mldp_index, addr, mi,   /* old_value */
2530                  0);
2531
2532       mcast_group_info->type = 4;
2533       mcast_group_info->mcast_source_address_pool = 0;
2534       mcast_group_info->num_sources = 0;
2535       clib_memcpy (&mcast_group_info->mcast_address, addr,
2536                    sizeof (ip6_address_t));
2537     }
2538 }
2539
2540 /**
2541  * @brief Delete a multicast Address from the advertised MLD set
2542  */
2543 static void
2544 ip6_neighbor_del_mld_prefix (ip6_radv_t * radv_info, ip6_address_t * addr)
2545 {
2546   ip6_mldp_group_t *mcast_group_info;
2547   uword *p;
2548
2549   p = mhash_get (&radv_info->address_to_mldp_index, &addr);
2550   mcast_group_info =
2551     p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0;
2552
2553   if (mcast_group_info)
2554     {
2555       mhash_unset (&radv_info->address_to_mldp_index, &addr,
2556                    /* old_value */ 0);
2557       pool_put (radv_info->mldp_group_pool, mcast_group_info);
2558     }
2559 }
2560
2561 /**
2562  * @brief Add a multicast Address to the advertised MLD set
2563  */
2564 static void
2565 ip6_neighbor_add_mld_grp (ip6_radv_t * a,
2566                           ip6_multicast_address_scope_t scope,
2567                           ip6_multicast_link_local_group_id_t group)
2568 {
2569   ip6_address_t addr;
2570
2571   ip6_set_reserved_multicast_address (&addr, scope, group);
2572
2573   ip6_neighbor_add_mld_prefix (a, &addr);
2574 }
2575
2576 /**
2577  * @brief create and initialize router advertisement parameters with default
2578  * values for this intfc
2579  */
2580 u32
2581 ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm,
2582                                    u32 sw_if_index, u32 is_add)
2583 {
2584   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
2585   ip6_radv_t *a = 0;
2586   u32 ri = ~0;
2587   vnet_sw_interface_t *sw_if0;
2588   ethernet_interface_t *eth_if0 = 0;
2589
2590   /* lookup radv container  - ethernet interfaces only */
2591   sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
2592   if (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
2593     eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
2594
2595   if (!eth_if0)
2596     return ri;
2597
2598   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index,
2599                            ~0);
2600   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2601
2602   if (ri != ~0)
2603     {
2604       a = pool_elt_at_index (nm->if_radv_pool, ri);
2605
2606       if (!is_add)
2607         {
2608           ip6_radv_prefix_t *p;
2609           ip6_mldp_group_t *m;
2610
2611           /* release the lock on the interface's mcast adj */
2612           adj_unlock (a->mcast_adj_index);
2613
2614           /* clean up prefix and MDP pools */
2615           /* *INDENT-OFF* */
2616           pool_flush(p, a->adv_prefixes_pool,
2617           ({
2618               mhash_unset (&a->address_to_prefix_index, &p->prefix, 0);
2619           }));
2620           pool_flush (m, a->mldp_group_pool,
2621           ({
2622               mhash_unset (&a->address_to_mldp_index, &m->mcast_address, 0);
2623           }));
2624           /* *INDENT-ON* */
2625
2626           pool_free (a->mldp_group_pool);
2627           pool_free (a->adv_prefixes_pool);
2628
2629           mhash_free (&a->address_to_prefix_index);
2630           mhash_free (&a->address_to_mldp_index);
2631
2632           if (a->keep_sending_rs)
2633             a->keep_sending_rs = 0;
2634
2635           pool_put (nm->if_radv_pool, a);
2636           nm->if_radv_pool_index_by_sw_if_index[sw_if_index] = ~0;
2637           ri = ~0;
2638         }
2639     }
2640   else
2641     {
2642       if (is_add)
2643         {
2644           pool_get (nm->if_radv_pool, a);
2645
2646           ri = a - nm->if_radv_pool;
2647           nm->if_radv_pool_index_by_sw_if_index[sw_if_index] = ri;
2648
2649           /* initialize default values (most of which are zero) */
2650           memset (a, 0, sizeof (a[0]));
2651
2652           a->sw_if_index = sw_if_index;
2653           a->max_radv_interval = DEF_MAX_RADV_INTERVAL;
2654           a->min_radv_interval = DEF_MIN_RADV_INTERVAL;
2655           a->curr_hop_limit = DEF_CURR_HOP_LIMIT;
2656           a->adv_router_lifetime_in_sec = DEF_DEF_RTR_LIFETIME;
2657
2658           /* send ll address source address option */
2659           a->adv_link_layer_address = 1;
2660
2661           a->min_delay_between_radv = MIN_DELAY_BETWEEN_RAS;
2662           a->max_delay_between_radv = MAX_DELAY_BETWEEN_RAS;
2663           a->max_rtr_default_lifetime = MAX_DEF_RTR_LIFETIME;
2664           a->seed = (u32) clib_cpu_time_now ();
2665           (void) random_u32 (&a->seed);
2666           a->randomizer = clib_cpu_time_now ();
2667           (void) random_u64 (&a->randomizer);
2668
2669           a->initial_adverts_count = MAX_INITIAL_RTR_ADVERTISEMENTS;
2670           a->initial_adverts_sent = a->initial_adverts_count - 1;
2671           a->initial_adverts_interval = MAX_INITIAL_RTR_ADVERT_INTERVAL;
2672
2673           /* deafult is to send */
2674           a->send_radv = 1;
2675
2676           /* fill in radv_info for this interface that will be needed later */
2677           a->adv_link_mtu =
2678             vnet_sw_interface_get_mtu (vnm, sw_if_index, VNET_MTU_IP6);
2679
2680           clib_memcpy (a->link_layer_address, eth_if0->address, 6);
2681
2682           /* fill in default link-local address  (this may be overridden) */
2683           ip6_link_local_address_from_ethernet_address
2684             (&a->link_local_address, eth_if0->address);
2685
2686           mhash_init (&a->address_to_prefix_index, sizeof (uword),
2687                       sizeof (ip6_address_t));
2688           mhash_init (&a->address_to_mldp_index, sizeof (uword),
2689                       sizeof (ip6_address_t));
2690
2691           a->mcast_adj_index = adj_mcast_add_or_lock (FIB_PROTOCOL_IP6,
2692                                                       VNET_LINK_IP6,
2693                                                       sw_if_index);
2694
2695           a->keep_sending_rs = 0;
2696
2697           /* add multicast groups we will always be reporting  */
2698           ip6_neighbor_add_mld_grp (a,
2699                                     IP6_MULTICAST_SCOPE_link_local,
2700                                     IP6_MULTICAST_GROUP_ID_all_hosts);
2701           ip6_neighbor_add_mld_grp (a,
2702                                     IP6_MULTICAST_SCOPE_link_local,
2703                                     IP6_MULTICAST_GROUP_ID_all_routers);
2704           ip6_neighbor_add_mld_grp (a,
2705                                     IP6_MULTICAST_SCOPE_link_local,
2706                                     IP6_MULTICAST_GROUP_ID_mldv2_routers);
2707         }
2708     }
2709   return ri;
2710 }
2711
2712 /* send an mldpv2 report  */
2713 static void
2714 ip6_neighbor_send_mldpv2_report (u32 sw_if_index)
2715 {
2716   vnet_main_t *vnm = vnet_get_main ();
2717   vlib_main_t *vm = vnm->vlib_main;
2718   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
2719   vnet_sw_interface_t *sw_if0;
2720   ethernet_interface_t *eth_if0;
2721   u32 ri;
2722   int bogus_length;
2723
2724   ip6_radv_t *radv_info;
2725   u16 payload_length;
2726   vlib_buffer_t *b0;
2727   ip6_header_t *ip0;
2728   u32 *to_next;
2729   vlib_frame_t *f;
2730   u32 bo0;
2731   u32 n_to_alloc = 1;
2732   u32 n_allocated;
2733
2734   icmp6_multicast_listener_report_header_t *rh0;
2735   icmp6_multicast_listener_report_packet_t *rp0;
2736
2737   sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
2738   ASSERT (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
2739   eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
2740
2741   if (!eth_if0 || !vnet_sw_interface_is_admin_up (vnm, sw_if_index))
2742     return;
2743
2744   /* look up the radv_t  information for this interface */
2745   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index,
2746                            ~0);
2747
2748   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2749
2750   if (ri == ~0)
2751     return;
2752
2753   /* send report now - build a mldpv2 report packet  */
2754   n_allocated = vlib_buffer_alloc_from_free_list (vm,
2755                                                   &bo0,
2756                                                   n_to_alloc,
2757                                                   VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
2758   if (PREDICT_FALSE (n_allocated == 0))
2759     {
2760       clib_warning ("buffer allocation failure");
2761       return;
2762     }
2763
2764   b0 = vlib_get_buffer (vm, bo0);
2765
2766   /* adjust the sizeof the buffer to just include the ipv6 header */
2767   b0->current_length = sizeof (icmp6_multicast_listener_report_packet_t);
2768
2769   payload_length = sizeof (icmp6_multicast_listener_report_header_t);
2770
2771   b0->error = ICMP6_ERROR_NONE;
2772
2773   rp0 = vlib_buffer_get_current (b0);
2774   ip0 = (ip6_header_t *) & rp0->ip;
2775   rh0 = (icmp6_multicast_listener_report_header_t *) & rp0->report_hdr;
2776
2777   memset (rp0, 0x0, sizeof (icmp6_multicast_listener_report_packet_t));
2778
2779   ip0->ip_version_traffic_class_and_flow_label =
2780     clib_host_to_net_u32 (0x6 << 28);
2781
2782   ip0->protocol = IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS;
2783   /* for DEBUG - vnet driver won't seem to emit router alerts */
2784   /* ip0->protocol = IP_PROTOCOL_ICMP6; */
2785   ip0->hop_limit = 1;
2786
2787   rh0->icmp.type = ICMP6_multicast_listener_report_v2;
2788
2789   /* source address MUST be the link-local address */
2790   radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
2791   ip0->src_address = radv_info->link_local_address;
2792
2793   /* destination is all mldpv2 routers */
2794   ip6_set_reserved_multicast_address (&ip0->dst_address,
2795                                       IP6_MULTICAST_SCOPE_link_local,
2796                                       IP6_MULTICAST_GROUP_ID_mldv2_routers);
2797
2798   /* add reports here */
2799   ip6_mldp_group_t *m;
2800   int num_addr_records = 0;
2801   icmp6_multicast_address_record_t rr;
2802
2803   /* fill in the hop-by-hop extension header (router alert) info */
2804   rh0->ext_hdr.next_hdr = IP_PROTOCOL_ICMP6;
2805   rh0->ext_hdr.n_data_u64s = 0;
2806
2807   rh0->alert.type = IP6_MLDP_ALERT_TYPE;
2808   rh0->alert.len = 2;
2809   rh0->alert.value = 0;
2810
2811   rh0->pad.type = 1;
2812   rh0->pad.len = 0;
2813
2814   rh0->icmp.checksum = 0;
2815
2816   /* *INDENT-OFF* */
2817   pool_foreach (m, radv_info->mldp_group_pool,
2818   ({
2819     rr.type = m->type;
2820     rr.aux_data_len_u32s = 0;
2821     rr.num_sources = clib_host_to_net_u16 (m->num_sources);
2822     clib_memcpy(&rr.mcast_addr, &m->mcast_address, sizeof(ip6_address_t));
2823
2824     num_addr_records++;
2825
2826     vlib_buffer_add_data
2827       (vm, vlib_buffer_get_free_list_index (b0), bo0,
2828        (void *)&rr, sizeof(icmp6_multicast_address_record_t));
2829
2830     payload_length += sizeof( icmp6_multicast_address_record_t);
2831   }));
2832   /* *INDENT-ON* */
2833
2834   rh0->rsvd = 0;
2835   rh0->num_addr_records = clib_host_to_net_u16 (num_addr_records);
2836
2837   /* update lengths */
2838   ip0->payload_length = clib_host_to_net_u16 (payload_length);
2839
2840   rh0->icmp.checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0,
2841                                                           &bogus_length);
2842   ASSERT (bogus_length == 0);
2843
2844   /*
2845    * OK to override w/ no regard for actual FIB, because
2846    * ip6-rewrite only looks at the adjacency.
2847    */
2848   vnet_buffer (b0)->sw_if_index[VLIB_RX] =
2849     vnet_main.local_interface_sw_if_index;
2850
2851   vnet_buffer (b0)->ip.adj_index[VLIB_TX] = radv_info->mcast_adj_index;
2852   b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
2853
2854   vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "ip6-rewrite-mcast");
2855
2856   f = vlib_get_frame_to_node (vm, node->index);
2857   to_next = vlib_frame_vector_args (f);
2858   to_next[0] = bo0;
2859   f->n_vectors = 1;
2860
2861   vlib_put_frame_to_node (vm, node->index, f);
2862   return;
2863 }
2864
2865 /* *INDENT-OFF* */
2866 VLIB_REGISTER_NODE (ip6_icmp_router_solicitation_node,static) =
2867 {
2868   .function = icmp6_router_solicitation,
2869   .name = "icmp6-router-solicitation",
2870
2871   .vector_size = sizeof (u32),
2872
2873   .format_trace = format_icmp6_input_trace,
2874
2875   .n_next_nodes = ICMP6_ROUTER_SOLICITATION_N_NEXT,
2876   .next_nodes = {
2877     [ICMP6_ROUTER_SOLICITATION_NEXT_DROP] = "ip6-drop",
2878     [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW] = "ip6-rewrite-mcast",
2879     [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX] = "interface-output",
2880   },
2881 };
2882 /* *INDENT-ON* */
2883
2884 /* send a RA or update the timer info etc.. */
2885 static uword
2886 ip6_neighbor_process_timer_event (vlib_main_t * vm,
2887                                   vlib_node_runtime_t * node,
2888                                   vlib_frame_t * frame)
2889 {
2890   vnet_main_t *vnm = vnet_get_main ();
2891   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
2892   ip6_radv_t *radv_info;
2893   vlib_frame_t *f = 0;
2894   u32 n_this_frame = 0;
2895   u32 n_left_to_next = 0;
2896   u32 *to_next = 0;
2897   u32 bo0;
2898   icmp6_router_solicitation_header_t *h0;
2899   vlib_buffer_t *b0;
2900   f64 now = vlib_time_now (vm);
2901
2902   /* Interface ip6 radv info list */
2903   /* *INDENT-OFF* */
2904   pool_foreach (radv_info, nm->if_radv_pool,
2905   ({
2906     if( !vnet_sw_interface_is_admin_up (vnm, radv_info->sw_if_index))
2907       {
2908         radv_info->initial_adverts_sent = radv_info->initial_adverts_count-1;
2909         radv_info->next_multicast_time = now;
2910         radv_info->last_multicast_time = now;
2911         radv_info->last_radv_time = 0;
2912         radv_info->all_routers_mcast = 0;
2913         continue;
2914       }
2915
2916     /* Make sure that we've joined the all-routers multicast group */
2917     if(!radv_info->all_routers_mcast)
2918       {
2919         /* send MDLP_REPORT_EVENT message */
2920         ip6_neighbor_send_mldpv2_report(radv_info->sw_if_index);
2921         radv_info->all_routers_mcast = 1;
2922       }
2923
2924     /* is it time to send a multicast  RA on this interface? */
2925     if(radv_info->send_radv && (now >=  radv_info->next_multicast_time))
2926       {
2927         u32 n_to_alloc = 1;
2928         u32 n_allocated;
2929
2930         f64 rfn = (radv_info->max_radv_interval - radv_info->min_radv_interval) *
2931           random_f64 (&radv_info->seed) + radv_info->min_radv_interval;
2932
2933         /* multicast send - compute next multicast send time */
2934         if( radv_info->initial_adverts_sent > 0)
2935           {
2936             radv_info->initial_adverts_sent--;
2937             if(rfn > radv_info-> initial_adverts_interval)
2938               rfn =  radv_info-> initial_adverts_interval;
2939
2940             /* check to see if we are ceasing to send */
2941             if( radv_info->initial_adverts_sent  == 0)
2942               if(radv_info->cease_radv)
2943                 radv_info->send_radv = 0;
2944           }
2945
2946         radv_info->next_multicast_time =  rfn + now;
2947         radv_info->last_multicast_time = now;
2948
2949         /* send advert now - build a "solicted" router advert with unspecified source address */
2950         n_allocated = vlib_buffer_alloc_from_free_list
2951           (vm, &bo0, n_to_alloc, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
2952
2953         if (PREDICT_FALSE(n_allocated == 0))
2954           {
2955             clib_warning ("buffer allocation failure");
2956             continue;
2957           }
2958         b0 = vlib_get_buffer (vm, bo0);
2959         b0->current_length = sizeof( icmp6_router_solicitation_header_t);
2960         b0->error = ICMP6_ERROR_NONE;
2961         vnet_buffer (b0)->sw_if_index[VLIB_RX] = radv_info->sw_if_index;
2962
2963         h0 =  vlib_buffer_get_current (b0);
2964
2965         memset (h0, 0, sizeof (icmp6_router_solicitation_header_t));
2966
2967         h0->ip.ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (0x6 << 28);
2968         h0->ip.payload_length = clib_host_to_net_u16 (sizeof (icmp6_router_solicitation_header_t)
2969                                                       - STRUCT_OFFSET_OF (icmp6_router_solicitation_header_t, neighbor));
2970         h0->ip.protocol = IP_PROTOCOL_ICMP6;
2971         h0->ip.hop_limit = 255;
2972
2973         /* set src/dst address as "unspecified" this marks this packet as internally generated rather than recieved */
2974         h0->ip.src_address.as_u64[0] = 0;
2975         h0->ip.src_address.as_u64[1] = 0;
2976
2977         h0->ip.dst_address.as_u64[0] = 0;
2978         h0->ip.dst_address.as_u64[1] = 0;
2979
2980         h0->neighbor.icmp.type = ICMP6_router_solicitation;
2981
2982         if (PREDICT_FALSE(f == 0))
2983           {
2984             f = vlib_get_frame_to_node (vm, ip6_icmp_router_solicitation_node.index);
2985             to_next = vlib_frame_vector_args (f);
2986             n_left_to_next = VLIB_FRAME_SIZE;
2987             n_this_frame = 0;
2988           }
2989
2990         n_this_frame++;
2991         n_left_to_next--;
2992         to_next[0] = bo0;
2993         to_next += 1;
2994
2995         if (PREDICT_FALSE(n_left_to_next == 0))
2996           {
2997             f->n_vectors = n_this_frame;
2998             vlib_put_frame_to_node (vm, ip6_icmp_router_solicitation_node.index, f);
2999             f = 0;
3000           }
3001       }
3002   }));
3003   /* *INDENT-ON* */
3004
3005   if (f)
3006     {
3007       ASSERT (n_this_frame);
3008       f->n_vectors = n_this_frame;
3009       vlib_put_frame_to_node (vm, ip6_icmp_router_solicitation_node.index, f);
3010     }
3011   return 0;
3012 }
3013
3014 static uword
3015 ip6_icmp_neighbor_discovery_event_process (vlib_main_t * vm,
3016                                            vlib_node_runtime_t * node,
3017                                            vlib_frame_t * frame)
3018 {
3019   uword event_type;
3020   ip6_icmp_neighbor_discovery_event_data_t *event_data;
3021
3022   /* init code here */
3023
3024   while (1)
3025     {
3026       vlib_process_wait_for_event_or_clock (vm, 1. /* seconds */ );
3027
3028       event_data = vlib_process_get_event_data (vm, &event_type);
3029
3030       if (!event_data)
3031         {
3032           /* No events found: timer expired. */
3033           /* process interface list and send RAs as appropriate, update timer info */
3034           ip6_neighbor_process_timer_event (vm, node, frame);
3035         }
3036       else
3037         {
3038           switch (event_type)
3039             {
3040
3041             case ICMP6_ND_EVENT_INIT:
3042               break;
3043
3044             case ~0:
3045               break;
3046
3047             default:
3048               ASSERT (0);
3049             }
3050
3051           if (event_data)
3052             _vec_len (event_data) = 0;
3053         }
3054     }
3055   return frame->n_vectors;
3056 }
3057
3058 /* *INDENT-OFF* */
3059 VLIB_REGISTER_NODE (ip6_icmp_router_advertisement_node,static) =
3060 {
3061   .function = icmp6_router_advertisement,
3062   .name = "icmp6-router-advertisement",
3063
3064   .vector_size = sizeof (u32),
3065
3066   .format_trace = format_icmp6_input_trace,
3067
3068   .n_next_nodes = 1,
3069   .next_nodes = {
3070     [0] = "ip6-drop",
3071   },
3072 };
3073 /* *INDENT-ON* */
3074
3075 vlib_node_registration_t ip6_icmp_neighbor_discovery_event_node = {
3076
3077   .function = ip6_icmp_neighbor_discovery_event_process,
3078   .name = "ip6-icmp-neighbor-discovery-event-process",
3079   .type = VLIB_NODE_TYPE_PROCESS,
3080 };
3081
3082 static uword
3083 icmp6_neighbor_solicitation (vlib_main_t * vm,
3084                              vlib_node_runtime_t * node, vlib_frame_t * frame)
3085 {
3086   return icmp6_neighbor_solicitation_or_advertisement (vm, node, frame,
3087                                                        /* is_solicitation */
3088                                                        1);
3089 }
3090
3091 static uword
3092 icmp6_neighbor_advertisement (vlib_main_t * vm,
3093                               vlib_node_runtime_t * node,
3094                               vlib_frame_t * frame)
3095 {
3096   return icmp6_neighbor_solicitation_or_advertisement (vm, node, frame,
3097                                                        /* is_solicitation */
3098                                                        0);
3099 }
3100
3101 /* *INDENT-OFF* */
3102 VLIB_REGISTER_NODE (ip6_icmp_neighbor_solicitation_node,static) =
3103 {
3104   .function = icmp6_neighbor_solicitation,
3105   .name = "icmp6-neighbor-solicitation",
3106
3107   .vector_size = sizeof (u32),
3108
3109   .format_trace = format_icmp6_input_trace,
3110
3111   .n_next_nodes = ICMP6_NEIGHBOR_SOLICITATION_N_NEXT,
3112   .next_nodes = {
3113     [ICMP6_NEIGHBOR_SOLICITATION_NEXT_DROP] = "ip6-drop",
3114     [ICMP6_NEIGHBOR_SOLICITATION_NEXT_REPLY] = "interface-output",
3115   },
3116 };
3117 /* *INDENT-ON* */
3118
3119 /* *INDENT-OFF* */
3120 VLIB_REGISTER_NODE (ip6_icmp_neighbor_advertisement_node,static) =
3121 {
3122   .function = icmp6_neighbor_advertisement,
3123   .name = "icmp6-neighbor-advertisement",
3124
3125   .vector_size = sizeof (u32),
3126
3127   .format_trace = format_icmp6_input_trace,
3128
3129   .n_next_nodes = 1,
3130   .next_nodes = {
3131     [0] = "ip6-drop",
3132   },
3133 };
3134 /* *INDENT-ON* */
3135
3136 typedef enum
3137 {
3138   IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
3139   IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX,
3140   IP6_DISCOVER_NEIGHBOR_N_NEXT,
3141 } ip6_discover_neighbor_next_t;
3142
3143 typedef enum
3144 {
3145   IP6_DISCOVER_NEIGHBOR_ERROR_DROP,
3146   IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT,
3147   IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS,
3148 } ip6_discover_neighbor_error_t;
3149
3150 static uword
3151 ip6_discover_neighbor_inline (vlib_main_t * vm,
3152                               vlib_node_runtime_t * node,
3153                               vlib_frame_t * frame, int is_glean)
3154 {
3155   vnet_main_t *vnm = vnet_get_main ();
3156   ip6_main_t *im = &ip6_main;
3157   ip_lookup_main_t *lm = &im->lookup_main;
3158   u32 *from, *to_next_drop;
3159   uword n_left_from, n_left_to_next_drop;
3160   static f64 time_last_seed_change = -1e100;
3161   static u32 hash_seeds[3];
3162   static uword hash_bitmap[256 / BITS (uword)];
3163   f64 time_now;
3164   int bogus_length;
3165   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
3166
3167   if (node->flags & VLIB_NODE_FLAG_TRACE)
3168     ip6_forward_next_trace (vm, node, frame, VLIB_TX);
3169
3170   time_now = vlib_time_now (vm);
3171   if (time_now - time_last_seed_change > 1e-3)
3172     {
3173       uword i;
3174       u32 *r = clib_random_buffer_get_data (&vm->random_buffer,
3175                                             sizeof (hash_seeds));
3176       for (i = 0; i < ARRAY_LEN (hash_seeds); i++)
3177         hash_seeds[i] = r[i];
3178
3179       /* Mark all hash keys as been not-seen before. */
3180       for (i = 0; i < ARRAY_LEN (hash_bitmap); i++)
3181         hash_bitmap[i] = 0;
3182
3183       time_last_seed_change = time_now;
3184     }
3185
3186   from = vlib_frame_vector_args (frame);
3187   n_left_from = frame->n_vectors;
3188
3189   while (n_left_from > 0)
3190     {
3191       vlib_get_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
3192                            to_next_drop, n_left_to_next_drop);
3193
3194       while (n_left_from > 0 && n_left_to_next_drop > 0)
3195         {
3196           vlib_buffer_t *p0;
3197           ip6_header_t *ip0;
3198           u32 pi0, adj_index0, a0, b0, c0, m0, sw_if_index0, drop0;
3199           uword bm0;
3200           ip_adjacency_t *adj0;
3201           vnet_hw_interface_t *hw_if0;
3202           ip6_radv_t *radv_info;
3203           u32 next0;
3204
3205           pi0 = from[0];
3206
3207           p0 = vlib_get_buffer (vm, pi0);
3208
3209           adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
3210
3211           ip0 = vlib_buffer_get_current (p0);
3212
3213           adj0 = adj_get (adj_index0);
3214
3215           if (!is_glean)
3216             {
3217               ip0->dst_address.as_u64[0] =
3218                 adj0->sub_type.nbr.next_hop.ip6.as_u64[0];
3219               ip0->dst_address.as_u64[1] =
3220                 adj0->sub_type.nbr.next_hop.ip6.as_u64[1];
3221             }
3222
3223           a0 = hash_seeds[0];
3224           b0 = hash_seeds[1];
3225           c0 = hash_seeds[2];
3226
3227           sw_if_index0 = adj0->rewrite_header.sw_if_index;
3228           vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
3229
3230           a0 ^= sw_if_index0;
3231           b0 ^= ip0->dst_address.as_u32[0];
3232           c0 ^= ip0->dst_address.as_u32[1];
3233
3234           hash_v3_mix32 (a0, b0, c0);
3235
3236           b0 ^= ip0->dst_address.as_u32[2];
3237           c0 ^= ip0->dst_address.as_u32[3];
3238
3239           hash_v3_finalize32 (a0, b0, c0);
3240
3241           c0 &= BITS (hash_bitmap) - 1;
3242           c0 = c0 / BITS (uword);
3243           m0 = (uword) 1 << (c0 % BITS (uword));
3244
3245           bm0 = hash_bitmap[c0];
3246           drop0 = (bm0 & m0) != 0;
3247
3248           /* Mark it as seen. */
3249           hash_bitmap[c0] = bm0 | m0;
3250
3251           from += 1;
3252           n_left_from -= 1;
3253           to_next_drop[0] = pi0;
3254           to_next_drop += 1;
3255           n_left_to_next_drop -= 1;
3256
3257           hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
3258
3259           /* If the interface is link-down, drop the pkt */
3260           if (!(hw_if0->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
3261             drop0 = 1;
3262
3263           if (vec_len (nm->if_radv_pool_index_by_sw_if_index) > sw_if_index0)
3264             {
3265               u32 ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index0];
3266
3267               if (ri != ~0)
3268                 radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3269               else
3270                 drop0 = 1;
3271             }
3272           else
3273             drop0 = 1;
3274
3275           /*
3276            * the adj has been updated to a rewrite but the node the DPO that got
3277            * us here hasn't - yet. no big deal. we'll drop while we wait.
3278            */
3279           if (IP_LOOKUP_NEXT_REWRITE == adj0->lookup_next_index)
3280             drop0 = 1;
3281
3282           p0->error =
3283             node->errors[drop0 ? IP6_DISCOVER_NEIGHBOR_ERROR_DROP
3284                          : IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT];
3285
3286           if (drop0)
3287             continue;
3288
3289           {
3290             u32 bi0 = 0;
3291             icmp6_neighbor_solicitation_header_t *h0;
3292             vlib_buffer_t *b0;
3293
3294             h0 = vlib_packet_template_get_packet
3295               (vm, &im->discover_neighbor_packet_template, &bi0);
3296             if (!h0)
3297               continue;
3298
3299             /*
3300              * Build ethernet header.
3301              * Choose source address based on destination lookup
3302              * adjacency.
3303              */
3304             if (!ip6_src_address_for_packet (lm,
3305                                              sw_if_index0,
3306                                              &ip0->dst_address,
3307                                              &h0->ip.src_address))
3308               {
3309                 /* There is no address on the interface */
3310                 p0->error =
3311                   node->errors[IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS];
3312                 vlib_buffer_free (vm, &bi0, 1);
3313                 continue;
3314               }
3315
3316             /*
3317              * Destination address is a solicited node multicast address.
3318              * We need to fill in
3319              * the low 24 bits with low 24 bits of target's address.
3320              */
3321             h0->ip.dst_address.as_u8[13] = ip0->dst_address.as_u8[13];
3322             h0->ip.dst_address.as_u8[14] = ip0->dst_address.as_u8[14];
3323             h0->ip.dst_address.as_u8[15] = ip0->dst_address.as_u8[15];
3324
3325             h0->neighbor.target_address = ip0->dst_address;
3326
3327             clib_memcpy (h0->link_layer_option.ethernet_address,
3328                          hw_if0->hw_address, vec_len (hw_if0->hw_address));
3329
3330             /* $$$$ appears we need this; why is the checksum non-zero? */
3331             h0->neighbor.icmp.checksum = 0;
3332             h0->neighbor.icmp.checksum =
3333               ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h0->ip,
3334                                                  &bogus_length);
3335
3336             ASSERT (bogus_length == 0);
3337
3338             vlib_buffer_copy_trace_flag (vm, p0, bi0);
3339             b0 = vlib_get_buffer (vm, bi0);
3340             vnet_buffer (b0)->sw_if_index[VLIB_TX]
3341               = vnet_buffer (p0)->sw_if_index[VLIB_TX];
3342
3343             vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
3344               radv_info->mcast_adj_index;
3345
3346             b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
3347             next0 = IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX;
3348
3349             vlib_set_next_frame_buffer (vm, node, next0, bi0);
3350           }
3351         }
3352
3353       vlib_put_next_frame (vm, node, IP6_DISCOVER_NEIGHBOR_NEXT_DROP,
3354                            n_left_to_next_drop);
3355     }
3356
3357   return frame->n_vectors;
3358 }
3359
3360 static uword
3361 ip6_discover_neighbor (vlib_main_t * vm,
3362                        vlib_node_runtime_t * node, vlib_frame_t * frame)
3363 {
3364   return (ip6_discover_neighbor_inline (vm, node, frame, 0));
3365 }
3366
3367 static uword
3368 ip6_glean (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
3369 {
3370   return (ip6_discover_neighbor_inline (vm, node, frame, 1));
3371 }
3372
3373 static char *ip6_discover_neighbor_error_strings[] = {
3374   [IP6_DISCOVER_NEIGHBOR_ERROR_DROP] = "address overflow drops",
3375   [IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT] = "neighbor solicitations sent",
3376   [IP6_DISCOVER_NEIGHBOR_ERROR_NO_SOURCE_ADDRESS]
3377     = "no source address for ND solicitation",
3378 };
3379
3380 /* *INDENT-OFF* */
3381 VLIB_REGISTER_NODE (ip6_glean_node) =
3382 {
3383   .function = ip6_glean,
3384   .name = "ip6-glean",
3385   .vector_size = sizeof (u32),
3386   .format_trace = format_ip6_forward_next_trace,
3387   .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
3388   .error_strings = ip6_discover_neighbor_error_strings,
3389   .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
3390   .next_nodes =
3391   {
3392     [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "ip6-drop",
3393     [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "ip6-rewrite-mcast",
3394   },
3395 };
3396 VLIB_REGISTER_NODE (ip6_discover_neighbor_node) =
3397 {
3398   .function = ip6_discover_neighbor,
3399   .name = "ip6-discover-neighbor",
3400   .vector_size = sizeof (u32),
3401   .format_trace = format_ip6_forward_next_trace,
3402   .n_errors = ARRAY_LEN (ip6_discover_neighbor_error_strings),
3403   .error_strings = ip6_discover_neighbor_error_strings,
3404   .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
3405   .next_nodes =
3406   {
3407     [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "ip6-drop",
3408     [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "ip6-rewrite-mcast",
3409   },
3410 };
3411 /* *INDENT-ON* */
3412
3413 /* API support functions */
3414 int
3415 ip6_neighbor_ra_config (vlib_main_t * vm, u32 sw_if_index,
3416                         u8 suppress, u8 managed, u8 other,
3417                         u8 ll_option, u8 send_unicast, u8 cease,
3418                         u8 use_lifetime, u32 lifetime,
3419                         u32 initial_count, u32 initial_interval,
3420                         u32 max_interval, u32 min_interval, u8 is_no)
3421 {
3422   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
3423   int error;
3424   u32 ri;
3425
3426   /* look up the radv_t  information for this interface */
3427   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index,
3428                            ~0);
3429   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3430   error = (ri != ~0) ? 0 : VNET_API_ERROR_INVALID_SW_IF_INDEX;
3431
3432   if (!error)
3433     {
3434
3435       ip6_radv_t *radv_info;
3436       radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3437
3438       if ((max_interval != 0) && (min_interval == 0))
3439         min_interval = .75 * max_interval;
3440
3441       max_interval =
3442         (max_interval !=
3443          0) ? ((is_no) ? DEF_MAX_RADV_INTERVAL : max_interval) :
3444         radv_info->max_radv_interval;
3445       min_interval =
3446         (min_interval !=
3447          0) ? ((is_no) ? DEF_MIN_RADV_INTERVAL : min_interval) :
3448         radv_info->min_radv_interval;
3449       lifetime =
3450         (use_lifetime !=
3451          0) ? ((is_no) ? DEF_DEF_RTR_LIFETIME : lifetime) :
3452         radv_info->adv_router_lifetime_in_sec;
3453
3454       if (lifetime)
3455         {
3456           if (lifetime > MAX_DEF_RTR_LIFETIME)
3457             lifetime = MAX_DEF_RTR_LIFETIME;
3458
3459           if (lifetime <= max_interval)
3460             return VNET_API_ERROR_INVALID_VALUE;
3461         }
3462
3463       if (min_interval != 0)
3464         {
3465           if ((min_interval > .75 * max_interval) || (min_interval < 3))
3466             return VNET_API_ERROR_INVALID_VALUE;
3467         }
3468
3469       if ((initial_count > MAX_INITIAL_RTR_ADVERTISEMENTS) ||
3470           (initial_interval > MAX_INITIAL_RTR_ADVERT_INTERVAL))
3471         return VNET_API_ERROR_INVALID_VALUE;
3472
3473       /*
3474          if "flag" is set and is_no is true then restore default value else set value corresponding to "flag"
3475          if "flag" is clear  don't change corresponding value
3476        */
3477       radv_info->send_radv =
3478         (suppress != 0) ? ((is_no != 0) ? 1 : 0) : radv_info->send_radv;
3479       radv_info->adv_managed_flag =
3480         (managed != 0) ? ((is_no) ? 0 : 1) : radv_info->adv_managed_flag;
3481       radv_info->adv_other_flag =
3482         (other != 0) ? ((is_no) ? 0 : 1) : radv_info->adv_other_flag;
3483       radv_info->adv_link_layer_address =
3484         (ll_option !=
3485          0) ? ((is_no) ? 1 : 0) : radv_info->adv_link_layer_address;
3486       radv_info->send_unicast =
3487         (send_unicast != 0) ? ((is_no) ? 0 : 1) : radv_info->send_unicast;
3488       radv_info->cease_radv =
3489         (cease != 0) ? ((is_no) ? 0 : 1) : radv_info->cease_radv;
3490
3491       radv_info->min_radv_interval = min_interval;
3492       radv_info->max_radv_interval = max_interval;
3493       radv_info->adv_router_lifetime_in_sec = lifetime;
3494
3495       radv_info->initial_adverts_count =
3496         (initial_count !=
3497          0) ? ((is_no) ? MAX_INITIAL_RTR_ADVERTISEMENTS : initial_count) :
3498         radv_info->initial_adverts_count;
3499       radv_info->initial_adverts_interval =
3500         (initial_interval !=
3501          0) ? ((is_no) ? MAX_INITIAL_RTR_ADVERT_INTERVAL : initial_interval) :
3502         radv_info->initial_adverts_interval;
3503
3504       /* restart */
3505       if ((cease != 0) && (is_no))
3506         radv_info->send_radv = 1;
3507
3508       radv_info->initial_adverts_sent = radv_info->initial_adverts_count - 1;
3509       radv_info->next_multicast_time = vlib_time_now (vm);
3510       radv_info->last_multicast_time = vlib_time_now (vm);
3511       radv_info->last_radv_time = 0;
3512     }
3513   return (error);
3514 }
3515
3516 int
3517 ip6_neighbor_ra_prefix (vlib_main_t * vm, u32 sw_if_index,
3518                         ip6_address_t * prefix_addr, u8 prefix_len,
3519                         u8 use_default, u32 val_lifetime, u32 pref_lifetime,
3520                         u8 no_advertise, u8 off_link, u8 no_autoconfig,
3521                         u8 no_onlink, u8 is_no)
3522 {
3523   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
3524   int error;
3525
3526   u32 ri;
3527
3528   /* look up the radv_t  information for this interface */
3529   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index,
3530                            ~0);
3531
3532   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3533
3534   error = (ri != ~0) ? 0 : VNET_API_ERROR_INVALID_SW_IF_INDEX;
3535
3536   if (!error)
3537     {
3538       f64 now = vlib_time_now (vm);
3539       ip6_radv_t *radv_info;
3540       radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3541
3542       /* prefix info add, delete or update */
3543       ip6_radv_prefix_t *prefix;
3544
3545       /* lookup  prefix info for this  address on this interface */
3546       uword *p = mhash_get (&radv_info->address_to_prefix_index, prefix_addr);
3547
3548       prefix = p ? pool_elt_at_index (radv_info->adv_prefixes_pool, p[0]) : 0;
3549
3550       if (is_no)
3551         {
3552           /* delete */
3553           if (!prefix)
3554             return VNET_API_ERROR_INVALID_VALUE;        /* invalid prefix */
3555
3556           if (prefix->prefix_len != prefix_len)
3557             return VNET_API_ERROR_INVALID_VALUE_2;
3558
3559           /* FIXME - Should the DP do this or the CP ? */
3560           /* do specific delete processing here before returning */
3561           /* try to remove from routing table */
3562
3563           mhash_unset (&radv_info->address_to_prefix_index, prefix_addr,
3564                        /* old_value */ 0);
3565           pool_put (radv_info->adv_prefixes_pool, prefix);
3566
3567           radv_info->initial_adverts_sent =
3568             radv_info->initial_adverts_count - 1;
3569           radv_info->next_multicast_time = vlib_time_now (vm);
3570           radv_info->last_multicast_time = vlib_time_now (vm);
3571           radv_info->last_radv_time = 0;
3572           return (error);
3573         }
3574
3575       /* adding or changing */
3576       if (!prefix)
3577         {
3578           /* add */
3579           u32 pi;
3580           pool_get (radv_info->adv_prefixes_pool, prefix);
3581           pi = prefix - radv_info->adv_prefixes_pool;
3582           mhash_set (&radv_info->address_to_prefix_index, prefix_addr, pi,
3583                      /* old_value */ 0);
3584
3585           memset (prefix, 0x0, sizeof (ip6_radv_prefix_t));
3586
3587           prefix->prefix_len = prefix_len;
3588           clib_memcpy (&prefix->prefix, prefix_addr, sizeof (ip6_address_t));
3589
3590           /* initialize default values */
3591           prefix->adv_on_link_flag = 1; /* L bit set */
3592           prefix->adv_autonomous_flag = 1;      /* A bit set */
3593           prefix->adv_valid_lifetime_in_secs = DEF_ADV_VALID_LIFETIME;
3594           prefix->adv_pref_lifetime_in_secs = DEF_ADV_PREF_LIFETIME;
3595           prefix->enabled = 1;
3596           prefix->decrement_lifetime_flag = 1;
3597           prefix->deprecated_prefix_flag = 1;
3598
3599           if (off_link == 0)
3600             {
3601               /* FIXME - Should the DP do this or the CP ? */
3602               /* insert prefix into routing table as a connected prefix */
3603             }
3604
3605           if (use_default)
3606             goto restart;
3607         }
3608       else
3609         {
3610
3611           if (prefix->prefix_len != prefix_len)
3612             return VNET_API_ERROR_INVALID_VALUE_2;
3613
3614           if (off_link != 0)
3615             {
3616               /* FIXME - Should the DP do this or the CP ? */
3617               /* remove from routing table if already there */
3618             }
3619         }
3620
3621       if ((val_lifetime == ~0) || (pref_lifetime == ~0))
3622         {
3623           prefix->adv_valid_lifetime_in_secs = ~0;
3624           prefix->adv_pref_lifetime_in_secs = ~0;
3625           prefix->decrement_lifetime_flag = 0;
3626         }
3627       else
3628         {
3629           prefix->adv_valid_lifetime_in_secs = val_lifetime;;
3630           prefix->adv_pref_lifetime_in_secs = pref_lifetime;
3631         }
3632
3633       /* copy  remaining */
3634       prefix->enabled = !(no_advertise != 0);
3635       prefix->adv_on_link_flag = !((off_link != 0) || (no_onlink != 0));
3636       prefix->adv_autonomous_flag = !(no_autoconfig != 0);
3637
3638     restart:
3639       /* restart */
3640       /* fill in the expiration times  */
3641       prefix->valid_lifetime_expires =
3642         now + prefix->adv_valid_lifetime_in_secs;
3643       prefix->pref_lifetime_expires = now + prefix->adv_pref_lifetime_in_secs;
3644
3645       radv_info->initial_adverts_sent = radv_info->initial_adverts_count - 1;
3646       radv_info->next_multicast_time = vlib_time_now (vm);
3647       radv_info->last_multicast_time = vlib_time_now (vm);
3648       radv_info->last_radv_time = 0;
3649     }
3650   return (error);
3651 }
3652
3653 clib_error_t *
3654 ip6_neighbor_cmd (vlib_main_t * vm, unformat_input_t * main_input,
3655                   vlib_cli_command_t * cmd)
3656 {
3657   vnet_main_t *vnm = vnet_get_main ();
3658   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
3659   clib_error_t *error = 0;
3660   u8 is_no = 0;
3661   u8 suppress = 0, managed = 0, other = 0;
3662   u8 suppress_ll_option = 0, send_unicast = 0, cease = 0;
3663   u8 use_lifetime = 0;
3664   u32 sw_if_index, ra_lifetime = 0, ra_initial_count =
3665     0, ra_initial_interval = 0;
3666   u32 ra_max_interval = 0, ra_min_interval = 0;
3667
3668   unformat_input_t _line_input, *line_input = &_line_input;
3669   vnet_sw_interface_t *sw_if0;
3670
3671   int add_radv_info = 1;
3672   __attribute__ ((unused)) ip6_radv_t *radv_info = 0;
3673   ip6_address_t ip6_addr;
3674   u32 addr_len;
3675
3676
3677   /* Get a line of input. */
3678   if (!unformat_user (main_input, unformat_line_input, line_input))
3679     return 0;
3680
3681   /* get basic radv info for this interface */
3682   if (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3683     {
3684
3685       if (unformat_user (line_input,
3686                          unformat_vnet_sw_interface, vnm, &sw_if_index))
3687         {
3688           u32 ri;
3689           ethernet_interface_t *eth_if0 = 0;
3690
3691           sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
3692           if (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
3693             eth_if0 =
3694               ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
3695
3696           if (!eth_if0)
3697             {
3698               error =
3699                 clib_error_return (0, "Interface must be of ethernet type");
3700               goto done;
3701             }
3702
3703           /* look up the radv_t  information for this interface */
3704           vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index,
3705                                    sw_if_index, ~0);
3706
3707           ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3708
3709           if (ri != ~0)
3710             {
3711               radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3712             }
3713           else
3714             {
3715               error = clib_error_return (0, "unknown interface %U'",
3716                                          format_unformat_error, line_input);
3717               goto done;
3718             }
3719         }
3720       else
3721         {
3722           error = clib_error_return (0, "invalid interface name %U'",
3723                                      format_unformat_error, line_input);
3724           goto done;
3725         }
3726     }
3727
3728   /* get the rest of the command */
3729   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3730     {
3731       if (unformat (line_input, "no"))
3732         is_no = 1;
3733       else if (unformat (line_input, "prefix %U/%d",
3734                          unformat_ip6_address, &ip6_addr, &addr_len))
3735         {
3736           add_radv_info = 0;
3737           break;
3738         }
3739       else if (unformat (line_input, "ra-managed-config-flag"))
3740         {
3741           managed = 1;
3742           break;
3743         }
3744       else if (unformat (line_input, "ra-other-config-flag"))
3745         {
3746           other = 1;
3747           break;
3748         }
3749       else if (unformat (line_input, "ra-suppress") ||
3750                unformat (line_input, "ra-surpress"))
3751         {
3752           suppress = 1;
3753           break;
3754         }
3755       else if (unformat (line_input, "ra-suppress-link-layer") ||
3756                unformat (line_input, "ra-surpress-link-layer"))
3757         {
3758           suppress_ll_option = 1;
3759           break;
3760         }
3761       else if (unformat (line_input, "ra-send-unicast"))
3762         {
3763           send_unicast = 1;
3764           break;
3765         }
3766       else if (unformat (line_input, "ra-lifetime"))
3767         {
3768           if (!unformat (line_input, "%d", &ra_lifetime))
3769             {
3770               error = unformat_parse_error (line_input);
3771               goto done;
3772             }
3773           use_lifetime = 1;
3774           break;
3775         }
3776       else if (unformat (line_input, "ra-initial"))
3777         {
3778           if (!unformat
3779               (line_input, "%d %d", &ra_initial_count, &ra_initial_interval))
3780             {
3781               error = unformat_parse_error (line_input);
3782               goto done;
3783             }
3784           break;
3785         }
3786       else if (unformat (line_input, "ra-interval"))
3787         {
3788           if (!unformat (line_input, "%d", &ra_max_interval))
3789             {
3790               error = unformat_parse_error (line_input);
3791               goto done;
3792             }
3793
3794           if (!unformat (line_input, "%d", &ra_min_interval))
3795             ra_min_interval = 0;
3796           break;
3797         }
3798       else if (unformat (line_input, "ra-cease"))
3799         {
3800           cease = 1;
3801           break;
3802         }
3803       else
3804         {
3805           error = unformat_parse_error (line_input);
3806           goto done;
3807         }
3808     }
3809
3810   if (add_radv_info)
3811     {
3812       ip6_neighbor_ra_config (vm, sw_if_index,
3813                               suppress, managed, other,
3814                               suppress_ll_option, send_unicast, cease,
3815                               use_lifetime, ra_lifetime,
3816                               ra_initial_count, ra_initial_interval,
3817                               ra_max_interval, ra_min_interval, is_no);
3818     }
3819   else
3820     {
3821       u32 valid_lifetime_in_secs = 0;
3822       u32 pref_lifetime_in_secs = 0;
3823       u8 use_prefix_default_values = 0;
3824       u8 no_advertise = 0;
3825       u8 off_link = 0;
3826       u8 no_autoconfig = 0;
3827       u8 no_onlink = 0;
3828
3829       /* get the rest of the command */
3830       while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3831         {
3832           if (unformat (line_input, "default"))
3833             {
3834               use_prefix_default_values = 1;
3835               break;
3836             }
3837           else if (unformat (line_input, "infinite"))
3838             {
3839               valid_lifetime_in_secs = ~0;
3840               pref_lifetime_in_secs = ~0;
3841               break;
3842             }
3843           else if (unformat (line_input, "%d %d", &valid_lifetime_in_secs,
3844                              &pref_lifetime_in_secs))
3845             break;
3846           else
3847             break;
3848         }
3849
3850
3851       /* get the rest of the command */
3852       while (!use_prefix_default_values &&
3853              unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3854         {
3855           if (unformat (line_input, "no-advertise"))
3856             no_advertise = 1;
3857           else if (unformat (line_input, "off-link"))
3858             off_link = 1;
3859           else if (unformat (line_input, "no-autoconfig"))
3860             no_autoconfig = 1;
3861           else if (unformat (line_input, "no-onlink"))
3862             no_onlink = 1;
3863           else
3864             {
3865               error = unformat_parse_error (line_input);
3866               goto done;
3867             }
3868         }
3869
3870       ip6_neighbor_ra_prefix (vm, sw_if_index,
3871                               &ip6_addr, addr_len,
3872                               use_prefix_default_values,
3873                               valid_lifetime_in_secs,
3874                               pref_lifetime_in_secs,
3875                               no_advertise,
3876                               off_link, no_autoconfig, no_onlink, is_no);
3877     }
3878
3879 done:
3880   unformat_free (line_input);
3881
3882   return error;
3883 }
3884
3885 static void
3886 ip6_print_addrs (vlib_main_t * vm, u32 * addrs)
3887 {
3888   ip_lookup_main_t *lm = &ip6_main.lookup_main;
3889   u32 i;
3890
3891   for (i = 0; i < vec_len (addrs); i++)
3892     {
3893       ip_interface_address_t *a =
3894         pool_elt_at_index (lm->if_address_pool, addrs[i]);
3895       ip6_address_t *address = ip_interface_address_get_address (lm, a);
3896
3897       vlib_cli_output (vm, "\t\t%U/%d",
3898                        format_ip6_address, address, a->address_length);
3899     }
3900 }
3901
3902 static clib_error_t *
3903 show_ip6_interface_cmd (vlib_main_t * vm,
3904                         unformat_input_t * input, vlib_cli_command_t * cmd)
3905 {
3906   vnet_main_t *vnm = vnet_get_main ();
3907   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
3908   clib_error_t *error = 0;
3909   u32 sw_if_index;
3910
3911   sw_if_index = ~0;
3912
3913   if (unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
3914     {
3915       u32 ri;
3916
3917       /* look up the radv_t  information for this interface */
3918       vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index,
3919                                sw_if_index, ~0);
3920
3921       ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3922
3923       if (ri != ~0)
3924         {
3925           ip_lookup_main_t *lm = &ip6_main.lookup_main;
3926           ip6_radv_t *radv_info;
3927           radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3928
3929           vlib_cli_output (vm, "%U is admin %s\n",
3930                            format_vnet_sw_interface_name, vnm,
3931                            vnet_get_sw_interface (vnm, sw_if_index),
3932                            (vnet_sw_interface_is_admin_up (vnm, sw_if_index) ?
3933                             "up" : "down"));
3934
3935           u32 ai;
3936           u32 *link_scope = 0, *global_scope = 0;
3937           u32 *local_scope = 0, *unknown_scope = 0;
3938           ip_interface_address_t *a;
3939
3940           vec_validate_init_empty (lm->if_address_pool_index_by_sw_if_index,
3941                                    sw_if_index, ~0);
3942           ai = lm->if_address_pool_index_by_sw_if_index[sw_if_index];
3943
3944           while (ai != (u32) ~ 0)
3945             {
3946               a = pool_elt_at_index (lm->if_address_pool, ai);
3947               ip6_address_t *address =
3948                 ip_interface_address_get_address (lm, a);
3949
3950               if (ip6_address_is_link_local_unicast (address))
3951                 vec_add1 (link_scope, ai);
3952               else if (ip6_address_is_global_unicast (address))
3953                 vec_add1 (global_scope, ai);
3954               else if (ip6_address_is_local_unicast (address))
3955                 vec_add1 (local_scope, ai);
3956               else
3957                 vec_add1 (unknown_scope, ai);
3958
3959               ai = a->next_this_sw_interface;
3960             }
3961
3962           if (vec_len (link_scope))
3963             {
3964               vlib_cli_output (vm, "\tLink-local address(es):\n");
3965               ip6_print_addrs (vm, link_scope);
3966               vec_free (link_scope);
3967             }
3968
3969           if (vec_len (local_scope))
3970             {
3971               vlib_cli_output (vm, "\tLocal unicast address(es):\n");
3972               ip6_print_addrs (vm, local_scope);
3973               vec_free (local_scope);
3974             }
3975
3976           if (vec_len (global_scope))
3977             {
3978               vlib_cli_output (vm, "\tGlobal unicast address(es):\n");
3979               ip6_print_addrs (vm, global_scope);
3980               vec_free (global_scope);
3981             }
3982
3983           if (vec_len (unknown_scope))
3984             {
3985               vlib_cli_output (vm, "\tOther-scope address(es):\n");
3986               ip6_print_addrs (vm, unknown_scope);
3987               vec_free (unknown_scope);
3988             }
3989
3990           vlib_cli_output (vm, "\tLink-local address(es):\n");
3991           vlib_cli_output (vm, "\t\t%U\n", format_ip6_address,
3992                            &radv_info->link_local_address);
3993
3994           vlib_cli_output (vm, "\tJoined group address(es):\n");
3995           ip6_mldp_group_t *m;
3996           /* *INDENT-OFF* */
3997           pool_foreach (m, radv_info->mldp_group_pool,
3998           ({
3999             vlib_cli_output (vm, "\t\t%U\n", format_ip6_address,
4000                              &m->mcast_address);
4001           }));
4002           /* *INDENT-ON* */
4003
4004           vlib_cli_output (vm, "\tAdvertised Prefixes:\n");
4005           ip6_radv_prefix_t *p;
4006           /* *INDENT-OFF* */
4007           pool_foreach (p, radv_info->adv_prefixes_pool,
4008           ({
4009             vlib_cli_output (vm, "\t\tprefix %U,  length %d\n",
4010                              format_ip6_address, &p->prefix, p->prefix_len);
4011           }));
4012           /* *INDENT-ON* */
4013
4014           vlib_cli_output (vm, "\tMTU is %d\n", radv_info->adv_link_mtu);
4015           vlib_cli_output (vm, "\tICMP error messages are unlimited\n");
4016           vlib_cli_output (vm, "\tICMP redirects are disabled\n");
4017           vlib_cli_output (vm, "\tICMP unreachables are not sent\n");
4018           vlib_cli_output (vm, "\tND DAD is disabled\n");
4019           //vlib_cli_output (vm, "\tND reachable time is %d milliseconds\n",);
4020           vlib_cli_output (vm, "\tND advertised reachable time is %d\n",
4021                            radv_info->adv_neighbor_reachable_time_in_msec);
4022           vlib_cli_output (vm,
4023                            "\tND advertised retransmit interval is %d (msec)\n",
4024                            radv_info->
4025                            adv_time_in_msec_between_retransmitted_neighbor_solicitations);
4026
4027           u32 ra_interval = radv_info->max_radv_interval;
4028           u32 ra_interval_min = radv_info->min_radv_interval;
4029           vlib_cli_output (vm,
4030                            "\tND router advertisements are sent every %d seconds (min interval is %d)\n",
4031                            ra_interval, ra_interval_min);
4032           vlib_cli_output (vm,
4033                            "\tND router advertisements live for %d seconds\n",
4034                            radv_info->adv_router_lifetime_in_sec);
4035           vlib_cli_output (vm,
4036                            "\tHosts %s stateless autoconfig for addresses\n",
4037                            (radv_info->adv_managed_flag) ? "use" :
4038                            " don't use");
4039           vlib_cli_output (vm, "\tND router advertisements sent %d\n",
4040                            radv_info->n_advertisements_sent);
4041           vlib_cli_output (vm, "\tND router solicitations received %d\n",
4042                            radv_info->n_solicitations_rcvd);
4043           vlib_cli_output (vm, "\tND router solicitations dropped %d\n",
4044                            radv_info->n_solicitations_dropped);
4045         }
4046       else
4047         {
4048           error = clib_error_return (0, "IPv6 not enabled on interface",
4049                                      format_unformat_error, input);
4050
4051         }
4052     }
4053   return error;
4054 }
4055
4056 /*?
4057  * This command is used to display various IPv6 attributes on a given
4058  * interface.
4059  *
4060  * @cliexpar
4061  * Example of how to display IPv6 settings:
4062  * @cliexstart{show ip6 interface GigabitEthernet2/0/0}
4063  * GigabitEthernet2/0/0 is admin up
4064  *         Link-local address(es):
4065  *                 fe80::ab8/64
4066  *         Joined group address(es):
4067  *                 ff02::1
4068  *                 ff02::2
4069  *                 ff02::16
4070  *                 ff02::1:ff00:ab8
4071  *         Advertised Prefixes:
4072  *                 prefix fe80::fe:28ff:fe9c:75b3,  length 64
4073  *         MTU is 1500
4074  *         ICMP error messages are unlimited
4075  *         ICMP redirects are disabled
4076  *         ICMP unreachables are not sent
4077  *         ND DAD is disabled
4078  *         ND advertised reachable time is 0
4079  *         ND advertised retransmit interval is 0 (msec)
4080  *         ND router advertisements are sent every 200 seconds (min interval is 150)
4081  *         ND router advertisements live for 600 seconds
4082  *         Hosts use stateless autoconfig for addresses
4083  *         ND router advertisements sent 19336
4084  *         ND router solicitations received 0
4085  *         ND router solicitations dropped 0
4086  * @cliexend
4087  * Example of output if IPv6 is not enabled on the interface:
4088  * @cliexstart{show ip6 interface GigabitEthernet2/0/0}
4089  * show ip6 interface: IPv6 not enabled on interface
4090  * @cliexend
4091 ?*/
4092 /* *INDENT-OFF* */
4093 VLIB_CLI_COMMAND (show_ip6_interface_command, static) =
4094 {
4095   .path = "show ip6 interface",
4096   .function = show_ip6_interface_cmd,
4097   .short_help = "show ip6 interface <interface>",
4098 };
4099 /* *INDENT-ON* */
4100
4101 clib_error_t *
4102 disable_ip6_interface (vlib_main_t * vm, u32 sw_if_index)
4103 {
4104   clib_error_t *error = 0;
4105   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
4106   u32 ri;
4107
4108   /* look up the radv_t  information for this interface */
4109   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index,
4110                            ~0);
4111   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
4112
4113   /* if not created - do nothing */
4114   if (ri != ~0)
4115     {
4116       ip6_radv_t *radv_info;
4117
4118       radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
4119
4120       /* check radv_info ref count for other ip6 addresses on this interface */
4121       /* This implicitly excludes the link local address */
4122       if (radv_info->ref_count == 0)
4123         {
4124           /* essentially "disables" ipv6 on this interface */
4125           ip6_ll_prefix_t ilp = {
4126             .ilp_addr = radv_info->link_local_address,
4127             .ilp_sw_if_index = sw_if_index,
4128           };
4129           ip6_ll_table_entry_delete (&ilp);
4130           ip6_sw_interface_enable_disable (sw_if_index, 0);
4131           ip6_mfib_interface_enable_disable (sw_if_index, 0);
4132           ip6_neighbor_sw_interface_add_del (vnet_get_main (), sw_if_index,
4133                                              0);
4134         }
4135     }
4136   return error;
4137 }
4138
4139 int
4140 ip6_interface_enabled (vlib_main_t * vm, u32 sw_if_index)
4141 {
4142   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
4143   u32 ri = ~0;
4144
4145   /* look up the radv_t  information for this interface */
4146   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index,
4147                            ~0);
4148
4149   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
4150
4151   return ri != ~0;
4152 }
4153
4154 clib_error_t *
4155 enable_ip6_interface (vlib_main_t * vm, u32 sw_if_index)
4156 {
4157   clib_error_t *error = 0;
4158   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
4159   u32 ri;
4160   int is_add = 1;
4161
4162   /* look up the radv_t  information for this interface */
4163   vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index,
4164                            ~0);
4165
4166   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
4167
4168   /* if not created yet */
4169   if (ri == ~0)
4170     {
4171       vnet_main_t *vnm = vnet_get_main ();
4172       vnet_sw_interface_t *sw_if0;
4173
4174       sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
4175       if (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
4176         {
4177           ethernet_interface_t *eth_if0;
4178
4179           eth_if0 =
4180             ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
4181           if (eth_if0)
4182             {
4183               /* create radv_info. for this interface.  This holds all the info needed for router adverts */
4184               ri =
4185                 ip6_neighbor_sw_interface_add_del (vnm, sw_if_index, is_add);
4186
4187               if (ri != ~0)
4188                 {
4189                   ip6_radv_t *radv_info;
4190                   ip6_address_t link_local_address;
4191
4192                   radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
4193
4194                   ip6_link_local_address_from_ethernet_mac_address
4195                     (&link_local_address, eth_if0->address);
4196
4197                   sw_if0 = vnet_get_sw_interface (vnm, sw_if_index);
4198                   if (sw_if0->type == VNET_SW_INTERFACE_TYPE_SUB ||
4199                       sw_if0->type == VNET_SW_INTERFACE_TYPE_PIPE ||
4200                       sw_if0->type == VNET_SW_INTERFACE_TYPE_P2P)
4201                     {
4202                       /* make up  an interface id */
4203                       link_local_address.as_u64[1] =
4204                         random_u64 (&radv_info->randomizer);
4205
4206                       link_local_address.as_u64[0] =
4207                         clib_host_to_net_u64 (0xFE80000000000000ULL);
4208                       /* clear u bit */
4209                       link_local_address.as_u8[8] &= 0xfd;
4210                     }
4211                   {
4212                     ip6_ll_prefix_t ilp = {
4213                       .ilp_addr = link_local_address,
4214                       .ilp_sw_if_index = sw_if_index,
4215                     };
4216
4217                     ip6_ll_table_entry_update (&ilp, FIB_ROUTE_PATH_LOCAL);
4218                   }
4219
4220                   /* essentially "enables" ipv6 on this interface */
4221                   ip6_mfib_interface_enable_disable (sw_if_index, 1);
4222                   ip6_sw_interface_enable_disable (sw_if_index, 1);
4223
4224                   if (!error)
4225                     {
4226                       radv_info->link_local_address = link_local_address;
4227                     }
4228                 }
4229             }
4230         }
4231     }
4232   return error;
4233 }
4234
4235 int
4236 ip6_get_ll_address (u32 sw_if_index, ip6_address_t * addr)
4237 {
4238   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
4239   ip6_radv_t *radv_info;
4240   u32 ri;
4241
4242   if (vec_len (nm->if_radv_pool_index_by_sw_if_index) < sw_if_index)
4243     return 0;
4244
4245   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
4246
4247   if (ri == ~0)
4248     return 0;
4249
4250   radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
4251   *addr = radv_info->link_local_address;
4252
4253   return (!0);
4254 }
4255
4256 static clib_error_t *
4257 enable_ip6_interface_cmd (vlib_main_t * vm,
4258                           unformat_input_t * input, vlib_cli_command_t * cmd)
4259 {
4260   vnet_main_t *vnm = vnet_get_main ();
4261   clib_error_t *error = 0;
4262   u32 sw_if_index;
4263
4264   sw_if_index = ~0;
4265
4266   if (unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
4267     {
4268       enable_ip6_interface (vm, sw_if_index);
4269     }
4270   else
4271     {
4272       error = clib_error_return (0, "unknown interface\n'",
4273                                  format_unformat_error, input);
4274
4275     }
4276   return error;
4277 }
4278
4279 /*?
4280  * This command is used to enable IPv6 on a given interface.
4281  *
4282  * @cliexpar
4283  * Example of how enable IPv6 on a given interface:
4284  * @cliexcmd{enable ip6 interface GigabitEthernet2/0/0}
4285 ?*/
4286 /* *INDENT-OFF* */
4287 VLIB_CLI_COMMAND (enable_ip6_interface_command, static) =
4288 {
4289   .path = "enable ip6 interface",
4290   .function = enable_ip6_interface_cmd,
4291   .short_help = "enable ip6 interface <interface>",
4292 };
4293 /* *INDENT-ON* */
4294
4295 static clib_error_t *
4296 disable_ip6_interface_cmd (vlib_main_t * vm,
4297                            unformat_input_t * input, vlib_cli_command_t * cmd)
4298 {
4299   vnet_main_t *vnm = vnet_get_main ();
4300   clib_error_t *error = 0;
4301   u32 sw_if_index;
4302
4303   sw_if_index = ~0;
4304
4305   if (unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
4306     {
4307       error = disable_ip6_interface (vm, sw_if_index);
4308     }
4309   else
4310     {
4311       error = clib_error_return (0, "unknown interface\n'",
4312                                  format_unformat_error, input);
4313
4314     }
4315   return error;
4316 }
4317
4318 /*?
4319  * This command is used to disable IPv6 on a given interface.
4320  *
4321  * @cliexpar
4322  * Example of how disable IPv6 on a given interface:
4323  * @cliexcmd{disable ip6 interface GigabitEthernet2/0/0}
4324 ?*/
4325 /* *INDENT-OFF* */
4326 VLIB_CLI_COMMAND (disable_ip6_interface_command, static) =
4327 {
4328   .path = "disable ip6 interface",
4329   .function = disable_ip6_interface_cmd,
4330   .short_help = "disable ip6 interface <interface>",
4331 };
4332 /* *INDENT-ON* */
4333
4334 /*?
4335  * This command is used to configure the neighbor discovery
4336  * parameters on a given interface. Use the '<em>show ip6 interface</em>'
4337  * command to display some of the current neighbor discovery parameters
4338  * on a given interface. This command has three formats:
4339  *
4340  *
4341  * <b>Format 1 - Router Advertisement Options:</b> (Only one can be entered in a single command)
4342  *
4343  * '<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>'
4344  *
4345  * Where:
4346  *
4347  * <em>[no] ra-managed-config-flag</em> - Advertises in ICMPv6
4348  * router-advertisement messages to use stateful address
4349  * auto-configuration to obtain address information (sets the M-bit).
4350  * Default is the M-bit is not set and the '<em>no</em>' option
4351  * returns it to this default state.
4352  *
4353  * <em>[no] ra-other-config-flag</em> - Indicates in ICMPv6
4354  * router-advertisement messages that hosts use stateful auto
4355  * configuration to obtain nonaddress related information (sets
4356  * the O-bit). Default is the O-bit is not set and the '<em>no</em>'
4357  * option returns it to this default state.
4358  *
4359  * <em>[no] ra-suppress</em> - Disables sending ICMPv6 router-advertisement
4360  * messages. The '<em>no</em>' option implies to enable sending ICMPv6
4361  * router-advertisement messages.
4362  *
4363  * <em>[no] ra-suppress-link-layer</em> - Indicates not to include the
4364  * optional source link-layer address in the ICMPv6 router-advertisement
4365  * messages. Default is to include the optional source link-layer address
4366  * and the '<em>no</em>' option returns it to this default state.
4367  *
4368  * <em>[no] ra-send-unicast</em> - Use the source address of the
4369  * router-solicitation message if availiable. The default is to use
4370  * multicast address of all nodes, and the '<em>no</em>' option returns
4371  * it to this default state.
4372  *
4373  * <em>[no] ra-lifetime <lifetime></em> - Advertises the lifetime of a
4374  * default router in ICMPv6 router-advertisement messages. The range is
4375  * from 0 to 9000 seconds. '<em><lifetime></em>' must be greater than
4376  * '<em><max-interval></em>'. The default value is 600 seconds and the
4377  * '<em>no</em>' option returns it to this default value.
4378  *
4379  * <em>[no] ra-initial <cnt> <interval></em> - Number of initial ICMPv6
4380  * router-advertisement messages sent and the interval between each
4381  * message. Range for count is 1 - 3 and default is 3. Range for interval
4382  * is 1 to 16 seconds, and default is 16 seconds. The '<em>no</em>' option
4383  * returns both to their default value.
4384  *
4385  * <em>[no] ra-interval <max-interval> [<min-interval>]</em> - Configures the
4386  * interval between sending ICMPv6 router-advertisement messages. The
4387  * range for max-interval is from 4 to 200 seconds. min-interval can not
4388  * be more than 75% of max-interval. If not set, min-interval will be
4389  * set to 75% of max-interval. The range for min-interval is from 3 to
4390  * 150 seconds.  The '<em>no</em>' option returns both to their default
4391  * value.
4392  *
4393  * <em>[no] ra-cease</em> - Cease sending ICMPv6 router-advertisement messages.
4394  * The '<em>no</em>' options implies to start (or restart) sending
4395  * ICMPv6 router-advertisement messages.
4396  *
4397  *
4398  * <b>Format 2 - Prefix Options:</b>
4399  *
4400  * '<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>'
4401  *
4402  * Where:
4403  *
4404  * <em>no</em> - All additional flags are ignored and the prefix is deleted.
4405  *
4406  * <em><valid-lifetime> <pref-lifetime></em> - '<em><valid-lifetime></em>' is the
4407  * length of time in seconds during what the prefix is valid for the purpose of
4408  * on-link determination. Range is 7203 to 2592000 seconds and default is 2592000
4409  * seconds (30 days). '<em><pref-lifetime></em>' is the prefered-lifetime and is the
4410  * length of time in seconds during what addresses generated from the prefix remain
4411  * preferred. Range is 0 to 604800 seconds and default is 604800 seconds (7 days).
4412  *
4413  * <em>infinite</em> - Both '<em><valid-lifetime></em>' and '<em><<pref-lifetime></em>'
4414  * are inifinte, no timeout.
4415  *
4416  * <em>no-advertise</em> - Do not send full router address in prefix
4417  * advertisement. Default is to advertise (i.e. - This flag is off by default).
4418  *
4419  * <em>off-link</em> - Prefix is off-link, clear L-bit in packet. Default is on-link
4420  * (i.e. - This flag is off and L-bit in packet is set by default and this prefix can
4421  * be used for on-link determination). '<em>no-onlink</em>' also controls the L-bit.
4422  *
4423  * <em>no-autoconfig</em> - Do not use prefix for autoconfiguration, clear A-bit in packet.
4424  * Default is autoconfig (i.e. - This flag is off and A-bit in packet is set by default.
4425  *
4426  * <em>no-onlink</em> - Do not use prefix for onlink determination, clear L-bit in packet.
4427  * Default is on-link (i.e. - This flag is off and L-bit in packet is set by default and
4428  * this prefix can be used for on-link determination). '<em>off-link</em>' also controls
4429  * the L-bit.
4430  *
4431  *
4432  * <b>Format 3: - Default of Prefix:</b>
4433  *
4434  * '<em><b>ip6 nd <interface> [no] prefix <ip6-address>/<width> default</b></em>'
4435  *
4436  * When a new prefix is added (or existing one is being overwritten) <em>default</em>
4437  * uses default values for the prefix. If <em>no</em> is used, the <em>default</em>
4438  * is ignored and the prefix is deleted.
4439  *
4440  *
4441  * @cliexpar
4442  * Example of how set a router advertisement option:
4443  * @cliexcmd{ip6 nd GigabitEthernet2/0/0 ra-interval 100 20}
4444  * Example of how to add a prefix:
4445  * @cliexcmd{ip6 nd GigabitEthernet2/0/0 prefix fe80::fe:28ff:fe9c:75b3/64 infinite no-advertise}
4446  * Example of how to delete a prefix:
4447  * @cliexcmd{ip6 nd GigabitEthernet2/0/0 no prefix fe80::fe:28ff:fe9c:75b3/64}
4448 ?*/
4449 /* *INDENT-OFF* */
4450 VLIB_CLI_COMMAND (ip6_nd_command, static) =
4451 {
4452   .path = "ip6 nd",
4453   .short_help = "ip6 nd <interface> ...",
4454   .function = ip6_neighbor_cmd,
4455 };
4456 /* *INDENT-ON* */
4457
4458 clib_error_t *
4459 set_ip6_link_local_address (vlib_main_t * vm,
4460                             u32 sw_if_index, ip6_address_t * address)
4461 {
4462   clib_error_t *error = 0;
4463   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
4464   u32 ri;
4465   ip6_radv_t *radv_info;
4466   vnet_main_t *vnm = vnet_get_main ();
4467
4468   if (!ip6_address_is_link_local_unicast (address))
4469     {
4470       vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_LINK_LOCAL;
4471       return (error = clib_error_return (0, "address not link-local",
4472                                          format_unformat_error));
4473     }
4474
4475   /* call enable ipv6  */
4476   enable_ip6_interface (vm, sw_if_index);
4477
4478   ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
4479
4480   if (ri != ~0)
4481     {
4482       radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
4483
4484       /* save if link local address (overwrite default) */
4485
4486       /* delete the old one */
4487       error = ip6_add_del_interface_address (vm, sw_if_index,
4488                                              &radv_info->link_local_address,
4489                                              128, 1 /* is_del */ );
4490
4491       if (!error)
4492         {
4493           /* add the new one */
4494           error = ip6_add_del_interface_address (vm, sw_if_index,
4495                                                  address, 128,
4496                                                  0 /* is_del */ );
4497
4498           if (!error)
4499             {
4500               radv_info->link_local_address = *address;
4501             }
4502         }
4503     }
4504   else
4505     {
4506       vnm->api_errno = VNET_API_ERROR_IP6_NOT_ENABLED;
4507       error = clib_error_return (0, "ip6 not enabled for interface",
4508                                  format_unformat_error);
4509     }
4510   return error;
4511 }
4512
4513 clib_error_t *
4514 set_ip6_link_local_address_cmd (vlib_main_t * vm,
4515                                 unformat_input_t * input,
4516                                 vlib_cli_command_t * cmd)
4517 {
4518   vnet_main_t *vnm = vnet_get_main ();
4519   clib_error_t *error = 0;
4520   u32 sw_if_index;
4521   ip6_address_t ip6_addr;
4522
4523   if (unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
4524     {
4525       /* get the rest of the command */
4526       while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
4527         {
4528           if (unformat (input, "%U", unformat_ip6_address, &ip6_addr))
4529             break;
4530           else
4531             return (unformat_parse_error (input));
4532         }
4533     }
4534   error = set_ip6_link_local_address (vm, sw_if_index, &ip6_addr);
4535   return error;
4536 }
4537
4538 /*?
4539  * This command is used to assign an IPv6 Link-local address to an
4540  * interface. This command will enable IPv6 on an interface if it
4541  * is not already enabled. Use the '<em>show ip6 interface</em>' command
4542  * to display the assigned Link-local address.
4543  *
4544  * @cliexpar
4545  * Example of how to assign an IPv6 Link-local address to an interface:
4546  * @cliexcmd{set ip6 link-local address GigabitEthernet2/0/0 FE80::AB8}
4547 ?*/
4548 /* *INDENT-OFF* */
4549 VLIB_CLI_COMMAND (set_ip6_link_local_address_command, static) =
4550 {
4551   .path = "set ip6 link-local address",
4552   .short_help = "set ip6 link-local address <interface> <ip6-address>",
4553   .function = set_ip6_link_local_address_cmd,
4554 };
4555 /* *INDENT-ON* */
4556
4557 /**
4558  * @brief callback when an interface address is added or deleted
4559  */
4560 static void
4561 ip6_neighbor_add_del_interface_address (ip6_main_t * im,
4562                                         uword opaque,
4563                                         u32 sw_if_index,
4564                                         ip6_address_t * address,
4565                                         u32 address_length,
4566                                         u32 if_address_index, u32 is_delete)
4567 {
4568   vnet_main_t *vnm = vnet_get_main ();
4569   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
4570   u32 ri;
4571   vlib_main_t *vm = vnm->vlib_main;
4572   ip6_radv_t *radv_info;
4573   ip6_address_t a;
4574
4575   /* create solicited node multicast address for this interface adddress */
4576   ip6_set_solicited_node_multicast_address (&a, 0);
4577
4578   a.as_u8[0xd] = address->as_u8[0xd];
4579   a.as_u8[0xe] = address->as_u8[0xe];
4580   a.as_u8[0xf] = address->as_u8[0xf];
4581
4582   if (!is_delete)
4583     {
4584       /* try to  create radv_info - does nothing if ipv6 already enabled */
4585       enable_ip6_interface (vm, sw_if_index);
4586
4587       /* look up the radv_t  information for this interface */
4588       vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index,
4589                                sw_if_index, ~0);
4590       ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
4591       if (ri != ~0)
4592         {
4593           /* get radv_info */
4594           radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
4595
4596           /* add address */
4597           if (!ip6_address_is_link_local_unicast (address))
4598             radv_info->ref_count++;
4599
4600           ip6_neighbor_add_mld_prefix (radv_info, &a);
4601         }
4602     }
4603   else
4604     {
4605
4606       /* delete */
4607       /* look up the radv_t  information for this interface */
4608       vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index,
4609                                sw_if_index, ~0);
4610       ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
4611
4612       if (ri != ~0)
4613         {
4614           /* get radv_info */
4615           radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
4616
4617           ip6_neighbor_del_mld_prefix (radv_info, &a);
4618
4619           /* if interface up send MLDP "report" */
4620           radv_info->all_routers_mcast = 0;
4621
4622           /* add address */
4623           if (!ip6_address_is_link_local_unicast (address))
4624             radv_info->ref_count--;
4625         }
4626       /* Ensure that IPv6 is disabled, and LL removed after ref_count reaches 0 */
4627       disable_ip6_interface (vm, sw_if_index);
4628     }
4629 }
4630
4631 clib_error_t *
4632 ip6_set_neighbor_limit (u32 neighbor_limit)
4633 {
4634   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
4635
4636   nm->limit_neighbor_cache_size = neighbor_limit;
4637   return 0;
4638 }
4639
4640 static void
4641 ip6_neighbor_table_bind (ip6_main_t * im,
4642                          uword opaque,
4643                          u32 sw_if_index,
4644                          u32 new_fib_index, u32 old_fib_index)
4645 {
4646   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
4647   ip6_neighbor_t *n = NULL;
4648   u32 i, *to_re_add = 0;
4649
4650   /* *INDENT-OFF* */
4651   pool_foreach (n, nm->neighbor_pool,
4652   ({
4653     if (n->key.sw_if_index == sw_if_index)
4654       vec_add1 (to_re_add, n - nm->neighbor_pool);
4655   }));
4656   /* *INDENT-ON* */
4657
4658   for (i = 0; i < vec_len (to_re_add); i++)
4659     {
4660       n = pool_elt_at_index (nm->neighbor_pool, to_re_add[i]);
4661       ip6_neighbor_adj_fib_remove (n, old_fib_index);
4662       ip6_neighbor_adj_fib_add (n, new_fib_index);
4663     }
4664   vec_free (to_re_add);
4665 }
4666
4667 static clib_error_t *
4668 ip6_neighbor_init (vlib_main_t * vm)
4669 {
4670   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
4671   ip6_main_t *im = &ip6_main;
4672
4673   mhash_init (&nm->neighbor_index_by_key,
4674               /* value size */ sizeof (uword),
4675               /* key size */ sizeof (ip6_neighbor_key_t));
4676
4677   icmp6_register_type (vm, ICMP6_neighbor_solicitation,
4678                        ip6_icmp_neighbor_solicitation_node.index);
4679   icmp6_register_type (vm, ICMP6_neighbor_advertisement,
4680                        ip6_icmp_neighbor_advertisement_node.index);
4681   icmp6_register_type (vm, ICMP6_router_solicitation,
4682                        ip6_icmp_router_solicitation_node.index);
4683   icmp6_register_type (vm, ICMP6_router_advertisement,
4684                        ip6_icmp_router_advertisement_node.index);
4685
4686   /* handler node for ip6 neighbor discovery events and timers */
4687   vlib_register_node (vm, &ip6_icmp_neighbor_discovery_event_node);
4688
4689   /* add call backs */
4690   ip6_add_del_interface_address_callback_t cb;
4691   memset (&cb, 0x0, sizeof (ip6_add_del_interface_address_callback_t));
4692
4693   /* when an interface address changes... */
4694   cb.function = ip6_neighbor_add_del_interface_address;
4695   cb.function_opaque = 0;
4696   vec_add1 (im->add_del_interface_address_callbacks, cb);
4697
4698   ip6_table_bind_callback_t cbt;
4699   cbt.function = ip6_neighbor_table_bind;
4700   cbt.function_opaque = 0;
4701   vec_add1 (im->table_bind_callbacks, cbt);
4702
4703   mhash_init (&nm->pending_resolutions_by_address,
4704               /* value size */ sizeof (uword),
4705               /* key size */ sizeof (ip6_address_t));
4706
4707   mhash_init (&nm->mac_changes_by_address,
4708               /* value size */ sizeof (uword),
4709               /* key size */ sizeof (ip6_address_t));
4710
4711   /* default, configurable */
4712   nm->limit_neighbor_cache_size = 50000;
4713
4714   nm->wc_ip6_nd_publisher_node = (uword) ~ 0;
4715
4716   nm->ip6_ra_publisher_node = (uword) ~ 0;
4717
4718 #if 0
4719   /* $$$$ Hack fix for today */
4720   vec_validate_init_empty
4721     (im->discover_neighbor_next_index_by_hw_if_index, 32, 0 /* drop */ );
4722 #endif
4723
4724   return 0;
4725 }
4726
4727 VLIB_INIT_FUNCTION (ip6_neighbor_init);
4728
4729
4730 void
4731 vnet_register_ip6_neighbor_resolution_event (vnet_main_t * vnm,
4732                                              void *address_arg,
4733                                              uword node_index,
4734                                              uword type_opaque, uword data)
4735 {
4736   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
4737   ip6_address_t *address = address_arg;
4738   uword *p;
4739   pending_resolution_t *pr;
4740
4741   pool_get (nm->pending_resolutions, pr);
4742
4743   pr->next_index = ~0;
4744   pr->node_index = node_index;
4745   pr->type_opaque = type_opaque;
4746   pr->data = data;
4747
4748   p = mhash_get (&nm->pending_resolutions_by_address, address);
4749   if (p)
4750     {
4751       /* Insert new resolution at the head of the list */
4752       pr->next_index = p[0];
4753       mhash_unset (&nm->pending_resolutions_by_address, address, 0);
4754     }
4755
4756   mhash_set (&nm->pending_resolutions_by_address, address,
4757              pr - nm->pending_resolutions, 0 /* old value */ );
4758 }
4759
4760 int
4761 vnet_add_del_ip6_nd_change_event (vnet_main_t * vnm,
4762                                   void *data_callback,
4763                                   u32 pid,
4764                                   void *address_arg,
4765                                   uword node_index,
4766                                   uword type_opaque, uword data, int is_add)
4767 {
4768   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
4769   ip6_address_t *address = address_arg;
4770
4771   /* Try to find an existing entry */
4772   u32 *first = (u32 *) mhash_get (&nm->mac_changes_by_address, address);
4773   u32 *p = first;
4774   pending_resolution_t *mc;
4775   while (p && *p != ~0)
4776     {
4777       mc = pool_elt_at_index (nm->mac_changes, *p);
4778       if (mc->node_index == node_index && mc->type_opaque == type_opaque
4779           && mc->pid == pid)
4780         break;
4781       p = &mc->next_index;
4782     }
4783
4784   int found = p && *p != ~0;
4785   if (is_add)
4786     {
4787       if (found)
4788         return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
4789
4790       pool_get (nm->mac_changes, mc);
4791       /* *INDENT-OFF* */
4792       *mc = (pending_resolution_t)
4793       {
4794         .next_index = ~0,
4795         .node_index = node_index,
4796         .type_opaque = type_opaque,
4797         .data = data,
4798         .data_callback = data_callback,
4799         .pid = pid,
4800       };
4801       /* *INDENT-ON* */
4802
4803       /* Insert new resolution at the end of the list */
4804       u32 new_idx = mc - nm->mac_changes;
4805       if (p)
4806         p[0] = new_idx;
4807       else
4808         mhash_set (&nm->mac_changes_by_address, address, new_idx, 0);
4809     }
4810   else
4811     {
4812       if (!found)
4813         return VNET_API_ERROR_NO_SUCH_ENTRY;
4814
4815       /* Clients may need to clean up pool entries, too */
4816       void (*fp) (u32, u8 *) = data_callback;
4817       if (fp)
4818         (*fp) (mc->data, 0 /* no new mac addrs */ );
4819
4820       /* Remove the entry from the list and delete the entry */
4821       *p = mc->next_index;
4822       pool_put (nm->mac_changes, mc);
4823
4824       /* Remove from hash if we deleted the last entry */
4825       if (*p == ~0 && p == first)
4826         mhash_unset (&nm->mac_changes_by_address, address, 0);
4827     }
4828   return 0;
4829 }
4830
4831 int
4832 vnet_ip6_nd_term (vlib_main_t * vm,
4833                   vlib_node_runtime_t * node,
4834                   vlib_buffer_t * p0,
4835                   ethernet_header_t * eth,
4836                   ip6_header_t * ip, u32 sw_if_index, u16 bd_index)
4837 {
4838   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
4839   icmp6_neighbor_solicitation_or_advertisement_header_t *ndh;
4840
4841   ndh = ip6_next_header (ip);
4842   if (ndh->icmp.type != ICMP6_neighbor_solicitation &&
4843       ndh->icmp.type != ICMP6_neighbor_advertisement)
4844     return 0;
4845
4846   if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
4847                      (p0->flags & VLIB_BUFFER_IS_TRACED)))
4848     {
4849       u8 *t0 = vlib_add_trace (vm, node, p0,
4850                                sizeof (icmp6_input_trace_t));
4851       clib_memcpy (t0, ip, sizeof (icmp6_input_trace_t));
4852     }
4853
4854   /* Check if anyone want ND events for L2 BDs */
4855   if (PREDICT_FALSE
4856       (nm->wc_ip6_nd_publisher_node != (uword) ~ 0
4857        && !ip6_address_is_link_local_unicast (&ip->src_address)))
4858     {
4859       vnet_nd_wc_publish (sw_if_index, eth->src_address, &ip->src_address);
4860     }
4861
4862   /* Check if MAC entry exsist for solicited target IP */
4863   if (ndh->icmp.type == ICMP6_neighbor_solicitation)
4864     {
4865       icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *opt;
4866       l2_bridge_domain_t *bd_config;
4867       u8 *macp;
4868
4869       opt = (void *) (ndh + 1);
4870       if ((opt->header.type !=
4871            ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address) ||
4872           (opt->header.n_data_u64s != 1))
4873         return 0;               /* source link layer address option not present */
4874
4875       bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
4876       macp =
4877         (u8 *) hash_get_mem (bd_config->mac_by_ip6, &ndh->target_address);
4878       if (macp)
4879         {                       /* found ip-mac entry, generate eighbor advertisement response */
4880           int bogus_length;
4881           vlib_node_runtime_t *error_node =
4882             vlib_node_get_runtime (vm, ip6_icmp_input_node.index);
4883           ip->dst_address = ip->src_address;
4884           ip->src_address = ndh->target_address;
4885           ip->hop_limit = 255;
4886           opt->header.type =
4887             ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
4888           clib_memcpy (opt->ethernet_address, macp, 6);
4889           ndh->icmp.type = ICMP6_neighbor_advertisement;
4890           ndh->advertisement_flags = clib_host_to_net_u32
4891             (ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED |
4892              ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE);
4893           ndh->icmp.checksum = 0;
4894           ndh->icmp.checksum =
4895             ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip, &bogus_length);
4896           clib_memcpy (eth->dst_address, eth->src_address, 6);
4897           clib_memcpy (eth->src_address, macp, 6);
4898           vlib_error_count (vm, error_node->node_index,
4899                             ICMP6_ERROR_NEIGHBOR_ADVERTISEMENTS_TX, 1);
4900           return 1;
4901         }
4902     }
4903
4904   return 0;
4905
4906 }
4907
4908 int
4909 ip6_neighbor_proxy_add_del (u32 sw_if_index, ip6_address_t * addr, u8 is_del)
4910 {
4911   u32 fib_index;
4912
4913   fib_prefix_t pfx = {
4914     .fp_len = 128,
4915     .fp_proto = FIB_PROTOCOL_IP6,
4916     .fp_addr = {
4917                 .ip6 = *addr,
4918                 },
4919   };
4920   ip46_address_t nh = {
4921     .ip6 = *addr,
4922   };
4923
4924   fib_index = ip6_fib_table_get_index_for_sw_if_index (sw_if_index);
4925
4926   if (~0 == fib_index)
4927     return VNET_API_ERROR_NO_SUCH_FIB;
4928
4929   if (is_del)
4930     {
4931       fib_table_entry_path_remove (fib_index,
4932                                    &pfx,
4933                                    FIB_SOURCE_IP6_ND_PROXY,
4934                                    DPO_PROTO_IP6,
4935                                    &nh,
4936                                    sw_if_index,
4937                                    ~0, 1, FIB_ROUTE_PATH_FLAG_NONE);
4938       /* flush the ND cache of this address if it's there */
4939       vnet_unset_ip6_ethernet_neighbor (vlib_get_main (),
4940                                         sw_if_index, addr, NULL, 0);
4941     }
4942   else
4943     {
4944       fib_table_entry_path_add (fib_index,
4945                                 &pfx,
4946                                 FIB_SOURCE_IP6_ND_PROXY,
4947                                 FIB_ENTRY_FLAG_NONE,
4948                                 DPO_PROTO_IP6,
4949                                 &nh,
4950                                 sw_if_index,
4951                                 ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
4952     }
4953   return (0);
4954 }
4955
4956 static clib_error_t *
4957 set_ip6_nd_proxy_cmd (vlib_main_t * vm,
4958                       unformat_input_t * input, vlib_cli_command_t * cmd)
4959 {
4960   vnet_main_t *vnm = vnet_get_main ();
4961   clib_error_t *error = 0;
4962   ip6_address_t addr;
4963   u32 sw_if_index;
4964   u8 is_del = 0;
4965
4966   if (unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
4967     {
4968       /* get the rest of the command */
4969       while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
4970         {
4971           if (unformat (input, "%U", unformat_ip6_address, &addr))
4972             break;
4973           else if (unformat (input, "delete") || unformat (input, "del"))
4974             is_del = 1;
4975           else
4976             return (unformat_parse_error (input));
4977         }
4978     }
4979
4980   ip6_neighbor_proxy_add_del (sw_if_index, &addr, is_del);
4981
4982   return error;
4983 }
4984
4985 /* *INDENT-OFF* */
4986 VLIB_CLI_COMMAND (set_ip6_nd_proxy_command, static) =
4987 {
4988   .path = "set ip6 nd proxy",
4989   .short_help = "set ip6 nd proxy <HOST> <INTERFACE>",
4990   .function = set_ip6_nd_proxy_cmd,
4991 };
4992 /* *INDENT-ON* */
4993
4994 void
4995 ethernet_ndp_change_mac (u32 sw_if_index)
4996 {
4997   ip6_neighbor_main_t *nm = &ip6_neighbor_main;
4998   ip6_neighbor_t *n;
4999   adj_index_t ai;
5000
5001   /* *INDENT-OFF* */
5002   pool_foreach (n, nm->neighbor_pool,
5003   ({
5004     if (n->key.sw_if_index == sw_if_index)
5005       {
5006         adj_nbr_walk_nh6 (sw_if_index,
5007                           &n->key.ip6_address,
5008                           ip6_nd_mk_complete_walk, n);
5009       }
5010   }));
5011   /* *INDENT-ON* */
5012
5013   ai = adj_glean_get (FIB_PROTOCOL_IP6, sw_if_index);
5014
5015   if (ADJ_INDEX_INVALID != ai)
5016     adj_glean_update_rewrite (ai);
5017 }
5018
5019 void
5020 send_ip6_na (vlib_main_t * vm, u32 sw_if_index)
5021 {
5022   ip6_main_t *i6m = &ip6_main;
5023   ip6_address_t *ip6_addr = ip6_interface_first_address (i6m, sw_if_index);
5024
5025   send_ip6_na_w_addr (vm, ip6_addr, sw_if_index);
5026 }
5027
5028 void
5029 send_ip6_na_w_addr (vlib_main_t * vm,
5030                     const ip6_address_t * ip6_addr, u32 sw_if_index)
5031 {
5032   ip6_main_t *i6m = &ip6_main;
5033   vnet_main_t *vnm = vnet_get_main ();
5034   u8 *rewrite, rewrite_len;
5035   vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
5036   u8 dst_address[6];
5037
5038   if (ip6_addr)
5039     {
5040       clib_warning
5041         ("Sending unsolicitated NA IP6 address %U on sw_if_idex %d",
5042          format_ip6_address, ip6_addr, sw_if_index);
5043
5044       /* Form unsolicited neighbor advertisement packet from NS pkt template */
5045       int bogus_length;
5046       u32 bi = 0;
5047       icmp6_neighbor_solicitation_header_t *h =
5048         vlib_packet_template_get_packet (vm,
5049                                          &i6m->discover_neighbor_packet_template,
5050                                          &bi);
5051       if (!h)
5052         return;
5053
5054       ip6_set_reserved_multicast_address (&h->ip.dst_address,
5055                                           IP6_MULTICAST_SCOPE_link_local,
5056                                           IP6_MULTICAST_GROUP_ID_all_hosts);
5057       h->ip.src_address = ip6_addr[0];
5058       h->neighbor.icmp.type = ICMP6_neighbor_advertisement;
5059       h->neighbor.target_address = ip6_addr[0];
5060       h->neighbor.advertisement_flags = clib_host_to_net_u32
5061         (ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE);
5062       clib_memcpy (h->link_layer_option.ethernet_address,
5063                    hi->hw_address, vec_len (hi->hw_address));
5064       h->neighbor.icmp.checksum =
5065         ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length);
5066       ASSERT (bogus_length == 0);
5067
5068       /* Setup MAC header with IP6 Etype and mcast DMAC */
5069       vlib_buffer_t *b = vlib_get_buffer (vm, bi);
5070       ip6_multicast_ethernet_address (dst_address,
5071                                       IP6_MULTICAST_GROUP_ID_all_hosts);
5072       rewrite =
5073         ethernet_build_rewrite (vnm, sw_if_index, VNET_LINK_IP6, dst_address);
5074       rewrite_len = vec_len (rewrite);
5075       vlib_buffer_advance (b, -rewrite_len);
5076       ethernet_header_t *e = vlib_buffer_get_current (b);
5077       clib_memcpy (e->dst_address, rewrite, rewrite_len);
5078       vec_free (rewrite);
5079
5080       /* Send unsolicited ND advertisement packet out the specified interface */
5081       vnet_buffer (b)->sw_if_index[VLIB_RX] =
5082         vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
5083       vlib_frame_t *f = vlib_get_frame_to_node (vm, hi->output_node_index);
5084       u32 *to_next = vlib_frame_vector_args (f);
5085       to_next[0] = bi;
5086       f->n_vectors = 1;
5087       vlib_put_frame_to_node (vm, hi->output_node_index, f);
5088     }
5089 }
5090
5091 /*
5092  * fd.io coding-style-patch-verification: ON
5093  *
5094  * Local Variables:
5095  * eval: (c-set-style "gnu")
5096  * End:
5097  */