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