2 * ip/ip6_neighbor.c: IP6 neighbor handling
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <vnet/ip/ip.h>
19 #include <vnet/ethernet/ethernet.h>
20 #include <vppinfra/mhash.h>
21 #include <vppinfra/md5.h>
24 #include <vnet/devices/dpdk/dpdk.h>
28 ip6_address_t ip6_address;
33 /* can't use sizeof link_layer_address, that's 8 */
34 #define ETHER_MAC_ADDR_LEN 6
37 ip6_neighbor_key_t key;
38 u8 link_layer_address[8];
39 u64 cpu_time_last_updated;
42 /* advertised prefix option */
44 /* basic advertised information */
48 int adv_autonomous_flag;
49 u32 adv_valid_lifetime_in_secs;
50 u32 adv_pref_lifetime_in_secs;
52 /* advertised values are computed from these times if decrementing */
53 f64 valid_lifetime_expires;
54 f64 pref_lifetime_expires;
56 /* local information */
58 int deprecated_prefix_flag;
59 int decrement_lifetime_flag;
61 #define MIN_ADV_VALID_LIFETIME 7203 /* seconds */
62 #define DEF_ADV_VALID_LIFETIME 2592000
63 #define DEF_ADV_PREF_LIFETIME 604800
65 /* extensions are added here, mobile, DNS etc.. */
70 /* group information */
72 ip6_address_t mcast_address;
74 ip6_address_t *mcast_source_address_pool;
77 /* configured router advertisement information per ipv6 interface */
80 /* advertised config information, zero means unspecified */
84 u16 adv_router_lifetime_in_sec;
85 u32 adv_neighbor_reachable_time_in_msec;
86 u32 adv_time_in_msec_between_retransmitted_neighbor_solicitations;
91 /* source link layer option */
92 u8 link_layer_address[8];
93 u8 link_layer_addr_len;
96 ip6_radv_prefix_t * adv_prefixes_pool;
98 /* Hash table mapping address to index in interface advertised prefix pool. */
99 mhash_t address_to_prefix_index;
101 /* MLDP group information */
102 ip6_mldp_group_t * mldp_group_pool;
104 /* Hash table mapping address to index in mldp address pool. */
105 mhash_t address_to_mldp_index;
107 /* local information */
110 int send_radv; /* radv on/off on this interface - set by config */
111 int cease_radv; /* we are ceasing to send - set byf config */
113 int adv_link_layer_address;
115 int failed_device_check;
116 int all_routers_mcast;
120 u32 all_nodes_adj_index;
121 u32 all_routers_adj_index;
122 u32 all_mldv2_routers_adj_index;
124 /* timing information */
125 #define DEF_MAX_RADV_INTERVAL 200
126 #define DEF_MIN_RADV_INTERVAL .75 * DEF_MAX_RADV_INTERVAL
127 #define DEF_CURR_HOP_LIMIT 64
128 #define DEF_DEF_RTR_LIFETIME 3 * DEF_MAX_RADV_INTERVAL
129 #define MAX_DEF_RTR_LIFETIME 9000
131 #define MAX_INITIAL_RTR_ADVERT_INTERVAL 16 /* seconds */
132 #define MAX_INITIAL_RTR_ADVERTISEMENTS 3 /*transmissions */
133 #define MIN_DELAY_BETWEEN_RAS 3 /* seconds */
134 #define MAX_DELAY_BETWEEN_RAS 1800 /* seconds */
135 #define MAX_RA_DELAY_TIME .5 /* seconds */
137 f64 max_radv_interval;
138 f64 min_radv_interval;
139 f64 min_delay_between_radv;
140 f64 max_delay_between_radv;
141 f64 max_rtr_default_lifetime;
144 f64 last_multicast_time;
145 f64 next_multicast_time;
148 u32 initial_adverts_count;
149 f64 initial_adverts_interval;
150 u32 initial_adverts_sent;
153 u32 n_advertisements_sent;
154 u32 n_solicitations_rcvd;
155 u32 n_solicitations_dropped;
157 /* Link local address to use (defaults to underlying physical for logical interfaces */
158 ip6_address_t link_local_address;
159 u8 link_local_prefix_len;
168 } pending_resolution_t;
172 /* Hash tables mapping name to opcode. */
173 uword * opcode_by_name;
175 /* lite beer "glean" adjacency handling */
176 mhash_t pending_resolutions_by_address;
177 pending_resolution_t * pending_resolutions;
179 u32 * neighbor_input_next_index_by_hw_if_index;
181 ip6_neighbor_t * neighbor_pool;
183 mhash_t neighbor_index_by_key;
185 u32 * if_radv_pool_index_by_sw_if_index;
187 ip6_radv_t * if_radv_pool;
189 /* Neighbor attack mitigation */
190 u32 limit_neighbor_cache_size;
191 u32 neighbor_delete_rotor;
193 } ip6_neighbor_main_t;
195 static ip6_neighbor_main_t ip6_neighbor_main;
197 static u8 * format_ip6_neighbor_ip6_entry (u8 * s, va_list * va)
199 vlib_main_t * vm = va_arg (*va, vlib_main_t *);
200 ip6_neighbor_t * n = va_arg (*va, ip6_neighbor_t *);
201 vnet_main_t * vnm = vnet_get_main();
202 vnet_sw_interface_t * si;
205 return format (s, "%=12s%=20s%=20s%=40s", "Time", "Address", "Link layer", "Interface");
207 si = vnet_get_sw_interface (vnm, n->key.sw_if_index);
208 s = format (s, "%=12U%=20U%=20U%=40U",
209 format_vlib_cpu_time, vm, n->cpu_time_last_updated,
210 format_ip6_address, &n->key.ip6_address,
211 format_ethernet_address, n->link_layer_address,
212 format_vnet_sw_interface_name, vnm, si);
217 static clib_error_t *
218 ip6_neighbor_sw_interface_up_down (vnet_main_t * vnm,
222 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
225 if (! (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
227 u32 i, * to_delete = 0;
229 pool_foreach (n, nm->neighbor_pool, ({
230 if (n->key.sw_if_index == sw_if_index)
231 vec_add1 (to_delete, n - nm->neighbor_pool);
234 for (i = 0; i < vec_len (to_delete); i++)
236 n = pool_elt_at_index (nm->neighbor_pool, to_delete[i]);
237 mhash_unset (&nm->neighbor_index_by_key, &n->key, 0);
238 pool_put (nm->neighbor_pool, n);
241 vec_free (to_delete);
247 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (ip6_neighbor_sw_interface_up_down);
249 static void unset_random_neighbor_entry (void)
251 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
252 vnet_main_t * vnm = vnet_get_main();
253 vlib_main_t * vm = vnm->vlib_main;
257 index = pool_next_index (nm->neighbor_pool, nm->neighbor_delete_rotor);
258 nm->neighbor_delete_rotor = index;
260 /* Try again from elt 0, could happen if an intfc goes down */
263 index = pool_next_index (nm->neighbor_pool, nm->neighbor_delete_rotor);
264 nm->neighbor_delete_rotor = index;
267 /* Nothing left in the pool */
271 e = pool_elt_at_index (nm->neighbor_pool, index);
273 vnet_unset_ip6_ethernet_neighbor (vm, e->key.sw_if_index,
275 e->link_layer_address,
282 u8 link_layer_address[6];
285 } ip6_neighbor_set_unset_rpc_args_t;
287 static void ip6_neighbor_set_unset_rpc_callback
288 ( ip6_neighbor_set_unset_rpc_args_t * a);
291 static void set_unset_ip6_neighbor_rpc
295 u8 *link_layer_addreess,
298 ip6_neighbor_set_unset_rpc_args_t args;
300 args.sw_if_index = sw_if_index;
301 args.is_add = is_add;
302 memcpy (&args.addr, a, sizeof (*a));
303 memcpy (args.link_layer_address, link_layer_addreess, 6);
305 vl_api_rpc_call_main_thread (ip6_neighbor_set_unset_rpc_callback,
306 (u8 *) &args, sizeof (args));
311 vnet_set_ip6_ethernet_neighbor (vlib_main_t * vm,
314 u8 * link_layer_address,
315 uword n_bytes_link_layer_address)
317 vnet_main_t * vnm = vnet_get_main();
318 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
319 ip6_neighbor_key_t k;
321 ip6_main_t * im = &ip6_main;
324 pending_resolution_t * pr;
327 if (os_get_cpu_number())
329 set_unset_ip6_neighbor_rpc (vm, sw_if_index, a, link_layer_address,
330 1 /* set new neighbor */);
335 k.sw_if_index = sw_if_index;
336 k.ip6_address = a[0];
339 vlib_worker_thread_barrier_sync (vm);
341 p = mhash_get (&nm->neighbor_index_by_key, &k);
343 n = pool_elt_at_index (nm->neighbor_pool, p[0]);
346 ip6_add_del_route_args_t args;
349 memset (&adj, 0, sizeof(adj));
350 adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
351 adj.explicit_fib_index = ~0;
353 vnet_rewrite_for_sw_interface
355 VNET_L3_PACKET_TYPE_IP6,
357 ip6_rewrite_node.index,
360 sizeof (adj.rewrite_data));
362 args.table_index_or_table_id = im->fib_index_by_sw_if_index[sw_if_index];
363 args.flags = IP6_ROUTE_FLAG_FIB_INDEX | IP6_ROUTE_FLAG_ADD | IP6_ROUTE_FLAG_NEIGHBOR;
364 args.dst_address = a[0];
365 args.dst_address_length = 128;
370 ip6_add_del_route (im, &args);
371 pool_get (nm->neighbor_pool, n);
372 mhash_set (&nm->neighbor_index_by_key, &k, n - nm->neighbor_pool,
377 /* Update time stamp and ethernet address. */
378 memcpy (n->link_layer_address, link_layer_address, n_bytes_link_layer_address);
379 n->cpu_time_last_updated = clib_cpu_time_now ();
381 /* Customer(s) waiting for this address to be resolved? */
382 p = mhash_get (&nm->pending_resolutions_by_address, a);
388 while (next_index != (u32)~0)
390 pr = pool_elt_at_index (nm->pending_resolutions, next_index);
391 vlib_process_signal_event (vm, pr->node_index,
394 next_index = pr->next_index;
395 pool_put (nm->pending_resolutions, pr);
398 mhash_unset (&nm->pending_resolutions_by_address, a, 0);
401 vlib_worker_thread_barrier_release(vm);
406 vnet_unset_ip6_ethernet_neighbor (vlib_main_t * vm,
409 u8 * link_layer_address,
410 uword n_bytes_link_layer_address)
412 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
413 ip6_neighbor_key_t k;
415 ip6_main_t * im = &ip6_main;
416 ip6_add_del_route_args_t args;
421 if (os_get_cpu_number())
423 set_unset_ip6_neighbor_rpc (vm, sw_if_index, a, link_layer_address,
429 k.sw_if_index = sw_if_index;
430 k.ip6_address = a[0];
433 vlib_worker_thread_barrier_sync (vm);
435 p = mhash_get (&nm->neighbor_index_by_key, &k);
442 n = pool_elt_at_index (nm->neighbor_pool, p[0]);
443 mhash_unset (&nm->neighbor_index_by_key, &n->key, 0);
444 pool_put (nm->neighbor_pool, n);
446 args.table_index_or_table_id = im->fib_index_by_sw_if_index[sw_if_index];
447 args.flags = IP6_ROUTE_FLAG_FIB_INDEX | IP6_ROUTE_FLAG_DEL
448 | IP6_ROUTE_FLAG_NEIGHBOR;
449 args.dst_address = a[0];
450 args.dst_address_length = 128;
454 ip6_add_del_route (im, &args);
456 vlib_worker_thread_barrier_release(vm);
460 static void ip6_neighbor_set_unset_rpc_callback
461 ( ip6_neighbor_set_unset_rpc_args_t * a)
463 vlib_main_t * vm = vlib_get_main();
465 vnet_set_ip6_ethernet_neighbor (vm, a->sw_if_index, &a->addr,
466 a->link_layer_address, 6);
468 vnet_unset_ip6_ethernet_neighbor (vm, a->sw_if_index, &a->addr,
469 a->link_layer_address, 6);
473 ip6_neighbor_sort (void *a1, void *a2)
475 vnet_main_t * vnm = vnet_get_main();
476 ip6_neighbor_t * n1 = a1, * n2 = a2;
478 cmp = vnet_sw_interface_compare (vnm, n1->key.sw_if_index,
479 n2->key.sw_if_index);
481 cmp = ip6_address_compare (&n1->key.ip6_address, &n2->key.ip6_address);
485 static clib_error_t *
486 show_ip6_neighbors (vlib_main_t * vm,
487 unformat_input_t * input,
488 vlib_cli_command_t * cmd)
490 vnet_main_t * vnm = vnet_get_main();
491 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
492 ip6_neighbor_t * n, * ns;
493 clib_error_t * error = 0;
496 /* Filter entries by interface if given. */
498 (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index);
501 pool_foreach (n, nm->neighbor_pool, ({ vec_add1 (ns, n[0]); }));
502 vec_sort_with_function (ns, ip6_neighbor_sort);
503 vlib_cli_output (vm, "%U", format_ip6_neighbor_ip6_entry, vm, 0);
504 vec_foreach (n, ns) {
505 if (sw_if_index != ~0 && n->key.sw_if_index != sw_if_index)
507 vlib_cli_output (vm, "%U", format_ip6_neighbor_ip6_entry, vm, n);
514 VLIB_CLI_COMMAND (show_ip6_neighbors_command, static) = {
515 .path = "show ip6 neighbors",
516 .function = show_ip6_neighbors,
517 .short_help = "Show ip6 neighbors",
520 static clib_error_t *
521 set_ip6_neighbor (vlib_main_t * vm,
522 unformat_input_t * input,
523 vlib_cli_command_t * cmd)
525 vnet_main_t * vnm = vnet_get_main();
532 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
534 /* intfc, ip6-address, mac-address */
535 if (unformat (input, "%U %U %U",
536 unformat_vnet_sw_interface, vnm, &sw_if_index,
537 unformat_ip6_address, &addr,
538 unformat_ethernet_address, mac_address))
541 else if (unformat (input, "delete") || unformat (input, "del"))
548 return clib_error_return (0, "Missing interface, ip6 or hw address");
551 vnet_set_ip6_ethernet_neighbor (vm, sw_if_index, &addr,
552 mac_address, sizeof(mac_address));
554 vnet_unset_ip6_ethernet_neighbor (vm, sw_if_index, &addr,
555 mac_address, sizeof(mac_address));
559 VLIB_CLI_COMMAND (set_ip6_neighbor_command, static) = {
560 .path = "set ip6 neighbor",
561 .function = set_ip6_neighbor,
562 .short_help = "set ip6 neighbor [del] <intfc> <ip6-address> <mac-address>",
566 ICMP6_NEIGHBOR_SOLICITATION_NEXT_DROP,
567 ICMP6_NEIGHBOR_SOLICITATION_NEXT_REPLY,
568 ICMP6_NEIGHBOR_SOLICITATION_N_NEXT,
569 } icmp6_neighbor_solicitation_or_advertisement_next_t;
571 static_always_inline uword
572 icmp6_neighbor_solicitation_or_advertisement (vlib_main_t * vm,
573 vlib_node_runtime_t * node,
574 vlib_frame_t * frame,
575 uword is_solicitation)
577 vnet_main_t * vnm = vnet_get_main();
578 ip6_main_t * im = &ip6_main;
579 ip_lookup_main_t * lm = &im->lookup_main;
580 uword n_packets = frame->n_vectors;
581 u32 * from, * to_next;
582 u32 n_left_from, n_left_to_next, next_index, n_advertisements_sent;
583 icmp6_neighbor_discovery_option_type_t option_type;
584 vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip6_icmp_input_node.index);
587 from = vlib_frame_vector_args (frame);
588 n_left_from = n_packets;
589 next_index = node->cached_next_index;
591 if (node->flags & VLIB_NODE_FLAG_TRACE)
592 vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
594 sizeof (icmp6_input_trace_t));
598 ? ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address
599 : ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address);
600 n_advertisements_sent = 0;
602 while (n_left_from > 0)
604 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
606 while (n_left_from > 0 && n_left_to_next > 0)
610 icmp6_neighbor_solicitation_or_advertisement_header_t * h0;
611 icmp6_neighbor_discovery_ethernet_link_layer_address_option_t * o0;
612 u32 bi0, options_len0, sw_if_index0, next0, error0;
613 u32 ip6_sadd_link_local, ip6_sadd_unspecified;
617 bi0 = to_next[0] = from[0];
624 p0 = vlib_get_buffer (vm, bi0);
625 ip0 = vlib_buffer_get_current (p0);
626 h0 = ip6_next_header (ip0);
627 options_len0 = clib_net_to_host_u16 (ip0->payload_length) - sizeof (h0[0]);
629 error0 = ICMP6_ERROR_NONE;
630 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
631 ip6_sadd_link_local = ip6_address_is_link_local_unicast(&ip0->src_address);
632 ip6_sadd_unspecified = ip6_address_is_unspecified (&ip0->src_address);
634 /* Check that source address is unspecified, link-local or else on-link. */
635 if (!ip6_sadd_unspecified && !ip6_sadd_link_local)
637 u32 src_adj_index0 = ip6_src_lookup_for_packet (im, p0, ip0);
638 ip_adjacency_t * adj0 = ip_get_adjacency (&im->lookup_main, src_adj_index0);
640 /* Allow all realistic-looking rewrite adjacencies to pass */
641 ni0 = adj0->lookup_next_index;
642 is_rewrite0 = (ni0 >= IP_LOOKUP_NEXT_ARP) &&
643 (ni0 < IP_LOOKUP_N_NEXT);
645 error0 = ((adj0->rewrite_header.sw_if_index != sw_if_index0
647 ? ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_NOT_ON_LINK
651 o0 = (void *) (h0 + 1);
652 o0 = ((options_len0 == 8 && o0->header.type == option_type
653 && o0->header.n_data_u64s == 1) ? o0 : 0);
655 /* If src address unspecified or link local, donot learn neighbor MAC */
656 if (PREDICT_TRUE (error0 == ICMP6_ERROR_NONE && o0 != 0 &&
657 !ip6_sadd_unspecified && !ip6_sadd_link_local))
659 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
660 if (nm->limit_neighbor_cache_size &&
661 pool_elts (nm->neighbor_pool) >= nm->limit_neighbor_cache_size)
662 unset_random_neighbor_entry();
663 vnet_set_ip6_ethernet_neighbor (
665 is_solicitation ? &ip0->src_address : &h0->target_address,
666 o0->ethernet_address, sizeof (o0->ethernet_address));
669 if (is_solicitation && error0 == ICMP6_ERROR_NONE)
671 /* Check that target address is one that we know about. */
672 ip_interface_address_t * ia0;
673 ip6_address_fib_t ip6_af0;
676 ip6_addr_fib_init (&ip6_af0, &h0->target_address,
677 vec_elt (im->fib_index_by_sw_if_index,
680 /* Gross kludge, "thank you" MJ, don't even ask */
681 oldheap = clib_mem_set_heap (clib_per_cpu_mheaps[0]);
682 ia0 = ip_get_interface_address (lm, &ip6_af0);
683 clib_mem_set_heap (oldheap);
685 ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_UNKNOWN : error0;
689 next0 = (error0 != ICMP6_ERROR_NONE
690 ? ICMP6_NEIGHBOR_SOLICITATION_NEXT_DROP
691 : ICMP6_NEIGHBOR_SOLICITATION_NEXT_REPLY);
695 error0 = error0 == ICMP6_ERROR_NONE ?
696 ICMP6_ERROR_NEIGHBOR_ADVERTISEMENTS_RX : error0;
699 if (is_solicitation && error0 == ICMP6_ERROR_NONE)
701 vnet_sw_interface_t * sw_if0;
702 ethernet_interface_t * eth_if0;
703 ethernet_header_t *eth0;
705 /* dst address is either source address or the all-nodes mcast addr */
706 if(!ip6_sadd_unspecified)
707 ip0->dst_address = ip0->src_address;
709 ip6_set_reserved_multicast_address(&ip0->dst_address,
710 IP6_MULTICAST_SCOPE_link_local,
711 IP6_MULTICAST_GROUP_ID_all_hosts);
713 ip0->src_address = h0->target_address;
714 ip0->hop_limit = 255;
715 h0->icmp.type = ICMP6_neighbor_advertisement;
717 sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
718 ASSERT (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
719 eth_if0 = ethernet_get_interface (ðernet_main, sw_if0->hw_if_index);
722 memcpy (o0->ethernet_address, eth_if0->address, 6);
724 ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
727 h0->advertisement_flags = clib_host_to_net_u32
728 (ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED
729 | ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE);
731 h0->icmp.checksum = 0;
733 ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0,
735 ASSERT(bogus_length == 0);
737 /* Reuse current MAC header, copy SMAC to DMAC and
738 * interface MAC to SMAC */
739 vlib_buffer_reset (p0);
740 eth0 = vlib_buffer_get_current(p0);
741 memcpy(eth0->dst_address, eth0->src_address, 6);
742 memcpy(eth0->src_address, eth_if0->address, 6);
744 /* Setup input and output sw_if_index for packet */
745 ASSERT(vnet_buffer(p0)->sw_if_index[VLIB_RX] == sw_if_index0);
746 vnet_buffer(p0)->sw_if_index[VLIB_TX] = sw_if_index0;
747 vnet_buffer(p0)->sw_if_index[VLIB_RX] =
748 vnet_main.local_interface_sw_if_index;
750 n_advertisements_sent++;
753 p0->error = error_node->errors[error0];
755 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
756 to_next, n_left_to_next,
760 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
763 /* Account for advertisements sent. */
764 vlib_error_count (vm, error_node->node_index, ICMP6_ERROR_NEIGHBOR_ADVERTISEMENTS_TX, n_advertisements_sent);
766 return frame->n_vectors;
769 /* for "syslogging" - use elog for now */
770 #define foreach_log_level \
772 _ (INFO, "INFORMATION") \
773 _ (NOTICE, "NOTICE") \
774 _ (WARNING, "WARNING") \
776 _ (CRIT, "CRITICAL") \
778 _ (EMERG, "EMERGENCY")
781 #define _(f,s) LOG_##f,
786 static char * log_level_strings[] = {
792 static int logmask = 1 << LOG_DEBUG;
795 ip6_neighbor_syslog(vlib_main_t *vm, int priority, char * fmt, ...)
797 /* just use elog for now */
801 if( (priority > LOG_EMERG) ||
802 !(logmask & (1 << priority)))
808 what = va_format (0, fmt, &va);
810 ELOG_TYPE_DECLARE (e) = {
811 .format = "ip6 nd: (%s): %s",
812 .format_args = "T4T4",
814 struct { u32 s[2]; } * ed;
815 ed = ELOG_DATA (&vm->elog_main, e);
816 ed->s[0] = elog_string(&vm->elog_main, log_level_strings[priority]);
817 ed->s[1] = elog_string(&vm->elog_main, (char *)what);
823 /* ipv6 neighbor discovery - router advertisements */
825 ICMP6_ROUTER_SOLICITATION_NEXT_DROP,
826 ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW,
827 ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX,
828 ICMP6_ROUTER_SOLICITATION_N_NEXT,
829 } icmp6_router_solicitation_or_advertisement_next_t;
831 static_always_inline uword
832 icmp6_router_solicitation(vlib_main_t * vm,
833 vlib_node_runtime_t * node,
834 vlib_frame_t * frame)
836 vnet_main_t * vnm = vnet_get_main();
837 ip6_main_t * im = &ip6_main;
838 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
839 uword n_packets = frame->n_vectors;
840 u32 * from, * to_next;
841 u32 n_left_from, n_left_to_next, next_index;
842 u32 n_advertisements_sent = 0;
845 icmp6_neighbor_discovery_option_type_t option_type;
847 vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip6_icmp_input_node.index);
849 from = vlib_frame_vector_args (frame);
850 n_left_from = n_packets;
851 next_index = node->cached_next_index;
853 if (node->flags & VLIB_NODE_FLAG_TRACE)
854 vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
856 sizeof (icmp6_input_trace_t));
858 /* source may append his LL address */
859 option_type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
861 while (n_left_from > 0)
863 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
865 while (n_left_from > 0 && n_left_to_next > 0)
869 ip6_radv_t *radv_info = 0;
871 icmp6_neighbor_discovery_header_t * h0;
872 icmp6_neighbor_discovery_ethernet_link_layer_address_option_t * o0;
874 u32 bi0, options_len0, sw_if_index0, next0, error0;
875 u32 is_solicitation = 1, is_dropped = 0;
876 u32 is_unspecified, is_link_local;
878 bi0 = to_next[0] = from[0];
885 p0 = vlib_get_buffer (vm, bi0);
886 ip0 = vlib_buffer_get_current (p0);
887 h0 = ip6_next_header (ip0);
888 options_len0 = clib_net_to_host_u16 (ip0->payload_length) - sizeof (h0[0]);
889 is_unspecified = ip6_address_is_unspecified (&ip0->src_address);
890 is_link_local = ip6_address_is_link_local_unicast (&ip0->src_address);
892 error0 = ICMP6_ERROR_NONE;
893 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
895 /* check if solicitation (not from nd_timer node) */
896 if (ip6_address_is_unspecified (&ip0->dst_address))
899 /* Check that source address is unspecified, link-local or else on-link. */
900 if (!is_unspecified && !is_link_local)
902 u32 src_adj_index0 = ip6_src_lookup_for_packet (im, p0, ip0);
903 ip_adjacency_t * adj0 = ip_get_adjacency (&im->lookup_main, src_adj_index0);
905 error0 = ((adj0->rewrite_header.sw_if_index != sw_if_index0
906 || (adj0->lookup_next_index != IP_LOOKUP_NEXT_ARP
907 && adj0->lookup_next_index != IP_LOOKUP_NEXT_REWRITE))
908 ? ICMP6_ERROR_ROUTER_SOLICITATION_SOURCE_NOT_ON_LINK
912 /* check for source LL option and process */
913 o0 = (void *) (h0 + 1);
914 o0 = ((options_len0 == 8
915 && o0->header.type == option_type
916 && o0->header.n_data_u64s == 1)
920 /* if src address unspecified IGNORE any options */
921 if (PREDICT_TRUE (error0 == ICMP6_ERROR_NONE && o0 != 0 &&
922 !is_unspecified && !is_link_local)) {
923 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
924 if (nm->limit_neighbor_cache_size &&
925 pool_elts (nm->neighbor_pool) >= nm->limit_neighbor_cache_size)
926 unset_random_neighbor_entry();
928 vnet_set_ip6_ethernet_neighbor (vm, sw_if_index0,
930 o0->ethernet_address,
931 sizeof (o0->ethernet_address));
934 /* default is to drop */
935 next0 = ICMP6_ROUTER_SOLICITATION_NEXT_DROP;
937 if (error0 == ICMP6_ERROR_NONE)
939 vnet_sw_interface_t * sw_if0;
940 ethernet_interface_t * eth_if0;
943 sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
944 ASSERT (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
945 eth_if0 = ethernet_get_interface (ðernet_main, sw_if0->hw_if_index);
947 /* only support ethernet interface type for now */
948 error0 = (!eth_if0) ? ICMP6_ERROR_ROUTER_SOLICITATION_UNSUPPORTED_INTF : error0;
950 if (error0 == ICMP6_ERROR_NONE)
954 /* adjust the sizeof the buffer to just include the ipv6 header */
955 p0->current_length -= (options_len0 + sizeof(icmp6_neighbor_discovery_header_t));
957 /* look up the radv_t information for this interface */
958 vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index0, ~0);
960 ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index0];
963 radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
965 error0 = ((!radv_info) ? ICMP6_ERROR_ROUTER_SOLICITATION_RADV_NOT_CONFIG : error0);
967 if (error0 == ICMP6_ERROR_NONE)
969 f64 now = vlib_time_now (vm);
971 /* for solicited adverts - need to rate limit */
974 if( (now - radv_info->last_radv_time) < MIN_DELAY_BETWEEN_RAS )
977 radv_info->last_radv_time = now;
981 icmp6_router_advertisement_header_t rh;
983 rh.icmp.type = ICMP6_router_advertisement;
985 rh.icmp.checksum = 0;
987 rh.current_hop_limit = radv_info->curr_hop_limit;
988 rh.router_lifetime_in_sec = clib_host_to_net_u16(radv_info->adv_router_lifetime_in_sec);
989 rh.time_in_msec_between_retransmitted_neighbor_solicitations =
990 clib_host_to_net_u32(radv_info->adv_time_in_msec_between_retransmitted_neighbor_solicitations);
991 rh.neighbor_reachable_time_in_msec =
992 clib_host_to_net_u32(radv_info->adv_neighbor_reachable_time_in_msec);
994 rh.flags = (radv_info->adv_managed_flag) ? ICMP6_ROUTER_DISCOVERY_FLAG_ADDRESS_CONFIG_VIA_DHCP : 0;
995 rh.flags |= ( (radv_info->adv_other_flag) ? ICMP6_ROUTER_DISCOVERY_FLAG_OTHER_CONFIG_VIA_DHCP : 0);
998 u16 payload_length = sizeof(icmp6_router_advertisement_header_t);
1000 vlib_buffer_add_data (vm,
1001 p0->free_list_index,
1003 (void *)&rh, sizeof(icmp6_router_advertisement_header_t));
1005 if(radv_info->adv_link_layer_address)
1007 icmp6_neighbor_discovery_ethernet_link_layer_address_option_t h;
1009 h.header.type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
1010 h.header.n_data_u64s = 1;
1012 /* copy ll address */
1013 memcpy(&h.ethernet_address[0], eth_if0->address, 6);
1015 vlib_buffer_add_data (vm,
1016 p0->free_list_index,
1018 (void *)&h, sizeof(icmp6_neighbor_discovery_ethernet_link_layer_address_option_t));
1020 payload_length += sizeof(icmp6_neighbor_discovery_ethernet_link_layer_address_option_t);
1023 /* add MTU option */
1024 if(radv_info->adv_link_mtu)
1026 icmp6_neighbor_discovery_mtu_option_t h;
1029 h.mtu = clib_host_to_net_u32(radv_info->adv_link_mtu);
1030 h.header.type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_mtu;
1031 h.header.n_data_u64s = 1;
1033 payload_length += sizeof( icmp6_neighbor_discovery_mtu_option_t);
1035 vlib_buffer_add_data (vm,
1036 p0->free_list_index,
1038 (void *)&h, sizeof(icmp6_neighbor_discovery_mtu_option_t));
1041 /* add advertised prefix options */
1042 ip6_radv_prefix_t *pr_info;
1044 pool_foreach (pr_info, radv_info->adv_prefixes_pool, ({
1046 if(pr_info->enabled &&
1047 (!pr_info->decrement_lifetime_flag || (pr_info->pref_lifetime_expires >0)))
1049 /* advertise this prefix */
1050 icmp6_neighbor_discovery_prefix_information_option_t h;
1052 h.header.type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_prefix_information;
1053 h.header.n_data_u64s = (sizeof(icmp6_neighbor_discovery_prefix_information_option_t) >> 3);
1055 h.dst_address_length = pr_info->prefix_len;
1057 h.flags = (pr_info->adv_on_link_flag) ? ICMP6_NEIGHBOR_DISCOVERY_PREFIX_INFORMATION_FLAG_ON_LINK : 0;
1058 h.flags |= (pr_info->adv_autonomous_flag) ? ICMP6_NEIGHBOR_DISCOVERY_PREFIX_INFORMATION_AUTO : 0;
1060 if(radv_info->cease_radv && pr_info->deprecated_prefix_flag)
1062 h.valid_time = clib_host_to_net_u32(MIN_ADV_VALID_LIFETIME);
1063 h.preferred_time = 0;
1067 if(pr_info->decrement_lifetime_flag)
1069 pr_info->adv_valid_lifetime_in_secs = ((pr_info->valid_lifetime_expires > now)) ?
1070 (pr_info->valid_lifetime_expires - now) : 0;
1072 pr_info->adv_pref_lifetime_in_secs = ((pr_info->pref_lifetime_expires > now)) ?
1073 (pr_info->pref_lifetime_expires - now) : 0;
1076 h.valid_time = clib_host_to_net_u32(pr_info->adv_valid_lifetime_in_secs);
1077 h.preferred_time = clib_host_to_net_u32(pr_info->adv_pref_lifetime_in_secs) ;
1081 memcpy(&h.dst_address, &pr_info->prefix, sizeof(ip6_address_t));
1083 payload_length += sizeof( icmp6_neighbor_discovery_prefix_information_option_t);
1085 vlib_buffer_add_data (vm,
1086 p0->free_list_index,
1088 (void *)&h, sizeof(icmp6_neighbor_discovery_prefix_information_option_t));
1093 /* add additional options before here */
1095 /* finish building the router advertisement... */
1096 if(!is_unspecified && radv_info->send_unicast)
1098 ip0->dst_address = ip0->src_address;
1102 /* target address is all-nodes mcast addr */
1103 ip6_set_reserved_multicast_address(&ip0->dst_address,
1104 IP6_MULTICAST_SCOPE_link_local,
1105 IP6_MULTICAST_GROUP_ID_all_hosts);
1108 /* source address MUST be the link-local address */
1109 ip0->src_address = radv_info->link_local_address;
1111 ip0->hop_limit = 255;
1112 ip0->payload_length = clib_host_to_net_u16 (payload_length);
1114 icmp6_router_advertisement_header_t * rh0 = (icmp6_router_advertisement_header_t *)(ip0 + 1);
1115 rh0->icmp.checksum =
1116 ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0,
1118 ASSERT(bogus_length == 0);
1120 /* setup output if and adjacency */
1121 vnet_buffer (p0)->sw_if_index[VLIB_RX] =
1122 vnet_main.local_interface_sw_if_index;
1124 if (is_solicitation)
1126 ethernet_header_t *eth0;
1127 /* Reuse current MAC header, copy SMAC to DMAC and
1128 * interface MAC to SMAC */
1129 vlib_buffer_reset (p0);
1130 eth0 = vlib_buffer_get_current(p0);
1131 memcpy(eth0->dst_address, eth0->src_address, 6);
1132 memcpy(eth0->src_address, eth_if0->address, 6);
1133 next0 = is_dropped ?
1134 next0 : ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX;
1135 vnet_buffer(p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1139 adj_index0 = radv_info->all_nodes_adj_index;
1140 if (adj_index0 == 0)
1141 error0 = ICMP6_ERROR_DST_LOOKUP_MISS;
1144 ip_adjacency_t * adj0 = ip_get_adjacency (&im->lookup_main, adj_index0);
1146 ((adj0->rewrite_header.sw_if_index != sw_if_index0
1147 || adj0->lookup_next_index != IP_LOOKUP_NEXT_REWRITE)
1148 ? ICMP6_ERROR_ROUTER_SOLICITATION_DEST_UNKNOWN
1150 next0 = is_dropped ?
1151 next0 : ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW;
1152 vnet_buffer (p0)->ip.adj_index[VLIB_RX] = adj_index0;
1156 radv_info->n_solicitations_dropped += is_dropped;
1157 radv_info->n_solicitations_rcvd += is_solicitation;
1159 if((error0 == ICMP6_ERROR_NONE) && !is_dropped)
1161 radv_info->n_advertisements_sent++;
1162 n_advertisements_sent++;
1168 p0->error = error_node->errors[error0];
1170 if(error0 != ICMP6_ERROR_NONE)
1171 vlib_error_count (vm, error_node->node_index, error0, 1);
1173 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1174 to_next, n_left_to_next,
1179 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1182 /* Account for router advertisements sent. */
1183 vlib_error_count (vm, error_node->node_index, ICMP6_ERROR_ROUTER_ADVERTISEMENTS_TX, n_advertisements_sent);
1185 return frame->n_vectors;
1188 /* validate advertised info for consistancy (see RFC-4861 section 6.2.7) - log any inconsistencies, packet will always be dropped */
1189 static_always_inline uword
1190 icmp6_router_advertisement(vlib_main_t * vm,
1191 vlib_node_runtime_t * node,
1192 vlib_frame_t * frame)
1194 vnet_main_t * vnm = vnet_get_main();
1195 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
1196 uword n_packets = frame->n_vectors;
1197 u32 * from, * to_next;
1198 u32 n_left_from, n_left_to_next, next_index;
1199 u32 n_advertisements_rcvd = 0;
1201 vlib_node_runtime_t * error_node = vlib_node_get_runtime (vm, ip6_icmp_input_node.index);
1203 from = vlib_frame_vector_args (frame);
1204 n_left_from = n_packets;
1205 next_index = node->cached_next_index;
1207 if (node->flags & VLIB_NODE_FLAG_TRACE)
1208 vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
1210 sizeof (icmp6_input_trace_t));
1212 while (n_left_from > 0)
1214 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1216 while (n_left_from > 0 && n_left_to_next > 0)
1220 ip6_radv_t *radv_info = 0;
1221 icmp6_router_advertisement_header_t * h0;
1222 u32 bi0, options_len0, sw_if_index0, next0, error0;
1224 bi0 = to_next[0] = from[0];
1229 n_left_to_next -= 1;
1231 p0 = vlib_get_buffer (vm, bi0);
1232 ip0 = vlib_buffer_get_current (p0);
1233 h0 = ip6_next_header (ip0);
1234 options_len0 = clib_net_to_host_u16 (ip0->payload_length) - sizeof (h0[0]);
1236 error0 = ICMP6_ERROR_NONE;
1237 sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1239 /* Check that source address is link-local*/
1240 error0 = (!ip6_address_is_link_local_unicast (&ip0->src_address)) ?
1241 ICMP6_ERROR_ROUTER_ADVERTISEMENT_SOURCE_NOT_LINK_LOCAL : error0;
1243 /* default is to drop */
1244 next0 = ICMP6_ROUTER_SOLICITATION_NEXT_DROP;
1246 n_advertisements_rcvd++;
1248 if (error0 == ICMP6_ERROR_NONE)
1250 vnet_sw_interface_t * sw_if0;
1251 ethernet_interface_t * eth_if0;
1253 sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
1254 ASSERT (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
1255 eth_if0 = ethernet_get_interface (ðernet_main, sw_if0->hw_if_index);
1257 /* only support ethernet interface type for now */
1258 error0 = (!eth_if0) ? ICMP6_ERROR_ROUTER_SOLICITATION_UNSUPPORTED_INTF : error0;
1260 if (error0 == ICMP6_ERROR_NONE)
1264 /* look up the radv_t information for this interface */
1265 vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index0, ~0);
1267 ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index0];
1270 radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
1272 error0 = ((!radv_info) ? ICMP6_ERROR_ROUTER_SOLICITATION_RADV_NOT_CONFIG : error0);
1274 if (error0 == ICMP6_ERROR_NONE)
1276 /* validate advertised information */
1277 if((h0->current_hop_limit && radv_info->curr_hop_limit) &&
1278 (h0->current_hop_limit != radv_info->curr_hop_limit))
1280 ip6_neighbor_syslog(vm, LOG_WARNING,
1281 "our AdvCurHopLimit on %U doesn't agree with %U",
1282 format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1285 if((h0->flags & ICMP6_ROUTER_DISCOVERY_FLAG_ADDRESS_CONFIG_VIA_DHCP) !=
1286 radv_info->adv_managed_flag)
1288 ip6_neighbor_syslog(vm, LOG_WARNING,
1289 "our AdvManagedFlag on %U doesn't agree with %U",
1290 format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1293 if((h0->flags & ICMP6_ROUTER_DISCOVERY_FLAG_OTHER_CONFIG_VIA_DHCP) !=
1294 radv_info->adv_other_flag)
1296 ip6_neighbor_syslog(vm, LOG_WARNING,
1297 "our AdvOtherConfigFlag on %U doesn't agree with %U",
1298 format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1301 if((h0->time_in_msec_between_retransmitted_neighbor_solicitations &&
1302 radv_info->adv_time_in_msec_between_retransmitted_neighbor_solicitations) &&
1303 (h0->time_in_msec_between_retransmitted_neighbor_solicitations !=
1304 clib_host_to_net_u32(radv_info->adv_time_in_msec_between_retransmitted_neighbor_solicitations)))
1306 ip6_neighbor_syslog(vm, LOG_WARNING,
1307 "our AdvRetransTimer on %U doesn't agree with %U",
1308 format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1311 if((h0->neighbor_reachable_time_in_msec &&
1312 radv_info->adv_neighbor_reachable_time_in_msec) &&
1313 (h0->neighbor_reachable_time_in_msec !=
1314 clib_host_to_net_u32(radv_info->adv_neighbor_reachable_time_in_msec)))
1316 ip6_neighbor_syslog(vm, LOG_WARNING,
1317 "our AdvReachableTime on %U doesn't agree with %U",
1318 format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1321 /* check for MTU or prefix options or .. */
1322 u8 * opt_hdr = (u8 *)(h0 + 1);
1323 while( options_len0 > 0)
1325 icmp6_neighbor_discovery_option_header_t *o0 = ( icmp6_neighbor_discovery_option_header_t *)opt_hdr;
1326 int opt_len = o0->n_data_u64s << 3;
1327 icmp6_neighbor_discovery_option_type_t option_type = o0->type;
1329 if(options_len0 < 2)
1331 ip6_neighbor_syslog(vm, LOG_ERR,
1332 "malformed RA packet on %U from %U",
1333 format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1339 ip6_neighbor_syslog(vm, LOG_ERR,
1340 " zero length option in RA on %U from %U",
1341 format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1344 else if( opt_len > options_len0)
1346 ip6_neighbor_syslog(vm, LOG_ERR,
1347 "option length in RA packet greater than total length on %U from %U",
1348 format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1352 options_len0 -= opt_len;
1357 case ICMP6_NEIGHBOR_DISCOVERY_OPTION_mtu:
1359 icmp6_neighbor_discovery_mtu_option_t *h =
1360 (icmp6_neighbor_discovery_mtu_option_t *)(o0);
1362 if(opt_len < sizeof(*h))
1365 if((h->mtu && radv_info->adv_link_mtu) &&
1366 (h->mtu != clib_host_to_net_u32(radv_info->adv_link_mtu)))
1368 ip6_neighbor_syslog(vm, LOG_WARNING,
1369 "our AdvLinkMTU on %U doesn't agree with %U",
1370 format_vnet_sw_if_index_name, vnm, sw_if_index0, format_ip6_address, &ip0->src_address);
1375 case ICMP6_NEIGHBOR_DISCOVERY_OPTION_prefix_information:
1377 icmp6_neighbor_discovery_prefix_information_option_t *h =
1378 (icmp6_neighbor_discovery_prefix_information_option_t *)(o0);
1380 /* validate advertised prefix options */
1381 ip6_radv_prefix_t *pr_info;
1382 u32 preferred, valid;
1384 if(opt_len < sizeof(*h))
1387 preferred = clib_net_to_host_u32(h->preferred_time);
1388 valid = clib_net_to_host_u32(h->valid_time);
1390 /* look for matching prefix - if we our advertising it, it better be consistant */
1391 pool_foreach (pr_info, radv_info->adv_prefixes_pool, ({
1394 ip6_address_mask_from_width(&mask, pr_info->prefix_len);
1396 if(pr_info->enabled &&
1397 (pr_info->prefix_len == h->dst_address_length) &&
1398 ip6_address_is_equal_masked (&pr_info->prefix, &h->dst_address, &mask))
1401 if(!pr_info->decrement_lifetime_flag &&
1402 valid != pr_info->adv_valid_lifetime_in_secs)
1404 ip6_neighbor_syslog(vm, LOG_WARNING,
1405 "our ADV validlifetime on %U for %U does not agree with %U",
1406 format_vnet_sw_if_index_name, vnm, sw_if_index0,format_ip6_address, &pr_info->prefix,
1407 format_ip6_address, &h->dst_address);
1409 if(!pr_info->decrement_lifetime_flag &&
1410 preferred != pr_info->adv_pref_lifetime_in_secs)
1412 ip6_neighbor_syslog(vm, LOG_WARNING,
1413 "our ADV preferredlifetime on %U for %U does not agree with %U",
1414 format_vnet_sw_if_index_name, vnm, sw_if_index0,format_ip6_address, &pr_info->prefix,
1415 format_ip6_address, &h->dst_address);
1431 p0->error = error_node->errors[error0];
1433 if(error0 != ICMP6_ERROR_NONE)
1434 vlib_error_count (vm, error_node->node_index, error0, 1);
1436 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1437 to_next, n_left_to_next,
1441 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1444 /* Account for router advertisements sent. */
1445 vlib_error_count (vm, error_node->node_index, ICMP6_ERROR_ROUTER_ADVERTISEMENTS_RX, n_advertisements_rcvd);
1447 return frame->n_vectors;
1450 /* create and initialize router advertisement parameters with default values for this intfc */
1452 ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm,
1456 ip6_main_t * im = &ip6_main;
1457 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
1458 ip_lookup_main_t * lm = &im->lookup_main;
1461 vnet_sw_interface_t * sw_if0;
1462 ethernet_interface_t * eth_if0 = 0;
1464 /* lookup radv container - ethernet interfaces only */
1465 sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
1466 if(sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
1467 eth_if0 = ethernet_get_interface (ðernet_main, sw_if0->hw_if_index);
1472 vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
1473 ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
1477 a = pool_elt_at_index (nm->if_radv_pool, ri);
1481 u32 i, * to_delete = 0;
1482 ip6_radv_prefix_t *p;
1483 ip6_mldp_group_t *m;
1485 /* remove adjacencies */
1486 ip_del_adjacency (lm, a->all_nodes_adj_index);
1487 ip_del_adjacency (lm, a->all_routers_adj_index);
1488 ip_del_adjacency (lm, a->all_mldv2_routers_adj_index);
1490 /* clean up prefix_pool */
1491 pool_foreach (p, a->adv_prefixes_pool, ({
1492 vec_add1 (to_delete, p - a->adv_prefixes_pool);
1495 for (i = 0; i < vec_len (to_delete); i++)
1497 p = pool_elt_at_index (a->adv_prefixes_pool, to_delete[i]);
1498 mhash_unset (&a->address_to_prefix_index, &p->prefix, 0);
1499 pool_put (a->adv_prefixes_pool, p);
1502 vec_free (to_delete);
1505 /* clean up mldp group pool */
1506 pool_foreach (m, a->mldp_group_pool, ({
1507 vec_add1 (to_delete, m - a->mldp_group_pool);
1510 for (i = 0; i < vec_len (to_delete); i++)
1512 m = pool_elt_at_index (a->mldp_group_pool, to_delete[i]);
1513 mhash_unset (&a->address_to_mldp_index, &m->mcast_address, 0);
1514 pool_put (a->mldp_group_pool, m);
1517 vec_free (to_delete);
1519 pool_put (nm->if_radv_pool, a);
1520 nm->if_radv_pool_index_by_sw_if_index[sw_if_index] = ~0;
1528 vnet_hw_interface_t * hw_if0;
1530 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index);
1532 pool_get (nm->if_radv_pool, a);
1534 ri = a - nm->if_radv_pool;
1535 nm->if_radv_pool_index_by_sw_if_index[sw_if_index] = ri;
1537 /* initialize default values (most of which are zero) */
1538 memset (a, 0, sizeof (a[0]));
1540 a->sw_if_index = sw_if_index;
1542 a->max_radv_interval = DEF_MAX_RADV_INTERVAL;
1543 a->min_radv_interval = DEF_MIN_RADV_INTERVAL;
1544 a->curr_hop_limit = DEF_CURR_HOP_LIMIT;
1545 a->adv_router_lifetime_in_sec = DEF_DEF_RTR_LIFETIME;
1547 a->adv_link_layer_address = 1; /* send ll address source address option */
1549 a->min_delay_between_radv = MIN_DELAY_BETWEEN_RAS;
1550 a->max_delay_between_radv = MAX_DELAY_BETWEEN_RAS;
1551 a->max_rtr_default_lifetime = MAX_DEF_RTR_LIFETIME;
1552 a->seed = random_default_seed();
1554 /* for generating random interface ids */
1555 a->randomizer = 0x1119194911191949;
1556 a->randomizer = random_u64 ((u32 *)&a->randomizer);
1558 a->initial_adverts_count = MAX_INITIAL_RTR_ADVERTISEMENTS ;
1559 a->initial_adverts_sent = a->initial_adverts_count-1;
1560 a->initial_adverts_interval = MAX_INITIAL_RTR_ADVERT_INTERVAL;
1562 /* deafult is to send */
1565 /* fill in radv_info for this interface that will be needed later */
1566 a->adv_link_mtu = hw_if0->max_l3_packet_bytes[VLIB_RX];
1568 memcpy (a->link_layer_address, eth_if0->address, 6);
1570 /* fill in default link-local address (this may be overridden) */
1571 ip6_link_local_address_from_ethernet_address (&a->link_local_address, eth_if0->address);
1572 a->link_local_prefix_len = 64;
1574 mhash_init (&a->address_to_prefix_index, sizeof (uword), sizeof (ip6_address_t));
1575 mhash_init (&a->address_to_mldp_index, sizeof (uword), sizeof (ip6_address_t));
1578 ip_adjacency_t *adj;
1579 u8 link_layer_address[6] =
1580 {0x33, 0x33, 0x00, 0x00, 0x00, IP6_MULTICAST_GROUP_ID_all_hosts};
1582 adj = ip_add_adjacency (lm, /* template */ 0, /* block size */ 1,
1583 &a->all_nodes_adj_index);
1585 adj->lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
1586 adj->if_address_index = ~0;
1588 vnet_rewrite_for_sw_interface
1590 VNET_L3_PACKET_TYPE_IP6,
1592 ip6_rewrite_node.index,
1594 &adj->rewrite_header,
1595 sizeof (adj->rewrite_data));
1599 ip_adjacency_t *adj;
1600 u8 link_layer_address[6] =
1601 {0x33, 0x33, 0x00, 0x00, 0x00, IP6_MULTICAST_GROUP_ID_all_routers};
1603 adj = ip_add_adjacency (lm, /* template */ 0, /* block size */ 1,
1604 &a->all_routers_adj_index);
1606 adj->lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
1607 adj->if_address_index = ~0;
1609 vnet_rewrite_for_sw_interface
1611 VNET_L3_PACKET_TYPE_IP6,
1613 ip6_rewrite_node.index,
1615 &adj->rewrite_header,
1616 sizeof (adj->rewrite_data));
1620 ip_adjacency_t *adj;
1621 u8 link_layer_address[6] =
1622 {0x33, 0x33, 0x00, 0x00, 0x00, IP6_MULTICAST_GROUP_ID_mldv2_routers};
1624 adj = ip_add_adjacency (lm, /* template */ 0, /* block size */ 1,
1625 &a->all_mldv2_routers_adj_index);
1627 adj->lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
1628 adj->if_address_index = ~0;
1630 vnet_rewrite_for_sw_interface
1632 VNET_L3_PACKET_TYPE_IP6,
1634 ip6_rewrite_node.index,
1636 &adj->rewrite_header,
1637 sizeof (adj->rewrite_data));
1640 /* add multicast groups we will always be reporting */
1642 ip6_mldp_group_t *mcast_group_info;
1644 ip6_set_reserved_multicast_address (&addr,
1645 IP6_MULTICAST_SCOPE_link_local,
1646 IP6_MULTICAST_GROUP_ID_all_hosts);
1648 /* lookup mldp info for this interface */
1650 uword * p = mhash_get (&a->address_to_mldp_index, &addr);
1651 mcast_group_info = p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0;
1654 if(!mcast_group_info)
1658 pool_get (a->mldp_group_pool, mcast_group_info);
1660 mi = mcast_group_info - a->mldp_group_pool;
1661 mhash_set (&a->address_to_mldp_index, &addr, mi, /* old_value */ 0);
1663 mcast_group_info->type = 4;
1664 mcast_group_info->mcast_source_address_pool = 0;
1665 mcast_group_info->num_sources = 0;
1666 memcpy(&mcast_group_info->mcast_address, &addr, sizeof(ip6_address_t));
1669 ip6_set_reserved_multicast_address (&addr,
1670 IP6_MULTICAST_SCOPE_link_local,
1671 IP6_MULTICAST_GROUP_ID_all_routers);
1673 p = mhash_get (&a->address_to_mldp_index, &addr);
1674 mcast_group_info = p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0;
1676 if(!mcast_group_info)
1680 pool_get (a->mldp_group_pool, mcast_group_info);
1682 mi = mcast_group_info - a->mldp_group_pool;
1683 mhash_set (&a->address_to_mldp_index, &addr, mi, /* old_value */ 0);
1685 mcast_group_info->type = 4;
1686 mcast_group_info->mcast_source_address_pool = 0;
1687 mcast_group_info->num_sources = 0;
1688 memcpy(&mcast_group_info->mcast_address, &addr, sizeof(ip6_address_t));
1691 ip6_set_reserved_multicast_address (&addr,
1692 IP6_MULTICAST_SCOPE_link_local,
1693 IP6_MULTICAST_GROUP_ID_mldv2_routers);
1695 p = mhash_get (&a->address_to_mldp_index, &addr);
1696 mcast_group_info = p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0;
1698 if(!mcast_group_info)
1702 pool_get (a->mldp_group_pool, mcast_group_info);
1704 mi = mcast_group_info - a->mldp_group_pool;
1705 mhash_set (&a->address_to_mldp_index, &addr, mi, /* old_value */ 0);
1707 mcast_group_info->type = 4;
1708 mcast_group_info->mcast_source_address_pool = 0;
1709 mcast_group_info->num_sources = 0;
1710 memcpy(&mcast_group_info->mcast_address, &addr, sizeof(ip6_address_t));
1717 /* send an mldpv2 report */
1719 ip6_neighbor_send_mldpv2_report(u32 sw_if_index)
1721 vnet_main_t * vnm = vnet_get_main();
1722 vlib_main_t * vm = vnm->vlib_main;
1723 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
1724 vnet_sw_interface_t * sw_if0;
1725 ethernet_interface_t * eth_if0;
1729 ip6_radv_t *radv_info;
1739 icmp6_multicast_listener_report_header_t *rh0;
1740 icmp6_multicast_listener_report_packet_t *rp0;
1742 sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
1743 ASSERT (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
1744 eth_if0 = ethernet_get_interface (ðernet_main, sw_if0->hw_if_index);
1746 if (!eth_if0 || !vnet_sw_interface_is_admin_up (vnm, sw_if_index))
1749 /* look up the radv_t information for this interface */
1750 vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
1752 ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
1757 /* send report now - build a mldpv2 report packet */
1758 n_allocated = vlib_buffer_alloc_from_free_list(vm,
1761 VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
1762 if (PREDICT_FALSE(n_allocated == 0))
1764 clib_warning ("buffer allocation failure");
1768 b0 = vlib_get_buffer (vm, bo0);
1770 /* adjust the sizeof the buffer to just include the ipv6 header */
1771 b0->current_length = sizeof(icmp6_multicast_listener_report_packet_t);
1773 payload_length = sizeof(icmp6_multicast_listener_report_header_t);
1775 b0->error = ICMP6_ERROR_NONE;
1777 rp0 = vlib_buffer_get_current (b0);
1778 ip0 = (ip6_header_t *)&rp0-> ip;
1779 rh0 = (icmp6_multicast_listener_report_header_t *)&rp0-> report_hdr;
1781 memset (rp0 , 0x0, sizeof (icmp6_multicast_listener_report_packet_t));
1783 ip0->ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (0x6 << 28);
1785 ip0->protocol = IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS;
1786 /* for DEBUG - vnet driver won't seem to emit router alerts */
1787 /* ip0->protocol = IP_PROTOCOL_ICMP6; */
1790 rh0->icmp.type = ICMP6_multicast_listener_report_v2;
1792 /* source address MUST be the link-local address */
1793 radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
1794 ip0->src_address = radv_info->link_local_address;
1796 /* destination is all mldpv2 routers */
1797 ip6_set_reserved_multicast_address(&ip0->dst_address,
1798 IP6_MULTICAST_SCOPE_link_local,
1799 IP6_MULTICAST_GROUP_ID_mldv2_routers);
1801 /* add reports here */
1802 ip6_mldp_group_t *m;
1803 int num_addr_records = 0;
1804 icmp6_multicast_address_record_t rr;
1806 /* fill in the hop-by-hop extension header (router alert) info */
1807 rh0->ext_hdr.next_hdr = IP_PROTOCOL_ICMP6;
1808 rh0->ext_hdr.n_data_u64s = 0;
1810 rh0->alert.type = IP6_MLDP_ALERT_TYPE;
1812 rh0->alert.value = 0;
1817 rh0->icmp.checksum = 0;
1819 pool_foreach (m, radv_info->mldp_group_pool, ({
1822 rr.aux_data_len_u32s = 0;
1823 rr.num_sources = clib_host_to_net_u16 (m->num_sources);
1824 memcpy(&rr.mcast_addr, &m->mcast_address, sizeof(ip6_address_t));
1828 vlib_buffer_add_data (vm,
1829 b0->free_list_index,
1831 (void *)&rr, sizeof(icmp6_multicast_address_record_t));
1833 payload_length += sizeof( icmp6_multicast_address_record_t);
1837 rh0->num_addr_records = clib_host_to_net_u16(num_addr_records);
1839 /* update lengths */
1840 ip0->payload_length = clib_host_to_net_u16 (payload_length);
1842 rh0->icmp.checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0,
1844 ASSERT(bogus_length == 0);
1847 * OK to override w/ no regard for actual FIB, because
1848 * ip6-rewrite-local only looks at the adjacency.
1850 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
1851 vnet_main.local_interface_sw_if_index;
1853 vnet_buffer (b0)->ip.adj_index[VLIB_RX] =
1854 radv_info->all_mldv2_routers_adj_index;
1856 vlib_node_t * node = vlib_get_node_by_name (vm, (u8 *) "ip6-rewrite-local");
1858 f = vlib_get_frame_to_node (vm, node->index);
1859 to_next = vlib_frame_vector_args (f);
1863 vlib_put_frame_to_node (vm, node->index, f);
1867 VLIB_REGISTER_NODE (ip6_icmp_router_solicitation_node,static) = {
1868 .function = icmp6_router_solicitation,
1869 .name = "icmp6-router-solicitation",
1871 .vector_size = sizeof (u32),
1873 .format_trace = format_icmp6_input_trace,
1875 .n_next_nodes = ICMP6_ROUTER_SOLICITATION_N_NEXT,
1877 [ICMP6_ROUTER_SOLICITATION_NEXT_DROP] = "error-drop",
1878 [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW] = "ip6-rewrite-local",
1879 [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX] = "interface-output",
1883 /* send a RA or update the timer info etc.. */
1885 ip6_neighbor_process_timer_event (vlib_main_t * vm,
1886 vlib_node_runtime_t * node,
1887 vlib_frame_t * frame)
1889 vnet_main_t * vnm = vnet_get_main();
1890 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
1891 ip6_radv_t *radv_info;
1892 vlib_frame_t * f = 0;
1893 u32 n_this_frame = 0;
1897 icmp6_router_solicitation_header_t * h0;
1899 f64 now = vlib_time_now (vm);
1901 /* Interface ip6 radv info list */
1902 pool_foreach (radv_info, nm->if_radv_pool, ({
1904 if( !vnet_sw_interface_is_admin_up (vnm, radv_info->sw_if_index))
1906 radv_info->initial_adverts_sent = radv_info->initial_adverts_count-1;
1907 radv_info->next_multicast_time = now;
1908 radv_info->last_multicast_time = now;
1909 radv_info->last_radv_time = 0;
1910 radv_info->all_routers_mcast = 0;
1914 /* Make sure that we've joined the all-routers multicast group */
1915 if(!radv_info->all_routers_mcast)
1917 /* send MDLP_REPORT_EVENT message */
1918 ip6_neighbor_send_mldpv2_report(radv_info->sw_if_index);
1919 radv_info->all_routers_mcast = 1;
1922 /* is it time to send a multicast RA on this interface? */
1923 if(radv_info->send_radv && (now >= radv_info->next_multicast_time))
1928 f64 rfn = (radv_info->max_radv_interval - radv_info->min_radv_interval) *
1929 random_f64 (&radv_info->seed) + radv_info->min_radv_interval;
1931 /* multicast send - compute next multicast send time */
1932 if( radv_info->initial_adverts_sent > 0)
1934 radv_info->initial_adverts_sent--;
1935 if(rfn > radv_info-> initial_adverts_interval)
1936 rfn = radv_info-> initial_adverts_interval;
1938 /* check to see if we are ceasing to send */
1939 if( radv_info->initial_adverts_sent == 0)
1940 if(radv_info->cease_radv)
1941 radv_info->send_radv = 0;
1944 radv_info->next_multicast_time = rfn + now;
1945 radv_info->last_multicast_time = now;
1947 /* send advert now - build a "solicted" router advert with unspecified source address */
1948 n_allocated = vlib_buffer_alloc_from_free_list(vm,
1951 VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
1953 if (PREDICT_FALSE(n_allocated == 0))
1955 clib_warning ("buffer allocation failure");
1958 b0 = vlib_get_buffer (vm, bo0);
1959 b0->current_length = sizeof( icmp6_router_solicitation_header_t);
1960 b0->error = ICMP6_ERROR_NONE;
1961 vnet_buffer (b0)->sw_if_index[VLIB_RX] = radv_info->sw_if_index;
1963 h0 = vlib_buffer_get_current (b0);
1965 memset (h0, 0, sizeof (icmp6_router_solicitation_header_t));
1967 h0->ip.ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (0x6 << 28);
1968 h0->ip.payload_length = clib_host_to_net_u16 (sizeof (icmp6_router_solicitation_header_t)
1969 - STRUCT_OFFSET_OF (icmp6_router_solicitation_header_t, neighbor));
1970 h0->ip.protocol = IP_PROTOCOL_ICMP6;
1971 h0->ip.hop_limit = 255;
1973 /* set src/dst address as "unspecified" this marks this packet as internally generated rather than recieved */
1974 h0->ip.src_address.as_u64[0] = 0;
1975 h0->ip.src_address.as_u64[1] = 0;
1977 h0->ip.dst_address.as_u64[0] = 0;
1978 h0->ip.dst_address.as_u64[1] = 0;
1980 h0->neighbor.icmp.type = ICMP6_router_solicitation;
1982 if (PREDICT_FALSE(f == 0))
1984 f = vlib_get_frame_to_node (vm, ip6_icmp_router_solicitation_node.index);
1985 to_next = vlib_frame_vector_args (f);
1986 n_left_to_next = VLIB_FRAME_SIZE;
1995 if (PREDICT_FALSE(n_left_to_next == 0))
1997 f->n_vectors = n_this_frame;
1998 vlib_put_frame_to_node (vm, ip6_icmp_router_solicitation_node.index, f);
2006 ASSERT(n_this_frame);
2007 f->n_vectors = n_this_frame;
2008 vlib_put_frame_to_node (vm, ip6_icmp_router_solicitation_node.index, f);
2014 ip6_icmp_neighbor_discovery_event_process (vlib_main_t * vm,
2015 vlib_node_runtime_t * node,
2016 vlib_frame_t * frame)
2019 ip6_icmp_neighbor_discovery_event_data_t * event_data;
2021 /* init code here */
2025 vlib_process_wait_for_event_or_clock (vm, 1. /* seconds */);
2027 event_data = vlib_process_get_event_data (vm, &event_type);
2031 /* No events found: timer expired. */
2032 /* process interface list and send RAs as appropriate, update timer info */
2033 ip6_neighbor_process_timer_event (vm, node, frame);
2037 switch (event_type) {
2039 case ICMP6_ND_EVENT_INIT:
2050 _vec_len (event_data) = 0;
2053 return frame->n_vectors;
2056 VLIB_REGISTER_NODE (ip6_icmp_router_advertisement_node,static) = {
2057 .function = icmp6_router_advertisement,
2058 .name = "icmp6-router-advertisement",
2060 .vector_size = sizeof (u32),
2062 .format_trace = format_icmp6_input_trace,
2070 vlib_node_registration_t ip6_icmp_neighbor_discovery_event_node = {
2072 .function = ip6_icmp_neighbor_discovery_event_process,
2073 .name = "ip6-icmp-neighbor-discovery-event-process",
2074 .type = VLIB_NODE_TYPE_PROCESS,
2078 icmp6_neighbor_solicitation (vlib_main_t * vm,
2079 vlib_node_runtime_t * node,
2080 vlib_frame_t * frame)
2081 { return icmp6_neighbor_solicitation_or_advertisement (vm, node, frame, /* is_solicitation */ 1); }
2084 icmp6_neighbor_advertisement (vlib_main_t * vm,
2085 vlib_node_runtime_t * node,
2086 vlib_frame_t * frame)
2087 { return icmp6_neighbor_solicitation_or_advertisement (vm, node, frame, /* is_solicitation */ 0); }
2089 VLIB_REGISTER_NODE (ip6_icmp_neighbor_solicitation_node,static) = {
2090 .function = icmp6_neighbor_solicitation,
2091 .name = "icmp6-neighbor-solicitation",
2093 .vector_size = sizeof (u32),
2095 .format_trace = format_icmp6_input_trace,
2097 .n_next_nodes = ICMP6_NEIGHBOR_SOLICITATION_N_NEXT,
2099 [ICMP6_NEIGHBOR_SOLICITATION_NEXT_DROP] = "error-drop",
2100 [ICMP6_NEIGHBOR_SOLICITATION_NEXT_REPLY] = "interface-output",
2104 VLIB_REGISTER_NODE (ip6_icmp_neighbor_advertisement_node,static) = {
2105 .function = icmp6_neighbor_advertisement,
2106 .name = "icmp6-neighbor-advertisement",
2108 .vector_size = sizeof (u32),
2110 .format_trace = format_icmp6_input_trace,
2118 /* API support functions */
2120 ip6_neighbor_ra_config(vlib_main_t * vm, u32 sw_if_index,
2121 u8 surpress, u8 managed, u8 other,
2122 u8 ll_option, u8 send_unicast, u8 cease,
2123 u8 use_lifetime, u32 lifetime,
2124 u32 initial_count, u32 initial_interval,
2125 u32 max_interval, u32 min_interval,
2128 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2132 /* look up the radv_t information for this interface */
2133 vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2134 ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2135 error = (ri != ~0) ? 0 : VNET_API_ERROR_INVALID_SW_IF_INDEX;
2140 ip6_radv_t * radv_info;
2141 radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
2143 if((max_interval != 0) && (min_interval ==0))
2144 min_interval = .75 * max_interval;
2146 max_interval = (max_interval != 0) ? ( (is_no) ? DEF_MAX_RADV_INTERVAL : max_interval) : radv_info->max_radv_interval;
2147 min_interval = (min_interval != 0) ? ( (is_no) ? DEF_MIN_RADV_INTERVAL : min_interval) : radv_info->min_radv_interval;
2148 lifetime = (use_lifetime != 0) ? ( (is_no) ? DEF_DEF_RTR_LIFETIME : lifetime) : radv_info->adv_router_lifetime_in_sec;
2152 if(lifetime > MAX_DEF_RTR_LIFETIME)
2153 lifetime = MAX_DEF_RTR_LIFETIME;
2155 if(lifetime <= max_interval)
2156 return VNET_API_ERROR_INVALID_VALUE;
2159 if(min_interval != 0)
2161 if((min_interval > .75 * max_interval) ||
2163 return VNET_API_ERROR_INVALID_VALUE;
2166 if((initial_count > MAX_INITIAL_RTR_ADVERTISEMENTS) ||
2167 (initial_interval > MAX_INITIAL_RTR_ADVERT_INTERVAL))
2168 return VNET_API_ERROR_INVALID_VALUE;
2171 if "flag" is set and is_no is true then restore default value else set value corresponding to "flag"
2172 if "flag" is clear don't change corresponding value
2174 radv_info->send_radv = (surpress != 0) ? ( (is_no != 0) ? 1 : 0 ) : radv_info->send_radv;
2175 radv_info->adv_managed_flag = ( managed != 0) ? ( (is_no) ? 0 : 1) : radv_info->adv_managed_flag;
2176 radv_info->adv_other_flag = (other != 0) ? ( (is_no) ? 0: 1) : radv_info->adv_other_flag;
2177 radv_info->adv_link_layer_address = ( ll_option != 0) ? ( (is_no) ? 1 : 0) : radv_info->adv_link_layer_address;
2178 radv_info->send_unicast = (send_unicast != 0) ? ( (is_no) ? 0 : 1) : radv_info->send_unicast;
2179 radv_info->cease_radv = ( cease != 0) ? ( (is_no) ? 0 : 1) : radv_info->cease_radv;
2181 radv_info->min_radv_interval = min_interval;
2182 radv_info->max_radv_interval = max_interval;
2183 radv_info->adv_router_lifetime_in_sec = lifetime;
2185 radv_info->initial_adverts_count =
2186 (initial_count != 0) ? ( (is_no) ? MAX_INITIAL_RTR_ADVERTISEMENTS : initial_count) : radv_info->initial_adverts_count ;
2187 radv_info->initial_adverts_interval =
2188 (initial_interval != 0) ? ( (is_no) ? MAX_INITIAL_RTR_ADVERT_INTERVAL : initial_interval) : radv_info->initial_adverts_interval;
2191 if((cease != 0) && (is_no))
2192 radv_info-> send_radv = 1;
2194 radv_info->initial_adverts_sent = radv_info->initial_adverts_count -1;
2195 radv_info->next_multicast_time = vlib_time_now (vm);
2196 radv_info->last_multicast_time = vlib_time_now (vm);
2197 radv_info->last_radv_time = 0;
2203 ip6_neighbor_ra_prefix(vlib_main_t * vm, u32 sw_if_index,
2204 ip6_address_t *prefix_addr, u8 prefix_len,
2205 u8 use_default, u32 val_lifetime, u32 pref_lifetime,
2206 u8 no_advertise, u8 off_link, u8 no_autoconfig, u8 no_onlink,
2209 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2214 /* look up the radv_t information for this interface */
2215 vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2217 ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2219 error = (ri != ~0) ? 0 : VNET_API_ERROR_INVALID_SW_IF_INDEX;
2223 f64 now = vlib_time_now (vm);
2224 ip6_radv_t * radv_info;
2225 radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
2227 /* prefix info add, delete or update */
2228 ip6_radv_prefix_t * prefix;
2230 /* lookup prefix info for this address on this interface */
2231 uword * p = mhash_get (&radv_info->address_to_prefix_index, prefix_addr);
2233 prefix = p ? pool_elt_at_index (radv_info->adv_prefixes_pool, p[0]) : 0;
2239 return VNET_API_ERROR_INVALID_VALUE; /* invalid prefix */
2241 if(prefix->prefix_len != prefix_len)
2242 return VNET_API_ERROR_INVALID_VALUE_2;
2244 /* FIXME - Should the DP do this or the CP ?*/
2245 /* do specific delete processing here before returning */
2246 /* try to remove from routing table */
2248 mhash_unset (&radv_info->address_to_prefix_index, prefix_addr,/* old_value */ 0);
2249 pool_put (radv_info->adv_prefixes_pool, prefix);
2251 radv_info->initial_adverts_sent = radv_info->initial_adverts_count -1;
2252 radv_info->next_multicast_time = vlib_time_now (vm);
2253 radv_info->last_multicast_time = vlib_time_now (vm);
2254 radv_info->last_radv_time = 0;
2258 /* adding or changing */
2263 pool_get (radv_info->adv_prefixes_pool, prefix);
2264 pi = prefix - radv_info->adv_prefixes_pool;
2265 mhash_set (&radv_info->address_to_prefix_index, prefix_addr, pi, /* old_value */ 0);
2267 memset(prefix, 0x0, sizeof(ip6_radv_prefix_t));
2269 prefix->prefix_len = prefix_len;
2270 memcpy(&prefix->prefix, prefix_addr, sizeof(ip6_address_t));
2272 /* initialize default values */
2273 prefix->adv_on_link_flag = 1; /* L bit set */
2274 prefix->adv_autonomous_flag = 1; /* A bit set */
2275 prefix->adv_valid_lifetime_in_secs = DEF_ADV_VALID_LIFETIME;
2276 prefix->adv_pref_lifetime_in_secs = DEF_ADV_PREF_LIFETIME;
2277 prefix->enabled = 1;
2278 prefix->decrement_lifetime_flag = 1;
2279 prefix->deprecated_prefix_flag = 1;
2283 /* FIXME - Should the DP do this or the CP ?*/
2284 /* insert prefix into routing table as a connected prefix */
2293 if(prefix->prefix_len != prefix_len)
2294 return VNET_API_ERROR_INVALID_VALUE_2;
2298 /* FIXME - Should the DP do this or the CP ?*/
2299 /* remove from routing table if already there */
2303 if((val_lifetime == ~0) || (pref_lifetime == ~0))
2305 prefix->adv_valid_lifetime_in_secs = ~0;
2306 prefix->adv_pref_lifetime_in_secs = ~0;
2307 prefix->decrement_lifetime_flag = 0;
2311 prefix->adv_valid_lifetime_in_secs = val_lifetime;;
2312 prefix->adv_pref_lifetime_in_secs = pref_lifetime;
2315 /* copy remaining */
2316 prefix->enabled = !(no_advertise != 0);
2317 prefix->adv_on_link_flag = !((off_link != 0) || (no_onlink != 0));
2318 prefix->adv_autonomous_flag = !(no_autoconfig != 0);
2322 /* fill in the expiration times */
2323 prefix->valid_lifetime_expires = now + prefix->adv_valid_lifetime_in_secs;
2324 prefix->pref_lifetime_expires = now + prefix->adv_pref_lifetime_in_secs;
2326 radv_info->initial_adverts_sent = radv_info->initial_adverts_count -1;
2327 radv_info->next_multicast_time = vlib_time_now (vm);
2328 radv_info->last_multicast_time = vlib_time_now (vm);
2329 radv_info->last_radv_time = 0;
2335 ip6_neighbor_cmd(vlib_main_t * vm, unformat_input_t * main_input, vlib_cli_command_t * cmd)
2337 vnet_main_t * vnm = vnet_get_main();
2338 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2339 clib_error_t * error = 0;
2341 u8 surpress = 0, managed = 0, other = 0;
2342 u8 surpress_ll_option = 0, send_unicast = 0, cease= 0;
2343 u8 use_lifetime = 0;
2344 u32 sw_if_index, ra_lifetime = 0, ra_initial_count = 0, ra_initial_interval = 0;
2345 u32 ra_max_interval = 0 , ra_min_interval = 0;
2347 unformat_input_t _line_input, * line_input = &_line_input;
2348 vnet_sw_interface_t * sw_if0;
2350 int add_radv_info = 1;
2351 __attribute__((unused)) ip6_radv_t * radv_info = 0;
2352 ip6_address_t ip6_addr;
2356 /* Get a line of input. */
2357 if (! unformat_user (main_input, unformat_line_input, line_input))
2360 /* get basic radv info for this interface */
2361 if(unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2364 if (unformat_user (line_input,
2365 unformat_vnet_sw_interface, vnm, &sw_if_index))
2368 ethernet_interface_t * eth_if0 = 0;
2370 sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
2371 if(sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
2372 eth_if0 = ethernet_get_interface (ðernet_main, sw_if0->hw_if_index);
2376 error = clib_error_return (0, "Interface must be of ethernet type");
2380 /* look up the radv_t information for this interface */
2381 vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2383 ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2387 radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
2391 error = clib_error_return (0, "unknown interface %U'",
2392 format_unformat_error, line_input);
2398 error = clib_error_return (0, "invalid interface name %U'",
2399 format_unformat_error, line_input);
2404 /* get the rest of the command */
2405 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2407 if (unformat (line_input, "no"))
2409 else if(unformat (line_input, "prefix %U/%d",
2410 unformat_ip6_address, &ip6_addr,
2416 else if (unformat (line_input, "ra-managed-config-flag"))
2421 else if (unformat (line_input, "ra-other-config-flag"))
2426 else if (unformat (line_input, "ra-surpress"))
2431 else if (unformat (line_input, "ra-surpress-link-layer"))
2433 surpress_ll_option = 1;
2436 else if (unformat (line_input, "ra-send-unicast"))
2441 else if (unformat (line_input, "ra-lifetime"))
2443 if (!unformat (line_input, "%d", &ra_lifetime))
2444 return(error = unformat_parse_error (line_input));
2448 else if (unformat (line_input, "ra-initial"))
2450 if (!unformat (line_input, "%d %d", &ra_initial_count, &ra_initial_interval))
2451 return(error = unformat_parse_error (line_input));
2454 else if (unformat (line_input, "ra-interval"))
2456 if (!unformat (line_input, "%d", &ra_max_interval))
2457 return(error = unformat_parse_error (line_input));
2459 if (!unformat (line_input, "%d", &ra_min_interval))
2460 ra_min_interval = 0;
2463 else if(unformat (line_input, "ra-cease"))
2469 return(unformat_parse_error (line_input));
2474 ip6_neighbor_ra_config(vm, sw_if_index,
2475 surpress, managed, other,
2476 surpress_ll_option, send_unicast, cease,
2477 use_lifetime, ra_lifetime,
2478 ra_initial_count, ra_initial_interval,
2479 ra_max_interval, ra_min_interval,
2484 u32 valid_lifetime_in_secs = 0;
2485 u32 pref_lifetime_in_secs = 0;
2486 u8 use_prefix_default_values = 0;
2487 u8 no_advertise = 0;
2489 u8 no_autoconfig = 0;
2492 /* get the rest of the command */
2493 while(unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2495 if(unformat (line_input, "default"))
2497 use_prefix_default_values = 1;
2500 else if(unformat (line_input, "infinite"))
2502 valid_lifetime_in_secs = ~0;
2503 pref_lifetime_in_secs = ~0;
2506 else if(unformat (line_input, "%d %d", &valid_lifetime_in_secs,
2507 &pref_lifetime_in_secs))
2514 /* get the rest of the command */
2515 while (!use_prefix_default_values &&
2516 unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2518 if(unformat (line_input, "no-advertise"))
2520 else if(unformat (line_input, "off-link"))
2522 else if(unformat (line_input, "no-autoconfig"))
2524 else if(unformat (line_input, "no-onlink"))
2527 return(unformat_parse_error (line_input));
2530 ip6_neighbor_ra_prefix(vm, sw_if_index,
2531 &ip6_addr, addr_len,
2532 use_prefix_default_values,
2533 valid_lifetime_in_secs,
2534 pref_lifetime_in_secs,
2542 unformat_free (line_input);
2548 static clib_error_t *
2549 show_ip6_interface_cmd (vlib_main_t * vm,
2550 unformat_input_t * input,
2551 vlib_cli_command_t * cmd)
2553 vnet_main_t * vnm = vnet_get_main();
2554 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2555 clib_error_t * error = 0;
2560 if (unformat_user (input,
2561 unformat_vnet_sw_interface, vnm, &sw_if_index))
2565 /* look up the radv_t information for this interface */
2566 vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2568 ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2572 ip_lookup_main_t * lm = &ip6_main.lookup_main;
2573 ip6_radv_t * radv_info;
2574 radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
2576 vlib_cli_output (vm, "%U is admin %s\n", format_vnet_sw_interface_name, vnm,
2577 vnet_get_sw_interface (vnm, sw_if_index),
2578 (vnet_sw_interface_is_admin_up (vnm, sw_if_index) ? "up" : "down"));
2581 u32 *global_scope = 0,i;
2582 ip_interface_address_t * a;
2584 vec_validate_init_empty (lm->if_address_pool_index_by_sw_if_index, sw_if_index, ~0);
2585 ai = lm->if_address_pool_index_by_sw_if_index[sw_if_index];
2587 while (ai != (u32)~0)
2589 a = pool_elt_at_index(lm->if_address_pool, ai);
2590 ip6_address_t * address = ip_interface_address_get_address (lm, a);
2592 if( ip6_address_is_link_local_unicast (address))
2593 vlib_cli_output (vm, "\tIPv6 is enabled, link-local address is %U\n", format_ip6_address,
2596 if((address->as_u8[0] & 0xe0) == 0x20)
2597 vec_add1 (global_scope, ai);
2599 ai = a->next_this_sw_interface;
2602 vlib_cli_output (vm, "\tGlobal unicast address(es):\n");
2603 for (i = 0; i < vec_len (global_scope); i++)
2605 a = pool_elt_at_index(lm->if_address_pool, global_scope[i]);
2606 ip6_address_t * address = ip_interface_address_get_address (lm, a);
2607 ip6_address_t mask, subnet;
2610 ip6_address_mask_from_width(&mask, a->address_length);
2611 ip6_address_mask(&subnet, &mask);
2613 vlib_cli_output (vm, "\t\t%U, subnet is %U/%d",
2614 format_ip6_address, address,
2615 format_ip6_address,&subnet,
2618 vec_free (global_scope);
2619 vlib_cli_output (vm, "\tJoined group address(es):\n");
2620 ip6_mldp_group_t *m;
2621 pool_foreach (m, radv_info->mldp_group_pool, ({
2622 vlib_cli_output (vm, "\t\t%U\n", format_ip6_address, &m->mcast_address);
2625 vlib_cli_output (vm, "\tAdvertised Prefixes:\n");
2626 ip6_radv_prefix_t * p;
2627 pool_foreach (p, radv_info->adv_prefixes_pool, ({
2628 vlib_cli_output (vm, "\t\tprefix %U, length %d\n",
2629 format_ip6_address, &p->prefix, p->prefix_len);
2632 vlib_cli_output (vm, "\tMTU is %d\n", radv_info->adv_link_mtu);
2633 vlib_cli_output (vm, "\tICMP error messages are unlimited\n");
2634 vlib_cli_output (vm, "\tICMP redirects are disabled\n");
2635 vlib_cli_output (vm, "\tICMP unreachables are not sent\n");
2636 vlib_cli_output (vm, "\tND DAD is disabled\n");
2637 //vlib_cli_output (vm, "\tND reachable time is %d milliseconds\n",);
2638 vlib_cli_output (vm, "\tND advertised reachable time is %d\n",
2639 radv_info->adv_neighbor_reachable_time_in_msec);
2640 vlib_cli_output (vm, "\tND advertised retransmit interval is %d (msec)\n",
2641 radv_info->adv_time_in_msec_between_retransmitted_neighbor_solicitations);
2643 u32 ra_interval = radv_info->max_radv_interval;
2644 u32 ra_interval_min = radv_info->min_radv_interval;
2645 vlib_cli_output (vm, "\tND router advertisements are sent every %d seconds (min interval is %d)\n",
2646 ra_interval, ra_interval_min);
2647 vlib_cli_output (vm, "\tND router advertisements live for %d seconds\n",
2648 radv_info->adv_router_lifetime_in_sec);
2649 vlib_cli_output (vm, "\tHosts %s stateless autoconfig for addresses\n",
2650 (radv_info->adv_managed_flag) ? "use" :" don't use");
2651 vlib_cli_output (vm, "\tND router advertisements sent %d\n", radv_info->n_advertisements_sent);
2652 vlib_cli_output (vm, "\tND router solicitations received %d\n", radv_info->n_solicitations_rcvd);
2653 vlib_cli_output (vm, "\tND router solicitations dropped %d\n", radv_info->n_solicitations_dropped);
2657 error = clib_error_return (0, "Ipv6 not enabled on interface",
2658 format_unformat_error, input);
2665 VLIB_CLI_COMMAND (show_ip6_interface_command, static) = {
2666 .path = "show ip6 interface",
2667 .function = show_ip6_interface_cmd,
2668 .short_help = "Show ip6 interface <iface name>",
2672 disable_ip6_interface(vlib_main_t * vm,
2675 clib_error_t * error = 0;
2676 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2679 /* look up the radv_t information for this interface */
2680 vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2681 ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2683 /* if not created - do nothing */
2686 vnet_main_t * vnm = vnet_get_main();
2687 ip6_radv_t * radv_info;
2689 radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
2691 /* check radv_info ref count for other ip6 addresses on this interface */
2692 if(radv_info->ref_count == 0 )
2694 /* essentially "disables" ipv6 on this interface */
2695 error = ip6_add_del_interface_address (vm, sw_if_index,
2696 &radv_info->link_local_address,
2697 radv_info->link_local_prefix_len,
2700 ip6_neighbor_sw_interface_add_del (vnm, sw_if_index, 0/* is_add */);
2707 ip6_interface_enabled(vlib_main_t * vm,
2710 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2713 /* look up the radv_t information for this interface */
2714 vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2716 ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2722 enable_ip6_interface(vlib_main_t * vm,
2725 clib_error_t * error = 0;
2726 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2730 /* look up the radv_t information for this interface */
2731 vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
2733 ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2735 /* if not created yet */
2738 vnet_main_t * vnm = vnet_get_main();
2739 vnet_sw_interface_t * sw_if0;
2741 sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
2742 if(sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
2744 ethernet_interface_t * eth_if0;
2746 eth_if0 = ethernet_get_interface (ðernet_main, sw_if0->hw_if_index);
2749 /* create radv_info. for this interface. This holds all the info needed for router adverts */
2750 ri = ip6_neighbor_sw_interface_add_del (vnm, sw_if_index, is_add);
2754 ip6_radv_t * radv_info;
2755 ip6_address_t link_local_address;
2757 radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
2759 ip6_link_local_address_from_ethernet_mac_address (&link_local_address,
2762 sw_if0 = vnet_get_sw_interface (vnm, sw_if_index);
2763 if(sw_if0->type == VNET_SW_INTERFACE_TYPE_SUB)
2765 /* make up an interface id */
2769 link_local_address.as_u64[0] = radv_info->randomizer;
2772 md5_add (&m, &link_local_address, 16);
2773 md5_finish (&m, digest);
2775 memcpy(&link_local_address, digest, 16);
2777 radv_info->randomizer = link_local_address.as_u64[0];
2779 link_local_address.as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL);
2781 link_local_address.as_u8[8] &= 0xfd;
2784 /* essentially "enables" ipv6 on this interface */
2785 error = ip6_add_del_interface_address (vm, sw_if_index,
2786 &link_local_address, 64 /* address width */,
2790 ip6_neighbor_sw_interface_add_del (vnm, sw_if_index, !is_add);
2793 radv_info->link_local_address = link_local_address;
2794 radv_info->link_local_prefix_len = 64;
2803 static clib_error_t *
2804 enable_ip6_interface_cmd (vlib_main_t * vm,
2805 unformat_input_t * input,
2806 vlib_cli_command_t * cmd)
2808 vnet_main_t * vnm = vnet_get_main();
2809 clib_error_t * error = 0;
2814 if (unformat_user (input,
2815 unformat_vnet_sw_interface, vnm, &sw_if_index))
2817 enable_ip6_interface(vm, sw_if_index);
2821 error = clib_error_return (0, "unknown interface\n'",
2822 format_unformat_error, input);
2828 VLIB_CLI_COMMAND (enable_ip6_interface_command, static) = {
2829 .path = "enable ip6 interface",
2830 .function = enable_ip6_interface_cmd,
2831 .short_help = "enable ip6 interface <iface name>",
2834 static clib_error_t *
2835 disable_ip6_interface_cmd (vlib_main_t * vm,
2836 unformat_input_t * input,
2837 vlib_cli_command_t * cmd)
2839 vnet_main_t * vnm = vnet_get_main();
2840 clib_error_t * error = 0;
2845 if (unformat_user (input,
2846 unformat_vnet_sw_interface, vnm, &sw_if_index))
2848 error = disable_ip6_interface(vm, sw_if_index);
2852 error = clib_error_return (0, "unknown interface\n'",
2853 format_unformat_error, input);
2859 VLIB_CLI_COMMAND (disable_ip6_interface_command, static) = {
2860 .path = "disable ip6 interface",
2861 .function = disable_ip6_interface_cmd,
2862 .short_help = "disable ip6 interface <iface name>",
2865 VLIB_CLI_COMMAND (ip6_nd_command, static) = {
2867 .short_help = "Set ip6 neighbor discovery parameters",
2868 .function = ip6_neighbor_cmd,
2872 set_ip6_link_local_address(vlib_main_t * vm,
2874 ip6_address_t *address,
2877 clib_error_t * error = 0;
2878 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2880 ip6_radv_t * radv_info;
2881 vnet_main_t * vnm = vnet_get_main();
2883 if( !ip6_address_is_link_local_unicast (address))
2885 vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_LINK_LOCAL;
2886 return(error = clib_error_return (0, "address not link-local",
2887 format_unformat_error));
2890 /* call enable ipv6 */
2891 enable_ip6_interface(vm, sw_if_index);
2893 ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2897 radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
2899 /* save if link local address (overwrite default) */
2901 /* delete the old one */
2902 error = ip6_add_del_interface_address (vm, sw_if_index,
2903 &radv_info->link_local_address,
2904 radv_info->link_local_prefix_len /* address width */,
2909 /* add the new one */
2910 error = ip6_add_del_interface_address (vm, sw_if_index,
2912 address_length /* address width */,
2917 radv_info->link_local_address = *address;
2918 radv_info->link_local_prefix_len = address_length;
2924 vnm->api_errno = VNET_API_ERROR_IP6_NOT_ENABLED;
2925 error = clib_error_return (0, "ip6 not enabled for interface",
2926 format_unformat_error);
2932 set_ip6_link_local_address_cmd (vlib_main_t * vm,
2933 unformat_input_t * input,
2934 vlib_cli_command_t * cmd)
2936 vnet_main_t * vnm = vnet_get_main();
2937 clib_error_t * error = 0;
2939 ip6_address_t ip6_addr;
2942 if (unformat_user (input,
2943 unformat_vnet_sw_interface, vnm, &sw_if_index))
2945 /* get the rest of the command */
2946 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2948 if(unformat (input, "%U/%d",
2949 unformat_ip6_address, &ip6_addr,
2953 return(unformat_parse_error (input));
2956 error = set_ip6_link_local_address(vm,
2963 VLIB_CLI_COMMAND (set_ip6_link_local_address_command, static) = {
2964 .path = "set ip6 link-local address",
2965 .short_help = "Set ip6 interface link-local address <intfc> <address.>",
2966 .function = set_ip6_link_local_address_cmd,
2969 /* callback when an interface address is added or deleted */
2971 ip6_neighbor_add_del_interface_address (ip6_main_t * im,
2974 ip6_address_t * address,
2976 u32 if_address_index,
2979 vnet_main_t * vnm = vnet_get_main();
2980 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
2982 vlib_main_t * vm = vnm->vlib_main;
2983 ip6_radv_t * radv_info;
2985 ip6_mldp_group_t *mcast_group_info;
2987 /* create solicited node multicast address for this interface adddress */
2988 ip6_set_solicited_node_multicast_address (&a, 0);
2990 a.as_u8[0xd] = address->as_u8[0xd];
2991 a.as_u8[0xe] = address->as_u8[0xe];
2992 a.as_u8[0xf] = address->as_u8[0xf];
2996 /* try to create radv_info - does nothing if ipv6 already enabled */
2997 enable_ip6_interface(vm, sw_if_index);
2999 /* look up the radv_t information for this interface */
3000 vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
3001 ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3005 radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3008 if( !ip6_address_is_link_local_unicast (address))
3009 radv_info->ref_count++;
3011 /* lookup prefix info for this address on this interface */
3012 uword * p = mhash_get (&radv_info->address_to_mldp_index, &a);
3013 mcast_group_info = p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0;
3015 /* add -solicted node multicast address */
3016 if(!mcast_group_info)
3020 pool_get (radv_info->mldp_group_pool, mcast_group_info);
3022 mi = mcast_group_info - radv_info->mldp_group_pool;
3023 mhash_set (&radv_info->address_to_mldp_index, &a, mi, /* old_value */ 0);
3025 mcast_group_info->type = 4;
3026 mcast_group_info->mcast_source_address_pool = 0;
3027 mcast_group_info->num_sources = 0;
3028 memcpy(&mcast_group_info->mcast_address, &a, sizeof(ip6_address_t));
3036 /* look up the radv_t information for this interface */
3037 vec_validate_init_empty (nm->if_radv_pool_index_by_sw_if_index, sw_if_index, ~0);
3038 ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3042 radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3044 /* lookup prefix info for this address on this interface */
3045 uword * p = mhash_get (&radv_info->address_to_mldp_index, &a);
3046 mcast_group_info = p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0;
3048 if(mcast_group_info)
3050 mhash_unset (&radv_info->address_to_mldp_index, &a,/* old_value */ 0);
3051 pool_put (radv_info->mldp_group_pool, mcast_group_info);
3054 /* if interface up send MLDP "report" */
3055 radv_info->all_routers_mcast = 0;
3058 if( !ip6_address_is_link_local_unicast (address))
3059 radv_info->ref_count--;
3064 clib_error_t *ip6_set_neighbor_limit (u32 neighbor_limit)
3066 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3068 nm->limit_neighbor_cache_size = neighbor_limit;
3072 static clib_error_t * ip6_neighbor_init (vlib_main_t * vm)
3074 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3075 ip6_main_t * im = &ip6_main;
3077 mhash_init (&nm->neighbor_index_by_key,
3078 /* value size */ sizeof (uword),
3079 /* key size */ sizeof (ip6_neighbor_key_t));
3081 icmp6_register_type (vm, ICMP6_neighbor_solicitation, ip6_icmp_neighbor_solicitation_node.index);
3082 icmp6_register_type (vm, ICMP6_neighbor_advertisement, ip6_icmp_neighbor_advertisement_node.index);
3083 icmp6_register_type (vm, ICMP6_router_solicitation, ip6_icmp_router_solicitation_node.index);
3084 icmp6_register_type (vm, ICMP6_router_advertisement, ip6_icmp_router_advertisement_node.index);
3086 /* handler node for ip6 neighbor discovery events and timers */
3087 vlib_register_node (vm, &ip6_icmp_neighbor_discovery_event_node);
3089 /* add call backs */
3090 ip6_add_del_interface_address_callback_t cb;
3091 memset(&cb, 0x0, sizeof(ip6_add_del_interface_address_callback_t));
3093 /* when an interface address changes... */
3094 cb.function = ip6_neighbor_add_del_interface_address;
3095 cb.function_opaque = 0;
3096 vec_add1 (im->add_del_interface_address_callbacks, cb);
3098 mhash_init (&nm->pending_resolutions_by_address,
3099 /* value size */ sizeof (uword),
3100 /* key size */ sizeof (ip6_address_t));
3102 /* default, configurable */
3103 nm->limit_neighbor_cache_size = 50000;
3106 /* $$$$ Hack fix for today */
3107 vec_validate_init_empty
3108 (im->discover_neighbor_next_index_by_hw_if_index, 32, 0 /* drop */);
3114 VLIB_INIT_FUNCTION (ip6_neighbor_init);
3117 void vnet_register_ip6_neighbor_resolution_event (vnet_main_t * vnm,
3123 ip6_neighbor_main_t * nm = &ip6_neighbor_main;
3124 ip6_address_t * address = address_arg;
3126 pending_resolution_t * pr;
3128 pool_get (nm->pending_resolutions, pr);
3130 pr->next_index = ~0;
3131 pr->node_index = node_index;
3132 pr->type_opaque = type_opaque;
3135 p = mhash_get (&nm->pending_resolutions_by_address, address);
3138 /* Insert new resolution at the head of the list */
3139 pr->next_index = p[0];
3140 mhash_unset (&nm->pending_resolutions_by_address, address, 0);
3143 mhash_set (&nm->pending_resolutions_by_address, address,
3144 pr - nm->pending_resolutions, 0 /* old value */);