virtio-net

软件环境:qemu,linux kernel
硬件环境:x86 PC
目标:在host ubuntu20.04上通过qemu运行linux虚拟机

创建网络方式

参考:https://huaweicloud.csdn.net/63566a32d3efff3090b5e8ac.html?spm=1001.2101.3001.6650.6&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Eactivity-6-124536607-blog-106767540.235%5Ev43%5Epc_blog_bottom_relevance_base7&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Eactivity-6-124536607-blog-106767540.235%5Ev43%5Epc_blog_bottom_relevance_base7&utm_relevant_index=13

Tap

user

编译qemu

#编译在x86运行的qemu for arm64版本
./configure --enable-kvm --enable-debug --enable-gtk --target-list=aarch64-softmmu
make -j4 
#拷贝生成物
cp ./aarch64-softmmu/qemu-system-aarch64 your-dir
cp pc-bios/efi-virtio.rom your-dir

调试Virtio-net

#1. debug virtio-net
gdb ./qemu-system-aarch64-4.2.1
set args -m 4096 -cpu cortex-a57 -smp 1 -M virt -bios QEMU_EFI.fd -nographic -drive if=none,file=ubuntu20.04-arm64.img,id=hd0 -device virtio-blk-device,drive=hd0
b virtio_net_handle_ctrl
r 

Virtio-net驱动

   1af4:1000 network device (legacy),1af4代表vendor ID:RedHat;1000代表Device ID:net Device

在这里插入图片描述

初始化

  • Virtio Device初始化。Qemu/hw/net/virtio-net.c
  1. virtio_net_class_init
#0 virtio_net_class_init (klass=0x555556a547e0, data=0x0) at /home/bstcd/data/sp/x86-server/qemu/qemu-4.2.1/hw/net/virtio-net.c:3234
#1 0x0000555555eddb91 in type_initialize (ti=0x555556991950) at qom/object.c:349
#2 0x0000555555edf1f3 in object_class_foreach_tramp (key=0x555556991ad0, value=0x555556991950, opaque=0x7fffffffde60) at qom/object.c:963
#3 0x00007ffff715e1b8 in g_hash_table_foreach () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#4 0x0000555555edf2d6 in object_class_foreach (fn=
0x555555edf433 <object_class_get_list_tramp>, implements_type=0x5555561a923d "machine", include_abstract=false, opaque=0x7fffffffdeb0) at qom/object.c:985
#5 0x0000555555edf4b6 in object_class_get_list (implements_type=0x5555561a923d "machine", include_abstract=false) at qom/object.c:1039
#6 0x0000555555b853e3 in select_machine () at vl.c:2593
#7 0x0000555555b88287 in main (argc=16, argv=0x7fffffffe238, envp=0x7fffffffe2c0) at vl.c:3852 
向DeviceClass和VirtioDeviceClass注册各种回调函数:
dc->props = virtio_net_properties;
dc->vmsd = &vmstate_virtio_net;
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
vdc->realize = virtio_net_device_realize;
vdc->unrealize = virtio_net_device_unrealize;
vdc->get_config = virtio_net_get_config;
vdc->set_config = virtio_net_set_config;
vdc->get_features = virtio_net_get_features;
vdc->set_features = virtio_net_set_features;
vdc->bad_features = virtio_net_bad_features;
vdc->reset = virtio_net_reset;
vdc->set_status = virtio_net_set_status;
vdc->guest_notifier_mask = virtio_net_guest_notifier_mask;
vdc->guest_notifier_pending = virtio_net_guest_notifier_pending;
vdc->legacy_features |= (0x1 << VIRTIO_NET_F_GSO);
vdc->post_load = virtio_net_post_load_virtio;
vdc->vmsd = &vmstate_virtio_net_device;
vdc->primary_unplug_pending = primary_unplug_pending;
Properties:定义VirtIONet设备上host_features各种寄存器属性
  1. virtio_net_device_realize //设备初始化
