概述
背景
网卡使用的是sigmastar的SSD202D芯片,该芯片有两个网口,其中一个网口需要外部的phy,方案图如下:
那么两个网口的mac地址是怎么存储的呢?如果是存储在mac模块内的flash是最理想的,烧录一次后就跟硬件走,芯片出厂前厂家烧录到芯片内更好。然而并不是。查看资料和代码后知道芯片并不会存储,每次上电后需要写入到mac寄存器。厂家的文档可以印证:
意思是厂家提供一个脚本,开机进入系统后自动读取eth0的mac地址,+1后写到eth1去。
问题
本来我也是用厂家这个脚本的,直到测试提几个问题单才发现有缺陷:
- 通过dhcp获取ip地址,每次重启后ip地址都会变;
- 在路由上看设备会占用好几个ip;
- 用非ifconfig列表的ip地址也能访问网关;
这些问题现象看起来很诡异的,每次都怀疑是不是测试搞错了。专门花时间分析了一下网络相关,原因也慢慢知道了。通过厂家的脚本写mac地址的方案在我们项目这里有个问题,这个脚本在dhcp之后才被执行! 就是说开机启动后eth1拿的一个不可预知的mac地址(跟eth0同一个默认mac地址)通过dhcp获取到了ip地址,然后再通过脚本配置了一个新的mac地址,然后再dhcp一个新的ip地址,所以导致了上面这些问题。
解决
这个问题可以通过把设置mac地址的脚本提前来解决,脚本目录如下:
# ls /etc/init.d/
S01syslogd S02klogd S02sysctl S10mdev S20urandom S21haveged S40network S41dhcpcd S50sshd rcK rcS
S40network S41dhcpcd 这两个脚本负责配置网络,我在 rcS 脚本设备eth1的mac地址,rcS 在后面执行的,想解决的话可以把脚本放在 S40network 脚本之前。
想了一下,这种方式还是不靠谱,因为设置mac地址的脚本依赖 ifconfig 命令,如果网络都没配置的话,命令执行的是什么结果呢?我没有去验证这个事情,因为我找到了更好的办法 - 修改uboot源码。看源码时得知,在uboot启动时会从 env 区(flash)读取eth0的mac地址,并写到mac寄存器,内核启动后加载mac驱动,驱动会尝试从mac寄存器读mac地址,验证是合法的就继续使用,不合法就用默认的mac地址。所以官方文档推荐在uboot通过” setenv -f ethaddr xx:xx:xx:xx:xx:xx “命令来烧录eth0的mac地址,但是eth1却晾下不管了(估计同系列有的芯片只有eth0)。
uboot启动时,会从 env 区读取eth0的mac地址,然后写到mac寄存器去,我添加了一段代码,把mac地址+1,同时写到eth1的mac寄存器去,以上问题得以解决。当然,只有一个网口的芯片不能用同一套uboot的代码。修改代码如下:
/boot/drivers/mstar/emac/infinity2m/mhal_emac.c
/*
根据 emac0 计算 emac1, emac1 的mac 地址默认比 emac0 大1
*/
void MHal_calc_emac1_mac(u32 *w0, u32 *w1, u8 m0,u8 m1,u8 m2,u8 m3,u8 m4,u8 m5)
{
m5 += 1;
if (m5 == 0)
{
m4 += 1;
if (m4 == 0)
{
m3 += 1;
if (m3 == 0)
{
m2 += 1;
if (m2 == 0)
{
m1 += 1;
if (m1 == 0)
{
m0 += 1;
}
}
}
}
}
*w0 = (u32)m3 << 24 | m2 << 16 | m1 << 8 | m0;
*w1 = (u32)m5 << 8 | m4;
}
void MHal_EMAC_Write_SA1_MAC_Address(u8 m0,u8 m1,u8 m2,u8 m3,u8 m4,u8 m5)
{
u32 w0 = (u32)m3 << 24 | m2 << 16 | m1 << 8 | m0;
u32 w1 = (u32)m5 << 8 | m4;
TITANIA_EMAC regs = (TITANIA_EMAC) REG_ADDR_BASE;
// 设置emac0的mac地址
regs->REG_EMAC_SA1L_L= w0&0x0000FFFF;
regs->REG_EMAC_SA1L_H= w0>>16;
regs->REG_EMAC_SA1H_L= w1&0x0000FFFF;
regs->REG_EMAC_SA1H_H= w1>>16;
// 添加对emac1 mac地址设置
MHal_calc_emac1_mac(&w0, &w1, m0, m1, m2, m3, m4, m5);
regs = (TITANIA_EMAC) REG_ADDR_BASE_EMAC1;
regs->REG_EMAC_SA1L_L= w0&0x0000FFFF;
regs->REG_EMAC_SA1L_H= w0>>16;
regs->REG_EMAC_SA1H_L= w1&0x0000FFFF;
regs->REG_EMAC_SA1H_H= w1>>16;
}
上面代码的 MHal_calc_emac1_mac 函数是自己实现的,然后需要找到emac1的基址,学着emac0一样写进去即可。
总结
- BUG要认真对待,了解内部实现并深入分析,不然表面现象会百思不得其解。
- 厂商可能是同一个uboot同时适配单个或多个网口的型号,所以用脚本的方案,可能改变脚本的启动顺序也能解决。无论用哪种方案,要写清楚文档或者代码提交记录,否则后面的人很难理解。
end
最后
以上就是跳跃烤鸡为你收集整理的网关第二路网口(eth1)mac地址烧录问题的全部内容,希望文章能够帮你解决网关第二路网口(eth1)mac地址烧录问题所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复