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
14 from scapy.packet import Raw
15 from scapy.layers.l2 import Ether
16 from scapy.layers.inet import IP, UDP, ICMP
17 from scapy.layers.inet6 import IPv6, ICMPv6DestUnreach
18 from framework import VppTestCase, VppTestRunner
22 def get_mac_addr(bytes_addr):
23 return ':'.join('%02x' % ord(b) for b in bytes_addr)
28 return '.'.join('%d' % ord(b) for b in bytes_addr)
31 # Unpack Ethernet Frame
32 def ethernet_frame(data):
33 dest_mac, src_mac, proto = struct.unpack('! 6s 6s H', data[:14])
34 return dest_mac, src_mac, socket.htons(proto), data[14:]
38 def ipv4_packet(data):
39 proto, src, target = struct.unpack('! 8x 1x B 2x 4s 4s', data[:20])
40 return proto, src, target, data[20:]
44 def ipv6_packet(data):
45 nh, src, target = struct.unpack('! 6x B 1x 16s 16s', data[:40])
46 return nh, src, target, data[40:]
49 # Unpacks any UDP Packet
51 src_port, dest_port, size = struct.unpack('! H H 2x H', data[:8])
52 return src_port, dest_port, size, data[8:]
55 # Unpacks any TCP Packet
57 src_port, dest_port, seq, flag = struct.unpack('! H H L 4x H', data[:14])
58 return src_port, dest_port, seq, data[((flag >> 12) * 4):]
61 def receivePackets(sock, counters):
62 # Wait for some packets on socket
64 data = sock.recv(65536)
66 # punt socket metadata
67 # packet_desc = data[0:8]
70 _, _, eth_proto, data = ethernet_frame(data[8:])
73 proto, _, _, data = ipv4_packet(data)
76 _, dst_port, _, data = udp_seg(data)
79 _, dst_port, _, data = udp_seg(data)
80 counters[dst_port] = 0
82 elif eth_proto == 0xdd86:
83 nh, _, _, data = ipv6_packet(data)
86 _, dst_port, _, data = udp_seg(data)
89 _, dst_port, _, data = udp_seg(data)
90 counters[dst_port] = 0
93 class serverSocketThread(threading.Thread):
94 """ Socket server thread"""
96 def __init__(self, threadID, sockName, counters):
97 threading.Thread.__init__(self)
98 self.threadID = threadID
99 self.sockName = sockName
101 self.counters = counters
104 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
106 os.unlink(self.sockName)
109 self.sock.bind(self.sockName)
111 receivePackets(self.sock, self.counters)
114 class TestPuntSocket(VppTestCase):
117 ports = [1111, 2222, 3333, 4444]
118 sock_servers = list()
124 super(TestPuntSocket, cls).setUpClass()
127 def tearDownClass(cls):
128 super(TestPuntSocket, cls).tearDownClass()
131 def setUpConstants(cls):
132 cls.extra_vpp_punt_config = [
133 "punt", "{", "socket", cls.tempdir+"/socket_punt", "}"]
134 super(TestPuntSocket, cls).setUpConstants()
137 super(TestPuntSocket, self).setUp()
140 self.create_pg_interfaces(range(2))
141 for i in self.pg_interfaces:
145 del self.sock_servers[:]
146 super(TestPuntSocket, self).tearDown()
148 def socket_client_create(self, sock_name, id=None):
149 thread = serverSocketThread(id, sock_name, self.portsCheck)
150 self.sock_servers.append(thread)
153 def socket_client_close(self):
154 for thread in self.sock_servers:
158 class TestIP4PuntSocket(TestPuntSocket):
159 """ Punt Socket for IPv4 """
163 super(TestIP4PuntSocket, cls).setUpClass()
166 def tearDownClass(cls):
167 super(TestIP4PuntSocket, cls).tearDownClass()
170 super(TestIP4PuntSocket, self).setUp()
172 for i in self.pg_interfaces:
177 super(TestIP4PuntSocket, self).tearDown()
178 for i in self.pg_interfaces:
182 def test_punt_socket_dump(self):
183 """ Punt socket registration/deregistration"""
185 punts = self.vapi.punt_socket_dump(is_ip6=0)
186 self.assertEqual(len(punts), 0)
189 # configure a punt socket
191 self.vapi.punt_socket_register(1111, self.tempdir+"/socket_punt_1111")
192 self.vapi.punt_socket_register(2222, self.tempdir+"/socket_punt_2222")
193 punts = self.vapi.punt_socket_dump(is_ip6=0)
194 self.assertEqual(len(punts), 2)
195 self.assertEqual(punts[0].punt.l4_port, 1111)
196 self.assertEqual(punts[1].punt.l4_port, 2222)
199 # deregister a punt socket
201 self.vapi.punt_socket_deregister(1111)
202 punts = self.vapi.punt_socket_dump(is_ip6=0)
203 self.assertEqual(len(punts), 1)
206 # configure a punt socket again
208 self.vapi.punt_socket_register(1111, self.tempdir+"/socket_punt_1111")
209 self.vapi.punt_socket_register(3333, self.tempdir+"/socket_punt_3333")
210 punts = self.vapi.punt_socket_dump(is_ip6=0)
211 self.assertEqual(len(punts), 3)
214 # deregister all punt socket
216 self.vapi.punt_socket_deregister(1111)
217 self.vapi.punt_socket_deregister(2222)
218 self.vapi.punt_socket_deregister(3333)
219 punts = self.vapi.punt_socket_dump(is_ip6=0)
220 self.assertEqual(len(punts), 0)
222 def test_punt_socket_traffic_single_port_single_socket(self):
223 """ Punt socket traffic single port single socket"""
227 p = (Ether(src=self.pg0.remote_mac,
228 dst=self.pg0.local_mac) /
229 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
230 UDP(sport=9876, dport=port) /
233 pkts = p * self.nr_packets
234 self.portsCheck[port] = self.nr_packets
236 punts = self.vapi.punt_socket_dump(is_ip6=0)
237 self.assertEqual(len(punts), 0)
240 # expect ICMP - port unreachable for all packets
242 self.vapi.cli("clear trace")
243 self.pg0.add_stream(pkts)
244 self.pg_enable_capture(self.pg_interfaces)
246 # FIXME - when punt socket deregister is implemented
247 # rx = self.pg0.get_capture(self.nr_packets)
249 # self.assertEqual(int(p[IP].proto), 1) # ICMP
250 # self.assertEqual(int(p[ICMP].code), 3) # unreachable
253 # configure a punt socket
255 self.socket_client_create(self.tempdir+"/socket_" + str(port))
256 self.vapi.punt_socket_register(port, self.tempdir+"/socket_" +
258 punts = self.vapi.punt_socket_dump(is_ip6=0)
259 self.assertEqual(len(punts), 1)
261 self.logger.debug("Sending %s packets to port %d",
262 str(self.portsCheck[port]), port)
264 # expect punt socket and no packets on pg0
266 self.vapi.cli("clear errors")
267 self.vapi.cli("clear trace")
268 self.pg0.add_stream(pkts)
269 self.pg_enable_capture(self.pg_interfaces)
271 self.pg0.get_capture(0)
272 self.logger.info(self.vapi.cli("show trace"))
273 self.socket_client_close()
274 self.assertEqual(self.portsCheck[port], 0)
277 # remove punt socket. expect ICMP - port unreachable for all packets
279 self.vapi.punt_socket_deregister(port)
280 punts = self.vapi.punt_socket_dump(is_ip6=0)
281 self.assertEqual(len(punts), 0)
282 self.pg0.add_stream(pkts)
283 self.pg_enable_capture(self.pg_interfaces)
285 # FIXME - when punt socket deregister is implemented
286 # self.pg0.get_capture(nr_packets)
288 def test_punt_socket_traffic_multi_port_multi_sockets(self):
289 """ Punt socket traffic multi ports and multi sockets"""
292 self.portsCheck[p] = 0
295 # create stream with random pakets count per given ports
298 for _ in range(0, self.nr_packets):
299 # choose port from port list
300 p = random.choice(self.ports)
302 Ether(src=self.pg0.remote_mac,
303 dst=self.pg0.local_mac) /
304 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
305 UDP(sport=9876, dport=p) /
307 self.portsCheck[p] += 1
311 punts = self.vapi.punt_socket_dump(is_ip6=0)
312 self.assertEqual(len(punts), 0)
315 # configure a punt socket
318 self.socket_client_create(self.tempdir+"/socket_" + str(p))
319 self.vapi.punt_socket_register(p, self.tempdir+"/socket_" + str(p))
320 punts = self.vapi.punt_socket_dump(is_ip6=0)
321 self.assertEqual(len(punts), len(self.ports))
324 self.logger.debug("Sending %s packets to port %d",
325 str(self.portsCheck[p]), p)
328 # expect punt socket and no packets on pg0
330 self.vapi.cli("clear errors")
331 self.vapi.cli("clear trace")
332 self.pg0.add_stream(pkts)
333 self.pg_enable_capture(self.pg_interfaces)
335 self.pg0.get_capture(0)
336 self.logger.info(self.vapi.cli("show trace"))
337 self.socket_client_close()
340 self.assertEqual(self.portsCheck[p], 0)
341 self.vapi.punt_socket_deregister(p)
342 punts = self.vapi.punt_socket_dump(is_ip6=0)
343 self.assertEqual(len(punts), 0)
345 def test_punt_socket_traffic_multi_ports_single_socket(self):
346 """ Punt socket traffic multi ports and single socket"""
349 self.portsCheck[p] = 0
352 # create stream with random pakets count per given ports
355 for _ in range(0, self.nr_packets):
356 # choose port from port list
357 p = random.choice(self.ports)
359 Ether(src=self.pg0.remote_mac,
360 dst=self.pg0.local_mac) /
361 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
362 UDP(sport=9876, dport=p) /
364 self.portsCheck[p] += 1
369 punts = self.vapi.punt_socket_dump(is_ip6=0)
370 self.assertEqual(len(punts), 0)
372 # configure a punt socket
374 self.socket_client_create(self.tempdir+"/socket_multi")
376 self.vapi.punt_socket_register(p, self.tempdir+"/socket_multi")
377 punts = self.vapi.punt_socket_dump(is_ip6=0)
378 self.assertEqual(len(punts), len(self.ports))
381 self.logger.debug("Sending %s packets to port %d",
382 str(self.portsCheck[p]), p)
384 # expect punt socket and no packets on pg0
386 self.vapi.cli("clear errors")
387 self.vapi.cli("clear trace")
388 self.pg0.add_stream(pkts)
389 self.pg_enable_capture(self.pg_interfaces)
391 self.pg0.get_capture(0)
392 self.logger.info(self.vapi.cli("show trace"))
393 self.socket_client_close()
396 self.assertEqual(self.portsCheck[p], 0)
397 self.vapi.punt_socket_deregister(p)
398 punts = self.vapi.punt_socket_dump(is_ip6=0)
399 self.assertEqual(len(punts), 0)
402 class TestIP6PuntSocket(TestPuntSocket):
403 """ Punt Socket for IPv6"""
407 super(TestIP6PuntSocket, cls).setUpClass()
410 def tearDownClass(cls):
411 super(TestIP6PuntSocket, cls).tearDownClass()
414 super(TestIP6PuntSocket, self).setUp()
416 for i in self.pg_interfaces:
421 super(TestIP6PuntSocket, self).tearDown()
422 for i in self.pg_interfaces:
426 def test_punt_socket_dump(self):
427 """ Punt socket registration """
429 punts = self.vapi.punt_socket_dump(is_ip6=1)
430 self.assertEqual(len(punts), 0)
433 # configure a punt socket
435 self.vapi.punt_socket_register(1111, self.tempdir+"/socket_1111",
437 self.vapi.punt_socket_register(2222, self.tempdir+"/socket_2222",
439 punts = self.vapi.punt_socket_dump(is_ip6=1)
440 self.assertEqual(len(punts), 2)
441 self.assertEqual(punts[0].punt.l4_port, 1111)
442 self.assertEqual(punts[1].punt.l4_port, 2222)
445 # deregister a punt socket
447 self.vapi.punt_socket_deregister(1111, is_ip4=0)
448 punts = self.vapi.punt_socket_dump(is_ip6=1)
449 self.assertEqual(len(punts), 1)
452 # configure a punt socket again
454 self.vapi.punt_socket_register(1111, self.tempdir+"/socket_1111",
456 punts = self.vapi.punt_socket_dump(is_ip6=1)
457 self.assertEqual(len(punts), 2)
460 # deregister all punt socket
462 self.vapi.punt_socket_deregister(1111, is_ip4=0)
463 self.vapi.punt_socket_deregister(2222, is_ip4=0)
464 self.vapi.punt_socket_deregister(3333, is_ip4=0)
465 punts = self.vapi.punt_socket_dump(is_ip6=1)
466 self.assertEqual(len(punts), 0)
468 def test_punt_socket_traffic_single_port_single_socket(self):
469 """ Punt socket traffic single port single socket"""
473 p = (Ether(src=self.pg0.remote_mac,
474 dst=self.pg0.local_mac) /
475 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
476 inet6.UDP(sport=9876, dport=port) /
479 pkts = p * self.nr_packets
480 self.portsCheck[port] = self.nr_packets
482 punts = self.vapi.punt_socket_dump(is_ip6=1)
483 self.assertEqual(len(punts), 0)
486 # expect ICMPv6 - destination unreachable for all packets
488 self.vapi.cli("clear trace")
489 self.pg0.add_stream(pkts)
490 self.pg_enable_capture(self.pg_interfaces)
492 # FIXME - when punt socket deregister is implemented
493 # rx = self.pg0.get_capture(self.nr_packets)
495 # self.assertEqual(int(p[IPv6].nh), 58) # ICMPv6
496 # self.assertEqual(int(p[ICMPv6DestUnreach].code),4) # unreachable
499 # configure a punt socket
501 self.socket_client_create(self.tempdir+"/socket_" + str(port))
502 self.vapi.punt_socket_register(port, self.tempdir+"/socket_" +
504 punts = self.vapi.punt_socket_dump(is_ip6=1)
505 self.assertEqual(len(punts), 1)
507 self.logger.debug("Sending %s packets to port %d",
508 str(self.portsCheck[port]), port)
510 # expect punt socket and no packets on pg0
512 self.vapi.cli("clear errors")
513 self.vapi.cli("clear trace")
514 self.pg0.add_stream(pkts)
515 self.pg_enable_capture(self.pg_interfaces)
517 self.pg0.get_capture(0)
518 self.logger.info(self.vapi.cli("show trace"))
519 self.socket_client_close()
520 self.assertEqual(self.portsCheck[port], 0)
523 # remove punt socket. expect ICMP - dest. unreachable for all packets
525 self.vapi.punt_socket_deregister(port, is_ip4=0)
526 punts = self.vapi.punt_socket_dump(is_ip6=1)
527 self.assertEqual(len(punts), 0)
528 self.pg0.add_stream(pkts)
529 self.pg_enable_capture(self.pg_interfaces)
531 # FIXME - when punt socket deregister is implemented
532 # self.pg0.get_capture(nr_packets)
534 def test_punt_socket_traffic_multi_port_multi_sockets(self):
535 """ Punt socket traffic multi ports and multi sockets"""
538 self.portsCheck[p] = 0
541 # create stream with random pakets count per given ports
544 for _ in range(0, self.nr_packets):
545 # choose port from port list
546 p = random.choice(self.ports)
548 Ether(src=self.pg0.remote_mac,
549 dst=self.pg0.local_mac) /
550 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
551 inet6.UDP(sport=9876, dport=p) /
553 self.portsCheck[p] += 1
557 punts = self.vapi.punt_socket_dump(is_ip6=1)
558 self.assertEqual(len(punts), 0)
561 # configure a punt socket
564 self.socket_client_create(self.tempdir+"/socket_" + str(p))
565 self.vapi.punt_socket_register(p, self.tempdir+"/socket_" + str(p),
567 punts = self.vapi.punt_socket_dump(is_ip6=1)
568 self.assertEqual(len(punts), len(self.ports))
571 self.logger.debug("Sending %s packets to port %d",
572 str(self.portsCheck[p]), p)
575 # expect punt socket and no packets on pg0
577 self.vapi.cli("clear errors")
578 self.vapi.cli("clear trace")
579 self.pg0.add_stream(pkts)
580 self.pg_enable_capture(self.pg_interfaces)
582 self.pg0.get_capture(0)
583 self.logger.info(self.vapi.cli("show trace"))
584 self.socket_client_close()
587 self.assertEqual(self.portsCheck[p], 0)
588 self.vapi.punt_socket_deregister(p, is_ip4=0)
589 punts = self.vapi.punt_socket_dump(is_ip6=1)
590 self.assertEqual(len(punts), 0)
592 def test_punt_socket_traffic_multi_ports_single_socket(self):
593 """ Punt socket traffic multi ports and single socket"""
596 self.portsCheck[p] = 0
599 # create stream with random pakets count per given ports
602 for _ in range(0, self.nr_packets):
603 # choose port from port list
604 p = random.choice(self.ports)
606 Ether(src=self.pg0.remote_mac,
607 dst=self.pg0.local_mac) /
608 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
609 inet6.UDP(sport=9876, dport=p) /
611 self.portsCheck[p] += 1
616 punts = self.vapi.punt_socket_dump(is_ip6=1)
617 self.assertEqual(len(punts), 0)
620 # configure a punt socket
622 self.socket_client_create(self.tempdir+"/socket_multi")
624 self.vapi.punt_socket_register(p, self.tempdir+"/socket_multi",
626 punts = self.vapi.punt_socket_dump(is_ip6=1)
627 self.assertEqual(len(punts), len(self.ports))
630 self.logger.debug("Send %s packets to port %d",
631 str(self.portsCheck[p]), p)
633 # expect punt socket and no packets on pg0
635 self.vapi.cli("clear errors")
636 self.vapi.cli("clear trace")
637 self.pg0.add_stream(pkts)
638 self.pg_enable_capture(self.pg_interfaces)
640 self.pg0.get_capture(0)
641 self.logger.info(self.vapi.cli("show trace"))
642 self.socket_client_close()
645 self.assertEqual(self.portsCheck[p], 0)
646 self.vapi.punt_socket_deregister(p, is_ip4=0)
647 punts = self.vapi.punt_socket_dump(is_ip6=1)
648 self.assertEqual(len(punts), 0)
650 if __name__ == '__main__':
651 unittest.main(testRunner=VppTestRunner)