Tap虚拟网卡

1 概述

Tap设备通常用于虚拟化场景下,其驱动代码位于drivers/net/tun.c,tap与tun复用大部分代码,

注:drivers/net/tap.c并不是tap设备的代码,而是macvtap和ipvtap;

下文中,我们统一称tap;参考下图tap设备架构:

图中标注了关键函数,以及数据流向。 tap设备分为两部分:

  • 网卡功能,向上对接着内核协议栈,对应驱动中的数据结构tun_struct;
  • 数据接口,向下对接虚拟网卡后端,对应驱动中的数据结构tun_file,它有两种接口:
    • file,给用户态使用,在内核的处理函数是tun_chr_read/write_iter();
    • socket,给内核态使用,主要是vhost,如上图中;

在上面的图中,哪部分是虚拟网卡?

  • virtio-net + (qemu-vhost) + tap
    • virtio-net是Guest上虚拟网卡的前端,
    • qemu是控制平面,vhost是数据平面
    • tap设备是需要网卡的后端;
  • tap + (qemu-vhost) + virtio-net
    • tap是Host上虚拟网卡的前端;
    • qemu是控制平面,vhost是数据平面;
    • virti-net是虚拟网卡的后端;

tap设备本身作为虚拟网卡,同时也是Guest虚拟网卡的后端,

  • 作为Host虚拟网卡的前端 (为自己带盐);
  • 作为virtio-net + (qemu-vhost)的后端 (给别人善后);

2 tun_file

2.1 创建

在我们open /dev/net/tun时,参考代码:

tun_chr_open()
---tfile = (struct tun_file *)sk_alloc(net, AF_UNSPEC, GFP_KERNEL,&tun_proto, 0);...if (ptr_ring_init(&tfile->tx_ring, 0, GFP_KERNEL)) {sk_free(&tfile->sk);return -ENOMEM;}...tfile->socket.file = file;tfile->socket.ops = &tun_socket_ops;sock_init_data(&tfile->socket, &tfile->sk);...file->private_data = tfile;...
---

 我们获得了一个fd,它对应着一个tun_file,这个tun_file中还有一个socket;但是,我们并不能对这个fd直接执行sendmsg/recvmsg,因为它代表的是一个char设备;要想获得tun_file中的socket,需要从内核态调用特殊接口:

get_socket()-> get_tap_socket()-> tun_get_socket()---if (file->f_op != &tun_fops)return ERR_PTR(-EINVAL);tfile = file->private_data;if (!tfile)return ERR_PTR(-EBADFD);return &tfile->socket;---

2.2 功能 

对于tap虚拟网卡来说,每个tun_file就是它的一个通道,或者说队列;

                          

在tun_net_xmit(),可以明显的看到其根据queue_mapping选择tun_file的流程:

tun_net_xmit()
---int txq = skb->queue_mapping;...tfile = rcu_dereference(tun->tfiles[txq]);...if (ptr_ring_produce(&tfile->tx_ring, skb))goto drop;...
---

tun_file在创建之后,第一次通过ioctl TUNSETIFF,会创建一个tap设备;同时,也可以attach到一个已经存在的tap设备中,

TUNSETIFF 1st time,
create a net_device and attach current tun_file on it
------------------------------------------------------------------
tun_set_iff()
---dev = alloc_netdev_mqs(sizeof(struct tun_struct), name,NET_NAME_UNKNOWN, tun_setup, queues,queues);...err = tun_attach(tun, file, false, ifr->ifr_flags & IFF_NAPI,ifr->ifr_flags & IFF_NAPI_FRAGS, false);...err = register_netdevice(tun->dev);...strcpy(ifr->ifr_name, tun->dev->name);...// This name will be copied to userland
---TUNSETIFF 2nd time,
attach another tun_file on this tun net_device
-------------------------------------------------------------------
tun_set_iff()
---dev = __dev_get_by_name(net, ifr->ifr_name);if (dev) {...err = tun_attach(tun, file, ifr->ifr_flags & IFF_NOFILTER,ifr->ifr_flags & IFF_NAPI,ifr->ifr_flags & IFF_NAPI_FRAGS, true);...}
---

