X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=vnet%2Fvnet%2Fip%2Fip6_neighbor.c;h=92417a4402566338e9aa45b7bae8bd8e5cc1161a;hb=3e046ea96e7e9d98a8dd67eab84031e1d71b4422;hp=e042385d9fa61be51e7e7c9069d44ba51f5d7d8b;hpb=0683c9cc130d45f1246be78fa4ebf3f8d7f322bb;p=vpp.git diff --git a/vnet/vnet/ip/ip6_neighbor.c b/vnet/vnet/ip/ip6_neighbor.c index e042385d9fa..92417a44025 100644 --- a/vnet/vnet/ip/ip6_neighbor.c +++ b/vnet/vnet/ip/ip6_neighbor.c @@ -16,6 +16,7 @@ */ #include +#include #include #include #include @@ -23,10 +24,6 @@ #include #include -#if DPDK==1 -#include -#endif - /** * @file * @brief IPv6 Neighbor Adjacency and Neighbor Discovery. @@ -35,26 +32,10 @@ * adjacency tables and neighbor discovery logic. */ -typedef struct { - ip6_address_t ip6_address; - u32 sw_if_index; - u32 pad; -} ip6_neighbor_key_t; - -/* can't use sizeof link_layer_address, that's 8 */ +/* can't use sizeof link_layer_address, that's 8 */ #define ETHER_MAC_ADDR_LEN 6 -typedef struct { - ip6_neighbor_key_t key; - u8 link_layer_address[8]; - u16 flags; -#define IP6_NEIGHBOR_FLAG_STATIC (1 << 0) -#define IP6_NEIGHBOR_FLAG_DYNAMIC (2 << 0) - u64 cpu_time_last_updated; - adj_index_t adj_index; -} ip6_neighbor_t; - -/* advertised prefix option */ +/* advertised prefix option */ typedef struct { /* basic advertised information */ ip6_address_t prefix; @@ -267,6 +248,7 @@ ip6_neighbor_sw_interface_up_down (vnet_main_t * vnm, { n = pool_elt_at_index (nm->neighbor_pool, to_delete[i]); mhash_unset (&nm->neighbor_index_by_key, &n->key, 0); + fib_table_entry_delete_index (n->fib_entry_index, FIB_SOURCE_ADJ); pool_put (nm->neighbor_pool, n); } @@ -316,7 +298,6 @@ typedef struct { ip6_address_t addr; } ip6_neighbor_set_unset_rpc_args_t; -#if DPDK > 0 static void ip6_neighbor_set_unset_rpc_callback ( ip6_neighbor_set_unset_rpc_args_t * a); @@ -339,51 +320,184 @@ static void set_unset_ip6_neighbor_rpc vl_api_rpc_call_main_thread (ip6_neighbor_set_unset_rpc_callback, (u8 *) &args, sizeof (args)); } -#endif static void -ip6_nd_mk_complete (ip6_neighbor_t * nbr) +ip6_nbr_probe (ip_adjacency_t *adj) { - fib_prefix_t pfx = { - .fp_len = 128, - .fp_proto = FIB_PROTOCOL_IP6, - .fp_addr = { - .ip6 = nbr->key.ip6_address, - }, - }; - ip6_main_t *im; - u32 fib_index; + icmp6_neighbor_solicitation_header_t * h; + vnet_main_t * vnm = vnet_get_main(); + ip6_main_t * im = &ip6_main; + ip_interface_address_t * ia; + ip6_address_t * dst, *src; + vnet_hw_interface_t * hi; + vnet_sw_interface_t * si; + vlib_buffer_t * b; + int bogus_length; + vlib_main_t * vm; + u32 bi = 0; - im = &ip6_main; - fib_index = im->fib_index_by_sw_if_index[nbr->key.sw_if_index]; + vm = vlib_get_main(); - /* only once please */ - if (ADJ_INDEX_INVALID == nbr->adj_index) + si = vnet_get_sw_interface(vnm, adj->rewrite_header.sw_if_index); + dst = &adj->sub_type.nbr.next_hop.ip6; + + if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)) { - nbr->adj_index = - adj_nbr_add_or_lock_w_rewrite(FIB_PROTOCOL_IP6, - FIB_LINK_IP6, - &pfx.fp_addr, - nbr->key.sw_if_index, - nbr->link_layer_address); - ASSERT(ADJ_INDEX_INVALID != nbr->adj_index); - - fib_table_entry_update_one_path(fib_index, - &pfx, - FIB_SOURCE_ADJ, - FIB_ENTRY_FLAG_NONE, - FIB_PROTOCOL_IP6, - &pfx.fp_addr, - nbr->key.sw_if_index, - ~0, - 1, - MPLS_LABEL_INVALID, - FIB_ROUTE_PATH_FLAG_NONE); + return; + } + src = ip6_interface_address_matching_destination(im, dst, + adj->rewrite_header.sw_if_index, + &ia); + if (! src) + { + return; + } + + h = vlib_packet_template_get_packet(vm, + &im->discover_neighbor_packet_template, + &bi); + + hi = vnet_get_sup_hw_interface(vnm, adj->rewrite_header.sw_if_index); + + h->ip.dst_address.as_u8[13] = dst->as_u8[13]; + h->ip.dst_address.as_u8[14] = dst->as_u8[14]; + h->ip.dst_address.as_u8[15] = dst->as_u8[15]; + h->ip.src_address = src[0]; + h->neighbor.target_address = dst[0]; + + clib_memcpy (h->link_layer_option.ethernet_address, + hi->hw_address, + vec_len(hi->hw_address)); + + h->neighbor.icmp.checksum = + ip6_tcp_udp_icmp_compute_checksum(vm, 0, &h->ip, &bogus_length); + ASSERT(bogus_length == 0); + + b = vlib_get_buffer (vm, bi); + vnet_buffer (b)->sw_if_index[VLIB_RX] = + vnet_buffer (b)->sw_if_index[VLIB_TX] = + adj->rewrite_header.sw_if_index; + + /* Add encapsulation string for software interface (e.g. ethernet header). */ + vnet_rewrite_one_header(adj[0], h, sizeof (ethernet_header_t)); + vlib_buffer_advance(b, -adj->rewrite_header.data_bytes); + + { + vlib_frame_t * f = vlib_get_frame_to_node(vm, hi->output_node_index); + u32 * to_next = vlib_frame_vector_args(f); + to_next[0] = bi; + f->n_vectors = 1; + vlib_put_frame_to_node(vm, hi->output_node_index, f); + } +} + +static void +ip6_nd_mk_complete (adj_index_t ai, ip6_neighbor_t * nbr) +{ + adj_nbr_update_rewrite (ai, ADJ_NBR_REWRITE_FLAG_COMPLETE, + ethernet_build_rewrite (vnet_get_main (), + nbr->key.sw_if_index, + adj_get_link_type(ai), + nbr->link_layer_address)); +} + +static void +ip6_nd_mk_incomplete (adj_index_t ai, ip6_neighbor_t * nbr) +{ + adj_nbr_update_rewrite ( + ai, + ADJ_NBR_REWRITE_FLAG_INCOMPLETE, + ethernet_build_rewrite (vnet_get_main (), + nbr->key.sw_if_index, + adj_get_link_type(ai), + VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST)); +} + +#define IP6_NBR_MK_KEY(k, sw_if_index, addr) \ +{ \ + k.sw_if_index = sw_if_index; \ + k.ip6_address = *addr; \ + k.pad = 0; \ +} + +static ip6_neighbor_t * +ip6_nd_find (u32 sw_if_index, + const ip6_address_t * addr) +{ + ip6_neighbor_main_t * nm = &ip6_neighbor_main; + ip6_neighbor_t * n = NULL; + ip6_neighbor_key_t k; + uword *p; + + IP6_NBR_MK_KEY(k, sw_if_index, addr); + + p = mhash_get (&nm->neighbor_index_by_key, &k); + if (p) { + n = pool_elt_at_index (nm->neighbor_pool, p[0]); + } + + return (n); +} + +static adj_walk_rc_t +ip6_nd_mk_complete_walk (adj_index_t ai, void *ctx) +{ + ip6_neighbor_t *nbr = ctx; + + ip6_nd_mk_complete (ai, nbr); + + return (ADJ_WALK_RC_CONTINUE); +} + +static adj_walk_rc_t +ip6_nd_mk_incomplete_walk (adj_index_t ai, void *ctx) +{ + ip6_neighbor_t *nbr = ctx; + + ip6_nd_mk_incomplete (ai, nbr); + + return (ADJ_WALK_RC_CONTINUE); +} + +void +ip6_ethernet_update_adjacency (vnet_main_t * vnm, + u32 sw_if_index, + u32 ai) +{ + ip6_neighbor_t *nbr; + ip_adjacency_t *adj; + + adj = adj_get (ai); + + nbr = ip6_nd_find (sw_if_index, &adj->sub_type.nbr.next_hop.ip6); + + if (NULL != nbr) + { + adj_nbr_walk_nh6 (sw_if_index, &nbr->key.ip6_address, + ip6_nd_mk_complete_walk, nbr); } else { - adj_nbr_update_rewrite(nbr->adj_index, - nbr->link_layer_address); + /* + * no matching ND entry. + * construct the rewrite required to for an ND packet, and stick + * that in the adj's pipe to smoke. + */ + adj_nbr_update_rewrite (ai, + ADJ_NBR_REWRITE_FLAG_INCOMPLETE, + ethernet_build_rewrite (vnm, + sw_if_index, + VNET_LINK_IP6, + VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST)); + + /* + * since the FIB has added this adj for a route, it makes sense it may + * want to forward traffic sometime soon. Let's send a speculative ND. + * just one. If we were to do periodically that wouldn't be bad either, + * but that's more code than i'm prepared to write at this time for + * relatively little reward. + */ + ip6_nbr_probe (adj); } } @@ -403,21 +517,17 @@ vnet_set_ip6_ethernet_neighbor (vlib_main_t * vm, u32 next_index; pending_resolution_t * pr, * mc; -#if DPDK > 0 if (os_get_cpu_number()) { set_unset_ip6_neighbor_rpc (vm, sw_if_index, a, link_layer_address, 1 /* set new neighbor */, is_static); return 0; } -#endif k.sw_if_index = sw_if_index; k.ip6_address = a[0]; k.pad = 0; - vlib_worker_thread_barrier_sync (vm); - p = mhash_get (&nm->neighbor_index_by_key, &k); if (p) { n = pool_elt_at_index (nm->neighbor_pool, p[0]); @@ -429,11 +539,40 @@ vnet_set_ip6_ethernet_neighbor (vlib_main_t * vm, } if (make_new_nd_cache_entry) { + fib_prefix_t pfx = { + .fp_len = 128, + .fp_proto = FIB_PROTOCOL_IP6, + .fp_addr = { + .ip6 = k.ip6_address, + }, + }; + u32 fib_index; + pool_get (nm->neighbor_pool, n); mhash_set (&nm->neighbor_index_by_key, &k, n - nm->neighbor_pool, /* old value */ 0); n->key = k; - n->adj_index = ADJ_INDEX_INVALID; + + clib_memcpy (n->link_layer_address, + link_layer_address, + n_bytes_link_layer_address); + + /* + * create the adj-fib. the entry in the FIB table for and to the peer. + */ + fib_index = ip6_main.fib_index_by_sw_if_index[n->key.sw_if_index]; + n->fib_entry_index = + fib_table_entry_update_one_path(fib_index, + &pfx, + FIB_SOURCE_ADJ, + FIB_ENTRY_FLAG_NONE, + FIB_PROTOCOL_IP6, + &pfx.fp_addr, + n->key.sw_if_index, + ~0, + 1, + NULL, // no label stack + FIB_ROUTE_PATH_FLAG_NONE); } else { @@ -445,20 +584,22 @@ vnet_set_ip6_ethernet_neighbor (vlib_main_t * vm, link_layer_address, n_bytes_link_layer_address)) return -1; - } - /* Update time stamp and ethernet address. */ - clib_memcpy (n->link_layer_address, - link_layer_address, - n_bytes_link_layer_address); + clib_memcpy (n->link_layer_address, + link_layer_address, + n_bytes_link_layer_address); + } + /* Update time stamp and flags. */ n->cpu_time_last_updated = clib_cpu_time_now (); if (is_static) n->flags |= IP6_NEIGHBOR_FLAG_STATIC; else n->flags |= IP6_NEIGHBOR_FLAG_DYNAMIC; - ip6_nd_mk_complete(n); + adj_nbr_walk_nh6 (sw_if_index, + &n->key.ip6_address, + ip6_nd_mk_complete_walk, n); /* Customer(s) waiting for this address to be resolved? */ p = mhash_get (&nm->pending_resolutions_by_address, a); @@ -507,44 +648,9 @@ vnet_set_ip6_ethernet_neighbor (vlib_main_t * vm, } } - vlib_worker_thread_barrier_release(vm); return 0; } -static void -ip6_nd_mk_incomplete (ip6_neighbor_t *nbr) -{ - fib_prefix_t pfx = { - .fp_len = 128, - .fp_proto = FIB_PROTOCOL_IP6, - .fp_addr = { - .ip6 = nbr->key.ip6_address, - }, - }; - u32 fib_index; - ip6_main_t *im; - - im = &ip6_main; - fib_index = im->fib_index_by_sw_if_index[nbr->key.sw_if_index]; - - /* - * revert the adj this ND entry sourced to incomplete - */ - adj_nbr_update_rewrite(nbr->adj_index, - NULL); - - /* - * remove the FIB entry the ND entry sourced - */ - fib_table_entry_delete(fib_index, &pfx, FIB_SOURCE_ADJ); - - /* - * Unlock the adj now that the ARP entry is no longer a source - */ - adj_unlock(nbr->adj_index); - nbr->adj_index = ADJ_INDEX_INVALID; -} - int vnet_unset_ip6_ethernet_neighbor (vlib_main_t * vm, u32 sw_if_index, @@ -558,21 +664,17 @@ vnet_unset_ip6_ethernet_neighbor (vlib_main_t * vm, uword * p; int rv = 0; -#if DPDK > 0 if (os_get_cpu_number()) { set_unset_ip6_neighbor_rpc (vm, sw_if_index, a, link_layer_address, 0 /* unset */, 0); return 0; } -#endif k.sw_if_index = sw_if_index; k.ip6_address = a[0]; k.pad = 0; - vlib_worker_thread_barrier_sync (vm); - p = mhash_get (&nm->neighbor_index_by_key, &k); if (p == 0) { @@ -582,16 +684,19 @@ vnet_unset_ip6_ethernet_neighbor (vlib_main_t * vm, n = pool_elt_at_index (nm->neighbor_pool, p[0]); - ip6_nd_mk_incomplete(n); + adj_nbr_walk_nh6 (sw_if_index, + &n->key.ip6_address, + ip6_nd_mk_incomplete_walk, + n); + mhash_unset (&nm->neighbor_index_by_key, &n->key, 0); + fib_table_entry_delete_index (n->fib_entry_index, FIB_SOURCE_ADJ); pool_put (nm->neighbor_pool, n); out: - vlib_worker_thread_barrier_release(vm); return rv; } -#if DPDK > 0 static void ip6_neighbor_set_unset_rpc_callback ( ip6_neighbor_set_unset_rpc_args_t * a) { @@ -603,7 +708,6 @@ static void ip6_neighbor_set_unset_rpc_callback vnet_unset_ip6_ethernet_neighbor (vm, a->sw_if_index, &a->addr, a->link_layer_address, 6); } -#endif static int ip6_neighbor_sort (void *a1, void *a2) @@ -618,13 +722,31 @@ ip6_neighbor_sort (void *a1, void *a2) return cmp; } +ip6_neighbor_t * +ip6_neighbors_entries (u32 sw_if_index) +{ + ip6_neighbor_main_t * nm = &ip6_neighbor_main; + ip6_neighbor_t *n, *ns = 0; + + /* *INDENT-OFF* */ + pool_foreach (n, nm->neighbor_pool, ({ + if (sw_if_index != ~0 && n->key.sw_if_index != sw_if_index) + continue; + vec_add1 (ns, n[0]); + })); + /* *INDENT-ON* */ + + if (ns) + vec_sort_with_function (ns, ip6_neighbor_sort); + return ns; +} + static clib_error_t * show_ip6_neighbors (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { vnet_main_t * vnm = vnet_get_main(); - ip6_neighbor_main_t * nm = &ip6_neighbor_main; ip6_neighbor_t * n, * ns; clib_error_t * error = 0; u32 sw_if_index; @@ -633,16 +755,15 @@ show_ip6_neighbors (vlib_main_t * vm, sw_if_index = ~0; (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index); - ns = 0; - pool_foreach (n, nm->neighbor_pool, ({ vec_add1 (ns, n[0]); })); - vec_sort_with_function (ns, ip6_neighbor_sort); - vlib_cli_output (vm, "%U", format_ip6_neighbor_ip6_entry, vm, 0); - vec_foreach (n, ns) { - if (sw_if_index != ~0 && n->key.sw_if_index != sw_if_index) - continue; - vlib_cli_output (vm, "%U", format_ip6_neighbor_ip6_entry, vm, n); - } - vec_free (ns); + ns = ip6_neighbors_entries (sw_if_index); + if (ns) + { + vlib_cli_output (vm, "%U", format_ip6_neighbor_ip6_entry, vm, 0); + vec_foreach (n, ns) { + vlib_cli_output (vm, "%U", format_ip6_neighbor_ip6_entry, vm, n); + } + vec_free (ns); + } return error; } @@ -929,7 +1050,8 @@ icmp6_neighbor_solicitation_or_advertisement (vlib_main_t * vm, vlib_buffer_advance(p0, - ethernet_buffer_header_size(p0)); eth0 = vlib_buffer_get_current(p0); clib_memcpy(eth0->dst_address, eth0->src_address, 6); - clib_memcpy(eth0->src_address, eth_if0->address, 6); + if (eth_if0) + clib_memcpy(eth0->src_address, eth_if0->address, 6); /* Setup input and output sw_if_index for packet */ ASSERT(vnet_buffer(p0)->sw_if_index[VLIB_RX] == sw_if_index0); @@ -1346,9 +1468,10 @@ icmp6_router_solicitation(vlib_main_t * vm, : error0); next0 = is_dropped ? next0 : ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW; - vnet_buffer (p0)->ip.adj_index[VLIB_RX] = adj_index0; + vnet_buffer (p0)->ip.adj_index[VLIB_TX] = adj_index0; } } + p0->flags |= VNET_BUFFER_LOCALLY_ORIGINATED; radv_info->n_solicitations_dropped += is_dropped; radv_info->n_solicitations_rcvd += is_solicitation; @@ -1714,7 +1837,6 @@ ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm, pool_put (nm->if_radv_pool, a); nm->if_radv_pool_index_by_sw_if_index[sw_if_index] = ~0; ri = ~0; - ip6_sw_interface_enable_disable(sw_if_index, 0); } } else @@ -1723,7 +1845,6 @@ ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm, { vnet_hw_interface_t * hw_if0; - ip6_sw_interface_enable_disable(sw_if_index, 1); hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index); pool_get (nm->if_radv_pool, a); @@ -1746,11 +1867,10 @@ ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm, a->min_delay_between_radv = MIN_DELAY_BETWEEN_RAS; a->max_delay_between_radv = MAX_DELAY_BETWEEN_RAS; a->max_rtr_default_lifetime = MAX_DEF_RTR_LIFETIME; - a->seed = random_default_seed(); - - /* for generating random interface ids */ - a->randomizer = 0x1119194911191949ULL; - a->randomizer = random_u64 ((u32 *)&a->randomizer); + a->seed = (u32) clib_cpu_time_now(); + (void) random_u32 (&a->seed); + a->randomizer = clib_cpu_time_now(); + (void) random_u64 (&a->randomizer); a->initial_adverts_count = MAX_INITIAL_RTR_ADVERTISEMENTS ; a->initial_adverts_sent = a->initial_adverts_count-1; @@ -1776,7 +1896,7 @@ ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm, {0x33, 0x33, 0x00, 0x00, 0x00, IP6_MULTICAST_GROUP_ID_all_hosts}; a->all_nodes_adj_index = adj_rewrite_add_and_lock(FIB_PROTOCOL_IP6, - FIB_LINK_IP6, + VNET_LINK_IP6, sw_if_index, link_layer_address); } @@ -1786,7 +1906,7 @@ ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm, {0x33, 0x33, 0x00, 0x00, 0x00, IP6_MULTICAST_GROUP_ID_all_routers}; a->all_routers_adj_index = adj_rewrite_add_and_lock(FIB_PROTOCOL_IP6, - FIB_LINK_IP6, + VNET_LINK_IP6, sw_if_index, link_layer_address); } @@ -1797,7 +1917,7 @@ ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm, a->all_mldv2_routers_adj_index = adj_rewrite_add_and_lock(FIB_PROTOCOL_IP6, - FIB_LINK_IP6, + VNET_LINK_IP6, sw_if_index, link_layer_address); } @@ -2010,15 +2130,16 @@ ip6_neighbor_send_mldpv2_report(u32 sw_if_index) /* * OK to override w/ no regard for actual FIB, because - * ip6-rewrite-local only looks at the adjacency. + * ip6-rewrite only looks at the adjacency. */ vnet_buffer (b0)->sw_if_index[VLIB_RX] = vnet_main.local_interface_sw_if_index; - vnet_buffer (b0)->ip.adj_index[VLIB_RX] = + vnet_buffer (b0)->ip.adj_index[VLIB_TX] = radv_info->all_mldv2_routers_adj_index; + b0->flags |= VNET_BUFFER_LOCALLY_ORIGINATED; - vlib_node_t * node = vlib_get_node_by_name (vm, (u8 *) "ip6-rewrite-local"); + vlib_node_t * node = vlib_get_node_by_name (vm, (u8 *) "ip6-rewrite"); f = vlib_get_frame_to_node (vm, node->index); to_next = vlib_frame_vector_args (f); @@ -2040,7 +2161,7 @@ VLIB_REGISTER_NODE (ip6_icmp_router_solicitation_node,static) = { .n_next_nodes = ICMP6_ROUTER_SOLICITATION_N_NEXT, .next_nodes = { [ICMP6_ROUTER_SOLICITATION_NEXT_DROP] = "error-drop", - [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW] = "ip6-rewrite-local", + [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW] = "ip6-rewrite", [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX] = "interface-output", }, }; @@ -3725,11 +3846,9 @@ ethernet_ndp_change_mac (vlib_main_t * vm, u32 sw_if_index) pool_foreach (n, nm->neighbor_pool, ({ if (n->key.sw_if_index == sw_if_index) { - if (ADJ_INDEX_INVALID != n->adj_index) - { - adj_nbr_update_rewrite(n->adj_index, - n->link_layer_address); - } + adj_nbr_walk_nh6 (sw_if_index, + &n->key.ip6_address, + ip6_nd_mk_complete_walk, n); } })); /* *INDENT-ON* */