diff mbox series

[RFCv5,net-next,02/20] net: introduce operation helpers for netdev features

Message ID 20220324154932.17557-3-shenjian15@huawei.com (mailing list archive)
State RFC
Delegated to: Netdev Maintainers
Headers show
Series net: extend the type of netdev_features_t to bitmap | 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 fail Series longer than 15 patches (and no cover letter)
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit fail Errors and warnings before: 581 this patch: 641
netdev/cc_maintainers warning 1 maintainers not CCed: pabeni@redhat.com
netdev/build_clang fail Errors and warnings before: 463 this patch: 565
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 fail Errors and warnings before: 681 this patch: 525
netdev/checkpatch warning CHECK: Alignment should match open parenthesis CHECK: Macro argument 'ndev' may be better as '(ndev)' to avoid precedence issues CHECK: Please don't use multiple blank lines WARNING: line length of 82 exceeds 80 columns WARNING: line length of 84 exceeds 80 columns WARNING: line length of 89 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

shenjian (K) March 24, 2022, 3:49 p.m. UTC
Introduce a set of bitmap operation helpers for netdev features,
then we can use them to replace the logical operation with them.
As the nic driversare not supposed to modify netdev_features
directly, it also introduces wrappers helpers to this.

The implementation of these helpers are based on the old prototype
of netdev_features_t is still u64. I will rewrite them on the last
patch, when the prototype changes.

Signed-off-by: Jian Shen <shenjian15@huawei.com>
---
 include/linux/netdevice.h | 597 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 597 insertions(+)

Comments

Jakub Kicinski March 25, 2022, 1:09 a.m. UTC | #1
On Thu, 24 Mar 2022 23:49:14 +0800 Jian Shen wrote:
> Introduce a set of bitmap operation helpers for netdev features,
> then we can use them to replace the logical operation with them.
> As the nic driversare not supposed to modify netdev_features
> directly, it also introduces wrappers helpers to this.
> 
> The implementation of these helpers are based on the old prototype
> of netdev_features_t is still u64. I will rewrite them on the last
> patch, when the prototype changes.
> 
> Signed-off-by: Jian Shen <shenjian15@huawei.com>
> ---
>  include/linux/netdevice.h | 597 ++++++++++++++++++++++++++++++++++++++

Please move these helpers to a new header file which won't be included
by netdevice.h and include it at users appropriately.

> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index 7307b9553bcf..0af4b26896d6 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -2295,6 +2295,603 @@ struct net_device {
>  };
>  #define to_net_dev(d) container_of(d, struct net_device, dev)
>  
> +static inline void netdev_features_zero(netdev_features_t *dst)
> +{
> +	*dst = 0;
> +}
> +
> +static inline void netdev_features_fill(netdev_features_t *dst)
> +{
> +	*dst = ~0ULL;
> +}
> +
> +static inline bool netdev_features_empty(const netdev_features_t src)

Don't pass by value something larger than 64 bit.

> +{
> +	return src == 0;
> +}
> +
> +/* helpers for netdev features '==' operation */
> +static inline bool netdev_features_equal(const netdev_features_t src1,
> +					 const netdev_features_t src2)
> +{
> +	return src1 == src2;
> +}

> +/* helpers for netdev features '&=' operation */
> +static inline void
> +netdev_features_direct_and(netdev_features_t *dst,
> +			   const netdev_features_t features)
> +{
> +	*dst = netdev_features_and(*dst, features);
> +}
> +
> +static inline void
> +netdev_active_features_direct_and(struct net_device *ndev,

s/direct_and/mask/ ?

> +				  const netdev_features_t features)
> +{
> +	ndev->active_features = netdev_active_features_and(ndev, features);
> +}

> +
> +/* helpers for netdev features '|' operation */
> +static inline netdev_features_t
> +netdev_features_or(const netdev_features_t a, const netdev_features_t b)
> +{
> +	return a | b;
> +}

> +/* helpers for netdev features '|=' operation */
> +static inline void
> +netdev_features_direct_or(netdev_features_t *dst,

s/direct_or/set/ ?

> +			  const netdev_features_t features)
> +{
> +	*dst = netdev_features_or(*dst, features);
> +}

> +/* helpers for netdev features '^' operation */
> +static inline netdev_features_t
> +netdev_features_xor(const netdev_features_t a, const netdev_features_t b)
> +{
> +	return a ^ b;
> +}

