]>
Commit | Line | Data |
---|---|---|
7c653fc5 HS |
1 | #!/usr/bin/env python |
2 | ||
3 | # | |
4 | # Part of NetDEF Topology Tests | |
5 | # | |
6 | # Copyright (c) 2018, LabN Consulting, L.L.C. | |
7 | # Authored by Lou Berger <lberger@labn.net> | |
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 | import os | |
25 | import re | |
26 | import sys | |
27 | import json | |
28 | import functools | |
29 | import pytest | |
30 | ||
31 | CWD = os.path.dirname(os.path.realpath(__file__)) | |
32 | sys.path.append(os.path.join(CWD, "../")) | |
33 | ||
34 | # pylint: disable=C0413 | |
35 | # Import topogen and topotest helpers | |
36 | from lib import topotest | |
37 | from lib.topogen import Topogen, TopoRouter, get_topogen | |
38 | from lib.topolog import logger | |
39 | from lib.common_config import required_linux_kernel_version | |
40 | from mininet.topo import Topo | |
41 | ||
42 | ||
43 | class Topology(Topo): | |
44 | """ | |
45 | CE1 CE3 CE5 | |
46 | (eth0) (eth0) (eth0) | |
47 | :2 :2 :2 | |
48 | | | | | |
49 | 2001: 2001: 2001: | |
50 | 1::/64 3::/64 5::/64 | |
51 | | | | | |
52 | :1 :1 :1 | |
53 | +-(eth1)--(eth2)---(eth3)-+ | |
54 | | \ / | | | |
55 | | (vrf10) (vrf20) | | |
56 | | R1 | | |
57 | +----------(eth0)---------+ | |
58 | :1 | |
59 | | | |
60 | 2001::/64 | |
61 | | | |
62 | :2 | |
63 | (eth0) | |
64 | +----------(eth0)--------------+ | |
65 | | R2 | | |
66 | | (vrf10) (vrf20) | | |
67 | | / / \ | | |
68 | +-(eth1)-----(eth2)-----(eth3)-+ | |
69 | :1 :1 :1 | |
70 | | | | | |
71 | +------+ +------+ +------+ | |
72 | / 2001: \ / 2001: \ / 2001: \ | |
73 | \ 2::/64 / \ 4::/64 / \ 6::/64 / | |
74 | +------+ +------+ +------+ | |
75 | | | | | |
76 | :2 :2 :2 | |
77 | (eth0) (eth0) (eth0) | |
78 | CE2 CE4 CE6 | |
79 | """ | |
80 | def build(self, *_args, **_opts): | |
81 | tgen = get_topogen(self) | |
82 | tgen.add_router("r1") | |
83 | tgen.add_router("r2") | |
84 | tgen.add_router("ce1") | |
85 | tgen.add_router("ce2") | |
86 | tgen.add_router("ce3") | |
87 | tgen.add_router("ce4") | |
88 | tgen.add_router("ce5") | |
89 | tgen.add_router("ce6") | |
90 | ||
91 | tgen.add_link(tgen.gears["r1"], tgen.gears["r2"], "eth0", "eth0") | |
92 | tgen.add_link(tgen.gears["ce1"], tgen.gears["r1"], "eth0", "eth1") | |
93 | tgen.add_link(tgen.gears["ce2"], tgen.gears["r2"], "eth0", "eth1") | |
94 | tgen.add_link(tgen.gears["ce3"], tgen.gears["r1"], "eth0", "eth2") | |
95 | tgen.add_link(tgen.gears["ce4"], tgen.gears["r2"], "eth0", "eth2") | |
96 | tgen.add_link(tgen.gears["ce5"], tgen.gears["r1"], "eth0", "eth3") | |
97 | tgen.add_link(tgen.gears["ce6"], tgen.gears["r2"], "eth0", "eth3") | |
98 | ||
99 | ||
100 | def setup_module(mod): | |
101 | result = required_linux_kernel_version("4.15") | |
102 | if result is not True: | |
103 | pytest.skip("Kernel requirements are not met") | |
104 | ||
105 | tgen = Topogen(Topology, mod.__name__) | |
106 | tgen.start_topology() | |
107 | router_list = tgen.routers() | |
108 | for rname, router in tgen.routers().items(): | |
109 | router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) | |
110 | router.load_config(TopoRouter.RD_ZEBRA, | |
111 | os.path.join(CWD, '{}/zebra.conf'.format(rname))) | |
112 | router.load_config(TopoRouter.RD_BGP, | |
113 | os.path.join(CWD, '{}/bgpd.conf'.format(rname))) | |
114 | ||
115 | tgen.gears["r1"].run("ip link add vrf10 type vrf table 10") | |
116 | tgen.gears["r1"].run("ip link set vrf10 up") | |
117 | tgen.gears["r1"].run("ip link add vrf20 type vrf table 20") | |
118 | tgen.gears["r1"].run("ip link set vrf20 up") | |
119 | tgen.gears["r1"].run("ip link set eth1 master vrf10") | |
120 | tgen.gears["r1"].run("ip link set eth2 master vrf10") | |
121 | tgen.gears["r1"].run("ip link set eth3 master vrf20") | |
122 | ||
123 | tgen.gears["r2"].run("ip link add vrf10 type vrf table 10") | |
124 | tgen.gears["r2"].run("ip link set vrf10 up") | |
125 | tgen.gears["r2"].run("ip link add vrf20 type vrf table 20") | |
126 | tgen.gears["r2"].run("ip link set vrf20 up") | |
127 | tgen.gears["r2"].run("ip link set eth1 master vrf10") | |
128 | tgen.gears["r2"].run("ip link set eth2 master vrf20") | |
129 | tgen.gears["r2"].run("ip link set eth3 master vrf20") | |
130 | tgen.start_router() | |
131 | ||
132 | ||
133 | def teardown_module(mod): | |
134 | tgen = get_topogen() | |
135 | tgen.stop_topology() | |
136 | ||
137 | ||
138 | def open_json_file(filename): | |
139 | try: | |
140 | with open(filename, "r") as f: | |
141 | return json.load(f) | |
142 | except IOError: | |
143 | assert False, "Could not read file {}".format(filename) | |
144 | ||
145 | ||
146 | def test_rib(): | |
147 | def _check(name, cmd, expected_file): | |
148 | logger.info("polling") | |
149 | tgen = get_topogen() | |
150 | router = tgen.gears[name] | |
151 | output = json.loads(router.vtysh_cmd(cmd)) | |
152 | expected = open_json_file("{}/{}".format(CWD, expected_file)) | |
153 | return topotest.json_cmp(output, expected) | |
154 | ||
155 | def check(name, cmd, expected_file): | |
156 | logger.info("[+] check {} \"{}\" {}".format(name, cmd, expected_file)) | |
157 | tgen = get_topogen() | |
158 | func = functools.partial(_check, name, cmd, expected_file) | |
159 | success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) | |
160 | assert result is None, 'Failed' | |
161 | ||
162 | check("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib.json") | |
163 | check("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib.json") | |
164 | check("r1", "show ipv6 route vrf vrf10 json", "r1/vrf10_rib.json") | |
165 | check("r1", "show ipv6 route vrf vrf20 json", "r1/vrf20_rib.json") | |
166 | check("r2", "show ipv6 route vrf vrf10 json", "r2/vrf10_rib.json") | |
167 | check("r2", "show ipv6 route vrf vrf20 json", "r2/vrf20_rib.json") | |
168 | check("ce1", "show ipv6 route json", "ce1/ipv6_rib.json") | |
169 | check("ce2", "show ipv6 route json", "ce2/ipv6_rib.json") | |
170 | check("ce3", "show ipv6 route json", "ce3/ipv6_rib.json") | |
171 | check("ce4", "show ipv6 route json", "ce4/ipv6_rib.json") | |
172 | check("ce5", "show ipv6 route json", "ce5/ipv6_rib.json") | |
173 | check("ce6", "show ipv6 route json", "ce6/ipv6_rib.json") | |
174 | ||
175 | ||
176 | def test_ping(): | |
177 | def _check(name, dest_addr, match): | |
178 | tgen = get_topogen() | |
179 | output = tgen.gears[name].run("ping6 {} -c 1 -w 1".format(dest_addr)) | |
180 | logger.info(output) | |
181 | assert match in output, "ping fail" | |
182 | ||
183 | def check(name, dest_addr, match): | |
184 | logger.info("[+] check {} {} {}".format(name, dest_addr, match)) | |
185 | tgen = get_topogen() | |
186 | func = functools.partial(_check, name, dest_addr, match) | |
187 | success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) | |
188 | assert result is None, 'Failed' | |
189 | ||
190 | check("ce1", "2001:2::2", " 0% packet loss") | |
191 | check("ce1", "2001:3::2", " 0% packet loss") | |
192 | check("ce1", "2001:4::2", " 100% packet loss") | |
193 | check("ce1", "2001:5::2", " 100% packet loss") | |
194 | check("ce1", "2001:6::2", " 100% packet loss") | |
195 | check("ce4", "2001:1::2", " 100% packet loss") | |
196 | check("ce4", "2001:2::2", " 100% packet loss") | |
197 | check("ce4", "2001:3::2", " 100% packet loss") | |
198 | check("ce4", "2001:5::2", " 0% packet loss") | |
199 | check("ce4", "2001:6::2", " 0% packet loss") | |
200 | ||
201 | ||
202 | if __name__ == "__main__": | |
203 | args = ["-s"] + sys.argv[1:] | |
204 | sys.exit(pytest.main(args)) |