summaryrefslogtreecommitdiffstats
path: root/src/vnet
diff options
context:
space:
mode:
authorMatthew Smith <mgsmith@netgate.com>2019-08-07 11:46:30 -0500
committerAndrew Yourtchenko <ayourtch@gmail.com>2019-09-18 21:53:10 +0000
commitda900b25c8fa47c70b4dcba7f2cb68716dcfad46 (patch)
tree343eb581de97718e26ba64926ef1fe95e5c56a42 /src/vnet
parentf4dcae4164f93dac80d4af19af0ee20e712ec673 (diff)
ip: allow addrs from the same prefix on intf
Type: feature Adding a prefix to an interface was not permitted if it overlapped with another prefix on an interface which used the same FIB. Loosen the restriction. Allow 2 or more addresses from the same prefix on a single interface. Reference count the prefix to figure out when a glean/connected route for the prefix needs to be added or removed. Added unit tests to check that the route is only removed when all addresses in the prefix are removed from the interface. Change-Id: I1a962ecb5e1ee65fc6d41f98a4cc097a51a55321 Signed-off-by: Matthew Smith <mgsmith@netgate.com> (cherry picked from commit 6c92f5babdc3c52cf343509fc9cf9d8a9a3df390)
Diffstat (limited to 'src/vnet')
-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
4 files changed, 396 insertions, 101 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 { \