趣谈 Linux 操作系统
刘超
前网易杭州研究院云计算技术部首席架构师
85459 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 72 讲
趣谈 Linux 操作系统
15
15
1.0x
00:00/00:00
登录|注册

55 | 网络虚拟化:如何成立独立的合作部?

解析接收过程
宿主机内核协议栈处理完毕之后,会发送给tap虚拟网卡,完成从虚拟机里面到宿主机的整个发送过程
tun_chr_write_iter函数中,tun_get_user将要发送的网络包从qemu拷贝到宿主机内核里面来,然后调用netif_rx_ni开始调用宿主机内核协议栈进行处理
在宿主机内核中字符设备文件的file_operations里面的write_iter会被调用,也即会调用tun_chr_write_iter
QEMU调用writev向字符设备文件写入,进入宿主机的内核
调用virtio_net_handle_tx_bh函数,从传输队列中获取要发送的数据,然后调用qemu_sendv_packet_async进行发送
QEMU收到通知后,通过VM exit指令退出客户机模式,进入宿主机模式
调用virtqueue_add将网络包放入发送队列,然后调用virtqueue_notify通知qemu
在前端驱动和qemu后端驱动之间有两个队列virtqueue,一个用于发送,一个用于接收
virtio_net的net_device_ops定义了发送网络包调用的函数为start_xmit
数据经过VFS层和内核协议栈到达虚拟机内核的网络设备驱动(virtio_net)
用户态应用程序通过write系统调用写入socket
课堂练习
宿主机内核处理接收网络包
QEMU处理发送网络包
virtio_net驱动发送网络包
虚拟机内部发送网络包
网络虚拟化场景下网络包的发送过程

该思维导图由 AI 生成,仅供参考

上一节,我们讲了存储虚拟化,这一节我们来讲网络虚拟化。
网络虚拟化有和存储虚拟化类似的地方,例如,它们都是基于 virtio 的,因而我们在看网络虚拟化的过程中,会看到和存储虚拟化很像的数据结构和原理。但是,网络虚拟化也有自己的特殊性。例如,存储虚拟化是将宿主机上的文件作为客户机上的硬盘,而网络虚拟化需要依赖于内核协议栈进行网络包的封装与解封装。那怎么实现客户机和宿主机之间的互通呢?我们就一起来看一看。

解析初始化过程

