MPLS infrastructure improvments
[vpp.git] / test / test_gre.py
1 #!/usr/bin/env python
2
3 import unittest
4 import socket
5 from logging import *
6
7 from framework import VppTestCase, VppTestRunner
8 from vpp_sub_interface import VppSubInterface, VppDot1QSubint, VppDot1ADSubint
9 from vpp_gre_interface import VppGreInterface
10 from vpp_ip_route import IpRoute, RoutePath
11 from vpp_papi_provider import L2_VTR_OP
12
13 from scapy.packet import Raw
14 from scapy.layers.l2 import Ether, Dot1Q, ARP, GRE
15 from scapy.layers.inet import IP, UDP
16 from scapy.layers.inet6 import ICMPv6ND_NS, ICMPv6ND_RA, IPv6, UDP
17 from scapy.contrib.mpls import MPLS
18 from scapy.volatile import RandMAC, RandIP
19
20
21 class TestGRE(VppTestCase):
22     """ GRE Test Case """
23
24     @classmethod
25     def setUpClass(cls):
26         super(TestGRE, cls).setUpClass()
27
28     def setUp(self):
29         super(TestGRE, self).setUp()
30
31         # create 2 pg interfaces - set one in a non-default table.
32         self.create_pg_interfaces(range(2))
33
34         self.pg1.set_table_ip4(1)
35         for i in self.pg_interfaces:
36             i.admin_up()
37             i.config_ip4()
38             i.resolve_arp()
39
40     def tearDown(self):
41         super(TestGRE, self).tearDown()
42
43     def create_stream_ip4(self, src_if, src_ip, dst_ip):
44         pkts = []
45         for i in range(0, 257):
46             info = self.create_packet_info(src_if.sw_if_index,
47                                            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) /
52                  Raw(payload))
53             info.data = p.copy()
54             pkts.append(p)
55         return pkts
56
57     def create_tunnel_stream_4o4(self, src_if,
58                                  tunnel_src, tunnel_dst,
59                                  src_ip, dst_ip):
60         pkts = []
61         for i in range(0, 257):
62             info = self.create_packet_info(src_if.sw_if_index,
63                                            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) /
67                  GRE() /
68                  IP(src=src_ip, dst=dst_ip) /
69                  UDP(sport=1234, dport=1234) /
70                  Raw(payload))
71             info.data = p.copy()
72             pkts.append(p)
73         return pkts
74
75     def create_tunnel_stream_6o4(self, src_if,
76                                  tunnel_src, tunnel_dst,
77                                  src_ip, dst_ip):
78         pkts = []
79         for i in range(0, 257):
80             info = self.create_packet_info(src_if.sw_if_index,
81                                            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) /
85                  GRE() /
86                  IPv6(src=src_ip, dst=dst_ip) /
87                  UDP(sport=1234, dport=1234) /
88                  Raw(payload))
89             info.data = p.copy()
90             pkts.append(p)
91         return pkts
92
93     def create_tunnel_stream_l2o4(self, src_if,
94                                   tunnel_src, tunnel_dst):
95         pkts = []
96         for i in range(0, 257):
97             info = self.create_packet_info(src_if.sw_if_index,
98                                            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) /
102                  GRE() /
103                  Ether(dst=RandMAC('*:*:*:*:*:*'),
104                        src=RandMAC('*:*:*:*:*:*')) /
105                  IP(src=str(RandIP()), dst=str(RandIP())) /
106                  UDP(sport=1234, dport=1234) /
107                  Raw(payload))
108             info.data = p.copy()
109             pkts.append(p)
110         return pkts
111
112     def create_tunnel_stream_vlano4(self, src_if,
113                                     tunnel_src, tunnel_dst, vlan):
114         pkts = []
115         for i in range(0, 257):
116             info = self.create_packet_info(src_if.sw_if_index,
117                                            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) /
121                  GRE() /
122                  Ether(dst=RandMAC('*:*:*:*:*:*'),
123                        src=RandMAC('*:*:*:*:*:*')) /
124                  Dot1Q(vlan=vlan) /
125                  IP(src=str(RandIP()), dst=str(RandIP())) /
126                  UDP(sport=1234, dport=1234) /
127                  Raw(payload))
128             info.data = p.copy()
129             pkts.append(p)
130         return pkts
131
132     def verify_filter(self, capture, sent):
133         if not len(capture) == len(sent):
134             # filter out any IPv6 RAs from the captur
135             for p in capture:
136                 if (p.haslayer(ICMPv6ND_RA)):
137                     capture.remove(p)
138         return capture
139
140     def verify_tunneled_4o4(self, src_if, capture, sent,
141                             tunnel_src, tunnel_dst):
142
143         capture = self.verify_filter(capture, sent)
144         self.assertEqual(len(capture), len(sent))
145
146         for i in range(len(capture)):
147             try:
148                 tx = sent[i]
149                 rx = capture[i]
150
151                 tx_ip = tx[IP]
152                 rx_ip = rx[IP]
153
154                 self.assertEqual(rx_ip.src, tunnel_src)
155                 self.assertEqual(rx_ip.dst, tunnel_dst)
156
157                 rx_gre = rx[GRE]
158                 rx_ip = rx_gre[IP]
159
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)
164
165             except:
166                 rx.show()
167                 tx.show()
168                 raise
169
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))
174
175         for i in range(len(capture)):
176             try:
177                 tx = sent[i]
178                 rx = capture[i]
179
180                 tx_ip = tx[IP]
181                 rx_ip = rx[IP]
182
183                 self.assertEqual(rx_ip.src, tunnel_src)
184                 self.assertEqual(rx_ip.dst, tunnel_dst)
185
186                 rx_gre = rx[GRE]
187                 rx_l2 = rx_gre[Ether]
188                 rx_ip = rx_l2[IP]
189                 tx_gre = tx[GRE]
190                 tx_l2 = tx_gre[Ether]
191                 tx_ip = tx_l2[IP]
192
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)
197
198             except:
199                 rx.show()
200                 tx.show()
201                 raise
202
203     def verify_tunneled_vlano4(self, src_if, capture, sent,
204                                tunnel_src, tunnel_dst, vlan):
205         try:
206             capture = self.verify_filter(capture, sent)
207             self.assertEqual(len(capture), len(sent))
208         except:
209             capture.show()
210             raise
211
212         for i in range(len(capture)):
213             try:
214                 tx = sent[i]
215                 rx = capture[i]
216
217                 tx_ip = tx[IP]
218                 rx_ip = rx[IP]
219
220                 self.assertEqual(rx_ip.src, tunnel_src)
221                 self.assertEqual(rx_ip.dst, tunnel_dst)
222
223                 rx_gre = rx[GRE]
224                 rx_l2 = rx_gre[Ether]
225                 rx_vlan = rx_l2[Dot1Q]
226                 rx_ip = rx_l2[IP]
227
228                 self.assertEqual(rx_vlan.vlan, vlan)
229
230                 tx_gre = tx[GRE]
231                 tx_l2 = tx_gre[Ether]
232                 tx_ip = tx_l2[IP]
233
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)
238
239             except:
240                 rx.show()
241                 tx.show()
242                 raise
243
244     def verify_decapped_4o4(self, src_if, capture, sent):
245         capture = self.verify_filter(capture, sent)
246         self.assertEqual(len(capture), len(sent))
247
248         for i in range(len(capture)):
249             try:
250                 tx = sent[i]
251                 rx = capture[i]
252
253                 tx_ip = tx[IP]
254                 rx_ip = rx[IP]
255                 tx_gre = tx[GRE]
256                 tx_ip = tx_gre[IP]
257
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)
262
263             except:
264                 rx.show()
265                 tx.show()
266                 raise
267
268     def verify_decapped_6o4(self, src_if, capture, sent):
269         capture = self.verify_filter(capture, sent)
270         self.assertEqual(len(capture), len(sent))
271
272         for i in range(len(capture)):
273             try:
274                 tx = sent[i]
275                 rx = capture[i]
276
277                 tx_ip = tx[IP]
278                 rx_ip = rx[IPv6]
279                 tx_gre = tx[GRE]
280                 tx_ip = tx_gre[IPv6]
281
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)
285
286             except:
287                 rx.show()
288                 tx.show()
289                 raise
290
291     def test_gre(self):
292         """ GRE tunnel Tests """
293
294         #
295         # Create an L3 GRE tunnel.
296         #  - set it admin up
297         #  - assign an IP Addres
298         #  - Add a route via the tunnel
299         #
300         gre_if = VppGreInterface(self,
301                                  self.pg0.local_ip4,
302                                  "1.1.1.2")
303         gre_if.add_vpp_config()
304
305         #
306         # The double create (create the same tunnel twice) should fail,
307         # and we should still be able to use the original
308         #
309         try:
310             gre_if.add_vpp_config()
311         except Exception:
312             pass
313         else:
314             self.fail("Double GRE tunnel add does not fail")
315
316         gre_if.admin_up()
317         gre_if.config_ip4()
318
319         route_via_tun = IpRoute(self, "4.4.4.4", 32,
320                                 [RoutePath("0.0.0.0", gre_if.sw_if_index)])
321
322         route_via_tun.add_vpp_config()
323
324         #
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
328         #    which is a drop.
329         #
330         tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
331         self.pg0.add_stream(tx)
332
333         self.pg_enable_capture(self.pg_interfaces)
334         self.pg_start()
335
336         rx = self.pg0.get_capture()
337
338         try:
339             self.assertEqual(0, len(rx))
340         except:
341             error("GRE packets forwarded without DIP resolved")
342             error(rx.show())
343             raise
344
345         #
346         # Add a route that resolves the tunnel's destination
347         #
348         route_tun_dst = IpRoute(self, "1.1.1.2", 32,
349                                 [RoutePath(self.pg0.remote_ip4,
350                                            self.pg0.sw_if_index)])
351         route_tun_dst.add_vpp_config()
352
353         #
354         # Send a packet stream that is routed into the tunnel
355         #  - packets are GRE encapped
356         #
357         self.vapi.cli("clear trace")
358         tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
359         self.pg0.add_stream(tx)
360
361         self.pg_enable_capture(self.pg_interfaces)
362         self.pg_start()
363
364         rx = self.pg0.get_capture()
365         self.verify_tunneled_4o4(self.pg0, rx, tx,
366                                  self.pg0.local_ip4, "1.1.1.2")
367
368         #
369         # Send tunneled packets that match the created tunnel and
370         # are decapped and forwarded
371         #
372         self.vapi.cli("clear trace")
373         tx = self.create_tunnel_stream_4o4(self.pg0,
374                                            "1.1.1.2",
375                                            self.pg0.local_ip4,
376                                            self.pg0.local_ip4,
377                                            self.pg0.remote_ip4)
378         self.pg0.add_stream(tx)
379
380         self.pg_enable_capture(self.pg_interfaces)
381         self.pg_start()
382
383         rx = self.pg0.get_capture()
384         self.verify_decapped_4o4(self.pg0, rx, tx)
385
386         #
387         # Send tunneled packets that do not match the tunnel's src
388         #
389         self.vapi.cli("clear trace")
390         tx = self.create_tunnel_stream_4o4(self.pg0,
391                                            "1.1.1.3",
392                                            self.pg0.local_ip4,
393                                            self.pg0.local_ip4,
394                                            self.pg0.remote_ip4)
395         self.pg0.add_stream(tx)
396
397         self.pg_enable_capture(self.pg_interfaces)
398         self.pg_start()
399
400         rx = self.pg0.get_capture()
401         try:
402             self.assertEqual(0, len(rx))
403         except:
404             error("GRE packets forwarded despite no SRC address match")
405             error(rx.show())
406             raise
407
408         #
409         # Configure IPv6 on the PG interface so we can route IPv6
410         # packets
411         #
412         self.pg0.config_ip6()
413         self.pg0.resolve_ndp()
414
415         #
416         # Send IPv6 tunnel encapslated packets
417         #  - dropped since IPv6 is not enabled on the tunnel
418         #
419         self.vapi.cli("clear trace")
420         tx = self.create_tunnel_stream_6o4(self.pg0,
421                                            "1.1.1.2",
422                                            self.pg0.local_ip4,
423                                            self.pg0.local_ip6,
424                                            self.pg0.remote_ip6)
425         self.pg0.add_stream(tx)
426
427         self.pg_enable_capture(self.pg_interfaces)
428         self.pg_start()
429
430         rx = self.pg0.get_capture()
431         try:
432             self.assertEqual(0, len(rx))
433         except:
434             error("IPv6 GRE packets forwarded despite IPv6 not enabled on tunnel")
435             error(rx.show())
436             raise
437
438         #
439         # Enable IPv6 on the tunnel
440         #
441         gre_if.config_ip6()
442
443         #
444         # Send IPv6 tunnel encapslated packets
445         #  - forwarded since IPv6 is enabled on the tunnel
446         #
447         self.vapi.cli("clear trace")
448         tx = self.create_tunnel_stream_6o4(self.pg0,
449                                            "1.1.1.2",
450                                            self.pg0.local_ip4,
451                                            self.pg0.local_ip6,
452                                            self.pg0.remote_ip6)
453         self.pg0.add_stream(tx)
454
455         self.pg_enable_capture(self.pg_interfaces)
456         self.pg_start()
457
458         rx = self.pg0.get_capture()
459         self.verify_decapped_6o4(self.pg0, rx, tx)
460
461         #
462         # test case cleanup
463         #
464         route_tun_dst.remove_vpp_config()
465         route_via_tun.remove_vpp_config()
466         gre_if.remove_vpp_config()
467
468         self.pg0.unconfig_ip6()
469
470     def test_gre_vrf(self):
471         """ GRE tunnel VRF Tests """
472
473         #
474         # Create an L3 GRE tunnel whose destination is in the non-default
475         # table. The underlay is thus non-default - the overlay is still
476         # the default.
477         #  - set it admin up
478         #  - assign an IP Addres
479         #
480         gre_if = VppGreInterface(self, self.pg1.local_ip4,
481                                  "2.2.2.2",
482                                  outer_fib_id=1)
483         gre_if.add_vpp_config()
484         gre_if.admin_up()
485         gre_if.config_ip4()
486
487         #
488         # Add a route via the tunnel - in the overlay
489         #
490         route_via_tun = IpRoute(self, "9.9.9.9", 32,
491                                 [RoutePath("0.0.0.0", gre_if.sw_if_index)])
492         route_via_tun.add_vpp_config()
493
494         #
495         # Add a route that resolves the tunnel's destination - in the
496         # underlay table
497         #
498         route_tun_dst = IpRoute(self, "2.2.2.2", 32, table_id=1,
499                                 paths=[RoutePath(self.pg1.remote_ip4,
500                                                  self.pg1.sw_if_index)])
501         route_tun_dst.add_vpp_config()
502
503         #
504         # Send a packet stream that is routed into the tunnel
505         # packets are sent in on pg0 which is in the default table
506         #  - packets are GRE encapped
507         #
508         self.vapi.cli("clear trace")
509         tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "9.9.9.9")
510         self.pg0.add_stream(tx)
511
512         self.pg_enable_capture(self.pg_interfaces)
513         self.pg_start()
514
515         rx = self.pg1.get_capture()
516         self.verify_tunneled_4o4(self.pg1, rx, tx,
517                                  self.pg1.local_ip4, "2.2.2.2")
518
519         #
520         # Send tunneled packets that match the created tunnel and
521         # are decapped and forwarded. This tests the decap lookup
522         # does not happen in the encap table
523         #
524         self.vapi.cli("clear trace")
525         tx = self.create_tunnel_stream_4o4(self.pg1,
526                                            "2.2.2.2",
527                                            self.pg1.local_ip4,
528                                            self.pg0.local_ip4,
529                                            self.pg0.remote_ip4)
530         self.pg1.add_stream(tx)
531
532         self.pg_enable_capture(self.pg_interfaces)
533         self.pg_start()
534
535         rx = self.pg0.get_capture()
536         self.verify_decapped_4o4(self.pg0, rx, tx)
537
538         #
539         # test case cleanup
540         #
541         route_tun_dst.remove_vpp_config()
542         route_via_tun.remove_vpp_config()
543         gre_if.remove_vpp_config()
544
545     def test_gre_l2(self):
546         """ GRE tunnel L2 Tests """
547
548         #
549         # Add routes to resolve the tunnel destinations
550         #
551         route_tun1_dst = IpRoute(self, "2.2.2.2", 32,
552                                  [RoutePath(self.pg0.remote_ip4,
553                                             self.pg0.sw_if_index)])
554         route_tun2_dst = IpRoute(self, "2.2.2.3", 32,
555                                  [RoutePath(self.pg0.remote_ip4,
556                                             self.pg0.sw_if_index)])
557
558         route_tun1_dst.add_vpp_config()
559         route_tun2_dst.add_vpp_config()
560
561         #
562         # Create 2 L2 GRE tunnels and x-connect them
563         #
564         gre_if1 = VppGreInterface(self, self.pg0.local_ip4,
565                                   "2.2.2.2",
566                                   is_teb=1)
567         gre_if2 = VppGreInterface(self, self.pg0.local_ip4,
568                                   "2.2.2.3",
569                                   is_teb=1)
570         gre_if1.add_vpp_config()
571         gre_if2.add_vpp_config()
572
573         gre_if1.admin_up()
574         gre_if2.admin_up()
575
576         self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
577                                                gre_if2.sw_if_index,
578                                                enable=1)
579         self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
580                                                gre_if1.sw_if_index,
581                                                enable=1)
582
583         #
584         # Send in tunnel encapped L2. expect out tunnel encapped L2
585         # in both directions
586         #
587         self.vapi.cli("clear trace")
588         tx = self.create_tunnel_stream_l2o4(self.pg0,
589                                             "2.2.2.2",
590                                             self.pg0.local_ip4)
591         self.pg0.add_stream(tx)
592
593         self.pg_enable_capture(self.pg_interfaces)
594         self.pg_start()
595
596         rx = self.pg0.get_capture()
597         self.verify_tunneled_l2o4(self.pg0, rx, tx,
598                                   self.pg0.local_ip4,
599                                   "2.2.2.3")
600
601         self.vapi.cli("clear trace")
602         tx = self.create_tunnel_stream_l2o4(self.pg0,
603                                             "2.2.2.3",
604                                             self.pg0.local_ip4)
605         self.pg0.add_stream(tx)
606
607         self.pg_enable_capture(self.pg_interfaces)
608         self.pg_start()
609
610         rx = self.pg0.get_capture()
611         self.verify_tunneled_l2o4(self.pg0, rx, tx,
612                                   self.pg0.local_ip4,
613                                   "2.2.2.2")
614
615         self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
616                                                gre_if2.sw_if_index,
617                                                enable=0)
618         self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
619                                                gre_if1.sw_if_index,
620                                                enable=0)
621
622         #
623         # Create a VLAN sub-interfaces on the GRE TEB interfaces
624         # then x-connect them
625         #
626         gre_if_11 = VppDot1QSubint(self, gre_if1, 11)
627         gre_if_12 = VppDot1QSubint(self, gre_if2, 12)
628
629         # gre_if_11.add_vpp_config()
630         # gre_if_12.add_vpp_config()
631
632         gre_if_11.admin_up()
633         gre_if_12.admin_up()
634
635         self.vapi.sw_interface_set_l2_xconnect(gre_if_11.sw_if_index,
636                                                gre_if_12.sw_if_index,
637                                                enable=1)
638         self.vapi.sw_interface_set_l2_xconnect(gre_if_12.sw_if_index,
639                                                gre_if_11.sw_if_index,
640                                                enable=1)
641
642         #
643         # Configure both to pop thier respective VLAN tags,
644         # so that during the x-coonect they will subsequently push
645         #
646         self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_12.sw_if_index,
647                                                   L2_VTR_OP.L2_POP_1,
648                                                   12)
649         self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_11.sw_if_index,
650                                                   L2_VTR_OP.L2_POP_1,
651                                                   11)
652
653         #
654         # Send traffic in both directiond - expect the VLAN tags to
655         # be swapped.
656         #
657         self.vapi.cli("clear trace")
658         tx = self.create_tunnel_stream_vlano4(self.pg0,
659                                               "2.2.2.2",
660                                               self.pg0.local_ip4,
661                                               11)
662         self.pg0.add_stream(tx)
663
664         self.pg_enable_capture(self.pg_interfaces)
665         self.pg_start()
666
667         rx = self.pg0.get_capture()
668         self.verify_tunneled_vlano4(self.pg0, rx, tx,
669                                     self.pg0.local_ip4,
670                                     "2.2.2.3",
671                                     12)
672
673         self.vapi.cli("clear trace")
674         tx = self.create_tunnel_stream_vlano4(self.pg0,
675                                               "2.2.2.3",
676                                               self.pg0.local_ip4,
677                                               12)
678         self.pg0.add_stream(tx)
679
680         self.pg_enable_capture(self.pg_interfaces)
681         self.pg_start()
682
683         rx = self.pg0.get_capture()
684         self.verify_tunneled_vlano4(self.pg0, rx, tx,
685                                     self.pg0.local_ip4,
686                                     "2.2.2.2",
687                                     11)
688
689         #
690         # Cleanup Test resources
691         #
692         gre_if_11.remove_vpp_config()
693         gre_if_12.remove_vpp_config()
694         gre_if1.remove_vpp_config()
695         gre_if2.remove_vpp_config()
696         route_tun1_dst.add_vpp_config()
697         route_tun2_dst.add_vpp_config()
698
699
700 if __name__ == '__main__':
701     unittest.main(testRunner=VppTestRunner)