From 8b5af39c7ac2fe146762670209a77a33ce8a66d9 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Wed, 14 Sep 2011 12:44:28 -0700 Subject: [PATCH] uncommit --- meta | 4 +- patches/ib_acme-add-missing-carriage-r | 27 + patches/ibacm-add-performance-counters | 744 +++++++++++++++++++++++++ 3 files changed, 774 insertions(+), 1 deletion(-) create mode 100644 patches/ib_acme-add-missing-carriage-r create mode 100644 patches/ibacm-add-performance-counters diff --git a/meta b/meta index 826d5b8..b1291b2 100644 --- a/meta +++ b/meta @@ -1,7 +1,9 @@ Version: 1 -Previous: 53348cfa254ac1a568f2d53187136662c905995c +Previous: 3458c5e1039f7f35fc994c1de4c6459ef7b96ade Head: 1958ff2ca4ff687a0f6fe4116af4173bba4767a2 Applied: + ibacm-add-performance-counters: 9d3ba5d9bd6ae5738af3b680fba82ccc1e7ae820 + ib_acme-add-missing-carriage-r: 1958ff2ca4ff687a0f6fe4116af4173bba4767a2 Unapplied: acm1.0.5: af72eb3f07335de5fbffd7eed79cbf814859e095 name2ip: 8e00708e882239292492e13aa51c82042255933c diff --git a/patches/ib_acme-add-missing-carriage-r b/patches/ib_acme-add-missing-carriage-r new file mode 100644 index 0000000..713a65e --- /dev/null +++ b/patches/ib_acme-add-missing-carriage-r @@ -0,0 +1,27 @@ +Bottom: 131a3de8a72737d956e57cbdeed00328b22d8209 +Top: 3d98f5a3a2be46ced4b026df8246d5d4d43784be +Author: Sean Hefty +Date: 2011-08-29 16:14:50 -0700 + +ib_acme: Add missing carriage return in usage statements + +Signed-off-by: Sean Hefty + + +--- + +diff --git a/src/acme.c b/src/acme.c +index f3faa68..3d7461b 100644 +--- a/src/acme.c ++++ b/src/acme.c +@@ -76,8 +76,8 @@ static void show_usage(char *program) + printf(" [-d dest_addr] - destination addresses for path queries\n"); + printf(" [-v] - verify ACM response against SA query response\n"); + printf(" [-c] - read ACM cached data only\n"); +- printf(" [-P] - query performance data from destination service"); +- printf(" [-S svc_addr] - address of ACM service, default: local service"); ++ printf(" [-P] - query performance data from destination service\n"); ++ printf(" [-S svc_addr] - address of ACM service, default: local service\n"); + printf("usage 2: %s\n", program); + printf("Generate default ib_acm service configuration and option files\n"); + printf(" -A [addr_file] - generate local address configuration file\n"); diff --git a/patches/ibacm-add-performance-counters b/patches/ibacm-add-performance-counters new file mode 100644 index 0000000..ef336ef --- /dev/null +++ b/patches/ibacm-add-performance-counters @@ -0,0 +1,744 @@ +Bottom: c1a3265ecb373be6114f838a6a7b82453aafd16e +Top: 131a3de8a72737d956e57cbdeed00328b22d8209 +Author: Sean Hefty +Date: 2011-06-27 10:29:36 -0700 + +ibacm: Add performance counters + +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 + + +--- + +diff --git a/include/infiniband/acm.h b/include/infiniband/acm.h +index 5ef8c1d..bc85137 100644 +--- a/include/infiniband/acm.h ++++ b/include/infiniband/acm.h +@@ -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; + }; +@@ -92,11 +93,36 @@ struct acm_ep_addr_data { + union acm_ep_info info; + }; + ++/* ++ * Resolve messages with the opcode set to ACM_OP_RESOLVE are only ++ * used to communicate with the local ib_acm service. Message fields ++ * in this case are not byte swapped, but note that the acm_ep_info ++ * data is in network order. ++ */ + struct acm_resolve_msg { + struct acm_hdr hdr; + 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 ++}; ++ ++/* ++ * Performance messages are sent/receive in network byte order. ++ */ ++struct acm_perf_msg { ++ struct acm_hdr hdr; ++ uint64_t data[0]; ++}; ++ + struct acm_msg { + struct acm_hdr hdr; + union{ +diff --git a/src/acm.c b/src/acm.c +index 1c643f3..fed0440 100644 +--- a/src/acm.c ++++ b/src/acm.c +@@ -47,7 +47,7 @@ + #include + #include "acm_mad.h" + +-#define src_out reserved[0] ++#define src_out data[0] + + #define MAX_EP_ADDR 4 + #define MAX_EP_MC 2 +@@ -200,7 +200,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"; +@@ -899,6 +903,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; +@@ -1009,6 +1014,11 @@ acm_client_resolve_resp(struct acm_client *client, struct acm_msg *req_msg, + 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"); +@@ -1020,7 +1030,7 @@ acm_client_resolve_resp(struct acm_client *client, struct acm_msg *req_msg, + msg.hdr.opcode |= ACM_OP_ACK; + msg.hdr.status = status; + msg.hdr.length = ACM_MSG_HDR_LENGTH; +- memset(msg.hdr.reserved, 0, sizeof(msg.hdr.reserved)); ++ memset(msg.hdr.data, 0, sizeof(msg.hdr.data)); + + if (status == ACM_STATUS_SUCCESS) { + msg.hdr.length += ACM_MSG_EP_LENGTH; +@@ -1853,6 +1863,7 @@ acm_svr_query_path(struct acm_client *client, struct acm_msg *msg) + sizeof(struct ibv_path_record)); + mad->comp_mask = acm_path_comp_mask(&msg->resolve_data[0].info.path); + ++ atomic_inc(&counter[ACM_CNTR_ROUTE_QUERY]); + acm_post_send(&ep->sa_queue, sa_msg); + return ACM_STATUS_SUCCESS; + +@@ -1901,6 +1912,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; + } +@@ -2089,10 +2101,12 @@ acm_svr_resolve_dest(struct acm_client *client, struct acm_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; +@@ -2182,6 +2196,7 @@ acm_svr_resolve_path(struct acm_client *client, struct acm_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: +@@ -2216,6 +2231,51 @@ put: + return ret; + } + ++static int acm_svr_resolve(struct acm_client *client, struct acm_msg *msg) ++{ ++ 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); ++ } 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_msg *msg) ++{ ++ int ret, i; ++ uint16_t len; ++ ++ 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; ++ len = htons(ACM_MSG_HDR_LENGTH + (ACM_MAX_COUNTER * sizeof(uint64_t))); ++ msg->hdr.length = htons(len); ++ ++ for (i = 0; i < ACM_MAX_COUNTER; i++) ++ msg->perf_data[i] = htonll((uint64_t) atomic_get(&counter[i])); ++ ++ ret = send(client->sock, (char *) msg, len, 0); ++ if (ret != msg->hdr.length) ++ acm_log(0, "ERROR - failed to send response\n"); ++ else ++ ret = 0; ++ ++ return ret; ++} ++ ++static int acm_msg_length(struct acm_msg *msg) ++{ ++ return (msg->hdr.opcode == ACM_OP_RESOLVE) ? ++ msg->hdr.length : ntohs(msg->hdr.length); ++} ++ + static void acm_svr_receive(struct acm_client *client) + { + struct acm_msg msg; +@@ -2223,7 +2283,7 @@ static void acm_svr_receive(struct acm_client *client) + + acm_log(2, "client %d\n", client->index); + ret = recv(client->sock, (char *) &msg, sizeof msg, 0); +- if (ret <= 0 || ret != msg.hdr.length) { ++ if (ret <= 0 || ret != acm_msg_length(&msg)) { + acm_log(2, "client disconnected\n"); + ret = ACM_STATUS_ENOTCONN; + goto out; +@@ -2234,19 +2294,17 @@ static void acm_svr_receive(struct acm_client *client) + goto out; + } + +- if ((msg.hdr.opcode & ACM_OP_MASK) != ACM_OP_RESOLVE) { +- acm_log(0, "ERROR - unknown opcode 0x%x\n", msg.hdr.opcode); +- goto out; +- } +- +- if (msg.resolve_data[0].type == ACM_EP_INFO_PATH) { +- if (msg.resolve_data[0].flags & ACM_FLAGS_QUERY_SA) { +- ret = acm_svr_query_path(client, &msg); +- } else { +- ret = acm_svr_resolve_path(client, &msg); +- } +- } else { ++ switch (msg.hdr.opcode & ACM_OP_MASK) { ++ case ACM_OP_RESOLVE: ++ atomic_inc(&counter[ACM_CNTR_RESOLVE]); + ret = acm_svr_resolve(client, &msg); ++ break; ++ case ACM_OP_PERF_QUERY: ++ ret = acm_svr_perf_query(client, &msg); ++ break; ++ default: ++ acm_log(0, "ERROR - unknown opcode 0x%x\n", msg.hdr.opcode); ++ break; + } + + out: +@@ -2563,7 +2621,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); +@@ -2583,9 +2640,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; + } + +@@ -3086,7 +3140,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) { +@@ -3129,6 +3183,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"); +diff --git a/src/acme.c b/src/acme.c +index d42ba81..f3faa68 100644 +--- a/src/acme.c ++++ b/src/acme.c +@@ -49,11 +49,13 @@ static char *opts_file = ACM_OPTS_FILE; + + static char *dest_addr; + static char *src_addr; ++static char *svc_arg = "localhost"; ++static char *dest_arg; ++static char *src_arg; + static char addr_type = 'u'; + static int verify; + static int nodelay; +-static int make_addr; +-static int make_opts; ++static int perf_query; + int verbose; + + struct ibv_context **verbs; +@@ -67,13 +69,17 @@ extern char **parse(char *args, int *count); + static void show_usage(char *program) + { + printf("usage 1: %s\n", program); ++ printf("Query specified ib_acm service for data\n"); + printf(" [-f addr_format] - i(p), n(ame), l(id), g(gid), or u(nspecified)\n"); +- printf(" default: 'u'\n"); +- printf(" [-s src_addr] - format defined by -f option\n"); +- printf(" [-d] dest_addr - format defined by -f option\n"); ++ printf(" address format for -s and -d options, default: 'u'\n"); ++ printf(" [-s src_addr] - source address for path queries\n"); ++ printf(" [-d dest_addr] - destination addresses for path queries\n"); + printf(" [-v] - verify ACM response against SA query response\n"); + printf(" [-c] - read ACM cached data only\n"); ++ printf(" [-P] - query performance data from destination service"); ++ printf(" [-S svc_addr] - address of ACM service, default: local service"); + printf("usage 2: %s\n", program); ++ printf("Generate default ib_acm service configuration and option files\n"); + 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"); +@@ -443,7 +449,7 @@ static int resolve_ip(struct ibv_path_record *path) + ret = inet_pton(AF_INET, src_addr, &src.sin_addr); + if (ret <= 0) { + printf("inet_pton error on source address (%s): 0x%x\n", src_addr, ret); +- return ret; ++ return -1; + } + saddr = (struct sockaddr *) &src; + } else { +@@ -454,7 +460,7 @@ static int resolve_ip(struct ibv_path_record *path) + ret = inet_pton(AF_INET, dest_addr, &dest.sin_addr); + if (ret <= 0) { + printf("inet_pton error on destination address (%s): 0x%x\n", dest_addr, ret); +- return ret; ++ return -1; + } + + ret = ib_acm_resolve_ip(saddr, (struct sockaddr *) &dest, +@@ -575,63 +581,121 @@ static char *get_dest(char *arg, char *format) + *format = 'i'; + return addr; + } else { +- *format = 'u'; ++ *format = 'n'; + return arg; + } + } + +-static int resolve(char *program, char *dest_arg) ++static void resolve(char *svc) + { +- char **dest_list; ++ char **dest_list, **src_list; + struct ibv_path_record path; +- int ret, i = 0; ++ int ret, d = 0, s = 0; + char dest_type; + +- ret = libacm_init(); +- if (ret) { +- printf("Unable to contact ib_acm service\n"); +- return ret; +- } +- + dest_list = parse(dest_arg, NULL); + if (!dest_list) { + printf("Unable to parse destination argument\n"); ++ return; ++ } ++ ++ src_list = src_arg ? parse(src_arg, NULL) : NULL; ++ ++ printf("Service: %s\n", svc); ++ for (dest_addr = get_dest(dest_list[d], &dest_type); dest_addr; ++ dest_addr = get_dest(dest_list[++d], &dest_type)) { ++ s = 0; ++ src_addr = src_list ? src_list[s] : NULL; ++ do { ++ printf("Destination: %s\n", dest_addr); ++ if (src_addr) ++ printf("Source: %s\n", src_addr); ++ switch (dest_type) { ++ case 'i': ++ ret = resolve_ip(&path); ++ break; ++ case 'n': ++ ret = resolve_name(&path); ++ break; ++ case 'l': ++ memset(&path, 0, sizeof path); ++ ret = resolve_lid(&path); ++ break; ++ case 'g': ++ memset(&path, 0, sizeof path); ++ ret = resolve_gid(&path); ++ break; ++ default: ++ break; ++ } ++ ++ if (!ret) ++ show_path(&path); ++ ++ if (verify) ++ ret = verify_resolve(&path); ++ printf("\n"); ++ ++ if (src_list) ++ src_addr = src_list[++s]; ++ } while (src_addr); ++ } ++ ++ free(dest_list); ++} ++ ++static void query_perf(char *svc) ++{ ++ int ret, cnt, i; ++ uint64_t *counters; ++ ++ ret = ib_acm_query_perf(&counters, &cnt); ++ if (ret) { ++ printf("%s: Failed to query perf data %s\n", svc, strerror(errno)); ++ return; ++ } ++ ++ printf("%s,", svc); ++ for (i = 0; i < cnt; i++) ++ printf("%llu,", (unsigned long long) counters[i]); ++ printf("\n"); ++ ib_acm_free_perf(counters); ++} ++ ++static int query_svcs(void) ++{ ++ char **svc_list; ++ int ret, i; ++ ++ svc_list = parse(svc_arg, NULL); ++ if (!svc_list) { ++ printf("Unable to parse service list argument\n"); + return -1; + } + +- for (dest_addr = get_dest(dest_list[i], &dest_type); dest_addr; +- dest_addr = get_dest(dest_list[++i], &dest_type)) { +- printf("Destination: %s\n", dest_addr); +- switch (dest_type) { +- case 'i': +- ret = resolve_ip(&path); +- break; +- case 'n': +- ret = resolve_name(&path); +- break; +- case 'l': +- memset(&path, 0, sizeof path); +- ret = resolve_lid(&path); +- break; +- case 'g': +- memset(&path, 0, sizeof path); +- ret = resolve_gid(&path); +- break; +- default: +- show_usage(program); +- exit(1); ++ if (perf_query) { ++ printf("Destination,Error Count,Resolve Count,No Data,Addr Query Count," ++ "Addr Cache Count,Route Query Count,Route Cache Count\n"); ++ } ++ ++ for (i = 0; svc_list[i]; i++) { ++ ret = ib_acm_connect(svc_list[i]); ++ if (ret) { ++ printf("%s,unable to contact service: %s\n", ++ svc_list[i], strerror(errno)); ++ continue; + } + +- if (!ret) +- show_path(&path); ++ if (dest_arg) ++ resolve(svc_list[i]); + +- if (verify) +- ret = verify_resolve(&path); +- printf("\n"); ++ if (perf_query) ++ query_perf(svc_list[i]); ++ ++ ib_acm_disconnect(); + } + +- free(dest_list); +- libacm_cleanup(); ++ free(svc_list); + return ret; + } + +@@ -648,20 +712,24 @@ char *opt_arg(int argc, char **argv) + + int CDECL_FUNC main(int argc, char **argv) + { +- char *dest_arg = NULL; + int op, ret; ++ int make_addr = 0; ++ int make_opts = 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:PS:V")) != -1) { + switch (op) { + case 'f': + addr_type = optarg[0]; ++ if (addr_type != 'i' && addr_type != 'n' && ++ addr_type != 'l' && addr_type != 'g') ++ goto show_use; + break; + case 's': +- src_addr = optarg; ++ src_arg = optarg; + break; + case 'd': + dest_arg = optarg; +@@ -685,23 +753,26 @@ int CDECL_FUNC main(int argc, char **argv) + case 'D': + dest_dir = optarg; + break; ++ case 'P': ++ perf_query = 1; ++ break; ++ case 'S': ++ svc_arg = optarg; ++ break; + case 'V': + verbose = 1; + break; + default: +- show_usage(argv[0]); +- exit(1); ++ goto show_use; + } + } + +- if ((src_addr && !dest_arg) || +- (!src_addr && !dest_arg && !make_addr && !make_opts)) { +- show_usage(argv[0]); +- exit(1); +- } ++ if ((src_arg && !dest_arg) || ++ (!src_arg && !dest_arg && !perf_query && !make_addr && !make_opts)) ++ goto show_use; + +- if (dest_arg) +- ret = resolve(argv[0], dest_arg); ++ if (dest_arg || perf_query) ++ ret = query_svcs(); + + if (!ret && make_addr) + ret = gen_addr(); +@@ -709,8 +780,13 @@ 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); + return ret; ++ ++show_use: ++ show_usage(argv[0]); ++ exit(1); + } +diff --git a/src/libacm.c b/src/libacm.c +index 8a644c4..f96760c 100644 +--- a/src/libacm.c ++++ b/src/libacm.c +@@ -36,6 +36,8 @@ + #include + #include + #include ++#include ++#include + + 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; + } + } + +@@ -312,3 +315,42 @@ out: + lock_release(&lock); + return ret; + } ++ ++int ib_acm_query_perf(uint64_t **counters, int *count) ++{ ++ struct acm_msg msg; ++ int ret, i; ++ ++ lock_acquire(&lock); ++ memset(&msg, 0, sizeof msg); ++ msg.hdr.version = ACM_VERSION; ++ msg.hdr.opcode = ACM_OP_PERF_QUERY; ++ msg.hdr.length = htons(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 != ntohs(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; ++ } ++ ++ *count = msg.hdr.data[0]; ++ for (i = 0; i < *count; i++) ++ (*counters)[i] = ntohll(msg.perf_data[i]); ++ ret = 0; ++out: ++ lock_release(&lock); ++ return ret; ++} +diff --git a/src/libacm.h b/src/libacm.h +index 16df8b0..049b7a9 100644 +--- a/src/libacm.h ++++ b/src/libacm.h +@@ -27,10 +27,13 @@ + * SOFTWARE. + */ + ++#ifndef LIBACM_H ++#define LIBACM_H ++ + #include + +-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 */ -- 2.41.0