基于qemu-kvm-0.12.1.2-2.160.el6_1.8.src.rpm

虚拟网卡类型为virtio-net-pci
virtio网卡设备对应的命令行参数为 
-device virtio-net-pci,netdev=hostnet0,id=net0,mac=00:16:36:01:c4:86,bus=pci.0,addr=0x3
1. 在parse命令行的时候,qemu把所有的-device选项parse后保存到qemu_device_opts中
2. 调用module_call_init(MODULE_INIT_DEVICE); 往系统中添加所有支持的设备类型
virtio-net-pci的设备类型信息如下(virtio-pci.c):
static PCIDeviceInfo virtio_info[] = {
{
.qdev.name  = "virtio-net-pci",
.qdev.size  = sizeof(VirtIOPCIProxy),
.init       = virtio_net_init_pci,
.exit       = virtio_net_exit_pci,
.romfile    = "pxe-virtio.bin",
.qdev.props = (Property[]) {
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
DEFINE_NIC_PROPERTIES(VirtIOPCIProxy, nic),
DEFINE_PROP_UINT32("x-txtimer", VirtIOPCIProxy,
net.txtimer, TX_TIMER_INTERVAL),
DEFINE_PROP_INT32("x-txburst", VirtIOPCIProxy,
net.txburst, TX_BURST),
DEFINE_PROP_STRING("tx", VirtIOPCIProxy, net.tx),
DEFINE_PROP_END_OF_LIST(),
},
.qdev.reset = virtio_pci_reset,
}
};
3. 调用qemu_opts_foreach(&qemu_device_opts, device_init_func, NULL, 1) 创建命令行上指定的设备
4. device_init_func调用qdev_device_add(opts)
5. qdev_device_add函数的流程如下:
a) 调用qemu_opt_get(opts, "driver")获取driver选项,这里应该是virtio-net-pci
b) 调用qdev_find_info(NULL, driver)来获取注册的DeviceInfo,这里应该是上面virtio_info里面关于
virtio-net-pci的结构
c) 调用qemu_opt_get(opts, "bus")获取bus路径,以/分隔各组件。这里是pci.0
d) 如果bus路径不为空,则调用qbus_find(path)来获取bus实例(BusState结构)
qbus_find函数的流程如下:
d.1) 先找到路径中的根bus,如果路径以/开头,则根bus为main_system_bus,否则,使用
qbus_find_recursive(main_system_bus, elem, NULL)来查找。这里的elem = "pci.0"
d.2) 如果整个路径已经完成,则返回当前bus
d.2) parse出下一个组件,调用qbus_find_dev查找对应的设备
d.3) parse出下一个组件,调用qbus_find_bus查找属于上层设备的子bus
d.4) 返回步骤2
由于这里的值是pci.0,因此其实只进行了一次qbus_find_recursive调用
e) 如果bus路径为空,则调用qbus_find_recursive(main_system_bus, NULL, info->bus_info)来获取bus
实例。这里的info是driver("virtio-net-pci")所对应的DeviceInfo,即最上面的结构
virtio-pci的初始化步骤是virtio_pci_register_devices -> pci_qdev_register_many -> 
pci_qdev_register,在该函数中,会设置info->bus_info = &pci_bus_info,这样就把PCIDeviceInfo
和pci的BusInfo联系起来了
qbus_find_recursive是一个递归函数,其流程如下:
e.1) 如果当前bus的名称和指定的名称相同(指定名称不为空的情况下),并且当前bus指向的bus info和
指定的bus info相同(指定bus info不为空的情况下),则返回当前bus
e.2) 这里是一个两重循环:
对于当前bus所有附属的设备(bus->children为链表头)
对于当前设备所有的附属bus(dev->child_bus为链表头)
调用qbus_find_recursive函数
f) 调用qdev_create_from_info(bus, info)来创建设备,返回的是DeviceState结构。这里其实返回的是
一个VirtIOPCIProxy实例,因为create的时候是根据qdev.size来分配内存大小的。
g) 如果qemu_opts_id(opts)不为空,则设置qdev->id
h) 调用qemu_opt_foreach(opts, set_property, qdev, 1)来设置设备的各种属性
i) 调用qdev_init来初始化设备。
j) qdev_init会调用dev->info->init函数。这里实际调用的函数是virtio_net_init_pci
在这里也大致描述一下bus pci.0是如何生成的
1. 在main函数里面很前面的地方会调用module_call_init(MODULE_INIT_MACHINE);
2. module_call_init会调用所有已注册QEMUMachine的init函数。该版本的qemu是注册了
pc_machine_rhel610, pc_machine_rhel600, pc_machine_rhel550, pc_machine_rhel544,
pc_machine_rhel540这几个 (pc.c)
3. 这些Machine的init函数(pc_init_rhel600, ...)都会调用到pc_init_pci函数
4. pc_init_pci回调用pc_init1,pc_init1在pci_enabled情况下会调用i440fx_init (piix_pci.c)
5. i440fx_init首先会调用qdev_create(NULL, "i440FX-pcihost")创建一个host device
6. 然后调用pci_bus_new在该设备下面创建一个附属的pci bus。在调用该函数时,传递的name为NULL。
下面再看看这个bus的名称怎么会变成pci.0的
7. pci_bus_new调用pci_bus_new_inplace(bus, parent, name, devfn_min),其中bus指向刚分配的
内存,parent是前面创建的host device,name为NULL,devfn_min为0
8. pci_bus_new_inplace会调用qbus_create_inplace(&bus->qbus, &pci_bus_info, parent, name),
注意这里的第二个参数是&pci_bus_info
9. qbus_create_inplace在开始的地方会为该bus生成一个名称。因为传递进来的name为NULL,并且
parent(那个host device)的id也为NULL,因此分支会跳到下面的代码
len = strlen(info->name) + 16;
buf = qemu_malloc(len);
len = snprintf(buf, len, "%s.%d", info->name,
parent ? parent->num_child_bus : 0);
for (i = 0; i < len; i++)
buf[i] = qemu_tolower(buf[i]);
bus->name = buf;
10. 在该段代码中,info就是之前pci_bus_new_inplace调用时传进来的&pci_bus_info,info->name是
字符串"PCI"。并且,因为这是在host device上创建的第一个bus,因此parent->num_child_bus = 0,
最后经过小写处理之后,该bus的名称就成为了"pci.0"
这一段分析所对应的bus/device layout如下
main-system-bus ---->  i440FX-pcihost ----> pci.0

