diff options
-rw-r--r-- | src/plugins/avf/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/plugins/avf/avf.h | 8 | ||||
-rw-r--r-- | src/plugins/avf/avf_advanced_flow.h | 177 | ||||
-rw-r--r-- | src/plugins/avf/avf_fdir_lib.c | 36 | ||||
-rw-r--r-- | src/plugins/avf/avf_rss_lib.c | 141 | ||||
-rw-r--r-- | src/plugins/avf/device.c | 39 | ||||
-rw-r--r-- | src/plugins/avf/flow.c | 286 | ||||
-rw-r--r-- | src/plugins/avf/virtchnl.h | 2 |
8 files changed, 638 insertions, 52 deletions
diff --git a/src/plugins/avf/CMakeLists.txt b/src/plugins/avf/CMakeLists.txt index f7900a64958..ca6f2cb6803 100644 --- a/src/plugins/avf/CMakeLists.txt +++ b/src/plugins/avf/CMakeLists.txt @@ -23,6 +23,7 @@ add_vpp_plugin(avf avf_api.c flow.c avf_fdir_lib.c + avf_rss_lib.c MULTIARCH_SOURCES input.c diff --git a/src/plugins/avf/avf.h b/src/plugins/avf/avf.h index a1da4c8866b..293a1a89937 100644 --- a/src/plugins/avf/avf.h +++ b/src/plugins/avf/avf.h @@ -19,6 +19,7 @@ #define _AVF_H_ #include <avf/virtchnl.h> +#include <avf/avf_advanced_flow.h> #include <vppinfra/types.h> #include <vppinfra/error_bootstrap.h> @@ -37,6 +38,7 @@ #define AVF_AQ_ENQ_SUSPEND_TIME 50e-6 #define AVF_AQ_ENQ_MAX_WAIT_TIME 250e-3 +#define AVF_AQ_BUF_SIZE 4096 #define AVF_RESET_SUSPEND_TIME 20e-3 #define AVF_RESET_MAX_WAIT_TIME 1 @@ -202,7 +204,9 @@ typedef struct { u32 flow_index; u32 mark; + u8 flow_type_flag; struct avf_fdir_conf *rcfg; + struct virtchnl_rss_cfg *rss_cfg; } avf_flow_entry_t; typedef struct @@ -291,6 +295,7 @@ typedef struct u32 calling_process_index; u8 eth_addr[6]; int is_add, is_enable; + enum virthnl_adv_ops vc_op; /* below parameters are used for 'program flow' event */ u8 *rule; @@ -349,7 +354,8 @@ extern vlib_node_registration_t avf_input_node; extern vlib_node_registration_t avf_process_node; extern vnet_device_class_t avf_device_class; -clib_error_t *avf_program_flow (u32 dev_instance, int is_add, u8 *rule, +clib_error_t *avf_program_flow (u32 dev_instance, int is_add, + enum virthnl_adv_ops vc_op, u8 *rule, u32 rule_len, u8 *program_status, u32 status_len); diff --git a/src/plugins/avf/avf_advanced_flow.h b/src/plugins/avf/avf_advanced_flow.h index 42288b7163b..f2a60322b93 100644 --- a/src/plugins/avf/avf_advanced_flow.h +++ b/src/plugins/avf/avf_advanced_flow.h @@ -45,6 +45,7 @@ #define AVF_ETHER_TYPE_IPV6 0x86DD /**< IPv6 Protocol. */ #define VIRTCHNL_MAX_NUM_PROTO_HDRS 32 +#define VIRTCHNL_MAX_SIZE_GEN_PACKET 1024 #define PROTO_HDR_SHIFT 5 #define PROTO_HDR_FIELD_START(proto_hdr_type) \ (proto_hdr_type << PROTO_HDR_SHIFT) @@ -284,14 +285,26 @@ struct virtchnl_proto_hdrs { u8 tunnel_level; /** - * specify where protocol header start from. - * 0 - from the outer layer - * 1 - from the first inner layer - * 2 - from the second inner layer + * specify where protocol header start from. Must be 0 when sending a generic + * packet request. 0 - from the outer layer 1 - from the first inner layer 2 + *- from the second inner layer * .... **/ - int count; /* the proto layers must < VIRTCHNL_MAX_NUM_PROTO_HDRS */ - struct virtchnl_proto_hdr proto_hdr[VIRTCHNL_MAX_NUM_PROTO_HDRS]; + int count; + /** + * the proto layers must < VIRTCHNL_MAX_NUM_PROTO_HDRS. + * Must be 0 when sending a generic packet request. + **/ + union + { + struct virtchnl_proto_hdr proto_hdr[VIRTCHNL_MAX_NUM_PROTO_HDRS]; + struct + { + u16 pkt_len; + u8 spec[VIRTCHNL_MAX_SIZE_GEN_PACKET]; + u8 mask[VIRTCHNL_MAX_SIZE_GEN_PACKET]; + } raw; + }; }; VIRTCHNL_CHECK_STRUCT_LEN (2312, virtchnl_proto_hdrs); @@ -765,6 +778,7 @@ struct avf_flow_item enum virtchnl_proto_hdr_type type; /**< Item type. */ const void *spec; /**< Pointer to item specification structure. */ const void *mask; /**< Bit-mask applied to spec and last. */ + int is_generic; /* indicate if this item is for a generic flow pattern. */ }; struct avf_fdir_conf @@ -783,18 +797,20 @@ enum virthnl_adv_ops VIRTCHNL_ADV_OP_ADD_FDIR_FILTER = 0, VIRTCHNL_ADV_OP_DEL_FDIR_FILTER, VIRTCHNL_ADV_OP_QUERY_FDIR_FILTER, + VIRTCHNL_ADV_OP_ADD_RSS_CFG, + VIRTCHNL_ADV_OP_DEL_RSS_CFG, VIRTCHNL_ADV_OP_MAX }; /* virtual channel op handler */ -typedef int (*avf_fdir_vc_op_t) (void *vc_hdl, enum virthnl_adv_ops vc_op, +typedef int (*avf_flow_vc_op_t) (void *vc_hdl, enum virthnl_adv_ops vc_op, void *in, u32 in_len, void *out, u32 out_len); /* virtual channel context object */ -struct avf_fdir_vc_ctx +struct avf_flow_vc_ctx { void *vc_hdl; /* virtual channel handler */ - avf_fdir_vc_op_t vc_op; + avf_flow_vc_op_t vc_op; }; /** @@ -955,7 +971,7 @@ int avf_fdir_rcfg_act_mark (struct avf_fdir_conf *rcfg, const u32 mark, * 0 = successful. * < 0 = failure. */ -int avf_fdir_rcfg_validate (struct avf_fdir_vc_ctx *ctx, +int avf_fdir_rcfg_validate (struct avf_flow_vc_ctx *ctx, struct avf_fdir_conf *rcfg); /** @@ -971,7 +987,7 @@ int avf_fdir_rcfg_validate (struct avf_fdir_vc_ctx *ctx, * 0 = successfule. * < 0 = failure. */ -int avf_fdir_rule_create (struct avf_fdir_vc_ctx *ctx, +int avf_fdir_rule_create (struct avf_flow_vc_ctx *ctx, struct avf_fdir_conf *rcfg); /** @@ -986,7 +1002,7 @@ int avf_fdir_rule_create (struct avf_fdir_vc_ctx *ctx, * 0 = successfule. * < 0 = failure. */ -int avf_fdir_rule_destroy (struct avf_fdir_vc_ctx *ctx, +int avf_fdir_rule_destroy (struct avf_flow_vc_ctx *ctx, struct avf_fdir_conf *rcfg); /* @@ -1008,6 +1024,24 @@ int avf_fdir_parse_pattern (struct avf_fdir_conf *rcfg, struct avf_flow_error *error); /* + * Parse avf patterns for generic flow and set pattern fields. + * + * @param rcfg + * flow config + * @param avf_items + * pattern items + * @param error + * save error cause + * + * @return + * 0 = successful. + * < 0 = failure + */ +int avf_fdir_parse_generic_pattern (struct avf_fdir_conf *rcfg, + struct avf_flow_item avf_items[], + struct avf_flow_error *error); + +/* * Parse flow actions, set actions. * * @param actions @@ -1025,6 +1059,125 @@ int avf_fdir_parse_action (const struct avf_flow_action actions[], struct avf_fdir_conf *rcfg, struct avf_flow_error *error); +/* + * Parse avf patterns and set pattern fields for RSS. + * + * @param rss_cfg + * flow config + * @param avf_items + * pattern items + * @param error + * save error cause + * + * @return + * 0 = successful. + * < 0 = failure + */ +int avf_rss_parse_pattern (struct virtchnl_rss_cfg *rss_cfg, + struct avf_flow_item avf_items[], + struct avf_flow_error *error); + +/* + * Parse avf patterns and set pattern fields for RSS generic flow. + * + * @param rss_cfg + * flow config + * @param avf_items + * pattern items + * @param error + * save error cause + * + * @return + * 0 = successful. + * < 0 = failure + */ +int avf_rss_parse_generic_pattern (struct virtchnl_rss_cfg *rss_cfg, + struct avf_flow_item avf_items[], + struct avf_flow_error *error); + +/* + * Parse RSS flow actions, set actions. + * + * @param actions + * flow actions + * @param rss_cfg + * flow config + * @param error + * save error cause + * + * @return + * 0 = successful. + * < 0 = failure + */ +int avf_rss_parse_action (const struct avf_flow_action actions[], + struct virtchnl_rss_cfg *rss_cfg, + struct avf_flow_error *error); + +/** + * Create a RSS rule cfg object. + * + * @param rss_cfg + * created rule cfg object. + * @param tunnel + * tunnel level where protocol header start from + * 0 from moster outer layer. + * 1 from first inner layer. + * 2 form second inner layer. + * Must be 0 for generic flow. + * + * @return + * 0 = successful. + * < 0 = failure. + */ +int avf_rss_cfg_create (struct virtchnl_rss_cfg **rss_cfg, int tunnel_level); + +int avf_rss_rcfg_destroy (struct virtchnl_rss_cfg *rss_cfg); + +/** + * Create a RSS flow rule + * + * @param ctx + * virtual channel context + * @param rss_cfg + * rule cfg object. + * + * @return + * 0 = successfule. + * < 0 = failure. + */ +int avf_rss_rule_create (struct avf_flow_vc_ctx *ctx, + struct virtchnl_rss_cfg *rss_cfg); + +/** + * Destroy a RSS flow rule + * + * @param ctx + * virtual channel context + * @param rss_cfg + * rule cfg object. + * + * @return + * 0 = successfule. + * < 0 = failure. + */ +int avf_rss_rule_destroy (struct avf_flow_vc_ctx *ctx, + struct virtchnl_rss_cfg *rss_cfg); + +/** + * Parse generic flow pattern to get spec and mask + * + * @param item + * flow item + * @param pkt_buf + * spec buffer. + * @param msk_buf + * mask buffer . + * @param spec_len + * length of spec. + */ +void avf_parse_generic_pattern (struct avf_flow_item *item, u8 *pkt_buf, + u8 *msk_buf, u16 spec_len); + /** * Initialize flow error structure. * diff --git a/src/plugins/avf/avf_fdir_lib.c b/src/plugins/avf/avf_fdir_lib.c index f38614e87ec..b16c09f9742 100644 --- a/src/plugins/avf/avf_fdir_lib.c +++ b/src/plugins/avf/avf_fdir_lib.c @@ -591,7 +591,7 @@ avf_fdir_rcfg_act_mark (struct avf_fdir_conf *rcfg, const u32 mark, } int -avf_fdir_rcfg_validate (struct avf_fdir_vc_ctx *ctx, +avf_fdir_rcfg_validate (struct avf_flow_vc_ctx *ctx, struct avf_fdir_conf *rcfg) { int ret; @@ -617,7 +617,7 @@ avf_fdir_rcfg_validate (struct avf_fdir_vc_ctx *ctx, } int -avf_fdir_rule_create (struct avf_fdir_vc_ctx *ctx, struct avf_fdir_conf *rcfg) +avf_fdir_rule_create (struct avf_flow_vc_ctx *ctx, struct avf_fdir_conf *rcfg) { int ret; rcfg->add_fltr.vsi_id = rcfg->vsi; @@ -644,7 +644,7 @@ avf_fdir_rule_create (struct avf_fdir_vc_ctx *ctx, struct avf_fdir_conf *rcfg) } int -avf_fdir_rule_destroy (struct avf_fdir_vc_ctx *ctx, struct avf_fdir_conf *rcfg) +avf_fdir_rule_destroy (struct avf_flow_vc_ctx *ctx, struct avf_fdir_conf *rcfg) { int ret; struct virtchnl_fdir_del fdir_ret; @@ -786,6 +786,36 @@ avf_fdir_parse_action (const struct avf_flow_action actions[], } int +avf_fdir_parse_generic_pattern (struct avf_fdir_conf *rcfg, + struct avf_flow_item avf_items[], + struct avf_flow_error *error) +{ + struct avf_flow_item *item = avf_items; + u8 *pkt_buf, *msk_buf; + u16 spec_len, pkt_len; + + spec_len = clib_strnlen (item->spec, VIRTCHNL_MAX_SIZE_GEN_PACKET); + pkt_len = spec_len / 2; + + pkt_buf = clib_mem_alloc (pkt_len); + msk_buf = clib_mem_alloc (pkt_len); + + avf_parse_generic_pattern (item, pkt_buf, msk_buf, spec_len); + + clib_memcpy (rcfg->add_fltr.rule_cfg.proto_hdrs.raw.spec, pkt_buf, pkt_len); + clib_memcpy (rcfg->add_fltr.rule_cfg.proto_hdrs.raw.mask, msk_buf, pkt_len); + + rcfg->add_fltr.rule_cfg.proto_hdrs.count = 0; + rcfg->add_fltr.rule_cfg.proto_hdrs.tunnel_level = 0; + rcfg->add_fltr.rule_cfg.proto_hdrs.raw.pkt_len = pkt_len; + + clib_mem_free (pkt_buf); + clib_mem_free (msk_buf); + + return 0; +} + +int avf_fdir_parse_pattern (struct avf_fdir_conf *rcfg, struct avf_flow_item avf_items[], struct avf_flow_error *error) diff --git a/src/plugins/avf/avf_rss_lib.c b/src/plugins/avf/avf_rss_lib.c new file mode 100644 index 00000000000..45843bdb00d --- /dev/null +++ b/src/plugins/avf/avf_rss_lib.c @@ -0,0 +1,141 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2022 Intel and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +#include <vppinfra/mem.h> +#include "avf_advanced_flow.h" + +int +avf_rss_cfg_create (struct virtchnl_rss_cfg **rss_cfg, int tunnel_level) +{ + *rss_cfg = clib_mem_alloc (sizeof (**rss_cfg)); + if ((*rss_cfg) == NULL) + return -1; + + clib_memset (*rss_cfg, 0, sizeof (**rss_cfg)); + + (*rss_cfg)->proto_hdrs.tunnel_level = tunnel_level; + + return 0; +} + +int +avf_rss_rcfg_destroy (struct virtchnl_rss_cfg *rss_cfg) +{ + clib_mem_free (rss_cfg); + + return 0; +} + +int +avf_rss_parse_action (const struct avf_flow_action actions[], + struct virtchnl_rss_cfg *rss_cfg, + struct avf_flow_error *error) +{ + const struct avf_flow_action_rss *rss; + int ret; + + rss = actions->conf; + + if (rss->func == AVF_ETH_HASH_FUNCTION_SIMPLE_XOR) + { + rss_cfg->rss_algorithm = VIRTCHNL_RSS_ALG_XOR_ASYMMETRIC; + ret = avf_flow_error_set (error, AVF_FAILURE, AVF_FLOW_ERROR_TYPE_ACTION, + actions, "simple xor is not supported."); + return ret; + } + else if (rss->func == AVF_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) + { + rss_cfg->rss_algorithm = VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC; + } + else + { + rss_cfg->rss_algorithm = VIRTCHNL_RSS_ALG_TOEPLITZ_ASYMMETRIC; + } + + return 0; +} + +int +avf_rss_parse_generic_pattern (struct virtchnl_rss_cfg *rss_cfg, + struct avf_flow_item avf_items[], + struct avf_flow_error *error) +{ + struct avf_flow_item *item = avf_items; + u8 *pkt_buf, *msk_buf; + u16 spec_len, pkt_len; + + spec_len = clib_strnlen (item->spec, VIRTCHNL_MAX_SIZE_GEN_PACKET); + pkt_len = spec_len / 2; + + pkt_buf = clib_mem_alloc (pkt_len); + msk_buf = clib_mem_alloc (pkt_len); + + avf_parse_generic_pattern (item, pkt_buf, msk_buf, spec_len); + + clib_memcpy (rss_cfg->proto_hdrs.raw.spec, pkt_buf, pkt_len); + clib_memcpy (rss_cfg->proto_hdrs.raw.mask, msk_buf, pkt_len); + + rss_cfg->proto_hdrs.count = 0; + rss_cfg->proto_hdrs.tunnel_level = 0; + rss_cfg->proto_hdrs.raw.pkt_len = pkt_len; + + clib_mem_free (pkt_buf); + clib_mem_free (msk_buf); + + return 0; +} + +/* Used for common flow creation */ +int +avf_rss_parse_pattern (struct virtchnl_rss_cfg *rss_cfg, + struct avf_flow_item avf_items[], + struct avf_flow_error *error) +{ + return -1; +} + +int +avf_rss_rule_create (struct avf_flow_vc_ctx *ctx, + struct virtchnl_rss_cfg *rss_cfg) +{ + int ret; + + ret = ctx->vc_op (ctx->vc_hdl, VIRTCHNL_ADV_OP_ADD_RSS_CFG, rss_cfg, + sizeof (*rss_cfg), 0, 0); + + return ret; +} + +int +avf_rss_rule_destroy (struct avf_flow_vc_ctx *ctx, + struct virtchnl_rss_cfg *rss_cfg) +{ + int ret; + + ret = ctx->vc_op (ctx->vc_hdl, VIRTCHNL_ADV_OP_DEL_RSS_CFG, rss_cfg, + sizeof (*rss_cfg), 0, 0); + + return ret; +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/avf/device.c b/src/plugins/avf/device.c index ae6597da183..b0f6244cdaf 100644 --- a/src/plugins/avf/device.c +++ b/src/plugins/avf/device.c @@ -1241,16 +1241,32 @@ error: clib_error_t * avf_op_program_flow (vlib_main_t *vm, avf_device_t *ad, int is_create, - u8 *rule, u32 rule_len, u8 *program_status, - u32 status_len) + enum virthnl_adv_ops vc_op, u8 *rule, u32 rule_len, + u8 *program_status, u32 status_len) { + virtchnl_ops_t op; + avf_log_debug (ad, "avf_op_program_flow: vsi_id %u is_create %u", ad->vsi_id, is_create); - return avf_send_to_pf (vm, ad, - is_create ? VIRTCHNL_OP_ADD_FDIR_FILTER : - VIRTCHNL_OP_DEL_FDIR_FILTER, - rule, rule_len, program_status, status_len); + switch (vc_op) + { + case VIRTCHNL_ADV_OP_ADD_FDIR_FILTER: + case VIRTCHNL_ADV_OP_DEL_FDIR_FILTER: + op = + is_create ? VIRTCHNL_OP_ADD_FDIR_FILTER : VIRTCHNL_OP_DEL_FDIR_FILTER; + break; + case VIRTCHNL_ADV_OP_ADD_RSS_CFG: + case VIRTCHNL_ADV_OP_DEL_RSS_CFG: + op = is_create ? VIRTCHNL_OP_ADD_RSS_CFG : VIRTCHNL_OP_DEL_RSS_CFG; + break; + default: + return clib_error_return (0, "invalid virtchnl opcode"); + ; + } + + return avf_send_to_pf (vm, ad, op, rule, rule_len, program_status, + status_len); } static void @@ -1264,9 +1280,9 @@ avf_process_handle_request (vlib_main_t * vm, avf_process_req_t * req) else if (req->type == AVF_PROCESS_REQ_CONFIG_PROMISC_MDDE) req->error = avf_op_config_promisc_mode (vm, ad, req->is_enable); else if (req->type == AVF_PROCESS_REQ_PROGRAM_FLOW) - req->error = - avf_op_program_flow (vm, ad, req->is_add, req->rule, req->rule_len, - req->program_status, req->status_len); + req->error = avf_op_program_flow (vm, ad, req->is_add, req->vc_op, + req->rule, req->rule_len, + req->program_status, req->status_len); else clib_panic ("BUG: unknown avf proceess request type"); @@ -1894,8 +1910,8 @@ avf_clear_hw_interface_counters (u32 instance) } clib_error_t * -avf_program_flow (u32 dev_instance, int is_add, u8 *rule, u32 rule_len, - u8 *program_status, u32 status_len) +avf_program_flow (u32 dev_instance, int is_add, enum virthnl_adv_ops vc_op, + u8 *rule, u32 rule_len, u8 *program_status, u32 status_len) { vlib_main_t *vm = vlib_get_main (); avf_process_req_t req; @@ -1903,6 +1919,7 @@ avf_program_flow (u32 dev_instance, int is_add, u8 *rule, u32 rule_len, req.dev_instance = dev_instance; req.type = AVF_PROCESS_REQ_PROGRAM_FLOW; req.is_add = is_add; + req.vc_op = vc_op; req.rule = rule; req.rule_len = rule_len; req.program_status = program_status; diff --git a/src/plugins/avf/flow.c b/src/plugins/avf/flow.c index e0d21cd96a2..37cac004f6d 100644 --- a/src/plugins/avf/flow.c +++ b/src/plugins/avf/flow.c @@ -44,6 +44,8 @@ (f->type == VNET_FLOW_TYPE_IP6_N_TUPLE_TAGGED) || \ (f->type == VNET_FLOW_TYPE_IP6_VXLAN)) +#define FLOW_IS_GENERIC_CLASS(f) (f->type == VNET_FLOW_TYPE_GENERIC) + /* check if flow is L3 type */ #define FLOW_IS_L3_TYPE(f) \ ((f->type == VNET_FLOW_TYPE_IP4) || (f->type == VNET_FLOW_TYPE_IP6)) @@ -63,7 +65,7 @@ (f->type == VNET_FLOW_TYPE_IP4_GTPU)) int -avf_fdir_vc_op_callback (void *vc_hdl, enum virthnl_adv_ops vc_op, void *in, +avf_flow_vc_op_callback (void *vc_hdl, enum virthnl_adv_ops vc_op, void *in, u32 in_len, void *out, u32 out_len) { u32 dev_instance = *(u32 *) vc_hdl; @@ -79,9 +81,11 @@ avf_fdir_vc_op_callback (void *vc_hdl, enum virthnl_adv_ops vc_op, void *in, switch (vc_op) { case VIRTCHNL_ADV_OP_ADD_FDIR_FILTER: + case VIRTCHNL_ADV_OP_ADD_RSS_CFG: is_add = 1; break; case VIRTCHNL_ADV_OP_DEL_FDIR_FILTER: + case VIRTCHNL_ADV_OP_DEL_RSS_CFG: is_add = 0; break; default: @@ -90,18 +94,114 @@ avf_fdir_vc_op_callback (void *vc_hdl, enum virthnl_adv_ops vc_op, void *in, return -1; } - err = avf_program_flow (dev_instance, is_add, in, in_len, out, out_len); + err = + avf_program_flow (dev_instance, is_add, vc_op, in, in_len, out, out_len); if (err != 0) { - avf_log_err (ad, "avf fdir program failed: %U", format_clib_error, err); + avf_log_err (ad, "avf flow program failed: %U", format_clib_error, err); clib_error_free (err); return -1; } - avf_log_debug (ad, "avf fdir program success"); + avf_log_debug (ad, "avf flow program success"); return 0; } +static inline enum avf_eth_hash_function +avf_flow_convert_rss_func (vnet_rss_function_t func) +{ + enum avf_eth_hash_function rss_func; + + switch (func) + { + case VNET_RSS_FUNC_DEFAULT: + rss_func = AVF_ETH_HASH_FUNCTION_DEFAULT; + break; + case VNET_RSS_FUNC_TOEPLITZ: + rss_func = AVF_ETH_HASH_FUNCTION_TOEPLITZ; + break; + case VNET_RSS_FUNC_SIMPLE_XOR: + rss_func = AVF_ETH_HASH_FUNCTION_SIMPLE_XOR; + break; + case VNET_RSS_FUNC_SYMMETRIC_TOEPLITZ: + rss_func = AVF_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ; + break; + default: + rss_func = AVF_ETH_HASH_FUNCTION_MAX; + break; + } + + return rss_func; +} + +/** Maximum number of queue indices in struct avf_flow_action_rss. */ +#define ACTION_RSS_QUEUE_NUM 128 + +static inline void +avf_flow_convert_rss_queues (u32 queue_index, u32 queue_num, + struct avf_flow_action_rss *act_rss) +{ + u16 *queues = clib_mem_alloc (sizeof (*queues) * ACTION_RSS_QUEUE_NUM); + int i; + + for (i = 0; i < queue_num; i++) + queues[i] = queue_index++; + + act_rss->queue_num = queue_num; + act_rss->queue = queues; + + return; +} + +void +avf_parse_generic_pattern (struct avf_flow_item *item, u8 *pkt_buf, + u8 *msk_buf, u16 spec_len) +{ + u8 *raw_spec, *raw_mask; + u8 tmp_val = 0; + u8 tmp_c = 0; + int i, j; + + raw_spec = (u8 *) item->spec; + raw_mask = (u8 *) item->mask; + + /* convert string to int array */ + for (i = 0, j = 0; i < spec_len; i += 2, j++) + { + tmp_c = raw_spec[i]; + if (tmp_c >= 'a' && tmp_c <= 'f') + tmp_val = tmp_c - 'a' + 10; + if (tmp_c >= 'A' && tmp_c <= 'F') + tmp_val = tmp_c - 'A' + 10; + if (tmp_c >= '0' && tmp_c <= '9') + tmp_val = tmp_c - '0'; + + tmp_c = raw_spec[i + 1]; + if (tmp_c >= 'a' && tmp_c <= 'f') + pkt_buf[j] = tmp_val * 16 + tmp_c - 'a' + 10; + if (tmp_c >= 'A' && tmp_c <= 'F') + pkt_buf[j] = tmp_val * 16 + tmp_c - 'A' + 10; + if (tmp_c >= '0' && tmp_c <= '9') + pkt_buf[j] = tmp_val * 16 + tmp_c - '0'; + + tmp_c = raw_mask[i]; + if (tmp_c >= 'a' && tmp_c <= 'f') + tmp_val = tmp_c - 0x57; + if (tmp_c >= 'A' && tmp_c <= 'F') + tmp_val = tmp_c - 0x37; + if (tmp_c >= '0' && tmp_c <= '9') + tmp_val = tmp_c - '0'; + + tmp_c = raw_mask[i + 1]; + if (tmp_c >= 'a' && tmp_c <= 'f') + msk_buf[j] = tmp_val * 16 + tmp_c - 'a' + 10; + if (tmp_c >= 'A' && tmp_c <= 'F') + msk_buf[j] = tmp_val * 16 + tmp_c - 'A' + 10; + if (tmp_c >= '0' && tmp_c <= '9') + msk_buf[j] = tmp_val * 16 + tmp_c - '0'; + } +} + static int avf_flow_add (u32 dev_instance, vnet_flow_t *f, avf_flow_entry_t *fe) { @@ -112,13 +212,15 @@ avf_flow_add (u32 dev_instance, vnet_flow_t *f, avf_flow_entry_t *fe) u16 src_port_mask = 0, dst_port_mask = 0; u8 protocol = IP_PROTOCOL_RESERVED; bool fate = false; + bool is_fdir = true; struct avf_flow_error error; int layer = 0; int action_count = 0; - struct avf_fdir_vc_ctx vc_ctx; + struct avf_flow_vc_ctx vc_ctx; struct avf_fdir_conf *filter; + struct virtchnl_rss_cfg *rss_cfg; struct avf_flow_item avf_items[VIRTCHNL_MAX_NUM_PROTO_HDRS]; struct avf_flow_action avf_actions[VIRTCHNL_MAX_NUM_ACTIONS]; @@ -133,6 +235,7 @@ avf_flow_add (u32 dev_instance, vnet_flow_t *f, avf_flow_entry_t *fe) struct avf_flow_action_queue act_q = {}; struct avf_flow_action_mark act_msk = {}; + struct avf_flow_action_rss act_rss = {}; enum { @@ -140,6 +243,7 @@ avf_flow_add (u32 dev_instance, vnet_flow_t *f, avf_flow_entry_t *fe) FLOW_ETHERNET_CLASS, FLOW_IPV4_CLASS, FLOW_IPV6_CLASS, + FLOW_GENERIC_CLASS, } flow_class = FLOW_UNKNOWN_CLASS; if (FLOW_IS_ETHERNET_CLASS (f)) @@ -148,6 +252,8 @@ avf_flow_add (u32 dev_instance, vnet_flow_t *f, avf_flow_entry_t *fe) flow_class = FLOW_IPV4_CLASS; else if (FLOW_IS_IPV6_CLASS (f)) flow_class = FLOW_IPV6_CLASS; + else if (FLOW_IS_GENERIC_CLASS (f)) + flow_class = FLOW_GENERIC_CLASS; else return VNET_FLOW_ERROR_NOT_SUPPORTED; @@ -158,13 +264,32 @@ avf_flow_add (u32 dev_instance, vnet_flow_t *f, avf_flow_entry_t *fe) goto done; } + ret = avf_rss_cfg_create (&rss_cfg, 0); + if (ret) + { + rv = VNET_FLOW_ERROR_INTERNAL; + goto done; + } + /* init a virtual channel context */ vc_ctx.vc_hdl = &dev_instance; - vc_ctx.vc_op = avf_fdir_vc_op_callback; + vc_ctx.vc_op = avf_flow_vc_op_callback; clib_memset (avf_items, 0, sizeof (avf_actions)); clib_memset (avf_actions, 0, sizeof (avf_actions)); + /* Handle generic flow first */ + if (flow_class == FLOW_GENERIC_CLASS) + { + avf_items[layer].is_generic = true; + avf_items[layer].spec = f->generic.pattern.spec; + avf_items[layer].mask = f->generic.pattern.mask; + + layer++; + + goto pattern_end; + } + /* Ethernet Layer */ avf_items[layer].type = VIRTCHNL_PROTO_HDR_ETH; avf_items[layer].spec = NULL; @@ -349,13 +474,6 @@ avf_flow_add (u32 dev_instance, vnet_flow_t *f, avf_flow_entry_t *fe) pattern_end: /* pattern end flag */ avf_items[layer].type = VIRTCHNL_PROTO_HDR_NONE; - ret = avf_fdir_parse_pattern (filter, avf_items, &error); - if (ret) - { - avf_log_err (ad, "avf fdir parse pattern failed: %s", error.message); - rv = VNET_FLOW_ERROR_NOT_SUPPORTED; - goto done; - } /* Action */ /* Only one 'fate' can be assigned */ @@ -385,6 +503,37 @@ pattern_end: action_count++; } + if (f->actions & VNET_FLOW_ACTION_RSS) + { + avf_actions[action_count].conf = &act_rss; + + if ((act_rss.func = avf_flow_convert_rss_func (f->rss_fun)) == + AVF_ETH_HASH_FUNCTION_MAX) + { + rv = VNET_FLOW_ERROR_NOT_SUPPORTED; + goto done; + } + + if (f->queue_num) + { + /* convert rss queues to array */ + avf_flow_convert_rss_queues (f->queue_index, f->queue_num, &act_rss); + avf_actions[action_count].type = VIRTCHNL_ACTION_Q_REGION; + is_fdir = true; + } + + is_fdir = false; + + if (fate == true) + { + rv = VNET_FLOW_ERROR_INTERNAL; + goto done; + } + else + fate = true; + action_count++; + } + if (fate == false) { avf_actions[action_count].type = VIRTCHNL_ACTION_PASSTHRU; @@ -406,14 +555,39 @@ pattern_end: /* action end flag */ avf_actions[action_count].type = VIRTCHNL_ACTION_NONE; - /* parse action */ - ret = avf_fdir_parse_action (avf_actions, filter, &error); - if (ret) + /* parse pattern and actions */ + if (is_fdir) { - avf_log_err (ad, "avf fdir parse action failed: %s", error.message); - rv = VNET_FLOW_ERROR_NOT_SUPPORTED; - goto done; - } + if (flow_class == FLOW_GENERIC_CLASS) + { + ret = avf_fdir_parse_generic_pattern (filter, avf_items, &error); + if (ret) + { + avf_log_err (ad, "avf fdir parse generic pattern failed: %s", + error.message); + rv = VNET_FLOW_ERROR_NOT_SUPPORTED; + goto done; + } + } + else + { + ret = avf_fdir_parse_pattern (filter, avf_items, &error); + if (ret) + { + avf_log_err (ad, "avf fdir parse pattern failed: %s", + error.message); + rv = VNET_FLOW_ERROR_NOT_SUPPORTED; + goto done; + } + } + + ret = avf_fdir_parse_action (avf_actions, filter, &error); + if (ret) + { + avf_log_err (ad, "avf fdir parse action failed: %s", error.message); + rv = VNET_FLOW_ERROR_NOT_SUPPORTED; + goto done; + } /* create flow rule, save rule */ ret = avf_fdir_rule_create (&vc_ctx, filter); @@ -428,7 +602,58 @@ pattern_end: else { fe->rcfg = filter; + fe->flow_type_flag = 1; + } + } + else + { + if (flow_class == FLOW_GENERIC_CLASS) + { + ret = avf_rss_parse_generic_pattern (rss_cfg, avf_items, &error); + if (ret) + { + avf_log_err (ad, "avf rss parse generic pattern failed: %s", + error.message); + rv = VNET_FLOW_ERROR_NOT_SUPPORTED; + goto done; + } + } + else + { + ret = avf_rss_parse_pattern (rss_cfg, avf_items, &error); + if (ret) + { + avf_log_warn (ad, + "avf rss is not supported except generic flow"); + rv = VNET_FLOW_ERROR_NOT_SUPPORTED; + goto done; + } + } + + ret = avf_rss_parse_action (avf_actions, rss_cfg, &error); + if (ret) + { + avf_log_err (ad, "avf rss parse action failed: %s", error.message); + rv = VNET_FLOW_ERROR_NOT_SUPPORTED; + goto done; + } + + /* create flow rule, save rule */ + ret = avf_rss_rule_create (&vc_ctx, rss_cfg); + + if (ret) + { + avf_log_err (ad, "avf rss rule create failed"); + rv = VNET_FLOW_ERROR_INTERNAL; + goto done; + } + else + { + fe->rss_cfg = rss_cfg; + fe->flow_type_flag = 0; + } } + done: return rv; @@ -495,6 +720,7 @@ avf_flow_ops_fn (vnet_main_t *vm, vnet_flow_dev_op_t op, u32 dev_instance, case VNET_FLOW_TYPE_IP4_L2TPV3OIP: case VNET_FLOW_TYPE_IP4_IPSEC_ESP: case VNET_FLOW_TYPE_IP4_IPSEC_AH: + case VNET_FLOW_TYPE_GENERIC: if ((rv = avf_flow_add (dev_instance, flow, fe))) goto done; break; @@ -509,13 +735,22 @@ avf_flow_ops_fn (vnet_main_t *vm, vnet_flow_dev_op_t op, u32 dev_instance, { fe = vec_elt_at_index (ad->flow_entries, *private_data); - struct avf_fdir_vc_ctx ctx; + struct avf_flow_vc_ctx ctx; ctx.vc_hdl = &dev_instance; - ctx.vc_op = avf_fdir_vc_op_callback; + ctx.vc_op = avf_flow_vc_op_callback; - rv = avf_fdir_rule_destroy (&ctx, fe->rcfg); - if (rv) - return VNET_FLOW_ERROR_INTERNAL; + if (fe->flow_type_flag) + { + rv = avf_fdir_rule_destroy (&ctx, fe->rcfg); + if (rv) + return VNET_FLOW_ERROR_INTERNAL; + } + else + { + rv = avf_rss_rule_destroy (&ctx, fe->rss_cfg); + if (rv) + return VNET_FLOW_ERROR_INTERNAL; + } if (fe->mark) { @@ -525,6 +760,7 @@ avf_flow_ops_fn (vnet_main_t *vm, vnet_flow_dev_op_t op, u32 dev_instance, } (void) avf_fdir_rcfg_destroy (fe->rcfg); + (void) avf_rss_rcfg_destroy (fe->rss_cfg); clib_memset (fe, 0, sizeof (*fe)); pool_put (ad->flow_entries, fe); goto disable_rx_offload; diff --git a/src/plugins/avf/virtchnl.h b/src/plugins/avf/virtchnl.h index ae4fe4a5e3c..98d6f4adf8d 100644 --- a/src/plugins/avf/virtchnl.h +++ b/src/plugins/avf/virtchnl.h @@ -97,6 +97,8 @@ enum _ (31, DISABLE_CHANNELS) \ _ (32, ADD_CLOUD_FILTER) \ _ (33, DEL_CLOUD_FILTER) \ + _ (45, ADD_RSS_CFG) \ + _ (46, DEL_RSS_CFG) \ _ (47, ADD_FDIR_FILTER) \ _ (48, DEL_FDIR_FILTER) \ _ (49, QUERY_FDIR_FILTER) \ |