Skip to content

Commit

Permalink
Merge branch 'tc-action-offload'
Browse files Browse the repository at this point in the history
Simon Horman says:

====================
allow user to offload tc action to net device

Baowen Zheng says:

Allow use of flow_indr_dev_register/flow_indr_dev_setup_offload to offload
tc actions independent of flows.

The motivation for this work is to prepare for using TC police action
instances to provide hardware offload of OVS metering feature - which calls
for policers that may be used by multiple flows and whose lifecycle is
independent of any flows that use them.

This patch includes basic changes to offload drivers to return EOPNOTSUPP
if this feature is used - it is not yet supported by any driver.

Tc cli command to offload and quote an action:

 # tc qdisc del dev $DEV ingress && sleep 1 || true
 # tc actions delete action police index 200 || true

 # tc qdisc add dev $DEV ingress
 # tc qdisc show dev $DEV ingress

 # tc actions add action police rate 100mbit burst 10000k index 200 skip_sw
 # tc -s -d actions list action police
 total acts 1

         action order 0:  police 0xc8 rate 100Mbit burst 10000Kb mtu 2Kb action reclassify
         overhead 0b linklayer ethernet
         ref 1 bind 0  installed 142 sec used 0 sec
         Action statistics:
         Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
         backlog 0b 0p requeues 0
         skip_sw in_hw in_hw_count 1
         used_hw_stats delayed

 # tc filter add dev $DEV protocol ip parent ffff: \
         flower skip_sw ip_proto tcp action police index 200
 # tc -s -d filter show dev $DEV protocol ip parent ffff:
 filter pref 49152 flower chain 0
 filter pref 49152 flower chain 0 handle 0x1
   eth_type ipv4
   ip_proto tcp
   skip_sw
   in_hw in_hw_count 1
         action order 1:  police 0xc8 rate 100Mbit burst 10000Kb mtu 2Kb action
         reclassify overhead 0b linklayer ethernet
         ref 2 bind 1  installed 300 sec used 0 sec
         Action statistics:
         Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
         backlog 0b 0p requeues 0
         skip_sw in_hw in_hw_count 1
         used_hw_stats delayed

 # tc filter add dev $DEV protocol ipv6 parent ffff: \
         flower skip_sw ip_proto tcp action police index 200
 # tc -s -d filter show dev $DEV protocol ipv6 parent ffff:
   filter pref 49151 flower chain 0
   filter pref 49151 flower chain 0 handle 0x1
   eth_type ipv6
   ip_proto tcp
   skip_sw
   in_hw in_hw_count 1
         action order 1:  police 0xc8 rate 100Mbit burst 10000Kb mtu 2Kb action
         reclassify overhead 0b linklayer ethernet
         ref 3 bind 2  installed 761 sec used 0 sec
         Action statistics:
         Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
         backlog 0b 0p requeues 0
         skip_sw in_hw in_hw_count 1
         used_hw_stats delayed

 # tc -s -d actions list action police
 total acts 1

          action order 0:  police 0xc8 rate 100Mbit burst 10000Kb mtu 2Kb action reclassify overhead 0b linklayer ethernet
          ref 3 bind 2  installed 917 sec used 0 sec
          Action statistics:
          Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
          backlog 0b 0p requeues 0
          skip_sw in_hw in_hw_count 1
         used_hw_stats delayed

Changes between v7 and v8:
* Rename enum offload_act_command as enum flow_offload_act_command
* Add a single patch to rename exts stats update function for readability.
* Fix the kernel test robot issue reported by Oliver Sang.

Changes between v6 and v7:
* Add a single patch to rename offload functions with offload for readability.
* Post 166b6a4 ("flow_offload: return EOPNOTSUPP for the unsupported mpls action type") as a bug fix to netdev.
* Rename enum flow_act_command as enum flow_offload_act_command
* Rename the new added action offload setup ops with offload instead of flow
* Rename the new added action offload function with offload instead of flow.
* Add more selftest cases for validate filter and actions.

Changes between v5 and v6:
* Fix issue reported by Dan Carpenter found using Smatch.

