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

更换网站后台logo的专业设计

更换网站后台,logo的专业设计,wordpress3.6,网站投票链接怎么做的网络虚拟化有和存储虚拟化类似的地方,例如,它们都是基于 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/137182/

相关文章:

  • 中国移动网站建设怎么做大连模板网站制作哪家专业
  • 聊城网站优化合作社网站模板
  • 秦皇岛做网站多少钱网站ui设计是什么
  • 做企业网站所要注意什么怎么制作游戏u盘
  • 网站建设在哪里发布二级建造师建设云网站
  • 网站数据怎么更新网站搭建技术有哪些
  • 最超值的郑州网站建设wordpress主页小工具
  • 沈阳网站建设方案策划乐山网站开发
  • 个人网站怎么做cps网站开发教学文章
  • 山东省建设工程注册中心网站做网络推广工作怎么样
  • 卖建材的网站有哪些现在建设网站都用什么软件
  • 水母智能设计平台秦皇岛seo招聘
  • 衡阳哪有做网站推广的网页制作与设计中string对象ppt
  • 成都网站建设网站制作长沙新媒体营销
  • 做简历网站 知乎秦皇岛 网站
  • 长泰网站建设梵克雅宝官网中国官网
  • 大学生做网站沈阳看男科哪家医院好
  • 推荐做pc端网站船员专用网站开发建议
  • 网站的搜索功能网页版qq邮箱怎么发文件
  • 网站建设文献综述模板个人域名备案完成了 可以改网站内容吗
  • 企业网站关键词应如何优化备案一个网站为什么需要域名
  • 建设一个网站可以做什么广告发布服务属于什么服务
  • 哪个网站是专门做封面素材网站主页设计优点
  • 网站建设总结 优帮云兰州网络营销推广价格
  • 查询网站备案服务商论坛类网站搭建
  • 网页制作模板的淘宝网站代码seo推广方式
  • 企业网站的内容牛商网
  • 用手机如何做网站小型教育网站的开发与建设论文
  • 公司网站百度推广红色的网站
  • 成品电影网站建设wordpress 4.7.11搬家