blob: 47a260081cc338d19e0d1a61855656e068d1c3e2 [file] [log] [blame]
Neale Rannsd724e4f2020-04-02 15:02:16 +00001#!/usr/bin/env python3
2
3import unittest
4
Dave Wallace8800f732023-08-31 00:47:44 -04005from framework import VppTestCase
6from asfframework import VppTestRunner
Neale Rannsd724e4f2020-04-02 15:02:16 +00007
8from scapy.packet import Raw
9from scapy.layers.l2 import Ether
Dave Wallace8800f732023-08-31 00:47:44 -040010from scapy.layers.inet import IP, UDP
Neale Rannsd724e4f2020-04-02 15:02:16 +000011from scapy.layers.inet6 import IPv6
12
13from vpp_papi import VppEnum
Dmitry Valter34fa0ce2024-03-11 10:38:46 +000014from config import config
Neale Rannsd724e4f2020-04-02 15:02:16 +000015
16N_PKTS = 63
17
18
Dmitry Valter34fa0ce2024-03-11 10:38:46 +000019@unittest.skipIf("urpf" in config.excluded_plugins, "Exclude URPF plugin tests")
Neale Rannsd724e4f2020-04-02 15:02:16 +000020class TestURPF(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020021 """Unicast Reverse Path Forwarding Test Case"""
Neale Rannsd724e4f2020-04-02 15:02:16 +000022
23 @classmethod
24 def setUpClass(cls):
25 super(TestURPF, cls).setUpClass()
26
27 @classmethod
28 def tearDownClass(cls):
29 super(TestURPF, cls).tearDownClass()
30
31 def setUp(self):
32 super(TestURPF, self).setUp()
33
34 # create 4 pg interfaces so there are a few addresses
35 # in the FIB
36 self.create_pg_interfaces(range(4))
37
38 for i in self.pg_interfaces:
39 i.admin_up()
40 i.config_ip4()
41 i.resolve_arp()
42 i.config_ip6()
43 i.resolve_ndp()
44
45 def tearDown(self):
46 for i in self.pg_interfaces:
47 i.unconfig_ip4()
48 i.unconfig_ip6()
49 i.admin_down()
50 super(TestURPF, self).tearDown()
51
52 def test_urpf4(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020053 """uRPF IP4"""
Neale Rannsd724e4f2020-04-02 15:02:16 +000054
55 e = VppEnum
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020056 p_spoof_loose = (
57 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
58 / IP(src="3.3.3.3", dst=self.pg1.remote_ip4)
59 / UDP(sport=1234, dport=1234)
60 / Raw(b"\xa5" * 100)
61 ) * N_PKTS
62 p_spoof_strict = (
63 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
64 / IP(src=self.pg2.remote_ip4, dst=self.pg1.remote_ip4)
65 / UDP(sport=1234, dport=1234)
66 / Raw(b"\xa5" * 100)
67 ) * N_PKTS
68 p_good = (
69 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
70 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4)
71 / UDP(sport=1234, dport=1234)
72 / Raw(b"\xa5" * 100)
73 ) * N_PKTS
Neale Rannsd724e4f2020-04-02 15:02:16 +000074
75 #
76 # before adding the uRPF, ensure all packets are forwarded
77 #
78 self.send_and_expect(self.pg0, p_good, self.pg1)
79 self.send_and_expect(self.pg0, p_spoof_strict, self.pg1)
80 self.send_and_expect(self.pg0, p_spoof_loose, self.pg1)
81
82 #
83 # apply loose uRPF check on pg0 rx
84 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020085 self.vapi.urpf_update(
86 is_input=True,
87 mode=e.vl_api_urpf_mode_t.URPF_API_MODE_LOOSE,
88 af=e.vl_api_address_family_t.ADDRESS_IP4,
89 sw_if_index=self.pg0.sw_if_index,
90 )
Neale Rannsd724e4f2020-04-02 15:02:16 +000091
92 # good packets still pass
93 self.send_and_expect(self.pg0, p_good, self.pg1)
94 # packets from address for which there is a route are forwarded
95 self.send_and_expect(self.pg0, p_spoof_strict, self.pg1)
96 # packets from address to which there is no route are dropped
97 self.send_and_assert_no_replies(self.pg0, p_spoof_loose)
98
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020099 self.assert_error_counter_equal("/err/ip4-rx-urpf-loose/uRPF Drop", N_PKTS)
Neale Rannsd724e4f2020-04-02 15:02:16 +0000100
101 #
102 # crank it up to strict mode
103 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200104 self.vapi.urpf_update(
105 is_input=True,
106 mode=e.vl_api_urpf_mode_t.URPF_API_MODE_STRICT,
107 af=e.vl_api_address_family_t.ADDRESS_IP4,
108 sw_if_index=self.pg0.sw_if_index,
109 )
Neale Rannsd724e4f2020-04-02 15:02:16 +0000110
111 # good packets still pass
112 self.send_and_expect(self.pg0, p_good, self.pg1)
113 # packets that would not be routed back thru pg0 are dropped
114 self.send_and_assert_no_replies(self.pg0, p_spoof_strict)
115 self.send_and_assert_no_replies(self.pg0, p_spoof_loose)
116
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200117 self.assert_error_counter_equal("/err/ip4-rx-urpf-strict/uRPF Drop", 2 * N_PKTS)
Neale Rannsd724e4f2020-04-02 15:02:16 +0000118
119 #
120 # disable uRPF, all traffic should pass
121 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200122 self.vapi.urpf_update(
123 is_input=True,
124 mode=e.vl_api_urpf_mode_t.URPF_API_MODE_OFF,
125 af=e.vl_api_address_family_t.ADDRESS_IP4,
126 sw_if_index=self.pg0.sw_if_index,
127 )
Neale Rannsd724e4f2020-04-02 15:02:16 +0000128
129 self.send_and_expect(self.pg0, p_good, self.pg1)
130 self.send_and_expect(self.pg0, p_spoof_strict, self.pg1)
131 self.send_and_expect(self.pg0, p_spoof_loose, self.pg1)
132
133 #
134 # Now apply in the TX direction
135 # for loose it is the same deal, they should not be forwarded
136 # if there's no route
137 # for strict they should not be forwarded if they would be
138 # forwarded thru that interface.
139 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200140 self.vapi.urpf_update(
141 is_input=False,
142 mode=e.vl_api_urpf_mode_t.URPF_API_MODE_LOOSE,
143 af=e.vl_api_address_family_t.ADDRESS_IP4,
144 sw_if_index=self.pg1.sw_if_index,
145 )
Neale Rannsd724e4f2020-04-02 15:02:16 +0000146
147 self.send_and_expect(self.pg0, p_good, self.pg1)
148 self.send_and_expect(self.pg0, p_spoof_strict, self.pg1)
149 self.send_and_assert_no_replies(self.pg0, p_spoof_loose)
150
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200151 self.assert_error_counter_equal("/err/ip4-tx-urpf-loose/uRPF Drop", N_PKTS)
Neale Rannsd724e4f2020-04-02 15:02:16 +0000152
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200153 self.vapi.urpf_update(
154 is_input=False,
155 mode=e.vl_api_urpf_mode_t.URPF_API_MODE_STRICT,
156 af=e.vl_api_address_family_t.ADDRESS_IP4,
157 sw_if_index=self.pg1.sw_if_index,
158 )
Neale Rannsd724e4f2020-04-02 15:02:16 +0000159
160 self.send_and_expect(self.pg0, p_good, self.pg1)
161 # the strict packet, from a peer is allowed, since it does
162 # not forward via pg1
163 self.send_and_expect(self.pg0, p_spoof_strict, self.pg1)
164 self.send_and_assert_no_replies(self.pg0, p_spoof_loose)
165
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200166 self.assert_error_counter_equal("/err/ip4-tx-urpf-strict/uRPF Drop", N_PKTS)
Neale Rannsd724e4f2020-04-02 15:02:16 +0000167
168 # change the strict packet so that it would forward through pg1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200169 p_spoof_strict = (
170 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
171 / IP(src=self.pg1.remote_ip4, dst=self.pg1.remote_ip4)
172 / UDP(sport=1234, dport=1234)
173 / Raw(b"\xa5" * 100)
174 ) * N_PKTS
Neale Rannsd724e4f2020-04-02 15:02:16 +0000175
176 self.send_and_assert_no_replies(self.pg0, p_spoof_strict)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200177 self.assert_error_counter_equal("/err/ip4-tx-urpf-strict/uRPF Drop", 2 * N_PKTS)
Neale Rannsd724e4f2020-04-02 15:02:16 +0000178
179 # cleanup
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200180 self.vapi.urpf_update(
181 is_input=False,
182 mode=e.vl_api_urpf_mode_t.URPF_API_MODE_OFF,
183 af=e.vl_api_address_family_t.ADDRESS_IP4,
184 sw_if_index=self.pg1.sw_if_index,
185 )
Neale Rannsd724e4f2020-04-02 15:02:16 +0000186
187 def test_urpf6(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200188 """uRPF IP6"""
Neale Rannsd724e4f2020-04-02 15:02:16 +0000189
190 e = VppEnum
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200191 p_spoof_loose = (
192 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
193 / IPv6(src="3::3", dst=self.pg1.remote_ip6)
194 / UDP(sport=1236, dport=1236)
195 / Raw(b"\xa5" * 100)
196 ) * N_PKTS
197 p_spoof_strict = (
198 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
199 / IPv6(src=self.pg2.remote_ip6, dst=self.pg1.remote_ip6)
200 / UDP(sport=1236, dport=1236)
201 / Raw(b"\xa5" * 100)
202 ) * N_PKTS
203 p_good = (
204 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
205 / IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6)
206 / UDP(sport=1236, dport=1236)
207 / Raw(b"\xa5" * 100)
208 ) * N_PKTS
Neale Rannsd724e4f2020-04-02 15:02:16 +0000209
210 #
211 # before adding the uRPF, ensure all packets are forwarded
212 #
213 self.send_and_expect(self.pg0, p_good, self.pg1)
214 self.send_and_expect(self.pg0, p_spoof_strict, self.pg1)
215 self.send_and_expect(self.pg0, p_spoof_loose, self.pg1)
216
217 #
218 # apply loose uRPF check on pg0 rx
219 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200220 self.vapi.urpf_update(
221 is_input=True,
222 mode=e.vl_api_urpf_mode_t.URPF_API_MODE_LOOSE,
223 af=e.vl_api_address_family_t.ADDRESS_IP6,
224 sw_if_index=self.pg0.sw_if_index,
225 )
Neale Rannsd724e4f2020-04-02 15:02:16 +0000226
227 # good packets still pass
228 self.send_and_expect(self.pg0, p_good, self.pg1)
229 # packets from address for which there is a route are forwarded
230 self.send_and_expect(self.pg0, p_spoof_strict, self.pg1)
231 # packets from address to which there is no route are dropped
232 self.send_and_assert_no_replies(self.pg0, p_spoof_loose)
233
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200234 self.assert_error_counter_equal("/err/ip6-rx-urpf-loose/uRPF Drop", N_PKTS)
Neale Rannsd724e4f2020-04-02 15:02:16 +0000235
236 #
237 # crank it up to strict mode
238 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200239 self.vapi.urpf_update(
240 is_input=True,
241 mode=e.vl_api_urpf_mode_t.URPF_API_MODE_STRICT,
242 af=e.vl_api_address_family_t.ADDRESS_IP6,
243 sw_if_index=self.pg0.sw_if_index,
244 )
Neale Rannsd724e4f2020-04-02 15:02:16 +0000245
246 # good packets still pass
247 self.send_and_expect(self.pg0, p_good, self.pg1)
248 # packets that would not be routed back thru pg0 are dropped
249 self.send_and_assert_no_replies(self.pg0, p_spoof_strict)
250 self.send_and_assert_no_replies(self.pg0, p_spoof_loose)
251
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200252 self.assert_error_counter_equal("/err/ip6-rx-urpf-strict/uRPF Drop", 2 * N_PKTS)
Neale Rannsd724e4f2020-04-02 15:02:16 +0000253
254 #
255 # disable uRPF, all traffic should pass
256 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200257 self.vapi.urpf_update(
258 is_input=True,
259 mode=e.vl_api_urpf_mode_t.URPF_API_MODE_OFF,
260 af=e.vl_api_address_family_t.ADDRESS_IP6,
261 sw_if_index=self.pg0.sw_if_index,
262 )
Neale Rannsd724e4f2020-04-02 15:02:16 +0000263
264 self.send_and_expect(self.pg0, p_good, self.pg1)
265 self.send_and_expect(self.pg0, p_spoof_strict, self.pg1)
266 self.send_and_expect(self.pg0, p_spoof_loose, self.pg1)
267
268 #
269 # Now apply in the TX direction
270 # for loose it is the same deal, they should not be forwarded
271 # if there's no route
272 # for strict they should not be forwarded if they would be
273 # forwarded thru that interface.
274 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200275 self.vapi.urpf_update(
276 is_input=False,
277 mode=e.vl_api_urpf_mode_t.URPF_API_MODE_LOOSE,
278 af=e.vl_api_address_family_t.ADDRESS_IP6,
279 sw_if_index=self.pg1.sw_if_index,
280 )
Neale Rannsd724e4f2020-04-02 15:02:16 +0000281
282 self.send_and_expect(self.pg0, p_good, self.pg1)
283 self.send_and_expect(self.pg0, p_spoof_strict, self.pg1)
284 self.send_and_assert_no_replies(self.pg0, p_spoof_loose)
285
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200286 self.assert_error_counter_equal("/err/ip6-tx-urpf-loose/uRPF Drop", N_PKTS)
Neale Rannsd724e4f2020-04-02 15:02:16 +0000287
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200288 self.vapi.urpf_update(
289 is_input=False,
290 mode=e.vl_api_urpf_mode_t.URPF_API_MODE_STRICT,
291 af=e.vl_api_address_family_t.ADDRESS_IP6,
292 sw_if_index=self.pg1.sw_if_index,
293 )
Neale Rannsd724e4f2020-04-02 15:02:16 +0000294
295 self.send_and_expect(self.pg0, p_good, self.pg1)
296 # the strict packet, from a peer is allowed, since it does
297 # not forward via pg1
298 self.send_and_expect(self.pg0, p_spoof_strict, self.pg1)
299 self.send_and_assert_no_replies(self.pg0, p_spoof_loose)
300
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200301 self.assert_error_counter_equal("/err/ip6-tx-urpf-strict/uRPF Drop", N_PKTS)
Neale Rannsd724e4f2020-04-02 15:02:16 +0000302
303 # change the strict packet so that it would forward through pg1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200304 p_spoof_strict = (
305 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
306 / IPv6(src=self.pg1.remote_ip6, dst=self.pg1.remote_ip6)
307 / UDP(sport=1236, dport=1236)
308 / Raw(b"\xa5" * 100)
309 ) * N_PKTS
Neale Rannsd724e4f2020-04-02 15:02:16 +0000310
311 self.send_and_assert_no_replies(self.pg0, p_spoof_strict)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200312 self.assert_error_counter_equal("/err/ip6-tx-urpf-strict/uRPF Drop", 2 * N_PKTS)
Neale Rannsd724e4f2020-04-02 15:02:16 +0000313
314 # cleanup
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200315 self.vapi.urpf_update(
316 is_input=False,
317 mode=e.vl_api_urpf_mode_t.URPF_API_MODE_OFF,
318 af=e.vl_api_address_family_t.ADDRESS_IP6,
319 sw_if_index=self.pg1.sw_if_index,
320 )
Neale Rannsd724e4f2020-04-02 15:02:16 +0000321
Pim van Pelt2fa69ef2023-12-10 21:07:38 +0100322 def test_interface_dump(self):
323 """uRPF Interface Dump"""
324
325 self.create_loopback_interfaces(3)
326 e = VppEnum
327 self.vapi.urpf_update(
328 is_input=True,
329 mode=e.vl_api_urpf_mode_t.URPF_API_MODE_STRICT,
330 af=e.vl_api_address_family_t.ADDRESS_IP4,
331 sw_if_index=self.loop1.sw_if_index,
332 )
333 self.vapi.urpf_update(
334 is_input=False,
335 mode=e.vl_api_urpf_mode_t.URPF_API_MODE_LOOSE,
336 af=e.vl_api_address_family_t.ADDRESS_IP6,
337 sw_if_index=self.loop2.sw_if_index,
338 )
339
340 ret = self.vapi.urpf_interface_dump()
341 self.assertEqual(len(ret), 2)
342
343 dump_loop1 = ret[0]
344 dump_loop2 = ret[1]
345 self.assertEqual(dump_loop1.sw_if_index, self.loop1.sw_if_index)
346 self.assertTrue(dump_loop1.is_input)
347 self.assertEqual(dump_loop1.mode, e.vl_api_urpf_mode_t.URPF_API_MODE_STRICT)
348 self.assertEqual(dump_loop1.af, e.vl_api_address_family_t.ADDRESS_IP4)
349 self.assertEqual(dump_loop2.sw_if_index, self.loop2.sw_if_index)
350 self.assertFalse(dump_loop2.is_input)
351 self.assertEqual(dump_loop2.mode, e.vl_api_urpf_mode_t.URPF_API_MODE_LOOSE)
352 self.assertEqual(dump_loop2.af, e.vl_api_address_family_t.ADDRESS_IP6)
353
354 ret = self.vapi.urpf_interface_dump(sw_if_index=self.loop1.sw_if_index)
355 self.assertEqual(len(ret), 1)
356
357 dump_loop1 = ret[0]
358 self.assertEqual(dump_loop1.sw_if_index, self.loop1.sw_if_index)
359 self.assertTrue(dump_loop1.is_input)
360 self.assertEqual(dump_loop1.mode, e.vl_api_urpf_mode_t.URPF_API_MODE_STRICT)
361 self.assertEqual(dump_loop1.af, e.vl_api_address_family_t.ADDRESS_IP4)
362
363 # cleanup
364 self.vapi.urpf_update(
365 is_input=False,
366 mode=e.vl_api_urpf_mode_t.URPF_API_MODE_OFF,
367 af=e.vl_api_address_family_t.ADDRESS_IP4,
368 sw_if_index=self.loop1.sw_if_index,
369 )
370 self.vapi.urpf_update(
371 is_input=False,
372 mode=e.vl_api_urpf_mode_t.URPF_API_MODE_OFF,
373 af=e.vl_api_address_family_t.ADDRESS_IP6,
374 sw_if_index=self.loop2.sw_if_index,
375 )
376
Neale Rannsd724e4f2020-04-02 15:02:16 +0000377
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200378if __name__ == "__main__":
Neale Rannsd724e4f2020-04-02 15:02:16 +0000379 unittest.main(testRunner=VppTestRunner)