我们还是从 Virtio Network Device 这个设备的初始化讲起。
static const TypeInfo device_type_info = {
.name = TYPE_DEVICE,
.parent = TYPE_OBJECT,
.instance_size = sizeof(DeviceState),
.instance_init = device_initfn,
.instance_post_init = device_post_init,
.instance_finalize = device_finalize,
.class_base_init = device_class_base_init,
.class_init = device_class_init,
.abstract = true,
.class_size = sizeof(DeviceClass),
};
static const TypeInfo virtio_device_info = {
.name = TYPE_VIRTIO_DEVICE,
.parent = TYPE_DEVICE,
.instance_size = sizeof(VirtIODevice),
.class_init = virtio_device_class_init,
.instance_finalize = virtio_device_instance_finalize,
.abstract = true,
.class_size = sizeof(VirtioDeviceClass),
};
static const TypeInfo virtio_net_info = {
.name = TYPE_VIRTIO_NET,
.parent = TYPE_VIRTIO_DEVICE,
.instance_size = sizeof(VirtIONet),
.instance_init = virtio_net_instance_init,
.class_init = virtio_net_class_init,
};
static void virtio_register_types(void)
{
type_register_static(&virtio_net_info);
}
type_init(virtio_register_types)
Virtio Network Device 这种类的定义是有多层继承关系的,TYPE_VIRTIO_NET 的父类是 TYPE_VIRTIO_DEVICE,TYPE_VIRTIO_DEVICE 的父类是 TYPE_DEVICE,TYPE_DEVICE 的父类是 TYPE_OBJECT,继承关系到头了。
type_init 用于注册这种类。这里面每一层都有 class_init,用于从 TypeImpl 生成 xxxClass,也有 instance_init,会将 xxxClass 初始化为实例。
TYPE_VIRTIO_NET 层的 class_init 函数 virtio_net_class_init,定义了 DeviceClass 的 realize 函数为 virtio_net_device_realize,这一点和存储块设备是一样的。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了网络虚拟化的初始化过程和网络包的发送过程,突出了其特殊性和技术细节。首先介绍了Virtio Network Device的初始化,通过多层继承关系和class_init实现设备的初始化。接着详细介绍了VirtIODevice结构和VirtQueue数组,用于前端和后端互相传输数据的队列。特别强调了网络设备需要分发送队列和接收队列两个方向,因此在初始化队列时需要考虑这一点。文章还介绍了处理网络包接收和发送的相关函数,以及创建虚拟机内网卡的过程。通过代码和注释的解析,读者可以快速了解网络虚拟化的工作原理和关键步骤。此外,文章还详细解释了tap_open函数打开字符设备文件"/dev/net/tun",并通过ioctl操作这个文件与内核进行交互的过程。整体而言,本文对网络虚拟化的技术细节进行了深入剖析,适合对网络虚拟化感兴趣的读者阅读。 文章还总结了网络包的发送过程,从虚拟机内部到宿主机的网络传输过程,详细解释了各个环节的调用链和关键函数。在虚拟机内部的用户态应用程序写入socket后,经过内核协议栈到达虚拟机内核的网络设备驱动virtio_net,再通过队列和通知机制传输至宿主机的后端驱动qemu,最终经过字符设备文件写入宿主机内核,完成整个发送过程。同时,文章提出了课堂练习,鼓励读者根据类似思路解析接收过程,促进读者的深入学习和思考。整体而言,本文内容丰富,逻辑清晰,是一篇值得深入研读的技术文章。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《趣谈 Linux 操作系统》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(14)

  • 最新
  • 精选
  • zhj
    不仅是走了两次协议栈,关键是客户机内核栈封包-->宿主机内核栈解包,然后又利用宿主机协议栈封包发出去,这个流程感觉好怪异,两次走协议栈,三次动包,这个不能优化吗

    作者回复: 当然能优化呀,所以才有DPDK,virio vhost,SR-IOV等,所以这里分析的是传统的模式

    2019-08-20
    15
  • 饭粒
    写的真好,尤其总结精华。一篇内容要断断续续看好久。。

    作者回复: 加油

    2019-08-15
    5
  • kkxue
    学了这么多年的虚拟网络,不及老师一节课的深度啊

    作者回复: 别这样说,诚惶诚恐

    2019-08-04
    1
  • leslie
    学习了:跟完刘老师的趣谈网络协议再跟着linux系统,发现收获又不一样;同时在跟老师的网络协议的过程中,还被迫去跟着学习刘文浩老师的计算机组成原理-否则没法理解老师的一些概念。 这大概就是老师之前说的学习方法吧:书阅读越厚、读书的过程中不断去相应的扩展、学习、提升理解,然后整理出自己的东西-书就薄了;虽然书薄了,可是笔记和自己的学习笔录却反而越来越厚了;感谢老师简单形象的教诲。

    作者回复: 谢谢夸奖

    2019-08-03
    1
  • 安排
    网络包是什么样的?经过协议栈处理之前的还是之后的?这样看来虚拟机里面发送网络数据要走两次协议栈吗?因为虚拟机本身也有自己的协议栈,经过虚拟机协议栈处理的数据qemu会进行拆包重新还原出原始的数据吗?

    作者回复: 是的,两次协议栈

    2019-08-02
    2
    1
  • 💢 星星💢
    我感觉每次看看总结就差不多了。。一看到文中的代码,头很疼,本人c语言基础一般,调用来调用去。头很晕。每次看老师的文章。我先是大致看一下文章的大概意思,最后认真看一下总结。但是第二天好像又忘得七七八八了。自己基础还是太差了。刘老师的功底,太过于深厚。佩服。
    2019-11-07
    2
    13
  • williamcai
    能大概理解虚拟化原来是这么回事,用软件来模拟设备,最后还是要真正的设备来处理
    2019-12-24
    3
  • 青年祭司
    老师,如果是一个宿主机上的两个虚拟机之间互相发送数据,会有优化吗
    2020-07-24
    1
  • Felix
    打个卡,证明我坚持到这里,并不说明我看懂了😂
    2024-03-13归属地:广东
  • 呆萌白的大白。
    有几个问题还是想请教一下作者: 一:课程中讲的virtio-net后端是vhost-net吗? 二:vhost-net模式下,guestos中的网络IO一定会引起vmexit吗? 三:vmexit之后,KVM是怎么通知给vhost-net内核线程的,KVM直接调用vhost-net模块吗? 四:前端肯定都是virtio-net了,vhost-net后端跟virtio-net后端,vmexit之后都是KVM模块直接调用后端的驱动代码吗,那这段时间guestos始终出去vmexit状态,不做任何操作吗? 五:vhost-net怎么把包传递给guestos啊,也是KVM直接调用代码吗?那是guestos发包,vmexit然后一直等着,对端回包之后KVM再vmentry吗?因为IO中断就一直阻塞是不是效率太差了,而且非常用可能外部访问虚拟机提供的服务啊,这时候虚拟机本身就是在vmentry已进入的状态啊,这就矛盾了啊.
    2022-04-25
收起评论
显示
设置
留言
14
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部