X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fip%2Fip6_neighbor.c;h=fee4356f5e0164f2344be818ffe263e9c5391a56;hb=25b049484fcf9161edb2c19250066b893c38c264;hp=82b402ff26387924e71219c6797ededd330c2a27;hpb=438f63094465d35c278155484fe85153e438873e;p=vpp.git diff --git a/src/vnet/ip/ip6_neighbor.c b/src/vnet/ip/ip6_neighbor.c index 82b402ff263..fee4356f5e0 100644 --- a/src/vnet/ip/ip6_neighbor.c +++ b/src/vnet/ip/ip6_neighbor.c @@ -19,12 +19,12 @@ #include #include #include -#include #include #include #include #include #include +#include /** * @file @@ -154,6 +154,15 @@ typedef struct /* Link local address to use (defaults to underlying physical for logical interfaces */ ip6_address_t link_local_address; + + /* router solicitations sending state */ + u8 keep_sending_rs; /* when true then next fields are valid */ + icmp6_send_router_solicitation_params_t params; + f64 sleep_interval; + f64 due_time; + u32 n_left; + f64 start_time; + vlib_buffer_t *buffer; } ip6_radv_t; typedef struct @@ -198,6 +207,10 @@ typedef struct /* Wildcard nd report publisher */ uword wc_ip6_nd_publisher_node; uword wc_ip6_nd_publisher_et; + + /* Router advertisement report publisher */ + uword ip6_ra_publisher_node; + uword ip6_ra_publisher_et; } ip6_neighbor_main_t; /* ipv6 neighbor discovery - timer/event types */ @@ -220,6 +233,7 @@ static ip6_neighbor_main_t ip6_neighbor_main; static ip6_address_t ip6a_zero; /* ip6 address 0 */ static void wc_nd_signal_report (wc_nd_report_t * r); +static void ra_signal_report (ra_report_t * r); /** * @brief publish wildcard arp event @@ -263,6 +277,37 @@ wc_nd_set_publisher_node (uword node_index, uword event_type) nm->wc_ip6_nd_publisher_et = event_type; } +static int +ra_publish (ra_report_t * r) +{ + void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length); + vl_api_rpc_call_main_thread (ra_signal_report, (u8 *) r, sizeof *r); + return 0; +} + +static void +ra_signal_report (ra_report_t * r) +{ + vlib_main_t *vm = vlib_get_main (); + ip6_neighbor_main_t *nm = &ip6_neighbor_main; + uword ni = nm->ip6_ra_publisher_node; + uword et = nm->ip6_ra_publisher_et; + + if (ni == (uword) ~ 0) + return; + ra_report_t *q = vlib_process_signal_event_data (vm, ni, et, 1, sizeof *q); + + *q = *r; +} + +void +ra_set_publisher_node (uword node_index, uword event_type) +{ + ip6_neighbor_main_t *nm = &ip6_neighbor_main; + nm->ip6_ra_publisher_node = node_index; + nm->ip6_ra_publisher_et = event_type; +} + static u8 * format_ip6_neighbor_ip6_entry (u8 * s, va_list * va) { @@ -273,7 +318,7 @@ format_ip6_neighbor_ip6_entry (u8 * s, va_list * va) u8 *flags = 0; if (!n) - return format (s, "%=12s%=20s%=6s%=20s%=40s", "Time", "Address", "Flags", + return format (s, "%=12s%=25s%=6s%=20s%=40s", "Time", "Address", "Flags", "Link layer", "Interface"); if (n->flags & IP6_NEIGHBOR_FLAG_DYNAMIC) @@ -286,7 +331,7 @@ format_ip6_neighbor_ip6_entry (u8 * s, va_list * va) flags = format (flags, "N"); si = vnet_get_sw_interface (vnm, n->key.sw_if_index); - s = format (s, "%=12U%=20U%=6s%=20U%=40U", + s = format (s, "%=12U%=25U%=6s%=20U%=40U", format_vlib_cpu_time, vm, n->cpu_time_last_updated, format_ip6_address, &n->key.ip6_address, flags ? (char *) flags : "", @@ -302,18 +347,29 @@ ip6_neighbor_adj_fib_remove (ip6_neighbor_t * n, u32 fib_index) { if (FIB_NODE_INDEX_INVALID != n->fib_entry_index) { - fib_prefix_t pfx = { - .fp_len = 128, - .fp_proto = FIB_PROTOCOL_IP6, - .fp_addr.ip6 = n->key.ip6_address, - }; - fib_table_entry_path_remove (fib_index, - &pfx, - FIB_SOURCE_ADJ, - DPO_PROTO_IP6, - &pfx.fp_addr, - n->key.sw_if_index, ~0, - 1, FIB_ROUTE_PATH_FLAG_NONE); + if (ip6_address_is_link_local_unicast (&n->key.ip6_address)) + { + ip6_ll_prefix_t pfx = { + .ilp_addr = n->key.ip6_address, + .ilp_sw_if_index = n->key.sw_if_index, + }; + ip6_ll_table_entry_delete (&pfx); + } + else + { + fib_prefix_t pfx = { + .fp_len = 128, + .fp_proto = FIB_PROTOCOL_IP6, + .fp_addr.ip6 = n->key.ip6_address, + }; + fib_table_entry_path_remove (fib_index, + &pfx, + FIB_SOURCE_ADJ, + DPO_PROTO_IP6, + &pfx.fp_addr, + n->key.sw_if_index, ~0, + 1, FIB_ROUTE_PATH_FLAG_NONE); + } } } @@ -566,8 +622,10 @@ ip6_ethernet_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai) switch (adj->lookup_next_index) { - case IP_LOOKUP_NEXT_ARP: case IP_LOOKUP_NEXT_GLEAN: + adj_glean_update_rewrite (ai); + break; + case IP_LOOKUP_NEXT_ARP: if (NULL != nbr) { adj_nbr_walk_nh6 (sw_if_index, &nbr->key.ip6_address, @@ -638,18 +696,30 @@ ip6_ethernet_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai) static void ip6_neighbor_adj_fib_add (ip6_neighbor_t * n, u32 fib_index) { - fib_prefix_t pfx = { - .fp_len = 128, - .fp_proto = FIB_PROTOCOL_IP6, - .fp_addr.ip6 = n->key.ip6_address, - }; + if (ip6_address_is_link_local_unicast (&n->key.ip6_address)) + { + ip6_ll_prefix_t pfx = { + .ilp_addr = n->key.ip6_address, + .ilp_sw_if_index = n->key.sw_if_index, + }; + n->fib_entry_index = + ip6_ll_table_entry_update (&pfx, FIB_ROUTE_PATH_FLAG_NONE); + } + else + { + fib_prefix_t pfx = { + .fp_len = 128, + .fp_proto = FIB_PROTOCOL_IP6, + .fp_addr.ip6 = n->key.ip6_address, + }; - n->fib_entry_index = - fib_table_entry_path_add (fib_index, &pfx, FIB_SOURCE_ADJ, - FIB_ENTRY_FLAG_ATTACHED, - DPO_PROTO_IP6, &pfx.fp_addr, - n->key.sw_if_index, ~0, 1, NULL, - FIB_ROUTE_PATH_FLAG_NONE); + n->fib_entry_index = + fib_table_entry_path_add (fib_index, &pfx, FIB_SOURCE_ADJ, + FIB_ENTRY_FLAG_ATTACHED, + DPO_PROTO_IP6, &pfx.fp_addr, + n->key.sw_if_index, ~0, 1, NULL, + FIB_ROUTE_PATH_FLAG_NONE); + } } int @@ -706,9 +776,8 @@ vnet_set_ip6_ethernet_neighbor (vlib_main_t * vm, */ if (!is_no_fib_entry) { - ip6_neighbor_adj_fib_add (n, - ip6_fib_table_get_index_for_sw_if_index - (n->key.sw_if_index)); + ip6_neighbor_adj_fib_add + (n, ip6_fib_table_get_index_for_sw_if_index (n->key.sw_if_index)); } else { @@ -1133,7 +1202,7 @@ icmp6_neighbor_solicitation_or_advertisement (vlib_main_t * vm, &h0->target_address, o0->ethernet_address, sizeof (o0->ethernet_address), - 0, ip6_sadd_link_local); + 0, 0); } if (is_solicitation && error0 == ICMP6_ERROR_NONE) @@ -1151,9 +1220,18 @@ icmp6_neighbor_solicitation_or_advertisement (vlib_main_t * vm, } else { - fei = ip6_fib_table_lookup_exact_match (fib_index, - &h0->target_address, - 128); + if (ip6_address_is_link_local_unicast (&h0->target_address)) + { + fei = ip6_fib_table_lookup_exact_match + (ip6_ll_fib_get (sw_if_index0), + &h0->target_address, 128); + } + else + { + fei = ip6_fib_table_lookup_exact_match (fib_index, + &h0->target_address, + 128); + } if (FIB_NODE_INDEX_INVALID == fei) { @@ -1172,7 +1250,8 @@ icmp6_neighbor_solicitation_or_advertisement (vlib_main_t * vm, } else if (fib_entry_is_sourced - (fei, FIB_SOURCE_IP6_ND_PROXY)) + (fei, FIB_SOURCE_IP6_ND_PROXY) || + fib_entry_is_sourced (fei, FIB_SOURCE_IP6_ND)) { /* The address was added by IPv6 Proxy ND config. * We should only respond to these if the NS arrived on @@ -1843,6 +1922,22 @@ icmp6_router_advertisement (vlib_main_t * vm, if (error0 == ICMP6_ERROR_NONE) { + radv_info->keep_sending_rs = 0; + + ra_report_t r; + + r.sw_if_index = sw_if_index0; + memcpy (r.router_address, &ip0->src_address, 16); + r.current_hop_limit = h0->current_hop_limit; + r.flags = h0->flags; + r.router_lifetime_in_sec = + clib_net_to_host_u16 (h0->router_lifetime_in_sec); + r.neighbor_reachable_time_in_msec = + clib_net_to_host_u32 + (h0->neighbor_reachable_time_in_msec); + r.time_in_msec_between_retransmitted_neighbor_solicitations = clib_net_to_host_u32 (h0->time_in_msec_between_retransmitted_neighbor_solicitations); + r.prefixes = 0; + /* validate advertised information */ if ((h0->current_hop_limit && radv_info->curr_hop_limit) && (h0->current_hop_limit != @@ -1960,6 +2055,20 @@ icmp6_router_advertisement (vlib_main_t * vm, switch (option_type) { + case ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address: + { + icmp6_neighbor_discovery_ethernet_link_layer_address_option_t + * h = + (icmp6_neighbor_discovery_ethernet_link_layer_address_option_t + *) (o0); + + if (opt_len < sizeof (*h)) + break; + + memcpy (r.slla, h->ethernet_address, 6); + } + break; + case ICMP6_NEIGHBOR_DISCOVERY_OPTION_mtu: { icmp6_neighbor_discovery_mtu_option_t *h = @@ -1969,6 +2078,8 @@ icmp6_router_advertisement (vlib_main_t * vm, if (opt_len < sizeof (*h)) break; + r.mtu = clib_net_to_host_u32 (h->mtu); + if ((h->mtu && radv_info->adv_link_mtu) && (h->mtu != clib_host_to_net_u32 @@ -1998,10 +2109,23 @@ icmp6_router_advertisement (vlib_main_t * vm, if (opt_len < sizeof (*h)) break; + vec_validate (r.prefixes, + vec_len (r.prefixes)); + ra_report_prefix_info_t *prefix = + vec_elt_at_index (r.prefixes, + vec_len (r.prefixes) - 1); + preferred = clib_net_to_host_u32 (h->preferred_time); valid = clib_net_to_host_u32 (h->valid_time); + prefix->preferred_time = preferred; + prefix->valid_time = valid; + prefix->flags = h->flags & 0xc0; + prefix->dst_address_length = + h->dst_address_length; + prefix->dst_address = h->dst_address; + /* look for matching prefix - if we our advertising it, it better be consistant */ /* *INDENT-OFF* */ pool_foreach (pr_info, radv_info->adv_prefixes_pool, @@ -2042,6 +2166,7 @@ icmp6_router_advertisement (vlib_main_t * vm, break; } } + ra_publish (&r); } } } @@ -2059,7 +2184,7 @@ icmp6_router_advertisement (vlib_main_t * vm, vlib_put_next_frame (vm, node, next_index, n_left_to_next); } - /* Account for router advertisements sent. */ + /* Account for router advertisements received. */ vlib_error_count (vm, error_node->node_index, ICMP6_ERROR_ROUTER_ADVERTISEMENTS_RX, n_advertisements_rcvd); @@ -2067,6 +2192,252 @@ icmp6_router_advertisement (vlib_main_t * vm, return frame->n_vectors; } +static inline f64 +random_f64_from_to (f64 from, f64 to) +{ + static u32 seed = 0; + static u8 seed_set = 0; + if (!seed_set) + { + seed = random_default_seed (); + seed_set = 1; + } + return random_f64 (&seed) * (to - from) + from; +} + +static inline u8 +get_mac_address (u32 sw_if_index, u8 * address) +{ + vnet_main_t *vnm = vnet_get_main (); + vnet_hw_interface_t *hw_if = vnet_get_sup_hw_interface (vnm, sw_if_index); + if (!hw_if->hw_address) + return 1; + clib_memcpy (address, hw_if->hw_address, 6); + return 0; +} + +static inline vlib_buffer_t * +create_buffer_for_rs (vlib_main_t * vm, ip6_radv_t * radv_info) +{ + u32 bi0; + vlib_buffer_t *p0; + vlib_buffer_free_list_t *fl; + icmp6_router_solicitation_header_t *rh; + u16 payload_length; + int bogus_length; + u32 sw_if_index; + + sw_if_index = radv_info->sw_if_index; + + if (vlib_buffer_alloc (vm, &bi0, 1) != 1) + { + clib_warning ("buffer allocation failure"); + return 0; + } + + p0 = vlib_get_buffer (vm, bi0); + fl = vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX); + vlib_buffer_init_for_free_list (p0, fl); + VLIB_BUFFER_TRACE_TRAJECTORY_INIT (p0); + p0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED; + + vnet_buffer (p0)->sw_if_index[VLIB_RX] = sw_if_index; + vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index; + + vnet_buffer (p0)->ip.adj_index[VLIB_TX] = radv_info->mcast_adj_index; + + rh = vlib_buffer_get_current (p0); + p0->current_length = sizeof (*rh); + + rh->neighbor.icmp.type = ICMP6_router_solicitation; + rh->neighbor.icmp.code = 0; + rh->neighbor.icmp.checksum = 0; + rh->neighbor.reserved_must_be_zero = 0; + + rh->link_layer_option.header.type = + ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address; + if (0 != get_mac_address (sw_if_index, + rh->link_layer_option.ethernet_address)) + { + clib_warning ("interface with sw_if_index %u has no mac address", + sw_if_index); + vlib_buffer_free (vm, &bi0, 1); + return 0; + } + rh->link_layer_option.header.n_data_u64s = 1; + + payload_length = sizeof (rh->neighbor) + sizeof (u64); + + rh->ip.ip_version_traffic_class_and_flow_label = + clib_host_to_net_u32 (0x6 << 28); + rh->ip.payload_length = clib_host_to_net_u16 (payload_length); + rh->ip.protocol = IP_PROTOCOL_ICMP6; + rh->ip.hop_limit = 255; + rh->ip.src_address = radv_info->link_local_address; + /* set address ff02::2 */ + rh->ip.dst_address.as_u64[0] = clib_host_to_net_u64 (0xff02L << 48); + rh->ip.dst_address.as_u64[1] = clib_host_to_net_u64 (2); + + rh->neighbor.icmp.checksum = ip6_tcp_udp_icmp_compute_checksum (vm, p0, + &rh->ip, + &bogus_length); + + return p0; +} + +static inline void +stop_sending_rs (vlib_main_t * vm, ip6_radv_t * ra) +{ + u32 bi0; + + ra->keep_sending_rs = 0; + if (ra->buffer) + { + bi0 = vlib_get_buffer_index (vm, ra->buffer); + vlib_buffer_free (vm, &bi0, 1); + ra->buffer = 0; + } +} + +static inline bool +check_send_rs (vlib_main_t * vm, ip6_radv_t * radv_info, f64 current_time, + f64 * due_time) +{ + vlib_buffer_t *p0; + vlib_frame_t *f; + u32 *to_next; + u32 next_index; + vlib_buffer_t *c0; + u32 ci0; + + icmp6_send_router_solicitation_params_t *params; + + if (!radv_info->keep_sending_rs) + return false; + + params = &radv_info->params; + + if (radv_info->due_time > current_time) + { + *due_time = radv_info->due_time; + return true; + } + + p0 = radv_info->buffer; + + next_index = ip6_rewrite_mcast_node.index; + + c0 = vlib_buffer_copy (vm, p0); + ci0 = vlib_get_buffer_index (vm, c0); + + f = vlib_get_frame_to_node (vm, next_index); + to_next = vlib_frame_vector_args (f); + to_next[0] = ci0; + f->n_vectors = 1; + vlib_put_frame_to_node (vm, next_index, f); + + if (params->mrc != 0 && --radv_info->n_left == 0) + stop_sending_rs (vm, radv_info); + else + { + radv_info->sleep_interval = + (2 + random_f64_from_to (-0.1, 0.1)) * radv_info->sleep_interval; + if (radv_info->sleep_interval > params->mrt) + radv_info->sleep_interval = + (1 + random_f64_from_to (-0.1, 0.1)) * params->mrt; + + radv_info->due_time = current_time + radv_info->sleep_interval; + + if (params->mrd != 0 + && current_time > radv_info->start_time + params->mrd) + stop_sending_rs (vm, radv_info); + else + *due_time = radv_info->due_time; + } + + return radv_info->keep_sending_rs; +} + +static uword +send_rs_process (vlib_main_t * vm, vlib_node_runtime_t * rt, + vlib_frame_t * f0) +{ + ip6_neighbor_main_t *nm = &ip6_neighbor_main; + ip6_radv_t *radv_info; + uword *event_data = 0; + f64 sleep_time = 1e9; + f64 current_time; + f64 due_time; + f64 dt = 0; + + while (true) + { + vlib_process_wait_for_event_or_clock (vm, sleep_time); + vlib_process_get_events (vm, &event_data); + vec_reset_length (event_data); + + current_time = vlib_time_now (vm); + do + { + due_time = current_time + 1e9; + /* *INDENT-OFF* */ + pool_foreach (radv_info, nm->if_radv_pool, + ({ + if (check_send_rs (vm, radv_info, current_time, &dt) + && (dt < due_time)) + due_time = dt; + })); + /* *INDENT-ON* */ + current_time = vlib_time_now (vm); + } + while (due_time < current_time); + + sleep_time = due_time - current_time; + } + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (send_rs_process_node) = { + .function = send_rs_process, + .type = VLIB_NODE_TYPE_PROCESS, + .name = "send-rs-process", +}; +/* *INDENT-ON* */ + +void +icmp6_send_router_solicitation (vlib_main_t * vm, u32 sw_if_index, u8 stop, + icmp6_send_router_solicitation_params_t * + params) +{ + ip6_neighbor_main_t *nm = &ip6_neighbor_main; + u32 rai; + ip6_radv_t *ra = 0; + + ASSERT (~0 != sw_if_index); + + rai = nm->if_radv_pool_index_by_sw_if_index[sw_if_index]; + ra = pool_elt_at_index (nm->if_radv_pool, rai); + + if (stop) + stop_sending_rs (vm, ra); + else + { + ra->keep_sending_rs = 1; + ra->params = *params; + ra->n_left = params->mrc; + ra->start_time = vlib_time_now (vm); + ra->sleep_interval = (1 + random_f64_from_to (-0.1, 0.1)) * params->irt; + ra->due_time = 0; /* send first packet ASAP */ + ra->buffer = create_buffer_for_rs (vm, ra); + if (!ra->buffer) + ra->keep_sending_rs = 0; + else + vlib_process_signal_event (vm, send_rs_process_node.index, 1, 0); + } +} + /** * @brief Add a multicast Address to the advertised MLD set */ @@ -2077,7 +2448,7 @@ ip6_neighbor_add_mld_prefix (ip6_radv_t * radv_info, ip6_address_t * addr) uword *p; /* lookup mldp info for this interface */ - p = mhash_get (&radv_info->address_to_mldp_index, &addr); + p = mhash_get (&radv_info->address_to_mldp_index, addr); mcast_group_info = p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0; @@ -2089,13 +2460,13 @@ ip6_neighbor_add_mld_prefix (ip6_radv_t * radv_info, ip6_address_t * addr) pool_get (radv_info->mldp_group_pool, mcast_group_info); mi = mcast_group_info - radv_info->mldp_group_pool; - mhash_set (&radv_info->address_to_mldp_index, &addr, mi, /* old_value */ + mhash_set (&radv_info->address_to_mldp_index, addr, mi, /* old_value */ 0); mcast_group_info->type = 4; mcast_group_info->mcast_source_address_pool = 0; mcast_group_info->num_sources = 0; - clib_memcpy (&mcast_group_info->mcast_address, &addr, + clib_memcpy (&mcast_group_info->mcast_address, addr, sizeof (ip6_address_t)); } } @@ -2192,6 +2563,9 @@ ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm, mhash_free (&a->address_to_prefix_index); mhash_free (&a->address_to_mldp_index); + if (a->keep_sending_rs) + a->keep_sending_rs = 0; + pool_put (nm->if_radv_pool, a); nm->if_radv_pool_index_by_sw_if_index[sw_if_index] = ~0; ri = ~0; @@ -2255,6 +2629,8 @@ ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm, VNET_LINK_IP6, sw_if_index); + a->keep_sending_rs = 0; + /* add multicast groups we will always be reporting */ ip6_neighbor_add_mld_grp (a, IP6_MULTICAST_SCOPE_link_local, @@ -3271,6 +3647,10 @@ show_ip6_interface_cmd (vlib_main_t * vm, vec_free (unknown_scope); } + vlib_cli_output (vm, "\tLink-local address(es):\n"); + vlib_cli_output (vm, "\t\t%U\n", format_ip6_address, + &radv_info->link_local_address); + vlib_cli_output (vm, "\tJoined group address(es):\n"); ip6_mldp_group_t *m; /* *INDENT-OFF* */ @@ -3393,7 +3773,6 @@ disable_ip6_interface (vlib_main_t * vm, u32 sw_if_index) /* if not created - do nothing */ if (ri != ~0) { - vnet_main_t *vnm = vnet_get_main (); ip6_radv_t *radv_info; radv_info = pool_elt_at_index (nm->if_radv_pool, ri); @@ -3403,14 +3782,15 @@ disable_ip6_interface (vlib_main_t * vm, u32 sw_if_index) if (radv_info->ref_count == 0) { /* essentially "disables" ipv6 on this interface */ - error = ip6_add_del_interface_address (vm, sw_if_index, - &radv_info-> - link_local_address, 128, - 1 /* is_del */ ); - - ip6_neighbor_sw_interface_add_del (vnm, sw_if_index, - 0 /* is_add */ ); + ip6_ll_prefix_t ilp = { + .ilp_addr = radv_info->link_local_address, + .ilp_sw_if_index = sw_if_index, + }; + ip6_ll_table_entry_delete (&ilp); + ip6_sw_interface_enable_disable (sw_if_index, 0); ip6_mfib_interface_enable_disable (sw_if_index, 0); + ip6_neighbor_sw_interface_add_del (vnet_get_main (), sw_if_index, + 0); } } return error; @@ -3479,38 +3859,28 @@ enable_ip6_interface (vlib_main_t * vm, u32 sw_if_index) sw_if0->type == VNET_SW_INTERFACE_TYPE_P2P) { /* make up an interface id */ - md5_context_t m; - u8 digest[16]; - - link_local_address.as_u64[0] = radv_info->randomizer; - - md5_init (&m); - md5_add (&m, &link_local_address, 16); - md5_finish (&m, digest); - - clib_memcpy (&link_local_address, digest, 16); - - radv_info->randomizer = link_local_address.as_u64[0]; + link_local_address.as_u64[1] = + random_u64 (&radv_info->randomizer); link_local_address.as_u64[0] = clib_host_to_net_u64 (0xFE80000000000000ULL); /* clear u bit */ link_local_address.as_u8[8] &= 0xfd; } + { + ip6_ll_prefix_t ilp = { + .ilp_addr = link_local_address, + .ilp_sw_if_index = sw_if_index, + }; - ip6_mfib_interface_enable_disable (sw_if_index, 1); + ip6_ll_table_entry_update (&ilp, FIB_ROUTE_PATH_LOCAL); + } /* essentially "enables" ipv6 on this interface */ - error = ip6_add_del_interface_address (vm, sw_if_index, - &link_local_address, - 128 - /* address width */ , - 0 /* is_del */ ); - - if (error) - ip6_neighbor_sw_interface_add_del (vnm, sw_if_index, - !is_add); - else + ip6_mfib_interface_enable_disable (sw_if_index, 1); + ip6_sw_interface_enable_disable (sw_if_index, 1); + + if (!error) { radv_info->link_local_address = link_local_address; } @@ -3521,6 +3891,27 @@ enable_ip6_interface (vlib_main_t * vm, u32 sw_if_index) return error; } +int +ip6_get_ll_address (u32 sw_if_index, ip6_address_t * addr) +{ + ip6_neighbor_main_t *nm = &ip6_neighbor_main; + ip6_radv_t *radv_info; + u32 ri; + + if (vec_len (nm->if_radv_pool_index_by_sw_if_index) < sw_if_index) + return 0; + + ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index]; + + if (ri == ~0) + return 0; + + radv_info = pool_elt_at_index (nm->if_radv_pool, ri); + *addr = radv_info->link_local_address; + + return (!0); +} + static clib_error_t * enable_ip6_interface_cmd (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) @@ -3981,6 +4372,8 @@ ip6_neighbor_init (vlib_main_t * vm) nm->wc_ip6_nd_publisher_node = (uword) ~ 0; + nm->ip6_ra_publisher_node = (uword) ~ 0; + #if 0 /* $$$$ Hack fix for today */ vec_validate_init_empty @@ -4256,6 +4649,7 @@ ethernet_ndp_change_mac (u32 sw_if_index) { ip6_neighbor_main_t *nm = &ip6_neighbor_main; ip6_neighbor_t *n; + adj_index_t ai; /* *INDENT-OFF* */ pool_foreach (n, nm->neighbor_pool, @@ -4268,14 +4662,31 @@ ethernet_ndp_change_mac (u32 sw_if_index) } })); /* *INDENT-ON* */ + + ai = adj_glean_get (FIB_PROTOCOL_IP6, sw_if_index); + + if (ADJ_INDEX_INVALID != ai) + adj_glean_update_rewrite (ai); } void -send_ip6_na (vlib_main_t * vm, vnet_hw_interface_t * hi) +send_ip6_na (vlib_main_t * vm, const vnet_hw_interface_t * hi) { ip6_main_t *i6m = &ip6_main; u32 sw_if_index = hi->sw_if_index; ip6_address_t *ip6_addr = ip6_interface_first_address (i6m, sw_if_index); + + send_ip6_na_w_addr (vm, ip6_addr, hi); +} + +void +send_ip6_na_w_addr (vlib_main_t * vm, + const ip6_address_t * ip6_addr, + const vnet_hw_interface_t * hi) +{ + ip6_main_t *i6m = &ip6_main; + u32 sw_if_index = hi->sw_if_index; + if (ip6_addr) { clib_warning