123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397 |
- /*
- * lib/route/link/api.c Link Info 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-2008 Thomas Graf <tgraf@suug.ch>
- */
- /**
- * @ingroup link
- * @defgroup link_API Link Modules API
- * @brief API for modules implementing specific link types/semantics.
- *
- * @par 1) Registering/Unregistering a new link info type
- * @code
- * static struct rtnl_link_info_ops vlan_info_ops = {
- * .io_name = "vlan",
- * .io_alloc = vlan_alloc,
- * .io_parse = vlan_parse,
- * .io_dump[NL_DUMP_BRIEF] = vlan_dump_brief,
- * .io_dump[NL_DUMP_FULL] = vlan_dump_full,
- * .io_free = vlan_free,
- * };
- *
- * static void __init vlan_init(void)
- * {
- * rtnl_link_register_info(&vlan_info_ops);
- * }
- *
- * static void __exit vlan_exit(void)
- * {
- * rtnl_link_unregister_info(&vlan_info_ops);
- * }
- * @endcode
- *
- * @{
- */
- #include <netlink-private/netlink.h>
- #include <netlink/netlink.h>
- #include <netlink/utils.h>
- #include <netlink/route/link.h>
- #include <netlink-private/route/link/api.h>
- static NL_LIST_HEAD(info_ops);
- /* lock protecting info_ops and af_ops */
- static NL_RW_LOCK(info_lock);
- static struct rtnl_link_info_ops *__rtnl_link_info_ops_lookup(const char *name)
- {
- struct rtnl_link_info_ops *ops;
- nl_list_for_each_entry(ops, &info_ops, io_list)
- if (!strcmp(ops->io_name, name))
- return ops;
- return NULL;
- }
- /**
- * @name Link Info Modules
- * @{
- */
- /**
- * Return operations of a specific link info type
- * @arg name Name of link info type.
- *
- * @note The returned pointer must be given back using rtnl_link_info_ops_put()
- *
- * @return Pointer to operations or NULL if unavailable.
- */
- struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *name)
- {
- struct rtnl_link_info_ops *ops;
- nl_write_lock(&info_lock);
- if ((ops = __rtnl_link_info_ops_lookup(name)))
- ops->io_refcnt++;
- nl_write_unlock(&info_lock);
- return ops;
- }
- /**
- * Give back reference to a set of operations.
- * @arg ops Link info operations.
- */
- void rtnl_link_info_ops_put(struct rtnl_link_info_ops *ops)
- {
- if (ops)
- ops->io_refcnt--;
- }
- /**
- * Register operations for a link info type
- * @arg ops Link info operations
- *
- * This function must be called by modules implementing a specific link
- * info type. 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 Link info name not specified.
- * @return -NLE_EXIST Operations for address family already registered.
- */
- int rtnl_link_register_info(struct rtnl_link_info_ops *ops)
- {
- int err = 0;
- if (ops->io_name == NULL)
- return -NLE_INVAL;
- nl_write_lock(&info_lock);
- if (__rtnl_link_info_ops_lookup(ops->io_name)) {
- err = -NLE_EXIST;
- goto errout;
- }
- NL_DBG(1, "Registered link info operations %s\n", ops->io_name);
- nl_list_add_tail(&ops->io_list, &info_ops);
- errout:
- nl_write_unlock(&info_lock);
- return err;
- }
- /**
- * Unregister operations for a link info type
- * @arg ops Link info operations
- *
- * This function must be called if a module implementing a specific link
- * info type is unloaded or becomes unavailable. It must provide a
- * set of operations which have previously been registered using
- * rtnl_link_register_info().
- *
- * @return 0 on success or a negative error code
- * @return _NLE_OPNOTSUPP Link info operations not registered.
- * @return -NLE_BUSY Link info operations still in use.
- */
- int rtnl_link_unregister_info(struct rtnl_link_info_ops *ops)
- {
- struct rtnl_link_info_ops *t;
- int err = -NLE_OPNOTSUPP;
- nl_write_lock(&info_lock);
- nl_list_for_each_entry(t, &info_ops, io_list) {
- if (t == ops) {
- if (t->io_refcnt > 0) {
- err = -NLE_BUSY;
- goto errout;
- }
- nl_list_del(&t->io_list);
- NL_DBG(1, "Unregistered link info operations %s\n",
- ops->io_name);
- err = 0;
- goto errout;
- }
- }
- errout:
- nl_write_unlock(&info_lock);
- return err;
- }
- /** @} */
- /**
- * @name Link Address Family Modules
- * @{
- */
- 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;
- nl_write_lock(&info_lock);
- if (af_ops[family])
- af_ops[family]->ao_refcnt++;
- nl_write_unlock(&info_lock);
- 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)
- {
- if (ops)
- ops->ao_refcnt--;
- }
- /**
- * Allocate and return data buffer for link address family modules
- * @arg link Link object
- * @arg ops Address family operations
- *
- * This function must be called by link address family modules in all
- * cases where the API does not provide the data buffer as argument
- * already. This typically includes set functions the module provides.
- * Calling this function is strictly required to ensure proper allocation
- * of the buffer upon first use. Link objects will NOT proactively
- * allocate a data buffer for each registered link address family.
- *
- * @return Pointer to data buffer or NULL on error.
- */
- void *rtnl_link_af_alloc(struct rtnl_link *link,
- const struct rtnl_link_af_ops *ops)
- {
- int family;
- if (!link || !ops)
- BUG();
- family = ops->ao_family;
- if (!link->l_af_data[family]) {
- if (!ops->ao_alloc)
- BUG();
-
- link->l_af_data[family] = ops->ao_alloc(link);
- if (!link->l_af_data[family])
- return NULL;
- }
- return link->l_af_data[family];
- }
- /**
- * Return data buffer for link address family modules
- * @arg link Link object
- * @arg ops Address family operations
- *
- * This function returns a pointer to the data buffer for the specified link
- * address family module or NULL if the buffer was not allocated yet. This
- * function is typically used by get functions of modules which are not
- * interested in having the data buffer allocated if no values have been set
- * yet.
- *
- * @return Pointer to data buffer or NULL on error.
- */
- void *rtnl_link_af_data(const struct rtnl_link *link,
- const struct rtnl_link_af_ops *ops)
- {
- if (!link || !ops)
- BUG();
- return link->l_af_data[ops->ao_family];
- }
- /**
- * 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)
- {
- int err = 0;
- if (ops->ao_family == AF_UNSPEC || ops->ao_family >= AF_MAX)
- return -NLE_INVAL;
- nl_write_lock(&info_lock);
- if (af_ops[ops->ao_family]) {
- err = -NLE_EXIST;
- goto errout;
- }
- ops->ao_refcnt = 0;
- af_ops[ops->ao_family] = ops;
- NL_DBG(1, "Registered link address family operations %u\n",
- ops->ao_family);
- errout:
- nl_write_unlock(&info_lock);
- return err;
- }
- /**
- * 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)
- {
- int err = -NLE_INVAL;
- if (!ops)
- return err;
- nl_write_lock(&info_lock);
- if (!af_ops[ops->ao_family]) {
- err = -NLE_OBJ_NOTFOUND;
- goto errout;
- }
- if (ops->ao_refcnt > 0) {
- err = -NLE_BUSY;
- goto errout;
- }
- af_ops[ops->ao_family] = NULL;
- NL_DBG(1, "Unregistered link address family operations %u\n",
- ops->ao_family);
- errout:
- nl_write_unlock(&info_lock);
- return err;
- }
- /**
- * Compare af data for a link address family
- * @arg a Link object a
- * @arg b Link object b
- * @arg family af data family
- *
- * This function will compare af_data between two links
- * a and b of family given by arg family
- *
- * @return 0 if address family specific data matches or is not present
- * or != 0 if it mismatches.
- */
- int rtnl_link_af_data_compare(struct rtnl_link *a, struct rtnl_link *b,
- int family)
- {
- struct rtnl_link_af_ops *af_ops;
- int ret = 0;
- if (!a->l_af_data[family] && !b->l_af_data[family])
- return 0;
- if (!a->l_af_data[family] || !b->l_af_data[family])
- return ~0;
- af_ops = rtnl_link_af_ops_lookup(family);
- if (!af_ops)
- return ~0;
- if (af_ops->ao_compare == NULL) {
- ret = ~0;
- goto out;
- }
- ret = af_ops->ao_compare(a, b, family, ~0, 0);
- out:
- rtnl_link_af_ops_put(af_ops);
- return ret;
- }
- /** @} */
- /** @} */
|