summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/vnet/ip/ip4_forward.c313
-rw-r--r--src/vnet/ip/ip6_forward.c151
-rw-r--r--src/vnet/ip/lookup.c2
-rw-r--r--src/vnet/ip/lookup.h31
-rw-r--r--test/test_ip4.py65
-rw-r--r--test/test_ip6.py79
6 files changed, 532 insertions, 109 deletions
diff --git a/src/vnet/ip/ip4_forward.c b/src/vnet/ip/ip4_forward.c
index 9ceb2063e11..21fe8c06d81 100644
--- a/src/vnet/ip/ip4_forward.c
+++ b/src/vnet/ip/ip4_forward.c
@@ -339,74 +339,122 @@ ip4_add_subnet_bcast_route (u32 fib_index,
}
static void
-ip4_add_interface_routes (u32 sw_if_index,
- ip4_main_t * im, u32 fib_index,
- ip_interface_address_t * a)
+ip4_add_interface_prefix_routes (ip4_main_t *im,
+ u32 sw_if_index,
+ u32 fib_index,
+ ip_interface_address_t * a)
{
ip_lookup_main_t *lm = &im->lookup_main;
+ ip_interface_prefix_t *if_prefix;
ip4_address_t *address = ip_interface_address_get_address (lm, a);
- fib_prefix_t pfx = {
- .fp_len = a->address_length,
+
+ ip_interface_prefix_key_t key = {
+ .prefix = {
+ .fp_len = a->address_length,
+ .fp_proto = FIB_PROTOCOL_IP4,
+ .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[a->address_length],
+ },
+ .sw_if_index = sw_if_index,
+ };
+
+ fib_prefix_t pfx_special = {
.fp_proto = FIB_PROTOCOL_IP4,
- .fp_addr.ip4 = *address,
};
- if (pfx.fp_len <= 30)
+ /* If prefix already set on interface, just increment ref count & return */
+ if_prefix = ip_get_interface_prefix (lm, &key);
+ if (if_prefix)
{
- /* a /30 or shorter - add a glean for the network address */
- fib_table_entry_update_one_path (fib_index, &pfx,
- FIB_SOURCE_INTERFACE,
- (FIB_ENTRY_FLAG_CONNECTED |
- FIB_ENTRY_FLAG_ATTACHED),
- DPO_PROTO_IP4,
- /* No next-hop address */
- NULL,
- sw_if_index,
- // invalid FIB index
+ if_prefix->ref_count += 1;
+ return;
+ }
+
+ /* New prefix - allocate a pool entry, initialize it, add to the hash */
+ pool_get (lm->if_prefix_pool, if_prefix);
+ if_prefix->ref_count = 1;
+ if_prefix->src_ia_index = a - lm->if_address_pool;
+ clib_memcpy (&if_prefix->key, &key, sizeof (key));
+ mhash_set (&lm->prefix_to_if_prefix_index, &key,
+ if_prefix - lm->if_prefix_pool, 0 /* old value */);
+
+ /* length <= 30 - add glean, drop first address, maybe drop bcast address */
+ if (a->address_length <= 30)
+ {
+ pfx_special.fp_len = a->address_length;
+ pfx_special.fp_addr.ip4.as_u32 = address->as_u32;
+
+ /* set the glean route for the prefix */
+ fib_table_entry_update_one_path (fib_index, &pfx_special,
+ FIB_SOURCE_INTERFACE,
+ (FIB_ENTRY_FLAG_CONNECTED |
+ FIB_ENTRY_FLAG_ATTACHED),
+ DPO_PROTO_IP4,
+ /* No next-hop address */
+ NULL,
+ sw_if_index,
+ /* invalid FIB index */
~0,
1,
- // no out-label stack
+ /* no out-label stack */
NULL,
FIB_ROUTE_PATH_FLAG_NONE);
- /* Add the two broadcast addresses as drop */
- fib_prefix_t net_pfx = {
- .fp_len = 32,
- .fp_proto = FIB_PROTOCOL_IP4,
- .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len],
- };
- if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
- fib_table_entry_special_add(fib_index,
- &net_pfx,
- FIB_SOURCE_INTERFACE,
- (FIB_ENTRY_FLAG_DROP |
- FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
- net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
- if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
- ip4_add_subnet_bcast_route(fib_index, &net_pfx, sw_if_index);
- }
- else if (pfx.fp_len == 31)
- {
- u32 mask = clib_host_to_net_u32(1);
- fib_prefix_t net_pfx = pfx;
+ /* set a drop route for the base address of the prefix */
+ pfx_special.fp_len = 32;
+ pfx_special.fp_addr.ip4.as_u32 =
+ address->as_u32 & im->fib_masks[a->address_length];
- net_pfx.fp_len = 32;
- net_pfx.fp_addr.ip4.as_u32 ^= mask;
+ if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
+ fib_table_entry_special_add (fib_index, &pfx_special,
+ FIB_SOURCE_INTERFACE,
+ (FIB_ENTRY_FLAG_DROP |
+ FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
- /* a /31 - add the other end as an attached host */
- fib_table_entry_update_one_path (fib_index, &net_pfx,
- FIB_SOURCE_INTERFACE,
- (FIB_ENTRY_FLAG_ATTACHED),
- DPO_PROTO_IP4,
- &net_pfx.fp_addr,
- sw_if_index,
- // invalid FIB index
+ /* set a route for the broadcast address of the prefix */
+ pfx_special.fp_len = 32;
+ pfx_special.fp_addr.ip4.as_u32 =
+ address->as_u32 | ~im->fib_masks[a->address_length];
+ if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
+ ip4_add_subnet_bcast_route (fib_index, &pfx_special, sw_if_index);
+
+
+ }
+ /* length == 31 - add an attached route for the other address */
+ else if (a->address_length == 31)
+ {
+ pfx_special.fp_len = 32;
+ pfx_special.fp_addr.ip4.as_u32 =
+ address->as_u32 ^ clib_host_to_net_u32(1);
+
+ fib_table_entry_update_one_path (fib_index, &pfx_special,
+ FIB_SOURCE_INTERFACE,
+ (FIB_ENTRY_FLAG_ATTACHED),
+ DPO_PROTO_IP4,
+ &pfx_special.fp_addr,
+ sw_if_index,
+ /* invalid FIB index */
~0,
1,
NULL,
FIB_ROUTE_PATH_FLAG_NONE);
}
- pfx.fp_len = 32;
+}
+
+static void
+ip4_add_interface_routes (u32 sw_if_index,
+ ip4_main_t * im, u32 fib_index,
+ ip_interface_address_t * a)
+{
+ ip_lookup_main_t *lm = &im->lookup_main;
+ ip4_address_t *address = ip_interface_address_get_address (lm, a);
+ fib_prefix_t pfx = {
+ .fp_len = 32,
+ .fp_proto = FIB_PROTOCOL_IP4,
+ .fp_addr.ip4 = *address,
+ };
+
+ /* set special routes for the prefix if needed */
+ ip4_add_interface_prefix_routes (im, sw_if_index, fib_index, a);
if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
{
@@ -443,45 +491,143 @@ ip4_add_interface_routes (u32 sw_if_index,
}
static void
-ip4_del_interface_routes (ip4_main_t * im,
- u32 fib_index,
- ip4_address_t * address, u32 address_length)
+ip4_del_interface_prefix_routes (ip4_main_t * im,
+ u32 sw_if_index,
+ u32 fib_index,
+ ip4_address_t * address,
+ u32 address_length)
{
- fib_prefix_t pfx = {
- .fp_len = address_length,
+ ip_lookup_main_t *lm = &im->lookup_main;
+ ip_interface_prefix_t *if_prefix;
+
+ ip_interface_prefix_key_t key = {
+ .prefix = {
+ .fp_len = address_length,
+ .fp_proto = FIB_PROTOCOL_IP4,
+ .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[address_length],
+ },
+ .sw_if_index = sw_if_index,
+ };
+
+ fib_prefix_t pfx_special = {
+ .fp_len = 32,
.fp_proto = FIB_PROTOCOL_IP4,
- .fp_addr.ip4 = *address,
};
- if (pfx.fp_len <= 30)
+ if_prefix = ip_get_interface_prefix (lm, &key);
+ if (!if_prefix)
{
- fib_prefix_t net_pfx = {
- .fp_len = 32,
- .fp_proto = FIB_PROTOCOL_IP4,
- .fp_addr.ip4.as_u32 = address->as_u32 & im->fib_masks[pfx.fp_len],
- };
- if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
- fib_table_entry_special_remove(fib_index,
- &net_pfx,
- FIB_SOURCE_INTERFACE);
- net_pfx.fp_addr.ip4.as_u32 |= ~im->fib_masks[pfx.fp_len];
- if (net_pfx.fp_addr.ip4.as_u32 != pfx.fp_addr.ip4.as_u32)
- fib_table_entry_special_remove(fib_index,
- &net_pfx,
- FIB_SOURCE_INTERFACE);
- fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
+ clib_warning ("Prefix not found while deleting %U",
+ format_ip4_address_and_length, address, address_length);
+ return;
}
- else if (pfx.fp_len == 31)
+
+ if_prefix->ref_count -= 1;
+
+ /*
+ * Routes need to be adjusted if:
+ * - deleting last intf addr in prefix
+ * - deleting intf addr used as default source address in glean adjacency
+ *
+ * We're done now otherwise
+ */
+ if ((if_prefix->ref_count > 0) &&
+ !pool_is_free_index (lm->if_address_pool, if_prefix->src_ia_index))
+ return;
+
+ /* length <= 30, delete glean route, first address, last address */
+ if (address_length <= 30)
{
- u32 mask = clib_host_to_net_u32(1);
- fib_prefix_t net_pfx = pfx;
- net_pfx.fp_len = 32;
- net_pfx.fp_addr.ip4.as_u32 ^= mask;
+ /* remove glean route for prefix */
+ pfx_special.fp_addr.ip4 = *address;
+ pfx_special.fp_len = address_length;
+ fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
+
+ /* if no more intf addresses in prefix, remove other special routes */
+ if (!if_prefix->ref_count)
+ {
+ /* first address in prefix */
+ pfx_special.fp_addr.ip4.as_u32 =
+ address->as_u32 & im->fib_masks[address_length];
+ pfx_special.fp_len = 32;
+
+ if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
+ fib_table_entry_special_remove (fib_index,
+ &pfx_special,
+ FIB_SOURCE_INTERFACE);
+
+ /* prefix broadcast address */
+ pfx_special.fp_addr.ip4.as_u32 =
+ address->as_u32 | ~im->fib_masks[address_length];
+ pfx_special.fp_len = 32;
- fib_table_entry_delete (fib_index, &net_pfx, FIB_SOURCE_INTERFACE);
+ if (pfx_special.fp_addr.ip4.as_u32 != address->as_u32)
+ fib_table_entry_special_remove (fib_index,
+ &pfx_special,
+ FIB_SOURCE_INTERFACE);
+ }
+ else
+ /* default source addr just got deleted, find another */
+ {
+ ip_interface_address_t *new_src_ia = NULL;
+ ip4_address_t *new_src_addr = NULL;
+
+ new_src_addr =
+ ip4_interface_address_matching_destination
+ (im, address, sw_if_index, &new_src_ia);
+
+ if_prefix->src_ia_index = new_src_ia - lm->if_address_pool;
+
+ pfx_special.fp_len = address_length;
+ pfx_special.fp_addr.ip4 = *new_src_addr;
+
+ /* set new glean route for the prefix */
+ fib_table_entry_update_one_path (fib_index, &pfx_special,
+ FIB_SOURCE_INTERFACE,
+ (FIB_ENTRY_FLAG_CONNECTED |
+ FIB_ENTRY_FLAG_ATTACHED),
+ DPO_PROTO_IP4,
+ /* No next-hop address */
+ NULL,
+ sw_if_index,
+ /* invalid FIB index */
+ ~0,
+ 1,
+ /* no out-label stack */
+ NULL,
+ FIB_ROUTE_PATH_FLAG_NONE);
+ return;
+ }
+ }
+ /* length == 31, delete attached route for the other address */
+ else if (address_length == 31)
+ {
+ pfx_special.fp_addr.ip4.as_u32 =
+ address->as_u32 ^ clib_host_to_net_u32(1);
+
+ fib_table_entry_delete (fib_index, &pfx_special, FIB_SOURCE_INTERFACE);
}
+ mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */);
+ pool_put (lm->if_prefix_pool, if_prefix);
+}
+
+static void
+ip4_del_interface_routes (u32 sw_if_index,
+ ip4_main_t * im,
+ u32 fib_index,
+ ip4_address_t * address, u32 address_length)
+{
+ fib_prefix_t pfx = {
+ .fp_len = address_length,
+ .fp_proto = FIB_PROTOCOL_IP4,
+ .fp_addr.ip4 = *address,
+ };
+
+ ip4_del_interface_prefix_routes (im, sw_if_index, fib_index,
+ address, address_length);
+
pfx.fp_len = 32;
fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
}
@@ -579,6 +725,13 @@ ip4_add_del_interface_address_internal (vlib_main_t * vm,
address,
address_length))
{
+ /* an intf may have >1 addr from the same prefix */
+ if ((sw_if_index == sif->sw_if_index) &&
+ (ia->address_length == address_length) &&
+ (x->as_u32 != address->as_u32))
+ continue;
+
+ /* error if the length or intf was different */
vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
return
@@ -610,7 +763,8 @@ ip4_add_del_interface_address_internal (vlib_main_t * vm,
if (vnet_sw_interface_is_admin_up (vnm, sw_if_index))
{
if (is_del)
- ip4_del_interface_routes (im, ip4_af.fib_index, address,
+ ip4_del_interface_routes (sw_if_index,
+ im, ip4_af.fib_index, address,
address_length);
else
ip4_add_interface_routes (sw_if_index,
@@ -712,7 +866,8 @@ ip4_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
im, fib_index,
ia);
else
- ip4_del_interface_routes (im, fib_index,
+ ip4_del_interface_routes (sw_if_index,
+ im, fib_index,
a, ia->address_length);
}));
/* *INDENT-ON* */
diff --git a/src/vnet/ip/ip6_forward.c b/src/vnet/ip/ip6_forward.c
index f9e3e0a0ab3..8734e19a889 100644
--- a/src/vnet/ip/ip6_forward.c
+++ b/src/vnet/ip/ip6_forward.c
@@ -60,22 +60,53 @@
#define OI_DECAP 0x80000000
static void
-ip6_add_interface_routes (vnet_main_t * vnm, u32 sw_if_index,
- ip6_main_t * im, u32 fib_index,
- ip_interface_address_t * a)
+ip6_add_interface_prefix_routes (ip6_main_t * im,
+ u32 sw_if_index,
+ u32 fib_index,
+ ip6_address_t * address, u32 address_length)
{
ip_lookup_main_t *lm = &im->lookup_main;
- ip6_address_t *address = ip_interface_address_get_address (lm, a);
- fib_prefix_t pfx = {
- .fp_len = a->address_length,
- .fp_proto = FIB_PROTOCOL_IP6,
- .fp_addr.ip6 = *address,
+ ip_interface_prefix_t *if_prefix;
+
+ ip_interface_prefix_key_t key = {
+ .prefix = {
+ .fp_len = address_length,
+ .fp_proto = FIB_PROTOCOL_IP6,
+ .fp_addr.ip6 = {
+ .as_u64 = {
+ address->as_u64[0] &
+ im->fib_masks[address_length].
+ as_u64[0],
+ address->
+ as_u64[1] &
+ im->fib_masks[address_length].
+ as_u64[1],
+ },
+ },
+ },
+ .sw_if_index = sw_if_index,
};
- if (a->address_length < 128)
+ /* If prefix already set on interface, just increment ref count & return */
+ if_prefix = ip_get_interface_prefix (lm, &key);
+ if (if_prefix)
+ {
+ if_prefix->ref_count += 1;
+ return;
+ }
+
+ /* New prefix - allocate a pool entry, initialize it, add to the hash */
+ pool_get (lm->if_prefix_pool, if_prefix);
+ if_prefix->ref_count = 1;
+ clib_memcpy (&if_prefix->key, &key, sizeof (key));
+ mhash_set (&lm->prefix_to_if_prefix_index, &key,
+ if_prefix - lm->if_prefix_pool, 0 /* old value */ );
+
+ /* length < 128 - add glean */
+ if (address_length < 128)
{
- fib_table_entry_update_one_path (fib_index,
- &pfx,
+ /* set the glean route for the prefix */
+ fib_table_entry_update_one_path (fib_index, &key.prefix,
FIB_SOURCE_INTERFACE,
(FIB_ENTRY_FLAG_CONNECTED |
FIB_ENTRY_FLAG_ATTACHED),
@@ -84,9 +115,27 @@ ip6_add_interface_routes (vnet_main_t * vnm, u32 sw_if_index,
NULL, sw_if_index,
/* invalid FIB index */
~0, 1,
- /* no label stack */
+ /* no out-label stack */
NULL, FIB_ROUTE_PATH_FLAG_NONE);
}
+}
+
+static void
+ip6_add_interface_routes (vnet_main_t * vnm, u32 sw_if_index,
+ ip6_main_t * im, u32 fib_index,
+ ip_interface_address_t * a)
+{
+ ip_lookup_main_t *lm = &im->lookup_main;
+ ip6_address_t *address = ip_interface_address_get_address (lm, a);
+ fib_prefix_t pfx = {
+ .fp_len = a->address_length,
+ .fp_proto = FIB_PROTOCOL_IP6,
+ .fp_addr.ip6 = *address,
+ };
+
+ /* set special routes for the prefix if needed */
+ ip6_add_interface_prefix_routes (im, sw_if_index, fib_index,
+ address, a->address_length);
pfx.fp_len = 128;
if (sw_if_index < vec_len (lm->classify_table_index_by_sw_if_index))
@@ -121,23 +170,73 @@ ip6_add_interface_routes (vnet_main_t * vnm, u32 sw_if_index,
}
static void
-ip6_del_interface_routes (ip6_main_t * im,
+ip6_del_interface_prefix_routes (ip6_main_t * im,
+ u32 sw_if_index,
+ u32 fib_index,
+ ip6_address_t * address, u32 address_length)
+{
+ ip_lookup_main_t *lm = &im->lookup_main;
+ ip_interface_prefix_t *if_prefix;
+
+ ip_interface_prefix_key_t key = {
+ .prefix = {
+ .fp_len = address_length,
+ .fp_proto = FIB_PROTOCOL_IP6,
+ .fp_addr.ip6 = {
+ .as_u64 = {
+ address->as_u64[0] &
+ im->fib_masks[address_length].
+ as_u64[0],
+ address->
+ as_u64[1] &
+ im->fib_masks[address_length].
+ as_u64[1],
+ },
+ },
+ },
+ .sw_if_index = sw_if_index,
+ };
+
+ if_prefix = ip_get_interface_prefix (lm, &key);
+ if (!if_prefix)
+ {
+ clib_warning ("Prefix not found while deleting %U",
+ format_ip4_address_and_length, address, address_length);
+ return;
+ }
+
+ /* If not deleting last intf addr in prefix, decrement ref count & return */
+ if_prefix->ref_count -= 1;
+ if (if_prefix->ref_count > 0)
+ return;
+
+ /* length <= 30, delete glean route */
+ if (address_length <= 128)
+ {
+ /* remove glean route for prefix */
+ fib_table_entry_delete (fib_index, &key.prefix, FIB_SOURCE_INTERFACE);
+
+ }
+
+ mhash_unset (&lm->prefix_to_if_prefix_index, &key, 0 /* old_value */ );
+ pool_put (lm->if_prefix_pool, if_prefix);
+}
+
+static void
+ip6_del_interface_routes (u32 sw_if_index, ip6_main_t * im,
u32 fib_index,
ip6_address_t * address, u32 address_length)
{
fib_prefix_t pfx = {
- .fp_len = address_length,
+ .fp_len = 128,
.fp_proto = FIB_PROTOCOL_IP6,
.fp_addr.ip6 = *address,
};
- if (pfx.fp_len < 128)
- {
- fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
-
- }
+ /* delete special routes for the prefix if needed */
+ ip6_del_interface_prefix_routes (im, sw_if_index, fib_index,
+ address, address_length);
- pfx.fp_len = 128;
fib_table_entry_delete (fib_index, &pfx, FIB_SOURCE_INTERFACE);
}
@@ -278,6 +377,13 @@ ip6_add_del_interface_address (vlib_main_t * vm,
address,
address_length))
{
+ /* an intf may have >1 addr from the same prefix */
+ if ((sw_if_index == sif->sw_if_index) &&
+ (ia->address_length == address_length) &&
+ !ip6_address_is_equal (x, address))
+ continue;
+
+ /* error if the length or intf was different */
vnm->api_errno = VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
return
clib_error_create
@@ -311,7 +417,8 @@ ip6_add_del_interface_address (vlib_main_t * vm,
ip6_sw_interface_enable_disable (sw_if_index, !is_del);
if (is_del)
- ip6_del_interface_routes (im, ip6_af.fib_index, address, address_length);
+ ip6_del_interface_routes (sw_if_index,
+ im, ip6_af.fib_index, address, address_length);
else
ip6_add_interface_routes (vnm, sw_if_index,
im, ip6_af.fib_index,
@@ -361,7 +468,7 @@ ip6_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
im, fib_index,
ia);
else
- ip6_del_interface_routes (im, fib_index,
+ ip6_del_interface_routes (sw_if_index, im, fib_index,
a, ia->address_length);
}));
/* *INDENT-ON* */
diff --git a/src/vnet/ip/lookup.c b/src/vnet/ip/lookup.c
index 8c89ed4f490..60cedac57d8 100644
--- a/src/vnet/ip/lookup.c
+++ b/src/vnet/ip/lookup.c
@@ -207,6 +207,8 @@ ip_lookup_init (ip_lookup_main_t * lm, u32 is_ip6)
lm->fib_result_n_bytes = sizeof (uword);
lm->is_ip6 = is_ip6;
+ mhash_init (&lm->prefix_to_if_prefix_index, sizeof (uword),
+ sizeof (ip_interface_prefix_key_t));
if (is_ip6)
{
lm->format_address_and_length = format_ip6_address_and_length;
diff --git a/src/vnet/ip/lookup.h b/src/vnet/ip/lookup.h
index 4c598e3a460..6340e57e095 100644
--- a/src/vnet/ip/lookup.h
+++ b/src/vnet/ip/lookup.h
@@ -86,6 +86,24 @@ typedef u32 flow_hash_config_t;
/* An all zeros address */
extern const ip46_address_t zero_addr;
+typedef struct
+{
+ fib_prefix_t prefix;
+
+ u32 sw_if_index;
+} ip_interface_prefix_key_t;
+
+typedef struct
+{
+ /* key - prefix and sw_if_index */
+ ip_interface_prefix_key_t key;
+
+ /* number of addresses in this prefix on the interface */
+ u16 ref_count;
+
+ /* index of the interface address used as a default source address */
+ u32 src_ia_index;
+} ip_interface_prefix_t;
typedef struct
{
@@ -131,6 +149,12 @@ typedef struct ip_lookup_main_t
~0 means this interface has no address. */
u32 *if_address_pool_index_by_sw_if_index;
+ /** Pool of prefixes containing addresses assigned to interfaces */
+ ip_interface_prefix_t *if_prefix_pool;
+
+ /** Hash table mapping prefix to index in interface prefix pool */
+ mhash_t prefix_to_if_prefix_index;
+
/** First table index to use for this interface, ~0 => none */
u32 *classify_table_index_by_sw_if_index;
@@ -178,6 +202,13 @@ ip_interface_address_get_address (ip_lookup_main_t * lm,
return mhash_key_to_mem (&lm->address_to_if_address_index, a->address_key);
}
+always_inline ip_interface_prefix_t *
+ip_get_interface_prefix (ip_lookup_main_t * lm, ip_interface_prefix_key_t * k)
+{
+ uword *p = mhash_get (&lm->prefix_to_if_prefix_index, k);
+ return p ? pool_elt_at_index (lm->if_prefix_pool, p[0]) : 0;
+}
+
/* *INDENT-OFF* */
#define foreach_ip_interface_address(lm,a,sw_if_index,loop,body) \
do { \
diff --git a/test/test_ip4.py b/test/test_ip4.py
index a6920f8dba5..0923771200e 100644
--- a/test/test_ip4.py
+++ b/test/test_ip4.py
@@ -15,7 +15,9 @@ from framework import VppTestCase, VppTestRunner
from util import ppp
from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpMRoute, \
VppMRoutePath, MRouteItfFlags, MRouteEntryFlags, VppMplsIpBind, \
- VppMplsTable, VppIpTable, FibPathType, find_route
+ VppMplsTable, VppIpTable, FibPathType, find_route, \
+ VppIpInterfaceAddress
+from vpp_ip import VppIpAddress
from vpp_sub_interface import VppSubInterface, VppDot1QSubint, VppDot1ADSubint
from vpp_papi import VppEnum
@@ -210,19 +212,19 @@ class TestIPv4(VppTestCase):
self.verify_capture(i, pkts)
-class TestIPV4IfAddrRoute(VppTestCase):
+class TestIPv4IfAddrRoute(VppTestCase):
""" IPv4 Interface Addr Route Test Case """
@classmethod
def setUpClass(cls):
- super(TestIPV4IfAddrRoute, cls).setUpClass()
+ super(TestIPv4IfAddrRoute, cls).setUpClass()
@classmethod
def tearDownClass(cls):
- super(TestIPV4IfAddrRoute, cls).tearDownClass()
+ super(TestIPv4IfAddrRoute, cls).tearDownClass()
def setUp(self):
- super(TestIPV4IfAddrRoute, self).setUp()
+ super(TestIPv4IfAddrRoute, self).setUp()
# create 1 pg interface
self.create_pg_interfaces(range(1))
@@ -233,11 +235,62 @@ class TestIPV4IfAddrRoute(VppTestCase):
i.resolve_arp()
def tearDown(self):
- super(TestIPV4IfAddrRoute, self).tearDown()
+ super(TestIPv4IfAddrRoute, self).tearDown()
for i in self.pg_interfaces:
i.unconfig_ip4()
i.admin_down()
+ def test_ipv4_ifaddrs_same_prefix(self):
+ """ IPv4 Interface Addresses Same Prefix test
+
+ Test scenario:
+
+ - Verify no route in FIB for prefix 10.10.10.0/24
+ - Configure IPv4 address 10.10.10.10/24 on an interface
+ - Verify route in FIB for prefix 10.10.10.0/24
+ - Configure IPv4 address 10.10.10.20/24 on an interface
+ - Delete 10.10.10.10/24 from interface
+ - Verify route in FIB for prefix 10.10.10.0/24
+ - Delete 10.10.10.20/24 from interface
+ - Verify no route in FIB for prefix 10.10.10.0/24
+ """
+
+ # create two addresses, verify route not present
+ if_addr1 = VppIpInterfaceAddress(self, self.pg0,
+ VppIpAddress("10.10.10.10"), 24)
+ if_addr2 = VppIpInterfaceAddress(self, self.pg0,
+ VppIpAddress("10.10.10.20"), 24)
+ self.assertFalse(if_addr1.query_vpp_config()) # 10.10.10.0/24
+ self.assertFalse(find_route(self, "10.10.10.10", 32))
+ self.assertFalse(find_route(self, "10.10.10.20", 32))
+ self.assertFalse(find_route(self, "10.10.10.255", 32))
+ self.assertFalse(find_route(self, "10.10.10.0", 32))
+
+ # configure first address, verify route present
+ if_addr1.add_vpp_config()
+ self.assertTrue(if_addr1.query_vpp_config()) # 10.10.10.0/24
+ self.assertTrue(find_route(self, "10.10.10.10", 32))
+ self.assertFalse(find_route(self, "10.10.10.20", 32))
+ self.assertTrue(find_route(self, "10.10.10.255", 32))
+ self.assertTrue(find_route(self, "10.10.10.0", 32))
+
+ # configure second address, delete first, verify route not removed
+ if_addr2.add_vpp_config()
+ if_addr1.remove_vpp_config()
+ self.assertTrue(if_addr1.query_vpp_config()) # 10.10.10.0/24
+ self.assertFalse(find_route(self, "10.10.10.10", 32))
+ self.assertTrue(find_route(self, "10.10.10.20", 32))
+ self.assertTrue(find_route(self, "10.10.10.255", 32))
+ self.assertTrue(find_route(self, "10.10.10.0", 32))
+
+ # delete second address, verify route removed
+ if_addr2.remove_vpp_config()
+ self.assertFalse(if_addr1.query_vpp_config()) # 10.10.10.0/24
+ self.assertFalse(find_route(self, "10.10.10.10", 32))
+ self.assertFalse(find_route(self, "10.10.10.20", 32))
+ self.assertFalse(find_route(self, "10.10.10.255", 32))
+ self.assertFalse(find_route(self, "10.10.10.0", 32))
+
def test_ipv4_ifaddr_route(self):
""" IPv4 Interface Address Route test
diff --git a/test/test_ip6.py b/test/test_ip6.py
index f8295513516..f2c4c00424e 100644
--- a/test/test_ip6.py
+++ b/test/test_ip6.py
@@ -20,10 +20,11 @@ from six import moves
from framework import VppTestCase, VppTestRunner
from util import ppp, ip6_normalize, mk_ll_addr
-from vpp_ip import DpoProto
+from vpp_ip import DpoProto, VppIpAddress
from vpp_ip_route import VppIpRoute, VppRoutePath, find_route, VppIpMRoute, \
VppMRoutePath, MRouteItfFlags, MRouteEntryFlags, VppMplsIpBind, \
- VppMplsRoute, VppMplsTable, VppIpTable, FibPathType
+ VppMplsRoute, VppMplsTable, VppIpTable, FibPathType, \
+ VppIpInterfaceAddress
from vpp_neighbor import find_nbr, VppNeighbor
from vpp_pg_interface import is_ipv6_misc
from vpp_sub_interface import VppSubInterface, VppDot1QSubint
@@ -935,6 +936,80 @@ class TestIPv6(TestIPv6ND):
self.pg0.ip6_ra_config(no=1, suppress=1, send_unicast=0)
+class TestIPv6IfAddrRoute(VppTestCase):
+ """ IPv6 Interface Addr Route Test Case """
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestIPv6IfAddrRoute, cls).setUpClass()
+
+ @classmethod
+ def tearDownClass(cls):
+ super(TestIPv6IfAddrRoute, cls).tearDownClass()
+
+ def setUp(self):
+ super(TestIPv6IfAddrRoute, self).setUp()
+
+ # create 1 pg interface
+ self.create_pg_interfaces(range(1))
+
+ for i in self.pg_interfaces:
+ i.admin_up()
+ i.config_ip6()
+ i.resolve_ndp()
+
+ def tearDown(self):
+ super(TestIPv6IfAddrRoute, self).tearDown()
+ for i in self.pg_interfaces:
+ i.unconfig_ip6()
+ i.admin_down()
+
+ def test_ipv6_ifaddrs_same_prefix(self):
+ """ IPv6 Interface Addresses Same Prefix test
+
+ Test scenario:
+
+ - Verify no route in FIB for prefix 2001:10::/64
+ - Configure IPv4 address 2001:10::10/64 on an interface
+ - Verify route in FIB for prefix 2001:10::/64
+ - Configure IPv4 address 2001:10::20/64 on an interface
+ - Delete 2001:10::10/64 from interface
+ - Verify route in FIB for prefix 2001:10::/64
+ - Delete 2001:10::20/64 from interface
+ - Verify no route in FIB for prefix 2001:10::/64
+ """
+
+ addr1 = "2001:10::10"
+ addr2 = "2001:10::20"
+
+ if_addr1 = VppIpInterfaceAddress(self, self.pg0,
+ VppIpAddress(addr1), 64)
+ if_addr2 = VppIpInterfaceAddress(self, self.pg0,
+ VppIpAddress(addr2), 64)
+ self.assertFalse(if_addr1.query_vpp_config()) # 2001:10::/64
+ self.assertFalse(find_route(self, addr1, 128))
+ self.assertFalse(find_route(self, addr2, 128))
+
+ # configure first address, verify route present
+ if_addr1.add_vpp_config()
+ self.assertTrue(if_addr1.query_vpp_config()) # 2001:10::/64
+ self.assertTrue(find_route(self, addr1, 128))
+ self.assertFalse(find_route(self, addr2, 128))
+
+ # configure second address, delete first, verify route not removed
+ if_addr2.add_vpp_config()
+ if_addr1.remove_vpp_config()
+ self.assertTrue(if_addr1.query_vpp_config()) # 2001:10::/64
+ self.assertFalse(find_route(self, addr1, 128))
+ self.assertTrue(find_route(self, addr2, 128))
+
+ # delete second address, verify route removed
+ if_addr2.remove_vpp_config()
+ self.assertFalse(if_addr1.query_vpp_config()) # 2001:10::/64
+ self.assertFalse(find_route(self, addr1, 128))
+ self.assertFalse(find_route(self, addr2, 128))
+
+
class TestICMPv6Echo(VppTestCase):
""" ICMPv6 Echo Test Case """