libnl 1.1
Functions
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:
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().

{
        struct nl_cache_mngr *mngr;

        if (handle == NULL)
                BUG();

        mngr = calloc(1, sizeof(*mngr));
        if (!mngr)
                goto enomem;

        mngr->cm_handle = handle;
        mngr->cm_nassocs = 32;
        mngr->cm_protocol = protocol;
        mngr->cm_flags = flags;
        mngr->cm_assocs = calloc(mngr->cm_nassocs,
                                 sizeof(struct nl_cache_assoc));
        if (!mngr->cm_assocs)
                goto enomem;


        nl_socket_modify_cb(mngr->cm_handle, NL_CB_VALID, NL_CB_CUSTOM,
                            event_input, mngr);

        /* Required to receive async event notifications */
        nl_disable_sequence_check(mngr->cm_handle);

        if (nl_connect(mngr->cm_handle, protocol) < 0)
                goto errout;

        if (nl_socket_set_nonblocking(mngr->cm_handle) < 0)
                goto errout;

        NL_DBG(1, "Allocated cache manager %p, protocol %d, %d caches\n",
               mngr, protocol, mngr->cm_nassocs);

        return mngr;

enomem:
        nl_errno(ENOMEM);
errout:
        nl_cache_mngr_free(mngr);
        return NULL;
}
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().

{
        struct nl_cache_ops *ops;
        struct nl_cache *cache;
        struct nl_af_group *grp;
        int err, i;

        ops = nl_cache_ops_lookup(name);
        if (!ops) {
                nl_error(ENOENT, "Unknown cache type");
                return NULL;
        }

        if (ops->co_protocol != mngr->cm_protocol) {
                nl_error(EINVAL, "Netlink protocol mismatch");
                return NULL;
        }

        if (ops->co_groups == NULL) {
                nl_error(EOPNOTSUPP, NULL);
                return NULL;
        }

        for (i = 0; i < mngr->cm_nassocs; i++) {
                if (mngr->cm_assocs[i].ca_cache &&
                    mngr->cm_assocs[i].ca_cache->c_ops == ops) {
                        nl_error(EEXIST, "Cache of this type already managed");
                        return NULL;
                }
        }

retry:
        for (i = 0; i < mngr->cm_nassocs; i++)
                if (!mngr->cm_assocs[i].ca_cache)
                        break;

        if (i >= mngr->cm_nassocs) {
                mngr->cm_nassocs += 16;
                mngr->cm_assocs = realloc(mngr->cm_assocs,
                                          mngr->cm_nassocs *
                                          sizeof(struct nl_cache_assoc));
                if (mngr->cm_assocs == NULL) {
                        nl_errno(ENOMEM);
                        return NULL;
                } else {
                        NL_DBG(1, "Increased capacity of cache manager %p " \
                                  "to %d\n", mngr, mngr->cm_nassocs);
                        goto retry;
                }
        }

        cache = nl_cache_alloc(ops);
        if (!cache) {
                nl_errno(ENOMEM);
                return NULL;
        }

        for (grp = ops->co_groups; grp->ag_group; grp++) {
                err = nl_socket_add_membership(mngr->cm_handle, grp->ag_group);
                if (err < 0)
                        goto errout_free_cache;
        }

        err = nl_cache_refill(mngr->cm_handle, cache);
        if (err < 0)
                goto errout_drop_membership;

        mngr->cm_assocs[i].ca_cache = cache;
        mngr->cm_assocs[i].ca_change = cb;

        if (mngr->cm_flags & NL_AUTO_PROVIDE)
                nl_cache_mngt_provide(cache);

        NL_DBG(1, "Added cache %p <%s> to cache manager %p\n",
               cache, nl_cache_name(cache), mngr);

        return cache;

errout_drop_membership:
        for (grp = ops->co_groups; grp->ag_group; grp++)
                nl_socket_drop_membership(mngr->cm_handle, grp->ag_group);
errout_free_cache:
        nl_cache_free(cache);

        return NULL;
}
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.

{
        return nl_socket_get_fd(mngr->cm_handle);
}
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().

{
        int ret;
        struct pollfd fds = {
                .fd = nl_socket_get_fd(mngr->cm_handle),
                .events = POLLIN,
        };

        NL_DBG(3, "Cache manager %p, poll() fd %d\n", mngr, fds.fd);
        ret = poll(&fds, 1, timeout);
        NL_DBG(3, "Cache manager %p, poll() returned %d\n", mngr, ret);
        if (ret < 0)
                return nl_errno(errno);

        if (ret == 0)
                return 0;

        return nl_cache_mngr_data_ready(mngr);
}
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().

{
        int err;

        err = nl_recvmsgs_default(mngr->cm_handle);
        if (err < 0)
                return err;

        return 1;
}
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().

{
        if (!mngr)
                return;

        if (mngr->cm_handle) {
                nl_close(mngr->cm_handle);
                nl_handle_destroy(mngr->cm_handle);
        }

        free(mngr->cm_assocs);
        free(mngr);

        NL_DBG(1, "Cache manager %p freed\n", mngr);
}