Manager
[Caching]

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);
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:
handle Netlink socket/handle to be used
protocol Netlink Protocol this manager is used for
flags Flags
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().

00151 {
00152         struct nl_cache_mngr *mngr;
00153 
00154         if (handle == NULL)
00155                 BUG();
00156 
00157         mngr = calloc(1, sizeof(*mngr));
00158         if (!mngr)
00159                 goto enomem;
00160 
00161         mngr->cm_handle = handle;
00162         mngr->cm_nassocs = 32;
00163         mngr->cm_protocol = protocol;
00164         mngr->cm_flags = flags;
00165         mngr->cm_assocs = calloc(mngr->cm_nassocs,
00166                                  sizeof(struct nl_cache_assoc));
00167         if (!mngr->cm_assocs)
00168                 goto enomem;
00169 
00170 
00171         nl_socket_modify_cb(mngr->cm_handle, NL_CB_VALID, NL_CB_CUSTOM,
00172                             event_input, mngr);
00173 
00174         /* Required to receive async event notifications */
00175         nl_disable_sequence_check(mngr->cm_handle);
00176 
00177         if (nl_connect(mngr->cm_handle, protocol) < 0)
00178                 goto errout;
00179 
00180         if (nl_socket_set_nonblocking(mngr->cm_handle) < 0)
00181                 goto errout;
00182 
00183         NL_DBG(1, "Allocated cache manager %p, protocol %d, %d caches\n",
00184                mngr, protocol, mngr->cm_nassocs);
00185 
00186         return mngr;
00187 
00188 enomem:
00189         nl_errno(ENOMEM);
00190 errout:
00191         nl_cache_mngr_free(mngr);
00192         return NULL;
00193 }

struct nl_cache* nl_cache_mngr_add ( struct nl_cache_mngr *  mngr,
const char *  name,
change_func_t  cb 
) [read]
Parameters:
mngr Cache manager.
name Name of cache to keep track of
cb Function 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().

00211 {
00212         struct nl_cache_ops *ops;
00213         struct nl_cache *cache;
00214         struct nl_af_group *grp;
00215         int err, i;
00216 
00217         ops = nl_cache_ops_lookup(name);
00218         if (!ops) {
00219                 nl_error(ENOENT, "Unknown cache type");
00220                 return NULL;
00221         }
00222 
00223         if (ops->co_protocol != mngr->cm_protocol) {
00224                 nl_error(EINVAL, "Netlink protocol mismatch");
00225                 return NULL;
00226         }
00227 
00228         if (ops->co_groups == NULL) {
00229                 nl_error(EOPNOTSUPP, NULL);
00230                 return NULL;
00231         }
00232 
00233         for (i = 0; i < mngr->cm_nassocs; i++) {
00234                 if (mngr->cm_assocs[i].ca_cache &&
00235                     mngr->cm_assocs[i].ca_cache->c_ops == ops) {
00236                         nl_error(EEXIST, "Cache of this type already managed");
00237                         return NULL;
00238                 }
00239         }
00240 
00241 retry:
00242         for (i = 0; i < mngr->cm_nassocs; i++)
00243                 if (!mngr->cm_assocs[i].ca_cache)
00244                         break;
00245 
00246         if (i >= mngr->cm_nassocs) {
00247                 mngr->cm_nassocs += 16;
00248                 mngr->cm_assocs = realloc(mngr->cm_assocs,
00249                                           mngr->cm_nassocs *
00250                                           sizeof(struct nl_cache_assoc));
00251                 if (mngr->cm_assocs == NULL) {
00252                         nl_errno(ENOMEM);
00253                         return NULL;
00254                 } else {
00255                         NL_DBG(1, "Increased capacity of cache manager %p " \
00256                                   "to %d\n", mngr, mngr->cm_nassocs);
00257                         goto retry;
00258                 }
00259         }
00260 
00261         cache = nl_cache_alloc(ops);
00262         if (!cache) {
00263                 nl_errno(ENOMEM);
00264                 return NULL;
00265         }
00266 
00267         for (grp = ops->co_groups; grp->ag_group; grp++) {
00268                 err = nl_socket_add_membership(mngr->cm_handle, grp->ag_group);
00269                 if (err < 0)
00270                         goto errout_free_cache;
00271         }
00272 
00273         err = nl_cache_refill(mngr->cm_handle, cache);
00274         if (err < 0)
00275                 goto errout_drop_membership;
00276 
00277         mngr->cm_assocs[i].ca_cache = cache;
00278         mngr->cm_assocs[i].ca_change = cb;
00279 
00280         if (mngr->cm_flags & NL_AUTO_PROVIDE)
00281                 nl_cache_mngt_provide(cache);
00282 
00283         NL_DBG(1, "Added cache %p <%s> to cache manager %p\n",
00284                cache, nl_cache_name(cache), mngr);
00285 
00286         return cache;
00287 
00288 errout_drop_membership:
00289         for (grp = ops->co_groups; grp->ag_group; grp++)
00290                 nl_socket_drop_membership(mngr->cm_handle, grp->ag_group);
00291 errout_free_cache:
00292         nl_cache_free(cache);
00293 
00294         return NULL;
00295 }

int nl_cache_mngr_get_fd ( struct nl_cache_mngr *  mngr  ) 
Parameters:
mngr Cache 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.

00306 {
00307         return nl_socket_get_fd(mngr->cm_handle);
00308 }

int nl_cache_mngr_poll ( struct nl_cache_mngr *  mngr,
int  timeout 
)
Parameters:
mngr Cache Manager
timeout Upper 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().

00326 {
00327         int ret;
00328         struct pollfd fds = {
00329                 .fd = nl_socket_get_fd(mngr->cm_handle),
00330                 .events = POLLIN,
00331         };
00332 
00333         NL_DBG(3, "Cache manager %p, poll() fd %d\n", mngr, fds.fd);
00334         ret = poll(&fds, 1, timeout);
00335         NL_DBG(3, "Cache manager %p, poll() returned %d\n", mngr, ret);
00336         if (ret < 0)
00337                 return nl_errno(errno);
00338 
00339         if (ret == 0)
00340                 return 0;
00341 
00342         return nl_cache_mngr_data_ready(mngr);
00343 }

int nl_cache_mngr_data_ready ( struct nl_cache_mngr *  mngr  ) 
Parameters:
mngr Cache 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().

00357 {
00358         int err;
00359 
00360         err = nl_recvmsgs_default(mngr->cm_handle);
00361         if (err < 0)
00362                 return err;
00363 
00364         return 1;
00365 }

void nl_cache_mngr_free ( struct nl_cache_mngr *  mngr  ) 
Parameters:
mngr Cache 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().

00374 {
00375         if (!mngr)
00376                 return;
00377 
00378         if (mngr->cm_handle) {
00379                 nl_close(mngr->cm_handle);
00380                 nl_handle_destroy(mngr->cm_handle);
00381         }
00382 
00383         free(mngr->cm_assocs);
00384         free(mngr);
00385 
00386         NL_DBG(1, "Cache manager %p freed\n", mngr);
00387 }


Generated on 30 Oct 2009 for libnl by  doxygen 1.6.1