diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /net/core/rtnetlink.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'net/core/rtnetlink.c')
-rw-r--r-- | net/core/rtnetlink.c | 331 |
1 files changed, 269 insertions, 62 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index f78d821bd935..abd936d8a716 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -196,7 +196,7 @@ EXPORT_SYMBOL_GPL(__rtnl_register); | |||
196 | * as failure of this function is very unlikely, it can only happen due | 196 | * as failure of this function is very unlikely, it can only happen due |
197 | * to lack of memory when allocating the chain to store all message | 197 | * to lack of memory when allocating the chain to store all message |
198 | * handlers for a protocol. Meant for use in init functions where lack | 198 | * handlers for a protocol. Meant for use in init functions where lack |
199 | * of memory implies no sense in continueing. | 199 | * of memory implies no sense in continuing. |
200 | */ | 200 | */ |
201 | void rtnl_register(int protocol, int msgtype, | 201 | void rtnl_register(int protocol, int msgtype, |
202 | rtnl_doit_func doit, rtnl_dumpit_func dumpit) | 202 | rtnl_doit_func doit, rtnl_dumpit_func dumpit) |
@@ -299,14 +299,6 @@ static void __rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops) | |||
299 | unregister_netdevice_many(&list_kill); | 299 | unregister_netdevice_many(&list_kill); |
300 | } | 300 | } |
301 | 301 | ||
302 | void rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops) | ||
303 | { | ||
304 | rtnl_lock(); | ||
305 | __rtnl_kill_links(net, ops); | ||
306 | rtnl_unlock(); | ||
307 | } | ||
308 | EXPORT_SYMBOL_GPL(rtnl_kill_links); | ||
309 | |||
310 | /** | 302 | /** |
311 | * __rtnl_link_unregister - Unregister rtnl_link_ops from rtnetlink. | 303 | * __rtnl_link_unregister - Unregister rtnl_link_ops from rtnetlink. |
312 | * @ops: struct rtnl_link_ops * to unregister | 304 | * @ops: struct rtnl_link_ops * to unregister |
@@ -355,16 +347,106 @@ static size_t rtnl_link_get_size(const struct net_device *dev) | |||
355 | if (!ops) | 347 | if (!ops) |
356 | return 0; | 348 | return 0; |
357 | 349 | ||
358 | size = nlmsg_total_size(sizeof(struct nlattr)) + /* IFLA_LINKINFO */ | 350 | size = nla_total_size(sizeof(struct nlattr)) + /* IFLA_LINKINFO */ |
359 | nlmsg_total_size(strlen(ops->kind) + 1); /* IFLA_INFO_KIND */ | 351 | nla_total_size(strlen(ops->kind) + 1); /* IFLA_INFO_KIND */ |
360 | 352 | ||
361 | if (ops->get_size) | 353 | if (ops->get_size) |
362 | /* IFLA_INFO_DATA + nested data */ | 354 | /* IFLA_INFO_DATA + nested data */ |
363 | size += nlmsg_total_size(sizeof(struct nlattr)) + | 355 | size += nla_total_size(sizeof(struct nlattr)) + |
364 | ops->get_size(dev); | 356 | ops->get_size(dev); |
365 | 357 | ||
366 | if (ops->get_xstats_size) | 358 | if (ops->get_xstats_size) |
367 | size += ops->get_xstats_size(dev); /* IFLA_INFO_XSTATS */ | 359 | /* IFLA_INFO_XSTATS */ |
360 | size += nla_total_size(ops->get_xstats_size(dev)); | ||
361 | |||
362 | return size; | ||
363 | } | ||
364 | |||
365 | static LIST_HEAD(rtnl_af_ops); | ||
366 | |||
367 | static const struct rtnl_af_ops *rtnl_af_lookup(const int family) | ||
368 | { | ||
369 | const struct rtnl_af_ops *ops; | ||
370 | |||
371 | list_for_each_entry(ops, &rtnl_af_ops, list) { | ||
372 | if (ops->family == family) | ||
373 | return ops; | ||
374 | } | ||
375 | |||
376 | return NULL; | ||
377 | } | ||
378 | |||
379 | /** | ||
380 | * __rtnl_af_register - Register rtnl_af_ops with rtnetlink. | ||
381 | * @ops: struct rtnl_af_ops * to register | ||
382 | * | ||
383 | * The caller must hold the rtnl_mutex. | ||
384 | * | ||
385 | * Returns 0 on success or a negative error code. | ||
386 | */ | ||
387 | int __rtnl_af_register(struct rtnl_af_ops *ops) | ||
388 | { | ||
389 | list_add_tail(&ops->list, &rtnl_af_ops); | ||
390 | return 0; | ||
391 | } | ||
392 | EXPORT_SYMBOL_GPL(__rtnl_af_register); | ||
393 | |||
394 | /** | ||
395 | * rtnl_af_register - Register rtnl_af_ops with rtnetlink. | ||
396 | * @ops: struct rtnl_af_ops * to register | ||
397 | * | ||
398 | * Returns 0 on success or a negative error code. | ||
399 | */ | ||
400 | int rtnl_af_register(struct rtnl_af_ops *ops) | ||
401 | { | ||
402 | int err; | ||
403 | |||
404 | rtnl_lock(); | ||
405 | err = __rtnl_af_register(ops); | ||
406 | rtnl_unlock(); | ||
407 | return err; | ||
408 | } | ||
409 | EXPORT_SYMBOL_GPL(rtnl_af_register); | ||
410 | |||
411 | /** | ||
412 | * __rtnl_af_unregister - Unregister rtnl_af_ops from rtnetlink. | ||
413 | * @ops: struct rtnl_af_ops * to unregister | ||
414 | * | ||
415 | * The caller must hold the rtnl_mutex. | ||
416 | */ | ||
417 | void __rtnl_af_unregister(struct rtnl_af_ops *ops) | ||
418 | { | ||
419 | list_del(&ops->list); | ||
420 | } | ||
421 | EXPORT_SYMBOL_GPL(__rtnl_af_unregister); | ||
422 | |||
423 | /** | ||
424 | * rtnl_af_unregister - Unregister rtnl_af_ops from rtnetlink. | ||
425 | * @ops: struct rtnl_af_ops * to unregister | ||
426 | */ | ||
427 | void rtnl_af_unregister(struct rtnl_af_ops *ops) | ||
428 | { | ||
429 | rtnl_lock(); | ||
430 | __rtnl_af_unregister(ops); | ||
431 | rtnl_unlock(); | ||
432 | } | ||
433 | EXPORT_SYMBOL_GPL(rtnl_af_unregister); | ||
434 | |||
435 | static size_t rtnl_link_get_af_size(const struct net_device *dev) | ||
436 | { | ||
437 | struct rtnl_af_ops *af_ops; | ||
438 | size_t size; | ||
439 | |||
440 | /* IFLA_AF_SPEC */ | ||
441 | size = nla_total_size(sizeof(struct nlattr)); | ||
442 | |||
443 | list_for_each_entry(af_ops, &rtnl_af_ops, list) { | ||
444 | if (af_ops->get_link_af_size) { | ||
445 | /* AF_* + nested data */ | ||
446 | size += nla_total_size(sizeof(struct nlattr)) + | ||
447 | af_ops->get_link_af_size(dev); | ||
448 | } | ||
449 | } | ||
368 | 450 | ||
369 | return size; | 451 | return size; |
370 | } | 452 | } |
@@ -612,36 +694,7 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a, | |||
612 | 694 | ||
613 | static void copy_rtnl_link_stats64(void *v, const struct rtnl_link_stats64 *b) | 695 | static void copy_rtnl_link_stats64(void *v, const struct rtnl_link_stats64 *b) |
614 | { | 696 | { |
615 | struct rtnl_link_stats64 a; | 697 | memcpy(v, b, sizeof(*b)); |
616 | |||
617 | a.rx_packets = b->rx_packets; | ||
618 | a.tx_packets = b->tx_packets; | ||
619 | a.rx_bytes = b->rx_bytes; | ||
620 | a.tx_bytes = b->tx_bytes; | ||
621 | a.rx_errors = b->rx_errors; | ||
622 | a.tx_errors = b->tx_errors; | ||
623 | a.rx_dropped = b->rx_dropped; | ||
624 | a.tx_dropped = b->tx_dropped; | ||
625 | |||
626 | a.multicast = b->multicast; | ||
627 | a.collisions = b->collisions; | ||
628 | |||
629 | a.rx_length_errors = b->rx_length_errors; | ||
630 | a.rx_over_errors = b->rx_over_errors; | ||
631 | a.rx_crc_errors = b->rx_crc_errors; | ||
632 | a.rx_frame_errors = b->rx_frame_errors; | ||
633 | a.rx_fifo_errors = b->rx_fifo_errors; | ||
634 | a.rx_missed_errors = b->rx_missed_errors; | ||
635 | |||
636 | a.tx_aborted_errors = b->tx_aborted_errors; | ||
637 | a.tx_carrier_errors = b->tx_carrier_errors; | ||
638 | a.tx_fifo_errors = b->tx_fifo_errors; | ||
639 | a.tx_heartbeat_errors = b->tx_heartbeat_errors; | ||
640 | a.tx_window_errors = b->tx_window_errors; | ||
641 | |||
642 | a.rx_compressed = b->rx_compressed; | ||
643 | a.tx_compressed = b->tx_compressed; | ||
644 | memcpy(v, &a, sizeof(a)); | ||
645 | } | 698 | } |
646 | 699 | ||
647 | /* All VF info */ | 700 | /* All VF info */ |
@@ -707,7 +760,8 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev) | |||
707 | + nla_total_size(4) /* IFLA_NUM_VF */ | 760 | + nla_total_size(4) /* IFLA_NUM_VF */ |
708 | + rtnl_vfinfo_size(dev) /* IFLA_VFINFO_LIST */ | 761 | + rtnl_vfinfo_size(dev) /* IFLA_VFINFO_LIST */ |
709 | + rtnl_port_size(dev) /* IFLA_VF_PORTS + IFLA_PORT_SELF */ | 762 | + rtnl_port_size(dev) /* IFLA_VF_PORTS + IFLA_PORT_SELF */ |
710 | + rtnl_link_get_size(dev); /* IFLA_LINKINFO */ | 763 | + rtnl_link_get_size(dev) /* IFLA_LINKINFO */ |
764 | + rtnl_link_get_af_size(dev); /* IFLA_AF_SPEC */ | ||
711 | } | 765 | } |
712 | 766 | ||
713 | static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev) | 767 | static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev) |
@@ -793,8 +847,10 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
793 | struct nlmsghdr *nlh; | 847 | struct nlmsghdr *nlh; |
794 | struct rtnl_link_stats64 temp; | 848 | struct rtnl_link_stats64 temp; |
795 | const struct rtnl_link_stats64 *stats; | 849 | const struct rtnl_link_stats64 *stats; |
796 | struct nlattr *attr; | 850 | struct nlattr *attr, *af_spec; |
851 | struct rtnl_af_ops *af_ops; | ||
797 | 852 | ||
853 | ASSERT_RTNL(); | ||
798 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags); | 854 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags); |
799 | if (nlh == NULL) | 855 | if (nlh == NULL) |
800 | return -EMSGSIZE; | 856 | return -EMSGSIZE; |
@@ -813,6 +869,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
813 | netif_running(dev) ? dev->operstate : IF_OPER_DOWN); | 869 | netif_running(dev) ? dev->operstate : IF_OPER_DOWN); |
814 | NLA_PUT_U8(skb, IFLA_LINKMODE, dev->link_mode); | 870 | NLA_PUT_U8(skb, IFLA_LINKMODE, dev->link_mode); |
815 | NLA_PUT_U32(skb, IFLA_MTU, dev->mtu); | 871 | NLA_PUT_U32(skb, IFLA_MTU, dev->mtu); |
872 | NLA_PUT_U32(skb, IFLA_GROUP, dev->group); | ||
816 | 873 | ||
817 | if (dev->ifindex != dev->iflink) | 874 | if (dev->ifindex != dev->iflink) |
818 | NLA_PUT_U32(skb, IFLA_LINK, dev->iflink); | 875 | NLA_PUT_U32(skb, IFLA_LINK, dev->iflink); |
@@ -902,6 +959,36 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
902 | goto nla_put_failure; | 959 | goto nla_put_failure; |
903 | } | 960 | } |
904 | 961 | ||
962 | if (!(af_spec = nla_nest_start(skb, IFLA_AF_SPEC))) | ||
963 | goto nla_put_failure; | ||
964 | |||
965 | list_for_each_entry(af_ops, &rtnl_af_ops, list) { | ||
966 | if (af_ops->fill_link_af) { | ||
967 | struct nlattr *af; | ||
968 | int err; | ||
969 | |||
970 | if (!(af = nla_nest_start(skb, af_ops->family))) | ||
971 | goto nla_put_failure; | ||
972 | |||
973 | err = af_ops->fill_link_af(skb, dev); | ||
974 | |||
975 | /* | ||
976 | * Caller may return ENODATA to indicate that there | ||
977 | * was no data to be dumped. This is not an error, it | ||
978 | * means we should trim the attribute header and | ||
979 | * continue. | ||
980 | */ | ||
981 | if (err == -ENODATA) | ||
982 | nla_nest_cancel(skb, af); | ||
983 | else if (err < 0) | ||
984 | goto nla_put_failure; | ||
985 | |||
986 | nla_nest_end(skb, af); | ||
987 | } | ||
988 | } | ||
989 | |||
990 | nla_nest_end(skb, af_spec); | ||
991 | |||
905 | return nlmsg_end(skb, nlh); | 992 | return nlmsg_end(skb, nlh); |
906 | 993 | ||
907 | nla_put_failure: | 994 | nla_put_failure: |
@@ -921,10 +1008,11 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
921 | s_h = cb->args[0]; | 1008 | s_h = cb->args[0]; |
922 | s_idx = cb->args[1]; | 1009 | s_idx = cb->args[1]; |
923 | 1010 | ||
1011 | rcu_read_lock(); | ||
924 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { | 1012 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { |
925 | idx = 0; | 1013 | idx = 0; |
926 | head = &net->dev_index_head[h]; | 1014 | head = &net->dev_index_head[h]; |
927 | hlist_for_each_entry(dev, node, head, index_hlist) { | 1015 | hlist_for_each_entry_rcu(dev, node, head, index_hlist) { |
928 | if (idx < s_idx) | 1016 | if (idx < s_idx) |
929 | goto cont; | 1017 | goto cont; |
930 | if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK, | 1018 | if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK, |
@@ -937,6 +1025,7 @@ cont: | |||
937 | } | 1025 | } |
938 | } | 1026 | } |
939 | out: | 1027 | out: |
1028 | rcu_read_unlock(); | ||
940 | cb->args[1] = idx; | 1029 | cb->args[1] = idx; |
941 | cb->args[0] = h; | 1030 | cb->args[0] = h; |
942 | 1031 | ||
@@ -950,16 +1039,19 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = { | |||
950 | [IFLA_MAP] = { .len = sizeof(struct rtnl_link_ifmap) }, | 1039 | [IFLA_MAP] = { .len = sizeof(struct rtnl_link_ifmap) }, |
951 | [IFLA_MTU] = { .type = NLA_U32 }, | 1040 | [IFLA_MTU] = { .type = NLA_U32 }, |
952 | [IFLA_LINK] = { .type = NLA_U32 }, | 1041 | [IFLA_LINK] = { .type = NLA_U32 }, |
1042 | [IFLA_MASTER] = { .type = NLA_U32 }, | ||
953 | [IFLA_TXQLEN] = { .type = NLA_U32 }, | 1043 | [IFLA_TXQLEN] = { .type = NLA_U32 }, |
954 | [IFLA_WEIGHT] = { .type = NLA_U32 }, | 1044 | [IFLA_WEIGHT] = { .type = NLA_U32 }, |
955 | [IFLA_OPERSTATE] = { .type = NLA_U8 }, | 1045 | [IFLA_OPERSTATE] = { .type = NLA_U8 }, |
956 | [IFLA_LINKMODE] = { .type = NLA_U8 }, | 1046 | [IFLA_LINKMODE] = { .type = NLA_U8 }, |
957 | [IFLA_LINKINFO] = { .type = NLA_NESTED }, | 1047 | [IFLA_LINKINFO] = { .type = NLA_NESTED }, |
958 | [IFLA_NET_NS_PID] = { .type = NLA_U32 }, | 1048 | [IFLA_NET_NS_PID] = { .type = NLA_U32 }, |
1049 | [IFLA_NET_NS_FD] = { .type = NLA_U32 }, | ||
959 | [IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 }, | 1050 | [IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 }, |
960 | [IFLA_VFINFO_LIST] = {. type = NLA_NESTED }, | 1051 | [IFLA_VFINFO_LIST] = {. type = NLA_NESTED }, |
961 | [IFLA_VF_PORTS] = { .type = NLA_NESTED }, | 1052 | [IFLA_VF_PORTS] = { .type = NLA_NESTED }, |
962 | [IFLA_PORT_SELF] = { .type = NLA_NESTED }, | 1053 | [IFLA_PORT_SELF] = { .type = NLA_NESTED }, |
1054 | [IFLA_AF_SPEC] = { .type = NLA_NESTED }, | ||
963 | }; | 1055 | }; |
964 | EXPORT_SYMBOL(ifla_policy); | 1056 | EXPORT_SYMBOL(ifla_policy); |
965 | 1057 | ||
@@ -1003,6 +1095,8 @@ struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]) | |||
1003 | */ | 1095 | */ |
1004 | if (tb[IFLA_NET_NS_PID]) | 1096 | if (tb[IFLA_NET_NS_PID]) |
1005 | net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID])); | 1097 | net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID])); |
1098 | else if (tb[IFLA_NET_NS_FD]) | ||
1099 | net = get_net_ns_by_fd(nla_get_u32(tb[IFLA_NET_NS_FD])); | ||
1006 | else | 1100 | else |
1007 | net = get_net(src_net); | 1101 | net = get_net(src_net); |
1008 | return net; | 1102 | return net; |
@@ -1021,6 +1115,27 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[]) | |||
1021 | return -EINVAL; | 1115 | return -EINVAL; |
1022 | } | 1116 | } |
1023 | 1117 | ||
1118 | if (tb[IFLA_AF_SPEC]) { | ||
1119 | struct nlattr *af; | ||
1120 | int rem, err; | ||
1121 | |||
1122 | nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) { | ||
1123 | const struct rtnl_af_ops *af_ops; | ||
1124 | |||
1125 | if (!(af_ops = rtnl_af_lookup(nla_type(af)))) | ||
1126 | return -EAFNOSUPPORT; | ||
1127 | |||
1128 | if (!af_ops->set_link_af) | ||
1129 | return -EOPNOTSUPP; | ||
1130 | |||
1131 | if (af_ops->validate_link_af) { | ||
1132 | err = af_ops->validate_link_af(dev, af); | ||
1133 | if (err < 0) | ||
1134 | return err; | ||
1135 | } | ||
1136 | } | ||
1137 | } | ||
1138 | |||
1024 | return 0; | 1139 | return 0; |
1025 | } | 1140 | } |
1026 | 1141 | ||
@@ -1070,6 +1185,41 @@ static int do_setvfinfo(struct net_device *dev, struct nlattr *attr) | |||
1070 | return err; | 1185 | return err; |
1071 | } | 1186 | } |
1072 | 1187 | ||
1188 | static int do_set_master(struct net_device *dev, int ifindex) | ||
1189 | { | ||
1190 | struct net_device *master_dev; | ||
1191 | const struct net_device_ops *ops; | ||
1192 | int err; | ||
1193 | |||
1194 | if (dev->master) { | ||
1195 | if (dev->master->ifindex == ifindex) | ||
1196 | return 0; | ||
1197 | ops = dev->master->netdev_ops; | ||
1198 | if (ops->ndo_del_slave) { | ||
1199 | err = ops->ndo_del_slave(dev->master, dev); | ||
1200 | if (err) | ||
1201 | return err; | ||
1202 | } else { | ||
1203 | return -EOPNOTSUPP; | ||
1204 | } | ||
1205 | } | ||
1206 | |||
1207 | if (ifindex) { | ||
1208 | master_dev = __dev_get_by_index(dev_net(dev), ifindex); | ||
1209 | if (!master_dev) | ||
1210 | return -EINVAL; | ||
1211 | ops = master_dev->netdev_ops; | ||
1212 | if (ops->ndo_add_slave) { | ||
1213 | err = ops->ndo_add_slave(master_dev, dev); | ||
1214 | if (err) | ||
1215 | return err; | ||
1216 | } else { | ||
1217 | return -EOPNOTSUPP; | ||
1218 | } | ||
1219 | } | ||
1220 | return 0; | ||
1221 | } | ||
1222 | |||
1073 | static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | 1223 | static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, |
1074 | struct nlattr **tb, char *ifname, int modified) | 1224 | struct nlattr **tb, char *ifname, int modified) |
1075 | { | 1225 | { |
@@ -1077,7 +1227,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
1077 | int send_addr_notify = 0; | 1227 | int send_addr_notify = 0; |
1078 | int err; | 1228 | int err; |
1079 | 1229 | ||
1080 | if (tb[IFLA_NET_NS_PID]) { | 1230 | if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD]) { |
1081 | struct net *net = rtnl_link_get_net(dev_net(dev), tb); | 1231 | struct net *net = rtnl_link_get_net(dev_net(dev), tb); |
1082 | if (IS_ERR(net)) { | 1232 | if (IS_ERR(net)) { |
1083 | err = PTR_ERR(net); | 1233 | err = PTR_ERR(net); |
@@ -1157,6 +1307,11 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
1157 | modified = 1; | 1307 | modified = 1; |
1158 | } | 1308 | } |
1159 | 1309 | ||
1310 | if (tb[IFLA_GROUP]) { | ||
1311 | dev_set_group(dev, nla_get_u32(tb[IFLA_GROUP])); | ||
1312 | modified = 1; | ||
1313 | } | ||
1314 | |||
1160 | /* | 1315 | /* |
1161 | * Interface selected by interface index but interface | 1316 | * Interface selected by interface index but interface |
1162 | * name provided implies that a name change has been | 1317 | * name provided implies that a name change has been |
@@ -1188,6 +1343,13 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
1188 | goto errout; | 1343 | goto errout; |
1189 | } | 1344 | } |
1190 | 1345 | ||
1346 | if (tb[IFLA_MASTER]) { | ||
1347 | err = do_set_master(dev, nla_get_u32(tb[IFLA_MASTER])); | ||
1348 | if (err) | ||
1349 | goto errout; | ||
1350 | modified = 1; | ||
1351 | } | ||
1352 | |||
1191 | if (tb[IFLA_TXQLEN]) | 1353 | if (tb[IFLA_TXQLEN]) |
1192 | dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); | 1354 | dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); |
1193 | 1355 | ||
@@ -1261,12 +1423,30 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
1261 | goto errout; | 1423 | goto errout; |
1262 | modified = 1; | 1424 | modified = 1; |
1263 | } | 1425 | } |
1426 | |||
1427 | if (tb[IFLA_AF_SPEC]) { | ||
1428 | struct nlattr *af; | ||
1429 | int rem; | ||
1430 | |||
1431 | nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) { | ||
1432 | const struct rtnl_af_ops *af_ops; | ||
1433 | |||
1434 | if (!(af_ops = rtnl_af_lookup(nla_type(af)))) | ||
1435 | BUG(); | ||
1436 | |||
1437 | err = af_ops->set_link_af(dev, af); | ||
1438 | if (err < 0) | ||
1439 | goto errout; | ||
1440 | |||
1441 | modified = 1; | ||
1442 | } | ||
1443 | } | ||
1264 | err = 0; | 1444 | err = 0; |
1265 | 1445 | ||
1266 | errout: | 1446 | errout: |
1267 | if (err < 0 && modified && net_ratelimit()) | 1447 | if (err < 0 && modified && net_ratelimit()) |
1268 | printk(KERN_WARNING "A link change request failed with " | 1448 | printk(KERN_WARNING "A link change request failed with " |
1269 | "some changes comitted already. Interface %s may " | 1449 | "some changes committed already. Interface %s may " |
1270 | "have been left with an inconsistent configuration, " | 1450 | "have been left with an inconsistent configuration, " |
1271 | "please check.\n", dev->name); | 1451 | "please check.\n", dev->name); |
1272 | 1452 | ||
@@ -1325,6 +1505,7 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
1325 | char ifname[IFNAMSIZ]; | 1505 | char ifname[IFNAMSIZ]; |
1326 | struct nlattr *tb[IFLA_MAX+1]; | 1506 | struct nlattr *tb[IFLA_MAX+1]; |
1327 | int err; | 1507 | int err; |
1508 | LIST_HEAD(list_kill); | ||
1328 | 1509 | ||
1329 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); | 1510 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); |
1330 | if (err < 0) | 1511 | if (err < 0) |
@@ -1348,7 +1529,9 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
1348 | if (!ops) | 1529 | if (!ops) |
1349 | return -EOPNOTSUPP; | 1530 | return -EOPNOTSUPP; |
1350 | 1531 | ||
1351 | ops->dellink(dev, NULL); | 1532 | ops->dellink(dev, &list_kill); |
1533 | unregister_netdevice_many(&list_kill); | ||
1534 | list_del(&list_kill); | ||
1352 | return 0; | 1535 | return 0; |
1353 | } | 1536 | } |
1354 | 1537 | ||
@@ -1396,12 +1579,6 @@ struct net_device *rtnl_create_link(struct net *src_net, struct net *net, | |||
1396 | dev->rtnl_link_state = RTNL_LINK_INITIALIZING; | 1579 | dev->rtnl_link_state = RTNL_LINK_INITIALIZING; |
1397 | dev->real_num_tx_queues = real_num_queues; | 1580 | dev->real_num_tx_queues = real_num_queues; |
1398 | 1581 | ||
1399 | if (strchr(dev->name, '%')) { | ||
1400 | err = dev_alloc_name(dev, dev->name); | ||
1401 | if (err < 0) | ||
1402 | goto err_free; | ||
1403 | } | ||
1404 | |||
1405 | if (tb[IFLA_MTU]) | 1582 | if (tb[IFLA_MTU]) |
1406 | dev->mtu = nla_get_u32(tb[IFLA_MTU]); | 1583 | dev->mtu = nla_get_u32(tb[IFLA_MTU]); |
1407 | if (tb[IFLA_ADDRESS]) | 1584 | if (tb[IFLA_ADDRESS]) |
@@ -1416,16 +1593,34 @@ struct net_device *rtnl_create_link(struct net *src_net, struct net *net, | |||
1416 | set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); | 1593 | set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); |
1417 | if (tb[IFLA_LINKMODE]) | 1594 | if (tb[IFLA_LINKMODE]) |
1418 | dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]); | 1595 | dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]); |
1596 | if (tb[IFLA_GROUP]) | ||
1597 | dev_set_group(dev, nla_get_u32(tb[IFLA_GROUP])); | ||
1419 | 1598 | ||
1420 | return dev; | 1599 | return dev; |
1421 | 1600 | ||
1422 | err_free: | ||
1423 | free_netdev(dev); | ||
1424 | err: | 1601 | err: |
1425 | return ERR_PTR(err); | 1602 | return ERR_PTR(err); |
1426 | } | 1603 | } |
1427 | EXPORT_SYMBOL(rtnl_create_link); | 1604 | EXPORT_SYMBOL(rtnl_create_link); |
1428 | 1605 | ||
1606 | static int rtnl_group_changelink(struct net *net, int group, | ||
1607 | struct ifinfomsg *ifm, | ||
1608 | struct nlattr **tb) | ||
1609 | { | ||
1610 | struct net_device *dev; | ||
1611 | int err; | ||
1612 | |||
1613 | for_each_netdev(net, dev) { | ||
1614 | if (dev->group == group) { | ||
1615 | err = do_setlink(dev, ifm, tb, NULL, 0); | ||
1616 | if (err < 0) | ||
1617 | return err; | ||
1618 | } | ||
1619 | } | ||
1620 | |||
1621 | return 0; | ||
1622 | } | ||
1623 | |||
1429 | static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 1624 | static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
1430 | { | 1625 | { |
1431 | struct net *net = sock_net(skb->sk); | 1626 | struct net *net = sock_net(skb->sk); |
@@ -1453,10 +1648,12 @@ replay: | |||
1453 | ifm = nlmsg_data(nlh); | 1648 | ifm = nlmsg_data(nlh); |
1454 | if (ifm->ifi_index > 0) | 1649 | if (ifm->ifi_index > 0) |
1455 | dev = __dev_get_by_index(net, ifm->ifi_index); | 1650 | dev = __dev_get_by_index(net, ifm->ifi_index); |
1456 | else if (ifname[0]) | 1651 | else { |
1457 | dev = __dev_get_by_name(net, ifname); | 1652 | if (ifname[0]) |
1458 | else | 1653 | dev = __dev_get_by_name(net, ifname); |
1459 | dev = NULL; | 1654 | else |
1655 | dev = NULL; | ||
1656 | } | ||
1460 | 1657 | ||
1461 | err = validate_linkmsg(dev, tb); | 1658 | err = validate_linkmsg(dev, tb); |
1462 | if (err < 0) | 1659 | if (err < 0) |
@@ -1520,8 +1717,13 @@ replay: | |||
1520 | return do_setlink(dev, ifm, tb, ifname, modified); | 1717 | return do_setlink(dev, ifm, tb, ifname, modified); |
1521 | } | 1718 | } |
1522 | 1719 | ||
1523 | if (!(nlh->nlmsg_flags & NLM_F_CREATE)) | 1720 | if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { |
1721 | if (ifm->ifi_index == 0 && tb[IFLA_GROUP]) | ||
1722 | return rtnl_group_changelink(net, | ||
1723 | nla_get_u32(tb[IFLA_GROUP]), | ||
1724 | ifm, tb); | ||
1524 | return -ENODEV; | 1725 | return -ENODEV; |
1726 | } | ||
1525 | 1727 | ||
1526 | if (ifm->ifi_index) | 1728 | if (ifm->ifi_index) |
1527 | return -EOPNOTSUPP; | 1729 | return -EOPNOTSUPP; |
@@ -1546,6 +1748,9 @@ replay: | |||
1546 | snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); | 1748 | snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); |
1547 | 1749 | ||
1548 | dest_net = rtnl_link_get_net(net, tb); | 1750 | dest_net = rtnl_link_get_net(net, tb); |
1751 | if (IS_ERR(dest_net)) | ||
1752 | return PTR_ERR(dest_net); | ||
1753 | |||
1549 | dev = rtnl_create_link(net, dest_net, ifname, ops, tb); | 1754 | dev = rtnl_create_link(net, dest_net, ifname, ops, tb); |
1550 | 1755 | ||
1551 | if (IS_ERR(dev)) | 1756 | if (IS_ERR(dev)) |
@@ -1759,6 +1964,8 @@ static int rtnetlink_event(struct notifier_block *this, unsigned long event, voi | |||
1759 | case NETDEV_GOING_DOWN: | 1964 | case NETDEV_GOING_DOWN: |
1760 | case NETDEV_UNREGISTER: | 1965 | case NETDEV_UNREGISTER: |
1761 | case NETDEV_UNREGISTER_BATCH: | 1966 | case NETDEV_UNREGISTER_BATCH: |
1967 | case NETDEV_RELEASE: | ||
1968 | case NETDEV_JOIN: | ||
1762 | break; | 1969 | break; |
1763 | default: | 1970 | default: |
1764 | rtmsg_ifinfo(RTM_NEWLINK, dev, 0); | 1971 | rtmsg_ifinfo(RTM_NEWLINK, dev, 0); |