From 30f7e41987960a9e94ec79f12e31b7de788e7100 Mon Sep 17 00:00:00 2001 From: Mohsin Kazmi Date: Wed, 10 Jul 2019 18:45:55 +0200 Subject: gbp: Add extended SFC unit tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Type: feature Change-Id: I1218257af0053ae27c4394d7666fde87a732e08c Signed-off-by: Mohsin Kazmi Signed-off-by: BenoƮt Ganne (cherry picked from commit a3c8ca10e9fb09e81a0dba40ad8a5fc6a9d27467) --- src/plugins/gbp/test/test_gbp.py | 461 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 459 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/gbp/test/test_gbp.py b/src/plugins/gbp/test/test_gbp.py index 3989e233c93..09362e4fa89 100644 --- a/src/plugins/gbp/test/test_gbp.py +++ b/src/plugins/gbp/test/test_gbp.py @@ -4170,6 +4170,463 @@ class TestGBP(VppTestCase): # self.pg7.unconfig_ip4() + def test_gbp_redirect_extended(self): + """ GBP Endpoint Redirect Extended """ + + self.vapi.cli("set logging class gbp level debug") + + ep_flags = VppEnum.vl_api_gbp_endpoint_flags_t + routed_dst_mac = "00:0c:0c:0c:0c:0c" + routed_src_mac = "00:22:bd:f8:19:ff" + + learnt = [{'mac': '00:00:11:11:11:02', + 'ip': '10.0.1.2', + 'ip6': '2001:10::2'}, + {'mac': '00:00:11:11:11:03', + 'ip': '10.0.1.3', + 'ip6': '2001:10::3'}] + + # + # IP tables + # + t4 = VppIpTable(self, 1) + t4.add_vpp_config() + t6 = VppIpTable(self, 1, True) + t6.add_vpp_config() + + # create IPv4 and IPv6 RD UU VxLAN-GBP TEP and bind them to the right + # VRF + rd_uu4 = VppVxlanGbpTunnel( + self, + self.pg7.local_ip4, + self.pg7.remote_ip4, + 114, + mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t. + VXLAN_GBP_API_TUNNEL_MODE_L3)) + rd_uu4.add_vpp_config() + VppIpInterfaceBind(self, rd_uu4, t4).add_vpp_config() + + rd_uu6 = VppVxlanGbpTunnel( + self, + self.pg7.local_ip4, + self.pg7.remote_ip4, + 115, + mode=(VppEnum.vl_api_vxlan_gbp_api_tunnel_mode_t. + VXLAN_GBP_API_TUNNEL_MODE_L3)) + rd_uu6.add_vpp_config() + VppIpInterfaceBind(self, rd_uu6, t4).add_vpp_config() + + rd1 = VppGbpRouteDomain(self, 2, 402, t4, t6, rd_uu4, rd_uu6) + rd1.add_vpp_config() + + self.loop0.set_mac(self.router_mac) + self.loop1.set_mac(self.router_mac) + self.loop2.set_mac(self.router_mac) + + # + # Bind the BVI to the RD + # + VppIpInterfaceBind(self, self.loop0, t4).add_vpp_config() + VppIpInterfaceBind(self, self.loop0, t6).add_vpp_config() + VppIpInterfaceBind(self, self.loop1, t4).add_vpp_config() + VppIpInterfaceBind(self, self.loop1, t6).add_vpp_config() + VppIpInterfaceBind(self, self.loop2, t4).add_vpp_config() + VppIpInterfaceBind(self, self.loop2, t6).add_vpp_config() + + # + # Pg7 hosts a BD's UU-fwd + # + self.pg7.config_ip4() + self.pg7.resolve_arp() + + # + # a GBP bridge domains for the EPs + # + bd1 = VppBridgeDomain(self, 1) + bd1.add_vpp_config() + gbd1 = VppGbpBridgeDomain(self, bd1, rd1, self.loop0) + gbd1.add_vpp_config() + + bd2 = VppBridgeDomain(self, 2) + bd2.add_vpp_config() + gbd2 = VppGbpBridgeDomain(self, bd2, rd1, self.loop1) + gbd2.add_vpp_config() + + # ... and has a /32 and /128 applied + ip4_addr1 = VppIpInterfaceAddress(self, gbd1.bvi, "10.0.0.128", 32) + ip4_addr1.add_vpp_config() + ip6_addr1 = VppIpInterfaceAddress(self, gbd1.bvi, "2001:10::128", 128) + ip6_addr1.add_vpp_config() + ip4_addr2 = VppIpInterfaceAddress(self, gbd2.bvi, "10.0.1.128", 32) + ip4_addr2.add_vpp_config() + ip6_addr2 = VppIpInterfaceAddress(self, gbd2.bvi, "2001:11::128", 128) + ip6_addr2.add_vpp_config() + + # + # The Endpoint-groups + # + epg_220 = VppGbpEndpointGroup(self, 220, 440, rd1, gbd1, + None, gbd1.bvi, + "10.0.0.128", + "2001:10::128", + VppGbpEndpointRetention(2)) + epg_220.add_vpp_config() + epg_221 = VppGbpEndpointGroup(self, 221, 441, rd1, gbd2, + None, gbd2.bvi, + "10.0.1.128", + "2001:11::128", + VppGbpEndpointRetention(2)) + epg_221.add_vpp_config() + + # + # a GBP bridge domains for the SEPs + # + bd_uu3 = VppVxlanGbpTunnel(self, self.pg7.local_ip4, + self.pg7.remote_ip4, 116) + bd_uu3.add_vpp_config() + + bd3 = VppBridgeDomain(self, 3) + bd3.add_vpp_config() + gbd3 = VppGbpBridgeDomain(self, bd3, rd1, self.loop2, + bd_uu3, learn=False) + gbd3.add_vpp_config() + + ip4_addr3 = VppIpInterfaceAddress(self, gbd3.bvi, "12.0.0.128", 32) + ip4_addr3.add_vpp_config() + ip6_addr3 = VppIpInterfaceAddress(self, gbd3.bvi, "4001:10::128", 128) + ip6_addr3.add_vpp_config() + + # + # self.logger.info(self.vapi.cli("show gbp bridge")) + # self.logger.info(self.vapi.cli("show vxlan-gbp tunnel")) + # self.logger.info(self.vapi.cli("show gbp vxlan")) + # self.logger.info(self.vapi.cli("show int addr")) + # + + # + # EPGs in which the service endpoints exist + # + epg_320 = VppGbpEndpointGroup(self, 320, 550, rd1, gbd3, + None, gbd3.bvi, + "12.0.0.128", + "4001:10::128", + VppGbpEndpointRetention(2)) + epg_320.add_vpp_config() + + # + # endpoints + # + ep1 = VppGbpEndpoint(self, self.pg0, + epg_220, None, + "10.0.0.1", "11.0.0.1", + "2001:10::1", "3001:10::1") + ep1.add_vpp_config() + ep2 = VppGbpEndpoint(self, self.pg1, + epg_221, None, + "10.0.1.1", "11.0.1.1", + "2001:11::1", "3001:11::1") + ep2.add_vpp_config() + + # + # service endpoints + # + sep1 = VppGbpEndpoint(self, self.pg3, + epg_320, None, + "12.0.0.1", "13.0.0.1", + "4001:10::1", "5001:10::1") + sep2 = VppGbpEndpoint(self, self.pg4, + epg_320, None, + "12.0.0.2", "13.0.0.2", + "4001:10::2", "5001:10::2") + + # sep1 and sep2 are not added to config yet + # they are unknown for now + + # + # add routes to EPG subnets + # + VppGbpSubnet(self, rd1, "10.0.0.0", 24, + VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT + ).add_vpp_config() + VppGbpSubnet(self, rd1, "10.0.1.0", 24, + VppEnum.vl_api_gbp_subnet_type_t.GBP_API_SUBNET_TRANSPORT + ).add_vpp_config() + + # + # Local host to known local host in different BD + # with SFC contract (source and destination are in + # one node and service endpoint in another node) + # + p4 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) / + IP(src=ep1.ip4.address, dst=ep2.ip4.address) / + UDP(sport=1234, dport=1234) / + Raw('\xa5' * 100)), + (Ether(src=ep2.mac, dst=str(self.router_mac)) / + IP(src=ep2.ip4.address, dst=ep1.ip4.address) / + UDP(sport=1234, dport=1234) / + Raw('\xa5' * 100))] + p6 = [(Ether(src=ep1.mac, dst=str(self.router_mac)) / + IPv6(src=ep1.ip6.address, dst=ep2.ip6.address) / + UDP(sport=1234, dport=1234) / + Raw('\xa5' * 100)), + (Ether(src=ep2.mac, dst=str(self.router_mac)) / + IPv6(src=ep2.ip6.address, dst=ep1.ip6.address) / + UDP(sport=1234, dport=1230) / + Raw('\xa5' * 100))] + + # should be dropped since no contract yet + self.send_and_assert_no_replies(self.pg0, [p4[0]]) + self.send_and_assert_no_replies(self.pg0, [p6[0]]) + + # + # Add a contract with a rule to load-balance redirect via SEP1 and SEP2 + # one of the next-hops is via an EP that is not known + # + acl = VppGbpAcl(self) + rule4 = acl.create_rule(permit_deny=1, proto=17) + rule6 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17) + acl_index = acl.add_vpp_config([rule4, rule6]) + + # + # test the src-ip hash mode + # + c1 = VppGbpContract( + self, 402, epg_220.sclass, epg_221.sclass, acl_index, + [VppGbpContractRule( + VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, + VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC, + [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd, + sep1.ip4, sep1.epg.rd)]), + VppGbpContractRule( + VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, + VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC, + [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd, + sep1.ip6, sep1.epg.rd)])], + [ETH_P_IP, ETH_P_IPV6]) + c1.add_vpp_config() + + c2 = VppGbpContract( + self, 402, epg_221.sclass, epg_220.sclass, acl_index, + [VppGbpContractRule( + VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, + VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC, + [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd, + sep1.ip4, sep1.epg.rd)]), + VppGbpContractRule( + VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_REDIRECT, + VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC, + [VppGbpContractNextHop(sep1.vmac, sep1.epg.bd, + sep1.ip6, sep1.epg.rd)])], + [ETH_P_IP, ETH_P_IPV6]) + c2.add_vpp_config() + + # ep1 <--> ep2 redirected through sep1 + # sep1 is unknown + # packet is redirected to sep bd and then go through sep bd UU + + rxs = self.send_and_expect(self.pg0, p4[0] * 17, self.pg7) + + for rx in rxs: + self.assertEqual(rx[Ether].src, self.pg7.local_mac) + self.assertEqual(rx[Ether].dst, self.pg7.remote_mac) + self.assertEqual(rx[IP].src, self.pg7.local_ip4) + self.assertEqual(rx[IP].dst, self.pg7.remote_ip4) + self.assertEqual(rx[VXLAN].vni, 116) + self.assertTrue(rx[VXLAN].flags.G) + self.assertTrue(rx[VXLAN].flags.Instance) + # redirect policy has been applied + self.assertTrue(rx[VXLAN].gpflags.A) + self.assertFalse(rx[VXLAN].gpflags.D) + + inner = rx[VXLAN].payload + + self.assertEqual(inner[Ether].src, routed_src_mac) + self.assertEqual(inner[Ether].dst, sep1.mac) + self.assertEqual(inner[IP].src, ep1.ip4.address) + self.assertEqual(inner[IP].dst, ep2.ip4.address) + + rxs = self.send_and_expect(self.pg1, p4[1] * 17, self.pg7) + + for rx in rxs: + self.assertEqual(rx[Ether].src, self.pg7.local_mac) + self.assertEqual(rx[Ether].dst, self.pg7.remote_mac) + self.assertEqual(rx[IP].src, self.pg7.local_ip4) + self.assertEqual(rx[IP].dst, self.pg7.remote_ip4) + self.assertEqual(rx[VXLAN].vni, 116) + self.assertTrue(rx[VXLAN].flags.G) + self.assertTrue(rx[VXLAN].flags.Instance) + # redirect policy has been applied + self.assertTrue(rx[VXLAN].gpflags.A) + self.assertFalse(rx[VXLAN].gpflags.D) + + inner = rx[VXLAN].payload + + self.assertEqual(inner[Ether].src, routed_src_mac) + self.assertEqual(inner[Ether].dst, sep1.mac) + self.assertEqual(inner[IP].src, ep2.ip4.address) + self.assertEqual(inner[IP].dst, ep1.ip4.address) + + rxs = self.send_and_expect(self.pg0, p6[0] * 17, self.pg7) + + for rx in rxs: + self.assertEqual(rx[Ether].src, self.pg7.local_mac) + self.assertEqual(rx[Ether].dst, self.pg7.remote_mac) + self.assertEqual(rx[IP].src, self.pg7.local_ip4) + self.assertEqual(rx[IP].dst, self.pg7.remote_ip4) + self.assertEqual(rx[VXLAN].vni, 116) + self.assertTrue(rx[VXLAN].flags.G) + self.assertTrue(rx[VXLAN].flags.Instance) + # redirect policy has been applied + inner = rx[VXLAN].payload + + self.assertEqual(inner[Ether].src, routed_src_mac) + self.assertEqual(inner[Ether].dst, sep1.mac) + self.assertEqual(inner[IPv6].src, ep1.ip6.address) + self.assertEqual(inner[IPv6].dst, ep2.ip6.address) + + rxs = self.send_and_expect(self.pg1, p6[1] * 17, self.pg7) + + for rx in rxs: + self.assertEqual(rx[Ether].src, self.pg7.local_mac) + self.assertEqual(rx[Ether].dst, self.pg7.remote_mac) + self.assertEqual(rx[IP].src, self.pg7.local_ip4) + self.assertEqual(rx[IP].dst, self.pg7.remote_ip4) + self.assertEqual(rx[VXLAN].vni, 116) + self.assertTrue(rx[VXLAN].flags.G) + self.assertTrue(rx[VXLAN].flags.Instance) + # redirect policy has been applied + self.assertTrue(rx[VXLAN].gpflags.A) + self.assertFalse(rx[VXLAN].gpflags.D) + + inner = rx[VXLAN].payload + + self.assertEqual(inner[Ether].src, routed_src_mac) + self.assertEqual(inner[Ether].dst, sep1.mac) + self.assertEqual(inner[IPv6].src, ep2.ip6.address) + self.assertEqual(inner[IPv6].dst, ep1.ip6.address) + + # configure sep1: it is now local + # packets between ep1 and ep2 are redirected locally + sep1.add_vpp_config() + + rxs = self.send_and_expect(self.pg0, p4[0] * 17, sep1.itf) + + for rx in rxs: + self.assertEqual(rx[Ether].src, routed_src_mac) + self.assertEqual(rx[Ether].dst, sep1.mac) + self.assertEqual(rx[IP].src, ep1.ip4.address) + self.assertEqual(rx[IP].dst, ep2.ip4.address) + + rxs = self.send_and_expect(self.pg1, p6[1] * 17, sep1.itf) + + for rx in rxs: + self.assertEqual(rx[Ether].src, routed_src_mac) + self.assertEqual(rx[Ether].dst, sep1.mac) + self.assertEqual(rx[IPv6].src, ep2.ip6.address) + self.assertEqual(rx[IPv6].dst, ep1.ip6.address) + + # packet coming from the l2 spine-proxy to sep1 + p = (Ether(src=self.pg7.remote_mac, + dst=self.pg7.local_mac) / + IP(src=self.pg7.remote_ip4, + dst=self.pg7.local_ip4) / + UDP(sport=1234, dport=48879) / + VXLAN(vni=116, gpid=440, gpflags=0x08, flags=0x88) / + Ether(src=str(self.router_mac), dst=sep1.mac) / + IP(src=ep1.ip4.address, dst=ep2.ip4.address) / + UDP(sport=1234, dport=1234) / + Raw('\xa5' * 100)) + + rxs = self.send_and_expect(self.pg7, [p] * 17, sep1.itf) + + for rx in rxs: + self.assertEqual(rx[Ether].src, str(self.router_mac)) + self.assertEqual(rx[Ether].dst, sep1.mac) + self.assertEqual(rx[IP].src, ep1.ip4.address) + self.assertEqual(rx[IP].dst, ep2.ip4.address) + + # contract for SEP to communicate with dst EP + c3 = VppGbpContract( + self, 402, epg_320.sclass, epg_221.sclass, acl_index, + [VppGbpContractRule( + VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, + VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC), + VppGbpContractRule( + VppEnum.vl_api_gbp_rule_action_t.GBP_API_RULE_PERMIT, + VppEnum.vl_api_gbp_hash_mode_t.GBP_API_HASH_MODE_SYMMETRIC)], + [ETH_P_IP, ETH_P_IPV6]) + c3.add_vpp_config() + + # temporarily remove ep2, so that ep2 is remote & unknown + ep2.remove_vpp_config() + + # packet going back from sep1 to its original dest (ep2) + # as ep2 is now unknown (see above), it must go through + # the rd UU (packet is routed) + + p1 = (Ether(src=sep1.mac, dst=self.router_mac) / + IP(src=ep1.ip4.address, dst=ep2.ip4.address) / + UDP(sport=1234, dport=1234) / + Raw('\xa5' * 100)) + + rxs = self.send_and_expect(self.pg3, [p1] * 17, self.pg7) + + for rx in rxs: + self.assertEqual(rx[Ether].src, self.pg7.local_mac) + self.assertEqual(rx[Ether].dst, self.pg7.remote_mac) + self.assertEqual(rx[IP].src, self.pg7.local_ip4) + self.assertEqual(rx[IP].dst, self.pg7.remote_ip4) + self.assertEqual(rx[VXLAN].vni, 114) + self.assertTrue(rx[VXLAN].flags.G) + self.assertTrue(rx[VXLAN].flags.Instance) + # redirect policy has been applied + inner = rx[VXLAN].payload + self.assertEqual(inner[Ether].src, routed_src_mac) + self.assertEqual(inner[Ether].dst, routed_dst_mac) + self.assertEqual(inner[IP].src, ep1.ip4.address) + self.assertEqual(inner[IP].dst, ep2.ip4.address) + + self.logger.info(self.vapi.cli("show bridge 3 detail")) + sep1.remove_vpp_config() + + self.logger.info(self.vapi.cli("show bridge 1 detail")) + self.logger.info(self.vapi.cli("show bridge 2 detail")) + + # re-add ep2: it is local again :) + ep2.add_vpp_config() + + # packet coming back from the remote sep through rd UU + p2 = (Ether(src=self.pg7.remote_mac, + dst=self.pg7.local_mac) / + IP(src=self.pg7.remote_ip4, + dst=self.pg7.local_ip4) / + UDP(sport=1234, dport=48879) / + VXLAN(vni=114, gpid=441, gpflags=0x09, flags=0x88) / + Ether(src=str(self.router_mac), dst=self.router_mac) / + IP(src=ep1.ip4.address, dst=ep2.ip4.address) / + UDP(sport=1234, dport=1234) / + Raw('\xa5' * 100)) + + rxs = self.send_and_expect(self.pg7, [p2], self.pg1) + + for rx in rxs: + self.assertEqual(rx[Ether].src, str(self.router_mac)) + self.assertEqual(rx[Ether].dst, self.pg1.remote_mac) + self.assertEqual(rx[IP].src, ep1.ip4.address) + self.assertEqual(rx[IP].dst, ep2.ip4.address) + + # + # bd_uu2.add_vpp_config() + # + + # + # cleanup + # + c1.remove_vpp_config() + c2.remove_vpp_config() + c3.remove_vpp_config() + self.pg7.unconfig_ip4() + def test_gbp_l3_out(self): """ GBP L3 Out """ @@ -4742,7 +5199,7 @@ class TestGBP(VppTestCase): Dot1Q(vlan=100) / IP(src="10.220.0.1", dst="10.222.0.1") / UDP(sport=1222, dport=1235) / - Raw('\xa5' * 100))] + Raw('\xa5' * 100))] rxs = self.send_and_expect(self.pg0, p, self.pg7) @@ -4786,7 +5243,7 @@ class TestGBP(VppTestCase): Dot1Q(vlan=100) / IPv6(src="10:220::1", dst="10:222::1") / UDP(sport=7777, dport=8881) / - Raw('\xa5' * 100))] + Raw('\xa5' * 100))] self.logger.info(self.vapi.cli("sh ip6 fib 10:222::1")) rxs = self.send_and_expect(self.pg0, p, self.pg7) -- cgit 1.2.3-korg