功能

网络子系统负责系统的网络IO,通过与网络设备(路由器、交换机等)的数据交互,实现端到端的数据交互过程。下图示意网络数据流:

2e4ed485a21739331a9b86f49c872d27.png

​ 图 8-1 网络数据流视图

网络子系统位于端系统中,从上图可以看出网络子系统在数据面划分成应用层、传输层、网络层、链路层、物理层。每一层可以对应到OSI^定义的网络七层模型^1。

架构

网络子系统架构可以分软件视角,硬件视角两个维度描述。软件视角淡化物理位置、设备差异,强调逻辑分层;硬件视角强调系统维度描述架构组成元素,本文以鲲鹏920芯片作为系统参考对象。

软件视角的网络子系统是linux网络子系统;硬件视角的网络子系统是鲲鹏网络子系统。

linux网络子系统

linux kernel 4.19版本中,网络子系统代码目录定义如下:

/net

/net/core

/driver/net

linux网络子系统按照逻辑分层方式描述架构分层。通过逻辑抽象分层,linux网络子系统给用户态提供统一的BSD Socket接口通道,并同时支持各种不同的硬件,各种不同的网络协议。

33f7f70ed9ace0bc2de3619c51acb879.png

​ 图8-2 linux网络子系统

linux 网络子系统内模块众多,功能复杂,本文不详细讲解每个模块的功能及实现。我们从数据面、管理面两个维度描述该子系统的工作原理。

数据面

在发送方向上,应用程序通过send()系统调用接口进行报文发送,报文内容会先进入内核空间完成必要的协议层处理,此时硬件Device未必是就绪状态,所以Driver程序必须等其就绪才能通知其进行报文发送处理。在此之前,报文必须缓存在主存内。

在接收方向上,硬件Device收到数据报文后,驱动收到中断通知完成数据报文读取进内核空间,完成必要的协议层处理,此时应用程序未必是就绪状态,所以内核需等其就绪后才能唤醒其进行报文接收处理。在此之前,报文必须缓存在主存内。

报文在内核中缓存是通过一个称之为sk_buff的数据结构进行管理的,该结构复杂,内部细节较多,这里不展开描述。其基本原理是:

报文头的解析/封装采取空间预留技术,在协议层内各种协议报文头处理过程中,协议头解析/封装结果只需在预留空间内偏移,省去了很多内存拷贝,迁移操作。

报文体的构造采取数据分段技术,当报文体内容过长时,可以通过分段形式不断补充数据,sk_buff以链方式管理数据包,同样也省去了很多内存拷贝、迁移操作。

以上两个逻辑可以图例方式表达:

549a3200d7f628a48f74aa69bad0f3c9.png

​ 图8-3 报文收发逻辑

在图例中更容易清晰看到:

内存拷贝:收发两个方向(硬件设备用户应用程序),都存在两次拷贝操作,一次是软件拷贝,一次是硬件拷贝。

执行调度:收报流程中,硬件设备中断触发驱动软件分配sk_buff,驱动软件触发软中断驱动协议层完成报文处理,待用户线程就绪时唤醒其执行接收报文处理。发送流程中,用户线程分配sk_buff,协议层完成报文处理后入发送缓存队列,随后通过软中断调度触发驱动软件通知硬件设备进行发送报文。

所以linux网络子系统数据面在空间性能方面存在内存拷贝的性能开销,时间性能方面存在多次调度切换的性能开销。

管理面

linux网络子系统管理面通过一个重要对象进行管理:网络设备。

f589735c16d778b6f900c10820e20800.png

​图8-4 网络设备驱动架构

网络设备驱动架构中,对协议层抽象出统一的报文收发接口,使协议层与各种网络设备充分解耦。通过注册回调函数方式,实现具体硬件设备的收发报文接口调用。其中关键的数据结构是struct net_device,其对各种网络设备进行抽象、封装,屏蔽硬件差异。

网络设备驱动程序通过register_netdev()注册设备上线,注册时携带协议层定义的数据结构、回调函数,从而配合协议层对其进行控制。

