7 import scapy.layers.inet6 as inet6
11 from struct import unpack, unpack_from
12 from util import ppp, ppc
13 from re import compile
15 from scapy.packet import Raw
16 from scapy.layers.l2 import Ether
17 from scapy.layers.inet import IP, UDP, ICMP
18 from scapy.layers.inet6 import IPv6, ICMPv6DestUnreach
19 from framework import VppTestCase, VppTestRunner
23 def get_mac_addr(bytes_addr):
24 return ':'.join('%02x' % scapy.compat.orb(b) for b in bytes_addr)
29 return '.'.join('%d' % scapy.compat.orb(b) for b in bytes_addr)
32 # Unpack Ethernet Frame
33 def ethernet_frame(data):
34 dest_mac, src_mac, proto = struct.unpack('! 6s 6s H', data[:14])
35 return dest_mac, src_mac, socket.htons(proto), data[14:]
39 def ipv4_packet(data):
40 proto, src, target = struct.unpack('! 8x 1x B 2x 4s 4s', data[:20])
41 return proto, src, target, data[20:]
45 def ipv6_packet(data):
46 nh, src, target = struct.unpack('! 6x B 1x 16s 16s', data[:40])
47 return nh, src, target, data[40:]
50 # Unpacks any UDP Packet
52 src_port, dest_port, size = struct.unpack('! H H 2x H', data[:8])
53 return src_port, dest_port, size, data[8:]
56 # Unpacks any TCP Packet
58 src_port, dest_port, seq, flag = struct.unpack('! H H L 4x H', data[:14])
59 return src_port, dest_port, seq, data[((flag >> 12) * 4):]
62 def receivePackets(sock, counters):
63 # Wait for some packets on socket
65 data = sock.recv(65536)
67 # punt socket metadata
68 # packet_desc = data[0:8]
71 _, _, eth_proto, data = ethernet_frame(data[8:])
74 proto, _, _, data = ipv4_packet(data)
77 _, dst_port, _, data = udp_seg(data)
80 _, dst_port, _, data = udp_seg(data)
81 counters[dst_port] = 0
83 elif eth_proto == 0xdd86:
84 nh, _, _, data = ipv6_packet(data)
87 _, dst_port, _, data = udp_seg(data)
90 _, dst_port, _, data = udp_seg(data)
91 counters[dst_port] = 0
94 class serverSocketThread(threading.Thread):
95 """ Socket server thread"""
97 def __init__(self, threadID, sockName, counters):
98 threading.Thread.__init__(self)
99 self.threadID = threadID
100 self.sockName = sockName
102 self.counters = counters
105 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
107 os.unlink(self.sockName)
110 self.sock.bind(self.sockName)
112 receivePackets(self.sock, self.counters)
115 class TestPuntSocket(VppTestCase):
118 ports = [1111, 2222, 3333, 4444]
119 sock_servers = list()
125 super(TestPuntSocket, cls).setUpClass()
128 def tearDownClass(cls):
129 super(TestPuntSocket, cls).tearDownClass()
132 def setUpConstants(cls):
133 cls.extra_vpp_punt_config = [
134 "punt", "{", "socket", cls.tempdir+"/socket_punt", "}"]
135 super(TestPuntSocket, cls).setUpConstants()
138 super(TestPuntSocket, self).setUp()
141 self.create_pg_interfaces(range(2))
142 for i in self.pg_interfaces:
146 del self.sock_servers[:]
147 super(TestPuntSocket, self).tearDown()
149 def socket_client_create(self, sock_name, id=None):
150 thread = serverSocketThread(id, sock_name, self.portsCheck)
151 self.sock_servers.append(thread)
154 def socket_client_close(self):
155 for thread in self.sock_servers:
159 class TestIP4PuntSocket(TestPuntSocket):
160 """ Punt Socket for IPv4 """
164 super(TestIP4PuntSocket, cls).setUpClass()
167 def tearDownClass(cls):
168 super(TestIP4PuntSocket, cls).tearDownClass()
171 super(TestIP4PuntSocket, self).setUp()
173 for i in self.pg_interfaces:
178 super(TestIP4PuntSocket, self).tearDown()
179 for i in self.pg_interfaces:
183 def test_punt_socket_dump(self):
184 """ Punt socket registration/deregistration"""
186 punts = self.vapi.punt_socket_dump(is_ip6=0)
187 self.assertEqual(len(punts), 0)
190 # configure a punt socket
192 self.vapi.punt_socket_register(1111, self.tempdir+"/socket_punt_1111")
193 self.vapi.punt_socket_register(2222, self.tempdir+"/socket_punt_2222")
194 punts = self.vapi.punt_socket_dump(is_ip6=0)
195 self.assertEqual(len(punts), 2)
196 self.assertEqual(punts[0].punt.l4_port, 1111)
197 self.assertEqual(punts[1].punt.l4_port, 2222)
200 # deregister a punt socket
202 self.vapi.punt_socket_deregister(1111)
203 punts = self.vapi.punt_socket_dump(is_ip6=0)
204 self.assertEqual(len(punts), 1)
207 # configure a punt socket again
209 self.vapi.punt_socket_register(1111, self.tempdir+"/socket_punt_1111")
210 self.vapi.punt_socket_register(3333, self.tempdir+"/socket_punt_3333")
211 punts = self.vapi.punt_socket_dump(is_ip6=0)
212 self.assertEqual(len(punts), 3)
215 # deregister all punt socket
217 self.vapi.punt_socket_deregister(1111)
218 self.vapi.punt_socket_deregister(2222)
219 self.vapi.punt_socket_deregister(3333)
220 punts = self.vapi.punt_socket_dump(is_ip6=0)
221 self.assertEqual(len(punts), 0)
223 def test_punt_socket_traffic_single_port_single_socket(self):
224 """ Punt socket traffic single port single socket"""
228 p = (Ether(src=self.pg0.remote_mac,
229 dst=self.pg0.local_mac) /
230 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
231 UDP(sport=9876, dport=port) /
234 pkts = p * self.nr_packets
235 self.portsCheck[port] = self.nr_packets
237 punts = self.vapi.punt_socket_dump(is_ip6=0)
238 self.assertEqual(len(punts), 0)
241 # expect ICMP - port unreachable for all packets
243 self.vapi.cli("clear trace")
244 self.pg0.add_stream(pkts)
245 self.pg_enable_capture(self.pg_interfaces)
247 # FIXME - when punt socket deregister is implemented
248 # rx = self.pg0.get_capture(self.nr_packets)
250 # self.assertEqual(int(p[IP].proto), 1) # ICMP
251 # self.assertEqual(int(p[ICMP].code), 3) # unreachable
254 # configure a punt socket
256 self.socket_client_create(self.tempdir+"/socket_" + str(port))
257 self.vapi.punt_socket_register(port, self.tempdir+"/socket_" +
259 punts = self.vapi.punt_socket_dump(is_ip6=0)
260 self.assertEqual(len(punts), 1)
262 self.logger.debug("Sending %s packets to port %d",
263 str(self.portsCheck[port]), port)
265 # expect punt socket and no packets on pg0
267 self.vapi.cli("clear errors")
268 self.vapi.cli("clear trace")
269 self.pg0.add_stream(pkts)
270 self.pg_enable_capture(self.pg_interfaces)
272 self.pg0.get_capture(0)
273 self.logger.info(self.vapi.cli("show trace"))
274 self.socket_client_close()
275 self.assertEqual(self.portsCheck[port], 0)
278 # remove punt socket. expect ICMP - port unreachable for all packets
280 self.vapi.punt_socket_deregister(port)
281 punts = self.vapi.punt_socket_dump(is_ip6=0)
282 self.assertEqual(len(punts), 0)
283 self.pg0.add_stream(pkts)
284 self.pg_enable_capture(self.pg_interfaces)
286 # FIXME - when punt socket deregister is implemented
287 # self.pg0.get_capture(nr_packets)
289 def test_punt_socket_traffic_multi_port_multi_sockets(self):
290 """ Punt socket traffic multi ports and multi sockets"""
293 self.portsCheck[p] = 0
296 # create stream with random pakets count per given ports
299 for _ in range(0, self.nr_packets):
300 # choose port from port list
301 p = random.choice(self.ports)
303 Ether(src=self.pg0.remote_mac,
304 dst=self.pg0.local_mac) /
305 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
306 UDP(sport=9876, dport=p) /
308 self.portsCheck[p] += 1
312 punts = self.vapi.punt_socket_dump(is_ip6=0)
313 self.assertEqual(len(punts), 0)
316 # configure a punt socket
319 self.socket_client_create(self.tempdir+"/socket_" + str(p))
320 self.vapi.punt_socket_register(p, self.tempdir+"/socket_" + str(p))
321 punts = self.vapi.punt_socket_dump(is_ip6=0)
322 self.assertEqual(len(punts), len(self.ports))
325 self.logger.debug("Sending %s packets to port %d",
326 str(self.portsCheck[p]), p)
329 # expect punt socket and no packets on pg0
331 self.vapi.cli("clear errors")
332 self.vapi.cli("clear trace")
333 self.pg0.add_stream(pkts)
334 self.pg_enable_capture(self.pg_interfaces)
336 self.pg0.get_capture(0)
337 self.logger.info(self.vapi.cli("show trace"))
338 self.socket_client_close()
341 self.assertEqual(self.portsCheck[p], 0)
342 self.vapi.punt_socket_deregister(p)
343 punts = self.vapi.punt_socket_dump(is_ip6=0)
344 self.assertEqual(len(punts), 0)
346 def test_punt_socket_traffic_multi_ports_single_socket(self):
347 """ Punt socket traffic multi ports and single socket"""
350 self.portsCheck[p] = 0
353 # create stream with random pakets count per given ports
356 for _ in range(0, self.nr_packets):
357 # choose port from port list
358 p = random.choice(self.ports)
360 Ether(src=self.pg0.remote_mac,
361 dst=self.pg0.local_mac) /
362 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
363 UDP(sport=9876, dport=p) /
365 self.portsCheck[p] += 1
370 punts = self.vapi.punt_socket_dump(is_ip6=0)
371 self.assertEqual(len(punts), 0)
373 # configure a punt socket
375 self.socket_client_create(self.tempdir+"/socket_multi")
377 self.vapi.punt_socket_register(p, self.tempdir+"/socket_multi")
378 punts = self.vapi.punt_socket_dump(is_ip6=0)
379 self.assertEqual(len(punts), len(self.ports))
382 self.logger.debug("Sending %s packets to port %d",
383 str(self.portsCheck[p]), p)
385 # expect punt socket and no packets on pg0
387 self.vapi.cli("clear errors")
388 self.vapi.cli("clear trace")
389 self.pg0.add_stream(pkts)
390 self.pg_enable_capture(self.pg_interfaces)
392 self.pg0.get_capture(0)
393 self.logger.info(self.vapi.cli("show trace"))
394 self.socket_client_close()
397 self.assertEqual(self.portsCheck[p], 0)
398 self.vapi.punt_socket_deregister(p)
399 punts = self.vapi.punt_socket_dump(is_ip6=0)
400 self.assertEqual(len(punts), 0)
403 class TestIP6PuntSocket(TestPuntSocket):
404 """ Punt Socket for IPv6"""
408 super(TestIP6PuntSocket, cls).setUpClass()
411 def tearDownClass(cls):
412 super(TestIP6PuntSocket, cls).tearDownClass()
415 super(TestIP6PuntSocket, self).setUp()
417 for i in self.pg_interfaces:
422 super(TestIP6PuntSocket, self).tearDown()
423 for i in self.pg_interfaces:
427 def test_punt_socket_dump(self):
428 """ Punt socket registration """
430 punts = self.vapi.punt_socket_dump(is_ip6=1)
431 self.assertEqual(len(punts), 0)
434 # configure a punt socket
436 self.vapi.punt_socket_register(1111, self.tempdir+"/socket_1111",
438 self.vapi.punt_socket_register(2222, self.tempdir+"/socket_2222",
440 punts = self.vapi.punt_socket_dump(is_ip6=1)
441 self.assertEqual(len(punts), 2)
442 self.assertEqual(punts[0].punt.l4_port, 1111)
443 self.assertEqual(punts[1].punt.l4_port, 2222)
446 # deregister a punt socket
448 self.vapi.punt_socket_deregister(1111, is_ip4=0)
449 punts = self.vapi.punt_socket_dump(is_ip6=1)
450 self.assertEqual(len(punts), 1)
453 # configure a punt socket again
455 self.vapi.punt_socket_register(1111, self.tempdir+"/socket_1111",
457 punts = self.vapi.punt_socket_dump(is_ip6=1)
458 self.assertEqual(len(punts), 2)
461 # deregister all punt socket
463 self.vapi.punt_socket_deregister(1111, is_ip4=0)
464 self.vapi.punt_socket_deregister(2222, is_ip4=0)
465 self.vapi.punt_socket_deregister(3333, is_ip4=0)
466 punts = self.vapi.punt_socket_dump(is_ip6=1)
467 self.assertEqual(len(punts), 0)
469 def test_punt_socket_traffic_single_port_single_socket(self):
470 """ Punt socket traffic single port single socket"""
474 p = (Ether(src=self.pg0.remote_mac,
475 dst=self.pg0.local_mac) /
476 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
477 inet6.UDP(sport=9876, dport=port) /
480 pkts = p * self.nr_packets
481 self.portsCheck[port] = self.nr_packets
483 punts = self.vapi.punt_socket_dump(is_ip6=1)
484 self.assertEqual(len(punts), 0)
487 # expect ICMPv6 - destination unreachable for all packets
489 self.vapi.cli("clear trace")
490 self.pg0.add_stream(pkts)
491 self.pg_enable_capture(self.pg_interfaces)
493 # FIXME - when punt socket deregister is implemented
494 # rx = self.pg0.get_capture(self.nr_packets)
496 # self.assertEqual(int(p[IPv6].nh), 58) # ICMPv6
497 # self.assertEqual(int(p[ICMPv6DestUnreach].code),4) # unreachable
500 # configure a punt socket
502 self.socket_client_create(self.tempdir+"/socket_" + str(port))
503 self.vapi.punt_socket_register(port, self.tempdir+"/socket_" +
505 punts = self.vapi.punt_socket_dump(is_ip6=1)
506 self.assertEqual(len(punts), 1)
508 self.logger.debug("Sending %s packets to port %d",
509 str(self.portsCheck[port]), port)
511 # expect punt socket and no packets on pg0
513 self.vapi.cli("clear errors")
514 self.vapi.cli("clear trace")
515 self.pg0.add_stream(pkts)
516 self.pg_enable_capture(self.pg_interfaces)
518 self.pg0.get_capture(0)
519 self.logger.info(self.vapi.cli("show trace"))
520 self.socket_client_close()
521 self.assertEqual(self.portsCheck[port], 0)
524 # remove punt socket. expect ICMP - dest. unreachable for all packets
526 self.vapi.punt_socket_deregister(port, is_ip4=0)
527 punts = self.vapi.punt_socket_dump(is_ip6=1)
528 self.assertEqual(len(punts), 0)
529 self.pg0.add_stream(pkts)
530 self.pg_enable_capture(self.pg_interfaces)
532 # FIXME - when punt socket deregister is implemented
533 # self.pg0.get_capture(nr_packets)
535 def test_punt_socket_traffic_multi_port_multi_sockets(self):
536 """ Punt socket traffic multi ports and multi sockets"""
539 self.portsCheck[p] = 0
542 # create stream with random pakets count per given ports
545 for _ in range(0, self.nr_packets):
546 # choose port from port list
547 p = random.choice(self.ports)
549 Ether(src=self.pg0.remote_mac,
550 dst=self.pg0.local_mac) /
551 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
552 inet6.UDP(sport=9876, dport=p) /
554 self.portsCheck[p] += 1
558 punts = self.vapi.punt_socket_dump(is_ip6=1)
559 self.assertEqual(len(punts), 0)
562 # configure a punt socket
565 self.socket_client_create(self.tempdir+"/socket_" + str(p))
566 self.vapi.punt_socket_register(p, self.tempdir+"/socket_" + str(p),
568 punts = self.vapi.punt_socket_dump(is_ip6=1)
569 self.assertEqual(len(punts), len(self.ports))
572 self.logger.debug("Sending %s packets to port %d",
573 str(self.portsCheck[p]), p)
576 # expect punt socket and no packets on pg0
578 self.vapi.cli("clear errors")
579 self.vapi.cli("clear trace")
580 self.pg0.add_stream(pkts)
581 self.pg_enable_capture(self.pg_interfaces)
583 self.pg0.get_capture(0)
584 self.logger.info(self.vapi.cli("show trace"))
585 self.socket_client_close()
588 self.assertEqual(self.portsCheck[p], 0)
589 self.vapi.punt_socket_deregister(p, is_ip4=0)
590 punts = self.vapi.punt_socket_dump(is_ip6=1)
591 self.assertEqual(len(punts), 0)
593 def test_punt_socket_traffic_multi_ports_single_socket(self):
594 """ Punt socket traffic multi ports and single socket"""
597 self.portsCheck[p] = 0
600 # create stream with random pakets count per given ports
603 for _ in range(0, self.nr_packets):
604 # choose port from port list
605 p = random.choice(self.ports)
607 Ether(src=self.pg0.remote_mac,
608 dst=self.pg0.local_mac) /
609 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
610 inet6.UDP(sport=9876, dport=p) /
612 self.portsCheck[p] += 1
617 punts = self.vapi.punt_socket_dump(is_ip6=1)
618 self.assertEqual(len(punts), 0)
621 # configure a punt socket
623 self.socket_client_create(self.tempdir+"/socket_multi")
625 self.vapi.punt_socket_register(p, self.tempdir+"/socket_multi",
627 punts = self.vapi.punt_socket_dump(is_ip6=1)
628 self.assertEqual(len(punts), len(self.ports))
631 self.logger.debug("Send %s packets to port %d",
632 str(self.portsCheck[p]), p)
634 # expect punt socket and no packets on pg0
636 self.vapi.cli("clear errors")
637 self.vapi.cli("clear trace")
638 self.pg0.add_stream(pkts)
639 self.pg_enable_capture(self.pg_interfaces)
641 self.pg0.get_capture(0)
642 self.logger.info(self.vapi.cli("show trace"))
643 self.socket_client_close()
646 self.assertEqual(self.portsCheck[p], 0)
647 self.vapi.punt_socket_deregister(p, is_ip4=0)
648 punts = self.vapi.punt_socket_dump(is_ip6=1)
649 self.assertEqual(len(punts), 0)
651 if __name__ == '__main__':
652 unittest.main(testRunner=VppTestRunner)