Commit 2dce2390 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch '40GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue

Tony Nguyen says:

====================
ice: iavf: add support for TC U32 filters on VFs

Ahmed Zaki says:

The Intel Ethernet 800 Series is designed with a pipeline that has
an on-chip programmable capability called Dynamic Device Personalization
(DDP). A DDP package is loaded by the driver during probe time. The DDP
package programs functionality in both the parser and switching blocks in
the pipeline, allowing dynamic support for new and existing protocols.
Once the pipeline is configured, the driver can identify the protocol and
apply any HW action in different stages, for example, direct packets to
desired hardware queues (flow director), queue groups or drop.

Patches 1-8 introduce a DDP package parser API that enables different
pipeline stages in the driver to learn the HW parser capabilities from
the DDP package that is downloaded to HW. The parser library takes raw
packet patterns and masks (in binary) indicating the packet protocol fields
to be matched and generates the final HW profiles that can be applied at
the required stage. With this API, raw flow filtering for FDIR or RSS
could be done on new protocols or headers without any driver or Kernel
updates (only need to update the DDP package). These patches were submitted
before [1] but were not accepted mainly due to lack of a user.

Patches 9-11 extend the virtchnl support to allow the VF to request raw
flow director filters. Upon receiving the raw FDIR filter request, the PF
driver allocates and runs a parser lib instance and generates the hardware
profile definitions required to program the FDIR stage. These were also
submitted before [2].

Finally, patches 12 and 13 add TC U32 filter support to the iavf driver.
Using the parser API, the ice driver runs the raw patterns sent by the
user and then adds a new profile to the FDIR stage associated with the VF's
VSI. Refer to examples in patch 13 commit message.

[1]: https://lore.kernel.org/netdev/20230904021455.3944605-1-junfeng.guo@intel.com/
[2]: https://lore.kernel.org/intel-wired-lan/20230818064703.154183-1-junfeng.guo@intel.com/

* '40GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue:
  iavf: add support for offloading tc U32 cls filters
  iavf: refactor add/del FDIR filters
  ice: enable FDIR filters from raw binary patterns for VFs
  ice: add method to disable FDIR SWAP option
  virtchnl: support raw packet in protocol header
  ice: add API for parser profile initialization
  ice: add UDP tunnels support to the parser
  ice: support turning on/off the parser's double vlan mode
  ice: add parser execution main loop
  ice: add parser internal helper functions
  ice: add debugging functions for the parser sections
  ice: parse and init various DDP parser sections
  ice: add parser create and destroy skeleton
====================

