ethernet: check destination mac for L3 in ethernet-input node
[vpp.git] / test / test_l2_flood.py
1 #!/usr/bin/env python3
2
3 import unittest
4
5 from framework import VppTestCase
6 from asfframework import VppTestRunner
7 from vpp_ip_route import VppIpRoute, VppRoutePath
8 from vpp_l2 import L2_PORT_TYPE, BRIDGE_FLAGS
9
10 from scapy.packet import Raw
11 from scapy.layers.l2 import Ether
12 from scapy.layers.inet import IP, UDP
13
14 NUM_PKTS = 67
15
16
17 class TestL2Flood(VppTestCase):
18     """L2-flood"""
19
20     @classmethod
21     def setUpClass(cls):
22         super(TestL2Flood, cls).setUpClass()
23
24     @classmethod
25     def tearDownClass(cls):
26         super(TestL2Flood, cls).tearDownClass()
27
28     def setUp(self):
29         super(TestL2Flood, self).setUp()
30
31         # 12 l2 interface and one l3
32         self.create_pg_interfaces(range(13))
33         self.create_bvi_interfaces(1)
34
35         for i in self.pg_interfaces:
36             i.admin_up()
37         for i in self.bvi_interfaces:
38             i.admin_up()
39
40         self.pg12.config_ip4()
41         self.pg12.resolve_arp()
42         self.bvi0.config_ip4()
43
44     def tearDown(self):
45         self.pg12.unconfig_ip4()
46         self.bvi0.unconfig_ip4()
47
48         for i in self.pg_interfaces:
49             i.admin_down()
50         for i in self.bvi_interfaces:
51             i.admin_down()
52         super(TestL2Flood, self).tearDown()
53
54     def test_flood(self):
55         """L2 Flood Tests"""
56
57         #
58         # Create a single bridge Domain
59         #
60         self.vapi.bridge_domain_add_del_v2(
61             bd_id=1, is_add=1, flood=1, uu_flood=1, forward=1, learn=1
62         )
63
64         #
65         # add each interface to the BD. 3 interfaces per split horizon group
66         #
67         for i in self.pg_interfaces[0:4]:
68             self.vapi.sw_interface_set_l2_bridge(
69                 rx_sw_if_index=i.sw_if_index, bd_id=1, shg=0
70             )
71         for i in self.pg_interfaces[4:8]:
72             self.vapi.sw_interface_set_l2_bridge(
73                 rx_sw_if_index=i.sw_if_index, bd_id=1, shg=1
74             )
75         for i in self.pg_interfaces[8:12]:
76             self.vapi.sw_interface_set_l2_bridge(
77                 rx_sw_if_index=i.sw_if_index, bd_id=1, shg=2
78             )
79         for i in self.bvi_interfaces:
80             self.vapi.sw_interface_set_l2_bridge(
81                 rx_sw_if_index=i.sw_if_index, bd_id=1, shg=2, port_type=L2_PORT_TYPE.BVI
82             )
83
84         p = (
85             Ether(dst="ff:ff:ff:ff:ff:ff", src="00:00:de:ad:be:ef")
86             / IP(src="10.10.10.10", dst="1.1.1.1")
87             / UDP(sport=1234, dport=1234)
88             / Raw(b"\xa5" * 100)
89         )
90
91         #
92         # input on pg0 expect copies on pg1->11
93         # this is in SHG=0 so its flooded to all, expect the pg0 since that's
94         # the ingress link
95         #
96         self.pg0.add_stream(p * NUM_PKTS)
97         self.pg_enable_capture(self.pg_interfaces)
98         self.pg_start()
99
100         for i in self.pg_interfaces[1:12]:
101             rx0 = i.get_capture(NUM_PKTS, timeout=1)
102
103         #
104         # input on pg4 (SHG=1) expect copies on pg0->3 (SHG=0)
105         # and pg8->11 (SHG=2)
106         #
107         self.pg4.add_stream(p * NUM_PKTS)
108         self.pg_enable_capture(self.pg_interfaces)
109         self.pg_start()
110
111         for i in self.pg_interfaces[:4]:
112             rx0 = i.get_capture(NUM_PKTS, timeout=1)
113         for i in self.pg_interfaces[8:12]:
114             rx0 = i.get_capture(NUM_PKTS, timeout=1)
115         for i in self.pg_interfaces[4:8]:
116             i.assert_nothing_captured(remark="Different SH group")
117
118         #
119         # An IP route so the packet that hits the BVI is sent out of pg12
120         #
121         ip_route = VppIpRoute(
122             self,
123             "1.1.1.1",
124             32,
125             [VppRoutePath(self.pg12.remote_ip4, self.pg12.sw_if_index)],
126         )
127         ip_route.add_vpp_config()
128
129         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
130
131         #
132         # input on pg0 expect copies on pg1->12
133         # this is in SHG=0 so its flooded to all, expect the pg0 since that's
134         # the ingress link
135         #
136         self.pg0.add_stream(p * NUM_PKTS)
137         self.pg_enable_capture(self.pg_interfaces)
138         self.pg_start()
139
140         for i in self.pg_interfaces[1:]:
141             rx0 = i.get_capture(NUM_PKTS, timeout=1)
142
143         #
144         # input on pg4 (SHG=1) expect copies on pg0->3 (SHG=0)
145         # and pg8->12 (SHG=2)
146         #
147         self.pg4.add_stream(p * NUM_PKTS)
148         self.pg_enable_capture(self.pg_interfaces)
149         self.pg_start()
150
151         for i in self.pg_interfaces[:4]:
152             rx0 = i.get_capture(NUM_PKTS, timeout=1)
153         for i in self.pg_interfaces[8:13]:
154             rx0 = i.get_capture(NUM_PKTS, timeout=1)
155         for i in self.pg_interfaces[4:8]:
156             i.assert_nothing_captured(remark="Different SH group")
157
158         #
159         # cleanup
160         #
161         for i in self.pg_interfaces[:12]:
162             self.vapi.sw_interface_set_l2_bridge(
163                 rx_sw_if_index=i.sw_if_index, bd_id=1, enable=0
164             )
165         for i in self.bvi_interfaces:
166             self.vapi.sw_interface_set_l2_bridge(
167                 rx_sw_if_index=i.sw_if_index,
168                 bd_id=1,
169                 shg=2,
170                 port_type=L2_PORT_TYPE.BVI,
171                 enable=0,
172             )
173
174         self.vapi.bridge_domain_add_del_v2(bd_id=1, is_add=0)
175
176     def test_flood_one(self):
177         """L2 no-Flood Test"""
178
179         #
180         # Create a single bridge Domain
181         #
182         self.vapi.bridge_domain_add_del_v2(
183             bd_id=1, is_add=1, flood=1, uu_flood=1, forward=1, learn=1
184         )
185
186         #
187         # add 2 interfaces to the BD. this means a flood goes to only
188         # one member
189         #
190         for i in self.pg_interfaces[:2]:
191             self.vapi.sw_interface_set_l2_bridge(
192                 rx_sw_if_index=i.sw_if_index, bd_id=1, shg=0
193             )
194
195         p = (
196             Ether(dst="ff:ff:ff:ff:ff:ff", src="00:00:de:ad:be:ef")
197             / IP(src="10.10.10.10", dst="1.1.1.1")
198             / UDP(sport=1234, dport=1234)
199             / Raw(b"\xa5" * 100)
200         )
201
202         #
203         # input on pg0 expect copies on pg1
204         #
205         self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg1)
206
207         #
208         # cleanup
209         #
210         for i in self.pg_interfaces[:2]:
211             self.vapi.sw_interface_set_l2_bridge(
212                 rx_sw_if_index=i.sw_if_index, bd_id=1, enable=0
213             )
214         self.vapi.bridge_domain_add_del_v2(bd_id=1, is_add=0)
215
216     def test_uu_fwd(self):
217         """UU Flood"""
218
219         #
220         # Create a single bridge Domain
221         #
222         self.vapi.bridge_domain_add_del_v2(
223             bd_id=1, is_add=1, uu_flood=1, flood=1, forward=1, learn=1
224         )
225
226         #
227         # add each interface to the BD. 3 interfaces per split horizon group
228         #
229         for i in self.pg_interfaces[0:4]:
230             self.vapi.sw_interface_set_l2_bridge(
231                 rx_sw_if_index=i.sw_if_index, bd_id=1, shg=0
232             )
233
234         #
235         # an unknown unicast and broadcast packets
236         #
237         p_uu = (
238             Ether(dst="00:00:00:c1:5c:00", src="00:00:de:ad:be:ef")
239             / IP(src="10.10.10.10", dst="1.1.1.1")
240             / UDP(sport=1234, dport=1234)
241             / Raw(b"\xa5" * 100)
242         )
243         p_bm = (
244             Ether(dst="ff:ff:ff:ff:ff:ff", src="00:00:de:ad:be:ef")
245             / IP(src="10.10.10.10", dst="1.1.1.1")
246             / UDP(sport=1234, dport=1234)
247             / Raw(b"\xa5" * 100)
248         )
249
250         #
251         # input on pg0, expected copies on pg1->4
252         #
253         self.pg0.add_stream(p_uu * NUM_PKTS)
254         self.pg_enable_capture(self.pg_interfaces)
255         self.pg_start()
256
257         for i in self.pg_interfaces[1:4]:
258             rx0 = i.get_capture(NUM_PKTS, timeout=1)
259
260         self.pg0.add_stream(p_bm * NUM_PKTS)
261         self.pg_enable_capture(self.pg_interfaces)
262         self.pg_start()
263
264         for i in self.pg_interfaces[1:4]:
265             rx0 = i.get_capture(NUM_PKTS, timeout=1)
266
267         #
268         # use pg8 as the uu-fwd interface
269         #
270         self.vapi.sw_interface_set_l2_bridge(
271             rx_sw_if_index=self.pg8.sw_if_index,
272             bd_id=1,
273             shg=0,
274             port_type=L2_PORT_TYPE.UU_FWD,
275         )
276
277         #
278         # expect the UU packet on the uu-fwd interface and not be flooded
279         #
280         self.pg0.add_stream(p_uu * NUM_PKTS)
281         self.pg_enable_capture(self.pg_interfaces)
282         self.pg_start()
283
284         rx0 = self.pg8.get_capture(NUM_PKTS, timeout=1)
285
286         for i in self.pg_interfaces[0:4]:
287             i.assert_nothing_captured(remark="UU not flooded")
288
289         self.pg0.add_stream(p_bm * NUM_PKTS)
290         self.pg_enable_capture(self.pg_interfaces)
291         self.pg_start()
292
293         for i in self.pg_interfaces[1:4]:
294             rx0 = i.get_capture(NUM_PKTS, timeout=1)
295
296         #
297         # remove the uu-fwd interface and expect UU to be flooded again
298         #
299         self.vapi.sw_interface_set_l2_bridge(
300             rx_sw_if_index=self.pg8.sw_if_index,
301             bd_id=1,
302             shg=0,
303             port_type=L2_PORT_TYPE.UU_FWD,
304             enable=0,
305         )
306
307         self.pg0.add_stream(p_uu * NUM_PKTS)
308         self.pg_enable_capture(self.pg_interfaces)
309         self.pg_start()
310
311         for i in self.pg_interfaces[1:4]:
312             rx0 = i.get_capture(NUM_PKTS, timeout=1)
313
314         #
315         # change the BD config to not support UU-flood
316         #
317         self.vapi.bridge_flags(bd_id=1, is_set=0, flags=BRIDGE_FLAGS.UU_FLOOD)
318
319         self.send_and_assert_no_replies(self.pg0, p_uu)
320
321         #
322         # re-add the uu-fwd interface
323         #
324         self.vapi.sw_interface_set_l2_bridge(
325             rx_sw_if_index=self.pg8.sw_if_index,
326             bd_id=1,
327             shg=0,
328             port_type=L2_PORT_TYPE.UU_FWD,
329         )
330         self.logger.info(self.vapi.cli("sh bridge 1 detail"))
331
332         self.pg0.add_stream(p_uu * NUM_PKTS)
333         self.pg_enable_capture(self.pg_interfaces)
334         self.pg_start()
335
336         rx0 = self.pg8.get_capture(NUM_PKTS, timeout=1)
337
338         for i in self.pg_interfaces[0:4]:
339             i.assert_nothing_captured(remark="UU not flooded")
340
341         #
342         # remove the uu-fwd interface
343         #
344         self.vapi.sw_interface_set_l2_bridge(
345             rx_sw_if_index=self.pg8.sw_if_index,
346             bd_id=1,
347             shg=0,
348             port_type=L2_PORT_TYPE.UU_FWD,
349             enable=0,
350         )
351         self.send_and_assert_no_replies(self.pg0, p_uu)
352
353         #
354         # cleanup
355         #
356         for i in self.pg_interfaces[:4]:
357             self.vapi.sw_interface_set_l2_bridge(
358                 rx_sw_if_index=i.sw_if_index, bd_id=1, enable=0
359             )
360
361         self.vapi.bridge_domain_add_del_v2(bd_id=1, is_add=0)
362
363
364 if __name__ == "__main__":
365     unittest.main(testRunner=VppTestRunner)