summaryrefslogtreecommitdiffstats
path: root/lib/route/link.c
diff options
context:
space:
mode:
authorDavid Ahern <dsa@cumulusnetworks.com>2015-11-25 19:14:15 (GMT)
committerThomas Haller <thaller@redhat.com>2015-12-07 10:42:29 (GMT)
commitb3aeeadd782a1bd269cb7befd6092fb7a32cae6f (patch)
tree57f5d2383b48ae3ecd61f3a39a12a907d2594ff6 /lib/route/link.c
parent1b2c247571c748a422864f9122bd16cb20e37f83 (diff)
downloadlibnl-b3aeeadd782a1bd269cb7befd6092fb7a32cae6f.zip
libnl-b3aeeadd782a1bd269cb7befd6092fb7a32cae6f.tar.gz
libnl-b3aeeadd782a1bd269cb7befd6092fb7a32cae6f.tar.bz2
lib: handle family-based parsing of IFLA_AF_SPEC attribute
The encoding of the IFLA_AF_SPEC attribute varies depending on the family used for the request (RTM_GETLINK) message. For AF_UNSPEC the encoding has another level of nesting for each address family with the type encoded first. i.e., af_spec = nla_nest_start(skb, IFLA_AF_SPEC) for each family: af = nla_nest_start(skb, af_ops->family) af_ops->fill_link_af(skb, dev, ext_filter_mask) nest_end nest_end This allows the parser to find the address family by looking at the first type. Whereas AF_BRIDGE encoding is just: af_spec = nla_nest_start(skb, IFLA_AF_SPEC) br_fill_ifvlaninfo{_compressed}(skb, vg) nest_end which means the parser can not use the attribute itself to know the family to which the attribute belongs. Signed-off-by: David Ahern <dsa@cumulusnetworks.com> [thaller@redhat.com: refactor code by merging a later patch by tobias.jungel@bisdn.de and introduce new function ao_parse_af_full()] Signed-off-by: Thomas Haller <thaller@redhat.com>
Diffstat (limited to 'lib/route/link.c')
-rw-r--r--lib/route/link.c41
1 files changed, 28 insertions, 13 deletions
diff --git a/lib/route/link.c b/lib/route/link.c
index 768b899..d763d97 100644
--- a/lib/route/link.c
+++ b/lib/route/link.c
@@ -496,6 +496,7 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
struct ifinfomsg *ifi;
struct nlattr *tb[IFLA_MAX+1];
struct rtnl_link_af_ops *af_ops = NULL;
+ struct rtnl_link_af_ops *af_ops_family;
int err, family;
struct nla_policy real_link_policy[IFLA_MAX+1];
@@ -524,7 +525,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 = af_lookup_and_alloc(link, family))) {
+ if ((af_ops_family = af_ops = af_lookup_and_alloc(link, family))) {
if (af_ops->ao_protinfo_policy) {
memcpy(&real_link_policy[IFLA_PROTINFO],
af_ops->ao_protinfo_policy,
@@ -570,7 +571,7 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
if (af_ops->ao_protinfo_policy) {
tb[IFLA_PROTINFO] = (struct nlattr *)af_ops->ao_protinfo_policy;
}
- link->l_family = family = af;
+ link->l_family = af;
link->l_af_ops = af_ops;
}
@@ -601,21 +602,35 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
}
if (tb[IFLA_AF_SPEC]) {
- struct nlattr *af_attr;
- int remaining;
+ /* parsing of IFLA_AF_SPEC is dependent on the family used
+ * in the request message.
+ */
+ if (af_ops_family && af_ops_family->ao_parse_af_full) {
+ err = af_ops_family->ao_parse_af_full(link,
+ tb[IFLA_AF_SPEC],
+ link->l_af_data[af_ops_family->ao_family]);
+ if (err < 0)
+ goto errout;
+ link->ce_mask |= LINK_ATTR_AF_SPEC;
+ } else if (family == AF_UNSPEC) {
+ 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)];
+ 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);
- if (err < 0)
- goto errout;
+ err = af_ops->ao_parse_af(link, af_attr, af_data);
+ if (err < 0)
+ goto errout;
+ }
}
-
+ link->ce_mask |= LINK_ATTR_AF_SPEC;
+ } else {
+ NL_DBG(3, "IFLA_AF_SPEC parsing not implemented for family %d\n",
+ family);
}
- link->ce_mask |= LINK_ATTR_AF_SPEC;
}
if (tb[IFLA_PROMISCUITY]) {