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

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