aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorThomas Graf <tgraf@infradead.org>2010-11-15 23:30:14 -0500
committerDavid S. Miller <davem@davemloft.net>2010-11-17 14:28:24 -0500
commitf8ff182c716c6f11ca3061961f5722f26a14e101 (patch)
tree6ea721a7feb71850c61b9d02400d162674d91c21 /net/core
parentd67ef35fff67845c64d806c033cc7c569ccebfff (diff)
rtnetlink: Link address family API
Each net_device contains address family specific data such as per device settings and statistics. We already expose this data via procfs/sysfs and partially netlink. The netlink method requires the requester to send one RTM_GETLINK request for each address family it wishes to receive data of and then merge this data itself. This patch implements a new API which combines all address family specific link data in a new netlink attribute IFLA_AF_SPEC. IFLA_AF_SPEC contains a sequence of nested attributes, one for each address family which in turn defines the structure of its own attribute. Example: [IFLA_AF_SPEC] = { [AF_INET] = { [IFLA_INET_CONF] = ..., }, [AF_INET6] = { [IFLA_INET6_FLAGS] = ..., [IFLA_INET6_CONF] = ..., } } The API also allows for address families to implement a function which parses the IFLA_AF_SPEC attribute sent by userspace to implement address family specific link options. Signed-off-by: Thomas Graf <tgraf@infradead.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r--net/core/rtnetlink.c147
1 files changed, 145 insertions, 2 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 841c287ef40a..bf69e5871b1a 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -362,6 +362,95 @@ static size_t rtnl_link_get_size(const struct net_device *dev)
362 return size; 362 return size;
363} 363}
364 364
365static LIST_HEAD(rtnl_af_ops);
366
367static 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 */
387int __rtnl_af_register(struct rtnl_af_ops *ops)
388{
389 list_add_tail(&ops->list, &rtnl_af_ops);
390 return 0;
391}
392EXPORT_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 */
400int 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}
409EXPORT_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 */
417void __rtnl_af_unregister(struct rtnl_af_ops *ops)
418{
419 list_del(&ops->list);
420}
421EXPORT_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 */
427void rtnl_af_unregister(struct rtnl_af_ops *ops)
428{
429 rtnl_lock();
430 __rtnl_af_unregister(ops);
431 rtnl_unlock();
432}
433EXPORT_SYMBOL_GPL(rtnl_af_unregister);
434
435static 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 }
450
451 return size;
452}
453
365static int rtnl_link_fill(struct sk_buff *skb, const struct net_device *dev) 454static int rtnl_link_fill(struct sk_buff *skb, const struct net_device *dev)
366{ 455{
367 const struct rtnl_link_ops *ops = dev->rtnl_link_ops; 456 const struct rtnl_link_ops *ops = dev->rtnl_link_ops;
@@ -671,7 +760,8 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev)
671 + nla_total_size(4) /* IFLA_NUM_VF */ 760 + nla_total_size(4) /* IFLA_NUM_VF */
672 + rtnl_vfinfo_size(dev) /* IFLA_VFINFO_LIST */ 761 + rtnl_vfinfo_size(dev) /* IFLA_VFINFO_LIST */
673 + rtnl_port_size(dev) /* IFLA_VF_PORTS + IFLA_PORT_SELF */ 762 + rtnl_port_size(dev) /* IFLA_VF_PORTS + IFLA_PORT_SELF */
674 + 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 */
675} 765}
676 766
677static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev) 767static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev)
@@ -757,7 +847,8 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
757 struct nlmsghdr *nlh; 847 struct nlmsghdr *nlh;
758 struct rtnl_link_stats64 temp; 848 struct rtnl_link_stats64 temp;
759 const struct rtnl_link_stats64 *stats; 849 const struct rtnl_link_stats64 *stats;
760 struct nlattr *attr; 850 struct nlattr *attr, *af_spec;
851 struct rtnl_af_ops *af_ops;
761 852
762 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags); 853 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
763 if (nlh == NULL) 854 if (nlh == NULL)
@@ -866,6 +957,36 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
866 goto nla_put_failure; 957 goto nla_put_failure;
867 } 958 }
868 959
960 if (!(af_spec = nla_nest_start(skb, IFLA_AF_SPEC)))
961 goto nla_put_failure;
962
963 list_for_each_entry(af_ops, &rtnl_af_ops, list) {
964 if (af_ops->fill_link_af) {
965 struct nlattr *af;
966 int err;
967
968 if (!(af = nla_nest_start(skb, af_ops->family)))
969 goto nla_put_failure;
970
971 err = af_ops->fill_link_af(skb, dev);
972
973 /*
974 * Caller may return ENODATA to indicate that there
975 * was no data to be dumped. This is not an error, it
976 * means we should trim the attribute header and
977 * continue.
978 */
979 if (err == -ENODATA)
980 nla_nest_cancel(skb, af);
981 else if (err < 0)
982 goto nla_put_failure;
983
984 nla_nest_end(skb, af);
985 }
986 }
987
988 nla_nest_end(skb, af_spec);
989
869 return nlmsg_end(skb, nlh); 990 return nlmsg_end(skb, nlh);
870 991
871nla_put_failure: 992nla_put_failure:
@@ -924,6 +1045,7 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {
924 [IFLA_VFINFO_LIST] = {. type = NLA_NESTED }, 1045 [IFLA_VFINFO_LIST] = {. type = NLA_NESTED },
925 [IFLA_VF_PORTS] = { .type = NLA_NESTED }, 1046 [IFLA_VF_PORTS] = { .type = NLA_NESTED },
926 [IFLA_PORT_SELF] = { .type = NLA_NESTED }, 1047 [IFLA_PORT_SELF] = { .type = NLA_NESTED },
1048 [IFLA_AF_SPEC] = { .type = NLA_NESTED },
927}; 1049};
928EXPORT_SYMBOL(ifla_policy); 1050EXPORT_SYMBOL(ifla_policy);
929 1051
@@ -1225,6 +1347,27 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
1225 goto errout; 1347 goto errout;
1226 modified = 1; 1348 modified = 1;
1227 } 1349 }
1350
1351 if (tb[IFLA_AF_SPEC]) {
1352 struct nlattr *af;
1353 int rem;
1354
1355 nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) {
1356 const struct rtnl_af_ops *af_ops;
1357
1358 if (!(af_ops = rtnl_af_lookup(nla_type(af))))
1359 continue;
1360
1361 if (!af_ops->parse_link_af)
1362 continue;
1363
1364 err = af_ops->parse_link_af(dev, af);
1365 if (err < 0)
1366 goto errout;
1367
1368 modified = 1;
1369 }
1370 }
1228 err = 0; 1371 err = 0;
1229 1372
1230errout: 1373errout: