vxlan: vxlan/vxlan.api API cleanup
[vpp.git] / test / test_span.py
1 #!/usr/bin/env python3
2
3 import unittest
4
5 from scapy.packet import Raw
6 from scapy.layers.l2 import Ether, Dot1Q, GRE, ERSPAN
7 from scapy.layers.inet import IP, UDP
8 from scapy.layers.vxlan import VXLAN
9
10 from framework import VppTestCase, VppTestRunner
11 from util import Host, ppp
12 from vpp_sub_interface import L2_VTR_OP, VppDot1QSubint, VppDot1ADSubint
13 from vpp_gre_interface import VppGreInterface
14 from vpp_vxlan_tunnel import VppVxlanTunnel
15 from collections import namedtuple
16 from vpp_papi import VppEnum
17
18
19 Tag = namedtuple('Tag', ['dot1', 'vlan'])
20 DOT1AD = 0x88A8
21 DOT1Q = 0x8100
22
23
24 class TestSpan(VppTestCase):
25     """ SPAN Test Case """
26
27     @classmethod
28     def setUpClass(cls):
29         super(TestSpan, cls).setUpClass()
30         # Test variables
31         cls.pkts_per_burst = 257    # Number of packets per burst
32         # create 3 pg interfaces
33         cls.create_pg_interfaces(range(3))
34
35         cls.bd_id = 55
36         cls.sub_if = VppDot1QSubint(cls, cls.pg0, 100)
37         cls.vlan_sub_if = VppDot1QSubint(cls, cls.pg2, 300)
38         cls.vlan_sub_if.set_vtr(L2_VTR_OP.L2_POP_1, tag=300)
39
40         cls.qinq_sub_if = VppDot1ADSubint(cls, cls.pg2, 33, 400, 500)
41         cls.qinq_sub_if.set_vtr(L2_VTR_OP.L2_POP_2, outer=500, inner=400)
42
43         # packet flows mapping pg0 -> pg1, pg2 -> pg3, etc.
44         cls.flows = dict()
45         cls.flows[cls.pg0] = [cls.pg1]
46         cls.flows[cls.pg1] = [cls.pg0]
47
48         # packet sizes
49         cls.pg_if_packet_sizes = [64, 512, 1518]  # , 9018]
50
51         # setup all interfaces
52         for i in cls.pg_interfaces:
53             i.admin_up()
54             i.config_ip4()
55             i.resolve_arp()
56
57     def setUp(self):
58         super(TestSpan, self).setUp()
59         self.vxlan = VppVxlanTunnel(self, src=self.pg2.local_ip4,
60                                     dst=self.pg2.remote_ip4, vni=1111)
61         self.vxlan.add_vpp_config()
62         self.reset_packet_infos()
63
64     def tearDown(self):
65         super(TestSpan, self).tearDown()
66
67     def show_commands_at_teardown(self):
68         self.logger.info(self.vapi.ppcli("show interface span"))
69
70     def xconnect(self, a, b, is_add=1):
71         self.vapi.sw_interface_set_l2_xconnect(a, b, enable=is_add)
72         self.vapi.sw_interface_set_l2_xconnect(b, a, enable=is_add)
73
74     def bridge(self, sw_if_index, is_add=1):
75         self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=sw_if_index,
76                                              bd_id=self.bd_id, enable=is_add)
77
78     def _remove_tag(self, packet, vlan, tag_type):
79         self.assertEqual(packet.type, tag_type)
80         payload = packet.payload
81         self.assertEqual(payload.vlan, vlan)
82         inner_type = payload.type
83         payload = payload.payload
84         packet.remove_payload()
85         packet.add_payload(payload)
86         packet.type = inner_type
87
88     def remove_tags(self, packet, tags):
89         for t in tags:
90             self._remove_tag(packet, t.vlan, t.dot1)
91         return packet
92
93     def decap_gre(self, pkt):
94         """
95         Decapsulate the original payload frame by removing GRE header
96         """
97         self.assertEqual(pkt[Ether].src, self.pg2.local_mac)
98         self.assertEqual(pkt[Ether].dst, self.pg2.remote_mac)
99
100         self.assertEqual(pkt[IP].src, self.pg2.local_ip4)
101         self.assertEqual(pkt[IP].dst, self.pg2.remote_ip4)
102
103         return pkt[GRE].payload
104
105     def decap_erspan(self, pkt, session):
106         """
107         Decapsulate the original payload frame by removing ERSPAN header
108         """
109         self.assertEqual(pkt[Ether].src, self.pg2.local_mac)
110         self.assertEqual(pkt[Ether].dst, self.pg2.remote_mac)
111
112         self.assertEqual(pkt[IP].src, self.pg2.local_ip4)
113         self.assertEqual(pkt[IP].dst, self.pg2.remote_ip4)
114
115         self.assertEqual(pkt[ERSPAN].ver, 1)
116         self.assertEqual(pkt[ERSPAN].vlan, 0)
117         self.assertEqual(pkt[ERSPAN].cos, 0)
118         self.assertEqual(pkt[ERSPAN].en, 3)
119         self.assertEqual(pkt[ERSPAN].t, 0)
120         self.assertEqual(pkt[ERSPAN].session_id, session)
121         self.assertEqual(pkt[ERSPAN].reserved, 0)
122         self.assertEqual(pkt[ERSPAN].index, 0)
123
124         return pkt[ERSPAN].payload
125
126     def decap_vxlan(self, pkt):
127         """
128         Decapsulate the original payload frame by removing VXLAN header
129         """
130         self.assertEqual(pkt[Ether].src, self.pg2.local_mac)
131         self.assertEqual(pkt[Ether].dst, self.pg2.remote_mac)
132
133         self.assertEqual(pkt[IP].src, self.pg2.local_ip4)
134         self.assertEqual(pkt[IP].dst, self.pg2.remote_ip4)
135
136         return pkt[VXLAN].payload
137
138     def create_stream(self, src_if, packet_sizes, do_dot1=False, bcast=False):
139         pkts = []
140         dst_if = self.flows[src_if][0]
141         dst_mac = src_if.remote_mac
142         if bcast:
143             dst_mac = "ff:ff:ff:ff:ff:ff"
144
145         for i in range(0, self.pkts_per_burst):
146             payload = "span test"
147             size = packet_sizes[int((i / 2) % len(packet_sizes))]
148             p = (Ether(src=src_if.local_mac, dst=dst_mac) /
149                  IP(src=src_if.remote_ip4, dst=dst_if.remote_ip4) /
150                  UDP(sport=10000 + src_if.sw_if_index * 1000 + i, dport=1234) /
151                  Raw(payload))
152             if do_dot1:
153                 p = self.sub_if.add_dot1_layer(p)
154             self.extend_packet(p, size)
155             pkts.append(p)
156         return pkts
157
158     def verify_capture(self, cap1, cap2):
159         self.assertEqual(len(cap1), len(cap2),
160                          "Different number of sent and mirrored packets :"
161                          "%u != %u" % (len(cap1), len(cap2)))
162
163         pkts1 = [(pkt[Ether] / pkt[IP] / pkt[UDP]) for pkt in cap1]
164         pkts2 = [(pkt[Ether] / pkt[IP] / pkt[UDP]) for pkt in cap2]
165
166         self.assertEqual(pkts1.sort(), pkts2.sort())
167
168     def test_device_span(self):
169         """ SPAN device rx mirror """
170
171         # Create bi-directional cross-connects between pg0 and pg1
172         self.xconnect(self.pg0.sw_if_index, self.pg1.sw_if_index)
173         # Create incoming packet streams for packet-generator interfaces
174         pkts = self.create_stream(self.pg0, self.pg_if_packet_sizes)
175         self.pg0.add_stream(pkts)
176
177         # Enable SPAN on pg0 (mirrored to pg2)
178         self.vapi.sw_interface_span_enable_disable(
179             self.pg0.sw_if_index, self.pg2.sw_if_index)
180
181         self.logger.info(self.vapi.ppcli("show interface span"))
182         # Enable packet capturing and start packet sending
183         self.pg_enable_capture(self.pg_interfaces)
184         self.pg_start()
185
186         # Verify packets outgoing packet streams on mirrored interface (pg2)
187         n_pkts = len(pkts)
188         pg1_pkts = self.pg1.get_capture(n_pkts)
189         pg2_pkts = self.pg2.get_capture(n_pkts)
190
191         # Disable SPAN on pg0 (mirrored to pg2)
192         self.vapi.sw_interface_span_enable_disable(
193             self.pg0.sw_if_index, self.pg2.sw_if_index, state=0)
194         self.xconnect(self.pg0.sw_if_index, self.pg1.sw_if_index, is_add=0)
195
196         self.verify_capture(pg1_pkts, pg2_pkts)
197
198     def test_span_l2_rx(self):
199         """ SPAN l2 rx mirror """
200
201         self.sub_if.admin_up()
202
203         self.bridge(self.pg2.sw_if_index)
204         # Create bi-directional cross-connects between pg0 subif and pg1
205         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index)
206         # Create incoming packet streams for packet-generator interfaces
207         pkts = self.create_stream(
208             self.pg0, self.pg_if_packet_sizes, do_dot1=True)
209         self.pg0.add_stream(pkts)
210
211         # Enable SPAN on pg0 (mirrored to pg2)
212         self.vapi.sw_interface_span_enable_disable(
213             self.sub_if.sw_if_index, self.pg2.sw_if_index, is_l2=1)
214
215         self.logger.info(self.vapi.ppcli("show interface span"))
216         # Enable packet capturing and start packet sending
217         self.pg_enable_capture(self.pg_interfaces)
218         self.pg_start()
219
220         # Verify packets outgoing packet streams on mirrored interface (pg2)
221         pg2_expected = len(pkts)
222         pg1_pkts = self.pg1.get_capture(pg2_expected)
223         pg2_pkts = self.pg2.get_capture(pg2_expected)
224         self.bridge(self.pg2.sw_if_index, is_add=0)
225
226         # Disable SPAN on pg0 (mirrored to pg2)
227         self.vapi.sw_interface_span_enable_disable(
228             self.sub_if.sw_if_index, self.pg2.sw_if_index, state=0, is_l2=1)
229         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
230
231         self.verify_capture(pg1_pkts, pg2_pkts)
232
233     def test_span_l2_rx_dst_vxlan(self):
234         """ SPAN l2 rx mirror into vxlan """
235
236         self.sub_if.admin_up()
237         self.vapi.sw_interface_set_flags(self.vxlan.sw_if_index,
238                                          flags=1)
239
240         self.bridge(self.vxlan.sw_if_index, is_add=1)
241         # Create bi-directional cross-connects between pg0 subif and pg1
242         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index)
243         # Create incoming packet streams for packet-generator interfaces
244         pkts = self.create_stream(
245             self.pg0, self.pg_if_packet_sizes, do_dot1=True)
246         self.pg0.add_stream(pkts)
247
248         # Enable SPAN on pg0 sub if (mirrored to vxlan)
249         self.vapi.sw_interface_span_enable_disable(
250             self.sub_if.sw_if_index, self.vxlan.sw_if_index, is_l2=1)
251
252         self.logger.info(self.vapi.ppcli("show interface span"))
253         # Enable packet capturing and start packet sending
254         self.pg_enable_capture(self.pg_interfaces)
255         self.pg_start()
256
257         # Verify packets outgoing packet streams on mirrored interface (pg2)
258         n_pkts = len(pkts)
259         pg1_pkts = self.pg1.get_capture(n_pkts)
260         pg2_pkts = [self.decap_vxlan(p) for p in self.pg2.get_capture(n_pkts)]
261
262         self.bridge(self.vxlan.sw_if_index, is_add=0)
263         # Disable SPAN on pg0 sub if (mirrored to vxlan)
264         self.vapi.sw_interface_span_enable_disable(
265             self.sub_if.sw_if_index, self.vxlan.sw_if_index, state=0, is_l2=1)
266         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
267         self.verify_capture(pg1_pkts, pg2_pkts)
268
269     def test_span_l2_rx_dst_gre_erspan(self):
270         """ SPAN l2 rx mirror into gre-erspan """
271
272         self.sub_if.admin_up()
273
274         gre_if = VppGreInterface(self, self.pg2.local_ip4,
275                                  self.pg2.remote_ip4,
276                                  session=543,
277                                  type=(VppEnum.vl_api_gre_tunnel_type_t.
278                                        GRE_API_TUNNEL_TYPE_ERSPAN))
279
280         gre_if.add_vpp_config()
281         gre_if.admin_up()
282
283         self.bridge(gre_if.sw_if_index)
284         # Create bi-directional cross-connects between pg0 and pg1
285         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=1)
286
287         # Create incoming packet streams for packet-generator interfaces
288         pkts = self.create_stream(
289             self.pg0, self.pg_if_packet_sizes, do_dot1=True)
290         self.pg0.add_stream(pkts)
291
292         # Enable SPAN on pg0 sub if (mirrored to gre-erspan)
293         self.vapi.sw_interface_span_enable_disable(
294             self.sub_if.sw_if_index, gre_if.sw_if_index, is_l2=1)
295
296         # Enable packet capturing and start packet sending
297         self.pg_enable_capture(self.pg_interfaces)
298         self.pg_start()
299
300         # Verify packets outgoing packet streams on mirrored interface (pg2)
301         n_pkts = len(pkts)
302         pg1_pkts = self.pg1.get_capture(n_pkts)
303         pg2_pkts = self.pg2.get_capture(n_pkts)
304
305         def decap(p): return self.decap_erspan(p, session=543)
306         pg2_decaped = [decap(p) for p in pg2_pkts]
307
308         self.bridge(gre_if.sw_if_index, is_add=0)
309
310         # Disable SPAN on pg0 sub if
311         self.vapi.sw_interface_span_enable_disable(
312             self.sub_if.sw_if_index, gre_if.sw_if_index, state=0, is_l2=1)
313         gre_if.remove_vpp_config()
314         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
315
316         self.verify_capture(pg1_pkts, pg2_decaped)
317
318     def test_span_l2_rx_dst_gre_subif_vtr(self):
319         """ SPAN l2 rx mirror into gre-subif+vtr """
320
321         self.sub_if.admin_up()
322
323         gre_if = VppGreInterface(self, self.pg2.local_ip4,
324                                  self.pg2.remote_ip4,
325                                  type=(VppEnum.vl_api_gre_tunnel_type_t.
326                                        GRE_API_TUNNEL_TYPE_TEB))
327
328         gre_if.add_vpp_config()
329         gre_if.admin_up()
330
331         gre_sub_if = VppDot1QSubint(self, gre_if, 500)
332         gre_sub_if.set_vtr(L2_VTR_OP.L2_POP_1, tag=500)
333         gre_sub_if.admin_up()
334
335         self.bridge(gre_sub_if.sw_if_index)
336         # Create bi-directional cross-connects between pg0 and pg1
337         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=1)
338
339         # Create incoming packet streams for packet-generator interfaces
340         pkts = self.create_stream(
341             self.pg0, self.pg_if_packet_sizes, do_dot1=True)
342         self.pg0.add_stream(pkts)
343
344         # Enable SPAN on pg0 sub if (mirrored to gre sub if)
345         self.vapi.sw_interface_span_enable_disable(
346             self.sub_if.sw_if_index, gre_sub_if.sw_if_index, is_l2=1)
347
348         # Enable packet capturing and start packet sending
349         self.pg_enable_capture(self.pg_interfaces)
350         self.pg_start()
351
352         # Verify packets outgoing packet streams on mirrored interface (pg2)
353         n_pkts = len(pkts)
354         pg1_pkts = self.pg1.get_capture(n_pkts)
355         pg2_pkts = self.pg2.get_capture(n_pkts)
356
357         def decap(p): return self.remove_tags(
358             self.decap_gre(p), [Tag(dot1=DOT1Q, vlan=500)])
359         pg2_decaped = [decap(p) for p in pg2_pkts]
360
361         self.bridge(gre_sub_if.sw_if_index, is_add=0)
362
363         # Disable SPAN on pg0 sub if
364         self.vapi.sw_interface_span_enable_disable(
365             self.sub_if.sw_if_index, gre_sub_if.sw_if_index, state=0, is_l2=1)
366         gre_if.remove_vpp_config()
367         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
368
369         self.verify_capture(pg1_pkts, pg2_decaped)
370
371     def test_span_l2_rx_dst_1q_vtr(self):
372         """ SPAN l2 rx mirror into 1q subif+vtr """
373
374         self.sub_if.admin_up()
375         self.vlan_sub_if.admin_up()
376
377         self.bridge(self.vlan_sub_if.sw_if_index)
378         # Create bi-directional cross-connects between pg0 and pg1
379         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=1)
380
381         # Create incoming packet streams for packet-generator interfaces
382         pkts = self.create_stream(
383             self.pg0, self.pg_if_packet_sizes, do_dot1=True)
384         self.pg0.add_stream(pkts)
385
386         self.vapi.sw_interface_span_enable_disable(
387             self.sub_if.sw_if_index, self.vlan_sub_if.sw_if_index, is_l2=1)
388
389         # Enable packet capturing and start packet sending
390         self.pg_enable_capture(self.pg_interfaces)
391         self.pg_start()
392
393         # Verify packets outgoing packet streams on mirrored interface (pg2)
394         n_pkts = len(pkts)
395         pg1_pkts = self.pg1.get_capture(n_pkts)
396         pg2_pkts = self.pg2.get_capture(n_pkts)
397         pg2_untagged = [self.remove_tags(p, [Tag(dot1=DOT1Q, vlan=300)])
398                         for p in pg2_pkts]
399
400         self.bridge(self.vlan_sub_if.sw_if_index, is_add=0)
401         # Disable SPAN on pg0 sub if (mirrored to vxlan)
402         self.vapi.sw_interface_span_enable_disable(
403             self.sub_if.sw_if_index, self.vlan_sub_if.sw_if_index, state=0,
404             is_l2=1)
405         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
406
407         self.verify_capture(pg1_pkts, pg2_untagged)
408
409     def test_span_l2_rx_dst_1ad_vtr(self):
410         """ SPAN l2 rx mirror into 1ad subif+vtr """
411
412         self.sub_if.admin_up()
413         self.qinq_sub_if.admin_up()
414
415         self.bridge(self.qinq_sub_if.sw_if_index)
416         # Create bi-directional cross-connects between pg0 and pg1
417         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=1)
418
419         # Create incoming packet streams for packet-generator interfaces
420         pkts = self.create_stream(
421             self.pg0, self.pg_if_packet_sizes, do_dot1=True)
422         self.pg0.add_stream(pkts)
423
424         self.vapi.sw_interface_span_enable_disable(
425             self.sub_if.sw_if_index, self.qinq_sub_if.sw_if_index, is_l2=1)
426
427         # Enable packet capturing and start packet sending
428         self.pg_enable_capture(self.pg_interfaces)
429         self.pg_start()
430
431         # Verify packets outgoing packet streams on mirrored interface (pg2)
432         n_pkts = len(pkts)
433         pg1_pkts = self.pg1.get_capture(n_pkts)
434         pg2_pkts = self.pg2.get_capture(n_pkts)
435         pg2_untagged = [self.remove_tags(p, [Tag(dot1=DOT1AD, vlan=400),
436                                              Tag(dot1=DOT1Q, vlan=500)])
437                         for p in pg2_pkts]
438
439         self.bridge(self.qinq_sub_if.sw_if_index, is_add=0)
440         # Disable SPAN on pg0 sub if (mirrored to vxlan)
441         self.vapi.sw_interface_span_enable_disable(
442             self.sub_if.sw_if_index, self.qinq_sub_if.sw_if_index, state=0,
443             is_l2=1)
444         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
445
446         self.verify_capture(pg1_pkts, pg2_untagged)
447
448     def test_l2_tx_span(self):
449         """ SPAN l2 tx mirror """
450
451         self.sub_if.admin_up()
452         self.bridge(self.pg2.sw_if_index)
453         # Create bi-directional cross-connects between pg0 and pg1
454         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index)
455         # Create incoming packet streams for packet-generator interfaces
456         pkts = self.create_stream(
457             self.pg0, self.pg_if_packet_sizes, do_dot1=True)
458         self.pg0.add_stream(pkts)
459
460         # Enable SPAN on pg1 (mirrored to pg2)
461         self.vapi.sw_interface_span_enable_disable(
462             self.pg1.sw_if_index, self.pg2.sw_if_index, is_l2=1, state=2)
463
464         self.logger.info(self.vapi.ppcli("show interface span"))
465         # Enable packet capturing and start packet sending
466         self.pg_enable_capture(self.pg_interfaces)
467         self.pg_start()
468
469         # Verify packets outgoing packet streams on mirrored interface (pg2)
470         n_pkts = len(pkts)
471         pg1_pkts = self.pg1.get_capture(n_pkts)
472         pg2_pkts = self.pg2.get_capture(n_pkts)
473         self.bridge(self.pg2.sw_if_index, is_add=0)
474         # Disable SPAN on pg0 (mirrored to pg2)
475         self.vapi.sw_interface_span_enable_disable(
476             self.pg1.sw_if_index, self.pg2.sw_if_index, state=0, is_l2=1)
477         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
478
479         self.verify_capture(pg1_pkts, pg2_pkts)
480
481     def test_l2_rx_tx_span(self):
482         """ SPAN l2 rx tx mirror """
483
484         self.sub_if.admin_up()
485         self.bridge(self.pg2.sw_if_index)
486         # Create bi-directional cross-connects between pg0 and pg1
487         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index)
488
489         # Create incoming packet streams for packet-generator interfaces
490         pg0_pkts = self.create_stream(
491             self.pg0, self.pg_if_packet_sizes, do_dot1=True)
492         self.pg0.add_stream(pg0_pkts)
493         pg1_pkts = self.create_stream(
494             self.pg1, self.pg_if_packet_sizes, do_dot1=False)
495         self.pg1.add_stream(pg1_pkts)
496
497         # Enable SPAN on pg0 (mirrored to pg2)
498         self.vapi.sw_interface_span_enable_disable(
499             self.sub_if.sw_if_index, self.pg2.sw_if_index, is_l2=1, state=3)
500         self.logger.info(self.vapi.ppcli("show interface span"))
501
502         # Enable packet capturing and start packet sending
503         self.pg_enable_capture(self.pg_interfaces)
504         self.pg_start()
505
506         # Verify packets outgoing packet streams on mirrored interface (pg2)
507         pg0_expected = len(pg1_pkts)
508         pg1_expected = len(pg0_pkts)
509         pg2_expected = pg0_expected + pg1_expected
510
511         pg0_pkts = self.pg0.get_capture(pg0_expected)
512         pg1_pkts = self.pg1.get_capture(pg1_expected)
513         pg2_pkts = self.pg2.get_capture(pg2_expected)
514
515         self.bridge(self.pg2.sw_if_index, is_add=0)
516         # Disable SPAN on pg0 (mirrored to pg2)
517         self.vapi.sw_interface_span_enable_disable(
518             self.sub_if.sw_if_index, self.pg2.sw_if_index, state=0, is_l2=1)
519         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
520
521         self.verify_capture(pg0_pkts + pg1_pkts, pg2_pkts)
522
523     def test_l2_bcast_mirror(self):
524         """ SPAN l2 broadcast mirror """
525
526         self.sub_if.admin_up()
527         self.bridge(self.pg2.sw_if_index)
528
529         # Create bi-directional cross-connects between pg0 and pg1
530         self.vapi.sw_interface_set_l2_bridge(
531             rx_sw_if_index=self.sub_if.sw_if_index, bd_id=99, enable=1)
532         self.vapi.sw_interface_set_l2_bridge(
533             rx_sw_if_index=self.pg1.sw_if_index, bd_id=99, enable=1)
534
535         # Create incoming packet streams for packet-generator interfaces
536         pg0_pkts = self.create_stream(
537             self.pg0, self.pg_if_packet_sizes, do_dot1=True, bcast=True)
538         self.pg0.add_stream(pg0_pkts)
539         pg1_pkts = self.create_stream(
540             self.pg1, self.pg_if_packet_sizes, do_dot1=False, bcast=True)
541         self.pg1.add_stream(pg1_pkts)
542
543         # Enable SPAN on pg0 (mirrored to pg2)
544         self.vapi.sw_interface_span_enable_disable(
545             self.sub_if.sw_if_index, self.pg2.sw_if_index, is_l2=1, state=3)
546         self.logger.info(self.vapi.ppcli("show interface span"))
547
548         # Enable packet capturing and start packet sending
549         self.pg_enable_capture(self.pg_interfaces)
550         self.pg_start()
551
552         # Verify packets outgoing packet streams on mirrored interface (pg2)
553         pg0_expected = len(pg1_pkts)
554         pg1_expected = len(pg0_pkts)
555         pg2_expected = pg0_expected + pg1_expected
556
557         pg0_pkts = self.pg0.get_capture(pg0_expected)
558         pg1_pkts = self.pg1.get_capture(pg1_expected)
559         pg2_pkts = self.pg2.get_capture(pg2_expected)
560
561         self.bridge(self.pg2.sw_if_index, is_add=0)
562         self.vapi.sw_interface_set_l2_bridge(
563             rx_sw_if_index=self.sub_if.sw_if_index, bd_id=99, enable=0)
564         self.vapi.sw_interface_set_l2_bridge(
565             rx_sw_if_index=self.pg1.sw_if_index, bd_id=99, enable=0)
566         # Disable SPAN on pg0 (mirrored to pg2)
567         self.vapi.sw_interface_span_enable_disable(
568             self.sub_if.sw_if_index, self.pg2.sw_if_index, state=0, is_l2=1)
569
570         self.verify_capture(pg0_pkts + pg1_pkts, pg2_pkts)
571
572
573 if __name__ == '__main__':
574     unittest.main(testRunner=VppTestRunner)