libnl  1.1
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. More...
 
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. More...
 
int nl_cache_mngr_get_fd (struct nl_cache_mngr *mngr)
 Get file descriptor. More...
 
int nl_cache_mngr_poll (struct nl_cache_mngr *mngr, int timeout)
 Check for event notifications. More...
 
int nl_cache_mngr_data_ready (struct nl_cache_mngr *mngr)
 Receive available event notifications. More...
 
void nl_cache_mngr_free (struct nl_cache_mngr *mngr)
 Free cache manager. More...
 

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);
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");
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, ...);
}
4) Release cache manager

Function Documentation

struct nl_cache_mngr* nl_cache_mngr_alloc ( struct nl_handle *  handle,
int  protocol,
int  flags 
)
read
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.

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().

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 
171  nl_socket_modify_cb(mngr->cm_handle, NL_CB_VALID, NL_CB_CUSTOM,
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 
188 enomem:
189  nl_errno(ENOMEM);
190 errout:
191  nl_cache_mngr_free(mngr);
192  return NULL;
193 }
struct nl_cache* nl_cache_mngr_add ( struct nl_cache_mngr *  mngr,
const char *  name,
change_func_t  cb 
)
read
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.

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().

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 
241 retry:
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)
281  nl_cache_mngt_provide(cache);
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 
288 errout_drop_membership:
289  for (grp = ops->co_groups; grp->ag_group; grp++)
290  nl_socket_drop_membership(mngr->cm_handle, grp->ag_group);
291 errout_free_cache:
292  nl_cache_free(cache);
293 
294  return NULL;
295 }
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 }
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.

References nl_cache_mngr_data_ready().

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)
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.

References nl_recvmsgs_default().

Referenced by nl_cache_mngr_poll().

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 }
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.

References nl_close(), and nl_handle_destroy().

Referenced by nl_cache_mngr_alloc().

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 }