diff mbox series

[v6,net-next,08/12] flow_offload: add process to update action stats from hardware

Message ID 20211209092806.12336-9-simon.horman@corigine.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series allow user to offload tc action to net device | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 65 this patch: 65
netdev/cc_maintainers warning 2 maintainers not CCed: kuba@kernel.org davem@davemloft.net
netdev/build_clang success Errors and warnings before: 28 this patch: 28
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 78 this patch: 78
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 81 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Simon Horman Dec. 9, 2021, 9:28 a.m. UTC
From: Baowen Zheng <baowen.zheng@corigine.com>

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

Stats update process should not run in context of preempt_disable.

Signed-off-by: Baowen Zheng <baowen.zheng@corigine.com>
Signed-off-by: Louis Peens <louis.peens@corigine.com>
Signed-off-by: Simon Horman <simon.horman@corigine.com>
---
 include/net/act_api.h |  1 +
 include/net/pkt_cls.h | 18 ++++++++++--------
 net/sched/act_api.c   | 34 ++++++++++++++++++++++++++++++++++
 3 files changed, 45 insertions(+), 8 deletions(-)

Comments

Jamal Hadi Salim Dec. 11, 2021, 7:52 p.m. UTC | #1
On 2021-12-09 04:28, Simon Horman wrote:
> include/net/act_api.h |  1 +
>   include/net/pkt_cls.h | 18 ++++++++++--------
>   net/sched/act_api.c   | 34 ++++++++++++++++++++++++++++++++++
>   3 files changed, 45 insertions(+), 8 deletions(-)
> 
> diff --git a/include/net/act_api.h b/include/net/act_api.h
> index 7e4e79b50216..ce094e79f722 100644
> --- a/include/net/act_api.h
> +++ b/include/net/act_api.h
> @@ -253,6 +253,7 @@ 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,
>   			     struct netlink_ext_ack *newchain);
> diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
> index 13f0e4a3a136..1942fe72b3e3 100644
> --- a/include/net/pkt_cls.h
> +++ b/include/net/pkt_cls.h
> @@ -269,18 +269,20 @@ tcf_exts_stats_update(const struct tcf_exts *exts,
>   #ifdef CONFIG_NET_CLS_ACT
>   	int i;
>   
> -	preempt_disable();
> -
>   	for (i = 0; i < exts->nr_actions; i++) {
>   		struct tc_action *a = exts->actions[i];
>   
> -		tcf_action_stats_update(a, bytes, packets, drops,
> -					lastuse, true);
> -		a->used_hw_stats = used_hw_stats;
> -		a->used_hw_stats_valid = used_hw_stats_valid;
> -	}
> +		/* if stats from hw, just skip */
> +		if (tcf_action_update_hw_stats(a)) {
> +			preempt_disable();
> +			tcf_action_stats_update(a, bytes, packets, drops,
> +						lastuse, true);
> +			preempt_enable();
>   
> -	preempt_enable();
> +			a->used_hw_stats = used_hw_stats;
> +			a->used_hw_stats_valid = used_hw_stats_valid;
> +		}
> +	}
>   #endif
>   }

Sorry - didnt quiet follow this one even after reading to the end.
I may have missed the obvious in the equivalence:
In the old code we did the preempt first then collect. The changed
version only does it if tcf_action_update_hw_stats() is true.

