我无法为IPv6/ICMPv6数据包设置"do not fragment"标志.我正在做PMTUD,我想强制路由器丢弃比MTU更大的数据包.使用setsockopt和IPV6_MTU_DISCOVER不起作用.
int on = IPV6_PMTUDISC_DO; // tried also IPV6_PMTUDISC_PROBE
setsockopt(socket, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &on, sizeof(on));
Run Code Online (Sandbox Code Playgroud)
结果:

我也不能IPV6_DONTFRAG像Unix-Linux Addison-Wesley-Stevens2003-Unix网络编程中所描述的那样使用setosckopt,因为我有netinet/in6.h包含的头文件并IPV6_DONTFRAG在其中定义linux/in6.h.包含linux/in6.h在我的源代码中会导致这些重定义错误.
In file included from mypmtud.cc:30:0: /usr/include/linux/in6.h:30:8: error: redefinition of ‘struct in6_addr’ In file included from /usr/include/netdb.h:28:0,
from mypmtud.cc:23: /usr/include/netinet/in.h:198:8: error: previous definition of ‘struct in6_addr’ In file included from mypmtud.cc:30:0: /usr/include/linux/in6.h:46:8: error: redefinition of ‘struct sockaddr_in6’ In file included from /usr/include/netdb.h:28:0,
from mypmtud.cc:23: /usr/include/netinet/in.h:239:8: error: previous definition of ‘struct sockaddr_in6’ In file included from mypmtud.cc:30:0: /usr/include/linux/in6.h:54:8: error: redefinition of ‘struct ipv6_mreq’ In file included from /usr/include/netdb.h:28:0,
from mypmtud.cc:23: /usr/include/netinet/in.h:275:8: error: previous definition of ‘struct ipv6_mreq’ make: *** [mypmtud] Error 1
Run Code Online (Sandbox Code Playgroud)
环境:VirtualBox 4.26上的Ubuntu 12.10和虚拟网络的GNS3.虚拟Cisco C3660路由器只有基本配置:ip,ipv6地址,无关闭和设置mtu.
编辑: 我需要IPv6堆栈/操作系统内核丢弃大于链接MTU的数据包或发信号通知"此数据包需要碎片化".我怎样才能实现这种行为?
我试图setsockopt用IPV6_DONTFRAG(在我的代码定义了它#define IPV6_DONTFRAG 62),setsockopt用IPV6_MTU_DISCOVER,int on = IPV6_PMTUDISC_DO并setsockopt用IPV6_RECVPATHMTU.
但我没有得到PACKET TOO BIG答复或ancillary data与cmsg_level == IPPROTO_IPV6和cmsg_type == IPV6_PATHMTU.
我的部分代码:
/** sending ICMP packet*/
if (((length = sendto(mysocket, packet, lengthBuff, 0, result->ai_addr, result->ai_addrlen)) < 0) && (errno == EMSGSIZE)){
// works for IPv4, doesn't work with IPv6
cout << "changing maxBuff and lengthBuff size" << endl;
maxBuff = lengthBuff;
lengthBuff = (minBuff + maxBuff) / 2;
if (packet) {
delete(packet);
packet = NULL;
}
} else if (length < 0){
cerr << "Error: sending data." << endl;
freeaddrinfo(result);
close(mysocket);
if (packet) {
delete(packet);
packet = NULL;
}
exit(1);
} else if(((recvmsg(mysocket, &msg, 0)) != -1) && (errno != EINTR)) {
// reading ancillary dada as described in *Unix-Linux Addison-Wesley - Stevens2003 - Unix Network Programming, page 736*
cmsgh = CMSG_FIRSTHDR(&msg);
if(cmsgh != NULL) {
cout << "getting msg " << endl;
cout << "msg len " << msg.msg_controllen << endl;
if(cmsgh->cmsg_level == IPPROTO_ICMPV6 && cmsgh->cmsg_type == IPV6_PATHMTU)
{
cout << "CMSGHEADER - GOOD" << endl;
//mtustruct = CMSG_DATA(&msg);
maxBuff = lengthBuff;
lengthBuff = (minBuff + maxBuff) / 2;
if (packet) {
delete(packet);
packet = NULL;
}
}
else{
cout << "different ancillary data. " << endl;
cout << " level " << cmsgh->cmsg_level << " type " << cmsgh->cmsg_type << endl;
}
}
} else {
cout << "no ERROR with sendto and no RESCVMSG" << endl;
}
/** receiving ICMP data */
tv.tv_sec = 3;
tv.tv_usec = 0;
int retval; // select
FD_ZERO(&mySet);
FD_SET(mysocket, &mySet);
retval = select(mysocket + 1, &mySet, NULL, NULL, &tv);
if (retval == -1) {
cerr << "select failed" << endl;
//break;
exit(1);
} else if (retval) {
if ((length = recvfrom(mysocket, buffer, MAX, 0, result->ai_addr, &(result->ai_addrlen))) == -1) {
cerr << "Error: receiving data." << endl;
} else {
icmpRec = (struct icmp6_hdr*) buffer;
if((icmpRec->icmp6_type == ICMP6_PACKET_TOO_BIG)) {
cout << "next hop MTU: " << ntohl(icmpRec->icmp6_mtu) << endl;
maxBuff = ntohl(icmpRec->icmp6_mtu);
} else if ((icmpRec->icmp6_type == ICMP6_ECHO_REPLY) && (ntohs(icmpRec->icmp6_id) == pid) && (ntohs(icmpRec->icmp6_seq) == (seq - 1))) {
cout << "code " << ntohs(icmpRec->icmp6_code) << endl;
cout << "ICMP ECHO REPLY" << endl;
minBuff = lengthBuff;
}
}
}
Run Code Online (Sandbox Code Playgroud)
EDIT2:
我意识到,setsockopt以确定IPV6_DONTFRAG是不是为我工作,但setsockopt与IPV6_MTU_DISCOVER正在为自己的界面.eth1接口MTU为1500(默认),如果sendto要发送更大的数据包,errno则设置为EMSGSIZE.也有一段时间后,我得到PACKET TOO BIG消息,这些不是自己的内核/操作系统发送消息.
我真正的问题是,我没有PACKET TOO BIG从运行在GNS3上的虚拟路由器(Cisco c3660)获得(在VirtualBox 4.2.6上运行Ubuntu 12.10)消息.
我想强制路由器丢弃比MTU更大的数据包
在IPv6中,总是会丢弃大于MTU的数据包.与IPv4不同,IPv6路由器不会对数据包进行分段.相反,源预计将执行PMTU和:
Linux确实完全支持IPV6_DONTFRAG(我认为它是在2.6.35中添加的),尽管它只影响本地行为.