> +/* helpers for netdev features '^=' operation */
> +static inline void
> +netdev_active_features_direct_xor(struct net_device *ndev,

s/direct_xor/toggle/ ?

> +/* helpers for netdev features '& ~' operation */
> +static inline netdev_features_t
> +netdev_features_andnot(const netdev_features_t a, const netdev_features_t b)
> +{
> +	return a & ~b;
> +}

> +static inline void
> +netdev_features_direct_andnot(netdev_features_t *dst,

s/andnot/clear/ ?

> +			     const netdev_features_t features)
> +{
> +	*dst = netdev_features_andnot(*dst, features);
> +}

> +/* helpers for netdev features 'set bit' operation */
> +static inline void netdev_features_set_bit(int nr, netdev_features_t *src)

s/features_set_bit/feature_add/ ?

> +{
> +	*src |= __NETIF_F_BIT(nr);
> +}

> +/* helpers for netdev features 'set bit array' operation */
> +static inline void netdev_features_set_array(const int *array, int array_size,
> +					     netdev_features_t *dst)
> +{
> +	int i;
> +
> +	for (i = 0; i < array_size; i++)
> +		netdev_features_set_bit(array[i], dst);
> +}
> +
> +#define netdev_active_features_set_array(ndev, array, array_size) \
> +		netdev_features_set_array(array, array_size, &ndev->active_features)
> +
> +#define netdev_hw_features_set_array(ndev, array, array_size) \
> +		netdev_features_set_array(array, array_size, &ndev->hw_features)
> +
> +#define netdev_wanted_features_set_array(ndev, array, array_size) \
> +		netdev_features_set_array(array, array_size, &ndev->wanted_features)
> +
> +#define netdev_vlan_features_set_array(ndev, array, array_size) \
> +		netdev_features_set_array(array, array_size, &ndev->vlan_features)
> +
> +#define netdev_hw_enc_features_set_array(ndev, array, array_size) \
> +		netdev_features_set_array(array, array_size, &ndev->hw_enc_features)
> +
> +#define netdev_mpls_features_set_array(ndev, array, array_size) \
> +		netdev_features_set_array(array, array_size, &ndev->mpls_features)
> +
> +#define netdev_gso_partial_features_set_array(ndev, array, array_size) \
> +		netdev_features_set_array(array, array_size, &ndev->gso_partial_features)
> +
> +/* helpers for netdev features 'clear bit' operation */
> +static inline void netdev_features_clear_bit(int nr, netdev_features_t *src)

All the mentions of '_bit' are unnecessary IMHO.
shenjian (K) April 16, 2022, 3:33 a.m. UTC | #2
在 2022/3/25 9:09, Jakub Kicinski 写道:
> On Thu, 24 Mar 2022 23:49:14 +0800 Jian Shen wrote:
>> Introduce a set of bitmap operation helpers for netdev features,
>> then we can use them to replace the logical operation with them.
>> As the nic driversare not supposed to modify netdev_features
>> directly, it also introduces wrappers helpers to this.
>>
>> The implementation of these helpers are based on the old prototype
>> of netdev_features_t is still u64. I will rewrite them on the last
>> patch, when the prototype changes.
>>
>> Signed-off-by: Jian Shen <shenjian15@huawei.com>
>> ---
>>   include/linux/netdevice.h | 597 ++++++++++++++++++++++++++++++++++++++
> Please move these helpers to a new header file which won't be included
> by netdevice.h and include it at users appropriately.
I introduced a new header file "netdev_features_helper",  and moved 
thses helpers
to it.  Some helpers need to include struct  net_device which defined in 
netdevice.h,
but there are also some inline functions in netdevice.h need to use 
these netdev_features
helpers. It's conflicted.

So far I thought 3 ways to solved it, but all of them are not satisfactory.
1) Split netdevice.h, move the definition of struct net_device and its 
relative definitions to
a new header file A( haven't got a reasonable name).  Both the 
netdev_features_helper.h
and the netdevice include A.

2) Split netdevice.h, move the inline functions to a new header file B. 
The netdev_features_helper.h
inlucde netdevice.h, and B include netdev_features_helper.h and 
netdevice.h. All the source files
which using these ininline functions should include B.

3) Split netdevice.h, move the inline functions to to 
netdev_featurer_helper.h. The netdev_features_helper.h
inlucde netdevice.h, All the source files which using these ininline 
functions should include netde_features_helper.h.

I'd like to get more advice to this.

