3 from framework import tag_fixme_vpp_workers
4 from framework import VppTestCase, VppTestRunner
6 from vpp_udp_encap import find_udp_encap, VppUdpEncap
7 from vpp_udp_decap import VppUdpDecap
8 from vpp_ip_route import (
18 from vpp_neighbor import VppNeighbor
19 from vpp_papi import VppEnum
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
30 @tag_fixme_vpp_workers
31 class TestUdpEncap(VppTestCase):
32 """UDP Encap Test Case"""
36 super(TestUdpEncap, cls).setUpClass()
39 def tearDownClass(cls):
40 super(TestUdpEncap, cls).tearDownClass()
43 super(TestUdpEncap, self).setUp()
45 # create 2 pg interfaces
46 self.create_pg_interfaces(range(4))
49 # assign them different tables.
53 for i in self.pg_interfaces:
57 tbl = VppIpTable(self, table_id)
59 self.tables.append(tbl)
60 tbl = VppIpTable(self, table_id, is_ip6=1)
62 self.tables.append(tbl)
64 i.set_table_ip4(table_id)
65 i.set_table_ip6(table_id)
73 for i in self.pg_interfaces:
79 super(TestUdpEncap, self).tearDown()
81 def validate_outer4(self, rx, encap_obj):
82 self.assertEqual(rx[IP].src, encap_obj.src_ip_s)
83 self.assertEqual(rx[IP].dst, encap_obj.dst_ip_s)
84 self.assertEqual(rx[UDP].sport, encap_obj.src_port)
85 self.assertEqual(rx[UDP].dport, encap_obj.dst_port)
87 def validate_outer6(self, rx, encap_obj):
88 self.assertEqual(rx[IPv6].src, encap_obj.src_ip_s)
89 self.assertEqual(rx[IPv6].dst, encap_obj.dst_ip_s)
90 self.assertEqual(rx[UDP].sport, encap_obj.src_port)
91 self.assertEqual(rx[UDP].dport, encap_obj.dst_port)
93 def validate_inner4(self, rx, tx, ttl=None):
94 self.assertEqual(rx[IP].src, tx[IP].src)
95 self.assertEqual(rx[IP].dst, tx[IP].dst)
97 self.assertEqual(rx[IP].ttl, ttl)
99 self.assertEqual(rx[IP].ttl, tx[IP].ttl)
101 def validate_inner6(self, rx, tx, hlim=None):
102 self.assertEqual(rx.src, tx[IPv6].src)
103 self.assertEqual(rx.dst, tx[IPv6].dst)
105 self.assertEqual(rx.hlim, hlim)
107 self.assertEqual(rx.hlim, tx[IPv6].hlim)
109 def test_udp_encap(self):
113 # construct a UDP encap object through each of the peers
114 # v4 through the first two peers, v6 through the second.
115 # The last encap is v4 and is used to check the codepath
116 # where 2 different udp encap objects are processed at the
119 udp_encap_0 = VppUdpEncap(
120 self, self.pg0.local_ip4, self.pg0.remote_ip4, 330, 440
122 udp_encap_1 = VppUdpEncap(
123 self, self.pg1.local_ip4, self.pg1.remote_ip4, 331, 441, table_id=1
125 udp_encap_2 = VppUdpEncap(
126 self, self.pg2.local_ip6, self.pg2.remote_ip6, 332, 442, table_id=2
128 udp_encap_3 = VppUdpEncap(
129 self, self.pg3.local_ip6, self.pg3.remote_ip6, 333, 443, table_id=3
131 udp_encap_4 = VppUdpEncap(
132 self, self.pg0.local_ip4, self.pg0.remote_ip4, 334, 444
134 udp_encap_0.add_vpp_config()
135 udp_encap_1.add_vpp_config()
136 udp_encap_2.add_vpp_config()
137 udp_encap_3.add_vpp_config()
138 udp_encap_4.add_vpp_config()
140 self.logger.info(self.vapi.cli("sh udp encap"))
142 self.assertTrue(find_udp_encap(self, udp_encap_2))
143 self.assertTrue(find_udp_encap(self, udp_encap_3))
144 self.assertTrue(find_udp_encap(self, udp_encap_0))
145 self.assertTrue(find_udp_encap(self, udp_encap_1))
146 self.assertTrue(find_udp_encap(self, udp_encap_4))
149 # Routes via each UDP encap object - all combinations of v4 and v6.
151 route_4o4 = VppIpRoute(
159 type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
160 next_hop_id=udp_encap_0.id,
161 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
166 # specific route to match encap4, to test encap of 2 packets using 2
168 route_4o4_2 = VppIpRoute(
176 type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
177 next_hop_id=udp_encap_4.id,
178 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
183 route_4o6 = VppIpRoute(
191 type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
192 next_hop_id=udp_encap_2.id,
193 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
197 route_6o4 = VppIpRoute(
205 type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
206 next_hop_id=udp_encap_1.id,
207 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
211 route_6o6 = VppIpRoute(
219 type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
220 next_hop_id=udp_encap_3.id,
221 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
225 route_4o6.add_vpp_config()
226 route_6o6.add_vpp_config()
227 route_6o4.add_vpp_config()
228 route_4o4.add_vpp_config()
229 route_4o4_2.add_vpp_config()
233 # we add a single packet matching the last encap at the beginning of
234 # the packet vector so that we encap 2 packets with different udp
235 # encap object at the same time
238 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
239 / IP(src="2.2.2.2", dst="1.1.0.1")
240 / UDP(sport=1234, dport=1234)
244 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
245 / IP(src="2.2.2.2", dst="1.1.0.2")
246 / UDP(sport=1234, dport=1234)
249 rx = self.send_and_expect(
250 self.pg1, p_4o4_2 * 1 + p_4o4 * (NUM_PKTS - 1), self.pg0
252 # checking encap4 magic packet
254 self.validate_outer4(p, udp_encap_4)
255 p = IP(p["UDP"].payload.load)
256 self.validate_inner4(p, p_4o4_2)
257 self.assertEqual(udp_encap_4.get_stats()["packets"], 1)
258 # checking remaining packets for encap0
260 self.validate_outer4(p, udp_encap_0)
261 p = IP(p["UDP"].payload.load)
262 self.validate_inner4(p, p_4o4)
263 self.assertEqual(udp_encap_0.get_stats()["packets"], NUM_PKTS - 1)
269 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
270 / IP(src="2.2.2.2", dst="1.1.2.1")
271 / UDP(sport=1234, dport=1234)
274 rx = self.send_and_expect(self.pg0, p_4o6 * NUM_PKTS, self.pg2)
276 self.validate_outer6(p, udp_encap_2)
277 p = IP(p["UDP"].payload.load)
278 self.validate_inner4(p, p_4o6)
279 self.assertEqual(udp_encap_2.get_stats()["packets"], NUM_PKTS)
285 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
286 / IPv6(src="2001::100", dst="2001::1")
287 / UDP(sport=1234, dport=1234)
290 rx = self.send_and_expect(self.pg0, p_6o4 * NUM_PKTS, self.pg1)
292 self.validate_outer4(p, udp_encap_1)
293 p = IPv6(p["UDP"].payload.load)
294 self.validate_inner6(p, p_6o4)
295 self.assertEqual(udp_encap_1.get_stats()["packets"], NUM_PKTS)
301 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
302 / IPv6(src="2001::100", dst="2001::3")
303 / UDP(sport=1234, dport=1234)
306 rx = self.send_and_expect(self.pg0, p_6o6 * NUM_PKTS, self.pg3)
308 self.validate_outer6(p, udp_encap_3)
309 p = IPv6(p["UDP"].payload.load)
310 self.validate_inner6(p, p_6o6)
311 self.assertEqual(udp_encap_3.get_stats()["packets"], NUM_PKTS)
314 # A route with an output label
315 # the TTL of the inner packet is decremented on LSP ingress
317 route_4oMPLSo4 = VppIpRoute(
325 type=FibPathType.FIB_PATH_TYPE_UDP_ENCAP,
327 labels=[VppMplsLabel(66)],
331 route_4oMPLSo4.add_vpp_config()
334 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
335 / IP(src="2.2.2.2", dst="1.1.2.22")
336 / UDP(sport=1234, dport=1234)
339 rx = self.send_and_expect(self.pg0, p_4omo4 * NUM_PKTS, self.pg1)
341 self.validate_outer4(p, udp_encap_1)
342 p = MPLS(p["UDP"].payload.load)
343 self.validate_inner4(p, p_4omo4, ttl=63)
344 self.assertEqual(udp_encap_1.get_stats()["packets"], 2 * NUM_PKTS)
346 def test_udp_decap(self):
349 # construct a UDP decap object for each type of protocol
353 udp_api_proto = VppEnum.vl_api_udp_decap_next_proto_t
354 next_proto = udp_api_proto.UDP_API_DECAP_PROTO_IP4
355 udp_decap_0 = VppUdpDecap(self, 1, 220, next_proto)
358 next_proto = udp_api_proto.UDP_API_DECAP_PROTO_IP6
359 udp_decap_1 = VppUdpDecap(self, 0, 221, next_proto)
362 next_proto = udp_api_proto.UDP_API_DECAP_PROTO_MPLS
363 udp_decap_2 = VppUdpDecap(self, 1, 222, next_proto)
365 udp_decap_0.add_vpp_config()
366 udp_decap_1.add_vpp_config()
367 udp_decap_2.add_vpp_config()
370 # Routes via the corresponding pg after the UDP decap
372 route_4 = VppIpRoute(
376 [VppRoutePath("0.0.0.0", self.pg0.sw_if_index)],
380 route_6 = VppIpRoute(
381 self, "2001::1", 128, [VppRoutePath("::", self.pg1.sw_if_index)], table_id=1
384 route_mo4 = VppIpRoute(
388 [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)],
392 route_4.add_vpp_config()
393 route_6.add_vpp_config()
394 route_mo4.add_vpp_config()
397 # Adding neighbors to route the packets
399 n_4 = VppNeighbor(self, self.pg0.sw_if_index, "00:11:22:33:44:55", "1.1.1.1")
400 n_6 = VppNeighbor(self, self.pg1.sw_if_index, "11:22:33:44:55:66", "2001::1")
401 n_mo4 = VppNeighbor(self, self.pg2.sw_if_index, "22:33:44:55:66:77", "3.3.3.3")
405 n_mo4.add_vpp_config()
408 # MPLS decapsulation config
410 mpls_table = VppMplsTable(self, 0)
411 mpls_table.add_vpp_config()
412 mpls_route = VppMplsRoute(
421 proto=FibPathProto.FIB_PATH_NH_PROTO_IP4,
425 mpls_route.add_vpp_config()
428 # UDP over ipv4 decap
431 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
432 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
433 / UDP(sport=1111, dport=220)
434 / IP(src="2.2.2.2", dst="1.1.1.1")
435 / UDP(sport=1234, dport=4321)
439 rx = self.send_and_expect(self.pg0, p_4 * NUM_PKTS, self.pg0)
440 p_4 = IP(p_4["UDP"].payload)
442 p = IP(p["Ether"].payload)
443 self.validate_inner4(p, p_4, ttl=63)
446 # UDP over ipv6 decap
449 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
450 / IPv6(src=self.pg1.remote_ip6, dst=self.pg1.local_ip6)
451 / UDP(sport=2222, dport=221)
452 / IPv6(src="2001::100", dst="2001::1")
453 / UDP(sport=1234, dport=4321)
457 rx = self.send_and_expect(self.pg1, p_6 * NUM_PKTS, self.pg1)
458 p_6 = IPv6(p_6["UDP"].payload)
459 p = IPv6(rx[0]["Ether"].payload)
461 p = IPv6(p["Ether"].payload)
462 self.validate_inner6(p, p_6, hlim=63)
465 # UDP over mpls decap
468 Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
469 / IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4)
470 / UDP(sport=3333, dport=222)
471 / MPLS(label=77, ttl=1)
472 / IP(src="4.4.4.4", dst="3.3.3.3")
473 / UDP(sport=1234, dport=4321)
477 self.pg2.enable_mpls()
478 rx = self.send_and_expect(self.pg2, p_mo4 * NUM_PKTS, self.pg2)
479 self.pg2.disable_mpls()
480 p_mo4 = IP(MPLS(p_mo4["UDP"].payload).payload)
482 p = IP(p["Ether"].payload)
483 self.validate_inner4(p, p_mo4, ttl=63)
486 @tag_fixme_vpp_workers
487 class TestUDP(VppTestCase):
492 super(TestUDP, cls).setUpClass()
495 def tearDownClass(cls):
496 super(TestUDP, cls).tearDownClass()
499 super(TestUDP, self).setUp()
500 self.vapi.session_enable_disable(is_enable=1)
501 self.create_loopback_interfaces(2)
505 for i in self.lo_interfaces:
509 tbl = VppIpTable(self, table_id)
512 i.set_table_ip4(table_id)
516 # Configure namespaces
517 self.vapi.app_namespace_add_del(
518 namespace_id="0", sw_if_index=self.loop0.sw_if_index
520 self.vapi.app_namespace_add_del(
521 namespace_id="1", sw_if_index=self.loop1.sw_if_index
525 for i in self.lo_interfaces:
529 self.vapi.session_enable_disable(is_enable=0)
530 super(TestUDP, self).tearDown()
532 def test_udp_transfer(self):
533 """UDP echo client/server transfer"""
535 # Add inter-table routes
538 self.loop1.local_ip4,
540 [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=1)],
544 self.loop0.local_ip4,
546 [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=0)],
549 ip_t01.add_vpp_config()
550 ip_t10.add_vpp_config()
552 # Start builtin server and client
553 uri = "udp://" + self.loop0.local_ip4 + "/1234"
554 error = self.vapi.cli(
555 "test echo server appns 0 fifo-size 4 no-echo" + "uri " + uri
558 self.logger.critical(error)
559 self.assertNotIn("failed", error)
561 error = self.vapi.cli(
562 "test echo client mbytes 10 appns 1 "
563 + "fifo-size 4 no-output test-bytes "
564 + "syn-timeout 2 no-return uri "
568 self.logger.critical(error)
569 self.assertNotIn("failed", error)
571 self.logger.debug(self.vapi.cli("show session verbose 2"))
573 # Delete inter-table routes
574 ip_t01.remove_vpp_config()
575 ip_t10.remove_vpp_config()
578 if __name__ == "__main__":
579 unittest.main(testRunner=VppTestRunner)