udp: remove buggy assert in udp encap
[vpp.git] / test / test_udp.py
1 #!/usr/bin/env python3
2 import unittest
3 from framework import tag_fixme_vpp_workers
4 from framework import VppTestCase, VppTestRunner
5
6 from vpp_udp_encap import find_udp_encap, VppUdpEncap
7 from vpp_udp_decap import VppUdpDecap
8 from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpTable, VppMplsLabel, \
9     VppMplsTable, VppMplsRoute, FibPathType, FibPathProto
10 from vpp_neighbor import VppNeighbor
11 from vpp_papi import VppEnum
12
13 from scapy.packet import Raw
14 from scapy.layers.l2 import Ether
15 from scapy.layers.inet import IP, UDP, ICMP
16 from scapy.layers.inet6 import IPv6
17 from scapy.contrib.mpls import MPLS
18
19 NUM_PKTS = 67
20
21
22 @tag_fixme_vpp_workers
23 class TestUdpEncap(VppTestCase):
24     """ UDP Encap Test Case """
25
26     @classmethod
27     def setUpClass(cls):
28         super(TestUdpEncap, cls).setUpClass()
29
30     @classmethod
31     def tearDownClass(cls):
32         super(TestUdpEncap, cls).tearDownClass()
33
34     def setUp(self):
35         super(TestUdpEncap, self).setUp()
36
37         # create 2 pg interfaces
38         self.create_pg_interfaces(range(4))
39
40         # setup interfaces
41         # assign them different tables.
42         table_id = 0
43         self.tables = []
44
45         for i in self.pg_interfaces:
46             i.admin_up()
47
48             if table_id != 0:
49                 tbl = VppIpTable(self, table_id)
50                 tbl.add_vpp_config()
51                 self.tables.append(tbl)
52                 tbl = VppIpTable(self, table_id, is_ip6=1)
53                 tbl.add_vpp_config()
54                 self.tables.append(tbl)
55
56             i.set_table_ip4(table_id)
57             i.set_table_ip6(table_id)
58             i.config_ip4()
59             i.resolve_arp()
60             i.config_ip6()
61             i.resolve_ndp()
62             table_id += 1
63
64     def tearDown(self):
65         for i in self.pg_interfaces:
66             i.unconfig_ip4()
67             i.unconfig_ip6()
68             i.set_table_ip4(0)
69             i.set_table_ip6(0)
70             i.admin_down()
71         super(TestUdpEncap, self).tearDown()
72
73     def validate_outer4(self, rx, encap_obj):
74         self.assertEqual(rx[IP].src, encap_obj.src_ip_s)
75         self.assertEqual(rx[IP].dst, encap_obj.dst_ip_s)
76         self.assertEqual(rx[UDP].sport, encap_obj.src_port)
77         self.assertEqual(rx[UDP].dport, encap_obj.dst_port)
78
79     def validate_outer6(self, rx, encap_obj):
80         self.assertEqual(rx[IPv6].src, encap_obj.src_ip_s)
81         self.assertEqual(rx[IPv6].dst, encap_obj.dst_ip_s)
82         self.assertEqual(rx[UDP].sport, encap_obj.src_port)
83         self.assertEqual(rx[UDP].dport, encap_obj.dst_port)
84
85     def validate_inner4(self, rx, tx, ttl=None):
86         self.assertEqual(rx[IP].src, tx[IP].src)
87         self.assertEqual(rx[IP].dst, tx[IP].dst)
88         if ttl:
89             self.assertEqual(rx[IP].ttl, ttl)
90         else:
91             self.assertEqual(rx[IP].ttl, tx[IP].ttl)
92
93     def validate_inner6(self, rx, tx, hlim=None):
94         self.assertEqual(rx.src, tx[IPv6].src)
95         self.assertEqual(rx.dst, tx[IPv6].dst)
96         if hlim:
97             self.assertEqual(rx.hlim, hlim)
98         else:
99             self.assertEqual(rx.hlim, tx[IPv6].hlim)
100
101     def test_udp_encap(self):
102         """ UDP Encap test
103         """
104
105         #
106         # construct a UDP encap object through each of the peers
107         # v4 through the first two peers, v6 through the second.
108         # The last encap is v4 and is used to check the codepath
109         # where 2 different udp encap objects are processed at the
110         # same time
111         #
112         udp_encap_0 = VppUdpEncap(self,
113                                   self.pg0.local_ip4,
114                                   self.pg0.remote_ip4,
115                                   330, 440)
116         udp_encap_1 = VppUdpEncap(self,
117                                   self.pg1.local_ip4,
118                                   self.pg1.remote_ip4,
119                                   331, 441,
120                                   table_id=1)
121         udp_encap_2 = VppUdpEncap(self,
122                                   self.pg2.local_ip6,
123                                   self.pg2.remote_ip6,
124                                   332, 442,
125                                   table_id=2)
126         udp_encap_3 = VppUdpEncap(self,
127                                   self.pg3.local_ip6,
128                                   self.pg3.remote_ip6,
129                                   333, 443,
130                                   table_id=3)
131         udp_encap_4 = VppUdpEncap(self,
132                                   self.pg0.local_ip4,
133                                   self.pg0.remote_ip4,
134                                   334, 444)
135         udp_encap_0.add_vpp_config()
136         udp_encap_1.add_vpp_config()
137         udp_encap_2.add_vpp_config()
138         udp_encap_3.add_vpp_config()
139         udp_encap_4.add_vpp_config()
140
141         self.logger.info(self.vapi.cli("sh udp encap"))
142
143         self.assertTrue(find_udp_encap(self, udp_encap_2))
144         self.assertTrue(find_udp_encap(self, udp_encap_3))
145         self.assertTrue(find_udp_encap(self, udp_encap_0))
146         self.assertTrue(find_udp_encap(self, udp_encap_1))
147         self.assertTrue(find_udp_encap(self, udp_encap_4))
148
149         #
150         # Routes via each UDP encap object - all combinations of v4 and v6.
151         #
152         route_4o4 = VppIpRoute(
153             self, "1.1.0.1", 24,
154             [VppRoutePath("0.0.0.0",
155                           0xFFFFFFFF,
156                           type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
157                           next_hop_id=udp_encap_0.id,
158                           proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)],
159             table_id=1)
160         # specific route to match encap4, to test encap of 2 packets using 2
161         # different encap
162         route_4o4_2 = VppIpRoute(
163             self, "1.1.0.2", 32,
164             [VppRoutePath("0.0.0.0",
165                           0xFFFFFFFF,
166                           type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
167                           next_hop_id=udp_encap_4.id,
168                           proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)],
169             table_id=1)
170         route_4o6 = VppIpRoute(
171             self, "1.1.2.1", 32,
172             [VppRoutePath("0.0.0.0",
173                           0xFFFFFFFF,
174                           type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
175                           next_hop_id=udp_encap_2.id,
176                           proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
177         route_6o4 = VppIpRoute(
178             self, "2001::1", 128,
179             [VppRoutePath("0.0.0.0",
180                           0xFFFFFFFF,
181                           type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
182                           next_hop_id=udp_encap_1.id,
183                           proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
184         route_6o6 = VppIpRoute(
185             self, "2001::3", 128,
186             [VppRoutePath("0.0.0.0",
187                           0xFFFFFFFF,
188                           type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
189                           next_hop_id=udp_encap_3.id,
190                           proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
191         route_4o6.add_vpp_config()
192         route_6o6.add_vpp_config()
193         route_6o4.add_vpp_config()
194         route_4o4.add_vpp_config()
195         route_4o4_2.add_vpp_config()
196
197         #
198         # 4o4 encap
199         # we add a single packet matching the last encap at the beginning of
200         # the packet vector so that we encap 2 packets with different udp
201         # encap object at the same time
202         #
203         p_4o4 = (Ether(src=self.pg1.remote_mac,
204                        dst=self.pg1.local_mac) /
205                  IP(src="2.2.2.2", dst="1.1.0.1") /
206                  UDP(sport=1234, dport=1234) /
207                  Raw(b'\xa5' * 100))
208         p_4o4_2 = (Ether(src=self.pg1.remote_mac,
209                          dst=self.pg1.local_mac) /
210                    IP(src="2.2.2.2", dst="1.1.0.2") /
211                    UDP(sport=1234, dport=1234) /
212                    Raw(b'\xa5' * 100))
213         rx = self.send_and_expect(
214             self.pg1, p_4o4_2 * 1 + p_4o4 * (NUM_PKTS - 1), self.pg0)
215         # checking encap4 magic packet
216         p = rx.pop(0)
217         self.validate_outer4(p, udp_encap_4)
218         p = IP(p["UDP"].payload.load)
219         self.validate_inner4(p, p_4o4_2)
220         self.assertEqual(udp_encap_4.get_stats()['packets'], 1)
221         # checking remaining packets for encap0
222         for p in rx:
223             self.validate_outer4(p, udp_encap_0)
224             p = IP(p["UDP"].payload.load)
225             self.validate_inner4(p, p_4o4)
226         self.assertEqual(udp_encap_0.get_stats()['packets'], NUM_PKTS - 1)
227
228         #
229         # 4o6 encap
230         #
231         p_4o6 = (Ether(src=self.pg0.remote_mac,
232                        dst=self.pg0.local_mac) /
233                  IP(src="2.2.2.2", dst="1.1.2.1") /
234                  UDP(sport=1234, dport=1234) /
235                  Raw(b'\xa5' * 100))
236         rx = self.send_and_expect(self.pg0, p_4o6*NUM_PKTS, self.pg2)
237         for p in rx:
238             self.validate_outer6(p, udp_encap_2)
239             p = IP(p["UDP"].payload.load)
240             self.validate_inner4(p, p_4o6)
241         self.assertEqual(udp_encap_2.get_stats()['packets'], NUM_PKTS)
242
243         #
244         # 6o4 encap
245         #
246         p_6o4 = (Ether(src=self.pg0.remote_mac,
247                        dst=self.pg0.local_mac) /
248                  IPv6(src="2001::100", dst="2001::1") /
249                  UDP(sport=1234, dport=1234) /
250                  Raw(b'\xa5' * 100))
251         rx = self.send_and_expect(self.pg0, p_6o4*NUM_PKTS, self.pg1)
252         for p in rx:
253             self.validate_outer4(p, udp_encap_1)
254             p = IPv6(p["UDP"].payload.load)
255             self.validate_inner6(p, p_6o4)
256         self.assertEqual(udp_encap_1.get_stats()['packets'], NUM_PKTS)
257
258         #
259         # 6o6 encap
260         #
261         p_6o6 = (Ether(src=self.pg0.remote_mac,
262                        dst=self.pg0.local_mac) /
263                  IPv6(src="2001::100", dst="2001::3") /
264                  UDP(sport=1234, dport=1234) /
265                  Raw(b'\xa5' * 100))
266         rx = self.send_and_expect(self.pg0, p_6o6*NUM_PKTS, self.pg3)
267         for p in rx:
268             self.validate_outer6(p, udp_encap_3)
269             p = IPv6(p["UDP"].payload.load)
270             self.validate_inner6(p, p_6o6)
271         self.assertEqual(udp_encap_3.get_stats()['packets'], NUM_PKTS)
272
273         #
274         # A route with an output label
275         # the TTL of the inner packet is decremented on LSP ingress
276         #
277         route_4oMPLSo4 = VppIpRoute(
278             self, "1.1.2.22", 32,
279             [VppRoutePath("0.0.0.0",
280                           0xFFFFFFFF,
281                           type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
282                           next_hop_id=1,
283                           labels=[VppMplsLabel(66)])])
284         route_4oMPLSo4.add_vpp_config()
285
286         p_4omo4 = (Ether(src=self.pg0.remote_mac,
287                          dst=self.pg0.local_mac) /
288                    IP(src="2.2.2.2", dst="1.1.2.22") /
289                    UDP(sport=1234, dport=1234) /
290                    Raw(b'\xa5' * 100))
291         rx = self.send_and_expect(self.pg0, p_4omo4*NUM_PKTS, self.pg1)
292         for p in rx:
293             self.validate_outer4(p, udp_encap_1)
294             p = MPLS(p["UDP"].payload.load)
295             self.validate_inner4(p, p_4omo4, ttl=63)
296         self.assertEqual(udp_encap_1.get_stats()['packets'], 2*NUM_PKTS)
297
298     def test_udp_decap(self):
299         """ UDP Decap test
300         """
301         #
302         # construct a UDP decap object for each type of protocol
303         #
304
305         # IPv4
306         udp_api_proto = VppEnum.vl_api_udp_decap_next_proto_t
307         next_proto = udp_api_proto.UDP_API_DECAP_PROTO_IP4
308         udp_decap_0 = VppUdpDecap(self, 1, 220, next_proto)
309
310         # IPv6
311         next_proto = udp_api_proto.UDP_API_DECAP_PROTO_IP6
312         udp_decap_1 = VppUdpDecap(self, 0, 221, next_proto)
313
314         # MPLS
315         next_proto = udp_api_proto.UDP_API_DECAP_PROTO_MPLS
316         udp_decap_2 = VppUdpDecap(self, 1, 222, next_proto)
317
318         udp_decap_0.add_vpp_config()
319         udp_decap_1.add_vpp_config()
320         udp_decap_2.add_vpp_config()
321
322         #
323         # Routes via the corresponding pg after the UDP decap
324         #
325         route_4 = VppIpRoute(
326             self, "1.1.1.1", 32,
327             [VppRoutePath("0.0.0.0", self.pg0.sw_if_index)],
328             table_id=0)
329
330         route_6 = VppIpRoute(
331             self, "2001::1", 128,
332             [VppRoutePath("::", self.pg1.sw_if_index)],
333             table_id=1)
334
335         route_mo4 = VppIpRoute(
336             self, "3.3.3.3", 32,
337             [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)],
338             table_id=2)
339
340         route_4.add_vpp_config()
341         route_6.add_vpp_config()
342         route_mo4.add_vpp_config()
343
344         #
345         # Adding neighbors to route the packets
346         #
347         n_4 = VppNeighbor(self,
348                           self.pg0.sw_if_index,
349                           "00:11:22:33:44:55",
350                           "1.1.1.1")
351         n_6 = VppNeighbor(self,
352                           self.pg1.sw_if_index,
353                           "11:22:33:44:55:66",
354                           "2001::1")
355         n_mo4 = VppNeighbor(self,
356                             self.pg2.sw_if_index,
357                             "22:33:44:55:66:77",
358                             "3.3.3.3")
359
360         n_4.add_vpp_config()
361         n_6.add_vpp_config()
362         n_mo4.add_vpp_config()
363
364         #
365         # MPLS decapsulation config
366         #
367         mpls_table = VppMplsTable(self, 0)
368         mpls_table.add_vpp_config()
369         mpls_route = VppMplsRoute(
370             self, 77, 1,
371             [VppRoutePath("0.0.0.0",
372                           0xFFFFFFFF,
373                           nh_table_id=2,
374                           proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
375         mpls_route.add_vpp_config()
376
377         #
378         # UDP over ipv4 decap
379         #
380         p_4 = (Ether(src=self.pg0.remote_mac,
381                      dst=self.pg0.local_mac) /
382                IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
383                UDP(sport=1111, dport=220) /
384                IP(src="2.2.2.2", dst="1.1.1.1") /
385                UDP(sport=1234, dport=4321) /
386                Raw(b'\xa5' * 100))
387
388         rx = self.send_and_expect(self.pg0, p_4*NUM_PKTS, self.pg0)
389         p_4 = IP(p_4["UDP"].payload)
390         for p in rx:
391             p = IP(p["Ether"].payload)
392             self.validate_inner4(p, p_4, ttl=63)
393
394         #
395         # UDP over ipv6 decap
396         #
397         p_6 = (Ether(src=self.pg1.remote_mac,
398                      dst=self.pg1.local_mac) /
399                IPv6(src=self.pg1.remote_ip6, dst=self.pg1.local_ip6) /
400                UDP(sport=2222, dport=221) /
401                IPv6(src="2001::100", dst="2001::1") /
402                UDP(sport=1234, dport=4321) /
403                Raw(b'\xa5' * 100))
404
405         rx = self.send_and_expect(self.pg1, p_6*NUM_PKTS, self.pg1)
406         p_6 = IPv6(p_6["UDP"].payload)
407         p = IPv6(rx[0]["Ether"].payload)
408         for p in rx:
409             p = IPv6(p["Ether"].payload)
410             self.validate_inner6(p, p_6, hlim=63)
411
412         #
413         # UDP over mpls decap
414         #
415         p_mo4 = (Ether(src=self.pg2.remote_mac,
416                        dst=self.pg2.local_mac) /
417                  IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4) /
418                  UDP(sport=3333, dport=222) /
419                  MPLS(label=77, ttl=1) /
420                  IP(src="4.4.4.4", dst="3.3.3.3") /
421                  UDP(sport=1234, dport=4321) /
422                  Raw(b'\xa5' * 100))
423
424         self.pg2.enable_mpls()
425         rx = self.send_and_expect(self.pg2, p_mo4*NUM_PKTS, self.pg2)
426         self.pg2.disable_mpls()
427         p_mo4 = IP(MPLS(p_mo4["UDP"].payload).payload)
428         for p in rx:
429             p = IP(p["Ether"].payload)
430             self.validate_inner4(p, p_mo4, ttl=63)
431
432
433 @tag_fixme_vpp_workers
434 class TestUDP(VppTestCase):
435     """ UDP Test Case """
436
437     @classmethod
438     def setUpClass(cls):
439         super(TestUDP, cls).setUpClass()
440
441     @classmethod
442     def tearDownClass(cls):
443         super(TestUDP, cls).tearDownClass()
444
445     def setUp(self):
446         super(TestUDP, self).setUp()
447         self.vapi.session_enable_disable(is_enable=1)
448         self.create_loopback_interfaces(2)
449
450         table_id = 0
451
452         for i in self.lo_interfaces:
453             i.admin_up()
454
455             if table_id != 0:
456                 tbl = VppIpTable(self, table_id)
457                 tbl.add_vpp_config()
458
459             i.set_table_ip4(table_id)
460             i.config_ip4()
461             table_id += 1
462
463         # Configure namespaces
464         self.vapi.app_namespace_add_del(namespace_id="0",
465                                         sw_if_index=self.loop0.sw_if_index)
466         self.vapi.app_namespace_add_del(namespace_id="1",
467                                         sw_if_index=self.loop1.sw_if_index)
468
469     def tearDown(self):
470         for i in self.lo_interfaces:
471             i.unconfig_ip4()
472             i.set_table_ip4(0)
473             i.admin_down()
474         self.vapi.session_enable_disable(is_enable=0)
475         super(TestUDP, self).tearDown()
476
477     def test_udp_transfer(self):
478         """ UDP echo client/server transfer """
479
480         # Add inter-table routes
481         ip_t01 = VppIpRoute(self, self.loop1.local_ip4, 32,
482                             [VppRoutePath("0.0.0.0",
483                                           0xffffffff,
484                                           nh_table_id=1)])
485         ip_t10 = VppIpRoute(self, self.loop0.local_ip4, 32,
486                             [VppRoutePath("0.0.0.0",
487                                           0xffffffff,
488                                           nh_table_id=0)], table_id=1)
489         ip_t01.add_vpp_config()
490         ip_t10.add_vpp_config()
491
492         # Start builtin server and client
493         uri = "udp://" + self.loop0.local_ip4 + "/1234"
494         error = self.vapi.cli("test echo server appns 0 fifo-size 4 no-echo" +
495                               "uri " + uri)
496         if error:
497             self.logger.critical(error)
498             self.assertNotIn("failed", error)
499
500         error = self.vapi.cli("test echo client mbytes 10 appns 1 " +
501                               "fifo-size 4 no-output test-bytes " +
502                               "syn-timeout 2 no-return uri " + uri)
503         if error:
504             self.logger.critical(error)
505             self.assertNotIn("failed", error)
506
507         self.logger.debug(self.vapi.cli("show session verbose 2"))
508
509         # Delete inter-table routes
510         ip_t01.remove_vpp_config()
511         ip_t10.remove_vpp_config()
512
513
514 if __name__ == '__main__':
515     unittest.main(testRunner=VppTestRunner)