fib: make mfib optional 46/40746/9
authorBenoît Ganne <[email protected]>
Tue, 16 Apr 2024 07:36:05 +0000 (09:36 +0200)
committerNeale Ranns <[email protected]>
Fri, 12 Jul 2024 03:09:22 +0000 (03:09 +0000)
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 <[email protected]>
14 files changed:
src/plugins/unittest/session_test.c
src/vnet/interface_api.c
src/vnet/ip/ip.api
src/vnet/ip/ip.h
src/vnet/ip/ip_api.c
src/vnet/ip/ip_test.c
src/vnet/ip/lookup.c
test/test_ip4_vrf_multi_instance.py
test/test_ip6_vrf_multi_instance.py
test/test_nat44_ed.py
test/test_nat44_ei.py
test/test_nat64.py
test/vm_vpp_interfaces.py
test/vpp_ip_route.py

index 12d000b..6d28b2d 100644 (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);
     }
 
index c727e51..69bf4b7 100644 (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);
 }
index 967f56c..fc7d758 100644 (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
index 9ebefa0..084243d 100644 (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);
 
index 6dd9514..5ced88f 100644 (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);
index 727afba..0d1c710 100644 (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)
 {
index c0fa430..b978bd7 100644 (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
            {
index cbda790..318a4a8 100644 (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):
         """
index da3de8e..26519b1 100644 (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):
         """
index d3d6d07..6eb4c66 100644 (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."""
index ae9194b..4748744 100644 (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"
index 7333181..c327965 100644 (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}
         )
 
index 85417dc..0f1e33d 100644 (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:
index d36c567..31aab3a 100644 (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}
         )