Linux驱动开发、16-回环网卡驱动设计

1、回环网卡:它是一种虚拟设备,原理是自发自收,形成逻辑上的回路

 

 

 

2、回环网卡驱动设计步骤

 

设备初始化:

1、分配网卡设备:struct net_device *dev = alloc_netdev(0, "lo", loopback_setup);

参数1:私有空间

设备名:"lo"

回调函数:用来初始化设备,初始化数据包格式,关联操作函数集合

 

2、向内核注册网络设备:

err = register_netdev(dev);

错误跳转到注销:free_netdev(dev);

 

3、将注册好的设备回传给内核,不然会报错

net->loopback_dev = dev;

 

初始化回调函数 static void loopback_setup(struct net_device *dev)

1、 初始化数据格式 dev->mtu(网卡最大接收包长度)、网卡类型标志 dev->flags

2、 关联操作函数:

dev->header_ops = ð_header_ops; /*这个函数是内核提供的,

用来构造数据包包头*/

dev->netdev_ops = &loopback_ops; /*网卡操作集合*/

 

编写网卡操作集合

1、关联集合

/*操作函数集合*/

static const struct net_device_ops loopback_ops = {

.ndo_start_xmit= loopback_xmit, /*发送函数*/

.ndo_get_stats = loopback_get_stats, /*状态统计*/

};

 

 

 

2、数据传输:loopback_xmit,

static netdev_tx_t loopback_xmit(struct sk_buff *skb,

 struct net_device *dev)

{

/*自发自收就不用停止上层协议传输数据了

既不用调用netif_stop_queue(dev);*/

/*1、填充数据包的协议类型*/

/*2、统计包数量,长度*/

/*3、在发送调用接收函数实现回环,将数据包丢给上层协议处理*/

ret = netif_rx(skb);

return 0;

}

3、统计处理loopback_get_stats

static struct net_device_stats *loopback_get_stats(struct net_device *dev)

{

struct net_device_stats *stats = &dev->stats; /*接收来至*/

....

将相关状态填写到该结构体中

....

return stats; /*将结构体返回给内核跟新数据*/

}

4、配置dev->ethtool_ops = &loopback_ethtool_ops;(不重要)

该配置支持用户空间工具。这些工具负责设置和提取设备参数。ethtool工具可以为以 太网卡NIC配置参数:可以在终端查看效果ethtool -e eth0


5、程序设计


#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 bytes = 0;
unsigned long packets = 0;
/*
 * The higher levels take care of making this non-reentrant (it's
 * called with bh's disabled).
 */
static netdev_tx_t loopback_xmit(struct sk_buff *skb,
struct net_device *dev)
{
int ret = 0;
/*自发自收就不用停止上层协议传输数据了*/

/*填充数据包的协议类型*/
skb->protocol = eth_type_trans(skb,dev);

/*统计包数量*/
bytes += skb->len;
packets++;


/*在发送调用接收函数实现回环,将数据包丢给上层协议处理*/
ret = netif_rx(skb);

if(ret < 0)
{
printk("send skb err!\n");
}

return 0;

}


static struct net_device_stats *loopback_get_stats(struct net_device *dev)
{
struct net_device_stats *stats = &dev->stats;

stats->rx_packets = packets;
stats->tx_packets = packets;
stats->rx_bytes = bytes;
stats->tx_bytes = bytes;
return stats;
}


/*操作函数集合*/
static const struct net_device_ops loopback_ops = {
.ndo_start_xmit= loopback_xmit, /*发送函数*/
.ndo_get_stats = loopback_get_stats, /*获取相关状态,包长度,个数等*/
};


/*
 * The loopback device is special. There is only one instance
 * per network namespace.
 */
 unsigned char dev_addr[] = {1,2,3,4,5,6} ;
static void loopback_setup(struct net_device *dev)
{
/*1、初始化数据格式*/
dev->mtu = (16 * 1024) + 20 + 20 + 12; /* interface MTU value*/
dev->hard_header_len = ETH_HLEN; /* 14 */
dev->addr_len = ETH_ALEN; /* 6 */
dev->tx_queue_len = 0;
dev->type = ARPHRD_LOOPBACK; /* 0x0001*/
dev->flags = IFF_LOOPBACK; /*网卡类型标志*/
dev->dev_addr = dev_addr; /*MAC地址*/
dev->header_ops = &eth_header_ops; /*这个函数是内核提供的,数据包头构造*/
dev->netdev_ops = &loopback_ops; /*网卡操作集合*/
}




/* Setup and register the loopback device. */
static __net_init int loopback_net_init(struct net *net)
{
int err = -ENOMEM;
/*1、分配结构*/
struct net_device *dev;
dev = alloc_netdev(0,"lo",loopback_setup);
if(!dev)
goto out;

/*2、注册网络设备*/
err = register_netdev(dev);
if(err < 0)
goto out_free_netdev;

/*3、向内核填充设备*/
net->loopback_dev = dev;

return 0;


out_free_netdev:
free_netdev(dev);
out:
if (net_eq(net, &init_net))
panic("loopback: Failed to register netdevice: %d\n", err);
return err;
}


static __net_exit void loopback_net_exit(struct net *net)
{
struct net_device *dev = net->loopback_dev;
unregister_netdev(dev);
}
/* Registered in net/core/dev.c */
struct pernet_operations __net_initdata loopback_net_ops = {
       .init = loopback_net_init,
       .exit = loopback_net_exit,
};

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章