udp: fix csum computation when offload disabled
[vpp.git] / test / test_acl_plugin_conns.py
1 #!/usr/bin/env python3
2 """ ACL plugin extended stateful tests """
3
4 import unittest
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
13
14 from vpp_acl import AclRule, VppAcl, VppAclInterface
15
16
17 def to_acl_rule(self, is_permit, wildcard_sport=False):
18     p = self
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
24     if p.haslayer(IPv6):
25         rule_l4_proto = p[IPv6].nh
26     else:
27         rule_l4_proto = p[IP].proto
28
29     if wildcard_sport:
30         rule_l4_sport_first = 0
31         rule_l4_sport_last = 65535
32     else:
33         rule_l4_sport_first = rule_l4_sport
34         rule_l4_sport_last = rule_l4_sport
35
36     new_rule = AclRule(
37         is_permit=is_permit,
38         proto=rule_l4_proto,
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,
45     )
46
47     return new_rule
48
49
50 Packet.to_acl_rule = to_acl_rule
51
52
53 class IterateWithSleep:
54     def __init__(self, testcase, n_iters, description, sleep_sec):
55         self.curr = 0
56         self.testcase = testcase
57         self.n_iters = n_iters
58         self.sleep_sec = sleep_sec
59         self.description = description
60
61     def __iter__(self):
62         for x in range(0, self.n_iters):
63             yield x
64             self.testcase.sleep(self.sleep_sec)
65
66
67 class Conn(L4_Conn):
68     def apply_acls(self, reflect_side, acl_side):
69         pkts = []
70         pkts.append(self.pkt(0))
71         pkts.append(self.pkt(1))
72         pkt = pkts[reflect_side]
73
74         r = []
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()
79
80         r = []
81         r.append(self.wildcard_rule(0))
82         deny_acl = VppAcl(self.testcase, r)
83         deny_acl.add_vpp_config()
84
85         if reflect_side == acl_side:
86             acl_if0 = VppAclInterface(
87                 self.testcase,
88                 self.ifs[acl_side].sw_if_index,
89                 [reflect_acl, deny_acl],
90                 n_input=1,
91             )
92             acl_if1 = VppAclInterface(
93                 self.testcase, self.ifs[1 - acl_side].sw_if_index, [], n_input=0
94             )
95             acl_if0.add_vpp_config()
96             acl_if1.add_vpp_config()
97         else:
98             acl_if0 = VppAclInterface(
99                 self.testcase,
100                 self.ifs[acl_side].sw_if_index,
101                 [deny_acl, reflect_acl],
102                 n_input=1,
103             )
104             acl_if1 = VppAclInterface(
105                 self.testcase, self.ifs[1 - acl_side].sw_if_index, [], n_input=0
106             )
107             acl_if0.add_vpp_config()
108             acl_if1.add_vpp_config()
109
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
114         new_rule = AclRule(
115             is_permit=is_permit,
116             proto=0,
117             src_prefix=ip_network((any_addr[is_ip6], 0)),
118             dst_prefix=ip_network((any_addr[is_ip6], 0)),
119             sport_from=0,
120             sport_to=65535,
121             dport_from=0,
122             dport_to=65535,
123         )
124         return new_rule
125
126
127 @unittest.skipUnless(config.extended, "part of extended tests")
128 class ACLPluginConnTestCase(VppTestCase):
129     """ACL plugin connection-oriented extended testcases"""
130
131     @classmethod
132     def setUpClass(cls):
133         super(ACLPluginConnTestCase, cls).setUpClass()
134         # create pg0 and pg1
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:
139             i.admin_up()
140             i.config_ip4()
141             i.config_ip6()
142             i.resolve_arp()
143             i.resolve_ndp()
144
145     @classmethod
146     def tearDownClass(cls):
147         super(ACLPluginConnTestCase, cls).tearDownClass()
148
149     def tearDown(self):
150         """Run standard test teardown and log various show commands"""
151         super(ACLPluginConnTestCase, self).tearDown()
152
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"))
161
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):
174             pass
175         # now try to send a packet on the reflected side
176         try:
177             p2 = conn1.send_through(1).command()
178         except:
179             # If we asserted while waiting, it's good.
180             # the conn should have timed out.
181             p2 = None
182         self.assert_equal(p2, None, "packet on long-idle conn")
183
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)
191         conn1.send(0)
192         conn1.recv(1)
193         # create and check that the conn2/3 work
194         self.sleep(0.1)
195         conn2.send_pingpong(0)
196         self.sleep(0.1)
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)
201         try:
202             p2 = conn2.send_through(1).command()
203         except:
204             # If we asserted while waiting, it's good.
205             # the conn should have timed out.
206             p2 = None
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")
211
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
225         try:
226             p2 = conn1.send_through(1).command()
227         except:
228             # If we asserted while waiting, it's good.
229             # the conn should have timed out.
230             p2 = None
231         self.assert_equal(p2, None, "packet on supposedly deleted conn")
232
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):
241             pass
242         # ensure conn times out
243         try:
244             p2 = conn1.send_through(1).command()
245         except:
246             # If we asserted while waiting, it's good.
247             # the conn should have timed out.
248             p2 = None
249         self.assert_equal(p2, None, "packet on supposedly deleted conn")
250
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):
262             pass
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):
267             pass
268         try:
269             p2 = conn1.send_through(1).command()
270         except:
271             # If we asserted while waiting, it's good.
272             # the conn should have timed out.
273             p2 = None
274         self.assert_equal(p2, None, "packet on supposedly deleted conn")
275
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):
287             pass
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):
294             pass
295         # Now it should have timed out already
296         try:
297             p2 = conn1.send_through(1).command()
298         except:
299             # If we asserted while waiting, it's good.
300             # the conn should have timed out.
301             p2 = None
302         self.assert_equal(p2, None, "packet on supposedly deleted conn")
303
304     def test_0000_conn_prepare_test(self):
305         """Prepare the settings"""
306         self.vapi.ppcli("set acl-plugin session timeout udp idle 1")
307
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)
311
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)
315
316     def test_0005_clear_conn_test(self):
317         """IPv4: reflect egress, clear conn"""
318         self.run_clear_conn_test(AF_INET, 1)
319
320     def test_0006_clear_conn_test(self):
321         """IPv4: reflect ingress, clear conn"""
322         self.run_clear_conn_test(AF_INET, 0)
323
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)
327
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)
331
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)
335
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)
339
340     def test_1005_clear_conn_test(self):
341         """IPv6: reflect egress, clear conn"""
342         self.run_clear_conn_test(AF_INET6, 1)
343
344     def test_1006_clear_conn_test(self):
345         """IPv6: reflect ingress, clear conn"""
346         self.run_clear_conn_test(AF_INET6, 0)
347
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)
351
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)
355
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")
363
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)
367
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)
371
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)
375
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)
379
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)
383
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)
387
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)
391
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)
395
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)
399
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)
403
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)
407
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)