nat: disable nat44-ed/ei features on interface deletion 46/37746/2
authorVladislav Grishenko <themiron@yandex-team.ru>
Sun, 4 Dec 2022 10:02:03 +0000 (15:02 +0500)
committerMatthew Smith <mgsmith@netgate.com>
Thu, 15 Dec 2022 13:19:57 +0000 (13:19 +0000)
After deleting a sw interface with nat44 features, the next created
sw interface will get the same sw_index reused and therefore will
erroneously have the same nat features enabled.

Type: fix
Change-Id: I1d84f842ab7ab2a757668ae1a111efe67e1e924d
Signed-off-by: Vladislav Grishenko <themiron@yandex-team.ru>
src/plugins/nat/nat44-ed/nat44_ed.c
src/plugins/nat/nat44-ei/nat44_ei.c
test/test_nat44_ed.py
test/test_nat44_ei.py

index 348fff2..82b9de1 100644 (file)
@@ -2587,6 +2587,55 @@ nat44_ed_del_output_interfaces ()
   return error;
 }
 
+static clib_error_t *
+nat44_ed_sw_interface_add_del (vnet_main_t *vnm, u32 sw_if_index, u32 is_add)
+{
+  snat_main_t *sm = &snat_main;
+  snat_interface_t *i;
+  int error = 0;
+
+  if (is_add)
+    return 0;
+
+  if (!sm->enabled)
+    return 0;
+
+  i = nat44_ed_get_interface (sm->interfaces, sw_if_index);
+  if (i)
+    {
+      bool is_inside = nat44_ed_is_interface_inside (i);
+      bool is_outside = nat44_ed_is_interface_outside (i);
+
+      if (is_inside)
+       {
+         error |= nat44_ed_del_interface (sw_if_index, 1);
+       }
+      if (is_outside)
+       {
+         error |= nat44_ed_del_interface (sw_if_index, 0);
+       }
+
+      if (error)
+       {
+         nat_log_err ("error occurred while removing interface");
+       }
+    }
+
+  i = nat44_ed_get_interface (sm->output_feature_interfaces, sw_if_index);
+  if (i)
+    {
+      error = nat44_ed_del_output_interface (sw_if_index);
+      if (error)
+       {
+         nat_log_err ("error occurred while removing output interface");
+       }
+    }
+
+  return 0;
+}
+
+VNET_SW_INTERFACE_ADD_DEL_FUNCTION (nat44_ed_sw_interface_add_del);
+
 int
 nat44_ed_del_static_mappings ()
 {
index 171ca7d..e16625a 100644 (file)
@@ -1183,6 +1183,55 @@ nat44_ei_del_output_interfaces ()
   return error;
 }
 