cheers,
jamal
Baowen Zheng Dec. 12, 2021, 9 a.m. UTC | #2
On December 12, 2021 3:52 AM, Jamal Hadi Salim wrote:
>On 2021-12-09 04:28, Simon Horman wrote:
>> include/net/act_api.h |  1 +
>>   include/net/pkt_cls.h | 18 ++++++++++--------
>>   net/sched/act_api.c   | 34 ++++++++++++++++++++++++++++++++++
>>   3 files changed, 45 insertions(+), 8 deletions(-)
>>
>> diff --git a/include/net/act_api.h b/include/net/act_api.h index
>> 7e4e79b50216..ce094e79f722 100644
>> --- a/include/net/act_api.h
>> +++ b/include/net/act_api.h
>> @@ -253,6 +253,7 @@ 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,
>>   			     struct netlink_ext_ack *newchain); diff --git
>> a/include/net/pkt_cls.h b/include/net/pkt_cls.h index
>> 13f0e4a3a136..1942fe72b3e3 100644
>> --- a/include/net/pkt_cls.h
>> +++ b/include/net/pkt_cls.h
>> @@ -269,18 +269,20 @@ tcf_exts_stats_update(const struct tcf_exts *exts,
>>   #ifdef CONFIG_NET_CLS_ACT
>>   	int i;
>>
>> -	preempt_disable();
>> -
>>   	for (i = 0; i < exts->nr_actions; i++) {
>>   		struct tc_action *a = exts->actions[i];
>>
>> -		tcf_action_stats_update(a, bytes, packets, drops,
>> -					lastuse, true);
>> -		a->used_hw_stats = used_hw_stats;
>> -		a->used_hw_stats_valid = used_hw_stats_valid;
>> -	}
>> +		/* if stats from hw, just skip */
>> +		if (tcf_action_update_hw_stats(a)) {
>> +			preempt_disable();
>> +			tcf_action_stats_update(a, bytes, packets, drops,
>> +						lastuse, true);
>> +			preempt_enable();
>>
>> -	preempt_enable();
>> +			a->used_hw_stats = used_hw_stats;
>> +			a->used_hw_stats_valid = used_hw_stats_valid;
>> +		}
>> +	}
>>   #endif
>>   }
>
>Sorry - didnt quiet follow this one even after reading to the end.
>I may have missed the obvious in the equivalence:
>In the old code we did the preempt first then collect. The changed version only
>does it if tcf_action_update_hw_stats() is true.
Hi Jamal, for this change, this is because for the function of tcf_action_update_hw_stats, it will try to retrieve hw stats fron hardware. But in he process of retrieving stats information, the driver may have
Lock or other sleeping function. So we should not call tcf_action_update_hw_stats function in context of preempt_disable.
Actually, since there is no vendor to support update single action stats from hardware, so it is not obvious, we will post our implement support after these patches set. 
Do you think if it make sense?
>
>cheers,
>jamal
Jamal Hadi Salim Dec. 14, 2021, 12:01 p.m. UTC | #3
On 2021-12-12 04:00, Baowen Zheng wrote:
> On December 12, 2021 3:52 AM, Jamal Hadi Salim wrote:
>> On 2021-12-09 04:28, Simon Horman wrote:
>>> include/net/act_api.h |  1 +
>>>    include/net/pkt_cls.h | 18 ++++++++++--------
>>>    net/sched/act_api.c   | 34 ++++++++++++++++++++++++++++++++++
>>>    3 files changed, 45 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/include/net/act_api.h b/include/net/act_api.h index
>>> 7e4e79b50216..ce094e79f722 100644
>>> --- a/include/net/act_api.h
>>> +++ b/include/net/act_api.h
>>> @@ -253,6 +253,7 @@ 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,
>>>    			     struct netlink_ext_ack *newchain); diff --git
>>> a/include/net/pkt_cls.h b/include/net/pkt_cls.h index
>>> 13f0e4a3a136..1942fe72b3e3 100644
>>> --- a/include/net/pkt_cls.h
>>> +++ b/include/net/pkt_cls.h
>>> @@ -269,18 +269,20 @@ tcf_exts_stats_update(const struct tcf_exts *exts,
>>>    #ifdef CONFIG_NET_CLS_ACT
>>>    	int i;
>>>
>>> -	preempt_disable();
>>> -
>>>    	for (i = 0; i < exts->nr_actions; i++) {
>>>    		struct tc_action *a = exts->actions[i];
>>>
>>> -		tcf_action_stats_update(a, bytes, packets, drops,
>>> -					lastuse, true);
>>> -		a->used_hw_stats = used_hw_stats;
>>> -		a->used_hw_stats_valid = used_hw_stats_valid;
>>> -	}
>>> +		/* if stats from hw, just skip */
>>> +		if (tcf_action_update_hw_stats(a)) {
>>> +			preempt_disable();
>>> +			tcf_action_stats_update(a, bytes, packets, drops,
>>> +						lastuse, true);
>>> +			preempt_enable();
>>>
>>> -	preempt_enable();
>>> +			a->used_hw_stats = used_hw_stats;
>>> +			a->used_hw_stats_valid = used_hw_stats_valid;
>>> +		}
>>> +	}
>>>    #endif
>>>    }
>>
>> Sorry - didnt quiet follow this one even after reading to the end.
>> I may have missed the obvious in the equivalence:
>> In the old code we did the preempt first then collect. The changed version only
>> does it if tcf_action_update_hw_stats() is true.
> Hi Jamal, for this change, this is because for the function of tcf_action_update_hw_stats, it will try to retrieve hw stats fron hardware. But in he process of retrieving stats information, the driver may have
> Lock or other sleeping function. So we should not call tcf_action_update_hw_stats function in context of preempt_disable.

