libnl 1.1.4
Functions
Manager

Helps keeping caches up to date. More...

Functions

struct nl_cache_mngr * nl_cache_mngr_alloc (struct nl_handle *handle, int protocol, int flags)
 Allocate new cache manager.
 
struct nl_cache * nl_cache_mngr_add (struct nl_cache_mngr *mngr, const char *name, change_func_t cb)
 Add cache responsibility to cache manager.
 
int nl_cache_mngr_get_fd (struct nl_cache_mngr *mngr)
 Get file descriptor.
 
int nl_cache_mngr_poll (struct nl_cache_mngr *mngr, int timeout)
 Check for event notifications.
 
int nl_cache_mngr_data_ready (struct nl_cache_mngr *mngr)
 Receive available event notifications.
 
void nl_cache_mngr_free (struct nl_cache_mngr *mngr)
 Free cache manager.
 

Detailed Description

The purpose of a cache manager is to keep track of caches and automatically receive event notifications to keep the caches up to date with the kernel state. Each manager has exactly one netlink socket assigned which limits the scope of each manager to exactly one netlink family. Therefore all caches committed to a manager must be part of the same netlink family. Due to the nature of a manager, it is not possible to have a cache maintain two instances of the same cache type. The socket is subscribed to the event notification group of each cache and also put into non-blocking mode. Functions exist to poll() on the socket to wait for new events to be received.

App libnl Kernel
| |
+-----------------+ [ notification, link change ]
| | Cache Manager | | [ (IFF_UP | IFF_RUNNING) ]
| | |
| | +------------+| | | [ notification, new addr ]
<-------|---| route/link |<-------(async)--+ [ 10.0.1.1/32 dev eth1 ]
| | +------------+| | |
| +------------+| |
<---|---|---| route/addr |<------|-(async)--------------+
| +------------+|
| | +------------+| |
<-------|---| ... ||
| | +------------+| |
+-----------------+
| |
1) Creating a new cache manager
struct nl_cache_mngr *mngr;
// Allocate a new cache manager for RTNETLINK and automatically
// provide the caches added to the manager.
mngr = nl_cache_mngr_alloc(NETLINK_ROUTE, NL_AUTO_PROVIDE);
struct nl_cache_mngr * nl_cache_mngr_alloc(struct nl_handle *handle, int protocol, int flags)
Allocate new cache manager.
Definition: cache_mngr.c:149
2) Keep track of a cache
struct nl_cache *cache;
// Create a new cache for links/interfaces and ask the manager to
// keep it up to date for us. This will trigger a full dump request
// to initially fill the cache.
cache = nl_cache_mngr_add(mngr, "route/link");
struct nl_cache * nl_cache_mngr_add(struct nl_cache_mngr *mngr, const char *name, change_func_t cb)
Add cache responsibility to cache manager.
Definition: cache_mngr.c:209
3) Make the manager receive updates
// Give the manager the ability to receive updates, will call poll()
// with a timeout of 5 seconds.
if (nl_cache_mngr_poll(mngr, 5000) > 0) {
// Manager received at least one update, dump cache?
nl_cache_dump(cache, ...);
}
int nl_cache_mngr_poll(struct nl_cache_mngr *mngr, int timeout)
Check for event notifications.
Definition: cache_mngr.c:325
void nl_cache_dump(struct nl_cache *cache, struct nl_dump_params *params)
Dump all elements of a cache.
Definition: cache.c:731
4) Release cache manager
void nl_cache_mngr_free(struct nl_cache_mngr *mngr)
Free cache manager.
Definition: cache_mngr.c:373

Function Documentation

◆ nl_cache_mngr_alloc()

struct nl_cache_mngr * nl_cache_mngr_alloc ( struct nl_handle *  handle,
int  protocol,
int  flags 
)
Parameters
handleNetlink socket/handle to be used
protocolNetlink Protocol this manager is used for
flagsFlags
Returns
Newly allocated cache manager or NULL on failure.

Definition at line 149 of file cache_mngr.c.

151{
152 struct nl_cache_mngr *mngr;
153
154 if (handle == NULL)
155 BUG();
156
157 mngr = calloc(1, sizeof(*mngr));
158 if (!mngr)
159 goto enomem;
160
161 mngr->cm_handle = handle;
162 mngr->cm_nassocs = 32;
163 mngr->cm_protocol = protocol;
164 mngr->cm_flags = flags;
165 mngr->cm_assocs = calloc(mngr->cm_nassocs,
166 sizeof(struct nl_cache_assoc));
167 if (!mngr->cm_assocs)
168 goto enomem;
169
170
172 event_input, mngr);
173
174 /* Required to receive async event notifications */
175 nl_disable_sequence_check(mngr->cm_handle);
176
177 if (nl_connect(mngr->cm_handle, protocol) < 0)
178 goto errout;
179
180 if (nl_socket_set_nonblocking(mngr->cm_handle) < 0)
181 goto errout;
182
183 NL_DBG(1, "Allocated cache manager %p, protocol %d, %d caches\n",
184 mngr, protocol, mngr->cm_nassocs);
185
186 return mngr;
187
188enomem:
189 nl_errno(ENOMEM);
190errout:
191 nl_cache_mngr_free(mngr);
192 return NULL;
193}
@ NL_CB_VALID
Message is valid.
Definition: handlers.h:96
@ NL_CB_CUSTOM
Customized handler specified by the user.
Definition: handlers.h:84
int nl_connect(struct nl_handle *handle, int protocol)
Create and connect netlink socket.
Definition: nl.c:191
void nl_disable_sequence_check(struct nl_handle *handle)
Disable sequence number checking.
Definition: socket.c:285
int nl_socket_modify_cb(struct nl_handle *handle, enum nl_cb_type type, enum nl_cb_kind kind, nl_recvmsg_msg_cb_t func, void *arg)
Modify the callback handler associated to the socket.
Definition: socket.c:514
int nl_socket_set_nonblocking(struct nl_handle *handle)
Set file descriptor of socket handle to non-blocking state.
Definition: socket.c:454

References nl_cache_mngr_free(), NL_CB_CUSTOM, NL_CB_VALID, nl_connect(), nl_disable_sequence_check(), nl_socket_modify_cb(), and nl_socket_set_nonblocking().

◆ nl_cache_mngr_add()

struct nl_cache * nl_cache_mngr_add ( struct nl_cache_mngr *  mngr,
const char *  name,
change_func_t  cb 
)
Parameters
mngrCache manager.
nameName of cache to keep track of
cbFunction to be called upon changes.

Allocates a new cache of the specified type and adds it to the manager. The operation will trigger a full dump request from the kernel to initially fill the contents of the cache. The manager will subscribe to the notification group of the cache to keep track of any further changes.

Returns
The newly allocated cache or NULL on failure.

Definition at line 209 of file cache_mngr.c.

211{
212 struct nl_cache_ops *ops;
213 struct nl_cache *cache;
214 struct nl_af_group *grp;
215 int err, i;
216
217 ops = nl_cache_ops_lookup(name);
218 if (!ops) {
219 nl_error(ENOENT, "Unknown cache type");
220 return NULL;
221 }
222
223 if (ops->co_protocol != mngr->cm_protocol) {
224 nl_error(EINVAL, "Netlink protocol mismatch");
225 return NULL;
226 }
227
228 if (ops->co_groups == NULL) {
229 nl_error(EOPNOTSUPP, NULL);
230 return NULL;
231 }
232
233 for (i = 0; i < mngr->cm_nassocs; i++) {
234 if (mngr->cm_assocs[i].ca_cache &&
235 mngr->cm_assocs[i].ca_cache->c_ops == ops) {
236 nl_error(EEXIST, "Cache of this type already managed");
237 return NULL;
238 }
239 }
240
241retry:
242 for (i = 0; i < mngr->cm_nassocs; i++)
243 if (!mngr->cm_assocs[i].ca_cache)
244 break;
245
246 if (i >= mngr->cm_nassocs) {
247 mngr->cm_nassocs += 16;
248 mngr->cm_assocs = realloc(mngr->cm_assocs,
249 mngr->cm_nassocs *
250 sizeof(struct nl_cache_assoc));
251 if (mngr->cm_assocs == NULL) {
252 nl_errno(ENOMEM);
253 return NULL;
254 } else {
255 NL_DBG(1, "Increased capacity of cache manager %p " \
256 "to %d\n", mngr, mngr->cm_nassocs);
257 goto retry;
258 }
259 }
260
261 cache = nl_cache_alloc(ops);
262 if (!cache) {
263 nl_errno(ENOMEM);
264 return NULL;
265 }
266
267 for (grp = ops->co_groups; grp->ag_group; grp++) {
268 err = nl_socket_add_membership(mngr->cm_handle, grp->ag_group);
269 if (err < 0)
270 goto errout_free_cache;
271 }
272
273 err = nl_cache_refill(mngr->cm_handle, cache);
274 if (err < 0)
275 goto errout_drop_membership;
276
277 mngr->cm_assocs[i].ca_cache = cache;
278 mngr->cm_assocs[i].ca_change = cb;
279
280 if (mngr->cm_flags & NL_AUTO_PROVIDE)
282
283 NL_DBG(1, "Added cache %p <%s> to cache manager %p\n",
284 cache, nl_cache_name(cache), mngr);
285
286 return cache;
287
288errout_drop_membership:
289 for (grp = ops->co_groups; grp->ag_group; grp++)
290 nl_socket_drop_membership(mngr->cm_handle, grp->ag_group);
291errout_free_cache:
292 nl_cache_free(cache);
293
294 return NULL;
295}
struct nl_cache_ops * nl_cache_ops_lookup(const char *name)
Lookup cache operations by name.
Definition: cache_mngt.c:68
void nl_cache_mngt_provide(struct nl_cache *cache)
Provide a cache for global use.
Definition: cache_mngt.c:304
void nl_cache_free(struct nl_cache *cache)
Free a cache.
Definition: cache.c:277
struct nl_cache * nl_cache_alloc(struct nl_cache_ops *ops)
Allocate an empty cache.
Definition: cache.c:170
int nl_cache_refill(struct nl_handle *handle, struct nl_cache *cache)
(Re)fill a cache with the contents in the kernel.
Definition: cache.c:680
int nl_socket_drop_membership(struct nl_handle *handle, int group)
Leave a group.
Definition: socket.c:388
int nl_socket_add_membership(struct nl_handle *handle, int group)
Join a group.
Definition: socket.c:361
Address family to netlink group association.
Definition: cache-api.h:144
int ag_group
Netlink group identifier.
Definition: cache-api.h:149
Cache Operations.
Definition: cache-api.h:164

References nl_af_group::ag_group, nl_cache_alloc(), nl_cache_free(), nl_cache_mngt_provide(), nl_cache_ops_lookup(), nl_cache_refill(), nl_socket_add_membership(), and nl_socket_drop_membership().

◆ nl_cache_mngr_get_fd()

int nl_cache_mngr_get_fd ( struct nl_cache_mngr *  mngr)
Parameters
mngrCache Manager

Get the file descriptor of the socket associated to the manager. This can be used to change socket options or monitor activity using poll()/select().

Definition at line 305 of file cache_mngr.c.

306{
307 return nl_socket_get_fd(mngr->cm_handle);
308}

◆ nl_cache_mngr_poll()

int nl_cache_mngr_poll ( struct nl_cache_mngr *  mngr,
int  timeout 
)
Parameters
mngrCache Manager
timeoutUpper limit poll() will block, in milliseconds.

Causes poll() to be called to check for new event notifications being available. Automatically receives and handles available notifications.

This functionally is ideally called regularly during an idle period.

Returns
A positive value if at least one update was handled, 0 for none, or a negative error code.

Definition at line 325 of file cache_mngr.c.

326{
327 int ret;
328 struct pollfd fds = {
329 .fd = nl_socket_get_fd(mngr->cm_handle),
330 .events = POLLIN,
331 };
332
333 NL_DBG(3, "Cache manager %p, poll() fd %d\n", mngr, fds.fd);
334 ret = poll(&fds, 1, timeout);
335 NL_DBG(3, "Cache manager %p, poll() returned %d\n", mngr, ret);
336 if (ret < 0)
337 return nl_errno(errno);
338
339 if (ret == 0)
340 return 0;
341
342 return nl_cache_mngr_data_ready(mngr);
343}
int nl_cache_mngr_data_ready(struct nl_cache_mngr *mngr)
Receive available event notifications.
Definition: cache_mngr.c:356

References nl_cache_mngr_data_ready().

◆ nl_cache_mngr_data_ready()

int nl_cache_mngr_data_ready ( struct nl_cache_mngr *  mngr)
Parameters
mngrCache manager

This function can be called if the socket associated to the manager contains updates to be received. This function should not be used if nl_cache_mngr_poll() is used.

Returns
A positive value if at least one update was handled, 0 for none, or a negative error code.

Definition at line 356 of file cache_mngr.c.

357{
358 int err;
359
360 err = nl_recvmsgs_default(mngr->cm_handle);
361 if (err < 0)
362 return err;
363
364 return 1;
365}
int nl_recvmsgs_default(struct nl_handle *handle)
Receive a set of message from a netlink socket using handlers in nl_handle.
Definition: nl.c:782

References nl_recvmsgs_default().

Referenced by nl_cache_mngr_poll().

◆ nl_cache_mngr_free()

void nl_cache_mngr_free ( struct nl_cache_mngr *  mngr)
Parameters
mngrCache manager

Release all resources after usage of a cache manager.

Definition at line 373 of file cache_mngr.c.

374{
375 if (!mngr)
376 return;
377
378 if (mngr->cm_handle) {
379 nl_close(mngr->cm_handle);
380 nl_handle_destroy(mngr->cm_handle);
381 }
382
383 free(mngr->cm_assocs);
384 free(mngr);
385
386 NL_DBG(1, "Cache manager %p freed\n", mngr);
387}
void nl_close(struct nl_handle *handle)
Close/Disconnect netlink socket.
Definition: nl.c:247
void nl_handle_destroy(struct nl_handle *handle)
Destroy netlink handle.
Definition: socket.c:246

References nl_close(), and nl_handle_destroy().

Referenced by nl_cache_mngr_alloc().