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>
41 uint8_t shift,
void *data,
46 if (!(value = calloc(1,
sizeof(*value) + len)))
49 value->mv_type = type;
51 value->mv_shift = shift;
55 memcpy(value + 1, data, len);
62 return meta_alloc(TCF_META_TYPE_INT, TCF_META_ID_VALUE, 0, &value, 8);
65 struct rtnl_meta_value *rtnl_meta_value_alloc_var(
void *data,
size_t len)
67 return meta_alloc(TCF_META_TYPE_VAR, TCF_META_ID_VALUE, 0, data, len);
70 struct rtnl_meta_value *rtnl_meta_value_alloc_id(uint8_t type, uint16_t
id,
71 uint8_t shift, uint64_t mask)
75 if (
id > TCF_META_ID_MAX)
79 if (type == TCF_META_TYPE_VAR)
85 return meta_alloc(type,
id, shift, &mask, masklen);
93 void rtnl_ematch_meta_set_lvalue(
struct rtnl_ematch *e,
struct rtnl_meta_value *v)
95 struct meta_data *m = rtnl_ematch_data(e);
99 void rtnl_ematch_meta_set_rvalue(
struct rtnl_ematch *e,
struct rtnl_meta_value *v)
101 struct meta_data *m = rtnl_ematch_data(e);
105 void rtnl_ematch_meta_set_operand(
struct rtnl_ematch *e, uint8_t opnd)
107 struct meta_data *m = rtnl_ematch_data(e);
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, },
117 static int meta_parse(
struct rtnl_ematch *e,
void *data,
size_t len)
119 struct meta_data *m = rtnl_ematch_data(e);
120 struct nlattr *tb[TCA_EM_META_MAX+1];
122 struct tcf_meta_hdr *hdr;
127 if ((err =
nla_parse(tb, TCA_EM_META_MAX, data, len, meta_policy)) < 0)
130 if (!tb[TCA_EM_META_HDR])
131 return -NLE_MISSING_ATTR;
133 hdr =
nla_data(tb[TCA_EM_META_HDR]);
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]);
140 v = meta_alloc(TCF_META_TYPE(hdr->left.kind),
141 TCF_META_ID(hdr->left.kind),
142 hdr->left.shift, vdata, vlen);
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]);
154 v = meta_alloc(TCF_META_TYPE(hdr->right.kind),
155 TCF_META_ID(hdr->right.kind),
156 hdr->right.shift, vdata, vlen);
158 rtnl_meta_value_put(m->left);
163 m->opnd = hdr->left.op;
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),
216 static char *int_id2str(
int id,
char *buf,
size_t size)
218 return __type2str(
id, buf, size, meta_int, ARRAY_SIZE(meta_int));
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),
226 static char *var_id2str(
int id,
char *buf,
size_t size)
228 return __type2str(
id, buf, size, meta_var, ARRAY_SIZE(meta_var));
235 switch (v->mv_type) {
236 case TCF_META_TYPE_INT:
237 if (v->mv_id == TCF_META_ID_VALUE) {
239 *(uint32_t *) (v + 1));
242 int_id2str(v->mv_id, buf,
sizeof(buf)));
245 nl_dump(p,
" >> %u", v->mv_shift);
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));
254 case TCF_META_TYPE_VAR:
255 if (v->mv_id == TCF_META_ID_VALUE) {
256 nl_dump(p,
"%s", (
char *) (v + 1));
259 var_id2str(v->mv_id, buf,
sizeof(buf)));
262 nl_dump(p,
" >> %u", v->mv_shift);
268 static void meta_dump(
struct rtnl_ematch *e,
struct nl_dump_params *p)
270 struct meta_data *m = rtnl_ematch_data(e);
274 dump_value(m->left, p);
276 nl_dump(p,
" %s ", rtnl_ematch_opnd2txt(m->opnd, buf,
sizeof(buf)));
278 dump_value(m->right, p);
282 static int meta_fill(
struct rtnl_ematch *e,
struct nl_msg *msg)
284 struct meta_data *m = rtnl_ematch_data(e);
285 struct tcf_meta_hdr hdr;
287 if (!(m->left && m->right))
288 return -NLE_MISSING_ATTR;
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;
298 NLA_PUT(msg, TCA_EM_META_HDR,
sizeof(hdr), &hdr);
301 NLA_PUT(msg, TCA_EM_META_LVALUE, m->left->mv_len, (m->left + 1));
303 if (m->right->mv_len)
304 NLA_PUT(msg, TCA_EM_META_RVALUE, m->right->mv_len, (m->right + 1));
312 static void meta_free(
struct rtnl_ematch *e)
314 struct meta_data *m = rtnl_ematch_data(e);
320 .eo_kind = TCF_EM_META,
322 .eo_minlen =
sizeof(
struct tcf_meta_hdr),
324 .eo_parse = meta_parse,
325 .eo_dump = meta_dump,
326 .eo_fill = meta_fill,
327 .eo_free = meta_free,
330 static void __init meta_init(
void)
Attribute validation policy.
#define NLA_PUT(msg, attrtype, attrlen, data)
Add unspecific attribute to netlink message.
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
int rtnl_ematch_register(struct rtnl_ematch_ops *ops)
Register ematch module.
int nla_len(const struct nlattr *nla)
Return length of the payload .
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.
uint16_t minlen
Minimal length of payload required.
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Extended Match Operations.