Skip to content

Instantly share code, notes, and snippets.

@meunomemauricio
Last active December 3, 2018 17:36
Show Gist options
  • Save meunomemauricio/1a1dd58df49ee732e5b042e656f1a1bf to your computer and use it in GitHub Desktop.
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.
#! /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()
@chrismarget
Copy link

I see that my blog inspired this code. I'm happy to know you found it useful!

/chris

@meunomemauricio
Copy link
Author

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