fib: make mfib optional

In some cases we do not need multicast support. Making it optional helps
scaling to high number of VRFs, by reducing the control plane operations
and memory consumption.

Type: improvement

Change-Id: Ib34ed3fe2806e2f4624981da4e4a3c49c69f70be
Signed-off-by: Benoît Ganne <bganne@cisco.com>
This commit is contained in:
Benoît Ganne 2024-04-16 09:36:05 +02:00 committed by Neale Ranns
parent caaa633223
commit ff570d3d07
14 changed files with 167 additions and 46 deletions

View File

@ -133,7 +133,8 @@ session_create_lookpback (u32 table_id, u32 * sw_if_index,
if (table_id != 0)
{
ip_table_create (FIB_PROTOCOL_IP4, table_id, 0, 0);
ip_table_create (FIB_PROTOCOL_IP4, table_id, 0 /* is_api */,
1 /* create_mfib */, 0);
ip_table_bind (FIB_PROTOCOL_IP4, *sw_if_index, table_id);
}

View File

@ -579,7 +579,7 @@ ip_table_bind (fib_protocol_t fproto, u32 sw_if_index, u32 table_id)
fib_index = fib_table_find (fproto, table_id);
mfib_index = mfib_table_find (fproto, table_id);
if (~0 == fib_index || ~0 == mfib_index)
if (~0 == fib_index)
{
return (VNET_API_ERROR_NO_SUCH_FIB);
}
@ -601,7 +601,8 @@ ip_table_bind (fib_protocol_t fproto, u32 sw_if_index, u32 table_id)
/* clang-format on */
fib_table_bind (fproto, sw_if_index, fib_index);
mfib_table_bind (fproto, sw_if_index, mfib_index);
if (mfib_index != ~0)
mfib_table_bind (fproto, sw_if_index, mfib_index);
return (0);
}

View File

