2 """ ACL plugin extended stateful tests """
5 from config import config
6 from framework import VppTestCase, VppTestRunner
7 from scapy.layers.l2 import Ether
8 from scapy.packet import Raw
9 from scapy.layers.inet import IP, UDP, TCP
10 from scapy.packet import Packet
11 from socket import inet_pton, AF_INET, AF_INET6
12 from scapy.layers.inet6 import IPv6, ICMPv6Unknown, ICMPv6EchoRequest
13 from scapy.layers.inet6 import ICMPv6EchoReply, IPv6ExtHdrRouting
14 from scapy.layers.inet6 import IPv6ExtHdrFragment
15 from pprint import pprint
16 from random import randint
17 from util import L4_Conn
18 from ipaddress import ip_network
20 from vpp_acl import AclRule, VppAcl, VppAclInterface
23 def to_acl_rule(self, is_permit, wildcard_sport=False):
25 rule_family = AF_INET6 if p.haslayer(IPv6) else AF_INET
26 rule_prefix_len = 128 if p.haslayer(IPv6) else 32
27 rule_l3_layer = IPv6 if p.haslayer(IPv6) else IP
28 rule_l4_sport = p.sport
29 rule_l4_dport = p.dport
31 rule_l4_proto = p[IPv6].nh
33 rule_l4_proto = p[IP].proto
36 rule_l4_sport_first = 0
37 rule_l4_sport_last = 65535
39 rule_l4_sport_first = rule_l4_sport
40 rule_l4_sport_last = rule_l4_sport
42 new_rule = AclRule(is_permit=is_permit, proto=rule_l4_proto,
43 src_prefix=ip_network(
44 (p[rule_l3_layer].src, rule_prefix_len)),
45 dst_prefix=ip_network(
46 (p[rule_l3_layer].dst, rule_prefix_len)),
47 sport_from=rule_l4_sport_first,
48 sport_to=rule_l4_sport_last,
49 dport_from=rule_l4_dport, dport_to=rule_l4_dport)
54 Packet.to_acl_rule = to_acl_rule
57 class IterateWithSleep():
58 def __init__(self, testcase, n_iters, description, sleep_sec):
60 self.testcase = testcase
61 self.n_iters = n_iters
62 self.sleep_sec = sleep_sec
63 self.description = description
66 for x in range(0, self.n_iters):
68 self.testcase.sleep(self.sleep_sec)
72 def apply_acls(self, reflect_side, acl_side):
74 pkts.append(self.pkt(0))
75 pkts.append(self.pkt(1))
76 pkt = pkts[reflect_side]
79 r.append(pkt.to_acl_rule(2, wildcard_sport=True))
80 r.append(self.wildcard_rule(0))
81 reflect_acl = VppAcl(self.testcase, r)
82 reflect_acl.add_vpp_config()
85 r.append(self.wildcard_rule(0))
86 deny_acl = VppAcl(self.testcase, r)
87 deny_acl.add_vpp_config()
89 if reflect_side == acl_side:
90 acl_if0 = VppAclInterface(self.testcase,
91 self.ifs[acl_side].sw_if_index,
92 [reflect_acl, deny_acl], n_input=1)
93 acl_if1 = VppAclInterface(self.testcase,
94 self.ifs[1-acl_side].sw_if_index, [],
96 acl_if0.add_vpp_config()
97 acl_if1.add_vpp_config()
99 acl_if0 = VppAclInterface(self.testcase,
100 self.ifs[acl_side].sw_if_index,
101 [deny_acl, reflect_acl], n_input=1)
102 acl_if1 = VppAclInterface(self.testcase,
103 self.ifs[1-acl_side].sw_if_index, [],
105 acl_if0.add_vpp_config()
106 acl_if1.add_vpp_config()
108 def wildcard_rule(self, is_permit):
109 any_addr = ["0.0.0.0", "::"]
110 rule_family = self.address_family
111 is_ip6 = 1 if rule_family == AF_INET6 else 0
112 new_rule = AclRule(is_permit=is_permit, proto=0,
113 src_prefix=ip_network(
114 (any_addr[is_ip6], 0)),
115 dst_prefix=ip_network(
116 (any_addr[is_ip6], 0)),
117 sport_from=0, sport_to=65535, dport_from=0,
122 @unittest.skipUnless(config.extended, "part of extended tests")
123 class ACLPluginConnTestCase(VppTestCase):
124 """ ACL plugin connection-oriented extended testcases """
128 super(ACLPluginConnTestCase, cls).setUpClass()
130 cls.create_pg_interfaces(range(2))
131 cmd = "set acl-plugin session table event-trace 1"
132 cls.logger.info(cls.vapi.cli(cmd))
133 for i in cls.pg_interfaces:
141 def tearDownClass(cls):
142 super(ACLPluginConnTestCase, cls).tearDownClass()
145 """Run standard test teardown and log various show commands
147 super(ACLPluginConnTestCase, self).tearDown()
149 def show_commands_at_teardown(self):
150 self.logger.info(self.vapi.cli("show ip neighbors"))
151 self.logger.info(self.vapi.cli("show ip6 neighbors"))
152 self.logger.info(self.vapi.cli("show acl-plugin sessions"))
153 self.logger.info(self.vapi.cli("show acl-plugin acl"))
154 self.logger.info(self.vapi.cli("show acl-plugin interface"))
155 self.logger.info(self.vapi.cli("show acl-plugin tables"))
156 self.logger.info(self.vapi.cli("show event-logger all"))
158 def run_basic_conn_test(self, af, acl_side):
159 """ Basic conn timeout test """
160 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242)
161 conn1.apply_acls(0, acl_side)
162 conn1.send_through(0)
163 # the return packets should pass
164 conn1.send_through(1)
165 # send some packets on conn1, ensure it doesn't go away
166 for i in IterateWithSleep(self, 20, "Keep conn active", 0.3):
167 conn1.send_through(1)
168 # allow the conn to time out
169 for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1):
171 # now try to send a packet on the reflected side
173 p2 = conn1.send_through(1).command()
175 # If we asserted while waiting, it's good.
176 # the conn should have timed out.
178 self.assert_equal(p2, None, "packet on long-idle conn")
180 def run_active_conn_test(self, af, acl_side):
181 """ Idle connection behind active connection test """
182 base = 10000 + 1000*acl_side
183 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, base + 1, 2323)
184 conn2 = Conn(self, self.pg0, self.pg1, af, UDP, base + 2, 2323)
185 conn3 = Conn(self, self.pg0, self.pg1, af, UDP, base + 3, 2323)
186 conn1.apply_acls(0, acl_side)
189 # create and check that the conn2/3 work
191 conn2.send_pingpong(0)
193 conn3.send_pingpong(0)
194 # send some packets on conn1, keep conn2/3 idle
195 for i in IterateWithSleep(self, 20, "Keep conn active", 0.2):
196 conn1.send_through(1)
198 p2 = conn2.send_through(1).command()
200 # If we asserted while waiting, it's good.
201 # the conn should have timed out.
203 # We should have not received the packet on a long-idle
204 # connection, because it should have timed out
205 # If it didn't - it is a problem
206 self.assert_equal(p2, None, "packet on long-idle conn")
208 def run_clear_conn_test(self, af, acl_side):
209 """ Clear the connections via CLI """
210 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242)
211 conn1.apply_acls(0, acl_side)
212 conn1.send_through(0)
213 # the return packets should pass
214 conn1.send_through(1)
215 # send some packets on conn1, ensure it doesn't go away
216 for i in IterateWithSleep(self, 20, "Keep conn active", 0.3):
217 conn1.send_through(1)
218 # clear all connections
219 self.vapi.ppcli("clear acl-plugin sessions")
220 # now try to send a packet on the reflected side
222 p2 = conn1.send_through(1).command()
224 # If we asserted while waiting, it's good.
225 # the conn should have timed out.
227 self.assert_equal(p2, None, "packet on supposedly deleted conn")
229 def run_tcp_transient_setup_conn_test(self, af, acl_side):
230 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53001, 5151)
231 conn1.apply_acls(0, acl_side)
232 conn1.send_through(0, 'S')
233 # the return packets should pass
234 conn1.send_through(1, 'SA')
235 # allow the conn to time out
236 for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1):
238 # ensure conn times out
240 p2 = conn1.send_through(1).command()
242 # If we asserted while waiting, it's good.
243 # the conn should have timed out.
245 self.assert_equal(p2, None, "packet on supposedly deleted conn")
247 def run_tcp_established_conn_test(self, af, acl_side):
248 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052)
249 conn1.apply_acls(0, acl_side)
250 conn1.send_through(0, 'S')
251 # the return packets should pass
252 conn1.send_through(1, 'SA')
253 # complete the threeway handshake
254 # (NB: sequence numbers not tracked, so not set!)
255 conn1.send_through(0, 'A')
256 # allow the conn to time out if it's in embryonic timer
257 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
259 # Try to send the packet from the "forbidden" side - it must pass
260 conn1.send_through(1, 'A')
261 # ensure conn times out for real
262 for i in IterateWithSleep(self, 130, "Wait for timeout", 0.1):
265 p2 = conn1.send_through(1).command()
267 # If we asserted while waiting, it's good.
268 # the conn should have timed out.
270 self.assert_equal(p2, None, "packet on supposedly deleted conn")
272 def run_tcp_transient_teardown_conn_test(self, af, acl_side):
273 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052)
274 conn1.apply_acls(0, acl_side)
275 conn1.send_through(0, 'S')
276 # the return packets should pass
277 conn1.send_through(1, 'SA')
278 # complete the threeway handshake
279 # (NB: sequence numbers not tracked, so not set!)
280 conn1.send_through(0, 'A')
281 # allow the conn to time out if it's in embryonic timer
282 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
284 # Try to send the packet from the "forbidden" side - it must pass
285 conn1.send_through(1, 'A')
286 # Send the FIN to bounce the session out of established
287 conn1.send_through(1, 'FA')
288 # If conn landed on transient timer it will time out here
289 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
291 # Now it should have timed out already
293 p2 = conn1.send_through(1).command()
295 # If we asserted while waiting, it's good.
296 # the conn should have timed out.
298 self.assert_equal(p2, None, "packet on supposedly deleted conn")
300 def test_0000_conn_prepare_test(self):
301 """ Prepare the settings """
302 self.vapi.ppcli("set acl-plugin session timeout udp idle 1")
304 def test_0001_basic_conn_test(self):
305 """ IPv4: Basic conn timeout test reflect on ingress """
306 self.run_basic_conn_test(AF_INET, 0)
308 def test_0002_basic_conn_test(self):
309 """ IPv4: Basic conn timeout test reflect on egress """
310 self.run_basic_conn_test(AF_INET, 1)
312 def test_0005_clear_conn_test(self):
313 """ IPv4: reflect egress, clear conn """
314 self.run_clear_conn_test(AF_INET, 1)
316 def test_0006_clear_conn_test(self):
317 """ IPv4: reflect ingress, clear conn """
318 self.run_clear_conn_test(AF_INET, 0)
320 def test_0011_active_conn_test(self):
321 """ IPv4: Idle conn behind active conn, reflect on ingress """
322 self.run_active_conn_test(AF_INET, 0)
324 def test_0012_active_conn_test(self):
325 """ IPv4: Idle conn behind active conn, reflect on egress """
326 self.run_active_conn_test(AF_INET, 1)
328 def test_1001_basic_conn_test(self):
329 """ IPv6: Basic conn timeout test reflect on ingress """
330 self.run_basic_conn_test(AF_INET6, 0)
332 def test_1002_basic_conn_test(self):
333 """ IPv6: Basic conn timeout test reflect on egress """
334 self.run_basic_conn_test(AF_INET6, 1)
336 def test_1005_clear_conn_test(self):
337 """ IPv6: reflect egress, clear conn """
338 self.run_clear_conn_test(AF_INET6, 1)
340 def test_1006_clear_conn_test(self):
341 """ IPv6: reflect ingress, clear conn """
342 self.run_clear_conn_test(AF_INET6, 0)
344 def test_1011_active_conn_test(self):
345 """ IPv6: Idle conn behind active conn, reflect on ingress """
346 self.run_active_conn_test(AF_INET6, 0)
348 def test_1012_active_conn_test(self):
349 """ IPv6: Idle conn behind active conn, reflect on egress """
350 self.run_active_conn_test(AF_INET6, 1)
352 def test_2000_prepare_for_tcp_test(self):
353 """ Prepare for TCP session tests """
354 # ensure the session hangs on if it gets treated as UDP
355 self.vapi.ppcli("set acl-plugin session timeout udp idle 200")
356 # let the TCP connection time out at 5 seconds
357 self.vapi.ppcli("set acl-plugin session timeout tcp idle 10")
358 self.vapi.ppcli("set acl-plugin session timeout tcp transient 1")
360 def test_2001_tcp_transient_conn_test(self):
361 """ IPv4: transient TCP session (incomplete 3WHS), ref. on ingress """
362 self.run_tcp_transient_setup_conn_test(AF_INET, 0)
364 def test_2002_tcp_transient_conn_test(self):
365 """ IPv4: transient TCP session (incomplete 3WHS), ref. on egress """
366 self.run_tcp_transient_setup_conn_test(AF_INET, 1)
368 def test_2003_tcp_transient_conn_test(self):
369 """ IPv4: established TCP session (complete 3WHS), ref. on ingress """
370 self.run_tcp_established_conn_test(AF_INET, 0)
372 def test_2004_tcp_transient_conn_test(self):
373 """ IPv4: established TCP session (complete 3WHS), ref. on egress """
374 self.run_tcp_established_conn_test(AF_INET, 1)
376 def test_2005_tcp_transient_teardown_conn_test(self):
377 """ IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on ingress """
378 self.run_tcp_transient_teardown_conn_test(AF_INET, 0)
380 def test_2006_tcp_transient_teardown_conn_test(self):
381 """ IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on egress """
382 self.run_tcp_transient_teardown_conn_test(AF_INET, 1)
384 def test_3001_tcp_transient_conn_test(self):
385 """ IPv6: transient TCP session (incomplete 3WHS), ref. on ingress """
386 self.run_tcp_transient_setup_conn_test(AF_INET6, 0)
388 def test_3002_tcp_transient_conn_test(self):
389 """ IPv6: transient TCP session (incomplete 3WHS), ref. on egress """
390 self.run_tcp_transient_setup_conn_test(AF_INET6, 1)
392 def test_3003_tcp_transient_conn_test(self):
393 """ IPv6: established TCP session (complete 3WHS), ref. on ingress """
394 self.run_tcp_established_conn_test(AF_INET6, 0)
396 def test_3004_tcp_transient_conn_test(self):
397 """ IPv6: established TCP session (complete 3WHS), ref. on egress """
398 self.run_tcp_established_conn_test(AF_INET6, 1)
400 def test_3005_tcp_transient_teardown_conn_test(self):
401 """ IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on ingress """
402 self.run_tcp_transient_teardown_conn_test(AF_INET6, 0)
404 def test_3006_tcp_transient_teardown_conn_test(self):
405 """ IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on egress """
406 self.run_tcp_transient_teardown_conn_test(AF_INET6, 1)