@@ -37,6 +37,7 @@
#define ACM_OP_MASK 0x0F
#define ACM_OP_RESOLVE 0x01
+#define ACM_OP_PERF_QUERY 0x02
#define ACM_OP_ACK 0x80
#define ACM_STATUS_SUCCESS 0
@@ -66,7 +67,7 @@ struct acm_hdr {
uint8_t version;
uint8_t opcode;
uint8_t status;
- uint8_t reserved[3];
+ uint8_t data[3];
uint16_t length;
uint64_t tid;
};
@@ -97,6 +98,22 @@ struct acm_resolve_msg {
struct acm_ep_addr_data data[0];
};
+enum {
+ ACM_CNTR_ERROR,
+ ACM_CNTR_RESOLVE,
+ ACM_CNTR_NODATA,
+ ACM_CNTR_ADDR_QUERY,
+ ACM_CNTR_ADDR_CACHE,
+ ACM_CNTR_ROUTE_QUERY,
+ ACM_CNTR_ROUTE_CACHE,
+ ACM_MAX_COUNTER
+};
+
+struct acm_perf_msg {
+ struct acm_hdr hdr;
+ uint64_t data[0];
+};
+
struct acm_msg {
struct acm_hdr hdr;
uint8_t data[ACM_MSG_DATA_LENGTH];
@@ -47,7 +47,7 @@
#include <search.h>
#include "acm_mad.h"
-#define src_out reserved[0]
+#define src_out data[0]
#define MAX_EP_ADDR 4
#define MAX_EP_MC 2
@@ -194,7 +194,11 @@ static struct acm_client client[FD_SETSIZE - 1];
static FILE *flog;
static lock_t log_lock;
PER_THREAD char log_data[ACM_MAX_ADDRESS];
+static atomic_t counter[ACM_MAX_COUNTER];
+/*
+ * Service options - may be set through acm_opts file.
+ */
static char *opts_file = "/etc/ibacm/acm_opts.cfg";
static char *addr_file = "/etc/ibacm/acm_addr.cfg";
static char log_file[128] = "/var/log/ibacm.log";
@@ -893,6 +897,7 @@ static uint8_t acm_resolve_path(struct acm_ep *ep, struct acm_dest *dest,
memcpy(mad->data, &dest->path, sizeof(dest->path));
mad->comp_mask = acm_path_comp_mask(&dest->path);
+ atomic_inc(&counter[ACM_CNTR_ROUTE_QUERY]);
dest->state = ACM_QUERY_ROUTE;
acm_post_send(&ep->sa_queue, msg);
return ACM_STATUS_SUCCESS;
@@ -1004,6 +1009,11 @@ acm_client_resolve_resp(struct acm_client *client, struct acm_resolve_msg *req_m
acm_log(2, "client %d, status 0x%x\n", client->index, status);
memset(&msg, 0, sizeof msg);
+ if (status == ACM_STATUS_ENODATA)
+ atomic_inc(&counter[ACM_CNTR_NODATA]);
+ else if (status)
+ atomic_inc(&counter[ACM_CNTR_ERROR]);
+
lock_acquire(&client->lock);
if (client->sock == INVALID_SOCKET) {
acm_log(0, "ERROR - connection lost\n");
@@ -1015,7 +1025,7 @@ acm_client_resolve_resp(struct acm_client *client, struct acm_resolve_msg *req_m
resp_msg->hdr.opcode |= ACM_OP_ACK;
resp_msg->hdr.status = status;
resp_msg->hdr.length = ACM_MSG_HDR_LENGTH;
- memset(resp_msg->hdr.reserved, 0, sizeof(resp_msg->hdr.reserved));
+ memset(resp_msg->hdr.data, 0, sizeof(resp_msg->hdr.data));
if (status == ACM_STATUS_SUCCESS) {
resp_msg->hdr.length += ACM_MSG_EP_LENGTH;
@@ -1848,6 +1858,7 @@ acm_svr_query_path(struct acm_client *client, struct acm_resolve_msg *msg)
memcpy(mad->data, &msg->data[0].info.path, sizeof(struct ibv_path_record));
mad->comp_mask = acm_path_comp_mask(&msg->data[0].info.path);
+ atomic_inc(&counter[ACM_CNTR_ROUTE_QUERY]);
acm_post_send(&ep->sa_queue, sa_msg);
return ACM_STATUS_SUCCESS;
@@ -1896,6 +1907,7 @@ acm_send_resolve(struct acm_ep *ep, struct acm_dest *dest,
for (i = 0; i < ep->mc_cnt; i++)
memcpy(&rec->gid[i], ep->mc_dest[i].address, 16);
+ atomic_inc(&counter[ACM_CNTR_ADDR_QUERY]);
acm_post_send(&ep->resolve_queue, msg);
return 0;
}
@@ -2038,7 +2050,7 @@ acm_svr_queue_req(struct acm_dest *dest, struct acm_client *client,
}
static int
-acm_svr_resolve(struct acm_client *client, struct acm_resolve_msg *msg)
+acm_svr_resolve_dest(struct acm_client *client, struct acm_resolve_msg *msg)
{
struct acm_ep *ep;
struct acm_dest *dest;
@@ -2082,10 +2094,12 @@ acm_svr_resolve(struct acm_client *client, struct acm_resolve_msg *msg)
switch (dest->state) {
case ACM_READY:
acm_log(2, "request satisfied from local cache\n");
+ atomic_inc(&counter[ACM_CNTR_ROUTE_CACHE]);
status = ACM_STATUS_SUCCESS;
break;
case ACM_ADDR_RESOLVED:
acm_log(2, "have address, resolving route\n");
+ atomic_inc(&counter[ACM_CNTR_ADDR_CACHE]);
status = acm_resolve_path(ep, dest, acm_dest_sa_resp);
if (status) {
break;
@@ -2175,6 +2189,7 @@ acm_svr_resolve_path(struct acm_client *client, struct acm_resolve_msg *msg)
switch (dest->state) {
case ACM_READY:
acm_log(2, "request satisfied from local cache\n");
+ atomic_inc(&counter[ACM_CNTR_ROUTE_CACHE]);
status = ACM_STATUS_SUCCESS;
break;
case ACM_INIT:
@@ -2209,10 +2224,46 @@ put:
return ret;
}
+static int acm_svr_resolve(struct acm_client *client, struct acm_resolve_msg *msg)
+{
+ if (msg->data[0].type == ACM_EP_INFO_PATH) {
+ if (msg->data[0].flags & ACM_FLAGS_QUERY_SA) {
+ return acm_svr_query_path(client, msg);
+ } else {
+ return acm_svr_resolve_path(client, msg);
+ }
+ } else {
+ return acm_svr_resolve_dest(client, msg);
+ }
+}
+
+static int acm_svr_perf_query(struct acm_client *client, struct acm_perf_msg *msg)
+{
+ int ret, i;
+
+ acm_log(2, "client %d\n", client->index);
+ msg->hdr.opcode |= ACM_OP_ACK;
+ msg->hdr.status = ACM_STATUS_SUCCESS;
+ msg->hdr.data[0] = ACM_MAX_COUNTER;
+ msg->hdr.data[1] = 0;
+ msg->hdr.data[2] = 0;
+ msg->hdr.length = ACM_MSG_HDR_LENGTH + (ACM_MAX_COUNTER * sizeof(uint64_t));
+
+ for (i = 0; i < ACM_MAX_COUNTER; i++)
+ msg->data[i] = (uint64_t) atomic_get(&counter[i]);
+
+ ret = send(client->sock, (char *) msg, msg->hdr.length, 0);
+ if (ret != msg->hdr.length)
+ acm_log(0, "ERROR - failed to send response\n");
+ else
+ ret = 0;
+
+ return ret;
+}
+
static void acm_svr_receive(struct acm_client *client)
{
struct acm_msg msg;
- struct acm_resolve_msg *resolve_msg = (struct acm_resolve_msg *) &msg;
int ret;
acm_log(2, "client %d\n", client->index);
@@ -2228,19 +2279,17 @@ static void acm_svr_receive(struct acm_client *client)
goto out;
}
- if ((msg.hdr.opcode & ACM_OP_MASK) != ACM_OP_RESOLVE) {
+ switch (msg.hdr.opcode & ACM_OP_MASK) {
+ case ACM_OP_RESOLVE:
+ atomic_inc(&counter[ACM_CNTR_RESOLVE]);
+ ret = acm_svr_resolve(client, (struct acm_resolve_msg *) &msg);
+ break;
+ case ACM_OP_PERF_QUERY:
+ ret = acm_svr_perf_query(client, (struct acm_perf_msg *) &msg);
+ break;
+ default:
acm_log(0, "ERROR - unknown opcode 0x%x\n", msg.hdr.opcode);
- goto out;
- }
-
- if (resolve_msg->data[0].type == ACM_EP_INFO_PATH) {
- if (resolve_msg->data[0].flags & ACM_FLAGS_QUERY_SA) {
- ret = acm_svr_query_path(client, resolve_msg);
- } else {
- ret = acm_svr_resolve_path(client, resolve_msg);
- }
- } else {
- ret = acm_svr_resolve(client, resolve_msg);
+ break;
}
out:
@@ -2557,7 +2606,6 @@ static struct acm_ep *
acm_alloc_ep(struct acm_port *port, uint16_t pkey, uint16_t pkey_index)
{
struct acm_ep *ep;
- int i;
acm_log(1, "\n");
ep = calloc(1, sizeof *ep);
@@ -2577,9 +2625,6 @@ acm_alloc_ep(struct acm_port *port, uint16_t pkey, uint16_t pkey_index)
DListInit(&ep->wait_queue);
lock_init(&ep->lock);
- for (i = 0; i < MAX_EP_MC; i++)
- acm_init_dest(&ep->mc_dest[i], ACM_ADDRESS_GID, NULL, 0);
-
return ep;
}
@@ -3080,7 +3125,7 @@ static void show_usage(char *program)
int CDECL_FUNC main(int argc, char **argv)
{
- int op, daemon = 1;
+ int i, op, daemon = 1;
while ((op = getopt(argc, argv, "DPA:O:")) != -1) {
switch (op) {
@@ -3123,6 +3168,9 @@ int CDECL_FUNC main(int argc, char **argv)
DListInit(&dev_list);
DListInit(&timeout_list);
event_init(&timeout_event);
+ for (i = 0; i < ACM_MAX_COUNTER; i++)
+ atomic_init(&counter[i]);
+
umad_init();
if (acm_open_devices()) {
acm_log(0, "ERROR - unable to open any devices\n");
@@ -52,8 +52,6 @@ static char *src_addr;
static char addr_type = 'u';
static int verify;
static int nodelay;
-static int make_addr;
-static int make_opts;
int verbose;
struct ibv_context **verbs;
@@ -74,6 +72,8 @@ static void show_usage(char *program)
printf(" [-v] - verify ACM response against SA query response\n");
printf(" [-c] - read ACM cached data only\n");
printf("usage 2: %s\n", program);
+ printf(" -P dest_addr - query performance data from destination service");
+ printf("usage 3: %s\n", program);
printf(" -A [addr_file] - generate local address configuration file\n");
printf(" (default is %s)\n", ACM_ADDR_FILE);
printf(" -O [opt_file] - generate local acm_opts.cfg options file\n");
@@ -587,7 +587,7 @@ static int resolve(char *program, char *dest_arg)
int ret, i = 0;
char dest_type;
- ret = libacm_init();
+ ret = ib_acm_connect("127.0.0.1");
if (ret) {
printf("Unable to contact ib_acm service\n");
return ret;
@@ -631,7 +631,47 @@ static int resolve(char *program, char *dest_arg)
}
free(dest_list);
- libacm_cleanup();
+ ib_acm_disconnect();
+ return ret;
+}
+
+static int query_perf(char *program, char *dest_arg)
+{
+ char **dest_list;
+ int ret, cnt, i, d;
+ uint64_t *counters;
+
+ dest_list = parse(dest_arg, NULL);
+ if (!dest_list) {
+ printf("Unable to parse destination argument\n");
+ return -1;
+ }
+
+ printf("Destination,Error Count,Resolve Count,No Data,Addr Query Count,"
+ "Addr Cache Count,Route Query Count,Route Cache Count\n");
+ for (d = 0; dest_list[d]; d++) {
+
+ printf("%s,", dest_list[d]);
+ ret = ib_acm_connect(dest_list[d]);
+ if (ret) {
+ printf("Unable to contact ib_acm service\n");
+ continue;
+ }
+
+ ret = ib_acm_query_perf(&counters, &cnt);
+ if (ret) {
+ printf("Failed to query perf data %s\n", strerror(errno));
+ } else {
+ for (i = 0; i < cnt; i++)
+ printf("%llu,", (unsigned long long) counters[i]);
+ printf("\n");
+ ib_acm_free_perf(counters);
+ }
+
+ ib_acm_disconnect();
+ }
+
+ free(dest_list);
return ret;
}
@@ -650,12 +690,15 @@ int CDECL_FUNC main(int argc, char **argv)
{
char *dest_arg = NULL;
int op, ret;
+ int make_addr = 0;
+ int make_opts = 0;
+ int perf_query = 0;
ret = osd_init();
if (ret)
goto out;
- while ((op = getopt(argc, argv, "f:s:d:vcA::O::D:V")) != -1) {
+ while ((op = getopt(argc, argv, "f:s:d:vcA::O::D:P:V")) != -1) {
switch (op) {
case 'f':
addr_type = optarg[0];
@@ -685,6 +728,10 @@ int CDECL_FUNC main(int argc, char **argv)
case 'D':
dest_dir = optarg;
break;
+ case 'P':
+ perf_query = 1;
+ dest_arg = optarg;
+ break;
case 'V':
verbose = 1;
break;
@@ -700,8 +747,12 @@ int CDECL_FUNC main(int argc, char **argv)
exit(1);
}
- if (dest_arg)
- ret = resolve(argv[0], dest_arg);
+ if (dest_arg) {
+ if (perf_query)
+ ret = query_perf(argv[0], dest_arg);
+ else
+ ret = resolve(argv[0], dest_arg);
+ }
if (!ret && make_addr)
ret = gen_addr();
@@ -709,6 +760,7 @@ int CDECL_FUNC main(int argc, char **argv)
if (!ret && make_opts)
ret = gen_opts();
+ osd_close();
out:
if (verbose || !(make_addr || make_opts) || ret)
printf("return status 0x%x\n", ret);
@@ -36,6 +36,8 @@
#include <infiniband/acm.h>
#include <stdio.h>
#include <errno.h>
+#include <netdb.h>
+#include <arpa/inet.h>
struct acm_port {
uint8_t port_num;
@@ -66,45 +68,46 @@ static void acm_set_server_port(void)
}
}
-int libacm_init(void)
+int ib_acm_connect(char *dest)
{
- struct sockaddr_in addr;
+ struct addrinfo hint, *res;
int ret;
- ret = osd_init();
+ acm_set_server_port();
+ memset(&hint, 0, sizeof hint);
+ hint.ai_protocol = IPPROTO_TCP;
+ ret = getaddrinfo(dest, NULL, &hint, &res);
if (ret)
return ret;
- acm_set_server_port();
- sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sock == INVALID_SOCKET) {
ret = socket_errno();
goto err1;
}
- memset(&addr, 0, sizeof addr);
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- addr.sin_port = htons(server_port);
- ret = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
+ ((struct sockaddr_in *) res->ai_addr)->sin_port = htons(server_port);
+ ret = connect(sock, res->ai_addr, res->ai_addrlen);
if (ret)
goto err2;
+ freeaddrinfo(res);
return 0;
err2:
closesocket(sock);
sock = INVALID_SOCKET;
err1:
- osd_close();
+ freeaddrinfo(res);
return ret;
}
-void libacm_cleanup(void)
+void ib_acm_disconnect(void)
{
if (sock != INVALID_SOCKET) {
shutdown(sock, SHUT_RDWR);
closesocket(sock);
+ sock = INVALID_SOCKET;
}
}
@@ -310,3 +313,42 @@ out:
lock_release(&lock);
return ret;
}
+
+int ib_acm_query_perf(uint64_t **counters, int *count)
+{
+ struct acm_msg msg;
+ struct acm_perf_msg *perf_msg = (struct acm_perf_msg *) &msg;
+ int ret;
+
+ lock_acquire(&lock);
+ memset(&msg, 0, sizeof msg);
+ msg.hdr.version = ACM_VERSION;
+ msg.hdr.opcode = ACM_OP_PERF_QUERY;
+ msg.hdr.length = ACM_MSG_HDR_LENGTH;
+
+ ret = send(sock, (char *) &msg, msg.hdr.length, 0);
+ if (ret != msg.hdr.length)
+ goto out;
+
+ ret = recv(sock, (char *) &msg, sizeof msg, 0);
+ if (ret < ACM_MSG_HDR_LENGTH || ret != msg.hdr.length)
+ goto out;
+
+ if (msg.hdr.status) {
+ ret = acm_error(msg.hdr.status);
+ goto out;
+ }
+
+ *counters = malloc(sizeof(uint64_t) * msg.hdr.data[0]);
+ if (!*counters) {
+ ret = ACM_STATUS_ENOMEM;
+ goto out;
+ }
+
+ memcpy(*counters, perf_msg->data, sizeof(uint64_t) * msg.hdr.data[0]);
+ *count = msg.hdr.data[0];
+ ret = 0;
+out:
+ lock_release(&lock);
+ return ret;
+}
@@ -27,10 +27,13 @@
* SOFTWARE.
*/
+#ifndef LIBACM_H
+#define LIBACM_H
+
#include <infiniband/acm.h>
-int libacm_init();
-void libacm_cleanup();
+int ib_acm_connect(char *dest_svc);
+void ib_acm_disconnect();
int ib_acm_resolve_name(char *src, char *dest,
struct ibv_path_data **paths, int *count, uint32_t flags);
@@ -38,3 +41,8 @@ int ib_acm_resolve_ip(struct sockaddr *src, struct sockaddr *dest,
struct ibv_path_data **paths, int *count, uint32_t flags);
int ib_acm_resolve_path(struct ibv_path_record *path, uint32_t flags);
#define ib_acm_free_paths(paths) free(paths)
+
+int ib_acm_query_perf(uint64_t **counters, int *count);
+#define ib_acm_free_perf(counters) free(counters)
+
+#endif /* LIBACM_H */
Add performance counters to track service usage. Counters are exposed via a new perf query request. Update ib_acme to retrieve counters from a specified endpoint. Counters that are currently defined are: - Address and route resolution errors - Resolution requests - Requests not satisfied as a result of no data available - Requests requiring an address lookup - Requests that found address information in the cache - Requests requiring a route lookup (i.e. path record query) - Requests that found route information in the cache Signed-off-by: Sean Hefty <sean.hefty@intel.com> --- include/infiniband/acm.h | 19 +++++++++- src/acm.c | 90 +++++++++++++++++++++++++++++++++++----------- src/acme.c | 66 ++++++++++++++++++++++++++++++---- src/libacm.c | 66 ++++++++++++++++++++++++++++------ src/libacm.h | 12 +++++- 5 files changed, 209 insertions(+), 44 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html