blob: cb9d40de4c492ccacd63bc2291d8094508659247 [file] [log] [blame]
Pavel Kotuceke88865d2018-11-28 07:42:11 +01001#!/usr/bin/env python
2import binascii
3import random
4import socket
Pavel Kotuceke88865d2018-11-28 07:42:11 +01005import os
Pavel Kotucek9edb83a2018-12-11 16:57:25 +01006import threading
7import struct
Pavel Kotucek9edb83a2018-12-11 16:57:25 +01008from struct import unpack, unpack_from
Paul Vinciguerra22ab6f72019-03-07 17:55:33 -08009
10try:
11 import unittest2 as unittest
12except ImportError:
13 import unittest
14
Pavel Kotuceke88865d2018-11-28 07:42:11 +010015from util import ppp, ppc
16from re import compile
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -070017import scapy.compat
Pavel Kotuceke88865d2018-11-28 07:42:11 +010018from scapy.packet import Raw
19from scapy.layers.l2 import Ether
20from scapy.layers.inet import IP, UDP, ICMP
Paul Vinciguerra22ab6f72019-03-07 17:55:33 -080021import scapy.layers.inet6 as inet6
Pavel Kotuceke88865d2018-11-28 07:42:11 +010022from scapy.layers.inet6 import IPv6, ICMPv6DestUnreach
Paul Vinciguerra22ab6f72019-03-07 17:55:33 -080023import six
Pavel Kotuceke88865d2018-11-28 07:42:11 +010024from framework import VppTestCase, VppTestRunner
25
Neale Ranns76b56492018-09-28 15:16:14 +000026from vpp_ip import DpoProto
27from vpp_ip_route import VppIpRoute, VppRoutePath
28
Pavel Kotuceke88865d2018-11-28 07:42:11 +010029
Pavel Kotucek9edb83a2018-12-11 16:57:25 +010030# Format MAC Address
31def get_mac_addr(bytes_addr):
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -070032 return ':'.join('%02x' % scapy.compat.orb(b) for b in bytes_addr)
Pavel Kotucek9edb83a2018-12-11 16:57:25 +010033
34
35# Format IP Address
36def ipv4(bytes_addr):
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -070037 return '.'.join('%d' % scapy.compat.orb(b) for b in bytes_addr)
Pavel Kotucek9edb83a2018-12-11 16:57:25 +010038
39
40# Unpack Ethernet Frame
41def ethernet_frame(data):
42 dest_mac, src_mac, proto = struct.unpack('! 6s 6s H', data[:14])
43 return dest_mac, src_mac, socket.htons(proto), data[14:]
44
45
46# Unpack IPv4 Packets
47def ipv4_packet(data):
48 proto, src, target = struct.unpack('! 8x 1x B 2x 4s 4s', data[:20])
49 return proto, src, target, data[20:]
50
51
52# Unpack IPv6 Packets
53def ipv6_packet(data):
54 nh, src, target = struct.unpack('! 6x B 1x 16s 16s', data[:40])
55 return nh, src, target, data[40:]
56
57
58# Unpacks any UDP Packet
59def udp_seg(data):
60 src_port, dest_port, size = struct.unpack('! H H 2x H', data[:8])
61 return src_port, dest_port, size, data[8:]
62
63
64# Unpacks any TCP Packet
65def tcp_seg(data):
66 src_port, dest_port, seq, flag = struct.unpack('! H H L 4x H', data[:14])
67 return src_port, dest_port, seq, data[((flag >> 12) * 4):]
68
69
70def receivePackets(sock, counters):
71 # Wait for some packets on socket
72 while True:
73 data = sock.recv(65536)
74
75 # punt socket metadata
76 # packet_desc = data[0:8]
77
78 # Ethernet
79 _, _, eth_proto, data = ethernet_frame(data[8:])
80 # Ipv4
81 if eth_proto == 8:
82 proto, _, _, data = ipv4_packet(data)
83 # TCP
84 if proto == 6:
85 _, dst_port, _, data = udp_seg(data)
86 # UDP
87 elif proto == 17:
88 _, dst_port, _, data = udp_seg(data)
89 counters[dst_port] = 0
90 # Ipv6
91 elif eth_proto == 0xdd86:
92 nh, _, _, data = ipv6_packet(data)
93 # TCP
94 if nh == 6:
95 _, dst_port, _, data = udp_seg(data)
96 # UDP
97 elif nh == 17:
98 _, dst_port, _, data = udp_seg(data)
99 counters[dst_port] = 0
100
101
102class serverSocketThread(threading.Thread):
103 """ Socket server thread"""
104
105 def __init__(self, threadID, sockName, counters):
106 threading.Thread.__init__(self)
107 self.threadID = threadID
108 self.sockName = sockName
109 self.sock = None
110 self.counters = counters
111
112 def run(self):
113 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
114 try:
115 os.unlink(self.sockName)
116 except:
117 pass
118 self.sock.bind(self.sockName)
119
120 receivePackets(self.sock, self.counters)
121
122
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100123class TestPuntSocket(VppTestCase):
124 """ Punt Socket """
125
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100126 ports = [1111, 2222, 3333, 4444]
127 sock_servers = list()
128 portsCheck = dict()
129 nr_packets = 256
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100130
131 @classmethod
Paul Vinciguerra8d991d92019-01-25 14:05:48 -0800132 def setUpClass(cls):
133 super(TestPuntSocket, cls).setUpClass()
134
135 @classmethod
136 def tearDownClass(cls):
137 super(TestPuntSocket, cls).tearDownClass()
138
139 @classmethod
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100140 def setUpConstants(cls):
Ole Troana45dc072018-12-21 16:04:22 +0100141 cls.extra_vpp_punt_config = [
142 "punt", "{", "socket", cls.tempdir+"/socket_punt", "}"]
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100143 super(TestPuntSocket, cls).setUpConstants()
144
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100145 def setUp(self):
146 super(TestPuntSocket, self).setUp()
147 random.seed()
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100148
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100149 self.create_pg_interfaces(range(2))
150 for i in self.pg_interfaces:
151 i.admin_up()
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100152
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100153 def tearDown(self):
154 del self.sock_servers[:]
Paul Vinciguerra8d991d92019-01-25 14:05:48 -0800155 super(TestPuntSocket, self).tearDown()
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100156
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100157 def socket_client_create(self, sock_name, id=None):
158 thread = serverSocketThread(id, sock_name, self.portsCheck)
159 self.sock_servers.append(thread)
160 thread.start()
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100161
162 def socket_client_close(self):
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100163 for thread in self.sock_servers:
164 thread.sock.close()
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100165
166
167class TestIP4PuntSocket(TestPuntSocket):
168 """ Punt Socket for IPv4 """
169
Paul Vinciguerra8d991d92019-01-25 14:05:48 -0800170 @classmethod
171 def setUpClass(cls):
172 super(TestIP4PuntSocket, cls).setUpClass()
173
174 @classmethod
175 def tearDownClass(cls):
176 super(TestIP4PuntSocket, cls).tearDownClass()
177
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100178 def setUp(self):
179 super(TestIP4PuntSocket, self).setUp()
180
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100181 for i in self.pg_interfaces:
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100182 i.config_ip4()
183 i.resolve_arp()
184
185 def tearDown(self):
186 super(TestIP4PuntSocket, self).tearDown()
187 for i in self.pg_interfaces:
188 i.unconfig_ip4()
189 i.admin_down()
190
191 def test_punt_socket_dump(self):
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100192 """ Punt socket registration/deregistration"""
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100193
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100194 punts = self.vapi.punt_socket_dump(is_ip6=0)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100195 self.assertEqual(len(punts), 0)
196
197 #
198 # configure a punt socket
199 #
Paul Vinciguerra22ab6f72019-03-07 17:55:33 -0800200 self.vapi.punt_socket_register(1111, b"%s/socket_punt_1111" %
201 six.ensure_binary(self.tempdir))
202 self.vapi.punt_socket_register(2222, b"%s/socket_punt_2222" %
203 six.ensure_binary(self.tempdir))
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100204 punts = self.vapi.punt_socket_dump(is_ip6=0)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100205 self.assertEqual(len(punts), 2)
206 self.assertEqual(punts[0].punt.l4_port, 1111)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100207 self.assertEqual(punts[1].punt.l4_port, 2222)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100208
209 #
210 # deregister a punt socket
211 #
212 self.vapi.punt_socket_deregister(1111)
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100213 punts = self.vapi.punt_socket_dump(is_ip6=0)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100214 self.assertEqual(len(punts), 1)
215
216 #
217 # configure a punt socket again
218 #
Paul Vinciguerra22ab6f72019-03-07 17:55:33 -0800219 self.vapi.punt_socket_register(1111, b"%s/socket_punt_1111" %
220 six.ensure_binary(self.tempdir))
221 self.vapi.punt_socket_register(3333, b"%s/socket_punt_3333" %
222 six.ensure_binary(self.tempdir))
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100223 punts = self.vapi.punt_socket_dump(is_ip6=0)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100224 self.assertEqual(len(punts), 3)
225
226 #
227 # deregister all punt socket
228 #
229 self.vapi.punt_socket_deregister(1111)
230 self.vapi.punt_socket_deregister(2222)
231 self.vapi.punt_socket_deregister(3333)
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100232 punts = self.vapi.punt_socket_dump(is_ip6=0)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100233 self.assertEqual(len(punts), 0)
234
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100235 def test_punt_socket_traffic_single_port_single_socket(self):
236 """ Punt socket traffic single port single socket"""
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100237
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100238 port = self.ports[0]
239
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100240 p = (Ether(src=self.pg0.remote_mac,
241 dst=self.pg0.local_mac) /
242 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100243 UDP(sport=9876, dport=port) /
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100244 Raw('\xa5' * 100))
245
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100246 pkts = p * self.nr_packets
247 self.portsCheck[port] = self.nr_packets
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100248
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100249 punts = self.vapi.punt_socket_dump(is_ip6=0)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100250 self.assertEqual(len(punts), 0)
251
252 #
253 # expect ICMP - port unreachable for all packets
254 #
255 self.vapi.cli("clear trace")
256 self.pg0.add_stream(pkts)
257 self.pg_enable_capture(self.pg_interfaces)
258 self.pg_start()
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100259 # FIXME - when punt socket deregister is implemented
260 # rx = self.pg0.get_capture(self.nr_packets)
261 # for p in rx:
262 # self.assertEqual(int(p[IP].proto), 1) # ICMP
263 # self.assertEqual(int(p[ICMP].code), 3) # unreachable
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100264
265 #
266 # configure a punt socket
267 #
Paul Vinciguerra22ab6f72019-03-07 17:55:33 -0800268 self.socket_client_create(b"%s/socket_%d" % (
269 six.ensure_binary(self.tempdir), port))
270 self.vapi.punt_socket_register(port, b"%s/socket_%d" % (
271 six.ensure_binary(self.tempdir), port))
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100272 punts = self.vapi.punt_socket_dump(is_ip6=0)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100273 self.assertEqual(len(punts), 1)
274
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100275 self.logger.debug("Sending %s packets to port %d",
276 str(self.portsCheck[port]), port)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100277 #
278 # expect punt socket and no packets on pg0
279 #
280 self.vapi.cli("clear errors")
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100281 self.vapi.cli("clear trace")
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100282 self.pg0.add_stream(pkts)
283 self.pg_enable_capture(self.pg_interfaces)
284 self.pg_start()
285 self.pg0.get_capture(0)
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100286 self.logger.info(self.vapi.cli("show trace"))
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100287 self.socket_client_close()
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100288 self.assertEqual(self.portsCheck[port], 0)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100289
290 #
291 # remove punt socket. expect ICMP - port unreachable for all packets
292 #
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100293 self.vapi.punt_socket_deregister(port)
294 punts = self.vapi.punt_socket_dump(is_ip6=0)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100295 self.assertEqual(len(punts), 0)
296 self.pg0.add_stream(pkts)
297 self.pg_enable_capture(self.pg_interfaces)
298 self.pg_start()
299 # FIXME - when punt socket deregister is implemented
300 # self.pg0.get_capture(nr_packets)
301
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100302 def test_punt_socket_traffic_multi_port_multi_sockets(self):
303 """ Punt socket traffic multi ports and multi sockets"""
304
305 for p in self.ports:
306 self.portsCheck[p] = 0
307
308 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700309 # create stream with random packets count per given ports
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100310 #
311 pkts = list()
312 for _ in range(0, self.nr_packets):
313 # choose port from port list
314 p = random.choice(self.ports)
315 pkts.append((
316 Ether(src=self.pg0.remote_mac,
317 dst=self.pg0.local_mac) /
318 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
319 UDP(sport=9876, dport=p) /
320 Raw('\xa5' * 100)))
321 self.portsCheck[p] += 1
322 #
323 # no punt socket
324 #
325 punts = self.vapi.punt_socket_dump(is_ip6=0)
326 self.assertEqual(len(punts), 0)
327
328 #
329 # configure a punt socket
330 #
331 for p in self.ports:
Paul Vinciguerra22ab6f72019-03-07 17:55:33 -0800332 self.socket_client_create(b"%s/socket_%d" % (
333 six.ensure_binary(self.tempdir), p))
334 self.vapi.punt_socket_register(p, b"%s/socket_%d" % (
335 six.ensure_binary(self.tempdir), p))
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100336 punts = self.vapi.punt_socket_dump(is_ip6=0)
337 self.assertEqual(len(punts), len(self.ports))
338
339 for p in self.ports:
340 self.logger.debug("Sending %s packets to port %d",
341 str(self.portsCheck[p]), p)
342
343 #
344 # expect punt socket and no packets on pg0
345 #
346 self.vapi.cli("clear errors")
347 self.vapi.cli("clear trace")
348 self.pg0.add_stream(pkts)
349 self.pg_enable_capture(self.pg_interfaces)
350 self.pg_start()
351 self.pg0.get_capture(0)
352 self.logger.info(self.vapi.cli("show trace"))
353 self.socket_client_close()
354
355 for p in self.ports:
356 self.assertEqual(self.portsCheck[p], 0)
357 self.vapi.punt_socket_deregister(p)
358 punts = self.vapi.punt_socket_dump(is_ip6=0)
359 self.assertEqual(len(punts), 0)
360
361 def test_punt_socket_traffic_multi_ports_single_socket(self):
362 """ Punt socket traffic multi ports and single socket"""
363
364 for p in self.ports:
365 self.portsCheck[p] = 0
366
367 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700368 # create stream with random packets count per given ports
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100369 #
370 pkts = list()
371 for _ in range(0, self.nr_packets):
372 # choose port from port list
373 p = random.choice(self.ports)
374 pkts.append((
375 Ether(src=self.pg0.remote_mac,
376 dst=self.pg0.local_mac) /
377 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
378 UDP(sport=9876, dport=p) /
379 Raw('\xa5' * 100)))
380 self.portsCheck[p] += 1
381
382 #
383 # no punt socket
384 #
385 punts = self.vapi.punt_socket_dump(is_ip6=0)
386 self.assertEqual(len(punts), 0)
387
388 # configure a punt socket
389 #
Paul Vinciguerra22ab6f72019-03-07 17:55:33 -0800390 self.socket_client_create(b"%s/socket_multi" %
391 six.ensure_binary(self.tempdir))
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100392 for p in self.ports:
Paul Vinciguerra22ab6f72019-03-07 17:55:33 -0800393 self.vapi.punt_socket_register(p,
394 b"%s/socket_multi" %
395 six.ensure_binary(self.tempdir))
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100396 punts = self.vapi.punt_socket_dump(is_ip6=0)
397 self.assertEqual(len(punts), len(self.ports))
398
399 for p in self.ports:
400 self.logger.debug("Sending %s packets to port %d",
401 str(self.portsCheck[p]), p)
402 #
403 # expect punt socket and no packets on pg0
404 #
405 self.vapi.cli("clear errors")
406 self.vapi.cli("clear trace")
407 self.pg0.add_stream(pkts)
408 self.pg_enable_capture(self.pg_interfaces)
409 self.pg_start()
410 self.pg0.get_capture(0)
411 self.logger.info(self.vapi.cli("show trace"))
412 self.socket_client_close()
413
414 for p in self.ports:
415 self.assertEqual(self.portsCheck[p], 0)
416 self.vapi.punt_socket_deregister(p)
417 punts = self.vapi.punt_socket_dump(is_ip6=0)
418 self.assertEqual(len(punts), 0)
419
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100420
421class TestIP6PuntSocket(TestPuntSocket):
422 """ Punt Socket for IPv6"""
423
Paul Vinciguerra8d991d92019-01-25 14:05:48 -0800424 @classmethod
425 def setUpClass(cls):
426 super(TestIP6PuntSocket, cls).setUpClass()
427
428 @classmethod
429 def tearDownClass(cls):
430 super(TestIP6PuntSocket, cls).tearDownClass()
431
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100432 def setUp(self):
433 super(TestIP6PuntSocket, self).setUp()
434
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100435 for i in self.pg_interfaces:
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100436 i.config_ip6()
437 i.resolve_ndp()
438
439 def tearDown(self):
440 super(TestIP6PuntSocket, self).tearDown()
441 for i in self.pg_interfaces:
442 i.unconfig_ip6()
443 i.admin_down()
444
445 def test_punt_socket_dump(self):
446 """ Punt socket registration """
447
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100448 punts = self.vapi.punt_socket_dump(is_ip6=1)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100449 self.assertEqual(len(punts), 0)
450
451 #
452 # configure a punt socket
453 #
Paul Vinciguerra22ab6f72019-03-07 17:55:33 -0800454 self.vapi.punt_socket_register(1111, b"%s/socket_1111" %
455 six.ensure_binary(self.tempdir),
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100456 is_ip4=0)
Paul Vinciguerra22ab6f72019-03-07 17:55:33 -0800457 self.vapi.punt_socket_register(2222, b"%s/socket_2222" %
458 six.ensure_binary(self.tempdir),
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100459 is_ip4=0)
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100460 punts = self.vapi.punt_socket_dump(is_ip6=1)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100461 self.assertEqual(len(punts), 2)
462 self.assertEqual(punts[0].punt.l4_port, 1111)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100463 self.assertEqual(punts[1].punt.l4_port, 2222)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100464
465 #
466 # deregister a punt socket
467 #
468 self.vapi.punt_socket_deregister(1111, is_ip4=0)
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100469 punts = self.vapi.punt_socket_dump(is_ip6=1)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100470 self.assertEqual(len(punts), 1)
471
472 #
473 # configure a punt socket again
474 #
Paul Vinciguerra22ab6f72019-03-07 17:55:33 -0800475 self.vapi.punt_socket_register(1111, b"%s/socket_1111" %
476 six.ensure_binary(self.tempdir),
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100477 is_ip4=0)
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100478 punts = self.vapi.punt_socket_dump(is_ip6=1)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100479 self.assertEqual(len(punts), 2)
480
481 #
482 # deregister all punt socket
483 #
484 self.vapi.punt_socket_deregister(1111, is_ip4=0)
485 self.vapi.punt_socket_deregister(2222, is_ip4=0)
486 self.vapi.punt_socket_deregister(3333, is_ip4=0)
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100487 punts = self.vapi.punt_socket_dump(is_ip6=1)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100488 self.assertEqual(len(punts), 0)
489
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100490 def test_punt_socket_traffic_single_port_single_socket(self):
491 """ Punt socket traffic single port single socket"""
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100492
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100493 port = self.ports[0]
494
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100495 p = (Ether(src=self.pg0.remote_mac,
496 dst=self.pg0.local_mac) /
497 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100498 inet6.UDP(sport=9876, dport=port) /
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100499 Raw('\xa5' * 100))
500
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100501 pkts = p * self.nr_packets
502 self.portsCheck[port] = self.nr_packets
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100503
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100504 punts = self.vapi.punt_socket_dump(is_ip6=1)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100505 self.assertEqual(len(punts), 0)
506
507 #
508 # expect ICMPv6 - destination unreachable for all packets
509 #
510 self.vapi.cli("clear trace")
511 self.pg0.add_stream(pkts)
512 self.pg_enable_capture(self.pg_interfaces)
513 self.pg_start()
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100514 # FIXME - when punt socket deregister is implemented
515 # rx = self.pg0.get_capture(self.nr_packets)
516 # for p in rx:
517 # self.assertEqual(int(p[IPv6].nh), 58) # ICMPv6
518 # self.assertEqual(int(p[ICMPv6DestUnreach].code),4) # unreachable
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100519
520 #
521 # configure a punt socket
522 #
Paul Vinciguerra22ab6f72019-03-07 17:55:33 -0800523 self.socket_client_create(b"%s/socket_%d" % (
524 six.ensure_binary(self.tempdir), port))
525 self.vapi.punt_socket_register(port, b"%s/socket_%d" % (
526 six.ensure_binary(self.tempdir), port), is_ip4=0)
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100527 punts = self.vapi.punt_socket_dump(is_ip6=1)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100528 self.assertEqual(len(punts), 1)
529
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100530 self.logger.debug("Sending %s packets to port %d",
531 str(self.portsCheck[port]), port)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100532 #
533 # expect punt socket and no packets on pg0
534 #
535 self.vapi.cli("clear errors")
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100536 self.vapi.cli("clear trace")
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100537 self.pg0.add_stream(pkts)
538 self.pg_enable_capture(self.pg_interfaces)
539 self.pg_start()
540 self.pg0.get_capture(0)
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100541 self.logger.info(self.vapi.cli("show trace"))
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100542 self.socket_client_close()
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100543 self.assertEqual(self.portsCheck[port], 0)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100544
545 #
546 # remove punt socket. expect ICMP - dest. unreachable for all packets
547 #
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100548 self.vapi.punt_socket_deregister(port, is_ip4=0)
549 punts = self.vapi.punt_socket_dump(is_ip6=1)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100550 self.assertEqual(len(punts), 0)
551 self.pg0.add_stream(pkts)
552 self.pg_enable_capture(self.pg_interfaces)
553 self.pg_start()
554 # FIXME - when punt socket deregister is implemented
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100555 # self.pg0.get_capture(nr_packets)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100556
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100557 def test_punt_socket_traffic_multi_port_multi_sockets(self):
558 """ Punt socket traffic multi ports and multi sockets"""
559
560 for p in self.ports:
561 self.portsCheck[p] = 0
562
563 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700564 # create stream with random packets count per given ports
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100565 #
566 pkts = list()
567 for _ in range(0, self.nr_packets):
568 # choose port from port list
569 p = random.choice(self.ports)
570 pkts.append((
571 Ether(src=self.pg0.remote_mac,
572 dst=self.pg0.local_mac) /
573 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
574 inet6.UDP(sport=9876, dport=p) /
575 Raw('\xa5' * 100)))
576 self.portsCheck[p] += 1
577 #
578 # no punt socket
579 #
580 punts = self.vapi.punt_socket_dump(is_ip6=1)
581 self.assertEqual(len(punts), 0)
582
583 #
584 # configure a punt socket
585 #
586 for p in self.ports:
Paul Vinciguerra22ab6f72019-03-07 17:55:33 -0800587 self.socket_client_create(b"%s/socket_%d" % (
588 six.ensure_binary(self.tempdir), p))
589 self.vapi.punt_socket_register(p, b"%s/socket_%d" % (
590 six.ensure_binary(self.tempdir), p), is_ip4=0)
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100591 punts = self.vapi.punt_socket_dump(is_ip6=1)
592 self.assertEqual(len(punts), len(self.ports))
593
594 for p in self.ports:
595 self.logger.debug("Sending %s packets to port %d",
596 str(self.portsCheck[p]), p)
597
598 #
599 # expect punt socket and no packets on pg0
600 #
601 self.vapi.cli("clear errors")
602 self.vapi.cli("clear trace")
603 self.pg0.add_stream(pkts)
604 self.pg_enable_capture(self.pg_interfaces)
605 self.pg_start()
606 self.pg0.get_capture(0)
607 self.logger.info(self.vapi.cli("show trace"))
608 self.socket_client_close()
609
610 for p in self.ports:
611 self.assertEqual(self.portsCheck[p], 0)
612 self.vapi.punt_socket_deregister(p, is_ip4=0)
613 punts = self.vapi.punt_socket_dump(is_ip6=1)
614 self.assertEqual(len(punts), 0)
615
616 def test_punt_socket_traffic_multi_ports_single_socket(self):
617 """ Punt socket traffic multi ports and single socket"""
618
619 for p in self.ports:
620 self.portsCheck[p] = 0
621
622 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700623 # create stream with random packets count per given ports
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100624 #
625 pkts = list()
626 for _ in range(0, self.nr_packets):
627 # choose port from port list
628 p = random.choice(self.ports)
629 pkts.append((
630 Ether(src=self.pg0.remote_mac,
631 dst=self.pg0.local_mac) /
632 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
633 inet6.UDP(sport=9876, dport=p) /
634 Raw('\xa5' * 100)))
635 self.portsCheck[p] += 1
636
637 #
638 # no punt socket
639 #
640 punts = self.vapi.punt_socket_dump(is_ip6=1)
641 self.assertEqual(len(punts), 0)
642
643 #
644 # configure a punt socket
645 #
Paul Vinciguerra22ab6f72019-03-07 17:55:33 -0800646 self.socket_client_create(b"%s/socket_multi" %
647 six.ensure_binary(self.tempdir))
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100648 for p in self.ports:
Paul Vinciguerra22ab6f72019-03-07 17:55:33 -0800649 self.vapi.punt_socket_register(p,
650 b"%s/socket_multi" %
651 six.ensure_binary(self.tempdir),
Pavel Kotucek9edb83a2018-12-11 16:57:25 +0100652 is_ip4=0)
653 punts = self.vapi.punt_socket_dump(is_ip6=1)
654 self.assertEqual(len(punts), len(self.ports))
655
656 for p in self.ports:
657 self.logger.debug("Send %s packets to port %d",
658 str(self.portsCheck[p]), p)
659 #
660 # expect punt socket and no packets on pg0
661 #
662 self.vapi.cli("clear errors")
663 self.vapi.cli("clear trace")
664 self.pg0.add_stream(pkts)
665 self.pg_enable_capture(self.pg_interfaces)
666 self.pg_start()
667 self.pg0.get_capture(0)
668 self.logger.info(self.vapi.cli("show trace"))
669 self.socket_client_close()
670
671 for p in self.ports:
672 self.assertEqual(self.portsCheck[p], 0)
673 self.vapi.punt_socket_deregister(p, is_ip4=0)
674 punts = self.vapi.punt_socket_dump(is_ip6=1)
675 self.assertEqual(len(punts), 0)
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100676
Neale Ranns76b56492018-09-28 15:16:14 +0000677
678class TestPunt(VppTestCase):
679 """ Punt Test Case """
680
681 @classmethod
682 def setUpClass(cls):
683 super(TestPunt, cls).setUpClass()
684
685 @classmethod
686 def tearDownClass(cls):
687 super(TestPunt, cls).tearDownClass()
688
689 def setUp(self):
690 super(TestPunt, self).setUp()
691
692 self.create_pg_interfaces(range(4))
693
694 for i in self.pg_interfaces:
695 i.admin_up()
696 i.config_ip4()
697 i.resolve_arp()
698 i.config_ip6()
699 i.resolve_ndp()
700
701 def tearDown(self):
702 for i in self.pg_interfaces:
703 i.unconfig_ip4()
704 i.unconfig_ip6()
705 i.ip6_disable()
706 i.admin_down()
707 super(TestPunt, self).tearDown()
708
709 def test_punt(self):
710 """ Excpetion Path testing """
711
712 #
713 # Using the test CLI we will hook in a exception path to
714 # send ACL deny packets out of pg0 and pg1.
715 # the ACL is src,dst = 1.1.1.1,1.1.1.2
716 #
717 ip_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32,
718 [VppRoutePath(self.pg3.remote_ip4,
719 self.pg3.sw_if_index)])
720 ip_1_1_1_2.add_vpp_config()
721 ip_1_2 = VppIpRoute(self, "1::2", 128,
722 [VppRoutePath(self.pg3.remote_ip6,
723 self.pg3.sw_if_index,
724 proto=DpoProto.DPO_PROTO_IP6)],
725 is_ip6=1)
726 ip_1_2.add_vpp_config()
727
728 p4 = (Ether(src=self.pg2.remote_mac,
729 dst=self.pg2.local_mac) /
730 IP(src="1.1.1.1", dst="1.1.1.2") /
731 UDP(sport=1234, dport=1234) /
732 Raw('\xa5' * 100))
733 p6 = (Ether(src=self.pg2.remote_mac,
734 dst=self.pg2.local_mac) /
735 IPv6(src="1::1", dst="1::2") /
736 UDP(sport=1234, dport=1234) /
737 Raw('\xa5' * 100))
738 self.send_and_expect(self.pg2, p4*1, self.pg3)
739 self.send_and_expect(self.pg2, p6*1, self.pg3)
740
741 #
742 # apply the punting features
743 #
744 self.vapi.cli("test punt pg2")
745
746 #
747 # pkts now dropped
748 #
749 self.send_and_assert_no_replies(self.pg2, p4*65)
750 self.send_and_assert_no_replies(self.pg2, p6*65)
751
752 #
753 # Check state:
754 # 1 - node error counters
755 # 2 - per-reason counters
756 # 2, 3 are the index of the assigned punt reason
757 #
758 stats = self.statistics.get_counter(
759 "/err/punt-dispatch/No registrations")
760 self.assertEqual(stats, 130)
761
762 stats = self.statistics.get_counter("/net/punt")
Neale Rannsb71fa752019-04-04 12:43:36 +0000763 self.assertEqual(stats[0][7]['packets'], 65)
764 self.assertEqual(stats[0][8]['packets'], 65)
Neale Ranns76b56492018-09-28 15:16:14 +0000765
766 #
767 # use the test CLI to test a client that punts exception
768 # packets out of pg0
769 #
770 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip4)
771 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip6)
772
773 rx4s = self.send_and_expect(self.pg2, p4*65, self.pg0)
774 rx6s = self.send_and_expect(self.pg2, p6*65, self.pg0)
775
776 #
777 # check the packets come out IP unmodified but destined to pg0 host
778 #
779 for rx in rx4s:
780 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
781 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
782 self.assertEqual(p4[IP].dst, rx[IP].dst)
783 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
784 for rx in rx6s:
785 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
786 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
787 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
788 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
789
790 stats = self.statistics.get_counter("/net/punt")
Neale Rannsb71fa752019-04-04 12:43:36 +0000791 self.assertEqual(stats[0][7]['packets'], 2*65)
792 self.assertEqual(stats[0][8]['packets'], 2*65)
Neale Ranns76b56492018-09-28 15:16:14 +0000793
794 #
795 # add another registration for the same reason to send packets
796 # out of pg1
797 #
798 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip4)
799 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip6)
800
801 self.vapi.cli("clear trace")
802 self.pg2.add_stream(p4 * 65)
803 self.pg_enable_capture(self.pg_interfaces)
804 self.pg_start()
805
806 rxd = self.pg0.get_capture(65)
807 for rx in rxd:
808 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
809 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
810 self.assertEqual(p4[IP].dst, rx[IP].dst)
811 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
812 rxd = self.pg1.get_capture(65)
813 for rx in rxd:
814 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
815 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
816 self.assertEqual(p4[IP].dst, rx[IP].dst)
817 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
818
819 self.vapi.cli("clear trace")
820 self.pg2.add_stream(p6 * 65)
821 self.pg_enable_capture(self.pg_interfaces)
822 self.pg_start()
823
824 rxd = self.pg0.get_capture(65)
825 for rx in rxd:
826 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
827 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
828 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
829 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
830 rxd = self.pg1.get_capture(65)
831 for rx in rxd:
832 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
833 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
834 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
835 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
836
837 stats = self.statistics.get_counter("/net/punt")
Neale Rannsb71fa752019-04-04 12:43:36 +0000838 self.assertEqual(stats[0][7]['packets'], 3*65)
839 self.assertEqual(stats[0][8]['packets'], 3*65)
Neale Ranns76b56492018-09-28 15:16:14 +0000840
841 self.logger.info(self.vapi.cli("show vlib graph punt-dispatch"))
842 self.logger.info(self.vapi.cli("show punt client"))
843 self.logger.info(self.vapi.cli("show punt reason"))
844 self.logger.info(self.vapi.cli("show punt stats"))
845 self.logger.info(self.vapi.cli("show punt db"))
846
847 self.vapi.cli("test punt clear")
848
849
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100850if __name__ == '__main__':
851 unittest.main(testRunner=VppTestRunner)