diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c
index 8b77582bdfa0..8023a3f0d43b 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c
@@ -4,6 +4,7 @@
 #include <linux/etherdevice.h>
 #include <linux/io-64-nonatomic-hi-lo.h>
 #include <linux/lockdep.h>
+#include <linux/netdev_feature_helpers.h>
 #include <net/dst_metadata.h>
 
 #include "nfpcore/nfp_cpp.h"
diff --git a/include/linux/netdev_feature_helpers.h b/include/linux/netdev_feature_helpers.h
new file mode 100644
index 000000000000..4bb5de61e4e9
--- /dev/null
+++ b/include/linux/netdev_feature_helpers.h
@@ -0,0 +1,607 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Network device features helpers.
+ */
+#ifndef _LINUX_NETDEV_FEATURES_HELPER_H
+#define _LINUX_NETDEV_FEATURES_HELPER_H
+
+#include <linux/netdevice.h>
+
+static inline void __netdev_features_zero(netdev_features_t *dst)
+{
+	*dst = 0;
+}
+
+#define netdev_features_zero(features) __netdev_features_zero(&(features))
+
+/* active_feature prefer to netdev->features */
+#define netdev_active_features_zero(ndev) \
+		netdev_features_zero((ndev)->features)
+
+#define netdev_hw_features_zero(ndev) \
+		netdev_features_zero((ndev)->hw_features)
+
+#define netdev_wanted_features_zero(ndev) \
+		netdev_features_zero((ndev)->wanted_features)
+
+#define netdev_vlan_features_zero(ndev) \
+		netdev_features_zero((ndev)->vlan_features)
+
+#define netdev_hw_enc_features_zero(ndev) \
+		netdev_features_zero((ndev)->hw_enc_features)
+
+#define netdev_mpls_features_zero(ndev) \
+		netdev_features_zero((ndev)->mpls_features)
+
+#define netdev_gso_partial_features_zero(ndev) \
+		netdev_features_zero((ndev)->gso_partial_features)
+
+static inline void __netdev_features_fill(netdev_features_t *dst)
+{
+	*dst = ~0ULL;
+}
+
+#define netdev_features_fill(features) __netdev_features_fill(&(features))
+
+static inline bool __netdev_features_empty(const netdev_features_t *src)
+{
+	return *src == 0;
+}
+
+#define netdev_features_empty(features) __netdev_features_empty(&(features))
+
+#define netdev_active_features_empty(ndev) \
+		netdev_features_empty((ndev)->features)
+
+#define netdev_hw_features_empty(ndev) \
+		netdev_features_empty((ndev)->hw_features)
+
+#define netdev_wanted_features_empty(ndev) \
+		netdev_features_empty((ndev)->wanted_features)
+
+#define netdev_vlan_features_empty(ndev) \
+		netdev_features_empty((ndev)->vlan_features)
+
+#define netdev_hw_enc_features_empty(ndev) \
+		netdev_features_empty((ndev)->hw_enc_features)
+
+#define netdev_mpls_features_empty(ndev) \
+		netdev_features_empty((ndev)->mpls_features)
+
+#define netdev_gso_partial_features_empty(ndev) \
+		netdev_features_empty((ndev)->gso_partial_features)
+
+/* helpers for netdev features '==' operation */
+static inline bool __netdev_features_equal(const netdev_features_t *feats1,
+					   const netdev_features_t *feats2)
+{
+	return *feats1 == *feats2;
+}
+
+#define netdev_features_equal(feat1, feat2)	\
+			__netdev_features_equal(&(feat1), &(feat2))
+
+#define netdev_active_features_equal(ndev, __features) \
+		netdev_features_equal((ndev)->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)->hw_enc_features, __features)
+
+#define netdev_mpls_features_equal(ndev, __features) \
+		netdev_features_equal((ndev)->mpls_features, __features)
+
+#define netdev_gso_partial_features_equal(ndev, __features) \
+		netdev_features_equal((ndev)->gso_partial_features, __features)
+
+/* helpers for netdev features '&' operation */
+static inline bool
+__netdev_features_and(netdev_features_t *dst, const netdev_features_t *a,
+		      const netdev_features_t *b)
+{
+	*dst = *a & *b;
+	return *dst != 0;
+}
+
+#define netdev_features_and(dst, a, b) __netdev_features_and(&(dst), &(a), &(b))
+
+#define netdev_active_features_and(ndev, a, b) \
+		netdev_features_and((ndev)->features, a, b)
+
+#define netdev_hw_features_and(ndev, a, b) \
+		netdev_features_and((ndev)->hw_features, a, b)
+
+#define netdev_wanted_features_and(ndev, a, b) \
+		netdev_features_and((ndev)->wanted_features, a, b)
+
+#define netdev_vlan_features_and(ndev, a, b) \
+		netdev_features_and((ndev)->vlan_features, a, b)
+
+#define netdev_hw_enc_features_and(ndev, a, b) \
+		netdev_features_and((ndev)->hw_enc_features, a, b)
+
+#define netdev_mpls_features_and(ndev, a, b) \
+		netdev_features_and((ndev)->mpls_features, a, b)
+
+#define netdev_gso_partial_features_and(ndev, a, b) \
+		netdev_features_and((ndev)->gso_partial_features, a, b)
+
+/* helpers for netdev features '&=' operation */
+static inline bool
+__netdev_features_mask(netdev_features_t *dst,
+		       const netdev_features_t *features)
+{
+	return __netdev_features_and(dst, dst, features);
+}
+
+#define netdev_features_mask(dst, __features)	\
+	__netdev_features_mask(&(dst), &(__features))
+
+#define netdev_active_features_mask(ndev, __features) \
+		netdev_features_mask((ndev)->features, __features)
+
+#define netdev_hw_features_mask(ndev, __features) \
+		netdev_features_mask((ndev)->hw_features, __features)
+
+#define netdev_wanted_features_mask(ndev, __features) \
+		netdev_features_mask((ndev)->wanted_features, __features)
+
+#define netdev_vlan_features_mask(ndev, __features) \
+		netdev_features_mask((ndev)->vlan_features, __features)
+
+#define netdev_hw_enc_features_mask(ndev, __features) \
+		netdev_features_mask((ndev)->hw_enc_features, __features)
+
+#define netdev_mpls_features_mask(ndev, __features) \
+		netdev_features_mask((ndev)->mpls_features, __features)
+
+#define netdev_gso_partial_features_mask(ndev, __features) \
+		netdev_features_mask((ndev)->gso_partial_features, __features)
+
+/* helpers for netdev features '|' operation */
+static inline void
+__netdev_features_or(netdev_features_t *dst, const netdev_features_t *a,
+		     const netdev_features_t *b)
+{
+	*dst = *a | *b;
+}
+
+#define netdev_features_or(dst, a, b) __netdev_features_or(&(dst), &(a), &(b))
+
+#define netdev_active_features_or(ndev, a, b) \
+		netdev_features_or((ndev)->features, a, b)
+
+#define netdev_hw_features_or(ndev, a, b) \
+		netdev_features_or((ndev)->hw_features, a, b)
+
+#define netdev_wanted_features_or(ndev, a, b) \
+		netdev_features_or((ndev)->wanted_features, a, b)
+
+#define netdev_vlan_features_or(ndev, a, b) \
+		netdev_features_or((ndev)->vlan_features, a, b)
+
+#define netdev_hw_enc_features_or(ndev, a, b) \
+		netdev_features_or((ndev)->hw_enc_features, a, b)
+
+#define netdev_mpls_features_or(ndev, a, b) \
+		netdev_features_or((ndev)->mpls_features, a, b)
+
+#define netdev_gso_partial_features_or(ndev, a, b) \
+		netdev_features_or((ndev)->gso_partial_features, a, b)
+
+/* helpers for netdev features '|=' operation */
+static inline void
+__netdev_features_set(netdev_features_t *dst, const netdev_features_t *features)
+{
+	__netdev_features_or(dst, dst, features);
+}
+
+#define netdev_features_set(dst, __features)	\
+		__netdev_features_set(&(dst), &(__features))
+
+#define netdev_active_features_set(ndev, __features) \
+		netdev_features_set((ndev)->features, __features)
+
+#define netdev_hw_features_set(ndev, __features) \
+		netdev_features_set((ndev)->hw_features, __features)
+
+#define netdev_wanted_features_set(ndev, __features) \
+		netdev_features_set((ndev)->wanted_features, __features)
+
+#define netdev_vlan_features_set(ndev, __features) \
+		netdev_features_set((ndev)->vlan_features, __features)
+
+#define netdev_hw_enc_features_set(ndev, __features) \
+		netdev_features_set((ndev)->hw_enc_features, __features)
+
+#define netdev_mpls_features_set(ndev, __features) \
+		netdev_features_set((ndev)->mpls_features, __features)
+
+#define netdev_gso_partial_features_set(ndev, __features) \
+		netdev_features_set((ndev)->gso_partial_features, __features)
+
+static inline void __netdev_feature_change(int nr, netdev_features_t *src)
+{
+	if (*src & __NETIF_F_BIT(nr))
+		*src &= ~(__NETIF_F_BIT(nr));
+	else
+		*src |= __NETIF_F_BIT(nr);
+}
+
+#define netdev_feature_change(nr, src)	\
+		__netdev_feature_change(nr, &(src))
+
+#define netdev_active_feature_change(ndev, nr) \
+		netdev_feature_change(nr, (ndev)->features)
+
+#define netdev_hw_feature_change(ndev, nr) \
+		netdev_feature_change(nr, (ndev)->hw_features)
+
+#define netdev_wanted_feature_change(ndev, nr) \
+		netdev_feature_change(nr, (ndev)->wanted_features)
+
+#define netdev_vlan_feature_change(ndev, nr) \
+		netdev_feature_change(nr, (ndev)->vlan_features)
+
+#define netdev_hw_enc_feature_change(ndev, nr) \
+		netdev_feature_change(nr, (ndev)->hw_enc_features)
+
+#define netdev_mpls_feature_change(ndev, nr) \
+		netdev_feature_change(nr, (ndev)->mpls_features)
+
+#define netdev_gso_partial_feature_change(ndev, nr) \
+		netdev_feature_change(nr, (ndev)->gso_partial_features)
+
+/* helpers for netdev features '^' operation */
+static inline void
+__netdev_features_xor(netdev_features_t *dst, const netdev_features_t *a,
+		      const netdev_features_t *b)
+{
+	*dst = *a ^ *b;
+}
+
+#define netdev_features_xor(dst, a, b) __netdev_features_xor(&(dst), &(a), &(b))
+
+#define netdev_active_features_xor(ndev, a, b) \
+		netdev_features_xor((ndev)->features, a, b)
+
+#define netdev_hw_features_xor(ndev, a, b) \
+		netdev_features_xor((ndev)->hw_features, a, b)
+
+#define netdev_wanted_features_xor(ndev, a, b) \
+		netdev_features_xor((ndev)->wanted_features, a, b)
+
+#define netdev_vlan_features_xor(ndev, a, b) \
+		netdev_features_xor((ndev)->vlan_features, a, b)
+
+#define netdev_hw_enc_features_xor(ndev, a, b) \
+		netdev_features_xor((ndev)->hw_enc_features, a, b)
+
+#define netdev_mpls_features_xor(ndev, a, b) \
+		netdev_features_xor((ndev)->mpls_features, a, b)
+
+#define netdev_gso_partial_features_xor(ndev, a, b) \
+		netdev_features_xor((ndev)->gso_partial_features, a, b)
+
+/* helpers for netdev features '^=' operation */
+static inline void
+__netdev_features_toggle(netdev_features_t *dst,
+			 const netdev_features_t *features)
+{
+	__netdev_features_xor(dst, dst, features);
+}
+
+#define netdev_features_toggle(dst, __features)	\
+		__netdev_features_toggle(&(dst), &(__features))
+
+#define netdev_active_features_toggle(ndev, __features) \
+		netdev_features_toggle((ndev)->features, __features)
+
+#define netdev_hw_features_toggle(ndev, __features) \
+		netdev_features_toggle((ndev)->hw_features, __features)
+
+#define netdev_wanted_features_toggle(ndev, __features) \
+		netdev_features_toggle((ndev)->wanted_features, __features)
+
+#define netdev_vlan_features_toggle(ndev, __features) \
+		netdev_features_toggle((ndev)->vlan_features, __features)
+
+#define netdev_hw_enc_features_toggle(ndev, __features) \
+		netdev_features_toggle((ndev)->hw_enc_features, __features)
+
+#define netdev_mpls_features_toggle(ndev, __features) \
+		netdev_features_toggle((ndev)->mpls_features, __features)
+
+#define netdev_gso_partial_features_toggle(ndev, __features) \
+		netdev_features_toggle((ndev)->gso_partial_features, __features)
+
+/* helpers for netdev features '& ~' operation */
+static inline bool
+__netdev_features_andnot(netdev_features_t *dst, const netdev_features_t *a,
+			 const netdev_features_t *b)
+{
+	*dst = *a & ~(*b);
+	return *dst == 0;
+}
+
+#define netdev_features_andnot(dst, a, b)	\
+		__netdev_features_andnot(&(dst), &(a), &(b))
+
+#define netdev_active_features_andnot(ndev, a, b) \
+		netdev_features_andnot((ndev)->features, a, b)
+
+#define netdev_hw_features_andnot(ndev, a, b) \
+		netdev_features_andnot((ndev)->hw_features, a, b)
+
+#define netdev_wanted_features_andnot(ndev, a, b) \
+		netdev_features_andnot((ndev)->wanted_features, a, b)
+
+#define netdev_vlan_features_andnot(ndev, a, b) \
+		netdev_features_andnot((ndev)->vlan_features, a, b)
+
+#define netdev_hw_enc_features_andnot(ndev, a, b) \
+		netdev_features_andnot((ndev)->hw_enc_features, a, b)
+
+#define netdev_mpls_features_andnot(ndev, a, b) \
+		netdev_features_andnot((ndev)->mpls_features, a, b)
+
+#define netdev_gso_partial_features_andnot(ndev, a, b) \
+		netdev_features_andnot((ndev)->gso_partial_features, a, b)
+
+static inline void
+__netdev_features_clear(netdev_features_t *dst,
+			const netdev_features_t *features)
+{
+	__netdev_features_andnot(dst, dst, features);
+}
+
+#define netdev_features_clear(dst, __features)	\
+		__netdev_features_clear(&(dst), &(__features))
+
+#define netdev_active_features_clear(ndev, __features) \
+		netdev_features_clear((ndev)->features, __features)
+
+#define netdev_hw_features_clear(ndev, __features) \
+		netdev_features_clear((ndev)->hw_features, __features)
+
+#define netdev_wanted_features_clear(ndev, __features) \
+		netdev_features_clear((ndev)->wanted_features, __features)
+
+#define netdev_vlan_features_clear(ndev, __features) \
+		netdev_features_clear((ndev)->vlan_features, __features)
+
+#define netdev_hw_enc_features_clear(ndev, __features) \
+		netdev_features_clear((ndev)->hw_enc_features, __features)
+
+#define netdev_mpls_features_clear(ndev, __features) \
+		netdev_features_clear((ndev)->mpls_features, __features)
+
+#define netdev_gso_partial_features_clear(ndev, __features) \
+		netdev_features_clear((ndev)->gso_partial_features, __features)
+
+/* helpers for netdev features 'set bit' operation */
+static inline void __netdev_feature_add(int nr, netdev_features_t *src)
+{
+	*src |= __NETIF_F_BIT(nr);
+}
+
+#define netdev_feature_add(nr, src) __netdev_feature_add(nr, &(src))
+
+#define netdev_active_feature_add(ndev, nr) \
+		netdev_feature_add(nr, (ndev)->features)
+
+#define netdev_hw_feature_add(ndev, nr) \
+		netdev_feature_add(nr, (ndev)->hw_features)
+
+#define netdev_wanted_feature_add(ndev, nr) \
+		netdev_feature_add(nr, (ndev)->wanted_features)
+
+#define netdev_vlan_feature_add(ndev, nr) \
+		netdev_feature_add(nr, (ndev)->vlan_features)
+
+#define netdev_hw_enc_feature_add(ndev, nr) \
+		netdev_feature_add(nr, (ndev)->hw_enc_features)
+
+#define netdev_mpls_feature_add(ndev, nr) \
+		netdev_feature_add(nr, (ndev)->mpls_features)
+
+#define netdev_gso_partial_feature_add(ndev, nr) \
+		netdev_feature_add(nr, (ndev)->gso_partial_features)
+
+/* helpers for netdev features 'set bit array' operation */
+static inline void
+__netdev_features_set_array(const struct netdev_feature_set *set,
+			    netdev_features_t *dst)
+{
+	unsigned int i;
+
+	for (i = 0; i < set->cnt; i++)
+		__netdev_feature_add(set->feature_bits[i], dst);
+}
+
+#define netdev_features_set_array(set, dst) \
+		__netdev_features_set_array(set, &(dst))
+
+#define netdev_active_features_set_array(ndev, set) \
+		netdev_features_set_array(set, (ndev)->features)
+
+#define netdev_hw_features_set_array(ndev, set) \
+		netdev_features_set_array(set, (ndev)->hw_features)
+
+#define netdev_wanted_features_set_array(ndev, set) \
+		netdev_features_set_array(set, (ndev)->wanted_features)
+
+#define netdev_vlan_features_set_array(ndev, set) \
+		netdev_features_set_array(set, (ndev)->vlan_features)
+
+#define netdev_hw_enc_features_set_array(ndev, set) \
+		netdev_features_set_array(set, (ndev)->hw_enc_features)
+
+#define netdev_mpls_features_set_array(ndev, set) \
+		netdev_features_set_array(set, (ndev)->mpls_features)
+
+#define netdev_gso_partial_features_set_array(ndev, set) \
+		netdev_features_set_array(set, (ndev)->gso_partial_features)
+
+/* helpers for netdev features 'clear bit' operation */
+static inline void __netdev_feature_del(int nr, netdev_features_t *src)
+{
+	*src &= ~__NETIF_F_BIT(nr);
+}
+
+#define netdev_feature_del(nr, src) __netdev_feature_del(nr, &(src))
+
+#define netdev_active_feature_del(ndev, nr) \
+		netdev_feature_del(nr, (ndev)->features)
+
+#define netdev_hw_feature_del(ndev, nr) \
+		netdev_feature_del(nr, (ndev)->hw_features)
+
+#define netdev_wanted_feature_del(ndev, nr) \
+		netdev_feature_del(nr, (ndev)->wanted_features)
+
+#define netdev_vlan_feature_del(ndev, nr) \
+		netdev_feature_del(nr, (ndev)->vlan_features)
+
+#define netdev_hw_enc_feature_del(ndev, nr) \
+		netdev_feature_del(nr, (ndev)->hw_enc_features)
+
+#define netdev_mpls_feature_del(ndev, nr) \
+		netdev_feature_del(nr, (ndev)->mpls_features)
+
+#define netdev_gso_partial_feature_del(ndev, nr) \
+		netdev_feature_del(nr, (ndev)->gso_partial_features)
+
+/* helpers for netdev features 'clear bit array' operation */
+static inline void
+__netdev_features_clear_array(const struct netdev_feature_set *set,
+			      netdev_features_t *dst)
+{
+	unsigned int i;
+
+	for (i = 0; i < set->cnt; i++)
+		__netdev_feature_del(set->feature_bits[i], dst);
+}
+
+#define netdev_features_clear_array(set, dst) \
+		__netdev_features_clear_array(set, &(dst))
+
+#define netdev_active_features_clear_array(ndev, set) \
+		netdev_features_clear_array(set, (ndev)->features)
+
+#define netdev_hw_features_clear_array(ndev, set) \
+		netdev_features_clear_array(set, (ndev)->hw_features)
+
+#define netdev_wanted_features_clear_array(ndev, set) \
+		netdev_features_clear_array(set, (ndev)->wanted_features)
+
+#define netdev_vlan_features_clear_array(ndev, set) \
+		netdev_features_clear_array(set, (ndev)->vlan_features)
+
+#define netdev_hw_enc_features_clear_array(ndev, set) \
+		netdev_features_clear_array(set, (ndev)->hw_enc_features)
+
+#define netdev_mpls_features_clear_array(ndev, set) \
+		netdev_features_set_array(set, (ndev)->mpls_features)
+
+#define netdev_gso_partial_features_clear_array(ndev, set) \
+		netdev_features_clear_array(set, (ndev)->gso_partial_features)
+
+static inline bool __netdev_features_intersects(const netdev_features_t *feats1,
+						const netdev_features_t *feats2)
+{
+	return (*feats1 & *feats2) > 0;
+}
+
+#define netdev_features_intersects(feats1, feats2)	\
+		__netdev_features_intersects(&(feats1), &(feats2))
+
+#define netdev_active_features_intersects(ndev, __features) \
+		netdev_features_intersects((ndev)->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_features_copy(netdev_features_t *dst,
+					  const netdev_features_t *src)
+{
+	*dst = *src;
+}
+
+#define netdev_features_copy(dst, src)	__netdev_features_copy(&(dst), &(src))
+
+#define netdev_active_features_copy(ndev, __features)	\
+		netdev_features_copy((ndev)->features, __features)
+
+#define netdev_hw_features_copy(ndev, __features)	\
+		netdev_features_copy((ndev)->hw_features, __features)
+
+#define netdev_wanted_features_copy(ndev, __features)	\
+		netdev_features_copy((ndev)->wanted_features, __features)
+
+#define netdev_vlan_features_copy(ndev, __features)	\
+		netdev_features_copy((ndev)->vlan_features, __features)
+
+#define netdev_hw_enc_features_copy(ndev, __features)	\
+		netdev_features_copy((ndev)->hw_enc_features, __features)
+
+#define netdev_mpls_features_copy(ndev, __features)	\
+		netdev_features_copy((ndev)->mpls_features, __features)
+
+#define netdev_gso_partial_features_copy(ndev, __features)	\
+		netdev_features_copy((ndev)->gso_partial_features, __features)
+
+/* helpers for netdev features 'subset' */
+static inline bool __netdev_features_subset(const netdev_features_t *feats1,
+					    const netdev_features_t *feats2)
+{
+	return (*feats1 & *feats2) == *feats2;
+}
+
+#define netdev_features_subset(feats1, feats2)	\
+		__netdev_features_subset(&(feats1), &(feats2))
+
+static inline netdev_features_t netdev_intersect_features(netdev_features_t f1,
+							  netdev_features_t f2)
+{
+	if ((f1 ^ f2) & NETIF_F_HW_CSUM) {
+		if (f1 & NETIF_F_HW_CSUM)
+			f1 |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
+		else
+			f2 |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
+	}
+
+	return f1 & f2;
+}
+
+static inline netdev_features_t
+netdev_get_wanted_features(struct net_device *dev)
+{
+	return (dev->features & ~dev->hw_features) | dev->wanted_features;
+}
+
+#endif
diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h
index 7c2d77d75a88..9d434b4e6e6e 100644
--- a/include/linux/netdev_features.h
+++ b/include/linux/netdev_features.h
@@ -11,6 +11,17 @@
 
 typedef u64 netdev_features_t;
 
+struct netdev_feature_set {
+	unsigned int cnt;
+	unsigned short feature_bits[];
+};
+
+#define DECLARE_NETDEV_FEATURE_SET(name, features...)			\
+	const struct netdev_feature_set name = {			\
+		.cnt = sizeof((unsigned short[]){ features }) / sizeof(unsigned short),	\
+		.feature_bits = { features },				\
+	}
+
 enum {
 	NETIF_F_SG_BIT,			/* Scatter/gather IO. */
 	NETIF_F_IP_CSUM_BIT,		/* Can checksum TCP/UDP over IPv4. */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index f0068c1ff1df..9bbab3856347 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2345,6 +2345,36 @@ struct net_device {
 };
 #define to_net_dev(d) container_of(d, struct net_device, dev)
 
+/* helpers for netdev features 'test bit' operation */
+static inline bool __netdev_feature_test(int nr, const netdev_features_t *src)
+{
+	return (*src & __NETIF_F_BIT(nr)) > 0;
+}
+
+#define netdev_feature_test(nr, __features)	\
+		__netdev_feature_test(nr, &(__features))
+
+#define netdev_active_feature_test(ndev, nr) \
+		netdev_feature_test(nr, (ndev)->features)
+
+#define netdev_hw_feature_test(ndev, nr) \
+		netdev_feature_test(nr, (ndev)->hw_features)
+
+#define netdev_wanted_feature_test(ndev, nr) \
+		netdev_feature_test(nr, (ndev)->wanted_features)
+
+#define netdev_vlan_feature_test(ndev, nr) \
+		netdev_feature_test(nr, (ndev)->vlan_features)
+
+#define netdev_hw_enc_feature_test(ndev, nr) \
+		netdev_feature_test(nr, (ndev)->hw_enc_features)
+
+#define netdev_mpls_feature_test(ndev, nr) \
+		netdev_feature_test(nr, (ndev)->mpls_features)
+
+#define netdev_gso_partial_feature_test(ndev, nr) \
+		netdev_feature_test(nr, (ndev)->gso_partial_features)
+
 static inline bool netif_elide_gro(const struct net_device *dev)
 {
 	if (!(dev->features & NETIF_F_GRO) || dev->xdp_prog)
@@ -4860,24 +4890,6 @@ extern const struct kobj_ns_type_operations net_ns_type_operations;
 
 const char *netdev_drivername(const struct net_device *dev);
 
-static inline netdev_features_t netdev_intersect_features(netdev_features_t f1,
-							  netdev_features_t f2)
-{
-	if ((f1 ^ f2) & NETIF_F_HW_CSUM) {
-		if (f1 & NETIF_F_HW_CSUM)
-			f1 |= (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM);
-		else
-			f2 |= (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM);
-	}
-
-	return f1 & f2;
-}
-
-static inline netdev_features_t netdev_get_wanted_features(
-	struct net_device *dev)
-{
-	return (dev->features & ~dev->hw_features) | dev->wanted_features;
-}
 netdev_features_t netdev_increment_features(netdev_features_t all,
 	netdev_features_t one, netdev_features_t mask);
 
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index e1bb41a443c4..7940074bdb27 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -21,6 +21,7 @@
 #include <linux/slab.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
+#include <linux/netdev_feature_helpers.h>
 #include <linux/net_tstamp.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
diff --git a/net/core/dev.c b/net/core/dev.c
index d66c73c1c734..fdae614ecffa 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -88,6 +88,7 @@
 #include <linux/interrupt.h>
 #include <linux/if_ether.h>
 #include <linux/netdevice.h>
+#include <linux/netdev_feature_helpers.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/skbuff.h>
