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