2 """ ACL plugin extended stateful tests """
5 from framework import VppTestCase, VppTestRunner, running_extended_tests
6 from scapy.layers.l2 import Ether
7 from scapy.packet import Raw
8 from scapy.layers.inet import IP, UDP, TCP
9 from scapy.packet import Packet
10 from socket import inet_pton, AF_INET, AF_INET6
11 from scapy.layers.inet6 import IPv6, ICMPv6Unknown, ICMPv6EchoRequest
12 from scapy.layers.inet6 import ICMPv6EchoReply, IPv6ExtHdrRouting
13 from scapy.layers.inet6 import IPv6ExtHdrFragment
14 from pprint import pprint
15 from random import randint
16 from util import L4_Conn
19 def to_acl_rule(self, is_permit, wildcard_sport=False):
21 rule_family = AF_INET6 if p.haslayer(IPv6) else AF_INET
22 rule_prefix_len = 128 if p.haslayer(IPv6) else 32
23 rule_l3_layer = IPv6 if p.haslayer(IPv6) else IP
24 rule_l4_sport = p.sport
25 rule_l4_dport = p.dport
27 rule_l4_proto = p[IPv6].nh
29 rule_l4_proto = p[IP].proto
32 rule_l4_sport_first = 0
33 rule_l4_sport_last = 65535
35 rule_l4_sport_first = rule_l4_sport
36 rule_l4_sport_last = rule_l4_sport
39 'is_permit': is_permit,
40 'is_ipv6': p.haslayer(IPv6),
41 'src_ip_addr': inet_pton(rule_family,
42 p[rule_l3_layer].src),
43 'src_ip_prefix_len': rule_prefix_len,
44 'dst_ip_addr': inet_pton(rule_family,
45 p[rule_l3_layer].dst),
46 'dst_ip_prefix_len': rule_prefix_len,
47 'srcport_or_icmptype_first': rule_l4_sport_first,
48 'srcport_or_icmptype_last': rule_l4_sport_last,
49 'dstport_or_icmpcode_first': rule_l4_dport,
50 'dstport_or_icmpcode_last': rule_l4_dport,
51 'proto': rule_l4_proto,
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 res = self.testcase.vapi.acl_add_replace(0xffffffff, r)
84 self.testcase.assert_equal(res.retval, 0, "error adding ACL")
85 reflect_acl_index = res.acl_index
88 r.append(self.wildcard_rule(0))
89 res = self.testcase.vapi.acl_add_replace(0xffffffff, r)
90 self.testcase.assert_equal(res.retval, 0, "error adding deny ACL")
91 deny_acl_index = res.acl_index
93 if reflect_side == acl_side:
94 self.testcase.vapi.acl_interface_set_acl_list(
95 self.ifs[acl_side].sw_if_index, 1,
98 self.testcase.vapi.acl_interface_set_acl_list(
99 self.ifs[1-acl_side].sw_if_index, 0, [])
101 self.testcase.vapi.acl_interface_set_acl_list(
102 self.ifs[acl_side].sw_if_index, 1,
105 self.testcase.vapi.acl_interface_set_acl_list(
106 self.ifs[1-acl_side].sw_if_index, 0, [])
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
113 'is_permit': is_permit,
115 'src_ip_addr': inet_pton(rule_family, any_addr[is_ip6]),
116 'src_ip_prefix_len': 0,
117 'dst_ip_addr': inet_pton(rule_family, any_addr[is_ip6]),
118 'dst_ip_prefix_len': 0,
119 'srcport_or_icmptype_first': 0,
120 'srcport_or_icmptype_last': 65535,
121 'dstport_or_icmpcode_first': 0,
122 'dstport_or_icmpcode_last': 65535,
128 @unittest.skipUnless(running_extended_tests, "part of extended tests")
129 class ACLPluginConnTestCase(VppTestCase):
130 """ ACL plugin connection-oriented extended testcases """
134 super(ACLPluginConnTestCase, cls).setUpClass()
136 cls.create_pg_interfaces(range(2))
137 cmd = "set acl-plugin session table event-trace 1"
138 cls.logger.info(cls.vapi.cli(cmd))
139 for i in cls.pg_interfaces:
147 def tearDownClass(cls):
148 super(ACLPluginConnTestCase, cls).tearDownClass()
151 """Run standard test teardown and log various show commands
153 super(ACLPluginConnTestCase, self).tearDown()
155 def show_commands_at_teardown(self):
156 self.logger.info(self.vapi.cli("show ip neighbors"))
157 self.logger.info(self.vapi.cli("show ip6 neighbors"))
158 self.logger.info(self.vapi.cli("show acl-plugin sessions"))
159 self.logger.info(self.vapi.cli("show acl-plugin acl"))
160 self.logger.info(self.vapi.cli("show acl-plugin interface"))
161 self.logger.info(self.vapi.cli("show acl-plugin tables"))
162 self.logger.info(self.vapi.cli("show event-logger all"))
164 def run_basic_conn_test(self, af, acl_side):
165 """ Basic conn timeout test """
166 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242)
167 conn1.apply_acls(0, acl_side)
168 conn1.send_through(0)
169 # the return packets should pass
170 conn1.send_through(1)
171 # send some packets on conn1, ensure it doesn't go away
172 for i in IterateWithSleep(self, 20, "Keep conn active", 0.3):
173 conn1.send_through(1)
174 # allow the conn to time out
175 for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1):
177 # now try to send a packet on the reflected side
179 p2 = conn1.send_through(1).command()
181 # If we asserted while waiting, it's good.
182 # the conn should have timed out.
184 self.assert_equal(p2, None, "packet on long-idle conn")
186 def run_active_conn_test(self, af, acl_side):
187 """ Idle connection behind active connection test """
188 base = 10000 + 1000*acl_side
189 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, base + 1, 2323)
190 conn2 = Conn(self, self.pg0, self.pg1, af, UDP, base + 2, 2323)
191 conn3 = Conn(self, self.pg0, self.pg1, af, UDP, base + 3, 2323)
192 conn1.apply_acls(0, acl_side)
195 # create and check that the conn2/3 work
197 conn2.send_pingpong(0)
199 conn3.send_pingpong(0)
200 # send some packets on conn1, keep conn2/3 idle
201 for i in IterateWithSleep(self, 20, "Keep conn active", 0.2):
202 conn1.send_through(1)
204 p2 = conn2.send_through(1).command()
206 # If we asserted while waiting, it's good.
207 # the conn should have timed out.
209 # We should have not received the packet on a long-idle
210 # connection, because it should have timed out
211 # If it didn't - it is a problem
212 self.assert_equal(p2, None, "packet on long-idle conn")
214 def run_clear_conn_test(self, af, acl_side):
215 """ Clear the connections via CLI """
216 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242)
217 conn1.apply_acls(0, acl_side)
218 conn1.send_through(0)
219 # the return packets should pass
220 conn1.send_through(1)
221 # send some packets on conn1, ensure it doesn't go away
222 for i in IterateWithSleep(self, 20, "Keep conn active", 0.3):
223 conn1.send_through(1)
224 # clear all connections
225 self.vapi.ppcli("clear acl-plugin sessions")
226 # now try to send a packet on the reflected side
228 p2 = conn1.send_through(1).command()
230 # If we asserted while waiting, it's good.
231 # the conn should have timed out.
233 self.assert_equal(p2, None, "packet on supposedly deleted conn")
235 def run_tcp_transient_setup_conn_test(self, af, acl_side):
236 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53001, 5151)
237 conn1.apply_acls(0, acl_side)
238 conn1.send_through(0, 'S')
239 # the return packets should pass
240 conn1.send_through(1, 'SA')
241 # allow the conn to time out
242 for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1):
244 # ensure conn times out
246 p2 = conn1.send_through(1).command()
248 # If we asserted while waiting, it's good.
249 # the conn should have timed out.
251 self.assert_equal(p2, None, "packet on supposedly deleted conn")
253 def run_tcp_established_conn_test(self, af, acl_side):
254 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052)
255 conn1.apply_acls(0, acl_side)
256 conn1.send_through(0, 'S')
257 # the return packets should pass
258 conn1.send_through(1, 'SA')
259 # complete the threeway handshake
260 # (NB: sequence numbers not tracked, so not set!)
261 conn1.send_through(0, 'A')
262 # allow the conn to time out if it's in embryonic timer
263 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
265 # Try to send the packet from the "forbidden" side - it must pass
266 conn1.send_through(1, 'A')
267 # ensure conn times out for real
268 for i in IterateWithSleep(self, 130, "Wait for timeout", 0.1):
271 p2 = conn1.send_through(1).command()
273 # If we asserted while waiting, it's good.
274 # the conn should have timed out.
276 self.assert_equal(p2, None, "packet on supposedly deleted conn")
278 def run_tcp_transient_teardown_conn_test(self, af, acl_side):
279 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052)
280 conn1.apply_acls(0, acl_side)
281 conn1.send_through(0, 'S')
282 # the return packets should pass
283 conn1.send_through(1, 'SA')
284 # complete the threeway handshake
285 # (NB: sequence numbers not tracked, so not set!)
286 conn1.send_through(0, 'A')
287 # allow the conn to time out if it's in embryonic timer
288 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
290 # Try to send the packet from the "forbidden" side - it must pass
291 conn1.send_through(1, 'A')
292 # Send the FIN to bounce the session out of established
293 conn1.send_through(1, 'FA')
294 # If conn landed on transient timer it will time out here
295 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
297 # Now it should have timed out already
299 p2 = conn1.send_through(1).command()
301 # If we asserted while waiting, it's good.
302 # the conn should have timed out.
304 self.assert_equal(p2, None, "packet on supposedly deleted conn")
306 def test_0000_conn_prepare_test(self):
307 """ Prepare the settings """
308 self.vapi.ppcli("set acl-plugin session timeout udp idle 1")
310 def test_0001_basic_conn_test(self):
311 """ IPv4: Basic conn timeout test reflect on ingress """
312 self.run_basic_conn_test(AF_INET, 0)
314 def test_0002_basic_conn_test(self):
315 """ IPv4: Basic conn timeout test reflect on egress """
316 self.run_basic_conn_test(AF_INET, 1)
318 def test_0005_clear_conn_test(self):
319 """ IPv4: reflect egress, clear conn """
320 self.run_clear_conn_test(AF_INET, 1)
322 def test_0006_clear_conn_test(self):
323 """ IPv4: reflect ingress, clear conn """
324 self.run_clear_conn_test(AF_INET, 0)
326 def test_0011_active_conn_test(self):
327 """ IPv4: Idle conn behind active conn, reflect on ingress """
328 self.run_active_conn_test(AF_INET, 0)
330 def test_0012_active_conn_test(self):
331 """ IPv4: Idle conn behind active conn, reflect on egress """
332 self.run_active_conn_test(AF_INET, 1)
334 def test_1001_basic_conn_test(self):
335 """ IPv6: Basic conn timeout test reflect on ingress """
336 self.run_basic_conn_test(AF_INET6, 0)
338 def test_1002_basic_conn_test(self):
339 """ IPv6: Basic conn timeout test reflect on egress """
340 self.run_basic_conn_test(AF_INET6, 1)
342 def test_1005_clear_conn_test(self):
343 """ IPv6: reflect egress, clear conn """
344 self.run_clear_conn_test(AF_INET6, 1)
346 def test_1006_clear_conn_test(self):
347 """ IPv6: reflect ingress, clear conn """
348 self.run_clear_conn_test(AF_INET6, 0)
350 def test_1011_active_conn_test(self):
351 """ IPv6: Idle conn behind active conn, reflect on ingress """
352 self.run_active_conn_test(AF_INET6, 0)
354 def test_1012_active_conn_test(self):
355 """ IPv6: Idle conn behind active conn, reflect on egress """
356 self.run_active_conn_test(AF_INET6, 1)
358 def test_2000_prepare_for_tcp_test(self):
359 """ Prepare for TCP session tests """
360 # ensure the session hangs on if it gets treated as UDP
361 self.vapi.ppcli("set acl-plugin session timeout udp idle 200")
362 # let the TCP connection time out at 5 seconds
363 self.vapi.ppcli("set acl-plugin session timeout tcp idle 10")
364 self.vapi.ppcli("set acl-plugin session timeout tcp transient 1")
366 def test_2001_tcp_transient_conn_test(self):
367 """ IPv4: transient TCP session (incomplete 3WHS), ref. on ingress """
368 self.run_tcp_transient_setup_conn_test(AF_INET, 0)
370 def test_2002_tcp_transient_conn_test(self):
371 """ IPv4: transient TCP session (incomplete 3WHS), ref. on egress """
372 self.run_tcp_transient_setup_conn_test(AF_INET, 1)
374 def test_2003_tcp_transient_conn_test(self):
375 """ IPv4: established TCP session (complete 3WHS), ref. on ingress """
376 self.run_tcp_established_conn_test(AF_INET, 0)
378 def test_2004_tcp_transient_conn_test(self):
379 """ IPv4: established TCP session (complete 3WHS), ref. on egress """
380 self.run_tcp_established_conn_test(AF_INET, 1)
382 def test_2005_tcp_transient_teardown_conn_test(self):
383 """ IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on ingress """
384 self.run_tcp_transient_teardown_conn_test(AF_INET, 0)
386 def test_2006_tcp_transient_teardown_conn_test(self):
387 """ IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on egress """
388 self.run_tcp_transient_teardown_conn_test(AF_INET, 1)
390 def test_3001_tcp_transient_conn_test(self):
391 """ IPv6: transient TCP session (incomplete 3WHS), ref. on ingress """
392 self.run_tcp_transient_setup_conn_test(AF_INET6, 0)
394 def test_3002_tcp_transient_conn_test(self):
395 """ IPv6: transient TCP session (incomplete 3WHS), ref. on egress """
396 self.run_tcp_transient_setup_conn_test(AF_INET6, 1)
398 def test_3003_tcp_transient_conn_test(self):
399 """ IPv6: established TCP session (complete 3WHS), ref. on ingress """
400 self.run_tcp_established_conn_test(AF_INET6, 0)
402 def test_3004_tcp_transient_conn_test(self):
403 """ IPv6: established TCP session (complete 3WHS), ref. on egress """
404 self.run_tcp_established_conn_test(AF_INET6, 1)
406 def test_3005_tcp_transient_teardown_conn_test(self):
407 """ IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on ingress """
408 self.run_tcp_transient_teardown_conn_test(AF_INET6, 0)
410 def test_3006_tcp_transient_teardown_conn_test(self):
411 """ IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on egress """
412 self.run_tcp_transient_teardown_conn_test(AF_INET6, 1)