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_l2o4(self, src_if, capture, sent,
234 tunnel_src, tunnel_dst):
235 self.assertEqual(len(capture), len(sent))
237 for i in range(len(capture)):
245 self.assertEqual(rx_ip.src, tunnel_src)
246 self.assertEqual(rx_ip.dst, tunnel_dst)
249 rx_l2 = rx_gre[Ether]
252 tx_l2 = tx_gre[Ether]
255 self.assertEqual(rx_ip.src, tx_ip.src)
256 self.assertEqual(rx_ip.dst, tx_ip.dst)
257 # bridged, not L3 forwarded, so no TTL decrement
258 self.assertEqual(rx_ip.ttl, tx_ip.ttl)
261 self.logger.error(ppp("Rx:", rx))
262 self.logger.error(ppp("Tx:", tx))
265 def verify_tunneled_vlano4(self, src_if, capture, sent,
266 tunnel_src, tunnel_dst, vlan):
268 self.assertEqual(len(capture), len(sent))
270 ppc("Unexpected packets captured:", capture)
273 for i in range(len(capture)):
281 self.assertEqual(rx_ip.src, tunnel_src)
282 self.assertEqual(rx_ip.dst, tunnel_dst)
285 rx_l2 = rx_gre[Ether]
286 rx_vlan = rx_l2[Dot1Q]
289 self.assertEqual(rx_vlan.vlan, vlan)
292 tx_l2 = tx_gre[Ether]
295 self.assertEqual(rx_ip.src, tx_ip.src)
296 self.assertEqual(rx_ip.dst, tx_ip.dst)
297 # bridged, not L3 forwarded, so no TTL decrement
298 self.assertEqual(rx_ip.ttl, tx_ip.ttl)
301 self.logger.error(ppp("Rx:", rx))
302 self.logger.error(ppp("Tx:", tx))
305 def verify_decapped_4o4(self, src_if, capture, sent):
306 self.assertEqual(len(capture), len(sent))
308 for i in range(len(capture)):
318 self.assertEqual(rx_ip.src, tx_ip.src)
319 self.assertEqual(rx_ip.dst, tx_ip.dst)
320 # IP processing post pop has decremented the TTL
321 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
324 self.logger.error(ppp("Rx:", rx))
325 self.logger.error(ppp("Tx:", tx))
328 def verify_decapped_6o4(self, src_if, capture, sent):
329 self.assertEqual(len(capture), len(sent))
331 for i in range(len(capture)):
341 self.assertEqual(rx_ip.src, tx_ip.src)
342 self.assertEqual(rx_ip.dst, tx_ip.dst)
343 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
346 self.logger.error(ppp("Rx:", rx))
347 self.logger.error(ppp("Tx:", tx))
351 """ GRE IPv4 tunnel Tests """
354 # Create an L3 GRE tunnel.
356 # - assign an IP Addres
357 # - Add a route via the tunnel
359 gre_if = VppGreInterface(self,
362 gre_if.add_vpp_config()
365 # The double create (create the same tunnel twice) should fail,
366 # and we should still be able to use the original
369 gre_if.add_vpp_config()
373 self.fail("Double GRE tunnel add does not fail")
378 route_via_tun = VppIpRoute(self, "4.4.4.4", 32,
379 [VppRoutePath("0.0.0.0",
380 gre_if.sw_if_index)])
382 route_via_tun.add_vpp_config()
385 # Send a packet stream that is routed into the tunnel
386 # - they are all dropped since the tunnel's desintation IP
387 # is unresolved - or resolves via the default route - which
390 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
391 self.pg0.add_stream(tx)
393 self.pg_enable_capture(self.pg_interfaces)
396 self.pg0.assert_nothing_captured(
397 remark="GRE packets forwarded without DIP resolved")
400 # Add a route that resolves the tunnel's destination
402 route_tun_dst = VppIpRoute(self, "1.1.1.2", 32,
403 [VppRoutePath(self.pg0.remote_ip4,
404 self.pg0.sw_if_index)])
405 route_tun_dst.add_vpp_config()
408 # Send a packet stream that is routed into the tunnel
409 # - packets are GRE encapped
411 self.vapi.cli("clear trace")
412 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
413 self.pg0.add_stream(tx)
415 self.pg_enable_capture(self.pg_interfaces)
418 rx = self.pg0.get_capture(len(tx))
419 self.verify_tunneled_4o4(self.pg0, rx, tx,
420 self.pg0.local_ip4, "1.1.1.2")
423 # Send tunneled packets that match the created tunnel and
424 # are decapped and forwarded
426 self.vapi.cli("clear trace")
427 tx = self.create_tunnel_stream_4o4(self.pg0,
432 self.pg0.add_stream(tx)
434 self.pg_enable_capture(self.pg_interfaces)
437 rx = self.pg0.get_capture(len(tx))
438 self.verify_decapped_4o4(self.pg0, rx, tx)
441 # Send tunneled packets that do not match the tunnel's src
443 self.vapi.cli("clear trace")
444 tx = self.create_tunnel_stream_4o4(self.pg0,
449 self.pg0.add_stream(tx)
451 self.pg_enable_capture(self.pg_interfaces)
454 self.pg0.assert_nothing_captured(
455 remark="GRE packets forwarded despite no SRC address match")
458 # Configure IPv6 on the PG interface so we can route IPv6
461 self.pg0.config_ip6()
462 self.pg0.resolve_ndp()
465 # Send IPv6 tunnel encapslated packets
466 # - dropped since IPv6 is not enabled on the tunnel
468 self.vapi.cli("clear trace")
469 tx = self.create_tunnel_stream_6o4(self.pg0,
474 self.pg0.add_stream(tx)
476 self.pg_enable_capture(self.pg_interfaces)
479 self.pg0.assert_nothing_captured(remark="IPv6 GRE packets forwarded "
480 "despite IPv6 not enabled on tunnel")
483 # Enable IPv6 on the tunnel
488 # Send IPv6 tunnel encapslated packets
489 # - forwarded since IPv6 is enabled on the tunnel
491 self.vapi.cli("clear trace")
492 tx = self.create_tunnel_stream_6o4(self.pg0,
497 self.pg0.add_stream(tx)
499 self.pg_enable_capture(self.pg_interfaces)
502 rx = self.pg0.get_capture(len(tx))
503 self.verify_decapped_6o4(self.pg0, rx, tx)
508 route_tun_dst.remove_vpp_config()
509 route_via_tun.remove_vpp_config()
510 gre_if.remove_vpp_config()
512 self.pg0.unconfig_ip6()
515 """ GRE IPv6 tunnel Tests """
517 self.pg1.config_ip6()
518 self.pg1.resolve_ndp()
521 # Create an L3 GRE tunnel.
523 # - assign an IP Address
524 # - Add a route via the tunnel
526 gre_if = VppGre6Interface(self,
529 gre_if.add_vpp_config()
533 route_via_tun = VppIpRoute(
534 self, "4004::1", 128,
535 [VppRoutePath("0::0",
537 proto=DpoProto.DPO_PROTO_IP6)],
540 route_via_tun.add_vpp_config()
543 # Send a packet stream that is routed into the tunnel
544 # - they are all dropped since the tunnel's desintation IP
545 # is unresolved - or resolves via the default route - which
548 tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
549 self.pg2.add_stream(tx)
551 self.pg_enable_capture(self.pg_interfaces)
554 self.pg2.assert_nothing_captured(
555 remark="GRE packets forwarded without DIP resolved")
558 # Add a route that resolves the tunnel's destination
560 route_tun_dst = VppIpRoute(
561 self, "1002::1", 128,
562 [VppRoutePath(self.pg2.remote_ip6,
563 self.pg2.sw_if_index,
564 proto=DpoProto.DPO_PROTO_IP6)],
566 route_tun_dst.add_vpp_config()
569 # Send a packet stream that is routed into the tunnel
570 # - packets are GRE encapped
572 self.vapi.cli("clear trace")
573 tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
574 self.pg2.add_stream(tx)
576 self.pg_enable_capture(self.pg_interfaces)
579 rx = self.pg2.get_capture(len(tx))
580 self.verify_tunneled_6o6(self.pg2, rx, tx,
581 self.pg2.local_ip6, "1002::1")
584 # Test decap. decapped packets go out pg1
586 tx = self.create_tunnel_stream_6o6(self.pg2,
591 self.vapi.cli("clear trace")
592 self.pg2.add_stream(tx)
594 self.pg_enable_capture(self.pg_interfaces)
596 rx = self.pg1.get_capture(len(tx))
599 # RX'd packet is UDP over IPv6, test the GRE header is gone.
601 self.assertFalse(rx[0].haslayer(GRE))
602 self.assertEqual(rx[0][IPv6].dst, self.pg1.remote_ip6)
607 route_tun_dst.remove_vpp_config()
608 route_via_tun.remove_vpp_config()
609 gre_if.remove_vpp_config()
611 self.pg2.unconfig_ip6()
612 self.pg1.unconfig_ip6()
614 def test_gre_vrf(self):
615 """ GRE tunnel VRF Tests """
618 # Create an L3 GRE tunnel whose destination is in the non-default
619 # table. The underlay is thus non-default - the overlay is still
622 # - assign an IP Addres
624 gre_if = VppGreInterface(self, self.pg1.local_ip4,
627 gre_if.add_vpp_config()
632 # Add a route via the tunnel - in the overlay
634 route_via_tun = VppIpRoute(self, "9.9.9.9", 32,
635 [VppRoutePath("0.0.0.0",
636 gre_if.sw_if_index)])
637 route_via_tun.add_vpp_config()
640 # Add a route that resolves the tunnel's destination - in the
643 route_tun_dst = VppIpRoute(self, "2.2.2.2", 32, table_id=1,
644 paths=[VppRoutePath(self.pg1.remote_ip4,
645 self.pg1.sw_if_index)])
646 route_tun_dst.add_vpp_config()
649 # Send a packet stream that is routed into the tunnel
650 # packets are sent in on pg0 which is in the default table
651 # - packets are GRE encapped
653 self.vapi.cli("clear trace")
654 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "9.9.9.9")
655 self.pg0.add_stream(tx)
657 self.pg_enable_capture(self.pg_interfaces)
660 rx = self.pg1.get_capture(len(tx))
661 self.verify_tunneled_4o4(self.pg1, rx, tx,
662 self.pg1.local_ip4, "2.2.2.2")
665 # Send tunneled packets that match the created tunnel and
666 # are decapped and forwarded. This tests the decap lookup
667 # does not happen in the encap table
669 self.vapi.cli("clear trace")
670 tx = self.create_tunnel_stream_4o4(self.pg1,
675 self.pg1.add_stream(tx)
677 self.pg_enable_capture(self.pg_interfaces)
680 rx = self.pg0.get_capture(len(tx))
681 self.verify_decapped_4o4(self.pg0, rx, tx)
684 # Send tunneled packets that match the created tunnel and
685 # but arrive on an interface that is not in the tunnel's
686 # encap VRF, these are dropped
688 self.vapi.cli("clear trace")
689 tx = self.create_tunnel_stream_4o4(self.pg2,
694 self.pg1.add_stream(tx)
696 self.pg_enable_capture(self.pg_interfaces)
699 self.pg0.assert_nothing_captured(
700 remark="GRE decap packets in wrong VRF")
705 route_tun_dst.remove_vpp_config()
706 route_via_tun.remove_vpp_config()
707 gre_if.remove_vpp_config()
709 def test_gre_l2(self):
710 """ GRE tunnel L2 Tests """
713 # Add routes to resolve the tunnel destinations
715 route_tun1_dst = VppIpRoute(self, "2.2.2.2", 32,
716 [VppRoutePath(self.pg0.remote_ip4,
717 self.pg0.sw_if_index)])
718 route_tun2_dst = VppIpRoute(self, "2.2.2.3", 32,
719 [VppRoutePath(self.pg0.remote_ip4,
720 self.pg0.sw_if_index)])
722 route_tun1_dst.add_vpp_config()
723 route_tun2_dst.add_vpp_config()
726 # Create 2 L2 GRE tunnels and x-connect them
728 gre_if1 = VppGreInterface(self, self.pg0.local_ip4,
730 type=GreTunnelTypes.TT_TEB)
731 gre_if2 = VppGreInterface(self, self.pg0.local_ip4,
733 type=GreTunnelTypes.TT_TEB)
734 gre_if1.add_vpp_config()
735 gre_if2.add_vpp_config()
740 self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
743 self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
748 # Send in tunnel encapped L2. expect out tunnel encapped L2
751 self.vapi.cli("clear trace")
752 tx = self.create_tunnel_stream_l2o4(self.pg0,
755 self.pg0.add_stream(tx)
757 self.pg_enable_capture(self.pg_interfaces)
760 rx = self.pg0.get_capture(len(tx))
761 self.verify_tunneled_l2o4(self.pg0, rx, tx,
765 self.vapi.cli("clear trace")
766 tx = self.create_tunnel_stream_l2o4(self.pg0,
769 self.pg0.add_stream(tx)
771 self.pg_enable_capture(self.pg_interfaces)
774 rx = self.pg0.get_capture(len(tx))
775 self.verify_tunneled_l2o4(self.pg0, rx, tx,
779 self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
782 self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
787 # Create a VLAN sub-interfaces on the GRE TEB interfaces
788 # then x-connect them
790 gre_if_11 = VppDot1QSubint(self, gre_if1, 11)
791 gre_if_12 = VppDot1QSubint(self, gre_if2, 12)
793 # gre_if_11.add_vpp_config()
794 # gre_if_12.add_vpp_config()
799 self.vapi.sw_interface_set_l2_xconnect(gre_if_11.sw_if_index,
800 gre_if_12.sw_if_index,
802 self.vapi.sw_interface_set_l2_xconnect(gre_if_12.sw_if_index,
803 gre_if_11.sw_if_index,
807 # Configure both to pop thier respective VLAN tags,
808 # so that during the x-coonect they will subsequently push
810 self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_12.sw_if_index,
813 self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_11.sw_if_index,
818 # Send traffic in both directiond - expect the VLAN tags to
821 self.vapi.cli("clear trace")
822 tx = self.create_tunnel_stream_vlano4(self.pg0,
826 self.pg0.add_stream(tx)
828 self.pg_enable_capture(self.pg_interfaces)
831 rx = self.pg0.get_capture(len(tx))
832 self.verify_tunneled_vlano4(self.pg0, rx, tx,
837 self.vapi.cli("clear trace")
838 tx = self.create_tunnel_stream_vlano4(self.pg0,
842 self.pg0.add_stream(tx)
844 self.pg_enable_capture(self.pg_interfaces)
847 rx = self.pg0.get_capture(len(tx))
848 self.verify_tunneled_vlano4(self.pg0, rx, tx,
854 # Cleanup Test resources
856 gre_if_11.remove_vpp_config()
857 gre_if_12.remove_vpp_config()
858 gre_if1.remove_vpp_config()
859 gre_if2.remove_vpp_config()
860 route_tun1_dst.add_vpp_config()
861 route_tun2_dst.add_vpp_config()
864 if __name__ == '__main__':
865 unittest.main(testRunner=VppTestRunner)