我们有一个模拟,其中I / O处理器使用IPv6多播消息将数据发送到子系统。但是,在某些情况下,我们希望子系统与I / O处理器在同一主机上建模。尝试执行此操作时,发送失败,并显示错误“网络不可达”。
我们正在运行SUSE Linux Enterprise Server 12 SP3,其内核为4.4.73-5-default。
如果我们使用IPv4多播,我们能够发送消息。我们必须为多播地址添加一条路由:
sudo ip route添加224.0.0.0/7 dev lo
我尝试为IPv6添加相应的路由:
sudo ip -6路由添加ff00 :: / 8 dev lo
但是它不起作用。当我尝试显示路由时,它还表示网络不可达(度量标准为-1)
ip -6路由显示表全部
在其输出中具有此
无法访问的默认开发者原型内核指标4294967295错误-101优选介质
为接口设置了多播标志:
ip -6链接显示dev lo
产生
1:lo:mtu 65536 qdisc无队列状态未知模式默认组默认qlen 1 链接/循环bass 00:00:00:00:00:00 00:00:00:00:00:00
这是一个我用来尝试发送数据的简单程序:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <netdb.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int
main(void)
{
int sock;
int status;
const char *dest_addr_str = "ff15::3";
const int port_num = 50000;
const char *ifname = "lo";
unsigned int ifindex;
const char *buffer = "Hello";
size_t msg_len;
ssize_t num_bytes;
struct sockaddr_in6 dest_addr;
sock = socket(AF_INET6, SOCK_DGRAM, 0);
if (sock == -1)
{
printf("Error creating socket, errno = %d\n", errno);
exit(EXIT_FAILURE);
}
/* Setup destinaton address */
memset(&dest_addr, 0, sizeof(struct sockaddr_in6));
dest_addr.sin6_family = AF_INET6;
dest_addr.sin6_port = htons(port_num);
if (inet_pton(AF_INET6, dest_addr_str, &dest_addr.sin6_addr) <= 0)
{
printf("inet_pton error\n, errno = %d", errno);
exit(EXIT_FAILURE);
}
/* Set the outgoing interface */
ifindex = if_nametoindex(ifname);
printf("outgoing interface: %u\n", ifindex);
status = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF,
&ifindex, sizeof(ifindex));
if (status == -1)
{
printf("setting multicast if failed, errno = %d\n", errno);
exit(EXIT_FAILURE);
}
/* Send message */
msg_len = strlen(buffer);
num_bytes = sendto(sock, buffer, msg_len, 0,
(struct sockaddr *) &dest_addr,
sizeof(struct sockaddr_in6));
if (num_bytes == -1)
{
printf("sendto failed, errno = %d\n", errno);
}
else
{
printf("sent %d bytes\n", (int)num_bytes);
}
close(sock);
return 0;
}
这是一个更简单的接收器,在我的测试中它什么也没收到:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define BUF_SIZE 1024
int
main(void)
{
int status;
int sock;
char buf[BUF_SIZE];
const char *grp_addr_str = "ff15::3";
const char *local_addr_str = "::";
const int port_num = 50000;
const char *ifname = "lo";
int flag = 1;
struct sockaddr_in6 addr;
struct sockaddr_in6 peer_addr;
struct ipv6_mreq mreq;
ssize_t num_bytes;
socklen_t len;
const char *p_addr;
char peer_addr_str[INET6_ADDRSTRLEN];
sock = socket(AF_INET6, SOCK_DGRAM, 0);
if (sock == -1)
{
printf("Error creating socket, errno = %d\n", errno);
exit(EXIT_FAILURE);
}
status = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
if (status == -1)
{
printf("Reuse ADDR failed, errno = %d\n", errno);
exit(EXIT_FAILURE);
}
memset(&addr, 0, sizeof(struct sockaddr_in6));
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(port_num);
status = inet_pton(AF_INET6, local_addr_str, &addr.sin6_addr);
if (status == 0)
{
printf("inet_pton failed for local addr, errno = %d\n", errno);
exit(EXIT_FAILURE);
}
status = bind(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in6));
if (status == -1)
{
printf ("Error binding socket, errno = %d\n", errno);
exit(EXIT_FAILURE);
}
status = inet_pton(AF_INET6, grp_addr_str, &mreq.ipv6mr_multiaddr);
if (status == 0)
{
printf("inet_pton failed for multicast addr, errno = %d\n", errno);
exit(EXIT_FAILURE);
}
mreq.ipv6mr_interface = if_nametoindex(ifname);
status = setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
(char *)&mreq, sizeof(mreq));
if (status == -1)
{
printf("Join group failed, errno = %d\n", errno);
exit(EXIT_FAILURE);
}
/* Receive message */
len = sizeof(struct sockaddr_in6);
num_bytes = recvfrom(sock, buf, BUF_SIZE, 0,
(struct sockaddr *) &peer_addr, &len);
if (num_bytes == -1)
{
printf ("recvfrom failed, errno = %d\n", errno);
exit(EXIT_FAILURE);
}
else
{
/* Display address of client that sent the message */
p_addr = inet_ntop(AF_INET6, &peer_addr.sin6_addr, peer_addr_str,
INET6_ADDRSTRLEN);
if (p_addr == 0)
{
printf("Couldn't convert client address to string\n");
}
else
{
printf("Server received %d bytes from (%s, %u, %s)\n",
(int)num_bytes, peer_addr_str,
ntohs(peer_addr.sin6_port), buf);
}
}
return 0;
}
如果我将发送方和接收方中的ifname更改为另一个接口,例如eth8,则发送方发送正常,接收方接收并打印消息。
但是,如果我将lo作为接口,则发件人会显示此错误:
传出接口:1 发送失败,errno = 101
表示“网络不可达”。
如果我在dest_addr_str中使用前缀ff11(本地接口)而不是ff15(本地站点),则能够将数据发送到其他接口(在lo之外)。那可能就是我们要做的。但是我们希望使用环回接口,我们不必更改多播地址。更改这些意味着我们必须维护两个消息数据库。
感谢您的帮助。
答案 0 :(得分:0)
您只是想测试?实际系统不会通过环回发送多播消息。
我建议您改用 dummy 界面:
# ip link add dummy0 type dummy
# ip link set dev dummy0 up
# ip address show dev dummy0
24: dummy0: <BROADCAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
link/ether 86:0a:20:b1:b5:f1 brd ff:ff:ff:ff:ff:ff
inet6 fe80::840a:20ff:feb1:b5f1/64 scope link
valid_lft forever preferred_lft forever
虚拟接口模拟已建立但未连接到任何其他主机的以太网连接。它可以用于使用分配给它的任何IP地址与同一主机上的其他进程进行通信,并且它还应该接受多播流量。