MAC 地址有效性判断
is_valid_ether_addr
kernel-5.10/drivers/net/ethernet/stmicro/stmmac/stmmac_main.cif (!is_valid_ether_addr(addr))kernel-5.10/include/linux/etherdevice.h```h /**- is_valid_ether_addr - Determine if the given Ethernet address is valid
- @addr: Pointer to a six-byte array containing the Ethernet address *
- Check that the Ethernet address (MAC) is not 00:00:00:00:00:00, is not
- a multicast address, and is not FF:FF:FF:FF:FF:FF. *
- Return true if the address is valid. *
- Please note: addr must be aligned to u16.
/
static inline bool is_valid_ether_addr(const u8 *addr)
{
/ FF:FF:FF:FF:FF:FF is a multicast address so we don’t need to
- explicitly check for it here. */ return !is_multicast_ether_addr(addr) && !is_zero_ether_addr(addr); } ``` 有效mac地址不能为多播地址,或者全为0。
is_multicast_ether_addr
/**
* is_multicast_ether_addr - Determine if the Ethernet address is a multicast.
* @addr: Pointer to a six-byte array containing the Ethernet address
*
* Return true if the address is a multicast address.
* By definition the broadcast address is also a multicast address.
*/
static inline bool is_multicast_ether_addr(const u8 *addr)
{
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
u32 a = *(const u32 *)addr;
#else
u16 a = *(const u16 *)addr;
#endif
#ifdef __BIG_ENDIAN
return 0x01 & (a >> ((sizeof(a) * 8) - 8));
#else
return 0x01 & a;
#endif
}
核心目标:高效检测 MAC 地址第1字节(最高字节)的最低位(bit 0)是否为1
字节序处理的本质:
- 小端序系统(Little-Endian):
return 0x01 & a; // 直接取内存最低字节- 内存布局:
[低地址] addr[0] (B0) | addr[1] (B1) | ... [高地址] - 当读取
u16/u32时,a的低字节就是 MAC 的首字节B0 - 示例(u32读取):
MAC: 01:23:45:67:89:ab 内存:0x01, 0x23, 0x45, 0x67, ... 小端u32值:0x67452301 (最低字节=0x01) 直接检测 0x01 & 1 → 1 (多播)
- 内存布局:
- 大端序系统(Big-Endian):
return 0x01 & (a >> ((sizeof(a) * 8) - 8));- 内存布局:
[低地址] B0 (最高字节) | B1 | ... [高地址] - 右移位操作:
sizeof(a)*8→ 获取变量总位数(u32=32位, u16=16位)-8→ 准备取出首字节- 移位效果:
u32 示例:0x01234567 >> (32-8)=24 → 0x00000001 u16 示例:0x0123 >> (16-8)=8 → 0x0001 - 示例:
MAC: 01:23:45:67:89:ab 内存:0x01, 0x23, 0x45, 0x67, ... 大端u32值:0x01234567 右移24位:0x00000001 → 检测最低位 1 (多播)
- 内存布局:
is_zero_ether_addr
/**
* is_zero_ether_addr - Determine if give Ethernet address is all zeros.
* @addr: Pointer to a six-byte array containing the Ethernet address
*
* Return true if the address is all zeroes.
*
* Please note: addr must be aligned to u16.
*/
static inline bool is_zero_ether_addr(const u8 *addr)
{
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
return ((*(const u32 *)addr) | (*(const u16 *)(addr + 4))) == 0;
#else
return (*(const u16 *)(addr + 0) |
*(const u16 *)(addr + 2) |
*(const u16 *)(addr + 4)) == 0;
#endif
}
核心目标:高效检测6字节全零状态
算法设计:
- 或运算特性:
0 | 0 | 0 = 0,任何非零值都会使结果≠0 - 内存访问优化: | 模式 | 内存访问次数 | 操作说明 | |———————|————-|—————————-| | 高效非对齐 (u32+u16) | 2次 | 前4字节(u32)+后2字节(u16) | | 标准对齐 (u16×3) | 3次 | 每次读取2字节,共3次 |
字节序无影响证明:
- 无论字节序如何排列,全零时:
内存内容:0x00,0x00,0x00,0x00,0x00,0x00 读取结果: u32读取 → 0x00000000 u16读取 → 0x0000 或运算:0 | 0 = 0 - 非零示例:
内存:0x00,0x00,0x01,0x00,0x00,0x00 小端u32:0x00000100 → 0x00000100 (≠0) 大端u32:0x00000001 → 0x00000001 (≠0)
留下评论