#0 virtio_net_device_realize (dev=0x55555616ba70 <__func__.32466>, errp=0x555556cb3480) at /home/bstcd/data/sp/x86-server/qemu/qemu-4.2.1/hw/net/virtio-net.c:2932
#1 0x000055555598bc6e in virtio_device_realize (dev=0x555556cb3480, errp=0x7fffffffcf20) at /home/bstcd/data/sp/x86-server/qemu/qemu-4.2.1/hw/virtio/virtio.c:3594
#2 0x0000555555c16ef0 in device_set_realized (obj=0x555556cb3480, value=true, errp=0x7fffffffd168) at hw/core/qdev.c:876
#3 0x0000555555ee1bf1 in property_set_bool (obj=0x555556cb3480, v=0x555556cc1dd0, name=0x555556170931 "realized", opaque=0x555556cb6d30, errp=0x7fffffffd168)
at qom/object.c:2078
#4 0x0000555555edfda8 in object_property_set (obj=0x555556cb3480, v=0x555556cc1dd0, name=0x555556170931 "realized", errp=0x7fffffffd168) at qom/object.c:1270
#5 0x0000555555ee2fdc in object_property_set_qobject (obj=0x555556cb3480, value=0x555556cc1d20, name=0x555556170931 "realized", errp=0x7fffffffd168) at qom/qom-qobject.c:26
#6 0x0000555555ee00a1 in object_property_set_bool (obj=0x555556cb3480, value=true, name=0x555556170931 "realized", errp=0x7fffffffd168) at qom/object.c:1336
#7 0x00005555559a15b4 in virtio_net_pci_realize (vpci_dev=0x555556cab310, errp=0x7fffffffd168)
at /home/bstcd/data/sp/x86-server/qemu/qemu-4.2.1/hw/virtio/virtio-net-pci.c:56
#8 0x0000555555e32e45 in virtio_pci_realize (pci_dev=0x555556cab310, errp=0x7fffffffd168) at hw/virtio/virtio-pci.c:1803
#9 0x0000555555d68eef in pci_qdev_realize (qdev=0x555556cab310, errp=0x7fffffffd220) at hw/pci/pci.c:2099
#10 0x0000555555e331f4 in virtio_pci_dc_realize (qdev=0x555556cab310, errp=0x7fffffffd220) at hw/virtio/virtio-pci.c:1876
#11 0x0000555555c16ef0 in device_set_realized (obj=0x555556cab310, value=true, errp=0x7fffffffd3e0) at hw/core/qdev.c:876
#12 0x0000555555ee1bf1 in property_set_bool (obj=0x555556cab310, v=0x555556cbc0d0, name=0x5555561d6bf1 "realized", opaque=0x555556caabb0, errp=0x7fffffffd3e0)
at qom/object.c:2078
#13 0x0000555555edfda8 in object_property_set (obj=0x555556cab310, v=0x555556cbc0d0, name=0x5555561d6bf1 "realized", errp=0x7fffffffd3e0) at qom/object.c:1270
#14 0x0000555555ee2fdc in object_property_set_qobject (obj=0x555556cab310, value=0x555556cbbff0, name=0x5555561d6bf1 "realized", errp=0x7fffffffd3e0) at qom/qom-qobject.c:26
#15 0x0000555555ee00a1 in object_property_set_bool (obj=0x555556cab310, value=true, name=0x5555561d6bf1 "realized", errp=0x7fffffffd3e0) at qom/object.c:1336
#16 0x0000555555c15b4b in qdev_init_nofail (dev=0x555556cab310) at hw/core/qdev.c:363
#17 0x0000555555d6899f in pci_nic_init_nofail (nd=0x555556945cc0 <nd_table>, rootbus=0x555556c40790, default_model=0x555556c76af0 "virtio-net-pci", default_devaddr=0x0)
at hw/pci/pci.c:1944
#18 0x00005555559aa907 in create_pcie (vms=0x555556a97170, pic=0x7fffffffd6e0) at /home/bstcd/data/sp/x86-server/qemu/qemu-4.2.1/hw/arm/virt.c:1257
#19 0x00005555559ac411 in machvirt_init (machine=0x555556a97170) at /home/bstcd/data/sp/x86-server/qemu/qemu-4.2.1/hw/arm/virt.c:1730
#20 0x0000555555c22276 in machine_run_board_init (machine=0x555556a97170) at hw/core/machine.c:1143
#21 0x0000555555b89406 in main (argc=14, argv=0x7fffffffe268, envp=0x7fffffffe2e0) at vl.c:4348 
#判断是否支持mtu
#判断支持DUPLEX是half还是full
#判断speed值是否合法
#host_feature设置STANDBY
virtio_init //初始化virtio-net设备
#检查tx_queue_size/rx_queue_size合法性

