blob: 1f28cf3d18d282999fffadc6529aa356f50a6e7e [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
15from vpp_papi import VppEnum
16
Paul Vinciguerra582eac52020-04-03 12:18:40 -040017from scapy.packet import raw
Matthew Smith39e94282020-02-11 11:25:32 -060018from scapy.layers.l2 import Ether, ARP
19from scapy.layers.inet import IP, ICMP, icmptypes
20from scapy.layers.inet6 import IPv6, ipv6nh, IPv6ExtHdrHopByHop, \
21 ICMPv6MLReport2, ICMPv6ND_NA, ICMPv6ND_NS, ICMPv6NDOptDstLLAddr, \
22 ICMPv6NDOptSrcLLAddr, ICMPv6EchoRequest, ICMPv6EchoReply
23from scapy.contrib.igmpv3 import IGMPv3, IGMPv3mr, IGMPv3gr
24from scapy.layers.vrrp import IPPROTO_VRRP, VRRPv3
25from scapy.utils6 import in6_getnsma, in6_getnsmac
Klement Sekerab23ffd72021-05-31 16:08:53 +020026from config import config
27from framework import VppTestCase, VppTestRunner
Matthew Smith39e94282020-02-11 11:25:32 -060028from util import ip6_normalize
29
30VRRP_VR_FLAG_PREEMPT = 1
31VRRP_VR_FLAG_ACCEPT = 2
32VRRP_VR_FLAG_UNICAST = 4
33VRRP_VR_FLAG_IPV6 = 8
34
35VRRP_VR_STATE_INIT = 0
36VRRP_VR_STATE_BACKUP = 1
37VRRP_VR_STATE_MASTER = 2
38VRRP_VR_STATE_INTF_DOWN = 3
39
40
41def is_non_arp(p):
42 """ Want to filter out advertisements, igmp, etc"""
43 if p.haslayer(ARP):
44 return False
45
46 return True
47
48
49def is_not_adv(p):
50 """ Filter out everything but advertisements. E.g. multicast RD/ND """
51 if p.haslayer(VRRPv3):
52 return False
53
54 return True
55
56
57def is_not_echo_reply(p):
58 """ filter out advertisements and other while waiting for echo reply """
59 if p.haslayer(IP) and p.haslayer(ICMP):
60 if icmptypes[p[ICMP].type] == "echo-reply":
61 return False
62 elif p.haslayer(IPv6) and p.haslayer(ICMPv6EchoReply):
63 return False
64
65 return True
66
67
68class VppVRRPVirtualRouter(VppObject):
69
70 def __init__(self,
71 test,
72 intf,
73 vr_id,
74 prio=100,
75 intvl=100,
76 flags=VRRP_VR_FLAG_PREEMPT,
77 vips=None):
78 self._test = test
79 self._intf = intf
80 self._sw_if_index = self._intf.sw_if_index
81 self._vr_id = vr_id
82 self._prio = prio
83 self._intvl = intvl
84 self._flags = flags
85 if (flags & VRRP_VR_FLAG_IPV6):
86 self._is_ipv6 = 1
87 self._adv_dest_mac = "33:33:00:00:00:12"
88 self._virtual_mac = "00:00:5e:00:02:%02x" % vr_id
89 self._adv_dest_ip = "ff02::12"
90 self._vips = ([intf.local_ip6] if vips is None else vips)
91 else:
92 self._is_ipv6 = 0
93 self._adv_dest_mac = "01:00:5e:00:00:12"
94 self._virtual_mac = "00:00:5e:00:01:%02x" % vr_id
95 self._adv_dest_ip = "224.0.0.18"
96 self._vips = ([intf.local_ip4] if vips is None else vips)
97 self._tracked_ifs = []
98
99 def add_vpp_config(self):
100 self._test.vapi.vrrp_vr_add_del(is_add=1,
101 sw_if_index=self._intf.sw_if_index,
102 vr_id=self._vr_id,
103 priority=self._prio,
104 interval=self._intvl,
105 flags=self._flags,
106 n_addrs=len(self._vips),
107 addrs=self._vips)
108
109 def query_vpp_config(self):
110 vrs = self._test.vapi.vrrp_vr_dump(sw_if_index=self._intf.sw_if_index)
111 for vr in vrs:
112 if vr.config.vr_id != self._vr_id:
113 continue
114
115 is_ipv6 = (1 if (vr.config.flags & VRRP_VR_FLAG_IPV6) else 0)
116 if is_ipv6 != self._is_ipv6:
117 continue
118
119 return vr
120
121 return None
122
123 def remove_vpp_config(self):
124 self._test.vapi.vrrp_vr_add_del(is_add=0,
125 sw_if_index=self._intf.sw_if_index,
126 vr_id=self._vr_id,
127 priority=self._prio,
128 interval=self._intvl,
129 flags=self._flags,
130 n_addrs=len(self._vips),
131 addrs=self._vips)
132
133 def start_stop(self, is_start):
134 self._test.vapi.vrrp_vr_start_stop(is_start=is_start,
135 sw_if_index=self._intf.sw_if_index,
136 vr_id=self._vr_id,
137 is_ipv6=self._is_ipv6)
138 self._start_time = (time.time() if is_start else None)
139
140 def add_del_tracked_interface(self, is_add, sw_if_index, prio):
141 args = {
142 'sw_if_index': self._intf.sw_if_index,
143 'is_ipv6': self._is_ipv6,
144 'vr_id': self._vr_id,
145 'is_add': is_add,
146 'n_ifs': 1,
147 'ifs': [{'sw_if_index': sw_if_index, 'priority': prio}]
148 }
149 self._test.vapi.vrrp_vr_track_if_add_del(**args)
150 self._tracked_ifs.append(args['ifs'][0])
151
152 def set_unicast_peers(self, addrs):
153 args = {
154 'sw_if_index': self._intf.sw_if_index,
155 'is_ipv6': self._is_ipv6,
156 'vr_id': self._vr_id,
157 'n_addrs': len(addrs),
158 'addrs': addrs
159 }
160 self._test.vapi.vrrp_vr_set_peers(**args)
161 self._unicast_peers = addrs
162
Matthew Smith39e94282020-02-11 11:25:32 -0600163 def start_time(self):
164 return self._start_time
165
166 def virtual_mac(self):
167 return self._virtual_mac
168
169 def virtual_ips(self):
170 return self._vips
171
172 def adv_dest_mac(self):
173 return self._adv_dest_mac
174
175 def adv_dest_ip(self):
176 return self._adv_dest_ip
177
178 def priority(self):
179 return self._prio
180
181 def vr_id(self):
182 return self._vr_id
183
184 def adv_interval(self):
185 return self._intvl
186
187 def interface(self):
188 return self._intf
189
190 def assert_state_equals(self, state):
191 vr_details = self.query_vpp_config()
192 self._test.assertEqual(vr_details.runtime.state, state)
193
194 def master_down_seconds(self):
195 vr_details = self.query_vpp_config()
196 return (vr_details.runtime.master_down_int * 0.01)
197
Paul Vinciguerraa5dd6d72021-04-15 11:37:44 -0400198 def vrrp_adv_packet(self, prio=None, src_ip=None):
199 dst_ip = self._adv_dest_ip
200 if prio is None:
201 prio = self._prio
202 eth = Ether(dst=self._adv_dest_mac, src=self._virtual_mac)
203 vrrp = VRRPv3(vrid=self._vr_id, priority=prio,
204 ipcount=len(self._vips), adv=self._intvl)
205 if self._is_ipv6:
206 src_ip = (self._intf.local_ip6_ll if src_ip is None else src_ip)
207 ip = IPv6(src=src_ip, dst=dst_ip, nh=IPPROTO_VRRP, hlim=255)
208 vrrp.addrlist = self._vips
209 else:
210 src_ip = (self._intf.local_ip4 if src_ip is None else src_ip)
211 ip = IP(src=src_ip, dst=dst_ip, proto=IPPROTO_VRRP, ttl=255, id=0)
212 vrrp.addrlist = self._vips
213
214 # Fill in default values & checksums
215 pkt = Ether(raw(eth / ip / vrrp))
216 return pkt
217
218
Klement Sekerab23ffd72021-05-31 16:08:53 +0200219@unittest.skipUnless(config.extended, "part of extended tests")
Rajaselvam8cc66b52021-06-30 11:20:20 +0530220class TestVRRP4(VppTestCase):
Matthew Smith39e94282020-02-11 11:25:32 -0600221 """ IPv4 VRRP Test Case """
222
223 @classmethod
224 def setUpClass(cls):
225 super(TestVRRP4, cls).setUpClass()
226
227 @classmethod
228 def tearDownClass(cls):
229 super(TestVRRP4, cls).tearDownClass()
230
231 def setUp(self):
232 super(TestVRRP4, self).setUp()
233
234 self.create_pg_interfaces(range(2))
235
236 for i in self.pg_interfaces:
237 i.admin_up()
238 i.config_ip4()
239 i.generate_remote_hosts(5)
240 i.configure_ipv4_neighbors()
241
242 self._vrs = []
243 self._default_flags = VRRP_VR_FLAG_PREEMPT
244 self._default_adv = 100
245
246 def tearDown(self):
247 for vr in self._vrs:
248 try:
249 vr_api = vr.query_vpp_config()
250 if vr_api.runtime.state != VRRP_VR_STATE_INIT:
251 vr.start_stop(is_start=0)
252 vr.remove_vpp_config()
253 except:
254 self.logger.error("Error cleaning up")
255
256 for i in self.pg_interfaces:
257 i.admin_down()
258 i.unconfig_ip4()
259 i.unconfig_ip6()
260
261 self._vrs = []
262
263 super(TestVRRP4, self).tearDown()
264
265 def verify_vrrp4_igmp(self, pkt):
266 ip = pkt[IP]
267 self.assertEqual(ip.dst, "224.0.0.22")
268 self.assertEqual(ip.proto, 2)
269
270 igmp = pkt[IGMPv3]
271 self.assertEqual(IGMPv3.igmpv3types[igmp.type],
272 "Version 3 Membership Report")
273
274 igmpmr = pkt[IGMPv3mr]
275 self.assertEqual(igmpmr.numgrp, 1)
276 self.assertEqual(igmpmr.records[0].maddr, "224.0.0.18")
277
278 def verify_vrrp4_garp(self, pkt, vip, vmac):
279 arp = pkt[ARP]
280
281 # ARP "who-has" op == 1
282 self.assertEqual(arp.op, 1)
283 self.assertEqual(arp.pdst, arp.psrc)
284 self.assertEqual(arp.pdst, vip)
285 self.assertEqual(arp.hwsrc, vmac)
286
287 def verify_vrrp4_adv(self, rx_pkt, vr, prio=None):
288 vips = vr.virtual_ips()
289 eth = rx_pkt[Ether]
290 ip = rx_pkt[IP]
291 vrrp = rx_pkt[VRRPv3]
292
Rajaselvam8cc66b52021-06-30 11:20:20 +0530293 pkt = vr.vrrp_adv_packet(prio=prio)
Matthew Smith39e94282020-02-11 11:25:32 -0600294
295 # Source MAC is virtual MAC, destination is multicast MAC
296 self.assertEqual(eth.src, vr.virtual_mac())
297 self.assertEqual(eth.dst, vr.adv_dest_mac())
298
299 self.assertEqual(ip.dst, "224.0.0.18")
300 self.assertEqual(ip.ttl, 255)
301 self.assertEqual(ip.proto, IPPROTO_VRRP)
302
303 self.assertEqual(vrrp.version, 3)
304 self.assertEqual(vrrp.type, 1)
305 self.assertEqual(vrrp.vrid, vr.vr_id())
306 if prio is None:
307 prio = vr.priority()
308 self.assertEqual(vrrp.priority, prio)
309 self.assertEqual(vrrp.ipcount, len(vips))
310 self.assertEqual(vrrp.adv, vr.adv_interval())
311 self.assertListEqual(vrrp.addrlist, vips)
312
313 # VR with priority 255 owns the virtual address and should
314 # become master and start advertising immediately.
315 def test_vrrp4_master_adv(self):
316 """ IPv4 Master VR advertises """
317 self.pg_enable_capture(self.pg_interfaces)
318 self.pg_start()
319
320 prio = 255
321 intvl = self._default_adv
322 vr = VppVRRPVirtualRouter(self, self.pg0, 100,
323 prio=prio, intvl=intvl,
324 flags=self._default_flags)
325
326 vr.add_vpp_config()
327 vr.start_stop(is_start=1)
328 self.logger.info(self.vapi.cli("show vrrp vr"))
329 vr.start_stop(is_start=0)
330 self.logger.info(self.vapi.cli("show vrrp vr"))
331
332 pkts = self.pg0.get_capture(4)
333
334 # Init -> Master: IGMP Join, VRRP adv, gratuitous ARP are sent
335 self.verify_vrrp4_igmp(pkts[0])
336 self.verify_vrrp4_adv(pkts[1], vr, prio=prio)
337 self.verify_vrrp4_garp(pkts[2], vr.virtual_ips()[0], vr.virtual_mac())
338 # Master -> Init: Adv with priority 0 sent to force an election
339 self.verify_vrrp4_adv(pkts[3], vr, prio=0)
340
341 vr.remove_vpp_config()
342 self._vrs = []
343
344 # VR with priority < 255 enters backup state and does not advertise as
345 # long as it receives higher priority advertisements
346 def test_vrrp4_backup_noadv(self):
347 """ IPv4 Backup VR does not advertise """
348 self.pg_enable_capture(self.pg_interfaces)
349 self.pg_start()
350
351 vr_id = 100
352 prio = 100
353 intvl = self._default_adv
354 intvl_s = intvl * 0.01
355 vr = VppVRRPVirtualRouter(self, self.pg0, vr_id,
356 prio=prio, intvl=intvl,
357 flags=self._default_flags,
358 vips=[self.pg0.remote_ip4])
359 self._vrs.append(vr)
360 vr.add_vpp_config()
361
362 vr.start_stop(is_start=1)
363
364 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
365 # watch for advertisements for 2x the master down preemption timeout
366 end_time = vr.start_time() + 2 * vr.master_down_seconds()
367
368 # Init -> Backup: An IGMP join should be sent
369 pkts = self.pg0.get_capture(1)
370 self.verify_vrrp4_igmp(pkts[0])
371
372 # send higher prio advertisements, should not receive any
373 src_ip = self.pg0.remote_ip4
Rajaselvam8cc66b52021-06-30 11:20:20 +0530374 pkts = [vr.vrrp_adv_packet(prio=prio+10, src_ip=src_ip)]
Matthew Smith39e94282020-02-11 11:25:32 -0600375 while time.time() < end_time:
376 self.send_and_assert_no_replies(self.pg0, pkts, timeout=intvl_s)
377 self.logger.info(self.vapi.cli("show trace"))
378
379 vr.start_stop(is_start=0)
380 self.logger.info(self.vapi.cli("show vrrp vr"))
381 vr.remove_vpp_config()
382 self._vrs = []
383
384 def test_vrrp4_master_arp(self):
385 """ IPv4 Master VR replies to ARP """
386 self.pg_start()
387
388 # VR virtual IP is the default, which is the pg local IP
389 vr_id = 100
390 prio = 255
391 intvl = self._default_adv
392 vr = VppVRRPVirtualRouter(self, self.pg0, 100,
393 prio=prio, intvl=intvl,
394 flags=self._default_flags)
395 self._vrs.append(vr)
396
397 vr.add_vpp_config()
398
399 # before the VR is up, ARP should resolve to interface MAC
400 self.pg0.resolve_arp()
401 self.assertNotEqual(self.pg0.local_mac, vr.virtual_mac())
402
403 # start the VR, ARP should now resolve to virtual MAC
404 vr.start_stop(is_start=1)
405 self.pg0.resolve_arp()
406 self.assertEqual(self.pg0.local_mac, vr.virtual_mac())
407
408 # stop the VR, ARP should resolve to interface MAC again
409 vr.start_stop(is_start=0)
410 self.pg0.resolve_arp()
411 self.assertNotEqual(self.pg0.local_mac, vr.virtual_mac())
412
413 vr.remove_vpp_config()
414 self._vrs = []
415
416 def test_vrrp4_backup_noarp(self):
417 """ IPv4 Backup VR ignores ARP """
418 # We need an address for a virtual IP that is not the IP that
419 # ARP requests will originate from
420
421 vr_id = 100
422 prio = 100
423 intvl = self._default_adv
424 vip = self.pg0.remote_hosts[1].ip4
425 vr = VppVRRPVirtualRouter(self, self.pg0, vr_id,
426 prio=prio, intvl=intvl,
427 flags=self._default_flags,
428 vips=[vip])
429 self._vrs.append(vr)
430 vr.add_vpp_config()
431
432 arp_req = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) /
433 ARP(op=ARP.who_has, pdst=vip,
434 psrc=self.pg0.remote_ip4, hwsrc=self.pg0.remote_mac))
435
436 # Before the VR is started make sure no reply to request for VIP
437 self.pg_start()
438 self.pg_enable_capture(self.pg_interfaces)
439 self.send_and_assert_no_replies(self.pg0, [arp_req], timeout=1)
440
441 # VR should start in backup state and still should not reply to ARP
442 # send a higher priority adv to make sure it does not become master
Rajaselvam8cc66b52021-06-30 11:20:20 +0530443 adv = vr.vrrp_adv_packet(prio=prio+10, src_ip=self.pg0.remote_ip4)
Matthew Smith39e94282020-02-11 11:25:32 -0600444 vr.start_stop(is_start=1)
445 self.send_and_assert_no_replies(self.pg0, [adv, arp_req], timeout=1)
446
447 vr.start_stop(is_start=0)
448 vr.remove_vpp_config()
449 self._vrs = []
450
451 def test_vrrp4_election(self):
452 """ IPv4 Backup VR becomes master if no advertisements received """
453
454 vr_id = 100
455 prio = 100
456 intvl = self._default_adv
457 intvl_s = intvl * 0.01
458 vip = self.pg0.remote_ip4
459 vr = VppVRRPVirtualRouter(self, self.pg0, vr_id,
460 prio=prio, intvl=intvl,
461 flags=self._default_flags,
462 vips=[vip])
463 self._vrs.append(vr)
464 vr.add_vpp_config()
465
466 # After adding the VR, it should be in the init state
467 vr.assert_state_equals(VRRP_VR_STATE_INIT)
468
469 self.pg_start()
470 vr.start_stop(is_start=1)
471
472 # VR should be in backup state after starting
473 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
474 end_time = vr.start_time() + vr.master_down_seconds()
475
476 # should not receive adverts until timer expires & state transition
477 self.pg_enable_capture(self.pg_interfaces)
478 while (time.time() + intvl_s) < end_time:
479 time.sleep(intvl_s)
480 self.pg0.assert_nothing_captured(filter_out_fn=is_not_adv)
481
482 # VR should be in master state, should send an adv
483 self.pg0.enable_capture()
484 self.pg0.wait_for_packet(intvl_s, is_not_adv)
485 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
486
487 def test_vrrp4_backup_preempts(self):
488 """ IPv4 Backup VR preempts lower priority master """
489
490 vr_id = 100
491 prio = 100
492 intvl = self._default_adv
493 intvl_s = intvl * 0.01
494 vip = self.pg0.remote_ip4
495 vr = VppVRRPVirtualRouter(self, self.pg0, vr_id,
496 prio=prio, intvl=intvl,
497 flags=self._default_flags,
498 vips=[vip])
499 self._vrs.append(vr)
500 vr.add_vpp_config()
501
502 # After adding the VR, it should be in the init state
503 vr.assert_state_equals(VRRP_VR_STATE_INIT)
504
505 self.pg_start()
506 vr.start_stop(is_start=1)
507
508 # VR should be in backup state after starting
509 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
510 end_time = vr.start_time() + vr.master_down_seconds()
511
512 # send lower prio advertisements until timer expires
513 src_ip = self.pg0.remote_ip4
Rajaselvam8cc66b52021-06-30 11:20:20 +0530514 pkts = [vr.vrrp_adv_packet(prio=prio-10, src_ip=src_ip)]
Matthew Smith39e94282020-02-11 11:25:32 -0600515 while time.time() + intvl_s < end_time:
516 self.send_and_assert_no_replies(self.pg0, pkts, timeout=intvl_s)
517 self.logger.info(self.vapi.cli("show trace"))
518
519 # when timer expires, VR should take over as master
520 self.pg0.enable_capture()
521 self.pg0.wait_for_packet(timeout=intvl_s, filter_out_fn=is_not_adv)
522 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
523
524 def test_vrrp4_master_preempted(self):
525 """ IPv4 Master VR preempted by higher priority backup """
526
527 # A prio 255 VR cannot be preempted so the prio has to be lower and
528 # we have to wait for it to take over
529 vr_id = 100
530 prio = 100
531 intvl = self._default_adv
532 vip = self.pg0.remote_ip4
533 vr = VppVRRPVirtualRouter(self, self.pg0, vr_id,
534 prio=prio, intvl=intvl,
535 flags=self._default_flags,
536 vips=[vip])
537 self._vrs.append(vr)
538 vr.add_vpp_config()
539
540 # After adding the VR, it should be in the init state
541 vr.assert_state_equals(VRRP_VR_STATE_INIT)
542
543 # start VR
544 vr.start_stop(is_start=1)
545 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
546
547 # wait for VR to take over as master
548 end_time = vr.start_time() + vr.master_down_seconds()
549 sleep_s = end_time - time.time()
550 time.sleep(sleep_s)
551 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
552
553 # Build advertisement packet and send it
Rajaselvam8cc66b52021-06-30 11:20:20 +0530554 pkts = [vr.vrrp_adv_packet(prio=255, src_ip=self.pg0.remote_ip4)]
Matthew Smith39e94282020-02-11 11:25:32 -0600555 self.pg_send(self.pg0, pkts)
556
557 # VR should be in backup state again
558 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
559
560 def test_vrrp4_accept_mode_disabled(self):
561 """ IPv4 Master VR does not reply for VIP w/ accept mode off """
562
563 # accept mode only matters when prio < 255, so it will have to
564 # come up as a backup and take over as master after the timeout
565 vr_id = 100
566 prio = 100
567 intvl = self._default_adv
568 vip = self.pg0.remote_hosts[4].ip4
569 vr = VppVRRPVirtualRouter(self, self.pg0, vr_id,
570 prio=prio, intvl=intvl,
571 flags=self._default_flags,
572 vips=[vip])
573 self._vrs.append(vr)
574 vr.add_vpp_config()
575
576 # After adding the VR, it should be in the init state
577 vr.assert_state_equals(VRRP_VR_STATE_INIT)
578
579 # start VR
580 vr.start_stop(is_start=1)
581 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
582
583 # wait for VR to take over as master
584 end_time = vr.start_time() + vr.master_down_seconds()
585 sleep_s = end_time - time.time()
586 time.sleep(sleep_s)
587 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
588
589 # send an ICMP echo to the VR virtual IP address
590 echo = (Ether(dst=vr.virtual_mac(), src=self.pg0.remote_mac) /
591 IP(dst=vip, src=self.pg0.remote_ip4) /
592 ICMP(seq=1, id=self.pg0.sw_if_index, type='echo-request'))
593 self.pg_send(self.pg0, [echo])
594
595 # wait for an echo reply. none should be received
596 time.sleep(1)
597 self.pg0.assert_nothing_captured(filter_out_fn=is_not_echo_reply)
598
599 def test_vrrp4_accept_mode_enabled(self):
600 """ IPv4 Master VR replies for VIP w/ accept mode on """
601
602 # A prio 255 VR cannot be preempted so the prio has to be lower and
603 # we have to wait for it to take over
604 vr_id = 100
605 prio = 100
606 intvl = self._default_adv
607 vip = self.pg0.remote_hosts[4].ip4
608 flags = (VRRP_VR_FLAG_PREEMPT | VRRP_VR_FLAG_ACCEPT)
609 vr = VppVRRPVirtualRouter(self, self.pg0, vr_id,
610 prio=prio, intvl=intvl,
611 flags=flags,
612 vips=[vip])
613 self._vrs.append(vr)
614 vr.add_vpp_config()
615
616 # After adding the VR, it should be in the init state
617 vr.assert_state_equals(VRRP_VR_STATE_INIT)
618
619 # start VR
620 vr.start_stop(is_start=1)
621 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
622
623 # wait for VR to take over as master
624 end_time = vr.start_time() + vr.master_down_seconds()
625 sleep_s = end_time - time.time()
626 time.sleep(sleep_s)
627 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
628
629 # send an ICMP echo to the VR virtual IP address
630 echo = (Ether(dst=vr.virtual_mac(), src=self.pg0.remote_mac) /
631 IP(dst=vip, src=self.pg0.remote_ip4) /
632 ICMP(seq=1, id=self.pg0.sw_if_index, type='echo-request'))
633 self.pg_send(self.pg0, [echo])
634
635 # wait for an echo reply.
636 time.sleep(1)
637 rx_pkts = self.pg0.get_capture(expected_count=1, timeout=1,
638 filter_out_fn=is_not_echo_reply)
639
640 self.assertEqual(rx_pkts[0][IP].src, vip)
641 self.assertEqual(rx_pkts[0][IP].dst, self.pg0.remote_ip4)
642 self.assertEqual(icmptypes[rx_pkts[0][ICMP].type], "echo-reply")
643 self.assertEqual(rx_pkts[0][ICMP].seq, 1)
644 self.assertEqual(rx_pkts[0][ICMP].id, self.pg0.sw_if_index)
645
646 def test_vrrp4_intf_tracking(self):
647 """ IPv4 Master VR adjusts priority based on tracked interface """
648
649 vr_id = 100
650 prio = 255
651 intvl = self._default_adv
652 intvl_s = intvl * 0.01
653 vip = self.pg0.local_ip4
654 vr = VppVRRPVirtualRouter(self, self.pg0, vr_id,
655 prio=prio, intvl=intvl,
656 flags=self._default_flags,
657 vips=[vip])
658 self._vrs.append(vr)
659 vr.add_vpp_config()
660
661 # After adding the VR, it should be in the init state
662 vr.assert_state_equals(VRRP_VR_STATE_INIT)
663
664 # add pg1 as a tracked interface and start the VR
665 adjustment = 50
666 adjusted_prio = prio - adjustment
667 vr.add_del_tracked_interface(is_add=1,
668 sw_if_index=self.pg1.sw_if_index,
669 prio=adjustment)
670 vr.start_stop(is_start=1)
671 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
672
Rajaselvam8cc66b52021-06-30 11:20:20 +0530673 adv_configured = vr.vrrp_adv_packet(prio=prio)
674 adv_adjusted = vr.vrrp_adv_packet(prio=adjusted_prio)
Matthew Smith39e94282020-02-11 11:25:32 -0600675
676 # tracked intf is up -> advertised priority == configured priority
677 self.pg0.enable_capture()
678 rx = self.pg0.wait_for_packet(timeout=intvl_s,
679 filter_out_fn=is_not_adv)
680 self.assertEqual(rx, adv_configured)
681
682 # take down pg1, verify priority is now being adjusted
683 self.pg1.admin_down()
684 self.pg0.enable_capture()
685 rx = self.pg0.wait_for_packet(timeout=intvl_s,
686 filter_out_fn=is_not_adv)
687 self.assertEqual(rx, adv_adjusted)
688
689 # bring up pg1, verify priority now matches configured value
690 self.pg1.admin_up()
691 self.pg0.enable_capture()
692 rx = self.pg0.wait_for_packet(timeout=intvl_s,
693 filter_out_fn=is_not_adv)
694 self.assertEqual(rx, adv_configured)
695
696 # remove IP address from pg1, verify priority now being adjusted
697 self.pg1.unconfig_ip4()
698 self.pg0.enable_capture()
699 rx = self.pg0.wait_for_packet(timeout=intvl_s,
700 filter_out_fn=is_not_adv)
701 self.assertEqual(rx, adv_adjusted)
702
703 # add IP address to pg1, verify priority now matches configured value
704 self.pg1.config_ip4()
705 self.pg0.enable_capture()
706 rx = self.pg0.wait_for_packet(timeout=intvl_s,
707 filter_out_fn=is_not_adv)
708 self.assertEqual(rx, adv_configured)
709
710 def test_vrrp4_master_adv_unicast(self):
711 """ IPv4 Master VR advertises (unicast) """
712
713 vr_id = 100
714 prio = 255
715 intvl = self._default_adv
716 intvl_s = intvl * 0.01
717 vip = self.pg0.local_ip4
718 flags = (self._default_flags | VRRP_VR_FLAG_UNICAST)
719 unicast_peer = self.pg0.remote_hosts[4]
720 vr = VppVRRPVirtualRouter(self, self.pg0, vr_id,
721 prio=prio, intvl=intvl,
722 flags=flags,
723 vips=[vip])
724 self._vrs.append(vr)
725 vr.add_vpp_config()
726 vr.set_unicast_peers([unicast_peer.ip4])
727
728 # After adding the VR, it should be in the init state
729 vr.assert_state_equals(VRRP_VR_STATE_INIT)
730
731 # Start VR, transition to master
732 vr.start_stop(is_start=1)
733 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
734
735 self.pg0.enable_capture()
736 rx = self.pg0.wait_for_packet(timeout=intvl_s,
737 filter_out_fn=is_not_adv)
738
739 self.assertTrue(rx.haslayer(Ether))
740 self.assertTrue(rx.haslayer(IP))
741 self.assertTrue(rx.haslayer(VRRPv3))
742 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
743 self.assertEqual(rx[Ether].dst, unicast_peer.mac)
744 self.assertEqual(rx[IP].src, self.pg0.local_ip4)
745 self.assertEqual(rx[IP].dst, unicast_peer.ip4)
746 self.assertEqual(rx[VRRPv3].vrid, vr_id)
747 self.assertEqual(rx[VRRPv3].priority, prio)
748 self.assertEqual(rx[VRRPv3].ipcount, 1)
749 self.assertEqual(rx[VRRPv3].addrlist, [vip])
750
751
Klement Sekerab23ffd72021-05-31 16:08:53 +0200752@unittest.skipUnless(config.extended, "part of extended tests")
Rajaselvam8cc66b52021-06-30 11:20:20 +0530753class TestVRRP6(VppTestCase):
Matthew Smith39e94282020-02-11 11:25:32 -0600754 """ IPv6 VRRP Test Case """
755
756 @classmethod
757 def setUpClass(cls):
758 super(TestVRRP6, cls).setUpClass()
759
760 @classmethod
761 def tearDownClass(cls):
762 super(TestVRRP6, cls).tearDownClass()
763
764 def setUp(self):
765 super(TestVRRP6, self).setUp()
766
767 self.create_pg_interfaces(range(2))
768
769 for i in self.pg_interfaces:
770 i.admin_up()
771 i.config_ip6()
772 i.generate_remote_hosts(5)
773 i.configure_ipv6_neighbors()
774
775 self._vrs = []
776 self._default_flags = (VRRP_VR_FLAG_IPV6 | VRRP_VR_FLAG_PREEMPT)
777 self._default_adv = 100
778
779 def tearDown(self):
780 for vr in self._vrs:
781 try:
782 vr_api = vr.query_vpp_config()
783 if vr_api.runtime.state != VRRP_VR_STATE_INIT:
784 vr.start_stop(is_start=0)
785 vr.remove_vpp_config()
786 except:
787 self.logger.error("Error cleaning up")
788
789 for i in self.pg_interfaces:
790 i.admin_down()
791 i.unconfig_ip4()
792 i.unconfig_ip6()
793
794 self._vrs = []
795
796 super(TestVRRP6, self).tearDown()
797
798 def verify_vrrp6_mlr(self, pkt, vr):
799 ip6 = pkt[IPv6]
800 self.assertEqual(ip6.dst, "ff02::16")
801 self.assertEqual(ipv6nh[ip6.nh], "Hop-by-Hop Option Header")
802
803 hbh = pkt[IPv6ExtHdrHopByHop]
804 self.assertEqual(ipv6nh[hbh.nh], "ICMPv6")
805
806 self.assertTrue(pkt.haslayer(ICMPv6MLReport2))
807 mlr = pkt[ICMPv6MLReport2]
808 # should contain mc addr records for:
809 # - VRRPv3 multicast addr
810 # - solicited node mc addr record for each VR virtual IPv6 address
811 vips = vr.virtual_ips()
812 self.assertEqual(mlr.records_number, len(vips) + 1)
813 self.assertEqual(mlr.records[0].dst, vr.adv_dest_ip())
814
815 def verify_vrrp6_adv(self, rx_pkt, vr, prio=None):
816 self.assertTrue(rx_pkt.haslayer(Ether))
817 self.assertTrue(rx_pkt.haslayer(IPv6))
818 self.assertTrue(rx_pkt.haslayer(VRRPv3))
819
820 # generate a packet for this VR and compare it to the one received
Rajaselvam8cc66b52021-06-30 11:20:20 +0530821 pkt = vr.vrrp_adv_packet(prio=prio)
Matthew Smith39e94282020-02-11 11:25:32 -0600822 self.assertTrue(rx_pkt.haslayer(Ether))
823 self.assertTrue(rx_pkt.haslayer(IPv6))
824 self.assertTrue(rx_pkt.haslayer(VRRPv3))
825
826 self.assertEqual(pkt, rx_pkt)
827
828 def verify_vrrp6_gna(self, pkt, vr):
829 self.assertTrue(pkt.haslayer(Ether))
830 self.assertTrue(pkt.haslayer(IPv6))
831 self.assertTrue(pkt.haslayer(ICMPv6ND_NA))
832 self.assertTrue(pkt.haslayer(ICMPv6NDOptDstLLAddr))
833
834 self.assertEqual(pkt[Ether].dst, "33:33:00:00:00:01")
835
836 self.assertEqual(pkt[IPv6].dst, "ff02::1")
837 # convert addrs to packed format since string versions could differ
Paul Vinciguerra582eac52020-04-03 12:18:40 -0400838 src_addr = inet_pton(socket.AF_INET6, pkt[IPv6].src)
839 vr_ll_addr = inet_pton(socket.AF_INET6, vr.interface().local_ip6_ll)
Matthew Smith39e94282020-02-11 11:25:32 -0600840 self.assertEqual(src_addr, vr_ll_addr)
841
842 self.assertTrue(pkt[ICMPv6ND_NA].tgt in vr.virtual_ips())
843 self.assertEqual(pkt[ICMPv6NDOptDstLLAddr].lladdr, vr.virtual_mac())
844
845 # VR with priority 255 owns the virtual address and should
846 # become master and start advertising immediately.
847 def test_vrrp6_master_adv(self):
848 """ IPv6 Master VR advertises """
849 self.pg_enable_capture(self.pg_interfaces)
850 self.pg_start()
851
852 prio = 255
853 intvl = self._default_adv
854 vr = VppVRRPVirtualRouter(self, self.pg0, 100,
855 prio=prio, intvl=intvl,
856 flags=self._default_flags)
857 self._vrs.append(vr)
858
859 vr.add_vpp_config()
860 self.logger.info(self.vapi.cli("show vrrp vr"))
861 vr.start_stop(is_start=1)
862 self.logger.info(self.vapi.cli("show vrrp vr"))
863 vr.start_stop(is_start=0)
864 self.logger.info(self.vapi.cli("show vrrp vr"))
865
866 pkts = self.pg0.get_capture(4, filter_out_fn=None)
867
868 # Init -> Master: Multicast group Join, VRRP adv, gratuitous NAs sent
869 self.verify_vrrp6_mlr(pkts[0], vr)
870 self.verify_vrrp6_adv(pkts[1], vr, prio=prio)
871 self.verify_vrrp6_gna(pkts[2], vr)
872 # Master -> Init: Adv with priority 0 sent to force an election
873 self.verify_vrrp6_adv(pkts[3], vr, prio=0)
874
875 vr.remove_vpp_config()
876 self._vrs = []
877
878 # VR with priority < 255 enters backup state and does not advertise as
879 # long as it receives higher priority advertisements
880 def test_vrrp6_backup_noadv(self):
881 """ IPv6 Backup VR does not advertise """
882 self.pg_enable_capture(self.pg_interfaces)
883 self.pg_start()
884
885 vr_id = 100
886 prio = 100
887 intvl = self._default_adv
888 intvl_s = intvl * 0.01
889 vr = VppVRRPVirtualRouter(self, self.pg0, vr_id,
890 prio=prio, intvl=intvl,
891 flags=self._default_flags,
892 vips=[self.pg0.remote_ip6])
893 vr.add_vpp_config()
894 self._vrs.append(vr)
895
896 vr.start_stop(is_start=1)
897
898 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
899 # watch for advertisements for 2x the master down preemption timeout
900 end_time = vr.start_time() + 2 * vr.master_down_seconds()
901
902 # Init -> Backup: A multicast listener report should be sent
903 pkts = self.pg0.get_capture(1, filter_out_fn=None)
904
905 # send higher prio advertisements, should not see VPP send any
906 src_ip = self.pg0.remote_ip6_ll
907 num_advs = 5
Rajaselvam8cc66b52021-06-30 11:20:20 +0530908 pkts = [vr.vrrp_adv_packet(prio=prio+10, src_ip=src_ip)]
Matthew Smith39e94282020-02-11 11:25:32 -0600909 self.logger.info(self.vapi.cli("show vlib graph"))
910 while time.time() < end_time:
911 self.send_and_assert_no_replies(self.pg0, pkts, timeout=intvl_s)
912 self.logger.info(self.vapi.cli("show trace"))
913 num_advs -= 1
914
915 vr.start_stop(is_start=0)
916 self.logger.info(self.vapi.cli("show vrrp vr"))
917 vr.remove_vpp_config()
918 self._vrs = []
919
920 def test_vrrp6_master_nd(self):
921 """ IPv6 Master VR replies to NDP """
922 self.pg_start()
923
924 # VR virtual IP is the default, which is the pg local IP
925 vr_id = 100
926 prio = 255
927 intvl = self._default_adv
928 vr = VppVRRPVirtualRouter(self, self.pg0, 100,
929 prio=prio, intvl=intvl,
930 flags=self._default_flags)
931 vr.add_vpp_config()
932 self._vrs.append(vr)
933
934 # before the VR is up, NDP should resolve to interface MAC
935 self.pg0.resolve_ndp()
936 self.assertNotEqual(self.pg0.local_mac, vr.virtual_mac())
937
938 # start the VR, NDP should now resolve to virtual MAC
939 vr.start_stop(is_start=1)
940 self.pg0.resolve_ndp()
941 self.assertEqual(self.pg0.local_mac, vr.virtual_mac())
942
943 # stop the VR, ARP should resolve to interface MAC again
944 vr.start_stop(is_start=0)
945 self.pg0.resolve_ndp()
946 self.assertNotEqual(self.pg0.local_mac, vr.virtual_mac())
947
948 vr.remove_vpp_config()
949 self._vrs = []
950
951 def test_vrrp6_backup_nond(self):
952 """ IPv6 Backup VR ignores NDP """
953 # We need an address for a virtual IP that is not the IP that
954 # ARP requests will originate from
955
956 vr_id = 100
957 prio = 100
958 intvl = self._default_adv
959 intvl_s = intvl * 0.01
960 vip = self.pg0.remote_hosts[1].ip6
961 vr = VppVRRPVirtualRouter(self, self.pg0, vr_id,
962 prio=prio, intvl=intvl,
963 flags=self._default_flags,
964 vips=[vip])
965 vr.add_vpp_config()
966 self._vrs.append(vr)
967
968 nsma = in6_getnsma(inet_pton(socket.AF_INET6, vip))
969 dmac = in6_getnsmac(nsma)
970 dst_ip = inet_ntop(socket.AF_INET6, nsma)
971
972 ndp_req = (Ether(dst=dmac, src=self.pg0.remote_mac) /
973 IPv6(dst=dst_ip, src=self.pg0.remote_ip6) /
974 ICMPv6ND_NS(tgt=vip) /
975 ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac))
976
977 # Before the VR is started make sure no reply to request for VIP
978 self.send_and_assert_no_replies(self.pg0, [ndp_req], timeout=1)
979
980 # VR should start in backup state and still should not reply to NDP
981 # send a higher priority adv to make sure it does not become master
Rajaselvam8cc66b52021-06-30 11:20:20 +0530982 adv = vr.vrrp_adv_packet(prio=prio+10, src_ip=self.pg0.remote_ip6)
Matthew Smith39e94282020-02-11 11:25:32 -0600983 pkts = [adv, ndp_req]
984 vr.start_stop(is_start=1)
985 self.send_and_assert_no_replies(self.pg0, pkts, timeout=intvl_s)
986
987 vr.start_stop(is_start=0)
988
989 def test_vrrp6_election(self):
990 """ IPv6 Backup VR becomes master if no advertisements received """
991
992 vr_id = 100
993 prio = 100
994 intvl = self._default_adv
995 intvl_s = intvl * 0.01
996 vip = self.pg0.remote_ip6
997 vr = VppVRRPVirtualRouter(self, self.pg0, vr_id,
998 prio=prio, intvl=intvl,
999 flags=self._default_flags,
1000 vips=[vip])
1001 self._vrs.append(vr)
1002 vr.add_vpp_config()
1003
1004 # After adding the VR, it should be in the init state
1005 vr.assert_state_equals(VRRP_VR_STATE_INIT)
1006
1007 self.pg_start()
1008 vr.start_stop(is_start=1)
1009
1010 # VR should be in backup state after starting
1011 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
1012 end_time = vr.start_time() + vr.master_down_seconds()
1013
1014 # no advertisements should arrive until timer expires
1015 self.pg0.enable_capture()
1016 while (time.time() + intvl_s) < end_time:
1017 time.sleep(intvl_s)
1018 self.pg0.assert_nothing_captured(filter_out_fn=is_not_adv)
1019
1020 # VR should be in master state after timer expires
1021 self.pg0.enable_capture()
1022 self.pg0.wait_for_packet(intvl_s, is_not_adv)
1023 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
1024
1025 def test_vrrp6_backup_preempts(self):
1026 """ IPv6 Backup VR preempts lower priority master """
1027
1028 vr_id = 100
1029 prio = 100
1030 intvl = self._default_adv
1031 intvl_s = intvl * 0.01
1032 vip = self.pg0.remote_ip6
1033 vr = VppVRRPVirtualRouter(self, self.pg0, vr_id,
1034 prio=prio, intvl=intvl,
1035 flags=self._default_flags,
1036 vips=[vip])
1037 self._vrs.append(vr)
1038 vr.add_vpp_config()
1039
1040 # After adding the VR, it should be in the init state
1041 vr.assert_state_equals(VRRP_VR_STATE_INIT)
1042
1043 self.pg_start()
1044 vr.start_stop(is_start=1)
1045
1046 # VR should be in backup state after starting
1047 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
1048 end_time = vr.start_time() + vr.master_down_seconds()
1049
1050 # send lower prio advertisements until timer expires
1051 src_ip = self.pg0.remote_ip6
Rajaselvam8cc66b52021-06-30 11:20:20 +05301052 pkts = [vr.vrrp_adv_packet(prio=prio-10, src_ip=src_ip)]
Matthew Smith39e94282020-02-11 11:25:32 -06001053 while (time.time() + intvl_s) < end_time:
1054 self.send_and_assert_no_replies(self.pg0, pkts, timeout=intvl_s)
1055 self.logger.info(self.vapi.cli("show trace"))
1056
1057 # when timer expires, VR should take over as master
1058 self.pg0.enable_capture()
1059 self.pg0.wait_for_packet(timeout=intvl_s, filter_out_fn=is_not_adv)
1060 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
1061
1062 def test_vrrp6_master_preempted(self):
1063 """ IPv6 Master VR preempted by higher priority backup """
1064
1065 # A prio 255 VR cannot be preempted so the prio has to be lower and
1066 # we have to wait for it to take over
1067 vr_id = 100
1068 prio = 100
1069 intvl = self._default_adv
1070 vip = self.pg0.remote_ip6
1071 vr = VppVRRPVirtualRouter(self, self.pg0, vr_id,
1072 prio=prio, intvl=intvl,
1073 flags=self._default_flags,
1074 vips=[vip])
1075 self._vrs.append(vr)
1076 vr.add_vpp_config()
1077
1078 # After adding the VR, it should be in the init state
1079 vr.assert_state_equals(VRRP_VR_STATE_INIT)
1080
1081 # start VR
1082 vr.start_stop(is_start=1)
1083 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
1084
1085 # wait for VR to take over as master
1086 end_time = vr.start_time() + vr.master_down_seconds()
1087 sleep_s = end_time - time.time()
1088 time.sleep(sleep_s)
1089 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
1090
1091 # Build advertisement packet and send it
Rajaselvam8cc66b52021-06-30 11:20:20 +05301092 pkts = [vr.vrrp_adv_packet(prio=255, src_ip=self.pg0.remote_ip6)]
Matthew Smith39e94282020-02-11 11:25:32 -06001093 self.pg_send(self.pg0, pkts)
1094
1095 # VR should be in backup state again
1096 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
1097
1098 def test_vrrp6_accept_mode_disabled(self):
1099 """ IPv6 Master VR does not reply for VIP w/ accept mode off """
1100
1101 # accept mode only matters when prio < 255, so it will have to
1102 # come up as a backup and take over as master after the timeout
1103 vr_id = 100
1104 prio = 100
1105 intvl = self._default_adv
1106 vip = self.pg0.remote_hosts[4].ip6
1107 vr = VppVRRPVirtualRouter(self, self.pg0, vr_id,
1108 prio=prio, intvl=intvl,
1109 flags=self._default_flags,
1110 vips=[vip])
1111 self._vrs.append(vr)
1112 vr.add_vpp_config()
1113
1114 # After adding the VR, it should be in the init state
1115 vr.assert_state_equals(VRRP_VR_STATE_INIT)
1116
1117 # start VR
1118 vr.start_stop(is_start=1)
1119 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
1120
1121 # wait for VR to take over as master
1122 end_time = vr.start_time() + vr.master_down_seconds()
1123 sleep_s = end_time - time.time()
1124 time.sleep(sleep_s)
1125 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
1126
1127 # send an ICMPv6 echo to the VR virtual IP address
1128 echo = (Ether(dst=vr.virtual_mac(), src=self.pg0.remote_mac) /
1129 IPv6(dst=vip, src=self.pg0.remote_ip6) /
1130 ICMPv6EchoRequest(seq=1, id=self.pg0.sw_if_index))
1131 self.pg_send(self.pg0, [echo])
1132
1133 # wait for an echo reply. none should be received
1134 time.sleep(1)
1135 self.pg0.assert_nothing_captured(filter_out_fn=is_not_echo_reply)
1136
1137 def test_vrrp6_accept_mode_enabled(self):
1138 """ IPv6 Master VR replies for VIP w/ accept mode on """
1139
1140 # A prio 255 VR cannot be preempted so the prio has to be lower and
1141 # we have to wait for it to take over
1142 vr_id = 100
1143 prio = 100
1144 intvl = self._default_adv
1145 vip = self.pg0.remote_hosts[4].ip6
1146 flags = (self._default_flags | VRRP_VR_FLAG_ACCEPT)
1147 vr = VppVRRPVirtualRouter(self, self.pg0, vr_id,
1148 prio=prio, intvl=intvl,
1149 flags=flags,
1150 vips=[vip])
1151 self._vrs.append(vr)
1152 vr.add_vpp_config()
1153
1154 # After adding the VR, it should be in the init state
1155 vr.assert_state_equals(VRRP_VR_STATE_INIT)
1156
1157 # start VR
1158 vr.start_stop(is_start=1)
1159 vr.assert_state_equals(VRRP_VR_STATE_BACKUP)
1160
1161 # wait for VR to take over as master
1162 end_time = vr.start_time() + vr.master_down_seconds()
1163 sleep_s = end_time - time.time()
1164 time.sleep(sleep_s)
1165 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
1166
1167 # send an ICMP echo to the VR virtual IP address
1168 echo = (Ether(dst=vr.virtual_mac(), src=self.pg0.remote_mac) /
1169 IPv6(dst=vip, src=self.pg0.remote_ip6) /
1170 ICMPv6EchoRequest(seq=1, id=self.pg0.sw_if_index))
1171 self.pg_send(self.pg0, [echo])
1172
1173 # wait for an echo reply.
1174 time.sleep(1)
1175 rx_pkts = self.pg0.get_capture(expected_count=1, timeout=1,
1176 filter_out_fn=is_not_echo_reply)
1177
1178 self.assertEqual(rx_pkts[0][IPv6].src, vip)
1179 self.assertEqual(rx_pkts[0][IPv6].dst, self.pg0.remote_ip6)
1180 self.assertEqual(rx_pkts[0][ICMPv6EchoReply].seq, 1)
1181 self.assertEqual(rx_pkts[0][ICMPv6EchoReply].id, self.pg0.sw_if_index)
1182
1183 def test_vrrp6_intf_tracking(self):
1184 """ IPv6 Master VR adjusts priority based on tracked interface """
1185
1186 vr_id = 100
1187 prio = 255
1188 intvl = self._default_adv
1189 intvl_s = intvl * 0.01
1190 vip = self.pg0.local_ip6
1191 vr = VppVRRPVirtualRouter(self, self.pg0, vr_id,
1192 prio=prio, intvl=intvl,
1193 flags=self._default_flags,
1194 vips=[vip])
1195 self._vrs.append(vr)
1196 vr.add_vpp_config()
1197
1198 # After adding the VR, it should be in the init state
1199 vr.assert_state_equals(VRRP_VR_STATE_INIT)
1200
1201 # add pg1 as a tracked interface and start the VR
1202 adjustment = 50
1203 adjusted_prio = prio - adjustment
1204 vr.add_del_tracked_interface(is_add=1,
1205 sw_if_index=self.pg1.sw_if_index,
1206 prio=adjustment)
1207 vr.start_stop(is_start=1)
1208 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
1209
Rajaselvam8cc66b52021-06-30 11:20:20 +05301210 adv_configured = vr.vrrp_adv_packet(prio=prio)
1211 adv_adjusted = vr.vrrp_adv_packet(prio=adjusted_prio)
Matthew Smith39e94282020-02-11 11:25:32 -06001212
1213 # tracked intf is up -> advertised priority == configured priority
1214 self.pg0.enable_capture()
1215 rx = self.pg0.wait_for_packet(timeout=intvl_s,
1216 filter_out_fn=is_not_adv)
1217 self.assertEqual(rx, adv_configured)
1218
1219 # take down pg1, verify priority is now being adjusted
1220 self.pg1.admin_down()
1221 self.pg0.enable_capture()
1222 rx = self.pg0.wait_for_packet(timeout=intvl_s,
1223 filter_out_fn=is_not_adv)
1224 self.assertEqual(rx, adv_adjusted)
1225
1226 # bring up pg1, verify priority now matches configured value
1227 self.pg1.admin_up()
1228 self.pg0.enable_capture()
1229 rx = self.pg0.wait_for_packet(timeout=intvl_s,
1230 filter_out_fn=is_not_adv)
1231 self.assertEqual(rx, adv_configured)
1232
1233 # remove IP address from pg1, verify priority now being adjusted
1234 self.pg1.unconfig_ip6()
1235 self.pg0.enable_capture()
1236 rx = self.pg0.wait_for_packet(timeout=intvl_s,
1237 filter_out_fn=is_not_adv)
1238 self.assertEqual(rx, adv_adjusted)
1239
1240 # add IP address to pg1, verify priority now matches configured value
1241 self.pg1.config_ip6()
1242 self.pg0.enable_capture()
1243 rx = self.pg0.wait_for_packet(timeout=intvl_s,
1244 filter_out_fn=is_not_adv)
1245 self.assertEqual(rx, adv_configured)
1246
1247 def test_vrrp6_master_adv_unicast(self):
1248 """ IPv6 Master VR advertises (unicast) """
1249
1250 vr_id = 100
1251 prio = 255
1252 intvl = self._default_adv
1253 intvl_s = intvl * 0.01
1254 vip = self.pg0.local_ip6
1255 flags = (self._default_flags | VRRP_VR_FLAG_UNICAST)
1256 unicast_peer = self.pg0.remote_hosts[4]
1257 vr = VppVRRPVirtualRouter(self, self.pg0, vr_id,
1258 prio=prio, intvl=intvl,
1259 flags=flags,
1260 vips=[vip])
1261 self._vrs.append(vr)
1262 vr.add_vpp_config()
1263 vr.set_unicast_peers([unicast_peer.ip6])
1264
1265 # After adding the VR, it should be in the init state
1266 vr.assert_state_equals(VRRP_VR_STATE_INIT)
1267
1268 # Start VR, transition to master
1269 vr.start_stop(is_start=1)
1270 vr.assert_state_equals(VRRP_VR_STATE_MASTER)
1271
1272 self.pg0.enable_capture()
1273 rx = self.pg0.wait_for_packet(timeout=intvl_s,
1274 filter_out_fn=is_not_adv)
1275
1276 self.assertTrue(rx.haslayer(Ether))
1277 self.assertTrue(rx.haslayer(IPv6))
1278 self.assertTrue(rx.haslayer(VRRPv3))
1279 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1280 self.assertEqual(rx[Ether].dst, unicast_peer.mac)
1281 self.assertEqual(ip6_normalize(rx[IPv6].src),
1282 ip6_normalize(self.pg0.local_ip6_ll))
1283 self.assertEqual(ip6_normalize(rx[IPv6].dst),
1284 ip6_normalize(unicast_peer.ip6))
1285 self.assertEqual(rx[VRRPv3].vrid, vr_id)
1286 self.assertEqual(rx[VRRPv3].priority, prio)
1287 self.assertEqual(rx[VRRPv3].ipcount, 1)
1288 self.assertEqual(rx[VRRPv3].addrlist, [vip])
1289
1290
1291if __name__ == '__main__':
1292 unittest.main(testRunner=VppTestRunner)