QEMU虚拟网卡设备的创建流程相关推荐

  1. 网络虚拟化——QEMU虚拟网卡

    写在前面 网络虚拟化曾经只是内核虚拟化功能开发者才会关注的技术.但随着云计算模式和云原生概念的推广,云上业务的部署形态都已转向了虚拟机和容器,而两者都依赖网络虚拟化技术提供高性能网络功能,因此虚拟网络 ...

  2. 隐藏在计算机网卡怎样删除,如何卸载电脑中隐藏的虚拟网卡设备

    虚拟网卡主要是建立远程计算机间的局域网,在此虚拟的局域网上能进行所有物理存在的局域网的操作,可以互相访问,可以联网玩游戏.当需要卸载电脑系统中的虚拟网卡时,在设备管理器中无法查看到虚拟网卡设备,那么怎 ...

  3. 服务器虚拟网卡卸载不掉,怎么彻底卸载虚拟网卡设备。 彻底卸载虚拟网卡设备的方法。...

    今天给大家带来怎么彻底卸载虚拟网卡设备.,彻底卸载虚拟网卡设备的方法.,让您轻松解决问题.网友求助:求助如何卸载虚拟网卡? 具体方法如下:1 使用Win+R调出运行,在其中输入:devmgmt.msc ...

  4. linux虚拟网卡tun,Centos7 创建虚拟网卡(tun/tap)

    创建网卡.创建网桥并建立桥接 [root@kolla ~]# cat create.sh create_br(){ tunctl -t storage -u root brctl addbr virb ...

  5. STM32MP157 | 虚拟网卡设备驱动

    一.网络设备驱动 1. 概念 网络设备是Linux的第三类标准设备,没有对应的设备文件,使用内部设备名访问.网络设备及其驱动属于整个TCP/IP协议层的一部分,实现遵循TCP/IP协议栈的要求. 网络 ...

  6. linux TUN 虚拟网卡设备

    [网络虚拟化技术(二): TUN/TAP MACVLAN MACVTAP] https://blog.kghost.info/2013/03/27/linux-network-tun/ TUN 设备是 ...

  7. linux上使用tun/tap设备模拟一个虚拟网卡,并将该虚拟网卡连接到新创建的网桥上

    目录 linux上使用tun/tap设备模拟一个虚拟网卡,并将该虚拟网卡连接到新创建的网桥上 一.tun/tap设备简介 二.在linux上使用tun/tap设备模拟一个虚拟网卡 三. 创建网桥连接到 ...

  8. 11-S3C2440驱动学习(五)嵌入式linux-网络设备驱动(一)虚拟网卡驱动程序

    本节是网卡驱动的入门基础部分,移植移植DM9000C网卡驱动程序 请看下节:移植DM9000C网卡驱动程序http://blog.csdn.net/fengyuwuzu0519/article/det ...

  9. sstap tun虚拟网卡没有安装_虚拟设备之TUN和TAP

    前言 最近尝试了下 Zerotier,感觉还挺好用的, 比较好奇它的实现原理,查了下,遂有了下文. TAP与TUN是什么 不同于硬件物理网卡,TAP/TUN 是在 Linux 内核 2.4.x 版本之 ...

