IGMP: proxy device
[vpp.git] / test / test_span.py
1 #!/usr/bin/env python
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 VppDot1QSubint, VppDot1ADSubint
13 from vpp_gre_interface import VppGreInterface, VppGre6Interface
14 from vpp_papi_provider import L2_VTR_OP
15 from collections import namedtuple
16
17 Tag = namedtuple('Tag', ['dot1', 'vlan'])
18 DOT1AD = 0x88A8
19 DOT1Q = 0x8100
20
21
22 class TestSpan(VppTestCase):
23     """ SPAN Test Case """
24
25     @classmethod
26     def setUpClass(cls):
27         super(TestSpan, cls).setUpClass()
28         # Test variables
29         cls.pkts_per_burst = 257    # Number of packets per burst
30         # create 3 pg interfaces
31         cls.create_pg_interfaces(range(3))
32
33         cls.bd_id = 55
34         cls.sub_if = VppDot1QSubint(cls, cls.pg0, 100)
35         cls.vlan_sub_if = VppDot1QSubint(cls, cls.pg2, 300)
36         cls.vlan_sub_if.set_vtr(L2_VTR_OP.L2_POP_1, tag=300)
37
38         cls.qinq_sub_if = VppDot1ADSubint(cls, cls.pg2, 33, 400, 500)
39         cls.qinq_sub_if.set_vtr(L2_VTR_OP.L2_POP_2, outer=500, inner=400)
40
41         # packet flows mapping pg0 -> pg1, pg2 -> pg3, etc.
42         cls.flows = dict()
43         cls.flows[cls.pg0] = [cls.pg1]
44         cls.flows[cls.pg1] = [cls.pg0]
45
46         # packet sizes
47         cls.pg_if_packet_sizes = [64, 512, 1518]  # , 9018]
48
49         # setup all interfaces
50         for i in cls.pg_interfaces:
51             i.admin_up()
52             i.config_ip4()
53             i.resolve_arp()
54
55         cls.vxlan = cls.vapi.vxlan_add_del_tunnel(
56             src_addr=cls.pg2.local_ip4n,
57             dst_addr=cls.pg2.remote_ip4n,
58             vni=1111,
59             is_add=1)
60
61     def setUp(self):
62         super(TestSpan, self).setUp()
63         self.reset_packet_infos()
64
65     def tearDown(self):
66         super(TestSpan, self).tearDown()
67         if not self.vpp_dead:
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(
76             sw_if_index, 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[(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                                          admin_up_down=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                                  type=2,
277                                  session=543)
278
279         gre_if.add_vpp_config()
280         gre_if.admin_up()
281
282         self.bridge(gre_if.sw_if_index)
283         # Create bi-directional cross-connects between pg0 and pg1
284         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=1)
285
286         # Create incoming packet streams for packet-generator interfaces
287         pkts = self.create_stream(
288             self.pg0, self.pg_if_packet_sizes, do_dot1=True)
289         self.pg0.add_stream(pkts)
290
291         # Enable SPAN on pg0 sub if (mirrored to gre-erspan)
292         self.vapi.sw_interface_span_enable_disable(
293             self.sub_if.sw_if_index, gre_if.sw_if_index, is_l2=1)
294
295         # Enable packet capturing and start packet sending
296         self.pg_enable_capture(self.pg_interfaces)
297         self.pg_start()
298
299         # Verify packets outgoing packet streams on mirrored interface (pg2)
300         n_pkts = len(pkts)
301         pg1_pkts = self.pg1.get_capture(n_pkts)
302         pg2_pkts = self.pg2.get_capture(n_pkts)
303
304         def decap(p): return self.decap_erspan(p, session=543)
305         pg2_decaped = [decap(p) for p in pg2_pkts]
306
307         self.bridge(gre_if.sw_if_index, is_add=0)
308
309         # Disable SPAN on pg0 sub if
310         self.vapi.sw_interface_span_enable_disable(
311             self.sub_if.sw_if_index, gre_if.sw_if_index, state=0, is_l2=1)
312         gre_if.remove_vpp_config()
313         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
314
315         self.verify_capture(pg1_pkts, pg2_decaped)
316
317     def test_span_l2_rx_dst_gre_subif_vtr(self):
318         """ SPAN l2 rx mirror into gre-subif+vtr """
319
320         self.sub_if.admin_up()
321
322         gre_if = VppGreInterface(self, self.pg2.local_ip4,
323                                  self.pg2.remote_ip4,
324                                  type=1)
325
326         gre_if.add_vpp_config()
327         gre_if.admin_up()
328
329         gre_sub_if = VppDot1QSubint(self, gre_if, 500)
330         gre_sub_if.set_vtr(L2_VTR_OP.L2_POP_1, tag=500)
331         gre_sub_if.admin_up()
332
333         self.bridge(gre_sub_if.sw_if_index)
334         # Create bi-directional cross-connects between pg0 and pg1
335         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=1)
336
337         # Create incoming packet streams for packet-generator interfaces
338         pkts = self.create_stream(
339             self.pg0, self.pg_if_packet_sizes, do_dot1=True)
340         self.pg0.add_stream(pkts)
341
342         # Enable SPAN on pg0 sub if (mirrored to gre sub if)
343         self.vapi.sw_interface_span_enable_disable(
344             self.sub_if.sw_if_index, gre_sub_if.sw_if_index, is_l2=1)
345
346         # Enable packet capturing and start packet sending
347         self.pg_enable_capture(self.pg_interfaces)
348         self.pg_start()
349
350         # Verify packets outgoing packet streams on mirrored interface (pg2)
351         n_pkts = len(pkts)
352         pg1_pkts = self.pg1.get_capture(n_pkts)
353         pg2_pkts = self.pg2.get_capture(n_pkts)
354
355         def decap(p): return self.remove_tags(
356             self.decap_gre(p), [Tag(dot1=DOT1Q, vlan=500)])
357         pg2_decaped = [decap(p) for p in pg2_pkts]
358
359         self.bridge(gre_sub_if.sw_if_index, is_add=0)
360
361         # Disable SPAN on pg0 sub if
362         self.vapi.sw_interface_span_enable_disable(
363             self.sub_if.sw_if_index, gre_sub_if.sw_if_index, state=0, is_l2=1)
364         gre_if.remove_vpp_config()
365         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
366
367         self.verify_capture(pg1_pkts, pg2_decaped)
368
369     def test_span_l2_rx_dst_1q_vtr(self):
370         """ SPAN l2 rx mirror into 1q subif+vtr """
371
372         self.sub_if.admin_up()
373         self.vlan_sub_if.admin_up()
374
375         self.bridge(self.vlan_sub_if.sw_if_index)
376         # Create bi-directional cross-connects between pg0 and pg1
377         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=1)
378
379         # Create incoming packet streams for packet-generator interfaces
380         pkts = self.create_stream(
381             self.pg0, self.pg_if_packet_sizes, do_dot1=True)
382         self.pg0.add_stream(pkts)
383
384         self.vapi.sw_interface_span_enable_disable(
385             self.sub_if.sw_if_index, self.vlan_sub_if.sw_if_index, is_l2=1)
386
387         # Enable packet capturing and start packet sending
388         self.pg_enable_capture(self.pg_interfaces)
389         self.pg_start()
390
391         # Verify packets outgoing packet streams on mirrored interface (pg2)
392         n_pkts = len(pkts)
393         pg1_pkts = self.pg1.get_capture(n_pkts)
394         pg2_pkts = self.pg2.get_capture(n_pkts)
395         pg2_untagged = [self.remove_tags(p, [Tag(dot1=DOT1Q, vlan=300)])
396                         for p in pg2_pkts]
397
398         self.bridge(self.vlan_sub_if.sw_if_index, is_add=0)
399         # Disable SPAN on pg0 sub if (mirrored to vxlan)
400         self.vapi.sw_interface_span_enable_disable(
401             self.sub_if.sw_if_index, self.vlan_sub_if.sw_if_index, state=0,
402             is_l2=1)
403         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
404
405         self.verify_capture(pg1_pkts, pg2_untagged)
406
407     def test_span_l2_rx_dst_1ad_vtr(self):
408         """ SPAN l2 rx mirror into 1ad subif+vtr """
409
410         self.sub_if.admin_up()
411         self.qinq_sub_if.admin_up()
412
413         self.bridge(self.qinq_sub_if.sw_if_index)
414         # Create bi-directional cross-connects between pg0 and pg1
415         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=1)
416
417         # Create incoming packet streams for packet-generator interfaces
418         pkts = self.create_stream(
419             self.pg0, self.pg_if_packet_sizes, do_dot1=True)
420         self.pg0.add_stream(pkts)
421
422         self.vapi.sw_interface_span_enable_disable(
423             self.sub_if.sw_if_index, self.qinq_sub_if.sw_if_index, is_l2=1)
424
425         # Enable packet capturing and start packet sending
426         self.pg_enable_capture(self.pg_interfaces)
427         self.pg_start()
428
429         # Verify packets outgoing packet streams on mirrored interface (pg2)
430         n_pkts = len(pkts)
431         pg1_pkts = self.pg1.get_capture(n_pkts)
432         pg2_pkts = self.pg2.get_capture(n_pkts)
433         pg2_untagged = [self.remove_tags(p, [Tag(dot1=DOT1AD, vlan=400),
434                                              Tag(dot1=DOT1Q, vlan=500)])
435                         for p in pg2_pkts]
436
437         self.bridge(self.qinq_sub_if.sw_if_index, is_add=0)
438         # Disable SPAN on pg0 sub if (mirrored to vxlan)
439         self.vapi.sw_interface_span_enable_disable(
440             self.sub_if.sw_if_index, self.qinq_sub_if.sw_if_index, state=0,
441             is_l2=1)
442         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
443
444         self.verify_capture(pg1_pkts, pg2_untagged)
445
446     def test_l2_tx_span(self):
447         """ SPAN l2 tx mirror """
448
449         self.sub_if.admin_up()
450         self.bridge(self.pg2.sw_if_index)
451         # Create bi-directional cross-connects between pg0 and pg1
452         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index)
453         # Create incoming packet streams for packet-generator interfaces
454         pkts = self.create_stream(
455             self.pg0, self.pg_if_packet_sizes, do_dot1=True)
456         self.pg0.add_stream(pkts)
457
458         # Enable SPAN on pg1 (mirrored to pg2)
459         self.vapi.sw_interface_span_enable_disable(
460             self.pg1.sw_if_index, self.pg2.sw_if_index, is_l2=1, state=2)
461
462         self.logger.info(self.vapi.ppcli("show interface span"))
463         # Enable packet capturing and start packet sending
464         self.pg_enable_capture(self.pg_interfaces)
465         self.pg_start()
466
467         # Verify packets outgoing packet streams on mirrored interface (pg2)
468         n_pkts = len(pkts)
469         pg1_pkts = self.pg1.get_capture(n_pkts)
470         pg2_pkts = self.pg2.get_capture(n_pkts)
471         self.bridge(self.pg2.sw_if_index, is_add=0)
472         # Disable SPAN on pg0 (mirrored to pg2)
473         self.vapi.sw_interface_span_enable_disable(
474             self.pg1.sw_if_index, self.pg2.sw_if_index, state=0, is_l2=1)
475         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
476
477         self.verify_capture(pg1_pkts, pg2_pkts)
478
479     def test_l2_rx_tx_span(self):
480         """ SPAN l2 rx tx mirror """
481
482         self.sub_if.admin_up()
483         self.bridge(self.pg2.sw_if_index)
484         # Create bi-directional cross-connects between pg0 and pg1
485         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index)
486
487         # Create incoming packet streams for packet-generator interfaces
488         pg0_pkts = self.create_stream(
489             self.pg0, self.pg_if_packet_sizes, do_dot1=True)
490         self.pg0.add_stream(pg0_pkts)
491         pg1_pkts = self.create_stream(
492             self.pg1, self.pg_if_packet_sizes, do_dot1=False)
493         self.pg1.add_stream(pg1_pkts)
494
495         # Enable SPAN on pg0 (mirrored to pg2)
496         self.vapi.sw_interface_span_enable_disable(
497             self.sub_if.sw_if_index, self.pg2.sw_if_index, is_l2=1, state=3)
498         self.logger.info(self.vapi.ppcli("show interface span"))
499
500         # Enable packet capturing and start packet sending
501         self.pg_enable_capture(self.pg_interfaces)
502         self.pg_start()
503
504         # Verify packets outgoing packet streams on mirrored interface (pg2)
505         pg0_expected = len(pg1_pkts)
506         pg1_expected = len(pg0_pkts)
507         pg2_expected = pg0_expected + pg1_expected
508
509         pg0_pkts = self.pg0.get_capture(pg0_expected)
510         pg1_pkts = self.pg1.get_capture(pg1_expected)
511         pg2_pkts = self.pg2.get_capture(pg2_expected)
512
513         self.bridge(self.pg2.sw_if_index, is_add=0)
514         # Disable SPAN on pg0 (mirrored to pg2)
515         self.vapi.sw_interface_span_enable_disable(
516             self.sub_if.sw_if_index, self.pg2.sw_if_index, state=0, is_l2=1)
517         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
518
519         self.verify_capture(pg0_pkts + pg1_pkts, pg2_pkts)
520
521     def test_l2_bcast_mirror(self):
522         """ SPAN l2 broadcast mirror """
523
524         self.sub_if.admin_up()
525         self.bridge(self.pg2.sw_if_index)
526
527         # Create bi-directional cross-connects between pg0 and pg1
528         self.vapi.sw_interface_set_l2_bridge(
529             self.sub_if.sw_if_index, bd_id=99, enable=1)
530         self.vapi.sw_interface_set_l2_bridge(
531             self.pg1.sw_if_index, bd_id=99, enable=1)
532
533         # Create incoming packet streams for packet-generator interfaces
534         pg0_pkts = self.create_stream(
535             self.pg0, self.pg_if_packet_sizes, do_dot1=True, bcast=True)
536         self.pg0.add_stream(pg0_pkts)
537         pg1_pkts = self.create_stream(
538             self.pg1, self.pg_if_packet_sizes, do_dot1=False, bcast=True)
539         self.pg1.add_stream(pg1_pkts)
540
541         # Enable SPAN on pg0 (mirrored to pg2)
542         self.vapi.sw_interface_span_enable_disable(
543             self.sub_if.sw_if_index, self.pg2.sw_if_index, is_l2=1, state=3)
544         self.logger.info(self.vapi.ppcli("show interface span"))
545
546         # Enable packet capturing and start packet sending
547         self.pg_enable_capture(self.pg_interfaces)
548         self.pg_start()
549
550         # Verify packets outgoing packet streams on mirrored interface (pg2)
551         pg0_expected = len(pg1_pkts)
552         pg1_expected = len(pg0_pkts)
553         pg2_expected = pg0_expected + pg1_expected
554
555         pg0_pkts = self.pg0.get_capture(pg0_expected)
556         pg1_pkts = self.pg1.get_capture(pg1_expected)
557         pg2_pkts = self.pg2.get_capture(pg2_expected)
558
559         self.bridge(self.pg2.sw_if_index, is_add=0)
560         self.vapi.sw_interface_set_l2_bridge(
561             self.sub_if.sw_if_index, bd_id=99, enable=0)
562         self.vapi.sw_interface_set_l2_bridge(
563             self.pg1.sw_if_index, bd_id=99, enable=0)
564         # Disable SPAN on pg0 (mirrored to pg2)
565         self.vapi.sw_interface_span_enable_disable(
566             self.sub_if.sw_if_index, self.pg2.sw_if_index, state=0, is_l2=1)
567
568         self.verify_capture(pg0_pkts + pg1_pkts, pg2_pkts)
569
570
571 if __name__ == '__main__':
572     unittest.main(testRunner=VppTestRunner)