Still confused probably because this is one of those functions that
are badly named. Initially i thought that it was useful to call this
function for both offloaded vs non-offloaded stats. But it seems it is
only useful for hw offloaded stats? If so, please consider a patch for
renaming this appropriately for readability.

Regardless, two things:

1) In the old code the last two lines
+			a->used_hw_stats = used_hw_stats;
+			a->used_hw_stats_valid = used_hw_stats_valid;
inside the preempt check and with this they are outside.

This is fine if the only reason we have this function is for h/w
offload.

2) You introduced tcf_action_update_hw_stats() which also does preempt
disable/enable and seems to repeat some of the things you are doing
as well in this function?

> Actually, since there is no vendor to support update single action stats from hardware, so it is not obvious, we will post our implement support after these patches set.
> Do you think if it make sense?

Since you plan to have more patches:
If it doesnt affect your current goals then i would suggest you
leave it to later. The question is, with what you already have
in this patchset, do we get something functional and standalone?

cheers,
jamal





>> cheers,
>> jamal
Baowen Zheng Dec. 14, 2021, 1:43 p.m. UTC | #4
On December 14, 2021 8:01 PM, Jamal Hadi Salim wrote:
>On 2021-12-12 04:00, Baowen Zheng wrote:
>> On December 12, 2021 3:52 AM, Jamal Hadi Salim wrote:
>>> On 2021-12-09 04:28, Simon Horman wrote:
>>>> include/net/act_api.h |  1 +
>>>>    include/net/pkt_cls.h | 18 ++++++++++--------
>>>>    net/sched/act_api.c   | 34 ++++++++++++++++++++++++++++++++++
>>>>    3 files changed, 45 insertions(+), 8 deletions(-)
>>>>
>>>> diff --git a/include/net/act_api.h b/include/net/act_api.h index
>>>> 7e4e79b50216..ce094e79f722 100644
>>>> --- a/include/net/act_api.h
>>>> +++ b/include/net/act_api.h
>>>> @@ -253,6 +253,7 @@ 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,
>>>>    			     struct netlink_ext_ack *newchain); diff --git
>>>> a/include/net/pkt_cls.h b/include/net/pkt_cls.h index
>>>> 13f0e4a3a136..1942fe72b3e3 100644
>>>> --- a/include/net/pkt_cls.h
>>>> +++ b/include/net/pkt_cls.h
>>>> @@ -269,18 +269,20 @@ tcf_exts_stats_update(const struct tcf_exts
>*exts,
>>>>    #ifdef CONFIG_NET_CLS_ACT
>>>>    	int i;
>>>>
>>>> -	preempt_disable();
>>>> -
>>>>    	for (i = 0; i < exts->nr_actions; i++) {
>>>>    		struct tc_action *a = exts->actions[i];
>>>>
>>>> -		tcf_action_stats_update(a, bytes, packets, drops,
>>>> -					lastuse, true);
>>>> -		a->used_hw_stats = used_hw_stats;
>>>> -		a->used_hw_stats_valid = used_hw_stats_valid;
>>>> -	}
>>>> +		/* if stats from hw, just skip */
>>>> +		if (tcf_action_update_hw_stats(a)) {
>>>> +			preempt_disable();
>>>> +			tcf_action_stats_update(a, bytes, packets, drops,
>>>> +						lastuse, true);
>>>> +			preempt_enable();
>>>>
>>>> -	preempt_enable();
>>>> +			a->used_hw_stats = used_hw_stats;
>>>> +			a->used_hw_stats_valid = used_hw_stats_valid;
>>>> +		}
>>>> +	}
>>>>    #endif
>>>>    }
>>>
>>> Sorry - didnt quiet follow this one even after reading to the end.
>>> I may have missed the obvious in the equivalence:
>>> In the old code we did the preempt first then collect. The changed
>>> version only does it if tcf_action_update_hw_stats() is true.
>> Hi Jamal, for this change, this is because for the function of
>> tcf_action_update_hw_stats, it will try to retrieve hw stats fron hardware.
>But in he process of retrieving stats information, the driver may have Lock or
>other sleeping function. So we should not call tcf_action_update_hw_stats
>function in context of preempt_disable.
>
>Still confused probably because this is one of those functions that are badly
>named. Initially i thought that it was useful to call this function for both
>offloaded vs non-offloaded stats. But it seems it is only useful for hw
>offloaded stats? If so, please consider a patch for renaming this appropriately
>for readability.
Yes, it is only for hw offload stats and is used to sync the stats information from the
Offloaded filter to the actions the filter referred to.

