classifier.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /*
  2. * lib/route/classifier.c Classifier
  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-2006 Thomas Graf <tgraf@suug.ch>
  10. */
  11. /**
  12. * @ingroup tc
  13. * @defgroup cls Classifiers
  14. *
  15. * @par Classifier Identification
  16. * - protocol
  17. * - priority
  18. * - parent
  19. * - interface
  20. * - kind
  21. * - handle
  22. *
  23. * @{
  24. */
  25. #include <netlink-local.h>
  26. #include <netlink-tc.h>
  27. #include <netlink/netlink.h>
  28. #include <netlink/utils.h>
  29. #include <netlink/route/tc.h>
  30. #include <netlink/route/classifier.h>
  31. #include <netlink/route/classifier-modules.h>
  32. #include <netlink/route/link.h>
  33. static struct nl_cache_ops rtnl_cls_ops;
  34. static int cls_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
  35. struct nlmsghdr *nlh, struct nl_parser_param *pp)
  36. {
  37. int err;
  38. struct rtnl_cls *cls;
  39. struct rtnl_cls_ops *cops;
  40. cls = rtnl_cls_alloc();
  41. if (!cls) {
  42. err = nl_errno(ENOMEM);
  43. goto errout;
  44. }
  45. cls->ce_msgtype = nlh->nlmsg_type;
  46. err = tca_msg_parser(nlh, (struct rtnl_tca *) cls);
  47. if (err < 0)
  48. goto errout_free;
  49. cls->c_prio = TC_H_MAJ(cls->c_info) >> 16;
  50. cls->c_protocol = ntohs(TC_H_MIN(cls->c_info));
  51. cops = rtnl_cls_lookup_ops(cls);
  52. if (cops && cops->co_msg_parser) {
  53. err = cops->co_msg_parser(cls);
  54. if (err < 0)
  55. goto errout_free;
  56. }
  57. err = pp->pp_cb((struct nl_object *) cls, pp);
  58. if (err < 0)
  59. goto errout_free;
  60. err = P_ACCEPT;
  61. errout_free:
  62. rtnl_cls_put(cls);
  63. errout:
  64. return err;
  65. }
  66. static int cls_request_update(struct nl_cache *cache, struct nl_handle *handle)
  67. {
  68. struct tcmsg tchdr = {
  69. .tcm_family = AF_UNSPEC,
  70. .tcm_ifindex = cache->c_iarg1,
  71. .tcm_parent = cache->c_iarg2,
  72. };
  73. return nl_send_simple(handle, RTM_GETTFILTER, NLM_F_DUMP, &tchdr,
  74. sizeof(tchdr));
  75. }
  76. static struct nl_msg *cls_build(struct rtnl_cls *cls, int type, int flags)
  77. {
  78. struct nl_msg *msg;
  79. struct rtnl_cls_ops *cops;
  80. int err, prio, proto;
  81. struct tcmsg *tchdr;
  82. msg = tca_build_msg((struct rtnl_tca *) cls, type, flags);
  83. if (!msg)
  84. goto errout;
  85. tchdr = nlmsg_data(nlmsg_hdr(msg));
  86. prio = rtnl_cls_get_prio(cls);
  87. proto = rtnl_cls_get_protocol(cls);
  88. tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto)),
  89. cops = rtnl_cls_lookup_ops(cls);
  90. if (cops && cops->co_get_opts) {
  91. struct nl_msg *opts;
  92. opts = cops->co_get_opts(cls);
  93. if (opts) {
  94. err = nla_put_nested(msg, TCA_OPTIONS, opts);
  95. nlmsg_free(opts);
  96. if (err < 0)
  97. goto errout;
  98. }
  99. }
  100. return msg;
  101. errout:
  102. nlmsg_free(msg);
  103. return NULL;
  104. }
  105. /**
  106. * @name Classifier Addition/Modification/Deletion
  107. * @{
  108. */
  109. /**
  110. * Build a netlink message to add a new classifier
  111. * @arg cls classifier to add
  112. * @arg flags additional netlink message flags
  113. *
  114. * Builds a new netlink message requesting an addition of a classifier
  115. * The netlink message header isn't fully equipped with all relevant
  116. * fields and must be sent out via nl_send_auto_complete() or
  117. * supplemented as needed. \a classifier must contain the attributes of
  118. * the new classifier set via \c rtnl_cls_set_* functions. \a opts
  119. * may point to the clsasifier specific options.
  120. *
  121. * @return New netlink message
  122. */
  123. struct nl_msg * rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags)
  124. {
  125. return cls_build(cls, RTM_NEWTFILTER, NLM_F_CREATE | flags);
  126. }
  127. /**
  128. * Add a new classifier
  129. * @arg handle netlink handle
  130. * @arg cls classifier to add
  131. * @arg flags additional netlink message flags
  132. *
  133. * Builds a netlink message by calling rtnl_cls_build_add_request(),
  134. * sends the request to the kernel and waits for the next ACK to be
  135. * received and thus blocks until the request has been processed.
  136. *
  137. * @return 0 on sucess or a negative error if an error occured.
  138. */
  139. int rtnl_cls_add(struct nl_handle *handle, struct rtnl_cls *cls, int flags)
  140. {
  141. int err;
  142. struct nl_msg *msg;
  143. msg = rtnl_cls_build_add_request(cls, flags);
  144. if (!msg)
  145. return nl_errno(ENOMEM);
  146. err = nl_send_auto_complete(handle, msg);
  147. nlmsg_free(msg);
  148. if (err < 0)
  149. return err;
  150. return nl_wait_for_ack(handle);
  151. }
  152. /**
  153. * Build a netlink message to change classifier attributes
  154. * @arg cls classifier to change
  155. * @arg flags additional netlink message flags
  156. *
  157. * Builds a new netlink message requesting a change of a neigh
  158. * attributes. The netlink message header isn't fully equipped with
  159. * all relevant fields and must thus be sent out via nl_send_auto_complete()
  160. * or supplemented as needed.
  161. *
  162. * @return The netlink message
  163. */
  164. struct nl_msg *rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags)
  165. {
  166. return cls_build(cls, RTM_NEWTFILTER, NLM_F_REPLACE | flags);
  167. }
  168. /**
  169. * Change a classifier
  170. * @arg handle netlink handle
  171. * @arg cls classifier to change
  172. * @arg flags additional netlink message flags
  173. *
  174. * Builds a netlink message by calling rtnl_cls_build_change_request(),
  175. * sends the request to the kernel and waits for the next ACK to be
  176. * received and thus blocks until the request has been processed.
  177. *
  178. * @return 0 on sucess or a negative error if an error occured.
  179. */
  180. int rtnl_cls_change(struct nl_handle *handle, struct rtnl_cls *cls,
  181. int flags)
  182. {
  183. int err;
  184. struct nl_msg *msg;
  185. msg = rtnl_cls_build_change_request(cls, flags);
  186. if (!msg)
  187. return nl_errno(ENOMEM);
  188. err = nl_send_auto_complete(handle, msg);
  189. nlmsg_free(msg);
  190. if (err < 0)
  191. return err;
  192. return nl_wait_for_ack(handle);
  193. }
  194. /**
  195. * Build a netlink request message to delete a classifier
  196. * @arg cls classifier to delete
  197. * @arg flags additional netlink message flags
  198. *
  199. * Builds a new netlink message requesting a deletion of a classifier.
  200. * The netlink message header isn't fully equipped with all relevant
  201. * fields and must thus be sent out via nl_send_auto_complete()
  202. * or supplemented as needed.
  203. *
  204. * @return New netlink message
  205. */
  206. struct nl_msg *rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags)
  207. {
  208. return cls_build(cls, RTM_DELTFILTER, flags);
  209. }
  210. /**
  211. * Delete a classifier
  212. * @arg handle netlink handle
  213. * @arg cls classifier to delete
  214. * @arg flags additional netlink message flags
  215. *
  216. * Builds a netlink message by calling rtnl_cls_build_delete_request(),
  217. * sends the request to the kernel and waits for the next ACK to be
  218. * received and thus blocks until the request has been processed.
  219. *
  220. * @return 0 on sucess or a negative error if an error occured.
  221. */
  222. int rtnl_cls_delete(struct nl_handle *handle, struct rtnl_cls *cls, int flags)
  223. {
  224. int err;
  225. struct nl_msg *msg;
  226. msg = rtnl_cls_build_delete_request(cls, flags);
  227. if (!msg)
  228. return nl_errno(ENOMEM);
  229. err = nl_send_auto_complete(handle, msg);
  230. nlmsg_free(msg);
  231. if (err < 0)
  232. return err;
  233. return nl_wait_for_ack(handle);
  234. }
  235. /** @} */
  236. /**
  237. * @name Cache Management
  238. * @{
  239. */
  240. /**
  241. * Build a classifier cache including all classifiers attached to the
  242. * specified class/qdisc on eht specified interface.
  243. * @arg handle netlink handle
  244. * @arg ifindex interface index of the link the classes are
  245. * attached to.
  246. * @arg parent parent qdisc/class
  247. *
  248. * Allocates a new cache, initializes it properly and updates it to
  249. * include all classes attached to the specified interface.
  250. *
  251. * @note The caller is responsible for destroying and freeing the
  252. * cache after using it.
  253. * @return The cache or NULL if an error has occured.
  254. */
  255. struct nl_cache *rtnl_cls_alloc_cache(struct nl_handle *handle,
  256. int ifindex, uint32_t parent)
  257. {
  258. struct nl_cache * cache;
  259. cache = nl_cache_alloc(&rtnl_cls_ops);
  260. if (cache == NULL)
  261. return NULL;
  262. cache->c_iarg1 = ifindex;
  263. cache->c_iarg2 = parent;
  264. if (handle && nl_cache_refill(handle, cache) < 0) {
  265. nl_cache_free(cache);
  266. return NULL;
  267. }
  268. return cache;
  269. }
  270. /** @} */
  271. static struct nl_cache_ops rtnl_cls_ops = {
  272. .co_name = "route/cls",
  273. .co_hdrsize = sizeof(struct tcmsg),
  274. .co_msgtypes = {
  275. { RTM_NEWTFILTER, NL_ACT_NEW, "new" },
  276. { RTM_DELTFILTER, NL_ACT_DEL, "del" },
  277. { RTM_GETTFILTER, NL_ACT_GET, "get" },
  278. END_OF_MSGTYPES_LIST,
  279. },
  280. .co_protocol = NETLINK_ROUTE,
  281. .co_request_update = cls_request_update,
  282. .co_msg_parser = cls_msg_parser,
  283. .co_obj_ops = &cls_obj_ops,
  284. };
  285. static void __init cls_init(void)
  286. {
  287. nl_cache_mngt_register(&rtnl_cls_ops);
  288. }
  289. static void __exit cls_exit(void)
  290. {
  291. nl_cache_mngt_unregister(&rtnl_cls_ops);
  292. }
  293. /** @} */