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
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
17 Tag = namedtuple('Tag', ['dot1', 'vlan'])
22 class TestSpan(VppTestCase):
23 """ SPAN Test Case """
27 super(TestSpan, cls).setUpClass()
29 cls.pkts_per_burst = 257 # Number of packets per burst
30 # create 3 pg interfaces
31 cls.create_pg_interfaces(range(3))
34 cls.sub_if = VppDot1QSubint(cls, cls.pg0, 100)
35 cls.dst_sub_if = VppDot1QSubint(cls, cls.pg2, 300)
36 cls.dst_sub_if.set_vtr(L2_VTR_OP.L2_POP_1, tag=300)
37 # packet flows mapping pg0 -> pg1, pg2 -> pg3, etc.
39 cls.flows[cls.pg0] = [cls.pg1]
40 cls.flows[cls.pg1] = [cls.pg0]
43 cls.pg_if_packet_sizes = [64, 512] # , 1518, 9018]
45 cls.interfaces = list(cls.pg_interfaces)
47 # setup all interfaces
48 for i in cls.interfaces:
53 cls.vxlan = cls.vapi.vxlan_add_del_tunnel(
54 src_addr=cls.pg2.local_ip4n,
55 dst_addr=cls.pg2.remote_ip4n,
60 super(TestSpan, self).setUp()
61 self.reset_packet_infos()
64 super(TestSpan, self).tearDown()
66 self.logger.info(self.vapi.ppcli("show interface span"))
68 def xconnect(self, a, b, is_add=1):
69 self.vapi.sw_interface_set_l2_xconnect(a, b, enable=is_add)
70 self.vapi.sw_interface_set_l2_xconnect(b, a, enable=is_add)
72 def bridge(self, sw_if_index, is_add=1):
73 self.vapi.sw_interface_set_l2_bridge(
74 sw_if_index, bd_id=self.bd_id, enable=is_add)
76 def _remove_tag(self, packet, vlan, tag_type):
77 self.assertEqual(packet.type, tag_type)
78 payload = packet.payload
79 self.assertEqual(payload.vlan, vlan)
80 inner_type = payload.type
81 payload = payload.payload
82 packet.remove_payload()
83 packet.add_payload(payload)
84 packet.type = inner_type
86 def remove_tags(self, packet, tags):
88 self._remove_tag(packet, t.vlan, t.dot1)
91 def decap_gre(self, pkt):
93 Decapsulate the original payload frame by removing GRE header
95 self.assertEqual(pkt[Ether].src, self.pg2.local_mac)
96 self.assertEqual(pkt[Ether].dst, self.pg2.remote_mac)
98 self.assertEqual(pkt[IP].src, self.pg2.local_ip4)
99 self.assertEqual(pkt[IP].dst, self.pg2.remote_ip4)
101 return pkt[GRE].payload
103 def decap_vxlan(self, pkt):
105 Decapsulate the original payload frame by removing VXLAN header
107 self.assertEqual(pkt[Ether].src, self.pg2.local_mac)
108 self.assertEqual(pkt[Ether].dst, self.pg2.remote_mac)
110 self.assertEqual(pkt[IP].src, self.pg2.local_ip4)
111 self.assertEqual(pkt[IP].dst, self.pg2.remote_ip4)
113 return pkt[VXLAN].payload
115 def create_stream(self, src_if, packet_sizes, do_dot1=False):
117 dst_if = self.flows[src_if][0]
118 for i in range(0, self.pkts_per_burst):
119 pkt_info = self.create_packet_info(src_if, dst_if)
120 payload = self.info_to_payload(pkt_info)
121 size = packet_sizes[(i / 2) % len(packet_sizes)]
122 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
123 IP(src=src_if.remote_ip4, dst=dst_if.remote_ip4) /
124 UDP(sport=10000 + src_if.sw_if_index * 1000 + i, dport=1234) /
127 p = self.sub_if.add_dot1_layer(p)
128 pkt_info.data = p.copy()
129 self.extend_packet(p, size)
133 def verify_capture(self, cap1, cap2):
134 self.assertEqual(len(cap1), len(cap2),
135 "Different number of sent and mirrored packets :"
136 "%u != %u" % (len(cap1), len(cap2)))
138 pkts1 = [(pkt[Ether] / pkt[IP] / pkt[UDP]) for pkt in cap1]
139 pkts2 = [(pkt[Ether] / pkt[IP] / pkt[UDP]) for pkt in cap2]
141 self.assertEqual(pkts1.sort(), pkts2.sort())
143 def test_device_span(self):
144 """ SPAN device rx mirror test
148 3 interfaces, pg0 l2xconnected with pg1
149 2. sending l2 eth packets between 2 interfaces (pg0, pg1) and
151 64B, 512B, 1518B, 9018B (ether_size)
152 burst of packets per interface
155 # Create bi-directional cross-connects between pg0 and pg1
156 self.xconnect(self.pg0.sw_if_index, self.pg1.sw_if_index)
157 # Create incoming packet streams for packet-generator interfaces
158 pkts = self.create_stream(self.pg0, self.pg_if_packet_sizes)
159 self.pg0.add_stream(pkts)
161 # Enable SPAN on pg0 (mirrored to pg2)
162 self.vapi.sw_interface_span_enable_disable(
163 self.pg0.sw_if_index, self.pg2.sw_if_index)
165 self.logger.info(self.vapi.ppcli("show interface span"))
166 # Enable packet capturing and start packet sending
167 self.pg_enable_capture(self.pg_interfaces)
170 # Verify packets outgoing packet streams on mirrored interface (pg2)
171 self.logger.info("Verifying capture on interfaces %s and %s" %
172 (self.pg1.name, self.pg2.name))
174 n_pkts = self.get_packet_count_for_if_idx(self.pg1.sw_if_index)
175 pg1_pkts = self.pg1.get_capture(n_pkts)
176 pg2_pkts = self.pg2.get_capture(n_pkts)
178 # Disable SPAN on pg0 (mirrored to pg2)
179 self.vapi.sw_interface_span_enable_disable(
180 self.pg0.sw_if_index, self.pg2.sw_if_index, state=0)
181 self.xconnect(self.pg0.sw_if_index, self.pg1.sw_if_index, is_add=0)
183 self.verify_capture(pg1_pkts, pg2_pkts)
185 def test_span_l2_rx(self):
186 """ SPAN l2 rx mirror test """
188 self.sub_if.admin_up()
190 self.bridge(self.pg2.sw_if_index)
191 # Create bi-directional cross-connects between pg0 and pg1
192 self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index)
193 # Create incoming packet streams for packet-generator interfaces
194 pkts = self.create_stream(
195 self.pg0, self.pg_if_packet_sizes, do_dot1=True)
196 self.pg0.add_stream(pkts)
198 # Enable SPAN on pg0 (mirrored to pg2)
199 self.vapi.sw_interface_span_enable_disable(
200 self.sub_if.sw_if_index, self.pg2.sw_if_index, is_l2=1)
202 self.logger.info(self.vapi.ppcli("show interface span"))
203 # Enable packet capturing and start packet sending
204 self.pg_enable_capture(self.pg_interfaces)
207 # Verify packets outgoing packet streams on mirrored interface (pg2)
208 self.logger.info("Verifying capture on interfaces %s and %s" %
209 (self.pg1.name, self.pg2.name))
210 pg2_expected = len(pkts)
211 pg1_pkts = self.pg1.get_capture(pg2_expected)
212 pg2_pkts = self.pg2.get_capture(pg2_expected)
213 self.bridge(self.pg2.sw_if_index, is_add=0)
215 # Disable SPAN on pg0 (mirrored to pg2)
216 self.vapi.sw_interface_span_enable_disable(
217 self.sub_if.sw_if_index, self.pg2.sw_if_index, state=0, is_l2=1)
218 self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
220 self.verify_capture(pg1_pkts, pg2_pkts)
222 def test_span_l2_rx_dst_vxlan(self):
223 """ SPAN l2 rx mirror into vxlan test """
225 self.sub_if.admin_up()
226 self.vapi.sw_interface_set_flags(self.vxlan.sw_if_index,
229 self.bridge(self.vxlan.sw_if_index, is_add=1)
230 # Create bi-directional cross-connects between pg0 and pg1
231 self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index)
232 # Create incoming packet streams for packet-generator interfaces
233 pkts = self.create_stream(
234 self.pg0, self.pg_if_packet_sizes, do_dot1=True)
235 self.pg0.add_stream(pkts)
237 # Enable SPAN on pg0 sub if (mirrored to vxlan)
238 self.vapi.sw_interface_span_enable_disable(
239 self.sub_if.sw_if_index, self.vxlan.sw_if_index, is_l2=1)
241 self.logger.info(self.vapi.ppcli("show interface span"))
242 # Enable packet capturing and start packet sending
243 self.pg_enable_capture(self.pg_interfaces)
246 # Verify packets outgoing packet streams on mirrored interface (pg2)
247 self.logger.info("Verifying capture on interfaces %s and %s" %
248 (self.pg1.name, self.pg2.name))
249 pg2_expected = self.get_packet_count_for_if_idx(self.pg1.sw_if_index)
250 pg1_pkts = self.pg1.get_capture()
251 pg2_pkts = [self.decap_vxlan(p)
252 for p in self.pg2.get_capture(pg2_expected)]
254 self.bridge(self.vxlan.sw_if_index, is_add=0)
255 # Disable SPAN on pg0 sub if (mirrored to vxlan)
256 self.vapi.sw_interface_span_enable_disable(
257 self.sub_if.sw_if_index, self.vxlan.sw_if_index, state=0, is_l2=1)
258 self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
259 self.verify_capture(pg1_pkts, pg2_pkts)
261 def test_span_l2_rx_dst_gre_subif_vtr(self):
262 """ SPAN l2 rx mirror into gre-subif+vtr """
264 self.sub_if.admin_up()
266 gre_if = VppGreInterface(self, self.pg2.local_ip4,
270 gre_if.add_vpp_config()
273 gre_sub_if = VppDot1QSubint(self, gre_if, 500)
274 gre_sub_if.set_vtr(L2_VTR_OP.L2_POP_1, tag=500)
275 gre_sub_if.admin_up()
277 self.bridge(gre_sub_if.sw_if_index)
278 # Create bi-directional cross-connects between pg0 and pg1
279 self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=1)
281 # Create incoming packet streams for packet-generator interfaces
282 pkts = self.create_stream(
283 self.pg0, self.pg_if_packet_sizes, do_dot1=True)
284 self.pg0.add_stream(pkts)
286 self.vapi.sw_interface_span_enable_disable(
287 self.sub_if.sw_if_index, gre_sub_if.sw_if_index, is_l2=1)
289 # Enable packet capturing and start packet sending
290 self.pg_enable_capture(self.pg_interfaces)
293 # Verify packets outgoing packet streams on mirrored interface (pg2)
294 self.logger.info("Verifying capture on interfaces %s and %s" %
295 (self.pg1.name, self.pg2.name))
296 pg2_expected = self.get_packet_count_for_if_idx(self.pg1.sw_if_index)
297 pg1_pkts = self.pg1.get_capture()
298 pg2_pkts = self.pg2.get_capture(pg2_expected)
299 pg2_decaped = [self.remove_tags(self.decap_gre(
300 p), [Tag(dot1=DOT1Q, vlan=500)]) for p in pg2_pkts]
301 self.bridge(gre_sub_if.sw_if_index, is_add=0)
303 # Disable SPAN on pg0 sub if
304 self.vapi.sw_interface_span_enable_disable(
305 self.sub_if.sw_if_index, gre_sub_if.sw_if_index, state=0, is_l2=1)
306 gre_if.remove_vpp_config()
307 self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
309 self.verify_capture(pg1_pkts, pg2_decaped)
311 def test_span_l2_rx_dst_vtr(self):
312 """ SPAN l2 rx mirror into subif+vtr """
314 self.sub_if.admin_up()
315 self.dst_sub_if.admin_up()
317 self.bridge(self.dst_sub_if.sw_if_index)
318 # Create bi-directional cross-connects between pg0 and pg1
319 self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=1)
321 # Create incoming packet streams for packet-generator interfaces
322 pkts = self.create_stream(
323 self.pg0, self.pg_if_packet_sizes, do_dot1=True)
324 self.pg0.add_stream(pkts)
326 self.vapi.sw_interface_span_enable_disable(
327 self.sub_if.sw_if_index, self.dst_sub_if.sw_if_index, is_l2=1)
329 # Enable packet capturing and start packet sending
330 self.pg_enable_capture(self.pg_interfaces)
333 # Verify packets outgoing packet streams on mirrored interface (pg2)
334 self.logger.info("Verifying capture on interfaces %s and %s" %
335 (self.pg1.name, self.pg2.name))
336 pg2_expected = self.get_packet_count_for_if_idx(self.pg1.sw_if_index)
337 pg1_pkts = self.pg1.get_capture()
338 pg2_pkts = self.pg2.get_capture(pg2_expected)
339 pg2_untagged = [self.remove_tags(p, [Tag(dot1=DOT1Q, vlan=300)])
342 self.bridge(self.dst_sub_if.sw_if_index, is_add=0)
343 # Disable SPAN on pg0 sub if (mirrored to vxlan)
344 self.vapi.sw_interface_span_enable_disable(
345 self.sub_if.sw_if_index, self.dst_sub_if.sw_if_index, state=0,
347 self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
349 self.verify_capture(pg1_pkts, pg2_untagged)
351 def test_l2_tx_span(self):
352 """ SPAN l2 tx mirror test """
354 self.sub_if.admin_up()
355 self.bridge(self.pg2.sw_if_index)
356 # Create bi-directional cross-connects between pg0 and pg1
357 self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index)
358 # Create incoming packet streams for packet-generator interfaces
359 pkts = self.create_stream(
360 self.pg0, self.pg_if_packet_sizes, do_dot1=True)
361 self.pg0.add_stream(pkts)
363 # Enable SPAN on pg1 (mirrored to pg2)
364 self.vapi.sw_interface_span_enable_disable(
365 self.pg1.sw_if_index, self.pg2.sw_if_index, is_l2=1, state=2)
367 self.logger.info(self.vapi.ppcli("show interface span"))
368 # Enable packet capturing and start packet sending
369 self.pg_enable_capture(self.pg_interfaces)
372 # Verify packets outgoing packet streams on mirrored interface (pg2)
373 self.logger.info("Verifying capture on interfaces %s and %s" %
374 (self.pg1.name, self.pg2.name))
375 pg2_expected = self.get_packet_count_for_if_idx(self.pg1.sw_if_index)
376 pg1_pkts = self.pg1.get_capture()
377 pg2_pkts = self.pg2.get_capture(pg2_expected)
378 self.bridge(self.pg2.sw_if_index, is_add=0)
379 # Disable SPAN on pg0 (mirrored to pg2)
380 self.vapi.sw_interface_span_enable_disable(
381 self.pg1.sw_if_index, self.pg2.sw_if_index, state=0, is_l2=1)
382 self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
384 self.verify_capture(pg1_pkts, pg2_pkts)
386 def test_l2_rx_tx_span(self):
387 """ SPAN l2 rx tx mirror test """
389 self.sub_if.admin_up()
390 self.bridge(self.pg2.sw_if_index)
391 # Create bi-directional cross-connects between pg0 and pg1
392 self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index)
394 # Create incoming packet streams for packet-generator interfaces
395 pg0_pkts = self.create_stream(
396 self.pg0, self.pg_if_packet_sizes, do_dot1=True)
397 self.pg0.add_stream(pg0_pkts)
398 pg1_pkts = self.create_stream(
399 self.pg1, self.pg_if_packet_sizes, do_dot1=False)
400 self.pg1.add_stream(pg1_pkts)
402 # Enable SPAN on pg0 (mirrored to pg2)
403 self.vapi.sw_interface_span_enable_disable(
404 self.sub_if.sw_if_index, self.pg2.sw_if_index, is_l2=1, state=3)
405 self.logger.info(self.vapi.ppcli("show interface span"))
407 # Enable packet capturing and start packet sending
408 self.pg_enable_capture(self.pg_interfaces)
411 # Verify packets outgoing packet streams on mirrored interface (pg2)
412 self.logger.info("Verifying capture on interfaces %s and %s" %
413 (self.pg1.name, self.pg2.name))
414 pg0_expected = self.get_packet_count_for_if_idx(self.pg0.sw_if_index)
415 pg1_expected = self.get_packet_count_for_if_idx(self.pg1.sw_if_index)
416 pg2_expected = pg0_expected + pg1_expected
418 pg0_pkts = self.pg0.get_capture(pg0_expected)
419 pg1_pkts = self.pg1.get_capture(pg1_expected)
420 pg2_pkts = self.pg2.get_capture(pg2_expected)
422 self.bridge(self.pg2.sw_if_index, is_add=0)
423 # Disable SPAN on pg0 (mirrored to pg2)
424 self.vapi.sw_interface_span_enable_disable(
425 self.sub_if.sw_if_index, self.pg2.sw_if_index, state=0, is_l2=1)
426 self.xconnect(self.sub_if.sw_if_index, self.pg1.sw_if_index, is_add=0)
428 self.verify_capture(pg0_pkts + pg1_pkts, pg2_pkts)
431 if __name__ == '__main__':
432 unittest.main(testRunner=VppTestRunner)