1 /* 2 * lib/cache.c Caching Module 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 cache_mngt 14 * @defgroup cache Cache 15 * 16 * @code 17 * Cache Management | | Type Specific Cache Operations 18 * 19 * | | +----------------+ +------------+ 20 * | request update | | msg_parser | 21 * | | +----------------+ +------------+ 22 * +- - - - -^- - - - - - - -^- -|- - - - 23 * nl_cache_update: | | | | 24 * 1) --------- co_request_update ------+ | | 25 * | | | 26 * 2) destroy old cache +----------- pp_cb ---------|---+ 27 * | | | 28 * 3) ---------- nl_recvmsgs ----------+ +- cb_valid -+ 29 * +--------------+ | | | | 30 * | nl_cache_add |<-----+ + - - -v- -|- - - - - - - - - - - 31 * +--------------+ | | +-------------+ 32 * | nl_recvmsgs | 33 * | | +-----|-^-----+ 34 * +---v-|---+ 35 * | | | nl_recv | 36 * +---------+ 37 * | | Core Netlink 38 * @endcode 39 * 40 * @{ 41 */ 42 43 #include <netlink-local.h> 44 #include <netlink/netlink.h> 45 #include <netlink/cache.h> 46 #include <netlink/object.h> 47 #include <netlink/utils.h> 48 49 /** 50 * @name Cache Creation/Deletion 51 * @{ 52 */ 53 54 /** 55 * Allocate an empty cache 56 * @arg ops cache operations to base the cache on 57 * 58 * @return A newly allocated and initialized cache. 59 */ 60 struct nl_cache *nl_cache_alloc(struct nl_cache_ops *ops) 61 { 62 struct nl_cache *cache; 63 64 cache = calloc(1, sizeof(*cache)); 65 if (!cache) 66 return NULL; 67 68 nl_init_list_head(&cache->c_items); 69 cache->c_ops = ops; 70 71 NL_DBG(2, "Allocated cache %p <%s>.\n", cache, nl_cache_name(cache)); 72 73 return cache; 74 } 75 76 int nl_cache_alloc_and_fill(struct nl_cache_ops *ops, struct nl_sock *sock, 77 struct nl_cache **result) 78 { 79 struct nl_cache *cache; 80 int err; 81 82 if (!(cache = nl_cache_alloc(ops))) 83 return -NLE_NOMEM; 84 85 if (sock && (err = nl_cache_refill(sock, cache)) < 0) { 86 nl_cache_free(cache); 87 return err; 88 } 89 90 *result = cache; 91 return 0; 92 } 93 94 /** 95 * Clear a cache. 96 * @arg cache cache to clear 97 * 98 * Removes all elements of a cache. 99 */ 100 void nl_cache_clear(struct nl_cache *cache) 101 { 102 struct nl_object *obj, *tmp; 103 104 NL_DBG(1, "Clearing cache %p <%s>...\n", cache, nl_cache_name(cache)); 105 106 nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list) 107 nl_cache_remove(obj); 108 } 109 110 /** 111 * Free a cache. 112 * @arg cache Cache to free. 113 * 114 * Removes all elements of a cache and frees all memory. 115 * 116 * @note Use this function if you are working with allocated caches. 117 */ 118 void nl_cache_free(struct nl_cache *cache) 119 { 120 if (!cache) 121 return; 122 123 nl_cache_clear(cache); 124 NL_DBG(1, "Freeing cache %p <%s>...\n", cache, nl_cache_name(cache)); 125 free(cache); 126 } 127 128 /** @} */ 129 130 /** 131 * @name Cache Modifications 132 * @{ 133 */ 134 135 static int __cache_add(struct nl_cache *cache, struct nl_object *obj) 136 { 137 obj->ce_cache = cache; 138 139 nl_list_add_tail(&obj->ce_list, &cache->c_items); 140 cache->c_nitems++; 141 142 NL_DBG(1, "Added %p to cache %p <%s>.\n", 143 obj, cache, nl_cache_name(cache)); 144 145 return 0; 146 } 147 148 /** 149 * Add object to a cache. 150 * @arg cache Cache to add object to 151 * @arg obj Object to be added to the cache 152 * 153 * Adds the given object to the specified cache. The object is cloned 154 * if it has been added to another cache already. 155 * 156 * @return 0 or a negative error code. 157 */ 158 int nl_cache_add(struct nl_cache *cache, struct nl_object *obj) 159 { 160 struct nl_object *new; 161 162 if (cache->c_ops->co_obj_ops != obj->ce_ops) 163 return -NLE_OBJ_MISMATCH; 164 165 if (!nl_list_empty(&obj->ce_list)) { 166 new = nl_object_clone(obj); 167 if (!new) 168 return -NLE_NOMEM; 169 } else { 170 nl_object_get(obj); 171 new = obj; 172 } 173 174 return __cache_add(cache, new); 175 } 176 177 /** 178 * Removes an object from a cache. 179 * @arg obj Object to remove from its cache 180 * 181 * Removes the object \c obj from the cache it is assigned to, since 182 * an object can only be assigned to one cache at a time, the cache 183 * must ne be passed along with it. 184 */ 185 void nl_cache_remove(struct nl_object *obj) 186 { 187 struct nl_cache *cache = obj->ce_cache; 188 189 if (cache == NULL) 190 return; 191 192 nl_list_del(&obj->ce_list); 193 obj->ce_cache = NULL; 194 nl_object_put(obj); 195 cache->c_nitems--; 196 197 NL_DBG(1, "Deleted %p from cache %p <%s>.\n", 198 obj, cache, nl_cache_name(cache)); 199 } 200 201 /** @} */ 202 203 /** 204 * @name Synchronization 205 * @{ 206 */ 207 208 /** 209 * Request a full dump from the kernel to fill a cache 210 * @arg sk Netlink socket. 211 * @arg cache Cache subjected to be filled. 212 * 213 * Send a dumping request to the kernel causing it to dump all objects 214 * related to the specified cache to the netlink socket. 215 * 216 * Use nl_cache_pickup() to read the objects from the socket and fill them 217 * into a cache. 218 */ 219 int nl_cache_request_full_dump(struct nl_sock *sk, struct nl_cache *cache) 220 { 221 NL_DBG(2, "Requesting dump from kernel for cache %p <%s>...\n", 222 cache, nl_cache_name(cache)); 223 224 if (cache->c_ops->co_request_update == NULL) 225 return -NLE_OPNOTSUPP; 226 227 return cache->c_ops->co_request_update(cache, sk); 228 } 229 230 /** @cond SKIP */ 231 struct update_xdata { 232 struct nl_cache_ops *ops; 233 struct nl_parser_param *params; 234 }; 235 236 static int update_msg_parser(struct nl_msg *msg, void *arg) 237 { 238 struct update_xdata *x = arg; 239 240 return nl_cache_parse(x->ops, &msg->nm_src, msg->nm_nlh, x->params); 241 } 242 /** @endcond */ 243 244 int __cache_pickup(struct nl_sock *sk, struct nl_cache *cache, 245 struct nl_parser_param *param) 246 { 247 int err; 248 struct nl_cb *cb; 249 struct update_xdata x = { 250 .ops = cache->c_ops, 251 .params = param, 252 }; 253 254 NL_DBG(1, "Picking up answer for cache %p <%s>...\n", 255 cache, nl_cache_name(cache)); 256 257 cb = nl_cb_clone(sk->s_cb); 258 if (cb == NULL) 259 return -NLE_NOMEM; 260 261 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, update_msg_parser, &x); 262 263 err = nl_recvmsgs(sk, cb); 264 if (err < 0) 265 NL_DBG(2, "While picking up for %p <%s>, recvmsgs() returned " \ 266 "%d: %s", cache, nl_cache_name(cache), 267 err, nl_geterror(err)); 268 269 nl_cb_put(cb); 270 271 return err; 272 } 273 274 static int pickup_cb(struct nl_object *c, struct nl_parser_param *p) 275 { 276 return nl_cache_add((struct nl_cache *) p->pp_arg, c); 277 } 278 279 /** 280 * Pickup a netlink dump response and put it into a cache. 281 * @arg sk Netlink socket. 282 * @arg cache Cache to put items into. 283 * 284 * Waits for netlink messages to arrive, parses them and puts them into 285 * the specified cache. 286 * 287 * @return 0 on success or a negative error code. 288 */ 289 int nl_cache_pickup(struct nl_sock *sk, struct nl_cache *cache) 290 { 291 struct nl_parser_param p = { 292 .pp_cb = pickup_cb, 293 .pp_arg = cache, 294 }; 295 296 return __cache_pickup(sk, cache, &p); 297 } 298 299 300 /** @} */ 301 302 /** 303 * @name Parsing 304 * @{ 305 */ 306 307 /** @cond SKIP */ 308 int nl_cache_parse(struct nl_cache_ops *ops, struct sockaddr_nl *who, 309 struct nlmsghdr *nlh, struct nl_parser_param *params) 310 { 311 int i, err; 312 313 if (!nlmsg_valid_hdr(nlh, ops->co_hdrsize)) 314 return -NLE_MSG_TOOSHORT; 315 316 for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) { 317 if (ops->co_msgtypes[i].mt_id == nlh->nlmsg_type) { 318 err = ops->co_msg_parser(ops, who, nlh, params); 319 if (err != -NLE_OPNOTSUPP) 320 goto errout; 321 } 322 } 323 324 325 err = -NLE_MSGTYPE_NOSUPPORT; 326 errout: 327 return err; 328 } 329 /** @endcond */ 330 331 /** 332 * Parse a netlink message and add it to the cache. 333 * @arg cache cache to add element to 334 * @arg msg netlink message 335 * 336 * Parses a netlink message by calling the cache specific message parser 337 * and adds the new element to the cache. 338 * 339 * @return 0 or a negative error code. 340 */ 341 int nl_cache_parse_and_add(struct nl_cache *cache, struct nl_msg *msg) 342 { 343 struct nl_parser_param p = { 344 .pp_cb = pickup_cb, 345 .pp_arg = cache, 346 }; 347 348 return nl_cache_parse(cache->c_ops, NULL, nlmsg_hdr(msg), &p); 349 } 350 351 /** 352 * (Re)fill a cache with the contents in the kernel. 353 * @arg sk Netlink socket. 354 * @arg cache cache to update 355 * 356 * Clears the specified cache and fills it with the current state in 357 * the kernel. 358 * 359 * @return 0 or a negative error code. 360 */ 361 int nl_cache_refill(struct nl_sock *sk, struct nl_cache *cache) 362 { 363 int err; 364 365 err = nl_cache_request_full_dump(sk, cache); 366 if (err < 0) 367 return err; 368 369 NL_DBG(2, "Upading cache %p <%s>, request sent, waiting for dump...\n", 370 cache, nl_cache_name(cache)); 371 nl_cache_clear(cache); 372 373 return nl_cache_pickup(sk, cache); 374 } 375 376 /** @} */ 377
This page was automatically generated by LXR 0.3.1. • OpenWrt