We will consider to add a patch to rename this function for readability.
>
>Regardless, two things:
>
>1) In the old code the last two lines
>+			a->used_hw_stats = used_hw_stats;
>+			a->used_hw_stats_valid = used_hw_stats_valid;
>inside the preempt check and with this they are outside.
>
>This is fine if the only reason we have this function is for h/w offload.
>
>2) You introduced tcf_action_update_hw_stats() which also does preempt
>disable/enable and seems to repeat some of the things you are doing as well
>in this function?
As I mentioned above, the function of tcf_exts_stats_update is used to sync the stats
information from the offloaded filter to the actions the filter referred to.
Then the new added function tcf_action_update_hw_stats() is used to sync the stats
Information from the hw device that offloads this action.  So if the action is offloaded
to hw as a single action, then it will not sync the stats from the hw filter.
>
>> Actually, since there is no vendor to support update single action stats from
>hardware, so it is not obvious, we will post our implement support after these
>patches set.
>> Do you think if it make sense?
>
>Since you plan to have more patches:
>If it doesnt affect your current goals then i would suggest you leave it to later.
>The question is, with what you already have in this patchset, do we get
>something functional and standalone?
>
What we will post later to support update single action stats from hardware is code for driver side,
It will mainly implement the flow_offload_act_command of stats an action from hw in driver.

So i think it will proper to post the whole framework code in act_api and cls_api in this series. 
Then when we post the driver patch, we will not need to change the act/cls implement.

WDYT?

>cheers,
>jamal
>
>
>
>
>
>>> cheers,
>>> jamal
Jamal Hadi Salim Dec. 14, 2021, 2:29 p.m. UTC | #5
On 2021-12-14 08:43, Baowen Zheng wrote:
> On December 14, 2021 8:01 PM, Jamal Hadi Salim wrote:
>> On 2021-12-12 04:00, Baowen Zheng wrote:

