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