Thanks!
>> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
>> index 7307b9553bcf..0af4b26896d6 100644
>> --- a/include/linux/netdevice.h
>> +++ b/include/linux/netdevice.h
>> @@ -2295,6 +2295,603 @@ struct net_device {
>>   };
>>   #define to_net_dev(d) container_of(d, struct net_device, dev)
>>   
>> +static inline void netdev_features_zero(netdev_features_t *dst)
>> +{
>> +	*dst = 0;
>> +}
>> +
>> +static inline void netdev_features_fill(netdev_features_t *dst)
>> +{
>> +	*dst = ~0ULL;
>> +}
>> +
>> +static inline bool netdev_features_empty(const netdev_features_t src)
> Don't pass by value something larger than 64 bit.
>
>> +{
>> +	return src == 0;
>> +}
>> +
>> +/* helpers for netdev features '==' operation */
>> +static inline bool netdev_features_equal(const netdev_features_t src1,
>> +					 const netdev_features_t src2)
>> +{
>> +	return src1 == src2;
>> +}
>> +/* helpers for netdev features '&=' operation */
>> +static inline void
>> +netdev_features_direct_and(netdev_features_t *dst,
>> +			   const netdev_features_t features)
>> +{
>> +	*dst = netdev_features_and(*dst, features);
>> +}
>> +
>> +static inline void
>> +netdev_active_features_direct_and(struct net_device *ndev,
> s/direct_and/mask/ ?
>
>> +				  const netdev_features_t features)
>> +{
>> +	ndev->active_features = netdev_active_features_and(ndev, features);
>> +}
>> +
>> +/* helpers for netdev features '|' operation */
>> +static inline netdev_features_t
>> +netdev_features_or(const netdev_features_t a, const netdev_features_t b)
>> +{
>> +	return a | b;
>> +}
>> +/* helpers for netdev features '|=' operation */
>> +static inline void
>> +netdev_features_direct_or(netdev_features_t *dst,
> s/direct_or/set/ ?
>
>> +			  const netdev_features_t features)
>> +{
>> +	*dst = netdev_features_or(*dst, features);
>> +}
>> +/* helpers for netdev features '^' operation */
>> +static inline netdev_features_t
>> +netdev_features_xor(const netdev_features_t a, const netdev_features_t b)
>> +{
>> +	return a ^ b;
>> +}
>> +/* helpers for netdev features '^=' operation */
>> +static inline void
>> +netdev_active_features_direct_xor(struct net_device *ndev,
> s/direct_xor/toggle/ ?
>
>> +/* helpers for netdev features '& ~' operation */
>> +static inline netdev_features_t
>> +netdev_features_andnot(const netdev_features_t a, const netdev_features_t b)
>> +{
>> +	return a & ~b;
>> +}
>> +static inline void
>> +netdev_features_direct_andnot(netdev_features_t *dst,
> s/andnot/clear/ ?
>
>> +			     const netdev_features_t features)
>> +{
>> +	*dst = netdev_features_andnot(*dst, features);
>> +}
>> +/* helpers for netdev features 'set bit' operation */
>> +static inline void netdev_features_set_bit(int nr, netdev_features_t *src)
> s/features_set_bit/feature_add/ ?
>
>> +{
>> +	*src |= __NETIF_F_BIT(nr);
>> +}
>> +/* helpers for netdev features 'set bit array' operation */
>> +static inline void netdev_features_set_array(const int *array, int array_size,
>> +					     netdev_features_t *dst)
>> +{
>> +	int i;
>> +
>> +	for (i = 0; i < array_size; i++)
>> +		netdev_features_set_bit(array[i], dst);
>> +}
>> +
>> +#define netdev_active_features_set_array(ndev, array, array_size) \
>> +		netdev_features_set_array(array, array_size, &ndev->active_features)
>> +
>> +#define netdev_hw_features_set_array(ndev, array, array_size) \
>> +		netdev_features_set_array(array, array_size, &ndev->hw_features)
>> +
>> +#define netdev_wanted_features_set_array(ndev, array, array_size) \
>> +		netdev_features_set_array(array, array_size, &ndev->wanted_features)
>> +
>> +#define netdev_vlan_features_set_array(ndev, array, array_size) \
>> +		netdev_features_set_array(array, array_size, &ndev->vlan_features)
>> +
>> +#define netdev_hw_enc_features_set_array(ndev, array, array_size) \
>> +		netdev_features_set_array(array, array_size, &ndev->hw_enc_features)
>> +
>> +#define netdev_mpls_features_set_array(ndev, array, array_size) \
>> +		netdev_features_set_array(array, array_size, &ndev->mpls_features)
>> +
>> +#define netdev_gso_partial_features_set_array(ndev, array, array_size) \
>> +		netdev_features_set_array(array, array_size, &ndev->gso_partial_features)
>> +
>> +/* helpers for netdev features 'clear bit' operation */
>> +static inline void netdev_features_clear_bit(int nr, netdev_features_t *src)
> All the mentions of '_bit' are unnecessary IMHO.
> .
>
Jakub Kicinski April 16, 2022, 7:42 a.m. UTC | #3
On Sat, 16 Apr 2022 11:33:58 +0800 shenjian (K) wrote:
> 在 2022/3/25 9:09, Jakub Kicinski 写道:
> > On Thu, 24 Mar 2022 23:49:14 +0800 Jian Shen wrote:  
> >> Introduce a set of bitmap operation helpers for netdev features,
> >> then we can use them to replace the logical operation with them.
> >> As the nic driversare not supposed to modify netdev_features
> >> directly, it also introduces wrappers helpers to this.
> >>
> >> The implementation of these helpers are based on the old prototype
> >> of netdev_features_t is still u64. I will rewrite them on the last
> >> patch, when the prototype changes.
> >>
> >> Signed-off-by: Jian Shen <shenjian15@huawei.com>
> >> ---
> >>   include/linux/netdevice.h | 597 ++++++++++++++++++++++++++++++++++++++  
> > Please move these helpers to a new header file which won't be included
> > by netdevice.h and include it at users appropriately.  
> I introduced a new header file "netdev_features_helper",  and moved 
> thses helpers
> to it.  Some helpers need to include struct  net_device which defined in 
> netdevice.h,
> but there are also some inline functions in netdevice.h need to use 
> these netdev_features
> helpers. It's conflicted.
> 
> So far I thought 3 ways to solved it, but all of them are not satisfactory.
> 1) Split netdevice.h, move the definition of struct net_device and its 
> relative definitions to
> a new header file A( haven't got a reasonable name).  Both the 
> netdev_features_helper.h
> and the netdevice include A.
> 
> 2) Split netdevice.h, move the inline functions to a new header file B. 
> The netdev_features_helper.h
> inlucde netdevice.h, and B include netdev_features_helper.h and 
> netdevice.h. All the source files
> which using these ininline functions should include B.
> 
> 3) Split netdevice.h, move the inline functions to to 
> netdev_featurer_helper.h. The netdev_features_helper.h
> inlucde netdevice.h, All the source files which using these ininline 
> functions should include netde_features_helper.h.
> 
> I'd like to get more advice to this.

