当前位置: 首页 > news >正文

宁波seo站外优化推广广西南宁人才招聘网站

宁波seo站外优化推广,广西南宁人才招聘网站,上海网站营销怎么样,全国建设交易信息网站网络虚拟化有和存储虚拟化类似的地方,例如,它们都是基于 virtio 的,因而在看网络虚拟化的过程中,会看到和存储虚拟化很像的数据结构和原理。但是,网络虚拟化也有自己的特殊性。例如,存储虚拟化是将宿主机上…

网络虚拟化有和存储虚拟化类似的地方,例如,它们都是基于 virtio 的,因而在看网络虚拟化的过程中,会看到和存储虚拟化很像的数据结构和原理。但是,网络虚拟化也有自己的特殊性。例如,存储虚拟化是将宿主机上的文件作为客户机上的硬盘,而网络虚拟化需要依赖于内核协议栈进行网络包的封装与解封装。

当网络包经过客户机的协议栈到达 virtio_net 驱动的时候,按照 net_device_ops 的定义,start_xmit 会被调用。

static const struct net_device_ops virtnet_netdev = {.ndo_open            = virtnet_open,.ndo_stop          = virtnet_close,.ndo_start_xmit      = start_xmit,.ndo_validate_addr   = eth_validate_addr,.ndo_set_mac_address = virtnet_set_mac_address,.ndo_set_rx_mode     = virtnet_set_rx_mode,.ndo_get_stats64     = virtnet_stats,.ndo_vlan_rx_add_vid = virtnet_vlan_rx_add_vid,.ndo_vlan_rx_kill_vid = virtnet_vlan_rx_kill_vid,.ndo_xdp    = virtnet_xdp,.ndo_features_check  = passthru_features_check,
};

接下来的调用链为:start_xmit->xmit_skb-> virtqueue_add_outbuf->virtqueue_add,将网络包放入队列中,并调用 virtqueue_notify 通知接收方。

static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
{struct virtnet_info *vi = netdev_priv(dev);int qnum = skb_get_queue_mapping(skb);struct send_queue *sq = &vi->sq[qnum];int err;struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);bool kick = !skb->xmit_more;bool use_napi = sq->napi.weight;
....../* Try to transmit */err = xmit_skb(sq, skb);
......if (kick || netif_xmit_stopped(txq))virtqueue_kick(sq->vq);return NETDEV_TX_OK;
}bool virtqueue_kick(struct virtqueue *vq)
{if (virtqueue_kick_prepare(vq))return virtqueue_notify(vq);return true;
}

写入一个 I/O 会使得 qemu 触发 VM exit,这个逻辑我们在解析 CPU 的时候看到过。

接下来,那会调用 VirtQueue 的 handle_output 函数。前面我们已经设置过这个函数了,其实就是 virtio_net_handle_tx_bh。

static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq)
{VirtIONet *n = VIRTIO_NET(vdev);VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))];q->tx_waiting = 1;virtio_queue_set_notification(vq, 0);qemu_bh_schedule(q->tx_bh);
}

virtio_net_handle_tx_bh 调用了 qemu_bh_schedule,而在 virtio_net_add_queue 中调用 qemu_bh_new,并把函数设置为 virtio_net_tx_bh。

virtio_net_tx_bh 函数调用发送函数 virtio_net_flush_tx。

static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
{VirtIONet *n = q->n;VirtIODevice *vdev = VIRTIO_DEVICE(n);VirtQueueElement *elem;int32_t num_packets = 0;int queue_index = vq2q(virtio_get_queue_index(q->tx_vq));for (;;) {ssize_t ret;unsigned int out_num;struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE + 1], *out_sg;struct virtio_net_hdr_mrg_rxbuf mhdr;elem = virtqueue_pop(q->tx_vq, sizeof(VirtQueueElement));out_num = elem->out_num;out_sg = elem->out_sg;
......ret = qemu_sendv_packet_async(qemu_get_subqueue(n->nic, queue_index),out_sg, out_num, virtio_net_tx_complete);}
......return num_packets;
}

virtio_net_flush_tx 会调用 virtqueue_pop。这里面,我们能看到对于 vring 的操作,也即从这里面将客户机里面写入的数据读取出来。

然后,我们调用 qemu_sendv_packet_async 发送网络包。接下来的调用链为:qemu_sendv_packet_async->qemu_net_queue_send_iov->qemu_net_queue_flush->qemu_net_queue_deliver。

在 qemu_net_queue_deliver 中,我们会调用 NetQueue 的 deliver 函数。前面 qemu_new_net_queue 会把 deliver 函数设置为 qemu_deliver_packet_iov。它会调用 nc->info->receive_iov。

