/
githubmirror
/
rdma-core
Обзор
Документация
Войти
/
githubmirror
/
rdma-core
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
ibacm/src/libacm.c
533 строки
12 KB
Jason Gunthorpe
ibacm: Ensure strings are NULL terminated
05 май 2020, 16:59
05 май 2020, 16:59
224b03c
Код
Авторство
О чём код?
/* * Copyright (c) 2009 Intel Corporation. All rights reserved. * Copyright (c) 2013 Mellanox Technologies LTD. All rights reserved. * * This software is available to you under the OpenIB.org BSD license * below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include <config.h> #include <osd.h> #include "libacm.h" #include <infiniband/acm.h> #include <stdio.h> #include <errno.h> #include <netdb.h> #include <arpa/inet.h> #include <sys/socket.h> #include <sys/un.h> #include <util/util.h> static pthread_mutex_t acm_lock = PTHREAD_MUTEX_INITIALIZER; static int sock = -1; static short server_port = 6125; static void acm_set_server_port(void) { FILE *f; f = fopen(IBACM_IBACME_PORT_FILE, "r"); if (f) { if (fscanf(f, "%hu", (unsigned short *) &server_port) != 1) printf("Failed to read server port\n"); fclose(f); } } static int ib_acm_connect_open(char *dest) { struct addrinfo hint, *res; int ret; acm_set_server_port(); memset(&hint, 0, sizeof hint); hint.ai_family = AF_UNSPEC; hint.ai_protocol = IPPROTO_TCP; ret = getaddrinfo(dest, NULL, &hint, &res); if (ret) return ret; sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sock == -1) { ret = errno; goto freeaddr; } ((struct sockaddr_in *) res->ai_addr)->sin_port = htobe16(server_port); ret = connect(sock, res->ai_addr, res->ai_addrlen); if (ret) { close(sock); sock = -1; } freeaddr: freeaddrinfo(res); return ret; } static int ib_acm_connect_unix(char *dest) { struct sockaddr_un addr; int ret; addr.sun_family = AF_UNIX; if (dest) { if (snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", dest) >= sizeof(addr.sun_path)) { errno = ENAMETOOLONG; return errno; } } else { BUILD_ASSERT(sizeof(IBACM_IBACME_SERVER_PATH) <= sizeof(addr.sun_path)); strcpy(addr.sun_path, IBACM_IBACME_SERVER_PATH); } sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0) return errno; if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) { ret = errno; close(sock); sock = -1; errno = ret; return ret; } return 0; } int ib_acm_connect(char *dest) { if (dest && *dest == '/') return ib_acm_connect_unix(dest); return ib_acm_connect_open(dest); } void ib_acm_disconnect(void) { if (sock != -1) { shutdown(sock, SHUT_RDWR); close(sock); sock = -1; } } static int acm_format_resp(struct acm_msg *msg, struct ibv_path_data **paths, int *count, int print) { struct ibv_path_data *path_data; char addr[ACM_MAX_ADDRESS]; int i, addr_cnt; *count = 0; addr_cnt = (msg->hdr.length - ACM_MSG_HDR_LENGTH) / sizeof(struct acm_ep_addr_data); path_data = (struct ibv_path_data *) calloc(1, addr_cnt * sizeof(struct ibv_path_data)); if (!path_data) return -1; for (i = 0; i < addr_cnt; i++) { switch (msg->resolve_data[i].type) { case ACM_EP_INFO_PATH: path_data[i].flags = msg->resolve_data[i].flags; path_data[i].path = msg->resolve_data[i].info.path; (*count)++; break; default: if (!(msg->resolve_data[i].flags & ACM_EP_FLAG_SOURCE)) goto err; switch (msg->resolve_data[i].type) { case ACM_EP_INFO_ADDRESS_IP: inet_ntop(AF_INET, msg->resolve_data[i].info.addr, addr, sizeof addr); break; case ACM_EP_INFO_ADDRESS_IP6: inet_ntop(AF_INET6, msg->resolve_data[i].info.addr, addr, sizeof addr); break; case ACM_EP_INFO_NAME: memcpy(addr, msg->resolve_data[i].info.name, ACM_MAX_ADDRESS); break; default: goto err; } if (print) printf("Source: %s\n", addr); break; } } *paths = path_data; return 0; err: free(path_data); return -1; } static int acm_format_ep_addr(struct acm_ep_addr_data *data, uint8_t *addr, uint8_t type, uint32_t flags) { data->type = type; data->flags = flags; switch (type) { case ACM_EP_INFO_NAME: if (!check_snprintf((char *)data->info.name, sizeof(data->info.name), "%s", (char *)addr)) return -1; break; case ACM_EP_INFO_ADDRESS_IP: memcpy(data->info.addr, &((struct sockaddr_in *) addr)->sin_addr, 4); break; case ACM_EP_INFO_ADDRESS_IP6: memcpy(data->info.addr, &((struct sockaddr_in6 *) addr)->sin6_addr, 16); break; default: return -1; } return 0; } static inline int ERR(int err) { errno = err; return -1; } static int acm_error(uint8_t status) { switch (status) { case ACM_STATUS_SUCCESS: return 0; case ACM_STATUS_ENOMEM: return ERR(ENOMEM); case ACM_STATUS_EINVAL: return ERR(EINVAL); case ACM_STATUS_ENODATA: return ERR(ENODATA); case ACM_STATUS_ENOTCONN: return ERR(ENOTCONN); case ACM_STATUS_ETIMEDOUT: return ERR(ETIMEDOUT); case ACM_STATUS_ESRCADDR: case ACM_STATUS_EDESTADDR: return ERR(EADDRNOTAVAIL); case ACM_STATUS_ESRCTYPE: case ACM_STATUS_EDESTTYPE: default: return ERR(EINVAL); } } static int acm_resolve(uint8_t *src, uint8_t *dest, uint8_t type, struct ibv_path_data **paths, int *count, uint32_t flags, int print) { struct acm_msg msg; int ret, cnt = 0; pthread_mutex_lock(&acm_lock); memset(&msg, 0, sizeof msg); msg.hdr.version = ACM_VERSION; msg.hdr.opcode = ACM_OP_RESOLVE; if (src) { ret = acm_format_ep_addr(&msg.resolve_data[cnt++], src, type, ACM_EP_FLAG_SOURCE); if (ret) goto out; } ret = acm_format_ep_addr(&msg.resolve_data[cnt++], dest, type, ACM_EP_FLAG_DEST | flags); if (ret) goto out; msg.hdr.length = ACM_MSG_HDR_LENGTH + (cnt * ACM_MSG_EP_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; } ret = acm_format_resp(&msg, paths, count, print); out: pthread_mutex_unlock(&acm_lock); return ret; } int ib_acm_resolve_name(char *src, char *dest, struct ibv_path_data **paths, int *count, uint32_t flags, int print) { return acm_resolve((uint8_t *) src, (uint8_t *) dest, ACM_EP_INFO_NAME, paths, count, flags, print); } int ib_acm_resolve_ip(struct sockaddr *src, struct sockaddr *dest, struct ibv_path_data **paths, int *count, uint32_t flags, int print) { if (((struct sockaddr *) dest)->sa_family == AF_INET) { return acm_resolve((uint8_t *) src, (uint8_t *) dest, ACM_EP_INFO_ADDRESS_IP, paths, count, flags, print); } else { return acm_resolve((uint8_t *) src, (uint8_t *) dest, ACM_EP_INFO_ADDRESS_IP6, paths, count, flags, print); } } int ib_acm_resolve_path(struct ibv_path_record *path, uint32_t flags) { struct acm_msg msg; struct acm_ep_addr_data *data; int ret; pthread_mutex_lock(&acm_lock); memset(&msg, 0, sizeof msg); msg.hdr.version = ACM_VERSION; msg.hdr.opcode = ACM_OP_RESOLVE; msg.hdr.length = ACM_MSG_HDR_LENGTH + ACM_MSG_EP_LENGTH; data = &msg.resolve_data[0]; data->flags = flags; data->type = ACM_EP_INFO_PATH; data->info.path = *path; 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; ret = acm_error(msg.hdr.status); if (!ret) *path = data->info.path; out: pthread_mutex_unlock(&acm_lock); return ret; } int ib_acm_query_perf(int index, uint64_t **counters, int *count) { struct acm_msg msg; int ret, i; pthread_mutex_lock(&acm_lock); memset(&msg, 0, sizeof msg); msg.hdr.version = ACM_VERSION; msg.hdr.opcode = ACM_OP_PERF_QUERY; msg.hdr.src_index = index; msg.hdr.length = htobe16(ACM_MSG_HDR_LENGTH); ret = send(sock, (char *) &msg, ACM_MSG_HDR_LENGTH, 0); 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 = ACM_STATUS_EINVAL; goto out; } if (msg.hdr.status) { ret = acm_error(msg.hdr.status); goto out; } *counters = malloc(sizeof(uint64_t) * msg.hdr.src_out); if (!*counters) { ret = ACM_STATUS_ENOMEM; goto out; } *count = msg.hdr.src_out; for (i = 0; i < *count; i++) (*counters)[i] = be64toh(msg.perf_data[i]); ret = 0; out: pthread_mutex_unlock(&acm_lock); return ret; } int ib_acm_enum_ep(int index, struct acm_ep_config_data **data, uint8_t port) { struct acm_ep_config_data *netw_edata = NULL; struct acm_ep_config_data *host_edata = NULL; struct acm_hdr hdr; struct acm_msg msg; int ret; int len; int i; pthread_mutex_lock(&acm_lock); memset(&msg, 0, sizeof msg); msg.hdr.version = ACM_VERSION; msg.hdr.opcode = ACM_OP_EP_QUERY; msg.hdr.src_out = index; msg.hdr.src_index = port; msg.hdr.length = htobe16(ACM_MSG_HDR_LENGTH); ret = send(sock, (char *) &msg, ACM_MSG_HDR_LENGTH, 0); if (ret != ACM_MSG_HDR_LENGTH) goto out; ret = recv(sock, (char *) &hdr, sizeof(hdr), 0); if (ret != sizeof(hdr)) { ret = ACM_STATUS_EINVAL; goto out; } if (hdr.status) { ret = acm_error(hdr.status); goto out; } len = be16toh(hdr.length) - sizeof(hdr); netw_edata = malloc(len); host_edata = malloc(len); if (!netw_edata || !host_edata) { ret = ACM_STATUS_ENOMEM; goto out; } 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->phys_port_cnt = netw_edata->phys_port_cnt; 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: free(netw_edata); if (ret) free(host_edata); pthread_mutex_unlock(&acm_lock); return ret; } int ib_acm_query_perf_ep_addr(uint8_t *src, uint8_t type, uint64_t **counters, int *count) { struct acm_msg msg; int ret, i, len; if (!src) return -1; pthread_mutex_lock(&acm_lock); memset(&msg, 0, sizeof msg); msg.hdr.version = ACM_VERSION; msg.hdr.opcode = ACM_OP_PERF_QUERY; ret = acm_format_ep_addr(&msg.resolve_data[0], src, type, ACM_EP_FLAG_SOURCE); if (ret) goto out; len = ACM_MSG_HDR_LENGTH + ACM_MSG_EP_LENGTH; msg.hdr.length = htobe16(len); ret = send(sock, (char *) &msg, len, 0); if (ret != len) goto out; ret = recv(sock, (char *) &msg, sizeof msg, 0); if (ret < ACM_MSG_HDR_LENGTH || ret != be16toh(msg.hdr.length)) { ret = ACM_STATUS_EINVAL; goto out; } if (msg.hdr.status) { ret = acm_error(msg.hdr.status); goto out; } *counters = malloc(sizeof(uint64_t) * msg.hdr.src_out); if (!*counters) { ret = ACM_STATUS_ENOMEM; goto out; } *count = msg.hdr.src_out; for (i = 0; i < *count; i++) (*counters)[i] = be64toh(msg.perf_data[i]); ret = 0; out: pthread_mutex_unlock(&acm_lock); return ret; } const char *ib_acm_cntr_name(int index) { static const char *const cntr_name[] = { [ACM_CNTR_ERROR] = "Error Count", [ACM_CNTR_RESOLVE] = "Resolve Count", [ACM_CNTR_NODATA] = "No Data", [ACM_CNTR_ADDR_QUERY] = "Addr Query Count", [ACM_CNTR_ADDR_CACHE] = "Addr Cache Count", [ACM_CNTR_ROUTE_QUERY] = "Route Query Count", [ACM_CNTR_ROUTE_CACHE] = "Route Cache Count", }; if (index < ACM_CNTR_ERROR || index > ACM_MAX_COUNTER) return "Unknown"; return cntr_name[index]; }