Commit 420d0318 authored by Jakub Kicinski's avatar Jakub Kicinski Committed by David S. Miller

rtnetlink: remove a level of indentation in rtnl_newlink()

rtnl_newlink() used to create VLAs based on link kind.  Since
commit ccf8dbcd ("rtnetlink: Remove VLA usage") statically
sized array is created on the stack, so there is no more use
for a separate code block that used to be the VLA's live range.

While at it christmas tree the variables.  Note that there is
a goto-based retry so to be on the safe side the variables can
no longer be initialized in place.  It doesn't seem to matter,
logically, but why make the code harder to read..
Signed-off-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: default avatarDavid Ahern <dsahern@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 74315c39
...@@ -2974,17 +2974,22 @@ static int rtnl_group_changelink(const struct sk_buff *skb, ...@@ -2974,17 +2974,22 @@ static int rtnl_group_changelink(const struct sk_buff *skb,
static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct nlattr *slave_attr[RTNL_SLAVE_MAX_TYPE + 1];
unsigned char name_assign_type = NET_NAME_USER;
struct nlattr *linkinfo[IFLA_INFO_MAX + 1];
const struct rtnl_link_ops *m_ops = NULL;
struct nlattr *attr[RTNL_MAX_TYPE + 1];
struct net_device *master_dev = NULL;
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
const struct rtnl_link_ops *ops; const struct rtnl_link_ops *ops;
const struct rtnl_link_ops *m_ops = NULL; struct nlattr *tb[IFLA_MAX + 1];
struct net *dest_net, *link_net;
struct nlattr **slave_data;
char kind[MODULE_NAME_LEN];
struct net_device *dev; struct net_device *dev;
struct net_device *master_dev = NULL;
struct ifinfomsg *ifm; struct ifinfomsg *ifm;
char kind[MODULE_NAME_LEN];
char ifname[IFNAMSIZ]; char ifname[IFNAMSIZ];
struct nlattr *tb[IFLA_MAX+1]; struct nlattr **data;
struct nlattr *linkinfo[IFLA_INFO_MAX+1];
unsigned char name_assign_type = NET_NAME_USER;
int err; int err;
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
...@@ -3040,195 +3045,185 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -3040,195 +3045,185 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
ops = NULL; ops = NULL;
} }
if (1) { data = NULL;
struct nlattr *attr[RTNL_MAX_TYPE + 1]; if (ops) {
struct nlattr *slave_attr[RTNL_SLAVE_MAX_TYPE + 1]; if (ops->maxtype > RTNL_MAX_TYPE)
struct nlattr **data = NULL; return -EINVAL;
struct nlattr **slave_data = NULL;
struct net *dest_net, *link_net = NULL;
if (ops) {
if (ops->maxtype > RTNL_MAX_TYPE)
return -EINVAL;
if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) { if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) {
err = nla_parse_nested(attr, ops->maxtype, err = nla_parse_nested(attr, ops->maxtype,
linkinfo[IFLA_INFO_DATA], linkinfo[IFLA_INFO_DATA],
ops->policy, extack); ops->policy, extack);
if (err < 0) if (err < 0)
return err; return err;
data = attr; data = attr;
} }
if (ops->validate) { if (ops->validate) {
err = ops->validate(tb, data, extack); err = ops->validate(tb, data, extack);
if (err < 0) if (err < 0)
return err; return err;
}
} }
}
if (m_ops) { slave_data = NULL;
if (m_ops->slave_maxtype > RTNL_SLAVE_MAX_TYPE) if (m_ops) {
return -EINVAL; if (m_ops->slave_maxtype > RTNL_SLAVE_MAX_TYPE)
return -EINVAL;
if (m_ops->slave_maxtype && if (m_ops->slave_maxtype &&
linkinfo[IFLA_INFO_SLAVE_DATA]) { linkinfo[IFLA_INFO_SLAVE_DATA]) {
err = nla_parse_nested(slave_attr, err = nla_parse_nested(slave_attr, m_ops->slave_maxtype,
m_ops->slave_maxtype, linkinfo[IFLA_INFO_SLAVE_DATA],
linkinfo[IFLA_INFO_SLAVE_DATA], m_ops->slave_policy, extack);
m_ops->slave_policy, if (err < 0)
extack); return err;
if (err < 0) slave_data = slave_attr;
return err;
slave_data = slave_attr;
}
} }
}
if (dev) { if (dev) {
int status = 0; int status = 0;
if (nlh->nlmsg_flags & NLM_F_EXCL)
return -EEXIST;
if (nlh->nlmsg_flags & NLM_F_REPLACE)
return -EOPNOTSUPP;
if (linkinfo[IFLA_INFO_DATA]) { if (nlh->nlmsg_flags & NLM_F_EXCL)
if (!ops || ops != dev->rtnl_link_ops || return -EEXIST;
!ops->changelink) if (nlh->nlmsg_flags & NLM_F_REPLACE)
return -EOPNOTSUPP; return -EOPNOTSUPP;
err = ops->changelink(dev, tb, data, extack); if (linkinfo[IFLA_INFO_DATA]) {
if (err < 0) if (!ops || ops != dev->rtnl_link_ops ||
return err; !ops->changelink)
status |= DO_SETLINK_NOTIFY; return -EOPNOTSUPP;
}
if (linkinfo[IFLA_INFO_SLAVE_DATA]) { err = ops->changelink(dev, tb, data, extack);
if (!m_ops || !m_ops->slave_changelink) if (err < 0)
return -EOPNOTSUPP; return err;
status |= DO_SETLINK_NOTIFY;
}
err = m_ops->slave_changelink(master_dev, dev, if (linkinfo[IFLA_INFO_SLAVE_DATA]) {
tb, slave_data, if (!m_ops || !m_ops->slave_changelink)
extack); return -EOPNOTSUPP;
if (err < 0)
return err;
status |= DO_SETLINK_NOTIFY;
}
return do_setlink(skb, dev, ifm, extack, tb, ifname, err = m_ops->slave_changelink(master_dev, dev, tb,
status); slave_data, extack);
if (err < 0)
return err;
status |= DO_SETLINK_NOTIFY;
} }
if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { return do_setlink(skb, dev, ifm, extack, tb, ifname, status);
if (ifm->ifi_index == 0 && tb[IFLA_GROUP]) }
return rtnl_group_changelink(skb, net,
if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
if (ifm->ifi_index == 0 && tb[IFLA_GROUP])
return rtnl_group_changelink(skb, net,
nla_get_u32(tb[IFLA_GROUP]), nla_get_u32(tb[IFLA_GROUP]),
ifm, extack, tb); ifm, extack, tb);
return -ENODEV; return -ENODEV;
} }
if (tb[IFLA_MAP] || tb[IFLA_PROTINFO]) if (tb[IFLA_MAP] || tb[IFLA_PROTINFO])
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (!ops) { if (!ops) {
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
if (kind[0]) { if (kind[0]) {
__rtnl_unlock(); __rtnl_unlock();
request_module("rtnl-link-%s", kind); request_module("rtnl-link-%s", kind);
rtnl_lock(); rtnl_lock();
ops = rtnl_link_ops_get(kind); ops = rtnl_link_ops_get(kind);
if (ops) if (ops)
goto replay; goto replay;
}
#endif
NL_SET_ERR_MSG(extack, "Unknown device type");
return -EOPNOTSUPP;
} }
#endif
NL_SET_ERR_MSG(extack, "Unknown device type");
return -EOPNOTSUPP;
}
if (!ops->setup) if (!ops->setup)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (!ifname[0]) {
snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind);
name_assign_type = NET_NAME_ENUM;
}
dest_net = rtnl_link_get_net_capable(skb, net, tb, CAP_NET_ADMIN); if (!ifname[0]) {
if (IS_ERR(dest_net)) snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind);
return PTR_ERR(dest_net); name_assign_type = NET_NAME_ENUM;
}
if (tb[IFLA_LINK_NETNSID]) { dest_net = rtnl_link_get_net_capable(skb, net, tb, CAP_NET_ADMIN);
int id = nla_get_s32(tb[IFLA_LINK_NETNSID]); if (IS_ERR(dest_net))
return PTR_ERR(dest_net);
link_net = get_net_ns_by_id(dest_net, id); if (tb[IFLA_LINK_NETNSID]) {
if (!link_net) { int id = nla_get_s32(tb[IFLA_LINK_NETNSID]);
NL_SET_ERR_MSG(extack, "Unknown network namespace id");
err = -EINVAL;
goto out;
}
err = -EPERM;
if (!netlink_ns_capable(skb, link_net->user_ns, CAP_NET_ADMIN))
goto out;
}
dev = rtnl_create_link(link_net ? : dest_net, ifname, link_net = get_net_ns_by_id(dest_net, id);
name_assign_type, ops, tb, extack); if (!link_net) {
if (IS_ERR(dev)) { NL_SET_ERR_MSG(extack, "Unknown network namespace id");
err = PTR_ERR(dev); err = -EINVAL;
goto out; goto out;
} }
err = -EPERM;
if (!netlink_ns_capable(skb, link_net->user_ns, CAP_NET_ADMIN))
goto out;
} else {
link_net = NULL;
}
dev->ifindex = ifm->ifi_index; dev = rtnl_create_link(link_net ? : dest_net, ifname,
name_assign_type, ops, tb, extack);
if (IS_ERR(dev)) {
err = PTR_ERR(dev);
goto out;
}
if (ops->newlink) { dev->ifindex = ifm->ifi_index;
err = ops->newlink(link_net ? : net, dev, tb, data,
extack); if (ops->newlink) {
/* Drivers should call free_netdev() in ->destructor err = ops->newlink(link_net ? : net, dev, tb, data, extack);
* and unregister it on failure after registration /* Drivers should call free_netdev() in ->destructor
* so that device could be finally freed in rtnl_unlock. * and unregister it on failure after registration
*/ * so that device could be finally freed in rtnl_unlock.
if (err < 0) { */
/* If device is not registered at all, free it now */ if (err < 0) {
if (dev->reg_state == NETREG_UNINITIALIZED) /* If device is not registered at all, free it now */
free_netdev(dev); if (dev->reg_state == NETREG_UNINITIALIZED)
goto out;
}
} else {
err = register_netdevice(dev);
if (err < 0) {
free_netdev(dev); free_netdev(dev);
goto out; goto out;
} }
} else {
err = register_netdevice(dev);
if (err < 0) {
free_netdev(dev);
goto out;
} }
err = rtnl_configure_link(dev, ifm); }
err = rtnl_configure_link(dev, ifm);
if (err < 0)
goto out_unregister;
if (link_net) {
err = dev_change_net_namespace(dev, dest_net, ifname);
if (err < 0) if (err < 0)
goto out_unregister; goto out_unregister;
if (link_net) { }
err = dev_change_net_namespace(dev, dest_net, ifname); if (tb[IFLA_MASTER]) {
if (err < 0) err = do_set_master(dev, nla_get_u32(tb[IFLA_MASTER]), extack);
goto out_unregister; if (err)
} goto out_unregister;
if (tb[IFLA_MASTER]) { }
err = do_set_master(dev, nla_get_u32(tb[IFLA_MASTER]),
extack);
if (err)
goto out_unregister;
}
out: out:
if (link_net) if (link_net)
put_net(link_net); put_net(link_net);
put_net(dest_net); put_net(dest_net);
return err; return err;
out_unregister: out_unregister:
if (ops->newlink) { if (ops->newlink) {
LIST_HEAD(list_kill); LIST_HEAD(list_kill);
ops->dellink(dev, &list_kill); ops->dellink(dev, &list_kill);
unregister_netdevice_many(&list_kill); unregister_netdevice_many(&list_kill);
} else { } else {
unregister_netdevice(dev); unregister_netdevice(dev);
}
goto out;
} }
goto out;
} }
static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh, static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment