From 3fa6a6b4104729e8e6bc07be61e04ee25b8d3611 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 11 Nov 2010 15:50:49 +0100 Subject: link: API for address family specific link data Introduces a new API to handle address familiy specific link data such as IFLA_PROTINFO. It provides entry hooks for parsing IFLA_PROTINFO attributes and allows to include the parsed data when a link object is dumped. --- include/netlink-types.h | 48 ++++++------- include/netlink/route/link/api.h | 115 ++++++++++++++++++++++++++++++ include/netlink/route/link/info-api.h | 59 ++------------- lib/route/link.c | 130 +++++++++++++++++++++++++++++++--- lib/route/link/api.c | 94 +++++++++++++++++++++++- lib/route/link/vlan.c | 4 +- 6 files changed, 358 insertions(+), 92 deletions(-) create mode 100644 include/netlink/route/link/api.h diff --git a/include/netlink-types.h b/include/netlink-types.h index 5b0ec5f..24911b9 100644 --- a/include/netlink-types.h +++ b/include/netlink-types.h @@ -150,31 +150,31 @@ struct rtnl_link { NLHDR_COMMON - char l_name[IFNAMSIZ]; - - uint32_t l_family; - uint32_t l_arptype; - uint32_t l_index; - uint32_t l_flags; - uint32_t l_change; - uint32_t l_mtu; - uint32_t l_link; - uint32_t l_txqlen; - uint32_t l_weight; - uint32_t l_master; - struct nl_addr *l_addr; - struct nl_addr *l_bcast; - char l_qdisc[IFQDISCSIZ]; - struct rtnl_link_map l_map; - uint64_t l_stats[RTNL_LINK_STATS_MAX+1]; - uint32_t l_flag_mask; - uint32_t l_num_vf; - uint8_t l_operstate; - uint8_t l_linkmode; + char l_name[IFNAMSIZ]; + uint32_t l_family; + uint32_t l_arptype; + uint32_t l_index; + uint32_t l_flags; + uint32_t l_change; + uint32_t l_mtu; + uint32_t l_link; + uint32_t l_txqlen; + uint32_t l_weight; + uint32_t l_master; + struct nl_addr * l_addr; + struct nl_addr * l_bcast; + char l_qdisc[IFQDISCSIZ]; + struct rtnl_link_map l_map; + uint64_t l_stats[RTNL_LINK_STATS_MAX+1]; + uint32_t l_flag_mask; + uint32_t l_num_vf; + uint8_t l_operstate; + uint8_t l_linkmode; /* 2 byte hole */ - struct rtnl_link_info_ops *l_info_ops; - void * l_info; - char * l_ifalias; + struct rtnl_link_info_ops * l_info_ops; + void * l_af_data[AF_MAX]; + void * l_info; + char * l_ifalias; }; struct rtnl_ncacheinfo diff --git a/include/netlink/route/link/api.h b/include/netlink/route/link/api.h new file mode 100644 index 0000000..ae5af59 --- /dev/null +++ b/include/netlink/route/link/api.h @@ -0,0 +1,115 @@ +/* + * netlink/route/link/api.h Link Modules API + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2010 Thomas Graf + */ + +#ifndef NETLINK_LINK_API_H_ +#define NETLINK_LINK_API_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @ingroup link_info + * + * Link info operations + */ +struct rtnl_link_info_ops +{ + /** Name of operations, must match name on kernel side */ + char * io_name; + + /** Reference count (internal, do not use) */ + int io_refcnt; + + /** Called to assign an info type to a link. + * Has to allocate enough resources to hold attributes. Can + * use link->l_info to store a pointer. */ + int (*io_alloc)(struct rtnl_link *); + + /** Called to parse the link info attribute. + * Must parse the attribute and assign all values to the link. + */ + int (*io_parse)(struct rtnl_link *, + struct nlattr *, + struct nlattr *); + + /** Called when the link object is dumped. + * Must dump the info type specific attributes. */ + void (*io_dump[NL_DUMP_MAX+1])(struct rtnl_link *, + struct nl_dump_params *); + + /** Called when a link object is cloned. + * Must clone all info type specific attributes. */ + int (*io_clone)(struct rtnl_link *, struct rtnl_link *); + + /** Called when construction a link netlink message. + * Must append all info type specific attributes to the message. */ + int (*io_put_attrs)(struct nl_msg *, struct rtnl_link *); + + /** Called to release all resources previously allocated + * in either io_alloc() or io_parse(). */ + void (*io_free)(struct rtnl_link *); + + struct rtnl_link_info_ops * io_next; +}; + +extern struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *); + +extern int rtnl_link_register_info(struct rtnl_link_info_ops *); +extern int rtnl_link_unregister_info(struct rtnl_link_info_ops *); + + +struct rtnl_link_af_ops +{ + /** The address family this operations set implements */ + const unsigned int ao_family; + + /** Number of users of this operations, DO NOT MODIFY. */ + int ao_refcnt; + + /** Validation policy for IFLA_PROTINFO attribute. This pointer + * can be set to a nla_policy structure describing the minimal + * requirements the attribute must meet. Failure of meeting these + * requirements will result in a parsing error. */ + const struct nla_policy *ao_protinfo_policy; + + /** Called after address family has been assigned to link. Must + * allocate data buffer to hold address family specific data and + * store it in link->l_af_data. */ + void * (*ao_alloc)(struct rtnl_link *); + + /** Called when the link is cloned, must allocate a clone of the + * address family specific buffer and return it. */ + void * (*ao_clone)(struct rtnl_link *, void *); + + /** Called when the link gets freed. Must free all allocated data */ + void (*ao_free)(struct rtnl_link *, void *); + + /** Called if a IFLA_PROTINFO attribute needs to be parsed. Typically + * stores the parsed data in the address family specific buffer. */ + int (*ao_parse_protinfo)(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 *, + void *); +}; + +extern struct rtnl_link_af_ops *rtnl_link_af_ops_lookup(unsigned int); +extern void rtnl_link_af_ops_put(struct rtnl_link_af_ops *); +extern int rtnl_link_af_register(struct rtnl_link_af_ops *); +extern int rtnl_link_af_unregister(struct rtnl_link_af_ops *); + + +#endif diff --git a/include/netlink/route/link/info-api.h b/include/netlink/route/link/info-api.h index 7e18e31..4750e18 100644 --- a/include/netlink/route/link/info-api.h +++ b/include/netlink/route/link/info-api.h @@ -6,66 +6,15 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2008 Thomas Graf + * Copyright (c) 2003-2010 Thomas Graf */ #ifndef NETLINK_LINK_INFO_API_H_ #define NETLINK_LINK_INFO_API_H_ -#include +#warning " is obsolete and may be removed in the future." +#warning "include instead. -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @ingroup link_info - * - * Link info operations - */ -struct rtnl_link_info_ops -{ - /** Name of operations, must match name on kernel side */ - char * io_name; - - /** Reference count (internal, do not use) */ - int io_refcnt; - - /** Called to assign an info type to a link. - * Has to allocate enough resources to hold attributes. Can - * use link->l_info to store a pointer. */ - int (*io_alloc)(struct rtnl_link *); - - /** Called to parse the link info attribute. - * Must parse the attribute and assign all values to the link. - */ - int (*io_parse)(struct rtnl_link *, - struct nlattr *, - struct nlattr *); - - /** Called when the link object is dumped. - * Must dump the info type specific attributes. */ - void (*io_dump[NL_DUMP_MAX+1])(struct rtnl_link *, - struct nl_dump_params *); - - /** Called when a link object is cloned. - * Must clone all info type specific attributes. */ - int (*io_clone)(struct rtnl_link *, struct rtnl_link *); - - /** Called when construction a link netlink message. - * Must append all info type specific attributes to the message. */ - int (*io_put_attrs)(struct nl_msg *, struct rtnl_link *); - - /** Called to release all resources previously allocated - * in either io_alloc() or io_parse(). */ - void (*io_free)(struct rtnl_link *); - - struct rtnl_link_info_ops * io_next; -}; - -extern struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *); - -extern int rtnl_link_register_info(struct rtnl_link_info_ops *); -extern int rtnl_link_unregister_info(struct rtnl_link_info_ops *); +#include #endif diff --git a/lib/route/link.c b/lib/route/link.c index 6aa3c77..2082d6e 100644 --- a/lib/route/link.c +++ b/lib/route/link.c @@ -154,7 +154,7 @@ #include #include #include -#include +#include /** @cond SKIP */ #define LINK_ATTR_MTU 0x0001 @@ -183,6 +183,84 @@ static struct nl_cache_ops rtnl_link_ops; static struct nl_object_ops link_obj_ops; /** @endcond */ +static int af_free(struct rtnl_link *link, struct rtnl_link_af_ops *ops, + void *data, void *arg) +{ + if (ops->ao_free) + ops->ao_free(link, data); + + rtnl_link_af_ops_put(ops); + + return 0; +} + +static int af_clone(struct rtnl_link *link, struct rtnl_link_af_ops *ops, + void *data, void *arg) +{ + struct rtnl_link *dst = arg; + + if (ops->ao_clone && + !(dst->l_af_data[ops->ao_family] = ops->ao_clone(link, data))) + return -NLE_NOMEM; + + return 0; +} + +static int af_dump_line(struct rtnl_link *link, struct rtnl_link_af_ops *ops, + void *data, void *arg) +{ + struct nl_dump_params *p = arg; + + if (ops->ao_dump[NL_DUMP_LINE]) + ops->ao_dump[NL_DUMP_LINE](link, p, data); + + return 0; +} + +static int af_dump_details(struct rtnl_link *link, struct rtnl_link_af_ops *ops, + void *data, void *arg) +{ + struct nl_dump_params *p = arg; + + if (ops->ao_dump[NL_DUMP_DETAILS]) + ops->ao_dump[NL_DUMP_DETAILS](link, p, data); + + return 0; +} + +static int af_dump_stats(struct rtnl_link *link, struct rtnl_link_af_ops *ops, + void *data, void *arg) +{ + struct nl_dump_params *p = arg; + + if (ops->ao_dump[NL_DUMP_STATS]) + ops->ao_dump[NL_DUMP_STATS](link, p, data); + + return 0; +} + +static int do_foreach_af(struct rtnl_link *link, + int (*cb)(struct rtnl_link *, + struct rtnl_link_af_ops *, void *, void *), + void *arg) +{ + int i, err; + + for (i = 0; i < AF_MAX; i++) { + if (link->l_af_data[i]) { + struct rtnl_link_af_ops *ops; + + if (!(ops = rtnl_link_af_ops_lookup(i))) + BUG(); + + if ((err = cb(link, ops, link->l_af_data[i], arg)) < 0) + return err; + } + } + + return 0; +} + static void release_link_info(struct rtnl_link *link) { struct rtnl_link_info_ops *io = link->l_info_ops; @@ -208,6 +286,8 @@ static void link_free_data(struct nl_object *c) nl_addr_put(link->l_bcast); free(link->l_ifalias); + + do_foreach_af(link, af_free, NULL); } } @@ -235,6 +315,9 @@ static int link_clone(struct nl_object *_dst, struct nl_object *_src) return err; } + if ((err = do_foreach_af(src, af_clone, dst)) < 0) + return err; + return 0; } @@ -270,6 +353,7 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, struct rtnl_link *link; struct ifinfomsg *ifi; struct nlattr *tb[IFLA_MAX+1]; + struct rtnl_link_af_ops *af_ops = NULL; int err; link = rtnl_link_alloc(); @@ -280,6 +364,27 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, link->ce_msgtype = n->nlmsg_type; + if (!nlmsg_valid_hdr(n, sizeof(*ifi))) + return -NLE_MSG_TOOSHORT; + + ifi = nlmsg_data(n); + link->l_family = ifi->ifi_family; + link->l_arptype = ifi->ifi_type; + link->l_index = ifi->ifi_index; + link->l_flags = ifi->ifi_flags; + link->l_change = ifi->ifi_change; + link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY | + LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX | + LINK_ATTR_FLAGS | LINK_ATTR_CHANGE); + + if ((af_ops = rtnl_link_af_ops_lookup(ifi->ifi_family))) { + if (af_ops->ao_protinfo_policy) { + memcpy(&link_policy[IFLA_PROTINFO], + af_ops->ao_protinfo_policy, + sizeof(struct nla_policy)); + } + } + err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, link_policy); if (err < 0) goto errout; @@ -291,15 +396,6 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ); - ifi = nlmsg_data(n); - link->l_family = ifi->ifi_family; - link->l_arptype = ifi->ifi_type; - link->l_index = ifi->ifi_index; - link->l_flags = ifi->ifi_flags; - link->l_change = ifi->ifi_change; - link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY | - LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX | - LINK_ATTR_FLAGS | LINK_ATTR_CHANGE); if (tb[IFLA_STATS]) { struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]); @@ -478,8 +574,16 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, } } + if (tb[IFLA_PROTINFO] && af_ops && af_ops->ao_parse_protinfo) { + err = af_ops->ao_parse_protinfo(link, tb[IFLA_PROTINFO], + link->l_af_data[link->l_family]); + if (err < 0) + goto errout; + } + err = pp->pp_cb((struct nl_object *) link, pp); errout: + rtnl_link_af_ops_put(af_ops); rtnl_link_put(link); return err; } @@ -522,6 +626,8 @@ static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p) if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_LINE]) link->l_info_ops->io_dump[NL_DUMP_LINE](link, p); + do_foreach_af(link, af_dump_line, p); + nl_dump(p, "\n"); } @@ -570,6 +676,8 @@ static void link_dump_details(struct nl_object *obj, struct nl_dump_params *p) if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_DETAILS]) link->l_info_ops->io_dump[NL_DUMP_DETAILS](link, p); + + do_foreach_af(link, af_dump_details, p); } static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p) @@ -633,6 +741,8 @@ static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p) if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS]) link->l_info_ops->io_dump[NL_DUMP_STATS](link, p); + + do_foreach_af(link, af_dump_stats, p); } #if 0 diff --git a/lib/route/link/api.c b/lib/route/link/api.c index a0e7679..2a8dd1d 100644 --- a/lib/route/link/api.c +++ b/lib/route/link/api.c @@ -43,7 +43,7 @@ #include #include #include -#include +#include static struct rtnl_link_info_ops *info_ops; @@ -94,5 +94,97 @@ int rtnl_link_unregister_info(struct rtnl_link_info_ops *ops) return 0; } +static struct rtnl_link_af_ops *af_ops[AF_MAX]; + +/** + * Return operations of a specific link address family + * @arg family Address family + * + * @note The returned pointer must be given back using rtnl_link_af_ops_put() + * + * @return Pointer to operations or NULL if unavailable. + */ +struct rtnl_link_af_ops *rtnl_link_af_ops_lookup(const unsigned int family) +{ + if (family == AF_UNSPEC || family >= AF_MAX) + return NULL; + + if (af_ops[family]) + af_ops[family]->ao_refcnt++; + + return af_ops[family]; +} + +/** + * Give back reference to a set of operations. + * @arg ops Address family operations. + */ +void rtnl_link_af_ops_put(struct rtnl_link_af_ops *ops) +{ + ops->ao_refcnt--; +} + +/** + * Register operations for a link address family + * @arg ops Address family operations + * + * This function must be called by modules implementing a specific link + * address family. It will make the operations implemented by the module + * available for everyone else. + * + * @return 0 on success or a negative error code. + * @return -NLE_INVAL Address family is out of range (0..AF_MAX) + * @return -NLE_EXIST Operations for address family already registered. + */ +int rtnl_link_af_register(struct rtnl_link_af_ops *ops) +{ + if (ops->ao_family == AF_UNSPEC || ops->ao_family >= AF_MAX) + return -NLE_INVAL; + + if (af_ops[ops->ao_family]) + return -NLE_EXIST; + + ops->ao_refcnt = 0; + af_ops[ops->ao_family] = ops; + + NL_DBG(1, "Registered link address family operations %u\n", + ops->ao_family); + + return 0; +} + +/** + * Unregister operations for a link address family + * @arg ops Address family operations + * + * This function must be called if a module implementing a specific link + * address family is unloaded or becomes unavailable. It must provide a + * set of operations which have previously been registered using + * rtnl_link_af_register(). + * + * @return 0 on success or a negative error code + * @return -NLE_INVAL ops is NULL + * @return -NLE_OBJ_NOTFOUND Address family operations not registered. + * @return -NLE_BUSY Address family operations still in use. + */ +int rtnl_link_af_unregister(struct rtnl_link_af_ops *ops) +{ + if (!ops) + return -NLE_INVAL; + + if (!af_ops[ops->ao_family]) + return -NLE_OBJ_NOTFOUND; + + if (ops->ao_refcnt > 0) + return -NLE_BUSY; + + af_ops[ops->ao_family] = NULL; + + NL_DBG(1, "Unregistered link address family operations %u\n", + ops->ao_family); + + return 0; +} + /** @} */ diff --git a/lib/route/link/vlan.c b/lib/route/link/vlan.c index c466afe..a76cb83 100644 --- a/lib/route/link/vlan.c +++ b/lib/route/link/vlan.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2008 Thomas Graf + * Copyright (c) 2003-2010 Thomas Graf */ /** @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include -- cgit v0.12