2 分钟阅读 次阅读

is_valid_ether_addr

  • kernel-5.10/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
    if (!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)
    

留下评论