[simulation] add IPv6 loopback address support (#12828)

This commit adds support for IPv6 loopback address (::1) in the
simulation platform. When the local interface is set to the IPv6
loopback address, it uses the interface-local multicast group
(ff01::116) instead of the link-local group (ff02::116) for
node-to-node communication.

It also ensures that the `sin6_scope_id` is correctly set for the
loopback address in the transmission socket.
This commit is contained in:
Yakun Xu
2026-05-07 22:37:40 +08:00
committed by GitHub
parent 3d731aae2f
commit 87fdaa6946
2 changed files with 25 additions and 9 deletions
+24 -9
View File
@@ -50,6 +50,7 @@
#define UTILS_SOCKET_LOCAL_HOST_ADDR "127.0.0.1" #define UTILS_SOCKET_LOCAL_HOST_ADDR "127.0.0.1"
#define UTILS_SOCKET_GROUP_ADDR "224.0.0.116" #define UTILS_SOCKET_GROUP_ADDR "224.0.0.116"
#define UTILS_SOCKET_GROUP_ADDR6 "ff02::116" #define UTILS_SOCKET_GROUP_ADDR6 "ff02::116"
#define UTILS_SOCKET_GROUP_ADDR6_LO "ff01::116"
const char *gLocalInterface = UTILS_SOCKET_LOCAL_HOST_ADDR; const char *gLocalInterface = UTILS_SOCKET_LOCAL_HOST_ADDR;
@@ -76,7 +77,16 @@ static bool IsAddressLinkLocal(const struct in6_addr *aAddress)
return ((aAddress->s6_addr[0] & 0xff) == 0xfe) && ((aAddress->s6_addr[1] & 0xc0) == 0x80); return ((aAddress->s6_addr[0] & 0xff) == 0xfe) && ((aAddress->s6_addr[1] & 0xc0) == 0x80);
} }
static void InitRxSocket(utilsSocket *aSocket, const struct in_addr *aIp4Address, unsigned int aIfIndex) static bool IsAddressLoopback(const struct in6_addr *aAddress)
{
static const uint8_t sLoopbackAddr[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
return memcmp(aAddress->s6_addr, sLoopbackAddr, sizeof(aAddress->s6_addr)) == 0;
}
static void InitRxSocket(utilsSocket *aSocket,
const struct in_addr *aIp4Address,
const struct in6_addr *aIp6Address,
unsigned int aIfIndex)
{ {
int fd; int fd;
int one = 1; int one = 1;
@@ -118,7 +128,13 @@ static void InitRxSocket(utilsSocket *aSocket, const struct in_addr *aIp4Address
else else
{ {
struct ipv6_mreq mreq; struct ipv6_mreq mreq;
struct sockaddr_in6 *sockaddr = &aSocket->mGroupAddr.mSockAddr6; struct sockaddr_in6 *sockaddr = &aSocket->mGroupAddr.mSockAddr6;
const char *groupAddr = UTILS_SOCKET_GROUP_ADDR6;
if (aIp6Address != NULL && IsAddressLoopback(aIp6Address))
{
groupAddr = UTILS_SOCKET_GROUP_ADDR6_LO;
}
rval = setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &aIfIndex, sizeof(aIfIndex)); rval = setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &aIfIndex, sizeof(aIfIndex));
ExpectOrExitWithErrorMsg(rval != -1, "setsockopt(RxFd, IPV6_MULTICAST_IF)"); ExpectOrExitWithErrorMsg(rval != -1, "setsockopt(RxFd, IPV6_MULTICAST_IF)");
@@ -127,8 +143,7 @@ static void InitRxSocket(utilsSocket *aSocket, const struct in_addr *aIp4Address
sockaddr->sin6_family = AF_INET6; sockaddr->sin6_family = AF_INET6;
sockaddr->sin6_port = htons(aSocket->mPortBase); sockaddr->sin6_port = htons(aSocket->mPortBase);
sockaddr->sin6_scope_id = aIfIndex; // This specifies network interface for link local scope sockaddr->sin6_scope_id = aIfIndex; // This specifies network interface for link local scope
ExpectOrExitWithErrorMsg(inet_pton(AF_INET6, UTILS_SOCKET_GROUP_ADDR6, &sockaddr->sin6_addr), ExpectOrExitWithErrorMsg(inet_pton(AF_INET6, groupAddr, &sockaddr->sin6_addr), "inet_pton(AF_INET6)");
"inet_pton(AF_INET6)");
memset(&mreq, 0, sizeof(mreq)); memset(&mreq, 0, sizeof(mreq));
mreq.ipv6mr_multiaddr = sockaddr->sin6_addr; mreq.ipv6mr_multiaddr = sockaddr->sin6_addr;
@@ -150,7 +165,7 @@ exit:
} }
} }
void InitTxSocketIp6(utilsSocket *aSocket, const struct in6_addr *aAddress, unsigned int aIfIndex) static void InitTxSocketIp6(utilsSocket *aSocket, const struct in6_addr *aAddress, unsigned int aIfIndex)
{ {
int fd; int fd;
int one = 1; int one = 1;
@@ -164,7 +179,7 @@ void InitTxSocketIp6(utilsSocket *aSocket, const struct in6_addr *aAddress, unsi
sockaddr.sin6_family = AF_INET6; sockaddr.sin6_family = AF_INET6;
sockaddr.sin6_addr = *aAddress; sockaddr.sin6_addr = *aAddress;
sockaddr.sin6_port = htons(aSocket->mPort); sockaddr.sin6_port = htons(aSocket->mPort);
if (IsAddressLinkLocal(aAddress)) if (IsAddressLinkLocal(aAddress) || IsAddressLoopback(aAddress))
{ {
sockaddr.sin6_scope_id = aIfIndex; sockaddr.sin6_scope_id = aIfIndex;
} }
@@ -283,7 +298,7 @@ static bool TryInitSocketIfname(utilsSocket *aSocket, const char *aLocalInterfac
DieNow(OT_EXIT_FAILURE); DieNow(OT_EXIT_FAILURE);
} }
InitRxSocket(aSocket, (addr6 ? NULL : addr4), ifIndex); InitRxSocket(aSocket, (addr6 ? NULL : addr4), addr6, ifIndex);
aSocket->mInitialized = true; aSocket->mInitialized = true;
aSocket->mUseIp6 = (addr6 != NULL); aSocket->mUseIp6 = (addr6 != NULL);
@@ -299,7 +314,7 @@ static bool TryInitSocketIp4(utilsSocket *aSocket, const char *aLocalInterface)
ExpectOrExitWithErrorMsg(inet_pton(AF_INET, aLocalInterface, &addr4), "inet_pton(AF_INET)"); ExpectOrExitWithErrorMsg(inet_pton(AF_INET, aLocalInterface, &addr4), "inet_pton(AF_INET)");
InitTxSocketIp4(aSocket, &addr4); InitTxSocketIp4(aSocket, &addr4);
InitRxSocket(aSocket, &addr4, 0); InitRxSocket(aSocket, &addr4, NULL, 0);
aSocket->mInitialized = true; aSocket->mInitialized = true;
aSocket->mUseIp6 = false; aSocket->mUseIp6 = false;
@@ -344,7 +359,7 @@ static bool TryInitSocketIp6(utilsSocket *aSocket, const char *aLocalInterface)
} }
InitTxSocketIp6(aSocket, &addr6, ifIndex); InitTxSocketIp6(aSocket, &addr6, ifIndex);
InitRxSocket(aSocket, NULL, ifIndex); InitRxSocket(aSocket, NULL, &addr6, ifIndex);
aSocket->mInitialized = true; aSocket->mInitialized = true;
aSocket->mUseIp6 = true; aSocket->mUseIp6 = true;
break; break;
+1
View File
@@ -64,6 +64,7 @@ test_ipv6()
OT_NODE_TYPE=rcp OT_SIMULATION_LOCAL_HOST=$IFACE_NAME $EXPECT_TEST OT_NODE_TYPE=rcp OT_SIMULATION_LOCAL_HOST=$IFACE_NAME $EXPECT_TEST
OT_NODE_TYPE=rcp OT_SIMULATION_LOCAL_HOST=$IP6ADDR $EXPECT_TEST OT_NODE_TYPE=rcp OT_SIMULATION_LOCAL_HOST=$IP6ADDR $EXPECT_TEST
OT_NODE_TYPE=rcp OT_SIMULATION_LOCAL_HOST=::1 $EXPECT_TEST
} }
test_ipv4() test_ipv4()