VLAN Manager tool
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

167 lines
4.9 KiB

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. from pysnmp.hlapi import *
  4. from pysnmp.smi.builder import MibBuilder
  5. from pysnmp.smi.view import MibViewController
  6. import random
  7. import unittest
  8. _mbuilder = MibBuilder()
  9. _mvc = MibViewController(_mbuilder)
  10. # received packages
  11. # pvid: dot1qPvid
  12. #
  13. # tx packets:
  14. # dot1qVlanStaticEgressPorts
  15. # dot1qVlanStaticUntaggedPorts
  16. #
  17. # vlans:
  18. # dot1qVlanCurrentTable
  19. # lists ALL vlans, including baked in ones
  20. #
  21. # note that even though an snmpwalk of dot1qVlanStaticEgressPorts
  22. # skips over other vlans (only shows statics), the other vlans (1,2,3)
  23. # are still accessible via that oid
  24. #
  25. # LLDP:
  26. # 1.0.8802.1.1.2.1.4.1.1 aka LLDP-MIB, lldpRemTable
  27. class SNMPSwitch(object):
  28. def __init__(self, host, community):
  29. self._eng = SnmpEngine()
  30. self._cd = CommunityData(community, mpModel=0)
  31. self._targ = UdpTransportTarget((host, 161))
  32. def _get(self, oid):
  33. oid = ObjectIdentity(*oid)
  34. oid.resolveWithMib(_mvc)
  35. errorInd, errorStatus, errorIndex, varBinds = \
  36. next(getCmd(self._eng, self._cd, self._targ, ContextData(), ObjectType(oid)))
  37. if errorInd: # pragma: no cover
  38. raise ValueError(errorIndication)
  39. elif errorStatus:
  40. raise ValueError('%s at %s' %
  41. (errorStatus.prettyPrint(), errorIndex and
  42. varBinds[int(errorIndex)-1][0] or '?'))
  43. else:
  44. if len(varBinds) != 1: # pragma: no cover
  45. raise ValueError('too many return values')
  46. varBind = varBinds[0]
  47. return varBind[1]
  48. def _set(self, oid, value):
  49. oid = ObjectIdentity(*oid)
  50. oid.resolveWithMib(_mvc)
  51. if isinstance(value, (int, long)):
  52. value = Integer(value)
  53. elif isinstance(value, str):
  54. value = OctetString(value)
  55. errorInd, errorStatus, errorIndex, varBinds = \
  56. next(setCmd(self._eng, self._cd, self._targ, ContextData(), ObjectType(oid, value)))
  57. if errorInd: # pragma: no cover
  58. raise ValueError(errorIndication)
  59. elif errorStatus: # pragma: no cover
  60. raise ValueError('%s at %s' %
  61. (errorStatus.prettyPrint(), errorIndex and
  62. varBinds[int(errorIndex)-1][0] or '?'))
  63. else:
  64. for varBind in varBinds:
  65. if varBind[1] != value: # pragma: no cover
  66. raise RuntimeError('failed to set: %s' % ' = '.join([x.prettyPrint() for x in varBind]))
  67. def _walk(self, *oid):
  68. oid = ObjectIdentity(*oid)
  69. # XXX - keep these, this might stop working, no clue what managed to magically make things work
  70. # ref: http://snmplabs.com/pysnmp/examples/smi/manager/browsing-mib-tree.html#mib-objects-to-pdu-var-binds
  71. # mibdump.py --mib-source '/Users/jmg/Nextcloud/Documents/user manuals/netgear/gs7xxt-v6.3.1.19-mibs' --mib-source /usr/share/snmp/mibs --rebuild rfc1212 pbridge vlan
  72. #oid.addAsn1MibSource('/usr/share/snmp/mibs', '/Users/jmg/Nextcloud/Documents/user manuals/netgear/gs7xxt-v6.3.1.19-mibs')
  73. oid.resolveWithMib(_mvc)
  74. for (errorInd, errorStatus, errorIndex, varBinds) in nextCmd(
  75. self._eng, self._cd, self._targ, ContextData(),
  76. ObjectType(oid),
  77. lexicographicMode=False):
  78. if errorInd: # pragma: no cover
  79. raise ValueError(errorIndication)
  80. elif errorStatus: # pragma: no cover
  81. raise ValueError('%s at %s' % (errorStatus.prettyPrint(), errorIndex and varBinds[int(errorIndex)-1][0] or '?'))
  82. else:
  83. for varBind in varBinds:
  84. yield varBind
  85. def findport(self, name):
  86. return [ x[0][-1] for x in self._walk('IF-MIB', 'ifName') if str(x[1]) == name ][0]
  87. def getvlanname(self, vlan):
  88. v = self._get(('Q-BRIDGE-MIB', 'dot1qVlanStaticName', vlan))
  89. return str(v).decode('utf-8')
  90. def createvlan(self, vlan, name):
  91. # createAndGo(4)
  92. self._set(('Q-BRIDGE-MIB', 'dot1qVlanStaticRowStatus',
  93. int(vlan)), 4)
  94. self._set(('Q-BRIDGE-MIB', 'dot1qVlanStaticName', int(vlan)),
  95. name)
  96. def deletevlan(self, vlan):
  97. self._set(('Q-BRIDGE-MIB', 'dot1qVlanStaticRowStatus',
  98. int(vlan)), 6) # destroy(6)
  99. def getvlans(self):
  100. return (x[0][-1] for x in self._walk('Q-BRIDGE-MIB', 'dot1qVlanStatus'))
  101. def staticvlans(self):
  102. return (x[0][-1] for x in self._walk('Q-BRIDGE-MIB', 'dot1qVlanStaticName'))
  103. class Test(unittest.TestCase):
  104. def setUp(self):
  105. args = open('test.creds').read().split()
  106. self.switch = SNMPSwitch(*args)
  107. def test_unpacktable(self):
  108. pass
  109. def test_misc(self):
  110. switch = self.switch
  111. self.assertEqual(switch.findport('g1'), 1)
  112. self.assertEqual(switch.findport('l1'), 14)
  113. def test_vlan(self):
  114. switch = self.switch
  115. existingvlans = set(switch.getvlans())
  116. while True:
  117. testvlan = random.randint(1,4095)
  118. if testvlan not in existingvlans:
  119. break
  120. # Test that getting a non-existant vlans raises an exception
  121. self.assertRaises(ValueError, switch.getvlanname, testvlan)
  122. self.assertTrue(set(switch.staticvlans()).issubset(existingvlans))
  123. testname = 'Sometestname'
  124. # Create test vlan
  125. switch.createvlan(testvlan, testname)
  126. try:
  127. # make sure the test vlan was created
  128. self.assertIn(testvlan, set(switch.staticvlans()))
  129. self.assertEqual(testname, switch.getvlanname(testvlan))
  130. finally:
  131. switch.deletevlan(testvlan)