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
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(self, "4004::1", 128,
520 [VppRoutePath("0::0",
525 route_via_tun.add_vpp_config()
528 # Send a packet stream that is routed into the tunnel
529 # - they are all dropped since the tunnel's desintation IP
530 # is unresolved - or resolves via the default route - which
533 tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
534 self.pg2.add_stream(tx)
536 self.pg_enable_capture(self.pg_interfaces)
539 self.pg2.assert_nothing_captured(
540 remark="GRE packets forwarded without DIP resolved")
543 # Add a route that resolves the tunnel's destination
545 route_tun_dst = VppIpRoute(self, "1002::1", 128,
546 [VppRoutePath(self.pg2.remote_ip6,
547 self.pg2.sw_if_index,
550 route_tun_dst.add_vpp_config()
553 # Send a packet stream that is routed into the tunnel
554 # - packets are GRE encapped
556 self.vapi.cli("clear trace")
557 tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
558 self.pg2.add_stream(tx)
560 self.pg_enable_capture(self.pg_interfaces)
563 rx = self.pg2.get_capture(len(tx))
564 self.verify_tunneled_6o6(self.pg2, rx, tx,
565 self.pg2.local_ip6, "1002::1")
570 route_tun_dst.remove_vpp_config()
571 route_via_tun.remove_vpp_config()
572 gre_if.remove_vpp_config()
574 self.pg2.unconfig_ip6()
576 def test_gre_vrf(self):
577 """ GRE tunnel VRF Tests """
580 # Create an L3 GRE tunnel whose destination is in the non-default
581 # table. The underlay is thus non-default - the overlay is still
584 # - assign an IP Addres
586 gre_if = VppGreInterface(self, self.pg1.local_ip4,
589 gre_if.add_vpp_config()
594 # Add a route via the tunnel - in the overlay
596 route_via_tun = VppIpRoute(self, "9.9.9.9", 32,
597 [VppRoutePath("0.0.0.0",
598 gre_if.sw_if_index)])
599 route_via_tun.add_vpp_config()
602 # Add a route that resolves the tunnel's destination - in the
605 route_tun_dst = VppIpRoute(self, "2.2.2.2", 32, table_id=1,
606 paths=[VppRoutePath(self.pg1.remote_ip4,
607 self.pg1.sw_if_index)])
608 route_tun_dst.add_vpp_config()
611 # Send a packet stream that is routed into the tunnel
612 # packets are sent in on pg0 which is in the default table
613 # - packets are GRE encapped
615 self.vapi.cli("clear trace")
616 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "9.9.9.9")
617 self.pg0.add_stream(tx)
619 self.pg_enable_capture(self.pg_interfaces)
622 rx = self.pg1.get_capture(len(tx))
623 self.verify_tunneled_4o4(self.pg1, rx, tx,
624 self.pg1.local_ip4, "2.2.2.2")
627 # Send tunneled packets that match the created tunnel and
628 # are decapped and forwarded. This tests the decap lookup
629 # does not happen in the encap table
631 self.vapi.cli("clear trace")
632 tx = self.create_tunnel_stream_4o4(self.pg1,
637 self.pg1.add_stream(tx)
639 self.pg_enable_capture(self.pg_interfaces)
642 rx = self.pg0.get_capture(len(tx))
643 self.verify_decapped_4o4(self.pg0, rx, tx)
648 route_tun_dst.remove_vpp_config()
649 route_via_tun.remove_vpp_config()
650 gre_if.remove_vpp_config()
652 def test_gre_l2(self):
653 """ GRE tunnel L2 Tests """
656 # Add routes to resolve the tunnel destinations
658 route_tun1_dst = VppIpRoute(self, "2.2.2.2", 32,
659 [VppRoutePath(self.pg0.remote_ip4,
660 self.pg0.sw_if_index)])
661 route_tun2_dst = VppIpRoute(self, "2.2.2.3", 32,
662 [VppRoutePath(self.pg0.remote_ip4,
663 self.pg0.sw_if_index)])
665 route_tun1_dst.add_vpp_config()
666 route_tun2_dst.add_vpp_config()
669 # Create 2 L2 GRE tunnels and x-connect them
671 gre_if1 = VppGreInterface(self, self.pg0.local_ip4,
674 gre_if2 = VppGreInterface(self, self.pg0.local_ip4,
677 gre_if1.add_vpp_config()
678 gre_if2.add_vpp_config()
683 self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
686 self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
691 # Send in tunnel encapped L2. expect out tunnel encapped L2
694 self.vapi.cli("clear trace")
695 tx = self.create_tunnel_stream_l2o4(self.pg0,
698 self.pg0.add_stream(tx)
700 self.pg_enable_capture(self.pg_interfaces)
703 rx = self.pg0.get_capture(len(tx))
704 self.verify_tunneled_l2o4(self.pg0, rx, tx,
708 self.vapi.cli("clear trace")
709 tx = self.create_tunnel_stream_l2o4(self.pg0,
712 self.pg0.add_stream(tx)
714 self.pg_enable_capture(self.pg_interfaces)
717 rx = self.pg0.get_capture(len(tx))
718 self.verify_tunneled_l2o4(self.pg0, rx, tx,
722 self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
725 self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
730 # Create a VLAN sub-interfaces on the GRE TEB interfaces
731 # then x-connect them
733 gre_if_11 = VppDot1QSubint(self, gre_if1, 11)
734 gre_if_12 = VppDot1QSubint(self, gre_if2, 12)
736 # gre_if_11.add_vpp_config()
737 # gre_if_12.add_vpp_config()
742 self.vapi.sw_interface_set_l2_xconnect(gre_if_11.sw_if_index,
743 gre_if_12.sw_if_index,
745 self.vapi.sw_interface_set_l2_xconnect(gre_if_12.sw_if_index,
746 gre_if_11.sw_if_index,
750 # Configure both to pop thier respective VLAN tags,
751 # so that during the x-coonect they will subsequently push
753 self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_12.sw_if_index,
756 self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_11.sw_if_index,
761 # Send traffic in both directiond - expect the VLAN tags to
764 self.vapi.cli("clear trace")
765 tx = self.create_tunnel_stream_vlano4(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_vlano4(self.pg0, rx, tx,
780 self.vapi.cli("clear trace")
781 tx = self.create_tunnel_stream_vlano4(self.pg0,
785 self.pg0.add_stream(tx)
787 self.pg_enable_capture(self.pg_interfaces)
790 rx = self.pg0.get_capture(len(tx))
791 self.verify_tunneled_vlano4(self.pg0, rx, tx,
797 # Cleanup Test resources
799 gre_if_11.remove_vpp_config()
800 gre_if_12.remove_vpp_config()
801 gre_if1.remove_vpp_config()
802 gre_if2.remove_vpp_config()
803 route_tun1_dst.add_vpp_config()
804 route_tun2_dst.add_vpp_config()
807 if __name__ == '__main__':
808 unittest.main(testRunner=VppTestRunner)