]>
Commit | Line | Data |
---|---|---|
8a28936d | 1 | #!/usr/bin/env python |
acddc0ed | 2 | # SPDX-License-Identifier: GPL-2.0-or-later |
8a28936d | 3 | |
d5214400 | 4 | # Copyright 2018, LabN Consulting, L.L.C. |
d5214400 | 5 | |
787e7624 | 6 | # |
8a28936d | 7 | # want_rd_routes = [ |
b4bfe0aa LB |
8 | # {'rd':'10:1', 'p':'5.1.0.0/24', 'n':'1.1.1.1', 'bp': True}, |
9 | # {'rd':'10:1', 'p':'5.1.0.0/24', 'n':'1.1.1.1', 'bp': False}, | |
787e7624 | 10 | # |
8a28936d PZ |
11 | # {'rd':'10:3', 'p':'5.1.0.0/24', 'n':'3.3.3.3'}, |
12 | # ] | |
787e7624 | 13 | # |
8a28936d PZ |
14 | # ribRequireVpnRoutes('r2','Customer routes',want_rd_routes) |
15 | # | |
16 | # want_unicast_routes = [ | |
17 | # {'p':'5.1.0.0/24', 'n':'1.1.1.1'}, | |
18 | # ] | |
19 | # | |
20 | # ribRequireUnicastRoutes('r1','ipv4','r1-cust1','Customer routes in vrf',want_unicast_routes) | |
21 | # ribRequireUnicastRoutes('r1','ipv4','','Customer routes in default',want_unicast_routes) | |
22 | # | |
23 | ||
c8e5983d | 24 | from lib.lutil import luCommand, luResult, LUtil |
8a28936d | 25 | import json |
587e28a4 | 26 | import re |
8a28936d | 27 | |
fea00bad | 28 | |
8a28936d | 29 | # gpz: get rib in json form and compare against desired routes |
044e2a31 | 30 | class BgpRib: |
b4bfe0aa | 31 | def log(self, str): |
701a0192 | 32 | LUtil.log("BgpRib: " + str) |
b4bfe0aa | 33 | |
787e7624 | 34 | def routes_include_wanted(self, pfxtbl, want, debug): |
35 | # helper function to RequireVpnRoutes | |
e7294b32 | 36 | for pfx in pfxtbl.keys(): |
787e7624 | 37 | if debug: |
b4bfe0aa | 38 | self.log("trying pfx %s" % pfx) |
2bb8b49c | 39 | if pfx != want["p"]: |
787e7624 | 40 | if debug: |
b4bfe0aa | 41 | self.log("want pfx=" + want["p"] + ", not " + pfx) |
787e7624 | 42 | continue |
43 | if debug: | |
b4bfe0aa | 44 | self.log("have pfx=%s" % pfx) |
787e7624 | 45 | for r in pfxtbl[pfx]: |
b4bfe0aa | 46 | bp = r.get("bestpath", False) |
787e7624 | 47 | if debug: |
b4bfe0aa | 48 | self.log("trying route %s bp=%s" % (r, bp)) |
787e7624 | 49 | nexthops = r["nexthops"] |
50 | for nh in nexthops: | |
51 | if debug: | |
b4bfe0aa | 52 | self.log("trying nh %s" % nh["ip"]) |
787e7624 | 53 | if nh["ip"] == want["n"]: |
54 | if debug: | |
b4bfe0aa LB |
55 | self.log("found %s" % want["n"]) |
56 | if bp == want.get("bp", bp): | |
57 | return 1 | |
58 | elif debug: | |
59 | self.log("bestpath mismatch %s != %s" % (bp, want["bp"])) | |
787e7624 | 60 | else: |
61 | if debug: | |
b4bfe0aa | 62 | self.log("want nh=" + want["n"] + ", not " + nh["ip"]) |
787e7624 | 63 | if debug: |
b4bfe0aa | 64 | self.log("missing route: pfx=" + want["p"] + ", nh=" + want["n"]) |
787e7624 | 65 | return 0 |
8a28936d | 66 | |
2bb8b49c | 67 | def RequireVpnRoutes(self, target, title, wantroutes, debug=0): |
787e7624 | 68 | import json |
69 | ||
ffd3f544 | 70 | logstr = "RequireVpnRoutes " + str(wantroutes) |
2bb8b49c DS |
71 | # non json form for humans |
72 | luCommand( | |
73 | target, | |
74 | 'vtysh -c "show bgp ipv4 vpn"', | |
75 | ".", | |
76 | "None", | |
77 | "Get VPN RIB (non-json)", | |
78 | ) | |
79 | ret = luCommand( | |
80 | target, | |
81 | 'vtysh -c "show bgp ipv4 vpn json"', | |
82 | ".*", | |
83 | "None", | |
84 | "Get VPN RIB (json)", | |
85 | ) | |
86 | if re.search(r"^\s*$", ret): | |
87 | # degenerate case: empty json means no routes | |
88 | if len(wantroutes) > 0: | |
89 | luResult(target, False, title, logstr) | |
90 | return | |
90bdefa0 | 91 | luResult(target, True, title, logstr) |
2bb8b49c DS |
92 | rib = json.loads(ret) |
93 | rds = rib["routes"]["routeDistinguishers"] | |
94 | for want in wantroutes: | |
95 | found = 0 | |
96 | if debug: | |
97 | self.log("want rd %s" % want["rd"]) | |
98 | for rd in rds.keys(): | |
99 | if rd != want["rd"]: | |
100 | continue | |
101 | if debug: | |
102 | self.log("found rd %s" % rd) | |
103 | table = rds[rd] | |
104 | if self.routes_include_wanted(table, want, debug): | |
105 | found = 1 | |
106 | break | |
107 | if not found: | |
108 | luResult(target, False, title, logstr) | |
109 | return | |
110 | luResult(target, True, title, logstr) | |
8a28936d | 111 | |
2bb8b49c | 112 | def RequireUnicastRoutes(self, target, afi, vrf, title, wantroutes, debug=0): |
f89211f7 | 113 | logstr = "RequireUnicastRoutes %s" % str(wantroutes) |
787e7624 | 114 | vrfstr = "" |
115 | if vrf != "": | |
116 | vrfstr = "vrf %s" % (vrf) | |
8a28936d | 117 | |
787e7624 | 118 | if (afi != "ipv4") and (afi != "ipv6"): |
b4bfe0aa | 119 | self.log("ERROR invalid afi") |
8a28936d | 120 | |
2bb8b49c DS |
121 | cmdstr = "show bgp %s %s unicast" % (vrfstr, afi) |
122 | # non json form for humans | |
123 | cmd = 'vtysh -c "%s"' % cmdstr | |
124 | luCommand(target, cmd, ".", "None", "Get %s %s RIB (non-json)" % (vrfstr, afi)) | |
125 | cmd = 'vtysh -c "%s json"' % cmdstr | |
126 | ret = luCommand( | |
127 | target, cmd, ".*", "None", "Get %s %s RIB (json)" % (vrfstr, afi) | |
128 | ) | |
129 | if re.search(r"^\s*$", ret): | |
130 | # degenerate case: empty json means no routes | |
131 | if len(wantroutes) > 0: | |
132 | luResult(target, False, title, logstr) | |
587e28a4 | 133 | return |
ffd3f544 | 134 | luResult(target, True, title, logstr) |
2bb8b49c DS |
135 | rib = json.loads(ret) |
136 | try: | |
137 | table = rib["routes"] | |
138 | # KeyError: 'routes' probably means missing/bad VRF | |
139 | except KeyError as err: | |
140 | if vrf != "": | |
141 | errstr = "-script ERROR: check if wrong vrf (%s)" % (vrf) | |
142 | else: | |
143 | errstr = "-script ERROR: check if vrf missing" | |
144 | luResult(target, False, title + errstr, logstr) | |
145 | return | |
146 | # if debug: | |
147 | # self.log("table=%s" % table) | |
148 | for want in wantroutes: | |
149 | if debug: | |
150 | self.log("want=%s" % want) | |
151 | if not self.routes_include_wanted(table, want, debug): | |
152 | luResult(target, False, title, logstr) | |
153 | return | |
154 | luResult(target, True, title, logstr) | |
8a28936d PZ |
155 | |
156 | ||
787e7624 | 157 | BgpRib = BgpRib() |
158 | ||
8a28936d | 159 | |
2bb8b49c DS |
160 | def bgpribRequireVpnRoutes(target, title, wantroutes, debug=0): |
161 | BgpRib.RequireVpnRoutes(target, title, wantroutes, debug) | |
8a28936d | 162 | |
787e7624 | 163 | |
2bb8b49c DS |
164 | def bgpribRequireUnicastRoutes(target, afi, vrf, title, wantroutes, debug=0): |
165 | BgpRib.RequireUnicastRoutes(target, afi, vrf, title, wantroutes, debug) |