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