blob: e8c560211bc104f7c07f590060c6b2bffcb685da [file] [log] [blame]
Zachary Leaf7cd35f52021-06-25 08:11:15 -05001from os import remove
2import socket
3import unittest
4
5from util import ppp
6from framework import VppTestRunner
7from template_ipsec import SpdFlowCacheTemplate
8
9
10class SpdFlowCacheInbound(SpdFlowCacheTemplate):
11 # Override setUpConstants to enable inbound flow cache in config
12 @classmethod
13 def setUpConstants(cls):
14 super(SpdFlowCacheInbound, cls).setUpConstants()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020015 cls.vpp_cmdline.extend(["ipsec", "{", "ipv4-inbound-spd-flow-cache on", "}"])
16 cls.logger.info("VPP modified cmdline is %s" % " ".join(cls.vpp_cmdline))
Zachary Leaf7cd35f52021-06-25 08:11:15 -050017
18
19class IPSec4SpdTestCaseBypass(SpdFlowCacheInbound):
20 """ IPSec/IPv4 inbound: Policy mode test case with flow cache \
21 (add bypass)"""
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020022
Zachary Leaf7cd35f52021-06-25 08:11:15 -050023 def test_ipsec_spd_inbound_bypass(self):
24 # In this test case, packets in IPv4 FWD path are configured
25 # to go through IPSec inbound SPD policy lookup.
26 #
27 # 2 inbound SPD rules (1 HIGH and 1 LOW) are added.
28 # - High priority rule action is set to DISCARD.
29 # - Low priority rule action is set to BYPASS.
30 #
31 # Since BYPASS rules take precedence over DISCARD
32 # (the order being PROTECT, BYPASS, DISCARD) we expect the
33 # BYPASS rule to match and traffic to be correctly forwarded.
34 self.create_interfaces(2)
35 pkt_count = 5
36
37 self.spd_create_and_intf_add(1, [self.pg1, self.pg0])
38
39 # create input rules
40 # bypass rule should take precedence over discard rule,
41 # even though it's lower priority
42 policy_0 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020043 1,
44 self.pg1,
45 self.pg0,
46 socket.IPPROTO_UDP,
47 is_out=0,
48 priority=10,
49 policy_type="bypass",
50 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -050051 policy_1 = self.spd_add_rem_policy( # inbound, priority 15
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020052 1,
53 self.pg1,
54 self.pg0,
55 socket.IPPROTO_UDP,
56 is_out=0,
57 priority=15,
58 policy_type="discard",
59 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -050060
61 # create output rule so we can capture forwarded packets
62 policy_2 = self.spd_add_rem_policy( # outbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020063 1,
64 self.pg0,
65 self.pg1,
66 socket.IPPROTO_UDP,
67 is_out=1,
68 priority=10,
69 policy_type="bypass",
70 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -050071
72 # check flow cache is empty before sending traffic
73 self.verify_num_inbound_flow_cache_entries(0)
74 # create the packet stream
75 packets = self.create_stream(self.pg0, self.pg1, pkt_count)
76 # add the stream to the source interface
77 self.pg0.add_stream(packets)
78 self.pg1.enable_capture()
79 self.pg_start()
80
81 # check capture on pg1
82 capture = self.pg1.get_capture()
83 for packet in capture:
84 try:
85 self.logger.debug(ppp("SPD Add - Got packet:", packet))
86 except Exception:
87 self.logger.error(ppp("Unexpected or invalid packet:", packet))
88 raise
89 self.logger.debug("SPD: Num packets: %s", len(capture.res))
90
91 # verify captured packets
92 self.verify_capture(self.pg0, self.pg1, capture)
93 # verify all policies matched the expected number of times
94 self.verify_policy_match(pkt_count, policy_0)
95 self.verify_policy_match(0, policy_1)
96 self.verify_policy_match(pkt_count, policy_2)
97 # check input policy has been cached
98 self.verify_num_inbound_flow_cache_entries(1)
99
100
101class IPSec4SpdTestCaseDiscard(SpdFlowCacheInbound):
102 """ IPSec/IPv4 inbound: Policy mode test case with flow cache \
103 (add discard)"""
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200104
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500105 def test_ipsec_spd_inbound_discard(self):
106 # In this test case, packets in IPv4 FWD path are configured
107 # to go through IPSec inbound SPD policy lookup.
108 # 1 DISCARD rule is added, so all traffic should be dropped.
109 self.create_interfaces(2)
110 pkt_count = 5
111
112 self.spd_create_and_intf_add(1, [self.pg1, self.pg0])
113
114 # create input rule
115 policy_0 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200116 1,
117 self.pg1,
118 self.pg0,
119 socket.IPPROTO_UDP,
120 is_out=0,
121 priority=10,
122 policy_type="discard",
123 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500124
125 # create output rule so we can capture forwarded packets
126 policy_1 = self.spd_add_rem_policy( # outbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200127 1,
128 self.pg0,
129 self.pg1,
130 socket.IPPROTO_UDP,
131 is_out=1,
132 priority=10,
133 policy_type="bypass",
134 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500135
136 # check flow cache is empty before sending traffic
137 self.verify_num_inbound_flow_cache_entries(0)
138 # create the packet stream
139 packets = self.create_stream(self.pg0, self.pg1, pkt_count)
140 # add the stream to the source interface
141 self.pg0.add_stream(packets)
142 self.pg1.enable_capture()
143 self.pg_start()
144 # inbound discard rule should have dropped traffic
145 self.pg1.assert_nothing_captured()
146 # verify all policies matched the expected number of times
147 self.verify_policy_match(pkt_count, policy_0)
148 self.verify_policy_match(0, policy_1)
149 # only inbound discard rule should have been cached
150 self.verify_num_inbound_flow_cache_entries(1)
151
152
Tianyu Li26c39872022-04-22 11:22:55 +0800153class IPSec4SpdTestCaseRemoveInbound(SpdFlowCacheInbound):
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500154 """ IPSec/IPv4 inbound: Policy mode test case with flow cache \
155 (remove bypass)"""
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200156
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500157 def test_ipsec_spd_inbound_remove(self):
158 # In this test case, packets in IPv4 FWD path are configured
159 # to go through IPSec inbound SPD policy lookup.
160 #
161 # 2 inbound SPD rules (1 HIGH and 1 LOW) are added.
162 # - High priority rule action is set to DISCARD.
163 # - Low priority rule action is set to BYPASS.
164 #
165 # Since BYPASS rules take precedence over DISCARD
166 # (the order being PROTECT, BYPASS, DISCARD) we expect the
167 # BYPASS rule to match and traffic to be correctly forwarded.
168 #
169 # The BYPASS rules is then removed, and we check that all traffic
170 # is now correctly dropped.
171 self.create_interfaces(2)
172 pkt_count = 5
173
174 self.spd_create_and_intf_add(1, [self.pg1, self.pg0])
175
176 # create input rules
177 # bypass rule should take precedence over discard rule,
178 # even though it's lower priority
179 policy_0 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200180 1,
181 self.pg1,
182 self.pg0,
183 socket.IPPROTO_UDP,
184 is_out=0,
185 priority=10,
186 policy_type="bypass",
187 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500188 policy_1 = self.spd_add_rem_policy( # inbound, priority 15
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200189 1,
190 self.pg1,
191 self.pg0,
192 socket.IPPROTO_UDP,
193 is_out=0,
194 priority=15,
195 policy_type="discard",
196 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500197
198 # create output rule so we can capture forwarded packets
199 policy_2 = self.spd_add_rem_policy( # outbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200200 1,
201 self.pg0,
202 self.pg1,
203 socket.IPPROTO_UDP,
204 is_out=1,
205 priority=10,
206 policy_type="bypass",
207 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500208
209 # check flow cache is empty before sending traffic
210 self.verify_num_inbound_flow_cache_entries(0)
211 # create the packet stream
212 packets = self.create_stream(self.pg0, self.pg1, pkt_count)
213 # add the stream to the source interface
214 self.pg0.add_stream(packets)
215 self.pg1.enable_capture()
216 self.pg_start()
217
218 # check capture on pg1
219 capture = self.pg1.get_capture()
220 for packet in capture:
221 try:
222 self.logger.debug(ppp("SPD Add - Got packet:", packet))
223 except Exception:
224 self.logger.error(ppp("Unexpected or invalid packet:", packet))
225 raise
226 self.logger.debug("SPD: Num packets: %s", len(capture.res))
227
228 # verify captured packets
229 self.verify_capture(self.pg0, self.pg1, capture)
230 # verify all policies matched the expected number of times
231 self.verify_policy_match(pkt_count, policy_0)
232 self.verify_policy_match(0, policy_1)
233 self.verify_policy_match(pkt_count, policy_2)
234 # check input policy has been cached
235 self.verify_num_inbound_flow_cache_entries(1)
236
237 # remove the input bypass rule
238 self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200239 1,
240 self.pg1,
241 self.pg0,
242 socket.IPPROTO_UDP,
243 is_out=0,
244 priority=10,
245 policy_type="bypass",
246 remove=True,
247 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500248 # verify flow cache counter has been reset by rule removal
249 self.verify_num_inbound_flow_cache_entries(0)
250
251 # resend the same packets
252 self.pg0.add_stream(packets)
253 self.pg1.enable_capture() # flush the old capture
254 self.pg_start()
255
256 # inbound discard rule should have dropped traffic
257 self.pg1.assert_nothing_captured()
258 # verify all policies matched the expected number of times
259 self.verify_policy_match(pkt_count, policy_0)
260 self.verify_policy_match(pkt_count, policy_1)
261 self.verify_policy_match(pkt_count, policy_2)
262 # by removing the bypass rule, we should have reset the flow cache
263 # we only expect the discard rule to now be in the flow cache
264 self.verify_num_inbound_flow_cache_entries(1)
265
266
Tianyu Li26c39872022-04-22 11:22:55 +0800267class IPSec4SpdTestCaseReaddInbound(SpdFlowCacheInbound):
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500268 """ IPSec/IPv4 inbound: Policy mode test case with flow cache \
269 (add, remove, re-add bypass)"""
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200270
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500271 def test_ipsec_spd_inbound_readd(self):
272 # In this test case, packets in IPv4 FWD path are configured
273 # to go through IPSec inbound SPD policy lookup.
274 #
275 # 2 inbound SPD rules (1 HIGH and 1 LOW) are added.
276 # - High priority rule action is set to DISCARD.
277 # - Low priority rule action is set to BYPASS.
278 #
279 # Since BYPASS rules take precedence over DISCARD
280 # (the order being PROTECT, BYPASS, DISCARD) we expect the
281 # BYPASS rule to match and traffic to be correctly forwarded.
282 #
283 # The BYPASS rules is then removed, and we check that all traffic
284 # is now correctly dropped.
285 #
286 # The BYPASS rule is then readded, checking traffic is not forwarded
287 # correctly again
288 self.create_interfaces(2)
289 pkt_count = 5
290
291 self.spd_create_and_intf_add(1, [self.pg1, self.pg0])
292
293 # create input rules
294 # bypass rule should take precedence over discard rule,
295 # even though it's lower priority
296 policy_0 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200297 1,
298 self.pg1,
299 self.pg0,
300 socket.IPPROTO_UDP,
301 is_out=0,
302 priority=10,
303 policy_type="bypass",
304 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500305 policy_1 = self.spd_add_rem_policy( # inbound, priority 15
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200306 1,
307 self.pg1,
308 self.pg0,
309 socket.IPPROTO_UDP,
310 is_out=0,
311 priority=15,
312 policy_type="discard",
313 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500314
315 # create output rule so we can capture forwarded packets
316 policy_2 = self.spd_add_rem_policy( # outbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200317 1,
318 self.pg0,
319 self.pg1,
320 socket.IPPROTO_UDP,
321 is_out=1,
322 priority=10,
323 policy_type="bypass",
324 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500325
326 # check flow cache is empty before sending traffic
327 self.verify_num_inbound_flow_cache_entries(0)
328 # create the packet stream
329 packets = self.create_stream(self.pg0, self.pg1, pkt_count)
330 # add the stream to the source interface
331 self.pg0.add_stream(packets)
332 self.pg1.enable_capture()
333 self.pg_start()
334
335 # check capture on pg1
336 capture = self.pg1.get_capture()
337 for packet in capture:
338 try:
339 self.logger.debug(ppp("SPD Add - Got packet:", packet))
340 except Exception:
341 self.logger.error(ppp("Unexpected or invalid packet:", packet))
342 raise
343 self.logger.debug("SPD: Num packets: %s", len(capture.res))
344
345 # verify captured packets
346 self.verify_capture(self.pg0, self.pg1, capture)
347 # verify all policies matched the expected number of times
348 self.verify_policy_match(pkt_count, policy_0)
349 self.verify_policy_match(0, policy_1)
350 self.verify_policy_match(pkt_count, policy_2)
351 # check input policy has been cached
352 self.verify_num_inbound_flow_cache_entries(1)
353
354 # remove the input bypass rule
355 self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200356 1,
357 self.pg1,
358 self.pg0,
359 socket.IPPROTO_UDP,
360 is_out=0,
361 priority=10,
362 policy_type="bypass",
363 remove=True,
364 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500365 # verify flow cache counter has been reset by rule removal
366 self.verify_num_inbound_flow_cache_entries(0)
367
368 # resend the same packets
369 self.pg0.add_stream(packets)
370 self.pg1.enable_capture() # flush the old capture
371 self.pg_start()
372
373 # inbound discard rule should have dropped traffic
374 self.pg1.assert_nothing_captured()
375 # verify all policies matched the expected number of times
376 self.verify_policy_match(pkt_count, policy_0)
377 self.verify_policy_match(pkt_count, policy_1)
378 self.verify_policy_match(pkt_count, policy_2)
379 # by removing the bypass rule, flow cache was reset
380 # we only expect the discard rule to now be in the flow cache
381 self.verify_num_inbound_flow_cache_entries(1)
382
383 # readd the input bypass rule
384 policy_0 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200385 1,
386 self.pg1,
387 self.pg0,
388 socket.IPPROTO_UDP,
389 is_out=0,
390 priority=10,
391 policy_type="bypass",
392 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500393 # verify flow cache counter has been reset by rule addition
394 self.verify_num_inbound_flow_cache_entries(0)
395
396 # resend the same packets
397 self.pg0.add_stream(packets)
398 self.pg1.enable_capture() # flush the old capture
399 self.pg_start()
400
401 # check capture on pg1
402 capture = self.pg1.get_capture()
403 for packet in capture:
404 try:
405 self.logger.debug(ppp("SPD Add - Got packet:", packet))
406 except Exception:
407 self.logger.error(ppp("Unexpected or invalid packet:", packet))
408 raise
409
410 # verify captured packets
411 self.verify_capture(self.pg0, self.pg1, capture)
412 # verify all policies matched the expected number of times
413 self.verify_policy_match(pkt_count, policy_0)
414 self.verify_policy_match(pkt_count, policy_1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200415 self.verify_policy_match(pkt_count * 2, policy_2)
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500416 # by readding the bypass rule, we reset the flow cache
417 # we only expect the bypass rule to now be in the flow cache
418 self.verify_num_inbound_flow_cache_entries(1)
419
420
Tianyu Li26c39872022-04-22 11:22:55 +0800421class IPSec4SpdTestCaseMultipleInbound(SpdFlowCacheInbound):
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500422 """ IPSec/IPv4 inbound: Policy mode test case with flow cache \
423 (multiple interfaces, multiple rules)"""
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200424
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500425 def test_ipsec_spd_inbound_multiple(self):
426 # In this test case, packets in IPv4 FWD path are configured to go
427 # through IPSec outbound SPD policy lookup.
428 #
429 # Multiples rules on multiple interfaces are tested at the same time.
430 # 3x interfaces are configured, binding the same SPD to each.
431 # Each interface has 1 SPD rule- 2x BYPASS and 1x DISCARD
432 #
433 # Traffic should be forwarded with destinations pg1 & pg2
434 # and dropped to pg0.
435 self.create_interfaces(3)
436 pkt_count = 5
437 # bind SPD to all interfaces
438 self.spd_create_and_intf_add(1, self.pg_interfaces)
439 # add input rules on all interfaces
440 # pg0 -> pg1
441 policy_0 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200442 1,
443 self.pg1,
444 self.pg0,
445 socket.IPPROTO_UDP,
446 is_out=0,
447 priority=10,
448 policy_type="bypass",
449 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500450 # pg1 -> pg2
451 policy_1 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200452 1,
453 self.pg2,
454 self.pg1,
455 socket.IPPROTO_UDP,
456 is_out=0,
457 priority=10,
458 policy_type="bypass",
459 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500460 # pg2 -> pg0
461 policy_2 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200462 1,
463 self.pg0,
464 self.pg2,
465 socket.IPPROTO_UDP,
466 is_out=0,
467 priority=10,
468 policy_type="discard",
469 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500470
471 # create output rules covering the the full ip range
472 # 0.0.0.0 -> 255.255.255.255, so we can capture forwarded packets
473 policy_3 = self.spd_add_rem_policy( # outbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200474 1,
475 self.pg0,
476 self.pg0,
477 socket.IPPROTO_UDP,
478 is_out=1,
479 priority=10,
480 policy_type="bypass",
481 all_ips=True,
482 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500483
484 # check flow cache is empty (0 active elements) before sending traffic
485 self.verify_num_inbound_flow_cache_entries(0)
486
487 # create the packet streams
488 packets0 = self.create_stream(self.pg0, self.pg1, pkt_count)
489 packets1 = self.create_stream(self.pg1, self.pg2, pkt_count)
490 packets2 = self.create_stream(self.pg2, self.pg0, pkt_count)
491 # add the streams to the source interfaces
492 self.pg0.add_stream(packets0)
493 self.pg1.add_stream(packets1)
494 self.pg2.add_stream(packets2)
495 # enable capture on all interfaces
496 for pg in self.pg_interfaces:
497 pg.enable_capture()
498 # start the packet generator
499 self.pg_start()
500
501 # get captures from ifs
502 if_caps = []
503 for pg in [self.pg1, self.pg2]: # we are expecting captures on pg1/pg2
504 if_caps.append(pg.get_capture())
505 for packet in if_caps[-1]:
506 try:
507 self.logger.debug(ppp("SPD Add - Got packet:", packet))
508 except Exception:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200509 self.logger.error(ppp("Unexpected or invalid packet:", packet))
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500510 raise
511
512 # verify captures that matched BYPASS rules
513 self.verify_capture(self.pg0, self.pg1, if_caps[0])
514 self.verify_capture(self.pg1, self.pg2, if_caps[1])
515 # verify that traffic to pg0 matched DISCARD rule and was dropped
516 self.pg0.assert_nothing_captured()
517 # verify all policies matched the expected number of times
518 self.verify_policy_match(pkt_count, policy_0)
519 self.verify_policy_match(pkt_count, policy_1)
520 self.verify_policy_match(pkt_count, policy_2)
521 # check flow/policy match was cached for: 3x input policies
522 self.verify_num_inbound_flow_cache_entries(3)
523
524
Tianyu Li26c39872022-04-22 11:22:55 +0800525class IPSec4SpdTestCaseOverwriteStaleInbound(SpdFlowCacheInbound):
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500526 """ IPSec/IPv4 inbound: Policy mode test case with flow cache \
527 (overwrite stale entries)"""
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200528
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500529 def test_ipsec_spd_inbound_overwrite(self):
530 # The operation of the flow cache is setup so that the entire cache
531 # is invalidated when adding or removing an SPD policy rule.
532 # For performance, old cache entries are not zero'd, but remain
533 # in the table as "stale" entries. If a flow matches a stale entry,
534 # and the epoch count does NOT match the current count, the entry
535 # is overwritten.
536 # In this test, 3 active rules are created and matched to enter
537 # them into the flow cache.
538 # A single entry is removed to invalidate the entire cache.
539 # We then readd the rule and test that overwriting of the previous
540 # stale entries occurs as expected, and that the flow cache entry
541 # counter is updated correctly.
542 self.create_interfaces(3)
543 pkt_count = 5
544 # bind SPD to all interfaces
545 self.spd_create_and_intf_add(1, self.pg_interfaces)
546 # add input rules on all interfaces
547 # pg0 -> pg1
548 policy_0 = self.spd_add_rem_policy( # inbound
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200549 1,
550 self.pg1,
551 self.pg0,
552 socket.IPPROTO_UDP,
553 is_out=0,
554 priority=10,
555 policy_type="bypass",
556 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500557 # pg1 -> pg2
558 policy_1 = self.spd_add_rem_policy( # inbound
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200559 1,
560 self.pg2,
561 self.pg1,
562 socket.IPPROTO_UDP,
563 is_out=0,
564 priority=10,
565 policy_type="bypass",
566 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500567 # pg2 -> pg0
568 policy_2 = self.spd_add_rem_policy( # inbound
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200569 1,
570 self.pg0,
571 self.pg2,
572 socket.IPPROTO_UDP,
573 is_out=0,
574 priority=10,
575 policy_type="discard",
576 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500577
578 # create output rules covering the the full ip range
579 # 0.0.0.0 -> 255.255.255.255, so we can capture forwarded packets
580 policy_3 = self.spd_add_rem_policy( # outbound
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200581 1,
582 self.pg0,
583 self.pg0,
584 socket.IPPROTO_UDP,
585 is_out=1,
586 priority=10,
587 policy_type="bypass",
588 all_ips=True,
589 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500590
591 # check flow cache is empty (0 active elements) before sending traffic
592 self.verify_num_inbound_flow_cache_entries(0)
593
594 # create the packet streams
595 packets0 = self.create_stream(self.pg0, self.pg1, pkt_count)
596 packets1 = self.create_stream(self.pg1, self.pg2, pkt_count)
597 packets2 = self.create_stream(self.pg2, self.pg0, pkt_count)
598 # add the streams to the source interfaces
599 self.pg0.add_stream(packets0)
600 self.pg1.add_stream(packets1)
601 self.pg2.add_stream(packets2)
602 # enable capture on all interfaces
603 for pg in self.pg_interfaces:
604 pg.enable_capture()
605 # start the packet generator
606 self.pg_start()
607
608 # get captures from ifs
609 if_caps = []
610 for pg in [self.pg1, self.pg2]: # we are expecting captures on pg1/pg2
611 if_caps.append(pg.get_capture())
612 for packet in if_caps[-1]:
613 try:
614 self.logger.debug(ppp("SPD Add - Got packet:", packet))
615 except Exception:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200616 self.logger.error(ppp("Unexpected or invalid packet:", packet))
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500617 raise
618
619 # verify captures that matched BYPASS rules
620 self.verify_capture(self.pg0, self.pg1, if_caps[0])
621 self.verify_capture(self.pg1, self.pg2, if_caps[1])
622 # verify that traffic to pg0 matched DISCARD rule and was dropped
623 self.pg0.assert_nothing_captured()
624 # verify all policies matched the expected number of times
625 self.verify_policy_match(pkt_count, policy_0)
626 self.verify_policy_match(pkt_count, policy_1)
627 self.verify_policy_match(pkt_count, policy_2)
628 # check flow/policy match was cached for: 3x input policies
629 self.verify_num_inbound_flow_cache_entries(3)
630
631 # adding an outbound policy should not invalidate output flow cache
632 self.spd_add_rem_policy( # outbound
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200633 1,
634 self.pg0,
635 self.pg0,
636 socket.IPPROTO_UDP,
637 is_out=1,
638 priority=1,
639 policy_type="bypass",
640 all_ips=True,
641 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500642 # check inbound flow cache counter has not been reset
643 self.verify_num_inbound_flow_cache_entries(3)
644
645 # remove + readd bypass policy - flow cache counter will be reset,
646 # and there will be 3x stale entries in flow cache
647 self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200648 1,
649 self.pg1,
650 self.pg0,
651 socket.IPPROTO_UDP,
652 is_out=0,
653 priority=10,
654 policy_type="bypass",
655 remove=True,
656 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500657 # readd policy
658 policy_0 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200659 1,
660 self.pg1,
661 self.pg0,
662 socket.IPPROTO_UDP,
663 is_out=0,
664 priority=10,
665 policy_type="bypass",
666 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500667 # check counter was reset
668 self.verify_num_inbound_flow_cache_entries(0)
669
670 # resend the same packets
671 self.pg0.add_stream(packets0)
672 self.pg1.add_stream(packets1)
673 self.pg2.add_stream(packets2)
674 for pg in self.pg_interfaces:
675 pg.enable_capture() # flush previous captures
676 self.pg_start()
677
678 # get captures from ifs
679 if_caps = []
680 for pg in [self.pg1, self.pg2]: # we are expecting captures on pg1/pg2
681 if_caps.append(pg.get_capture())
682 for packet in if_caps[-1]:
683 try:
684 self.logger.debug(ppp("SPD Add - Got packet:", packet))
685 except Exception:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200686 self.logger.error(ppp("Unexpected or invalid packet:", packet))
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500687 raise
688
689 # verify captures that matched BYPASS rules
690 self.verify_capture(self.pg0, self.pg1, if_caps[0])
691 self.verify_capture(self.pg1, self.pg2, if_caps[1])
692 # verify that traffic to pg0 matched DISCARD rule and was dropped
693 self.pg0.assert_nothing_captured()
694 # verify all policies matched the expected number of times
695 self.verify_policy_match(pkt_count, policy_0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200696 self.verify_policy_match(pkt_count * 2, policy_1)
697 self.verify_policy_match(pkt_count * 2, policy_2)
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500698 # we are overwriting 3x stale entries - check flow cache counter
699 # is correct
700 self.verify_num_inbound_flow_cache_entries(3)
701
702
Tianyu Li26c39872022-04-22 11:22:55 +0800703class IPSec4SpdTestCaseCollisionInbound(SpdFlowCacheInbound):
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500704 """ IPSec/IPv4 inbound: Policy mode test case with flow cache \
705 (hash collision)"""
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200706
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500707 # Override class setup to restrict hash table size to 16 buckets.
708 # This forces using only the lower 4 bits of the hash as a key,
709 # making hash collisions easy to find.
710 @classmethod
711 def setUpConstants(cls):
712 super(SpdFlowCacheInbound, cls).setUpConstants()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200713 cls.vpp_cmdline.extend(
714 [
715 "ipsec",
716 "{",
717 "ipv4-inbound-spd-flow-cache on",
718 "ipv4-inbound-spd-hash-buckets 16",
719 "}",
720 ]
721 )
722 cls.logger.info("VPP modified cmdline is %s" % " ".join(cls.vpp_cmdline))
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500723
724 def test_ipsec_spd_inbound_collision(self):
725 # The flow cache operation is setup to overwrite an entry
726 # if a hash collision occurs.
727 # In this test, 2 packets are configured that result in a
728 # hash with the same lower 4 bits.
729 # After the first packet is received, there should be one
730 # active entry in the flow cache.
731 # After the second packet with the same lower 4 bit hash
732 # is received, this should overwrite the same entry.
733 # Therefore there will still be a total of one (1) entry,
734 # in the flow cache with two matching policies.
735 # crc32_supported() method is used to check cpu for crc32
736 # intrinsic support for hashing.
737 # If crc32 is not supported, we fall back to clib_xxhash()
738 self.create_interfaces(4)
739 pkt_count = 5
740 # bind SPD to all interfaces
741 self.spd_create_and_intf_add(1, self.pg_interfaces)
742
743 # create output rules covering the the full ip range
744 # 0.0.0.0 -> 255.255.255.255, so we can capture forwarded packets
745 policy_0 = self.spd_add_rem_policy( # outbound
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200746 1,
747 self.pg0,
748 self.pg0,
749 socket.IPPROTO_UDP,
750 is_out=1,
751 priority=10,
752 policy_type="bypass",
753 all_ips=True,
754 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500755
756 capture_intfs = []
757 if self.crc32_supported(): # create crc32 collision on last 4 bits
758 hashed_with_crc32 = True
759 # add matching rules
760 policy_1 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200761 1,
762 self.pg1,
763 self.pg2,
764 socket.IPPROTO_UDP,
765 is_out=0,
766 priority=10,
767 policy_type="bypass",
768 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500769 policy_2 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200770 1,
771 self.pg3,
772 self.pg0,
773 socket.IPPROTO_UDP,
774 is_out=0,
775 priority=10,
776 policy_type="bypass",
777 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500778
779 # we expect to get captures on pg1 + pg3
780 capture_intfs.append(self.pg1)
781 capture_intfs.append(self.pg3)
782
783 # check flow cache is empty before sending traffic
784 self.verify_num_inbound_flow_cache_entries(0)
785
786 # create the packet streams
787 # packet hashes to:
788 # ad727628
789 packets1 = self.create_stream(self.pg2, self.pg1, pkt_count, 1, 1)
790 # b5512898
791 packets2 = self.create_stream(self.pg0, self.pg3, pkt_count, 1, 1)
792 # add the streams to the source interfaces
793 self.pg2.add_stream(packets1)
794 self.pg0.add_stream(packets2)
795 else: # create xxhash collision on last 4 bits
796 hashed_with_crc32 = False
797 # add matching rules
798 policy_1 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200799 1,
800 self.pg1,
801 self.pg2,
802 socket.IPPROTO_UDP,
803 is_out=0,
804 priority=10,
805 policy_type="bypass",
806 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500807 policy_2 = self.spd_add_rem_policy( # inbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200808 1,
809 self.pg2,
810 self.pg3,
811 socket.IPPROTO_UDP,
812 is_out=0,
813 priority=10,
814 policy_type="bypass",
815 )
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500816
817 capture_intfs.append(self.pg1)
818 capture_intfs.append(self.pg2)
819
820 # check flow cache is empty before sending traffic
821 self.verify_num_inbound_flow_cache_entries(0)
822
823 # create the packet streams
824 # 2f8f90f557eef12c
825 packets1 = self.create_stream(self.pg2, self.pg1, pkt_count, 1, 1)
826 # 6b7f9987719ffc1c
827 packets2 = self.create_stream(self.pg3, self.pg2, pkt_count, 1, 1)
828 # add the streams to the source interfaces
829 self.pg2.add_stream(packets1)
830 self.pg3.add_stream(packets2)
831
832 # enable capture on interfaces we expect capture on & send pkts
833 for pg in capture_intfs:
834 pg.enable_capture()
835 self.pg_start()
836
837 # get captures
838 if_caps = []
839 for pg in capture_intfs:
840 if_caps.append(pg.get_capture())
841 for packet in if_caps[-1]:
842 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200843 self.logger.debug(ppp("SPD Add - Got packet:", packet))
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500844 except Exception:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200845 self.logger.error(ppp("Unexpected or invalid packet:", packet))
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500846 raise
847
848 # verify captures that matched BYPASS rule
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200849 if hashed_with_crc32:
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500850 self.verify_capture(self.pg2, self.pg1, if_caps[0])
851 self.verify_capture(self.pg0, self.pg3, if_caps[1])
852 else: # hashed with xxhash
853 self.verify_capture(self.pg2, self.pg1, if_caps[0])
854 self.verify_capture(self.pg3, self.pg2, if_caps[1])
855
856 # verify all policies matched the expected number of times
857 self.verify_policy_match(pkt_count, policy_1)
858 self.verify_policy_match(pkt_count, policy_2)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200859 self.verify_policy_match(pkt_count * 2, policy_0) # output policy
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500860 # we have matched 2 policies, but due to the hash collision
861 # one active entry is expected
862 self.verify_num_inbound_flow_cache_entries(1)
863
864
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200865if __name__ == "__main__":
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500866 unittest.main(testRunner=VppTestRunner)