簡體   English   中英

IP_PKTINFO套接字選項無效

[英]IP_PKTINFO socket option not working

我已經在這個問題上敲了幾個星期,現在我終於屈服於這樣一個事實:我無法弄清楚這一點。 我也一直在我的團隊中與網絡工程師一起工作無濟於事。 我的問題如下:

我正在開發一個應用程序,它可以在多個vlan上進行非常簡單的UDP組連接(每個vlan都作為自己的虛擬接口公開,在這種情況下,如果相關,則NIC是SolarFlare)。 所有這些連接都發生在單個套接字上(根據有效負載序列號對消息進行重復數據刪除)。 在執行IP_ADD_MEMBERSHIP之前,我正在設置這樣的套接字選項:

setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &yes, sizeof yes)
setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &yes, sizeof(yes))
setsockopt(sock, IPPROTO_IP, PACKET_AUXDATA, &yes, sizeof(yes))

我需要通過IP_PKTINFO獲取接口索引或通過PACKET_AUXDATA獲取vlan id,以便收集下游的統計信息。 現在,一切都初始化沒有錯誤,我能夠毫無問題地處理UDP有效負載。 我遇到麻煩的地方是當我嘗試訪問上面請求的輔助/控制消息時,如簡單的調試日志所示:

for (cmsgptr = CMSG_FIRSTHDR(&msg);
    cmsgptr != NULL;
    cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
    printf("Control Message: cmsg_level: %d, cmsg_type %d\n", cmsgptr->cmsg_level, cmsgptr->cmsg_type);
}

對於收到的每個數據包,這只輸出:

Control Message: cmsg_level: 1, cmsg_type 29

作為參考,SOL_SOCKET = 1且SO_TIMESTAMP = 29。 因此,雖然我正在請求3種不同的控制消息類型,但只填充了時間戳。 此行為與我是在單個接口上加入單個UDP組還是在多個接口上加入多個組無關。

一種解決方案是重寫應用程序以將每個接口放在其自己的套接字上,然后將所有內容匯集到隊列中,但根據我的經驗,上下文切換會破壞應用程序的性能。 根據手冊頁ip(7),自Linux內核2.2以來,IP_PKTINFO已經可用。 我正在運行Ubuntu 14.04.4,它使用內核3.13.0-24-generic。

任何幫助,見解或方向將不勝感激!

在黑暗的猜測中拍攝

1)每次成功調用setsockopt后,需要將yes重置為1。 文檔暗示這不是必需的,但這就是我要做的。

int yes = 1;
setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &yes, sizeof(yes));

yes = 1;
setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &yes, sizeof(yes));

yes = 1;
setsockopt(sock, IPPROTO_IP, PACKET_AUXDATA, &yes, sizeof(yes));

2)您是否檢查setsockopt的返回值以查看這些調用是否正確成功。 目前尚不清楚你是否已經驗證他們返回“0”表示成功,或者“-1”表示錯誤。 您應該打印每個呼叫的返回碼。

3)您沒有顯示您的recvmsg代碼,這是您可能用於獲取額外信息的代碼。 但是struct msghdr可能沒有正確初始化。 具體來說,你的緩沖區是否足以獲得所有控制數據? 以下是我在代碼中的操作方法:

struct iovec vec;
ssize_t ret;

const size_t CONTROL_DATA_SIZE = 1000;  // THIS NEEDS TO BE BIG ENOUGH.
char controldata[CONTROL_DATA_SIZE]; 
struct msghdr hdr = {};
sockaddr_storage addrRemote = {};

vec.iov_base = buf;
vec.iov_len = len;

hdr.msg_name = &addrRemote;
hdr.msg_namelen = sizeof(addrRemote);
hdr.msg_iov = &vec;
hdr.msg_iovlen = 1;
hdr.msg_control = controldata;
hdr.msg_controllen = CONTROL_DATA_SIZE;

ret = ::recvmsg(sockfd, &hdr, flags);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM