blob: 6aca520926b5c66b2676afb19d9dfc5fabaa96c8 [file] [log] [blame]
Thomas Graf44d36242007-09-15 01:28:01 +02001/*
2 * lib/cache_mngr.c Cache Manager
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 *
Thomas Grafe34ed952012-04-21 12:11:45 +02009 * Copyright (c) 2003-2012 Thomas Graf <tgraf@suug.ch>
Thomas Graf44d36242007-09-15 01:28:01 +020010 */
11
12/**
13 * @ingroup cache_mngt
14 * @defgroup cache_mngr Manager
Thomas Graffec10a22012-05-10 12:03:59 +020015 * @brief Manager keeping caches up to date automatically.
16 *
17 * The cache manager keeps caches up to date automatically by listening to
18 * netlink notifications and integrating the received information into the
19 * existing cache.
20 *
21 * @note This functionality is still considered experimental.
22 *
23 * Related sections in the development guide:
24 * - @core_doc{_cache_manager,Cache Manager}
Thomas Graf44d36242007-09-15 01:28:01 +020025 *
Thomas Graf44d36242007-09-15 01:28:01 +020026 * @{
Thomas Graffec10a22012-05-10 12:03:59 +020027 *
28 * Header
29 * ------
30 * ~~~~{.c}
31 * #include <netlink/cache.h>
32 * ~~~~
Thomas Graf44d36242007-09-15 01:28:01 +020033 */
34
Thomas Graf9680f912013-01-24 13:51:24 +010035#include <netlink-private/netlink.h>
André Draszikc1948ec2016-08-25 13:15:00 +010036#include <netlink-private/utils.h>
Thomas Graf44d36242007-09-15 01:28:01 +020037#include <netlink/netlink.h>
38#include <netlink/cache.h>
39#include <netlink/utils.h>
40
Thomas Graf743756f2012-04-21 15:22:04 +020041/** @cond SKIP */
Thomas Grafadbc5682012-04-21 12:23:38 +020042#define NASSOC_INIT 16
43#define NASSOC_EXPAND 8
Thomas Graf743756f2012-04-21 15:22:04 +020044/** @endcond */
Thomas Grafadbc5682012-04-21 12:23:38 +020045
Thomas Graf44d36242007-09-15 01:28:01 +020046static int include_cb(struct nl_object *obj, struct nl_parser_param *p)
47{
48 struct nl_cache_assoc *ca = p->pp_arg;
Thomas Graf2bcd8ec2011-10-21 11:31:15 +020049 struct nl_cache_ops *ops = ca->ca_cache->c_ops;
Thomas Graf44d36242007-09-15 01:28:01 +020050
51 NL_DBG(2, "Including object %p into cache %p\n", obj, ca->ca_cache);
52#ifdef NL_DEBUG
53 if (nl_debug >= 4)
54 nl_object_dump(obj, &nl_debug_dp);
55#endif
Thomas Graf2bcd8ec2011-10-21 11:31:15 +020056
57 if (ops->co_event_filter)
58 if (ops->co_event_filter(ca->ca_cache, obj) != NL_OK)
59 return 0;
60
Thomas Grafbd1e4d02012-04-22 15:23:52 +020061 if (ops->co_include_event)
62 return ops->co_include_event(ca->ca_cache, obj, ca->ca_change,
Tobias Jungel66d032a2016-11-13 15:21:46 +010063 ca->ca_change_v2,
Thomas Grafbd1e4d02012-04-22 15:23:52 +020064 ca->ca_change_data);
Tobias Jungel66d032a2016-11-13 15:21:46 +010065 else {
66 if (ca->ca_change_v2)
67 return nl_cache_include_v2(ca->ca_cache, obj, ca->ca_change_v2, ca->ca_change_data);
68 else
69 return nl_cache_include(ca->ca_cache, obj, ca->ca_change, ca->ca_change_data);
70 }
71
Thomas Graf44d36242007-09-15 01:28:01 +020072}
73
74static int event_input(struct nl_msg *msg, void *arg)
75{
76 struct nl_cache_mngr *mngr = arg;
77 int protocol = nlmsg_get_proto(msg);
78 int type = nlmsg_hdr(msg)->nlmsg_type;
79 struct nl_cache_ops *ops;
80 int i, n;
81 struct nl_parser_param p = {
82 .pp_cb = include_cb,
83 };
84
85 NL_DBG(2, "Cache manager %p, handling new message %p as event\n",
86 mngr, msg);
87#ifdef NL_DEBUG
88 if (nl_debug >= 4)
89 nl_msg_dump(msg, stderr);
90#endif
91
92 if (mngr->cm_protocol != protocol)
93 BUG();
94
95 for (i = 0; i < mngr->cm_nassocs; i++) {
96 if (mngr->cm_assocs[i].ca_cache) {
97 ops = mngr->cm_assocs[i].ca_cache->c_ops;
98 for (n = 0; ops->co_msgtypes[n].mt_id >= 0; n++)
99 if (ops->co_msgtypes[n].mt_id == type)
100 goto found;
101 }
102 }
103
104 return NL_SKIP;
105
106found:
107 NL_DBG(2, "Associated message %p to cache %p\n",
108 msg, mngr->cm_assocs[i].ca_cache);
109 p.pp_arg = &mngr->cm_assocs[i];
110
111 return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p);
112}
113
114/**
115 * Allocate new cache manager
Thomas Grafe34ed952012-04-21 12:11:45 +0200116 * @arg sk Netlink socket or NULL to auto allocate
117 * @arg protocol Netlink protocol this manager is used for
118 * @arg flags Flags (\c NL_AUTO_PROVIDE)
Thomas Grafc1073d62011-03-22 00:40:26 +0100119 * @arg result Result pointer
Thomas Graf44d36242007-09-15 01:28:01 +0200120 *
Thomas Grafe34ed952012-04-21 12:11:45 +0200121 * Allocates a new cache manager for the specified netlink protocol.
122 *
123 * 1. If sk is not specified (\c NULL) a netlink socket matching the
124 * specified protocol will be automatically allocated.
125 *
126 * 2. The socket will be put in non-blocking mode and sequence checking
127 * will be disabled regardless of whether the socket was provided by
128 * the caller or automatically allocated.
129 *
130 * 3. The socket will be connected.
131 *
132 * If the flag \c NL_AUTO_PROVIDE is specified, any cache added to the
133 * manager will automatically be made available to other users using
134 * nl_cache_mngt_provide().
135 *
136 * @note If the socket is provided by the caller, it is NOT recommended
137 * to use the socket for anything else besides receiving netlink
138 * notifications.
139 *
Thomas Grafc1073d62011-03-22 00:40:26 +0100140 * @return 0 on success or a negative error code.
Thomas Graf44d36242007-09-15 01:28:01 +0200141 */
Thomas Graf11553702008-05-15 13:26:32 +0200142int nl_cache_mngr_alloc(struct nl_sock *sk, int protocol, int flags,
Thomas Graf8a3efff2008-05-14 17:49:44 +0200143 struct nl_cache_mngr **result)
Thomas Graf44d36242007-09-15 01:28:01 +0200144{
145 struct nl_cache_mngr *mngr;
Thomas Graf8a3efff2008-05-14 17:49:44 +0200146 int err = -NLE_NOMEM;
Thomas Graf44d36242007-09-15 01:28:01 +0200147
Thomas Grafe34ed952012-04-21 12:11:45 +0200148 /* Catch abuse of flags */
149 if (flags & NL_ALLOCATED_SOCK)
Thomas Graf44d36242007-09-15 01:28:01 +0200150 BUG();
151
152 mngr = calloc(1, sizeof(*mngr));
153 if (!mngr)
Thomas Grafe34ed952012-04-21 12:11:45 +0200154 return -NLE_NOMEM;
Thomas Graf44d36242007-09-15 01:28:01 +0200155
Thomas Grafe34ed952012-04-21 12:11:45 +0200156 if (!sk) {
157 if (!(sk = nl_socket_alloc()))
158 goto errout;
159
160 flags |= NL_ALLOCATED_SOCK;
161 }
162
163 mngr->cm_sock = sk;
Thomas Grafadbc5682012-04-21 12:23:38 +0200164 mngr->cm_nassocs = NASSOC_INIT;
Thomas Graf44d36242007-09-15 01:28:01 +0200165 mngr->cm_protocol = protocol;
166 mngr->cm_flags = flags;
167 mngr->cm_assocs = calloc(mngr->cm_nassocs,
168 sizeof(struct nl_cache_assoc));
169 if (!mngr->cm_assocs)
Thomas Graf8a3efff2008-05-14 17:49:44 +0200170 goto errout;
Thomas Graf44d36242007-09-15 01:28:01 +0200171
Thomas Graf44d36242007-09-15 01:28:01 +0200172 /* Required to receive async event notifications */
Thomas Grafe34ed952012-04-21 12:11:45 +0200173 nl_socket_disable_seq_check(mngr->cm_sock);
Thomas Graf44d36242007-09-15 01:28:01 +0200174
Tobias Klauserb6cadfe2014-06-17 14:58:10 +0200175 if ((err = nl_connect(mngr->cm_sock, protocol)) < 0)
Thomas Graf44d36242007-09-15 01:28:01 +0200176 goto errout;
177
Tobias Klauserb6cadfe2014-06-17 14:58:10 +0200178 if ((err = nl_socket_set_nonblocking(mngr->cm_sock)) < 0)
Thomas Graf44d36242007-09-15 01:28:01 +0200179 goto errout;
180
roopa4d94ed52012-11-18 22:14:23 -0800181 /* Create and allocate socket for sync cache fills */
182 mngr->cm_sync_sock = nl_socket_alloc();
Tobias Klauser8f822702014-06-17 14:58:09 +0200183 if (!mngr->cm_sync_sock) {
184 err = -NLE_NOMEM;
roopa4d94ed52012-11-18 22:14:23 -0800185 goto errout;
Tobias Klauser8f822702014-06-17 14:58:09 +0200186 }
roopa4d94ed52012-11-18 22:14:23 -0800187 if ((err = nl_connect(mngr->cm_sync_sock, protocol)) < 0)
188 goto errout_free_sync_sock;
189
Thomas Graf44d36242007-09-15 01:28:01 +0200190 NL_DBG(1, "Allocated cache manager %p, protocol %d, %d caches\n",
191 mngr, protocol, mngr->cm_nassocs);
192
Thomas Graf8a3efff2008-05-14 17:49:44 +0200193 *result = mngr;
194 return 0;
Thomas Graf44d36242007-09-15 01:28:01 +0200195
roopa4d94ed52012-11-18 22:14:23 -0800196errout_free_sync_sock:
197 nl_socket_free(mngr->cm_sync_sock);
Thomas Graf44d36242007-09-15 01:28:01 +0200198errout:
199 nl_cache_mngr_free(mngr);
Thomas Graf8a3efff2008-05-14 17:49:44 +0200200 return err;
Thomas Graf44d36242007-09-15 01:28:01 +0200201}
202
203/**
Tobias Jungel66d032a2016-11-13 15:21:46 +0100204 * Set change_func_v2 for cache manager
205 * @arg mngr Cache manager.
206 * @arg cache Cache associated with the callback
207 * @arg cb Function to be called upon changes.
208 * @arg data Argument passed on to change callback
209 *
210 * Adds callback change_func_v2 to a registered cache. This callback provides
211 * in like the standard change_func the added or remove netlink object. In case
212 * of a change the old and the new object is provided as well as the according
213 * diff. If this callback is registered this has a higher priority then the
214 * change_func registered during cache registration. Hence only one callback is
215 * executed.
216 *
217 * The first netlink object in the callback is refering to the old object and
218 * the second to the new. This means on NL_ACT_CHANGE the first is the previous
219 * object in the cache and the second the updated version. On NL_ACT_DEL the
220 * first is the deleted object the second is NULL. On NL_ACT_NEW the first is
221 * NULL and the second the new netlink object.
222 *
223 * The user is responsible for calling nl_cache_mngr_poll() or monitor
224 * the socket and call nl_cache_mngr_data_ready() to allow the library
225 * to process netlink notification events.
226 *
227 * @see nl_cache_mngr_poll()
228 * @see nl_cache_mngr_data_ready()
229 *
230 * @return 0 on success or a negative error code.
231 * @return -NLE_PROTO_MISMATCH Protocol mismatch between cache manager and
232 * cache type
233 * @return -NLE_OPNOTSUPP Cache type does not support updates
234 * @return -NLE_RANGE Cache of this type is not registered
235 */
236static int nl_cache_mngr_set_change_func_v2(struct nl_cache_mngr *mngr,
237 struct nl_cache *cache,
238 change_func_v2_t cb, void *data)
239{
240 struct nl_cache_ops *ops;
241 int i;
242
243 ops = cache->c_ops;
244 if (!ops)
245 return -NLE_INVAL;
246
247 if (ops->co_protocol != mngr->cm_protocol)
248 return -NLE_PROTO_MISMATCH;
249
250 if (ops->co_groups == NULL)
251 return -NLE_OPNOTSUPP;
252
253 for (i = 0; i < mngr->cm_nassocs; i++)
254 if (mngr->cm_assocs[i].ca_cache == cache)
255 break;
256
257 if (i >= mngr->cm_nassocs) {
258 return -NLE_RANGE;
259 }
260
261 mngr->cm_assocs[i].ca_change_v2 = cb;
262 mngr->cm_assocs[i].ca_change_data = data;
263
264 return 0;
265}
266
267/**
roopa30d86262012-11-12 12:38:32 -0800268 * Add cache to cache manager
Thomas Graf44d36242007-09-15 01:28:01 +0200269 * @arg mngr Cache manager.
roopa30d86262012-11-12 12:38:32 -0800270 * @arg cache Cache to be added to cache manager
Thomas Grafdbefb732008-01-14 16:38:37 +0100271 * @arg cb Function to be called upon changes.
Thomas Grafc1073d62011-03-22 00:40:26 +0100272 * @arg data Argument passed on to change callback
Thomas Graf44d36242007-09-15 01:28:01 +0200273 *
roopa30d86262012-11-12 12:38:32 -0800274 * Adds cache to the manager. The operation will trigger a full
275 * dump request from the kernel to initially fill the contents
276 * of the cache. The manager will subscribe to the notification group
277 * of the cache and keep track of any further changes.
Thomas Graf44d36242007-09-15 01:28:01 +0200278 *
Thomas Graf743756f2012-04-21 15:22:04 +0200279 * The user is responsible for calling nl_cache_mngr_poll() or monitor
280 * the socket and call nl_cache_mngr_data_ready() to allow the library
281 * to process netlink notification events.
282 *
283 * @see nl_cache_mngr_poll()
284 * @see nl_cache_mngr_data_ready()
285 *
Thomas Graf8a3efff2008-05-14 17:49:44 +0200286 * @return 0 on success or a negative error code.
Thomas Graf653ea342012-04-21 09:59:26 +0200287 * @return -NLE_PROTO_MISMATCH Protocol mismatch between cache manager and
288 * cache type
289 * @return -NLE_OPNOTSUPP Cache type does not support updates
290 * @return -NLE_EXIST Cache of this type already being managed
Thomas Graf44d36242007-09-15 01:28:01 +0200291 */
roopa30d86262012-11-12 12:38:32 -0800292int nl_cache_mngr_add_cache(struct nl_cache_mngr *mngr, struct nl_cache *cache,
293 change_func_t cb, void *data)
Thomas Graf44d36242007-09-15 01:28:01 +0200294{
295 struct nl_cache_ops *ops;
Thomas Graf44d36242007-09-15 01:28:01 +0200296 struct nl_af_group *grp;
297 int err, i;
298
roopa30d86262012-11-12 12:38:32 -0800299 ops = cache->c_ops;
Thomas Graf8a3efff2008-05-14 17:49:44 +0200300 if (!ops)
roopa30d86262012-11-12 12:38:32 -0800301 return -NLE_INVAL;
Thomas Graf44d36242007-09-15 01:28:01 +0200302
Thomas Graf8a3efff2008-05-14 17:49:44 +0200303 if (ops->co_protocol != mngr->cm_protocol)
304 return -NLE_PROTO_MISMATCH;
Thomas Graf44d36242007-09-15 01:28:01 +0200305
Thomas Graf8a3efff2008-05-14 17:49:44 +0200306 if (ops->co_groups == NULL)
307 return -NLE_OPNOTSUPP;
Thomas Graf44d36242007-09-15 01:28:01 +0200308
Thomas Graf8a3efff2008-05-14 17:49:44 +0200309 for (i = 0; i < mngr->cm_nassocs; i++)
Thomas Graf44d36242007-09-15 01:28:01 +0200310 if (mngr->cm_assocs[i].ca_cache &&
Thomas Graf8a3efff2008-05-14 17:49:44 +0200311 mngr->cm_assocs[i].ca_cache->c_ops == ops)
312 return -NLE_EXIST;
Thomas Graf44d36242007-09-15 01:28:01 +0200313
Thomas Graf44d36242007-09-15 01:28:01 +0200314 for (i = 0; i < mngr->cm_nassocs; i++)
315 if (!mngr->cm_assocs[i].ca_cache)
316 break;
317
318 if (i >= mngr->cm_nassocs) {
Rasmus Villemoes3cbfa902017-06-08 10:59:12 +0200319 struct nl_cache_assoc *cm_assocs;
320 int cm_nassocs = mngr->cm_nassocs + NASSOC_EXPAND;
321
322 cm_assocs = realloc(mngr->cm_assocs,
323 cm_nassocs * sizeof(struct nl_cache_assoc));
324 if (cm_assocs == NULL)
Thomas Graf8a3efff2008-05-14 17:49:44 +0200325 return -NLE_NOMEM;
Thomas Grafadbc5682012-04-21 12:23:38 +0200326
Rasmus Villemoes3cbfa902017-06-08 10:59:12 +0200327 memset(cm_assocs + mngr->cm_nassocs, 0,
Thomas Grafadbc5682012-04-21 12:23:38 +0200328 NASSOC_EXPAND * sizeof(struct nl_cache_assoc));
Rasmus Villemoes3cbfa902017-06-08 10:59:12 +0200329 mngr->cm_assocs = cm_assocs;
330 mngr->cm_nassocs = cm_nassocs;
Thomas Grafadbc5682012-04-21 12:23:38 +0200331
332 NL_DBG(1, "Increased capacity of cache manager %p " \
333 "to %d\n", mngr, mngr->cm_nassocs);
Thomas Graf44d36242007-09-15 01:28:01 +0200334 }
335
Thomas Graf44d36242007-09-15 01:28:01 +0200336 for (grp = ops->co_groups; grp->ag_group; grp++) {
Thomas Grafe34ed952012-04-21 12:11:45 +0200337 err = nl_socket_add_membership(mngr->cm_sock, grp->ag_group);
Thomas Graf44d36242007-09-15 01:28:01 +0200338 if (err < 0)
roopa30d86262012-11-12 12:38:32 -0800339 return err;
Thomas Graf44d36242007-09-15 01:28:01 +0200340 }
341
roopa4d94ed52012-11-18 22:14:23 -0800342 err = nl_cache_refill(mngr->cm_sync_sock, cache);
Thomas Graf44d36242007-09-15 01:28:01 +0200343 if (err < 0)
344 goto errout_drop_membership;
345
346 mngr->cm_assocs[i].ca_cache = cache;
347 mngr->cm_assocs[i].ca_change = cb;
Andreas Fett4ab22cc2010-09-22 20:10:26 +0200348 mngr->cm_assocs[i].ca_change_data = data;
Thomas Graf44d36242007-09-15 01:28:01 +0200349
350 if (mngr->cm_flags & NL_AUTO_PROVIDE)
351 nl_cache_mngt_provide(cache);
352
353 NL_DBG(1, "Added cache %p <%s> to cache manager %p\n",
354 cache, nl_cache_name(cache), mngr);
355
Thomas Graf8a3efff2008-05-14 17:49:44 +0200356 return 0;
Thomas Graf44d36242007-09-15 01:28:01 +0200357
358errout_drop_membership:
359 for (grp = ops->co_groups; grp->ag_group; grp++)
Thomas Grafe34ed952012-04-21 12:11:45 +0200360 nl_socket_drop_membership(mngr->cm_sock, grp->ag_group);
roopa30d86262012-11-12 12:38:32 -0800361
362 return err;
363}
364
365/**
366 * Add cache to cache manager
367 * @arg mngr Cache manager.
Tobias Jungel66d032a2016-11-13 15:21:46 +0100368 * @arg cache Cache to be added to cache manager
369 * @arg cb V2 function to be called upon changes.
370 * @arg data Argument passed on to change callback
371 *
372 * Adds cache to the manager. The operation will trigger a full
373 * dump request from the kernel to initially fill the contents
374 * of the cache. The manager will subscribe to the notification group
375 * of the cache and keep track of any further changes.
376 *
377 * The user is responsible for calling nl_cache_mngr_poll() or monitor
378 * the socket and call nl_cache_mngr_data_ready() to allow the library
379 * to process netlink notification events.
380 *
381 * @see nl_cache_mngr_poll()
382 * @see nl_cache_mngr_data_ready()
383 *
384 * @return 0 on success or a negative error code.
385 * @return -NLE_PROTO_MISMATCH Protocol mismatch between cache manager and
386 * cache type
387 * @return -NLE_OPNOTSUPP Cache type does not support updates
388 * @return -NLE_EXIST Cache of this type already being managed
389 */
390int nl_cache_mngr_add_cache_v2(struct nl_cache_mngr *mngr, struct nl_cache *cache,
391 change_func_v2_t cb, void *data) {
392 int err;
393 err = nl_cache_mngr_add_cache(mngr, cache, NULL, NULL);
394 if (err < 0)
395 return err;
396
397 return nl_cache_mngr_set_change_func_v2(mngr, cache, cb, data);
398}
399
400/**
401 * Add cache to cache manager
402 * @arg mngr Cache manager.
roopa30d86262012-11-12 12:38:32 -0800403 * @arg name Name of cache to keep track of
404 * @arg cb Function to be called upon changes.
405 * @arg data Argument passed on to change callback
406 * @arg result Pointer to store added cache (optional)
407 *
408 * Allocates a new cache of the specified type and adds it to the manager.
409 * The operation will trigger a full dump request from the kernel to
410 * initially fill the contents of the cache. The manager will subscribe
411 * to the notification group of the cache and keep track of any further
412 * changes.
413 *
414 * The user is responsible for calling nl_cache_mngr_poll() or monitor
415 * the socket and call nl_cache_mngr_data_ready() to allow the library
416 * to process netlink notification events.
417 *
418 * @see nl_cache_mngr_poll()
419 * @see nl_cache_mngr_data_ready()
420 *
421 * @return 0 on success or a negative error code.
422 * @return -NLE_NOCACHE Unknown cache type
423 * @return -NLE_PROTO_MISMATCH Protocol mismatch between cache manager and
424 * cache type
425 * @return -NLE_OPNOTSUPP Cache type does not support updates
426 * @return -NLE_EXIST Cache of this type already being managed
427 */
428int nl_cache_mngr_add(struct nl_cache_mngr *mngr, const char *name,
429 change_func_t cb, void *data, struct nl_cache **result)
430{
431 struct nl_cache_ops *ops;
432 struct nl_cache *cache;
433 int err;
434
Thomas Grafcb82c2a2012-11-16 00:20:18 +0100435 ops = nl_cache_ops_lookup_safe(name);
roopa30d86262012-11-12 12:38:32 -0800436 if (!ops)
437 return -NLE_NOCACHE;
438
439 cache = nl_cache_alloc(ops);
Thomas Grafcb82c2a2012-11-16 00:20:18 +0100440 nl_cache_ops_put(ops);
roopa30d86262012-11-12 12:38:32 -0800441 if (!cache)
442 return -NLE_NOMEM;
443
444 err = nl_cache_mngr_add_cache(mngr, cache, cb, data);
445 if (err < 0)
446 goto errout_free_cache;
447
448 *result = cache;
449 return 0;
450
Thomas Graf44d36242007-09-15 01:28:01 +0200451errout_free_cache:
452 nl_cache_free(cache);
453
Thomas Graf8a3efff2008-05-14 17:49:44 +0200454 return err;
Thomas Graf44d36242007-09-15 01:28:01 +0200455}
456
457/**
Thomas Graf743756f2012-04-21 15:22:04 +0200458 * Get socket file descriptor
Thomas Graf44d36242007-09-15 01:28:01 +0200459 * @arg mngr Cache Manager
460 *
Thomas Graf743756f2012-04-21 15:22:04 +0200461 * Get the file descriptor of the socket associated with the manager.
462 *
463 * @note Do not use the socket for anything besides receiving
464 * notifications.
Thomas Graf44d36242007-09-15 01:28:01 +0200465 */
466int nl_cache_mngr_get_fd(struct nl_cache_mngr *mngr)
467{
Thomas Grafe34ed952012-04-21 12:11:45 +0200468 return nl_socket_get_fd(mngr->cm_sock);
Thomas Graf44d36242007-09-15 01:28:01 +0200469}
470
471/**
472 * Check for event notifications
473 * @arg mngr Cache Manager
474 * @arg timeout Upper limit poll() will block, in milliseconds.
475 *
476 * Causes poll() to be called to check for new event notifications
Thomas Graf743756f2012-04-21 15:22:04 +0200477 * being available. Calls nl_cache_mngr_data_ready() to process
478 * available data.
Thomas Graf44d36242007-09-15 01:28:01 +0200479 *
480 * This functionally is ideally called regularly during an idle
481 * period.
482 *
Thomas Graf743756f2012-04-21 15:22:04 +0200483 * A timeout can be specified in milliseconds to limit the time the
484 * function will wait for updates.
485 *
486 * @see nl_cache_mngr_data_ready()
487 *
488 * @return The number of messages processed or a negative error code.
Thomas Graf44d36242007-09-15 01:28:01 +0200489 */
490int nl_cache_mngr_poll(struct nl_cache_mngr *mngr, int timeout)
491{
492 int ret;
493 struct pollfd fds = {
Thomas Grafe34ed952012-04-21 12:11:45 +0200494 .fd = nl_socket_get_fd(mngr->cm_sock),
Thomas Graf44d36242007-09-15 01:28:01 +0200495 .events = POLLIN,
496 };
497
498 NL_DBG(3, "Cache manager %p, poll() fd %d\n", mngr, fds.fd);
499 ret = poll(&fds, 1, timeout);
500 NL_DBG(3, "Cache manager %p, poll() returned %d\n", mngr, ret);
Lubomir Rintelf5452952015-01-25 18:11:53 +0100501 if (ret < 0) {
Lubomir Rintelf5452952015-01-25 18:11:53 +0100502 NL_DBG(4, "nl_cache_mngr_poll(%p): poll() failed with %d (%s)\n",
André Draszikc1948ec2016-08-25 13:15:00 +0100503 mngr, errno, nl_strerror_l(errno));
Thomas Graf8a3efff2008-05-14 17:49:44 +0200504 return -nl_syserr2nlerr(errno);
Lubomir Rintelf5452952015-01-25 18:11:53 +0100505 }
Thomas Graf44d36242007-09-15 01:28:01 +0200506
Thomas Grafe34ed952012-04-21 12:11:45 +0200507 /* No events, return */
Thomas Graf44d36242007-09-15 01:28:01 +0200508 if (ret == 0)
509 return 0;
510
511 return nl_cache_mngr_data_ready(mngr);
512}
513
514/**
515 * Receive available event notifications
516 * @arg mngr Cache manager
517 *
518 * This function can be called if the socket associated to the manager
Thomas Graf743756f2012-04-21 15:22:04 +0200519 * contains updates to be received. This function should only be used
520 * if nl_cache_mngr_poll() is not used.
Thomas Graf44d36242007-09-15 01:28:01 +0200521 *
Thomas Graf743756f2012-04-21 15:22:04 +0200522 * The function will process messages until there is no more data to
523 * be read from the socket.
524 *
525 * @see nl_cache_mngr_poll()
526 *
527 * @return The number of messages processed or a negative error code.
Thomas Graf44d36242007-09-15 01:28:01 +0200528 */
529int nl_cache_mngr_data_ready(struct nl_cache_mngr *mngr)
530{
Thomas Grafa518a312012-04-21 12:47:29 +0200531 int err, nread = 0;
Thomas Grafb3201122012-04-21 10:51:34 +0200532 struct nl_cb *cb;
Thomas Graf44d36242007-09-15 01:28:01 +0200533
Thomas Grafb3201122012-04-21 10:51:34 +0200534 NL_DBG(2, "Cache manager %p, reading new data from fd %d\n",
Thomas Grafe34ed952012-04-21 12:11:45 +0200535 mngr, nl_socket_get_fd(mngr->cm_sock));
Thomas Grafb3201122012-04-21 10:51:34 +0200536
Thomas Grafe34ed952012-04-21 12:11:45 +0200537 cb = nl_cb_clone(mngr->cm_sock->s_cb);
Thomas Grafb3201122012-04-21 10:51:34 +0200538 if (cb == NULL)
539 return -NLE_NOMEM;
540
541 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, event_input, mngr);
542
Thomas Graf6f156a72012-05-08 22:48:00 +0200543 while ((err = nl_recvmsgs_report(mngr->cm_sock, cb)) > 0) {
Thomas Grafa518a312012-04-21 12:47:29 +0200544 NL_DBG(2, "Cache manager %p, recvmsgs read %d messages\n",
545 mngr, err);
546 nread += err;
547 }
548
Thomas Grafb3201122012-04-21 10:51:34 +0200549 nl_cb_put(cb);
Andrew Collins53ac5022013-06-17 15:58:43 -0600550 if (err < 0 && err != -NLE_AGAIN)
Thomas Graf44d36242007-09-15 01:28:01 +0200551 return err;
552
Thomas Grafa518a312012-04-21 12:47:29 +0200553 return nread;
Thomas Graf44d36242007-09-15 01:28:01 +0200554}
555
556/**
Thomas Graf51653662012-04-21 15:48:37 +0200557 * Print information about cache manager
558 * @arg mngr Cache manager
559 * @arg p Dumping parameters
560 *
561 * Prints information about the cache manager including all managed caches.
562 *
563 * @note This is a debugging function.
564 */
565void nl_cache_mngr_info(struct nl_cache_mngr *mngr, struct nl_dump_params *p)
566{
567 char buf[128];
568 int i;
569
570 nl_dump_line(p, "cache-manager <%p>\n", mngr);
571 nl_dump_line(p, " .protocol = %s\n",
572 nl_nlfamily2str(mngr->cm_protocol, buf, sizeof(buf)));
573 nl_dump_line(p, " .flags = %#x\n", mngr->cm_flags);
574 nl_dump_line(p, " .nassocs = %u\n", mngr->cm_nassocs);
575 nl_dump_line(p, " .sock = <%p>\n", mngr->cm_sock);
576
577 for (i = 0; i < mngr->cm_nassocs; i++) {
578 struct nl_cache_assoc *assoc = &mngr->cm_assocs[i];
579
580 if (assoc->ca_cache) {
581 nl_dump_line(p, " .cache[%d] = <%p> {\n", i, assoc->ca_cache);
582 nl_dump_line(p, " .name = %s\n", assoc->ca_cache->c_ops->co_name);
583 nl_dump_line(p, " .change_func = <%p>\n", assoc->ca_change);
584 nl_dump_line(p, " .change_data = <%p>\n", assoc->ca_change_data);
585 nl_dump_line(p, " .nitems = %u\n", nl_cache_nitems(assoc->ca_cache));
586 nl_dump_line(p, " .objects = {\n");
587
588 p->dp_prefix += 6;
589 nl_cache_dump(assoc->ca_cache, p);
590 p->dp_prefix -= 6;
591
592 nl_dump_line(p, " }\n");
593 nl_dump_line(p, " }\n");
594 }
595 }
596}
597
598/**
Thomas Graf080727d2008-02-05 12:35:41 +0100599 * Free cache manager and all caches.
600 * @arg mngr Cache manager.
Thomas Graf44d36242007-09-15 01:28:01 +0200601 *
Thomas Grafe34ed952012-04-21 12:11:45 +0200602 * Release all resources held by a cache manager.
Thomas Graf44d36242007-09-15 01:28:01 +0200603 */
604void nl_cache_mngr_free(struct nl_cache_mngr *mngr)
605{
Thomas Graf080727d2008-02-05 12:35:41 +0100606 int i;
607
Thomas Graf44d36242007-09-15 01:28:01 +0200608 if (!mngr)
609 return;
610
Thomas Grafe34ed952012-04-21 12:11:45 +0200611 if (mngr->cm_sock)
612 nl_close(mngr->cm_sock);
613
roopa4d94ed52012-11-18 22:14:23 -0800614 if (mngr->cm_sync_sock) {
615 nl_close(mngr->cm_sync_sock);
616 nl_socket_free(mngr->cm_sync_sock);
617 }
618
Thomas Grafe34ed952012-04-21 12:11:45 +0200619 if (mngr->cm_flags & NL_ALLOCATED_SOCK)
620 nl_socket_free(mngr->cm_sock);
Thomas Graf080727d2008-02-05 12:35:41 +0100621
Alexander Sack98197172011-10-21 00:31:39 +0200622 for (i = 0; i < mngr->cm_nassocs; i++) {
623 if (mngr->cm_assocs[i].ca_cache) {
624 nl_cache_mngt_unprovide(mngr->cm_assocs[i].ca_cache);
Thomas Graf080727d2008-02-05 12:35:41 +0100625 nl_cache_free(mngr->cm_assocs[i].ca_cache);
Alexander Sack98197172011-10-21 00:31:39 +0200626 }
627 }
Thomas Graf44d36242007-09-15 01:28:01 +0200628
629 free(mngr->cm_assocs);
Thomas Graf44d36242007-09-15 01:28:01 +0200630
631 NL_DBG(1, "Cache manager %p freed\n", mngr);
Thomas Haller29a38942014-06-10 17:53:37 +0200632
633 free(mngr);
Thomas Graf44d36242007-09-15 01:28:01 +0200634}
635
636/** @} */