From e05c4be14c86da88413c598e4c0244dd4ed03fd6 Mon Sep 17 00:00:00 2001 From: Daniel STAN Date: Fri, 26 Jul 2013 02:07:01 +0200 Subject: [PATCH] =?UTF-8?q?[hptools]=20=C3=A9viter=20les=20collisions=20de?= =?UTF-8?q?=20mac?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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é. --- gestion/hptools.py | 53 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/gestion/hptools.py b/gestion/hptools.py index 619e0851..15beebe6 100755 --- a/gestion/hptools.py +++ b/gestion/hptools.py @@ -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