From 17ff3c1fa5687255a118c53223fa2cd49132d929 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Wed, 4 Jul 2018 10:24:24 -0700 Subject: Pipes A pipe resembles a unix pipe. Each end of the pipe is a full VPP interface. pipes can be used for e.g. packet recirculation, inter-BD, etc. Change-Id: I185bb9fb43dd233ff45da63ac1b85ae2e1ceca16 Signed-off-by: Neale Ranns --- test/test_pipe.py | 255 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 test/test_pipe.py (limited to 'test/test_pipe.py') diff --git a/test/test_pipe.py b/test/test_pipe.py new file mode 100644 index 00000000000..a89c1e90236 --- /dev/null +++ b/test/test_pipe.py @@ -0,0 +1,255 @@ +#!/usr/bin/env python +from socket import AF_INET, AF_INET6, inet_pton + +from framework import VppTestCase, VppTestRunner +from vpp_interface import VppInterface +from vpp_ip_route import VppIpTable, VppIpRoute, VppRoutePath + +from scapy.packet import Raw +from scapy.layers.l2 import Ether +from scapy.layers.inet import IP, UDP + + +class VppPipe(VppInterface): + """ + VPP Pipe + """ + + @property + def east(self): + return self.result.pipe_sw_if_index[1] + + @property + def west(self): + return self.result.pipe_sw_if_index[0] + + def __init__(self, test, instance=0xffffffff): + super(VppPipe, self).__init__(test) + self._test = test + self.instance = instance + + def add_vpp_config(self): + self.result = self._test.vapi.pipe_create( + 0 if self.instance == 0xffffffff else 1, + self.instance) + self.set_sw_if_index(self.result.parent_sw_if_index) + + def remove_vpp_config(self): + self._test.vapi.pipe_delete( + self.result.parent_sw_if_index) + + def __str__(self): + return self.object_id() + + def object_id(self): + return "pipe-%d" % (self._sw_if_index) + + def query_vpp_config(self): + pipes = self._test.vapi.pipe_dump() + for p in pipes: + if p.parent_sw_if_index == self.result.parent_sw_if_index: + return True + return False + + def set_unnumbered(self, ip_sw_if_index, is_add=True): + res = self._test.vapi.sw_interface_set_unnumbered( + self.east, ip_sw_if_index, is_add) + res = self._test.vapi.sw_interface_set_unnumbered( + self.west, ip_sw_if_index, is_add) + + +class TestPipe(VppTestCase): + """ Pipes """ + + def setUp(self): + super(TestPipe, self).setUp() + + self.create_pg_interfaces(range(4)) + + for i in self.pg_interfaces: + i.admin_up() + + def tearDown(self): + for i in self.pg_interfaces: + i.admin_down() + + super(TestPipe, self).tearDown() + + def test_pipe(self): + """ Pipes """ + + pipes = [] + pipes.append(VppPipe(self)) + pipes.append(VppPipe(self, 10)) + + for p in pipes: + p.add_vpp_config() + p.admin_up() + + # + # L2 cross-connect pipe0 east with pg0 and west with pg1 + # + self.vapi.sw_interface_set_l2_xconnect(self.pg0.sw_if_index, + pipes[0].east, + enable=1) + self.vapi.sw_interface_set_l2_xconnect(pipes[0].east, + self.pg0.sw_if_index, + enable=1) + self.vapi.sw_interface_set_l2_xconnect(self.pg1.sw_if_index, + pipes[0].west, + enable=1) + self.vapi.sw_interface_set_l2_xconnect(pipes[0].west, + self.pg1.sw_if_index, + enable=1) + + # test bi-drectional L2 flow pg0<->pg1 + p = (Ether(src=self.pg0.remote_mac, + dst=self.pg1.remote_mac) / + IP(src="1.1.1.1", + dst="1.1.1.2") / + UDP(sport=1234, dport=1234) / + Raw('\xa5' * 100)) + + self.send_and_expect(self.pg0, p * 65, self.pg1) + self.send_and_expect(self.pg1, p * 65, self.pg0) + + # + # Attach ACL to ensure features are run on the pipe + # + rule_1 = ({'is_permit': 0, + 'is_ipv6': 0, + 'proto': 17, + 'srcport_or_icmptype_first': 1234, + 'srcport_or_icmptype_last': 1234, + 'src_ip_prefix_len': 32, + 'src_ip_addr': inet_pton(AF_INET, "1.1.1.1"), + 'dstport_or_icmpcode_first': 1234, + 'dstport_or_icmpcode_last': 1234, + 'dst_ip_prefix_len': 32, + 'dst_ip_addr': inet_pton(AF_INET, "1.1.1.2")}) + acl = self.vapi.acl_add_replace(acl_index=4294967295, + r=[rule_1]) + + # Apply the ACL on the pipe on output + self.vapi.acl_interface_set_acl_list(pipes[0].east, + 0, + [acl.acl_index]) + self.send_and_assert_no_replies(self.pg0, p * 65) + self.send_and_expect(self.pg1, p * 65, self.pg0) + + # remove from output and apply on input + self.vapi.acl_interface_set_acl_list(pipes[0].east, + 0, + []) + self.vapi.acl_interface_set_acl_list(pipes[0].west, + 1, + [acl.acl_index]) + self.send_and_assert_no_replies(self.pg0, p * 65) + self.send_and_expect(self.pg1, p * 65, self.pg0) + self.vapi.acl_interface_set_acl_list(pipes[0].west, + 0, + []) + self.send_and_expect(self.pg0, p * 65, self.pg1) + self.send_and_expect(self.pg1, p * 65, self.pg0) + + # + # L3 routes in two separate tables so a pipe can be used to L3 + # x-connect + # + tables = [] + tables.append(VppIpTable(self, 1)) + tables.append(VppIpTable(self, 2)) + + for t in tables: + t.add_vpp_config() + + self.pg2.set_table_ip4(1) + self.pg2.config_ip4() + self.pg2.resolve_arp() + self.pg3.set_table_ip4(2) + self.pg3.config_ip4() + self.pg3.resolve_arp() + + routes = [] + routes.append(VppIpRoute(self, "1.1.1.1", 32, + [VppRoutePath(self.pg3.remote_ip4, + self.pg3.sw_if_index)], + table_id=2)) + routes.append(VppIpRoute(self, "1.1.1.1", 32, + [VppRoutePath("0.0.0.0", pipes[1].east)], + table_id=1)) + routes.append(VppIpRoute(self, "1.1.1.2", 32, + [VppRoutePath("0.0.0.0", pipes[1].west)], + table_id=2)) + routes.append(VppIpRoute(self, "1.1.1.2", 32, + [VppRoutePath(self.pg2.remote_ip4, + self.pg2.sw_if_index)], + table_id=1)) + + for r in routes: + r.add_vpp_config() + + p_east = (Ether(src=self.pg2.remote_mac, + dst=self.pg2.local_mac) / + IP(src="1.1.1.2", + dst="1.1.1.1") / + UDP(sport=1234, dport=1234) / + Raw('\xa5' * 100)) + + # bind the pipe ends to the correct tables + self.vapi.sw_interface_set_table(pipes[1].west, 0, 2) + self.vapi.sw_interface_set_table(pipes[1].east, 0, 1) + + # IP is not enabled on the pipes at this point + self.send_and_assert_no_replies(self.pg2, p_east * 65) + + # IP enable the Pipes by making them unnumbered + pipes[0].set_unnumbered(self.pg2.sw_if_index) + pipes[1].set_unnumbered(self.pg3.sw_if_index) + + self.send_and_expect(self.pg2, p_east * 65, self.pg3) + + # and the return path + p_west = (Ether(src=self.pg3.remote_mac, + dst=self.pg3.local_mac) / + IP(src="1.1.1.1", + dst="1.1.1.2") / + UDP(sport=1234, dport=1234) / + Raw('\xa5' * 100)) + self.send_and_expect(self.pg3, p_west * 65, self.pg2) + + # + # Use ACLs to test features run on the Pipes + # + self.vapi.acl_interface_set_acl_list(pipes[1].east, + 0, + [acl.acl_index]) + self.send_and_assert_no_replies(self.pg2, p_east * 65) + self.send_and_expect(self.pg3, p_west * 65, self.pg2) + + # remove from output and apply on input + self.vapi.acl_interface_set_acl_list(pipes[1].east, + 0, + []) + self.vapi.acl_interface_set_acl_list(pipes[1].west, + 1, + [acl.acl_index]) + self.send_and_assert_no_replies(self.pg2, p_east * 65) + self.send_and_expect(self.pg3, p_west * 65, self.pg2) + self.vapi.acl_interface_set_acl_list(pipes[1].west, + 0, + []) + self.send_and_expect(self.pg2, p_east * 65, self.pg3) + self.send_and_expect(self.pg3, p_west * 65, self.pg2) + + # cleanup (so the tables delete) + self.pg2.unconfig_ip4() + self.pg2.set_table_ip4(0) + self.pg3.unconfig_ip4() + self.pg3.set_table_ip4(0) + self.vapi.sw_interface_set_table(pipes[1].west, 0, 0) + self.vapi.sw_interface_set_table(pipes[1].east, 0, 0) + + +if __name__ == '__main__': + unittest.main(testRunner=VppTestRunner) -- cgit 1.2.3-korg