Re: [PATCH v2 1/4] ibacm: Replace ioctl with netlink

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Jan 29, 2019 at 09:44:03AM +0100, Håkon Bugge wrote:
> ibacm uses ioctl with SIOCGIFCONF to enumerate the interfaces. This
> particular ioctl will only return interfaces that are "running".
> 
> This is a problem if, for example, ibacm is started before the
> interfaces get plumbed, or when an interface gets resurrected.
> 
> By using netlink (nl), we avoid using the sysfs interface to read the
> gid, as it is supplied directly by nl.
> 
> This commit does not change the existing functionality, but is made
> to prepare for a fix where ibacm is unable to resurrect an interface.
> 
> Detailed logging added:
> 
> acm_if_iter: name: stib0 label:     stib0 index:  9
> flags: broadcast,multicast,up,running,lowerup
> addr: 192.168.200.200/24 pkey: 0x88b4 guid: 0x21280001a17c97
> 
> Signed-off-by: Håkon Bugge <haakon.bugge@xxxxxxxxxx>

Reviewed-by: Ira Weiny <ira.weiny@xxxxxxxxx>

> 
> ---
> 
> v1 -> v2:
>    * Use static for CB function (Jason, Ira)
>    * Use original order of includes (Ira)
>    * Use ib_gid's global.interface_id instead of casting (Ira)
>    * Require Netlink in CMakeLists.txt (Jason)
>    * Removed ioctl.h include (Håkon)
>    * Removed Gerrit's Change-Id tag (Håkon)
> ---
>  ibacm/CMakeLists.txt |   4 +
>  ibacm/src/acm.c      |   7 ++
>  ibacm/src/acm_util.c | 251 ++++++++++++++++++++++++-------------------
>  ibacm/src/acm_util.h |   5 +-
>  4 files changed, 155 insertions(+), 112 deletions(-)
> 
> diff --git a/ibacm/CMakeLists.txt b/ibacm/CMakeLists.txt
> index 3a4e2632..7020def6 100644
> --- a/ibacm/CMakeLists.txt
> +++ b/ibacm/CMakeLists.txt
> @@ -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}
> diff --git a/ibacm/src/acm.c b/ibacm/src/acm.c
> index 6453c5f0..e8d50a4a 100644
> --- a/ibacm/src/acm.c
> +++ b/ibacm/src/acm.c
> @@ -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;
>  }
> diff --git a/ibacm/src/acm_util.c b/ibacm/src/acm_util.c
> index f4654f12..fecb6c89 100644
> --- a/ibacm/src/acm_util.c
> +++ b/ibacm/src/acm_util.c
> @@ -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;
>  }
> diff --git a/ibacm/src/acm_util.h b/ibacm/src/acm_util.h
> index cfa6f1a2..83b49edd 100644
> --- a/ibacm/src/acm_util.h
> +++ b/ibacm/src/acm_util.h
> @@ -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 */
> -- 
> 2.20.1
> 



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Photo]     [Yosemite News]     [Yosemite Photos]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux