回环网卡驱动设计

Posted on 2015-03-14 17:51  Bumble_Bee  阅读(497)  评论(1编辑  收藏  举报

  回环网卡是一个虚拟网卡,当上层协议栈发出包后,包又会被发回给上层协议栈。下面来编程实现回环网卡驱动。

  所需头文件

#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/socket.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/in.h>
#include <linux/init.h>

#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <net/sock.h>
#include <net/checksum.h>
#include <linux/if_ether.h>    /* For the statistics structure. */
#include <linux/if_arp.h>    /* For ARPHRD_ETHER */
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/percpu.h>
#include <net/net_namespace.h>

  全局变量

unsigned long bites = 0;    //记录数据量
unsigned long packets = 0;   //记录数据包的数量

struct net_device *dev;     //定义一个网卡驱动

 

  从上篇网卡驱动架构分析中可知,首先要进行网卡的初始化

static __net_init int loopback_net_init(struct net *net)
{
    dev = alloc_netdev(0,"lo%d",lo_setup);  //给网卡驱动分配空间    
    register_netdev(dev);            //注册网卡驱动
    net->loopback_dev = dev;          

    return 0;
}

  这里没有用alloc_etherdev函数,因为alloc_etherdev只能为以太网卡分配空间。我们这里使用alloc_netdev函数,linux中函数定义为

define alloc_netdev(sizeof_priv, name, setup),其中第一个参数表示net_device结构中一个成员priv占用空间的大小,我们这里不使用,所以填0。第二个参数表示回环网卡的名称,第三个参数是一个函数指针,分配完空间后会自动调用setup函数来进行网卡的初始化,所以我们将初始化的操作移至setup函数中。分配好空间之后将网卡驱动注册到linux内核中。最后告诉linux内核回环网卡驱动为dev。

  接下来是lo_setup函数的实现

static void __init lo_setup(struct net_device *dev)
{
    dev->netdev_ops = &lo_ops;        //网卡操作函数集
    dev->mtu = (16*1024) + 20 + 20 + 12;  //最大能接收数据包的大小 
    dev->flags = IFF_LOOPBACK;        //网卡驱动的标志
    dev->header_ops = &eth_header_ops;   //构造头的函数集

}

  lo_setup函数进行网卡的初始化。上篇文章提到初始化中断号、I/O基地址、MAC地址都是针对物理的网卡,我们今天的回环网卡是一个虚拟网卡,所以不需要对他们进行初始化。这里初始化的有这几项:

    1、网卡操作函数集

    2、最大能接收数据包的大小

    3、网卡驱动的标志,指明是一个回环网卡

    4、构造头的函数集

  网卡操作函数集实现两个函数:数据的接收和查询网卡状态

struct net_device_ops lo_ops = 
{
    .ndo_start_xmit = lo_xmit,
    .ndo_get_stats = lo_get_stats,
};

  首先看发送数据函数的实现:

  

static int lo_xmit(struct sk_buff *skb, struct net_device *dev)
{
    /*标明以太网协议*/
    skb->protocol = eth_type_trans(skb,dev);

    /*统计信息*/
    bites += skb->len;
    packets ++;

    netif_rx(skb);

    return 0;
}

  由于回环网卡在发送数据之后立刻就将数据接收回来,所以不必让上层协议暂停发送数据。再者回环网卡是虚拟网卡,也不需要将数据写入寄存器中发送。在这个函数中我们只简单的统计数据长度和包数量的信息,然后将数据包发回给上层协议栈即可。

  然后是查看状态函数

static struct net_device_stats *lo_get_stats(struct net_device *dev)
{
    struct net_device_stats *stats = &dev->stats;
    stats->rx_packets = packets;
    stats->tx_packets = packets;
    stats->rx_bytes = bites;
    stats->tx_bytes = bites;

    return stats;
}

  这样回环网卡的驱动程序大致就设计完了。由于回环网卡是虚拟网卡,不牵扯中断、寄存器等硬件信息,所以驱动程序十分简单。

  如果有疑问或错误,欢迎指出。