首页 > 代码库 > linux内核数据包转发流程(一):网络设备驱动

linux内核数据包转发流程(一):网络设备驱动

【版权声明:转载请保留出处:blog.csdn.net/gentleliu。邮箱:shallnew*163.com】

网卡驱动为每一个新的接口在一个全局的网络设备列表里插入一个数据结构.每一个接口由一个结构 net_device 项来描写叙述, 它在 <linux/netdevice.h> 里定义。该结构必须动态分配。

进行这样的分配的内核函数是 alloc_netdev, 它有下列原型:
struct net_device *alloc_netdev(int sizeof_priv, const char *name, void (*setup)(struct net_device *));
sizeof_priv 是驱动的的"私有数据"区的大小;name 是这个接口的名子;这个名子能够有一个 printf 风格的 %d 在里面. 内核用下一个可用的接口号来替换这个 %d。setup 是一个初始化函数的指针, 被调用来设置 net_device 结构的剩余部分。
网络子系统为各种接口提供了一些帮助函数, 包裹着 alloc_netdev。最通用的是 alloc_etherdev, 定义在 <linux/etherdevice.h>,还有其它网络设备接口,如alloc_fcdev ( 定义在 <linux/fcdevice.h> ) 为 fiber-channel 设备, alloc_fddidev (<linux/fddidevice.h>) 为 FDDI 设备, 或者 aloc_trdev (<linux/trdevice.h>) 为令牌环设备。
alloc_etherdev函数原型为:
struct net_device *alloc_etherdev(int sizeof_priv);
当中sizeof_priv 是驱动的的"私有数据"区的大小;这个函数分配一个网络设备使用 eth%d 作为參数 name. 它提供了自己的初始化函数 ( ether_setup )来设置几个 net_device 字段, 使用对以太网设备合适的值。 因此, 没有驱动提供的初始化函数给 alloc_etherdev;
他自己提供的初始化函数ether_setup为:
/**
 * ether_setup - setup Ethernet network device
 * @dev: network device
 * Fill in the fields of the device structure with Ethernet-generic values.
 */
void ether_setup(struct net_device *dev)
{
    dev->header_ops        = e_header_ops;
    dev->type        = ARPHRD_ETHER;
    dev->hard_header_len     = ETH_HLEN;
    dev->mtu        = ETH_DATA_LEN;
    dev->addr_len        = ETH_ALEN;
    dev->tx_queue_len    = 1000;    /* Ethernet wants good queues */
    dev->flags        = IFF_BROADCAST|IFF_MULTICAST;

    memset(dev->broadcast, 0xFF, ETH_ALEN);

}

EXPORT_SYMBOL(ether_setup);
实际上该函数也是不过负责了一些以太网范围中的缺省值而已。一般alloc_netdev函数提供的setup函数也会调用该函数来设置这些缺省值。
事实上无论使用alloc_netdev函数还是alloc_etherdev函数都不只设置这些缺省值就够了。
既然是编写网络设备驱动,就要完毕网卡的基本功能:收发数据包,统计网卡数据等,所以一般还要设置该结构体里面的这些功能函数指针,而这些函数正是网络设备驱动须要实现的基本功能。所以假设使用函数alloc_netdev分配空间,那么setup函数一般实现为:
{
        ether_setup(dev);  
      
    #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))  
        dev->netdev_ops = &xxx_netdev_ops;  
    #else  
        dev->open               = xxx_open;  
        dev->stop               = xxx_stop;  
        dev->hard_start_xmit    = xxx_tx;  
        dev->get_stats          = xxx_stats;  
    //    dev->change_mtu         = xxx_change_mtu;  
        ...  
    #endif  
}
假设使用alloc_etherdev函数分配,那么在该函数之后还须要作例如以下设置:
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))  
        dev->netdev_ops = &xxx_netdev_ops;  
    #else  
        dev->open               = xxx_open;  
        dev->stop               = xxx_stop;  
        dev->hard_start_xmit    = xxx_tx;  
        dev->get_stats          = xxx_stats;  
    //    dev->change_mtu         = xxx_change_mtu;  
        ...  
    #endif

事实上二者的区别就是alloc_etherdev函数默认自己主动调用ether_setup函数而且自己主动分配一个网络设备使用 eth%d 作为參数 name,而函数alloc_netdev须要自己传入參数来设置这些项而已。
net_device 结构初始化之后, 传递这个结构给 register_netdev函数完毕注冊。
然后你必需要做的就是实现之前注冊的那些函数,收发函数的具体分析会在后面具体解说。