]> git.proxmox.com Git - mirror_frr.git/blame - tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py
(all tests): Add extra check to make sure daemons are still running after each essent...
[mirror_frr.git] / tests / topotests / bgp_multiview_topo1 / test_bgp_multiview_topo1.py
CommitLineData
586e15c4
MW
1#!/usr/bin/env python
2
3#
4# test_bgp_multiview_topo1.py
5# Part of NetDEF Topology Tests
6#
7# Copyright (c) 2016 by
8# Network Device Education Foundation, Inc. ("NetDEF")
9#
10# Permission to use, copy, modify, and/or distribute this software
11# for any purpose with or without fee is hereby granted, provided
12# that the above copyright notice and this permission notice appear
13# in all copies.
14#
15# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
16# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
18# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
19# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
21# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22# OF THIS SOFTWARE.
23#
24
25"""
594b1259 26test_bgp_multiview_topo1.py: Simple Quagga/FRR Route-Server Test
586e15c4 27
04df53ab
MW
28+----------+ +----------+ +----------+ +----------+ +----------+
29| peer1 | | peer2 | | peer3 | | peer4 | | peer5 |
30| AS 65001 | | AS 65002 | | AS 65003 | | AS 65004 | | AS 65005 |
31+-----+----+ +-----+----+ +-----+----+ +-----+----+ +-----+----+
32 | .1 | .2 | .3 | .4 | .5
33 | ______/ / / _________/
34 \ / ________________/ / /
35 | | / _________________________/ / +----------+
36 | | | / __________________________/ ___| peer6 |
37 | | | | / ____________________________/.6 | AS 65006 |
38 | | | | | / _________________________ +----------+
39 | | | | | | / __________________ \ +----------+
40 | | | | | | | / \ \___| peer7 |
41 | | | | | | | | \ .7 | AS 65007 |
42 ~~~~~~~~~~~~~~~~~~~~~ \ +----------+
43 ~~ SW1 ~~ \ +----------+
44 ~~ Switch ~~ \_____| peer8 |
45 ~~ 172.16.1.0/24 ~~ .8 | AS 65008 |
46 ~~~~~~~~~~~~~~~~~~~~~ +----------+
47 |
48 | .254
49 +---------+---------+
594b1259 50 | FRR R1 |
04df53ab
MW
51 | BGP Multi-View |
52 | Peer 1-3 > View 1 |
53 | Peer 4-5 > View 2 |
54 | Peer 6-8 > View 3 |
55 +---------+---------+
56 | .1
57 |
58 ~~~~~~~~~~~~~ Stub Network is redistributed
59 ~~ SW0 ~~ into each BGP view with different
60 ~~ 172.20.0.1/28 ~~ attributes (using route-map)
61 ~~ Stub Switch ~~
62 ~~~~~~~~~~~~~
63"""
586e15c4
MW
64
65import os
66import re
67import sys
68import difflib
594b1259
MW
69import pytest
70from time import sleep
586e15c4
MW
71
72from mininet.topo import Topo
73from mininet.net import Mininet
74from mininet.node import Node, OVSSwitch, Host
75from mininet.log import setLogLevel, info
76from mininet.cli import CLI
77from mininet.link import Intf
78
79from functools import partial
586e15c4 80
594b1259
MW
81sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
82from lib import topotest
586e15c4 83
2cda38e4
MW
84fatal_error = ""
85
586e15c4
MW
86
87#####################################################
88##
89## Network Topology Definition
90##
91#####################################################
92
93class NetworkTopo(Topo):
594b1259 94 "BGP Multiview Topology 1"
586e15c4
MW
95
96 def build(self, **_opts):
97
586e15c4
MW
98 exabgpPrivateDirs = ['/etc/exabgp',
99 '/var/run/exabgp',
100 '/var/log']
594b1259 101
586e15c4 102 # Setup Routers
594b1259 103 router = {}
586e15c4 104 for i in range(1, 2):
594b1259 105 router[i] = topotest.addRouter(self, 'r%s' % i)
586e15c4
MW
106
107 # Setup Provider BGP peers
108 peer = {}
109 for i in range(1, 9):
110 peer[i] = self.addHost('peer%s' % i, ip='172.16.1.%s/24' % i,
111 defaultRoute='via 172.16.1.254',
112 privateDirs=exabgpPrivateDirs)
113
114 # Setup Switches
115 switch = {}
116 # First switch is for a dummy interface (for local network)
594b1259
MW
117 switch[0] = self.addSwitch('sw0', cls=topotest.LegacySwitch)
118 self.addLink(switch[0], router[1], intfName2='r1-stub')
586e15c4 119 # Second switch is for connection to all peering routers
594b1259
MW
120 switch[1] = self.addSwitch('sw1', cls=topotest.LegacySwitch)
121 self.addLink(switch[1], router[1], intfName2='r1-eth0')
586e15c4
MW
122 for j in range(1, 9):
123 self.addLink(switch[1], peer[j], intfName2='peer%s-eth0' % j)
124
125
126#####################################################
127##
128## Tests starting
129##
130#####################################################
131
132def setup_module(module):
133 global topo, net
134
135 print("\n\n** %s: Setup Topology" % module.__name__)
136 print("******************************************\n")
137
138 print("Cleanup old Mininet runs")
139 os.system('sudo mn -c > /dev/null 2>&1')
140
141 thisDir = os.path.dirname(os.path.realpath(__file__))
142 topo = NetworkTopo()
143
144 net = Mininet(controller=None, topo=topo)
145 net.start()
146
147 # Starting Routers
148 for i in range(1, 2):
149 net['r%s' % i].loadConf('zebra', '%s/r%s/zebra.conf' % (thisDir, i))
150 net['r%s' % i].loadConf('bgpd', '%s/r%s/bgpd.conf' % (thisDir, i))
594b1259 151 net['r%s' % i].startRouter()
586e15c4
MW
152
153 # Starting PE Hosts and init ExaBGP on each of them
154 print('*** Starting BGP on all 8 Peers in 10s')
155 sleep(10)
156 for i in range(1, 9):
157 net['peer%s' % i].cmd('cp %s/exabgp.env /etc/exabgp/exabgp.env' % thisDir)
158 net['peer%s' % i].cmd('cp %s/peer%s/* /etc/exabgp/' % (thisDir, i))
159 net['peer%s' % i].cmd('chmod 644 /etc/exabgp/*')
160 net['peer%s' % i].cmd('chmod 755 /etc/exabgp/*.py')
161 net['peer%s' % i].cmd('chown -R exabgp:exabgp /etc/exabgp')
162 net['peer%s' % i].cmd('exabgp -e /etc/exabgp/exabgp.env /etc/exabgp/exabgp.cfg')
163 print('peer%s' % i),
164 print('')
165
594b1259 166 # For debugging after starting Quagga/FRR daemons, uncomment the next line
586e15c4
MW
167 # CLI(net)
168
169def teardown_module(module):
170 global net
171
172 print("\n\n** %s: Shutdown Topology" % module.__name__)
173 print("******************************************\n")
174
175 # Shutdown - clean up everything
176 print('*** Killing BGP on Peer routers')
177 # Killing ExaBGP
178 for i in range(1, 9):
179 net['peer%s' % i].cmd('kill `cat /var/run/exabgp/exabgp.pid`')
180
181 # End - Shutdown network
182 net.stop()
183
594b1259 184def test_router_running():
2cda38e4 185 global fatal_error
586e15c4
MW
186 global net
187
2cda38e4
MW
188 # Skip if previous fatal error condition is raised
189 if (fatal_error != ""):
190 pytest.skip(fatal_error)
191
b36d3e1c 192 print("\n\n** Check if FRR/Quagga is running on each Router node")
586e15c4
MW
193 print("******************************************\n")
194 sleep(5)
195
594b1259 196 # Starting Routers
e631b518 197 for i in range(1, 2):
594b1259
MW
198 fatal_error = net['r%s' % i].checkRouterRunning()
199 assert fatal_error == "", fatal_error
200
201 # For debugging after starting FRR/Quagga daemons, uncomment the next line
202 # CLI(net)
203
586e15c4
MW
204
205def test_bgp_converge():
206 "Check for BGP converged on all peers and BGP views"
207
2cda38e4 208 global fatal_error
586e15c4
MW
209 global net
210
2cda38e4
MW
211 # Skip if previous fatal error condition is raised
212 if (fatal_error != ""):
213 pytest.skip(fatal_error)
214
586e15c4
MW
215 # Wait for BGP to converge (All Neighbors in either Full or TwoWay State)
216 print("\n\n** Verify for BGP to converge")
217 print("******************************************\n")
218 timeout = 60
219 while timeout > 0:
220 print("Timeout in %s: " % timeout),
221 sys.stdout.flush()
222 # Look for any node not yet converged
223 for i in range(1, 2):
224 for view in range(1, 4):
225 notConverged = net['r%s' % i].cmd('vtysh -c "show ip bgp view %s summary" 2> /dev/null | grep ^[0-9] | grep -v " 11$"' % view)
226 if notConverged:
227 print('Waiting for r%s, view %s' % (i, view))
228 sys.stdout.flush()
229 break
230 if notConverged:
231 break
232 if notConverged:
233 sleep(5)
234 timeout -= 5
235 else:
236 print('Done')
237 break
238 else:
239 # Bail out with error if a router fails to converge
5b7a4ad3 240 bgpStatus = net['r%s' % i].cmd('vtysh -c "show ip bgp view %s summary"' % view)
586e15c4
MW
241 assert False, "BGP did not converge:\n%s" % bgpStatus
242
b36d3e1c
MW
243 # Wait for an extra 30s to announce all routes
244 print('Waiting 30s for routes to be announced');
245 sleep(30)
246
586e15c4
MW
247 print("BGP converged.")
248
249 # if timeout < 60:
250 # # Only wait if we actually went through a convergence
251 # print("\nwaiting 15s for routes to populate")
252 # sleep(15)
253
7e7fc73b
MW
254 # Make sure that all daemons are running
255 for i in range(1, 2):
256 fatal_error = net['r%s' % i].checkRouterRunning()
257 assert fatal_error == "", fatal_error
258
594b1259 259 # For debugging after starting Quagga/FRR daemons, uncomment the next line
586e15c4
MW
260 # CLI(net)
261
262def test_bgp_routingTable():
2cda38e4 263 global fatal_error
586e15c4
MW
264 global net
265
2cda38e4
MW
266 # Skip if previous fatal error condition is raised
267 if (fatal_error != ""):
268 pytest.skip(fatal_error)
269
586e15c4
MW
270 thisDir = os.path.dirname(os.path.realpath(__file__))
271
b2764f90 272 print("\n\n** Verifying BGP Routing Tables")
586e15c4
MW
273 print("******************************************\n")
274 failures = 0
275 for i in range(1, 2):
276 for view in range(1, 4):
277 refTableFile = '%s/r%s/show_ip_bgp_view_%s.ref' % (thisDir, i, view)
278 if os.path.isfile(refTableFile):
279 # Read expected result from file
280 expected = open(refTableFile).read().rstrip()
281 # Fix newlines (make them all the same)
282 expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
283
284 # Actual output from router
285 actual = net['r%s' % i].cmd('vtysh -c "show ip bgp view %s" 2> /dev/null' % view).rstrip()
286
287 # Fix inconsitent spaces between 0.99.24 and newer versions of Quagga...
288 actual = re.sub('0 0', '0 0', actual)
289 actual = re.sub(r'([0-9]) 32768', r'\1 32768', actual)
290 # Remove summary line (changed recently)
291 actual = re.sub(r'Total number.*', '', actual)
292 actual = re.sub(r'Displayed.*', '', actual)
293 actual = actual.rstrip()
d98b7d63
MW
294 # Fix table version (ignore it)
295 actual = re.sub(r'(BGP table version is )[0-9]+', r'\1XXX', actual)
586e15c4
MW
296
297 # Fix newlines (make them all the same)
298 actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
299
300 # Generate Diff
3b6bac2a
MW
301 diff = ''.join(difflib.context_diff(actual, expected,
302 fromfile="actual BGP routing table",
303 tofile="expected BGP routing table"))
586e15c4
MW
304 # Empty string if it matches, otherwise diff contains unified diff
305
306 if diff:
307 sys.stderr.write('r%s failed Routing Table Check for view %s:\n%s\n'
308 % (i, view, diff))
309 failures += 1
310 else:
311 print("r%s ok" % i)
312
313 assert failures == 0, "Routing Table verification failed for router r%s, view %s:\n%s" % (i, view, diff)
314
7e7fc73b
MW
315 # Make sure that all daemons are running
316 for i in range(1, 2):
317 fatal_error = net['r%s' % i].checkRouterRunning()
318 assert fatal_error == "", fatal_error
319
594b1259 320 # For debugging after starting FRR/Quagga daemons, uncomment the next line
586e15c4
MW
321 # CLI(net)
322
50c40bde 323
99561211
MW
324def test_shutdown_check_stderr():
325 global fatal_error
326 global net
327
328 # Skip if previous fatal error condition is raised
329 if (fatal_error != ""):
330 pytest.skip(fatal_error)
331
332 if os.environ.get('TOPOTESTS_CHECK_STDERR') is None:
50c40bde
MW
333 print("SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n")
334 pytest.skip('Skipping test for Stderr output')
99561211
MW
335
336 thisDir = os.path.dirname(os.path.realpath(__file__))
337
b2764f90 338 print("\n\n** Verifying unexpected STDERR output from daemons")
99561211
MW
339 print("******************************************\n")
340
341 net['r1'].stopRouter()
342
343 log = net['r1'].getStdErr('bgpd')
344 print("\nBGPd StdErr Log:\n" + log)
345 log = net['r1'].getStdErr('zebra')
346 print("\nZebra StdErr Log:\n" + log)
347
586e15c4 348
50c40bde
MW
349def test_shutdown_check_memleak():
350 global fatal_error
351 global net
352
353 # Skip if previous fatal error condition is raised
354 if (fatal_error != ""):
355 pytest.skip(fatal_error)
356
357 if os.environ.get('TOPOTESTS_CHECK_MEMLEAK') is None:
358 print("SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n")
359 pytest.skip('Skipping test for memory leaks')
360
361 thisDir = os.path.dirname(os.path.realpath(__file__))
362
363 net['r1'].stopRouter()
364 net['r1'].report_memory_leaks(os.environ.get('TOPOTESTS_CHECK_MEMLEAK'), os.path.basename(__file__))
365
366
586e15c4
MW
367if __name__ == '__main__':
368
369 setLogLevel('info')
2cda38e4
MW
370 # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli
371 # retval = pytest.main(["-s", "--tb=no"])
586e15c4
MW
372 retval = pytest.main(["-s"])
373 sys.exit(retval)