meta.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /*
  2. * lib/route/cls/ematch/meta.c Metadata Match
  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) 2010-2013 Thomas Graf <tgraf@suug.ch>
  10. */
  11. /**
  12. * @ingroup ematch
  13. * @defgroup em_meta Metadata Match
  14. *
  15. * @{
  16. */
  17. #include <netlink-private/netlink.h>
  18. #include <netlink-private/tc.h>
  19. #include <netlink/netlink.h>
  20. #include <netlink/route/cls/ematch.h>
  21. #include <netlink/route/cls/ematch/meta.h>
  22. struct rtnl_meta_value
  23. {
  24. uint8_t mv_type;
  25. uint8_t mv_shift;
  26. uint16_t mv_id;
  27. size_t mv_len;
  28. };
  29. struct meta_data
  30. {
  31. struct rtnl_meta_value * left;
  32. struct rtnl_meta_value * right;
  33. uint8_t opnd;
  34. };
  35. static struct rtnl_meta_value *meta_alloc(uint8_t type, uint16_t id,
  36. uint8_t shift, void *data,
  37. size_t len)
  38. {
  39. struct rtnl_meta_value *value;
  40. if (!(value = calloc(1, sizeof(*value) + len)))
  41. return NULL;
  42. value->mv_type = type;
  43. value->mv_id = id;
  44. value->mv_shift = shift;
  45. value->mv_len = len;
  46. memcpy(value + 1, data, len);
  47. return value;
  48. }
  49. struct rtnl_meta_value *rtnl_meta_value_alloc_int(uint64_t value)
  50. {
  51. return meta_alloc(TCF_META_TYPE_INT, TCF_META_ID_VALUE, 0, &value, 8);
  52. }
  53. struct rtnl_meta_value *rtnl_meta_value_alloc_var(void *data, size_t len)
  54. {
  55. return meta_alloc(TCF_META_TYPE_VAR, TCF_META_ID_VALUE, 0, data, len);
  56. }
  57. struct rtnl_meta_value *rtnl_meta_value_alloc_id(uint8_t type, uint16_t id,
  58. uint8_t shift, uint64_t mask)
  59. {
  60. size_t masklen = 0;
  61. if (id > TCF_META_ID_MAX)
  62. return NULL;
  63. if (mask) {
  64. if (type == TCF_META_TYPE_VAR)
  65. return NULL;
  66. masklen = 8;
  67. }
  68. return meta_alloc(type, id, shift, &mask, masklen);
  69. }
  70. void rtnl_meta_value_put(struct rtnl_meta_value *mv)
  71. {
  72. free(mv);
  73. }
  74. void rtnl_ematch_meta_set_lvalue(struct rtnl_ematch *e, struct rtnl_meta_value *v)
  75. {
  76. struct meta_data *m = rtnl_ematch_data(e);
  77. m->left = v;
  78. }
  79. void rtnl_ematch_meta_set_rvalue(struct rtnl_ematch *e, struct rtnl_meta_value *v)
  80. {
  81. struct meta_data *m = rtnl_ematch_data(e);
  82. m->right = v;
  83. }
  84. void rtnl_ematch_meta_set_operand(struct rtnl_ematch *e, uint8_t opnd)
  85. {
  86. struct meta_data *m = rtnl_ematch_data(e);
  87. m->opnd = opnd;
  88. }
  89. static struct nla_policy meta_policy[TCA_EM_META_MAX+1] = {
  90. [TCA_EM_META_HDR] = { .minlen = sizeof(struct tcf_meta_hdr) },
  91. [TCA_EM_META_LVALUE] = { .minlen = 1, },
  92. [TCA_EM_META_RVALUE] = { .minlen = 1, },
  93. };
  94. static int meta_parse(struct rtnl_ematch *e, void *data, size_t len)
  95. {
  96. struct meta_data *m = rtnl_ematch_data(e);
  97. struct nlattr *tb[TCA_EM_META_MAX+1];
  98. struct rtnl_meta_value *v;
  99. struct tcf_meta_hdr *hdr;
  100. void *vdata = NULL;
  101. size_t vlen = 0;
  102. int err;
  103. if ((err = nla_parse(tb, TCA_EM_META_MAX, data, len, meta_policy)) < 0)
  104. return err;
  105. if (!tb[TCA_EM_META_HDR])
  106. return -NLE_MISSING_ATTR;
  107. hdr = nla_data(tb[TCA_EM_META_HDR]);
  108. if (tb[TCA_EM_META_LVALUE]) {
  109. vdata = nla_data(tb[TCA_EM_META_LVALUE]);
  110. vlen = nla_len(tb[TCA_EM_META_LVALUE]);
  111. }
  112. v = meta_alloc(TCF_META_TYPE(hdr->left.kind),
  113. TCF_META_ID(hdr->left.kind),
  114. hdr->left.shift, vdata, vlen);
  115. if (!v)
  116. return -NLE_NOMEM;
  117. m->left = v;
  118. vlen = 0;
  119. if (tb[TCA_EM_META_RVALUE]) {
  120. vdata = nla_data(tb[TCA_EM_META_RVALUE]);
  121. vlen = nla_len(tb[TCA_EM_META_RVALUE]);
  122. }
  123. v = meta_alloc(TCF_META_TYPE(hdr->right.kind),
  124. TCF_META_ID(hdr->right.kind),
  125. hdr->right.shift, vdata, vlen);
  126. if (!v) {
  127. rtnl_meta_value_put(m->left);
  128. return -NLE_NOMEM;
  129. }
  130. m->right = v;
  131. m->opnd = hdr->left.op;
  132. return 0;
  133. }
  134. static const struct trans_tbl meta_int[] = {
  135. __ADD(TCF_META_ID_RANDOM, random)
  136. __ADD(TCF_META_ID_LOADAVG_0, loadavg_0)
  137. __ADD(TCF_META_ID_LOADAVG_1, loadavg_1)
  138. __ADD(TCF_META_ID_LOADAVG_2, loadavg_2)
  139. __ADD(TCF_META_ID_DEV, dev)
  140. __ADD(TCF_META_ID_PRIORITY, prio)
  141. __ADD(TCF_META_ID_PROTOCOL, proto)
  142. __ADD(TCF_META_ID_PKTTYPE, pkttype)
  143. __ADD(TCF_META_ID_PKTLEN, pktlen)
  144. __ADD(TCF_META_ID_DATALEN, datalen)
  145. __ADD(TCF_META_ID_MACLEN, maclen)
  146. __ADD(TCF_META_ID_NFMARK, mark)
  147. __ADD(TCF_META_ID_TCINDEX, tcindex)
  148. __ADD(TCF_META_ID_RTCLASSID, rtclassid)
  149. __ADD(TCF_META_ID_RTIIF, rtiif)
  150. __ADD(TCF_META_ID_SK_FAMILY, sk_family)
  151. __ADD(TCF_META_ID_SK_STATE, sk_state)
  152. __ADD(TCF_META_ID_SK_REUSE, sk_reuse)
  153. __ADD(TCF_META_ID_SK_REFCNT, sk_refcnt)
  154. __ADD(TCF_META_ID_SK_RCVBUF, sk_rcvbuf)
  155. __ADD(TCF_META_ID_SK_SNDBUF, sk_sndbuf)
  156. __ADD(TCF_META_ID_SK_SHUTDOWN, sk_sutdown)
  157. __ADD(TCF_META_ID_SK_PROTO, sk_proto)
  158. __ADD(TCF_META_ID_SK_TYPE, sk_type)
  159. __ADD(TCF_META_ID_SK_RMEM_ALLOC, sk_rmem_alloc)
  160. __ADD(TCF_META_ID_SK_WMEM_ALLOC, sk_wmem_alloc)
  161. __ADD(TCF_META_ID_SK_WMEM_QUEUED, sk_wmem_queued)
  162. __ADD(TCF_META_ID_SK_RCV_QLEN, sk_rcv_qlen)
  163. __ADD(TCF_META_ID_SK_SND_QLEN, sk_snd_qlen)
  164. __ADD(TCF_META_ID_SK_ERR_QLEN, sk_err_qlen)
  165. __ADD(TCF_META_ID_SK_FORWARD_ALLOCS, sk_forward_allocs)
  166. __ADD(TCF_META_ID_SK_ALLOCS, sk_allocs)
  167. __ADD(TCF_META_ID_SK_ROUTE_CAPS, sk_route_caps)
  168. __ADD(TCF_META_ID_SK_HASH, sk_hash)
  169. __ADD(TCF_META_ID_SK_LINGERTIME, sk_lingertime)
  170. __ADD(TCF_META_ID_SK_ACK_BACKLOG, sk_ack_backlog)
  171. __ADD(TCF_META_ID_SK_MAX_ACK_BACKLOG, sk_max_ack_backlog)
  172. __ADD(TCF_META_ID_SK_PRIO, sk_prio)
  173. __ADD(TCF_META_ID_SK_RCVLOWAT, sk_rcvlowat)
  174. __ADD(TCF_META_ID_SK_RCVTIMEO, sk_rcvtimeo)
  175. __ADD(TCF_META_ID_SK_SNDTIMEO, sk_sndtimeo)
  176. __ADD(TCF_META_ID_SK_SENDMSG_OFF, sk_sendmsg_off)
  177. __ADD(TCF_META_ID_SK_WRITE_PENDING, sk_write_pending)
  178. __ADD(TCF_META_ID_VLAN_TAG, vlan)
  179. __ADD(TCF_META_ID_RXHASH, rxhash)
  180. };
  181. static char *int_id2str(int id, char *buf, size_t size)
  182. {
  183. return __type2str(id, buf, size, meta_int, ARRAY_SIZE(meta_int));
  184. }
  185. static const struct trans_tbl meta_var[] = {
  186. __ADD(TCF_META_ID_DEV,devname)
  187. __ADD(TCF_META_ID_SK_BOUND_IF,sk_bound_if)
  188. };
  189. static char *var_id2str(int id, char *buf, size_t size)
  190. {
  191. return __type2str(id, buf, size, meta_var, ARRAY_SIZE(meta_var));
  192. }
  193. static void dump_value(struct rtnl_meta_value *v, struct nl_dump_params *p)
  194. {
  195. char buf[32];
  196. switch (v->mv_type) {
  197. case TCF_META_TYPE_INT:
  198. if (v->mv_id == TCF_META_ID_VALUE) {
  199. nl_dump(p, "%u",
  200. *(uint32_t *) (v + 1));
  201. } else {
  202. nl_dump(p, "%s",
  203. int_id2str(v->mv_id, buf, sizeof(buf)));
  204. if (v->mv_shift)
  205. nl_dump(p, " >> %u", v->mv_shift);
  206. if (v->mv_len == 4)
  207. nl_dump(p, " & %#x", *(uint32_t *) (v + 1));
  208. else if (v->mv_len == 8)
  209. nl_dump(p, " & %#x", *(uint64_t *) (v + 1));
  210. }
  211. break;
  212. case TCF_META_TYPE_VAR:
  213. if (v->mv_id == TCF_META_ID_VALUE) {
  214. nl_dump(p, "%s", (char *) (v + 1));
  215. } else {
  216. nl_dump(p, "%s",
  217. var_id2str(v->mv_id, buf, sizeof(buf)));
  218. if (v->mv_shift)
  219. nl_dump(p, " >> %u", v->mv_shift);
  220. }
  221. break;
  222. }
  223. }
  224. static void meta_dump(struct rtnl_ematch *e, struct nl_dump_params *p)
  225. {
  226. struct meta_data *m = rtnl_ematch_data(e);
  227. char buf[32];
  228. nl_dump(p, "meta(");
  229. dump_value(m->left, p);
  230. nl_dump(p, " %s ", rtnl_ematch_opnd2txt(m->opnd, buf, sizeof(buf)));
  231. dump_value(m->right, p);
  232. nl_dump(p, ")");
  233. }
  234. static int meta_fill(struct rtnl_ematch *e, struct nl_msg *msg)
  235. {
  236. struct meta_data *m = rtnl_ematch_data(e);
  237. struct tcf_meta_hdr hdr;
  238. if (!(m->left && m->right))
  239. return -NLE_MISSING_ATTR;
  240. memset(&hdr, 0, sizeof(hdr));
  241. hdr.left.kind = (m->left->mv_type << 12) & TCF_META_TYPE_MASK;
  242. hdr.left.kind |= m->left->mv_id & TCF_META_ID_MASK;
  243. hdr.left.shift = m->left->mv_shift;
  244. hdr.left.op = m->opnd;
  245. hdr.right.kind = (m->right->mv_type << 12) & TCF_META_TYPE_MASK;
  246. hdr.right.kind |= m->right->mv_id & TCF_META_ID_MASK;
  247. NLA_PUT(msg, TCA_EM_META_HDR, sizeof(hdr), &hdr);
  248. if (m->left->mv_len)
  249. NLA_PUT(msg, TCA_EM_META_LVALUE, m->left->mv_len, (m->left + 1));
  250. if (m->right->mv_len)
  251. NLA_PUT(msg, TCA_EM_META_RVALUE, m->right->mv_len, (m->right + 1));
  252. return 0;
  253. nla_put_failure:
  254. return -NLE_NOMEM;
  255. }
  256. static void meta_free(struct rtnl_ematch *e)
  257. {
  258. struct meta_data *m = rtnl_ematch_data(e);
  259. free(m->left);
  260. free(m->right);
  261. }
  262. static struct rtnl_ematch_ops meta_ops = {
  263. .eo_kind = TCF_EM_META,
  264. .eo_name = "meta",
  265. .eo_minlen = sizeof(struct tcf_meta_hdr),
  266. .eo_datalen = sizeof(struct meta_data),
  267. .eo_parse = meta_parse,
  268. .eo_dump = meta_dump,
  269. .eo_fill = meta_fill,
  270. .eo_free = meta_free,
  271. };
  272. static void __init meta_init(void)
  273. {
  274. rtnl_ematch_register(&meta_ops);
  275. }
  276. /** @} */