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()
123 def setUpConstants(cls):
124 cls.extra_vpp_punt_config = [
125 "punt", "{", "socket", cls.tempdir+"/socket_punt", "}"]
126 super(TestPuntSocket, cls).setUpConstants()
129 super(TestPuntSocket, self).setUp()
132 self.create_pg_interfaces(range(2))
133 for i in self.pg_interfaces:
137 del self.sock_servers[:]
139 def socket_client_create(self, sock_name, id=None):
140 thread = serverSocketThread(id, sock_name, self.portsCheck)
141 self.sock_servers.append(thread)
144 def socket_client_close(self):
145 for thread in self.sock_servers:
149 class TestIP4PuntSocket(TestPuntSocket):
150 """ Punt Socket for IPv4 """
153 super(TestIP4PuntSocket, self).setUp()
155 for i in self.pg_interfaces:
160 super(TestIP4PuntSocket, self).tearDown()
161 for i in self.pg_interfaces:
165 def test_punt_socket_dump(self):
166 """ Punt socket registration/deregistration"""
168 punts = self.vapi.punt_socket_dump(is_ip6=0)
169 self.assertEqual(len(punts), 0)
172 # configure a punt socket
174 self.vapi.punt_socket_register(1111, self.tempdir+"/socket_punt_1111")
175 self.vapi.punt_socket_register(2222, self.tempdir+"/socket_punt_2222")
176 punts = self.vapi.punt_socket_dump(is_ip6=0)
177 self.assertEqual(len(punts), 2)
178 self.assertEqual(punts[0].punt.l4_port, 1111)
179 self.assertEqual(punts[1].punt.l4_port, 2222)
182 # deregister a punt socket
184 self.vapi.punt_socket_deregister(1111)
185 punts = self.vapi.punt_socket_dump(is_ip6=0)
186 self.assertEqual(len(punts), 1)
189 # configure a punt socket again
191 self.vapi.punt_socket_register(1111, self.tempdir+"/socket_punt_1111")
192 self.vapi.punt_socket_register(3333, self.tempdir+"/socket_punt_3333")
193 punts = self.vapi.punt_socket_dump(is_ip6=0)
194 self.assertEqual(len(punts), 3)
197 # deregister all punt socket
199 self.vapi.punt_socket_deregister(1111)
200 self.vapi.punt_socket_deregister(2222)
201 self.vapi.punt_socket_deregister(3333)
202 punts = self.vapi.punt_socket_dump(is_ip6=0)
203 self.assertEqual(len(punts), 0)
205 def test_punt_socket_traffic_single_port_single_socket(self):
206 """ Punt socket traffic single port single socket"""
210 p = (Ether(src=self.pg0.remote_mac,
211 dst=self.pg0.local_mac) /
212 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
213 UDP(sport=9876, dport=port) /
216 pkts = p * self.nr_packets
217 self.portsCheck[port] = self.nr_packets
219 punts = self.vapi.punt_socket_dump(is_ip6=0)
220 self.assertEqual(len(punts), 0)
223 # expect ICMP - port unreachable for all packets
225 self.vapi.cli("clear trace")
226 self.pg0.add_stream(pkts)
227 self.pg_enable_capture(self.pg_interfaces)
229 # FIXME - when punt socket deregister is implemented
230 # rx = self.pg0.get_capture(self.nr_packets)
232 # self.assertEqual(int(p[IP].proto), 1) # ICMP
233 # self.assertEqual(int(p[ICMP].code), 3) # unreachable
236 # configure a punt socket
238 self.socket_client_create(self.tempdir+"/socket_" + str(port))
239 self.vapi.punt_socket_register(port, self.tempdir+"/socket_" +
241 punts = self.vapi.punt_socket_dump(is_ip6=0)
242 self.assertEqual(len(punts), 1)
244 self.logger.debug("Sending %s packets to port %d",
245 str(self.portsCheck[port]), port)
247 # expect punt socket and no packets on pg0
249 self.vapi.cli("clear errors")
250 self.vapi.cli("clear trace")
251 self.pg0.add_stream(pkts)
252 self.pg_enable_capture(self.pg_interfaces)
254 self.pg0.get_capture(0)
255 self.logger.info(self.vapi.cli("show trace"))
256 self.socket_client_close()
257 self.assertEqual(self.portsCheck[port], 0)
260 # remove punt socket. expect ICMP - port unreachable for all packets
262 self.vapi.punt_socket_deregister(port)
263 punts = self.vapi.punt_socket_dump(is_ip6=0)
264 self.assertEqual(len(punts), 0)
265 self.pg0.add_stream(pkts)
266 self.pg_enable_capture(self.pg_interfaces)
268 # FIXME - when punt socket deregister is implemented
269 # self.pg0.get_capture(nr_packets)
271 def test_punt_socket_traffic_multi_port_multi_sockets(self):
272 """ Punt socket traffic multi ports and multi sockets"""
275 self.portsCheck[p] = 0
278 # create stream with random pakets count per given ports
281 for _ in range(0, self.nr_packets):
282 # choose port from port list
283 p = random.choice(self.ports)
285 Ether(src=self.pg0.remote_mac,
286 dst=self.pg0.local_mac) /
287 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
288 UDP(sport=9876, dport=p) /
290 self.portsCheck[p] += 1
294 punts = self.vapi.punt_socket_dump(is_ip6=0)
295 self.assertEqual(len(punts), 0)
298 # configure a punt socket
301 self.socket_client_create(self.tempdir+"/socket_" + str(p))
302 self.vapi.punt_socket_register(p, self.tempdir+"/socket_" + str(p))
303 punts = self.vapi.punt_socket_dump(is_ip6=0)
304 self.assertEqual(len(punts), len(self.ports))
307 self.logger.debug("Sending %s packets to port %d",
308 str(self.portsCheck[p]), p)
311 # expect punt socket and no packets on pg0
313 self.vapi.cli("clear errors")
314 self.vapi.cli("clear trace")
315 self.pg0.add_stream(pkts)
316 self.pg_enable_capture(self.pg_interfaces)
318 self.pg0.get_capture(0)
319 self.logger.info(self.vapi.cli("show trace"))
320 self.socket_client_close()
323 self.assertEqual(self.portsCheck[p], 0)
324 self.vapi.punt_socket_deregister(p)
325 punts = self.vapi.punt_socket_dump(is_ip6=0)
326 self.assertEqual(len(punts), 0)
328 def test_punt_socket_traffic_multi_ports_single_socket(self):
329 """ Punt socket traffic multi ports and single socket"""
332 self.portsCheck[p] = 0
335 # create stream with random pakets count per given ports
338 for _ in range(0, self.nr_packets):
339 # choose port from port list
340 p = random.choice(self.ports)
342 Ether(src=self.pg0.remote_mac,
343 dst=self.pg0.local_mac) /
344 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
345 UDP(sport=9876, dport=p) /
347 self.portsCheck[p] += 1
352 punts = self.vapi.punt_socket_dump(is_ip6=0)
353 self.assertEqual(len(punts), 0)
355 # configure a punt socket
357 self.socket_client_create(self.tempdir+"/socket_multi")
359 self.vapi.punt_socket_register(p, self.tempdir+"/socket_multi")
360 punts = self.vapi.punt_socket_dump(is_ip6=0)
361 self.assertEqual(len(punts), len(self.ports))
364 self.logger.debug("Sending %s packets to port %d",
365 str(self.portsCheck[p]), p)
367 # expect punt socket and no packets on pg0
369 self.vapi.cli("clear errors")
370 self.vapi.cli("clear trace")
371 self.pg0.add_stream(pkts)
372 self.pg_enable_capture(self.pg_interfaces)
374 self.pg0.get_capture(0)
375 self.logger.info(self.vapi.cli("show trace"))
376 self.socket_client_close()
379 self.assertEqual(self.portsCheck[p], 0)
380 self.vapi.punt_socket_deregister(p)
381 punts = self.vapi.punt_socket_dump(is_ip6=0)
382 self.assertEqual(len(punts), 0)
385 class TestIP6PuntSocket(TestPuntSocket):
386 """ Punt Socket for IPv6"""
389 super(TestIP6PuntSocket, self).setUp()
391 for i in self.pg_interfaces:
396 super(TestIP6PuntSocket, self).tearDown()
397 for i in self.pg_interfaces:
401 def test_punt_socket_dump(self):
402 """ Punt socket registration """
404 punts = self.vapi.punt_socket_dump(is_ip6=1)
405 self.assertEqual(len(punts), 0)
408 # configure a punt socket
410 self.vapi.punt_socket_register(1111, self.tempdir+"/socket_1111",
412 self.vapi.punt_socket_register(2222, self.tempdir+"/socket_2222",
414 punts = self.vapi.punt_socket_dump(is_ip6=1)
415 self.assertEqual(len(punts), 2)
416 self.assertEqual(punts[0].punt.l4_port, 1111)
417 self.assertEqual(punts[1].punt.l4_port, 2222)
420 # deregister a punt socket
422 self.vapi.punt_socket_deregister(1111, is_ip4=0)
423 punts = self.vapi.punt_socket_dump(is_ip6=1)
424 self.assertEqual(len(punts), 1)
427 # configure a punt socket again
429 self.vapi.punt_socket_register(1111, self.tempdir+"/socket_1111",
431 punts = self.vapi.punt_socket_dump(is_ip6=1)
432 self.assertEqual(len(punts), 2)
435 # deregister all punt socket
437 self.vapi.punt_socket_deregister(1111, is_ip4=0)
438 self.vapi.punt_socket_deregister(2222, is_ip4=0)
439 self.vapi.punt_socket_deregister(3333, is_ip4=0)
440 punts = self.vapi.punt_socket_dump(is_ip6=1)
441 self.assertEqual(len(punts), 0)
443 def test_punt_socket_traffic_single_port_single_socket(self):
444 """ Punt socket traffic single port single socket"""
448 p = (Ether(src=self.pg0.remote_mac,
449 dst=self.pg0.local_mac) /
450 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
451 inet6.UDP(sport=9876, dport=port) /
454 pkts = p * self.nr_packets
455 self.portsCheck[port] = self.nr_packets
457 punts = self.vapi.punt_socket_dump(is_ip6=1)
458 self.assertEqual(len(punts), 0)
461 # expect ICMPv6 - destination unreachable for all packets
463 self.vapi.cli("clear trace")
464 self.pg0.add_stream(pkts)
465 self.pg_enable_capture(self.pg_interfaces)
467 # FIXME - when punt socket deregister is implemented
468 # rx = self.pg0.get_capture(self.nr_packets)
470 # self.assertEqual(int(p[IPv6].nh), 58) # ICMPv6
471 # self.assertEqual(int(p[ICMPv6DestUnreach].code),4) # unreachable
474 # configure a punt socket
476 self.socket_client_create(self.tempdir+"/socket_" + str(port))
477 self.vapi.punt_socket_register(port, self.tempdir+"/socket_" +
479 punts = self.vapi.punt_socket_dump(is_ip6=1)
480 self.assertEqual(len(punts), 1)
482 self.logger.debug("Sending %s packets to port %d",
483 str(self.portsCheck[port]), port)
485 # expect punt socket and no packets on pg0
487 self.vapi.cli("clear errors")
488 self.vapi.cli("clear trace")
489 self.pg0.add_stream(pkts)
490 self.pg_enable_capture(self.pg_interfaces)
492 self.pg0.get_capture(0)
493 self.logger.info(self.vapi.cli("show trace"))
494 self.socket_client_close()
495 self.assertEqual(self.portsCheck[port], 0)
498 # remove punt socket. expect ICMP - dest. unreachable for all packets
500 self.vapi.punt_socket_deregister(port, is_ip4=0)
501 punts = self.vapi.punt_socket_dump(is_ip6=1)
502 self.assertEqual(len(punts), 0)
503 self.pg0.add_stream(pkts)
504 self.pg_enable_capture(self.pg_interfaces)
506 # FIXME - when punt socket deregister is implemented
507 # self.pg0.get_capture(nr_packets)
509 def test_punt_socket_traffic_multi_port_multi_sockets(self):
510 """ Punt socket traffic multi ports and multi sockets"""
513 self.portsCheck[p] = 0
516 # create stream with random pakets count per given ports
519 for _ in range(0, self.nr_packets):
520 # choose port from port list
521 p = random.choice(self.ports)
523 Ether(src=self.pg0.remote_mac,
524 dst=self.pg0.local_mac) /
525 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
526 inet6.UDP(sport=9876, dport=p) /
528 self.portsCheck[p] += 1
532 punts = self.vapi.punt_socket_dump(is_ip6=1)
533 self.assertEqual(len(punts), 0)
536 # configure a punt socket
539 self.socket_client_create(self.tempdir+"/socket_" + str(p))
540 self.vapi.punt_socket_register(p, self.tempdir+"/socket_" + str(p),
542 punts = self.vapi.punt_socket_dump(is_ip6=1)
543 self.assertEqual(len(punts), len(self.ports))
546 self.logger.debug("Sending %s packets to port %d",
547 str(self.portsCheck[p]), p)
550 # expect punt socket and no packets on pg0
552 self.vapi.cli("clear errors")
553 self.vapi.cli("clear trace")
554 self.pg0.add_stream(pkts)
555 self.pg_enable_capture(self.pg_interfaces)
557 self.pg0.get_capture(0)
558 self.logger.info(self.vapi.cli("show trace"))
559 self.socket_client_close()
562 self.assertEqual(self.portsCheck[p], 0)
563 self.vapi.punt_socket_deregister(p, is_ip4=0)
564 punts = self.vapi.punt_socket_dump(is_ip6=1)
565 self.assertEqual(len(punts), 0)
567 def test_punt_socket_traffic_multi_ports_single_socket(self):
568 """ Punt socket traffic multi ports and single socket"""
571 self.portsCheck[p] = 0
574 # create stream with random pakets count per given ports
577 for _ in range(0, self.nr_packets):
578 # choose port from port list
579 p = random.choice(self.ports)
581 Ether(src=self.pg0.remote_mac,
582 dst=self.pg0.local_mac) /
583 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
584 inet6.UDP(sport=9876, dport=p) /
586 self.portsCheck[p] += 1
591 punts = self.vapi.punt_socket_dump(is_ip6=1)
592 self.assertEqual(len(punts), 0)
595 # configure a punt socket
597 self.socket_client_create(self.tempdir+"/socket_multi")
599 self.vapi.punt_socket_register(p, self.tempdir+"/socket_multi",
601 punts = self.vapi.punt_socket_dump(is_ip6=1)
602 self.assertEqual(len(punts), len(self.ports))
605 self.logger.debug("Send %s packets to port %d",
606 str(self.portsCheck[p]), p)
608 # expect punt socket and no packets on pg0
610 self.vapi.cli("clear errors")
611 self.vapi.cli("clear trace")
612 self.pg0.add_stream(pkts)
613 self.pg_enable_capture(self.pg_interfaces)
615 self.pg0.get_capture(0)
616 self.logger.info(self.vapi.cli("show trace"))
617 self.socket_client_close()
620 self.assertEqual(self.portsCheck[p], 0)
621 self.vapi.punt_socket_deregister(p, is_ip4=0)
622 punts = self.vapi.punt_socket_dump(is_ip6=1)
623 self.assertEqual(len(punts), 0)
625 if __name__ == '__main__':
626 unittest.main(testRunner=VppTestRunner)