abf: exclude networks with deny rules 76/37876/6
authorJosh Dorsey <jdorsey@netgate.com>
Wed, 4 Jan 2023 21:28:07 +0000 (21:28 +0000)
committerNeale Ranns <neale@graphiant.com>
Thu, 12 Jan 2023 02:17:37 +0000 (02:17 +0000)
Type: improvement

Signed-off-by: Josh Dorsey <jdorsey@netgate.com>
Change-Id: Iee43ca9278922fc7396764b88cff1a87bcb28349

src/plugins/abf/FEATURE.yaml
src/plugins/abf/abf_itf_attach.c
test/test_abf.py

index b9f3285..7902dbe 100644 (file)
@@ -1,9 +1,12 @@
 ---
 name: ACL Based Forwarding
-maintainer: Neale Ranns <nranns@cisco.com>
+maintainer: Neale Ranns <neale@graphiant.com>
 features:
   - 'Policy Based Routing'
-  - ACLs match traffic to be forwarded
+  - ACLs identify how traffic should be forwarded. Packets matching a permit
+    rule are forwarded using ABF policy. Packets matching a deny rule are
+    excluded from ABF handling and continue traversing the input feature arc on
+    the L3 path.
   - Each rule in the ACL has an associated 'path' which determines how the
     traffic will be forwarded. This path is described as a FIB path, so anything
     possible with basic L3 forwarding is possible with ABF (with the exception
index 6f85ff6..a14717e 100644 (file)
@@ -567,10 +567,11 @@ abf_input_inline (vlib_main_t * vm,
                                         (FIB_PROTOCOL_IP6 == fproto), 1, 0,
                                         &fa_5tuple0);
 
-         if (acl_plugin_match_5tuple_inline
-             (acl_plugin.p_acl_main, lc_index, &fa_5tuple0,
-              (FIB_PROTOCOL_IP6 == fproto), &action, &match_acl_pos,
-              &match_acl_index, &match_rule_index, &trace_bitmap))
+         if (acl_plugin_match_5tuple_inline (
+               acl_plugin.p_acl_main, lc_index, &fa_5tuple0,
+               (FIB_PROTOCOL_IP6 == fproto), &action, &match_acl_pos,
+               &match_acl_index, &match_rule_index, &trace_bitmap) &&
+             action > 0)
            {
              /*
               * match:
index 856d02a..87e6842 100644 (file)
@@ -343,6 +343,132 @@ class TestAbf(VppTestCase):
         #
         self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg1)
 
+    def test_abf4_deny(self):
+        """IPv4 ACL Deny Rule"""
+        import ipaddress
+
+        #
+        # Rules 1/2
+        #
+        pg0_subnet = ipaddress.ip_network(self.pg0.local_ip4_prefix, strict=False)
+        pg2_subnet = ipaddress.ip_network(self.pg2.local_ip4_prefix, strict=False)
+        pg3_subnet = ipaddress.ip_network(self.pg3.local_ip4_prefix, strict=False)
+        rule_deny = AclRule(
+            is_permit=0,
+            proto=17,
+            ports=1234,
+            src_prefix=IPv4Network(pg0_subnet),
+            dst_prefix=IPv4Network(pg3_subnet),
+        )
+        rule_permit = AclRule(
+            is_permit=1,
+            proto=17,
+            ports=1234,
+            src_prefix=IPv4Network(pg0_subnet),
+            dst_prefix=IPv4Network(pg2_subnet),
+        )
+        acl_1 = VppAcl(self, rules=[rule_deny, rule_permit])
+        acl_1.add_vpp_config()
+
+        #
+        # ABF policy for ACL 1 - path via interface 1
+        #
+        abf_1 = VppAbfPolicy(
+            self, 10, acl_1, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]
+        )
+        abf_1.add_vpp_config()
+
+        #
+        # Attach the policy to input interface Pg0
+        #
+        attach_1 = VppAbfAttach(self, 10, self.pg0.sw_if_index, 50)
+        attach_1.add_vpp_config()
+
+        #
+        # a packet matching the deny rule
+        #
+        p_deny = (
+            Ether(src=self.pg0.remote_mac, dst=self.pg3.remote_mac)
+            / IP(src=self.pg0.remote_ip4, dst=self.pg3.remote_ip4)
+            / UDP(sport=1234, dport=1234)
+            / Raw(b"\xa5" * 100)
+        )
+        self.send_and_expect(self.pg0, p_deny * NUM_PKTS, self.pg3)
+
+        #
+        # a packet matching the permit rule
+        #
+        p_permit = (
+            Ether(src=self.pg0.remote_mac, dst=self.pg2.remote_mac)
+            / IP(src=self.pg0.remote_ip4, dst=self.pg2.remote_ip4)
+            / UDP(sport=1234, dport=1234)
+            / Raw(b"\xa5" * 100)
+        )
+        self.send_and_expect(self.pg0, p_permit * NUM_PKTS, self.pg1)
+
+    def test_abf6_deny(self):
+        """IPv6 ACL Deny Rule"""
+        import ipaddress
+
+        #
+        # Rules 1/2
+        #
+        pg0_subnet = ipaddress.ip_network(self.pg0.local_ip6_prefix, strict=False)
+        pg2_subnet = ipaddress.ip_network(self.pg2.local_ip6_prefix, strict=False)
+        pg3_subnet = ipaddress.ip_network(self.pg3.local_ip6_prefix, strict=False)
+        rule_deny = AclRule(
+            is_permit=0,
+            proto=17,
+            ports=1234,
+            src_prefix=IPv6Network(pg0_subnet),
+            dst_prefix=IPv6Network(pg3_subnet),
+        )
+        rule_permit = AclRule(
+            is_permit=1,
+            proto=17,
+            ports=1234,
+            src_prefix=IPv6Network(pg0_subnet),
+            dst_prefix=IPv6Network(pg2_subnet),
+        )
+        acl_1 = VppAcl(self, rules=[rule_deny, rule_permit])
+        acl_1.add_vpp_config()
+
+        #
+        # ABF policy for ACL 1 - path via interface 1
+        #
+        abf_1 = VppAbfPolicy(
+            self, 10, acl_1, [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)]
+        )
+        abf_1.add_vpp_config()
+
+        #
+        # Attach the policy to input interface Pg0
+        #
+        attach_1 = VppAbfAttach(self, 10, self.pg0.sw_if_index, 50, is_ipv6=1)
+        attach_1.add_vpp_config()
+
+        #
+        # a packet matching the deny rule
+        #
+        p_deny = (
+            Ether(src=self.pg0.remote_mac, dst=self.pg3.remote_mac)
+            / IPv6(src=self.pg0.remote_ip6, dst=self.pg3.remote_ip6)
+            / UDP(sport=1234, dport=1234)
+            / Raw(b"\xa5" * 100)
+        )
+        self.send_and_expect(self.pg0, p_deny * NUM_PKTS, self.pg3)
+
+        #
+        # a packet matching the permit rule
+        #
+        p_permit = (
+            Ether(src=self.pg0.remote_mac, dst=self.pg2.remote_mac)
+            / IPv6(src=self.pg0.remote_ip6, dst=self.pg2.remote_ip6)
+            / UDP(sport=1234, dport=1234)
+            / Raw(b"\xa5" * 100)
+        )
+        self.send_and_expect(self.pg0, p_permit * NUM_PKTS, self.pg1)
+
 
 if __name__ == "__main__":
     unittest.main(testRunner=VppTestRunner)