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