blob: 8af3b6cfcda5655a64189480bf5e7f8e97a29d8f [file] [log] [blame]
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +00001import socket
2import unittest
3
4from util import ppp
5from framework import VppTestRunner
6from template_ipsec import SpdFlowCacheTemplate
7
8
9class SpdFlowCacheOutbound(SpdFlowCacheTemplate):
10 # Override setUpConstants to enable outbound flow cache in config
11 @classmethod
12 def setUpConstants(cls):
13 super(SpdFlowCacheOutbound, cls).setUpConstants()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020014 cls.vpp_cmdline.extend(["ipsec", "{", "ipv4-outbound-spd-flow-cache on", "}"])
15 cls.logger.info("VPP modified cmdline is %s" % " ".join(cls.vpp_cmdline))
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +000016
17
18class IPSec4SpdTestCaseAdd(SpdFlowCacheOutbound):
19 """ IPSec/IPv4 outbound: Policy mode test case with flow cache \
20 (add rule)"""
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020021
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +000022 def test_ipsec_spd_outbound_add(self):
23 # In this test case, packets in IPv4 FWD path are configured
24 # to go through IPSec outbound SPD policy lookup.
25 # 2 SPD rules (1 HIGH and 1 LOW) are added.
26 # High priority rule action is set to BYPASS.
27 # Low priority rule action is set to DISCARD.
28 # Traffic sent on pg0 interface should match high priority
29 # rule and should be sent out on pg1 interface.
30 self.create_interfaces(2)
31 pkt_count = 5
32 self.spd_create_and_intf_add(1, [self.pg1])
33 policy_0 = self.spd_add_rem_policy( # outbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020034 1,
35 self.pg0,
36 self.pg1,
37 socket.IPPROTO_UDP,
38 is_out=1,
39 priority=10,
40 policy_type="bypass",
41 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +000042 policy_1 = self.spd_add_rem_policy( # outbound, priority 5
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020043 1,
44 self.pg0,
45 self.pg1,
46 socket.IPPROTO_UDP,
47 is_out=1,
48 priority=5,
49 policy_type="discard",
50 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +000051
52 # check flow cache is empty before sending traffic
53 self.verify_num_outbound_flow_cache_entries(0)
54
55 # create the packet stream
56 packets = self.create_stream(self.pg0, self.pg1, pkt_count)
57 # add the stream to the source interface + enable capture
58 self.pg0.add_stream(packets)
59 self.pg0.enable_capture()
60 self.pg1.enable_capture()
61 # start the packet generator
62 self.pg_start()
63 # get capture
64 capture = self.pg1.get_capture()
65 for packet in capture:
66 try:
67 self.logger.debug(ppp("SPD - Got packet:", packet))
68 except Exception:
69 self.logger.error(ppp("Unexpected or invalid packet:", packet))
70 raise
71 self.logger.debug("SPD: Num packets: %s", len(capture.res))
72
73 # assert nothing captured on pg0
74 self.pg0.assert_nothing_captured()
75 # verify captured packets
76 self.verify_capture(self.pg0, self.pg1, capture)
77 # verify all policies matched the expected number of times
78 self.verify_policy_match(pkt_count, policy_0)
79 self.verify_policy_match(0, policy_1)
80 # check policy in SPD has been cached after traffic
81 # matched BYPASS rule in SPD
82 self.verify_num_outbound_flow_cache_entries(1)
83
84
Tianyu Li26c39872022-04-22 11:22:55 +080085class IPSec4SpdTestCaseRemoveOutbound(SpdFlowCacheOutbound):
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +000086 """ IPSec/IPv4 outbound: Policy mode test case with flow cache \
87 (remove rule)"""
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020088
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +000089 def test_ipsec_spd_outbound_remove(self):
90 # In this test case, packets in IPv4 FWD path are configured
91 # to go through IPSec outbound SPD policy lookup.
92 # 2 SPD rules (1 HIGH and 1 LOW) are added.
93 # High priority rule action is set to BYPASS.
94 # Low priority rule action is set to DISCARD.
95 # High priority rule is then removed.
96 # Traffic sent on pg0 interface should match low priority
97 # rule and should be discarded after SPD lookup.
98 self.create_interfaces(2)
99 pkt_count = 5
100 self.spd_create_and_intf_add(1, [self.pg1])
101 policy_0 = self.spd_add_rem_policy( # outbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200102 1,
103 self.pg0,
104 self.pg1,
105 socket.IPPROTO_UDP,
106 is_out=1,
107 priority=10,
108 policy_type="bypass",
109 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000110 policy_1 = self.spd_add_rem_policy( # outbound, priority 5
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200111 1,
112 self.pg0,
113 self.pg1,
114 socket.IPPROTO_UDP,
115 is_out=1,
116 priority=5,
117 policy_type="discard",
118 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000119
120 # check flow cache is empty before sending traffic
121 self.verify_num_outbound_flow_cache_entries(0)
122
123 # create the packet stream
124 packets = self.create_stream(self.pg0, self.pg1, pkt_count)
125 # add the stream to the source interface + enable capture
126 self.pg0.add_stream(packets)
127 self.pg0.enable_capture()
128 self.pg1.enable_capture()
129 # start the packet generator
130 self.pg_start()
131 # get capture
132 capture = self.pg1.get_capture()
133 for packet in capture:
134 try:
135 self.logger.debug(ppp("SPD - Got packet:", packet))
136 except Exception:
137 self.logger.error(ppp("Unexpected or invalid packet:", packet))
138 raise
139
140 # assert nothing captured on pg0
141 self.pg0.assert_nothing_captured()
142 # verify capture on pg1
143 self.logger.debug("SPD: Num packets: %s", len(capture.res))
144 self.verify_capture(self.pg0, self.pg1, capture)
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 # check policy in SPD has been cached after traffic
149 # matched BYPASS rule in SPD
150 self.verify_num_outbound_flow_cache_entries(1)
151
152 # now remove the bypass rule
153 self.spd_add_rem_policy( # outbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200154 1,
155 self.pg0,
156 self.pg1,
157 socket.IPPROTO_UDP,
158 is_out=1,
159 priority=10,
160 policy_type="bypass",
161 remove=True,
162 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000163 # verify flow cache counter has been reset by rule removal
164 self.verify_num_outbound_flow_cache_entries(0)
165
166 # resend the same packets
167 self.pg0.add_stream(packets)
168 self.pg0.enable_capture() # flush the old captures
169 self.pg1.enable_capture()
170 self.pg_start()
171 # assert nothing captured on pg0
172 self.pg0.assert_nothing_captured()
173 # all packets will be dropped by SPD rule
174 self.pg1.assert_nothing_captured()
175 # verify all policies matched the expected number of times
176 self.verify_policy_match(pkt_count, policy_0)
177 self.verify_policy_match(pkt_count, policy_1)
178 # previous stale entry in flow cache should have been overwritten,
179 # with one active entry
180 self.verify_num_outbound_flow_cache_entries(1)
181
182
Tianyu Li26c39872022-04-22 11:22:55 +0800183class IPSec4SpdTestCaseReaddOutbound(SpdFlowCacheOutbound):
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000184 """ IPSec/IPv4 outbound: Policy mode test case with flow cache \
185 (add, remove, re-add)"""
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200186
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000187 def test_ipsec_spd_outbound_readd(self):
188 # In this test case, packets in IPv4 FWD path are configured
189 # to go through IPSec outbound SPD policy lookup.
190 # 2 SPD rules (1 HIGH and 1 LOW) are added.
191 # High priority rule action is set to BYPASS.
192 # Low priority rule action is set to DISCARD.
193 # Traffic sent on pg0 interface should match high priority
194 # rule and should be sent out on pg1 interface.
195 # High priority rule is then removed.
196 # Traffic sent on pg0 interface should match low priority
197 # rule and should be discarded after SPD lookup.
198 # Readd high priority rule.
199 # Traffic sent on pg0 interface should match high priority
200 # rule and should be sent out on pg1 interface.
201 self.create_interfaces(2)
202 pkt_count = 5
203 self.spd_create_and_intf_add(1, [self.pg1])
204 policy_0 = self.spd_add_rem_policy( # outbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200205 1,
206 self.pg0,
207 self.pg1,
208 socket.IPPROTO_UDP,
209 is_out=1,
210 priority=10,
211 policy_type="bypass",
212 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000213 policy_1 = self.spd_add_rem_policy( # outbound, priority 5
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200214 1,
215 self.pg0,
216 self.pg1,
217 socket.IPPROTO_UDP,
218 is_out=1,
219 priority=5,
220 policy_type="discard",
221 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000222
223 # check flow cache is empty before sending traffic
224 self.verify_num_outbound_flow_cache_entries(0)
225
226 # create the packet stream
227 packets = self.create_stream(self.pg0, self.pg1, pkt_count)
228 # add the stream to the source interface + enable capture
229 self.pg0.add_stream(packets)
230 self.pg0.enable_capture()
231 self.pg1.enable_capture()
232 # start the packet generator
233 self.pg_start()
234 # get capture
235 capture = self.pg1.get_capture()
236 for packet in capture:
237 try:
238 self.logger.debug(ppp("SPD - Got packet:", packet))
239 except Exception:
240 self.logger.error(ppp("Unexpected or invalid packet:", packet))
241 raise
242 self.logger.debug("SPD: Num packets: %s", len(capture.res))
243
244 # assert nothing captured on pg0
245 self.pg0.assert_nothing_captured()
246 # verify capture on pg1
247 self.verify_capture(self.pg0, self.pg1, capture)
248 # verify all policies matched the expected number of times
249 self.verify_policy_match(pkt_count, policy_0)
250 self.verify_policy_match(0, policy_1)
251 # check policy in SPD has been cached after traffic
252 # matched BYPASS rule in SPD
253 self.verify_num_outbound_flow_cache_entries(1)
254
255 # now remove the bypass rule, leaving only the discard rule
256 self.spd_add_rem_policy( # outbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200257 1,
258 self.pg0,
259 self.pg1,
260 socket.IPPROTO_UDP,
261 is_out=1,
262 priority=10,
263 policy_type="bypass",
264 remove=True,
265 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000266 # verify flow cache counter has been reset by rule removal
267 self.verify_num_outbound_flow_cache_entries(0)
268
269 # resend the same packets
270 self.pg0.add_stream(packets)
271 self.pg0.enable_capture() # flush the old captures
272 self.pg1.enable_capture()
273 self.pg_start()
274
275 # assert nothing captured on pg0
276 self.pg0.assert_nothing_captured()
277 # all packets will be dropped by SPD rule
278 self.pg1.assert_nothing_captured()
279 # verify all policies matched the expected number of times
280 self.verify_policy_match(pkt_count, policy_0)
281 self.verify_policy_match(pkt_count, policy_1)
282 # previous stale entry in flow cache should have been overwritten
283 self.verify_num_outbound_flow_cache_entries(1)
284
285 # now readd the bypass rule
286 policy_0 = self.spd_add_rem_policy( # outbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200287 1,
288 self.pg0,
289 self.pg1,
290 socket.IPPROTO_UDP,
291 is_out=1,
292 priority=10,
293 policy_type="bypass",
294 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000295 # verify flow cache counter has been reset by rule addition
296 self.verify_num_outbound_flow_cache_entries(0)
297
298 # resend the same packets
299 self.pg0.add_stream(packets)
300 self.pg0.enable_capture() # flush the old captures
301 self.pg1.enable_capture()
302 self.pg_start()
303
304 # get capture
305 capture = self.pg1.get_capture(pkt_count)
306 for packet in capture:
307 try:
308 self.logger.debug(ppp("SPD - Got packet:", packet))
309 except Exception:
310 self.logger.error(ppp("Unexpected or invalid packet:", packet))
311 raise
312 self.logger.debug("SPD: Num packets: %s", len(capture.res))
313
314 # assert nothing captured on pg0
315 self.pg0.assert_nothing_captured()
316 # verify captured packets
317 self.verify_capture(self.pg0, self.pg1, capture)
318 # verify all policies matched the expected number of times
319 self.verify_policy_match(pkt_count, policy_0)
320 self.verify_policy_match(pkt_count, policy_1)
321 # previous stale entry in flow cache should have been overwritten
322 self.verify_num_outbound_flow_cache_entries(1)
323
324
Tianyu Li26c39872022-04-22 11:22:55 +0800325class IPSec4SpdTestCaseMultipleOutbound(SpdFlowCacheOutbound):
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000326 """ IPSec/IPv4 outbound: Policy mode test case with flow cache \
327 (multiple interfaces, multiple rules)"""
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200328
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000329 def test_ipsec_spd_outbound_multiple(self):
330 # In this test case, packets in IPv4 FWD path are configured to go
331 # through IPSec outbound SPD policy lookup.
332 # Multiples rules on multiple interfaces are tested at the same time.
333 # 3x interfaces are configured, binding the same SPD to each.
334 # Each interface has 2 SPD rules (1 BYPASS and 1 DISCARD).
335 # On pg0 & pg1, the BYPASS rule is HIGH priority
336 # On pg2, the DISCARD rule is HIGH priority
337 # Traffic should be received on pg0 & pg1 and dropped on pg2.
338 self.create_interfaces(3)
339 pkt_count = 5
340 # bind SPD to all interfaces
341 self.spd_create_and_intf_add(1, self.pg_interfaces)
342 # add rules on all interfaces
343 policy_01 = self.spd_add_rem_policy( # outbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200344 1,
345 self.pg0,
346 self.pg1,
347 socket.IPPROTO_UDP,
348 is_out=1,
349 priority=10,
350 policy_type="bypass",
351 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000352 policy_02 = self.spd_add_rem_policy( # outbound, priority 5
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200353 1,
354 self.pg0,
355 self.pg1,
356 socket.IPPROTO_UDP,
357 is_out=1,
358 priority=5,
359 policy_type="discard",
360 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000361
362 policy_11 = self.spd_add_rem_policy( # outbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200363 1,
364 self.pg1,
365 self.pg2,
366 socket.IPPROTO_UDP,
367 is_out=1,
368 priority=10,
369 policy_type="bypass",
370 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000371 policy_12 = self.spd_add_rem_policy( # outbound, priority 5
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200372 1,
373 self.pg1,
374 self.pg2,
375 socket.IPPROTO_UDP,
376 is_out=1,
377 priority=5,
378 policy_type="discard",
379 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000380
381 policy_21 = self.spd_add_rem_policy( # outbound, priority 5
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200382 1,
383 self.pg2,
384 self.pg0,
385 socket.IPPROTO_UDP,
386 is_out=1,
387 priority=5,
388 policy_type="bypass",
389 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000390 policy_22 = self.spd_add_rem_policy( # outbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200391 1,
392 self.pg2,
393 self.pg0,
394 socket.IPPROTO_UDP,
395 is_out=1,
396 priority=10,
397 policy_type="discard",
398 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000399
Zachary Leaf26fec712021-10-26 10:05:58 -0500400 # interfaces bound to an SPD, will by default drop inbound
401 # traffic with no matching policies. add catch-all inbound
402 # bypass rule to SPD:
403 self.spd_add_rem_policy( # inbound, all interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200404 1,
405 None,
406 None,
407 socket.IPPROTO_UDP,
408 is_out=0,
409 priority=10,
410 policy_type="bypass",
411 all_ips=True,
412 )
Zachary Leaf26fec712021-10-26 10:05:58 -0500413
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000414 # check flow cache is empty (0 active elements) before sending traffic
415 self.verify_num_outbound_flow_cache_entries(0)
416
417 # create the packet streams
418 packets0 = self.create_stream(self.pg0, self.pg1, pkt_count)
419 packets1 = self.create_stream(self.pg1, self.pg2, pkt_count)
420 packets2 = self.create_stream(self.pg2, self.pg0, pkt_count)
421 # add the streams to the source interfaces
422 self.pg0.add_stream(packets0)
423 self.pg1.add_stream(packets1)
424 self.pg2.add_stream(packets2)
425 # enable capture on all interfaces
426 for pg in self.pg_interfaces:
427 pg.enable_capture()
428 # start the packet generator
429 self.pg_start()
430
431 # get captures
432 if_caps = []
433 for pg in [self.pg1, self.pg2]: # we are expecting captures on pg1/pg2
434 if_caps.append(pg.get_capture())
435 for packet in if_caps[-1]:
436 try:
437 self.logger.debug(ppp("SPD - Got packet:", packet))
438 except Exception:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200439 self.logger.error(ppp("Unexpected or invalid packet:", packet))
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000440 raise
441 self.logger.debug("SPD: Num packets: %s", len(if_caps[0].res))
442 self.logger.debug("SPD: Num packets: %s", len(if_caps[1].res))
443
444 # verify captures that matched BYPASS rule
445 self.verify_capture(self.pg0, self.pg1, if_caps[0])
446 self.verify_capture(self.pg1, self.pg2, if_caps[1])
447 # verify that traffic to pg0 matched DISCARD rule and was dropped
448 self.pg0.assert_nothing_captured()
449 # verify all packets that were expected to match rules, matched
450 # pg0 -> pg1
451 self.verify_policy_match(pkt_count, policy_01)
452 self.verify_policy_match(0, policy_02)
453 # pg1 -> pg2
454 self.verify_policy_match(pkt_count, policy_11)
455 self.verify_policy_match(0, policy_12)
456 # pg2 -> pg0
457 self.verify_policy_match(0, policy_21)
458 self.verify_policy_match(pkt_count, policy_22)
459 # check that 3 matching policies in SPD have been cached
460 self.verify_num_outbound_flow_cache_entries(3)
461
462
Tianyu Li26c39872022-04-22 11:22:55 +0800463class IPSec4SpdTestCaseOverwriteStaleOutbound(SpdFlowCacheOutbound):
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000464 """ IPSec/IPv4 outbound: Policy mode test case with flow cache \
465 (overwrite stale entries)"""
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200466
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000467 def test_ipsec_spd_outbound_overwrite(self):
468 # The operation of the flow cache is setup so that the entire cache
469 # is invalidated when adding or removing an SPD policy rule.
470 # For performance, old cache entries are not zero'd, but remain
471 # in the table as "stale" entries. If a flow matches a stale entry,
472 # and the epoch count does NOT match the current count, the entry
473 # is overwritten.
474 # In this test, 3 active rules are created and matched to enter
475 # them into the flow cache.
476 # A single entry is removed to invalidate the entire cache.
477 # We then readd the rule and test that overwriting of the previous
478 # stale entries occurs as expected, and that the flow cache entry
479 # counter is updated correctly.
480 self.create_interfaces(3)
481 pkt_count = 2
482 # bind SPD to all interfaces
483 self.spd_create_and_intf_add(1, self.pg_interfaces)
484 # add output rules on all interfaces
485 # pg0 -> pg1
486 policy_0 = self.spd_add_rem_policy( # outbound
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200487 1,
488 self.pg0,
489 self.pg1,
490 socket.IPPROTO_UDP,
491 is_out=1,
492 priority=10,
493 policy_type="bypass",
494 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000495 # pg1 -> pg2
496 policy_1 = self.spd_add_rem_policy( # outbound
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200497 1,
498 self.pg1,
499 self.pg2,
500 socket.IPPROTO_UDP,
501 is_out=1,
502 priority=10,
503 policy_type="bypass",
504 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000505 # pg2 -> pg0
506 policy_2 = self.spd_add_rem_policy( # outbound
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200507 1,
508 self.pg2,
509 self.pg0,
510 socket.IPPROTO_UDP,
511 is_out=1,
512 priority=10,
513 policy_type="discard",
514 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000515
Zachary Leaf26fec712021-10-26 10:05:58 -0500516 # interfaces bound to an SPD, will by default drop inbound
517 # traffic with no matching policies. add catch-all inbound
518 # bypass rule to SPD:
519 self.spd_add_rem_policy( # inbound, all interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200520 1,
521 None,
522 None,
523 socket.IPPROTO_UDP,
524 is_out=0,
525 priority=10,
526 policy_type="bypass",
527 all_ips=True,
528 )
Zachary Leaf26fec712021-10-26 10:05:58 -0500529
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000530 # check flow cache is empty (0 active elements) before sending traffic
531 self.verify_num_outbound_flow_cache_entries(0)
532
533 # create the packet streams
534 packets0 = self.create_stream(self.pg0, self.pg1, pkt_count)
535 packets1 = self.create_stream(self.pg1, self.pg2, pkt_count)
536 packets2 = self.create_stream(self.pg2, self.pg0, pkt_count)
537 # add the streams to the source interfaces
538 self.pg0.add_stream(packets0)
539 self.pg1.add_stream(packets1)
540 self.pg2.add_stream(packets2)
541 # enable capture on all interfaces
542 for pg in self.pg_interfaces:
543 pg.enable_capture()
544 # start the packet generator
545 self.pg_start()
546
547 # get captures from ifs
548 if_caps = []
549 for pg in [self.pg1, self.pg2]: # we are expecting captures on pg1/pg2
550 if_caps.append(pg.get_capture())
551 for packet in if_caps[-1]:
552 try:
553 self.logger.debug(ppp("SPD Add - Got packet:", packet))
554 except Exception:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200555 self.logger.error(ppp("Unexpected or invalid packet:", packet))
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000556 raise
557
558 # verify captures that matched BYPASS rules
559 self.verify_capture(self.pg0, self.pg1, if_caps[0])
560 self.verify_capture(self.pg1, self.pg2, if_caps[1])
561 # verify that traffic to pg0 matched DISCARD rule and was dropped
562 self.pg0.assert_nothing_captured()
563 # verify all policies matched the expected number of times
564 self.verify_policy_match(pkt_count, policy_0)
565 self.verify_policy_match(pkt_count, policy_1)
566 self.verify_policy_match(pkt_count, policy_2)
567 # check flow/policy match was cached for: 3x output policies
568 self.verify_num_outbound_flow_cache_entries(3)
569
570 # adding an inbound policy should not invalidate output flow cache
571 self.spd_add_rem_policy( # inbound
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200572 1,
573 self.pg0,
574 self.pg1,
575 socket.IPPROTO_UDP,
576 is_out=0,
577 priority=10,
578 policy_type="bypass",
579 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000580 # check flow cache counter has not been reset
581 self.verify_num_outbound_flow_cache_entries(3)
582
583 # remove a bypass policy - flow cache counter will be reset, and
584 # there will be 3x stale entries in flow cache
585 self.spd_add_rem_policy( # outbound
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200586 1,
587 self.pg0,
588 self.pg1,
589 socket.IPPROTO_UDP,
590 is_out=1,
591 priority=10,
592 policy_type="bypass",
593 remove=True,
594 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000595 # readd policy
596 policy_0 = self.spd_add_rem_policy( # outbound
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200597 1,
598 self.pg0,
599 self.pg1,
600 socket.IPPROTO_UDP,
601 is_out=1,
602 priority=10,
603 policy_type="bypass",
604 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000605 # check counter was reset with flow cache invalidation
606 self.verify_num_outbound_flow_cache_entries(0)
607
608 # resend the same packets
609 self.pg0.add_stream(packets0)
610 self.pg1.add_stream(packets1)
611 self.pg2.add_stream(packets2)
612 for pg in self.pg_interfaces:
613 pg.enable_capture() # flush previous captures
614 self.pg_start()
615
616 # get captures from ifs
617 if_caps = []
618 for pg in [self.pg1, self.pg2]: # we are expecting captures on pg1/pg2
619 if_caps.append(pg.get_capture())
620 for packet in if_caps[-1]:
621 try:
622 self.logger.debug(ppp("SPD Add - Got packet:", packet))
623 except Exception:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200624 self.logger.error(ppp("Unexpected or invalid packet:", packet))
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000625 raise
626
627 # verify captures that matched BYPASS rules
628 self.verify_capture(self.pg0, self.pg1, if_caps[0])
629 self.verify_capture(self.pg1, self.pg2, if_caps[1])
630 # verify that traffic to pg0 matched DISCARD rule and was dropped
631 self.pg0.assert_nothing_captured()
632 # verify all policies matched the expected number of times
633 self.verify_policy_match(pkt_count, policy_0)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200634 self.verify_policy_match(pkt_count * 2, policy_1)
635 self.verify_policy_match(pkt_count * 2, policy_2)
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000636 # we are overwriting 3x stale entries - check flow cache counter
637 # is correct
638 self.verify_num_outbound_flow_cache_entries(3)
639
640
Tianyu Li26c39872022-04-22 11:22:55 +0800641class IPSec4SpdTestCaseCollisionOutbound(SpdFlowCacheOutbound):
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000642 """ IPSec/IPv4 outbound: Policy mode test case with flow cache \
643 (hash collision)"""
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200644
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000645 # Override class setup to restrict vector size to 16 elements.
646 # This forces using only the lower 4 bits of the hash as a key,
647 # making hash collisions easy to find.
648 @classmethod
649 def setUpConstants(cls):
650 super(SpdFlowCacheOutbound, cls).setUpConstants()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200651 cls.vpp_cmdline.extend(
652 [
653 "ipsec",
654 "{",
655 "ipv4-outbound-spd-flow-cache on",
656 "ipv4-outbound-spd-hash-buckets 16",
657 "}",
658 ]
659 )
660 cls.logger.info("VPP modified cmdline is %s" % " ".join(cls.vpp_cmdline))
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000661
662 def test_ipsec_spd_outbound_collision(self):
663 # The flow cache operation is setup to overwrite an entry
664 # if a hash collision occurs.
665 # In this test, 2 packets are configured that result in a
666 # hash with the same lower 4 bits.
667 # After the first packet is received, there should be one
668 # active entry in the flow cache.
669 # After the second packet with the same lower 4 bit hash
670 # is received, this should overwrite the same entry.
671 # Therefore there will still be a total of one (1) entry,
672 # in the flow cache with two matching policies.
673 # crc32_supported() method is used to check cpu for crc32
674 # intrinsic support for hashing.
675 # If crc32 is not supported, we fall back to clib_xxhash()
676 self.create_interfaces(3)
677 pkt_count = 5
678 # bind SPD to all interfaces
679 self.spd_create_and_intf_add(1, self.pg_interfaces)
680 # add rules
681 policy_0 = self.spd_add_rem_policy( # outbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200682 1,
683 self.pg1,
684 self.pg2,
685 socket.IPPROTO_UDP,
686 is_out=1,
687 priority=10,
688 policy_type="bypass",
689 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000690 policy_1 = self.spd_add_rem_policy( # outbound, priority 10
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200691 1,
692 self.pg2,
693 self.pg0,
694 socket.IPPROTO_UDP,
695 is_out=1,
696 priority=10,
697 policy_type="bypass",
698 )
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000699
Zachary Leaf26fec712021-10-26 10:05:58 -0500700 # interfaces bound to an SPD, will by default drop inbound
701 # traffic with no matching policies. add catch-all inbound
702 # bypass rule to SPD:
703 self.spd_add_rem_policy( # inbound, all interfaces
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200704 1,
705 None,
706 None,
707 socket.IPPROTO_UDP,
708 is_out=0,
709 priority=10,
710 policy_type="bypass",
711 all_ips=True,
712 )
Zachary Leaf26fec712021-10-26 10:05:58 -0500713
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000714 # check flow cache is empty (0 active elements) before sending traffic
715 self.verify_num_outbound_flow_cache_entries(0)
716
717 # create the packet streams generating collision on last 4 bits
718 if self.crc32_supported():
719 # packet hashes to:
720 # 432c99c2
721 packets1 = self.create_stream(self.pg1, self.pg2, pkt_count, 1, 1)
722 # 31f8f3f2
723 packets2 = self.create_stream(self.pg2, self.pg0, pkt_count, 6, 6)
724 else: # clib_xxhash
725 # ec3a258551bc0306
726 packets1 = self.create_stream(self.pg1, self.pg2, pkt_count, 2, 2)
727 # 61fee526d18d7a6
728 packets2 = self.create_stream(self.pg2, self.pg0, pkt_count, 3, 3)
729
730 # add the streams to the source interfaces
731 self.pg1.add_stream(packets1)
732 self.pg2.add_stream(packets2)
733 # enable capture on all interfaces
734 for pg in self.pg_interfaces:
735 pg.enable_capture()
736 # start the packet generator
737 self.pg_start()
738
739 # get captures from ifs - the proper pkt_count of packets was saved by
740 # create_packet_info() based on dst_if parameter
741 if_caps = []
742 for pg in [self.pg2, self.pg0]: # we are expecting captures on pg2/pg0
743 if_caps.append(pg.get_capture())
744 for packet in if_caps[-1]:
745 try:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200746 self.logger.debug(ppp("SPD - Got packet:", packet))
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000747 except Exception:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200748 self.logger.error(ppp("Unexpected or invalid packet:", packet))
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000749 raise
750 self.logger.debug("SPD: Num packets: %s", len(if_caps[0].res))
751 self.logger.debug("SPD: Num packets: %s", len(if_caps[1].res))
752
753 # verify captures that matched BYPASS rule
754 self.verify_capture(self.pg1, self.pg2, if_caps[0])
755 self.verify_capture(self.pg2, self.pg0, if_caps[1])
756 # verify all packets that were expected to match rules, matched
757 self.verify_policy_match(pkt_count, policy_0)
758 self.verify_policy_match(pkt_count, policy_1)
759 # we have matched 2 policies, but due to the hash collision
760 # one active entry is expected
761 self.verify_num_outbound_flow_cache_entries(1)
762
763
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200764if __name__ == "__main__":
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000765 unittest.main(testRunner=VppTestRunner)