vppapigen: support counters only .api
[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 (
9     VppIpRoute,
10     VppRoutePath,
11     VppIpTable,
12     VppMplsLabel,
13     VppMplsTable,
14     VppMplsRoute,
15     FibPathType,
16     FibPathProto,
17 )
18 from vpp_neighbor import VppNeighbor
19 from vpp_papi import VppEnum
20
21 from scapy.packet import Raw
22 from scapy.layers.l2 import Ether
23 from scapy.layers.inet import IP, UDP, ICMP
24 from scapy.layers.inet6 import IPv6
25 from scapy.contrib.mpls import MPLS
26
27 NUM_PKTS = 67
28 ENTROPY_PORT_MIN = 0x3 << 14
29 ENTROPY_PORT_MAX = 0xFFFF
30
31
32 @tag_fixme_vpp_workers
33 class TestUdpEncap(VppTestCase):
34     """UDP Encap Test Case"""
35
36     @classmethod
37     def setUpClass(cls):
38         super(TestUdpEncap, cls).setUpClass()
39
40     @classmethod
41     def tearDownClass(cls):
42         super(TestUdpEncap, cls).tearDownClass()
43
44     def setUp(self):
45         super(TestUdpEncap, self).setUp()
46
47         # create 2 pg interfaces
48         self.create_pg_interfaces(range(4))
49
50         # setup interfaces
51         # assign them different tables.
52         table_id = 0
53         self.tables = []
54
55         for i in self.pg_interfaces:
56             i.admin_up()
57
58             if table_id != 0:
59                 tbl = VppIpTable(self, table_id)
60                 tbl.add_vpp_config()
61                 self.tables.append(tbl)
62                 tbl = VppIpTable(self, table_id, is_ip6=1)
63                 tbl.add_vpp_config()
64                 self.tables.append(tbl)
65
66             i.set_table_ip4(table_id)
67             i.set_table_ip6(table_id)
68             i.config_ip4()
69             i.resolve_arp()
70             i.config_ip6()
71             i.resolve_ndp()
72             table_id += 1
73
74     def tearDown(self):
75         for i in self.pg_interfaces:
76             i.unconfig_ip4()
77             i.unconfig_ip6()
78             i.set_table_ip4(0)
79             i.set_table_ip6(0)
80             i.admin_down()
81         super(TestUdpEncap, self).tearDown()
82
83     def validate_outer4(self, rx, encap_obj, sport_entropy=False):
84         self.assertEqual(rx[IP].src, encap_obj.src_ip_s)
85         self.assertEqual(rx[IP].dst, encap_obj.dst_ip_s)
86         if sport_entropy:
87             self.assert_in_range(rx[UDP].sport, ENTROPY_PORT_MIN, ENTROPY_PORT_MAX)
88         else:
89             self.assertEqual(rx[UDP].sport, encap_obj.src_port)
90         self.assertEqual(rx[UDP].dport, encap_obj.dst_port)
91
92     def validate_outer6(self, rx, encap_obj, sport_entropy=False):
93         self.assertEqual(rx[IPv6].src, encap_obj.src_ip_s)
94         self.assertEqual(rx[IPv6].dst, encap_obj.dst_ip_s)
95         if sport_entropy:
96             self.assert_in_range(rx[UDP].sport, ENTROPY_PORT_MIN, ENTROPY_PORT_MAX)
97         else:
98             self.assertEqual(rx[UDP].sport, encap_obj.src_port)
99         self.assertEqual(rx[UDP].dport, encap_obj.dst_port)
100
101     def validate_inner4(self, rx, tx, ttl=None):
102         self.assertEqual(rx[IP].src, tx[IP].src)
103         self.assertEqual(rx[IP].dst, tx[IP].dst)
104         if ttl:
105             self.assertEqual(rx[IP].ttl, ttl)
106         else:
107             self.assertEqual(rx[IP].ttl, tx[IP].ttl)
108
109     def validate_inner6(self, rx, tx, hlim=None):
110         self.assertEqual(rx.src, tx[IPv6].src)
111         self.assertEqual(rx.dst, tx[IPv6].dst)
112         if hlim:
113             self.assertEqual(rx.hlim, hlim)
114         else:
115             self.assertEqual(rx.hlim, tx[IPv6].hlim)
116
117     def test_udp_encap(self):
118         """UDP Encap test"""
119
120         #
121         # construct a UDP encap object through each of the peers
122         # v4 through the first two peers, v6 through the second.
123         # The last encap is v4 and is used to check the codepath
124         # where 2 different udp encap objects are processed at the
125         # same time
126         #
127         udp_encap_0 = VppUdpEncap(
128             self, self.pg0.local_ip4, self.pg0.remote_ip4, 330, 440
129         )
130         udp_encap_1 = VppUdpEncap(
131             self, self.pg1.local_ip4, self.pg1.remote_ip4, 331, 441, table_id=1
132         )
133         udp_encap_2 = VppUdpEncap(
134             self, self.pg2.local_ip6, self.pg2.remote_ip6, 332, 442, table_id=2
135         )
136         udp_encap_3 = VppUdpEncap(
137             self, self.pg3.local_ip6, self.pg3.remote_ip6, 333, 443, table_id=3
138         )
139         udp_encap_4 = VppUdpEncap(
140             self, self.pg0.local_ip4, self.pg0.remote_ip4, 334, 444
141         )
142         udp_encap_0.add_vpp_config()
143         udp_encap_1.add_vpp_config()
144         udp_encap_2.add_vpp_config()
145         udp_encap_3.add_vpp_config()
146         udp_encap_4.add_vpp_config()
147
148         self.logger.info(self.vapi.cli("sh udp encap"))
149
150         self.assertTrue(find_udp_encap(self, udp_encap_2))
151         self.assertTrue(find_udp_encap(self, udp_encap_3))
152         self.assertTrue(find_udp_encap(self, udp_encap_0))
153         self.assertTrue(find_udp_encap(self, udp_encap_1))
154         self.assertTrue(find_udp_encap(self, udp_encap_4))
155
156         #
157         # Routes via each UDP encap object - all combinations of v4 and v6.
158         #
159         route_4o4 = VppIpRoute(
160             self,
161             "1.1.0.1",
162             24,
163             [
164                 VppRoutePath(
165                     "0.0.0.0",
166                     0xFFFFFFFF,
167                     type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
168                     next_hop_id=udp_encap_0.id,
169                     proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
170                 )
171             ],
172             table_id=1,
173         )
174         # specific route to match encap4, to test encap of 2 packets using 2
175         # different encap
176         route_4o4_2 = VppIpRoute(
177             self,
178             "1.1.0.2",
179             32,
180             [
181                 VppRoutePath(
182                     "0.0.0.0",
183                     0xFFFFFFFF,
184                     type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
185                     next_hop_id=udp_encap_4.id,
186                     proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
187                 )
188             ],
189             table_id=1,
190         )
191         route_4o6 = VppIpRoute(
192             self,
193             "1.1.2.1",
194             32,
195             [
196                 VppRoutePath(
197                     "0.0.0.0",
198                     0xFFFFFFFF,
199                     type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
200                     next_hop_id=udp_encap_2.id,
201                     proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
202                 )
203             ],
204         )
205         route_6o4 = VppIpRoute(
206             self,
207             "2001::1",
208             128,
209             [
210                 VppRoutePath(
211                     "0.0.0.0",
212                     0xFFFFFFFF,
213                     type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
214                     next_hop_id=udp_encap_1.id,
215                     proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
216                 )
217             ],
218         )
219         route_6o6 = VppIpRoute(
220             self,
221             "2001::3",
222             128,
223             [
224                 VppRoutePath(
225                     "0.0.0.0",
226                     0xFFFFFFFF,
227                     type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
228                     next_hop_id=udp_encap_3.id,
229                     proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
230                 )
231             ],
232         )
233         route_4o6.add_vpp_config()
234         route_6o6.add_vpp_config()
235         route_6o4.add_vpp_config()
236         route_4o4.add_vpp_config()
237         route_4o4_2.add_vpp_config()
238
239         #
240         # 4o4 encap
241         # we add a single packet matching the last encap at the beginning of
242         # the packet vector so that we encap 2 packets with different udp
243         # encap object at the same time
244         #
245         p_4o4 = (
246             Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
247             / IP(src="2.2.2.2", dst="1.1.0.1")
248             / UDP(sport=1234, dport=1234)
249             / Raw(b"\xa5" * 100)
250         )
251         p_4o4_2 = (
252             Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
253             / IP(src="2.2.2.2", dst="1.1.0.2")
254             / UDP(sport=1234, dport=1234)
255             / Raw(b"\xa5" * 100)
256         )
257         rx = self.send_and_expect(
258             self.pg1, p_4o4_2 * 1 + p_4o4 * (NUM_PKTS - 1), self.pg0
259         )
260         # checking encap4 magic packet
261         p = rx.pop(0)
262         self.validate_outer4(p, udp_encap_4)
263         p = IP(p["UDP"].payload.load)
264         self.validate_inner4(p, p_4o4_2)
265         self.assertEqual(udp_encap_4.get_stats()["packets"], 1)
266         # checking remaining packets for encap0
267         for p in rx:
268             self.validate_outer4(p, udp_encap_0)
269             p = IP(p["UDP"].payload.load)
270             self.validate_inner4(p, p_4o4)
271         self.assertEqual(udp_encap_0.get_stats()["packets"], NUM_PKTS - 1)
272
273         #
274         # 4o6 encap
275         #
276         p_4o6 = (
277             Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
278             / IP(src="2.2.2.2", dst="1.1.2.1")
279             / UDP(sport=1234, dport=1234)
280             / Raw(b"\xa5" * 100)
281         )
282         rx = self.send_and_expect(self.pg0, p_4o6 * NUM_PKTS, self.pg2)
283         for p in rx:
284             self.validate_outer6(p, udp_encap_2)
285             p = IP(p["UDP"].payload.load)
286             self.validate_inner4(p, p_4o6)
287         self.assertEqual(udp_encap_2.get_stats()["packets"], NUM_PKTS)
288
289         #
290         # 6o4 encap
291         #
292         p_6o4 = (
293             Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
294             / IPv6(src="2001::100", dst="2001::1")
295             / UDP(sport=1234, dport=1234)
296             / Raw(b"\xa5" * 100)
297         )
298         rx = self.send_and_expect(self.pg0, p_6o4 * NUM_PKTS, self.pg1)
299         for p in rx:
300             self.validate_outer4(p, udp_encap_1)
301             p = IPv6(p["UDP"].payload.load)
302             self.validate_inner6(p, p_6o4)
303         self.assertEqual(udp_encap_1.get_stats()["packets"], NUM_PKTS)
304
305         #
306         # 6o6 encap
307         #
308         p_6o6 = (
309             Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
310             / IPv6(src="2001::100", dst="2001::3")
311             / UDP(sport=1234, dport=1234)
312             / Raw(b"\xa5" * 100)
313         )
314         rx = self.send_and_expect(self.pg0, p_6o6 * NUM_PKTS, self.pg3)
315         for p in rx:
316             self.validate_outer6(p, udp_encap_3)
317             p = IPv6(p["UDP"].payload.load)
318             self.validate_inner6(p, p_6o6)
319         self.assertEqual(udp_encap_3.get_stats()["packets"], NUM_PKTS)
320
321         #
322         # A route with an output label
323         # the TTL of the inner packet is decremented on LSP ingress
324         #
325         route_4oMPLSo4 = VppIpRoute(
326             self,
327             "1.1.2.22",
328             32,
329             [
330                 VppRoutePath(
331                     "0.0.0.0",
332                     0xFFFFFFFF,
333                     type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
334                     next_hop_id=1,
335                     labels=[VppMplsLabel(66)],
336                 )
337             ],
338         )
339         route_4oMPLSo4.add_vpp_config()
340
341         p_4omo4 = (
342             Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
343             / IP(src="2.2.2.2", dst="1.1.2.22")
344             / UDP(sport=1234, dport=1234)
345             / Raw(b"\xa5" * 100)
346         )
347         rx = self.send_and_expect(self.pg0, p_4omo4 * NUM_PKTS, self.pg1)
348         for p in rx:
349             self.validate_outer4(p, udp_encap_1)
350             p = MPLS(p["UDP"].payload.load)
351             self.validate_inner4(p, p_4omo4, ttl=63)
352         self.assertEqual(udp_encap_1.get_stats()["packets"], 2 * NUM_PKTS)
353
354     def test_udp_encap_entropy(self):
355         """UDP Encap src port entropy test"""
356
357         #
358         # construct a UDP encap object through each of the peers
359         # v4 through the first two peers, v6 through the second.
360         # use zero source port to enable entropy per rfc7510.
361         #
362         udp_encap_0 = VppUdpEncap(self, self.pg0.local_ip4, self.pg0.remote_ip4, 0, 440)
363         udp_encap_1 = VppUdpEncap(
364             self, self.pg1.local_ip4, self.pg1.remote_ip4, 0, 441, table_id=1
365         )
366         udp_encap_2 = VppUdpEncap(
367             self, self.pg2.local_ip6, self.pg2.remote_ip6, 0, 442, table_id=2
368         )
369         udp_encap_3 = VppUdpEncap(
370             self, self.pg3.local_ip6, self.pg3.remote_ip6, 0, 443, table_id=3
371         )
372         udp_encap_0.add_vpp_config()
373         udp_encap_1.add_vpp_config()
374         udp_encap_2.add_vpp_config()
375         udp_encap_3.add_vpp_config()
376
377         self.logger.info(self.vapi.cli("sh udp encap"))
378
379         self.assertTrue(find_udp_encap(self, udp_encap_0))
380         self.assertTrue(find_udp_encap(self, udp_encap_1))
381         self.assertTrue(find_udp_encap(self, udp_encap_2))
382         self.assertTrue(find_udp_encap(self, udp_encap_3))
383
384         #
385         # Routes via each UDP encap object - all combinations of v4 and v6.
386         #
387         route_4o4 = VppIpRoute(
388             self,
389             "1.1.0.1",
390             24,
391             [
392                 VppRoutePath(
393                     "0.0.0.0",
394                     0xFFFFFFFF,
395                     type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
396                     next_hop_id=udp_encap_0.id,
397                     proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
398                 )
399             ],
400             table_id=1,
401         )
402         route_4o6 = VppIpRoute(
403             self,
404             "1.1.2.1",
405             32,
406             [
407                 VppRoutePath(
408                     "0.0.0.0",
409                     0xFFFFFFFF,
410                     type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
411                     next_hop_id=udp_encap_2.id,
412                     proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
413                 )
414             ],
415         )
416         route_6o4 = VppIpRoute(
417             self,
418             "2001::1",
419             128,
420             [
421                 VppRoutePath(
422                     "0.0.0.0",
423                     0xFFFFFFFF,
424                     type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
425                     next_hop_id=udp_encap_1.id,
426                     proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
427                 )
428             ],
429         )
430         route_6o6 = VppIpRoute(
431             self,
432             "2001::3",
433             128,
434             [
435                 VppRoutePath(
436                     "0.0.0.0",
437                     0xFFFFFFFF,
438                     type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
439                     next_hop_id=udp_encap_3.id,
440                     proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
441                 )
442             ],
443         )
444         route_4o4.add_vpp_config()
445         route_4o6.add_vpp_config()
446         route_6o6.add_vpp_config()
447         route_6o4.add_vpp_config()
448
449         #
450         # 4o4 encap
451         #
452         p_4o4 = []
453         for i in range(NUM_PKTS):
454             p_4o4.append(
455                 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
456                 / IP(src="2.2.2.2", dst="1.1.0.1")
457                 / UDP(sport=1234 + i, dport=1234)
458                 / Raw(b"\xa5" * 100)
459             )
460         rx = self.send_and_expect(self.pg1, p_4o4, self.pg0)
461         sports = set()
462         for i, p in enumerate(rx):
463             self.validate_outer4(p, udp_encap_0, True)
464             sports.add(p["UDP"].sport)
465             p = IP(p["UDP"].payload.load)
466             self.validate_inner4(p, p_4o4[i])
467         self.assertEqual(udp_encap_0.get_stats()["packets"], NUM_PKTS)
468         self.assertGreater(
469             len(sports), 1, "source port {} is not an entropy value".format(sports)
470         )
471
472         #
473         # 4o6 encap
474         #
475         p_4o6 = []
476         for i in range(NUM_PKTS):
477             p_4o6.append(
478                 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
479                 / IP(src="2.2.2.2", dst="1.1.2.1")
480                 / UDP(sport=1234 + i, dport=1234)
481                 / Raw(b"\xa5" * 100)
482             )
483         rx = self.send_and_expect(self.pg0, p_4o6, self.pg2)
484         sports = set()
485         for p in rx:
486             self.validate_outer6(p, udp_encap_2, True)
487             sports.add(p["UDP"].sport)
488             p = IP(p["UDP"].payload.load)
489             self.validate_inner4(p, p_4o6[i])
490         self.assertEqual(udp_encap_2.get_stats()["packets"], NUM_PKTS)
491         self.assertGreater(
492             len(sports), 1, "source port {} is not an entropy value".format(sports)
493         )
494
495         #
496         # 6o4 encap
497         #
498         p_6o4 = []
499         for i in range(NUM_PKTS):
500             p_6o4.append(
501                 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
502                 / IPv6(src="2001::100", dst="2001::1")
503                 / UDP(sport=1234 + i, dport=1234)
504                 / Raw(b"\xa5" * 100)
505             )
506         rx = self.send_and_expect(self.pg0, p_6o4, self.pg1)
507         sports = set()
508         for p in rx:
509             self.validate_outer4(p, udp_encap_1, True)
510             sports.add(p["UDP"].sport)
511             p = IPv6(p["UDP"].payload.load)
512             self.validate_inner6(p, p_6o4[i])
513         self.assertEqual(udp_encap_1.get_stats()["packets"], NUM_PKTS)
514         self.assertGreater(
515             len(sports), 1, "source port {} is not an entropy value".format(sports)
516         )
517
518         #
519         # 6o6 encap
520         #
521         p_6o6 = []
522         for i in range(NUM_PKTS):
523             p_6o6.append(
524                 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
525                 / IPv6(src="2001::100", dst="2001::3")
526                 / UDP(sport=1234 + i, dport=1234)
527                 / Raw(b"\xa5" * 100)
528             )
529         rx = self.send_and_expect(self.pg0, p_6o6, self.pg3)
530         sports = set()
531         for p in rx:
532             self.validate_outer6(p, udp_encap_3, True)
533             sports.add(p["UDP"].sport)
534             p = IPv6(p["UDP"].payload.load)
535             self.validate_inner6(p, p_6o6[i])
536         self.assertEqual(udp_encap_3.get_stats()["packets"], NUM_PKTS)
537         self.assertGreater(
538             len(sports), 1, "source port {} is not an entropy value".format(sports)
539         )
540
541     def test_udp_decap(self):
542         """UDP Decap test"""
543         #
544         # construct a UDP decap object for each type of protocol
545         #
546
547         # IPv4
548         udp_api_proto = VppEnum.vl_api_udp_decap_next_proto_t
549         next_proto = udp_api_proto.UDP_API_DECAP_PROTO_IP4
550         udp_decap_0 = VppUdpDecap(self, 1, 220, next_proto)
551
552         # IPv6
553         next_proto = udp_api_proto.UDP_API_DECAP_PROTO_IP6
554         udp_decap_1 = VppUdpDecap(self, 0, 221, next_proto)
555
556         # MPLS
557         next_proto = udp_api_proto.UDP_API_DECAP_PROTO_MPLS
558         udp_decap_2 = VppUdpDecap(self, 1, 222, next_proto)
559
560         udp_decap_0.add_vpp_config()
561         udp_decap_1.add_vpp_config()
562         udp_decap_2.add_vpp_config()
563
564         #
565         # Routes via the corresponding pg after the UDP decap
566         #
567         route_4 = VppIpRoute(
568             self,
569             "1.1.1.1",
570             32,
571             [VppRoutePath("0.0.0.0", self.pg0.sw_if_index)],
572             table_id=0,
573         )
574
575         route_6 = VppIpRoute(
576             self, "2001::1", 128, [VppRoutePath("::", self.pg1.sw_if_index)], table_id=1
577         )
578
579         route_mo4 = VppIpRoute(
580             self,
581             "3.3.3.3",
582             32,
583             [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)],
584             table_id=2,
585         )
586
587         route_4.add_vpp_config()
588         route_6.add_vpp_config()
589         route_mo4.add_vpp_config()
590
591         #
592         # Adding neighbors to route the packets
593         #
594         n_4 = VppNeighbor(self, self.pg0.sw_if_index, "00:11:22:33:44:55", "1.1.1.1")
595         n_6 = VppNeighbor(self, self.pg1.sw_if_index, "11:22:33:44:55:66", "2001::1")
596         n_mo4 = VppNeighbor(self, self.pg2.sw_if_index, "22:33:44:55:66:77", "3.3.3.3")
597
598         n_4.add_vpp_config()
599         n_6.add_vpp_config()
600         n_mo4.add_vpp_config()
601
602         #
603         # MPLS decapsulation config
604         #
605         mpls_table = VppMplsTable(self, 0)
606         mpls_table.add_vpp_config()
607         mpls_route = VppMplsRoute(
608             self,
609             77,
610             1,
611             [
612                 VppRoutePath(
613                     "0.0.0.0",
614                     0xFFFFFFFF,
615                     nh_table_id=2,
616                     proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
617                 )
618             ],
619         )
620         mpls_route.add_vpp_config()
621
622         #
623         # UDP over ipv4 decap
624         #
625         p_4 = (
626             Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
627             / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
628             / UDP(sport=1111, dport=220)
629             / IP(src="2.2.2.2", dst="1.1.1.1")
630             / UDP(sport=1234, dport=4321)
631             / Raw(b"\xa5" * 100)
632         )
633
634         rx = self.send_and_expect(self.pg0, p_4 * NUM_PKTS, self.pg0)
635         p_4 = IP(p_4["UDP"].payload)
636         for p in rx:
637             p = IP(p["Ether"].payload)
638             self.validate_inner4(p, p_4, ttl=63)
639
640         #
641         # UDP over ipv6 decap
642         #
643         p_6 = (
644             Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
645             / IPv6(src=self.pg1.remote_ip6, dst=self.pg1.local_ip6)
646             / UDP(sport=2222, dport=221)
647             / IPv6(src="2001::100", dst="2001::1")
648             / UDP(sport=1234, dport=4321)
649             / Raw(b"\xa5" * 100)
650         )
651
652         rx = self.send_and_expect(self.pg1, p_6 * NUM_PKTS, self.pg1)
653         p_6 = IPv6(p_6["UDP"].payload)
654         p = IPv6(rx[0]["Ether"].payload)
655         for p in rx:
656             p = IPv6(p["Ether"].payload)
657             self.validate_inner6(p, p_6, hlim=63)
658
659         #
660         # UDP over mpls decap
661         #
662         p_mo4 = (
663             Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
664             / IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4)
665             / UDP(sport=3333, dport=222)
666             / MPLS(label=77, ttl=1)
667             / IP(src="4.4.4.4", dst="3.3.3.3")
668             / UDP(sport=1234, dport=4321)
669             / Raw(b"\xa5" * 100)
670         )
671
672         self.pg2.enable_mpls()
673         rx = self.send_and_expect(self.pg2, p_mo4 * NUM_PKTS, self.pg2)
674         self.pg2.disable_mpls()
675         p_mo4 = IP(MPLS(p_mo4["UDP"].payload).payload)
676         for p in rx:
677             p = IP(p["Ether"].payload)
678             self.validate_inner4(p, p_mo4, ttl=63)
679
680
681 @tag_fixme_vpp_workers
682 class TestUDP(VppTestCase):
683     """UDP Test Case"""
684
685     @classmethod
686     def setUpClass(cls):
687         super(TestUDP, cls).setUpClass()
688
689     @classmethod
690     def tearDownClass(cls):
691         super(TestUDP, cls).tearDownClass()
692
693     def setUp(self):
694         super(TestUDP, self).setUp()
695         self.vapi.session_enable_disable(is_enable=1)
696         self.create_loopback_interfaces(2)
697
698         table_id = 0
699
700         for i in self.lo_interfaces:
701             i.admin_up()
702
703             if table_id != 0:
704                 tbl = VppIpTable(self, table_id)
705                 tbl.add_vpp_config()
706
707             i.set_table_ip4(table_id)
708             i.config_ip4()
709             table_id += 1
710
711         # Configure namespaces
712         self.vapi.app_namespace_add_del_v4(
713             namespace_id="0", sw_if_index=self.loop0.sw_if_index
714         )
715         self.vapi.app_namespace_add_del_v4(
716             namespace_id="1", sw_if_index=self.loop1.sw_if_index
717         )
718
719     def tearDown(self):
720         for i in self.lo_interfaces:
721             i.unconfig_ip4()
722             i.set_table_ip4(0)
723             i.admin_down()
724         self.vapi.session_enable_disable(is_enable=0)
725         super(TestUDP, self).tearDown()
726
727     def test_udp_transfer(self):
728         """UDP echo client/server transfer"""
729
730         # Add inter-table routes
731         ip_t01 = VppIpRoute(
732             self,
733             self.loop1.local_ip4,
734             32,
735             [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=1)],
736         )
737         ip_t10 = VppIpRoute(
738             self,
739             self.loop0.local_ip4,
740             32,
741             [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=0)],
742             table_id=1,
743         )
744         ip_t01.add_vpp_config()
745         ip_t10.add_vpp_config()
746
747         # Start builtin server and client
748         uri = "udp://" + self.loop0.local_ip4 + "/1234"
749         error = self.vapi.cli(
750             "test echo server appns 0 fifo-size 4 no-echo" + "uri " + uri
751         )
752         if error:
753             self.logger.critical(error)
754             self.assertNotIn("failed", error)
755
756         error = self.vapi.cli(
757             "test echo client mbytes 10 appns 1 "
758             + "fifo-size 4 no-output test-bytes "
759             + "syn-timeout 2 no-return uri "
760             + uri
761         )
762         if error:
763             self.logger.critical(error)
764             self.assertNotIn("failed", error)
765
766         self.logger.debug(self.vapi.cli("show session verbose 2"))
767
768         # Delete inter-table routes
769         ip_t01.remove_vpp_config()
770         ip_t10.remove_vpp_config()
771
772
773 if __name__ == "__main__":
774     unittest.main(testRunner=VppTestRunner)