Larger surgery is probably too much. What does netdevice.h need? Looks
like it mostly needs the type and the helper for testing if feature is
set. So maybe we can put those in netdevice.h and the rest in a new
header?
More advanced helpers like netdev_get_wanted_features() can move to the
new header as well.
shenjian (K) April 16, 2022, 9:09 a.m. UTC | #4
在 2022/4/16 15:42, Jakub Kicinski 写道:
> On Sat, 16 Apr 2022 11:33:58 +0800 shenjian (K) wrote:
>> 在 2022/3/25 9:09, Jakub Kicinski 写道:
>>> On Thu, 24 Mar 2022 23:49:14 +0800 Jian Shen wrote:
>>>> Introduce a set of bitmap operation helpers for netdev features,
>>>> then we can use them to replace the logical operation with them.
>>>> As the nic driversare not supposed to modify netdev_features
>>>> directly, it also introduces wrappers helpers to this.
>>>>
>>>> The implementation of these helpers are based on the old prototype
>>>> of netdev_features_t is still u64. I will rewrite them on the last
>>>> patch, when the prototype changes.
>>>>
>>>> Signed-off-by: Jian Shen <shenjian15@huawei.com>
>>>> ---
>>>>    include/linux/netdevice.h | 597 ++++++++++++++++++++++++++++++++++++++
>>> Please move these helpers to a new header file which won't be included
>>> by netdevice.h and include it at users appropriately.
>> I introduced a new header file "netdev_features_helper",  and moved
>> thses helpers
>> to it.  Some helpers need to include struct  net_device which defined in
>> netdevice.h,
>> but there are also some inline functions in netdevice.h need to use
>> these netdev_features
>> helpers. It's conflicted.
>>
>> So far I thought 3 ways to solved it, but all of them are not satisfactory.
>> 1) Split netdevice.h, move the definition of struct net_device and its
>> relative definitions to
>> a new header file A( haven't got a reasonable name).  Both the
>> netdev_features_helper.h
>> and the netdevice include A.
>>
>> 2) Split netdevice.h, move the inline functions to a new header file B.
>> The netdev_features_helper.h
>> inlucde netdevice.h, and B include netdev_features_helper.h and
>> netdevice.h. All the source files
>> which using these ininline functions should include B.
>>
>> 3) Split netdevice.h, move the inline functions to to
>> netdev_featurer_helper.h. The netdev_features_helper.h
>> inlucde netdevice.h, All the source files which using these ininline
>> functions should include netde_features_helper.h.
>>
>> I'd like to get more advice to this.
> Larger surgery is probably too much. What does netdevice.h need? Looks
> like it mostly needs the type and the helper for testing if feature is
> set. So maybe we can put those in netdevice.h and the rest in a new
> header?
> More advanced helpers like netdev_get_wanted_features() can move to the
> new header as well.
> .
ok, got it, thanks
diff mbox series

Patch

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 7307b9553bcf..0af4b26896d6 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2295,6 +2295,603 @@  struct net_device {
 };
 #define to_net_dev(d) container_of(d, struct net_device, dev)
 
