VPP-1508 python3 tests: .encode('hex')
[vpp.git] / test / test_ip4.py
1 #!/usr/bin/env python
2 import binascii
3 import random
4 import socket
5 import unittest
6
7 from framework import VppTestCase, VppTestRunner
8 from vpp_sub_interface import VppSubInterface, VppDot1QSubint, VppDot1ADSubint
9 from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpMRoute, \
10     VppMRoutePath, MRouteItfFlags, MRouteEntryFlags, VppMplsIpBind, \
11     VppMplsTable, VppIpTable
12
13 from scapy.packet import Raw
14 from scapy.layers.l2 import Ether, Dot1Q, ARP
15 from scapy.layers.inet import IP, UDP, TCP, ICMP, icmptypes, icmpcodes
16 from util import ppp
17 from scapy.contrib.mpls import MPLS
18
19
20 class TestIPv4(VppTestCase):
21     """ IPv4 Test Case """
22
23     def setUp(self):
24         """
25         Perform test setup before test case.
26
27         **Config:**
28             - create 3 pg interfaces
29                 - untagged pg0 interface
30                 - Dot1Q subinterface on pg1
31                 - Dot1AD subinterface on pg2
32             - setup interfaces:
33                 - put it into UP state
34                 - set IPv4 addresses
35                 - resolve neighbor address using ARP
36             - configure 200 fib entries
37
38         :ivar list interfaces: pg interfaces and subinterfaces.
39         :ivar dict flows: IPv4 packet flows in test.
40         """
41         super(TestIPv4, self).setUp()
42
43         # create 3 pg interfaces
44         self.create_pg_interfaces(range(3))
45
46         # create 2 subinterfaces for pg1 and pg2
47         self.sub_interfaces = [
48             VppDot1QSubint(self, self.pg1, 100),
49             VppDot1ADSubint(self, self.pg2, 200, 300, 400)]
50
51         # packet flows mapping pg0 -> pg1.sub, pg2.sub, etc.
52         self.flows = dict()
53         self.flows[self.pg0] = [self.pg1.sub_if, self.pg2.sub_if]
54         self.flows[self.pg1.sub_if] = [self.pg0, self.pg2.sub_if]
55         self.flows[self.pg2.sub_if] = [self.pg0, self.pg1.sub_if]
56
57         # packet sizes
58         self.pg_if_packet_sizes = [64, 1500, 9020]
59
60         self.interfaces = list(self.pg_interfaces)
61         self.interfaces.extend(self.sub_interfaces)
62
63         # setup all interfaces
64         for i in self.interfaces:
65             i.admin_up()
66             i.config_ip4()
67             i.resolve_arp()
68
69         # config 2M FIB entries
70         self.config_fib_entries(200)
71
72     def tearDown(self):
73         """Run standard test teardown and log ``show ip arp``."""
74         super(TestIPv4, self).tearDown()
75         if not self.vpp_dead:
76             self.logger.info(self.vapi.cli("show ip arp"))
77             # info(self.vapi.cli("show ip fib"))  # many entries
78
79     def config_fib_entries(self, count):
80         """For each interface add to the FIB table *count* routes to
81         "10.0.0.1/32" destination with interface's local address as next-hop
82         address.
83
84         :param int count: Number of FIB entries.
85
86         - *TODO:* check if the next-hop address shouldn't be remote address
87           instead of local address.
88         """
89         n_int = len(self.interfaces)
90         percent = 0
91         counter = 0.0
92         dest_addr = socket.inet_pton(socket.AF_INET, "10.0.0.1")
93         dest_addr_len = 32
94         for i in self.interfaces:
95             next_hop_address = i.local_ip4n
96             for j in range(count / n_int):
97                 self.vapi.ip_add_del_route(
98                     dest_addr, dest_addr_len, next_hop_address)
99                 counter += 1
100                 if counter / count * 100 > percent:
101                     self.logger.info("Configure %d FIB entries .. %d%% done" %
102                                      (count, percent))
103                     percent += 1
104
105     def modify_packet(self, src_if, packet_size, pkt):
106         """Add load, set destination IP and extend packet to required packet
107         size for defined interface.
108
109         :param VppInterface src_if: Interface to create packet for.
110         :param int packet_size: Required packet size.
111         :param Scapy pkt: Packet to be modified.
112         """
113         dst_if_idx = packet_size / 10 % 2
114         dst_if = self.flows[src_if][dst_if_idx]
115         info = self.create_packet_info(src_if, dst_if)
116         payload = self.info_to_payload(info)
117         p = pkt/Raw(payload)
118         p[IP].dst = dst_if.remote_ip4
119         info.data = p.copy()
120         if isinstance(src_if, VppSubInterface):
121             p = src_if.add_dot1_layer(p)
122         self.extend_packet(p, packet_size)
123
124         return p
125
126     def create_stream(self, src_if):
127         """Create input packet stream for defined interface.
128
129         :param VppInterface src_if: Interface to create packet stream for.
130         """
131         hdr_ext = 4 if isinstance(src_if, VppSubInterface) else 0
132         pkt_tmpl = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
133                     IP(src=src_if.remote_ip4) /
134                     UDP(sport=1234, dport=1234))
135
136         pkts = [self.modify_packet(src_if, i, pkt_tmpl)
137                 for i in xrange(self.pg_if_packet_sizes[0],
138                                 self.pg_if_packet_sizes[1], 10)]
139         pkts_b = [self.modify_packet(src_if, i, pkt_tmpl)
140                   for i in xrange(self.pg_if_packet_sizes[1] + hdr_ext,
141                                   self.pg_if_packet_sizes[2] + hdr_ext, 50)]
142         pkts.extend(pkts_b)
143
144         return pkts
145
146     def verify_capture(self, dst_if, capture):
147         """Verify captured input packet stream for defined interface.
148
149         :param VppInterface dst_if: Interface to verify captured packet stream
150             for.
151         :param list capture: Captured packet stream.
152         """
153         self.logger.info("Verifying capture on interface %s" % dst_if.name)
154         last_info = dict()
155         for i in self.interfaces:
156             last_info[i.sw_if_index] = None
157         is_sub_if = False
158         dst_sw_if_index = dst_if.sw_if_index
159         if hasattr(dst_if, 'parent'):
160             is_sub_if = True
161         for packet in capture:
162             if is_sub_if:
163                 # Check VLAN tags and Ethernet header
164                 packet = dst_if.remove_dot1_layer(packet)
165             self.assertTrue(Dot1Q not in packet)
166             try:
167                 ip = packet[IP]
168                 udp = packet[UDP]
169                 payload_info = self.payload_to_info(str(packet[Raw]))
170                 packet_index = payload_info.index
171                 self.assertEqual(payload_info.dst, dst_sw_if_index)
172                 self.logger.debug(
173                     "Got packet on port %s: src=%u (id=%u)" %
174                     (dst_if.name, payload_info.src, packet_index))
175                 next_info = self.get_next_packet_info_for_interface2(
176                     payload_info.src, dst_sw_if_index,
177                     last_info[payload_info.src])
178                 last_info[payload_info.src] = next_info
179                 self.assertTrue(next_info is not None)
180                 self.assertEqual(packet_index, next_info.index)
181                 saved_packet = next_info.data
182                 # Check standard fields
183                 self.assertEqual(ip.src, saved_packet[IP].src)
184                 self.assertEqual(ip.dst, saved_packet[IP].dst)
185                 self.assertEqual(udp.sport, saved_packet[UDP].sport)
186                 self.assertEqual(udp.dport, saved_packet[UDP].dport)
187             except:
188                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
189                 raise
190         for i in self.interfaces:
191             remaining_packet = self.get_next_packet_info_for_interface2(
192                 i.sw_if_index, dst_sw_if_index, last_info[i.sw_if_index])
193             self.assertTrue(remaining_packet is None,
194                             "Interface %s: Packet expected from interface %s "
195                             "didn't arrive" % (dst_if.name, i.name))
196
197     def test_fib(self):
198         """ IPv4 FIB test
199
200         Test scenario:
201
202             - Create IPv4 stream for pg0 interface
203             - Create IPv4 tagged streams for pg1's and pg2's sub-interface.
204             - Send and verify received packets on each interface.
205         """
206
207         pkts = self.create_stream(self.pg0)
208         self.pg0.add_stream(pkts)
209
210         for i in self.sub_interfaces:
211             pkts = self.create_stream(i)
212             i.parent.add_stream(pkts)
213
214         self.pg_enable_capture(self.pg_interfaces)
215         self.pg_start()
216
217         pkts = self.pg0.get_capture()
218         self.verify_capture(self.pg0, pkts)
219
220         for i in self.sub_interfaces:
221             pkts = i.parent.get_capture()
222             self.verify_capture(i, pkts)
223
224
225 class TestICMPEcho(VppTestCase):
226     """ ICMP Echo Test Case """
227
228     def setUp(self):
229         super(TestICMPEcho, self).setUp()
230
231         # create 1 pg interface
232         self.create_pg_interfaces(range(1))
233
234         for i in self.pg_interfaces:
235             i.admin_up()
236             i.config_ip4()
237             i.resolve_arp()
238
239     def tearDown(self):
240         super(TestICMPEcho, self).tearDown()
241         for i in self.pg_interfaces:
242             i.unconfig_ip4()
243             i.admin_down()
244
245     def test_icmp_echo(self):
246         """ VPP replies to ICMP Echo Request
247
248         Test scenario:
249
250             - Receive ICMP Echo Request message on pg0 interface.
251             - Check outgoing ICMP Echo Reply message on pg0 interface.
252         """
253
254         icmp_id = 0xb
255         icmp_seq = 5
256         icmp_load = '\x0a' * 18
257         p_echo_request = (Ether(src=self.pg0.remote_mac,
258                                 dst=self.pg0.local_mac) /
259                           IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
260                           ICMP(id=icmp_id, seq=icmp_seq) /
261                           Raw(load=icmp_load))
262
263         self.pg0.add_stream(p_echo_request)
264         self.pg_enable_capture(self.pg_interfaces)
265         self.pg_start()
266
267         rx = self.pg0.get_capture(1)
268         rx = rx[0]
269         ether = rx[Ether]
270         ipv4 = rx[IP]
271         icmp = rx[ICMP]
272
273         self.assertEqual(ether.src, self.pg0.local_mac)
274         self.assertEqual(ether.dst, self.pg0.remote_mac)
275
276         self.assertEqual(ipv4.src, self.pg0.local_ip4)
277         self.assertEqual(ipv4.dst, self.pg0.remote_ip4)
278
279         self.assertEqual(icmptypes[icmp.type], "echo-reply")
280         self.assertEqual(icmp.id, icmp_id)
281         self.assertEqual(icmp.seq, icmp_seq)
282         self.assertEqual(icmp[Raw].load, icmp_load)
283
284
285 class TestIPv4FibCrud(VppTestCase):
286     """ FIB - add/update/delete - ip4 routes
287
288     Test scenario:
289         - add 1k,
290         - del 100,
291         - add new 1k,
292         - del 1.5k
293
294     ..note:: Python API is too slow to add many routes, needs replacement.
295     """
296
297     def config_fib_many_to_one(self, start_dest_addr, next_hop_addr, count):
298         """
299
300         :param start_dest_addr:
301         :param next_hop_addr:
302         :param count:
303         :return list: added ips with 32 prefix
304         """
305         added_ips = []
306         dest_addr = int(binascii.hexlify(socket.inet_pton(socket.AF_INET,
307                                          start_dest_addr)), 16)
308         dest_addr_len = 32
309         n_next_hop_addr = socket.inet_pton(socket.AF_INET, next_hop_addr)
310         for _ in range(count):
311             n_dest_addr = '{:08x}'.format(dest_addr).decode('hex')
312             self.vapi.ip_add_del_route(n_dest_addr, dest_addr_len,
313                                        n_next_hop_addr)
314             added_ips.append(socket.inet_ntoa(n_dest_addr))
315             dest_addr += 1
316         return added_ips
317
318     def unconfig_fib_many_to_one(self, start_dest_addr, next_hop_addr, count):
319
320         removed_ips = []
321         dest_addr = int(binascii.hexlify(socket.inet_pton(socket.AF_INET,
322                                          start_dest_addr)), 16)
323         dest_addr_len = 32
324         n_next_hop_addr = socket.inet_pton(socket.AF_INET, next_hop_addr)
325         for _ in range(count):
326             n_dest_addr = '{:08x}'.format(dest_addr).decode('hex')
327             self.vapi.ip_add_del_route(n_dest_addr, dest_addr_len,
328                                        n_next_hop_addr, is_add=0)
329             removed_ips.append(socket.inet_ntoa(n_dest_addr))
330             dest_addr += 1
331         return removed_ips
332
333     def create_stream(self, src_if, dst_if, dst_ips, count):
334         pkts = []
335
336         for _ in range(count):
337             dst_addr = random.choice(dst_ips)
338             info = self.create_packet_info(src_if, dst_if)
339             payload = self.info_to_payload(info)
340             p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
341                  IP(src=src_if.remote_ip4, dst=dst_addr) /
342                  UDP(sport=1234, dport=1234) /
343                  Raw(payload))
344             info.data = p.copy()
345             self.extend_packet(p, random.choice(self.pg_if_packet_sizes))
346             pkts.append(p)
347
348         return pkts
349
350     def _find_ip_match(self, find_in, pkt):
351         for p in find_in:
352             if self.payload_to_info(str(p[Raw])) == \
353                     self.payload_to_info(str(pkt[Raw])):
354                 if p[IP].src != pkt[IP].src:
355                     break
356                 if p[IP].dst != pkt[IP].dst:
357                     break
358                 if p[UDP].sport != pkt[UDP].sport:
359                     break
360                 if p[UDP].dport != pkt[UDP].dport:
361                     break
362                 return p
363         return None
364
365     @staticmethod
366     def _match_route_detail(route_detail, ip, address_length=32, table_id=0):
367         if route_detail.address == socket.inet_pton(socket.AF_INET, ip):
368             if route_detail.table_id != table_id:
369                 return False
370             elif route_detail.address_length != address_length:
371                 return False
372             else:
373                 return True
374         else:
375             return False
376
377     def verify_capture(self, dst_interface, received_pkts, expected_pkts):
378         self.assertEqual(len(received_pkts), len(expected_pkts))
379         to_verify = list(expected_pkts)
380         for p in received_pkts:
381             self.assertEqual(p.src, dst_interface.local_mac)
382             self.assertEqual(p.dst, dst_interface.remote_mac)
383             x = self._find_ip_match(to_verify, p)
384             to_verify.remove(x)
385         self.assertListEqual(to_verify, [])
386
387     def verify_route_dump(self, fib_dump, ips):
388
389         def _ip_in_route_dump(ip, fib_dump):
390             return next((route for route in fib_dump
391                          if self._match_route_detail(route, ip)),
392                         False)
393
394         for ip in ips:
395             self.assertTrue(_ip_in_route_dump(ip, fib_dump),
396                             'IP {} is not in fib dump.'.format(ip))
397
398     def verify_not_in_route_dump(self, fib_dump, ips):
399
400         def _ip_in_route_dump(ip, fib_dump):
401             return next((route for route in fib_dump
402                          if self._match_route_detail(route, ip)),
403                         False)
404
405         for ip in ips:
406             self.assertFalse(_ip_in_route_dump(ip, fib_dump),
407                              'IP {} is in fib dump.'.format(ip))
408
409     @classmethod
410     def setUpClass(cls):
411         """
412         #. Create and initialize 3 pg interfaces.
413         #. initialize class attributes configured_routes and deleted_routes
414            to store information between tests.
415         """
416         super(TestIPv4FibCrud, cls).setUpClass()
417
418         try:
419             # create 3 pg interfaces
420             cls.create_pg_interfaces(range(3))
421
422             cls.interfaces = list(cls.pg_interfaces)
423
424             # setup all interfaces
425             for i in cls.interfaces:
426                 i.admin_up()
427                 i.config_ip4()
428                 i.resolve_arp()
429
430             cls.configured_routes = []
431             cls.deleted_routes = []
432             cls.pg_if_packet_sizes = [64, 512, 1518, 9018]
433
434         except Exception:
435             super(TestIPv4FibCrud, cls).tearDownClass()
436             raise
437
438     def setUp(self):
439         super(TestIPv4FibCrud, self).setUp()
440         self.reset_packet_infos()
441
442     def test_1_add_routes(self):
443         """ Add 1k routes
444
445         - add 100 routes check with traffic script.
446         """
447         # config 1M FIB entries
448         self.configured_routes.extend(self.config_fib_many_to_one(
449             "10.0.0.0", self.pg0.remote_ip4, 100))
450
451         fib_dump = self.vapi.ip_fib_dump()
452         self.verify_route_dump(fib_dump, self.configured_routes)
453
454         self.stream_1 = self.create_stream(
455             self.pg1, self.pg0, self.configured_routes, 100)
456         self.stream_2 = self.create_stream(
457             self.pg2, self.pg0, self.configured_routes, 100)
458         self.pg1.add_stream(self.stream_1)
459         self.pg2.add_stream(self.stream_2)
460
461         self.pg_enable_capture(self.pg_interfaces)
462         self.pg_start()
463
464         pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
465         self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
466
467     def test_2_del_routes(self):
468         """ Delete 100 routes
469
470         - delete 10 routes check with traffic script.
471         """
472         self.deleted_routes.extend(self.unconfig_fib_many_to_one(
473             "10.0.0.10", self.pg0.remote_ip4, 10))
474         for x in self.deleted_routes:
475             self.configured_routes.remove(x)
476
477         fib_dump = self.vapi.ip_fib_dump()
478         self.verify_route_dump(fib_dump, self.configured_routes)
479
480         self.stream_1 = self.create_stream(
481             self.pg1, self.pg0, self.configured_routes, 100)
482         self.stream_2 = self.create_stream(
483             self.pg2, self.pg0, self.configured_routes, 100)
484         self.stream_3 = self.create_stream(
485             self.pg1, self.pg0, self.deleted_routes, 100)
486         self.stream_4 = self.create_stream(
487             self.pg2, self.pg0, self.deleted_routes, 100)
488         self.pg1.add_stream(self.stream_1 + self.stream_3)
489         self.pg2.add_stream(self.stream_2 + self.stream_4)
490         self.pg_enable_capture(self.pg_interfaces)
491         self.pg_start()
492
493         pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
494         self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
495
496     def test_3_add_new_routes(self):
497         """ Add 1k routes
498
499         - re-add 5 routes check with traffic script.
500         - add 100 routes check with traffic script.
501         """
502         tmp = self.config_fib_many_to_one(
503             "10.0.0.10", self.pg0.remote_ip4, 5)
504         self.configured_routes.extend(tmp)
505         for x in tmp:
506             self.deleted_routes.remove(x)
507
508         self.configured_routes.extend(self.config_fib_many_to_one(
509             "10.0.1.0", self.pg0.remote_ip4, 100))
510
511         fib_dump = self.vapi.ip_fib_dump()
512         self.verify_route_dump(fib_dump, self.configured_routes)
513
514         self.stream_1 = self.create_stream(
515             self.pg1, self.pg0, self.configured_routes, 300)
516         self.stream_2 = self.create_stream(
517             self.pg2, self.pg0, self.configured_routes, 300)
518         self.stream_3 = self.create_stream(
519             self.pg1, self.pg0, self.deleted_routes, 100)
520         self.stream_4 = self.create_stream(
521             self.pg2, self.pg0, self.deleted_routes, 100)
522
523         self.pg1.add_stream(self.stream_1 + self.stream_3)
524         self.pg2.add_stream(self.stream_2 + self.stream_4)
525         self.pg_enable_capture(self.pg_interfaces)
526         self.pg_start()
527
528         pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
529         self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
530
531     def test_4_del_routes(self):
532         """ Delete 1.5k routes
533
534         - delete 5 routes check with traffic script.
535         - add 100 routes check with traffic script.
536         """
537         self.deleted_routes.extend(self.unconfig_fib_many_to_one(
538             "10.0.0.0", self.pg0.remote_ip4, 15))
539         self.deleted_routes.extend(self.unconfig_fib_many_to_one(
540             "10.0.0.20", self.pg0.remote_ip4, 85))
541         self.deleted_routes.extend(self.unconfig_fib_many_to_one(
542             "10.0.1.0", self.pg0.remote_ip4, 100))
543         fib_dump = self.vapi.ip_fib_dump()
544         self.verify_not_in_route_dump(fib_dump, self.deleted_routes)
545
546
547 class TestIPNull(VppTestCase):
548     """ IPv4 routes via NULL """
549
550     def setUp(self):
551         super(TestIPNull, self).setUp()
552
553         # create 2 pg interfaces
554         self.create_pg_interfaces(range(2))
555
556         for i in self.pg_interfaces:
557             i.admin_up()
558             i.config_ip4()
559             i.resolve_arp()
560
561     def tearDown(self):
562         super(TestIPNull, self).tearDown()
563         for i in self.pg_interfaces:
564             i.unconfig_ip4()
565             i.admin_down()
566
567     def test_ip_null(self):
568         """ IP NULL route """
569
570         #
571         # A route via IP NULL that will reply with ICMP unreachables
572         #
573         ip_unreach = VppIpRoute(self, "10.0.0.1", 32, [], is_unreach=1)
574         ip_unreach.add_vpp_config()
575
576         p_unreach = (Ether(src=self.pg0.remote_mac,
577                            dst=self.pg0.local_mac) /
578                      IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
579                      UDP(sport=1234, dport=1234) /
580                      Raw('\xa5' * 100))
581
582         self.pg0.add_stream(p_unreach)
583         self.pg_enable_capture(self.pg_interfaces)
584         self.pg_start()
585
586         rx = self.pg0.get_capture(1)
587         rx = rx[0]
588         icmp = rx[ICMP]
589
590         self.assertEqual(icmptypes[icmp.type], "dest-unreach")
591         self.assertEqual(icmpcodes[icmp.type][icmp.code], "host-unreachable")
592         self.assertEqual(icmp.src, self.pg0.remote_ip4)
593         self.assertEqual(icmp.dst, "10.0.0.1")
594
595         #
596         # ICMP replies are rate limited. so sit and spin.
597         #
598         self.sleep(1)
599
600         #
601         # A route via IP NULL that will reply with ICMP prohibited
602         #
603         ip_prohibit = VppIpRoute(self, "10.0.0.2", 32, [], is_prohibit=1)
604         ip_prohibit.add_vpp_config()
605
606         p_prohibit = (Ether(src=self.pg0.remote_mac,
607                             dst=self.pg0.local_mac) /
608                       IP(src=self.pg0.remote_ip4, dst="10.0.0.2") /
609                       UDP(sport=1234, dport=1234) /
610                       Raw('\xa5' * 100))
611
612         self.pg0.add_stream(p_prohibit)
613         self.pg_enable_capture(self.pg_interfaces)
614         self.pg_start()
615
616         rx = self.pg0.get_capture(1)
617
618         rx = rx[0]
619         icmp = rx[ICMP]
620
621         self.assertEqual(icmptypes[icmp.type], "dest-unreach")
622         self.assertEqual(icmpcodes[icmp.type][icmp.code], "host-prohibited")
623         self.assertEqual(icmp.src, self.pg0.remote_ip4)
624         self.assertEqual(icmp.dst, "10.0.0.2")
625
626     def test_ip_drop(self):
627         """ IP Drop Routes """
628
629         p = (Ether(src=self.pg0.remote_mac,
630                    dst=self.pg0.local_mac) /
631              IP(src=self.pg0.remote_ip4, dst="1.1.1.1") /
632              UDP(sport=1234, dport=1234) /
633              Raw('\xa5' * 100))
634
635         r1 = VppIpRoute(self, "1.1.1.0", 24,
636                         [VppRoutePath(self.pg1.remote_ip4,
637                                       self.pg1.sw_if_index)])
638         r1.add_vpp_config()
639
640         rx = self.send_and_expect(self.pg0, p * 65, self.pg1)
641
642         #
643         # insert a more specific as a drop
644         #
645         r2 = VppIpRoute(self, "1.1.1.1", 32, [], is_drop=1)
646         r2.add_vpp_config()
647
648         self.send_and_assert_no_replies(self.pg0, p * 65, "Drop Route")
649         r2.remove_vpp_config()
650         rx = self.send_and_expect(self.pg0, p * 65, self.pg1)
651
652
653 class TestIPDisabled(VppTestCase):
654     """ IPv4 disabled """
655
656     def setUp(self):
657         super(TestIPDisabled, self).setUp()
658
659         # create 2 pg interfaces
660         self.create_pg_interfaces(range(2))
661
662         # PG0 is IP enalbed
663         self.pg0.admin_up()
664         self.pg0.config_ip4()
665         self.pg0.resolve_arp()
666
667         # PG 1 is not IP enabled
668         self.pg1.admin_up()
669
670     def tearDown(self):
671         super(TestIPDisabled, self).tearDown()
672         for i in self.pg_interfaces:
673             i.unconfig_ip4()
674             i.admin_down()
675
676     def test_ip_disabled(self):
677         """ IP Disabled """
678
679         #
680         # An (S,G).
681         # one accepting interface, pg0, 2 forwarding interfaces
682         #
683         route_232_1_1_1 = VppIpMRoute(
684             self,
685             "0.0.0.0",
686             "232.1.1.1", 32,
687             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
688             [VppMRoutePath(self.pg1.sw_if_index,
689                            MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
690              VppMRoutePath(self.pg0.sw_if_index,
691                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
692         route_232_1_1_1.add_vpp_config()
693
694         pu = (Ether(src=self.pg1.remote_mac,
695                     dst=self.pg1.local_mac) /
696               IP(src="10.10.10.10", dst=self.pg0.remote_ip4) /
697               UDP(sport=1234, dport=1234) /
698               Raw('\xa5' * 100))
699         pm = (Ether(src=self.pg1.remote_mac,
700                     dst=self.pg1.local_mac) /
701               IP(src="10.10.10.10", dst="232.1.1.1") /
702               UDP(sport=1234, dport=1234) /
703               Raw('\xa5' * 100))
704
705         #
706         # PG1 does not forward IP traffic
707         #
708         self.send_and_assert_no_replies(self.pg1, pu, "IP disabled")
709         self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
710
711         #
712         # IP enable PG1
713         #
714         self.pg1.config_ip4()
715
716         #
717         # Now we get packets through
718         #
719         self.pg1.add_stream(pu)
720         self.pg_enable_capture(self.pg_interfaces)
721         self.pg_start()
722         rx = self.pg0.get_capture(1)
723
724         self.pg1.add_stream(pm)
725         self.pg_enable_capture(self.pg_interfaces)
726         self.pg_start()
727         rx = self.pg0.get_capture(1)
728
729         #
730         # Disable PG1
731         #
732         self.pg1.unconfig_ip4()
733
734         #
735         # PG1 does not forward IP traffic
736         #
737         self.send_and_assert_no_replies(self.pg1, pu, "IP disabled")
738         self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
739
740
741 class TestIPSubNets(VppTestCase):
742     """ IPv4 Subnets """
743
744     def setUp(self):
745         super(TestIPSubNets, self).setUp()
746
747         # create a 2 pg interfaces
748         self.create_pg_interfaces(range(2))
749
750         # pg0 we will use to experiemnt
751         self.pg0.admin_up()
752
753         # pg1 is setup normally
754         self.pg1.admin_up()
755         self.pg1.config_ip4()
756         self.pg1.resolve_arp()
757
758     def tearDown(self):
759         super(TestIPSubNets, self).tearDown()
760         for i in self.pg_interfaces:
761             i.admin_down()
762
763     def test_ip_sub_nets(self):
764         """ IP Sub Nets """
765
766         #
767         # Configure a covering route to forward so we know
768         # when we are dropping
769         #
770         cover_route = VppIpRoute(self, "10.0.0.0", 8,
771                                  [VppRoutePath(self.pg1.remote_ip4,
772                                                self.pg1.sw_if_index)])
773         cover_route.add_vpp_config()
774
775         p = (Ether(src=self.pg1.remote_mac,
776                    dst=self.pg1.local_mac) /
777              IP(dst="10.10.10.10", src=self.pg0.local_ip4) /
778              UDP(sport=1234, dport=1234) /
779              Raw('\xa5' * 100))
780
781         self.pg1.add_stream(p)
782         self.pg_enable_capture(self.pg_interfaces)
783         self.pg_start()
784         rx = self.pg1.get_capture(1)
785
786         #
787         # Configure some non-/24 subnets on an IP interface
788         #
789         ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
790
791         self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
792                                                ip_addr_n,
793                                                16)
794
795         pn = (Ether(src=self.pg1.remote_mac,
796                     dst=self.pg1.local_mac) /
797               IP(dst="10.10.0.0", src=self.pg0.local_ip4) /
798               UDP(sport=1234, dport=1234) /
799               Raw('\xa5' * 100))
800         pb = (Ether(src=self.pg1.remote_mac,
801                     dst=self.pg1.local_mac) /
802               IP(dst="10.10.255.255", src=self.pg0.local_ip4) /
803               UDP(sport=1234, dport=1234) /
804               Raw('\xa5' * 100))
805
806         self.send_and_assert_no_replies(self.pg1, pn, "IP Network address")
807         self.send_and_assert_no_replies(self.pg1, pb, "IP Broadcast address")
808
809         # remove the sub-net and we are forwarding via the cover again
810         self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
811                                                ip_addr_n,
812                                                16,
813                                                is_add=0)
814         self.pg1.add_stream(pn)
815         self.pg_enable_capture(self.pg_interfaces)
816         self.pg_start()
817         rx = self.pg1.get_capture(1)
818         self.pg1.add_stream(pb)
819         self.pg_enable_capture(self.pg_interfaces)
820         self.pg_start()
821         rx = self.pg1.get_capture(1)
822
823         #
824         # A /31 is a special case where the 'other-side' is an attached host
825         # packets to that peer generate ARP requests
826         #
827         ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
828
829         self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
830                                                ip_addr_n,
831                                                31)
832
833         pn = (Ether(src=self.pg1.remote_mac,
834                     dst=self.pg1.local_mac) /
835               IP(dst="10.10.10.11", src=self.pg0.local_ip4) /
836               UDP(sport=1234, dport=1234) /
837               Raw('\xa5' * 100))
838
839         self.pg1.add_stream(pn)
840         self.pg_enable_capture(self.pg_interfaces)
841         self.pg_start()
842         rx = self.pg0.get_capture(1)
843         rx[ARP]
844
845         # remove the sub-net and we are forwarding via the cover again
846         self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
847                                                ip_addr_n,
848                                                31,
849                                                is_add=0)
850         self.pg1.add_stream(pn)
851         self.pg_enable_capture(self.pg_interfaces)
852         self.pg_start()
853         rx = self.pg1.get_capture(1)
854
855
856 class TestIPLoadBalance(VppTestCase):
857     """ IPv4 Load-Balancing """
858
859     def setUp(self):
860         super(TestIPLoadBalance, self).setUp()
861
862         self.create_pg_interfaces(range(5))
863         mpls_tbl = VppMplsTable(self, 0)
864         mpls_tbl.add_vpp_config()
865
866         for i in self.pg_interfaces:
867             i.admin_up()
868             i.config_ip4()
869             i.resolve_arp()
870             i.enable_mpls()
871
872     def tearDown(self):
873         for i in self.pg_interfaces:
874             i.disable_mpls()
875             i.unconfig_ip4()
876             i.admin_down()
877         super(TestIPLoadBalance, self).tearDown()
878
879     def send_and_expect_load_balancing(self, input, pkts, outputs):
880         input.add_stream(pkts)
881         self.pg_enable_capture(self.pg_interfaces)
882         self.pg_start()
883         for oo in outputs:
884             rx = oo._get_capture(1)
885             self.assertNotEqual(0, len(rx))
886
887     def send_and_expect_one_itf(self, input, pkts, itf):
888         input.add_stream(pkts)
889         self.pg_enable_capture(self.pg_interfaces)
890         self.pg_start()
891         rx = itf.get_capture(len(pkts))
892
893     def test_ip_load_balance(self):
894         """ IP Load-Balancing """
895
896         #
897         # An array of packets that differ only in the destination port
898         #
899         port_ip_pkts = []
900         port_mpls_pkts = []
901
902         #
903         # An array of packets that differ only in the source address
904         #
905         src_ip_pkts = []
906         src_mpls_pkts = []
907
908         for ii in range(65):
909             port_ip_hdr = (IP(dst="10.0.0.1", src="20.0.0.1") /
910                            UDP(sport=1234, dport=1234 + ii) /
911                            Raw('\xa5' * 100))
912             port_ip_pkts.append((Ether(src=self.pg0.remote_mac,
913                                        dst=self.pg0.local_mac) /
914                                  port_ip_hdr))
915             port_mpls_pkts.append((Ether(src=self.pg0.remote_mac,
916                                          dst=self.pg0.local_mac) /
917                                    MPLS(label=66, ttl=2) /
918                                    port_ip_hdr))
919
920             src_ip_hdr = (IP(dst="10.0.0.1", src="20.0.0.%d" % ii) /
921                           UDP(sport=1234, dport=1234) /
922                           Raw('\xa5' * 100))
923             src_ip_pkts.append((Ether(src=self.pg0.remote_mac,
924                                       dst=self.pg0.local_mac) /
925                                 src_ip_hdr))
926             src_mpls_pkts.append((Ether(src=self.pg0.remote_mac,
927                                         dst=self.pg0.local_mac) /
928                                   MPLS(label=66, ttl=2) /
929                                   src_ip_hdr))
930
931         route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
932                                     [VppRoutePath(self.pg1.remote_ip4,
933                                                   self.pg1.sw_if_index),
934                                      VppRoutePath(self.pg2.remote_ip4,
935                                                   self.pg2.sw_if_index)])
936         route_10_0_0_1.add_vpp_config()
937
938         binding = VppMplsIpBind(self, 66, "10.0.0.1", 32)
939         binding.add_vpp_config()
940
941         #
942         # inject the packet on pg0 - expect load-balancing across the 2 paths
943         #  - since the default hash config is to use IP src,dst and port
944         #    src,dst
945         # We are not going to ensure equal amounts of packets across each link,
946         # since the hash algorithm is statistical and therefore this can never
947         # be guaranteed. But wuth 64 different packets we do expect some
948         # balancing. So instead just ensure there is traffic on each link.
949         #
950         self.send_and_expect_load_balancing(self.pg0, port_ip_pkts,
951                                             [self.pg1, self.pg2])
952         self.send_and_expect_load_balancing(self.pg0, src_ip_pkts,
953                                             [self.pg1, self.pg2])
954         self.send_and_expect_load_balancing(self.pg0, port_mpls_pkts,
955                                             [self.pg1, self.pg2])
956         self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts,
957                                             [self.pg1, self.pg2])
958
959         #
960         # change the flow hash config so it's only IP src,dst
961         #  - now only the stream with differing source address will
962         #    load-balance
963         #
964         self.vapi.set_ip_flow_hash(0, src=1, dst=1, sport=0, dport=0)
965
966         self.send_and_expect_load_balancing(self.pg0, src_ip_pkts,
967                                             [self.pg1, self.pg2])
968         self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts,
969                                             [self.pg1, self.pg2])
970
971         self.send_and_expect_one_itf(self.pg0, port_ip_pkts, self.pg2)
972
973         #
974         # change the flow hash config back to defaults
975         #
976         self.vapi.set_ip_flow_hash(0, src=1, dst=1, sport=1, dport=1)
977
978         #
979         # Recursive prefixes
980         #  - testing that 2 stages of load-balancing occurs and there is no
981         #    polarisation (i.e. only 2 of 4 paths are used)
982         #
983         port_pkts = []
984         src_pkts = []
985
986         for ii in range(257):
987             port_pkts.append((Ether(src=self.pg0.remote_mac,
988                                     dst=self.pg0.local_mac) /
989                               IP(dst="1.1.1.1", src="20.0.0.1") /
990                               UDP(sport=1234, dport=1234 + ii) /
991                               Raw('\xa5' * 100)))
992             src_pkts.append((Ether(src=self.pg0.remote_mac,
993                                    dst=self.pg0.local_mac) /
994                              IP(dst="1.1.1.1", src="20.0.0.%d" % ii) /
995                              UDP(sport=1234, dport=1234) /
996                              Raw('\xa5' * 100)))
997
998         route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
999                                     [VppRoutePath(self.pg3.remote_ip4,
1000                                                   self.pg3.sw_if_index),
1001                                      VppRoutePath(self.pg4.remote_ip4,
1002                                                   self.pg4.sw_if_index)])
1003         route_10_0_0_2.add_vpp_config()
1004
1005         route_1_1_1_1 = VppIpRoute(self, "1.1.1.1", 32,
1006                                    [VppRoutePath("10.0.0.2", 0xffffffff),
1007                                     VppRoutePath("10.0.0.1", 0xffffffff)])
1008         route_1_1_1_1.add_vpp_config()
1009
1010         #
1011         # inject the packet on pg0 - expect load-balancing across all 4 paths
1012         #
1013         self.vapi.cli("clear trace")
1014         self.send_and_expect_load_balancing(self.pg0, port_pkts,
1015                                             [self.pg1, self.pg2,
1016                                              self.pg3, self.pg4])
1017         self.send_and_expect_load_balancing(self.pg0, src_pkts,
1018                                             [self.pg1, self.pg2,
1019                                              self.pg3, self.pg4])
1020
1021         #
1022         # Recursive prefixes
1023         #  - testing that 2 stages of load-balancing, no choices
1024         #
1025         port_pkts = []
1026
1027         for ii in range(257):
1028             port_pkts.append((Ether(src=self.pg0.remote_mac,
1029                                     dst=self.pg0.local_mac) /
1030                               IP(dst="1.1.1.2", src="20.0.0.2") /
1031                               UDP(sport=1234, dport=1234 + ii) /
1032                               Raw('\xa5' * 100)))
1033
1034         route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1035                                     [VppRoutePath(self.pg3.remote_ip4,
1036                                                   self.pg3.sw_if_index)])
1037         route_10_0_0_3.add_vpp_config()
1038
1039         route_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32,
1040                                    [VppRoutePath("10.0.0.3", 0xffffffff)])
1041         route_1_1_1_2.add_vpp_config()
1042
1043         #
1044         # inject the packet on pg0 - expect load-balancing across all 4 paths
1045         #
1046         self.vapi.cli("clear trace")
1047         self.send_and_expect_one_itf(self.pg0, port_pkts, self.pg3)
1048
1049
1050 class TestIPVlan0(VppTestCase):
1051     """ IPv4 VLAN-0 """
1052
1053     def setUp(self):
1054         super(TestIPVlan0, self).setUp()
1055
1056         self.create_pg_interfaces(range(2))
1057         mpls_tbl = VppMplsTable(self, 0)
1058         mpls_tbl.add_vpp_config()
1059
1060         for i in self.pg_interfaces:
1061             i.admin_up()
1062             i.config_ip4()
1063             i.resolve_arp()
1064             i.enable_mpls()
1065
1066     def tearDown(self):
1067         for i in self.pg_interfaces:
1068             i.disable_mpls()
1069             i.unconfig_ip4()
1070             i.admin_down()
1071         super(TestIPVlan0, self).tearDown()
1072
1073     def test_ip_vlan_0(self):
1074         """ IP VLAN-0 """
1075
1076         pkts = (Ether(src=self.pg0.remote_mac,
1077                       dst=self.pg0.local_mac) /
1078                 Dot1Q(vlan=0) /
1079                 IP(dst=self.pg1.remote_ip4,
1080                    src=self.pg0.remote_ip4) /
1081                 UDP(sport=1234, dport=1234) /
1082                 Raw('\xa5' * 100)) * 65
1083
1084         #
1085         # Expect that packets sent on VLAN-0 are forwarded on the
1086         # main interface.
1087         #
1088         self.send_and_expect(self.pg0, pkts, self.pg1)
1089
1090
1091 class TestIPPunt(VppTestCase):
1092     """ IPv4 Punt Police/Redirect """
1093
1094     def setUp(self):
1095         super(TestIPPunt, self).setUp()
1096
1097         self.create_pg_interfaces(range(2))
1098
1099         for i in self.pg_interfaces:
1100             i.admin_up()
1101             i.config_ip4()
1102             i.resolve_arp()
1103
1104     def tearDown(self):
1105         super(TestIPPunt, self).tearDown()
1106         for i in self.pg_interfaces:
1107             i.unconfig_ip4()
1108             i.admin_down()
1109
1110     def test_ip_punt(self):
1111         """ IP punt police and redirect """
1112
1113         p = (Ether(src=self.pg0.remote_mac,
1114                    dst=self.pg0.local_mac) /
1115              IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
1116              TCP(sport=1234, dport=1234) /
1117              Raw('\xa5' * 100))
1118
1119         pkts = p * 1025
1120
1121         #
1122         # Configure a punt redirect via pg1.
1123         #
1124         nh_addr = socket.inet_pton(socket.AF_INET,
1125                                    self.pg1.remote_ip4)
1126         self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
1127                                    self.pg1.sw_if_index,
1128                                    nh_addr)
1129
1130         self.send_and_expect(self.pg0, pkts, self.pg1)
1131
1132         #
1133         # add a policer
1134         #
1135         policer = self.vapi.policer_add_del("ip4-punt", 400, 0, 10, 0,
1136                                             rate_type=1)
1137         self.vapi.ip_punt_police(policer.policer_index)
1138
1139         self.vapi.cli("clear trace")
1140         self.pg0.add_stream(pkts)
1141         self.pg_enable_capture(self.pg_interfaces)
1142         self.pg_start()
1143
1144         #
1145         # the number of packet recieved should be greater than 0,
1146         # but not equal to the number sent, since some were policed
1147         #
1148         rx = self.pg1._get_capture(1)
1149         self.assertGreater(len(rx), 0)
1150         self.assertLess(len(rx), len(pkts))
1151
1152         #
1153         # remove the poilcer. back to full rx
1154         #
1155         self.vapi.ip_punt_police(policer.policer_index, is_add=0)
1156         self.vapi.policer_add_del("ip4-punt", 400, 0, 10, 0,
1157                                   rate_type=1, is_add=0)
1158         self.send_and_expect(self.pg0, pkts, self.pg1)
1159
1160         #
1161         # remove the redirect. expect full drop.
1162         #
1163         self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
1164                                    self.pg1.sw_if_index,
1165                                    nh_addr,
1166                                    is_add=0)
1167         self.send_and_assert_no_replies(self.pg0, pkts,
1168                                         "IP no punt config")
1169
1170         #
1171         # Add a redirect that is not input port selective
1172         #
1173         self.vapi.ip_punt_redirect(0xffffffff,
1174                                    self.pg1.sw_if_index,
1175                                    nh_addr)
1176         self.send_and_expect(self.pg0, pkts, self.pg1)
1177
1178         self.vapi.ip_punt_redirect(0xffffffff,
1179                                    self.pg1.sw_if_index,
1180                                    nh_addr,
1181                                    is_add=0)
1182
1183
1184 class TestIPDeag(VppTestCase):
1185     """ IPv4 Deaggregate Routes """
1186
1187     def setUp(self):
1188         super(TestIPDeag, self).setUp()
1189
1190         self.create_pg_interfaces(range(3))
1191
1192         for i in self.pg_interfaces:
1193             i.admin_up()
1194             i.config_ip4()
1195             i.resolve_arp()
1196
1197     def tearDown(self):
1198         super(TestIPDeag, self).tearDown()
1199         for i in self.pg_interfaces:
1200             i.unconfig_ip4()
1201             i.admin_down()
1202
1203     def test_ip_deag(self):
1204         """ IP Deag Routes """
1205
1206         #
1207         # Create a table to be used for:
1208         #  1 - another destination address lookup
1209         #  2 - a source address lookup
1210         #
1211         table_dst = VppIpTable(self, 1)
1212         table_src = VppIpTable(self, 2)
1213         table_dst.add_vpp_config()
1214         table_src.add_vpp_config()
1215
1216         #
1217         # Add a route in the default table to point to a deag/
1218         # second lookup in each of these tables
1219         #
1220         route_to_dst = VppIpRoute(self, "1.1.1.1", 32,
1221                                   [VppRoutePath("0.0.0.0",
1222                                                 0xffffffff,
1223                                                 nh_table_id=1)])
1224         route_to_src = VppIpRoute(self, "1.1.1.2", 32,
1225                                   [VppRoutePath("0.0.0.0",
1226                                                 0xffffffff,
1227                                                 nh_table_id=2,
1228                                                 is_source_lookup=1)])
1229         route_to_dst.add_vpp_config()
1230         route_to_src.add_vpp_config()
1231
1232         #
1233         # packets to these destination are dropped, since they'll
1234         # hit the respective default routes in the second table
1235         #
1236         p_dst = (Ether(src=self.pg0.remote_mac,
1237                        dst=self.pg0.local_mac) /
1238                  IP(src="5.5.5.5", dst="1.1.1.1") /
1239                  TCP(sport=1234, dport=1234) /
1240                  Raw('\xa5' * 100))
1241         p_src = (Ether(src=self.pg0.remote_mac,
1242                        dst=self.pg0.local_mac) /
1243                  IP(src="2.2.2.2", dst="1.1.1.2") /
1244                  TCP(sport=1234, dport=1234) /
1245                  Raw('\xa5' * 100))
1246         pkts_dst = p_dst * 257
1247         pkts_src = p_src * 257
1248
1249         self.send_and_assert_no_replies(self.pg0, pkts_dst,
1250                                         "IP in dst table")
1251         self.send_and_assert_no_replies(self.pg0, pkts_src,
1252                                         "IP in src table")
1253
1254         #
1255         # add a route in the dst table to forward via pg1
1256         #
1257         route_in_dst = VppIpRoute(self, "1.1.1.1", 32,
1258                                   [VppRoutePath(self.pg1.remote_ip4,
1259                                                 self.pg1.sw_if_index)],
1260                                   table_id=1)
1261         route_in_dst.add_vpp_config()
1262         self.send_and_expect(self.pg0, pkts_dst, self.pg1)
1263
1264         #
1265         # add a route in the src table to forward via pg2
1266         #
1267         route_in_src = VppIpRoute(self, "2.2.2.2", 32,
1268                                   [VppRoutePath(self.pg2.remote_ip4,
1269                                                 self.pg2.sw_if_index)],
1270                                   table_id=2)
1271         route_in_src.add_vpp_config()
1272         self.send_and_expect(self.pg0, pkts_src, self.pg2)
1273
1274         #
1275         # loop in the lookup DP
1276         #
1277         route_loop = VppIpRoute(self, "2.2.2.3", 32,
1278                                 [VppRoutePath("0.0.0.0",
1279                                               0xffffffff,
1280                                               nh_table_id=0)])
1281         route_loop.add_vpp_config()
1282
1283         p_l = (Ether(src=self.pg0.remote_mac,
1284                      dst=self.pg0.local_mac) /
1285                IP(src="2.2.2.4", dst="2.2.2.3") /
1286                TCP(sport=1234, dport=1234) /
1287                Raw('\xa5' * 100))
1288
1289         self.send_and_assert_no_replies(self.pg0, p_l * 257,
1290                                         "IP lookup loop")
1291
1292
1293 class TestIPInput(VppTestCase):
1294     """ IPv4 Input Exceptions """
1295
1296     def setUp(self):
1297         super(TestIPInput, self).setUp()
1298
1299         self.create_pg_interfaces(range(2))
1300
1301         for i in self.pg_interfaces:
1302             i.admin_up()
1303             i.config_ip4()
1304             i.resolve_arp()
1305
1306     def tearDown(self):
1307         super(TestIPInput, self).tearDown()
1308         for i in self.pg_interfaces:
1309             i.unconfig_ip4()
1310             i.admin_down()
1311
1312     def test_ip_input(self):
1313         """ IP Input Exceptions """
1314
1315         # i can't find a way in scapy to construct an IP packet
1316         # with a length less than the IP header length
1317
1318         #
1319         # Packet too short - this is forwarded
1320         #
1321         p_short = (Ether(src=self.pg0.remote_mac,
1322                          dst=self.pg0.local_mac) /
1323                    IP(src=self.pg0.remote_ip4,
1324                       dst=self.pg1.remote_ip4,
1325                       len=40) /
1326                    UDP(sport=1234, dport=1234) /
1327                    Raw('\xa5' * 100))
1328
1329         rx = self.send_and_expect(self.pg0, p_short * 65, self.pg1)
1330
1331         #
1332         # Packet too long - this is dropped
1333         #
1334         p_long = (Ether(src=self.pg0.remote_mac,
1335                         dst=self.pg0.local_mac) /
1336                   IP(src=self.pg0.remote_ip4,
1337                      dst=self.pg1.remote_ip4,
1338                      len=400) /
1339                   UDP(sport=1234, dport=1234) /
1340                   Raw('\xa5' * 100))
1341
1342         rx = self.send_and_assert_no_replies(self.pg0, p_long * 65,
1343                                              "too long")
1344
1345         #
1346         # bad chksum - this is dropped
1347         #
1348         p_chksum = (Ether(src=self.pg0.remote_mac,
1349                           dst=self.pg0.local_mac) /
1350                     IP(src=self.pg0.remote_ip4,
1351                        dst=self.pg1.remote_ip4,
1352                        chksum=400) /
1353                     UDP(sport=1234, dport=1234) /
1354                     Raw('\xa5' * 100))
1355
1356         rx = self.send_and_assert_no_replies(self.pg0, p_chksum * 65,
1357                                              "bad checksum")
1358
1359         #
1360         # bad version - this is dropped
1361         #
1362         p_ver = (Ether(src=self.pg0.remote_mac,
1363                        dst=self.pg0.local_mac) /
1364                  IP(src=self.pg0.remote_ip4,
1365                     dst=self.pg1.remote_ip4,
1366                     version=3) /
1367                  UDP(sport=1234, dport=1234) /
1368                  Raw('\xa5' * 100))
1369
1370         rx = self.send_and_assert_no_replies(self.pg0, p_ver * 65,
1371                                              "funky version")
1372
1373         #
1374         # fragment offset 1 - this is dropped
1375         #
1376         p_frag = (Ether(src=self.pg0.remote_mac,
1377                         dst=self.pg0.local_mac) /
1378                   IP(src=self.pg0.remote_ip4,
1379                      dst=self.pg1.remote_ip4,
1380                      frag=1) /
1381                   UDP(sport=1234, dport=1234) /
1382                   Raw('\xa5' * 100))
1383
1384         rx = self.send_and_assert_no_replies(self.pg0, p_frag * 65,
1385                                              "frag offset")
1386
1387         #
1388         # TTL expired packet
1389         #
1390         p_ttl = (Ether(src=self.pg0.remote_mac,
1391                        dst=self.pg0.local_mac) /
1392                  IP(src=self.pg0.remote_ip4,
1393                     dst=self.pg1.remote_ip4,
1394                     ttl=1) /
1395                  UDP(sport=1234, dport=1234) /
1396                  Raw('\xa5' * 100))
1397
1398         rx = self.send_and_expect(self.pg0, p_ttl * 65, self.pg0)
1399
1400         rx = rx[0]
1401         icmp = rx[ICMP]
1402
1403         self.assertEqual(icmptypes[icmp.type], "time-exceeded")
1404         self.assertEqual(icmpcodes[icmp.type][icmp.code],
1405                          "ttl-zero-during-transit")
1406         self.assertEqual(icmp.src, self.pg0.remote_ip4)
1407         self.assertEqual(icmp.dst, self.pg1.remote_ip4)
1408
1409         #
1410         # MTU exceeded
1411         #
1412         p_mtu = (Ether(src=self.pg0.remote_mac,
1413                        dst=self.pg0.local_mac) /
1414                  IP(src=self.pg0.remote_ip4,
1415                     dst=self.pg1.remote_ip4,
1416                     ttl=10, flags='DF') /
1417                  UDP(sport=1234, dport=1234) /
1418                  Raw('\xa5' * 2000))
1419
1420         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1500, 0, 0, 0])
1421
1422         rx = self.send_and_expect(self.pg0, p_mtu * 65, self.pg0)
1423         rx = rx[0]
1424         icmp = rx[ICMP]
1425
1426         self.assertEqual(icmptypes[icmp.type], "dest-unreach")
1427         self.assertEqual(icmpcodes[icmp.type][icmp.code],
1428                          "fragmentation-needed")
1429         self.assertEqual(icmp.src, self.pg0.remote_ip4)
1430         self.assertEqual(icmp.dst, self.pg1.remote_ip4)
1431
1432         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2500, 0, 0, 0])
1433         rx = self.send_and_expect(self.pg0, p_mtu * 65, self.pg1)
1434
1435         # Reset MTU for subsequent tests
1436         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [9000, 0, 0, 0])
1437
1438
1439 class TestIPDirectedBroadcast(VppTestCase):
1440     """ IPv4 Directed Broadcast """
1441
1442     def setUp(self):
1443         super(TestIPDirectedBroadcast, self).setUp()
1444
1445         self.create_pg_interfaces(range(2))
1446
1447         for i in self.pg_interfaces:
1448             i.admin_up()
1449
1450     def tearDown(self):
1451         super(TestIPDirectedBroadcast, self).tearDown()
1452         for i in self.pg_interfaces:
1453             i.admin_down()
1454
1455     def test_ip_input(self):
1456         """ IP Directed Broadcast """
1457
1458         #
1459         # set the directed broadcast on pg0 first, then config IP4 addresses
1460         # for pg1 directed broadcast is always disabled
1461         self.vapi.sw_interface_set_ip_directed_broadcast(
1462             self.pg0.sw_if_index, 1)
1463
1464         p0 = (Ether(src=self.pg1.remote_mac,
1465                     dst=self.pg1.local_mac) /
1466               IP(src="1.1.1.1",
1467                  dst=self.pg0._local_ip4_bcast) /
1468               UDP(sport=1234, dport=1234) /
1469               Raw('\xa5' * 2000))
1470         p1 = (Ether(src=self.pg0.remote_mac,
1471                     dst=self.pg0.local_mac) /
1472               IP(src="1.1.1.1",
1473                  dst=self.pg1._local_ip4_bcast) /
1474               UDP(sport=1234, dport=1234) /
1475               Raw('\xa5' * 2000))
1476
1477         self.pg0.config_ip4()
1478         self.pg0.resolve_arp()
1479         self.pg1.config_ip4()
1480         self.pg1.resolve_arp()
1481
1482         #
1483         # test packet is L2 broadcast
1484         #
1485         rx = self.send_and_expect(self.pg1, p0 * 65, self.pg0)
1486         self.assertTrue(rx[0][Ether].dst, "ff:ff:ff:ff:ff:ff")
1487
1488         self.send_and_assert_no_replies(self.pg0, p1 * 65,
1489                                         "directed broadcast disabled")
1490
1491         #
1492         # toggle directed broadcast on pg0
1493         #
1494         self.vapi.sw_interface_set_ip_directed_broadcast(
1495             self.pg0.sw_if_index, 0)
1496         self.send_and_assert_no_replies(self.pg1, p0 * 65,
1497                                         "directed broadcast disabled")
1498
1499         self.vapi.sw_interface_set_ip_directed_broadcast(
1500             self.pg0.sw_if_index, 1)
1501         rx = self.send_and_expect(self.pg1, p0 * 65, self.pg0)
1502
1503         self.pg0.unconfig_ip4()
1504         self.pg1.unconfig_ip4()
1505
1506
1507 class TestIPLPM(VppTestCase):
1508     """ IPv4 longest Prefix Match """
1509
1510     def setUp(self):
1511         super(TestIPLPM, self).setUp()
1512
1513         self.create_pg_interfaces(range(4))
1514
1515         for i in self.pg_interfaces:
1516             i.admin_up()
1517             i.config_ip4()
1518             i.resolve_arp()
1519
1520     def tearDown(self):
1521         super(TestIPLPM, self).tearDown()
1522         for i in self.pg_interfaces:
1523             i.admin_down()
1524             i.unconfig_ip4()
1525
1526     def test_ip_lpm(self):
1527         """ IP longest Prefix Match """
1528
1529         s_24 = VppIpRoute(self, "10.1.2.0", 24,
1530                           [VppRoutePath(self.pg1.remote_ip4,
1531                                         self.pg1.sw_if_index)])
1532         s_24.add_vpp_config()
1533         s_8 = VppIpRoute(self, "10.0.0.0", 8,
1534                          [VppRoutePath(self.pg2.remote_ip4,
1535                                        self.pg2.sw_if_index)])
1536         s_8.add_vpp_config()
1537
1538         p_8 = (Ether(src=self.pg0.remote_mac,
1539                      dst=self.pg0.local_mac) /
1540                IP(src="1.1.1.1",
1541                   dst="10.1.1.1") /
1542                UDP(sport=1234, dport=1234) /
1543                Raw('\xa5' * 2000))
1544         p_24 = (Ether(src=self.pg0.remote_mac,
1545                       dst=self.pg0.local_mac) /
1546                 IP(src="1.1.1.1",
1547                    dst="10.1.2.1") /
1548                 UDP(sport=1234, dport=1234) /
1549                 Raw('\xa5' * 2000))
1550
1551         self.logger.info(self.vapi.cli("sh ip fib mtrie"))
1552         rx = self.send_and_expect(self.pg0, p_8 * 65, self.pg2)
1553         rx = self.send_and_expect(self.pg0, p_24 * 65, self.pg1)
1554
1555
1556 class TestIPv4Frag(VppTestCase):
1557     """ IPv4 fragmentation """
1558
1559     @classmethod
1560     def setUpClass(cls):
1561         super(TestIPv4Frag, cls).setUpClass()
1562
1563         cls.create_pg_interfaces([0, 1])
1564         cls.src_if = cls.pg0
1565         cls.dst_if = cls.pg1
1566
1567         # setup all interfaces
1568         for i in cls.pg_interfaces:
1569             i.admin_up()
1570             i.config_ip4()
1571             i.resolve_arp()
1572
1573     def test_frag_large_packets(self):
1574         """ Fragmentation of large packets """
1575
1576         p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1577              IP(src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4) /
1578              UDP(sport=1234, dport=5678) / Raw())
1579         self.extend_packet(p, 6000, "abcde")
1580         saved_payload = p[Raw].load
1581
1582         # Force fragmentation by setting MTU of output interface
1583         # lower than packet size
1584         self.vapi.sw_interface_set_mtu(self.dst_if.sw_if_index,
1585                                        [5000, 0, 0, 0])
1586
1587         self.pg_enable_capture()
1588         self.src_if.add_stream(p)
1589         self.pg_start()
1590
1591         # Expecting 3 fragments because size of created fragments currently
1592         # cannot be larger then VPP buffer size (which is 2048)
1593         packets = self.dst_if.get_capture(3)
1594
1595         # Assume VPP sends the fragments in order
1596         payload = ''
1597         for p in packets:
1598             payload_offset = p.frag * 8
1599             if payload_offset > 0:
1600                 payload_offset -= 8  # UDP header is not in payload
1601             self.assert_equal(payload_offset, len(payload))
1602             payload += p[Raw].load
1603         self.assert_equal(payload, saved_payload, "payload")
1604
1605
1606 if __name__ == '__main__':
1607     unittest.main(testRunner=VppTestRunner)