From 53d31eb26e2f022da19e2f69ae391d150dced4cf Mon Sep 17 00:00:00 2001 From: Ghislain Bourgeois Date: Mon, 9 Sep 2024 18:14:53 -0400 Subject: [PATCH 1/6] Use getaddrinfo() when connecting to rfsimulator This commits uses getaddrinfo(3) when connecting as client to the rfsimulator. This enables name lookups, through DNS or a hosts file. This change makes it easier to use the simulator in a dynamic environment like Docker or Kubernetes by only targeting the name of the container or service. --- radio/rfsimulator/simulator.c | 60 ++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/radio/rfsimulator/simulator.c b/radio/rfsimulator/simulator.c index c5197eaab8..776bbf73cc 100644 --- a/radio/rfsimulator/simulator.c +++ b/radio/rfsimulator/simulator.c @@ -29,6 +29,7 @@ */ #include +#include #include #include #include @@ -38,6 +39,8 @@ #include #include #include +#include + #include #include #include @@ -577,27 +580,62 @@ static int startServer(openair0_device *device) { return 0; } -static int startClient(openair0_device *device) { +static int client_try_connect(const char *host, uint16_t port) +{ + int sock = -1; + int s; + struct addrinfo *result = NULL; + struct addrinfo *rp = NULL; + + char dport[6]; + snprintf(dport, sizeof(dport), "%d", port); + + struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM, + }; + + s = getaddrinfo(host, dport, &hints, &result); + if (s != 0) { + LOG_I(HW, "getaddrinfo: %s\n", gai_strerror(s)); + return -1; + } + for (rp = result; rp != NULL; rp = rp->ai_next) { + sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sock == -1) { + continue; + } + + if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) { + LOG_I(HW, "Connection to %s:%d established\n", host, port); + break; + } + + close(sock); + } + + freeaddrinfo(result); + + return sock; +} + +static int startClient(openair0_device *device) +{ rfsimulator_state_t *t = device->priv; t->role = SIMU_ROLE_CLIENT; int sock; - if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - LOG_E(HW, "socket(SOCK_STREAM) failed, errno(%d)\n", errno); - return -1; - } - struct sockaddr_in addr = {.sin_family = AF_INET, .sin_port = htons(t->port), .sin_addr = {.s_addr = INADDR_ANY}}; - addr.sin_addr.s_addr = inet_addr(t->ip); - bool connected=false; - while(!connected) { + while (true) { LOG_I(HW, "Trying to connect to %s:%d\n", t->ip, t->port); + sock = client_try_connect(t->ip, t->port); - if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) { + if (sock > 0) { LOG_I(HW, "Connection to %s:%d established\n", t->ip, t->port); - connected=true; + break; } LOG_I(HW, "connect() to %s:%d failed, errno(%d)\n", t->ip, t->port, errno); + fprintf(stderr, "Could not connect\n"); sleep(1); } From 320747e0b0a85e09cb21da2963e5d1fc4ef66544 Mon Sep 17 00:00:00 2001 From: Ghislain Bourgeois Date: Fri, 20 Sep 2024 15:22:10 -0400 Subject: [PATCH 2/6] Use getaddrinfo() and add IPv6 support in startServer This commit refactors startServer to use getaddrinfo() to prepare the socket creation. Doing so, it also adds support for IPv6 by using AF_UNSPEC as the address family. --- radio/rfsimulator/simulator.c | 63 +++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/radio/rfsimulator/simulator.c b/radio/rfsimulator/simulator.c index 776bbf73cc..02f05b1e25 100644 --- a/radio/rfsimulator/simulator.c +++ b/radio/rfsimulator/simulator.c @@ -547,30 +547,67 @@ static int rfsimu_vtime_cmd(char *buff, int debug, telnet_printfunc_t prnt, void return CMDSTATUS_FOUND; } -static int startServer(openair0_device *device) { - rfsimulator_state_t *t = (rfsimulator_state_t *) device->priv; +static int startServer(openair0_device *device) +{ + int sock = -1; + struct addrinfo *results = NULL; + struct addrinfo *rp= NULL; + + rfsimulator_state_t *t = (rfsimulator_state_t *)device->priv; t->role = SIMU_ROLE_SERVER; - t->listen_sock = socket(AF_INET, SOCK_STREAM, 0); - if (t->listen_sock < 0) { - LOG_E(HW, "socket(SOCK_STREAM) failed, errno(%d)\n", errno); + + char port[6]; + snprintf(port, sizeof(port), "%d", t->port); + + struct addrinfo hints = { + .ai_family = AF_INET6, + .ai_socktype = SOCK_STREAM, + .ai_flags = AI_PASSIVE, + }; + + int s = getaddrinfo(NULL, port, &hints, &results); + if (s != 0) { + LOG_E(HW, "getaddrinfo: %s\n", gai_strerror(s)); + freeaddrinfo(results); return -1; } + int enable = 1; - if (setsockopt(t->listen_sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) != 0) { - LOG_E(HW, "setsockopt(SO_REUSEADDR) failed, errno(%d)\n", errno); - return -1; + int disable = 0; + for (rp = results; rp != NULL; rp = rp->ai_next) { + sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sock == -1) { + continue; + } + + if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &disable, sizeof(int)) != 0) { + continue; + } + + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) != 0) { + continue; + } + + if (bind(sock, rp->ai_addr, rp->ai_addrlen) == 0) { + break; + } + + close(sock); } - struct sockaddr_in addr = {.sin_family = AF_INET, .sin_port = htons(t->port), .sin_addr = {.s_addr = INADDR_ANY}}; - int rc = bind(t->listen_sock, (struct sockaddr *)&addr, sizeof(addr)); - if (rc < 0) { - LOG_E(HW, "bind() failed, errno(%d)\n", errno); + + freeaddrinfo(results); + + if (sock <= 0) { + LOG_E(HW, "could not open a socket\n"); return -1; } + t->listen_sock = sock; + if (listen(t->listen_sock, 5) != 0) { LOG_E(HW, "listen() failed, errno(%d)\n", errno); return -1; } - struct epoll_event ev= {0}; + struct epoll_event ev = {0}; ev.events = EPOLLIN; ev.data.fd = t->listen_sock; if (epoll_ctl(t->epollfd, EPOLL_CTL_ADD, t->listen_sock, &ev) != 0) { From 6344fce6e48875e6d330abae3db78dab957d4c9d Mon Sep 17 00:00:00 2001 From: Ghislain Bourgeois Date: Wed, 2 Oct 2024 10:34:27 -0400 Subject: [PATCH 3/6] Reinitialize sock to -1 after closing Prevents bug where a closed socket is returned. --- radio/rfsimulator/simulator.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/radio/rfsimulator/simulator.c b/radio/rfsimulator/simulator.c index 02f05b1e25..2b358cd5bb 100644 --- a/radio/rfsimulator/simulator.c +++ b/radio/rfsimulator/simulator.c @@ -593,6 +593,7 @@ static int startServer(openair0_device *device) } close(sock); + sock = -1; } freeaddrinfo(results); @@ -649,6 +650,7 @@ static int client_try_connect(const char *host, uint16_t port) } close(sock); + sock = -1; } freeaddrinfo(result); From a648afd4c69f06e1013d4ff0a4b9314172e5963c Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 7 Oct 2024 14:14:10 +0200 Subject: [PATCH 4/6] RFsim Client: Improve logs - Remove double "Connection ... established" (already printed in caller) - Remove useless, there is already the logging module - Print getaddrinfo() error as LOG_E (error) --- radio/rfsimulator/simulator.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/radio/rfsimulator/simulator.c b/radio/rfsimulator/simulator.c index 2b358cd5bb..3c19b492c8 100644 --- a/radio/rfsimulator/simulator.c +++ b/radio/rfsimulator/simulator.c @@ -635,7 +635,7 @@ static int client_try_connect(const char *host, uint16_t port) s = getaddrinfo(host, dport, &hints, &result); if (s != 0) { - LOG_I(HW, "getaddrinfo: %s\n", gai_strerror(s)); + LOG_E(HW, "getaddrinfo: %s\n", gai_strerror(s)); return -1; } for (rp = result; rp != NULL; rp = rp->ai_next) { @@ -645,7 +645,6 @@ static int client_try_connect(const char *host, uint16_t port) } if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) { - LOG_I(HW, "Connection to %s:%d established\n", host, port); break; } @@ -674,7 +673,6 @@ static int startClient(openair0_device *device) } LOG_I(HW, "connect() to %s:%d failed, errno(%d)\n", t->ip, t->port, errno); - fprintf(stderr, "Could not connect\n"); sleep(1); } From ac7c02d8e59ab49e3299d0bff81bd2308200437f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 7 Oct 2024 14:11:33 +0200 Subject: [PATCH 5/6] CI 5G E1 RFsim test: Use DNS name for RFsim --- ci-scripts/yaml_files/5g_rfsimulator_e1/docker-compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-scripts/yaml_files/5g_rfsimulator_e1/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator_e1/docker-compose.yaml index 8c937ed76c..c5d4d3aa61 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_e1/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator_e1/docker-compose.yaml @@ -289,7 +289,7 @@ services: USE_ADDITIONAL_OPTIONS: --sa --rfsim --log_config.global_log_options level,nocolor,time -r 106 --numerology 1 -C 3619200000 --uicc0.imsi 208990100001100 - --rfsimulator.serveraddr 192.168.78.2 + --rfsimulator.serveraddr oai-du depends_on: - oai-du networks: From d6f0ff37c2903f0c78627b10259150a160eb6f49 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 7 Oct 2024 14:12:52 +0200 Subject: [PATCH 6/6] RFsim: doc serveraddr: mention IPv4v6 and DNS --- radio/rfsimulator/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/rfsimulator/README.md b/radio/rfsimulator/README.md index ba63ae4ec0..c86724fa0d 100644 --- a/radio/rfsimulator/README.md +++ b/radio/rfsimulator/README.md @@ -71,7 +71,7 @@ The RF simulator is using the configuration module, and its parameters are defin | CL option | usage | default | |:--------------------- |:-------------------------------------------------------------------------------|----: | -|`--rfsimulator.serveraddr `| ip address to connect to, or `server` to behave as a tcp server | 127.0.0.1 | +|`--rfsimulator.serveraddr `| IPv4v6 address or DNS name to connect to, or `server` to behave as a IPv4v6 TCP server | 127.0.0.1 | |`--rfsimulator.serverport `| port number to connect to or to listen on (eNB, which behaves as a tcp server) | 4043 | |`--rfsimulator.options` | list of comma separated run-time options, two are supported: `chanmod`, `saviq`| all options disabled | |`--rfsimulator.options saviq` | store IQs to a file for future replay | disabled |