linux创建虚拟网卡vnet,Qemu之Network Device全虚拟方案二:虚拟网卡的创建
当命令行传入nic相关参数时,Qemu就会解析网络相关的参数后进入虚拟网卡的创建流
程。而在上文中提到对于所有-net类型的设备,都视作一个net client来对待。而在net
client的建立之前,需要先创建Qemu内部的hub和对应的port,来关联每一个net
client,而对于每个创建的-net类型的设备都是可以可以配置其接口的vlan号,从而控制数据包在其中配置的vlan内部进行转发,从而做到多个
虚拟设备之间的switch。
Hub及port的建立
main() file: vl.c, line: 2345 net_init_clients() file: net.c, line: 991 net_init_client() file: net.c, line: 962 net_client_init() file: net.c, line: 701 net_client_init1() file: net.c, line: 628 peer = net_hub_add_port(u.net->has_vlan ? u.net->vlan : 0, NULL);
net_hub_add_port()传入的第一个参数为vlan号,如果没有配置vlan的话则默认为0。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
NetClientState *net_hub_add_port(int hub_id, const char *name)
{
NetHub *hub;
NetHubPort *port;
QLIST_FOREACH(hub, &hubs, next) { id == hub_id) { break;
}
} if (!hub) {
hub = net_hub_new(hub_id);
}
port = net_hub_port_new(hub, name);nc;
}
对于在此过程中创建的各种数据结构关系如下图:
相关的解释:
hubs全局链挂载的NetHub结构对应于指定创建的每一个vlan号;
每个hub下面可以挂载属于同一vlan的多个NetHubPort来描述的port;
每个NetHubPort下归属的NetClientState nc结构表示了具体挂载的net client;
“e1000”,”tap1”都有自己的net client结构,而各自的NetClientInfo都指向了net_hub_port_info;该变量定义了一系列hub操作函数;
最后net_hub_add_port()返回了每个nic对应的NetClientState结构,即图中的peer。
nic设备与hub port的关联
nic设备完成hub及port的创建后,进入nic相关的初始化,即net_init_nic()。
1
2
3
4
5
6
7
8
9
10
11
12
static int net_init_nic(const NetClientOptions *opts, const char *name, NetClientState *peer)
{
NICInfo *nd;
idx = nic_get_free_idx();
nd = &nd_table[idx];
nd->netdev = peer;
nd->name = g_strdup(name);
......
nd->used = 1;
nb_nics++; return idx;
}
解释:
首先从nd_table[]中找到空闲的NICInfo结构,每一个nd_table项代表了一个NIC设备;
填充相关的内容,其中最重要的是net->netdev = peer,此时hub中的NetClient与NICInfo关联,通过NICInfo可找到NetClient;
tap设备与hub port的关联
tap设备完成hub及port的创建后,进入tap相关的初始化,即net_init_tap()。前文中已描述过部分的tap设备相关初始化内容,主要是tap设备的打开和事件监听的设置。而这里主要描述hub port与tap设备的关联。
主要调用流程:
net_init_tap() file: tap.c, line: 589 net_tap_init() file: tap.c, line: 552 tap_open() file: tap-linux.c, line: 38 fd = open(PATH_NET_TUN, O_RDWR) file: tap-linux.c, line: 43 net_tap_fd_init() file: tap.c, line: 325
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static TAPState *net_tap_fd_init(NetClientState *peer, const char *model, const char *name, int fd, int vnet_hdr)
{
NetClientState *nc;
TAPState *s;
nc = qemu_new_net_client(&net_tap_info, peer, model, name);
s = DO_UPCAST(TAPState, nc, nc);
s->fd = fd;
s->host_vnet_hdr_len = vnet_hdr ? sizeof(struct virtio_net_hdr) : 0;
s->using_vnet_hdr = 0;
s->has_ufo = tap_probe_has_ufo(s->fd);
tap_set_offload(&s->nc, 0, 0, 0, 0, 0);
tap_read_poll(s, 1);
s->vhost_net = NULL; return s;
}
该函数最主要的工作就是建立了代表tap设备的TAPState结构与hub port的关联;Tap设备对应的hub
port的NetClientState的peer指向了TAPState的NetClient,而TAPState的NetClient的peer指向
了hub port的NetClientInfo;
tap_read_poll()就是上文分析的设置tap设备读写监听事件。
虚拟网卡的建立
上面图中可以看到TAP设备结构与tap对应的hub
port通过NetClientInfo的peer指针相互进行了关联,而代表e1000的NICInfo中的NetClientInfo与e1000对
应的hub port只有单向的关联,从hub port到NICInfo并没有关联,因此建立两者相互关联需要说到Guest的虚拟网卡的建立。
Guest OS物理内存管理
在说明虚拟网卡的建立前,首先得说一下Guest OS中的物理内存管理。
在虚拟机创建之初,Qemu使用malloc()从其进程地址空间中申请了一块与虚拟机的物理内存大小相等的区域,该块区域就是作为了Guest OS的物理内存来使用。
物理内存通常是不连续的,例如地址0xA0000至0xFFFFF、0xE0000000至0xFFFFFFFF等通常留给BIOS ROM和MMIO,而不是物理内存。
设:
虚拟机包括n块物理内存,分别记做P1, P2, …, Pn;
每块物理内存的起始地址分别记做PB1, PB2, …, PBn;
每块物理内存的大小分别为PS1, PS2, …, PSn。
Qemu根据虚拟机的物理内存布局,将该区域划分成n个子区域,分别记做V1, V2, …, Vn;
第i个子区域与第i块物理内存对应,每个子区域的起始线性地址记做VB1, VB2, …, VBn;
每个子区域的大小等于对应的物理内存块的大小,仍是PS1, PS2, …, PSn。
在Qemu创建虚拟机的时候会向KVM通告Guest OS所使用的物理内存布局,采用KVMSlot的数据结构来表示:
1
2
3
4
5
6
7
8
typedef struct KVMSlot
{
hwaddr start_addr;
ram_addr_t memory_size;
void *ram;
int slot;
int flags;
} KVMSlot;
调用关系:
Qemu:
kvm_set_phys_mem()-> file:kvm-all.c, line:550 kvm_set_user_memory_region()-> file:kvm-all.c, line:191 kvm_vm_ioctl()-> 通过KVM_SET_USER_MEMORY_REGION进入Kernel KVM:
kvm_vm_ioctl_set_memory_region()-> file: kvm_main.c, line:931 __kvm_set_memory_region() file: kvm_main.c, line:734
Guest OS访问任意一块物理地址GPA时,都可以通过KVMSlot记载的关系来得到Qemu的虚拟地址映射即HVA,Qemu中地址空间与VM中地址空间的关系如下图:
虚拟网卡
为什么先要提下Guest OS的物理内存管理呢,因为作为一个硬件设备,OS要控制其必然通过PIO与MMIO来与其交互。而目前的网卡主要涉及到MMIO,而且还是PCI接口,所以必然落入图中的PCI mem。
Qemu根据传入的创建指定NIC类型的参数来进行指定NIC的创建操作,对于e1000虚拟网卡来说,其通过
type_init(e1000_register_types)
注册了MODULE_INIT_QOM类型的设备,而当Qemu创建e1000虚拟设备时,通过内部的PCI
Bus设备抽象层来进行了e1000的初始化,该抽象层这里不做过多的描述。主要关注网卡部分的初始化:
static TypeInfo e1000_info = { file: e1000.c, line: 1289 .name = "e1000",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(E1000State),
.class_init = e1000_class_init,
k->init = pci_e1000_init; exit = pci_e1000_uninit;
k->romfile = "pxe-e1000.rom";
k->vendor_id = PCI_VENDOR_ID_INTEL;
k->device_id = E1000_DEVID;
k->revision = 0x03;
k->class_id = PCI_CLASS_NETWORK_ETHERNET;
dc->desc = "Intel Gigabit Ethernet";
dc->reset = qdev_e1000_reset;
dc->vmsd = &vmstate_e1000;
dc->props = e1000_properties;
} static int pci_e1000_init(PCIDevice *pci_dev)
{
e1000_mmio_setup(d); dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio); dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->io); nic = qemu_new_nic(&net_e1000_info, &d->conf, object_get_typename(OBJECT(d)), d->dev.qdev.id, d);
conf.bootindex, &pci_dev->qdev, "/ethernet-phy@0"); 加入系统启动设备配置中
} static NetClientInfo net_e1000_info = {
.type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState),
.can_receive = e1000_can_receive,
.receive = e1000_receive,
.link_status_changed = e1000_set_link_status,
};
最后PCI设备抽象层将e1000代表的net client与上文描述的e1000所占用的NICinfo所对应hub port的NetClientState *peer进行关联。
至此就完成了虚拟网卡的建立,最终在Qemu的hub中的各Nic的关系如下:
linux创建虚拟网卡vnet,Qemu之Network Device全虚拟方案二:虚拟网卡的创建相关推荐
- Qemu之Network Device全虚拟方案
Qemu之Network Device全虚拟方案一:前端网络流的建立 KVM在I/O虚拟化方面,传统的方式是使用Qemu纯软件的方式来模拟I/O设备,其中包括经常使用的网卡设备.这次我们重点分析Qem ...
- pandas中series一维数组的创建、索引的更改+索引切片和布尔索引+dataframe二维数组的创建、基本属性、索引方法(传统方法和lociloc)、nan操作、排序+案例
目录 一.为什么要学习pandas? 二.pandas的常用数据类型 1.series--一维的且带标签的数组 (1)创建一维数组 (2)通过列表形式创建的series带标签数组可以改变索引,传入索引 ...
- 关于ENSP上路由设备40错误,创建的虚拟网卡为VirtualBox Host-Only Network #2
创建的网卡为VirtualBox Host-Only Network #2 这个问题确实似很头疼的问题,有时候我们使用ensp出现40错误大部分都是因为我们的网卡和配置文件对不上,导致设备起不来. 首 ...
- Linux重启网卡报Job for network.service failed because the control process exited with error code. 错误
重启网卡报Job for network.service failed because the control process exited with error code. 错误 centos7下重 ...
- linux单 网卡添加多个网段的ip,[转载]linux 单网卡来绑定多IP实现多网段访问以及多网卡绑定单IP实现附载均...
今天有遇到实现linux下访问多网段问题,以前只是有注意资料修改linux路由的的方法,在使用2003系统时倒是有经常单网卡访问多网段.前提是先绑定每个网段的一个IP 那同理如果我们需要实现linux ...
- [转]VMware虚拟机上网络连接(network type)的三种模式--bridged、host-only、NAT
转自:http://www.cnblogs.com/xiaochaohuashengmi/archive/2011/03/15/1985084.html VMWare提供了三种工作模式,它们是brid ...
- VMware虚拟机上网络连接(network type)的三种模式--bridged、host-only、NAT
VMWare提供了三种工作模式,它们是bridged(桥接模式).NAT(网络地址转换模式)和host-only(主机模式).要想在网络管理和维护中合理应用它们,你就应该先了解一下这三种工作模式. 1 ...
- Linux文件系统概述:硬盘驱动>通用块设备层>文件系统>虚拟文件系统(VFS)
目录 一.概述 1. 硬盘驱动 2. 通用块设备层 General Block Device Layer 3. 文件系统 4. 虚拟文件系统(VFS) 二.存储介质 闪存(Flash Memory) ...
- 使用libvirt和qemu将pci pass through设备添加到虚拟机上
透传的优势 guest使用透传设备可以获得设备近乎原生的性能, PCI pass-throught设备给动态迁移带来的问题, dest host可能没有同样的硬件. 就算可以模拟一个设备,但是原始设备 ...
最新文章
- Keras中神经网络可视化模块keras.utils.vis_util 的安装
- vim常用命令总结 (转)
- 72 页 PPT,带你梳理神经网络完整架构(含 PyTorch 代码)
- A股开盘:深证区块链50指数跌0.94%,美邦服饰涨停
- 《Head first HTML与CSS 第二版》读书笔记 第一章 了解HTML
- vb 计算机cot,VB编程中运算sin、cos、tan、cot的程序怎么写?
- 黑马学习之全平台听歌神器
- c语言函数字符传送,C语言中send()函数和sendto()函数的使用方法
- PHP编写Android初步
- C语言中关于中文字符的存储及相关探索
- Win10 LTSC 2019进入桌面时假死的拆中处理方法
- Django的BUG:ImportError: cannot import name 'patterns'
- tf.train.Saver()
- Ubuntu常用软件下载以及视频流裁剪转码获取教程(可直接下载油管、B站、优酷等视频资源!)
- 华为rh2288v2服务器系统,灵动高效!华为RH2288 V2服务器评测
- 人工智能数学基础--概率与统计7:学习中一些术语的称呼或表示变化说明以及独立事件的一些补充推论
- 百度百科首页登录入口在哪,个人如何创建百度百科
- Python学习:代码过长的换行方式
- 李彦宏说百度吹的牛都实现了,还扔出来一个ACE计划
- 一道题Wrong Answer之后该何去何从?
热门文章
- 硬盘双击打不开,u盘双击打不开解决办法
- php提取网页mp3,怎么提取网页中的音乐|下载网页中的音乐 网页音乐提取工具及使用教程分享...
- TF卡怎样恢复已删除的数据?修复实用教学
- 安装VMware时警告此产品安装程序不支持降级
- 数学物理方程的Matlab实现
- Termux个人云盘搭建——kodbox
- python图像锐化滤波_OpenCV-Python学习(九):图像滤波
- winpe 2.0与windows AIK的纠葛
- Matlab程序代码,智能微电网PSO优化算法,多目标调度,粒子群算法,综合能源系统优化,机组最优组合,光伏出力预测
- Web实现:装饰边框添加阴影