diff mbox series

[rdma-core,2/2] iwpmd: add NO_PORT_MAP support

Message ID aa81728e56437537a2292bdebdfed4fcf937b06c.1548789085.git.swise@opengridcomputing.com (mailing list archive)
State Not Applicable
Headers show
Series Support for no port mapping requirements | expand

Commit Message

Steve Wise Jan. 29, 2019, 7:11 p.m. UTC
A soft iwarp driver that uses the host TCP stack via a kernel mode
socket does not need port mapping.  In fact, if the port map daemon,
iwpmd, is running, then iwpmd must not try and create/bind a socket to
the actual port for a soft iwarp connection, since the driver already
has that socket bound.

Yet if the soft iwarp driver wants to interoperate with hard iwarp
devices that -are- using port mapping, then the soft iwarp driver's
mappings still need to be maintained and advertised by the iwpm protocol.

This patch enhances iwpmd to support the new version 4 IWPM netlink
protocol.  It does so while still providing support for kernels with
ABI version 3.

Signed-off-by: Steve Wise <swise@opengridcomputing.com>
---
 iwpmd/iwarp_pm.h        |   8 +-
 iwpmd/iwarp_pm_helper.c |  26 ++++--
 iwpmd/iwarp_pm_server.c | 229 +++++++++++++++++++++++++++++++++++-------------
 3 files changed, 193 insertions(+), 70 deletions(-)
diff mbox series

Patch

diff --git a/iwpmd/iwarp_pm.h b/iwpmd/iwarp_pm.h
index c3f19a12e27d..83cbb8ed9c5b 100644
--- a/iwpmd/iwarp_pm.h
+++ b/iwpmd/iwarp_pm.h
@@ -108,7 +108,8 @@  enum {
         IWPM_UNKNOWN_MAPPING_ERR,
         IWPM_CLIENT_DEV_INFO_ERR,
         IWPM_USER_LIB_INFO_ERR,
-        IWPM_REMOTE_QUERY_REJECT
+        IWPM_REMOTE_QUERY_REJECT,
+        IWPM_VERSION_MISMATCH_ERR,
 };
 
 /* iwpm param indexes */
@@ -236,9 +237,10 @@  int is_wcard_ipaddr(struct sockaddr_storage *);
 
 /* iwarp_pm_helper.c */
 
-iwpm_mapped_port *create_iwpm_mapped_port(struct sockaddr_storage *, int);
+iwpm_mapped_port *create_iwpm_mapped_port(struct sockaddr_storage *, int, __u32 flags);
 
-iwpm_mapped_port *reopen_iwpm_mapped_port(struct sockaddr_storage *, struct sockaddr_storage *, int);
+iwpm_mapped_port *reopen_iwpm_mapped_port(struct sockaddr_storage *, struct sockaddr_storage *, int,
+				__u32 flags);
 
 void add_iwpm_mapped_port(iwpm_mapped_port *);
 
