[PATCH net-next 0/3] flow_offload: hardware offload of TC actions

STALE1827d

42 messages, 6 authors, 2021-08-03 · open the first message on its own page

[PATCH net-next 0/3] flow_offload: hardware offload of TC actions

From: Simon Horman <hidden>
Date: 2021-07-22 09:19:57

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. 

Changes since 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.

Baowen Zheng (3):
  flow_offload: allow user to offload tc action to net device
  flow_offload: add process to delete offloaded actions from net device
  flow_offload: add process to update action stats from hardware

 drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c  |   2 +-
 .../ethernet/mellanox/mlx5/core/en/rep/tc.c   |   3 +
 .../ethernet/netronome/nfp/flower/offload.c   |   3 +
 include/linux/netdevice.h                     |   1 +
 include/net/act_api.h                         |   1 +
 include/net/flow_offload.h                    |  15 ++
 include/net/pkt_cls.h                         |  20 +++
 net/core/flow_offload.c                       |  26 ++-
 net/sched/act_api.c                           | 162 +++++++++++++++++-
 net/sched/cls_api.c                           |  42 ++++-
 10 files changed, 264 insertions(+), 11 deletions(-)

-- 
2.20.1

[PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Simon Horman <hidden>
Date: 2021-07-22 09:19:59

From: Baowen Zheng <redacted>

Use flow_indr_dev_register/flow_indr_dev_setup_offload to
offload tc action.

We offload the tc action mainly for ovs meter configuration.
Make some basic changes for different vendors to return EOPNOTSUPP.

We need to call tc_cleanup_flow_action to clean up tc action entry since
in tc_setup_action, some actions may hold dev refcnt, especially the mirror
action.

As per review from the RFC, the kernel test robot will fail to run, so
we add CONFIG_NET_CLS_ACT control for the action offload.

Signed-off-by: Baowen Zheng <redacted>
Signed-off-by: Louis Peens <redacted>
Signed-off-by: Simon Horman <redacted>
---
 drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c  |  2 +-
 .../ethernet/mellanox/mlx5/core/en/rep/tc.c   |  3 ++
 .../ethernet/netronome/nfp/flower/offload.c   |  3 ++
 include/linux/netdevice.h                     |  1 +
 include/net/flow_offload.h                    | 15 ++++++++
 include/net/pkt_cls.h                         | 15 ++++++++
 net/core/flow_offload.c                       | 26 +++++++++++++-
 net/sched/act_api.c                           | 33 +++++++++++++++++
 net/sched/cls_api.c                           | 36 ++++++++++++++++---
 9 files changed, 128 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
index 5e4429b14b8c..edbbf7b4df77 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
@@ -1951,7 +1951,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) {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
index 059799e4f483..111daacc4cc3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
@@ -486,6 +486,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,
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c
index 2406d33356ad..88bbc86347b4 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c
@@ -1869,6 +1869,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;
 
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 42f6f866d5f3..b138219baf6f 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -923,6 +923,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
diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
index 69c9eabf8325..26644596fd54 100644
--- a/include/net/flow_offload.h
+++ b/include/net/flow_offload.h
@@ -553,6 +553,21 @@ struct flow_cls_offload {
 	u32 classid;
 };
 
+enum flow_act_command {
+	FLOW_ACT_REPLACE,
+	FLOW_ACT_DESTROY,
+	FLOW_ACT_STATS,
+};
+
+struct flow_offload_action {
+	struct netlink_ext_ack *extack;
+	enum flow_act_command command;
+	struct flow_stats stats;
+	struct flow_action action;
+};
+
+struct flow_offload_action *flow_action_alloc(unsigned int num_actions);
+
 static inline struct flow_rule *
 flow_cls_offload_flow_rule(struct flow_cls_offload *flow_cmd)
 {
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index ec7823921bd2..cd4cf6b10f5d 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -266,6 +266,9 @@ 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,
@@ -536,8 +539,19 @@ tcf_match_indev(struct sk_buff *skb, int ifindex)
 	return ifindex == skb->skb_iif;
 }
 
+#ifdef CONFIG_NET_CLS_ACT
 int tc_setup_flow_action(struct flow_action *flow_action,
 			 const struct tcf_exts *exts);
+#else
+static inline int tc_setup_flow_action(struct flow_action *flow_action,
+				       const struct tcf_exts *exts)
+{
+		return 0;
+}
+#endif
+
+int tc_setup_action(struct flow_action *flow_action,
+		    struct tc_action *actions[]);
 void tc_cleanup_flow_action(struct flow_action *flow_action);
 
 int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type,
@@ -558,6 +572,7 @@ int tc_setup_cb_reoffload(struct tcf_block *block, struct tcf_proto *tp,
 			  enum tc_setup_type type, void *type_data,
 			  void *cb_priv, u32 *flags, unsigned int *in_hw_count);
 unsigned int tcf_exts_num_actions(struct tcf_exts *exts);
+unsigned int tcf_act_num_actions(struct tc_action *actions[]);
 
 #ifdef CONFIG_NET_CLS_ACT
 int tcf_qevent_init(struct tcf_qevent *qe, struct Qdisc *sch,
diff --git a/net/core/flow_offload.c b/net/core/flow_offload.c
index 715b67f6c62f..0fa2f75cc9b3 100644
--- a/net/core/flow_offload.c
+++ b/net/core/flow_offload.c
@@ -27,6 +27,27 @@ struct flow_rule *flow_rule_alloc(unsigned int num_actions)
 }
 EXPORT_SYMBOL(flow_rule_alloc);
 
+struct flow_offload_action *flow_action_alloc(unsigned int num_actions)
+{
+	struct flow_offload_action *fl_action;
+	int i;
+
+	fl_action = kzalloc(struct_size(fl_action, action.entries, num_actions),
+			    GFP_KERNEL);
+	if (!fl_action)
+		return NULL;
+
+	fl_action->action.num_entries = num_actions;
+	/* Pre-fill each action hw_stats with DONT_CARE.
+	 * Caller can override this if it wants stats for a given action.
+	 */
+	for (i = 0; i < num_actions; i++)
+		fl_action->action.entries[i].hw_stats = FLOW_ACTION_HW_STATS_DONT_CARE;
+
+	return fl_action;
+}
+EXPORT_SYMBOL(flow_action_alloc);
+
 #define FLOW_DISSECTOR_MATCH(__rule, __type, __out)				\
 	const struct flow_match *__m = &(__rule)->match;			\
 	struct flow_dissector *__d = (__m)->dissector;				\
@@ -476,6 +497,9 @@ int flow_indr_dev_setup_offload(struct net_device *dev, struct Qdisc *sch,
 
 	mutex_unlock(&flow_indr_block_lock);
 
-	return list_empty(&bo->cb_list) ? -EOPNOTSUPP : 0;
+	if (bo)
+		return list_empty(&bo->cb_list) ? -EOPNOTSUPP : 0;
+	else
+		return 0;
 }
 EXPORT_SYMBOL(flow_indr_dev_setup_offload);
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 998a2374f7ae..185f17ea60d5 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -1060,6 +1060,36 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
 	return ERR_PTR(err);
 }
 
+/* offload the tc command after inserted */
+int tcf_action_offload_cmd(struct tc_action *actions[],
+			   struct netlink_ext_ack *extack)
+{
+	struct flow_offload_action *fl_act;
+	int err = 0;
+
+	fl_act = flow_action_alloc(tcf_act_num_actions(actions));
+	if (!fl_act)
+		return -ENOMEM;
+
+	fl_act->extack = extack;
+	err = tc_setup_action(&fl_act->action, actions);
+	if (err) {
+		NL_SET_ERR_MSG_MOD(extack,
+				   "Failed to setup tc actions for offload\n");
+		goto err_out;
+	}
+	fl_act->command = FLOW_ACT_REPLACE;
+
+	flow_indr_dev_setup_offload(NULL, NULL, TC_SETUP_ACT, fl_act, NULL, NULL);
+
+	tc_cleanup_flow_action(&fl_act->action);
+
+err_out:
+	kfree(fl_act);
+	return err;
+}
+EXPORT_SYMBOL(tcf_action_offload_cmd);
+
 /* Returns numbers of initialized actions or negative error. */
 
 int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
@@ -1514,6 +1544,9 @@ static int tcf_action_add(struct net *net, struct nlattr *nla,
 		return ret;
 	ret = tcf_add_notify(net, n, actions, portid, attr_size, extack);
 
+	/* offload actions to hardware if possible */
+	tcf_action_offload_cmd(actions, extack);
+
 	/* only put existing actions */
 	for (i = 0; i < TCA_ACT_MAX_PRIO; i++)
 		if (init_res[i] == ACT_P_CREATED)
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index c8cb59a11098..9b9770dab5e8 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -3544,8 +3544,8 @@ static enum flow_action_hw_stats tc_act_hw_stats(u8 hw_stats)
 	return hw_stats;
 }
 