Changes beteeen v4 and v5:
* Made changes of code style according to the public review comments.
* Add a fix for unsupported mpls action type in flow action setup stage.
* Add ops to tc_action_ops for flow action setup to facilitate
  adding a standalone action module.
* Add notification process when deleting action in reoffload process.

Changes between v3 and v4:
* Made changes according to the public review comments.
* Validate flags inside tcf_action_init() instead of creating new
  tcf_exts_validate_actions() function.
* Exactly match when validating flags of actions and filters.
* Add index to flow_action_entry for driver to identify actions.

Changes between v2 and v3:
* Made changes according to the review comments.
* Delete in_hw and not_in_hw flag and user can judge if the action is
  offloaded to any hardware by in_hw_count.
* Split the main patch of the action offload to three single patch to
  facilitate code review.

Changes between v1 and v2:
* Add the skip_hw/skip_sw for user to specify if the action should be in
  hardware or software.
* Fix issue of sleeping function called from invalid context.
* Change the action offload/delete from batch to one by one.
* Add some parameters to the netlink message for user space to look up
  the offload status of the actions.
* Add reoffload process to update action hw_count when driver is inserted
  or removed.

Changes between v1 and RFC:
* Fix robot test failure.
* Change actions offload process in action add function rather than action
  init.
* Change actions offload delete process after tcf_del_notify to keep
  undeleted actions.
