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. |
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)--------------+
| +------------+|
| | +------------+| |
<-------|---| ... ||
| | +------------+| |
+-----------------+
| |
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 *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");
// 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, ...); }
nl_cache_mngr_free(mngr);
struct nl_cache_mngr* nl_cache_mngr_alloc | ( | struct nl_handle * | handle, | |
int | protocol, | |||
int | flags | |||
) | [read] |
handle | Netlink socket/handle to be used | |
protocol | Netlink Protocol this manager is used for | |
flags | Flags |
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] |
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.
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 | ) |
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.
int nl_cache_mngr_poll | ( | struct nl_cache_mngr * | mngr, | |
int | timeout | |||
) |
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.
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 | ) |
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.
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 | ) |
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 }