@ -57,6 +57,23 @@ autoreply define ip_table_add_del
vl_api_ip_table_t table;
};
/** \brief Add / del table request - version 2
A table can be added multiple times, but need be deleted only once.
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@param table - the FIB table to add or del
@param create_mfib - whether to create mfib or not
@param is_add - add or del
*/
autoreply define ip_table_add_del_v2
{
u32 client_index;
u32 context;
vl_api_ip_table_t table;
bool create_mfib [default=true];
bool is_add [default=true];
};
/** \brief Allocate an unused table
A table can be added multiple times.
If a large number of tables are in use (millions), this API might

View File

@ -262,7 +262,7 @@ extern vlib_node_registration_t ip4_inacl_node;
extern vlib_node_registration_t ip6_inacl_node;
void ip_table_create (fib_protocol_t fproto, u32 table_id, u8 is_api,
const u8 * name);
u8 create_mfib, const u8 *name);
void ip_table_delete (fib_protocol_t fproto, u32 table_id, u8 is_api);

View File

@ -636,7 +636,8 @@ vl_api_ip_table_add_del_t_handler (vl_api_ip_table_add_del_t * mp)
if (mp->is_add)
{
ip_table_create (fproto, table_id, 1, mp->table.name);
ip_table_create (fproto, table_id, 1 /* is_api */, 1 /* create_mfib */,
mp->table.name);
}
else
{
@ -646,6 +647,28 @@ vl_api_ip_table_add_del_t_handler (vl_api_ip_table_add_del_t * mp)
REPLY_MACRO (VL_API_IP_TABLE_ADD_DEL_REPLY);
}
void
vl_api_ip_table_add_del_v2_t_handler (vl_api_ip_table_add_del_v2_t *mp)
{
vl_api_ip_table_add_del_v2_reply_t *rmp;
fib_protocol_t fproto =
(mp->table.is_ip6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
u32 table_id = ntohl (mp->table.table_id);
int rv = 0;
if (mp->is_add)
{
ip_table_create (fproto, table_id, 1 /* is_api */, mp->create_mfib,
mp->table.name);
}
else
{
ip_table_delete (fproto, table_id, 1);
}
REPLY_MACRO (VL_API_IP_TABLE_ADD_DEL_V2_REPLY);
}
void
vl_api_ip_table_allocate_t_handler (vl_api_ip_table_allocate_t *mp)
{
@ -661,7 +684,8 @@ vl_api_ip_table_allocate_t_handler (vl_api_ip_table_allocate_t *mp)
if (~0 == table_id)
rv = VNET_API_ERROR_EAGAIN;
else
ip_table_create (fproto, table_id, 1, mp->table.name);
ip_table_create (fproto, table_id, 1 /* is_api */, 1 /* create_mfib */,
mp->table.name);
REPLY_MACRO2 (VL_API_IP_TABLE_ALLOCATE_REPLY, {
clib_memcpy_fast (&rmp->table, &mp->table, sizeof (mp->table));
@ -915,8 +939,8 @@ vl_api_ip_route_lookup_v2_t_handler (vl_api_ip_route_lookup_v2_t *mp)
}
void
ip_table_create (fib_protocol_t fproto,
u32 table_id, u8 is_api, const u8 * name)
ip_table_create (fib_protocol_t fproto, u32 table_id, u8 is_api,
u8 create_mfib, const u8 *name)
{
u32 fib_index, mfib_index;
vnet_main_t *vnm = vnet_get_main ();
@ -936,16 +960,23 @@ ip_table_create (fib_protocol_t fproto,
* their own unicast tables.
*/
fib_index = fib_table_find (fproto, table_id);
mfib_index = mfib_table_find (fproto, table_id);
/*
* Always try to re-lock in case the fib was deleted by an API call
* but was not yet freed because some other locks were held
*/
fib_table_find_or_create_and_lock_w_name (
fproto, table_id, (is_api ? FIB_SOURCE_API : FIB_SOURCE_CLI), name);
mfib_table_find_or_create_and_lock_w_name (
fproto, table_id, (is_api ? MFIB_SOURCE_API : MFIB_SOURCE_CLI), name);
if (create_mfib)
{
/* same for mfib, if needs be */
mfib_index = mfib_table_find (fproto, table_id);
mfib_table_find_or_create_and_lock_w_name (
fproto, table_id, (is_api ? MFIB_SOURCE_API : MFIB_SOURCE_CLI),
name);
}
else
mfib_index = 0;
if ((~0 == fib_index) || (~0 == mfib_index))
call_elf_section_ip_table_callbacks (vnm, table_id, 1 /* is_add */ ,
@ -1655,9 +1686,10 @@ vl_api_ip_table_replace_begin_t_handler (vl_api_ip_table_replace_begin_t * mp)
rv = VNET_API_ERROR_NO_SUCH_FIB;
else
{
u32 mfib_index = mfib_table_find (fproto, ntohl (mp->table.table_id));
fib_table_mark (fib_index, fproto, FIB_SOURCE_API);
mfib_table_mark (mfib_table_find (fproto, ntohl (mp->table.table_id)),
fproto, MFIB_SOURCE_API);
if (mfib_index != INDEX_INVALID)
mfib_table_mark (mfib_index, fproto, MFIB_SOURCE_API);
}
REPLY_MACRO (VL_API_IP_TABLE_REPLACE_BEGIN_REPLY);
}
@ -1677,10 +1709,10 @@ vl_api_ip_table_replace_end_t_handler (vl_api_ip_table_replace_end_t * mp)
rv = VNET_API_ERROR_NO_SUCH_FIB;
else
{
u32 mfib_index = mfib_table_find (fproto, ntohl (mp->table.table_id));
fib_table_sweep (fib_index, fproto, FIB_SOURCE_API);
mfib_table_sweep (mfib_table_find
(fproto, ntohl (mp->table.table_id)), fproto,
MFIB_SOURCE_API);
if (mfib_index != INDEX_INVALID)
mfib_table_sweep (mfib_index, fproto, MFIB_SOURCE_API);
}
REPLY_MACRO (VL_API_IP_TABLE_REPLACE_END_REPLY);
}
@ -1703,6 +1735,7 @@ vl_api_ip_table_flush_t_handler (vl_api_ip_table_flush_t * mp)
vnet_main_t *vnm = vnet_get_main ();
vnet_interface_main_t *im = &vnm->interface_main;
vnet_sw_interface_t *si;
u32 mfib_index;
/* Shut down interfaces in this FIB / clean out intfc routes */
pool_foreach (si, im->sw_interfaces)
@ -1717,8 +1750,10 @@ vl_api_ip_table_flush_t_handler (vl_api_ip_table_flush_t * mp)
}
fib_table_flush (fib_index, fproto, FIB_SOURCE_API);
mfib_table_flush (mfib_table_find (fproto, ntohl (mp->table.table_id)),
fproto, MFIB_SOURCE_API);
mfib_index = mfib_table_find (fproto, ntohl (mp->table.table_id));
if (mfib_index != INDEX_INVALID)
mfib_table_flush (mfib_index, fproto, MFIB_SOURCE_API);
}
REPLY_MACRO (VL_API_IP_TABLE_FLUSH_REPLY);

View File

@ -463,6 +463,60 @@ api_ip_table_add_del (vat_main_t *vam)
return ret;
}
static int
api_ip_table_add_del_v2 (vat_main_t *vam)
{
unformat_input_t *i = vam->input;
vl_api_ip_table_add_del_v2_t *mp;
u8 create_mfib = 1;
u32 table_id = ~0;
u8 is_ipv6 = 0;
u8 is_add = 1;
int ret = 0;
/* Parse args required to build the message */
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
if (unformat (i, "ipv6"))
is_ipv6 = 1;
else if (unformat (i, "del"))
is_add = 0;
else if (unformat (i, "add"))
is_add = 1;
else if (unformat (i, "table %d", &table_id))
;
else if (unformat (i, "no-mfib"))
create_mfib = 0;
else
{
clib_warning ("parse error '%U'", format_unformat_error, i);
return -99;
}
}
if (~0 == table_id)
{
errmsg ("missing table-ID");
return -99;
}
/* Construct the API message */
M (IP_TABLE_ADD_DEL_V2, mp);
mp->table.table_id = ntohl (table_id);
mp->table.is_ip6 = is_ipv6;
mp->is_add = is_add;
mp->create_mfib = create_mfib;
/* send it... */
S (mp);
/* Wait for a reply... */
W (ret);
return ret;
}
static int
api_ip_table_replace_begin (vat_main_t *vam)
{

View File

@ -419,10 +419,12 @@ vnet_ip_table_cmd (vlib_main_t * vm,
unformat_input_t _line_input, *line_input = &_line_input;
clib_error_t *error = NULL;
u32 table_id, is_add;
u8 create_mfib;
u8 *name = NULL;
is_add = 1;
table_id = ~0;
create_mfib = 1;
/* Get a line of input. */
if (!unformat_user (main_input, unformat_line_input, line_input))
@ -438,6 +440,8 @@ vnet_ip_table_cmd (vlib_main_t * vm,
is_add = 1;
else if (unformat (line_input, "name %s", &name))
;
else if (unformat (line_input, "no-mfib"))
create_mfib = 0;
else
{
error = unformat_parse_error (line_input);
@ -459,7 +463,8 @@ vnet_ip_table_cmd (vlib_main_t * vm,
table_id = ip_table_get_unused_id (fproto);
vlib_cli_output (vm, "%u\n", table_id);
}
ip_table_create (fproto, table_id, 0, name);
ip_table_create (fproto, table_id, 0 /* is_api */, create_mfib,
name);
}
else
{

View File

@ -195,7 +195,7 @@ class TestIp4VrfMultiInst(VppTestCase):
for i in range(count):
vrf_id = i + start
self.vapi.ip_table_add_del(is_add=1, table={"table_id": vrf_id})
self.vapi.ip_table_add_del_v2(is_add=1, table={"table_id": vrf_id})
self.logger.info("IPv4 VRF ID %d created" % vrf_id)
if vrf_id not in self.vrf_list:
self.vrf_list.append(vrf_id)
@ -249,7 +249,7 @@ class TestIp4VrfMultiInst(VppTestCase):
self.logger.info("IPv4 VRF ID %d reset finished" % vrf_id)
self.logger.debug(self.vapi.ppcli("show ip fib"))
self.logger.debug(self.vapi.ppcli("show ip neighbors"))
self.vapi.ip_table_add_del(is_add=0, table={"table_id": vrf_id})
self.vapi.ip_table_add_del_v2(is_add=0, table={"table_id": vrf_id})
def create_stream(self, src_if, packet_sizes):
"""

View File

@ -213,7 +213,7 @@ class TestIP6VrfMultiInst(VppTestCase):
"""
for i in range(count):
vrf_id = i + start
self.vapi.ip_table_add_del(
self.vapi.ip_table_add_del_v2(
is_add=1, table={"table_id": vrf_id, "is_ip6": 1}
)
self.logger.info("IPv6 VRF ID %d created" % vrf_id)
@ -276,7 +276,7 @@ class TestIP6VrfMultiInst(VppTestCase):
self.vrf_list.remove(vrf_id)
if vrf_id in self.vrf_reset_list:
self.vrf_reset_list.remove(vrf_id)
self.vapi.ip_table_add_del(is_add=0, table={"table_id": vrf_id, "is_ip6": 1})
self.vapi.ip_table_add_del_v2(is_add=0, table={"table_id": vrf_id, "is_ip6": 1})
def create_stream(self, src_if, packet_sizes):
"""

View File

@ -90,7 +90,7 @@ class TestNAT44ED(VppTestCase):
@classmethod
def create_and_add_ip4_table(cls, i, table_id=0):
cls.vapi.ip_table_add_del(is_add=1, table={"table_id": table_id})
cls.vapi.ip_table_add_del_v2(is_add=1, table={"table_id": table_id})
i.set_table_ip4(table_id)
@classmethod
@ -172,7 +172,7 @@ class TestNAT44ED(VppTestCase):
cls.configure_ip4_interface(i, hosts=3)
# test specific (test-multiple-vrf)
cls.vapi.ip_table_add_del(is_add=1, table={"table_id": 1})
cls.vapi.ip_table_add_del_v2(is_add=1, table={"table_id": 1})
# test specific (test-one-armed-nat44-static)
cls.pg4.generate_remote_hosts(2)
@ -4397,8 +4397,8 @@ class TestNAT44EDMW(TestNAT44ED):
self.pg7.unconfig()
self.pg8.unconfig()
self.vapi.ip_table_add_del(is_add=0, table={"table_id": vrf_id_in})
self.vapi.ip_table_add_del(is_add=0, table={"table_id": vrf_id_out})
self.vapi.ip_table_add_del_v2(is_add=0, table={"table_id": vrf_id_in})
self.vapi.ip_table_add_del_v2(is_add=0, table={"table_id": vrf_id_out})
def test_dynamic_output_feature_vrf(self):
"""NAT44ED dynamic translation test: output-feature, VRF"""
@ -4467,7 +4467,7 @@ class TestNAT44EDMW(TestNAT44ED):
self.pg7.unconfig()
self.pg8.unconfig()
self.vapi.ip_table_add_del(is_add=0, table={"table_id": new_vrf_id})
self.vapi.ip_table_add_del_v2(is_add=0, table={"table_id": new_vrf_id})
def test_next_src_nat(self):
"""NAT44ED On way back forward packet to nat44-in2out node."""

View File

@ -953,8 +953,8 @@ class TestNAT44EI(MethodHolder):
cls.pg1.configure_ipv4_neighbors()
cls.overlapping_interfaces = list(list(cls.pg_interfaces[4:7]))
cls.vapi.ip_table_add_del(is_add=1, table={"table_id": 10})
cls.vapi.ip_table_add_del(is_add=1, table={"table_id": 20})
cls.vapi.ip_table_add_del_v2(is_add=1, table={"table_id": 10})
cls.vapi.ip_table_add_del_v2(is_add=1, table={"table_id": 20})
cls.pg4._local_ip4 = "172.16.255.1"
cls.pg4._remote_hosts[0]._ip4 = "172.16.255.2"
@ -2682,8 +2682,8 @@ class TestNAT44EI(MethodHolder):
self.pg0.unconfig_ip4()
self.pg1.unconfig_ip4()
self.vapi.ip_table_add_del(is_add=1, table={"table_id": vrf_id1})
self.vapi.ip_table_add_del(is_add=1, table={"table_id": vrf_id2})
self.vapi.ip_table_add_del_v2(is_add=1, table={"table_id": vrf_id1})
self.vapi.ip_table_add_del_v2(is_add=1, table={"table_id": vrf_id2})
self.pg0.set_table_ip4(vrf_id1)
self.pg1.set_table_ip4(vrf_id2)
self.pg0.config_ip4()
@ -2730,8 +2730,8 @@ class TestNAT44EI(MethodHolder):
self.pg1.config_ip4()
self.pg0.resolve_arp()
self.pg1.resolve_arp()
self.vapi.ip_table_add_del(is_add=0, table={"table_id": vrf_id1})
self.vapi.ip_table_add_del(is_add=0, table={"table_id": vrf_id2})
self.vapi.ip_table_add_del_v2(is_add=0, table={"table_id": vrf_id1})
self.vapi.ip_table_add_del_v2(is_add=0, table={"table_id": vrf_id2})
def test_vrf_feature_independent(self):
"""NAT44EI tenant VRF independent address pool mode"""
@ -3468,8 +3468,8 @@ class TestNAT44EI(MethodHolder):
self.pg1.unconfig_ip4()
self.pg2.unconfig_ip4()
self.vapi.ip_table_add_del(is_add=1, table={"table_id": vrf_id1})
self.vapi.ip_table_add_del(is_add=1, table={"table_id": vrf_id2})
self.vapi.ip_table_add_del_v2(is_add=1, table={"table_id": vrf_id1})
self.vapi.ip_table_add_del_v2(is_add=1, table={"table_id": vrf_id2})
self.pg1.set_table_ip4(vrf_id1)
self.pg2.set_table_ip4(vrf_id2)
self.pg1.config_ip4()
@ -4302,8 +4302,8 @@ class TestNAT44EIMW(MethodHolder):
cls.pg1.configure_ipv4_neighbors()
cls.overlapping_interfaces = list(list(cls.pg_interfaces[4:7]))
cls.vapi.ip_table_add_del(is_add=1, table={"table_id": 10})
cls.vapi.ip_table_add_del(is_add=1, table={"table_id": 20})
cls.vapi.ip_table_add_del_v2(is_add=1, table={"table_id": 10})
cls.vapi.ip_table_add_del_v2(is_add=1, table={"table_id": 20})
cls.pg4._local_ip4 = "172.16.255.1"
cls.pg4._remote_hosts[0]._ip4 = "172.16.255.2"

View File

@ -74,7 +74,7 @@ class TestNAT64(VppTestCase):
cls.ip6_interfaces.append(cls.pg_interfaces[2])
cls.ip4_interfaces = list(cls.pg_interfaces[1:2])
cls.vapi.ip_table_add_del(
cls.vapi.ip_table_add_del_v2(
is_add=1, table={"table_id": cls.vrf1_id, "is_ip6": 1}
)

View File

@ -489,11 +489,15 @@ class TestVPPInterfacesQemu:
except Exception:
pass
try:
self.vapi.ip_table_add_del(is_add=0, table={"table_id": layer3["ip4_vrf"]})
self.vapi.ip_table_add_del_v2(
is_add=0, table={"table_id": layer3["ip4_vrf"]}
)
except Exception:
pass
try:
self.vapi.ip_table_add_del(is_add=0, table={"table_id": layer3["ip6_vrf"]})
self.vapi.ip_table_add_del_v2(
is_add=0, table={"table_id": layer3["ip6_vrf"]}
)
except Exception:
pass
try:
@ -693,7 +697,7 @@ class TestVPPInterfacesQemu:
vrf_id -- vrf_id
"""
is_ipv6 = 0 if ip_version == 4 else 1
self.vapi.ip_table_add_del(
self.vapi.ip_table_add_del_v2(
is_add=1, table={"table_id": vrf_id, "is_ip6": is_ipv6}
)
for sw_if_index, ip_prefix in if_idx_ip_prefixes:

View File

@ -169,16 +169,20 @@ def fib_interface_ip_prefix(test, addr, len, sw_if_index):
class VppIpTable(VppObject):
def __init__(self, test, table_id, is_ip6=0, register=True, name=""):
def __init__(
self, test, table_id, is_ip6=0, register=True, name="", create_mfib=True
):
self._test = test
self.name = name
self.table_id = table_id
self.is_ip6 = is_ip6
self.register = register
self.create_mfib = True
def add_vpp_config(self):
self._test.vapi.ip_table_add_del(
self._test.vapi.ip_table_add_del_v2(
is_add=1,
create_mfib=self.create_mfib,
table={"is_ip6": self.is_ip6, "table_id": self.table_id, "name": self.name},
)
if self.register:
@ -186,7 +190,7 @@ class VppIpTable(VppObject):
return self
def remove_vpp_config(self):
self._test.vapi.ip_table_add_del(
self._test.vapi.ip_table_add_del_v2(
is_add=0, table={"is_ip6": self.is_ip6, "table_id": self.table_id}
)