*/
#include <vnet/ip/ip.h>
+#include <vnet/ip/ip6_neighbor.h>
#include <vnet/ethernet/ethernet.h>
#include <vppinfra/mhash.h>
#include <vppinfra/md5.h>
#include <vnet/fib/fib_table.h>
#include <vnet/fib/ip6_fib.h>
-#if DPDK==1
-#include <vnet/devices/dpdk/dpdk.h>
-#endif
-
/**
* @file
* @brief IPv6 Neighbor Adjacency and Neighbor Discovery.
* 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;
{
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);
}
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);
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);
}
}
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]);
}
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
{
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);
}
}
- 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,
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)
{
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)
{
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)
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;
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;
}
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);
: 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;
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
{
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);
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;
{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);
}
{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);
}
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);
}
/*
* 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);
.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",
},
};
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* */