summaryrefslogtreecommitdiff
path: root/lib/route
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2010-11-13 01:38:13 +0100
committerThomas Graf <tgraf@suug.ch>2010-11-13 01:38:13 +0100
commit2e3ca4db0cbca7974888e7d3e7d84ba8fbbcf639 (patch)
tree9eef79db9b7b3d6df3b933f464b552b3ab0c9c5d /lib/route
parenta4efc65c3a0fcf2a56336290e94ba58c212873db (diff)
downloadlibnl-2e3ca4db0cbca7974888e7d3e7d84ba8fbbcf639.tar.gz
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.
Diffstat (limited to 'lib/route')
-rw-r--r--lib/route/link.c51
-rw-r--r--lib/route/link/inet6.c1
2 files changed, 43 insertions, 9 deletions
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,