df3d9dbfda829b9d0f81eef276a632b56ce4b797
[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
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_vxlan(self, pkt):
106         """
107         Decapsulate the original payload frame by removing VXLAN 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         return pkt[VXLAN].payload
116
117     def create_stream(self, src_if, packet_sizes, do_dot1=False, bcast=False):
118         pkts = []
119         dst_if = self.flows[src_if][0]
120         dst_mac = src_if.remote_mac
121         if bcast:
122             dst_mac = "ff:ff:ff:ff:ff:ff"
123
124         for i in range(0, self.pkts_per_burst):
125             payload = "span test"
126             size = packet_sizes[(i / 2) % len(packet_sizes)]
127             p = (Ether(src=src_if.local_mac, dst=dst_mac) /
128                  IP(src=src_if.remote_ip4, dst=dst_if.remote_ip4) /
129                  UDP(sport=10000 + src_if.sw_if_index * 1000 + i, dport=1234) /
130                  Raw(payload))
131             if do_dot1:
132                 p = self.sub_if.add_dot1_layer(p)
133             self.extend_packet(p, size)
134             pkts.append(p)
135         return pkts
136
137     def verify_capture(self, cap1, cap2):
138         self.assertEqual(len(cap1), len(cap2),
139                          "Different number of sent and mirrored packets :"
140                          "%u != %u" % (len(cap1), len(cap2)))
141
142         pkts1 = [(pkt[Ether] / pkt[IP] / pkt[UDP]) for pkt in cap1]
143         pkts2 = [(pkt[Ether] / pkt[IP] / pkt[UDP]) for pkt in cap2]
144
145         self.assertEqual(pkts1.sort(), pkts2.sort())
146
147     def test_device_span(self):
148         """ SPAN device rx mirror """
149
150         # Create bi-directional cross-connects between pg0 and pg1
151         self.xconnect(self.pg0.sw_if_index, self.pg1.sw_if_index)
152         # Create incoming packet streams for packet-generator interfaces
153         pkts = self.create_stream(self.pg0, self.pg_if_packet_sizes)
154         self.pg0.add_stream(pkts)
155
156         # Enable SPAN on pg0 (mirrored to pg2)
157         self.vapi.sw_interface_span_enable_disable(
158             self.pg0.sw_if_index, self.pg2.sw_if_index)
159
160         self.logger.info(self.vapi.ppcli("show interface span"))
161         # Enable packet capturing and start packet sending
162         self.pg_enable_capture(self.pg_interfaces)
163         self.pg_start()
164
165         # Verify packets outgoing packet streams on mirrored interface (pg2)
166         n_pkts = len(pkts)
167         pg1_pkts = self.pg1.get_capture(n_pkts)
168         pg2_pkts = self.pg2.get_capture(n_pkts)
169
170         # Disable SPAN on pg0 (mirrored to pg2)
171         self.vapi.sw_interface_span_enable_disable(
172             self.pg0.sw_if_index, self.pg2.sw_if_index, state=0)
173         self.xconnect(self.pg0.sw_if_index, self.pg1.sw_if_index, is_add=0)
174
175         self.verify_capture(pg1_pkts, pg2_pkts)
176
177     def test_span_l2_rx(self):
178         """ SPAN l2 rx mirror """
179
180         self.sub_if.admin_up()
181
182         self.bridge(self.pg2.sw_if_index)
183         # Create bi-directional cross-connects between pg0 subif and pg1
184         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index)
185         # Create incoming packet streams for packet-generator interfaces
186         pkts = self.create_stream(
187             self.pg0, self.pg_if_packet_sizes, do_dot1=True)
188         self.pg0.add_stream(pkts)
189
190         # Enable SPAN on pg0 (mirrored to pg2)
191         self.vapi.sw_interface_span_enable_disable(
192             self.sub_if.sw_if_index, self.pg2.sw_if_index, is_l2=1)
193
194         self.logger.info(self.vapi.ppcli("show interface span"))
195         # Enable packet capturing and start packet sending
196         self.pg_enable_capture(self.pg_interfaces)
197         self.pg_start()
198
199         # Verify packets outgoing packet streams on mirrored interface (pg2)
200         pg2_expected = len(pkts)
201         pg1_pkts = self.pg1.get_capture(pg2_expected)
202         pg2_pkts = self.pg2.get_capture(pg2_expected)
203         self.bridge(self.pg2.sw_if_index, is_add=0)
204
205         # Disable SPAN on pg0 (mirrored to pg2)
206         self.vapi.sw_interface_span_enable_disable(
207             self.sub_if.sw_if_index, self.pg2.sw_if_index, state=0, is_l2=1)
208         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
209
210         self.verify_capture(pg1_pkts, pg2_pkts)
211
212     def test_span_l2_rx_dst_vxlan(self):
213         """ SPAN l2 rx mirror into vxlan """
214
215         self.sub_if.admin_up()
216         self.vapi.sw_interface_set_flags(self.vxlan.sw_if_index,
217                                          admin_up_down=1)
218
219         self.bridge(self.vxlan.sw_if_index, is_add=1)
220         # Create bi-directional cross-connects between pg0 subif and pg1
221         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index)
222         # Create incoming packet streams for packet-generator interfaces
223         pkts = self.create_stream(
224             self.pg0, self.pg_if_packet_sizes, do_dot1=True)
225         self.pg0.add_stream(pkts)
226
227         # Enable SPAN on pg0 sub if (mirrored to vxlan)
228         self.vapi.sw_interface_span_enable_disable(
229             self.sub_if.sw_if_index, self.vxlan.sw_if_index, is_l2=1)
230
231         self.logger.info(self.vapi.ppcli("show interface span"))
232         # Enable packet capturing and start packet sending
233         self.pg_enable_capture(self.pg_interfaces)
234         self.pg_start()
235
236         # Verify packets outgoing packet streams on mirrored interface (pg2)
237         n_pkts = len(pkts)
238         pg1_pkts = self.pg1.get_capture(n_pkts)
239         pg2_pkts = [self.decap_vxlan(p) for p in self.pg2.get_capture(n_pkts)]
240
241         self.bridge(self.vxlan.sw_if_index, is_add=0)
242         # Disable SPAN on pg0 sub if (mirrored to vxlan)
243         self.vapi.sw_interface_span_enable_disable(
244             self.sub_if.sw_if_index, self.vxlan.sw_if_index, state=0, is_l2=1)
245         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
246         self.verify_capture(pg1_pkts, pg2_pkts)
247
248     def test_span_l2_rx_dst_gre_subif_vtr(self):
249         """ SPAN l2 rx mirror into gre-subif+vtr """
250
251         self.sub_if.admin_up()
252
253         gre_if = VppGreInterface(self, self.pg2.local_ip4,
254                                  self.pg2.remote_ip4,
255                                  is_teb=1)
256
257         gre_if.add_vpp_config()
258         gre_if.admin_up()
259
260         gre_sub_if = VppDot1QSubint(self, gre_if, 500)
261         gre_sub_if.set_vtr(L2_VTR_OP.L2_POP_1, tag=500)
262         gre_sub_if.admin_up()
263
264         self.bridge(gre_sub_if.sw_if_index)
265         # Create bi-directional cross-connects between pg0 and pg1
266         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=1)
267
268         # Create incoming packet streams for packet-generator interfaces
269         pkts = self.create_stream(
270             self.pg0, self.pg_if_packet_sizes, do_dot1=True)
271         self.pg0.add_stream(pkts)
272
273         self.vapi.sw_interface_span_enable_disable(
274             self.sub_if.sw_if_index, gre_sub_if.sw_if_index, is_l2=1)
275
276         # Enable packet capturing and start packet sending
277         self.pg_enable_capture(self.pg_interfaces)
278         self.pg_start()
279
280         # Verify packets outgoing packet streams on mirrored interface (pg2)
281         n_pkts = len(pkts)
282         pg1_pkts = self.pg1.get_capture(n_pkts)
283         pg2_pkts = self.pg2.get_capture(n_pkts)
284
285         def decap(p): return self.remove_tags(
286             self.decap_gre(p), [Tag(dot1=DOT1Q, vlan=500)])
287         pg2_decaped = [decap(p) for p in pg2_pkts]
288
289         self.bridge(gre_sub_if.sw_if_index, is_add=0)
290
291         # Disable SPAN on pg0 sub if
292         self.vapi.sw_interface_span_enable_disable(
293             self.sub_if.sw_if_index, gre_sub_if.sw_if_index, state=0, is_l2=1)
294         gre_if.remove_vpp_config()
295         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
296
297         self.verify_capture(pg1_pkts, pg2_decaped)
298
299     def test_span_l2_rx_dst_1q_vtr(self):
300         """ SPAN l2 rx mirror into 1q subif+vtr """
301
302         self.sub_if.admin_up()
303         self.vlan_sub_if.admin_up()
304
305         self.bridge(self.vlan_sub_if.sw_if_index)
306         # Create bi-directional cross-connects between pg0 and pg1
307         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=1)
308
309         # Create incoming packet streams for packet-generator interfaces
310         pkts = self.create_stream(
311             self.pg0, self.pg_if_packet_sizes, do_dot1=True)
312         self.pg0.add_stream(pkts)
313
314         self.vapi.sw_interface_span_enable_disable(
315             self.sub_if.sw_if_index, self.vlan_sub_if.sw_if_index, is_l2=1)
316
317         # Enable packet capturing and start packet sending
318         self.pg_enable_capture(self.pg_interfaces)
319         self.pg_start()
320
321         # Verify packets outgoing packet streams on mirrored interface (pg2)
322         n_pkts = len(pkts)
323         pg1_pkts = self.pg1.get_capture(n_pkts)
324         pg2_pkts = self.pg2.get_capture(n_pkts)
325         pg2_untagged = [self.remove_tags(p, [Tag(dot1=DOT1Q, vlan=300)])
326                         for p in pg2_pkts]
327
328         self.bridge(self.vlan_sub_if.sw_if_index, is_add=0)
329         # Disable SPAN on pg0 sub if (mirrored to vxlan)
330         self.vapi.sw_interface_span_enable_disable(
331             self.sub_if.sw_if_index, self.vlan_sub_if.sw_if_index, state=0,
332             is_l2=1)
333         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
334
335         self.verify_capture(pg1_pkts, pg2_untagged)
336
337     def test_span_l2_rx_dst_1ad_vtr(self):
338         """ SPAN l2 rx mirror into 1ad subif+vtr """
339
340         self.sub_if.admin_up()
341         self.qinq_sub_if.admin_up()
342
343         self.bridge(self.qinq_sub_if.sw_if_index)
344         # Create bi-directional cross-connects between pg0 and pg1
345         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=1)
346
347         # Create incoming packet streams for packet-generator interfaces
348         pkts = self.create_stream(
349             self.pg0, self.pg_if_packet_sizes, do_dot1=True)
350         self.pg0.add_stream(pkts)
351
352         self.vapi.sw_interface_span_enable_disable(
353             self.sub_if.sw_if_index, self.qinq_sub_if.sw_if_index, is_l2=1)
354
355         # Enable packet capturing and start packet sending
356         self.pg_enable_capture(self.pg_interfaces)
357         self.pg_start()
358
359         # Verify packets outgoing packet streams on mirrored interface (pg2)
360         n_pkts = len(pkts)
361         pg1_pkts = self.pg1.get_capture(n_pkts)
362         pg2_pkts = self.pg2.get_capture(n_pkts)
363         pg2_untagged = [self.remove_tags(p, [Tag(dot1=DOT1AD, vlan=400),
364                                              Tag(dot1=DOT1Q, vlan=500)])
365                         for p in pg2_pkts]
366
367         self.bridge(self.qinq_sub_if.sw_if_index, is_add=0)
368         # Disable SPAN on pg0 sub if (mirrored to vxlan)
369         self.vapi.sw_interface_span_enable_disable(
370             self.sub_if.sw_if_index, self.qinq_sub_if.sw_if_index, state=0,
371             is_l2=1)
372         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
373
374         self.verify_capture(pg1_pkts, pg2_untagged)
375
376     def test_l2_tx_span(self):
377         """ SPAN l2 tx mirror """
378
379         self.sub_if.admin_up()
380         self.bridge(self.pg2.sw_if_index)
381         # Create bi-directional cross-connects between pg0 and pg1
382         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index)
383         # Create incoming packet streams for packet-generator interfaces
384         pkts = self.create_stream(
385             self.pg0, self.pg_if_packet_sizes, do_dot1=True)
386         self.pg0.add_stream(pkts)
387
388         # Enable SPAN on pg1 (mirrored to pg2)
389         self.vapi.sw_interface_span_enable_disable(
390             self.pg1.sw_if_index, self.pg2.sw_if_index, is_l2=1, state=2)
391
392         self.logger.info(self.vapi.ppcli("show interface span"))
393         # Enable packet capturing and start packet sending
394         self.pg_enable_capture(self.pg_interfaces)
395         self.pg_start()
396
397         # Verify packets outgoing packet streams on mirrored interface (pg2)
398         n_pkts = len(pkts)
399         pg1_pkts = self.pg1.get_capture(n_pkts)
400         pg2_pkts = self.pg2.get_capture(n_pkts)
401         self.bridge(self.pg2.sw_if_index, is_add=0)
402         # Disable SPAN on pg0 (mirrored to pg2)
403         self.vapi.sw_interface_span_enable_disable(
404             self.pg1.sw_if_index, self.pg2.sw_if_index, state=0, 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_pkts)
408
409     def test_l2_rx_tx_span(self):
410         """ SPAN l2 rx tx mirror """
411
412         self.sub_if.admin_up()
413         self.bridge(self.pg2.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)
416
417         # Create incoming packet streams for packet-generator interfaces
418         pg0_pkts = self.create_stream(
419             self.pg0, self.pg_if_packet_sizes, do_dot1=True)
420         self.pg0.add_stream(pg0_pkts)
421         pg1_pkts = self.create_stream(
422             self.pg1, self.pg_if_packet_sizes, do_dot1=False)
423         self.pg1.add_stream(pg1_pkts)
424
425         # Enable SPAN on pg0 (mirrored to pg2)
426         self.vapi.sw_interface_span_enable_disable(
427             self.sub_if.sw_if_index, self.pg2.sw_if_index, is_l2=1, state=3)
428         self.logger.info(self.vapi.ppcli("show interface span"))
429
430         # Enable packet capturing and start packet sending
431         self.pg_enable_capture(self.pg_interfaces)
432         self.pg_start()
433
434         # Verify packets outgoing packet streams on mirrored interface (pg2)
435         pg0_expected = len(pg1_pkts)
436         pg1_expected = len(pg0_pkts)
437         pg2_expected = pg0_expected + pg1_expected
438
439         pg0_pkts = self.pg0.get_capture(pg0_expected)
440         pg1_pkts = self.pg1.get_capture(pg1_expected)
441         pg2_pkts = self.pg2.get_capture(pg2_expected)
442
443         self.bridge(self.pg2.sw_if_index, is_add=0)
444         # Disable SPAN on pg0 (mirrored to pg2)
445         self.vapi.sw_interface_span_enable_disable(
446             self.sub_if.sw_if_index, self.pg2.sw_if_index, state=0, is_l2=1)
447         self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
448
449         self.verify_capture(pg0_pkts + pg1_pkts, pg2_pkts)
450
451     def test_l2_bcast_mirror(self):
452         """ SPAN l2 broadcast mirror """
453
454         self.sub_if.admin_up()
455         self.bridge(self.pg2.sw_if_index)
456
457         # Create bi-directional cross-connects between pg0 and pg1
458         self.vapi.sw_interface_set_l2_bridge(
459             self.sub_if.sw_if_index, bd_id=99, enable=1)
460         self.vapi.sw_interface_set_l2_bridge(
461             self.pg1.sw_if_index, bd_id=99, enable=1)
462
463         # Create incoming packet streams for packet-generator interfaces
464         pg0_pkts = self.create_stream(
465             self.pg0, self.pg_if_packet_sizes, do_dot1=True, bcast=True)
466         self.pg0.add_stream(pg0_pkts)
467         pg1_pkts = self.create_stream(
468             self.pg1, self.pg_if_packet_sizes, do_dot1=False, bcast=True)
469         self.pg1.add_stream(pg1_pkts)
470
471         # Enable SPAN on pg0 (mirrored to pg2)
472         self.vapi.sw_interface_span_enable_disable(
473             self.sub_if.sw_if_index, self.pg2.sw_if_index, is_l2=1, state=3)
474         self.logger.info(self.vapi.ppcli("show interface span"))
475
476         # Enable packet capturing and start packet sending
477         self.pg_enable_capture(self.pg_interfaces)
478         self.pg_start()
479
480         # Verify packets outgoing packet streams on mirrored interface (pg2)
481         pg0_expected = len(pg1_pkts)
482         pg1_expected = len(pg0_pkts)
483         pg2_expected = pg0_expected + pg1_expected
484
485         pg0_pkts = self.pg0.get_capture(pg0_expected)
486         pg1_pkts = self.pg1.get_capture(pg1_expected)
487         pg2_pkts = self.pg2.get_capture(pg2_expected)
488
489         self.bridge(self.pg2.sw_if_index, is_add=0)
490         self.vapi.sw_interface_set_l2_bridge(
491             self.sub_if.sw_if_index, bd_id=99, enable=0)
492         self.vapi.sw_interface_set_l2_bridge(
493             self.pg1.sw_if_index, bd_id=99, enable=0)
494         # Disable SPAN on pg0 (mirrored to pg2)
495         self.vapi.sw_interface_span_enable_disable(
496             self.sub_if.sw_if_index, self.pg2.sw_if_index, state=0, is_l2=1)
497
498         self.verify_capture(pg0_pkts + pg1_pkts, pg2_pkts)
499
500
501 if __name__ == '__main__':
502     unittest.main(testRunner=VppTestRunner)