1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * net/sched/em_meta.c Metadata ematch
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Authors: Thomas Graf <tgraf@suug.ch>
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * ==========================================================================
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * The metadata ematch compares two meta objects where each object
10*4882a593Smuzhiyun * represents either a meta value stored in the kernel or a static
11*4882a593Smuzhiyun * value provided by userspace. The objects are not provided by
12*4882a593Smuzhiyun * userspace itself but rather a definition providing the information
13*4882a593Smuzhiyun * to build them. Every object is of a certain type which must be
14*4882a593Smuzhiyun * equal to the object it is being compared to.
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * The definition of a objects conists of the type (meta type), a
17*4882a593Smuzhiyun * identifier (meta id) and additional type specific information.
18*4882a593Smuzhiyun * The meta id is either TCF_META_TYPE_VALUE for values provided by
19*4882a593Smuzhiyun * userspace or a index to the meta operations table consisting of
20*4882a593Smuzhiyun * function pointers to type specific meta data collectors returning
21*4882a593Smuzhiyun * the value of the requested meta value.
22*4882a593Smuzhiyun *
23*4882a593Smuzhiyun * lvalue rvalue
24*4882a593Smuzhiyun * +-----------+ +-----------+
25*4882a593Smuzhiyun * | type: INT | | type: INT |
26*4882a593Smuzhiyun * def | id: DEV | | id: VALUE |
27*4882a593Smuzhiyun * | data: | | data: 3 |
28*4882a593Smuzhiyun * +-----------+ +-----------+
29*4882a593Smuzhiyun * | |
30*4882a593Smuzhiyun * ---> meta_ops[INT][DEV](...) |
31*4882a593Smuzhiyun * | |
32*4882a593Smuzhiyun * ----------- |
33*4882a593Smuzhiyun * V V
34*4882a593Smuzhiyun * +-----------+ +-----------+
35*4882a593Smuzhiyun * | type: INT | | type: INT |
36*4882a593Smuzhiyun * obj | id: DEV | | id: VALUE |
37*4882a593Smuzhiyun * | data: 2 |<--data got filled out | data: 3 |
38*4882a593Smuzhiyun * +-----------+ +-----------+
39*4882a593Smuzhiyun * | |
40*4882a593Smuzhiyun * --------------> 2 equals 3 <--------------
41*4882a593Smuzhiyun *
42*4882a593Smuzhiyun * This is a simplified schema, the complexity varies depending
43*4882a593Smuzhiyun * on the meta type. Obviously, the length of the data must also
44*4882a593Smuzhiyun * be provided for non-numeric types.
45*4882a593Smuzhiyun *
46*4882a593Smuzhiyun * Additionally, type dependent modifiers such as shift operators
47*4882a593Smuzhiyun * or mask may be applied to extend the functionaliy. As of now,
48*4882a593Smuzhiyun * the variable length type supports shifting the byte string to
49*4882a593Smuzhiyun * the right, eating up any number of octets and thus supporting
50*4882a593Smuzhiyun * wildcard interface name comparisons such as "ppp%" matching
51*4882a593Smuzhiyun * ppp0..9.
52*4882a593Smuzhiyun *
53*4882a593Smuzhiyun * NOTE: Certain meta values depend on other subsystems and are
54*4882a593Smuzhiyun * only available if that subsystem is enabled in the kernel.
55*4882a593Smuzhiyun */
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun #include <linux/slab.h>
58*4882a593Smuzhiyun #include <linux/module.h>
59*4882a593Smuzhiyun #include <linux/types.h>
60*4882a593Smuzhiyun #include <linux/kernel.h>
61*4882a593Smuzhiyun #include <linux/sched.h>
62*4882a593Smuzhiyun #include <linux/sched/loadavg.h>
63*4882a593Smuzhiyun #include <linux/string.h>
64*4882a593Smuzhiyun #include <linux/skbuff.h>
65*4882a593Smuzhiyun #include <linux/random.h>
66*4882a593Smuzhiyun #include <linux/if_vlan.h>
67*4882a593Smuzhiyun #include <linux/tc_ematch/tc_em_meta.h>
68*4882a593Smuzhiyun #include <net/dst.h>
69*4882a593Smuzhiyun #include <net/route.h>
70*4882a593Smuzhiyun #include <net/pkt_cls.h>
71*4882a593Smuzhiyun #include <net/sock.h>
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun struct meta_obj {
74*4882a593Smuzhiyun unsigned long value;
75*4882a593Smuzhiyun unsigned int len;
76*4882a593Smuzhiyun };
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun struct meta_value {
79*4882a593Smuzhiyun struct tcf_meta_val hdr;
80*4882a593Smuzhiyun unsigned long val;
81*4882a593Smuzhiyun unsigned int len;
82*4882a593Smuzhiyun };
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun struct meta_match {
85*4882a593Smuzhiyun struct meta_value lvalue;
86*4882a593Smuzhiyun struct meta_value rvalue;
87*4882a593Smuzhiyun };
88*4882a593Smuzhiyun
meta_id(struct meta_value * v)89*4882a593Smuzhiyun static inline int meta_id(struct meta_value *v)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun return TCF_META_ID(v->hdr.kind);
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun
meta_type(struct meta_value * v)94*4882a593Smuzhiyun static inline int meta_type(struct meta_value *v)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun return TCF_META_TYPE(v->hdr.kind);
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun #define META_COLLECTOR(FUNC) static void meta_##FUNC(struct sk_buff *skb, \
100*4882a593Smuzhiyun struct tcf_pkt_info *info, struct meta_value *v, \
101*4882a593Smuzhiyun struct meta_obj *dst, int *err)
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun /**************************************************************************
104*4882a593Smuzhiyun * System status & misc
105*4882a593Smuzhiyun **************************************************************************/
106*4882a593Smuzhiyun
META_COLLECTOR(int_random)107*4882a593Smuzhiyun META_COLLECTOR(int_random)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun get_random_bytes(&dst->value, sizeof(dst->value));
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun
fixed_loadavg(int load)112*4882a593Smuzhiyun static inline unsigned long fixed_loadavg(int load)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun int rnd_load = load + (FIXED_1/200);
115*4882a593Smuzhiyun int rnd_frac = ((rnd_load & (FIXED_1-1)) * 100) >> FSHIFT;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun return ((rnd_load >> FSHIFT) * 100) + rnd_frac;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
META_COLLECTOR(int_loadavg_0)120*4882a593Smuzhiyun META_COLLECTOR(int_loadavg_0)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun dst->value = fixed_loadavg(avenrun[0]);
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun
META_COLLECTOR(int_loadavg_1)125*4882a593Smuzhiyun META_COLLECTOR(int_loadavg_1)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun dst->value = fixed_loadavg(avenrun[1]);
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
META_COLLECTOR(int_loadavg_2)130*4882a593Smuzhiyun META_COLLECTOR(int_loadavg_2)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun dst->value = fixed_loadavg(avenrun[2]);
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun /**************************************************************************
136*4882a593Smuzhiyun * Device names & indices
137*4882a593Smuzhiyun **************************************************************************/
138*4882a593Smuzhiyun
int_dev(struct net_device * dev,struct meta_obj * dst)139*4882a593Smuzhiyun static inline int int_dev(struct net_device *dev, struct meta_obj *dst)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun if (unlikely(dev == NULL))
142*4882a593Smuzhiyun return -1;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun dst->value = dev->ifindex;
145*4882a593Smuzhiyun return 0;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
var_dev(struct net_device * dev,struct meta_obj * dst)148*4882a593Smuzhiyun static inline int var_dev(struct net_device *dev, struct meta_obj *dst)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun if (unlikely(dev == NULL))
151*4882a593Smuzhiyun return -1;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun dst->value = (unsigned long) dev->name;
154*4882a593Smuzhiyun dst->len = strlen(dev->name);
155*4882a593Smuzhiyun return 0;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun
META_COLLECTOR(int_dev)158*4882a593Smuzhiyun META_COLLECTOR(int_dev)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun *err = int_dev(skb->dev, dst);
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
META_COLLECTOR(var_dev)163*4882a593Smuzhiyun META_COLLECTOR(var_dev)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun *err = var_dev(skb->dev, dst);
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun /**************************************************************************
169*4882a593Smuzhiyun * vlan tag
170*4882a593Smuzhiyun **************************************************************************/
171*4882a593Smuzhiyun
META_COLLECTOR(int_vlan_tag)172*4882a593Smuzhiyun META_COLLECTOR(int_vlan_tag)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun unsigned short tag;
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun if (skb_vlan_tag_present(skb))
177*4882a593Smuzhiyun dst->value = skb_vlan_tag_get(skb);
178*4882a593Smuzhiyun else if (!__vlan_get_tag(skb, &tag))
179*4882a593Smuzhiyun dst->value = tag;
180*4882a593Smuzhiyun else
181*4882a593Smuzhiyun *err = -1;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun /**************************************************************************
187*4882a593Smuzhiyun * skb attributes
188*4882a593Smuzhiyun **************************************************************************/
189*4882a593Smuzhiyun
META_COLLECTOR(int_priority)190*4882a593Smuzhiyun META_COLLECTOR(int_priority)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun dst->value = skb->priority;
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun
META_COLLECTOR(int_protocol)195*4882a593Smuzhiyun META_COLLECTOR(int_protocol)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun /* Let userspace take care of the byte ordering */
198*4882a593Smuzhiyun dst->value = skb_protocol(skb, false);
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun
META_COLLECTOR(int_pkttype)201*4882a593Smuzhiyun META_COLLECTOR(int_pkttype)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun dst->value = skb->pkt_type;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
META_COLLECTOR(int_pktlen)206*4882a593Smuzhiyun META_COLLECTOR(int_pktlen)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun dst->value = skb->len;
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun
META_COLLECTOR(int_datalen)211*4882a593Smuzhiyun META_COLLECTOR(int_datalen)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun dst->value = skb->data_len;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
META_COLLECTOR(int_maclen)216*4882a593Smuzhiyun META_COLLECTOR(int_maclen)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun dst->value = skb->mac_len;
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun
META_COLLECTOR(int_rxhash)221*4882a593Smuzhiyun META_COLLECTOR(int_rxhash)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun dst->value = skb_get_hash(skb);
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun /**************************************************************************
227*4882a593Smuzhiyun * Netfilter
228*4882a593Smuzhiyun **************************************************************************/
229*4882a593Smuzhiyun
META_COLLECTOR(int_mark)230*4882a593Smuzhiyun META_COLLECTOR(int_mark)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun dst->value = skb->mark;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun /**************************************************************************
236*4882a593Smuzhiyun * Traffic Control
237*4882a593Smuzhiyun **************************************************************************/
238*4882a593Smuzhiyun
META_COLLECTOR(int_tcindex)239*4882a593Smuzhiyun META_COLLECTOR(int_tcindex)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun dst->value = skb->tc_index;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun /**************************************************************************
245*4882a593Smuzhiyun * Routing
246*4882a593Smuzhiyun **************************************************************************/
247*4882a593Smuzhiyun
META_COLLECTOR(int_rtclassid)248*4882a593Smuzhiyun META_COLLECTOR(int_rtclassid)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun if (unlikely(skb_dst(skb) == NULL))
251*4882a593Smuzhiyun *err = -1;
252*4882a593Smuzhiyun else
253*4882a593Smuzhiyun #ifdef CONFIG_IP_ROUTE_CLASSID
254*4882a593Smuzhiyun dst->value = skb_dst(skb)->tclassid;
255*4882a593Smuzhiyun #else
256*4882a593Smuzhiyun dst->value = 0;
257*4882a593Smuzhiyun #endif
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
META_COLLECTOR(int_rtiif)260*4882a593Smuzhiyun META_COLLECTOR(int_rtiif)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun if (unlikely(skb_rtable(skb) == NULL))
263*4882a593Smuzhiyun *err = -1;
264*4882a593Smuzhiyun else
265*4882a593Smuzhiyun dst->value = inet_iif(skb);
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun /**************************************************************************
269*4882a593Smuzhiyun * Socket Attributes
270*4882a593Smuzhiyun **************************************************************************/
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun #define skip_nonlocal(skb) \
273*4882a593Smuzhiyun (unlikely(skb->sk == NULL))
274*4882a593Smuzhiyun
META_COLLECTOR(int_sk_family)275*4882a593Smuzhiyun META_COLLECTOR(int_sk_family)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun if (skip_nonlocal(skb)) {
278*4882a593Smuzhiyun *err = -1;
279*4882a593Smuzhiyun return;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun dst->value = skb->sk->sk_family;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun
META_COLLECTOR(int_sk_state)284*4882a593Smuzhiyun META_COLLECTOR(int_sk_state)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun if (skip_nonlocal(skb)) {
287*4882a593Smuzhiyun *err = -1;
288*4882a593Smuzhiyun return;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun dst->value = skb->sk->sk_state;
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun
META_COLLECTOR(int_sk_reuse)293*4882a593Smuzhiyun META_COLLECTOR(int_sk_reuse)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun if (skip_nonlocal(skb)) {
296*4882a593Smuzhiyun *err = -1;
297*4882a593Smuzhiyun return;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun dst->value = skb->sk->sk_reuse;
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
META_COLLECTOR(int_sk_bound_if)302*4882a593Smuzhiyun META_COLLECTOR(int_sk_bound_if)
303*4882a593Smuzhiyun {
304*4882a593Smuzhiyun if (skip_nonlocal(skb)) {
305*4882a593Smuzhiyun *err = -1;
306*4882a593Smuzhiyun return;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun /* No error if bound_dev_if is 0, legal userspace check */
309*4882a593Smuzhiyun dst->value = skb->sk->sk_bound_dev_if;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun
META_COLLECTOR(var_sk_bound_if)312*4882a593Smuzhiyun META_COLLECTOR(var_sk_bound_if)
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun if (skip_nonlocal(skb)) {
315*4882a593Smuzhiyun *err = -1;
316*4882a593Smuzhiyun return;
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun if (skb->sk->sk_bound_dev_if == 0) {
320*4882a593Smuzhiyun dst->value = (unsigned long) "any";
321*4882a593Smuzhiyun dst->len = 3;
322*4882a593Smuzhiyun } else {
323*4882a593Smuzhiyun struct net_device *dev;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun rcu_read_lock();
326*4882a593Smuzhiyun dev = dev_get_by_index_rcu(sock_net(skb->sk),
327*4882a593Smuzhiyun skb->sk->sk_bound_dev_if);
328*4882a593Smuzhiyun *err = var_dev(dev, dst);
329*4882a593Smuzhiyun rcu_read_unlock();
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun
META_COLLECTOR(int_sk_refcnt)333*4882a593Smuzhiyun META_COLLECTOR(int_sk_refcnt)
334*4882a593Smuzhiyun {
335*4882a593Smuzhiyun if (skip_nonlocal(skb)) {
336*4882a593Smuzhiyun *err = -1;
337*4882a593Smuzhiyun return;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun dst->value = refcount_read(&skb->sk->sk_refcnt);
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun
META_COLLECTOR(int_sk_rcvbuf)342*4882a593Smuzhiyun META_COLLECTOR(int_sk_rcvbuf)
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun if (!sk) {
347*4882a593Smuzhiyun *err = -1;
348*4882a593Smuzhiyun return;
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun dst->value = sk->sk_rcvbuf;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
META_COLLECTOR(int_sk_shutdown)353*4882a593Smuzhiyun META_COLLECTOR(int_sk_shutdown)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun if (!sk) {
358*4882a593Smuzhiyun *err = -1;
359*4882a593Smuzhiyun return;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun dst->value = sk->sk_shutdown;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun
META_COLLECTOR(int_sk_proto)364*4882a593Smuzhiyun META_COLLECTOR(int_sk_proto)
365*4882a593Smuzhiyun {
366*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun if (!sk) {
369*4882a593Smuzhiyun *err = -1;
370*4882a593Smuzhiyun return;
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun dst->value = sk->sk_protocol;
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun
META_COLLECTOR(int_sk_type)375*4882a593Smuzhiyun META_COLLECTOR(int_sk_type)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun if (!sk) {
380*4882a593Smuzhiyun *err = -1;
381*4882a593Smuzhiyun return;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun dst->value = sk->sk_type;
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun
META_COLLECTOR(int_sk_rmem_alloc)386*4882a593Smuzhiyun META_COLLECTOR(int_sk_rmem_alloc)
387*4882a593Smuzhiyun {
388*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun if (!sk) {
391*4882a593Smuzhiyun *err = -1;
392*4882a593Smuzhiyun return;
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun dst->value = sk_rmem_alloc_get(sk);
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun
META_COLLECTOR(int_sk_wmem_alloc)397*4882a593Smuzhiyun META_COLLECTOR(int_sk_wmem_alloc)
398*4882a593Smuzhiyun {
399*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun if (!sk) {
402*4882a593Smuzhiyun *err = -1;
403*4882a593Smuzhiyun return;
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun dst->value = sk_wmem_alloc_get(sk);
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun
META_COLLECTOR(int_sk_omem_alloc)408*4882a593Smuzhiyun META_COLLECTOR(int_sk_omem_alloc)
409*4882a593Smuzhiyun {
410*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun if (!sk) {
413*4882a593Smuzhiyun *err = -1;
414*4882a593Smuzhiyun return;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun dst->value = atomic_read(&sk->sk_omem_alloc);
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun
META_COLLECTOR(int_sk_rcv_qlen)419*4882a593Smuzhiyun META_COLLECTOR(int_sk_rcv_qlen)
420*4882a593Smuzhiyun {
421*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun if (!sk) {
424*4882a593Smuzhiyun *err = -1;
425*4882a593Smuzhiyun return;
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun dst->value = sk->sk_receive_queue.qlen;
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun
META_COLLECTOR(int_sk_snd_qlen)430*4882a593Smuzhiyun META_COLLECTOR(int_sk_snd_qlen)
431*4882a593Smuzhiyun {
432*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun if (!sk) {
435*4882a593Smuzhiyun *err = -1;
436*4882a593Smuzhiyun return;
437*4882a593Smuzhiyun }
438*4882a593Smuzhiyun dst->value = sk->sk_write_queue.qlen;
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun
META_COLLECTOR(int_sk_wmem_queued)441*4882a593Smuzhiyun META_COLLECTOR(int_sk_wmem_queued)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun if (!sk) {
446*4882a593Smuzhiyun *err = -1;
447*4882a593Smuzhiyun return;
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun dst->value = READ_ONCE(sk->sk_wmem_queued);
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun
META_COLLECTOR(int_sk_fwd_alloc)452*4882a593Smuzhiyun META_COLLECTOR(int_sk_fwd_alloc)
453*4882a593Smuzhiyun {
454*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun if (!sk) {
457*4882a593Smuzhiyun *err = -1;
458*4882a593Smuzhiyun return;
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun dst->value = sk->sk_forward_alloc;
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun
META_COLLECTOR(int_sk_sndbuf)463*4882a593Smuzhiyun META_COLLECTOR(int_sk_sndbuf)
464*4882a593Smuzhiyun {
465*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun if (!sk) {
468*4882a593Smuzhiyun *err = -1;
469*4882a593Smuzhiyun return;
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun dst->value = sk->sk_sndbuf;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun
META_COLLECTOR(int_sk_alloc)474*4882a593Smuzhiyun META_COLLECTOR(int_sk_alloc)
475*4882a593Smuzhiyun {
476*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun if (!sk) {
479*4882a593Smuzhiyun *err = -1;
480*4882a593Smuzhiyun return;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun dst->value = (__force int) sk->sk_allocation;
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun
META_COLLECTOR(int_sk_hash)485*4882a593Smuzhiyun META_COLLECTOR(int_sk_hash)
486*4882a593Smuzhiyun {
487*4882a593Smuzhiyun if (skip_nonlocal(skb)) {
488*4882a593Smuzhiyun *err = -1;
489*4882a593Smuzhiyun return;
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun dst->value = skb->sk->sk_hash;
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun
META_COLLECTOR(int_sk_lingertime)494*4882a593Smuzhiyun META_COLLECTOR(int_sk_lingertime)
495*4882a593Smuzhiyun {
496*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun if (!sk) {
499*4882a593Smuzhiyun *err = -1;
500*4882a593Smuzhiyun return;
501*4882a593Smuzhiyun }
502*4882a593Smuzhiyun dst->value = sk->sk_lingertime / HZ;
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun
META_COLLECTOR(int_sk_err_qlen)505*4882a593Smuzhiyun META_COLLECTOR(int_sk_err_qlen)
506*4882a593Smuzhiyun {
507*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun if (!sk) {
510*4882a593Smuzhiyun *err = -1;
511*4882a593Smuzhiyun return;
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun dst->value = sk->sk_error_queue.qlen;
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun
META_COLLECTOR(int_sk_ack_bl)516*4882a593Smuzhiyun META_COLLECTOR(int_sk_ack_bl)
517*4882a593Smuzhiyun {
518*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun if (!sk) {
521*4882a593Smuzhiyun *err = -1;
522*4882a593Smuzhiyun return;
523*4882a593Smuzhiyun }
524*4882a593Smuzhiyun dst->value = READ_ONCE(sk->sk_ack_backlog);
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun
META_COLLECTOR(int_sk_max_ack_bl)527*4882a593Smuzhiyun META_COLLECTOR(int_sk_max_ack_bl)
528*4882a593Smuzhiyun {
529*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun if (!sk) {
532*4882a593Smuzhiyun *err = -1;
533*4882a593Smuzhiyun return;
534*4882a593Smuzhiyun }
535*4882a593Smuzhiyun dst->value = READ_ONCE(sk->sk_max_ack_backlog);
536*4882a593Smuzhiyun }
537*4882a593Smuzhiyun
META_COLLECTOR(int_sk_prio)538*4882a593Smuzhiyun META_COLLECTOR(int_sk_prio)
539*4882a593Smuzhiyun {
540*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun if (!sk) {
543*4882a593Smuzhiyun *err = -1;
544*4882a593Smuzhiyun return;
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun dst->value = sk->sk_priority;
547*4882a593Smuzhiyun }
548*4882a593Smuzhiyun
META_COLLECTOR(int_sk_rcvlowat)549*4882a593Smuzhiyun META_COLLECTOR(int_sk_rcvlowat)
550*4882a593Smuzhiyun {
551*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun if (!sk) {
554*4882a593Smuzhiyun *err = -1;
555*4882a593Smuzhiyun return;
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun dst->value = READ_ONCE(sk->sk_rcvlowat);
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun
META_COLLECTOR(int_sk_rcvtimeo)560*4882a593Smuzhiyun META_COLLECTOR(int_sk_rcvtimeo)
561*4882a593Smuzhiyun {
562*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun if (!sk) {
565*4882a593Smuzhiyun *err = -1;
566*4882a593Smuzhiyun return;
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun dst->value = sk->sk_rcvtimeo / HZ;
569*4882a593Smuzhiyun }
570*4882a593Smuzhiyun
META_COLLECTOR(int_sk_sndtimeo)571*4882a593Smuzhiyun META_COLLECTOR(int_sk_sndtimeo)
572*4882a593Smuzhiyun {
573*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun if (!sk) {
576*4882a593Smuzhiyun *err = -1;
577*4882a593Smuzhiyun return;
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun dst->value = sk->sk_sndtimeo / HZ;
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun
META_COLLECTOR(int_sk_sendmsg_off)582*4882a593Smuzhiyun META_COLLECTOR(int_sk_sendmsg_off)
583*4882a593Smuzhiyun {
584*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun if (!sk) {
587*4882a593Smuzhiyun *err = -1;
588*4882a593Smuzhiyun return;
589*4882a593Smuzhiyun }
590*4882a593Smuzhiyun dst->value = sk->sk_frag.offset;
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun
META_COLLECTOR(int_sk_write_pend)593*4882a593Smuzhiyun META_COLLECTOR(int_sk_write_pend)
594*4882a593Smuzhiyun {
595*4882a593Smuzhiyun const struct sock *sk = skb_to_full_sk(skb);
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun if (!sk) {
598*4882a593Smuzhiyun *err = -1;
599*4882a593Smuzhiyun return;
600*4882a593Smuzhiyun }
601*4882a593Smuzhiyun dst->value = sk->sk_write_pending;
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun /**************************************************************************
605*4882a593Smuzhiyun * Meta value collectors assignment table
606*4882a593Smuzhiyun **************************************************************************/
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun struct meta_ops {
609*4882a593Smuzhiyun void (*get)(struct sk_buff *, struct tcf_pkt_info *,
610*4882a593Smuzhiyun struct meta_value *, struct meta_obj *, int *);
611*4882a593Smuzhiyun };
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun #define META_ID(name) TCF_META_ID_##name
614*4882a593Smuzhiyun #define META_FUNC(name) { .get = meta_##name }
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun /* Meta value operations table listing all meta value collectors and
617*4882a593Smuzhiyun * assigns them to a type and meta id. */
618*4882a593Smuzhiyun static struct meta_ops __meta_ops[TCF_META_TYPE_MAX + 1][TCF_META_ID_MAX + 1] = {
619*4882a593Smuzhiyun [TCF_META_TYPE_VAR] = {
620*4882a593Smuzhiyun [META_ID(DEV)] = META_FUNC(var_dev),
621*4882a593Smuzhiyun [META_ID(SK_BOUND_IF)] = META_FUNC(var_sk_bound_if),
622*4882a593Smuzhiyun },
623*4882a593Smuzhiyun [TCF_META_TYPE_INT] = {
624*4882a593Smuzhiyun [META_ID(RANDOM)] = META_FUNC(int_random),
625*4882a593Smuzhiyun [META_ID(LOADAVG_0)] = META_FUNC(int_loadavg_0),
626*4882a593Smuzhiyun [META_ID(LOADAVG_1)] = META_FUNC(int_loadavg_1),
627*4882a593Smuzhiyun [META_ID(LOADAVG_2)] = META_FUNC(int_loadavg_2),
628*4882a593Smuzhiyun [META_ID(DEV)] = META_FUNC(int_dev),
629*4882a593Smuzhiyun [META_ID(PRIORITY)] = META_FUNC(int_priority),
630*4882a593Smuzhiyun [META_ID(PROTOCOL)] = META_FUNC(int_protocol),
631*4882a593Smuzhiyun [META_ID(PKTTYPE)] = META_FUNC(int_pkttype),
632*4882a593Smuzhiyun [META_ID(PKTLEN)] = META_FUNC(int_pktlen),
633*4882a593Smuzhiyun [META_ID(DATALEN)] = META_FUNC(int_datalen),
634*4882a593Smuzhiyun [META_ID(MACLEN)] = META_FUNC(int_maclen),
635*4882a593Smuzhiyun [META_ID(NFMARK)] = META_FUNC(int_mark),
636*4882a593Smuzhiyun [META_ID(TCINDEX)] = META_FUNC(int_tcindex),
637*4882a593Smuzhiyun [META_ID(RTCLASSID)] = META_FUNC(int_rtclassid),
638*4882a593Smuzhiyun [META_ID(RTIIF)] = META_FUNC(int_rtiif),
639*4882a593Smuzhiyun [META_ID(SK_FAMILY)] = META_FUNC(int_sk_family),
640*4882a593Smuzhiyun [META_ID(SK_STATE)] = META_FUNC(int_sk_state),
641*4882a593Smuzhiyun [META_ID(SK_REUSE)] = META_FUNC(int_sk_reuse),
642*4882a593Smuzhiyun [META_ID(SK_BOUND_IF)] = META_FUNC(int_sk_bound_if),
643*4882a593Smuzhiyun [META_ID(SK_REFCNT)] = META_FUNC(int_sk_refcnt),
644*4882a593Smuzhiyun [META_ID(SK_RCVBUF)] = META_FUNC(int_sk_rcvbuf),
645*4882a593Smuzhiyun [META_ID(SK_SNDBUF)] = META_FUNC(int_sk_sndbuf),
646*4882a593Smuzhiyun [META_ID(SK_SHUTDOWN)] = META_FUNC(int_sk_shutdown),
647*4882a593Smuzhiyun [META_ID(SK_PROTO)] = META_FUNC(int_sk_proto),
648*4882a593Smuzhiyun [META_ID(SK_TYPE)] = META_FUNC(int_sk_type),
649*4882a593Smuzhiyun [META_ID(SK_RMEM_ALLOC)] = META_FUNC(int_sk_rmem_alloc),
650*4882a593Smuzhiyun [META_ID(SK_WMEM_ALLOC)] = META_FUNC(int_sk_wmem_alloc),
651*4882a593Smuzhiyun [META_ID(SK_OMEM_ALLOC)] = META_FUNC(int_sk_omem_alloc),
652*4882a593Smuzhiyun [META_ID(SK_WMEM_QUEUED)] = META_FUNC(int_sk_wmem_queued),
653*4882a593Smuzhiyun [META_ID(SK_RCV_QLEN)] = META_FUNC(int_sk_rcv_qlen),
654*4882a593Smuzhiyun [META_ID(SK_SND_QLEN)] = META_FUNC(int_sk_snd_qlen),
655*4882a593Smuzhiyun [META_ID(SK_ERR_QLEN)] = META_FUNC(int_sk_err_qlen),
656*4882a593Smuzhiyun [META_ID(SK_FORWARD_ALLOCS)] = META_FUNC(int_sk_fwd_alloc),
657*4882a593Smuzhiyun [META_ID(SK_ALLOCS)] = META_FUNC(int_sk_alloc),
658*4882a593Smuzhiyun [META_ID(SK_HASH)] = META_FUNC(int_sk_hash),
659*4882a593Smuzhiyun [META_ID(SK_LINGERTIME)] = META_FUNC(int_sk_lingertime),
660*4882a593Smuzhiyun [META_ID(SK_ACK_BACKLOG)] = META_FUNC(int_sk_ack_bl),
661*4882a593Smuzhiyun [META_ID(SK_MAX_ACK_BACKLOG)] = META_FUNC(int_sk_max_ack_bl),
662*4882a593Smuzhiyun [META_ID(SK_PRIO)] = META_FUNC(int_sk_prio),
663*4882a593Smuzhiyun [META_ID(SK_RCVLOWAT)] = META_FUNC(int_sk_rcvlowat),
664*4882a593Smuzhiyun [META_ID(SK_RCVTIMEO)] = META_FUNC(int_sk_rcvtimeo),
665*4882a593Smuzhiyun [META_ID(SK_SNDTIMEO)] = META_FUNC(int_sk_sndtimeo),
666*4882a593Smuzhiyun [META_ID(SK_SENDMSG_OFF)] = META_FUNC(int_sk_sendmsg_off),
667*4882a593Smuzhiyun [META_ID(SK_WRITE_PENDING)] = META_FUNC(int_sk_write_pend),
668*4882a593Smuzhiyun [META_ID(VLAN_TAG)] = META_FUNC(int_vlan_tag),
669*4882a593Smuzhiyun [META_ID(RXHASH)] = META_FUNC(int_rxhash),
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun };
672*4882a593Smuzhiyun
meta_ops(struct meta_value * val)673*4882a593Smuzhiyun static inline struct meta_ops *meta_ops(struct meta_value *val)
674*4882a593Smuzhiyun {
675*4882a593Smuzhiyun return &__meta_ops[meta_type(val)][meta_id(val)];
676*4882a593Smuzhiyun }
677*4882a593Smuzhiyun
678*4882a593Smuzhiyun /**************************************************************************
679*4882a593Smuzhiyun * Type specific operations for TCF_META_TYPE_VAR
680*4882a593Smuzhiyun **************************************************************************/
681*4882a593Smuzhiyun
meta_var_compare(struct meta_obj * a,struct meta_obj * b)682*4882a593Smuzhiyun static int meta_var_compare(struct meta_obj *a, struct meta_obj *b)
683*4882a593Smuzhiyun {
684*4882a593Smuzhiyun int r = a->len - b->len;
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun if (r == 0)
687*4882a593Smuzhiyun r = memcmp((void *) a->value, (void *) b->value, a->len);
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun return r;
690*4882a593Smuzhiyun }
691*4882a593Smuzhiyun
meta_var_change(struct meta_value * dst,struct nlattr * nla)692*4882a593Smuzhiyun static int meta_var_change(struct meta_value *dst, struct nlattr *nla)
693*4882a593Smuzhiyun {
694*4882a593Smuzhiyun int len = nla_len(nla);
695*4882a593Smuzhiyun
696*4882a593Smuzhiyun dst->val = (unsigned long)kmemdup(nla_data(nla), len, GFP_KERNEL);
697*4882a593Smuzhiyun if (dst->val == 0UL)
698*4882a593Smuzhiyun return -ENOMEM;
699*4882a593Smuzhiyun dst->len = len;
700*4882a593Smuzhiyun return 0;
701*4882a593Smuzhiyun }
702*4882a593Smuzhiyun
meta_var_destroy(struct meta_value * v)703*4882a593Smuzhiyun static void meta_var_destroy(struct meta_value *v)
704*4882a593Smuzhiyun {
705*4882a593Smuzhiyun kfree((void *) v->val);
706*4882a593Smuzhiyun }
707*4882a593Smuzhiyun
meta_var_apply_extras(struct meta_value * v,struct meta_obj * dst)708*4882a593Smuzhiyun static void meta_var_apply_extras(struct meta_value *v,
709*4882a593Smuzhiyun struct meta_obj *dst)
710*4882a593Smuzhiyun {
711*4882a593Smuzhiyun int shift = v->hdr.shift;
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun if (shift && shift < dst->len)
714*4882a593Smuzhiyun dst->len -= shift;
715*4882a593Smuzhiyun }
716*4882a593Smuzhiyun
meta_var_dump(struct sk_buff * skb,struct meta_value * v,int tlv)717*4882a593Smuzhiyun static int meta_var_dump(struct sk_buff *skb, struct meta_value *v, int tlv)
718*4882a593Smuzhiyun {
719*4882a593Smuzhiyun if (v->val && v->len &&
720*4882a593Smuzhiyun nla_put(skb, tlv, v->len, (void *) v->val))
721*4882a593Smuzhiyun goto nla_put_failure;
722*4882a593Smuzhiyun return 0;
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun nla_put_failure:
725*4882a593Smuzhiyun return -1;
726*4882a593Smuzhiyun }
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun /**************************************************************************
729*4882a593Smuzhiyun * Type specific operations for TCF_META_TYPE_INT
730*4882a593Smuzhiyun **************************************************************************/
731*4882a593Smuzhiyun
meta_int_compare(struct meta_obj * a,struct meta_obj * b)732*4882a593Smuzhiyun static int meta_int_compare(struct meta_obj *a, struct meta_obj *b)
733*4882a593Smuzhiyun {
734*4882a593Smuzhiyun /* Let gcc optimize it, the unlikely is not really based on
735*4882a593Smuzhiyun * some numbers but jump free code for mismatches seems
736*4882a593Smuzhiyun * more logical. */
737*4882a593Smuzhiyun if (unlikely(a->value == b->value))
738*4882a593Smuzhiyun return 0;
739*4882a593Smuzhiyun else if (a->value < b->value)
740*4882a593Smuzhiyun return -1;
741*4882a593Smuzhiyun else
742*4882a593Smuzhiyun return 1;
743*4882a593Smuzhiyun }
744*4882a593Smuzhiyun
meta_int_change(struct meta_value * dst,struct nlattr * nla)745*4882a593Smuzhiyun static int meta_int_change(struct meta_value *dst, struct nlattr *nla)
746*4882a593Smuzhiyun {
747*4882a593Smuzhiyun if (nla_len(nla) >= sizeof(unsigned long)) {
748*4882a593Smuzhiyun dst->val = *(unsigned long *) nla_data(nla);
749*4882a593Smuzhiyun dst->len = sizeof(unsigned long);
750*4882a593Smuzhiyun } else if (nla_len(nla) == sizeof(u32)) {
751*4882a593Smuzhiyun dst->val = nla_get_u32(nla);
752*4882a593Smuzhiyun dst->len = sizeof(u32);
753*4882a593Smuzhiyun } else
754*4882a593Smuzhiyun return -EINVAL;
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun return 0;
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun
meta_int_apply_extras(struct meta_value * v,struct meta_obj * dst)759*4882a593Smuzhiyun static void meta_int_apply_extras(struct meta_value *v,
760*4882a593Smuzhiyun struct meta_obj *dst)
761*4882a593Smuzhiyun {
762*4882a593Smuzhiyun if (v->hdr.shift)
763*4882a593Smuzhiyun dst->value >>= v->hdr.shift;
764*4882a593Smuzhiyun
765*4882a593Smuzhiyun if (v->val)
766*4882a593Smuzhiyun dst->value &= v->val;
767*4882a593Smuzhiyun }
768*4882a593Smuzhiyun
meta_int_dump(struct sk_buff * skb,struct meta_value * v,int tlv)769*4882a593Smuzhiyun static int meta_int_dump(struct sk_buff *skb, struct meta_value *v, int tlv)
770*4882a593Smuzhiyun {
771*4882a593Smuzhiyun if (v->len == sizeof(unsigned long)) {
772*4882a593Smuzhiyun if (nla_put(skb, tlv, sizeof(unsigned long), &v->val))
773*4882a593Smuzhiyun goto nla_put_failure;
774*4882a593Smuzhiyun } else if (v->len == sizeof(u32)) {
775*4882a593Smuzhiyun if (nla_put_u32(skb, tlv, v->val))
776*4882a593Smuzhiyun goto nla_put_failure;
777*4882a593Smuzhiyun }
778*4882a593Smuzhiyun
779*4882a593Smuzhiyun return 0;
780*4882a593Smuzhiyun
781*4882a593Smuzhiyun nla_put_failure:
782*4882a593Smuzhiyun return -1;
783*4882a593Smuzhiyun }
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun /**************************************************************************
786*4882a593Smuzhiyun * Type specific operations table
787*4882a593Smuzhiyun **************************************************************************/
788*4882a593Smuzhiyun
789*4882a593Smuzhiyun struct meta_type_ops {
790*4882a593Smuzhiyun void (*destroy)(struct meta_value *);
791*4882a593Smuzhiyun int (*compare)(struct meta_obj *, struct meta_obj *);
792*4882a593Smuzhiyun int (*change)(struct meta_value *, struct nlattr *);
793*4882a593Smuzhiyun void (*apply_extras)(struct meta_value *, struct meta_obj *);
794*4882a593Smuzhiyun int (*dump)(struct sk_buff *, struct meta_value *, int);
795*4882a593Smuzhiyun };
796*4882a593Smuzhiyun
797*4882a593Smuzhiyun static const struct meta_type_ops __meta_type_ops[TCF_META_TYPE_MAX + 1] = {
798*4882a593Smuzhiyun [TCF_META_TYPE_VAR] = {
799*4882a593Smuzhiyun .destroy = meta_var_destroy,
800*4882a593Smuzhiyun .compare = meta_var_compare,
801*4882a593Smuzhiyun .change = meta_var_change,
802*4882a593Smuzhiyun .apply_extras = meta_var_apply_extras,
803*4882a593Smuzhiyun .dump = meta_var_dump
804*4882a593Smuzhiyun },
805*4882a593Smuzhiyun [TCF_META_TYPE_INT] = {
806*4882a593Smuzhiyun .compare = meta_int_compare,
807*4882a593Smuzhiyun .change = meta_int_change,
808*4882a593Smuzhiyun .apply_extras = meta_int_apply_extras,
809*4882a593Smuzhiyun .dump = meta_int_dump
810*4882a593Smuzhiyun }
811*4882a593Smuzhiyun };
812*4882a593Smuzhiyun
meta_type_ops(struct meta_value * v)813*4882a593Smuzhiyun static inline const struct meta_type_ops *meta_type_ops(struct meta_value *v)
814*4882a593Smuzhiyun {
815*4882a593Smuzhiyun return &__meta_type_ops[meta_type(v)];
816*4882a593Smuzhiyun }
817*4882a593Smuzhiyun
818*4882a593Smuzhiyun /**************************************************************************
819*4882a593Smuzhiyun * Core
820*4882a593Smuzhiyun **************************************************************************/
821*4882a593Smuzhiyun
meta_get(struct sk_buff * skb,struct tcf_pkt_info * info,struct meta_value * v,struct meta_obj * dst)822*4882a593Smuzhiyun static int meta_get(struct sk_buff *skb, struct tcf_pkt_info *info,
823*4882a593Smuzhiyun struct meta_value *v, struct meta_obj *dst)
824*4882a593Smuzhiyun {
825*4882a593Smuzhiyun int err = 0;
826*4882a593Smuzhiyun
827*4882a593Smuzhiyun if (meta_id(v) == TCF_META_ID_VALUE) {
828*4882a593Smuzhiyun dst->value = v->val;
829*4882a593Smuzhiyun dst->len = v->len;
830*4882a593Smuzhiyun return 0;
831*4882a593Smuzhiyun }
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun meta_ops(v)->get(skb, info, v, dst, &err);
834*4882a593Smuzhiyun if (err < 0)
835*4882a593Smuzhiyun return err;
836*4882a593Smuzhiyun
837*4882a593Smuzhiyun if (meta_type_ops(v)->apply_extras)
838*4882a593Smuzhiyun meta_type_ops(v)->apply_extras(v, dst);
839*4882a593Smuzhiyun
840*4882a593Smuzhiyun return 0;
841*4882a593Smuzhiyun }
842*4882a593Smuzhiyun
em_meta_match(struct sk_buff * skb,struct tcf_ematch * m,struct tcf_pkt_info * info)843*4882a593Smuzhiyun static int em_meta_match(struct sk_buff *skb, struct tcf_ematch *m,
844*4882a593Smuzhiyun struct tcf_pkt_info *info)
845*4882a593Smuzhiyun {
846*4882a593Smuzhiyun int r;
847*4882a593Smuzhiyun struct meta_match *meta = (struct meta_match *) m->data;
848*4882a593Smuzhiyun struct meta_obj l_value, r_value;
849*4882a593Smuzhiyun
850*4882a593Smuzhiyun if (meta_get(skb, info, &meta->lvalue, &l_value) < 0 ||
851*4882a593Smuzhiyun meta_get(skb, info, &meta->rvalue, &r_value) < 0)
852*4882a593Smuzhiyun return 0;
853*4882a593Smuzhiyun
854*4882a593Smuzhiyun r = meta_type_ops(&meta->lvalue)->compare(&l_value, &r_value);
855*4882a593Smuzhiyun
856*4882a593Smuzhiyun switch (meta->lvalue.hdr.op) {
857*4882a593Smuzhiyun case TCF_EM_OPND_EQ:
858*4882a593Smuzhiyun return !r;
859*4882a593Smuzhiyun case TCF_EM_OPND_LT:
860*4882a593Smuzhiyun return r < 0;
861*4882a593Smuzhiyun case TCF_EM_OPND_GT:
862*4882a593Smuzhiyun return r > 0;
863*4882a593Smuzhiyun }
864*4882a593Smuzhiyun
865*4882a593Smuzhiyun return 0;
866*4882a593Smuzhiyun }
867*4882a593Smuzhiyun
meta_delete(struct meta_match * meta)868*4882a593Smuzhiyun static void meta_delete(struct meta_match *meta)
869*4882a593Smuzhiyun {
870*4882a593Smuzhiyun if (meta) {
871*4882a593Smuzhiyun const struct meta_type_ops *ops = meta_type_ops(&meta->lvalue);
872*4882a593Smuzhiyun
873*4882a593Smuzhiyun if (ops && ops->destroy) {
874*4882a593Smuzhiyun ops->destroy(&meta->lvalue);
875*4882a593Smuzhiyun ops->destroy(&meta->rvalue);
876*4882a593Smuzhiyun }
877*4882a593Smuzhiyun }
878*4882a593Smuzhiyun
879*4882a593Smuzhiyun kfree(meta);
880*4882a593Smuzhiyun }
881*4882a593Smuzhiyun
meta_change_data(struct meta_value * dst,struct nlattr * nla)882*4882a593Smuzhiyun static inline int meta_change_data(struct meta_value *dst, struct nlattr *nla)
883*4882a593Smuzhiyun {
884*4882a593Smuzhiyun if (nla) {
885*4882a593Smuzhiyun if (nla_len(nla) == 0)
886*4882a593Smuzhiyun return -EINVAL;
887*4882a593Smuzhiyun
888*4882a593Smuzhiyun return meta_type_ops(dst)->change(dst, nla);
889*4882a593Smuzhiyun }
890*4882a593Smuzhiyun
891*4882a593Smuzhiyun return 0;
892*4882a593Smuzhiyun }
893*4882a593Smuzhiyun
meta_is_supported(struct meta_value * val)894*4882a593Smuzhiyun static inline int meta_is_supported(struct meta_value *val)
895*4882a593Smuzhiyun {
896*4882a593Smuzhiyun return !meta_id(val) || meta_ops(val)->get;
897*4882a593Smuzhiyun }
898*4882a593Smuzhiyun
899*4882a593Smuzhiyun static const struct nla_policy meta_policy[TCA_EM_META_MAX + 1] = {
900*4882a593Smuzhiyun [TCA_EM_META_HDR] = { .len = sizeof(struct tcf_meta_hdr) },
901*4882a593Smuzhiyun };
902*4882a593Smuzhiyun
em_meta_change(struct net * net,void * data,int len,struct tcf_ematch * m)903*4882a593Smuzhiyun static int em_meta_change(struct net *net, void *data, int len,
904*4882a593Smuzhiyun struct tcf_ematch *m)
905*4882a593Smuzhiyun {
906*4882a593Smuzhiyun int err;
907*4882a593Smuzhiyun struct nlattr *tb[TCA_EM_META_MAX + 1];
908*4882a593Smuzhiyun struct tcf_meta_hdr *hdr;
909*4882a593Smuzhiyun struct meta_match *meta = NULL;
910*4882a593Smuzhiyun
911*4882a593Smuzhiyun err = nla_parse_deprecated(tb, TCA_EM_META_MAX, data, len,
912*4882a593Smuzhiyun meta_policy, NULL);
913*4882a593Smuzhiyun if (err < 0)
914*4882a593Smuzhiyun goto errout;
915*4882a593Smuzhiyun
916*4882a593Smuzhiyun err = -EINVAL;
917*4882a593Smuzhiyun if (tb[TCA_EM_META_HDR] == NULL)
918*4882a593Smuzhiyun goto errout;
919*4882a593Smuzhiyun hdr = nla_data(tb[TCA_EM_META_HDR]);
920*4882a593Smuzhiyun
921*4882a593Smuzhiyun if (TCF_META_TYPE(hdr->left.kind) != TCF_META_TYPE(hdr->right.kind) ||
922*4882a593Smuzhiyun TCF_META_TYPE(hdr->left.kind) > TCF_META_TYPE_MAX ||
923*4882a593Smuzhiyun TCF_META_ID(hdr->left.kind) > TCF_META_ID_MAX ||
924*4882a593Smuzhiyun TCF_META_ID(hdr->right.kind) > TCF_META_ID_MAX)
925*4882a593Smuzhiyun goto errout;
926*4882a593Smuzhiyun
927*4882a593Smuzhiyun meta = kzalloc(sizeof(*meta), GFP_KERNEL);
928*4882a593Smuzhiyun if (meta == NULL) {
929*4882a593Smuzhiyun err = -ENOMEM;
930*4882a593Smuzhiyun goto errout;
931*4882a593Smuzhiyun }
932*4882a593Smuzhiyun
933*4882a593Smuzhiyun memcpy(&meta->lvalue.hdr, &hdr->left, sizeof(hdr->left));
934*4882a593Smuzhiyun memcpy(&meta->rvalue.hdr, &hdr->right, sizeof(hdr->right));
935*4882a593Smuzhiyun
936*4882a593Smuzhiyun if (!meta_is_supported(&meta->lvalue) ||
937*4882a593Smuzhiyun !meta_is_supported(&meta->rvalue)) {
938*4882a593Smuzhiyun err = -EOPNOTSUPP;
939*4882a593Smuzhiyun goto errout;
940*4882a593Smuzhiyun }
941*4882a593Smuzhiyun
942*4882a593Smuzhiyun if (meta_change_data(&meta->lvalue, tb[TCA_EM_META_LVALUE]) < 0 ||
943*4882a593Smuzhiyun meta_change_data(&meta->rvalue, tb[TCA_EM_META_RVALUE]) < 0)
944*4882a593Smuzhiyun goto errout;
945*4882a593Smuzhiyun
946*4882a593Smuzhiyun m->datalen = sizeof(*meta);
947*4882a593Smuzhiyun m->data = (unsigned long) meta;
948*4882a593Smuzhiyun
949*4882a593Smuzhiyun err = 0;
950*4882a593Smuzhiyun errout:
951*4882a593Smuzhiyun if (err && meta)
952*4882a593Smuzhiyun meta_delete(meta);
953*4882a593Smuzhiyun return err;
954*4882a593Smuzhiyun }
955*4882a593Smuzhiyun
em_meta_destroy(struct tcf_ematch * m)956*4882a593Smuzhiyun static void em_meta_destroy(struct tcf_ematch *m)
957*4882a593Smuzhiyun {
958*4882a593Smuzhiyun if (m)
959*4882a593Smuzhiyun meta_delete((struct meta_match *) m->data);
960*4882a593Smuzhiyun }
961*4882a593Smuzhiyun
em_meta_dump(struct sk_buff * skb,struct tcf_ematch * em)962*4882a593Smuzhiyun static int em_meta_dump(struct sk_buff *skb, struct tcf_ematch *em)
963*4882a593Smuzhiyun {
964*4882a593Smuzhiyun struct meta_match *meta = (struct meta_match *) em->data;
965*4882a593Smuzhiyun struct tcf_meta_hdr hdr;
966*4882a593Smuzhiyun const struct meta_type_ops *ops;
967*4882a593Smuzhiyun
968*4882a593Smuzhiyun memset(&hdr, 0, sizeof(hdr));
969*4882a593Smuzhiyun memcpy(&hdr.left, &meta->lvalue.hdr, sizeof(hdr.left));
970*4882a593Smuzhiyun memcpy(&hdr.right, &meta->rvalue.hdr, sizeof(hdr.right));
971*4882a593Smuzhiyun
972*4882a593Smuzhiyun if (nla_put(skb, TCA_EM_META_HDR, sizeof(hdr), &hdr))
973*4882a593Smuzhiyun goto nla_put_failure;
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun ops = meta_type_ops(&meta->lvalue);
976*4882a593Smuzhiyun if (ops->dump(skb, &meta->lvalue, TCA_EM_META_LVALUE) < 0 ||
977*4882a593Smuzhiyun ops->dump(skb, &meta->rvalue, TCA_EM_META_RVALUE) < 0)
978*4882a593Smuzhiyun goto nla_put_failure;
979*4882a593Smuzhiyun
980*4882a593Smuzhiyun return 0;
981*4882a593Smuzhiyun
982*4882a593Smuzhiyun nla_put_failure:
983*4882a593Smuzhiyun return -1;
984*4882a593Smuzhiyun }
985*4882a593Smuzhiyun
986*4882a593Smuzhiyun static struct tcf_ematch_ops em_meta_ops = {
987*4882a593Smuzhiyun .kind = TCF_EM_META,
988*4882a593Smuzhiyun .change = em_meta_change,
989*4882a593Smuzhiyun .match = em_meta_match,
990*4882a593Smuzhiyun .destroy = em_meta_destroy,
991*4882a593Smuzhiyun .dump = em_meta_dump,
992*4882a593Smuzhiyun .owner = THIS_MODULE,
993*4882a593Smuzhiyun .link = LIST_HEAD_INIT(em_meta_ops.link)
994*4882a593Smuzhiyun };
995*4882a593Smuzhiyun
init_em_meta(void)996*4882a593Smuzhiyun static int __init init_em_meta(void)
997*4882a593Smuzhiyun {
998*4882a593Smuzhiyun return tcf_em_register(&em_meta_ops);
999*4882a593Smuzhiyun }
1000*4882a593Smuzhiyun
exit_em_meta(void)1001*4882a593Smuzhiyun static void __exit exit_em_meta(void)
1002*4882a593Smuzhiyun {
1003*4882a593Smuzhiyun tcf_em_unregister(&em_meta_ops);
1004*4882a593Smuzhiyun }
1005*4882a593Smuzhiyun
1006*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1007*4882a593Smuzhiyun
1008*4882a593Smuzhiyun module_init(init_em_meta);
1009*4882a593Smuzhiyun module_exit(exit_em_meta);
1010*4882a593Smuzhiyun
1011*4882a593Smuzhiyun MODULE_ALIAS_TCF_EMATCH(TCF_EM_META);
1012