Home | History | Annotate | Download | only in lib
      1 /*
      2  * lib/cache_mngt.c	Cache Management
      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 core
     14  * @defgroup cache_mngt Caching
     15  * @{
     16  */
     17 
     18 #include <netlink-local.h>
     19 #include <netlink/netlink.h>
     20 #include <netlink/cache.h>
     21 #include <netlink/utils.h>
     22 
     23 static struct nl_cache_ops *cache_ops;
     24 
     25 /**
     26  * @name Cache Operations Sets
     27  * @{
     28  */
     29 
     30 /**
     31  * Lookup the set cache operations of a certain cache type
     32  * @arg name		name of the cache type
     33  *
     34  * @return The cache operations or NULL if no operations
     35  *         have been registered under the specified name.
     36  */
     37 struct nl_cache_ops *nl_cache_ops_lookup(const char *name)
     38 {
     39 	struct nl_cache_ops *ops;
     40 
     41 	for (ops = cache_ops; ops; ops = ops->co_next)
     42 		if (!strcmp(ops->co_name, name))
     43 			return ops;
     44 
     45 	return NULL;
     46 }
     47 
     48 /**
     49  * Associate a message type to a set of cache operations
     50  * @arg protocol		netlink protocol
     51  * @arg msgtype			netlink message type
     52  *
     53  * Associates the specified netlink message type with
     54  * a registered set of cache operations.
     55  *
     56  * @return The cache operations or NULL if no association
     57  *         could be made.
     58  */
     59 struct nl_cache_ops *nl_cache_ops_associate(int protocol, int msgtype)
     60 {
     61 	int i;
     62 	struct nl_cache_ops *ops;
     63 
     64 	for (ops = cache_ops; ops; ops = ops->co_next) {
     65 		if (ops->co_protocol != protocol)
     66 			continue;
     67 
     68 		for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
     69 			if (ops->co_msgtypes[i].mt_id == msgtype)
     70 				return ops;
     71 	}
     72 
     73 	return NULL;
     74 }
     75 
     76 /**
     77  * Lookup message type cache association
     78  * @arg ops			cache operations
     79  * @arg msgtype			netlink message type
     80  *
     81  * Searches for a matching message type association ing the specified
     82  * cache operations.
     83  *
     84  * @return A message type association or NULL.
     85  */
     86 struct nl_msgtype *nl_msgtype_lookup(struct nl_cache_ops *ops, int msgtype)
     87 {
     88 	int i;
     89 
     90 	for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
     91 		if (ops->co_msgtypes[i].mt_id == msgtype)
     92 			return &ops->co_msgtypes[i];
     93 
     94 	return NULL;
     95 }
     96 
     97 static struct nl_cache_ops *cache_ops_lookup_for_obj(struct nl_object_ops *obj_ops)
     98 {
     99 	struct nl_cache_ops *ops;
    100 
    101 	for (ops = cache_ops; ops; ops = ops->co_next)
    102 		if (ops->co_obj_ops == obj_ops)
    103 			return ops;
    104 
    105 	return NULL;
    106 
    107 }
    108 
    109 /**
    110  * Call a function for each registered cache operation
    111  * @arg cb		Callback function to be called
    112  * @arg arg		User specific argument.
    113  */
    114 void nl_cache_ops_foreach(void (*cb)(struct nl_cache_ops *, void *), void *arg)
    115 {
    116 	struct nl_cache_ops *ops;
    117 
    118 	for (ops = cache_ops; ops; ops = ops->co_next)
    119 		cb(ops, arg);
    120 }
    121 
    122 /**
    123  * Register a set of cache operations
    124  * @arg ops		cache operations
    125  *
    126  * Called by users of caches to announce the avaibility of
    127  * a certain cache type.
    128  *
    129  * @return 0 on success or a negative error code.
    130  */
    131 int nl_cache_mngt_register(struct nl_cache_ops *ops)
    132 {
    133 	if (!ops->co_name || !ops->co_obj_ops)
    134 		return -NLE_INVAL;
    135 
    136 	if (nl_cache_ops_lookup(ops->co_name))
    137 		return -NLE_EXIST;
    138 
    139 	ops->co_next = cache_ops;
    140 	cache_ops = ops;
    141 
    142 	NL_DBG(1, "Registered cache operations %s\n", ops->co_name);
    143 
    144 	return 0;
    145 }
    146 
    147 /**
    148  * Unregister a set of cache operations
    149  * @arg ops		cache operations
    150  *
    151  * Called by users of caches to announce a set of
    152  * cache operations is no longer available. The
    153  * specified cache operations must have been registered
    154  * previously using nl_cache_mngt_register()
    155  *
    156  * @return 0 on success or a negative error code
    157  */
    158 int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
    159 {
    160 	struct nl_cache_ops *t, **tp;
    161 
    162 	for (tp = &cache_ops; (t=*tp) != NULL; tp = &t->co_next)
    163 		if (t == ops)
    164 			break;
    165 
    166 	if (!t)
    167 		return -NLE_NOCACHE;
    168 
    169 	NL_DBG(1, "Unregistered cache operations %s\n", ops->co_name);
    170 
    171 	*tp = t->co_next;
    172 	return 0;
    173 }
    174 
    175 /** @} */
    176 
    177 /**
    178  * @name Global Cache Provisioning/Requiring
    179  * @{
    180  */
    181 
    182 /**
    183  * Provide a cache for global use
    184  * @arg cache		cache to provide
    185  *
    186  * Offers the specified cache to be used by other modules.
    187  * Only one cache per type may be shared at a time,
    188  * a previsouly provided caches will be overwritten.
    189  */
    190 void nl_cache_mngt_provide(struct nl_cache *cache)
    191 {
    192 	struct nl_cache_ops *ops;
    193 
    194 	ops = cache_ops_lookup_for_obj(cache->c_ops->co_obj_ops);
    195 	if (!ops)
    196 		BUG();
    197 	else
    198 		ops->co_major_cache = cache;
    199 }
    200 
    201 /**
    202  * Unprovide a cache for global use
    203  * @arg cache		cache to unprovide
    204  *
    205  * Cancels the offer to use a cache globally. The
    206  * cache will no longer be returned via lookups but
    207  * may still be in use.
    208  */
    209 void nl_cache_mngt_unprovide(struct nl_cache *cache)
    210 {
    211 	struct nl_cache_ops *ops;
    212 
    213 	ops = cache_ops_lookup_for_obj(cache->c_ops->co_obj_ops);
    214 	if (!ops)
    215 		BUG();
    216 	else if (ops->co_major_cache == cache)
    217 		ops->co_major_cache = NULL;
    218 }
    219 
    220 /**
    221  * Demand the use of a global cache
    222  * @arg name		name of the required object type
    223  *
    224  * Trys to find a cache of the specified type for global
    225  * use.
    226  *
    227  * @return A cache provided by another subsystem of the
    228  *         specified type marked to be available.
    229  */
    230 struct nl_cache *nl_cache_mngt_require(const char *name)
    231 {
    232 	struct nl_cache_ops *ops;
    233 
    234 	ops = nl_cache_ops_lookup(name);
    235 	if (!ops || !ops->co_major_cache) {
    236 		fprintf(stderr, "Application BUG: Your application must "
    237 			"call nl_cache_mngt_provide() and\nprovide a valid "
    238 			"%s cache to be used for internal lookups.\nSee the "
    239 			" API documentation for more details.\n", name);
    240 
    241 		return NULL;
    242 	}
    243 
    244 	return ops->co_major_cache;
    245 }
    246 
    247 /** @} */
    248 
    249 /** @} */
    250