From 2e3ca4db0cbca7974888e7d3e7d84ba8fbbcf639 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Sat, 13 Nov 2010 01:38:13 +0100 Subject: [PATCH] link: Support for IFLA_AF_SPEC This feature isn't upstream yet. It's required to test a patch in my local tree. Makes the link parser understand IFLA_AF_SPEC and call the address family specific parser. --- include/linux/if_link.h | 19 ++++++++++++ include/netlink/route/link/api.h | 5 ++++ lib/route/link.c | 51 ++++++++++++++++++++++++++------ lib/route/link/inet6.c | 1 + 4 files changed, 67 insertions(+), 9 deletions(-) diff --git a/include/linux/if_link.h b/include/linux/if_link.h index 2fc66dd..292d1cd 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -80,6 +80,24 @@ struct rtnl_link_ifmap { __u8 port; }; +/* + * IFLA_AF_SPEC + * Contains nested attributes for address family specific attributes. + * Each address family may create a attribute with the address family + * number as type and create its own attribute structure in it. + * + * Example: + * [IFLA_AF_SPEC] = { + * [AF_INET6] = { + * [IFLA_INET6_FLAGS] = ..., + * [IFLA_INET6_CONF] = ..., + * }, + * [AF_BRIDGE] = { + * [IFLA_BRIDGE_PORT] = ... + * } + * } + */ + enum { IFLA_UNSPEC, IFLA_ADDRESS, @@ -116,6 +134,7 @@ enum { IFLA_STATS64, IFLA_VF_PORTS, IFLA_PORT_SELF, + IFLA_AF_SPEC, __IFLA_MAX }; diff --git a/include/netlink/route/link/api.h b/include/netlink/route/link/api.h index 8222e23..2280b4a 100644 --- a/include/netlink/route/link/api.h +++ b/include/netlink/route/link/api.h @@ -105,6 +105,11 @@ struct rtnl_link_af_ops int (*ao_parse_protinfo)(struct rtnl_link *, struct nlattr *, void *); + /** Called if a IFLA_AF_SPEC attribute needs to be parsed. Typically + * stores the parsed data in the address family specific buffer. */ + int (*ao_parse_af)(struct rtnl_link *, + struct nlattr *, void *); + /** Dump address family specific link attributes */ void (*ao_dump[NL_DUMP_MAX+1])(struct rtnl_link *, struct nl_dump_params *, diff --git a/lib/route/link.c b/lib/route/link.c index 6e6460b..60e1600 100644 --- a/lib/route/link.c +++ b/lib/route/link.c @@ -183,6 +183,26 @@ static struct nl_cache_ops rtnl_link_ops; static struct nl_object_ops link_obj_ops; /** @endcond */ +static struct rtnl_link_af_ops *af_lookup_and_alloc(struct rtnl_link *link, + int family) +{ + struct rtnl_link_af_ops *af_ops; + + af_ops = rtnl_link_af_ops_lookup(family); + if (!af_ops) + return NULL; + + if (!link->l_af_data[family] && af_ops->ao_alloc) { + link->l_af_data[family] = af_ops->ao_alloc(link); + if (!link->l_af_data[family]) { + rtnl_link_af_ops_put(af_ops); + return NULL; + } + } + + return af_ops; +} + static int af_free(struct rtnl_link *link, struct rtnl_link_af_ops *ops, void *data, void *arg) { @@ -339,6 +359,7 @@ static struct nla_policy link_policy[IFLA_MAX+1] = { [IFLA_MAP] = { .minlen = sizeof(struct rtnl_link_ifmap) }, [IFLA_IFALIAS] = { .type = NLA_STRING, .maxlen = IFALIASZ }, [IFLA_NUM_VF] = { .type = NLA_U32 }, + [IFLA_AF_SPEC] = { .type = NLA_NESTED }, }; static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = { @@ -377,15 +398,7 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX | LINK_ATTR_FLAGS | LINK_ATTR_CHANGE); - if ((af_ops = rtnl_link_af_ops_lookup(family))) { - if (af_ops->ao_alloc) { - link->l_af_data[family] = af_ops->ao_alloc(link); - if (!link->l_af_data[family]) { - err = -NLE_NOMEM; - goto errout; - } - } - + if ((af_ops = af_lookup_and_alloc(link, family))) { if (af_ops->ao_protinfo_policy) { memcpy(&link_policy[IFLA_PROTINFO], af_ops->ao_protinfo_policy, @@ -588,6 +601,26 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, goto errout; } + if (tb[IFLA_AF_SPEC]) { + struct nlattr *af_attr; + int remaining; + + nla_for_each_nested(af_attr, tb[IFLA_AF_SPEC], remaining) { + af_ops = af_lookup_and_alloc(link, nla_type(af_attr)); + if (af_ops && af_ops->ao_parse_af) { + char *af_data = link->l_af_data[nla_type(af_attr)]; + + err = af_ops->ao_parse_af(link, af_attr, af_data); + + rtnl_link_af_ops_put(af_ops); + + if (err < 0) + goto errout; + } + + } + } + err = pp->pp_cb((struct nl_object *) link, pp); errout: rtnl_link_af_ops_put(af_ops); diff --git a/lib/route/link/inet6.c b/lib/route/link/inet6.c index e368404..6e8e08c 100644 --- a/lib/route/link/inet6.c +++ b/lib/route/link/inet6.c @@ -311,6 +311,7 @@ static struct rtnl_link_af_ops inet6_ops = { .ao_clone = &inet6_clone, .ao_free = &inet6_free, .ao_parse_protinfo = &inet6_parse_protinfo, + .ao_parse_af = &inet6_parse_protinfo, .ao_dump[NL_DUMP_DETAILS] = &inet6_dump_details, .ao_dump[NL_DUMP_STATS] = &inet6_dump_stats, .ao_protinfo_policy = &protinfo_policy,