blob: b913a9805991e61fca24f38b3627074f2aaa3eca [file] [log] [blame]
Zachary Leaf7cd35f52021-06-25 08:11:15 -05001import socket
2import unittest
3
4from util import ppp
Pratikshya Prasai657bdf72022-08-18 11:09:38 -04005from asfframework import VppTestRunner
Zachary Leaf7cd35f52021-06-25 08:11:15 -05006from template_ipsec import SpdFlowCacheTemplate
7
8
9class SpdFlowCacheInbound(SpdFlowCacheTemplate):
10 # Override setUpConstants to enable inbound flow cache in config
11 @classmethod
12 def setUpConstants(cls):
13 super(SpdFlowCacheInbound, cls).setUpConstants()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020014 cls.vpp_cmdline.extend(["ipsec", "{", "ipv4-inbound-spd-flow-cache on", "}"])
15 cls.logger.info("VPP modified cmdline is %s" % " ".join(cls.vpp_cmdline))
Zachary Leaf7cd35f52021-06-25 08:11:15 -050016
17
18class IPSec4SpdTestCaseBypass(SpdFlowCacheInbound):
19 """ IPSec/IPv4 inbound: Policy mode test case with flow cache \
20 (add bypass)"""
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020021
Zachary Leaf7cd35f52021-06-25 08:11:15 -050022 def test_ipsec_spd_inbound_bypass(self):
23 # In this test case, packets in IPv4 FWD path are configured
24 # to go through IPSec inbound SPD policy lookup.
25 #
26 # 2 inbound SPD rules (1 HIGH and 1 LOW) are added.
27 # - High priority rule action is set to DISCARD.
28 # - Low priority rule action is set to BYPASS.
29 #
30 # Since BYPASS rules take precedence over DISCARD
31 # (the order being PROTECT, BYPASS, DISCARD) we expect the
32 # BYPASS rule to match and traffic to be correctly forwarded.
33 self.create_interfaces(2)
34 pkt_count = 5
35
36 self.spd_create_and_intf_add(1, [self.pg1, self.pg0])
37
38 # create input rules
39 # bypass rule should take precedence over discard rule,
40 # even though it's lower priority
41 policy_0 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020042 1,
43 self.pg1,
44 self.pg0,
45 socket.IPPROTO_UDP,
46 is_out=0,
47 priority=10,
48 policy_type="bypass",
49 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -050050 policy_1 = self.spd_add_rem_policy( # inbound, priority 15
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020051 1,
52 self.pg1,
53 self.pg0,
54 socket.IPPROTO_UDP,
55 is_out=0,
56 priority=15,
57 policy_type="discard",
58 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -050059
60 # create output rule so we can capture forwarded packets
61 policy_2 = self.spd_add_rem_policy( # outbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020062 1,
63 self.pg0,
64 self.pg1,
65 socket.IPPROTO_UDP,
66 is_out=1,
67 priority=10,
68 policy_type="bypass",
69 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -050070
71 # check flow cache is empty before sending traffic
72 self.verify_num_inbound_flow_cache_entries(0)
73 # create the packet stream
74 packets = self.create_stream(self.pg0, self.pg1, pkt_count)
75 # add the stream to the source interface
76 self.pg0.add_stream(packets)
77 self.pg1.enable_capture()
78 self.pg_start()
79
80 # check capture on pg1
81 capture = self.pg1.get_capture()
82 for packet in capture:
83 try:
84 self.logger.debug(ppp("SPD Add - Got packet:", packet))
85 except Exception:
86 self.logger.error(ppp("Unexpected or invalid packet:", packet))
87 raise
88 self.logger.debug("SPD: Num packets: %s", len(capture.res))
89
90 # verify captured packets
91 self.verify_capture(self.pg0, self.pg1, capture)
92 # verify all policies matched the expected number of times
93 self.verify_policy_match(pkt_count, policy_0)
94 self.verify_policy_match(0, policy_1)
95 self.verify_policy_match(pkt_count, policy_2)
96 # check input policy has been cached
97 self.verify_num_inbound_flow_cache_entries(1)
98
99
100class IPSec4SpdTestCaseDiscard(SpdFlowCacheInbound):
101 """ IPSec/IPv4 inbound: Policy mode test case with flow cache \
102 (add discard)"""
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200103
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500104 def test_ipsec_spd_inbound_discard(self):
105 # In this test case, packets in IPv4 FWD path are configured
106 # to go through IPSec inbound SPD policy lookup.
107 # 1 DISCARD rule is added, so all traffic should be dropped.
108 self.create_interfaces(2)
109 pkt_count = 5
110
111 self.spd_create_and_intf_add(1, [self.pg1, self.pg0])
112
113 # create input rule
114 policy_0 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200115 1,
116 self.pg1,
117 self.pg0,
118 socket.IPPROTO_UDP,
119 is_out=0,
120 priority=10,
121 policy_type="discard",
122 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500123
124 # create output rule so we can capture forwarded packets
125 policy_1 = self.spd_add_rem_policy( # outbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200126 1,
127 self.pg0,
128 self.pg1,
129 socket.IPPROTO_UDP,
130 is_out=1,
131 priority=10,
132 policy_type="bypass",
133 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500134
135 # check flow cache is empty before sending traffic
136 self.verify_num_inbound_flow_cache_entries(0)
137 # create the packet stream
138 packets = self.create_stream(self.pg0, self.pg1, pkt_count)
139 # add the stream to the source interface
140 self.pg0.add_stream(packets)
141 self.pg1.enable_capture()
142 self.pg_start()
143 # inbound discard rule should have dropped traffic
144 self.pg1.assert_nothing_captured()
145 # verify all policies matched the expected number of times
146 self.verify_policy_match(pkt_count, policy_0)
147 self.verify_policy_match(0, policy_1)
148 # only inbound discard rule should have been cached
149 self.verify_num_inbound_flow_cache_entries(1)
150
151
Tianyu Li26c39872022-04-22 11:22:55 +0800152class IPSec4SpdTestCaseRemoveInbound(SpdFlowCacheInbound):
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500153 """ IPSec/IPv4 inbound: Policy mode test case with flow cache \
154 (remove bypass)"""
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200155
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500156 def test_ipsec_spd_inbound_remove(self):
157 # In this test case, packets in IPv4 FWD path are configured
158 # to go through IPSec inbound SPD policy lookup.
159 #
160 # 2 inbound SPD rules (1 HIGH and 1 LOW) are added.
161 # - High priority rule action is set to DISCARD.
162 # - Low priority rule action is set to BYPASS.
163 #
164 # Since BYPASS rules take precedence over DISCARD
165 # (the order being PROTECT, BYPASS, DISCARD) we expect the
166 # BYPASS rule to match and traffic to be correctly forwarded.
167 #
168 # The BYPASS rules is then removed, and we check that all traffic
169 # is now correctly dropped.
170 self.create_interfaces(2)
171 pkt_count = 5
172
173 self.spd_create_and_intf_add(1, [self.pg1, self.pg0])
174
175 # create input rules
176 # bypass rule should take precedence over discard rule,
177 # even though it's lower priority
178 policy_0 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200179 1,
180 self.pg1,
181 self.pg0,
182 socket.IPPROTO_UDP,
183 is_out=0,
184 priority=10,
185 policy_type="bypass",
186 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500187 policy_1 = self.spd_add_rem_policy( # inbound, priority 15
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200188 1,
189 self.pg1,
190 self.pg0,
191 socket.IPPROTO_UDP,
192 is_out=0,
193 priority=15,
194 policy_type="discard",
195 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500196
197 # create output rule so we can capture forwarded packets
198 policy_2 = self.spd_add_rem_policy( # outbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200199 1,
200 self.pg0,
201 self.pg1,
202 socket.IPPROTO_UDP,
203 is_out=1,
204 priority=10,
205 policy_type="bypass",
206 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500207
208 # check flow cache is empty before sending traffic
209 self.verify_num_inbound_flow_cache_entries(0)
210 # create the packet stream
211 packets = self.create_stream(self.pg0, self.pg1, pkt_count)
212 # add the stream to the source interface
213 self.pg0.add_stream(packets)
214 self.pg1.enable_capture()
215 self.pg_start()
216
217 # check capture on pg1
218 capture = self.pg1.get_capture()
219 for packet in capture:
220 try:
221 self.logger.debug(ppp("SPD Add - Got packet:", packet))
222 except Exception:
223 self.logger.error(ppp("Unexpected or invalid packet:", packet))
224 raise
225 self.logger.debug("SPD: Num packets: %s", len(capture.res))
226
227 # verify captured packets
228 self.verify_capture(self.pg0, self.pg1, capture)
229 # verify all policies matched the expected number of times
230 self.verify_policy_match(pkt_count, policy_0)
231 self.verify_policy_match(0, policy_1)
232 self.verify_policy_match(pkt_count, policy_2)
233 # check input policy has been cached
234 self.verify_num_inbound_flow_cache_entries(1)
235
236 # remove the input bypass rule
237 self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200238 1,
239 self.pg1,
240 self.pg0,
241 socket.IPPROTO_UDP,
242 is_out=0,
243 priority=10,
244 policy_type="bypass",
245 remove=True,
246 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500247 # verify flow cache counter has been reset by rule removal
248 self.verify_num_inbound_flow_cache_entries(0)
249
250 # resend the same packets
251 self.pg0.add_stream(packets)
252 self.pg1.enable_capture() # flush the old capture
253 self.pg_start()
254
255 # inbound discard rule should have dropped traffic
256 self.pg1.assert_nothing_captured()
257 # verify all policies matched the expected number of times
258 self.verify_policy_match(pkt_count, policy_0)
259 self.verify_policy_match(pkt_count, policy_1)
260 self.verify_policy_match(pkt_count, policy_2)
261 # by removing the bypass rule, we should have reset the flow cache
262 # we only expect the discard rule to now be in the flow cache
263 self.verify_num_inbound_flow_cache_entries(1)
264
265
Tianyu Li26c39872022-04-22 11:22:55 +0800266class IPSec4SpdTestCaseReaddInbound(SpdFlowCacheInbound):
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500267 """ IPSec/IPv4 inbound: Policy mode test case with flow cache \
268 (add, remove, re-add bypass)"""
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200269
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500270 def test_ipsec_spd_inbound_readd(self):
271 # In this test case, packets in IPv4 FWD path are configured
272 # to go through IPSec inbound SPD policy lookup.
273 #
274 # 2 inbound SPD rules (1 HIGH and 1 LOW) are added.
275 # - High priority rule action is set to DISCARD.
276 # - Low priority rule action is set to BYPASS.
277 #
278 # Since BYPASS rules take precedence over DISCARD
279 # (the order being PROTECT, BYPASS, DISCARD) we expect the
280 # BYPASS rule to match and traffic to be correctly forwarded.
281 #
282 # The BYPASS rules is then removed, and we check that all traffic
283 # is now correctly dropped.
284 #
285 # The BYPASS rule is then readded, checking traffic is not forwarded
286 # correctly again
287 self.create_interfaces(2)
288 pkt_count = 5
289
290 self.spd_create_and_intf_add(1, [self.pg1, self.pg0])
291
292 # create input rules
293 # bypass rule should take precedence over discard rule,
294 # even though it's lower priority
295 policy_0 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200296 1,
297 self.pg1,
298 self.pg0,
299 socket.IPPROTO_UDP,
300 is_out=0,
301 priority=10,
302 policy_type="bypass",
303 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500304 policy_1 = self.spd_add_rem_policy( # inbound, priority 15
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200305 1,
306 self.pg1,
307 self.pg0,
308 socket.IPPROTO_UDP,
309 is_out=0,
310 priority=15,
311 policy_type="discard",
312 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500313
314 # create output rule so we can capture forwarded packets
315 policy_2 = self.spd_add_rem_policy( # outbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200316 1,
317 self.pg0,
318 self.pg1,
319 socket.IPPROTO_UDP,
320 is_out=1,
321 priority=10,
322 policy_type="bypass",
323 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500324
325 # check flow cache is empty before sending traffic
326 self.verify_num_inbound_flow_cache_entries(0)
327 # create the packet stream
328 packets = self.create_stream(self.pg0, self.pg1, pkt_count)
329 # add the stream to the source interface
330 self.pg0.add_stream(packets)
331 self.pg1.enable_capture()
332 self.pg_start()
333
334 # check capture on pg1
335 capture = self.pg1.get_capture()
336 for packet in capture:
337 try:
338 self.logger.debug(ppp("SPD Add - Got packet:", packet))
339 except Exception:
340 self.logger.error(ppp("Unexpected or invalid packet:", packet))
341 raise
342 self.logger.debug("SPD: Num packets: %s", len(capture.res))
343
344 # verify captured packets
345 self.verify_capture(self.pg0, self.pg1, capture)
346 # verify all policies matched the expected number of times
347 self.verify_policy_match(pkt_count, policy_0)
348 self.verify_policy_match(0, policy_1)
349 self.verify_policy_match(pkt_count, policy_2)
350 # check input policy has been cached
351 self.verify_num_inbound_flow_cache_entries(1)
352
353 # remove the input bypass rule
354 self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200355 1,
356 self.pg1,
357 self.pg0,
358 socket.IPPROTO_UDP,
359 is_out=0,
360 priority=10,
361 policy_type="bypass",
362 remove=True,
363 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500364 # verify flow cache counter has been reset by rule removal
365 self.verify_num_inbound_flow_cache_entries(0)
366
367 # resend the same packets
368 self.pg0.add_stream(packets)
369 self.pg1.enable_capture() # flush the old capture
370 self.pg_start()
371
372 # inbound discard rule should have dropped traffic
373 self.pg1.assert_nothing_captured()
374 # verify all policies matched the expected number of times
375 self.verify_policy_match(pkt_count, policy_0)
376 self.verify_policy_match(pkt_count, policy_1)
377 self.verify_policy_match(pkt_count, policy_2)
378 # by removing the bypass rule, flow cache was reset
379 # we only expect the discard rule to now be in the flow cache
380 self.verify_num_inbound_flow_cache_entries(1)
381
382 # readd the input bypass rule
383 policy_0 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200384 1,
385 self.pg1,
386 self.pg0,
387 socket.IPPROTO_UDP,
388 is_out=0,
389 priority=10,
390 policy_type="bypass",
391 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500392 # verify flow cache counter has been reset by rule addition
393 self.verify_num_inbound_flow_cache_entries(0)
394
395 # resend the same packets
396 self.pg0.add_stream(packets)
397 self.pg1.enable_capture() # flush the old capture
398 self.pg_start()
399
400 # check capture on pg1
401 capture = self.pg1.get_capture()
402 for packet in capture:
403 try:
404 self.logger.debug(ppp("SPD Add - Got packet:", packet))
405 except Exception:
406 self.logger.error(ppp("Unexpected or invalid packet:", packet))
407 raise
408
409 # verify captured packets
410 self.verify_capture(self.pg0, self.pg1, capture)
411 # verify all policies matched the expected number of times
412 self.verify_policy_match(pkt_count, policy_0)
413 self.verify_policy_match(pkt_count, policy_1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200414 self.verify_policy_match(pkt_count * 2, policy_2)
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500415 # by readding the bypass rule, we reset the flow cache
416 # we only expect the bypass rule to now be in the flow cache
417 self.verify_num_inbound_flow_cache_entries(1)
418
419
Tianyu Li26c39872022-04-22 11:22:55 +0800420class IPSec4SpdTestCaseMultipleInbound(SpdFlowCacheInbound):
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500421 """ IPSec/IPv4 inbound: Policy mode test case with flow cache \
422 (multiple interfaces, multiple rules)"""
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200423
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500424 def test_ipsec_spd_inbound_multiple(self):
425 # In this test case, packets in IPv4 FWD path are configured to go
426 # through IPSec outbound SPD policy lookup.
427 #
428 # Multiples rules on multiple interfaces are tested at the same time.
429 # 3x interfaces are configured, binding the same SPD to each.
430 # Each interface has 1 SPD rule- 2x BYPASS and 1x DISCARD
431 #
432 # Traffic should be forwarded with destinations pg1 & pg2
433 # and dropped to pg0.
434 self.create_interfaces(3)
435 pkt_count = 5
436 # bind SPD to all interfaces
437 self.spd_create_and_intf_add(1, self.pg_interfaces)
438 # add input rules on all interfaces
439 # pg0 -> pg1
440 policy_0 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200441 1,
442 self.pg1,
443 self.pg0,
444 socket.IPPROTO_UDP,
445 is_out=0,
446 priority=10,
447 policy_type="bypass",
448 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500449 # pg1 -> pg2
450 policy_1 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200451 1,
452 self.pg2,
453 self.pg1,
454 socket.IPPROTO_UDP,
455 is_out=0,
456 priority=10,
457 policy_type="bypass",
458 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500459 # pg2 -> pg0
460 policy_2 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200461 1,
462 self.pg0,
463 self.pg2,
464 socket.IPPROTO_UDP,
465 is_out=0,
466 priority=10,
467 policy_type="discard",
468 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500469
470 # create output rules covering the the full ip range
471 # 0.0.0.0 -> 255.255.255.255, so we can capture forwarded packets
472 policy_3 = self.spd_add_rem_policy( # outbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200473 1,
474 self.pg0,
475 self.pg0,
476 socket.IPPROTO_UDP,
477 is_out=1,
478 priority=10,
479 policy_type="bypass",
480 all_ips=True,
481 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500482
483 # check flow cache is empty (0 active elements) before sending traffic
484 self.verify_num_inbound_flow_cache_entries(0)
485
486 # create the packet streams
487 packets0 = self.create_stream(self.pg0, self.pg1, pkt_count)
488 packets1 = self.create_stream(self.pg1, self.pg2, pkt_count)
489 packets2 = self.create_stream(self.pg2, self.pg0, pkt_count)
490 # add the streams to the source interfaces
491 self.pg0.add_stream(packets0)
492 self.pg1.add_stream(packets1)
493 self.pg2.add_stream(packets2)
494 # enable capture on all interfaces
495 for pg in self.pg_interfaces:
496 pg.enable_capture()
497 # start the packet generator
498 self.pg_start()
499
500 # get captures from ifs
501 if_caps = []
502 for pg in [self.pg1, self.pg2]: # we are expecting captures on pg1/pg2
503 if_caps.append(pg.get_capture())
504 for packet in if_caps[-1]:
505 try:
506 self.logger.debug(ppp("SPD Add - Got packet:", packet))
507 except Exception:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200508 self.logger.error(ppp("Unexpected or invalid packet:", packet))
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500509 raise
510
511 # verify captures that matched BYPASS rules
512 self.verify_capture(self.pg0, self.pg1, if_caps[0])
513 self.verify_capture(self.pg1, self.pg2, if_caps[1])
514 # verify that traffic to pg0 matched DISCARD rule and was dropped
515 self.pg0.assert_nothing_captured()
516 # verify all policies matched the expected number of times
517 self.verify_policy_match(pkt_count, policy_0)
518 self.verify_policy_match(pkt_count, policy_1)
519 self.verify_policy_match(pkt_count, policy_2)
520 # check flow/policy match was cached for: 3x input policies
521 self.verify_num_inbound_flow_cache_entries(3)
522
523
Tianyu Li26c39872022-04-22 11:22:55 +0800524class IPSec4SpdTestCaseOverwriteStaleInbound(SpdFlowCacheInbound):
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500525 """ IPSec/IPv4 inbound: Policy mode test case with flow cache \
526 (overwrite stale entries)"""
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200527
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500528 def test_ipsec_spd_inbound_overwrite(self):
529 # The operation of the flow cache is setup so that the entire cache
530 # is invalidated when adding or removing an SPD policy rule.
531 # For performance, old cache entries are not zero'd, but remain
532 # in the table as "stale" entries. If a flow matches a stale entry,
533 # and the epoch count does NOT match the current count, the entry
534 # is overwritten.
535 # In this test, 3 active rules are created and matched to enter
536 # them into the flow cache.
537 # A single entry is removed to invalidate the entire cache.
538 # We then readd the rule and test that overwriting of the previous
539 # stale entries occurs as expected, and that the flow cache entry
540 # counter is updated correctly.
541 self.create_interfaces(3)
542 pkt_count = 5
543 # bind SPD to all interfaces
544 self.spd_create_and_intf_add(1, self.pg_interfaces)
545 # add input rules on all interfaces
546 # pg0 -> pg1
547 policy_0 = self.spd_add_rem_policy( # inbound
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200548 1,
549 self.pg1,
550 self.pg0,
551 socket.IPPROTO_UDP,
552 is_out=0,
553 priority=10,
554 policy_type="bypass",
555 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500556 # pg1 -> pg2
557 policy_1 = self.spd_add_rem_policy( # inbound
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200558 1,
559 self.pg2,
560 self.pg1,
561 socket.IPPROTO_UDP,
562 is_out=0,
563 priority=10,
564 policy_type="bypass",
565 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500566 # pg2 -> pg0
567 policy_2 = self.spd_add_rem_policy( # inbound
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200568 1,
569 self.pg0,
570 self.pg2,
571 socket.IPPROTO_UDP,
572 is_out=0,
573 priority=10,
574 policy_type="discard",
575 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500576
577 # create output rules covering the the full ip range
578 # 0.0.0.0 -> 255.255.255.255, so we can capture forwarded packets
579 policy_3 = self.spd_add_rem_policy( # outbound
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200580 1,
581 self.pg0,
582 self.pg0,
583 socket.IPPROTO_UDP,
584 is_out=1,
585 priority=10,
586 policy_type="bypass",
587 all_ips=True,
588 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500589
590 # check flow cache is empty (0 active elements) before sending traffic
591 self.verify_num_inbound_flow_cache_entries(0)
592
593 # create the packet streams
594 packets0 = self.create_stream(self.pg0, self.pg1, pkt_count)
595 packets1 = self.create_stream(self.pg1, self.pg2, pkt_count)
596 packets2 = self.create_stream(self.pg2, self.pg0, pkt_count)
597 # add the streams to the source interfaces
598 self.pg0.add_stream(packets0)
599 self.pg1.add_stream(packets1)
600 self.pg2.add_stream(packets2)
601 # enable capture on all interfaces
602 for pg in self.pg_interfaces:
603 pg.enable_capture()
604 # start the packet generator
605 self.pg_start()
606
607 # get captures from ifs
608 if_caps = []
609 for pg in [self.pg1, self.pg2]: # we are expecting captures on pg1/pg2
610 if_caps.append(pg.get_capture())
611 for packet in if_caps[-1]:
612 try:
613 self.logger.debug(ppp("SPD Add - Got packet:", packet))
614 except Exception:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200615 self.logger.error(ppp("Unexpected or invalid packet:", packet))
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500616 raise
617
618 # verify captures that matched BYPASS rules
619 self.verify_capture(self.pg0, self.pg1, if_caps[0])
620 self.verify_capture(self.pg1, self.pg2, if_caps[1])
621 # verify that traffic to pg0 matched DISCARD rule and was dropped
622 self.pg0.assert_nothing_captured()
623 # verify all policies matched the expected number of times
624 self.verify_policy_match(pkt_count, policy_0)
625 self.verify_policy_match(pkt_count, policy_1)
626 self.verify_policy_match(pkt_count, policy_2)
627 # check flow/policy match was cached for: 3x input policies
628 self.verify_num_inbound_flow_cache_entries(3)
629
630 # adding an outbound policy should not invalidate output flow cache
631 self.spd_add_rem_policy( # outbound
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200632 1,
633 self.pg0,
634 self.pg0,
635 socket.IPPROTO_UDP,
636 is_out=1,
637 priority=1,
638 policy_type="bypass",
639 all_ips=True,
640 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500641 # check inbound flow cache counter has not been reset
642 self.verify_num_inbound_flow_cache_entries(3)
643
644 # remove + readd bypass policy - flow cache counter will be reset,
645 # and there will be 3x stale entries in flow cache
646 self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200647 1,
648 self.pg1,
649 self.pg0,
650 socket.IPPROTO_UDP,
651 is_out=0,
652 priority=10,
653 policy_type="bypass",
654 remove=True,
655 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500656 # readd policy
657 policy_0 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200658 1,
659 self.pg1,
660 self.pg0,
661 socket.IPPROTO_UDP,
662 is_out=0,
663 priority=10,
664 policy_type="bypass",
665 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500666 # check counter was reset
667 self.verify_num_inbound_flow_cache_entries(0)
668
669 # resend the same packets
670 self.pg0.add_stream(packets0)
671 self.pg1.add_stream(packets1)
672 self.pg2.add_stream(packets2)
673 for pg in self.pg_interfaces:
674 pg.enable_capture() # flush previous captures
675 self.pg_start()
676
677 # get captures from ifs
678 if_caps = []
679 for pg in [self.pg1, self.pg2]: # we are expecting captures on pg1/pg2
680 if_caps.append(pg.get_capture())
681 for packet in if_caps[-1]:
682 try:
683 self.logger.debug(ppp("SPD Add - Got packet:", packet))
684 except Exception:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200685 self.logger.error(ppp("Unexpected or invalid packet:", packet))
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500686 raise
687
688 # verify captures that matched BYPASS rules
689 self.verify_capture(self.pg0, self.pg1, if_caps[0])
690 self.verify_capture(self.pg1, self.pg2, if_caps[1])
691 # verify that traffic to pg0 matched DISCARD rule and was dropped
692 self.pg0.assert_nothing_captured()
693 # verify all policies matched the expected number of times
694 self.verify_policy_match(pkt_count, policy_0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200695 self.verify_policy_match(pkt_count * 2, policy_1)
696 self.verify_policy_match(pkt_count * 2, policy_2)
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500697 # we are overwriting 3x stale entries - check flow cache counter
698 # is correct
699 self.verify_num_inbound_flow_cache_entries(3)
700
701
Tianyu Li26c39872022-04-22 11:22:55 +0800702class IPSec4SpdTestCaseCollisionInbound(SpdFlowCacheInbound):
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500703 """ IPSec/IPv4 inbound: Policy mode test case with flow cache \
704 (hash collision)"""
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200705
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500706 # Override class setup to restrict hash table size to 16 buckets.
707 # This forces using only the lower 4 bits of the hash as a key,
708 # making hash collisions easy to find.
709 @classmethod
710 def setUpConstants(cls):
711 super(SpdFlowCacheInbound, cls).setUpConstants()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200712 cls.vpp_cmdline.extend(
713 [
714 "ipsec",
715 "{",
716 "ipv4-inbound-spd-flow-cache on",
717 "ipv4-inbound-spd-hash-buckets 16",
718 "}",
719 ]
720 )
721 cls.logger.info("VPP modified cmdline is %s" % " ".join(cls.vpp_cmdline))
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500722
723 def test_ipsec_spd_inbound_collision(self):
724 # The flow cache operation is setup to overwrite an entry
725 # if a hash collision occurs.
726 # In this test, 2 packets are configured that result in a
727 # hash with the same lower 4 bits.
728 # After the first packet is received, there should be one
729 # active entry in the flow cache.
730 # After the second packet with the same lower 4 bit hash
731 # is received, this should overwrite the same entry.
732 # Therefore there will still be a total of one (1) entry,
733 # in the flow cache with two matching policies.
734 # crc32_supported() method is used to check cpu for crc32
735 # intrinsic support for hashing.
736 # If crc32 is not supported, we fall back to clib_xxhash()
737 self.create_interfaces(4)
738 pkt_count = 5
739 # bind SPD to all interfaces
740 self.spd_create_and_intf_add(1, self.pg_interfaces)
741
742 # create output rules covering the the full ip range
743 # 0.0.0.0 -> 255.255.255.255, so we can capture forwarded packets
744 policy_0 = self.spd_add_rem_policy( # outbound
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200745 1,
746 self.pg0,
747 self.pg0,
748 socket.IPPROTO_UDP,
749 is_out=1,
750 priority=10,
751 policy_type="bypass",
752 all_ips=True,
753 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500754
755 capture_intfs = []
756 if self.crc32_supported(): # create crc32 collision on last 4 bits
757 hashed_with_crc32 = True
758 # add matching rules
759 policy_1 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200760 1,
761 self.pg1,
762 self.pg2,
763 socket.IPPROTO_UDP,
764 is_out=0,
765 priority=10,
766 policy_type="bypass",
767 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500768 policy_2 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200769 1,
770 self.pg3,
771 self.pg0,
772 socket.IPPROTO_UDP,
773 is_out=0,
774 priority=10,
775 policy_type="bypass",
776 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500777
778 # we expect to get captures on pg1 + pg3
779 capture_intfs.append(self.pg1)
780 capture_intfs.append(self.pg3)
781
782 # check flow cache is empty before sending traffic
783 self.verify_num_inbound_flow_cache_entries(0)
784
785 # create the packet streams
786 # packet hashes to:
787 # ad727628
Fan Zhange7901e82024-05-24 16:46:00 +0100788 packets1 = self.create_stream(self.pg2, self.pg1, pkt_count, 1, 4500)
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500789 # b5512898
Fan Zhange7901e82024-05-24 16:46:00 +0100790 packets2 = self.create_stream(self.pg0, self.pg3, pkt_count, 1, 4500)
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500791 # add the streams to the source interfaces
792 self.pg2.add_stream(packets1)
793 self.pg0.add_stream(packets2)
794 else: # create xxhash collision on last 4 bits
795 hashed_with_crc32 = False
796 # add matching rules
797 policy_1 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200798 1,
799 self.pg1,
800 self.pg2,
801 socket.IPPROTO_UDP,
802 is_out=0,
803 priority=10,
804 policy_type="bypass",
805 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500806 policy_2 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200807 1,
808 self.pg2,
809 self.pg3,
810 socket.IPPROTO_UDP,
811 is_out=0,
812 priority=10,
813 policy_type="bypass",
814 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500815
816 capture_intfs.append(self.pg1)
817 capture_intfs.append(self.pg2)
818
819 # check flow cache is empty before sending traffic
820 self.verify_num_inbound_flow_cache_entries(0)
821
822 # create the packet streams
823 # 2f8f90f557eef12c
Fan Zhange7901e82024-05-24 16:46:00 +0100824 packets1 = self.create_stream(self.pg2, self.pg1, pkt_count, 1, 4500)
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500825 # 6b7f9987719ffc1c
Fan Zhange7901e82024-05-24 16:46:00 +0100826 packets2 = self.create_stream(self.pg3, self.pg2, pkt_count, 1, 4500)
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500827 # add the streams to the source interfaces
828 self.pg2.add_stream(packets1)
829 self.pg3.add_stream(packets2)
830
831 # enable capture on interfaces we expect capture on & send pkts
832 for pg in capture_intfs:
833 pg.enable_capture()
834 self.pg_start()
835
836 # get captures
837 if_caps = []
838 for pg in capture_intfs:
839 if_caps.append(pg.get_capture())
840 for packet in if_caps[-1]:
841 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200842 self.logger.debug(ppp("SPD Add - Got packet:", packet))
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500843 except Exception:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200844 self.logger.error(ppp("Unexpected or invalid packet:", packet))
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500845 raise
846
847 # verify captures that matched BYPASS rule
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200848 if hashed_with_crc32:
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500849 self.verify_capture(self.pg2, self.pg1, if_caps[0])
850 self.verify_capture(self.pg0, self.pg3, if_caps[1])
851 else: # hashed with xxhash
852 self.verify_capture(self.pg2, self.pg1, if_caps[0])
853 self.verify_capture(self.pg3, self.pg2, if_caps[1])
854
855 # verify all policies matched the expected number of times
856 self.verify_policy_match(pkt_count, policy_1)
857 self.verify_policy_match(pkt_count, policy_2)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200858 self.verify_policy_match(pkt_count * 2, policy_0) # output policy
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500859 # we have matched 2 policies, but due to the hash collision
860 # one active entry is expected
861 self.verify_num_inbound_flow_cache_entries(1)
862
863
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200864if __name__ == "__main__":
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500865 unittest.main(testRunner=VppTestRunner)