u32.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. /*
  2. * lib/route/cls/u32.c u32 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. * Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard@siemens.com>
  11. * Copyright (c) 2005-2006 Siemens AG Oesterreich
  12. */
  13. /**
  14. * @ingroup cls_api
  15. * @defgroup u32 Universal 32-bit Classifier
  16. *
  17. * @{
  18. */
  19. #include <netlink-local.h>
  20. #include <netlink-tc.h>
  21. #include <netlink/netlink.h>
  22. #include <netlink/attr.h>
  23. #include <netlink/utils.h>
  24. #include <netlink/route/tc.h>
  25. #include <netlink/route/classifier.h>
  26. #include <netlink/route/classifier-modules.h>
  27. #include <netlink/route/cls/u32.h>
  28. /** @cond SKIP */
  29. #define U32_ATTR_DIVISOR 0x001
  30. #define U32_ATTR_HASH 0x002
  31. #define U32_ATTR_CLASSID 0x004
  32. #define U32_ATTR_LINK 0x008
  33. #define U32_ATTR_PCNT 0x010
  34. #define U32_ATTR_SELECTOR 0x020
  35. #define U32_ATTR_ACTION 0x040
  36. #define U32_ATTR_POLICE 0x080
  37. #define U32_ATTR_INDEV 0x100
  38. /** @endcond */
  39. static inline struct rtnl_u32 *u32_cls(struct rtnl_cls *cls)
  40. {
  41. return (struct rtnl_u32 *) cls->c_subdata;
  42. }
  43. static inline struct rtnl_u32 *u32_alloc(struct rtnl_cls *cls)
  44. {
  45. if (!cls->c_subdata)
  46. cls->c_subdata = calloc(1, sizeof(struct rtnl_u32));
  47. return u32_cls(cls);
  48. }
  49. static inline struct tc_u32_sel *u32_selector(struct rtnl_u32 *u)
  50. {
  51. return (struct tc_u32_sel *) u->cu_selector->d_data;
  52. }
  53. static inline struct tc_u32_sel *u32_selector_alloc(struct rtnl_u32 *u)
  54. {
  55. if (!u->cu_selector)
  56. u->cu_selector = nl_data_alloc(NULL, sizeof(struct tc_u32_sel));
  57. return u32_selector(u);
  58. }
  59. static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
  60. [TCA_U32_DIVISOR] = { .type = NLA_U32 },
  61. [TCA_U32_HASH] = { .type = NLA_U32 },
  62. [TCA_U32_CLASSID] = { .type = NLA_U32 },
  63. [TCA_U32_LINK] = { .type = NLA_U32 },
  64. [TCA_U32_INDEV] = { .type = NLA_STRING,
  65. .maxlen = IFNAMSIZ },
  66. [TCA_U32_SEL] = { .minlen = sizeof(struct tc_u32_sel) },
  67. [TCA_U32_PCNT] = { .minlen = sizeof(struct tc_u32_pcnt) },
  68. };
  69. static int u32_msg_parser(struct rtnl_cls *cls)
  70. {
  71. int err;
  72. struct nlattr *tb[TCA_U32_MAX + 1];
  73. struct rtnl_u32 *u;
  74. err = tca_parse(tb, TCA_U32_MAX, (struct rtnl_tca *) cls, u32_policy);
  75. if (err < 0)
  76. return err;
  77. u = u32_alloc(cls);
  78. if (!u)
  79. goto errout_nomem;
  80. if (tb[TCA_U32_DIVISOR]) {
  81. u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]);
  82. u->cu_mask |= U32_ATTR_DIVISOR;
  83. }
  84. if (tb[TCA_U32_SEL]) {
  85. u->cu_selector = nla_get_data(tb[TCA_U32_SEL]);
  86. if (!u->cu_selector)
  87. goto errout_nomem;
  88. u->cu_mask |= U32_ATTR_SELECTOR;
  89. }
  90. if (tb[TCA_U32_HASH]) {
  91. u->cu_hash = nla_get_u32(tb[TCA_U32_HASH]);
  92. u->cu_mask |= U32_ATTR_HASH;
  93. }
  94. if (tb[TCA_U32_CLASSID]) {
  95. u->cu_classid = nla_get_u32(tb[TCA_U32_CLASSID]);
  96. u->cu_mask |= U32_ATTR_CLASSID;
  97. }
  98. if (tb[TCA_U32_LINK]) {
  99. u->cu_link = nla_get_u32(tb[TCA_U32_LINK]);
  100. u->cu_mask |= U32_ATTR_LINK;
  101. }
  102. if (tb[TCA_U32_ACT]) {
  103. u->cu_act = nla_get_data(tb[TCA_U32_ACT]);
  104. if (!u->cu_act)
  105. goto errout_nomem;
  106. u->cu_mask |= U32_ATTR_ACTION;
  107. }
  108. if (tb[TCA_U32_POLICE]) {
  109. u->cu_police = nla_get_data(tb[TCA_U32_POLICE]);
  110. if (!u->cu_police)
  111. goto errout_nomem;
  112. u->cu_mask |= U32_ATTR_POLICE;
  113. }
  114. if (tb[TCA_U32_PCNT]) {
  115. struct tc_u32_sel *sel;
  116. int pcnt_size;
  117. if (!tb[TCA_U32_SEL]) {
  118. err = nl_error(EINVAL, "Missing TCA_U32_SEL required "
  119. "for TCA_U32_PCNT");
  120. goto errout;
  121. }
  122. sel = u->cu_selector->d_data;
  123. pcnt_size = sizeof(struct tc_u32_pcnt) +
  124. (sel->nkeys * sizeof(uint64_t));
  125. if (nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
  126. err = nl_error(EINVAL, "Invalid size for TCA_U32_PCNT");
  127. goto errout;
  128. }
  129. u->cu_pcnt = nla_get_data(tb[TCA_U32_PCNT]);
  130. if (!u->cu_pcnt)
  131. goto errout_nomem;
  132. u->cu_mask |= U32_ATTR_PCNT;
  133. }
  134. if (tb[TCA_U32_INDEV]) {
  135. nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ);
  136. u->cu_mask |= U32_ATTR_INDEV;
  137. }
  138. return 0;
  139. errout_nomem:
  140. err = nl_errno(ENOMEM);
  141. errout:
  142. return err;
  143. }
  144. static void u32_free_data(struct rtnl_cls *cls)
  145. {
  146. struct rtnl_u32 *u = u32_cls(cls);
  147. if (!u)
  148. return;
  149. nl_data_free(u->cu_selector);
  150. nl_data_free(u->cu_act);
  151. nl_data_free(u->cu_police);
  152. nl_data_free(u->cu_pcnt);
  153. free(cls->c_subdata);
  154. }
  155. static int u32_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src)
  156. {
  157. struct rtnl_u32 *dst, *src = u32_cls(_src);
  158. if (!src)
  159. return 0;
  160. dst = u32_alloc(_dst);
  161. if (!dst)
  162. return nl_errno(ENOMEM);
  163. if (src->cu_selector)
  164. if (!(dst->cu_selector = nl_data_clone(src->cu_selector)))
  165. goto errout;
  166. if (src->cu_act)
  167. if (!(dst->cu_act = nl_data_clone(src->cu_act)))
  168. goto errout;
  169. if (src->cu_police)
  170. if (!(dst->cu_police = nl_data_clone(src->cu_police)))
  171. goto errout;
  172. if (src->cu_pcnt)
  173. if (!(dst->cu_pcnt = nl_data_clone(src->cu_pcnt)))
  174. goto errout;
  175. return 0;
  176. errout:
  177. return nl_get_errno();
  178. }
  179. static int u32_dump_brief(struct rtnl_cls *cls, struct nl_dump_params *p,
  180. int line)
  181. {
  182. struct rtnl_u32 *u = u32_cls(cls);
  183. char buf[32];
  184. if (!u)
  185. goto ignore;
  186. if (u->cu_mask & U32_ATTR_DIVISOR)
  187. dp_dump(p, " divisor %u", u->cu_divisor);
  188. else if (u->cu_mask & U32_ATTR_CLASSID)
  189. dp_dump(p, " target %s",
  190. rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf)));
  191. ignore:
  192. return line;
  193. }
  194. static int print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
  195. struct rtnl_cls *cls, struct rtnl_u32 *u, int line)
  196. {
  197. int i;
  198. struct tc_u32_key *key;
  199. if (sel->hmask || sel->hoff) {
  200. /* I guess this will never be used since the kernel only
  201. * exports the selector if no divisor is set but hash offset
  202. * and hash mask make only sense in hash filters with divisor
  203. * set */
  204. dp_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask);
  205. }
  206. if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
  207. dp_dump(p, " offset at %u", sel->off);
  208. if (sel->flags & TC_U32_VAROFFSET)
  209. dp_dump(p, " variable (at %u & 0x%x) >> %u",
  210. sel->offoff, ntohs(sel->offmask), sel->offshift);
  211. }
  212. if (sel->flags) {
  213. int flags = sel->flags;
  214. dp_dump(p, " <");
  215. #define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
  216. flags &= ~TC_U32_##f; dp_dump(p, #f "%s", flags ? "," : ""); }
  217. PRINT_FLAG(TERMINAL);
  218. PRINT_FLAG(OFFSET);
  219. PRINT_FLAG(VAROFFSET);
  220. PRINT_FLAG(EAT);
  221. #undef PRINT_FLAG
  222. dp_dump(p, ">");
  223. }
  224. for (i = 0; i < sel->nkeys; i++) {
  225. key = (struct tc_u32_key *) ((char *) sel + sizeof(*sel)) + i;
  226. dp_dump(p, "\n");
  227. dp_dump_line(p, line++, " match key at %s%u ",
  228. key->offmask ? "nexthdr+" : "", key->off);
  229. if (key->offmask)
  230. dp_dump(p, "[0x%u] ", key->offmask);
  231. dp_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
  232. if (p->dp_type == NL_DUMP_STATS &&
  233. (u->cu_mask & U32_ATTR_PCNT)) {
  234. struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
  235. dp_dump(p, " successful %" PRIu64, pcnt->kcnts[i]);
  236. }
  237. }
  238. return line;
  239. }
  240. static int u32_dump_full(struct rtnl_cls *cls, struct nl_dump_params *p,
  241. int line)
  242. {
  243. struct rtnl_u32 *u = u32_cls(cls);
  244. struct tc_u32_sel *s;
  245. if (!u)
  246. goto ignore;
  247. if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
  248. dp_dump(p, "no-selector\n");
  249. return line;
  250. }
  251. s = u->cu_selector->d_data;
  252. dp_dump(p, "nkeys %u ", s->nkeys);
  253. if (u->cu_mask & U32_ATTR_HASH)
  254. dp_dump(p, "ht key 0x%x hash 0x%u",
  255. TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
  256. if (u->cu_mask & U32_ATTR_LINK)
  257. dp_dump(p, "link %u ", u->cu_link);
  258. if (u->cu_mask & U32_ATTR_INDEV)
  259. dp_dump(p, "indev %s ", u->cu_indev);
  260. line = print_selector(p, s, cls, u, line);
  261. dp_dump(p, "\n");
  262. ignore:
  263. return line;
  264. #if 0
  265. #define U32_ATTR_ACTION 0x040
  266. #define U32_ATTR_POLICE 0x080
  267. struct nl_data act;
  268. struct nl_data police;
  269. #endif
  270. }
  271. static int u32_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p,
  272. int line)
  273. {
  274. struct rtnl_u32 *u = u32_cls(cls);
  275. if (!u)
  276. goto ignore;
  277. if (u->cu_mask & U32_ATTR_PCNT) {
  278. struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
  279. dp_dump(p, "\n");
  280. dp_dump_line(p, line++, "%s successful hits\n");
  281. dp_dump_line(p, line++, "%s %8llu %8llu\n",
  282. pc->rhit, pc->rcnt);
  283. }
  284. ignore:
  285. return line;
  286. }
  287. static struct nl_msg *u32_get_opts(struct rtnl_cls *cls)
  288. {
  289. struct rtnl_u32 *u;
  290. struct nl_msg *msg;
  291. u = u32_cls(cls);
  292. if (!u)
  293. return NULL;
  294. msg = nlmsg_alloc();
  295. if (!msg)
  296. return NULL;
  297. if (u->cu_mask & U32_ATTR_DIVISOR)
  298. nla_put_u32(msg, TCA_U32_DIVISOR, u->cu_divisor);
  299. if (u->cu_mask & U32_ATTR_HASH)
  300. nla_put_u32(msg, TCA_U32_HASH, u->cu_hash);
  301. if (u->cu_mask & U32_ATTR_CLASSID)
  302. nla_put_u32(msg, TCA_U32_CLASSID, u->cu_classid);
  303. if (u->cu_mask & U32_ATTR_LINK)
  304. nla_put_u32(msg, TCA_U32_LINK, u->cu_link);
  305. if (u->cu_mask & U32_ATTR_SELECTOR)
  306. nla_put_data(msg, TCA_U32_SEL, u->cu_selector);
  307. if (u->cu_mask & U32_ATTR_ACTION)
  308. nla_put_data(msg, TCA_U32_ACT, u->cu_act);
  309. if (u->cu_mask & U32_ATTR_POLICE)
  310. nla_put_data(msg, TCA_U32_POLICE, u->cu_police);
  311. if (u->cu_mask & U32_ATTR_INDEV)
  312. nla_put_string(msg, TCA_U32_INDEV, u->cu_indev);
  313. return msg;
  314. }
  315. /**
  316. * @name Attribute Modifications
  317. * @{
  318. */
  319. void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash,
  320. int nodeid)
  321. {
  322. uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
  323. tca_set_handle((struct rtnl_tca *) cls, handle );
  324. }
  325. int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
  326. {
  327. struct rtnl_u32 *u;
  328. u = u32_alloc(cls);
  329. if (!u)
  330. return nl_errno(ENOMEM);
  331. u->cu_classid = classid;
  332. u->cu_mask |= U32_ATTR_CLASSID;
  333. return 0;
  334. }
  335. /** @} */
  336. /**
  337. * @name Selector Modifications
  338. * @{
  339. */
  340. int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags)
  341. {
  342. struct tc_u32_sel *sel;
  343. struct rtnl_u32 *u;
  344. u = u32_alloc(cls);
  345. if (!u)
  346. return nl_errno(ENOMEM);
  347. sel = u32_selector_alloc(u);
  348. if (!sel)
  349. return nl_errno(ENOMEM);
  350. sel->flags |= flags;
  351. u->cu_mask |= U32_ATTR_SELECTOR;
  352. return 0;
  353. }
  354. /**
  355. * Append new 32-bit key to the selector
  356. *
  357. * @arg cls classifier to be modifier
  358. * @arg val value to be matched (network byte-order)
  359. * @arg mask mask to be applied before matching (network byte-order)
  360. * @arg off offset, in bytes, to start matching
  361. * @arg offmask offset mask
  362. *
  363. * General selectors define the pattern, mask and offset the pattern will be
  364. * matched to the packet contents. Using the general selectors you can match
  365. * virtually any single bit in the IP (or upper layer) header.
  366. *
  367. */
  368. int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
  369. int off, int offmask)
  370. {
  371. struct tc_u32_sel *sel;
  372. struct rtnl_u32 *u;
  373. int err;
  374. u = u32_alloc(cls);
  375. if (!u)
  376. return nl_errno(ENOMEM);
  377. sel = u32_selector_alloc(u);
  378. if (!sel)
  379. return nl_errno(ENOMEM);
  380. err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
  381. if (err < 0)
  382. return err;
  383. /* the selector might have been moved by realloc */
  384. sel = u32_selector(u);
  385. sel->keys[sel->nkeys].mask = mask;
  386. sel->keys[sel->nkeys].val = val & mask;
  387. sel->keys[sel->nkeys].off = off;
  388. sel->keys[sel->nkeys].offmask = offmask;
  389. sel->nkeys++;
  390. u->cu_mask |= U32_ATTR_SELECTOR;
  391. return 0;
  392. }
  393. int rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask,
  394. int off, int offmask)
  395. {
  396. int shift = 24 - 8 * (off & 3);
  397. return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
  398. htonl((uint32_t)mask << shift),
  399. off & ~3, offmask);
  400. }
  401. /**
  402. * Append new selector key to match a 16-bit number
  403. *
  404. * @arg cls classifier to be modified
  405. * @arg val value to be matched (host byte-order)
  406. * @arg mask mask to be applied before matching (host byte-order)
  407. * @arg off offset, in bytes, to start matching
  408. * @arg offmask offset mask
  409. */
  410. int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask,
  411. int off, int offmask)
  412. {
  413. int shift = ((off & 3) == 0 ? 16 : 0);
  414. if (off % 2)
  415. return nl_error(EINVAL, "Invalid offset alignment");
  416. return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
  417. htonl((uint32_t)mask << shift),
  418. off & ~3, offmask);
  419. }
  420. /**
  421. * Append new selector key to match a 32-bit number
  422. *
  423. * @arg cls classifier to be modified
  424. * @arg val value to be matched (host byte-order)
  425. * @arg mask mask to be applied before matching (host byte-order)
  426. * @arg off offset, in bytes, to start matching
  427. * @arg offmask offset mask
  428. */
  429. int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
  430. int off, int offmask)
  431. {
  432. return rtnl_u32_add_key(cls, htonl(val), htonl(mask),
  433. off & ~3, offmask);
  434. }
  435. int rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, struct in_addr *addr,
  436. uint8_t bitmask, int off, int offmask)
  437. {
  438. uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
  439. return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask);
  440. }
  441. int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, struct in6_addr *addr,
  442. uint8_t bitmask, int off, int offmask)
  443. {
  444. int i, err;
  445. for (i = 1; i <= 4; i++) {
  446. if (32 * i - bitmask <= 0) {
  447. if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
  448. 0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
  449. return err;
  450. }
  451. else if (32 * i - bitmask < 32) {
  452. uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
  453. if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
  454. htonl(mask), off+4*(i-1), offmask)) < 0)
  455. return err;
  456. }
  457. /* otherwise, if (32*i - bitmask >= 32) no key is generated */
  458. }
  459. return 0;
  460. }
  461. /** @} */
  462. static struct rtnl_cls_ops u32_ops = {
  463. .co_kind = "u32",
  464. .co_msg_parser = u32_msg_parser,
  465. .co_free_data = u32_free_data,
  466. .co_clone = u32_clone,
  467. .co_get_opts = u32_get_opts,
  468. .co_dump[NL_DUMP_BRIEF] = u32_dump_brief,
  469. .co_dump[NL_DUMP_FULL] = u32_dump_full,
  470. .co_dump[NL_DUMP_STATS] = u32_dump_stats,
  471. };
  472. static void __init u32_init(void)
  473. {
  474. rtnl_cls_register(&u32_ops);
  475. }
  476. static void __exit u32_exit(void)
  477. {
  478. rtnl_cls_unregister(&u32_ops);
  479. }
  480. /** @} */