You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用pysnmp v3实现指定VLAN查询Cisco交换机MAC地址表?

解决Cisco交换机SNMPv3获取全VLAN MAC地址表的问题

问题背景

我正尝试通过SNMPv3从Cisco交换机获取完整MAC地址表,发现Cisco需逐个VLAN查询,与其他厂商不同。现有pysnmp bulk命令仅能获取VLAN 1的MAC表,尝试新方法时触发错误,寻求解决方案。

等效SNMPv2c命令:

snmpwalk -v2c -c letsconfigRO@10 10.0.0.101 1.3.6.1.2.1.17.4.3.1.1

当前可用代码(仅获取VLAN 1)

auth = cmdgen.UsmUserData(userName=snmpv3Username,
                          authKey=snmpv3Password,
                          authProtocol=authProtocol,
                          privKey=privKey,
                          privProtocol=privProtocol)

errorIndication, errorStatus, errorIndex, varBinds = cmdGen.bulkCmd(
    auth,
    cmdgen.UdpTransportTarget((host, 161)),
    0, 1000,
    cmdgen.MibVariable(walk_oid),
    lookupMib=False,
    lexicographicMode=False
)

这段代码可正常执行,但仅返回VLAN 1的MAC地址表。

尝试的错误代码及问题

# Create SNMP engine instance
snmp_engine = SnmpEngine()

# Create SNMPv3 user data object
user = UsmUserData(userName=snmpv3Username,
                   authKey=snmpv3Password,
                   authProtocol=authProtocol,
                   privKey=privKey,
                   privProtocol=privProtocol)
# Define SNMPv3 target
target = UdpTransportTarget(('10.0.0.101', 161))

# Define VLAN ID
vlan_id = 10

# Define OID for retrieving MAC addresses for a specific VLAN
oid = ObjectType(ObjectIdentity('BRIDGE-MIB', 'dot1dTpFdbPort'))

# Define OID for retrieving VLAN membership information
vmVlan_oid = ObjectType(ObjectIdentity('CISCO-VLAN-MEMBERSHIP-MIB', 'vmVlan', vlan_id))

# Perform bulkwalk operation to retrieve the MAC address table
iterator = bulkCmd(
    snmp_engine,
    user,
    target,
    ContextData(),
    oid,
    lexicographicMode=False,
    maxRepetitions=500,
    acInfo=(vmVlan_oid, None)
)

执行时触发错误:

TypeError: int() argument must be a string, a bytes-like object or a real number, not 'ObjectType'

解决方案

错误原因

acInfo参数需要的是上下文引擎ID的元组,而非ObjectType对象。Cisco交换机查询特定VLAN的MAC表时,需将VLAN ID作为**上下文名称(Context Name)**传入,而非通过acInfo传递MIB对象;同时原代码漏掉了bulkCmd必填的non-repeaters和max-repetitions位置参数,导致参数错位。

修正后的单VLAN查询代码

from pysnmp.hlapi import SnmpEngine, UsmUserData, UdpTransportTarget, ContextData, ObjectType, ObjectIdentity, bulkCmd

snmp_engine = SnmpEngine()

# 配置SNMPv3认证信息
user = UsmUserData(
    userName=snmpv3Username,
    authKey=snmpv3Password,
    authProtocol=authProtocol,
    privKey=privKey,
    privProtocol=privProtocol
)

target = UdpTransportTarget(('10.0.0.101', 161))
vlan_id = 10

# 将VLAN ID转为字符串作为SNMP上下文名称,这是Cisco识别目标VLAN的关键
context_data = ContextData(contextName=str(vlan_id))

# 指定查询MAC表的OID(BRIDGE-MIB::dot1dTpFdbPort)
oid = ObjectType(ObjectIdentity('BRIDGE-MIB', 'dot1dTpFdbPort'))

# 执行bulk查询,注意参数顺序:non-repeaters、max-repetitions需放在OID之前
iterator = bulkCmd(
    snmp_engine,
    user,
    target,
    context_data,
    0,  # non-repeaters:固定为0
    500,  # max-repetitions:单次返回的最大条目数
    oid,
    lookupMib=False,
    lexicographicMode=False
)

# 解析并输出结果
for errorIndication, errorStatus, errorIndex, varBinds in iterator:
    if errorIndication:
        print(errorIndication)
    elif errorStatus:
        print(f"{errorStatus.prettyPrint()} at {errorIndex and varBinds[int(errorIndex)-1][0] or '?'}")
    else:
        for varBind in varBinds:
            # 从OID的最后6个节点提取MAC地址并格式化
            mac_oid_nodes = varBind[0].getOid()[-6:]
            mac_address = ':'.join(f'{int(node):02x}' for node in mac_oid_nodes)
            port = varBind[1].prettyPrint()
            print(f"VLAN {vlan_id} - MAC: {mac_address}, Port: {port}")

批量获取所有VLAN的MAC表

若要获取所有VLAN的MAC表,可先通过CISCO-VLAN-MEMBERSHIP-MIB::vmVlan获取所有存在的VLAN ID,再循环遍历每个VLAN执行上述查询:

# 第一步:获取所有VLAN ID
vlan_oid = ObjectType(ObjectIdentity('CISCO-VLAN-MEMBERSHIP-MIB', 'vmVlan'))
vlan_iterator = bulkCmd(
    snmp_engine,
    user,
    target,
    ContextData(),
    0, 500,
    vlan_oid,
    lookupMib=False
)

vlans = set()
for errorIndication, errorStatus, errorIndex, varBinds in vlan_iterator:
    if not errorIndication and not errorStatus:
        for varBind in varBinds:
            vlans.add(varBind[1].prettyPrint())

# 第二步:遍历每个VLAN查询MAC表
for vlan in vlans:
    context_data = ContextData(contextName=vlan)
    mac_iterator = bulkCmd(
        snmp_engine,
        user,
        target,
        context_data,
        0, 500,
        ObjectType(ObjectIdentity('BRIDGE-MIB', 'dot1dTpFdbPort')),
        lookupMib=False,
        lexicographicMode=False
    )
    # 解析当前VLAN的MAC表数据(代码同单VLAN查询的结果解析部分)
    print(f"\n--- VLAN {vlan} MAC Address Table ---")
    for errorIndication, errorStatus, errorIndex, varBinds in mac_iterator:
        if errorIndication:
            print(errorIndication)
        elif errorStatus:
            print(f"{errorStatus.prettyPrint()} at {errorIndex and varBinds[int(errorIndex)-1][0] or '?'}")
        else:
            for varBind in varBinds:
                mac_oid_nodes = varBind[0].getOid()[-6:]
                mac_address = ':'.join(f'{int(node):02x}' for node in mac_oid_nodes)
                port = varBind[1].prettyPrint()
                print(f"MAC: {mac_address}, Port: {port}")

内容的提问来源于stack exchange,提问作者Rob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 20:15:04