virtio net前端

######版本为linux4.13.2#########
virtio_init
    bus_register(&virtio_bus)

static struct bus_type virtio_bus = {
    .name  = "virtio",
    .match = virtio_dev_match,
    .dev_groups = virtio_dev_groups,
    .uevent = virtio_uevent,
    .probe = virtio_dev_probe,
    .remove = virtio_dev_remove,
};

virtio_dev_probe //virtio bus的probe
    virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER) //发现virtio驱动
        dev->config->set_status(dev, dev->config->get_status(dev) | status);
    virtio_finalize_features
        virtio_add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK) //features ok
    drv->probe(dev) //调用驱动的probe,比如virtio net的 virtnet_probe
    virtio_device_ready //设置VIRTIO_CONFIG_S_DRIVER_OK
    virtio_config_enable //配置使能
    
-----------
//virtio net前端驱动入口
virtio_net_driver_init
    register_virtio_driver(&virtio_net_driver)
        driver_register
            bus_add_driver
                driver_attach //bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)
                    __driver_attach    
                        driver_probe_device
                            really_probe
                                dev->bus->probe(dev) 或 drv->probe //一般bus的probe里会调用drv的probe
省略掉device的probe,这里驱动在注册时也会调用probe(这里最好把device的probe分析下,不然始终没连接起来!)
static struct virtio_driver virtio_net_driver = {
    .feature_table = features,
    .feature_table_size = ARRAY_SIZE(features),
    .feature_table_legacy = features_legacy,
    .feature_table_size_legacy = ARRAY_SIZE(features_legacy),
    .driver.name =    KBUILD_MODNAME,
    .driver.owner =    THIS_MODULE,
    .id_table =    id_table,
    .validate =    virtnet_validate,
    .probe =    virtnet_probe,
    .remove =    virtnet_remove,
    .config_changed = virtnet_config_changed,
#ifdef CONFIG_PM_SLEEP
    .freeze =    virtnet_freeze,
    .restore =    virtnet_restore,
#endif
};
virtnet_probe
    dev->netdev_ops = &virtnet_netdev; //此ops回调结构体包含了open、stop、start_xmit、set_mac_address、poll_controller等
    dev->ethtool_ops = &virtnet_ethtool_ops; //ethtool的ops
    INIT_WORK(&vi->config_work, virtnet_config_changed_work); //配置改变工作队列
    init_vqs
        virtnet_alloc_queues
            INIT_DELAYED_WORK(&vi->refill, refill_work); //后面会用到,用于延时填充avail ring
            netif_napi_add //添加virtnet_poll到rq[i].napi
            netif_tx_napi_add //添加virtnet_poll_tx到sq[i].napi
            sg_init_table 
        virtnet_find_vqs
            callbacks[rxq2vq(i)] = skb_recv_done; //接收回调
            callbacks[txq2vq(i)] = skb_xmit_done; //发送回调
            vi->vdev->config->find_vqs(XXX,callbacks,XXX) //回调赋值,中断中会调用此回调


            
//填充avail ring
refill_work
                

//接收回调
skb_recv_done
    virtqueue_napi_schedule
        virtnet_poll
        
//接收处理napi
virtnet_poll
    virtnet_poll_cleantx
    virtnet_receive
        {virtqueue_get_buf
            virtqueue_get_buf_ctx //从vring used中取出id、len;从desc_state中取出data?(在virtqueue_add 的时候会进行赋值)
                detach_buf //释放相关内存及指针,这里会有num_free++操作(空闲buffer数,已经处理后释放的buffer数)
        receive_buf
            receive_small[receive_big、receive_mergeable]
                build_skb
            skb_vnet_hdr
            virtio_net_hdr_to_skb
            napi_gro_receive //送给上层处理
        } //循环处理完所有used ring包
        try_fill_recv //条件是:空闲vring数量大于一半;如果失败会启动delaywork

try_fill_recv 添加buffer。主要在receiving路径被调用;也可以在receiving之前的ndo_open中;另一个场景是refill_work(利用napi_disable来关闭receiving)
    {add_recvbuf_mergeable
    add_recvbuf_big
    add_recvbuf_small
        virtqueue_add_inbuf
            virtqueue_add //添加一个buffer到avail ring
    }//循环,每次添加一个,知道把空闲的buffer添加满!
    virtqueue_kick //notify
        virtqueue_kick_prepare
            vring_need_event
                return (__u16)(new_idx - event_idx - 1) < (__u16)(new_idx - old);//简化后就是event_idx+1>old;而event_idx是记录后端处理位置;意思就是后端处理位置超过(加1后超过,其实是等于)了上次添加buffer的位置,就返回真,需要新添加buffer
            //没用event的场景看vring.used->flags判断是否notify
        virtqueue_notify
调用其的函数有:
refill_work //用work队列延时填
virtnet_receive《- virtnet_poll《-virtnet_alloc_queues(netif_napi_add)《- virtnet_netpoll(napi_schedule)《-virtnet_netdev.ndo_poll_controller《-netpoll_poll_dev(ops->ndo_poll_controller)//《-netpoll_send_skb_on_dev《-netpoll_send_skb《-netpoll_send_udp(貌似跟丢了,反正是在napi中调用)
调用try_fill_recv条件:if (rq->vq->num_free > virtqueue_get_vring_size(rq->vq) / 2);vq->num_free为空闲的vring数量(vring_num-avail_num);即空闲vring数量大于一半时就触发添加。
virtnet_open
virtnet_restore_up

总结:guest中virtio网卡驱动在napi中调用接收函数中判断是否应该添加buffer到vring中。当空闲vring数量大于一半时,会调用try_fill_recv来试图添加buffer,因为还得满足vring_need_event条件;如果try_fill_recv失败会利用schedule_delayed_work来延时再调用。pci中断处理程序中会调用,virtio net注册的回调,进而调用napi来处理接收。
------------------------
//发送处理napi
virtnet_poll_tx

