网卡是软件与介质之间的那道门:上面收帧,下面发电平。 衡量网卡能力的不是带宽,是 PPS——因为它按「帧」计费。
1.9.1 讲的是「线」,这一节讲「接在线上那块板」。 这一节会算三个数:每秒多少字节、小帧能跑多少 PPS、大帧能跑多少 PPS。
一、网卡做的四件事
一件都不能少:
| 做的事 | 具体 | 不做会怎样 |
|---|---|---|
| 封装/解封装 | 加帧头、剥帧头 | 上层拿到的是裸字节 |
| 算 CRC | 发时算、收时验 | 坏帧照样上交 |
| 持有 MAC | 出厂烧在卡里 | 没法被寻址 |
| DMA 搬运 | 直接写内存 | CPU 被拷贝拖死 |
第二行那个 CRC 是网卡最有价值的活:它让「坏帧」在进入内存之前就被丢掉, 上层永远看不到损坏的数据。 这也是为什么应用层很少需要自己校验「字节有没有错」——底下已经拦掉了。 第四行那个 DMA 是性能关键:早年的网卡靠 CPU 一个字节一个字节搬, 千兆网卡能把 CPU 占满;有了 DMA,网卡直接把数据写进内存,CPU 只收一个中断。 这就是「网卡也是性能部件」的原因。
二、同样的带宽,帧越小越吃设备
拿一张 144 Mbps 的网卡算三个数:
| 算法 | 算式 | 结果 |
|---|---|---|
| 每秒字节 | 144 × 10⁶ ÷ 8 | 18000000 |
| 64 字节帧的 PPS | 18000000 ÷ 64 | 281250 |
| 1518 字节帧的 PPS | 18000000 ÷ 1518 | 11857 |
第二行与第三行差了二十多倍: 同样一条 144 Mbps 的链路,全发小帧时每秒要处理 28 万个帧,全发大帧只要 1.2 万个。 而设备处理每个帧的成本是固定的(查表、校验、入队),所以「PPS 打满」比「带宽打满」更容易。 一个 64 字节的帧,真正装数据的只有 46 字节: 64 减 6(目的)减 6(源)减 2(类型)减 4(校验)等于 46。 线上还要再加 12 字节帧间隔与 8 字节前导码,所以小帧在介质上一共占 84 字节。 开销比载荷还大。 这就是「DDoS 用小包打」的原理:同样的带宽,小包能把设备打满而链路还没满。 所以抗攻击不能只看带宽,要看 PPS。
三、网卡也是被攻击面
这一点常被忽略:
| 攻击点 | 手法 | 防护 |
|---|---|---|
| MAC 泛洪 | 塞满交换机表 | 端口安全、MAC 限制 |
| 混杂模式 | 抓别人的包 | 交换机隔离、加密 |
| 唤醒包 | 远程开机被滥用 | 关掉 WoL |
第一行是针对交换机的:交换机表有容量上限,塞满之后它只能退化成「泛洪」, 于是所有流量都被广播给所有人——这时候攻击者开混杂模式就能抓到别人的包。 所以「MAC 泛洪 + 混杂模式」是一套组合拳。 第二行那个「混杂模式」是抓包工具的默认前提: Wireshark 能抓到别人的包,靠的就是把网卡设成混杂。 但这在交换网络里默认抓不到——除非你做了端口镜像,或者先做 MAC 泛洪。 「交换机网络里抓不到别人的包」这件事,是分层隔离的直接结果。
四、动手 Demo:网卡把「帧」变成「电信号」
列出本机网卡的 MAC、MTU、速率,再拿其中一张算三个数。 重点是那个 PPS,它比带宽更能反映设备压力。
import psutil, _netsim as N
for name, addrs in psutil.net_if_addrs().items():
mac = [a.address for a in addrs if a.family == psutil.AF_LINK]
s = psutil.net_if_stats().get(name)
if mac and s:
print('%-16s %-20s %-6d %s'
% (name[:16], mac[0].upper(), s.mtu, s.speed or '—'))
mbps = 144
bps = mbps * 10 ** 6
print()
print('144 Mbps 一秒最多 %d 字节' % (bps // 8))
print('64 字节帧 → %d PPS' % (bps // 8 // 64))
print('1518 字节帧 → %d PPS' % (bps // 8 // 1518))
print('64 字节帧真正装数据 %d 字节' % (64 - 6 - 6 - 2 - 4))
实跑输出:
--------------------------------------------------------------------
网卡把「帧」变成「电信号」
--------------------------------------------------------------------
**网卡是软件与介质之间的那道门**:**上面收到的是帧,下面发出去的是电平。**
接口 MAC MTU 速率Mbps
---------------------------------------------------------
WLAN 9C-B6-D0-0D-D5-0F 1500 144
以太网 28-F1-0E-18-FA-25 1500 —
本地连接* 1 9E-B6-D0-0D-D5-0F 1500 —
本地连接* 2 AE-B6-D0-0D-D5-0F 1500 —
蓝牙网络连接 9C-B6-D0-0D-D5-10 1500 3
拿其中速率 144 Mbps 的那张来算三个数:
**一秒最多能发多少字节**:144 × 10⁶ ÷ 8 = 18,000,000 字节
**最小帧 64 字节时,一秒最多多少帧(PPS)**:281,250 帧
**最大帧 1518 字节时,一秒多少帧**:11,857 帧
**第二行那个数叫 PPS(每秒包数),是交换机的重要指标**:
**它比「带宽」更能反映设备的处理能力**——
**因为每个帧都要查表、判 CRC、决定往哪送,这些都是按「帧」计费的。**
**一个 64 字节的帧,真正装数据的只有 46 字节**(64 − 6 目的 − 6 源 − 2 类型 − 4 校验 = 46)。
**线上实际还要再加 12 字节帧间隔与 8 字节前导码**,**所以小帧在物理介质上一共占 84 字节。**
**所以小包流量对交换机的压力远大于大包。**
**这也是「DDoS 用小包打」的原因**:**同样的带宽,小包能把设备打满而链路还没满。**
281250 对 11857,差了二十三倍多: 这就是「小包打设备」的算术基础——同样 144 Mbps,全发小帧时每秒要处理 28 万个帧。 64 字节帧的载荷只有 46 字节(64 减 6 减 6 减 2 减 4):开销 18 字节,接近载荷的 40%。 线上再加 12 字节帧间隔与 8 字节前导码,一共占 84 字节。 速率那一列出现「—」的网卡是没插线或没协商成功:它们仍然报 MTU 1500, 因为 MTU 是协议值不是协商结果——这也是「MTU 测不出网卡差异」的原因。
30 秒实验
- 把
mbps改成 1000, 再算一遍 PPS——千兆网卡的 PPS 上限是不是也涨十倍?想想设备的处理能力能不能跟上。 - 算一下 128 字节帧的 PPS,和 64 字节的比。
- 查一下「巨帧(Jumbo Frame)」为什么能降低 PPS 压力。
常见误区
- 以为网卡只管收发、不管校验。 CRC 是网卡算的,坏帧在进内存前就被丢了, 所以应用层很少需要自己验字节。
- 以为带宽一样就一样快。 PPS 才是设备处理的瓶颈,同样带宽下小包的帧数是大包的二十多倍。
- 以为交换机网络里能随便抓到别人的包。 默认抓不到,要靠端口镜像或 MAC 泛洪才行。
自测三问(点开对答案)
1. 网卡做的四件事是什么? —— **封装/解封装、算 CRC、持有 MAC、DMA 搬运。**CRC 让坏帧在进内存前就被丢掉, DMA 让 CPU 不被拷贝拖死。 2. 为什么说 PPS 比带宽更能反映设备能力? —— **设备处理每个帧的成本是固定的**(查表、校验、入队), 所以同样带宽下小包数量是大包的二十多倍,先把设备打满。 3. 为什么「MAC 泛洪 + 混杂模式」是一套组合拳? —— **泛洪让交换机退化成广播,混杂模式就能收到别人的包。**前提是交换机表被塞满—— 所以防御要做端口安全与 MAC 限制。下一节讲中继器——它只做一件事:把变弱的信号重新整形。
- ☐ (本节完,下一节 1.9.3 中继器)