UDP-Lite 協議 (RFC 3828)

UDP-Lite 是一種標準跟蹤 IETF 傳輸協議,其特點是可變長度的校驗和。 這對於透過無線網路傳輸多媒體(影片,VoIP)具有優勢,因為部分損壞的資料包仍然可以饋送到編解碼器中,而不會因校驗和測試失敗而被丟棄。

此檔案簡要描述了現有的核心支援和套接字 API。 有關深入資訊,您可以參考

1. 應用

一些應用程式已成功移植到 UDP-Lite。 Ethereal(現在稱為 wireshark)預設情況下支援 UDP-Litev4/v6。

將應用程式移植到 UDP-Lite 非常簡單:只需更改套接字級別和 IPPROTO;傳送方還需要設定校驗和覆蓋長度(預設值 = 標頭長度 = 8)。 詳細資訊在下一節中。

2. 程式設計 API

UDP-Lite 提供了一種無連線、不可靠的資料報服務,因此使用與 UDP 相同的套接字型別。 事實上,從 UDP 移植到 UDP-Lite 非常容易:只需新增 IPPROTO_UDPLITE 作為 socket(2) 呼叫的最後一個引數,以便語句看起來像

s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDPLITE);

或者,分別為

s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDPLITE);

只需進行上述更改,您就可以執行 UDP-Lite 服務或連線到 UDP-Lite 伺服器。 核心將假定您對使用部分校驗和覆蓋不感興趣,因此會模擬 UDP 模式(完全覆蓋)。

要利用部分校驗和覆蓋工具,需要設定一個套接字選項,該選項採用一個整數來指定覆蓋長度

  • 傳送方校驗和覆蓋:UDPLITE_SEND_CSCOV

    例如

    int val = 20;
    setsockopt(s, SOL_UDPLITE, UDPLITE_SEND_CSCOV, &val, sizeof(int));
    

    將校驗和覆蓋長度設定為 20 位元組(12b 資料 + 8b 標頭)。 每個資料包只有前 20 個位元組(加上偽標頭)將被校驗和。 這對於具有 12 位元組基本標頭的 RTP 應用程式很有用。

  • 接收方校驗和覆蓋:UDPLITE_RECV_CSCOV

    此選項是接收方類似的選項。 它是真正可選的,即不需要啟用具有部分校驗和覆蓋的流量。 它的功能是作為流量過濾器:啟用後,它指示核心丟棄所有覆蓋範圍_小於_此值的資料包。 例如,如果要保護 RTP 和 UDP 標頭,則接收方可以強制僅允許最小覆蓋範圍為 20 的資料包

    int min = 20;
    setsockopt(s, SOL_UDPLITE, UDPLITE_RECV_CSCOV, &min, sizeof(int));
    

對 getsockopt(2) 的呼叫是類似的。 作為一種擴充套件而不是獨立的協議,所有從 UDP 已知的套接字選項都可以與以前完全相同的方式使用,例如 UDP_CORK 或 UDP_ENCAP。

UDP-Lite 校驗和覆蓋選項的詳細討論在第 IV 節中。

3. 標頭檔案

套接字 API 需要透過 /usr/include 中的標頭檔案提供支援

  • /usr/include/netinet/in.h 定義 IPPROTO_UDPLITE

  • /usr/include/netinet/udplite.h 用於 UDP-Lite 標頭欄位和協議常量

出於測試目的,以下內容可以用作 mini 標頭檔案

#define IPPROTO_UDPLITE       136
#define SOL_UDPLITE           136
#define UDPLITE_SEND_CSCOV     10
#define UDPLITE_RECV_CSCOV     11

適用於各種發行版的現成標頭檔案位於 UDP-Lite tarball 中。

4. 核心關於各種套接字選項的行為

要啟用除錯訊息,需要將日誌級別設定為 8,因為大多數訊息都使用 KERN_DEBUG 級別 (7)。

  1. 傳送方套接字選項

如果傳送方指定值 0 作為覆蓋長度,則模組假定完全覆蓋,傳輸覆蓋長度為 0 且校驗和正確的資料包。 如果傳送方指定的覆蓋範圍 < 8 且與 0 不同,則核心假定 8 作為預設值。 最後,如果指定的覆蓋長度超過資料包長度,則使用資料包長度代替覆蓋長度。

  1. 接收方套接字選項

接收方指定它願意接受的覆蓋長度的最小值。 此處的值 0 表示接收方始終希望覆蓋整個資料包。 在這種情況下,所有部分覆蓋的資料包都將被丟棄並記錄錯誤。

無法指定非法值 (<0 和 <8);在這些情況下,假定預設值為 8。

所有覆蓋值小於指定閾值的資料包都將被丟棄,這些事件也會被記錄。

  1. 停用校驗和計算

在傳送方和接收方,始終會執行校驗和,並且無法使用 SO_NO_CHECK 停用。 因此

setsockopt(sockfd, SOL_SOCKET, SO_NO_CHECK,  ... );

將始終被忽略,而

getsockopt(sockfd, SOL_SOCKET, SO_NO_CHECK, &value, ...);

的值沒有意義(如 TCP 中)。 校驗和欄位為零的資料包是非法的(參見 RFC 3828,第 3.1 節),並且將被靜默丟棄。

  1. 分片

