blob: b46bef65f1630685d4f5e6481eca95b78602c96e [file] [log] [blame]
Renato Botelho do Coutoead1e532019-10-31 13:31:07 -05001#!/usr/bin/env python3
Damjan Marionf56b77a2016-10-03 19:44:57 +02002
Paul Vinciguerra582eac52020-04-03 12:18:40 -04003import socket
snaramre5d4b8912019-12-13 23:39:35 +00004from socket import inet_pton, inet_ntop
Paul Vinciguerraa6fe4632018-11-25 11:21:50 -08005import unittest
6
Neale Rannsae809832018-11-23 09:00:27 -08007from parameterized import parameterized
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07008import scapy.compat
Paul Vinciguerraa6fe4632018-11-25 11:21:50 -08009import scapy.layers.inet6 as inet6
Neale Rannsdfef64b2021-05-20 16:28:12 +000010from scapy.layers.inet import UDP, IP
Paul Vinciguerraa6fe4632018-11-25 11:21:50 -080011from scapy.contrib.mpls import MPLS
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020012from scapy.layers.inet6 import (
13 IPv6,
14 ICMPv6ND_NS,
15 ICMPv6ND_RS,
16 ICMPv6ND_RA,
17 ICMPv6NDOptMTU,
18 ICMPv6NDOptSrcLLAddr,
19 ICMPv6NDOptPrefixInfo,
20 ICMPv6ND_NA,
21 ICMPv6NDOptDstLLAddr,
22 ICMPv6DestUnreach,
23 icmp6types,
24 ICMPv6TimeExceeded,
25 ICMPv6EchoRequest,
26 ICMPv6EchoReply,
27 IPv6ExtHdrHopByHop,
28 ICMPv6MLReport2,
29 ICMPv6MLDMultAddrRec,
30)
Neale Rannsdfef64b2021-05-20 16:28:12 +000031from scapy.layers.l2 import Ether, Dot1Q, GRE
Paul Vinciguerraa6fe4632018-11-25 11:21:50 -080032from scapy.packet import Raw
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020033from scapy.utils6 import (
34 in6_getnsma,
35 in6_getnsmac,
36 in6_ptop,
37 in6_islladdr,
38 in6_mactoifaceid,
39)
Paul Vinciguerraa6fe4632018-11-25 11:21:50 -080040from six import moves
Klement Sekeraf62ae122016-10-11 11:47:09 +020041
Andrew Yourtchenko06f32812021-01-14 10:19:08 +000042from framework import VppTestCase, VppTestRunner, tag_run_solo
Paul Vinciguerrae8fece82019-02-28 15:34:00 -080043from util import ppp, ip6_normalize, mk_ll_addr
Neale Ranns990f6942020-10-20 07:20:17 +000044from vpp_papi import VppEnum
Neale Ranns8f5fef22020-12-21 08:29:34 +000045from vpp_ip import DpoProto, VppIpPuntPolicer, VppIpPuntRedirect, VppIpPathMtu
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020046from vpp_ip_route import (
47 VppIpRoute,
48 VppRoutePath,
49 find_route,
50 VppIpMRoute,
51 VppMRoutePath,
52 VppMplsIpBind,
53 VppMplsRoute,
54 VppMplsTable,
55 VppIpTable,
56 FibPathType,
57 FibPathProto,
58 VppIpInterfaceAddress,
59 find_route_in_dump,
60 find_mroute_in_dump,
61 VppIp6LinkLocalAddress,
62 VppIpRouteV2,
63)
Neale Rannsb3b2de72017-03-08 05:17:22 -080064from vpp_neighbor import find_nbr, VppNeighbor
Neale Ranns8f5fef22020-12-21 08:29:34 +000065from vpp_ipip_tun_interface import VppIpIpTunInterface
Paul Vinciguerraa6fe4632018-11-25 11:21:50 -080066from vpp_pg_interface import is_ipv6_misc
67from vpp_sub_interface import VppSubInterface, VppDot1QSubint
Brian Russell5214f3a2021-01-19 16:58:34 +000068from vpp_policer import VppPolicer, PolicerAction
Neale Rannsefd7bc22019-11-11 08:32:34 +000069from ipaddress import IPv6Network, IPv6Address
Neale Rannsdfef64b2021-05-20 16:28:12 +000070from vpp_gre_interface import VppGreInterface
71from vpp_teib import VppTeib
Neale Ranns75152282017-01-09 01:00:45 -080072
Juraj Sloboda4b9669d2018-01-15 10:39:21 +010073AF_INET6 = socket.AF_INET6
74
Paul Vinciguerra1e18eb22018-11-25 16:09:26 -080075try:
76 text_type = unicode
77except NameError:
78 text_type = str
79
Paul Vinciguerra4271c972019-05-14 13:25:49 -040080NUM_PKTS = 67
81
Juraj Sloboda4b9669d2018-01-15 10:39:21 +010082
Neale Ranns3f844d02017-02-18 00:03:54 -080083class TestIPv6ND(VppTestCase):
84 def validate_ra(self, intf, rx, dst_ip=None):
85 if not dst_ip:
86 dst_ip = intf.remote_ip6
87
88 # unicasted packets must come to the unicast mac
89 self.assertEqual(rx[Ether].dst, intf.remote_mac)
90
91 # and from the router's MAC
92 self.assertEqual(rx[Ether].src, intf.local_mac)
93
94 # the rx'd RA should be addressed to the sender's source
95 self.assertTrue(rx.haslayer(ICMPv6ND_RA))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020096 self.assertEqual(in6_ptop(rx[IPv6].dst), in6_ptop(dst_ip))
Neale Ranns3f844d02017-02-18 00:03:54 -080097
98 # and come from the router's link local
99 self.assertTrue(in6_islladdr(rx[IPv6].src))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200100 self.assertEqual(in6_ptop(rx[IPv6].src), in6_ptop(mk_ll_addr(intf.local_mac)))
Neale Ranns3f844d02017-02-18 00:03:54 -0800101
102 def validate_na(self, intf, rx, dst_ip=None, tgt_ip=None):
103 if not dst_ip:
104 dst_ip = intf.remote_ip6
105 if not tgt_ip:
106 dst_ip = intf.local_ip6
107
108 # unicasted packets must come to the unicast mac
109 self.assertEqual(rx[Ether].dst, intf.remote_mac)
110
111 # and from the router's MAC
112 self.assertEqual(rx[Ether].src, intf.local_mac)
113
114 # the rx'd NA should be addressed to the sender's source
115 self.assertTrue(rx.haslayer(ICMPv6ND_NA))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200116 self.assertEqual(in6_ptop(rx[IPv6].dst), in6_ptop(dst_ip))
Neale Ranns3f844d02017-02-18 00:03:54 -0800117
118 # and come from the target address
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200119 self.assertEqual(in6_ptop(rx[IPv6].src), in6_ptop(tgt_ip))
Neale Ranns3f844d02017-02-18 00:03:54 -0800120
121 # Dest link-layer options should have the router's MAC
122 dll = rx[ICMPv6NDOptDstLLAddr]
123 self.assertEqual(dll.lladdr, intf.local_mac)
124
Neale Rannsdcd6d622017-05-26 02:59:16 -0700125 def validate_ns(self, intf, rx, tgt_ip):
126 nsma = in6_getnsma(inet_pton(AF_INET6, tgt_ip))
127 dst_ip = inet_ntop(AF_INET6, nsma)
128
129 # NS is broadcast
Neale Rannsc7b8f202018-04-25 06:34:31 -0700130 self.assertEqual(rx[Ether].dst, in6_getnsmac(nsma))
Neale Rannsdcd6d622017-05-26 02:59:16 -0700131
132 # and from the router's MAC
133 self.assertEqual(rx[Ether].src, intf.local_mac)
134
135 # the rx'd NS should be addressed to an mcast address
136 # derived from the target address
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200137 self.assertEqual(in6_ptop(rx[IPv6].dst), in6_ptop(dst_ip))
Neale Rannsdcd6d622017-05-26 02:59:16 -0700138
139 # expect the tgt IP in the NS header
140 ns = rx[ICMPv6ND_NS]
141 self.assertEqual(in6_ptop(ns.tgt), in6_ptop(tgt_ip))
142
143 # packet is from the router's local address
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200144 self.assertEqual(in6_ptop(rx[IPv6].src), intf.local_ip6)
Neale Rannsdcd6d622017-05-26 02:59:16 -0700145
146 # Src link-layer options should have the router's MAC
147 sll = rx[ICMPv6NDOptSrcLLAddr]
148 self.assertEqual(sll.lladdr, intf.local_mac)
149
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200150 def send_and_expect_ra(
151 self, intf, pkts, remark, dst_ip=None, filter_out_fn=is_ipv6_misc
152 ):
Neale Ranns3f844d02017-02-18 00:03:54 -0800153 intf.add_stream(pkts)
Neale Ranns3f844d02017-02-18 00:03:54 -0800154 self.pg_enable_capture(self.pg_interfaces)
155 self.pg_start()
156 rx = intf.get_capture(1, filter_out_fn=filter_out_fn)
157
158 self.assertEqual(len(rx), 1)
159 rx = rx[0]
160 self.validate_ra(intf, rx, dst_ip)
161
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200162 def send_and_expect_na(
163 self, intf, pkts, remark, dst_ip=None, tgt_ip=None, filter_out_fn=is_ipv6_misc
164 ):
Neale Ranns2a3ea492017-04-19 05:24:40 -0700165 intf.add_stream(pkts)
166 self.pg_enable_capture(self.pg_interfaces)
167 self.pg_start()
168 rx = intf.get_capture(1, filter_out_fn=filter_out_fn)
169
170 self.assertEqual(len(rx), 1)
171 rx = rx[0]
172 self.validate_na(intf, rx, dst_ip, tgt_ip)
173
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200174 def send_and_expect_ns(
175 self, tx_intf, rx_intf, pkts, tgt_ip, filter_out_fn=is_ipv6_misc
176 ):
Neale Rannscbe25aa2019-09-30 10:53:31 +0000177 self.vapi.cli("clear trace")
Neale Rannsdcd6d622017-05-26 02:59:16 -0700178 tx_intf.add_stream(pkts)
179 self.pg_enable_capture(self.pg_interfaces)
180 self.pg_start()
181 rx = rx_intf.get_capture(1, filter_out_fn=filter_out_fn)
182
183 self.assertEqual(len(rx), 1)
184 rx = rx[0]
185 self.validate_ns(rx_intf, rx, tgt_ip)
186
Neale Rannsdcd6d622017-05-26 02:59:16 -0700187 def verify_ip(self, rx, smac, dmac, sip, dip):
188 ether = rx[Ether]
189 self.assertEqual(ether.dst, dmac)
190 self.assertEqual(ether.src, smac)
191
192 ip = rx[IPv6]
193 self.assertEqual(ip.src, sip)
194 self.assertEqual(ip.dst, dip)
195
Neale Rannsfd2417b2021-07-16 14:00:16 +0000196 def get_ip6_nd_rx_requests(self, itf):
197 """Get IP6 ND RX request stats for and interface"""
198 return self.statistics["/net/ip6-nd/rx/requests"][:, itf.sw_if_index].sum()
199
200 def get_ip6_nd_tx_requests(self, itf):
201 """Get IP6 ND TX request stats for and interface"""
202 return self.statistics["/net/ip6-nd/tx/requests"][:, itf.sw_if_index].sum()
203
204 def get_ip6_nd_rx_replies(self, itf):
205 """Get IP6 ND RX replies stats for and interface"""
206 return self.statistics["/net/ip6-nd/rx/replies"][:, itf.sw_if_index].sum()
207
208 def get_ip6_nd_tx_replies(self, itf):
209 """Get IP6 ND TX replies stats for and interface"""
210 return self.statistics["/net/ip6-nd/tx/replies"][:, itf.sw_if_index].sum()
211
Neale Ranns3f844d02017-02-18 00:03:54 -0800212
Andrew Yourtchenko06f32812021-01-14 10:19:08 +0000213@tag_run_solo
Neale Ranns3f844d02017-02-18 00:03:54 -0800214class TestIPv6(TestIPv6ND):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200215 """IPv6 Test Case"""
Damjan Marionf56b77a2016-10-03 19:44:57 +0200216
217 @classmethod
218 def setUpClass(cls):
219 super(TestIPv6, cls).setUpClass()
220
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -0700221 @classmethod
222 def tearDownClass(cls):
223 super(TestIPv6, cls).tearDownClass()
224
Klement Sekeraf62ae122016-10-11 11:47:09 +0200225 def setUp(self):
Matej Klotton86d87c42016-11-11 11:38:55 +0100226 """
227 Perform test setup before test case.
228
229 **Config:**
230 - create 3 pg interfaces
231 - untagged pg0 interface
232 - Dot1Q subinterface on pg1
233 - Dot1AD subinterface on pg2
234 - setup interfaces:
235 - put it into UP state
236 - set IPv6 addresses
237 - resolve neighbor address using NDP
238 - configure 200 fib entries
239
240 :ivar list interfaces: pg interfaces and subinterfaces.
241 :ivar dict flows: IPv4 packet flows in test.
Matej Klotton86d87c42016-11-11 11:38:55 +0100242
243 *TODO:* Create AD sub interface
244 """
Klement Sekeraf62ae122016-10-11 11:47:09 +0200245 super(TestIPv6, self).setUp()
Damjan Marionf56b77a2016-10-03 19:44:57 +0200246
Klement Sekeraf62ae122016-10-11 11:47:09 +0200247 # create 3 pg interfaces
248 self.create_pg_interfaces(range(3))
Damjan Marionf56b77a2016-10-03 19:44:57 +0200249
Klement Sekeraf62ae122016-10-11 11:47:09 +0200250 # create 2 subinterfaces for p1 and pg2
251 self.sub_interfaces = [
252 VppDot1QSubint(self, self.pg1, 100),
Matej Klotton86d87c42016-11-11 11:38:55 +0100253 VppDot1QSubint(self, self.pg2, 200)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200254 # TODO: VppDot1ADSubint(self, self.pg2, 200, 300, 400)
Matej Klotton86d87c42016-11-11 11:38:55 +0100255 ]
Damjan Marionf56b77a2016-10-03 19:44:57 +0200256
Klement Sekeraf62ae122016-10-11 11:47:09 +0200257 # packet flows mapping pg0 -> pg1.sub, pg2.sub, etc.
258 self.flows = dict()
259 self.flows[self.pg0] = [self.pg1.sub_if, self.pg2.sub_if]
260 self.flows[self.pg1.sub_if] = [self.pg0, self.pg2.sub_if]
261 self.flows[self.pg2.sub_if] = [self.pg0, self.pg1.sub_if]
Damjan Marionf56b77a2016-10-03 19:44:57 +0200262
Klement Sekeraf62ae122016-10-11 11:47:09 +0200263 # packet sizes
Jan Geletye6c78ee2018-06-26 12:24:03 +0200264 self.pg_if_packet_sizes = [64, 1500, 9020]
Damjan Marionf56b77a2016-10-03 19:44:57 +0200265
Klement Sekeraf62ae122016-10-11 11:47:09 +0200266 self.interfaces = list(self.pg_interfaces)
267 self.interfaces.extend(self.sub_interfaces)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200268
Klement Sekeraf62ae122016-10-11 11:47:09 +0200269 # setup all interfaces
270 for i in self.interfaces:
271 i.admin_up()
272 i.config_ip6()
273 i.resolve_ndp()
274
Damjan Marionf56b77a2016-10-03 19:44:57 +0200275 def tearDown(self):
Matej Klotton86d87c42016-11-11 11:38:55 +0100276 """Run standard test teardown and log ``show ip6 neighbors``."""
Vladislav Grishenko1fb62c02022-05-16 01:44:43 +0500277 for i in reversed(self.interfaces):
Neale Ranns75152282017-01-09 01:00:45 -0800278 i.unconfig_ip6()
Neale Ranns75152282017-01-09 01:00:45 -0800279 i.admin_down()
Neale Ranns744902e2017-08-14 10:35:44 -0700280 for i in self.sub_interfaces:
Neale Ranns75152282017-01-09 01:00:45 -0800281 i.remove_vpp_config()
282
Klement Sekeraf62ae122016-10-11 11:47:09 +0200283 super(TestIPv6, self).tearDown()
284 if not self.vpp_dead:
Matej Klotton86d87c42016-11-11 11:38:55 +0100285 self.logger.info(self.vapi.cli("show ip6 neighbors"))
Klement Sekeraf62ae122016-10-11 11:47:09 +0200286 # info(self.vapi.cli("show ip6 fib")) # many entries
Damjan Marionf56b77a2016-10-03 19:44:57 +0200287
Jan Geletye6c78ee2018-06-26 12:24:03 +0200288 def modify_packet(self, src_if, packet_size, pkt):
289 """Add load, set destination IP and extend packet to required packet
290 size for defined interface.
291
292 :param VppInterface src_if: Interface to create packet for.
293 :param int packet_size: Required packet size.
294 :param Scapy pkt: Packet to be modified.
295 """
snaramre07a0f212019-10-11 21:28:56 +0000296 dst_if_idx = int(packet_size / 10 % 2)
Jan Geletye6c78ee2018-06-26 12:24:03 +0200297 dst_if = self.flows[src_if][dst_if_idx]
298 info = self.create_packet_info(src_if, dst_if)
299 payload = self.info_to_payload(info)
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800300 p = pkt / Raw(payload)
Jan Geletye6c78ee2018-06-26 12:24:03 +0200301 p[IPv6].dst = dst_if.remote_ip6
302 info.data = p.copy()
303 if isinstance(src_if, VppSubInterface):
304 p = src_if.add_dot1_layer(p)
305 self.extend_packet(p, packet_size)
306
307 return p
308
309 def create_stream(self, src_if):
Matej Klotton86d87c42016-11-11 11:38:55 +0100310 """Create input packet stream for defined interface.
311
312 :param VppInterface src_if: Interface to create packet stream for.
Matej Klotton86d87c42016-11-11 11:38:55 +0100313 """
Jan Geletye6c78ee2018-06-26 12:24:03 +0200314 hdr_ext = 4 if isinstance(src_if, VppSubInterface) else 0
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200315 pkt_tmpl = (
316 Ether(dst=src_if.local_mac, src=src_if.remote_mac)
317 / IPv6(src=src_if.remote_ip6)
318 / inet6.UDP(sport=1234, dport=1234)
319 )
Jan Geletye6c78ee2018-06-26 12:24:03 +0200320
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200321 pkts = [
322 self.modify_packet(src_if, i, pkt_tmpl)
323 for i in moves.range(
324 self.pg_if_packet_sizes[0], self.pg_if_packet_sizes[1], 10
325 )
326 ]
327 pkts_b = [
328 self.modify_packet(src_if, i, pkt_tmpl)
329 for i in moves.range(
330 self.pg_if_packet_sizes[1] + hdr_ext,
331 self.pg_if_packet_sizes[2] + hdr_ext,
332 50,
333 )
334 ]
Jan Geletye6c78ee2018-06-26 12:24:03 +0200335 pkts.extend(pkts_b)
336
Damjan Marionf56b77a2016-10-03 19:44:57 +0200337 return pkts
338
Klement Sekeraf62ae122016-10-11 11:47:09 +0200339 def verify_capture(self, dst_if, capture):
Matej Klotton86d87c42016-11-11 11:38:55 +0100340 """Verify captured input packet stream for defined interface.
341
342 :param VppInterface dst_if: Interface to verify captured packet stream
343 for.
344 :param list capture: Captured packet stream.
345 """
346 self.logger.info("Verifying capture on interface %s" % dst_if.name)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200347 last_info = dict()
Damjan Marionf56b77a2016-10-03 19:44:57 +0200348 for i in self.interfaces:
Klement Sekeraf62ae122016-10-11 11:47:09 +0200349 last_info[i.sw_if_index] = None
350 is_sub_if = False
351 dst_sw_if_index = dst_if.sw_if_index
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200352 if hasattr(dst_if, "parent"):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200353 is_sub_if = True
Damjan Marionf56b77a2016-10-03 19:44:57 +0200354 for packet in capture:
Klement Sekeraf62ae122016-10-11 11:47:09 +0200355 if is_sub_if:
356 # Check VLAN tags and Ethernet header
357 packet = dst_if.remove_dot1_layer(packet)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200358 self.assertTrue(Dot1Q not in packet)
359 try:
360 ip = packet[IPv6]
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800361 udp = packet[inet6.UDP]
Paul Vinciguerraeaea4212019-03-06 11:58:06 -0800362 payload_info = self.payload_to_info(packet[Raw])
Damjan Marionf56b77a2016-10-03 19:44:57 +0200363 packet_index = payload_info.index
Klement Sekeraf62ae122016-10-11 11:47:09 +0200364 self.assertEqual(payload_info.dst, dst_sw_if_index)
Klement Sekerada505f62017-01-04 12:58:53 +0100365 self.logger.debug(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200366 "Got packet on port %s: src=%u (id=%u)"
367 % (dst_if.name, payload_info.src, packet_index)
368 )
Klement Sekeraf62ae122016-10-11 11:47:09 +0200369 next_info = self.get_next_packet_info_for_interface2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200370 payload_info.src, dst_sw_if_index, last_info[payload_info.src]
371 )
Klement Sekeraf62ae122016-10-11 11:47:09 +0200372 last_info[payload_info.src] = next_info
Damjan Marionf56b77a2016-10-03 19:44:57 +0200373 self.assertTrue(next_info is not None)
374 self.assertEqual(packet_index, next_info.index)
375 saved_packet = next_info.data
376 # Check standard fields
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200377 self.assertEqual(ip.src, saved_packet[IPv6].src)
378 self.assertEqual(ip.dst, saved_packet[IPv6].dst)
379 self.assertEqual(udp.sport, saved_packet[inet6.UDP].sport)
380 self.assertEqual(udp.dport, saved_packet[inet6.UDP].dport)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200381 except:
Klement Sekera7bb873a2016-11-18 07:38:42 +0100382 self.logger.error(ppp("Unexpected or invalid packet:", packet))
Damjan Marionf56b77a2016-10-03 19:44:57 +0200383 raise
384 for i in self.interfaces:
Klement Sekeraf62ae122016-10-11 11:47:09 +0200385 remaining_packet = self.get_next_packet_info_for_interface2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200386 i.sw_if_index, dst_sw_if_index, last_info[i.sw_if_index]
387 )
388 self.assertTrue(
389 remaining_packet is None,
390 "Interface %s: Packet expected from interface %s "
391 "didn't arrive" % (dst_if.name, i.name),
392 )
Damjan Marionf56b77a2016-10-03 19:44:57 +0200393
Klement Sekerae8498652019-06-17 12:23:15 +0000394 def test_next_header_anomaly(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200395 """IPv6 next header anomaly test
Klement Sekerae8498652019-06-17 12:23:15 +0000396
397 Test scenario:
398 - ipv6 next header field = Fragment Header (44)
399 - next header is ICMPv6 Echo Request
400 - wait for reassembly
401 """
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200402 pkt = (
403 Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac)
404 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6, nh=44)
405 / ICMPv6EchoRequest()
406 )
Klement Sekerae8498652019-06-17 12:23:15 +0000407
408 self.pg0.add_stream(pkt)
409 self.pg_start()
410
411 # wait for reassembly
412 self.sleep(10)
413
Damjan Marionf56b77a2016-10-03 19:44:57 +0200414 def test_fib(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200415 """IPv6 FIB test
Matej Klotton86d87c42016-11-11 11:38:55 +0100416
417 Test scenario:
418 - Create IPv6 stream for pg0 interface
419 - Create IPv6 tagged streams for pg1's and pg2's subinterface.
420 - Send and verify received packets on each interface.
421 """
Damjan Marionf56b77a2016-10-03 19:44:57 +0200422
Jan Geletye6c78ee2018-06-26 12:24:03 +0200423 pkts = self.create_stream(self.pg0)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200424 self.pg0.add_stream(pkts)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200425
Klement Sekeraf62ae122016-10-11 11:47:09 +0200426 for i in self.sub_interfaces:
Jan Geletye6c78ee2018-06-26 12:24:03 +0200427 pkts = self.create_stream(i)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200428 i.parent.add_stream(pkts)
429
430 self.pg_enable_capture(self.pg_interfaces)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200431 self.pg_start()
432
Klement Sekeraf62ae122016-10-11 11:47:09 +0200433 pkts = self.pg0.get_capture()
434 self.verify_capture(self.pg0, pkts)
435
436 for i in self.sub_interfaces:
437 pkts = i.parent.get_capture()
438 self.verify_capture(i, pkts)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200439
Neale Ranns75152282017-01-09 01:00:45 -0800440 def test_ns(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200441 """IPv6 Neighbour Solicitation Exceptions
Neale Ranns75152282017-01-09 01:00:45 -0800442
Klement Sekerada505f62017-01-04 12:58:53 +0100443 Test scenario:
Neale Ranns75152282017-01-09 01:00:45 -0800444 - Send an NS Sourced from an address not covered by the link sub-net
445 - Send an NS to an mcast address the router has not joined
446 - Send NS for a target address the router does not onn.
447 """
448
Neale Rannsfd2417b2021-07-16 14:00:16 +0000449 n_rx_req_pg0 = self.get_ip6_nd_rx_requests(self.pg0)
450 n_tx_rep_pg0 = self.get_ip6_nd_tx_replies(self.pg0)
451
Neale Ranns75152282017-01-09 01:00:45 -0800452 #
453 # An NS from a non link source address
454 #
Neale Ranns3f844d02017-02-18 00:03:54 -0800455 nsma = in6_getnsma(inet_pton(AF_INET6, self.pg0.local_ip6))
456 d = inet_ntop(AF_INET6, nsma)
Neale Ranns75152282017-01-09 01:00:45 -0800457
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200458 p = (
459 Ether(dst=in6_getnsmac(nsma))
460 / IPv6(dst=d, src="2002::2")
461 / ICMPv6ND_NS(tgt=self.pg0.local_ip6)
462 / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)
463 )
Neale Ranns75152282017-01-09 01:00:45 -0800464 pkts = [p]
465
Klement Sekerada505f62017-01-04 12:58:53 +0100466 self.send_and_assert_no_replies(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200467 self.pg0, pkts, "No response to NS source by address not on sub-net"
468 )
Neale Rannsfd2417b2021-07-16 14:00:16 +0000469 self.assert_equal(self.get_ip6_nd_rx_requests(self.pg0), n_rx_req_pg0 + 1)
Neale Ranns75152282017-01-09 01:00:45 -0800470
471 #
Klement Sekerada505f62017-01-04 12:58:53 +0100472 # An NS for sent to a solicited mcast group the router is
473 # not a member of FAILS
Neale Ranns75152282017-01-09 01:00:45 -0800474 #
475 if 0:
Neale Ranns3f844d02017-02-18 00:03:54 -0800476 nsma = in6_getnsma(inet_pton(AF_INET6, "fd::ffff"))
477 d = inet_ntop(AF_INET6, nsma)
Neale Ranns75152282017-01-09 01:00:45 -0800478
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200479 p = (
480 Ether(dst=in6_getnsmac(nsma))
481 / IPv6(dst=d, src=self.pg0.remote_ip6)
482 / ICMPv6ND_NS(tgt=self.pg0.local_ip6)
483 / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)
484 )
Neale Ranns75152282017-01-09 01:00:45 -0800485 pkts = [p]
486
Klement Sekerada505f62017-01-04 12:58:53 +0100487 self.send_and_assert_no_replies(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200488 self.pg0, pkts, "No response to NS sent to unjoined mcast address"
489 )
Neale Ranns75152282017-01-09 01:00:45 -0800490
491 #
492 # An NS whose target address is one the router does not own
493 #
Neale Ranns3f844d02017-02-18 00:03:54 -0800494 nsma = in6_getnsma(inet_pton(AF_INET6, self.pg0.local_ip6))
495 d = inet_ntop(AF_INET6, nsma)
Neale Ranns75152282017-01-09 01:00:45 -0800496
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200497 p = (
498 Ether(dst=in6_getnsmac(nsma))
499 / IPv6(dst=d, src=self.pg0.remote_ip6)
500 / ICMPv6ND_NS(tgt="fd::ffff")
501 / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)
502 )
Neale Ranns75152282017-01-09 01:00:45 -0800503 pkts = [p]
504
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200505 self.send_and_assert_no_replies(
506 self.pg0, pkts, "No response to NS for unknown target"
507 )
Neale Rannsfd2417b2021-07-16 14:00:16 +0000508 self.assert_equal(self.get_ip6_nd_rx_requests(self.pg0), n_rx_req_pg0 + 2)
Neale Ranns75152282017-01-09 01:00:45 -0800509
Neale Rannsb3b2de72017-03-08 05:17:22 -0800510 #
511 # A neighbor entry that has no associated FIB-entry
512 #
513 self.pg0.generate_remote_hosts(4)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200514 nd_entry = VppNeighbor(
515 self,
516 self.pg0.sw_if_index,
517 self.pg0.remote_hosts[2].mac,
518 self.pg0.remote_hosts[2].ip6,
519 is_no_fib_entry=1,
520 )
Neale Rannsb3b2de72017-03-08 05:17:22 -0800521 nd_entry.add_vpp_config()
522
523 #
524 # check we have the neighbor, but no route
525 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200526 self.assertTrue(
527 find_nbr(self, self.pg0.sw_if_index, self.pg0._remote_hosts[2].ip6)
528 )
529 self.assertFalse(find_route(self, self.pg0._remote_hosts[2].ip6, 128))
Neale Rannsb3b2de72017-03-08 05:17:22 -0800530
Neale Ranns2a3ea492017-04-19 05:24:40 -0700531 #
532 # send an NS from a link local address to the interface's global
533 # address
534 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200535 p = (
536 Ether(dst=in6_getnsmac(nsma), src=self.pg0.remote_mac)
537 / IPv6(dst=d, src=self.pg0._remote_hosts[2].ip6_ll)
538 / ICMPv6ND_NS(tgt=self.pg0.local_ip6)
539 / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)
540 )
Neale Ranns2a3ea492017-04-19 05:24:40 -0700541
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200542 self.send_and_expect_na(
543 self.pg0,
544 p,
545 "NS from link-local",
546 dst_ip=self.pg0._remote_hosts[2].ip6_ll,
547 tgt_ip=self.pg0.local_ip6,
548 )
Neale Rannsfd2417b2021-07-16 14:00:16 +0000549 self.assert_equal(self.get_ip6_nd_rx_requests(self.pg0), n_rx_req_pg0 + 3)
550 self.assert_equal(self.get_ip6_nd_tx_replies(self.pg0), n_tx_rep_pg0 + 1)
Neale Ranns2a3ea492017-04-19 05:24:40 -0700551
552 #
553 # we should have learned an ND entry for the peer's link-local
554 # but not inserted a route to it in the FIB
555 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200556 self.assertTrue(
557 find_nbr(self, self.pg0.sw_if_index, self.pg0._remote_hosts[2].ip6_ll)
558 )
559 self.assertFalse(find_route(self, self.pg0._remote_hosts[2].ip6_ll, 128))
Neale Ranns2a3ea492017-04-19 05:24:40 -0700560
561 #
562 # An NS to the router's own Link-local
563 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200564 p = (
565 Ether(dst=in6_getnsmac(nsma), src=self.pg0.remote_mac)
566 / IPv6(dst=d, src=self.pg0._remote_hosts[3].ip6_ll)
567 / ICMPv6ND_NS(tgt=self.pg0.local_ip6_ll)
568 / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)
569 )
Neale Ranns2a3ea492017-04-19 05:24:40 -0700570
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200571 self.send_and_expect_na(
572 self.pg0,
573 p,
574 "NS to/from link-local",
575 dst_ip=self.pg0._remote_hosts[3].ip6_ll,
576 tgt_ip=self.pg0.local_ip6_ll,
577 )
Neale Ranns2a3ea492017-04-19 05:24:40 -0700578
579 #
Neale Rannse2b67362021-04-02 07:34:39 +0000580 # do not respond to a NS for the peer's address
581 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200582 p = (
583 Ether(dst=in6_getnsmac(nsma), src=self.pg0.remote_mac)
584 / IPv6(dst=d, src=self.pg0._remote_hosts[3].ip6_ll)
585 / ICMPv6ND_NS(tgt=self.pg0._remote_hosts[3].ip6_ll)
586 / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)
587 )
Neale Rannse2b67362021-04-02 07:34:39 +0000588
589 self.send_and_assert_no_replies(self.pg0, p)
590
591 #
Neale Ranns2a3ea492017-04-19 05:24:40 -0700592 # we should have learned an ND entry for the peer's link-local
593 # but not inserted a route to it in the FIB
594 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200595 self.assertTrue(
596 find_nbr(self, self.pg0.sw_if_index, self.pg0._remote_hosts[3].ip6_ll)
597 )
598 self.assertFalse(find_route(self, self.pg0._remote_hosts[3].ip6_ll, 128))
Neale Ranns2a3ea492017-04-19 05:24:40 -0700599
Neale Rannsfd2417b2021-07-16 14:00:16 +0000600 def test_nd_incomplete(self):
601 """IP6-ND Incomplete"""
602 self.pg1.generate_remote_hosts(3)
603
604 p0 = (
605 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
606 / IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_hosts[1].ip6)
607 / UDP(sport=1234, dport=1234)
608 / Raw()
609 )
610
611 #
612 # a packet to an unresolved destination generates an ND request
613 #
614 n_tx_req_pg1 = self.get_ip6_nd_tx_requests(self.pg1)
615 self.send_and_expect_ns(self.pg0, self.pg1, p0, self.pg1.remote_hosts[1].ip6)
616 self.assert_equal(self.get_ip6_nd_tx_requests(self.pg1), n_tx_req_pg1 + 1)
617
618 #
619 # a reply to the request
620 #
621 self.assert_equal(self.get_ip6_nd_rx_replies(self.pg1), 0)
622 na = (
623 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
624 / IPv6(dst=self.pg1.local_ip6, src=self.pg1.remote_hosts[1].ip6)
625 / ICMPv6ND_NA(tgt=self.pg1.remote_hosts[1].ip6)
626 / ICMPv6NDOptSrcLLAddr(lladdr=self.pg1.remote_hosts[1].mac)
627 )
628 self.send_and_assert_no_replies(self.pg1, [na])
629 self.assert_equal(self.get_ip6_nd_rx_replies(self.pg1), 1)
630
Neale Rannsdcd6d622017-05-26 02:59:16 -0700631 def test_ns_duplicates(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200632 """ND Duplicates"""
Neale Rannsdcd6d622017-05-26 02:59:16 -0700633
634 #
635 # Generate some hosts on the LAN
636 #
637 self.pg1.generate_remote_hosts(3)
638
639 #
640 # Add host 1 on pg1 and pg2
641 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200642 ns_pg1 = VppNeighbor(
643 self,
644 self.pg1.sw_if_index,
645 self.pg1.remote_hosts[1].mac,
646 self.pg1.remote_hosts[1].ip6,
647 )
Neale Rannsdcd6d622017-05-26 02:59:16 -0700648 ns_pg1.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200649 ns_pg2 = VppNeighbor(
650 self,
651 self.pg2.sw_if_index,
652 self.pg2.remote_mac,
653 self.pg1.remote_hosts[1].ip6,
654 )
Neale Rannsdcd6d622017-05-26 02:59:16 -0700655 ns_pg2.add_vpp_config()
656
657 #
658 # IP packet destined for pg1 remote host arrives on pg1 again.
659 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200660 p = (
661 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
662 / IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_hosts[1].ip6)
663 / inet6.UDP(sport=1234, dport=1234)
664 / Raw()
665 )
Neale Rannsdcd6d622017-05-26 02:59:16 -0700666
667 self.pg0.add_stream(p)
668 self.pg_enable_capture(self.pg_interfaces)
669 self.pg_start()
670
671 rx1 = self.pg1.get_capture(1)
672
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200673 self.verify_ip(
674 rx1[0],
675 self.pg1.local_mac,
676 self.pg1.remote_hosts[1].mac,
677 self.pg0.remote_ip6,
678 self.pg1.remote_hosts[1].ip6,
679 )
Neale Rannsdcd6d622017-05-26 02:59:16 -0700680
681 #
682 # remove the duplicate on pg1
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700683 # packet stream should generate NSs out of pg1
Neale Rannsdcd6d622017-05-26 02:59:16 -0700684 #
685 ns_pg1.remove_vpp_config()
686
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200687 self.send_and_expect_ns(self.pg0, self.pg1, p, self.pg1.remote_hosts[1].ip6)
Neale Rannsdcd6d622017-05-26 02:59:16 -0700688
689 #
690 # Add it back
691 #
692 ns_pg1.add_vpp_config()
693
694 self.pg0.add_stream(p)
695 self.pg_enable_capture(self.pg_interfaces)
696 self.pg_start()
697
698 rx1 = self.pg1.get_capture(1)
699
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200700 self.verify_ip(
701 rx1[0],
702 self.pg1.local_mac,
703 self.pg1.remote_hosts[1].mac,
704 self.pg0.remote_ip6,
705 self.pg1.remote_hosts[1].ip6,
706 )
Neale Rannsdcd6d622017-05-26 02:59:16 -0700707
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200708 def validate_ra(self, intf, rx, dst_ip=None, src_ip=None, mtu=9000, pi_opt=None):
Neale Ranns32e1c012016-11-22 17:07:28 +0000709 if not dst_ip:
710 dst_ip = intf.remote_ip6
Neale Rannscbe25aa2019-09-30 10:53:31 +0000711 if not src_ip:
712 src_ip = mk_ll_addr(intf.local_mac)
Neale Ranns75152282017-01-09 01:00:45 -0800713
Neale Ranns5737d882017-02-03 06:14:49 -0800714 # unicasted packets must come to the unicast mac
Neale Ranns32e1c012016-11-22 17:07:28 +0000715 self.assertEqual(rx[Ether].dst, intf.remote_mac)
716
717 # and from the router's MAC
718 self.assertEqual(rx[Ether].src, intf.local_mac)
Neale Ranns75152282017-01-09 01:00:45 -0800719
720 # the rx'd RA should be addressed to the sender's source
721 self.assertTrue(rx.haslayer(ICMPv6ND_RA))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200722 self.assertEqual(in6_ptop(rx[IPv6].dst), in6_ptop(dst_ip))
Neale Ranns75152282017-01-09 01:00:45 -0800723
724 # and come from the router's link local
725 self.assertTrue(in6_islladdr(rx[IPv6].src))
Neale Rannscbe25aa2019-09-30 10:53:31 +0000726 self.assertEqual(in6_ptop(rx[IPv6].src), in6_ptop(src_ip))
Neale Ranns75152282017-01-09 01:00:45 -0800727
Neale Ranns87df12d2017-02-18 08:16:41 -0800728 # it should contain the links MTU
729 ra = rx[ICMPv6ND_RA]
730 self.assertEqual(ra[ICMPv6NDOptMTU].mtu, mtu)
731
732 # it should contain the source's link layer address option
733 sll = ra[ICMPv6NDOptSrcLLAddr]
734 self.assertEqual(sll.lladdr, intf.local_mac)
735
736 if not pi_opt:
737 # the RA should not contain prefix information
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200738 self.assertFalse(ra.haslayer(ICMPv6NDOptPrefixInfo))
Neale Ranns87df12d2017-02-18 08:16:41 -0800739 else:
740 raos = rx.getlayer(ICMPv6NDOptPrefixInfo, 1)
741
742 # the options are nested in the scapy packet in way that i cannot
743 # decipher how to decode. this 1st layer of option always returns
744 # nested classes, so a direct obj1=obj2 comparison always fails.
Paul Vinciguerraab055082019-06-06 14:07:55 -0400745 # however, the getlayer(.., 2) does give one instance.
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700746 # so we cheat here and construct a new opt instance for comparison
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800747 rd = ICMPv6NDOptPrefixInfo(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200748 prefixlen=raos.prefixlen, prefix=raos.prefix, L=raos.L, A=raos.A
749 )
Neale Ranns87df12d2017-02-18 08:16:41 -0800750 if type(pi_opt) is list:
751 for ii in range(len(pi_opt)):
752 self.assertEqual(pi_opt[ii], rd)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200753 rd = rx.getlayer(ICMPv6NDOptPrefixInfo, ii + 2)
Neale Ranns87df12d2017-02-18 08:16:41 -0800754 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200755 self.assertEqual(
756 pi_opt,
757 raos,
758 "Expected: %s, received: %s"
759 % (pi_opt.show(dump=True), raos.show(dump=True)),
760 )
Neale Ranns87df12d2017-02-18 08:16:41 -0800761
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200762 def send_and_expect_ra(
763 self,
764 intf,
765 pkts,
766 remark,
767 dst_ip=None,
768 filter_out_fn=is_ipv6_misc,
769 opt=None,
770 src_ip=None,
771 ):
Neale Rannscbe25aa2019-09-30 10:53:31 +0000772 self.vapi.cli("clear trace")
Neale Ranns32e1c012016-11-22 17:07:28 +0000773 intf.add_stream(pkts)
Neale Ranns32e1c012016-11-22 17:07:28 +0000774 self.pg_enable_capture(self.pg_interfaces)
775 self.pg_start()
776 rx = intf.get_capture(1, filter_out_fn=filter_out_fn)
777
778 self.assertEqual(len(rx), 1)
779 rx = rx[0]
Neale Rannscbe25aa2019-09-30 10:53:31 +0000780 self.validate_ra(intf, rx, dst_ip, src_ip=src_ip, pi_opt=opt)
Neale Ranns32e1c012016-11-22 17:07:28 +0000781
Alexander Chernavin3b28fd72023-02-02 14:22:56 +0000782 def test_ip6_ra_dump(self):
783 """IPv6 RA dump"""
784
785 # Dump IPv6 RA for all interfaces
786 ip6_ra_dump = self.vapi.sw_interface_ip6nd_ra_dump(sw_if_index=0xFFFFFFFF)
787 self.assertEqual(len(ip6_ra_dump), len(self.interfaces))
788
789 for ip6_ra in ip6_ra_dump:
790 self.assertFalse(ip6_ra.send_radv)
791 self.assertEqual(ip6_ra.n_prefixes, 0)
792 self.assertEqual(len(ip6_ra.prefixes), 0)
793 self.assertEqual(ip6_ra.last_radv_time, 0.0)
794 self.assertEqual(ip6_ra.last_multicast_time, 0.0)
795 self.assertEqual(ip6_ra.next_multicast_time, 0.0)
796 self.assertEqual(ip6_ra.n_advertisements_sent, 0)
797 self.assertEqual(ip6_ra.n_solicitations_rcvd, 0)
798 self.assertEqual(ip6_ra.n_solicitations_dropped, 0)
799
800 # Enable sending IPv6 RA for an interface
801 self.pg0.ip6_ra_config(no=1, suppress=1)
802
803 # Add IPv6 RA prefixes for the interface
804 pfx0 = IPv6Network(
805 "%s/%s" % (self.pg0.local_ip6, self.pg0.local_ip6_prefix_len), strict=False
806 )
807 pfx1 = IPv6Network("fafa::/96")
808 self.pg0.ip6_ra_prefix(pfx0, off_link=0, no_autoconfig=0)
809 self.pg0.ip6_ra_prefix(pfx1, off_link=1, no_autoconfig=1)
810
811 # Wait for multicast IPv6 RA
812 self.sleep(1)
813
814 # Dump IPv6 RA for the interface
815 ip6_ra_dump = self.vapi.sw_interface_ip6nd_ra_dump(
816 sw_if_index=self.pg0.sw_if_index
817 )
818 self.assertEqual(len(ip6_ra_dump), 1)
819 ip6_ra = ip6_ra_dump[0]
820
821 self.assertEqual(ip6_ra.sw_if_index, self.pg0.sw_if_index)
822 self.assertTrue(ip6_ra.send_radv)
823 self.assertEqual(ip6_ra.n_prefixes, 2)
824 self.assertEqual(len(ip6_ra.prefixes), 2)
825 self.assertEqual(ip6_ra.last_radv_time, 0.0)
826 self.assertGreater(ip6_ra.last_multicast_time, 0.0)
827 self.assertGreater(ip6_ra.next_multicast_time, 0.0)
828 self.assertGreater(ip6_ra.n_advertisements_sent, 0)
829 self.assertEqual(ip6_ra.n_solicitations_rcvd, 0)
830 self.assertEqual(ip6_ra.n_solicitations_dropped, 0)
831
832 self.assertEqual(ip6_ra.prefixes[0].prefix, pfx0)
833 self.assertTrue(ip6_ra.prefixes[0].onlink_flag)
834 self.assertTrue(ip6_ra.prefixes[0].autonomous_flag)
835 self.assertFalse(ip6_ra.prefixes[0].no_advertise)
836
837 self.assertEqual(ip6_ra.prefixes[1].prefix, pfx1)
838 self.assertFalse(ip6_ra.prefixes[1].onlink_flag)
839 self.assertFalse(ip6_ra.prefixes[1].autonomous_flag)
840 self.assertFalse(ip6_ra.prefixes[1].no_advertise)
841
842 # Reset sending IPv6 RA for the interface
843 self.pg0.ip6_ra_config(suppress=1)
844
845 # Remove IPv6 RA prefixes for the interface
846 self.pg0.ip6_ra_prefix(pfx0, is_no=1)
847 self.pg0.ip6_ra_prefix(pfx1, is_no=1)
848
849 # Dump IPv6 RA for the interface
850 ip6_ra_dump = self.vapi.sw_interface_ip6nd_ra_dump(
851 sw_if_index=self.pg0.sw_if_index
852 )
853 self.assertEqual(len(ip6_ra_dump), 1)
854 ip6_ra = ip6_ra_dump[0]
855
856 self.assertEqual(ip6_ra.sw_if_index, self.pg0.sw_if_index)
857 self.assertFalse(ip6_ra.send_radv)
858 self.assertEqual(ip6_ra.n_prefixes, 0)
859 self.assertEqual(len(ip6_ra.prefixes), 0)
860
Neale Ranns75152282017-01-09 01:00:45 -0800861 def test_rs(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200862 """IPv6 Router Solicitation Exceptions
Neale Ranns75152282017-01-09 01:00:45 -0800863
Klement Sekerada505f62017-01-04 12:58:53 +0100864 Test scenario:
Neale Ranns75152282017-01-09 01:00:45 -0800865 """
866
Alexander Chernavine99f7622022-03-05 15:51:54 +0000867 self.pg0.ip6_ra_config(no=1, suppress=1)
868
Neale Ranns75152282017-01-09 01:00:45 -0800869 #
Klement Sekerada505f62017-01-04 12:58:53 +0100870 # Before we begin change the IPv6 RA responses to use the unicast
871 # address - that way we will not confuse them with the periodic
872 # RAs which go to the mcast address
Neale Ranns32e1c012016-11-22 17:07:28 +0000873 # Sit and wait for the first periodic RA.
874 #
875 # TODO
Neale Ranns75152282017-01-09 01:00:45 -0800876 #
877 self.pg0.ip6_ra_config(send_unicast=1)
878
879 #
880 # An RS from a link source address
881 # - expect an RA in return
882 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200883 p = (
884 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
885 / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6)
886 / ICMPv6ND_RS()
887 )
Neale Ranns75152282017-01-09 01:00:45 -0800888 pkts = [p]
889 self.send_and_expect_ra(self.pg0, pkts, "Genuine RS")
890
891 #
892 # For the next RS sent the RA should be rate limited
893 #
894 self.send_and_assert_no_replies(self.pg0, pkts, "RA rate limited")
895
896 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -0700897 # When we reconfigure the IPv6 RA config,
898 # we reset the RA rate limiting,
Klement Sekerada505f62017-01-04 12:58:53 +0100899 # so we need to do this before each test below so as not to drop
900 # packets for rate limiting reasons. Test this works here.
Neale Ranns75152282017-01-09 01:00:45 -0800901 #
902 self.pg0.ip6_ra_config(send_unicast=1)
903 self.send_and_expect_ra(self.pg0, pkts, "Rate limit reset RS")
904
905 #
906 # An RS sent from a non-link local source
907 #
908 self.pg0.ip6_ra_config(send_unicast=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200909 p = (
910 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
911 / IPv6(dst=self.pg0.local_ip6, src="2002::ffff")
912 / ICMPv6ND_RS()
913 )
Neale Ranns75152282017-01-09 01:00:45 -0800914 pkts = [p]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200915 self.send_and_assert_no_replies(self.pg0, pkts, "RS from non-link source")
Neale Ranns75152282017-01-09 01:00:45 -0800916
917 #
918 # Source an RS from a link local address
919 #
920 self.pg0.ip6_ra_config(send_unicast=1)
921 ll = mk_ll_addr(self.pg0.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200922 p = (
923 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
924 / IPv6(dst=self.pg0.local_ip6, src=ll)
925 / ICMPv6ND_RS()
926 )
Neale Ranns75152282017-01-09 01:00:45 -0800927 pkts = [p]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200928 self.send_and_expect_ra(self.pg0, pkts, "RS sourced from link-local", dst_ip=ll)
Neale Ranns32e1c012016-11-22 17:07:28 +0000929
930 #
Ole Troan5d280d52021-08-06 09:58:09 +0200931 # Source an RS from a link local address
932 # Ensure suppress also applies to solicited RS
933 #
934 self.pg0.ip6_ra_config(send_unicast=1, suppress=1)
935 ll = mk_ll_addr(self.pg0.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200936 p = (
937 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
938 / IPv6(dst=self.pg0.local_ip6, src=ll)
939 / ICMPv6ND_RS()
940 )
Ole Troan5d280d52021-08-06 09:58:09 +0200941 pkts = [p]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200942 self.send_and_assert_no_replies(self.pg0, pkts, "Suppressed RS from link-local")
Ole Troan5d280d52021-08-06 09:58:09 +0200943
944 #
Neale Ranns32e1c012016-11-22 17:07:28 +0000945 # Send the RS multicast
946 #
Ole Troan5d280d52021-08-06 09:58:09 +0200947 self.pg0.ip6_ra_config(no=1, suppress=1) # Reset suppress flag to zero
Neale Ranns32e1c012016-11-22 17:07:28 +0000948 self.pg0.ip6_ra_config(send_unicast=1)
Neale Ranns3f844d02017-02-18 00:03:54 -0800949 dmac = in6_getnsmac(inet_pton(AF_INET6, "ff02::2"))
Neale Ranns32e1c012016-11-22 17:07:28 +0000950 ll = mk_ll_addr(self.pg0.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200951 p = (
952 Ether(dst=dmac, src=self.pg0.remote_mac)
953 / IPv6(dst="ff02::2", src=ll)
954 / ICMPv6ND_RS()
955 )
Neale Ranns32e1c012016-11-22 17:07:28 +0000956 pkts = [p]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200957 self.send_and_expect_ra(self.pg0, pkts, "RS sourced from link-local", dst_ip=ll)
Neale Ranns75152282017-01-09 01:00:45 -0800958
959 #
Klement Sekerada505f62017-01-04 12:58:53 +0100960 # Source from the unspecified address ::. This happens when the RS
961 # is sent before the host has a configured address/sub-net,
962 # i.e. auto-config. Since the sender has no IP address, the reply
963 # comes back mcast - so the capture needs to not filter this.
964 # If we happen to pick up the periodic RA at this point then so be it,
965 # it's not an error.
Neale Ranns75152282017-01-09 01:00:45 -0800966 #
Alexander Chernavine99f7622022-03-05 15:51:54 +0000967 self.pg0.ip6_ra_config(send_unicast=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200968 p = (
969 Ether(dst=dmac, src=self.pg0.remote_mac)
970 / IPv6(dst="ff02::2", src="::")
971 / ICMPv6ND_RS()
972 )
Neale Ranns75152282017-01-09 01:00:45 -0800973 pkts = [p]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200974 self.send_and_expect_ra(
975 self.pg0,
976 pkts,
977 "RS sourced from unspecified",
978 dst_ip="ff02::1",
979 filter_out_fn=None,
980 )
Neale Ranns75152282017-01-09 01:00:45 -0800981
982 #
Neale Ranns87df12d2017-02-18 08:16:41 -0800983 # Configure The RA to announce the links prefix
984 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200985 self.pg0.ip6_ra_prefix(
986 "%s/%s" % (self.pg0.local_ip6, self.pg0.local_ip6_prefix_len)
987 )
Neale Ranns87df12d2017-02-18 08:16:41 -0800988
989 #
990 # RAs should now contain the prefix information option
991 #
Paul Vinciguerra978aa642018-11-24 22:19:12 -0800992 opt = ICMPv6NDOptPrefixInfo(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200993 prefixlen=self.pg0.local_ip6_prefix_len, prefix=self.pg0.local_ip6, L=1, A=1
994 )
Neale Ranns87df12d2017-02-18 08:16:41 -0800995
996 self.pg0.ip6_ra_config(send_unicast=1)
997 ll = mk_ll_addr(self.pg0.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200998 p = (
999 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1000 / IPv6(dst=self.pg0.local_ip6, src=ll)
1001 / ICMPv6ND_RS()
1002 )
1003 self.send_and_expect_ra(self.pg0, p, "RA with prefix-info", dst_ip=ll, opt=opt)
Neale Ranns87df12d2017-02-18 08:16:41 -08001004
1005 #
1006 # Change the prefix info to not off-link
1007 # L-flag is clear
1008 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001009 self.pg0.ip6_ra_prefix(
1010 "%s/%s" % (self.pg0.local_ip6, self.pg0.local_ip6_prefix_len), off_link=1
1011 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001012
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001013 opt = ICMPv6NDOptPrefixInfo(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001014 prefixlen=self.pg0.local_ip6_prefix_len, prefix=self.pg0.local_ip6, L=0, A=1
1015 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001016
1017 self.pg0.ip6_ra_config(send_unicast=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001018 self.send_and_expect_ra(
1019 self.pg0, p, "RA with Prefix info with L-flag=0", dst_ip=ll, opt=opt
1020 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001021
1022 #
1023 # Change the prefix info to not off-link, no-autoconfig
1024 # L and A flag are clear in the advert
1025 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001026 self.pg0.ip6_ra_prefix(
1027 "%s/%s" % (self.pg0.local_ip6, self.pg0.local_ip6_prefix_len),
1028 off_link=1,
1029 no_autoconfig=1,
1030 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001031
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001032 opt = ICMPv6NDOptPrefixInfo(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001033 prefixlen=self.pg0.local_ip6_prefix_len, prefix=self.pg0.local_ip6, L=0, A=0
1034 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001035
1036 self.pg0.ip6_ra_config(send_unicast=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001037 self.send_and_expect_ra(
1038 self.pg0, p, "RA with Prefix info with A & L-flag=0", dst_ip=ll, opt=opt
1039 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001040
1041 #
1042 # Change the flag settings back to the defaults
1043 # L and A flag are set in the advert
1044 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001045 self.pg0.ip6_ra_prefix(
1046 "%s/%s" % (self.pg0.local_ip6, self.pg0.local_ip6_prefix_len)
1047 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001048
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001049 opt = ICMPv6NDOptPrefixInfo(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001050 prefixlen=self.pg0.local_ip6_prefix_len, prefix=self.pg0.local_ip6, L=1, A=1
1051 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001052
1053 self.pg0.ip6_ra_config(send_unicast=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001054 self.send_and_expect_ra(self.pg0, p, "RA with Prefix info", dst_ip=ll, opt=opt)
Neale Ranns87df12d2017-02-18 08:16:41 -08001055
1056 #
1057 # Change the prefix info to not off-link, no-autoconfig
1058 # L and A flag are clear in the advert
1059 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001060 self.pg0.ip6_ra_prefix(
1061 "%s/%s" % (self.pg0.local_ip6, self.pg0.local_ip6_prefix_len),
1062 off_link=1,
1063 no_autoconfig=1,
1064 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001065
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001066 opt = ICMPv6NDOptPrefixInfo(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001067 prefixlen=self.pg0.local_ip6_prefix_len, prefix=self.pg0.local_ip6, L=0, A=0
1068 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001069
1070 self.pg0.ip6_ra_config(send_unicast=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001071 self.send_and_expect_ra(
1072 self.pg0, p, "RA with Prefix info with A & L-flag=0", dst_ip=ll, opt=opt
1073 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001074
1075 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07001076 # Use the reset to defaults option to revert to defaults
Neale Ranns87df12d2017-02-18 08:16:41 -08001077 # L and A flag are clear in the advert
1078 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001079 self.pg0.ip6_ra_prefix(
1080 "%s/%s" % (self.pg0.local_ip6, self.pg0.local_ip6_prefix_len), use_default=1
1081 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001082
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001083 opt = ICMPv6NDOptPrefixInfo(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001084 prefixlen=self.pg0.local_ip6_prefix_len, prefix=self.pg0.local_ip6, L=1, A=1
1085 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001086
1087 self.pg0.ip6_ra_config(send_unicast=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001088 self.send_and_expect_ra(
1089 self.pg0, p, "RA with Prefix reverted to defaults", dst_ip=ll, opt=opt
1090 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001091
1092 #
1093 # Advertise Another prefix. With no L-flag/A-flag
1094 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001095 self.pg0.ip6_ra_prefix(
1096 "%s/%s" % (self.pg1.local_ip6, self.pg1.local_ip6_prefix_len),
1097 off_link=1,
1098 no_autoconfig=1,
1099 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001100
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001101 opt = [
1102 ICMPv6NDOptPrefixInfo(
1103 prefixlen=self.pg0.local_ip6_prefix_len,
1104 prefix=self.pg0.local_ip6,
1105 L=1,
1106 A=1,
1107 ),
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001108 ICMPv6NDOptPrefixInfo(
1109 prefixlen=self.pg1.local_ip6_prefix_len,
1110 prefix=self.pg1.local_ip6,
1111 L=0,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001112 A=0,
1113 ),
1114 ]
Neale Ranns87df12d2017-02-18 08:16:41 -08001115
1116 self.pg0.ip6_ra_config(send_unicast=1)
1117 ll = mk_ll_addr(self.pg0.remote_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001118 p = (
1119 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1120 / IPv6(dst=self.pg0.local_ip6, src=ll)
1121 / ICMPv6ND_RS()
1122 )
1123 self.send_and_expect_ra(
1124 self.pg0, p, "RA with multiple Prefix infos", dst_ip=ll, opt=opt
1125 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001126
1127 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07001128 # Remove the first prefix-info - expect the second is still in the
Neale Ranns87df12d2017-02-18 08:16:41 -08001129 # advert
1130 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001131 self.pg0.ip6_ra_prefix(
1132 "%s/%s" % (self.pg0.local_ip6, self.pg0.local_ip6_prefix_len), is_no=1
1133 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001134
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001135 opt = ICMPv6NDOptPrefixInfo(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001136 prefixlen=self.pg1.local_ip6_prefix_len, prefix=self.pg1.local_ip6, L=0, A=0
1137 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001138
1139 self.pg0.ip6_ra_config(send_unicast=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001140 self.send_and_expect_ra(
1141 self.pg0, p, "RA with Prefix reverted to defaults", dst_ip=ll, opt=opt
1142 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001143
1144 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07001145 # Remove the second prefix-info - expect no prefix-info in the adverts
Neale Ranns87df12d2017-02-18 08:16:41 -08001146 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001147 self.pg0.ip6_ra_prefix(
1148 "%s/%s" % (self.pg1.local_ip6, self.pg1.local_ip6_prefix_len), is_no=1
1149 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001150
Neale Rannscbe25aa2019-09-30 10:53:31 +00001151 #
1152 # change the link's link local, so we know that works too.
1153 #
1154 self.vapi.sw_interface_ip6_set_link_local_address(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001155 sw_if_index=self.pg0.sw_if_index, ip="fe80::88"
1156 )
Neale Rannscbe25aa2019-09-30 10:53:31 +00001157
Neale Ranns87df12d2017-02-18 08:16:41 -08001158 self.pg0.ip6_ra_config(send_unicast=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001159 self.send_and_expect_ra(
1160 self.pg0,
1161 p,
1162 "RA with Prefix reverted to defaults",
1163 dst_ip=ll,
1164 src_ip="fe80::88",
1165 )
Neale Ranns87df12d2017-02-18 08:16:41 -08001166
1167 #
Neale Ranns5737d882017-02-03 06:14:49 -08001168 # Reset the periodic advertisements back to default values
Neale Ranns75152282017-01-09 01:00:45 -08001169 #
Alexander Chernavine99f7622022-03-05 15:51:54 +00001170 self.pg0.ip6_ra_config(suppress=1)
1171 self.pg0.ip6_ra_config(no=1, send_unicast=1)
Damjan Marionf56b77a2016-10-03 19:44:57 +02001172
Neale Rannsf267d112020-02-07 09:45:07 +00001173 def test_mld(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001174 """MLD Report"""
Neale Rannsf267d112020-02-07 09:45:07 +00001175 #
1176 # test one MLD is sent after applying an IPv6 Address on an interface
1177 #
1178 self.pg_enable_capture(self.pg_interfaces)
1179 self.pg_start()
1180
1181 subitf = VppDot1QSubint(self, self.pg1, 99)
Vladislav Grishenko1fb62c02022-05-16 01:44:43 +05001182 self.interfaces.append(subitf)
1183 self.sub_interfaces.append(subitf)
Neale Rannsf267d112020-02-07 09:45:07 +00001184
1185 subitf.admin_up()
1186 subitf.config_ip6()
1187
Neale Ranns03c254e2020-03-17 14:25:10 +00001188 rxs = self.pg1._get_capture(timeout=4, filter_out_fn=None)
Neale Rannsf267d112020-02-07 09:45:07 +00001189
1190 #
1191 # hunt for the MLD on vlan 99
1192 #
1193 for rx in rxs:
1194 # make sure ipv6 packets with hop by hop options have
1195 # correct checksums
1196 self.assert_packet_checksums_valid(rx)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001197 if (
1198 rx.haslayer(IPv6ExtHdrHopByHop)
1199 and rx.haslayer(Dot1Q)
1200 and rx[Dot1Q].vlan == 99
1201 ):
Neale Rannsf267d112020-02-07 09:45:07 +00001202 mld = rx[ICMPv6MLReport2]
1203
1204 self.assertEqual(mld.records_number, 4)
1205
Neale Ranns3f844d02017-02-18 00:03:54 -08001206
Christian Hoppsf5d38e02020-05-04 10:28:03 -04001207class TestIPv6RouteLookup(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001208 """IPv6 Route Lookup Test Case"""
1209
Christian Hoppsf5d38e02020-05-04 10:28:03 -04001210 routes = []
1211
1212 def route_lookup(self, prefix, exact):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001213 return self.vapi.api(
1214 self.vapi.papi.ip_route_lookup,
1215 {
1216 "table_id": 0,
1217 "exact": exact,
1218 "prefix": prefix,
1219 },
1220 )
Christian Hoppsf5d38e02020-05-04 10:28:03 -04001221
1222 @classmethod
1223 def setUpClass(cls):
1224 super(TestIPv6RouteLookup, cls).setUpClass()
1225
1226 @classmethod
1227 def tearDownClass(cls):
1228 super(TestIPv6RouteLookup, cls).tearDownClass()
1229
1230 def setUp(self):
1231 super(TestIPv6RouteLookup, self).setUp()
1232
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001233 drop_nh = VppRoutePath("::1", 0xFFFFFFFF, type=FibPathType.FIB_PATH_TYPE_DROP)
Christian Hoppsf5d38e02020-05-04 10:28:03 -04001234
1235 # Add 3 routes
1236 r = VppIpRoute(self, "2001:1111::", 32, [drop_nh])
1237 r.add_vpp_config()
1238 self.routes.append(r)
1239
1240 r = VppIpRoute(self, "2001:1111:2222::", 48, [drop_nh])
1241 r.add_vpp_config()
1242 self.routes.append(r)
1243
1244 r = VppIpRoute(self, "2001:1111:2222::1", 128, [drop_nh])
1245 r.add_vpp_config()
1246 self.routes.append(r)
1247
1248 def tearDown(self):
1249 # Remove the routes we added
1250 for r in self.routes:
1251 r.remove_vpp_config()
1252
1253 super(TestIPv6RouteLookup, self).tearDown()
1254
1255 def test_exact_match(self):
1256 # Verify we find the host route
1257 prefix = "2001:1111:2222::1/128"
1258 result = self.route_lookup(prefix, True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001259 assert prefix == str(result.route.prefix)
Christian Hoppsf5d38e02020-05-04 10:28:03 -04001260
1261 # Verify we find a middle prefix route
1262 prefix = "2001:1111:2222::/48"
1263 result = self.route_lookup(prefix, True)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001264 assert prefix == str(result.route.prefix)
Christian Hoppsf5d38e02020-05-04 10:28:03 -04001265
1266 # Verify we do not find an available LPM.
1267 with self.vapi.assert_negative_api_retval():
1268 self.route_lookup("2001::2/128", True)
1269
1270 def test_longest_prefix_match(self):
1271 # verify we find lpm
1272 lpm_prefix = "2001:1111:2222::/48"
1273 result = self.route_lookup("2001:1111:2222::2/128", False)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001274 assert lpm_prefix == str(result.route.prefix)
Christian Hoppsf5d38e02020-05-04 10:28:03 -04001275
1276 # Verify we find the exact when not requested
1277 result = self.route_lookup(lpm_prefix, False)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001278 assert lpm_prefix == str(result.route.prefix)
Christian Hoppsf5d38e02020-05-04 10:28:03 -04001279
1280 # Can't seem to delete the default route so no negative LPM test.
1281
1282
Matthew Smith6c92f5b2019-08-07 11:46:30 -05001283class TestIPv6IfAddrRoute(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001284 """IPv6 Interface Addr Route Test Case"""
Matthew Smith6c92f5b2019-08-07 11:46:30 -05001285
1286 @classmethod
1287 def setUpClass(cls):
1288 super(TestIPv6IfAddrRoute, cls).setUpClass()
1289
1290 @classmethod
1291 def tearDownClass(cls):
1292 super(TestIPv6IfAddrRoute, cls).tearDownClass()
1293
1294 def setUp(self):
1295 super(TestIPv6IfAddrRoute, self).setUp()
1296
1297 # create 1 pg interface
1298 self.create_pg_interfaces(range(1))
1299
1300 for i in self.pg_interfaces:
1301 i.admin_up()
1302 i.config_ip6()
1303 i.resolve_ndp()
1304
1305 def tearDown(self):
1306 super(TestIPv6IfAddrRoute, self).tearDown()
1307 for i in self.pg_interfaces:
1308 i.unconfig_ip6()
1309 i.admin_down()
1310
1311 def test_ipv6_ifaddrs_same_prefix(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001312 """IPv6 Interface Addresses Same Prefix test
Matthew Smith6c92f5b2019-08-07 11:46:30 -05001313
1314 Test scenario:
1315
1316 - Verify no route in FIB for prefix 2001:10::/64
1317 - Configure IPv4 address 2001:10::10/64 on an interface
1318 - Verify route in FIB for prefix 2001:10::/64
1319 - Configure IPv4 address 2001:10::20/64 on an interface
1320 - Delete 2001:10::10/64 from interface
1321 - Verify route in FIB for prefix 2001:10::/64
1322 - Delete 2001:10::20/64 from interface
1323 - Verify no route in FIB for prefix 2001:10::/64
1324 """
1325
1326 addr1 = "2001:10::10"
1327 addr2 = "2001:10::20"
1328
Neale Rannsefd7bc22019-11-11 08:32:34 +00001329 if_addr1 = VppIpInterfaceAddress(self, self.pg0, addr1, 64)
1330 if_addr2 = VppIpInterfaceAddress(self, self.pg0, addr2, 64)
1331 self.assertFalse(if_addr1.query_vpp_config())
Matthew Smith6c92f5b2019-08-07 11:46:30 -05001332 self.assertFalse(find_route(self, addr1, 128))
1333 self.assertFalse(find_route(self, addr2, 128))
1334
1335 # configure first address, verify route present
1336 if_addr1.add_vpp_config()
Neale Rannsefd7bc22019-11-11 08:32:34 +00001337 self.assertTrue(if_addr1.query_vpp_config())
Matthew Smith6c92f5b2019-08-07 11:46:30 -05001338 self.assertTrue(find_route(self, addr1, 128))
1339 self.assertFalse(find_route(self, addr2, 128))
1340
1341 # configure second address, delete first, verify route not removed
1342 if_addr2.add_vpp_config()
1343 if_addr1.remove_vpp_config()
Neale Rannsefd7bc22019-11-11 08:32:34 +00001344 self.assertFalse(if_addr1.query_vpp_config())
1345 self.assertTrue(if_addr2.query_vpp_config())
Matthew Smith6c92f5b2019-08-07 11:46:30 -05001346 self.assertFalse(find_route(self, addr1, 128))
1347 self.assertTrue(find_route(self, addr2, 128))
1348
1349 # delete second address, verify route removed
1350 if_addr2.remove_vpp_config()
Neale Rannsefd7bc22019-11-11 08:32:34 +00001351 self.assertFalse(if_addr1.query_vpp_config())
Matthew Smith6c92f5b2019-08-07 11:46:30 -05001352 self.assertFalse(find_route(self, addr1, 128))
1353 self.assertFalse(find_route(self, addr2, 128))
1354
yedgdbd366b2020-05-14 10:51:53 +08001355 def test_ipv6_ifaddr_del(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001356 """Delete an interface address that does not exist"""
yedgdbd366b2020-05-14 10:51:53 +08001357
1358 loopbacks = self.create_loopback_interfaces(1)
1359 lo = self.lo_interfaces[0]
1360
1361 lo.config_ip6()
1362 lo.admin_up()
1363
1364 #
1365 # try and remove pg0's subnet from lo
1366 #
1367 with self.vapi.assert_negative_api_retval():
1368 self.vapi.sw_interface_add_del_address(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001369 sw_if_index=lo.sw_if_index, prefix=self.pg0.local_ip6_prefix, is_add=0
1370 )
yedgdbd366b2020-05-14 10:51:53 +08001371
Matthew Smith6c92f5b2019-08-07 11:46:30 -05001372
Jan Geletye6c78ee2018-06-26 12:24:03 +02001373class TestICMPv6Echo(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001374 """ICMPv6 Echo Test Case"""
Jan Geletye6c78ee2018-06-26 12:24:03 +02001375
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001376 @classmethod
1377 def setUpClass(cls):
1378 super(TestICMPv6Echo, cls).setUpClass()
1379
1380 @classmethod
1381 def tearDownClass(cls):
1382 super(TestICMPv6Echo, cls).tearDownClass()
1383
Jan Geletye6c78ee2018-06-26 12:24:03 +02001384 def setUp(self):
1385 super(TestICMPv6Echo, self).setUp()
1386
1387 # create 1 pg interface
1388 self.create_pg_interfaces(range(1))
1389
1390 for i in self.pg_interfaces:
1391 i.admin_up()
1392 i.config_ip6()
Benoît Ganne2699fe22021-01-18 19:25:38 +01001393 i.resolve_ndp(link_layer=True)
Jan Geletye6c78ee2018-06-26 12:24:03 +02001394 i.resolve_ndp()
1395
1396 def tearDown(self):
1397 super(TestICMPv6Echo, self).tearDown()
1398 for i in self.pg_interfaces:
1399 i.unconfig_ip6()
Jan Geletye6c78ee2018-06-26 12:24:03 +02001400 i.admin_down()
1401
1402 def test_icmpv6_echo(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001403 """VPP replies to ICMPv6 Echo Request
Jan Geletye6c78ee2018-06-26 12:24:03 +02001404
1405 Test scenario:
1406
1407 - Receive ICMPv6 Echo Request message on pg0 interface.
1408 - Check outgoing ICMPv6 Echo Reply message on pg0 interface.
1409 """
1410
Benoît Ganne2699fe22021-01-18 19:25:38 +01001411 # test both with global and local ipv6 addresses
1412 dsts = (self.pg0.local_ip6, self.pg0.local_ip6_ll)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001413 id = 0xB
Benoît Ganne2699fe22021-01-18 19:25:38 +01001414 seq = 5
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001415 data = b"\x0a" * 18
Benoît Ganne2699fe22021-01-18 19:25:38 +01001416 p = list()
1417 for dst in dsts:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001418 p.append(
1419 (
1420 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1421 / IPv6(src=self.pg0.remote_ip6, dst=dst)
1422 / ICMPv6EchoRequest(id=id, seq=seq, data=data)
1423 )
1424 )
Jan Geletye6c78ee2018-06-26 12:24:03 +02001425
Benoît Ganne2699fe22021-01-18 19:25:38 +01001426 self.pg0.add_stream(p)
Jan Geletye6c78ee2018-06-26 12:24:03 +02001427 self.pg_enable_capture(self.pg_interfaces)
1428 self.pg_start()
Benoît Ganne2699fe22021-01-18 19:25:38 +01001429 rxs = self.pg0.get_capture(len(dsts))
Jan Geletye6c78ee2018-06-26 12:24:03 +02001430
Benoît Ganne2699fe22021-01-18 19:25:38 +01001431 for rx, dst in zip(rxs, dsts):
1432 ether = rx[Ether]
1433 ipv6 = rx[IPv6]
1434 icmpv6 = rx[ICMPv6EchoReply]
1435 self.assertEqual(ether.src, self.pg0.local_mac)
1436 self.assertEqual(ether.dst, self.pg0.remote_mac)
1437 self.assertEqual(ipv6.src, dst)
1438 self.assertEqual(ipv6.dst, self.pg0.remote_ip6)
1439 self.assertEqual(icmp6types[icmpv6.type], "Echo Reply")
1440 self.assertEqual(icmpv6.id, id)
1441 self.assertEqual(icmpv6.seq, seq)
1442 self.assertEqual(icmpv6.data, data)
Jan Geletye6c78ee2018-06-26 12:24:03 +02001443
1444
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001445class TestIPv6RD(TestIPv6ND):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001446 """IPv6 Router Discovery Test Case"""
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001447
1448 @classmethod
1449 def setUpClass(cls):
1450 super(TestIPv6RD, cls).setUpClass()
1451
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001452 @classmethod
1453 def tearDownClass(cls):
1454 super(TestIPv6RD, cls).tearDownClass()
1455
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001456 def setUp(self):
1457 super(TestIPv6RD, self).setUp()
1458
1459 # create 2 pg interfaces
1460 self.create_pg_interfaces(range(2))
1461
1462 self.interfaces = list(self.pg_interfaces)
1463
1464 # setup all interfaces
1465 for i in self.interfaces:
1466 i.admin_up()
1467 i.config_ip6()
1468
1469 def tearDown(self):
Neale Ranns744902e2017-08-14 10:35:44 -07001470 for i in self.interfaces:
1471 i.unconfig_ip6()
1472 i.admin_down()
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001473 super(TestIPv6RD, self).tearDown()
1474
1475 def test_rd_send_router_solicitation(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001476 """Verify router solicitation packets"""
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001477
1478 count = 2
1479 self.pg_enable_capture(self.pg_interfaces)
1480 self.pg_start()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001481 self.vapi.ip6nd_send_router_solicitation(self.pg1.sw_if_index, mrc=count)
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001482 rx_list = self.pg1.get_capture(count, timeout=3)
1483 self.assertEqual(len(rx_list), count)
1484 for packet in rx_list:
Paul Vinciguerra978aa642018-11-24 22:19:12 -08001485 self.assertEqual(packet.haslayer(IPv6), 1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001486 self.assertEqual(packet[IPv6].haslayer(ICMPv6ND_RS), 1)
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001487 dst = ip6_normalize(packet[IPv6].dst)
1488 dst2 = ip6_normalize("ff02::2")
1489 self.assert_equal(dst, dst2)
1490 src = ip6_normalize(packet[IPv6].src)
1491 src2 = ip6_normalize(self.pg1.local_ip6_ll)
1492 self.assert_equal(src, src2)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001493 self.assertTrue(bool(packet[ICMPv6ND_RS].haslayer(ICMPv6NDOptSrcLLAddr)))
1494 self.assert_equal(packet[ICMPv6NDOptSrcLLAddr].lladdr, self.pg1.local_mac)
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001495
1496 def verify_prefix_info(self, reported_prefix, prefix_option):
Neale Ranns37029302018-08-10 05:30:06 -07001497 prefix = IPv6Network(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001498 text_type(
1499 prefix_option.getfieldval("prefix")
1500 + "/"
1501 + text_type(prefix_option.getfieldval("prefixlen"))
1502 ),
1503 strict=False,
1504 )
1505 self.assert_equal(
1506 reported_prefix.prefix.network_address, prefix.network_address
1507 )
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001508 L = prefix_option.getfieldval("L")
1509 A = prefix_option.getfieldval("A")
1510 option_flags = (L << 7) | (A << 6)
1511 self.assert_equal(reported_prefix.flags, option_flags)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001512 self.assert_equal(
1513 reported_prefix.valid_time, prefix_option.getfieldval("validlifetime")
1514 )
1515 self.assert_equal(
1516 reported_prefix.preferred_time,
1517 prefix_option.getfieldval("preferredlifetime"),
1518 )
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001519
1520 def test_rd_receive_router_advertisement(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001521 """Verify events triggered by received RA packets"""
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001522
Neale Rannscbe25aa2019-09-30 10:53:31 +00001523 self.vapi.want_ip6_ra_events(enable=1)
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001524
1525 prefix_info_1 = ICMPv6NDOptPrefixInfo(
1526 prefix="1::2",
1527 prefixlen=50,
1528 validlifetime=200,
1529 preferredlifetime=500,
1530 L=1,
1531 A=1,
1532 )
1533
1534 prefix_info_2 = ICMPv6NDOptPrefixInfo(
1535 prefix="7::4",
1536 prefixlen=20,
1537 validlifetime=70,
1538 preferredlifetime=1000,
1539 L=1,
1540 A=0,
1541 )
1542
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001543 p = (
1544 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
1545 / IPv6(dst=self.pg1.local_ip6_ll, src=mk_ll_addr(self.pg1.remote_mac))
1546 / ICMPv6ND_RA()
1547 / prefix_info_1
1548 / prefix_info_2
1549 )
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001550 self.pg1.add_stream([p])
1551 self.pg_start()
1552
1553 ev = self.vapi.wait_for_event(10, "ip6_ra_event")
1554
1555 self.assert_equal(ev.current_hop_limit, 0)
1556 self.assert_equal(ev.flags, 8)
1557 self.assert_equal(ev.router_lifetime_in_sec, 1800)
1558 self.assert_equal(ev.neighbor_reachable_time_in_msec, 0)
1559 self.assert_equal(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001560 ev.time_in_msec_between_retransmitted_neighbor_solicitations, 0
1561 )
Juraj Sloboda4b9669d2018-01-15 10:39:21 +01001562
1563 self.assert_equal(ev.n_prefixes, 2)
1564
1565 self.verify_prefix_info(ev.prefixes[0], prefix_info_1)
1566 self.verify_prefix_info(ev.prefixes[1], prefix_info_2)
1567
1568
Juraj Slobodac0374232018-02-01 15:18:49 +01001569class TestIPv6RDControlPlane(TestIPv6ND):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001570 """IPv6 Router Discovery Control Plane Test Case"""
Juraj Slobodac0374232018-02-01 15:18:49 +01001571
1572 @classmethod
1573 def setUpClass(cls):
1574 super(TestIPv6RDControlPlane, cls).setUpClass()
1575
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001576 @classmethod
1577 def tearDownClass(cls):
1578 super(TestIPv6RDControlPlane, cls).tearDownClass()
1579
Juraj Slobodac0374232018-02-01 15:18:49 +01001580 def setUp(self):
1581 super(TestIPv6RDControlPlane, self).setUp()
1582
1583 # create 1 pg interface
1584 self.create_pg_interfaces(range(1))
1585
1586 self.interfaces = list(self.pg_interfaces)
1587
1588 # setup all interfaces
1589 for i in self.interfaces:
1590 i.admin_up()
1591 i.config_ip6()
1592
1593 def tearDown(self):
1594 super(TestIPv6RDControlPlane, self).tearDown()
1595
1596 @staticmethod
1597 def create_ra_packet(pg, routerlifetime=None):
1598 src_ip = pg.remote_ip6_ll
1599 dst_ip = pg.local_ip6
1600 if routerlifetime is not None:
1601 ra = ICMPv6ND_RA(routerlifetime=routerlifetime)
1602 else:
1603 ra = ICMPv6ND_RA()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001604 p = (
1605 Ether(dst=pg.local_mac, src=pg.remote_mac)
1606 / IPv6(dst=dst_ip, src=src_ip)
1607 / ra
1608 )
Juraj Slobodac0374232018-02-01 15:18:49 +01001609 return p
1610
1611 @staticmethod
1612 def get_default_routes(fib):
1613 list = []
1614 for entry in fib:
Neale Ranns097fa662018-05-01 05:17:55 -07001615 if entry.route.prefix.prefixlen == 0:
1616 for path in entry.route.paths:
Juraj Slobodac0374232018-02-01 15:18:49 +01001617 if path.sw_if_index != 0xFFFFFFFF:
Neale Ranns097fa662018-05-01 05:17:55 -07001618 defaut_route = {}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001619 defaut_route["sw_if_index"] = path.sw_if_index
1620 defaut_route["next_hop"] = path.nh.address.ip6
Neale Ranns097fa662018-05-01 05:17:55 -07001621 list.append(defaut_route)
Juraj Slobodac0374232018-02-01 15:18:49 +01001622 return list
1623
1624 @staticmethod
1625 def get_interface_addresses(fib, pg):
1626 list = []
1627 for entry in fib:
Neale Ranns097fa662018-05-01 05:17:55 -07001628 if entry.route.prefix.prefixlen == 128:
1629 path = entry.route.paths[0]
Juraj Slobodac0374232018-02-01 15:18:49 +01001630 if path.sw_if_index == pg.sw_if_index:
Neale Ranns097fa662018-05-01 05:17:55 -07001631 list.append(str(entry.route.prefix.network_address))
Juraj Slobodac0374232018-02-01 15:18:49 +01001632 return list
1633
Neale Rannscbe25aa2019-09-30 10:53:31 +00001634 def wait_for_no_default_route(self, n_tries=50, s_time=1):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001635 while n_tries:
Neale Rannscbe25aa2019-09-30 10:53:31 +00001636 fib = self.vapi.ip_route_dump(0, True)
1637 default_routes = self.get_default_routes(fib)
Ole Troan6e6ad642020-02-04 13:28:13 +01001638 if 0 == len(default_routes):
Neale Rannscbe25aa2019-09-30 10:53:31 +00001639 return True
1640 n_tries = n_tries - 1
1641 self.sleep(s_time)
1642
1643 return False
1644
Juraj Slobodac0374232018-02-01 15:18:49 +01001645 def test_all(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001646 """Test handling of SLAAC addresses and default routes"""
Juraj Slobodac0374232018-02-01 15:18:49 +01001647
Neale Ranns097fa662018-05-01 05:17:55 -07001648 fib = self.vapi.ip_route_dump(0, True)
Juraj Slobodac0374232018-02-01 15:18:49 +01001649 default_routes = self.get_default_routes(fib)
1650 initial_addresses = set(self.get_interface_addresses(fib, self.pg0))
1651 self.assertEqual(default_routes, [])
Neale Ranns097fa662018-05-01 05:17:55 -07001652 router_address = IPv6Address(text_type(self.pg0.remote_ip6_ll))
Juraj Slobodac0374232018-02-01 15:18:49 +01001653
1654 self.vapi.ip6_nd_address_autoconfig(self.pg0.sw_if_index, 1, 1)
1655
1656 self.sleep(0.1)
1657
1658 # send RA
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001659 packet = (
1660 self.create_ra_packet(self.pg0)
1661 / ICMPv6NDOptPrefixInfo(
1662 prefix="1::",
1663 prefixlen=64,
1664 validlifetime=2,
1665 preferredlifetime=2,
1666 L=1,
1667 A=1,
1668 )
1669 / ICMPv6NDOptPrefixInfo(
1670 prefix="7::",
1671 prefixlen=20,
1672 validlifetime=1500,
1673 preferredlifetime=1000,
1674 L=1,
1675 A=0,
1676 )
1677 )
Juraj Slobodac0374232018-02-01 15:18:49 +01001678 self.pg0.add_stream([packet])
1679 self.pg_start()
1680
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +00001681 self.sleep_on_vpp_time(0.1)
Juraj Slobodac0374232018-02-01 15:18:49 +01001682
Neale Ranns097fa662018-05-01 05:17:55 -07001683 fib = self.vapi.ip_route_dump(0, True)
Juraj Slobodac0374232018-02-01 15:18:49 +01001684
1685 # check FIB for new address
1686 addresses = set(self.get_interface_addresses(fib, self.pg0))
1687 new_addresses = addresses.difference(initial_addresses)
1688 self.assertEqual(len(new_addresses), 1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001689 prefix = IPv6Network(
1690 text_type("%s/%d" % (list(new_addresses)[0], 20)), strict=False
1691 )
1692 self.assertEqual(prefix, IPv6Network(text_type("1::/20")))
Juraj Slobodac0374232018-02-01 15:18:49 +01001693
1694 # check FIB for new default route
1695 default_routes = self.get_default_routes(fib)
1696 self.assertEqual(len(default_routes), 1)
1697 dr = default_routes[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001698 self.assertEqual(dr["sw_if_index"], self.pg0.sw_if_index)
1699 self.assertEqual(dr["next_hop"], router_address)
Juraj Slobodac0374232018-02-01 15:18:49 +01001700
1701 # send RA to delete default route
1702 packet = self.create_ra_packet(self.pg0, routerlifetime=0)
1703 self.pg0.add_stream([packet])
1704 self.pg_start()
1705
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +00001706 self.sleep_on_vpp_time(0.1)
Juraj Slobodac0374232018-02-01 15:18:49 +01001707
1708 # check that default route is deleted
Neale Ranns097fa662018-05-01 05:17:55 -07001709 fib = self.vapi.ip_route_dump(0, True)
Juraj Slobodac0374232018-02-01 15:18:49 +01001710 default_routes = self.get_default_routes(fib)
1711 self.assertEqual(len(default_routes), 0)
1712
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +00001713 self.sleep_on_vpp_time(0.1)
Juraj Slobodac0374232018-02-01 15:18:49 +01001714
1715 # send RA
1716 packet = self.create_ra_packet(self.pg0)
1717 self.pg0.add_stream([packet])
1718 self.pg_start()
1719
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +00001720 self.sleep_on_vpp_time(0.1)
Juraj Slobodac0374232018-02-01 15:18:49 +01001721
1722 # check FIB for new default route
Neale Ranns097fa662018-05-01 05:17:55 -07001723 fib = self.vapi.ip_route_dump(0, True)
Juraj Slobodac0374232018-02-01 15:18:49 +01001724 default_routes = self.get_default_routes(fib)
1725 self.assertEqual(len(default_routes), 1)
1726 dr = default_routes[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001727 self.assertEqual(dr["sw_if_index"], self.pg0.sw_if_index)
1728 self.assertEqual(dr["next_hop"], router_address)
Juraj Slobodac0374232018-02-01 15:18:49 +01001729
1730 # send RA, updating router lifetime to 1s
1731 packet = self.create_ra_packet(self.pg0, 1)
1732 self.pg0.add_stream([packet])
1733 self.pg_start()
1734
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +00001735 self.sleep_on_vpp_time(0.1)
Juraj Slobodac0374232018-02-01 15:18:49 +01001736
1737 # check that default route still exists
Neale Ranns097fa662018-05-01 05:17:55 -07001738 fib = self.vapi.ip_route_dump(0, True)
Juraj Slobodac0374232018-02-01 15:18:49 +01001739 default_routes = self.get_default_routes(fib)
1740 self.assertEqual(len(default_routes), 1)
1741 dr = default_routes[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001742 self.assertEqual(dr["sw_if_index"], self.pg0.sw_if_index)
1743 self.assertEqual(dr["next_hop"], router_address)
Juraj Slobodac0374232018-02-01 15:18:49 +01001744
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +00001745 self.sleep_on_vpp_time(1)
Juraj Slobodac0374232018-02-01 15:18:49 +01001746
1747 # check that default route is deleted
Neale Rannscbe25aa2019-09-30 10:53:31 +00001748 self.assertTrue(self.wait_for_no_default_route())
Juraj Slobodac0374232018-02-01 15:18:49 +01001749
1750 # check FIB still contains the SLAAC address
1751 addresses = set(self.get_interface_addresses(fib, self.pg0))
1752 new_addresses = addresses.difference(initial_addresses)
Paul Vinciguerra4271c972019-05-14 13:25:49 -04001753
Juraj Slobodac0374232018-02-01 15:18:49 +01001754 self.assertEqual(len(new_addresses), 1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001755 prefix = IPv6Network(
1756 text_type("%s/%d" % (list(new_addresses)[0], 20)), strict=False
1757 )
1758 self.assertEqual(prefix, IPv6Network(text_type("1::/20")))
Juraj Slobodac0374232018-02-01 15:18:49 +01001759
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +00001760 self.sleep_on_vpp_time(1)
Juraj Slobodac0374232018-02-01 15:18:49 +01001761
1762 # check that SLAAC address is deleted
Neale Ranns097fa662018-05-01 05:17:55 -07001763 fib = self.vapi.ip_route_dump(0, True)
Juraj Slobodac0374232018-02-01 15:18:49 +01001764 addresses = set(self.get_interface_addresses(fib, self.pg0))
1765 new_addresses = addresses.difference(initial_addresses)
1766 self.assertEqual(len(new_addresses), 0)
1767
1768
Neale Ranns3f844d02017-02-18 00:03:54 -08001769class IPv6NDProxyTest(TestIPv6ND):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001770 """IPv6 ND ProxyTest Case"""
Neale Ranns3f844d02017-02-18 00:03:54 -08001771
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001772 @classmethod
1773 def setUpClass(cls):
1774 super(IPv6NDProxyTest, cls).setUpClass()
1775
1776 @classmethod
1777 def tearDownClass(cls):
1778 super(IPv6NDProxyTest, cls).tearDownClass()
1779
Neale Ranns3f844d02017-02-18 00:03:54 -08001780 def setUp(self):
1781 super(IPv6NDProxyTest, self).setUp()
1782
1783 # create 3 pg interfaces
1784 self.create_pg_interfaces(range(3))
1785
1786 # pg0 is the master interface, with the configured subnet
1787 self.pg0.admin_up()
1788 self.pg0.config_ip6()
1789 self.pg0.resolve_ndp()
1790
1791 self.pg1.ip6_enable()
1792 self.pg2.ip6_enable()
1793
1794 def tearDown(self):
1795 super(IPv6NDProxyTest, self).tearDown()
1796
1797 def test_nd_proxy(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001798 """IPv6 Proxy ND"""
Neale Ranns3f844d02017-02-18 00:03:54 -08001799
1800 #
1801 # Generate some hosts in the subnet that we are proxying
1802 #
1803 self.pg0.generate_remote_hosts(8)
1804
1805 nsma = in6_getnsma(inet_pton(AF_INET6, self.pg0.local_ip6))
1806 d = inet_ntop(AF_INET6, nsma)
1807
1808 #
1809 # Send an NS for one of those remote hosts on one of the proxy links
1810 # expect no response since it's from an address that is not
1811 # on the link that has the prefix configured
1812 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001813 ns_pg1 = (
1814 Ether(dst=in6_getnsmac(nsma), src=self.pg1.remote_mac)
1815 / IPv6(dst=d, src=self.pg0._remote_hosts[2].ip6)
1816 / ICMPv6ND_NS(tgt=self.pg0.local_ip6)
1817 / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0._remote_hosts[2].mac)
1818 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001819
1820 self.send_and_assert_no_replies(self.pg1, ns_pg1, "Off link NS")
1821
1822 #
1823 # Add proxy support for the host
1824 #
Ole Troane1ade682019-03-04 23:55:43 +01001825 self.vapi.ip6nd_proxy_add_del(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001826 is_add=1,
1827 ip=inet_pton(AF_INET6, self.pg0._remote_hosts[2].ip6),
1828 sw_if_index=self.pg1.sw_if_index,
1829 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001830
1831 #
1832 # try that NS again. this time we expect an NA back
1833 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001834 self.send_and_expect_na(
1835 self.pg1,
1836 ns_pg1,
1837 "NS to proxy entry",
1838 dst_ip=self.pg0._remote_hosts[2].ip6,
1839 tgt_ip=self.pg0.local_ip6,
1840 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001841
1842 #
1843 # ... and that we have an entry in the ND cache
1844 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001845 self.assertTrue(
1846 find_nbr(self, self.pg1.sw_if_index, self.pg0._remote_hosts[2].ip6)
1847 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001848
1849 #
1850 # ... and we can route traffic to it
1851 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001852 t = (
1853 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
1854 / IPv6(dst=self.pg0._remote_hosts[2].ip6, src=self.pg0.remote_ip6)
1855 / inet6.UDP(sport=10000, dport=20000)
1856 / Raw(b"\xa5" * 100)
1857 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001858
1859 self.pg0.add_stream(t)
1860 self.pg_enable_capture(self.pg_interfaces)
1861 self.pg_start()
1862 rx = self.pg1.get_capture(1)
1863 rx = rx[0]
1864
1865 self.assertEqual(rx[Ether].dst, self.pg0._remote_hosts[2].mac)
1866 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1867
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001868 self.assertEqual(rx[IPv6].src, t[IPv6].src)
1869 self.assertEqual(rx[IPv6].dst, t[IPv6].dst)
Neale Ranns3f844d02017-02-18 00:03:54 -08001870
1871 #
1872 # Test we proxy for the host on the main interface
1873 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001874 ns_pg0 = (
1875 Ether(dst=in6_getnsmac(nsma), src=self.pg0.remote_mac)
1876 / IPv6(dst=d, src=self.pg0.remote_ip6)
1877 / ICMPv6ND_NS(tgt=self.pg0._remote_hosts[2].ip6)
1878 / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)
1879 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001880
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001881 self.send_and_expect_na(
1882 self.pg0,
1883 ns_pg0,
1884 "NS to proxy entry on main",
1885 tgt_ip=self.pg0._remote_hosts[2].ip6,
1886 dst_ip=self.pg0.remote_ip6,
1887 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001888
1889 #
1890 # Setup and resolve proxy for another host on another interface
1891 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001892 ns_pg2 = (
1893 Ether(dst=in6_getnsmac(nsma), src=self.pg2.remote_mac)
1894 / IPv6(dst=d, src=self.pg0._remote_hosts[3].ip6)
1895 / ICMPv6ND_NS(tgt=self.pg0.local_ip6)
1896 / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0._remote_hosts[2].mac)
1897 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001898
Ole Troane1ade682019-03-04 23:55:43 +01001899 self.vapi.ip6nd_proxy_add_del(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001900 is_add=1,
1901 ip=inet_pton(AF_INET6, self.pg0._remote_hosts[3].ip6),
1902 sw_if_index=self.pg2.sw_if_index,
1903 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001904
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001905 self.send_and_expect_na(
1906 self.pg2,
1907 ns_pg2,
1908 "NS to proxy entry other interface",
1909 dst_ip=self.pg0._remote_hosts[3].ip6,
1910 tgt_ip=self.pg0.local_ip6,
1911 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001912
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001913 self.assertTrue(
1914 find_nbr(self, self.pg2.sw_if_index, self.pg0._remote_hosts[3].ip6)
1915 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001916
1917 #
1918 # hosts can communicate. pg2->pg1
1919 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001920 t2 = (
1921 Ether(dst=self.pg2.local_mac, src=self.pg0.remote_hosts[3].mac)
1922 / IPv6(dst=self.pg0._remote_hosts[2].ip6, src=self.pg0._remote_hosts[3].ip6)
1923 / inet6.UDP(sport=10000, dport=20000)
1924 / Raw(b"\xa5" * 100)
1925 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001926
1927 self.pg2.add_stream(t2)
1928 self.pg_enable_capture(self.pg_interfaces)
1929 self.pg_start()
1930 rx = self.pg1.get_capture(1)
1931 rx = rx[0]
1932
1933 self.assertEqual(rx[Ether].dst, self.pg0._remote_hosts[2].mac)
1934 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1935
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001936 self.assertEqual(rx[IPv6].src, t2[IPv6].src)
1937 self.assertEqual(rx[IPv6].dst, t2[IPv6].dst)
Neale Ranns3f844d02017-02-18 00:03:54 -08001938
1939 #
1940 # remove the proxy configs
1941 #
Ole Troane1ade682019-03-04 23:55:43 +01001942 self.vapi.ip6nd_proxy_add_del(
Ole Troan9a475372019-03-05 16:58:24 +01001943 ip=inet_pton(AF_INET6, self.pg0._remote_hosts[2].ip6),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001944 sw_if_index=self.pg1.sw_if_index,
1945 is_add=0,
1946 )
Ole Troane1ade682019-03-04 23:55:43 +01001947 self.vapi.ip6nd_proxy_add_del(
Ole Troan9a475372019-03-05 16:58:24 +01001948 ip=inet_pton(AF_INET6, self.pg0._remote_hosts[3].ip6),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001949 sw_if_index=self.pg2.sw_if_index,
1950 is_add=0,
1951 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001952
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001953 self.assertFalse(
1954 find_nbr(self, self.pg2.sw_if_index, self.pg0._remote_hosts[3].ip6)
1955 )
1956 self.assertFalse(
1957 find_nbr(self, self.pg1.sw_if_index, self.pg0._remote_hosts[2].ip6)
1958 )
Neale Ranns3f844d02017-02-18 00:03:54 -08001959
1960 #
1961 # no longer proxy-ing...
1962 #
1963 self.send_and_assert_no_replies(self.pg0, ns_pg0, "Proxy unconfigured")
1964 self.send_and_assert_no_replies(self.pg1, ns_pg1, "Proxy unconfigured")
1965 self.send_and_assert_no_replies(self.pg2, ns_pg2, "Proxy unconfigured")
1966
1967 #
1968 # no longer forwarding. traffic generates NS out of the glean/main
1969 # interface
1970 #
1971 self.pg2.add_stream(t2)
1972 self.pg_enable_capture(self.pg_interfaces)
1973 self.pg_start()
1974
1975 rx = self.pg0.get_capture(1)
1976
1977 self.assertTrue(rx[0].haslayer(ICMPv6ND_NS))
1978
1979
Tianyu Li6d95f8c2022-02-25 05:51:10 +00001980class TestIP6Null(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001981 """IPv6 routes via NULL"""
Neale Ranns37be7362017-02-21 17:30:26 -08001982
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001983 @classmethod
1984 def setUpClass(cls):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00001985 super(TestIP6Null, cls).setUpClass()
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001986
1987 @classmethod
1988 def tearDownClass(cls):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00001989 super(TestIP6Null, cls).tearDownClass()
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07001990
Neale Ranns37be7362017-02-21 17:30:26 -08001991 def setUp(self):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00001992 super(TestIP6Null, self).setUp()
Neale Ranns37be7362017-02-21 17:30:26 -08001993
1994 # create 2 pg interfaces
1995 self.create_pg_interfaces(range(1))
1996
1997 for i in self.pg_interfaces:
1998 i.admin_up()
1999 i.config_ip6()
2000 i.resolve_ndp()
2001
2002 def tearDown(self):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00002003 super(TestIP6Null, self).tearDown()
Neale Ranns37be7362017-02-21 17:30:26 -08002004 for i in self.pg_interfaces:
2005 i.unconfig_ip6()
2006 i.admin_down()
2007
2008 def test_ip_null(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002009 """IP NULL route"""
Neale Ranns37be7362017-02-21 17:30:26 -08002010
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002011 p = (
2012 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2013 / IPv6(src=self.pg0.remote_ip6, dst="2001::1")
2014 / inet6.UDP(sport=1234, dport=1234)
2015 / Raw(b"\xa5" * 100)
2016 )
Neale Ranns37be7362017-02-21 17:30:26 -08002017
2018 #
2019 # A route via IP NULL that will reply with ICMP unreachables
2020 #
Neale Ranns097fa662018-05-01 05:17:55 -07002021 ip_unreach = VppIpRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002022 self,
2023 "2001::",
2024 64,
2025 [
2026 VppRoutePath(
2027 "::", 0xFFFFFFFF, type=FibPathType.FIB_PATH_TYPE_ICMP_UNREACH
2028 )
2029 ],
2030 )
Neale Ranns37be7362017-02-21 17:30:26 -08002031 ip_unreach.add_vpp_config()
2032
2033 self.pg0.add_stream(p)
2034 self.pg_enable_capture(self.pg_interfaces)
2035 self.pg_start()
2036
2037 rx = self.pg0.get_capture(1)
2038 rx = rx[0]
2039 icmp = rx[ICMPv6DestUnreach]
2040
2041 # 0 = "No route to destination"
2042 self.assertEqual(icmp.code, 0)
2043
2044 # ICMP is rate limited. pause a bit
2045 self.sleep(1)
2046
2047 #
2048 # A route via IP NULL that will reply with ICMP prohibited
2049 #
Neale Ranns097fa662018-05-01 05:17:55 -07002050 ip_prohibit = VppIpRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002051 self,
2052 "2001::1",
2053 128,
2054 [
2055 VppRoutePath(
2056 "::", 0xFFFFFFFF, type=FibPathType.FIB_PATH_TYPE_ICMP_PROHIBIT
2057 )
2058 ],
2059 )
Neale Ranns37be7362017-02-21 17:30:26 -08002060 ip_prohibit.add_vpp_config()
2061
2062 self.pg0.add_stream(p)
2063 self.pg_enable_capture(self.pg_interfaces)
2064 self.pg_start()
2065
2066 rx = self.pg0.get_capture(1)
2067 rx = rx[0]
2068 icmp = rx[ICMPv6DestUnreach]
2069
2070 # 1 = "Communication with destination administratively prohibited"
2071 self.assertEqual(icmp.code, 1)
2072
2073
Tianyu Li6d95f8c2022-02-25 05:51:10 +00002074class TestIP6Disabled(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002075 """IPv6 disabled"""
Neale Ranns180279b2017-03-16 15:49:09 -04002076
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002077 @classmethod
2078 def setUpClass(cls):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00002079 super(TestIP6Disabled, cls).setUpClass()
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002080
2081 @classmethod
2082 def tearDownClass(cls):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00002083 super(TestIP6Disabled, cls).tearDownClass()
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002084
Neale Ranns180279b2017-03-16 15:49:09 -04002085 def setUp(self):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00002086 super(TestIP6Disabled, self).setUp()
Neale Ranns180279b2017-03-16 15:49:09 -04002087
2088 # create 2 pg interfaces
2089 self.create_pg_interfaces(range(2))
2090
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07002091 # PG0 is IP enabled
Neale Ranns180279b2017-03-16 15:49:09 -04002092 self.pg0.admin_up()
2093 self.pg0.config_ip6()
2094 self.pg0.resolve_ndp()
2095
2096 # PG 1 is not IP enabled
2097 self.pg1.admin_up()
2098
2099 def tearDown(self):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00002100 super(TestIP6Disabled, self).tearDown()
Neale Ranns180279b2017-03-16 15:49:09 -04002101 for i in self.pg_interfaces:
2102 i.unconfig_ip4()
2103 i.admin_down()
2104
Neale Ranns180279b2017-03-16 15:49:09 -04002105 def test_ip_disabled(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002106 """IP Disabled"""
Neale Ranns180279b2017-03-16 15:49:09 -04002107
Neale Ranns990f6942020-10-20 07:20:17 +00002108 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
2109 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
Neale Ranns180279b2017-03-16 15:49:09 -04002110 #
2111 # An (S,G).
2112 # one accepting interface, pg0, 2 forwarding interfaces
2113 #
2114 route_ff_01 = VppIpMRoute(
2115 self,
2116 "::",
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002117 "ffef::1",
2118 128,
Neale Ranns990f6942020-10-20 07:20:17 +00002119 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002120 [
2121 VppMRoutePath(
2122 self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
2123 ),
2124 VppMRoutePath(
2125 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
2126 ),
2127 ],
2128 )
Neale Ranns180279b2017-03-16 15:49:09 -04002129 route_ff_01.add_vpp_config()
2130
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002131 pu = (
2132 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
2133 / IPv6(src="2001::1", dst=self.pg0.remote_ip6)
2134 / inet6.UDP(sport=1234, dport=1234)
2135 / Raw(b"\xa5" * 100)
2136 )
2137 pm = (
2138 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
2139 / IPv6(src="2001::1", dst="ffef::1")
2140 / inet6.UDP(sport=1234, dport=1234)
2141 / Raw(b"\xa5" * 100)
2142 )
Neale Ranns180279b2017-03-16 15:49:09 -04002143
2144 #
2145 # PG1 does not forward IP traffic
2146 #
2147 self.send_and_assert_no_replies(self.pg1, pu, "IPv6 disabled")
2148 self.send_and_assert_no_replies(self.pg1, pm, "IPv6 disabled")
2149
2150 #
2151 # IP enable PG1
2152 #
2153 self.pg1.config_ip6()
2154
2155 #
2156 # Now we get packets through
2157 #
2158 self.pg1.add_stream(pu)
2159 self.pg_enable_capture(self.pg_interfaces)
2160 self.pg_start()
2161 rx = self.pg0.get_capture(1)
2162
2163 self.pg1.add_stream(pm)
2164 self.pg_enable_capture(self.pg_interfaces)
2165 self.pg_start()
2166 rx = self.pg0.get_capture(1)
2167
2168 #
2169 # Disable PG1
2170 #
2171 self.pg1.unconfig_ip6()
2172
2173 #
2174 # PG1 does not forward IP traffic
2175 #
2176 self.send_and_assert_no_replies(self.pg1, pu, "IPv6 disabled")
2177 self.send_and_assert_no_replies(self.pg1, pm, "IPv6 disabled")
2178
2179
Neale Ranns227038a2017-04-21 01:07:59 -07002180class TestIP6LoadBalance(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002181 """IPv6 Load-Balancing"""
Neale Ranns227038a2017-04-21 01:07:59 -07002182
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002183 @classmethod
2184 def setUpClass(cls):
2185 super(TestIP6LoadBalance, cls).setUpClass()
2186
2187 @classmethod
2188 def tearDownClass(cls):
2189 super(TestIP6LoadBalance, cls).tearDownClass()
2190
Neale Ranns227038a2017-04-21 01:07:59 -07002191 def setUp(self):
2192 super(TestIP6LoadBalance, self).setUp()
2193
2194 self.create_pg_interfaces(range(5))
2195
Neale Ranns15002542017-09-10 04:39:11 -07002196 mpls_tbl = VppMplsTable(self, 0)
2197 mpls_tbl.add_vpp_config()
2198
Neale Ranns227038a2017-04-21 01:07:59 -07002199 for i in self.pg_interfaces:
2200 i.admin_up()
2201 i.config_ip6()
2202 i.resolve_ndp()
Neale Ranns71275e32017-05-25 12:38:58 -07002203 i.enable_mpls()
Neale Ranns227038a2017-04-21 01:07:59 -07002204
2205 def tearDown(self):
Neale Ranns227038a2017-04-21 01:07:59 -07002206 for i in self.pg_interfaces:
2207 i.unconfig_ip6()
2208 i.admin_down()
Neale Ranns71275e32017-05-25 12:38:58 -07002209 i.disable_mpls()
Neale Ranns15002542017-09-10 04:39:11 -07002210 super(TestIP6LoadBalance, self).tearDown()
Neale Ranns227038a2017-04-21 01:07:59 -07002211
Neale Ranns227038a2017-04-21 01:07:59 -07002212 def test_ip6_load_balance(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002213 """IPv6 Load-Balancing"""
Neale Ranns227038a2017-04-21 01:07:59 -07002214
2215 #
2216 # An array of packets that differ only in the destination port
Neale Ranns71275e32017-05-25 12:38:58 -07002217 # - IP only
2218 # - MPLS EOS
2219 # - MPLS non-EOS
2220 # - MPLS non-EOS with an entropy label
Neale Ranns227038a2017-04-21 01:07:59 -07002221 #
Neale Ranns71275e32017-05-25 12:38:58 -07002222 port_ip_pkts = []
2223 port_mpls_pkts = []
2224 port_mpls_neos_pkts = []
2225 port_ent_pkts = []
Neale Ranns227038a2017-04-21 01:07:59 -07002226
2227 #
2228 # An array of packets that differ only in the source address
2229 #
Neale Ranns71275e32017-05-25 12:38:58 -07002230 src_ip_pkts = []
2231 src_mpls_pkts = []
Neale Ranns227038a2017-04-21 01:07:59 -07002232
Paul Vinciguerra4271c972019-05-14 13:25:49 -04002233 for ii in range(NUM_PKTS):
Paul Vinciguerra978aa642018-11-24 22:19:12 -08002234 port_ip_hdr = (
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002235 IPv6(dst="3000::1", src="3000:1::1")
2236 / inet6.UDP(sport=1234, dport=1234 + ii)
2237 / Raw(b"\xa5" * 100)
2238 )
2239 port_ip_pkts.append(
2240 (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / port_ip_hdr)
2241 )
2242 port_mpls_pkts.append(
2243 (
2244 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2245 / MPLS(label=66, ttl=2)
2246 / port_ip_hdr
2247 )
2248 )
2249 port_mpls_neos_pkts.append(
2250 (
2251 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2252 / MPLS(label=67, ttl=2)
2253 / MPLS(label=77, ttl=2)
2254 / port_ip_hdr
2255 )
2256 )
2257 port_ent_pkts.append(
2258 (
2259 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2260 / MPLS(label=67, ttl=2)
2261 / MPLS(label=14, ttl=2)
2262 / MPLS(label=999, ttl=2)
2263 / port_ip_hdr
2264 )
2265 )
Paul Vinciguerra978aa642018-11-24 22:19:12 -08002266 src_ip_hdr = (
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002267 IPv6(dst="3000::1", src="3000:1::%d" % ii)
2268 / inet6.UDP(sport=1234, dport=1234)
2269 / Raw(b"\xa5" * 100)
2270 )
2271 src_ip_pkts.append(
2272 (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / src_ip_hdr)
2273 )
2274 src_mpls_pkts.append(
2275 (
2276 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2277 / MPLS(label=66, ttl=2)
2278 / src_ip_hdr
2279 )
2280 )
Neale Ranns227038a2017-04-21 01:07:59 -07002281
Neale Ranns71275e32017-05-25 12:38:58 -07002282 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07002283 # A route for the IP packets
Neale Ranns71275e32017-05-25 12:38:58 -07002284 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002285 route_3000_1 = VppIpRoute(
2286 self,
2287 "3000::1",
2288 128,
2289 [
2290 VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index),
2291 VppRoutePath(self.pg2.remote_ip6, self.pg2.sw_if_index),
2292 ],
2293 )
Neale Ranns227038a2017-04-21 01:07:59 -07002294 route_3000_1.add_vpp_config()
2295
2296 #
Neale Ranns71275e32017-05-25 12:38:58 -07002297 # a local-label for the EOS packets
2298 #
2299 binding = VppMplsIpBind(self, 66, "3000::1", 128, is_ip6=1)
2300 binding.add_vpp_config()
2301
2302 #
2303 # An MPLS route for the non-EOS packets
2304 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002305 route_67 = VppMplsRoute(
2306 self,
2307 67,
2308 0,
2309 [
2310 VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, labels=[67]),
2311 VppRoutePath(self.pg2.remote_ip6, self.pg2.sw_if_index, labels=[67]),
2312 ],
2313 )
Neale Ranns71275e32017-05-25 12:38:58 -07002314 route_67.add_vpp_config()
2315
2316 #
Neale Ranns227038a2017-04-21 01:07:59 -07002317 # inject the packet on pg0 - expect load-balancing across the 2 paths
2318 # - since the default hash config is to use IP src,dst and port
2319 # src,dst
2320 # We are not going to ensure equal amounts of packets across each link,
2321 # since the hash algorithm is statistical and therefore this can never
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07002322 # be guaranteed. But with 64 different packets we do expect some
Neale Ranns227038a2017-04-21 01:07:59 -07002323 # balancing. So instead just ensure there is traffic on each link.
2324 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002325 rx = self.send_and_expect_load_balancing(
2326 self.pg0, port_ip_pkts, [self.pg1, self.pg2]
2327 )
Neale Ranns3d5f08a2021-01-22 16:12:38 +00002328 n_ip_pg0 = len(rx[0])
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002329 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts, [self.pg1, self.pg2])
2330 self.send_and_expect_load_balancing(
2331 self.pg0, port_mpls_pkts, [self.pg1, self.pg2]
2332 )
2333 self.send_and_expect_load_balancing(
2334 self.pg0, src_mpls_pkts, [self.pg1, self.pg2]
2335 )
2336 rx = self.send_and_expect_load_balancing(
2337 self.pg0, port_mpls_neos_pkts, [self.pg1, self.pg2]
2338 )
Neale Ranns3d5f08a2021-01-22 16:12:38 +00002339 n_mpls_pg0 = len(rx[0])
2340
2341 #
2342 # change the router ID and expect the distribution changes
2343 #
2344 self.vapi.set_ip_flow_hash_router_id(router_id=0x11111111)
2345
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002346 rx = self.send_and_expect_load_balancing(
2347 self.pg0, port_ip_pkts, [self.pg1, self.pg2]
2348 )
Neale Ranns3d5f08a2021-01-22 16:12:38 +00002349 self.assertNotEqual(n_ip_pg0, len(rx[0]))
2350
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002351 rx = self.send_and_expect_load_balancing(
2352 self.pg0, src_mpls_pkts, [self.pg1, self.pg2]
2353 )
Neale Ranns3d5f08a2021-01-22 16:12:38 +00002354 self.assertNotEqual(n_mpls_pg0, len(rx[0]))
Neale Ranns71275e32017-05-25 12:38:58 -07002355
2356 #
2357 # The packets with Entropy label in should not load-balance,
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07002358 # since the Entropy value is fixed.
Neale Ranns71275e32017-05-25 12:38:58 -07002359 #
Neale Ranns699bea22022-02-17 09:22:16 +00002360 self.send_and_expect_only(self.pg0, port_ent_pkts, self.pg1)
Neale Ranns227038a2017-04-21 01:07:59 -07002361
2362 #
2363 # change the flow hash config so it's only IP src,dst
2364 # - now only the stream with differing source address will
2365 # load-balance
2366 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002367 self.vapi.set_ip_flow_hash(
2368 vrf_id=0, src=1, dst=1, proto=1, sport=0, dport=0, is_ipv6=1
2369 )
Neale Ranns227038a2017-04-21 01:07:59 -07002370
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002371 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts, [self.pg1, self.pg2])
2372 self.send_and_expect_load_balancing(
2373 self.pg0, src_mpls_pkts, [self.pg1, self.pg2]
2374 )
Neale Ranns699bea22022-02-17 09:22:16 +00002375 self.send_and_expect_only(self.pg0, port_ip_pkts, self.pg2)
Neale Ranns227038a2017-04-21 01:07:59 -07002376
2377 #
2378 # change the flow hash config back to defaults
2379 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002380 self.vapi.set_ip_flow_hash(
2381 vrf_id=0, src=1, dst=1, sport=1, dport=1, proto=1, is_ipv6=1
2382 )
Neale Ranns227038a2017-04-21 01:07:59 -07002383
2384 #
2385 # Recursive prefixes
2386 # - testing that 2 stages of load-balancing occurs and there is no
2387 # polarisation (i.e. only 2 of 4 paths are used)
2388 #
2389 port_pkts = []
2390 src_pkts = []
2391
2392 for ii in range(257):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002393 port_pkts.append(
2394 (
2395 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2396 / IPv6(dst="4000::1", src="4000:1::1")
2397 / inet6.UDP(sport=1234, dport=1234 + ii)
2398 / Raw(b"\xa5" * 100)
2399 )
2400 )
2401 src_pkts.append(
2402 (
2403 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2404 / IPv6(dst="4000::1", src="4000:1::%d" % ii)
2405 / inet6.UDP(sport=1234, dport=1234)
2406 / Raw(b"\xa5" * 100)
2407 )
2408 )
Neale Ranns227038a2017-04-21 01:07:59 -07002409
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002410 route_3000_2 = VppIpRoute(
2411 self,
2412 "3000::2",
2413 128,
2414 [
2415 VppRoutePath(self.pg3.remote_ip6, self.pg3.sw_if_index),
2416 VppRoutePath(self.pg4.remote_ip6, self.pg4.sw_if_index),
2417 ],
2418 )
Neale Ranns227038a2017-04-21 01:07:59 -07002419 route_3000_2.add_vpp_config()
2420
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002421 route_4000_1 = VppIpRoute(
2422 self,
2423 "4000::1",
2424 128,
2425 [VppRoutePath("3000::1", 0xFFFFFFFF), VppRoutePath("3000::2", 0xFFFFFFFF)],
2426 )
Neale Ranns227038a2017-04-21 01:07:59 -07002427 route_4000_1.add_vpp_config()
2428
2429 #
2430 # inject the packet on pg0 - expect load-balancing across all 4 paths
2431 #
2432 self.vapi.cli("clear trace")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002433 self.send_and_expect_load_balancing(
2434 self.pg0, port_pkts, [self.pg1, self.pg2, self.pg3, self.pg4]
2435 )
2436 self.send_and_expect_load_balancing(
2437 self.pg0, src_pkts, [self.pg1, self.pg2, self.pg3, self.pg4]
2438 )
Neale Ranns227038a2017-04-21 01:07:59 -07002439
Neale Ranns42e6b092017-07-31 02:56:03 -07002440 #
2441 # Recursive prefixes
2442 # - testing that 2 stages of load-balancing no choices
2443 #
2444 port_pkts = []
2445
2446 for ii in range(257):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002447 port_pkts.append(
2448 (
2449 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2450 / IPv6(dst="6000::1", src="6000:1::1")
2451 / inet6.UDP(sport=1234, dport=1234 + ii)
2452 / Raw(b"\xa5" * 100)
2453 )
2454 )
Neale Ranns42e6b092017-07-31 02:56:03 -07002455
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002456 route_5000_2 = VppIpRoute(
2457 self,
2458 "5000::2",
2459 128,
2460 [VppRoutePath(self.pg3.remote_ip6, self.pg3.sw_if_index)],
2461 )
Neale Ranns42e6b092017-07-31 02:56:03 -07002462 route_5000_2.add_vpp_config()
2463
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002464 route_6000_1 = VppIpRoute(
2465 self, "6000::1", 128, [VppRoutePath("5000::2", 0xFFFFFFFF)]
2466 )
Neale Ranns42e6b092017-07-31 02:56:03 -07002467 route_6000_1.add_vpp_config()
2468
2469 #
2470 # inject the packet on pg0 - expect load-balancing across all 4 paths
2471 #
2472 self.vapi.cli("clear trace")
Neale Ranns699bea22022-02-17 09:22:16 +00002473 self.send_and_expect_only(self.pg0, port_pkts, self.pg3)
Neale Ranns42e6b092017-07-31 02:56:03 -07002474
Neale Ranns227038a2017-04-21 01:07:59 -07002475
Brian Russella1f36062021-01-19 16:58:14 +00002476class IP6PuntSetup(object):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002477 """Setup for IPv6 Punt Police/Redirect"""
Neale Rannsd91c1db2017-07-31 02:30:50 -07002478
Brian Russella1f36062021-01-19 16:58:14 +00002479 def punt_setup(self):
Pavel Kotucek609e1212018-11-27 09:59:44 +01002480 self.create_pg_interfaces(range(4))
Neale Rannsd91c1db2017-07-31 02:30:50 -07002481
2482 for i in self.pg_interfaces:
2483 i.admin_up()
2484 i.config_ip6()
2485 i.resolve_ndp()
2486
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002487 self.pkt = (
2488 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2489 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
2490 / inet6.TCP(sport=1234, dport=1234)
2491 / Raw(b"\xa5" * 100)
2492 )
Brian Russella1f36062021-01-19 16:58:14 +00002493
2494 def punt_teardown(self):
Neale Rannsd91c1db2017-07-31 02:30:50 -07002495 for i in self.pg_interfaces:
2496 i.unconfig_ip6()
2497 i.admin_down()
2498
Brian Russella1f36062021-01-19 16:58:14 +00002499
2500class TestIP6Punt(IP6PuntSetup, VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002501 """IPv6 Punt Police/Redirect"""
Brian Russella1f36062021-01-19 16:58:14 +00002502
2503 def setUp(self):
2504 super(TestIP6Punt, self).setUp()
2505 super(TestIP6Punt, self).punt_setup()
2506
2507 def tearDown(self):
2508 super(TestIP6Punt, self).punt_teardown()
2509 super(TestIP6Punt, self).tearDown()
2510
Neale Rannsd91c1db2017-07-31 02:30:50 -07002511 def test_ip_punt(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002512 """IP6 punt police and redirect"""
Neale Rannsd91c1db2017-07-31 02:30:50 -07002513
Brian Russella1f36062021-01-19 16:58:14 +00002514 pkts = self.pkt * 1025
Neale Rannsd91c1db2017-07-31 02:30:50 -07002515
2516 #
2517 # Configure a punt redirect via pg1.
2518 #
Ole Troan0bcad322018-12-11 13:04:01 +01002519 nh_addr = self.pg1.remote_ip6
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002520 ip_punt_redirect = VppIpPuntRedirect(
2521 self, self.pg0.sw_if_index, self.pg1.sw_if_index, nh_addr
2522 )
Jakub Grajciar2df2f752020-12-01 11:23:44 +01002523 ip_punt_redirect.add_vpp_config()
Neale Rannsd91c1db2017-07-31 02:30:50 -07002524
2525 self.send_and_expect(self.pg0, pkts, self.pg1)
2526
2527 #
2528 # add a policer
2529 #
Jakub Grajciarcd01fb42020-03-02 13:16:53 +01002530 policer = VppPolicer(self, "ip6-punt", 400, 0, 10, 0, rate_type=1)
2531 policer.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002532 ip_punt_policer = VppIpPuntPolicer(self, policer.policer_index, is_ip6=True)
Jakub Grajciar2df2f752020-12-01 11:23:44 +01002533 ip_punt_policer.add_vpp_config()
Neale Rannsd91c1db2017-07-31 02:30:50 -07002534
2535 self.vapi.cli("clear trace")
2536 self.pg0.add_stream(pkts)
2537 self.pg_enable_capture(self.pg_interfaces)
2538 self.pg_start()
2539
2540 #
Paul Vinciguerra8feeaff2019-03-27 11:25:48 -07002541 # the number of packet received should be greater than 0,
Neale Rannsd91c1db2017-07-31 02:30:50 -07002542 # but not equal to the number sent, since some were policed
2543 #
2544 rx = self.pg1._get_capture(1)
Brian Russelle9887262021-01-27 14:45:22 +00002545 stats = policer.get_stats()
2546
2547 # Single rate policer - expect conform, violate but no exceed
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002548 self.assertGreater(stats["conform_packets"], 0)
2549 self.assertEqual(stats["exceed_packets"], 0)
2550 self.assertGreater(stats["violate_packets"], 0)
Brian Russelle9887262021-01-27 14:45:22 +00002551
Paul Vinciguerra3d2df212018-11-24 23:19:53 -08002552 self.assertGreater(len(rx), 0)
2553 self.assertLess(len(rx), len(pkts))
Neale Rannsd91c1db2017-07-31 02:30:50 -07002554
2555 #
Paul Vinciguerraeb414432019-02-20 09:01:14 -08002556 # remove the policer. back to full rx
Neale Rannsd91c1db2017-07-31 02:30:50 -07002557 #
Jakub Grajciar2df2f752020-12-01 11:23:44 +01002558 ip_punt_policer.remove_vpp_config()
Jakub Grajciarcd01fb42020-03-02 13:16:53 +01002559 policer.remove_vpp_config()
Neale Rannsd91c1db2017-07-31 02:30:50 -07002560 self.send_and_expect(self.pg0, pkts, self.pg1)
2561
2562 #
2563 # remove the redirect. expect full drop.
2564 #
Jakub Grajciar2df2f752020-12-01 11:23:44 +01002565 ip_punt_redirect.remove_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002566 self.send_and_assert_no_replies(self.pg0, pkts, "IP no punt config")
Neale Rannsd91c1db2017-07-31 02:30:50 -07002567
2568 #
2569 # Add a redirect that is not input port selective
2570 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002571 ip_punt_redirect = VppIpPuntRedirect(
2572 self, 0xFFFFFFFF, self.pg1.sw_if_index, nh_addr
2573 )
Jakub Grajciar2df2f752020-12-01 11:23:44 +01002574 ip_punt_redirect.add_vpp_config()
Neale Rannsd91c1db2017-07-31 02:30:50 -07002575 self.send_and_expect(self.pg0, pkts, self.pg1)
Jakub Grajciar2df2f752020-12-01 11:23:44 +01002576 ip_punt_redirect.remove_vpp_config()
Pavel Kotucek609e1212018-11-27 09:59:44 +01002577
2578 def test_ip_punt_dump(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002579 """IP6 punt redirect dump"""
Pavel Kotucek609e1212018-11-27 09:59:44 +01002580
2581 #
2582 # Configure a punt redirects
2583 #
Jakub Grajciar2df2f752020-12-01 11:23:44 +01002584 nh_address = self.pg3.remote_ip6
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002585 ipr_03 = VppIpPuntRedirect(
2586 self, self.pg0.sw_if_index, self.pg3.sw_if_index, nh_address
2587 )
2588 ipr_13 = VppIpPuntRedirect(
2589 self, self.pg1.sw_if_index, self.pg3.sw_if_index, nh_address
2590 )
2591 ipr_23 = VppIpPuntRedirect(
2592 self, self.pg2.sw_if_index, self.pg3.sw_if_index, "0::0"
2593 )
Jakub Grajciar2df2f752020-12-01 11:23:44 +01002594 ipr_03.add_vpp_config()
2595 ipr_13.add_vpp_config()
2596 ipr_23.add_vpp_config()
Pavel Kotucek609e1212018-11-27 09:59:44 +01002597
2598 #
2599 # Dump pg0 punt redirects
2600 #
Jakub Grajciar2df2f752020-12-01 11:23:44 +01002601 self.assertTrue(ipr_03.query_vpp_config())
2602 self.assertTrue(ipr_13.query_vpp_config())
2603 self.assertTrue(ipr_23.query_vpp_config())
Pavel Kotucek609e1212018-11-27 09:59:44 +01002604
2605 #
2606 # Dump punt redirects for all interfaces
2607 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002608 punts = self.vapi.ip_punt_redirect_dump(0xFFFFFFFF, is_ipv6=1)
Pavel Kotucek609e1212018-11-27 09:59:44 +01002609 self.assertEqual(len(punts), 3)
2610 for p in punts:
2611 self.assertEqual(p.punt.tx_sw_if_index, self.pg3.sw_if_index)
Ole Troan0bcad322018-12-11 13:04:01 +01002612 self.assertNotEqual(punts[1].punt.nh, self.pg3.remote_ip6)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002613 self.assertEqual(str(punts[2].punt.nh), "::")
Neale Rannsd91c1db2017-07-31 02:30:50 -07002614
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002615
Brian Russell5214f3a2021-01-19 16:58:34 +00002616class TestIP6PuntHandoff(IP6PuntSetup, VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002617 """IPv6 Punt Police/Redirect"""
2618
Klement Sekera8d815022021-03-15 16:58:10 +01002619 vpp_worker_count = 2
Brian Russell5214f3a2021-01-19 16:58:34 +00002620
2621 def setUp(self):
2622 super(TestIP6PuntHandoff, self).setUp()
2623 super(TestIP6PuntHandoff, self).punt_setup()
2624
2625 def tearDown(self):
2626 super(TestIP6PuntHandoff, self).punt_teardown()
2627 super(TestIP6PuntHandoff, self).tearDown()
2628
2629 def test_ip_punt(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002630 """IP6 punt policer thread handoff"""
Brian Russell5214f3a2021-01-19 16:58:34 +00002631 pkts = self.pkt * NUM_PKTS
2632
2633 #
2634 # Configure a punt redirect via pg1.
2635 #
2636 nh_addr = self.pg1.remote_ip6
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002637 ip_punt_redirect = VppIpPuntRedirect(
2638 self, self.pg0.sw_if_index, self.pg1.sw_if_index, nh_addr
2639 )
Brian Russell5214f3a2021-01-19 16:58:34 +00002640 ip_punt_redirect.add_vpp_config()
2641
2642 action_tx = PolicerAction(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002643 VppEnum.vl_api_sse2_qos_action_type_t.SSE2_QOS_ACTION_API_TRANSMIT, 0
2644 )
Brian Russell5214f3a2021-01-19 16:58:34 +00002645 #
2646 # This policer drops no packets, we are just
2647 # testing that they get to the right thread.
2648 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002649 policer = VppPolicer(
2650 self,
2651 "ip6-punt",
2652 400,
2653 0,
2654 10,
2655 0,
2656 1,
2657 0,
2658 0,
2659 False,
2660 action_tx,
2661 action_tx,
2662 action_tx,
2663 )
Brian Russell5214f3a2021-01-19 16:58:34 +00002664 policer.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002665 ip_punt_policer = VppIpPuntPolicer(self, policer.policer_index, is_ip6=True)
Brian Russell5214f3a2021-01-19 16:58:34 +00002666 ip_punt_policer.add_vpp_config()
2667
2668 for worker in [0, 1]:
2669 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
2670 if worker == 0:
2671 self.logger.debug(self.vapi.cli("show trace max 100"))
2672
Brian Russelle9887262021-01-27 14:45:22 +00002673 # Combined stats, all threads
2674 stats = policer.get_stats()
2675
2676 # Single rate policer - expect conform, violate but no exceed
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002677 self.assertGreater(stats["conform_packets"], 0)
2678 self.assertEqual(stats["exceed_packets"], 0)
2679 self.assertGreater(stats["violate_packets"], 0)
Brian Russelle9887262021-01-27 14:45:22 +00002680
2681 # Worker 0, should have done all the policing
2682 stats0 = policer.get_stats(worker=0)
2683 self.assertEqual(stats, stats0)
2684
2685 # Worker 1, should have handed everything off
2686 stats1 = policer.get_stats(worker=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002687 self.assertEqual(stats1["conform_packets"], 0)
2688 self.assertEqual(stats1["exceed_packets"], 0)
2689 self.assertEqual(stats1["violate_packets"], 0)
Brian Russelle9887262021-01-27 14:45:22 +00002690
Brian Russellbb983142021-02-10 13:56:06 +00002691 # Bind the policer to worker 1 and repeat
2692 policer.bind_vpp_config(1, True)
2693 for worker in [0, 1]:
2694 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
2695 self.logger.debug(self.vapi.cli("show trace max 100"))
2696
2697 # The 2 workers should now have policed the same amount
2698 stats = policer.get_stats()
2699 stats0 = policer.get_stats(worker=0)
2700 stats1 = policer.get_stats(worker=1)
2701
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002702 self.assertGreater(stats0["conform_packets"], 0)
2703 self.assertEqual(stats0["exceed_packets"], 0)
2704 self.assertGreater(stats0["violate_packets"], 0)
Brian Russellbb983142021-02-10 13:56:06 +00002705
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002706 self.assertGreater(stats1["conform_packets"], 0)
2707 self.assertEqual(stats1["exceed_packets"], 0)
2708 self.assertGreater(stats1["violate_packets"], 0)
Brian Russellbb983142021-02-10 13:56:06 +00002709
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002710 self.assertEqual(
2711 stats0["conform_packets"] + stats1["conform_packets"],
2712 stats["conform_packets"],
2713 )
Brian Russellbb983142021-02-10 13:56:06 +00002714
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002715 self.assertEqual(
2716 stats0["violate_packets"] + stats1["violate_packets"],
2717 stats["violate_packets"],
2718 )
Brian Russellbb983142021-02-10 13:56:06 +00002719
2720 # Unbind the policer and repeat
2721 policer.bind_vpp_config(1, False)
2722 for worker in [0, 1]:
2723 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
2724 self.logger.debug(self.vapi.cli("show trace max 100"))
2725
2726 # The policer should auto-bind to worker 0 when packets arrive
2727 stats = policer.get_stats()
2728 stats0new = policer.get_stats(worker=0)
2729 stats1new = policer.get_stats(worker=1)
2730
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002731 self.assertGreater(stats0new["conform_packets"], stats0["conform_packets"])
2732 self.assertEqual(stats0new["exceed_packets"], 0)
2733 self.assertGreater(stats0new["violate_packets"], stats0["violate_packets"])
Brian Russellbb983142021-02-10 13:56:06 +00002734
2735 self.assertEqual(stats1, stats1new)
2736
Brian Russell5214f3a2021-01-19 16:58:34 +00002737 #
2738 # Clean up
2739 #
2740 ip_punt_policer.remove_vpp_config()
2741 policer.remove_vpp_config()
2742 ip_punt_redirect.remove_vpp_config()
2743
2744
Tianyu Li6d95f8c2022-02-25 05:51:10 +00002745class TestIP6Deag(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002746 """IPv6 Deaggregate Routes"""
Neale Rannsce9e0b42018-08-01 12:53:17 -07002747
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002748 @classmethod
2749 def setUpClass(cls):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00002750 super(TestIP6Deag, cls).setUpClass()
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002751
2752 @classmethod
2753 def tearDownClass(cls):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00002754 super(TestIP6Deag, cls).tearDownClass()
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002755
Neale Rannsce9e0b42018-08-01 12:53:17 -07002756 def setUp(self):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00002757 super(TestIP6Deag, self).setUp()
Neale Rannsce9e0b42018-08-01 12:53:17 -07002758
2759 self.create_pg_interfaces(range(3))
2760
2761 for i in self.pg_interfaces:
2762 i.admin_up()
2763 i.config_ip6()
2764 i.resolve_ndp()
2765
2766 def tearDown(self):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00002767 super(TestIP6Deag, self).tearDown()
Neale Rannsce9e0b42018-08-01 12:53:17 -07002768 for i in self.pg_interfaces:
2769 i.unconfig_ip6()
2770 i.admin_down()
2771
2772 def test_ip_deag(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002773 """IP Deag Routes"""
Neale Rannsce9e0b42018-08-01 12:53:17 -07002774
2775 #
2776 # Create a table to be used for:
2777 # 1 - another destination address lookup
2778 # 2 - a source address lookup
2779 #
2780 table_dst = VppIpTable(self, 1, is_ip6=1)
2781 table_src = VppIpTable(self, 2, is_ip6=1)
2782 table_dst.add_vpp_config()
2783 table_src.add_vpp_config()
2784
2785 #
2786 # Add a route in the default table to point to a deag/
2787 # second lookup in each of these tables
2788 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002789 route_to_dst = VppIpRoute(
2790 self, "1::1", 128, [VppRoutePath("::", 0xFFFFFFFF, nh_table_id=1)]
2791 )
Neale Ranns097fa662018-05-01 05:17:55 -07002792 route_to_src = VppIpRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002793 self,
2794 "1::2",
2795 128,
2796 [
2797 VppRoutePath(
2798 "::",
2799 0xFFFFFFFF,
2800 nh_table_id=2,
2801 type=FibPathType.FIB_PATH_TYPE_SOURCE_LOOKUP,
2802 )
2803 ],
2804 )
Neale Ranns097fa662018-05-01 05:17:55 -07002805
Neale Rannsce9e0b42018-08-01 12:53:17 -07002806 route_to_dst.add_vpp_config()
2807 route_to_src.add_vpp_config()
2808
2809 #
2810 # packets to these destination are dropped, since they'll
2811 # hit the respective default routes in the second table
2812 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002813 p_dst = (
2814 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2815 / IPv6(src="5::5", dst="1::1")
2816 / inet6.TCP(sport=1234, dport=1234)
2817 / Raw(b"\xa5" * 100)
2818 )
2819 p_src = (
2820 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2821 / IPv6(src="2::2", dst="1::2")
2822 / inet6.TCP(sport=1234, dport=1234)
2823 / Raw(b"\xa5" * 100)
2824 )
Neale Rannsce9e0b42018-08-01 12:53:17 -07002825 pkts_dst = p_dst * 257
2826 pkts_src = p_src * 257
2827
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002828 self.send_and_assert_no_replies(self.pg0, pkts_dst, "IP in dst table")
2829 self.send_and_assert_no_replies(self.pg0, pkts_src, "IP in src table")
Neale Rannsce9e0b42018-08-01 12:53:17 -07002830
2831 #
2832 # add a route in the dst table to forward via pg1
2833 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002834 route_in_dst = VppIpRoute(
2835 self,
2836 "1::1",
2837 128,
2838 [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)],
2839 table_id=1,
2840 )
Neale Rannsce9e0b42018-08-01 12:53:17 -07002841 route_in_dst.add_vpp_config()
2842
2843 self.send_and_expect(self.pg0, pkts_dst, self.pg1)
2844
2845 #
2846 # add a route in the src table to forward via pg2
2847 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002848 route_in_src = VppIpRoute(
2849 self,
2850 "2::2",
2851 128,
2852 [VppRoutePath(self.pg2.remote_ip6, self.pg2.sw_if_index)],
2853 table_id=2,
2854 )
Neale Rannsce9e0b42018-08-01 12:53:17 -07002855 route_in_src.add_vpp_config()
2856 self.send_and_expect(self.pg0, pkts_src, self.pg2)
2857
2858 #
2859 # loop in the lookup DP
2860 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002861 route_loop = VppIpRoute(self, "3::3", 128, [VppRoutePath("::", 0xFFFFFFFF)])
Neale Rannsce9e0b42018-08-01 12:53:17 -07002862 route_loop.add_vpp_config()
2863
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002864 p_l = (
2865 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2866 / IPv6(src="3::4", dst="3::3")
2867 / inet6.TCP(sport=1234, dport=1234)
2868 / Raw(b"\xa5" * 100)
2869 )
Neale Rannsce9e0b42018-08-01 12:53:17 -07002870
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002871 self.send_and_assert_no_replies(self.pg0, p_l * 257, "IP lookup loop")
Neale Rannsce9e0b42018-08-01 12:53:17 -07002872
2873
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002874class TestIP6Input(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002875 """IPv6 Input Exception Test Cases"""
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002876
Paul Vinciguerra7f9b7f92019-03-12 19:23:27 -07002877 @classmethod
2878 def setUpClass(cls):
2879 super(TestIP6Input, cls).setUpClass()
2880
2881 @classmethod
2882 def tearDownClass(cls):
2883 super(TestIP6Input, cls).tearDownClass()
2884
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002885 def setUp(self):
2886 super(TestIP6Input, self).setUp()
2887
2888 self.create_pg_interfaces(range(2))
2889
2890 for i in self.pg_interfaces:
2891 i.admin_up()
2892 i.config_ip6()
2893 i.resolve_ndp()
2894
2895 def tearDown(self):
2896 super(TestIP6Input, self).tearDown()
2897 for i in self.pg_interfaces:
2898 i.unconfig_ip6()
2899 i.admin_down()
2900
Neale Rannsae809832018-11-23 09:00:27 -08002901 def test_ip_input_icmp_reply(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002902 """IP6 Input Exception - Return ICMP (3,0)"""
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002903 #
Neale Rannsae809832018-11-23 09:00:27 -08002904 # hop limit - ICMP replies
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002905 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002906 p_version = (
2907 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2908 / IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6, hlim=1)
2909 / inet6.UDP(sport=1234, dport=1234)
2910 / Raw(b"\xa5" * 100)
2911 )
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002912
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002913 rxs = self.send_and_expect_some(self.pg0, p_version * NUM_PKTS, self.pg0)
Neale Rannsae809832018-11-23 09:00:27 -08002914
Neale Ranns5c6dd172022-02-17 09:08:47 +00002915 for rx in rxs:
2916 icmp = rx[ICMPv6TimeExceeded]
2917 # 0: "hop limit exceeded in transit",
2918 self.assertEqual((icmp.type, icmp.code), (3, 0))
Neale Rannsae809832018-11-23 09:00:27 -08002919
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002920 icmpv6_data = "\x0a" * 18
Neale Rannsae809832018-11-23 09:00:27 -08002921 all_0s = "::"
2922 all_1s = "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"
2923
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002924 @parameterized.expand(
2925 [
2926 # Name, src, dst, l4proto, msg, timeout
2927 (
2928 "src='iface', dst='iface'",
2929 None,
2930 None,
2931 inet6.UDP(sport=1234, dport=1234),
2932 "funky version",
2933 None,
2934 ),
2935 (
2936 "src='All 0's', dst='iface'",
2937 all_0s,
2938 None,
2939 ICMPv6EchoRequest(id=0xB, seq=5, data=icmpv6_data),
2940 None,
2941 0.1,
2942 ),
2943 (
2944 "src='iface', dst='All 0's'",
2945 None,
2946 all_0s,
2947 ICMPv6EchoRequest(id=0xB, seq=5, data=icmpv6_data),
2948 None,
2949 0.1,
2950 ),
2951 (
2952 "src='All 1's', dst='iface'",
2953 all_1s,
2954 None,
2955 ICMPv6EchoRequest(id=0xB, seq=5, data=icmpv6_data),
2956 None,
2957 0.1,
2958 ),
2959 (
2960 "src='iface', dst='All 1's'",
2961 None,
2962 all_1s,
2963 ICMPv6EchoRequest(id=0xB, seq=5, data=icmpv6_data),
2964 None,
2965 0.1,
2966 ),
2967 (
2968 "src='All 1's', dst='All 1's'",
2969 all_1s,
2970 all_1s,
2971 ICMPv6EchoRequest(id=0xB, seq=5, data=icmpv6_data),
2972 None,
2973 0.1,
2974 ),
2975 ]
2976 )
Neale Rannsae809832018-11-23 09:00:27 -08002977 def test_ip_input_no_replies(self, name, src, dst, l4, msg, timeout):
2978
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002979 self._testMethodDoc = "IPv6 Input Exception - %s" % name
Neale Rannsae809832018-11-23 09:00:27 -08002980
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002981 p_version = (
2982 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2983 / IPv6(
2984 src=src or self.pg0.remote_ip6,
2985 dst=dst or self.pg1.remote_ip6,
2986 version=3,
2987 )
2988 / l4
2989 / Raw(b"\xa5" * 100)
2990 )
Neale Rannsae809832018-11-23 09:00:27 -08002991
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002992 self.send_and_assert_no_replies(
2993 self.pg0, p_version * NUM_PKTS, remark=msg or "", timeout=timeout
2994 )
Neale Ranns4c7c8e52017-10-21 09:37:55 -07002995
Dave Barach90800962019-05-24 13:03:01 -04002996 def test_hop_by_hop(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002997 """Hop-by-hop header test"""
Dave Barach90800962019-05-24 13:03:01 -04002998
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02002999 p = (
3000 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3001 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
3002 / IPv6ExtHdrHopByHop()
3003 / inet6.UDP(sport=1234, dport=1234)
3004 / Raw(b"\xa5" * 100)
3005 )
Dave Barach90800962019-05-24 13:03:01 -04003006
3007 self.pg0.add_stream(p)
3008 self.pg_enable_capture(self.pg_interfaces)
3009 self.pg_start()
Neale Ranns4c7c8e52017-10-21 09:37:55 -07003010
Neale Ranns9db6ada2019-11-08 12:42:31 +00003011
Tianyu Li6d95f8c2022-02-25 05:51:10 +00003012class TestIP6Replace(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003013 """IPv6 Table Replace"""
Neale Ranns9db6ada2019-11-08 12:42:31 +00003014
3015 @classmethod
3016 def setUpClass(cls):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00003017 super(TestIP6Replace, cls).setUpClass()
Neale Ranns9db6ada2019-11-08 12:42:31 +00003018
3019 @classmethod
3020 def tearDownClass(cls):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00003021 super(TestIP6Replace, cls).tearDownClass()
Neale Ranns9db6ada2019-11-08 12:42:31 +00003022
3023 def setUp(self):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00003024 super(TestIP6Replace, self).setUp()
Neale Ranns9db6ada2019-11-08 12:42:31 +00003025
3026 self.create_pg_interfaces(range(4))
3027
3028 table_id = 1
3029 self.tables = []
3030
3031 for i in self.pg_interfaces:
3032 i.admin_up()
3033 i.config_ip6()
Neale Ranns9db6ada2019-11-08 12:42:31 +00003034 i.generate_remote_hosts(2)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003035 self.tables.append(VppIpTable(self, table_id, True).add_vpp_config())
Neale Ranns9db6ada2019-11-08 12:42:31 +00003036 table_id += 1
3037
3038 def tearDown(self):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00003039 super(TestIP6Replace, self).tearDown()
Neale Ranns9db6ada2019-11-08 12:42:31 +00003040 for i in self.pg_interfaces:
3041 i.admin_down()
Neale Rannsec40a7d2020-04-23 07:36:12 +00003042 i.unconfig_ip6()
Neale Ranns9db6ada2019-11-08 12:42:31 +00003043
3044 def test_replace(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003045 """IP Table Replace"""
Neale Ranns9db6ada2019-11-08 12:42:31 +00003046
Neale Ranns990f6942020-10-20 07:20:17 +00003047 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
3048 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
Neale Ranns9db6ada2019-11-08 12:42:31 +00003049 N_ROUTES = 20
3050 links = [self.pg0, self.pg1, self.pg2, self.pg3]
3051 routes = [[], [], [], []]
3052
3053 # the sizes of 'empty' tables
3054 for t in self.tables:
3055 self.assertEqual(len(t.dump()), 2)
3056 self.assertEqual(len(t.mdump()), 5)
3057
3058 # load up the tables with some routes
3059 for ii, t in enumerate(self.tables):
3060 for jj in range(1, N_ROUTES):
3061 uni = VppIpRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003062 self,
3063 "2001::%d" % jj if jj != 0 else "2001::",
3064 128,
3065 [
3066 VppRoutePath(
3067 links[ii].remote_hosts[0].ip6, links[ii].sw_if_index
3068 ),
3069 VppRoutePath(
3070 links[ii].remote_hosts[1].ip6, links[ii].sw_if_index
3071 ),
3072 ],
3073 table_id=t.table_id,
3074 ).add_vpp_config()
Neale Ranns9db6ada2019-11-08 12:42:31 +00003075 multi = VppIpMRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003076 self,
3077 "::",
3078 "ff:2001::%d" % jj,
3079 128,
Neale Ranns990f6942020-10-20 07:20:17 +00003080 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003081 [
3082 VppMRoutePath(
3083 self.pg0.sw_if_index,
3084 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT,
3085 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
3086 ),
3087 VppMRoutePath(
3088 self.pg1.sw_if_index,
3089 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
3090 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
3091 ),
3092 VppMRoutePath(
3093 self.pg2.sw_if_index,
3094 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
3095 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
3096 ),
3097 VppMRoutePath(
3098 self.pg3.sw_if_index,
3099 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
3100 proto=FibPathProto.FIB_PATH_NH_PROTO_IP6,
3101 ),
3102 ],
3103 table_id=t.table_id,
3104 ).add_vpp_config()
3105 routes[ii].append({"uni": uni, "multi": multi})
Neale Ranns9db6ada2019-11-08 12:42:31 +00003106
3107 #
3108 # replace the tables a few times
3109 #
3110 for kk in range(3):
3111 # replace each table
3112 for t in self.tables:
3113 t.replace_begin()
3114
3115 # all the routes are still there
3116 for ii, t in enumerate(self.tables):
3117 dump = t.dump()
3118 mdump = t.mdump()
3119 for r in routes[ii]:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003120 self.assertTrue(find_route_in_dump(dump, r["uni"], t))
3121 self.assertTrue(find_mroute_in_dump(mdump, r["multi"], t))
Neale Ranns9db6ada2019-11-08 12:42:31 +00003122
3123 # redownload the even numbered routes
3124 for ii, t in enumerate(self.tables):
3125 for jj in range(0, N_ROUTES, 2):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003126 routes[ii][jj]["uni"].add_vpp_config()
3127 routes[ii][jj]["multi"].add_vpp_config()
Neale Ranns9db6ada2019-11-08 12:42:31 +00003128
3129 # signal each table converged
3130 for t in self.tables:
3131 t.replace_end()
3132
3133 # we should find the even routes, but not the odd
3134 for ii, t in enumerate(self.tables):
3135 dump = t.dump()
3136 mdump = t.mdump()
3137 for jj in range(0, N_ROUTES, 2):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003138 self.assertTrue(find_route_in_dump(dump, routes[ii][jj]["uni"], t))
3139 self.assertTrue(
3140 find_mroute_in_dump(mdump, routes[ii][jj]["multi"], t)
3141 )
Neale Ranns9db6ada2019-11-08 12:42:31 +00003142 for jj in range(1, N_ROUTES - 1, 2):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003143 self.assertFalse(find_route_in_dump(dump, routes[ii][jj]["uni"], t))
3144 self.assertFalse(
3145 find_mroute_in_dump(mdump, routes[ii][jj]["multi"], t)
3146 )
Neale Ranns9db6ada2019-11-08 12:42:31 +00003147
3148 # reload all the routes
3149 for ii, t in enumerate(self.tables):
3150 for r in routes[ii]:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003151 r["uni"].add_vpp_config()
3152 r["multi"].add_vpp_config()
Neale Ranns9db6ada2019-11-08 12:42:31 +00003153
3154 # all the routes are still there
3155 for ii, t in enumerate(self.tables):
3156 dump = t.dump()
3157 mdump = t.mdump()
3158 for r in routes[ii]:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003159 self.assertTrue(find_route_in_dump(dump, r["uni"], t))
3160 self.assertTrue(find_mroute_in_dump(mdump, r["multi"], t))
Neale Ranns9db6ada2019-11-08 12:42:31 +00003161
3162 #
3163 # finally flush the tables for good measure
3164 #
3165 for t in self.tables:
3166 t.flush()
3167 self.assertEqual(len(t.dump()), 2)
3168 self.assertEqual(len(t.mdump()), 5)
3169
3170
Tianyu Li6d95f8c2022-02-25 05:51:10 +00003171class TestIP6AddrReplace(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003172 """IPv6 Interface Address Replace"""
Neale Ranns59f71132020-04-08 12:19:38 +00003173
3174 @classmethod
3175 def setUpClass(cls):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00003176 super(TestIP6AddrReplace, cls).setUpClass()
Neale Ranns59f71132020-04-08 12:19:38 +00003177
3178 @classmethod
3179 def tearDownClass(cls):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00003180 super(TestIP6AddrReplace, cls).tearDownClass()
Neale Ranns59f71132020-04-08 12:19:38 +00003181
3182 def setUp(self):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00003183 super(TestIP6AddrReplace, self).setUp()
Neale Ranns59f71132020-04-08 12:19:38 +00003184
3185 self.create_pg_interfaces(range(4))
3186
3187 for i in self.pg_interfaces:
3188 i.admin_up()
3189
3190 def tearDown(self):
Tianyu Li6d95f8c2022-02-25 05:51:10 +00003191 super(TestIP6AddrReplace, self).tearDown()
Neale Ranns59f71132020-04-08 12:19:38 +00003192 for i in self.pg_interfaces:
3193 i.admin_down()
3194
3195 def get_n_pfxs(self, intf):
3196 return len(self.vapi.ip_address_dump(intf.sw_if_index, True))
3197
3198 def test_replace(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003199 """IP interface address replace"""
Neale Ranns59f71132020-04-08 12:19:38 +00003200
3201 intf_pfxs = [[], [], [], []]
3202
3203 # add prefixes to each of the interfaces
3204 for i in range(len(self.pg_interfaces)):
3205 intf = self.pg_interfaces[i]
3206
3207 # 2001:16:x::1/64
3208 addr = "2001:16:%d::1" % intf.sw_if_index
3209 a = VppIpInterfaceAddress(self, intf, addr, 64).add_vpp_config()
3210 intf_pfxs[i].append(a)
3211
3212 # 2001:16:x::2/64 - a different address in the same subnet as above
3213 addr = "2001:16:%d::2" % intf.sw_if_index
3214 a = VppIpInterfaceAddress(self, intf, addr, 64).add_vpp_config()
3215 intf_pfxs[i].append(a)
3216
3217 # 2001:15:x::2/64 - a different address and subnet
3218 addr = "2001:15:%d::2" % intf.sw_if_index
3219 a = VppIpInterfaceAddress(self, intf, addr, 64).add_vpp_config()
3220 intf_pfxs[i].append(a)
3221
3222 # a dump should n_address in it
3223 for intf in self.pg_interfaces:
3224 self.assertEqual(self.get_n_pfxs(intf), 3)
3225
3226 #
3227 # remove all the address thru a replace
3228 #
3229 self.vapi.sw_interface_address_replace_begin()
3230 self.vapi.sw_interface_address_replace_end()
3231 for intf in self.pg_interfaces:
3232 self.assertEqual(self.get_n_pfxs(intf), 0)
3233
3234 #
3235 # add all the interface addresses back
3236 #
3237 for p in intf_pfxs:
3238 for v in p:
3239 v.add_vpp_config()
3240 for intf in self.pg_interfaces:
3241 self.assertEqual(self.get_n_pfxs(intf), 3)
3242
3243 #
3244 # replace again, but this time update/re-add the address on the first
3245 # two interfaces
3246 #
3247 self.vapi.sw_interface_address_replace_begin()
3248
3249 for p in intf_pfxs[:2]:
3250 for v in p:
3251 v.add_vpp_config()
3252
3253 self.vapi.sw_interface_address_replace_end()
3254
3255 # on the first two the address still exist,
3256 # on the other two they do not
3257 for intf in self.pg_interfaces[:2]:
3258 self.assertEqual(self.get_n_pfxs(intf), 3)
3259 for p in intf_pfxs[:2]:
3260 for v in p:
3261 self.assertTrue(v.query_vpp_config())
3262 for intf in self.pg_interfaces[2:]:
3263 self.assertEqual(self.get_n_pfxs(intf), 0)
3264
3265 #
3266 # add all the interface addresses back on the last two
3267 #
3268 for p in intf_pfxs[2:]:
3269 for v in p:
3270 v.add_vpp_config()
3271 for intf in self.pg_interfaces:
3272 self.assertEqual(self.get_n_pfxs(intf), 3)
3273
3274 #
3275 # replace again, this time add different prefixes on all the interfaces
3276 #
3277 self.vapi.sw_interface_address_replace_begin()
3278
3279 pfxs = []
3280 for intf in self.pg_interfaces:
3281 # 2001:18:x::1/64
3282 addr = "2001:18:%d::1" % intf.sw_if_index
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003283 pfxs.append(VppIpInterfaceAddress(self, intf, addr, 64).add_vpp_config())
Neale Ranns59f71132020-04-08 12:19:38 +00003284
3285 self.vapi.sw_interface_address_replace_end()
3286
3287 # only .18 should exist on each interface
3288 for intf in self.pg_interfaces:
3289 self.assertEqual(self.get_n_pfxs(intf), 1)
3290 for pfx in pfxs:
3291 self.assertTrue(pfx.query_vpp_config())
3292
3293 #
3294 # remove everything
3295 #
3296 self.vapi.sw_interface_address_replace_begin()
3297 self.vapi.sw_interface_address_replace_end()
3298 for intf in self.pg_interfaces:
3299 self.assertEqual(self.get_n_pfxs(intf), 0)
3300
3301 #
3302 # add prefixes to each interface. post-begin add the prefix from
3303 # interface X onto interface Y. this would normally be an error
3304 # since it would generate a 'duplicate address' warning. but in
3305 # this case, since what is newly downloaded is sane, it's ok
3306 #
3307 for intf in self.pg_interfaces:
3308 # 2001:18:x::1/64
3309 addr = "2001:18:%d::1" % intf.sw_if_index
3310 VppIpInterfaceAddress(self, intf, addr, 64).add_vpp_config()
3311
3312 self.vapi.sw_interface_address_replace_begin()
3313
3314 pfxs = []
3315 for intf in self.pg_interfaces:
3316 # 2001:18:x::1/64
3317 addr = "2001:18:%d::1" % (intf.sw_if_index + 1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003318 pfxs.append(VppIpInterfaceAddress(self, intf, addr, 64).add_vpp_config())
Neale Ranns59f71132020-04-08 12:19:38 +00003319
3320 self.vapi.sw_interface_address_replace_end()
3321
3322 self.logger.info(self.vapi.cli("sh int addr"))
3323
3324 for intf in self.pg_interfaces:
3325 self.assertEqual(self.get_n_pfxs(intf), 1)
3326 for pfx in pfxs:
3327 self.assertTrue(pfx.query_vpp_config())
3328
3329
Neale Rannsec40a7d2020-04-23 07:36:12 +00003330class TestIP6LinkLocal(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003331 """IPv6 Link Local"""
Neale Rannsec40a7d2020-04-23 07:36:12 +00003332
3333 @classmethod
3334 def setUpClass(cls):
3335 super(TestIP6LinkLocal, cls).setUpClass()
3336
3337 @classmethod
3338 def tearDownClass(cls):
3339 super(TestIP6LinkLocal, cls).tearDownClass()
3340
3341 def setUp(self):
3342 super(TestIP6LinkLocal, self).setUp()
3343
3344 self.create_pg_interfaces(range(2))
3345
3346 for i in self.pg_interfaces:
3347 i.admin_up()
3348
3349 def tearDown(self):
3350 super(TestIP6LinkLocal, self).tearDown()
3351 for i in self.pg_interfaces:
3352 i.admin_down()
3353
3354 def test_ip6_ll(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003355 """IPv6 Link Local"""
Neale Rannsec40a7d2020-04-23 07:36:12 +00003356
3357 #
3358 # two APIs to add a link local address.
3359 # 1 - just like any other prefix
3360 # 2 - with the special set LL API
3361 #
3362
3363 #
3364 # First with the API to set a 'normal' prefix
3365 #
3366 ll1 = "fe80:1::1"
3367 ll2 = "fe80:2::2"
3368 ll3 = "fe80:3::3"
3369
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003370 VppNeighbor(
3371 self, self.pg0.sw_if_index, self.pg0.remote_mac, ll2
3372 ).add_vpp_config()
Neale Rannsdfef64b2021-05-20 16:28:12 +00003373
Neale Rannsec40a7d2020-04-23 07:36:12 +00003374 VppIpInterfaceAddress(self, self.pg0, ll1, 128).add_vpp_config()
3375
3376 #
3377 # should be able to ping the ll
3378 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003379 p_echo_request_1 = (
3380 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3381 / IPv6(src=ll2, dst=ll1)
3382 / ICMPv6EchoRequest()
3383 )
Neale Rannsec40a7d2020-04-23 07:36:12 +00003384
3385 self.send_and_expect(self.pg0, [p_echo_request_1], self.pg0)
3386
3387 #
3388 # change the link-local on pg0
3389 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003390 v_ll3 = VppIpInterfaceAddress(self, self.pg0, ll3, 128).add_vpp_config()
Neale Rannsec40a7d2020-04-23 07:36:12 +00003391
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003392 p_echo_request_3 = (
3393 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3394 / IPv6(src=ll2, dst=ll3)
3395 / ICMPv6EchoRequest()
3396 )
Neale Rannsec40a7d2020-04-23 07:36:12 +00003397
3398 self.send_and_expect(self.pg0, [p_echo_request_3], self.pg0)
3399
3400 #
3401 # set a normal v6 prefix on the link
3402 #
3403 self.pg0.config_ip6()
3404
3405 self.send_and_expect(self.pg0, [p_echo_request_3], self.pg0)
3406
3407 # the link-local cannot be removed
3408 with self.vapi.assert_negative_api_retval():
3409 v_ll3.remove_vpp_config()
3410
3411 #
3412 # Use the specific link-local API on pg1
3413 #
3414 VppIp6LinkLocalAddress(self, self.pg1, ll1).add_vpp_config()
3415 self.send_and_expect(self.pg1, [p_echo_request_1], self.pg1)
3416
3417 VppIp6LinkLocalAddress(self, self.pg1, ll3).add_vpp_config()
3418 self.send_and_expect(self.pg1, [p_echo_request_3], self.pg1)
3419
Neale Rannsdfef64b2021-05-20 16:28:12 +00003420 def test_ip6_ll_p2p(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003421 """IPv6 Link Local P2P (GRE)"""
Neale Rannsdfef64b2021-05-20 16:28:12 +00003422
3423 self.pg0.config_ip4()
3424 self.pg0.resolve_arp()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003425 gre_if = VppGreInterface(
3426 self, self.pg0.local_ip4, self.pg0.remote_ip4
3427 ).add_vpp_config()
Neale Rannsdfef64b2021-05-20 16:28:12 +00003428 gre_if.admin_up()
3429
3430 ll1 = "fe80:1::1"
3431 ll2 = "fe80:2::2"
3432
3433 VppIpInterfaceAddress(self, gre_if, ll1, 128).add_vpp_config()
3434
3435 self.logger.info(self.vapi.cli("sh ip6-ll gre0 fe80:2::2"))
3436
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003437 p_echo_request_1 = (
3438 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3439 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
3440 / GRE()
3441 / IPv6(src=ll2, dst=ll1)
3442 / ICMPv6EchoRequest()
3443 )
Neale Rannsdfef64b2021-05-20 16:28:12 +00003444 self.send_and_expect(self.pg0, [p_echo_request_1], self.pg0)
3445
3446 self.pg0.unconfig_ip4()
3447 gre_if.remove_vpp_config()
3448
3449 def test_ip6_ll_p2mp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003450 """IPv6 Link Local P2MP (GRE)"""
Neale Rannsdfef64b2021-05-20 16:28:12 +00003451
3452 self.pg0.config_ip4()
3453 self.pg0.resolve_arp()
3454
3455 gre_if = VppGreInterface(
3456 self,
3457 self.pg0.local_ip4,
3458 "0.0.0.0",
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003459 mode=(VppEnum.vl_api_tunnel_mode_t.TUNNEL_API_MODE_MP),
3460 ).add_vpp_config()
Neale Rannsdfef64b2021-05-20 16:28:12 +00003461 gre_if.admin_up()
3462
3463 ll1 = "fe80:1::1"
3464 ll2 = "fe80:2::2"
3465
3466 VppIpInterfaceAddress(self, gre_if, ll1, 128).add_vpp_config()
3467
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003468 p_echo_request_1 = (
3469 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3470 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
3471 / GRE()
3472 / IPv6(src=ll2, dst=ll1)
3473 / ICMPv6EchoRequest()
3474 )
Neale Rannsdfef64b2021-05-20 16:28:12 +00003475
3476 # no route back at this point
3477 self.send_and_assert_no_replies(self.pg0, [p_echo_request_1])
3478
3479 # add teib entry for the peer
3480 teib = VppTeib(self, gre_if, ll2, self.pg0.remote_ip4)
3481 teib.add_vpp_config()
3482
3483 self.logger.info(self.vapi.cli("sh ip6-ll gre0 %s" % ll2))
3484 self.send_and_expect(self.pg0, [p_echo_request_1], self.pg0)
3485
3486 # teardown
3487 self.pg0.unconfig_ip4()
3488
Neale Rannsec40a7d2020-04-23 07:36:12 +00003489
Neale Ranns8f5fef22020-12-21 08:29:34 +00003490class TestIPv6PathMTU(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003491 """IPv6 Path MTU"""
Neale Ranns8f5fef22020-12-21 08:29:34 +00003492
3493 def setUp(self):
3494 super(TestIPv6PathMTU, self).setUp()
3495
3496 self.create_pg_interfaces(range(2))
3497
3498 # setup all interfaces
3499 for i in self.pg_interfaces:
3500 i.admin_up()
3501 i.config_ip6()
3502 i.resolve_ndp()
3503
3504 def tearDown(self):
3505 super(TestIPv6PathMTU, self).tearDown()
3506 for i in self.pg_interfaces:
3507 i.unconfig_ip6()
3508 i.admin_down()
3509
3510 def test_path_mtu_local(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003511 """Path MTU for attached neighbour"""
Neale Ranns8f5fef22020-12-21 08:29:34 +00003512
3513 self.vapi.cli("set log class ip level debug")
3514 #
3515 # The goal here is not test that fragmentation works correctly,
3516 # that's done elsewhere, the intent is to ensure that the Path MTU
3517 # settings are honoured.
3518 #
3519
3520 #
3521 # IPv6 will only frag locally generated packets, so use tunnelled
3522 # packets post encap
3523 #
3524 tun = VppIpIpTunInterface(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003525 self, self.pg1, self.pg1.local_ip6, self.pg1.remote_ip6
3526 )
Neale Ranns8f5fef22020-12-21 08:29:34 +00003527 tun.add_vpp_config()
3528 tun.admin_up()
3529 tun.config_ip6()
3530
3531 # set the interface MTU to a reasonable value
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003532 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2800, 0, 0, 0])
Neale Ranns8f5fef22020-12-21 08:29:34 +00003533
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003534 p_6k = (
3535 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3536 / IPv6(src=self.pg0.remote_ip6, dst=tun.remote_ip6)
3537 / UDP(sport=1234, dport=5678)
3538 / Raw(b"0xa" * 2000)
3539 )
3540 p_2k = (
3541 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3542 / IPv6(src=self.pg0.remote_ip6, dst=tun.remote_ip6)
3543 / UDP(sport=1234, dport=5678)
3544 / Raw(b"0xa" * 1000)
3545 )
3546 p_1k = (
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" * 600)
3551 )
Neale Ranns8f5fef22020-12-21 08:29:34 +00003552
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003553 nbr = VppNeighbor(
3554 self, self.pg1.sw_if_index, self.pg1.remote_mac, self.pg1.remote_ip6
3555 ).add_vpp_config()
Neale Ranns8f5fef22020-12-21 08:29:34 +00003556
3557 # this is now the interface MTU frags
Neale Rannsec5371e2022-03-04 11:45:41 +00003558 self.send_and_expect(self.pg0, [p_6k], self.pg1, n_rx=4)
Neale Ranns8f5fef22020-12-21 08:29:34 +00003559 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3560 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3561
3562 # drop the path MTU for this neighbour to below the interface MTU
3563 # expect more frags
3564 pmtu = VppIpPathMtu(self, self.pg1.remote_ip6, 1300).add_vpp_config()
3565
3566 # print/format the adj delegate and trackers
3567 self.logger.info(self.vapi.cli("sh ip pmtu"))
3568 self.logger.info(self.vapi.cli("sh adj 7"))
3569
3570 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3571 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3572
3573 # increase the path MTU to more than the interface
3574 # expect to use the interface MTU
3575 pmtu.modify(8192)
3576
3577 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3578 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3579
3580 # go back to an MTU from the path
3581 pmtu.modify(1300)
3582
3583 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3584 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3585
3586 # raise the interface's MTU
3587 # should still use that of the path
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003588 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2000, 0, 0, 0])
Neale Ranns8f5fef22020-12-21 08:29:34 +00003589 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3590 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3591
3592 # set path high and interface low
3593 pmtu.modify(2000)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003594 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1300, 0, 0, 0])
Neale Ranns8f5fef22020-12-21 08:29:34 +00003595 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 # remove the path MTU
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003599 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2800, 0, 0, 0])
Neale Ranns8f5fef22020-12-21 08:29:34 +00003600 pmtu.modify(0)
3601
3602 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3603 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3604
3605 def test_path_mtu_remote(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003606 """Path MTU for remote neighbour"""
Neale Ranns8f5fef22020-12-21 08:29:34 +00003607
3608 self.vapi.cli("set log class ip level debug")
3609 #
3610 # The goal here is not test that fragmentation works correctly,
3611 # that's done elsewhere, the intent is to ensure that the Path MTU
3612 # settings are honoured.
3613 #
3614 tun_dst = "2001::1"
3615
3616 route = VppIpRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003617 self, tun_dst, 64, [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)]
3618 ).add_vpp_config()
Neale Ranns8f5fef22020-12-21 08:29:34 +00003619
3620 #
3621 # IPv6 will only frag locally generated packets, so use tunnelled
3622 # packets post encap
3623 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003624 tun = VppIpIpTunInterface(self, self.pg1, self.pg1.local_ip6, tun_dst)
Neale Ranns8f5fef22020-12-21 08:29:34 +00003625 tun.add_vpp_config()
3626 tun.admin_up()
3627 tun.config_ip6()
3628
3629 # set the interface MTU to a reasonable value
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003630 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2800, 0, 0, 0])
Neale Ranns8f5fef22020-12-21 08:29:34 +00003631
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003632 p_2k = (
3633 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3634 / IPv6(src=self.pg0.remote_ip6, dst=tun.remote_ip6)
3635 / UDP(sport=1234, dport=5678)
3636 / Raw(b"0xa" * 1000)
3637 )
3638 p_1k = (
3639 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3640 / IPv6(src=self.pg0.remote_ip6, dst=tun.remote_ip6)
3641 / UDP(sport=1234, dport=5678)
3642 / Raw(b"0xa" * 600)
3643 )
Neale Ranns8f5fef22020-12-21 08:29:34 +00003644
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003645 nbr = VppNeighbor(
3646 self, self.pg1.sw_if_index, self.pg1.remote_mac, self.pg1.remote_ip6
3647 ).add_vpp_config()
Neale Ranns8f5fef22020-12-21 08:29:34 +00003648
3649 # this is now the interface MTU frags
3650 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3651 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3652
3653 # drop the path MTU for this neighbour to below the interface MTU
3654 # expect more frags
3655 pmtu = VppIpPathMtu(self, tun_dst, 1300).add_vpp_config()
3656
3657 # print/format the fib entry/dpo
3658 self.logger.info(self.vapi.cli("sh ip6 fib 2001::1"))
3659
3660 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3661 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3662
3663 # increase the path MTU to more than the interface
3664 # expect to use the interface MTU
3665 pmtu.modify(8192)
3666
3667 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3668 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3669
3670 # go back to an MTU from the path
3671 pmtu.modify(1300)
3672
3673 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3674 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3675
3676 # raise the interface's MTU
3677 # should still use that of the path
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003678 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2000, 0, 0, 0])
Neale Ranns8f5fef22020-12-21 08:29:34 +00003679 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3680 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3681
3682 # turn the tun_dst into an attached neighbour
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003683 route.modify([VppRoutePath("::", self.pg1.sw_if_index)])
3684 nbr2 = VppNeighbor(
3685 self, self.pg1.sw_if_index, self.pg1.remote_mac, tun_dst
3686 ).add_vpp_config()
Neale Ranns8f5fef22020-12-21 08:29:34 +00003687
3688 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3689 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3690
3691 # add back to not attached
3692 nbr2.remove_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003693 route.modify([VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)])
Neale Ranns8f5fef22020-12-21 08:29:34 +00003694
3695 # set path high and interface low
3696 pmtu.modify(2000)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003697 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1300, 0, 0, 0])
Neale Ranns8f5fef22020-12-21 08:29:34 +00003698 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3699 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3700
3701 # remove the path MTU
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003702 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2800, 0, 0, 0])
Neale Ranns8f5fef22020-12-21 08:29:34 +00003703 pmtu.remove_vpp_config()
3704 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3705 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3706
3707
Neale Ranns976b2592019-12-04 06:11:00 +00003708class TestIPFibSource(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003709 """IPv6 Table FibSource"""
Neale Ranns976b2592019-12-04 06:11:00 +00003710
3711 @classmethod
3712 def setUpClass(cls):
3713 super(TestIPFibSource, cls).setUpClass()
3714
3715 @classmethod
3716 def tearDownClass(cls):
3717 super(TestIPFibSource, cls).tearDownClass()
3718
3719 def setUp(self):
3720 super(TestIPFibSource, self).setUp()
3721
3722 self.create_pg_interfaces(range(2))
3723
3724 for i in self.pg_interfaces:
3725 i.admin_up()
3726 i.config_ip6()
3727 i.resolve_arp()
3728 i.generate_remote_hosts(2)
3729 i.configure_ipv6_neighbors()
3730
3731 def tearDown(self):
3732 super(TestIPFibSource, self).tearDown()
3733 for i in self.pg_interfaces:
3734 i.admin_down()
3735 i.unconfig_ip4()
3736
3737 def test_fib_source(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003738 """IP Table FibSource"""
Neale Ranns976b2592019-12-04 06:11:00 +00003739
3740 routes = self.vapi.ip_route_v2_dump(0, True)
3741
3742 # 2 interfaces (4 routes) + 2 specials + 4 neighbours = 10 routes
3743 self.assertEqual(len(routes), 10)
3744
3745 # dump all the sources in the FIB
3746 sources = self.vapi.fib_source_dump()
3747 for source in sources:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003748 if source.src.name == "API":
Neale Ranns976b2592019-12-04 06:11:00 +00003749 api_source = source.src
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003750 if source.src.name == "interface":
Neale Ranns976b2592019-12-04 06:11:00 +00003751 intf_source = source.src
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003752 if source.src.name == "adjacency":
Neale Ranns976b2592019-12-04 06:11:00 +00003753 adj_source = source.src
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003754 if source.src.name == "special":
Neale Ranns976b2592019-12-04 06:11:00 +00003755 special_source = source.src
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003756 if source.src.name == "default-route":
Neale Ranns976b2592019-12-04 06:11:00 +00003757 dr_source = source.src
3758
3759 # dump the individual route types
3760 routes = self.vapi.ip_route_v2_dump(0, True, src=adj_source.id)
3761 self.assertEqual(len(routes), 4)
3762 routes = self.vapi.ip_route_v2_dump(0, True, src=intf_source.id)
3763 self.assertEqual(len(routes), 4)
3764 routes = self.vapi.ip_route_v2_dump(0, True, src=special_source.id)
3765 self.assertEqual(len(routes), 1)
3766 routes = self.vapi.ip_route_v2_dump(0, True, src=dr_source.id)
3767 self.assertEqual(len(routes), 1)
3768
3769 # add a new soure that'a better than the API
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003770 self.vapi.fib_source_add(
3771 src={"name": "bgp", "priority": api_source.priority - 1}
3772 )
Neale Ranns976b2592019-12-04 06:11:00 +00003773
3774 # dump all the sources to check our new one is there
3775 sources = self.vapi.fib_source_dump()
3776
3777 for source in sources:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003778 if source.src.name == "bgp":
Neale Ranns976b2592019-12-04 06:11:00 +00003779 bgp_source = source.src
3780
3781 self.assertTrue(bgp_source)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003782 self.assertEqual(bgp_source.priority, api_source.priority - 1)
Neale Ranns976b2592019-12-04 06:11:00 +00003783
3784 # add a route with the default API source
3785 r1 = VppIpRouteV2(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003786 self,
3787 "2001::1",
3788 128,
3789 [VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index)],
3790 ).add_vpp_config()
Neale Ranns976b2592019-12-04 06:11:00 +00003791
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003792 r2 = VppIpRouteV2(
3793 self,
3794 "2001::1",
3795 128,
3796 [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)],
3797 src=bgp_source.id,
3798 ).add_vpp_config()
Neale Ranns976b2592019-12-04 06:11:00 +00003799
3800 # ensure the BGP source takes priority
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003801 p = (
3802 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3803 / IPv6(src=self.pg0.remote_ip6, dst="2001::1")
3804 / inet6.UDP(sport=1234, dport=1234)
3805 / Raw(b"\xa5" * 100)
3806 )
Neale Ranns976b2592019-12-04 06:11:00 +00003807
3808 self.send_and_expect(self.pg0, [p], self.pg1)
3809
3810 r2.remove_vpp_config()
3811 r1.remove_vpp_config()
3812
3813 self.assertFalse(find_route(self, "2001::1", 128))
3814
3815
Neale Ranns91adf242021-05-27 12:18:52 +00003816class TestIPxAF(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003817 """IP cross AF"""
Neale Ranns91adf242021-05-27 12:18:52 +00003818
3819 @classmethod
3820 def setUpClass(cls):
3821 super(TestIPxAF, cls).setUpClass()
3822
3823 @classmethod
3824 def tearDownClass(cls):
3825 super(TestIPxAF, cls).tearDownClass()
3826
3827 def setUp(self):
3828 super(TestIPxAF, self).setUp()
3829
3830 self.create_pg_interfaces(range(2))
3831
3832 for i in self.pg_interfaces:
3833 i.admin_up()
3834 i.config_ip6()
3835 i.config_ip4()
3836 i.resolve_arp()
3837 i.resolve_ndp()
3838
3839 def tearDown(self):
3840 super(TestIPxAF, self).tearDown()
3841 for i in self.pg_interfaces:
3842 i.admin_down()
3843 i.unconfig_ip4()
3844 i.unconfig_ip6()
3845
3846 def test_x_af(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003847 """Cross AF routing"""
Neale Ranns91adf242021-05-27 12:18:52 +00003848
3849 N_PKTS = 63
3850 # a v4 route via a v6 attached next-hop
3851 VppIpRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003852 self,
3853 "1.1.1.1",
3854 32,
3855 [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index)],
3856 ).add_vpp_config()
Neale Ranns91adf242021-05-27 12:18:52 +00003857
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003858 p = (
3859 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3860 / IP(src=self.pg0.remote_ip4, dst="1.1.1.1")
3861 / UDP(sport=1234, dport=1234)
3862 / Raw(b"\xa5" * 100)
3863 )
Neale Ranns91adf242021-05-27 12:18:52 +00003864 rxs = self.send_and_expect(self.pg0, p * N_PKTS, self.pg1)
3865
3866 for rx in rxs:
3867 self.assertEqual(rx[IP].dst, "1.1.1.1")
3868
3869 # a v6 route via a v4 attached next-hop
3870 VppIpRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003871 self,
3872 "2001::1",
3873 128,
3874 [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
3875 ).add_vpp_config()
Neale Ranns91adf242021-05-27 12:18:52 +00003876
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003877 p = (
3878 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3879 / IPv6(src=self.pg0.remote_ip6, dst="2001::1")
3880 / UDP(sport=1234, dport=1234)
3881 / Raw(b"\xa5" * 100)
3882 )
Neale Ranns91adf242021-05-27 12:18:52 +00003883 rxs = self.send_and_expect(self.pg0, p * N_PKTS, self.pg1)
3884
3885 for rx in rxs:
3886 self.assertEqual(rx[IPv6].dst, "2001::1")
3887
3888 # a recursive v4 route via a v6 next-hop (from above)
3889 VppIpRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003890 self, "2.2.2.2", 32, [VppRoutePath("2001::1", 0xFFFFFFFF)]
3891 ).add_vpp_config()
Neale Ranns91adf242021-05-27 12:18:52 +00003892
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003893 p = (
3894 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3895 / IP(src=self.pg0.remote_ip4, dst="2.2.2.2")
3896 / UDP(sport=1234, dport=1234)
3897 / Raw(b"\xa5" * 100)
3898 )
Neale Ranns91adf242021-05-27 12:18:52 +00003899 rxs = self.send_and_expect(self.pg0, p * N_PKTS, self.pg1)
3900
3901 # a recursive v4 route via a v6 next-hop
3902 VppIpRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003903 self, "2.2.2.3", 32, [VppRoutePath(self.pg1.remote_ip6, 0xFFFFFFFF)]
3904 ).add_vpp_config()
Neale Ranns91adf242021-05-27 12:18:52 +00003905
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003906 p = (
3907 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3908 / IP(src=self.pg0.remote_ip4, dst="2.2.2.3")
3909 / UDP(sport=1234, dport=1234)
3910 / Raw(b"\xa5" * 100)
3911 )
Neale Ranns91adf242021-05-27 12:18:52 +00003912 rxs = self.send_and_expect(self.pg0, p * N_PKTS, self.pg1)
3913
3914 # a recursive v6 route via a v4 next-hop
3915 VppIpRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003916 self, "3001::1", 128, [VppRoutePath(self.pg1.remote_ip4, 0xFFFFFFFF)]
3917 ).add_vpp_config()
Neale Ranns91adf242021-05-27 12:18:52 +00003918
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003919 p = (
3920 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3921 / IPv6(src=self.pg0.remote_ip6, dst="3001::1")
3922 / UDP(sport=1234, dport=1234)
3923 / Raw(b"\xa5" * 100)
3924 )
Neale Ranns91adf242021-05-27 12:18:52 +00003925 rxs = self.send_and_expect(self.pg0, p * N_PKTS, self.pg1)
3926
3927 for rx in rxs:
3928 self.assertEqual(rx[IPv6].dst, "3001::1")
3929
3930 VppIpRoute(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003931 self, "3001::2", 128, [VppRoutePath("1.1.1.1", 0xFFFFFFFF)]
3932 ).add_vpp_config()
Neale Ranns91adf242021-05-27 12:18:52 +00003933
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003934 p = (
3935 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3936 / IPv6(src=self.pg0.remote_ip6, dst="3001::2")
3937 / UDP(sport=1234, dport=1234)
3938 / Raw(b"\xa5" * 100)
3939 )
Neale Ranns91adf242021-05-27 12:18:52 +00003940 rxs = self.send_and_expect(self.pg0, p * N_PKTS, self.pg1)
3941
3942 for rx in rxs:
3943 self.assertEqual(rx[IPv6].dst, "3001::2")
3944
3945
Benoît Ganne7c7b5052021-10-04 12:03:20 +02003946class TestIPv6Punt(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003947 """IPv6 Punt Police/Redirect"""
Benoît Ganne7c7b5052021-10-04 12:03:20 +02003948
3949 def setUp(self):
3950 super(TestIPv6Punt, self).setUp()
3951 self.create_pg_interfaces(range(4))
3952
3953 for i in self.pg_interfaces:
3954 i.admin_up()
3955 i.config_ip6()
3956 i.resolve_ndp()
3957
3958 def tearDown(self):
3959 super(TestIPv6Punt, self).tearDown()
3960 for i in self.pg_interfaces:
3961 i.unconfig_ip6()
3962 i.admin_down()
3963
3964 def test_ip6_punt(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003965 """IPv6 punt police and redirect"""
Benoît Ganne7c7b5052021-10-04 12:03:20 +02003966
3967 # use UDP packet that have a port we need to explicitly
3968 # register to get punted.
3969 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
3970 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
3971 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
3972 punt_udp = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003973 "type": pt_l4,
3974 "punt": {
3975 "l4": {
3976 "af": af_ip6,
3977 "protocol": udp_proto,
3978 "port": 7654,
Benoît Ganne7c7b5052021-10-04 12:03:20 +02003979 }
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003980 },
Benoît Ganne7c7b5052021-10-04 12:03:20 +02003981 }
3982
3983 self.vapi.set_punt(is_add=1, punt=punt_udp)
3984
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003985 pkts = (
3986 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
3987 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
3988 / UDP(sport=1234, dport=7654)
3989 / Raw(b"\xa5" * 100)
3990 ) * 1025
Benoît Ganne7c7b5052021-10-04 12:03:20 +02003991
3992 #
3993 # Configure a punt redirect via pg1.
3994 #
3995 nh_addr = self.pg1.remote_ip6
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02003996 ip_punt_redirect = VppIpPuntRedirect(
3997 self, self.pg0.sw_if_index, self.pg1.sw_if_index, nh_addr
3998 )
Benoît Ganne7c7b5052021-10-04 12:03:20 +02003999 ip_punt_redirect.add_vpp_config()
4000
4001 self.send_and_expect(self.pg0, pkts, self.pg1)
4002
4003 #
4004 # add a policer
4005 #
4006 policer = VppPolicer(self, "ip6-punt", 400, 0, 10, 0, rate_type=1)
4007 policer.add_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02004008 ip_punt_policer = VppIpPuntPolicer(self, policer.policer_index, is_ip6=True)
Benoît Ganne7c7b5052021-10-04 12:03:20 +02004009 ip_punt_policer.add_vpp_config()
4010
4011 self.vapi.cli("clear trace")
4012 self.pg0.add_stream(pkts)
4013 self.pg_enable_capture(self.pg_interfaces)
4014 self.pg_start()
4015
4016 #
4017 # the number of packet received should be greater than 0,
4018 # but not equal to the number sent, since some were policed
4019 #
4020 rx = self.pg1._get_capture(1)
4021
4022 stats = policer.get_stats()
4023
4024 # Single rate policer - expect conform, violate but no exceed
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02004025 self.assertGreater(stats["conform_packets"], 0)
4026 self.assertEqual(stats["exceed_packets"], 0)
4027 self.assertGreater(stats["violate_packets"], 0)
Benoît Ganne7c7b5052021-10-04 12:03:20 +02004028
4029 self.assertGreater(len(rx), 0)
4030 self.assertLess(len(rx), len(pkts))
4031
4032 #
4033 # remove the policer. back to full rx
4034 #
4035 ip_punt_policer.remove_vpp_config()
4036 policer.remove_vpp_config()
4037 self.send_and_expect(self.pg0, pkts, self.pg1)
4038
4039 #
4040 # remove the redirect. expect full drop.
4041 #
4042 ip_punt_redirect.remove_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02004043 self.send_and_assert_no_replies(self.pg0, pkts, "IP no punt config")
Benoît Ganne7c7b5052021-10-04 12:03:20 +02004044
4045 #
4046 # Add a redirect that is not input port selective
4047 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02004048 ip_punt_redirect = VppIpPuntRedirect(
4049 self, 0xFFFFFFFF, self.pg1.sw_if_index, nh_addr
4050 )
Benoît Ganne7c7b5052021-10-04 12:03:20 +02004051 ip_punt_redirect.add_vpp_config()
4052 self.send_and_expect(self.pg0, pkts, self.pg1)
4053 ip_punt_redirect.remove_vpp_config()
4054
4055 def test_ip6_punt_dump(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02004056 """IPv6 punt redirect dump"""
Benoît Ganne7c7b5052021-10-04 12:03:20 +02004057
4058 #
4059 # Configure a punt redirects
4060 #
4061 nh_address = self.pg3.remote_ip6
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02004062 ipr_03 = VppIpPuntRedirect(
4063 self, self.pg0.sw_if_index, self.pg3.sw_if_index, nh_address
4064 )
4065 ipr_13 = VppIpPuntRedirect(
4066 self, self.pg1.sw_if_index, self.pg3.sw_if_index, nh_address
4067 )
4068 ipr_23 = VppIpPuntRedirect(
4069 self, self.pg2.sw_if_index, self.pg3.sw_if_index, "::"
4070 )
Benoît Ganne7c7b5052021-10-04 12:03:20 +02004071 ipr_03.add_vpp_config()
4072 ipr_13.add_vpp_config()
4073 ipr_23.add_vpp_config()
4074
4075 #
4076 # Dump pg0 punt redirects
4077 #
4078 self.assertTrue(ipr_03.query_vpp_config())
4079 self.assertTrue(ipr_13.query_vpp_config())
4080 self.assertTrue(ipr_23.query_vpp_config())
4081
4082 #
4083 # Dump punt redirects for all interfaces
4084 #
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02004085 punts = self.vapi.ip_punt_redirect_dump(sw_if_index=0xFFFFFFFF, is_ipv6=True)
Benoît Ganne7c7b5052021-10-04 12:03:20 +02004086 self.assertEqual(len(punts), 3)
4087 for p in punts:
4088 self.assertEqual(p.punt.tx_sw_if_index, self.pg3.sw_if_index)
4089 self.assertNotEqual(punts[1].punt.nh, self.pg3.remote_ip6)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02004090 self.assertEqual(str(punts[2].punt.nh), "::")
Benoît Ganne7c7b5052021-10-04 12:03:20 +02004091
4092
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02004093if __name__ == "__main__":
Klement Sekeraf62ae122016-10-11 11:47:09 +02004094 unittest.main(testRunner=VppTestRunner)