tun_file一端对接Host Networking Stack,另一端则通过file或者socket对接着Tap虚拟网卡的后端, 作为skb通道,它主要包含两部分功能,缓存和事件通知;

  • 当skb从Host协议栈发送进Tap设备时,
    tun_net_xmit()
    ---if (ptr_ring_produce(&tfile->tx_ring, skb))goto drop;/* NETIF_F_LLTX requires to do our own update of trans_start */queue = netdev_get_tx_queue(dev, txq);queue->trans_start = jiffies;/* Notify and wake up reader process */if (tfile->flags & TUN_FASYNC)kill_fasync(&tfile->fasync, SIGIO, POLL_IN);tfile->socket.sk->sk_data_ready(tfile->socket.sk);
    ---
    //sock_def_readable() sock_init_data()=====================SYNC==========================
    tun_recvmsg() / tun_chr_read_iter()-> tun_do_read()-> tun_ring_recv()---ptr = ptr_ring_consume(&tfile->tx_ring);if (ptr)goto out;if (noblock) {error = -EAGAIN;goto out;}add_wait_queue(&tfile->socket.wq.wait, &wait);while (1) {set_current_state(TASK_INTERRUPTIBLE);ptr = ptr_ring_consume(&tfile->tx_ring);if (ptr)break;...schedule();}__set_current_state(TASK_RUNNING);remove_wait_queue(&tfile->socket.wq.wait, &wait);---=====================ASYNC==========================
    vhost_net_enable_vq()
    ---sock = vhost_vq_get_backend(vq);if (!sock)return 0;return vhost_poll_start(poll, sock->file);
    ---tun_chr_poll()
    ---sk = tfile->socket.sk;poll_wait(file, sk_sleep(sk), wait);...
    ---vhost_poll_init()
    ---init_waitqueue_func_entry(&poll->wait, vhost_poll_wakeup);
    ---
    sk_sleep()就是sk->sk_wq,在sk_def_readable()会对其执行唤醒操作,进而调用vhost_poll_wakeup(),后者会提交一个vhost work,执行handle_rx操作。

    tun_file中的ptr ring会缓存skb,并通过skb的sk_data_ready()发出通知;等待事件有两种,同步或者异步,参考以上代码片段。

  • 当skb从Tap设备发往Host协议栈时,代码较为简单:

    tun_sendmsg() / tun_chr_write_iter()-> tun_get_user()-> tun_rx_batched()-> netif_receive_skb()

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/204917.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

四、分代垃圾回收机制及垃圾回收算法

学习垃圾回收的意义 Java 与 C等语言最大的技术区别:自动化的垃圾回收机制(GC) 为什么要了解 GC 和内存分配策略 1、面试需要 2、GC 对应用的性能是有影响的; 3、写代码有好处 栈:栈中的生命周期是跟随线程&…

Python 日志(略讲)

日志操作 日志输出: # 输出日志信息 logging.debug("调试级别日志") logging.info("信息级别日志") logging.warning("警告级别日志") logging.error("错误级别日志") logging.critical("严重级别日志")级别设置…

Java程序员,你掌握了多线程吗?(文末送书)

目录 01、多线程对于Java的意义02、为什么Java工程师必须掌握多线程03、Java多线程使用方式04、如何学好Java多线程送书规则 摘要:互联网的每一个角落,无论是大型电商平台的秒杀活动,社交平台的实时消息推送,还是在线视频平台的流…

unity 2d 入门 飞翔小鸟 下坠功能且碰到地面要停止 刚体 胶囊碰撞器 (四)

1、实现对象要受重力 在对应的图层添加刚体 改成持续 2、设置胶囊碰撞器并设置水平方向 3、地面添加盒状碰撞器 运行则能看到小鸟下坠并落到地面上

Windows本地如何添加域名映射?(修改hosts文件)

1. DNS(域名系统) Domain Name System(域名系统):为了加快定位IP地址的速度, 将域名映射进行层层缓存的系统. 目的:互联网通过IP(10.223.146.45)定位浏览器建立连接,但是我们不易区别IP,为了方便用户辨识I…

柏睿网络分析:为什么微模块化机房越来越受欢迎?

与传统机房相比,微模块化机房的建设周期更短,扩展性更强,能耗更低,运维难度也相对较低。因此,微模块化机房是一种高效、灵活、节能的机房解决方案,适用于各种规模的数据中心。 一体化分布式部署&#xff1a…

idea利用SpringMVC框架整合ThymeLeaf

简洁一些:两个重要文件 1.controller指定html文件:我们访问http://localhost:8080/test package com.example.appledemo.controller;import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import o…

甘草书店:#9 2023年11月23日 星期四 「麦田创业历程分享1——联合创始人的魔幻相遇」

