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,
55 Packet.to_acl_rule = to_acl_rule
58 class IterateWithSleep():
59 def __init__(self, testcase, n_iters, description, sleep_sec):
61 self.testcase = testcase
62 self.n_iters = n_iters
63 self.sleep_sec = sleep_sec
64 self.description = description
67 for x in range(0, self.n_iters):
69 self.testcase.sleep(self.sleep_sec)
73 def apply_acls(self, reflect_side, acl_side):
75 pkts.append(self.pkt(0))
76 pkts.append(self.pkt(1))
77 pkt = pkts[reflect_side]
80 r.append(pkt.to_acl_rule(2, wildcard_sport=True))
81 r.append(self.wildcard_rule(0))
82 res = self.testcase.api_acl_add_replace(0xffffffff, r)
83 self.testcase.assert_equal(res.retval, 0, "error adding ACL")
84 reflect_acl_index = res.acl_index
87 r.append(self.wildcard_rule(0))
88 res = self.testcase.api_acl_add_replace(0xffffffff, r)
89 self.testcase.assert_equal(res.retval, 0, "error adding deny ACL")
90 deny_acl_index = res.acl_index
92 if reflect_side == acl_side:
93 self.testcase.api_acl_interface_set_acl_list(
94 self.ifs[acl_side].sw_if_index, 2, 1,
97 self.testcase.api_acl_interface_set_acl_list(
98 self.ifs[1-acl_side].sw_if_index, 0, 0, [])
100 self.testcase.api_acl_interface_set_acl_list(
101 self.ifs[acl_side].sw_if_index, 2, 1,
104 self.testcase.api_acl_interface_set_acl_list(
105 self.ifs[1-acl_side].sw_if_index, 0, 0, [])
107 def wildcard_rule(self, is_permit):
108 any_addr = ["0.0.0.0", "::"]
109 rule_family = self.address_family
110 is_ip6 = 1 if rule_family == AF_INET6 else 0
112 'is_permit': is_permit,
114 'src_ip_addr': inet_pton(rule_family, any_addr[is_ip6]),
115 'src_ip_prefix_len': 0,
116 'dst_ip_addr': inet_pton(rule_family, any_addr[is_ip6]),
117 'dst_ip_prefix_len': 0,
118 'srcport_or_icmptype_first': 0,
119 'srcport_or_icmptype_last': 65535,
120 'dstport_or_icmpcode_first': 0,
121 'dstport_or_icmpcode_last': 65535,
127 @unittest.skipUnless(running_extended_tests(), "part of extended tests")
128 class ACLPluginConnTestCase(VppTestCase):
129 """ ACL plugin connection-oriented extended testcases """
132 def setUpClass(self):
133 super(ACLPluginConnTestCase, self).setUpClass()
135 self.create_pg_interfaces(range(2))
136 for i in self.pg_interfaces:
144 """Run standard test teardown and log various show commands
146 super(ACLPluginConnTestCase, self).tearDown()
147 if not self.vpp_dead:
148 self.logger.info(self.vapi.cli("show ip arp"))
149 self.logger.info(self.vapi.cli("show ip6 neighbors"))
150 self.logger.info(self.vapi.cli("show acl-plugin sessions"))
151 self.logger.info(self.vapi.cli("show acl-plugin acl"))
152 self.logger.info(self.vapi.cli("show acl-plugin interface"))
153 self.logger.info(self.vapi.cli("show acl-plugin tables"))
155 def api_acl_add_replace(self, acl_index, r, count=-1, tag="",
157 """Add/replace an ACL
159 :param int acl_index: ACL index to replace, 4294967295 to create new.
160 :param acl_rule r: ACL rules array.
161 :param str tag: symbolic tag (description) for this ACL.
162 :param int count: number of rules.
166 return self.vapi.api(self.vapi.papi.acl_add_replace,
167 {'acl_index': acl_index,
171 }, expected_retval=expected_retval)
173 def api_acl_interface_set_acl_list(self, sw_if_index, count, n_input, acls,
175 return self.vapi.api(self.vapi.papi.acl_interface_set_acl_list,
176 {'sw_if_index': sw_if_index,
180 }, expected_retval=expected_retval)
182 def api_acl_dump(self, acl_index, expected_retval=0):
183 return self.vapi.api(self.vapi.papi.acl_dump,
184 {'acl_index': acl_index},
185 expected_retval=expected_retval)
187 def run_basic_conn_test(self, af, acl_side):
188 """ Basic conn timeout test """
189 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242)
190 conn1.apply_acls(0, acl_side)
191 conn1.send_through(0)
192 # the return packets should pass
193 conn1.send_through(1)
194 # send some packets on conn1, ensure it doesn't go away
195 for i in IterateWithSleep(self, 20, "Keep conn active", 0.3):
196 conn1.send_through(1)
197 # allow the conn to time out
198 for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1):
200 # now try to send a packet on the reflected side
202 p2 = conn1.send_through(1).command()
204 # If we asserted while waiting, it's good.
205 # the conn should have timed out.
207 self.assert_equal(p2, None, "packet on long-idle conn")
209 def run_active_conn_test(self, af, acl_side):
210 """ Idle connection behind active connection test """
211 base = 10000 + 1000*acl_side
212 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, base + 1, 2323)
213 conn2 = Conn(self, self.pg0, self.pg1, af, UDP, base + 2, 2323)
214 conn3 = Conn(self, self.pg0, self.pg1, af, UDP, base + 3, 2323)
215 conn1.apply_acls(0, acl_side)
218 # create and check that the conn2/3 work
220 conn2.send_pingpong(0)
222 conn3.send_pingpong(0)
223 # send some packets on conn1, keep conn2/3 idle
224 for i in IterateWithSleep(self, 20, "Keep conn active", 0.2):
225 conn1.send_through(1)
227 p2 = conn2.send_through(1).command()
229 # If we asserted while waiting, it's good.
230 # the conn should have timed out.
232 # We should have not received the packet on a long-idle
233 # connection, because it should have timed out
234 # If it didn't - it is a problem
235 self.assert_equal(p2, None, "packet on long-idle conn")
237 def run_clear_conn_test(self, af, acl_side):
238 """ Clear the connections via CLI """
239 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242)
240 conn1.apply_acls(0, acl_side)
241 conn1.send_through(0)
242 # the return packets should pass
243 conn1.send_through(1)
244 # send some packets on conn1, ensure it doesn't go away
245 for i in IterateWithSleep(self, 20, "Keep conn active", 0.3):
246 conn1.send_through(1)
247 # clear all connections
248 self.vapi.ppcli("clear acl-plugin sessions")
249 # now try to send a packet on the reflected side
251 p2 = conn1.send_through(1).command()
253 # If we asserted while waiting, it's good.
254 # the conn should have timed out.
256 self.assert_equal(p2, None, "packet on supposedly deleted conn")
258 def run_tcp_transient_setup_conn_test(self, af, acl_side):
259 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53001, 5151)
260 conn1.apply_acls(0, acl_side)
261 conn1.send_through(0, 'S')
262 # the return packets should pass
263 conn1.send_through(1, 'SA')
264 # allow the conn to time out
265 for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1):
267 # ensure conn times out
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_established_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 # ensure conn times out for real
291 for i in IterateWithSleep(self, 130, "Wait for timeout", 0.1):
294 p2 = conn1.send_through(1).command()
296 # If we asserted while waiting, it's good.
297 # the conn should have timed out.
299 self.assert_equal(p2, None, "packet on supposedly deleted conn")
301 def run_tcp_transient_teardown_conn_test(self, af, acl_side):
302 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052)
303 conn1.apply_acls(0, acl_side)
304 conn1.send_through(0, 'S')
305 # the return packets should pass
306 conn1.send_through(1, 'SA')
307 # complete the threeway handshake
308 # (NB: sequence numbers not tracked, so not set!)
309 conn1.send_through(0, 'A')
310 # allow the conn to time out if it's in embryonic timer
311 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
313 # Try to send the packet from the "forbidden" side - it must pass
314 conn1.send_through(1, 'A')
315 # Send the FIN to bounce the session out of established
316 conn1.send_through(1, 'FA')
317 # If conn landed on transient timer it will time out here
318 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
320 # Now it should have timed out already
322 p2 = conn1.send_through(1).command()
324 # If we asserted while waiting, it's good.
325 # the conn should have timed out.
327 self.assert_equal(p2, None, "packet on supposedly deleted conn")
329 def test_0000_conn_prepare_test(self):
330 """ Prepare the settings """
331 self.vapi.ppcli("set acl-plugin session timeout udp idle 1")
333 def test_0001_basic_conn_test(self):
334 """ IPv4: Basic conn timeout test reflect on ingress """
335 self.run_basic_conn_test(AF_INET, 0)
337 def test_0002_basic_conn_test(self):
338 """ IPv4: Basic conn timeout test reflect on egress """
339 self.run_basic_conn_test(AF_INET, 1)
341 def test_0005_clear_conn_test(self):
342 """ IPv4: reflect egress, clear conn """
343 self.run_clear_conn_test(AF_INET, 1)
345 def test_0006_clear_conn_test(self):
346 """ IPv4: reflect ingress, clear conn """
347 self.run_clear_conn_test(AF_INET, 0)
349 def test_0011_active_conn_test(self):
350 """ IPv4: Idle conn behind active conn, reflect on ingress """
351 self.run_active_conn_test(AF_INET, 0)
353 def test_0012_active_conn_test(self):
354 """ IPv4: Idle conn behind active conn, reflect on egress """
355 self.run_active_conn_test(AF_INET, 1)
357 def test_1001_basic_conn_test(self):
358 """ IPv6: Basic conn timeout test reflect on ingress """
359 self.run_basic_conn_test(AF_INET6, 0)
361 def test_1002_basic_conn_test(self):
362 """ IPv6: Basic conn timeout test reflect on egress """
363 self.run_basic_conn_test(AF_INET6, 1)
365 def test_1005_clear_conn_test(self):
366 """ IPv6: reflect egress, clear conn """
367 self.run_clear_conn_test(AF_INET6, 1)
369 def test_1006_clear_conn_test(self):
370 """ IPv6: reflect ingress, clear conn """
371 self.run_clear_conn_test(AF_INET6, 0)
373 def test_1011_active_conn_test(self):
374 """ IPv6: Idle conn behind active conn, reflect on ingress """
375 self.run_active_conn_test(AF_INET6, 0)
377 def test_1012_active_conn_test(self):
378 """ IPv6: Idle conn behind active conn, reflect on egress """
379 self.run_active_conn_test(AF_INET6, 1)
381 def test_2000_prepare_for_tcp_test(self):
382 """ Prepare for TCP session tests """
383 # ensure the session hangs on if it gets treated as UDP
384 self.vapi.ppcli("set acl-plugin session timeout udp idle 200")
385 # let the TCP connection time out at 5 seconds
386 self.vapi.ppcli("set acl-plugin session timeout tcp idle 10")
387 self.vapi.ppcli("set acl-plugin session timeout tcp transient 1")
389 def test_2001_tcp_transient_conn_test(self):
390 """ IPv4: transient TCP session (incomplete 3WHS), ref. on ingress """
391 self.run_tcp_transient_setup_conn_test(AF_INET, 0)
393 def test_2002_tcp_transient_conn_test(self):
394 """ IPv4: transient TCP session (incomplete 3WHS), ref. on egress """
395 self.run_tcp_transient_setup_conn_test(AF_INET, 1)
397 def test_2003_tcp_transient_conn_test(self):
398 """ IPv4: established TCP session (complete 3WHS), ref. on ingress """
399 self.run_tcp_established_conn_test(AF_INET, 0)
401 def test_2004_tcp_transient_conn_test(self):
402 """ IPv4: established TCP session (complete 3WHS), ref. on egress """
403 self.run_tcp_established_conn_test(AF_INET, 1)
405 def test_2005_tcp_transient_teardown_conn_test(self):
406 """ IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on ingress """
407 self.run_tcp_transient_teardown_conn_test(AF_INET, 0)
409 def test_2006_tcp_transient_teardown_conn_test(self):
410 """ IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on egress """
411 self.run_tcp_transient_teardown_conn_test(AF_INET, 1)
413 def test_3001_tcp_transient_conn_test(self):
414 """ IPv6: transient TCP session (incomplete 3WHS), ref. on ingress """
415 self.run_tcp_transient_setup_conn_test(AF_INET6, 0)
417 def test_3002_tcp_transient_conn_test(self):
418 """ IPv6: transient TCP session (incomplete 3WHS), ref. on egress """
419 self.run_tcp_transient_setup_conn_test(AF_INET6, 1)
421 def test_3003_tcp_transient_conn_test(self):
422 """ IPv6: established TCP session (complete 3WHS), ref. on ingress """
423 self.run_tcp_established_conn_test(AF_INET6, 0)
425 def test_3004_tcp_transient_conn_test(self):
426 """ IPv6: established TCP session (complete 3WHS), ref. on egress """
427 self.run_tcp_established_conn_test(AF_INET6, 1)
429 def test_3005_tcp_transient_teardown_conn_test(self):
430 """ IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on ingress """
431 self.run_tcp_transient_teardown_conn_test(AF_INET6, 0)
433 def test_3006_tcp_transient_teardown_conn_test(self):
434 """ IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on egress """
435 self.run_tcp_transient_teardown_conn_test(AF_INET6, 1)