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