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