* Add process to update actions stats from hardware.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Dec 19, 2021
2 parents f85b244 + eb473ba commit 434ed21
Show file tree
Hide file tree
Showing 42 changed files with 1,222 additions and 320 deletions.
4 changes: 2 additions & 2 deletions drivers/net/dsa/ocelot/felix_vsc9959.c
Original file line number Diff line number Diff line change
Expand Up @@ -1745,7 +1745,7 @@ static void vsc9959_psfp_sfi_table_del(struct ocelot *ocelot, u32 index)
static void vsc9959_psfp_parse_gate(const struct flow_action_entry *entry,
struct felix_stream_gate *sgi)
{
sgi->index = entry->gate.index;
sgi->index = entry->hw_index;
sgi->ipv_valid = (entry->gate.prio < 0) ? 0 : 1;
sgi->init_ipv = (sgi->ipv_valid) ? entry->gate.prio : 0;
sgi->basetime = entry->gate.basetime;
Expand Down Expand Up @@ -1947,7 +1947,7 @@ static int vsc9959_psfp_filter_add(struct ocelot *ocelot, int port,
kfree(sgi);
break;
case FLOW_ACTION_POLICE:
index = a->police.index + VSC9959_PSFP_POLICER_BASE;
index = a->hw_index + VSC9959_PSFP_POLICER_BASE;
if (index > VSC9959_PSFP_POLICER_MAX) {
ret = -EINVAL;
goto err;
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/dsa/sja1105/sja1105_flower.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ int sja1105_cls_flower_add(struct dsa_switch *ds, int port,
vl_rule = true;

rc = sja1105_vl_gate(priv, port, extack, cookie,
&key, act->gate.index,
&key, act->hw_index,
act->gate.prio,
act->gate.basetime,
act->gate.cycletime,
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1962,7 +1962,7 @@ static int bnxt_tc_setup_indr_cb(struct net_device *netdev, struct Qdisc *sch, v
void *data,
void (*cleanup)(struct flow_block_cb *block_cb))
{
if (!bnxt_is_netdev_indr_offload(netdev))
if (!netdev || !bnxt_is_netdev_indr_offload(netdev))
return -EOPNOTSUPP;

switch (type) {
Expand Down
6 changes: 3 additions & 3 deletions drivers/net/ethernet/freescale/enetc/enetc_qos.c
Original file line number Diff line number Diff line change
Expand Up @@ -1182,7 +1182,7 @@ static int enetc_psfp_parse_clsflower(struct enetc_ndev_priv *priv,
}

/* parsing gate action */
if (entryg->gate.index >= priv->psfp_cap.max_psfp_gate) {
if (entryg->hw_index >= priv->psfp_cap.max_psfp_gate) {
NL_SET_ERR_MSG_MOD(extack, "No Stream Gate resource!");
err = -ENOSPC;
goto free_filter;
Expand All @@ -1202,7 +1202,7 @@ static int enetc_psfp_parse_clsflower(struct enetc_ndev_priv *priv,
}

refcount_set(&sgi->refcount, 1);
sgi->index = entryg->gate.index;
sgi->index = entryg->hw_index;
sgi->init_ipv = entryg->gate.prio;
sgi->basetime = entryg->gate.basetime;
sgi->cycletime = entryg->gate.cycletime;
Expand Down Expand Up @@ -1244,7 +1244,7 @@ static int enetc_psfp_parse_clsflower(struct enetc_ndev_priv *priv,
refcount_set(&fmi->refcount, 1);
fmi->cir = entryp->police.rate_bytes_ps;
fmi->cbs = entryp->police.burst;
fmi->index = entryp->police.index;
fmi->index = entryp->hw_index;
filter->flags |= ENETC_PSFP_FLAGS_FMI;
filter->fmi_index = fmi->index;
sfi->meter_id = fmi->index;
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,9 @@ int mlx5e_rep_indr_setup_cb(struct net_device *netdev, struct Qdisc *sch, void *
void *data,
void (*cleanup)(struct flow_block_cb *block_cb))
{
if (!netdev)
return -EOPNOTSUPP;

switch (type) {
case TC_SETUP_BLOCK:
return mlx5e_rep_indr_setup_block(netdev, sch, cb_priv, type_data,
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp,
*/
burst = roundup_pow_of_two(act->police.burst);
err = mlxsw_sp_acl_rulei_act_police(mlxsw_sp, rulei,
act->police.index,
act->hw_index,
act->police.rate_bytes_ps,
burst, extack);
if (err)
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/ethernet/mscc/ocelot_flower.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
}
filter->action.police_ena = true;

pol_ix = a->police.index + ocelot->vcap_pol.base;
pol_ix = a->hw_index + ocelot->vcap_pol.base;
pol_max = ocelot->vcap_pol.max;

if (ocelot->vcap_pol.max2 && pol_ix > pol_max) {
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/ethernet/netronome/nfp/flower/offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -1867,6 +1867,9 @@ nfp_flower_indr_setup_tc_cb(struct net_device *netdev, struct Qdisc *sch, void *
void *data,
void (*cleanup)(struct flow_block_cb *block_cb))
{
if (!netdev)
return -EOPNOTSUPP;

if (!nfp_fl_is_netdev_to_offload(netdev))
return -EOPNOTSUPP;

Expand Down
1 change: 1 addition & 0 deletions include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -920,6 +920,7 @@ enum tc_setup_type {
TC_SETUP_QDISC_TBF,
TC_SETUP_QDISC_FIFO,
TC_SETUP_QDISC_HTB,
TC_SETUP_ACT,
};

/* These structures hold the attributes of bpf state that are being passed
Expand Down
27 changes: 26 additions & 1 deletion include/net/act_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

#include <linux/refcount.h>
#include <net/flow_offload.h>
#include <net/sch_generic.h>
#include <net/pkt_sched.h>
#include <net/net_namespace.h>
Expand Down Expand Up @@ -44,6 +45,7 @@ struct tc_action {
u8 hw_stats;
u8 used_hw_stats;
bool used_hw_stats_valid;
u32 in_hw_count;
};
#define tcf_index common.tcfa_index
#define tcf_refcnt common.tcfa_refcnt
Expand Down Expand Up @@ -88,6 +90,16 @@ static inline void tcf_tm_dump(struct tcf_t *dtm, const struct tcf_t *stm)
dtm->expires = jiffies_to_clock_t(stm->expires);
}

static inline enum flow_action_hw_stats tc_act_hw_stats(u8 hw_stats)
{
if (WARN_ON_ONCE(hw_stats > TCA_ACT_HW_STATS_ANY))
return FLOW_ACTION_HW_STATS_DONT_CARE;
else if (!hw_stats)
return FLOW_ACTION_HW_STATS_DISABLED;

return hw_stats;
}

#ifdef CONFIG_NET_CLS_ACT

#define ACT_P_CREATED 1
Expand Down Expand Up @@ -121,6 +133,8 @@ struct tc_action_ops {
struct psample_group *
(*get_psample_group)(const struct tc_action *a,
tc_action_priv_destructor *destructor);
int (*offload_act_setup)(struct tc_action *act, void *entry_data,
u32 *index_inc, bool bind);
};

struct tc_action_net {
Expand Down Expand Up @@ -189,7 +203,7 @@ int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions,
int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
struct nlattr *est,
struct tc_action *actions[], int init_res[], size_t *attr_size,
u32 flags, struct netlink_ext_ack *extack);
u32 flags, u32 fl_flags, struct netlink_ext_ack *extack);
struct tc_action_ops *tc_action_load_ops(struct nlattr *nla, bool police,
bool rtnl_held,
struct netlink_ext_ack *extack);
Expand Down Expand Up @@ -240,6 +254,9 @@ void tcf_action_update_stats(struct tc_action *a, u64 bytes, u64 packets,
u64 drops, bool hw);
int tcf_action_copy_stats(struct sk_buff *, struct tc_action *, int);

int tcf_action_update_hw_stats(struct tc_action *action);
int tcf_action_reoffload_cb(flow_indr_block_bind_cb_t *cb,
void *cb_priv, bool add);
int tcf_action_check_ctrlact(int action, struct tcf_proto *tp,
struct tcf_chain **handle,
struct netlink_ext_ack *newchain);
Expand All @@ -251,6 +268,14 @@ DECLARE_STATIC_KEY_FALSE(tcf_frag_xmit_count);
#endif

int tcf_dev_queue_xmit(struct sk_buff *skb, int (*xmit)(struct sk_buff *skb));

#else /* !CONFIG_NET_CLS_ACT */

static inline int tcf_action_reoffload_cb(flow_indr_block_bind_cb_t *cb,
void *cb_priv, bool add) {
return 0;
}

#endif /* CONFIG_NET_CLS_ACT */

static inline void tcf_action_stats_update(struct tc_action *a, u64 bytes,
Expand Down
20 changes: 18 additions & 2 deletions include/net/flow_offload.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ void flow_action_cookie_destroy(struct flow_action_cookie *cookie);

struct flow_action_entry {
enum flow_action_id id;
u32 hw_index;
enum flow_action_hw_stats hw_stats;
action_destr destructor;
void *destructor_priv;
Expand Down Expand Up @@ -232,7 +233,6 @@ struct flow_action_entry {
bool truncate;
} sample;
struct { /* FLOW_ACTION_POLICE */
u32 index;
u32 burst;
u64 rate_bytes_ps;
u64 burst_pkt;
Expand Down Expand Up @@ -267,7 +267,6 @@ struct flow_action_entry {
u8 ttl;
} mpls_mangle;
struct {
u32 index;
s32 prio;
u64 basetime;
u64 cycletime;
Expand Down Expand Up @@ -552,6 +551,23 @@ struct flow_cls_offload {
u32 classid;
};

enum offload_act_command {
FLOW_ACT_REPLACE,
FLOW_ACT_DESTROY,
FLOW_ACT_STATS,
};

struct flow_offload_action {
struct netlink_ext_ack *extack; /* NULL in FLOW_ACT_STATS process*/
enum offload_act_command command;
enum flow_action_id id;
u32 index;
struct flow_stats stats;
struct flow_action action;
};

struct flow_offload_action *offload_action_alloc(unsigned int num_actions);

static inline struct flow_rule *
flow_cls_offload_flow_rule(struct flow_cls_offload *flow_cmd)
{
Expand Down
38 changes: 24 additions & 14 deletions include/net/pkt_cls.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,26 +262,31 @@ static inline void tcf_exts_put_net(struct tcf_exts *exts)
for (; 0; (void)(i), (void)(a), (void)(exts))
#endif

#define tcf_act_for_each_action(i, a, actions) \
for (i = 0; i < TCA_ACT_MAX_PRIO && ((a) = actions[i]); i++)

static inline void
tcf_exts_stats_update(const struct tcf_exts *exts,
u64 bytes, u64 packets, u64 drops, u64 lastuse,
u8 used_hw_stats, bool used_hw_stats_valid)
tcf_exts_hw_stats_update(const struct tcf_exts *exts,
u64 bytes, u64 packets, u64 drops, u64 lastuse,
u8 used_hw_stats, bool used_hw_stats_valid)
{
#ifdef CONFIG_NET_CLS_ACT
int i;

preempt_disable();

for (i = 0; i < exts->nr_actions; i++) {
struct tc_action *a = exts->actions[i];

tcf_action_stats_update(a, bytes, packets, drops,
lastuse, true);
a->used_hw_stats = used_hw_stats;
a->used_hw_stats_valid = used_hw_stats_valid;
}
/* if stats from hw, just skip */
if (tcf_action_update_hw_stats(a)) {
preempt_disable();
tcf_action_stats_update(a, bytes, packets, drops,
lastuse, true);
preempt_enable();

preempt_enable();
a->used_hw_stats = used_hw_stats;
a->used_hw_stats_valid = used_hw_stats_valid;
}
}
#endif
}

Expand Down Expand Up @@ -325,6 +330,9 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp,
struct nlattr **tb, struct nlattr *rate_tlv,
struct tcf_exts *exts, u32 flags,
struct netlink_ext_ack *extack);
int tcf_exts_validate_ex(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
struct nlattr *rate_tlv, struct tcf_exts *exts,
u32 flags, u32 fl_flags, struct netlink_ext_ack *extack);
void tcf_exts_destroy(struct tcf_exts *exts);
void tcf_exts_change(struct tcf_exts *dst, struct tcf_exts *src);
int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts);
Expand Down Expand Up @@ -536,9 +544,11 @@ tcf_match_indev(struct sk_buff *skb, int ifindex)
return ifindex == skb->skb_iif;
}

int tc_setup_flow_action(struct flow_action *flow_action,
const struct tcf_exts *exts);
void tc_cleanup_flow_action(struct flow_action *flow_action);
int tc_setup_offload_action(struct flow_action *flow_action,
const struct tcf_exts *exts);
void tc_cleanup_offload_action(struct flow_action *flow_action);
int tc_setup_action(struct flow_action *flow_action,
struct tc_action *actions[]);

int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type,
void *type_data, bool err_stop, bool rtnl_held);
Expand Down
5 changes: 0 additions & 5 deletions include/net/tc_act/tc_gate.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,6 @@ static inline bool is_tcf_gate(const struct tc_action *a)
return false;
}

static inline u32 tcf_gate_index(const struct tc_action *a)
{
return a->tcfa_index;
}

static inline s32 tcf_gate_prio(const struct tc_action *a)
{
s32 tcfg_prio;
Expand Down
9 changes: 6 additions & 3 deletions include/uapi/linux/pkt_cls.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@ enum {
TCA_ACT_FLAGS,
TCA_ACT_HW_STATS,
TCA_ACT_USED_HW_STATS,
TCA_ACT_IN_HW_COUNT,
__TCA_ACT_MAX
};

/* See other TCA_ACT_FLAGS_ * flags in include/net/act_api.h. */
#define TCA_ACT_FLAGS_NO_PERCPU_STATS 1 /* Don't use percpu allocator for
* actions stats.
*/
#define TCA_ACT_FLAGS_NO_PERCPU_STATS (1 << 0) /* Don't use percpu allocator for
* actions stats.
*/
#define TCA_ACT_FLAGS_SKIP_HW (1 << 1) /* don't offload action to HW */
#define TCA_ACT_FLAGS_SKIP_SW (1 << 2) /* don't use action in SW */

/* tca HW stats type
* When user does not pass the attribute, he does not care.
Expand Down
Loading

0 comments on commit 434ed21

Please sign in to comment.