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 """
511 # Create an L3 GRE tunnel.
513 # - assign an IP Address
514 # - Add a route via the tunnel
516 gre_if = VppGre6Interface(self,
519 gre_if.add_vpp_config()
523 route_via_tun = VppIpRoute(
524 self, "4004::1", 128,
525 [VppRoutePath("0::0",
527 proto=DpoProto.DPO_PROTO_IP6)],
530 route_via_tun.add_vpp_config()
533 # Send a packet stream that is routed into the tunnel
534 # - they are all dropped since the tunnel's desintation IP
535 # is unresolved - or resolves via the default route - which
538 tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
539 self.pg2.add_stream(tx)
541 self.pg_enable_capture(self.pg_interfaces)
544 self.pg2.assert_nothing_captured(
545 remark="GRE packets forwarded without DIP resolved")
548 # Add a route that resolves the tunnel's destination
550 route_tun_dst = VppIpRoute(
551 self, "1002::1", 128,
552 [VppRoutePath(self.pg2.remote_ip6,
553 self.pg2.sw_if_index,
554 proto=DpoProto.DPO_PROTO_IP6)],
556 route_tun_dst.add_vpp_config()
559 # Send a packet stream that is routed into the tunnel
560 # - packets are GRE encapped
562 self.vapi.cli("clear trace")
563 tx = self.create_stream_ip6(self.pg2, "5005::1", "4004::1")
564 self.pg2.add_stream(tx)
566 self.pg_enable_capture(self.pg_interfaces)
569 rx = self.pg2.get_capture(len(tx))
570 self.verify_tunneled_6o6(self.pg2, rx, tx,
571 self.pg2.local_ip6, "1002::1")
576 route_tun_dst.remove_vpp_config()
577 route_via_tun.remove_vpp_config()
578 gre_if.remove_vpp_config()
580 self.pg2.unconfig_ip6()
582 def test_gre_vrf(self):
583 """ GRE tunnel VRF Tests """
586 # Create an L3 GRE tunnel whose destination is in the non-default
587 # table. The underlay is thus non-default - the overlay is still
590 # - assign an IP Addres
592 gre_if = VppGreInterface(self, self.pg1.local_ip4,
595 gre_if.add_vpp_config()
600 # Add a route via the tunnel - in the overlay
602 route_via_tun = VppIpRoute(self, "9.9.9.9", 32,
603 [VppRoutePath("0.0.0.0",
604 gre_if.sw_if_index)])
605 route_via_tun.add_vpp_config()
608 # Add a route that resolves the tunnel's destination - in the
611 route_tun_dst = VppIpRoute(self, "2.2.2.2", 32, table_id=1,
612 paths=[VppRoutePath(self.pg1.remote_ip4,
613 self.pg1.sw_if_index)])
614 route_tun_dst.add_vpp_config()
617 # Send a packet stream that is routed into the tunnel
618 # packets are sent in on pg0 which is in the default table
619 # - packets are GRE encapped
621 self.vapi.cli("clear trace")
622 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "9.9.9.9")
623 self.pg0.add_stream(tx)
625 self.pg_enable_capture(self.pg_interfaces)
628 rx = self.pg1.get_capture(len(tx))
629 self.verify_tunneled_4o4(self.pg1, rx, tx,
630 self.pg1.local_ip4, "2.2.2.2")
633 # Send tunneled packets that match the created tunnel and
634 # are decapped and forwarded. This tests the decap lookup
635 # does not happen in the encap table
637 self.vapi.cli("clear trace")
638 tx = self.create_tunnel_stream_4o4(self.pg1,
643 self.pg1.add_stream(tx)
645 self.pg_enable_capture(self.pg_interfaces)
648 rx = self.pg0.get_capture(len(tx))
649 self.verify_decapped_4o4(self.pg0, rx, tx)
654 route_tun_dst.remove_vpp_config()
655 route_via_tun.remove_vpp_config()
656 gre_if.remove_vpp_config()
658 def test_gre_l2(self):
659 """ GRE tunnel L2 Tests """
662 # Add routes to resolve the tunnel destinations
664 route_tun1_dst = VppIpRoute(self, "2.2.2.2", 32,
665 [VppRoutePath(self.pg0.remote_ip4,
666 self.pg0.sw_if_index)])
667 route_tun2_dst = VppIpRoute(self, "2.2.2.3", 32,
668 [VppRoutePath(self.pg0.remote_ip4,
669 self.pg0.sw_if_index)])
671 route_tun1_dst.add_vpp_config()
672 route_tun2_dst.add_vpp_config()
675 # Create 2 L2 GRE tunnels and x-connect them
677 gre_if1 = VppGreInterface(self, self.pg0.local_ip4,
680 gre_if2 = VppGreInterface(self, self.pg0.local_ip4,
683 gre_if1.add_vpp_config()
684 gre_if2.add_vpp_config()
689 self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
692 self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
697 # Send in tunnel encapped L2. expect out tunnel encapped L2
700 self.vapi.cli("clear trace")
701 tx = self.create_tunnel_stream_l2o4(self.pg0,
704 self.pg0.add_stream(tx)
706 self.pg_enable_capture(self.pg_interfaces)
709 rx = self.pg0.get_capture(len(tx))
710 self.verify_tunneled_l2o4(self.pg0, rx, tx,
714 self.vapi.cli("clear trace")
715 tx = self.create_tunnel_stream_l2o4(self.pg0,
718 self.pg0.add_stream(tx)
720 self.pg_enable_capture(self.pg_interfaces)
723 rx = self.pg0.get_capture(len(tx))
724 self.verify_tunneled_l2o4(self.pg0, rx, tx,
728 self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
731 self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
736 # Create a VLAN sub-interfaces on the GRE TEB interfaces
737 # then x-connect them
739 gre_if_11 = VppDot1QSubint(self, gre_if1, 11)
740 gre_if_12 = VppDot1QSubint(self, gre_if2, 12)
742 # gre_if_11.add_vpp_config()
743 # gre_if_12.add_vpp_config()
748 self.vapi.sw_interface_set_l2_xconnect(gre_if_11.sw_if_index,
749 gre_if_12.sw_if_index,
751 self.vapi.sw_interface_set_l2_xconnect(gre_if_12.sw_if_index,
752 gre_if_11.sw_if_index,
756 # Configure both to pop thier respective VLAN tags,
757 # so that during the x-coonect they will subsequently push
759 self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_12.sw_if_index,
762 self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_11.sw_if_index,
767 # Send traffic in both directiond - expect the VLAN tags to
770 self.vapi.cli("clear trace")
771 tx = self.create_tunnel_stream_vlano4(self.pg0,
775 self.pg0.add_stream(tx)
777 self.pg_enable_capture(self.pg_interfaces)
780 rx = self.pg0.get_capture(len(tx))
781 self.verify_tunneled_vlano4(self.pg0, rx, tx,
786 self.vapi.cli("clear trace")
787 tx = self.create_tunnel_stream_vlano4(self.pg0,
791 self.pg0.add_stream(tx)
793 self.pg_enable_capture(self.pg_interfaces)
796 rx = self.pg0.get_capture(len(tx))
797 self.verify_tunneled_vlano4(self.pg0, rx, tx,
803 # Cleanup Test resources
805 gre_if_11.remove_vpp_config()
806 gre_if_12.remove_vpp_config()
807 gre_if1.remove_vpp_config()
808 gre_if2.remove_vpp_config()
809 route_tun1_dst.add_vpp_config()
810 route_tun2_dst.add_vpp_config()
813 if __name__ == '__main__':
814 unittest.main(testRunner=VppTestRunner)