6 from framework import VppTestCase, VppTestRunner
7 from vpp_sub_interface import VppDot1QSubint
8 from vpp_gre_interface import VppGreInterface
9 from vpp_ip_route import VppIpRoute, VppRoutePath
10 from vpp_papi_provider import L2_VTR_OP
12 from scapy.packet import Raw
13 from scapy.layers.l2 import Ether, Dot1Q, GRE
14 from scapy.layers.inet import IP, UDP
15 from scapy.layers.inet6 import IPv6
16 from scapy.volatile import RandMAC, RandIP
18 from util import ppp, ppc
21 class TestGRE(VppTestCase):
26 super(TestGRE, cls).setUpClass()
29 super(TestGRE, self).setUp()
31 # create 2 pg interfaces - set one in a non-default table.
32 self.create_pg_interfaces(range(2))
34 self.pg1.set_table_ip4(1)
35 for i in self.pg_interfaces:
41 super(TestGRE, self).tearDown()
43 def create_stream_ip4(self, src_if, src_ip, dst_ip):
45 for i in range(0, 257):
46 info = self.create_packet_info(src_if, src_if)
47 payload = self.info_to_payload(info)
48 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
49 IP(src=src_ip, dst=dst_ip) /
50 UDP(sport=1234, dport=1234) /
56 def create_tunnel_stream_4o4(self, src_if,
57 tunnel_src, tunnel_dst,
60 for i in range(0, 257):
61 info = self.create_packet_info(src_if, src_if)
62 payload = self.info_to_payload(info)
63 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
64 IP(src=tunnel_src, dst=tunnel_dst) /
66 IP(src=src_ip, dst=dst_ip) /
67 UDP(sport=1234, dport=1234) /
73 def create_tunnel_stream_6o4(self, src_if,
74 tunnel_src, tunnel_dst,
77 for i in range(0, 257):
78 info = self.create_packet_info(src_if, src_if)
79 payload = self.info_to_payload(info)
80 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
81 IP(src=tunnel_src, dst=tunnel_dst) /
83 IPv6(src=src_ip, dst=dst_ip) /
84 UDP(sport=1234, dport=1234) /
90 def create_tunnel_stream_l2o4(self, src_if,
91 tunnel_src, tunnel_dst):
93 for i in range(0, 257):
94 info = self.create_packet_info(src_if, src_if)
95 payload = self.info_to_payload(info)
96 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
97 IP(src=tunnel_src, dst=tunnel_dst) /
99 Ether(dst=RandMAC('*:*:*:*:*:*'),
100 src=RandMAC('*:*:*:*:*:*')) /
101 IP(src=str(RandIP()), dst=str(RandIP())) /
102 UDP(sport=1234, dport=1234) /
108 def create_tunnel_stream_vlano4(self, src_if,
109 tunnel_src, tunnel_dst, vlan):
111 for i in range(0, 257):
112 info = self.create_packet_info(src_if, src_if)
113 payload = self.info_to_payload(info)
114 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
115 IP(src=tunnel_src, dst=tunnel_dst) /
117 Ether(dst=RandMAC('*:*:*:*:*:*'),
118 src=RandMAC('*:*:*:*:*:*')) /
120 IP(src=str(RandIP()), dst=str(RandIP())) /
121 UDP(sport=1234, dport=1234) /
127 def verify_tunneled_4o4(self, src_if, capture, sent,
128 tunnel_src, tunnel_dst):
130 self.assertEqual(len(capture), len(sent))
132 for i in range(len(capture)):
140 self.assertEqual(rx_ip.src, tunnel_src)
141 self.assertEqual(rx_ip.dst, tunnel_dst)
146 self.assertEqual(rx_ip.src, tx_ip.src)
147 self.assertEqual(rx_ip.dst, tx_ip.dst)
148 # IP processing post pop has decremented the TTL
149 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
152 self.logger.error(ppp("Rx:", rx))
153 self.logger.error(ppp("Tx:", tx))
156 def verify_tunneled_l2o4(self, src_if, capture, sent,
157 tunnel_src, tunnel_dst):
158 self.assertEqual(len(capture), len(sent))
160 for i in range(len(capture)):
168 self.assertEqual(rx_ip.src, tunnel_src)
169 self.assertEqual(rx_ip.dst, tunnel_dst)
172 rx_l2 = rx_gre[Ether]
175 tx_l2 = tx_gre[Ether]
178 self.assertEqual(rx_ip.src, tx_ip.src)
179 self.assertEqual(rx_ip.dst, tx_ip.dst)
180 # bridged, not L3 forwarded, so no TTL decrement
181 self.assertEqual(rx_ip.ttl, tx_ip.ttl)
184 self.logger.error(ppp("Rx:", rx))
185 self.logger.error(ppp("Tx:", tx))
188 def verify_tunneled_vlano4(self, src_if, capture, sent,
189 tunnel_src, tunnel_dst, vlan):
191 self.assertEqual(len(capture), len(sent))
193 ppc("Unexpected packets captured:", capture)
196 for i in range(len(capture)):
204 self.assertEqual(rx_ip.src, tunnel_src)
205 self.assertEqual(rx_ip.dst, tunnel_dst)
208 rx_l2 = rx_gre[Ether]
209 rx_vlan = rx_l2[Dot1Q]
212 self.assertEqual(rx_vlan.vlan, vlan)
215 tx_l2 = tx_gre[Ether]
218 self.assertEqual(rx_ip.src, tx_ip.src)
219 self.assertEqual(rx_ip.dst, tx_ip.dst)
220 # bridged, not L3 forwarded, so no TTL decrement
221 self.assertEqual(rx_ip.ttl, tx_ip.ttl)
224 self.logger.error(ppp("Rx:", rx))
225 self.logger.error(ppp("Tx:", tx))
228 def verify_decapped_4o4(self, src_if, capture, sent):
229 self.assertEqual(len(capture), len(sent))
231 for i in range(len(capture)):
241 self.assertEqual(rx_ip.src, tx_ip.src)
242 self.assertEqual(rx_ip.dst, tx_ip.dst)
243 # IP processing post pop has decremented the TTL
244 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
247 self.logger.error(ppp("Rx:", rx))
248 self.logger.error(ppp("Tx:", tx))
251 def verify_decapped_6o4(self, src_if, capture, sent):
252 self.assertEqual(len(capture), len(sent))
254 for i in range(len(capture)):
264 self.assertEqual(rx_ip.src, tx_ip.src)
265 self.assertEqual(rx_ip.dst, tx_ip.dst)
266 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
269 self.logger.error(ppp("Rx:", rx))
270 self.logger.error(ppp("Tx:", tx))
274 """ GRE tunnel Tests """
277 # Create an L3 GRE tunnel.
279 # - assign an IP Addres
280 # - Add a route via the tunnel
282 gre_if = VppGreInterface(self,
285 gre_if.add_vpp_config()
288 # The double create (create the same tunnel twice) should fail,
289 # and we should still be able to use the original
292 gre_if.add_vpp_config()
296 self.fail("Double GRE tunnel add does not fail")
301 route_via_tun = VppIpRoute(self, "4.4.4.4", 32,
302 [VppRoutePath("0.0.0.0",
303 gre_if.sw_if_index)])
305 route_via_tun.add_vpp_config()
308 # Send a packet stream that is routed into the tunnel
309 # - they are all dropped since the tunnel's desintation IP
310 # is unresolved - or resolves via the default route - which
313 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
314 self.pg0.add_stream(tx)
316 self.pg_enable_capture(self.pg_interfaces)
319 self.pg0.assert_nothing_captured(
320 remark="GRE packets forwarded without DIP resolved")
323 # Add a route that resolves the tunnel's destination
325 route_tun_dst = VppIpRoute(self, "1.1.1.2", 32,
326 [VppRoutePath(self.pg0.remote_ip4,
327 self.pg0.sw_if_index)])
328 route_tun_dst.add_vpp_config()
331 # Send a packet stream that is routed into the tunnel
332 # - packets are GRE encapped
334 self.vapi.cli("clear trace")
335 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
336 self.pg0.add_stream(tx)
338 self.pg_enable_capture(self.pg_interfaces)
341 rx = self.pg0.get_capture(len(tx))
342 self.verify_tunneled_4o4(self.pg0, rx, tx,
343 self.pg0.local_ip4, "1.1.1.2")
346 # Send tunneled packets that match the created tunnel and
347 # are decapped and forwarded
349 self.vapi.cli("clear trace")
350 tx = self.create_tunnel_stream_4o4(self.pg0,
355 self.pg0.add_stream(tx)
357 self.pg_enable_capture(self.pg_interfaces)
360 rx = self.pg0.get_capture(len(tx))
361 self.verify_decapped_4o4(self.pg0, rx, tx)
364 # Send tunneled packets that do not match the tunnel's src
366 self.vapi.cli("clear trace")
367 tx = self.create_tunnel_stream_4o4(self.pg0,
372 self.pg0.add_stream(tx)
374 self.pg_enable_capture(self.pg_interfaces)
377 self.pg0.assert_nothing_captured(
378 remark="GRE packets forwarded despite no SRC address match")
381 # Configure IPv6 on the PG interface so we can route IPv6
384 self.pg0.config_ip6()
385 self.pg0.resolve_ndp()
388 # Send IPv6 tunnel encapslated packets
389 # - dropped since IPv6 is not enabled on the tunnel
391 self.vapi.cli("clear trace")
392 tx = self.create_tunnel_stream_6o4(self.pg0,
397 self.pg0.add_stream(tx)
399 self.pg_enable_capture(self.pg_interfaces)
402 self.pg0.assert_nothing_captured(remark="IPv6 GRE packets forwarded "
403 "despite IPv6 not enabled on tunnel")
406 # Enable IPv6 on the tunnel
411 # Send IPv6 tunnel encapslated packets
412 # - forwarded since IPv6 is enabled on the tunnel
414 self.vapi.cli("clear trace")
415 tx = self.create_tunnel_stream_6o4(self.pg0,
420 self.pg0.add_stream(tx)
422 self.pg_enable_capture(self.pg_interfaces)
425 rx = self.pg0.get_capture(len(tx))
426 self.verify_decapped_6o4(self.pg0, rx, tx)
431 route_tun_dst.remove_vpp_config()
432 route_via_tun.remove_vpp_config()
433 gre_if.remove_vpp_config()
435 self.pg0.unconfig_ip6()
437 def test_gre_vrf(self):
438 """ GRE tunnel VRF Tests """
441 # Create an L3 GRE tunnel whose destination is in the non-default
442 # table. The underlay is thus non-default - the overlay is still
445 # - assign an IP Addres
447 gre_if = VppGreInterface(self, self.pg1.local_ip4,
450 gre_if.add_vpp_config()
455 # Add a route via the tunnel - in the overlay
457 route_via_tun = VppIpRoute(self, "9.9.9.9", 32,
458 [VppRoutePath("0.0.0.0",
459 gre_if.sw_if_index)])
460 route_via_tun.add_vpp_config()
463 # Add a route that resolves the tunnel's destination - in the
466 route_tun_dst = VppIpRoute(self, "2.2.2.2", 32, table_id=1,
467 paths=[VppRoutePath(self.pg1.remote_ip4,
468 self.pg1.sw_if_index)])
469 route_tun_dst.add_vpp_config()
472 # Send a packet stream that is routed into the tunnel
473 # packets are sent in on pg0 which is in the default table
474 # - packets are GRE encapped
476 self.vapi.cli("clear trace")
477 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "9.9.9.9")
478 self.pg0.add_stream(tx)
480 self.pg_enable_capture(self.pg_interfaces)
483 rx = self.pg1.get_capture(len(tx))
484 self.verify_tunneled_4o4(self.pg1, rx, tx,
485 self.pg1.local_ip4, "2.2.2.2")
488 # Send tunneled packets that match the created tunnel and
489 # are decapped and forwarded. This tests the decap lookup
490 # does not happen in the encap table
492 self.vapi.cli("clear trace")
493 tx = self.create_tunnel_stream_4o4(self.pg1,
498 self.pg1.add_stream(tx)
500 self.pg_enable_capture(self.pg_interfaces)
503 rx = self.pg0.get_capture(len(tx))
504 self.verify_decapped_4o4(self.pg0, rx, tx)
509 route_tun_dst.remove_vpp_config()
510 route_via_tun.remove_vpp_config()
511 gre_if.remove_vpp_config()
513 def test_gre_l2(self):
514 """ GRE tunnel L2 Tests """
517 # Add routes to resolve the tunnel destinations
519 route_tun1_dst = VppIpRoute(self, "2.2.2.2", 32,
520 [VppRoutePath(self.pg0.remote_ip4,
521 self.pg0.sw_if_index)])
522 route_tun2_dst = VppIpRoute(self, "2.2.2.3", 32,
523 [VppRoutePath(self.pg0.remote_ip4,
524 self.pg0.sw_if_index)])
526 route_tun1_dst.add_vpp_config()
527 route_tun2_dst.add_vpp_config()
530 # Create 2 L2 GRE tunnels and x-connect them
532 gre_if1 = VppGreInterface(self, self.pg0.local_ip4,
535 gre_if2 = VppGreInterface(self, self.pg0.local_ip4,
538 gre_if1.add_vpp_config()
539 gre_if2.add_vpp_config()
544 self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
547 self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
552 # Send in tunnel encapped L2. expect out tunnel encapped L2
555 self.vapi.cli("clear trace")
556 tx = self.create_tunnel_stream_l2o4(self.pg0,
559 self.pg0.add_stream(tx)
561 self.pg_enable_capture(self.pg_interfaces)
564 rx = self.pg0.get_capture(len(tx))
565 self.verify_tunneled_l2o4(self.pg0, rx, tx,
569 self.vapi.cli("clear trace")
570 tx = self.create_tunnel_stream_l2o4(self.pg0,
573 self.pg0.add_stream(tx)
575 self.pg_enable_capture(self.pg_interfaces)
578 rx = self.pg0.get_capture(len(tx))
579 self.verify_tunneled_l2o4(self.pg0, rx, tx,
583 self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
586 self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
591 # Create a VLAN sub-interfaces on the GRE TEB interfaces
592 # then x-connect them
594 gre_if_11 = VppDot1QSubint(self, gre_if1, 11)
595 gre_if_12 = VppDot1QSubint(self, gre_if2, 12)
597 # gre_if_11.add_vpp_config()
598 # gre_if_12.add_vpp_config()
603 self.vapi.sw_interface_set_l2_xconnect(gre_if_11.sw_if_index,
604 gre_if_12.sw_if_index,
606 self.vapi.sw_interface_set_l2_xconnect(gre_if_12.sw_if_index,
607 gre_if_11.sw_if_index,
611 # Configure both to pop thier respective VLAN tags,
612 # so that during the x-coonect they will subsequently push
614 self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_12.sw_if_index,
617 self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_11.sw_if_index,
622 # Send traffic in both directiond - expect the VLAN tags to
625 self.vapi.cli("clear trace")
626 tx = self.create_tunnel_stream_vlano4(self.pg0,
630 self.pg0.add_stream(tx)
632 self.pg_enable_capture(self.pg_interfaces)
635 rx = self.pg0.get_capture(len(tx))
636 self.verify_tunneled_vlano4(self.pg0, rx, tx,
641 self.vapi.cli("clear trace")
642 tx = self.create_tunnel_stream_vlano4(self.pg0,
646 self.pg0.add_stream(tx)
648 self.pg_enable_capture(self.pg_interfaces)
651 rx = self.pg0.get_capture(len(tx))
652 self.verify_tunneled_vlano4(self.pg0, rx, tx,
658 # Cleanup Test resources
660 gre_if_11.remove_vpp_config()
661 gre_if_12.remove_vpp_config()
662 gre_if1.remove_vpp_config()
663 gre_if2.remove_vpp_config()
664 route_tun1_dst.add_vpp_config()
665 route_tun2_dst.add_vpp_config()
668 if __name__ == '__main__':
669 unittest.main(testRunner=VppTestRunner)