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        = ð_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函数完成注册。
然后你必须要做的就是实现之前注册的那些函数,收发函数的具体分析会在后面详细讲解。

你可能感兴趣的:(网络,内核,网卡,linux内核,以太网)