Python SNMP 获取交换机ARP表和FDB表(MAC和端口对应表)

本文介绍了通过Python实现的SNMP脚本,展示如何从Cisco、华为和H3C设备获取ARP、端口映射等信息,包括1.3.6.1.2.1系列OID的使用和不同数据格式转换。
部署运行你感兴趣的模型镜像
import sys

import pysnmp.hlapi as hlapi
import pysnmp.proto.rfc1902 as rfc1902


def snmp_walk(host, oid, format='str', strip_prefix=True, community='public'):
    res = []
    for (errorIndication,
         errorStatus,
         errorIndex,
         varBinds) in hlapi.nextCmd(hlapi.SnmpEngine(),
                                    hlapi.CommunityData(community),
                                    hlapi.UdpTransportTarget((host, 161), timeout=4.0, retries=3),
                                    hlapi.ContextData(),
                                    hlapi.ObjectType(hlapi.ObjectIdentity(oid)),
                                    lookupMib=False,
                                    lexicographicMode=False):
        if errorIndication:
            raise ConnectionError(f'SNMP error: "{str(errorIndication)}". Status={str(errorStatus)}')
        elif errorStatus:
            raise ConnectionError('errorStatus: %s at %s' % (errorStatus.prettyPrint(),
                                                             errorIndex and varBinds[int(errorIndex) - 1][0] or '?'))
        else:
            for x in varBinds:
                k, v = x
                if strip_prefix:
                    k = str(k)[len(str(oid)) + 1:]
                if isinstance(v, rfc1902.Integer):
                    res.append((str(k), int(v)))
                else:
                    if format == 'numbers':
                        res.append((str(k), v.asNumbers()))
                    elif format == 'hex':
                        res.append((str(k), v.asOctets().hex()))
                    elif format == 'raw':
                        res.append((str(k), v))
                    elif format == 'bin':
                        res.append((str(k), v.asOctets()))
                    elif format == 'int':
                        res.append((str(k), int(v)))
                    elif format == 'preview':
                        res.append((str(k), str(v)))
                    elif format == 'any':
                        try:
                            res.append((str(k), v.asOctets().decode('utf-8')))
                        except UnicodeDecodeError:
                            res.append((str(k), '0x' + v.asOctets().hex()))
                    elif format == 'str':
                        res.append((str(k), v.asOctets().decode(v.encoding)))
                    else:
                        assert False, "Unknown format for walk()."
    res = {a: b for a, b in res}
    return res


def split_numbers(oid):
    return [int(x) for x in oid.split('.')]


def read_ipv4_from_oid_tail(oid, with_len=True):
    parts = [int(x) for x in oid.split('.')]
    if with_len:
        assert (parts[-5] == 4)  # number of elements
    return '.'.join([str(x) for x in parts[-4:]])


def read_bid_from_oid_tail(oid, with_len=True):
    parts = [int(x) for x in oid.split('.')]
    if with_len:
        assert (parts[-5] == 1)  # number of elements
    return '.'.join([str(x) for x in parts[-1:]])


def read_mac_from_oid_tail(oid, with_len=True):
    parts = [int(x) for x in oid.split('.')]
    if with_len:
        assert (parts[-5] == 6)  # number of elements
    return '.'.join([str(x) for x in parts[-6:]])


def machex(getvar):
    macs = getvar.split('.')
    i = 0
    ma = []
    for x in range(0, 6):
        maca = macs[i]
        if len(maca) == 1:
            a = hex(int(maca)).replace("x", "")
        else:
            a = hex(int(maca))[2:]
        ma.append(a)
        i = i + 1
    return ma[0] + ":" + ma[1] + ":" + ma[2] + ":" + ma[3] + ":" + ma[4] + ":" + ma[5]


if __name__ == "__main__":

    # Read ARP table
    print(" - Reading device ARP table...", file=sys.stderr)
    atPhysAddress = snmp_walk('192.168.0.1', '1.3.6.1.2.1.3.1.1.2', 'hex', community='public')
    for oid, mac in atPhysAddress.items():
        ip = read_ipv4_from_oid_tail(oid, with_len=False)
        print(ip)
        print(mac)
    # Read dot1dBasePortIfIndex table
    print(" - Reading device dot1dBasePortIfIndex table...", file=sys.stderr)
    dot1dBasePortIfIndex = snmp_walk('192.168.0.1', '1.3.6.1.2.1.17.1.4.1.2', 'int', community='public')
    dot1dBasePort = {}
    for bid, id in dot1dBasePortIfIndex.items():
        ip = read_ipv4_from_oid_tail(bid, with_len=False)
        print('bid=', bid)
        print('id=', id)
        dot1dBasePort[bid] = str(id)
    print(dot1dBasePort)

    # Read ifDescr table
    print(" - Reading device ifDescr table...", file=sys.stderr)
    ifDescr = snmp_walk('192.168.0.1', '1.3.6.1.2.1.2.2.1.2', 'str', community='public')
    Descr = {}
    for id, desc in ifDescr.items():
        ip = read_ipv4_from_oid_tail(id, with_len=False)
        print('id=', id)
        print('desc=', desc)
        Descr[id] = desc
    print(Descr)

    dot1dBasePortDescr = {}
    for key in dot1dBasePort.keys():
        dot1dBasePortDescr[key] = Descr[dot1dBasePort[key]]

    print(dot1dBasePortDescr)

    # Read dot1qTpFdbPort table
    print(" - Reading device dot1qTpFdbPort table...", file=sys.stderr)
    dot1qTpFdbPort = snmp_walk('192.168.0.1', '1.3.6.1.2.1.17.4.3.1.2', 'int', community='public')
    dot1qTpFdb = {}
    for mac, bid in dot1qTpFdbPort.items():
        macdec = read_mac_from_oid_tail(mac, with_len=False)
        print('machex=', machex(macdec))
        print('bid=', bid)
        dot1qTpFdb[machex(macdec)] = str(bid)
    print(dot1qTpFdb)

    dot1qTpFdbDescr = {}
    for key in dot1qTpFdb.keys():
        if dot1qTpFdb[key] in dot1dBasePortDescr.keys():
            dot1qTpFdbDescr[key] = dot1dBasePortDescr[dot1qTpFdb[key]]

    print(dot1qTpFdbDescr)

