Qdiscs配置TSN网络

1  MQPRIO

 

MQPRIO qdisc 是一个简单的队列规则,可以通过优先级以及优先级对应的流量等级,将不同流量映射到硬件队列的区间。连续的流量等级可以1对1的映射到硬件的队列上。

使用方法如下:

tc qdisc ... dev dev ( parent classid | root) [ handle major: ] mqprio [ num_tc tcs ] [ map P0 P1 P2...  ] [ queues count1@offset1 count2@offset2 ...  ] [ hw 1|0 ] [ mode dcb|channel] ] [ shaper dcb| [ bw_rlimit min_rate min_rate1 min_rate2 ...  max_rate max_rate1 max_rate2 ...  ]]

num_tc:使用的流量等级,最大支持16个等级

map: 将VLAN优先级 (VLAN PRI) 0 -15映射到特定的流量等级

queues: 为每个流量等级提供队列的数量和范围。每个流量等级的队列范围不能重叠且必须连续

hw: 设置为1支持硬件卸载,设置为0配置为仅在软件使用用户指定的值

举个例子:(来源open62541 pub/sub TSN)

sudo tc qdisc add dev <I210 interface> parent root mqprio num_tc 3 map 2 2 1 0 2 2 2 2 2 2 2 2 2 2 2 2 queues 1@0 1@1 2@2 hw 0

[num_tc 3] 定义3个流量等级

[map 2 2 1 0 2 2 2 2 2 2 2 2 2 2 2 2]

PRI

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

TC

2

2

1

0

2

2

2

2

2

2

2

2

2

2

2

2

如果VLAN PRI=3 就映射到了TC=0

[queues 1@0 1@1 2@2]

i210网卡有4个收发队列 1..4

TC=0:队列1

TC=1:队列 2

TC=2:队列3和队列4

2. ETF

The ETF (Earliest TxTime First) qdisc 允许应用控制数据包从流量控制层到网络设备层的时刻。如果网络接口支持并且配置了offload,ETF也会控制数据包离开网络控制器(就是控制数据包从网卡发出的时刻)

ETF会在发送时间(txtime)到达之前的一段时间(delta) 缓存数据包,这个时间可以由delta选项控制

ETF需要安装在其他的qdisc下,例如mqprio

ETF依赖于SO_TXTIME socket选项和 SCM_TXTIME CMSG在每一个数据包的control message。具体的做法可以参考Open62541中的ua_pubsub_ethernet.c代码中959行的sendWithTxTime函数

static UA_StatusCode
sendWithTxTime(UA_PubSubChannel *channel, UA_ExtensionObject *transportSettings, void *bufSend, size_t lenBuf) {
    /* Send the data packet with the tx time */
    char dataPacket[CMSG_SPACE(sizeof(UA_UInt64))] = {0};
    /* Structure for messages sent and received */
    struct msghdr message;
    /* Structure for scattering or gathering of input/output */
    struct iovec  inputOutputVec;
    ssize_t       msgCount;

    UA_PubSubChannelDataEthernet *channelDataEthernet =
        (UA_PubSubChannelDataEthernet *) channel->handle;

    /* Structure for socket internet address */
    struct sockaddr_ll socketAddress = { 0 };

    socketAddress.sll_family   = AF_PACKET;
    socketAddress.sll_ifindex  = channelDataEthernet->ifindex;
    socketAddress.sll_protocol = htons(ETHERTYPE_UADP);

    inputOutputVec.iov_base   = bufSend;
    inputOutputVec.iov_len    = lenBuf;

    memset(&message, 0, sizeof(message));
    /* Provide message name / optional address */
    message.msg_name          = &socketAddress;
    /* Provide message address size in bytes */
    message.msg_namelen       = sizeof(socketAddress);
    /* Provide array of input/output buffers */
    message.msg_iov           = &inputOutputVec;
    /* Provide the number of elements in the array */
    message.msg_iovlen        = 1;

    /* Get ethernet ETF transport settings */
    UA_EthernetWriterGroupTransportDataType *ethernettransportSettings;
    ethernettransportSettings = (UA_EthernetWriterGroupTransportDataType *)transportSettings->content.decoded.data;

    /*
     * We specify the transmission time in the CMSG.
     */
    /* Provide the necessary data */
    message.msg_control    = dataPacket;
    /* Provide the size of necessary bytes */
    message.msg_controllen = sizeof(dataPacket);
    /* Structure for storing the necessary data */
    struct cmsghdr*       controlMsg;
    /* Control message created for tx time */
    controlMsg             = CMSG_FIRSTHDR(&message);
    controlMsg->cmsg_level = SOL_SOCKET;
    controlMsg->cmsg_type  = SCM_TXTIME;
    controlMsg->cmsg_len   = CMSG_LEN(sizeof(UA_UInt64));
    if(ethernettransportSettings && (ethernettransportSettings->transmission_time != 0))
        *((UA_UInt64 *) CMSG_DATA(controlMsg)) = ethernettransportSettings->transmission_time;

    msgCount = sendmsg(channel->sockfd, &message, 0);
    if ((msgCount < 1) && (msgCount != (UA_Int32)lenBuf)) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    return UA_STATUSCODE_GOOD;
}

举个例子:一个带txtime的数据包如果发给ETF,ETF会缓存这个数据包直到 (txtime-delta) , 然后将数据包丢给网络设备。在(txtime-delta)到达之前,ETF会丢掉任何数据包,因此保证最先到达的TxTime出队

使用方法如下:

tc qdisc ... dev dev parent classid [ handle major: ] etf clockid clockid [ delta delta_nsecs ] [ deadline_mode ] [ offload ]

clockid:指定qdisc使用的内部时钟, 用于测量时间和调度时间

