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