2018-07-04 10:24:24 -07:00
|
|
|
#!/usr/bin/env python
|
|
|
|
from socket import AF_INET, AF_INET6, inet_pton
|
2019-05-14 13:35:19 -04:00
|
|
|
import unittest
|
2018-07-04 10:24:24 -07:00
|
|
|
|
|
|
|
from scapy.packet import Raw
|
|
|
|
from scapy.layers.l2 import Ether
|
|
|
|
from scapy.layers.inet import IP, UDP
|
|
|
|
|
2019-05-14 13:35:19 -04:00
|
|
|
from framework import VppTestCase, VppTestRunner
|
|
|
|
from vpp_interface import VppInterface
|
|
|
|
from vpp_ip_route import VppIpTable, VppIpRoute, VppRoutePath
|
|
|
|
|
2019-05-14 13:25:49 -04:00
|
|
|
NUM_PKTS = 67
|
|
|
|
|
2018-07-04 10:24:24 -07:00
|
|
|
|
|
|
|
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)
|
2018-04-11 08:08:30 -07:00
|
|
|
self.set_sw_if_index(self.result.sw_if_index)
|
2018-07-04 10:24:24 -07:00
|
|
|
|
|
|
|
def remove_vpp_config(self):
|
|
|
|
self._test.vapi.pipe_delete(
|
2018-04-11 08:08:30 -07:00
|
|
|
self.result.sw_if_index)
|
2018-07-04 10:24:24 -07:00
|
|
|
|
|
|
|
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:
|
2018-04-11 08:08:30 -07:00
|
|
|
if p.sw_if_index == self.result.sw_if_index:
|
2018-07-04 10:24:24 -07:00
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def set_unnumbered(self, ip_sw_if_index, is_add=True):
|
2019-03-05 16:58:24 +01:00
|
|
|
res = self._test.vapi.sw_interface_set_unnumbered(ip_sw_if_index,
|
|
|
|
self.east, is_add)
|
|
|
|
res = self._test.vapi.sw_interface_set_unnumbered(ip_sw_if_index,
|
|
|
|
self.west, is_add)
|
2018-07-04 10:24:24 -07:00
|
|
|
|
|
|
|
|
|
|
|
class TestPipe(VppTestCase):
|
|
|
|
""" Pipes """
|
|
|
|
|
2019-03-12 19:23:27 -07:00
|
|
|
@classmethod
|
|
|
|
def setUpClass(cls):
|
|
|
|
super(TestPipe, cls).setUpClass()
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def tearDownClass(cls):
|
|
|
|
super(TestPipe, cls).tearDownClass()
|
|
|
|
|
2018-07-04 10:24:24 -07:00
|
|
|
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 """
|
|
|
|
|
2018-04-11 08:08:30 -07:00
|
|
|
pipes = [VppPipe(self), VppPipe(self, 10)]
|
2018-07-04 10:24:24 -07:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
2019-03-27 11:25:48 -07:00
|
|
|
# test bi-directional L2 flow pg0<->pg1
|
2018-07-04 10:24:24 -07:00
|
|
|
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))
|
|
|
|
|
2019-05-14 13:25:49 -04:00
|
|
|
self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg1)
|
|
|
|
self.send_and_expect(self.pg1, p * NUM_PKTS, self.pg0)
|
2018-07-04 10:24:24 -07:00
|
|
|
|
|
|
|
#
|
|
|
|
# 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])
|
2019-05-14 13:25:49 -04:00
|
|
|
self.send_and_assert_no_replies(self.pg0, p * NUM_PKTS)
|
|
|
|
self.send_and_expect(self.pg1, p * NUM_PKTS, self.pg0)
|
2018-07-04 10:24:24 -07:00
|
|
|
|
|
|
|
# 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])
|
2019-05-14 13:25:49 -04:00
|
|
|
self.send_and_assert_no_replies(self.pg0, p * NUM_PKTS)
|
|
|
|
self.send_and_expect(self.pg1, p * NUM_PKTS, self.pg0)
|
2018-07-04 10:24:24 -07:00
|
|
|
self.vapi.acl_interface_set_acl_list(pipes[0].west,
|
|
|
|
0,
|
|
|
|
[])
|
2019-05-14 13:25:49 -04:00
|
|
|
self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg1)
|
|
|
|
self.send_and_expect(self.pg1, p * NUM_PKTS, self.pg0)
|
2018-07-04 10:24:24 -07:00
|
|
|
|
|
|
|
#
|
|
|
|
# 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
|
2019-05-14 13:25:49 -04:00
|
|
|
self.send_and_assert_no_replies(self.pg2, p_east * NUM_PKTS)
|
2018-07-04 10:24:24 -07:00
|
|
|
|
|
|
|
# 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)
|
|
|
|
|
2019-05-14 13:25:49 -04:00
|
|
|
self.send_and_expect(self.pg2, p_east * NUM_PKTS, self.pg3)
|
2018-07-04 10:24:24 -07:00
|
|
|
|
|
|
|
# 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))
|
2019-05-14 13:25:49 -04:00
|
|
|
self.send_and_expect(self.pg3, p_west * NUM_PKTS, self.pg2)
|
2018-07-04 10:24:24 -07:00
|
|
|
|
|
|
|
#
|
|
|
|
# Use ACLs to test features run on the Pipes
|
|
|
|
#
|
|
|
|
self.vapi.acl_interface_set_acl_list(pipes[1].east,
|
|
|
|
0,
|
|
|
|
[acl.acl_index])
|
2019-05-14 13:25:49 -04:00
|
|
|
self.send_and_assert_no_replies(self.pg2, p_east * NUM_PKTS)
|
|
|
|
self.send_and_expect(self.pg3, p_west * NUM_PKTS, self.pg2)
|
2018-07-04 10:24:24 -07:00
|
|
|
|
|
|
|
# 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])
|
2019-05-14 13:25:49 -04:00
|
|
|
self.send_and_assert_no_replies(self.pg2, p_east * NUM_PKTS)
|
|
|
|
self.send_and_expect(self.pg3, p_west * NUM_PKTS, self.pg2)
|
2018-07-04 10:24:24 -07:00
|
|
|
self.vapi.acl_interface_set_acl_list(pipes[1].west,
|
|
|
|
0,
|
|
|
|
[])
|
2019-05-14 13:25:49 -04:00
|
|
|
self.send_and_expect(self.pg2, p_east * NUM_PKTS, self.pg3)
|
|
|
|
self.send_and_expect(self.pg3, p_west * NUM_PKTS, self.pg2)
|
2018-07-04 10:24:24 -07:00
|
|
|
|
|
|
|
# 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)
|