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,
};