我正在实现DPLPMTUDerrno = EMSGSIZE
,当我发送的 UDP 数据包长于本地接口的 MTU 时,我想抑制 Linux 内核返回 -1 。我想避免在发送多个数据报时(尤其是在使用 时sendmmsg(2)
)处理错误处理的痛苦,每个数据报可能属于不同的连接。我宁愿让内核丢弃数据包,让应用程序 DPLPMTUD 逻辑找出 MTU。
ip(7)
有话要说:
It is possible to implement RFC 4821 MTU probing with SOCK_DGRAM
or SOCK_RAW sockets by setting a value of IP_PMTUDISC_PROBE
(available since Linux 2.6.22). This is also particularly use‐
ful for diagnostic tools such as tracepath(8) that wish to de‐
liberately send probe packets larger than the observed Path MTU.
然而,设置此选项不会产生预期的效果。这是说明问题的代码:
/* emsgsize.c: test whether IP_PMTUDISC_PROBE suppresses EMSGSIZE
*
* Usage: emsgsize packet_size
*/
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#define CHECK(w_, s_) do { if ((s_) < 0) { perror(w_); return 1; }} while (0)
/* Payload */
static unsigned char data[64 * 1024];
int
main (int argc, char **argv)
{
int fd, on, s, size;
struct sockaddr_in si;
ssize_t sent;
if (argc != 2)
{
fprintf(stderr, "usage: emsgsize size\n");
return 1;
}
size = atoi(argv[1]);
memset(&si, 0, sizeof(si));
si.sin_family = AF_INET;
fd = socket(si.sin_family, SOCK_DGRAM, 0);
CHECK("socket", fd);
s = bind(fd, (struct sockaddr *) &si, sizeof(si));
CHECK("bind", s);
/* This is supposed to suppress sendmsg(2) returning -1 with
* errno = EMSGSIZE, see ip(7):
*
" It is possible to implement RFC 4821 MTU probing with SOCK_DGRAM
" or SOCK_RAW sockets by setting a value of IP_PMTUDISC_PROBE
" (available since Linux 2.6.22). This is also particularly use-
" ful for diagnostic tools such as tracepath(8) that wish to de-
" liberately send probe packets larger than the observed Path MTU.
*/
on = IP_PMTUDISC_PROBE;
s = setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &on, sizeof(on));
CHECK("setsockopt", s);
memset(&si, 0, sizeof(si));
si.sin_family = AF_INET;
si.sin_port = htons(12345); /* Destination does not matter */
s = inet_pton(AF_INET, "127.0.0.1", &si.sin_addr);
CHECK("inet_pton", s);
sent = sendto(fd, data, (size_t) size, 0, (struct sockaddr *) &si,
sizeof(si));
CHECK("sendto", sent);
return 0;
}
当我发送大于 MTU 的数据包时,sendto()
上面返回 -1 并errno
设置为EMSGSIZE
-- 正是我想要避免的。
有没有办法做我想做的事?