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.inet6 import IPv6
9 from scapy.volatile import RandMAC, RandIP
11 from framework import VppTestCase, VppTestRunner
12 from vpp_sub_interface import VppDot1QSubint
13 from vpp_gre_interface import VppGreInterface, VppGre6Interface
14 from vpp_ip import DpoProto
15 from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable
16 from vpp_papi_provider import L2_VTR_OP
17 from util import ppp, ppc
26 class TestGRE(VppTestCase):
31 super(TestGRE, cls).setUpClass()
34 super(TestGRE, self).setUp()
36 # create 3 pg interfaces - set one in a non-default table.
37 self.create_pg_interfaces(range(3))
39 self.tbl = VppIpTable(self, 1)
40 self.tbl.add_vpp_config()
41 self.pg1.set_table_ip4(1)
43 for i in self.pg_interfaces:
47 self.pg0.resolve_arp()
49 self.pg1.resolve_arp()
51 self.pg2.resolve_ndp()
54 for i in self.pg_interfaces:
58 self.pg1.set_table_ip4(0)
59 super(TestGRE, self).tearDown()
61 def create_stream_ip4(self, src_if, src_ip, dst_ip):
63 for i in range(0, 257):
64 info = self.create_packet_info(src_if, src_if)
65 payload = self.info_to_payload(info)
66 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
67 IP(src=src_ip, dst=dst_ip) /
68 UDP(sport=1234, dport=1234) /
74 def create_stream_ip6(self, src_if, src_ip, dst_ip):
76 for i in range(0, 257):
77 info = self.create_packet_info(src_if, src_if)
78 payload = self.info_to_payload(info)
79 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
80 IPv6(src=src_ip, dst=dst_ip) /
81 UDP(sport=1234, dport=1234) /
87 def create_tunnel_stream_4o4(self, src_if,
88 tunnel_src, tunnel_dst,
91 for i in range(0, 257):
92 info = self.create_packet_info(src_if, src_if)
93 payload = self.info_to_payload(info)
94 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
95 IP(src=tunnel_src, dst=tunnel_dst) /
97 IP(src=src_ip, dst=dst_ip) /
98 UDP(sport=1234, dport=1234) /
104 def create_tunnel_stream_6o4(self, src_if,
105 tunnel_src, tunnel_dst,
108 for i in range(0, 257):
109 info = self.create_packet_info(src_if, src_if)
110 payload = self.info_to_payload(info)
111 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
112 IP(src=tunnel_src, dst=tunnel_dst) /
114 IPv6(src=src_ip, dst=dst_ip) /
115 UDP(sport=1234, dport=1234) /
121 def create_tunnel_stream_6o6(self, src_if,
122 tunnel_src, tunnel_dst,
125 for i in range(0, 257):
126 info = self.create_packet_info(src_if, src_if)
127 payload = self.info_to_payload(info)
128 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
129 IPv6(src=tunnel_src, dst=tunnel_dst) /
131 IPv6(src=src_ip, dst=dst_ip) /
132 UDP(sport=1234, dport=1234) /
138 def create_tunnel_stream_l2o4(self, src_if,
139 tunnel_src, tunnel_dst):
141 for i in range(0, 257):
142 info = self.create_packet_info(src_if, src_if)
143 payload = self.info_to_payload(info)
144 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
145 IP(src=tunnel_src, dst=tunnel_dst) /
147 Ether(dst=RandMAC('*:*:*:*:*:*'),
148 src=RandMAC('*:*:*:*:*:*')) /
149 IP(src=str(RandIP()), dst=str(RandIP())) /
150 UDP(sport=1234, dport=1234) /
156 def create_tunnel_stream_vlano4(self, src_if,
157 tunnel_src, tunnel_dst, vlan):
159 for i in range(0, 257):
160 info = self.create_packet_info(src_if, src_if)
161 payload = self.info_to_payload(info)
162 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
163 IP(src=tunnel_src, dst=tunnel_dst) /
165 Ether(dst=RandMAC('*:*:*:*:*:*'),
166 src=RandMAC('*:*:*:*:*:*')) /
168 IP(src=str(RandIP()), dst=str(RandIP())) /
169 UDP(sport=1234, dport=1234) /
175 def verify_tunneled_4o4(self, src_if, capture, sent,
176 tunnel_src, tunnel_dst):
178 self.assertEqual(len(capture), len(sent))
180 for i in range(len(capture)):
188 self.assertEqual(rx_ip.src, tunnel_src)
189 self.assertEqual(rx_ip.dst, tunnel_dst)
194 self.assertEqual(rx_ip.src, tx_ip.src)
195 self.assertEqual(rx_ip.dst, tx_ip.dst)
196 # IP processing post pop has decremented the TTL
197 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
200 self.logger.error(ppp("Rx:", rx))
201 self.logger.error(ppp("Tx:", tx))
204 def verify_tunneled_6o6(self, src_if, capture, sent,
205 tunnel_src, tunnel_dst):
207 self.assertEqual(len(capture), len(sent))
209 for i in range(len(capture)):
217 self.assertEqual(rx_ip.src, tunnel_src)
218 self.assertEqual(rx_ip.dst, tunnel_dst)
220 rx_gre = GRE(str(rx_ip[IPv6].payload))
223 self.assertEqual(rx_ip.src, tx_ip.src)
224 self.assertEqual(rx_ip.dst, tx_ip.dst)
227 self.logger.error(ppp("Rx:", rx))
228 self.logger.error(ppp("Tx:", tx))
231 def verify_tunneled_4o6(self, src_if, capture, sent,
232 tunnel_src, tunnel_dst):
234 self.assertEqual(len(capture), len(sent))
236 for i in range(len(capture)):
243 self.assertEqual(rx_ip.src, tunnel_src)
244 self.assertEqual(rx_ip.dst, tunnel_dst)
246 rx_gre = GRE(str(rx_ip[IPv6].payload))
250 self.assertEqual(rx_ip.src, tx_ip.src)
251 self.assertEqual(rx_ip.dst, tx_ip.dst)
254 self.logger.error(ppp("Rx:", rx))
255 self.logger.error(ppp("Tx:", tx))
258 def verify_tunneled_6o4(self, src_if, capture, sent,
259 tunnel_src, tunnel_dst):
261 self.assertEqual(len(capture), len(sent))
263 for i in range(len(capture)):
270 self.assertEqual(rx_ip.src, tunnel_src)
271 self.assertEqual(rx_ip.dst, tunnel_dst)
273 rx_gre = GRE(str(rx_ip[IP].payload))
277 self.assertEqual(rx_ip.src, tx_ip.src)
278 self.assertEqual(rx_ip.dst, tx_ip.dst)
281 self.logger.error(ppp("Rx:", rx))
282 self.logger.error(ppp("Tx:", tx))
285 def verify_tunneled_l2o4(self, src_if, capture, sent,
286 tunnel_src, tunnel_dst):
287 self.assertEqual(len(capture), len(sent))
289 for i in range(len(capture)):
297 self.assertEqual(rx_ip.src, tunnel_src)
298 self.assertEqual(rx_ip.dst, tunnel_dst)
301 rx_l2 = rx_gre[Ether]
304 tx_l2 = tx_gre[Ether]
307 self.assertEqual(rx_ip.src, tx_ip.src)
308 self.assertEqual(rx_ip.dst, tx_ip.dst)
309 # bridged, not L3 forwarded, so no TTL decrement
310 self.assertEqual(rx_ip.ttl, tx_ip.ttl)
313 self.logger.error(ppp("Rx:", rx))
314 self.logger.error(ppp("Tx:", tx))
317 def verify_tunneled_vlano4(self, src_if, capture, sent,
318 tunnel_src, tunnel_dst, vlan):
320 self.assertEqual(len(capture), len(sent))
322 ppc("Unexpected packets captured:", capture)
325 for i in range(len(capture)):
333 self.assertEqual(rx_ip.src, tunnel_src)
334 self.assertEqual(rx_ip.dst, tunnel_dst)
337 rx_l2 = rx_gre[Ether]
338 rx_vlan = rx_l2[Dot1Q]
341 self.assertEqual(rx_vlan.vlan, vlan)
344 tx_l2 = tx_gre[Ether]
347 self.assertEqual(rx_ip.src, tx_ip.src)
348 self.assertEqual(rx_ip.dst, tx_ip.dst)
349 # bridged, not L3 forwarded, so no TTL decrement
350 self.assertEqual(rx_ip.ttl, tx_ip.ttl)
353 self.logger.error(ppp("Rx:", rx))
354 self.logger.error(ppp("Tx:", tx))
357 def verify_decapped_4o4(self, src_if, capture, sent):
358 self.assertEqual(len(capture), len(sent))
360 for i in range(len(capture)):
370 self.assertEqual(rx_ip.src, tx_ip.src)
371 self.assertEqual(rx_ip.dst, tx_ip.dst)
372 # IP processing post pop has decremented the TTL
373 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
376 self.logger.error(ppp("Rx:", rx))
377 self.logger.error(ppp("Tx:", tx))
380 def verify_decapped_6o4(self, src_if, capture, sent):
381 self.assertEqual(len(capture), len(sent))
383 for i in range(len(capture)):
393 self.assertEqual(rx_ip.src, tx_ip.src)
394 self.assertEqual(rx_ip.dst, tx_ip.dst)
395 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
398 self.logger.error(ppp("Rx:", rx))
399 self.logger.error(ppp("Tx:", tx))
403 """ GRE IPv4 tunnel Tests """
406 # Create an L3 GRE tunnel.
408 # - assign an IP Addres
409 # - Add a route via the tunnel
411 gre_if = VppGreInterface(self,
414 gre_if.add_vpp_config()
417 # The double create (create the same tunnel twice) should fail,
418 # and we should still be able to use the original
421 gre_if.add_vpp_config()
425 self.fail("Double GRE tunnel add does not fail")
430 route_via_tun = VppIpRoute(self, "4.4.4.4", 32,
431 [VppRoutePath("0.0.0.0",
432 gre_if.sw_if_index)])
434 route_via_tun.add_vpp_config()
437 # Send a packet stream that is routed into the tunnel
438 # - they are all dropped since the tunnel's desintation IP
439 # is unresolved - or resolves via the default route - which
442 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
444 self.send_and_assert_no_replies(self.pg0, tx)
447 # Add a route that resolves the tunnel's destination
449 route_tun_dst = VppIpRoute(self, "1.1.1.2", 32,
450 [VppRoutePath(self.pg0.remote_ip4,
451 self.pg0.sw_if_index)])
452 route_tun_dst.add_vpp_config()
455 # Send a packet stream that is routed into the tunnel
456 # - packets are GRE encapped
458 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
459 rx = self.send_and_expect(self.pg0, tx, self.pg0)
460 self.verify_tunneled_4o4(self.pg0, rx, tx,
461 self.pg0.local_ip4, "1.1.1.2")
464 # Send tunneled packets that match the created tunnel and
465 # are decapped and forwarded
467 tx = self.create_tunnel_stream_4o4(self.pg0,
472 rx = self.send_and_expect(self.pg0, tx, self.pg0)
473 self.verify_decapped_4o4(self.pg0, rx, tx)
476 # Send tunneled packets that do not match the tunnel's src
478 self.vapi.cli("clear trace")
479 tx = self.create_tunnel_stream_4o4(self.pg0,
484 self.send_and_assert_no_replies(
486 remark="GRE packets forwarded despite no SRC address match")
489 # Configure IPv6 on the PG interface so we can route IPv6
492 self.pg0.config_ip6()
493 self.pg0.resolve_ndp()
496 # Send IPv6 tunnel encapslated packets
497 # - dropped since IPv6 is not enabled on the tunnel
499 tx = self.create_tunnel_stream_6o4(self.pg0,
504 self.send_and_assert_no_replies(self.pg0, tx,
505 "IPv6 GRE packets forwarded "
506 "despite IPv6 not enabled on tunnel")
509 # Enable IPv6 on the tunnel
514 # Send IPv6 tunnel encapslated packets
515 # - forwarded since IPv6 is enabled on the tunnel
517 tx = self.create_tunnel_stream_6o4(self.pg0,
522 rx = self.send_and_expect(self.pg0, tx, self.pg0)
523 self.verify_decapped_6o4(self.pg0, rx, tx)
526 # Send v6 packets for v4 encap
528 route6_via_tun = VppIpRoute(
529 self, "2001::1", 128,
532 proto=DpoProto.DPO_PROTO_IP6)],
534 route6_via_tun.add_vpp_config()
536 tx = self.create_stream_ip6(self.pg0, "2001::2", "2001::1")
537 rx = self.send_and_expect(self.pg0, tx, self.pg0)
539 self.verify_tunneled_6o4(self.pg0, rx, tx,
540 self.pg0.local_ip4, "1.1.1.2")
545 route_tun_dst.remove_vpp_config()
546 route_via_tun.remove_vpp_config()
547 route6_via_tun.remove_vpp_config()
548 gre_if.remove_vpp_config()
550 self.pg0.unconfig_ip6()
553 """ GRE IPv6 tunnel Tests """
555 self.pg1.config_ip6()
556 self.pg1.resolve_ndp()
559 # Create an L3 GRE tunnel.
561 # - assign an IP Address
562 # - Add a route via the tunnel
564 gre_if = VppGre6Interface(self,
567 gre_if.add_vpp_config()
571 route_via_tun = VppIpRoute(
572 self, "4004::1", 128,
573 [VppRoutePath("0::0",
575 proto=DpoProto.DPO_PROTO_IP6)],
578 route_via_tun.add_vpp_config()
581 # Send a packet stream that is routed into the tunnel
582 # - they are all dropped since the tunnel's desintation IP
583 # is unresolved - or resolves via the default route - which
586 tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
587 self.send_and_assert_no_replies(
589 "GRE packets forwarded without DIP resolved")
592 # Add a route that resolves the tunnel's destination
594 route_tun_dst = VppIpRoute(
595 self, "1002::1", 128,
596 [VppRoutePath(self.pg2.remote_ip6,
597 self.pg2.sw_if_index,
598 proto=DpoProto.DPO_PROTO_IP6)],
600 route_tun_dst.add_vpp_config()
603 # Send a packet stream that is routed into the tunnel
604 # - packets are GRE encapped
606 tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
607 rx = self.send_and_expect(self.pg2, tx, self.pg2)
608 self.verify_tunneled_6o6(self.pg2, rx, tx,
609 self.pg2.local_ip6, "1002::1")
612 # Test decap. decapped packets go out pg1
614 tx = self.create_tunnel_stream_6o6(self.pg2,
619 rx = self.send_and_expect(self.pg2, tx, self.pg1)
622 # RX'd packet is UDP over IPv6, test the GRE header is gone.
624 self.assertFalse(rx[0].haslayer(GRE))
625 self.assertEqual(rx[0][IPv6].dst, self.pg1.remote_ip6)
630 route4_via_tun = VppIpRoute(self, "1.1.1.1", 32,
631 [VppRoutePath("0.0.0.0",
632 gre_if.sw_if_index)])
633 route4_via_tun.add_vpp_config()
635 tx = self.create_stream_ip4(self.pg0, "1.1.1.2", "1.1.1.1")
636 rx = self.send_and_expect(self.pg0, tx, self.pg2)
638 self.verify_tunneled_4o6(self.pg0, rx, tx,
639 self.pg2.local_ip6, "1002::1")
644 route_tun_dst.remove_vpp_config()
645 route_via_tun.remove_vpp_config()
646 route4_via_tun.remove_vpp_config()
647 gre_if.remove_vpp_config()
649 self.pg2.unconfig_ip6()
650 self.pg1.unconfig_ip6()
652 def test_gre_vrf(self):
653 """ GRE tunnel VRF Tests """
656 # Create an L3 GRE tunnel whose destination is in the non-default
657 # table. The underlay is thus non-default - the overlay is still
660 # - assign an IP Addres
662 gre_if = VppGreInterface(self, self.pg1.local_ip4,
665 gre_if.add_vpp_config()
670 # Add a route via the tunnel - in the overlay
672 route_via_tun = VppIpRoute(self, "9.9.9.9", 32,
673 [VppRoutePath("0.0.0.0",
674 gre_if.sw_if_index)])
675 route_via_tun.add_vpp_config()
678 # Add a route that resolves the tunnel's destination - in the
681 route_tun_dst = VppIpRoute(self, "2.2.2.2", 32, table_id=1,
682 paths=[VppRoutePath(self.pg1.remote_ip4,
683 self.pg1.sw_if_index)])
684 route_tun_dst.add_vpp_config()
687 # Send a packet stream that is routed into the tunnel
688 # packets are sent in on pg0 which is in the default table
689 # - packets are GRE encapped
691 self.vapi.cli("clear trace")
692 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "9.9.9.9")
693 rx = self.send_and_expect(self.pg0, tx, self.pg1)
694 self.verify_tunneled_4o4(self.pg1, rx, tx,
695 self.pg1.local_ip4, "2.2.2.2")
698 # Send tunneled packets that match the created tunnel and
699 # are decapped and forwarded. This tests the decap lookup
700 # does not happen in the encap table
702 self.vapi.cli("clear trace")
703 tx = self.create_tunnel_stream_4o4(self.pg1,
708 rx = self.send_and_expect(self.pg1, tx, self.pg0)
709 self.verify_decapped_4o4(self.pg0, rx, tx)
712 # Send tunneled packets that match the created tunnel
713 # but arrive on an interface that is not in the tunnel's
714 # encap VRF, these are dropped.
715 # IP enable the interface so they aren't dropped due to
716 # IP not being enabled.
718 self.pg2.config_ip4()
719 self.vapi.cli("clear trace")
720 tx = self.create_tunnel_stream_4o4(self.pg2,
725 rx = self.send_and_assert_no_replies(
727 "GRE decap packets in wrong VRF")
729 self.pg2.unconfig_ip4()
734 route_tun_dst.remove_vpp_config()
735 route_via_tun.remove_vpp_config()
736 gre_if.remove_vpp_config()
738 def test_gre_l2(self):
739 """ GRE tunnel L2 Tests """
742 # Add routes to resolve the tunnel destinations
744 route_tun1_dst = VppIpRoute(self, "2.2.2.2", 32,
745 [VppRoutePath(self.pg0.remote_ip4,
746 self.pg0.sw_if_index)])
747 route_tun2_dst = VppIpRoute(self, "2.2.2.3", 32,
748 [VppRoutePath(self.pg0.remote_ip4,
749 self.pg0.sw_if_index)])
751 route_tun1_dst.add_vpp_config()
752 route_tun2_dst.add_vpp_config()
755 # Create 2 L2 GRE tunnels and x-connect them
757 gre_if1 = VppGreInterface(self, self.pg0.local_ip4,
759 type=GreTunnelTypes.TT_TEB)
760 gre_if2 = VppGreInterface(self, self.pg0.local_ip4,
762 type=GreTunnelTypes.TT_TEB)
763 gre_if1.add_vpp_config()
764 gre_if2.add_vpp_config()
769 self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
772 self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
777 # Send in tunnel encapped L2. expect out tunnel encapped L2
780 tx = self.create_tunnel_stream_l2o4(self.pg0,
783 rx = self.send_and_expect(self.pg0, tx, self.pg0)
784 self.verify_tunneled_l2o4(self.pg0, rx, tx,
788 tx = self.create_tunnel_stream_l2o4(self.pg0,
791 rx = self.send_and_expect(self.pg0, tx, self.pg0)
792 self.verify_tunneled_l2o4(self.pg0, rx, tx,
796 self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
799 self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
804 # Create a VLAN sub-interfaces on the GRE TEB interfaces
805 # then x-connect them
807 gre_if_11 = VppDot1QSubint(self, gre_if1, 11)
808 gre_if_12 = VppDot1QSubint(self, gre_if2, 12)
810 # gre_if_11.add_vpp_config()
811 # gre_if_12.add_vpp_config()
816 self.vapi.sw_interface_set_l2_xconnect(gre_if_11.sw_if_index,
817 gre_if_12.sw_if_index,
819 self.vapi.sw_interface_set_l2_xconnect(gre_if_12.sw_if_index,
820 gre_if_11.sw_if_index,
824 # Configure both to pop thier respective VLAN tags,
825 # so that during the x-coonect they will subsequently push
827 self.vapi.l2_interface_vlan_tag_rewrite(gre_if_12.sw_if_index,
830 self.vapi.l2_interface_vlan_tag_rewrite(gre_if_11.sw_if_index,
835 # Send traffic in both directiond - expect the VLAN tags to
838 tx = self.create_tunnel_stream_vlano4(self.pg0,
842 rx = self.send_and_expect(self.pg0, tx, self.pg0)
843 self.verify_tunneled_vlano4(self.pg0, rx, tx,
848 tx = self.create_tunnel_stream_vlano4(self.pg0,
852 rx = self.send_and_expect(self.pg0, tx, self.pg0)
853 self.verify_tunneled_vlano4(self.pg0, rx, tx,
859 # Cleanup Test resources
861 gre_if_11.remove_vpp_config()
862 gre_if_12.remove_vpp_config()
863 gre_if1.remove_vpp_config()
864 gre_if2.remove_vpp_config()
865 route_tun1_dst.add_vpp_config()
866 route_tun2_dst.add_vpp_config()
868 def test_gre_loop(self):
869 """ GRE tunnel loop Tests """
872 # Create an L3 GRE tunnel.
874 # - assign an IP Addres
876 gre_if = VppGreInterface(self,
879 gre_if.add_vpp_config()
884 # add a route to the tunnel's destination that points
885 # through the tunnel, hence forming a loop in the forwarding
888 route_dst = VppIpRoute(self, "1.1.1.2", 32,
889 [VppRoutePath("0.0.0.0",
890 gre_if.sw_if_index)])
891 route_dst.add_vpp_config()
894 # packets to the tunnels destination should be dropped
896 tx = self.create_stream_ip4(self.pg0, "1.1.1.1", "1.1.1.2")
897 self.send_and_assert_no_replies(self.pg2, tx)
899 self.logger.info(self.vapi.ppcli("sh adj 7"))
904 route_dst.modify([VppRoutePath(self.pg1.remote_ip4,
905 self.pg1.sw_if_index)])
906 route_dst.add_vpp_config()
908 rx = self.send_and_expect(self.pg0, tx, self.pg1)
911 # a good route throught the tunnel to check it restacked
913 route_via_tun_2 = VppIpRoute(self, "2.2.2.2", 32,
914 [VppRoutePath("0.0.0.0",
915 gre_if.sw_if_index)])
916 route_via_tun_2.add_vpp_config()
918 tx = self.create_stream_ip4(self.pg0, "2.2.2.3", "2.2.2.2")
919 rx = self.send_and_expect(self.pg0, tx, self.pg1)
920 self.verify_tunneled_4o4(self.pg1, rx, tx,
921 self.pg0.local_ip4, "1.1.1.2")
926 route_via_tun_2.remove_vpp_config()
927 gre_if.remove_vpp_config()
930 if __name__ == '__main__':
931 unittest.main(testRunner=VppTestRunner)