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