У нас есть симуляция, в которой процессор ввода-вывода отправляет данные подсистемам, используя многоадресные сообщения IPv6. Однако у нас есть сценарии, в которых мы хотим, чтобы подсистемы были смоделированы на том же хосте, что и процессор ввода-вывода. Когда мы пытаемся это сделать, отправка завершается с ошибкой «Сеть недоступна».
Мы используем SUSE Linux Enterprise Server 12 SP3 с ядром 4.4.73-5 по умолчанию.
Мы можем отправлять сообщения, если используем многоадресную рассылку IPv4. Нам пришлось добавить маршрут для адресов многоадресной рассылки:
sudo ip route add 224.0.0.0/7 dev lo
Я попытался добавить соответствующий маршрут для IPv6:
sudo ip -6 route add ff00 :: / 8 dev lo
но это не работает. Когда я пытаюсь показать маршрут, он также говорит, что сеть недоступна (и имеет -1 для метрики)
ip -6 route show table all
имеет это среди своих выходных
недостижимое значение по умолчанию dev lo Proto метрика ядра 4294967295 ошибка -101 pref medium
Для интерфейса установлен флаг многоадресной рассылки:
ip -6 link show dev lo
производит
1: lo: mtu 65536 Состояние qdisc noqueue Режим НЕИЗВЕСТНЫЙ Группа ПО УМОЛЧАНИЮ по умолчанию qlen 1
link / loopbask 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;
}
Если я изменю имя if в отправителе и получателе на другой интерфейс, такой как eth8, отправитель отправляет штраф, а получатель получает и печатает сообщение.
Однако, если в качестве интерфейса используется lo, отправитель печатает эту ошибку:
исходящий интерфейс: 1
отправить не удалось, errno = 101
, что переводится как «Сеть недоступна».
Я могу отправлять данные на другие интерфейсы (кроме lo), если я использую префикс ff11 (интерфейс локальный) вместо ff15 (сайт локальный) в dest_addr_str. Это может быть то, что мы должны сделать. Но мы надеялись, что при использовании интерфейса обратной связи нам не придется менять адреса многоадресной рассылки. Изменение этих средств означает, что мы должны поддерживать две базы данных сообщений.
Спасибо за любую помощь.