8 from struct import unpack, unpack_from
11 import unittest2 as unittest
15 from util import ppp, ppc
16 from re import compile
18 from scapy.packet import Raw
19 from scapy.layers.l2 import Ether
20 from scapy.layers.inet import IP, UDP, ICMP
21 import scapy.layers.inet6 as inet6
22 from scapy.layers.inet6 import IPv6, ICMPv6DestUnreach
24 from framework import VppTestCase, VppTestRunner
28 def get_mac_addr(bytes_addr):
29 return ':'.join('%02x' % scapy.compat.orb(b) for b in bytes_addr)
34 return '.'.join('%d' % scapy.compat.orb(b) for b in bytes_addr)
37 # Unpack Ethernet Frame
38 def ethernet_frame(data):
39 dest_mac, src_mac, proto = struct.unpack('! 6s 6s H', data[:14])
40 return dest_mac, src_mac, socket.htons(proto), data[14:]
44 def ipv4_packet(data):
45 proto, src, target = struct.unpack('! 8x 1x B 2x 4s 4s', data[:20])
46 return proto, src, target, data[20:]
50 def ipv6_packet(data):
51 nh, src, target = struct.unpack('! 6x B 1x 16s 16s', data[:40])
52 return nh, src, target, data[40:]
55 # Unpacks any UDP Packet
57 src_port, dest_port, size = struct.unpack('! H H 2x H', data[:8])
58 return src_port, dest_port, size, data[8:]
61 # Unpacks any TCP Packet
63 src_port, dest_port, seq, flag = struct.unpack('! H H L 4x H', data[:14])
64 return src_port, dest_port, seq, data[((flag >> 12) * 4):]
67 def receivePackets(sock, counters):
68 # Wait for some packets on socket
70 data = sock.recv(65536)
72 # punt socket metadata
73 # packet_desc = data[0:8]
76 _, _, eth_proto, data = ethernet_frame(data[8:])
79 proto, _, _, data = ipv4_packet(data)
82 _, dst_port, _, data = udp_seg(data)
85 _, dst_port, _, data = udp_seg(data)
86 counters[dst_port] = 0
88 elif eth_proto == 0xdd86:
89 nh, _, _, data = ipv6_packet(data)
92 _, dst_port, _, data = udp_seg(data)
95 _, dst_port, _, data = udp_seg(data)
96 counters[dst_port] = 0
99 class serverSocketThread(threading.Thread):
100 """ Socket server thread"""
102 def __init__(self, threadID, sockName, counters):
103 threading.Thread.__init__(self)
104 self.threadID = threadID
105 self.sockName = sockName
107 self.counters = counters
110 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
112 os.unlink(self.sockName)
115 self.sock.bind(self.sockName)
117 receivePackets(self.sock, self.counters)
120 class TestPuntSocket(VppTestCase):
123 ports = [1111, 2222, 3333, 4444]
124 sock_servers = list()
130 super(TestPuntSocket, cls).setUpClass()
133 def tearDownClass(cls):
134 super(TestPuntSocket, cls).tearDownClass()
137 def setUpConstants(cls):
138 cls.extra_vpp_punt_config = [
139 "punt", "{", "socket", cls.tempdir+"/socket_punt", "}"]
140 super(TestPuntSocket, cls).setUpConstants()
143 super(TestPuntSocket, self).setUp()
146 self.create_pg_interfaces(range(2))
147 for i in self.pg_interfaces:
151 del self.sock_servers[:]
152 super(TestPuntSocket, self).tearDown()
154 def socket_client_create(self, sock_name, id=None):
155 thread = serverSocketThread(id, sock_name, self.portsCheck)
156 self.sock_servers.append(thread)
159 def socket_client_close(self):
160 for thread in self.sock_servers:
164 class TestIP4PuntSocket(TestPuntSocket):
165 """ Punt Socket for IPv4 """
169 super(TestIP4PuntSocket, cls).setUpClass()
172 def tearDownClass(cls):
173 super(TestIP4PuntSocket, cls).tearDownClass()
176 super(TestIP4PuntSocket, self).setUp()
178 for i in self.pg_interfaces:
183 super(TestIP4PuntSocket, self).tearDown()
184 for i in self.pg_interfaces:
188 def test_punt_socket_dump(self):
189 """ Punt socket registration/deregistration"""
191 punts = self.vapi.punt_socket_dump(is_ip6=0)
192 self.assertEqual(len(punts), 0)
195 # configure a punt socket
197 self.vapi.punt_socket_register(1111, b"%s/socket_punt_1111" %
198 six.ensure_binary(self.tempdir))
199 self.vapi.punt_socket_register(2222, b"%s/socket_punt_2222" %
200 six.ensure_binary(self.tempdir))
201 punts = self.vapi.punt_socket_dump(is_ip6=0)
202 self.assertEqual(len(punts), 2)
203 self.assertEqual(punts[0].punt.l4_port, 1111)
204 self.assertEqual(punts[1].punt.l4_port, 2222)
207 # deregister a punt socket
209 self.vapi.punt_socket_deregister(1111)
210 punts = self.vapi.punt_socket_dump(is_ip6=0)
211 self.assertEqual(len(punts), 1)
214 # configure a punt socket again
216 self.vapi.punt_socket_register(1111, b"%s/socket_punt_1111" %
217 six.ensure_binary(self.tempdir))
218 self.vapi.punt_socket_register(3333, b"%s/socket_punt_3333" %
219 six.ensure_binary(self.tempdir))
220 punts = self.vapi.punt_socket_dump(is_ip6=0)
221 self.assertEqual(len(punts), 3)
224 # deregister all punt socket
226 self.vapi.punt_socket_deregister(1111)
227 self.vapi.punt_socket_deregister(2222)
228 self.vapi.punt_socket_deregister(3333)
229 punts = self.vapi.punt_socket_dump(is_ip6=0)
230 self.assertEqual(len(punts), 0)
232 def test_punt_socket_traffic_single_port_single_socket(self):
233 """ Punt socket traffic single port single socket"""
237 p = (Ether(src=self.pg0.remote_mac,
238 dst=self.pg0.local_mac) /
239 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
240 UDP(sport=9876, dport=port) /
243 pkts = p * self.nr_packets
244 self.portsCheck[port] = self.nr_packets
246 punts = self.vapi.punt_socket_dump(is_ip6=0)
247 self.assertEqual(len(punts), 0)
250 # expect ICMP - port unreachable for all packets
252 self.vapi.cli("clear trace")
253 self.pg0.add_stream(pkts)
254 self.pg_enable_capture(self.pg_interfaces)
256 # FIXME - when punt socket deregister is implemented
257 # rx = self.pg0.get_capture(self.nr_packets)
259 # self.assertEqual(int(p[IP].proto), 1) # ICMP
260 # self.assertEqual(int(p[ICMP].code), 3) # unreachable
263 # configure a punt socket
265 self.socket_client_create(b"%s/socket_%d" % (
266 six.ensure_binary(self.tempdir), port))
267 self.vapi.punt_socket_register(port, b"%s/socket_%d" % (
268 six.ensure_binary(self.tempdir), port))
269 punts = self.vapi.punt_socket_dump(is_ip6=0)
270 self.assertEqual(len(punts), 1)
272 self.logger.debug("Sending %s packets to port %d",
273 str(self.portsCheck[port]), port)
275 # expect punt socket and no packets on pg0
277 self.vapi.cli("clear errors")
278 self.vapi.cli("clear trace")
279 self.pg0.add_stream(pkts)
280 self.pg_enable_capture(self.pg_interfaces)
282 self.pg0.get_capture(0)
283 self.logger.info(self.vapi.cli("show trace"))
284 self.socket_client_close()
285 self.assertEqual(self.portsCheck[port], 0)
288 # remove punt socket. expect ICMP - port unreachable for all packets
290 self.vapi.punt_socket_deregister(port)
291 punts = self.vapi.punt_socket_dump(is_ip6=0)
292 self.assertEqual(len(punts), 0)
293 self.pg0.add_stream(pkts)
294 self.pg_enable_capture(self.pg_interfaces)
296 # FIXME - when punt socket deregister is implemented
297 # self.pg0.get_capture(nr_packets)
299 def test_punt_socket_traffic_multi_port_multi_sockets(self):
300 """ Punt socket traffic multi ports and multi sockets"""
303 self.portsCheck[p] = 0
306 # create stream with random pakets count per given ports
309 for _ in range(0, self.nr_packets):
310 # choose port from port list
311 p = random.choice(self.ports)
313 Ether(src=self.pg0.remote_mac,
314 dst=self.pg0.local_mac) /
315 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
316 UDP(sport=9876, dport=p) /
318 self.portsCheck[p] += 1
322 punts = self.vapi.punt_socket_dump(is_ip6=0)
323 self.assertEqual(len(punts), 0)
326 # configure a punt socket
329 self.socket_client_create(b"%s/socket_%d" % (
330 six.ensure_binary(self.tempdir), p))
331 self.vapi.punt_socket_register(p, b"%s/socket_%d" % (
332 six.ensure_binary(self.tempdir), p))
333 punts = self.vapi.punt_socket_dump(is_ip6=0)
334 self.assertEqual(len(punts), len(self.ports))
337 self.logger.debug("Sending %s packets to port %d",
338 str(self.portsCheck[p]), p)
341 # expect punt socket and no packets on pg0
343 self.vapi.cli("clear errors")
344 self.vapi.cli("clear trace")
345 self.pg0.add_stream(pkts)
346 self.pg_enable_capture(self.pg_interfaces)
348 self.pg0.get_capture(0)
349 self.logger.info(self.vapi.cli("show trace"))
350 self.socket_client_close()
353 self.assertEqual(self.portsCheck[p], 0)
354 self.vapi.punt_socket_deregister(p)
355 punts = self.vapi.punt_socket_dump(is_ip6=0)
356 self.assertEqual(len(punts), 0)
358 def test_punt_socket_traffic_multi_ports_single_socket(self):
359 """ Punt socket traffic multi ports and single socket"""
362 self.portsCheck[p] = 0
365 # create stream with random pakets count per given ports
368 for _ in range(0, self.nr_packets):
369 # choose port from port list
370 p = random.choice(self.ports)
372 Ether(src=self.pg0.remote_mac,
373 dst=self.pg0.local_mac) /
374 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
375 UDP(sport=9876, dport=p) /
377 self.portsCheck[p] += 1
382 punts = self.vapi.punt_socket_dump(is_ip6=0)
383 self.assertEqual(len(punts), 0)
385 # configure a punt socket
387 self.socket_client_create(b"%s/socket_multi" %
388 six.ensure_binary(self.tempdir))
390 self.vapi.punt_socket_register(p,
392 six.ensure_binary(self.tempdir))
393 punts = self.vapi.punt_socket_dump(is_ip6=0)
394 self.assertEqual(len(punts), len(self.ports))
397 self.logger.debug("Sending %s packets to port %d",
398 str(self.portsCheck[p]), p)
400 # expect punt socket and no packets on pg0
402 self.vapi.cli("clear errors")
403 self.vapi.cli("clear trace")
404 self.pg0.add_stream(pkts)
405 self.pg_enable_capture(self.pg_interfaces)
407 self.pg0.get_capture(0)
408 self.logger.info(self.vapi.cli("show trace"))
409 self.socket_client_close()
412 self.assertEqual(self.portsCheck[p], 0)
413 self.vapi.punt_socket_deregister(p)
414 punts = self.vapi.punt_socket_dump(is_ip6=0)
415 self.assertEqual(len(punts), 0)
418 class TestIP6PuntSocket(TestPuntSocket):
419 """ Punt Socket for IPv6"""
423 super(TestIP6PuntSocket, cls).setUpClass()
426 def tearDownClass(cls):
427 super(TestIP6PuntSocket, cls).tearDownClass()
430 super(TestIP6PuntSocket, self).setUp()
432 for i in self.pg_interfaces:
437 super(TestIP6PuntSocket, self).tearDown()
438 for i in self.pg_interfaces:
442 def test_punt_socket_dump(self):
443 """ Punt socket registration """
445 punts = self.vapi.punt_socket_dump(is_ip6=1)
446 self.assertEqual(len(punts), 0)
449 # configure a punt socket
451 self.vapi.punt_socket_register(1111, b"%s/socket_1111" %
452 six.ensure_binary(self.tempdir),
454 self.vapi.punt_socket_register(2222, b"%s/socket_2222" %
455 six.ensure_binary(self.tempdir),
457 punts = self.vapi.punt_socket_dump(is_ip6=1)
458 self.assertEqual(len(punts), 2)
459 self.assertEqual(punts[0].punt.l4_port, 1111)
460 self.assertEqual(punts[1].punt.l4_port, 2222)
463 # deregister a punt socket
465 self.vapi.punt_socket_deregister(1111, is_ip4=0)
466 punts = self.vapi.punt_socket_dump(is_ip6=1)
467 self.assertEqual(len(punts), 1)
470 # configure a punt socket again
472 self.vapi.punt_socket_register(1111, b"%s/socket_1111" %
473 six.ensure_binary(self.tempdir),
475 punts = self.vapi.punt_socket_dump(is_ip6=1)
476 self.assertEqual(len(punts), 2)
479 # deregister all punt socket
481 self.vapi.punt_socket_deregister(1111, is_ip4=0)
482 self.vapi.punt_socket_deregister(2222, is_ip4=0)
483 self.vapi.punt_socket_deregister(3333, is_ip4=0)
484 punts = self.vapi.punt_socket_dump(is_ip6=1)
485 self.assertEqual(len(punts), 0)
487 def test_punt_socket_traffic_single_port_single_socket(self):
488 """ Punt socket traffic single port single socket"""
492 p = (Ether(src=self.pg0.remote_mac,
493 dst=self.pg0.local_mac) /
494 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
495 inet6.UDP(sport=9876, dport=port) /
498 pkts = p * self.nr_packets
499 self.portsCheck[port] = self.nr_packets
501 punts = self.vapi.punt_socket_dump(is_ip6=1)
502 self.assertEqual(len(punts), 0)
505 # expect ICMPv6 - destination unreachable for all packets
507 self.vapi.cli("clear trace")
508 self.pg0.add_stream(pkts)
509 self.pg_enable_capture(self.pg_interfaces)
511 # FIXME - when punt socket deregister is implemented
512 # rx = self.pg0.get_capture(self.nr_packets)
514 # self.assertEqual(int(p[IPv6].nh), 58) # ICMPv6
515 # self.assertEqual(int(p[ICMPv6DestUnreach].code),4) # unreachable
518 # configure a punt socket
520 self.socket_client_create(b"%s/socket_%d" % (
521 six.ensure_binary(self.tempdir), port))
522 self.vapi.punt_socket_register(port, b"%s/socket_%d" % (
523 six.ensure_binary(self.tempdir), port), is_ip4=0)
524 punts = self.vapi.punt_socket_dump(is_ip6=1)
525 self.assertEqual(len(punts), 1)
527 self.logger.debug("Sending %s packets to port %d",
528 str(self.portsCheck[port]), port)
530 # expect punt socket and no packets on pg0
532 self.vapi.cli("clear errors")
533 self.vapi.cli("clear trace")
534 self.pg0.add_stream(pkts)
535 self.pg_enable_capture(self.pg_interfaces)
537 self.pg0.get_capture(0)
538 self.logger.info(self.vapi.cli("show trace"))
539 self.socket_client_close()
540 self.assertEqual(self.portsCheck[port], 0)
543 # remove punt socket. expect ICMP - dest. unreachable for all packets
545 self.vapi.punt_socket_deregister(port, is_ip4=0)
546 punts = self.vapi.punt_socket_dump(is_ip6=1)
547 self.assertEqual(len(punts), 0)
548 self.pg0.add_stream(pkts)
549 self.pg_enable_capture(self.pg_interfaces)
551 # FIXME - when punt socket deregister is implemented
552 # self.pg0.get_capture(nr_packets)
554 def test_punt_socket_traffic_multi_port_multi_sockets(self):
555 """ Punt socket traffic multi ports and multi sockets"""
558 self.portsCheck[p] = 0
561 # create stream with random pakets count per given ports
564 for _ in range(0, self.nr_packets):
565 # choose port from port list
566 p = random.choice(self.ports)
568 Ether(src=self.pg0.remote_mac,
569 dst=self.pg0.local_mac) /
570 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
571 inet6.UDP(sport=9876, dport=p) /
573 self.portsCheck[p] += 1
577 punts = self.vapi.punt_socket_dump(is_ip6=1)
578 self.assertEqual(len(punts), 0)
581 # configure a punt socket
584 self.socket_client_create(b"%s/socket_%d" % (
585 six.ensure_binary(self.tempdir), p))
586 self.vapi.punt_socket_register(p, b"%s/socket_%d" % (
587 six.ensure_binary(self.tempdir), p), is_ip4=0)
588 punts = self.vapi.punt_socket_dump(is_ip6=1)
589 self.assertEqual(len(punts), len(self.ports))
592 self.logger.debug("Sending %s packets to port %d",
593 str(self.portsCheck[p]), p)
596 # expect punt socket and no packets on pg0
598 self.vapi.cli("clear errors")
599 self.vapi.cli("clear trace")
600 self.pg0.add_stream(pkts)
601 self.pg_enable_capture(self.pg_interfaces)
603 self.pg0.get_capture(0)
604 self.logger.info(self.vapi.cli("show trace"))
605 self.socket_client_close()
608 self.assertEqual(self.portsCheck[p], 0)
609 self.vapi.punt_socket_deregister(p, is_ip4=0)
610 punts = self.vapi.punt_socket_dump(is_ip6=1)
611 self.assertEqual(len(punts), 0)
613 def test_punt_socket_traffic_multi_ports_single_socket(self):
614 """ Punt socket traffic multi ports and single socket"""
617 self.portsCheck[p] = 0
620 # create stream with random pakets count per given ports
623 for _ in range(0, self.nr_packets):
624 # choose port from port list
625 p = random.choice(self.ports)
627 Ether(src=self.pg0.remote_mac,
628 dst=self.pg0.local_mac) /
629 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
630 inet6.UDP(sport=9876, dport=p) /
632 self.portsCheck[p] += 1
637 punts = self.vapi.punt_socket_dump(is_ip6=1)
638 self.assertEqual(len(punts), 0)
641 # configure a punt socket
643 self.socket_client_create(b"%s/socket_multi" %
644 six.ensure_binary(self.tempdir))
646 self.vapi.punt_socket_register(p,
648 six.ensure_binary(self.tempdir),
650 punts = self.vapi.punt_socket_dump(is_ip6=1)
651 self.assertEqual(len(punts), len(self.ports))
654 self.logger.debug("Send %s packets to port %d",
655 str(self.portsCheck[p]), p)
657 # expect punt socket and no packets on pg0
659 self.vapi.cli("clear errors")
660 self.vapi.cli("clear trace")
661 self.pg0.add_stream(pkts)
662 self.pg_enable_capture(self.pg_interfaces)
664 self.pg0.get_capture(0)
665 self.logger.info(self.vapi.cli("show trace"))
666 self.socket_client_close()
669 self.assertEqual(self.portsCheck[p], 0)
670 self.vapi.punt_socket_deregister(p, is_ip4=0)
671 punts = self.vapi.punt_socket_dump(is_ip6=1)
672 self.assertEqual(len(punts), 0)
674 if __name__ == '__main__':
675 unittest.main(testRunner=VppTestRunner)