818510555462f5875994a27e7d22ec624dc881c6
[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         #
109         udp_encap_0 = VppUdpEncap(self,
110                                   self.pg0.local_ip4,
111                                   self.pg0.remote_ip4,
112                                   330, 440)
113         udp_encap_1 = VppUdpEncap(self,
114                                   self.pg1.local_ip4,
115                                   self.pg1.remote_ip4,
116                                   331, 441,
117                                   table_id=1)
118         udp_encap_2 = VppUdpEncap(self,
119                                   self.pg2.local_ip6,
120                                   self.pg2.remote_ip6,
121                                   332, 442,
122                                   table_id=2)
123         udp_encap_3 = VppUdpEncap(self,
124                                   self.pg3.local_ip6,
125                                   self.pg3.remote_ip6,
126                                   333, 443,
127                                   table_id=3)
128         udp_encap_0.add_vpp_config()
129         udp_encap_1.add_vpp_config()
130         udp_encap_2.add_vpp_config()
131         udp_encap_3.add_vpp_config()
132
133         self.logger.info(self.vapi.cli("sh udp encap"))
134
135         self.assertTrue(find_udp_encap(self, udp_encap_2))
136         self.assertTrue(find_udp_encap(self, udp_encap_3))
137         self.assertTrue(find_udp_encap(self, udp_encap_0))
138         self.assertTrue(find_udp_encap(self, udp_encap_1))
139
140         #
141         # Routes via each UDP encap object - all combinations of v4 and v6.
142         #
143         route_4o4 = VppIpRoute(
144             self, "1.1.0.1", 24,
145             [VppRoutePath("0.0.0.0",
146                           0xFFFFFFFF,
147                           type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
148                           next_hop_id=udp_encap_0.id,
149                           proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)],
150             table_id=1)
151         route_4o6 = VppIpRoute(
152             self, "1.1.2.1", 32,
153             [VppRoutePath("0.0.0.0",
154                           0xFFFFFFFF,
155                           type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
156                           next_hop_id=udp_encap_2.id,
157                           proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
158         route_6o4 = VppIpRoute(
159             self, "2001::1", 128,
160             [VppRoutePath("0.0.0.0",
161                           0xFFFFFFFF,
162                           type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
163                           next_hop_id=udp_encap_1.id,
164                           proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
165         route_6o6 = VppIpRoute(
166             self, "2001::3", 128,
167             [VppRoutePath("0.0.0.0",
168                           0xFFFFFFFF,
169                           type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
170                           next_hop_id=udp_encap_3.id,
171                           proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)])
172         route_4o6.add_vpp_config()
173         route_6o6.add_vpp_config()
174         route_6o4.add_vpp_config()
175         route_4o4.add_vpp_config()
176
177         #
178         # 4o4 encap
179         #
180         p_4o4 = (Ether(src=self.pg1.remote_mac,
181                        dst=self.pg1.local_mac) /
182                  IP(src="2.2.2.2", dst="1.1.0.1") /
183                  UDP(sport=1234, dport=1234) /
184                  Raw(b'\xa5' * 100))
185         rx = self.send_and_expect(self.pg1, p_4o4*NUM_PKTS, self.pg0)
186         for p in rx:
187             self.validate_outer4(p, udp_encap_0)
188             p = IP(p["UDP"].payload.load)
189             self.validate_inner4(p, p_4o4)
190         self.assertEqual(udp_encap_0.get_stats()['packets'], NUM_PKTS)
191
192         #
193         # 4o6 encap
194         #
195         p_4o6 = (Ether(src=self.pg0.remote_mac,
196                        dst=self.pg0.local_mac) /
197                  IP(src="2.2.2.2", dst="1.1.2.1") /
198                  UDP(sport=1234, dport=1234) /
199                  Raw(b'\xa5' * 100))
200         rx = self.send_and_expect(self.pg0, p_4o6*NUM_PKTS, self.pg2)
201         for p in rx:
202             self.validate_outer6(p, udp_encap_2)
203             p = IP(p["UDP"].payload.load)
204             self.validate_inner4(p, p_4o6)
205         self.assertEqual(udp_encap_2.get_stats()['packets'], NUM_PKTS)
206
207         #
208         # 6o4 encap
209         #
210         p_6o4 = (Ether(src=self.pg0.remote_mac,
211                        dst=self.pg0.local_mac) /
212                  IPv6(src="2001::100", dst="2001::1") /
213                  UDP(sport=1234, dport=1234) /
214                  Raw(b'\xa5' * 100))
215         rx = self.send_and_expect(self.pg0, p_6o4*NUM_PKTS, self.pg1)
216         for p in rx:
217             self.validate_outer4(p, udp_encap_1)
218             p = IPv6(p["UDP"].payload.load)
219             self.validate_inner6(p, p_6o4)
220         self.assertEqual(udp_encap_1.get_stats()['packets'], NUM_PKTS)
221
222         #
223         # 6o6 encap
224         #
225         p_6o6 = (Ether(src=self.pg0.remote_mac,
226                        dst=self.pg0.local_mac) /
227                  IPv6(src="2001::100", dst="2001::3") /
228                  UDP(sport=1234, dport=1234) /
229                  Raw(b'\xa5' * 100))
230         rx = self.send_and_expect(self.pg0, p_6o6*NUM_PKTS, self.pg3)
231         for p in rx:
232             self.validate_outer6(p, udp_encap_3)
233             p = IPv6(p["UDP"].payload.load)
234             self.validate_inner6(p, p_6o6)
235         self.assertEqual(udp_encap_3.get_stats()['packets'], NUM_PKTS)
236
237         #
238         # A route with an output label
239         # the TTL of the inner packet is decremented on LSP ingress
240         #
241         route_4oMPLSo4 = VppIpRoute(
242             self, "1.1.2.22", 32,
243             [VppRoutePath("0.0.0.0",
244                           0xFFFFFFFF,
245                           type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
246                           next_hop_id=1,
247                           labels=[VppMplsLabel(66)])])
248         route_4oMPLSo4.add_vpp_config()
249
250         p_4omo4 = (Ether(src=self.pg0.remote_mac,
251                          dst=self.pg0.local_mac) /
252                    IP(src="2.2.2.2", dst="1.1.2.22") /
253                    UDP(sport=1234, dport=1234) /
254                    Raw(b'\xa5' * 100))
255         rx = self.send_and_expect(self.pg0, p_4omo4*NUM_PKTS, self.pg1)
256         for p in rx:
257             self.validate_outer4(p, udp_encap_1)
258             p = MPLS(p["UDP"].payload.load)
259             self.validate_inner4(p, p_4omo4, ttl=63)
260         self.assertEqual(udp_encap_1.get_stats()['packets'], 2*NUM_PKTS)
261
262     def test_udp_decap(self):
263         """ UDP Decap test
264         """
265         #
266         # construct a UDP decap object for each type of protocol
267         #
268
269         # IPv4
270         udp_api_proto = VppEnum.vl_api_udp_decap_next_proto_t
271         next_proto = udp_api_proto.UDP_API_DECAP_PROTO_IP4
272         udp_decap_0 = VppUdpDecap(self, 1, 220, next_proto)
273
274         # IPv6
275         next_proto = udp_api_proto.UDP_API_DECAP_PROTO_IP6
276         udp_decap_1 = VppUdpDecap(self, 0, 221, next_proto)
277
278         # MPLS
279         next_proto = udp_api_proto.UDP_API_DECAP_PROTO_MPLS
280         udp_decap_2 = VppUdpDecap(self, 1, 222, next_proto)
281
282         udp_decap_0.add_vpp_config()
283         udp_decap_1.add_vpp_config()
284         udp_decap_2.add_vpp_config()
285
286         #
287         # Routes via the corresponding pg after the UDP decap
288         #
289         route_4 = VppIpRoute(
290             self, "1.1.1.1", 32,
291             [VppRoutePath("0.0.0.0", self.pg0.sw_if_index)],
292             table_id=0)
293
294         route_6 = VppIpRoute(
295             self, "2001::1", 128,
296             [VppRoutePath("::", self.pg1.sw_if_index)],
297             table_id=1)
298
299         route_mo4 = VppIpRoute(
300             self, "3.3.3.3", 32,
301             [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)],
302             table_id=2)
303
304         route_4.add_vpp_config()
305         route_6.add_vpp_config()
306         route_mo4.add_vpp_config()
307
308         #
309         # Adding neighbors to route the packets
310         #
311         n_4 = VppNeighbor(self,
312                           self.pg0.sw_if_index,
313                           "00:11:22:33:44:55",
314                           "1.1.1.1")
315         n_6 = VppNeighbor(self,
316                           self.pg1.sw_if_index,
317                           "11:22:33:44:55:66",
318                           "2001::1")
319         n_mo4 = VppNeighbor(self,
320                             self.pg2.sw_if_index,
321                             "22:33:44:55:66:77",
322                             "3.3.3.3")
323
324         n_4.add_vpp_config()
325         n_6.add_vpp_config()
326         n_mo4.add_vpp_config()
327
328         #
329         # MPLS decapsulation config
330         #
331         mpls_table = VppMplsTable(self, 0)
332         mpls_table.add_vpp_config()
333         mpls_route = VppMplsRoute(
334             self, 77, 1,
335             [VppRoutePath("0.0.0.0",
336                           0xFFFFFFFF,
337                           nh_table_id=2,
338                           proto=FibPathProto.FIB_PATH_NH_PROTO_IP4)])
339         mpls_route.add_vpp_config()
340
341         #
342         # UDP over ipv4 decap
343         #
344         p_4 = (Ether(src=self.pg0.remote_mac,
345                      dst=self.pg0.local_mac) /
346                IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
347                UDP(sport=1111, dport=220) /
348                IP(src="2.2.2.2", dst="1.1.1.1") /
349                UDP(sport=1234, dport=4321) /
350                Raw(b'\xa5' * 100))
351
352         rx = self.send_and_expect(self.pg0, p_4*NUM_PKTS, self.pg0)
353         p_4 = IP(p_4["UDP"].payload)
354         for p in rx:
355             p = IP(p["Ether"].payload)
356             self.validate_inner4(p, p_4, ttl=63)
357
358         #
359         # UDP over ipv6 decap
360         #
361         p_6 = (Ether(src=self.pg1.remote_mac,
362                      dst=self.pg1.local_mac) /
363                IPv6(src=self.pg1.remote_ip6, dst=self.pg1.local_ip6) /
364                UDP(sport=2222, dport=221) /
365                IPv6(src="2001::100", dst="2001::1") /
366                UDP(sport=1234, dport=4321) /
367                Raw(b'\xa5' * 100))
368
369         rx = self.send_and_expect(self.pg1, p_6*NUM_PKTS, self.pg1)
370         p_6 = IPv6(p_6["UDP"].payload)
371         p = IPv6(rx[0]["Ether"].payload)
372         for p in rx:
373             p = IPv6(p["Ether"].payload)
374             self.validate_inner6(p, p_6, hlim=63)
375
376         #
377         # UDP over mpls decap
378         #
379         p_mo4 = (Ether(src=self.pg2.remote_mac,
380                        dst=self.pg2.local_mac) /
381                  IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4) /
382                  UDP(sport=3333, dport=222) /
383                  MPLS(label=77, ttl=1) /
384                  IP(src="4.4.4.4", dst="3.3.3.3") /
385                  UDP(sport=1234, dport=4321) /
386                  Raw(b'\xa5' * 100))
387
388         self.pg2.enable_mpls()
389         rx = self.send_and_expect(self.pg2, p_mo4*NUM_PKTS, self.pg2)
390         self.pg2.disable_mpls()
391         p_mo4 = IP(MPLS(p_mo4["UDP"].payload).payload)
392         for p in rx:
393             p = IP(p["Ether"].payload)
394             self.validate_inner4(p, p_mo4, ttl=63)
395
396
397 @tag_fixme_vpp_workers
398 class TestUDP(VppTestCase):
399     """ UDP Test Case """
400
401     @classmethod
402     def setUpClass(cls):
403         super(TestUDP, cls).setUpClass()
404
405     @classmethod
406     def tearDownClass(cls):
407         super(TestUDP, cls).tearDownClass()
408
409     def setUp(self):
410         super(TestUDP, self).setUp()
411         self.vapi.session_enable_disable(is_enable=1)
412         self.create_loopback_interfaces(2)
413
414         table_id = 0
415
416         for i in self.lo_interfaces:
417             i.admin_up()
418
419             if table_id != 0:
420                 tbl = VppIpTable(self, table_id)
421                 tbl.add_vpp_config()
422
423             i.set_table_ip4(table_id)
424             i.config_ip4()
425             table_id += 1
426
427         # Configure namespaces
428         self.vapi.app_namespace_add_del(namespace_id="0",
429                                         sw_if_index=self.loop0.sw_if_index)
430         self.vapi.app_namespace_add_del(namespace_id="1",
431                                         sw_if_index=self.loop1.sw_if_index)
432
433     def tearDown(self):
434         for i in self.lo_interfaces:
435             i.unconfig_ip4()
436             i.set_table_ip4(0)
437             i.admin_down()
438         self.vapi.session_enable_disable(is_enable=0)
439         super(TestUDP, self).tearDown()
440
441     def test_udp_transfer(self):
442         """ UDP echo client/server transfer """
443
444         # Add inter-table routes
445         ip_t01 = VppIpRoute(self, self.loop1.local_ip4, 32,
446                             [VppRoutePath("0.0.0.0",
447                                           0xffffffff,
448                                           nh_table_id=1)])
449         ip_t10 = VppIpRoute(self, self.loop0.local_ip4, 32,
450                             [VppRoutePath("0.0.0.0",
451                                           0xffffffff,
452                                           nh_table_id=0)], table_id=1)
453         ip_t01.add_vpp_config()
454         ip_t10.add_vpp_config()
455
456         # Start builtin server and client
457         uri = "udp://" + self.loop0.local_ip4 + "/1234"
458         error = self.vapi.cli("test echo server appns 0 fifo-size 4 no-echo" +
459                               "uri " + uri)
460         if error:
461             self.logger.critical(error)
462             self.assertNotIn("failed", error)
463
464         error = self.vapi.cli("test echo client mbytes 10 appns 1 " +
465                               "fifo-size 4 no-output test-bytes " +
466                               "syn-timeout 2 no-return uri " + uri)
467         if error:
468             self.logger.critical(error)
469             self.assertNotIn("failed", error)
470
471         self.logger.debug(self.vapi.cli("show session verbose 2"))
472
473         # Delete inter-table routes
474         ip_t01.remove_vpp_config()
475         ip_t10.remove_vpp_config()
476
477
478 if __name__ == '__main__':
479     unittest.main(testRunner=VppTestRunner)