最新文章

  1. Spring Bean四种注入方式(Springboot环境)
  2. 总结403到504的常用问题
  3. 野火 stm32f429 pcb_PCB板价格是如何核算的
  4. Google员工自述:在哈佛教书和在Google工作的差别
  5. 将数据转化为API,OpenDataSoft获540万美元A轮融资
  6. 最小二乘法C#实现,简单代码
  7. Java技巧: 根据网址查询DNS/IP地址
  8. Python 数据分析三剑客之 NumPy(二):数组索引 / 切片 / 广播 / 拼接 / 分割
  9. 设计模式原则(3)--Dependency Inversion Principle(DIP)--依赖倒转原则
  10. 盖得化工--selenium翻页测试
  11. C中得到4号错误(中断),怎么办
  12. 【LeetCode-SQL】1336. 每次访问的交易次数
  13. 正则化及正则化项的理解
  14. 车规电阻AEC-Q200测试项目及元器件检测设备
  15. Apache Struts2远程代码执行漏洞(S2-019)复现
  16. php禁用session和cookies,session与cookie的区别是什么?如果客户端禁用了cookie功能,将会对session有什么影响?...
  17. QT在界面背景图设置后运行显示黑屏
  18. STM32 PWM的理解
  19. 寻迹小车笔记——红外对管(TCRT5000)原理
  20. VUE“粘性”阅读进度条

热门文章

  1. 手机webapp meta标签 (全屏)
  2. 零积分下载,2014年辛星mysql教程秋季版第一本已经完工,期待您的支持
  3. 三行代码接入,社交软件打字时底下弹出的表情布局,自定义ViewPager+页面点标+各种功能的android小框架。...
  4. 原型继承与属性拷贝的混合应用
  5. 基于nginx的tomcat负载均衡和集群(超简单)
  6. 在vs2005中使用loki的方法
  7. Css的filter常用滤波器属性及语句大全
  8. NHibernate one-to-one
  9. Web 2.0背后的长尾理论
  10. 设计模式实战 - 责任链模式