Last active
December 3, 2018 17:36
-
-
Save meunomemauricio/1a1dd58df49ee732e5b042e656f1a1bf to your computer and use it in GitHub Desktop.
Function to calculate the MST Digest from the MST instances and VLANs protected.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/python | |
import re | |
import hmac | |
import base64 | |
# Key specified by 802.1Q-2011, table 13-1 | |
# Key is encoded in Base64 | |
MAGIC_KEY = 'E6wGpi5H/VH5XSuiQ80DRg==' | |
def get_list_from_range_string(range_str): | |
"""Parse the String and return a list of integers. | |
Use '-' to specify a range, or ',' to separate VLAN IDs in a list. | |
Spaces and Negative numbers are not permitted. Zero is fine. | |
Examples: | |
'1' => [1] | |
'1-5' => [1, 2, 3, 4, 5] | |
'1-2,4-5' => [1, 2, 4, 5] | |
""" | |
final_list = set() | |
# Use split to separate groups | |
for item in range_str.split(','): | |
try: | |
# Use RegEx to find ranges whitin the Groups | |
match = re.match('(\d+)-(\d+)', item) | |
if match: | |
values = range(int(match.group(1)), int(match.group(2))+1) | |
# Use the |= operator (union) to add the range to the set | |
final_list |= set(values) | |
else: | |
final_list.add(int(item)) | |
except ValueError: | |
raise RuntimeError('Could not parse the string correctly.') | |
return list(final_list) | |
def calculate_mst_digest(mst_config): | |
"""Calculate the MST Configuration Digest of a Switch. | |
VLANs must be specified as a dictionary in which the keys are MST | |
instances and the value a vlan range string with every vlan the | |
instance contains. | |
ex:. mst_config = { | |
1: '1,10-19,100', | |
2: '2,20-29,200', | |
3: '3,30-39,300', | |
} | |
Based on http://www.fragmentationneeded.net/2015/01/manually-calculating-mst-digests.html # noqa | |
""" | |
# Convert the Range Strings to a list of VLANs | |
for mst_instance, range_string in mst_config.iteritems(): | |
mst_config[mst_instance] = get_list_from_range_string(range_string) | |
# Create a list with 4096 positions | |
instance_table = [0] * 4096 | |
# Each position in the instance-table represents a VLAN and the value in | |
# that position is the MST instance protecting that VLAN | |
for mst_instance, vlans in mst_config.iteritems(): | |
for vlan in vlans: | |
instance_table[vlan] = int(mst_instance) | |
# Convert MST instance numbers into one big bit string (each instance is 16 | |
# bits) | |
bit_string = '' | |
for instance in instance_table: | |
# First most significant 8bits | |
bit_string += '{0:02}'.format(instance / 256).decode('hex') | |
# Least significant 8 bits | |
bit_string += '{0:02}'.format(instance % 256).decode('hex') | |
# Perform HMAC MD5 hash using the key from 802.1Q | |
digest = hmac.new(base64.b64decode(MAGIC_KEY), bit_string) | |
return digest.hexdigest() | |
def main(): | |
"""Executes the function using the same values as the example.""" | |
vlans = { | |
1: '1,10-19,100', | |
2: '2,20-29,200', | |
3: '3,30-39,300', | |
} | |
print('MST Digest: {}'.format(calculate_mst_digest(vlans))) | |
if __name__ == '__main__': | |
main() |
Indeed, Chris! It helped me a lot in a previous job. Thanks for sharing the knowledge!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I see that my blog inspired this code. I'm happy to know you found it useful!
/chris