]> git.ipfire.org Git - thirdparty/libnl.git/commitdiff
link: Support for IFLA_AF_SPEC
authorThomas Graf <tgraf@suug.ch>
Sat, 13 Nov 2010 00:38:13 +0000 (01:38 +0100)
committerThomas Graf <tgraf@suug.ch>
Sat, 13 Nov 2010 00:38:13 +0000 (01:38 +0100)
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.

include/linux/if_link.h
include/netlink/route/link/api.h
lib/route/link.c
lib/route/link/inet6.c

index 2fc66dd783eefd18119cbd29f5d5b7fe54a15ec4..292d1cd57cd0592eb04d649c0a2d1c10b167349b 100644 (file)
@@ -80,6 +80,24 @@ struct rtnl_link_ifmap {
        __u8    port;
 };
 
+/*
+ * IFLA_AF_SPEC
+ *   Contains nested attributes for address family specific attributes.
+ *   Each address family may create a attribute with the address family
+ *   number as type and create its own attribute structure in it.
+ *
+ *   Example:
+ *   [IFLA_AF_SPEC] = {
+ *       [AF_INET6] = {
+ *           [IFLA_INET6_FLAGS] = ...,
+ *           [IFLA_INET6_CONF] = ...,
+ *       },
+ *       [AF_BRIDGE] = {
+ *           [IFLA_BRIDGE_PORT] = ...
+ *       }
+ *   }
+ */
+
 enum {
        IFLA_UNSPEC,
        IFLA_ADDRESS,
@@ -116,6 +134,7 @@ enum {
        IFLA_STATS64,
        IFLA_VF_PORTS,
        IFLA_PORT_SELF,
+       IFLA_AF_SPEC,
        __IFLA_MAX
 };
 
index 8222e230942e27e71ae65e5b097e7f43e34f1d38..2280b4aad870f4bdfa53c76cc30c58550d10408d 100644 (file)
@@ -105,6 +105,11 @@ struct rtnl_link_af_ops
        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 *,
index 6e6460b59df70a23f13ae9e6ce2adb1273504cbd..60e1600a6b65aad4def3bb6acfbbace2a3c8c2c4 100644 (file)
@@ -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);
index e36840421540765e82a9268cc619b820e070f9b4..6e8e08c9411a58703890175bff328672a4f1b5cd 100644 (file)
@@ -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,