测试思科、华为、H3C可以正常运行;

有些H3C设备没有提供

dot1qTpFdbPort(1.3.6.1.2.1.17.7.1.2.2.1.2)

需要使用

dot1dTpFdbPort

MAC地址对应的端口号。

1.3.6.1.2.1.17.4.3.1.2

您可能感兴趣的与本文相关的镜像

Python3.11

Python3.11

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

### 回答问题: **MAC地址转发项(MAC FDB项)ARP项是网络设备中两个关键的数据结构,分别用于二层(数据链路层)三层(网络层)的转发决策。** --- #### 1. **MAC地址转发项(Forwarding Database, FDB)** - ✅ **定义**: MAC地址转发(也称FDB或CAM)记录了**MAC地址与交换机端口之间的映射关系**,用于在局域网内部进行帧的快速转发。 - 📌 **作用层级**:OSI模型的 **第2层(数据链路层)** - 🔧 **典型设备**:以太网交换机、网桥、支持VLAN的嵌入式系统 - 🗂️ **项内容示例**: ``` | MAC Address | Port | VLAN ID | Aging Time | |------------------|--------|---------|------------| | 00:1A:2B:3C:4D:5E| eth1 | 100 | 300s | ``` - ⚙️ **工作原理**: 1. 当交换机从某个端口收到一个数据帧时,它会学习源MAC地址,并将其与入端口绑定,存入FDB。 2. 如果目的MAC已在中 → 转发到对应端口(单播) 3. 如果目的MAC不在中 → 泛洪到所有相关端口(广播行为) 4. 项有过期时间(aging time),长时间未使用的条目会被清除 - 💡 **举例说明**: > 主机A(MAC: AA:AA:AA:AA:AA:AA)连接在交换机的 `port1` 上发送了一个帧。交换机会记录:“AA:AA:AA... 在 port1”,下次有人要发给这个MAC,就只往 `port1` 发,而不是广播。 - 🔄 **刷新/删除场景**: - 网络拓扑变化(如主备切换) - 设备下线 - 收到SmartLink的“Flush报文” → 清除特定端口或全部FDB项(防止旧路径残留造成错包) --- #### 2. **ARP项(Address Resolution Protocol Table)** - ✅ **定义**: ARP记录了**IP地址与MAC地址之间的映射关系**,用于实现IP通信前的地址解析。 - 📌 **作用层级**:OSI模型的 **第3层(网络层)** - 🔧 **典型设备**:路由器、主机、三层交换机、网关设备 - 🗂️ **项内容示例**: ``` | IP Address | MAC Address | Interface | State | |----------------|-------------------|-----------|---------| | 192.168.1.100 | 00:1A:2B:3C:4D:5E | vlan1 | Reachable | ``` - ⚙️ **工作原理**: 1. 当主机想向 `192.168.1.100` 发送IP包时,必须知道其MAC地址。 2. 查询本地ARP缓存: - 找到 → 直接封装成帧发送 - 找不到 → 广播发送ARP请求:“谁有192.168.1.100?” 3. 目标主机回复ARP应答,告知自己的MAC地址 4. 本机将 `(IP, MAC)` 存入ARP,后续通信直接使用 - 💡 **动态 vs 静态**: - 动态ARP:自动学习,有超时机制(通常10分钟) - 静态ARP:手动配置,永不超时(用于关键服务器) - 🔄 **刷新/删除场景**: - IP冲突检测 - 网络故障恢复 - 收到SmartLink Flush报文后调用 `ipc_arpClearByPort(up);` → 清除该端口下所有ARP条目,避免使用过期路由 --- ### ✅ 对比总结: | 特性 | MAC FDB 项 | ARP 项 | |------|---------------|----------| | 层级 | 二层(数据链路层) | 三层(网络层) | | 映射关系 | MAC地址 ↔ 交换机端口 | IP地址 ↔ MAC地址 | | 使用设备 | 交换机、网桥 | 主机、路由器、三层设备 | | 构建方式 | 源MAC学习 | ARP请求/响应 | | 典型命令查看 | `bridge fdb show` (Linux) | `arp -a` 或 `ip neigh` | | 是否需要泛洪 | 未知目的MAC泛洪 | 未知IP需ARP广播 | | 删除时机 | 拓扑变更、老化、收到flush | 接口down、老化、手动清除 | --- ### 🔍 结合你之前的代码理解: 在你的 `smartLinkTppktHandle` 函数中出现的相关操作: ```c adSmartLinkFlushPort(up); // → 可能清除FDB中该端口下的MAC项 // ipc_arpClearByPort(up); // 被注释,但意图是清除该端口相关的ARP条目 ``` 👉 这些操作的意义是: > 当SmartLink协议检测到链路切换(例如主备倒换),立即清除旧路径上的 **MAC转发项** **ARP缓存**,强制设备重新学习正确路径,避免错包、丢包或环路。 这是高可靠性网络(如工业以太网、环网冗余协议)中的标准做法。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值