aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/avf/CMakeLists.txt1
-rw-r--r--src/plugins/avf/avf.h8
-rw-r--r--src/plugins/avf/avf_advanced_flow.h177
-rw-r--r--src/plugins/avf/avf_fdir_lib.c36
-rw-r--r--src/plugins/avf/avf_rss_lib.c141
-rw-r--r--src/plugins/avf/device.c39
-rw-r--r--src/plugins/avf/flow.c286
-rw-r--r--src/plugins/avf/virtchnl.h2
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) \