Skip to content

Commit d6a4792

Browse files
Overlap vlan finder
1 parent 8882d72 commit d6a4792

File tree

1 file changed

+132
-0
lines changed

1 file changed

+132
-0
lines changed

vlans.py

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import tarfile
2+
from collections import defaultdict
3+
from pyaci.core import aciClassMetas
4+
# from pprint import pprint
5+
import json
6+
7+
8+
class Fabric:
9+
10+
def __init__(self, dc_name, config_file):
11+
self.dc_name = dc_name
12+
self.config_file = config_file
13+
14+
@staticmethod
15+
def _get_dn(_class, attributes, parent_dn):
16+
if attributes.get('dn', '') != '':
17+
return attributes['dn']
18+
if parent_dn == '':
19+
return
20+
rn_template = aciClassMetas.get(_class, {}).get('rnFormat')
21+
if rn_template is None:
22+
return
23+
rn = rn_template.format(**attributes)
24+
return f'{parent_dn}/{rn}'
25+
26+
def _read_mos(self, subtree, mos, parent_dn=''):
27+
for _class, body in subtree.items():
28+
record = body['attributes']
29+
dn = self._get_dn(_class, record, parent_dn)
30+
if dn is None:
31+
continue
32+
33+
# Update indexes
34+
record['dn'] = dn
35+
mos.by_dn[dn] = record
36+
mos.by_class[_class].append(dn)
37+
38+
# Iterate child subtrees
39+
for child in body.get('children', []):
40+
self._read_mos(child, mos, parent_dn=dn)
41+
42+
def extract_config(self):
43+
with tarfile.open(name=self.config_file, mode='r:gz') as tar:
44+
mos = MOs(self.dc_name)
45+
for fi in tar:
46+
if fi.isfile() and fi.name.endswith('.json'):
47+
f = tar.extractfile(fi)
48+
data = json.loads(f.read())
49+
self._read_mos(data, mos)
50+
return mos
51+
52+
53+
class MOs:
54+
55+
def __init__(self, dc_name):
56+
self.dc_name = dc_name
57+
self.by_dn = {}
58+
self.by_class = defaultdict(list)
59+
60+
def get_by_class(self, _class):
61+
return self.by_class.get(_class)
62+
63+
def get_by_dn(self, dn):
64+
return self.by_dn.get(dn)
65+
66+
def get_pool_dn(self, dom_dn):
67+
pool_rs_dn = f'{dom_dn}/rsvlanNs'
68+
pool_rs = self.get_by_dn(pool_rs_dn)
69+
if pool_rs is None:
70+
return
71+
return pool_rs['tDn']
72+
73+
def get_vlans(self, pool_dn):
74+
vlans = set()
75+
if pool_dn is None:
76+
return vlans
77+
for block_dn in self.get_by_class('fvnsEncapBlk'):
78+
if not block_dn.startswith(pool_dn):
79+
continue
80+
block = self.get_by_dn(block_dn)
81+
_from = int(block['from'].split('-')[1])
82+
_to = int(block['to'].split('-')[1])
83+
vlans.update(set(range(_from, _to + 1)))
84+
return vlans
85+
86+
def check_vlan_mappings(self):
87+
doms_by_epg = defaultdict(lambda: {'doms': [], 'overlapping': set()})
88+
89+
for dom_att_dn in self.get_by_class('fvRsDomAtt'):
90+
epg_dn = '/'.join(dom_att_dn.split('/')[:4])
91+
dom_dn = self.get_by_dn(dom_att_dn).get('tDn')
92+
# Ignore everything except physical and VMM
93+
if not dom_dn[4:8] in ['phys', 'vmmp']:
94+
continue
95+
doms_by_epg[epg_dn]['doms'].append(dom_dn)
96+
97+
for epg_dn, metadata in doms_by_epg.items():
98+
if len(metadata['doms']) <= 1:
99+
continue
100+
for dom_dn1 in metadata['doms']:
101+
for dom_dn2 in metadata['doms']:
102+
if dom_dn1 == dom_dn2:
103+
continue
104+
pool_dn1 = self.get_pool_dn(dom_dn1)
105+
pool_dn2 = self.get_pool_dn(dom_dn2)
106+
if pool_dn1 == pool_dn2 or pool_dn1 is None:
107+
continue
108+
vlans1 = self.get_vlans(pool_dn1)
109+
vlans2 = self.get_vlans(pool_dn2)
110+
metadata['overlapping'].update(vlans1.intersection(vlans2))
111+
if len(metadata['overlapping']) > 0:
112+
count = len(metadata['overlapping'])
113+
print(f'{epg_dn}, {count}')
114+
115+
116+
fabrics = [
117+
Fabric('gtn', 'gtn/GTN-ce2_defaultOneTime-2020-11-17T17-00-27.tar.gz'),
118+
Fabric('b12', 'b12/B12-ce2_defaultOneTime-2020-11-17T20-00-55.tar.gz'),
119+
Fabric('det', 'det/DET-ce2_defaultOneTime-2020-11-17T17-08-11.tar.gz'),
120+
Fabric('nlv', 'nlv/NLV-ce2_defaultOneTime-2020-11-17T12-07-26.tar.gz'),
121+
]
122+
123+
124+
def main():
125+
for fabric in fabrics:
126+
mos = fabric.extract_config()
127+
print(fabric.dc_name)
128+
mos.check_vlan_mappings()
129+
130+
131+
if __name__ == '__main__':
132+
main()

0 commit comments

Comments
 (0)