static NetClientInfo net_tap_info = {.type = NET_CLIENT_DRIVER_TAP,.size = sizeof(TAPState),.receive = tap_receive,.receive_raw = tap_receive_raw,.receive_iov = tap_receive_iov,.poll = tap_poll,.cleanup = tap_cleanup,.has_ufo = tap_has_ufo,.has_vnet_hdr = tap_has_vnet_hdr,.has_vnet_hdr_len = tap_has_vnet_hdr_len,.using_vnet_hdr = tap_using_vnet_hdr,.set_offload = tap_set_offload,.set_vnet_hdr_len = tap_set_vnet_hdr_len,.set_vnet_le = tap_set_vnet_le,.set_vnet_be = tap_set_vnet_be,
};

根据 net_tap_info 的定义调用的是 tap_receive_iov。他会调用 tap_write_packet->writev 写入这个字符设备。

在内核的字符设备驱动中,tun_chr_write_iter 会被调用。

static ssize_t tun_chr_write_iter(struct kiocb *iocb, struct iov_iter *from)
{struct file *file = iocb->ki_filp;struct tun_struct *tun = tun_get(file);struct tun_file *tfile = file->private_data;ssize_t result;result = tun_get_user(tun, tfile, NULL, from,file->f_flags & O_NONBLOCK, false);tun_put(tun);return result;
}

当我们使用 writev() 系统调用向 tun/tap 设备的字符设备文件写入数据时,tun_chr_write 函数将被调用。它会使用 tun_get_user,从用户区接收数据,将数据存入 skb 中,然后调用关键的函数 netif_rx_ni(skb) ,将 skb 送给 tcp/ip 协议栈处理,最终完成虚拟网卡的数据接收。

把网络虚拟化场景下网络包的发送过程总结一下。

  • 在虚拟机里面的用户态,应用程序通过 write 系统调用写入 socket。
  • 写入的内容经过 VFS 层,内核协议栈,到达虚拟机里面的内核的网络设备驱动,也即 virtio_net。
  • virtio_net 网络设备有一个操作结构 struct net_device_ops,里面定义了发送一个网络包调用的函数为 start_xmit。
  • 在 virtio_net 的前端驱动和 qemu 中的后端驱动之间,有两个队列 virtqueue,一个用于发送,一个用于接收。然后,我们需要在 start_xmit 中调用 virtqueue_add,将网络包放入发送队列,然后调用 virtqueue_notify 通知 qemu。
  • qemu 本来处于 KVM_RUN 的状态,收到通知后,通过 VM exit 指令退出客户机模式,进入宿主机模式。发送网络包的时候,virtio_net_handle_tx_bh 函数会被调用。
  • 接下来是一个 for 循环,我们需要在循环中调用 virtqueue_pop,从传输队列中获取要发送的数据,然后调用 qemu_sendv_packet_async 进行发送。
  • qemu 会调用 writev 向字符设备文件写入,进入宿主机的内核。
  • 在宿主机内核中字符设备文件的 file_operations 里面的 write_iter 会被调用,也即会调用 tun_chr_write_iter。
  • 在 tun_chr_write_iter 函数中,tun_get_user 将要发送的网络包从 qemu 拷贝到宿主机内核里面来,然后调用 netif_rx_ni 开始调用宿主机内核协议栈进行处理。
  • 宿主机内核协议栈处理完毕之后,会发送给 tap 虚拟网卡,完成从虚拟机里面到宿主机的整个发送过程。

此文章为12月Day2学习笔记,内容来源于极客时间《趣谈Linux操作系统》,推荐该课程。

http://www.yayakq.cn/news/600172/

相关文章:

  • php网站开发前端网站关键词互点
  • 做gif动图的网站犯法吗重庆森林为什么不能看
  • 融资网站建设重点云盘搜
  • 做视频网站玩什么配置iis6.0新发布网站访问速度慢
  • 简单的网站设计模板下载宣传式网站
  • 湖州网站设计建设杭州app开发外包公司
  • 动易网站系统怎么样wordpress调用多个底部
  • 网站pc端和手机端分离怎么做沈阳专门做网站
  • 淄博营销网站建设公司网站平台搭建流程
  • 家具能在什么网站上做怎么做竞价托管
  • wordpress接入官方号廊坊关键词seo排名网站
  • 网站后台编码网站制作和维护费用
  • 网站备案没通过电商网站前端源码
  • 网站内容更新湖南门户网站建设
  • 国外网站入口网站是哪个公司做的
  • 重庆奉节网站建设公司哪家专业发布外链的步骤
  • 移动网站 案例网站整合建设是啥意思
  • 公司企业网站开发投资公司名字起名大全
  • 楼盘网站开发新手做网络销售难吗
  • 住房和城乡建设部的网站首页福田外贸网站建设
  • 企业网站新闻wp怎么做营销型的物流网站模板下载
  • 青岛做网站排名大同网站建设哪家好
  • 网站统计代码放哪里gif动图素材网站
  • 网站快速排名优化wordpress用什么空间
  • 在线做简单的网站wordpress安装包文件夹
  • 网站不备案写一个小程序多少钱
  • 织梦做的网站首页幻灯片怎么不能显示学网站设计和平面设计
  • 网站建设科技公司外部环境分析jsp语言做网站
  • 新手如何做网站运营网络营销方案分析
  • 政务服务网站 建设方案公司网站更换域名流程