//发送回调
skb_xmit_done

=========================
module_pci_driver(virtio_pci_driver)
    module_driver(__pci_driver, pci_register_driver, pci_unregister_driver) //驱动注册宏
        pci_register_driver
            __pci_register_driver
                drv->driver.bus = &pci_bus_type;
                driver_register

struct bus_type pci_bus_type = {
    .name        = "pci",
    .match        = pci_bus_match,
    .uevent        = pci_uevent,
    .probe        = pci_device_probe,
    .remove        = pci_device_remove,
    .shutdown    = pci_device_shutdown,
    .dev_groups    = pci_dev_groups,
    .bus_groups    = pci_bus_groups,
    .drv_groups    = pci_drv_groups,
    .pm        = PCI_PM_OPS_PTR,
    .num_vf        = pci_bus_num_vf,
};

pci_device_probe
    __pci_device_probe
        pci_call_probe
            local_pci_probe
                pci_drv->probe //这里会调用virtio_pci_driver的probe(virtio_pci_probe)

//virtio pci驱动入口
virtio_pci_probe
    virtio_pci_legacy_probe
        vp_dev->ioaddr = pci_iomap(pci_dev, 0, 0) //通过device映射io地址
        vp_dev->isr = vp_dev->ioaddr + VIRTIO_PCI_ISR //获取isr中断寄存器地址
        vp_dev->vdev.config = &virtio_pci_config_ops //包含vp的set、get、vp_find_vqs等
        vp_dev->config_vector = vp_config_vector
        vp_dev->setup_vq = setup_vq
    [virtio_pci_modern_probe]
    register_virtio_device
        device_register

vp_find_vqs //config->find_vqs
    vp_find_vqs_msix //软中断?
        vp_request_msix_vectors
            request_irq(XXX,vp_config_changed,XXX) //pci配置改变中断
            request_irq(XXX,vp_vring_interrupt,XXX) //pci硬件中断?
        vp_setup_vq
            vp_dev->setup_vq
        request_irq(XXX,vring_interrupt,XXX) //pci硬件中断?
    [vp_find_vqs_intx] //常规中断,就一个
        request_irq(XXX,vp_interrupt,XXX)
        vp_setup_vq
            vp_dev->setup_vq
vp_config_vector //设置VIRTIO_MSI_CONFIG_VECTOR寄存器,用来做msi软中断?
setup_vq
    vring_create_virtqueue
        vring_init
        __vring_new_virtqueue
vring_interrupt
    more_used //
    vq->vq.callback //调用virtqueue的接受或发送回调
vp_config_changed
    virtio_config_changed
        __virtio_config_changed
            drv->config_changed
vp_vring_interrupt
    vring_interrupt
vp_interrupt
    ioread8(vp_dev->isr) //读清isr
    vp_config_changed
    vp_vring_interrupt

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是 virtio 规范 v1.1 中所有 Virtio 网络设备的 feature bit 及其含义: 1. VIRTIO_NET_F_CSUM (0):表示设备支持 TCP/UDP 校验和计算。 2. VIRTIO_NET_F_GUEST_CSUM (1):表示设备支持让客户机进行 TCP/UDP 校验和计算。 3. VIRTIO_NET_F_CTRL_GUEST_OFFLOADS (2):表示设备支持向客户机暴露控制通道,并支持客户机开启或关闭校验和、分段和 GSO 等功能。 4. VIRTIO_NET_F_MAC (5):表示设备支持配置 MAC 地址。 5. VIRTIO_NET_F_GUEST_TSO4 (7):表示设备支持让客户机进行 TCPv4 大分段 (TSO)。 6. VIRTIO_NET_F_GUEST_TSO6 (8):表示设备支持让客户机进行 TCPv6 大分段 (TSO)。 7. VIRTIO_NET_F_GUEST_ECN (9):表示设备支持让客户机启用 ECN。 8. VIRTIO_NET_F_GUEST_UFO (10):表示设备支持让客户机进行 UDP 分段 (UFO)。 9. VIRTIO_NET_F_HOST_TSO4 (11):表示设备支持向主机进行 TCPv4 大分段 (TSO)。 10. VIRTIO_NET_F_HOST_TSO6 (12):表示设备支持向主机进行 TCPv6 大分段 (TSO)。 11. VIRTIO_NET_F_HOST_ECN (13):表示设备支持向主机启用 ECN。 12. VIRTIO_NET_F_HOST_UFO (14):表示设备支持向主机进行 UDP 分段 (UFO)。 13. VIRTIO_NET_F_MRG_RXBUF (15):表示设备支持向主机发送大数据包,并且支持将多个小数据包合并为一个大数据包。 14. VIRTIO_NET_F_STATUS (16):表示设备支持向主机报告网络设备的状态。 15. VIRTIO_NET_F_CTRL_VQ (17):表示设备支持向主机暴露控制通道。 16. VIRTIO_NET_F_CTRL_RX (18):表示设备支持向主机发送控制信息。 17. VIRTIO_NET_F_CTRL_VLAN (19):表示设备支持 VLAN。 18. VIRTIO_NET_F_GUEST_ANNOUNCE (21):表示设备支持客户机通知主机其 IP 地址。 19. VIRTIO_NET_F_MQ (22):表示设备支持使用多个队列。 20. VIRTIO_NET_F_CTRL_MAC_ADDR (23):表示设备支持通过控制通道向客户机发送 MAC 地址。 以上是 virtio 规范 v1.1 中的所有 Virtio 网络设备的 feature bit 及其含义。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值