GRE tests and fixes
[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, IpPath
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, 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                                 [IpPath("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                                 [IpPath(self.pg0.remote_ip4, self.pg0.sw_if_index)])
350         route_tun_dst.add_vpp_config()
351
352         #
353         # Send a packet stream that is routed into the tunnel
354         #  - packets are GRE encapped
355         #
356         self.vapi.cli("clear trace")
357         tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "4.4.4.4")
358         self.pg0.add_stream(tx)
359
360         self.pg_enable_capture(self.pg_interfaces)
361         self.pg_start()
362
363         rx = self.pg0.get_capture()
364         self.verify_tunneled_4o4(self.pg0, rx, tx,
365                                  self.pg0.local_ip4, "1.1.1.2")
366
367         #
368         # Send tunneled packets that match the created tunnel and
369         # are decapped and forwarded
370         #
371         self.vapi.cli("clear trace")
372         tx = self.create_tunnel_stream_4o4(self.pg0,
373                                            "1.1.1.2",
374                                            self.pg0.local_ip4,
375                                            self.pg0.local_ip4,
376                                            self.pg0.remote_ip4)
377         self.pg0.add_stream(tx)
378
379         self.pg_enable_capture(self.pg_interfaces)
380         self.pg_start()
381
382         rx = self.pg0.get_capture()
383         self.verify_decapped_4o4(self.pg0, rx, tx)
384
385         #
386         # Send tunneled packets that do not match the tunnel's src
387         #
388         self.vapi.cli("clear trace")
389         tx = self.create_tunnel_stream_4o4(self.pg0,
390                                            "1.1.1.3",
391                                            self.pg0.local_ip4,
392                                            self.pg0.local_ip4,
393                                            self.pg0.remote_ip4)
394         self.pg0.add_stream(tx)
395
396         self.pg_enable_capture(self.pg_interfaces)
397         self.pg_start()
398
399         rx = self.pg0.get_capture()
400         try:
401             self.assertEqual(0, len(rx))
402         except:
403             error("GRE packets forwarded despite no SRC address match")
404             error(rx.show())
405             raise
406
407         #
408         # Configure IPv6 on the PG interface so we can route IPv6
409         # packets
410         #
411         self.pg0.config_ip6()
412         self.pg0.resolve_ndp()
413
414         #
415         # Send IPv6 tunnel encapslated packets
416         #  - dropped since IPv6 is not enabled on the tunnel
417         #
418         self.vapi.cli("clear trace")
419         tx = self.create_tunnel_stream_6o4(self.pg0,
420                                            "1.1.1.2",
421                                            self.pg0.local_ip4,
422                                            self.pg0.local_ip6,
423                                            self.pg0.remote_ip6)
424         self.pg0.add_stream(tx)
425
426         self.pg_enable_capture(self.pg_interfaces)
427         self.pg_start()
428
429         rx = self.pg0.get_capture()
430         try:
431             self.assertEqual(0, len(rx))
432         except:
433             error("IPv6 GRE packets forwarded despite IPv6 not enabled on tunnel")
434             error(rx.show())
435             raise
436
437         #
438         # Enable IPv6 on the tunnel
439         #
440         gre_if.config_ip6()
441
442         #
443         # Send IPv6 tunnel encapslated packets
444         #  - forwarded since IPv6 is enabled on the tunnel
445         #
446         self.vapi.cli("clear trace")
447         tx = self.create_tunnel_stream_6o4(self.pg0,
448                                            "1.1.1.2",
449                                            self.pg0.local_ip4,
450                                            self.pg0.local_ip6,
451                                            self.pg0.remote_ip6)
452         self.pg0.add_stream(tx)
453
454         self.pg_enable_capture(self.pg_interfaces)
455         self.pg_start()
456
457         rx = self.pg0.get_capture()
458         self.verify_decapped_6o4(self.pg0, rx, tx)
459
460         #
461         # test case cleanup
462         #
463         route_tun_dst.remove_vpp_config()
464         route_via_tun.remove_vpp_config()
465         gre_if.remove_vpp_config()
466
467         self.pg0.unconfig_ip6()
468
469     def test_gre_vrf(self):
470         """ GRE tunnel VRF Tests """
471
472         #
473         # Create an L3 GRE tunnel whose destination is in the non-default
474         # table. The underlay is thus non-default - the overlay is still
475         # the default.
476         #  - set it admin up
477         #  - assign an IP Addres
478         #
479         gre_if = VppGreInterface(self, self.pg1.local_ip4,
480                                  "2.2.2.2",
481                                  outer_fib_id=1)
482         gre_if.add_vpp_config()
483         gre_if.admin_up()
484         gre_if.config_ip4()
485
486         #
487         # Add a route via the tunnel - in the overlay
488         #
489         route_via_tun = IpRoute(self, "9.9.9.9", 32,
490                                 [IpPath("0.0.0.0", gre_if.sw_if_index)])
491         route_via_tun.add_vpp_config()
492
493         #
494         # Add a route that resolves the tunnel's destination - in the
495         # underlay table
496         #
497         route_tun_dst = IpRoute(self, "2.2.2.2", 32, table_id=1,
498                                 paths=[IpPath(self.pg1.remote_ip4,
499                                               self.pg1.sw_if_index)])
500         route_tun_dst.add_vpp_config()
501
502         #
503         # Send a packet stream that is routed into the tunnel
504         # packets are sent in on pg0 which is in the default table
505         #  - packets are GRE encapped
506         #
507         self.vapi.cli("clear trace")
508         tx = self.create_stream_ip4(self.pg0, "5.5.5.5", "9.9.9.9")
509         self.pg0.add_stream(tx)
510
511         self.pg_enable_capture(self.pg_interfaces)
512         self.pg_start()
513
514         rx = self.pg1.get_capture()
515         self.verify_tunneled_4o4(self.pg1, rx, tx,
516                                  self.pg1.local_ip4, "2.2.2.2")
517
518         #
519         # Send tunneled packets that match the created tunnel and
520         # are decapped and forwarded. This tests the decap lookup
521         # does not happen in the encap table
522         #
523         self.vapi.cli("clear trace")
524         tx = self.create_tunnel_stream_4o4(self.pg1,
525                                            "2.2.2.2",
526                                            self.pg1.local_ip4,
527                                            self.pg0.local_ip4,
528                                            self.pg0.remote_ip4)
529         self.pg1.add_stream(tx)
530
531         self.pg_enable_capture(self.pg_interfaces)
532         self.pg_start()
533
534         rx = self.pg0.get_capture()
535         self.verify_decapped_4o4(self.pg0, rx, tx)
536
537         #
538         # test case cleanup
539         #
540         route_tun_dst.remove_vpp_config()
541         route_via_tun.remove_vpp_config()
542         gre_if.remove_vpp_config()
543
544     def test_gre_l2(self):
545         """ GRE tunnel L2 Tests """
546
547         #
548         # Add routes to resolve the tunnel destinations
549         #
550         route_tun1_dst = IpRoute(self, "2.2.2.2", 32,
551                                  [IpPath(self.pg0.remote_ip4,
552                                          self.pg0.sw_if_index)])
553         route_tun2_dst = IpRoute(self, "2.2.2.3", 32,
554                                  [IpPath(self.pg0.remote_ip4,
555                                          self.pg0.sw_if_index)])
556
557         route_tun1_dst.add_vpp_config()
558         route_tun2_dst.add_vpp_config()
559
560         #
561         # Create 2 L2 GRE tunnels and x-connect them
562         #
563         gre_if1 = VppGreInterface(self, self.pg0.local_ip4,
564                                   "2.2.2.2",
565                                   is_teb=1)
566         gre_if2 = VppGreInterface(self, self.pg0.local_ip4,
567                                   "2.2.2.3",
568                                   is_teb=1)
569         gre_if1.add_vpp_config()
570         gre_if2.add_vpp_config()
571
572         gre_if1.admin_up()
573         gre_if2.admin_up()
574
575         self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
576                                                gre_if2.sw_if_index,
577                                                enable=1)
578         self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
579                                                gre_if1.sw_if_index,
580                                                enable=1)
581
582         #
583         # Send in tunnel encapped L2. expect out tunnel encapped L2
584         # in both directions
585         #
586         self.vapi.cli("clear trace")
587         tx = self.create_tunnel_stream_l2o4(self.pg0,
588                                             "2.2.2.2",
589                                             self.pg0.local_ip4)
590         self.pg0.add_stream(tx)
591
592         self.pg_enable_capture(self.pg_interfaces)
593         self.pg_start()
594
595         rx = self.pg0.get_capture()
596         self.verify_tunneled_l2o4(self.pg0, rx, tx,
597                                   self.pg0.local_ip4,
598                                   "2.2.2.3")
599
600         self.vapi.cli("clear trace")
601         tx = self.create_tunnel_stream_l2o4(self.pg0,
602                                             "2.2.2.3",
603                                             self.pg0.local_ip4)
604         self.pg0.add_stream(tx)
605
606         self.pg_enable_capture(self.pg_interfaces)
607         self.pg_start()
608
609         rx = self.pg0.get_capture()
610         self.verify_tunneled_l2o4(self.pg0, rx, tx,
611                                   self.pg0.local_ip4,
612                                   "2.2.2.2")
613
614         self.vapi.sw_interface_set_l2_xconnect(gre_if1.sw_if_index,
615                                                gre_if2.sw_if_index,
616                                                enable=0)
617         self.vapi.sw_interface_set_l2_xconnect(gre_if2.sw_if_index,
618                                                gre_if1.sw_if_index,
619                                                enable=0)
620
621         #
622         # Create a VLAN sub-interfaces on the GRE TEB interfaces
623         # then x-connect them
624         #
625         gre_if_11 = VppDot1QSubint(self, gre_if1, 11)
626         gre_if_12 = VppDot1QSubint(self, gre_if2, 12)
627
628         # gre_if_11.add_vpp_config()
629         # gre_if_12.add_vpp_config()
630
631         gre_if_11.admin_up()
632         gre_if_12.admin_up()
633
634         self.vapi.sw_interface_set_l2_xconnect(gre_if_11.sw_if_index,
635                                                gre_if_12.sw_if_index,
636                                                enable=1)
637         self.vapi.sw_interface_set_l2_xconnect(gre_if_12.sw_if_index,
638                                                gre_if_11.sw_if_index,
639                                                enable=1)
640
641         #
642         # Configure both to pop thier respective VLAN tags,
643         # so that during the x-coonect they will subsequently push
644         #
645         self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_12.sw_if_index,
646                                                   L2_VTR_OP.L2_POP_1,
647                                                   12)
648         self.vapi.sw_interface_set_l2_tag_rewrite(gre_if_11.sw_if_index,
649                                                   L2_VTR_OP.L2_POP_1,
650                                                   11)
651
652         #
653         # Send traffic in both directiond - expect the VLAN tags to
654         # be swapped.
655         #
656         self.vapi.cli("clear trace")
657         tx = self.create_tunnel_stream_vlano4(self.pg0,
658                                               "2.2.2.2",
659                                               self.pg0.local_ip4,
660                                               11)
661         self.pg0.add_stream(tx)
662
663         self.pg_enable_capture(self.pg_interfaces)
664         self.pg_start()
665
666         rx = self.pg0.get_capture()
667         self.verify_tunneled_vlano4(self.pg0, rx, tx,
668                                     self.pg0.local_ip4,
669                                     "2.2.2.3",
670                                     12)
671
672         self.vapi.cli("clear trace")
673         tx = self.create_tunnel_stream_vlano4(self.pg0,
674                                               "2.2.2.3",
675                                               self.pg0.local_ip4,
676                                               12)
677         self.pg0.add_stream(tx)
678
679         self.pg_enable_capture(self.pg_interfaces)
680         self.pg_start()
681
682         rx = self.pg0.get_capture()
683         self.verify_tunneled_vlano4(self.pg0, rx, tx,
684                                     self.pg0.local_ip4,
685                                     "2.2.2.2",
686                                     11)
687
688         #
689         # Cleanup Test resources
690         #
691         gre_if_11.remove_vpp_config()
692         gre_if_12.remove_vpp_config()
693         gre_if1.remove_vpp_config()
694         gre_if2.remove_vpp_config()
695         route_tun1_dst.add_vpp_config()
696         route_tun2_dst.add_vpp_config()
697
698
699 if __name__ == '__main__':
700     unittest.main(testRunner=VppTestRunner)