blob: 41b8268e6bc5ef14c9a45f9c3b46cf971ca5f3d1 [file] [log] [blame]
Matthew Smith39e94282020-02-11 11:25:32 -06001#!/usr/bin/env python3
2
3#
4# Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
5#
6# SPDX-License-Identifier: Apache-2.0
7#
8
9import unittest
10import time
Paul Vinciguerra582eac52020-04-03 12:18:40 -040011import socket
12from socket import inet_pton, inet_ntop
Matthew Smith39e94282020-02-11 11:25:32 -060013
14from vpp_object import VppObject
Matthew Smith39e94282020-02-11 11:25:32 -060015
Paul Vinciguerra582eac52020-04-03 12:18:40 -040016from scapy.packet import raw
Matthew Smith39e94282020-02-11 11:25:32 -060017from scapy.layers.l2 import Ether, ARP
18from scapy.layers.inet import IP, ICMP, icmptypes
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020019from scapy.layers.inet6 import (
20 IPv6,
21 ipv6nh,
22 IPv6ExtHdrHopByHop,
23 ICMPv6MLReport2,
24 ICMPv6ND_NA,
25 ICMPv6ND_NS,
26 ICMPv6NDOptDstLLAddr,
27 ICMPv6NDOptSrcLLAddr,
28 ICMPv6EchoRequest,
29 ICMPv6EchoReply,
30)
Dave Wallace8800f732023-08-31 00:47:44 -040031from scapy.contrib.igmpv3 import IGMPv3, IGMPv3mr
Matthew Smith39e94282020-02-11 11:25:32 -060032from scapy.layers.vrrp import IPPROTO_VRRP, VRRPv3
33from scapy.utils6 import in6_getnsma, in6_getnsmac
Klement Sekerab23ffd72021-05-31 16:08:53 +020034from config import config
Dave Wallace8800f732023-08-31 00:47:44 -040035from framework import VppTestCase
36from asfframework import VppTestRunner
Matthew Smith39e94282020-02-11 11:25:32 -060037from util import ip6_normalize
38
39VRRP_VR_FLAG_PREEMPT = 1
40VRRP_VR_FLAG_ACCEPT = 2
41VRRP_VR_FLAG_UNICAST = 4
42VRRP_VR_FLAG_IPV6 = 8
43
44VRRP_VR_STATE_INIT = 0
45VRRP_VR_STATE_BACKUP = 1
46VRRP_VR_STATE_MASTER = 2
47VRRP_VR_STATE_INTF_DOWN = 3
48
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020049VRRP_INDEX_INVALID = 0xFFFFFFFF
Emanuele Di Pascale7539e4b2022-03-29 12:29:23 +020050
Matthew Smith39e94282020-02-11 11:25:32 -060051
52def is_non_arp(p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020053 """Want to filter out advertisements, igmp, etc"""
Matthew Smith39e94282020-02-11 11:25:32 -060054 if p.haslayer(ARP):
55 return False
56
57 return True
58
59
60def is_not_adv(p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020061 """Filter out everything but advertisements. E.g. multicast RD/ND"""
Matthew Smith39e94282020-02-11 11:25:32 -060062 if p.haslayer(VRRPv3):
63 return False
64
65 return True
66
67
68def is_not_echo_reply(p):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020069 """filter out advertisements and other while waiting for echo reply"""
Matthew Smith39e94282020-02-11 11:25:32 -060070 if p.haslayer(IP) and p.haslayer(ICMP):
71 if icmptypes[p[ICMP].type] == "echo-reply":
72 return False
73 elif p.haslayer(IPv6) and p.haslayer(ICMPv6EchoReply):
74 return False
75
76 return True
77
78
79class VppVRRPVirtualRouter(VppObject):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020080 def __init__(
81 self,
82 test,
83 intf,
84 vr_id,
85 prio=100,
86 intvl=100,
87 flags=VRRP_VR_FLAG_PREEMPT,
88 vips=None,
89 ):
Matthew Smith39e94282020-02-11 11:25:32 -060090 self._test = test
91 self._intf = intf
92 self._sw_if_index = self._intf.sw_if_index
93 self._vr_id = vr_id
94 self._prio = prio
95 self._intvl = intvl
96 self._flags = flags
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020097 if flags & VRRP_VR_FLAG_IPV6:
Matthew Smith39e94282020-02-11 11:25:32 -060098 self._is_ipv6 = 1
99 self._adv_dest_mac = "33:33:00:00:00:12"
100 self._virtual_mac = "00:00:5e:00:02:%02x" % vr_id
101 self._adv_dest_ip = "ff02::12"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200102 self._vips = [intf.local_ip6] if vips is None else vips
Matthew Smith39e94282020-02-11 11:25:32 -0600103 else:
104 self._is_ipv6 = 0
105 self._adv_dest_mac = "01:00:5e:00:00:12"
106 self._virtual_mac = "00:00:5e:00:01:%02x" % vr_id
107 self._adv_dest_ip = "224.0.0.18"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200108 self._vips = [intf.local_ip4] if vips is None else vips
Matthew Smith39e94282020-02-11 11:25:32 -0600109 self._tracked_ifs = []
Emanuele Di Pascale7539e4b2022-03-29 12:29:23 +0200110 self._vrrp_index = VRRP_INDEX_INVALID
Matthew Smith39e94282020-02-11 11:25:32 -0600111
112 def add_vpp_config(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200113 self._test.vapi.vrrp_vr_add_del(
114 is_add=1,
115 sw_if_index=self._intf.sw_if_index,
116 vr_id=self._vr_id,
117 priority=self._prio,
118 interval=self._intvl,
119 flags=self._flags,
120 n_addrs=len(self._vips),
121 addrs=self._vips,
122 )
Matthew Smith39e94282020-02-11 11:25:32 -0600123
Emanuele Di Pascale7539e4b2022-03-29 12:29:23 +0200124 def update_vpp_config(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200125 r = self._test.vapi.vrrp_vr_update(
126 vrrp_index=self._vrrp_index,
127 sw_if_index=self._intf.sw_if_index,
128 vr_id=self._vr_id,
129 priority=self._prio,
130 interval=self._intvl,
131 flags=self._flags,
132 n_addrs=len(self._vips),
133 addrs=self._vips,
134 )
Emanuele Di Pascale7539e4b2022-03-29 12:29:23 +0200135 self._vrrp_index = r.vrrp_index
136
137 def delete_vpp_config(self):
138 self._test.vapi.vrrp_vr_del(vrrp_index=self._vrrp_index)
139
Matthew Smith39e94282020-02-11 11:25:32 -0600140 def query_vpp_config(self):
141 vrs = self._test.vapi.vrrp_vr_dump(sw_if_index=self._intf.sw_if_index)
142 for vr in vrs:
143 if vr.config.vr_id != self._vr_id:
144 continue
145
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200146 is_ipv6 = 1 if (vr.config.flags & VRRP_VR_FLAG_IPV6) else 0
Matthew Smith39e94282020-02-11 11:25:32 -0600147 if is_ipv6 != self._is_ipv6:
148 continue
149
150 return vr
151
152 return None
153
154 def remove_vpp_config(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200155 self._test.vapi.vrrp_vr_add_del(
156 is_add=0,
157 sw_if_index=self._intf.sw_if_index,
158 vr_id=self._vr_id,
159 priority=self._prio,
160 interval=self._intvl,
161 flags=self._flags,
162 n_addrs=len(self._vips),
163 addrs=self._vips,
164 )
Matthew Smith39e94282020-02-11 11:25:32 -0600165
166 def start_stop(self, is_start):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200167 self._test.vapi.vrrp_vr_start_stop(
168 is_start=is_start,
169 sw_if_index=self._intf.sw_if_index,
170 vr_id=self._vr_id,
171 is_ipv6=self._is_ipv6,
172 )
173 self._start_time = time.time() if is_start else None
Matthew Smith39e94282020-02-11 11:25:32 -0600174
175 def add_del_tracked_interface(self, is_add, sw_if_index, prio):
176 args = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200177 "sw_if_index": self._intf.sw_if_index,
178 "is_ipv6": self._is_ipv6,
179 "vr_id": self._vr_id,
180 "is_add": is_add,
181 "n_ifs": 1,
182 "ifs": [{"sw_if_index": sw_if_index, "priority": prio}],
Matthew Smith39e94282020-02-11 11:25:32 -0600183 }
184 self._test.vapi.vrrp_vr_track_if_add_del(**args)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200185 self._tracked_ifs.append(args["ifs"][0])
Matthew Smith39e94282020-02-11 11:25:32 -0600186
187 def set_unicast_peers(self, addrs):
188 args = {
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200189 "sw_if_index": self._intf.sw_if_index,
190 "is_ipv6": self._is_ipv6,
191 "vr_id": self._vr_id,
192 "n_addrs": len(addrs),
193 "addrs": addrs,
Matthew Smith39e94282020-02-11 11:25:32 -0600194 }
195 self._test.vapi.vrrp_vr_set_peers(**args)
196 self._unicast_peers = addrs
197
Matthew Smith39e94282020-02-11 11:25:32 -0600198 def start_time(self):
199 return self._start_time
200
201 def virtual_mac(self):
202 return self._virtual_mac
203
204 def virtual_ips(self):
205 return self._vips
206
207 def adv_dest_mac(self):
208 return self._adv_dest_mac
209
210 def adv_dest_ip(self):
211 return self._adv_dest_ip
212
213 def priority(self):
214 return self._prio
215
216 def vr_id(self):
217 return self._vr_id
218
219 def adv_interval(self):
220 return self._intvl
221
222 def interface(self):
223 return self._intf
224
225 def assert_state_equals(self, state):
226 vr_details = self.query_vpp_config()
227 self._test.assertEqual(vr_details.runtime.state, state)
228
229 def master_down_seconds(self):
230 vr_details = self.query_vpp_config()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200231 return vr_details.runtime.master_down_int * 0.01
Matthew Smith39e94282020-02-11 11:25:32 -0600232
Paul Vinciguerraa5dd6d72021-04-15 11:37:44 -0400233 def vrrp_adv_packet(self, prio=None, src_ip=None):
234 dst_ip = self._adv_dest_ip
235 if prio is None:
236 prio = self._prio
237 eth = Ether(dst=self._adv_dest_mac, src=self._virtual_mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200238 vrrp = VRRPv3(
239 vrid=self._vr_id, priority=prio, ipcount=len(self._vips), adv=self._intvl
240 )
Paul Vinciguerraa5dd6d72021-04-15 11:37:44 -0400241 if self._is_ipv6:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200242 src_ip = self._intf.local_ip6_ll if src_ip is None else src_ip
Paul Vinciguerraa5dd6d72021-04-15 11:37:44 -0400243 ip = IPv6(src=src_ip, dst=dst_ip, nh=IPPROTO_VRRP, hlim=255)
244 vrrp.addrlist = self._vips
245 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200246 src_ip = self._intf.local_ip4 if src_ip is None else src_ip
Paul Vinciguerraa5dd6d72021-04-15 11:37:44 -0400247 ip = IP(src=src_ip, dst=dst_ip, proto=IPPROTO_VRRP, ttl=255, id=0)
248 vrrp.addrlist = self._vips
249
250 # Fill in default values & checksums
251 pkt = Ether(raw(eth / ip / vrrp))
252 return pkt
253
254
Dmitry Valter34fa0ce2024-03-11 10:38:46 +0000255@unittest.skipIf("vrrp" in config.excluded_plugins, "Exclude VRRP plugin tests")
Rajaselvam8cc66b52021-06-30 11:20:20 +0530256class TestVRRP4(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200257 """IPv4 VRRP Test Case"""
Matthew Smith39e94282020-02-11 11:25:32 -0600258
259 @classmethod
260 def setUpClass(cls):
261 super(TestVRRP4, cls).setUpClass()
262
263 @classmethod
264 def tearDownClass(cls):
265 super(TestVRRP4, cls).tearDownClass()
266
267 def setUp(self):
268 super(TestVRRP4, self).setUp()
269
270 self.create_pg_interfaces(range(2))
271
272 for i in self.pg_interfaces:
273 i.admin_up()
274 i.config_ip4()
275 i.generate_remote_hosts(5)
276 i.configure_ipv4_neighbors()
277
278 self._vrs = []
279 self._default_flags = VRRP_VR_FLAG_PREEMPT
280 self._default_adv = 100
281
282 def tearDown(self):
283 for vr in self._vrs:
284 try:
285 vr_api = vr.query_vpp_config()
286 if vr_api.runtime.state != VRRP_VR_STATE_INIT:
287 vr.start_stop(is_start=0)
288 vr.remove_vpp_config()
289 except:
290 self.logger.error("Error cleaning up")
291
292 for i in self.pg_interfaces:
293 i.admin_down()
294 i.unconfig_ip4()
295 i.unconfig_ip6()
296
297 self._vrs = []
298
299 super(TestVRRP4, self).tearDown()
300
301 def verify_vrrp4_igmp(self, pkt):
302 ip = pkt[IP]
303 self.assertEqual(ip.dst, "224.0.0.22")
304 self.assertEqual(ip.proto, 2)
305
306 igmp = pkt[IGMPv3]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200307 self.assertEqual(IGMPv3.igmpv3types[igmp.type], "Version 3 Membership Report")
Matthew Smith39e94282020-02-11 11:25:32 -0600308
309 igmpmr = pkt[IGMPv3mr]
310 self.assertEqual(igmpmr.numgrp, 1)
311 self.assertEqual(igmpmr.records[0].maddr, "224.0.0.18")
312
313 def verify_vrrp4_garp(self, pkt, vip, vmac):
314 arp = pkt[ARP]
315
316 # ARP "who-has" op == 1
317 self.assertEqual(arp.op, 1)
318 self.assertEqual(arp.pdst, arp.psrc)
319 self.assertEqual(arp.pdst, vip)
320 self.assertEqual(arp.hwsrc, vmac)
321
322 def verify_vrrp4_adv(self, rx_pkt, vr, prio=None):
323 vips = vr.virtual_ips()
324 eth = rx_pkt[Ether]
325 ip = rx_pkt[IP]
326 vrrp = rx_pkt[VRRPv3]
327
Rajaselvam8cc66b52021-06-30 11:20:20 +0530328 pkt = vr.vrrp_adv_packet(prio=prio)
Matthew Smith39e94282020-02-11 11:25:32 -0600329
330 # Source MAC is virtual MAC, destination is multicast MAC
331 self.assertEqual(eth.src, vr.virtual_mac())
332 self.assertEqual(eth.dst, vr.adv_dest_mac())
333
334 self.assertEqual(ip.dst, "224.0.0.18")
335 self.assertEqual(ip.ttl, 255)
336 self.assertEqual(ip.proto, IPPROTO_VRRP)
337
338 self.assertEqual(vrrp.version, 3)
339 self.assertEqual(vrrp.type, 1)
340 self.assertEqual(vrrp.vrid, vr.vr_id())
341 if prio is None:
342 prio = vr.priority()
343 self.assertEqual(vrrp.priority, prio)
344 self.assertEqual(vrrp.ipcount, len(vips))
345 self.assertEqual(vrrp.adv, vr.adv_interval())
346 self.assertListEqual(vrrp.addrlist, vips)
347
348 # VR with priority 255 owns the virtual address and should
349 # become master and start advertising immediately.
Alexander Chernavin65e770d2022-04-11 13:02:11 +0000350 @unittest.skipUnless(config.extended, "part of extended tests")
Matthew Smith39e94282020-02-11 11:25:32 -0600351 def test_vrrp4_master_adv(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200352 """IPv4 Master VR advertises"""
Matthew Smith39e94282020-02-11 11:25:32 -0600353 self.pg_enable_capture(self.pg_interfaces)
354 self.pg_start()
355
356 prio = 255
357 intvl = self._default_adv
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200358 vr = VppVRRPVirtualRouter(
359 self, self.pg0, 100, prio=prio, intvl=intvl, flags=self._default_flags
360 )
Matthew Smith39e94282020-02-11 11:25:32 -0600361
362 vr.add_vpp_config()
363 vr.start_stop(is_start=1)
364 self.logger.info(self.vapi.cli("show vrrp vr"))
365 vr.start_stop(is_start=0)
366 self.logger.info(self.vapi.cli("show vrrp vr"))
367
368 pkts = self.pg0.get_capture(4)
369
370 # Init -> Master: IGMP Join, VRRP adv, gratuitous ARP are sent
371 self.verify_vrrp4_igmp(pkts[0])
372 self.verify_vrrp4_adv(pkts[1], vr, prio=prio)
373 self.verify_vrrp4_garp(pkts[2], vr.virtual_ips()[0], vr.virtual_mac())
374 # Master -> Init: Adv with priority 0 sent to force an election
375 self.verify_vrrp4_adv(pkts[3], vr, prio=0)
376
377 vr.remove_vpp_config()
378 self._vrs = []
379
Emanuele Di Pascale7539e4b2022-03-29 12:29:23 +0200380 # Same as above but with the update API, and add a change
381 # of parameters to test that too
Alexander Chernavin65e770d2022-04-11 13:02:11 +0000382 @unittest.skipUnless(config.extended, "part of extended tests")
Emanuele Di Pascale7539e4b2022-03-29 12:29:23 +0200383 def test_vrrp4_master_adv_update(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200384 """IPv4 Master VR adv + Update to Backup"""
Emanuele Di Pascale7539e4b2022-03-29 12:29:23 +0200385 self.pg_enable_capture(self.pg_interfaces)
386 self.pg_start()
387
388 prio = 255
389 intvl = self._default_adv
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200390 vr = VppVRRPVirtualRouter(
391 self, self.pg0, 100, prio=prio, intvl=intvl, flags=self._default_flags
392 )
Emanuele Di Pascale7539e4b2022-03-29 12:29:23 +0200393
394 vr.update_vpp_config()
395 vr.start_stop(is_start=1)
396 self.logger.info(self.vapi.cli("show vrrp vr"))
397 # Update VR with lower prio and larger interval
398 # we need to keep old VR for the adv checks
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200399 upd_vr = VppVRRPVirtualRouter(
400 self,
401 self.pg0,
402 100,
403 prio=100,
404 intvl=2 * intvl,
405 flags=self._default_flags,
406 vips=[self.pg0.remote_ip4],
407 )
Emanuele Di Pascale7539e4b2022-03-29 12:29:23 +0200408 upd_vr._vrrp_index = vr._vrrp_index
409 upd_vr.update_vpp_config()
410 start_time = time.time()
411 self.logger.info(self.vapi.cli("show vrrp vr"))
412 upd_vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
413 self._vrs = [upd_vr]
414
415 pkts = self.pg0.get_capture(5)
416 # Init -> Master: IGMP Join, VRRP adv, gratuitous ARP are sent
417 self.verify_vrrp4_igmp(pkts[0])
418 self.verify_vrrp4_adv(pkts[1], vr, prio=prio)
419 self.verify_vrrp4_garp(pkts[2], vr.virtual_ips()[0], vr.virtual_mac())
420 # Master -> Init: Adv with priority 0 sent to force an election
421 self.verify_vrrp4_adv(pkts[3], vr, prio=0)
422 # Init -> Backup: An IGMP join should be sent
423 self.verify_vrrp4_igmp(pkts[4])
424
425 # send higher prio advertisements, should not receive any
426 end_time = start_time + 2 * upd_vr.master_down_seconds()
427 src_ip = self.pg0.remote_ip4
428 pkts = [upd_vr.vrrp_adv_packet(prio=110, src_ip=src_ip)]
429 while time.time() < end_time:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200430 self.send_and_assert_no_replies(self.pg0, pkts, timeout=intvl * 0.01)
Emanuele Di Pascale7539e4b2022-03-29 12:29:23 +0200431 self.logger.info(self.vapi.cli("show trace"))
432
433 upd_vr.start_stop(is_start=0)
434 self.logger.info(self.vapi.cli("show vrrp vr"))
435
Matthew Smith39e94282020-02-11 11:25:32 -0600436 # VR with priority < 255 enters backup state and does not advertise as
437 # long as it receives higher priority advertisements
Alexander Chernavin65e770d2022-04-11 13:02:11 +0000438 @unittest.skipUnless(config.extended, "part of extended tests")
Matthew Smith39e94282020-02-11 11:25:32 -0600439 def test_vrrp4_backup_noadv(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200440 """IPv4 Backup VR does not advertise"""
Matthew Smith39e94282020-02-11 11:25:32 -0600441 self.pg_enable_capture(self.pg_interfaces)
442 self.pg_start()
443
444 vr_id = 100
445 prio = 100
446 intvl = self._default_adv
447 intvl_s = intvl * 0.01
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200448 vr = VppVRRPVirtualRouter(
449 self,
450 self.pg0,
451 vr_id,
452 prio=prio,
453 intvl=intvl,
454 flags=self._default_flags,
455 vips=[self.pg0.remote_ip4],
456 )
Matthew Smith39e94282020-02-11 11:25:32 -0600457 self._vrs.append(vr)
458 vr.add_vpp_config()
459
460 vr.start_stop(is_start=1)
461
462 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
463 # watch for advertisements for 2x the master down preemption timeout
464 end_time = vr.start_time() + 2 * vr.master_down_seconds()
465
466 # Init -> Backup: An IGMP join should be sent
467 pkts = self.pg0.get_capture(1)
468 self.verify_vrrp4_igmp(pkts[0])
469
470 # send higher prio advertisements, should not receive any
471 src_ip = self.pg0.remote_ip4
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200472 pkts = [vr.vrrp_adv_packet(prio=prio + 10, src_ip=src_ip)]
Matthew Smith39e94282020-02-11 11:25:32 -0600473 while time.time() < end_time:
474 self.send_and_assert_no_replies(self.pg0, pkts, timeout=intvl_s)
475 self.logger.info(self.vapi.cli("show trace"))
476
477 vr.start_stop(is_start=0)
478 self.logger.info(self.vapi.cli("show vrrp vr"))
479 vr.remove_vpp_config()
480 self._vrs = []
481
482 def test_vrrp4_master_arp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200483 """IPv4 Master VR replies to ARP"""
Matthew Smith39e94282020-02-11 11:25:32 -0600484 self.pg_start()
485
486 # VR virtual IP is the default, which is the pg local IP
487 vr_id = 100
488 prio = 255
489 intvl = self._default_adv
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200490 vr = VppVRRPVirtualRouter(
491 self, self.pg0, 100, prio=prio, intvl=intvl, flags=self._default_flags
492 )
Matthew Smith39e94282020-02-11 11:25:32 -0600493 self._vrs.append(vr)
494
495 vr.add_vpp_config()
496
497 # before the VR is up, ARP should resolve to interface MAC
498 self.pg0.resolve_arp()
499 self.assertNotEqual(self.pg0.local_mac, vr.virtual_mac())
500
501 # start the VR, ARP should now resolve to virtual MAC
502 vr.start_stop(is_start=1)
503 self.pg0.resolve_arp()
504 self.assertEqual(self.pg0.local_mac, vr.virtual_mac())
505
506 # stop the VR, ARP should resolve to interface MAC again
507 vr.start_stop(is_start=0)
508 self.pg0.resolve_arp()
509 self.assertNotEqual(self.pg0.local_mac, vr.virtual_mac())
510
511 vr.remove_vpp_config()
512 self._vrs = []
513
Alexander Chernavin65e770d2022-04-11 13:02:11 +0000514 @unittest.skipUnless(config.extended, "part of extended tests")
Matthew Smith39e94282020-02-11 11:25:32 -0600515 def test_vrrp4_backup_noarp(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200516 """IPv4 Backup VR ignores ARP"""
Matthew Smith39e94282020-02-11 11:25:32 -0600517 # We need an address for a virtual IP that is not the IP that
518 # ARP requests will originate from
519
520 vr_id = 100
521 prio = 100
522 intvl = self._default_adv
523 vip = self.pg0.remote_hosts[1].ip4
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200524 vr = VppVRRPVirtualRouter(
525 self,
526 self.pg0,
527 vr_id,
528 prio=prio,
529 intvl=intvl,
530 flags=self._default_flags,
531 vips=[vip],
532 )
Matthew Smith39e94282020-02-11 11:25:32 -0600533 self._vrs.append(vr)
534 vr.add_vpp_config()
535
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200536 arp_req = Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(
537 op=ARP.who_has,
538 pdst=vip,
539 psrc=self.pg0.remote_ip4,
540 hwsrc=self.pg0.remote_mac,
541 )
Matthew Smith39e94282020-02-11 11:25:32 -0600542
543 # Before the VR is started make sure no reply to request for VIP
544 self.pg_start()
545 self.pg_enable_capture(self.pg_interfaces)
546 self.send_and_assert_no_replies(self.pg0, [arp_req], timeout=1)
547
548 # VR should start in backup state and still should not reply to ARP
549 # send a higher priority adv to make sure it does not become master
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200550 adv = vr.vrrp_adv_packet(prio=prio + 10, src_ip=self.pg0.remote_ip4)
Matthew Smith39e94282020-02-11 11:25:32 -0600551 vr.start_stop(is_start=1)
552 self.send_and_assert_no_replies(self.pg0, [adv, arp_req], timeout=1)
553
554 vr.start_stop(is_start=0)
555 vr.remove_vpp_config()
556 self._vrs = []
557
Alexander Chernavin65e770d2022-04-11 13:02:11 +0000558 @unittest.skipUnless(config.extended, "part of extended tests")
Matthew Smith39e94282020-02-11 11:25:32 -0600559 def test_vrrp4_election(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200560 """IPv4 Backup VR becomes master if no advertisements received"""
Matthew Smith39e94282020-02-11 11:25:32 -0600561
562 vr_id = 100
563 prio = 100
564 intvl = self._default_adv
565 intvl_s = intvl * 0.01
566 vip = self.pg0.remote_ip4
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200567 vr = VppVRRPVirtualRouter(
568 self,
569 self.pg0,
570 vr_id,
571 prio=prio,
572 intvl=intvl,
573 flags=self._default_flags,
574 vips=[vip],
575 )
Matthew Smith39e94282020-02-11 11:25:32 -0600576 self._vrs.append(vr)
577 vr.add_vpp_config()
578
579 # After adding the VR, it should be in the init state
580 vr.assert_state_equals(VRRP_VR_STATE_INIT)
581
582 self.pg_start()
583 vr.start_stop(is_start=1)
584
585 # VR should be in backup state after starting
586 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
587 end_time = vr.start_time() + vr.master_down_seconds()
588
589 # should not receive adverts until timer expires & state transition
590 self.pg_enable_capture(self.pg_interfaces)
591 while (time.time() + intvl_s) < end_time:
592 time.sleep(intvl_s)
593 self.pg0.assert_nothing_captured(filter_out_fn=is_not_adv)
594
595 # VR should be in master state, should send an adv
596 self.pg0.enable_capture()
597 self.pg0.wait_for_packet(intvl_s, is_not_adv)
598 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
599
Alexander Chernavin65e770d2022-04-11 13:02:11 +0000600 @unittest.skipUnless(config.extended, "part of extended tests")
Matthew Smith39e94282020-02-11 11:25:32 -0600601 def test_vrrp4_backup_preempts(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200602 """IPv4 Backup VR preempts lower priority master"""
Matthew Smith39e94282020-02-11 11:25:32 -0600603
604 vr_id = 100
605 prio = 100
606 intvl = self._default_adv
607 intvl_s = intvl * 0.01
608 vip = self.pg0.remote_ip4
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200609 vr = VppVRRPVirtualRouter(
610 self,
611 self.pg0,
612 vr_id,
613 prio=prio,
614 intvl=intvl,
615 flags=self._default_flags,
616 vips=[vip],
617 )
Matthew Smith39e94282020-02-11 11:25:32 -0600618 self._vrs.append(vr)
619 vr.add_vpp_config()
620
621 # After adding the VR, it should be in the init state
622 vr.assert_state_equals(VRRP_VR_STATE_INIT)
623
624 self.pg_start()
625 vr.start_stop(is_start=1)
626
627 # VR should be in backup state after starting
628 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
629 end_time = vr.start_time() + vr.master_down_seconds()
630
631 # send lower prio advertisements until timer expires
632 src_ip = self.pg0.remote_ip4
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200633 pkts = [vr.vrrp_adv_packet(prio=prio - 10, src_ip=src_ip)]
Matthew Smith39e94282020-02-11 11:25:32 -0600634 while time.time() + intvl_s < end_time:
635 self.send_and_assert_no_replies(self.pg0, pkts, timeout=intvl_s)
636 self.logger.info(self.vapi.cli("show trace"))
637
638 # when timer expires, VR should take over as master
639 self.pg0.enable_capture()
640 self.pg0.wait_for_packet(timeout=intvl_s, filter_out_fn=is_not_adv)
641 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
642
Alexander Chernavin65e770d2022-04-11 13:02:11 +0000643 @unittest.skipUnless(config.extended, "part of extended tests")
Matthew Smith39e94282020-02-11 11:25:32 -0600644 def test_vrrp4_master_preempted(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200645 """IPv4 Master VR preempted by higher priority backup"""
Matthew Smith39e94282020-02-11 11:25:32 -0600646
647 # A prio 255 VR cannot be preempted so the prio has to be lower and
648 # we have to wait for it to take over
649 vr_id = 100
650 prio = 100
651 intvl = self._default_adv
652 vip = self.pg0.remote_ip4
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200653 vr = VppVRRPVirtualRouter(
654 self,
655 self.pg0,
656 vr_id,
657 prio=prio,
658 intvl=intvl,
659 flags=self._default_flags,
660 vips=[vip],
661 )
Matthew Smith39e94282020-02-11 11:25:32 -0600662 self._vrs.append(vr)
663 vr.add_vpp_config()
664
665 # After adding the VR, it should be in the init state
666 vr.assert_state_equals(VRRP_VR_STATE_INIT)
667
668 # start VR
669 vr.start_stop(is_start=1)
670 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
671
672 # wait for VR to take over as master
673 end_time = vr.start_time() + vr.master_down_seconds()
674 sleep_s = end_time - time.time()
675 time.sleep(sleep_s)
676 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
677
678 # Build advertisement packet and send it
Rajaselvam8cc66b52021-06-30 11:20:20 +0530679 pkts = [vr.vrrp_adv_packet(prio=255, src_ip=self.pg0.remote_ip4)]
Matthew Smith39e94282020-02-11 11:25:32 -0600680 self.pg_send(self.pg0, pkts)
681
682 # VR should be in backup state again
683 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
684
Alexander Chernavin65e770d2022-04-11 13:02:11 +0000685 @unittest.skipUnless(config.extended, "part of extended tests")
Matthew Smith39e94282020-02-11 11:25:32 -0600686 def test_vrrp4_accept_mode_disabled(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200687 """IPv4 Master VR does not reply for VIP w/ accept mode off"""
Matthew Smith39e94282020-02-11 11:25:32 -0600688
689 # accept mode only matters when prio < 255, so it will have to
690 # come up as a backup and take over as master after the timeout
691 vr_id = 100
692 prio = 100
693 intvl = self._default_adv
694 vip = self.pg0.remote_hosts[4].ip4
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200695 vr = VppVRRPVirtualRouter(
696 self,
697 self.pg0,
698 vr_id,
699 prio=prio,
700 intvl=intvl,
701 flags=self._default_flags,
702 vips=[vip],
703 )
Matthew Smith39e94282020-02-11 11:25:32 -0600704 self._vrs.append(vr)
705 vr.add_vpp_config()
706
707 # After adding the VR, it should be in the init state
708 vr.assert_state_equals(VRRP_VR_STATE_INIT)
709
710 # start VR
711 vr.start_stop(is_start=1)
712 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
713
714 # wait for VR to take over as master
715 end_time = vr.start_time() + vr.master_down_seconds()
716 sleep_s = end_time - time.time()
717 time.sleep(sleep_s)
718 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
719
720 # send an ICMP echo to the VR virtual IP address
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200721 echo = (
722 Ether(dst=vr.virtual_mac(), src=self.pg0.remote_mac)
723 / IP(dst=vip, src=self.pg0.remote_ip4)
724 / ICMP(seq=1, id=self.pg0.sw_if_index, type="echo-request")
725 )
Matthew Smith39e94282020-02-11 11:25:32 -0600726 self.pg_send(self.pg0, [echo])
727
728 # wait for an echo reply. none should be received
729 time.sleep(1)
730 self.pg0.assert_nothing_captured(filter_out_fn=is_not_echo_reply)
731
Alexander Chernavin65e770d2022-04-11 13:02:11 +0000732 @unittest.skipUnless(config.extended, "part of extended tests")
Matthew Smith39e94282020-02-11 11:25:32 -0600733 def test_vrrp4_accept_mode_enabled(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200734 """IPv4 Master VR replies for VIP w/ accept mode on"""
Matthew Smith39e94282020-02-11 11:25:32 -0600735
736 # A prio 255 VR cannot be preempted so the prio has to be lower and
737 # we have to wait for it to take over
738 vr_id = 100
739 prio = 100
740 intvl = self._default_adv
741 vip = self.pg0.remote_hosts[4].ip4
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200742 flags = VRRP_VR_FLAG_PREEMPT | VRRP_VR_FLAG_ACCEPT
743 vr = VppVRRPVirtualRouter(
744 self, self.pg0, vr_id, prio=prio, intvl=intvl, flags=flags, vips=[vip]
745 )
Matthew Smith39e94282020-02-11 11:25:32 -0600746 self._vrs.append(vr)
747 vr.add_vpp_config()
748
749 # After adding the VR, it should be in the init state
750 vr.assert_state_equals(VRRP_VR_STATE_INIT)
751
752 # start VR
753 vr.start_stop(is_start=1)
754 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
755
756 # wait for VR to take over as master
757 end_time = vr.start_time() + vr.master_down_seconds()
758 sleep_s = end_time - time.time()
759 time.sleep(sleep_s)
760 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
761
762 # send an ICMP echo to the VR virtual IP address
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200763 echo = (
764 Ether(dst=vr.virtual_mac(), src=self.pg0.remote_mac)
765 / IP(dst=vip, src=self.pg0.remote_ip4)
766 / ICMP(seq=1, id=self.pg0.sw_if_index, type="echo-request")
767 )
Matthew Smith39e94282020-02-11 11:25:32 -0600768 self.pg_send(self.pg0, [echo])
769
770 # wait for an echo reply.
771 time.sleep(1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200772 rx_pkts = self.pg0.get_capture(
773 expected_count=1, timeout=1, filter_out_fn=is_not_echo_reply
774 )
Matthew Smith39e94282020-02-11 11:25:32 -0600775
776 self.assertEqual(rx_pkts[0][IP].src, vip)
777 self.assertEqual(rx_pkts[0][IP].dst, self.pg0.remote_ip4)
778 self.assertEqual(icmptypes[rx_pkts[0][ICMP].type], "echo-reply")
779 self.assertEqual(rx_pkts[0][ICMP].seq, 1)
780 self.assertEqual(rx_pkts[0][ICMP].id, self.pg0.sw_if_index)
781
Alexander Chernavin65e770d2022-04-11 13:02:11 +0000782 @unittest.skipUnless(config.extended, "part of extended tests")
Matthew Smith39e94282020-02-11 11:25:32 -0600783 def test_vrrp4_intf_tracking(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200784 """IPv4 Master VR adjusts priority based on tracked interface"""
Matthew Smith39e94282020-02-11 11:25:32 -0600785
786 vr_id = 100
787 prio = 255
788 intvl = self._default_adv
789 intvl_s = intvl * 0.01
790 vip = self.pg0.local_ip4
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200791 vr = VppVRRPVirtualRouter(
792 self,
793 self.pg0,
794 vr_id,
795 prio=prio,
796 intvl=intvl,
797 flags=self._default_flags,
798 vips=[vip],
799 )
Matthew Smith39e94282020-02-11 11:25:32 -0600800 self._vrs.append(vr)
801 vr.add_vpp_config()
802
803 # After adding the VR, it should be in the init state
804 vr.assert_state_equals(VRRP_VR_STATE_INIT)
805
806 # add pg1 as a tracked interface and start the VR
807 adjustment = 50
808 adjusted_prio = prio - adjustment
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200809 vr.add_del_tracked_interface(
810 is_add=1, sw_if_index=self.pg1.sw_if_index, prio=adjustment
811 )
Matthew Smith39e94282020-02-11 11:25:32 -0600812 vr.start_stop(is_start=1)
813 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
814
Rajaselvam8cc66b52021-06-30 11:20:20 +0530815 adv_configured = vr.vrrp_adv_packet(prio=prio)
816 adv_adjusted = vr.vrrp_adv_packet(prio=adjusted_prio)
Matthew Smith39e94282020-02-11 11:25:32 -0600817
818 # tracked intf is up -> advertised priority == configured priority
819 self.pg0.enable_capture()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200820 rx = self.pg0.wait_for_packet(timeout=intvl_s, filter_out_fn=is_not_adv)
Matthew Smith39e94282020-02-11 11:25:32 -0600821 self.assertEqual(rx, adv_configured)
822
823 # take down pg1, verify priority is now being adjusted
824 self.pg1.admin_down()
825 self.pg0.enable_capture()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200826 rx = self.pg0.wait_for_packet(timeout=intvl_s, filter_out_fn=is_not_adv)
Matthew Smith39e94282020-02-11 11:25:32 -0600827 self.assertEqual(rx, adv_adjusted)
828
829 # bring up pg1, verify priority now matches configured value
830 self.pg1.admin_up()
831 self.pg0.enable_capture()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200832 rx = self.pg0.wait_for_packet(timeout=intvl_s, filter_out_fn=is_not_adv)
Matthew Smith39e94282020-02-11 11:25:32 -0600833 self.assertEqual(rx, adv_configured)
834
835 # remove IP address from pg1, verify priority now being adjusted
836 self.pg1.unconfig_ip4()
837 self.pg0.enable_capture()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200838 rx = self.pg0.wait_for_packet(timeout=intvl_s, filter_out_fn=is_not_adv)
Matthew Smith39e94282020-02-11 11:25:32 -0600839 self.assertEqual(rx, adv_adjusted)
840
841 # add IP address to pg1, verify priority now matches configured value
842 self.pg1.config_ip4()
843 self.pg0.enable_capture()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200844 rx = self.pg0.wait_for_packet(timeout=intvl_s, filter_out_fn=is_not_adv)
Matthew Smith39e94282020-02-11 11:25:32 -0600845 self.assertEqual(rx, adv_configured)
846
Alexander Chernavin65e770d2022-04-11 13:02:11 +0000847 @unittest.skipUnless(config.extended, "part of extended tests")
Matthew Smith39e94282020-02-11 11:25:32 -0600848 def test_vrrp4_master_adv_unicast(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200849 """IPv4 Master VR advertises (unicast)"""
Matthew Smith39e94282020-02-11 11:25:32 -0600850
851 vr_id = 100
852 prio = 255
853 intvl = self._default_adv
854 intvl_s = intvl * 0.01
855 vip = self.pg0.local_ip4
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200856 flags = self._default_flags | VRRP_VR_FLAG_UNICAST
Matthew Smith39e94282020-02-11 11:25:32 -0600857 unicast_peer = self.pg0.remote_hosts[4]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200858 vr = VppVRRPVirtualRouter(
859 self, self.pg0, vr_id, prio=prio, intvl=intvl, flags=flags, vips=[vip]
860 )
Matthew Smith39e94282020-02-11 11:25:32 -0600861 self._vrs.append(vr)
862 vr.add_vpp_config()
863 vr.set_unicast_peers([unicast_peer.ip4])
864
865 # After adding the VR, it should be in the init state
866 vr.assert_state_equals(VRRP_VR_STATE_INIT)
867
868 # Start VR, transition to master
869 vr.start_stop(is_start=1)
870 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
871
872 self.pg0.enable_capture()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200873 rx = self.pg0.wait_for_packet(timeout=intvl_s, filter_out_fn=is_not_adv)
Matthew Smith39e94282020-02-11 11:25:32 -0600874
875 self.assertTrue(rx.haslayer(Ether))
876 self.assertTrue(rx.haslayer(IP))
877 self.assertTrue(rx.haslayer(VRRPv3))
878 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
879 self.assertEqual(rx[Ether].dst, unicast_peer.mac)
880 self.assertEqual(rx[IP].src, self.pg0.local_ip4)
881 self.assertEqual(rx[IP].dst, unicast_peer.ip4)
882 self.assertEqual(rx[VRRPv3].vrid, vr_id)
883 self.assertEqual(rx[VRRPv3].priority, prio)
884 self.assertEqual(rx[VRRPv3].ipcount, 1)
885 self.assertEqual(rx[VRRPv3].addrlist, [vip])
886
887
Dmitry Valter34fa0ce2024-03-11 10:38:46 +0000888@unittest.skipIf("vrrp" in config.excluded_plugins, "Exclude VRRP plugin tests")
Rajaselvam8cc66b52021-06-30 11:20:20 +0530889class TestVRRP6(VppTestCase):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200890 """IPv6 VRRP Test Case"""
Matthew Smith39e94282020-02-11 11:25:32 -0600891
892 @classmethod
893 def setUpClass(cls):
894 super(TestVRRP6, cls).setUpClass()
895
896 @classmethod
897 def tearDownClass(cls):
898 super(TestVRRP6, cls).tearDownClass()
899
900 def setUp(self):
901 super(TestVRRP6, self).setUp()
902
903 self.create_pg_interfaces(range(2))
904
905 for i in self.pg_interfaces:
906 i.admin_up()
907 i.config_ip6()
908 i.generate_remote_hosts(5)
909 i.configure_ipv6_neighbors()
910
911 self._vrs = []
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200912 self._default_flags = VRRP_VR_FLAG_IPV6 | VRRP_VR_FLAG_PREEMPT
Matthew Smith39e94282020-02-11 11:25:32 -0600913 self._default_adv = 100
914
915 def tearDown(self):
916 for vr in self._vrs:
917 try:
918 vr_api = vr.query_vpp_config()
919 if vr_api.runtime.state != VRRP_VR_STATE_INIT:
920 vr.start_stop(is_start=0)
921 vr.remove_vpp_config()
922 except:
923 self.logger.error("Error cleaning up")
924
925 for i in self.pg_interfaces:
926 i.admin_down()
927 i.unconfig_ip4()
928 i.unconfig_ip6()
929
930 self._vrs = []
931
932 super(TestVRRP6, self).tearDown()
933
934 def verify_vrrp6_mlr(self, pkt, vr):
935 ip6 = pkt[IPv6]
936 self.assertEqual(ip6.dst, "ff02::16")
937 self.assertEqual(ipv6nh[ip6.nh], "Hop-by-Hop Option Header")
938
939 hbh = pkt[IPv6ExtHdrHopByHop]
940 self.assertEqual(ipv6nh[hbh.nh], "ICMPv6")
941
942 self.assertTrue(pkt.haslayer(ICMPv6MLReport2))
943 mlr = pkt[ICMPv6MLReport2]
944 # should contain mc addr records for:
945 # - VRRPv3 multicast addr
946 # - solicited node mc addr record for each VR virtual IPv6 address
947 vips = vr.virtual_ips()
948 self.assertEqual(mlr.records_number, len(vips) + 1)
949 self.assertEqual(mlr.records[0].dst, vr.adv_dest_ip())
950
951 def verify_vrrp6_adv(self, rx_pkt, vr, prio=None):
952 self.assertTrue(rx_pkt.haslayer(Ether))
953 self.assertTrue(rx_pkt.haslayer(IPv6))
954 self.assertTrue(rx_pkt.haslayer(VRRPv3))
955
956 # generate a packet for this VR and compare it to the one received
Rajaselvam8cc66b52021-06-30 11:20:20 +0530957 pkt = vr.vrrp_adv_packet(prio=prio)
Matthew Smith39e94282020-02-11 11:25:32 -0600958 self.assertTrue(rx_pkt.haslayer(Ether))
959 self.assertTrue(rx_pkt.haslayer(IPv6))
960 self.assertTrue(rx_pkt.haslayer(VRRPv3))
961
962 self.assertEqual(pkt, rx_pkt)
963
964 def verify_vrrp6_gna(self, pkt, vr):
965 self.assertTrue(pkt.haslayer(Ether))
966 self.assertTrue(pkt.haslayer(IPv6))
967 self.assertTrue(pkt.haslayer(ICMPv6ND_NA))
968 self.assertTrue(pkt.haslayer(ICMPv6NDOptDstLLAddr))
969
970 self.assertEqual(pkt[Ether].dst, "33:33:00:00:00:01")
971
972 self.assertEqual(pkt[IPv6].dst, "ff02::1")
973 # convert addrs to packed format since string versions could differ
Paul Vinciguerra582eac52020-04-03 12:18:40 -0400974 src_addr = inet_pton(socket.AF_INET6, pkt[IPv6].src)
975 vr_ll_addr = inet_pton(socket.AF_INET6, vr.interface().local_ip6_ll)
Matthew Smith39e94282020-02-11 11:25:32 -0600976 self.assertEqual(src_addr, vr_ll_addr)
977
978 self.assertTrue(pkt[ICMPv6ND_NA].tgt in vr.virtual_ips())
979 self.assertEqual(pkt[ICMPv6NDOptDstLLAddr].lladdr, vr.virtual_mac())
980
981 # VR with priority 255 owns the virtual address and should
982 # become master and start advertising immediately.
Alexander Chernavin65e770d2022-04-11 13:02:11 +0000983 @unittest.skipUnless(config.extended, "part of extended tests")
Matthew Smith39e94282020-02-11 11:25:32 -0600984 def test_vrrp6_master_adv(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200985 """IPv6 Master VR advertises"""
Matthew Smith39e94282020-02-11 11:25:32 -0600986 self.pg_enable_capture(self.pg_interfaces)
987 self.pg_start()
988
989 prio = 255
990 intvl = self._default_adv
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200991 vr = VppVRRPVirtualRouter(
992 self, self.pg0, 100, prio=prio, intvl=intvl, flags=self._default_flags
993 )
Matthew Smith39e94282020-02-11 11:25:32 -0600994 self._vrs.append(vr)
995
996 vr.add_vpp_config()
997 self.logger.info(self.vapi.cli("show vrrp vr"))
998 vr.start_stop(is_start=1)
999 self.logger.info(self.vapi.cli("show vrrp vr"))
1000 vr.start_stop(is_start=0)
1001 self.logger.info(self.vapi.cli("show vrrp vr"))
1002
1003 pkts = self.pg0.get_capture(4, filter_out_fn=None)
1004
1005 # Init -> Master: Multicast group Join, VRRP adv, gratuitous NAs sent
1006 self.verify_vrrp6_mlr(pkts[0], vr)
1007 self.verify_vrrp6_adv(pkts[1], vr, prio=prio)
1008 self.verify_vrrp6_gna(pkts[2], vr)
1009 # Master -> Init: Adv with priority 0 sent to force an election
1010 self.verify_vrrp6_adv(pkts[3], vr, prio=0)
1011
1012 vr.remove_vpp_config()
1013 self._vrs = []
1014
Emanuele Di Pascale7539e4b2022-03-29 12:29:23 +02001015 # Same as above but with the update API, and add a change
1016 # of parameters to test that too
Alexander Chernavin65e770d2022-04-11 13:02:11 +00001017 @unittest.skipUnless(config.extended, "part of extended tests")
Emanuele Di Pascale7539e4b2022-03-29 12:29:23 +02001018 def test_vrrp6_master_adv_update(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001019 """IPv6 Master VR adv + Update to Backup"""
Emanuele Di Pascale7539e4b2022-03-29 12:29:23 +02001020 self.pg_enable_capture(self.pg_interfaces)
1021 self.pg_start()
1022
1023 prio = 255
1024 intvl = self._default_adv
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001025 vr = VppVRRPVirtualRouter(
1026 self, self.pg0, 100, prio=prio, intvl=intvl, flags=self._default_flags
1027 )
Emanuele Di Pascale7539e4b2022-03-29 12:29:23 +02001028
1029 vr.update_vpp_config()
1030 vr.start_stop(is_start=1)
1031 self.logger.info(self.vapi.cli("show vrrp vr"))
1032 # Update VR with lower prio and larger interval
1033 # we need to keep old VR for the adv checks
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001034 upd_vr = VppVRRPVirtualRouter(
1035 self,
1036 self.pg0,
1037 100,
1038 prio=100,
1039 intvl=2 * intvl,
1040 flags=self._default_flags,
1041 vips=[self.pg0.remote_ip6],
1042 )
Emanuele Di Pascale7539e4b2022-03-29 12:29:23 +02001043 upd_vr._vrrp_index = vr._vrrp_index
1044 upd_vr.update_vpp_config()
1045 start_time = time.time()
1046 self.logger.info(self.vapi.cli("show vrrp vr"))
1047 upd_vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
1048 self._vrs = [upd_vr]
1049
1050 pkts = self.pg0.get_capture(5, filter_out_fn=None)
1051
1052 # Init -> Master: Multicast group Join, VRRP adv, gratuitous NAs sent
1053 self.verify_vrrp6_mlr(pkts[0], vr)
1054 self.verify_vrrp6_adv(pkts[1], vr, prio=prio)
1055 self.verify_vrrp6_gna(pkts[2], vr)
1056 # Master -> Init: Adv with priority 0 sent to force an election
1057 self.verify_vrrp6_adv(pkts[3], vr, prio=0)
1058 # Init -> Backup: A multicast listener report should be sent
1059 # not actually verified in the test below, where I took this from
1060
1061 # send higher prio advertisements, should not see VPP send any
1062 src_ip = self.pg0.remote_ip6_ll
1063 pkts = [upd_vr.vrrp_adv_packet(prio=110, src_ip=src_ip)]
1064 self.logger.info(self.vapi.cli("show vlib graph"))
1065 end_time = start_time + 2 * upd_vr.master_down_seconds()
1066 while time.time() < end_time:
1067 self.send_and_assert_no_replies(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001068 self.pg0, pkts, timeout=0.01 * upd_vr._intvl
1069 )
Emanuele Di Pascale7539e4b2022-03-29 12:29:23 +02001070 self.logger.info(self.vapi.cli("show trace"))
1071
1072 vr.start_stop(is_start=0)
1073 self.logger.info(self.vapi.cli("show vrrp vr"))
1074
Matthew Smith39e94282020-02-11 11:25:32 -06001075 # VR with priority < 255 enters backup state and does not advertise as
1076 # long as it receives higher priority advertisements
Alexander Chernavin65e770d2022-04-11 13:02:11 +00001077 @unittest.skipUnless(config.extended, "part of extended tests")
Matthew Smith39e94282020-02-11 11:25:32 -06001078 def test_vrrp6_backup_noadv(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001079 """IPv6 Backup VR does not advertise"""
Matthew Smith39e94282020-02-11 11:25:32 -06001080 self.pg_enable_capture(self.pg_interfaces)
1081 self.pg_start()
1082
1083 vr_id = 100
1084 prio = 100
1085 intvl = self._default_adv
1086 intvl_s = intvl * 0.01
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001087 vr = VppVRRPVirtualRouter(
1088 self,
1089 self.pg0,
1090 vr_id,
1091 prio=prio,
1092 intvl=intvl,
1093 flags=self._default_flags,
1094 vips=[self.pg0.remote_ip6],
1095 )
Matthew Smith39e94282020-02-11 11:25:32 -06001096 vr.add_vpp_config()
1097 self._vrs.append(vr)
1098
1099 vr.start_stop(is_start=1)
1100
1101 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
1102 # watch for advertisements for 2x the master down preemption timeout
1103 end_time = vr.start_time() + 2 * vr.master_down_seconds()
1104
1105 # Init -> Backup: A multicast listener report should be sent
1106 pkts = self.pg0.get_capture(1, filter_out_fn=None)
1107
1108 # send higher prio advertisements, should not see VPP send any
1109 src_ip = self.pg0.remote_ip6_ll
1110 num_advs = 5
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001111 pkts = [vr.vrrp_adv_packet(prio=prio + 10, src_ip=src_ip)]
Matthew Smith39e94282020-02-11 11:25:32 -06001112 self.logger.info(self.vapi.cli("show vlib graph"))
1113 while time.time() < end_time:
1114 self.send_and_assert_no_replies(self.pg0, pkts, timeout=intvl_s)
1115 self.logger.info(self.vapi.cli("show trace"))
1116 num_advs -= 1
1117
1118 vr.start_stop(is_start=0)
1119 self.logger.info(self.vapi.cli("show vrrp vr"))
1120 vr.remove_vpp_config()
1121 self._vrs = []
1122
1123 def test_vrrp6_master_nd(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001124 """IPv6 Master VR replies to NDP"""
Matthew Smith39e94282020-02-11 11:25:32 -06001125 self.pg_start()
1126
1127 # VR virtual IP is the default, which is the pg local IP
1128 vr_id = 100
1129 prio = 255
1130 intvl = self._default_adv
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001131 vr = VppVRRPVirtualRouter(
1132 self, self.pg0, 100, prio=prio, intvl=intvl, flags=self._default_flags
1133 )
Matthew Smith39e94282020-02-11 11:25:32 -06001134 vr.add_vpp_config()
1135 self._vrs.append(vr)
1136
1137 # before the VR is up, NDP should resolve to interface MAC
1138 self.pg0.resolve_ndp()
1139 self.assertNotEqual(self.pg0.local_mac, vr.virtual_mac())
1140
1141 # start the VR, NDP should now resolve to virtual MAC
1142 vr.start_stop(is_start=1)
1143 self.pg0.resolve_ndp()
1144 self.assertEqual(self.pg0.local_mac, vr.virtual_mac())
1145
1146 # stop the VR, ARP should resolve to interface MAC again
1147 vr.start_stop(is_start=0)
1148 self.pg0.resolve_ndp()
1149 self.assertNotEqual(self.pg0.local_mac, vr.virtual_mac())
1150
1151 vr.remove_vpp_config()
1152 self._vrs = []
1153
Alexander Chernavin65e770d2022-04-11 13:02:11 +00001154 @unittest.skipUnless(config.extended, "part of extended tests")
Matthew Smith39e94282020-02-11 11:25:32 -06001155 def test_vrrp6_backup_nond(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001156 """IPv6 Backup VR ignores NDP"""
Matthew Smith39e94282020-02-11 11:25:32 -06001157 # We need an address for a virtual IP that is not the IP that
1158 # ARP requests will originate from
1159
1160 vr_id = 100
1161 prio = 100
1162 intvl = self._default_adv
1163 intvl_s = intvl * 0.01
1164 vip = self.pg0.remote_hosts[1].ip6
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001165 vr = VppVRRPVirtualRouter(
1166 self,
1167 self.pg0,
1168 vr_id,
1169 prio=prio,
1170 intvl=intvl,
1171 flags=self._default_flags,
1172 vips=[vip],
1173 )
Matthew Smith39e94282020-02-11 11:25:32 -06001174 vr.add_vpp_config()
1175 self._vrs.append(vr)
1176
1177 nsma = in6_getnsma(inet_pton(socket.AF_INET6, vip))
1178 dmac = in6_getnsmac(nsma)
1179 dst_ip = inet_ntop(socket.AF_INET6, nsma)
1180
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001181 ndp_req = (
1182 Ether(dst=dmac, src=self.pg0.remote_mac)
1183 / IPv6(dst=dst_ip, src=self.pg0.remote_ip6)
1184 / ICMPv6ND_NS(tgt=vip)
1185 / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)
1186 )
Matthew Smith39e94282020-02-11 11:25:32 -06001187
1188 # Before the VR is started make sure no reply to request for VIP
1189 self.send_and_assert_no_replies(self.pg0, [ndp_req], timeout=1)
1190
1191 # VR should start in backup state and still should not reply to NDP
1192 # send a higher priority adv to make sure it does not become master
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001193 adv = vr.vrrp_adv_packet(prio=prio + 10, src_ip=self.pg0.remote_ip6)
Matthew Smith39e94282020-02-11 11:25:32 -06001194 pkts = [adv, ndp_req]
1195 vr.start_stop(is_start=1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001196 self.send_and_assert_no_replies(self.pg0, pkts, timeout=intvl_s)
Matthew Smith39e94282020-02-11 11:25:32 -06001197
1198 vr.start_stop(is_start=0)
1199
Alexander Chernavin65e770d2022-04-11 13:02:11 +00001200 @unittest.skipUnless(config.extended, "part of extended tests")
Matthew Smith39e94282020-02-11 11:25:32 -06001201 def test_vrrp6_election(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001202 """IPv6 Backup VR becomes master if no advertisements received"""
Matthew Smith39e94282020-02-11 11:25:32 -06001203
1204 vr_id = 100
1205 prio = 100
1206 intvl = self._default_adv
1207 intvl_s = intvl * 0.01
1208 vip = self.pg0.remote_ip6
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001209 vr = VppVRRPVirtualRouter(
1210 self,
1211 self.pg0,
1212 vr_id,
1213 prio=prio,
1214 intvl=intvl,
1215 flags=self._default_flags,
1216 vips=[vip],
1217 )
Matthew Smith39e94282020-02-11 11:25:32 -06001218 self._vrs.append(vr)
1219 vr.add_vpp_config()
1220
1221 # After adding the VR, it should be in the init state
1222 vr.assert_state_equals(VRRP_VR_STATE_INIT)
1223
1224 self.pg_start()
1225 vr.start_stop(is_start=1)
1226
1227 # VR should be in backup state after starting
1228 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
1229 end_time = vr.start_time() + vr.master_down_seconds()
1230
1231 # no advertisements should arrive until timer expires
1232 self.pg0.enable_capture()
1233 while (time.time() + intvl_s) < end_time:
1234 time.sleep(intvl_s)
1235 self.pg0.assert_nothing_captured(filter_out_fn=is_not_adv)
1236
1237 # VR should be in master state after timer expires
1238 self.pg0.enable_capture()
1239 self.pg0.wait_for_packet(intvl_s, is_not_adv)
1240 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
1241
Alexander Chernavin65e770d2022-04-11 13:02:11 +00001242 @unittest.skipUnless(config.extended, "part of extended tests")
Matthew Smith39e94282020-02-11 11:25:32 -06001243 def test_vrrp6_backup_preempts(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001244 """IPv6 Backup VR preempts lower priority master"""
Matthew Smith39e94282020-02-11 11:25:32 -06001245
1246 vr_id = 100
1247 prio = 100
1248 intvl = self._default_adv
1249 intvl_s = intvl * 0.01
1250 vip = self.pg0.remote_ip6
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001251 vr = VppVRRPVirtualRouter(
1252 self,
1253 self.pg0,
1254 vr_id,
1255 prio=prio,
1256 intvl=intvl,
1257 flags=self._default_flags,
1258 vips=[vip],
1259 )
Matthew Smith39e94282020-02-11 11:25:32 -06001260 self._vrs.append(vr)
1261 vr.add_vpp_config()
1262
1263 # After adding the VR, it should be in the init state
1264 vr.assert_state_equals(VRRP_VR_STATE_INIT)
1265
1266 self.pg_start()
1267 vr.start_stop(is_start=1)
1268
1269 # VR should be in backup state after starting
1270 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
1271 end_time = vr.start_time() + vr.master_down_seconds()
1272
1273 # send lower prio advertisements until timer expires
1274 src_ip = self.pg0.remote_ip6
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001275 pkts = [vr.vrrp_adv_packet(prio=prio - 10, src_ip=src_ip)]
Matthew Smith39e94282020-02-11 11:25:32 -06001276 while (time.time() + intvl_s) < end_time:
1277 self.send_and_assert_no_replies(self.pg0, pkts, timeout=intvl_s)
1278 self.logger.info(self.vapi.cli("show trace"))
1279
1280 # when timer expires, VR should take over as master
1281 self.pg0.enable_capture()
1282 self.pg0.wait_for_packet(timeout=intvl_s, filter_out_fn=is_not_adv)
1283 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
1284
Alexander Chernavin65e770d2022-04-11 13:02:11 +00001285 @unittest.skipUnless(config.extended, "part of extended tests")
Matthew Smith39e94282020-02-11 11:25:32 -06001286 def test_vrrp6_master_preempted(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001287 """IPv6 Master VR preempted by higher priority backup"""
Matthew Smith39e94282020-02-11 11:25:32 -06001288
1289 # A prio 255 VR cannot be preempted so the prio has to be lower and
1290 # we have to wait for it to take over
1291 vr_id = 100
1292 prio = 100
1293 intvl = self._default_adv
1294 vip = self.pg0.remote_ip6
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001295 vr = VppVRRPVirtualRouter(
1296 self,
1297 self.pg0,
1298 vr_id,
1299 prio=prio,
1300 intvl=intvl,
1301 flags=self._default_flags,
1302 vips=[vip],
1303 )
Matthew Smith39e94282020-02-11 11:25:32 -06001304 self._vrs.append(vr)
1305 vr.add_vpp_config()
1306
1307 # After adding the VR, it should be in the init state
1308 vr.assert_state_equals(VRRP_VR_STATE_INIT)
1309
1310 # start VR
1311 vr.start_stop(is_start=1)
1312 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
1313
1314 # wait for VR to take over as master
1315 end_time = vr.start_time() + vr.master_down_seconds()
1316 sleep_s = end_time - time.time()
1317 time.sleep(sleep_s)
1318 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
1319
1320 # Build advertisement packet and send it
Rajaselvam8cc66b52021-06-30 11:20:20 +05301321 pkts = [vr.vrrp_adv_packet(prio=255, src_ip=self.pg0.remote_ip6)]
Matthew Smith39e94282020-02-11 11:25:32 -06001322 self.pg_send(self.pg0, pkts)
1323
1324 # VR should be in backup state again
1325 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
1326
Alexander Chernavin65e770d2022-04-11 13:02:11 +00001327 @unittest.skipUnless(config.extended, "part of extended tests")
Matthew Smith39e94282020-02-11 11:25:32 -06001328 def test_vrrp6_accept_mode_disabled(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001329 """IPv6 Master VR does not reply for VIP w/ accept mode off"""
Matthew Smith39e94282020-02-11 11:25:32 -06001330
1331 # accept mode only matters when prio < 255, so it will have to
1332 # come up as a backup and take over as master after the timeout
1333 vr_id = 100
1334 prio = 100
1335 intvl = self._default_adv
1336 vip = self.pg0.remote_hosts[4].ip6
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001337 vr = VppVRRPVirtualRouter(
1338 self,
1339 self.pg0,
1340 vr_id,
1341 prio=prio,
1342 intvl=intvl,
1343 flags=self._default_flags,
1344 vips=[vip],
1345 )
Matthew Smith39e94282020-02-11 11:25:32 -06001346 self._vrs.append(vr)
1347 vr.add_vpp_config()
1348
1349 # After adding the VR, it should be in the init state
1350 vr.assert_state_equals(VRRP_VR_STATE_INIT)
1351
1352 # start VR
1353 vr.start_stop(is_start=1)
1354 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
1355
1356 # wait for VR to take over as master
1357 end_time = vr.start_time() + vr.master_down_seconds()
1358 sleep_s = end_time - time.time()
1359 time.sleep(sleep_s)
1360 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
1361
1362 # send an ICMPv6 echo to the VR virtual IP address
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001363 echo = (
1364 Ether(dst=vr.virtual_mac(), src=self.pg0.remote_mac)
1365 / IPv6(dst=vip, src=self.pg0.remote_ip6)
1366 / ICMPv6EchoRequest(seq=1, id=self.pg0.sw_if_index)
1367 )
Matthew Smith39e94282020-02-11 11:25:32 -06001368 self.pg_send(self.pg0, [echo])
1369
1370 # wait for an echo reply. none should be received
1371 time.sleep(1)
1372 self.pg0.assert_nothing_captured(filter_out_fn=is_not_echo_reply)
1373
Alexander Chernavin65e770d2022-04-11 13:02:11 +00001374 @unittest.skipUnless(config.extended, "part of extended tests")
Matthew Smith39e94282020-02-11 11:25:32 -06001375 def test_vrrp6_accept_mode_enabled(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001376 """IPv6 Master VR replies for VIP w/ accept mode on"""
Matthew Smith39e94282020-02-11 11:25:32 -06001377
1378 # A prio 255 VR cannot be preempted so the prio has to be lower and
1379 # we have to wait for it to take over
1380 vr_id = 100
1381 prio = 100
1382 intvl = self._default_adv
1383 vip = self.pg0.remote_hosts[4].ip6
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001384 flags = self._default_flags | VRRP_VR_FLAG_ACCEPT
1385 vr = VppVRRPVirtualRouter(
1386 self, self.pg0, vr_id, prio=prio, intvl=intvl, flags=flags, vips=[vip]
1387 )
Matthew Smith39e94282020-02-11 11:25:32 -06001388 self._vrs.append(vr)
1389 vr.add_vpp_config()
1390
1391 # After adding the VR, it should be in the init state
1392 vr.assert_state_equals(VRRP_VR_STATE_INIT)
1393
1394 # start VR
1395 vr.start_stop(is_start=1)
1396 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
1397
1398 # wait for VR to take over as master
1399 end_time = vr.start_time() + vr.master_down_seconds()
1400 sleep_s = end_time - time.time()
1401 time.sleep(sleep_s)
1402 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
1403
1404 # send an ICMP echo to the VR virtual IP address
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001405 echo = (
1406 Ether(dst=vr.virtual_mac(), src=self.pg0.remote_mac)
1407 / IPv6(dst=vip, src=self.pg0.remote_ip6)
1408 / ICMPv6EchoRequest(seq=1, id=self.pg0.sw_if_index)
1409 )
Matthew Smith39e94282020-02-11 11:25:32 -06001410 self.pg_send(self.pg0, [echo])
1411
1412 # wait for an echo reply.
1413 time.sleep(1)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001414 rx_pkts = self.pg0.get_capture(
1415 expected_count=1, timeout=1, filter_out_fn=is_not_echo_reply
1416 )
Matthew Smith39e94282020-02-11 11:25:32 -06001417
1418 self.assertEqual(rx_pkts[0][IPv6].src, vip)
1419 self.assertEqual(rx_pkts[0][IPv6].dst, self.pg0.remote_ip6)
1420 self.assertEqual(rx_pkts[0][ICMPv6EchoReply].seq, 1)
1421 self.assertEqual(rx_pkts[0][ICMPv6EchoReply].id, self.pg0.sw_if_index)
1422
Alexander Chernavin65e770d2022-04-11 13:02:11 +00001423 @unittest.skipUnless(config.extended, "part of extended tests")
Matthew Smith39e94282020-02-11 11:25:32 -06001424 def test_vrrp6_intf_tracking(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001425 """IPv6 Master VR adjusts priority based on tracked interface"""
Matthew Smith39e94282020-02-11 11:25:32 -06001426
1427 vr_id = 100
1428 prio = 255
1429 intvl = self._default_adv
1430 intvl_s = intvl * 0.01
1431 vip = self.pg0.local_ip6
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001432 vr = VppVRRPVirtualRouter(
1433 self,
1434 self.pg0,
1435 vr_id,
1436 prio=prio,
1437 intvl=intvl,
1438 flags=self._default_flags,
1439 vips=[vip],
1440 )
Matthew Smith39e94282020-02-11 11:25:32 -06001441 self._vrs.append(vr)
1442 vr.add_vpp_config()
1443
1444 # After adding the VR, it should be in the init state
1445 vr.assert_state_equals(VRRP_VR_STATE_INIT)
1446
1447 # add pg1 as a tracked interface and start the VR
1448 adjustment = 50
1449 adjusted_prio = prio - adjustment
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001450 vr.add_del_tracked_interface(
1451 is_add=1, sw_if_index=self.pg1.sw_if_index, prio=adjustment
1452 )
Matthew Smith39e94282020-02-11 11:25:32 -06001453 vr.start_stop(is_start=1)
1454 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
1455
Rajaselvam8cc66b52021-06-30 11:20:20 +05301456 adv_configured = vr.vrrp_adv_packet(prio=prio)
1457 adv_adjusted = vr.vrrp_adv_packet(prio=adjusted_prio)
Matthew Smith39e94282020-02-11 11:25:32 -06001458
1459 # tracked intf is up -> advertised priority == configured priority
1460 self.pg0.enable_capture()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001461 rx = self.pg0.wait_for_packet(timeout=intvl_s, filter_out_fn=is_not_adv)
Matthew Smith39e94282020-02-11 11:25:32 -06001462 self.assertEqual(rx, adv_configured)
1463
1464 # take down pg1, verify priority is now being adjusted
1465 self.pg1.admin_down()
1466 self.pg0.enable_capture()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001467 rx = self.pg0.wait_for_packet(timeout=intvl_s, filter_out_fn=is_not_adv)
Matthew Smith39e94282020-02-11 11:25:32 -06001468 self.assertEqual(rx, adv_adjusted)
1469
1470 # bring up pg1, verify priority now matches configured value
1471 self.pg1.admin_up()
1472 self.pg0.enable_capture()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001473 rx = self.pg0.wait_for_packet(timeout=intvl_s, filter_out_fn=is_not_adv)
Matthew Smith39e94282020-02-11 11:25:32 -06001474 self.assertEqual(rx, adv_configured)
1475
1476 # remove IP address from pg1, verify priority now being adjusted
1477 self.pg1.unconfig_ip6()
1478 self.pg0.enable_capture()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001479 rx = self.pg0.wait_for_packet(timeout=intvl_s, filter_out_fn=is_not_adv)
Matthew Smith39e94282020-02-11 11:25:32 -06001480 self.assertEqual(rx, adv_adjusted)
1481
1482 # add IP address to pg1, verify priority now matches configured value
1483 self.pg1.config_ip6()
1484 self.pg0.enable_capture()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001485 rx = self.pg0.wait_for_packet(timeout=intvl_s, filter_out_fn=is_not_adv)
Matthew Smith39e94282020-02-11 11:25:32 -06001486 self.assertEqual(rx, adv_configured)
1487
Alexander Chernavin65e770d2022-04-11 13:02:11 +00001488 @unittest.skipUnless(config.extended, "part of extended tests")
Matthew Smith39e94282020-02-11 11:25:32 -06001489 def test_vrrp6_master_adv_unicast(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001490 """IPv6 Master VR advertises (unicast)"""
Matthew Smith39e94282020-02-11 11:25:32 -06001491
1492 vr_id = 100
1493 prio = 255
1494 intvl = self._default_adv
1495 intvl_s = intvl * 0.01
1496 vip = self.pg0.local_ip6
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001497 flags = self._default_flags | VRRP_VR_FLAG_UNICAST
Matthew Smith39e94282020-02-11 11:25:32 -06001498 unicast_peer = self.pg0.remote_hosts[4]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001499 vr = VppVRRPVirtualRouter(
1500 self, self.pg0, vr_id, prio=prio, intvl=intvl, flags=flags, vips=[vip]
1501 )
Matthew Smith39e94282020-02-11 11:25:32 -06001502 self._vrs.append(vr)
1503 vr.add_vpp_config()
1504 vr.set_unicast_peers([unicast_peer.ip6])
1505
1506 # After adding the VR, it should be in the init state
1507 vr.assert_state_equals(VRRP_VR_STATE_INIT)
1508
1509 # Start VR, transition to master
1510 vr.start_stop(is_start=1)
1511 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
1512
1513 self.pg0.enable_capture()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001514 rx = self.pg0.wait_for_packet(timeout=intvl_s, filter_out_fn=is_not_adv)
Matthew Smith39e94282020-02-11 11:25:32 -06001515
1516 self.assertTrue(rx.haslayer(Ether))
1517 self.assertTrue(rx.haslayer(IPv6))
1518 self.assertTrue(rx.haslayer(VRRPv3))
1519 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1520 self.assertEqual(rx[Ether].dst, unicast_peer.mac)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001521 self.assertEqual(
1522 ip6_normalize(rx[IPv6].src), ip6_normalize(self.pg0.local_ip6_ll)
1523 )
1524 self.assertEqual(ip6_normalize(rx[IPv6].dst), ip6_normalize(unicast_peer.ip6))
Matthew Smith39e94282020-02-11 11:25:32 -06001525 self.assertEqual(rx[VRRPv3].vrid, vr_id)
1526 self.assertEqual(rx[VRRPv3].priority, prio)
1527 self.assertEqual(rx[VRRPv3].ipcount, 1)
1528 self.assertEqual(rx[VRRPv3].addrlist, [vip])
1529
1530
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001531if __name__ == "__main__":
Matthew Smith39e94282020-02-11 11:25:32 -06001532 unittest.main(testRunner=VppTestRunner)