虚拟网卡驱动
来源:互联网 发布:淘宝royce 假货 编辑:程序博客网 时间:2024/05/01 10:28
学习了linux驱动程序,模仿tun写了一个虚拟网卡驱动,非常简陋
[虚拟网卡设备] <----> [字符设备] <----> [NIC]
设备虚拟网络卡设备,和字符设备,通过socket向虚拟网卡发送和接受的数据,可以通过字符设备进行读写.
通过一个用户空间程序,可以将字符设备和真实的网卡连接起来,并实现虚拟网卡和真实网卡的桥接
- #include <linux/module.h>
- #include <linux/errno.h>
- #include <linux/kernel.h>
- #include <linux/miscdevice.h>
- #include <linux/init.h>
- #include <linux/major.h>
- #include <linux/slab.h>
- #include <linux/fcntl.h>
- #include <linux/skbuff.h>
- #include <linux/netdevice.h>
- #include <linux/etherdevice.h>
- #include <linux/if.h>
- #include <linux/if_arp.h>
- #include <linux/if_ether.h>
- #define DBG(x...) printk(x)
- //#define DBG(x...)
- #define VNIC_MINOR 200
- #define READQ_SIZE 500
- #define SETIFUP 0xff0001
- #define SETIFDN 0xff0002
- #define SETIFRUN 0xff0003
- static LIST_HEAD(vnic_net_list);
- struct vnic_struct{
- struct list_head list; //设备链表
- wait_queue_head_t read_head; //等待队列
- spinlock_t lock; //琐
- struct sk_buff_head readq; //收包队列
- struct net_device *dev; //net_device
- struct net_device_stats stats; //设备状态
- };
- loff_t no_chr_llseek(struct file *file, loff_t offset, int origin){
- return -ESPIPE;
- }
- static int vnic_chr_open(struct inode *inode, struct file *file){
- file->private_data = NULL;
- return 0;
- }
- static int vnic_chr_close(struct inode *inode, struct file *file){
- return 0;
- }
- static ssize_t vnic_chr_read(struct file * file, char __user * buf,
- size_t count, loff_t *pos){
- struct sk_buff *skb;
- struct vnic_struct *vnic = file->private_data;
- int len;
- DECLARE_WAITQUEUE(wait, current); //声明并初始化等待队列
- add_wait_queue(&vnic->read_head, &wait); //加入等待队列
- wait_event_interruptible(vnic->read_head, skb_queue_len(&vnic->readq)>0);
- if(vnic == NULL){
- DBG(KERN_INFO"vnic data wrong/n");
- return -1;
- }
- skb = skb_dequeue(&vnic->readq); //从收包队列中解包
- if(skb == NULL){
- DBG(KERN_INFO"no packet/n");
- return 0;
- }
- netif_wake_queue(vnic->dev); //重新唤醒收包队列(当队列满时,将停止收包,这边来唤醒)
- len = skb->len;
- if(copy_to_user(buf, skb->data, len)){ //提交给用户空间
- DBG(KERN_ERR"copy to use failed/n");
- }
- /*
- 统计状态维护
- */
- vnic->stats.tx_packets++;
- vnic->stats.tx_bytes += len;
- kfree_skb(skb); //释放skb
- remove_wait_queue(&vnic->read_head, &wait); //移出等待队列
- schedule(); //放弃cpu
- return len;
- }
- static ssize_t vnic_chr_write(struct file * file, const char __user * buf,
- size_t count, loff_t *pos){
- struct vnic_struct *vnic;
- struct sk_buff *skb;
- struct net_device *dev;
- int len;
- int align = 2;
- vnic = file->private_data;
- if(vnic == NULL){
- DBG(KERN_DEBUG"write data wrong/n");
- return -1;
- }
- dev = vnic->dev;
- len = count;
- if(len > dev->mtu + ETH_HLEN){ //包过大
- vnic->stats.rx_dropped++;
- DBG(KERN_INFO"packet too long/n");
- return -1;
- }
- skb = alloc_skb(len + align, GFP_KERNEL); //分配skb
- if(skb == NULL){
- vnic->stats.rx_dropped++;
- DBG(KERN_ERR"alloc skb failed/n");
- return -1;
- }
- skb_reserve(skb, align); //16bytes对齐
- skb_put(skb, len); //移动指针,准备数据copy
- if(copy_from_user(skb->data, buf, len)){ //用户空间copy数据
- kfree_skb(skb); //失败,释放skb
- DBG(KERN_INFO"copy from user failed/n");
- vnic->stats.rx_dropped++;
- return -1;
- }
- skb->dev = dev;
- skb->protocol = eth_type_trans(skb, dev); //解析以太协议
- netif_rx_ni(skb); //提交给上层协议栈
- dev->last_rx = jiffies; //last_rx维护
- /*
- 设备状态维护
- */
- vnic->stats.rx_packets++;
- vnic->stats.rx_bytes += len;
- return len;
- }
- int vnic_net_open(struct net_device *dev){
- netif_start_queue(dev); //启动队列
- return 0;
- }
- int vnic_net_stop(struct net_device *dev){
- netif_stop_queue(dev); //停止队列
- return 0;
- }
- int vnic_net_tx(struct sk_buff *skb,
- struct net_device *dev){
- struct vnic_struct *vnic = netdev_priv(dev);
- if(skb_queue_len(&vnic->readq) >= dev->tx_queue_len){ //队列是否满
- vnic->stats.tx_dropped++; //丢包
- kfree_skb(skb);
- netif_stop_queue(dev); //停止队列
- DBG(KERN_INFO"read queue is full/n");
- }else{
- skb_queue_tail(&vnic->readq, skb); //加入收包队列,等待处理
- dev->trans_start = jiffies;
- }
- wake_up_interruptible(&vnic->read_head); //唤醒等待队列
- DBG(KERN_DEBUG"tx queue: %d/n", skb_queue_len(&vnic->readq));
- return 0;
- }
- static struct net_device_stats *vnic_net_stats(struct net_device *dev)
- {
- struct vnic_struct *vnic = netdev_priv(dev);
- return &vnic->stats;
- }
- void vnic_setup(struct net_device *dev){
- struct vnic_struct *vnic = netdev_priv(dev); //获取net_device私有数据
- ether_setup(dev); //设置设备为以太网设备,定义部分以太网络的参数
- /*
- 以下为设置网络设备的操作函数
- */
- dev->open = vnic_net_open;
- dev->stop = vnic_net_stop;
- dev->hard_start_xmit = vnic_net_tx;
- dev->get_stats = vnic_net_stats;
- random_ether_addr(dev->dev_addr); //随机源地址
- dev->tx_queue_len = READQ_SIZE; //收包队列长度
- vnic->dev = dev; //设置私有数据的net_device成员
- memset(&vnic->stats, 0, sizeof(struct net_device_stats));
- spin_lock_init(&vnic->lock);
- init_waitqueue_head(&vnic->read_head); //初始化等待队列
- skb_queue_head_init(&vnic->readq); //初始化收包队列
- spin_lock(&vnic->lock);
- list_add(&vnic->list, &vnic_net_list); //将新建vnic_struct加入到设备链表
- spin_unlock(&vnic->lock);
- }
- struct net_device *setup_dev(void){
- struct net_device *dev;
- dev = alloc_netdev(sizeof(struct vnic_struct), "vnic%d", vnic_setup); //分配net_device,初始化函数vnic_setup
- if(dev == NULL){
- DBG(KERN_ERR"alloc net device failed/n");
- return NULL;
- }
- if(register_netdev(dev) != 0){ //注册网络设备
- DBG(KERN_ERR"register net device failed/n");
- return NULL;
- }
- return dev;
- }
- int shutdown_dev(void){
- struct vnic_struct *vnic, *next;
- list_for_each_entry_safe(vnic, next, &vnic_net_list, list){ //遍历所有vnic_struct
- spin_lock(&vnic->lock);
- skb_queue_purge(&vnic->readq); //清空收包队列
- list_del(&vnic->list); //将当前vnic_struct从队列中删除
- unregister_netdev(vnic->dev); //注销网络设备
- free_netdev(vnic->dev); //释放网络设备
- spin_unlock(&vnic->lock);
- }
- return 0;
- }
- static int vnic_chr_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg){
- int ret = 0;
- struct net_device *dev;
- struct vnic_struct *vnic;
- switch(cmd){
- case SETIFUP: //建立虚拟网卡
- if((dev = setup_dev()) == NULL){
- DBG(KERN_DEBUG"setup net device failed/n");
- ret = -EFAULT;
- }else{
- file->private_data = netdev_priv(dev);
- }
- break;
- case SETIFDN: //关闭虚拟网卡
- if(shutdown_dev() == -1){
- DBG(KERN_DEBUG"shutdown net device failed/n");
- ret = -EFAULT;
- }
- break;
- }
- return ret;
- }
- struct file_operations vnic_ops = {
- .owner = THIS_MODULE,
- .llseek = no_chr_llseek,
- .open = vnic_chr_open,
- .release = vnic_chr_close,
- .read = vnic_chr_read,
- .write = vnic_chr_write,
- .ioctl = vnic_chr_ioctl
- };
- static struct miscdevice vnic_misc = {
- .minor = VNIC_MINOR, //混合设备minor号
- .name = "vnic", //设备名称
- .fops = &vnic_ops //操作函数定义
- };
- int vnic_chr_init(void){
- int ret = 0;
- ret = misc_register(&vnic_misc); //注册为混合设备,major = 10
- if(ret){
- DBG(KERN_INFO"misc register failed, device name:%s/n", vnic_misc.name);
- }else{
- DBG(KERN_INFO"misc register OK, device: %s, minor: %d/n", vnic_misc.name, vnic_misc.minor);
- }
- return ret;
- }
- void vnic_chr_exit(void){
- misc_deregister(&vnic_misc); //注销混合设备
- shutdown_dev(); //关闭网络设备
- DBG(KERN_INFO"misc deregister OK/n");
- }
- MODULE_AUTHOR("wzq");
- MODULE_LICENSE("GPL");
- module_init(vnic_chr_init);
- module_exit(vnic_chr_exit);
- 网卡驱动2----虚拟网卡
- 虚拟网卡驱动
- linux虚拟网卡驱动
- 虚拟网卡驱动
- 虚拟网卡驱动
- linux虚拟网卡驱动
- 网卡驱动之虚拟网卡驱动编写
- 网卡驱动之虚拟网卡驱动编写
- 虚拟网卡驱动(二)
- linux虚拟网卡驱动代码
- Linux驱动之虚拟网卡
- windows虚拟网卡驱动开发
- linux驱动之网卡驱动-虚拟网卡驱动编写
- [Linux驱动开发] 网络设备之虚拟网卡
- 安装微软自带虚拟网卡驱动
- WIN7 64位 x64虚拟网卡驱动
- 虚拟网卡驱动出现的问题
- VMware 虚拟网卡驱动无法安装
- ksoftirqd内核线程
- 35岁IT老人的随笔
- 老的BH机制
- 《越狱》中电磁场破坏钢筋混凝土墙的原理
- DataGridView新特色、常用操作
- 虚拟网卡驱动
- 内核源码编排
- 我的挨踢人生--泪笔!!
- Seasar+S2Dao+S2Struts+Mayaa
- 《FC7和红帽企业Linux5完全指南》学习笔记
- 入门大杂混
- 如何在Solaris/OpenSolaris上mount ntfs文件系统?
- 数据库定义-约束
- ns2中link的有关知识