Link: https://patch.msgid.link/20240813222249.3708070-1-anthony.l.nguyen@intel.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 795b1aa8 623122ac
......@@ -33,6 +33,7 @@
#include <net/udp.h>
#include <net/tc_act/tc_gact.h>
#include <net/tc_act/tc_mirred.h>
#include <net/tc_act/tc_skbedit.h>
#include "iavf_type.h"
#include <linux/avf/virtchnl.h>
......@@ -393,6 +394,8 @@ struct iavf_adapter {
VIRTCHNL_VF_OFFLOAD_VLAN_V2)
#define CRC_OFFLOAD_ALLOWED(_a) ((_a)->vf_res->vf_cap_flags & \
VIRTCHNL_VF_OFFLOAD_CRC)
#define TC_U32_SUPPORT(_a) ((_a)->vf_res->vf_cap_flags & \
VIRTCHNL_VF_OFFLOAD_TC_U32)
#define VLAN_V2_FILTERING_ALLOWED(_a) \
(VLAN_V2_ALLOWED((_a)) && \
((_a)->vlan_v2_caps.filtering.filtering_support.outer || \
......@@ -437,6 +440,7 @@ struct iavf_adapter {
#define IAVF_MAX_FDIR_FILTERS 128 /* max allowed Flow Director filters */
u16 fdir_active_fltr;
u16 raw_fdir_active_fltr;
struct list_head fdir_list_head;
spinlock_t fdir_fltr_lock; /* protect the Flow Director filter list */
......@@ -444,6 +448,32 @@ struct iavf_adapter {
spinlock_t adv_rss_lock; /* protect the RSS management list */
};
/* Must be called with fdir_fltr_lock lock held */
static inline bool iavf_fdir_max_reached(struct iavf_adapter *adapter)
{
return adapter->fdir_active_fltr + adapter->raw_fdir_active_fltr >=
IAVF_MAX_FDIR_FILTERS;
}
static inline void
iavf_inc_fdir_active_fltr(struct iavf_adapter *adapter,
struct iavf_fdir_fltr *fltr)
{
if (iavf_is_raw_fdir(fltr))
adapter->raw_fdir_active_fltr++;
else
adapter->fdir_active_fltr++;
}
static inline void
iavf_dec_fdir_active_fltr(struct iavf_adapter *adapter,
struct iavf_fdir_fltr *fltr)
{
if (iavf_is_raw_fdir(fltr))
adapter->raw_fdir_active_fltr--;
else
adapter->fdir_active_fltr--;
}
/* Ethtool Private Flags */
......
......@@ -927,7 +927,7 @@ iavf_get_ethtool_fdir_entry(struct iavf_adapter *adapter,
spin_lock_bh(&adapter->fdir_fltr_lock);
rule = iavf_find_fdir_fltr_by_loc(adapter, fsp->location);
rule = iavf_find_fdir_fltr(adapter, false, fsp->location);
if (!rule) {
ret = -EINVAL;
goto release_lock;
......@@ -1072,6 +1072,9 @@ iavf_get_fdir_fltr_ids(struct iavf_adapter *adapter, struct ethtool_rxnfc *cmd,
spin_lock_bh(&adapter->fdir_fltr_lock);
list_for_each_entry(fltr, &adapter->fdir_list_head, list) {
if (iavf_is_raw_fdir(fltr))
continue;
if (cnt == cmd->rule_cnt) {
val = -EMSGSIZE;
goto release_lock;
......@@ -1263,15 +1266,7 @@ static int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
return -EINVAL;
spin_lock_bh(&adapter->fdir_fltr_lock);
if (adapter->fdir_active_fltr >= IAVF_MAX_FDIR_FILTERS) {
spin_unlock_bh(&adapter->fdir_fltr_lock);
dev_err(&adapter->pdev->dev,
"Unable to add Flow Director filter because VF reached the limit of max allowed filters (%u)\n",
IAVF_MAX_FDIR_FILTERS);
return -ENOSPC;
}
if (iavf_find_fdir_fltr_by_loc(adapter, fsp->location)) {
if (iavf_find_fdir_fltr(adapter, false, fsp->location)) {
dev_err(&adapter->pdev->dev, "Failed to add Flow Director filter, it already exists\n");
spin_unlock_bh(&adapter->fdir_fltr_lock);
return -EEXIST;
......@@ -1291,23 +1286,10 @@ static int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
}
err = iavf_add_fdir_fltr_info(adapter, fsp, fltr);
if (err)
goto ret;
spin_lock_bh(&adapter->fdir_fltr_lock);
iavf_fdir_list_add_fltr(adapter, fltr);
adapter->fdir_active_fltr++;
if (adapter->link_up)
fltr->state = IAVF_FDIR_FLTR_ADD_REQUEST;
else
fltr->state = IAVF_FDIR_FLTR_INACTIVE;
spin_unlock_bh(&adapter->fdir_fltr_lock);
if (!err)
err = iavf_fdir_add_fltr(adapter, fltr);
if (adapter->link_up)
iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_FDIR_FILTER);
ret:
if (err && fltr)
if (err)
kfree(fltr);
mutex_unlock(&adapter->crit_lock);
......@@ -1324,34 +1306,11 @@ static int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
static int iavf_del_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rxnfc *cmd)
{
struct ethtool_rx_flow_spec *fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
struct iavf_fdir_fltr *fltr = NULL;
int err = 0;
if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))
return -EOPNOTSUPP;
spin_lock_bh(&adapter->fdir_fltr_lock);
fltr = iavf_find_fdir_fltr_by_loc(adapter, fsp->location);
if (fltr) {
if (fltr->state == IAVF_FDIR_FLTR_ACTIVE) {
fltr->state = IAVF_FDIR_FLTR_DEL_REQUEST;
} else if (fltr->state == IAVF_FDIR_FLTR_INACTIVE) {
list_del(&fltr->list);
kfree(fltr);
adapter->fdir_active_fltr--;
fltr = NULL;
} else {
err = -EBUSY;
}
} else if (adapter->fdir_active_fltr) {
err = -EINVAL;
}
spin_unlock_bh(&adapter->fdir_fltr_lock);
if (fltr && fltr->state == IAVF_FDIR_FLTR_DEL_REQUEST)
iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_DEL_FDIR_FILTER);
return err;
return iavf_fdir_del_fltr(adapter, false, fsp->location);
}
/**
......
......@@ -796,6 +796,9 @@ bool iavf_fdir_is_dup_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *
spin_lock_bh(&adapter->fdir_fltr_lock);
list_for_each_entry(tmp, &adapter->fdir_list_head, list) {
if (iavf_is_raw_fdir(fltr))
continue;
if (tmp->flow_type != fltr->flow_type)
continue;
......@@ -815,33 +818,52 @@ bool iavf_fdir_is_dup_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *
}
/**
* iavf_find_fdir_fltr_by_loc - find filter with location
* iavf_find_fdir_fltr - find FDIR filter
* @adapter: pointer to the VF adapter structure
* @loc: location to find.
* @is_raw: filter type, is raw (tc u32) or not (ethtool)
* @data: data to ID the filter, type dependent
*
* Returns pointer to Flow Director filter if found or null
* Returns: pointer to Flow Director filter if found or NULL. Lock must be held.
*/
struct iavf_fdir_fltr *iavf_find_fdir_fltr_by_loc(struct iavf_adapter *adapter, u32 loc)
struct iavf_fdir_fltr *iavf_find_fdir_fltr(struct iavf_adapter *adapter,
bool is_raw, u32 data)
{
struct iavf_fdir_fltr *rule;
list_for_each_entry(rule, &adapter->fdir_list_head, list)
if (rule->loc == loc)
list_for_each_entry(rule, &adapter->fdir_list_head, list) {
if ((is_raw && rule->cls_u32_handle == data) ||
(!is_raw && rule->loc == data))
return rule;
}
return NULL;
}
/**
* iavf_fdir_list_add_fltr - add a new node to the flow director filter list
* iavf_fdir_add_fltr - add a new node to the flow director filter list
* @adapter: pointer to the VF adapter structure
* @fltr: filter node to add to structure
*
* Return: 0 on success or negative errno on failure.
*/
void iavf_fdir_list_add_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr)
int iavf_fdir_add_fltr(struct iavf_adapter *adapter,
struct iavf_fdir_fltr *fltr)
{
struct iavf_fdir_fltr *rule, *parent = NULL;
spin_lock_bh(&adapter->fdir_fltr_lock);
if (iavf_fdir_max_reached(adapter)) {
spin_unlock_bh(&adapter->fdir_fltr_lock);
dev_err(&adapter->pdev->dev,
"Unable to add Flow Director filter (limit (%u) reached)\n",
IAVF_MAX_FDIR_FILTERS);
return -ENOSPC;
}
list_for_each_entry(rule, &adapter->fdir_list_head, list) {
if (iavf_is_raw_fdir(fltr))
break;
if (rule->loc >= fltr->loc)
break;
parent = rule;
......@@ -851,4 +873,55 @@ void iavf_fdir_list_add_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr
list_add(&fltr->list, &parent->list);
else
list_add(&fltr->list, &adapter->fdir_list_head);
iavf_inc_fdir_active_fltr(adapter, fltr);
if (adapter->link_up)
fltr->state = IAVF_FDIR_FLTR_ADD_REQUEST;
else
fltr->state = IAVF_FDIR_FLTR_INACTIVE;
spin_unlock_bh(&adapter->fdir_fltr_lock);
if (adapter->link_up)
iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_FDIR_FILTER);
return 0;
}
/**
* iavf_fdir_del_fltr - delete a flow director filter from the list
* @adapter: pointer to the VF adapter structure
* @is_raw: filter type, is raw (tc u32) or not (ethtool)
* @data: data to ID the filter, type dependent
*
* Return: 0 on success or negative errno on failure.
*/
int iavf_fdir_del_fltr(struct iavf_adapter *adapter, bool is_raw, u32 data)
{
struct iavf_fdir_fltr *fltr = NULL;
int err = 0;
spin_lock_bh(&adapter->fdir_fltr_lock);
fltr = iavf_find_fdir_fltr(adapter, is_raw, data);
if (fltr) {
if (fltr->state == IAVF_FDIR_FLTR_ACTIVE) {
fltr->state = IAVF_FDIR_FLTR_DEL_REQUEST;
} else if (fltr->state == IAVF_FDIR_FLTR_INACTIVE) {
list_del(&fltr->list);
iavf_dec_fdir_active_fltr(adapter, fltr);
kfree(fltr);
fltr = NULL;
} else {
err = -EBUSY;
}
} else if (adapter->fdir_active_fltr) {
err = -EINVAL;
}
if (fltr && fltr->state == IAVF_FDIR_FLTR_DEL_REQUEST)
iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_DEL_FDIR_FILTER);
spin_unlock_bh(&adapter->fdir_fltr_lock);
return err;
}
......@@ -117,17 +117,26 @@ struct iavf_fdir_fltr {
u32 flow_id;
u32 cls_u32_handle; /* for FDIR added via tc u32 */
u32 loc; /* Rule location inside the flow table */
u32 q_index;
struct virtchnl_fdir_add vc_add_msg;
};
static inline bool iavf_is_raw_fdir(struct iavf_fdir_fltr *fltr)
{
return !fltr->vc_add_msg.rule_cfg.proto_hdrs.count;
}
int iavf_validate_fdir_fltr_masks(struct iavf_adapter *adapter,
struct iavf_fdir_fltr *fltr);
int iavf_fill_fdir_add_msg(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr);
void iavf_print_fdir_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr);
bool iavf_fdir_is_dup_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr);
void iavf_fdir_list_add_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr);
struct iavf_fdir_fltr *iavf_find_fdir_fltr_by_loc(struct iavf_adapter *adapter, u32 loc);
int iavf_fdir_add_fltr(struct iavf_adapter *adapter,
struct iavf_fdir_fltr *fltr);
int iavf_fdir_del_fltr(struct iavf_adapter *adapter, bool is_raw, u32 data);
struct iavf_fdir_fltr *iavf_find_fdir_fltr(struct iavf_adapter *adapter,
bool is_raw, u32 data);
#endif /* _IAVF_FDIR_H_ */
......@@ -4013,7 +4013,7 @@ static int iavf_delete_clsflower(struct iavf_adapter *adapter,
/**
* iavf_setup_tc_cls_flower - flower classifier offloads
* @adapter: board private structure
* @adapter: pointer to iavf adapter structure
* @cls_flower: pointer to flow_cls_offload struct with flow info
*/
static int iavf_setup_tc_cls_flower(struct iavf_adapter *adapter,
......@@ -4031,6 +4031,154 @@ static int iavf_setup_tc_cls_flower(struct iavf_adapter *adapter,
}
}
/**
* iavf_add_cls_u32 - Add U32 classifier offloads
* @adapter: pointer to iavf adapter structure
* @cls_u32: pointer to tc_cls_u32_offload struct with flow info
*
* Return: 0 on success or negative errno on failure.
*/
static int iavf_add_cls_u32(struct iavf_adapter *adapter,
struct tc_cls_u32_offload *cls_u32)
{
struct netlink_ext_ack *extack = cls_u32->common.extack;
struct virtchnl_fdir_rule *rule_cfg;
struct virtchnl_filter_action *vact;
struct virtchnl_proto_hdrs *hdrs;
struct ethhdr *spec_h, *mask_h;
const struct tc_action *act;
struct iavf_fdir_fltr *fltr;
struct tcf_exts *exts;
unsigned int q_index;
int i, status = 0;
int off_base = 0;
if (cls_u32->knode.link_handle) {
NL_SET_ERR_MSG_MOD(extack, "Linking not supported");
return -EOPNOTSUPP;
}
fltr = kzalloc(sizeof(*fltr), GFP_KERNEL);
if (!fltr)
return -ENOMEM;
rule_cfg = &fltr->vc_add_msg.rule_cfg;
hdrs = &rule_cfg->proto_hdrs;
hdrs->count = 0;
/* The parser lib at the PF expects the packet starting with MAC hdr */
switch (ntohs(cls_u32->common.protocol)) {
case ETH_P_802_3:
break;
case ETH_P_IP:
spec_h = (struct ethhdr *)hdrs->raw.spec;
mask_h = (struct ethhdr *)hdrs->raw.mask;
spec_h->h_proto = htons(ETH_P_IP);
mask_h->h_proto = htons(0xFFFF);
off_base += ETH_HLEN;
break;
default:
NL_SET_ERR_MSG_MOD(extack, "Only 802_3 and ip filter protocols are supported");
status = -EOPNOTSUPP;
goto free_alloc;
}
for (i = 0; i < cls_u32->knode.sel->nkeys; i++) {
__be32 val, mask;
int off;
off = off_base + cls_u32->knode.sel->keys[i].off;
val = cls_u32->knode.sel->keys[i].val;
mask = cls_u32->knode.sel->keys[i].mask;
if (off >= sizeof(hdrs->raw.spec)) {
NL_SET_ERR_MSG_MOD(extack, "Input exceeds maximum allowed.");
status = -EINVAL;
goto free_alloc;
}
memcpy(&hdrs->raw.spec[off], &val, sizeof(val));
memcpy(&hdrs->raw.mask[off], &mask, sizeof(mask));
hdrs->raw.pkt_len = off + sizeof(val);
}
/* Only one action is allowed */
rule_cfg->action_set.count = 1;
vact = &rule_cfg->action_set.actions[0];
exts = cls_u32->knode.exts;
tcf_exts_for_each_action(i, act, exts) {
/* FDIR queue */
if (is_tcf_skbedit_rx_queue_mapping(act)) {
q_index = tcf_skbedit_rx_queue_mapping(act);
if (q_index >= adapter->num_active_queues) {
status = -EINVAL;
goto free_alloc;
}
vact->type = VIRTCHNL_ACTION_QUEUE;
vact->act_conf.queue.index = q_index;
break;
}
/* Drop */
if (is_tcf_gact_shot(act)) {
vact->type = VIRTCHNL_ACTION_DROP;
break;
}
/* Unsupported action */
NL_SET_ERR_MSG_MOD(extack, "Unsupported action.");
status = -EOPNOTSUPP;
goto free_alloc;
}
fltr->vc_add_msg.vsi_id = adapter->vsi.id;
fltr->cls_u32_handle = cls_u32->knode.handle;
return iavf_fdir_add_fltr(adapter, fltr);
free_alloc:
kfree(fltr);
return status;
}
/**
* iavf_del_cls_u32 - Delete U32 classifier offloads
* @adapter: pointer to iavf adapter structure
* @cls_u32: pointer to tc_cls_u32_offload struct with flow info
*
* Return: 0 on success or negative errno on failure.
*/
static int iavf_del_cls_u32(struct iavf_adapter *adapter,
struct tc_cls_u32_offload *cls_u32)
{
return iavf_fdir_del_fltr(adapter, true, cls_u32->knode.handle);
}
/**
* iavf_setup_tc_cls_u32 - U32 filter offloads
* @adapter: pointer to iavf adapter structure
* @cls_u32: pointer to tc_cls_u32_offload struct with flow info
*
* Return: 0 on success or negative errno on failure.
*/
static int iavf_setup_tc_cls_u32(struct iavf_adapter *adapter,
struct tc_cls_u32_offload *cls_u32)
{
if (!TC_U32_SUPPORT(adapter) || !FDIR_FLTR_SUPPORT(adapter))
return -EOPNOTSUPP;
switch (cls_u32->command) {
case TC_CLSU32_NEW_KNODE:
case TC_CLSU32_REPLACE_KNODE:
return iavf_add_cls_u32(adapter, cls_u32);
case TC_CLSU32_DELETE_KNODE:
return iavf_del_cls_u32(adapter, cls_u32);
default:
return -EOPNOTSUPP;
}
}
/**
* iavf_setup_tc_block_cb - block callback for tc
* @type: type of offload
......@@ -4050,6 +4198,8 @@ static int iavf_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
switch (type) {
case TC_SETUP_CLSFLOWER:
return iavf_setup_tc_cls_flower(cb_priv, type_data);
case TC_SETUP_CLSU32:
return iavf_setup_tc_cls_u32(cb_priv, type_data);
default:
return -EOPNOTSUPP;
}
......@@ -4332,8 +4482,8 @@ static void iavf_disable_fdir(struct iavf_adapter *adapter)
fdir->state == IAVF_FDIR_FLTR_INACTIVE) {
/* Delete filters not registered in PF */
list_del(&fdir->list);
iavf_dec_fdir_active_fltr(adapter, fdir);
kfree(fdir);
adapter->fdir_active_fltr--;
} else if (fdir->state == IAVF_FDIR_FLTR_ADD_PENDING ||
fdir->state == IAVF_FDIR_FLTR_DIS_REQUEST ||
fdir->state == IAVF_FDIR_FLTR_ACTIVE) {
......@@ -4843,9 +4993,11 @@ int iavf_process_config(struct iavf_adapter *adapter)
/* get HW VLAN features that can be toggled */
hw_vlan_features = iavf_get_netdev_vlan_hw_features(adapter);
/* Enable cloud filter if ADQ is supported */
if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ)
/* Enable HW TC offload if ADQ or tc U32 is supported */
if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_ADQ ||
TC_U32_SUPPORT(adapter))
hw_features |= NETIF_F_HW_TC;
if (vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_USO)
hw_features |= NETIF_F_GSO_UDP_L4;
......
......@@ -142,6 +142,7 @@ int iavf_send_vf_config_msg(struct iavf_adapter *adapter)
VIRTCHNL_VF_OFFLOAD_WB_ON_ITR |
VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2 |
VIRTCHNL_VF_OFFLOAD_ENCAP |
VIRTCHNL_VF_OFFLOAD_TC_U32 |
VIRTCHNL_VF_OFFLOAD_VLAN_V2 |
VIRTCHNL_VF_OFFLOAD_CRC |
VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM |
......@@ -1961,8 +1962,8 @@ static void iavf_activate_fdir_filters(struct iavf_adapter *adapter)
* list on PF is already cleared after a reset
*/
list_del(&f->list);
iavf_dec_fdir_active_fltr(adapter, f);
kfree(f);
adapter->fdir_active_fltr--;
}
}
spin_unlock_bh(&adapter->fdir_fltr_lock);
......@@ -2135,8 +2136,8 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
dev_err(&adapter->pdev->dev,
"%s\n", msg);
list_del(&fdir->list);
iavf_dec_fdir_active_fltr(adapter, fdir);
kfree(fdir);
adapter->fdir_active_fltr--;
}
}
spin_unlock_bh(&adapter->fdir_fltr_lock);
......@@ -2451,8 +2452,12 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
list) {
if (fdir->state == IAVF_FDIR_FLTR_ADD_PENDING) {
if (add_fltr->status == VIRTCHNL_FDIR_SUCCESS) {
dev_info(&adapter->pdev->dev, "Flow Director filter with location %u is added\n",
fdir->loc);
if (!iavf_is_raw_fdir(fdir))
dev_info(&adapter->pdev->dev, "Flow Director filter with location %u is added\n",
fdir->loc);
else
dev_info(&adapter->pdev->dev, "Flow Director filter (raw) for TC handle %x is added\n",
TC_U32_USERHTID(fdir->cls_u32_handle));
fdir->state = IAVF_FDIR_FLTR_ACTIVE;
fdir->flow_id = add_fltr->flow_id;
} else {
......@@ -2460,8 +2465,8 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
add_fltr->status);
iavf_print_fdir_fltr(adapter, fdir);
list_del(&fdir->list);
iavf_dec_fdir_active_fltr(adapter, fdir);
kfree(fdir);
adapter->fdir_active_fltr--;
}
}
}
......@@ -2479,11 +2484,15 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
if (del_fltr->status == VIRTCHNL_FDIR_SUCCESS ||
del_fltr->status ==
VIRTCHNL_FDIR_FAILURE_RULE_NONEXIST) {
dev_info(&adapter->pdev->dev, "Flow Director filter with location %u is deleted\n",
fdir->loc);
if (!iavf_is_raw_fdir(fdir))
dev_info(&adapter->pdev->dev, "Flow Director filter with location %u is deleted\n",
fdir->loc);
else
dev_info(&adapter->pdev->dev, "Flow Director filter (raw) for TC handle %x is deleted\n",
TC_U32_USERHTID(fdir->cls_u32_handle));
list_del(&fdir->list);
iavf_dec_fdir_active_fltr(adapter, fdir);
kfree(fdir);
adapter->fdir_active_fltr--;
} else {
fdir->state = IAVF_FDIR_FLTR_ACTIVE;
dev_info(&adapter->pdev->dev, "Failed to delete Flow Director filter with status: %d\n",
......
......@@ -28,6 +28,8 @@ ice-y := ice_main.o \
ice_vlan_mode.o \
ice_flex_pipe.o \
ice_flow.o \
ice_parser.o \
ice_parser_rt.o \
ice_idc.o \
devlink/devlink.o \
devlink/devlink_port.o \
......
......@@ -10,6 +10,7 @@
#include "ice_type.h"
#include "ice_nvm.h"
#include "ice_flex_pipe.h"
#include "ice_parser.h"
#include <linux/avf/virtchnl.h>
#include "ice_switch.h"
#include "ice_fdir.h"
......
......@@ -289,11 +289,11 @@ void *ice_pkg_enum_section(struct ice_seg *ice_seg, struct ice_pkg_enum *state,
* indicates a base offset of 10, and the index for the entry is 2, then
* section handler function should set the offset to 10 + 2 = 12.
*/
static void *ice_pkg_enum_entry(struct ice_seg *ice_seg,
struct ice_pkg_enum *state, u32 sect_type,
u32 *offset,
void *(*handler)(u32 sect_type, void *section,
u32 index, u32 *offset))
void *ice_pkg_enum_entry(struct ice_seg *ice_seg,
struct ice_pkg_enum *state, u32 sect_type,
u32 *offset,
void *(*handler)(u32 sect_type, void *section,
u32 index, u32 *offset))
{
void *entry;
......
......@@ -261,10 +261,17 @@ struct ice_meta_sect {
#define ICE_SID_CDID_KEY_BUILDER_RSS 47
#define ICE_SID_CDID_REDIR_RSS 48
#define ICE_SID_RXPARSER_CAM 50
#define ICE_SID_RXPARSER_NOMATCH_CAM 51
#define ICE_SID_RXPARSER_IMEM 52
#define ICE_SID_RXPARSER_MARKER_PTYPE 55
#define ICE_SID_RXPARSER_BOOST_TCAM 56
#define ICE_SID_RXPARSER_PROTO_GRP 57
#define ICE_SID_RXPARSER_METADATA_INIT 58
#define ICE_SID_TXPARSER_BOOST_TCAM 66
#define ICE_SID_RXPARSER_MARKER_GRP 72
#define ICE_SID_RXPARSER_PG_SPILL 76
#define ICE_SID_RXPARSER_NOMATCH_SPILL 78
#define ICE_SID_XLT0_PE 80
#define ICE_SID_XLT_KEY_BUILDER_PE 81
......@@ -276,6 +283,7 @@ struct ice_meta_sect {
#define ICE_SID_CDID_KEY_BUILDER_PE 87
#define ICE_SID_CDID_REDIR_PE 88
#define ICE_SID_RXPARSER_FLAG_REDIR 97
/* Label Metadata section IDs */
#define ICE_SID_LBL_FIRST 0x80000010
#define ICE_SID_LBL_RXPARSER_TMEM 0x80000018
......@@ -451,6 +459,11 @@ int ice_update_pkg(struct ice_hw *hw, struct ice_buf *bufs, u32 count);
int ice_pkg_buf_reserve_section(struct ice_buf_build *bld, u16 count);
u16 ice_pkg_buf_get_active_sections(struct ice_buf_build *bld);
void *
ice_pkg_enum_entry(struct ice_seg *ice_seg, struct ice_pkg_enum *state,
u32 sect_type, u32 *offset,
void *(*handler)(u32 sect_type, void *section,
u32 index, u32 *offset));
void *ice_pkg_enum_section(struct ice_seg *ice_seg, struct ice_pkg_enum *state,
u32 sect_type);
......
......@@ -2981,6 +2981,50 @@ ice_add_prof_attrib(struct ice_prof_map *prof, u8 ptg, u16 ptype,
}
/**
* ice_disable_fd_swap - set register appropriately to disable FD SWAP
* @hw: pointer to the HW struct
* @prof_id: profile ID
*/
static void
ice_disable_fd_swap(struct ice_hw *hw, u8 prof_id)
{
u16 swap_val, fvw_num;
unsigned int i;
swap_val = ICE_SWAP_VALID;
fvw_num = hw->blk[ICE_BLK_FD].es.fvw / ICE_FDIR_REG_SET_SIZE;
/* Since the SWAP Flag in the Programming Desc doesn't work,
* here add method to disable the SWAP Option via setting
* certain SWAP and INSET register sets.
*/
for (i = 0; i < fvw_num ; i++) {
u32 raw_swap, raw_in;
unsigned int j;
raw_swap = 0;
raw_in = 0;
for (j = 0; j < ICE_FDIR_REG_SET_SIZE; j++) {
raw_swap |= (swap_val++) << (j * BITS_PER_BYTE);
raw_in |= ICE_INSET_DFLT << (j * BITS_PER_BYTE);
}
/* write the FDIR swap register set */
wr32(hw, GLQF_FDSWAP(prof_id, i), raw_swap);
ice_debug(hw, ICE_DBG_INIT, "swap wr(%d, %d): 0x%x = 0x%08x\n",
prof_id, i, GLQF_FDSWAP(prof_id, i), raw_swap);
/* write the FDIR inset register set */
wr32(hw, GLQF_FDINSET(prof_id, i), raw_in);
ice_debug(hw, ICE_DBG_INIT, "inset wr(%d, %d): 0x%x = 0x%08x\n",
prof_id, i, GLQF_FDINSET(prof_id, i), raw_in);
}
}
/*
* ice_add_prof - add profile
* @hw: pointer to the HW struct
* @blk: hardware block
......@@ -2991,6 +3035,7 @@ ice_add_prof_attrib(struct ice_prof_map *prof, u8 ptg, u16 ptype,
* @es: extraction sequence (length of array is determined by the block)
* @masks: mask for extraction sequence
* @symm: symmetric setting for RSS profiles
* @fd_swap: enable/disable FDIR paired src/dst fields swap option
*
* This function registers a profile, which matches a set of PTYPES with a
* particular extraction sequence. While the hardware profile is allocated
......@@ -3000,7 +3045,7 @@ ice_add_prof_attrib(struct ice_prof_map *prof, u8 ptg, u16 ptype,
int
ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],
const struct ice_ptype_attributes *attr, u16 attr_cnt,
struct ice_fv_word *es, u16 *masks, bool symm)
struct ice_fv_word *es, u16 *masks, bool symm, bool fd_swap)
{
u32 bytes = DIV_ROUND_UP(ICE_FLOW_PTYPE_MAX, BITS_PER_BYTE);
DECLARE_BITMAP(ptgs_used, ICE_XLT1_CNT);
......@@ -3020,7 +3065,7 @@ ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],
status = ice_alloc_prof_id(hw, blk, &prof_id);
if (status)
goto err_ice_add_prof;
if (blk == ICE_BLK_FD) {
if (blk == ICE_BLK_FD && fd_swap) {
/* For Flow Director block, the extraction sequence may
* need to be altered in the case where there are paired
* fields that have no match. This is necessary because
......@@ -3031,6 +3076,8 @@ ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],
status = ice_update_fd_swap(hw, prof_id, es);
if (status)
goto err_ice_add_prof;
} else if (blk == ICE_BLK_FD) {
ice_disable_fd_swap(hw, prof_id);
}
status = ice_update_prof_masking(hw, blk, prof_id, masks);
if (status)
......@@ -4098,6 +4145,54 @@ ice_add_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl)
return status;
}
/**
* ice_flow_assoc_fdir_prof - add an FDIR profile for main/ctrl VSI
* @hw: pointer to the HW struct
* @blk: HW block
* @dest_vsi: dest VSI
* @fdir_vsi: fdir programming VSI
* @hdl: profile handle
*
* Update the hardware tables to enable the FDIR profile indicated by @hdl for
* the VSI specified by @dest_vsi. On success, the flow will be enabled.
*
* Return: 0 on success or negative errno on failure.
*/
int
ice_flow_assoc_fdir_prof(struct ice_hw *hw, enum ice_block blk,
u16 dest_vsi, u16 fdir_vsi, u64 hdl)
{
u16 vsi_num;
int status;
if (blk != ICE_BLK_FD)
return -EINVAL;
vsi_num = ice_get_hw_vsi_num(hw, dest_vsi);
status = ice_add_prof_id_flow(hw, blk, vsi_num, hdl);
if (status) {
ice_debug(hw, ICE_DBG_FLOW, "Adding HW profile failed for main VSI flow entry: %d\n",
status);
return status;
}
vsi_num = ice_get_hw_vsi_num(hw, fdir_vsi);
status = ice_add_prof_id_flow(hw, blk, vsi_num, hdl);
if (status) {
ice_debug(hw, ICE_DBG_FLOW, "Adding HW profile failed for ctrl VSI flow entry: %d\n",
status);
goto err;
}
return 0;
err:
vsi_num = ice_get_hw_vsi_num(hw, dest_vsi);
ice_rem_prof_id_flow(hw, blk, vsi_num, hdl);
return status;
}
/**
* ice_rem_prof_from_list - remove a profile from list
* @hw: pointer to the HW struct
......
......@@ -6,6 +6,8 @@
#include "ice_type.h"
#define ICE_FDIR_REG_SET_SIZE 4
int
ice_acquire_change_lock(struct ice_hw *hw, enum ice_aq_res_access_type access);
void ice_release_change_lock(struct ice_hw *hw);
......@@ -42,13 +44,16 @@ bool ice_hw_ptype_ena(struct ice_hw *hw, u16 ptype);
int
ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],
const struct ice_ptype_attributes *attr, u16 attr_cnt,
struct ice_fv_word *es, u16 *masks, bool symm);
struct ice_fv_word *es, u16 *masks, bool symm, bool fd_swap);
struct ice_prof_map *
ice_search_prof_id(struct ice_hw *hw, enum ice_block blk, u64 id);
int
ice_add_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl);
int
ice_rem_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl);
int
ice_flow_assoc_fdir_prof(struct ice_hw *hw, enum ice_block blk,
u16 dest_vsi, u16 fdir_vsi, u64 hdl);
enum ice_ddp_state ice_init_pkg(struct ice_hw *hw, u8 *buff, u32 len);
enum ice_ddp_state
ice_copy_and_init_pkg(struct ice_hw *hw, const u8 *buf, u32 len);
......
......@@ -409,6 +409,29 @@ static const u32 ice_ptypes_gtpc_tid[] = {
};
/* Packet types for GTPU */
static const struct ice_ptype_attributes ice_attr_gtpu_session[] = {
{ ICE_MAC_IPV4_GTPU_IPV4_FRAG, ICE_PTYPE_ATTR_GTP_SESSION },
{ ICE_MAC_IPV4_GTPU_IPV4_PAY, ICE_PTYPE_ATTR_GTP_SESSION },
{ ICE_MAC_IPV4_GTPU_IPV4_UDP_PAY, ICE_PTYPE_ATTR_GTP_SESSION },
{ ICE_MAC_IPV4_GTPU_IPV4_TCP, ICE_PTYPE_ATTR_GTP_SESSION },
{ ICE_MAC_IPV4_GTPU_IPV4_ICMP, ICE_PTYPE_ATTR_GTP_SESSION },
{ ICE_MAC_IPV6_GTPU_IPV4_FRAG, ICE_PTYPE_ATTR_GTP_SESSION },
{ ICE_MAC_IPV6_GTPU_IPV4_PAY, ICE_PTYPE_ATTR_GTP_SESSION },
{ ICE_MAC_IPV6_GTPU_IPV4_UDP_PAY, ICE_PTYPE_ATTR_GTP_SESSION },
{ ICE_MAC_IPV6_GTPU_IPV4_TCP, ICE_PTYPE_ATTR_GTP_SESSION },
{ ICE_MAC_IPV6_GTPU_IPV4_ICMP, ICE_PTYPE_ATTR_GTP_SESSION },
{ ICE_MAC_IPV4_GTPU_IPV6_FRAG, ICE_PTYPE_ATTR_GTP_SESSION },
{ ICE_MAC_IPV4_GTPU_IPV6_PAY, ICE_PTYPE_ATTR_GTP_SESSION },
{ ICE_MAC_IPV4_GTPU_IPV6_UDP_PAY, ICE_PTYPE_ATTR_GTP_SESSION },
{ ICE_MAC_IPV4_GTPU_IPV6_TCP, ICE_PTYPE_ATTR_GTP_SESSION },
{ ICE_MAC_IPV4_GTPU_IPV6_ICMPV6, ICE_PTYPE_ATTR_GTP_SESSION },
{ ICE_MAC_IPV6_GTPU_IPV6_FRAG, ICE_PTYPE_ATTR_GTP_SESSION },
{ ICE_MAC_IPV6_GTPU_IPV6_PAY, ICE_PTYPE_ATTR_GTP_SESSION },
{ ICE_MAC_IPV6_GTPU_IPV6_UDP_PAY, ICE_PTYPE_ATTR_GTP_SESSION },
{ ICE_MAC_IPV6_GTPU_IPV6_TCP, ICE_PTYPE_ATTR_GTP_SESSION },
{ ICE_MAC_IPV6_GTPU_IPV6_ICMPV6, ICE_PTYPE_ATTR_GTP_SESSION },
};
static const struct ice_ptype_attributes ice_attr_gtpu_eh[] = {
{ ICE_MAC_IPV4_GTPU_IPV4_FRAG, ICE_PTYPE_ATTR_GTP_PDU_EH },
{ ICE_MAC_IPV4_GTPU_IPV4_PAY, ICE_PTYPE_ATTR_GTP_PDU_EH },
......@@ -1400,7 +1423,7 @@ ice_flow_add_prof_sync(struct ice_hw *hw, enum ice_block blk,
/* Add a HW profile for this flow profile */
status = ice_add_prof(hw, blk, prof_id, (u8 *)params->ptypes,
params->attr, params->attr_cnt, params->es,
params->mask, symm);
params->mask, symm, true);
if (status) {
ice_debug(hw, ICE_DBG_FLOW, "Error adding a HW flow profile\n");
goto out;
......@@ -1523,6 +1546,90 @@ ice_flow_disassoc_prof(struct ice_hw *hw, enum ice_block blk,
return status;
}
#define FLAG_GTP_EH_PDU_LINK BIT_ULL(13)
#define FLAG_GTP_EH_PDU BIT_ULL(14)
#define HI_BYTE_IN_WORD GENMASK(15, 8)
#define LO_BYTE_IN_WORD GENMASK(7, 0)
#define FLAG_GTPU_MSK \
(FLAG_GTP_EH_PDU | FLAG_GTP_EH_PDU_LINK)
#define FLAG_GTPU_UP \
(FLAG_GTP_EH_PDU | FLAG_GTP_EH_PDU_LINK)
#define FLAG_GTPU_DW FLAG_GTP_EH_PDU
/**
* ice_flow_set_parser_prof - Set flow profile based on the parsed profile info
* @hw: pointer to the HW struct
* @dest_vsi: dest VSI
* @fdir_vsi: fdir programming VSI
* @prof: stores parsed profile info from raw flow
* @blk: classification blk
*
* Return: 0 on success or negative errno on failure.
*/
int
ice_flow_set_parser_prof(struct ice_hw *hw, u16 dest_vsi, u16 fdir_vsi,
struct ice_parser_profile *prof, enum ice_block blk)
{
u64 id = find_first_bit(prof->ptypes, ICE_FLOW_PTYPE_MAX);
struct ice_flow_prof_params *params __free(kfree);
u8 fv_words = hw->blk[blk].es.fvw;
int status;
int i, idx;
params = kzalloc(sizeof(*params), GFP_KERNEL);
if (!params)
return -ENOMEM;
for (i = 0; i < ICE_MAX_FV_WORDS; i++) {
params->es[i].prot_id = ICE_PROT_INVALID;
params->es[i].off = ICE_FV_OFFSET_INVAL;
}
for (i = 0; i < prof->fv_num; i++) {
if (hw->blk[blk].es.reverse)
idx = fv_words - i - 1;
else
idx = i;
params->es[idx].prot_id = prof->fv[i].proto_id;
params->es[idx].off = prof->fv[i].offset;
params->mask[idx] = (((prof->fv[i].msk) << BITS_PER_BYTE) &
HI_BYTE_IN_WORD) |
(((prof->fv[i].msk) >> BITS_PER_BYTE) &
LO_BYTE_IN_WORD);
}
switch (prof->flags) {
case FLAG_GTPU_DW:
params->attr = ice_attr_gtpu_down;
params->attr_cnt = ARRAY_SIZE(ice_attr_gtpu_down);
break;
case FLAG_GTPU_UP:
params->attr = ice_attr_gtpu_up;
params->attr_cnt = ARRAY_SIZE(ice_attr_gtpu_up);
break;
default:
if (prof->flags_msk & FLAG_GTPU_MSK) {
params->attr = ice_attr_gtpu_session;
params->attr_cnt = ARRAY_SIZE(ice_attr_gtpu_session);
}
break;
}
status = ice_add_prof(hw, blk, id, (u8 *)prof->ptypes,
params->attr, params->attr_cnt,
params->es, params->mask, false, false);
if (status)
return status;
status = ice_flow_assoc_fdir_prof(hw, blk, dest_vsi, fdir_vsi, id);
if (status)
ice_rem_prof(hw, blk, id);
return status;
}
/**
* ice_flow_add_prof - Add a flow profile for packet segments and matched fields
* @hw: pointer to the HW struct
......
......@@ -5,6 +5,7 @@
#define _ICE_FLOW_H_
#include "ice_flex_type.h"
#include "ice_parser.h"
#define ICE_FLOW_ENTRY_HANDLE_INVAL 0
#define ICE_FLOW_FLD_OFF_INVAL 0xffff
......@@ -326,6 +327,7 @@ enum ice_rss_cfg_hdr_type {
ICE_RSS_ANY_HEADERS
};
struct ice_vsi;
struct ice_rss_hash_cfg {
u32 addl_hdrs; /* protocol header fields */
u64 hash_flds; /* hash bit field (ICE_FLOW_HASH_*) to configure */
......@@ -445,6 +447,9 @@ ice_flow_add_prof(struct ice_hw *hw, enum ice_block blk, enum ice_flow_dir dir,
bool symm, struct ice_flow_prof **prof);
int ice_flow_rem_prof(struct ice_hw *hw, enum ice_block blk, u64 prof_id);
int
ice_flow_set_parser_prof(struct ice_hw *hw, u16 dest_vsi, u16 fdir_vsi,
struct ice_parser_profile *prof, enum ice_block blk);
int
ice_flow_add_entry(struct ice_hw *hw, enum ice_block blk, u64 prof_id,
u64 entry_id, u16 vsi, enum ice_flow_priority prio,
void *data, u64 *entry_h);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -61,6 +61,7 @@ static inline u32 ice_round_to_num(u32 N, u32 R)
ICE_DBG_AQ_DESC | \
ICE_DBG_AQ_DESC_BUF | \
ICE_DBG_AQ_CMD)
#define ICE_DBG_PARSER BIT_ULL(28)
#define ICE_DBG_USER BIT_ULL(31)
......
......@@ -12,6 +12,7 @@
#include <net/devlink.h>
#include <linux/avf/virtchnl.h>
#include "ice_type.h"
#include "ice_flow.h"
#include "ice_virtchnl_fdir.h"
#include "ice_vsi_vlan_ops.h"
......@@ -52,6 +53,12 @@ struct ice_mdd_vf_events {
u16 last_printed;
};
/* Structure to store fdir fv entry */
struct ice_fdir_prof_info {
struct ice_parser_profile prof;
u64 fdir_active_cnt;
};
/* VF operations */
struct ice_vf_ops {
enum ice_disq_rst_src reset_type;
......@@ -91,6 +98,7 @@ struct ice_vf {
u16 lan_vsi_idx; /* index into PF struct */
u16 ctrl_vsi_idx;
struct ice_vf_fdir fdir;
struct ice_fdir_prof_info fdir_prof_info[ICE_MAX_PTGS];
/* first vector index of this VF in the PF space */
int first_vector_idx;
struct ice_sw *vf_sw_id; /* switch ID the VF VSIs connect to */
......
......@@ -461,6 +461,10 @@ static int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg)
if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_FDIR_PF)
vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_FDIR_PF;
if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_TC_U32 &&
vfres->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_FDIR_PF)
vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_TC_U32;
if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2)
vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2;
......
......@@ -247,6 +247,7 @@ VIRTCHNL_CHECK_STRUCT_LEN(16, virtchnl_vsi_resource);
/* used to negotiate communicating link speeds in Mbps */
#define VIRTCHNL_VF_CAP_ADV_LINK_SPEED BIT(7)
#define VIRTCHNL_VF_OFFLOAD_CRC BIT(10)
#define VIRTCHNL_VF_OFFLOAD_TC_U32 BIT(11)
#define VIRTCHNL_VF_OFFLOAD_VLAN_V2 BIT(15)
#define VIRTCHNL_VF_OFFLOAD_VLAN BIT(16)
#define VIRTCHNL_VF_OFFLOAD_RX_POLLING BIT(17)
......@@ -1121,6 +1122,7 @@ enum virtchnl_vfr_states {
};
#define VIRTCHNL_MAX_NUM_PROTO_HDRS 32
#define VIRTCHNL_MAX_SIZE_RAW_PACKET 1024
#define PROTO_HDR_SHIFT 5
#define PROTO_HDR_FIELD_START(proto_hdr_type) ((proto_hdr_type) << PROTO_HDR_SHIFT)
#define PROTO_HDR_FIELD_MASK ((1UL << PROTO_HDR_SHIFT) - 1)
......@@ -1266,13 +1268,22 @@ struct virtchnl_proto_hdrs {
u8 pad[3];
/**
* specify where protocol header start from.
* must be 0 when sending a raw 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];
union {
struct virtchnl_proto_hdr
proto_hdr[VIRTCHNL_MAX_NUM_PROTO_HDRS];
struct {
u16 pkt_len;
u8 spec[VIRTCHNL_MAX_SIZE_RAW_PACKET];
u8 mask[VIRTCHNL_MAX_SIZE_RAW_PACKET];
} raw;
};
};
VIRTCHNL_CHECK_STRUCT_LEN(2312, virtchnl_proto_hdrs);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment