tests: Use errno value rather than a specific int
[vpp.git] / test / test_ipsec_spd_flow_cache_input.py
1 import socket
2 import unittest
3
4 from util import ppp
5 from asfframework import VppTestRunner
6 from template_ipsec import SpdFlowCacheTemplate
7
8
9 class SpdFlowCacheInbound(SpdFlowCacheTemplate):
10     # Override setUpConstants to enable inbound flow cache in config
11     @classmethod
12     def setUpConstants(cls):
13         super(SpdFlowCacheInbound, cls).setUpConstants()
14         cls.vpp_cmdline.extend(["ipsec", "{", "ipv4-inbound-spd-flow-cache on", "}"])
15         cls.logger.info("VPP modified cmdline is %s" % " ".join(cls.vpp_cmdline))
16
17
18 class IPSec4SpdTestCaseBypass(SpdFlowCacheInbound):
19     """ IPSec/IPv4 inbound: Policy mode test case with flow cache \
20         (add bypass)"""
21
22     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
42             1,
43             self.pg1,
44             self.pg0,
45             socket.IPPROTO_UDP,
46             is_out=0,
47             priority=10,
48             policy_type="bypass",
49         )
50         policy_1 = self.spd_add_rem_policy(  # inbound, priority 15
51             1,
52             self.pg1,
53             self.pg0,
54             socket.IPPROTO_UDP,
55             is_out=0,
56             priority=15,
57             policy_type="discard",
58         )
59
60         # create output rule so we can capture forwarded packets
61         policy_2 = self.spd_add_rem_policy(  # outbound, priority 10
62             1,
63             self.pg0,
64             self.pg1,
65             socket.IPPROTO_UDP,
66             is_out=1,
67             priority=10,
68             policy_type="bypass",
69         )
70
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
100 class IPSec4SpdTestCaseDiscard(SpdFlowCacheInbound):
101     """ IPSec/IPv4 inbound: Policy mode test case with flow cache \
102         (add discard)"""
103
104     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
115             1,
116             self.pg1,
117             self.pg0,
118             socket.IPPROTO_UDP,
119             is_out=0,
120             priority=10,
121             policy_type="discard",
122         )
123
124         # create output rule so we can capture forwarded packets
125         policy_1 = self.spd_add_rem_policy(  # outbound, priority 10
126             1,
127             self.pg0,
128             self.pg1,
129             socket.IPPROTO_UDP,
130             is_out=1,
131             priority=10,
132             policy_type="bypass",
133         )
134
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
152 class IPSec4SpdTestCaseRemoveInbound(SpdFlowCacheInbound):
153     """ IPSec/IPv4 inbound: Policy mode test case with flow cache \
154         (remove bypass)"""
155
156     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
179             1,
180             self.pg1,
181             self.pg0,
182             socket.IPPROTO_UDP,
183             is_out=0,
184             priority=10,
185             policy_type="bypass",
186         )
187         policy_1 = self.spd_add_rem_policy(  # inbound, priority 15
188             1,
189             self.pg1,
190             self.pg0,
191             socket.IPPROTO_UDP,
192             is_out=0,
193             priority=15,
194             policy_type="discard",
195         )
196
197         # create output rule so we can capture forwarded packets
198         policy_2 = self.spd_add_rem_policy(  # outbound, priority 10
199             1,
200             self.pg0,
201             self.pg1,
202             socket.IPPROTO_UDP,
203             is_out=1,
204             priority=10,
205             policy_type="bypass",
206         )
207
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
238             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         )
247         # 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
266 class IPSec4SpdTestCaseReaddInbound(SpdFlowCacheInbound):
267     """ IPSec/IPv4 inbound: Policy mode test case with flow cache \
268         (add, remove, re-add bypass)"""
269
270     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
296             1,
297             self.pg1,
298             self.pg0,
299             socket.IPPROTO_UDP,
300             is_out=0,
301             priority=10,
302             policy_type="bypass",
303         )
304         policy_1 = self.spd_add_rem_policy(  # inbound, priority 15
305             1,
306             self.pg1,
307             self.pg0,
308             socket.IPPROTO_UDP,
309             is_out=0,
310             priority=15,
311             policy_type="discard",
312         )
313
314         # create output rule so we can capture forwarded packets
315         policy_2 = self.spd_add_rem_policy(  # outbound, priority 10
316             1,
317             self.pg0,
318             self.pg1,
319             socket.IPPROTO_UDP,
320             is_out=1,
321             priority=10,
322             policy_type="bypass",
323         )
324
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
355             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         )
364         # 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
384             1,
385             self.pg1,
386             self.pg0,
387             socket.IPPROTO_UDP,
388             is_out=0,
389             priority=10,
390             policy_type="bypass",
391         )
392         # 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)
414         self.verify_policy_match(pkt_count * 2, policy_2)
415         # 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
420 class IPSec4SpdTestCaseMultipleInbound(SpdFlowCacheInbound):
421     """ IPSec/IPv4 inbound: Policy mode test case with flow cache \
422         (multiple interfaces, multiple rules)"""
423
424     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
441             1,
442             self.pg1,
443             self.pg0,
444             socket.IPPROTO_UDP,
445             is_out=0,
446             priority=10,
447             policy_type="bypass",
448         )
449         # pg1 -> pg2
450         policy_1 = self.spd_add_rem_policy(  # inbound, priority 10
451             1,
452             self.pg2,
453             self.pg1,
454             socket.IPPROTO_UDP,
455             is_out=0,
456             priority=10,
457             policy_type="bypass",
458         )
459         # pg2 -> pg0
460         policy_2 = self.spd_add_rem_policy(  # inbound, priority 10
461             1,
462             self.pg0,
463             self.pg2,
464             socket.IPPROTO_UDP,
465             is_out=0,
466             priority=10,
467             policy_type="discard",
468         )
469
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
473             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         )
482
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:
508                     self.logger.error(ppp("Unexpected or invalid packet:", packet))
509                     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
524 class IPSec4SpdTestCaseOverwriteStaleInbound(SpdFlowCacheInbound):
525     """ IPSec/IPv4 inbound: Policy mode test case with flow cache \
526         (overwrite stale entries)"""
527
528     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
548             1,
549             self.pg1,
550             self.pg0,
551             socket.IPPROTO_UDP,
552             is_out=0,
553             priority=10,
554             policy_type="bypass",
555         )
556         # pg1 -> pg2
557         policy_1 = self.spd_add_rem_policy(  # inbound
558             1,
559             self.pg2,
560             self.pg1,
561             socket.IPPROTO_UDP,
562             is_out=0,
563             priority=10,
564             policy_type="bypass",
565         )
566         # pg2 -> pg0
567         policy_2 = self.spd_add_rem_policy(  # inbound
568             1,
569             self.pg0,
570             self.pg2,
571             socket.IPPROTO_UDP,
572             is_out=0,
573             priority=10,
574             policy_type="discard",
575         )
576
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
580             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         )
589
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:
615                     self.logger.error(ppp("Unexpected or invalid packet:", packet))
616                     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
632             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         )
641         # 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
647             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         )
656         # readd policy
657         policy_0 = self.spd_add_rem_policy(  # inbound, priority 10
658             1,
659             self.pg1,
660             self.pg0,
661             socket.IPPROTO_UDP,
662             is_out=0,
663             priority=10,
664             policy_type="bypass",
665         )
666         # 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:
685                     self.logger.error(ppp("Unexpected or invalid packet:", packet))
686                     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)
695         self.verify_policy_match(pkt_count * 2, policy_1)
696         self.verify_policy_match(pkt_count * 2, policy_2)
697         # we are overwriting 3x stale entries - check flow cache counter
698         # is correct
699         self.verify_num_inbound_flow_cache_entries(3)
700
701
702 class IPSec4SpdTestCaseCollisionInbound(SpdFlowCacheInbound):
703     """ IPSec/IPv4 inbound: Policy mode test case with flow cache \
704         (hash collision)"""
705
706     # 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()
712         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))
722
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
745             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         )
754
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
760                 1,
761                 self.pg1,
762                 self.pg2,
763                 socket.IPPROTO_UDP,
764                 is_out=0,
765                 priority=10,
766                 policy_type="bypass",
767             )
768             policy_2 = self.spd_add_rem_policy(  # inbound, priority 10
769                 1,
770                 self.pg3,
771                 self.pg0,
772                 socket.IPPROTO_UDP,
773                 is_out=0,
774                 priority=10,
775                 policy_type="bypass",
776             )
777
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
788             packets1 = self.create_stream(self.pg2, self.pg1, pkt_count, 1, 1)
789             # b5512898
790             packets2 = self.create_stream(self.pg0, self.pg3, pkt_count, 1, 1)
791             # 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
798                 1,
799                 self.pg1,
800                 self.pg2,
801                 socket.IPPROTO_UDP,
802                 is_out=0,
803                 priority=10,
804                 policy_type="bypass",
805             )
806             policy_2 = self.spd_add_rem_policy(  # inbound, priority 10
807                 1,
808                 self.pg2,
809                 self.pg3,
810                 socket.IPPROTO_UDP,
811                 is_out=0,
812                 priority=10,
813                 policy_type="bypass",
814             )
815
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
824             packets1 = self.create_stream(self.pg2, self.pg1, pkt_count, 1, 1)
825             # 6b7f9987719ffc1c
826             packets2 = self.create_stream(self.pg3, self.pg2, pkt_count, 1, 1)
827             # 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:
842                     self.logger.debug(ppp("SPD Add - Got packet:", packet))
843                 except Exception:
844                     self.logger.error(ppp("Unexpected or invalid packet:", packet))
845                     raise
846
847         # verify captures that matched BYPASS rule
848         if hashed_with_crc32:
849             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)
858         self.verify_policy_match(pkt_count * 2, policy_0)  # output policy
859         # 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
864 if __name__ == "__main__":
865     unittest.main(testRunner=VppTestRunner)