gbp: Add unit tests for contracts 41/19041/3
authorMohsin Kazmi <sykazmi@cisco.com>
Thu, 18 Apr 2019 13:54:58 +0000 (15:54 +0200)
committerNeale Ranns <nranns@cisco.com>
Fri, 17 May 2019 09:47:25 +0000 (09:47 +0000)
Change-Id: Ib6615739b1db44b7788f462196cd477b6e23d67e
Signed-off-by: Mohsin Kazmi <sykazmi@cisco.com>
test/test_gbp.py

index e9b5f5d..33de9b5 100644 (file)
@@ -10,7 +10,7 @@ from scapy.layers.inet6 import IPv6, ICMPv6ND_NS, ICMPv6NDOptSrcLLAddr, \
     ICMPv6ND_NA
 from scapy.utils6 import in6_getnsma, in6_getnsmac
 from scapy.layers.vxlan import VXLAN
-from scapy.data import ETH_P_IP, ETH_P_IPV6
+from scapy.data import ETH_P_IP, ETH_P_IPV6, ETH_P_ARP
 from scapy.utils import inet_pton, inet_ntop
 
 from framework import VppTestCase, VppTestRunner
@@ -699,6 +699,24 @@ class TestGBP(VppTestCase):
             self.assertEqual(r[IPv6].src, src_ip)
         return rx
 
+    def send_and_expect_no_arp(self, src, tx, dst):
+        self.pg_send(src, tx)
+        dst.get_capture(0, timeout=1)
+        dst.assert_nothing_captured(remark="")
+        timeout = 0.1
+
+    def send_and_expect_arp(self, src, tx, dst):
+        rx = self.send_and_expect(src, tx, dst)
+
+        for r in rx:
+            self.assertEqual(r[Ether].src, tx[0][Ether].src)
+            self.assertEqual(r[Ether].dst, tx[0][Ether].dst)
+            self.assertEqual(r[ARP].psrc, tx[0][ARP].psrc)
+            self.assertEqual(r[ARP].pdst, tx[0][ARP].pdst)
+            self.assertEqual(r[ARP].hwsrc, tx[0][ARP].hwsrc)
+            self.assertEqual(r[ARP].hwdst, tx[0][ARP].hwdst)
+        return rx
+
     def test_gbp(self):
         """ Group Based Policy """
 
@@ -1962,6 +1980,211 @@ class TestGBP(VppTestCase):
         self.logger.info(self.vapi.cli("sh int"))
         self.logger.info(self.vapi.cli("sh gbp vxlan"))
 