delta:在入队或出队一个数据包之后,qdisc会根据下次的txtime - delta调度下一次的唤醒时间。这个参数一般作为系统调度延时的经验值。

offload:当offload 被设置,etf 会试着将网络接口配置为基于事件的发送仲裁(需要硬件支持)。这个特征经常被称作"Launch Time" or "Time-Based Scheduling"

举个例子:(来源open62541 pub/sub TSN)

sudo tc qdisc add dev eno1 parent $MQPRIO_NUM:1 etf offload clockid CLOCK_TAI delta 150000

[$MQPRIO_NUM:1]   配置队列1为ETF(对应TC=0)

[clockid CLOCK_TAI]  参考时钟:CLOCK_TAI,

[offload] 使能"Launch Time"

[delta 150000] 在下次txtime 之前150us调度数据包

 

3. ETS

IEEE 802.1Qbv/D2.2 Enhancements for Scheduled Traffic (EST), 早期被称作Time Aware Shaper (TAS), 是对802.1Q中定义传输选择算法的增强,已经正式作为802.1Q-2018中的一部分。由于工业控制大部分需要保证周期数据的的确定性,因此该协议对于TSN在工业控制中的应用比较重要。

ETS基于预先设定的周期性门控制列表,动态地为出口队列提供开/关控制的机制。ETS定义了一个时间窗口,是一个时间触发型网络(Time-trigged)。这个窗口在这个机制中是被预先确定的。这个门控制列表被周期性的扫描,并按预先定义的次序为不同的队列开放传输端口。如下图所示:出口硬件有8个队列,每个都有唯一的传输选择算法。传输由门控制列表(gate control list, GCL)控制。对于给定队列门控制有两个状态 :打开和关闭

In Linux, EST/TAS 可以通过配置 taprio 实现. Time Aware Priority Shaper (TAPRIO), qdisc 实现IEEE 802.1Q-2018 Section 8.6.9的简单版本,可以配置一系列门控状态,每个门控状态关联到不同的流量等级(TC

TAPRIO的配置指令如下:

tc qdisc ... dev dev parent classid [ handle major: ] taprio

       num_tc tcs

               map P0 P1 P2 ...  queues count1@offset1 count2@offset2

       ...

               base-time base-time clockid clockid

               sched-entry <command 1> <gate mask 1> <interval 1>

               sched-entry <command 2> <gate mask 2> <interval 2>

               sched-entry <command 3> <gate mask 3> <interval 3>

               sched-entry <command N> <gate mask N> <interval N>

num_tc:使用的流量等级,最大支持16个等级

map: 将优先级 (VLAN PRI) 0 -15映射到特定的流量等级

queues: 为每个流量等级提供队列的数量和范围。每个流量等级的队列范围不能重叠且必须连续

base-time

指定调度的起始时刻,单位是纳秒,参考时钟由clockid指定。如果'base-time'是过去的时间,那么调度开始时间为base-time + (N * cycle-time),其中N比现在时刻大的最小整数。"cycle-time" 所有调度项目的时间总和,也就是调度周期

一般默认设置为0(因为时钟是同步的,所以在所有设备上设置一个相同的值即可)

clockid:指定qdisc参考的内部时钟

sched-entry:

门控制的调度项目,sched-entry <command> <gatemask> <interval>

<command> 只支持"S"

<gate mask>  每一位( bit)对应流量等级的开关状态(例如:bit 0 代表流量等级0/TC0)0  表示关闭,1表示打开

<interval>标志当前门控状态持续的时间

flags:

0x01:  txtime支持模式,qdisc通过发送时间戳判断数据包的发送周期

0x02:  full-offload模式, GCL直接传递给网卡,并且交给网卡执行,在这个模式下不需要设置clockid,默认网卡参考的时钟是/dev/ptpN (N 可以通过如下指令获取 ethtool -T eth0 | grep 'PTP Hardware Clock' ) (如果设备仅作为bridge,只需要通过ptp4l同步/dev/ptpN即可,并不需要phc2sys将/dev/ptpN同步到系统时钟) 

举例来说:(TI AM64X)

#Setup interface and queue configuration
       ip link set dev eth0 down
       ethtool -L eth0 tx 3

#disable rrobin
ethtool --set-priv-flags eth0 p0-rx-ptype-rrobin off

#bring up eth0 interface
ip link set dev eth0 up
#Setup EST schedule with 3 Gates (Q0-Q2). For description of Command parameters, see manual page for taprio.
#TC0 <-> Q0, TC1 <-> Q1, and TC2 <-> Q2
tc qdisc replace dev eth0 parent root handle 100 taprio \
   num_tc 3 \
   map 0 0 1 2 0 0 0 0 0 0 0 0 0 0 0 0 \
   queues 1@0 1@1 1@2 \
   base-time 0000 \
   sched-entry S 4 125000 \
   sched-entry S 2 125000 \
   sched-entry S 1 250000 \
   flags 2

首先设置网卡3个发送队列: ethtool -L eth0 tx 3

定义3个流量等级TC:    num_tc 3

将流量等级映射到VLAN优先级:

PRI

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

TC

0

0

1

2

0

0

0

0

0

0

0

0

0

0

0

0

映射流量等级到硬件队列 TC0 <-> 队列1, TC1 <-> 队列2, and TC2 <-> 队列3 :

queues 1@0 1@1 1@2

这样 PRI=2的数据包会通过队列2发送,这样 PRI=3的数据包会通过队列3发送

每个调度周期,首先打开TC2(bit = 2,b100)对应的队列125000纳秒;再打开TC1 (bit = 1,b010)对应的队列125000纳秒, 再打开TC0 (bit = 0,b001)对应的队列250000纳秒

网卡硬件offload: flags 2 (因此不需要clockid)

这样实现的时许如下图所示:

  • 5
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值