]>
Commit | Line | Data |
---|---|---|
b1367d68 DA |
1 | #!/usr/bin/env python |
2 | ||
3 | # Copyright (c) 2021 by | |
4 | # Donatas Abraitis <donatas.abraitis@gmail.com> | |
5 | # | |
6 | # Permission to use, copy, modify, and/or distribute this software | |
7 | # for any purpose with or without fee is hereby granted, provided | |
8 | # that the above copyright notice and this permission notice appear | |
9 | # in all copies. | |
10 | # | |
11 | # THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES | |
12 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
13 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR | |
14 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY | |
15 | # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
16 | # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS | |
17 | # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | |
18 | # OF THIS SOFTWARE. | |
19 | # | |
20 | ||
21 | """ | |
22 | https://tools.ietf.org/html/rfc4271 | |
23 | ||
24 | Check if NEXT_HOP attribute is not changed if peer X shares a | |
25 | common subnet with this address. | |
26 | ||
27 | - Otherwise, if the route being announced was learned from an | |
28 | external peer, the speaker can use an IP address of any | |
29 | adjacent router (known from the received NEXT_HOP attribute) | |
30 | that the speaker itself uses for local route calculation in | |
31 | the NEXT_HOP attribute, provided that peer X shares a common | |
32 | subnet with this address. This is a second form of "third | |
33 | party" NEXT_HOP attribute. | |
34 | """ | |
35 | ||
36 | import os | |
37 | import sys | |
38 | import json | |
39 | import time | |
40 | import pytest | |
41 | import functools | |
42 | ||
ad889e0d DA |
43 | pytestmark = [pytest.mark.bgpd] |
44 | ||
b1367d68 DA |
45 | CWD = os.path.dirname(os.path.realpath(__file__)) |
46 | sys.path.append(os.path.join(CWD, "../")) | |
47 | ||
48 | # pylint: disable=C0413 | |
49 | from lib import topotest | |
50 | from lib.topogen import Topogen, TopoRouter, get_topogen | |
51 | from lib.topolog import logger | |
8db751b8 | 52 | from lib.micronet_compat import Topo |
b1367d68 | 53 | |
bf3a0a9a DS |
54 | pytestmark = [pytest.mark.bgpd] |
55 | ||
b1367d68 DA |
56 | |
57 | class TemplateTopo(Topo): | |
58 | def build(self, *_args, **_opts): | |
59 | tgen = get_topogen(self) | |
60 | ||
61 | for routern in range(1, 4): | |
62 | tgen.add_router("r{}".format(routern)) | |
63 | ||
64 | switch = tgen.add_switch("s1") | |
65 | switch.add_link(tgen.gears["r1"]) | |
66 | switch.add_link(tgen.gears["r2"]) | |
67 | switch.add_link(tgen.gears["r3"]) | |
68 | ||
69 | ||
70 | def setup_module(mod): | |
71 | tgen = Topogen(TemplateTopo, mod.__name__) | |
72 | tgen.start_topology() | |
73 | ||
74 | router_list = tgen.routers() | |
75 | ||
76 | for i, (rname, router) in enumerate(router_list.items(), 1): | |
77 | router.load_config( | |
78 | TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) | |
79 | ) | |
80 | router.load_config( | |
81 | TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) | |
82 | ) | |
83 | ||
84 | tgen.start_router() | |
85 | ||
86 | ||
87 | def teardown_module(mod): | |
88 | tgen = get_topogen() | |
89 | tgen.stop_topology() | |
90 | ||
91 | ||
92 | def test_bgp_ebgp_common_subnet_nh_unchanged(): | |
93 | tgen = get_topogen() | |
94 | ||
95 | if tgen.routers_have_failure(): | |
96 | pytest.skip(tgen.errors) | |
97 | ||
98 | r2 = tgen.gears["r2"] | |
99 | r3 = tgen.gears["r3"] | |
100 | ||
101 | def _bgp_converge(router): | |
102 | output = json.loads(router.vtysh_cmd("show ip bgp summary json")) | |
103 | expected = { | |
104 | "ipv4Unicast": { | |
105 | "peers": { | |
106 | "192.168.1.1": {"state": "Established"}, | |
107 | "192.168.1.103": {"state": "Established"}, | |
108 | } | |
109 | } | |
110 | } | |
111 | return topotest.json_cmp(output, expected) | |
112 | ||
113 | test_func = functools.partial(_bgp_converge, r3) | |
114 | success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) | |
115 | ||
116 | assert result is None, 'Failed bgp convergence in "{}"'.format(r3) | |
117 | ||
118 | def _bgp_nh_unchanged(router): | |
119 | output = json.loads(router.vtysh_cmd("show ip bgp 172.16.1.1/32 json")) | |
120 | expected = {"paths": [{"nexthops": [{"ip": "192.168.1.1"}]}]} | |
121 | return topotest.json_cmp(output, expected) | |
122 | ||
123 | test_func = functools.partial(_bgp_nh_unchanged, r2) | |
124 | success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) | |
125 | ||
126 | assert result is None, 'Wrong next-hop in "{}"'.format(r2) | |
127 | ||
128 | ||
129 | if __name__ == "__main__": | |
130 | args = ["-s"] + sys.argv[1:] | |
131 | sys.exit(pytest.main(args)) |