From 5a218cdfefca845fa39526a545cc6902f18d422b Mon Sep 17 00:00:00 2001 From: Hassan Khadour Date: Thu, 29 Jun 2023 00:49:36 +0300 Subject: [PATCH] Add ipv6 address support for initial communication. Currenty initial negotiation performed via ipv4 which is not suitable for modern ipv6 only topology. This patch allow to specify which address family to use, default behaviour not changed. New option: --ipv6-addr Usage example: ./ib_write_bw -d mlx5_0 --ipv6-addr ./ib_write_bw -d mlx5_0 --ipv6-addr 2a02:6b8:c0e:97f:0:441d:9fbd:3f1e signed-off-by: Dmitry Monakhov Signed-off-by: Hassan Khadour --- man/perftest.1 | 4 +++ src/perftest_communication.c | 50 +++++++++++++++++++++--------------- src/perftest_parameters.c | 9 +++++++ src/perftest_parameters.h | 1 + src/perftest_resources.c | 19 +++++++++++++- src/perftest_resources.h | 13 ++++++++++ 6 files changed, 75 insertions(+), 21 deletions(-) diff --git a/man/perftest.1 b/man/perftest.1 index d3f6f780..6fc8e816 100644 --- a/man/perftest.1 +++ b/man/perftest.1 @@ -268,6 +268,10 @@ many different options and modes. Use IPv6 GID. Default is IPv4. Not relevant for RawEth. .TP +.B --ipv6-addr= + Use IPv6 address for parameters negotiation. Default is IPv4. + Not relevant for RawEth. +.TP .B --bind_source_ip Source IP of the interface used for connection establishment. By default taken from routing table. Not relevant for RawEth. diff --git a/src/perftest_communication.c b/src/perftest_communication.c index db9ae6dd..1c464d59 100755 --- a/src/perftest_communication.c +++ b/src/perftest_communication.c @@ -669,7 +669,7 @@ static int ethernet_client_connect(struct perftest_comm *comm) int sockfd = -1; memset(&hints, 0, sizeof hints); - hints.ai_family = AF_INET; + hints.ai_family = comm->rdma_params->ai_family; hints.ai_socktype = SOCK_STREAM; if (comm->rdma_params->has_source_ip) { @@ -726,7 +726,7 @@ static int ethernet_server_connect(struct perftest_comm *comm) memset(&hints, 0, sizeof hints); hints.ai_flags = AI_PASSIVE; - hints.ai_family = AF_INET; + hints.ai_family = comm->rdma_params->ai_family; hints.ai_socktype = SOCK_STREAM; if (check_add_port(&service,comm->rdma_params->port,src_ip,&hints,&res)) @@ -736,6 +736,9 @@ static int ethernet_server_connect(struct perftest_comm *comm) } for (t = res; t; t = t->ai_next) { + if (t->ai_family != comm->rdma_params->ai_family) + continue; + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); if (sockfd >= 0) { @@ -906,7 +909,8 @@ int rdma_client_connect(struct pingpong_context *ctx,struct perftest_parameters { char *service; int temp,num_of_retry= NUM_OF_RETRIES; - struct sockaddr_in sin, source_sin; + struct sockaddr_storage source_sin; + struct sockaddr *sin; struct sockaddr *source_ptr = NULL; struct addrinfo *res; struct rdma_cm_event *event; @@ -914,7 +918,7 @@ int rdma_client_connect(struct pingpong_context *ctx,struct perftest_parameters struct addrinfo hints; memset(&hints, 0, sizeof hints); - hints.ai_family = AF_INET; + hints.ai_family = user_param->ai_family; hints.ai_socktype = SOCK_STREAM; if (check_add_port(&service,user_param->port,user_param->servername,&hints,&res)) { @@ -922,13 +926,13 @@ int rdma_client_connect(struct pingpong_context *ctx,struct perftest_parameters return FAILURE; } - if (res->ai_family != PF_INET) { + if (res->ai_family != user_param->ai_family) { freeaddrinfo(res); return FAILURE; } - memcpy(&sin, res->ai_addr, sizeof(sin)); - freeaddrinfo(res); - sin.sin_port = htons((unsigned short)user_param->port); + + sin = res->ai_addr; + sockaddr_set_port(sin, (unsigned short)user_param->port); if (user_param->has_source_ip) { if (check_add_port(&service, 0x0, user_param->source_ip, &hints, &res)) @@ -940,7 +944,6 @@ int rdma_client_connect(struct pingpong_context *ctx,struct perftest_parameters //coverity[deref_after_free] memcpy(&source_sin, res->ai_addr, sizeof(source_sin)); source_ptr = (struct sockaddr *)&source_sin; - freeaddrinfo(res); } while (1) { @@ -950,12 +953,14 @@ int rdma_client_connect(struct pingpong_context *ctx,struct perftest_parameters return FAILURE; } - if (rdma_resolve_addr(ctx->cm_id, source_ptr, (struct sockaddr *)&sin, 2000)) { + if (rdma_resolve_addr(ctx->cm_id, source_ptr, sin, 2000)) { + freeaddrinfo(res); fprintf(stderr, "rdma_resolve_addr failed\n"); return FAILURE; } if (rdma_get_cm_event(ctx->cm_channel,&event)) { + freeaddrinfo(res); fprintf(stderr, "rdma_get_cm_events failed\n"); return FAILURE; } @@ -969,6 +974,7 @@ int rdma_client_connect(struct pingpong_context *ctx,struct perftest_parameters if (event->event != RDMA_CM_EVENT_ADDR_RESOLVED) { fprintf(stderr, "unexpected CM event %d\n",event->event); + freeaddrinfo(res); rdma_ack_cm_event(event); return FAILURE; } @@ -977,6 +983,8 @@ int rdma_client_connect(struct pingpong_context *ctx,struct perftest_parameters break; } + freeaddrinfo(res); + if (user_param->tos != DEF_TOS) { if (rdma_set_option(ctx->cm_id,RDMA_OPTION_ID,RDMA_OPTION_ID_TOS,&user_param->tos,sizeof(uint8_t))) { @@ -1124,35 +1132,36 @@ int rdma_server_connect(struct pingpong_context *ctx, struct rdma_conn_param conn_param; struct addrinfo hints; char *service; - struct sockaddr_in sin; + struct sockaddr *sin; char* src_ip = user_param->has_source_ip ? user_param->source_ip : NULL; memset(&hints, 0, sizeof hints); hints.ai_flags = AI_PASSIVE; - hints.ai_family = AF_INET; + hints.ai_family = user_param->ai_family; hints.ai_socktype = SOCK_STREAM; - memset(&sin, 0x0, sizeof(sin)); - if (check_add_port(&service,user_param->port,src_ip,&hints,&res)) { fprintf(stderr, "Problem in resolving basic address and port\n"); return FAILURE; } - if (res->ai_family != PF_INET) { + if (res->ai_family != user_param->ai_family) { freeaddrinfo(res); return FAILURE; } - memcpy(&sin, res->ai_addr, sizeof(sin)); - sin.sin_port = htons((unsigned short)user_param->port); - freeaddrinfo(res); - if (rdma_bind_addr(ctx->cm_id_control,(struct sockaddr *)&sin)) { + sin = res->ai_addr; + sockaddr_set_port(sin, (unsigned short)user_param->port); + + if (rdma_bind_addr(ctx->cm_id_control, sin)) { + freeaddrinfo(res); fprintf(stderr," rdma_bind_addr failed\n"); return 1; } + freeaddrinfo(res); + if (rdma_listen(ctx->cm_id_control, user_param->num_of_qps)) { fprintf(stderr, "rdma_listen failed\n"); return 1; @@ -1243,6 +1252,7 @@ int create_comm_struct(struct perftest_comm *comm, memset(comm->rdma_params, 0, sizeof(struct perftest_parameters)); comm->rdma_params->port = user_param->port; + comm->rdma_params->ai_family = user_param->ai_family; comm->rdma_params->sockfd = -1; comm->rdma_params->gid_index = user_param->gid_index; comm->rdma_params->gid_index2 = user_param->gid_index2; @@ -2034,7 +2044,7 @@ int rdma_cm_get_rdma_address(struct perftest_parameters *user_param, char port[6] = "", error_message[ERROR_MSG_SIZE] = ""; sprintf(port, "%d", user_param->port); - hints->ai_family = AF_INET; + hints->ai_family = user_param->ai_family; // if we have servername specified, it is a client, we should use server name // if it is not specified, we should use explicit source_ip if possible if ((NULL != user_param->servername) || (!user_param->has_source_ip)) { diff --git a/src/perftest_parameters.c b/src/perftest_parameters.c index 1257f8f8..67281f70 100755 --- a/src/perftest_parameters.c +++ b/src/perftest_parameters.c @@ -461,6 +461,8 @@ static void usage(const char *argv0, VerbType verb, TestType tst, int connection if (connection_type != RawEth) { printf(" --ipv6 "); printf(" Use IPv6 GID. Default is IPv4\n"); + printf(" --ipv6-addr= "); + printf(" Use IPv6 address for parameters negotiation. Default is IPv4\n"); } // please note it is a different source_ip from raw_ethernet case @@ -816,6 +818,7 @@ static void init_perftest_params(struct perftest_parameters *user_param) user_param->retry_count = DEF_RETRY_COUNT; user_param->dont_xchg_versions = 0; user_param->ipv6 = 0; + user_param->ai_family = AF_INET; user_param->report_per_port = 0; user_param->use_odp = 0; user_param->use_hugepages = 0; @@ -2175,6 +2178,7 @@ int parser(struct perftest_parameters *user_param,char *argv[], int argc) static int mmap_file_flag = 0; static int mmap_offset_flag = 0; static int ipv6_flag = 0; + static int ipv6_addr_flag = 0; static int raw_ipv6_flag = 0; static int report_per_port_flag = 0; static int odp_flag = 0; @@ -2326,6 +2330,7 @@ int parser(struct perftest_parameters *user_param,char *argv[], int argc) { .name = "mmap", .has_arg = 1, .flag = &mmap_file_flag, .val = 1}, { .name = "mmap-offset", .has_arg = 1, .flag = &mmap_offset_flag, .val = 1}, { .name = "ipv6", .has_arg = 0, .flag = &ipv6_flag, .val = 1}, + { .name = "ipv6-addr", .has_arg = 0, .flag = &ipv6_addr_flag, .val = 1}, #ifdef HAVE_IPV6 { .name = "raw_ipv6", .has_arg = 0, .flag = &raw_ipv6_flag, .val = 1}, #endif @@ -3047,6 +3052,10 @@ int parser(struct perftest_parameters *user_param,char *argv[], int argc) user_param->ipv6 = 1; } + if (ipv6_addr_flag) { + user_param->ai_family = AF_INET6; + } + if (raw_ipv6_flag) { if (user_param->is_new_raw_eth_param) { if (user_param->is_server_ip) { diff --git a/src/perftest_parameters.h b/src/perftest_parameters.h index 0ed65ba5..559bfa48 100755 --- a/src/perftest_parameters.h +++ b/src/perftest_parameters.h @@ -602,6 +602,7 @@ struct perftest_parameters { int dont_xchg_versions; int ipv6; int raw_ipv6; + int ai_family; int report_per_port; int use_odp; int use_hugepages; diff --git a/src/perftest_resources.c b/src/perftest_resources.c index 971eb8fe..d9ec4319 100755 --- a/src/perftest_resources.c +++ b/src/perftest_resources.c @@ -831,13 +831,30 @@ int check_add_port(char **service,int port, free(*service); if (number < 0) { - fprintf(stderr, "%s for %s:%d\n", gai_strerror(number), servername, port); + fprintf(stderr, "%s for ai_family: %x service: %s port: %d\n", + gai_strerror(number), hints->ai_family, servername, port); return FAILURE; } return SUCCESS; } +/****************************************************************************** + * + ******************************************************************************/ +int sockaddr_set_port(struct sockaddr *sin,int port) +{ + switch (sin->sa_family) { + case AF_INET: ((struct sockaddr_in*) sin)->sin_port = htons(port); + break; + case AF_INET6: ((struct sockaddr_in6*) sin)->sin6_port = htons(port); + break; + default: + fprintf(stderr, "ai_family: %x is not yet supported\n", sin->sa_family); + return FAILURE; + } + return SUCCESS; +} /****************************************************************************** * ******************************************************************************/ diff --git a/src/perftest_resources.h b/src/perftest_resources.h index 274c9e7c..e782dded 100755 --- a/src/perftest_resources.h +++ b/src/perftest_resources.h @@ -260,6 +260,19 @@ int check_add_port(char **service,int port, struct addrinfo *hints, struct addrinfo **res); +/* sockaddr_set_port + * + * Description : Initialize port for given sockaddr structure + * + * Parameters : + * service - an empty char** to contain the service name. + * port - The selected port on which the server will listen. + * sin - sockaddr params for the connection. + * + * Return Value : SUCCESS, FAILURE. + */ +int sockaddr_set_port(struct sockaddr *sin,int port); + /* ctx_find_dev * * Description : Returns the device corresponding to ib_devname