+static inline void netdev_features_zero(netdev_features_t *dst)
+{
+	*dst = 0;
+}
+
+static inline void netdev_features_fill(netdev_features_t *dst)
+{
+	*dst = ~0ULL;
+}
+
+static inline bool netdev_features_empty(const netdev_features_t src)
+{
+	return src == 0;
+}
+
+/* helpers for netdev features '==' operation */
+static inline bool netdev_features_equal(const netdev_features_t src1,
+					 const netdev_features_t src2)
+{
+	return src1 == src2;
+}
+
+#define netdev_active_features_equal(ndev, features) \
+		netdev_features_equal(ndev->active_features, features)
+
+#define netdev_hw_features_equal(ndev, features) \
+		netdev_features_equal(ndev->hw_features, features)
+
+#define netdev_wanted_features_equal(ndev, features) \
+		netdev_features_equal(ndev->wanted_features, features)
+
+#define netdev_vlan_features_equal(ndev, features) \
+		netdev_features_equal(ndev->vlan_features, features)
+
+#define netdev_hw_enc_features_equal(ndev, features) \
+		netdev_features_equal(ndev->vlan_features, features)
+
+#define netdev_mpls_features_equal(ndev, features) \
+		netdev_features_equal(ndev->vlan_features, features)
+
+#define netdev_gso_partial_features_equal(ndev, features) \
+		netdev_features_equal(ndev->vlan_features, features)
+
+/* helpers for netdev features '&' operation */
+static inline netdev_features_t
+netdev_features_and(const netdev_features_t a, const netdev_features_t b)
+{
+	return a & b;
+}
+
+#define netdev_active_features_and(ndev, features) \
+		netdev_features_and(ndev->active_features, features)
+
+#define netdev_hw_features_and(ndev, features) \
+		netdev_features_and(ndev->hw_features, features)
+
+#define netdev_wanted_features_and(ndev, features) \
+		netdev_features_and(ndev->wanted_features, features)
+
+#define netdev_vlan_features_and(ndev, features) \
+		netdev_features_and(ndev->vlan_features, features)
+
+#define netdev_hw_enc_features_and(ndev, features) \
+		netdev_features_and(ndev->hw_enc_features, features)
+
+#define netdev_mpls_features_and(ndev, features) \
+		netdev_features_and(ndev->mpls_features, features)
+
+#define netdev_gso_partial_features_and(ndev, features) \
+		netdev_features_and(ndev->gso_partial_features, features)
+
+/* helpers for netdev features '&=' operation */
+static inline void
+netdev_features_direct_and(netdev_features_t *dst,
+			   const netdev_features_t features)
+{
+	*dst = netdev_features_and(*dst, features);
+}
+
+static inline void
+netdev_active_features_direct_and(struct net_device *ndev,
+				  const netdev_features_t features)
+{
+	ndev->active_features = netdev_active_features_and(ndev, features);
+}
+
+static inline void
+netdev_hw_features_direct_and(struct net_device *ndev,
+			      const netdev_features_t features)
+{
+	ndev->hw_features = netdev_hw_features_and(ndev, features);
+}
+
+static inline void
+netdev_wanted_features_direct_and(struct net_device *ndev,
+				  const netdev_features_t features)
+{
+	ndev->wanted_features = netdev_wanted_features_and(ndev, features);
+}
+
+static inline void
+netdev_vlan_features_direct_and(struct net_device *ndev,
+				const netdev_features_t features)
+{
+	ndev->vlan_features = netdev_vlan_features_and(ndev, features);
+}
+
+static inline void
+netdev_hw_enc_features_direct_and(struct net_device *ndev,
+				  const netdev_features_t features)
+{
+	ndev->hw_enc_features = netdev_hw_enc_features_and(ndev, features);
+}
+
+static inline void
+netdev_mpls_features_direct_and(struct net_device *ndev,
+				const netdev_features_t features)
+{
+	ndev->mpls_features = netdev_mpls_features_and(ndev, features);
+}
+
+static inline void
+netdev_gso_partial_features_direct_and(struct net_device *ndev,
+				       const netdev_features_t features)
+{
+	ndev->gso_partial_features = netdev_mpls_features_and(ndev, features);
+}
+
+/* helpers for netdev features '|' operation */
+static inline netdev_features_t
+netdev_features_or(const netdev_features_t a, const netdev_features_t b)
+{
+	return a | b;
+}
+
+#define netdev_active_features_or(ndev, features) \
+		netdev_features_or(ndev->active_features, features)
+
+#define netdev_hw_features_or(ndev, features) \
+		netdev_features_or(ndev->hw_features, features)
+
+#define netdev_wanted_features_or(ndev, features) \
+		netdev_features_or(ndev->wanted_features, features)
+
+#define netdev_vlan_features_or(ndev, features) \
+		netdev_features_or(ndev->vlan_features, features)
+
+#define netdev_hw_enc_features_or(ndev, features) \
+		netdev_features_or(ndev->hw_enc_features, features)
+
+#define netdev_mpls_features_or(ndev, features) \
+		netdev_features_or(ndev->mpls_features, features)
+
+#define netdev_gso_partial_features_or(ndev, features) \
+		netdev_features_or(ndev->gso_partial_features, features)
+
+/* helpers for netdev features '|=' operation */
+static inline void
+netdev_features_direct_or(netdev_features_t *dst,
+			  const netdev_features_t features)
+{
+	*dst = netdev_features_or(*dst, features);
+}
+
+static inline void
+netdev_active_features_direct_or(struct net_device *ndev,
+				 const netdev_features_t features)
+{
+	ndev->active_features = netdev_active_features_or(ndev, features);
+}
+
+static inline void
+netdev_hw_features_direct_or(struct net_device *ndev,
+			     const netdev_features_t features)
+{
+	ndev->hw_features = netdev_hw_features_or(ndev, features);
+}
+
+static inline void
+netdev_wanted_features_direct_or(struct net_device *ndev,
+				 const netdev_features_t features)
+{
+	ndev->wanted_features = netdev_wanted_features_or(ndev, features);
+}
+
+static inline void
+netdev_vlan_features_direct_or(struct net_device *ndev,
+			       const netdev_features_t features)
+{
+	ndev->vlan_features = netdev_vlan_features_or(ndev, features);
+}
+
+static inline void
+netdev_hw_enc_features_direct_or(struct net_device *ndev,
+				 const netdev_features_t features)
+{
+	ndev->hw_enc_features = netdev_hw_enc_features_or(ndev, features);
+}
+
+static inline void
+netdev_mpls_features_direct_or(struct net_device *ndev,
+			       const netdev_features_t features)
+{
+	ndev->mpls_features = netdev_mpls_features_or(ndev, features);
+}
+
+static inline void
+netdev_gso_partial_features_direct_or(struct net_device *ndev,
+				      const netdev_features_t features)
+{
+	ndev->gso_partial_features = netdev_mpls_features_or(ndev, features);
+}
+
+/* helpers for netdev features '^' operation */
+static inline netdev_features_t
+netdev_features_xor(const netdev_features_t a, const netdev_features_t b)
+{
+	return a ^ b;
+}
+
+#define netdev_active_features_xor(ndev, features) \
+		netdev_features_xor(ndev->active_features, features)
+
+#define netdev_hw_features_xor(ndev, features) \
+		netdev_features_xor(ndev->hw_features, features)
+
+#define netdev_wanted_features_xor(ndev, features) \
+		netdev_features_xor(ndev->wanted_features, features)
+
+#define netdev_vlan_features_xor(ndev, features) \
+		netdev_features_xor(ndev->vlan_features, features)
+
+#define netdev_hw_enc_features_xor(ndev, features) \
+		netdev_features_xor(ndev->hw_enc_features, features)
+
+#define netdev_mpls_features_xor(ndev, features) \
+		netdev_features_xor(ndev->mpls_features, features)
+
+#define netdev_gso_partial_features_xor(ndev, features) \
+		netdev_features_xor(ndev->gso_partial_features, features)
+
+/* helpers for netdev features '^=' operation */
+static inline void
+netdev_active_features_direct_xor(struct net_device *ndev,
+				  const netdev_features_t features)
+{
+	ndev->active_features = netdev_active_features_xor(ndev, features);
+}
+
+static inline void
+netdev_hw_features_direct_xor(struct net_device *ndev,
+			      const netdev_features_t features)
+{
+	ndev->hw_features = netdev_hw_features_xor(ndev, features);
+}
+
+static inline void
+netdev_wanted_features_direct_xor(struct net_device *ndev,
+				  const netdev_features_t features)
+{
+	ndev->wanted_features = netdev_wanted_features_xor(ndev, features);
+}
+
+static inline void
+netdev_vlan_features_direct_xor(struct net_device *ndev,
+				const netdev_features_t features)
+{
+	ndev->vlan_features = netdev_vlan_features_xor(ndev, features);
+}
+
+static inline void
+netdev_hw_enc_features_direct_xor(struct net_device *ndev,
+				  const netdev_features_t features)
+{
+	ndev->hw_enc_features = netdev_hw_enc_features_xor(ndev, features);
+}
+
+static inline void
+netdev_mpls_features_direct_xor(struct net_device *ndev,
+				const netdev_features_t features)
+{
+	ndev->mpls_features = netdev_mpls_features_xor(ndev, features);
+}
+
+static inline void
+netdev_gso_partial_features_direct_xor(struct net_device *ndev,
+				       const netdev_features_t features)
+{
+	ndev->gso_partial_features =
+			netdev_gso_partial_features_xor(ndev, features);
+}
+
+/* helpers for netdev features '& ~' operation */
+static inline netdev_features_t
+netdev_features_andnot(const netdev_features_t a, const netdev_features_t b)
+{
+	return a & ~b;
+}
+
+#define netdev_active_features_andnot(ndev, features) \
+		netdev_features_andnot(ndev->active_features, features)
+
+#define netdev_hw_features_andnot(ndev, features) \
+		netdev_features_andnot(ndev->hw_features, features)
+
+#define netdev_wanted_features_andnot(ndev, features) \
+		netdev_features_andnot(ndev->wanted_features, features)
+
+#define netdev_vlan_features_andnot(ndev, features) \
+		netdev_features_andnot(ndev->vlan_features, features)
+
+#define netdev_hw_enc_features_andnot(ndev, features) \
+		netdev_features_andnot(ndev->hw_enc_features, features)
+
+#define netdev_mpls_features_andnot(ndev, features) \
+		netdev_features_andnot(ndev->mpls_features, features)
+
+#define netdev_gso_partial_features_andnot(ndev, features) \
+		netdev_features_andnot(ndev->gso_partial_features, features)
+
+#define netdev_active_features_andnot_r(ndev, features) \
+		netdev_features_andnot(features, ndev->active_features)
+
+#define netdev_hw_features_andnot_r(ndev, features) \
+		netdev_features_andnot(features, ndev->hw_features)
+
+#define netdev_wanted_features_andnot_r(ndev, features) \
+		netdev_features_andnot(features, ndev->wanted_features)
+
+#define netdev_vlan_features_andnot_r(ndev, features) \
+		netdev_features_andnot(features, ndev->vlan_features)
+
+#define netdev_hw_enc_features_andnot_r(ndev, features) \
+		netdev_features_andnot(features, ndev->hw_enc_features)
+
+#define netdev_mpls_features_andnot_r(ndev, features) \
+		netdev_features_andnot(features, ndev->mpls_features)
+
+#define netdev_gso_partial_features_andnot_r(ndev, features) \
+		netdev_features_andnot(features, ndev->gso_partial_features)
+
+static inline void
+netdev_features_direct_andnot(netdev_features_t *dst,
+			     const netdev_features_t features)
+{
+	*dst = netdev_features_andnot(*dst, features);
+}
+
+static inline void
+netdev_active_features_direct_andnot(struct net_device *ndev,
+			     const netdev_features_t features)
+{
+	ndev->active_features = netdev_active_features_andnot(ndev, features);
+}
+
+static inline void
+netdev_hw_features_direct_andnot(struct net_device *ndev,
+			 const netdev_features_t features)
+{
+	ndev->hw_features = netdev_hw_features_andnot(ndev, features);
+}
+
+static inline void
+netdev_wanted_features_direct_andnot(struct net_device *ndev,
+			     const netdev_features_t features)
+{
+	ndev->wanted_features = netdev_wanted_features_andnot(ndev, features);
+}
+
+static inline void
+netdev_vlan_features_direct_andnot(struct net_device *ndev,
+			   const netdev_features_t features)
+{
+	ndev->vlan_features = netdev_vlan_features_andnot(ndev, features);
+}
+
+static inline void
+netdev_hw_enc_features_direct_andnot(struct net_device *ndev,
+			     const netdev_features_t features)
+{
+	ndev->hw_enc_features = netdev_hw_enc_features_andnot(ndev, features);
+}
+
+static inline void
+netdev_mpls_features_direct_andnot(struct net_device *ndev,
+			   const netdev_features_t features)
+{
+	ndev->mpls_features = netdev_mpls_features_andnot(ndev, features);
+}
+
+static inline void
+netdev_gso_partial_features_direct_andnot(struct net_device *ndev,
+				  const netdev_features_t features)
+{
+	ndev->gso_partial_features =
+		netdev_gso_partial_features_andnot(ndev, features);
+}
+
+/* helpers for netdev features 'set bit' operation */
+static inline void netdev_features_set_bit(int nr, netdev_features_t *src)
+{
+	*src |= __NETIF_F_BIT(nr);
+}
+
+#define netdev_active_features_set_bit(ndev, nr) \
+		netdev_features_set_bit(nr, &ndev->active_features)
+
+#define netdev_hw_features_set_bit(ndev, nr) \
+		netdev_features_set_bit(nr, &ndev->hw_features)
+
+#define netdev_wanted_features_set_bit(ndev, nr) \
+		netdev_features_set_bit(nr, &ndev->wanted_features)
+
+#define netdev_vlan_features_set_bit(ndev, nr) \
+		netdev_features_set_bit(nr, &ndev->vlan_features)
+
+#define netdev_hw_enc_features_set_bit(ndev, nr) \
+		netdev_features_set_bit(nr, &ndev->hw_enc_features)
+
+#define netdev_mpls_features_set_bit(ndev, nr) \
+		netdev_features_set_bit(nr, &ndev->mpls_features)
+
+#define netdev_gso_partial_features_set_bit(ndev, nr) \
+		netdev_features_set_bit(nr, &ndev->gso_partial_features)
+
+/* helpers for netdev features 'set bit array' operation */
+static inline void netdev_features_set_array(const int *array, int array_size,
+					     netdev_features_t *dst)
+{
+	int i;
+
+	for (i = 0; i < array_size; i++)
+		netdev_features_set_bit(array[i], dst);
+}
+
+#define netdev_active_features_set_array(ndev, array, array_size) \
+		netdev_features_set_array(array, array_size, &ndev->active_features)
+
+#define netdev_hw_features_set_array(ndev, array, array_size) \
+		netdev_features_set_array(array, array_size, &ndev->hw_features)
+
+#define netdev_wanted_features_set_array(ndev, array, array_size) \
+		netdev_features_set_array(array, array_size, &ndev->wanted_features)
+
+#define netdev_vlan_features_set_array(ndev, array, array_size) \
+		netdev_features_set_array(array, array_size, &ndev->vlan_features)
+
+#define netdev_hw_enc_features_set_array(ndev, array, array_size) \
+		netdev_features_set_array(array, array_size, &ndev->hw_enc_features)
+
+#define netdev_mpls_features_set_array(ndev, array, array_size) \
+		netdev_features_set_array(array, array_size, &ndev->mpls_features)
+
+#define netdev_gso_partial_features_set_array(ndev, array, array_size) \
+		netdev_features_set_array(array, array_size, &ndev->gso_partial_features)
+
+/* helpers for netdev features 'clear bit' operation */
+static inline void netdev_features_clear_bit(int nr, netdev_features_t *src)
+{
+	*src &= ~__NETIF_F_BIT(nr);
+}
+
+#define netdev_active_features_clear_bit(ndev, nr) \
+		netdev_features_clear_bit(nr, &ndev->active_features)
+
+#define netdev_hw_features_clear_bit(ndev, nr) \
+		netdev_features_clear_bit(nr, &ndev->hw_features)
+
+#define netdev_wanted_features_clear_bit(ndev, nr) \
+		netdev_features_clear_bit(nr, &ndev->wanted_features)
+
+#define netdev_vlan_features_clear_bit(ndev, nr) \
+		netdev_features_clear_bit(nr, &ndev->vlan_features)
+
+#define netdev_hw_enc_features_clear_bit(ndev, nr) \
+		netdev_features_clear_bit(nr, &ndev->hw_enc_features)
+
+#define netdev_mpls_features_clear_bit(ndev, nr) \
+		netdev_features_clear_bit(nr, &ndev->mpls_features)
+
+#define netdev_gso_partial_features_clear_bit(ndev, nr) \
+		netdev_features_clear_bit(nr, &ndev->gso_partial_features)
+
+/* helpers for netdev features 'test bit' operation */
+static inline bool netdev_features_test_bit(int nr, const netdev_features_t src)
+{
+	return (src & __NETIF_F_BIT(nr)) > 0;
+}
+
+#define netdev_active_features_test_bit(ndev, nr) \
+		netdev_features_test_bit(nr, ndev->active_features)
+
+#define netdev_hw_features_test_bit(ndev, nr) \
+		netdev_features_test_bit(nr, ndev->hw_features)
+
+#define netdev_wanted_features_test_bit(ndev, nr) \
+		netdev_features_test_bit(nr, ndev->wanted_features)
+
+#define netdev_vlan_features_test_bit(ndev, nr) \
+		netdev_features_test_bit(nr, ndev->vlan_features)
+
+#define netdev_hw_enc_features_test_bit(ndev, nr) \
+		netdev_features_test_bit(nr, ndev->hw_enc_features)
+
+#define netdev_mpls_features_test_bit(ndev, nr) \
+		netdev_features_test_bit(nr, ndev->mpls_features)
+
+#define netdev_gso_partial_features_test_bit(ndev, nr) \
+		netdev_features_test_bit(nr, ndev->gso_partial_features)
+
+static inline bool netdev_features_intersects(const netdev_features_t src1,
+					      const netdev_features_t src2)
+{
+	return (src1 & src2) > 0;
+}
+
+#define netdev_active_features_intersects(ndev, features) \
+		netdev_features_intersects(ndev->active_features, features)
+
+#define netdev_hw_features_intersects(ndev, features) \
+		netdev_features_intersects(ndev->hw_features, features)
+
+#define netdev_wanted_features_intersects(ndev, features) \
+		netdev_features_intersects(ndev->wanted_features, features)
+
+#define netdev_vlan_features_intersects(ndev, features) \
+		netdev_features_intersects(ndev->vlan_features, features)
+
+#define netdev_hw_enc_features_intersects(ndev, features) \
+		netdev_features_intersects(ndev->hw_enc_features, features)
+
+#define netdev_mpls_features_intersects(ndev, features) \
+		netdev_features_intersects(ndev->mpls_features, features)
+
+#define netdev_gso_partial_features_intersects(ndev, features) \
+		netdev_features_intersects(ndev->gso_partial_features, features)
+
+
+/* helpers for netdev features '=' operation */
+static inline void netdev_set_active_features(struct net_device *netdev,
+					      const netdev_features_t src)
+{
+	netdev->active_features = src;
+}
+
+static inline void netdev_set_hw_features(struct net_device *ndev,
+					  const netdev_features_t src)
+{
+	ndev->hw_features = src;
+}
+
+static inline void netdev_set_wanted_features(struct net_device *ndev,
+					      const netdev_features_t src)
+{
+	ndev->wanted_features = src;
+}
+
+static inline void netdev_set_vlan_features(struct net_device *ndev,
+					    const netdev_features_t src)
+{
+	ndev->vlan_features = src;
+}
+
+static inline void netdev_set_hw_enc_features(struct net_device *ndev,
+					      const netdev_features_t src)
+{
+	ndev->hw_enc_features = src;
+}
+
+static inline void netdev_set_mpls_features(struct net_device *ndev,
+					    const netdev_features_t src)
+{
+	ndev->mpls_features = src;
+}
+
+static inline void netdev_set_gso_partial_features(struct net_device *ndev,
+					    const netdev_features_t src)
+{
+	ndev->gso_partial_features = src;
+}
+
+/* helpers for netdev features 'get' operation */
+#define netdev_active_features(ndev)	((ndev)->active_features)
+#define netdev_hw_features(ndev)	((ndev)->hw_features)
+#define netdev_wanted_features(ndev)	((ndev)->wanted_features)
+#define netdev_vlan_features(ndev)	((ndev)->vlan_features)
+#define netdev_hw_enc_features(ndev)	((ndev)->hw_enc_features)
+#define netdev_mpls_features(ndev)	((ndev)->mpls_features)
+#define netdev_gso_partial_features(ndev)	((ndev)->gso_partial_features)
+
+/* helpers for netdev features 'subset' */
+static inline bool netdev_features_subset(const netdev_features_t src1,
+					  const netdev_features_t src2)
+{
+	return (src1 & src2) == src2;
+}
+
 static inline bool netif_elide_gro(const struct net_device *dev)
 {
 	if (!(dev->active_features & NETIF_F_GRO) || dev->xdp_prog)