@@ -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,
@@ -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,
@@ -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,
@@ -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,
@@ -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,
@@ -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),
@@ -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,
@@ -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,
@@ -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,
@@ -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,
@@ -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),
@@ -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[],
@@ -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,
@@ -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,
@@ -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,
@@ -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,
@@ -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,
This is to get rtnetlink code knowledge about devices touching by newlink and changelink to bring them to the same lock group. Signed-off-by: Kirill Tkhai <tkhai@ya.ru> --- drivers/infiniband/ulp/ipoib/ipoib_netlink.c | 1 + drivers/net/amt.c | 5 +++++ drivers/net/bonding/bond_netlink.c | 5 +++++ drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 1 + drivers/net/ipvlan/ipvlan_main.c | 1 + drivers/net/ipvlan/ipvtap.c | 1 + drivers/net/macsec.c | 1 + drivers/net/macvlan.c | 1 + drivers/net/macvtap.c | 1 + drivers/net/vxlan/vxlan_core.c | 6 ++++++ drivers/net/wireless/virtual/virt_wifi.c | 1 + include/net/rtnetlink.h | 16 ++++++++++++++++ net/8021q/vlan_netlink.c | 1 + net/core/rtnetlink.c | 5 +++++ net/dsa/netlink.c | 5 +++++ net/hsr/hsr_netlink.c | 6 ++++++ net/ieee802154/6lowpan/core.c | 1 + 17 files changed, 58 insertions(+)