#根据max_queues为1创建vqs个数为1
(gdb) p n->net_conf
$5 = {txtimer = 150000, txburst = 256, tx = 0x0, rx_queue_size = 256, tx_queue_size = 256, mtu = 0, speed = -1, duplex_str = 0x0, duplex = 255 '\377', primary_id_str = 0x0} 
#设置tx_timeout为n->net_conf.txtimer (150000)
#检查n->net_conf.tx
#设置n->net_conf.tx_queue_size为256
virtio_net_add_queue //创建rx_vq和tx_vq和设置回调
  virtio_add_queue //为rx_vq创建回调virtio_net_handle_rx
  virtio_add_queue //为tx_vq创建回调virtio_net_handle_tx_bh
  n->vqs[index].tx_bh = qemu_bh_new(virtio_net_tx_bh, &n->vqs[index]); 
  #设置vqs的tx_waiting为0

n->ctrl_vq = virtio_add_queue(vdev, 64, virtio_net_handle_ctrl); //创建ctrl_vq,长度64,回调virtio_net_handle_ctrl
qemu_macaddr_default_if_unset //设置默认mac "52:54:00:12:34:56"
#设置states为VIRTIO_NET_S_LINK_UP
#重置virtio_net_announce_timer

n->nic = qemu_new_nic //n->netclient_type为virtio-net-pci,创建网卡
  qemu_net_client_setup //根据配置创建网卡
qemu_format_nic_info_str //将model和macaddr格式化到info_str,model=virtio-net-pci,macaddr=52:54:00:12:34:56
#设置n->tx_burst为256
virtio_net_set_mrg_rx_bufs //n->mergeable_rx_bufs为0,设置guest/host_hdr_len为10 
#rxfilter_notify_enabled设置为1
  1. #初始化后VirtIONet结构为
(gdb) p n
$22 = (VirtIONet *) 0x555556cb3480
(gdb) p *n
$23 = {parent_obj = {parent_obj = {parent_obj = {class = 0x555556a54340, free = 0x0, Python Exception <class 'gdb.error'> There is no member named keys.:
properties = 0x555556c3eaa0, ref = 2, parent = 0x555556cab310}, id = 0x0,
canonical_path = 0x0, realized = false, pending_deleted_event = false, opts = 0x0, hotplugged = 0, allow_unplug_during_migration = false, parent_bus = 0x555556cb3408,
gpios = {lh_first = 0x0}, child_bus = {lh_first = 0x0}, num_child_bus = 0, instance_id_alias = -1, alias_required_for_version = 0}, name = 0x555556160a1e "virtio-net",
status = 0 '\000', isr = 0 '\000', queue_sel = 0, guest_features = 0, host_features = 956301312, backend_features = 0, config_len = 8, config = 0x555556cc1ea0,
config_vector = 65535, generation = 0, nvectors = 0, vq = 0x7ffff4055010, listener = {begin = 0x0, commit = 0x0, region_add = 0x0, region_del = 0x0, region_nop = 0x0,
log_start = 0x0, log_stop = 0x0, log_sync = 0x0, log_clear = 0x0, log_global_start = 0x0, log_global_stop = 0x0, log_global_after_sync = 0x0, eventfd_add = 0x0,
eventfd_del = 0x0, coalesced_io_add = 0x0, coalesced_io_del = 0x0, priority = 0, address_space = 0x0, link = {tqe_next = 0x0, tqe_circ = {tql_next = 0x0,
tql_prev = 0x0}}, link_as = {tqe_next = 0x0, tqe_circ = {tql_next = 0x0, tql_prev = 0x0}}}, device_id = 1, vm_running = false, broken = false, use_started = true,
started = false, start_on_kick = false, vmstate = 0x555556cc1ec0, bus_name = 0x0, device_endian = 1 '\001', use_guest_notifier_mask = true, dma_as = 0x0,
vector_queues = 0x555556adf8d0}, mac = "RT\000\022\064V", status = 1, vqs = 0x555556cc1ef0, ctrl_vq = 0x7ffff4055140, nic = 0x555556cc9e60, rsc_chains = {
tqh_first = 0x0, tqh_circ = {tql_next = 0x0, tql_prev = 0x0}}, tx_timeout = 150000, tx_burst = 256, has_vnet_hdr = 0, host_hdr_len = 0, guest_hdr_len = 10,
host_features = 12582855, rsc_timeout = 300000, rsc4_enabled = 0 '\000', rsc6_enabled = 0 '\000', has_ufo = 0 '\000', mergeable_rx_bufs = 0, promisc = 1 '\001',
allmulti = 0 '\000', alluni = 0 '\000', nomulti = 0 '\000', nouni = 0 '\000', nobcast = 0 '\000', vhost_started = 0 '\000', mac_table = {in_use = 0, first_multi = 0,
multi_overflow = 0 '\000', uni_overflow = 0 '\000', macs = 0x555556cca060 ""}, vlans = 0x555556cca1f0, net_conf = {txtimer = 150000, txburst = 256, tx = 0x0,
rx_queue_size = 256, tx_queue_size = 256, mtu = 0, speed = -1, duplex_str = 0x0, duplex = 255 '\377', primary_id_str = 0x0}, nic_conf = {macaddr = {
a = "RT\000\022\064V"}, peers = {ncs = {0x555556ae5fb0, 0x0 <repeats 1023 times>}, queues = 1}, bootindex = -1}, qdev = 0x0, multiqueue = 0, max_queues = 1,
curr_queues = 1, config_size = 8, netclient_name = 0x0, netclient_type = 0x555556cc1c20 "virtio-net-pci", curr_guest_offloads = 0, saved_guest_offloads = 0,
announce_timer = {tm = 0x555556cc9e20, params = {initial = 50, max = 550, rounds = 5, step = 100, has_interfaces = false, interfaces = 0x0, has_id = false, id = 0x0},
type = QEMU_CLOCK_VIRTUAL, round = 0}, needs_vnet_hdr_swap = false, mtu_bypass_backend = true, primary_device_opts = 0x0, primary_device_dict = 0x0, primary_dev = 0x0,
primary_bus = 0x0, primary_device_id = 0x0, standby_id = 0x0, primary_should_be_hidden = false, failover = false, primary_listener = {realize = 0x0, unrealize = 0x0,
should_be_hidden = 0x0, link = {tqe_next = 0x0, tqe_circ = {tql_next = 0x0, tql_prev = 0x0}}}, migration_state = {notify = 0x0, node = {le_next = 0x0, l 

Virtio Driver初始化

virtio-net协议

virtio_net_handle_rx

  • Rx_vq回调virtio_net_handle_rx
#0 virtio_net_handle_rx (vdev=0x7ffff4055010, vq=0x555556cb3480) at /home/bstcd/data/sp/x86-server/qemu/qemu-4.2.1/hw/net/virtio-net.c:1230
#1 0x000055555598857a in virtio_queue_notify_vq (vq=0x7ffff4055010) at /home/bstcd/data/sp/x86-server/qemu/qemu-4.2.1/hw/virtio/virtio.c:2337
#2 0x000055555598b89c in virtio_queue_host_notifier_read (n=0x7ffff4055088) at /home/bstcd/data/sp/x86-server/qemu/qemu-4.2.1/hw/virtio/virtio.c:3522
#3 0x000055555602a69f in aio_dispatch_handlers (ctx=0x5555569f8790) at util/aio-posix.c:429
#4 0x000055555602a836 in aio_dispatch (ctx=0x5555569f8790) at util/aio-posix.c:460
#5 0x0000555556025d1e in aio_ctx_dispatch (source=0x5555569f8790, callback=0x0, user_data=0x0) at util/async.c:260
#6 0x00007ffff717017d in g_main_context_dispatch () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#7 0x00005555560290e1 in glib_pollfds_poll () at util/main-loop.c:219
#8 0x000055555602915f in os_host_main_loop_wait (timeout=0) at util/main-loop.c:242
#9 0x0000555556029270 in main_loop_wait (nonblocking=0) at util/main-loop.c:518
#10 0x0000555555b821af in main_loop () at vl.c:1812
#11 0x0000555555b89704 in main (argc=14, argv=0x7fffffffe268, envp=0x7fffffffe2e0) at vl.c:4473 
qemu_flush_queued_packets
  qemu_flush_or_purge_queued_packets

virtio_net_handle_tx_bh

  • Tx_vq回调virtio_net_handle_tx_bh
  • 调用栈
(gdb) bt
#0 virtio_net_handle_tx_bh (vdev=0x5555559820f3 <trace_virtio_queue_notify+40>, vq=0x7fffffffdd00) at /home/bstcd/data/sp/x86-server/qemu/qemu-4.2.1/hw/net/virtio-net.c:2254
#1 0x000055555598857a in virtio_queue_notify_vq (vq=0x7ffff40550a8) at /home/bstcd/data/sp/x86-server/qemu/qemu-4.2.1/hw/virtio/virtio.c:2337
#2 0x000055555598b89c in virtio_queue_host_notifier_read (n=0x7ffff4055120) at /home/bstcd/data/sp/x86-server/qemu/qemu-4.2.1/hw/virtio/virtio.c:3522
#3 0x000055555602a69f in aio_dispatch_handlers (ctx=0x5555569f8790) at util/aio-posix.c:429
#4 0x000055555602a836 in aio_dispatch (ctx=0x5555569f8790) at util/aio-posix.c:460
#5 0x0000555556025d1e in aio_ctx_dispatch (source=0x5555569f8790, callback=0x0, user_data=0x0) at util/async.c:260
#6 0x00007ffff717017d in g_main_context_dispatch () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#7 0x00005555560290e1 in glib_pollfds_poll () at util/main-loop.c:219
#8 0x000055555602915f in os_host_main_loop_wait (timeout=0) at util/main-loop.c:242
#9 0x0000555556029270 in main_loop_wait (nonblocking=0) at util/main-loop.c:518
#10 0x0000555555b821af in main_loop () at vl.c:1812
#11 0x0000555555b89704 in main (argc=14, argv=0x7fffffffe268, envp=0x7fffffffe2e0) at vl.c:4473 
#如果不是VIRTIO_NET_S_LINK_UP丢弃
virtio_net_drop_tx_queue_data
#q->tx_waiting设置为1
virtio_queue_set_notification(vq, 0) 
  vq->notification设置为enable
  virtio_queue_split_set_notification
    vring_used_flags_unset_bit(vq, VRING_USED_F_NO_NOTIFY);
qemu_bh_schedule(q->tx_bh)

virtio_net_handle_ctrl

  • Ctrl_vq回调virtio_net_handle_ctrl
VIRTIO_NET_CTRL_RX
      virtio_net_handle_rx_mode(n, ctrl.cmd, iov, iov_cnt);
            VIRTIO_NET_CTRL_RX_PROMISC
              n->promisc = on;
            VIRTIO_NET_CTRL_RX_ALLMULTI
              n->allmulti = on;
            VIRTIO_NET_CTRL_RX_ALLUNI
              n->alluni = on;
            VIRTIO_NET_CTRL_RX_NOMULTI
              n->nomulti = on;
            VIRTIO_NET_CTRL_RX_NOUNI
              n->nouni = on;
            VIRTIO_NET_CTRL_RX_NOBCAST
              n->nobcast = on;
            else 
              return VIRTIO_NET_ERR;
 

VIRTIO_NET_CTRL_MAC
      virtio_net_handle_mac(n, ctrl.cmd, iov, iov_cnt);
            VIRTIO_NET_CTRL_MAC_ADDR_SET
              qemu_format_nic_info_str
            !=VIRTIO_NET_CTRL_MAC_TABLE_SET
              return VIRTIO_NET_ERR;
 memcpy

VIRTIO_NET_CTRL_VLAN
      virtio_net_handle_vlan_table(n, ctrl.cmd, iov, iov_cnt);
            VIRTIO_NET_CTRL_VLAN_ADD
              n->vlans[vid >> 5] |= (1U << (vid & 0x1f));
            VIRTIO_NET_CTRL_VLAN_DEL
              n->vlans[vid >> 5] &= ~(1U << (vid & 0x1f));

VIRTIO_NET_CTRL_ANNOUNCE
      virtio_net_handle_announce(n, ctrl.cmd, iov, iov_cnt);
            VIRTIO_NET_CTRL_ANNOUNCE_ACK
            VIRTIO_NET_S_ANNOUNCE
              qemu_announce_timer_step

VIRTIO_NET_CTRL_MQ
      virtio_net_handle_mq(n, ctrl.cmd, iov, iov_cnt);
            !=VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET
              virtio_net_set_status
              virtio_net_set_queues

VIRTIO_NET_CTRL_GUEST_OFFLOADS
      virtio_net_handle_offloads(n, ctrl.cmd, iov, iov_cnt);
            VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET
              virtio_net_supported_guest_offloads
              virtio_net_apply_guest_offloads
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值