aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2007-06-13 15:03:51 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-07-11 01:14:20 -0400
commit38f7b870d4a6a5d3ec21557e849620cb7d032965 (patch)
treea3a35058298554a87f90b8bd1694cac5c5a1eaa6 /net
parent0157f60c0caea24fa8347f4c0ed53297c412fce1 (diff)
[RTNETLINK]: Link creation API
Add rtnetlink API for creating, changing and deleting software devices. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/core/rtnetlink.c342
1 files changed, 335 insertions, 7 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 25ca219154e0..06c0c5afabf0 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -243,6 +243,143 @@ void rtnl_unregister_all(int protocol)
243 243
244EXPORT_SYMBOL_GPL(rtnl_unregister_all); 244EXPORT_SYMBOL_GPL(rtnl_unregister_all);
245 245
246static LIST_HEAD(link_ops);
247
248/**
249 * __rtnl_link_register - Register rtnl_link_ops with rtnetlink.
250 * @ops: struct rtnl_link_ops * to register
251 *
252 * The caller must hold the rtnl_mutex. This function should be used
253 * by drivers that create devices during module initialization. It
254 * must be called before registering the devices.
255 *
256 * Returns 0 on success or a negative error code.
257 */
258int __rtnl_link_register(struct rtnl_link_ops *ops)
259{
260 list_add_tail(&ops->list, &link_ops);
261 return 0;
262}
263
264EXPORT_SYMBOL_GPL(__rtnl_link_register);
265
266/**
267 * rtnl_link_register - Register rtnl_link_ops with rtnetlink.
268 * @ops: struct rtnl_link_ops * to register
269 *
270 * Returns 0 on success or a negative error code.
271 */
272int rtnl_link_register(struct rtnl_link_ops *ops)
273{
274 int err;
275
276 rtnl_lock();
277 err = __rtnl_link_register(ops);
278 rtnl_unlock();
279 return err;
280}
281
282EXPORT_SYMBOL_GPL(rtnl_link_register);
283
284/**
285 * __rtnl_link_unregister - Unregister rtnl_link_ops from rtnetlink.
286 * @ops: struct rtnl_link_ops * to unregister
287 *
288 * The caller must hold the rtnl_mutex. This function should be used
289 * by drivers that unregister devices during module unloading. It must
290 * be called after unregistering the devices.
291 */
292void __rtnl_link_unregister(struct rtnl_link_ops *ops)
293{
294 list_del(&ops->list);
295}
296
297EXPORT_SYMBOL_GPL(__rtnl_link_unregister);
298
299/**
300 * rtnl_link_unregister - Unregister rtnl_link_ops from rtnetlink.
301 * @ops: struct rtnl_link_ops * to unregister
302 */
303void rtnl_link_unregister(struct rtnl_link_ops *ops)
304{
305 rtnl_lock();
306 __rtnl_link_unregister(ops);
307 rtnl_unlock();
308}
309
310EXPORT_SYMBOL_GPL(rtnl_link_unregister);
311
312static const struct rtnl_link_ops *rtnl_link_ops_get(const char *kind)
313{
314 const struct rtnl_link_ops *ops;
315
316 list_for_each_entry(ops, &link_ops, list) {
317 if (!strcmp(ops->kind, kind))
318 return ops;
319 }
320 return NULL;
321}
322
323static size_t rtnl_link_get_size(const struct net_device *dev)
324{
325 const struct rtnl_link_ops *ops = dev->rtnl_link_ops;
326 size_t size;
327
328 if (!ops)
329 return 0;
330
331 size = nlmsg_total_size(sizeof(struct nlattr)) + /* IFLA_LINKINFO */
332 nlmsg_total_size(strlen(ops->kind) + 1); /* IFLA_INFO_KIND */
333
334 if (ops->get_size)
335 /* IFLA_INFO_DATA + nested data */
336 size += nlmsg_total_size(sizeof(struct nlattr)) +
337 ops->get_size(dev);
338
339 if (ops->get_xstats_size)
340 size += ops->get_xstats_size(dev); /* IFLA_INFO_XSTATS */
341
342 return size;
343}
344
345static int rtnl_link_fill(struct sk_buff *skb, const struct net_device *dev)
346{
347 const struct rtnl_link_ops *ops = dev->rtnl_link_ops;
348 struct nlattr *linkinfo, *data;
349 int err = -EMSGSIZE;
350
351 linkinfo = nla_nest_start(skb, IFLA_LINKINFO);
352 if (linkinfo == NULL)
353 goto out;
354
355 if (nla_put_string(skb, IFLA_INFO_KIND, ops->kind) < 0)
356 goto err_cancel_link;
357 if (ops->fill_xstats) {
358 err = ops->fill_xstats(skb, dev);
359 if (err < 0)
360 goto err_cancel_link;
361 }
362 if (ops->fill_info) {
363 data = nla_nest_start(skb, IFLA_INFO_DATA);
364 if (data == NULL)
365 goto err_cancel_link;
366 err = ops->fill_info(skb, dev);
367 if (err < 0)
368 goto err_cancel_data;
369 nla_nest_end(skb, data);
370 }
371
372 nla_nest_end(skb, linkinfo);
373 return 0;
374
375err_cancel_data:
376 nla_nest_cancel(skb, data);
377err_cancel_link:
378 nla_nest_cancel(skb, linkinfo);
379out:
380 return err;
381}
382
246static const int rtm_min[RTM_NR_FAMILIES] = 383static const int rtm_min[RTM_NR_FAMILIES] =
247{ 384{
248 [RTM_FAM(RTM_NEWLINK)] = NLMSG_LENGTH(sizeof(struct ifinfomsg)), 385 [RTM_FAM(RTM_NEWLINK)] = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
@@ -437,7 +574,7 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
437 a->tx_compressed = b->tx_compressed; 574 a->tx_compressed = b->tx_compressed;
438}; 575};
439 576
440static inline size_t if_nlmsg_size(void) 577static inline size_t if_nlmsg_size(const struct net_device *dev)
441{ 578{
442 return NLMSG_ALIGN(sizeof(struct ifinfomsg)) 579 return NLMSG_ALIGN(sizeof(struct ifinfomsg))
443 + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */ 580 + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
@@ -452,7 +589,8 @@ static inline size_t if_nlmsg_size(void)
452 + nla_total_size(4) /* IFLA_LINK */ 589 + nla_total_size(4) /* IFLA_LINK */
453 + nla_total_size(4) /* IFLA_MASTER */ 590 + nla_total_size(4) /* IFLA_MASTER */
454 + nla_total_size(1) /* IFLA_OPERSTATE */ 591 + nla_total_size(1) /* IFLA_OPERSTATE */
455 + nla_total_size(1); /* IFLA_LINKMODE */ 592 + nla_total_size(1) /* IFLA_LINKMODE */
593 + rtnl_link_get_size(dev); /* IFLA_LINKINFO */
456} 594}
457 595
458static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, 596static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
@@ -522,6 +660,11 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
522 } 660 }
523 } 661 }
524 662
663 if (dev->rtnl_link_ops) {
664 if (rtnl_link_fill(skb, dev) < 0)
665 goto nla_put_failure;
666 }
667
525 return nlmsg_end(skb, nlh); 668 return nlmsg_end(skb, nlh);
526 669
527nla_put_failure: 670nla_put_failure:
@@ -553,6 +696,8 @@ cont:
553 696
554static const struct nla_policy ifla_policy[IFLA_MAX+1] = { 697static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
555 [IFLA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ-1 }, 698 [IFLA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ-1 },
699 [IFLA_ADDRESS] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
700 [IFLA_BROADCAST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
556 [IFLA_MAP] = { .len = sizeof(struct rtnl_link_ifmap) }, 701 [IFLA_MAP] = { .len = sizeof(struct rtnl_link_ifmap) },
557 [IFLA_MTU] = { .type = NLA_U32 }, 702 [IFLA_MTU] = { .type = NLA_U32 },
558 [IFLA_TXQLEN] = { .type = NLA_U32 }, 703 [IFLA_TXQLEN] = { .type = NLA_U32 },
@@ -561,10 +706,15 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
561 [IFLA_LINKMODE] = { .type = NLA_U8 }, 706 [IFLA_LINKMODE] = { .type = NLA_U8 },
562}; 707};
563 708
709static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
710 [IFLA_INFO_KIND] = { .type = NLA_STRING },
711 [IFLA_INFO_DATA] = { .type = NLA_NESTED },
712};
713
564static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, 714static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
565 struct nlattr **tb, char *ifname) 715 struct nlattr **tb, char *ifname, int modified)
566{ 716{
567 int modified = 0, send_addr_notify = 0; 717 int send_addr_notify = 0;
568 int err; 718 int err;
569 719
570 if (tb[IFLA_MAP]) { 720 if (tb[IFLA_MAP]) {
@@ -729,13 +879,189 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
729 nla_len(tb[IFLA_BROADCAST]) < dev->addr_len) 879 nla_len(tb[IFLA_BROADCAST]) < dev->addr_len)
730 goto errout_dev; 880 goto errout_dev;
731 881
732 err = do_setlink(dev, ifm, tb, ifname); 882 err = do_setlink(dev, ifm, tb, ifname, 0);
733errout_dev: 883errout_dev:
734 dev_put(dev); 884 dev_put(dev);
735errout: 885errout:
736 return err; 886 return err;
737} 887}
738 888
889static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
890{
891 const struct rtnl_link_ops *ops;
892 struct net_device *dev;
893 struct ifinfomsg *ifm;
894 char ifname[IFNAMSIZ];
895 struct nlattr *tb[IFLA_MAX+1];
896 int err;
897
898 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
899 if (err < 0)
900 return err;
901
902 if (tb[IFLA_IFNAME])
903 nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
904
905 ifm = nlmsg_data(nlh);
906 if (ifm->ifi_index > 0)
907 dev = __dev_get_by_index(ifm->ifi_index);
908 else if (tb[IFLA_IFNAME])
909 dev = __dev_get_by_name(ifname);
910 else
911 return -EINVAL;
912
913 if (!dev)
914 return -ENODEV;
915
916 ops = dev->rtnl_link_ops;
917 if (!ops)
918 return -EOPNOTSUPP;
919
920 ops->dellink(dev);
921 return 0;
922}
923
924static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
925{
926 const struct rtnl_link_ops *ops;
927 struct net_device *dev;
928 struct ifinfomsg *ifm;
929 char kind[MODULE_NAME_LEN];
930 char ifname[IFNAMSIZ];
931 struct nlattr *tb[IFLA_MAX+1];
932 struct nlattr *linkinfo[IFLA_INFO_MAX+1];
933 int err;
934
935replay:
936 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
937 if (err < 0)
938 return err;
939
940 if (tb[IFLA_IFNAME])
941 nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
942 else
943 ifname[0] = '\0';
944
945 ifm = nlmsg_data(nlh);
946 if (ifm->ifi_index > 0)
947 dev = __dev_get_by_index(ifm->ifi_index);
948 else if (ifname[0])
949 dev = __dev_get_by_name(ifname);
950 else
951 dev = NULL;
952
953 if (tb[IFLA_LINKINFO]) {
954 err = nla_parse_nested(linkinfo, IFLA_INFO_MAX,
955 tb[IFLA_LINKINFO], ifla_info_policy);
956 if (err < 0)
957 return err;
958 } else
959 memset(linkinfo, 0, sizeof(linkinfo));
960
961 if (linkinfo[IFLA_INFO_KIND]) {
962 nla_strlcpy(kind, linkinfo[IFLA_INFO_KIND], sizeof(kind));
963 ops = rtnl_link_ops_get(kind);
964 } else {
965 kind[0] = '\0';
966 ops = NULL;
967 }
968
969 if (1) {
970 struct nlattr *attr[ops ? ops->maxtype + 1 : 0], **data = NULL;
971
972 if (ops) {
973 if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) {
974 err = nla_parse_nested(attr, ops->maxtype,
975 linkinfo[IFLA_INFO_DATA],
976 ops->policy);
977 if (err < 0)
978 return err;
979 data = attr;
980 }
981 if (ops->validate) {
982 err = ops->validate(tb, data);
983 if (err < 0)
984 return err;
985 }
986 }
987
988 if (dev) {
989 int modified = 0;
990
991 if (nlh->nlmsg_flags & NLM_F_EXCL)
992 return -EEXIST;
993 if (nlh->nlmsg_flags & NLM_F_REPLACE)
994 return -EOPNOTSUPP;
995
996 if (linkinfo[IFLA_INFO_DATA]) {
997 if (!ops || ops != dev->rtnl_link_ops ||
998 !ops->changelink)
999 return -EOPNOTSUPP;
1000
1001 err = ops->changelink(dev, tb, data);
1002 if (err < 0)
1003 return err;
1004 modified = 1;
1005 }
1006
1007 return do_setlink(dev, ifm, tb, ifname, modified);
1008 }
1009
1010 if (!(nlh->nlmsg_flags & NLM_F_CREATE))
1011 return -ENODEV;
1012
1013 if (ifm->ifi_index || ifm->ifi_flags || ifm->ifi_change)
1014 return -EOPNOTSUPP;
1015 if (tb[IFLA_ADDRESS] || tb[IFLA_BROADCAST] || tb[IFLA_MAP] ||
1016 tb[IFLA_MASTER] || tb[IFLA_PROTINFO])
1017 return -EOPNOTSUPP;
1018
1019 if (!ops) {
1020#ifdef CONFIG_KMOD
1021 if (kind[0]) {
1022 __rtnl_unlock();
1023 request_module("rtnl-link-%s", kind);
1024 rtnl_lock();
1025 ops = rtnl_link_ops_get(kind);
1026 if (ops)
1027 goto replay;
1028 }
1029#endif
1030 return -EOPNOTSUPP;
1031 }
1032
1033 if (!ifname[0])
1034 snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind);
1035 dev = alloc_netdev(ops->priv_size, ifname, ops->setup);
1036 if (!dev)
1037 return -ENOMEM;
1038
1039 if (strchr(dev->name, '%')) {
1040 err = dev_alloc_name(dev, dev->name);
1041 if (err < 0)
1042 goto err_free;
1043 }
1044 dev->rtnl_link_ops = ops;
1045
1046 if (tb[IFLA_MTU])
1047 dev->mtu = nla_get_u32(tb[IFLA_MTU]);
1048 if (tb[IFLA_TXQLEN])
1049 dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);
1050 if (tb[IFLA_WEIGHT])
1051 dev->weight = nla_get_u32(tb[IFLA_WEIGHT]);
1052 if (tb[IFLA_OPERSTATE])
1053 set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]));
1054 if (tb[IFLA_LINKMODE])
1055 dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]);
1056
1057 err = ops->newlink(dev, tb, data);
1058err_free:
1059 if (err < 0)
1060 free_netdev(dev);
1061 return err;
1062 }
1063}
1064
739static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) 1065static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
740{ 1066{
741 struct ifinfomsg *ifm; 1067 struct ifinfomsg *ifm;
@@ -756,7 +1082,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
756 } else 1082 } else
757 return -EINVAL; 1083 return -EINVAL;
758 1084
759 nskb = nlmsg_new(if_nlmsg_size(), GFP_KERNEL); 1085 nskb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL);
760 if (nskb == NULL) { 1086 if (nskb == NULL) {
761 err = -ENOBUFS; 1087 err = -ENOBUFS;
762 goto errout; 1088 goto errout;
@@ -806,7 +1132,7 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
806 struct sk_buff *skb; 1132 struct sk_buff *skb;
807 int err = -ENOBUFS; 1133 int err = -ENOBUFS;
808 1134
809 skb = nlmsg_new(if_nlmsg_size(), GFP_KERNEL); 1135 skb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL);
810 if (skb == NULL) 1136 if (skb == NULL)
811 goto errout; 1137 goto errout;
812 1138
@@ -961,6 +1287,8 @@ void __init rtnetlink_init(void)
961 1287
962 rtnl_register(PF_UNSPEC, RTM_GETLINK, rtnl_getlink, rtnl_dump_ifinfo); 1288 rtnl_register(PF_UNSPEC, RTM_GETLINK, rtnl_getlink, rtnl_dump_ifinfo);
963 rtnl_register(PF_UNSPEC, RTM_SETLINK, rtnl_setlink, NULL); 1289 rtnl_register(PF_UNSPEC, RTM_SETLINK, rtnl_setlink, NULL);
1290 rtnl_register(PF_UNSPEC, RTM_NEWLINK, rtnl_newlink, NULL);
1291 rtnl_register(PF_UNSPEC, RTM_DELLINK, rtnl_dellink, NULL);
964 1292
965 rtnl_register(PF_UNSPEC, RTM_GETADDR, NULL, rtnl_dump_all); 1293 rtnl_register(PF_UNSPEC, RTM_GETADDR, NULL, rtnl_dump_all);
966 rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all); 1294 rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all);