blob: 740e2e28510b2c8b3d4e03e6dffb6c46e137993c [file] [log] [blame]
Renato Botelho do Coutoead1e532019-10-31 13:31:07 -05001#!/usr/bin/env python3
Damjan Marionf56b77a2016-10-03 19:44:57 +02002
Paul Vinciguerra582eac52020-04-03 12:18:40 -04003import socket
snaramre5d4b8912019-12-13 23:39:35 +00004from socket import inet_pton, inet_ntop
Paul Vinciguerraa6fe4632018-11-25 11:21:50 -08005import unittest
6
Neale Rannsae809832018-11-23 09:00:27 -08007from parameterized import parameterized
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07008import scapy.compat
Paul Vinciguerraa6fe4632018-11-25 11:21:50 -08009import scapy.layers.inet6 as inet6
10from scapy.contrib.mpls import MPLS
11from scapy.layers.inet6 import IPv6, ICMPv6ND_NS, ICMPv6ND_RS, \
12 ICMPv6ND_RA, ICMPv6NDOptMTU, ICMPv6NDOptSrcLLAddr, ICMPv6NDOptPrefixInfo, \
13 ICMPv6ND_NA, ICMPv6NDOptDstLLAddr, ICMPv6DestUnreach, icmp6types, \
Neale Rannsf267d112020-02-07 09:45:07 +000014 ICMPv6TimeExceeded, ICMPv6EchoRequest, ICMPv6EchoReply, \
15 IPv6ExtHdrHopByHop, ICMPv6MLReport2, ICMPv6MLDMultAddrRec
Paul Vinciguerraa6fe4632018-11-25 11:21:50 -080016from scapy.layers.l2 import Ether, Dot1Q
17from scapy.packet import Raw
Paul Vinciguerraa6fe4632018-11-25 11:21:50 -080018from scapy.utils6 import in6_getnsma, in6_getnsmac, in6_ptop, in6_islladdr, \
19 in6_mactoifaceid
20from six import moves
Klement Sekeraf62ae122016-10-11 11:47:09 +020021
Damjan Marionf56b77a2016-10-03 19:44:57 +020022from framework import VppTestCase, VppTestRunner
Paul Vinciguerrae8fece82019-02-28 15:34:00 -080023from util import ppp, ip6_normalize, mk_ll_addr
Neale Ranns990f6942020-10-20 07:20:17 +000024from vpp_papi import VppEnum
Neale Rannsefd7bc22019-11-11 08:32:34 +000025from vpp_ip import DpoProto
Neale Ranns180279b2017-03-16 15:49:09 -040026from vpp_ip_route import VppIpRoute, VppRoutePath, find_route, VppIpMRoute, \
Neale Ranns990f6942020-10-20 07:20:17 +000027 VppMRoutePath, VppMplsIpBind, \
Neale Ranns9db6ada2019-11-08 12:42:31 +000028 VppMplsRoute, VppMplsTable, VppIpTable, FibPathType, FibPathProto, \
Neale Rannsec40a7d2020-04-23 07:36:12 +000029 VppIpInterfaceAddress, find_route_in_dump, find_mroute_in_dump, \
30 VppIp6LinkLocalAddress
Neale Rannsb3b2de72017-03-08 05:17:22 -080031from vpp_neighbor import find_nbr, VppNeighbor
Paul Vinciguerraa6fe4632018-11-25 11:21:50 -080032from vpp_pg_interface import is_ipv6_misc
33from vpp_sub_interface import VppSubInterface, VppDot1QSubint
Jakub Grajciarcd01fb42020-03-02 13:16:53 +010034from vpp_policer import VppPolicer
Neale Rannsefd7bc22019-11-11 08:32:34 +000035from ipaddress import IPv6Network, IPv6Address
Neale Ranns75152282017-01-09 01:00:45 -080036
Juraj Sloboda4b9669d2018-01-15 10:39:21 +010037AF_INET6 = socket.AF_INET6
38
Paul Vinciguerra1e18eb22018-11-25 16:09:26 -080039try:
40 text_type = unicode
41except NameError:
42 text_type = str
43
Paul Vinciguerra4271c972019-05-14 13:25:49 -040044NUM_PKTS = 67
45
Juraj Sloboda4b9669d2018-01-15 10:39:21 +010046
Neale Ranns3f844d02017-02-18 00:03:54 -080047class TestIPv6ND(VppTestCase):
48 def validate_ra(self, intf, rx, dst_ip=None):
49 if not dst_ip:
50 dst_ip = intf.remote_ip6
51
52 # unicasted packets must come to the unicast mac
53 self.assertEqual(rx[Ether].dst, intf.remote_mac)
54
55 # and from the router's MAC
56 self.assertEqual(rx[Ether].src, intf.local_mac)
57
58 # the rx'd RA should be addressed to the sender's source
59 self.assertTrue(rx.haslayer(ICMPv6ND_RA))
60 self.assertEqual(in6_ptop(rx[IPv6].dst),
61 in6_ptop(dst_ip))
62
63 # and come from the router's link local
64 self.assertTrue(in6_islladdr(rx[IPv6].src))
65 self.assertEqual(in6_ptop(rx[IPv6].src),
66 in6_ptop(mk_ll_addr(intf.local_mac)))
67
68 def validate_na(self, intf, rx, dst_ip=None, tgt_ip=None):
69 if not dst_ip:
70 dst_ip = intf.remote_ip6
71 if not tgt_ip:
72 dst_ip = intf.local_ip6
73
74 # unicasted packets must come to the unicast mac
75 self.assertEqual(rx[Ether].dst, intf.remote_mac)
76
77 # and from the router's MAC
78 self.assertEqual(rx[Ether].src, intf.local_mac)
79
80 # the rx'd NA should be addressed to the sender's source
81 self.assertTrue(rx.haslayer(ICMPv6ND_NA))
82 self.assertEqual(in6_ptop(rx[IPv6].dst),
83 in6_ptop(dst_ip))
84
85 # and come from the target address
Paul Vinciguerra978aa642018-11-24 22:19:12 -080086 self.assertEqual(
87 in6_ptop(rx[IPv6].src), in6_ptop(tgt_ip))
Neale Ranns3f844d02017-02-18 00:03:54 -080088
89 # Dest link-layer options should have the router's MAC
90 dll = rx[ICMPv6NDOptDstLLAddr]
91 self.assertEqual(dll.lladdr, intf.local_mac)
92
Neale Rannsdcd6d622017-05-26 02:59:16 -070093 def validate_ns(self, intf, rx, tgt_ip):
94 nsma = in6_getnsma(inet_pton(AF_INET6, tgt_ip))
95 dst_ip = inet_ntop(AF_INET6, nsma)
96
97 # NS is broadcast
Neale Rannsc7b8f202018-04-25 06:34:31 -070098 self.assertEqual(rx[Ether].dst, in6_getnsmac(nsma))
Neale Rannsdcd6d622017-05-26 02:59:16 -070099
100 # and from the router's MAC
101 self.assertEqual(rx[Ether].src, intf.local_mac)
102
103 # the rx'd NS should be addressed to an mcast address
104 # derived from the target address
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800105 self.assertEqual(
106 in6_ptop(rx[IPv6].dst), in6_ptop(dst_ip))
Neale Rannsdcd6d622017-05-26 02:59:16 -0700107
108 # expect the tgt IP in the NS header
109 ns = rx[ICMPv6ND_NS]
110 self.assertEqual(in6_ptop(ns.tgt), in6_ptop(tgt_ip))
111
112 # packet is from the router's local address
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800113 self.assertEqual(
114 in6_ptop(rx[IPv6].src), intf.local_ip6)
Neale Rannsdcd6d622017-05-26 02:59:16 -0700115
116 # Src link-layer options should have the router's MAC
117 sll = rx[ICMPv6NDOptSrcLLAddr]
118 self.assertEqual(sll.lladdr, intf.local_mac)
119
Neale Ranns3f844d02017-02-18 00:03:54 -0800120 def send_and_expect_ra(self, intf, pkts, remark, dst_ip=None,
121 filter_out_fn=is_ipv6_misc):
122 intf.add_stream(pkts)
Neale Ranns3f844d02017-02-18 00:03:54 -0800123 self.pg_enable_capture(self.pg_interfaces)
124 self.pg_start()
125 rx = intf.get_capture(1, filter_out_fn=filter_out_fn)
126
127 self.assertEqual(len(rx), 1)
128 rx = rx[0]
129 self.validate_ra(intf, rx, dst_ip)
130
Neale Ranns2a3ea492017-04-19 05:24:40 -0700131 def send_and_expect_na(self, intf, pkts, remark, dst_ip=None,
132 tgt_ip=None,
133 filter_out_fn=is_ipv6_misc):
134 intf.add_stream(pkts)
135 self.pg_enable_capture(self.pg_interfaces)
136 self.pg_start()
137 rx = intf.get_capture(1, filter_out_fn=filter_out_fn)
138
139 self.assertEqual(len(rx), 1)
140 rx = rx[0]
141 self.validate_na(intf, rx, dst_ip, tgt_ip)
142
Neale Rannsdcd6d622017-05-26 02:59:16 -0700143 def send_and_expect_ns(self, tx_intf, rx_intf, pkts, tgt_ip,
144 filter_out_fn=is_ipv6_misc):
Neale Rannscbe25aa2019-09-30 10:53:31 +0000145 self.vapi.cli("clear trace")
Neale Rannsdcd6d622017-05-26 02:59:16 -0700146 tx_intf.add_stream(pkts)
147 self.pg_enable_capture(self.pg_interfaces)
148 self.pg_start()
149 rx = rx_intf.get_capture(1, filter_out_fn=filter_out_fn)
150
151 self.assertEqual(len(rx), 1)
152 rx = rx[0]
153 self.validate_ns(rx_intf, rx, tgt_ip)
154
Neale Rannsdcd6d622017-05-26 02:59:16 -0700155 def verify_ip(self, rx, smac, dmac, sip, dip):
156 ether = rx[Ether]
157 self.assertEqual(ether.dst, dmac)
158 self.assertEqual(ether.src, smac)
159
160 ip = rx[IPv6]
161 self.assertEqual(ip.src, sip)
162 self.assertEqual(ip.dst, dip)
163
Neale Ranns3f844d02017-02-18 00:03:54 -0800164
165class TestIPv6(TestIPv6ND):
Damjan Marionf56b77a2016-10-03 19:44:57 +0200166 """ IPv6 Test Case """
167
168 @classmethod
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000169 def force_solo(cls):
170 return True
171
172 @classmethod
Damjan Marionf56b77a2016-10-03 19:44:57 +0200173 def setUpClass(cls):
174 super(TestIPv6, cls).setUpClass()
175
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -0700176 @classmethod
177 def tearDownClass(cls):
178 super(TestIPv6, cls).tearDownClass()
179
Klement Sekeraf62ae122016-10-11 11:47:09 +0200180 def setUp(self):
Matej Klotton86d87c42016-11-11 11:38:55 +0100181 """
182 Perform test setup before test case.
183
184 **Config:**
185 - create 3 pg interfaces
186 - untagged pg0 interface
187 - Dot1Q subinterface on pg1
188 - Dot1AD subinterface on pg2
189 - setup interfaces:
190 - put it into UP state
191 - set IPv6 addresses
192 - resolve neighbor address using NDP
193 - configure 200 fib entries
194
195 :ivar list interfaces: pg interfaces and subinterfaces.
196 :ivar dict flows: IPv4 packet flows in test.
Matej Klotton86d87c42016-11-11 11:38:55 +0100197
198 *TODO:* Create AD sub interface
199 """
Klement Sekeraf62ae122016-10-11 11:47:09 +0200200 super(TestIPv6, self).setUp()
Damjan Marionf56b77a2016-10-03 19:44:57 +0200201
Klement Sekeraf62ae122016-10-11 11:47:09 +0200202 # create 3 pg interfaces
203 self.create_pg_interfaces(range(3))
Damjan Marionf56b77a2016-10-03 19:44:57 +0200204
Klement Sekeraf62ae122016-10-11 11:47:09 +0200205 # create 2 subinterfaces for p1 and pg2
206 self.sub_interfaces = [
207 VppDot1QSubint(self, self.pg1, 100),
Matej Klotton86d87c42016-11-11 11:38:55 +0100208 VppDot1QSubint(self, self.pg2, 200)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200209 # TODO: VppDot1ADSubint(self, self.pg2, 200, 300, 400)
Matej Klotton86d87c42016-11-11 11:38:55 +0100210 ]
Damjan Marionf56b77a2016-10-03 19:44:57 +0200211
Klement Sekeraf62ae122016-10-11 11:47:09 +0200212 # packet flows mapping pg0 -> pg1.sub, pg2.sub, etc.
213 self.flows = dict()
214 self.flows[self.pg0] = [self.pg1.sub_if, self.pg2.sub_if]
215 self.flows[self.pg1.sub_if] = [self.pg0, self.pg2.sub_if]
216 self.flows[self.pg2.sub_if] = [self.pg0, self.pg1.sub_if]
Damjan Marionf56b77a2016-10-03 19:44:57 +0200217
Klement Sekeraf62ae122016-10-11 11:47:09 +0200218 # packet sizes
Jan Geletye6c78ee2018-06-26 12:24:03 +0200219 self.pg_if_packet_sizes = [64, 1500, 9020]
Damjan Marionf56b77a2016-10-03 19:44:57 +0200220
Klement Sekeraf62ae122016-10-11 11:47:09 +0200221 self.interfaces = list(self.pg_interfaces)
222 self.interfaces.extend(self.sub_interfaces)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200223
Klement Sekeraf62ae122016-10-11 11:47:09 +0200224 # setup all interfaces
225 for i in self.interfaces:
226 i.admin_up()
227 i.config_ip6()
228 i.resolve_ndp()
229
Damjan Marionf56b77a2016-10-03 19:44:57 +0200230 def tearDown(self):
Matej Klotton86d87c42016-11-11 11:38:55 +0100231 """Run standard test teardown and log ``show ip6 neighbors``."""
Neale Ranns744902e2017-08-14 10:35:44 -0700232 for i in self.interfaces:
Neale Ranns75152282017-01-09 01:00:45 -0800233 i.unconfig_ip6()
Neale Ranns75152282017-01-09 01:00:45 -0800234 i.admin_down()
Neale Ranns744902e2017-08-14 10:35:44 -0700235 for i in self.sub_interfaces:
Neale Ranns75152282017-01-09 01:00:45 -0800236 i.remove_vpp_config()
237
Klement Sekeraf62ae122016-10-11 11:47:09 +0200238 super(TestIPv6, self).tearDown()
239 if not self.vpp_dead:
Matej Klotton86d87c42016-11-11 11:38:55 +0100240 self.logger.info(self.vapi.cli("show ip6 neighbors"))
Klement Sekeraf62ae122016-10-11 11:47:09 +0200241 # info(self.vapi.cli("show ip6 fib")) # many entries
Damjan Marionf56b77a2016-10-03 19:44:57 +0200242
Jan Geletye6c78ee2018-06-26 12:24:03 +0200243 def modify_packet(self, src_if, packet_size, pkt):
244 """Add load, set destination IP and extend packet to required packet
245 size for defined interface.
246
247 :param VppInterface src_if: Interface to create packet for.
248 :param int packet_size: Required packet size.
249 :param Scapy pkt: Packet to be modified.
250 """
snaramre07a0f212019-10-11 21:28:56 +0000251 dst_if_idx = int(packet_size / 10 % 2)
Jan Geletye6c78ee2018-06-26 12:24:03 +0200252 dst_if = self.flows[src_if][dst_if_idx]
253 info = self.create_packet_info(src_if, dst_if)
254 payload = self.info_to_payload(info)
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800255 p = pkt / Raw(payload)
Jan Geletye6c78ee2018-06-26 12:24:03 +0200256 p[IPv6].dst = dst_if.remote_ip6
257 info.data = p.copy()
258 if isinstance(src_if, VppSubInterface):
259 p = src_if.add_dot1_layer(p)
260 self.extend_packet(p, packet_size)
261
262 return p
263
264 def create_stream(self, src_if):
Matej Klotton86d87c42016-11-11 11:38:55 +0100265 """Create input packet stream for defined interface.
266
267 :param VppInterface src_if: Interface to create packet stream for.
Matej Klotton86d87c42016-11-11 11:38:55 +0100268 """
Jan Geletye6c78ee2018-06-26 12:24:03 +0200269 hdr_ext = 4 if isinstance(src_if, VppSubInterface) else 0
270 pkt_tmpl = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
271 IPv6(src=src_if.remote_ip6) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800272 inet6.UDP(sport=1234, dport=1234))
Jan Geletye6c78ee2018-06-26 12:24:03 +0200273
274 pkts = [self.modify_packet(src_if, i, pkt_tmpl)
Paul Vinciguerraa6fe4632018-11-25 11:21:50 -0800275 for i in moves.range(self.pg_if_packet_sizes[0],
276 self.pg_if_packet_sizes[1], 10)]
Jan Geletye6c78ee2018-06-26 12:24:03 +0200277 pkts_b = [self.modify_packet(src_if, i, pkt_tmpl)
Paul Vinciguerraa6fe4632018-11-25 11:21:50 -0800278 for i in moves.range(self.pg_if_packet_sizes[1] + hdr_ext,
279 self.pg_if_packet_sizes[2] + hdr_ext,
280 50)]
Jan Geletye6c78ee2018-06-26 12:24:03 +0200281 pkts.extend(pkts_b)
282
Damjan Marionf56b77a2016-10-03 19:44:57 +0200283 return pkts
284
Klement Sekeraf62ae122016-10-11 11:47:09 +0200285 def verify_capture(self, dst_if, capture):
Matej Klotton86d87c42016-11-11 11:38:55 +0100286 """Verify captured input packet stream for defined interface.
287
288 :param VppInterface dst_if: Interface to verify captured packet stream
289 for.
290 :param list capture: Captured packet stream.
291 """
292 self.logger.info("Verifying capture on interface %s" % dst_if.name)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200293 last_info = dict()
Damjan Marionf56b77a2016-10-03 19:44:57 +0200294 for i in self.interfaces:
Klement Sekeraf62ae122016-10-11 11:47:09 +0200295 last_info[i.sw_if_index] = None
296 is_sub_if = False
297 dst_sw_if_index = dst_if.sw_if_index
298 if hasattr(dst_if, 'parent'):
299 is_sub_if = True
Damjan Marionf56b77a2016-10-03 19:44:57 +0200300 for packet in capture:
Klement Sekeraf62ae122016-10-11 11:47:09 +0200301 if is_sub_if:
302 # Check VLAN tags and Ethernet header
303 packet = dst_if.remove_dot1_layer(packet)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200304 self.assertTrue(Dot1Q not in packet)
305 try:
306 ip = packet[IPv6]
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800307 udp = packet[inet6.UDP]
Paul Vinciguerraeaea4212019-03-06 11:58:06 -0800308 payload_info = self.payload_to_info(packet[Raw])
Damjan Marionf56b77a2016-10-03 19:44:57 +0200309 packet_index = payload_info.index
Klement Sekeraf62ae122016-10-11 11:47:09 +0200310 self.assertEqual(payload_info.dst, dst_sw_if_index)
Klement Sekerada505f62017-01-04 12:58:53 +0100311 self.logger.debug(
312 "Got packet on port %s: src=%u (id=%u)" %
313 (dst_if.name, payload_info.src, packet_index))
Klement Sekeraf62ae122016-10-11 11:47:09 +0200314 next_info = self.get_next_packet_info_for_interface2(
315 payload_info.src, dst_sw_if_index,
316 last_info[payload_info.src])
317 last_info[payload_info.src] = next_info
Damjan Marionf56b77a2016-10-03 19:44:57 +0200318 self.assertTrue(next_info is not None)
319 self.assertEqual(packet_index, next_info.index)
320 saved_packet = next_info.data
321 # Check standard fields
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800322 self.assertEqual(
323 ip.src, saved_packet[IPv6].src)
324 self.assertEqual(
325 ip.dst, saved_packet[IPv6].dst)
326 self.assertEqual(
327 udp.sport, saved_packet[inet6.UDP].sport)
328 self.assertEqual(
329 udp.dport, saved_packet[inet6.UDP].dport)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200330 except:
Klement Sekera7bb873a2016-11-18 07:38:42 +0100331 self.logger.error(ppp("Unexpected or invalid packet:", packet))
Damjan Marionf56b77a2016-10-03 19:44:57 +0200332 raise
333 for i in self.interfaces:
Klement Sekeraf62ae122016-10-11 11:47:09 +0200334 remaining_packet = self.get_next_packet_info_for_interface2(
335 i.sw_if_index, dst_sw_if_index, last_info[i.sw_if_index])
Klement Sekera7bb873a2016-11-18 07:38:42 +0100336 self.assertTrue(remaining_packet is None,
337 "Interface %s: Packet expected from interface %s "
338 "didn't arrive" % (dst_if.name, i.name))
Damjan Marionf56b77a2016-10-03 19:44:57 +0200339
Klement Sekerae8498652019-06-17 12:23:15 +0000340 def test_next_header_anomaly(self):
341 """ IPv6 next header anomaly test
342
343 Test scenario:
344 - ipv6 next header field = Fragment Header (44)
345 - next header is ICMPv6 Echo Request
346 - wait for reassembly
347 """
348 pkt = (Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) /
349 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6, nh=44) /
350 ICMPv6EchoRequest())
351
352 self.pg0.add_stream(pkt)
353 self.pg_start()
354
355 # wait for reassembly
356 self.sleep(10)
357
Damjan Marionf56b77a2016-10-03 19:44:57 +0200358 def test_fib(self):
Matej Klotton86d87c42016-11-11 11:38:55 +0100359 """ IPv6 FIB test
360
361 Test scenario:
362 - Create IPv6 stream for pg0 interface
363 - Create IPv6 tagged streams for pg1's and pg2's subinterface.
364 - Send and verify received packets on each interface.
365 """
Damjan Marionf56b77a2016-10-03 19:44:57 +0200366
Jan Geletye6c78ee2018-06-26 12:24:03 +0200367 pkts = self.create_stream(self.pg0)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200368 self.pg0.add_stream(pkts)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200369
Klement Sekeraf62ae122016-10-11 11:47:09 +0200370 for i in self.sub_interfaces:
Jan Geletye6c78ee2018-06-26 12:24:03 +0200371 pkts = self.create_stream(i)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200372 i.parent.add_stream(pkts)
373
374 self.pg_enable_capture(self.pg_interfaces)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200375 self.pg_start()
376
Klement Sekeraf62ae122016-10-11 11:47:09 +0200377 pkts = self.pg0.get_capture()
378 self.verify_capture(self.pg0, pkts)
379
380 for i in self.sub_interfaces:
381 pkts = i.parent.get_capture()
382 self.verify_capture(i, pkts)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200383
Neale Ranns75152282017-01-09 01:00:45 -0800384 def test_ns(self):
Klement Sekerada505f62017-01-04 12:58:53 +0100385 """ IPv6 Neighbour Solicitation Exceptions
Neale Ranns75152282017-01-09 01:00:45 -0800386
Klement Sekerada505f62017-01-04 12:58:53 +0100387 Test scenario:
Neale Ranns75152282017-01-09 01:00:45 -0800388 - Send an NS Sourced from an address not covered by the link sub-net
389 - Send an NS to an mcast address the router has not joined
390 - Send NS for a target address the router does not onn.
391 """
392
393 #
394 # An NS from a non link source address
395 #
Neale Ranns3f844d02017-02-18 00:03:54 -0800396 nsma = in6_getnsma(inet_pton(AF_INET6, self.pg0.local_ip6))
397 d = inet_ntop(AF_INET6, nsma)
Neale Ranns75152282017-01-09 01:00:45 -0800398
399 p = (Ether(dst=in6_getnsmac(nsma)) /
400 IPv6(dst=d, src="2002::2") /
401 ICMPv6ND_NS(tgt=self.pg0.local_ip6) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800402 ICMPv6NDOptSrcLLAddr(
403 lladdr=self.pg0.remote_mac))
Neale Ranns75152282017-01-09 01:00:45 -0800404 pkts = [p]
405
Klement Sekerada505f62017-01-04 12:58:53 +0100406 self.send_and_assert_no_replies(
407 self.pg0, pkts,
408 "No response to NS source by address not on sub-net")
Neale Ranns75152282017-01-09 01:00:45 -0800409
410 #
Klement Sekerada505f62017-01-04 12:58:53 +0100411 # An NS for sent to a solicited mcast group the router is
412 # not a member of FAILS
Neale Ranns75152282017-01-09 01:00:45 -0800413 #
414 if 0:
Neale Ranns3f844d02017-02-18 00:03:54 -0800415 nsma = in6_getnsma(inet_pton(AF_INET6, "fd::ffff"))
416 d = inet_ntop(AF_INET6, nsma)
Neale Ranns75152282017-01-09 01:00:45 -0800417
418 p = (Ether(dst=in6_getnsmac(nsma)) /
419 IPv6(dst=d, src=self.pg0.remote_ip6) /
420 ICMPv6ND_NS(tgt=self.pg0.local_ip6) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800421 ICMPv6NDOptSrcLLAddr(
422 lladdr=self.pg0.remote_mac))
Neale Ranns75152282017-01-09 01:00:45 -0800423 pkts = [p]
424
Klement Sekerada505f62017-01-04 12:58:53 +0100425 self.send_and_assert_no_replies(
426 self.pg0, pkts,
427 "No response to NS sent to unjoined mcast address")
Neale Ranns75152282017-01-09 01:00:45 -0800428
429 #
430 # An NS whose target address is one the router does not own
431 #
Neale Ranns3f844d02017-02-18 00:03:54 -0800432 nsma = in6_getnsma(inet_pton(AF_INET6, self.pg0.local_ip6))
433 d = inet_ntop(AF_INET6, nsma)
Neale Ranns75152282017-01-09 01:00:45 -0800434
435 p = (Ether(dst=in6_getnsmac(nsma)) /
436 IPv6(dst=d, src=self.pg0.remote_ip6) /
437 ICMPv6ND_NS(tgt="fd::ffff") /
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800438 ICMPv6NDOptSrcLLAddr(
439 lladdr=self.pg0.remote_mac))
Neale Ranns75152282017-01-09 01:00:45 -0800440 pkts = [p]
441
442 self.send_and_assert_no_replies(self.pg0, pkts,
443 "No response to NS for unknown target")
444
Neale Rannsb3b2de72017-03-08 05:17:22 -0800445 #
446 # A neighbor entry that has no associated FIB-entry
447 #
448 self.pg0.generate_remote_hosts(4)
449 nd_entry = VppNeighbor(self,
450 self.pg0.sw_if_index,
451 self.pg0.remote_hosts[2].mac,
452 self.pg0.remote_hosts[2].ip6,
Neale Rannsb3b2de72017-03-08 05:17:22 -0800453 is_no_fib_entry=1)
454 nd_entry.add_vpp_config()
455
456 #
457 # check we have the neighbor, but no route
458 #
459 self.assertTrue(find_nbr(self,
460 self.pg0.sw_if_index,
Neale Ranns37029302018-08-10 05:30:06 -0700461 self.pg0._remote_hosts[2].ip6))
Neale Rannsb3b2de72017-03-08 05:17:22 -0800462 self.assertFalse(find_route(self,
463 self.pg0._remote_hosts[2].ip6,
Neale Ranns097fa662018-05-01 05:17:55 -0700464 128))
Neale Rannsb3b2de72017-03-08 05:17:22 -0800465
Neale Ranns2a3ea492017-04-19 05:24:40 -0700466 #
467 # send an NS from a link local address to the interface's global
468 # address
469 #
470 p = (Ether(dst=in6_getnsmac(nsma), src=self.pg0.remote_mac) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800471 IPv6(
472 dst=d, src=self.pg0._remote_hosts[2].ip6_ll) /
Neale Ranns2a3ea492017-04-19 05:24:40 -0700473 ICMPv6ND_NS(tgt=self.pg0.local_ip6) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800474 ICMPv6NDOptSrcLLAddr(
475 lladdr=self.pg0.remote_mac))
Neale Ranns2a3ea492017-04-19 05:24:40 -0700476
477 self.send_and_expect_na(self.pg0, p,
478 "NS from link-local",
479 dst_ip=self.pg0._remote_hosts[2].ip6_ll,
480 tgt_ip=self.pg0.local_ip6)
481
482 #
483 # we should have learned an ND entry for the peer's link-local
484 # but not inserted a route to it in the FIB
485 #
486 self.assertTrue(find_nbr(self,
487 self.pg0.sw_if_index,
Neale Ranns37029302018-08-10 05:30:06 -0700488 self.pg0._remote_hosts[2].ip6_ll))
Neale Ranns2a3ea492017-04-19 05:24:40 -0700489 self.assertFalse(find_route(self,
490 self.pg0._remote_hosts[2].ip6_ll,
Neale Ranns097fa662018-05-01 05:17:55 -0700491 128))
Neale Ranns2a3ea492017-04-19 05:24:40 -0700492
493 #
494 # An NS to the router's own Link-local
495 #
496 p = (Ether(dst=in6_getnsmac(nsma), src=self.pg0.remote_mac) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800497 IPv6(
498 dst=d, src=self.pg0._remote_hosts[3].ip6_ll) /
Neale Ranns2a3ea492017-04-19 05:24:40 -0700499 ICMPv6ND_NS(tgt=self.pg0.local_ip6_ll) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800500 ICMPv6NDOptSrcLLAddr(
501 lladdr=self.pg0.remote_mac))
Neale Ranns2a3ea492017-04-19 05:24:40 -0700502
503 self.send_and_expect_na(self.pg0, p,
504 "NS to/from link-local",
505 dst_ip=self.pg0._remote_hosts[3].ip6_ll,
506 tgt_ip=self.pg0.local_ip6_ll)
507
508 #
509 # we should have learned an ND entry for the peer's link-local
510 # but not inserted a route to it in the FIB
511 #
512 self.assertTrue(find_nbr(self,
513 self.pg0.sw_if_index,
Neale Ranns37029302018-08-10 05:30:06 -0700514 self.pg0._remote_hosts[3].ip6_ll))
Neale Ranns2a3ea492017-04-19 05:24:40 -0700515 self.assertFalse(find_route(self,
516 self.pg0._remote_hosts[3].ip6_ll,
Neale Ranns097fa662018-05-01 05:17:55 -0700517 128))
Neale Ranns2a3ea492017-04-19 05:24:40 -0700518
Neale Rannsdcd6d622017-05-26 02:59:16 -0700519 def test_ns_duplicates(self):
Neale Rannsda78f952017-05-24 09:15:43 -0700520 """ ND Duplicates"""
Neale Rannsdcd6d622017-05-26 02:59:16 -0700521
522 #
523 # Generate some hosts on the LAN
524 #
525 self.pg1.generate_remote_hosts(3)
526
527 #
528 # Add host 1 on pg1 and pg2
529 #
530 ns_pg1 = VppNeighbor(self,
531 self.pg1.sw_if_index,
532 self.pg1.remote_hosts[1].mac,
Neale Ranns37029302018-08-10 05:30:06 -0700533 self.pg1.remote_hosts[1].ip6)
Neale Rannsdcd6d622017-05-26 02:59:16 -0700534 ns_pg1.add_vpp_config()
535 ns_pg2 = VppNeighbor(self,
536 self.pg2.sw_if_index,
537 self.pg2.remote_mac,
Neale Ranns37029302018-08-10 05:30:06 -0700538 self.pg1.remote_hosts[1].ip6)
Neale Rannsdcd6d622017-05-26 02:59:16 -0700539 ns_pg2.add_vpp_config()
540
541 #
542 # IP packet destined for pg1 remote host arrives on pg1 again.
543 #
544 p = (Ether(dst=self.pg0.local_mac,
545 src=self.pg0.remote_mac) /
546 IPv6(src=self.pg0.remote_ip6,
547 dst=self.pg1.remote_hosts[1].ip6) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800548 inet6.UDP(sport=1234, dport=1234) /
Neale Rannsdcd6d622017-05-26 02:59:16 -0700549 Raw())
550
551 self.pg0.add_stream(p)
552 self.pg_enable_capture(self.pg_interfaces)
553 self.pg_start()
554
555 rx1 = self.pg1.get_capture(1)
556
557 self.verify_ip(rx1[0],
558 self.pg1.local_mac,
559 self.pg1.remote_hosts[1].mac,
560 self.pg0.remote_ip6,
561 self.pg1.remote_hosts[1].ip6)
562
563 #
564 # remove the duplicate on pg1
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700565 # packet stream should generate NSs out of pg1
Neale Rannsdcd6d622017-05-26 02:59:16 -0700566 #
567 ns_pg1.remove_vpp_config()
568
569 self.send_and_expect_ns(self.pg0, self.pg1,
570 p, self.pg1.remote_hosts[1].ip6)
571
572 #
573 # Add it back
574 #
575 ns_pg1.add_vpp_config()
576
577 self.pg0.add_stream(p)
578 self.pg_enable_capture(self.pg_interfaces)
579 self.pg_start()
580
581 rx1 = self.pg1.get_capture(1)
582
583 self.verify_ip(rx1[0],
584 self.pg1.local_mac,
585 self.pg1.remote_hosts[1].mac,
586 self.pg0.remote_ip6,
587 self.pg1.remote_hosts[1].ip6)
588
Neale Rannscbe25aa2019-09-30 10:53:31 +0000589 def validate_ra(self, intf, rx, dst_ip=None, src_ip=None,
590 mtu=9000, pi_opt=None):
Neale Ranns32e1c012016-11-22 17:07:28 +0000591 if not dst_ip:
592 dst_ip = intf.remote_ip6
Neale Rannscbe25aa2019-09-30 10:53:31 +0000593 if not src_ip:
594 src_ip = mk_ll_addr(intf.local_mac)
Neale Ranns75152282017-01-09 01:00:45 -0800595
Neale Ranns5737d882017-02-03 06:14:49 -0800596 # unicasted packets must come to the unicast mac
Neale Ranns32e1c012016-11-22 17:07:28 +0000597 self.assertEqual(rx[Ether].dst, intf.remote_mac)
598
599 # and from the router's MAC
600 self.assertEqual(rx[Ether].src, intf.local_mac)
Neale Ranns75152282017-01-09 01:00:45 -0800601
602 # the rx'd RA should be addressed to the sender's source
603 self.assertTrue(rx.haslayer(ICMPv6ND_RA))
604 self.assertEqual(in6_ptop(rx[IPv6].dst),
Neale Ranns32e1c012016-11-22 17:07:28 +0000605 in6_ptop(dst_ip))
Neale Ranns75152282017-01-09 01:00:45 -0800606
607 # and come from the router's link local
608 self.assertTrue(in6_islladdr(rx[IPv6].src))
Neale Rannscbe25aa2019-09-30 10:53:31 +0000609 self.assertEqual(in6_ptop(rx[IPv6].src), in6_ptop(src_ip))
Neale Ranns75152282017-01-09 01:00:45 -0800610
Neale Ranns87df12d2017-02-18 08:16:41 -0800611 # it should contain the links MTU
612 ra = rx[ICMPv6ND_RA]
613 self.assertEqual(ra[ICMPv6NDOptMTU].mtu, mtu)
614
615 # it should contain the source's link layer address option
616 sll = ra[ICMPv6NDOptSrcLLAddr]
617 self.assertEqual(sll.lladdr, intf.local_mac)
618
619 if not pi_opt:
620 # the RA should not contain prefix information
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800621 self.assertFalse(ra.haslayer(
622 ICMPv6NDOptPrefixInfo))
Neale Ranns87df12d2017-02-18 08:16:41 -0800623 else:
624 raos = rx.getlayer(ICMPv6NDOptPrefixInfo, 1)
625
626 # the options are nested in the scapy packet in way that i cannot
627 # decipher how to decode. this 1st layer of option always returns
628 # nested classes, so a direct obj1=obj2 comparison always fails.
Paul Vinciguerraab055082019-06-06 14:07:55 -0400629 # however, the getlayer(.., 2) does give one instance.
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700630 # so we cheat here and construct a new opt instance for comparison
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800631 rd = ICMPv6NDOptPrefixInfo(
632 prefixlen=raos.prefixlen,
633 prefix=raos.prefix,
634 L=raos.L,
635 A=raos.A)
Neale Ranns87df12d2017-02-18 08:16:41 -0800636 if type(pi_opt) is list:
637 for ii in range(len(pi_opt)):
638 self.assertEqual(pi_opt[ii], rd)
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800639 rd = rx.getlayer(
640 ICMPv6NDOptPrefixInfo, ii + 2)
Neale Ranns87df12d2017-02-18 08:16:41 -0800641 else:
Paul Vinciguerraab055082019-06-06 14:07:55 -0400642 self.assertEqual(pi_opt, raos, 'Expected: %s, received: %s'
643 % (pi_opt.show(dump=True),
644 raos.show(dump=True)))
Neale Ranns87df12d2017-02-18 08:16:41 -0800645
Neale Ranns32e1c012016-11-22 17:07:28 +0000646 def send_and_expect_ra(self, intf, pkts, remark, dst_ip=None,
Neale Ranns87df12d2017-02-18 08:16:41 -0800647 filter_out_fn=is_ipv6_misc,
Neale Rannscbe25aa2019-09-30 10:53:31 +0000648 opt=None,
649 src_ip=None):
650 self.vapi.cli("clear trace")
Neale Ranns32e1c012016-11-22 17:07:28 +0000651 intf.add_stream(pkts)
Neale Ranns32e1c012016-11-22 17:07:28 +0000652 self.pg_enable_capture(self.pg_interfaces)
653 self.pg_start()
654 rx = intf.get_capture(1, filter_out_fn=filter_out_fn)
655
656 self.assertEqual(len(rx), 1)
657 rx = rx[0]
Neale Rannscbe25aa2019-09-30 10:53:31 +0000658 self.validate_ra(intf, rx, dst_ip, src_ip=src_ip, pi_opt=opt)
Neale Ranns32e1c012016-11-22 17:07:28 +0000659
Neale Ranns75152282017-01-09 01:00:45 -0800660 def test_rs(self):
Klement Sekerada505f62017-01-04 12:58:53 +0100661 """ IPv6 Router Solicitation Exceptions
Neale Ranns75152282017-01-09 01:00:45 -0800662
Klement Sekerada505f62017-01-04 12:58:53 +0100663 Test scenario:
Neale Ranns75152282017-01-09 01:00:45 -0800664 """
665
666 #
Klement Sekerada505f62017-01-04 12:58:53 +0100667 # Before we begin change the IPv6 RA responses to use the unicast
668 # address - that way we will not confuse them with the periodic
669 # RAs which go to the mcast address
Neale Ranns32e1c012016-11-22 17:07:28 +0000670 # Sit and wait for the first periodic RA.
671 #
672 # TODO
Neale Ranns75152282017-01-09 01:00:45 -0800673 #
674 self.pg0.ip6_ra_config(send_unicast=1)
675
676 #
677 # An RS from a link source address
678 # - expect an RA in return
679 #
680 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
Neale Rannscbe25aa2019-09-30 10:53:31 +0000681 IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) /
Neale Ranns75152282017-01-09 01:00:45 -0800682 ICMPv6ND_RS())
683 pkts = [p]
684 self.send_and_expect_ra(self.pg0, pkts, "Genuine RS")
685
686 #
687 # For the next RS sent the RA should be rate limited
688 #
689 self.send_and_assert_no_replies(self.pg0, pkts, "RA rate limited")
690
691 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700692 # When we reconfigure the IPv6 RA config,
693 # we reset the RA rate limiting,
Klement Sekerada505f62017-01-04 12:58:53 +0100694 # so we need to do this before each test below so as not to drop
695 # packets for rate limiting reasons. Test this works here.
Neale Ranns75152282017-01-09 01:00:45 -0800696 #
697 self.pg0.ip6_ra_config(send_unicast=1)
698 self.send_and_expect_ra(self.pg0, pkts, "Rate limit reset RS")
699
700 #
701 # An RS sent from a non-link local source
702 #
703 self.pg0.ip6_ra_config(send_unicast=1)
704 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800705 IPv6(dst=self.pg0.local_ip6,
706 src="2002::ffff") /
Neale Ranns75152282017-01-09 01:00:45 -0800707 ICMPv6ND_RS())
708 pkts = [p]
709 self.send_and_assert_no_replies(self.pg0, pkts,
710 "RS from non-link source")
711
712 #
713 # Source an RS from a link local address
714 #
715 self.pg0.ip6_ra_config(send_unicast=1)
716 ll = mk_ll_addr(self.pg0.remote_mac)
717 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
718 IPv6(dst=self.pg0.local_ip6, src=ll) /
719 ICMPv6ND_RS())
720 pkts = [p]
Neale Ranns32e1c012016-11-22 17:07:28 +0000721 self.send_and_expect_ra(self.pg0, pkts,
722 "RS sourced from link-local",
723 dst_ip=ll)
724
725 #
726 # Send the RS multicast
727 #
728 self.pg0.ip6_ra_config(send_unicast=1)
Neale Ranns3f844d02017-02-18 00:03:54 -0800729 dmac = in6_getnsmac(inet_pton(AF_INET6, "ff02::2"))
Neale Ranns32e1c012016-11-22 17:07:28 +0000730 ll = mk_ll_addr(self.pg0.remote_mac)
731 p = (Ether(dst=dmac, src=self.pg0.remote_mac) /
732 IPv6(dst="ff02::2", src=ll) /
733 ICMPv6ND_RS())
734 pkts = [p]
735 self.send_and_expect_ra(self.pg0, pkts,
736 "RS sourced from link-local",
737 dst_ip=ll)
Neale Ranns75152282017-01-09 01:00:45 -0800738
739 #
Klement Sekerada505f62017-01-04 12:58:53 +0100740 # Source from the unspecified address ::. This happens when the RS
741 # is sent before the host has a configured address/sub-net,
742 # i.e. auto-config. Since the sender has no IP address, the reply
743 # comes back mcast - so the capture needs to not filter this.
744 # If we happen to pick up the periodic RA at this point then so be it,
745 # it's not an error.
Neale Ranns75152282017-01-09 01:00:45 -0800746 #
Neale Ranns32e1c012016-11-22 17:07:28 +0000747 self.pg0.ip6_ra_config(send_unicast=1, suppress=1)
748 p = (Ether(dst=dmac, src=self.pg0.remote_mac) /
749 IPv6(dst="ff02::2", src="::") /
Neale Ranns75152282017-01-09 01:00:45 -0800750 ICMPv6ND_RS())
751 pkts = [p]
Neale Ranns32e1c012016-11-22 17:07:28 +0000752 self.send_and_expect_ra(self.pg0, pkts,
753 "RS sourced from unspecified",
754 dst_ip="ff02::1",
755 filter_out_fn=None)
Neale Ranns75152282017-01-09 01:00:45 -0800756
757 #
Neale Ranns87df12d2017-02-18 08:16:41 -0800758 # Configure The RA to announce the links prefix
759 #
Paul Vinciguerraab055082019-06-06 14:07:55 -0400760 self.pg0.ip6_ra_prefix('%s/%s' % (self.pg0.local_ip6,
761 self.pg0.local_ip6_prefix_len))
Neale Ranns87df12d2017-02-18 08:16:41 -0800762
763 #
764 # RAs should now contain the prefix information option
765 #
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800766 opt = ICMPv6NDOptPrefixInfo(
767 prefixlen=self.pg0.local_ip6_prefix_len,
768 prefix=self.pg0.local_ip6,
769 L=1,
770 A=1)
Neale Ranns87df12d2017-02-18 08:16:41 -0800771
772 self.pg0.ip6_ra_config(send_unicast=1)
773 ll = mk_ll_addr(self.pg0.remote_mac)
774 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
775 IPv6(dst=self.pg0.local_ip6, src=ll) /
776 ICMPv6ND_RS())
777 self.send_and_expect_ra(self.pg0, p,
778 "RA with prefix-info",
779 dst_ip=ll,
780 opt=opt)
781
782 #
783 # Change the prefix info to not off-link
784 # L-flag is clear
785 #
Paul Vinciguerraab055082019-06-06 14:07:55 -0400786 self.pg0.ip6_ra_prefix('%s/%s' % (self.pg0.local_ip6,
787 self.pg0.local_ip6_prefix_len),
Neale Ranns87df12d2017-02-18 08:16:41 -0800788 off_link=1)
789
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800790 opt = ICMPv6NDOptPrefixInfo(
791 prefixlen=self.pg0.local_ip6_prefix_len,
792 prefix=self.pg0.local_ip6,
793 L=0,
794 A=1)
Neale Ranns87df12d2017-02-18 08:16:41 -0800795
796 self.pg0.ip6_ra_config(send_unicast=1)
797 self.send_and_expect_ra(self.pg0, p,
798 "RA with Prefix info with L-flag=0",
799 dst_ip=ll,
800 opt=opt)
801
802 #
803 # Change the prefix info to not off-link, no-autoconfig
804 # L and A flag are clear in the advert
805 #
Paul Vinciguerraab055082019-06-06 14:07:55 -0400806 self.pg0.ip6_ra_prefix('%s/%s' % (self.pg0.local_ip6,
807 self.pg0.local_ip6_prefix_len),
Neale Ranns87df12d2017-02-18 08:16:41 -0800808 off_link=1,
809 no_autoconfig=1)
810
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800811 opt = ICMPv6NDOptPrefixInfo(
812 prefixlen=self.pg0.local_ip6_prefix_len,
813 prefix=self.pg0.local_ip6,
814 L=0,
815 A=0)
Neale Ranns87df12d2017-02-18 08:16:41 -0800816
817 self.pg0.ip6_ra_config(send_unicast=1)
818 self.send_and_expect_ra(self.pg0, p,
819 "RA with Prefix info with A & L-flag=0",
820 dst_ip=ll,
821 opt=opt)
822
823 #
824 # Change the flag settings back to the defaults
825 # L and A flag are set in the advert
826 #
Paul Vinciguerraab055082019-06-06 14:07:55 -0400827 self.pg0.ip6_ra_prefix('%s/%s' % (self.pg0.local_ip6,
828 self.pg0.local_ip6_prefix_len))
Neale Ranns87df12d2017-02-18 08:16:41 -0800829
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800830 opt = ICMPv6NDOptPrefixInfo(
831 prefixlen=self.pg0.local_ip6_prefix_len,
832 prefix=self.pg0.local_ip6,
833 L=1,
834 A=1)
Neale Ranns87df12d2017-02-18 08:16:41 -0800835
836 self.pg0.ip6_ra_config(send_unicast=1)
837 self.send_and_expect_ra(self.pg0, p,
838 "RA with Prefix info",
839 dst_ip=ll,
840 opt=opt)
841
842 #
843 # Change the prefix info to not off-link, no-autoconfig
844 # L and A flag are clear in the advert
845 #
Paul Vinciguerraab055082019-06-06 14:07:55 -0400846 self.pg0.ip6_ra_prefix('%s/%s' % (self.pg0.local_ip6,
847 self.pg0.local_ip6_prefix_len),
Neale Ranns87df12d2017-02-18 08:16:41 -0800848 off_link=1,
849 no_autoconfig=1)
850
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800851 opt = ICMPv6NDOptPrefixInfo(
852 prefixlen=self.pg0.local_ip6_prefix_len,
853 prefix=self.pg0.local_ip6,
854 L=0,
855 A=0)
Neale Ranns87df12d2017-02-18 08:16:41 -0800856
857 self.pg0.ip6_ra_config(send_unicast=1)
858 self.send_and_expect_ra(self.pg0, p,
859 "RA with Prefix info with A & L-flag=0",
860 dst_ip=ll,
861 opt=opt)
862
863 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700864 # Use the reset to defaults option to revert to defaults
Neale Ranns87df12d2017-02-18 08:16:41 -0800865 # L and A flag are clear in the advert
866 #
Paul Vinciguerraab055082019-06-06 14:07:55 -0400867 self.pg0.ip6_ra_prefix('%s/%s' % (self.pg0.local_ip6,
868 self.pg0.local_ip6_prefix_len),
Neale Ranns87df12d2017-02-18 08:16:41 -0800869 use_default=1)
870
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800871 opt = ICMPv6NDOptPrefixInfo(
872 prefixlen=self.pg0.local_ip6_prefix_len,
873 prefix=self.pg0.local_ip6,
874 L=1,
875 A=1)
Neale Ranns87df12d2017-02-18 08:16:41 -0800876
877 self.pg0.ip6_ra_config(send_unicast=1)
878 self.send_and_expect_ra(self.pg0, p,
879 "RA with Prefix reverted to defaults",
880 dst_ip=ll,
881 opt=opt)
882
883 #
884 # Advertise Another prefix. With no L-flag/A-flag
885 #
Paul Vinciguerraab055082019-06-06 14:07:55 -0400886 self.pg0.ip6_ra_prefix('%s/%s' % (self.pg1.local_ip6,
887 self.pg1.local_ip6_prefix_len),
Neale Ranns87df12d2017-02-18 08:16:41 -0800888 off_link=1,
889 no_autoconfig=1)
890
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800891 opt = [ICMPv6NDOptPrefixInfo(
892 prefixlen=self.pg0.local_ip6_prefix_len,
893 prefix=self.pg0.local_ip6,
894 L=1,
895 A=1),
896 ICMPv6NDOptPrefixInfo(
897 prefixlen=self.pg1.local_ip6_prefix_len,
898 prefix=self.pg1.local_ip6,
899 L=0,
900 A=0)]
Neale Ranns87df12d2017-02-18 08:16:41 -0800901
902 self.pg0.ip6_ra_config(send_unicast=1)
903 ll = mk_ll_addr(self.pg0.remote_mac)
904 p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
905 IPv6(dst=self.pg0.local_ip6, src=ll) /
906 ICMPv6ND_RS())
907 self.send_and_expect_ra(self.pg0, p,
908 "RA with multiple Prefix infos",
909 dst_ip=ll,
910 opt=opt)
911
912 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700913 # Remove the first prefix-info - expect the second is still in the
Neale Ranns87df12d2017-02-18 08:16:41 -0800914 # advert
915 #
Paul Vinciguerraab055082019-06-06 14:07:55 -0400916 self.pg0.ip6_ra_prefix('%s/%s' % (self.pg0.local_ip6,
917 self.pg0.local_ip6_prefix_len),
Neale Ranns87df12d2017-02-18 08:16:41 -0800918 is_no=1)
919
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800920 opt = ICMPv6NDOptPrefixInfo(
921 prefixlen=self.pg1.local_ip6_prefix_len,
922 prefix=self.pg1.local_ip6,
923 L=0,
924 A=0)
Neale Ranns87df12d2017-02-18 08:16:41 -0800925
926 self.pg0.ip6_ra_config(send_unicast=1)
927 self.send_and_expect_ra(self.pg0, p,
928 "RA with Prefix reverted to defaults",
929 dst_ip=ll,
930 opt=opt)
931
932 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700933 # Remove the second prefix-info - expect no prefix-info in the adverts
Neale Ranns87df12d2017-02-18 08:16:41 -0800934 #
Paul Vinciguerraab055082019-06-06 14:07:55 -0400935 self.pg0.ip6_ra_prefix('%s/%s' % (self.pg1.local_ip6,
936 self.pg1.local_ip6_prefix_len),
Neale Ranns87df12d2017-02-18 08:16:41 -0800937 is_no=1)
938
Neale Rannscbe25aa2019-09-30 10:53:31 +0000939 #
940 # change the link's link local, so we know that works too.
941 #
942 self.vapi.sw_interface_ip6_set_link_local_address(
943 sw_if_index=self.pg0.sw_if_index,
944 ip="fe80::88")
945
Neale Ranns87df12d2017-02-18 08:16:41 -0800946 self.pg0.ip6_ra_config(send_unicast=1)
947 self.send_and_expect_ra(self.pg0, p,
948 "RA with Prefix reverted to defaults",
Neale Rannscbe25aa2019-09-30 10:53:31 +0000949 dst_ip=ll,
950 src_ip="fe80::88")
Neale Ranns87df12d2017-02-18 08:16:41 -0800951
952 #
Neale Ranns5737d882017-02-03 06:14:49 -0800953 # Reset the periodic advertisements back to default values
Neale Ranns75152282017-01-09 01:00:45 -0800954 #
Neale Ranns32e1c012016-11-22 17:07:28 +0000955 self.pg0.ip6_ra_config(no=1, suppress=1, send_unicast=0)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200956
Neale Rannsf267d112020-02-07 09:45:07 +0000957 def test_mld(self):
958 """ MLD Report """
959 #
960 # test one MLD is sent after applying an IPv6 Address on an interface
961 #
962 self.pg_enable_capture(self.pg_interfaces)
963 self.pg_start()
964
965 subitf = VppDot1QSubint(self, self.pg1, 99)
966
967 subitf.admin_up()
968 subitf.config_ip6()
969
Neale Ranns03c254e2020-03-17 14:25:10 +0000970 rxs = self.pg1._get_capture(timeout=4, filter_out_fn=None)
Neale Rannsf267d112020-02-07 09:45:07 +0000971
972 #
973 # hunt for the MLD on vlan 99
974 #
975 for rx in rxs:
976 # make sure ipv6 packets with hop by hop options have
977 # correct checksums
978 self.assert_packet_checksums_valid(rx)
979 if rx.haslayer(IPv6ExtHdrHopByHop) and \
980 rx.haslayer(Dot1Q) and \
981 rx[Dot1Q].vlan == 99:
982 mld = rx[ICMPv6MLReport2]
983
984 self.assertEqual(mld.records_number, 4)
985
Neale Ranns3f844d02017-02-18 00:03:54 -0800986
Christian Hoppsf5d38e02020-05-04 10:28:03 -0400987class TestIPv6RouteLookup(VppTestCase):
988 """ IPv6 Route Lookup Test Case """
989 routes = []
990
991 def route_lookup(self, prefix, exact):
992 return self.vapi.api(self.vapi.papi.ip_route_lookup,
993 {
994 'table_id': 0,
995 'exact': exact,
996 'prefix': prefix,
997 })
998
999 @classmethod
1000 def setUpClass(cls):
1001 super(TestIPv6RouteLookup, cls).setUpClass()
1002
1003 @classmethod
1004 def tearDownClass(cls):
1005 super(TestIPv6RouteLookup, cls).tearDownClass()
1006
1007 def setUp(self):
1008 super(TestIPv6RouteLookup, self).setUp()
1009
1010 drop_nh = VppRoutePath("::1", 0xffffffff,
1011 type=FibPathType.FIB_PATH_TYPE_DROP)
1012
1013 # Add 3 routes
1014 r = VppIpRoute(self, "2001:1111::", 32, [drop_nh])
1015 r.add_vpp_config()
1016 self.routes.append(r)
1017
1018 r = VppIpRoute(self, "2001:1111:2222::", 48, [drop_nh])
1019 r.add_vpp_config()
1020 self.routes.append(r)
1021
1022 r = VppIpRoute(self, "2001:1111:2222::1", 128, [drop_nh])
1023 r.add_vpp_config()
1024 self.routes.append(r)
1025
1026 def tearDown(self):
1027 # Remove the routes we added
1028 for r in self.routes:
1029 r.remove_vpp_config()
1030
1031 super(TestIPv6RouteLookup, self).tearDown()
1032
1033 def test_exact_match(self):
1034 # Verify we find the host route
1035 prefix = "2001:1111:2222::1/128"
1036 result = self.route_lookup(prefix, True)
1037 assert (prefix == str(result.route.prefix))
1038
1039 # Verify we find a middle prefix route
1040 prefix = "2001:1111:2222::/48"
1041 result = self.route_lookup(prefix, True)
1042 assert (prefix == str(result.route.prefix))
1043
1044 # Verify we do not find an available LPM.
1045 with self.vapi.assert_negative_api_retval():
1046 self.route_lookup("2001::2/128", True)
1047
1048 def test_longest_prefix_match(self):
1049 # verify we find lpm
1050 lpm_prefix = "2001:1111:2222::/48"
1051 result = self.route_lookup("2001:1111:2222::2/128", False)
1052 assert (lpm_prefix == str(result.route.prefix))
1053
1054 # Verify we find the exact when not requested
1055 result = self.route_lookup(lpm_prefix, False)
1056 assert (lpm_prefix == str(result.route.prefix))
1057
1058 # Can't seem to delete the default route so no negative LPM test.
1059
1060
Matthew Smith6c92f5b2019-08-07 11:46:30 -05001061class TestIPv6IfAddrRoute(VppTestCase):
1062 """ IPv6 Interface Addr Route Test Case """
1063
1064 @classmethod
1065 def setUpClass(cls):
1066 super(TestIPv6IfAddrRoute, cls).setUpClass()
1067
1068 @classmethod
1069 def tearDownClass(cls):
1070 super(TestIPv6IfAddrRoute, cls).tearDownClass()
1071
1072 def setUp(self):
1073 super(TestIPv6IfAddrRoute, self).setUp()
1074
1075 # create 1 pg interface
1076 self.create_pg_interfaces(range(1))
1077
1078 for i in self.pg_interfaces:
1079 i.admin_up()
1080 i.config_ip6()
1081 i.resolve_ndp()
1082
1083 def tearDown(self):
1084 super(TestIPv6IfAddrRoute, self).tearDown()
1085 for i in self.pg_interfaces:
1086 i.unconfig_ip6()
1087 i.admin_down()
1088
1089 def test_ipv6_ifaddrs_same_prefix(self):
1090 """ IPv6 Interface Addresses Same Prefix test
1091
1092 Test scenario:
1093
1094 - Verify no route in FIB for prefix 2001:10::/64
1095 - Configure IPv4 address 2001:10::10/64 on an interface
1096 - Verify route in FIB for prefix 2001:10::/64
1097 - Configure IPv4 address 2001:10::20/64 on an interface
1098 - Delete 2001:10::10/64 from interface
1099 - Verify route in FIB for prefix 2001:10::/64
1100 - Delete 2001:10::20/64 from interface
1101 - Verify no route in FIB for prefix 2001:10::/64
1102 """
1103
1104 addr1 = "2001:10::10"
1105 addr2 = "2001:10::20"
1106
Neale Rannsefd7bc22019-11-11 08:32:34 +00001107 if_addr1 = VppIpInterfaceAddress(self, self.pg0, addr1, 64)
1108 if_addr2 = VppIpInterfaceAddress(self, self.pg0, addr2, 64)
1109 self.assertFalse(if_addr1.query_vpp_config())
Matthew Smith6c92f5b2019-08-07 11:46:30 -05001110 self.assertFalse(find_route(self, addr1, 128))
1111 self.assertFalse(find_route(self, addr2, 128))
1112
1113 # configure first address, verify route present
1114 if_addr1.add_vpp_config()
Neale Rannsefd7bc22019-11-11 08:32:34 +00001115 self.assertTrue(if_addr1.query_vpp_config())
Matthew Smith6c92f5b2019-08-07 11:46:30 -05001116 self.assertTrue(find_route(self, addr1, 128))
1117 self.assertFalse(find_route(self, addr2, 128))
1118
1119 # configure second address, delete first, verify route not removed
1120 if_addr2.add_vpp_config()
1121 if_addr1.remove_vpp_config()
Neale Rannsefd7bc22019-11-11 08:32:34 +00001122 self.assertFalse(if_addr1.query_vpp_config())
1123 self.assertTrue(if_addr2.query_vpp_config())
Matthew Smith6c92f5b2019-08-07 11:46:30 -05001124 self.assertFalse(find_route(self, addr1, 128))
1125 self.assertTrue(find_route(self, addr2, 128))
1126
1127 # delete second address, verify route removed
1128 if_addr2.remove_vpp_config()
Neale Rannsefd7bc22019-11-11 08:32:34 +00001129 self.assertFalse(if_addr1.query_vpp_config())
Matthew Smith6c92f5b2019-08-07 11:46:30 -05001130 self.assertFalse(find_route(self, addr1, 128))
1131 self.assertFalse(find_route(self, addr2, 128))
1132
yedgdbd366b2020-05-14 10:51:53 +08001133 def test_ipv6_ifaddr_del(self):
1134 """ Delete an interface address that does not exist """
1135
1136 loopbacks = self.create_loopback_interfaces(1)
1137 lo = self.lo_interfaces[0]
1138
1139 lo.config_ip6()
1140 lo.admin_up()
1141
1142 #
1143 # try and remove pg0's subnet from lo
1144 #
1145 with self.vapi.assert_negative_api_retval():
1146 self.vapi.sw_interface_add_del_address(
1147 sw_if_index=lo.sw_if_index,
1148 prefix=self.pg0.local_ip6_prefix,
1149 is_add=0)
1150
Matthew Smith6c92f5b2019-08-07 11:46:30 -05001151
Jan Geletye6c78ee2018-06-26 12:24:03 +02001152class TestICMPv6Echo(VppTestCase):
1153 """ ICMPv6 Echo Test Case """
1154
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001155 @classmethod
1156 def setUpClass(cls):
1157 super(TestICMPv6Echo, cls).setUpClass()
1158
1159 @classmethod
1160 def tearDownClass(cls):
1161 super(TestICMPv6Echo, cls).tearDownClass()
1162
Jan Geletye6c78ee2018-06-26 12:24:03 +02001163 def setUp(self):
1164 super(TestICMPv6Echo, self).setUp()
1165
1166 # create 1 pg interface
1167 self.create_pg_interfaces(range(1))
1168
1169 for i in self.pg_interfaces:
1170 i.admin_up()
1171 i.config_ip6()
1172 i.resolve_ndp()
1173
1174 def tearDown(self):
1175 super(TestICMPv6Echo, self).tearDown()
1176 for i in self.pg_interfaces:
1177 i.unconfig_ip6()
Jan Geletye6c78ee2018-06-26 12:24:03 +02001178 i.admin_down()
1179
1180 def test_icmpv6_echo(self):
1181 """ VPP replies to ICMPv6 Echo Request
1182
1183 Test scenario:
1184
1185 - Receive ICMPv6 Echo Request message on pg0 interface.
1186 - Check outgoing ICMPv6 Echo Reply message on pg0 interface.
1187 """
1188
1189 icmpv6_id = 0xb
1190 icmpv6_seq = 5
Paul Vinciguerra22ab6f72019-03-07 17:55:33 -08001191 icmpv6_data = b'\x0a' * 18
Jan Geletye6c78ee2018-06-26 12:24:03 +02001192 p_echo_request = (Ether(src=self.pg0.remote_mac,
1193 dst=self.pg0.local_mac) /
1194 IPv6(src=self.pg0.remote_ip6,
1195 dst=self.pg0.local_ip6) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001196 ICMPv6EchoRequest(
1197 id=icmpv6_id,
1198 seq=icmpv6_seq,
1199 data=icmpv6_data))
Jan Geletye6c78ee2018-06-26 12:24:03 +02001200
1201 self.pg0.add_stream(p_echo_request)
1202 self.pg_enable_capture(self.pg_interfaces)
1203 self.pg_start()
1204
1205 rx = self.pg0.get_capture(1)
1206 rx = rx[0]
1207 ether = rx[Ether]
1208 ipv6 = rx[IPv6]
1209 icmpv6 = rx[ICMPv6EchoReply]
1210
1211 self.assertEqual(ether.src, self.pg0.local_mac)
1212 self.assertEqual(ether.dst, self.pg0.remote_mac)
1213
1214 self.assertEqual(ipv6.src, self.pg0.local_ip6)
1215 self.assertEqual(ipv6.dst, self.pg0.remote_ip6)
1216
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001217 self.assertEqual(
1218 icmp6types[icmpv6.type], "Echo Reply")
Jan Geletye6c78ee2018-06-26 12:24:03 +02001219 self.assertEqual(icmpv6.id, icmpv6_id)
1220 self.assertEqual(icmpv6.seq, icmpv6_seq)
1221 self.assertEqual(icmpv6.data, icmpv6_data)
1222
1223
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001224class TestIPv6RD(TestIPv6ND):
1225 """ IPv6 Router Discovery Test Case """
1226
1227 @classmethod
1228 def setUpClass(cls):
1229 super(TestIPv6RD, cls).setUpClass()
1230
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001231 @classmethod
1232 def tearDownClass(cls):
1233 super(TestIPv6RD, cls).tearDownClass()
1234
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001235 def setUp(self):
1236 super(TestIPv6RD, self).setUp()
1237
1238 # create 2 pg interfaces
1239 self.create_pg_interfaces(range(2))
1240
1241 self.interfaces = list(self.pg_interfaces)
1242
1243 # setup all interfaces
1244 for i in self.interfaces:
1245 i.admin_up()
1246 i.config_ip6()
1247
1248 def tearDown(self):
Neale Ranns744902e2017-08-14 10:35:44 -07001249 for i in self.interfaces:
1250 i.unconfig_ip6()
1251 i.admin_down()
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001252 super(TestIPv6RD, self).tearDown()
1253
1254 def test_rd_send_router_solicitation(self):
1255 """ Verify router solicitation packets """
1256
1257 count = 2
1258 self.pg_enable_capture(self.pg_interfaces)
1259 self.pg_start()
1260 self.vapi.ip6nd_send_router_solicitation(self.pg1.sw_if_index,
1261 mrc=count)
1262 rx_list = self.pg1.get_capture(count, timeout=3)
1263 self.assertEqual(len(rx_list), count)
1264 for packet in rx_list:
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001265 self.assertEqual(packet.haslayer(IPv6), 1)
1266 self.assertEqual(packet[IPv6].haslayer(
1267 ICMPv6ND_RS), 1)
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001268 dst = ip6_normalize(packet[IPv6].dst)
1269 dst2 = ip6_normalize("ff02::2")
1270 self.assert_equal(dst, dst2)
1271 src = ip6_normalize(packet[IPv6].src)
1272 src2 = ip6_normalize(self.pg1.local_ip6_ll)
1273 self.assert_equal(src, src2)
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001274 self.assertTrue(
1275 bool(packet[ICMPv6ND_RS].haslayer(
1276 ICMPv6NDOptSrcLLAddr)))
1277 self.assert_equal(
1278 packet[ICMPv6NDOptSrcLLAddr].lladdr,
1279 self.pg1.local_mac)
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001280
1281 def verify_prefix_info(self, reported_prefix, prefix_option):
Neale Ranns37029302018-08-10 05:30:06 -07001282 prefix = IPv6Network(
Paul Vinciguerra1e18eb22018-11-25 16:09:26 -08001283 text_type(prefix_option.getfieldval("prefix") +
1284 "/" +
1285 text_type(prefix_option.getfieldval("prefixlen"))),
Neale Ranns37029302018-08-10 05:30:06 -07001286 strict=False)
1287 self.assert_equal(reported_prefix.prefix.network_address,
1288 prefix.network_address)
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001289 L = prefix_option.getfieldval("L")
1290 A = prefix_option.getfieldval("A")
1291 option_flags = (L << 7) | (A << 6)
1292 self.assert_equal(reported_prefix.flags, option_flags)
1293 self.assert_equal(reported_prefix.valid_time,
1294 prefix_option.getfieldval("validlifetime"))
1295 self.assert_equal(reported_prefix.preferred_time,
1296 prefix_option.getfieldval("preferredlifetime"))
1297
1298 def test_rd_receive_router_advertisement(self):
1299 """ Verify events triggered by received RA packets """
1300
Neale Rannscbe25aa2019-09-30 10:53:31 +00001301 self.vapi.want_ip6_ra_events(enable=1)
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001302
1303 prefix_info_1 = ICMPv6NDOptPrefixInfo(
1304 prefix="1::2",
1305 prefixlen=50,
1306 validlifetime=200,
1307 preferredlifetime=500,
1308 L=1,
1309 A=1,
1310 )
1311
1312 prefix_info_2 = ICMPv6NDOptPrefixInfo(
1313 prefix="7::4",
1314 prefixlen=20,
1315 validlifetime=70,
1316 preferredlifetime=1000,
1317 L=1,
1318 A=0,
1319 )
1320
1321 p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
1322 IPv6(dst=self.pg1.local_ip6_ll,
1323 src=mk_ll_addr(self.pg1.remote_mac)) /
1324 ICMPv6ND_RA() /
1325 prefix_info_1 /
1326 prefix_info_2)
1327 self.pg1.add_stream([p])
1328 self.pg_start()
1329
1330 ev = self.vapi.wait_for_event(10, "ip6_ra_event")
1331
1332 self.assert_equal(ev.current_hop_limit, 0)
1333 self.assert_equal(ev.flags, 8)
1334 self.assert_equal(ev.router_lifetime_in_sec, 1800)
1335 self.assert_equal(ev.neighbor_reachable_time_in_msec, 0)
1336 self.assert_equal(
1337 ev.time_in_msec_between_retransmitted_neighbor_solicitations, 0)
1338
1339 self.assert_equal(ev.n_prefixes, 2)
1340
1341 self.verify_prefix_info(ev.prefixes[0], prefix_info_1)
1342 self.verify_prefix_info(ev.prefixes[1], prefix_info_2)
1343
1344
Juraj Slobodac0374232018-02-01 15:18:49 +01001345class TestIPv6RDControlPlane(TestIPv6ND):
1346 """ IPv6 Router Discovery Control Plane Test Case """
1347
1348 @classmethod
1349 def setUpClass(cls):
1350 super(TestIPv6RDControlPlane, cls).setUpClass()
1351
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001352 @classmethod
1353 def tearDownClass(cls):
1354 super(TestIPv6RDControlPlane, cls).tearDownClass()
1355
Juraj Slobodac0374232018-02-01 15:18:49 +01001356 def setUp(self):
1357 super(TestIPv6RDControlPlane, self).setUp()
1358
1359 # create 1 pg interface
1360 self.create_pg_interfaces(range(1))
1361
1362 self.interfaces = list(self.pg_interfaces)
1363
1364 # setup all interfaces
1365 for i in self.interfaces:
1366 i.admin_up()
1367 i.config_ip6()
1368
1369 def tearDown(self):
1370 super(TestIPv6RDControlPlane, self).tearDown()
1371
1372 @staticmethod
1373 def create_ra_packet(pg, routerlifetime=None):
1374 src_ip = pg.remote_ip6_ll
1375 dst_ip = pg.local_ip6
1376 if routerlifetime is not None:
1377 ra = ICMPv6ND_RA(routerlifetime=routerlifetime)
1378 else:
1379 ra = ICMPv6ND_RA()
1380 p = (Ether(dst=pg.local_mac, src=pg.remote_mac) /
1381 IPv6(dst=dst_ip, src=src_ip) / ra)
1382 return p
1383
1384 @staticmethod
1385 def get_default_routes(fib):
1386 list = []
1387 for entry in fib:
Neale Ranns097fa662018-05-01 05:17:55 -07001388 if entry.route.prefix.prefixlen == 0:
1389 for path in entry.route.paths:
Juraj Slobodac0374232018-02-01 15:18:49 +01001390 if path.sw_if_index != 0xFFFFFFFF:
Neale Ranns097fa662018-05-01 05:17:55 -07001391 defaut_route = {}
1392 defaut_route['sw_if_index'] = path.sw_if_index
1393 defaut_route['next_hop'] = path.nh.address.ip6
1394 list.append(defaut_route)
Juraj Slobodac0374232018-02-01 15:18:49 +01001395 return list
1396
1397 @staticmethod
1398 def get_interface_addresses(fib, pg):
1399 list = []
1400 for entry in fib:
Neale Ranns097fa662018-05-01 05:17:55 -07001401 if entry.route.prefix.prefixlen == 128:
1402 path = entry.route.paths[0]
Juraj Slobodac0374232018-02-01 15:18:49 +01001403 if path.sw_if_index == pg.sw_if_index:
Neale Ranns097fa662018-05-01 05:17:55 -07001404 list.append(str(entry.route.prefix.network_address))
Juraj Slobodac0374232018-02-01 15:18:49 +01001405 return list
1406
Neale Rannscbe25aa2019-09-30 10:53:31 +00001407 def wait_for_no_default_route(self, n_tries=50, s_time=1):
1408 while (n_tries):
1409 fib = self.vapi.ip_route_dump(0, True)
1410 default_routes = self.get_default_routes(fib)
Ole Troan6e6ad642020-02-04 13:28:13 +01001411 if 0 == len(default_routes):
Neale Rannscbe25aa2019-09-30 10:53:31 +00001412 return True
1413 n_tries = n_tries - 1
1414 self.sleep(s_time)
1415
1416 return False
1417
Juraj Slobodac0374232018-02-01 15:18:49 +01001418 def test_all(self):
1419 """ Test handling of SLAAC addresses and default routes """
1420
Neale Ranns097fa662018-05-01 05:17:55 -07001421 fib = self.vapi.ip_route_dump(0, True)
Juraj Slobodac0374232018-02-01 15:18:49 +01001422 default_routes = self.get_default_routes(fib)
1423 initial_addresses = set(self.get_interface_addresses(fib, self.pg0))
1424 self.assertEqual(default_routes, [])
Neale Ranns097fa662018-05-01 05:17:55 -07001425 router_address = IPv6Address(text_type(self.pg0.remote_ip6_ll))
Juraj Slobodac0374232018-02-01 15:18:49 +01001426
1427 self.vapi.ip6_nd_address_autoconfig(self.pg0.sw_if_index, 1, 1)
1428
1429 self.sleep(0.1)
1430
1431 # send RA
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001432 packet = (self.create_ra_packet(
1433 self.pg0) / ICMPv6NDOptPrefixInfo(
Juraj Slobodac0374232018-02-01 15:18:49 +01001434 prefix="1::",
1435 prefixlen=64,
1436 validlifetime=2,
1437 preferredlifetime=2,
1438 L=1,
1439 A=1,
1440 ) / ICMPv6NDOptPrefixInfo(
1441 prefix="7::",
1442 prefixlen=20,
1443 validlifetime=1500,
1444 preferredlifetime=1000,
1445 L=1,
1446 A=0,
1447 ))
1448 self.pg0.add_stream([packet])
1449 self.pg_start()
1450
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +00001451 self.sleep_on_vpp_time(0.1)
Juraj Slobodac0374232018-02-01 15:18:49 +01001452
Neale Ranns097fa662018-05-01 05:17:55 -07001453 fib = self.vapi.ip_route_dump(0, True)
Juraj Slobodac0374232018-02-01 15:18:49 +01001454
1455 # check FIB for new address
1456 addresses = set(self.get_interface_addresses(fib, self.pg0))
1457 new_addresses = addresses.difference(initial_addresses)
1458 self.assertEqual(len(new_addresses), 1)
Neale Ranns097fa662018-05-01 05:17:55 -07001459 prefix = IPv6Network(text_type("%s/%d" % (list(new_addresses)[0], 20)),
1460 strict=False)
1461 self.assertEqual(prefix, IPv6Network(text_type('1::/20')))
Juraj Slobodac0374232018-02-01 15:18:49 +01001462
1463 # check FIB for new default route
1464 default_routes = self.get_default_routes(fib)
1465 self.assertEqual(len(default_routes), 1)
1466 dr = default_routes[0]
1467 self.assertEqual(dr['sw_if_index'], self.pg0.sw_if_index)
1468 self.assertEqual(dr['next_hop'], router_address)
1469
1470 # send RA to delete default route
1471 packet = self.create_ra_packet(self.pg0, routerlifetime=0)
1472 self.pg0.add_stream([packet])
1473 self.pg_start()
1474
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +00001475 self.sleep_on_vpp_time(0.1)
Juraj Slobodac0374232018-02-01 15:18:49 +01001476
1477 # check that default route is deleted
Neale Ranns097fa662018-05-01 05:17:55 -07001478 fib = self.vapi.ip_route_dump(0, True)
Juraj Slobodac0374232018-02-01 15:18:49 +01001479 default_routes = self.get_default_routes(fib)
1480 self.assertEqual(len(default_routes), 0)
1481
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +00001482 self.sleep_on_vpp_time(0.1)
Juraj Slobodac0374232018-02-01 15:18:49 +01001483
1484 # send RA
1485 packet = self.create_ra_packet(self.pg0)
1486 self.pg0.add_stream([packet])
1487 self.pg_start()
1488
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +00001489 self.sleep_on_vpp_time(0.1)
Juraj Slobodac0374232018-02-01 15:18:49 +01001490
1491 # check FIB for new default route
Neale Ranns097fa662018-05-01 05:17:55 -07001492 fib = self.vapi.ip_route_dump(0, True)
Juraj Slobodac0374232018-02-01 15:18:49 +01001493 default_routes = self.get_default_routes(fib)
1494 self.assertEqual(len(default_routes), 1)
1495 dr = default_routes[0]
1496 self.assertEqual(dr['sw_if_index'], self.pg0.sw_if_index)
1497 self.assertEqual(dr['next_hop'], router_address)
1498
1499 # send RA, updating router lifetime to 1s
1500 packet = self.create_ra_packet(self.pg0, 1)
1501 self.pg0.add_stream([packet])
1502 self.pg_start()
1503
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +00001504 self.sleep_on_vpp_time(0.1)
Juraj Slobodac0374232018-02-01 15:18:49 +01001505
1506 # check that default route still exists
Neale Ranns097fa662018-05-01 05:17:55 -07001507 fib = self.vapi.ip_route_dump(0, True)
Juraj Slobodac0374232018-02-01 15:18:49 +01001508 default_routes = self.get_default_routes(fib)
1509 self.assertEqual(len(default_routes), 1)
1510 dr = default_routes[0]
1511 self.assertEqual(dr['sw_if_index'], self.pg0.sw_if_index)
1512 self.assertEqual(dr['next_hop'], router_address)
1513
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +00001514 self.sleep_on_vpp_time(1)
Juraj Slobodac0374232018-02-01 15:18:49 +01001515
1516 # check that default route is deleted
Neale Rannscbe25aa2019-09-30 10:53:31 +00001517 self.assertTrue(self.wait_for_no_default_route())
Juraj Slobodac0374232018-02-01 15:18:49 +01001518
1519 # check FIB still contains the SLAAC address
1520 addresses = set(self.get_interface_addresses(fib, self.pg0))
1521 new_addresses = addresses.difference(initial_addresses)
Paul Vinciguerra4271c972019-05-14 13:25:49 -04001522
Juraj Slobodac0374232018-02-01 15:18:49 +01001523 self.assertEqual(len(new_addresses), 1)
Neale Ranns097fa662018-05-01 05:17:55 -07001524 prefix = IPv6Network(text_type("%s/%d" % (list(new_addresses)[0], 20)),
1525 strict=False)
1526 self.assertEqual(prefix, IPv6Network(text_type('1::/20')))
Juraj Slobodac0374232018-02-01 15:18:49 +01001527
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +00001528 self.sleep_on_vpp_time(1)
Juraj Slobodac0374232018-02-01 15:18:49 +01001529
1530 # check that SLAAC address is deleted
Neale Ranns097fa662018-05-01 05:17:55 -07001531 fib = self.vapi.ip_route_dump(0, True)
Juraj Slobodac0374232018-02-01 15:18:49 +01001532 addresses = set(self.get_interface_addresses(fib, self.pg0))
1533 new_addresses = addresses.difference(initial_addresses)
1534 self.assertEqual(len(new_addresses), 0)
1535
1536
Neale Ranns3f844d02017-02-18 00:03:54 -08001537class IPv6NDProxyTest(TestIPv6ND):
1538 """ IPv6 ND ProxyTest Case """
1539
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001540 @classmethod
1541 def setUpClass(cls):
1542 super(IPv6NDProxyTest, cls).setUpClass()
1543
1544 @classmethod
1545 def tearDownClass(cls):
1546 super(IPv6NDProxyTest, cls).tearDownClass()
1547
Neale Ranns3f844d02017-02-18 00:03:54 -08001548 def setUp(self):
1549 super(IPv6NDProxyTest, self).setUp()
1550
1551 # create 3 pg interfaces
1552 self.create_pg_interfaces(range(3))
1553
1554 # pg0 is the master interface, with the configured subnet
1555 self.pg0.admin_up()
1556 self.pg0.config_ip6()
1557 self.pg0.resolve_ndp()
1558
1559 self.pg1.ip6_enable()
1560 self.pg2.ip6_enable()
1561
1562 def tearDown(self):
1563 super(IPv6NDProxyTest, self).tearDown()
1564
1565 def test_nd_proxy(self):
1566 """ IPv6 Proxy ND """
1567
1568 #
1569 # Generate some hosts in the subnet that we are proxying
1570 #
1571 self.pg0.generate_remote_hosts(8)
1572
1573 nsma = in6_getnsma(inet_pton(AF_INET6, self.pg0.local_ip6))
1574 d = inet_ntop(AF_INET6, nsma)
1575
1576 #
1577 # Send an NS for one of those remote hosts on one of the proxy links
1578 # expect no response since it's from an address that is not
1579 # on the link that has the prefix configured
1580 #
1581 ns_pg1 = (Ether(dst=in6_getnsmac(nsma), src=self.pg1.remote_mac) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001582 IPv6(dst=d,
1583 src=self.pg0._remote_hosts[2].ip6) /
Neale Ranns3f844d02017-02-18 00:03:54 -08001584 ICMPv6ND_NS(tgt=self.pg0.local_ip6) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001585 ICMPv6NDOptSrcLLAddr(
1586 lladdr=self.pg0._remote_hosts[2].mac))
Neale Ranns3f844d02017-02-18 00:03:54 -08001587
1588 self.send_and_assert_no_replies(self.pg1, ns_pg1, "Off link NS")
1589
1590 #
1591 # Add proxy support for the host
1592 #
Ole Troane1ade682019-03-04 23:55:43 +01001593 self.vapi.ip6nd_proxy_add_del(
Neale Rannscbe25aa2019-09-30 10:53:31 +00001594 is_add=1, ip=inet_pton(AF_INET6, self.pg0._remote_hosts[2].ip6),
Ole Troan9a475372019-03-05 16:58:24 +01001595 sw_if_index=self.pg1.sw_if_index)
Neale Ranns3f844d02017-02-18 00:03:54 -08001596
1597 #
1598 # try that NS again. this time we expect an NA back
1599 #
Neale Ranns2a3ea492017-04-19 05:24:40 -07001600 self.send_and_expect_na(self.pg1, ns_pg1,
1601 "NS to proxy entry",
1602 dst_ip=self.pg0._remote_hosts[2].ip6,
1603 tgt_ip=self.pg0.local_ip6)
Neale Ranns3f844d02017-02-18 00:03:54 -08001604
1605 #
1606 # ... and that we have an entry in the ND cache
1607 #
1608 self.assertTrue(find_nbr(self,
1609 self.pg1.sw_if_index,
Neale Ranns37029302018-08-10 05:30:06 -07001610 self.pg0._remote_hosts[2].ip6))
Neale Ranns3f844d02017-02-18 00:03:54 -08001611
1612 #
1613 # ... and we can route traffic to it
1614 #
1615 t = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
1616 IPv6(dst=self.pg0._remote_hosts[2].ip6,
1617 src=self.pg0.remote_ip6) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001618 inet6.UDP(sport=10000, dport=20000) /
Ole Troan770a0de2019-11-07 13:52:21 +01001619 Raw(b'\xa5' * 100))
Neale Ranns3f844d02017-02-18 00:03:54 -08001620
1621 self.pg0.add_stream(t)
1622 self.pg_enable_capture(self.pg_interfaces)
1623 self.pg_start()
1624 rx = self.pg1.get_capture(1)
1625 rx = rx[0]
1626
1627 self.assertEqual(rx[Ether].dst, self.pg0._remote_hosts[2].mac)
1628 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1629
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001630 self.assertEqual(rx[IPv6].src,
1631 t[IPv6].src)
1632 self.assertEqual(rx[IPv6].dst,
1633 t[IPv6].dst)
Neale Ranns3f844d02017-02-18 00:03:54 -08001634
1635 #
1636 # Test we proxy for the host on the main interface
1637 #
1638 ns_pg0 = (Ether(dst=in6_getnsmac(nsma), src=self.pg0.remote_mac) /
1639 IPv6(dst=d, src=self.pg0.remote_ip6) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001640 ICMPv6ND_NS(
1641 tgt=self.pg0._remote_hosts[2].ip6) /
1642 ICMPv6NDOptSrcLLAddr(
1643 lladdr=self.pg0.remote_mac))
Neale Ranns3f844d02017-02-18 00:03:54 -08001644
Neale Ranns2a3ea492017-04-19 05:24:40 -07001645 self.send_and_expect_na(self.pg0, ns_pg0,
1646 "NS to proxy entry on main",
1647 tgt_ip=self.pg0._remote_hosts[2].ip6,
1648 dst_ip=self.pg0.remote_ip6)
Neale Ranns3f844d02017-02-18 00:03:54 -08001649
1650 #
1651 # Setup and resolve proxy for another host on another interface
1652 #
1653 ns_pg2 = (Ether(dst=in6_getnsmac(nsma), src=self.pg2.remote_mac) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001654 IPv6(dst=d,
1655 src=self.pg0._remote_hosts[3].ip6) /
Neale Ranns3f844d02017-02-18 00:03:54 -08001656 ICMPv6ND_NS(tgt=self.pg0.local_ip6) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001657 ICMPv6NDOptSrcLLAddr(
1658 lladdr=self.pg0._remote_hosts[2].mac))
Neale Ranns3f844d02017-02-18 00:03:54 -08001659
Ole Troane1ade682019-03-04 23:55:43 +01001660 self.vapi.ip6nd_proxy_add_del(
Neale Rannscbe25aa2019-09-30 10:53:31 +00001661 is_add=1, ip=inet_pton(AF_INET6, self.pg0._remote_hosts[3].ip6),
Ole Troan9a475372019-03-05 16:58:24 +01001662 sw_if_index=self.pg2.sw_if_index)
Neale Ranns3f844d02017-02-18 00:03:54 -08001663
Neale Ranns2a3ea492017-04-19 05:24:40 -07001664 self.send_and_expect_na(self.pg2, ns_pg2,
1665 "NS to proxy entry other interface",
1666 dst_ip=self.pg0._remote_hosts[3].ip6,
1667 tgt_ip=self.pg0.local_ip6)
Neale Ranns3f844d02017-02-18 00:03:54 -08001668
1669 self.assertTrue(find_nbr(self,
1670 self.pg2.sw_if_index,
Neale Ranns37029302018-08-10 05:30:06 -07001671 self.pg0._remote_hosts[3].ip6))
Neale Ranns3f844d02017-02-18 00:03:54 -08001672
1673 #
1674 # hosts can communicate. pg2->pg1
1675 #
1676 t2 = (Ether(dst=self.pg2.local_mac,
1677 src=self.pg0.remote_hosts[3].mac) /
1678 IPv6(dst=self.pg0._remote_hosts[2].ip6,
1679 src=self.pg0._remote_hosts[3].ip6) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001680 inet6.UDP(sport=10000, dport=20000) /
Ole Troan770a0de2019-11-07 13:52:21 +01001681 Raw(b'\xa5' * 100))
Neale Ranns3f844d02017-02-18 00:03:54 -08001682
1683 self.pg2.add_stream(t2)
1684 self.pg_enable_capture(self.pg_interfaces)
1685 self.pg_start()
1686 rx = self.pg1.get_capture(1)
1687 rx = rx[0]
1688
1689 self.assertEqual(rx[Ether].dst, self.pg0._remote_hosts[2].mac)
1690 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1691
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001692 self.assertEqual(rx[IPv6].src,
1693 t2[IPv6].src)
1694 self.assertEqual(rx[IPv6].dst,
1695 t2[IPv6].dst)
Neale Ranns3f844d02017-02-18 00:03:54 -08001696
1697 #
1698 # remove the proxy configs
1699 #
Ole Troane1ade682019-03-04 23:55:43 +01001700 self.vapi.ip6nd_proxy_add_del(
Ole Troan9a475372019-03-05 16:58:24 +01001701 ip=inet_pton(AF_INET6, self.pg0._remote_hosts[2].ip6),
Neale Rannscbe25aa2019-09-30 10:53:31 +00001702 sw_if_index=self.pg1.sw_if_index, is_add=0)
Ole Troane1ade682019-03-04 23:55:43 +01001703 self.vapi.ip6nd_proxy_add_del(
Ole Troan9a475372019-03-05 16:58:24 +01001704 ip=inet_pton(AF_INET6, self.pg0._remote_hosts[3].ip6),
Neale Rannscbe25aa2019-09-30 10:53:31 +00001705 sw_if_index=self.pg2.sw_if_index, is_add=0)
Neale Ranns3f844d02017-02-18 00:03:54 -08001706
1707 self.assertFalse(find_nbr(self,
1708 self.pg2.sw_if_index,
Neale Ranns37029302018-08-10 05:30:06 -07001709 self.pg0._remote_hosts[3].ip6))
Neale Ranns3f844d02017-02-18 00:03:54 -08001710 self.assertFalse(find_nbr(self,
1711 self.pg1.sw_if_index,
Neale Ranns37029302018-08-10 05:30:06 -07001712 self.pg0._remote_hosts[2].ip6))
Neale Ranns3f844d02017-02-18 00:03:54 -08001713
1714 #
1715 # no longer proxy-ing...
1716 #
1717 self.send_and_assert_no_replies(self.pg0, ns_pg0, "Proxy unconfigured")
1718 self.send_and_assert_no_replies(self.pg1, ns_pg1, "Proxy unconfigured")
1719 self.send_and_assert_no_replies(self.pg2, ns_pg2, "Proxy unconfigured")
1720
1721 #
1722 # no longer forwarding. traffic generates NS out of the glean/main
1723 # interface
1724 #
1725 self.pg2.add_stream(t2)
1726 self.pg_enable_capture(self.pg_interfaces)
1727 self.pg_start()
1728
1729 rx = self.pg0.get_capture(1)
1730
1731 self.assertTrue(rx[0].haslayer(ICMPv6ND_NS))
1732
1733
Neale Ranns37be7362017-02-21 17:30:26 -08001734class TestIPNull(VppTestCase):
1735 """ IPv6 routes via NULL """
1736
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001737 @classmethod
1738 def setUpClass(cls):
1739 super(TestIPNull, cls).setUpClass()
1740
1741 @classmethod
1742 def tearDownClass(cls):
1743 super(TestIPNull, cls).tearDownClass()
1744
Neale Ranns37be7362017-02-21 17:30:26 -08001745 def setUp(self):
1746 super(TestIPNull, self).setUp()
1747
1748 # create 2 pg interfaces
1749 self.create_pg_interfaces(range(1))
1750
1751 for i in self.pg_interfaces:
1752 i.admin_up()
1753 i.config_ip6()
1754 i.resolve_ndp()
1755
1756 def tearDown(self):
1757 super(TestIPNull, self).tearDown()
1758 for i in self.pg_interfaces:
1759 i.unconfig_ip6()
1760 i.admin_down()
1761
1762 def test_ip_null(self):
1763 """ IP NULL route """
1764
1765 p = (Ether(src=self.pg0.remote_mac,
1766 dst=self.pg0.local_mac) /
1767 IPv6(src=self.pg0.remote_ip6, dst="2001::1") /
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001768 inet6.UDP(sport=1234, dport=1234) /
Ole Troan770a0de2019-11-07 13:52:21 +01001769 Raw(b'\xa5' * 100))
Neale Ranns37be7362017-02-21 17:30:26 -08001770
1771 #
1772 # A route via IP NULL that will reply with ICMP unreachables
1773 #
Neale Ranns097fa662018-05-01 05:17:55 -07001774 ip_unreach = VppIpRoute(
1775 self, "2001::", 64,
1776 [VppRoutePath("::", 0xffffffff,
1777 type=FibPathType.FIB_PATH_TYPE_ICMP_UNREACH)])
Neale Ranns37be7362017-02-21 17:30:26 -08001778 ip_unreach.add_vpp_config()
1779
1780 self.pg0.add_stream(p)
1781 self.pg_enable_capture(self.pg_interfaces)
1782 self.pg_start()
1783
1784 rx = self.pg0.get_capture(1)
1785 rx = rx[0]
1786 icmp = rx[ICMPv6DestUnreach]
1787
1788 # 0 = "No route to destination"
1789 self.assertEqual(icmp.code, 0)
1790
1791 # ICMP is rate limited. pause a bit
1792 self.sleep(1)
1793
1794 #
1795 # A route via IP NULL that will reply with ICMP prohibited
1796 #
Neale Ranns097fa662018-05-01 05:17:55 -07001797 ip_prohibit = VppIpRoute(
1798 self, "2001::1", 128,
1799 [VppRoutePath("::", 0xffffffff,
1800 type=FibPathType.FIB_PATH_TYPE_ICMP_PROHIBIT)])
Neale Ranns37be7362017-02-21 17:30:26 -08001801 ip_prohibit.add_vpp_config()
1802
1803 self.pg0.add_stream(p)
1804 self.pg_enable_capture(self.pg_interfaces)
1805 self.pg_start()
1806
1807 rx = self.pg0.get_capture(1)
1808 rx = rx[0]
1809 icmp = rx[ICMPv6DestUnreach]
1810
1811 # 1 = "Communication with destination administratively prohibited"
1812 self.assertEqual(icmp.code, 1)
1813
1814
Neale Ranns180279b2017-03-16 15:49:09 -04001815class TestIPDisabled(VppTestCase):
1816 """ IPv6 disabled """
1817
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001818 @classmethod
1819 def setUpClass(cls):
1820 super(TestIPDisabled, cls).setUpClass()
1821
1822 @classmethod
1823 def tearDownClass(cls):
1824 super(TestIPDisabled, cls).tearDownClass()
1825
Neale Ranns180279b2017-03-16 15:49:09 -04001826 def setUp(self):
1827 super(TestIPDisabled, self).setUp()
1828
1829 # create 2 pg interfaces
1830 self.create_pg_interfaces(range(2))
1831
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07001832 # PG0 is IP enabled
Neale Ranns180279b2017-03-16 15:49:09 -04001833 self.pg0.admin_up()
1834 self.pg0.config_ip6()
1835 self.pg0.resolve_ndp()
1836
1837 # PG 1 is not IP enabled
1838 self.pg1.admin_up()
1839
1840 def tearDown(self):
1841 super(TestIPDisabled, self).tearDown()
1842 for i in self.pg_interfaces:
1843 i.unconfig_ip4()
1844 i.admin_down()
1845
Neale Ranns180279b2017-03-16 15:49:09 -04001846 def test_ip_disabled(self):
1847 """ IP Disabled """
1848
Neale Ranns990f6942020-10-20 07:20:17 +00001849 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
1850 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
Neale Ranns180279b2017-03-16 15:49:09 -04001851 #
1852 # An (S,G).
1853 # one accepting interface, pg0, 2 forwarding interfaces
1854 #
1855 route_ff_01 = VppIpMRoute(
1856 self,
1857 "::",
1858 "ffef::1", 128,
Neale Ranns990f6942020-10-20 07:20:17 +00001859 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
Neale Ranns180279b2017-03-16 15:49:09 -04001860 [VppMRoutePath(self.pg1.sw_if_index,
Neale Ranns990f6942020-10-20 07:20:17 +00001861 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT),
Neale Ranns180279b2017-03-16 15:49:09 -04001862 VppMRoutePath(self.pg0.sw_if_index,
Neale Ranns990f6942020-10-20 07:20:17 +00001863 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD)])
Neale Ranns180279b2017-03-16 15:49:09 -04001864 route_ff_01.add_vpp_config()
1865
1866 pu = (Ether(src=self.pg1.remote_mac,
1867 dst=self.pg1.local_mac) /
1868 IPv6(src="2001::1", dst=self.pg0.remote_ip6) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001869 inet6.UDP(sport=1234, dport=1234) /
Ole Troan770a0de2019-11-07 13:52:21 +01001870 Raw(b'\xa5' * 100))
Neale Ranns180279b2017-03-16 15:49:09 -04001871 pm = (Ether(src=self.pg1.remote_mac,
1872 dst=self.pg1.local_mac) /
1873 IPv6(src="2001::1", dst="ffef::1") /
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001874 inet6.UDP(sport=1234, dport=1234) /
Ole Troan770a0de2019-11-07 13:52:21 +01001875 Raw(b'\xa5' * 100))
Neale Ranns180279b2017-03-16 15:49:09 -04001876
1877 #
1878 # PG1 does not forward IP traffic
1879 #
1880 self.send_and_assert_no_replies(self.pg1, pu, "IPv6 disabled")
1881 self.send_and_assert_no_replies(self.pg1, pm, "IPv6 disabled")
1882
1883 #
1884 # IP enable PG1
1885 #
1886 self.pg1.config_ip6()
1887
1888 #
1889 # Now we get packets through
1890 #
1891 self.pg1.add_stream(pu)
1892 self.pg_enable_capture(self.pg_interfaces)
1893 self.pg_start()
1894 rx = self.pg0.get_capture(1)
1895
1896 self.pg1.add_stream(pm)
1897 self.pg_enable_capture(self.pg_interfaces)
1898 self.pg_start()
1899 rx = self.pg0.get_capture(1)
1900
1901 #
1902 # Disable PG1
1903 #
1904 self.pg1.unconfig_ip6()
1905
1906 #
1907 # PG1 does not forward IP traffic
1908 #
1909 self.send_and_assert_no_replies(self.pg1, pu, "IPv6 disabled")
1910 self.send_and_assert_no_replies(self.pg1, pm, "IPv6 disabled")
1911
1912
Neale Ranns227038a2017-04-21 01:07:59 -07001913class TestIP6LoadBalance(VppTestCase):
1914 """ IPv6 Load-Balancing """
1915
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001916 @classmethod
1917 def setUpClass(cls):
1918 super(TestIP6LoadBalance, cls).setUpClass()
1919
1920 @classmethod
1921 def tearDownClass(cls):
1922 super(TestIP6LoadBalance, cls).tearDownClass()
1923
Neale Ranns227038a2017-04-21 01:07:59 -07001924 def setUp(self):
1925 super(TestIP6LoadBalance, self).setUp()
1926
1927 self.create_pg_interfaces(range(5))
1928
Neale Ranns15002542017-09-10 04:39:11 -07001929 mpls_tbl = VppMplsTable(self, 0)
1930 mpls_tbl.add_vpp_config()
1931
Neale Ranns227038a2017-04-21 01:07:59 -07001932 for i in self.pg_interfaces:
1933 i.admin_up()
1934 i.config_ip6()
1935 i.resolve_ndp()
Neale Ranns71275e32017-05-25 12:38:58 -07001936 i.enable_mpls()
Neale Ranns227038a2017-04-21 01:07:59 -07001937
1938 def tearDown(self):
Neale Ranns227038a2017-04-21 01:07:59 -07001939 for i in self.pg_interfaces:
1940 i.unconfig_ip6()
1941 i.admin_down()
Neale Ranns71275e32017-05-25 12:38:58 -07001942 i.disable_mpls()
Neale Ranns15002542017-09-10 04:39:11 -07001943 super(TestIP6LoadBalance, self).tearDown()
Neale Ranns227038a2017-04-21 01:07:59 -07001944
Paul Vinciguerraeb414432019-02-20 09:01:14 -08001945 def pg_send(self, input, pkts):
Neale Ranns62fe07c2017-10-31 12:28:22 -07001946 self.vapi.cli("clear trace")
Neale Ranns227038a2017-04-21 01:07:59 -07001947 input.add_stream(pkts)
1948 self.pg_enable_capture(self.pg_interfaces)
1949 self.pg_start()
Paul Vinciguerraeb414432019-02-20 09:01:14 -08001950
1951 def send_and_expect_load_balancing(self, input, pkts, outputs):
1952 self.pg_send(input, pkts)
Neale Ranns227038a2017-04-21 01:07:59 -07001953 for oo in outputs:
1954 rx = oo._get_capture(1)
1955 self.assertNotEqual(0, len(rx))
1956
Neale Ranns71275e32017-05-25 12:38:58 -07001957 def send_and_expect_one_itf(self, input, pkts, itf):
Paul Vinciguerraeb414432019-02-20 09:01:14 -08001958 self.pg_send(input, pkts)
Neale Ranns71275e32017-05-25 12:38:58 -07001959 rx = itf.get_capture(len(pkts))
1960
Neale Ranns227038a2017-04-21 01:07:59 -07001961 def test_ip6_load_balance(self):
1962 """ IPv6 Load-Balancing """
1963
1964 #
1965 # An array of packets that differ only in the destination port
Neale Ranns71275e32017-05-25 12:38:58 -07001966 # - IP only
1967 # - MPLS EOS
1968 # - MPLS non-EOS
1969 # - MPLS non-EOS with an entropy label
Neale Ranns227038a2017-04-21 01:07:59 -07001970 #
Neale Ranns71275e32017-05-25 12:38:58 -07001971 port_ip_pkts = []
1972 port_mpls_pkts = []
1973 port_mpls_neos_pkts = []
1974 port_ent_pkts = []
Neale Ranns227038a2017-04-21 01:07:59 -07001975
1976 #
1977 # An array of packets that differ only in the source address
1978 #
Neale Ranns71275e32017-05-25 12:38:58 -07001979 src_ip_pkts = []
1980 src_mpls_pkts = []
Neale Ranns227038a2017-04-21 01:07:59 -07001981
Paul Vinciguerra4271c972019-05-14 13:25:49 -04001982 for ii in range(NUM_PKTS):
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001983 port_ip_hdr = (
1984 IPv6(dst="3000::1", src="3000:1::1") /
1985 inet6.UDP(sport=1234, dport=1234 + ii) /
Ole Troan770a0de2019-11-07 13:52:21 +01001986 Raw(b'\xa5' * 100))
Neale Ranns71275e32017-05-25 12:38:58 -07001987 port_ip_pkts.append((Ether(src=self.pg0.remote_mac,
1988 dst=self.pg0.local_mac) /
1989 port_ip_hdr))
1990 port_mpls_pkts.append((Ether(src=self.pg0.remote_mac,
1991 dst=self.pg0.local_mac) /
1992 MPLS(label=66, ttl=2) /
1993 port_ip_hdr))
1994 port_mpls_neos_pkts.append((Ether(src=self.pg0.remote_mac,
1995 dst=self.pg0.local_mac) /
1996 MPLS(label=67, ttl=2) /
1997 MPLS(label=77, ttl=2) /
1998 port_ip_hdr))
1999 port_ent_pkts.append((Ether(src=self.pg0.remote_mac,
2000 dst=self.pg0.local_mac) /
2001 MPLS(label=67, ttl=2) /
2002 MPLS(label=14, ttl=2) /
2003 MPLS(label=999, ttl=2) /
2004 port_ip_hdr))
Paul Vinciguerra978aa642018-11-24 22:19:12 -08002005 src_ip_hdr = (
2006 IPv6(dst="3000::1", src="3000:1::%d" % ii) /
2007 inet6.UDP(sport=1234, dport=1234) /
Ole Troan770a0de2019-11-07 13:52:21 +01002008 Raw(b'\xa5' * 100))
Neale Ranns71275e32017-05-25 12:38:58 -07002009 src_ip_pkts.append((Ether(src=self.pg0.remote_mac,
2010 dst=self.pg0.local_mac) /
2011 src_ip_hdr))
2012 src_mpls_pkts.append((Ether(src=self.pg0.remote_mac,
2013 dst=self.pg0.local_mac) /
2014 MPLS(label=66, ttl=2) /
2015 src_ip_hdr))
Neale Ranns227038a2017-04-21 01:07:59 -07002016
Neale Ranns71275e32017-05-25 12:38:58 -07002017 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07002018 # A route for the IP packets
Neale Ranns71275e32017-05-25 12:38:58 -07002019 #
Neale Ranns227038a2017-04-21 01:07:59 -07002020 route_3000_1 = VppIpRoute(self, "3000::1", 128,
2021 [VppRoutePath(self.pg1.remote_ip6,
Neale Ranns097fa662018-05-01 05:17:55 -07002022 self.pg1.sw_if_index),
Neale Ranns227038a2017-04-21 01:07:59 -07002023 VppRoutePath(self.pg2.remote_ip6,
Neale Ranns097fa662018-05-01 05:17:55 -07002024 self.pg2.sw_if_index)])
Neale Ranns227038a2017-04-21 01:07:59 -07002025 route_3000_1.add_vpp_config()
2026
2027 #
Neale Ranns71275e32017-05-25 12:38:58 -07002028 # a local-label for the EOS packets
2029 #
2030 binding = VppMplsIpBind(self, 66, "3000::1", 128, is_ip6=1)
2031 binding.add_vpp_config()
2032
2033 #
2034 # An MPLS route for the non-EOS packets
2035 #
2036 route_67 = VppMplsRoute(self, 67, 0,
2037 [VppRoutePath(self.pg1.remote_ip6,
2038 self.pg1.sw_if_index,
Neale Ranns097fa662018-05-01 05:17:55 -07002039 labels=[67]),
Neale Ranns71275e32017-05-25 12:38:58 -07002040 VppRoutePath(self.pg2.remote_ip6,
2041 self.pg2.sw_if_index,
Neale Ranns097fa662018-05-01 05:17:55 -07002042 labels=[67])])
Neale Ranns71275e32017-05-25 12:38:58 -07002043 route_67.add_vpp_config()
2044
2045 #
Neale Ranns227038a2017-04-21 01:07:59 -07002046 # inject the packet on pg0 - expect load-balancing across the 2 paths
2047 # - since the default hash config is to use IP src,dst and port
2048 # src,dst
2049 # We are not going to ensure equal amounts of packets across each link,
2050 # since the hash algorithm is statistical and therefore this can never
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07002051 # be guaranteed. But with 64 different packets we do expect some
Neale Ranns227038a2017-04-21 01:07:59 -07002052 # balancing. So instead just ensure there is traffic on each link.
2053 #
Neale Ranns71275e32017-05-25 12:38:58 -07002054 self.send_and_expect_load_balancing(self.pg0, port_ip_pkts,
Neale Ranns227038a2017-04-21 01:07:59 -07002055 [self.pg1, self.pg2])
Neale Ranns71275e32017-05-25 12:38:58 -07002056 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts,
Neale Ranns227038a2017-04-21 01:07:59 -07002057 [self.pg1, self.pg2])
Neale Ranns71275e32017-05-25 12:38:58 -07002058 self.send_and_expect_load_balancing(self.pg0, port_mpls_pkts,
2059 [self.pg1, self.pg2])
2060 self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts,
2061 [self.pg1, self.pg2])
2062 self.send_and_expect_load_balancing(self.pg0, port_mpls_neos_pkts,
2063 [self.pg1, self.pg2])
2064
2065 #
2066 # The packets with Entropy label in should not load-balance,
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07002067 # since the Entropy value is fixed.
Neale Ranns71275e32017-05-25 12:38:58 -07002068 #
2069 self.send_and_expect_one_itf(self.pg0, port_ent_pkts, self.pg1)
Neale Ranns227038a2017-04-21 01:07:59 -07002070
2071 #
2072 # change the flow hash config so it's only IP src,dst
2073 # - now only the stream with differing source address will
2074 # load-balance
2075 #
Ole Troana5b2eec2019-03-11 19:23:25 +01002076 self.vapi.set_ip_flow_hash(vrf_id=0, src=1, dst=1, sport=0, dport=0,
2077 is_ipv6=1)
Neale Ranns227038a2017-04-21 01:07:59 -07002078
Neale Ranns71275e32017-05-25 12:38:58 -07002079 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts,
Neale Ranns227038a2017-04-21 01:07:59 -07002080 [self.pg1, self.pg2])
Neale Ranns71275e32017-05-25 12:38:58 -07002081 self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts,
2082 [self.pg1, self.pg2])
2083 self.send_and_expect_one_itf(self.pg0, port_ip_pkts, self.pg2)
Neale Ranns227038a2017-04-21 01:07:59 -07002084
2085 #
2086 # change the flow hash config back to defaults
2087 #
Ole Troana5b2eec2019-03-11 19:23:25 +01002088 self.vapi.set_ip_flow_hash(vrf_id=0, src=1, dst=1, sport=1, dport=1,
2089 is_ipv6=1)
Neale Ranns227038a2017-04-21 01:07:59 -07002090
2091 #
2092 # Recursive prefixes
2093 # - testing that 2 stages of load-balancing occurs and there is no
2094 # polarisation (i.e. only 2 of 4 paths are used)
2095 #
2096 port_pkts = []
2097 src_pkts = []
2098
2099 for ii in range(257):
2100 port_pkts.append((Ether(src=self.pg0.remote_mac,
2101 dst=self.pg0.local_mac) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -08002102 IPv6(dst="4000::1",
2103 src="4000:1::1") /
2104 inet6.UDP(sport=1234,
2105 dport=1234 + ii) /
Ole Troan770a0de2019-11-07 13:52:21 +01002106 Raw(b'\xa5' * 100)))
Neale Ranns227038a2017-04-21 01:07:59 -07002107 src_pkts.append((Ether(src=self.pg0.remote_mac,
2108 dst=self.pg0.local_mac) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -08002109 IPv6(dst="4000::1",
2110 src="4000:1::%d" % ii) /
2111 inet6.UDP(sport=1234, dport=1234) /
Ole Troan770a0de2019-11-07 13:52:21 +01002112 Raw(b'\xa5' * 100)))
Neale Ranns227038a2017-04-21 01:07:59 -07002113
2114 route_3000_2 = VppIpRoute(self, "3000::2", 128,
2115 [VppRoutePath(self.pg3.remote_ip6,
Neale Ranns097fa662018-05-01 05:17:55 -07002116 self.pg3.sw_if_index),
Neale Ranns227038a2017-04-21 01:07:59 -07002117 VppRoutePath(self.pg4.remote_ip6,
Neale Ranns097fa662018-05-01 05:17:55 -07002118 self.pg4.sw_if_index)])
Neale Ranns227038a2017-04-21 01:07:59 -07002119 route_3000_2.add_vpp_config()
2120
2121 route_4000_1 = VppIpRoute(self, "4000::1", 128,
2122 [VppRoutePath("3000::1",
Neale Ranns097fa662018-05-01 05:17:55 -07002123 0xffffffff),
Neale Ranns227038a2017-04-21 01:07:59 -07002124 VppRoutePath("3000::2",
Neale Ranns097fa662018-05-01 05:17:55 -07002125 0xffffffff)])
Neale Ranns227038a2017-04-21 01:07:59 -07002126 route_4000_1.add_vpp_config()
2127
2128 #
2129 # inject the packet on pg0 - expect load-balancing across all 4 paths
2130 #
2131 self.vapi.cli("clear trace")
2132 self.send_and_expect_load_balancing(self.pg0, port_pkts,
2133 [self.pg1, self.pg2,
2134 self.pg3, self.pg4])
2135 self.send_and_expect_load_balancing(self.pg0, src_pkts,
2136 [self.pg1, self.pg2,
2137 self.pg3, self.pg4])
2138
Neale Ranns42e6b092017-07-31 02:56:03 -07002139 #
2140 # Recursive prefixes
2141 # - testing that 2 stages of load-balancing no choices
2142 #
2143 port_pkts = []
2144
2145 for ii in range(257):
2146 port_pkts.append((Ether(src=self.pg0.remote_mac,
2147 dst=self.pg0.local_mac) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -08002148 IPv6(dst="6000::1",
2149 src="6000:1::1") /
2150 inet6.UDP(sport=1234,
2151 dport=1234 + ii) /
Ole Troan770a0de2019-11-07 13:52:21 +01002152 Raw(b'\xa5' * 100)))
Neale Ranns42e6b092017-07-31 02:56:03 -07002153
2154 route_5000_2 = VppIpRoute(self, "5000::2", 128,
2155 [VppRoutePath(self.pg3.remote_ip6,
Neale Ranns097fa662018-05-01 05:17:55 -07002156 self.pg3.sw_if_index)])
Neale Ranns42e6b092017-07-31 02:56:03 -07002157 route_5000_2.add_vpp_config()
2158
2159 route_6000_1 = VppIpRoute(self, "6000::1", 128,
2160 [VppRoutePath("5000::2",
Neale Ranns097fa662018-05-01 05:17:55 -07002161 0xffffffff)])
Neale Ranns42e6b092017-07-31 02:56:03 -07002162 route_6000_1.add_vpp_config()
2163
2164 #
2165 # inject the packet on pg0 - expect load-balancing across all 4 paths
2166 #
2167 self.vapi.cli("clear trace")
2168 self.send_and_expect_one_itf(self.pg0, port_pkts, self.pg3)
2169
Neale Ranns227038a2017-04-21 01:07:59 -07002170
Neale Rannsd91c1db2017-07-31 02:30:50 -07002171class TestIP6Punt(VppTestCase):
2172 """ IPv6 Punt Police/Redirect """
2173
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002174 @classmethod
2175 def setUpClass(cls):
2176 super(TestIP6Punt, cls).setUpClass()
2177
2178 @classmethod
2179 def tearDownClass(cls):
2180 super(TestIP6Punt, cls).tearDownClass()
2181
Neale Rannsd91c1db2017-07-31 02:30:50 -07002182 def setUp(self):
2183 super(TestIP6Punt, self).setUp()
2184
Pavel Kotucek609e1212018-11-27 09:59:44 +01002185 self.create_pg_interfaces(range(4))
Neale Rannsd91c1db2017-07-31 02:30:50 -07002186
2187 for i in self.pg_interfaces:
2188 i.admin_up()
2189 i.config_ip6()
2190 i.resolve_ndp()
2191
2192 def tearDown(self):
2193 super(TestIP6Punt, self).tearDown()
2194 for i in self.pg_interfaces:
2195 i.unconfig_ip6()
2196 i.admin_down()
2197
Neale Rannsd91c1db2017-07-31 02:30:50 -07002198 def test_ip_punt(self):
2199 """ IP6 punt police and redirect """
2200
2201 p = (Ether(src=self.pg0.remote_mac,
2202 dst=self.pg0.local_mac) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -08002203 IPv6(src=self.pg0.remote_ip6,
2204 dst=self.pg0.local_ip6) /
2205 inet6.TCP(sport=1234, dport=1234) /
Ole Troan770a0de2019-11-07 13:52:21 +01002206 Raw(b'\xa5' * 100))
Neale Rannsd91c1db2017-07-31 02:30:50 -07002207
2208 pkts = p * 1025
2209
2210 #
2211 # Configure a punt redirect via pg1.
2212 #
Ole Troan0bcad322018-12-11 13:04:01 +01002213 nh_addr = self.pg1.remote_ip6
Neale Rannsd91c1db2017-07-31 02:30:50 -07002214 self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
2215 self.pg1.sw_if_index,
Pavel Kotucek609e1212018-11-27 09:59:44 +01002216 nh_addr)
Neale Rannsd91c1db2017-07-31 02:30:50 -07002217
2218 self.send_and_expect(self.pg0, pkts, self.pg1)
2219
2220 #
2221 # add a policer
2222 #
Jakub Grajciarcd01fb42020-03-02 13:16:53 +01002223 policer = VppPolicer(self, "ip6-punt", 400, 0, 10, 0, rate_type=1)
2224 policer.add_vpp_config()
Neale Rannsd91c1db2017-07-31 02:30:50 -07002225 self.vapi.ip_punt_police(policer.policer_index, is_ip6=1)
2226
2227 self.vapi.cli("clear trace")
2228 self.pg0.add_stream(pkts)
2229 self.pg_enable_capture(self.pg_interfaces)
2230 self.pg_start()
2231
2232 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07002233 # the number of packet received should be greater than 0,
Neale Rannsd91c1db2017-07-31 02:30:50 -07002234 # but not equal to the number sent, since some were policed
2235 #
2236 rx = self.pg1._get_capture(1)
Paul Vinciguerra3d2df212018-11-24 23:19:53 -08002237 self.assertGreater(len(rx), 0)
2238 self.assertLess(len(rx), len(pkts))
Neale Rannsd91c1db2017-07-31 02:30:50 -07002239
2240 #
Paul Vinciguerraeb414432019-02-20 09:01:14 -08002241 # remove the policer. back to full rx
Neale Rannsd91c1db2017-07-31 02:30:50 -07002242 #
2243 self.vapi.ip_punt_police(policer.policer_index, is_add=0, is_ip6=1)
Jakub Grajciarcd01fb42020-03-02 13:16:53 +01002244 policer.remove_vpp_config()
Neale Rannsd91c1db2017-07-31 02:30:50 -07002245 self.send_and_expect(self.pg0, pkts, self.pg1)
2246
2247 #
2248 # remove the redirect. expect full drop.
2249 #
2250 self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
2251 self.pg1.sw_if_index,
2252 nh_addr,
Pavel Kotucek609e1212018-11-27 09:59:44 +01002253 is_add=0)
Neale Rannsd91c1db2017-07-31 02:30:50 -07002254 self.send_and_assert_no_replies(self.pg0, pkts,
2255 "IP no punt config")
2256
2257 #
2258 # Add a redirect that is not input port selective
2259 #
2260 self.vapi.ip_punt_redirect(0xffffffff,
2261 self.pg1.sw_if_index,
Pavel Kotucek609e1212018-11-27 09:59:44 +01002262 nh_addr)
Neale Rannsd91c1db2017-07-31 02:30:50 -07002263 self.send_and_expect(self.pg0, pkts, self.pg1)
2264
2265 self.vapi.ip_punt_redirect(0xffffffff,
2266 self.pg1.sw_if_index,
2267 nh_addr,
Pavel Kotucek609e1212018-11-27 09:59:44 +01002268 is_add=0)
2269
2270 def test_ip_punt_dump(self):
2271 """ IP6 punt redirect dump"""
2272
2273 #
2274 # Configure a punt redirects
2275 #
Ole Troan0bcad322018-12-11 13:04:01 +01002276 nh_addr = self.pg3.remote_ip6
Pavel Kotucek609e1212018-11-27 09:59:44 +01002277 self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
2278 self.pg3.sw_if_index,
2279 nh_addr)
2280 self.vapi.ip_punt_redirect(self.pg1.sw_if_index,
2281 self.pg3.sw_if_index,
2282 nh_addr)
2283 self.vapi.ip_punt_redirect(self.pg2.sw_if_index,
2284 self.pg3.sw_if_index,
Ole Troan0bcad322018-12-11 13:04:01 +01002285 '0::0')
Pavel Kotucek609e1212018-11-27 09:59:44 +01002286
2287 #
2288 # Dump pg0 punt redirects
2289 #
2290 punts = self.vapi.ip_punt_redirect_dump(self.pg0.sw_if_index,
2291 is_ipv6=1)
2292 for p in punts:
2293 self.assertEqual(p.punt.rx_sw_if_index, self.pg0.sw_if_index)
2294
2295 #
2296 # Dump punt redirects for all interfaces
2297 #
2298 punts = self.vapi.ip_punt_redirect_dump(0xffffffff, is_ipv6=1)
2299 self.assertEqual(len(punts), 3)
2300 for p in punts:
2301 self.assertEqual(p.punt.tx_sw_if_index, self.pg3.sw_if_index)
Ole Troan0bcad322018-12-11 13:04:01 +01002302 self.assertNotEqual(punts[1].punt.nh, self.pg3.remote_ip6)
2303 self.assertEqual(str(punts[2].punt.nh), '::')
Neale Rannsd91c1db2017-07-31 02:30:50 -07002304
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002305
Neale Rannsce9e0b42018-08-01 12:53:17 -07002306class TestIPDeag(VppTestCase):
2307 """ IPv6 Deaggregate Routes """
2308
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002309 @classmethod
2310 def setUpClass(cls):
2311 super(TestIPDeag, cls).setUpClass()
2312
2313 @classmethod
2314 def tearDownClass(cls):
2315 super(TestIPDeag, cls).tearDownClass()
2316
Neale Rannsce9e0b42018-08-01 12:53:17 -07002317 def setUp(self):
2318 super(TestIPDeag, self).setUp()
2319
2320 self.create_pg_interfaces(range(3))
2321
2322 for i in self.pg_interfaces:
2323 i.admin_up()
2324 i.config_ip6()
2325 i.resolve_ndp()
2326
2327 def tearDown(self):
2328 super(TestIPDeag, self).tearDown()
2329 for i in self.pg_interfaces:
2330 i.unconfig_ip6()
2331 i.admin_down()
2332
2333 def test_ip_deag(self):
2334 """ IP Deag Routes """
2335
2336 #
2337 # Create a table to be used for:
2338 # 1 - another destination address lookup
2339 # 2 - a source address lookup
2340 #
2341 table_dst = VppIpTable(self, 1, is_ip6=1)
2342 table_src = VppIpTable(self, 2, is_ip6=1)
2343 table_dst.add_vpp_config()
2344 table_src.add_vpp_config()
2345
2346 #
2347 # Add a route in the default table to point to a deag/
2348 # second lookup in each of these tables
2349 #
2350 route_to_dst = VppIpRoute(self, "1::1", 128,
2351 [VppRoutePath("::",
2352 0xffffffff,
Neale Ranns097fa662018-05-01 05:17:55 -07002353 nh_table_id=1)])
2354 route_to_src = VppIpRoute(
2355 self, "1::2", 128,
2356 [VppRoutePath("::",
2357 0xffffffff,
2358 nh_table_id=2,
2359 type=FibPathType.FIB_PATH_TYPE_SOURCE_LOOKUP)])
2360
Neale Rannsce9e0b42018-08-01 12:53:17 -07002361 route_to_dst.add_vpp_config()
2362 route_to_src.add_vpp_config()
2363
2364 #
2365 # packets to these destination are dropped, since they'll
2366 # hit the respective default routes in the second table
2367 #
2368 p_dst = (Ether(src=self.pg0.remote_mac,
2369 dst=self.pg0.local_mac) /
2370 IPv6(src="5::5", dst="1::1") /
Paul Vinciguerra978aa642018-11-24 22:19:12 -08002371 inet6.TCP(sport=1234, dport=1234) /
Ole Troan770a0de2019-11-07 13:52:21 +01002372 Raw(b'\xa5' * 100))
Neale Rannsce9e0b42018-08-01 12:53:17 -07002373 p_src = (Ether(src=self.pg0.remote_mac,
2374 dst=self.pg0.local_mac) /
2375 IPv6(src="2::2", dst="1::2") /
Paul Vinciguerra978aa642018-11-24 22:19:12 -08002376 inet6.TCP(sport=1234, dport=1234) /
Ole Troan770a0de2019-11-07 13:52:21 +01002377 Raw(b'\xa5' * 100))
Neale Rannsce9e0b42018-08-01 12:53:17 -07002378 pkts_dst = p_dst * 257
2379 pkts_src = p_src * 257
2380
2381 self.send_and_assert_no_replies(self.pg0, pkts_dst,
2382 "IP in dst table")
2383 self.send_and_assert_no_replies(self.pg0, pkts_src,
2384 "IP in src table")
2385
2386 #
2387 # add a route in the dst table to forward via pg1
2388 #
2389 route_in_dst = VppIpRoute(self, "1::1", 128,
2390 [VppRoutePath(self.pg1.remote_ip6,
Neale Ranns097fa662018-05-01 05:17:55 -07002391 self.pg1.sw_if_index)],
Neale Rannsce9e0b42018-08-01 12:53:17 -07002392 table_id=1)
2393 route_in_dst.add_vpp_config()
2394
2395 self.send_and_expect(self.pg0, pkts_dst, self.pg1)
2396
2397 #
2398 # add a route in the src table to forward via pg2
2399 #
2400 route_in_src = VppIpRoute(self, "2::2", 128,
2401 [VppRoutePath(self.pg2.remote_ip6,
Neale Ranns097fa662018-05-01 05:17:55 -07002402 self.pg2.sw_if_index)],
Neale Rannsce9e0b42018-08-01 12:53:17 -07002403 table_id=2)
2404 route_in_src.add_vpp_config()
2405 self.send_and_expect(self.pg0, pkts_src, self.pg2)
2406
2407 #
2408 # loop in the lookup DP
2409 #
2410 route_loop = VppIpRoute(self, "3::3", 128,
2411 [VppRoutePath("::",
Neale Ranns097fa662018-05-01 05:17:55 -07002412 0xffffffff)])
Neale Rannsce9e0b42018-08-01 12:53:17 -07002413 route_loop.add_vpp_config()
2414
2415 p_l = (Ether(src=self.pg0.remote_mac,
2416 dst=self.pg0.local_mac) /
2417 IPv6(src="3::4", dst="3::3") /
Paul Vinciguerra978aa642018-11-24 22:19:12 -08002418 inet6.TCP(sport=1234, dport=1234) /
Ole Troan770a0de2019-11-07 13:52:21 +01002419 Raw(b'\xa5' * 100))
Neale Rannsce9e0b42018-08-01 12:53:17 -07002420
2421 self.send_and_assert_no_replies(self.pg0, p_l * 257,
2422 "IP lookup loop")
2423
2424
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002425class TestIP6Input(VppTestCase):
Neale Rannsae809832018-11-23 09:00:27 -08002426 """ IPv6 Input Exception Test Cases """
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002427
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002428 @classmethod
2429 def setUpClass(cls):
2430 super(TestIP6Input, cls).setUpClass()
2431
2432 @classmethod
2433 def tearDownClass(cls):
2434 super(TestIP6Input, cls).tearDownClass()
2435
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002436 def setUp(self):
2437 super(TestIP6Input, self).setUp()
2438
2439 self.create_pg_interfaces(range(2))
2440
2441 for i in self.pg_interfaces:
2442 i.admin_up()
2443 i.config_ip6()
2444 i.resolve_ndp()
2445
2446 def tearDown(self):
2447 super(TestIP6Input, self).tearDown()
2448 for i in self.pg_interfaces:
2449 i.unconfig_ip6()
2450 i.admin_down()
2451
Neale Rannsae809832018-11-23 09:00:27 -08002452 def test_ip_input_icmp_reply(self):
2453 """ IP6 Input Exception - Return ICMP (3,0) """
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002454 #
Neale Rannsae809832018-11-23 09:00:27 -08002455 # hop limit - ICMP replies
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002456 #
2457 p_version = (Ether(src=self.pg0.remote_mac,
2458 dst=self.pg0.local_mac) /
2459 IPv6(src=self.pg0.remote_ip6,
2460 dst=self.pg1.remote_ip6,
2461 hlim=1) /
Paul Vinciguerra978aa642018-11-24 22:19:12 -08002462 inet6.UDP(sport=1234, dport=1234) /
Ole Troan770a0de2019-11-07 13:52:21 +01002463 Raw(b'\xa5' * 100))
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002464
Paul Vinciguerra4271c972019-05-14 13:25:49 -04002465 rx = self.send_and_expect(self.pg0, p_version * NUM_PKTS, self.pg0)
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002466 rx = rx[0]
2467 icmp = rx[ICMPv6TimeExceeded]
Neale Rannsae809832018-11-23 09:00:27 -08002468
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002469 # 0: "hop limit exceeded in transit",
Neale Rannsae809832018-11-23 09:00:27 -08002470 self.assertEqual((icmp.type, icmp.code), (3, 0))
2471
2472 icmpv6_data = '\x0a' * 18
2473 all_0s = "::"
2474 all_1s = "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"
2475
2476 @parameterized.expand([
2477 # Name, src, dst, l4proto, msg, timeout
2478 ("src='iface', dst='iface'", None, None,
2479 inet6.UDP(sport=1234, dport=1234), "funky version", None),
2480 ("src='All 0's', dst='iface'", all_0s, None,
2481 ICMPv6EchoRequest(id=0xb, seq=5, data=icmpv6_data), None, 0.1),
2482 ("src='iface', dst='All 0's'", None, all_0s,
2483 ICMPv6EchoRequest(id=0xb, seq=5, data=icmpv6_data), None, 0.1),
2484 ("src='All 1's', dst='iface'", all_1s, None,
2485 ICMPv6EchoRequest(id=0xb, seq=5, data=icmpv6_data), None, 0.1),
2486 ("src='iface', dst='All 1's'", None, all_1s,
2487 ICMPv6EchoRequest(id=0xb, seq=5, data=icmpv6_data), None, 0.1),
2488 ("src='All 1's', dst='All 1's'", all_1s, all_1s,
2489 ICMPv6EchoRequest(id=0xb, seq=5, data=icmpv6_data), None, 0.1),
2490
2491 ])
2492 def test_ip_input_no_replies(self, name, src, dst, l4, msg, timeout):
2493
2494 self._testMethodDoc = 'IPv6 Input Exception - %s' % name
2495
2496 p_version = (Ether(src=self.pg0.remote_mac,
2497 dst=self.pg0.local_mac) /
2498 IPv6(src=src or self.pg0.remote_ip6,
2499 dst=dst or self.pg1.remote_ip6,
2500 version=3) /
2501 l4 /
Ole Troan770a0de2019-11-07 13:52:21 +01002502 Raw(b'\xa5' * 100))
Neale Rannsae809832018-11-23 09:00:27 -08002503
Paul Vinciguerra4271c972019-05-14 13:25:49 -04002504 self.send_and_assert_no_replies(self.pg0, p_version * NUM_PKTS,
Neale Rannsae809832018-11-23 09:00:27 -08002505 remark=msg or "",
2506 timeout=timeout)
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002507
Dave Barach90800962019-05-24 13:03:01 -04002508 def test_hop_by_hop(self):
2509 """ Hop-by-hop header test """
2510
2511 p = (Ether(src=self.pg0.remote_mac,
2512 dst=self.pg0.local_mac) /
2513 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
2514 IPv6ExtHdrHopByHop() /
2515 inet6.UDP(sport=1234, dport=1234) /
Ole Troan770a0de2019-11-07 13:52:21 +01002516 Raw(b'\xa5' * 100))
Dave Barach90800962019-05-24 13:03:01 -04002517
2518 self.pg0.add_stream(p)
2519 self.pg_enable_capture(self.pg_interfaces)
2520 self.pg_start()
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002521
Neale Ranns9db6ada2019-11-08 12:42:31 +00002522
2523class TestIPReplace(VppTestCase):
2524 """ IPv6 Table Replace """
2525
2526 @classmethod
2527 def setUpClass(cls):
2528 super(TestIPReplace, cls).setUpClass()
2529
2530 @classmethod
2531 def tearDownClass(cls):
2532 super(TestIPReplace, cls).tearDownClass()
2533
2534 def setUp(self):
2535 super(TestIPReplace, self).setUp()
2536
2537 self.create_pg_interfaces(range(4))
2538
2539 table_id = 1
2540 self.tables = []
2541
2542 for i in self.pg_interfaces:
2543 i.admin_up()
2544 i.config_ip6()
Neale Ranns9db6ada2019-11-08 12:42:31 +00002545 i.generate_remote_hosts(2)
2546 self.tables.append(VppIpTable(self, table_id,
2547 True).add_vpp_config())
2548 table_id += 1
2549
2550 def tearDown(self):
2551 super(TestIPReplace, self).tearDown()
2552 for i in self.pg_interfaces:
2553 i.admin_down()
Neale Rannsec40a7d2020-04-23 07:36:12 +00002554 i.unconfig_ip6()
Neale Ranns9db6ada2019-11-08 12:42:31 +00002555
2556 def test_replace(self):
2557 """ IP Table Replace """
2558
Neale Ranns990f6942020-10-20 07:20:17 +00002559 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
2560 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
Neale Ranns9db6ada2019-11-08 12:42:31 +00002561 N_ROUTES = 20
2562 links = [self.pg0, self.pg1, self.pg2, self.pg3]
2563 routes = [[], [], [], []]
2564
2565 # the sizes of 'empty' tables
2566 for t in self.tables:
2567 self.assertEqual(len(t.dump()), 2)
2568 self.assertEqual(len(t.mdump()), 5)
2569
2570 # load up the tables with some routes
2571 for ii, t in enumerate(self.tables):
2572 for jj in range(1, N_ROUTES):
2573 uni = VppIpRoute(
2574 self, "2001::%d" % jj if jj != 0 else "2001::", 128,
2575 [VppRoutePath(links[ii].remote_hosts[0].ip6,
2576 links[ii].sw_if_index),
2577 VppRoutePath(links[ii].remote_hosts[1].ip6,
2578 links[ii].sw_if_index)],
2579 table_id=t.table_id).add_vpp_config()
2580 multi = VppIpMRoute(
2581 self, "::",
2582 "ff:2001::%d" % jj, 128,
Neale Ranns990f6942020-10-20 07:20:17 +00002583 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
Neale Ranns9db6ada2019-11-08 12:42:31 +00002584 [VppMRoutePath(self.pg0.sw_if_index,
Neale Ranns990f6942020-10-20 07:20:17 +00002585 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT,
Neale Ranns9db6ada2019-11-08 12:42:31 +00002586 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6),
2587 VppMRoutePath(self.pg1.sw_if_index,
Neale Ranns990f6942020-10-20 07:20:17 +00002588 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
Neale Ranns9db6ada2019-11-08 12:42:31 +00002589 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6),
2590 VppMRoutePath(self.pg2.sw_if_index,
Neale Ranns990f6942020-10-20 07:20:17 +00002591 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
Neale Ranns9db6ada2019-11-08 12:42:31 +00002592 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6),
2593 VppMRoutePath(self.pg3.sw_if_index,
Neale Ranns990f6942020-10-20 07:20:17 +00002594 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
Neale Ranns9db6ada2019-11-08 12:42:31 +00002595 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6)],
2596 table_id=t.table_id).add_vpp_config()
2597 routes[ii].append({'uni': uni,
2598 'multi': multi})
2599
2600 #
2601 # replace the tables a few times
2602 #
2603 for kk in range(3):
2604 # replace each table
2605 for t in self.tables:
2606 t.replace_begin()
2607
2608 # all the routes are still there
2609 for ii, t in enumerate(self.tables):
2610 dump = t.dump()
2611 mdump = t.mdump()
2612 for r in routes[ii]:
2613 self.assertTrue(find_route_in_dump(dump, r['uni'], t))
2614 self.assertTrue(find_mroute_in_dump(mdump, r['multi'], t))
2615
2616 # redownload the even numbered routes
2617 for ii, t in enumerate(self.tables):
2618 for jj in range(0, N_ROUTES, 2):
2619 routes[ii][jj]['uni'].add_vpp_config()
2620 routes[ii][jj]['multi'].add_vpp_config()
2621
2622 # signal each table converged
2623 for t in self.tables:
2624 t.replace_end()
2625
2626 # we should find the even routes, but not the odd
2627 for ii, t in enumerate(self.tables):
2628 dump = t.dump()
2629 mdump = t.mdump()
2630 for jj in range(0, N_ROUTES, 2):
2631 self.assertTrue(find_route_in_dump(
2632 dump, routes[ii][jj]['uni'], t))
2633 self.assertTrue(find_mroute_in_dump(
2634 mdump, routes[ii][jj]['multi'], t))
2635 for jj in range(1, N_ROUTES - 1, 2):
2636 self.assertFalse(find_route_in_dump(
2637 dump, routes[ii][jj]['uni'], t))
2638 self.assertFalse(find_mroute_in_dump(
2639 mdump, routes[ii][jj]['multi'], t))
2640
2641 # reload all the routes
2642 for ii, t in enumerate(self.tables):
2643 for r in routes[ii]:
2644 r['uni'].add_vpp_config()
2645 r['multi'].add_vpp_config()
2646
2647 # all the routes are still there
2648 for ii, t in enumerate(self.tables):
2649 dump = t.dump()
2650 mdump = t.mdump()
2651 for r in routes[ii]:
2652 self.assertTrue(find_route_in_dump(dump, r['uni'], t))
2653 self.assertTrue(find_mroute_in_dump(mdump, r['multi'], t))
2654
2655 #
2656 # finally flush the tables for good measure
2657 #
2658 for t in self.tables:
2659 t.flush()
2660 self.assertEqual(len(t.dump()), 2)
2661 self.assertEqual(len(t.mdump()), 5)
2662
2663
Neale Ranns59f71132020-04-08 12:19:38 +00002664class TestIP6Replace(VppTestCase):
2665 """ IPv4 Interface Address Replace """
2666
2667 @classmethod
2668 def setUpClass(cls):
2669 super(TestIP6Replace, cls).setUpClass()
2670
2671 @classmethod
2672 def tearDownClass(cls):
2673 super(TestIP6Replace, cls).tearDownClass()
2674
2675 def setUp(self):
2676 super(TestIP6Replace, self).setUp()
2677
2678 self.create_pg_interfaces(range(4))
2679
2680 for i in self.pg_interfaces:
2681 i.admin_up()
2682
2683 def tearDown(self):
2684 super(TestIP6Replace, self).tearDown()
2685 for i in self.pg_interfaces:
2686 i.admin_down()
2687
2688 def get_n_pfxs(self, intf):
2689 return len(self.vapi.ip_address_dump(intf.sw_if_index, True))
2690
2691 def test_replace(self):
2692 """ IP interface address replace """
2693
2694 intf_pfxs = [[], [], [], []]
2695
2696 # add prefixes to each of the interfaces
2697 for i in range(len(self.pg_interfaces)):
2698 intf = self.pg_interfaces[i]
2699
2700 # 2001:16:x::1/64
2701 addr = "2001:16:%d::1" % intf.sw_if_index
2702 a = VppIpInterfaceAddress(self, intf, addr, 64).add_vpp_config()
2703 intf_pfxs[i].append(a)
2704
2705 # 2001:16:x::2/64 - a different address in the same subnet as above
2706 addr = "2001:16:%d::2" % intf.sw_if_index
2707 a = VppIpInterfaceAddress(self, intf, addr, 64).add_vpp_config()
2708 intf_pfxs[i].append(a)
2709
2710 # 2001:15:x::2/64 - a different address and subnet
2711 addr = "2001:15:%d::2" % intf.sw_if_index
2712 a = VppIpInterfaceAddress(self, intf, addr, 64).add_vpp_config()
2713 intf_pfxs[i].append(a)
2714
2715 # a dump should n_address in it
2716 for intf in self.pg_interfaces:
2717 self.assertEqual(self.get_n_pfxs(intf), 3)
2718
2719 #
2720 # remove all the address thru a replace
2721 #
2722 self.vapi.sw_interface_address_replace_begin()
2723 self.vapi.sw_interface_address_replace_end()
2724 for intf in self.pg_interfaces:
2725 self.assertEqual(self.get_n_pfxs(intf), 0)
2726
2727 #
2728 # add all the interface addresses back
2729 #
2730 for p in intf_pfxs:
2731 for v in p:
2732 v.add_vpp_config()
2733 for intf in self.pg_interfaces:
2734 self.assertEqual(self.get_n_pfxs(intf), 3)
2735
2736 #
2737 # replace again, but this time update/re-add the address on the first
2738 # two interfaces
2739 #
2740 self.vapi.sw_interface_address_replace_begin()
2741
2742 for p in intf_pfxs[:2]:
2743 for v in p:
2744 v.add_vpp_config()
2745
2746 self.vapi.sw_interface_address_replace_end()
2747
2748 # on the first two the address still exist,
2749 # on the other two they do not
2750 for intf in self.pg_interfaces[:2]:
2751 self.assertEqual(self.get_n_pfxs(intf), 3)
2752 for p in intf_pfxs[:2]:
2753 for v in p:
2754 self.assertTrue(v.query_vpp_config())
2755 for intf in self.pg_interfaces[2:]:
2756 self.assertEqual(self.get_n_pfxs(intf), 0)
2757
2758 #
2759 # add all the interface addresses back on the last two
2760 #
2761 for p in intf_pfxs[2:]:
2762 for v in p:
2763 v.add_vpp_config()
2764 for intf in self.pg_interfaces:
2765 self.assertEqual(self.get_n_pfxs(intf), 3)
2766
2767 #
2768 # replace again, this time add different prefixes on all the interfaces
2769 #
2770 self.vapi.sw_interface_address_replace_begin()
2771
2772 pfxs = []
2773 for intf in self.pg_interfaces:
2774 # 2001:18:x::1/64
2775 addr = "2001:18:%d::1" % intf.sw_if_index
2776 pfxs.append(VppIpInterfaceAddress(self, intf, addr,
2777 64).add_vpp_config())
2778
2779 self.vapi.sw_interface_address_replace_end()
2780
2781 # only .18 should exist on each interface
2782 for intf in self.pg_interfaces:
2783 self.assertEqual(self.get_n_pfxs(intf), 1)
2784 for pfx in pfxs:
2785 self.assertTrue(pfx.query_vpp_config())
2786
2787 #
2788 # remove everything
2789 #
2790 self.vapi.sw_interface_address_replace_begin()
2791 self.vapi.sw_interface_address_replace_end()
2792 for intf in self.pg_interfaces:
2793 self.assertEqual(self.get_n_pfxs(intf), 0)
2794
2795 #
2796 # add prefixes to each interface. post-begin add the prefix from
2797 # interface X onto interface Y. this would normally be an error
2798 # since it would generate a 'duplicate address' warning. but in
2799 # this case, since what is newly downloaded is sane, it's ok
2800 #
2801 for intf in self.pg_interfaces:
2802 # 2001:18:x::1/64
2803 addr = "2001:18:%d::1" % intf.sw_if_index
2804 VppIpInterfaceAddress(self, intf, addr, 64).add_vpp_config()
2805
2806 self.vapi.sw_interface_address_replace_begin()
2807
2808 pfxs = []
2809 for intf in self.pg_interfaces:
2810 # 2001:18:x::1/64
2811 addr = "2001:18:%d::1" % (intf.sw_if_index + 1)
2812 pfxs.append(VppIpInterfaceAddress(self, intf,
2813 addr, 64).add_vpp_config())
2814
2815 self.vapi.sw_interface_address_replace_end()
2816
2817 self.logger.info(self.vapi.cli("sh int addr"))
2818
2819 for intf in self.pg_interfaces:
2820 self.assertEqual(self.get_n_pfxs(intf), 1)
2821 for pfx in pfxs:
2822 self.assertTrue(pfx.query_vpp_config())
2823
2824
Neale Rannsec40a7d2020-04-23 07:36:12 +00002825class TestIP6LinkLocal(VppTestCase):
2826 """ IPv6 Link Local """
2827
2828 @classmethod
2829 def setUpClass(cls):
2830 super(TestIP6LinkLocal, cls).setUpClass()
2831
2832 @classmethod
2833 def tearDownClass(cls):
2834 super(TestIP6LinkLocal, cls).tearDownClass()
2835
2836 def setUp(self):
2837 super(TestIP6LinkLocal, self).setUp()
2838
2839 self.create_pg_interfaces(range(2))
2840
2841 for i in self.pg_interfaces:
2842 i.admin_up()
2843
2844 def tearDown(self):
2845 super(TestIP6LinkLocal, self).tearDown()
2846 for i in self.pg_interfaces:
2847 i.admin_down()
2848
2849 def test_ip6_ll(self):
2850 """ IPv6 Link Local """
2851
2852 #
2853 # two APIs to add a link local address.
2854 # 1 - just like any other prefix
2855 # 2 - with the special set LL API
2856 #
2857
2858 #
2859 # First with the API to set a 'normal' prefix
2860 #
2861 ll1 = "fe80:1::1"
2862 ll2 = "fe80:2::2"
2863 ll3 = "fe80:3::3"
2864
2865 VppIpInterfaceAddress(self, self.pg0, ll1, 128).add_vpp_config()
2866
2867 #
2868 # should be able to ping the ll
2869 #
2870 p_echo_request_1 = (Ether(src=self.pg0.remote_mac,
2871 dst=self.pg0.local_mac) /
2872 IPv6(src=ll2,
2873 dst=ll1) /
2874 ICMPv6EchoRequest())
2875
2876 self.send_and_expect(self.pg0, [p_echo_request_1], self.pg0)
2877
2878 #
2879 # change the link-local on pg0
2880 #
2881 v_ll3 = VppIpInterfaceAddress(self, self.pg0,
2882 ll3, 128).add_vpp_config()
2883
2884 p_echo_request_3 = (Ether(src=self.pg0.remote_mac,
2885 dst=self.pg0.local_mac) /
2886 IPv6(src=ll2,
2887 dst=ll3) /
2888 ICMPv6EchoRequest())
2889
2890 self.send_and_expect(self.pg0, [p_echo_request_3], self.pg0)
2891
2892 #
2893 # set a normal v6 prefix on the link
2894 #
2895 self.pg0.config_ip6()
2896
2897 self.send_and_expect(self.pg0, [p_echo_request_3], self.pg0)
2898
2899 # the link-local cannot be removed
2900 with self.vapi.assert_negative_api_retval():
2901 v_ll3.remove_vpp_config()
2902
2903 #
2904 # Use the specific link-local API on pg1
2905 #
2906 VppIp6LinkLocalAddress(self, self.pg1, ll1).add_vpp_config()
2907 self.send_and_expect(self.pg1, [p_echo_request_1], self.pg1)
2908
2909 VppIp6LinkLocalAddress(self, self.pg1, ll3).add_vpp_config()
2910 self.send_and_expect(self.pg1, [p_echo_request_3], self.pg1)
2911
2912
Damjan Marionf56b77a2016-10-03 19:44:57 +02002913if __name__ == '__main__':
Klement Sekeraf62ae122016-10-11 11:47:09 +02002914 unittest.main(testRunner=VppTestRunner)