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