Commit e7199288 authored by Pavel Emelianov's avatar Pavel Emelianov Committed by David S. Miller

[RTNETLINK]: Introduce generic rtnl_create_link().

This routine gets the parsed rtnl attributes and creates a new
link with generic info (IFLA_LINKINFO policy). Its intention
is to help the drivers, that need to create several links at
once (like VETH).

This is nothing but a copy-paste-ed part of rtnl_newlink() function
that is responsible for creation of new device.
Signed-off-by: default avatarPavel Emelianov <xemul@openvz.org>
Acked-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bea3348e
...@@ -78,6 +78,10 @@ extern void __rtnl_link_unregister(struct rtnl_link_ops *ops); ...@@ -78,6 +78,10 @@ extern void __rtnl_link_unregister(struct rtnl_link_ops *ops);
extern int rtnl_link_register(struct rtnl_link_ops *ops); extern int rtnl_link_register(struct rtnl_link_ops *ops);
extern void rtnl_link_unregister(struct rtnl_link_ops *ops); extern void rtnl_link_unregister(struct rtnl_link_ops *ops);
extern struct net_device *rtnl_create_link(char *ifname,
const struct rtnl_link_ops *ops, struct nlattr *tb[]);
extern const struct nla_policy ifla_policy[IFLA_MAX+1];
#define MODULE_ALIAS_RTNL_LINK(kind) MODULE_ALIAS("rtnl-link-" kind) #define MODULE_ALIAS_RTNL_LINK(kind) MODULE_ALIAS("rtnl-link-" kind)
#endif #endif
...@@ -713,7 +713,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -713,7 +713,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len; return skb->len;
} }
static const struct nla_policy ifla_policy[IFLA_MAX+1] = { const struct nla_policy ifla_policy[IFLA_MAX+1] = {
[IFLA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ-1 }, [IFLA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ-1 },
[IFLA_ADDRESS] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN }, [IFLA_ADDRESS] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
[IFLA_BROADCAST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN }, [IFLA_BROADCAST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
...@@ -937,6 +937,48 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) ...@@ -937,6 +937,48 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
return 0; return 0;
} }
struct net_device *rtnl_create_link(char *ifname,
const struct rtnl_link_ops *ops, struct nlattr *tb[])
{
int err;
struct net_device *dev;
err = -ENOMEM;
dev = alloc_netdev(ops->priv_size, ifname, ops->setup);
if (!dev)
goto err;
if (strchr(dev->name, '%')) {
err = dev_alloc_name(dev, dev->name);
if (err < 0)
goto err_free;
}
dev->rtnl_link_ops = ops;
if (tb[IFLA_MTU])
dev->mtu = nla_get_u32(tb[IFLA_MTU]);
if (tb[IFLA_ADDRESS])
memcpy(dev->dev_addr, nla_data(tb[IFLA_ADDRESS]),
nla_len(tb[IFLA_ADDRESS]));
if (tb[IFLA_BROADCAST])
memcpy(dev->broadcast, nla_data(tb[IFLA_BROADCAST]),
nla_len(tb[IFLA_BROADCAST]));
if (tb[IFLA_TXQLEN])
dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);
if (tb[IFLA_OPERSTATE])
set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]));
if (tb[IFLA_LINKMODE])
dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]);
return dev;
err_free:
free_netdev(dev);
err:
return ERR_PTR(err);
}
static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{ {
const struct rtnl_link_ops *ops; const struct rtnl_link_ops *ops;
...@@ -1049,38 +1091,17 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) ...@@ -1049,38 +1091,17 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
if (!ifname[0]) if (!ifname[0])
snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind);
dev = alloc_netdev(ops->priv_size, ifname, ops->setup);
if (!dev) dev = rtnl_create_link(ifname, ops, tb);
return -ENOMEM;
if (IS_ERR(dev))
if (strchr(dev->name, '%')) { err = PTR_ERR(dev);
err = dev_alloc_name(dev, dev->name); else if (ops->newlink)
if (err < 0)
goto err_free;
}
dev->rtnl_link_ops = ops;
if (tb[IFLA_MTU])
dev->mtu = nla_get_u32(tb[IFLA_MTU]);
if (tb[IFLA_ADDRESS])
memcpy(dev->dev_addr, nla_data(tb[IFLA_ADDRESS]),
nla_len(tb[IFLA_ADDRESS]));
if (tb[IFLA_BROADCAST])
memcpy(dev->broadcast, nla_data(tb[IFLA_BROADCAST]),
nla_len(tb[IFLA_BROADCAST]));
if (tb[IFLA_TXQLEN])
dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);
if (tb[IFLA_OPERSTATE])
set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]));
if (tb[IFLA_LINKMODE])
dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]);
if (ops->newlink)
err = ops->newlink(dev, tb, data); err = ops->newlink(dev, tb, data);
else else
err = register_netdevice(dev); err = register_netdevice(dev);
err_free:
if (err < 0) if (err < 0 && !IS_ERR(dev))
free_netdev(dev); free_netdev(dev);
return err; return err;
} }
...@@ -1329,3 +1350,5 @@ EXPORT_SYMBOL(rtnl_unlock); ...@@ -1329,3 +1350,5 @@ EXPORT_SYMBOL(rtnl_unlock);
EXPORT_SYMBOL(rtnl_unicast); EXPORT_SYMBOL(rtnl_unicast);
EXPORT_SYMBOL(rtnl_notify); EXPORT_SYMBOL(rtnl_notify);
EXPORT_SYMBOL(rtnl_set_sk_err); EXPORT_SYMBOL(rtnl_set_sk_err);
EXPORT_SYMBOL(rtnl_create_link);
EXPORT_SYMBOL(ifla_policy);
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