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_route import VppIpRoute, VppRoutePath, DpoProto
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 3 pg interfaces - set one in a non-default table.
32 self.create_pg_interfaces(range(3))
33 self.pg1.set_table_ip4(1)
35 for i in self.pg_interfaces:
39 self.pg0.resolve_arp()
41 self.pg1.resolve_arp()
43 self.pg2.resolve_ndp()
46 super(TestGRE, self).tearDown()
47 for i in self.pg_interfaces:
52 def create_stream_ip4(self, src_if, src_ip, dst_ip):
54 for i in range(0, 257):
55 info = self.create_packet_info(src_if, src_if)
56 payload = self.info_to_payload(info)
57 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
58 IP(src=src_ip, dst=dst_ip) /
59 UDP(sport=1234, dport=1234) /
65 def create_stream_ip6(self, src_if, src_ip, dst_ip):
67 for i in range(0, 257):
68 info = self.create_packet_info(src_if, src_if)
69 payload = self.info_to_payload(info)
70 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
71 IPv6(src=src_ip, dst=dst_ip) /
72 UDP(sport=1234, dport=1234) /
78 def create_tunnel_stream_4o4(self, src_if,
79 tunnel_src, tunnel_dst,
82 for i in range(0, 257):
83 info = self.create_packet_info(src_if, src_if)
84 payload = self.info_to_payload(info)
85 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
86 IP(src=tunnel_src, dst=tunnel_dst) /
88 IP(src=src_ip, dst=dst_ip) /
89 UDP(sport=1234, dport=1234) /
95 def create_tunnel_stream_6o4(self, src_if,
96 tunnel_src, tunnel_dst,
99 for i in range(0, 257):
100 info = self.create_packet_info(src_if, src_if)
101 payload = self.info_to_payload(info)
102 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
103 IP(src=tunnel_src, dst=tunnel_dst) /
105 IPv6(src=src_ip, dst=dst_ip) /
106 UDP(sport=1234, dport=1234) /
112 def create_tunnel_stream_6o6(self, src_if,
113 tunnel_src, tunnel_dst,
116 for i in range(0, 257):
117 info = self.create_packet_info(src_if, src_if)
118 payload = self.info_to_payload(info)
119 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
120 IPv6(src=tunnel_src, dst=tunnel_dst) /
122 IPv6(src=src_ip, dst=dst_ip) /
123 UDP(sport=1234, dport=1234) /
129 def create_tunnel_stream_l2o4(self, src_if,
130 tunnel_src, tunnel_dst):
132 for i in range(0, 257):
133 info = self.create_packet_info(src_if, src_if)
134 payload = self.info_to_payload(info)
135 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
136 IP(src=tunnel_src, dst=tunnel_dst) /
138 Ether(dst=RandMAC('*:*:*:*:*:*'),
139 src=RandMAC('*:*:*:*:*:*')) /
140 IP(src=str(RandIP()), dst=str(RandIP())) /
141 UDP(sport=1234, dport=1234) /
147 def create_tunnel_stream_vlano4(self, src_if,
148 tunnel_src, tunnel_dst, vlan):
150 for i in range(0, 257):
151 info = self.create_packet_info(src_if, src_if)
152 payload = self.info_to_payload(info)
153 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
154 IP(src=tunnel_src, dst=tunnel_dst) /
156 Ether(dst=RandMAC('*:*:*:*:*:*'),
157 src=RandMAC('*:*:*:*:*:*')) /
159 IP(src=str(RandIP()), dst=str(RandIP())) /
160 UDP(sport=1234, dport=1234) /
166 def verify_tunneled_4o4(self, src_if, capture, sent,
167 tunnel_src, tunnel_dst):
169 self.assertEqual(len(capture), len(sent))
171 for i in range(len(capture)):
179 self.assertEqual(rx_ip.src, tunnel_src)
180 self.assertEqual(rx_ip.dst, tunnel_dst)
185 self.assertEqual(rx_ip.src, tx_ip.src)
186 self.assertEqual(rx_ip.dst, tx_ip.dst)
187 # IP processing post pop has decremented the TTL
188 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
191 self.logger.error(ppp("Rx:", rx))
192 self.logger.error(ppp("Tx:", tx))
195 def verify_tunneled_6o6(self, src_if, capture, sent,
196 tunnel_src, tunnel_dst):
198 self.assertEqual(len(capture), len(sent))
200 for i in range(len(capture)):
208 self.assertEqual(rx_ip.src, tunnel_src)
209 self.assertEqual(rx_ip.dst, tunnel_dst)
211 rx_gre = GRE(str(rx_ip[IPv6].payload))
214 self.assertEqual(rx_ip.src, tx_ip.src)
215 self.assertEqual(rx_ip.dst, tx_ip.dst)
218 self.logger.error(ppp("Rx:", rx))
219 self.logger.error(ppp("Tx:", tx))
222 def verify_tunneled_l2o4(self, src_if, capture, sent,
223 tunnel_src, tunnel_dst):
224 self.assertEqual(len(capture), len(sent))
226 for i in range(len(capture)):
234 self.assertEqual(rx_ip.src, tunnel_src)
235 self.assertEqual(rx_ip.dst, tunnel_dst)
238 rx_l2 = rx_gre[Ether]
241 tx_l2 = tx_gre[Ether]
244 self.assertEqual(rx_ip.src, tx_ip.src)
245 self.assertEqual(rx_ip.dst, tx_ip.dst)
246 # bridged, not L3 forwarded, so no TTL decrement
247 self.assertEqual(rx_ip.ttl, tx_ip.ttl)
250 self.logger.error(ppp("Rx:", rx))
251 self.logger.error(ppp("Tx:", tx))
254 def verify_tunneled_vlano4(self, src_if, capture, sent,
255 tunnel_src, tunnel_dst, vlan):
257 self.assertEqual(len(capture), len(sent))
259 ppc("Unexpected packets captured:", capture)
262 for i in range(len(capture)):
270 self.assertEqual(rx_ip.src, tunnel_src)
271 self.assertEqual(rx_ip.dst, tunnel_dst)
274 rx_l2 = rx_gre[Ether]
275 rx_vlan = rx_l2[Dot1Q]
278 self.assertEqual(rx_vlan.vlan, vlan)
281 tx_l2 = tx_gre[Ether]
284 self.assertEqual(rx_ip.src, tx_ip.src)
285 self.assertEqual(rx_ip.dst, tx_ip.dst)
286 # bridged, not L3 forwarded, so no TTL decrement
287 self.assertEqual(rx_ip.ttl, tx_ip.ttl)
290 self.logger.error(ppp("Rx:", rx))
291 self.logger.error(ppp("Tx:", tx))
294 def verify_decapped_4o4(self, src_if, capture, sent):
295 self.assertEqual(len(capture), len(sent))
297 for i in range(len(capture)):
307 self.assertEqual(rx_ip.src, tx_ip.src)
308 self.assertEqual(rx_ip.dst, tx_ip.dst)
309 # IP processing post pop has decremented the TTL
310 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
313 self.logger.error(ppp("Rx:", rx))
314 self.logger.error(ppp("Tx:", tx))
317 def verify_decapped_6o4(self, src_if, capture, sent):
318 self.assertEqual(len(capture), len(sent))
320 for i in range(len(capture)):
330 self.assertEqual(rx_ip.src, tx_ip.src)
331 self.assertEqual(rx_ip.dst, tx_ip.dst)
332 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
335 self.logger.error(ppp("Rx:", rx))
336 self.logger.error(ppp("Tx:", tx))
340 """ GRE IPv4 tunnel Tests """
343 # Create an L3 GRE tunnel.
345 # - assign an IP Addres
346 # - Add a route via the tunnel
348 gre_if = VppGreInterface(self,
351 gre_if.add_vpp_config()
354 # The double create (create the same tunnel twice) should fail,
355 # and we should still be able to use the original
358 gre_if.add_vpp_config()
362 self.fail("Double GRE tunnel add does not fail")
367 route_via_tun = VppIpRoute(self, "4.4.4.4", 32,
368 [VppRoutePath("0.0.0.0",
369 gre_if.sw_if_index)])
371 route_via_tun.add_vpp_config()
374 # Send a packet stream that is routed into the tunnel
375 # - they are all dropped since the tunnel's desintation IP
376 # is unresolved - or resolves via the default route - which
379 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
380 self.pg0.add_stream(tx)
382 self.pg_enable_capture(self.pg_interfaces)
385 self.pg0.assert_nothing_captured(
386 remark="GRE packets forwarded without DIP resolved")
389 # Add a route that resolves the tunnel's destination
391 route_tun_dst = VppIpRoute(self, "1.1.1.2", 32,
392 [VppRoutePath(self.pg0.remote_ip4,
393 self.pg0.sw_if_index)])
394 route_tun_dst.add_vpp_config()
397 # Send a packet stream that is routed into the tunnel
398 # - packets are GRE encapped
400 self.vapi.cli("clear trace")
401 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
402 self.pg0.add_stream(tx)
404 self.pg_enable_capture(self.pg_interfaces)
407 rx = self.pg0.get_capture(len(tx))
408 self.verify_tunneled_4o4(self.pg0, rx, tx,
409 self.pg0.local_ip4, "1.1.1.2")
412 # Send tunneled packets that match the created tunnel and
413 # are decapped and forwarded
415 self.vapi.cli("clear trace")
416 tx = self.create_tunnel_stream_4o4(self.pg0,
421 self.pg0.add_stream(tx)
423 self.pg_enable_capture(self.pg_interfaces)
426 rx = self.pg0.get_capture(len(tx))
427 self.verify_decapped_4o4(self.pg0, rx, tx)
430 # Send tunneled packets that do not match the tunnel's src
432 self.vapi.cli("clear trace")
433 tx = self.create_tunnel_stream_4o4(self.pg0,
438 self.pg0.add_stream(tx)
440 self.pg_enable_capture(self.pg_interfaces)
443 self.pg0.assert_nothing_captured(
444 remark="GRE packets forwarded despite no SRC address match")
447 # Configure IPv6 on the PG interface so we can route IPv6
450 self.pg0.config_ip6()
451 self.pg0.resolve_ndp()
454 # Send IPv6 tunnel encapslated packets
455 # - dropped since IPv6 is not enabled on the tunnel
457 self.vapi.cli("clear trace")
458 tx = self.create_tunnel_stream_6o4(self.pg0,
463 self.pg0.add_stream(tx)
465 self.pg_enable_capture(self.pg_interfaces)
468 self.pg0.assert_nothing_captured(remark="IPv6 GRE packets forwarded "
469 "despite IPv6 not enabled on tunnel")
472 # Enable IPv6 on the tunnel
477 # Send IPv6 tunnel encapslated packets
478 # - forwarded since IPv6 is enabled on the tunnel
480 self.vapi.cli("clear trace")
481 tx = self.create_tunnel_stream_6o4(self.pg0,
486 self.pg0.add_stream(tx)
488 self.pg_enable_capture(self.pg_interfaces)
491 rx = self.pg0.get_capture(len(tx))
492 self.verify_decapped_6o4(self.pg0, rx, tx)
497 route_tun_dst.remove_vpp_config()
498 route_via_tun.remove_vpp_config()
499 gre_if.remove_vpp_config()
501 self.pg0.unconfig_ip6()
504 """ GRE IPv6 tunnel Tests """
507 # Create an L3 GRE tunnel.
509 # - assign an IP Address
510 # - Add a route via the tunnel
512 gre_if = VppGre6Interface(self,
515 gre_if.add_vpp_config()
519 route_via_tun = VppIpRoute(
520 self, "4004::1", 128,
521 [VppRoutePath("0::0",
523 proto=DpoProto.DPO_PROTO_IP6)],
526 route_via_tun.add_vpp_config()
529 # Send a packet stream that is routed into the tunnel
530 # - they are all dropped since the tunnel's desintation IP
531 # is unresolved - or resolves via the default route - which
534 tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
535 self.pg2.add_stream(tx)
537 self.pg_enable_capture(self.pg_interfaces)
540 self.pg2.assert_nothing_captured(
541 remark="GRE packets forwarded without DIP resolved")
544 # Add a route that resolves the tunnel's destination
546 route_tun_dst = VppIpRoute(
547 self, "1002::1", 128,
548 [VppRoutePath(self.pg2.remote_ip6,
549 self.pg2.sw_if_index,
550 proto=DpoProto.DPO_PROTO_IP6)],
552 route_tun_dst.add_vpp_config()
555 # Send a packet stream that is routed into the tunnel
556 # - packets are GRE encapped
558 self.vapi.cli("clear trace")
559 tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
560 self.pg2.add_stream(tx)
562 self.pg_enable_capture(self.pg_interfaces)
565 rx = self.pg2.get_capture(len(tx))
566 self.verify_tunneled_6o6(self.pg2, rx, tx,
567 self.pg2.local_ip6, "1002::1")
572 route_tun_dst.remove_vpp_config()
573 route_via_tun.remove_vpp_config()
574 gre_if.remove_vpp_config()
576 self.pg2.unconfig_ip6()
578 def test_gre_vrf(self):
579 """ GRE tunnel VRF Tests """
582 # Create an L3 GRE tunnel whose destination is in the non-default
583 # table. The underlay is thus non-default - the overlay is still
586 # - assign an IP Addres
588 gre_if = VppGreInterface(self, self.pg1.local_ip4,
591 gre_if.add_vpp_config()
596 # Add a route via the tunnel - in the overlay
598 route_via_tun = VppIpRoute(self, "9.9.9.9", 32,
599 [VppRoutePath("0.0.0.0",
600 gre_if.sw_if_index)])
601 route_via_tun.add_vpp_config()
604 # Add a route that resolves the tunnel's destination - in the
607 route_tun_dst = VppIpRoute(self, "2.2.2.2", 32, table_id=1,
608 paths=[VppRoutePath(self.pg1.remote_ip4,
609 self.pg1.sw_if_index)])
610 route_tun_dst.add_vpp_config()
613 # Send a packet stream that is routed into the tunnel
614 # packets are sent in on pg0 which is in the default table
615 # - packets are GRE encapped
617 self.vapi.cli("clear trace")
618 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "9.9.9.9")
619 self.pg0.add_stream(tx)
621 self.pg_enable_capture(self.pg_interfaces)
624 rx = self.pg1.get_capture(len(tx))
625 self.verify_tunneled_4o4(self.pg1, rx, tx,
626 self.pg1.local_ip4, "2.2.2.2")
629 # Send tunneled packets that match the created tunnel and
630 # are decapped and forwarded. This tests the decap lookup
631 # does not happen in the encap table
633 self.vapi.cli("clear trace")
634 tx = self.create_tunnel_stream_4o4(self.pg1,
639 self.pg1.add_stream(tx)
641 self.pg_enable_capture(self.pg_interfaces)
644 rx = self.pg0.get_capture(len(tx))
645 self.verify_decapped_4o4(self.pg0, rx, tx)
650 route_tun_dst.remove_vpp_config()
651 route_via_tun.remove_vpp_config()
652 gre_if.remove_vpp_config()
654 def test_gre_l2(self):
655 """ GRE tunnel L2 Tests """
658 # Add routes to resolve the tunnel destinations
660 route_tun1_dst = VppIpRoute(self, "2.2.2.2", 32,
661 [VppRoutePath(self.pg0.remote_ip4,
662 self.pg0.sw_if_index)])
663 route_tun2_dst = VppIpRoute(self, "2.2.2.3", 32,
664 [VppRoutePath(self.pg0.remote_ip4,
665 self.pg0.sw_if_index)])
667 route_tun1_dst.add_vpp_config()
668 route_tun2_dst.add_vpp_config()
671 # Create 2 L2 GRE tunnels and x-connect them
673 gre_if1 = VppGreInterface(self, self.pg0.local_ip4,
676 gre_if2 = VppGreInterface(self, self.pg0.local_ip4,
679 gre_if1.add_vpp_config()
680 gre_if2.add_vpp_config()
685 self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
688 self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
693 # Send in tunnel encapped L2. expect out tunnel encapped L2
696 self.vapi.cli("clear trace")
697 tx = self.create_tunnel_stream_l2o4(self.pg0,
700 self.pg0.add_stream(tx)
702 self.pg_enable_capture(self.pg_interfaces)
705 rx = self.pg0.get_capture(len(tx))
706 self.verify_tunneled_l2o4(self.pg0, rx, tx,
710 self.vapi.cli("clear trace")
711 tx = self.create_tunnel_stream_l2o4(self.pg0,
714 self.pg0.add_stream(tx)
716 self.pg_enable_capture(self.pg_interfaces)
719 rx = self.pg0.get_capture(len(tx))
720 self.verify_tunneled_l2o4(self.pg0, rx, tx,
724 self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
727 self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
732 # Create a VLAN sub-interfaces on the GRE TEB interfaces
733 # then x-connect them
735 gre_if_11 = VppDot1QSubint(self, gre_if1, 11)
736 gre_if_12 = VppDot1QSubint(self, gre_if2, 12)
738 # gre_if_11.add_vpp_config()
739 # gre_if_12.add_vpp_config()
744 self.vapi.sw_interface_set_l2_xconnect(gre_if_11.sw_if_index,
745 gre_if_12.sw_if_index,
747 self.vapi.sw_interface_set_l2_xconnect(gre_if_12.sw_if_index,
748 gre_if_11.sw_if_index,
752 # Configure both to pop thier respective VLAN tags,
753 # so that during the x-coonect they will subsequently push
755 self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_12.sw_if_index,
758 self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_11.sw_if_index,
763 # Send traffic in both directiond - expect the VLAN tags to
766 self.vapi.cli("clear trace")
767 tx = self.create_tunnel_stream_vlano4(self.pg0,
771 self.pg0.add_stream(tx)
773 self.pg_enable_capture(self.pg_interfaces)
776 rx = self.pg0.get_capture(len(tx))
777 self.verify_tunneled_vlano4(self.pg0, rx, tx,
782 self.vapi.cli("clear trace")
783 tx = self.create_tunnel_stream_vlano4(self.pg0,
787 self.pg0.add_stream(tx)
789 self.pg_enable_capture(self.pg_interfaces)
792 rx = self.pg0.get_capture(len(tx))
793 self.verify_tunneled_vlano4(self.pg0, rx, tx,
799 # Cleanup Test resources
801 gre_if_11.remove_vpp_config()
802 gre_if_12.remove_vpp_config()
803 gre_if1.remove_vpp_config()
804 gre_if2.remove_vpp_config()
805 route_tun1_dst.add_vpp_config()
806 route_tun2_dst.add_vpp_config()
809 if __name__ == '__main__':
810 unittest.main(testRunner=VppTestRunner)