6 from framework import VppTestCase, VppTestRunner
7 from vpp_sub_interface import VppDot1QSubint
8 from vpp_gre_interface import VppGreInterface
9 from vpp_ip_route import IpRoute, RoutePath
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 ICMPv6ND_RA, 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 2 pg interfaces - set one in a non-default table.
32 self.create_pg_interfaces(range(2))
34 self.pg1.set_table_ip4(1)
35 for i in self.pg_interfaces:
41 super(TestGRE, self).tearDown()
43 def create_stream_ip4(self, src_if, src_ip, dst_ip):
45 for i in range(0, 257):
46 info = self.create_packet_info(src_if.sw_if_index,
48 payload = self.info_to_payload(info)
49 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
50 IP(src=src_ip, dst=dst_ip) /
51 UDP(sport=1234, dport=1234) /
57 def create_tunnel_stream_4o4(self, src_if,
58 tunnel_src, tunnel_dst,
61 for i in range(0, 257):
62 info = self.create_packet_info(src_if.sw_if_index,
64 payload = self.info_to_payload(info)
65 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
66 IP(src=tunnel_src, dst=tunnel_dst) /
68 IP(src=src_ip, dst=dst_ip) /
69 UDP(sport=1234, dport=1234) /
75 def create_tunnel_stream_6o4(self, src_if,
76 tunnel_src, tunnel_dst,
79 for i in range(0, 257):
80 info = self.create_packet_info(src_if.sw_if_index,
82 payload = self.info_to_payload(info)
83 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
84 IP(src=tunnel_src, dst=tunnel_dst) /
86 IPv6(src=src_ip, dst=dst_ip) /
87 UDP(sport=1234, dport=1234) /
93 def create_tunnel_stream_l2o4(self, src_if,
94 tunnel_src, tunnel_dst):
96 for i in range(0, 257):
97 info = self.create_packet_info(src_if.sw_if_index,
99 payload = self.info_to_payload(info)
100 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
101 IP(src=tunnel_src, dst=tunnel_dst) /
103 Ether(dst=RandMAC('*:*:*:*:*:*'),
104 src=RandMAC('*:*:*:*:*:*')) /
105 IP(src=str(RandIP()), dst=str(RandIP())) /
106 UDP(sport=1234, dport=1234) /
112 def create_tunnel_stream_vlano4(self, src_if,
113 tunnel_src, tunnel_dst, vlan):
115 for i in range(0, 257):
116 info = self.create_packet_info(src_if.sw_if_index,
118 payload = self.info_to_payload(info)
119 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
120 IP(src=tunnel_src, dst=tunnel_dst) /
122 Ether(dst=RandMAC('*:*:*:*:*:*'),
123 src=RandMAC('*:*:*:*:*:*')) /
125 IP(src=str(RandIP()), dst=str(RandIP())) /
126 UDP(sport=1234, dport=1234) /
132 def verify_filter(self, capture, sent):
133 if not len(capture) == len(sent):
134 # filter out any IPv6 RAs from the capture
136 if (p.haslayer(ICMPv6ND_RA)):
140 def verify_tunneled_4o4(self, src_if, capture, sent,
141 tunnel_src, tunnel_dst):
143 capture = self.verify_filter(capture, sent)
144 self.assertEqual(len(capture), len(sent))
146 for i in range(len(capture)):
154 self.assertEqual(rx_ip.src, tunnel_src)
155 self.assertEqual(rx_ip.dst, tunnel_dst)
160 self.assertEqual(rx_ip.src, tx_ip.src)
161 self.assertEqual(rx_ip.dst, tx_ip.dst)
162 # IP processing post pop has decremented the TTL
163 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
166 self.logger.error(ppp("Rx:", rx))
167 self.logger.error(ppp("Tx:", tx))
170 def verify_tunneled_l2o4(self, src_if, capture, sent,
171 tunnel_src, tunnel_dst):
172 capture = self.verify_filter(capture, sent)
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)
187 rx_l2 = rx_gre[Ether]
190 tx_l2 = tx_gre[Ether]
193 self.assertEqual(rx_ip.src, tx_ip.src)
194 self.assertEqual(rx_ip.dst, tx_ip.dst)
195 # bridged, not L3 forwarded, so no TTL decrement
196 self.assertEqual(rx_ip.ttl, tx_ip.ttl)
199 self.logger.error(ppp("Rx:", rx))
200 self.logger.error(ppp("Tx:", tx))
203 def verify_tunneled_vlano4(self, src_if, capture, sent,
204 tunnel_src, tunnel_dst, vlan):
206 capture = self.verify_filter(capture, sent)
207 self.assertEqual(len(capture), len(sent))
209 ppc("Unexpected packets captured:", capture)
212 for i in range(len(capture)):
220 self.assertEqual(rx_ip.src, tunnel_src)
221 self.assertEqual(rx_ip.dst, tunnel_dst)
224 rx_l2 = rx_gre[Ether]
225 rx_vlan = rx_l2[Dot1Q]
228 self.assertEqual(rx_vlan.vlan, vlan)
231 tx_l2 = tx_gre[Ether]
234 self.assertEqual(rx_ip.src, tx_ip.src)
235 self.assertEqual(rx_ip.dst, tx_ip.dst)
236 # bridged, not L3 forwarded, so no TTL decrement
237 self.assertEqual(rx_ip.ttl, tx_ip.ttl)
240 self.logger.error(ppp("Rx:", rx))
241 self.logger.error(ppp("Tx:", tx))
244 def verify_decapped_4o4(self, src_if, capture, sent):
245 capture = self.verify_filter(capture, sent)
246 self.assertEqual(len(capture), len(sent))
248 for i in range(len(capture)):
258 self.assertEqual(rx_ip.src, tx_ip.src)
259 self.assertEqual(rx_ip.dst, tx_ip.dst)
260 # IP processing post pop has decremented the TTL
261 self.assertEqual(rx_ip.ttl + 1, tx_ip.ttl)
264 self.logger.error(ppp("Rx:", rx))
265 self.logger.error(ppp("Tx:", tx))
268 def verify_decapped_6o4(self, src_if, capture, sent):
269 capture = self.verify_filter(capture, sent)
270 self.assertEqual(len(capture), len(sent))
272 for i in range(len(capture)):
282 self.assertEqual(rx_ip.src, tx_ip.src)
283 self.assertEqual(rx_ip.dst, tx_ip.dst)
284 self.assertEqual(rx_ip.hlim + 1, tx_ip.hlim)
287 self.logger.error(ppp("Rx:", rx))
288 self.logger.error(ppp("Tx:", tx))
292 """ GRE tunnel Tests """
295 # Create an L3 GRE tunnel.
297 # - assign an IP Addres
298 # - Add a route via the tunnel
300 gre_if = VppGreInterface(self,
303 gre_if.add_vpp_config()
306 # The double create (create the same tunnel twice) should fail,
307 # and we should still be able to use the original
310 gre_if.add_vpp_config()
314 self.fail("Double GRE tunnel add does not fail")
319 route_via_tun = IpRoute(self, "4.4.4.4", 32,
320 [RoutePath("0.0.0.0", gre_if.sw_if_index)])
322 route_via_tun.add_vpp_config()
325 # Send a packet stream that is routed into the tunnel
326 # - they are all dropped since the tunnel's desintation IP
327 # is unresolved - or resolves via the default route - which
330 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
331 self.pg0.add_stream(tx)
333 self.pg_enable_capture(self.pg_interfaces)
336 self.pg0.assert_nothing_captured(
337 remark="GRE packets forwarded without DIP resolved")
340 # Add a route that resolves the tunnel's destination
342 route_tun_dst = IpRoute(self, "1.1.1.2", 32,
343 [RoutePath(self.pg0.remote_ip4,
344 self.pg0.sw_if_index)])
345 route_tun_dst.add_vpp_config()
348 # Send a packet stream that is routed into the tunnel
349 # - packets are GRE encapped
351 self.vapi.cli("clear trace")
352 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
353 self.pg0.add_stream(tx)
355 self.pg_enable_capture(self.pg_interfaces)
358 rx = self.pg0.get_capture()
359 self.verify_tunneled_4o4(self.pg0, rx, tx,
360 self.pg0.local_ip4, "1.1.1.2")
363 # Send tunneled packets that match the created tunnel and
364 # are decapped and forwarded
366 self.vapi.cli("clear trace")
367 tx = self.create_tunnel_stream_4o4(self.pg0,
372 self.pg0.add_stream(tx)
374 self.pg_enable_capture(self.pg_interfaces)
377 rx = self.pg0.get_capture()
378 self.verify_decapped_4o4(self.pg0, rx, tx)
381 # Send tunneled packets that do not match the tunnel's src
383 self.vapi.cli("clear trace")
384 tx = self.create_tunnel_stream_4o4(self.pg0,
389 self.pg0.add_stream(tx)
391 self.pg_enable_capture(self.pg_interfaces)
394 self.pg0.assert_nothing_captured(
395 remark="GRE packets forwarded despite no SRC address match")
398 # Configure IPv6 on the PG interface so we can route IPv6
401 self.pg0.config_ip6()
402 self.pg0.resolve_ndp()
405 # Send IPv6 tunnel encapslated packets
406 # - dropped since IPv6 is not enabled on the tunnel
408 self.vapi.cli("clear trace")
409 tx = self.create_tunnel_stream_6o4(self.pg0,
414 self.pg0.add_stream(tx)
416 self.pg_enable_capture(self.pg_interfaces)
419 self.pg0.assert_nothing_captured(remark="IPv6 GRE packets forwarded "
420 "despite IPv6 not enabled on tunnel")
423 # Enable IPv6 on the tunnel
428 # Send IPv6 tunnel encapslated packets
429 # - forwarded since IPv6 is enabled on the tunnel
431 self.vapi.cli("clear trace")
432 tx = self.create_tunnel_stream_6o4(self.pg0,
437 self.pg0.add_stream(tx)
439 self.pg_enable_capture(self.pg_interfaces)
442 rx = self.pg0.get_capture()
443 self.verify_decapped_6o4(self.pg0, rx, tx)
448 route_tun_dst.remove_vpp_config()
449 route_via_tun.remove_vpp_config()
450 gre_if.remove_vpp_config()
452 self.pg0.unconfig_ip6()
454 def test_gre_vrf(self):
455 """ GRE tunnel VRF Tests """
458 # Create an L3 GRE tunnel whose destination is in the non-default
459 # table. The underlay is thus non-default - the overlay is still
462 # - assign an IP Addres
464 gre_if = VppGreInterface(self, self.pg1.local_ip4,
467 gre_if.add_vpp_config()
472 # Add a route via the tunnel - in the overlay
474 route_via_tun = IpRoute(self, "9.9.9.9", 32,
475 [RoutePath("0.0.0.0", gre_if.sw_if_index)])
476 route_via_tun.add_vpp_config()
479 # Add a route that resolves the tunnel's destination - in the
482 route_tun_dst = IpRoute(self, "2.2.2.2", 32, table_id=1,
483 paths=[RoutePath(self.pg1.remote_ip4,
484 self.pg1.sw_if_index)])
485 route_tun_dst.add_vpp_config()
488 # Send a packet stream that is routed into the tunnel
489 # packets are sent in on pg0 which is in the default table
490 # - packets are GRE encapped
492 self.vapi.cli("clear trace")
493 tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "9.9.9.9")
494 self.pg0.add_stream(tx)
496 self.pg_enable_capture(self.pg_interfaces)
499 rx = self.pg1.get_capture()
500 self.verify_tunneled_4o4(self.pg1, rx, tx,
501 self.pg1.local_ip4, "2.2.2.2")
504 # Send tunneled packets that match the created tunnel and
505 # are decapped and forwarded. This tests the decap lookup
506 # does not happen in the encap table
508 self.vapi.cli("clear trace")
509 tx = self.create_tunnel_stream_4o4(self.pg1,
514 self.pg1.add_stream(tx)
516 self.pg_enable_capture(self.pg_interfaces)
519 rx = self.pg0.get_capture()
520 self.verify_decapped_4o4(self.pg0, rx, tx)
525 route_tun_dst.remove_vpp_config()
526 route_via_tun.remove_vpp_config()
527 gre_if.remove_vpp_config()
529 def test_gre_l2(self):
530 """ GRE tunnel L2 Tests """
533 # Add routes to resolve the tunnel destinations
535 route_tun1_dst = IpRoute(self, "2.2.2.2", 32,
536 [RoutePath(self.pg0.remote_ip4,
537 self.pg0.sw_if_index)])
538 route_tun2_dst = IpRoute(self, "2.2.2.3", 32,
539 [RoutePath(self.pg0.remote_ip4,
540 self.pg0.sw_if_index)])
542 route_tun1_dst.add_vpp_config()
543 route_tun2_dst.add_vpp_config()
546 # Create 2 L2 GRE tunnels and x-connect them
548 gre_if1 = VppGreInterface(self, self.pg0.local_ip4,
551 gre_if2 = VppGreInterface(self, self.pg0.local_ip4,
554 gre_if1.add_vpp_config()
555 gre_if2.add_vpp_config()
560 self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
563 self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
568 # Send in tunnel encapped L2. expect out tunnel encapped L2
571 self.vapi.cli("clear trace")
572 tx = self.create_tunnel_stream_l2o4(self.pg0,
575 self.pg0.add_stream(tx)
577 self.pg_enable_capture(self.pg_interfaces)
580 rx = self.pg0.get_capture()
581 self.verify_tunneled_l2o4(self.pg0, rx, tx,
585 self.vapi.cli("clear trace")
586 tx = self.create_tunnel_stream_l2o4(self.pg0,
589 self.pg0.add_stream(tx)
591 self.pg_enable_capture(self.pg_interfaces)
594 rx = self.pg0.get_capture()
595 self.verify_tunneled_l2o4(self.pg0, rx, tx,
599 self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
602 self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
607 # Create a VLAN sub-interfaces on the GRE TEB interfaces
608 # then x-connect them
610 gre_if_11 = VppDot1QSubint(self, gre_if1, 11)
611 gre_if_12 = VppDot1QSubint(self, gre_if2, 12)
613 # gre_if_11.add_vpp_config()
614 # gre_if_12.add_vpp_config()
619 self.vapi.sw_interface_set_l2_xconnect(gre_if_11.sw_if_index,
620 gre_if_12.sw_if_index,
622 self.vapi.sw_interface_set_l2_xconnect(gre_if_12.sw_if_index,
623 gre_if_11.sw_if_index,
627 # Configure both to pop thier respective VLAN tags,
628 # so that during the x-coonect they will subsequently push
630 self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_12.sw_if_index,
633 self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_11.sw_if_index,
638 # Send traffic in both directiond - expect the VLAN tags to
641 self.vapi.cli("clear trace")
642 tx = self.create_tunnel_stream_vlano4(self.pg0,
646 self.pg0.add_stream(tx)
648 self.pg_enable_capture(self.pg_interfaces)
651 rx = self.pg0.get_capture()
652 self.verify_tunneled_vlano4(self.pg0, rx, tx,
657 self.vapi.cli("clear trace")
658 tx = self.create_tunnel_stream_vlano4(self.pg0,
662 self.pg0.add_stream(tx)
664 self.pg_enable_capture(self.pg_interfaces)
667 rx = self.pg0.get_capture()
668 self.verify_tunneled_vlano4(self.pg0, rx, tx,
674 # Cleanup Test resources
676 gre_if_11.remove_vpp_config()
677 gre_if_12.remove_vpp_config()
678 gre_if1.remove_vpp_config()
679 gre_if2.remove_vpp_config()
680 route_tun1_dst.add_vpp_config()
681 route_tun2_dst.add_vpp_config()
684 if __name__ == '__main__':
685 unittest.main(testRunner=VppTestRunner)