1#!/usr/bin/env python
2
3#
4# test_bgp_auth.py
5# Part of NetDEF Topology Tests
6#
7# Copyright (c) 2020 by Volta Networks
8#
9# Permission to use, copy, modify, and/or distribute this software
10# for any purpose with or without fee is hereby granted, provided
11# that the above copyright notice and this permission notice appear
12# in all copies.
13#
14# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
15# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
17# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
18# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
20# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21# OF THIS SOFTWARE.
22#
23
24"""
25test_bgp_auth.py: Test BGP Md5 Authentication
26
27                             +------+
28                    +--------|      |--------+
29                    | +------|  R1  |------+ |
30                    | | -----|      |----+ | |
31                    | | |    +------+    | | |
32                    | | |                | | |
33                   +------+            +------+
34                   |      |------------|      |
35                   |  R2  |------------|  R3  |
36                   |      |------------|      |
37                   +------+            +------+
38
39
40setup is 3 routers with 3 links between each each link in a different vrf
41Default, blue and red respectively
42Tests check various fiddling with passwords and checking that the peer
43establishment is as expected and passwords are not leaked across sockets
44for bgp instances
45"""
46
47import os
48import sys
49import json
50import platform
51from functools import partial
52import pytest
53from time import sleep
54
55# Save the Current Working Directory to find configuration files.
56CWD = os.path.dirname(os.path.realpath(__file__))
57sys.path.append(os.path.join(CWD, "../"))
58
59# pylint: disable=C0413
60# Import topogen and topotest helpers
61from lib import topotest
62from lib.topogen import Topogen, TopoRouter, get_topogen
63from lib.topolog import logger
64
65# Required to instantiate the topology builder class.
66from mininet.topo import Topo
67
68from lib.common_config import apply_raw_config
69
70ERROR_LIST = ["Malformed", "Failure", "Unknown", "Incomplete"]
71
72
73class InvalidCLIError(Exception):
74    """Raise when the CLI command is wrong"""
75
76    pass
77
78
79class TemplateTopo(Topo):
80    "Test topology builder"
81
82    def build(self, *_args, **_opts):
83        "Build function"
84        tgen = get_topogen(self)
85
86        # This function only purpose is to define allocation and relationship
87        # between routers, switches and hosts.
88        #
89        #
90        # Create routers
91        tgen.add_router("R1")
92        tgen.add_router("R2")
93        tgen.add_router("R3")
94
95        # R1-R2 1
96        switch = tgen.add_switch("s1")
97        switch.add_link(tgen.gears["R1"])
98        switch.add_link(tgen.gears["R2"])
99
100        # R1-R3 1
101        switch = tgen.add_switch("s2")
102        switch.add_link(tgen.gears["R1"])
103        switch.add_link(tgen.gears["R3"])
104
105        # R2-R3 1
106        switch = tgen.add_switch("s3")
107        switch.add_link(tgen.gears["R2"])
108        switch.add_link(tgen.gears["R3"])
109
110        # R1-R2 2
111        switch = tgen.add_switch("s4")
112        switch.add_link(tgen.gears["R1"])
113        switch.add_link(tgen.gears["R2"])
114
115        # R1-R3 2
116        switch = tgen.add_switch("s5")
117        switch.add_link(tgen.gears["R1"])
118        switch.add_link(tgen.gears["R3"])
119
120        # R2-R3 2
121        switch = tgen.add_switch("s6")
122        switch.add_link(tgen.gears["R2"])
123        switch.add_link(tgen.gears["R3"])
124
125        # R1-R2 3
126        switch = tgen.add_switch("s7")
127        switch.add_link(tgen.gears["R1"])
128        switch.add_link(tgen.gears["R2"])
129
130        # R1-R3 2
131        switch = tgen.add_switch("s8")
132        switch.add_link(tgen.gears["R1"])
133        switch.add_link(tgen.gears["R3"])
134
135        # R2-R3 2
136        switch = tgen.add_switch("s9")
137        switch.add_link(tgen.gears["R2"])
138        switch.add_link(tgen.gears["R3"])
139
140
141def setup_module(mod):
142    "Sets up the pytest environment"
143    # This function initiates the topology build with Topogen...
144    tgen = Topogen(TemplateTopo, mod.__name__)
145    # ... and here it calls Mininet initialization functions.
146    tgen.start_topology()
147
148    r1 = tgen.gears["R1"]
149    r2 = tgen.gears["R2"]
150    r3 = tgen.gears["R3"]
151
152    # blue vrf
153    r1.run("ip link add blue type vrf table 1001")
154    r1.run("ip link set up dev blue")
155    r2.run("ip link add blue type vrf table 1001")
156    r2.run("ip link set up dev blue")
157    r3.run("ip link add blue type vrf table 1001")
158    r3.run("ip link set up dev blue")
159
160    r1.run("ip link add lo1 type dummy")
161    r1.run("ip link set lo1 master blue")
162    r1.run("ip link set up dev lo1")
163    r2.run("ip link add lo1 type dummy")
164    r2.run("ip link set up dev lo1")
165    r2.run("ip link set lo1 master blue")
166    r3.run("ip link add lo1 type dummy")
167    r3.run("ip link set up dev lo1")
168    r3.run("ip link set lo1 master blue")
169
170    r1.run("ip link set R1-eth2 master blue")
171    r1.run("ip link set R1-eth3 master blue")
172    r2.run("ip link set R2-eth2 master blue")
173    r2.run("ip link set R2-eth3 master blue")
174    r3.run("ip link set R3-eth2 master blue")
175    r3.run("ip link set R3-eth3 master blue")
176
177    r1.run("ip link set up dev  R1-eth2")
178    r1.run("ip link set up dev  R1-eth3")
179    r2.run("ip link set up dev  R2-eth2")
180    r2.run("ip link set up dev  R2-eth3")
181    r3.run("ip link set up dev  R3-eth2")
182    r3.run("ip link set up dev  R3-eth3")
183
184    # red vrf
185    r1.run("ip link add red type vrf table 1002")
186    r1.run("ip link set up dev red")
187    r2.run("ip link add red type vrf table 1002")
188    r2.run("ip link set up dev red")
189    r3.run("ip link add red type vrf table 1002")
190    r3.run("ip link set up dev red")
191
192    r1.run("ip link add lo2 type dummy")
193    r1.run("ip link set lo2 master red")
194    r1.run("ip link set up dev lo2")
195    r2.run("ip link add lo2 type dummy")
196    r2.run("ip link set up dev lo2")
197    r2.run("ip link set lo2 master red")
198    r3.run("ip link add lo2 type dummy")
199    r3.run("ip link set up dev lo2")
200    r3.run("ip link set lo2 master red")
201
202    r1.run("ip link set R1-eth4 master red")
203    r1.run("ip link set R1-eth5 master red")
204    r2.run("ip link set R2-eth4 master red")
205    r2.run("ip link set R2-eth5 master red")
206    r3.run("ip link set R3-eth4 master red")
207    r3.run("ip link set R3-eth5 master red")
208
209    r1.run("ip link set up dev  R1-eth4")
210    r1.run("ip link set up dev  R1-eth5")
211    r2.run("ip link set up dev  R2-eth4")
212    r2.run("ip link set up dev  R2-eth5")
213    r3.run("ip link set up dev  R3-eth4")
214    r3.run("ip link set up dev  R3-eth5")
215
216    # This is a sample of configuration loading.
217    router_list = tgen.routers()
218
219    # For all registred routers, load the zebra configuration file
220    for rname, router in router_list.iteritems():
221        router.load_config(
222            TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
223        )
224        router.load_config(
225            TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname))
226        )
227        router.load_config(
228            TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
229        )
230
231    # After loading the configurations, this function loads configured daemons.
232    tgen.start_router()
233
234
235def teardown_module(mod):
236    "Teardown the pytest environment"
237    tgen = get_topogen()
238
239    # This function tears down the whole topology.
240    tgen.stop_topology()
241
242
243def vrf_str(vrf):
244    if vrf == "":
245        vrf_str = ""
246    else:
247        vrf_str = "vrf {}".format(vrf)
248
249    return vrf_str
250
251
252def peer_name(rtr, prefix, vrf):
253    "generate VRF string for CLI"
254    if vrf == "":
255        vrf_str = ""
256    else:
257        vrf_str = "_" + vrf
258
259    if prefix == "yes":
260        if rtr == "R2":
261            return "TWO_GROUP" + vrf_str
262        else:
263            return "THREE_GROUP" + vrf_str
264    else:
265        if rtr == "R2":
266            return "2.2.2.2"
267        else:
268            return "3.3.3.3"
269
270
271def print_diag(vrf):
272    "print failure disagnostics"
273
274    tgen = get_topogen()
275    router_list = tgen.routers()
276    for rname, router in router_list.iteritems():
277        print(rname + ":")
278        print(router.vtysh_cmd("show run"))
279        print(router.vtysh_cmd("show ip route {}".format(vrf_str(vrf))))
280        print(router.vtysh_cmd("show bgp {} neighbor".format(vrf_str(vrf))))
281
282
283def configure(conf_file):
284    "configure from a file"
285
286    tgen = get_topogen()
287    router_list = tgen.routers()
288    for rname, router in router_list.iteritems():
289        with open(
290            os.path.join(CWD, "{}/{}").format(router.name, conf_file), "r+"
291        ) as cfg:
292            new_config = cfg.read()
293
294            output = router.vtysh_multicmd(new_config, pretty_output=False)
295            for out_err in ERROR_LIST:
296                if out_err.lower() in output.lower():
297                    raise InvalidCLIError("%s" % output)
298
299
300def clear_bgp(vrf=""):
301    " clear bgp configuration for a vrf"
302
303    tgen = get_topogen()
304    r1 = tgen.gears["R1"]
305    r2 = tgen.gears["R2"]
306    r3 = tgen.gears["R3"]
307
308    router_list = tgen.routers()
309    if vrf == "":
310        r1.vtysh_cmd("conf t\nno router bgp 65001")
311        r2.vtysh_cmd("conf t\nno router bgp 65002")
312        r2.vtysh_cmd("conf t\nno router bgp 65003")
313    else:
314        r1.vtysh_cmd("conf t\nno router bgp 65001 vrf {}".format(vrf))
315        r2.vtysh_cmd("conf t\nno router bgp 65002 vrf {}".format(vrf))
316        r3.vtysh_cmd("conf t\nno router bgp 65003 vrf {}".format(vrf))
317
318
319def clear_ospf(vrf=""):
320    "clear ospf configuration for a vrf"
321
322    tgen = get_topogen()
323    router_list = tgen.routers()
324    for rname, router in router_list.iteritems():
325        if vrf == "":
326            router.vtysh_cmd("conf t\nno router ospf")
327        else:
328            router.vtysh_cmd("conf t\nno router ospf vrf {}".format(vrf))
329
330
331def check_neigh_state(router, peer, state, vrf=""):
332    "check BGP neighbor state on a router"
333
334    count = 0
335    matched = False
336    neigh_output = ""
337    while count < 125:
338        if vrf == "":
339            neigh_output = router.vtysh_cmd("show bgp neighbors {} json".format(peer))
340        else:
341            neigh_output = router.vtysh_cmd(
342                "show bgp vrf {} neighbors {} json".format(vrf, peer)
343            )
344        neigh_output_json = json.loads(neigh_output)
345        if neigh_output_json[peer]["bgpState"] == state:
346            matched = True
347            break
348        count += 1
349        sleep(1)
350
351    assertmsg = "{} could not peer {} state expected {} got {} ".format(
352        router.name, peer, state, neigh_output_json[peer]["bgpState"]
353    )
354    if matched != True:
355        print_diag(vrf)
356    assert matched == True, assertmsg
357
358
359def check_all_peers_established(vrf=""):
360    "standard check for extablished peers per vrf"
361
362    tgen = get_topogen()
363    r1 = tgen.gears["R1"]
364    r2 = tgen.gears["R2"]
365    r3 = tgen.gears["R3"]
366    # do r1 last as he might be the dynamic one
367    check_neigh_state(r2, "1.1.1.1", "Established", vrf)
368    check_neigh_state(r2, "3.3.3.3", "Established", vrf)
369    check_neigh_state(r3, "1.1.1.1", "Established", vrf)
370    check_neigh_state(r3, "2.2.2.2", "Established", vrf)
371    check_neigh_state(r1, "2.2.2.2", "Established", vrf)
372    check_neigh_state(r1, "3.3.3.3", "Established", vrf)
373
374
375def check_vrf_peer_remove_passwords(vrf="", prefix="no"):
376    "selectively remove passwords checking state"
377
378    tgen = get_topogen()
379    r1 = tgen.gears["R1"]
380    r2 = tgen.gears["R2"]
381    r3 = tgen.gears["R3"]
382
383    r1.vtysh_cmd(
384        "conf t\nrouter bgp 65001 {}\nno neighbor {} password".format(
385            vrf_str(vrf), peer_name("R2", prefix, vrf)
386        )
387    )
388
389    check_neigh_state(r2, "1.1.1.1", "Connect", vrf)
390    check_neigh_state(r2, "3.3.3.3", "Established", vrf)
391    check_neigh_state(r3, "1.1.1.1", "Established", vrf)
392    check_neigh_state(r3, "2.2.2.2", "Established", vrf)
393    # don't check dynamic downed peers - they are removed
394    if prefix == "no":
395        check_neigh_state(r1, "2.2.2.2", "Connect", vrf)
396    check_neigh_state(r1, "3.3.3.3", "Established", vrf)
397
398    r2.vtysh_cmd(
399        "conf t\nrouter bgp 65002 {}\nno neighbor 1.1.1.1 password".format(vrf_str(vrf))
400    )
401    check_all_peers_established(vrf)
402
403    r1.vtysh_cmd(
404        "conf t\nrouter bgp 65001 {}\nno neighbor {} password".format(
405            vrf_str(vrf), peer_name("R3", prefix, vrf)
406        )
407    )
408    check_neigh_state(r2, "1.1.1.1", "Established", vrf)
409    check_neigh_state(r2, "3.3.3.3", "Established", vrf)
410    check_neigh_state(r3, "1.1.1.1", "Connect", vrf)
411    check_neigh_state(r3, "2.2.2.2", "Established", vrf)
412    check_neigh_state(r1, "2.2.2.2", "Established", vrf)
413    # don't check dynamic downed peers - they are removed
414    if prefix == "no":
415        check_neigh_state(r1, "3.3.3.3", "Connect", vrf)
416
417    r3.vtysh_cmd(
418        "conf t\nrouter bgp 65003 {}\nno neighbor 1.1.1.1 password".format(vrf_str(vrf))
419    )
420    check_all_peers_established(vrf)
421
422    r2.vtysh_cmd(
423        "conf t\nrouter bgp 65002 {}\nno neighbor 3.3.3.3 password".format(vrf_str(vrf))
424    )
425    check_neigh_state(r2, "1.1.1.1", "Established", vrf)
426    check_neigh_state(r2, "3.3.3.3", "Connect", vrf)
427    check_neigh_state(r3, "1.1.1.1", "Established", vrf)
428    check_neigh_state(r3, "2.2.2.2", "Connect", vrf)
429    check_neigh_state(r1, "2.2.2.2", "Established", vrf)
430    check_neigh_state(r1, "3.3.3.3", "Established", vrf)
431
432    r3.vtysh_cmd(
433        "conf t\nrouter bgp 65003 {}\nno neighbor 2.2.2.2 password".format(vrf_str(vrf))
434    )
435    check_all_peers_established(vrf)
436
437
438def check_vrf_peer_change_passwords(vrf="", prefix="no"):
439    "selectively change passwords checking state"
440
441    tgen = get_topogen()
442    r1 = tgen.gears["R1"]
443    r2 = tgen.gears["R2"]
444    r3 = tgen.gears["R3"]
445    check_all_peers_established(vrf)
446
447    r1.vtysh_cmd(
448        "conf t\nrouter bgp 65001 {}\nneighbor {} password change1".format(
449            vrf_str(vrf), peer_name("R2", prefix, vrf)
450        )
451    )
452    check_neigh_state(r2, "1.1.1.1", "Connect", vrf)
453    check_neigh_state(r2, "3.3.3.3", "Established", vrf)
454    check_neigh_state(r3, "1.1.1.1", "Established", vrf)
455    check_neigh_state(r3, "2.2.2.2", "Established", vrf)
456    # don't check dynamic downed peers - they are removed
457    if prefix == "no":
458        check_neigh_state(r1, "2.2.2.2", "Connect", vrf)
459    check_neigh_state(r1, "3.3.3.3", "Established", vrf)
460
461    r2.vtysh_cmd(
462        "conf t\nrouter bgp 65002 {}\nneighbor 1.1.1.1 password change1".format(
463            vrf_str(vrf)
464        )
465    )
466    check_all_peers_established(vrf)
467
468    r1.vtysh_cmd(
469        "conf t\nrouter bgp 65001 {}\nneighbor {} password change2".format(
470            vrf_str(vrf), peer_name("R3", prefix, vrf)
471        )
472    )
473    check_neigh_state(r2, "1.1.1.1", "Established", vrf)
474    check_neigh_state(r2, "3.3.3.3", "Established", vrf)
475    check_neigh_state(r3, "1.1.1.1", "Connect", vrf)
476    check_neigh_state(r3, "2.2.2.2", "Established", vrf)
477    check_neigh_state(r1, "2.2.2.2", "Established", vrf)
478    # don't check dynamic downed peers - they are removed
479    if prefix == "no":
480        check_neigh_state(r1, "3.3.3.3", "Connect", vrf)
481
482    r3.vtysh_cmd(
483        "conf t\nrouter bgp 65003 {}\nneighbor 1.1.1.1 password change2".format(
484            vrf_str(vrf)
485        )
486    )
487    check_all_peers_established(vrf)
488
489    r2.vtysh_cmd(
490        "conf t\nrouter bgp 65002 {}\nneighbor 3.3.3.3 password change3".format(
491            vrf_str(vrf)
492        )
493    )
494    check_neigh_state(r2, "1.1.1.1", "Established", vrf)
495    check_neigh_state(r2, "3.3.3.3", "Connect", vrf)
496    check_neigh_state(r3, "1.1.1.1", "Established", vrf)
497    check_neigh_state(r3, "2.2.2.2", "Connect", vrf)
498    check_neigh_state(r1, "2.2.2.2", "Established", vrf)
499    check_neigh_state(r1, "3.3.3.3", "Established", vrf)
500
501    r3.vtysh_cmd(
502        "conf t\nrouter bgp 65003 {}\nneighbor 2.2.2.2 password change3".format(
503            vrf_str(vrf)
504        )
505    )
506    check_all_peers_established(vrf)
507
508
509def test_default_peer_established():
510    "default vrf 3 peers same password"
511
512    check_all_peers_established()
513    clear_bgp()
514    # tgen.mininet_cli()
515
516
517def test_default_peer_remove_passwords():
518    "selectively remove passwords checking state"
519
520    configure("bgpd.conf")
521    check_vrf_peer_remove_passwords()
522    clear_bgp()
523
524
525def test_default_peer_change_passwords():
526    "selectively change passwords checking state"
527
528    configure("bgpd.conf")
529    check_vrf_peer_change_passwords()
530    clear_bgp()
531
532
533def test_default_prefix_peer_established():
534    "default vrf 3 peers same password with prefix config"
535
536    # only supported in kernel > 5.3
537    if topotest.version_cmp(platform.release(), "5.3") < 0:
538        return
539
540    configure("bgpd_prefix.conf")
541    check_all_peers_established()
542    clear_bgp()
543    # tgen.mininet_cli()
544
545
546def test_prefix_peer_remove_passwords():
547    "selectively remove passwords checking state with prefix config"
548
549    # only supported in kernel > 5.3
550    if topotest.version_cmp(platform.release(), "5.3") < 0:
551        return
552    configure("bgpd_prefix.conf")
553    check_vrf_peer_remove_passwords(prefix="yes")
554    clear_bgp()
555
556
557def test_prefix_peer_change_passwords():
558    "selecively change passwords checkig state with prefix config"
559
560    # only supported in kernel > 5.3
561    if topotest.version_cmp(platform.release(), "5.3") < 0:
562        return
563    configure("bgpd_prefix.conf")
564    check_vrf_peer_change_passwords(prefix="yes")
565    clear_bgp()
566    clear_ospf()
567
568
569def test_vrf_peer_established():
570    "default vrf 3 peers same password with VRF config"
571
572    # clean routers and load vrf config
573    configure("bgpd_vrf.conf")
574    configure("ospfd_vrf.conf")
575
576    check_all_peers_established("blue")
577    clear_bgp("blue")
578    # tgen.mininet_cli()
579
580
581def test_vrf_peer_remove_passwords():
582    "selectively remove passwords checking state with VRF config"
583
584    configure("bgpd_vrf.conf")
585    check_vrf_peer_remove_passwords(vrf="blue")
586    clear_bgp("blue")
587
588
589def test_vrf_peer_change_passwords():
590    "selectively change passwords checking state with VRF config"
591
592    configure("bgpd_vrf.conf")
593    check_vrf_peer_change_passwords(vrf="blue")
594    clear_bgp("blue")
595
596
597def test_vrf_prefix_peer_established():
598    "default vrf 3 peers same password with VRF prefix config"
599
600    # only supported in kernel > 5.3
601    if topotest.version_cmp(platform.release(), "5.3") < 0:
602        clear_bgp("blue")
603        return
604
605    configure("bgpd_vrf_prefix.conf")
606    check_all_peers_established("blue")
607    clear_bgp("blue")
608
609
610def test_vrf_prefix_peer_remove_passwords():
611    "selectively remove passwords checking state with VRF prefix config"
612
613    # only supported in kernel > 5.3
614    if topotest.version_cmp(platform.release(), "5.3") < 0:
615        return
616
617    configure("bgpd_vrf_prefix.conf")
618    check_vrf_peer_remove_passwords(vrf="blue", prefix="yes")
619    clear_bgp("blue")
620
621
622def test_vrf_prefix_peer_change_passwords():
623    "selectively change passwords checking state with VRF prefix config"
624
625    tgen = get_topogen()
626    r1 = tgen.gears["R1"]
627    r2 = tgen.gears["R2"]
628    r3 = tgen.gears["R3"]
629
630    # only supported in kernel > 5.3
631    if topotest.version_cmp(platform.release(), "5.3") < 0:
632        clear_ospf("blue")
633        return
634
635    configure("bgpd_vrf_prefix.conf")
636    check_vrf_peer_change_passwords(vrf="blue", prefix="yes")
637    clear_bgp("blue")
638    clear_ospf("blue")
639
640
641def test_multiple_vrf_peer_established():
642    "default vrf 3 peers same password with multiple VRFs"
643
644    configure("bgpd_multi_vrf.conf")
645    configure("ospfd_multi_vrf.conf")
646    check_all_peers_established("blue")
647    check_all_peers_established("red")
648    clear_bgp("blue")
649    clear_bgp("red")
650    # tgen.mininet_cli()
651
652
653def test_multiple_vrf_peer_remove_passwords():
654    "selectively remove passwords checking state with multiple VRFs"
655
656    configure("bgpd_multi_vrf.conf")
657    check_vrf_peer_remove_passwords("blue")
658    check_all_peers_established("red")
659    check_vrf_peer_remove_passwords("red")
660    check_all_peers_established("blue")
661    clear_bgp("blue")
662    clear_bgp("red")
663    # tgen.mininet_cli()
664
665
666def test_multiple_vrf_peer_change_passwords():
667    "selectively change passwords checking state with multiple VRFs"
668
669    configure("bgpd_multi_vrf.conf")
670    check_vrf_peer_change_passwords("blue")
671    check_all_peers_established("red")
672    check_vrf_peer_change_passwords("red")
673    check_all_peers_established("blue")
674    clear_bgp("blue")
675    clear_bgp("red")
676    # tgen.mininet_cli()
677
678
679def test_multiple_vrf_prefix_peer_established():
680    "default vrf 3 peers same password with multilpe VRFs and prefix config"
681
682    # only supported in kernel > 5.3
683    if topotest.version_cmp(platform.release(), "5.3") < 0:
684        return
685
686    configure("bgpd_multi_vrf.conf")
687    configure("ospfd_multi_vrf.conf")
688    check_all_peers_established("blue")
689    check_all_peers_established("red")
690    clear_bgp("blue")
691    clear_bgp("red")
692    # tgen.mininet_cli()
693
694
695def test_multiple_vrf_prefix_peer_remove_passwords():
696    "selectively remove passwords checking state with multiple vrfs and prefix config"
697
698    # only supported in kernel > 5.3
699    if topotest.version_cmp(platform.release(), "5.3") < 0:
700        return
701
702    configure("bgpd_multi_vrf_prefix.conf")
703    tgen = get_topogen()
704    check_vrf_peer_remove_passwords(vrf="blue", prefix="yes")
705    check_all_peers_established("red")
706    check_vrf_peer_remove_passwords(vrf="red", prefix="yes")
707    check_all_peers_established("blue")
708    clear_bgp("blue")
709    clear_bgp("red")
710    # tgen.mininet_cli()
711
712
713def test_multiple_vrf_prefix_peer_change_passwords():
714    "selectively change passwords checking state with multiple vrfs and prefix config"
715
716    # only supported in kernel > 5.3
717    if topotest.version_cmp(platform.release(), "5.3") < 0:
718        clear_bgp("blue")
719        clear_bgp("red")
720        clear_ospf("blue")
721        clear_ospf("red")
722        return
723
724    configure("bgpd_multi_vrf_prefix.conf")
725    check_vrf_peer_change_passwords(vrf="blue", prefix="yes")
726    check_all_peers_established("red")
727    check_vrf_peer_change_passwords(vrf="red", prefix="yes")
728    check_all_peers_established("blue")
729    clear_bgp("blue")
730    clear_bgp("red")
731    clear_ospf("blue")
732    clear_ospf("red")
733    # tgen.mininet_cli()
734
735
736def test_memory_leak():
737    "Run the memory leak test and report results."
738    tgen = get_topogen()
739    if not tgen.is_memleak_enabled():
740        pytest.skip("Memory leak test/report is disabled")
741
742    tgen.report_memory_leaks()
743
744
745if __name__ == "__main__":
746    args = ["-s"] + sys.argv[1:]
747    sys.exit(pytest.main(args))
748