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