【发布时间】:2020-04-02 23:38:25
【问题描述】:
我正在尝试发送 IPv6 UDP 多播消息。
下面的部分测试代码显示了两个部分,一个用于发送 IPv6 组播消息,另一个用于发送 IPv4 组播消息。
IPv4 代码运行良好。
发送到 IPv6 的代码总是失败,返回 EADDRNOTAVAIL (99) 无法分配请求的地址。
...
if (ipV6Select)
{
// Create IPv6 DGRAM Socket
int sock = socket(AF_INET6, SOCK_DGRAM, 0);
if (sock < 0)
throw OIP::OipException(OIP_SOCK_ACTION_FAILED("Cannot set socket option IPV6 socket, socket function failed with retVal " <<
sock << " (errno=" << strerror(errno) << " (" << errno << ")."));
// Register multicast interface.
int ifIdx{static_cast<int>(if_nametoindex("svlan1_260"))};
std::cout << "Temp:ifIdx=" << ifIdx << std::endl;
std::lock_guard<std::mutex> lockGuard(setSockoptMutex);
retVal = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifIdx, sizeof(ifIdx));
if (retVal < 0)
throw OIP::OipException(OIP_SOCK_ACTION_FAILED("Cannot set socket option IPV6_MULTICAST_IF, setsockopt function failed with retVal " <<
retVal << " (errno=" << strerror(errno) << " (" << errno << ")."));
// Create IPv6 address.
struct sockaddr_in6 sockAddrIpV6{};
sockAddrIpV6.sin6_family = {AF_INET6};
sockAddrIpV6.sin6_port = {htons(2020)};
sockAddrIpV6.sin6_scope_id = {static_cast<uint32_t>(ifIdx)};
inet_pton(AF_INET6, "FF02:0000:0000:0000:0000:0000:0000:00FE", &sockAddrIpV6.sin6_addr);
std::cout << "IPV6 Send: family=" << sockAddrIpV6.sin6_family << ", sin6_port=" << sockAddrIpV6.sin6_port << ", sin6_scope_id=" << sockAddrIpV6.sin6_scope_id
<< ", addr=FF02:0000:0000:0000:0000:0000:0000:00FE" << std::endl;
// Send message to socket.
retVal = sendto(sock,
sendMsgCharBufVect.data(),
sendMsgCharBufVect.size(),
0,
reinterpret_cast<struct sockaddr*>(&sockAddrIpV6),
sizeof(struct sockaddr_in6));
if (retVal < 0)
throw OIP::OipException(OIP_SOCK_ACTION_FAILED("IPV6 Socket send data (socket sendto function) failed with retVal " << retVal <<
" (errno=" << strerror(errno) << " (" << errno << "))."));
}
// Send IPV4 multicast message.
else
{
// Create IPv4 DGRAM Socket
std::string ipV4Str{"239.0.0.254"};
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock < 0)
throw OIP::OipException(OIP_SOCK_ACTION_FAILED("Cannot set socket option IPV4 socket, socket function failed with retVal " <<
sock << " (errno=" << strerror(errno) << " (" << errno << ")."));
// Register multicast interface.
struct ip_mreqn mreqn{};
inet_aton(ipV4Str.c_str(), &mreqn.imr_multiaddr);
mreqn.imr_ifindex = {static_cast<int>(if_nametoindex("svlan1_260"))};
retVal = setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &mreqn, sizeof(mreqn));
if (retVal < 0)
throw OIP::OipException(OIP_SOCK_ACTION_FAILED("Cannot set socket option IP_MULTICAST_IF, setsockopt function failed with retVal " <<
retVal << " (errno=" << strerror(errno) << " (" << errno << ")."));
// Create IPv4 address.
struct sockaddr_in sockAddrIpV4{};
sockAddrIpV4.sin_family = {AF_INET};
sockAddrIpV4.sin_port = {htons(2020)};
inet_aton(ipV4Str.c_str(), &sockAddrIpV4.sin_addr);
std::cout << "IPV4 Send: family=" << sockAddrIpV4.sin_family << ", sin_port=" << sockAddrIpV4.sin_port << ", addr=" << std::hex << sockAddrIpV4.sin_addr.s_addr<< std::dec <<std::endl;
// Send message to socket.
retVal = sendto(sock,
sendMsgCharBufVect.data(),
sendMsgCharBufVect.size(),
0,
reinterpret_cast<struct sockaddr*>(&sockAddrIpV4),
sizeof(struct sockaddr_in));
if (retVal < 0)
throw OIP::OipException(OIP_SOCK_ACTION_FAILED("IPV4 Socket send data (socket sendto function) failed with retVal " << retVal <<
" (errno=" << strerror(errno) << " (" << errno << "))."));
}
...
tcpdump IPv4 显示带有请求地址的传出多播消息:
2020-04-02 23:30:19.384892 00:60:1d:7d:08:07 (oui Unknown) > 01:00:5e:00:00:fe (oui Unknown), ethertype 802.1Q (0x8100), length 90: vlan 260, p 0, ethertype IPv4, (tos 0x0, ttl 1, id 54916, offset 0, flags [none], proto UDP (17), length 72)
100.5.81.1.38790 > 239.0.0.254.2020: UDP, length 44
0x0000: 0100 5e00 00fe 0060 1d7d 0807 8100 0104
0x0010: 0800 4500 0048 d684 0000 0111 3e1c 6405
0x0020: 5101 ef00 00fe 9786 07e4 0034 a54a 4479
用于 IPV6 的 tcpdump 仅显示自动生成的 IPV6 多播消息:
2020-04-02 22:48:19.569203 00:60:1d:7d:08:07 (oui Unknown) > 33:33:00:00:00:16 (oui Unknown), ethertype 802.1Q (0x8100), length 174: vlan 260, p 0, ethertype IPv6, [|ip6]
0x0000: 3333 0000 0016 0060 1d7d 0807 8100 0104
0x0010: 86dd 6000 0000 0074 0001 0000 0000 0000
0x0020: 0000 0000 0000 0000 0000 ff02 0000 0000
2020-04-02 22:48:20.049156 00:60:1d:7d:08:07 (oui Unknown) > 33:33:00:00:00:16 (oui Unknown), ethertype 802.1Q (0x8100), length 174: vlan 260, p 0, ethertype IPv6, [|ip6]
0x0000: 3333 0000 0016 0060 1d7d 0807 8100 0104
0x0010: 86dd 6000 0000 0074 0001 0000 0000 0000
0x0020: 0000 0000 0000 0000 0000 ff02 0000 0000
2020-04-02 22:48:20.329171 00:60:1d:7d:08:07 (oui Unknown) > 33:33:ff:7d:08:07 (oui Unknown), ethertype 802.1Q (0x8100), length 90: vlan 260, p 0, ethertype IPv6, [|ip6]
0x0000: 3333 ff7d 0807 0060 1d7d 0807 8100 0104
0x0010: 86dd 6000 0000 0020 3aff 0000 0000 0000
0x0020: 0000 0000 0000 0000 0000 ff02 0000 0000
root@MEC2-81-1-STDBY:/lib# 2020-04-02 22:48:21.359289 00:60:1d:7d:08:07 (oui Unknown) > 33:33:00:00:00:16 (oui Unknown), ethertype 802.1Q (0x8100), length 134: vlan 260, p 0, ethertype IPv6, [|ip6]
0x0000: 3333 0000 0016 0060 1d7d 0807 8100 0104
0x0010: 86dd 6000 0000 004c 0001 fe80 0000 0000
0x0020: 0000 0260 1dff fe7d 0807 ff02 0000 0000
2020-04-02 22:48:21.389154 00:60:1d:7d:08:07 (oui Unknown) > 33:33:00:00:00:16 (oui Unknown), ethertype 802.1Q (0x8100), length 94: vlan 260, p 0, ethertype IPv6, [|ip6]
0x0000: 3333 0000 0016 0060 1d7d 0807 8100 0104
0x0010: 86dd 6000 0000 0024 0001 fe80 0000 0000
0x0020: 0000 0260 1dff fe7d 0807 ff02 0000 0000
2020-04-02 22:48:22.159152 00:60:1d:7d:08:07 (oui Unknown) > 33:33:00:00:00:16 (oui Unknown), ethertype 802.1Q (0x8100), length 134: vlan 260, p 0, ethertype IPv6, [|ip6]
0x0000: 3333 0000 0016 0060 1d7d 0807 8100 0104
0x0010: 86dd 6000 0000 004c 0001 fe80 0000 0000
0x0020: 0000 0260 1dff fe7d 0807 ff02 0000 0000
2020-04-02 22:48:22.319152 00:60:1d:7d:08:07 (oui Unknown) > 33:33:00:00:00:16 (oui Unknown), ethertype 802.1Q (0x8100), length 94: vlan 260, p 0, ethertype IPv6, [|ip6]
0x0000: 3333 0000 0016 0060 1d7d 0807 8100 0104
0x0010: 86dd 6000 0000 0024 0001 fe80 0000 0000
0x0020: 0000 0260 1dff fe7d 0807 ff02 0000 0000
网络接口: 使用的网络接口是 VLAN ID 为 260 的 VLAN 接口 svlan1_260,在物理网络接口 eth2 上创建。
eth2 Link encap:Ethernet HWaddr 00:00:00:00:81:01
UP BROADCAST RUNNING PROMISC MULTICAST MTU:1513 Metric:1
RX packets:3684437 errors:0 dropped:0 overruns:0 frame:0
TX packets:3410666 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:572562185 (546.0 MiB) TX bytes:109620349 (104.5 MiB)
Interrupt:32
svlan1_260 Link encap:Ethernet HWaddr 00:60:1d:7d:08:07
inet addr:100.5.81.1 Bcast:100.5.255.255 Mask:255.255.0.0
inet6 addr: fe80::260:1dff:fe7d:807/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:709 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:85982 (83.9 KiB)
问题:
有什么想法,IPv6 出了什么问题?
可能是地址错误,虽然我尝试了几个?
是否缺少任何套接字配置?
任何系统设置,没有正确设置?
谢谢
【问题讨论】:
-
如果您不使用永久多播地址(自己制作),则应设置 T 位(
ff12::fe)。您使用的地址属于 IANA 控制的永久 IPv6 多播范围:“动态 IPv6 多播地址可以由分配服务器或终端主机分配。无论分配机制如何,所有动态分配的 IPv6 多播地址必须将 T 位设置为 1。" -
Ron Maupin,感谢您的评论。我将 T 位标志更改为 1(动态分配的多播地址)。不幸的是,同样的失败仍然发生。
标签: linux udp ipv6 sendto multicastsocket