Linux Intel网卡IGB驱动修改mac地址

本文深入探讨了如何在Linux内核中,特别是在Intel IGB驱动下修改网卡的MAC地址。通过分析`igb_probe`函数,了解到如何从NVM读取MAC、设置自定义MAC,并探讨了相关网络驱动注册过程。文中还提供了添加自定义MAC的示例代码,并展示了修改后的效果。
摘要由CSDN通过智能技术生成

实然心血来潮,想研究一下Intel网卡mac地址是怎么设置的。本文使用IGB驱动,适合于i211等网卡。

MAC地址对于网络来说十分重要,观察过几个网络驱动,发现在Linux内核中,MAC来龙去脉无非以下几个:

1、通过某种方式读取到mac地址,如果没有,则会有随机的mac地址,比如从eeprom中读取一个预先定义的MAC号;
2、赋值到netdev的dev_addr——这个值是驱动中使用的地址;
3、注册网络驱动,多个网卡则要进行多次注册;
4、如果在用户空间更改mac地址,则使用net_device_ops对应的函数,在该实现函数中要更新netdev的dev_addr,还有可能要修改具体芯片的eeprom。
一、IGB驱动

IGB的初始化在igb_main.c文件igb_init_module()函数:

    static int __init igb_init_module(void)
    {
        int ret;
     
        pr_info("%s - version %s\n",
               igb_driver_string, igb_driver_version);
        pr_info("%s\n", igb_copyright);
     
    #ifdef CONFIG_IGB_DCA
        dca_register_notify(&dca_notifier);
    #endif
        ret = pci_register_driver(&igb_driver);
     
        return ret;
    }

调用pci_register_driver注册pci驱动,最终会调用到同文件的igb_probe函数,在probe函数中进行各种初始化工作,包括读取NVM的mac地址,注册网络设备。

注意,如果主板有多个网卡,由于它们的PCI地址不同,会多次调用到igb_probe函数。
读取MAC地址并进行赋值代码片段如下:

        /* copy the MAC address out of the NVM */
        // 读取eeprom的mac地址,实际调用的函数为igb_read_mac_addr_82575()。
        if (hw->mac.ops.read_mac_addr(hw))
            dev_err(&pdev->dev, "NVM Read Error\n");
     
        // 拷贝到netdev的dev_addr,这个是内核中使用的变量
        memcpy(netdev->dev_addr, hw->mac.addr, netdev->addr_len);
        // 判断MAC是否合法
        if (!is_valid_ether_addr(netdev->dev_addr)) {
            dev_err(&pdev->dev, "Invalid MAC Address\n");
            err = -EIO;
            goto err_eeprom;
        }

二、添加自定义的MAC地址

下面在igb_probe中写入自定义的MAC地址,示例代码片段如下:

        // new add by Late Lee
        unsigned char mac[] = {0x6c, 0x61, 0x74, 0x75, 0x6c, 0x65};
        // 根据pci地址做MAC区别,防止使用同一MAC
        if (pdev->bus->number == 1)
        {
                printk(KERN_ERR "net device num1.\n");
                mac[5] = 0x65;
        }
        else if (pdev->bus->number == 2)
        {
            printk(KERN_ERR "net device num2.\n");
            mac[5] = 0x66;
        }
        // 设置到nvm
        // 存疑:手册好像提到invm有次数限制,但看得不是很明白,故存疑
        // igb_rar_set_qsel(adapter, mac, 0, adapter->vfs_allocated_count);
        // end adding
     
        /* copy the MAC address out of the NVM */
        if (hw->mac.ops.read_mac_addr(hw))
            dev_err(&pdev->dev, "NVM Read Error\n");
        
        // add by Late Lee
        printk(KERN_ERR "read mac addr: %pM but will update it!!\n", hw->mac.addr);
        // 拷贝到hw结构体,其它函数需要使用
        memcpy(hw->mac.addr, mac, 6);
        // end adding
        memcpy(netdev->dev_addr, hw->mac.addr, netdev->addr_len);

思路如下:

1、首先根据PCI地址变换不同的MAC号,否则多个网卡都有相同的MAC号。

2、将自定义的mac地址拷贝到hw结构体的mac.addr中,注意,这个值会在igb_configure_rx函数(最后还是调用igb_rar_set_qsel)中调用到,因此要同步更新。如果只更新netdev的dev_addr是无法使用网络通信的。


效果如下:

    root@latelee:~# ifconfig
    eth0      Link encap:Ethernet  HWaddr 6c:61:74:75:6c:65
    ...
    eth1      Link encap:Ethernet  HWaddr 6c:61:74:75:6c:66
    ...

注:

1、网络操作函数集net_device_ops有设置MAC号接口:ndo_set_mac_address,对于igb驱动调用igb_set_mac,最后会调用igb_rar_set_qsel写入了iNVM中。
2、i211手册,table 8-6,0x5404 + 8 *n、0x5400 + 8*n分别是高、低地址,共32位字节。从代码上看,除了读取mac地址外,还有其它用途。
三、其它

下面是igb_probe函数栈调用:

    [    3.295643]  [<c16f6e6a>] dump_stack+0x41/0x57
    [    3.300176]  [<c144e5cf>] igb_probe+0xedf/0x1100
    [    3.304881]  [<c12c4957>] local_pci_probe+0x17/0x50
    [    3.309848]  [<c12c48f3>] ? pci_match_device+0xc3/0xe0
    [    3.315148]  [<c12c4b88>] pci_device_probe+0x58/0x80
    [    3.320202]  [<c13fc56f>] driver_probe_device+0x6f/0x200
    [    3.325601]  [<c12c48f3>] ? pci_match_device+0xc3/0xe0
    [    3.330825]  [<c13fc779>] __driver_attach+0x79/0x80
    [    3.335789]  [<c13fb0d8>] bus_for_each_dev+0x68/0x90
    [    3.340841]  [<c13fc3f9>] driver_attach+0x19/0x20
    [    3.345630]  [<c13fc700>] ? driver_probe_device+0x200/0x200
    [    3.351288]  [<c13fbfef>] bus_add_driver+0x14f/0x1d0
    [    3.356342]  [<c19c7631>] ? mdio_bus_init+0x38/0x38
    [    3.361308]  [<c19c7631>] ? mdio_bus_init+0x38/0x38
    [    3.366272]  [<c13fcae4>] driver_register+0x54/0xe0
    [    3.371242]  [<c16f6d19>] ? printk+0x38/0x3a
    [    3.375598]  [<c12c4c4e>] __pci_register_driver+0x2e/0x40
    [    3.381084]  [<c19c768d>] igb_init_module+0x5c/0x7a
    [    3.386051]  [<c10003b2>] do_one_initcall+0x72/0x190
    [    3.391105]  [<c19c7631>] ? mdio_bus_init+0x38/0x38
    [    3.396081]  [<c10596ab>] ? parse_args+0x1ab/0x370
    [    3.400966]  [<c1072d50>] ? __wake_up+0x40/0x50
    [    3.405584]  [<c198c648>] kernel_init_freeable+0x124/0x1c9
    [    3.411163]  [<c198c6ed>] ? kernel_init_freeable+0x1c9/0x1c9
    [    3.416924]  [<c16f54db>] kernel_init+0xb/0xe0
    [    3.421455]  [<c16faac1>] ret_from_kernel_thread+0x21/0x30
    [    3.427029]  [<c16f54d0>] ? rest_init+0x70/0x70
---------------------  

原文:https://blog.csdn.net/subfate/article/details/52440498  
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值