cls.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  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-2013 Thomas Graf <tgraf@suug.ch>
  10. */
  11. /**
  12. * @ingroup tc
  13. * @defgroup cls Classifiers
  14. * @{
  15. */
  16. #include <netlink-private/netlink.h>
  17. #include <netlink-private/tc.h>
  18. #include <netlink/netlink.h>
  19. #include <netlink/utils.h>
  20. #include <netlink-private/route/tc-api.h>
  21. #include <netlink/route/classifier.h>
  22. #include <netlink/route/link.h>
  23. /** @cond SKIP */
  24. #define CLS_ATTR_PRIO (TCA_ATTR_MAX << 1)
  25. #define CLS_ATTR_PROTOCOL (TCA_ATTR_MAX << 2)
  26. /** @endcond */
  27. static struct nl_object_ops cls_obj_ops;
  28. static struct nl_cache_ops rtnl_cls_ops;
  29. static int cls_build(struct rtnl_cls *cls, int type, int flags,
  30. struct nl_msg **result)
  31. {
  32. int err, prio, proto;
  33. struct tcmsg *tchdr;
  34. uint32_t required = TCA_ATTR_IFINDEX;
  35. if ((cls->ce_mask & required) != required) {
  36. APPBUG("ifindex must be specified");
  37. return -NLE_MISSING_ATTR;
  38. }
  39. err = rtnl_tc_msg_build(TC_CAST(cls), type, flags, result);
  40. if (err < 0)
  41. return err;
  42. tchdr = nlmsg_data(nlmsg_hdr(*result));
  43. prio = rtnl_cls_get_prio(cls);
  44. proto = rtnl_cls_get_protocol(cls);
  45. tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto));
  46. return 0;
  47. }
  48. /**
  49. * @name Allocation/Freeing
  50. * @{
  51. */
  52. struct rtnl_cls *rtnl_cls_alloc(void)
  53. {
  54. struct rtnl_tc *tc;
  55. tc = TC_CAST(nl_object_alloc(&cls_obj_ops));
  56. if (tc)
  57. tc->tc_type = RTNL_TC_TYPE_CLS;
  58. return (struct rtnl_cls *) tc;
  59. }
  60. void rtnl_cls_put(struct rtnl_cls *cls)
  61. {
  62. nl_object_put((struct nl_object *) cls);
  63. }
  64. /** @} */
  65. /**
  66. * @name Attributes
  67. * @{
  68. */
  69. void rtnl_cls_set_prio(struct rtnl_cls *cls, uint16_t prio)
  70. {
  71. cls->c_prio = prio;
  72. cls->ce_mask |= CLS_ATTR_PRIO;
  73. }
  74. uint16_t rtnl_cls_get_prio(struct rtnl_cls *cls)
  75. {
  76. if (cls->ce_mask & CLS_ATTR_PRIO)
  77. return cls->c_prio;
  78. else
  79. return 0;
  80. }
  81. void rtnl_cls_set_protocol(struct rtnl_cls *cls, uint16_t protocol)
  82. {
  83. cls->c_protocol = protocol;
  84. cls->ce_mask |= CLS_ATTR_PROTOCOL;
  85. }
  86. uint16_t rtnl_cls_get_protocol(struct rtnl_cls *cls)
  87. {
  88. if (cls->ce_mask & CLS_ATTR_PROTOCOL)
  89. return cls->c_protocol;
  90. else
  91. return ETH_P_ALL;
  92. }
  93. /** @} */
  94. /**
  95. * @name Addition/Modification/Deletion
  96. * @{
  97. */
  98. /**
  99. * Build a netlink message requesting the addition of a classifier
  100. * @arg cls Classifier to add
  101. * @arg flags Additional netlink message flags
  102. * @arg result Pointer to store resulting netlink message
  103. *
  104. * The behaviour of this function is identical to rtnl_cls_add() with
  105. * the exception that it will not send the message but return it int the
  106. * provided return pointer instead.
  107. *
  108. * @see rtnl_cls_add()
  109. *
  110. * @return 0 on success or a negative error code.
  111. */
  112. int rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags,
  113. struct nl_msg **result)
  114. {
  115. if (!(flags & NLM_F_CREATE) && !(cls->ce_mask & CLS_ATTR_PRIO)) {
  116. APPBUG("prio must be specified if not a new classifier");
  117. return -NLE_MISSING_ATTR;
  118. }
  119. return cls_build(cls, RTM_NEWTFILTER, flags, result);
  120. }
  121. /**
  122. * Add/Update classifier
  123. * @arg sk Netlink socket
  124. * @arg cls Classifier to add/update
  125. * @arg flags Additional netlink message flags
  126. *
  127. * Builds a \c RTM_NEWTFILTER netlink message requesting the addition
  128. * of a new classifier and sends the message to the kernel. The
  129. * configuration of the classifier is derived from the attributes of
  130. * the specified traffic class.
  131. *
  132. * The following flags may be specified:
  133. * - \c NLM_F_CREATE: Create classifier if it does not exist,
  134. * otherwise -NLE_OBJ_NOTFOUND is returned.
  135. * - \c NLM_F_EXCL: Return -NLE_EXISTS if a classifier with
  136. * matching handle exists already.
  137. *
  138. * Existing classifiers with matching handles will be updated, unless
  139. * the flag \c NLM_F_EXCL is specified. If no matching classifier
  140. * exists, it will be created if the flag \c NLM_F_CREATE is set,
  141. * otherwise the error -NLE_OBJ_NOTFOUND is returned.
  142. *
  143. * If the parent qdisc does not support classes, the error
  144. * \c NLE_OPNOTSUPP is returned.
  145. *
  146. * After sending, the function will wait for the ACK or an eventual
  147. * error message to be received and will therefore block until the
  148. * operation has been completed.
  149. *
  150. * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
  151. * this function to return immediately after sending. In this case,
  152. * it is the responsibility of the caller to handle any error
  153. * messages returned.
  154. *
  155. * @return 0 on success or a negative error code.
  156. */
  157. int rtnl_cls_add(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
  158. {
  159. struct nl_msg *msg;
  160. int err;
  161. if ((err = rtnl_cls_build_add_request(cls, flags, &msg)) < 0)
  162. return err;
  163. return nl_send_sync(sk, msg);
  164. }
  165. /**
  166. * Build a netlink message to change classifier attributes
  167. * @arg cls classifier to change
  168. * @arg flags additional netlink message flags
  169. * @arg result Pointer to store resulting message.
  170. *
  171. * Builds a new netlink message requesting a change of a neigh
  172. * attributes. The netlink message header isn't fully equipped with
  173. * all relevant fields and must thus be sent out via nl_send_auto_complete()
  174. * or supplemented as needed.
  175. *
  176. * @return 0 on success or a negative error code.
  177. */
  178. int rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags,
  179. struct nl_msg **result)
  180. {
  181. return cls_build(cls, RTM_NEWTFILTER, NLM_F_REPLACE | flags, result);
  182. }
  183. /**
  184. * Change a classifier
  185. * @arg sk Netlink socket.
  186. * @arg cls classifier to change
  187. * @arg flags additional netlink message flags
  188. *
  189. * Builds a netlink message by calling rtnl_cls_build_change_request(),
  190. * sends the request to the kernel and waits for the next ACK to be
  191. * received and thus blocks until the request has been processed.
  192. *
  193. * @return 0 on sucess or a negative error if an error occured.
  194. */
  195. int rtnl_cls_change(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
  196. {
  197. struct nl_msg *msg;
  198. int err;
  199. if ((err = rtnl_cls_build_change_request(cls, flags, &msg)) < 0)
  200. return err;
  201. return nl_send_sync(sk, msg);
  202. }
  203. /**
  204. * Build netlink message requesting the deletion of a classifier
  205. * @arg cls Classifier to delete
  206. * @arg flags Additional netlink message flags
  207. * @arg result Pointer to store resulting netlink message
  208. *
  209. * The behaviour of this function is identical to rtnl_cls_delete() with
  210. * the exception that it will not send the message but return it in the
  211. * provided return pointer instead.
  212. *
  213. * @see rtnl_cls_delete()
  214. *
  215. * @return 0 on success or a negative error code.
  216. */
  217. int rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags,
  218. struct nl_msg **result)
  219. {
  220. uint32_t required = CLS_ATTR_PRIO;
  221. if ((cls->ce_mask & required) != required) {
  222. APPBUG("prio must be specified");
  223. return -NLE_MISSING_ATTR;
  224. }
  225. return cls_build(cls, RTM_DELTFILTER, flags, result);
  226. }
  227. /**
  228. * Delete classifier
  229. * @arg sk Netlink socket
  230. * @arg cls Classifier to delete
  231. * @arg flags Additional netlink message flags
  232. *
  233. * Builds a \c RTM_DELTFILTER netlink message requesting the deletion
  234. * of a classifier and sends the message to the kernel.
  235. *
  236. * The message is constructed out of the following attributes:
  237. * - \c ifindex (required)
  238. * - \c prio (required)
  239. * - \c protocol (required)
  240. * - \c handle (required)
  241. * - \c parent (optional, if not specified parent equals root-qdisc)
  242. * - \c kind (optional, must match if provided)
  243. *
  244. * All other classifier attributes including all class type specific
  245. * attributes are ignored.
  246. *
  247. * After sending, the function will wait for the ACK or an eventual
  248. * error message to be received and will therefore block until the
  249. * operation has been completed.
  250. *
  251. * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
  252. * this function to return immediately after sending. In this case,
  253. * it is the responsibility of the caller to handle any error
  254. * messages returned.
  255. *
  256. * @return 0 on success or a negative error code.
  257. */
  258. int rtnl_cls_delete(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
  259. {
  260. struct nl_msg *msg;
  261. int err;
  262. if ((err = rtnl_cls_build_delete_request(cls, flags, &msg)) < 0)
  263. return err;
  264. return nl_send_sync(sk, msg);
  265. }
  266. /** @} */
  267. /**
  268. * @name Cache Related Functions
  269. * @{
  270. */
  271. /**
  272. * Allocate a cache and fill it with all configured classifiers
  273. * @arg sk Netlink socket
  274. * @arg ifindex Interface index of the network device
  275. * @arg parent Parent qdisc/traffic class class
  276. * @arg result Pointer to store the created cache
  277. *
  278. * Allocates a new classifier cache and fills it with a list of all
  279. * configured classifier attached to the specified parent qdisc/traffic
  280. * class on the specified network device. Release the cache with
  281. * nl_cache_free().
  282. *
  283. * @return 0 on success or a negative error code.
  284. */
  285. int rtnl_cls_alloc_cache(struct nl_sock *sk, int ifindex, uint32_t parent, struct nl_cache **result)
  286. {
  287. struct nl_cache * cache;
  288. int err;
  289. if (!(cache = nl_cache_alloc(&rtnl_cls_ops)))
  290. return -NLE_NOMEM;
  291. cache->c_iarg1 = ifindex;
  292. cache->c_iarg2 = parent;
  293. if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
  294. nl_cache_free(cache);
  295. return err;
  296. }
  297. *result = cache;
  298. return 0;
  299. }
  300. /** @} */
  301. static void cls_dump_line(struct rtnl_tc *tc, struct nl_dump_params *p)
  302. {
  303. struct rtnl_cls *cls = (struct rtnl_cls *) tc;
  304. char buf[32];
  305. nl_dump(p, " prio %u protocol %s", cls->c_prio,
  306. nl_ether_proto2str(cls->c_protocol, buf, sizeof(buf)));
  307. }
  308. static int cls_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
  309. struct nlmsghdr *nlh, struct nl_parser_param *pp)
  310. {
  311. struct rtnl_cls *cls;
  312. int err;
  313. if (!(cls = rtnl_cls_alloc()))
  314. return -NLE_NOMEM;
  315. if ((err = rtnl_tc_msg_parse(nlh, TC_CAST(cls))) < 0)
  316. goto errout;
  317. cls->c_prio = TC_H_MAJ(cls->c_info) >> 16;
  318. if (cls->c_prio)
  319. cls->ce_mask |= CLS_ATTR_PRIO;
  320. cls->c_protocol = ntohs(TC_H_MIN(cls->c_info));
  321. if (cls->c_protocol)
  322. cls->ce_mask |= CLS_ATTR_PROTOCOL;
  323. err = pp->pp_cb(OBJ_CAST(cls), pp);
  324. errout:
  325. rtnl_cls_put(cls);
  326. return err;
  327. }
  328. static int cls_request_update(struct nl_cache *cache, struct nl_sock *sk)
  329. {
  330. struct tcmsg tchdr = {
  331. .tcm_family = AF_UNSPEC,
  332. .tcm_ifindex = cache->c_iarg1,
  333. .tcm_parent = cache->c_iarg2,
  334. };
  335. return nl_send_simple(sk, RTM_GETTFILTER, NLM_F_DUMP, &tchdr,
  336. sizeof(tchdr));
  337. }
  338. static struct rtnl_tc_type_ops cls_ops = {
  339. .tt_type = RTNL_TC_TYPE_CLS,
  340. .tt_dump_prefix = "cls",
  341. .tt_dump = {
  342. [NL_DUMP_LINE] = cls_dump_line,
  343. },
  344. };
  345. static struct nl_cache_ops rtnl_cls_ops = {
  346. .co_name = "route/cls",
  347. .co_hdrsize = sizeof(struct tcmsg),
  348. .co_msgtypes = {
  349. { RTM_NEWTFILTER, NL_ACT_NEW, "new" },
  350. { RTM_DELTFILTER, NL_ACT_DEL, "del" },
  351. { RTM_GETTFILTER, NL_ACT_GET, "get" },
  352. END_OF_MSGTYPES_LIST,
  353. },
  354. .co_protocol = NETLINK_ROUTE,
  355. .co_groups = tc_groups,
  356. .co_request_update = cls_request_update,
  357. .co_msg_parser = cls_msg_parser,
  358. .co_obj_ops = &cls_obj_ops,
  359. };
  360. static struct nl_object_ops cls_obj_ops = {
  361. .oo_name = "route/cls",
  362. .oo_size = sizeof(struct rtnl_cls),
  363. .oo_free_data = rtnl_tc_free_data,
  364. .oo_clone = rtnl_tc_clone,
  365. .oo_dump = {
  366. [NL_DUMP_LINE] = rtnl_tc_dump_line,
  367. [NL_DUMP_DETAILS] = rtnl_tc_dump_details,
  368. [NL_DUMP_STATS] = rtnl_tc_dump_stats,
  369. },
  370. .oo_compare = rtnl_tc_compare,
  371. .oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE),
  372. };
  373. static void __init cls_init(void)
  374. {
  375. rtnl_tc_type_register(&cls_ops);
  376. nl_cache_mngt_register(&rtnl_cls_ops);
  377. }
  378. static void __exit cls_exit(void)
  379. {
  380. nl_cache_mngt_unregister(&rtnl_cls_ops);
  381. rtnl_tc_type_unregister(&cls_ops);
  382. }
  383. /** @} */