2 """ ACL plugin extended stateful tests """
5 from config import config
6 from framework import VppTestCase
7 from scapy.layers.inet import IP, UDP, TCP
8 from scapy.packet import Packet
9 from socket import AF_INET, AF_INET6
10 from scapy.layers.inet6 import IPv6
11 from util import L4_Conn
12 from ipaddress import ip_network
14 from vpp_acl import AclRule, VppAcl, VppAclInterface
17 def to_acl_rule(self, is_permit, wildcard_sport=False):
19 rule_family = AF_INET6 if p.haslayer(IPv6) else AF_INET
20 rule_prefix_len = 128 if p.haslayer(IPv6) else 32
21 rule_l3_layer = IPv6 if p.haslayer(IPv6) else IP
22 rule_l4_sport = p.sport
23 rule_l4_dport = p.dport
25 rule_l4_proto = p[IPv6].nh
27 rule_l4_proto = p[IP].proto
30 rule_l4_sport_first = 0
31 rule_l4_sport_last = 65535
33 rule_l4_sport_first = rule_l4_sport
34 rule_l4_sport_last = rule_l4_sport
39 src_prefix=ip_network((p[rule_l3_layer].src, rule_prefix_len)),
40 dst_prefix=ip_network((p[rule_l3_layer].dst, rule_prefix_len)),
41 sport_from=rule_l4_sport_first,
42 sport_to=rule_l4_sport_last,
43 dport_from=rule_l4_dport,
44 dport_to=rule_l4_dport,
50 Packet.to_acl_rule = to_acl_rule
53 class IterateWithSleep:
54 def __init__(self, testcase, n_iters, description, sleep_sec):
56 self.testcase = testcase
57 self.n_iters = n_iters
58 self.sleep_sec = sleep_sec
59 self.description = description
62 for x in range(0, self.n_iters):
64 self.testcase.sleep(self.sleep_sec)
68 def apply_acls(self, reflect_side, acl_side):
70 pkts.append(self.pkt(0))
71 pkts.append(self.pkt(1))
72 pkt = pkts[reflect_side]
75 r.append(pkt.to_acl_rule(2, wildcard_sport=True))
76 r.append(self.wildcard_rule(0))
77 reflect_acl = VppAcl(self.testcase, r)
78 reflect_acl.add_vpp_config()
81 r.append(self.wildcard_rule(0))
82 deny_acl = VppAcl(self.testcase, r)
83 deny_acl.add_vpp_config()
85 if reflect_side == acl_side:
86 acl_if0 = VppAclInterface(
88 self.ifs[acl_side].sw_if_index,
89 [reflect_acl, deny_acl],
92 acl_if1 = VppAclInterface(
93 self.testcase, self.ifs[1 - acl_side].sw_if_index, [], n_input=0
95 acl_if0.add_vpp_config()
96 acl_if1.add_vpp_config()
98 acl_if0 = VppAclInterface(
100 self.ifs[acl_side].sw_if_index,
101 [deny_acl, reflect_acl],
104 acl_if1 = VppAclInterface(
105 self.testcase, self.ifs[1 - acl_side].sw_if_index, [], n_input=0
107 acl_if0.add_vpp_config()
108 acl_if1.add_vpp_config()
110 def wildcard_rule(self, is_permit):
111 any_addr = ["0.0.0.0", "::"]
112 rule_family = self.address_family
113 is_ip6 = 1 if rule_family == AF_INET6 else 0
117 src_prefix=ip_network((any_addr[is_ip6], 0)),
118 dst_prefix=ip_network((any_addr[is_ip6], 0)),
127 @unittest.skipUnless(config.extended, "part of extended tests")
128 class ACLPluginConnTestCase(VppTestCase):
129 """ACL plugin connection-oriented extended testcases"""
133 super(ACLPluginConnTestCase, cls).setUpClass()
135 cls.create_pg_interfaces(range(2))
136 cmd = "set acl-plugin session table event-trace 1"
137 cls.logger.info(cls.vapi.cli(cmd))
138 for i in cls.pg_interfaces:
146 def tearDownClass(cls):
147 super(ACLPluginConnTestCase, cls).tearDownClass()
150 """Run standard test teardown and log various show commands"""
151 super(ACLPluginConnTestCase, self).tearDown()
153 def show_commands_at_teardown(self):
154 self.logger.info(self.vapi.cli("show ip neighbors"))
155 self.logger.info(self.vapi.cli("show ip6 neighbors"))
156 self.logger.info(self.vapi.cli("show acl-plugin sessions"))
157 self.logger.info(self.vapi.cli("show acl-plugin acl"))
158 self.logger.info(self.vapi.cli("show acl-plugin interface"))
159 self.logger.info(self.vapi.cli("show acl-plugin tables"))
160 self.logger.info(self.vapi.cli("show event-logger all"))
162 def run_basic_conn_test(self, af, acl_side):
163 """Basic conn timeout test"""
164 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242)
165 conn1.apply_acls(0, acl_side)
166 conn1.send_through(0)
167 # the return packets should pass
168 conn1.send_through(1)
169 # send some packets on conn1, ensure it doesn't go away
170 for i in IterateWithSleep(self, 20, "Keep conn active", 0.3):
171 conn1.send_through(1)
172 # allow the conn to time out
173 for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1):
175 # now try to send a packet on the reflected side
177 p2 = conn1.send_through(1).command()
179 # If we asserted while waiting, it's good.
180 # the conn should have timed out.
182 self.assert_equal(p2, None, "packet on long-idle conn")
184 def run_active_conn_test(self, af, acl_side):
185 """Idle connection behind active connection test"""
186 base = 10000 + 1000 * acl_side
187 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, base + 1, 2323)
188 conn2 = Conn(self, self.pg0, self.pg1, af, UDP, base + 2, 2323)
189 conn3 = Conn(self, self.pg0, self.pg1, af, UDP, base + 3, 2323)
190 conn1.apply_acls(0, acl_side)
193 # create and check that the conn2/3 work
195 conn2.send_pingpong(0)
197 conn3.send_pingpong(0)
198 # send some packets on conn1, keep conn2/3 idle
199 for i in IterateWithSleep(self, 20, "Keep conn active", 0.2):
200 conn1.send_through(1)
202 p2 = conn2.send_through(1).command()
204 # If we asserted while waiting, it's good.
205 # the conn should have timed out.
207 # We should have not received the packet on a long-idle
208 # connection, because it should have timed out
209 # If it didn't - it is a problem
210 self.assert_equal(p2, None, "packet on long-idle conn")
212 def run_clear_conn_test(self, af, acl_side):
213 """Clear the connections via CLI"""
214 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242)
215 conn1.apply_acls(0, acl_side)
216 conn1.send_through(0)
217 # the return packets should pass
218 conn1.send_through(1)
219 # send some packets on conn1, ensure it doesn't go away
220 for i in IterateWithSleep(self, 20, "Keep conn active", 0.3):
221 conn1.send_through(1)
222 # clear all connections
223 self.vapi.ppcli("clear acl-plugin sessions")
224 # now try to send a packet on the reflected side
226 p2 = conn1.send_through(1).command()
228 # If we asserted while waiting, it's good.
229 # the conn should have timed out.
231 self.assert_equal(p2, None, "packet on supposedly deleted conn")
233 def run_tcp_transient_setup_conn_test(self, af, acl_side):
234 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53001, 5151)
235 conn1.apply_acls(0, acl_side)
236 conn1.send_through(0, "S")
237 # the return packets should pass
238 conn1.send_through(1, "SA")
239 # allow the conn to time out
240 for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1):
242 # ensure conn times out
244 p2 = conn1.send_through(1).command()
246 # If we asserted while waiting, it's good.
247 # the conn should have timed out.
249 self.assert_equal(p2, None, "packet on supposedly deleted conn")
251 def run_tcp_established_conn_test(self, af, acl_side):
252 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052)
253 conn1.apply_acls(0, acl_side)
254 conn1.send_through(0, "S")
255 # the return packets should pass
256 conn1.send_through(1, "SA")
257 # complete the threeway handshake
258 # (NB: sequence numbers not tracked, so not set!)
259 conn1.send_through(0, "A")
260 # allow the conn to time out if it's in embryonic timer
261 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
263 # Try to send the packet from the "forbidden" side - it must pass
264 conn1.send_through(1, "A")
265 # ensure conn times out for real
266 for i in IterateWithSleep(self, 130, "Wait for timeout", 0.1):
269 p2 = conn1.send_through(1).command()
271 # If we asserted while waiting, it's good.
272 # the conn should have timed out.
274 self.assert_equal(p2, None, "packet on supposedly deleted conn")
276 def run_tcp_transient_teardown_conn_test(self, af, acl_side):
277 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052)
278 conn1.apply_acls(0, acl_side)
279 conn1.send_through(0, "S")
280 # the return packets should pass
281 conn1.send_through(1, "SA")
282 # complete the threeway handshake
283 # (NB: sequence numbers not tracked, so not set!)
284 conn1.send_through(0, "A")
285 # allow the conn to time out if it's in embryonic timer
286 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
288 # Try to send the packet from the "forbidden" side - it must pass
289 conn1.send_through(1, "A")
290 # Send the FIN to bounce the session out of established
291 conn1.send_through(1, "FA")
292 # If conn landed on transient timer it will time out here
293 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
295 # Now it should have timed out already
297 p2 = conn1.send_through(1).command()
299 # If we asserted while waiting, it's good.
300 # the conn should have timed out.
302 self.assert_equal(p2, None, "packet on supposedly deleted conn")
304 def test_0000_conn_prepare_test(self):
305 """Prepare the settings"""
306 self.vapi.ppcli("set acl-plugin session timeout udp idle 1")
308 def test_0001_basic_conn_test(self):
309 """IPv4: Basic conn timeout test reflect on ingress"""
310 self.run_basic_conn_test(AF_INET, 0)
312 def test_0002_basic_conn_test(self):
313 """IPv4: Basic conn timeout test reflect on egress"""
314 self.run_basic_conn_test(AF_INET, 1)
316 def test_0005_clear_conn_test(self):
317 """IPv4: reflect egress, clear conn"""
318 self.run_clear_conn_test(AF_INET, 1)
320 def test_0006_clear_conn_test(self):
321 """IPv4: reflect ingress, clear conn"""
322 self.run_clear_conn_test(AF_INET, 0)
324 def test_0011_active_conn_test(self):
325 """IPv4: Idle conn behind active conn, reflect on ingress"""
326 self.run_active_conn_test(AF_INET, 0)
328 def test_0012_active_conn_test(self):
329 """IPv4: Idle conn behind active conn, reflect on egress"""
330 self.run_active_conn_test(AF_INET, 1)
332 def test_1001_basic_conn_test(self):
333 """IPv6: Basic conn timeout test reflect on ingress"""
334 self.run_basic_conn_test(AF_INET6, 0)
336 def test_1002_basic_conn_test(self):
337 """IPv6: Basic conn timeout test reflect on egress"""
338 self.run_basic_conn_test(AF_INET6, 1)
340 def test_1005_clear_conn_test(self):
341 """IPv6: reflect egress, clear conn"""
342 self.run_clear_conn_test(AF_INET6, 1)
344 def test_1006_clear_conn_test(self):
345 """IPv6: reflect ingress, clear conn"""
346 self.run_clear_conn_test(AF_INET6, 0)
348 def test_1011_active_conn_test(self):
349 """IPv6: Idle conn behind active conn, reflect on ingress"""
350 self.run_active_conn_test(AF_INET6, 0)
352 def test_1012_active_conn_test(self):
353 """IPv6: Idle conn behind active conn, reflect on egress"""
354 self.run_active_conn_test(AF_INET6, 1)
356 def test_2000_prepare_for_tcp_test(self):
357 """Prepare for TCP session tests"""
358 # ensure the session hangs on if it gets treated as UDP
359 self.vapi.ppcli("set acl-plugin session timeout udp idle 200")
360 # let the TCP connection time out at 5 seconds
361 self.vapi.ppcli("set acl-plugin session timeout tcp idle 10")
362 self.vapi.ppcli("set acl-plugin session timeout tcp transient 1")
364 def test_2001_tcp_transient_conn_test(self):
365 """IPv4: transient TCP session (incomplete 3WHS), ref. on ingress"""
366 self.run_tcp_transient_setup_conn_test(AF_INET, 0)
368 def test_2002_tcp_transient_conn_test(self):
369 """IPv4: transient TCP session (incomplete 3WHS), ref. on egress"""
370 self.run_tcp_transient_setup_conn_test(AF_INET, 1)
372 def test_2003_tcp_transient_conn_test(self):
373 """IPv4: established TCP session (complete 3WHS), ref. on ingress"""
374 self.run_tcp_established_conn_test(AF_INET, 0)
376 def test_2004_tcp_transient_conn_test(self):
377 """IPv4: established TCP session (complete 3WHS), ref. on egress"""
378 self.run_tcp_established_conn_test(AF_INET, 1)
380 def test_2005_tcp_transient_teardown_conn_test(self):
381 """IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on ingress"""
382 self.run_tcp_transient_teardown_conn_test(AF_INET, 0)
384 def test_2006_tcp_transient_teardown_conn_test(self):
385 """IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on egress"""
386 self.run_tcp_transient_teardown_conn_test(AF_INET, 1)
388 def test_3001_tcp_transient_conn_test(self):
389 """IPv6: transient TCP session (incomplete 3WHS), ref. on ingress"""
390 self.run_tcp_transient_setup_conn_test(AF_INET6, 0)
392 def test_3002_tcp_transient_conn_test(self):
393 """IPv6: transient TCP session (incomplete 3WHS), ref. on egress"""
394 self.run_tcp_transient_setup_conn_test(AF_INET6, 1)
396 def test_3003_tcp_transient_conn_test(self):
397 """IPv6: established TCP session (complete 3WHS), ref. on ingress"""
398 self.run_tcp_established_conn_test(AF_INET6, 0)
400 def test_3004_tcp_transient_conn_test(self):
401 """IPv6: established TCP session (complete 3WHS), ref. on egress"""
402 self.run_tcp_established_conn_test(AF_INET6, 1)
404 def test_3005_tcp_transient_teardown_conn_test(self):
405 """IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on ingress"""
406 self.run_tcp_transient_teardown_conn_test(AF_INET6, 0)
408 def test_3006_tcp_transient_teardown_conn_test(self):
409 """IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on egress"""
410 self.run_tcp_transient_teardown_conn_test(AF_INET6, 1)