diff options
author | Ting Xu <ting.xu@intel.com> | 2022-10-21 16:48:44 +0800 |
---|---|---|
committer | Damjan Marion <dmarion@0xa5.net> | 2022-12-02 13:42:28 +0000 |
commit | a6d16b71308f1badf4b362d26d2326a2977fe462 (patch) | |
tree | 597e7423af50be1eafdd3ef3174703348b093ebc /src/plugins/avf | |
parent | 583d4c94dc69f624a44a8dfa5c82165f3ca27271 (diff) |
avf: support generic flow
Support generic flow in native avf.
Enable necessary RSS hash function for generic flow. Extend some
structures and functions from for FDIR only to for both RSS and FDIR
flows. Modify virtual channel message to align with ice kernel driver.
Add functions to parse generic flow patterns. The parsing results will
be delivered to the kernel driver and create corresponding flow rules.
Type: feature
Signed-off-by: Ting Xu <ting.xu@intel.com>
Change-Id: I82ce102a21993f1bae8a8bf23e491d5e1c261f61
Diffstat (limited to 'src/plugins/avf')
-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) \ |