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.rhkb.cn/news/213448.html

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

相关文章

L1-029:是不是太胖了

题目描述 据说一个人的标准体重应该是其身高(单位:厘米)减去100、再乘以0.9所得到的公斤数。已知市斤的数值是公斤数值的两倍。现给定某人身高,请你计算其标准体重应该是多少?(顺便也悄悄给自己算一下吧………

uni-app实现安卓原生态调用身份证阅读器读卡库读身份证和社保卡、银行卡、IC卡等功能

DONSEE系列多功能读写器Android Uniapp API接口规范V1.0.0 本项目Uniapp调用了身份证读卡器的库文件:DonseeDeviceLib-debug.aar,该库放到nativeplugins\donsee-card\android,然后会自动加载。SDK会自动检查是否拥有USB设备权限,…

python爬取 HTTP_2 网站超时问题的解决方案

问题背景 在进行网络数据爬取时,使用 Python 程序访问支持 HTTP/2 协议的网站时,有时会遇到超时问题。这可能会导致数据获取不完整,影响爬虫程序的正常运行。 问题描述 在实际操作中,当使用 Python 编写的爬虫程序访问支持 HTT…

特殊进程之守护进程

文章目录 1、守护进程的概念2、如何查看守护进程3、编写守护进程的步骤3.1 创建子进程,父进程退出3.2 在子进程中创建新会话3.3 改变当前工作目录3.4 重设文件权限掩码3.5 关闭不需要的文件描述符3.6 某些特殊的守护进程打开/dev/null 4、守护进程代码示例 1、守护进…

一对一聊天程序

package untitled1.src;import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.*; import java.net.*;public class MyServer extends JFrame{private ServerSocket server; // 服务器套接字pri…

22、pytest多个参数化的组合

官方实例 # content of test_multi_parametrie.py import pytestpytest.mark.parametrize("x",[0,1]) pytest.mark.parametrize("y",[2,3]) def test_foo(x,y):print("{}-{}".format(x,y))pass解读与实操 要获得多个参数化参数的所有组合&…

解决使用pnpm安装时Sharp模块报错的方法

在使用pnpm进行项目依赖安装的过程中,有时候会遇到Sharp模块报错的情况。Sharp是一个用于处理图像的Node.js模块,但它的安装可能会因为各种原因而失败,导致项目无法正常启动。本文将介绍这个问题的方法。 问题描述 解决方法 在命令行分别输…

jsp在线辅助教育系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 在线辅助教育系统是一套完善的java web信息管理系统,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发,数据库为Mysql5.0&…

概率密度函数(PDF)正态分布

概率密度函数(PDF)是一个描述连续随机变量取特定值的相对可能性的函数。对于正态分布的情况,其PDF有一个特定的形式,这个形式中包括了一个常数乘以一个指数函数,它假设误差项服从均值为0的正态分布: p ( …

【数据结构】——队列实现二叉树的功能

前言:二叉树的实现方式多种多样,有数组实现满二叉树,有链表实现完全二叉树,今天我们就用队列来实现二叉树。 创建二叉树: typedef int BTDataType; typedef struct BinaryTreeNode {BTDataType data;struct BinaryTre…

java8 常用code

文章目录 前言一、lambda1. 排序1.1 按照对象属性排序:1.2 字符串List排序:1.3 数据库排序jpa 2. 聚合2.1 基本聚合(返回对象list)2.2 多字段组合聚合(直接返回对象list数量) 二、基础语法2.1 List2.1.1 数…

Java对象转Map

在和外部系统对接时&#xff0c;对方系统提供的SDK方法入参全是Map&#xff0c;没办法&#xff0c;只能想办法把对象转成Map。这里&#xff0c;借助了hutool的工具类&#xff0c;可以方便的通过反射获取对象的属性。引入hutool的maven配置&#xff1a; <dependency><g…

Flink 使用场景

Apache Flink 功能强大&#xff0c;支持开发和运行多种不同种类的应用程序。它的主要特性包括&#xff1a;批流一体化、精密的状态管理、事件时间支持以及精确一次的状态一致性保障等。Flink 不仅可以运行在包括 YARN、 Mesos、K8s 在内的多种资源管理框架上&#xff0c;还支持…

智慧社区前景无限,科技引领未来发展

社区是城镇化发展的标志&#xff0c;作为人类现代社会的生活的基本圈子&#xff0c;是人类生活离不开的地方&#xff0c;社区人口密度大、车辆多&#xff0c;管理无序&#xff0c;社区的膨胀式发展多多少少带来一定的管理上的缺失。社区作为智慧城市建设的重要一环&#xff0c;…

时间复杂度为 O(n^2) 的排序算法 | 京东物流技术团队

对于小规模数据&#xff0c;我们可以选用时间复杂度为 O(n2) 的排序算法。因为时间复杂度并不代表实际代码的执行时间&#xff0c;它省去了低阶、系数和常数&#xff0c;仅代表的增长趋势&#xff0c;所以在小规模数据情况下&#xff0c; O(n2) 的排序算法可能会比 O(nlogn) 的…

uniapp实战 —— 竖排多级分类展示

效果预览 完整范例代码 页面 src\pages\category\category.vue <script setup lang"ts"> import { getCategoryTopAPI } from /apis/category import type { CategoryTopItem } from /types/category import { onLoad } from dcloudio/uni-app import { compu…

【链表Linked List】力扣-114 二叉树展开为链表

目录 题目描述 解题过程 官方题解 题目描述 给你二叉树的根结点 root &#xff0c;请你将它展开为一个单链表&#xff1a; 展开后的单链表应该同样使用 TreeNode &#xff0c;其中 right 子指针指向链表中下一个结点&#xff0c;而左子指针始终为 null 。展开后的单链表应…

【Vulnhub 靶场】【Momentum: 2】【简单】【20210628】

1、环境介绍 靶场介绍&#xff1a;https://www.vulnhub.com/entry/momentum-2,702/ 靶场下载&#xff1a;https://download.vulnhub.com/momentum/Momentum2.ova 靶场难度&#xff1a;简单 发布日期&#xff1a;2021年06月28日 文件大小&#xff1a;698 MB 靶场作者&#xff1…

在OpenCV基于深度学习的超分辨率模型实践

1. 引言 OpenCV是一个开源的计算机视觉库&#xff0c;拥有大量优秀的算法。基于最新的合并&#xff0c;OpenCV包含一个易于使用的接口&#xff0c;主要用于实现基于深度学习方法的超分辨率&#xff08;SR&#xff09;。该接口包含预先训练的模型&#xff0c;这些模型可以非常容…

如何为 3D 模型制作纹理的最佳方法

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 您可以通过不同的方式为 3D 模型创建 3D 纹理。下面我们将介绍为 3D …