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