From f5a45680ee1c9c586ab2b037e3d71354789e4403 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Beno=C3=AEt=20Ganne?= Date: Wed, 17 Mar 2021 14:41:33 +0100 Subject: [PATCH] rdma: add support for RSS configuration MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Type: feature Change-Id: I911ee94b624ef5edf46b34666597eff93df1d1ed Signed-off-by: Benoît Ganne --- src/plugins/rdma/api.c | 63 +++++++++++++++++++++++++++++++ src/plugins/rdma/device.c | 58 +++++++++++++++++++++++----- src/plugins/rdma/format.c | 40 +++++++++++++++++++- src/plugins/rdma/rdma.api | 66 +++++++++++++++++++++++++++++++- src/plugins/rdma/rdma.h | 21 +++++++++++ src/plugins/rdma/test_api.c | 92 ++++++++++++++++++++++++++++++++++++++++++++- src/plugins/rdma/unformat.c | 12 ++++++ 7 files changed, 338 insertions(+), 14 deletions(-) diff --git a/src/plugins/rdma/api.c b/src/plugins/rdma/api.c index 06e7385136f..7fe77105596 100644 --- a/src/plugins/rdma/api.c +++ b/src/plugins/rdma/api.c @@ -44,6 +44,69 @@ rdma_api_mode (vl_api_rdma_mode_t mode) return RDMA_MODE_AUTO; } +static rdma_rss4_t +rdma_api_rss4 (const vl_api_rdma_rss4_t rss4) +{ + switch (rss4) + { + case RDMA_API_RSS4_AUTO: + return RDMA_RSS4_AUTO; + case RDMA_API_RSS4_IP: + return RDMA_RSS4_IP; + case RDMA_API_RSS4_IP_UDP: + return RDMA_RSS4_IP_UDP; + case RDMA_API_RSS4_IP_TCP: + return RDMA_RSS4_IP_TCP; + } + return RDMA_RSS4_AUTO; +} + +static rdma_rss6_t +rdma_api_rss6 (const vl_api_rdma_rss6_t rss6) +{ + switch (rss6) + { + case RDMA_API_RSS6_AUTO: + return RDMA_RSS6_AUTO; + case RDMA_API_RSS6_IP: + return RDMA_RSS6_IP; + case RDMA_API_RSS6_IP_UDP: + return RDMA_RSS6_IP_UDP; + case RDMA_API_RSS6_IP_TCP: + return RDMA_RSS6_IP_TCP; + } + return RDMA_RSS6_AUTO; +} + +static void +vl_api_rdma_create_v3_t_handler (vl_api_rdma_create_v3_t *mp) +{ + vlib_main_t *vm = vlib_get_main (); + rdma_main_t *rm = &rdma_main; + vl_api_rdma_create_v3_reply_t *rmp; + rdma_create_if_args_t args; + int rv; + + clib_memset (&args, 0, sizeof (rdma_create_if_args_t)); + + args.ifname = mp->host_if; + args.name = mp->name; + args.rxq_num = ntohs (mp->rxq_num); + args.rxq_size = ntohs (mp->rxq_size); + args.txq_size = ntohs (mp->txq_size); + args.mode = rdma_api_mode (mp->mode); + args.disable_striding_rq = 0; + args.no_multi_seg = mp->no_multi_seg; + args.max_pktlen = ntohs (mp->max_pktlen); + args.rss4 = rdma_api_rss4 (mp->rss4); + args.rss6 = rdma_api_rss6 (mp->rss6); + rdma_create_if (vm, &args); + rv = args.rv; + + REPLY_MACRO2 (VL_API_RDMA_CREATE_V3_REPLY + rm->msg_id_base, + ({ rmp->sw_if_index = ntohl (args.sw_if_index); })); +} + static void vl_api_rdma_create_v2_t_handler (vl_api_rdma_create_v2_t * mp) { diff --git a/src/plugins/rdma/device.c b/src/plugins/rdma/device.c index 14262f597b7..1198d99b14e 100644 --- a/src/plugins/rdma/device.c +++ b/src/plugins/rdma/device.c @@ -311,7 +311,7 @@ rdma_async_event_read_ready (clib_file_t * f) vlib_log_emerg (rm->log_class, "%s: fatal error", rd->name); break; default: - rdma_log__ (VLIB_LOG_LEVEL_ERR, rd, "unhandeld RDMA async event %i", + rdma_log__ (VLIB_LOG_LEVEL_ERR, rd, "unhandeld RDMA async event %d", event.event_type); break; } @@ -611,8 +611,46 @@ rdma_rxq_init (vlib_main_t * vm, rdma_device_t * rd, u16 qid, u32 n_desc, return 0; } +static uint64_t +rdma_rss42ibv (const rdma_rss4_t rss4) +{ + switch (rss4) + { + case RDMA_RSS4_IP: + return IBV_RX_HASH_SRC_IPV4 | IBV_RX_HASH_DST_IPV4; + case RDMA_RSS4_IP_UDP: + return IBV_RX_HASH_SRC_IPV4 | IBV_RX_HASH_DST_IPV4 | + IBV_RX_HASH_SRC_PORT_UDP | IBV_RX_HASH_DST_PORT_UDP; + case RDMA_RSS4_AUTO: /* fallthrough */ + case RDMA_RSS4_IP_TCP: + return IBV_RX_HASH_SRC_IPV4 | IBV_RX_HASH_DST_IPV4 | + IBV_RX_HASH_SRC_PORT_TCP | IBV_RX_HASH_DST_PORT_TCP; + } + ASSERT (0); + return 0; +} + +static uint64_t +rdma_rss62ibv (const rdma_rss6_t rss6) +{ + switch (rss6) + { + case RDMA_RSS6_IP: + return IBV_RX_HASH_SRC_IPV6 | IBV_RX_HASH_DST_IPV6; + case RDMA_RSS6_IP_UDP: + return IBV_RX_HASH_SRC_IPV6 | IBV_RX_HASH_DST_IPV6 | + IBV_RX_HASH_SRC_PORT_UDP | IBV_RX_HASH_DST_PORT_UDP; + case RDMA_RSS6_AUTO: /* fallthrough */ + case RDMA_RSS6_IP_TCP: + return IBV_RX_HASH_SRC_IPV6 | IBV_RX_HASH_DST_IPV6 | + IBV_RX_HASH_SRC_PORT_TCP | IBV_RX_HASH_DST_PORT_TCP; + } + ASSERT (0); + return 0; +} + static clib_error_t * -rdma_rxq_finalize (vlib_main_t * vm, rdma_device_t * rd) +rdma_rxq_finalize (vlib_main_t *vm, rdma_device_t *rd) { struct ibv_rwq_ind_table_init_attr rwqia; struct ibv_qp_init_attr_ex qpia; @@ -658,15 +696,11 @@ rdma_rxq_finalize (vlib_main_t * vm, rdma_device_t * rd) qpia.rx_hash_conf.rx_hash_key = rdma_rss_hash_key; qpia.rx_hash_conf.rx_hash_function = IBV_RX_HASH_FUNC_TOEPLITZ; - qpia.rx_hash_conf.rx_hash_fields_mask = - IBV_RX_HASH_SRC_IPV4 | IBV_RX_HASH_DST_IPV4 | IBV_RX_HASH_SRC_PORT_TCP | - IBV_RX_HASH_DST_PORT_TCP; + qpia.rx_hash_conf.rx_hash_fields_mask = rdma_rss42ibv (rd->rss4); if ((rd->rx_qp4 = ibv_create_qp_ex (rd->ctx, &qpia)) == 0) return clib_error_return_unix (0, "IPv4 Queue Pair create failed"); - qpia.rx_hash_conf.rx_hash_fields_mask = - IBV_RX_HASH_SRC_IPV6 | IBV_RX_HASH_DST_IPV6 | IBV_RX_HASH_SRC_PORT_TCP | - IBV_RX_HASH_DST_PORT_TCP; + qpia.rx_hash_conf.rx_hash_fields_mask = rdma_rss62ibv (rd->rss6); if ((rd->rx_qp6 = ibv_create_qp_ex (rd->ctx, &qpia)) == 0) return clib_error_return_unix (0, "IPv6 Queue Pair create failed"); @@ -802,6 +836,9 @@ rdma_dev_init (vlib_main_t * vm, rdma_device_t * rd, ethernet_mac_address_generate (rd->hwaddr.bytes); + rd->rss4 = args->rss4; + rd->rss6 = args->rss6; + /* * /!\ WARNING /!\ creation order is important * We *must* create TX queues *before* RX queues, otherwise we will receive @@ -862,8 +899,9 @@ rdma_create_if (vlib_main_t * vm, rdma_create_if_args_t * args) !is_pow2 (args->rxq_size) || !is_pow2 (args->txq_size)) { args->rv = VNET_API_ERROR_INVALID_VALUE; - args->error = clib_error_return (0, "queue size must be a power of two " - "between %i and 65535", + args->error = clib_error_return (0, + "queue size must be a power of two " + "between %d and 65535", VLIB_FRAME_SIZE); goto err0; } diff --git a/src/plugins/rdma/format.c b/src/plugins/rdma/format.c index 84b6439a2fd..aada52a1ec3 100644 --- a/src/plugins/rdma/format.c +++ b/src/plugins/rdma/format.c @@ -72,6 +72,42 @@ format_rdma_bit_flag (u8 * s, va_list * args) return s; } +u8 * +format_rdma_rss4 (u8 *s, va_list *args) +{ + const rdma_rss4_t *rss4 = va_arg (*args, const rdma_rss4_t *); + switch (*rss4) + { + case RDMA_RSS4_IP: + return format (s, "ipv4"); + case RDMA_RSS4_IP_UDP: + return format (s, "ipv4-udp"); + case RDMA_RSS4_AUTO: /* fallthrough */ + case RDMA_RSS4_IP_TCP: + return format (s, "ipv4-tcp"); + } + ASSERT (0); + return format (s, "unknown(%x)", *rss4); +} + +u8 * +format_rdma_rss6 (u8 *s, va_list *args) +{ + const rdma_rss6_t *rss6 = va_arg (*args, const rdma_rss6_t *); + switch (*rss6) + { + case RDMA_RSS6_IP: + return format (s, "ipv6"); + case RDMA_RSS6_IP_UDP: + return format (s, "ipv6-udp"); + case RDMA_RSS6_AUTO: /* fallthrough */ + case RDMA_RSS6_IP_TCP: + return format (s, "ipv6-tcp"); + } + ASSERT (0); + return format (s, "unknown(%x)", *rss6); +} + u8 * format_rdma_device (u8 * s, va_list * args) { @@ -96,8 +132,10 @@ format_rdma_device (u8 * s, va_list * args) format_vlib_pci_vpd, d->vpd_r, "SN"); vlib_pci_free_device_info (d); } - s = format (s, "%Uflags: %U", format_white_space, indent, + s = format (s, "%Uflags: %U\n", format_white_space, indent, format_rdma_device_flags, rd); + s = format (s, "%Urss: %U %U", format_white_space, indent, format_rdma_rss4, + &rd->rss4, format_rdma_rss6, &rd->rss6); if (rd->error) s = format (s, "\n%Uerror %U", format_white_space, indent, format_clib_error, rd->error); diff --git a/src/plugins/rdma/rdma.api b/src/plugins/rdma/rdma.api index 4519e2316d3..f2c70c7e514 100644 --- a/src/plugins/rdma/rdma.api +++ b/src/plugins/rdma/rdma.api @@ -15,7 +15,7 @@ *------------------------------------------------------------------ */ -option version = "2.0.0"; +option version = "3.0.0"; import "vnet/interface_types.api"; enum rdma_mode @@ -25,7 +25,6 @@ enum rdma_mode RDMA_API_MODE_DV = 2, }; - /** \brief @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -67,6 +66,7 @@ define rdma_create define rdma_create_v2 { + option deprecated; u32 client_index; u32 context; @@ -81,6 +81,55 @@ define rdma_create_v2 option vat_help = " [name ] [rx-queue-size ] [tx-queue-size ] [num-rx-queues ] [mode ] [no-multi-seg] [max-pktlen ]"; }; +enum rdma_rss4 +{ + RDMA_API_RSS4_AUTO = 0, + RDMA_API_RSS4_IP = 1, + RDMA_API_RSS4_IP_UDP = 2, + RDMA_API_RSS4_IP_TCP = 3, +}; + +enum rdma_rss6 +{ + RDMA_API_RSS6_AUTO = 0, + RDMA_API_RSS6_IP = 1, + RDMA_API_RSS6_IP_UDP = 2, + RDMA_API_RSS6_IP_TCP = 3, +}; + +/** \brief + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param host_if - Linux netdev interface name + @param name - new rdma interface name + @param rxq_num - number of receive queues (optional) + @param rxq_size - receive queue size (optional) + @param txq_size - transmit queue size (optional) + @param mode - operation mode (optional) + @param no_multi_seg (optional) - disable chained buffer RX + @param max_pktlen (optional) - maximal RX packet size. + @param rss4 (optional) - IPv4 RSS + @param rss6 (optional) - IPv6 RSS +*/ + +define rdma_create_v3 +{ + u32 client_index; + u32 context; + + string host_if[64]; + string name[64]; + u16 rxq_num [default=1]; + u16 rxq_size [default=1024]; + u16 txq_size [default=1024]; + vl_api_rdma_mode_t mode [default=0]; + bool no_multi_seg [default=0]; + u16 max_pktlen [default=0]; + vl_api_rdma_rss4_t rss4 [default=0]; + vl_api_rdma_rss6_t rss6 [default=0]; + option vat_help = " [name ] [rx-queue-size ] [tx-queue-size ] [num-rx-queues ] [mode ] [no-multi-seg] [max-pktlen ] [rss ] [rss ]"; +}; + /** \brief @param context - sender context, to match reply w/ request @@ -114,6 +163,19 @@ define rdma_create_v2_reply @param sw_if_index - interface index */ +define rdma_create_v3_reply +{ + u32 context; + i32 retval; + vl_api_interface_index_t sw_if_index; +}; + +/** \brief + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sw_if_index - interface index +*/ + autoreply define rdma_delete { u32 client_index; diff --git a/src/plugins/rdma/rdma.h b/src/plugins/rdma/rdma.h index a8ab07012ee..323275c9f50 100644 --- a/src/plugins/rdma/rdma.h +++ b/src/plugins/rdma/rdma.h @@ -174,6 +174,23 @@ STATIC_ASSERT_OFFSET_OF (rdma_txq_t, cacheline2, 128); #define RDMA_RXQ_MAX_CHAIN_LOG_SZ 3 /* This should NOT be lower than 3! */ #define RDMA_RXQ_MAX_CHAIN_SZ (1U << RDMA_RXQ_MAX_CHAIN_LOG_SZ) #define RDMA_RXQ_LEGACY_MODE_MAX_CHAIN_SZ 5 + +typedef enum +{ + RDMA_RSS4_AUTO = 0, + RDMA_RSS4_IP, + RDMA_RSS4_IP_UDP, + RDMA_RSS4_IP_TCP, +} rdma_rss4_t; + +typedef enum +{ + RDMA_RSS6_AUTO = 0, + RDMA_RSS6_IP, + RDMA_RSS6_IP_UDP, + RDMA_RSS6_IP_TCP, +} rdma_rss6_t; + typedef struct { CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); @@ -195,6 +212,8 @@ typedef struct mac_address_t hwaddr; u32 async_event_clib_file_index; u32 dev_instance; + rdma_rss4_t rss4; + rdma_rss6_t rss6; struct ibv_context *ctx; struct ibv_pd *pd; @@ -264,6 +283,8 @@ typedef struct u8 no_multi_seg; u8 disable_striding_rq; u16 max_pktlen; + rdma_rss4_t rss4; + rdma_rss6_t rss6; /* return */ int rv; diff --git a/src/plugins/rdma/test_api.c b/src/plugins/rdma/test_api.c index ff5dec1ad95..e9d5fcaad98 100644 --- a/src/plugins/rdma/test_api.c +++ b/src/plugins/rdma/test_api.c @@ -58,6 +58,40 @@ api_rdma_mode (rdma_mode_t mode) return ~0; } +static vl_api_rdma_rss4_t +api_rdma_rss4 (rdma_rss4_t rss4) +{ + switch (rss4) + { + case RDMA_RSS4_AUTO: + return RDMA_API_RSS4_AUTO; + case RDMA_RSS4_IP: + return RDMA_API_RSS4_IP; + case RDMA_RSS4_IP_UDP: + return RDMA_API_RSS4_IP_UDP; + case RDMA_RSS4_IP_TCP: + return RDMA_API_RSS4_IP_TCP; + } + return ~0; +} + +static vl_api_rdma_rss6_t +api_rdma_rss6 (rdma_rss6_t rss6) +{ + switch (rss6) + { + case RDMA_RSS6_AUTO: + return RDMA_API_RSS6_AUTO; + case RDMA_RSS6_IP: + return RDMA_API_RSS6_IP; + case RDMA_RSS6_IP_UDP: + return RDMA_API_RSS6_IP_UDP; + case RDMA_RSS6_IP_TCP: + return RDMA_API_RSS6_IP_TCP; + } + return ~0; +} + /* rdma create API */ static int api_rdma_create (vat_main_t * vam) @@ -103,7 +137,10 @@ api_rdma_create_v2 (vat_main_t * vam) M (RDMA_CREATE_V2, mp); snprintf ((char *) mp->host_if, sizeof (mp->host_if), "%s", args.ifname); - snprintf ((char *) mp->name, sizeof (mp->name), "%s", args.name); + if (args.name) + snprintf ((char *) mp->name, sizeof (mp->name), "%s", args.name); + else + mp->name[0] = 0; mp->rxq_num = clib_host_to_net_u16 (args.rxq_num); mp->rxq_size = clib_host_to_net_u16 (args.rxq_size); mp->txq_size = clib_host_to_net_u16 (args.txq_size); @@ -117,6 +154,41 @@ api_rdma_create_v2 (vat_main_t * vam) return ret; } +static int +api_rdma_create_v3 (vat_main_t *vam) +{ + vl_api_rdma_create_v3_t *mp; + rdma_create_if_args_t args; + int ret; + + if (!unformat_user (vam->input, unformat_rdma_create_if_args, &args)) + { + clib_warning ("unknown input `%U'", format_unformat_error, vam->input); + return -99; + } + + M (RDMA_CREATE_V3, mp); + + snprintf ((char *) mp->host_if, sizeof (mp->host_if), "%s", args.ifname); + if (args.name) + snprintf ((char *) mp->name, sizeof (mp->name), "%s", args.name); + else + mp->name[0] = 0; + mp->rxq_num = clib_host_to_net_u16 (args.rxq_num); + mp->rxq_size = clib_host_to_net_u16 (args.rxq_size); + mp->txq_size = clib_host_to_net_u16 (args.txq_size); + mp->mode = api_rdma_mode (args.mode); + mp->no_multi_seg = args.no_multi_seg; + mp->max_pktlen = clib_host_to_net_u16 (args.max_pktlen); + mp->rss4 = api_rdma_rss4 (args.rss4); + mp->rss6 = api_rdma_rss6 (args.rss6); + + S (mp); + W (ret); + + return ret; +} + /* rdma-create reply handler */ static void vl_api_rdma_create_reply_t_handler (vl_api_rdma_create_reply_t * mp) @@ -153,6 +225,24 @@ vl_api_rdma_create_v2_reply_t_handler (vl_api_rdma_create_v2_reply_t * mp) vam->regenerate_interface_table = 1; } +/* rdma-create reply handler v3 */ +static void +vl_api_rdma_create_v3_reply_t_handler (vl_api_rdma_create_v3_reply_t *mp) +{ + vat_main_t *vam = rdma_test_main.vat_main; + i32 retval = ntohl (mp->retval); + + if (retval == 0) + { + fformat (vam->ofp, "created rdma with sw_if_index %d\n", + ntohl (mp->sw_if_index)); + } + + vam->retval = retval; + vam->result_ready = 1; + vam->regenerate_interface_table = 1; +} + /* rdma delete API */ static int api_rdma_delete (vat_main_t * vam) diff --git a/src/plugins/rdma/unformat.c b/src/plugins/rdma/unformat.c index 26c184793bd..c529958b585 100644 --- a/src/plugins/rdma/unformat.c +++ b/src/plugins/rdma/unformat.c @@ -54,6 +54,18 @@ unformat_rdma_create_if_args (unformat_input_t * input, va_list * vargs) args->no_multi_seg = 1; else if (unformat (line_input, "max-pktlen %u", &tmp)) args->max_pktlen = tmp; + else if (unformat (line_input, "rss ipv4-udp")) + args->rss4 = RDMA_RSS4_IP_UDP; + else if (unformat (line_input, "rss ipv4-tcp")) + args->rss4 = RDMA_RSS4_IP_TCP; + else if (unformat (line_input, "rss ipv4")) + args->rss4 = RDMA_RSS4_IP; + else if (unformat (line_input, "rss ipv6-udp")) + args->rss6 = RDMA_RSS6_IP_UDP; + else if (unformat (line_input, "rss ipv6-tcp")) + args->rss6 = RDMA_RSS6_IP_TCP; + else if (unformat (line_input, "rss ipv6")) + args->rss6 = RDMA_RSS6_IP; else { /* return failure on unknown input */ -- 2.16.6