6 from framework import VppTestCase, VppTestRunner
7 from vpp_sub_interface import VppDot1QSubint
8 from vpp_gre_interface import VppGreInterface, VppGre6Interface
9 from vpp_ip import DpoProto
10 from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable
11 from vpp_papi_provider import L2_VTR_OP
13 from scapy.packet import Raw
14 from scapy.layers.l2 import Ether, Dot1Q, GRE
15 from scapy.layers.inet import IP, UDP
16 from scapy.layers.inet6 import IPv6
17 from scapy.volatile import RandMAC, RandIP
19 from util import ppp, ppc
28 class TestGRE(VppTestCase):
33 super(TestGRE, cls).setUpClass()
36 super(TestGRE, self).setUp()
38 # create 3 pg interfaces - set one in a non-default table.
39 self.create_pg_interfaces(range(3))
41 self.tbl = VppIpTable(self, 1)
42 self.tbl.add_vpp_config()
43 self.pg1.set_table_ip4(1)
45 for i in self.pg_interfaces:
49 self.pg0.resolve_arp()
51 self.pg1.resolve_arp()
53 self.pg2.resolve_ndp()
56 for i in self.pg_interfaces:
60 self.pg1.set_table_ip4(0)
61 super(TestGRE, self).tearDown()
63 def create_stream_ip4(self, src_if, src_ip, dst_ip):
65 for i in range(0, 257):
66 info = self.create_packet_info(src_if, src_if)
67 payload = self.info_to_payload(info)
68 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
69 IP(src=src_ip, dst=dst_ip) /
70 UDP(sport=1234, dport=1234) /
76 def create_stream_ip6(self, src_if, src_ip, dst_ip):
78 for i in range(0, 257):
79 info = self.create_packet_info(src_if, src_if)
80 payload = self.info_to_payload(info)
81 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
82 IPv6(src=src_ip, dst=dst_ip) /
83 UDP(sport=1234, dport=1234) /
89 def create_tunnel_stream_4o4(self, src_if,
90 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 IP(src=src_ip, dst=dst_ip) /
100 UDP(sport=1234, dport=1234) /
106 def create_tunnel_stream_6o4(self, src_if,
107 tunnel_src, tunnel_dst,
110 for i in range(0, 257):
111 info = self.create_packet_info(src_if, src_if)
112 payload = self.info_to_payload(info)
113 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
114 IP(src=tunnel_src, dst=tunnel_dst) /
116 IPv6(src=src_ip, dst=dst_ip) /
117 UDP(sport=1234, dport=1234) /
123 def create_tunnel_stream_6o6(self, src_if,
124 tunnel_src, tunnel_dst,
127 for i in range(0, 257):
128 info = self.create_packet_info(src_if, src_if)
129 payload = self.info_to_payload(info)
130 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
131 IPv6(src=tunnel_src, dst=tunnel_dst) /
133 IPv6(src=src_ip, dst=dst_ip) /
134 UDP(sport=1234, dport=1234) /
140 def create_tunnel_stream_l2o4(self, src_if,
141 tunnel_src, tunnel_dst):
143 for i in range(0, 257):
144 info = self.create_packet_info(src_if, src_if)
145 payload = self.info_to_payload(info)
146 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
147 IP(src=tunnel_src, dst=tunnel_dst) /
149 Ether(dst=RandMAC('*:*:*:*:*:*'),
150 src=RandMAC('*:*:*:*:*:*')) /
151 IP(src=str(RandIP()), dst=str(RandIP())) /
152 UDP(sport=1234, dport=1234) /
158 def create_tunnel_stream_vlano4(self, src_if,
159 tunnel_src, tunnel_dst, vlan):
161 for i in range(0, 257):
162 info = self.create_packet_info(src_if, src_if)
163 payload = self.info_to_payload(info)
164 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
165 IP(src=tunnel_src, dst=tunnel_dst) /
167 Ether(dst=RandMAC('*:*:*:*:*:*'),
168 src=RandMAC('*:*:*:*:*:*')) /
170 IP(src=str(RandIP()), dst=str(RandIP())) /
171 UDP(sport=1234, dport=1234) /
177 def verify_tunneled_4o4(self, src_if, capture, sent,
178 tunnel_src, tunnel_dst):
180 self.assertEqual(len(capture), len(sent))
182 for i in range(len(capture)):
190 self.assertEqual(rx_ip.src, tunnel_src)
191 self.assertEqual(rx_ip.dst, tunnel_dst)
196 self.assertEqual(rx_ip.src, tx_ip.src)
197 self.assertEqual(rx_ip.dst, tx_ip.dst)
198 # IP processing post pop has decremented the TTL
199 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
202 self.logger.error(ppp("Rx:", rx))
203 self.logger.error(ppp("Tx:", tx))
206 def verify_tunneled_6o6(self, src_if, capture, sent,
207 tunnel_src, tunnel_dst):
209 self.assertEqual(len(capture), len(sent))
211 for i in range(len(capture)):
219 self.assertEqual(rx_ip.src, tunnel_src)
220 self.assertEqual(rx_ip.dst, tunnel_dst)
222 rx_gre = GRE(str(rx_ip[IPv6].payload))
225 self.assertEqual(rx_ip.src, tx_ip.src)
226 self.assertEqual(rx_ip.dst, tx_ip.dst)
229 self.logger.error(ppp("Rx:", rx))
230 self.logger.error(ppp("Tx:", tx))
233 def verify_tunneled_4o6(self, src_if, capture, sent,
234 tunnel_src, tunnel_dst):
236 self.assertEqual(len(capture), len(sent))
238 for i in range(len(capture)):
245 self.assertEqual(rx_ip.src, tunnel_src)
246 self.assertEqual(rx_ip.dst, tunnel_dst)
248 rx_gre = GRE(str(rx_ip[IPv6].payload))
252 self.assertEqual(rx_ip.src, tx_ip.src)
253 self.assertEqual(rx_ip.dst, tx_ip.dst)
256 self.logger.error(ppp("Rx:", rx))
257 self.logger.error(ppp("Tx:", tx))
260 def verify_tunneled_6o4(self, src_if, capture, sent,
261 tunnel_src, tunnel_dst):
263 self.assertEqual(len(capture), len(sent))
265 for i in range(len(capture)):
272 self.assertEqual(rx_ip.src, tunnel_src)
273 self.assertEqual(rx_ip.dst, tunnel_dst)
275 rx_gre = GRE(str(rx_ip[IP].payload))
279 self.assertEqual(rx_ip.src, tx_ip.src)
280 self.assertEqual(rx_ip.dst, tx_ip.dst)
283 self.logger.error(ppp("Rx:", rx))
284 self.logger.error(ppp("Tx:", tx))
287 def verify_tunneled_l2o4(self, src_if, capture, sent,
288 tunnel_src, tunnel_dst):
289 self.assertEqual(len(capture), len(sent))
291 for i in range(len(capture)):
299 self.assertEqual(rx_ip.src, tunnel_src)
300 self.assertEqual(rx_ip.dst, tunnel_dst)
303 rx_l2 = rx_gre[Ether]
306 tx_l2 = tx_gre[Ether]
309 self.assertEqual(rx_ip.src, tx_ip.src)
310 self.assertEqual(rx_ip.dst, tx_ip.dst)
311 # bridged, not L3 forwarded, so no TTL decrement
312 self.assertEqual(rx_ip.ttl, tx_ip.ttl)
315 self.logger.error(ppp("Rx:", rx))
316 self.logger.error(ppp("Tx:", tx))
319 def verify_tunneled_vlano4(self, src_if, capture, sent,
320 tunnel_src, tunnel_dst, vlan):
322 self.assertEqual(len(capture), len(sent))
324 ppc("Unexpected packets captured:", capture)
327 for i in range(len(capture)):
335 self.assertEqual(rx_ip.src, tunnel_src)
336 self.assertEqual(rx_ip.dst, tunnel_dst)
339 rx_l2 = rx_gre[Ether]
340 rx_vlan = rx_l2[Dot1Q]
343 self.assertEqual(rx_vlan.vlan, vlan)
346 tx_l2 = tx_gre[Ether]
349 self.assertEqual(rx_ip.src, tx_ip.src)
350 self.assertEqual(rx_ip.dst, tx_ip.dst)
351 # bridged, not L3 forwarded, so no TTL decrement
352 self.assertEqual(rx_ip.ttl, tx_ip.ttl)
355 self.logger.error(ppp("Rx:", rx))
356 self.logger.error(ppp("Tx:", tx))
359 def verify_decapped_4o4(self, src_if, capture, sent):
360 self.assertEqual(len(capture), len(sent))
362 for i in range(len(capture)):
372 self.assertEqual(rx_ip.src, tx_ip.src)
373 self.assertEqual(rx_ip.dst, tx_ip.dst)
374 # IP processing post pop has decremented the TTL
375 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
378 self.logger.error(ppp("Rx:", rx))
379 self.logger.error(ppp("Tx:", tx))
382 def verify_decapped_6o4(self, src_if, capture, sent):
383 self.assertEqual(len(capture), len(sent))
385 for i in range(len(capture)):
395 self.assertEqual(rx_ip.src, tx_ip.src)
396 self.assertEqual(rx_ip.dst, tx_ip.dst)
397 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
400 self.logger.error(ppp("Rx:", rx))
401 self.logger.error(ppp("Tx:", tx))
405 """ GRE IPv4 tunnel Tests """
408 # Create an L3 GRE tunnel.
410 # - assign an IP Addres
411 # - Add a route via the tunnel
413 gre_if = VppGreInterface(self,
416 gre_if.add_vpp_config()
419 # The double create (create the same tunnel twice) should fail,
420 # and we should still be able to use the original
423 gre_if.add_vpp_config()
427 self.fail("Double GRE tunnel add does not fail")
432 route_via_tun = VppIpRoute(self, "4.4.4.4", 32,
433 [VppRoutePath("0.0.0.0",
434 gre_if.sw_if_index)])
436 route_via_tun.add_vpp_config()
439 # Send a packet stream that is routed into the tunnel
440 # - they are all dropped since the tunnel's desintation IP
441 # is unresolved - or resolves via the default route - which
444 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
446 self.send_and_assert_no_replies(self.pg0, tx)
449 # Add a route that resolves the tunnel's destination
451 route_tun_dst = VppIpRoute(self, "1.1.1.2", 32,
452 [VppRoutePath(self.pg0.remote_ip4,
453 self.pg0.sw_if_index)])
454 route_tun_dst.add_vpp_config()
457 # Send a packet stream that is routed into the tunnel
458 # - packets are GRE encapped
460 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
461 rx = self.send_and_expect(self.pg0, tx, self.pg0)
462 self.verify_tunneled_4o4(self.pg0, rx, tx,
463 self.pg0.local_ip4, "1.1.1.2")
466 # Send tunneled packets that match the created tunnel and
467 # are decapped and forwarded
469 tx = self.create_tunnel_stream_4o4(self.pg0,
474 rx = self.send_and_expect(self.pg0, tx, self.pg0)
475 self.verify_decapped_4o4(self.pg0, rx, tx)
478 # Send tunneled packets that do not match the tunnel's src
480 self.vapi.cli("clear trace")
481 tx = self.create_tunnel_stream_4o4(self.pg0,
486 self.send_and_assert_no_replies(
488 remark="GRE packets forwarded despite no SRC address match")
491 # Configure IPv6 on the PG interface so we can route IPv6
494 self.pg0.config_ip6()
495 self.pg0.resolve_ndp()
498 # Send IPv6 tunnel encapslated packets
499 # - dropped since IPv6 is not enabled on the tunnel
501 tx = self.create_tunnel_stream_6o4(self.pg0,
506 self.send_and_assert_no_replies(self.pg0, tx,
507 "IPv6 GRE packets forwarded "
508 "despite IPv6 not enabled on tunnel")
511 # Enable IPv6 on the tunnel
516 # Send IPv6 tunnel encapslated packets
517 # - forwarded since IPv6 is enabled on the tunnel
519 tx = self.create_tunnel_stream_6o4(self.pg0,
524 rx = self.send_and_expect(self.pg0, tx, self.pg0)
525 self.verify_decapped_6o4(self.pg0, rx, tx)
528 # Send v6 packets for v4 encap
530 route6_via_tun = VppIpRoute(
531 self, "2001::1", 128,
534 proto=DpoProto.DPO_PROTO_IP6)],
536 route6_via_tun.add_vpp_config()
538 tx = self.create_stream_ip6(self.pg0, "2001::2", "2001::1")
539 rx = self.send_and_expect(self.pg0, tx, self.pg0)
541 self.verify_tunneled_6o4(self.pg0, rx, tx,
542 self.pg0.local_ip4, "1.1.1.2")
547 route_tun_dst.remove_vpp_config()
548 route_via_tun.remove_vpp_config()
549 route6_via_tun.remove_vpp_config()
550 gre_if.remove_vpp_config()
552 self.pg0.unconfig_ip6()
555 """ GRE IPv6 tunnel Tests """
557 self.pg1.config_ip6()
558 self.pg1.resolve_ndp()
561 # Create an L3 GRE tunnel.
563 # - assign an IP Address
564 # - Add a route via the tunnel
566 gre_if = VppGre6Interface(self,
569 gre_if.add_vpp_config()
573 route_via_tun = VppIpRoute(
574 self, "4004::1", 128,
575 [VppRoutePath("0::0",
577 proto=DpoProto.DPO_PROTO_IP6)],
580 route_via_tun.add_vpp_config()
583 # Send a packet stream that is routed into the tunnel
584 # - they are all dropped since the tunnel's desintation IP
585 # is unresolved - or resolves via the default route - which
588 tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
589 self.send_and_assert_no_replies(
591 "GRE packets forwarded without DIP resolved")
594 # Add a route that resolves the tunnel's destination
596 route_tun_dst = VppIpRoute(
597 self, "1002::1", 128,
598 [VppRoutePath(self.pg2.remote_ip6,
599 self.pg2.sw_if_index,
600 proto=DpoProto.DPO_PROTO_IP6)],
602 route_tun_dst.add_vpp_config()
605 # Send a packet stream that is routed into the tunnel
606 # - packets are GRE encapped
608 tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
609 rx = self.send_and_expect(self.pg2, tx, self.pg2)
610 self.verify_tunneled_6o6(self.pg2, rx, tx,
611 self.pg2.local_ip6, "1002::1")
614 # Test decap. decapped packets go out pg1
616 tx = self.create_tunnel_stream_6o6(self.pg2,
621 rx = self.send_and_expect(self.pg2, tx, self.pg1)
624 # RX'd packet is UDP over IPv6, test the GRE header is gone.
626 self.assertFalse(rx[0].haslayer(GRE))
627 self.assertEqual(rx[0][IPv6].dst, self.pg1.remote_ip6)
632 route4_via_tun = VppIpRoute(self, "1.1.1.1", 32,
633 [VppRoutePath("0.0.0.0",
634 gre_if.sw_if_index)])
635 route4_via_tun.add_vpp_config()
637 tx = self.create_stream_ip4(self.pg0, "1.1.1.2", "1.1.1.1")
638 rx = self.send_and_expect(self.pg0, tx, self.pg2)
640 self.verify_tunneled_4o6(self.pg0, rx, tx,
641 self.pg2.local_ip6, "1002::1")
646 route_tun_dst.remove_vpp_config()
647 route_via_tun.remove_vpp_config()
648 route4_via_tun.remove_vpp_config()
649 gre_if.remove_vpp_config()
651 self.pg2.unconfig_ip6()
652 self.pg1.unconfig_ip6()
654 def test_gre_vrf(self):
655 """ GRE tunnel VRF Tests """
658 # Create an L3 GRE tunnel whose destination is in the non-default
659 # table. The underlay is thus non-default - the overlay is still
662 # - assign an IP Addres
664 gre_if = VppGreInterface(self, self.pg1.local_ip4,
667 gre_if.add_vpp_config()
672 # Add a route via the tunnel - in the overlay
674 route_via_tun = VppIpRoute(self, "9.9.9.9", 32,
675 [VppRoutePath("0.0.0.0",
676 gre_if.sw_if_index)])
677 route_via_tun.add_vpp_config()
680 # Add a route that resolves the tunnel's destination - in the
683 route_tun_dst = VppIpRoute(self, "2.2.2.2", 32, table_id=1,
684 paths=[VppRoutePath(self.pg1.remote_ip4,
685 self.pg1.sw_if_index)])
686 route_tun_dst.add_vpp_config()
689 # Send a packet stream that is routed into the tunnel
690 # packets are sent in on pg0 which is in the default table
691 # - packets are GRE encapped
693 self.vapi.cli("clear trace")
694 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "9.9.9.9")
695 rx = self.send_and_expect(self.pg0, tx, self.pg1)
696 self.verify_tunneled_4o4(self.pg1, rx, tx,
697 self.pg1.local_ip4, "2.2.2.2")
700 # Send tunneled packets that match the created tunnel and
701 # are decapped and forwarded. This tests the decap lookup
702 # does not happen in the encap table
704 self.vapi.cli("clear trace")
705 tx = self.create_tunnel_stream_4o4(self.pg1,
710 rx = self.send_and_expect(self.pg1, tx, self.pg0)
711 self.verify_decapped_4o4(self.pg0, rx, tx)
714 # Send tunneled packets that match the created tunnel
715 # but arrive on an interface that is not in the tunnel's
716 # encap VRF, these are dropped.
717 # IP enable the interface so they aren't dropped due to
718 # IP not being enabled.
720 self.pg2.config_ip4()
721 self.vapi.cli("clear trace")
722 tx = self.create_tunnel_stream_4o4(self.pg2,
727 rx = self.send_and_assert_no_replies(
729 "GRE decap packets in wrong VRF")
731 self.pg2.unconfig_ip4()
736 route_tun_dst.remove_vpp_config()
737 route_via_tun.remove_vpp_config()
738 gre_if.remove_vpp_config()
740 def test_gre_l2(self):
741 """ GRE tunnel L2 Tests """
744 # Add routes to resolve the tunnel destinations
746 route_tun1_dst = VppIpRoute(self, "2.2.2.2", 32,
747 [VppRoutePath(self.pg0.remote_ip4,
748 self.pg0.sw_if_index)])
749 route_tun2_dst = VppIpRoute(self, "2.2.2.3", 32,
750 [VppRoutePath(self.pg0.remote_ip4,
751 self.pg0.sw_if_index)])
753 route_tun1_dst.add_vpp_config()
754 route_tun2_dst.add_vpp_config()
757 # Create 2 L2 GRE tunnels and x-connect them
759 gre_if1 = VppGreInterface(self, self.pg0.local_ip4,
761 type=GreTunnelTypes.TT_TEB)
762 gre_if2 = VppGreInterface(self, self.pg0.local_ip4,
764 type=GreTunnelTypes.TT_TEB)
765 gre_if1.add_vpp_config()
766 gre_if2.add_vpp_config()
771 self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
774 self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
779 # Send in tunnel encapped L2. expect out tunnel encapped L2
782 tx = self.create_tunnel_stream_l2o4(self.pg0,
785 rx = self.send_and_expect(self.pg0, tx, self.pg0)
786 self.verify_tunneled_l2o4(self.pg0, rx, tx,
790 tx = self.create_tunnel_stream_l2o4(self.pg0,
793 rx = self.send_and_expect(self.pg0, tx, self.pg0)
794 self.verify_tunneled_l2o4(self.pg0, rx, tx,
798 self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
801 self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
806 # Create a VLAN sub-interfaces on the GRE TEB interfaces
807 # then x-connect them
809 gre_if_11 = VppDot1QSubint(self, gre_if1, 11)
810 gre_if_12 = VppDot1QSubint(self, gre_if2, 12)
812 # gre_if_11.add_vpp_config()
813 # gre_if_12.add_vpp_config()
818 self.vapi.sw_interface_set_l2_xconnect(gre_if_11.sw_if_index,
819 gre_if_12.sw_if_index,
821 self.vapi.sw_interface_set_l2_xconnect(gre_if_12.sw_if_index,
822 gre_if_11.sw_if_index,
826 # Configure both to pop thier respective VLAN tags,
827 # so that during the x-coonect they will subsequently push
829 self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_12.sw_if_index,
832 self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_11.sw_if_index,
837 # Send traffic in both directiond - expect the VLAN tags to
840 tx = self.create_tunnel_stream_vlano4(self.pg0,
844 rx = self.send_and_expect(self.pg0, tx, self.pg0)
845 self.verify_tunneled_vlano4(self.pg0, rx, tx,
850 tx = self.create_tunnel_stream_vlano4(self.pg0,
854 rx = self.send_and_expect(self.pg0, tx, self.pg0)
855 self.verify_tunneled_vlano4(self.pg0, rx, tx,
861 # Cleanup Test resources
863 gre_if_11.remove_vpp_config()
864 gre_if_12.remove_vpp_config()
865 gre_if1.remove_vpp_config()
866 gre_if2.remove_vpp_config()
867 route_tun1_dst.add_vpp_config()
868 route_tun2_dst.add_vpp_config()
871 if __name__ == '__main__':
872 unittest.main(testRunner=VppTestRunner)