diff options
author | Pavel Emelianov <xemul@openvz.org> | 2007-08-09 01:16:38 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-10 19:47:45 -0400 |
commit | e71992889ee289a87f6641cfa40d64a5699bcb53 (patch) | |
tree | d078d6a4d98348518229ad12ad3ecc847680c884 /net/core | |
parent | bea3348eef27e6044b6161fd04c3152215f96411 (diff) |
[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: Pavel Emelianov <xemul@openvz.org>
Acked-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/rtnetlink.c | 83 |
1 files changed, 53 insertions, 30 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 2b0b6fac6cef..dca9e80ba574 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -713,7 +713,7 @@ cont: | |||
713 | return skb->len; | 713 | return skb->len; |
714 | } | 714 | } |
715 | 715 | ||
716 | static const struct nla_policy ifla_policy[IFLA_MAX+1] = { | 716 | const struct nla_policy ifla_policy[IFLA_MAX+1] = { |
717 | [IFLA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ-1 }, | 717 | [IFLA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ-1 }, |
718 | [IFLA_ADDRESS] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN }, | 718 | [IFLA_ADDRESS] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN }, |
719 | [IFLA_BROADCAST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN }, | 719 | [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 | return 0; | 937 | return 0; |
938 | } | 938 | } |
939 | 939 | ||
940 | struct net_device *rtnl_create_link(char *ifname, | ||
941 | const struct rtnl_link_ops *ops, struct nlattr *tb[]) | ||
942 | { | ||
943 | int err; | ||
944 | struct net_device *dev; | ||
945 | |||
946 | err = -ENOMEM; | ||
947 | dev = alloc_netdev(ops->priv_size, ifname, ops->setup); | ||
948 | if (!dev) | ||
949 | goto err; | ||
950 | |||
951 | if (strchr(dev->name, '%')) { | ||
952 | err = dev_alloc_name(dev, dev->name); | ||
953 | if (err < 0) | ||
954 | goto err_free; | ||
955 | } | ||
956 | |||
957 | dev->rtnl_link_ops = ops; | ||
958 | |||
959 | if (tb[IFLA_MTU]) | ||
960 | dev->mtu = nla_get_u32(tb[IFLA_MTU]); | ||
961 | if (tb[IFLA_ADDRESS]) | ||
962 | memcpy(dev->dev_addr, nla_data(tb[IFLA_ADDRESS]), | ||
963 | nla_len(tb[IFLA_ADDRESS])); | ||
964 | if (tb[IFLA_BROADCAST]) | ||
965 | memcpy(dev->broadcast, nla_data(tb[IFLA_BROADCAST]), | ||
966 | nla_len(tb[IFLA_BROADCAST])); | ||
967 | if (tb[IFLA_TXQLEN]) | ||
968 | dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); | ||
969 | if (tb[IFLA_OPERSTATE]) | ||
970 | set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); | ||
971 | if (tb[IFLA_LINKMODE]) | ||
972 | dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]); | ||
973 | |||
974 | return dev; | ||
975 | |||
976 | err_free: | ||
977 | free_netdev(dev); | ||
978 | err: | ||
979 | return ERR_PTR(err); | ||
980 | } | ||
981 | |||
940 | static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 982 | static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
941 | { | 983 | { |
942 | const struct rtnl_link_ops *ops; | 984 | const struct rtnl_link_ops *ops; |
@@ -1049,38 +1091,17 @@ replay: | |||
1049 | 1091 | ||
1050 | if (!ifname[0]) | 1092 | if (!ifname[0]) |
1051 | snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); | 1093 | snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); |
1052 | dev = alloc_netdev(ops->priv_size, ifname, ops->setup); | 1094 | |
1053 | if (!dev) | 1095 | dev = rtnl_create_link(ifname, ops, tb); |
1054 | return -ENOMEM; | 1096 | |
1055 | 1097 | if (IS_ERR(dev)) | |
1056 | if (strchr(dev->name, '%')) { | 1098 | err = PTR_ERR(dev); |
1057 | err = dev_alloc_name(dev, dev->name); | 1099 | else if (ops->newlink) |
1058 | if (err < 0) | ||
1059 | goto err_free; | ||
1060 | } | ||
1061 | dev->rtnl_link_ops = ops; | ||
1062 | |||
1063 | if (tb[IFLA_MTU]) | ||
1064 | dev->mtu = nla_get_u32(tb[IFLA_MTU]); | ||
1065 | if (tb[IFLA_ADDRESS]) | ||
1066 | memcpy(dev->dev_addr, nla_data(tb[IFLA_ADDRESS]), | ||
1067 | nla_len(tb[IFLA_ADDRESS])); | ||
1068 | if (tb[IFLA_BROADCAST]) | ||
1069 | memcpy(dev->broadcast, nla_data(tb[IFLA_BROADCAST]), | ||
1070 | nla_len(tb[IFLA_BROADCAST])); | ||
1071 | if (tb[IFLA_TXQLEN]) | ||
1072 | dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); | ||
1073 | if (tb[IFLA_OPERSTATE]) | ||
1074 | set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); | ||
1075 | if (tb[IFLA_LINKMODE]) | ||
1076 | dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]); | ||
1077 | |||
1078 | if (ops->newlink) | ||
1079 | err = ops->newlink(dev, tb, data); | 1100 | err = ops->newlink(dev, tb, data); |
1080 | else | 1101 | else |
1081 | err = register_netdevice(dev); | 1102 | err = register_netdevice(dev); |
1082 | err_free: | 1103 | |
1083 | if (err < 0) | 1104 | if (err < 0 && !IS_ERR(dev)) |
1084 | free_netdev(dev); | 1105 | free_netdev(dev); |
1085 | return err; | 1106 | return err; |
1086 | } | 1107 | } |
@@ -1329,3 +1350,5 @@ EXPORT_SYMBOL(rtnl_unlock); | |||
1329 | EXPORT_SYMBOL(rtnl_unicast); | 1350 | EXPORT_SYMBOL(rtnl_unicast); |
1330 | EXPORT_SYMBOL(rtnl_notify); | 1351 | EXPORT_SYMBOL(rtnl_notify); |
1331 | EXPORT_SYMBOL(rtnl_set_sk_err); | 1352 | EXPORT_SYMBOL(rtnl_set_sk_err); |
1353 | EXPORT_SYMBOL(rtnl_create_link); | ||
1354 | EXPORT_SYMBOL(ifla_policy); | ||