En la red local, a menudo necesita averiguar en qué puerto del conmutador se encuentra la dirección MAC específica del dispositivo. El problema se resuelve fácilmente si hay varios conmutadores en la red, pero cuando hay más de 30 de ellos, todo se vuelve mucho más complicado. Quiero compartir un pequeño script de Python que busca la dirección MAC deseada en la red y devuelve el nombre y el puerto del conmutador en el que está registrado este MAC.

La crítica constructiva es bienvenida. Detalles debajo del corte.
Si el diseño de la red se realiza correctamente, es decir, el conmutador raíz
CORE , al que están conectados los conmutadores de distribución
DS (conmutador de distribución), y a ellos, a su vez, los conmutadores de nivel de acceso
AS (conmutador de acceso). Esta regla no siempre es cierta; los interruptores de acceso se pueden conectar en serie. En cualquier caso, el puerto del conmutador ascendente contiene todas las direcciones MAC de los dispositivos conectados al conmutador descendente.
Por ejemplo, si el dispositivo que nos interesa está conectado al conmutador
AS3 , entonces, comenzando la búsqueda con
CORE , encontraremos esta dirección en el puerto que conduce a
DS1 . Al ir a
DS1 , encontraremos este MAC en el puerto que conduce a
AS2 , yendo a
AS2 , veremos que nos lleva a
AS3 , y solo en
AS3 encontraremos el puerto específico al que está conectado el dispositivo de interés.
No quería hacerlo todo a mano, ordenar todos los interruptores en un bucle y determinar dónde está el enlace ascendente y dónde no, así que nació la siguiente solución, que quiero compartir.
Un poco de teoría
Para encontrar el MAC
08: 62: 66: c7: b3: 45 en el conmutador Juniper, ejecute el siguiente comando:
show ethernet-switching table | match 08:62:66:c7:b3:45
Si existe tal MAC, la respuesta será la siguiente:
vlan151 08:62:66:c7:b3:45 D - xe-0/0/23.0
La última columna será el nombre de la interfaz del conmutador en el que está registrado el MAC. Pero, ¿cómo entender a dónde conduce esta interfaz? Y aquí las
descripciones de interfaz vienen al rescate. Estas son líneas en el archivo de configuración del conmutador que le permiten asignar etiquetas de texto a las interfaces.
El equipo
show interfaces xe-0/0/23 descriptions
mostrará lo siguiente:
Interface Admin Link Description xe-0/0/23 up up SW>DS1
En la configuración, indicamos que esta interfaz conduce al conmutador descendente:
set interfaces xe-0/0/23 description SW>DS1
Implementación
El guión propuesto hará lo siguiente:
- Conéctese a través de SSH al conmutador raíz
- comprobar en qué interfaz se encuentra la dirección MAC pasada en los parámetros;
- Verifique la descripción de esta interfaz;
- Si la interfaz conduce al conmutador, acceda al siguiente conmutador de la cadena de forma recursiva.
Por lo tanto, el script pasará por todos los conmutadores de red, comenzando desde el núcleo, e intentará encontrar el MAC deseado. Para una operación exitosa, es suficiente mantener actualizadas las descripciones en las interfaces, y la topología puede ser de casi cualquier complejidad.
Un ejemplo de un script:
python findmac.py 00:17:fc:21:e8:f9 {"host": "CORE", "iface": "xe-0/0/23.0", "description": "SW>DS1"} {"host": "DS1", "iface": "xe-0/0/11.0", "description": "SW>AS2"} {"host": "AS2", "iface": "xe-1/0/1.0", "description": "SW>AS3"} {"host": "AS3", "iface": "ge-0/0/26.0", "description": "none"}
Si no hay MAC, obtenemos
{"host": "CORE", "iface": "none"}
La última línea es el switch y el puerto que nos interesa, pero al mismo tiempo podemos rastrear toda la ruta de búsqueda.
El código completo está debajo del spoiler, gracias por su atención.
findmac.py import paramiko import time import sys import json import threading import logging login = 'user1' password = 'pass1234' searchpass = [] port = 22 class LogPipe(threading.Thread): def __init__(self, level): threading.Thread.__init__(self) self.daemon = False self.level = level self.fdRead, self.fdWrite = os.pipe() self.pipeReader = os.fdopen(self.fdRead) self.start() def fileno(self): return self.fdWrite def run(self): for line in iter(self.pipeReader.readline, ''): logging.log(self.level, line.strip('\n')) self.pipeReader.close() def close(self): os.close(self.fdWrite) def execute_ssh_command(host, port, username, password, command): try: