cache_mngr.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. /*
  2. * lib/cache_mngr.c Cache Manager
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation version 2.1
  7. * of the License.
  8. *
  9. * Copyright (c) 2003-2007 Thomas Graf <tgraf@suug.ch>
  10. */
  11. /**
  12. * @ingroup cache_mngt
  13. * @defgroup cache_mngr Manager
  14. * @brief Helps keeping caches up to date.
  15. *
  16. * The purpose of a cache manager is to keep track of caches and
  17. * automatically receive event notifications to keep the caches
  18. * up to date with the kernel state. Each manager has exactly one
  19. * netlink socket assigned which limits the scope of each manager
  20. * to exactly one netlink family. Therefore all caches committed
  21. * to a manager must be part of the same netlink family. Due to the
  22. * nature of a manager, it is not possible to have a cache maintain
  23. * two instances of the same cache type. The socket is subscribed
  24. * to the event notification group of each cache and also put into
  25. * non-blocking mode. Functions exist to poll() on the socket to
  26. * wait for new events to be received.
  27. *
  28. * @code
  29. * App libnl Kernel
  30. * | |
  31. * +-----------------+ [ notification, link change ]
  32. * | | Cache Manager | | [ (IFF_UP | IFF_RUNNING) ]
  33. * | | |
  34. * | | +------------+| | | [ notification, new addr ]
  35. * <-------|---| route/link |<-------(async)--+ [ 10.0.1.1/32 dev eth1 ]
  36. * | | +------------+| | |
  37. * | +------------+| |
  38. * <---|---|---| route/addr |<------|-(async)--------------+
  39. * | +------------+|
  40. * | | +------------+| |
  41. * <-------|---| ... ||
  42. * | | +------------+| |
  43. * +-----------------+
  44. * | |
  45. * @endcode
  46. *
  47. * @par 1) Creating a new cache manager
  48. * @code
  49. * struct nl_cache_mngr *mngr;
  50. *
  51. * // Allocate a new cache manager for RTNETLINK and automatically
  52. * // provide the caches added to the manager.
  53. * mngr = nl_cache_mngr_alloc(NETLINK_ROUTE, NL_AUTO_PROVIDE);
  54. * @endcode
  55. *
  56. * @par 2) Keep track of a cache
  57. * @code
  58. * struct nl_cache *cache;
  59. *
  60. * // Create a new cache for links/interfaces and ask the manager to
  61. * // keep it up to date for us. This will trigger a full dump request
  62. * // to initially fill the cache.
  63. * cache = nl_cache_mngr_add(mngr, "route/link");
  64. * @endcode
  65. *
  66. * @par 3) Make the manager receive updates
  67. * @code
  68. * // Give the manager the ability to receive updates, will call poll()
  69. * // with a timeout of 5 seconds.
  70. * if (nl_cache_mngr_poll(mngr, 5000) > 0) {
  71. * // Manager received at least one update, dump cache?
  72. * nl_cache_dump(cache, ...);
  73. * }
  74. * @endcode
  75. *
  76. * @par 4) Release cache manager
  77. * @code
  78. * nl_cache_mngr_free(mngr);
  79. * @endcode
  80. * @{
  81. */
  82. #include <netlink-local.h>
  83. #include <netlink/netlink.h>
  84. #include <netlink/cache.h>
  85. #include <netlink/utils.h>
  86. static int include_cb(struct nl_object *obj, struct nl_parser_param *p)
  87. {
  88. struct nl_cache_assoc *ca = p->pp_arg;
  89. NL_DBG(2, "Including object %p into cache %p\n", obj, ca->ca_cache);
  90. #ifdef NL_DEBUG
  91. if (nl_debug >= 4)
  92. nl_object_dump(obj, &nl_debug_dp);
  93. #endif
  94. return nl_cache_include(ca->ca_cache, obj, ca->ca_change);
  95. }
  96. static int event_input(struct nl_msg *msg, void *arg)
  97. {
  98. struct nl_cache_mngr *mngr = arg;
  99. int protocol = nlmsg_get_proto(msg);
  100. int type = nlmsg_hdr(msg)->nlmsg_type;
  101. struct nl_cache_ops *ops;
  102. int i, n;
  103. struct nl_parser_param p = {
  104. .pp_cb = include_cb,
  105. };
  106. NL_DBG(2, "Cache manager %p, handling new message %p as event\n",
  107. mngr, msg);
  108. #ifdef NL_DEBUG
  109. if (nl_debug >= 4)
  110. nl_msg_dump(msg, stderr);
  111. #endif
  112. if (mngr->cm_protocol != protocol)
  113. BUG();
  114. for (i = 0; i < mngr->cm_nassocs; i++) {
  115. if (mngr->cm_assocs[i].ca_cache) {
  116. ops = mngr->cm_assocs[i].ca_cache->c_ops;
  117. for (n = 0; ops->co_msgtypes[n].mt_id >= 0; n++)
  118. if (ops->co_msgtypes[n].mt_id == type)
  119. goto found;
  120. }
  121. }
  122. return NL_SKIP;
  123. found:
  124. NL_DBG(2, "Associated message %p to cache %p\n",
  125. msg, mngr->cm_assocs[i].ca_cache);
  126. p.pp_arg = &mngr->cm_assocs[i];
  127. return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p);
  128. }
  129. /**
  130. * Allocate new cache manager
  131. * @arg handle Netlink socket/handle to be used
  132. * @arg protocol Netlink Protocol this manager is used for
  133. * @arg flags Flags
  134. *
  135. * @return Newly allocated cache manager or NULL on failure.
  136. */
  137. struct nl_cache_mngr *nl_cache_mngr_alloc(struct nl_handle *handle,
  138. int protocol, int flags)
  139. {
  140. struct nl_cache_mngr *mngr;
  141. if (handle == NULL)
  142. BUG();
  143. mngr = calloc(1, sizeof(*mngr));
  144. if (!mngr)
  145. goto enomem;
  146. mngr->cm_handle = handle;
  147. mngr->cm_nassocs = 32;
  148. mngr->cm_protocol = protocol;
  149. mngr->cm_flags = flags;
  150. mngr->cm_assocs = calloc(mngr->cm_nassocs,
  151. sizeof(struct nl_cache_assoc));
  152. if (!mngr->cm_assocs)
  153. goto enomem;
  154. nl_socket_modify_cb(mngr->cm_handle, NL_CB_VALID, NL_CB_CUSTOM,
  155. event_input, mngr);
  156. /* Required to receive async event notifications */
  157. nl_disable_sequence_check(mngr->cm_handle);
  158. if (nl_connect(mngr->cm_handle, protocol) < 0)
  159. goto errout;
  160. if (nl_socket_set_nonblocking(mngr->cm_handle) < 0)
  161. goto errout;
  162. NL_DBG(1, "Allocated cache manager %p, protocol %d, %d caches\n",
  163. mngr, protocol, mngr->cm_nassocs);
  164. return mngr;
  165. enomem:
  166. nl_errno(ENOMEM);
  167. errout:
  168. nl_cache_mngr_free(mngr);
  169. return NULL;
  170. }
  171. /**
  172. * Add cache responsibility to cache manager
  173. * @arg mngr Cache manager.
  174. * @arg name Name of cache to keep track of
  175. * @arg cb Function to be called upon changes.
  176. *
  177. * Allocates a new cache of the specified type and adds it to the manager.
  178. * The operation will trigger a full dump request from the kernel to
  179. * initially fill the contents of the cache. The manager will subscribe
  180. * to the notification group of the cache to keep track of any further
  181. * changes.
  182. *
  183. * @return The newly allocated cache or NULL on failure.
  184. */
  185. struct nl_cache *nl_cache_mngr_add(struct nl_cache_mngr *mngr, const char *name,
  186. change_func_t cb)
  187. {
  188. struct nl_cache_ops *ops;
  189. struct nl_cache *cache;
  190. struct nl_af_group *grp;
  191. int err, i;
  192. ops = nl_cache_ops_lookup(name);
  193. if (!ops) {
  194. nl_error(ENOENT, "Unknown cache type");
  195. return NULL;
  196. }
  197. if (ops->co_protocol != mngr->cm_protocol) {
  198. nl_error(EINVAL, "Netlink protocol mismatch");
  199. return NULL;
  200. }
  201. if (ops->co_groups == NULL) {
  202. nl_error(EOPNOTSUPP, NULL);
  203. return NULL;
  204. }
  205. for (i = 0; i < mngr->cm_nassocs; i++) {
  206. if (mngr->cm_assocs[i].ca_cache &&
  207. mngr->cm_assocs[i].ca_cache->c_ops == ops) {
  208. nl_error(EEXIST, "Cache of this type already managed");
  209. return NULL;
  210. }
  211. }
  212. retry:
  213. for (i = 0; i < mngr->cm_nassocs; i++)
  214. if (!mngr->cm_assocs[i].ca_cache)
  215. break;
  216. if (i >= mngr->cm_nassocs) {
  217. mngr->cm_nassocs += 16;
  218. mngr->cm_assocs = realloc(mngr->cm_assocs,
  219. mngr->cm_nassocs *
  220. sizeof(struct nl_cache_assoc));
  221. if (mngr->cm_assocs == NULL) {
  222. nl_errno(ENOMEM);
  223. return NULL;
  224. } else {
  225. NL_DBG(1, "Increased capacity of cache manager %p " \
  226. "to %d\n", mngr, mngr->cm_nassocs);
  227. goto retry;
  228. }
  229. }
  230. cache = nl_cache_alloc(ops);
  231. if (!cache) {
  232. nl_errno(ENOMEM);
  233. return NULL;
  234. }
  235. for (grp = ops->co_groups; grp->ag_group; grp++) {
  236. err = nl_socket_add_membership(mngr->cm_handle, grp->ag_group);
  237. if (err < 0)
  238. goto errout_free_cache;
  239. }
  240. err = nl_cache_refill(mngr->cm_handle, cache);
  241. if (err < 0)
  242. goto errout_drop_membership;
  243. mngr->cm_assocs[i].ca_cache = cache;
  244. mngr->cm_assocs[i].ca_change = cb;
  245. if (mngr->cm_flags & NL_AUTO_PROVIDE)
  246. nl_cache_mngt_provide(cache);
  247. NL_DBG(1, "Added cache %p <%s> to cache manager %p\n",
  248. cache, nl_cache_name(cache), mngr);
  249. return cache;
  250. errout_drop_membership:
  251. for (grp = ops->co_groups; grp->ag_group; grp++)
  252. nl_socket_drop_membership(mngr->cm_handle, grp->ag_group);
  253. errout_free_cache:
  254. nl_cache_free(cache);
  255. return NULL;
  256. }
  257. /**
  258. * Get file descriptor
  259. * @arg mngr Cache Manager
  260. *
  261. * Get the file descriptor of the socket associated to the manager.
  262. * This can be used to change socket options or monitor activity
  263. * using poll()/select().
  264. */
  265. int nl_cache_mngr_get_fd(struct nl_cache_mngr *mngr)
  266. {
  267. return nl_socket_get_fd(mngr->cm_handle);
  268. }
  269. /**
  270. * Check for event notifications
  271. * @arg mngr Cache Manager
  272. * @arg timeout Upper limit poll() will block, in milliseconds.
  273. *
  274. * Causes poll() to be called to check for new event notifications
  275. * being available. Automatically receives and handles available
  276. * notifications.
  277. *
  278. * This functionally is ideally called regularly during an idle
  279. * period.
  280. *
  281. * @return A positive value if at least one update was handled, 0
  282. * for none, or a negative error code.
  283. */
  284. int nl_cache_mngr_poll(struct nl_cache_mngr *mngr, int timeout)
  285. {
  286. int ret;
  287. struct pollfd fds = {
  288. .fd = nl_socket_get_fd(mngr->cm_handle),
  289. .events = POLLIN,
  290. };
  291. NL_DBG(3, "Cache manager %p, poll() fd %d\n", mngr, fds.fd);
  292. ret = poll(&fds, 1, timeout);
  293. NL_DBG(3, "Cache manager %p, poll() returned %d\n", mngr, ret);
  294. if (ret < 0)
  295. return nl_errno(errno);
  296. if (ret == 0)
  297. return 0;
  298. return nl_cache_mngr_data_ready(mngr);
  299. }
  300. /**
  301. * Receive available event notifications
  302. * @arg mngr Cache manager
  303. *
  304. * This function can be called if the socket associated to the manager
  305. * contains updates to be received. This function should not be used
  306. * if nl_cache_mngr_poll() is used.
  307. *
  308. * @return A positive value if at least one update was handled, 0
  309. * for none, or a negative error code.
  310. */
  311. int nl_cache_mngr_data_ready(struct nl_cache_mngr *mngr)
  312. {
  313. int err;
  314. err = nl_recvmsgs_default(mngr->cm_handle);
  315. if (err < 0)
  316. return err;
  317. return 1;
  318. }
  319. /**
  320. * Free cache manager
  321. * @arg mngr Cache manager
  322. *
  323. * Release all resources after usage of a cache manager.
  324. */
  325. void nl_cache_mngr_free(struct nl_cache_mngr *mngr)
  326. {
  327. if (!mngr)
  328. return;
  329. if (mngr->cm_handle) {
  330. nl_close(mngr->cm_handle);
  331. nl_handle_destroy(mngr->cm_handle);
  332. }
  333. free(mngr->cm_assocs);
  334. free(mngr);
  335. NL_DBG(1, "Cache manager %p freed\n", mngr);
  336. }
  337. /** @} */