[posix] support interface name in ot-ctl (#6552)

This commit adds the Thread interface name to unix socket of
OpenThread daemon, so that ot-ctl can specify which daemon to connect
to.
This commit is contained in:
Yakun Xu
2021-05-08 18:21:13 -07:00
committed by GitHub
parent e7c4236c0a
commit f766d8047d
7 changed files with 122 additions and 28 deletions
+10 -7
View File
@@ -117,18 +117,21 @@ do_check()
RADIO_URL="spinel+hdlc+uart://${CORE_PTY}?region=US&max-power-table=11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26"
if [[ ${OT_DAEMON} == 'on' ]]; then
sudo "$PWD/build/posix/src/posix/ot-daemon" -d7 -v -I "${VALID_NETIF_NAME}" "${RADIO_URL}" &
sudo "$PWD/build/posix/src/posix/ot-daemon" -d7 -v -I "${VALID_NETIF_NAME}" "${RADIO_URL}" 2>&1 | tee "${OT_OUTPUT}" &
sleep 3
OT_CLI_CMD="$PWD/build/posix/src/posix/ot-ctl"
sudo "${OT_CLI_CMD}" panid 0xface | grep 'Done' || die 'failed to set panid with ot-ctl'
# macOS cannot explicitly set network interface name
NETIF_NAME=$(grep -o 'Thread interface: .\+' "${OT_OUTPUT}" | cut -d: -f2 | tr -d ' \r\n')
OT_CTL="$PWD/build/posix/src/posix/ot-ctl"
sudo "${OT_CTL}" -I "${NETIF_NAME}" panid 0xface | grep 'Done' || die 'failed to set panid with ot-ctl'
# verify this reset and factoryreset end immediately
sudo "${OT_CLI_CMD}" reset
sudo "${OT_CTL}" -I "${NETIF_NAME}" reset
# sleep a while for daemon ready
sleep 2
sudo "${OT_CLI_CMD}" factoryreset
sudo "${OT_CTL}" -I "${NETIF_NAME}" factoryreset
# sleep a while for daemon ready
sleep 2
OT_CLI_CMD="${OT_CTL} -I ${NETIF_NAME}"
else
OT_CLI="$PWD/build/posix/src/posix/ot-cli"
sudo "${OT_CLI}" -I "${VALID_NETIF_NAME}" -n "${RADIO_URL}"
@@ -201,9 +204,9 @@ EOF
if [[ ${OT_DAEMON} == 'on' ]]; then
sudo killall -9 expect || true
sudo killall -9 ot-ctl || true
NETIF_INDEX=$(ip link show "${VALID_NETIF_NAME}" | cut -f 1 -d ":" | head -n 1)
NETIF_INDEX=$(ip link show "${NETIF_NAME}" | cut -f 1 -d ":" | head -n 1)
sudo PATH="$(dirname "${OT_CLI_CMD}"):${PATH}" \
python3 "$PWD/tests/scripts/misc/test_multicast_join.py" "${NETIF_INDEX}" \
python3 "$PWD/tests/scripts/misc/test_multicast_join.py" "${NETIF_INDEX}" "${NETIF_NAME}" \
|| die 'multicast group join failed'
fi
+81 -12
View File
@@ -43,6 +43,7 @@
#define OPENTHREAD_USE_READLINE (HAVE_LIBEDIT || HAVE_LIBREADLINE)
#include <assert.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -62,6 +63,13 @@
#include "platform-posix.h"
namespace {
struct Config
{
const char *mNetifName;
};
enum
{
kLineBufferSize = OPENTHREAD_CONFIG_CLI_MAX_LINE_LENGTH,
@@ -71,10 +79,10 @@ static_assert(kLineBufferSize >= sizeof("> "), "kLineBufferSize is too small");
static_assert(kLineBufferSize >= sizeof("Done\r\n"), "kLineBufferSize is too small");
static_assert(kLineBufferSize >= sizeof("Error "), "kLineBufferSize is too small");
static int sSessionFd = -1;
int sSessionFd = -1;
#if OPENTHREAD_USE_READLINE
static void InputCallback(char *aLine)
void InputCallback(char *aLine)
{
if (aLine != nullptr)
{
@@ -89,7 +97,7 @@ static void InputCallback(char *aLine)
}
#endif // OPENTHREAD_USE_READLINE
static bool DoWrite(int aFile, const void *aBuffer, size_t aSize)
bool DoWrite(int aFile, const void *aBuffer, size_t aSize)
{
bool ret = true;
@@ -111,7 +119,7 @@ exit:
return ret;
}
static int ConnectSession(void)
int ConnectSession(const Config &aConfig)
{
int ret;
@@ -128,7 +136,12 @@ static int ConnectSession(void)
memset(&sockname, 0, sizeof(struct sockaddr_un));
sockname.sun_family = AF_UNIX;
strncpy(sockname.sun_path, OPENTHREAD_POSIX_DAEMON_SOCKET_NAME, sizeof(sockname.sun_path) - 1);
ret = snprintf(sockname.sun_path, sizeof(sockname.sun_path), OPENTHREAD_POSIX_DAEMON_SOCKET_NAME,
aConfig.mNetifName);
VerifyOrExit(ret >= 0 && static_cast<size_t>(ret) < sizeof(sockname.sun_path), {
errno = EINVAL;
ret = -1;
});
ret = connect(sSessionFd, reinterpret_cast<const struct sockaddr *>(&sockname), sizeof(struct sockaddr_un));
}
@@ -137,7 +150,7 @@ exit:
return ret;
}
static bool ReconnectSession(void)
bool ReconnectSession(Config &aConfig)
{
bool ok = false;
uint32_t delay = 0; // 100ms
@@ -149,7 +162,7 @@ static bool ReconnectSession(void)
usleep(delay);
delay = delay > 0 ? delay * 2 : 100000;
rval = ConnectSession();
rval = ConnectSession(aConfig);
VerifyOrExit(rval == -1, ok = true);
@@ -161,11 +174,64 @@ exit:
return ok;
}
static bool IsSeparator(char aChar)
enum
{
kOptInterfaceName = 'I',
kOptHelp = 'h',
};
const struct option kOptions[] = {
{"interface-name", required_argument, NULL, kOptInterfaceName},
{"help", required_argument, NULL, kOptHelp},
};
void PrintUsage(const char *aProgramName, FILE *aStream, int aExitCode)
{
fprintf(aStream,
"Syntax:\n"
" %s [Options] [--] ...\n"
"Options:\n"
" -h --help Display this usage information.\n"
" -I --interface-name name Thread network interface name.\n",
aProgramName);
exit(aExitCode);
}
bool IsSeparator(char aChar)
{
return (aChar == ' ') || (aChar == '\t') || (aChar == '\r') || (aChar == '\n');
}
Config ParseArg(int &aArgCount, char **&aArgVector)
{
Config config = {"wpan0"};
optind = 1;
for (int index, option; (option = getopt_long(aArgCount, aArgVector, "I:h", kOptions, &index)) != -1;)
{
switch (option)
{
case kOptInterfaceName:
config.mNetifName = optarg;
break;
case kOptHelp:
PrintUsage(aArgVector[0], stdout, OT_EXIT_SUCCESS);
break;
default:
PrintUsage(aArgVector[0], stderr, OT_EXIT_FAILURE);
break;
}
}
aArgCount -= optind;
aArgVector += optind;
return config;
}
} // namespace
int main(int argc, char *argv[])
{
bool isInteractive = true;
@@ -174,15 +240,18 @@ int main(int argc, char *argv[])
char lineBuffer[kLineBufferSize];
size_t lineBufferWritePos = 0;
int ret;
Config config;
VerifyOrExit(ConnectSession() != -1, perror("connect session failed"); ret = OT_EXIT_FAILURE);
config = ParseArg(argc, argv);
if (argc > 1)
VerifyOrExit(ConnectSession(config) != -1, perror("connect session failed"); ret = OT_EXIT_FAILURE);
if (argc > 0)
{
char buffer[kLineBufferSize];
size_t count = 0;
for (int i = 1; i < argc; i++)
for (int i = 0; i < argc; i++)
{
for (const char *c = argv[i]; *c; ++c)
{
@@ -259,7 +328,7 @@ int main(int argc, char *argv[])
if (rval == 0)
{
// daemon closed sSessionFd
if (isInteractive && ReconnectSession())
if (isInteractive && ReconnectSession(config))
{
continue;
}
+1
View File
@@ -296,6 +296,7 @@ static otInstance *InitInstance(PosixConfig *aConfig)
IgnoreError(otLoggingSetLevel(aConfig->mLogLevel));
instance = otSysInit(&aConfig->mPlatformConfig);
syslog(LOG_INFO, "Thread interface: %s", otSysGetThreadNetifName());
atexit(otSysDeinit);
+18 -4
View File
@@ -148,7 +148,18 @@ void platformDaemonEnable(otInstance *aInstance)
DieNow(OT_EXIT_FAILURE);
}
sDaemonLock = open(OPENTHREAD_POSIX_DAEMON_SOCKET_LOCK, O_CREAT | O_RDONLY | O_CLOEXEC, 0600);
{
static_assert(sizeof(OPENTHREAD_POSIX_DAEMON_SOCKET_LOCK) == sizeof(OPENTHREAD_POSIX_DAEMON_SOCKET_NAME),
"sock and lock file name pattern should have the same length!");
char lockfile[sizeof(sockname.sun_path)];
ret = snprintf(lockfile, sizeof(lockfile), OPENTHREAD_POSIX_DAEMON_SOCKET_LOCK, gNetifName);
if (ret < 0 && static_cast<size_t>(ret) >= sizeof(lockfile))
{
DieNowWithMessage("lockfile", OT_EXIT_INVALID_ARGUMENTS);
}
sDaemonLock = open(lockfile, O_CREAT | O_RDONLY | O_CLOEXEC, 0600);
}
if (sDaemonLock == -1)
{
@@ -162,10 +173,13 @@ void platformDaemonEnable(otInstance *aInstance)
memset(&sockname, 0, sizeof(struct sockaddr_un));
(void)unlink(OPENTHREAD_POSIX_DAEMON_SOCKET_NAME);
sockname.sun_family = AF_UNIX;
strncpy(sockname.sun_path, OPENTHREAD_POSIX_DAEMON_SOCKET_NAME, sizeof(sockname.sun_path) - 1);
ret = snprintf(sockname.sun_path, sizeof(sockname.sun_path), OPENTHREAD_POSIX_DAEMON_SOCKET_NAME, gNetifName);
if (ret < 0 && static_cast<size_t>(ret) >= sizeof(sockname.sun_path))
{
DieNowWithMessage("sockfile", OT_EXIT_INVALID_ARGUMENTS);
}
(void)unlink(sockname.sun_path);
ret = bind(sListenSocket, (const struct sockaddr *)&sockname, sizeof(struct sockaddr_un));
+5 -1
View File
@@ -83,7 +83,11 @@
*
*/
#ifndef OPENTHREAD_POSIX_CONFIG_DAEMON_SOCKET_BASENAME
#define OPENTHREAD_POSIX_CONFIG_DAEMON_SOCKET_BASENAME "/tmp/openthread"
#ifdef __linux__
#define OPENTHREAD_POSIX_CONFIG_DAEMON_SOCKET_BASENAME "/run/openthread-%s"
#else
#define OPENTHREAD_POSIX_CONFIG_DAEMON_SOCKET_BASENAME "/tmp/openthread-%s"
#endif
#endif
/**
+2
View File
@@ -162,6 +162,8 @@ otInstance *otSysInit(otPlatformConfig *aPlatformConfig)
platformNetifInit(instance, aPlatformConfig->mInterfaceName);
#elif OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
platformUdpInit(aPlatformConfig->mInterfaceName);
#else
gNetifName[0] = '\0';
#endif
#if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE || OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
+5 -4
View File
@@ -36,21 +36,22 @@ import time
from ipaddress import ip_address
def get_maddrs():
lines = subprocess.run(['ot-ctl', 'ipmaddr'], stdout=subprocess.PIPE).stdout.decode().split()
def get_maddrs(if_name):
lines = subprocess.run(['ot-ctl', '-I', if_name, 'ipmaddr'], stdout=subprocess.PIPE).stdout.decode().split()
return [ip_address(l) for l in lines if l.startswith('ff')]
def main():
group = 'ff02::158'
if_index = int(sys.argv[1])
if_name = sys.argv[2]
with socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) as s:
s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, if_index)
s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP,
struct.pack('16si', socket.inet_pton(socket.AF_INET6, group), if_index))
time.sleep(2)
maddrs = get_maddrs()
maddrs = get_maddrs(if_name)
print(maddrs)
if not any(addr == ip_address(group) for addr in maddrs):
return -1
@@ -59,7 +60,7 @@ def main():
struct.pack('16si', socket.inet_pton(socket.AF_INET6, group), if_index))
time.sleep(2)
maddrs = get_maddrs()
maddrs = get_maddrs(if_name)
print(maddrs)
if any(addr == ip_address(group) for addr in maddrs):
return -1