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.
This commit is contained in:
Thomas Graf 2010-11-13 01:38:13 +01:00
parent a4efc65c3a
commit 2e3ca4db0c
4 changed files with 67 additions and 9 deletions

View File

@ -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
};

View File

@ -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 *,

View File

@ -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);

View File

@ -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,