既然甘草是一家创业主题的书店咖啡馆,那就从我,从麦田开始分享一下创业历程吧。 需要声明的是,我从不认为我有资格对别人的创业指指点点,每位创业者的性格、背景、基础、诉求各有不同,时代发展也日新月异,…

netty07-粘包半包以及解决方案

粘包指的是发送方在发送数据时,多个数据包被合并成一个大的数据包发送到接收方,接收方在接收时无法准确地区分各个数据包的边界,从而导致数据粘在一起。 半包指的是发送方发送的数据包被拆分成了多个小的数据包,在接收方接收时&a…

Vue的Nuxt项目部署在服务器,pm2动态部署和npm run build静态部署

Nuxt项目的部署有两种方式,一种是静态部署,一种是动态部署 静态部署需要关闭项目的ssr功能,动态部署则不需关闭,所以怎么部署项目就看你用不用ssr功能了 。 1.静态部署 先说静态部署,很简单,只需要在nuxt…

【C语言】程序设计加密解密

🚩write in front🚩 🔎 介绍:"謓泽"正在路上朝着"攻城狮"方向"前进四" 🔎🏅 荣誉:2021|2022年度博客之星物联网与嵌入式开发TOP5|TOP4、2021|2222年获评百大博…

黛姿秘语,匠心之作,严谨工艺铸就完美肌肤

在喧嚣的都市中,我们每个人都渴望找到一款可以信赖长期使用的护肤品,让匹配的肌肤重新焕发光彩,找到更加年轻的自己,但是目前市面上的产品让人眼花缭乱,作为普通的消费者,无法去辨别什么产品好,…

北京市经信局局长姜广智带队调研三六零 强调大模型应与行业结合

12月6日,北京市经济和信息化局局长姜广智、副局长王磊带队走访调研三六零集团,就共促城市级数字安全基础设施项目落地,打造引领行业发展标杆项目,推动大模型落地应用赋能产业、行业发展等话题进行交流。360集团创始人周鸿祎接待来…

(十五)Flask覆写wsgi_app函数实现自定义中间件

中间件 一、剖析: 在前面讲session部分提到过:请求一进来,Flask会自动调用应用程序对象【Flask(__name__)】的__call__方法,这个方法负责处理请求并返回响应(其实如下图:其内部就是wsgi_app方法&#xff…

C++ 指针进阶

目录 一、字符指针 二、指针数组 三、数组指针 数组指针的定义 &数组名 与 数组名 数组指针的使用 四、数组参数 一维数组传参 二维数组传参 五、指针参数 一级指针传参 二级指针传参 六、函数指针 七、函数指针数组 八、指向函数指针数组的指针 九、回调函…

docker基本管理和概念

1、定义:一个开源的应用容器引擎,基于go语言开发,运行在liunx系统中的开源的、轻量级的“虚拟机” docker的容器技术可以在一台主机上轻松的为任何应用创建一个轻量级的、可移植的、自给自足的容器 docker的宿主机是liunx系统,集…

第二十一 网络通信

网络通信 21.1 网络程序设计基础 网络程序设计编写的是与其他计算机进行通信的程序。 21.1.1 局域网与互联网 实现两台计算机的通信,必须用一个网络线路来连接两台计算机 21.1.2 网络协议 1.ip协议 IP是Internet Protocol的简称,是一种网络协议 2…

Vue项目使用Sortable.js实现拖拽功能

想了解更多-可前往 Sortable.js官网 查看组件属性及参数 安装组件&#xff08;我这里使用的是NPM安装&#xff09; npm install sortablejs --save在需要使用拖拽功能的页面中使用&#xff08;完整功能代码&#xff09; <div class"tag_box"><div class&q…

使用VS Code远程开发MENJA小游戏并通过内网穿透分享本地游戏到公网

文章目录 前言1. 编写MENJA小游戏2. 安装cpolar内网穿透3. 配置MENJA小游戏公网访问地址4. 实现公网访问MENJA小游戏5. 固定MENJA小游戏公网地址 推荐一个人工智能学习网站 点击跳转学习 前言 本篇教程&#xff0c;我们将通过VS Code实现远程开发MENJA小游戏&#xff0c;并通…

centos服务器安装docker和Rabbitmq

centos服务器 一 centos安装docker1 安装docker所需要的依赖包2配置yum源3查看仓库中所有的docker版本4安装docker5 设置docker为开机自启6验证docker是否安装成功 二 使用docker安装RabbitMQ拉取RabbitMQ镜像创建并运行容器 一 centos安装docker 1 安装docker所需要的依赖包 …