blob: 25f2c623a0be0c2380903d2dcbadbd90820e1a63 [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 Vinciguerraa6fe4632018-11-25 11:21:50 -08008import scapy.layers.inet6 as inet6
Neale Rannsdfef64b2021-05-20 16:28:12 +00009from scapy.layers.inet import UDP, IP
Paul Vinciguerraa6fe4632018-11-25 11:21:50 -080010from scapy.contrib.mpls import MPLS
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020011from scapy.layers.inet6 import (
12 IPv6,
13 ICMPv6ND_NS,
14 ICMPv6ND_RS,
15 ICMPv6ND_RA,
16 ICMPv6NDOptMTU,
17 ICMPv6NDOptSrcLLAddr,
18 ICMPv6NDOptPrefixInfo,
19 ICMPv6ND_NA,
20 ICMPv6NDOptDstLLAddr,
21 ICMPv6DestUnreach,
22 icmp6types,
23 ICMPv6TimeExceeded,
24 ICMPv6EchoRequest,
25 ICMPv6EchoReply,
26 IPv6ExtHdrHopByHop,
27 ICMPv6MLReport2,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020028)
Neale Rannsdfef64b2021-05-20 16:28:12 +000029from scapy.layers.l2 import Ether, Dot1Q, GRE
Paul Vinciguerraa6fe4632018-11-25 11:21:50 -080030from scapy.packet import Raw
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020031from scapy.utils6 import (
32 in6_getnsma,
33 in6_getnsmac,
34 in6_ptop,
35 in6_islladdr,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020036)
Paul Vinciguerraa6fe4632018-11-25 11:21:50 -080037from six import moves
Klement Sekeraf62ae122016-10-11 11:47:09 +020038
Dave Wallace8800f732023-08-31 00:47:44 -040039from framework import VppTestCase
40from asfframework import VppTestRunner, tag_run_solo
Paul Vinciguerrae8fece82019-02-28 15:34:00 -080041from util import ppp, ip6_normalize, mk_ll_addr
Neale Ranns990f6942020-10-20 07:20:17 +000042from vpp_papi import VppEnum
Dave Wallace8800f732023-08-31 00:47:44 -040043from vpp_ip import VppIpPuntPolicer, VppIpPuntRedirect, VppIpPathMtu
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020044from vpp_ip_route import (
45 VppIpRoute,
46 VppRoutePath,
47 find_route,
48 VppIpMRoute,
49 VppMRoutePath,
50 VppMplsIpBind,
51 VppMplsRoute,
52 VppMplsTable,
53 VppIpTable,
54 FibPathType,
55 FibPathProto,
56 VppIpInterfaceAddress,
57 find_route_in_dump,
58 find_mroute_in_dump,
59 VppIp6LinkLocalAddress,
60 VppIpRouteV2,
61)
Neale Rannsb3b2de72017-03-08 05:17:22 -080062from vpp_neighbor import find_nbr, VppNeighbor
Neale Ranns8f5fef22020-12-21 08:29:34 +000063from vpp_ipip_tun_interface import VppIpIpTunInterface
Paul Vinciguerraa6fe4632018-11-25 11:21:50 -080064from vpp_pg_interface import is_ipv6_misc
65from vpp_sub_interface import VppSubInterface, VppDot1QSubint
Brian Russell5214f3a2021-01-19 16:58:34 +000066from vpp_policer import VppPolicer, PolicerAction
Neale Rannsefd7bc22019-11-11 08:32:34 +000067from ipaddress import IPv6Network, IPv6Address
Neale Rannsdfef64b2021-05-20 16:28:12 +000068from vpp_gre_interface import VppGreInterface
69from vpp_teib import VppTeib
Dmitry Valter34fa0ce2024-03-11 10:38:46 +000070from config import config
Neale Ranns75152282017-01-09 01:00:45 -080071
Juraj Sloboda4b9669d2018-01-15 10:39:21 +010072AF_INET6 = socket.AF_INET6
73
Paul Vinciguerra1e18eb22018-11-25 16:09:26 -080074try:
75 text_type = unicode
76except NameError:
77 text_type = str
78
Paul Vinciguerra4271c972019-05-14 13:25:49 -040079NUM_PKTS = 67
80
Juraj Sloboda4b9669d2018-01-15 10:39:21 +010081
Neale Ranns3f844d02017-02-18 00:03:54 -080082class TestIPv6ND(VppTestCase):
83 def validate_ra(self, intf, rx, dst_ip=None):
84 if not dst_ip:
85 dst_ip = intf.remote_ip6
86
87 # unicasted packets must come to the unicast mac
88 self.assertEqual(rx[Ether].dst, intf.remote_mac)
89
90 # and from the router's MAC
91 self.assertEqual(rx[Ether].src, intf.local_mac)
92
93 # the rx'd RA should be addressed to the sender's source
94 self.assertTrue(rx.haslayer(ICMPv6ND_RA))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020095 self.assertEqual(in6_ptop(rx[IPv6].dst), in6_ptop(dst_ip))
Neale Ranns3f844d02017-02-18 00:03:54 -080096
97 # and come from the router's link local
98 self.assertTrue(in6_islladdr(rx[IPv6].src))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020099 self.assertEqual(in6_ptop(rx[IPv6].src), in6_ptop(mk_ll_addr(intf.local_mac)))
Neale Ranns3f844d02017-02-18 00:03:54 -0800100
101 def validate_na(self, intf, rx, dst_ip=None, tgt_ip=None):
102 if not dst_ip:
103 dst_ip = intf.remote_ip6
104 if not tgt_ip:
105 dst_ip = intf.local_ip6
106
107 # unicasted packets must come to the unicast mac
108 self.assertEqual(rx[Ether].dst, intf.remote_mac)
109
110 # and from the router's MAC
111 self.assertEqual(rx[Ether].src, intf.local_mac)
112
113 # the rx'd NA should be addressed to the sender's source
114 self.assertTrue(rx.haslayer(ICMPv6ND_NA))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200115 self.assertEqual(in6_ptop(rx[IPv6].dst), in6_ptop(dst_ip))
Neale Ranns3f844d02017-02-18 00:03:54 -0800116
117 # and come from the target address
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200118 self.assertEqual(in6_ptop(rx[IPv6].src), in6_ptop(tgt_ip))
Neale Ranns3f844d02017-02-18 00:03:54 -0800119
120 # Dest link-layer options should have the router's MAC
121 dll = rx[ICMPv6NDOptDstLLAddr]
122 self.assertEqual(dll.lladdr, intf.local_mac)
123
Neale Rannsdcd6d622017-05-26 02:59:16 -0700124 def validate_ns(self, intf, rx, tgt_ip):
125 nsma = in6_getnsma(inet_pton(AF_INET6, tgt_ip))
126 dst_ip = inet_ntop(AF_INET6, nsma)
127
128 # NS is broadcast
Neale Rannsc7b8f202018-04-25 06:34:31 -0700129 self.assertEqual(rx[Ether].dst, in6_getnsmac(nsma))
Neale Rannsdcd6d622017-05-26 02:59:16 -0700130
131 # and from the router's MAC
132 self.assertEqual(rx[Ether].src, intf.local_mac)
133
134 # the rx'd NS should be addressed to an mcast address
135 # derived from the target address
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200136 self.assertEqual(in6_ptop(rx[IPv6].dst), in6_ptop(dst_ip))
Neale Rannsdcd6d622017-05-26 02:59:16 -0700137
138 # expect the tgt IP in the NS header
139 ns = rx[ICMPv6ND_NS]
140 self.assertEqual(in6_ptop(ns.tgt), in6_ptop(tgt_ip))
141
142 # packet is from the router's local address
Ole Troandbeb56d2023-10-13 09:19:45 +0200143 self.assertEqual(in6_ptop(rx[IPv6].src), intf.local_ip6_ll)
Neale Rannsdcd6d622017-05-26 02:59:16 -0700144
145 # Src link-layer options should have the router's MAC
146 sll = rx[ICMPv6NDOptSrcLLAddr]
147 self.assertEqual(sll.lladdr, intf.local_mac)
148
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200149 def send_and_expect_ra(
150 self, intf, pkts, remark, dst_ip=None, filter_out_fn=is_ipv6_misc
151 ):
Neale Ranns3f844d02017-02-18 00:03:54 -0800152 intf.add_stream(pkts)
Neale Ranns3f844d02017-02-18 00:03:54 -0800153 self.pg_enable_capture(self.pg_interfaces)
154 self.pg_start()
155 rx = intf.get_capture(1, filter_out_fn=filter_out_fn)
156
157 self.assertEqual(len(rx), 1)
158 rx = rx[0]
159 self.validate_ra(intf, rx, dst_ip)
160
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200161 def send_and_expect_na(
162 self, intf, pkts, remark, dst_ip=None, tgt_ip=None, filter_out_fn=is_ipv6_misc
163 ):
Neale Ranns2a3ea492017-04-19 05:24:40 -0700164 intf.add_stream(pkts)
165 self.pg_enable_capture(self.pg_interfaces)
166 self.pg_start()
167 rx = intf.get_capture(1, filter_out_fn=filter_out_fn)
168
169 self.assertEqual(len(rx), 1)
170 rx = rx[0]
171 self.validate_na(intf, rx, dst_ip, tgt_ip)
172
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200173 def send_and_expect_ns(
174 self, tx_intf, rx_intf, pkts, tgt_ip, filter_out_fn=is_ipv6_misc
175 ):
Neale Rannscbe25aa2019-09-30 10:53:31 +0000176 self.vapi.cli("clear trace")
Neale Rannsdcd6d622017-05-26 02:59:16 -0700177 tx_intf.add_stream(pkts)
178 self.pg_enable_capture(self.pg_interfaces)
179 self.pg_start()
180 rx = rx_intf.get_capture(1, filter_out_fn=filter_out_fn)
181
182 self.assertEqual(len(rx), 1)
183 rx = rx[0]
184 self.validate_ns(rx_intf, rx, tgt_ip)
185
Neale Rannsdcd6d622017-05-26 02:59:16 -0700186 def verify_ip(self, rx, smac, dmac, sip, dip):
187 ether = rx[Ether]
188 self.assertEqual(ether.dst, dmac)
189 self.assertEqual(ether.src, smac)
190
191 ip = rx[IPv6]
192 self.assertEqual(ip.src, sip)
193 self.assertEqual(ip.dst, dip)
194
Neale Rannsfd2417b2021-07-16 14:00:16 +0000195 def get_ip6_nd_rx_requests(self, itf):
196 """Get IP6 ND RX request stats for and interface"""
197 return self.statistics["/net/ip6-nd/rx/requests"][:, itf.sw_if_index].sum()
198
199 def get_ip6_nd_tx_requests(self, itf):
200 """Get IP6 ND TX request stats for and interface"""
201 return self.statistics["/net/ip6-nd/tx/requests"][:, itf.sw_if_index].sum()
202
203 def get_ip6_nd_rx_replies(self, itf):
204 """Get IP6 ND RX replies stats for and interface"""
205 return self.statistics["/net/ip6-nd/rx/replies"][:, itf.sw_if_index].sum()
206
207 def get_ip6_nd_tx_replies(self, itf):
208 """Get IP6 ND TX replies stats for and interface"""
209 return self.statistics["/net/ip6-nd/tx/replies"][:, itf.sw_if_index].sum()
210
Neale Ranns3f844d02017-02-18 00:03:54 -0800211
Andrew Yourtchenko06f32812021-01-14 10:19:08 +0000212@tag_run_solo
Neale Ranns3f844d02017-02-18 00:03:54 -0800213class TestIPv6(TestIPv6ND):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200214 """IPv6 Test Case"""
Damjan Marionf56b77a2016-10-03 19:44:57 +0200215
216 @classmethod
217 def setUpClass(cls):
218 super(TestIPv6, cls).setUpClass()
219
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -0700220 @classmethod
221 def tearDownClass(cls):
222 super(TestIPv6, cls).tearDownClass()
223
Klement Sekeraf62ae122016-10-11 11:47:09 +0200224 def setUp(self):
Matej Klotton86d87c42016-11-11 11:38:55 +0100225 """
226 Perform test setup before test case.
227
228 **Config:**
229 - create 3 pg interfaces
230 - untagged pg0 interface
231 - Dot1Q subinterface on pg1
232 - Dot1AD subinterface on pg2
233 - setup interfaces:
234 - put it into UP state
235 - set IPv6 addresses
236 - resolve neighbor address using NDP
237 - configure 200 fib entries
238
239 :ivar list interfaces: pg interfaces and subinterfaces.
240 :ivar dict flows: IPv4 packet flows in test.
Matej Klotton86d87c42016-11-11 11:38:55 +0100241
242 *TODO:* Create AD sub interface
243 """
Klement Sekeraf62ae122016-10-11 11:47:09 +0200244 super(TestIPv6, self).setUp()
Damjan Marionf56b77a2016-10-03 19:44:57 +0200245
Klement Sekeraf62ae122016-10-11 11:47:09 +0200246 # create 3 pg interfaces
247 self.create_pg_interfaces(range(3))
Damjan Marionf56b77a2016-10-03 19:44:57 +0200248
Klement Sekeraf62ae122016-10-11 11:47:09 +0200249 # create 2 subinterfaces for p1 and pg2
250 self.sub_interfaces = [
251 VppDot1QSubint(self, self.pg1, 100),
Dave Wallace940a70f2024-04-03 12:31:42 -0400252 VppDot1QSubint(self, self.pg2, 200),
Klement Sekeraf62ae122016-10-11 11:47:09 +0200253 # TODO: VppDot1ADSubint(self, self.pg2, 200, 300, 400)
Matej Klotton86d87c42016-11-11 11:38:55 +0100254 ]
Damjan Marionf56b77a2016-10-03 19:44:57 +0200255
Klement Sekeraf62ae122016-10-11 11:47:09 +0200256 # packet flows mapping pg0 -> pg1.sub, pg2.sub, etc.
257 self.flows = dict()
258 self.flows[self.pg0] = [self.pg1.sub_if, self.pg2.sub_if]
259 self.flows[self.pg1.sub_if] = [self.pg0, self.pg2.sub_if]
260 self.flows[self.pg2.sub_if] = [self.pg0, self.pg1.sub_if]
Damjan Marionf56b77a2016-10-03 19:44:57 +0200261
Klement Sekeraf62ae122016-10-11 11:47:09 +0200262 # packet sizes
Jan Geletye6c78ee2018-06-26 12:24:03 +0200263 self.pg_if_packet_sizes = [64, 1500, 9020]
Damjan Marionf56b77a2016-10-03 19:44:57 +0200264
Klement Sekeraf62ae122016-10-11 11:47:09 +0200265 self.interfaces = list(self.pg_interfaces)
266 self.interfaces.extend(self.sub_interfaces)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200267
Klement Sekeraf62ae122016-10-11 11:47:09 +0200268 # setup all interfaces
269 for i in self.interfaces:
270 i.admin_up()
271 i.config_ip6()
272 i.resolve_ndp()
273
Damjan Marionf56b77a2016-10-03 19:44:57 +0200274 def tearDown(self):
Matej Klotton86d87c42016-11-11 11:38:55 +0100275 """Run standard test teardown and log ``show ip6 neighbors``."""
Vladislav Grishenko1fb62c02022-05-16 01:44:43 +0500276 for i in reversed(self.interfaces):
Neale Ranns75152282017-01-09 01:00:45 -0800277 i.unconfig_ip6()
Neale Ranns75152282017-01-09 01:00:45 -0800278 i.admin_down()
Neale Ranns744902e2017-08-14 10:35:44 -0700279 for i in self.sub_interfaces:
Neale Ranns75152282017-01-09 01:00:45 -0800280 i.remove_vpp_config()
281
Klement Sekeraf62ae122016-10-11 11:47:09 +0200282 super(TestIPv6, self).tearDown()
283 if not self.vpp_dead:
Matej Klotton86d87c42016-11-11 11:38:55 +0100284 self.logger.info(self.vapi.cli("show ip6 neighbors"))
Klement Sekeraf62ae122016-10-11 11:47:09 +0200285 # info(self.vapi.cli("show ip6 fib")) # many entries
Damjan Marionf56b77a2016-10-03 19:44:57 +0200286
Jan Geletye6c78ee2018-06-26 12:24:03 +0200287 def modify_packet(self, src_if, packet_size, pkt):
288 """Add load, set destination IP and extend packet to required packet
289 size for defined interface.
290
291 :param VppInterface src_if: Interface to create packet for.
292 :param int packet_size: Required packet size.
293 :param Scapy pkt: Packet to be modified.
294 """
snaramre07a0f212019-10-11 21:28:56 +0000295 dst_if_idx = int(packet_size / 10 % 2)
Jan Geletye6c78ee2018-06-26 12:24:03 +0200296 dst_if = self.flows[src_if][dst_if_idx]
297 info = self.create_packet_info(src_if, dst_if)
298 payload = self.info_to_payload(info)
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800299 p = pkt / Raw(payload)
Jan Geletye6c78ee2018-06-26 12:24:03 +0200300 p[IPv6].dst = dst_if.remote_ip6
301 info.data = p.copy()
302 if isinstance(src_if, VppSubInterface):
303 p = src_if.add_dot1_layer(p)
304 self.extend_packet(p, packet_size)
305
306 return p
307
308 def create_stream(self, src_if):
Matej Klotton86d87c42016-11-11 11:38:55 +0100309 """Create input packet stream for defined interface.
310
311 :param VppInterface src_if: Interface to create packet stream for.
Matej Klotton86d87c42016-11-11 11:38:55 +0100312 """
Jan Geletye6c78ee2018-06-26 12:24:03 +0200313 hdr_ext = 4 if isinstance(src_if, VppSubInterface) else 0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200314 pkt_tmpl = (
315 Ether(dst=src_if.local_mac, src=src_if.remote_mac)
316 / IPv6(src=src_if.remote_ip6)
317 / inet6.UDP(sport=1234, dport=1234)
318 )
Jan Geletye6c78ee2018-06-26 12:24:03 +0200319
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200320 pkts = [
321 self.modify_packet(src_if, i, pkt_tmpl)
322 for i in moves.range(
323 self.pg_if_packet_sizes[0], self.pg_if_packet_sizes[1], 10
324 )
325 ]
326 pkts_b = [
327 self.modify_packet(src_if, i, pkt_tmpl)
328 for i in moves.range(
329 self.pg_if_packet_sizes[1] + hdr_ext,
330 self.pg_if_packet_sizes[2] + hdr_ext,
331 50,
332 )
333 ]
Jan Geletye6c78ee2018-06-26 12:24:03 +0200334 pkts.extend(pkts_b)
335
Damjan Marionf56b77a2016-10-03 19:44:57 +0200336 return pkts
337
Klement Sekeraf62ae122016-10-11 11:47:09 +0200338 def verify_capture(self, dst_if, capture):
Matej Klotton86d87c42016-11-11 11:38:55 +0100339 """Verify captured input packet stream for defined interface.
340
341 :param VppInterface dst_if: Interface to verify captured packet stream
342 for.
343 :param list capture: Captured packet stream.
344 """
345 self.logger.info("Verifying capture on interface %s" % dst_if.name)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200346 last_info = dict()
Damjan Marionf56b77a2016-10-03 19:44:57 +0200347 for i in self.interfaces:
Klement Sekeraf62ae122016-10-11 11:47:09 +0200348 last_info[i.sw_if_index] = None
349 is_sub_if = False
350 dst_sw_if_index = dst_if.sw_if_index
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200351 if hasattr(dst_if, "parent"):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200352 is_sub_if = True
Damjan Marionf56b77a2016-10-03 19:44:57 +0200353 for packet in capture:
Klement Sekeraf62ae122016-10-11 11:47:09 +0200354 if is_sub_if:
355 # Check VLAN tags and Ethernet header
356 packet = dst_if.remove_dot1_layer(packet)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200357 self.assertTrue(Dot1Q not in packet)
358 try:
359 ip = packet[IPv6]
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800360 udp = packet[inet6.UDP]
Paul Vinciguerraeaea4212019-03-06 11:58:06 -0800361 payload_info = self.payload_to_info(packet[Raw])
Damjan Marionf56b77a2016-10-03 19:44:57 +0200362 packet_index = payload_info.index
Klement Sekeraf62ae122016-10-11 11:47:09 +0200363 self.assertEqual(payload_info.dst, dst_sw_if_index)
Klement Sekerada505f62017-01-04 12:58:53 +0100364 self.logger.debug(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200365 "Got packet on port %s: src=%u (id=%u)"
366 % (dst_if.name, payload_info.src, packet_index)
367 )
Klement Sekeraf62ae122016-10-11 11:47:09 +0200368 next_info = self.get_next_packet_info_for_interface2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200369 payload_info.src, dst_sw_if_index, last_info[payload_info.src]
370 )
Klement Sekeraf62ae122016-10-11 11:47:09 +0200371 last_info[payload_info.src] = next_info
Damjan Marionf56b77a2016-10-03 19:44:57 +0200372 self.assertTrue(next_info is not None)
373 self.assertEqual(packet_index, next_info.index)
374 saved_packet = next_info.data
375 # Check standard fields
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200376 self.assertEqual(ip.src, saved_packet[IPv6].src)
377 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
378 self.assertEqual(udp.sport, saved_packet[inet6.UDP].sport)
379 self.assertEqual(udp.dport, saved_packet[inet6.UDP].dport)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200380 except:
Klement Sekera7bb873a2016-11-18 07:38:42 +0100381 self.logger.error(ppp("Unexpected or invalid packet:", packet))
Damjan Marionf56b77a2016-10-03 19:44:57 +0200382 raise
383 for i in self.interfaces:
Klement Sekeraf62ae122016-10-11 11:47:09 +0200384 remaining_packet = self.get_next_packet_info_for_interface2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200385 i.sw_if_index, dst_sw_if_index, last_info[i.sw_if_index]
386 )
387 self.assertTrue(
388 remaining_packet is None,
389 "Interface %s: Packet expected from interface %s "
390 "didn't arrive" % (dst_if.name, i.name),
391 )
Damjan Marionf56b77a2016-10-03 19:44:57 +0200392
Klement Sekerae8498652019-06-17 12:23:15 +0000393 def test_next_header_anomaly(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200394 """IPv6 next header anomaly test
Klement Sekerae8498652019-06-17 12:23:15 +0000395
396 Test scenario:
397 - ipv6 next header field = Fragment Header (44)
398 - next header is ICMPv6 Echo Request
399 - wait for reassembly
400 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200401 pkt = (
402 Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac)
403 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6, nh=44)
404 / ICMPv6EchoRequest()
405 )
Klement Sekerae8498652019-06-17 12:23:15 +0000406
407 self.pg0.add_stream(pkt)
408 self.pg_start()
409
410 # wait for reassembly
411 self.sleep(10)
412
Damjan Marionf56b77a2016-10-03 19:44:57 +0200413 def test_fib(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200414 """IPv6 FIB test
Matej Klotton86d87c42016-11-11 11:38:55 +0100415
416 Test scenario:
417 - Create IPv6 stream for pg0 interface
418 - Create IPv6 tagged streams for pg1's and pg2's subinterface.
419 - Send and verify received packets on each interface.
420 """
Damjan Marionf56b77a2016-10-03 19:44:57 +0200421
Jan Geletye6c78ee2018-06-26 12:24:03 +0200422 pkts = self.create_stream(self.pg0)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200423 self.pg0.add_stream(pkts)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200424
Klement Sekeraf62ae122016-10-11 11:47:09 +0200425 for i in self.sub_interfaces:
Jan Geletye6c78ee2018-06-26 12:24:03 +0200426 pkts = self.create_stream(i)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200427 i.parent.add_stream(pkts)
428
429 self.pg_enable_capture(self.pg_interfaces)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200430 self.pg_start()
431
Klement Sekeraf62ae122016-10-11 11:47:09 +0200432 pkts = self.pg0.get_capture()
433 self.verify_capture(self.pg0, pkts)
434
435 for i in self.sub_interfaces:
436 pkts = i.parent.get_capture()
437 self.verify_capture(i, pkts)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200438
Neale Ranns75152282017-01-09 01:00:45 -0800439 def test_ns(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200440 """IPv6 Neighbour Solicitation Exceptions
Neale Ranns75152282017-01-09 01:00:45 -0800441
Klement Sekerada505f62017-01-04 12:58:53 +0100442 Test scenario:
Neale Ranns75152282017-01-09 01:00:45 -0800443 - Send an NS Sourced from an address not covered by the link sub-net
444 - Send an NS to an mcast address the router has not joined
445 - Send NS for a target address the router does not onn.
446 """
447
Neale Rannsfd2417b2021-07-16 14:00:16 +0000448 n_rx_req_pg0 = self.get_ip6_nd_rx_requests(self.pg0)
449 n_tx_rep_pg0 = self.get_ip6_nd_tx_replies(self.pg0)
450
Neale Ranns75152282017-01-09 01:00:45 -0800451 #
452 # An NS from a non link source address
453 #
Neale Ranns3f844d02017-02-18 00:03:54 -0800454 nsma = in6_getnsma(inet_pton(AF_INET6, self.pg0.local_ip6))
455 d = inet_ntop(AF_INET6, nsma)
Neale Ranns75152282017-01-09 01:00:45 -0800456
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200457 p = (
458 Ether(dst=in6_getnsmac(nsma))
459 / IPv6(dst=d, src="2002::2")
460 / ICMPv6ND_NS(tgt=self.pg0.local_ip6)
461 / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)
462 )
Neale Ranns75152282017-01-09 01:00:45 -0800463 pkts = [p]
464
Klement Sekerada505f62017-01-04 12:58:53 +0100465 self.send_and_assert_no_replies(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200466 self.pg0, pkts, "No response to NS source by address not on sub-net"
467 )
Neale Rannsfd2417b2021-07-16 14:00:16 +0000468 self.assert_equal(self.get_ip6_nd_rx_requests(self.pg0), n_rx_req_pg0 + 1)
Neale Ranns75152282017-01-09 01:00:45 -0800469
470 #
Klement Sekerada505f62017-01-04 12:58:53 +0100471 # An NS for sent to a solicited mcast group the router is
472 # not a member of FAILS
Neale Ranns75152282017-01-09 01:00:45 -0800473 #
474 if 0:
Neale Ranns3f844d02017-02-18 00:03:54 -0800475 nsma = in6_getnsma(inet_pton(AF_INET6, "fd::ffff"))
476 d = inet_ntop(AF_INET6, nsma)
Neale Ranns75152282017-01-09 01:00:45 -0800477
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200478 p = (
479 Ether(dst=in6_getnsmac(nsma))
480 / IPv6(dst=d, src=self.pg0.remote_ip6)
481 / ICMPv6ND_NS(tgt=self.pg0.local_ip6)
482 / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)
483 )
Neale Ranns75152282017-01-09 01:00:45 -0800484 pkts = [p]
485
Klement Sekerada505f62017-01-04 12:58:53 +0100486 self.send_and_assert_no_replies(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200487 self.pg0, pkts, "No response to NS sent to unjoined mcast address"
488 )
Neale Ranns75152282017-01-09 01:00:45 -0800489
490 #
491 # An NS whose target address is one the router does not own
492 #
Neale Ranns3f844d02017-02-18 00:03:54 -0800493 nsma = in6_getnsma(inet_pton(AF_INET6, self.pg0.local_ip6))
494 d = inet_ntop(AF_INET6, nsma)
Neale Ranns75152282017-01-09 01:00:45 -0800495
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200496 p = (
497 Ether(dst=in6_getnsmac(nsma))
498 / IPv6(dst=d, src=self.pg0.remote_ip6)
499 / ICMPv6ND_NS(tgt="fd::ffff")
500 / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)
501 )
Neale Ranns75152282017-01-09 01:00:45 -0800502 pkts = [p]
503
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200504 self.send_and_assert_no_replies(
505 self.pg0, pkts, "No response to NS for unknown target"
506 )
Neale Rannsfd2417b2021-07-16 14:00:16 +0000507 self.assert_equal(self.get_ip6_nd_rx_requests(self.pg0), n_rx_req_pg0 + 2)
Neale Ranns75152282017-01-09 01:00:45 -0800508
Neale Rannsb3b2de72017-03-08 05:17:22 -0800509 #
510 # A neighbor entry that has no associated FIB-entry
511 #
512 self.pg0.generate_remote_hosts(4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200513 nd_entry = VppNeighbor(
514 self,
515 self.pg0.sw_if_index,
516 self.pg0.remote_hosts[2].mac,
517 self.pg0.remote_hosts[2].ip6,
518 is_no_fib_entry=1,
519 )
Neale Rannsb3b2de72017-03-08 05:17:22 -0800520 nd_entry.add_vpp_config()
521
522 #
523 # check we have the neighbor, but no route
524 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200525 self.assertTrue(
526 find_nbr(self, self.pg0.sw_if_index, self.pg0._remote_hosts[2].ip6)
527 )
528 self.assertFalse(find_route(self, self.pg0._remote_hosts[2].ip6, 128))
Neale Rannsb3b2de72017-03-08 05:17:22 -0800529
Neale Ranns2a3ea492017-04-19 05:24:40 -0700530 #
531 # send an NS from a link local address to the interface's global
532 # address
533 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200534 p = (
535 Ether(dst=in6_getnsmac(nsma), src=self.pg0.remote_mac)
536 / IPv6(dst=d, src=self.pg0._remote_hosts[2].ip6_ll)
537 / ICMPv6ND_NS(tgt=self.pg0.local_ip6)
538 / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)
539 )
Neale Ranns2a3ea492017-04-19 05:24:40 -0700540
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200541 self.send_and_expect_na(
542 self.pg0,
543 p,
544 "NS from link-local",
545 dst_ip=self.pg0._remote_hosts[2].ip6_ll,
546 tgt_ip=self.pg0.local_ip6,
547 )
Neale Rannsfd2417b2021-07-16 14:00:16 +0000548 self.assert_equal(self.get_ip6_nd_rx_requests(self.pg0), n_rx_req_pg0 + 3)
549 self.assert_equal(self.get_ip6_nd_tx_replies(self.pg0), n_tx_rep_pg0 + 1)
Neale Ranns2a3ea492017-04-19 05:24:40 -0700550
551 #
552 # we should have learned an ND entry for the peer's link-local
553 # but not inserted a route to it in the FIB
554 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200555 self.assertTrue(
556 find_nbr(self, self.pg0.sw_if_index, self.pg0._remote_hosts[2].ip6_ll)
557 )
558 self.assertFalse(find_route(self, self.pg0._remote_hosts[2].ip6_ll, 128))
Neale Ranns2a3ea492017-04-19 05:24:40 -0700559
560 #
561 # An NS to the router's own Link-local
562 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200563 p = (
564 Ether(dst=in6_getnsmac(nsma), src=self.pg0.remote_mac)
565 / IPv6(dst=d, src=self.pg0._remote_hosts[3].ip6_ll)
566 / ICMPv6ND_NS(tgt=self.pg0.local_ip6_ll)
567 / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)
568 )
Neale Ranns2a3ea492017-04-19 05:24:40 -0700569
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200570 self.send_and_expect_na(
571 self.pg0,
572 p,
573 "NS to/from link-local",
574 dst_ip=self.pg0._remote_hosts[3].ip6_ll,
575 tgt_ip=self.pg0.local_ip6_ll,
576 )
Neale Ranns2a3ea492017-04-19 05:24:40 -0700577
578 #
Neale Rannse2b67362021-04-02 07:34:39 +0000579 # do not respond to a NS for the peer's address
580 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200581 p = (
582 Ether(dst=in6_getnsmac(nsma), src=self.pg0.remote_mac)
583 / IPv6(dst=d, src=self.pg0._remote_hosts[3].ip6_ll)
584 / ICMPv6ND_NS(tgt=self.pg0._remote_hosts[3].ip6_ll)
585 / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)
586 )
Neale Rannse2b67362021-04-02 07:34:39 +0000587
588 self.send_and_assert_no_replies(self.pg0, p)
589
590 #
Neale Ranns2a3ea492017-04-19 05:24:40 -0700591 # we should have learned an ND entry for the peer's link-local
592 # but not inserted a route to it in the FIB
593 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200594 self.assertTrue(
595 find_nbr(self, self.pg0.sw_if_index, self.pg0._remote_hosts[3].ip6_ll)
596 )
597 self.assertFalse(find_route(self, self.pg0._remote_hosts[3].ip6_ll, 128))
Neale Ranns2a3ea492017-04-19 05:24:40 -0700598
Neale Rannsfd2417b2021-07-16 14:00:16 +0000599 def test_nd_incomplete(self):
600 """IP6-ND Incomplete"""
601 self.pg1.generate_remote_hosts(3)
602
603 p0 = (
604 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
605 / IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_hosts[1].ip6)
606 / UDP(sport=1234, dport=1234)
607 / Raw()
608 )
609
610 #
611 # a packet to an unresolved destination generates an ND request
612 #
613 n_tx_req_pg1 = self.get_ip6_nd_tx_requests(self.pg1)
614 self.send_and_expect_ns(self.pg0, self.pg1, p0, self.pg1.remote_hosts[1].ip6)
615 self.assert_equal(self.get_ip6_nd_tx_requests(self.pg1), n_tx_req_pg1 + 1)
616
617 #
618 # a reply to the request
619 #
620 self.assert_equal(self.get_ip6_nd_rx_replies(self.pg1), 0)
621 na = (
622 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
623 / IPv6(dst=self.pg1.local_ip6, src=self.pg1.remote_hosts[1].ip6)
624 / ICMPv6ND_NA(tgt=self.pg1.remote_hosts[1].ip6)
625 / ICMPv6NDOptSrcLLAddr(lladdr=self.pg1.remote_hosts[1].mac)
626 )
627 self.send_and_assert_no_replies(self.pg1, [na])
628 self.assert_equal(self.get_ip6_nd_rx_replies(self.pg1), 1)
629
Neale Rannsdcd6d622017-05-26 02:59:16 -0700630 def test_ns_duplicates(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200631 """ND Duplicates"""
Neale Rannsdcd6d622017-05-26 02:59:16 -0700632
633 #
634 # Generate some hosts on the LAN
635 #
636 self.pg1.generate_remote_hosts(3)
637
638 #
639 # Add host 1 on pg1 and pg2
640 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200641 ns_pg1 = VppNeighbor(
642 self,
643 self.pg1.sw_if_index,
644 self.pg1.remote_hosts[1].mac,
645 self.pg1.remote_hosts[1].ip6,
646 )
Neale Rannsdcd6d622017-05-26 02:59:16 -0700647 ns_pg1.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200648 ns_pg2 = VppNeighbor(
649 self,
650 self.pg2.sw_if_index,
651 self.pg2.remote_mac,
652 self.pg1.remote_hosts[1].ip6,
653 )
Neale Rannsdcd6d622017-05-26 02:59:16 -0700654 ns_pg2.add_vpp_config()
655
656 #
657 # IP packet destined for pg1 remote host arrives on pg1 again.
658 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200659 p = (
660 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
661 / IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_hosts[1].ip6)
662 / inet6.UDP(sport=1234, dport=1234)
663 / Raw()
664 )
Neale Rannsdcd6d622017-05-26 02:59:16 -0700665
666 self.pg0.add_stream(p)
667 self.pg_enable_capture(self.pg_interfaces)
668 self.pg_start()
669
670 rx1 = self.pg1.get_capture(1)
671
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200672 self.verify_ip(
673 rx1[0],
674 self.pg1.local_mac,
675 self.pg1.remote_hosts[1].mac,
676 self.pg0.remote_ip6,
677 self.pg1.remote_hosts[1].ip6,
678 )
Neale Rannsdcd6d622017-05-26 02:59:16 -0700679
680 #
681 # remove the duplicate on pg1
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700682 # packet stream should generate NSs out of pg1
Neale Rannsdcd6d622017-05-26 02:59:16 -0700683 #
684 ns_pg1.remove_vpp_config()
685
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200686 self.send_and_expect_ns(self.pg0, self.pg1, p, self.pg1.remote_hosts[1].ip6)
Neale Rannsdcd6d622017-05-26 02:59:16 -0700687
688 #
689 # Add it back
690 #
691 ns_pg1.add_vpp_config()
692
693 self.pg0.add_stream(p)
694 self.pg_enable_capture(self.pg_interfaces)
695 self.pg_start()
696
697 rx1 = self.pg1.get_capture(1)
698
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200699 self.verify_ip(
700 rx1[0],
701 self.pg1.local_mac,
702 self.pg1.remote_hosts[1].mac,
703 self.pg0.remote_ip6,
704 self.pg1.remote_hosts[1].ip6,
705 )
Neale Rannsdcd6d622017-05-26 02:59:16 -0700706
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200707 def validate_ra(self, intf, rx, dst_ip=None, src_ip=None, mtu=9000, pi_opt=None):
Neale Ranns32e1c012016-11-22 17:07:28 +0000708 if not dst_ip:
709 dst_ip = intf.remote_ip6
Neale Rannscbe25aa2019-09-30 10:53:31 +0000710 if not src_ip:
711 src_ip = mk_ll_addr(intf.local_mac)
Neale Ranns75152282017-01-09 01:00:45 -0800712
Neale Ranns5737d882017-02-03 06:14:49 -0800713 # unicasted packets must come to the unicast mac
Neale Ranns32e1c012016-11-22 17:07:28 +0000714 self.assertEqual(rx[Ether].dst, intf.remote_mac)
715
716 # and from the router's MAC
717 self.assertEqual(rx[Ether].src, intf.local_mac)
Neale Ranns75152282017-01-09 01:00:45 -0800718
719 # the rx'd RA should be addressed to the sender's source
720 self.assertTrue(rx.haslayer(ICMPv6ND_RA))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200721 self.assertEqual(in6_ptop(rx[IPv6].dst), in6_ptop(dst_ip))
Neale Ranns75152282017-01-09 01:00:45 -0800722
723 # and come from the router's link local
724 self.assertTrue(in6_islladdr(rx[IPv6].src))
Neale Rannscbe25aa2019-09-30 10:53:31 +0000725 self.assertEqual(in6_ptop(rx[IPv6].src), in6_ptop(src_ip))
Neale Ranns75152282017-01-09 01:00:45 -0800726
Neale Ranns87df12d2017-02-18 08:16:41 -0800727 # it should contain the links MTU
728 ra = rx[ICMPv6ND_RA]
729 self.assertEqual(ra[ICMPv6NDOptMTU].mtu, mtu)
730
731 # it should contain the source's link layer address option
732 sll = ra[ICMPv6NDOptSrcLLAddr]
733 self.assertEqual(sll.lladdr, intf.local_mac)
734
735 if not pi_opt:
736 # the RA should not contain prefix information
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200737 self.assertFalse(ra.haslayer(ICMPv6NDOptPrefixInfo))
Neale Ranns87df12d2017-02-18 08:16:41 -0800738 else:
739 raos = rx.getlayer(ICMPv6NDOptPrefixInfo, 1)
740
741 # the options are nested in the scapy packet in way that i cannot
742 # decipher how to decode. this 1st layer of option always returns
743 # nested classes, so a direct obj1=obj2 comparison always fails.
Paul Vinciguerraab055082019-06-06 14:07:55 -0400744 # however, the getlayer(.., 2) does give one instance.
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700745 # so we cheat here and construct a new opt instance for comparison
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800746 rd = ICMPv6NDOptPrefixInfo(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200747 prefixlen=raos.prefixlen, prefix=raos.prefix, L=raos.L, A=raos.A
748 )
Neale Ranns87df12d2017-02-18 08:16:41 -0800749 if type(pi_opt) is list:
750 for ii in range(len(pi_opt)):
751 self.assertEqual(pi_opt[ii], rd)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200752 rd = rx.getlayer(ICMPv6NDOptPrefixInfo, ii + 2)
Neale Ranns87df12d2017-02-18 08:16:41 -0800753 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200754 self.assertEqual(
755 pi_opt,
756 raos,
757 "Expected: %s, received: %s"
758 % (pi_opt.show(dump=True), raos.show(dump=True)),
759 )
Neale Ranns87df12d2017-02-18 08:16:41 -0800760
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200761 def send_and_expect_ra(
762 self,
763 intf,
764 pkts,
765 remark,
766 dst_ip=None,
767 filter_out_fn=is_ipv6_misc,
768 opt=None,
769 src_ip=None,
770 ):
Neale Rannscbe25aa2019-09-30 10:53:31 +0000771 self.vapi.cli("clear trace")
Neale Ranns32e1c012016-11-22 17:07:28 +0000772 intf.add_stream(pkts)
Neale Ranns32e1c012016-11-22 17:07:28 +0000773 self.pg_enable_capture(self.pg_interfaces)
774 self.pg_start()
775 rx = intf.get_capture(1, filter_out_fn=filter_out_fn)
776
777 self.assertEqual(len(rx), 1)
778 rx = rx[0]
Neale Rannscbe25aa2019-09-30 10:53:31 +0000779 self.validate_ra(intf, rx, dst_ip, src_ip=src_ip, pi_opt=opt)
Neale Ranns32e1c012016-11-22 17:07:28 +0000780
Alexander Chernavin3b28fd72023-02-02 14:22:56 +0000781 def test_ip6_ra_dump(self):
782 """IPv6 RA dump"""
783
784 # Dump IPv6 RA for all interfaces
785 ip6_ra_dump = self.vapi.sw_interface_ip6nd_ra_dump(sw_if_index=0xFFFFFFFF)
786 self.assertEqual(len(ip6_ra_dump), len(self.interfaces))
787
788 for ip6_ra in ip6_ra_dump:
789 self.assertFalse(ip6_ra.send_radv)
790 self.assertEqual(ip6_ra.n_prefixes, 0)
791 self.assertEqual(len(ip6_ra.prefixes), 0)
792 self.assertEqual(ip6_ra.last_radv_time, 0.0)
793 self.assertEqual(ip6_ra.last_multicast_time, 0.0)
794 self.assertEqual(ip6_ra.next_multicast_time, 0.0)
795 self.assertEqual(ip6_ra.n_advertisements_sent, 0)
796 self.assertEqual(ip6_ra.n_solicitations_rcvd, 0)
797 self.assertEqual(ip6_ra.n_solicitations_dropped, 0)
798
799 # Enable sending IPv6 RA for an interface
800 self.pg0.ip6_ra_config(no=1, suppress=1)
801
802 # Add IPv6 RA prefixes for the interface
803 pfx0 = IPv6Network(
804 "%s/%s" % (self.pg0.local_ip6, self.pg0.local_ip6_prefix_len), strict=False
805 )
806 pfx1 = IPv6Network("fafa::/96")
807 self.pg0.ip6_ra_prefix(pfx0, off_link=0, no_autoconfig=0)
808 self.pg0.ip6_ra_prefix(pfx1, off_link=1, no_autoconfig=1)
809
810 # Wait for multicast IPv6 RA
811 self.sleep(1)
812
813 # Dump IPv6 RA for the interface
814 ip6_ra_dump = self.vapi.sw_interface_ip6nd_ra_dump(
815 sw_if_index=self.pg0.sw_if_index
816 )
817 self.assertEqual(len(ip6_ra_dump), 1)
818 ip6_ra = ip6_ra_dump[0]
819
820 self.assertEqual(ip6_ra.sw_if_index, self.pg0.sw_if_index)
821 self.assertTrue(ip6_ra.send_radv)
822 self.assertEqual(ip6_ra.n_prefixes, 2)
823 self.assertEqual(len(ip6_ra.prefixes), 2)
824 self.assertEqual(ip6_ra.last_radv_time, 0.0)
825 self.assertGreater(ip6_ra.last_multicast_time, 0.0)
826 self.assertGreater(ip6_ra.next_multicast_time, 0.0)
827 self.assertGreater(ip6_ra.n_advertisements_sent, 0)
828 self.assertEqual(ip6_ra.n_solicitations_rcvd, 0)
829 self.assertEqual(ip6_ra.n_solicitations_dropped, 0)
830
831 self.assertEqual(ip6_ra.prefixes[0].prefix, pfx0)
832 self.assertTrue(ip6_ra.prefixes[0].onlink_flag)
833 self.assertTrue(ip6_ra.prefixes[0].autonomous_flag)
834 self.assertFalse(ip6_ra.prefixes[0].no_advertise)
835
836 self.assertEqual(ip6_ra.prefixes[1].prefix, pfx1)
837 self.assertFalse(ip6_ra.prefixes[1].onlink_flag)
838 self.assertFalse(ip6_ra.prefixes[1].autonomous_flag)
839 self.assertFalse(ip6_ra.prefixes[1].no_advertise)
840
841 # Reset sending IPv6 RA for the interface
842 self.pg0.ip6_ra_config(suppress=1)
843
844 # Remove IPv6 RA prefixes for the interface
845 self.pg0.ip6_ra_prefix(pfx0, is_no=1)
846 self.pg0.ip6_ra_prefix(pfx1, is_no=1)
847
848 # Dump IPv6 RA for the interface
849 ip6_ra_dump = self.vapi.sw_interface_ip6nd_ra_dump(
850 sw_if_index=self.pg0.sw_if_index
851 )
852 self.assertEqual(len(ip6_ra_dump), 1)
853 ip6_ra = ip6_ra_dump[0]
854
855 self.assertEqual(ip6_ra.sw_if_index, self.pg0.sw_if_index)
856 self.assertFalse(ip6_ra.send_radv)
857 self.assertEqual(ip6_ra.n_prefixes, 0)
858 self.assertEqual(len(ip6_ra.prefixes), 0)
859
Neale Ranns75152282017-01-09 01:00:45 -0800860 def test_rs(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200861 """IPv6 Router Solicitation Exceptions
Neale Ranns75152282017-01-09 01:00:45 -0800862
Klement Sekerada505f62017-01-04 12:58:53 +0100863 Test scenario:
Neale Ranns75152282017-01-09 01:00:45 -0800864 """
865
Alexander Chernavine99f7622022-03-05 15:51:54 +0000866 self.pg0.ip6_ra_config(no=1, suppress=1)
867
Neale Ranns75152282017-01-09 01:00:45 -0800868 #
Klement Sekerada505f62017-01-04 12:58:53 +0100869 # Before we begin change the IPv6 RA responses to use the unicast
870 # address - that way we will not confuse them with the periodic
871 # RAs which go to the mcast address
Neale Ranns32e1c012016-11-22 17:07:28 +0000872 # Sit and wait for the first periodic RA.
873 #
874 # TODO
Neale Ranns75152282017-01-09 01:00:45 -0800875 #
876 self.pg0.ip6_ra_config(send_unicast=1)
877
878 #
879 # An RS from a link source address
880 # - expect an RA in return
881 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200882 p = (
883 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
884 / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6)
885 / ICMPv6ND_RS()
886 )
Neale Ranns75152282017-01-09 01:00:45 -0800887 pkts = [p]
888 self.send_and_expect_ra(self.pg0, pkts, "Genuine RS")
889
890 #
891 # For the next RS sent the RA should be rate limited
892 #
893 self.send_and_assert_no_replies(self.pg0, pkts, "RA rate limited")
894
895 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700896 # When we reconfigure the IPv6 RA config,
897 # we reset the RA rate limiting,
Klement Sekerada505f62017-01-04 12:58:53 +0100898 # so we need to do this before each test below so as not to drop
899 # packets for rate limiting reasons. Test this works here.
Neale Ranns75152282017-01-09 01:00:45 -0800900 #
901 self.pg0.ip6_ra_config(send_unicast=1)
902 self.send_and_expect_ra(self.pg0, pkts, "Rate limit reset RS")
903
904 #
905 # An RS sent from a non-link local source
906 #
907 self.pg0.ip6_ra_config(send_unicast=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200908 p = (
909 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
910 / IPv6(dst=self.pg0.local_ip6, src="2002::ffff")
911 / ICMPv6ND_RS()
912 )
Neale Ranns75152282017-01-09 01:00:45 -0800913 pkts = [p]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200914 self.send_and_assert_no_replies(self.pg0, pkts, "RS from non-link source")
Neale Ranns75152282017-01-09 01:00:45 -0800915
916 #
917 # Source an RS from a link local address
918 #
919 self.pg0.ip6_ra_config(send_unicast=1)
920 ll = mk_ll_addr(self.pg0.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200921 p = (
922 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
923 / IPv6(dst=self.pg0.local_ip6, src=ll)
924 / ICMPv6ND_RS()
925 )
Neale Ranns75152282017-01-09 01:00:45 -0800926 pkts = [p]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200927 self.send_and_expect_ra(self.pg0, pkts, "RS sourced from link-local", dst_ip=ll)
Neale Ranns32e1c012016-11-22 17:07:28 +0000928
929 #
Ole Troan5d280d52021-08-06 09:58:09 +0200930 # Source an RS from a link local address
931 # Ensure suppress also applies to solicited RS
932 #
933 self.pg0.ip6_ra_config(send_unicast=1, suppress=1)
934 ll = mk_ll_addr(self.pg0.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200935 p = (
936 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
937 / IPv6(dst=self.pg0.local_ip6, src=ll)
938 / ICMPv6ND_RS()
939 )
Ole Troan5d280d52021-08-06 09:58:09 +0200940 pkts = [p]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200941 self.send_and_assert_no_replies(self.pg0, pkts, "Suppressed RS from link-local")
Ole Troan5d280d52021-08-06 09:58:09 +0200942
943 #
Neale Ranns32e1c012016-11-22 17:07:28 +0000944 # Send the RS multicast
945 #
Ole Troan5d280d52021-08-06 09:58:09 +0200946 self.pg0.ip6_ra_config(no=1, suppress=1) # Reset suppress flag to zero
Neale Ranns32e1c012016-11-22 17:07:28 +0000947 self.pg0.ip6_ra_config(send_unicast=1)
Neale Ranns3f844d02017-02-18 00:03:54 -0800948 dmac = in6_getnsmac(inet_pton(AF_INET6, "ff02::2"))
Neale Ranns32e1c012016-11-22 17:07:28 +0000949 ll = mk_ll_addr(self.pg0.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200950 p = (
951 Ether(dst=dmac, src=self.pg0.remote_mac)
952 / IPv6(dst="ff02::2", src=ll)
953 / ICMPv6ND_RS()
954 )
Neale Ranns32e1c012016-11-22 17:07:28 +0000955 pkts = [p]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200956 self.send_and_expect_ra(self.pg0, pkts, "RS sourced from link-local", dst_ip=ll)
Neale Ranns75152282017-01-09 01:00:45 -0800957
958 #
Klement Sekerada505f62017-01-04 12:58:53 +0100959 # Source from the unspecified address ::. This happens when the RS
960 # is sent before the host has a configured address/sub-net,
961 # i.e. auto-config. Since the sender has no IP address, the reply
962 # comes back mcast - so the capture needs to not filter this.
963 # If we happen to pick up the periodic RA at this point then so be it,
964 # it's not an error.
Neale Ranns75152282017-01-09 01:00:45 -0800965 #
Alexander Chernavine99f7622022-03-05 15:51:54 +0000966 self.pg0.ip6_ra_config(send_unicast=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200967 p = (
968 Ether(dst=dmac, src=self.pg0.remote_mac)
969 / IPv6(dst="ff02::2", src="::")
970 / ICMPv6ND_RS()
971 )
Neale Ranns75152282017-01-09 01:00:45 -0800972 pkts = [p]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200973 self.send_and_expect_ra(
974 self.pg0,
975 pkts,
976 "RS sourced from unspecified",
977 dst_ip="ff02::1",
978 filter_out_fn=None,
979 )
Neale Ranns75152282017-01-09 01:00:45 -0800980
981 #
Neale Ranns87df12d2017-02-18 08:16:41 -0800982 # Configure The RA to announce the links prefix
983 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200984 self.pg0.ip6_ra_prefix(
985 "%s/%s" % (self.pg0.local_ip6, self.pg0.local_ip6_prefix_len)
986 )
Neale Ranns87df12d2017-02-18 08:16:41 -0800987
988 #
989 # RAs should now contain the prefix information option
990 #
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800991 opt = ICMPv6NDOptPrefixInfo(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200992 prefixlen=self.pg0.local_ip6_prefix_len, prefix=self.pg0.local_ip6, L=1, A=1
993 )
Neale Ranns87df12d2017-02-18 08:16:41 -0800994
995 self.pg0.ip6_ra_config(send_unicast=1)
996 ll = mk_ll_addr(self.pg0.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200997 p = (
998 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
999 / IPv6(dst=self.pg0.local_ip6, src=ll)
1000 / ICMPv6ND_RS()
1001 )
1002 self.send_and_expect_ra(self.pg0, p, "RA with prefix-info", dst_ip=ll, opt=opt)
Neale Ranns87df12d2017-02-18 08:16:41 -08001003
1004 #
1005 # Change the prefix info to not off-link
1006 # L-flag is clear
1007 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001008 self.pg0.ip6_ra_prefix(
1009 "%s/%s" % (self.pg0.local_ip6, self.pg0.local_ip6_prefix_len), off_link=1
1010 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001011
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001012 opt = ICMPv6NDOptPrefixInfo(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001013 prefixlen=self.pg0.local_ip6_prefix_len, prefix=self.pg0.local_ip6, L=0, A=1
1014 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001015
1016 self.pg0.ip6_ra_config(send_unicast=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001017 self.send_and_expect_ra(
1018 self.pg0, p, "RA with Prefix info with L-flag=0", dst_ip=ll, opt=opt
1019 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001020
1021 #
1022 # Change the prefix info to not off-link, no-autoconfig
1023 # L and A flag are clear in the advert
1024 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001025 self.pg0.ip6_ra_prefix(
1026 "%s/%s" % (self.pg0.local_ip6, self.pg0.local_ip6_prefix_len),
1027 off_link=1,
1028 no_autoconfig=1,
1029 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001030
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001031 opt = ICMPv6NDOptPrefixInfo(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001032 prefixlen=self.pg0.local_ip6_prefix_len, prefix=self.pg0.local_ip6, L=0, A=0
1033 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001034
1035 self.pg0.ip6_ra_config(send_unicast=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001036 self.send_and_expect_ra(
1037 self.pg0, p, "RA with Prefix info with A & L-flag=0", dst_ip=ll, opt=opt
1038 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001039
1040 #
1041 # Change the flag settings back to the defaults
1042 # L and A flag are set in the advert
1043 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001044 self.pg0.ip6_ra_prefix(
1045 "%s/%s" % (self.pg0.local_ip6, self.pg0.local_ip6_prefix_len)
1046 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001047
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001048 opt = ICMPv6NDOptPrefixInfo(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001049 prefixlen=self.pg0.local_ip6_prefix_len, prefix=self.pg0.local_ip6, L=1, A=1
1050 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001051
1052 self.pg0.ip6_ra_config(send_unicast=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001053 self.send_and_expect_ra(self.pg0, p, "RA with Prefix info", dst_ip=ll, opt=opt)
Neale Ranns87df12d2017-02-18 08:16:41 -08001054
1055 #
1056 # Change the prefix info to not off-link, no-autoconfig
1057 # L and A flag are clear in the advert
1058 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001059 self.pg0.ip6_ra_prefix(
1060 "%s/%s" % (self.pg0.local_ip6, self.pg0.local_ip6_prefix_len),
1061 off_link=1,
1062 no_autoconfig=1,
1063 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001064
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001065 opt = ICMPv6NDOptPrefixInfo(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001066 prefixlen=self.pg0.local_ip6_prefix_len, prefix=self.pg0.local_ip6, L=0, A=0
1067 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001068
1069 self.pg0.ip6_ra_config(send_unicast=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001070 self.send_and_expect_ra(
1071 self.pg0, p, "RA with Prefix info with A & L-flag=0", dst_ip=ll, opt=opt
1072 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001073
1074 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07001075 # Use the reset to defaults option to revert to defaults
Neale Ranns87df12d2017-02-18 08:16:41 -08001076 # L and A flag are clear in the advert
1077 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001078 self.pg0.ip6_ra_prefix(
1079 "%s/%s" % (self.pg0.local_ip6, self.pg0.local_ip6_prefix_len), use_default=1
1080 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001081
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001082 opt = ICMPv6NDOptPrefixInfo(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001083 prefixlen=self.pg0.local_ip6_prefix_len, prefix=self.pg0.local_ip6, L=1, A=1
1084 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001085
1086 self.pg0.ip6_ra_config(send_unicast=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001087 self.send_and_expect_ra(
1088 self.pg0, p, "RA with Prefix reverted to defaults", dst_ip=ll, opt=opt
1089 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001090
1091 #
1092 # Advertise Another prefix. With no L-flag/A-flag
1093 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001094 self.pg0.ip6_ra_prefix(
1095 "%s/%s" % (self.pg1.local_ip6, self.pg1.local_ip6_prefix_len),
1096 off_link=1,
1097 no_autoconfig=1,
1098 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001099
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001100 opt = [
1101 ICMPv6NDOptPrefixInfo(
1102 prefixlen=self.pg0.local_ip6_prefix_len,
1103 prefix=self.pg0.local_ip6,
1104 L=1,
1105 A=1,
1106 ),
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001107 ICMPv6NDOptPrefixInfo(
1108 prefixlen=self.pg1.local_ip6_prefix_len,
1109 prefix=self.pg1.local_ip6,
1110 L=0,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001111 A=0,
1112 ),
1113 ]
Neale Ranns87df12d2017-02-18 08:16:41 -08001114
1115 self.pg0.ip6_ra_config(send_unicast=1)
1116 ll = mk_ll_addr(self.pg0.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001117 p = (
1118 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1119 / IPv6(dst=self.pg0.local_ip6, src=ll)
1120 / ICMPv6ND_RS()
1121 )
1122 self.send_and_expect_ra(
1123 self.pg0, p, "RA with multiple Prefix infos", dst_ip=ll, opt=opt
1124 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001125
1126 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07001127 # Remove the first prefix-info - expect the second is still in the
Neale Ranns87df12d2017-02-18 08:16:41 -08001128 # advert
1129 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001130 self.pg0.ip6_ra_prefix(
1131 "%s/%s" % (self.pg0.local_ip6, self.pg0.local_ip6_prefix_len), is_no=1
1132 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001133
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001134 opt = ICMPv6NDOptPrefixInfo(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001135 prefixlen=self.pg1.local_ip6_prefix_len, prefix=self.pg1.local_ip6, L=0, A=0
1136 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001137
1138 self.pg0.ip6_ra_config(send_unicast=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001139 self.send_and_expect_ra(
1140 self.pg0, p, "RA with Prefix reverted to defaults", dst_ip=ll, opt=opt
1141 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001142
1143 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07001144 # Remove the second prefix-info - expect no prefix-info in the adverts
Neale Ranns87df12d2017-02-18 08:16:41 -08001145 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001146 self.pg0.ip6_ra_prefix(
1147 "%s/%s" % (self.pg1.local_ip6, self.pg1.local_ip6_prefix_len), is_no=1
1148 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001149
Neale Rannscbe25aa2019-09-30 10:53:31 +00001150 #
1151 # change the link's link local, so we know that works too.
1152 #
1153 self.vapi.sw_interface_ip6_set_link_local_address(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001154 sw_if_index=self.pg0.sw_if_index, ip="fe80::88"
1155 )
Neale Rannscbe25aa2019-09-30 10:53:31 +00001156
Neale Ranns87df12d2017-02-18 08:16:41 -08001157 self.pg0.ip6_ra_config(send_unicast=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001158 self.send_and_expect_ra(
1159 self.pg0,
1160 p,
1161 "RA with Prefix reverted to defaults",
1162 dst_ip=ll,
1163 src_ip="fe80::88",
1164 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001165
1166 #
Neale Ranns5737d882017-02-03 06:14:49 -08001167 # Reset the periodic advertisements back to default values
Neale Ranns75152282017-01-09 01:00:45 -08001168 #
Alexander Chernavine99f7622022-03-05 15:51:54 +00001169 self.pg0.ip6_ra_config(suppress=1)
1170 self.pg0.ip6_ra_config(no=1, send_unicast=1)
Damjan Marionf56b77a2016-10-03 19:44:57 +02001171
Neale Rannsf267d112020-02-07 09:45:07 +00001172 def test_mld(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001173 """MLD Report"""
Neale Rannsf267d112020-02-07 09:45:07 +00001174 #
1175 # test one MLD is sent after applying an IPv6 Address on an interface
1176 #
1177 self.pg_enable_capture(self.pg_interfaces)
1178 self.pg_start()
1179
1180 subitf = VppDot1QSubint(self, self.pg1, 99)
Vladislav Grishenko1fb62c02022-05-16 01:44:43 +05001181 self.interfaces.append(subitf)
1182 self.sub_interfaces.append(subitf)
Neale Rannsf267d112020-02-07 09:45:07 +00001183
1184 subitf.admin_up()
1185 subitf.config_ip6()
1186
Neale Ranns03c254e2020-03-17 14:25:10 +00001187 rxs = self.pg1._get_capture(timeout=4, filter_out_fn=None)
Neale Rannsf267d112020-02-07 09:45:07 +00001188
1189 #
1190 # hunt for the MLD on vlan 99
1191 #
1192 for rx in rxs:
1193 # make sure ipv6 packets with hop by hop options have
1194 # correct checksums
1195 self.assert_packet_checksums_valid(rx)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001196 if (
1197 rx.haslayer(IPv6ExtHdrHopByHop)
1198 and rx.haslayer(Dot1Q)
1199 and rx[Dot1Q].vlan == 99
1200 ):
Neale Rannsf267d112020-02-07 09:45:07 +00001201 mld = rx[ICMPv6MLReport2]
1202
1203 self.assertEqual(mld.records_number, 4)
1204
Neale Ranns3f844d02017-02-18 00:03:54 -08001205
Christian Hoppsf5d38e02020-05-04 10:28:03 -04001206class TestIPv6RouteLookup(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001207 """IPv6 Route Lookup Test Case"""
1208
Christian Hoppsf5d38e02020-05-04 10:28:03 -04001209 routes = []
1210
1211 def route_lookup(self, prefix, exact):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001212 return self.vapi.api(
1213 self.vapi.papi.ip_route_lookup,
1214 {
1215 "table_id": 0,
1216 "exact": exact,
1217 "prefix": prefix,
1218 },
1219 )
Christian Hoppsf5d38e02020-05-04 10:28:03 -04001220
1221 @classmethod
1222 def setUpClass(cls):
1223 super(TestIPv6RouteLookup, cls).setUpClass()
1224
1225 @classmethod
1226 def tearDownClass(cls):
1227 super(TestIPv6RouteLookup, cls).tearDownClass()
1228
1229 def setUp(self):
1230 super(TestIPv6RouteLookup, self).setUp()
1231
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001232 drop_nh = VppRoutePath("::1", 0xFFFFFFFF, type=FibPathType.FIB_PATH_TYPE_DROP)
Christian Hoppsf5d38e02020-05-04 10:28:03 -04001233
1234 # Add 3 routes
1235 r = VppIpRoute(self, "2001:1111::", 32, [drop_nh])
1236 r.add_vpp_config()
1237 self.routes.append(r)
1238
1239 r = VppIpRoute(self, "2001:1111:2222::", 48, [drop_nh])
1240 r.add_vpp_config()
1241 self.routes.append(r)
1242
1243 r = VppIpRoute(self, "2001:1111:2222::1", 128, [drop_nh])
1244 r.add_vpp_config()
1245 self.routes.append(r)
1246
1247 def tearDown(self):
1248 # Remove the routes we added
1249 for r in self.routes:
1250 r.remove_vpp_config()
1251
1252 super(TestIPv6RouteLookup, self).tearDown()
1253
1254 def test_exact_match(self):
1255 # Verify we find the host route
1256 prefix = "2001:1111:2222::1/128"
1257 result = self.route_lookup(prefix, True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001258 assert prefix == str(result.route.prefix)
Christian Hoppsf5d38e02020-05-04 10:28:03 -04001259
1260 # Verify we find a middle prefix route
1261 prefix = "2001:1111:2222::/48"
1262 result = self.route_lookup(prefix, True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001263 assert prefix == str(result.route.prefix)
Christian Hoppsf5d38e02020-05-04 10:28:03 -04001264
1265 # Verify we do not find an available LPM.
1266 with self.vapi.assert_negative_api_retval():
1267 self.route_lookup("2001::2/128", True)
1268
1269 def test_longest_prefix_match(self):
1270 # verify we find lpm
1271 lpm_prefix = "2001:1111:2222::/48"
1272 result = self.route_lookup("2001:1111:2222::2/128", False)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001273 assert lpm_prefix == str(result.route.prefix)
Christian Hoppsf5d38e02020-05-04 10:28:03 -04001274
1275 # Verify we find the exact when not requested
1276 result = self.route_lookup(lpm_prefix, False)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001277 assert lpm_prefix == str(result.route.prefix)
Christian Hoppsf5d38e02020-05-04 10:28:03 -04001278
1279 # Can't seem to delete the default route so no negative LPM test.
1280
1281
Matthew Smith6c92f5b2019-08-07 11:46:30 -05001282class TestIPv6IfAddrRoute(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001283 """IPv6 Interface Addr Route Test Case"""
Matthew Smith6c92f5b2019-08-07 11:46:30 -05001284
1285 @classmethod
1286 def setUpClass(cls):
1287 super(TestIPv6IfAddrRoute, cls).setUpClass()
1288
1289 @classmethod
1290 def tearDownClass(cls):
1291 super(TestIPv6IfAddrRoute, cls).tearDownClass()
1292
1293 def setUp(self):
1294 super(TestIPv6IfAddrRoute, self).setUp()
1295
1296 # create 1 pg interface
1297 self.create_pg_interfaces(range(1))
1298
1299 for i in self.pg_interfaces:
1300 i.admin_up()
1301 i.config_ip6()
1302 i.resolve_ndp()
1303
1304 def tearDown(self):
1305 super(TestIPv6IfAddrRoute, self).tearDown()
1306 for i in self.pg_interfaces:
1307 i.unconfig_ip6()
1308 i.admin_down()
1309
1310 def test_ipv6_ifaddrs_same_prefix(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001311 """IPv6 Interface Addresses Same Prefix test
Matthew Smith6c92f5b2019-08-07 11:46:30 -05001312
1313 Test scenario:
1314
1315 - Verify no route in FIB for prefix 2001:10::/64
1316 - Configure IPv4 address 2001:10::10/64 on an interface
1317 - Verify route in FIB for prefix 2001:10::/64
1318 - Configure IPv4 address 2001:10::20/64 on an interface
1319 - Delete 2001:10::10/64 from interface
1320 - Verify route in FIB for prefix 2001:10::/64
1321 - Delete 2001:10::20/64 from interface
1322 - Verify no route in FIB for prefix 2001:10::/64
1323 """
1324
1325 addr1 = "2001:10::10"
1326 addr2 = "2001:10::20"
1327
Neale Rannsefd7bc22019-11-11 08:32:34 +00001328 if_addr1 = VppIpInterfaceAddress(self, self.pg0, addr1, 64)
1329 if_addr2 = VppIpInterfaceAddress(self, self.pg0, addr2, 64)
1330 self.assertFalse(if_addr1.query_vpp_config())
Matthew Smith6c92f5b2019-08-07 11:46:30 -05001331 self.assertFalse(find_route(self, addr1, 128))
1332 self.assertFalse(find_route(self, addr2, 128))
1333
1334 # configure first address, verify route present
1335 if_addr1.add_vpp_config()
Neale Rannsefd7bc22019-11-11 08:32:34 +00001336 self.assertTrue(if_addr1.query_vpp_config())
Matthew Smith6c92f5b2019-08-07 11:46:30 -05001337 self.assertTrue(find_route(self, addr1, 128))
1338 self.assertFalse(find_route(self, addr2, 128))
1339
1340 # configure second address, delete first, verify route not removed
1341 if_addr2.add_vpp_config()
1342 if_addr1.remove_vpp_config()
Neale Rannsefd7bc22019-11-11 08:32:34 +00001343 self.assertFalse(if_addr1.query_vpp_config())
1344 self.assertTrue(if_addr2.query_vpp_config())
Matthew Smith6c92f5b2019-08-07 11:46:30 -05001345 self.assertFalse(find_route(self, addr1, 128))
1346 self.assertTrue(find_route(self, addr2, 128))
1347
1348 # delete second address, verify route removed
1349 if_addr2.remove_vpp_config()
Neale Rannsefd7bc22019-11-11 08:32:34 +00001350 self.assertFalse(if_addr1.query_vpp_config())
Matthew Smith6c92f5b2019-08-07 11:46:30 -05001351 self.assertFalse(find_route(self, addr1, 128))
1352 self.assertFalse(find_route(self, addr2, 128))
1353
yedgdbd366b2020-05-14 10:51:53 +08001354 def test_ipv6_ifaddr_del(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001355 """Delete an interface address that does not exist"""
yedgdbd366b2020-05-14 10:51:53 +08001356
1357 loopbacks = self.create_loopback_interfaces(1)
1358 lo = self.lo_interfaces[0]
1359
1360 lo.config_ip6()
1361 lo.admin_up()
1362
1363 #
1364 # try and remove pg0's subnet from lo
1365 #
1366 with self.vapi.assert_negative_api_retval():
1367 self.vapi.sw_interface_add_del_address(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001368 sw_if_index=lo.sw_if_index, prefix=self.pg0.local_ip6_prefix, is_add=0
1369 )
yedgdbd366b2020-05-14 10:51:53 +08001370
Matthew Smith6c92f5b2019-08-07 11:46:30 -05001371
Dmitry Valter34fa0ce2024-03-11 10:38:46 +00001372@unittest.skipIf(
1373 "ping" in config.excluded_plugins, "Exclude tests requiring Ping plugin"
1374)
Jan Geletye6c78ee2018-06-26 12:24:03 +02001375class TestICMPv6Echo(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001376 """ICMPv6 Echo Test Case"""
Jan Geletye6c78ee2018-06-26 12:24:03 +02001377
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001378 @classmethod
1379 def setUpClass(cls):
1380 super(TestICMPv6Echo, cls).setUpClass()
1381
1382 @classmethod
1383 def tearDownClass(cls):
1384 super(TestICMPv6Echo, cls).tearDownClass()
1385
Jan Geletye6c78ee2018-06-26 12:24:03 +02001386 def setUp(self):
1387 super(TestICMPv6Echo, self).setUp()
1388
1389 # create 1 pg interface
1390 self.create_pg_interfaces(range(1))
1391
1392 for i in self.pg_interfaces:
1393 i.admin_up()
1394 i.config_ip6()
Benoît Ganne2699fe22021-01-18 19:25:38 +01001395 i.resolve_ndp(link_layer=True)
Jan Geletye6c78ee2018-06-26 12:24:03 +02001396 i.resolve_ndp()
1397
1398 def tearDown(self):
1399 super(TestICMPv6Echo, self).tearDown()
1400 for i in self.pg_interfaces:
1401 i.unconfig_ip6()
Jan Geletye6c78ee2018-06-26 12:24:03 +02001402 i.admin_down()
1403
1404 def test_icmpv6_echo(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001405 """VPP replies to ICMPv6 Echo Request
Jan Geletye6c78ee2018-06-26 12:24:03 +02001406
1407 Test scenario:
1408
1409 - Receive ICMPv6 Echo Request message on pg0 interface.
1410 - Check outgoing ICMPv6 Echo Reply message on pg0 interface.
1411 """
1412
Benoît Ganne2699fe22021-01-18 19:25:38 +01001413 # test both with global and local ipv6 addresses
1414 dsts = (self.pg0.local_ip6, self.pg0.local_ip6_ll)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001415 id = 0xB
Benoît Ganne2699fe22021-01-18 19:25:38 +01001416 seq = 5
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001417 data = b"\x0a" * 18
Benoît Ganne2699fe22021-01-18 19:25:38 +01001418 p = list()
1419 for dst in dsts:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001420 p.append(
1421 (
1422 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1423 / IPv6(src=self.pg0.remote_ip6, dst=dst)
1424 / ICMPv6EchoRequest(id=id, seq=seq, data=data)
1425 )
1426 )
Jan Geletye6c78ee2018-06-26 12:24:03 +02001427
Benoît Ganne2699fe22021-01-18 19:25:38 +01001428 self.pg0.add_stream(p)
Jan Geletye6c78ee2018-06-26 12:24:03 +02001429 self.pg_enable_capture(self.pg_interfaces)
1430 self.pg_start()
Benoît Ganne2699fe22021-01-18 19:25:38 +01001431 rxs = self.pg0.get_capture(len(dsts))
Jan Geletye6c78ee2018-06-26 12:24:03 +02001432
Benoît Ganne2699fe22021-01-18 19:25:38 +01001433 for rx, dst in zip(rxs, dsts):
1434 ether = rx[Ether]
1435 ipv6 = rx[IPv6]
1436 icmpv6 = rx[ICMPv6EchoReply]
1437 self.assertEqual(ether.src, self.pg0.local_mac)
1438 self.assertEqual(ether.dst, self.pg0.remote_mac)
1439 self.assertEqual(ipv6.src, dst)
1440 self.assertEqual(ipv6.dst, self.pg0.remote_ip6)
1441 self.assertEqual(icmp6types[icmpv6.type], "Echo Reply")
1442 self.assertEqual(icmpv6.id, id)
1443 self.assertEqual(icmpv6.seq, seq)
1444 self.assertEqual(icmpv6.data, data)
Jan Geletye6c78ee2018-06-26 12:24:03 +02001445
1446
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001447class TestIPv6RD(TestIPv6ND):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001448 """IPv6 Router Discovery Test Case"""
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001449
1450 @classmethod
1451 def setUpClass(cls):
1452 super(TestIPv6RD, cls).setUpClass()
1453
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001454 @classmethod
1455 def tearDownClass(cls):
1456 super(TestIPv6RD, cls).tearDownClass()
1457
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001458 def setUp(self):
1459 super(TestIPv6RD, self).setUp()
1460
1461 # create 2 pg interfaces
1462 self.create_pg_interfaces(range(2))
1463
1464 self.interfaces = list(self.pg_interfaces)
1465
1466 # setup all interfaces
1467 for i in self.interfaces:
1468 i.admin_up()
1469 i.config_ip6()
1470
1471 def tearDown(self):
Neale Ranns744902e2017-08-14 10:35:44 -07001472 for i in self.interfaces:
1473 i.unconfig_ip6()
1474 i.admin_down()
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001475 super(TestIPv6RD, self).tearDown()
1476
1477 def test_rd_send_router_solicitation(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001478 """Verify router solicitation packets"""
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001479
1480 count = 2
1481 self.pg_enable_capture(self.pg_interfaces)
1482 self.pg_start()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001483 self.vapi.ip6nd_send_router_solicitation(self.pg1.sw_if_index, mrc=count)
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001484 rx_list = self.pg1.get_capture(count, timeout=3)
1485 self.assertEqual(len(rx_list), count)
1486 for packet in rx_list:
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001487 self.assertEqual(packet.haslayer(IPv6), 1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001488 self.assertEqual(packet[IPv6].haslayer(ICMPv6ND_RS), 1)
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001489 dst = ip6_normalize(packet[IPv6].dst)
1490 dst2 = ip6_normalize("ff02::2")
1491 self.assert_equal(dst, dst2)
1492 src = ip6_normalize(packet[IPv6].src)
1493 src2 = ip6_normalize(self.pg1.local_ip6_ll)
1494 self.assert_equal(src, src2)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001495 self.assertTrue(bool(packet[ICMPv6ND_RS].haslayer(ICMPv6NDOptSrcLLAddr)))
1496 self.assert_equal(packet[ICMPv6NDOptSrcLLAddr].lladdr, self.pg1.local_mac)
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001497
1498 def verify_prefix_info(self, reported_prefix, prefix_option):
Neale Ranns37029302018-08-10 05:30:06 -07001499 prefix = IPv6Network(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001500 text_type(
1501 prefix_option.getfieldval("prefix")
1502 + "/"
1503 + text_type(prefix_option.getfieldval("prefixlen"))
1504 ),
1505 strict=False,
1506 )
1507 self.assert_equal(
1508 reported_prefix.prefix.network_address, prefix.network_address
1509 )
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001510 L = prefix_option.getfieldval("L")
1511 A = prefix_option.getfieldval("A")
1512 option_flags = (L << 7) | (A << 6)
1513 self.assert_equal(reported_prefix.flags, option_flags)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001514 self.assert_equal(
1515 reported_prefix.valid_time, prefix_option.getfieldval("validlifetime")
1516 )
1517 self.assert_equal(
1518 reported_prefix.preferred_time,
1519 prefix_option.getfieldval("preferredlifetime"),
1520 )
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001521
1522 def test_rd_receive_router_advertisement(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001523 """Verify events triggered by received RA packets"""
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001524
Neale Rannscbe25aa2019-09-30 10:53:31 +00001525 self.vapi.want_ip6_ra_events(enable=1)
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001526
1527 prefix_info_1 = ICMPv6NDOptPrefixInfo(
1528 prefix="1::2",
1529 prefixlen=50,
1530 validlifetime=200,
1531 preferredlifetime=500,
1532 L=1,
1533 A=1,
1534 )
1535
1536 prefix_info_2 = ICMPv6NDOptPrefixInfo(
1537 prefix="7::4",
1538 prefixlen=20,
1539 validlifetime=70,
1540 preferredlifetime=1000,
1541 L=1,
1542 A=0,
1543 )
1544
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001545 p = (
1546 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
1547 / IPv6(dst=self.pg1.local_ip6_ll, src=mk_ll_addr(self.pg1.remote_mac))
1548 / ICMPv6ND_RA()
1549 / prefix_info_1
1550 / prefix_info_2
1551 )
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001552 self.pg1.add_stream([p])
1553 self.pg_start()
1554
1555 ev = self.vapi.wait_for_event(10, "ip6_ra_event")
1556
1557 self.assert_equal(ev.current_hop_limit, 0)
1558 self.assert_equal(ev.flags, 8)
1559 self.assert_equal(ev.router_lifetime_in_sec, 1800)
1560 self.assert_equal(ev.neighbor_reachable_time_in_msec, 0)
1561 self.assert_equal(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001562 ev.time_in_msec_between_retransmitted_neighbor_solicitations, 0
1563 )
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001564
1565 self.assert_equal(ev.n_prefixes, 2)
1566
1567 self.verify_prefix_info(ev.prefixes[0], prefix_info_1)
1568 self.verify_prefix_info(ev.prefixes[1], prefix_info_2)
1569
1570
Juraj Slobodac0374232018-02-01 15:18:49 +01001571class TestIPv6RDControlPlane(TestIPv6ND):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001572 """IPv6 Router Discovery Control Plane Test Case"""
Juraj Slobodac0374232018-02-01 15:18:49 +01001573
1574 @classmethod
1575 def setUpClass(cls):
1576 super(TestIPv6RDControlPlane, cls).setUpClass()
1577
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001578 @classmethod
1579 def tearDownClass(cls):
1580 super(TestIPv6RDControlPlane, cls).tearDownClass()
1581
Juraj Slobodac0374232018-02-01 15:18:49 +01001582 def setUp(self):
1583 super(TestIPv6RDControlPlane, self).setUp()
1584
1585 # create 1 pg interface
1586 self.create_pg_interfaces(range(1))
1587
1588 self.interfaces = list(self.pg_interfaces)
1589
1590 # setup all interfaces
1591 for i in self.interfaces:
1592 i.admin_up()
1593 i.config_ip6()
1594
1595 def tearDown(self):
1596 super(TestIPv6RDControlPlane, self).tearDown()
1597
1598 @staticmethod
1599 def create_ra_packet(pg, routerlifetime=None):
1600 src_ip = pg.remote_ip6_ll
1601 dst_ip = pg.local_ip6
1602 if routerlifetime is not None:
1603 ra = ICMPv6ND_RA(routerlifetime=routerlifetime)
1604 else:
1605 ra = ICMPv6ND_RA()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001606 p = (
1607 Ether(dst=pg.local_mac, src=pg.remote_mac)
1608 / IPv6(dst=dst_ip, src=src_ip)
1609 / ra
1610 )
Juraj Slobodac0374232018-02-01 15:18:49 +01001611 return p
1612
1613 @staticmethod
1614 def get_default_routes(fib):
1615 list = []
1616 for entry in fib:
Neale Ranns097fa662018-05-01 05:17:55 -07001617 if entry.route.prefix.prefixlen == 0:
1618 for path in entry.route.paths:
Juraj Slobodac0374232018-02-01 15:18:49 +01001619 if path.sw_if_index != 0xFFFFFFFF:
Neale Ranns097fa662018-05-01 05:17:55 -07001620 defaut_route = {}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001621 defaut_route["sw_if_index"] = path.sw_if_index
1622 defaut_route["next_hop"] = path.nh.address.ip6
Neale Ranns097fa662018-05-01 05:17:55 -07001623 list.append(defaut_route)
Juraj Slobodac0374232018-02-01 15:18:49 +01001624 return list
1625
1626 @staticmethod
1627 def get_interface_addresses(fib, pg):
1628 list = []
1629 for entry in fib:
Neale Ranns097fa662018-05-01 05:17:55 -07001630 if entry.route.prefix.prefixlen == 128:
1631 path = entry.route.paths[0]
Juraj Slobodac0374232018-02-01 15:18:49 +01001632 if path.sw_if_index == pg.sw_if_index:
Neale Ranns097fa662018-05-01 05:17:55 -07001633 list.append(str(entry.route.prefix.network_address))
Juraj Slobodac0374232018-02-01 15:18:49 +01001634 return list
1635
Neale Rannscbe25aa2019-09-30 10:53:31 +00001636 def wait_for_no_default_route(self, n_tries=50, s_time=1):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001637 while n_tries:
Neale Rannscbe25aa2019-09-30 10:53:31 +00001638 fib = self.vapi.ip_route_dump(0, True)
1639 default_routes = self.get_default_routes(fib)
Ole Troan6e6ad642020-02-04 13:28:13 +01001640 if 0 == len(default_routes):
Neale Rannscbe25aa2019-09-30 10:53:31 +00001641 return True
1642 n_tries = n_tries - 1
1643 self.sleep(s_time)
1644
1645 return False
1646
Juraj Slobodac0374232018-02-01 15:18:49 +01001647 def test_all(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001648 """Test handling of SLAAC addresses and default routes"""
Juraj Slobodac0374232018-02-01 15:18:49 +01001649
Neale Ranns097fa662018-05-01 05:17:55 -07001650 fib = self.vapi.ip_route_dump(0, True)
Juraj Slobodac0374232018-02-01 15:18:49 +01001651 default_routes = self.get_default_routes(fib)
1652 initial_addresses = set(self.get_interface_addresses(fib, self.pg0))
1653 self.assertEqual(default_routes, [])
Neale Ranns097fa662018-05-01 05:17:55 -07001654 router_address = IPv6Address(text_type(self.pg0.remote_ip6_ll))
Juraj Slobodac0374232018-02-01 15:18:49 +01001655
1656 self.vapi.ip6_nd_address_autoconfig(self.pg0.sw_if_index, 1, 1)
1657
1658 self.sleep(0.1)
1659
1660 # send RA
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001661 packet = (
1662 self.create_ra_packet(self.pg0)
1663 / ICMPv6NDOptPrefixInfo(
1664 prefix="1::",
1665 prefixlen=64,
1666 validlifetime=2,
1667 preferredlifetime=2,
1668 L=1,
1669 A=1,
1670 )
1671 / ICMPv6NDOptPrefixInfo(
1672 prefix="7::",
1673 prefixlen=20,
1674 validlifetime=1500,
1675 preferredlifetime=1000,
1676 L=1,
1677 A=0,
1678 )
1679 )
Juraj Slobodac0374232018-02-01 15:18:49 +01001680 self.pg0.add_stream([packet])
1681 self.pg_start()
1682
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +00001683 self.sleep_on_vpp_time(0.1)
Juraj Slobodac0374232018-02-01 15:18:49 +01001684
Neale Ranns097fa662018-05-01 05:17:55 -07001685 fib = self.vapi.ip_route_dump(0, True)
Juraj Slobodac0374232018-02-01 15:18:49 +01001686
1687 # check FIB for new address
1688 addresses = set(self.get_interface_addresses(fib, self.pg0))
1689 new_addresses = addresses.difference(initial_addresses)
1690 self.assertEqual(len(new_addresses), 1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001691 prefix = IPv6Network(
1692 text_type("%s/%d" % (list(new_addresses)[0], 20)), strict=False
1693 )
1694 self.assertEqual(prefix, IPv6Network(text_type("1::/20")))
Juraj Slobodac0374232018-02-01 15:18:49 +01001695
1696 # check FIB for new default route
1697 default_routes = self.get_default_routes(fib)
1698 self.assertEqual(len(default_routes), 1)
1699 dr = default_routes[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001700 self.assertEqual(dr["sw_if_index"], self.pg0.sw_if_index)
1701 self.assertEqual(dr["next_hop"], router_address)
Juraj Slobodac0374232018-02-01 15:18:49 +01001702
1703 # send RA to delete default route
1704 packet = self.create_ra_packet(self.pg0, routerlifetime=0)
1705 self.pg0.add_stream([packet])
1706 self.pg_start()
1707
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +00001708 self.sleep_on_vpp_time(0.1)
Juraj Slobodac0374232018-02-01 15:18:49 +01001709
1710 # check that default route is deleted
Neale Ranns097fa662018-05-01 05:17:55 -07001711 fib = self.vapi.ip_route_dump(0, True)
Juraj Slobodac0374232018-02-01 15:18:49 +01001712 default_routes = self.get_default_routes(fib)
1713 self.assertEqual(len(default_routes), 0)
1714
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +00001715 self.sleep_on_vpp_time(0.1)
Juraj Slobodac0374232018-02-01 15:18:49 +01001716
1717 # send RA
1718 packet = self.create_ra_packet(self.pg0)
1719 self.pg0.add_stream([packet])
1720 self.pg_start()
1721
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +00001722 self.sleep_on_vpp_time(0.1)
Juraj Slobodac0374232018-02-01 15:18:49 +01001723
1724 # check FIB for new default route
Neale Ranns097fa662018-05-01 05:17:55 -07001725 fib = self.vapi.ip_route_dump(0, True)
Juraj Slobodac0374232018-02-01 15:18:49 +01001726 default_routes = self.get_default_routes(fib)
1727 self.assertEqual(len(default_routes), 1)
1728 dr = default_routes[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001729 self.assertEqual(dr["sw_if_index"], self.pg0.sw_if_index)
1730 self.assertEqual(dr["next_hop"], router_address)
Juraj Slobodac0374232018-02-01 15:18:49 +01001731
1732 # send RA, updating router lifetime to 1s
1733 packet = self.create_ra_packet(self.pg0, 1)
1734 self.pg0.add_stream([packet])
1735 self.pg_start()
1736
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +00001737 self.sleep_on_vpp_time(0.1)
Juraj Slobodac0374232018-02-01 15:18:49 +01001738
1739 # check that default route still exists
Neale Ranns097fa662018-05-01 05:17:55 -07001740 fib = self.vapi.ip_route_dump(0, True)
Juraj Slobodac0374232018-02-01 15:18:49 +01001741 default_routes = self.get_default_routes(fib)
1742 self.assertEqual(len(default_routes), 1)
1743 dr = default_routes[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001744 self.assertEqual(dr["sw_if_index"], self.pg0.sw_if_index)
1745 self.assertEqual(dr["next_hop"], router_address)
Juraj Slobodac0374232018-02-01 15:18:49 +01001746
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +00001747 self.sleep_on_vpp_time(1)
Juraj Slobodac0374232018-02-01 15:18:49 +01001748
1749 # check that default route is deleted
Neale Rannscbe25aa2019-09-30 10:53:31 +00001750 self.assertTrue(self.wait_for_no_default_route())
Juraj Slobodac0374232018-02-01 15:18:49 +01001751
1752 # check FIB still contains the SLAAC address
1753 addresses = set(self.get_interface_addresses(fib, self.pg0))
1754 new_addresses = addresses.difference(initial_addresses)
Paul Vinciguerra4271c972019-05-14 13:25:49 -04001755
Juraj Slobodac0374232018-02-01 15:18:49 +01001756 self.assertEqual(len(new_addresses), 1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001757 prefix = IPv6Network(
1758 text_type("%s/%d" % (list(new_addresses)[0], 20)), strict=False
1759 )
1760 self.assertEqual(prefix, IPv6Network(text_type("1::/20")))
Juraj Slobodac0374232018-02-01 15:18:49 +01001761
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +00001762 self.sleep_on_vpp_time(1)
Juraj Slobodac0374232018-02-01 15:18:49 +01001763
1764 # check that SLAAC address is deleted
Neale Ranns097fa662018-05-01 05:17:55 -07001765 fib = self.vapi.ip_route_dump(0, True)
Juraj Slobodac0374232018-02-01 15:18:49 +01001766 addresses = set(self.get_interface_addresses(fib, self.pg0))
1767 new_addresses = addresses.difference(initial_addresses)
1768 self.assertEqual(len(new_addresses), 0)
1769
1770
Neale Ranns3f844d02017-02-18 00:03:54 -08001771class IPv6NDProxyTest(TestIPv6ND):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001772 """IPv6 ND ProxyTest Case"""
Neale Ranns3f844d02017-02-18 00:03:54 -08001773
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001774 @classmethod
1775 def setUpClass(cls):
1776 super(IPv6NDProxyTest, cls).setUpClass()
1777
1778 @classmethod
1779 def tearDownClass(cls):
1780 super(IPv6NDProxyTest, cls).tearDownClass()
1781
Neale Ranns3f844d02017-02-18 00:03:54 -08001782 def setUp(self):
1783 super(IPv6NDProxyTest, self).setUp()
1784
1785 # create 3 pg interfaces
1786 self.create_pg_interfaces(range(3))
1787
1788 # pg0 is the master interface, with the configured subnet
1789 self.pg0.admin_up()
1790 self.pg0.config_ip6()
1791 self.pg0.resolve_ndp()
1792
1793 self.pg1.ip6_enable()
1794 self.pg2.ip6_enable()
1795
1796 def tearDown(self):
1797 super(IPv6NDProxyTest, self).tearDown()
1798
1799 def test_nd_proxy(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001800 """IPv6 Proxy ND"""
Neale Ranns3f844d02017-02-18 00:03:54 -08001801
1802 #
1803 # Generate some hosts in the subnet that we are proxying
1804 #
1805 self.pg0.generate_remote_hosts(8)
1806
1807 nsma = in6_getnsma(inet_pton(AF_INET6, self.pg0.local_ip6))
1808 d = inet_ntop(AF_INET6, nsma)
1809
1810 #
1811 # Send an NS for one of those remote hosts on one of the proxy links
1812 # expect no response since it's from an address that is not
1813 # on the link that has the prefix configured
1814 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001815 ns_pg1 = (
1816 Ether(dst=in6_getnsmac(nsma), src=self.pg1.remote_mac)
1817 / IPv6(dst=d, src=self.pg0._remote_hosts[2].ip6)
1818 / ICMPv6ND_NS(tgt=self.pg0.local_ip6)
1819 / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0._remote_hosts[2].mac)
1820 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001821
1822 self.send_and_assert_no_replies(self.pg1, ns_pg1, "Off link NS")
1823
1824 #
1825 # Add proxy support for the host
1826 #
Ole Troane1ade682019-03-04 23:55:43 +01001827 self.vapi.ip6nd_proxy_add_del(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001828 is_add=1,
1829 ip=inet_pton(AF_INET6, self.pg0._remote_hosts[2].ip6),
1830 sw_if_index=self.pg1.sw_if_index,
1831 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001832
1833 #
1834 # try that NS again. this time we expect an NA back
1835 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001836 self.send_and_expect_na(
1837 self.pg1,
1838 ns_pg1,
1839 "NS to proxy entry",
1840 dst_ip=self.pg0._remote_hosts[2].ip6,
1841 tgt_ip=self.pg0.local_ip6,
1842 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001843
1844 #
1845 # ... and that we have an entry in the ND cache
1846 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001847 self.assertTrue(
1848 find_nbr(self, self.pg1.sw_if_index, self.pg0._remote_hosts[2].ip6)
1849 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001850
1851 #
1852 # ... and we can route traffic to it
1853 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001854 t = (
1855 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1856 / IPv6(dst=self.pg0._remote_hosts[2].ip6, src=self.pg0.remote_ip6)
1857 / inet6.UDP(sport=10000, dport=20000)
1858 / Raw(b"\xa5" * 100)
1859 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001860
1861 self.pg0.add_stream(t)
1862 self.pg_enable_capture(self.pg_interfaces)
1863 self.pg_start()
1864 rx = self.pg1.get_capture(1)
1865 rx = rx[0]
1866
1867 self.assertEqual(rx[Ether].dst, self.pg0._remote_hosts[2].mac)
1868 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1869
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001870 self.assertEqual(rx[IPv6].src, t[IPv6].src)
1871 self.assertEqual(rx[IPv6].dst, t[IPv6].dst)
Neale Ranns3f844d02017-02-18 00:03:54 -08001872
1873 #
1874 # Test we proxy for the host on the main interface
1875 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001876 ns_pg0 = (
1877 Ether(dst=in6_getnsmac(nsma), src=self.pg0.remote_mac)
1878 / IPv6(dst=d, src=self.pg0.remote_ip6)
1879 / ICMPv6ND_NS(tgt=self.pg0._remote_hosts[2].ip6)
1880 / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)
1881 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001882
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001883 self.send_and_expect_na(
1884 self.pg0,
1885 ns_pg0,
1886 "NS to proxy entry on main",
1887 tgt_ip=self.pg0._remote_hosts[2].ip6,
1888 dst_ip=self.pg0.remote_ip6,
1889 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001890
1891 #
1892 # Setup and resolve proxy for another host on another interface
1893 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001894 ns_pg2 = (
1895 Ether(dst=in6_getnsmac(nsma), src=self.pg2.remote_mac)
1896 / IPv6(dst=d, src=self.pg0._remote_hosts[3].ip6)
1897 / ICMPv6ND_NS(tgt=self.pg0.local_ip6)
1898 / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0._remote_hosts[2].mac)
1899 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001900
Ole Troane1ade682019-03-04 23:55:43 +01001901 self.vapi.ip6nd_proxy_add_del(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001902 is_add=1,
1903 ip=inet_pton(AF_INET6, self.pg0._remote_hosts[3].ip6),
1904 sw_if_index=self.pg2.sw_if_index,
1905 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001906
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001907 self.send_and_expect_na(
1908 self.pg2,
1909 ns_pg2,
1910 "NS to proxy entry other interface",
1911 dst_ip=self.pg0._remote_hosts[3].ip6,
1912 tgt_ip=self.pg0.local_ip6,
1913 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001914
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001915 self.assertTrue(
1916 find_nbr(self, self.pg2.sw_if_index, self.pg0._remote_hosts[3].ip6)
1917 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001918
1919 #
1920 # hosts can communicate. pg2->pg1
1921 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001922 t2 = (
1923 Ether(dst=self.pg2.local_mac, src=self.pg0.remote_hosts[3].mac)
1924 / IPv6(dst=self.pg0._remote_hosts[2].ip6, src=self.pg0._remote_hosts[3].ip6)
1925 / inet6.UDP(sport=10000, dport=20000)
1926 / Raw(b"\xa5" * 100)
1927 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001928
1929 self.pg2.add_stream(t2)
1930 self.pg_enable_capture(self.pg_interfaces)
1931 self.pg_start()
1932 rx = self.pg1.get_capture(1)
1933 rx = rx[0]
1934
1935 self.assertEqual(rx[Ether].dst, self.pg0._remote_hosts[2].mac)
1936 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1937
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001938 self.assertEqual(rx[IPv6].src, t2[IPv6].src)
1939 self.assertEqual(rx[IPv6].dst, t2[IPv6].dst)
Neale Ranns3f844d02017-02-18 00:03:54 -08001940
1941 #
1942 # remove the proxy configs
1943 #
Ole Troane1ade682019-03-04 23:55:43 +01001944 self.vapi.ip6nd_proxy_add_del(
Ole Troan9a475372019-03-05 16:58:24 +01001945 ip=inet_pton(AF_INET6, self.pg0._remote_hosts[2].ip6),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001946 sw_if_index=self.pg1.sw_if_index,
1947 is_add=0,
1948 )
Ole Troane1ade682019-03-04 23:55:43 +01001949 self.vapi.ip6nd_proxy_add_del(
Ole Troan9a475372019-03-05 16:58:24 +01001950 ip=inet_pton(AF_INET6, self.pg0._remote_hosts[3].ip6),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001951 sw_if_index=self.pg2.sw_if_index,
1952 is_add=0,
1953 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001954
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001955 self.assertFalse(
1956 find_nbr(self, self.pg2.sw_if_index, self.pg0._remote_hosts[3].ip6)
1957 )
1958 self.assertFalse(
1959 find_nbr(self, self.pg1.sw_if_index, self.pg0._remote_hosts[2].ip6)
1960 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001961
1962 #
1963 # no longer proxy-ing...
1964 #
1965 self.send_and_assert_no_replies(self.pg0, ns_pg0, "Proxy unconfigured")
1966 self.send_and_assert_no_replies(self.pg1, ns_pg1, "Proxy unconfigured")
1967 self.send_and_assert_no_replies(self.pg2, ns_pg2, "Proxy unconfigured")
1968
1969 #
1970 # no longer forwarding. traffic generates NS out of the glean/main
1971 # interface
1972 #
1973 self.pg2.add_stream(t2)
1974 self.pg_enable_capture(self.pg_interfaces)
1975 self.pg_start()
1976
1977 rx = self.pg0.get_capture(1)
1978
1979 self.assertTrue(rx[0].haslayer(ICMPv6ND_NS))
1980
1981
Tianyu Li6d95f8c2022-02-25 05:51:10 +00001982class TestIP6Null(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001983 """IPv6 routes via NULL"""
Neale Ranns37be7362017-02-21 17:30:26 -08001984
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001985 @classmethod
1986 def setUpClass(cls):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00001987 super(TestIP6Null, cls).setUpClass()
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001988
1989 @classmethod
1990 def tearDownClass(cls):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00001991 super(TestIP6Null, cls).tearDownClass()
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001992
Neale Ranns37be7362017-02-21 17:30:26 -08001993 def setUp(self):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00001994 super(TestIP6Null, self).setUp()
Neale Ranns37be7362017-02-21 17:30:26 -08001995
1996 # create 2 pg interfaces
1997 self.create_pg_interfaces(range(1))
1998
1999 for i in self.pg_interfaces:
2000 i.admin_up()
2001 i.config_ip6()
2002 i.resolve_ndp()
2003
2004 def tearDown(self):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00002005 super(TestIP6Null, self).tearDown()
Neale Ranns37be7362017-02-21 17:30:26 -08002006 for i in self.pg_interfaces:
2007 i.unconfig_ip6()
2008 i.admin_down()
2009
2010 def test_ip_null(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002011 """IP NULL route"""
Neale Ranns37be7362017-02-21 17:30:26 -08002012
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002013 p = (
2014 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2015 / IPv6(src=self.pg0.remote_ip6, dst="2001::1")
2016 / inet6.UDP(sport=1234, dport=1234)
2017 / Raw(b"\xa5" * 100)
2018 )
Neale Ranns37be7362017-02-21 17:30:26 -08002019
2020 #
2021 # A route via IP NULL that will reply with ICMP unreachables
2022 #
Neale Ranns097fa662018-05-01 05:17:55 -07002023 ip_unreach = VppIpRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002024 self,
2025 "2001::",
2026 64,
2027 [
2028 VppRoutePath(
2029 "::", 0xFFFFFFFF, type=FibPathType.FIB_PATH_TYPE_ICMP_UNREACH
2030 )
2031 ],
2032 )
Neale Ranns37be7362017-02-21 17:30:26 -08002033 ip_unreach.add_vpp_config()
2034
2035 self.pg0.add_stream(p)
2036 self.pg_enable_capture(self.pg_interfaces)
2037 self.pg_start()
2038
2039 rx = self.pg0.get_capture(1)
2040 rx = rx[0]
2041 icmp = rx[ICMPv6DestUnreach]
2042
2043 # 0 = "No route to destination"
2044 self.assertEqual(icmp.code, 0)
2045
2046 # ICMP is rate limited. pause a bit
2047 self.sleep(1)
2048
2049 #
2050 # A route via IP NULL that will reply with ICMP prohibited
2051 #
Neale Ranns097fa662018-05-01 05:17:55 -07002052 ip_prohibit = VppIpRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002053 self,
2054 "2001::1",
2055 128,
2056 [
2057 VppRoutePath(
2058 "::", 0xFFFFFFFF, type=FibPathType.FIB_PATH_TYPE_ICMP_PROHIBIT
2059 )
2060 ],
2061 )
Neale Ranns37be7362017-02-21 17:30:26 -08002062 ip_prohibit.add_vpp_config()
2063
2064 self.pg0.add_stream(p)
2065 self.pg_enable_capture(self.pg_interfaces)
2066 self.pg_start()
2067
2068 rx = self.pg0.get_capture(1)
2069 rx = rx[0]
2070 icmp = rx[ICMPv6DestUnreach]
2071
2072 # 1 = "Communication with destination administratively prohibited"
2073 self.assertEqual(icmp.code, 1)
2074
2075
Tianyu Li6d95f8c2022-02-25 05:51:10 +00002076class TestIP6Disabled(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002077 """IPv6 disabled"""
Neale Ranns180279b2017-03-16 15:49:09 -04002078
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002079 @classmethod
2080 def setUpClass(cls):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00002081 super(TestIP6Disabled, cls).setUpClass()
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002082
2083 @classmethod
2084 def tearDownClass(cls):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00002085 super(TestIP6Disabled, cls).tearDownClass()
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002086
Neale Ranns180279b2017-03-16 15:49:09 -04002087 def setUp(self):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00002088 super(TestIP6Disabled, self).setUp()
Neale Ranns180279b2017-03-16 15:49:09 -04002089
2090 # create 2 pg interfaces
2091 self.create_pg_interfaces(range(2))
2092
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07002093 # PG0 is IP enabled
Neale Ranns180279b2017-03-16 15:49:09 -04002094 self.pg0.admin_up()
2095 self.pg0.config_ip6()
2096 self.pg0.resolve_ndp()
2097
2098 # PG 1 is not IP enabled
2099 self.pg1.admin_up()
2100
2101 def tearDown(self):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00002102 super(TestIP6Disabled, self).tearDown()
Neale Ranns180279b2017-03-16 15:49:09 -04002103 for i in self.pg_interfaces:
2104 i.unconfig_ip4()
2105 i.admin_down()
2106
Neale Ranns180279b2017-03-16 15:49:09 -04002107 def test_ip_disabled(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002108 """IP Disabled"""
Neale Ranns180279b2017-03-16 15:49:09 -04002109
Neale Ranns990f6942020-10-20 07:20:17 +00002110 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
2111 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
Neale Ranns180279b2017-03-16 15:49:09 -04002112 #
2113 # An (S,G).
2114 # one accepting interface, pg0, 2 forwarding interfaces
2115 #
2116 route_ff_01 = VppIpMRoute(
2117 self,
2118 "::",
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002119 "ffef::1",
2120 128,
Neale Ranns990f6942020-10-20 07:20:17 +00002121 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002122 [
2123 VppMRoutePath(
2124 self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
2125 ),
2126 VppMRoutePath(
2127 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
2128 ),
2129 ],
2130 )
Neale Ranns180279b2017-03-16 15:49:09 -04002131 route_ff_01.add_vpp_config()
2132
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002133 pu = (
2134 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
2135 / IPv6(src="2001::1", dst=self.pg0.remote_ip6)
2136 / inet6.UDP(sport=1234, dport=1234)
2137 / Raw(b"\xa5" * 100)
2138 )
2139 pm = (
2140 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
2141 / IPv6(src="2001::1", dst="ffef::1")
2142 / inet6.UDP(sport=1234, dport=1234)
2143 / Raw(b"\xa5" * 100)
2144 )
Neale Ranns180279b2017-03-16 15:49:09 -04002145
2146 #
2147 # PG1 does not forward IP traffic
2148 #
2149 self.send_and_assert_no_replies(self.pg1, pu, "IPv6 disabled")
2150 self.send_and_assert_no_replies(self.pg1, pm, "IPv6 disabled")
2151
2152 #
2153 # IP enable PG1
2154 #
2155 self.pg1.config_ip6()
2156
2157 #
2158 # Now we get packets through
2159 #
2160 self.pg1.add_stream(pu)
2161 self.pg_enable_capture(self.pg_interfaces)
2162 self.pg_start()
2163 rx = self.pg0.get_capture(1)
2164
2165 self.pg1.add_stream(pm)
2166 self.pg_enable_capture(self.pg_interfaces)
2167 self.pg_start()
2168 rx = self.pg0.get_capture(1)
2169
2170 #
2171 # Disable PG1
2172 #
2173 self.pg1.unconfig_ip6()
2174
2175 #
2176 # PG1 does not forward IP traffic
2177 #
2178 self.send_and_assert_no_replies(self.pg1, pu, "IPv6 disabled")
2179 self.send_and_assert_no_replies(self.pg1, pm, "IPv6 disabled")
2180
2181
Neale Ranns227038a2017-04-21 01:07:59 -07002182class TestIP6LoadBalance(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002183 """IPv6 Load-Balancing"""
Neale Ranns227038a2017-04-21 01:07:59 -07002184
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002185 @classmethod
2186 def setUpClass(cls):
2187 super(TestIP6LoadBalance, cls).setUpClass()
2188
2189 @classmethod
2190 def tearDownClass(cls):
2191 super(TestIP6LoadBalance, cls).tearDownClass()
2192
Neale Ranns227038a2017-04-21 01:07:59 -07002193 def setUp(self):
2194 super(TestIP6LoadBalance, self).setUp()
2195
2196 self.create_pg_interfaces(range(5))
2197
Neale Ranns15002542017-09-10 04:39:11 -07002198 mpls_tbl = VppMplsTable(self, 0)
2199 mpls_tbl.add_vpp_config()
2200
Neale Ranns227038a2017-04-21 01:07:59 -07002201 for i in self.pg_interfaces:
2202 i.admin_up()
2203 i.config_ip6()
2204 i.resolve_ndp()
Neale Ranns71275e32017-05-25 12:38:58 -07002205 i.enable_mpls()
Neale Ranns227038a2017-04-21 01:07:59 -07002206
2207 def tearDown(self):
Neale Ranns227038a2017-04-21 01:07:59 -07002208 for i in self.pg_interfaces:
2209 i.unconfig_ip6()
2210 i.admin_down()
Neale Ranns71275e32017-05-25 12:38:58 -07002211 i.disable_mpls()
Neale Ranns15002542017-09-10 04:39:11 -07002212 super(TestIP6LoadBalance, self).tearDown()
Neale Ranns227038a2017-04-21 01:07:59 -07002213
Neale Ranns227038a2017-04-21 01:07:59 -07002214 def test_ip6_load_balance(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002215 """IPv6 Load-Balancing"""
Neale Ranns227038a2017-04-21 01:07:59 -07002216
2217 #
2218 # An array of packets that differ only in the destination port
Neale Ranns71275e32017-05-25 12:38:58 -07002219 # - IP only
2220 # - MPLS EOS
2221 # - MPLS non-EOS
2222 # - MPLS non-EOS with an entropy label
Neale Ranns227038a2017-04-21 01:07:59 -07002223 #
Neale Ranns71275e32017-05-25 12:38:58 -07002224 port_ip_pkts = []
2225 port_mpls_pkts = []
2226 port_mpls_neos_pkts = []
2227 port_ent_pkts = []
Neale Ranns227038a2017-04-21 01:07:59 -07002228
2229 #
2230 # An array of packets that differ only in the source address
2231 #
Neale Ranns71275e32017-05-25 12:38:58 -07002232 src_ip_pkts = []
2233 src_mpls_pkts = []
Neale Ranns227038a2017-04-21 01:07:59 -07002234
Paul Vinciguerra4271c972019-05-14 13:25:49 -04002235 for ii in range(NUM_PKTS):
Paul Vinciguerra978aa642018-11-24 22:19:12 -08002236 port_ip_hdr = (
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002237 IPv6(dst="3000::1", src="3000:1::1")
2238 / inet6.UDP(sport=1234, dport=1234 + ii)
2239 / Raw(b"\xa5" * 100)
2240 )
2241 port_ip_pkts.append(
2242 (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / port_ip_hdr)
2243 )
2244 port_mpls_pkts.append(
2245 (
2246 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2247 / MPLS(label=66, ttl=2)
2248 / port_ip_hdr
2249 )
2250 )
2251 port_mpls_neos_pkts.append(
2252 (
2253 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2254 / MPLS(label=67, ttl=2)
2255 / MPLS(label=77, ttl=2)
2256 / port_ip_hdr
2257 )
2258 )
2259 port_ent_pkts.append(
2260 (
2261 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2262 / MPLS(label=67, ttl=2)
2263 / MPLS(label=14, ttl=2)
2264 / MPLS(label=999, ttl=2)
2265 / port_ip_hdr
2266 )
2267 )
Paul Vinciguerra978aa642018-11-24 22:19:12 -08002268 src_ip_hdr = (
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002269 IPv6(dst="3000::1", src="3000:1::%d" % ii)
2270 / inet6.UDP(sport=1234, dport=1234)
2271 / Raw(b"\xa5" * 100)
2272 )
2273 src_ip_pkts.append(
2274 (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / src_ip_hdr)
2275 )
2276 src_mpls_pkts.append(
2277 (
2278 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2279 / MPLS(label=66, ttl=2)
2280 / src_ip_hdr
2281 )
2282 )
Neale Ranns227038a2017-04-21 01:07:59 -07002283
Neale Ranns71275e32017-05-25 12:38:58 -07002284 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07002285 # A route for the IP packets
Neale Ranns71275e32017-05-25 12:38:58 -07002286 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002287 route_3000_1 = VppIpRoute(
2288 self,
2289 "3000::1",
2290 128,
2291 [
2292 VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index),
2293 VppRoutePath(self.pg2.remote_ip6, self.pg2.sw_if_index),
2294 ],
2295 )
Neale Ranns227038a2017-04-21 01:07:59 -07002296 route_3000_1.add_vpp_config()
2297
2298 #
Neale Ranns71275e32017-05-25 12:38:58 -07002299 # a local-label for the EOS packets
2300 #
2301 binding = VppMplsIpBind(self, 66, "3000::1", 128, is_ip6=1)
2302 binding.add_vpp_config()
2303
2304 #
2305 # An MPLS route for the non-EOS packets
2306 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002307 route_67 = VppMplsRoute(
2308 self,
2309 67,
2310 0,
2311 [
2312 VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, labels=[67]),
2313 VppRoutePath(self.pg2.remote_ip6, self.pg2.sw_if_index, labels=[67]),
2314 ],
2315 )
Neale Ranns71275e32017-05-25 12:38:58 -07002316 route_67.add_vpp_config()
2317
2318 #
Neale Ranns227038a2017-04-21 01:07:59 -07002319 # inject the packet on pg0 - expect load-balancing across the 2 paths
2320 # - since the default hash config is to use IP src,dst and port
2321 # src,dst
2322 # We are not going to ensure equal amounts of packets across each link,
2323 # since the hash algorithm is statistical and therefore this can never
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07002324 # be guaranteed. But with 64 different packets we do expect some
Neale Ranns227038a2017-04-21 01:07:59 -07002325 # balancing. So instead just ensure there is traffic on each link.
2326 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002327 rx = self.send_and_expect_load_balancing(
2328 self.pg0, port_ip_pkts, [self.pg1, self.pg2]
2329 )
Neale Ranns3d5f08a2021-01-22 16:12:38 +00002330 n_ip_pg0 = len(rx[0])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002331 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts, [self.pg1, self.pg2])
2332 self.send_and_expect_load_balancing(
2333 self.pg0, port_mpls_pkts, [self.pg1, self.pg2]
2334 )
2335 self.send_and_expect_load_balancing(
2336 self.pg0, src_mpls_pkts, [self.pg1, self.pg2]
2337 )
2338 rx = self.send_and_expect_load_balancing(
2339 self.pg0, port_mpls_neos_pkts, [self.pg1, self.pg2]
2340 )
Neale Ranns3d5f08a2021-01-22 16:12:38 +00002341 n_mpls_pg0 = len(rx[0])
2342
2343 #
2344 # change the router ID and expect the distribution changes
2345 #
2346 self.vapi.set_ip_flow_hash_router_id(router_id=0x11111111)
2347
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002348 rx = self.send_and_expect_load_balancing(
2349 self.pg0, port_ip_pkts, [self.pg1, self.pg2]
2350 )
Neale Ranns3d5f08a2021-01-22 16:12:38 +00002351 self.assertNotEqual(n_ip_pg0, len(rx[0]))
2352
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002353 rx = self.send_and_expect_load_balancing(
2354 self.pg0, src_mpls_pkts, [self.pg1, self.pg2]
2355 )
Neale Ranns3d5f08a2021-01-22 16:12:38 +00002356 self.assertNotEqual(n_mpls_pg0, len(rx[0]))
Neale Ranns71275e32017-05-25 12:38:58 -07002357
2358 #
2359 # The packets with Entropy label in should not load-balance,
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07002360 # since the Entropy value is fixed.
Neale Ranns71275e32017-05-25 12:38:58 -07002361 #
Neale Ranns699bea22022-02-17 09:22:16 +00002362 self.send_and_expect_only(self.pg0, port_ent_pkts, self.pg1)
Neale Ranns227038a2017-04-21 01:07:59 -07002363
2364 #
2365 # change the flow hash config so it's only IP src,dst
2366 # - now only the stream with differing source address will
2367 # load-balance
2368 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002369 self.vapi.set_ip_flow_hash(
2370 vrf_id=0, src=1, dst=1, proto=1, sport=0, dport=0, is_ipv6=1
2371 )
Neale Ranns227038a2017-04-21 01:07:59 -07002372
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002373 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts, [self.pg1, self.pg2])
2374 self.send_and_expect_load_balancing(
2375 self.pg0, src_mpls_pkts, [self.pg1, self.pg2]
2376 )
Neale Ranns699bea22022-02-17 09:22:16 +00002377 self.send_and_expect_only(self.pg0, port_ip_pkts, self.pg2)
Neale Ranns227038a2017-04-21 01:07:59 -07002378
2379 #
2380 # change the flow hash config back to defaults
2381 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002382 self.vapi.set_ip_flow_hash(
2383 vrf_id=0, src=1, dst=1, sport=1, dport=1, proto=1, is_ipv6=1
2384 )
Neale Ranns227038a2017-04-21 01:07:59 -07002385
2386 #
2387 # Recursive prefixes
2388 # - testing that 2 stages of load-balancing occurs and there is no
2389 # polarisation (i.e. only 2 of 4 paths are used)
2390 #
2391 port_pkts = []
2392 src_pkts = []
2393
2394 for ii in range(257):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002395 port_pkts.append(
2396 (
2397 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2398 / IPv6(dst="4000::1", src="4000:1::1")
2399 / inet6.UDP(sport=1234, dport=1234 + ii)
2400 / Raw(b"\xa5" * 100)
2401 )
2402 )
2403 src_pkts.append(
2404 (
2405 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2406 / IPv6(dst="4000::1", src="4000:1::%d" % ii)
2407 / inet6.UDP(sport=1234, dport=1234)
2408 / Raw(b"\xa5" * 100)
2409 )
2410 )
Neale Ranns227038a2017-04-21 01:07:59 -07002411
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002412 route_3000_2 = VppIpRoute(
2413 self,
2414 "3000::2",
2415 128,
2416 [
2417 VppRoutePath(self.pg3.remote_ip6, self.pg3.sw_if_index),
2418 VppRoutePath(self.pg4.remote_ip6, self.pg4.sw_if_index),
2419 ],
2420 )
Neale Ranns227038a2017-04-21 01:07:59 -07002421 route_3000_2.add_vpp_config()
2422
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002423 route_4000_1 = VppIpRoute(
2424 self,
2425 "4000::1",
2426 128,
2427 [VppRoutePath("3000::1", 0xFFFFFFFF), VppRoutePath("3000::2", 0xFFFFFFFF)],
2428 )
Neale Ranns227038a2017-04-21 01:07:59 -07002429 route_4000_1.add_vpp_config()
2430
2431 #
2432 # inject the packet on pg0 - expect load-balancing across all 4 paths
2433 #
2434 self.vapi.cli("clear trace")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002435 self.send_and_expect_load_balancing(
2436 self.pg0, port_pkts, [self.pg1, self.pg2, self.pg3, self.pg4]
2437 )
2438 self.send_and_expect_load_balancing(
2439 self.pg0, src_pkts, [self.pg1, self.pg2, self.pg3, self.pg4]
2440 )
Neale Ranns227038a2017-04-21 01:07:59 -07002441
Neale Ranns42e6b092017-07-31 02:56:03 -07002442 #
2443 # Recursive prefixes
2444 # - testing that 2 stages of load-balancing no choices
2445 #
2446 port_pkts = []
2447
2448 for ii in range(257):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002449 port_pkts.append(
2450 (
2451 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2452 / IPv6(dst="6000::1", src="6000:1::1")
2453 / inet6.UDP(sport=1234, dport=1234 + ii)
2454 / Raw(b"\xa5" * 100)
2455 )
2456 )
Neale Ranns42e6b092017-07-31 02:56:03 -07002457
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002458 route_5000_2 = VppIpRoute(
2459 self,
2460 "5000::2",
2461 128,
2462 [VppRoutePath(self.pg3.remote_ip6, self.pg3.sw_if_index)],
2463 )
Neale Ranns42e6b092017-07-31 02:56:03 -07002464 route_5000_2.add_vpp_config()
2465
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002466 route_6000_1 = VppIpRoute(
2467 self, "6000::1", 128, [VppRoutePath("5000::2", 0xFFFFFFFF)]
2468 )
Neale Ranns42e6b092017-07-31 02:56:03 -07002469 route_6000_1.add_vpp_config()
2470
2471 #
2472 # inject the packet on pg0 - expect load-balancing across all 4 paths
2473 #
2474 self.vapi.cli("clear trace")
Neale Ranns699bea22022-02-17 09:22:16 +00002475 self.send_and_expect_only(self.pg0, port_pkts, self.pg3)
Neale Ranns42e6b092017-07-31 02:56:03 -07002476
Neale Ranns227038a2017-04-21 01:07:59 -07002477
Brian Russella1f36062021-01-19 16:58:14 +00002478class IP6PuntSetup(object):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002479 """Setup for IPv6 Punt Police/Redirect"""
Neale Rannsd91c1db2017-07-31 02:30:50 -07002480
Brian Russella1f36062021-01-19 16:58:14 +00002481 def punt_setup(self):
Pavel Kotucek609e1212018-11-27 09:59:44 +01002482 self.create_pg_interfaces(range(4))
Neale Rannsd91c1db2017-07-31 02:30:50 -07002483
2484 for i in self.pg_interfaces:
2485 i.admin_up()
2486 i.config_ip6()
2487 i.resolve_ndp()
2488
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002489 self.pkt = (
2490 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2491 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
2492 / inet6.TCP(sport=1234, dport=1234)
2493 / Raw(b"\xa5" * 100)
2494 )
Brian Russella1f36062021-01-19 16:58:14 +00002495
2496 def punt_teardown(self):
Neale Rannsd91c1db2017-07-31 02:30:50 -07002497 for i in self.pg_interfaces:
2498 i.unconfig_ip6()
2499 i.admin_down()
2500
Brian Russella1f36062021-01-19 16:58:14 +00002501
2502class TestIP6Punt(IP6PuntSetup, VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002503 """IPv6 Punt Police/Redirect"""
Brian Russella1f36062021-01-19 16:58:14 +00002504
2505 def setUp(self):
2506 super(TestIP6Punt, self).setUp()
2507 super(TestIP6Punt, self).punt_setup()
2508
2509 def tearDown(self):
2510 super(TestIP6Punt, self).punt_teardown()
2511 super(TestIP6Punt, self).tearDown()
2512
Neale Rannsd91c1db2017-07-31 02:30:50 -07002513 def test_ip_punt(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002514 """IP6 punt police and redirect"""
Neale Rannsd91c1db2017-07-31 02:30:50 -07002515
Brian Russella1f36062021-01-19 16:58:14 +00002516 pkts = self.pkt * 1025
Neale Rannsd91c1db2017-07-31 02:30:50 -07002517
2518 #
2519 # Configure a punt redirect via pg1.
2520 #
Ole Troan0bcad322018-12-11 13:04:01 +01002521 nh_addr = self.pg1.remote_ip6
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002522 ip_punt_redirect = VppIpPuntRedirect(
2523 self, self.pg0.sw_if_index, self.pg1.sw_if_index, nh_addr
2524 )
Jakub Grajciar2df2f752020-12-01 11:23:44 +01002525 ip_punt_redirect.add_vpp_config()
Neale Rannsd91c1db2017-07-31 02:30:50 -07002526
2527 self.send_and_expect(self.pg0, pkts, self.pg1)
2528
2529 #
2530 # add a policer
2531 #
Jakub Grajciarcd01fb42020-03-02 13:16:53 +01002532 policer = VppPolicer(self, "ip6-punt", 400, 0, 10, 0, rate_type=1)
2533 policer.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002534 ip_punt_policer = VppIpPuntPolicer(self, policer.policer_index, is_ip6=True)
Jakub Grajciar2df2f752020-12-01 11:23:44 +01002535 ip_punt_policer.add_vpp_config()
Neale Rannsd91c1db2017-07-31 02:30:50 -07002536
2537 self.vapi.cli("clear trace")
2538 self.pg0.add_stream(pkts)
2539 self.pg_enable_capture(self.pg_interfaces)
2540 self.pg_start()
2541
2542 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07002543 # the number of packet received should be greater than 0,
Neale Rannsd91c1db2017-07-31 02:30:50 -07002544 # but not equal to the number sent, since some were policed
2545 #
2546 rx = self.pg1._get_capture(1)
Brian Russelle9887262021-01-27 14:45:22 +00002547 stats = policer.get_stats()
2548
2549 # Single rate policer - expect conform, violate but no exceed
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002550 self.assertGreater(stats["conform_packets"], 0)
2551 self.assertEqual(stats["exceed_packets"], 0)
2552 self.assertGreater(stats["violate_packets"], 0)
Brian Russelle9887262021-01-27 14:45:22 +00002553
Paul Vinciguerra3d2df212018-11-24 23:19:53 -08002554 self.assertGreater(len(rx), 0)
2555 self.assertLess(len(rx), len(pkts))
Neale Rannsd91c1db2017-07-31 02:30:50 -07002556
2557 #
Paul Vinciguerraeb414432019-02-20 09:01:14 -08002558 # remove the policer. back to full rx
Neale Rannsd91c1db2017-07-31 02:30:50 -07002559 #
Jakub Grajciar2df2f752020-12-01 11:23:44 +01002560 ip_punt_policer.remove_vpp_config()
Jakub Grajciarcd01fb42020-03-02 13:16:53 +01002561 policer.remove_vpp_config()
Neale Rannsd91c1db2017-07-31 02:30:50 -07002562 self.send_and_expect(self.pg0, pkts, self.pg1)
2563
2564 #
2565 # remove the redirect. expect full drop.
2566 #
Jakub Grajciar2df2f752020-12-01 11:23:44 +01002567 ip_punt_redirect.remove_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002568 self.send_and_assert_no_replies(self.pg0, pkts, "IP no punt config")
Neale Rannsd91c1db2017-07-31 02:30:50 -07002569
2570 #
2571 # Add a redirect that is not input port selective
2572 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002573 ip_punt_redirect = VppIpPuntRedirect(
2574 self, 0xFFFFFFFF, self.pg1.sw_if_index, nh_addr
2575 )
Jakub Grajciar2df2f752020-12-01 11:23:44 +01002576 ip_punt_redirect.add_vpp_config()
Neale Rannsd91c1db2017-07-31 02:30:50 -07002577 self.send_and_expect(self.pg0, pkts, self.pg1)
Jakub Grajciar2df2f752020-12-01 11:23:44 +01002578 ip_punt_redirect.remove_vpp_config()
Pavel Kotucek609e1212018-11-27 09:59:44 +01002579
2580 def test_ip_punt_dump(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002581 """IP6 punt redirect dump"""
Pavel Kotucek609e1212018-11-27 09:59:44 +01002582
2583 #
2584 # Configure a punt redirects
2585 #
Jakub Grajciar2df2f752020-12-01 11:23:44 +01002586 nh_address = self.pg3.remote_ip6
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002587 ipr_03 = VppIpPuntRedirect(
2588 self, self.pg0.sw_if_index, self.pg3.sw_if_index, nh_address
2589 )
2590 ipr_13 = VppIpPuntRedirect(
2591 self, self.pg1.sw_if_index, self.pg3.sw_if_index, nh_address
2592 )
2593 ipr_23 = VppIpPuntRedirect(
2594 self, self.pg2.sw_if_index, self.pg3.sw_if_index, "0::0"
2595 )
Jakub Grajciar2df2f752020-12-01 11:23:44 +01002596 ipr_03.add_vpp_config()
2597 ipr_13.add_vpp_config()
2598 ipr_23.add_vpp_config()
Pavel Kotucek609e1212018-11-27 09:59:44 +01002599
2600 #
2601 # Dump pg0 punt redirects
2602 #
Jakub Grajciar2df2f752020-12-01 11:23:44 +01002603 self.assertTrue(ipr_03.query_vpp_config())
2604 self.assertTrue(ipr_13.query_vpp_config())
2605 self.assertTrue(ipr_23.query_vpp_config())
Pavel Kotucek609e1212018-11-27 09:59:44 +01002606
2607 #
2608 # Dump punt redirects for all interfaces
2609 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002610 punts = self.vapi.ip_punt_redirect_dump(0xFFFFFFFF, is_ipv6=1)
Pavel Kotucek609e1212018-11-27 09:59:44 +01002611 self.assertEqual(len(punts), 3)
2612 for p in punts:
2613 self.assertEqual(p.punt.tx_sw_if_index, self.pg3.sw_if_index)
Ole Troan0bcad322018-12-11 13:04:01 +01002614 self.assertNotEqual(punts[1].punt.nh, self.pg3.remote_ip6)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002615 self.assertEqual(str(punts[2].punt.nh), "::")
Neale Rannsd91c1db2017-07-31 02:30:50 -07002616
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002617
Brian Russell5214f3a2021-01-19 16:58:34 +00002618class TestIP6PuntHandoff(IP6PuntSetup, VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002619 """IPv6 Punt Police/Redirect"""
2620
Klement Sekera8d815022021-03-15 16:58:10 +01002621 vpp_worker_count = 2
Brian Russell5214f3a2021-01-19 16:58:34 +00002622
2623 def setUp(self):
2624 super(TestIP6PuntHandoff, self).setUp()
2625 super(TestIP6PuntHandoff, self).punt_setup()
2626
2627 def tearDown(self):
2628 super(TestIP6PuntHandoff, self).punt_teardown()
2629 super(TestIP6PuntHandoff, self).tearDown()
2630
2631 def test_ip_punt(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002632 """IP6 punt policer thread handoff"""
Brian Russell5214f3a2021-01-19 16:58:34 +00002633 pkts = self.pkt * NUM_PKTS
2634
2635 #
2636 # Configure a punt redirect via pg1.
2637 #
2638 nh_addr = self.pg1.remote_ip6
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002639 ip_punt_redirect = VppIpPuntRedirect(
2640 self, self.pg0.sw_if_index, self.pg1.sw_if_index, nh_addr
2641 )
Brian Russell5214f3a2021-01-19 16:58:34 +00002642 ip_punt_redirect.add_vpp_config()
2643
2644 action_tx = PolicerAction(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002645 VppEnum.vl_api_sse2_qos_action_type_t.SSE2_QOS_ACTION_API_TRANSMIT, 0
2646 )
Brian Russell5214f3a2021-01-19 16:58:34 +00002647 #
2648 # This policer drops no packets, we are just
2649 # testing that they get to the right thread.
2650 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002651 policer = VppPolicer(
2652 self,
2653 "ip6-punt",
2654 400,
2655 0,
2656 10,
2657 0,
2658 1,
2659 0,
2660 0,
2661 False,
2662 action_tx,
2663 action_tx,
2664 action_tx,
2665 )
Brian Russell5214f3a2021-01-19 16:58:34 +00002666 policer.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002667 ip_punt_policer = VppIpPuntPolicer(self, policer.policer_index, is_ip6=True)
Brian Russell5214f3a2021-01-19 16:58:34 +00002668 ip_punt_policer.add_vpp_config()
2669
2670 for worker in [0, 1]:
2671 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
2672 if worker == 0:
2673 self.logger.debug(self.vapi.cli("show trace max 100"))
2674
Brian Russelle9887262021-01-27 14:45:22 +00002675 # Combined stats, all threads
2676 stats = policer.get_stats()
2677
2678 # Single rate policer - expect conform, violate but no exceed
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002679 self.assertGreater(stats["conform_packets"], 0)
2680 self.assertEqual(stats["exceed_packets"], 0)
2681 self.assertGreater(stats["violate_packets"], 0)
Brian Russelle9887262021-01-27 14:45:22 +00002682
2683 # Worker 0, should have done all the policing
2684 stats0 = policer.get_stats(worker=0)
2685 self.assertEqual(stats, stats0)
2686
2687 # Worker 1, should have handed everything off
2688 stats1 = policer.get_stats(worker=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002689 self.assertEqual(stats1["conform_packets"], 0)
2690 self.assertEqual(stats1["exceed_packets"], 0)
2691 self.assertEqual(stats1["violate_packets"], 0)
Brian Russelle9887262021-01-27 14:45:22 +00002692
Brian Russellbb983142021-02-10 13:56:06 +00002693 # Bind the policer to worker 1 and repeat
2694 policer.bind_vpp_config(1, True)
2695 for worker in [0, 1]:
2696 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
2697 self.logger.debug(self.vapi.cli("show trace max 100"))
2698
2699 # The 2 workers should now have policed the same amount
2700 stats = policer.get_stats()
2701 stats0 = policer.get_stats(worker=0)
2702 stats1 = policer.get_stats(worker=1)
2703
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002704 self.assertGreater(stats0["conform_packets"], 0)
2705 self.assertEqual(stats0["exceed_packets"], 0)
2706 self.assertGreater(stats0["violate_packets"], 0)
Brian Russellbb983142021-02-10 13:56:06 +00002707
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002708 self.assertGreater(stats1["conform_packets"], 0)
2709 self.assertEqual(stats1["exceed_packets"], 0)
2710 self.assertGreater(stats1["violate_packets"], 0)
Brian Russellbb983142021-02-10 13:56:06 +00002711
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002712 self.assertEqual(
2713 stats0["conform_packets"] + stats1["conform_packets"],
2714 stats["conform_packets"],
2715 )
Brian Russellbb983142021-02-10 13:56:06 +00002716
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002717 self.assertEqual(
2718 stats0["violate_packets"] + stats1["violate_packets"],
2719 stats["violate_packets"],
2720 )
Brian Russellbb983142021-02-10 13:56:06 +00002721
2722 # Unbind the policer and repeat
2723 policer.bind_vpp_config(1, False)
2724 for worker in [0, 1]:
2725 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
2726 self.logger.debug(self.vapi.cli("show trace max 100"))
2727
2728 # The policer should auto-bind to worker 0 when packets arrive
2729 stats = policer.get_stats()
2730 stats0new = policer.get_stats(worker=0)
2731 stats1new = policer.get_stats(worker=1)
2732
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002733 self.assertGreater(stats0new["conform_packets"], stats0["conform_packets"])
2734 self.assertEqual(stats0new["exceed_packets"], 0)
2735 self.assertGreater(stats0new["violate_packets"], stats0["violate_packets"])
Brian Russellbb983142021-02-10 13:56:06 +00002736
2737 self.assertEqual(stats1, stats1new)
2738
Brian Russell5214f3a2021-01-19 16:58:34 +00002739 #
2740 # Clean up
2741 #
2742 ip_punt_policer.remove_vpp_config()
2743 policer.remove_vpp_config()
2744 ip_punt_redirect.remove_vpp_config()
2745
2746
Tianyu Li6d95f8c2022-02-25 05:51:10 +00002747class TestIP6Deag(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002748 """IPv6 Deaggregate Routes"""
Neale Rannsce9e0b42018-08-01 12:53:17 -07002749
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002750 @classmethod
2751 def setUpClass(cls):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00002752 super(TestIP6Deag, cls).setUpClass()
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002753
2754 @classmethod
2755 def tearDownClass(cls):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00002756 super(TestIP6Deag, cls).tearDownClass()
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002757
Neale Rannsce9e0b42018-08-01 12:53:17 -07002758 def setUp(self):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00002759 super(TestIP6Deag, self).setUp()
Neale Rannsce9e0b42018-08-01 12:53:17 -07002760
2761 self.create_pg_interfaces(range(3))
2762
2763 for i in self.pg_interfaces:
2764 i.admin_up()
2765 i.config_ip6()
2766 i.resolve_ndp()
2767
2768 def tearDown(self):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00002769 super(TestIP6Deag, self).tearDown()
Neale Rannsce9e0b42018-08-01 12:53:17 -07002770 for i in self.pg_interfaces:
2771 i.unconfig_ip6()
2772 i.admin_down()
2773
2774 def test_ip_deag(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002775 """IP Deag Routes"""
Neale Rannsce9e0b42018-08-01 12:53:17 -07002776
2777 #
2778 # Create a table to be used for:
2779 # 1 - another destination address lookup
2780 # 2 - a source address lookup
2781 #
2782 table_dst = VppIpTable(self, 1, is_ip6=1)
2783 table_src = VppIpTable(self, 2, is_ip6=1)
2784 table_dst.add_vpp_config()
2785 table_src.add_vpp_config()
2786
2787 #
2788 # Add a route in the default table to point to a deag/
2789 # second lookup in each of these tables
2790 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002791 route_to_dst = VppIpRoute(
2792 self, "1::1", 128, [VppRoutePath("::", 0xFFFFFFFF, nh_table_id=1)]
2793 )
Neale Ranns097fa662018-05-01 05:17:55 -07002794 route_to_src = VppIpRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002795 self,
2796 "1::2",
2797 128,
2798 [
2799 VppRoutePath(
2800 "::",
2801 0xFFFFFFFF,
2802 nh_table_id=2,
2803 type=FibPathType.FIB_PATH_TYPE_SOURCE_LOOKUP,
2804 )
2805 ],
2806 )
Neale Ranns097fa662018-05-01 05:17:55 -07002807
Neale Rannsce9e0b42018-08-01 12:53:17 -07002808 route_to_dst.add_vpp_config()
2809 route_to_src.add_vpp_config()
2810
2811 #
2812 # packets to these destination are dropped, since they'll
2813 # hit the respective default routes in the second table
2814 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002815 p_dst = (
2816 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2817 / IPv6(src="5::5", dst="1::1")
2818 / inet6.TCP(sport=1234, dport=1234)
2819 / Raw(b"\xa5" * 100)
2820 )
2821 p_src = (
2822 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2823 / IPv6(src="2::2", dst="1::2")
2824 / inet6.TCP(sport=1234, dport=1234)
2825 / Raw(b"\xa5" * 100)
2826 )
Neale Rannsce9e0b42018-08-01 12:53:17 -07002827 pkts_dst = p_dst * 257
2828 pkts_src = p_src * 257
2829
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002830 self.send_and_assert_no_replies(self.pg0, pkts_dst, "IP in dst table")
2831 self.send_and_assert_no_replies(self.pg0, pkts_src, "IP in src table")
Neale Rannsce9e0b42018-08-01 12:53:17 -07002832
2833 #
2834 # add a route in the dst table to forward via pg1
2835 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002836 route_in_dst = VppIpRoute(
2837 self,
2838 "1::1",
2839 128,
2840 [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)],
2841 table_id=1,
2842 )
Neale Rannsce9e0b42018-08-01 12:53:17 -07002843 route_in_dst.add_vpp_config()
2844
2845 self.send_and_expect(self.pg0, pkts_dst, self.pg1)
2846
2847 #
2848 # add a route in the src table to forward via pg2
2849 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002850 route_in_src = VppIpRoute(
2851 self,
2852 "2::2",
2853 128,
2854 [VppRoutePath(self.pg2.remote_ip6, self.pg2.sw_if_index)],
2855 table_id=2,
2856 )
Neale Rannsce9e0b42018-08-01 12:53:17 -07002857 route_in_src.add_vpp_config()
2858 self.send_and_expect(self.pg0, pkts_src, self.pg2)
2859
2860 #
2861 # loop in the lookup DP
2862 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002863 route_loop = VppIpRoute(self, "3::3", 128, [VppRoutePath("::", 0xFFFFFFFF)])
Neale Rannsce9e0b42018-08-01 12:53:17 -07002864 route_loop.add_vpp_config()
2865
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002866 p_l = (
2867 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2868 / IPv6(src="3::4", dst="3::3")
2869 / inet6.TCP(sport=1234, dport=1234)
2870 / Raw(b"\xa5" * 100)
2871 )
Neale Rannsce9e0b42018-08-01 12:53:17 -07002872
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002873 self.send_and_assert_no_replies(self.pg0, p_l * 257, "IP lookup loop")
Neale Rannsce9e0b42018-08-01 12:53:17 -07002874
2875
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002876class TestIP6Input(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002877 """IPv6 Input Exception Test Cases"""
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002878
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002879 @classmethod
2880 def setUpClass(cls):
2881 super(TestIP6Input, cls).setUpClass()
2882
2883 @classmethod
2884 def tearDownClass(cls):
2885 super(TestIP6Input, cls).tearDownClass()
2886
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002887 def setUp(self):
2888 super(TestIP6Input, self).setUp()
2889
2890 self.create_pg_interfaces(range(2))
2891
2892 for i in self.pg_interfaces:
2893 i.admin_up()
2894 i.config_ip6()
2895 i.resolve_ndp()
2896
2897 def tearDown(self):
2898 super(TestIP6Input, self).tearDown()
2899 for i in self.pg_interfaces:
2900 i.unconfig_ip6()
2901 i.admin_down()
2902
Neale Rannsae809832018-11-23 09:00:27 -08002903 def test_ip_input_icmp_reply(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002904 """IP6 Input Exception - Return ICMP (3,0)"""
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002905 #
Neale Rannsae809832018-11-23 09:00:27 -08002906 # hop limit - ICMP replies
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002907 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002908 p_version = (
2909 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2910 / IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6, hlim=1)
2911 / inet6.UDP(sport=1234, dport=1234)
2912 / Raw(b"\xa5" * 100)
2913 )
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002914
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002915 rxs = self.send_and_expect_some(self.pg0, p_version * NUM_PKTS, self.pg0)
Neale Rannsae809832018-11-23 09:00:27 -08002916
Neale Ranns5c6dd172022-02-17 09:08:47 +00002917 for rx in rxs:
2918 icmp = rx[ICMPv6TimeExceeded]
2919 # 0: "hop limit exceeded in transit",
2920 self.assertEqual((icmp.type, icmp.code), (3, 0))
Neale Rannsae809832018-11-23 09:00:27 -08002921
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002922 icmpv6_data = "\x0a" * 18
Neale Rannsae809832018-11-23 09:00:27 -08002923 all_0s = "::"
2924 all_1s = "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"
2925
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002926 @parameterized.expand(
2927 [
2928 # Name, src, dst, l4proto, msg, timeout
2929 (
2930 "src='iface', dst='iface'",
2931 None,
2932 None,
2933 inet6.UDP(sport=1234, dport=1234),
2934 "funky version",
2935 None,
2936 ),
2937 (
2938 "src='All 0's', dst='iface'",
2939 all_0s,
2940 None,
2941 ICMPv6EchoRequest(id=0xB, seq=5, data=icmpv6_data),
2942 None,
2943 0.1,
2944 ),
2945 (
2946 "src='iface', dst='All 0's'",
2947 None,
2948 all_0s,
2949 ICMPv6EchoRequest(id=0xB, seq=5, data=icmpv6_data),
2950 None,
2951 0.1,
2952 ),
2953 (
2954 "src='All 1's', dst='iface'",
2955 all_1s,
2956 None,
2957 ICMPv6EchoRequest(id=0xB, seq=5, data=icmpv6_data),
2958 None,
2959 0.1,
2960 ),
2961 (
2962 "src='iface', dst='All 1's'",
2963 None,
2964 all_1s,
2965 ICMPv6EchoRequest(id=0xB, seq=5, data=icmpv6_data),
2966 None,
2967 0.1,
2968 ),
2969 (
2970 "src='All 1's', dst='All 1's'",
2971 all_1s,
2972 all_1s,
2973 ICMPv6EchoRequest(id=0xB, seq=5, data=icmpv6_data),
2974 None,
2975 0.1,
2976 ),
2977 ]
2978 )
Neale Rannsae809832018-11-23 09:00:27 -08002979 def test_ip_input_no_replies(self, name, src, dst, l4, msg, timeout):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002980 self._testMethodDoc = "IPv6 Input Exception - %s" % name
Neale Rannsae809832018-11-23 09:00:27 -08002981
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002982 p_version = (
2983 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2984 / IPv6(
2985 src=src or self.pg0.remote_ip6,
2986 dst=dst or self.pg1.remote_ip6,
2987 version=3,
2988 )
2989 / l4
2990 / Raw(b"\xa5" * 100)
2991 )
Neale Rannsae809832018-11-23 09:00:27 -08002992
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002993 self.send_and_assert_no_replies(
2994 self.pg0, p_version * NUM_PKTS, remark=msg or "", timeout=timeout
2995 )
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002996
Dave Barach90800962019-05-24 13:03:01 -04002997 def test_hop_by_hop(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002998 """Hop-by-hop header test"""
Dave Barach90800962019-05-24 13:03:01 -04002999
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003000 p = (
3001 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3002 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
3003 / IPv6ExtHdrHopByHop()
3004 / inet6.UDP(sport=1234, dport=1234)
3005 / Raw(b"\xa5" * 100)
3006 )
Dave Barach90800962019-05-24 13:03:01 -04003007
3008 self.pg0.add_stream(p)
3009 self.pg_enable_capture(self.pg_interfaces)
3010 self.pg_start()
Neale Ranns4c7c8e52017-10-21 09:37:55 -07003011
Neale Ranns9db6ada2019-11-08 12:42:31 +00003012
Tianyu Li6d95f8c2022-02-25 05:51:10 +00003013class TestIP6Replace(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003014 """IPv6 Table Replace"""
Neale Ranns9db6ada2019-11-08 12:42:31 +00003015
3016 @classmethod
3017 def setUpClass(cls):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00003018 super(TestIP6Replace, cls).setUpClass()
Neale Ranns9db6ada2019-11-08 12:42:31 +00003019
3020 @classmethod
3021 def tearDownClass(cls):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00003022 super(TestIP6Replace, cls).tearDownClass()
Neale Ranns9db6ada2019-11-08 12:42:31 +00003023
3024 def setUp(self):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00003025 super(TestIP6Replace, self).setUp()
Neale Ranns9db6ada2019-11-08 12:42:31 +00003026
3027 self.create_pg_interfaces(range(4))
3028
3029 table_id = 1
3030 self.tables = []
3031
3032 for i in self.pg_interfaces:
3033 i.admin_up()
3034 i.config_ip6()
Neale Ranns9db6ada2019-11-08 12:42:31 +00003035 i.generate_remote_hosts(2)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003036 self.tables.append(VppIpTable(self, table_id, True).add_vpp_config())
Neale Ranns9db6ada2019-11-08 12:42:31 +00003037 table_id += 1
3038
3039 def tearDown(self):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00003040 super(TestIP6Replace, self).tearDown()
Neale Ranns9db6ada2019-11-08 12:42:31 +00003041 for i in self.pg_interfaces:
3042 i.admin_down()
Neale Rannsec40a7d2020-04-23 07:36:12 +00003043 i.unconfig_ip6()
Neale Ranns9db6ada2019-11-08 12:42:31 +00003044
3045 def test_replace(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003046 """IP Table Replace"""
Neale Ranns9db6ada2019-11-08 12:42:31 +00003047
Neale Ranns990f6942020-10-20 07:20:17 +00003048 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
3049 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
Neale Ranns9db6ada2019-11-08 12:42:31 +00003050 N_ROUTES = 20
3051 links = [self.pg0, self.pg1, self.pg2, self.pg3]
3052 routes = [[], [], [], []]
3053
3054 # the sizes of 'empty' tables
3055 for t in self.tables:
3056 self.assertEqual(len(t.dump()), 2)
3057 self.assertEqual(len(t.mdump()), 5)
3058
3059 # load up the tables with some routes
3060 for ii, t in enumerate(self.tables):
3061 for jj in range(1, N_ROUTES):
3062 uni = VppIpRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003063 self,
3064 "2001::%d" % jj if jj != 0 else "2001::",
3065 128,
3066 [
3067 VppRoutePath(
3068 links[ii].remote_hosts[0].ip6, links[ii].sw_if_index
3069 ),
3070 VppRoutePath(
3071 links[ii].remote_hosts[1].ip6, links[ii].sw_if_index
3072 ),
3073 ],
3074 table_id=t.table_id,
3075 ).add_vpp_config()
Neale Ranns9db6ada2019-11-08 12:42:31 +00003076 multi = VppIpMRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003077 self,
3078 "::",
3079 "ff:2001::%d" % jj,
3080 128,
Neale Ranns990f6942020-10-20 07:20:17 +00003081 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003082 [
3083 VppMRoutePath(
3084 self.pg0.sw_if_index,
3085 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT,
3086 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
3087 ),
3088 VppMRoutePath(
3089 self.pg1.sw_if_index,
3090 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
3091 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
3092 ),
3093 VppMRoutePath(
3094 self.pg2.sw_if_index,
3095 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
3096 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
3097 ),
3098 VppMRoutePath(
3099 self.pg3.sw_if_index,
3100 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
3101 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
3102 ),
3103 ],
3104 table_id=t.table_id,
3105 ).add_vpp_config()
3106 routes[ii].append({"uni": uni, "multi": multi})
Neale Ranns9db6ada2019-11-08 12:42:31 +00003107
3108 #
3109 # replace the tables a few times
3110 #
3111 for kk in range(3):
3112 # replace each table
3113 for t in self.tables:
3114 t.replace_begin()
3115
3116 # all the routes are still there
3117 for ii, t in enumerate(self.tables):
3118 dump = t.dump()
3119 mdump = t.mdump()
3120 for r in routes[ii]:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003121 self.assertTrue(find_route_in_dump(dump, r["uni"], t))
3122 self.assertTrue(find_mroute_in_dump(mdump, r["multi"], t))
Neale Ranns9db6ada2019-11-08 12:42:31 +00003123
3124 # redownload the even numbered routes
3125 for ii, t in enumerate(self.tables):
3126 for jj in range(0, N_ROUTES, 2):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003127 routes[ii][jj]["uni"].add_vpp_config()
3128 routes[ii][jj]["multi"].add_vpp_config()
Neale Ranns9db6ada2019-11-08 12:42:31 +00003129
3130 # signal each table converged
3131 for t in self.tables:
3132 t.replace_end()
3133
3134 # we should find the even routes, but not the odd
3135 for ii, t in enumerate(self.tables):
3136 dump = t.dump()
3137 mdump = t.mdump()
3138 for jj in range(0, N_ROUTES, 2):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003139 self.assertTrue(find_route_in_dump(dump, routes[ii][jj]["uni"], t))
3140 self.assertTrue(
3141 find_mroute_in_dump(mdump, routes[ii][jj]["multi"], t)
3142 )
Neale Ranns9db6ada2019-11-08 12:42:31 +00003143 for jj in range(1, N_ROUTES - 1, 2):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003144 self.assertFalse(find_route_in_dump(dump, routes[ii][jj]["uni"], t))
3145 self.assertFalse(
3146 find_mroute_in_dump(mdump, routes[ii][jj]["multi"], t)
3147 )
Neale Ranns9db6ada2019-11-08 12:42:31 +00003148
3149 # reload all the routes
3150 for ii, t in enumerate(self.tables):
3151 for r in routes[ii]:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003152 r["uni"].add_vpp_config()
3153 r["multi"].add_vpp_config()
Neale Ranns9db6ada2019-11-08 12:42:31 +00003154
3155 # all the routes are still there
3156 for ii, t in enumerate(self.tables):
3157 dump = t.dump()
3158 mdump = t.mdump()
3159 for r in routes[ii]:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003160 self.assertTrue(find_route_in_dump(dump, r["uni"], t))
3161 self.assertTrue(find_mroute_in_dump(mdump, r["multi"], t))
Neale Ranns9db6ada2019-11-08 12:42:31 +00003162
3163 #
3164 # finally flush the tables for good measure
3165 #
3166 for t in self.tables:
3167 t.flush()
3168 self.assertEqual(len(t.dump()), 2)
3169 self.assertEqual(len(t.mdump()), 5)
3170
3171
Tianyu Li6d95f8c2022-02-25 05:51:10 +00003172class TestIP6AddrReplace(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003173 """IPv6 Interface Address Replace"""
Neale Ranns59f71132020-04-08 12:19:38 +00003174
3175 @classmethod
3176 def setUpClass(cls):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00003177 super(TestIP6AddrReplace, cls).setUpClass()
Neale Ranns59f71132020-04-08 12:19:38 +00003178
3179 @classmethod
3180 def tearDownClass(cls):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00003181 super(TestIP6AddrReplace, cls).tearDownClass()
Neale Ranns59f71132020-04-08 12:19:38 +00003182
3183 def setUp(self):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00003184 super(TestIP6AddrReplace, self).setUp()
Neale Ranns59f71132020-04-08 12:19:38 +00003185
3186 self.create_pg_interfaces(range(4))
3187
3188 for i in self.pg_interfaces:
3189 i.admin_up()
3190
3191 def tearDown(self):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00003192 super(TestIP6AddrReplace, self).tearDown()
Neale Ranns59f71132020-04-08 12:19:38 +00003193 for i in self.pg_interfaces:
3194 i.admin_down()
3195
3196 def get_n_pfxs(self, intf):
3197 return len(self.vapi.ip_address_dump(intf.sw_if_index, True))
3198
3199 def test_replace(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003200 """IP interface address replace"""
Neale Ranns59f71132020-04-08 12:19:38 +00003201
3202 intf_pfxs = [[], [], [], []]
3203
3204 # add prefixes to each of the interfaces
3205 for i in range(len(self.pg_interfaces)):
3206 intf = self.pg_interfaces[i]
3207
3208 # 2001:16:x::1/64
3209 addr = "2001:16:%d::1" % intf.sw_if_index
3210 a = VppIpInterfaceAddress(self, intf, addr, 64).add_vpp_config()
3211 intf_pfxs[i].append(a)
3212
3213 # 2001:16:x::2/64 - a different address in the same subnet as above
3214 addr = "2001:16:%d::2" % intf.sw_if_index
3215 a = VppIpInterfaceAddress(self, intf, addr, 64).add_vpp_config()
3216 intf_pfxs[i].append(a)
3217
3218 # 2001:15:x::2/64 - a different address and subnet
3219 addr = "2001:15:%d::2" % intf.sw_if_index
3220 a = VppIpInterfaceAddress(self, intf, addr, 64).add_vpp_config()
3221 intf_pfxs[i].append(a)
3222
3223 # a dump should n_address in it
3224 for intf in self.pg_interfaces:
3225 self.assertEqual(self.get_n_pfxs(intf), 3)
3226
3227 #
3228 # remove all the address thru a replace
3229 #
3230 self.vapi.sw_interface_address_replace_begin()
3231 self.vapi.sw_interface_address_replace_end()
3232 for intf in self.pg_interfaces:
3233 self.assertEqual(self.get_n_pfxs(intf), 0)
3234
3235 #
3236 # add all the interface addresses back
3237 #
3238 for p in intf_pfxs:
3239 for v in p:
3240 v.add_vpp_config()
3241 for intf in self.pg_interfaces:
3242 self.assertEqual(self.get_n_pfxs(intf), 3)
3243
3244 #
3245 # replace again, but this time update/re-add the address on the first
3246 # two interfaces
3247 #
3248 self.vapi.sw_interface_address_replace_begin()
3249
3250 for p in intf_pfxs[:2]:
3251 for v in p:
3252 v.add_vpp_config()
3253
3254 self.vapi.sw_interface_address_replace_end()
3255
3256 # on the first two the address still exist,
3257 # on the other two they do not
3258 for intf in self.pg_interfaces[:2]:
3259 self.assertEqual(self.get_n_pfxs(intf), 3)
3260 for p in intf_pfxs[:2]:
3261 for v in p:
3262 self.assertTrue(v.query_vpp_config())
3263 for intf in self.pg_interfaces[2:]:
3264 self.assertEqual(self.get_n_pfxs(intf), 0)
3265
3266 #
3267 # add all the interface addresses back on the last two
3268 #
3269 for p in intf_pfxs[2:]:
3270 for v in p:
3271 v.add_vpp_config()
3272 for intf in self.pg_interfaces:
3273 self.assertEqual(self.get_n_pfxs(intf), 3)
3274
3275 #
3276 # replace again, this time add different prefixes on all the interfaces
3277 #
3278 self.vapi.sw_interface_address_replace_begin()
3279
3280 pfxs = []
3281 for intf in self.pg_interfaces:
3282 # 2001:18:x::1/64
3283 addr = "2001:18:%d::1" % intf.sw_if_index
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003284 pfxs.append(VppIpInterfaceAddress(self, intf, addr, 64).add_vpp_config())
Neale Ranns59f71132020-04-08 12:19:38 +00003285
3286 self.vapi.sw_interface_address_replace_end()
3287
3288 # only .18 should exist on each interface
3289 for intf in self.pg_interfaces:
3290 self.assertEqual(self.get_n_pfxs(intf), 1)
3291 for pfx in pfxs:
3292 self.assertTrue(pfx.query_vpp_config())
3293
3294 #
3295 # remove everything
3296 #
3297 self.vapi.sw_interface_address_replace_begin()
3298 self.vapi.sw_interface_address_replace_end()
3299 for intf in self.pg_interfaces:
3300 self.assertEqual(self.get_n_pfxs(intf), 0)
3301
3302 #
3303 # add prefixes to each interface. post-begin add the prefix from
3304 # interface X onto interface Y. this would normally be an error
3305 # since it would generate a 'duplicate address' warning. but in
3306 # this case, since what is newly downloaded is sane, it's ok
3307 #
3308 for intf in self.pg_interfaces:
3309 # 2001:18:x::1/64
3310 addr = "2001:18:%d::1" % intf.sw_if_index
3311 VppIpInterfaceAddress(self, intf, addr, 64).add_vpp_config()
3312
3313 self.vapi.sw_interface_address_replace_begin()
3314
3315 pfxs = []
3316 for intf in self.pg_interfaces:
3317 # 2001:18:x::1/64
3318 addr = "2001:18:%d::1" % (intf.sw_if_index + 1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003319 pfxs.append(VppIpInterfaceAddress(self, intf, addr, 64).add_vpp_config())
Neale Ranns59f71132020-04-08 12:19:38 +00003320
3321 self.vapi.sw_interface_address_replace_end()
3322
3323 self.logger.info(self.vapi.cli("sh int addr"))
3324
3325 for intf in self.pg_interfaces:
3326 self.assertEqual(self.get_n_pfxs(intf), 1)
3327 for pfx in pfxs:
3328 self.assertTrue(pfx.query_vpp_config())
3329
3330
Dmitry Valter34fa0ce2024-03-11 10:38:46 +00003331@unittest.skipIf(
3332 "ping" in config.excluded_plugins, "Exclude tests requiring Ping plugin"
3333)
Neale Rannsec40a7d2020-04-23 07:36:12 +00003334class TestIP6LinkLocal(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003335 """IPv6 Link Local"""
Neale Rannsec40a7d2020-04-23 07:36:12 +00003336
3337 @classmethod
3338 def setUpClass(cls):
3339 super(TestIP6LinkLocal, cls).setUpClass()
3340
3341 @classmethod
3342 def tearDownClass(cls):
3343 super(TestIP6LinkLocal, cls).tearDownClass()
3344
3345 def setUp(self):
3346 super(TestIP6LinkLocal, self).setUp()
3347
3348 self.create_pg_interfaces(range(2))
3349
3350 for i in self.pg_interfaces:
3351 i.admin_up()
3352
3353 def tearDown(self):
3354 super(TestIP6LinkLocal, self).tearDown()
3355 for i in self.pg_interfaces:
3356 i.admin_down()
3357
3358 def test_ip6_ll(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003359 """IPv6 Link Local"""
Neale Rannsec40a7d2020-04-23 07:36:12 +00003360
3361 #
3362 # two APIs to add a link local address.
3363 # 1 - just like any other prefix
3364 # 2 - with the special set LL API
3365 #
3366
3367 #
3368 # First with the API to set a 'normal' prefix
3369 #
3370 ll1 = "fe80:1::1"
3371 ll2 = "fe80:2::2"
3372 ll3 = "fe80:3::3"
3373
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003374 VppNeighbor(
3375 self, self.pg0.sw_if_index, self.pg0.remote_mac, ll2
3376 ).add_vpp_config()
Neale Rannsdfef64b2021-05-20 16:28:12 +00003377
Neale Rannsec40a7d2020-04-23 07:36:12 +00003378 VppIpInterfaceAddress(self, self.pg0, ll1, 128).add_vpp_config()
3379
3380 #
3381 # should be able to ping the ll
3382 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003383 p_echo_request_1 = (
3384 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3385 / IPv6(src=ll2, dst=ll1)
3386 / ICMPv6EchoRequest()
3387 )
Neale Rannsec40a7d2020-04-23 07:36:12 +00003388
3389 self.send_and_expect(self.pg0, [p_echo_request_1], self.pg0)
3390
3391 #
3392 # change the link-local on pg0
3393 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003394 v_ll3 = VppIpInterfaceAddress(self, self.pg0, ll3, 128).add_vpp_config()
Neale Rannsec40a7d2020-04-23 07:36:12 +00003395
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003396 p_echo_request_3 = (
3397 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3398 / IPv6(src=ll2, dst=ll3)
3399 / ICMPv6EchoRequest()
3400 )
Neale Rannsec40a7d2020-04-23 07:36:12 +00003401
3402 self.send_and_expect(self.pg0, [p_echo_request_3], self.pg0)
3403
3404 #
3405 # set a normal v6 prefix on the link
3406 #
3407 self.pg0.config_ip6()
3408
3409 self.send_and_expect(self.pg0, [p_echo_request_3], self.pg0)
3410
3411 # the link-local cannot be removed
3412 with self.vapi.assert_negative_api_retval():
3413 v_ll3.remove_vpp_config()
3414
3415 #
3416 # Use the specific link-local API on pg1
3417 #
3418 VppIp6LinkLocalAddress(self, self.pg1, ll1).add_vpp_config()
Steven Luonge4238aa2024-04-19 09:49:20 -07003419 p_echo_request_1.dst = self.pg1.local_mac
Neale Rannsec40a7d2020-04-23 07:36:12 +00003420 self.send_and_expect(self.pg1, [p_echo_request_1], self.pg1)
3421
3422 VppIp6LinkLocalAddress(self, self.pg1, ll3).add_vpp_config()
Steven Luonge4238aa2024-04-19 09:49:20 -07003423 p_echo_request_3.dst = self.pg1.local_mac
Neale Rannsec40a7d2020-04-23 07:36:12 +00003424 self.send_and_expect(self.pg1, [p_echo_request_3], self.pg1)
3425
Dmitry Valter34fa0ce2024-03-11 10:38:46 +00003426 @unittest.skipIf(
3427 "gre" in config.excluded_plugins, "Exclude tests requiring GRE plugin"
3428 )
Neale Rannsdfef64b2021-05-20 16:28:12 +00003429 def test_ip6_ll_p2p(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003430 """IPv6 Link Local P2P (GRE)"""
Neale Rannsdfef64b2021-05-20 16:28:12 +00003431
3432 self.pg0.config_ip4()
3433 self.pg0.resolve_arp()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003434 gre_if = VppGreInterface(
3435 self, self.pg0.local_ip4, self.pg0.remote_ip4
3436 ).add_vpp_config()
Neale Rannsdfef64b2021-05-20 16:28:12 +00003437 gre_if.admin_up()
3438
3439 ll1 = "fe80:1::1"
3440 ll2 = "fe80:2::2"
3441
3442 VppIpInterfaceAddress(self, gre_if, ll1, 128).add_vpp_config()
3443
3444 self.logger.info(self.vapi.cli("sh ip6-ll gre0 fe80:2::2"))
3445
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003446 p_echo_request_1 = (
3447 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3448 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
3449 / GRE()
3450 / IPv6(src=ll2, dst=ll1)
3451 / ICMPv6EchoRequest()
3452 )
Neale Rannsdfef64b2021-05-20 16:28:12 +00003453 self.send_and_expect(self.pg0, [p_echo_request_1], self.pg0)
3454
3455 self.pg0.unconfig_ip4()
3456 gre_if.remove_vpp_config()
3457
Dmitry Valter34fa0ce2024-03-11 10:38:46 +00003458 @unittest.skipIf(
3459 "gre" in config.excluded_plugins, "Exclude tests requiring GRE plugin"
3460 )
Neale Rannsdfef64b2021-05-20 16:28:12 +00003461 def test_ip6_ll_p2mp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003462 """IPv6 Link Local P2MP (GRE)"""
Neale Rannsdfef64b2021-05-20 16:28:12 +00003463
3464 self.pg0.config_ip4()
3465 self.pg0.resolve_arp()
3466
3467 gre_if = VppGreInterface(
3468 self,
3469 self.pg0.local_ip4,
3470 "0.0.0.0",
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003471 mode=(VppEnum.vl_api_tunnel_mode_t.TUNNEL_API_MODE_MP),
3472 ).add_vpp_config()
Neale Rannsdfef64b2021-05-20 16:28:12 +00003473 gre_if.admin_up()
3474
3475 ll1 = "fe80:1::1"
3476 ll2 = "fe80:2::2"
3477
3478 VppIpInterfaceAddress(self, gre_if, ll1, 128).add_vpp_config()
3479
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003480 p_echo_request_1 = (
3481 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3482 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
3483 / GRE()
3484 / IPv6(src=ll2, dst=ll1)
3485 / ICMPv6EchoRequest()
3486 )
Neale Rannsdfef64b2021-05-20 16:28:12 +00003487
3488 # no route back at this point
3489 self.send_and_assert_no_replies(self.pg0, [p_echo_request_1])
3490
3491 # add teib entry for the peer
3492 teib = VppTeib(self, gre_if, ll2, self.pg0.remote_ip4)
3493 teib.add_vpp_config()
3494
3495 self.logger.info(self.vapi.cli("sh ip6-ll gre0 %s" % ll2))
3496 self.send_and_expect(self.pg0, [p_echo_request_1], self.pg0)
3497
3498 # teardown
3499 self.pg0.unconfig_ip4()
3500
Neale Rannsec40a7d2020-04-23 07:36:12 +00003501
Neale Ranns8f5fef22020-12-21 08:29:34 +00003502class TestIPv6PathMTU(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003503 """IPv6 Path MTU"""
Neale Ranns8f5fef22020-12-21 08:29:34 +00003504
3505 def setUp(self):
3506 super(TestIPv6PathMTU, self).setUp()
3507
3508 self.create_pg_interfaces(range(2))
3509
3510 # setup all interfaces
3511 for i in self.pg_interfaces:
3512 i.admin_up()
3513 i.config_ip6()
3514 i.resolve_ndp()
3515
3516 def tearDown(self):
3517 super(TestIPv6PathMTU, self).tearDown()
3518 for i in self.pg_interfaces:
3519 i.unconfig_ip6()
3520 i.admin_down()
3521
3522 def test_path_mtu_local(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003523 """Path MTU for attached neighbour"""
Neale Ranns8f5fef22020-12-21 08:29:34 +00003524
3525 self.vapi.cli("set log class ip level debug")
3526 #
3527 # The goal here is not test that fragmentation works correctly,
3528 # that's done elsewhere, the intent is to ensure that the Path MTU
3529 # settings are honoured.
3530 #
3531
3532 #
3533 # IPv6 will only frag locally generated packets, so use tunnelled
3534 # packets post encap
3535 #
3536 tun = VppIpIpTunInterface(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003537 self, self.pg1, self.pg1.local_ip6, self.pg1.remote_ip6
3538 )
Neale Ranns8f5fef22020-12-21 08:29:34 +00003539 tun.add_vpp_config()
3540 tun.admin_up()
3541 tun.config_ip6()
3542
3543 # set the interface MTU to a reasonable value
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003544 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2800, 0, 0, 0])
Neale Ranns8f5fef22020-12-21 08:29:34 +00003545
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003546 p_6k = (
3547 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3548 / IPv6(src=self.pg0.remote_ip6, dst=tun.remote_ip6)
3549 / UDP(sport=1234, dport=5678)
3550 / Raw(b"0xa" * 2000)
3551 )
3552 p_2k = (
3553 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3554 / IPv6(src=self.pg0.remote_ip6, dst=tun.remote_ip6)
3555 / UDP(sport=1234, dport=5678)
3556 / Raw(b"0xa" * 1000)
3557 )
3558 p_1k = (
3559 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3560 / IPv6(src=self.pg0.remote_ip6, dst=tun.remote_ip6)
3561 / UDP(sport=1234, dport=5678)
3562 / Raw(b"0xa" * 600)
3563 )
Neale Ranns8f5fef22020-12-21 08:29:34 +00003564
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003565 nbr = VppNeighbor(
3566 self, self.pg1.sw_if_index, self.pg1.remote_mac, self.pg1.remote_ip6
3567 ).add_vpp_config()
Neale Ranns8f5fef22020-12-21 08:29:34 +00003568
3569 # this is now the interface MTU frags
Neale Rannsec5371e2022-03-04 11:45:41 +00003570 self.send_and_expect(self.pg0, [p_6k], self.pg1, n_rx=4)
Neale Ranns8f5fef22020-12-21 08:29:34 +00003571 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3572 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3573
3574 # drop the path MTU for this neighbour to below the interface MTU
3575 # expect more frags
3576 pmtu = VppIpPathMtu(self, self.pg1.remote_ip6, 1300).add_vpp_config()
3577
3578 # print/format the adj delegate and trackers
3579 self.logger.info(self.vapi.cli("sh ip pmtu"))
3580 self.logger.info(self.vapi.cli("sh adj 7"))
3581
3582 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3583 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3584
3585 # increase the path MTU to more than the interface
3586 # expect to use the interface MTU
3587 pmtu.modify(8192)
3588
3589 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3590 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3591
3592 # go back to an MTU from the path
3593 pmtu.modify(1300)
3594
3595 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3596 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3597
3598 # raise the interface's MTU
3599 # should still use that of the path
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003600 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2000, 0, 0, 0])
Neale Ranns8f5fef22020-12-21 08:29:34 +00003601 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3602 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3603
3604 # set path high and interface low
3605 pmtu.modify(2000)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003606 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1300, 0, 0, 0])
Neale Ranns8f5fef22020-12-21 08:29:34 +00003607 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3608 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3609
3610 # remove the path MTU
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003611 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2800, 0, 0, 0])
Neale Ranns8f5fef22020-12-21 08:29:34 +00003612 pmtu.modify(0)
3613
3614 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3615 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3616
3617 def test_path_mtu_remote(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003618 """Path MTU for remote neighbour"""
Neale Ranns8f5fef22020-12-21 08:29:34 +00003619
3620 self.vapi.cli("set log class ip level debug")
3621 #
3622 # The goal here is not test that fragmentation works correctly,
3623 # that's done elsewhere, the intent is to ensure that the Path MTU
3624 # settings are honoured.
3625 #
3626 tun_dst = "2001::1"
3627
3628 route = VppIpRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003629 self, tun_dst, 64, [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)]
3630 ).add_vpp_config()
Neale Ranns8f5fef22020-12-21 08:29:34 +00003631
3632 #
3633 # IPv6 will only frag locally generated packets, so use tunnelled
3634 # packets post encap
3635 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003636 tun = VppIpIpTunInterface(self, self.pg1, self.pg1.local_ip6, tun_dst)
Neale Ranns8f5fef22020-12-21 08:29:34 +00003637 tun.add_vpp_config()
3638 tun.admin_up()
3639 tun.config_ip6()
3640
3641 # set the interface MTU to a reasonable value
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003642 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2800, 0, 0, 0])
Neale Ranns8f5fef22020-12-21 08:29:34 +00003643
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003644 p_2k = (
3645 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3646 / IPv6(src=self.pg0.remote_ip6, dst=tun.remote_ip6)
3647 / UDP(sport=1234, dport=5678)
3648 / Raw(b"0xa" * 1000)
3649 )
3650 p_1k = (
3651 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3652 / IPv6(src=self.pg0.remote_ip6, dst=tun.remote_ip6)
3653 / UDP(sport=1234, dport=5678)
3654 / Raw(b"0xa" * 600)
3655 )
Neale Ranns8f5fef22020-12-21 08:29:34 +00003656
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003657 nbr = VppNeighbor(
3658 self, self.pg1.sw_if_index, self.pg1.remote_mac, self.pg1.remote_ip6
3659 ).add_vpp_config()
Neale Ranns8f5fef22020-12-21 08:29:34 +00003660
3661 # this is now the interface MTU frags
3662 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3663 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3664
3665 # drop the path MTU for this neighbour to below the interface MTU
3666 # expect more frags
3667 pmtu = VppIpPathMtu(self, tun_dst, 1300).add_vpp_config()
3668
3669 # print/format the fib entry/dpo
3670 self.logger.info(self.vapi.cli("sh ip6 fib 2001::1"))
3671
3672 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3673 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3674
3675 # increase the path MTU to more than the interface
3676 # expect to use the interface MTU
3677 pmtu.modify(8192)
3678
3679 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3680 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3681
3682 # go back to an MTU from the path
3683 pmtu.modify(1300)
3684
3685 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3686 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3687
3688 # raise the interface's MTU
3689 # should still use that of the path
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003690 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2000, 0, 0, 0])
Neale Ranns8f5fef22020-12-21 08:29:34 +00003691 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3692 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3693
3694 # turn the tun_dst into an attached neighbour
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003695 route.modify([VppRoutePath("::", self.pg1.sw_if_index)])
3696 nbr2 = VppNeighbor(
3697 self, self.pg1.sw_if_index, self.pg1.remote_mac, tun_dst
3698 ).add_vpp_config()
Neale Ranns8f5fef22020-12-21 08:29:34 +00003699
3700 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3701 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3702
3703 # add back to not attached
3704 nbr2.remove_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003705 route.modify([VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)])
Neale Ranns8f5fef22020-12-21 08:29:34 +00003706
3707 # set path high and interface low
3708 pmtu.modify(2000)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003709 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1300, 0, 0, 0])
Neale Ranns8f5fef22020-12-21 08:29:34 +00003710 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3711 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3712
3713 # remove the path MTU
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003714 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2800, 0, 0, 0])
Neale Ranns8f5fef22020-12-21 08:29:34 +00003715 pmtu.remove_vpp_config()
3716 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3717 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3718
3719
Neale Ranns976b2592019-12-04 06:11:00 +00003720class TestIPFibSource(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003721 """IPv6 Table FibSource"""
Neale Ranns976b2592019-12-04 06:11:00 +00003722
3723 @classmethod
3724 def setUpClass(cls):
3725 super(TestIPFibSource, cls).setUpClass()
3726
3727 @classmethod
3728 def tearDownClass(cls):
3729 super(TestIPFibSource, cls).tearDownClass()
3730
3731 def setUp(self):
3732 super(TestIPFibSource, self).setUp()
3733
3734 self.create_pg_interfaces(range(2))
3735
3736 for i in self.pg_interfaces:
3737 i.admin_up()
3738 i.config_ip6()
3739 i.resolve_arp()
3740 i.generate_remote_hosts(2)
3741 i.configure_ipv6_neighbors()
3742
3743 def tearDown(self):
3744 super(TestIPFibSource, self).tearDown()
3745 for i in self.pg_interfaces:
3746 i.admin_down()
3747 i.unconfig_ip4()
3748
3749 def test_fib_source(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003750 """IP Table FibSource"""
Neale Ranns976b2592019-12-04 06:11:00 +00003751
3752 routes = self.vapi.ip_route_v2_dump(0, True)
3753
3754 # 2 interfaces (4 routes) + 2 specials + 4 neighbours = 10 routes
3755 self.assertEqual(len(routes), 10)
3756
3757 # dump all the sources in the FIB
3758 sources = self.vapi.fib_source_dump()
3759 for source in sources:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003760 if source.src.name == "API":
Neale Ranns976b2592019-12-04 06:11:00 +00003761 api_source = source.src
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003762 if source.src.name == "interface":
Neale Ranns976b2592019-12-04 06:11:00 +00003763 intf_source = source.src
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003764 if source.src.name == "adjacency":
Neale Ranns976b2592019-12-04 06:11:00 +00003765 adj_source = source.src
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003766 if source.src.name == "special":
Neale Ranns976b2592019-12-04 06:11:00 +00003767 special_source = source.src
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003768 if source.src.name == "default-route":
Neale Ranns976b2592019-12-04 06:11:00 +00003769 dr_source = source.src
3770
3771 # dump the individual route types
3772 routes = self.vapi.ip_route_v2_dump(0, True, src=adj_source.id)
3773 self.assertEqual(len(routes), 4)
3774 routes = self.vapi.ip_route_v2_dump(0, True, src=intf_source.id)
3775 self.assertEqual(len(routes), 4)
3776 routes = self.vapi.ip_route_v2_dump(0, True, src=special_source.id)
3777 self.assertEqual(len(routes), 1)
3778 routes = self.vapi.ip_route_v2_dump(0, True, src=dr_source.id)
3779 self.assertEqual(len(routes), 1)
3780
3781 # add a new soure that'a better than the API
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003782 self.vapi.fib_source_add(
3783 src={"name": "bgp", "priority": api_source.priority - 1}
3784 )
Neale Ranns976b2592019-12-04 06:11:00 +00003785
3786 # dump all the sources to check our new one is there
3787 sources = self.vapi.fib_source_dump()
3788
3789 for source in sources:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003790 if source.src.name == "bgp":
Neale Ranns976b2592019-12-04 06:11:00 +00003791 bgp_source = source.src
3792
3793 self.assertTrue(bgp_source)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003794 self.assertEqual(bgp_source.priority, api_source.priority - 1)
Neale Ranns976b2592019-12-04 06:11:00 +00003795
3796 # add a route with the default API source
3797 r1 = VppIpRouteV2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003798 self,
3799 "2001::1",
3800 128,
3801 [VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index)],
3802 ).add_vpp_config()
Neale Ranns976b2592019-12-04 06:11:00 +00003803
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003804 r2 = VppIpRouteV2(
3805 self,
3806 "2001::1",
3807 128,
3808 [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)],
3809 src=bgp_source.id,
3810 ).add_vpp_config()
Neale Ranns976b2592019-12-04 06:11:00 +00003811
3812 # ensure the BGP source takes priority
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003813 p = (
3814 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3815 / IPv6(src=self.pg0.remote_ip6, dst="2001::1")
3816 / inet6.UDP(sport=1234, dport=1234)
3817 / Raw(b"\xa5" * 100)
3818 )
Neale Ranns976b2592019-12-04 06:11:00 +00003819
3820 self.send_and_expect(self.pg0, [p], self.pg1)
3821
3822 r2.remove_vpp_config()
3823 r1.remove_vpp_config()
3824
3825 self.assertFalse(find_route(self, "2001::1", 128))
3826
3827
Neale Ranns91adf242021-05-27 12:18:52 +00003828class TestIPxAF(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003829 """IP cross AF"""
Neale Ranns91adf242021-05-27 12:18:52 +00003830
3831 @classmethod
3832 def setUpClass(cls):
3833 super(TestIPxAF, cls).setUpClass()
3834
3835 @classmethod
3836 def tearDownClass(cls):
3837 super(TestIPxAF, cls).tearDownClass()
3838
3839 def setUp(self):
3840 super(TestIPxAF, self).setUp()
3841
3842 self.create_pg_interfaces(range(2))
3843
3844 for i in self.pg_interfaces:
3845 i.admin_up()
3846 i.config_ip6()
3847 i.config_ip4()
3848 i.resolve_arp()
3849 i.resolve_ndp()
3850
3851 def tearDown(self):
3852 super(TestIPxAF, self).tearDown()
3853 for i in self.pg_interfaces:
3854 i.admin_down()
3855 i.unconfig_ip4()
3856 i.unconfig_ip6()
3857
3858 def test_x_af(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003859 """Cross AF routing"""
Neale Ranns91adf242021-05-27 12:18:52 +00003860
3861 N_PKTS = 63
3862 # a v4 route via a v6 attached next-hop
3863 VppIpRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003864 self,
3865 "1.1.1.1",
3866 32,
3867 [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)],
3868 ).add_vpp_config()
Neale Ranns91adf242021-05-27 12:18:52 +00003869
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003870 p = (
3871 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3872 / IP(src=self.pg0.remote_ip4, dst="1.1.1.1")
3873 / UDP(sport=1234, dport=1234)
3874 / Raw(b"\xa5" * 100)
3875 )
Neale Ranns91adf242021-05-27 12:18:52 +00003876 rxs = self.send_and_expect(self.pg0, p * N_PKTS, self.pg1)
3877
3878 for rx in rxs:
3879 self.assertEqual(rx[IP].dst, "1.1.1.1")
3880
3881 # a v6 route via a v4 attached next-hop
3882 VppIpRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003883 self,
3884 "2001::1",
3885 128,
3886 [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
3887 ).add_vpp_config()
Neale Ranns91adf242021-05-27 12:18:52 +00003888
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003889 p = (
3890 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3891 / IPv6(src=self.pg0.remote_ip6, dst="2001::1")
3892 / UDP(sport=1234, dport=1234)
3893 / Raw(b"\xa5" * 100)
3894 )
Neale Ranns91adf242021-05-27 12:18:52 +00003895 rxs = self.send_and_expect(self.pg0, p * N_PKTS, self.pg1)
3896
3897 for rx in rxs:
3898 self.assertEqual(rx[IPv6].dst, "2001::1")
3899
3900 # a recursive v4 route via a v6 next-hop (from above)
3901 VppIpRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003902 self, "2.2.2.2", 32, [VppRoutePath("2001::1", 0xFFFFFFFF)]
3903 ).add_vpp_config()
Neale Ranns91adf242021-05-27 12:18:52 +00003904
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003905 p = (
3906 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3907 / IP(src=self.pg0.remote_ip4, dst="2.2.2.2")
3908 / UDP(sport=1234, dport=1234)
3909 / Raw(b"\xa5" * 100)
3910 )
Neale Ranns91adf242021-05-27 12:18:52 +00003911 rxs = self.send_and_expect(self.pg0, p * N_PKTS, self.pg1)
3912
3913 # a recursive v4 route via a v6 next-hop
3914 VppIpRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003915 self, "2.2.2.3", 32, [VppRoutePath(self.pg1.remote_ip6, 0xFFFFFFFF)]
3916 ).add_vpp_config()
Neale Ranns91adf242021-05-27 12:18:52 +00003917
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003918 p = (
3919 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3920 / IP(src=self.pg0.remote_ip4, dst="2.2.2.3")
3921 / UDP(sport=1234, dport=1234)
3922 / Raw(b"\xa5" * 100)
3923 )
Neale Ranns91adf242021-05-27 12:18:52 +00003924 rxs = self.send_and_expect(self.pg0, p * N_PKTS, self.pg1)
3925
3926 # a recursive v6 route via a v4 next-hop
3927 VppIpRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003928 self, "3001::1", 128, [VppRoutePath(self.pg1.remote_ip4, 0xFFFFFFFF)]
3929 ).add_vpp_config()
Neale Ranns91adf242021-05-27 12:18:52 +00003930
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003931 p = (
3932 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3933 / IPv6(src=self.pg0.remote_ip6, dst="3001::1")
3934 / UDP(sport=1234, dport=1234)
3935 / Raw(b"\xa5" * 100)
3936 )
Neale Ranns91adf242021-05-27 12:18:52 +00003937 rxs = self.send_and_expect(self.pg0, p * N_PKTS, self.pg1)
3938
3939 for rx in rxs:
3940 self.assertEqual(rx[IPv6].dst, "3001::1")
3941
3942 VppIpRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003943 self, "3001::2", 128, [VppRoutePath("1.1.1.1", 0xFFFFFFFF)]
3944 ).add_vpp_config()
Neale Ranns91adf242021-05-27 12:18:52 +00003945
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003946 p = (
3947 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3948 / IPv6(src=self.pg0.remote_ip6, dst="3001::2")
3949 / UDP(sport=1234, dport=1234)
3950 / Raw(b"\xa5" * 100)
3951 )
Neale Ranns91adf242021-05-27 12:18:52 +00003952 rxs = self.send_and_expect(self.pg0, p * N_PKTS, self.pg1)
3953
3954 for rx in rxs:
3955 self.assertEqual(rx[IPv6].dst, "3001::2")
3956
3957
Benoît Ganne7c7b5052021-10-04 12:03:20 +02003958class TestIPv6Punt(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003959 """IPv6 Punt Police/Redirect"""
Benoît Ganne7c7b5052021-10-04 12:03:20 +02003960
3961 def setUp(self):
3962 super(TestIPv6Punt, self).setUp()
3963 self.create_pg_interfaces(range(4))
3964
3965 for i in self.pg_interfaces:
3966 i.admin_up()
3967 i.config_ip6()
3968 i.resolve_ndp()
3969
3970 def tearDown(self):
3971 super(TestIPv6Punt, self).tearDown()
3972 for i in self.pg_interfaces:
3973 i.unconfig_ip6()
3974 i.admin_down()
3975
3976 def test_ip6_punt(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003977 """IPv6 punt police and redirect"""
Benoît Ganne7c7b5052021-10-04 12:03:20 +02003978
3979 # use UDP packet that have a port we need to explicitly
3980 # register to get punted.
3981 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
3982 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
3983 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
3984 punt_udp = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003985 "type": pt_l4,
3986 "punt": {
3987 "l4": {
3988 "af": af_ip6,
3989 "protocol": udp_proto,
3990 "port": 7654,
Benoît Ganne7c7b5052021-10-04 12:03:20 +02003991 }
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003992 },
Benoît Ganne7c7b5052021-10-04 12:03:20 +02003993 }
3994
3995 self.vapi.set_punt(is_add=1, punt=punt_udp)
3996
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003997 pkts = (
3998 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3999 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
4000 / UDP(sport=1234, dport=7654)
4001 / Raw(b"\xa5" * 100)
4002 ) * 1025
Benoît Ganne7c7b5052021-10-04 12:03:20 +02004003
4004 #
4005 # Configure a punt redirect via pg1.
4006 #
4007 nh_addr = self.pg1.remote_ip6
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02004008 ip_punt_redirect = VppIpPuntRedirect(
4009 self, self.pg0.sw_if_index, self.pg1.sw_if_index, nh_addr
4010 )
Benoît Ganne7c7b5052021-10-04 12:03:20 +02004011 ip_punt_redirect.add_vpp_config()
4012
4013 self.send_and_expect(self.pg0, pkts, self.pg1)
4014
4015 #
4016 # add a policer
4017 #
4018 policer = VppPolicer(self, "ip6-punt", 400, 0, 10, 0, rate_type=1)
4019 policer.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02004020 ip_punt_policer = VppIpPuntPolicer(self, policer.policer_index, is_ip6=True)
Benoît Ganne7c7b5052021-10-04 12:03:20 +02004021 ip_punt_policer.add_vpp_config()
4022
4023 self.vapi.cli("clear trace")
4024 self.pg0.add_stream(pkts)
4025 self.pg_enable_capture(self.pg_interfaces)
4026 self.pg_start()
4027
4028 #
4029 # the number of packet received should be greater than 0,
4030 # but not equal to the number sent, since some were policed
4031 #
4032 rx = self.pg1._get_capture(1)
4033
4034 stats = policer.get_stats()
4035
4036 # Single rate policer - expect conform, violate but no exceed
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02004037 self.assertGreater(stats["conform_packets"], 0)
4038 self.assertEqual(stats["exceed_packets"], 0)
4039 self.assertGreater(stats["violate_packets"], 0)
Benoît Ganne7c7b5052021-10-04 12:03:20 +02004040
4041 self.assertGreater(len(rx), 0)
4042 self.assertLess(len(rx), len(pkts))
4043
4044 #
4045 # remove the policer. back to full rx
4046 #
4047 ip_punt_policer.remove_vpp_config()
4048 policer.remove_vpp_config()
4049 self.send_and_expect(self.pg0, pkts, self.pg1)
4050
4051 #
4052 # remove the redirect. expect full drop.
4053 #
4054 ip_punt_redirect.remove_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02004055 self.send_and_assert_no_replies(self.pg0, pkts, "IP no punt config")
Benoît Ganne7c7b5052021-10-04 12:03:20 +02004056
4057 #
4058 # Add a redirect that is not input port selective
4059 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02004060 ip_punt_redirect = VppIpPuntRedirect(
4061 self, 0xFFFFFFFF, self.pg1.sw_if_index, nh_addr
4062 )
Benoît Ganne7c7b5052021-10-04 12:03:20 +02004063 ip_punt_redirect.add_vpp_config()
4064 self.send_and_expect(self.pg0, pkts, self.pg1)
4065 ip_punt_redirect.remove_vpp_config()
4066
4067 def test_ip6_punt_dump(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02004068 """IPv6 punt redirect dump"""
Benoît Ganne7c7b5052021-10-04 12:03:20 +02004069
4070 #
4071 # Configure a punt redirects
4072 #
4073 nh_address = self.pg3.remote_ip6
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02004074 ipr_03 = VppIpPuntRedirect(
4075 self, self.pg0.sw_if_index, self.pg3.sw_if_index, nh_address
4076 )
4077 ipr_13 = VppIpPuntRedirect(
4078 self, self.pg1.sw_if_index, self.pg3.sw_if_index, nh_address
4079 )
4080 ipr_23 = VppIpPuntRedirect(
4081 self, self.pg2.sw_if_index, self.pg3.sw_if_index, "::"
4082 )
Benoît Ganne7c7b5052021-10-04 12:03:20 +02004083 ipr_03.add_vpp_config()
4084 ipr_13.add_vpp_config()
4085 ipr_23.add_vpp_config()
4086
4087 #
4088 # Dump pg0 punt redirects
4089 #
4090 self.assertTrue(ipr_03.query_vpp_config())
4091 self.assertTrue(ipr_13.query_vpp_config())
4092 self.assertTrue(ipr_23.query_vpp_config())
4093
4094 #
4095 # Dump punt redirects for all interfaces
4096 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02004097 punts = self.vapi.ip_punt_redirect_dump(sw_if_index=0xFFFFFFFF, is_ipv6=True)
Benoît Ganne7c7b5052021-10-04 12:03:20 +02004098 self.assertEqual(len(punts), 3)
4099 for p in punts:
4100 self.assertEqual(p.punt.tx_sw_if_index, self.pg3.sw_if_index)
4101 self.assertNotEqual(punts[1].punt.nh, self.pg3.remote_ip6)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02004102 self.assertEqual(str(punts[2].punt.nh), "::")
Benoît Ganne7c7b5052021-10-04 12:03:20 +02004103
4104
Vladislav Grishenkodea806d2024-02-20 11:58:01 +05004105class TestIP6InterfaceRx(VppTestCase):
4106 """IPv6 Interface Receive"""
4107
4108 @classmethod
4109 def setUpClass(cls):
4110 super(TestIP6InterfaceRx, cls).setUpClass()
4111
4112 @classmethod
4113 def tearDownClass(cls):
4114 super(TestIP6InterfaceRx, cls).tearDownClass()
4115
4116 def setUp(self):
4117 super(TestIP6InterfaceRx, self).setUp()
4118
4119 self.create_pg_interfaces(range(3))
4120
4121 table_id = 0
4122
4123 for i in self.pg_interfaces:
4124 i.admin_up()
4125
4126 if table_id != 0:
4127 table = VppIpTable(self, table_id, is_ip6=1)
4128 table.add_vpp_config()
4129
4130 i.set_table_ip6(table_id)
4131 i.config_ip6()
4132 i.resolve_ndp()
4133 table_id += 1
4134
4135 def tearDown(self):
4136 for i in self.pg_interfaces:
4137 i.unconfig_ip6()
4138 i.admin_down()
4139 i.set_table_ip6(0)
4140
4141 super(TestIP6InterfaceRx, self).tearDown()
4142
4143 def test_interface_rx(self):
4144 """IPv6 Interface Receive"""
4145
4146 #
4147 # add a route in the default table to receive ...
4148 #
4149 route_to_dst = VppIpRoute(
4150 self,
4151 "1::",
4152 122,
4153 [
4154 VppRoutePath(
4155 "::",
4156 self.pg1.sw_if_index,
4157 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
4158 )
4159 ],
4160 )
4161 route_to_dst.add_vpp_config()
4162
4163 #
4164 # packets to these destination are dropped, since they'll
4165 # hit the respective default routes in table 1
4166 #
4167 p_dst = (
4168 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
4169 / IPv6(src="5::5", dst="1::1")
4170 / inet6.TCP(sport=1234, dport=1234)
4171 / Raw(b"\xa5" * 100)
4172 )
4173 pkts_dst = p_dst * 10
4174
4175 self.send_and_assert_no_replies(self.pg0, pkts_dst, "IP in table 1")
4176
4177 #
4178 # add a route in the dst table to forward via pg1
4179 #
4180 route_in_dst = VppIpRoute(
4181 self,
4182 "1::1",
4183 128,
4184 [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)],
4185 table_id=1,
4186 )
4187 route_in_dst.add_vpp_config()
4188
4189 self.send_and_expect(self.pg0, pkts_dst, self.pg1)
4190
4191 #
4192 # add a route in the default table to receive ...
4193 #
4194 route_to_dst = VppIpRoute(
4195 self,
4196 "1::",
4197 122,
4198 [
4199 VppRoutePath(
4200 "::",
4201 self.pg2.sw_if_index,
4202 type=FibPathType.FIB_PATH_TYPE_INTERFACE_RX,
4203 )
4204 ],
4205 table_id=1,
4206 )
4207 route_to_dst.add_vpp_config()
4208
4209 #
4210 # packets to these destination are dropped, since they'll
4211 # hit the respective default routes in table 2
4212 #
4213 p_dst = (
4214 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
4215 / IPv6(src="6::6", dst="1::2")
4216 / inet6.TCP(sport=1234, dport=1234)
4217 / Raw(b"\xa5" * 100)
4218 )
4219 pkts_dst = p_dst * 10
4220
4221 self.send_and_assert_no_replies(self.pg0, pkts_dst, "IP in table 2")
4222
4223 #
4224 # add a route in the table 2 to forward via pg2
4225 #
4226 route_in_dst = VppIpRoute(
4227 self,
4228 "1::2",
4229 128,
4230 [VppRoutePath(self.pg2.remote_ip6, self.pg2.sw_if_index)],
4231 table_id=2,
4232 )
4233 route_in_dst.add_vpp_config()
4234
4235 self.send_and_expect(self.pg0, pkts_dst, self.pg2)
4236
4237
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02004238if __name__ == "__main__":
Klement Sekeraf62ae122016-10-11 11:47:09 +02004239 unittest.main(testRunner=VppTestRunner)