diff --git a/iwpmd/iwarp_pm_helper.c b/iwpmd/iwarp_pm_helper.c
index b8c230189d50..16311a9c989c 100644
--- a/iwpmd/iwarp_pm_helper.c
+++ b/iwpmd/iwarp_pm_helper.c
@@ -352,7 +352,7 @@  static iwpm_mapped_port *get_iwpm_port(int client_idx, struct sockaddr_storage *
  * @local_addr: local address to be mapped (IP address and TCP port)
  * @client_idx: the index of the client owner of the mapped port
  */
-iwpm_mapped_port *create_iwpm_mapped_port(struct sockaddr_storage *local_addr, int client_idx)
+iwpm_mapped_port *create_iwpm_mapped_port(struct sockaddr_storage *local_addr, int client_idx, __u32 flags)
 {
 	iwpm_mapped_port *iwpm_port;
 	struct sockaddr_storage mapped_addr;
@@ -362,8 +362,13 @@  iwpm_mapped_port *create_iwpm_mapped_port(struct sockaddr_storage *local_addr, i
 	if (get_iwpm_ip_addr(local_addr, &mapped_addr))
 		goto create_mapped_port_error;
 	/* get a tcp port from the host net stack */
-	if (get_iwpm_tcp_port(local_addr->ss_family, 0, &mapped_addr, &new_sd))
-		goto create_mapped_port_error;
+	if (flags & IWPM_FLAGS_NO_PORT_MAP) {
+		mapped_addr = *local_addr;
+		new_sd = -1;
+	} else {
+		if (get_iwpm_tcp_port(local_addr->ss_family, 0, &mapped_addr, &new_sd))
+			goto create_mapped_port_error;
+	}
 
 	iwpm_port = get_iwpm_port(client_idx, local_addr, &mapped_addr, new_sd);
 	return iwpm_port;
@@ -380,7 +385,8 @@  create_mapped_port_error:
  * @client_idx: the index of the client owner of the mapped port
  */
 iwpm_mapped_port *reopen_iwpm_mapped_port(struct sockaddr_storage *local_addr,
-						struct sockaddr_storage *mapped_addr, int client_idx)
+						struct sockaddr_storage *mapped_addr, int client_idx,
+						__u32 flags)
 {
 	iwpm_mapped_port *iwpm_port;
 	int new_sd;
@@ -395,9 +401,12 @@  iwpm_mapped_port *reopen_iwpm_mapped_port(struct sockaddr_storage *local_addr,
 		goto reopen_mapped_port_error;
 	}
 	/* get a tcp port from the host net stack */
-	if (get_iwpm_tcp_port(local_addr->ss_family, htobe16(1), mapped_addr, &new_sd))
-		goto reopen_mapped_port_error;
-
+	if (flags & IWPM_FLAGS_NO_PORT_MAP) {
+		new_sd = -1;
+	} else {
+		if (get_iwpm_tcp_port(local_addr->ss_family, htobe16(1), mapped_addr, &new_sd))
+			goto reopen_mapped_port_error;
+	}
 	iwpm_port = get_iwpm_port(client_idx, local_addr, mapped_addr, new_sd);
 	return iwpm_port;
 
@@ -520,7 +529,8 @@  find_same_mapping_exit:
  */
 void free_iwpm_port(iwpm_mapped_port *iwpm_port)
 {
-	close(iwpm_port->sd);
+	if (iwpm_port->sd != -1)
+		close(iwpm_port->sd);
 	free(iwpm_port);
 }
 
diff --git a/iwpmd/iwarp_pm_server.c b/iwpmd/iwarp_pm_server.c
index 63ed83ab17fd..aacadc2ba01c 100644
--- a/iwpmd/iwarp_pm_server.c
+++ b/iwpmd/iwarp_pm_server.c
@@ -35,9 +35,12 @@ 
 #include <systemd/sd-daemon.h>
 #include <getopt.h>
 #include "iwarp_pm.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 
 static const char iwpm_ulib_name [] = "iWarpPortMapperUser";
-static int iwpm_version = 3;
+static __u16 iwpm_version = IWPM_UABI_VERSION;
 
 LIST_HEAD(mapping_reqs);		      /* list of map tracking objects */
 LIST_HEAD(pending_messages);		      /* list of pending wire messages */
@@ -58,6 +61,7 @@  pthread_mutex_t pending_msg_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 static void iwpm_cleanup(void);
 static int print_mappings = 0;
+static int send_iwpm_mapinfo_request(int nl_sock, int client);
 
 /**
  * iwpm_signal_handler - Handle signals which iwarp port mapper receives
@@ -290,7 +294,8 @@  register_pid_error:
 /* Add mapping request - nlmsg attributes */
 static struct nla_policy manage_map_policy[IWPM_NLA_MANAGE_MAPPING_MAX] = {
         [IWPM_NLA_MANAGE_MAPPING_SEQ]        = { .type = NLA_U32 },
-        [IWPM_NLA_MANAGE_ADDR]               = { .minlen = sizeof(struct sockaddr_storage) }
+        [IWPM_NLA_MANAGE_ADDR]               = { .minlen = sizeof(struct sockaddr_storage) },
+        [IWPM_NLA_MANAGE_FLAGS]              = { .type = NLA_U32 }
 };
 
 /**
@@ -302,15 +307,15 @@  static struct nla_policy manage_map_policy[IWPM_NLA_MANAGE_MAPPING_MAX] = {
  * Process a mapping request for a local address and send a response to the client
  * which contains the mapped local address (IP address and TCP port)
  * nlmsg response attributes:
- *	[IWPM_NLA_MANAGE_MAPPING_SEQ]
- *	[IWPM_NLA_MANAGE_ADDR]
- *	[IWPM_NLA_MANAGE_MAPPED_LOC_ADDR]
+ *	[IWPM_NLA_RMANAGE_MAPPING_SEQ]
+ *	[IWPM_NLA_RMANAGE_ADDR]
+ *	[IWPM_NLA_RMANAGE_MAPPED_LOC_ADDR]
  *	[IWPM_NLA_RMANAGE_MAPPING_ERR]
  */
 static int process_iwpm_add_mapping(struct nlmsghdr *req_nlh, int client_idx, int nl_sock)
 {
 	iwpm_mapped_port *iwpm_port = NULL;
-	struct nlattr *nltb [IWPM_NLA_MANAGE_MAPPING_MAX];
+	struct nlattr *nltb [IWPM_NLA_MANAGE_MAPPING_MAX] = {};
 	struct nl_msg *resp_nlmsg = NULL;
 	struct sockaddr_storage *local_addr;
 	int not_mapped = 1;
@@ -318,13 +323,18 @@  static int process_iwpm_add_mapping(struct nlmsghdr *req_nlh, int client_idx, in
 	const char *msg_type = "Add Mapping Request";
 	const char *str_err = "";
 	int ret = -EINVAL;
+	__u32 flags;
+	int max = IWPM_NLA_MANAGE_MAPPING_MAX;
 
-	if (parse_iwpm_nlmsg(req_nlh, IWPM_NLA_MANAGE_MAPPING_MAX, manage_map_policy, nltb, msg_type)) {
+	if (iwpm_version != IWPM_UABI_VERSION)
+		max--;
+	if (parse_iwpm_nlmsg(req_nlh, max, manage_map_policy, nltb, msg_type)) {
 		err_code = IWPM_INVALID_NLMSG_ERR;
 		str_err = "Received Invalid nlmsg";
 		goto add_mapping_error;
 	}
 	local_addr = (struct sockaddr_storage *)nla_data(nltb[IWPM_NLA_MANAGE_ADDR]);
+	flags = nltb[IWPM_NLA_MANAGE_FLAGS] ? nla_get_u32(nltb[IWPM_NLA_MANAGE_FLAGS]) : 0;
 
 	iwpm_port = find_iwpm_mapping(local_addr, not_mapped);
 	if (iwpm_port) {
@@ -337,7 +347,7 @@  static int process_iwpm_add_mapping(struct nlmsghdr *req_nlh, int client_idx, in
 		}
 
 	} else {
-		iwpm_port = create_iwpm_mapped_port(local_addr, client_idx);
+		iwpm_port = create_iwpm_mapped_port(local_addr, client_idx, flags);
 		if (!iwpm_port) {
 			err_code = IWPM_CREATE_MAPPING_ERR;
 			str_err = "Unable to create new mapping";
@@ -351,12 +361,12 @@  static int process_iwpm_add_mapping(struct nlmsghdr *req_nlh, int client_idx, in
 		goto add_mapping_free_error;
 	}
 	str_err = "Invalid nlmsg attribute";
-	if ((ret = nla_put_u32(resp_nlmsg, IWPM_NLA_MANAGE_MAPPING_SEQ, req_nlh->nlmsg_seq)))
+	if ((ret = nla_put_u32(resp_nlmsg, IWPM_NLA_RMANAGE_MAPPING_SEQ, req_nlh->nlmsg_seq)))
 		goto add_mapping_free_error;
-	if ((ret = nla_put(resp_nlmsg, IWPM_NLA_MANAGE_ADDR,
+	if ((ret = nla_put(resp_nlmsg, IWPM_NLA_RMANAGE_ADDR,
 				sizeof(struct sockaddr_storage), &iwpm_port->local_addr)))
 		goto add_mapping_free_error;
-	if ((ret = nla_put(resp_nlmsg, IWPM_NLA_MANAGE_MAPPED_LOC_ADDR,
+	if ((ret = nla_put(resp_nlmsg, IWPM_NLA_RMANAGE_MAPPED_LOC_ADDR,
 				sizeof(struct sockaddr_storage), &iwpm_port->mapped_addr)))
 		goto add_mapping_free_error;
 	if ((ret = nla_put_u16(resp_nlmsg, IWPM_NLA_RMANAGE_MAPPING_ERR, err_code)))
@@ -392,7 +402,8 @@  add_mapping_error:
 static struct nla_policy query_map_policy[IWPM_NLA_QUERY_MAPPING_MAX] = {
         [IWPM_NLA_QUERY_MAPPING_SEQ]         = { .type = NLA_U32 },
         [IWPM_NLA_QUERY_LOCAL_ADDR]          = { .minlen = sizeof(struct sockaddr_storage) },
-        [IWPM_NLA_QUERY_REMOTE_ADDR]         = { .minlen = sizeof(struct sockaddr_storage) }
+        [IWPM_NLA_QUERY_REMOTE_ADDR]         = { .minlen = sizeof(struct sockaddr_storage) },
+        [IWPM_NLA_QUERY_FLAGS]               = { .type = NLA_U32 }
 };
 
 /**
@@ -409,7 +420,7 @@  static int process_iwpm_query_mapping(struct nlmsghdr *req_nlh, int client_idx,
 {
 	iwpm_mapped_port *iwpm_port = NULL;
 	iwpm_mapping_request *iwpm_map_req = NULL;
-	struct nlattr *nltb [IWPM_NLA_QUERY_MAPPING_MAX];
+	struct nlattr *nltb [IWPM_NLA_QUERY_MAPPING_MAX] = {};
 	struct sockaddr_storage *local_addr, *remote_addr;
 	sockaddr_union dest_addr;
 	iwpm_msg_parms msg_parms;
@@ -420,20 +431,25 @@  static int process_iwpm_query_mapping(struct nlmsghdr *req_nlh, int client_idx,
 	const char *msg_type = "Add & Query Mapping Request";
 	const char *str_err = "";
 	int ret = -EINVAL;
+	__u32 flags;
+	int max = IWPM_NLA_QUERY_MAPPING_MAX;
 
-	if (parse_iwpm_nlmsg(req_nlh, IWPM_NLA_QUERY_MAPPING_MAX, query_map_policy, nltb, msg_type)) {
+	if (iwpm_version != IWPM_UABI_VERSION)
+		max--;
+	if (parse_iwpm_nlmsg(req_nlh, max, query_map_policy, nltb, msg_type)) {
 		err_code = IWPM_INVALID_NLMSG_ERR;
 		str_err = "Received Invalid nlmsg";
 		goto query_mapping_error;
 	}
 	local_addr = (struct sockaddr_storage *)nla_data(nltb[IWPM_NLA_QUERY_LOCAL_ADDR]);
 	remote_addr = (struct sockaddr_storage *)nla_data(nltb[IWPM_NLA_QUERY_REMOTE_ADDR]);
+	flags = nltb[IWPM_NLA_QUERY_FLAGS] ? nla_get_u32(nltb[IWPM_NLA_QUERY_FLAGS]) : 0;
 
 	iwpm_port = find_iwpm_mapping(local_addr, not_mapped);
 	if (iwpm_port) {
 		atomic_fetch_add(&iwpm_port->ref_cnt, 1);
 	} else {
-		iwpm_port = create_iwpm_mapped_port(local_addr, client_idx);
+		iwpm_port = create_iwpm_mapped_port(local_addr, client_idx, flags);
 		if (!iwpm_port) {
 			err_code = IWPM_CREATE_MAPPING_ERR;
 			str_err = "Unable to create new mapping";
@@ -530,7 +546,7 @@  static int process_iwpm_remove_mapping(struct nlmsghdr *req_nlh, int client_idx,
 	const char *msg_type = "Remove Mapping Request";
 	int ret = 0;
 
-	if (parse_iwpm_nlmsg(req_nlh, IWPM_NLA_MANAGE_MAPPING_MAX, manage_map_policy, nltb, msg_type)) {
+	if (parse_iwpm_nlmsg(req_nlh, IWPM_NLA_REMOVE_MAPPING_MAX, manage_map_policy, nltb, msg_type)) {
 		send_iwpm_error_msg(req_nlh->nlmsg_seq, IWPM_INVALID_NLMSG_ERR, client_idx, nl_sock);
 		syslog(LOG_WARNING, "process_remove_mapping: Received Invalid nlmsg from client = %d\n",
 				client_idx);
@@ -869,7 +885,8 @@  static int process_iwpm_wire_ack(iwpm_msg_parms *msg_parms)
 /* Mapping info message - nlmsg attributes */
 static struct nla_policy mapinfo_policy[IWPM_NLA_MAPINFO_MAX] = {
         [IWPM_NLA_MAPINFO_LOCAL_ADDR]          = { .minlen = sizeof(struct sockaddr_storage) },
-        [IWPM_NLA_MAPINFO_MAPPED_ADDR]         = { .minlen = sizeof(struct sockaddr_storage) }
+        [IWPM_NLA_MAPINFO_MAPPED_ADDR]         = { .minlen = sizeof(struct sockaddr_storage) },
+        [IWPM_NLA_MAPINFO_FLAGS]               = { .type = NLA_U32 }
 };
 
 /**
@@ -886,20 +903,25 @@  static int process_iwpm_mapinfo(struct nlmsghdr *req_nlh, int client_idx, int nl
 {
 	iwpm_mapped_port *iwpm_port = NULL;
 	struct sockaddr_storage *local_addr, *local_mapped_addr;
-	struct nlattr *nltb [IWPM_NLA_MAPINFO_MAX];
+	struct nlattr *nltb [IWPM_NLA_MAPINFO_MAX] = {};
 	int not_mapped = 1;
 	__u16 err_code = 0;
 	const char *msg_type = "Mapping Info Msg";
 	const char *str_err = "";
 	int ret = -EINVAL;
+	__u32 flags;
+	int max = IWPM_NLA_MAPINFO_MAX;
 
-	if (parse_iwpm_nlmsg(req_nlh, IWPM_NLA_MAPINFO_MAX, mapinfo_policy, nltb, msg_type)) {
+	if (iwpm_version != IWPM_UABI_VERSION)
+		max--;
+	if (parse_iwpm_nlmsg(req_nlh, max, mapinfo_policy, nltb, msg_type)) {
 		err_code = IWPM_INVALID_NLMSG_ERR;
 		str_err = "Received Invalid nlmsg";
 		goto process_mapinfo_error;
 	}
 	local_addr = (struct sockaddr_storage *)nla_data(nltb[IWPM_NLA_MAPINFO_LOCAL_ADDR]);
 	local_mapped_addr = (struct sockaddr_storage *)nla_data(nltb[IWPM_NLA_MAPINFO_MAPPED_ADDR]);
+	flags = nltb[IWPM_NLA_MAPINFO_FLAGS] ? nla_get_u32(nltb[IWPM_NLA_MAPINFO_FLAGS]) : 0;
 
 	iwpm_port = find_iwpm_mapping(local_addr, not_mapped);
 	if (iwpm_port) {
@@ -915,7 +937,7 @@  static int process_iwpm_mapinfo(struct nlmsghdr *req_nlh, int client_idx, int nl
 		str_err = "Duplicate mapped port";
 		goto process_mapinfo_error;
 	}
-	iwpm_port = reopen_iwpm_mapped_port(local_addr, local_mapped_addr, client_idx);
+	iwpm_port = reopen_iwpm_mapped_port(local_addr, local_mapped_addr, client_idx, flags);
 	if (!iwpm_port) {
 		err_code = IWPM_CREATE_MAPPING_ERR;
 		str_err = "Unable to create new mapping";
@@ -1045,6 +1067,63 @@  send_error_msg_exit:
 	return ret;
 }
 
+/* Hello message - nlmsg attributes */
+static struct nla_policy hello_policy[IWPM_NLA_HELLO_MAX] = {
+        [IWPM_NLA_HELLO_ABI_VERSION]  =  { .type = NLA_U16 }
+};
+
+/**
+ * process_iwpm_hello - Process mapinfo count message
+ * @req_nlh: netlink header of the received message from the client
+ * @client_idx: the index of the client
+ * @nl_sock: netlink socket to send a message to the client
+ *
+ * Mapinfo count message is a mechanism for the port mapper and the client to
+ * synchronize on the number of mapinfo messages which were sucessfully exchanged and processed
+ */
+static int process_iwpm_hello(struct nlmsghdr *req_nlh, int client_idx, int nl_sock)
+{
+	struct nlattr *nltb [IWPM_NLA_HELLO_MAX];
+	const char *msg_type = "Hello Msg";
+	__u16 abi_version;
+	__u16 err_code = 0;
+	const char *str_err = "";
+	int ret = -EINVAL;
+
+	if (req_nlh->nlmsg_type == NLMSG_ERROR) {
+		abi_version = IWPM_UABI_VERSION_MIN;
+	} else {
+		if (parse_iwpm_nlmsg(req_nlh, IWPM_NLA_HELLO_MAX,
+						hello_policy, nltb, msg_type)) {
+			str_err = "Received Invalid nlmsg";
+			err_code = IWPM_INVALID_NLMSG_ERR;
+			goto hello_error;
+		}
+		abi_version = nla_get_u16(nltb[IWPM_NLA_HELLO_ABI_VERSION]);
+	}
+	if (abi_version > IWPM_UABI_VERSION) {
+		str_err = "UABI Version mismatch";
+		err_code = IWPM_VERSION_MISMATCH_ERR;
+		goto hello_error;
+	}
+	iwpm_version = abi_version;
+	iwpm_debug(IWARP_PM_NETLINK_DBG, "process_iwpm_hello: using abi_version %u\n", iwpm_version);
+
+	send_iwpm_mapinfo_request(nl_sock, RDMA_NL_IWCM);
+	if (iwpm_version == 3) {
+		/* Legacy RDMA_NL_C4IW for old kernels */
+		send_iwpm_mapinfo_request(nl_sock, RDMA_NL_IWCM+1);
+	}
+	return 0;
+hello_error:
+	syslog(LOG_WARNING, "process_iwpm_hello: %s.\n", str_err);
+	if (err_code) {
+		/* send error message to the client */
+		send_iwpm_error_msg(req_nlh->nlmsg_seq, err_code, client_idx, nl_sock);
+	}
+	return ret;
+}
+
 /**
  * process_iwpm_netlink_msg - Dispatch received netlink messages
  * @nl_sock: netlink socket to read the messages from
@@ -1084,13 +1163,19 @@  static int process_iwpm_netlink_msg(int nl_sock)
 			goto process_netlink_msg_exit;
 		}
 
-		if (nlh->nlmsg_type == NLMSG_ERROR) {
-			iwpm_debug(IWARP_PM_NETLINK_DBG, "process_netlink_msg: "
+		type = nlh->nlmsg_type;
+		client_idx = RDMA_NL_GET_CLIENT(type);
+		if (type == NLMSG_ERROR) {
+
+			/* RDMA_NL_IWCM HELLO error indicates V3 kernel */
+			if (nlh->nlmsg_seq == 0) {
+				ret = process_iwpm_hello(nlh, client_idx, nl_sock);
+			} else {
+				iwpm_debug(IWARP_PM_NETLINK_DBG, "process_netlink_msg: "
 					"Netlink error message seq = %u\n", nlh->nlmsg_seq);
+			}
 			goto process_netlink_msg_exit;
 		}
-		type = nlh->nlmsg_type;
-		client_idx = RDMA_NL_GET_CLIENT(type);
 		op = RDMA_NL_GET_OP(type);
 		iwpm_debug(IWARP_PM_NETLINK_DBG, "process_netlink_msg: Received a new message: "
 				"opcode = %u client idx = %u, client pid = %u,"
@@ -1133,6 +1218,9 @@  static int process_iwpm_netlink_msg(int nl_sock)
 		case RDMA_NL_IWPM_MAPINFO_NUM:
 			ret = process_iwpm_mapinfo_count(nlh, client_idx, nl_sock);
 			break;
+		case RDMA_NL_IWPM_HELLO:
+			ret = process_iwpm_hello(nlh, client_idx, nl_sock);
+			break;
 		default:
 			str_err = "Netlink message with invalid opcode";
 			ret = -1;
@@ -1202,55 +1290,79 @@  process_iwpm_msg_exit:
 }
 
 /**
- * init_iwpm_clients - Initialize the known clients of the iwarp port mapper
- * @iwarp_clients - array of port mapper clients to init
+ * send_iwpm_hello - Notify the client that the V4 iwarp port mapper is available
+ * @nl_sock: netlink socket to send a message to the client
  *
- * Return the number of known clients
+ * Send a HELLO message including the ABI_VERSION supported by iwpmd.  If the
+ * response is an ERROR message, then we know the kernel driver is < V4, so we
+ * drop back to the V3 protocol.  If the kernel is >= V4, then it will reply
+ * with its ABI Version.  The response is handled in iwarp_port_mapper().  Once
+ * the ABI version is negotiatied, iwpmd will send a mapinfo request to get any
+ * current mappings, using the correct ABI version. This allows working with
+ * V3 kernels.
  */
-static int init_iwpm_clients(__u32 iwarp_clients[])
+static int send_iwpm_hello(int nl_sock)
 {
-	int client_num = 2;
+	struct nl_msg *req_nlmsg;
+	const char *str_err;
+	__u16 nlmsg_type;
+	int ret;
 
-	iwarp_clients[0] = RDMA_NL_IWCM;
-	iwarp_clients[1] = RDMA_NL_IWCM+1; /* Legacy RDMA_NL_C4IW for old kernels */
+	nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_IWCM, RDMA_NL_IWPM_HELLO);
+	req_nlmsg = create_iwpm_nlmsg(nlmsg_type, RDMA_NL_IWCM);
+	if (!req_nlmsg) {
+		ret = -ENOMEM;
+		str_err = "Unable to create nlmsg request";
+		goto send_hello_error;
+	}
+	str_err = "Invalid nlmsg attribute";
+	if ((ret = nla_put_u16(req_nlmsg, IWPM_NLA_HELLO_ABI_VERSION, iwpm_version)))
+		goto send_hello_error;
 
-	return client_num;
+	if ((ret = send_iwpm_nlmsg(nl_sock, req_nlmsg, 0))) {
+		str_err = "Unable to send nlmsg response";
+		goto send_hello_error;
+	}
+	nlmsg_free(req_nlmsg);
+	return 0;
+send_hello_error:
+	if (req_nlmsg)
+		nlmsg_free(req_nlmsg);
+	syslog(LOG_WARNING, "send_hello_request: %s ret = %d.\n", str_err, ret);
+	return ret;
 }
 
 /**
  * send_iwpm_mapinfo_request - Notify the client that the iwarp port mapper is available
  * @nl_sock: netlink socket to send a message to the client
- * @iwarp_clients - array of port mapper clients to init
- * @length - the length of the array
+ * @client - client to receive the message
  */
-static int send_iwpm_mapinfo_request(int nl_sock, __u32 *iwarp_clients, int length)
+static int send_iwpm_mapinfo_request(int nl_sock, int client)
 {
 	struct nl_msg *req_nlmsg;
 	__u16 nlmsg_type;
-	int i;
 	const char *str_err;
 	int ret;
 
-	for (i = 0; i < length; i++) {
-		nlmsg_type = RDMA_NL_GET_TYPE(iwarp_clients[i], RDMA_NL_IWPM_MAPINFO);
-		req_nlmsg = create_iwpm_nlmsg(nlmsg_type, iwarp_clients[i]);
-		if (!req_nlmsg) {
-			ret = -ENOMEM;
-			str_err = "Unable to create nlmsg request";
-			goto send_mapinfo_error;
-		}
-		str_err = "Invalid nlmsg attribute";
-		if ((ret = nla_put_string(req_nlmsg, IWPM_NLA_MAPINFO_ULIB_NAME, iwpm_ulib_name)))
-			goto send_mapinfo_error;
-		if ((ret = nla_put_u16(req_nlmsg, IWPM_NLA_MAPINFO_ULIB_VER, iwpm_version)))
-			goto send_mapinfo_error;
-
-		if ((ret = send_iwpm_nlmsg(nl_sock, req_nlmsg, 0))) {
-			str_err = "Unable to send nlmsg response";
-			goto send_mapinfo_error;
-		}
-		nlmsg_free(req_nlmsg);
+	nlmsg_type = RDMA_NL_GET_TYPE(client, RDMA_NL_IWPM_MAPINFO);
+	req_nlmsg = create_iwpm_nlmsg(nlmsg_type, client);
+	if (!req_nlmsg) {
+		ret = -ENOMEM;
+		str_err = "Unable to create nlmsg request";
+		goto send_mapinfo_error;
 	}
+	str_err = "Invalid nlmsg attribute";
+	if ((ret = nla_put_string(req_nlmsg, IWPM_NLA_MAPINFO_ULIB_NAME, iwpm_ulib_name)))
+		goto send_mapinfo_error;
+
+	if ((ret = nla_put_u16(req_nlmsg, IWPM_NLA_MAPINFO_ULIB_VER, iwpm_version)))
+		goto send_mapinfo_error;
+
+	if ((ret = send_iwpm_nlmsg(nl_sock, req_nlmsg, 0))) {
+		str_err = "Unable to send nlmsg response";
+		goto send_mapinfo_error;
+	}
+	nlmsg_free(req_nlmsg);
 	return 0;
 send_mapinfo_error:
 	if (req_nlmsg)
@@ -1366,8 +1478,6 @@  static void daemonize_iwpm_server(void)
 
 int main(int argc, char *argv[])
 {
-	__u32 iwarp_clients[IWARP_PM_MAX_CLIENTS];
-	int known_clients;
 	FILE *fp;
 	int c;
 	int ret = EXIT_FAILURE;
@@ -1441,8 +1551,9 @@  int main(int argc, char *argv[])
 	if (ret)
 		goto error_exit;
 
-	known_clients = init_iwpm_clients(&iwarp_clients[0]);
-	send_iwpm_mapinfo_request(netlink_sock, &iwarp_clients[0], known_clients);
+	ret = send_iwpm_hello(netlink_sock);
+	if (ret)
+		goto error_exit;
 
 	if (systemd)
 		sd_notify(0, "READY=1");