[..]
>>
>> Still confused probably because this is one of those functions that are badly
>> named. Initially i thought that it was useful to call this function for both
>> offloaded vs non-offloaded stats. But it seems it is only useful for hw
>> offloaded stats? If so, please consider a patch for renaming this appropriately
>> for readability.
> Yes, it is only for hw offload stats and is used to sync the stats information from the
> Offloaded filter to the actions the filter referred to.
> 
> We will consider to add a patch to rename this function for readability.
>>
>> Regardless, two things:
>>
>> 1) In the old code the last two lines
>> +			a->used_hw_stats = used_hw_stats;
>> +			a->used_hw_stats_valid = used_hw_stats_valid;
>> inside the preempt check and with this they are outside.
>>
>> This is fine if the only reason we have this function is for h/w offload.
>>
>> 2) You introduced tcf_action_update_hw_stats() which also does preempt
>> disable/enable and seems to repeat some of the things you are doing as well
>> in this function?
> As I mentioned above, the function of tcf_exts_stats_update is used to sync the stats
> information from the offloaded filter to the actions the filter referred to.
> Then the new added function tcf_action_update_hw_stats() is used to sync the stats
> Information from the hw device that offloads this action.  So if the action is offloaded
> to hw as a single action, then it will not sync the stats from the hw filter.
>>
>>> Actually, since there is no vendor to support update single action stats from
>> hardware, so it is not obvious, we will post our implement support after these
>> patches set.
>>> Do you think if it make sense?
>>
>> Since you plan to have more patches:
>> If it doesnt affect your current goals then i would suggest you leave it to later.
>> The question is, with what you already have in this patchset, do we get
>> something functional and standalone?
>>
> What we will post later to support update single action stats from hardware is code for driver side,
> It will mainly implement the flow_offload_act_command of stats an action from hw in driver.
> 
> So i think it will proper to post the whole framework code in act_api and cls_api in this series.
> Then when we post the driver patch, we will not need to change the act/cls implement.
> 
> WDYT?

ok.

cheers,
jamal
diff mbox series

Patch

diff --git a/include/net/act_api.h b/include/net/act_api.h
index 7e4e79b50216..ce094e79f722 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -253,6 +253,7 @@  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,
 			     struct netlink_ext_ack *newchain);
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index 13f0e4a3a136..1942fe72b3e3 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -269,18 +269,20 @@  tcf_exts_stats_update(const struct tcf_exts *exts,
 #ifdef CONFIG_NET_CLS_ACT
 	int i;
 
-	preempt_disable();
-
 	for (i = 0; i < exts->nr_actions; i++) {
 		struct tc_action *a = exts->actions[i];
 
-		tcf_action_stats_update(a, bytes, packets, drops,
-					lastuse, true);
-		a->used_hw_stats = used_hw_stats;
-		a->used_hw_stats_valid = used_hw_stats_valid;
-	}
+		/* if stats from hw, just skip */
+		if (tcf_action_update_hw_stats(a)) {
+			preempt_disable();
+			tcf_action_stats_update(a, bytes, packets, drops,
+						lastuse, true);
+			preempt_enable();
 
-	preempt_enable();
+			a->used_hw_stats = used_hw_stats;
+			a->used_hw_stats_valid = used_hw_stats_valid;
+		}
+	}
 #endif
 }
 
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 1d469029f2cd..4e309b8e49bb 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -245,6 +245,37 @@  static int tcf_action_offload_add(struct tc_action *action,
 	return err;
 }
 
+int tcf_action_update_hw_stats(struct tc_action *action)
+{
+	struct flow_offload_action fl_act = {};
+	int err;
+
+	if (!tc_act_in_hw(action))
+		return -EOPNOTSUPP;
+
+	err = flow_action_init(&fl_act, action, FLOW_ACT_STATS, NULL);
+	if (err)
+		return err;
+
+	err = tcf_action_offload_cmd(&fl_act, NULL, NULL);
+	if (!err) {
+		preempt_disable();
+		tcf_action_stats_update(action, fl_act.stats.bytes,
+					fl_act.stats.pkts,
+					fl_act.stats.drops,
+					fl_act.stats.lastused,
+					true);
+		preempt_enable();
+		action->used_hw_stats = fl_act.stats.used_hw_stats;
+		action->used_hw_stats_valid = true;
+	} else {
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(tcf_action_update_hw_stats);
+
 static int tcf_action_offload_del(struct tc_action *action)
 {
 	struct flow_offload_action fl_act = {};
@@ -1317,6 +1348,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.
 	 */