[PATCH ibacm 1/4] ibacm: Allocate end-point addresses dynamically - v2

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

 



ibacm has a fixed number (4) of end-point addresses. An endpoint is
associated with the node GUID. Hence, if a system is brought up with
VFs enabled, ibacm will not be able to handle the end-point addresses.

When adding an address, the default provider, acmp, saves a pointer
into ibacm's acmc_ep addr_info attribute. But this may now be
re-allocated. Its generally a bad idea to have pointers in the
provider(s) pointing into acm's data structures.

This is fixed in acmp by changing struct acmp_addr to contain struct
acm_address instead of a pointer to it, and copying the address,
similar to how the info struct is handled.

In acm_svr_ep_query(), dynamic allocation and conditional reallocating
is implemented, in the case the number of end-point addresses exceeds
the fixed size of struct acm_msg. A re-factoring in
acm_nl_process_resolve() and in the acm_svr_foo_bar() functions was
necessary to accommodate the dynamic allocation of struct acm_msg.

In acm_if_iter_sys(), the number of struct ifreq's was increased to
256, in order to be able to test with up-to 256 addresses when ibacm
starts.

Finally, in ib_acm_enum_ep(), the read() was split in two, first read
the hdr, then determine the size of the rest of the data, allocate it,
and read them. To avoid endian conversion to/from the same structure,
two structures were allocated for simplicity.

Signed-off-by: Håkon Bugge <haakon.bugge@xxxxxxxxxx>
---
 ibacm/prov/acmp/src/acmp.c |   6 +-
 ibacm/src/acm.c            | 155 +++++++++++++++++++++++++++++++--------------
 ibacm/src/acm_util.c       |   2 +-
 ibacm/src/libacm.c         |  50 ++++++++++-----
 4 files changed, 145 insertions(+), 68 deletions(-)

