diff --git a/drivers/infiniband/ulp/ipoib/ipoib_netlink.c b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c
index 9ad8d9856275..2dd3231df36c 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_netlink.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_netlink.c
@@ -172,6 +172,7 @@ static struct rtnl_link_ops ipoib_link_ops __read_mostly = {
 	.policy		= ipoib_policy,
 	.priv_size	= sizeof(struct ipoib_dev_priv),
 	.setup		= ipoib_setup_common,
+	.newlink_deps	= &generic_newlink_deps,
 	.newlink	= ipoib_new_child_link,
 	.dellink	= ipoib_del_child_link,
 	.changelink	= ipoib_changelink,
diff --git a/drivers/net/amt.c b/drivers/net/amt.c
index 6d15ab3bfbbc..2288f4bf649c 100644
--- a/drivers/net/amt.c
+++ b/drivers/net/amt.c
@@ -3330,6 +3330,10 @@ static int amt_fill_info(struct sk_buff *skb, const struct net_device *dev)
 	return -EMSGSIZE;
 }
 
+struct link_deps amt_newlink_deps = {
+	.mandatory.data = { IFLA_AMT_LINK, },
+};
+
 static struct rtnl_link_ops amt_link_ops __read_mostly = {
 	.kind		= "amt",
 	.maxtype	= IFLA_AMT_MAX,
@@ -3337,6 +3341,7 @@ static struct rtnl_link_ops amt_link_ops __read_mostly = {
 	.priv_size	= sizeof(struct amt_dev),
 	.setup		= amt_link_setup,
 	.validate	= amt_validate,
+	.newlink_deps	= &amt_newlink_deps,
 	.newlink	= amt_newlink,
 	.dellink	= amt_dellink,
 	.get_size       = amt_get_size,
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c
index 2a6a424806aa..5fcab77d616f 100644
--- a/drivers/net/bonding/bond_netlink.c
+++ b/drivers/net/bonding/bond_netlink.c
@@ -906,6 +906,10 @@ static int bond_fill_linkxstats(struct sk_buff *skb,
 	return 0;
 }
 
+struct link_deps bond_changelink_deps = {
+	.optional.data = { IFLA_BOND_ACTIVE_SLAVE, IFLA_BOND_PRIMARY, },
+};
+
 struct rtnl_link_ops bond_link_ops __read_mostly = {
 	.kind			= "bond",
 	.priv_size		= sizeof(struct bonding),
@@ -914,6 +918,7 @@ struct rtnl_link_ops bond_link_ops __read_mostly = {
 	.policy			= bond_policy,
 	.validate		= bond_validate,
 	.newlink		= bond_newlink,
+	.changelink_deps	= &bond_changelink_deps,
 	.changelink		= bond_changelink,
 	.get_size		= bond_get_size,
 	.fill_info		= bond_fill_info,
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
index f3bea196a8f9..495368cbef34 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
@@ -400,6 +400,7 @@ struct rtnl_link_ops rmnet_link_ops __read_mostly = {
 	.priv_size	= sizeof(struct rmnet_priv),
 	.setup		= rmnet_vnd_setup,
 	.validate	= rmnet_rtnl_validate,
+	.newlink_deps	= &generic_newlink_deps,
 	.newlink	= rmnet_newlink,
 	.dellink	= rmnet_dellink,
 	.get_size	= rmnet_get_size,
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c
index 094f44dac5c8..aafaf9d1d822 100644
--- a/drivers/net/ipvlan/ipvlan_main.c
+++ b/drivers/net/ipvlan/ipvlan_main.c
@@ -700,6 +700,7 @@ static struct rtnl_link_ops ipvlan_link_ops = {
 	.priv_size	= sizeof(struct ipvl_dev),
 
 	.setup		= ipvlan_link_setup,
+	.newlink_deps	= &generic_newlink_deps,
 	.newlink	= ipvlan_link_new,
 	.dellink	= ipvlan_link_delete,
 	.get_link_net   = ipvlan_get_link_net,
diff --git a/drivers/net/ipvlan/ipvtap.c b/drivers/net/ipvlan/ipvtap.c
index 1afc4c47be73..df1d22092b21 100644
--- a/drivers/net/ipvlan/ipvtap.c
+++ b/drivers/net/ipvlan/ipvtap.c
@@ -128,6 +128,7 @@ static void ipvtap_setup(struct net_device *dev)
 static struct rtnl_link_ops ipvtap_link_ops __read_mostly = {
 	.kind		= "ipvtap",
 	.setup		= ipvtap_setup,
+	.newlink_deps	= &generic_newlink_deps,
 	.newlink	= ipvtap_newlink,
 	.dellink	= ipvtap_dellink,
 	.priv_size	= sizeof(struct ipvtap_dev),
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index 2da70bc3dd86..246cf09a0ebc 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -4430,6 +4430,7 @@ static struct rtnl_link_ops macsec_link_ops __read_mostly = {
 	.policy		= macsec_rtnl_policy,
 	.setup		= macsec_setup,
 	.validate	= macsec_validate_attr,
+	.newlink_deps	= &generic_newlink_deps,
 	.newlink	= macsec_newlink,
 	.changelink	= macsec_changelink,
 	.dellink	= macsec_dellink,
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 24298a33e0e9..b51e2e21dead 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -1754,6 +1754,7 @@ static struct net *macvlan_get_link_net(const struct net_device *dev)
 static struct rtnl_link_ops macvlan_link_ops = {
 	.kind		= "macvlan",
 	.setup		= macvlan_setup,
+	.newlink_deps	= &generic_newlink_deps,
 	.newlink	= macvlan_newlink,
 	.dellink	= macvlan_dellink,
 	.get_link_net	= macvlan_get_link_net,
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index 29a5929d48e5..f24168080e04 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -140,6 +140,7 @@ static struct net *macvtap_link_net(const struct net_device *dev)
 static struct rtnl_link_ops macvtap_link_ops __read_mostly = {
 	.kind		= "macvtap",
 	.setup		= macvtap_setup,
+	.newlink_deps	= &generic_newlink_deps,
 	.newlink	= macvtap_newlink,
 	.dellink	= macvtap_dellink,
 	.get_link_net	= macvtap_link_net,
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 8983e75e9881..b041ddc2ab34 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -4579,6 +4579,10 @@ static struct net *vxlan_get_link_net(const struct net_device *dev)
 	return READ_ONCE(vxlan->net);
 }
 
+struct link_deps vxlan_newlink_deps = {
+	.mandatory.data = { IFLA_VXLAN_LINK, },
+};
+
 static struct rtnl_link_ops vxlan_link_ops __read_mostly = {
 	.kind		= "vxlan",
 	.maxtype	= IFLA_VXLAN_MAX,
@@ -4586,7 +4590,9 @@ static struct rtnl_link_ops vxlan_link_ops __read_mostly = {
 	.priv_size	= sizeof(struct vxlan_dev),
 	.setup		= vxlan_setup,
 	.validate	= vxlan_validate,
+	.newlink_deps	= &vxlan_newlink_deps,
 	.newlink	= vxlan_newlink,
+	.changelink_deps= &vxlan_newlink_deps,
 	.changelink	= vxlan_changelink,
 	.dellink	= vxlan_dellink,
 	.get_size	= vxlan_get_size,
diff --git a/drivers/net/wireless/virtual/virt_wifi.c b/drivers/net/wireless/virtual/virt_wifi.c
index 4ee374080466..c80ae0e0df53 100644
--- a/drivers/net/wireless/virtual/virt_wifi.c
+++ b/drivers/net/wireless/virtual/virt_wifi.c
@@ -622,6 +622,7 @@ static void virt_wifi_dellink(struct net_device *dev,
 static struct rtnl_link_ops virt_wifi_link_ops = {
 	.kind		= "virt_wifi",
 	.setup		= virt_wifi_setup,
+	.newlink_deps	= &generic_newlink_deps,
 	.newlink	= virt_wifi_newlink,
 	.dellink	= virt_wifi_dellink,
 	.priv_size	= sizeof(struct virt_wifi_netdev_priv),
diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h
index b45d57b5968a..f1702e8872cf 100644
--- a/include/net/rtnetlink.h
+++ b/include/net/rtnetlink.h
@@ -29,6 +29,18 @@ static inline enum rtnl_kinds rtnl_msgtype_kind(int msgtype)
 	return msgtype & RTNL_KIND_MASK;
 }
 
+#define MAX_LINK_DEPS 5
+struct link_deps_table {
+	int	tb[MAX_LINK_DEPS + 1];
+	int	data[MAX_LINK_DEPS + 1];
+};
+
+struct link_deps {
+	struct link_deps_table mandatory;
+	struct link_deps_table optional;
+};
+extern struct link_deps generic_newlink_deps;
+
 void rtnl_register(int protocol, int msgtype,
 		   rtnl_doit_func, rtnl_dumpit_func, unsigned int flags);
 int rtnl_register_module(struct module *owner, int protocol, int msgtype,
@@ -58,7 +70,9 @@ static inline int rtnl_msg_family(const struct nlmsghdr *nlh)
  *		and @setup are unused. Returns a netdev or ERR_PTR().
  *	@priv_size: sizeof net_device private space
  *	@setup: net_device setup function
+ *	@newlink_deps: Indexes of real devices that newlink depends on.
  *	@newlink: Function for configuring and registering a new device
+ *	@changelink_deps: Indexes of real devices that changelink depends on.
  *	@changelink: Function for changing parameters of an existing device
  *	@dellink: Function to remove a device
  *	@get_size: Function to calculate required room for dumping device
@@ -96,11 +110,13 @@ struct rtnl_link_ops {
 					    struct nlattr *data[],
 					    struct netlink_ext_ack *extack);
 
+	struct link_deps	*newlink_deps;
 	int			(*newlink)(struct net *src_net,
 					   struct net_device *dev,
 					   struct nlattr *tb[],
 					   struct nlattr *data[],
 					   struct netlink_ext_ack *extack);
+	struct link_deps	*changelink_deps;
 	int			(*changelink)(struct net_device *dev,
 					      struct nlattr *tb[],
 					      struct nlattr *data[],
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c
index cf5219df7903..c71180ba0746 100644
--- a/net/8021q/vlan_netlink.c
+++ b/net/8021q/vlan_netlink.c
@@ -293,6 +293,7 @@ struct rtnl_link_ops vlan_link_ops __read_mostly = {
 	.priv_size	= sizeof(struct vlan_dev_priv),
 	.setup		= vlan_setup,
 	.validate	= vlan_validate,
+	.newlink_deps	= &generic_newlink_deps,
 	.newlink	= vlan_newlink,
 	.changelink	= vlan_changelink,
 	.dellink	= unregister_vlan_dev,
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 046736091b4f..cf060ba4cd1d 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -3490,6 +3490,11 @@ static int rtnl_group_changelink(const struct sk_buff *skb,
 	return err;
 }
 
+struct link_deps generic_newlink_deps = {
+	.mandatory.tb = { IFLA_LINK, }
+};
+EXPORT_SYMBOL_GPL(generic_newlink_deps);
+
 static int rtnl_newlink_create(struct sk_buff *skb, struct ifinfomsg *ifm,
 			       const struct rtnl_link_ops *ops,
 			       const struct nlmsghdr *nlh,
diff --git a/net/dsa/netlink.c b/net/dsa/netlink.c
index 1332e56349e5..835d935814fb 100644
--- a/net/dsa/netlink.c
+++ b/net/dsa/netlink.c
@@ -11,6 +11,10 @@ static const struct nla_policy dsa_policy[IFLA_DSA_MAX + 1] = {
 	[IFLA_DSA_CONDUIT]	= { .type = NLA_U32 },
 };
 
+struct link_deps dsa_changelink_deps = {
+	.optional.data = { IFLA_DSA_CONDUIT, },
+};
+
 static int dsa_changelink(struct net_device *dev, struct nlattr *tb[],
 			  struct nlattr *data[],
 			  struct netlink_ext_ack *extack)
@@ -57,6 +61,7 @@ struct rtnl_link_ops dsa_link_ops __read_mostly = {
 	.priv_size		= sizeof(struct dsa_port),
 	.maxtype		= IFLA_DSA_MAX,
 	.policy			= dsa_policy,
+	.changelink_deps	= &dsa_changelink_deps,
 	.changelink		= dsa_changelink,
 	.get_size		= dsa_get_size,
 	.fill_info		= dsa_fill_info,
diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c
index f6ff0b61e08a..6ec883739415 100644
--- a/net/hsr/hsr_netlink.c
+++ b/net/hsr/hsr_netlink.c
@@ -176,12 +176,18 @@ static int hsr_fill_info(struct sk_buff *skb, const struct net_device *dev)
 	return -EMSGSIZE;
 }
 
+static struct link_deps hsr_newlink_deps = {
+	.mandatory.data = { IFLA_HSR_SLAVE1, IFLA_HSR_SLAVE2, },
+	.optional.data = { IFLA_HSR_INTERLINK, },
+};
+
 static struct rtnl_link_ops hsr_link_ops __read_mostly = {
 	.kind		= "hsr",
 	.maxtype	= IFLA_HSR_MAX,
 	.policy		= hsr_policy,
 	.priv_size	= sizeof(struct hsr_priv),
 	.setup		= hsr_dev_setup,
+	.newlink_deps	= &hsr_newlink_deps,
 	.newlink	= hsr_newlink,
 	.dellink	= hsr_dellink,
 	.fill_info	= hsr_fill_info,
diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c
index 77b4e92027c5..4236aafd448f 100644
--- a/net/ieee802154/6lowpan/core.c
+++ b/net/ieee802154/6lowpan/core.c
@@ -196,6 +196,7 @@ static struct rtnl_link_ops lowpan_link_ops __read_mostly = {
 	.kind		= "lowpan",
 	.priv_size	= LOWPAN_PRIV_SIZE(sizeof(struct lowpan_802154_dev)),
 	.setup		= lowpan_setup,
+	.newlink_deps	= &generic_newlink_deps,
 	.newlink	= lowpan_newlink,
 	.dellink	= lowpan_dellink,
 	.validate	= lowpan_validate,
