blob: 3baec9f9e9bef14561855aaf0730fb264cf9412b [file] [log] [blame]
Renato Botelho do Coutoead1e532019-10-31 13:31:07 -05001#!/usr/bin/env python3
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +01002
Paul Vinciguerraa279d9c2019-02-28 09:00:09 -08003import unittest
4
Andrew Yourtchenkobc378782023-09-26 16:01:21 +02005from config import config
Dave Wallace8800f732023-08-31 00:47:44 -04006from framework import VppTestCase
7from asfframework import VppTestRunner
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02008from vpp_ip_route import (
9 VppIpRoute,
10 VppRoutePath,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020011 VppIpTable,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020012)
Jakub Grajciar2f8cd912020-03-27 06:55:06 +010013from vpp_acl import AclRule, VppAcl
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +010014
15from scapy.packet import Raw
Paul Vinciguerraa279d9c2019-02-28 09:00:09 -080016from scapy.layers.l2 import Ether
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +010017from scapy.layers.inet import IP, UDP
18from scapy.layers.inet6 import IPv6
Jakub Grajciar2f8cd912020-03-27 06:55:06 +010019from ipaddress import IPv4Network, IPv6Network
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +010020
Paul Vinciguerraa279d9c2019-02-28 09:00:09 -080021from vpp_object import VppObject
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +010022
Paul Vinciguerra4271c972019-05-14 13:25:49 -040023NUM_PKTS = 67
24
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +010025
26def find_abf_policy(test, id):
27 policies = test.vapi.abf_policy_dump()
28 for p in policies:
29 if id == p.policy.policy_id:
30 return True
31 return False
32
33
34def find_abf_itf_attach(test, id, sw_if_index):
35 attachs = test.vapi.abf_itf_attach_dump()
36 for a in attachs:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020037 if id == a.attach.policy_id and sw_if_index == a.attach.sw_if_index:
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +010038 return True
39 return False
40
41
42class VppAbfPolicy(VppObject):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020043 def __init__(self, test, policy_id, acl, paths):
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +010044 self._test = test
45 self.policy_id = policy_id
46 self.acl = acl
47 self.paths = paths
Neale Ranns097fa662018-05-01 05:17:55 -070048 self.encoded_paths = []
49 for path in self.paths:
50 self.encoded_paths.append(path.encode())
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +010051
52 def add_vpp_config(self):
53 self._test.vapi.abf_policy_add_del(
54 1,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020055 {
56 "policy_id": self.policy_id,
57 "acl_index": self.acl.acl_index,
58 "n_paths": len(self.paths),
59 "paths": self.encoded_paths,
60 },
61 )
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +010062 self._test.registry.register(self, self._test.logger)
63
64 def remove_vpp_config(self):
65 self._test.vapi.abf_policy_add_del(
66 0,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020067 {
68 "policy_id": self.policy_id,
69 "acl_index": self.acl.acl_index,
70 "n_paths": len(self.paths),
71 "paths": self.encoded_paths,
72 },
73 )
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +010074
75 def query_vpp_config(self):
76 return find_abf_policy(self._test, self.policy_id)
77
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +010078 def object_id(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020079 return "abf-policy-%d" % self.policy_id
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +010080
81
82class VppAbfAttach(VppObject):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020083 def __init__(self, test, policy_id, sw_if_index, priority, is_ipv6=0):
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +010084 self._test = test
85 self.policy_id = policy_id
86 self.sw_if_index = sw_if_index
87 self.priority = priority
88 self.is_ipv6 = is_ipv6
89
90 def add_vpp_config(self):
91 self._test.vapi.abf_itf_attach_add_del(
92 1,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020093 {
94 "policy_id": self.policy_id,
95 "sw_if_index": self.sw_if_index,
96 "priority": self.priority,
97 "is_ipv6": self.is_ipv6,
98 },
99 )
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100100 self._test.registry.register(self, self._test.logger)
101
102 def remove_vpp_config(self):
103 self._test.vapi.abf_itf_attach_add_del(
104 0,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200105 {
106 "policy_id": self.policy_id,
107 "sw_if_index": self.sw_if_index,
108 "priority": self.priority,
109 "is_ipv6": self.is_ipv6,
110 },
111 )
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100112
113 def query_vpp_config(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200114 return find_abf_itf_attach(self._test, self.policy_id, self.sw_if_index)
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100115
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100116 def object_id(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200117 return "abf-attach-%d-%d" % (self.policy_id, self.sw_if_index)
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100118
119
Andrew Yourtchenkobc378782023-09-26 16:01:21 +0200120@unittest.skipIf(
121 "acl" in config.excluded_plugins,
122 "Exclude ABF plugin tests due to absence of ACL plugin",
123)
124@unittest.skipIf("abf" in config.excluded_plugins, "Exclude ABF plugin tests")
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100125class TestAbf(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200126 """ABF Test Case"""
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100127
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -0700128 @classmethod
129 def setUpClass(cls):
130 super(TestAbf, cls).setUpClass()
131
132 @classmethod
133 def tearDownClass(cls):
134 super(TestAbf, cls).tearDownClass()
135
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100136 def setUp(self):
137 super(TestAbf, self).setUp()
138
Neale Rannsf726f532019-03-11 05:34:50 -0700139 self.create_pg_interfaces(range(5))
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100140
Neale Rannsf726f532019-03-11 05:34:50 -0700141 for i in self.pg_interfaces[:4]:
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100142 i.admin_up()
143 i.config_ip4()
144 i.resolve_arp()
145 i.config_ip6()
146 i.resolve_ndp()
147
148 def tearDown(self):
149 for i in self.pg_interfaces:
150 i.unconfig_ip4()
151 i.unconfig_ip6()
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100152 i.admin_down()
153 super(TestAbf, self).tearDown()
154
155 def test_abf4(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200156 """IPv4 ACL Based Forwarding"""
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100157
158 #
159 # We are not testing the various matching capabilities
160 # of ACLs, that's done elsewhere. Here ware are testing
161 # the application of ACLs to a forwarding path to achieve
162 # ABF
163 # So we construct just a few ACLs to ensure the ABF policies
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700164 # are correctly constructed and used. And a few path types
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100165 # to test the API path decoding.
166 #
167
168 #
169 # Rule 1
170 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200171 rule_1 = AclRule(
172 is_permit=1,
173 proto=17,
174 ports=1234,
175 src_prefix=IPv4Network("1.1.1.1/32"),
176 dst_prefix=IPv4Network("1.1.1.2/32"),
177 )
Jakub Grajciar2f8cd912020-03-27 06:55:06 +0100178 acl_1 = VppAcl(self, rules=[rule_1])
179 acl_1.add_vpp_config()
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100180
181 #
182 # ABF policy for ACL 1 - path via interface 1
183 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200184 abf_1 = VppAbfPolicy(
185 self, 10, acl_1, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]
186 )
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100187 abf_1.add_vpp_config()
188
189 #
190 # Attach the policy to input interface Pg0
191 #
192 attach_1 = VppAbfAttach(self, 10, self.pg0.sw_if_index, 50)
193 attach_1.add_vpp_config()
194
195 #
196 # fire in packet matching the ACL src,dst. If it's forwarded
197 # then the ABF was successful, since default routing will drop it
198 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200199 p_1 = (
200 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
201 / IP(src="1.1.1.1", dst="1.1.1.2")
202 / UDP(sport=1234, dport=1234)
203 / Raw(b"\xa5" * 100)
204 )
205 self.send_and_expect(self.pg0, p_1 * NUM_PKTS, self.pg1)
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100206
207 #
208 # Attach a 'better' priority policy to the same interface
209 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200210 abf_2 = VppAbfPolicy(
211 self, 11, acl_1, [VppRoutePath(self.pg2.remote_ip4, self.pg2.sw_if_index)]
212 )
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100213 abf_2.add_vpp_config()
214 attach_2 = VppAbfAttach(self, 11, self.pg0.sw_if_index, 40)
215 attach_2.add_vpp_config()
216
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200217 self.send_and_expect(self.pg0, p_1 * NUM_PKTS, self.pg2)
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100218
219 #
220 # Attach a policy with priority in the middle
221 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200222 abf_3 = VppAbfPolicy(
223 self, 12, acl_1, [VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index)]
224 )
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100225 abf_3.add_vpp_config()
226 attach_3 = VppAbfAttach(self, 12, self.pg0.sw_if_index, 45)
227 attach_3.add_vpp_config()
228
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200229 self.send_and_expect(self.pg0, p_1 * NUM_PKTS, self.pg2)
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100230
231 #
232 # remove the best priority
233 #
234 attach_2.remove_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200235 self.send_and_expect(self.pg0, p_1 * NUM_PKTS, self.pg3)
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100236
237 #
238 # Attach one of the same policies to Pg1
239 #
240 attach_4 = VppAbfAttach(self, 12, self.pg1.sw_if_index, 45)
241 attach_4.add_vpp_config()
242
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200243 p_2 = (
244 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
245 / IP(src="1.1.1.1", dst="1.1.1.2")
246 / UDP(sport=1234, dport=1234)
247 / Raw(b"\xa5" * 100)
248 )
Paul Vinciguerra4271c972019-05-14 13:25:49 -0400249 self.send_and_expect(self.pg1, p_2 * NUM_PKTS, self.pg3)
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100250
251 #
252 # detach the policy from PG1, now expect traffic to be dropped
253 #
254 attach_4.remove_vpp_config()
255
Paul Vinciguerra4271c972019-05-14 13:25:49 -0400256 self.send_and_assert_no_replies(self.pg1, p_2 * NUM_PKTS, "Detached")
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100257
Neale Rannsf726f532019-03-11 05:34:50 -0700258 #
259 # Swap to route via a next-hop in the non-default table
260 #
261 table_20 = VppIpTable(self, 20)
262 table_20.add_vpp_config()
263
264 self.pg4.set_table_ip4(table_20.table_id)
265 self.pg4.admin_up()
266 self.pg4.config_ip4()
267 self.pg4.resolve_arp()
268
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200269 abf_13 = VppAbfPolicy(
270 self,
271 13,
272 acl_1,
273 [
274 VppRoutePath(
275 self.pg4.remote_ip4, 0xFFFFFFFF, nh_table_id=table_20.table_id
276 )
277 ],
278 )
Neale Rannsf726f532019-03-11 05:34:50 -0700279 abf_13.add_vpp_config()
280 attach_5 = VppAbfAttach(self, 13, self.pg0.sw_if_index, 30)
281 attach_5.add_vpp_config()
282
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200283 self.send_and_expect(self.pg0, p_1 * NUM_PKTS, self.pg4)
Neale Rannsf726f532019-03-11 05:34:50 -0700284
285 self.pg4.unconfig_ip4()
286 self.pg4.set_table_ip4(0)
287
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100288 def test_abf6(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200289 """IPv6 ACL Based Forwarding"""
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100290
291 #
292 # Simple test for matching IPv6 packets
293 #
294
295 #
296 # Rule 1
297 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200298 rule_1 = AclRule(
299 is_permit=1,
300 proto=17,
301 ports=1234,
302 src_prefix=IPv6Network("2001::2/128"),
303 dst_prefix=IPv6Network("2001::1/128"),
304 )
Jakub Grajciar2f8cd912020-03-27 06:55:06 +0100305 acl_1 = VppAcl(self, rules=[rule_1])
306 acl_1.add_vpp_config()
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100307
308 #
309 # ABF policy for ACL 1 - path via interface 1
310 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200311 abf_1 = VppAbfPolicy(self, 10, acl_1, [VppRoutePath("3001::1", 0xFFFFFFFF)])
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100312 abf_1.add_vpp_config()
313
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200314 attach_1 = VppAbfAttach(self, 10, self.pg0.sw_if_index, 45, is_ipv6=True)
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100315 attach_1.add_vpp_config()
316
317 #
318 # a packet matching the rule
319 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200320 p = (
321 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
322 / IPv6(src="2001::2", dst="2001::1")
323 / UDP(sport=1234, dport=1234)
324 / Raw(b"\xa5" * 100)
325 )
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100326
327 #
328 # packets are dropped because there is no route to the policy's
329 # next hop
330 #
Paul Vinciguerra4271c972019-05-14 13:25:49 -0400331 self.send_and_assert_no_replies(self.pg1, p * NUM_PKTS, "no route")
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100332
333 #
334 # add a route resolving the next-hop
335 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200336 route = VppIpRoute(
337 self,
338 "3001::1",
339 32,
340 [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)],
341 )
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100342 route.add_vpp_config()
343
344 #
345 # now expect packets forwarded.
346 #
Paul Vinciguerra4271c972019-05-14 13:25:49 -0400347 self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg1)
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100348
Josh Dorsey6903da22023-01-04 21:28:07 +0000349 def test_abf4_deny(self):
350 """IPv4 ACL Deny Rule"""
351 import ipaddress
352
353 #
354 # Rules 1/2
355 #
356 pg0_subnet = ipaddress.ip_network(self.pg0.local_ip4_prefix, strict=False)
357 pg2_subnet = ipaddress.ip_network(self.pg2.local_ip4_prefix, strict=False)
358 pg3_subnet = ipaddress.ip_network(self.pg3.local_ip4_prefix, strict=False)
359 rule_deny = AclRule(
360 is_permit=0,
361 proto=17,
362 ports=1234,
363 src_prefix=IPv4Network(pg0_subnet),
364 dst_prefix=IPv4Network(pg3_subnet),
365 )
366 rule_permit = AclRule(
367 is_permit=1,
368 proto=17,
369 ports=1234,
370 src_prefix=IPv4Network(pg0_subnet),
371 dst_prefix=IPv4Network(pg2_subnet),
372 )
373 acl_1 = VppAcl(self, rules=[rule_deny, rule_permit])
374 acl_1.add_vpp_config()
375
376 #
377 # ABF policy for ACL 1 - path via interface 1
378 #
379 abf_1 = VppAbfPolicy(
380 self, 10, acl_1, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]
381 )
382 abf_1.add_vpp_config()
383
384 #
385 # Attach the policy to input interface Pg0
386 #
387 attach_1 = VppAbfAttach(self, 10, self.pg0.sw_if_index, 50)
388 attach_1.add_vpp_config()
389
390 #
391 # a packet matching the deny rule
392 #
393 p_deny = (
394 Ether(src=self.pg0.remote_mac, dst=self.pg3.remote_mac)
395 / IP(src=self.pg0.remote_ip4, dst=self.pg3.remote_ip4)
396 / UDP(sport=1234, dport=1234)
397 / Raw(b"\xa5" * 100)
398 )
399 self.send_and_expect(self.pg0, p_deny * NUM_PKTS, self.pg3)
400
401 #
402 # a packet matching the permit rule
403 #
404 p_permit = (
405 Ether(src=self.pg0.remote_mac, dst=self.pg2.remote_mac)
406 / IP(src=self.pg0.remote_ip4, dst=self.pg2.remote_ip4)
407 / UDP(sport=1234, dport=1234)
408 / Raw(b"\xa5" * 100)
409 )
410 self.send_and_expect(self.pg0, p_permit * NUM_PKTS, self.pg1)
411
412 def test_abf6_deny(self):
413 """IPv6 ACL Deny Rule"""
414 import ipaddress
415
416 #
417 # Rules 1/2
418 #
419 pg0_subnet = ipaddress.ip_network(self.pg0.local_ip6_prefix, strict=False)
420 pg2_subnet = ipaddress.ip_network(self.pg2.local_ip6_prefix, strict=False)
421 pg3_subnet = ipaddress.ip_network(self.pg3.local_ip6_prefix, strict=False)
422 rule_deny = AclRule(
423 is_permit=0,
424 proto=17,
425 ports=1234,
426 src_prefix=IPv6Network(pg0_subnet),
427 dst_prefix=IPv6Network(pg3_subnet),
428 )
429 rule_permit = AclRule(
430 is_permit=1,
431 proto=17,
432 ports=1234,
433 src_prefix=IPv6Network(pg0_subnet),
434 dst_prefix=IPv6Network(pg2_subnet),
435 )
436 acl_1 = VppAcl(self, rules=[rule_deny, rule_permit])
437 acl_1.add_vpp_config()
438
439 #
440 # ABF policy for ACL 1 - path via interface 1
441 #
442 abf_1 = VppAbfPolicy(
443 self, 10, acl_1, [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)]
444 )
445 abf_1.add_vpp_config()
446
447 #
448 # Attach the policy to input interface Pg0
449 #
450 attach_1 = VppAbfAttach(self, 10, self.pg0.sw_if_index, 50, is_ipv6=1)
451 attach_1.add_vpp_config()
452
453 #
454 # a packet matching the deny rule
455 #
456 p_deny = (
457 Ether(src=self.pg0.remote_mac, dst=self.pg3.remote_mac)
458 / IPv6(src=self.pg0.remote_ip6, dst=self.pg3.remote_ip6)
459 / UDP(sport=1234, dport=1234)
460 / Raw(b"\xa5" * 100)
461 )
462 self.send_and_expect(self.pg0, p_deny * NUM_PKTS, self.pg3)
463
464 #
465 # a packet matching the permit rule
466 #
467 p_permit = (
468 Ether(src=self.pg0.remote_mac, dst=self.pg2.remote_mac)
469 / IPv6(src=self.pg0.remote_ip6, dst=self.pg2.remote_ip6)
470 / UDP(sport=1234, dport=1234)
471 / Raw(b"\xa5" * 100)
472 )
473 self.send_and_expect(self.pg0, p_permit * NUM_PKTS, self.pg1)
474
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100475
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200476if __name__ == "__main__":
Andrew Yourtchenko669d07d2017-11-17 14:38:18 +0100477 unittest.main(testRunner=VppTestRunner)