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
17 from ipaddress import ip_network
19 from vpp_acl import AclRule, VppAcl, VppAclInterface
22 def to_acl_rule(self, is_permit, wildcard_sport=False):
24 rule_family = AF_INET6 if p.haslayer(IPv6) else AF_INET
25 rule_prefix_len = 128 if p.haslayer(IPv6) else 32
26 rule_l3_layer = IPv6 if p.haslayer(IPv6) else IP
27 rule_l4_sport = p.sport
28 rule_l4_dport = p.dport
30 rule_l4_proto = p[IPv6].nh
32 rule_l4_proto = p[IP].proto
35 rule_l4_sport_first = 0
36 rule_l4_sport_last = 65535
38 rule_l4_sport_first = rule_l4_sport
39 rule_l4_sport_last = rule_l4_sport
41 new_rule = AclRule(is_permit=is_permit, proto=rule_l4_proto,
42 src_prefix=ip_network(
43 (p[rule_l3_layer].src, rule_prefix_len)),
44 dst_prefix=ip_network(
45 (p[rule_l3_layer].dst, rule_prefix_len)),
46 sport_from=rule_l4_sport_first,
47 sport_to=rule_l4_sport_last,
48 dport_from=rule_l4_dport, dport_to=rule_l4_dport)
53 Packet.to_acl_rule = to_acl_rule
56 class IterateWithSleep():
57 def __init__(self, testcase, n_iters, description, sleep_sec):
59 self.testcase = testcase
60 self.n_iters = n_iters
61 self.sleep_sec = sleep_sec
62 self.description = description
65 for x in range(0, self.n_iters):
67 self.testcase.sleep(self.sleep_sec)
71 def apply_acls(self, reflect_side, acl_side):
73 pkts.append(self.pkt(0))
74 pkts.append(self.pkt(1))
75 pkt = pkts[reflect_side]
78 r.append(pkt.to_acl_rule(2, wildcard_sport=True))
79 r.append(self.wildcard_rule(0))
80 reflect_acl = VppAcl(self.testcase, r)
81 reflect_acl.add_vpp_config()
84 r.append(self.wildcard_rule(0))
85 deny_acl = VppAcl(self.testcase, r)
86 deny_acl.add_vpp_config()
88 if reflect_side == acl_side:
89 acl_if0 = VppAclInterface(self.testcase,
90 self.ifs[acl_side].sw_if_index,
91 [reflect_acl, deny_acl], n_input=1)
92 acl_if1 = VppAclInterface(self.testcase,
93 self.ifs[1-acl_side].sw_if_index, [],
95 acl_if0.add_vpp_config()
96 acl_if1.add_vpp_config()
98 acl_if0 = VppAclInterface(self.testcase,
99 self.ifs[acl_side].sw_if_index,
100 [deny_acl, reflect_acl], n_input=1)
101 acl_if1 = VppAclInterface(self.testcase,
102 self.ifs[1-acl_side].sw_if_index, [],
104 acl_if0.add_vpp_config()
105 acl_if1.add_vpp_config()
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
111 new_rule = AclRule(is_permit=is_permit, proto=0,
112 src_prefix=ip_network(
113 (any_addr[is_ip6], 0)),
114 dst_prefix=ip_network(
115 (any_addr[is_ip6], 0)),
116 sport_from=0, sport_to=65535, dport_from=0,
121 @unittest.skipUnless(running_extended_tests, "part of extended tests")
122 class ACLPluginConnTestCase(VppTestCase):
123 """ ACL plugin connection-oriented extended testcases """
127 super(ACLPluginConnTestCase, cls).setUpClass()
129 cls.create_pg_interfaces(range(2))
130 cmd = "set acl-plugin session table event-trace 1"
131 cls.logger.info(cls.vapi.cli(cmd))
132 for i in cls.pg_interfaces:
140 def tearDownClass(cls):
141 super(ACLPluginConnTestCase, cls).tearDownClass()
144 """Run standard test teardown and log various show commands
146 super(ACLPluginConnTestCase, self).tearDown()
148 def show_commands_at_teardown(self):
149 self.logger.info(self.vapi.cli("show ip neighbors"))
150 self.logger.info(self.vapi.cli("show ip6 neighbors"))
151 self.logger.info(self.vapi.cli("show acl-plugin sessions"))
152 self.logger.info(self.vapi.cli("show acl-plugin acl"))
153 self.logger.info(self.vapi.cli("show acl-plugin interface"))
154 self.logger.info(self.vapi.cli("show acl-plugin tables"))
155 self.logger.info(self.vapi.cli("show event-logger all"))
157 def run_basic_conn_test(self, af, acl_side):
158 """ Basic conn timeout test """
159 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242)
160 conn1.apply_acls(0, acl_side)
161 conn1.send_through(0)
162 # the return packets should pass
163 conn1.send_through(1)
164 # send some packets on conn1, ensure it doesn't go away
165 for i in IterateWithSleep(self, 20, "Keep conn active", 0.3):
166 conn1.send_through(1)
167 # allow the conn to time out
168 for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1):
170 # now try to send a packet on the reflected side
172 p2 = conn1.send_through(1).command()
174 # If we asserted while waiting, it's good.
175 # the conn should have timed out.
177 self.assert_equal(p2, None, "packet on long-idle conn")
179 def run_active_conn_test(self, af, acl_side):
180 """ Idle connection behind active connection test """
181 base = 10000 + 1000*acl_side
182 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, base + 1, 2323)
183 conn2 = Conn(self, self.pg0, self.pg1, af, UDP, base + 2, 2323)
184 conn3 = Conn(self, self.pg0, self.pg1, af, UDP, base + 3, 2323)
185 conn1.apply_acls(0, acl_side)
188 # create and check that the conn2/3 work
190 conn2.send_pingpong(0)
192 conn3.send_pingpong(0)
193 # send some packets on conn1, keep conn2/3 idle
194 for i in IterateWithSleep(self, 20, "Keep conn active", 0.2):
195 conn1.send_through(1)
197 p2 = conn2.send_through(1).command()
199 # If we asserted while waiting, it's good.
200 # the conn should have timed out.
202 # We should have not received the packet on a long-idle
203 # connection, because it should have timed out
204 # If it didn't - it is a problem
205 self.assert_equal(p2, None, "packet on long-idle conn")
207 def run_clear_conn_test(self, af, acl_side):
208 """ Clear the connections via CLI """
209 conn1 = Conn(self, self.pg0, self.pg1, af, UDP, 42001, 4242)
210 conn1.apply_acls(0, acl_side)
211 conn1.send_through(0)
212 # the return packets should pass
213 conn1.send_through(1)
214 # send some packets on conn1, ensure it doesn't go away
215 for i in IterateWithSleep(self, 20, "Keep conn active", 0.3):
216 conn1.send_through(1)
217 # clear all connections
218 self.vapi.ppcli("clear acl-plugin sessions")
219 # now try to send a packet on the reflected side
221 p2 = conn1.send_through(1).command()
223 # If we asserted while waiting, it's good.
224 # the conn should have timed out.
226 self.assert_equal(p2, None, "packet on supposedly deleted conn")
228 def run_tcp_transient_setup_conn_test(self, af, acl_side):
229 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53001, 5151)
230 conn1.apply_acls(0, acl_side)
231 conn1.send_through(0, 'S')
232 # the return packets should pass
233 conn1.send_through(1, 'SA')
234 # allow the conn to time out
235 for i in IterateWithSleep(self, 30, "Wait for timeout", 0.1):
237 # ensure conn times out
239 p2 = conn1.send_through(1).command()
241 # If we asserted while waiting, it's good.
242 # the conn should have timed out.
244 self.assert_equal(p2, None, "packet on supposedly deleted conn")
246 def run_tcp_established_conn_test(self, af, acl_side):
247 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052)
248 conn1.apply_acls(0, acl_side)
249 conn1.send_through(0, 'S')
250 # the return packets should pass
251 conn1.send_through(1, 'SA')
252 # complete the threeway handshake
253 # (NB: sequence numbers not tracked, so not set!)
254 conn1.send_through(0, 'A')
255 # allow the conn to time out if it's in embryonic timer
256 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
258 # Try to send the packet from the "forbidden" side - it must pass
259 conn1.send_through(1, 'A')
260 # ensure conn times out for real
261 for i in IterateWithSleep(self, 130, "Wait for timeout", 0.1):
264 p2 = conn1.send_through(1).command()
266 # If we asserted while waiting, it's good.
267 # the conn should have timed out.
269 self.assert_equal(p2, None, "packet on supposedly deleted conn")
271 def run_tcp_transient_teardown_conn_test(self, af, acl_side):
272 conn1 = Conn(self, self.pg0, self.pg1, af, TCP, 53002, 5052)
273 conn1.apply_acls(0, acl_side)
274 conn1.send_through(0, 'S')
275 # the return packets should pass
276 conn1.send_through(1, 'SA')
277 # complete the threeway handshake
278 # (NB: sequence numbers not tracked, so not set!)
279 conn1.send_through(0, 'A')
280 # allow the conn to time out if it's in embryonic timer
281 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
283 # Try to send the packet from the "forbidden" side - it must pass
284 conn1.send_through(1, 'A')
285 # Send the FIN to bounce the session out of established
286 conn1.send_through(1, 'FA')
287 # If conn landed on transient timer it will time out here
288 for i in IterateWithSleep(self, 30, "Wait for transient timeout", 0.1):
290 # Now it should have timed out already
292 p2 = conn1.send_through(1).command()
294 # If we asserted while waiting, it's good.
295 # the conn should have timed out.
297 self.assert_equal(p2, None, "packet on supposedly deleted conn")
299 def test_0000_conn_prepare_test(self):
300 """ Prepare the settings """
301 self.vapi.ppcli("set acl-plugin session timeout udp idle 1")
303 def test_0001_basic_conn_test(self):
304 """ IPv4: Basic conn timeout test reflect on ingress """
305 self.run_basic_conn_test(AF_INET, 0)
307 def test_0002_basic_conn_test(self):
308 """ IPv4: Basic conn timeout test reflect on egress """
309 self.run_basic_conn_test(AF_INET, 1)
311 def test_0005_clear_conn_test(self):
312 """ IPv4: reflect egress, clear conn """
313 self.run_clear_conn_test(AF_INET, 1)
315 def test_0006_clear_conn_test(self):
316 """ IPv4: reflect ingress, clear conn """
317 self.run_clear_conn_test(AF_INET, 0)
319 def test_0011_active_conn_test(self):
320 """ IPv4: Idle conn behind active conn, reflect on ingress """
321 self.run_active_conn_test(AF_INET, 0)
323 def test_0012_active_conn_test(self):
324 """ IPv4: Idle conn behind active conn, reflect on egress """
325 self.run_active_conn_test(AF_INET, 1)
327 def test_1001_basic_conn_test(self):
328 """ IPv6: Basic conn timeout test reflect on ingress """
329 self.run_basic_conn_test(AF_INET6, 0)
331 def test_1002_basic_conn_test(self):
332 """ IPv6: Basic conn timeout test reflect on egress """
333 self.run_basic_conn_test(AF_INET6, 1)
335 def test_1005_clear_conn_test(self):
336 """ IPv6: reflect egress, clear conn """
337 self.run_clear_conn_test(AF_INET6, 1)
339 def test_1006_clear_conn_test(self):
340 """ IPv6: reflect ingress, clear conn """
341 self.run_clear_conn_test(AF_INET6, 0)
343 def test_1011_active_conn_test(self):
344 """ IPv6: Idle conn behind active conn, reflect on ingress """
345 self.run_active_conn_test(AF_INET6, 0)
347 def test_1012_active_conn_test(self):
348 """ IPv6: Idle conn behind active conn, reflect on egress """
349 self.run_active_conn_test(AF_INET6, 1)
351 def test_2000_prepare_for_tcp_test(self):
352 """ Prepare for TCP session tests """
353 # ensure the session hangs on if it gets treated as UDP
354 self.vapi.ppcli("set acl-plugin session timeout udp idle 200")
355 # let the TCP connection time out at 5 seconds
356 self.vapi.ppcli("set acl-plugin session timeout tcp idle 10")
357 self.vapi.ppcli("set acl-plugin session timeout tcp transient 1")
359 def test_2001_tcp_transient_conn_test(self):
360 """ IPv4: transient TCP session (incomplete 3WHS), ref. on ingress """
361 self.run_tcp_transient_setup_conn_test(AF_INET, 0)
363 def test_2002_tcp_transient_conn_test(self):
364 """ IPv4: transient TCP session (incomplete 3WHS), ref. on egress """
365 self.run_tcp_transient_setup_conn_test(AF_INET, 1)
367 def test_2003_tcp_transient_conn_test(self):
368 """ IPv4: established TCP session (complete 3WHS), ref. on ingress """
369 self.run_tcp_established_conn_test(AF_INET, 0)
371 def test_2004_tcp_transient_conn_test(self):
372 """ IPv4: established TCP session (complete 3WHS), ref. on egress """
373 self.run_tcp_established_conn_test(AF_INET, 1)
375 def test_2005_tcp_transient_teardown_conn_test(self):
376 """ IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on ingress """
377 self.run_tcp_transient_teardown_conn_test(AF_INET, 0)
379 def test_2006_tcp_transient_teardown_conn_test(self):
380 """ IPv4: transient TCP session (3WHS,ACK,FINACK), ref. on egress """
381 self.run_tcp_transient_teardown_conn_test(AF_INET, 1)
383 def test_3001_tcp_transient_conn_test(self):
384 """ IPv6: transient TCP session (incomplete 3WHS), ref. on ingress """
385 self.run_tcp_transient_setup_conn_test(AF_INET6, 0)
387 def test_3002_tcp_transient_conn_test(self):
388 """ IPv6: transient TCP session (incomplete 3WHS), ref. on egress """
389 self.run_tcp_transient_setup_conn_test(AF_INET6, 1)
391 def test_3003_tcp_transient_conn_test(self):
392 """ IPv6: established TCP session (complete 3WHS), ref. on ingress """
393 self.run_tcp_established_conn_test(AF_INET6, 0)
395 def test_3004_tcp_transient_conn_test(self):
396 """ IPv6: established TCP session (complete 3WHS), ref. on egress """
397 self.run_tcp_established_conn_test(AF_INET6, 1)
399 def test_3005_tcp_transient_teardown_conn_test(self):
400 """ IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on ingress """
401 self.run_tcp_transient_teardown_conn_test(AF_INET6, 0)
403 def test_3006_tcp_transient_teardown_conn_test(self):
404 """ IPv6: transient TCP session (3WHS,ACK,FINACK), ref. on egress """
405 self.run_tcp_transient_teardown_conn_test(AF_INET6, 1)