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, VppIpTable
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))
34 self.tbl = VppIpTable(self, 1)
35 self.tbl.add_vpp_config()
36 self.pg1.set_table_ip4(1)
38 for i in self.pg_interfaces:
42 self.pg0.resolve_arp()
44 self.pg1.resolve_arp()
46 self.pg2.resolve_ndp()
49 for i in self.pg_interfaces:
53 self.pg1.set_table_ip4(0)
54 super(TestGRE, self).tearDown()
56 def create_stream_ip4(self, src_if, src_ip, dst_ip):
58 for i in range(0, 257):
59 info = self.create_packet_info(src_if, src_if)
60 payload = self.info_to_payload(info)
61 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
62 IP(src=src_ip, dst=dst_ip) /
63 UDP(sport=1234, dport=1234) /
69 def create_stream_ip6(self, src_if, src_ip, dst_ip):
71 for i in range(0, 257):
72 info = self.create_packet_info(src_if, src_if)
73 payload = self.info_to_payload(info)
74 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
75 IPv6(src=src_ip, dst=dst_ip) /
76 UDP(sport=1234, dport=1234) /
82 def create_tunnel_stream_4o4(self, src_if,
83 tunnel_src, tunnel_dst,
86 for i in range(0, 257):
87 info = self.create_packet_info(src_if, src_if)
88 payload = self.info_to_payload(info)
89 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
90 IP(src=tunnel_src, dst=tunnel_dst) /
92 IP(src=src_ip, dst=dst_ip) /
93 UDP(sport=1234, dport=1234) /
99 def create_tunnel_stream_6o4(self, src_if,
100 tunnel_src, tunnel_dst,
103 for i in range(0, 257):
104 info = self.create_packet_info(src_if, src_if)
105 payload = self.info_to_payload(info)
106 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
107 IP(src=tunnel_src, dst=tunnel_dst) /
109 IPv6(src=src_ip, dst=dst_ip) /
110 UDP(sport=1234, dport=1234) /
116 def create_tunnel_stream_6o6(self, src_if,
117 tunnel_src, tunnel_dst,
120 for i in range(0, 257):
121 info = self.create_packet_info(src_if, src_if)
122 payload = self.info_to_payload(info)
123 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
124 IPv6(src=tunnel_src, dst=tunnel_dst) /
126 IPv6(src=src_ip, dst=dst_ip) /
127 UDP(sport=1234, dport=1234) /
133 def create_tunnel_stream_l2o4(self, src_if,
134 tunnel_src, tunnel_dst):
136 for i in range(0, 257):
137 info = self.create_packet_info(src_if, src_if)
138 payload = self.info_to_payload(info)
139 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
140 IP(src=tunnel_src, dst=tunnel_dst) /
142 Ether(dst=RandMAC('*:*:*:*:*:*'),
143 src=RandMAC('*:*:*:*:*:*')) /
144 IP(src=str(RandIP()), dst=str(RandIP())) /
145 UDP(sport=1234, dport=1234) /
151 def create_tunnel_stream_vlano4(self, src_if,
152 tunnel_src, tunnel_dst, vlan):
154 for i in range(0, 257):
155 info = self.create_packet_info(src_if, src_if)
156 payload = self.info_to_payload(info)
157 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
158 IP(src=tunnel_src, dst=tunnel_dst) /
160 Ether(dst=RandMAC('*:*:*:*:*:*'),
161 src=RandMAC('*:*:*:*:*:*')) /
163 IP(src=str(RandIP()), dst=str(RandIP())) /
164 UDP(sport=1234, dport=1234) /
170 def verify_tunneled_4o4(self, src_if, capture, sent,
171 tunnel_src, tunnel_dst):
173 self.assertEqual(len(capture), len(sent))
175 for i in range(len(capture)):
183 self.assertEqual(rx_ip.src, tunnel_src)
184 self.assertEqual(rx_ip.dst, tunnel_dst)
189 self.assertEqual(rx_ip.src, tx_ip.src)
190 self.assertEqual(rx_ip.dst, tx_ip.dst)
191 # IP processing post pop has decremented the TTL
192 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
195 self.logger.error(ppp("Rx:", rx))
196 self.logger.error(ppp("Tx:", tx))
199 def verify_tunneled_6o6(self, src_if, capture, sent,
200 tunnel_src, tunnel_dst):
202 self.assertEqual(len(capture), len(sent))
204 for i in range(len(capture)):
212 self.assertEqual(rx_ip.src, tunnel_src)
213 self.assertEqual(rx_ip.dst, tunnel_dst)
215 rx_gre = GRE(str(rx_ip[IPv6].payload))
218 self.assertEqual(rx_ip.src, tx_ip.src)
219 self.assertEqual(rx_ip.dst, tx_ip.dst)
222 self.logger.error(ppp("Rx:", rx))
223 self.logger.error(ppp("Tx:", tx))
226 def verify_tunneled_l2o4(self, src_if, capture, sent,
227 tunnel_src, tunnel_dst):
228 self.assertEqual(len(capture), len(sent))
230 for i in range(len(capture)):
238 self.assertEqual(rx_ip.src, tunnel_src)
239 self.assertEqual(rx_ip.dst, tunnel_dst)
242 rx_l2 = rx_gre[Ether]
245 tx_l2 = tx_gre[Ether]
248 self.assertEqual(rx_ip.src, tx_ip.src)
249 self.assertEqual(rx_ip.dst, tx_ip.dst)
250 # bridged, not L3 forwarded, so no TTL decrement
251 self.assertEqual(rx_ip.ttl, tx_ip.ttl)
254 self.logger.error(ppp("Rx:", rx))
255 self.logger.error(ppp("Tx:", tx))
258 def verify_tunneled_vlano4(self, src_if, capture, sent,
259 tunnel_src, tunnel_dst, vlan):
261 self.assertEqual(len(capture), len(sent))
263 ppc("Unexpected packets captured:", capture)
266 for i in range(len(capture)):
274 self.assertEqual(rx_ip.src, tunnel_src)
275 self.assertEqual(rx_ip.dst, tunnel_dst)
278 rx_l2 = rx_gre[Ether]
279 rx_vlan = rx_l2[Dot1Q]
282 self.assertEqual(rx_vlan.vlan, vlan)
285 tx_l2 = tx_gre[Ether]
288 self.assertEqual(rx_ip.src, tx_ip.src)
289 self.assertEqual(rx_ip.dst, tx_ip.dst)
290 # bridged, not L3 forwarded, so no TTL decrement
291 self.assertEqual(rx_ip.ttl, tx_ip.ttl)
294 self.logger.error(ppp("Rx:", rx))
295 self.logger.error(ppp("Tx:", tx))
298 def verify_decapped_4o4(self, src_if, capture, sent):
299 self.assertEqual(len(capture), len(sent))
301 for i in range(len(capture)):
311 self.assertEqual(rx_ip.src, tx_ip.src)
312 self.assertEqual(rx_ip.dst, tx_ip.dst)
313 # IP processing post pop has decremented the TTL
314 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
317 self.logger.error(ppp("Rx:", rx))
318 self.logger.error(ppp("Tx:", tx))
321 def verify_decapped_6o4(self, src_if, capture, sent):
322 self.assertEqual(len(capture), len(sent))
324 for i in range(len(capture)):
334 self.assertEqual(rx_ip.src, tx_ip.src)
335 self.assertEqual(rx_ip.dst, tx_ip.dst)
336 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
339 self.logger.error(ppp("Rx:", rx))
340 self.logger.error(ppp("Tx:", tx))
344 """ GRE IPv4 tunnel Tests """
347 # Create an L3 GRE tunnel.
349 # - assign an IP Addres
350 # - Add a route via the tunnel
352 gre_if = VppGreInterface(self,
355 gre_if.add_vpp_config()
358 # The double create (create the same tunnel twice) should fail,
359 # and we should still be able to use the original
362 gre_if.add_vpp_config()
366 self.fail("Double GRE tunnel add does not fail")
371 route_via_tun = VppIpRoute(self, "4.4.4.4", 32,
372 [VppRoutePath("0.0.0.0",
373 gre_if.sw_if_index)])
375 route_via_tun.add_vpp_config()
378 # Send a packet stream that is routed into the tunnel
379 # - they are all dropped since the tunnel's desintation IP
380 # is unresolved - or resolves via the default route - which
383 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
384 self.pg0.add_stream(tx)
386 self.pg_enable_capture(self.pg_interfaces)
389 self.pg0.assert_nothing_captured(
390 remark="GRE packets forwarded without DIP resolved")
393 # Add a route that resolves the tunnel's destination
395 route_tun_dst = VppIpRoute(self, "1.1.1.2", 32,
396 [VppRoutePath(self.pg0.remote_ip4,
397 self.pg0.sw_if_index)])
398 route_tun_dst.add_vpp_config()
401 # Send a packet stream that is routed into the tunnel
402 # - packets are GRE encapped
404 self.vapi.cli("clear trace")
405 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
406 self.pg0.add_stream(tx)
408 self.pg_enable_capture(self.pg_interfaces)
411 rx = self.pg0.get_capture(len(tx))
412 self.verify_tunneled_4o4(self.pg0, rx, tx,
413 self.pg0.local_ip4, "1.1.1.2")
416 # Send tunneled packets that match the created tunnel and
417 # are decapped and forwarded
419 self.vapi.cli("clear trace")
420 tx = self.create_tunnel_stream_4o4(self.pg0,
425 self.pg0.add_stream(tx)
427 self.pg_enable_capture(self.pg_interfaces)
430 rx = self.pg0.get_capture(len(tx))
431 self.verify_decapped_4o4(self.pg0, rx, tx)
434 # Send tunneled packets that do not match the tunnel's src
436 self.vapi.cli("clear trace")
437 tx = self.create_tunnel_stream_4o4(self.pg0,
442 self.pg0.add_stream(tx)
444 self.pg_enable_capture(self.pg_interfaces)
447 self.pg0.assert_nothing_captured(
448 remark="GRE packets forwarded despite no SRC address match")
451 # Configure IPv6 on the PG interface so we can route IPv6
454 self.pg0.config_ip6()
455 self.pg0.resolve_ndp()
458 # Send IPv6 tunnel encapslated packets
459 # - dropped since IPv6 is not enabled on the tunnel
461 self.vapi.cli("clear trace")
462 tx = self.create_tunnel_stream_6o4(self.pg0,
467 self.pg0.add_stream(tx)
469 self.pg_enable_capture(self.pg_interfaces)
472 self.pg0.assert_nothing_captured(remark="IPv6 GRE packets forwarded "
473 "despite IPv6 not enabled on tunnel")
476 # Enable IPv6 on the tunnel
481 # Send IPv6 tunnel encapslated packets
482 # - forwarded since IPv6 is enabled on the tunnel
484 self.vapi.cli("clear trace")
485 tx = self.create_tunnel_stream_6o4(self.pg0,
490 self.pg0.add_stream(tx)
492 self.pg_enable_capture(self.pg_interfaces)
495 rx = self.pg0.get_capture(len(tx))
496 self.verify_decapped_6o4(self.pg0, rx, tx)
501 route_tun_dst.remove_vpp_config()
502 route_via_tun.remove_vpp_config()
503 gre_if.remove_vpp_config()
505 self.pg0.unconfig_ip6()
508 """ GRE IPv6 tunnel Tests """
510 self.pg1.config_ip6()
511 self.pg1.resolve_ndp()
514 # Create an L3 GRE tunnel.
516 # - assign an IP Address
517 # - Add a route via the tunnel
519 gre_if = VppGre6Interface(self,
522 gre_if.add_vpp_config()
526 route_via_tun = VppIpRoute(
527 self, "4004::1", 128,
528 [VppRoutePath("0::0",
530 proto=DpoProto.DPO_PROTO_IP6)],
533 route_via_tun.add_vpp_config()
536 # Send a packet stream that is routed into the tunnel
537 # - they are all dropped since the tunnel's desintation IP
538 # is unresolved - or resolves via the default route - which
541 tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
542 self.pg2.add_stream(tx)
544 self.pg_enable_capture(self.pg_interfaces)
547 self.pg2.assert_nothing_captured(
548 remark="GRE packets forwarded without DIP resolved")
551 # Add a route that resolves the tunnel's destination
553 route_tun_dst = VppIpRoute(
554 self, "1002::1", 128,
555 [VppRoutePath(self.pg2.remote_ip6,
556 self.pg2.sw_if_index,
557 proto=DpoProto.DPO_PROTO_IP6)],
559 route_tun_dst.add_vpp_config()
562 # Send a packet stream that is routed into the tunnel
563 # - packets are GRE encapped
565 self.vapi.cli("clear trace")
566 tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
567 self.pg2.add_stream(tx)
569 self.pg_enable_capture(self.pg_interfaces)
572 rx = self.pg2.get_capture(len(tx))
573 self.verify_tunneled_6o6(self.pg2, rx, tx,
574 self.pg2.local_ip6, "1002::1")
577 # Test decap. decapped packets go out pg1
579 tx = self.create_tunnel_stream_6o6(self.pg2,
584 self.vapi.cli("clear trace")
585 self.pg2.add_stream(tx)
587 self.pg_enable_capture(self.pg_interfaces)
589 rx = self.pg1.get_capture(len(tx))
592 # RX'd packet is UDP over IPv6, test the GRE header is gone.
594 self.assertFalse(rx[0].haslayer(GRE))
595 self.assertEqual(rx[0][IPv6].dst, self.pg1.remote_ip6)
600 route_tun_dst.remove_vpp_config()
601 route_via_tun.remove_vpp_config()
602 gre_if.remove_vpp_config()
604 self.pg2.unconfig_ip6()
605 self.pg1.unconfig_ip6()
607 def test_gre_vrf(self):
608 """ GRE tunnel VRF Tests """
611 # Create an L3 GRE tunnel whose destination is in the non-default
612 # table. The underlay is thus non-default - the overlay is still
615 # - assign an IP Addres
617 gre_if = VppGreInterface(self, self.pg1.local_ip4,
620 gre_if.add_vpp_config()
625 # Add a route via the tunnel - in the overlay
627 route_via_tun = VppIpRoute(self, "9.9.9.9", 32,
628 [VppRoutePath("0.0.0.0",
629 gre_if.sw_if_index)])
630 route_via_tun.add_vpp_config()
633 # Add a route that resolves the tunnel's destination - in the
636 route_tun_dst = VppIpRoute(self, "2.2.2.2", 32, table_id=1,
637 paths=[VppRoutePath(self.pg1.remote_ip4,
638 self.pg1.sw_if_index)])
639 route_tun_dst.add_vpp_config()
642 # Send a packet stream that is routed into the tunnel
643 # packets are sent in on pg0 which is in the default table
644 # - packets are GRE encapped
646 self.vapi.cli("clear trace")
647 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "9.9.9.9")
648 self.pg0.add_stream(tx)
650 self.pg_enable_capture(self.pg_interfaces)
653 rx = self.pg1.get_capture(len(tx))
654 self.verify_tunneled_4o4(self.pg1, rx, tx,
655 self.pg1.local_ip4, "2.2.2.2")
658 # Send tunneled packets that match the created tunnel and
659 # are decapped and forwarded. This tests the decap lookup
660 # does not happen in the encap table
662 self.vapi.cli("clear trace")
663 tx = self.create_tunnel_stream_4o4(self.pg1,
668 self.pg1.add_stream(tx)
670 self.pg_enable_capture(self.pg_interfaces)
673 rx = self.pg0.get_capture(len(tx))
674 self.verify_decapped_4o4(self.pg0, rx, tx)
679 route_tun_dst.remove_vpp_config()
680 route_via_tun.remove_vpp_config()
681 gre_if.remove_vpp_config()
683 def test_gre_l2(self):
684 """ GRE tunnel L2 Tests """
687 # Add routes to resolve the tunnel destinations
689 route_tun1_dst = VppIpRoute(self, "2.2.2.2", 32,
690 [VppRoutePath(self.pg0.remote_ip4,
691 self.pg0.sw_if_index)])
692 route_tun2_dst = VppIpRoute(self, "2.2.2.3", 32,
693 [VppRoutePath(self.pg0.remote_ip4,
694 self.pg0.sw_if_index)])
696 route_tun1_dst.add_vpp_config()
697 route_tun2_dst.add_vpp_config()
700 # Create 2 L2 GRE tunnels and x-connect them
702 gre_if1 = VppGreInterface(self, self.pg0.local_ip4,
705 gre_if2 = VppGreInterface(self, self.pg0.local_ip4,
708 gre_if1.add_vpp_config()
709 gre_if2.add_vpp_config()
714 self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
717 self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
722 # Send in tunnel encapped L2. expect out tunnel encapped L2
725 self.vapi.cli("clear trace")
726 tx = self.create_tunnel_stream_l2o4(self.pg0,
729 self.pg0.add_stream(tx)
731 self.pg_enable_capture(self.pg_interfaces)
734 rx = self.pg0.get_capture(len(tx))
735 self.verify_tunneled_l2o4(self.pg0, rx, tx,
739 self.vapi.cli("clear trace")
740 tx = self.create_tunnel_stream_l2o4(self.pg0,
743 self.pg0.add_stream(tx)
745 self.pg_enable_capture(self.pg_interfaces)
748 rx = self.pg0.get_capture(len(tx))
749 self.verify_tunneled_l2o4(self.pg0, rx, tx,
753 self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
756 self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
761 # Create a VLAN sub-interfaces on the GRE TEB interfaces
762 # then x-connect them
764 gre_if_11 = VppDot1QSubint(self, gre_if1, 11)
765 gre_if_12 = VppDot1QSubint(self, gre_if2, 12)
767 # gre_if_11.add_vpp_config()
768 # gre_if_12.add_vpp_config()
773 self.vapi.sw_interface_set_l2_xconnect(gre_if_11.sw_if_index,
774 gre_if_12.sw_if_index,
776 self.vapi.sw_interface_set_l2_xconnect(gre_if_12.sw_if_index,
777 gre_if_11.sw_if_index,
781 # Configure both to pop thier respective VLAN tags,
782 # so that during the x-coonect they will subsequently push
784 self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_12.sw_if_index,
787 self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_11.sw_if_index,
792 # Send traffic in both directiond - expect the VLAN tags to
795 self.vapi.cli("clear trace")
796 tx = self.create_tunnel_stream_vlano4(self.pg0,
800 self.pg0.add_stream(tx)
802 self.pg_enable_capture(self.pg_interfaces)
805 rx = self.pg0.get_capture(len(tx))
806 self.verify_tunneled_vlano4(self.pg0, rx, tx,
811 self.vapi.cli("clear trace")
812 tx = self.create_tunnel_stream_vlano4(self.pg0,
816 self.pg0.add_stream(tx)
818 self.pg_enable_capture(self.pg_interfaces)
821 rx = self.pg0.get_capture(len(tx))
822 self.verify_tunneled_vlano4(self.pg0, rx, tx,
828 # Cleanup Test resources
830 gre_if_11.remove_vpp_config()
831 gre_if_12.remove_vpp_config()
832 gre_if1.remove_vpp_config()
833 gre_if2.remove_vpp_config()
834 route_tun1_dst.add_vpp_config()
835 route_tun2_dst.add_vpp_config()
838 if __name__ == '__main__':
839 unittest.main(testRunner=VppTestRunner)