+static clib_error_t *
+nat44_ei_sw_interface_add_del (vnet_main_t *vnm, u32 sw_if_index, u32 is_add)
+{
+  nat44_ei_main_t *nm = &nat44_ei_main;
+  nat44_ei_interface_t *i;
+  int error = 0;
+
+  if (is_add)
+    return 0;
+
+  if (!nm->enabled)
+    return 0;
+
+  i = nat44_ei_get_interface (nm->interfaces, sw_if_index);
+  if (i)
+    {
+      bool is_inside = nat44_ei_interface_is_inside (i);
+      bool is_outside = nat44_ei_interface_is_outside (i);
+
+      if (is_inside)
+       {
+         error |= nat44_ei_del_interface (sw_if_index, 1);
+       }
+      if (is_outside)
+       {
+         error |= nat44_ei_del_interface (sw_if_index, 0);
+       }
+
+      if (error)
+       {
+         nat44_ei_log_err ("error occurred while removing interface");
+       }
+    }
+
+  i = nat44_ei_get_interface (nm->output_feature_interfaces, sw_if_index);
+  if (i)
+    {
+      error = nat44_ei_del_output_interface (sw_if_index);
+      if (error)
+       {
+         nat44_ei_log_err ("error occurred while removing output interface");
+       }
+    }
+
+  return 0;
+}
+
+VNET_SW_INTERFACE_ADD_DEL_FUNCTION (nat44_ei_sw_interface_add_del);
+
 int
 nat44_ei_del_static_mappings ()
 {
index 6b0eedc..8a8c968 100644 (file)
@@ -6,7 +6,7 @@ from random import randint, choice
 
 import scapy.compat
 from framework import tag_fixme_ubuntu2204, is_distro_ubuntu2204
-from framework import VppTestCase, VppTestRunner
+from framework import VppTestCase, VppTestRunner, VppLoInterface
 from scapy.data import IP_PROTOS
 from scapy.layers.inet import IP, TCP, UDP, ICMP, GRE
 from scapy.layers.inet import IPerror, TCPerror
@@ -2552,6 +2552,51 @@ class TestNAT44ED(VppTestCase):
             in_if.unconfig()
             out_if.unconfig()
 
+    def test_delete_interface(self):
+        """NAT44ED delete nat interface"""
+
+        self.nat_add_address(self.nat_addr)
+
+        interfaces = self.create_loopback_interfaces(4)
+        self.nat_add_outside_interface(interfaces[0])
+        self.nat_add_inside_interface(interfaces[1])
+        self.nat_add_outside_interface(interfaces[2])
+        self.nat_add_inside_interface(interfaces[2])
+        self.vapi.nat44_ed_add_del_output_interface(
+            sw_if_index=interfaces[3].sw_if_index, is_add=1
+        )
+
+        nat_sw_if_indices = [
+            i.sw_if_index
+            for i in self.vapi.nat44_interface_dump()
+            + list(self.vapi.vpp.details_iter(self.vapi.nat44_ed_output_interface_get))
+        ]
+        self.assertEqual(len(nat_sw_if_indices), len(interfaces))
+
+        loopbacks = []
+        for i in interfaces:
+            # delete nat-enabled interface
+            self.assertIn(i.sw_if_index, nat_sw_if_indices)
+            i.remove_vpp_config()
+
+            # create interface with the same index
+            lo = VppLoInterface(self)
+            loopbacks.append(lo)
+            self.assertEqual(lo.sw_if_index, i.sw_if_index)
+
+            # check interface is not nat-enabled
+            nat_sw_if_indices = [
+                i.sw_if_index
+                for i in self.vapi.nat44_interface_dump()
+                + list(
+                    self.vapi.vpp.details_iter(self.vapi.nat44_ed_output_interface_get)
+                )
+            ]
+            self.assertNotIn(lo.sw_if_index, nat_sw_if_indices)
+
+        for i in loopbacks:
+            i.remove_vpp_config()
+
 
 @tag_fixme_ubuntu2204
 class TestNAT44EDMW(TestNAT44ED):
index 259c445..955dbb5 100644 (file)
@@ -9,7 +9,7 @@ from io import BytesIO
 
 import scapy.compat
 from framework import tag_fixme_debian11, is_distro_debian11
-from framework import VppTestCase, VppTestRunner
+from framework import VppTestCase, VppTestRunner, VppLoInterface
 from ipfix import IPFIX, Set, Template, Data, IPFIXDecoder
 from scapy.all import (
     bind_layers,
@@ -4061,6 +4061,59 @@ class TestNAT44EI(MethodHolder):
         # a nonzero default should be reported for user_sessions
         self.assertNotEqual(nat44_ei_config.user_sessions, 0)
 
+    def test_delete_interface(self):
+        """NAT44EI delete nat interface"""
+
+        self.nat44_add_address(self.nat_addr)
+
+        interfaces = self.create_loopback_interfaces(4)
+
+        self.vapi.nat44_ei_interface_add_del_feature(
+            sw_if_index=interfaces[0].sw_if_index, is_add=1
+        )
+        flags = self.config_flags.NAT44_EI_IF_INSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
+            sw_if_index=interfaces[1].sw_if_index, flags=flags, is_add=1
+        )
+        flags |= self.config_flags.NAT44_EI_IF_OUTSIDE
+        self.vapi.nat44_ei_interface_add_del_feature(
+            sw_if_index=interfaces[2].sw_if_index, flags=flags, is_add=1
+        )
+        self.vapi.nat44_ei_add_del_output_interface(
+            sw_if_index=interfaces[3].sw_if_index, is_add=1
+        )
+
+        nat_sw_if_indices = [
+            i.sw_if_index
+            for i in self.vapi.nat44_ei_interface_dump()
+            + list(self.vapi.vpp.details_iter(self.vapi.nat44_ei_output_interface_get))
+        ]
+        self.assertEqual(len(nat_sw_if_indices), len(interfaces))
+
+        loopbacks = []
+        for i in interfaces:
+            # delete nat-enabled interface
+            self.assertIn(i.sw_if_index, nat_sw_if_indices)
+            i.remove_vpp_config()
+
+            # create interface with the same index
+            lo = VppLoInterface(self)
+            loopbacks.append(lo)
+            self.assertEqual(lo.sw_if_index, i.sw_if_index)
+
+            # check interface is not nat-enabled
+            nat_sw_if_indices = [
+                i.sw_if_index
+                for i in self.vapi.nat44_ei_interface_dump()
+                + list(
+                    self.vapi.vpp.details_iter(self.vapi.nat44_ei_output_interface_get)
+                )
+            ]
+            self.assertNotIn(lo.sw_if_index, nat_sw_if_indices)
+
+        for i in loopbacks:
+            i.remove_vpp_config()
+
 
 class TestNAT44Out2InDPO(MethodHolder):
     """NAT44EI Test Cases using out2in DPO"""