| 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@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 | |