@@ -1,3 +1,5 @@
+pkg_check_modules(NL libnl-3.0 libnl-route-3.0 REQUIRED)
+
publish_headers(infiniband
include/infiniband/acm.h
include/infiniband/acm_prov.h
@@ -7,6 +9,7 @@ publish_headers(infiniband
include_directories("include")
include_directories("src")
include_directories("linux")
+include_directories(${NL_INCLUDE_DIRS})
# NOTE: ibacm exports symbols from its own binary for use by ibacm
rdma_sbin_executable(ibacm
@@ -16,6 +19,7 @@ rdma_sbin_executable(ibacm
target_link_libraries(ibacm LINK_PRIVATE
ibverbs
ibumad
+ ${NL_LIBRARIES}
${SYSTEMD_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
${CMAKE_DL_LIBS}
@@ -3250,6 +3250,12 @@ int main(int argc, char **argv)
acm_log(0, "Error: failed to create sa resp rcving thread");
return -1;
}
+
+ if (acm_init_if_iter_sys()) {
+ acm_log(0, "Error: unable to initialize acm_if_iter_sys");
+ return -1;
+ }
+
acm_activate_devices();
acm_log(1, "starting server\n");
acm_server(systemd);
@@ -3260,6 +3266,7 @@ int main(int argc, char **argv)
acm_close_providers();
acm_stop_sa_handler();
umad_done();
+ acm_fini_if_iter_sys();
fclose(flog);
return 0;
}
@@ -33,42 +33,18 @@
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
-#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <errno.h>
+#include <netlink/route/addr.h>
+#include <netlink/route/link.h>
+#include <netlink/socket.h>
#include <infiniband/acm.h>
#include "acm_mad.h"
#include "acm_util.h"
-int acm_if_is_ib(char *ifname)
-{
- unsigned type;
- char buf[128];
- FILE *f;
- int ret;
-
- snprintf(buf, sizeof buf, "//sys//class//net//%s//type", ifname);
- f = fopen(buf, "r");
- if (!f) {
- acm_log(0, "failed to open %s\n", buf);
- return 0;
- }
-
- if (fgets(buf, sizeof buf, f)) {
- type = strtol(buf, NULL, 0);
- ret = (type == ARPHRD_INFINIBAND);
- } else {
- acm_log(0, "failed to read interface type\n");
- ret = 0;
- }
-
- fclose(f);
- return ret;
-}
-
int acm_if_get_pkey(char *ifname, uint16_t *pkey)
{
char buf[128], *end;
@@ -122,103 +98,156 @@ int acm_if_get_sgid(char *ifname, union ibv_gid *sgid)
return ret;
}
-int acm_if_iter_sys(acm_if_iter_cb cb, void *ctx)
+static struct nl_sock *sk = NULL;
+static struct nl_cache *link_cache;
+static struct nl_cache *addr_cache;
+
+int acm_init_if_iter_sys(void)
{
- struct ifconf *ifc;
- struct ifreq *ifr;
- char ip_str[INET6_ADDRSTRLEN];
- int family = AF_INET6;
- int s, ret, i, len;
- uint16_t pkey;
- union ibv_gid sgid;
- uint8_t addr_type;
- uint8_t addr[ACM_MAX_ADDRESS];
- char *alias_sep;
-
- s = socket(family, SOCK_DGRAM, 0);
- if (!s) {
- family = AF_INET;
- s = socket(family, SOCK_DGRAM, 0);
- if (!s)
- return -1;
+ int sts;
+
+ sk = nl_socket_alloc();
+ if (!sk) {
+ acm_log(0, "nl_socket_alloc");
+ return -1;
}
- len = sizeof(*ifc) + sizeof(*ifr) * 64;
- ifc = malloc(len);
- if (!ifc) {
- ret = -1;
- goto out1;
+ sts = nl_connect(sk, NETLINK_ROUTE);
+ if (sts) {
+ acm_log(0, "nl_connect failed");
+ goto out_connect;
}
- memset(ifc, 0, len);
- ifc->ifc_len = len - sizeof(*ifc);
- ifc->ifc_req = (struct ifreq *) (ifc + 1);
-
-retry_ioctl:
- ret = ioctl(s, SIOCGIFCONF, ifc);
- if (ret < 0) {
- acm_log(0, "ioctl IPv%s ifconf error: %s\n",
- (family == AF_INET6) ? "6" : "4", strerror(errno));
- if (family == AF_INET6) {
- close(s);
- family = AF_INET;
- s = socket(family, SOCK_DGRAM, 0);
- if (!s) {
- free(ifc);
- return ret;
- }
- goto retry_ioctl;
- }
- goto out2;
+ sts = rtnl_link_alloc_cache(sk, AF_UNSPEC, &link_cache);
+ if (sts) {
+ acm_log(0, "rtnl_link_alloc_cache failed");
+ goto out_connect;
}
- ifr = ifc->ifc_req;
- for (i = 0; i < ifc->ifc_len / sizeof(struct ifreq); i++) {
- switch (ifr[i].ifr_addr.sa_family) {
- case AF_INET:
- addr_type = ACM_ADDRESS_IP;
- memcpy(&addr, &((struct sockaddr_in *) &ifr[i].ifr_addr)->sin_addr,
- sizeof addr);
- inet_ntop(ifr[i].ifr_addr.sa_family,
- &((struct sockaddr_in *) &ifr[i].ifr_addr)->sin_addr,
- ip_str, sizeof ip_str);
- break;
- case AF_INET6:
- addr_type = ACM_ADDRESS_IP6;
- memcpy(&addr, &((struct sockaddr_in6 *) &ifr[i].ifr_addr)->sin6_addr,
- sizeof addr);
- inet_ntop(ifr[i].ifr_addr.sa_family,
- &((struct sockaddr_in6 *) &ifr[i].ifr_addr)->sin6_addr,
- ip_str, sizeof ip_str);
- break;
- default:
- continue;
- }
+ sts = rtnl_addr_alloc_cache(sk, &addr_cache);
+ if (sts) {
+ acm_log(0, "rtnl_addr_alloc_cache");
+ goto out_addr;
+ }
- acm_log(2, "%s\n", ifr[i].ifr_name);
+ return 0;
- alias_sep = strchr(ifr[i].ifr_name, ':');
- if (alias_sep)
- *alias_sep = '\0';
+out_addr:
+ nl_cache_free(link_cache);
- if (!acm_if_is_ib(ifr[i].ifr_name))
- continue;
+out_connect:
+ nl_close(sk);
+ return sts;
+}
- ret = acm_if_get_sgid(ifr[i].ifr_name, &sgid);
- if (ret)
- continue;
+void acm_fini_if_iter_sys(void)
+{
+ nl_cache_free(link_cache);
+ nl_cache_free(addr_cache);
+ nl_close(sk);
+}
- ret = acm_if_get_pkey(ifr[i].ifr_name, &pkey);
- if (ret)
- continue;
+static inline int af2acm_addr_type(int af)
+{
+ switch (af) {
+ case AF_INET:
+ return ACM_ADDRESS_IP;
- cb(ifr[i].ifr_name, &sgid, pkey, addr_type, addr, ip_str, ctx);
+ case AF_INET6:
+ return ACM_ADDRESS_IP6;
}
- ret = 0;
-out2:
- free(ifc);
-out1:
- close(s);
- return ret;
+ acm_log(0, "Unnkown address family\n");
+ return ACM_ADDRESS_INVALID;
+}
+
+struct ctx_and_cb {
+ void *ctx;
+ acm_if_iter_cb cb;
+};
+
+static void acm_if_iter(struct nl_object *obj, void *_ctx_and_cb)
+{
+ struct ctx_and_cb *ctx_cb = (struct ctx_and_cb *)_ctx_and_cb;
+ struct rtnl_addr *addr = (struct rtnl_addr *)obj;
+ uint8_t bin_addr[ACM_MAX_ADDRESS] = {};
+ char ip_str[INET6_ADDRSTRLEN];
+ struct nl_addr *link_addr;
+ struct rtnl_link *link;
+ char flags_str[128];
+ union ibv_gid sgid;
+ struct nl_addr *a;
+ uint16_t pkey;
+ int addr_len;
+ char *label;
+ int flags;
+ int ret;
+ int af;
+
+ link = rtnl_link_get(link_cache, rtnl_addr_get_ifindex(addr));
+ flags = rtnl_link_get_flags(link);
+
+ if (rtnl_link_get_arptype(link) != ARPHRD_INFINIBAND)
+ return;
+
+ if (!(flags & IFF_RUNNING))
+ return;
+
+ if (!(a = rtnl_addr_get_local(addr)))
+ return;
+
+ if ((addr_len = nl_addr_get_len(a)) > ACM_MAX_ADDRESS) {
+ acm_log(0, "address too long (%d)\n", addr_len);
+ return;
+ }
+
+ af = nl_addr_get_family(a);
+ if (af != AF_INET && af != AF_INET6)
+ return;
+
+ label = rtnl_addr_get_label(addr);
+ if (!label)
+ return;
+
+ link_addr = rtnl_link_get_addr(link);
+ memcpy(sgid.raw, nl_addr_get_binary_addr(link_addr) + 4, sizeof(sgid));
+
+ ret = acm_if_get_pkey(rtnl_link_get_name(link), &pkey);
+ if (ret)
+ return;
+
+ acm_log(2, "name: %5s label: %9s index: %2d flags: %s addr: %s pkey: 0x%04x guid: 0x%lx\n",
+ rtnl_link_get_name(link), label,
+ rtnl_addr_get_ifindex(addr),
+ rtnl_link_flags2str(flags, flags_str, sizeof(flags_str)),
+ nl_addr2str(a, ip_str, sizeof(ip_str)), pkey,
+ be64toh(sgid.global.interface_id));
+
+ memcpy(&bin_addr, nl_addr_get_binary_addr(a), addr_len);
+ ctx_cb->cb(rtnl_link_get_name(link), &sgid, pkey, af2acm_addr_type(af), bin_addr, ip_str, ctx_cb->ctx);
+}
+
+
+int acm_if_iter_sys(acm_if_iter_cb cb, void *ctx)
+{
+ struct ctx_and_cb ctx_cb;
+ int sts;
+
+ sts = nl_cache_refill(sk, link_cache);
+ if (sts) {
+ acm_log(0, "nl_cache_refill link_cache");
+ return sts;
+ }
+
+ sts = nl_cache_refill(sk, addr_cache);
+ if (sts) {
+ acm_log(0, "nl_cache_refill addr_cache");
+ return sts;
+ }
+
+ ctx_cb.ctx = ctx;
+ ctx_cb.cb = cb;
+ nl_cache_foreach(addr_cache, acm_if_iter, (void *)&ctx_cb);
+
+ return 0;
}
@@ -33,6 +33,7 @@
#include <infiniband/verbs.h>
#include <infiniband/acm_prov.h>
+
#ifdef ACME_PRINTS
#undef acm_log
@@ -47,12 +48,14 @@
int acm_if_is_ib(char *ifname);
int acm_if_get_pkey(char *ifname, uint16_t *pkey);
int acm_if_get_sgid(char *ifname, union ibv_gid *sgid);
-
+int acm_init_if_iter_sys(void);
+void acm_fini_if_iter_sys(void);
typedef void (*acm_if_iter_cb)(char *ifname, union ibv_gid *gid, uint16_t pkey,
uint8_t addr_type, uint8_t *addr,
char *ip_str, void *ctx);
int acm_if_iter_sys(acm_if_iter_cb cb, void *ctx);
+
char **parse(const char *args, int *count);
#endif /* ACM_IF_H */