#include <vnet/adj/adj_mcast.h>
#include <vnet/fib/fib_table.h>
#include <vnet/fib/ip6_fib.h>
+#include <vnet/mfib/ip6_mfib.h>
/**
* @file
/* local information */
u32 sw_if_index;
- u32 fib_index;
int send_radv; /* radv on/off on this interface - set by config */
int cease_radv; /* we are ceasing to send - set byf config */
int send_unicast;
} ip6_neighbor_main_t;
+/* ipv6 neighbor discovery - timer/event types */
+typedef enum
+{
+ ICMP6_ND_EVENT_INIT,
+} ip6_icmp_neighbor_discovery_event_type_t;
+
+typedef union
+{
+ u32 add_del_swindex;
+ struct
+ {
+ u32 up_down_swindex;
+ u32 fib_index;
+ } up_down_event;
+} ip6_icmp_neighbor_discovery_event_data_t;
+
static ip6_neighbor_main_t ip6_neighbor_main;
static ip6_address_t ip6a_zero; /* ip6 address 0 */
static void set_unset_ip6_neighbor_rpc
(vlib_main_t * vm,
u32 sw_if_index,
- ip6_address_t * a, u8 * link_layer_addreess, int is_add, int is_static)
+ ip6_address_t * a, u8 * link_layer_address, int is_add, int is_static)
{
ip6_neighbor_set_unset_rpc_args_t args;
void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
args.is_add = is_add;
args.is_static = is_static;
clib_memcpy (&args.addr, a, sizeof (*a));
- clib_memcpy (args.link_layer_address, link_layer_addreess, 6);
+ if (NULL != link_layer_address)
+ clib_memcpy (args.link_layer_address, link_layer_address, 6);
vl_api_rpc_call_main_thread (ip6_neighbor_set_unset_rpc_callback,
(u8 *) & args, sizeof (args));
&h0->target_address,
128);
- if (FIB_NODE_INDEX_INVALID == fei ||
- !(FIB_ENTRY_FLAG_LOCAL &
- fib_entry_get_flags_for_source (fei,
- FIB_SOURCE_INTERFACE)))
+ if (FIB_NODE_INDEX_INVALID == fei)
{
+ /* The target address is not in the FIB */
error0 =
ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_UNKNOWN;
}
+ else
+ {
+ if (FIB_ENTRY_FLAG_LOCAL &
+ fib_entry_get_flags_for_source (fei,
+ FIB_SOURCE_INTERFACE))
+ {
+ /* It's an address that belongs to one of our interfaces
+ * that's good. */
+ }
+ else
+ if (fib_entry_is_sourced
+ (fei, FIB_SOURCE_IP6_ND_PROXY))
+ {
+ /* The address was added by IPv6 Proxy ND config.
+ * We should only respond to these if the NS arrived on
+ * the link that has a matching covering prefix */
+ }
+ else
+ {
+ error0 =
+ ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_UNKNOWN;
+ }
+ }
}
}
return frame->n_vectors;
}
-/* create and initialize router advertisement parameters with default values for this intfc */
+/**
+ * @brief Add a multicast Address to the advertised MLD set
+ */
+static void
+ip6_neighbor_add_mld_prefix (ip6_radv_t * radv_info, ip6_address_t * addr)
+{
+ ip6_mldp_group_t *mcast_group_info;
+ uword *p;
+
+ /* lookup mldp info for this interface */
+ 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;
+
+ /* add address */
+ if (!mcast_group_info)
+ {
+ /* add */
+ u32 mi;
+ 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 */
+ 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,
+ sizeof (ip6_address_t));
+ }
+}
+
+/**
+ * @brief Delete a multicast Address from the advertised MLD set
+ */
+static void
+ip6_neighbor_del_mld_prefix (ip6_radv_t * radv_info, ip6_address_t * addr)
+{
+ ip6_mldp_group_t *mcast_group_info;
+ uword *p;
+
+ 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;
+
+ if (mcast_group_info)
+ {
+ mhash_unset (&radv_info->address_to_mldp_index, &addr,
+ /* old_value */ 0);
+ pool_put (radv_info->mldp_group_pool, mcast_group_info);
+ }
+}
+
+/**
+ * @brief Add a multicast Address to the advertised MLD set
+ */
+static void
+ip6_neighbor_add_mld_grp (ip6_radv_t * a,
+ ip6_multicast_address_scope_t scope,
+ ip6_multicast_link_local_group_id_t group)
+{
+ ip6_address_t addr;
+
+ ip6_set_reserved_multicast_address (&addr, scope, group);
+
+ ip6_neighbor_add_mld_prefix (a, &addr);
+}
+
+/**
+ * @brief create and initialize router advertisement parameters with default
+ * values for this intfc
+ */
static u32
ip6_neighbor_sw_interface_add_del (vnet_main_t * vnm,
u32 sw_if_index, u32 is_add)
if (!is_add)
{
- u32 i, *to_delete = 0;
ip6_radv_prefix_t *p;
ip6_mldp_group_t *m;
/* release the lock on the interface's mcast adj */
adj_unlock (a->mcast_adj_index);
- /* clean up prefix_pool */
+ /* clean up prefix and MDP pools */
/* *INDENT-OFF* */
- pool_foreach (p, a->adv_prefixes_pool,
+ pool_flush(p, a->adv_prefixes_pool,
({
- vec_add1 (to_delete, p - a->adv_prefixes_pool);
- }));
- /* *INDENT-ON* */
-
- for (i = 0; i < vec_len (to_delete); i++)
- {
- p = pool_elt_at_index (a->adv_prefixes_pool, to_delete[i]);
mhash_unset (&a->address_to_prefix_index, &p->prefix, 0);
- pool_put (a->adv_prefixes_pool, p);
- }
-
- vec_free (to_delete);
- to_delete = 0;
-
- /* clean up mldp group pool */
- /* *INDENT-OFF* */
- pool_foreach (m, a->mldp_group_pool,
+ }));
+ pool_flush (m, a->mldp_group_pool,
({
- vec_add1 (to_delete, m - a->mldp_group_pool);
+ mhash_unset (&a->address_to_mldp_index, &m->mcast_address, 0);
}));
/* *INDENT-ON* */
- for (i = 0; i < vec_len (to_delete); i++)
- {
- m = pool_elt_at_index (a->mldp_group_pool, to_delete[i]);
- mhash_unset (&a->address_to_mldp_index, &m->mcast_address, 0);
- pool_put (a->mldp_group_pool, m);
- }
+ pool_free (a->mldp_group_pool);
+ pool_free (a->adv_prefixes_pool);
- vec_free (to_delete);
+ mhash_free (&a->address_to_prefix_index);
+ mhash_free (&a->address_to_mldp_index);
pool_put (nm->if_radv_pool, a);
nm->if_radv_pool_index_by_sw_if_index[sw_if_index] = ~0;
memset (a, 0, sizeof (a[0]));
a->sw_if_index = sw_if_index;
- a->fib_index = ~0;
a->max_radv_interval = DEF_MAX_RADV_INTERVAL;
a->min_radv_interval = DEF_MIN_RADV_INTERVAL;
a->curr_hop_limit = DEF_CURR_HOP_LIMIT;
a->adv_router_lifetime_in_sec = DEF_DEF_RTR_LIFETIME;
- a->adv_link_layer_address = 1; /* send ll address source address option */
+ /* send ll address source address option */
+ a->adv_link_layer_address = 1;
a->min_delay_between_radv = MIN_DELAY_BETWEEN_RAS;
a->max_delay_between_radv = MAX_DELAY_BETWEEN_RAS;
sw_if_index);
/* add multicast groups we will always be reporting */
- ip6_address_t addr;
- ip6_mldp_group_t *mcast_group_info;
-
- ip6_set_reserved_multicast_address (&addr,
- IP6_MULTICAST_SCOPE_link_local,
- IP6_MULTICAST_GROUP_ID_all_hosts);
-
- /* lookup mldp info for this interface */
-
- uword *p = mhash_get (&a->address_to_mldp_index, &addr);
- mcast_group_info =
- p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0;
-
- /* add address */
- if (!mcast_group_info)
- {
- /* add */
- u32 mi;
- pool_get (a->mldp_group_pool, mcast_group_info);
-
- mi = mcast_group_info - a->mldp_group_pool;
- mhash_set (&a->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,
- sizeof (ip6_address_t));
- }
-
- ip6_set_reserved_multicast_address (&addr,
- IP6_MULTICAST_SCOPE_link_local,
- IP6_MULTICAST_GROUP_ID_all_routers);
-
- p = mhash_get (&a->address_to_mldp_index, &addr);
- mcast_group_info =
- p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0;
-
- if (!mcast_group_info)
- {
- /* add */
- u32 mi;
- pool_get (a->mldp_group_pool, mcast_group_info);
-
- mi = mcast_group_info - a->mldp_group_pool;
- mhash_set (&a->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,
- sizeof (ip6_address_t));
- }
-
- ip6_set_reserved_multicast_address (&addr,
- IP6_MULTICAST_SCOPE_link_local,
- IP6_MULTICAST_GROUP_ID_mldv2_routers);
-
- p = mhash_get (&a->address_to_mldp_index, &addr);
- mcast_group_info =
- p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0;
-
- if (!mcast_group_info)
- {
- /* add */
- u32 mi;
- pool_get (a->mldp_group_pool, mcast_group_info);
-
- mi = mcast_group_info - a->mldp_group_pool;
- mhash_set (&a->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,
- sizeof (ip6_address_t));
- }
+ ip6_neighbor_add_mld_grp (a,
+ IP6_MULTICAST_SCOPE_link_local,
+ IP6_MULTICAST_GROUP_ID_all_hosts);
+ ip6_neighbor_add_mld_grp (a,
+ IP6_MULTICAST_SCOPE_link_local,
+ IP6_MULTICAST_GROUP_ID_all_routers);
+ ip6_neighbor_add_mld_grp (a,
+ IP6_MULTICAST_SCOPE_link_local,
+ IP6_MULTICAST_GROUP_ID_mldv2_routers);
}
}
return ri;
ip6_neighbor_sw_interface_add_del (vnm, sw_if_index,
0 /* is_add */ );
+ ip6_mfib_interface_enable_disable (sw_if_index, 0);
}
}
return error;
link_local_address.as_u8[8] &= 0xfd;
}
+ ip6_mfib_interface_enable_disable (sw_if_index, 1);
+
/* essentially "enables" ipv6 on this interface */
error = ip6_add_del_interface_address (vm, sw_if_index,
&link_local_address,
};
/* *INDENT-ON* */
-/* callback when an interface address is added or deleted */
+/**
+ * @brief callback when an interface address is added or deleted
+ */
static void
ip6_neighbor_add_del_interface_address (ip6_main_t * im,
uword opaque,
vlib_main_t *vm = vnm->vlib_main;
ip6_radv_t *radv_info;
ip6_address_t a;
- ip6_mldp_group_t *mcast_group_info;
/* create solicited node multicast address for this interface adddress */
ip6_set_solicited_node_multicast_address (&a, 0);
if (!ip6_address_is_link_local_unicast (address))
radv_info->ref_count++;
- /* lookup prefix info for this address on this interface */
- uword *p = mhash_get (&radv_info->address_to_mldp_index, &a);
- mcast_group_info =
- p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0;
-
- /* add -solicted node multicast address */
- if (!mcast_group_info)
- {
- /* add */
- u32 mi;
- 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, &a, 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, &a,
- sizeof (ip6_address_t));
- }
+ ip6_neighbor_add_mld_prefix (radv_info, &a);
}
}
else
/* get radv_info */
radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
- /* lookup prefix info for this address on this interface */
- uword *p = mhash_get (&radv_info->address_to_mldp_index, &a);
- mcast_group_info =
- p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0;
-
- if (mcast_group_info)
- {
- mhash_unset (&radv_info->address_to_mldp_index, &a,
- /* old_value */ 0);
- pool_put (radv_info->mldp_group_pool, mcast_group_info);
- }
+ ip6_neighbor_del_mld_prefix (radv_info, &a);
/* if interface up send MLDP "report" */
radv_info->all_routers_mcast = 0;
}
+int
+ip6_neighbor_proxy_add_del (u32 sw_if_index, ip6_address_t * addr, u8 is_del)
+{
+ u32 fib_index;
+
+ fib_prefix_t pfx = {
+ .fp_len = 128,
+ .fp_proto = FIB_PROTOCOL_IP6,
+ .fp_addr = {
+ .ip6 = *addr,
+ },
+ };
+ ip46_address_t nh = {
+ .ip6 = *addr,
+ };
+
+ fib_index = ip6_fib_table_get_index_for_sw_if_index (sw_if_index);
+
+ if (~0 == fib_index)
+ return VNET_API_ERROR_NO_SUCH_FIB;
+
+ if (is_del)
+ {
+ fib_table_entry_path_remove (fib_index,
+ &pfx,
+ FIB_SOURCE_IP6_ND_PROXY,
+ FIB_PROTOCOL_IP6,
+ &nh,
+ sw_if_index,
+ ~0, 1, FIB_ROUTE_PATH_FLAG_NONE);
+ /* flush the ND cache of this address if it's there */
+ vnet_unset_ip6_ethernet_neighbor (vlib_get_main (),
+ sw_if_index, addr, NULL, 0);
+ }
+ else
+ {
+ fib_table_entry_path_add (fib_index,
+ &pfx,
+ FIB_SOURCE_IP6_ND_PROXY,
+ FIB_ENTRY_FLAG_NONE,
+ FIB_PROTOCOL_IP6,
+ &nh,
+ sw_if_index,
+ ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
+ }
+ return (0);
+}
+
+static clib_error_t *
+set_ip6_nd_proxy_cmd (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ clib_error_t *error = 0;
+ ip6_address_t addr;
+ u32 sw_if_index;
+ u8 is_del = 0;
+
+ if (unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
+ {
+ /* get the rest of the command */
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "%U", unformat_ip6_address, &addr))
+ break;
+ else if (unformat (input, "delete") || unformat (input, "del"))
+ is_del = 1;
+ else
+ return (unformat_parse_error (input));
+ }
+ }
+
+ ip6_neighbor_proxy_add_del (sw_if_index, &addr, is_del);
+
+ return error;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (set_ip6_nd_proxy_command, static) =
+{
+ .path = "set ip6 nd proxy",
+ .short_help = "set ip6 nd proxy <HOST> <INTERFACE>",
+ .function = set_ip6_nd_proxy_cmd,
+};
+/* *INDENT-ON* */
+
void
ethernet_ndp_change_mac (u32 sw_if_index)
{