Skip to content

Commit 7567f01

Browse files
Martin Belangerigaw
authored andcommitted
libnvme: Add nvme_getifaddrs()
The POSIX `getifaddrs()` API returns the list of network interfaces on the system, but invoking it can be costly. On large-scale systems with hundreds of NVMe-over-TCP connections, this API may be called hundreds of times, resulting in increased latency. This patch introduces `nvme_getifaddrs()`, a wrapper around `getifaddrs()` that caches the results on the first invocation and reuses the cached data on subsequent calls. Signed-off-by: Martin Belanger <[email protected]>
1 parent 5be98d6 commit 7567f01

3 files changed

Lines changed: 44 additions & 26 deletions

File tree

libnvme/src/nvme/private.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include <poll.h>
1414
#include <sys/socket.h>
1515
#include <sys/stat.h>
16+
#include <sys/types.h>
17+
#include <ifaddrs.h>
1618

1719
#include <nvme/fabrics.h>
1820
#include <nvme/mi.h>
@@ -273,6 +275,7 @@ struct nvme_global_ctx {
273275
bool create_only;
274276
bool dry_run;
275277
struct nvme_fabric_options *options;
278+
struct ifaddrs *ifaddrs_cache; /* init with nvme_getifaddrs() */
276279
};
277280

278281
struct nvmf_discovery_ctx {
@@ -552,4 +555,18 @@ static inline char *xstrdup(const char *s)
552555
return strdup(s);
553556
}
554557

558+
/**
559+
* nvme_getifaddrs - Cached wrapper around getifaddrs()
560+
* @ctx: pointer to the global context
561+
*
562+
* On the first call, this function invokes the POSIX getifaddrs()
563+
* and caches the result in the global context. Subsequent calls
564+
* return the cached data. The caller must NOT call freeifaddrs()
565+
* on the returned data. The cache will be freed when the global
566+
* context is freed.
567+
*
568+
* Return: Pointer to I/F data, NULL on error (with errno set).
569+
*/
570+
const struct ifaddrs *nvme_getifaddrs(struct nvme_global_ctx *ctx);
571+
555572
#endif /* _LIBNVME_PRIVATE_H */

libnvme/src/nvme/tree.c

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ struct candidate_args {
5555
const char *subsysnqn;
5656
const char *host_traddr;
5757
const char *host_iface;
58-
struct ifaddrs *iface_list;
58+
const struct ifaddrs *iface_list;
5959
bool (*addreq)(const char *, const char *);
6060
bool well_known_nqn;
6161
};
@@ -525,6 +525,9 @@ void nvme_free_global_ctx(struct nvme_global_ctx *ctx)
525525
if (!ctx)
526526
return;
527527

528+
freeifaddrs(ctx->ifaddrs_cache); /* NULL-safe */
529+
ctx->ifaddrs_cache = NULL;
530+
528531
free(ctx->options);
529532
nvme_for_each_host_safe(ctx, h, _h)
530533
__nvme_free_host(h);
@@ -1756,7 +1759,8 @@ static bool _match_ctrl(struct nvme_ctrl *c, struct candidate_args *candidate)
17561759
* Return: The matching function to use when comparing an existing
17571760
* controller to the candidate controller.
17581761
*/
1759-
static ctrl_match_t _candidate_init(struct candidate_args *candidate,
1762+
static ctrl_match_t _candidate_init(struct nvme_global_ctx *ctx,
1763+
struct candidate_args *candidate,
17601764
const char *transport,
17611765
const char *traddr,
17621766
const char *trsvcid,
@@ -1786,12 +1790,7 @@ static ctrl_match_t _candidate_init(struct candidate_args *candidate,
17861790
}
17871791

17881792
if (streq0(transport, "tcp")) {
1789-
/* For TCP we may need to access the interface map.
1790-
* Let's retrieve and cache the map.
1791-
*/
1792-
if (getifaddrs(&candidate->iface_list) == -1)
1793-
candidate->iface_list = NULL;
1794-
1793+
candidate->iface_list = nvme_getifaddrs(ctx); /* TCP only */
17951794
candidate->addreq = nvme_ipaddrs_eq;
17961795
return _tcp_match_ctrl;
17971796
}
@@ -1806,30 +1805,19 @@ static ctrl_match_t _candidate_init(struct candidate_args *candidate,
18061805
return _match_ctrl;
18071806
}
18081807

1809-
/**
1810-
* _candidate_free() - Release resources allocated by _candidate_init()
1811-
*
1812-
* @candidate: data to free.
1813-
*/
1814-
static void _candidate_free(struct candidate_args *candidate)
1815-
{
1816-
freeifaddrs(candidate->iface_list); /* This is NULL-safe */
1817-
}
1818-
1819-
#define _cleanup_candidate_ __cleanup__(_candidate_free)
1820-
18211808
nvme_ctrl_t __nvme_lookup_ctrl(nvme_subsystem_t s, const char *transport,
18221809
const char *traddr, const char *host_traddr,
18231810
const char *host_iface, const char *trsvcid,
18241811
const char *subsysnqn, nvme_ctrl_t p)
18251812
{
1826-
_cleanup_candidate_ struct candidate_args candidate = {};
1813+
struct candidate_args candidate = {};
18271814
struct nvme_ctrl *c, *matching_c = NULL;
18281815
ctrl_match_t ctrl_match;
18291816

18301817
/* Init candidate and get the matching function to use */
1831-
ctrl_match = _candidate_init(&candidate, transport, traddr, trsvcid,
1832-
subsysnqn, host_traddr, host_iface);
1818+
ctrl_match = _candidate_init(s->h->ctx, &candidate, transport, traddr,
1819+
trsvcid, subsysnqn, host_traddr,
1820+
host_iface);
18331821

18341822
c = p ? nvme_subsystem_next_ctrl(s, p) : nvme_subsystem_first_ctrl(s);
18351823
for (; c != NULL; c = nvme_subsystem_next_ctrl(s, c)) {
@@ -1847,12 +1835,13 @@ bool nvme_ctrl_config_match(struct nvme_ctrl *c, const char *transport,
18471835
const char *subsysnqn, const char *host_traddr,
18481836
const char *host_iface)
18491837
{
1850-
_cleanup_candidate_ struct candidate_args candidate = {};
1838+
struct candidate_args candidate = {};
18511839
ctrl_match_t ctrl_match;
18521840

18531841
/* Init candidate and get the matching function to use */
1854-
ctrl_match = _candidate_init(&candidate, transport, traddr, trsvcid,
1855-
subsysnqn, host_traddr, host_iface);
1842+
ctrl_match = _candidate_init(c->ctx, &candidate, transport, traddr,
1843+
trsvcid, subsysnqn, host_traddr,
1844+
host_iface);
18561845

18571846
return ctrl_match(c, &candidate);
18581847
}

libnvme/src/nvme/util.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,3 +1167,15 @@ void *__nvme_realloc(void *p, size_t len)
11671167

11681168
return result;
11691169
}
1170+
1171+
const struct ifaddrs *nvme_getifaddrs(struct nvme_global_ctx *ctx)
1172+
{
1173+
if (!ctx->ifaddrs_cache) {
1174+
struct ifaddrs *p;
1175+
1176+
if (!getifaddrs(&p))
1177+
ctx->ifaddrs_cache = p;
1178+
}
1179+
1180+
return ctx->ifaddrs_cache;
1181+
}

0 commit comments

Comments
 (0)