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 *,
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)
{
[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] = {
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,
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);
.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,