diff --git a/ibacm/prov/acmp/src/acmp.c b/ibacm/prov/acmp/src/acmp.c
index c10e62c0..f63f1dbf 100644
--- a/ibacm/prov/acmp/src/acmp.c
+++ b/ibacm/prov/acmp/src/acmp.c
@@ -166,7 +166,7 @@ struct acmp_send_queue {
 struct acmp_addr {
 	uint16_t              type;
 	union acm_ep_info     info;
-	struct acm_address    *addr;
+	struct acm_address    addr;
 	struct acmp_ep        *ep;
 };
 
@@ -2379,7 +2379,7 @@ static int acmp_add_addr(const struct acm_address *addr, void *ep_context,
 	}
 	ep->addr_info[i].type = addr->type;
 	memcpy(&ep->addr_info[i].info, &addr->info, sizeof(addr->info));
-	ep->addr_info[i].addr = (struct acm_address *) addr;
+	memcpy(&ep->addr_info[i].addr, addr, sizeof(*addr));
 	ep->addr_info[i].ep = ep;
 
 	if (loopback_prot != ACMP_LOOPBACK_PROT_LOCAL) {
@@ -2439,7 +2439,7 @@ static void acmp_remove_addr(void *addr_context)
 			pthread_mutex_lock(&port->lock);
 			list_for_each(&port->ep_list, ep, entry) {
 				pthread_mutex_unlock(&port->lock);
-				dest = acmp_get_dest(ep, address->type, address->addr->info.addr);
+				dest = acmp_get_dest(ep, address->type, address->addr.info.addr);
 				if (dest) {
 					acm_log(2, "Found a dest addr, deleting it\n");
 					pthread_mutex_lock(&ep->lock);
diff --git a/ibacm/src/acm.c b/ibacm/src/acm.c
index 182e89d9..6a02f33d 100644
--- a/ibacm/src/acm.c
+++ b/ibacm/src/acm.c
@@ -72,7 +72,6 @@
 #define src_index   data[1]
 #define dst_index   data[2]
 
-#define MAX_EP_ADDR 4
 #define NL_MSG_BUF_SIZE 4096
 #define ACM_PROV_NAME_SIZE 64
 #define NL_CLIENT_INDEX 0
@@ -139,7 +138,8 @@ struct acmc_ep {
 	struct acmc_port      *port;
 	struct acm_endpoint   endpoint;
 	void                  *prov_ep_context;
-	struct acmc_addr      addr_info[MAX_EP_ADDR];
+	int                   nmbr_ep_addrs;
+	struct acmc_addr      *addr_info;
 	struct list_node      entry;
 };
 
@@ -421,7 +421,7 @@ static void acm_mark_addr_invalid(struct acmc_ep *ep,
 {
 	int i;
 
-	for (i = 0; i < MAX_EP_ADDR; i++) {
+	for (i = 0; i < ep->nmbr_ep_addrs; i++) {
 		if (!acm_addr_cmp(&ep->addr_info[i].addr, data->info.addr, data->type)) {
 			ep->addr_info[i].addr.type = ACM_ADDRESS_INVALID;
 			ep->port->prov->remove_address(ep->addr_info[i].prov_addr_context);
@@ -437,7 +437,7 @@ acm_addr_lookup(const struct acm_endpoint *endpoint, uint8_t *addr, uint8_t addr
 	int i;
 
 	ep = container_of(endpoint, struct acmc_ep, endpoint);
-	for (i = 0; i < MAX_EP_ADDR; i++)
+	for (i = 0; i < ep->nmbr_ep_addrs; i++)
 		if (!acm_addr_cmp(&ep->addr_info[i].addr, addr, addr_type))
 			return &ep->addr_info[i].addr;
 
@@ -838,7 +838,7 @@ acm_get_port_ep_address(struct acmc_port *port, struct acm_ep_addr_data *data)
 		if ((data->type == ACM_EP_INFO_PATH) &&
 		    (!data->info.path.pkey ||
 		     (be16toh(data->info.path.pkey) == ep->endpoint.pkey))) {
-			for (i = 0; i < MAX_EP_ADDR; i++) {
+			for (i = 0; i < ep->nmbr_ep_addrs; i++) {
 				if (ep->addr_info[i].addr.type)
 					return &ep->addr_info[i];
 			}
@@ -1118,17 +1118,22 @@ acm_svr_resolve_path(struct acmc_client *client, struct acm_msg *msg)
 
 static int acm_svr_resolve(struct acmc_client *client, struct acm_msg *msg)
 {
+	int ret = 0;
+
 	(void) atomic_inc(&client->refcnt);
 
 	if (msg->resolve_data[0].type == ACM_EP_INFO_PATH) {
 		if (msg->resolve_data[0].flags & ACM_FLAGS_QUERY_SA) {
-			return acm_svr_query_path(client, msg);
+			ret = acm_svr_query_path(client, msg);
 		} else {
-			return acm_svr_resolve_path(client, msg);
+			ret = acm_svr_resolve_path(client, msg);
 		}
 	} else {
-		return acm_svr_resolve_dest(client, msg);
+		ret = acm_svr_resolve_dest(client, msg);
 	}
+
+	free(msg);
+	return ret;
 }
 
 static int acm_svr_perf_query(struct acmc_client *client, struct acm_msg *msg)
@@ -1181,15 +1186,48 @@ static int acm_svr_perf_query(struct acmc_client *client, struct acm_msg *msg)
 	else
 		ret = 0;
 
+	free(msg);
 	return ret;
 }
 
+static int may_be_realloc(struct acm_msg **msg_ptr,
+			int len,
+			int cnt,
+			int *cur_msg_siz_ptr,
+			int max_msg_siz)
+{
+
+	/* Check if a new address exceeds the protocol constrained max size */
+	if (len + (cnt + 1) * ACM_MAX_ADDRESS > max_msg_siz) {
+		acm_log(0, "ERROR - unable to amend more addresses to acm_msg due to protocol constraints\n");
+		return ENOMEM;
+	}
+
+	/* Check if a new address exeeds current size of msg */
+	if (len + (cnt + 1) * ACM_MAX_ADDRESS > *cur_msg_siz_ptr) {
+		const size_t chunk_size = 16 * ACM_MAX_ADDRESS;
+		struct acm_msg *new_msg = realloc(*msg_ptr, *cur_msg_siz_ptr + chunk_size);
+
+		if (!new_msg) {
+			acm_log(0, "ERROR - failed to allocate longer acm_msg\n");
+			return ENOMEM;
+		}
+
+		*msg_ptr = new_msg;
+		*cur_msg_siz_ptr += chunk_size;
+	}
+
+	return 0;
+}
+
 static int acm_svr_ep_query(struct acmc_client *client, struct acm_msg *msg)
 {
 	int ret, i;
 	uint16_t len;
 	struct acmc_ep *ep;
 	int index, cnt = 0;
+	int cur_msg_siz = sizeof(*msg);
+	int max_msg_siz = USHRT_MAX;
 
 	acm_log(2, "client %d\n", client->index);
 	index = msg->hdr.data[0];
@@ -1203,8 +1241,10 @@ static int acm_svr_ep_query(struct acmc_client *client, struct acm_msg *msg)
 			ACM_MAX_PROV_NAME - 1);
 		msg->ep_data[0].prov_name[ACM_MAX_PROV_NAME - 1] = '\0';
 		len = ACM_MSG_HDR_LENGTH + sizeof(struct acm_ep_config_data);
-		for (i = 0; i < MAX_EP_ADDR; i++) {
+		for (i = 0; i < ep->nmbr_ep_addrs; i++) {
 			if (ep->addr_info[i].addr.type != ACM_ADDRESS_INVALID) {
+				if (may_be_realloc(&msg, len, cnt, &cur_msg_siz, max_msg_siz))
+					break;
 				memcpy(msg->ep_data[0].addrs[cnt++].name,
 				       ep->addr_info[i].string_buf,
 				       ACM_MAX_ADDRESS);
@@ -1227,6 +1267,7 @@ static int acm_svr_ep_query(struct acmc_client *client, struct acm_msg *msg)
 	else
 		ret = 0;
 
+	free(msg);
 	return ret;
 }
 
@@ -1238,38 +1279,47 @@ static int acm_msg_length(struct acm_msg *msg)
 
 static void acm_svr_receive(struct acmc_client *client)
 {
-	struct acm_msg msg;
+	struct acm_msg *msg = malloc(sizeof(*msg));
 	int ret;
 
+	if (!msg) {
+		acm_log(0, "ERROR - Unable to alloc acm_msg\n");
+		ret = ENOMEM;
+		goto out;
+	}
+
 	acm_log(2, "client %d\n", client->index);
-	ret = recv(client->sock, (char *) &msg, sizeof msg, 0);
-	if (ret <= 0 || ret != acm_msg_length(&msg)) {
+	ret = recv(client->sock, (char *) msg, sizeof(*msg), 0);
+	if (ret <= 0 || ret != acm_msg_length(msg)) {
 		acm_log(2, "client disconnected\n");
 		ret = ACM_STATUS_ENOTCONN;
-		goto out;
+		goto out_free;
 	}
 
-	if (msg.hdr.version != ACM_VERSION) {
-		acm_log(0, "ERROR - unsupported version %d\n", msg.hdr.version);
-		goto out;
+	if (msg->hdr.version != ACM_VERSION) {
+		acm_log(0, "ERROR - unsupported version %d\n", msg->hdr.version);
+		goto out_free;
 	}
 
-	switch (msg.hdr.opcode & ACM_OP_MASK) {
+	switch (msg->hdr.opcode & ACM_OP_MASK) {
 	case ACM_OP_RESOLVE:
 		atomic_inc(&counter[ACM_CNTR_RESOLVE]);
-		ret = acm_svr_resolve(client, &msg);
-		break;
+		ret = acm_svr_resolve(client, msg);
+		goto out;
 	case ACM_OP_PERF_QUERY:
-		ret = acm_svr_perf_query(client, &msg);
-		break;
+		ret = acm_svr_perf_query(client, msg);
+		goto out;
 	case ACM_OP_EP_QUERY:
-		ret = acm_svr_ep_query(client, &msg);
-		break;
+		ret = acm_svr_ep_query(client, msg);
+		goto out;
 	default:
-		acm_log(0, "ERROR - unknown opcode 0x%x\n", msg.hdr.opcode);
+		acm_log(0, "ERROR - unknown opcode 0x%x\n", msg->hdr.opcode);
 		break;
 	}
 
+out_free:
+	free(msg);
+
 out:
 	if (ret)
 		acm_disconnect_client(client);
@@ -1412,7 +1462,7 @@ static int resync_system_ips(void)
 			port = &dev->port[cnt];
 
 			list_for_each(&port->ep_list, ep, entry) {
-				for (i = 0; i < MAX_EP_ADDR; i++) {
+				for (i = 0; i < ep->nmbr_ep_addrs; i++) {
 					if (ep->addr_info[i].addr.type == ACM_ADDRESS_IP ||
 					    ep->addr_info[i].addr.type == ACM_ADDRESS_IP6)
 						ep->addr_info[i].addr.type = ACM_ADDRESS_INVALID;
@@ -1672,7 +1722,7 @@ static void acm_nl_process_invalid_request(struct acmc_client *client,
 static void acm_nl_process_resolve(struct acmc_client *client,
 				   struct acm_nl_msg *acmnlmsg)
 {
-	struct acm_msg msg;
+	struct acm_msg *msg = malloc(sizeof(*msg));
 	struct nlattr *attr;
 	int payload_len;
 	int resolve_hdr_len;
@@ -1681,21 +1731,26 @@ static void acm_nl_process_resolve(struct acmc_client *client,
 	int status;
 	unsigned char *data;
 
-	memset(&msg, 0, sizeof(msg));
-	msg.hdr.opcode = ACM_OP_RESOLVE;
-	msg.hdr.version = ACM_VERSION;
-	msg.hdr.length = ACM_MSG_HDR_LENGTH + ACM_MSG_EP_LENGTH;
-	msg.hdr.status = ACM_STATUS_SUCCESS;
-	msg.hdr.tid = (uintptr_t) acmnlmsg;
-	msg.resolve_data[0].type = ACM_EP_INFO_PATH;
+	if (!msg) {
+		acm_log(0, "ERROR - Unable to allocate msg\n");
+		return;
+	}
+
+	memset(msg, 0, sizeof(*msg));
+	msg->hdr.opcode = ACM_OP_RESOLVE;
+	msg->hdr.version = ACM_VERSION;
+	msg->hdr.length = ACM_MSG_HDR_LENGTH + ACM_MSG_EP_LENGTH;
+	msg->hdr.status = ACM_STATUS_SUCCESS;
+	msg->hdr.tid = (uintptr_t) acmnlmsg;
+	msg->resolve_data[0].type = ACM_EP_INFO_PATH;
 
 	/* We support only one pathrecord */
 	acm_log(2, "path use 0x%x\n", acmnlmsg->resolve_header.path_use);
 	if (acmnlmsg->resolve_header.path_use ==
 	    LS_RESOLVE_PATH_USE_UNIDIRECTIONAL)
-		msg.resolve_data[0].info.path.reversible_numpath = 1;
+		msg->resolve_data[0].info.path.reversible_numpath = 1;
 	else
-		msg.resolve_data[0].info.path.reversible_numpath =
+		msg->resolve_data[0].info.path.reversible_numpath =
 			IBV_PATH_RECORD_REVERSIBLE | 1;
 
 	data = (unsigned char *) &acmnlmsg->nlmsg_header + NLMSG_HDRLEN;
@@ -1710,7 +1765,7 @@ static void acm_nl_process_resolve(struct acmc_client *client,
 		    attr->nla_len > rem)
 			break;
 
-		status = acm_nl_parse_path_attr(attr, &msg.resolve_data[0]);
+		status = acm_nl_parse_path_attr(attr, &msg->resolve_data[0]);
 		if (status) {
 			acm_nl_process_invalid_request(client, acmnlmsg);
 			return;
@@ -1723,7 +1778,7 @@ static void acm_nl_process_resolve(struct acmc_client *client,
 	}
 
 	atomic_inc(&counter[ACM_CNTR_RESOLVE]);
-	acm_svr_resolve(client, &msg);
+	acm_svr_resolve(client, msg);
 }
 
 static int acm_nl_is_valid_resolve_request(struct acm_nl_msg *acmnlmsg)
@@ -2018,12 +2073,21 @@ acm_ep_insert_addr(struct acmc_ep *ep, const char *name, uint8_t *addr,
 	memcpy(tmp, addr, acm_addr_len(addr_type));
 
 	if (!acm_addr_lookup(&ep->endpoint, addr, addr_type)) {
-		for (i = 0; (i < MAX_EP_ADDR) &&
+		for (i = 0; (i < ep->nmbr_ep_addrs) &&
 			    (ep->addr_info[i].addr.type != ACM_ADDRESS_INVALID); i++)
 			;
-		if (i == MAX_EP_ADDR) {
-			ret = ENOMEM;
-			goto out;
+		if (i == ep->nmbr_ep_addrs) {
+			++ep->nmbr_ep_addrs;
+			ep->addr_info = realloc(ep->addr_info, ep->nmbr_ep_addrs * sizeof(*ep->addr_info));
+			if (!ep->addr_info) {
+				ret = ENOMEM;
+				--ep->nmbr_ep_addrs;
+				goto out;
+			}
+			/* Added memory is not initialized */
+			memset(ep->addr_info + i, 0, sizeof(*ep->addr_info));
+			ep->addr_info[i].addr.endpoint = &ep->endpoint;
+			ep->addr_info[i].addr.id_string = ep->addr_info[i].string_buf;
 		}
 
 		/* Open the provider endpoint only if at least a name or
@@ -2194,7 +2258,7 @@ static void acm_ep_down(struct acmc_ep *ep)
 	acm_log(1, "%s %d pkey 0x%04x\n",
 		ep->port->dev->device.verbs->device->name,
 		ep->port->port.port_num, ep->endpoint.pkey);
-	for (i = 0; i < MAX_EP_ADDR; i++) {
+	for (i = 0; i < ep->nmbr_ep_addrs; i++) {
 		if (ep->addr_info[i].addr.type &&
 		    ep->addr_info[i].prov_addr_context)
 			ep->port->prov->remove_address(ep->addr_info[i].
@@ -2211,7 +2275,6 @@ static struct acmc_ep *
 acm_alloc_ep(struct acmc_port *port, uint16_t pkey)
 {
 	struct acmc_ep *ep;
-	int i;
 
 	acm_log(1, "\n");
 	ep = calloc(1, sizeof *ep);
@@ -2221,11 +2284,7 @@ acm_alloc_ep(struct acmc_port *port, uint16_t pkey)
 	ep->port = port;
 	ep->endpoint.port = &port->port;
 	ep->endpoint.pkey = pkey;
-
-	for (i = 0; i < MAX_EP_ADDR; i++) {
-		ep->addr_info[i].addr.endpoint = &ep->endpoint;
-		ep->addr_info[i].addr.id_string = ep->addr_info[i].string_buf;
-	}
+	ep->nmbr_ep_addrs = 0;
 
 	return ep;
 }
diff --git a/ibacm/src/acm_util.c b/ibacm/src/acm_util.c
index f4654f12..0cc23304 100644
--- a/ibacm/src/acm_util.c
+++ b/ibacm/src/acm_util.c
@@ -143,7 +143,7 @@ int acm_if_iter_sys(acm_if_iter_cb cb, void *ctx)
 			return -1;
 	}
 
-	len = sizeof(*ifc) + sizeof(*ifr) * 64;
+	len = sizeof(*ifc) + sizeof(*ifr) * 256;
 	ifc = malloc(len);
 	if (!ifc) {
 		ret = -1;
diff --git a/ibacm/src/libacm.c b/ibacm/src/libacm.c
index 1d9d7145..8f0bfc2a 100644
--- a/ibacm/src/libacm.c
+++ b/ibacm/src/libacm.c
@@ -384,11 +384,13 @@ out:
 
 int ib_acm_enum_ep(int index, struct acm_ep_config_data **data)
 {
+	struct acm_ep_config_data *netw_edata = NULL;
+	struct acm_ep_config_data *host_edata = NULL;
 	struct acm_msg msg;
+	struct acm_hdr hdr;
 	int ret;
 	int len;
-	int cnt;
-	struct acm_ep_config_data *edata;
+	int i;
 
 	pthread_mutex_lock(&acm_lock);
 	memset(&msg, 0, sizeof msg);
@@ -401,33 +403,49 @@ int ib_acm_enum_ep(int index, struct acm_ep_config_data **data)
 	if (ret != ACM_MSG_HDR_LENGTH)
 		goto out;
 
-	ret = recv(sock, (char *) &msg, sizeof msg, 0);
-	if (ret < ACM_MSG_HDR_LENGTH || ret != be16toh(msg.hdr.length)) {
+	ret = recv(sock, (char *) &hdr, sizeof(hdr), 0);
+	if (ret != sizeof(hdr)) {
 		ret = ACM_STATUS_EINVAL;
 		goto out;
 	}
 
-	if (msg.hdr.status) {
-		ret = acm_error(msg.hdr.status);
+	if (hdr.status) {
+		ret = acm_error(hdr.status);
 		goto out;
 	}
 
-	cnt = be16toh(msg.ep_data[0].addr_cnt);
-	len = sizeof(struct acm_ep_config_data) +
-		ACM_MAX_ADDRESS * cnt;
-	edata = malloc(len);
-	if (!edata) {
+	len = be16toh(hdr.length) - sizeof(hdr);
+	netw_edata = (struct acm_ep_config_data *)malloc(len);
+	host_edata = (struct acm_ep_config_data *)malloc(len);
+	if (!netw_edata || !host_edata) {
 		ret = ACM_STATUS_ENOMEM;
 		goto out;
 	}
 
-	memcpy(edata, &msg.ep_data[0], len);
-	edata->dev_guid = be64toh(msg.ep_data[0].dev_guid);
-	edata->pkey = be16toh(msg.ep_data[0].pkey);
-	edata->addr_cnt = cnt;
-	*data = edata;
+	ret = recv(sock, (char *)netw_edata, len, 0);
+	if (ret != len) {
+		ret = ACM_STATUS_EINVAL;
+		goto out;
+	}
+
+	host_edata->dev_guid	= be64toh(netw_edata->dev_guid);
+	host_edata->port_num	=         netw_edata->port_num;
+	host_edata->pkey	= be16toh(netw_edata->pkey);
+	host_edata->addr_cnt	= be16toh(netw_edata->addr_cnt);
+
+	memcpy(host_edata->prov_name, netw_edata->prov_name,
+	       sizeof(host_edata->prov_name));
+
+	for (i = 0; i < host_edata->addr_cnt; ++i)
+		host_edata->addrs[i] = netw_edata->addrs[i];
+
+	*data = host_edata;
 	ret = 0;
 out:
+	if (ret)
+		free(host_edata);
+	free(netw_edata);
+
 	pthread_mutex_unlock(&acm_lock);
 	return ret;
 }
-- 
2.14.3




[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