校驗和計算遵循緩衝區大小和 MTU。 UDP-Lite 資料包的大小由傳送緩衝區的大小決定。 傳送緩衝區的最小大小為 2048(在 include/net/sock.h 中定義為 SOCK_MIN_SNDBUF),預設值可配置為 net.core.wmem_default 或透過設定 SO_SNDBUF socket(7) 選項。 傳送緩衝區的最大上限由 net.core.wmem_max 決定。

給定一個大於傳送緩衝區大小的有效負載大小,UDP-Lite 將有效負載分成幾個單獨的資料包,在每種情況下都填充發送緩衝區大小。

精確的值還取決於介面 MTU。 介面 MTU 反過來可能會觸發 IP 分片。 在這種情況下,生成的 UDP-Lite 資料包被分成幾個 IP 資料包,其中只有第一個包含 L4 標頭。

傳送緩衝區大小對校驗和覆蓋長度有影響。 考慮以下示例

Payload: 1536 bytes          Send Buffer:     1024 bytes
MTU:     1500 bytes          Coverage Length:  856 bytes

UDP-Lite 將在兩個單獨的資料包中運送 1536 位元組

Packet 1: 1024 payload + 8 byte header + 20 byte IP header = 1052 bytes
Packet 2:  512 payload + 8 byte header + 20 byte IP header =  540 bytes

覆蓋資料包覆蓋第一個資料包中的 UDP-Lite 標頭和 848 位元組的有效負載,第二個資料包完全覆蓋。 請注意,對於第二個資料包,覆蓋長度超過了資料包長度。 在這種情況下,核心始終會將覆蓋長度重新調整為資料包長度。

作為將一個 UDP-Lite 資料包分成幾個小片段時會發生什麼的一個例子,考慮以下示例

Payload: 1024 bytes            Send buffer size: 1024 bytes
MTU:      300 bytes            Coverage length:   575 bytes

+-+-----------+--------------+--------------+--------------+
|8|    272    |      280     |     280      |     280      |
+-+-----------+--------------+--------------+--------------+
            280            560            840           1032
                                    ^
*****checksum coverage*************

UDP-Lite 模組生成一個 1032 位元組的資料包(1024 + 8 位元組標頭)。 根據介面 MTU,這些被分成 4 個 IP 資料包(280 位元組 IP 有效負載 + 20 位元組 IP 標頭)。 核心模組在將片段釋放到 IP 模組之前,對前兩個完整資料包的內容加上最後一個數據包的 15 個位元組求和。

要檢視 IPv6 分片的類似情況,請考慮連結 MTU 為 1280 位元組,寫入緩衝區為 3356 位元組。 如果校驗和覆蓋率小於 1232 位元組(MTU 減去 IPv6/片段標頭長度),則只需要考慮第一個片段。 使用更大的校驗和覆蓋長度時,需要對每個符合條件的片段進行校驗和。 假設我們的校驗和覆蓋率為 3062。3356 位元組的緩衝區將分成以下片段

Fragment 1: 1280 bytes carrying  1232 bytes of UDP-Lite data
Fragment 2: 1280 bytes carrying  1232 bytes of UDP-Lite data
Fragment 3:  948 bytes carrying   900 bytes of UDP-Lite data

前兩個片段必須完全進行校驗和,最後一個片段只有 598 (= 3062 - 2*1232) 位元組進行校驗和。

雖然正確處理這些情況很重要,但它們(令人惱火地)很少見:UDP-Lite 旨在最佳化無線(或通常嘈雜的)鏈路上的多媒體效能,因此可能需要更小的覆蓋長度。

5. UDP-Lite 執行時統計資訊及其含義

異常和錯誤情況以 KERN_DEBUG 級別記錄到 syslog。 有關 UDP-Lite 的即時統計資訊可在 /proc/net/snmp 中找到,並且(使用較新版本的 netstat)可以使用以下命令檢視

netstat -svu

這會顯示 UDP-Lite 統計變數,其含義如下。

InDatagrams

傳遞給使用者的總資料報數。

NoPorts

接收到未知埠的資料包數量。 這些情況是單獨計數的(不作為 InErrors)。

InErrors

錯誤 UDP-Lite 資料包的數量。 錯誤包括

  • 內部套接字佇列接收錯誤

  • 資料包太短(小於 8 個位元組或宣告的覆蓋長度超過接收到的長度)

  • xfrm4_policy_check() 返回錯誤

  • 應用程式指定了比傳入資料包更大的最小覆蓋長度

  • 校驗和覆蓋違反

  • 錯誤的校驗和

OutDatagrams

傳送的資料報總數。

這些統計資料來自 UDP MIB(RFC 2013)。

6. IPtables

有針對 UDP-Lite 的資料包匹配支援以及對 LOG 目標的支援。 如果您將以下行復制並貼上到 /etc/protocols 中

udplite 136     UDP-Lite        # UDP-Lite [RFC 3828]

然後

iptables -A INPUT -p udplite -j LOG

將生成到 syslog 的日誌輸出。 丟棄和拒絕資料包也有效。

7. 維護者地址

UDP-Lite 補丁是在以下地址開發的

University of Aberdeen Electronics Research Group Department of Engineering Fraser Noble Building Aberdeen AB24 3UE; UK

當前的維護者是 Gerrit Renker, <gerrit@erg.abdn.ac.uk>。 初始程式碼由 William Stanislaus, <william@erg.abdn.ac.uk> 開發。