VxWorks 6.6网络协议栈分析及网络接口基本知识

本文包含网络接口的硬件基本原理和VxWorks 6.6网络协议栈/驱动的分析,适用于VxWorks6.6以及之前的版本,并可用作其他版本协议栈的参考。

0. 概述

0.1 网络接口

以太网目前有两种模型,即ISO(国际标准化组织)定义的的OSI七层模型和IETF(互联网工程任务组)的TCP/IP五层模型,具体可参考 TCP/IP协议详解 。目前,TCP/IP为互联网的事实标准,具体分层如下所示:

OSI TCP/IP 实体
应用层
表示层 应用层 FTP/HTTP等
会话层
传输层 传输层 TCP/UDP
网络层 网络层 IP
链路层 链路层 MAC(介质访问控制器)
物理层 物理层 PHY(物理层)

上表中:

  • 以太网报文格式 与上表的分层对应:
物理层 链路层 网络层 传输层 应用层 链路层
前导位、起始标志 以太网头 IP头 TCP/UDP头等 FTP/HTTP数据等 CRC校验
  • MAC 又称为以太网控制器,既具有独立的链路层地址(MAC地址,又称为以太网地址),也就是通常意义上或者 狭义上的网口 ,用于控制链路层数据的传输;
  • PHY 用于控制物理层传输,用于物理链路与MAC之间数据的编解码、物理链路控制、载波侦听、线序交换等功能,通常只包含PCS(物理编码子层)、PMD(物理介质相关子层)、PMA(物理介质附加子层)等,但是1000Mbps以上的高速链路需要更多的子层(DTE XGXS、PHY XGXS);
  • MAC通过 MII(狭义上的介质独立接口) /RGMII(简化的千兆介质无关接口)/SGMII(串行千兆介质无关接口)/XGMII(超高速介质无关接口)总线等连接到PHY上;
  • 每个MAC通常只需要一个PHY,但是1000Mbps以上的高速网口的PHY设备需要可能还需要先通过内部PHY将TBI接口转换成SGMII接口或者将XGMII接口转换成XAUI接口,再连接到外部PHY,从而降低外部PHY的布线难度;
  • TBI、XAUI和MII、RGMII、SGMII、XGMII、GMII、QGMII等接口都属于 广义上的MII接口 ,对应于MII总线;
  • PHY必须挂在 MII总线 上,通过 MII控制器 访问;
  • MII接口有 MDIO22和MIDO45 两种标准,分别定义在 802.3ap clasue22和Clasue 45 中, 前者支持5位PHY地址和5位寄存器地址,后者增加了5位设备地址,允许控制PHY的不同子层; 因此 ,每个MII控制器最多通过MII总线支持 32个PHY设备
  • 广义上的网口 指的是MAC、MII控制器和PHY的综合体。

0.2 约定

  1. socket 即套接字,是BSD协议栈提出的网络接口,包含一个接收缓冲区,用于收发数据和控制数据传输;
  2. MBLK/Cluster/data 是BSD协议栈提出的缓冲区模型,每个数据区 data 对应一个 Cluster ,每个 Cluster 关联到1个 MBLK 上; MBLK 作为以太网报文的代表,可以将多个以太网报文分片串成一个链表,用以提升数据收发效率;
  3. 分析以VxWorks6.6上的MPC5200 FEC网口为例,适用于VxWorks6.6以及之前的版本,并可用作其他版本协议栈的参考;
  4. 流程图中的非关键函数参数和非关键流程被省略以突出重点和降低工作量;

1. END驱动架构

END驱动整体架构如下所示:

Snipaste_2022-08-13_11-59-17.png

其中:

  1. 用户可以通过3种接口访问协议栈接口:
  • socket :由 sockLib 库提供,包括 socket/bind/connect/listen/accept/getsockopt/setsockopt/recv/recvfrom/recvmsg/send/sendmsg/sendto() 等;其中:
  • 通用IO接口 :由 sockLib 库提供,包括 close/ioctl/write/ioctl()
  • ipcom/ipnet接口 :由 ipcom/ipnet 提供,包括 ifconfig 等;

