Linux内核设置MAC地址的过程-以SAMA5D27处理器为例

1 引言

    SAMA5D27处理器有一个Ethernet MAC(GMAC)控制器,支持10/100 Mbps。Linux下GMAC控制器的驱动源码路径为: \linux-at91\drivers\net\ethernet\cadence\macb_main.c。
    查看SAMA5D27处理器内核启动日志,找到网卡初始化部分,查看硬件MAC地址的设置。

在这里插入图片描述
    进入系统后,执行ifconfig查看网卡信息。下图中eth0 对应的是SAMA5D27 GMAC,连接的PHY KSZ8081。
在这里插入图片描述
    在SAMA5D27的Linux系统下,每次启动Linux系统,MAC都会发生变化,这个主要是驱动里关于MAC的处理机制导致的。下面的章节阐述了驱动中MAC的处理机制。

2 Linux内核驱动中MAC地址设置流程

找到并进入probe函数:macb_probe
路径:\linux-at91\drivers\net\ethernet\cadence\macb_main.c
在这里插入图片描述
找到mac 地址获取部分的函数。
在这里插入图片描述
首先来看函数:of_get_mac_address,路径:/drivers/of/of_net.c。该函数用于搜索设备树节点下是否配置MAC地址相关的属性。
在这里插入图片描述
    我们的设备树下并未配置MAC address相关的属性,接着进入of_get_nvmem_mac_address函数。

    函数:of_get_nvmem_mac_address,路径:/drivers/of/of_net.c。该函数用于搜索设备树节点下是否有nvmem(Non Volatile Memory,不易丢失的存储)配置MAC地址相关的属性。
在这里插入图片描述
    我们的设备树下并未配置非易失存储MAC address相关的属性,接着进入macb_get_hwaddr函数。

    函数:macb_get_hwaddr,路径:\drivers\net\ethernet\cadence\macb_main.c

在这里插入图片描述
    dev_get_platdata获取device结构体成员变量的void * platform_data。接下来读取GMAC Specific Address Bottom/Top Register[1:4],获取可用的 hw address,由于这个4组寄存器并未进行配置,值全部为零,并不是有效的MAC地址。
    在没有可用的 hw address的时候,会调用函数eth_hw_addr_random,随机生成一组MAC地址。

3 Linux用户态修改MAC地址

3.1 配置命令ifconfig

可以通过命令行设置MAC物理地址,命令如下:
ifconfig eth0 down
ifconfig eth0 hw ether 1234567890ab
ifconfig eth0 up

3.2 配置命令ifconfig与内核的交互

下面介绍一下命令行ifconfig是如何与内核交互的。
ifconfig的源代码位于busybox,也可自行下载,分析如下:
对应ifconfig eth0 down和ifconfig eth0 up的函数如下:

在这里插入图片描述

    比如,当我们敲ifconfig eth0 down时,实则就是调用:
set_if_down(“eth0”, master_flags.ifr_flags);

    除了上面的两个函数外,还有以下常用函数:
set_if_addr(); //设置地址(包括IP,掩码,广播,目的地)
set_master_hwaddr(); //设置mac物理地址

    接下来我们以eth0为例,来跟踪ifconfig up/down和ifconfig eth0 hw ether如何调用内核的。

1)分析set_if_up()
set_if_up()函数将会调用set_if_flags(“eth0”, flags | IFF_UP), 添加ifname(eth0) 开启标志位。
在这里插入图片描述

2)分析set_if_up()->set_if_flags(“eth0”, flags | IFF_UP)
该函数如下所示:

在这里插入图片描述
3)寻找SIOCSIFFLAGS宏,看看内核那里在实现它。
找到位于net\core\dev_ioctl.c的dev_ioctl()函数,该函数重要部分代码如下:
在这里插入图片描述
从上面可以看出,我们设置mac物理地址时的流程也会运行到这里,最终他们都会调用dev_ifsioc(net, &ifr, cmd)函数。

4)最终ifconfig eth0 up调用内核过程
在这里插入图片描述

然后在__dev_change_flags(dev, flags)函数中,通过判断flag的IFF_UP位上的值是否相反,来实现是调用__dev_close()还是__dev_open()来开关eth0。
如下图所示:

在这里插入图片描述
    然后__dev_open()则将会调用网卡驱动的net_device_ops结构体下的成员函数实现打开。
    __dev_open(dev):
    dev->netdev_ops->ndo_validate_addr(dev); //测试dev->dev_addr(hw addr)是否有效,一般都是调用eth_validate_addr()函数,需要注意hw_addr[0]的最低位不能为1
    dev->netdev_ops->ndo_open(dev); //调用open()函数实现ifconfig up

    同样__dev_close()会调用下面的成员函数实现关闭:
dev->netdev_ops->ndo_stop(dev); //调用stop ()函数实现ifconfig down

    寻找net_device_ops结构体的成员函数位于哪里?
    上面讲的dev 变量是struct net_device类型,而struct net_device在内核中表示我们的一个网卡驱动设备,注册该变量的文件都处于内核drivers/net目录下,通过register_netdev() 内核函数来注册。
    
    以SAMA5D27处理的GMAC网卡为例,路径:
\linux-at91\drivers\net\ethernet\cadence\macb_main.c
在这里插入图片描述
而对于ifconfig eth0 hw ether 设置网卡的MAC地址流程如下所示:

在这里插入图片描述
最终调用 eth_mac_addr 函数:
路径:/net/ethernet/eth.c
在这里插入图片描述

4 总结

    使用ifconfig命令可以临时修改MAC地址,但开发板重启后,由于内核重新加载,MAC地址还是会随机生成。如果想固定MAC地址,可以对内核进行修改,在MAC控制器驱动的probe函数中,macb_get_hwaddr函数下,直接对存储MAC地址的结构体进行赋值。

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

heat.huang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值