環境
系統:Ubuntu16.04
kernel:4.10.0-28-generic
建立目錄和檔案
~$ mkdir virnet
~$ cd virnet
~/virnet$ touch virnet.c
~/virnet$ touch Makefile
添加以下内容到virnet.c檔案
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
MODULE_LICENSE("GPL");
// 網絡裝置對象
static struct net_device *sg_dev;
// 有資料幀要發送時,kernel會調用該函數
static int virnet_send_packet(struct sk_buff *skb,struct net_device *dev)
{
// 統計已發送的資料包
dev->stats.tx_packets++;
// 統計已發送的位元組
dev->stats.tx_bytes+=skb->len;
// 釋放資料幀
dev_kfree_skb(skb);
return 0;
}
// 驅動程式支援的操作
static struct net_device_ops sg_ops=
{
// 發送資料幀
.ndo_start_xmit=virnet_send_packet,
};
// 驅動程式初始化
static int virnet_init(void)
{
// 建立一個網絡裝置,名為“virnet%d",kernel會自動填寫%d為網卡編号
//sg_dev=alloc_netdev(0,"virnet%d",ether_setup);
// kernel 4.4.0-97上需要四個參數如下
sg_dev=alloc_netdev(0,"virnet%d", NET_NAME_UNKNOWN, ether_setup);
// 該網絡裝置的操作集
sg_dev->netdev_ops=&sg_ops;
// MAC位址是01:02:03:04:05:06
memcpy(sg_dev->dev_addr,"\x01\x02\x03\x04\x05\x06",6);
// 注冊網絡裝置
register_netdev(sg_dev);
return 0;
}
// 驅動程式銷毀
static void virnet_exit(void)
{
// 登出網絡裝置
unregister_netdev(sg_dev);
// 釋放對象
free_netdev(sg_dev);
}
module_init(virnet_init);
module_exit(virnet_exit);
添加以下内容到Makefile檔案
obj-m := virnet.o
KERNEL_DIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
make -C $(KERNEL_DIR) SUBDIRS=$(PWD) modules
clean:
rm *.o *.ko *.mod.c
.PHONY:clean
編譯和測試
~/virnet$ make
~/virnet$ sudo insmod virnet.ko
~/virnet$ ifconfig -a
~/virnet$ sudo rmmod virnet
參考
第一個Linux網絡裝置驅動——最簡虛拟網卡virnet