diff --git a/CHANGELOG.md b/CHANGELOG.md index 3612185d8..8d072dba8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,6 +69,14 @@ the ring. A new API `spdk_mempool_lookup` has been added to lookup the memory pool created by the primary process. +### sock + +Add spdk_sock_get_optimal_sock_group(), which returns the optimal sock group for +this socket. When a socket is created, it is often assigned to a sock group using +spdk_sock_group_add_sock so that a set of sockets can be polled more efficiently. +For some network devices, it is optimal to assign particular sockets to specific +sock groups. This API is intended to provide the user with that information. + ## v19.04: ### nvme diff --git a/include/spdk/sock.h b/include/spdk/sock.h index 6b8463520..b5540995f 100644 --- a/include/spdk/sock.h +++ b/include/spdk/sock.h @@ -252,6 +252,16 @@ int spdk_sock_group_poll_count(struct spdk_sock_group *group, int max_events); */ int spdk_sock_group_close(struct spdk_sock_group **group); +/** + * Get the optimal sock group for this sock. + * + * \param sock The socket + * \param group Returns the optimal sock group. If there is no optimal sock group, returns NULL. + * + * \return 0 on success. Negated errno on failure. + */ +int spdk_sock_get_optimal_sock_group(struct spdk_sock *sock, struct spdk_sock_group **group); + #ifdef __cplusplus } #endif diff --git a/lib/sock/sock.c b/lib/sock/sock.c index 8cf7ee6cd..ba485cfc7 100644 --- a/lib/sock/sock.c +++ b/lib/sock/sock.c @@ -40,6 +40,123 @@ static STAILQ_HEAD(, spdk_net_impl) g_net_impls = STAILQ_HEAD_INITIALIZER(g_net_impls); +struct spdk_sock_placement_id_entry { + int placement_id; + uint32_t ref; + struct spdk_sock_group *group; + STAILQ_ENTRY(spdk_sock_placement_id_entry) link; +}; + +static STAILQ_HEAD(, spdk_sock_placement_id_entry) g_placement_id_map = STAILQ_HEAD_INITIALIZER( + g_placement_id_map); +static pthread_mutex_t g_map_table_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* Insert a group into the placement map. + * If the group is already in the map, take a reference. + */ +static int +spdk_sock_map_insert(int placement_id, struct spdk_sock_group *group) +{ + struct spdk_sock_placement_id_entry *entry; + + pthread_mutex_lock(&g_map_table_mutex); + STAILQ_FOREACH(entry, &g_placement_id_map, link) { + if (placement_id == entry->placement_id) { + /* The mapping already exists, it means that different sockets have + * the same placement_ids. + */ + entry->ref++; + pthread_mutex_unlock(&g_map_table_mutex); + return 0; + } + } + + entry = calloc(1, sizeof(*entry)); + if (!entry) { + SPDK_ERRLOG("Cannot allocate an entry for placement_id=%u\n", placement_id); + pthread_mutex_unlock(&g_map_table_mutex); + return -ENOMEM; + } + + entry->placement_id = placement_id; + entry->group = group; + entry->ref++; + + STAILQ_INSERT_TAIL(&g_placement_id_map, entry, link); + pthread_mutex_unlock(&g_map_table_mutex); + + return 0; +} + +/* Release a reference to the group for a given placement_id. + * If the reference count is 0, remove the group. + */ +static void +spdk_sock_map_release(int placement_id) +{ + struct spdk_sock_placement_id_entry *entry; + + pthread_mutex_lock(&g_map_table_mutex); + STAILQ_FOREACH(entry, &g_placement_id_map, link) { + if (placement_id == entry->placement_id) { + assert(entry->ref > 0); + entry->ref--; + if (!entry->ref) { + STAILQ_REMOVE(&g_placement_id_map, entry, spdk_sock_placement_id_entry, link); + } + break; + } + } + + pthread_mutex_unlock(&g_map_table_mutex); +} + +/* Look up the group for a placement_id. */ +static void +spdk_sock_map_lookup(int placement_id, struct spdk_sock_group **group) +{ + struct spdk_sock_placement_id_entry *entry; + + *group = NULL; + pthread_mutex_lock(&g_map_table_mutex); + STAILQ_FOREACH(entry, &g_placement_id_map, link) { + if (placement_id == entry->placement_id) { + assert(entry->group != NULL); + *group = entry->group; + break; + } + } + pthread_mutex_unlock(&g_map_table_mutex); +} + +/* Remove the socket group from the map table */ +static void +spdk_sock_remove_sock_group_from_map_table(struct spdk_sock_group *group) +{ + struct spdk_sock_placement_id_entry *entry; + + pthread_mutex_lock(&g_map_table_mutex); + STAILQ_FOREACH(entry, &g_placement_id_map, link) { + STAILQ_REMOVE(&g_placement_id_map, entry, spdk_sock_placement_id_entry, link); + } + pthread_mutex_unlock(&g_map_table_mutex); + +} + +int +spdk_sock_get_optimal_sock_group(struct spdk_sock *sock, struct spdk_sock_group **group) +{ + int placement_id = 0, rc; + + rc = sock->net_impl->get_placement_id(sock, &placement_id); + if (!rc && (placement_id != 0)) { + spdk_sock_map_lookup(placement_id, group); + return 0; + } else { + return -1; + } +} + int spdk_sock_getaddr(struct spdk_sock *sock, char *saddr, int slen, uint16_t *sport, char *caddr, int clen, uint16_t *cport) @@ -212,7 +329,7 @@ spdk_sock_group_add_sock(struct spdk_sock_group *group, struct spdk_sock *sock, spdk_sock_cb cb_fn, void *cb_arg) { struct spdk_sock_group_impl *group_impl = NULL; - int rc; + int rc, placement_id = 0; if (cb_fn == NULL) { errno = EINVAL; @@ -228,6 +345,14 @@ spdk_sock_group_add_sock(struct spdk_sock_group *group, struct spdk_sock *sock, return -1; } + rc = sock->net_impl->get_placement_id(sock, &placement_id); + if (!rc && (placement_id != 0)) { + rc = spdk_sock_map_insert(placement_id, group); + if (rc < 0) { + return -1; + } + } + STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) { if (sock->net_impl == group_impl->net_impl) { break; @@ -253,7 +378,7 @@ int spdk_sock_group_remove_sock(struct spdk_sock_group *group, struct spdk_sock *sock) { struct spdk_sock_group_impl *group_impl = NULL; - int rc; + int rc, placement_id = 0; STAILQ_FOREACH_FROM(group_impl, &group->group_impls, link) { if (sock->net_impl == group_impl->net_impl) { @@ -266,6 +391,11 @@ spdk_sock_group_remove_sock(struct spdk_sock_group *group, struct spdk_sock *soc return -1; } + rc = sock->net_impl->get_placement_id(sock, &placement_id); + if (!rc && (placement_id != 0)) { + spdk_sock_map_release(placement_id); + } + rc = group_impl->net_impl->group_impl_remove_sock(group_impl, sock); if (rc == 0) { TAILQ_REMOVE(&group_impl->socks, sock, link); @@ -366,6 +496,7 @@ spdk_sock_group_close(struct spdk_sock_group **group) free(group_impl); } + spdk_sock_remove_sock_group_from_map_table(*group); free(*group); *group = NULL;