我是靠谱客的博主 跳跃烤鸡,最近开发中收集的这篇文章主要介绍网关第二路网口(eth1)mac地址烧录问题,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

背景

网卡使用的是sigmastar的SSD202D芯片,该芯片有两个网口,其中一个网口需要外部的phy,方案图如下:
ssd201双网口方案
那么两个网口的mac地址是怎么存储的呢?如果是存储在mac模块内的flash是最理想的,烧录一次后就跟硬件走,芯片出厂前厂家烧录到芯片内更好。然而并不是。查看资料和代码后知道芯片并不会存储,每次上电后需要写入到mac寄存器。厂家的文档可以印证:
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地址烧录问题所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(34)

评论列表共有 0 条评论

立即
投稿
返回
顶部