Skip to content

Instantly share code, notes, and snippets.

@clouetb
Last active April 9, 2020 20:23
Show Gist options
  • Save clouetb/0719ed518cb3484eeb9696a56c6ad560 to your computer and use it in GitHub Desktop.
Save clouetb/0719ed518cb3484eeb9696a56c6ad560 to your computer and use it in GitHub Desktop.
A utility for flattening CISCO 'show system internal l2fm l2dbg macdb' command output
#!/usr/bin/env python3
import regex as re
from sys import argv, exit
macdb_regexpr = r"""
# Some examples matched by this regexp :
# VLAN: 2324 MAC: d867.d972.0fc3
# Time If/swid Db Op Src Slot FE Count
# Mon Apr 6 20:37:34 2020 0x160003e6 0 INSERT 3 5 7
# Mon Apr 6 20:37:59 2020 0x160003e6 0 NON_PI_MOD 3 2 15 6
# Mon Apr 6 21:33:03 2020 0x160003e6 0 FLUSH 2 0 15
#
# VLAN: 1982 MAC: d4d2.52ca.931a FE ID: 4
# Time If/swid Db Op Src Slot FE Count
# Tue Apr 7 12:54:21 2020 0x16000024 0 AGE 3 5 4
# Tue Apr 7 16:38:00 2020 0x16000024 0 AGE 3 6 4
#
# VLAN: 197 MAC: 0000.0c9f.f0c5
# Time If Db Op Src Slot FE Local Remote
# Tue Apr 7 22:20:01 2020 0x090300c5 1 MAC_SMLIST 2 0 15 0 0
# Tue Apr 7 22:20:01 2020 0x090300c5 1 GWMAC_SKIP_NO_CHG 2 0 15 0 0
# Test this regexp here https://regex101.com/r/dA9sQ5/8
(?(DEFINE)
(?P<vlan_descriptor> # A VLAN descriptor is an header with either a local or a remote descriptor
(?&vlan_header)
(?&local_or_remote_vlan)
)
(?P<local_or_remote_vlan> # A VLAN can be either local or remote
(?&local_vlan)
|
(?&remote_vlan)
)
(?P<local_vlan> # Local VLAN has local column header "Time If/swid Db Op Src Slot FE Count" and local columns
(?&local_vlan_column_header)
(?&local_vlan_event)+ # and several local style events
)
(?P<local_vlan_column_header>\s*Time\s*If\/swid\s*Db\s*Op\s*Src\s*Slot\s*FE\s*Count)
(?P<local_vlan_event>\s*(?&full_date)\s*(?&ifswid)\s*(?&db)\s*(?&op)\s*(?&src)\s*(?&slot)\s*(?&fe)\s*(?&count)?)
(?P<remote_vlan> # Remote VLAN has remote column header "Time If Db Op Src Slot FE Local Remote" and local columns
(?&remote_vlan_column_header)
(?&remote_vlan_event)+ # and several remote style events
)
(?P<remote_vlan_column_header>\s*Time\s*If\s*Db\s*Op\s*Src\s*Slot\s*FE\s*Local\s*Remote)
(?P<remote_vlan_event>\s*(?&full_date)\s*(?&ifswid)\s*(?&db)\s*(?&op)\s*(?&src)\s*(?&slot)\s*(?&fe)\s*(?&local)\s*(?&remote))
# VLAN header has VLAN id and MAC address and possibly an FE ID
(?P<vlan_header>\s*VLAN:\s*(?&vlan_id)\s*MAC:\s*(?&mac_address)\s*(FE\ ID:\s*(?&feid))?)
(?P<vlan_id>[0-9]+)
(?P<mac_address>[0-9a-f]{4}.[0-9a-f]{4}.[0-9a-f]{4})
(?P<feid>[0-9]+)
(?P<full_date>(?&day)\s*(?&month)\s*(?&day_in_month)\s*(?&time)\s*(?&year))
(?P<day>Mon|Tue|Wed|Thu|Fri|Sat|Sun)
(?P<day_in_month>[0-9]+)
(?P<month>Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
(?P<year>[0-9]{4})
(?P<time>([0-1][0-9]|[2][0-3]):([0-5][0-9]):([0-5][0-9]))
(?P<ifswid>0x[0-9a-f]{8})
(?P<op>[A-Z]([A-Z_]*))
(?P<db>[0-9]+)
(?P<src>[0-9]+)
(?P<slot>[0-9]+)
(?P<fe>[0-9]+)
(?P<count>([0-9]+))
(?P<local>([0-9]+))
(?P<remote>([0-9]+))
)
# Match all kind of VLAN descriptors (see above)
(?&vlan_descriptor)
"""
if len(argv) < 2:
print(f"""Usage :\n\t{__file__} [macdb file]""")
exit(1)
# Open parameter on command line
buffer = open(argv[1]).read()
expression = re.compile(macdb_regexpr, re.MULTILINE | re.VERBOSE)
# Extract all the matches in the specified file
matches = expression.finditer(buffer)
for match in matches:
# Returns a dict where each column contents is in a list
match_dict = match.capturesdict()
# VLAN type Local or Remote (don't know if useful)
local_or_remote = "L" if match_dict["local_vlan"] else "R"
for counter, event in enumerate(match_dict["full_date"], start=0):
# Output format is VLAN_ID;MAC_ADDR;L or R;Date and time;If/Swid;Op
print(
f"{match_dict['vlan_id'][0]};{match_dict['mac_address'][0]};"
f"{local_or_remote};{match_dict['full_date'][counter]};{match_dict['ifswid'][counter]};"
f"{match_dict['op'][counter]}"
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment