cb9d40de4c492ccacd63bc2291d8094508659247
[vpp.git] / test / test_punt.py
1 #!/usr/bin/env python
2 import binascii
3 import random
4 import socket
5 import os
6 import threading
7 import struct
8 from struct import unpack, unpack_from
9
10 try:
11     import unittest2 as unittest
12 except ImportError:
13     import unittest
14
15 from util import ppp, ppc
16 from re import compile
17 import scapy.compat
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
23 import six
24 from framework import VppTestCase, VppTestRunner
25
26 from vpp_ip import DpoProto
27 from vpp_ip_route import VppIpRoute, VppRoutePath
28
29
30 # Format MAC Address
31 def get_mac_addr(bytes_addr):
32     return ':'.join('%02x' % scapy.compat.orb(b) for b in bytes_addr)
33
34
35 # Format IP Address
36 def ipv4(bytes_addr):
37     return '.'.join('%d' % scapy.compat.orb(b) for b in bytes_addr)
38
39
40 # Unpack Ethernet Frame
41 def 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
47 def 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
53 def 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
59 def 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
65 def 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
70 def 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
102 class 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
123 class TestPuntSocket(VppTestCase):
124     """ Punt Socket """
125
126     ports = [1111, 2222, 3333, 4444]
127     sock_servers = list()
128     portsCheck = dict()
129     nr_packets = 256
130
131     @classmethod
132     def setUpClass(cls):
133         super(TestPuntSocket, cls).setUpClass()
134
135     @classmethod
136     def tearDownClass(cls):
137         super(TestPuntSocket, cls).tearDownClass()
138
139     @classmethod
140     def setUpConstants(cls):
141         cls.extra_vpp_punt_config = [
142             "punt", "{", "socket", cls.tempdir+"/socket_punt", "}"]
143         super(TestPuntSocket, cls).setUpConstants()
144
145     def setUp(self):
146         super(TestPuntSocket, self).setUp()
147         random.seed()
148
149         self.create_pg_interfaces(range(2))
150         for i in self.pg_interfaces:
151             i.admin_up()
152
153     def tearDown(self):
154         del self.sock_servers[:]
155         super(TestPuntSocket, self).tearDown()
156
157     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()
161
162     def socket_client_close(self):
163         for thread in self.sock_servers:
164             thread.sock.close()
165
166
167 class TestIP4PuntSocket(TestPuntSocket):
168     """ Punt Socket for IPv4 """
169
170     @classmethod
171     def setUpClass(cls):
172         super(TestIP4PuntSocket, cls).setUpClass()
173
174     @classmethod
175     def tearDownClass(cls):
176         super(TestIP4PuntSocket, cls).tearDownClass()
177
178     def setUp(self):
179         super(TestIP4PuntSocket, self).setUp()
180
181         for i in self.pg_interfaces:
182             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):
192         """ Punt socket registration/deregistration"""
193
194         punts = self.vapi.punt_socket_dump(is_ip6=0)
195         self.assertEqual(len(punts), 0)
196
197         #
198         # configure a punt socket
199         #
200         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))
204         punts = self.vapi.punt_socket_dump(is_ip6=0)
205         self.assertEqual(len(punts), 2)
206         self.assertEqual(punts[0].punt.l4_port, 1111)
207         self.assertEqual(punts[1].punt.l4_port, 2222)
208
209         #
210         # deregister a punt socket
211         #
212         self.vapi.punt_socket_deregister(1111)
213         punts = self.vapi.punt_socket_dump(is_ip6=0)
214         self.assertEqual(len(punts), 1)
215
216         #
217         # configure a punt socket again
218         #
219         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))
223         punts = self.vapi.punt_socket_dump(is_ip6=0)
224         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)
232         punts = self.vapi.punt_socket_dump(is_ip6=0)
233         self.assertEqual(len(punts), 0)
234
235     def test_punt_socket_traffic_single_port_single_socket(self):
236         """ Punt socket traffic single port single socket"""
237
238         port = self.ports[0]
239
240         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) /
243              UDP(sport=9876, dport=port) /
244              Raw('\xa5' * 100))
245
246         pkts = p * self.nr_packets
247         self.portsCheck[port] = self.nr_packets
248
249         punts = self.vapi.punt_socket_dump(is_ip6=0)
250         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()
259         # 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
264
265         #
266         # configure a punt socket
267         #
268         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))
272         punts = self.vapi.punt_socket_dump(is_ip6=0)
273         self.assertEqual(len(punts), 1)
274
275         self.logger.debug("Sending %s packets to port %d",
276                           str(self.portsCheck[port]), port)
277         #
278         # expect punt socket and no packets on pg0
279         #
280         self.vapi.cli("clear errors")
281         self.vapi.cli("clear trace")
282         self.pg0.add_stream(pkts)
283         self.pg_enable_capture(self.pg_interfaces)
284         self.pg_start()
285         self.pg0.get_capture(0)
286         self.logger.info(self.vapi.cli("show trace"))
287         self.socket_client_close()
288         self.assertEqual(self.portsCheck[port], 0)
289
290         #
291         # remove punt socket. expect ICMP - port unreachable for all packets
292         #
293         self.vapi.punt_socket_deregister(port)
294         punts = self.vapi.punt_socket_dump(is_ip6=0)
295         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
302     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         #
309         # create stream with random packets count per given ports
310         #
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:
332             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))
336         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         #
368         # create stream with random packets count per given ports
369         #
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         #
390         self.socket_client_create(b"%s/socket_multi" %
391                                   six.ensure_binary(self.tempdir))
392         for p in self.ports:
393             self.vapi.punt_socket_register(p,
394                                            b"%s/socket_multi" %
395                                            six.ensure_binary(self.tempdir))
396         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
420
421 class TestIP6PuntSocket(TestPuntSocket):
422     """ Punt Socket for IPv6"""
423
424     @classmethod
425     def setUpClass(cls):
426         super(TestIP6PuntSocket, cls).setUpClass()
427
428     @classmethod
429     def tearDownClass(cls):
430         super(TestIP6PuntSocket, cls).tearDownClass()
431
432     def setUp(self):
433         super(TestIP6PuntSocket, self).setUp()
434
435         for i in self.pg_interfaces:
436             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
448         punts = self.vapi.punt_socket_dump(is_ip6=1)
449         self.assertEqual(len(punts), 0)
450
451         #
452         # configure a punt socket
453         #
454         self.vapi.punt_socket_register(1111, b"%s/socket_1111" %
455                                        six.ensure_binary(self.tempdir),
456                                        is_ip4=0)
457         self.vapi.punt_socket_register(2222, b"%s/socket_2222" %
458                                        six.ensure_binary(self.tempdir),
459                                        is_ip4=0)
460         punts = self.vapi.punt_socket_dump(is_ip6=1)
461         self.assertEqual(len(punts), 2)
462         self.assertEqual(punts[0].punt.l4_port, 1111)
463         self.assertEqual(punts[1].punt.l4_port, 2222)
464
465         #
466         # deregister a punt socket
467         #
468         self.vapi.punt_socket_deregister(1111, is_ip4=0)
469         punts = self.vapi.punt_socket_dump(is_ip6=1)
470         self.assertEqual(len(punts), 1)
471
472         #
473         # configure a punt socket again
474         #
475         self.vapi.punt_socket_register(1111, b"%s/socket_1111" %
476                                        six.ensure_binary(self.tempdir),
477                                        is_ip4=0)
478         punts = self.vapi.punt_socket_dump(is_ip6=1)
479         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)
487         punts = self.vapi.punt_socket_dump(is_ip6=1)
488         self.assertEqual(len(punts), 0)
489
490     def test_punt_socket_traffic_single_port_single_socket(self):
491         """ Punt socket traffic single port single socket"""
492
493         port = self.ports[0]
494
495         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) /
498              inet6.UDP(sport=9876, dport=port) /
499              Raw('\xa5' * 100))
500
501         pkts = p * self.nr_packets
502         self.portsCheck[port] = self.nr_packets
503
504         punts = self.vapi.punt_socket_dump(is_ip6=1)
505         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()
514         # 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
519
520         #
521         # configure a punt socket
522         #
523         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)
527         punts = self.vapi.punt_socket_dump(is_ip6=1)
528         self.assertEqual(len(punts), 1)
529
530         self.logger.debug("Sending %s packets to port %d",
531                           str(self.portsCheck[port]), port)
532         #
533         # expect punt socket and no packets on pg0
534         #
535         self.vapi.cli("clear errors")
536         self.vapi.cli("clear trace")
537         self.pg0.add_stream(pkts)
538         self.pg_enable_capture(self.pg_interfaces)
539         self.pg_start()
540         self.pg0.get_capture(0)
541         self.logger.info(self.vapi.cli("show trace"))
542         self.socket_client_close()
543         self.assertEqual(self.portsCheck[port], 0)
544
545         #
546         # remove punt socket. expect ICMP - dest. unreachable for all packets
547         #
548         self.vapi.punt_socket_deregister(port, is_ip4=0)
549         punts = self.vapi.punt_socket_dump(is_ip6=1)
550         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
555         # self.pg0.get_capture(nr_packets)
556
557     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         #
564         # create stream with random packets count per given ports
565         #
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:
587             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)
591         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         #
623         # create stream with random packets count per given ports
624         #
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         #
646         self.socket_client_create(b"%s/socket_multi" %
647                                   six.ensure_binary(self.tempdir))
648         for p in self.ports:
649             self.vapi.punt_socket_register(p,
650                                            b"%s/socket_multi" %
651                                            six.ensure_binary(self.tempdir),
652                                            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)
676
677
678 class 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")
763         self.assertEqual(stats[0][7]['packets'], 65)
764         self.assertEqual(stats[0][8]['packets'], 65)
765
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")
791         self.assertEqual(stats[0][7]['packets'], 2*65)
792         self.assertEqual(stats[0][8]['packets'], 2*65)
793
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")
838         self.assertEqual(stats[0][7]['packets'], 3*65)
839         self.assertEqual(stats[0][8]['packets'], 3*65)
840
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
850 if __name__ == '__main__':
851     unittest.main(testRunner=VppTestRunner)