diff options
author | David Ahern <dsa@cumulusnetworks.com> | 2015-11-25 19:14:15 (GMT) |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2015-12-07 10:42:29 (GMT) |
commit | b3aeeadd782a1bd269cb7befd6092fb7a32cae6f (patch) | |
tree | 57f5d2383b48ae3ecd61f3a39a12a907d2594ff6 | |
parent | 1b2c247571c748a422864f9122bd16cb20e37f83 (diff) | |
download | libnl-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>
-rw-r--r-- | include/netlink-private/route/link/api.h | 5 | ||||
-rw-r--r-- | lib/route/link.c | 41 |
2 files changed, 33 insertions, 13 deletions
diff --git a/include/netlink-private/route/link/api.h b/include/netlink-private/route/link/api.h index 2d56658..6e11062 100644 --- a/include/netlink-private/route/link/api.h +++ b/include/netlink-private/route/link/api.h @@ -119,6 +119,11 @@ struct rtnl_link_af_ops int (*ao_fill_af)(struct rtnl_link *, struct nl_msg *msg, void *); + /** Called if the full IFLA_AF_SPEC data needs to be parsed. Typically + * stores the parsed data in the address family specific buffer. */ + int (*ao_parse_af_full)(struct rtnl_link *, + struct nlattr *, void *); + /** Called for GETLINK message to the kernel. Used to append * link address family specific attributes to the request message. */ int (*ao_get_af)(struct nl_msg *msg); 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]) { |