+    def test_gbp_contract(self):
+        """ GBP CONTRACTS """
+
+        #
+        # Bridge Domains
+        #
+        bd1 = VppBridgeDomain(self, 1, arp_term=0)
+        bd2 = VppBridgeDomain(self, 2, arp_term=0)
+
+        bd1.add_vpp_config()
+        bd2.add_vpp_config()
+
+        gbd1 = VppGbpBridgeDomain(self, bd1, self.loop0)
+        gbd2 = VppGbpBridgeDomain(self, bd2, self.loop1)
+
+        gbd1.add_vpp_config()
+        gbd2.add_vpp_config()
+
+        #
+        # Route Domains
+        #
+        gt4 = VppIpTable(self, 0)
+        gt4.add_vpp_config()
+        gt6 = VppIpTable(self, 0, is_ip6=True)
+        gt6.add_vpp_config()
+
+        rd0 = VppGbpRouteDomain(self, 0, gt4, gt6, None, None)
+
+        rd0.add_vpp_config()
+
+        #
+        # 3 EPGs, 2 of which share a BD.
+        #
+        epgs = [VppGbpEndpointGroup(self, 220, 1220, rd0, gbd1,
+                                    None, self.loop0,
+                                    "10.0.0.128", "2001:10::128"),
+                VppGbpEndpointGroup(self, 221, 1221, rd0, gbd1,
+                                    None, self.loop0,
+                                    "10.0.1.128", "2001:10:1::128"),
+                VppGbpEndpointGroup(self, 222, 1222, rd0, gbd2,
+                                    None, self.loop1,
+                                    "10.0.2.128", "2001:10:2::128")]
+        #
+        # 4 end-points, 2 in the same subnet, 3 in the same BD
+        #
+        eps = [VppGbpEndpoint(self, self.pg0,
+                              epgs[0], None,
+                              "10.0.0.1", "11.0.0.1",
+                              "2001:10::1", "3001::1"),
+               VppGbpEndpoint(self, self.pg1,
+                              epgs[0], None,
+                              "10.0.0.2", "11.0.0.2",
+                              "2001:10::2", "3001::2"),
+               VppGbpEndpoint(self, self.pg2,
+                              epgs[1], None,
+                              "10.0.1.1", "11.0.0.3",
+                              "2001:10:1::1", "3001::3"),
+               VppGbpEndpoint(self, self.pg3,
+                              epgs[2], None,
+                              "10.0.2.1", "11.0.0.4",
+                              "2001:10:2::1", "3001::4")]
+
+        #
+        # Config related to each of the EPGs
+        #
+        for epg in epgs:
+            # IP config on the BVI interfaces
+            if epg != epgs[1]:
+                VppIpInterfaceBind(self, epg.bvi, epg.rd.t4).add_vpp_config()
+                VppIpInterfaceBind(self, epg.bvi, epg.rd.t6).add_vpp_config()
+                self.vapi.sw_interface_set_mac_address(
+                    epg.bvi.sw_if_index,
+                    self.router_mac.packed)
+
+            if_ip4 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip4, 32)
+            if_ip6 = VppIpInterfaceAddress(self, epg.bvi, epg.bvi_ip6, 128)
+            if_ip4.add_vpp_config()
+            if_ip6.add_vpp_config()
+
+            # add the BD ARP termination entry for BVI IP
+            epg.bd_arp_ip4 = VppBridgeDomainArpEntry(self, epg.bd.bd,
+                                                     str(self.router_mac),
+                                                     epg.bvi_ip4)
+            epg.bd_arp_ip4.add_vpp_config()
+
+            # EPG in VPP
+            epg.add_vpp_config()
+
+        #
+        # config ep
+        #
+        for ep in eps:
+            ep.add_vpp_config()
+
+        self.logger.info(self.vapi.cli("show gbp endpoint"))
+        self.logger.info(self.vapi.cli("show interface"))
+        self.logger.info(self.vapi.cli("show br"))
+
+        #
+        # Intra epg allowed without contract
+        #
+        pkt_intra_epg_220_to_220 = (Ether(src=self.pg0.remote_mac,
+                                          dst=self.pg1.remote_mac) /
+                                    IP(src=eps[0].ip4.address,
+                                       dst=eps[1].ip4.address) /
+                                    UDP(sport=1234, dport=1234) /
+                                    Raw('\xa5' * 100))
+
+        self.send_and_expect_bridged(self.pg0,
+                                     pkt_intra_epg_220_to_220 * 65,
+                                     self.pg1)
+
+        #
+        # Inter epg denied without contract
+        #
+        pkt_inter_epg_220_to_221 = (Ether(src=self.pg0.remote_mac,
+                                          dst=self.pg2.remote_mac) /
+                                    IP(src=eps[0].ip4.address,
+                                       dst=eps[2].ip4.address) /
+                                    UDP(sport=1234, dport=1234) /
+                                    Raw('\xa5' * 100))
+
+        self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_221)
+
+        #
+        # A uni-directional contract from EPG 220 -> 221
+        #
+        acl = VppGbpAcl(self)
+        rule = acl.create_rule(permit_deny=1, proto=17)
+        rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17)
+        acl_index = acl.add_vpp_config([rule, rule2])
+        c1 = VppGbpContract(
+            self, epgs[0].sclass, epgs[1].sclass, acl_index,
+            [VppGbpContractRule(
+                VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
+                []),
+             VppGbpContractRule(
+                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
+                 [])],
+            [ETH_P_IP, ETH_P_IPV6])
+        c1.add_vpp_config()
+
+        self.send_and_expect_bridged(eps[0].itf,
+                                     pkt_inter_epg_220_to_221 * 65,
+                                     eps[2].itf)
+
+        pkt_inter_epg_220_to_222 = (Ether(src=self.pg0.remote_mac,
+                                          dst=str(self.router_mac)) /
+                                    IP(src=eps[0].ip4.address,
+                                       dst=eps[3].ip4.address) /
+                                    UDP(sport=1234, dport=1234) /
+                                    Raw('\xa5' * 100))
+        self.send_and_assert_no_replies(eps[0].itf,
+                                        pkt_inter_epg_220_to_222 * 65)
+
+        #
+        # contract for the return direction
+        #
+        c2 = VppGbpContract(
+            self, epgs[1].sclass, epgs[0].sclass, acl_index,
+            [VppGbpContractRule(
+                VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
+                []),
+             VppGbpContractRule(
+                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
+                 [])],
+            [ETH_P_IP, ETH_P_IPV6])
+        c2.add_vpp_config()
+
+        self.send_and_expect_bridged(eps[0].itf,
+                                     pkt_inter_epg_220_to_221 * 65,
+                                     eps[2].itf)
+        pkt_inter_epg_221_to_220 = (Ether(src=self.pg2.remote_mac,
+                                          dst=self.pg0.remote_mac) /
+                                    IP(src=eps[2].ip4.address,
+                                       dst=eps[0].ip4.address) /
+                                    UDP(sport=1234, dport=1234) /
+                                    Raw('\xa5' * 100))
+        self.send_and_expect_bridged(eps[2].itf,
+                                     pkt_inter_epg_221_to_220 * 65,
+                                     eps[0].itf)
+
+        #
+        # contract between 220 and 222 uni-direction
+        #
+        c3 = VppGbpContract(
+            self, epgs[0].sclass, epgs[2].sclass, acl_index,
+            [VppGbpContractRule(
+                VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
+                []),
+             VppGbpContractRule(
+                 VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT,
+                 [])],
+            [ETH_P_IP, ETH_P_IPV6])
+        c3.add_vpp_config()
+
+        self.send_and_expect(eps[0].itf,
+                             pkt_inter_epg_220_to_222 * 65,
+                             eps[3].itf)
+
+        c3.remove_vpp_config()
+        c1.remove_vpp_config()
+        c2.remove_vpp_config()
+        acl.remove_vpp_config()
+
     def test_gbp_bd_flags(self):
         """ GBP BD FLAGS """