[hptools] éviter les collisions de mac

La fonction walk de hptools fait appel au binaire snmpwalk. Celui-ci renvoi
(dans le cas d'une demande des hpSwitchPortFdbAddress) des lignes
de la forme:
STATISTICS-MIB::hpSwitchPortFdbAddress.$(numerodeport).'$(mac en binaire)' "$(mac en hexa) "
Par $(mac en binaire), je désigne une représentation où chaque octet de
l'adresse mac est représenté par le caractère ascii correspondant.

Cependant, il existe plus d'un caractère ascii non-représentable, et ces
caractères sont tous remplacés par des ".". Cela donne des résultats
avec plusieurs fois le même oid (quand présents sur la même prise):
STATISTICS-MIB::hpSwitchPortFdbAddress.25.'......' "D4 BE D9 80 CD F8 "
STATISTICS-MIB::hpSwitchPortFdbAddress.25.'......' "DC 9F DB 07 D9 12 "
STATISTICS-MIB::hpSwitchPortFdbAddress.25.'......' "DC 9F DB 07 DA A8 "
STATISTICS-MIB::hpSwitchPortFdbAddress.25.'......' "DC 9F DB 07 DB 1B "
(^^^^ ex ici avec des bornes wifi sur le port 25)

Cela pose un problème certain car la fonction walk renvoie un dictionnaire
indexé par les oid, ce qui écrase donc les données précédentes.

On patche en utilisant une lib snmp sachant traiter des oid binaires
arbitraires.
Comme cela change un peu la sortie de la fonction walk, j'ai préféré garder
l'ancienne version, tout en permettant l'utilisation de la nouvelle via
un argument optionnel de compatibilité.
This commit is contained in:
Daniel STAN 2013-07-26 02:07:01 +02:00
parent 6c54abcbf6
commit e05c4be14c

View file

@ -8,6 +8,8 @@ Donne la classe switch qui permet d'effectuer les opérations
élémentaires sur les switchs manageable HP 26xx.
Frédéric PAUGET
TODO réécrire ce script (la moitié des fonctions ne marchent plus,
l'autre ferait bien d'utiliser netsnmp ou équivalent)
"""
from time import sleep
from sys import stderr, path
@ -15,10 +17,12 @@ from commands import getstatusoutput
from annuaires_pg import chbre_prises, all_switchs
from os.path import exists
from os import system
import os
import sys
from re import findall
import re
from config import vlans
import netsnmp
path.append('/usr/scripts/gestion')
from ldap_crans import crans_ldap
@ -123,6 +127,7 @@ class snmp :
"""
self.host = host
self.version = version
self.community = community
if version == '1' or version == '2c' :
self.options = "-v %s -c '%s' %s " % ( version, community, host )
@ -179,10 +184,12 @@ class snmp :
"""
return self.__exec('snmpset -O vq %s %s %s %s' % (self.options, oid, typ, val ) )
def walk(self,base_oid) :
def walk(self,base_oid, bin_comp=False) :
""" Retourne le résultat de snmpwalk
le retour est un dictionnaire { oid : valeur }
"""
if bin_comp:
return snmp.bin_walk(self, base_oid)
lignes = self.__exec('snmpwalk -Ox %s %s' % (self.options, base_oid ) ).split('\n')
result = {}
for ligne in lignes:
@ -193,6 +200,37 @@ class snmp :
pass
return result
def bin_walk(self, base_oid):
""" Retourne le résultat de snmpwalk
le retour est un dictionnaire { oid : valeur }
TODO: prendre en compte l'auth et le snmp vn, n>1
TODO: malheureusement, la plupart des fonctions faisant appel
à walk ne marchent pas out-of-the-box, il faut donc
d'abord les convertir avant de leur faire utiliser cette nouvelle
fonction
"""
try:
prefix, b_oid = base_oid.split('::', 1)
except ValueError:
raise NotImplementedError('Merci de préciser un MIB')
os.environ['MIBS'] = prefix
# ^^^ Je suis triste de faire ça
oid_obj = netsnmp.VarList(netsnmp.Varbind(b_oid))
# oid_obj est remple des réponses du snmpwalk
netsnmp.snmpwalk(oid_obj,
Version = int(self.version),
DestHost=self.host,
Community=self.community,
)
#UseLongNames=1, #ceci devrait marcher selon la doc
#en pratique, non (cf /usr/lib/python2.7/dist-packages/netsnmp/client.py)
# On renvoie un résultat ressemblant à ce que fait le snmpwalk shell
return { '%s::%s.%s' % (prefix, res.tag, res.iid): res.val
for res in oid_obj }
#############################################################################################
### Gestion des switchs proprement dite
@ -228,13 +266,13 @@ class hpswitch :
if not prise : prise = self.prise
if self.__debug : self.__logDest.write("HP DEBUG : show_prise_mac(prise=%s)\n" % prise)
try:
data = self.walk('STATISTICS-MIB::hpSwitchPortFdbAddress.%d' % int(prise))
data = self.walk('STATISTICS-MIB::hpSwitchPortFdbAddress.%d' % int(prise),
bin_comp=True)
macs = []
for value in data.itervalues():
mac = value.replace(' ', '').lower().replace('"', '')
if not re.match('([0-9a-f]{2}){6}', mac):
mac = mac.encode('hex').lower()
mac = "%s:%s:%s:%s:%s:%s" % (mac[0:2], mac[2:4], mac[4:6], mac[6:8], mac[8:10], mac[10:12])
if len(value) != 6:
continue # Should not happen
mac = ':'.join('%02x' % ord(c) for c in value)
macs.append(mac)
return macs
except ValueError:
@ -247,7 +285,8 @@ class hpswitch :
mac = mac.lower()
# On interroge le switch
try:
data = self.walk('STATISTICS-MIB::hpSwitchPortFdbAddress')
data = self.walk('STATISTICS-MIB::hpSwitchPortFdbAddress',
bin_comp=True)
except ValueError:
print >> sys.stderr, "Le switch %s fait du caca..." % self.switch
return None