Home | History | Annotate | Download | only in link
      1 /*
      2  * lib/route/link/api.c		Link Info API
      3  *
      4  *	This library is free software; you can redistribute it and/or
      5  *	modify it under the terms of the GNU Lesser General Public
      6  *	License as published by the Free Software Foundation version 2.1
      7  *	of the License.
      8  *
      9  * Copyright (c) 2003-2008 Thomas Graf <tgraf (at) suug.ch>
     10  */
     11 
     12 /**
     13  * @ingroup link
     14  * @defgroup link_API Link Modules API
     15  * @brief API for modules implementing specific link types/semantics.
     16  *
     17  * @par 1) Registering/Unregistering a new link info type
     18  * @code
     19  * static struct rtnl_link_info_ops vlan_info_ops = {
     20  * 	.io_name		= "vlan",
     21  * 	.io_alloc		= vlan_alloc,
     22  * 	.io_parse		= vlan_parse,
     23  * 	.io_dump[NL_DUMP_BRIEF]	= vlan_dump_brief,
     24  * 	.io_dump[NL_DUMP_FULL]	= vlan_dump_full,
     25  * 	.io_free		= vlan_free,
     26  * };
     27  *
     28  * static void __init vlan_init(void)
     29  * {
     30  * 	rtnl_link_register_info(&vlan_info_ops);
     31  * }
     32  *
     33  * static void __exit vlan_exit(void)
     34  * {
     35  * 	rtnl_link_unregister_info(&vlan_info_ops);
     36  * }
     37  * @endcode
     38  *
     39  * @{
     40  */
     41 
     42 #include <netlink-private/netlink.h>
     43 #include <netlink/netlink.h>
     44 #include <netlink/utils.h>
     45 #include <netlink/route/link.h>
     46 #include <netlink-private/route/link/api.h>
     47 
     48 static NL_LIST_HEAD(info_ops);
     49 
     50 /* lock protecting info_ops and af_ops */
     51 static NL_RW_LOCK(info_lock);
     52 
     53 static struct rtnl_link_info_ops *__rtnl_link_info_ops_lookup(const char *name)
     54 {
     55 	struct rtnl_link_info_ops *ops;
     56 
     57 	nl_list_for_each_entry(ops, &info_ops, io_list)
     58 		if (!strcmp(ops->io_name, name))
     59 			return ops;
     60 
     61 	return NULL;
     62 }
     63 
     64 /**
     65  * @name Link Info Modules
     66  * @{
     67  */
     68 
     69 /**
     70  * Return operations of a specific link info type
     71  * @arg name		Name of link info type.
     72  *
     73  * @note The returned pointer must be given back using rtnl_link_info_ops_put()
     74  *
     75  * @return Pointer to operations or NULL if unavailable.
     76  */
     77 struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *name)
     78 {
     79 	struct rtnl_link_info_ops *ops;
     80 
     81 	nl_write_lock(&info_lock);
     82 	if ((ops = __rtnl_link_info_ops_lookup(name)))
     83 		ops->io_refcnt++;
     84 	nl_write_unlock(&info_lock);
     85 
     86 	return ops;
     87 }
     88 
     89 /**
     90  * Give back reference to a set of operations.
     91  * @arg ops		Link info operations.
     92  */
     93 void rtnl_link_info_ops_put(struct rtnl_link_info_ops *ops)
     94 {
     95 	if (ops)
     96 		ops->io_refcnt--;
     97 }
     98 
     99 /**
    100  * Register operations for a link info type
    101  * @arg ops		Link info operations
    102  *
    103  * This function must be called by modules implementing a specific link
    104  * info type. It will make the operations implemented by the module
    105  * available for everyone else.
    106  *
    107  * @return 0 on success or a negative error code.
    108  * @return -NLE_INVAL Link info name not specified.
    109  * @return -NLE_EXIST Operations for address family already registered.
    110  */
    111 int rtnl_link_register_info(struct rtnl_link_info_ops *ops)
    112 {
    113 	int err = 0;
    114 
    115 	if (ops->io_name == NULL)
    116 		return -NLE_INVAL;
    117 
    118 	nl_write_lock(&info_lock);
    119 	if (__rtnl_link_info_ops_lookup(ops->io_name)) {
    120 		err = -NLE_EXIST;
    121 		goto errout;
    122 	}
    123 
    124 	NL_DBG(1, "Registered link info operations %s\n", ops->io_name);
    125 
    126 	nl_list_add_tail(&ops->io_list, &info_ops);
    127 errout:
    128 	nl_write_unlock(&info_lock);
    129 
    130 	return err;
    131 }
    132 
    133 /**
    134  * Unregister operations for a link info type
    135  * @arg ops		Link info operations
    136  *
    137  * This function must be called if a module implementing a specific link
    138  * info type is unloaded or becomes unavailable. It must provide a
    139  * set of operations which have previously been registered using
    140  * rtnl_link_register_info().
    141  *
    142  * @return 0 on success or a negative error code
    143  * @return _NLE_OPNOTSUPP Link info operations not registered.
    144  * @return -NLE_BUSY Link info operations still in use.
    145  */
    146 int rtnl_link_unregister_info(struct rtnl_link_info_ops *ops)
    147 {
    148 	struct rtnl_link_info_ops *t;
    149 	int err = -NLE_OPNOTSUPP;
    150 
    151 	nl_write_lock(&info_lock);
    152 
    153 	nl_list_for_each_entry(t, &info_ops, io_list) {
    154 		if (t == ops) {
    155 			if (t->io_refcnt > 0) {
    156 				err = -NLE_BUSY;
    157 				goto errout;
    158 			}
    159 
    160 			nl_list_del(&t->io_list);
    161 
    162 			NL_DBG(1, "Unregistered link info operations %s\n",
    163 				ops->io_name);
    164 			err = 0;
    165 			goto errout;
    166 		}
    167 	}
    168 
    169 errout:
    170 	nl_write_unlock(&info_lock);
    171 
    172 	return err;
    173 }
    174 
    175 /** @} */
    176 
    177 /**
    178  * @name Link Address Family Modules
    179  * @{
    180  */
    181 
    182 static struct rtnl_link_af_ops *af_ops[AF_MAX];
    183 
    184 /**
    185  * Return operations of a specific link address family
    186  * @arg family		Address family
    187  *
    188  * @note The returned pointer must be given back using rtnl_link_af_ops_put()
    189  *
    190  * @return Pointer to operations or NULL if unavailable.
    191  */
    192 struct rtnl_link_af_ops *rtnl_link_af_ops_lookup(const unsigned int family)
    193 {
    194 	if (family == AF_UNSPEC || family >= AF_MAX)
    195 		return NULL;
    196 
    197 	nl_write_lock(&info_lock);
    198 	if (af_ops[family])
    199 		af_ops[family]->ao_refcnt++;
    200 	nl_write_unlock(&info_lock);
    201 
    202 	return af_ops[family];
    203 }
    204 
    205 /**
    206  * Give back reference to a set of operations.
    207  * @arg ops		Address family operations.
    208  */
    209 void rtnl_link_af_ops_put(struct rtnl_link_af_ops *ops)
    210 {
    211 	if (ops)
    212 		ops->ao_refcnt--;
    213 }
    214 
    215 /**
    216  * Allocate and return data buffer for link address family modules
    217  * @arg link		Link object
    218  * @arg ops		Address family operations
    219  *
    220  * This function must be called by link address family modules in all
    221  * cases where the API does not provide the data buffer as argument
    222  * already. This typically includes set functions the module provides.
    223  * Calling this function is strictly required to ensure proper allocation
    224  * of the buffer upon first use. Link objects will NOT proactively
    225  * allocate a data buffer for each registered link address family.
    226  *
    227  * @return Pointer to data buffer or NULL on error.
    228  */
    229 void *rtnl_link_af_alloc(struct rtnl_link *link,
    230 			 const struct rtnl_link_af_ops *ops)
    231 {
    232 	int family;
    233 
    234 	if (!link || !ops)
    235 		BUG();
    236 
    237 	family = ops->ao_family;
    238 
    239 	if (!link->l_af_data[family]) {
    240 		if (!ops->ao_alloc)
    241 			BUG();
    242 
    243 		link->l_af_data[family] = ops->ao_alloc(link);
    244 		if (!link->l_af_data[family])
    245 			return NULL;
    246 	}
    247 
    248 	return link->l_af_data[family];
    249 }
    250 
    251 /**
    252  * Return data buffer for link address family modules
    253  * @arg link		Link object
    254  * @arg ops		Address family operations
    255  *
    256  * This function returns a pointer to the data buffer for the specified link
    257  * address family module or NULL if the buffer was not allocated yet. This
    258  * function is typically used by get functions of modules which are not
    259  * interested in having the data buffer allocated if no values have been set
    260  * yet.
    261  *
    262  * @return Pointer to data buffer or NULL on error.
    263  */
    264 void *rtnl_link_af_data(const struct rtnl_link *link,
    265 			const struct rtnl_link_af_ops *ops)
    266 {
    267 	if (!link || !ops)
    268 		BUG();
    269 
    270 	return link->l_af_data[ops->ao_family];
    271 }
    272 
    273 /**
    274  * Register operations for a link address family
    275  * @arg ops		Address family operations
    276  *
    277  * This function must be called by modules implementing a specific link
    278  * address family. It will make the operations implemented by the module
    279  * available for everyone else.
    280  *
    281  * @return 0 on success or a negative error code.
    282  * @return -NLE_INVAL Address family is out of range (0..AF_MAX)
    283  * @return -NLE_EXIST Operations for address family already registered.
    284  */
    285 int rtnl_link_af_register(struct rtnl_link_af_ops *ops)
    286 {
    287 	int err = 0;
    288 
    289 	if (ops->ao_family == AF_UNSPEC || ops->ao_family >= AF_MAX)
    290 		return -NLE_INVAL;
    291 
    292 	nl_write_lock(&info_lock);
    293 	if (af_ops[ops->ao_family]) {
    294 		err = -NLE_EXIST;
    295 		goto errout;
    296 	}
    297 
    298 	ops->ao_refcnt = 0;
    299 	af_ops[ops->ao_family] = ops;
    300 
    301 	NL_DBG(1, "Registered link address family operations %u\n",
    302 		ops->ao_family);
    303 
    304 errout:
    305 	nl_write_unlock(&info_lock);
    306 
    307 	return err;
    308 }
    309 
    310 /**
    311  * Unregister operations for a link address family
    312  * @arg ops		Address family operations
    313  *
    314  * This function must be called if a module implementing a specific link
    315  * address family is unloaded or becomes unavailable. It must provide a
    316  * set of operations which have previously been registered using
    317  * rtnl_link_af_register().
    318  *
    319  * @return 0 on success or a negative error code
    320  * @return -NLE_INVAL ops is NULL
    321  * @return -NLE_OBJ_NOTFOUND Address family operations not registered.
    322  * @return -NLE_BUSY Address family operations still in use.
    323  */
    324 int rtnl_link_af_unregister(struct rtnl_link_af_ops *ops)
    325 {
    326 	int err = -NLE_INVAL;
    327 
    328 	if (!ops)
    329 		return err;
    330 
    331 	nl_write_lock(&info_lock);
    332 	if (!af_ops[ops->ao_family]) {
    333 		err = -NLE_OBJ_NOTFOUND;
    334 		goto errout;
    335 	}
    336 
    337 	if (ops->ao_refcnt > 0) {
    338 		err = -NLE_BUSY;
    339 		goto errout;
    340 	}
    341 
    342 	af_ops[ops->ao_family] = NULL;
    343 
    344 	NL_DBG(1, "Unregistered link address family operations %u\n",
    345 		ops->ao_family);
    346 
    347 errout:
    348 	nl_write_unlock(&info_lock);
    349 
    350 	return err;
    351 }
    352 
    353 /**
    354  * Compare af data for a link address family
    355  * @arg a		Link object a
    356  * @arg b		Link object b
    357  * @arg family		af data family
    358  *
    359  * This function will compare af_data between two links
    360  * a and b of family given by arg family
    361  *
    362  * @return 0 if address family specific data matches or is not present
    363  * or != 0 if it mismatches.
    364  */
    365 int rtnl_link_af_data_compare(struct rtnl_link *a, struct rtnl_link *b,
    366 			      int family)
    367 {
    368 	struct rtnl_link_af_ops *af_ops;
    369 	int ret = 0;
    370 
    371 	if (!a->l_af_data[family] && !b->l_af_data[family])
    372 		return 0;
    373 
    374 	if (!a->l_af_data[family] || !b->l_af_data[family])
    375 		return ~0;
    376 
    377 	af_ops = rtnl_link_af_ops_lookup(family);
    378 	if (!af_ops)
    379 		return ~0;
    380 
    381 	if (af_ops->ao_compare == NULL) {
    382 		ret = ~0;
    383 		goto out;
    384 	}
    385 
    386 	ret = af_ops->ao_compare(a, b, family, ~0, 0);
    387 
    388 out:
    389 	rtnl_link_af_ops_put(af_ops);
    390 
    391 	return ret;
    392 }
    393 
    394 /** @} */
    395 
    396 /** @} */
    397 
    398