2. sockLib 库位于 vxworks-6.6/target/src/wrn/coreip/sysdep/os/vxWorks/socket ,提供 socket接口 ,并调用 iosDrvInstall() 接口安装IO设备驱动,从而为每个socket套接字创建描述符以提供 通用IO接口 ,其中:

    • socket/accept 接口除了调用 ipcom/ipnet 注册的 socketRtn/acceptRtn() 钩子函数,还需要调用 iosLib 库接口创建IO设备作为socket描述符;
    • 其余socket接口 在进行简单的参数检查后直接调用 ipcom/ipnet 注册的对应钩子函数;
    • 通用IO接口 对应于 sockLib 库在安装IO设备驱动时注册的 socketClose/socketRead/socketWrite/socketIoctl() 接口,这些接口在进行简单的参数检查后直接调用 ipcom/ipnet 注册的对应钩子函数;

3. ipnet/ipcom 位于 components/ip_net2-6.6 ,使用sockLibAdd()将AF_NET/AF_PACKET等协议栈及包含 socket/bind/connect/listen/accept/getsockopt/setsockopt/recv/recvfrom/recvmsg/send/sendmsg/sendto() 等钩子的功能列表注册到 sockLib 的sockLibMap[];其中:

    • ipcom 提供OS封装层,用于屏蔽OS的不同,并绑定到MUX层,主要代码位于 components/ip_net2-6.6、ipcom/port/vxworks
    • ipnet/ipcom 调用 muxLib 提供的 muxDevStart/muxDevStop/muxIoctl/muxSend/muxDevLoad/muxDevUnload/muxBind/muxUnbind() 接口来完成协议栈绑定、、驱动加载、网口控制和数据收发功能;

4. muxLib 位于 vxworks-6.6/target/src/wrn/coreip/common/mux ,用于将协议栈绑定到不同的网口上,并提供网卡控制接口,包括:

    • muxDevStart/muxDevStop/muxIoctl接口 :主要通过调用 endLib 封装的网口驱动功能列表中相应的 start/stop/ioctl 钩子来完成;
    • muxSend接口 :首先通过 endLib 封装的网口驱动功能列表中的 formAddress 钩子生成地址,然后调用 endLib 封装的网口驱动功能列表中的 packetDataGet 钩子和 muxBind 接口安装的 stackRcvRtn 来过滤本地数据包,最后调用 endLib 封装的网口驱动功能列表中的 send/formAddress/packetDataGet 钩子来完成发送功能;
    • muxReceive接口 :通过 muxBind 接口安装的 stackRcvRtn 将数据上传到 ipnet/ipcom
    • muxDevLoad接口 :调用驱动提供的 xxxEndLoad 接口加载网口驱动,然后调用 endLib 提供的 endFlagsSet 设置END_MIB_2233标志( m5200FecEnd不支持2233 MIB ),并使用ioctl判断end类型以设置 pEnd->receiveRtn muxReceive m5200FecEnd类型为END_STYLE_END );

5. end 层用于提供网卡驱动的封装结构和公用代码。

2. 网卡驱动全工作流程

2.1 初始化流程

网卡驱动初始化入口为usrNetworkInit():

  1. usrNetworkInit :该位于 <工程目录>/prjConfig.c 中,调用 usrNetEndLibInit() ,用于初始化网卡驱动;
  2. usrNetEndLibInit :该接口位于 vxworks-6.6/target/src/config/usrNetwork.c vxworks-6.6/target/config/comps/src/net/coreip/usrNetEndLib.c 中,关键流程如下所示:
Snipaste_2022-08-13_11-55-29.png


其中:

    • vxbDevMethodRun() 遍历VxBus驱动,调用所有提供 muxDevConnect() 接口的网卡驱动, 不适用 于lite5200b的Legacy网卡驱动;
    • endDevTbl[] 数组包含Legacy网卡驱动,定义于BSP目录的configNet.h中:
#define FEC_LOAD_FUNC	m5200FecEndLoad
#define FEC_LOAD_STR "-1:0x0:-1:-1:0x40:0x30:0x0:0xff:2:0x4:" \
        FEC_CLOCK_SPEED(IPB_CLOCK_LITERAL)
#define FEC_BUFF_LOAN	1
END_TBL_ENTRY endDevTbl [] =