例如网卡硬件能力实现了很多offloading功能,尽量将一些机械重复的工作下沉至网卡硬件,其目的是解放CPU,提升系统吞吐量。net_device就通过xx_features进行表达硬件的能力,如下所示:

struct net_device {

...

netdev_features_tfeatures;

netdev_features_thw_features;

netdev_features_twanted_features;

netdev_features_tvlan_features;

netdev_features_thw_enc_features;

netdev_features_tmpls_features;

netdev_features_tgso_partial_features;

...

}

设备上线注册时,驱动程序根据硬件实际情况设置这些字段通知协议层硬件能力,协议层在处理报文时根据硬件能力就跳过某些计算过程。

结语

linux网络子系统是站在单CPU视角看数据面、管理面,现代服务器普遍是SMP/NUMA系统结构,仅仅从单CPU视角看网络子系统不能完整展现服务器内网络子系统的工作过程。

下面我们介绍下鲲鹏920系列的网络子系统,用来展示更多工作过程。

鲲鹏网络子系统

以鲲鹏920作为参考对象,介绍其网络子系统。

f820990f5c93503a98d5e9ebcfb55ca7.png

​图 8-5 鲲鹏网络子系统

组成部分:

网络ICL:

网络ICL(I/O Clusters)就是鲲鹏920网络子系统。网络ICL与PCIe系统架构兼容,可以支持多个PCI Function,每个PCI Function具备独立的任务空间、配置空间,以处理各自独立的服务数据、硬件参数配置。简单的说就是网络ICL可以向总线上报多个PCI Function。

PCI Function:

PCI Function可以呈现为物理网卡(PF)或虚拟网卡(VF),每个PF/VF可以被分配到1个或多个队列对(QP),其包括Tx队列和Rx队列,这些队列会映射到主存空间(Tx Queue、Rx Queue)。通过QP,PF或VF就可以进行主存的访存操作。

当PF或VF被分配多队列对时,这个网卡就具备同时与多个CPU进行报文收发处理(RSS技术)。

主存:

主存会提供存储空间映射到QP,并以ring buffer形式管理Tx Queue、Rx Queue。

中断:

接收到报文时,通过触发中断通知CPU的设备驱动程序处理收到的报文;发送报文完成后,通过触发中断通知CPU释放主存内的报文资源。

CPUs:

多核CPU,运行用户态程序、网络协议栈、网络驱动程序,软件形式通过总线触发Tx Schedule调度报文发送。

总线:

鲲鹏920片内总线。

Tx Schedule:

当主存 Tx Queue的ring buffer非空时,Tx Schedule就会被触发运行,执行发送调度操作。调度输出结果是触发TxDMA进行报文加载操作。

TxDMA / RxDMA:

TxDMA 用于将数据包从主存读取后加载进Packet Buffer,RxDMA用于从Packet Buffer读取后加载进主存队列。TxDMA / RxDMA的数据读存操作目的只有一个:给CPU”减负“,提升CPU利用率。

NIC Engine

PPP:提供NIC Engine可编程能力,为报文处理提供灵活性。包括提供基于VLAN和MAC信息的Rx方向的过滤能力,提供Flow Director机制实现RSS负载平衡能力。

Packet Buffer:提供Tx/Rx两个方向的报文缓存能力。

MAC复用器:

支持以太帧的发送/接收,实现CRC计算和校验,提供流控、自协商等能力。

为了更好的了解其工作原理,我们从报文收发两方面描述其工作原理。

接收数据流

接收数据流是指网络ICL从物理链路媒介中接收到数据,经过解析、过滤、复制等处理后,将数据报文存储到Packet Buffer,然后由RxDMA将数据报文存储至主存,最后向软件报告。

87c1b367324577a53a731cd61237d75b.png

​ 图 8-5 接收数据流过程

发送数据流

发送数据流是指网络设备驱动程序对ring buffer添加包任务,随后触发Tx Schedule发起调度,由NIC Engine完成主存内报文读取,TSO,报文编辑,MAC发送等操作。发送完成后,产生中断通知CPU释放包任务资源。

165a7a8ef22c1e64574064409ab3f40a.png

​ 图 8-6 发送数据流过程

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