1. 以太网 MAC 发送路径基本帧传输验证

任务目标

搭建一个最小可运行的 MAC 发送路径验证环境:构造一个最小以太网帧(目的 MAC + 源 MAC + 类型 + 载荷),驱动 MAC 发送逻辑,检查输出到 PHY 接口的字节流是否正确包含前导码(7×0x55)、SFD(0xD5)、原始帧内容以及追加在末尾的 FCS(CRC-32)。

环境与依赖

  • Python 3.8+,仅使用标准库 zlib(提供 CRC-32,与以太网 FCS 使用同一多项式,仅需按以太网规则取反并小端输出)。
  • 无需第三方库,无需硬件;本案例用软件模型模拟 MAC 发送路径,便于在无 PHY 的情况下验证字节级行为。

实现思路

MAC 发送路径按顺序完成四件事:拼接前导码与 SFD、输出帧内容、计算并追加 FCS、把结果交给 PHY 接口。FCS 计算使用 CRC-32,初值 0xFFFFFFFF,结果按位取反后以小端序追加 4 字节。下面代码把发送路径封装为 mac_send,并用一个断言检查输出结构。

关键完整代码

import zlib

PREAMBLE = b"\x55" * 7
SFD = b"\xd5"

def crc32_fcs(frame: bytes) -> bytes:
    # 以太网 FCS:CRC-32 取反后小端输出
    crc = zlib.crc32(frame) & 0xFFFFFFFF
    crc ^= 0xFFFFFFFF
    return crc.to_bytes(4, "little")

def mac_send(dst: bytes, src: bytes, ethertype: bytes, payload: bytes) -> bytes:
    assert len(dst) == 6 and len(src) == 6 and len(ethertype) == 2
    frame = dst + src + ethertype + payload
    fcs = crc32_fcs(frame)
    phy_bytes = PREAMBLE + SFD + frame + fcs
    return phy_bytes

def verify(phy_bytes: bytes, frame: bytes) -> None:
    assert phy_bytes[:7] == PREAMBLE, "前导码错误"
    assert phy_bytes[7:8] == SFD, "SFD 错误"
    assert phy_bytes[8:8 + len(frame)] == frame, "帧内容错误"
    fcs = phy_bytes[8 + len(frame):]
    assert fcs == crc32_fcs(frame), "FCS 错误"
    print("PASS: 前导码/SFD/帧/FCS 均正确")

if __name__ == "__main__":
    dst = bytes.fromhex("001122334455")
    src = bytes.fromhex("aabbccddeeff")
    ethertype = bytes.fromhex("0800")
    payload = b"hello-mac"
    frame = dst + src + ethertype + payload
    phy = mac_send(dst, src, ethertype, payload)
    print("PHY 输出:", phy.hex())
    verify(phy, frame)

运行与验证

  1. 保存为 mac_send.py,执行 python mac_send.py。
  2. 观察输出:应打印一行十六进制 PHY 字节流,并以 PASS: 前导码/SFD/帧/FCS 均正确 结束。
  3. 通过条件:脚本无 AssertionError;PHY 字节流前 7 字节为 55,第 8 字节为 d5,随后是 6+6+2+9=23 字节帧内容,最后 4 字节为 FCS。

预期输出(由代码逻辑唯一确定)

PHY 输出: 55555555555555d5001122334455aabbccddeeff080068656c6c6f2d6d6163<4字节FCS>
PASS: 前导码/SFD/帧/FCS 均正确

其中 <4字节FCS> 由 crc32_fcs 对帧内容计算得到,运行脚本即可看到具体值。

SVG:MAC 发送路径数据流

构造帧 加前导码+SFD 7×0x55 + 0xD5 计算 FCS CRC-32 取反 输出到 PHY dst+src+type+payload PREAMBLE+SFD+frame frame+FCS PHY 字节流