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 = ð_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,
};