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
45 src_prefix=ip_network((p[rule_l3_layer].src, rule_prefix_len)),
46 dst_prefix=ip_network((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,
50 dport_to=rule_l4_dport,
56 Packet.to_acl_rule = to_acl_rule
59 class IterateWithSleep:
60 def __init__(self, testcase, n_iters, description, sleep_sec):
62 self.testcase = testcase
63 self.n_iters = n_iters
64 self.sleep_sec = sleep_sec
65 self.description = description
68 for x in range(0, self.n_iters):
70 self.testcase.sleep(self.sleep_sec)
74 def apply_acls(self, reflect_side, acl_side):
76 pkts.append(self.pkt(0))
77 pkts.append(self.pkt(1))
78 pkt = pkts[reflect_side]
81 r.append(pkt.to_acl_rule(2, wildcard_sport=True))
82 r.append(self.wildcard_rule(0))
83 reflect_acl = VppAcl(self.testcase, r)
84 reflect_acl.add_vpp_config()
87 r.append(self.wildcard_rule(0))
88 deny_acl = VppAcl(self.testcase, r)
89 deny_acl.add_vpp_config()
91 if reflect_side == acl_side:
92 acl_if0 = VppAclInterface(
94 self.ifs[acl_side].sw_if_index,
95 [reflect_acl, deny_acl],
98 acl_if1 = VppAclInterface(
99 self.testcase, self.ifs[1 - acl_side].sw_if_index, [], n_input=0
101 acl_if0.add_vpp_config()
102 acl_if1.add_vpp_config()
104 acl_if0 = VppAclInterface(
106 self.ifs[acl_side].sw_if_index,
107 [deny_acl, reflect_acl],
110 acl_if1 = VppAclInterface(
111 self.testcase, self.ifs[1 - acl_side].sw_if_index, [], n_input=0
113 acl_if0.add_vpp_config()
114 acl_if1.add_vpp_config()
116 def wildcard_rule(self, is_permit):
117 any_addr = ["0.0.0.0", "::"]
118 rule_family = self.address_family
119 is_ip6 = 1 if rule_family == AF_INET6 else 0
123 src_prefix=ip_network((any_addr[is_ip6], 0)),
124 dst_prefix=ip_network((any_addr[is_ip6], 0)),
133 @unittest.skipUnless(config.extended, "part of extended tests")
134 class ACLPluginConnTestCase(VppTestCase):
135 """ACL plugin connection-oriented extended testcases"""
139 super(ACLPluginConnTestCase, cls).setUpClass()
141 cls.create_pg_interfaces(range(2))
142 cmd = "set acl-plugin session table event-trace 1"
143 cls.logger.info(cls.vapi.cli(cmd))
144 for i in cls.pg_interfaces:
152 def tearDownClass(cls):
153 super(ACLPluginConnTestCase, cls).tearDownClass()
156 """Run standard test teardown and log various show commands"""
157 super(ACLPluginConnTestCase, self).tearDown()
159 def show_commands_at_teardown(self):
160 self.logger.info(self.vapi.cli("show ip neighbors"))
161 self.logger.info(self.vapi.cli("show ip6 neighbors"))
162 self.logger.info(self.vapi.cli("show acl-plugin sessions"))
163 self.logger.info(self.vapi.cli("show acl-plugin acl"))
164 self.logger.info(self.vapi.cli("show acl-plugin interface"))
165 self.logger.info(self.vapi.cli("show acl-plugin tables"))
166 self.logger.info(self.vapi.cli("show event-logger all"))
168 def run_basic_conn_test(self, af, acl_side):
169 """Basic conn timeout test"""
170 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242)
171 conn1.apply_acls(0, acl_side)
172 conn1.send_through(0)
173 # the return packets should pass
174 conn1.send_through(1)
175 # send some packets on conn1, ensure it doesn't go away
176 for i in IterateWithSleep(self, 20, "Keep conn active", 0.3):
177 conn1.send_through(1)
178 # allow the conn to time out
179 for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1):
181 # now try to send a packet on the reflected side
183 p2 = conn1.send_through(1).command()
185 # If we asserted while waiting, it's good.
186 # the conn should have timed out.
188 self.assert_equal(p2, None, "packet on long-idle conn")
190 def run_active_conn_test(self, af, acl_side):
191 """Idle connection behind active connection test"""
192 base = 10000 + 1000 * acl_side
193 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, base + 1, 2323)
194 conn2 = Conn(self, self.pg0, self.pg1, af, UDP, base + 2, 2323)
195 conn3 = Conn(self, self.pg0, self.pg1, af, UDP, base + 3, 2323)
196 conn1.apply_acls(0, acl_side)
199 # create and check that the conn2/3 work
201 conn2.send_pingpong(0)
203 conn3.send_pingpong(0)
204 # send some packets on conn1, keep conn2/3 idle
205 for i in IterateWithSleep(self, 20, "Keep conn active", 0.2):
206 conn1.send_through(1)
208 p2 = conn2.send_through(1).command()
210 # If we asserted while waiting, it's good.
211 # the conn should have timed out.
213 # We should have not received the packet on a long-idle
214 # connection, because it should have timed out
215 # If it didn't - it is a problem
216 self.assert_equal(p2, None, "packet on long-idle conn")
218 def run_clear_conn_test(self, af, acl_side):
219 """Clear the connections via CLI"""
220 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242)
221 conn1.apply_acls(0, acl_side)
222 conn1.send_through(0)
223 # the return packets should pass
224 conn1.send_through(1)
225 # send some packets on conn1, ensure it doesn't go away
226 for i in IterateWithSleep(self, 20, "Keep conn active", 0.3):
227 conn1.send_through(1)
228 # clear all connections
229 self.vapi.ppcli("clear acl-plugin sessions")
230 # now try to send a packet on the reflected side
232 p2 = conn1.send_through(1).command()
234 # If we asserted while waiting, it's good.
235 # the conn should have timed out.
237 self.assert_equal(p2, None, "packet on supposedly deleted conn")
239 def run_tcp_transient_setup_conn_test(self, af, acl_side):
240 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53001, 5151)
241 conn1.apply_acls(0, acl_side)
242 conn1.send_through(0, "S")
243 # the return packets should pass
244 conn1.send_through(1, "SA")
245 # allow the conn to time out
246 for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1):
248 # ensure conn times out
250 p2 = conn1.send_through(1).command()
252 # If we asserted while waiting, it's good.
253 # the conn should have timed out.
255 self.assert_equal(p2, None, "packet on supposedly deleted conn")
257 def run_tcp_established_conn_test(self, af, acl_side):
258 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052)
259 conn1.apply_acls(0, acl_side)
260 conn1.send_through(0, "S")
261 # the return packets should pass
262 conn1.send_through(1, "SA")
263 # complete the threeway handshake
264 # (NB: sequence numbers not tracked, so not set!)
265 conn1.send_through(0, "A")
266 # allow the conn to time out if it's in embryonic timer
267 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
269 # Try to send the packet from the "forbidden" side - it must pass
270 conn1.send_through(1, "A")
271 # ensure conn times out for real
272 for i in IterateWithSleep(self, 130, "Wait for timeout", 0.1):
275 p2 = conn1.send_through(1).command()
277 # If we asserted while waiting, it's good.
278 # the conn should have timed out.
280 self.assert_equal(p2, None, "packet on supposedly deleted conn")
282 def run_tcp_transient_teardown_conn_test(self, af, acl_side):
283 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052)
284 conn1.apply_acls(0, acl_side)
285 conn1.send_through(0, "S")
286 # the return packets should pass
287 conn1.send_through(1, "SA")
288 # complete the threeway handshake
289 # (NB: sequence numbers not tracked, so not set!)
290 conn1.send_through(0, "A")
291 # allow the conn to time out if it's in embryonic timer
292 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
294 # Try to send the packet from the "forbidden" side - it must pass
295 conn1.send_through(1, "A")
296 # Send the FIN to bounce the session out of established
297 conn1.send_through(1, "FA")
298 # If conn landed on transient timer it will time out here
299 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
301 # Now it should have timed out already
303 p2 = conn1.send_through(1).command()
305 # If we asserted while waiting, it's good.
306 # the conn should have timed out.
308 self.assert_equal(p2, None, "packet on supposedly deleted conn")
310 def test_0000_conn_prepare_test(self):
311 """Prepare the settings"""
312 self.vapi.ppcli("set acl-plugin session timeout udp idle 1")
314 def test_0001_basic_conn_test(self):
315 """IPv4: Basic conn timeout test reflect on ingress"""
316 self.run_basic_conn_test(AF_INET, 0)
318 def test_0002_basic_conn_test(self):
319 """IPv4: Basic conn timeout test reflect on egress"""
320 self.run_basic_conn_test(AF_INET, 1)
322 def test_0005_clear_conn_test(self):
323 """IPv4: reflect egress, clear conn"""
324 self.run_clear_conn_test(AF_INET, 1)
326 def test_0006_clear_conn_test(self):
327 """IPv4: reflect ingress, clear conn"""
328 self.run_clear_conn_test(AF_INET, 0)
330 def test_0011_active_conn_test(self):
331 """IPv4: Idle conn behind active conn, reflect on ingress"""
332 self.run_active_conn_test(AF_INET, 0)
334 def test_0012_active_conn_test(self):
335 """IPv4: Idle conn behind active conn, reflect on egress"""
336 self.run_active_conn_test(AF_INET, 1)
338 def test_1001_basic_conn_test(self):
339 """IPv6: Basic conn timeout test reflect on ingress"""
340 self.run_basic_conn_test(AF_INET6, 0)
342 def test_1002_basic_conn_test(self):
343 """IPv6: Basic conn timeout test reflect on egress"""
344 self.run_basic_conn_test(AF_INET6, 1)
346 def test_1005_clear_conn_test(self):
347 """IPv6: reflect egress, clear conn"""
348 self.run_clear_conn_test(AF_INET6, 1)
350 def test_1006_clear_conn_test(self):
351 """IPv6: reflect ingress, clear conn"""
352 self.run_clear_conn_test(AF_INET6, 0)
354 def test_1011_active_conn_test(self):
355 """IPv6: Idle conn behind active conn, reflect on ingress"""
356 self.run_active_conn_test(AF_INET6, 0)
358 def test_1012_active_conn_test(self):
359 """IPv6: Idle conn behind active conn, reflect on egress"""
360 self.run_active_conn_test(AF_INET6, 1)
362 def test_2000_prepare_for_tcp_test(self):
363 """Prepare for TCP session tests"""
364 # ensure the session hangs on if it gets treated as UDP
365 self.vapi.ppcli("set acl-plugin session timeout udp idle 200")
366 # let the TCP connection time out at 5 seconds
367 self.vapi.ppcli("set acl-plugin session timeout tcp idle 10")
368 self.vapi.ppcli("set acl-plugin session timeout tcp transient 1")
370 def test_2001_tcp_transient_conn_test(self):
371 """IPv4: transient TCP session (incomplete 3WHS), ref. on ingress"""
372 self.run_tcp_transient_setup_conn_test(AF_INET, 0)
374 def test_2002_tcp_transient_conn_test(self):
375 """IPv4: transient TCP session (incomplete 3WHS), ref. on egress"""
376 self.run_tcp_transient_setup_conn_test(AF_INET, 1)
378 def test_2003_tcp_transient_conn_test(self):
379 """IPv4: established TCP session (complete 3WHS), ref. on ingress"""
380 self.run_tcp_established_conn_test(AF_INET, 0)
382 def test_2004_tcp_transient_conn_test(self):
383 """IPv4: established TCP session (complete 3WHS), ref. on egress"""
384 self.run_tcp_established_conn_test(AF_INET, 1)
386 def test_2005_tcp_transient_teardown_conn_test(self):
387 """IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on ingress"""
388 self.run_tcp_transient_teardown_conn_test(AF_INET, 0)
390 def test_2006_tcp_transient_teardown_conn_test(self):
391 """IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on egress"""
392 self.run_tcp_transient_teardown_conn_test(AF_INET, 1)
394 def test_3001_tcp_transient_conn_test(self):
395 """IPv6: transient TCP session (incomplete 3WHS), ref. on ingress"""
396 self.run_tcp_transient_setup_conn_test(AF_INET6, 0)
398 def test_3002_tcp_transient_conn_test(self):
399 """IPv6: transient TCP session (incomplete 3WHS), ref. on egress"""
400 self.run_tcp_transient_setup_conn_test(AF_INET6, 1)
402 def test_3003_tcp_transient_conn_test(self):
403 """IPv6: established TCP session (complete 3WHS), ref. on ingress"""
404 self.run_tcp_established_conn_test(AF_INET6, 0)
406 def test_3004_tcp_transient_conn_test(self):
407 """IPv6: established TCP session (complete 3WHS), ref. on egress"""
408 self.run_tcp_established_conn_test(AF_INET6, 1)
410 def test_3005_tcp_transient_teardown_conn_test(self):
411 """IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on ingress"""
412 self.run_tcp_transient_teardown_conn_test(AF_INET6, 0)
414 def test_3006_tcp_transient_teardown_conn_test(self):
415 """IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on egress"""
416 self.run_tcp_transient_teardown_conn_test(AF_INET6, 1)