Skip to content

Commit

Permalink
iavf: add support for offloading tc U32 cls filters
Browse files Browse the repository at this point in the history
Add support for offloading cls U32 filters. Only "skbedit queue_mapping"
and "drop" actions are supported. Also, only "ip" and "802_3" tc
protocols are allowed. The PF must advertise the VIRTCHNL_VF_OFFLOAD_TC_U32
capability flag.

Since the filters will be enabled via the FD stage at the PF, a new type
of FDIR filters is added and the existing list and state machine are used.

The new filters can be used to configure flow directors based on raw
(binary) pattern in the rx packet.

Examples:

0. # tc qdisc add dev enp175s0v0  ingress

1. Redirect UDP from src IP 192.168.2.1 to queue 12:

    # tc filter add dev <dev> protocol ip ingress u32 \
	match u32 0x45000000 0xff000000 at 0  \
	match u32 0x00110000 0x00ff0000 at 8  \
	match u32 0xC0A80201 0xffffffff at 12 \
	match u32 0x00000000 0x00000000 at 24 \
	action skbedit queue_mapping 12 skip_sw

2. Drop all ICMP:

    # tc filter add dev <dev> protocol ip ingress u32 \
	match u32 0x45000000 0xff000000 at 0  \
	match u32 0x00010000 0x00ff0000 at 8  \
	match u32 0x00000000 0x00000000 at 24 \
	action drop skip_sw

3. Redirect ICMP traffic from MAC 3c:fd:fe:a5:47:e0 to queue 7
   (note proto: 802_3):

   # tc filter add dev <dev> protocol 802_3 ingress u32 \
	match u32 0x00003CFD 0x0000ffff at 4   \
	match u32 0xFEA547E0 0xffffffff at 8   \
	match u32 0x08004500 0xffffff00 at 12  \
	match u32 0x00000001 0x000000ff at 20  \
	match u32 0x0000 0x0000 at 40          \
	action skbedit queue_mapping 7 skip_sw

Notes on matches:
1 - All intermediate fields that are needed to parse the correct PTYPE
    must be provided (in e.g. 3: Ethernet Type 0x0800 in MAC, IP version
    and IP length: 0x45 and protocol: 0x01 (ICMP)).
2 - The last match must provide an offset that guarantees all required
    headers are accounted for, even if the last header is not matched.
    For example, in #2, the last match is 4 bytes at offset 24 starting
    from IP header, so the total is 14 (MAC) + 24 + 4 = 42, which is the
    sum of MAC+IP+ICMP headers.

Reviewed-by: Sridhar Samudrala <[email protected]>
Reviewed-by: Marcin Szycik <[email protected]>
Signed-off-by: Ahmed Zaki <[email protected]>
Tested-by: Rafal Romanowski <[email protected]>
Reviewed-by: Simon Horman <[email protected]>
Signed-off-by: Tony Nguyen <[email protected]>
  • Loading branch information
azaki1 authored and anguy11 committed Aug 13, 2024
1 parent 995617d commit 623122a
Show file tree
Hide file tree
Showing 8 changed files with 238 additions and 27 deletions.
27 changes: 26 additions & 1 deletion drivers/net/ethernet/intel/iavf/iavf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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 || \
Expand Down Expand Up @@ -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 */

Expand All @@ -447,7 +451,28 @@ struct iavf_adapter {
/* 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 >= IAVF_MAX_FDIR_FILTERS;
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 */
Expand Down
9 changes: 6 additions & 3 deletions drivers/net/ethernet/intel/iavf/iavf_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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(adapter, fsp->location);
rule = iavf_find_fdir_fltr(adapter, false, fsp->location);
if (!rule) {
ret = -EINVAL;
goto release_lock;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1263,7 +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 (iavf_find_fdir_fltr(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;
Expand Down Expand Up @@ -1307,7 +1310,7 @@ static int iavf_del_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
if (!(adapter->flags & IAVF_FLAG_FDIR_ENABLED))
return -EOPNOTSUPP;

return iavf_fdir_del_fltr(adapter, fsp->location);
return iavf_fdir_del_fltr(adapter, false, fsp->location);
}

/**
Expand Down
29 changes: 20 additions & 9 deletions drivers/net/ethernet/intel/iavf/iavf_fdir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -817,18 +820,21 @@ bool iavf_fdir_is_dup_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *
/**
* 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. Lock must be held.
*/
struct iavf_fdir_fltr *iavf_find_fdir_fltr(struct iavf_adapter *adapter,
u32 loc)
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;
}
Expand All @@ -855,6 +861,9 @@ int iavf_fdir_add_fltr(struct iavf_adapter *adapter,
}

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;
Expand All @@ -864,7 +873,8 @@ int iavf_fdir_add_fltr(struct iavf_adapter *adapter,
list_add(&fltr->list, &parent->list);
else
list_add(&fltr->list, &adapter->fdir_list_head);
adapter->fdir_active_fltr++;

iavf_inc_fdir_active_fltr(adapter, fltr);

if (adapter->link_up)
fltr->state = IAVF_FDIR_FLTR_ADD_REQUEST;
Expand All @@ -881,25 +891,26 @@ int iavf_fdir_add_fltr(struct iavf_adapter *adapter,
/**
* iavf_fdir_del_fltr - delete a flow director filter from the list
* @adapter: pointer to the VF adapter structure
* @loc: location to delete.
* @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, u32 loc)
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, loc);
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);
adapter->fdir_active_fltr--;
fltr = NULL;
} else {
err = -EBUSY;
Expand Down
10 changes: 8 additions & 2 deletions drivers/net/ethernet/intel/iavf/iavf_fdir.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,20 +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);
int iavf_fdir_add_fltr(struct iavf_adapter *adapter,
struct iavf_fdir_fltr *fltr);
int iavf_fdir_del_fltr(struct iavf_adapter *adapter, u32 loc);
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,
u32 loc);
bool is_raw, u32 data);
#endif /* _IAVF_FDIR_H_ */
Loading

0 comments on commit 623122a

Please sign in to comment.