[PATCH 2/3] Handle family-based parsing of IFLA_AF_SPEC attribute

Tobias Jungel tobias.jungel at bisdn.de
Wed Nov 25 07:47:25 PST 2015


Hi David,

cool work, still I have some comments inline.

/tobi


On Di, 2015-11-24 at 11:56 -0800, David Ahern wrote:
> 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 at cumulusnetworks.com>
> ---
>  lib/route/link.c | 81
> +++++++++++++++++++++++++++++++++++++++++++++++---------
>  1 file changed, 68 insertions(+), 13 deletions(-)
> 
> diff --git a/lib/route/link.c b/lib/route/link.c
> index 3cb62df95d6a..b8e333c31a3a 100644
> --- a/lib/route/link.c
> +++ b/lib/route/link.c
> @@ -489,6 +489,56 @@ int rtnl_link_info_parse(struct rtnl_link *link,
> struct nlattr **tb)
>  	return 0;
>  }
>  
> +static int parse_af_spec_unspec(struct rtnl_link *link, struct
> nlattr *attr)
> +{
> +	struct nlattr *af_attr;
> +	int remaining;
> +	int err = 0;
> +
> +	nla_for_each_nested(af_attr, attr, remaining) {
> +		struct rtnl_link_af_ops *af_ops;
> +
> +		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;
> +			}
> +		}
> +
> +	}
> +
> +	link->ce_mask |= LINK_ATTR_AF_SPEC;
> +errout:

since af_lookup_and_alloc is called, I guess a rtnl_link_af_ops_put is
missing here.

> +	return err;
> +}
> +
> +static int parse_af_spec_bridge(struct rtnl_link *link, struct
> nlattr *attr)
> +{
> +	struct rtnl_link_af_ops *af_ops;
> +	struct nlattr *af_attr;
> +	char *af_data;
> +	int remaining;
> +	int err = 0;
> +
> +	af_ops = af_lookup_and_alloc(link, AF_BRIDGE);
> +	af_data = link->l_af_data[AF_BRIDGE];
> +
> +	if (af_ops && af_ops->ao_parse_af) {
> +		nla_for_each_nested(af_attr, attr, remaining) {
> +			err = af_ops->ao_parse_af(link, af_attr,
> af_data);
> +			if (err < 0)
> +				goto errout;
> +		}
> +	}
> +
> +	link->ce_mask |= LINK_ATTR_AF_SPEC;
> +errout:

same as above

> +	return err;
> +}
> +
>  static int link_msg_parser(struct nl_cache_ops *ops, struct
> sockaddr_nl *who,
>  			   struct nlmsghdr *n, struct
> nl_parser_param *pp)
>  {
> @@ -601,21 +651,26 @@ 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;
> -
> -		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;
> -			}
> +		struct nl_cache *cache = (struct nl_cache *) pp-
> >pp_arg;
>  

I do not think this is valid all the time. For instance if you
call nl_msg_parse pp_arg is a struct dp_xdata. The same goes for using
the cache manager.

Is there a way to determine the origin, that you can make sure you can
use nl_cache? Otherwise I guess you have to stick with the family of
the nlmsg as I proposed in my patch.


> +		/* parsing of IFLA_AF_SPEC is dependent on the
> family used
> +		 * in the request message which is conveniently
> passed via
> +		 * the nl_parser_param arg.
> +		 */
> +		switch(cache->c_iarg1) {
> +		case AF_BRIDGE:
> +			err = parse_af_spec_bridge(link,
> tb[IFLA_AF_SPEC]);
> +			break;
> +		case AF_UNSPEC:
> +			err = parse_af_spec_unspec(link,
> tb[IFLA_AF_SPEC]);
> +			break;
> +		default:
> +			err = -EINVAL;
> +			NL_DBG(1, "IFLA_AF_SPEC parsing not
> implemented for family %d\n",
> +				family);
>  		}
> -		link->ce_mask |= LINK_ATTR_AF_SPEC;
> +		if (err)
> +			goto errout;
>  	}
>  
>  	if (tb[IFLA_PROMISCUITY]) {



More information about the libnl mailing list