背景
工作中遇到客戶反饋,上層應用UDP固定間隔100ms發包,但本地tcpdump抓包存在波動,有的資料包之間間隔107ms甚至更多,以此重新梳理了下udp的傳送流程。
udp發包流程
udp_sendmsg
UDP corking 是一項最佳化技術,允許核心將多次資料累積成單個資料包傳送。在使用者程式中有兩種方法可以啟用此選項:
使用 setsockopt 系統呼叫設定 socket 的 UDP_CORK 選項
程式呼叫 send,sendto 或 sendmsg 時,帶 MSG_MORE 引數
如果沒設定UDP_CORK,直接傳送到ip層,根據客戶只是偶爾出現時延過高的情況,可以確定UDP_CORK並沒有被設定,udp這裡應該是直接下發的,udp_send_skb之後直接到ip層,排除udp_sendmsg導致時延波動問題
int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
{
... ...
/* Lockless fast path for the non-corking case. */
if (!corkreq) {
struct inet_cork cork;
skb = ip_make_skb(sk, fl4, getfrag, msg, ulen,
sizeof(struct udphdr), &ipc, &rt,
&cork, msg->msg_flags);
err = PTR_ERR(skb);
if (!IS_ERR_OR_NULL(skb))
err = udp_send_skb(skb, fl4, &cork);
goto out;
}
... ...
}
qdisc發包流程
當配額quota < 0 || need_resched時將觸發軟中斷,否則將直接進行發包。
quota 對應 net.core.dev_weight,可透過sysctl進行更改。
網路卡及驅動
如果網路卡慢,會導致網路卡佇列滿返回BUSY,資料包重新入隊,tcpdump將抓到重複的資料包。客戶並未反饋該現象,排除網路卡及網路卡驅動。
總結
未配置UDP_CORK的情況下,上層udp應用send呼叫包含兩個路徑,一個是send直接到網路卡驅動進行傳送,另一個是send到網路裝置子系統__dev_queue_skb,然後由軟中斷呼叫繼續傳送。
決定直接發還是由軟中斷髮的條件是,net.core.dev_weight和 need_resched(需要強制排程),可以透過sysctl -a | grep weight檢視其預設值。
對於__qdisc_run來講,dev_weight代表迴圈次數,可嘗試適當增大這個值,但可能會導致上層應用傳送時延增加。
sysctl net.core.dev_weight=4096
need_resched則與中斷\異常相關。
時延大的問題可能是軟中斷排程問題。