-int tc_setup_flow_action(struct flow_action *flow_action,
-			 const struct tcf_exts *exts)
+int tc_setup_action(struct flow_action *flow_action,
+		    struct tc_action *actions[])
 {
 	struct tc_action *act;
 	int i, j, k, err = 0;
@@ -3554,11 +3554,11 @@ int tc_setup_flow_action(struct flow_action *flow_action,
 	BUILD_BUG_ON(TCA_ACT_HW_STATS_IMMEDIATE != FLOW_ACTION_HW_STATS_IMMEDIATE);
 	BUILD_BUG_ON(TCA_ACT_HW_STATS_DELAYED != FLOW_ACTION_HW_STATS_DELAYED);
 
-	if (!exts)
+	if (!actions)
 		return 0;
 
 	j = 0;
-	tcf_exts_for_each_action(i, act, exts) {
+	tcf_act_for_each_action(i, act, actions) {
 		struct flow_action_entry *entry;
 
 		entry = &flow_action->entries[j];
@@ -3725,7 +3725,19 @@ int tc_setup_flow_action(struct flow_action *flow_action,
 	spin_unlock_bh(&act->tcfa_lock);
 	goto err_out;
 }
+EXPORT_SYMBOL(tc_setup_action);
+
+#ifdef CONFIG_NET_CLS_ACT
+int tc_setup_flow_action(struct flow_action *flow_action,
+			 const struct tcf_exts *exts)
+{
+	if (!exts)
+		return 0;
+
+	return tc_setup_action(flow_action, exts->actions);
+}
 EXPORT_SYMBOL(tc_setup_flow_action);
+#endif
 
 unsigned int tcf_exts_num_actions(struct tcf_exts *exts)
 {
@@ -3743,6 +3755,22 @@ unsigned int tcf_exts_num_actions(struct tcf_exts *exts)
 }
 EXPORT_SYMBOL(tcf_exts_num_actions);
 
+unsigned int tcf_act_num_actions(struct tc_action *actions[])
+{
+	unsigned int num_acts = 0;
+	struct tc_action *act;
+	int i;
+
+	tcf_act_for_each_action(i, act, actions) {
+		if (is_tcf_pedit(act))
+			num_acts += tcf_pedit_nkeys(act);
+		else
+			num_acts++;
+	}
+	return num_acts;
+}
+EXPORT_SYMBOL(tcf_act_num_actions);
+
 #ifdef CONFIG_NET_CLS_ACT
 static int tcf_qevent_parse_block_index(struct nlattr *block_index_attr,
 					u32 *p_block_index,
-- 
2.20.1

[PATCH net-next 2/3] flow_offload: add process to delete offloaded actions from net device

From: Simon Horman <hidden>
Date: 2021-07-22 09:20:01

From: Baowen Zheng <redacted>

Add a basic process to delete offloaded actions from net device.

Should not remove the offloaded action entries if the action
fails to delete in tcf_del_notify.

Signed-off-by: Baowen Zheng <redacted>
Signed-off-by: Louis Peens <redacted>
Signed-off-by: Simon Horman <redacted>
---
 include/net/pkt_cls.h |   1 +
 net/sched/act_api.c   | 112 +++++++++++++++++++++++++++++++++++-------
 net/sched/cls_api.c   |  14 ++++--
 3 files changed, 106 insertions(+), 21 deletions(-)
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index cd4cf6b10f5d..03dae225d64f 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -573,6 +573,7 @@ int tc_setup_cb_reoffload(struct tcf_block *block, struct tcf_proto *tp,
 			  void *cb_priv, u32 *flags, unsigned int *in_hw_count);
 unsigned int tcf_exts_num_actions(struct tcf_exts *exts);
 unsigned int tcf_act_num_actions(struct tc_action *actions[]);
+unsigned int tcf_act_num_actions_single(struct tc_action *act);
 
 #ifdef CONFIG_NET_CLS_ACT
 int tcf_qevent_init(struct tcf_qevent *qe, struct Qdisc *sch,
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 185f17ea60d5..23a4538916af 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -1060,36 +1060,109 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
 	return ERR_PTR(err);
 }
 
-/* offload the tc command after inserted */
-int tcf_action_offload_cmd(struct tc_action *actions[],
-			   struct netlink_ext_ack *extack)
+int tcf_action_offload_cmd_pre(struct tc_action *actions[],
+			       enum flow_act_command cmd,
+			       struct netlink_ext_ack *extack,
+			       struct flow_offload_action **fl_act)
 {
-	struct flow_offload_action *fl_act;
+	struct flow_offload_action *fl_act_p;
 	int err = 0;
 
-	fl_act = flow_action_alloc(tcf_act_num_actions(actions));
-	if (!fl_act)
+	fl_act_p = flow_action_alloc(tcf_act_num_actions(actions));
+	if (!fl_act_p)
 		return -ENOMEM;
 
-	fl_act->extack = extack;
-	err = tc_setup_action(&fl_act->action, actions);
+	fl_act_p->extack = extack;
+	fl_act_p->command = cmd;
+	err = tc_setup_action(&fl_act_p->action, actions);
 	if (err) {
 		NL_SET_ERR_MSG_MOD(extack,
 				   "Failed to setup tc actions for offload\n");
 		goto err_out;
 	}
-	fl_act->command = FLOW_ACT_REPLACE;
+	*fl_act = fl_act_p;
+	return 0;
+err_out:
+	kfree(fl_act_p);
+	return err;
+}
+EXPORT_SYMBOL(tcf_action_offload_cmd_pre);
+
+int tcf_action_offload_cmd_post(struct flow_offload_action *fl_act,
+				struct netlink_ext_ack *extack)
+{
+	if (IS_ERR(fl_act))
+		return PTR_ERR(fl_act);
 
 	flow_indr_dev_setup_offload(NULL, NULL, TC_SETUP_ACT, fl_act, NULL, NULL);
 
 	tc_cleanup_flow_action(&fl_act->action);
-
-err_out:
 	kfree(fl_act);
-	return err;
+	return 0;
+}
+
+/* offload the tc command after inserted */
+int tcf_action_offload_cmd(struct tc_action *actions[],
+			   struct netlink_ext_ack *extack)
+{
+	struct flow_offload_action *fl_act;
+	int err = 0;
+
+	err = tcf_action_offload_cmd_pre(actions,
+					 FLOW_ACT_REPLACE,
+					 extack,
+					 &fl_act);
+	if (err)
+		return err;
+
+	return tcf_action_offload_cmd_post(fl_act, extack);
 }
 EXPORT_SYMBOL(tcf_action_offload_cmd);
 
+/* offload the tc command after deleted */
+int tcf_action_offload_del_post(struct flow_offload_action *fl_act,
+				struct tc_action *actions[],
+				struct netlink_ext_ack *extack,
+				int fallback_num)
+{
+	int fallback_entries = 0;
+	struct tc_action *act;
+	int total_entries = 0;
+	int i;
+
+	if (!fl_act)
+		return -EINVAL;
+
+	if (fallback_num) {
+		/* for each the actions to fallback the action entries remain in the actions */
+		for (i = 0; i < TCA_ACT_MAX_PRIO; i++) {
+			act = actions[i];
+			if (!act)
+				continue;
+
+			fallback_entries += tcf_act_num_actions_single(act);
+		}
+		fallback_entries += fallback_num;
+	}
+	total_entries = fl_act->action.num_entries;
+	if (total_entries > fallback_entries) {
+		/* just offload the actions that is not fallback and start with the actions */
+		fl_act->action.num_entries -= fallback_entries;
+		flow_indr_dev_setup_offload(NULL, NULL, TC_SETUP_ACT, fl_act, NULL, NULL);
+
+		/* recovery num_entries for cleanup */
+		fl_act->action.num_entries = total_entries;
+	} else {
+		NL_SET_ERR_MSG(extack, "no entries to offload when deleting the tc actions");
+	}
+
+	tc_cleanup_flow_action(&fl_act->action);
+
+	kfree(fl_act);
+	return 0;
+}
+EXPORT_SYMBOL(tcf_action_offload_del_post);
+
 /* Returns numbers of initialized actions or negative error. */
 
 int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
@@ -1393,7 +1466,7 @@ static int tca_action_flush(struct net *net, struct nlattr *nla,
 	return err;
 }
 
-static int tcf_action_delete(struct net *net, struct tc_action *actions[])
+static int tcf_action_delete(struct net *net, struct tc_action *actions[], int *fallbacknum)
 {
 	int i;
 
@@ -1407,6 +1480,7 @@ static int tcf_action_delete(struct net *net, struct tc_action *actions[])
 		u32 act_index = a->tcfa_index;
 
 		actions[i] = NULL;
+		*fallbacknum = tcf_act_num_actions_single(a);
 		if (tcf_action_put(a)) {
 			/* last reference, action was deleted concurrently */
 			module_put(ops->owner);
@@ -1419,12 +1493,13 @@ static int tcf_action_delete(struct net *net, struct tc_action *actions[])
 				return ret;
 		}
 	}
+	*fallbacknum = 0;
 	return 0;
 }
 
 static int
 tcf_del_notify(struct net *net, struct nlmsghdr *n, struct tc_action *actions[],
-	       u32 portid, size_t attr_size, struct netlink_ext_ack *extack)
+	       u32 portid, size_t attr_size, struct netlink_ext_ack *extack, int *fallbacknum)
 {
 	int ret;
 	struct sk_buff *skb;
@@ -1442,7 +1517,7 @@ tcf_del_notify(struct net *net, struct nlmsghdr *n, struct tc_action *actions[],
 	}
 
 	/* now do the delete */
-	ret = tcf_action_delete(net, actions);
+	ret = tcf_action_delete(net, actions, fallbacknum);
 	if (ret < 0) {
 		NL_SET_ERR_MSG(extack, "Failed to delete TC action");
 		kfree_skb(skb);
@@ -1458,11 +1533,12 @@ static int
 tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
 	      u32 portid, int event, struct netlink_ext_ack *extack)
 {
-	int i, ret;
 	struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
 	struct tc_action *act;
 	size_t attr_size = 0;
 	struct tc_action *actions[TCA_ACT_MAX_PRIO] = {};
+	struct flow_offload_action *fl_act;
+	int i, ret, fallback_num;
 
 	ret = nla_parse_nested_deprecated(tb, TCA_ACT_MAX_PRIO, nla, NULL,
 					  extack);
@@ -1492,7 +1568,9 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
 	if (event == RTM_GETACTION)
 		ret = tcf_get_notify(net, portid, n, actions, event, extack);
 	else { /* delete */
-		ret = tcf_del_notify(net, n, actions, portid, attr_size, extack);
+		tcf_action_offload_cmd_pre(actions, FLOW_ACT_DESTROY, extack, &fl_act);
+		ret = tcf_del_notify(net, n, actions, portid, attr_size, extack, &fallback_num);
+		tcf_action_offload_del_post(fl_act, actions, extack, fallback_num);
 		if (ret)
 			goto err;
 		return 0;
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 9b9770dab5e8..23ce021f07f8 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -3755,6 +3755,15 @@ unsigned int tcf_exts_num_actions(struct tcf_exts *exts)
 }
 EXPORT_SYMBOL(tcf_exts_num_actions);
 
+unsigned int tcf_act_num_actions_single(struct tc_action *act)
+{
+	if (is_tcf_pedit(act))
+		return tcf_pedit_nkeys(act);
+	else
+		return 1;
+}
+EXPORT_SYMBOL(tcf_act_num_actions_single);
+
 unsigned int tcf_act_num_actions(struct tc_action *actions[])
 {
 	unsigned int num_acts = 0;
@@ -3762,10 +3771,7 @@ unsigned int tcf_act_num_actions(struct tc_action *actions[])
 	int i;
 
 	tcf_act_for_each_action(i, act, actions) {
-		if (is_tcf_pedit(act))
-			num_acts += tcf_pedit_nkeys(act);
-		else
-			num_acts++;
+		num_acts += tcf_act_num_actions_single(act);
 	}
 	return num_acts;
 }
-- 
2.20.1

[PATCH net-next 3/3] flow_offload: add process to update action stats from hardware

From: Simon Horman <hidden>
Date: 2021-07-22 09:20:08

From: Baowen Zheng <redacted>

When collecting stats for actions update them using both
both hardware and software counters.

Signed-off-by: Baowen Zheng <redacted>
Signed-off-by: Louis Peens <redacted>
Signed-off-by: Simon Horman <redacted>
---
 include/net/act_api.h      |  1 +
 include/net/flow_offload.h |  2 +-
 include/net/pkt_cls.h      |  4 ++++
 net/sched/act_api.c        | 49 ++++++++++++++++++++++++++++++++++----
 4 files changed, 51 insertions(+), 5 deletions(-)
diff --git a/include/net/act_api.h b/include/net/act_api.h
index 086b291e9530..fe8331b5efce 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -233,6 +233,7 @@ static inline void tcf_action_inc_overlimit_qstats(struct tc_action *a)
 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_check_ctrlact(int action, struct tcf_proto *tp,
 			     struct tcf_chain **handle,
diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
index 26644596fd54..467688fff7ce 100644
--- a/include/net/flow_offload.h
+++ b/include/net/flow_offload.h
@@ -560,7 +560,7 @@ enum flow_act_command {
 };
 
 struct flow_offload_action {
-	struct netlink_ext_ack *extack;
+	struct netlink_ext_ack *extack; /* NULL in FLOW_ACT_STATS process*/
 	enum flow_act_command command;
 	struct flow_stats stats;
 	struct flow_action action;
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index 03dae225d64f..569c9294b15b 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -282,6 +282,10 @@ tcf_exts_stats_update(const struct tcf_exts *exts,
 	for (i = 0; i < exts->nr_actions; i++) {
 		struct tc_action *a = exts->actions[i];
 
+		/* if stats from hw, just skip */
+		if (!tcf_action_update_hw_stats(a))
+			continue;
+
 		tcf_action_stats_update(a, bytes, packets, drops,
 					lastuse, true);
 		a->used_hw_stats = used_hw_stats;
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 23a4538916af..7d5535bc2c13 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -1089,15 +1089,18 @@ int tcf_action_offload_cmd_pre(struct tc_action *actions[],
 EXPORT_SYMBOL(tcf_action_offload_cmd_pre);
 
 int tcf_action_offload_cmd_post(struct flow_offload_action *fl_act,
-				struct netlink_ext_ack *extack)
+				struct netlink_ext_ack *extack,
+				bool keep_fl_act)
 {
 	if (IS_ERR(fl_act))
 		return PTR_ERR(fl_act);
 
 	flow_indr_dev_setup_offload(NULL, NULL, TC_SETUP_ACT, fl_act, NULL, NULL);
 
-	tc_cleanup_flow_action(&fl_act->action);
-	kfree(fl_act);
+	if (!keep_fl_act) {
+		tc_cleanup_flow_action(&fl_act->action);
+		kfree(fl_act);
+	}
 	return 0;
 }
 
@@ -1115,10 +1118,45 @@ int tcf_action_offload_cmd(struct tc_action *actions[],
 	if (err)
 		return err;
 
-	return tcf_action_offload_cmd_post(fl_act, extack);
+	return tcf_action_offload_cmd_post(fl_act, extack, false);
 }
 EXPORT_SYMBOL(tcf_action_offload_cmd);
 
+int tcf_action_update_hw_stats(struct tc_action *action)
+{
+	struct tc_action *actions[TCA_ACT_MAX_PRIO] = {
+		[0] = action,
+	};
+	struct flow_offload_action *fl_act;
+	int err = 0;
+
+	err = tcf_action_offload_cmd_pre(actions,
+					 FLOW_ACT_STATS,
+					 NULL,
+					 &fl_act);
+	if (err)
+		goto err_out;
+
+	err = tcf_action_offload_cmd_post(fl_act, NULL, true);
+
+	if (fl_act->stats.lastused) {
+		tcf_action_stats_update(action, fl_act->stats.bytes,
+					fl_act->stats.pkts,
+					fl_act->stats.drops,
+					fl_act->stats.lastused,
+					true);
+		err = 0;
+	} else {
+		err = -EOPNOTSUPP;
+	}
+	tc_cleanup_flow_action(&fl_act->action);
+	kfree(fl_act);
+
+err_out:
+	return err;
+}
+EXPORT_SYMBOL(tcf_action_update_hw_stats);
+
 /* offload the tc command after deleted */
 int tcf_action_offload_del_post(struct flow_offload_action *fl_act,
 				struct tc_action *actions[],
@@ -1255,6 +1293,9 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *p,
 	if (p == NULL)
 		goto errout;
 
+	/* update hw stats for this action */
+	tcf_action_update_hw_stats(p);
+
 	/* compat_mode being true specifies a call that is supposed
 	 * to add additional backward compatibility statistic TLVs.
 	 */
-- 
2.20.1

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Roi Dayan <hidden>
Date: 2021-07-22 12:24:16


On 2021-07-22 12:19 PM, Simon Horman wrote:
quoted hunk
From: Baowen Zheng <redacted>

Use flow_indr_dev_register/flow_indr_dev_setup_offload to
offload tc action.

We offload the tc action mainly for ovs meter configuration.
Make some basic changes for different vendors to return EOPNOTSUPP.

We need to call tc_cleanup_flow_action to clean up tc action entry since
in tc_setup_action, some actions may hold dev refcnt, especially the mirror
action.

As per review from the RFC, the kernel test robot will fail to run, so
we add CONFIG_NET_CLS_ACT control for the action offload.

Signed-off-by: Baowen Zheng <redacted>
Signed-off-by: Louis Peens <redacted>
Signed-off-by: Simon Horman <redacted>
---
  drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c  |  2 +-
  .../ethernet/mellanox/mlx5/core/en/rep/tc.c   |  3 ++
  .../ethernet/netronome/nfp/flower/offload.c   |  3 ++
  include/linux/netdevice.h                     |  1 +
  include/net/flow_offload.h                    | 15 ++++++++
  include/net/pkt_cls.h                         | 15 ++++++++
  net/core/flow_offload.c                       | 26 +++++++++++++-
  net/sched/act_api.c                           | 33 +++++++++++++++++
  net/sched/cls_api.c                           | 36 ++++++++++++++++---
  9 files changed, 128 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
index 5e4429b14b8c..edbbf7b4df77 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
@@ -1951,7 +1951,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) {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
index 059799e4f483..111daacc4cc3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
@@ -486,6 +486,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,
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c
index 2406d33356ad..88bbc86347b4 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c
@@ -1869,6 +1869,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;
  
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 42f6f866d5f3..b138219baf6f 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -923,6 +923,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
diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
index 69c9eabf8325..26644596fd54 100644
--- a/include/net/flow_offload.h
+++ b/include/net/flow_offload.h
@@ -553,6 +553,21 @@ struct flow_cls_offload {
  	u32 classid;
  };
  
+enum flow_act_command {
+	FLOW_ACT_REPLACE,
+	FLOW_ACT_DESTROY,
+	FLOW_ACT_STATS,
+};
+
+struct flow_offload_action {
+	struct netlink_ext_ack *extack;
+	enum flow_act_command command;
+	struct flow_stats stats;
+	struct flow_action action;
+};
+
+struct flow_offload_action *flow_action_alloc(unsigned int num_actions);
+
  static inline struct flow_rule *
  flow_cls_offload_flow_rule(struct flow_cls_offload *flow_cmd)
  {
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index ec7823921bd2..cd4cf6b10f5d 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -266,6 +266,9 @@ 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,
@@ -536,8 +539,19 @@ tcf_match_indev(struct sk_buff *skb, int ifindex)
  	return ifindex == skb->skb_iif;
  }
  
+#ifdef CONFIG_NET_CLS_ACT
  int tc_setup_flow_action(struct flow_action *flow_action,
  			 const struct tcf_exts *exts);
+#else
+static inline int tc_setup_flow_action(struct flow_action *flow_action,
+				       const struct tcf_exts *exts)
+{
+		return 0;
+}
+#endif
+
+int tc_setup_action(struct flow_action *flow_action,
+		    struct tc_action *actions[]);
  void tc_cleanup_flow_action(struct flow_action *flow_action);
  
  int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type,
@@ -558,6 +572,7 @@ int tc_setup_cb_reoffload(struct tcf_block *block, struct tcf_proto *tp,
  			  enum tc_setup_type type, void *type_data,
  			  void *cb_priv, u32 *flags, unsigned int *in_hw_count);
  unsigned int tcf_exts_num_actions(struct tcf_exts *exts);
+unsigned int tcf_act_num_actions(struct tc_action *actions[]);
  
  #ifdef CONFIG_NET_CLS_ACT
  int tcf_qevent_init(struct tcf_qevent *qe, struct Qdisc *sch,
diff --git a/net/core/flow_offload.c b/net/core/flow_offload.c
index 715b67f6c62f..0fa2f75cc9b3 100644
--- a/net/core/flow_offload.c
+++ b/net/core/flow_offload.c
@@ -27,6 +27,27 @@ struct flow_rule *flow_rule_alloc(unsigned int num_actions)
  }
  EXPORT_SYMBOL(flow_rule_alloc);
  
+struct flow_offload_action *flow_action_alloc(unsigned int num_actions)
+{
+	struct flow_offload_action *fl_action;
+	int i;
+
+	fl_action = kzalloc(struct_size(fl_action, action.entries, num_actions),
+			    GFP_KERNEL);
+	if (!fl_action)
+		return NULL;
Hi Simon,

Our automatic tests got a trace from flow_action_alloc()
introduced in this series.
I don't have specific commands right now but maybe its easy
to reproduce with option CONFIG_DEBUG_ATOMIC_SLEEP=y

fl_dump->fl_hw_update_stats->fl_hw_update_stats->tcf_exts_stats_update
   ->tcf_action_update_hw_stats->tcf_action_offload_cmd_pre->
     ->flow_action_alloc

Thanks,
Roi



[  761.008866] BUG: sleeping function called from invalid context at 
include/linux/sched/mm.h:201
[  761.011047] in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 
20194, name: handler1
[  761.013052] INFO: lockdep is turned off.
[  761.014102] CPU: 1 PID: 20194 Comm: handler1 Not tainted 
5.14.0-rc1_2021_07_22_09_58_22_ #1
[  761.015891] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 
rel-1.13.0-0-gf21b5a4aeb02-prebuilt.qemu.org 04/01/2014
[  761.017190] Call Trace:
[  761.017556]  dump_stack_lvl+0x57/0x7d
[  761.018038]  ___might_sleep.cold+0x15a/0x1b7
[  761.018583]  __kmalloc+0x259/0x430
[  761.019044]  ? flow_action_alloc+0x28/0xd0
[  761.019574]  ? lock_release+0x460/0x750
[  761.020068]  flow_action_alloc+0x28/0xd0
[  761.020586]  tcf_action_offload_cmd_pre+0x25/0x130
[  761.021188]  tcf_action_update_hw_stats+0x9e/0x2e0
[  761.021791]  ? tcf_action_offload_cmd+0xe0/0xe0
[  761.022358]  ? is_bpf_text_address+0x73/0x110
[  761.022918]  ? mlx5e_delete_flower+0xf50/0xf50 [mlx5_core]
[  761.023713]  ? tc_setup_cb_call+0x181/0x270
[  761.024254]  fl_hw_update_stats+0x2e4/0x4e0 [cls_flower]
[  761.024908]  ? fl_hw_replace_filter+0x6a0/0x6a0 [cls_flower]
[  761.025595]  ? lock_release+0x460/0x750
[  761.026095]  ? memcpy+0x39/0x60
[  761.026537]  fl_dump+0x499/0x5f0 [cls_flower]
[  761.027106]  ? fl_tmplt_dump+0x220/0x220 [cls_flower]
[  761.027746]  ? memcpy+0x39/0x60
[  761.028173]  ? nla_put+0x15f/0x1c0
[  761.028634]  tcf_fill_node+0x50f/0x930
[  761.029137]  ? __tcf_get_next_proto+0x470/0x470
[  761.029725]  ? memset+0x20/0x40
[  761.030167]  tfilter_notify+0x15e/0x2d0
[  761.030681]  tc_new_tfilter+0x1128/0x1ea0
[  761.031218]  ? tc_del_tfilter+0x13e0/0x13e0
[  761.031768]  ? security_capable+0x51/0x90
[  761.032280]  ? tc_del_tfilter+0x13e0/0x13e0
[  761.032826]  rtnetlink_rcv_msg+0x637/0x950


quoted hunk
+
+	fl_action->action.num_entries = num_actions;
+	/* Pre-fill each action hw_stats with DONT_CARE.
+	 * Caller can override this if it wants stats for a given action.
+	 */
+	for (i = 0; i < num_actions; i++)
+		fl_action->action.entries[i].hw_stats = FLOW_ACTION_HW_STATS_DONT_CARE;
+
+	return fl_action;
+}
+EXPORT_SYMBOL(flow_action_alloc);
+
  #define FLOW_DISSECTOR_MATCH(__rule, __type, __out)				\
  	const struct flow_match *__m = &(__rule)->match;			\
  	struct flow_dissector *__d = (__m)->dissector;				\
@@ -476,6 +497,9 @@ int flow_indr_dev_setup_offload(struct net_device *dev, struct Qdisc *sch,
  
  	mutex_unlock(&flow_indr_block_lock);
  
-	return list_empty(&bo->cb_list) ? -EOPNOTSUPP : 0;
+	if (bo)
+		return list_empty(&bo->cb_list) ? -EOPNOTSUPP : 0;
+	else
+		return 0;
  }
  EXPORT_SYMBOL(flow_indr_dev_setup_offload);
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 998a2374f7ae..185f17ea60d5 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -1060,6 +1060,36 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
  	return ERR_PTR(err);
  }
  
+/* offload the tc command after inserted */
+int tcf_action_offload_cmd(struct tc_action *actions[],
+			   struct netlink_ext_ack *extack)
+{
+	struct flow_offload_action *fl_act;
+	int err = 0;
+
+	fl_act = flow_action_alloc(tcf_act_num_actions(actions));
+	if (!fl_act)
+		return -ENOMEM;
+
+	fl_act->extack = extack;
+	err = tc_setup_action(&fl_act->action, actions);
+	if (err) {
+		NL_SET_ERR_MSG_MOD(extack,
+				   "Failed to setup tc actions for offload\n");
+		goto err_out;
+	}
+	fl_act->command = FLOW_ACT_REPLACE;
+
+	flow_indr_dev_setup_offload(NULL, NULL, TC_SETUP_ACT, fl_act, NULL, NULL);
+
+	tc_cleanup_flow_action(&fl_act->action);
+
+err_out:
+	kfree(fl_act);
+	return err;
+}
+EXPORT_SYMBOL(tcf_action_offload_cmd);
+
  /* Returns numbers of initialized actions or negative error. */
  
  int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
@@ -1514,6 +1544,9 @@ static int tcf_action_add(struct net *net, struct nlattr *nla,
  		return ret;
  	ret = tcf_add_notify(net, n, actions, portid, attr_size, extack);
  
+	/* offload actions to hardware if possible */
+	tcf_action_offload_cmd(actions, extack);
+
  	/* only put existing actions */
  	for (i = 0; i < TCA_ACT_MAX_PRIO; i++)
  		if (init_res[i] == ACT_P_CREATED)
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index c8cb59a11098..9b9770dab5e8 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -3544,8 +3544,8 @@ static enum flow_action_hw_stats tc_act_hw_stats(u8 hw_stats)
  	return hw_stats;
  }
  
-int tc_setup_flow_action(struct flow_action *flow_action,
-			 const struct tcf_exts *exts)
+int tc_setup_action(struct flow_action *flow_action,
+		    struct tc_action *actions[])
  {
  	struct tc_action *act;
  	int i, j, k, err = 0;
@@ -3554,11 +3554,11 @@ int tc_setup_flow_action(struct flow_action *flow_action,
  	BUILD_BUG_ON(TCA_ACT_HW_STATS_IMMEDIATE != FLOW_ACTION_HW_STATS_IMMEDIATE);
  	BUILD_BUG_ON(TCA_ACT_HW_STATS_DELAYED != FLOW_ACTION_HW_STATS_DELAYED);
  
-	if (!exts)
+	if (!actions)
  		return 0;
  
  	j = 0;
-	tcf_exts_for_each_action(i, act, exts) {
+	tcf_act_for_each_action(i, act, actions) {
  		struct flow_action_entry *entry;
  
  		entry = &flow_action->entries[j];
@@ -3725,7 +3725,19 @@ int tc_setup_flow_action(struct flow_action *flow_action,
  	spin_unlock_bh(&act->tcfa_lock);
  	goto err_out;
  }
+EXPORT_SYMBOL(tc_setup_action);
+
+#ifdef CONFIG_NET_CLS_ACT
+int tc_setup_flow_action(struct flow_action *flow_action,
+			 const struct tcf_exts *exts)
+{
+	if (!exts)
+		return 0;
+
+	return tc_setup_action(flow_action, exts->actions);
+}
  EXPORT_SYMBOL(tc_setup_flow_action);
+#endif
  
  unsigned int tcf_exts_num_actions(struct tcf_exts *exts)
  {
@@ -3743,6 +3755,22 @@ unsigned int tcf_exts_num_actions(struct tcf_exts *exts)
  }
  EXPORT_SYMBOL(tcf_exts_num_actions);
  
+unsigned int tcf_act_num_actions(struct tc_action *actions[])
+{
+	unsigned int num_acts = 0;
+	struct tc_action *act;
+	int i;
+
+	tcf_act_for_each_action(i, act, actions) {
+		if (is_tcf_pedit(act))
+			num_acts += tcf_pedit_nkeys(act);
+		else
+			num_acts++;
+	}
+	return num_acts;
+}
+EXPORT_SYMBOL(tcf_act_num_actions);
+
  #ifdef CONFIG_NET_CLS_ACT
  static int tcf_qevent_parse_block_index(struct nlattr *block_index_attr,
  					u32 *p_block_index,

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Simon Horman <hidden>
Date: 2021-07-22 13:19:22

On Thu, Jul 22, 2021 at 03:24:07PM +0300, Roi Dayan wrote:

On 2021-07-22 12:19 PM, Simon Horman wrote:
quoted
From: Baowen Zheng <redacted>

Use flow_indr_dev_register/flow_indr_dev_setup_offload to
offload tc action.

We offload the tc action mainly for ovs meter configuration.
Make some basic changes for different vendors to return EOPNOTSUPP.

We need to call tc_cleanup_flow_action to clean up tc action entry since
in tc_setup_action, some actions may hold dev refcnt, especially the mirror
action.

As per review from the RFC, the kernel test robot will fail to run, so
we add CONFIG_NET_CLS_ACT control for the action offload.

Signed-off-by: Baowen Zheng <redacted>
Signed-off-by: Louis Peens <redacted>
Signed-off-by: Simon Horman <redacted>
---
  drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c  |  2 +-
  .../ethernet/mellanox/mlx5/core/en/rep/tc.c   |  3 ++
  .../ethernet/netronome/nfp/flower/offload.c   |  3 ++
  include/linux/netdevice.h                     |  1 +
  include/net/flow_offload.h                    | 15 ++++++++
  include/net/pkt_cls.h                         | 15 ++++++++
  net/core/flow_offload.c                       | 26 +++++++++++++-
  net/sched/act_api.c                           | 33 +++++++++++++++++
  net/sched/cls_api.c                           | 36 ++++++++++++++++---
  9 files changed, 128 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
index 5e4429b14b8c..edbbf7b4df77 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
@@ -1951,7 +1951,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) {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
index 059799e4f483..111daacc4cc3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
@@ -486,6 +486,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,
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c
index 2406d33356ad..88bbc86347b4 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c
@@ -1869,6 +1869,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;
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 42f6f866d5f3..b138219baf6f 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -923,6 +923,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
diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
index 69c9eabf8325..26644596fd54 100644
--- a/include/net/flow_offload.h
+++ b/include/net/flow_offload.h
@@ -553,6 +553,21 @@ struct flow_cls_offload {
  	u32 classid;
  };
+enum flow_act_command {
+	FLOW_ACT_REPLACE,
+	FLOW_ACT_DESTROY,
+	FLOW_ACT_STATS,
+};
+
+struct flow_offload_action {
+	struct netlink_ext_ack *extack;
+	enum flow_act_command command;
+	struct flow_stats stats;
+	struct flow_action action;
+};
+
+struct flow_offload_action *flow_action_alloc(unsigned int num_actions);
+
  static inline struct flow_rule *
  flow_cls_offload_flow_rule(struct flow_cls_offload *flow_cmd)
  {
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index ec7823921bd2..cd4cf6b10f5d 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -266,6 +266,9 @@ 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,
@@ -536,8 +539,19 @@ tcf_match_indev(struct sk_buff *skb, int ifindex)
  	return ifindex == skb->skb_iif;
  }
+#ifdef CONFIG_NET_CLS_ACT
  int tc_setup_flow_action(struct flow_action *flow_action,
  			 const struct tcf_exts *exts);
+#else
+static inline int tc_setup_flow_action(struct flow_action *flow_action,
+				       const struct tcf_exts *exts)
+{
+		return 0;
+}
+#endif
+
+int tc_setup_action(struct flow_action *flow_action,
+		    struct tc_action *actions[]);
  void tc_cleanup_flow_action(struct flow_action *flow_action);
  int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type,
@@ -558,6 +572,7 @@ int tc_setup_cb_reoffload(struct tcf_block *block, struct tcf_proto *tp,
  			  enum tc_setup_type type, void *type_data,
  			  void *cb_priv, u32 *flags, unsigned int *in_hw_count);
  unsigned int tcf_exts_num_actions(struct tcf_exts *exts);
+unsigned int tcf_act_num_actions(struct tc_action *actions[]);
  #ifdef CONFIG_NET_CLS_ACT
  int tcf_qevent_init(struct tcf_qevent *qe, struct Qdisc *sch,
diff --git a/net/core/flow_offload.c b/net/core/flow_offload.c
index 715b67f6c62f..0fa2f75cc9b3 100644
--- a/net/core/flow_offload.c
+++ b/net/core/flow_offload.c
@@ -27,6 +27,27 @@ struct flow_rule *flow_rule_alloc(unsigned int num_actions)
  }
  EXPORT_SYMBOL(flow_rule_alloc);
+struct flow_offload_action *flow_action_alloc(unsigned int num_actions)
+{
+	struct flow_offload_action *fl_action;
+	int i;
+
+	fl_action = kzalloc(struct_size(fl_action, action.entries, num_actions),
+			    GFP_KERNEL);
+	if (!fl_action)
+		return NULL;
Hi Simon,

Our automatic tests got a trace from flow_action_alloc()
introduced in this series.
I don't have specific commands right now but maybe its easy
to reproduce with option CONFIG_DEBUG_ATOMIC_SLEEP=y

fl_dump->fl_hw_update_stats->fl_hw_update_stats->tcf_exts_stats_update
  ->tcf_action_update_hw_stats->tcf_action_offload_cmd_pre->
    ->flow_action_alloc

Thanks,
Roi
Thanks Roi,

we'll look into this.

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Vlad Buslov <hidden>
Date: 2021-07-22 13:29:22

On Thu 22 Jul 2021 at 12:19, Simon Horman [off-list ref] wrote:
quoted hunk
From: Baowen Zheng <redacted>

Use flow_indr_dev_register/flow_indr_dev_setup_offload to
offload tc action.

We offload the tc action mainly for ovs meter configuration.
Make some basic changes for different vendors to return EOPNOTSUPP.

We need to call tc_cleanup_flow_action to clean up tc action entry since
in tc_setup_action, some actions may hold dev refcnt, especially the mirror
action.

As per review from the RFC, the kernel test robot will fail to run, so
we add CONFIG_NET_CLS_ACT control for the action offload.

Signed-off-by: Baowen Zheng <redacted>
Signed-off-by: Louis Peens <redacted>
Signed-off-by: Simon Horman <redacted>
---
 drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c  |  2 +-
 .../ethernet/mellanox/mlx5/core/en/rep/tc.c   |  3 ++
 .../ethernet/netronome/nfp/flower/offload.c   |  3 ++
 include/linux/netdevice.h                     |  1 +
 include/net/flow_offload.h                    | 15 ++++++++
 include/net/pkt_cls.h                         | 15 ++++++++
 net/core/flow_offload.c                       | 26 +++++++++++++-
 net/sched/act_api.c                           | 33 +++++++++++++++++
 net/sched/cls_api.c                           | 36 ++++++++++++++++---
 9 files changed, 128 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
index 5e4429b14b8c..edbbf7b4df77 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
@@ -1951,7 +1951,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) {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
index 059799e4f483..111daacc4cc3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
@@ -486,6 +486,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,
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c
index 2406d33356ad..88bbc86347b4 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c
@@ -1869,6 +1869,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;
 
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 42f6f866d5f3..b138219baf6f 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -923,6 +923,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
diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
index 69c9eabf8325..26644596fd54 100644
--- a/include/net/flow_offload.h
+++ b/include/net/flow_offload.h
@@ -553,6 +553,21 @@ struct flow_cls_offload {
 	u32 classid;
 };
 
+enum flow_act_command {
+	FLOW_ACT_REPLACE,
+	FLOW_ACT_DESTROY,
+	FLOW_ACT_STATS,
+};
+
+struct flow_offload_action {
+	struct netlink_ext_ack *extack;
+	enum flow_act_command command;
+	struct flow_stats stats;
+	struct flow_action action;
+};
+
+struct flow_offload_action *flow_action_alloc(unsigned int num_actions);
+
 static inline struct flow_rule *
 flow_cls_offload_flow_rule(struct flow_cls_offload *flow_cmd)
 {
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index ec7823921bd2..cd4cf6b10f5d 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -266,6 +266,9 @@ 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,
@@ -536,8 +539,19 @@ tcf_match_indev(struct sk_buff *skb, int ifindex)
 	return ifindex == skb->skb_iif;
 }
 
+#ifdef CONFIG_NET_CLS_ACT
 int tc_setup_flow_action(struct flow_action *flow_action,
 			 const struct tcf_exts *exts);
+#else
+static inline int tc_setup_flow_action(struct flow_action *flow_action,
+				       const struct tcf_exts *exts)
+{
+		return 0;
+}
+#endif
+
+int tc_setup_action(struct flow_action *flow_action,
+		    struct tc_action *actions[]);
 void tc_cleanup_flow_action(struct flow_action *flow_action);
 
 int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type,
@@ -558,6 +572,7 @@ int tc_setup_cb_reoffload(struct tcf_block *block, struct tcf_proto *tp,
 			  enum tc_setup_type type, void *type_data,
 			  void *cb_priv, u32 *flags, unsigned int *in_hw_count);
 unsigned int tcf_exts_num_actions(struct tcf_exts *exts);
+unsigned int tcf_act_num_actions(struct tc_action *actions[]);
 
 #ifdef CONFIG_NET_CLS_ACT
 int tcf_qevent_init(struct tcf_qevent *qe, struct Qdisc *sch,
diff --git a/net/core/flow_offload.c b/net/core/flow_offload.c
index 715b67f6c62f..0fa2f75cc9b3 100644
--- a/net/core/flow_offload.c
+++ b/net/core/flow_offload.c
@@ -27,6 +27,27 @@ struct flow_rule *flow_rule_alloc(unsigned int num_actions)
 }
 EXPORT_SYMBOL(flow_rule_alloc);
 
+struct flow_offload_action *flow_action_alloc(unsigned int num_actions)
+{
+	struct flow_offload_action *fl_action;
+	int i;
+
+	fl_action = kzalloc(struct_size(fl_action, action.entries, num_actions),
+			    GFP_KERNEL);
+	if (!fl_action)
+		return NULL;
+
+	fl_action->action.num_entries = num_actions;
+	/* Pre-fill each action hw_stats with DONT_CARE.
+	 * Caller can override this if it wants stats for a given action.
+	 */
+	for (i = 0; i < num_actions; i++)
+		fl_action->action.entries[i].hw_stats = FLOW_ACTION_HW_STATS_DONT_CARE;
+
+	return fl_action;
+}
+EXPORT_SYMBOL(flow_action_alloc);
+
 #define FLOW_DISSECTOR_MATCH(__rule, __type, __out)				\
 	const struct flow_match *__m = &(__rule)->match;			\
 	struct flow_dissector *__d = (__m)->dissector;				\
@@ -476,6 +497,9 @@ int flow_indr_dev_setup_offload(struct net_device *dev, struct Qdisc *sch,
 
 	mutex_unlock(&flow_indr_block_lock);
 
-	return list_empty(&bo->cb_list) ? -EOPNOTSUPP : 0;
+	if (bo)
+		return list_empty(&bo->cb_list) ? -EOPNOTSUPP : 0;
+	else
+		return 0;
 }
 EXPORT_SYMBOL(flow_indr_dev_setup_offload);
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 998a2374f7ae..185f17ea60d5 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -1060,6 +1060,36 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
 	return ERR_PTR(err);
 }
 
+/* offload the tc command after inserted */
+int tcf_action_offload_cmd(struct tc_action *actions[],
+			   struct netlink_ext_ack *extack)
+{
+	struct flow_offload_action *fl_act;
+	int err = 0;
+
+	fl_act = flow_action_alloc(tcf_act_num_actions(actions));
+	if (!fl_act)
+		return -ENOMEM;
+
+	fl_act->extack = extack;
+	err = tc_setup_action(&fl_act->action, actions);
+	if (err) {
+		NL_SET_ERR_MSG_MOD(extack,
+				   "Failed to setup tc actions for offload\n");
+		goto err_out;
+	}
+	fl_act->command = FLOW_ACT_REPLACE;
+
+	flow_indr_dev_setup_offload(NULL, NULL, TC_SETUP_ACT, fl_act, NULL, NULL);
+
+	tc_cleanup_flow_action(&fl_act->action);
+
+err_out:
+	kfree(fl_act);
+	return err;
+}
+EXPORT_SYMBOL(tcf_action_offload_cmd);
+
 /* Returns numbers of initialized actions or negative error. */
 
 int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
@@ -1514,6 +1544,9 @@ static int tcf_action_add(struct net *net, struct nlattr *nla,
 		return ret;
 	ret = tcf_add_notify(net, n, actions, portid, attr_size, extack);
 
+	/* offload actions to hardware if possible */
+	tcf_action_offload_cmd(actions, extack);
+
I think this has already been suggested for RFC, but some sort of
visibility for offload status of action would be extremely welcome.
Perhaps "IN_HW" flag and counter, similar to what we have for offloaded
filters.
quoted hunk
 	/* only put existing actions */
 	for (i = 0; i < TCA_ACT_MAX_PRIO; i++)
 		if (init_res[i] == ACT_P_CREATED)
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index c8cb59a11098..9b9770dab5e8 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -3544,8 +3544,8 @@ static enum flow_action_hw_stats tc_act_hw_stats(u8 hw_stats)
 	return hw_stats;
 }
 
-int tc_setup_flow_action(struct flow_action *flow_action,
-			 const struct tcf_exts *exts)
+int tc_setup_action(struct flow_action *flow_action,
+		    struct tc_action *actions[])
 {
 	struct tc_action *act;
 	int i, j, k, err = 0;
@@ -3554,11 +3554,11 @@ int tc_setup_flow_action(struct flow_action *flow_action,
 	BUILD_BUG_ON(TCA_ACT_HW_STATS_IMMEDIATE != FLOW_ACTION_HW_STATS_IMMEDIATE);
 	BUILD_BUG_ON(TCA_ACT_HW_STATS_DELAYED != FLOW_ACTION_HW_STATS_DELAYED);
 
-	if (!exts)
+	if (!actions)
 		return 0;
 
 	j = 0;
-	tcf_exts_for_each_action(i, act, exts) {
+	tcf_act_for_each_action(i, act, actions) {
 		struct flow_action_entry *entry;
 
 		entry = &flow_action->entries[j];
@@ -3725,7 +3725,19 @@ int tc_setup_flow_action(struct flow_action *flow_action,
 	spin_unlock_bh(&act->tcfa_lock);
 	goto err_out;
 }
+EXPORT_SYMBOL(tc_setup_action);
+
+#ifdef CONFIG_NET_CLS_ACT
+int tc_setup_flow_action(struct flow_action *flow_action,
+			 const struct tcf_exts *exts)
+{
+	if (!exts)
+		return 0;
+
+	return tc_setup_action(flow_action, exts->actions);
+}
 EXPORT_SYMBOL(tc_setup_flow_action);
+#endif
 
 unsigned int tcf_exts_num_actions(struct tcf_exts *exts)
 {
@@ -3743,6 +3755,22 @@ unsigned int tcf_exts_num_actions(struct tcf_exts *exts)
 }
 EXPORT_SYMBOL(tcf_exts_num_actions);
 
+unsigned int tcf_act_num_actions(struct tc_action *actions[])
+{
+	unsigned int num_acts = 0;
+	struct tc_action *act;
+	int i;
+
+	tcf_act_for_each_action(i, act, actions) {
+		if (is_tcf_pedit(act))
+			num_acts += tcf_pedit_nkeys(act);
+		else
+			num_acts++;
+	}
+	return num_acts;
+}
+EXPORT_SYMBOL(tcf_act_num_actions);
+
 #ifdef CONFIG_NET_CLS_ACT
 static int tcf_qevent_parse_block_index(struct nlattr *block_index_attr,
 					u32 *p_block_index,

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Jamal Hadi Salim <jhs@mojatatu.com>
Date: 2021-07-22 13:33:18

On 2021-07-22 9:29 a.m., Vlad Buslov wrote:
On Thu 22 Jul 2021 at 12:19, Simon Horman [off-list ref] wrote:
quoted
From: Baowen Zheng <redacted>

Use flow_indr_dev_register/flow_indr_dev_setup_offload to
offload tc action.

We offload the tc action mainly for ovs meter configuration.
Make some basic changes for different vendors to return EOPNOTSUPP.

We need to call tc_cleanup_flow_action to clean up tc action entry since
in tc_setup_action, some actions may hold dev refcnt, especially the mirror
action.

As per review from the RFC, the kernel test robot will fail to run, so
we add CONFIG_NET_CLS_ACT control for the action offload.

Signed-off-by: Baowen Zheng <redacted>
Signed-off-by: Louis Peens <redacted>
Signed-off-by: Simon Horman <redacted>
---
  drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c  |  2 +-
  .../ethernet/mellanox/mlx5/core/en/rep/tc.c   |  3 ++
quoted
  			    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,
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c
[..]
quoted
  
+	/* offload actions to hardware if possible */
+	tcf_action_offload_cmd(actions, extack);
+
I think this has already been suggested for RFC, but some sort of
visibility for offload status of action would be extremely welcome.
Perhaps "IN_HW" flag and counter, similar to what we have for offloaded
filters.
Also showing a tc command line in the cover letter on how one would
ask for a specific action to be offloaded.

cheers,
jamal

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: kernel test robot <hidden>
Date: 2021-07-22 13:58:45

Hi Simon,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]

url:    https://github.com/0day-ci/linux/commits/Simon-Horman/flow_offload-hardware-offload-of-TC-actions/20210722-172229
base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git c2255ff47768c94a0ebc3968f007928bb47ea43b
config: microblaze-randconfig-r011-20210722 (attached as .config)
compiler: microblaze-linux-gcc (GCC) 10.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/9228a8efdbf7a736354b87c0db3260dd7d2c4abd
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Simon-Horman/flow_offload-hardware-offload-of-TC-actions/20210722-172229
        git checkout 9228a8efdbf7a736354b87c0db3260dd7d2c4abd
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-10.3.0 make.cross ARCH=microblaze 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <redacted>

All warnings (new ones prefixed by >>):
quoted
net/sched/act_api.c:1064:5: warning: no previous prototype for 'tcf_action_offload_cmd' [-Wmissing-prototypes]
    1064 | int tcf_action_offload_cmd(struct tc_action *actions[],
         |     ^~~~~~~~~~~~~~~~~~~~~~


vim +/tcf_action_offload_cmd +1064 net/sched/act_api.c

  1062	
  1063	/* offload the tc command after inserted */
1064	int tcf_action_offload_cmd(struct tc_action *actions[],
  1065				   struct netlink_ext_ack *extack)
  1066	{
  1067		struct flow_offload_action *fl_act;
  1068		int err = 0;
  1069	
  1070		fl_act = flow_action_alloc(tcf_act_num_actions(actions));
  1071		if (!fl_act)
  1072			return -ENOMEM;
  1073	
  1074		fl_act->extack = extack;
  1075		err = tc_setup_action(&fl_act->action, actions);
  1076		if (err) {
  1077			NL_SET_ERR_MSG_MOD(extack,
  1078					   "Failed to setup tc actions for offload\n");
  1079			goto err_out;
  1080		}
  1081		fl_act->command = FLOW_ACT_REPLACE;
  1082	
  1083		flow_indr_dev_setup_offload(NULL, NULL, TC_SETUP_ACT, fl_act, NULL, NULL);
  1084	
  1085		tc_cleanup_flow_action(&fl_act->action);
  1086	
  1087	err_out:
  1088		kfree(fl_act);
  1089		return err;
  1090	}
  1091	EXPORT_SYMBOL(tcf_action_offload_cmd);
  1092	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

Re: [PATCH net-next 2/3] flow_offload: add process to delete offloaded actions from net device

From: Vlad Buslov <hidden>
Date: 2021-07-22 14:25:25

On Thu 22 Jul 2021 at 12:19, Simon Horman [off-list ref] wrote:
quoted hunk
From: Baowen Zheng <redacted>

Add a basic process to delete offloaded actions from net device.

Should not remove the offloaded action entries if the action
fails to delete in tcf_del_notify.

Signed-off-by: Baowen Zheng <redacted>
Signed-off-by: Louis Peens <redacted>
Signed-off-by: Simon Horman <redacted>
---
 include/net/pkt_cls.h |   1 +
 net/sched/act_api.c   | 112 +++++++++++++++++++++++++++++++++++-------
 net/sched/cls_api.c   |  14 ++++--
 3 files changed, 106 insertions(+), 21 deletions(-)
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index cd4cf6b10f5d..03dae225d64f 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -573,6 +573,7 @@ int tc_setup_cb_reoffload(struct tcf_block *block, struct tcf_proto *tp,
 			  void *cb_priv, u32 *flags, unsigned int *in_hw_count);
 unsigned int tcf_exts_num_actions(struct tcf_exts *exts);
 unsigned int tcf_act_num_actions(struct tc_action *actions[]);
+unsigned int tcf_act_num_actions_single(struct tc_action *act);
 
 #ifdef CONFIG_NET_CLS_ACT
 int tcf_qevent_init(struct tcf_qevent *qe, struct Qdisc *sch,
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 185f17ea60d5..23a4538916af 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -1060,36 +1060,109 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
 	return ERR_PTR(err);
 }
 
-/* offload the tc command after inserted */
-int tcf_action_offload_cmd(struct tc_action *actions[],
-			   struct netlink_ext_ack *extack)
+int tcf_action_offload_cmd_pre(struct tc_action *actions[],
+			       enum flow_act_command cmd,
+			       struct netlink_ext_ack *extack,
+			       struct flow_offload_action **fl_act)
 {
-	struct flow_offload_action *fl_act;
+	struct flow_offload_action *fl_act_p;
 	int err = 0;
 
-	fl_act = flow_action_alloc(tcf_act_num_actions(actions));
-	if (!fl_act)
+	fl_act_p = flow_action_alloc(tcf_act_num_actions(actions));
+	if (!fl_act_p)
 		return -ENOMEM;
 
-	fl_act->extack = extack;
-	err = tc_setup_action(&fl_act->action, actions);
+	fl_act_p->extack = extack;
+	fl_act_p->command = cmd;
+	err = tc_setup_action(&fl_act_p->action, actions);
 	if (err) {
 		NL_SET_ERR_MSG_MOD(extack,
 				   "Failed to setup tc actions for offload\n");
 		goto err_out;
 	}
-	fl_act->command = FLOW_ACT_REPLACE;
+	*fl_act = fl_act_p;
+	return 0;
+err_out:
+	kfree(fl_act_p);
+	return err;
+}
+EXPORT_SYMBOL(tcf_action_offload_cmd_pre);
This doesn't seem be used anywhere outside this file.
+
+int tcf_action_offload_cmd_post(struct flow_offload_action *fl_act,
+				struct netlink_ext_ack *extack)
+{
+	if (IS_ERR(fl_act))
+		return PTR_ERR(fl_act);
 
 	flow_indr_dev_setup_offload(NULL, NULL, TC_SETUP_ACT, fl_act, NULL, NULL);
 
 	tc_cleanup_flow_action(&fl_act->action);
-
-err_out:
 	kfree(fl_act);
-	return err;
+	return 0;
+}
This one is not exported, by is non-static.
quoted hunk
+
+/* offload the tc command after inserted */
+int tcf_action_offload_cmd(struct tc_action *actions[],
+			   struct netlink_ext_ack *extack)
+{
+	struct flow_offload_action *fl_act;
+	int err = 0;
+
+	err = tcf_action_offload_cmd_pre(actions,
+					 FLOW_ACT_REPLACE,
+					 extack,
+					 &fl_act);
+	if (err)
+		return err;
+
+	return tcf_action_offload_cmd_post(fl_act, extack);
 }
 EXPORT_SYMBOL(tcf_action_offload_cmd);
 
+/* offload the tc command after deleted */
+int tcf_action_offload_del_post(struct flow_offload_action *fl_act,
+				struct tc_action *actions[],
+				struct netlink_ext_ack *extack,
+				int fallback_num)
+{
+	int fallback_entries = 0;
+	struct tc_action *act;
+	int total_entries = 0;
+	int i;
+
+	if (!fl_act)
+		return -EINVAL;
+
+	if (fallback_num) {
+		/* for each the actions to fallback the action entries remain in the actions */
+		for (i = 0; i < TCA_ACT_MAX_PRIO; i++) {
+			act = actions[i];
+			if (!act)
+				continue;
+
+			fallback_entries += tcf_act_num_actions_single(act);
+		}
+		fallback_entries += fallback_num;
+	}
+	total_entries = fl_act->action.num_entries;
+	if (total_entries > fallback_entries) {
+		/* just offload the actions that is not fallback and start with the actions */
+		fl_act->action.num_entries -= fallback_entries;
+		flow_indr_dev_setup_offload(NULL, NULL, TC_SETUP_ACT, fl_act, NULL, NULL);
+
+		/* recovery num_entries for cleanup */
+		fl_act->action.num_entries = total_entries;
+	} else {
+		NL_SET_ERR_MSG(extack, "no entries to offload when deleting the tc actions");
+	}
+
+	tc_cleanup_flow_action(&fl_act->action);
+
+	kfree(fl_act);
+	return 0;
+}
+EXPORT_SYMBOL(tcf_action_offload_del_post);
+
 /* Returns numbers of initialized actions or negative error. */
 
 int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
@@ -1393,7 +1466,7 @@ static int tca_action_flush(struct net *net, struct nlattr *nla,
 	return err;
 }
 
-static int tcf_action_delete(struct net *net, struct tc_action *actions[])
+static int tcf_action_delete(struct net *net, struct tc_action *actions[], int *fallbacknum)
 {
 	int i;
 
@@ -1407,6 +1480,7 @@ static int tcf_action_delete(struct net *net, struct tc_action *actions[])
 		u32 act_index = a->tcfa_index;
 
 		actions[i] = NULL;
+		*fallbacknum = tcf_act_num_actions_single(a);
 		if (tcf_action_put(a)) {
 			/* last reference, action was deleted concurrently */
 			module_put(ops->owner);
@@ -1419,12 +1493,13 @@ static int tcf_action_delete(struct net *net, struct tc_action *actions[])
 				return ret;
 		}
 	}
+	*fallbacknum = 0;
 	return 0;
 }
 
 static int
 tcf_del_notify(struct net *net, struct nlmsghdr *n, struct tc_action *actions[],
-	       u32 portid, size_t attr_size, struct netlink_ext_ack *extack)
+	       u32 portid, size_t attr_size, struct netlink_ext_ack *extack, int *fallbacknum)
 {
 	int ret;
 	struct sk_buff *skb;
@@ -1442,7 +1517,7 @@ tcf_del_notify(struct net *net, struct nlmsghdr *n, struct tc_action *actions[],
 	}
 
 	/* now do the delete */
-	ret = tcf_action_delete(net, actions);
+	ret = tcf_action_delete(net, actions, fallbacknum);
 	if (ret < 0) {
 		NL_SET_ERR_MSG(extack, "Failed to delete TC action");
 		kfree_skb(skb);
@@ -1458,11 +1533,12 @@ static int
 tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
 	      u32 portid, int event, struct netlink_ext_ack *extack)
 {
-	int i, ret;
 	struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
 	struct tc_action *act;
 	size_t attr_size = 0;
 	struct tc_action *actions[TCA_ACT_MAX_PRIO] = {};
+	struct flow_offload_action *fl_act;
+	int i, ret, fallback_num;
 
 	ret = nla_parse_nested_deprecated(tb, TCA_ACT_MAX_PRIO, nla, NULL,
 					  extack);
@@ -1492,7 +1568,9 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
 	if (event == RTM_GETACTION)
 		ret = tcf_get_notify(net, portid, n, actions, event, extack);
 	else { /* delete */
-		ret = tcf_del_notify(net, n, actions, portid, attr_size, extack);
+		tcf_action_offload_cmd_pre(actions, FLOW_ACT_DESTROY, extack, &fl_act);
+		ret = tcf_del_notify(net, n, actions, portid, attr_size, extack, &fallback_num);
+		tcf_action_offload_del_post(fl_act, actions, extack, fallback_num);
This tcf_action_offload_cmd_{pre|post}() approach looks slightly
complicated, especially with fallback_num calculations. I would suggest
to simplify it by only initializing action cookies in
flow_action->entries[] (I assume you don't really need all the action
data just to delete it, right?) for DEL/STATS and do one of the
following:

- Unoffload actions one-by-one after every deletion in
  tcf_actions_delete(), perhaps reusing the same flow_offload_action of
  size 1 by only changing the cookie on each iteration.

- If you really want to send the whole batch to the driver, save cookies
  for all successfully deleted actions in an array and initialize
  compound flow_offload_action from the array.

This would remove the need for whole pre/post thing, which otherwise
gets even more complicated in following patch by 'keep_fl_act' arg.
quoted hunk
 		if (ret)
 			goto err;
 		return 0;
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 9b9770dab5e8..23ce021f07f8 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -3755,6 +3755,15 @@ unsigned int tcf_exts_num_actions(struct tcf_exts *exts)
 }
 EXPORT_SYMBOL(tcf_exts_num_actions);
 
+unsigned int tcf_act_num_actions_single(struct tc_action *act)
+{
+	if (is_tcf_pedit(act))
+		return tcf_pedit_nkeys(act);
+	else
+		return 1;
+}
+EXPORT_SYMBOL(tcf_act_num_actions_single);
+
 unsigned int tcf_act_num_actions(struct tc_action *actions[])
 {
 	unsigned int num_acts = 0;
@@ -3762,10 +3771,7 @@ unsigned int tcf_act_num_actions(struct tc_action *actions[])
 	int i;
 
 	tcf_act_for_each_action(i, act, actions) {
-		if (is_tcf_pedit(act))
-			num_acts += tcf_pedit_nkeys(act);
-		else
-			num_acts++;
+		num_acts += tcf_act_num_actions_single(act);
 	}
 	return num_acts;
 }

Re: [PATCH net-next 2/3] flow_offload: add process to delete offloaded actions from net device

From: kernel test robot <hidden>
Date: 2021-07-22 14:50:54

Hi Simon,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]

url:    https://github.com/0day-ci/linux/commits/Simon-Horman/flow_offload-hardware-offload-of-TC-actions/20210722-172229
base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git c2255ff47768c94a0ebc3968f007928bb47ea43b
config: microblaze-randconfig-r011-20210722 (attached as .config)
compiler: microblaze-linux-gcc (GCC) 10.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/a8e2d0acfc98c127ab0b5189f7635049515c43f3
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Simon-Horman/flow_offload-hardware-offload-of-TC-actions/20210722-172229
        git checkout a8e2d0acfc98c127ab0b5189f7635049515c43f3
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-10.3.0 make.cross ARCH=microblaze 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <redacted>

All warnings (new ones prefixed by >>):
quoted
net/sched/act_api.c:1063:5: warning: no previous prototype for 'tcf_action_offload_cmd_pre' [-Wmissing-prototypes]
    1063 | int tcf_action_offload_cmd_pre(struct tc_action *actions[],
         |     ^~~~~~~~~~~~~~~~~~~~~~~~~~
quoted
net/sched/act_api.c:1091:5: warning: no previous prototype for 'tcf_action_offload_cmd_post' [-Wmissing-prototypes]
    1091 | int tcf_action_offload_cmd_post(struct flow_offload_action *fl_act,
         |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   net/sched/act_api.c:1105:5: warning: no previous prototype for 'tcf_action_offload_cmd' [-Wmissing-prototypes]
    1105 | int tcf_action_offload_cmd(struct tc_action *actions[],
         |     ^~~~~~~~~~~~~~~~~~~~~~
quoted
net/sched/act_api.c:1123:5: warning: no previous prototype for 'tcf_action_offload_del_post' [-Wmissing-prototypes]
    1123 | int tcf_action_offload_del_post(struct flow_offload_action *fl_act,
         |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~


vim +/tcf_action_offload_cmd_pre +1063 net/sched/act_api.c

  1062	
1063	int tcf_action_offload_cmd_pre(struct tc_action *actions[],
  1064				       enum flow_act_command cmd,
  1065				       struct netlink_ext_ack *extack,
  1066				       struct flow_offload_action **fl_act)
  1067	{
  1068		struct flow_offload_action *fl_act_p;
  1069		int err = 0;
  1070	
  1071		fl_act_p = flow_action_alloc(tcf_act_num_actions(actions));
  1072		if (!fl_act_p)
  1073			return -ENOMEM;
  1074	
  1075		fl_act_p->extack = extack;
  1076		fl_act_p->command = cmd;
  1077		err = tc_setup_action(&fl_act_p->action, actions);
  1078		if (err) {
  1079			NL_SET_ERR_MSG_MOD(extack,
  1080					   "Failed to setup tc actions for offload\n");
  1081			goto err_out;
  1082		}
  1083		*fl_act = fl_act_p;
  1084		return 0;
  1085	err_out:
  1086		kfree(fl_act_p);
  1087		return err;
  1088	}
  1089	EXPORT_SYMBOL(tcf_action_offload_cmd_pre);
  1090	
1091	int tcf_action_offload_cmd_post(struct flow_offload_action *fl_act,
  1092					struct netlink_ext_ack *extack)
  1093	{
  1094		if (IS_ERR(fl_act))
  1095			return PTR_ERR(fl_act);
  1096	
  1097		flow_indr_dev_setup_offload(NULL, NULL, TC_SETUP_ACT, fl_act, NULL, NULL);
  1098	
  1099		tc_cleanup_flow_action(&fl_act->action);
  1100		kfree(fl_act);
  1101		return 0;
  1102	}
  1103	
  1104	/* offload the tc command after inserted */
  1105	int tcf_action_offload_cmd(struct tc_action *actions[],
  1106				   struct netlink_ext_ack *extack)
  1107	{
  1108		struct flow_offload_action *fl_act;
  1109		int err = 0;
  1110	
  1111		err = tcf_action_offload_cmd_pre(actions,
  1112						 FLOW_ACT_REPLACE,
  1113						 extack,
  1114						 &fl_act);
  1115		if (err)
  1116			return err;
  1117	
  1118		return tcf_action_offload_cmd_post(fl_act, extack);
  1119	}
  1120	EXPORT_SYMBOL(tcf_action_offload_cmd);
  1121	
  1122	/* offload the tc command after deleted */
1123	int tcf_action_offload_del_post(struct flow_offload_action *fl_act,
  1124					struct tc_action *actions[],
  1125					struct netlink_ext_ack *extack,
  1126					int fallback_num)
  1127	{
  1128		int fallback_entries = 0;
  1129		struct tc_action *act;
  1130		int total_entries = 0;
  1131		int i;
  1132	
  1133		if (!fl_act)
  1134			return -EINVAL;
  1135	
  1136		if (fallback_num) {
  1137			/* for each the actions to fallback the action entries remain in the actions */
  1138			for (i = 0; i < TCA_ACT_MAX_PRIO; i++) {
  1139				act = actions[i];
  1140				if (!act)
  1141					continue;
  1142	
  1143				fallback_entries += tcf_act_num_actions_single(act);
  1144			}
  1145			fallback_entries += fallback_num;
  1146		}
  1147		total_entries = fl_act->action.num_entries;
  1148		if (total_entries > fallback_entries) {
  1149			/* just offload the actions that is not fallback and start with the actions */
  1150			fl_act->action.num_entries -= fallback_entries;
  1151			flow_indr_dev_setup_offload(NULL, NULL, TC_SETUP_ACT, fl_act, NULL, NULL);
  1152	
  1153			/* recovery num_entries for cleanup */
  1154			fl_act->action.num_entries = total_entries;
  1155		} else {
  1156			NL_SET_ERR_MSG(extack, "no entries to offload when deleting the tc actions");
  1157		}
  1158	
  1159		tc_cleanup_flow_action(&fl_act->action);
  1160	
  1161		kfree(fl_act);
  1162		return 0;
  1163	}
  1164	EXPORT_SYMBOL(tcf_action_offload_del_post);
  1165	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

Re: [PATCH net-next 3/3] flow_offload: add process to update action stats from hardware

From: Vlad Buslov <hidden>
Date: 2021-07-22 14:59:31

On Thu 22 Jul 2021 at 12:19, Simon Horman [off-list ref] wrote:
quoted hunk
From: Baowen Zheng <redacted>

When collecting stats for actions update them using both
both hardware and software counters.

Signed-off-by: Baowen Zheng <redacted>
Signed-off-by: Louis Peens <redacted>
Signed-off-by: Simon Horman <redacted>
---
 include/net/act_api.h      |  1 +
 include/net/flow_offload.h |  2 +-
 include/net/pkt_cls.h      |  4 ++++
 net/sched/act_api.c        | 49 ++++++++++++++++++++++++++++++++++----
 4 files changed, 51 insertions(+), 5 deletions(-)
diff --git a/include/net/act_api.h b/include/net/act_api.h
index 086b291e9530..fe8331b5efce 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -233,6 +233,7 @@ static inline void tcf_action_inc_overlimit_qstats(struct tc_action *a)
 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_check_ctrlact(int action, struct tcf_proto *tp,
 			     struct tcf_chain **handle,
diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
index 26644596fd54..467688fff7ce 100644
--- a/include/net/flow_offload.h
+++ b/include/net/flow_offload.h
@@ -560,7 +560,7 @@ enum flow_act_command {
 };
 
 struct flow_offload_action {
-	struct netlink_ext_ack *extack;
+	struct netlink_ext_ack *extack; /* NULL in FLOW_ACT_STATS process*/
 	enum flow_act_command command;
 	struct flow_stats stats;
 	struct flow_action action;
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index 03dae225d64f..569c9294b15b 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -282,6 +282,10 @@ tcf_exts_stats_update(const struct tcf_exts *exts,
 	for (i = 0; i < exts->nr_actions; i++) {
 		struct tc_action *a = exts->actions[i];
 
+		/* if stats from hw, just skip */
+		if (!tcf_action_update_hw_stats(a))
+			continue;
+
Is it okay to call this inside preempt disable section?
quoted hunk
 		tcf_action_stats_update(a, bytes, packets, drops,
 					lastuse, true);
 		a->used_hw_stats = used_hw_stats;
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 23a4538916af..7d5535bc2c13 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -1089,15 +1089,18 @@ int tcf_action_offload_cmd_pre(struct tc_action *actions[],
 EXPORT_SYMBOL(tcf_action_offload_cmd_pre);
 
 int tcf_action_offload_cmd_post(struct flow_offload_action *fl_act,
-				struct netlink_ext_ack *extack)
+				struct netlink_ext_ack *extack,
+				bool keep_fl_act)
 {
 	if (IS_ERR(fl_act))
 		return PTR_ERR(fl_act);
 
 	flow_indr_dev_setup_offload(NULL, NULL, TC_SETUP_ACT, fl_act, NULL, NULL);
 
-	tc_cleanup_flow_action(&fl_act->action);
-	kfree(fl_act);
+	if (!keep_fl_act) {
+		tc_cleanup_flow_action(&fl_act->action);
+		kfree(fl_act);
+	}
 	return 0;
 }
 
@@ -1115,10 +1118,45 @@ int tcf_action_offload_cmd(struct tc_action *actions[],
 	if (err)
 		return err;
 
-	return tcf_action_offload_cmd_post(fl_act, extack);
+	return tcf_action_offload_cmd_post(fl_act, extack, false);
 }
 EXPORT_SYMBOL(tcf_action_offload_cmd);
 
+int tcf_action_update_hw_stats(struct tc_action *action)
+{
+	struct tc_action *actions[TCA_ACT_MAX_PRIO] = {
+		[0] = action,
+	};
+	struct flow_offload_action *fl_act;
+	int err = 0;
+
Having some way to distinguish offloaded actions would also be useful
here to skip this function. I wonder how this affects dump rate when
executed for every single action, even when none of them were offloaded
through action API.
quoted hunk
+	err = tcf_action_offload_cmd_pre(actions,
+					 FLOW_ACT_STATS,
+					 NULL,
+					 &fl_act);
+	if (err)
+		goto err_out;
+
+	err = tcf_action_offload_cmd_post(fl_act, NULL, true);
+
+	if (fl_act->stats.lastused) {
+		tcf_action_stats_update(action, fl_act->stats.bytes,
+					fl_act->stats.pkts,
+					fl_act->stats.drops,
+					fl_act->stats.lastused,
+					true);
+		err = 0;
+	} else {
+		err = -EOPNOTSUPP;
+	}
+	tc_cleanup_flow_action(&fl_act->action);
+	kfree(fl_act);
+
+err_out:
+	return err;
+}
+EXPORT_SYMBOL(tcf_action_update_hw_stats);
+
 /* offload the tc command after deleted */
 int tcf_action_offload_del_post(struct flow_offload_action *fl_act,
 				struct tc_action *actions[],
@@ -1255,6 +1293,9 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *p,
 	if (p == NULL)
 		goto errout;
 
+	/* update hw stats for this action */
+	tcf_action_update_hw_stats(p);
+
 	/* compat_mode being true specifies a call that is supposed
 	 * to add additional backward compatibility statistic TLVs.
 	 */

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: kernel test robot <hidden>
Date: 2021-07-22 15:31:58

Hi Simon,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]

url:    https://github.com/0day-ci/linux/commits/Simon-Horman/flow_offload-hardware-offload-of-TC-actions/20210722-172229
base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git c2255ff47768c94a0ebc3968f007928bb47ea43b
config: powerpc-randconfig-r016-20210722 (attached as .config)
compiler: clang version 13.0.0 (https://github.com/llvm/llvm-project 9625ca5b602616b2f5584e8a49ba93c52c141e40)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install powerpc cross compiling tool for clang build
        # apt-get install binutils-powerpc-linux-gnu
        # https://github.com/0day-ci/linux/commit/9228a8efdbf7a736354b87c0db3260dd7d2c4abd
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Simon-Horman/flow_offload-hardware-offload-of-TC-actions/20210722-172229
        git checkout 9228a8efdbf7a736354b87c0db3260dd7d2c4abd
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=powerpc 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <redacted>

All warnings (new ones prefixed by >>):

   In file included from include/linux/dma-mapping.h:10:
   In file included from include/linux/scatterlist.h:9:
   In file included from arch/powerpc/include/asm/io.h:619:
   arch/powerpc/include/asm/io-defs.h:43:1: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
   DEF_PCI_AC_NORET(insb, (unsigned long p, void *b, unsigned long c),
   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   arch/powerpc/include/asm/io.h:616:3: note: expanded from macro 'DEF_PCI_AC_NORET'
                   __do_##name al;                                 \
                   ^~~~~~~~~~~~~~
   <scratch space>:238:1: note: expanded from here
   __do_insb
   ^
   arch/powerpc/include/asm/io.h:556:56: note: expanded from macro '__do_insb'
   #define __do_insb(p, b, n)      readsb((PCI_IO_ADDR)_IO_BASE+(p), (b), (n))
                                          ~~~~~~~~~~~~~~~~~~~~~^
   In file included from net/sched/act_api.c:13:
   In file included from include/linux/skbuff.h:31:
   In file included from include/linux/dma-mapping.h:10:
   In file included from include/linux/scatterlist.h:9:
   In file included from arch/powerpc/include/asm/io.h:619:
   arch/powerpc/include/asm/io-defs.h:45:1: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
   DEF_PCI_AC_NORET(insw, (unsigned long p, void *b, unsigned long c),
   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   arch/powerpc/include/asm/io.h:616:3: note: expanded from macro 'DEF_PCI_AC_NORET'
                   __do_##name al;                                 \
                   ^~~~~~~~~~~~~~
   <scratch space>:2:1: note: expanded from here
   __do_insw
   ^
   arch/powerpc/include/asm/io.h:557:56: note: expanded from macro '__do_insw'
   #define __do_insw(p, b, n)      readsw((PCI_IO_ADDR)_IO_BASE+(p), (b), (n))
                                          ~~~~~~~~~~~~~~~~~~~~~^
   In file included from net/sched/act_api.c:13:
   In file included from include/linux/skbuff.h:31:
   In file included from include/linux/dma-mapping.h:10:
   In file included from include/linux/scatterlist.h:9:
   In file included from arch/powerpc/include/asm/io.h:619:
   arch/powerpc/include/asm/io-defs.h:47:1: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
   DEF_PCI_AC_NORET(insl, (unsigned long p, void *b, unsigned long c),
   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   arch/powerpc/include/asm/io.h:616:3: note: expanded from macro 'DEF_PCI_AC_NORET'
                   __do_##name al;                                 \
                   ^~~~~~~~~~~~~~
   <scratch space>:4:1: note: expanded from here
   __do_insl
   ^
   arch/powerpc/include/asm/io.h:558:56: note: expanded from macro '__do_insl'
   #define __do_insl(p, b, n)      readsl((PCI_IO_ADDR)_IO_BASE+(p), (b), (n))
                                          ~~~~~~~~~~~~~~~~~~~~~^
   In file included from net/sched/act_api.c:13:
   In file included from include/linux/skbuff.h:31:
   In file included from include/linux/dma-mapping.h:10:
   In file included from include/linux/scatterlist.h:9:
   In file included from arch/powerpc/include/asm/io.h:619:
   arch/powerpc/include/asm/io-defs.h:49:1: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
   DEF_PCI_AC_NORET(outsb, (unsigned long p, const void *b, unsigned long c),
   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   arch/powerpc/include/asm/io.h:616:3: note: expanded from macro 'DEF_PCI_AC_NORET'
                   __do_##name al;                                 \
                   ^~~~~~~~~~~~~~
   <scratch space>:6:1: note: expanded from here
   __do_outsb
   ^
   arch/powerpc/include/asm/io.h:559:58: note: expanded from macro '__do_outsb'
   #define __do_outsb(p, b, n)     writesb((PCI_IO_ADDR)_IO_BASE+(p),(b),(n))
                                           ~~~~~~~~~~~~~~~~~~~~~^
   In file included from net/sched/act_api.c:13:
   In file included from include/linux/skbuff.h:31:
   In file included from include/linux/dma-mapping.h:10:
   In file included from include/linux/scatterlist.h:9:
   In file included from arch/powerpc/include/asm/io.h:619:
   arch/powerpc/include/asm/io-defs.h:51:1: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
   DEF_PCI_AC_NORET(outsw, (unsigned long p, const void *b, unsigned long c),
   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   arch/powerpc/include/asm/io.h:616:3: note: expanded from macro 'DEF_PCI_AC_NORET'
                   __do_##name al;                                 \
                   ^~~~~~~~~~~~~~
   <scratch space>:8:1: note: expanded from here
   __do_outsw
   ^
   arch/powerpc/include/asm/io.h:560:58: note: expanded from macro '__do_outsw'
   #define __do_outsw(p, b, n)     writesw((PCI_IO_ADDR)_IO_BASE+(p),(b),(n))
                                           ~~~~~~~~~~~~~~~~~~~~~^
   In file included from net/sched/act_api.c:13:
   In file included from include/linux/skbuff.h:31:
   In file included from include/linux/dma-mapping.h:10:
   In file included from include/linux/scatterlist.h:9:
   In file included from arch/powerpc/include/asm/io.h:619:
   arch/powerpc/include/asm/io-defs.h:53:1: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
   DEF_PCI_AC_NORET(outsl, (unsigned long p, const void *b, unsigned long c),
   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   arch/powerpc/include/asm/io.h:616:3: note: expanded from macro 'DEF_PCI_AC_NORET'
                   __do_##name al;                                 \
                   ^~~~~~~~~~~~~~
   <scratch space>:10:1: note: expanded from here
   __do_outsl
   ^
   arch/powerpc/include/asm/io.h:561:58: note: expanded from macro '__do_outsl'
   #define __do_outsl(p, b, n)     writesl((PCI_IO_ADDR)_IO_BASE+(p),(b),(n))
                                           ~~~~~~~~~~~~~~~~~~~~~^
quoted
net/sched/act_api.c:1064:5: warning: no previous prototype for function 'tcf_action_offload_cmd' [-Wmissing-prototypes]
   int tcf_action_offload_cmd(struct tc_action *actions[],
       ^
   net/sched/act_api.c:1064:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int tcf_action_offload_cmd(struct tc_action *actions[],
   ^
   static 
   13 warnings generated.


vim +/tcf_action_offload_cmd +1064 net/sched/act_api.c

  1062	
  1063	/* offload the tc command after inserted */
1064	int tcf_action_offload_cmd(struct tc_action *actions[],
  1065				   struct netlink_ext_ack *extack)
  1066	{
  1067		struct flow_offload_action *fl_act;
  1068		int err = 0;
  1069	
  1070		fl_act = flow_action_alloc(tcf_act_num_actions(actions));
  1071		if (!fl_act)
  1072			return -ENOMEM;
  1073	
  1074		fl_act->extack = extack;
  1075		err = tc_setup_action(&fl_act->action, actions);
  1076		if (err) {
  1077			NL_SET_ERR_MSG_MOD(extack,
  1078					   "Failed to setup tc actions for offload\n");
  1079			goto err_out;
  1080		}
  1081		fl_act->command = FLOW_ACT_REPLACE;
  1082	
  1083		flow_indr_dev_setup_offload(NULL, NULL, TC_SETUP_ACT, fl_act, NULL, NULL);
  1084	
  1085		tc_cleanup_flow_action(&fl_act->action);
  1086	
  1087	err_out:
  1088		kfree(fl_act);
  1089		return err;
  1090	}
  1091	EXPORT_SYMBOL(tcf_action_offload_cmd);
  1092	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

Re: [PATCH net-next 2/3] flow_offload: add process to delete offloaded actions from net device

From: kernel test robot <hidden>
Date: 2021-07-22 17:08:18

Hi Simon,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]

url:    https://github.com/0day-ci/linux/commits/Simon-Horman/flow_offload-hardware-offload-of-TC-actions/20210722-172229
base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git c2255ff47768c94a0ebc3968f007928bb47ea43b
config: powerpc-randconfig-r016-20210722 (attached as .config)
compiler: clang version 13.0.0 (https://github.com/llvm/llvm-project 9625ca5b602616b2f5584e8a49ba93c52c141e40)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install powerpc cross compiling tool for clang build
        # apt-get install binutils-powerpc-linux-gnu
        # https://github.com/0day-ci/linux/commit/a8e2d0acfc98c127ab0b5189f7635049515c43f3
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Simon-Horman/flow_offload-hardware-offload-of-TC-actions/20210722-172229
        git checkout a8e2d0acfc98c127ab0b5189f7635049515c43f3
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=powerpc 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <redacted>

All warnings (new ones prefixed by >>):

   In file included from include/linux/dma-mapping.h:10:
   In file included from include/linux/scatterlist.h:9:
   In file included from arch/powerpc/include/asm/io.h:619:
   arch/powerpc/include/asm/io-defs.h:43:1: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
   DEF_PCI_AC_NORET(insb, (unsigned long p, void *b, unsigned long c),
   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   arch/powerpc/include/asm/io.h:616:3: note: expanded from macro 'DEF_PCI_AC_NORET'
                   __do_##name al;                                 \
                   ^~~~~~~~~~~~~~
   <scratch space>:238:1: note: expanded from here
   __do_insb
   ^
   arch/powerpc/include/asm/io.h:556:56: note: expanded from macro '__do_insb'
   #define __do_insb(p, b, n)      readsb((PCI_IO_ADDR)_IO_BASE+(p), (b), (n))
                                          ~~~~~~~~~~~~~~~~~~~~~^
   In file included from net/sched/act_api.c:13:
   In file included from include/linux/skbuff.h:31:
   In file included from include/linux/dma-mapping.h:10:
   In file included from include/linux/scatterlist.h:9:
   In file included from arch/powerpc/include/asm/io.h:619:
   arch/powerpc/include/asm/io-defs.h:45:1: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
   DEF_PCI_AC_NORET(insw, (unsigned long p, void *b, unsigned long c),
   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   arch/powerpc/include/asm/io.h:616:3: note: expanded from macro 'DEF_PCI_AC_NORET'
                   __do_##name al;                                 \
                   ^~~~~~~~~~~~~~
   <scratch space>:2:1: note: expanded from here
   __do_insw
   ^
   arch/powerpc/include/asm/io.h:557:56: note: expanded from macro '__do_insw'
   #define __do_insw(p, b, n)      readsw((PCI_IO_ADDR)_IO_BASE+(p), (b), (n))
                                          ~~~~~~~~~~~~~~~~~~~~~^
   In file included from net/sched/act_api.c:13:
   In file included from include/linux/skbuff.h:31:
   In file included from include/linux/dma-mapping.h:10:
   In file included from include/linux/scatterlist.h:9:
   In file included from arch/powerpc/include/asm/io.h:619:
   arch/powerpc/include/asm/io-defs.h:47:1: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
   DEF_PCI_AC_NORET(insl, (unsigned long p, void *b, unsigned long c),
   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   arch/powerpc/include/asm/io.h:616:3: note: expanded from macro 'DEF_PCI_AC_NORET'
                   __do_##name al;                                 \
                   ^~~~~~~~~~~~~~
   <scratch space>:4:1: note: expanded from here
   __do_insl
   ^
   arch/powerpc/include/asm/io.h:558:56: note: expanded from macro '__do_insl'
   #define __do_insl(p, b, n)      readsl((PCI_IO_ADDR)_IO_BASE+(p), (b), (n))
                                          ~~~~~~~~~~~~~~~~~~~~~^
   In file included from net/sched/act_api.c:13:
   In file included from include/linux/skbuff.h:31:
   In file included from include/linux/dma-mapping.h:10:
   In file included from include/linux/scatterlist.h:9:
   In file included from arch/powerpc/include/asm/io.h:619:
   arch/powerpc/include/asm/io-defs.h:49:1: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
   DEF_PCI_AC_NORET(outsb, (unsigned long p, const void *b, unsigned long c),
   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   arch/powerpc/include/asm/io.h:616:3: note: expanded from macro 'DEF_PCI_AC_NORET'
                   __do_##name al;                                 \
                   ^~~~~~~~~~~~~~
   <scratch space>:6:1: note: expanded from here
   __do_outsb
   ^
   arch/powerpc/include/asm/io.h:559:58: note: expanded from macro '__do_outsb'
   #define __do_outsb(p, b, n)     writesb((PCI_IO_ADDR)_IO_BASE+(p),(b),(n))
                                           ~~~~~~~~~~~~~~~~~~~~~^
   In file included from net/sched/act_api.c:13:
   In file included from include/linux/skbuff.h:31:
   In file included from include/linux/dma-mapping.h:10:
   In file included from include/linux/scatterlist.h:9:
   In file included from arch/powerpc/include/asm/io.h:619:
   arch/powerpc/include/asm/io-defs.h:51:1: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
   DEF_PCI_AC_NORET(outsw, (unsigned long p, const void *b, unsigned long c),
   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   arch/powerpc/include/asm/io.h:616:3: note: expanded from macro 'DEF_PCI_AC_NORET'
                   __do_##name al;                                 \
                   ^~~~~~~~~~~~~~
   <scratch space>:8:1: note: expanded from here
   __do_outsw
   ^
   arch/powerpc/include/asm/io.h:560:58: note: expanded from macro '__do_outsw'
   #define __do_outsw(p, b, n)     writesw((PCI_IO_ADDR)_IO_BASE+(p),(b),(n))
                                           ~~~~~~~~~~~~~~~~~~~~~^
   In file included from net/sched/act_api.c:13:
   In file included from include/linux/skbuff.h:31:
   In file included from include/linux/dma-mapping.h:10:
   In file included from include/linux/scatterlist.h:9:
   In file included from arch/powerpc/include/asm/io.h:619:
   arch/powerpc/include/asm/io-defs.h:53:1: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
   DEF_PCI_AC_NORET(outsl, (unsigned long p, const void *b, unsigned long c),
   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   arch/powerpc/include/asm/io.h:616:3: note: expanded from macro 'DEF_PCI_AC_NORET'
                   __do_##name al;                                 \
                   ^~~~~~~~~~~~~~
   <scratch space>:10:1: note: expanded from here
   __do_outsl
   ^
   arch/powerpc/include/asm/io.h:561:58: note: expanded from macro '__do_outsl'
   #define __do_outsl(p, b, n)     writesl((PCI_IO_ADDR)_IO_BASE+(p),(b),(n))
                                           ~~~~~~~~~~~~~~~~~~~~~^
quoted
net/sched/act_api.c:1063:5: warning: no previous prototype for function 'tcf_action_offload_cmd_pre' [-Wmissing-prototypes]
   int tcf_action_offload_cmd_pre(struct tc_action *actions[],
       ^
   net/sched/act_api.c:1063:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int tcf_action_offload_cmd_pre(struct tc_action *actions[],
   ^
   static 
quoted
net/sched/act_api.c:1091:5: warning: no previous prototype for function 'tcf_action_offload_cmd_post' [-Wmissing-prototypes]
   int tcf_action_offload_cmd_post(struct flow_offload_action *fl_act,
       ^
   net/sched/act_api.c:1091:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int tcf_action_offload_cmd_post(struct flow_offload_action *fl_act,
   ^
   static 
   net/sched/act_api.c:1105:5: warning: no previous prototype for function 'tcf_action_offload_cmd' [-Wmissing-prototypes]
   int tcf_action_offload_cmd(struct tc_action *actions[],
       ^
   net/sched/act_api.c:1105:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int tcf_action_offload_cmd(struct tc_action *actions[],
   ^
   static 
quoted
net/sched/act_api.c:1123:5: warning: no previous prototype for function 'tcf_action_offload_del_post' [-Wmissing-prototypes]
   int tcf_action_offload_del_post(struct flow_offload_action *fl_act,
       ^
   net/sched/act_api.c:1123:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int tcf_action_offload_del_post(struct flow_offload_action *fl_act,
   ^
   static 
   16 warnings generated.


vim +/tcf_action_offload_cmd_pre +1063 net/sched/act_api.c

  1062	
1063	int tcf_action_offload_cmd_pre(struct tc_action *actions[],
  1064				       enum flow_act_command cmd,
  1065				       struct netlink_ext_ack *extack,
  1066				       struct flow_offload_action **fl_act)
  1067	{
  1068		struct flow_offload_action *fl_act_p;
  1069		int err = 0;
  1070	
  1071		fl_act_p = flow_action_alloc(tcf_act_num_actions(actions));
  1072		if (!fl_act_p)
  1073			return -ENOMEM;
  1074	
  1075		fl_act_p->extack = extack;
  1076		fl_act_p->command = cmd;
  1077		err = tc_setup_action(&fl_act_p->action, actions);
  1078		if (err) {
  1079			NL_SET_ERR_MSG_MOD(extack,
  1080					   "Failed to setup tc actions for offload\n");
  1081			goto err_out;
  1082		}
  1083		*fl_act = fl_act_p;
  1084		return 0;
  1085	err_out:
  1086		kfree(fl_act_p);
  1087		return err;
  1088	}
  1089	EXPORT_SYMBOL(tcf_action_offload_cmd_pre);
  1090	
1091	int tcf_action_offload_cmd_post(struct flow_offload_action *fl_act,
  1092					struct netlink_ext_ack *extack)
  1093	{
  1094		if (IS_ERR(fl_act))
  1095			return PTR_ERR(fl_act);
  1096	
  1097		flow_indr_dev_setup_offload(NULL, NULL, TC_SETUP_ACT, fl_act, NULL, NULL);
  1098	
  1099		tc_cleanup_flow_action(&fl_act->action);
  1100		kfree(fl_act);
  1101		return 0;
  1102	}
  1103	
  1104	/* offload the tc command after inserted */
  1105	int tcf_action_offload_cmd(struct tc_action *actions[],
  1106				   struct netlink_ext_ack *extack)
  1107	{
  1108		struct flow_offload_action *fl_act;
  1109		int err = 0;
  1110	
  1111		err = tcf_action_offload_cmd_pre(actions,
  1112						 FLOW_ACT_REPLACE,
  1113						 extack,
  1114						 &fl_act);
  1115		if (err)
  1116			return err;
  1117	
  1118		return tcf_action_offload_cmd_post(fl_act, extack);
  1119	}
  1120	EXPORT_SYMBOL(tcf_action_offload_cmd);
  1121	
  1122	/* offload the tc command after deleted */
1123	int tcf_action_offload_del_post(struct flow_offload_action *fl_act,
  1124					struct tc_action *actions[],
  1125					struct netlink_ext_ack *extack,
  1126					int fallback_num)
  1127	{
  1128		int fallback_entries = 0;
  1129		struct tc_action *act;
  1130		int total_entries = 0;
  1131		int i;
  1132	
  1133		if (!fl_act)
  1134			return -EINVAL;
  1135	
  1136		if (fallback_num) {
  1137			/* for each the actions to fallback the action entries remain in the actions */
  1138			for (i = 0; i < TCA_ACT_MAX_PRIO; i++) {
  1139				act = actions[i];
  1140				if (!act)
  1141					continue;
  1142	
  1143				fallback_entries += tcf_act_num_actions_single(act);
  1144			}
  1145			fallback_entries += fallback_num;
  1146		}
  1147		total_entries = fl_act->action.num_entries;
  1148		if (total_entries > fallback_entries) {
  1149			/* just offload the actions that is not fallback and start with the actions */
  1150			fl_act->action.num_entries -= fallback_entries;
  1151			flow_indr_dev_setup_offload(NULL, NULL, TC_SETUP_ACT, fl_act, NULL, NULL);
  1152	
  1153			/* recovery num_entries for cleanup */
  1154			fl_act->action.num_entries = total_entries;
  1155		} else {
  1156			NL_SET_ERR_MSG(extack, "no entries to offload when deleting the tc actions");
  1157		}
  1158	
  1159		tc_cleanup_flow_action(&fl_act->action);
  1160	
  1161		kfree(fl_act);
  1162		return 0;
  1163	}
  1164	EXPORT_SYMBOL(tcf_action_offload_del_post);
  1165	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Simon Horman <hidden>
Date: 2021-07-27 13:04:36

On Thu, Jul 22, 2021 at 09:33:09AM -0400, Jamal Hadi Salim wrote:
On 2021-07-22 9:29 a.m., Vlad Buslov wrote:
quoted
On Thu 22 Jul 2021 at 12:19, Simon Horman [off-list ref] wrote:
quoted
From: Baowen Zheng <redacted>

Use flow_indr_dev_register/flow_indr_dev_setup_offload to
offload tc action.

We offload the tc action mainly for ovs meter configuration.
Make some basic changes for different vendors to return EOPNOTSUPP.

We need to call tc_cleanup_flow_action to clean up tc action entry since
in tc_setup_action, some actions may hold dev refcnt, especially the mirror
action.

As per review from the RFC, the kernel test robot will fail to run, so
we add CONFIG_NET_CLS_ACT control for the action offload.

Signed-off-by: Baowen Zheng <redacted>
Signed-off-by: Louis Peens <redacted>
Signed-off-by: Simon Horman <redacted>
---
  drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c  |  2 +-
  .../ethernet/mellanox/mlx5/core/en/rep/tc.c   |  3 ++
quoted
quoted
  			    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,
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c
[..]
quoted
quoted
+	/* offload actions to hardware if possible */
+	tcf_action_offload_cmd(actions, extack);
+
I think this has already been suggested for RFC, but some sort of
visibility for offload status of action would be extremely welcome.
Perhaps "IN_HW" flag and counter, similar to what we have for offloaded
filters.
Also showing a tc command line in the cover letter on how one would
ask for a specific action to be offloaded.
In practice actions are offloaded when a flow using them is offloaded.
So I think we need to consider what the meaning of IN_HW is.

Is it that:

* The driver (and potentially hardware, though not in our current
  implementation) has accepted the action for offload;
* That a classifier that uses the action has bee offloaded;
* Or something else?

With regards to a counter, I'm not quite sure what this would be:

* The number of devices where the action has been offloaded (which ties
  into the question of what we mean by IN_HW)
* The number of offloaded classifier instances using the action
* Something else

Regarding a flag to control offload:

* For classifiers (at least the flower classifier) there is the skip_sw and
  skip_hw flags, which allow control of placement of a classifier in SW and
  HW.
* We could add similar flags for actions, which at least in my
  world view would have the net-effect of controlling which classifiers can
  be added to sw and hw - f.e. a classifier that uses an action marked
  skip_hw could not be added to HW.
* Doing so would add some extra complexity and its not immediately apparent
  to me what the use-case would be given that there are already flags for
  classifiers.

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Vlad Buslov <hidden>
Date: 2021-07-27 14:39:01

On Tue 27 Jul 2021 at 16:04, Simon Horman [off-list ref] wrote:
On Thu, Jul 22, 2021 at 09:33:09AM -0400, Jamal Hadi Salim wrote:
quoted
On 2021-07-22 9:29 a.m., Vlad Buslov wrote:
quoted
On Thu 22 Jul 2021 at 12:19, Simon Horman [off-list ref] wrote:
quoted
From: Baowen Zheng <redacted>

Use flow_indr_dev_register/flow_indr_dev_setup_offload to
offload tc action.

We offload the tc action mainly for ovs meter configuration.
Make some basic changes for different vendors to return EOPNOTSUPP.

We need to call tc_cleanup_flow_action to clean up tc action entry since
in tc_setup_action, some actions may hold dev refcnt, especially the mirror
action.

As per review from the RFC, the kernel test robot will fail to run, so
we add CONFIG_NET_CLS_ACT control for the action offload.

Signed-off-by: Baowen Zheng <redacted>
Signed-off-by: Louis Peens <redacted>
Signed-off-by: Simon Horman <redacted>
---
  drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c  |  2 +-
  .../ethernet/mellanox/mlx5/core/en/rep/tc.c   |  3 ++
quoted
quoted
  			    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,
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c
[..]
quoted
quoted
+	/* offload actions to hardware if possible */
+	tcf_action_offload_cmd(actions, extack);
+
I think this has already been suggested for RFC, but some sort of
visibility for offload status of action would be extremely welcome.
Perhaps "IN_HW" flag and counter, similar to what we have for offloaded
filters.
Also showing a tc command line in the cover letter on how one would
ask for a specific action to be offloaded.
In practice actions are offloaded when a flow using them is offloaded.
So I think we need to consider what the meaning of IN_HW is.

Is it that:

* The driver (and potentially hardware, though not in our current
  implementation) has accepted the action for offload;
* That a classifier that uses the action has bee offloaded;
* Or something else?
I think we have the same issue with filters - they might not be in
hardware after driver callback returned "success" (due to neigh state
being invalid for tunnel_key encap, for example).
With regards to a counter, I'm not quite sure what this would be:

* The number of devices where the action has been offloaded (which ties
  into the question of what we mean by IN_HW)
* The number of offloaded classifier instances using the action
* Something else
I would prefer to have semantics similar to filters:

1. Count number of driver callbacks that returned "success".

2. If count > 0, then set in_hw flag.

3. Set in_hw_count to success count.

This would allow user to immediately determine whether action passed
driver validation.
Regarding a flag to control offload:

* For classifiers (at least the flower classifier) there is the skip_sw and
  skip_hw flags, which allow control of placement of a classifier in SW and
  HW.
* We could add similar flags for actions, which at least in my
  world view would have the net-effect of controlling which classifiers can
  be added to sw and hw - f.e. a classifier that uses an action marked
  skip_hw could not be added to HW.
* Doing so would add some extra complexity and its not immediately apparent
  to me what the use-case would be given that there are already flags for
  classifiers.
Yeah, adding such flag for action offload seems to complicate things.
Also, "skip_sw" flag doesn't even make much sense for actions. I thought
that "skip_hw" flag would be nice to have for users that would like to
avoid "spamming" their NIC drivers (potentially causing higher latency
and resource consumption) for filters/actions they have no intention to
offload to hardware, but I'm not sure how useful is that option really
is.

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Jamal Hadi Salim <jhs@mojatatu.com>
Date: 2021-07-27 16:13:45

On 2021-07-27 10:38 a.m., Vlad Buslov wrote:
On Tue 27 Jul 2021 at 16:04, Simon Horman [off-list ref] wrote:
quoted
quoted
Also showing a tc command line in the cover letter on how one would
ask for a specific action to be offloaded.
In practice actions are offloaded when a flow using them is offloaded.
So I think we need to consider what the meaning of IN_HW is.

Is it that:

* The driver (and potentially hardware, though not in our current
   implementation) has accepted the action for offload;
* That a classifier that uses the action has bee offloaded;
* Or something else?
I think we have the same issue with filters - they might not be in
hardware after driver callback returned "success" (due to neigh state
being invalid for tunnel_key encap, for example).
Sounds like we need another state for this. Otherwise, how do you debug
that something is sitting in the driver and not in hardware after you
issued a command to offload it? How do i tell today?
Also knowing reason why something is sitting in the driver would be
helpful.
quoted
With regards to a counter, I'm not quite sure what this would be:

* The number of devices where the action has been offloaded (which ties
   into the question of what we mean by IN_HW)
* The number of offloaded classifier instances using the action
* Something else
I would prefer to have semantics similar to filters:

1. Count number of driver callbacks that returned "success".

2. If count > 0, then set in_hw flag.

3. Set in_hw_count to success count.

This would allow user to immediately determine whether action passed
driver validation.
I didnt follow this:
Are we refering to the the "block" semantics (where a filter for
example applies to multiple devices)?
quoted
Regarding a flag to control offload:

* For classifiers (at least the flower classifier) there is the skip_sw and
   skip_hw flags, which allow control of placement of a classifier in SW and
   HW.
* We could add similar flags for actions, which at least in my
   world view would have the net-effect of controlling which classifiers can
   be added to sw and hw - f.e. a classifier that uses an action marked
   skip_hw could not be added to HW.
I guess it depends on the hardware implementation.
In S/W we have two modes:
Approach A: create an action and then 2) bind it to a filter.
Approach B: Create a filter and then bind it to an action.

And #2A can be repeated multiple times for the same action
(would require some index as a reference for the action)
To Simon's comment above that would mean allowing
"a classifier that uses an action marked skip_hw to be added to HW"
i.e
Some hardware is capable of doing both option #A and #B.

Todays offload assumes #B - in which both filter and action are assumed
offloaded.

I am hoping whatever approach we end up agreeing on doesnt limit
either mode.
quoted
* Doing so would add some extra complexity and its not immediately apparent
   to me what the use-case would be given that there are already flags for
   classifiers.
Yeah, adding such flag for action offload seems to complicate things.
Also, "skip_sw" flag doesn't even make much sense for actions. I thought
that "skip_hw" flag would be nice to have for users that would like to
avoid "spamming" their NIC drivers (potentially causing higher latency
and resource consumption) for filters/actions they have no intention to
offload to hardware, but I'm not sure how useful is that option really
is.
Hold on Vlad.
So you are looking at this mostly as an optimization to speed up h/w
control updates? ;->

I was looking at it more as a (currently missing) feature improvement.
We already have a use case that is implemented by s/w today. The feature
mimics it in h/w.

At minimal all existing NICs should be able to support the counters
as mapped to simple actions like drop. I understand for example if some
cant support adding separately offloading of tunnels for example.
So the syntax is something along the lines of:

tc actions add action drop index 15 skip_sw
tc filter add dev ...parent ... protocol ip prio X ..\
u32/flower skip_sw match ... flowid 1:10 action gact index 15

You get an error if counter index 15 is not offloaded or
if skip_sw was left out..

And then later on, if you support sharing of actions:
tc filter add dev ...parent ... protocol ip prio X2 ..\
u32/flower skip_sw match ... flowid 1:10 action gact index 15

cheers,
jamal

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Vlad Buslov <hidden>
Date: 2021-07-27 16:47:53

On Tue 27 Jul 2021 at 19:13, Jamal Hadi Salim [off-list ref] wrote:
On 2021-07-27 10:38 a.m., Vlad Buslov wrote:
quoted
On Tue 27 Jul 2021 at 16:04, Simon Horman [off-list ref] wrote:
quoted
quoted
quoted
Also showing a tc command line in the cover letter on how one would
ask for a specific action to be offloaded.
In practice actions are offloaded when a flow using them is offloaded.
So I think we need to consider what the meaning of IN_HW is.

Is it that:

* The driver (and potentially hardware, though not in our current
   implementation) has accepted the action for offload;
* That a classifier that uses the action has bee offloaded;
* Or something else?
I think we have the same issue with filters - they might not be in
hardware after driver callback returned "success" (due to neigh state
being invalid for tunnel_key encap, for example).
Sounds like we need another state for this. Otherwise, how do you debug
that something is sitting in the driver and not in hardware after you
issued a command to offload it? How do i tell today?
Also knowing reason why something is sitting in the driver would be
helpful.
It is not about just adding another state. The issue is that there is no
way for drivers to change the state of software filter dynamically.
quoted
quoted
With regards to a counter, I'm not quite sure what this would be:

* The number of devices where the action has been offloaded (which ties
   into the question of what we mean by IN_HW)
* The number of offloaded classifier instances using the action
* Something else
I would prefer to have semantics similar to filters:
1. Count number of driver callbacks that returned "success".
2. If count > 0, then set in_hw flag.
3. Set in_hw_count to success count.
This would allow user to immediately determine whether action passed
driver validation.
I didnt follow this:
Are we refering to the the "block" semantics (where a filter for
example applies to multiple devices)?
This uses indirect offload infrastructure, which means all drivers
in flow_block_indr_dev_list will receive action offload requests.
quoted
quoted
Regarding a flag to control offload:

* For classifiers (at least the flower classifier) there is the skip_sw and
   skip_hw flags, which allow control of placement of a classifier in SW and
   HW.
* We could add similar flags for actions, which at least in my
   world view would have the net-effect of controlling which classifiers can
   be added to sw and hw - f.e. a classifier that uses an action marked
   skip_hw could not be added to HW.
I guess it depends on the hardware implementation.
In S/W we have two modes:
Approach A: create an action and then 2) bind it to a filter.
Approach B: Create a filter and then bind it to an action.

And #2A can be repeated multiple times for the same action
(would require some index as a reference for the action)
To Simon's comment above that would mean allowing
"a classifier that uses an action marked skip_hw to be added to HW"
i.e
Some hardware is capable of doing both option #A and #B.

Todays offload assumes #B - in which both filter and action are assumed
offloaded.

I am hoping whatever approach we end up agreeing on doesnt limit
either mode.
quoted
quoted
* Doing so would add some extra complexity and its not immediately apparent
   to me what the use-case would be given that there are already flags for
   classifiers.
Yeah, adding such flag for action offload seems to complicate things.
Also, "skip_sw" flag doesn't even make much sense for actions. I thought
that "skip_hw" flag would be nice to have for users that would like to
avoid "spamming" their NIC drivers (potentially causing higher latency
and resource consumption) for filters/actions they have no intention to
offload to hardware, but I'm not sure how useful is that option really
is.
Hold on Vlad.
So you are looking at this mostly as an optimization to speed up h/w
control updates? ;->
No. How would adding more flags improve h/w update rate? I was just
thinking that it is strange that users that are not interested in
offloads would suddenly have higher memory usage for their actions just
because they happen to have offload-capable driver loaded. But it is not
a major concern for me.
I was looking at it more as a (currently missing) feature improvement.
We already have a use case that is implemented by s/w today. The feature
mimics it in h/w.

At minimal all existing NICs should be able to support the counters
as mapped to simple actions like drop. I understand for example if some
cant support adding separately offloading of tunnels for example.
So the syntax is something along the lines of:

tc actions add action drop index 15 skip_sw
tc filter add dev ...parent ... protocol ip prio X ..\
u32/flower skip_sw match ... flowid 1:10 action gact index 15

You get an error if counter index 15 is not offloaded or
if skip_sw was left out..

And then later on, if you support sharing of actions:
tc filter add dev ...parent ... protocol ip prio X2 ..\
u32/flower skip_sw match ... flowid 1:10 action gact index 15

cheers,
jamal

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Simon Horman <hidden>
Date: 2021-07-28 07:46:39

On Tue, Jul 27, 2021 at 07:47:43PM +0300, Vlad Buslov wrote:
On Tue 27 Jul 2021 at 19:13, Jamal Hadi Salim [off-list ref] wrote:
quoted
On 2021-07-27 10:38 a.m., Vlad Buslov wrote:
quoted
On Tue 27 Jul 2021 at 16:04, Simon Horman [off-list ref] wrote:
quoted
quoted
quoted
Also showing a tc command line in the cover letter on how one would
ask for a specific action to be offloaded.
In practice actions are offloaded when a flow using them is offloaded.
So I think we need to consider what the meaning of IN_HW is.

Is it that:

* The driver (and potentially hardware, though not in our current
   implementation) has accepted the action for offload;
* That a classifier that uses the action has bee offloaded;
* Or something else?
I think we have the same issue with filters - they might not be in
hardware after driver callback returned "success" (due to neigh state
being invalid for tunnel_key encap, for example).
Sounds like we need another state for this. Otherwise, how do you debug
that something is sitting in the driver and not in hardware after you
issued a command to offload it? How do i tell today?
Also knowing reason why something is sitting in the driver would be
helpful.
It is not about just adding another state. The issue is that there is no
way for drivers to change the state of software filter dynamically.
I think it might be worth considering enhancing things at some point.
But I agree that its more than a matter of adding an extra flag. And
I think it's reasonable to implement something similar to the classifier
current offload handling of IN_HW now and consider enhancements separately.
quoted
quoted
quoted
With regards to a counter, I'm not quite sure what this would be:

* The number of devices where the action has been offloaded (which ties
   into the question of what we mean by IN_HW)
* The number of offloaded classifier instances using the action
* Something else
I would prefer to have semantics similar to filters:
1. Count number of driver callbacks that returned "success".
2. If count > 0, then set in_hw flag.
3. Set in_hw_count to success count.
This would allow user to immediately determine whether action passed
driver validation.
Thanks, that makes sense to me.
quoted
I didnt follow this:
Are we refering to the the "block" semantics (where a filter for
example applies to multiple devices)?
This uses indirect offload infrastructure, which means all drivers
in flow_block_indr_dev_list will receive action offload requests.
quoted
quoted
quoted
Regarding a flag to control offload:

* For classifiers (at least the flower classifier) there is the skip_sw and
   skip_hw flags, which allow control of placement of a classifier in SW and
   HW.
* We could add similar flags for actions, which at least in my
   world view would have the net-effect of controlling which classifiers can
   be added to sw and hw - f.e. a classifier that uses an action marked
   skip_hw could not be added to HW.
I guess it depends on the hardware implementation.
In S/W we have two modes:
Approach A: create an action and then 2) bind it to a filter.
Approach B: Create a filter and then bind it to an action.

And #2A can be repeated multiple times for the same action
(would require some index as a reference for the action)
To Simon's comment above that would mean allowing
"a classifier that uses an action marked skip_hw to be added to HW"
i.e
Some hardware is capable of doing both option #A and #B.

Todays offload assumes #B - in which both filter and action are assumed
offloaded.

I am hoping whatever approach we end up agreeing on doesnt limit
either mode.
quoted
quoted
* Doing so would add some extra complexity and its not immediately apparent
   to me what the use-case would be given that there are already flags for
   classifiers.
Yeah, adding such flag for action offload seems to complicate things.
Also, "skip_sw" flag doesn't even make much sense for actions. I thought
that "skip_hw" flag would be nice to have for users that would like to
avoid "spamming" their NIC drivers (potentially causing higher latency
and resource consumption) for filters/actions they have no intention to
offload to hardware, but I'm not sure how useful is that option really
is.
Hold on Vlad.
So you are looking at this mostly as an optimization to speed up h/w
control updates? ;->
No. How would adding more flags improve h/w update rate? I was just
thinking that it is strange that users that are not interested in
offloads would suddenly have higher memory usage for their actions just
because they happen to have offload-capable driver loaded. But it is not
a major concern for me.
In that case can we rely on the global tc-offload on/off flag
provided by ethtool? (I understand its not the same, but perhaps
it is sufficient in practice.)
quoted
I was looking at it more as a (currently missing) feature improvement.
We already have a use case that is implemented by s/w today. The feature
mimics it in h/w.

At minimal all existing NICs should be able to support the counters
as mapped to simple actions like drop. I understand for example if some
cant support adding separately offloading of tunnels for example.
So the syntax is something along the lines of:

tc actions add action drop index 15 skip_sw
tc filter add dev ...parent ... protocol ip prio X ..\
u32/flower skip_sw match ... flowid 1:10 action gact index 15

You get an error if counter index 15 is not offloaded or
if skip_sw was left out..

And then later on, if you support sharing of actions:
tc filter add dev ...parent ... protocol ip prio X2 ..\
u32/flower skip_sw match ... flowid 1:10 action gact index 15
Right, I understand that makes sense and is internally consistent.
But I think that in practice it only makes a difference "Approach B"
implementations, none of which currently exist.

I would suggest we can add this when the need arises, rather than
speculatively without hw/driver support. Its not precluded by the current
model AFAIK.

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Vlad Buslov <hidden>
Date: 2021-07-28 08:05:58

On Wed 28 Jul 2021 at 10:46, Simon Horman [off-list ref] wrote:
On Tue, Jul 27, 2021 at 07:47:43PM +0300, Vlad Buslov wrote:
quoted
On Tue 27 Jul 2021 at 19:13, Jamal Hadi Salim [off-list ref] wrote:
quoted
On 2021-07-27 10:38 a.m., Vlad Buslov wrote:
quoted
On Tue 27 Jul 2021 at 16:04, Simon Horman [off-list ref] wrote:
quoted
quoted
quoted
Also showing a tc command line in the cover letter on how one would
ask for a specific action to be offloaded.
In practice actions are offloaded when a flow using them is offloaded.
So I think we need to consider what the meaning of IN_HW is.

Is it that:

* The driver (and potentially hardware, though not in our current
   implementation) has accepted the action for offload;
* That a classifier that uses the action has bee offloaded;
* Or something else?
I think we have the same issue with filters - they might not be in
hardware after driver callback returned "success" (due to neigh state
being invalid for tunnel_key encap, for example).
Sounds like we need another state for this. Otherwise, how do you debug
that something is sitting in the driver and not in hardware after you
issued a command to offload it? How do i tell today?
Also knowing reason why something is sitting in the driver would be
helpful.
It is not about just adding another state. The issue is that there is no
way for drivers to change the state of software filter dynamically.
I think it might be worth considering enhancing things at some point.
But I agree that its more than a matter of adding an extra flag. And
I think it's reasonable to implement something similar to the classifier
current offload handling of IN_HW now and consider enhancements separately.
quoted
quoted
quoted
quoted
With regards to a counter, I'm not quite sure what this would be:

* The number of devices where the action has been offloaded (which ties
   into the question of what we mean by IN_HW)
* The number of offloaded classifier instances using the action
* Something else
I would prefer to have semantics similar to filters:
1. Count number of driver callbacks that returned "success".
2. If count > 0, then set in_hw flag.
3. Set in_hw_count to success count.
This would allow user to immediately determine whether action passed
driver validation.
Thanks, that makes sense to me.
quoted
quoted
I didnt follow this:
Are we refering to the the "block" semantics (where a filter for
example applies to multiple devices)?
This uses indirect offload infrastructure, which means all drivers
in flow_block_indr_dev_list will receive action offload requests.
quoted
quoted
quoted
Regarding a flag to control offload:

* For classifiers (at least the flower classifier) there is the skip_sw and
   skip_hw flags, which allow control of placement of a classifier in SW and
   HW.
* We could add similar flags for actions, which at least in my
   world view would have the net-effect of controlling which classifiers can
   be added to sw and hw - f.e. a classifier that uses an action marked
   skip_hw could not be added to HW.
I guess it depends on the hardware implementation.
In S/W we have two modes:
Approach A: create an action and then 2) bind it to a filter.
Approach B: Create a filter and then bind it to an action.

And #2A can be repeated multiple times for the same action
(would require some index as a reference for the action)
To Simon's comment above that would mean allowing
"a classifier that uses an action marked skip_hw to be added to HW"
i.e
Some hardware is capable of doing both option #A and #B.

Todays offload assumes #B - in which both filter and action are assumed
offloaded.

I am hoping whatever approach we end up agreeing on doesnt limit
either mode.
quoted
quoted
* Doing so would add some extra complexity and its not immediately apparent
   to me what the use-case would be given that there are already flags for
   classifiers.
Yeah, adding such flag for action offload seems to complicate things.
Also, "skip_sw" flag doesn't even make much sense for actions. I thought
that "skip_hw" flag would be nice to have for users that would like to
avoid "spamming" their NIC drivers (potentially causing higher latency
and resource consumption) for filters/actions they have no intention to
offload to hardware, but I'm not sure how useful is that option really
is.
Hold on Vlad.
So you are looking at this mostly as an optimization to speed up h/w
control updates? ;->
No. How would adding more flags improve h/w update rate? I was just
thinking that it is strange that users that are not interested in
offloads would suddenly have higher memory usage for their actions just
because they happen to have offload-capable driver loaded. But it is not
a major concern for me.
In that case can we rely on the global tc-offload on/off flag
provided by ethtool? (I understand its not the same, but perhaps
it is sufficient in practice.)
Yes, the ethtool should be sufficient. Didn't think about it initially.
Thanks!
quoted
quoted
I was looking at it more as a (currently missing) feature improvement.
We already have a use case that is implemented by s/w today. The feature
mimics it in h/w.

At minimal all existing NICs should be able to support the counters
as mapped to simple actions like drop. I understand for example if some
cant support adding separately offloading of tunnels for example.
So the syntax is something along the lines of:

tc actions add action drop index 15 skip_sw
tc filter add dev ...parent ... protocol ip prio X ..\
u32/flower skip_sw match ... flowid 1:10 action gact index 15

You get an error if counter index 15 is not offloaded or
if skip_sw was left out..

And then later on, if you support sharing of actions:
tc filter add dev ...parent ... protocol ip prio X2 ..\
u32/flower skip_sw match ... flowid 1:10 action gact index 15
Right, I understand that makes sense and is internally consistent.
But I think that in practice it only makes a difference "Approach B"
implementations, none of which currently exist.

I would suggest we can add this when the need arises, rather than
speculatively without hw/driver support. Its not precluded by the current
model AFAIK.

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Jamal Hadi Salim <jhs@mojatatu.com>
Date: 2021-07-28 13:53:10

On 2021-07-28 3:46 a.m., Simon Horman wrote:
On Tue, Jul 27, 2021 at 07:47:43PM +0300, Vlad Buslov wrote:
quoted
On Tue 27 Jul 2021 at 19:13, Jamal Hadi Salim [off-list ref] wrote:
quoted
On 2021-07-27 10:38 a.m., Vlad Buslov wrote:
quoted
On Tue 27 Jul 2021 at 16:04, Simon Horman [off-list ref] wrote:
[..]
quoted
quoted
quoted
I think we have the same issue with filters - they might not be in
hardware after driver callback returned "success" (due to neigh state
being invalid for tunnel_key encap, for example).
Sounds like we need another state for this. Otherwise, how do you debug
that something is sitting in the driver and not in hardware after you
issued a command to offload it? How do i tell today?
Also knowing reason why something is sitting in the driver would be
helpful.
It is not about just adding another state. The issue is that there is no
way for drivers to change the state of software filter dynamically.
I think it might be worth considering enhancing things at some point.
But I agree that its more than a matter of adding an extra flag. And
I think it's reasonable to implement something similar to the classifier
current offload handling of IN_HW now and consider enhancements separately.
Debugability is very important. If we have such gotchas we need to have
the admin at least be able to tell if the driver returns "success"
and the request is still sitting in the driver for whatever reason
At minimal there needs to be some indicator somewhere which say
"inprogress" or "waiting for resolution" etc.
If the control plane(user space app) starts making other decisions
based on assumptions that filter was successfully installed i.e
packets are being treated in the hardware then there could be
consequences when this assumption is wrong.

So if i undestood the challenge correctly it is: how do you relay
this info back so it is reflected in the filter details. Yes that
would require some mechanism to exist and possibly mapping state
between whats in the driver and in the cls layer.
If i am not mistaken, the switchdev folks handle this asynchronicty?
+Cc Ido, Jiri, Roopa

And it should be noted that: Yes, the filters have this
pre-existing condition but doesnt mean given the opportunity
to do actions we should replicate what they do.

[..]
quoted
quoted
I didnt follow this:
Are we refering to the the "block" semantics (where a filter for
example applies to multiple devices)?
This uses indirect offload infrastructure, which means all drivers
in flow_block_indr_dev_list will receive action offload requests.
Ok, understood.

[..]
quoted
No. How would adding more flags improve h/w update rate? I was just
thinking that it is strange that users that are not interested in
offloads would suddenly have higher memory usage for their actions just
because they happen to have offload-capable driver loaded. But it is not
a major concern for me.
In that case can we rely on the global tc-offload on/off flag
provided by ethtool? (I understand its not the same, but perhaps
it is sufficient in practice.)
ok.
So: I think i have seen this what is probably the spamming refered
with the intel (800?) driver ;-> Basically driver was reacting to
all filters regardless of need to offload or not.
I thought it was an oversight on their part and the driver needed
fixing. Are we invoking the offload regardless of whether h/w offload
is requested? In my naive view - at least when i looked at the intel
code - it didnt seem hard to avoid the spamming.

quoted
quoted
I was looking at it more as a (currently missing) feature improvement.
We already have a use case that is implemented by s/w today. The feature
mimics it in h/w.

At minimal all existing NICs should be able to support the counters
as mapped to simple actions like drop. I understand for example if some
cant support adding separately offloading of tunnels for example.
So the syntax is something along the lines of:

tc actions add action drop index 15 skip_sw
tc filter add dev ...parent ... protocol ip prio X ..\
u32/flower skip_sw match ... flowid 1:10 action gact index 15

You get an error if counter index 15 is not offloaded or
if skip_sw was left out..

And then later on, if you support sharing of actions:
tc filter add dev ...parent ... protocol ip prio X2 ..\
u32/flower skip_sw match ... flowid 1:10 action gact index 15
Right, I understand that makes sense and is internally consistent.
But I think that in practice it only makes a difference "Approach B"
implementations, none of which currently exist.
At minimal:
Shouldnt counters (easily correlated to basic actions like drop or
accept) fit the scenario of:
tc actions add action drop index 15 skip_sw
tc filter add dev ...parent ... protocol ip prio X .. \
u32/flower skip_sw match ... flowid 1:10 action gact index 15

?
I would suggest we can add this when the need arises, rather than
speculatively without hw/driver support. Its not precluded by the current
model AFAIK.
We are going to work on a driver that would have the "B" approach.
I am hoping - whatever the consensus here - it doesnt require a
surgery afterwards to make that work.

cheers,
jamal

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Simon Horman <hidden>
Date: 2021-07-28 14:46:39

On Wed, Jul 28, 2021 at 09:51:00AM -0400, Jamal Hadi Salim wrote:
On 2021-07-28 3:46 a.m., Simon Horman wrote:
quoted
On Tue, Jul 27, 2021 at 07:47:43PM +0300, Vlad Buslov wrote:
quoted
On Tue 27 Jul 2021 at 19:13, Jamal Hadi Salim [off-list ref] wrote:
quoted
On 2021-07-27 10:38 a.m., Vlad Buslov wrote:
quoted
On Tue 27 Jul 2021 at 16:04, Simon Horman [off-list ref] wrote:
[..]
quoted
quoted
quoted
quoted
I think we have the same issue with filters - they might not be in
hardware after driver callback returned "success" (due to neigh state
being invalid for tunnel_key encap, for example).
Sounds like we need another state for this. Otherwise, how do you debug
that something is sitting in the driver and not in hardware after you
issued a command to offload it? How do i tell today?
Also knowing reason why something is sitting in the driver would be
helpful.
It is not about just adding another state. The issue is that there is no
way for drivers to change the state of software filter dynamically.
I think it might be worth considering enhancing things at some point.
But I agree that its more than a matter of adding an extra flag. And
I think it's reasonable to implement something similar to the classifier
current offload handling of IN_HW now and consider enhancements separately.
Debugability is very important. If we have such gotchas we need to have
the admin at least be able to tell if the driver returns "success"
and the request is still sitting in the driver for whatever reason
At minimal there needs to be some indicator somewhere which say
"inprogress" or "waiting for resolution" etc.
If the control plane(user space app) starts making other decisions
based on assumptions that filter was successfully installed i.e
packets are being treated in the hardware then there could be
consequences when this assumption is wrong.

So if i undestood the challenge correctly it is: how do you relay
this info back so it is reflected in the filter details. Yes that
would require some mechanism to exist and possibly mapping state
between whats in the driver and in the cls layer.
If i am not mistaken, the switchdev folks handle this asynchronicty?
+Cc Ido, Jiri, Roopa

And it should be noted that: Yes, the filters have this
pre-existing condition but doesnt mean given the opportunity
to do actions we should replicate what they do.
I'd prefer symmetry between the use of IN_HW for filters and actions,
which I believe is what Vlad has suggested.

If we wish to enhance things - f.e. for debugging, which I
agree is important - then I think that is a separate topic.
[..]
quoted
quoted
quoted
I didnt follow this:
Are we refering to the the "block" semantics (where a filter for
example applies to multiple devices)?
This uses indirect offload infrastructure, which means all drivers
in flow_block_indr_dev_list will receive action offload requests.
Ok, understood.

[..]
quoted
quoted
No. How would adding more flags improve h/w update rate? I was just
thinking that it is strange that users that are not interested in
offloads would suddenly have higher memory usage for their actions just
because they happen to have offload-capable driver loaded. But it is not
a major concern for me.
In that case can we rely on the global tc-offload on/off flag
provided by ethtool? (I understand its not the same, but perhaps
it is sufficient in practice.)
ok.
So: I think i have seen this what is probably the spamming refered
with the intel (800?) driver ;-> Basically driver was reacting to
all filters regardless of need to offload or not.
I thought it was an oversight on their part and the driver needed
fixing. Are we invoking the offload regardless of whether h/w offload
is requested? In my naive view - at least when i looked at the intel
code - it didnt seem hard to avoid the spamming.
There is a per-netdev (not global as I wrote above) flag to enable and
disable offload. And there is per-classifier skip_hw flag. I can dig
through the code as easily as you can but I'd be surprised if the
driver is seeing offload requests if either of those settings
are in effect.
quoted
quoted
quoted
I was looking at it more as a (currently missing) feature improvement.
We already have a use case that is implemented by s/w today. The feature
mimics it in h/w.

At minimal all existing NICs should be able to support the counters
as mapped to simple actions like drop. I understand for example if some
cant support adding separately offloading of tunnels for example.
So the syntax is something along the lines of:

tc actions add action drop index 15 skip_sw
tc filter add dev ...parent ... protocol ip prio X ..\
u32/flower skip_sw match ... flowid 1:10 action gact index 15

You get an error if counter index 15 is not offloaded or
if skip_sw was left out..

And then later on, if you support sharing of actions:
tc filter add dev ...parent ... protocol ip prio X2 ..\
u32/flower skip_sw match ... flowid 1:10 action gact index 15
Right, I understand that makes sense and is internally consistent.
But I think that in practice it only makes a difference "Approach B"
implementations, none of which currently exist.
At minimal:
Shouldnt counters (easily correlated to basic actions like drop or
accept) fit the scenario of:
tc actions add action drop index 15 skip_sw
tc filter add dev ...parent ... protocol ip prio X .. \
u32/flower skip_sw match ... flowid 1:10 action gact index 15

?
quoted
I would suggest we can add this when the need arises, rather than
speculatively without hw/driver support. Its not precluded by the current
model AFAIK.
We are going to work on a driver that would have the "B" approach.
I am hoping - whatever the consensus here - it doesnt require a
surgery afterwards to make that work.
You should be able to build on the work proposed here to add what you
suggest into the framework to meet these requirements for your driver work.

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Jamal Hadi Salim <jhs@mojatatu.com>
Date: 2021-07-30 10:17:23

On 2021-07-28 10:46 a.m., Simon Horman wrote:
On Wed, Jul 28, 2021 at 09:51:00AM -0400, Jamal Hadi Salim wrote:
quoted
On 2021-07-28 3:46 a.m., Simon Horman wrote:
quoted
On Tue, Jul 27, 2021 at 07:47:43PM +0300, Vlad Buslov wrote:
quoted
On Tue 27 Jul 2021 at 19:13, Jamal Hadi Salim [off-list ref] wrote:
quoted
On 2021-07-27 10:38 a.m., Vlad Buslov wrote:
quoted
On Tue 27 Jul 2021 at 16:04, Simon Horman [off-list ref] wrote:
[..]
quoted
quoted
quoted
quoted
I think we have the same issue with filters - they might not be in
hardware after driver callback returned "success" (due to neigh state
being invalid for tunnel_key encap, for example).
Sounds like we need another state for this. Otherwise, how do you debug
that something is sitting in the driver and not in hardware after you
issued a command to offload it? How do i tell today?
Also knowing reason why something is sitting in the driver would be
helpful.
It is not about just adding another state. The issue is that there is no
way for drivers to change the state of software filter dynamically.
I think it might be worth considering enhancing things at some point.
But I agree that its more than a matter of adding an extra flag. And
I think it's reasonable to implement something similar to the classifier
current offload handling of IN_HW now and consider enhancements separately.
Debugability is very important. If we have such gotchas we need to have
the admin at least be able to tell if the driver returns "success"
and the request is still sitting in the driver for whatever reason
At minimal there needs to be some indicator somewhere which say
"inprogress" or "waiting for resolution" etc.
If the control plane(user space app) starts making other decisions
based on assumptions that filter was successfully installed i.e
packets are being treated in the hardware then there could be
consequences when this assumption is wrong.

So if i undestood the challenge correctly it is: how do you relay
this info back so it is reflected in the filter details. Yes that
would require some mechanism to exist and possibly mapping state
between whats in the driver and in the cls layer.
If i am not mistaken, the switchdev folks handle this asynchronicty?
+Cc Ido, Jiri, Roopa

And it should be noted that: Yes, the filters have this
pre-existing condition but doesnt mean given the opportunity
to do actions we should replicate what they do.
I'd prefer symmetry between the use of IN_HW for filters and actions,
which I believe is what Vlad has suggested.
It still not clear to me what it means from a command line pov.
How do i add a rule and when i dump it what does it show?
If we wish to enhance things - f.e. for debugging, which I
agree is important - then I think that is a separate topic.
My only concern is not to repeat mistakes that are in filters
just for the sake of symmetry. Example the fact that something
went wrong with insertion or insertion is still in progress
and you get an indication that all went well.
Looking at mlnx (NIC) ndrivers it does seem that in the normal case
the insertion into hw is synchronous (for anything that is not sw
only). I didnt quiet see what Vlad was referring to.
We have spent literally hours debugging issues where rules are being
offloaded thinking it was the driver so any extra info helps.

quoted
quoted
quoted
No. How would adding more flags improve h/w update rate? I was just
thinking that it is strange that users that are not interested in
offloads would suddenly have higher memory usage for their actions just
because they happen to have offload-capable driver loaded. But it is not
a major concern for me.
In that case can we rely on the global tc-offload on/off flag
provided by ethtool? (I understand its not the same, but perhaps
it is sufficient in practice.)
ok.
So: I think i have seen this what is probably the spamming refered
with the intel (800?) driver ;-> Basically driver was reacting to
all filters regardless of need to offload or not.
I thought it was an oversight on their part and the driver needed
fixing. Are we invoking the offload regardless of whether h/w offload
is requested? In my naive view - at least when i looked at the intel
code - it didnt seem hard to avoid the spamming.
There is a per-netdev (not global as I wrote above) flag to enable and
disable offload. And there is per-classifier skip_hw flag. I can dig
through the code as easily as you can but I'd be surprised if the
driver is seeing offload requests if either of those settings
are in effect.
For sure it was the 800 (Ice driver if you want to dig into the code).
I think the ethtool flag was turned on but not skip_sw in the policy. I
dont have the card installed in any board right now - either will go and
dig into the logs (because it spews the message into the logs).
Again not clear if this is what Vlad was calling spam.
quoted
quoted
quoted
quoted
I was looking at it more as a (currently missing) feature improvement.
We already have a use case that is implemented by s/w today. The feature
mimics it in h/w.

At minimal all existing NICs should be able to support the counters
as mapped to simple actions like drop. I understand for example if some
cant support adding separately offloading of tunnels for example.
So the syntax is something along the lines of:

tc actions add action drop index 15 skip_sw
tc filter add dev ...parent ... protocol ip prio X ..\
u32/flower skip_sw match ... flowid 1:10 action gact index 15

You get an error if counter index 15 is not offloaded or
if skip_sw was left out..

And then later on, if you support sharing of actions:
tc filter add dev ...parent ... protocol ip prio X2 ..\
u32/flower skip_sw match ... flowid 1:10 action gact index 15
Right, I understand that makes sense and is internally consistent.
But I think that in practice it only makes a difference "Approach B"
implementations, none of which currently exist.
At minimal:
Shouldnt counters (easily correlated to basic actions like drop or
accept) fit the scenario of:
tc actions add action drop index 15 skip_sw
tc filter add dev ...parent ... protocol ip prio X .. \
u32/flower skip_sw match ... flowid 1:10 action gact index 15

?
quoted
I would suggest we can add this when the need arises, rather than
speculatively without hw/driver support. Its not precluded by the current
model AFAIK.
We are going to work on a driver that would have the "B" approach.
I am hoping - whatever the consensus here - it doesnt require a
surgery afterwards to make that work.
You should be able to build on the work proposed here to add what you
suggest into the framework to meet these requirements for your driver work.
Then we are good. These are the same patches you have here?

cheers,
jamal

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Vlad Buslov <hidden>
Date: 2021-07-30 11:41:02

On Fri 30 Jul 2021 at 13:17, Jamal Hadi Salim [off-list ref] wrote:
On 2021-07-28 10:46 a.m., Simon Horman wrote:
quoted
On Wed, Jul 28, 2021 at 09:51:00AM -0400, Jamal Hadi Salim wrote:
quoted
On 2021-07-28 3:46 a.m., Simon Horman wrote:
quoted
On Tue, Jul 27, 2021 at 07:47:43PM +0300, Vlad Buslov wrote:
quoted
On Tue 27 Jul 2021 at 19:13, Jamal Hadi Salim [off-list ref] wrote:
quoted
On 2021-07-27 10:38 a.m., Vlad Buslov wrote:
quoted
On Tue 27 Jul 2021 at 16:04, Simon Horman [off-list ref] wrote:
[..]
quoted
quoted
quoted
quoted
I think we have the same issue with filters - they might not be in
hardware after driver callback returned "success" (due to neigh state
being invalid for tunnel_key encap, for example).
Sounds like we need another state for this. Otherwise, how do you debug
that something is sitting in the driver and not in hardware after you
issued a command to offload it? How do i tell today?
Also knowing reason why something is sitting in the driver would be
helpful.
It is not about just adding another state. The issue is that there is no
way for drivers to change the state of software filter dynamically.
I think it might be worth considering enhancing things at some point.
But I agree that its more than a matter of adding an extra flag. And
I think it's reasonable to implement something similar to the classifier
current offload handling of IN_HW now and consider enhancements separately.
Debugability is very important. If we have such gotchas we need to have
the admin at least be able to tell if the driver returns "success"
and the request is still sitting in the driver for whatever reason
At minimal there needs to be some indicator somewhere which say
"inprogress" or "waiting for resolution" etc.
If the control plane(user space app) starts making other decisions
based on assumptions that filter was successfully installed i.e
packets are being treated in the hardware then there could be
consequences when this assumption is wrong.

So if i undestood the challenge correctly it is: how do you relay
this info back so it is reflected in the filter details. Yes that
would require some mechanism to exist and possibly mapping state
between whats in the driver and in the cls layer.
If i am not mistaken, the switchdev folks handle this asynchronicty?
+Cc Ido, Jiri, Roopa

And it should be noted that: Yes, the filters have this
pre-existing condition but doesnt mean given the opportunity
to do actions we should replicate what they do.
I'd prefer symmetry between the use of IN_HW for filters and actions,
which I believe is what Vlad has suggested.
It still not clear to me what it means from a command line pov.
How do i add a rule and when i dump it what does it show?
quoted
If we wish to enhance things - f.e. for debugging, which I
agree is important - then I think that is a separate topic.
My only concern is not to repeat mistakes that are in filters
just for the sake of symmetry. Example the fact that something
went wrong with insertion or insertion is still in progress
and you get an indication that all went well.
Looking at mlnx (NIC) ndrivers it does seem that in the normal case
the insertion into hw is synchronous (for anything that is not sw
only). I didnt quiet see what Vlad was referring to.
Filters with tunnel_key encap actions can be offloaded/unoffloaded
dynamically based on neigh state (see mlx5e_rep_neigh_update()) and fib
events (see mlx5e_tc_fib_event_work()).

[...]

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Simon Horman <hidden>
Date: 2021-07-30 13:20:16

On Fri, Jul 30, 2021 at 06:17:18AM -0400, Jamal Hadi Salim wrote:
On 2021-07-28 10:46 a.m., Simon Horman wrote:
quoted
On Wed, Jul 28, 2021 at 09:51:00AM -0400, Jamal Hadi Salim wrote:
quoted
On 2021-07-28 3:46 a.m., Simon Horman wrote:
quoted
On Tue, Jul 27, 2021 at 07:47:43PM +0300, Vlad Buslov wrote:
quoted
On Tue 27 Jul 2021 at 19:13, Jamal Hadi Salim [off-list ref] wrote:
quoted
On 2021-07-27 10:38 a.m., Vlad Buslov wrote:
quoted
On Tue 27 Jul 2021 at 16:04, Simon Horman [off-list ref] wrote:
[..]
quoted
quoted
quoted
quoted
I think we have the same issue with filters - they might not be in
hardware after driver callback returned "success" (due to neigh state
being invalid for tunnel_key encap, for example).
Sounds like we need another state for this. Otherwise, how do you debug
that something is sitting in the driver and not in hardware after you
issued a command to offload it? How do i tell today?
Also knowing reason why something is sitting in the driver would be
helpful.
It is not about just adding another state. The issue is that there is no
way for drivers to change the state of software filter dynamically.
I think it might be worth considering enhancing things at some point.
But I agree that its more than a matter of adding an extra flag. And
I think it's reasonable to implement something similar to the classifier
current offload handling of IN_HW now and consider enhancements separately.
Debugability is very important. If we have such gotchas we need to have
the admin at least be able to tell if the driver returns "success"
and the request is still sitting in the driver for whatever reason
At minimal there needs to be some indicator somewhere which say
"inprogress" or "waiting for resolution" etc.
If the control plane(user space app) starts making other decisions
based on assumptions that filter was successfully installed i.e
packets are being treated in the hardware then there could be
consequences when this assumption is wrong.

So if i undestood the challenge correctly it is: how do you relay
this info back so it is reflected in the filter details. Yes that
would require some mechanism to exist and possibly mapping state
between whats in the driver and in the cls layer.
If i am not mistaken, the switchdev folks handle this asynchronicty?
+Cc Ido, Jiri, Roopa

And it should be noted that: Yes, the filters have this
pre-existing condition but doesnt mean given the opportunity
to do actions we should replicate what they do.
I'd prefer symmetry between the use of IN_HW for filters and actions,
which I believe is what Vlad has suggested.
It still not clear to me what it means from a command line pov.
How do i add a rule and when i dump it what does it show?
How about we confirm that once we've implemented the feature.

But I would assume that:

* Existing methods for adding rules work as before
* When one dumps an action (in a sufficiently verbose
  way) the in_hw and in_hw_counter fields are displayed as they are for
  filters.

Does that help?
quoted
If we wish to enhance things - f.e. for debugging, which I
agree is important - then I think that is a separate topic.
My only concern is not to repeat mistakes that are in filters
just for the sake of symmetry. Example the fact that something
went wrong with insertion or insertion is still in progress
and you get an indication that all went well.
Looking at mlnx (NIC) ndrivers it does seem that in the normal case
the insertion into hw is synchronous (for anything that is not sw
only). I didnt quiet see what Vlad was referring to.
We have spent literally hours debugging issues where rules are being
offloaded thinking it was the driver so any extra info helps.
I do think there is a value to symmetry between the APIs.
And I don't think doing so moves things in a bad direction.
But rather a separate discussion is needed to discuss how to
improve debuggability.

...
quoted
quoted
quoted
quoted
quoted
I was looking at it more as a (currently missing) feature improvement.
We already have a use case that is implemented by s/w today. The feature
mimics it in h/w.

At minimal all existing NICs should be able to support the counters
as mapped to simple actions like drop. I understand for example if some
cant support adding separately offloading of tunnels for example.
So the syntax is something along the lines of:

tc actions add action drop index 15 skip_sw
tc filter add dev ...parent ... protocol ip prio X ..\
u32/flower skip_sw match ... flowid 1:10 action gact index 15

You get an error if counter index 15 is not offloaded or
if skip_sw was left out..

And then later on, if you support sharing of actions:
tc filter add dev ...parent ... protocol ip prio X2 ..\
u32/flower skip_sw match ... flowid 1:10 action gact index 15
Right, I understand that makes sense and is internally consistent.
But I think that in practice it only makes a difference "Approach B"
implementations, none of which currently exist.
At minimal:
Shouldnt counters (easily correlated to basic actions like drop or
accept) fit the scenario of:
tc actions add action drop index 15 skip_sw
tc filter add dev ...parent ... protocol ip prio X .. \
u32/flower skip_sw match ... flowid 1:10 action gact index 15

?
quoted
I would suggest we can add this when the need arises, rather than
speculatively without hw/driver support. Its not precluded by the current
model AFAIK.
We are going to work on a driver that would have the "B" approach.
I am hoping - whatever the consensus here - it doesnt require a
surgery afterwards to make that work.
You should be able to build on the work proposed here to add what you
suggest into the framework to meet these requirements for your driver work.
Then we are good. These are the same patches you have here?
Yes.

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Jamal Hadi Salim <jhs@mojatatu.com>
Date: 2021-08-03 09:58:00

On 2021-07-30 7:40 a.m., Vlad Buslov wrote:
On Fri 30 Jul 2021 at 13:17, Jamal Hadi Salim [off-list ref] wrote:
quoted
On 2021-07-28 10:46 a.m., Simon Horman wrote:
Filters with tunnel_key encap actions can be offloaded/unoffloaded
dynamically based on neigh state (see mlx5e_rep_neigh_update()) and fib
events (see mlx5e_tc_fib_event_work()).
Thanks. Will look and compare against the FIB case.

cheers,
jamal

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Jamal Hadi Salim <jhs@mojatatu.com>
Date: 2021-08-03 10:14:13

On 2021-07-30 9:20 a.m., Simon Horman wrote:
On Fri, Jul 30, 2021 at 06:17:18AM -0400, Jamal Hadi Salim wrote:
quoted
On 2021-07-28 10:46 a.m., Simon Horman wrote:
[..]
quoted
It still not clear to me what it means from a command line pov.
How do i add a rule and when i dump it what does it show?
How about we confirm that once we've implemented the feature.

But I would assume that:

* Existing methods for adding rules work as before
* When one dumps an action (in a sufficiently verbose
   way) the in_hw and in_hw_counter fields are displayed as they are for
   filters.

Does that help?
I think it would help a lot more to say explicitly what it actually
means in the cover letter from a tc cli pov since the subject
is about offloading actions _independently_ of filters.
I am assuming you have some more patches on top of these that
actually will actually work for that.

Example of something you could show was adding a policer,
like so:

tc actions add action ... skip_sw...

then show get or dump showing things in h/w.
And del..

And i certainly hope that the above works and it is
not meant just for the consumption of some OVS use
case.
quoted
quoted
If we wish to enhance things - f.e. for debugging, which I
agree is important - then I think that is a separate topic.
My only concern is not to repeat mistakes that are in filters
just for the sake of symmetry. Example the fact that something
went wrong with insertion or insertion is still in progress
and you get an indication that all went well.
Looking at mlnx (NIC) ndrivers it does seem that in the normal case
the insertion into hw is synchronous (for anything that is not sw
only). I didnt quiet see what Vlad was referring to.
We have spent literally hours debugging issues where rules are being
offloaded thinking it was the driver so any extra info helps.
I do think there is a value to symmetry between the APIs.
And I don't think doing so moves things in a bad direction.
But rather a separate discussion is needed to discuss how to
improve debuggability.
Fair enough - lets have a separate discussion on debug-ability.
Maybe a new thread after reviewing Vlad's pointer.
quoted
quoted
You should be able to build on the work proposed here to add what you
suggest into the framework to meet these requirements for your driver work.
Then we are good. These are the same patches you have here?
Yes.
Thanks - will review with that in mind.

cheers,
jamal

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Jamal Hadi Salim <jhs@mojatatu.com>
Date: 2021-08-03 10:51:09

On 2021-07-22 5:19 a.m., Simon Horman wrote:
From: Baowen Zheng <redacted>

Use flow_indr_dev_register/flow_indr_dev_setup_offload to
offload tc action.

We offload the tc action mainly for ovs meter configuration.
Make some basic changes for different vendors to return EOPNOTSUPP.

We need to call tc_cleanup_flow_action to clean up tc action entry since
in tc_setup_action, some actions may hold dev refcnt, especially the mirror
action.

[..]
quoted hunk
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -1060,6 +1060,36 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
  	return ERR_PTR(err);
  }
  
+/* offload the tc command after inserted */
+int tcf_action_offload_cmd(struct tc_action *actions[],
+			   struct netlink_ext_ack *extack)
+{
+	struct flow_offload_action *fl_act;
+	int err = 0;
+
+	fl_act = flow_action_alloc(tcf_act_num_actions(actions));
+	if (!fl_act)
+		return -ENOMEM;
+
+	fl_act->extack = extack;
+	err = tc_setup_action(&fl_act->action, actions);
+	if (err) {
+		NL_SET_ERR_MSG_MOD(extack,
+				   "Failed to setup tc actions for offload\n");
+		goto err_out;
+	}
+	fl_act->command = FLOW_ACT_REPLACE;
+
The fn name is a bit misleading with _cmd suffix when it is
only targeting one command: REPLACE (and not the other two).

cheers,
jamal

Re: [PATCH net-next 2/3] flow_offload: add process to delete offloaded actions from net device

From: Jamal Hadi Salim <jhs@mojatatu.com>
Date: 2021-08-03 10:59:19

On 2021-07-22 5:19 a.m., Simon Horman wrote:

[..]

quoted hunk
  tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
  	      u32 portid, int event, struct netlink_ext_ack *extack)
  {
-	int i, ret;
  	struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
  	struct tc_action *act;
  	size_t attr_size = 0;
  	struct tc_action *actions[TCA_ACT_MAX_PRIO] = {};
+	struct flow_offload_action *fl_act;
+	int i, ret, fallback_num;
  
  	ret = nla_parse_nested_deprecated(tb, TCA_ACT_MAX_PRIO, nla, NULL,
  					  extack);
@@ -1492,7 +1568,9 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
  	if (event == RTM_GETACTION)
  		ret = tcf_get_notify(net, portid, n, actions, event, extack);
  	else { /* delete */
-		ret = tcf_del_notify(net, n, actions, portid, attr_size, extack);
+		tcf_action_offload_cmd_pre(actions, FLOW_ACT_DESTROY, extack, &fl_act);
+		ret = tcf_del_notify(net, n, actions, portid, attr_size, extack, &fallback_num);
+		tcf_action_offload_del_post(fl_act, actions, extack, fallback_num);
  		if (ret)
  			goto err;
It is hard to read from a patch context, but iiuc:
if the hardware update fails in tcf_action_offload_del_post() then
user space would still have been notified that it succeeded via
tcf_del_notify()... and there is no remediation after the fact.


cheers,
jamal

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Jamal Hadi Salim <jhs@mojatatu.com>
Date: 2021-08-03 11:05:57

On 2021-07-22 5:19 a.m., Simon Horman wrote:

Triggered by my observation on 2/3 went back and looked at this again to
see if we have same problem with notification on REPLACE case (I think
we do) but here's another comment:
quoted hunk
+EXPORT_SYMBOL(tcf_action_offload_cmd);
+
  /* Returns numbers of initialized actions or negative error. */
  
  int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
@@ -1514,6 +1544,9 @@ static int tcf_action_add(struct net *net, struct nlattr *nla,
  		return ret;
  	ret = tcf_add_notify(net, n, actions, portid, attr_size, extack);
  
+	/* offload actions to hardware if possible */
+	tcf_action_offload_cmd(actions, extack);
+
Above seems to be unconditional whether hw update is requested or not?
The comment says the right thing ("if possible") but the code
should have checked some sort of skip_sw check?

cheers,
jamal

Re: [PATCH net-next 3/3] flow_offload: add process to update action stats from hardware

From: Jamal Hadi Salim <jhs@mojatatu.com>
Date: 2021-08-03 11:24:51

On 2021-07-22 5:19 a.m., Simon Horman wrote:

[..]
quoted hunk
  /* offload the tc command after deleted */
  int tcf_action_offload_del_post(struct flow_offload_action *fl_act,
  				struct tc_action *actions[],
@@ -1255,6 +1293,9 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *p,
  	if (p == NULL)
  		goto errout;
  
+	/* update hw stats for this action */
+	tcf_action_update_hw_stats(p);
This is more a curiosity than a comment on the patch: Is the
driver polling for these stats synchronously and what we get here
is the last update or do we end up invoking beyond
the driver when requesting for the stats?

Overall commentary from looking at the patch set:
I believe your patches will support the individual tc actions
add/del/get/dump command line requests.
What is missing is an example usage all the way to the driver. I am sure
you have additional patches that put this to good  use. My suggestion
is to test that cli with that pov against your overall patches and
show this in your commit logs - even if those patches are to follow
later.


cheers,
jamal

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Simon Horman <hidden>
Date: 2021-08-03 11:31:11

On Tue, Aug 03, 2021 at 07:05:52AM -0400, Jamal Hadi Salim wrote:
On 2021-07-22 5:19 a.m., Simon Horman wrote:

Triggered by my observation on 2/3 went back and looked at this again to
see if we have same problem with notification on REPLACE case (I think
we do) but here's another comment:
quoted
+EXPORT_SYMBOL(tcf_action_offload_cmd);
+
  /* Returns numbers of initialized actions or negative error. */
  int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
@@ -1514,6 +1544,9 @@ static int tcf_action_add(struct net *net, struct nlattr *nla,
  		return ret;
  	ret = tcf_add_notify(net, n, actions, portid, attr_size, extack);
+	/* offload actions to hardware if possible */
+	tcf_action_offload_cmd(actions, extack);
+
Above seems to be unconditional whether hw update is requested or not?
The comment says the right thing ("if possible") but the code
should have checked some sort of skip_sw check?
Jamal, we are going around in circles.

As we have already discussed, this patchset does not add support for
skip_sw (or skip_hw) for actions.

Re: [PATCH net-next 3/3] flow_offload: add process to update action stats from hardware

From: Simon Horman <hidden>
Date: 2021-08-03 11:35:35

On Tue, Aug 03, 2021 at 07:24:47AM -0400, Jamal Hadi Salim wrote:
On 2021-07-22 5:19 a.m., Simon Horman wrote:

[..]
quoted
  /* offload the tc command after deleted */
  int tcf_action_offload_del_post(struct flow_offload_action *fl_act,
  				struct tc_action *actions[],
@@ -1255,6 +1293,9 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *p,
  	if (p == NULL)
  		goto errout;
+	/* update hw stats for this action */
+	tcf_action_update_hw_stats(p);
This is more a curiosity than a comment on the patch: Is the
driver polling for these stats synchronously and what we get here
is the last update or do we end up invoking beyond
the driver when requesting for the stats?
I would have to double check but I believe the driver will report
back stats already received from the HW, rather than going all the way
to HW when the above call is made.
Overall commentary from looking at the patch set:
I believe your patches will support the individual tc actions
add/del/get/dump command line requests.
Yes, that is the aim of this patchset.
What is missing is an example usage all the way to the driver. I am sure
you have additional patches that put this to good  use. My suggestion
is to test that cli with that pov against your overall patches and
show this in your commit logs - even if those patches are to follow
later.
Thanks, I'll see about making that so.

Just to be clear. We do have patches for the driver. And we do plan to post
them for inclusion in mainline. But I do believe that from a review
perspective its easier if one thing follows another.

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Simon Horman <hidden>
Date: 2021-08-03 11:37:12

On Tue, Aug 03, 2021 at 06:14:08AM -0400, Jamal Hadi Salim wrote:
On 2021-07-30 9:20 a.m., Simon Horman wrote:
quoted
On Fri, Jul 30, 2021 at 06:17:18AM -0400, Jamal Hadi Salim wrote:
quoted
On 2021-07-28 10:46 a.m., Simon Horman wrote:
[..]
quoted
quoted
It still not clear to me what it means from a command line pov.
How do i add a rule and when i dump it what does it show?
How about we confirm that once we've implemented the feature.

But I would assume that:

* Existing methods for adding rules work as before
* When one dumps an action (in a sufficiently verbose
   way) the in_hw and in_hw_counter fields are displayed as they are for
   filters.

Does that help?
I think it would help a lot more to say explicitly what it actually
means in the cover letter from a tc cli pov since the subject
is about offloading actions _independently_ of filters.
I am assuming you have some more patches on top of these that
actually will actually work for that.

Example of something you could show was adding a policer,
like so:

tc actions add action ... skip_sw...

then show get or dump showing things in h/w.
And del..

And i certainly hope that the above works and it is
not meant just for the consumption of some OVS use
case.
I agree it would be useful to include a tc cli example in the cover letter.
I'll see about making that so in v2.

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Jamal Hadi Salim <jhs@mojatatu.com>
Date: 2021-08-03 11:47:40

On 2021-08-03 7:36 a.m., Simon Horman wrote:
On Tue, Aug 03, 2021 at 06:14:08AM -0400, Jamal Hadi Salim wrote:
quoted
On 2021-07-30 9:20 a.m., Simon Horman wrote:
[..]
quoted
Example of something you could show was adding a policer,
like so:

tc actions add action ... skip_sw...

then show get or dump showing things in h/w.
And del..

And i certainly hope that the above works and it is
not meant just for the consumption of some OVS use
case.
I agree it would be useful to include a tc cli example in the cover letter.
I'll see about making that so in v2.
Thanks. That will remove 95% of my commentary.
Check my other comment on the user space notification.
I was just looking at the way classifiers handle things from this
perspective and they dont return to cls_api until completion so
the notification gets sent after both h/w and software succeed...

cheers,
jamal

tc offload debug-ability

From: Jamal Hadi Salim <jhs@mojatatu.com>
Date: 2021-08-03 12:02:32

I just changed the subject line..

On 2021-08-03 5:57 a.m., Jamal Hadi Salim wrote:
On 2021-07-30 7:40 a.m., Vlad Buslov wrote:
quoted
On Fri 30 Jul 2021 at 13:17, Jamal Hadi Salim [off-list ref] wrote:
quoted
On 2021-07-28 10:46 a.m., Simon Horman wrote:
quoted
Filters with tunnel_key encap actions can be offloaded/unoffloaded
dynamically based on neigh state (see mlx5e_rep_neigh_update()) and fib
events (see mlx5e_tc_fib_event_work()).
Thanks. Will look and compare against the FIB case.
So unless i am mistaken Vlad:
a) there is no way to reflect the  details when someone dumps the rules.
b) No notifications sent to the control plane (user space) when the
neighbor updates are offloaded.

My comments earlier are inspired by debugging tc offload and by this:

https://patches.linaro.org/cover/378345/

cheers,
jamal

Re: tc offload debug-ability

From: Vlad Buslov <hidden>
Date: 2021-08-03 12:15:10

On Tue 03 Aug 2021 at 15:02, Jamal Hadi Salim [off-list ref] wrote:
I just changed the subject line..

On 2021-08-03 5:57 a.m., Jamal Hadi Salim wrote:
quoted
On 2021-07-30 7:40 a.m., Vlad Buslov wrote:
quoted
On Fri 30 Jul 2021 at 13:17, Jamal Hadi Salim [off-list ref] wrote:
quoted
On 2021-07-28 10:46 a.m., Simon Horman wrote:
quoted
Filters with tunnel_key encap actions can be offloaded/unoffloaded
dynamically based on neigh state (see mlx5e_rep_neigh_update()) and fib
events (see mlx5e_tc_fib_event_work()).
Thanks. Will look and compare against the FIB case.
So unless i am mistaken Vlad:
a) there is no way to reflect the  details when someone dumps the rules.
b) No notifications sent to the control plane (user space) when the
neighbor updates are offloaded.
Correct.
My comments earlier are inspired by debugging tc offload and by this:

https://patches.linaro.org/cover/378345/

cheers,
jamal

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Simon Horman <hidden>
Date: 2021-08-03 12:32:09

On Tue, Aug 03, 2021 at 07:45:13AM -0400, Jamal Hadi Salim wrote:
On 2021-08-03 7:36 a.m., Simon Horman wrote:
quoted
On Tue, Aug 03, 2021 at 06:14:08AM -0400, Jamal Hadi Salim wrote:
quoted
On 2021-07-30 9:20 a.m., Simon Horman wrote:
[..]
quoted
quoted
Example of something you could show was adding a policer,
like so:

tc actions add action ... skip_sw...

then show get or dump showing things in h/w.
And del..

And i certainly hope that the above works and it is
not meant just for the consumption of some OVS use
case.
I agree it would be useful to include a tc cli example in the cover letter.
I'll see about making that so in v2.
Thanks. That will remove 95% of my commentary.
:)
Check my other comment on the user space notification.
I was just looking at the way classifiers handle things from this
perspective and they dont return to cls_api until completion so
the notification gets sent after both h/w and software succeed...
Thanks, I will look into this. But it would make my life slightly easier if

a) You could be more specific about what portion of cls_api you are
   referring to.
b) Constrained comments to a topic to a single sub-thread.

Re: tc offload debug-ability

From: Jamal Hadi Salim <jhs@mojatatu.com>
Date: 2021-08-03 12:50:32

On 2021-08-03 8:14 a.m., Vlad Buslov wrote:
On Tue 03 Aug 2021 at 15:02, Jamal Hadi Salim [off-list ref] wrote:
[..]
quoted
So unless i am mistaken Vlad:
a) there is no way to reflect the  details when someone dumps the rules.
b) No notifications sent to the control plane (user space) when the
neighbor updates are offloaded.
Correct.
Feels like we can adopt the same mechanics. Although, unless i am
misreading, it seems Ido's patches cover a slightly different use
case: not totally synchronous in successfully pushing the rule to
hardware i.e could be sitting somewhere in firmware on its way to
the ASIC (and at least your connectx driver seems to only be
relinquishing control after confirming the update succeeded).
Am i mistaken Ido?


cheers,
jamal

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Jamal Hadi Salim <jhs@mojatatu.com>
Date: 2021-08-03 13:01:50

On 2021-08-03 8:31 a.m., Simon Horman wrote:
On Tue, Aug 03, 2021 at 07:45:13AM -0400, Jamal Hadi Salim wrote:
Thanks, I will look into this. But it would make my life slightly easier if

a) You could be more specific about what portion of cls_api you are
    referring to.
b) Constrained comments to a topic to a single sub-thread.
Context, this was on the comment i made on 2/3 here:

-----
-        ret = tcf_del_notify(net, n, actions, portid, attr_size, extack);
+        tcf_action_offload_cmd_pre(actions, FLOW_ACT_DESTROY, extack, 
&fl_act);
+        ret = tcf_del_notify(net, n, actions, portid, attr_size, 
extack, &fallback_num);
+        tcf_action_offload_del_post(fl_act, actions, extack, fallback_num);
           if (ret)
               goto err;
----

where a notification goes to user space to say "success" but hardware
update fails.

If you look at fl_change() which does the offload you'll see that it
returns err on any of sw or hw failure (depending on request).
Notification of success is done in cls_api.c - example for 
creating/replacing with this snippet:

---
         err = tp->ops->change(net, skb, tp, cl, t->tcm_handle, tca, &fh,
                               flags, extack);
         if (err == 0) {
                 tfilter_notify(net, skb, n, tp, block, q, parent, fh,
                                RTM_NEWTFILTER, false, rtnl_held);
                 tfilter_put(tp, fh);
                 /* q pointer is NULL for shared blocks */
                 if (q)
                         q->flags &= ~TCQ_F_CAN_BYPASS;
         }
---

cheers,
jamal

Re: tc offload debug-ability

From: Ido Schimmel <idosch@nvidia.com>
Date: 2021-08-03 13:36:49

On Tue, Aug 03, 2021 at 08:50:27AM -0400, Jamal Hadi Salim wrote:
On 2021-08-03 8:14 a.m., Vlad Buslov wrote:
quoted
On Tue 03 Aug 2021 at 15:02, Jamal Hadi Salim [off-list ref] wrote:
[..]
quoted
quoted
So unless i am mistaken Vlad:
a) there is no way to reflect the  details when someone dumps the rules.
b) No notifications sent to the control plane (user space) when the
neighbor updates are offloaded.
Correct.
Feels like we can adopt the same mechanics. Although, unless i am
misreading, it seems Ido's patches cover a slightly different use
case: not totally synchronous in successfully pushing the rule to
hardware i.e could be sitting somewhere in firmware on its way to
the ASIC (and at least your connectx driver seems to only be
relinquishing control after confirming the update succeeded).
Am i mistaken Ido?
It is simply that all routes are notified from an atomic context, which
means installation to hardware needs to be deferred. But even if we
solve this case, there are other cases that cannot be solved.

For example, in IPv6 routes can be installed in response to RA packets
from softIRQ context. As another example, you can have several routes
with the same key already installed in the kernel, but only the one with
the lowest metric will be installed in hardware. Once it is deleted (for
example, in response to a netdev event), the kernel will try to install
the route with the higher metric. As a user, you want to get a
notification if this operation failed.

The same problem exists with tc actions, not sure about classifiers. For
example, we can mirror to a gretap to emulate ERSPAN. The hardware
expects all the headers to be specified, which means the path towards
the remote IP must be resolved in the kernel. Due to FIB/neigh/FDB
events it can obviously change, which means that the validity of the
action in hardware (not the classifier) changes over time with zero
visibility to user space.

So I believe that we need to be able to notify user space about the
state of the action. Whether it is in hardware / not in hardware /
failed to be installed to hardware.

cheers,
jamal

Re: [PATCH net-next 1/3] flow_offload: allow user to offload tc action to net device

From: Simon Horman <hidden>
Date: 2021-08-03 14:47:59

On Tue, Aug 03, 2021 at 09:01:45AM -0400, Jamal Hadi Salim wrote:
On 2021-08-03 8:31 a.m., Simon Horman wrote:
quoted
On Tue, Aug 03, 2021 at 07:45:13AM -0400, Jamal Hadi Salim wrote:
quoted
Thanks, I will look into this. But it would make my life slightly easier if

a) You could be more specific about what portion of cls_api you are
    referring to.
b) Constrained comments to a topic to a single sub-thread.
Context, this was on the comment i made on 2/3 here:

-----
-        ret = tcf_del_notify(net, n, actions, portid, attr_size, extack);
+        tcf_action_offload_cmd_pre(actions, FLOW_ACT_DESTROY, extack,
&fl_act);
+        ret = tcf_del_notify(net, n, actions, portid, attr_size, extack,
&fallback_num);
+        tcf_action_offload_del_post(fl_act, actions, extack, fallback_num);
          if (ret)
              goto err;
----

where a notification goes to user space to say "success" but hardware
update fails.

If you look at fl_change() which does the offload you'll see that it
returns err on any of sw or hw failure (depending on request).
Notification of success is done in cls_api.c - example for
creating/replacing with this snippet:

---
        err = tp->ops->change(net, skb, tp, cl, t->tcm_handle, tca, &fh,
                              flags, extack);
        if (err == 0) {
                tfilter_notify(net, skb, n, tp, block, q, parent, fh,
                               RTM_NEWTFILTER, false, rtnl_held);
                tfilter_put(tp, fh);
                /* q pointer is NULL for shared blocks */
                if (q)
                        q->flags &= ~TCQ_F_CAN_BYPASS;
        }
---
Thanks for the context Jamal, much appreciated.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help