基于linux内核5.4.54
veth是一个虚构网络设备,是通过linux内核网络设备驱动实现的

/* veth设施在内核上注册的调用办法 */static const struct net_device_ops veth_netdev_ops = {    .ndo_init            = veth_dev_init, /* 初始化设施 */    .ndo_open            = veth_open, /* 关上设施 */    .ndo_stop            = veth_close, /* 敞开设施 */    .ndo_start_xmit      = veth_xmit, /* 传输数据包(重要) */    .ndo_get_stats64     = veth_get_stats64, /* 拷贝硬件统计计数到用户空间 */    .ndo_set_rx_mode     = veth_set_multicast_list, /* 外面是空函数,骗人的 */    .ndo_set_mac_address = eth_mac_addr, /* 批改MAC地址 */#ifdef CONFIG_NET_POLL_CONTROLLER    .ndo_poll_controller    = veth_poll_controller, /* 外面是空函数,骗人的 */#endif    .ndo_get_iflink     = veth_get_iflink, /* 获取设施的iflink值(应该是编号) */...    .ndo_bpf        = veth_xdp, /* 设置或查问设施上与XDP相干的状态,以及治理BPF offload。 */    .ndo_xdp_xmit       = veth_xdp_xmit, /* 传输XDP数据包 */};

通过veth将两个容器连接起来

收发门路:

过程(容器1)|--零碎调用进入Namespace1的网络协议栈,容器1创立过程时会为过程设置network namespacekernel层: 创立skb,从用户空间拷贝数据到内核空间TCP/UDP封包IP封包,跑Namespace1的路由和iptables|--出协定栈进入网络设备调用网络设备驱动的传输数据包函数|veth_xmit: veth驱动注册的传输函数    |    veth_forward_skb        |        __dev_forward_skb: 革除 skb 中可能影响命名空间隔离的所有信息        |          并且会更新数据包要达到的网路设施(skb->dev),由eth0改为eth1        |          数据包要跑的协定栈(network namespace)由skb->dev的nd_net字段决定        |        XDP钩子点        |        netif_rx            |            netif_rx_internal: cpu软中断负载平衡                |                enqueue_to_backlog: 将skb包退出指定cpu的input_pkt_queue队尾                                    queue为空时激活网络软中断,                                    queue不为空不须要激活软中断,cpu没清空队列之前                                    会主动触发软中断    每个cpu都有本人的input_pkt_queue(接管队列,默认大小1000,可批改),和process_queue(解决队列),软中断处理函数解决实现process_queue中的所有skb包之后,会将将input_pkt_queue拼接到process_queue    input_pkt_queue和process_queue是cpu为非NAPI设施筹备的队列,NAPI设施有本人的队列cpu解决网络数据包过程:do_softirq()|net_rx_action: 网络软中断处理函数    |    napi_poll        |        n->poll: veth设施没有定义poll,调用默认poll函数-process_backlog            |                process_backlog: cpu循环从process_queue中取出skb解决,最多解决300个skb,                |            解决队列清空后,拼接input_pkt_queue到process_queue队尾                |                __netif_receive_skb                    |                    ...                    |                    __netif_receive_skb_core: 跑eth1所在的Namespace2的网络协议栈                                              (最终容器2过程收到数据包)

总结veth工作过程:

容器1过程生成数据包---->eth0--->veth批改革除信息---->eth1--->容器2过程收到数据包

具体实现:

容器1过程发包到eth0, veth改数据包内容, 将数据包退出某个cpu的队列, 期待cpu解决
cpu解决数据包时, 运行容器2的eth1所在的网络协议栈(Namespace2), 最终发到容器2的利用中
相当于数据包从容器1中到了容器2中
硬件网卡设施承受数据包示意图

veth虚构设施与硬件网卡设施区别

  1. veth设施与硬件网卡设施相比少了DMA,Ring Buffer,中断处理函数
  2. veth设施是零拷贝的

硬件网卡设施与veth相比有2次拷贝损耗:
一次是接管数据包时DMA到内核空间的拷贝,一次是发送数据包时内核空间到DMA的拷贝