cls_flow.c 16.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * net/sched/cls_flow.c		Generic flow classifier
 *
 * Copyright (c) 2007, 2008 Patrick McHardy <kaber@trash.net>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/jhash.h>
#include <linux/random.h>
#include <linux/pkt_cls.h>
#include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
22
#include <linux/if_vlan.h>
23
#include <linux/slab.h>
24
#include <linux/module.h>
25
#include <net/inet_sock.h>
26 27 28 29

#include <net/pkt_cls.h>
#include <net/ip.h>
#include <net/route.h>
30
#include <net/flow_dissector.h>
E
Eric Dumazet 已提交
31

32
#if IS_ENABLED(CONFIG_NF_CONNTRACK)
33 34 35 36 37
#include <net/netfilter/nf_conntrack.h>
#endif

struct flow_head {
	struct list_head	filters;
J
John Fastabend 已提交
38
	struct rcu_head		rcu;
39 40 41 42 43 44
};

struct flow_filter {
	struct list_head	list;
	struct tcf_exts		exts;
	struct tcf_ematch_tree	ematches;
J
John Fastabend 已提交
45
	struct tcf_proto	*tp;
46 47
	struct timer_list	perturb_timer;
	u32			perturb_period;
48 49 50 51 52 53 54 55 56 57 58
	u32			handle;

	u32			nkeys;
	u32			keymask;
	u32			mode;
	u32			mask;
	u32			xor;
	u32			rshift;
	u32			addend;
	u32			divisor;
	u32			baseclass;
59
	u32			hashrnd;
J
John Fastabend 已提交
60
	struct rcu_head		rcu;
61 62 63 64 65 66 67 68 69
};

static inline u32 addr_fold(void *addr)
{
	unsigned long a = (unsigned long)addr;

	return (a & 0xFFFFFFFF) ^ (BITS_PER_LONG > 32 ? a >> 32 : 0);
}

E
Eric Dumazet 已提交
70
static u32 flow_get_src(const struct sk_buff *skb, const struct flow_keys *flow)
71
{
72 73 74 75 76
	__be32 src = flow_get_u32_src(flow);

	if (src)
		return ntohl(src);

77
	return addr_fold(skb->sk);
78 79
}

E
Eric Dumazet 已提交
80
static u32 flow_get_dst(const struct sk_buff *skb, const struct flow_keys *flow)
81
{
82 83 84 85 86
	__be32 dst = flow_get_u32_dst(flow);

	if (dst)
		return ntohl(dst);

87
	return addr_fold(skb_dst(skb)) ^ (__force u16) tc_skb_protocol(skb);
88 89
}

J
Jamal Hadi Salim 已提交
90 91
static u32 flow_get_proto(const struct sk_buff *skb,
			  const struct flow_keys *flow)
92
{
93
	return flow->basic.ip_proto;
94 95
}

J
Jamal Hadi Salim 已提交
96 97
static u32 flow_get_proto_src(const struct sk_buff *skb,
			      const struct flow_keys *flow)
98
{
99
	if (flow->ports.ports)
100
		return ntohs(flow->ports.src);
101

102 103 104
	return addr_fold(skb->sk);
}

J
Jamal Hadi Salim 已提交
105 106
static u32 flow_get_proto_dst(const struct sk_buff *skb,
			      const struct flow_keys *flow)
107
{
108
	if (flow->ports.ports)
109
		return ntohs(flow->ports.dst);
110

111
	return addr_fold(skb_dst(skb)) ^ (__force u16) tc_skb_protocol(skb);
112 113 114 115
}

static u32 flow_get_iif(const struct sk_buff *skb)
{
116
	return skb->skb_iif;
117 118 119 120 121 122 123 124 125 126 127 128 129 130
}

static u32 flow_get_priority(const struct sk_buff *skb)
{
	return skb->priority;
}

static u32 flow_get_mark(const struct sk_buff *skb)
{
	return skb->mark;
}

static u32 flow_get_nfct(const struct sk_buff *skb)
{
131
#if IS_ENABLED(CONFIG_NF_CONNTRACK)
132
	return addr_fold(skb_nfct(skb));
133 134 135 136 137
#else
	return 0;
#endif
}

138
#if IS_ENABLED(CONFIG_NF_CONNTRACK)
139 140 141
#define CTTUPLE(skb, member)						\
({									\
	enum ip_conntrack_info ctinfo;					\
142
	const struct nf_conn *ct = nf_ct_get(skb, &ctinfo);		\
143 144 145 146 147 148 149 150 151 152 153 154
	if (ct == NULL)							\
		goto fallback;						\
	ct->tuplehash[CTINFO2DIR(ctinfo)].tuple.member;			\
})
#else
#define CTTUPLE(skb, member)						\
({									\
	goto fallback;							\
	0;								\
})
#endif

J
Jamal Hadi Salim 已提交
155 156
static u32 flow_get_nfct_src(const struct sk_buff *skb,
			     const struct flow_keys *flow)
157
{
158
	switch (tc_skb_protocol(skb)) {
159
	case htons(ETH_P_IP):
160
		return ntohl(CTTUPLE(skb, src.u3.ip));
161
	case htons(ETH_P_IPV6):
162 163 164
		return ntohl(CTTUPLE(skb, src.u3.ip6[3]));
	}
fallback:
E
Eric Dumazet 已提交
165
	return flow_get_src(skb, flow);
166 167
}

J
Jamal Hadi Salim 已提交
168 169
static u32 flow_get_nfct_dst(const struct sk_buff *skb,
			     const struct flow_keys *flow)
170
{
171
	switch (tc_skb_protocol(skb)) {
172
	case htons(ETH_P_IP):
173
		return ntohl(CTTUPLE(skb, dst.u3.ip));
174
	case htons(ETH_P_IPV6):
175 176 177
		return ntohl(CTTUPLE(skb, dst.u3.ip6[3]));
	}
fallback:
E
Eric Dumazet 已提交
178
	return flow_get_dst(skb, flow);
179 180
}

J
Jamal Hadi Salim 已提交
181 182
static u32 flow_get_nfct_proto_src(const struct sk_buff *skb,
				   const struct flow_keys *flow)
183 184 185
{
	return ntohs(CTTUPLE(skb, src.u.all));
fallback:
E
Eric Dumazet 已提交
186
	return flow_get_proto_src(skb, flow);
187 188
}

J
Jamal Hadi Salim 已提交
189 190
static u32 flow_get_nfct_proto_dst(const struct sk_buff *skb,
				   const struct flow_keys *flow)
191 192 193
{
	return ntohs(CTTUPLE(skb, dst.u.all));
fallback:
E
Eric Dumazet 已提交
194
	return flow_get_proto_dst(skb, flow);
195 196 197 198
}

static u32 flow_get_rtclassid(const struct sk_buff *skb)
{
199
#ifdef CONFIG_IP_ROUTE_CLASSID
E
Eric Dumazet 已提交
200 201
	if (skb_dst(skb))
		return skb_dst(skb)->tclassid;
202 203 204 205 206 207
#endif
	return 0;
}

static u32 flow_get_skuid(const struct sk_buff *skb)
{
208 209 210 211 212
	struct sock *sk = skb_to_full_sk(skb);

	if (sk && sk->sk_socket && sk->sk_socket->file) {
		kuid_t skuid = sk->sk_socket->file->f_cred->fsuid;

213 214
		return from_kuid(&init_user_ns, skuid);
	}
215 216 217 218 219
	return 0;
}

static u32 flow_get_skgid(const struct sk_buff *skb)
{
220 221 222 223 224
	struct sock *sk = skb_to_full_sk(skb);

	if (sk && sk->sk_socket && sk->sk_socket->file) {
		kgid_t skgid = sk->sk_socket->file->f_cred->fsgid;

225 226
		return from_kgid(&init_user_ns, skgid);
	}
227 228 229
	return 0;
}

230 231 232 233 234 235 236 237 238
static u32 flow_get_vlan_tag(const struct sk_buff *skb)
{
	u16 uninitialized_var(tag);

	if (vlan_get_tag(skb, &tag) < 0)
		return 0;
	return tag & VLAN_VID_MASK;
}

239 240
static u32 flow_get_rxhash(struct sk_buff *skb)
{
241
	return skb_get_hash(skb);
242 243
}

E
Eric Dumazet 已提交
244
static u32 flow_key_get(struct sk_buff *skb, int key, struct flow_keys *flow)
245 246 247
{
	switch (key) {
	case FLOW_KEY_SRC:
E
Eric Dumazet 已提交
248
		return flow_get_src(skb, flow);
249
	case FLOW_KEY_DST:
E
Eric Dumazet 已提交
250
		return flow_get_dst(skb, flow);
251
	case FLOW_KEY_PROTO:
E
Eric Dumazet 已提交
252
		return flow_get_proto(skb, flow);
253
	case FLOW_KEY_PROTO_SRC:
E
Eric Dumazet 已提交
254
		return flow_get_proto_src(skb, flow);
255
	case FLOW_KEY_PROTO_DST:
E
Eric Dumazet 已提交
256
		return flow_get_proto_dst(skb, flow);
257 258 259 260 261 262 263 264 265
	case FLOW_KEY_IIF:
		return flow_get_iif(skb);
	case FLOW_KEY_PRIORITY:
		return flow_get_priority(skb);
	case FLOW_KEY_MARK:
		return flow_get_mark(skb);
	case FLOW_KEY_NFCT:
		return flow_get_nfct(skb);
	case FLOW_KEY_NFCT_SRC:
E
Eric Dumazet 已提交
266
		return flow_get_nfct_src(skb, flow);
267
	case FLOW_KEY_NFCT_DST:
E
Eric Dumazet 已提交
268
		return flow_get_nfct_dst(skb, flow);
269
	case FLOW_KEY_NFCT_PROTO_SRC:
E
Eric Dumazet 已提交
270
		return flow_get_nfct_proto_src(skb, flow);
271
	case FLOW_KEY_NFCT_PROTO_DST:
E
Eric Dumazet 已提交
272
		return flow_get_nfct_proto_dst(skb, flow);
273 274 275 276 277 278
	case FLOW_KEY_RTCLASSID:
		return flow_get_rtclassid(skb);
	case FLOW_KEY_SKUID:
		return flow_get_skuid(skb);
	case FLOW_KEY_SKGID:
		return flow_get_skgid(skb);
279 280
	case FLOW_KEY_VLAN_TAG:
		return flow_get_vlan_tag(skb);
281 282
	case FLOW_KEY_RXHASH:
		return flow_get_rxhash(skb);
283 284 285 286 287 288
	default:
		WARN_ON(1);
		return 0;
	}
}

E
Eric Dumazet 已提交
289 290 291 292 293 294 295 296 297 298
#define FLOW_KEYS_NEEDED ((1 << FLOW_KEY_SRC) | 		\
			  (1 << FLOW_KEY_DST) |			\
			  (1 << FLOW_KEY_PROTO) |		\
			  (1 << FLOW_KEY_PROTO_SRC) |		\
			  (1 << FLOW_KEY_PROTO_DST) | 		\
			  (1 << FLOW_KEY_NFCT_SRC) |		\
			  (1 << FLOW_KEY_NFCT_DST) |		\
			  (1 << FLOW_KEY_NFCT_PROTO_SRC) |	\
			  (1 << FLOW_KEY_NFCT_PROTO_DST))

299
static int flow_classify(struct sk_buff *skb, const struct tcf_proto *tp,
300 301
			 struct tcf_result *res)
{
J
John Fastabend 已提交
302
	struct flow_head *head = rcu_dereference_bh(tp->root);
303 304 305 306 307 308
	struct flow_filter *f;
	u32 keymask;
	u32 classid;
	unsigned int n, key;
	int r;

J
John Fastabend 已提交
309
	list_for_each_entry_rcu(f, &head->filters, list) {
E
Eric Dumazet 已提交
310
		u32 keys[FLOW_KEY_MAX + 1];
E
Eric Dumazet 已提交
311
		struct flow_keys flow_keys;
312 313 314 315 316

		if (!tcf_em_tree_match(skb, &f->ematches, NULL))
			continue;

		keymask = f->keymask;
E
Eric Dumazet 已提交
317
		if (keymask & FLOW_KEYS_NEEDED)
318
			skb_flow_dissect_flow_keys(skb, &flow_keys, 0);
319 320 321 322

		for (n = 0; n < f->nkeys; n++) {
			key = ffs(keymask) - 1;
			keymask &= ~(1 << key);
E
Eric Dumazet 已提交
323
			keys[n] = flow_key_get(skb, key, &flow_keys);
324 325 326
		}

		if (f->mode == FLOW_MODE_HASH)
327
			classid = jhash2(keys, f->nkeys, f->hashrnd);
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
		else {
			classid = keys[0];
			classid = (classid & f->mask) ^ f->xor;
			classid = (classid >> f->rshift) + f->addend;
		}

		if (f->divisor)
			classid %= f->divisor;

		res->class   = 0;
		res->classid = TC_H_MAKE(f->baseclass, f->baseclass + classid);

		r = tcf_exts_exec(skb, &f->exts, res);
		if (r < 0)
			continue;
		return r;
	}
	return -1;
}

348 349 350 351 352 353 354 355 356
static void flow_perturbation(unsigned long arg)
{
	struct flow_filter *f = (struct flow_filter *)arg;

	get_random_bytes(&f->hashrnd, 4);
	if (f->perturb_period)
		mod_timer(&f->perturb_timer, jiffies + f->perturb_period);
}

357 358 359 360 361 362 363 364 365 366 367 368
static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = {
	[TCA_FLOW_KEYS]		= { .type = NLA_U32 },
	[TCA_FLOW_MODE]		= { .type = NLA_U32 },
	[TCA_FLOW_BASECLASS]	= { .type = NLA_U32 },
	[TCA_FLOW_RSHIFT]	= { .type = NLA_U32 },
	[TCA_FLOW_ADDEND]	= { .type = NLA_U32 },
	[TCA_FLOW_MASK]		= { .type = NLA_U32 },
	[TCA_FLOW_XOR]		= { .type = NLA_U32 },
	[TCA_FLOW_DIVISOR]	= { .type = NLA_U32 },
	[TCA_FLOW_ACT]		= { .type = NLA_NESTED },
	[TCA_FLOW_POLICE]	= { .type = NLA_NESTED },
	[TCA_FLOW_EMATCHES]	= { .type = NLA_NESTED },
369
	[TCA_FLOW_PERTURB]	= { .type = NLA_U32 },
370 371
};

J
John Fastabend 已提交
372 373 374 375 376
static void flow_destroy_filter(struct rcu_head *head)
{
	struct flow_filter *f = container_of(head, struct flow_filter, rcu);

	del_timer_sync(&f->perturb_timer);
377
	tcf_exts_destroy(&f->exts);
378
	tcf_em_tree_destroy(&f->ematches);
J
John Fastabend 已提交
379 380 381
	kfree(f);
}

382
static int flow_change(struct net *net, struct sk_buff *in_skb,
383
		       struct tcf_proto *tp, unsigned long base,
384
		       u32 handle, struct nlattr **tca,
385
		       unsigned long *arg, bool ovr)
386
{
J
John Fastabend 已提交
387 388
	struct flow_head *head = rtnl_dereference(tp->root);
	struct flow_filter *fold, *fnew;
389 390 391
	struct nlattr *opt = tca[TCA_OPTIONS];
	struct nlattr *tb[TCA_FLOW_MAX + 1];
	unsigned int nkeys = 0;
392
	unsigned int perturb_period = 0;
393 394 395 396 397 398 399 400
	u32 baseclass = 0;
	u32 keymask = 0;
	u32 mode;
	int err;

	if (opt == NULL)
		return -EINVAL;

401
	err = nla_parse_nested(tb, TCA_FLOW_MAX, opt, flow_policy, NULL);
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
	if (err < 0)
		return err;

	if (tb[TCA_FLOW_BASECLASS]) {
		baseclass = nla_get_u32(tb[TCA_FLOW_BASECLASS]);
		if (TC_H_MIN(baseclass) == 0)
			return -EINVAL;
	}

	if (tb[TCA_FLOW_KEYS]) {
		keymask = nla_get_u32(tb[TCA_FLOW_KEYS]);

		nkeys = hweight32(keymask);
		if (nkeys == 0)
			return -EINVAL;
417 418 419

		if (fls(keymask) - 1 > FLOW_KEY_MAX)
			return -EOPNOTSUPP;
420 421

		if ((keymask & (FLOW_KEY_SKUID|FLOW_KEY_SKGID)) &&
422
		    sk_user_ns(NETLINK_CB(in_skb).sk) != &init_user_ns)
423
			return -EOPNOTSUPP;
424 425
	}

J
John Fastabend 已提交
426 427
	fnew = kzalloc(sizeof(*fnew), GFP_KERNEL);
	if (!fnew)
428
		return -ENOBUFS;
429 430 431

	err = tcf_em_tree_validate(tp, tb[TCA_FLOW_EMATCHES], &fnew->ematches);
	if (err < 0)
432
		goto err1;
J
John Fastabend 已提交
433

434 435
	err = tcf_exts_init(&fnew->exts, TCA_FLOW_ACT, TCA_FLOW_POLICE);
	if (err < 0)
436 437 438 439 440
		goto err2;

	err = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &fnew->exts, ovr);
	if (err < 0)
		goto err2;
441

J
John Fastabend 已提交
442 443
	fold = (struct flow_filter *)*arg;
	if (fold) {
444
		err = -EINVAL;
J
John Fastabend 已提交
445
		if (fold->handle != handle && handle)
446
			goto err2;
447

J
John Fastabend 已提交
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
		/* Copy fold into fnew */
		fnew->tp = fold->tp;
		fnew->handle = fold->handle;
		fnew->nkeys = fold->nkeys;
		fnew->keymask = fold->keymask;
		fnew->mode = fold->mode;
		fnew->mask = fold->mask;
		fnew->xor = fold->xor;
		fnew->rshift = fold->rshift;
		fnew->addend = fold->addend;
		fnew->divisor = fold->divisor;
		fnew->baseclass = fold->baseclass;
		fnew->hashrnd = fold->hashrnd;

		mode = fold->mode;
463 464 465
		if (tb[TCA_FLOW_MODE])
			mode = nla_get_u32(tb[TCA_FLOW_MODE]);
		if (mode != FLOW_MODE_HASH && nkeys > 1)
466
			goto err2;
467 468

		if (mode == FLOW_MODE_HASH)
J
John Fastabend 已提交
469
			perturb_period = fold->perturb_period;
470 471
		if (tb[TCA_FLOW_PERTURB]) {
			if (mode != FLOW_MODE_HASH)
472
				goto err2;
473 474
			perturb_period = nla_get_u32(tb[TCA_FLOW_PERTURB]) * HZ;
		}
475 476 477
	} else {
		err = -EINVAL;
		if (!handle)
478
			goto err2;
479
		if (!tb[TCA_FLOW_KEYS])
480
			goto err2;
481 482 483 484 485

		mode = FLOW_MODE_MAP;
		if (tb[TCA_FLOW_MODE])
			mode = nla_get_u32(tb[TCA_FLOW_MODE]);
		if (mode != FLOW_MODE_HASH && nkeys > 1)
486
			goto err2;
487

488 489
		if (tb[TCA_FLOW_PERTURB]) {
			if (mode != FLOW_MODE_HASH)
490
				goto err2;
491 492 493
			perturb_period = nla_get_u32(tb[TCA_FLOW_PERTURB]) * HZ;
		}

494 495 496 497 498
		if (TC_H_MAJ(baseclass) == 0)
			baseclass = TC_H_MAKE(tp->q->handle, baseclass);
		if (TC_H_MIN(baseclass) == 0)
			baseclass = TC_H_MAKE(baseclass, 1);

J
John Fastabend 已提交
499 500 501 502
		fnew->handle = handle;
		fnew->mask  = ~0U;
		fnew->tp = tp;
		get_random_bytes(&fnew->hashrnd, 4);
503 504
	}

505 506
	setup_deferrable_timer(&fnew->perturb_timer, flow_perturbation,
			       (unsigned long)fnew);
507

508 509
	netif_keep_dst(qdisc_dev(tp->q));

510
	if (tb[TCA_FLOW_KEYS]) {
J
John Fastabend 已提交
511 512
		fnew->keymask = keymask;
		fnew->nkeys   = nkeys;
513 514
	}

J
John Fastabend 已提交
515
	fnew->mode = mode;
516 517

	if (tb[TCA_FLOW_MASK])
J
John Fastabend 已提交
518
		fnew->mask = nla_get_u32(tb[TCA_FLOW_MASK]);
519
	if (tb[TCA_FLOW_XOR])
J
John Fastabend 已提交
520
		fnew->xor = nla_get_u32(tb[TCA_FLOW_XOR]);
521
	if (tb[TCA_FLOW_RSHIFT])
J
John Fastabend 已提交
522
		fnew->rshift = nla_get_u32(tb[TCA_FLOW_RSHIFT]);
523
	if (tb[TCA_FLOW_ADDEND])
J
John Fastabend 已提交
524
		fnew->addend = nla_get_u32(tb[TCA_FLOW_ADDEND]);
525 526

	if (tb[TCA_FLOW_DIVISOR])
J
John Fastabend 已提交
527
		fnew->divisor = nla_get_u32(tb[TCA_FLOW_DIVISOR]);
528
	if (baseclass)
J
John Fastabend 已提交
529
		fnew->baseclass = baseclass;
530

J
John Fastabend 已提交
531
	fnew->perturb_period = perturb_period;
532
	if (perturb_period)
J
John Fastabend 已提交
533
		mod_timer(&fnew->perturb_timer, jiffies + perturb_period);
534

535
	if (*arg == 0)
J
John Fastabend 已提交
536 537
		list_add_tail_rcu(&fnew->list, &head->filters);
	else
538
		list_replace_rcu(&fold->list, &fnew->list);
539

J
John Fastabend 已提交
540
	*arg = (unsigned long)fnew;
541

J
John Fastabend 已提交
542 543
	if (fold)
		call_rcu(&fold->rcu, flow_destroy_filter);
544 545
	return 0;

546
err2:
547
	tcf_exts_destroy(&fnew->exts);
548
	tcf_em_tree_destroy(&fnew->ematches);
549
err1:
550
	kfree(fnew);
551 552 553
	return err;
}

554
static int flow_delete(struct tcf_proto *tp, unsigned long arg, bool *last)
555
{
556
	struct flow_head *head = rtnl_dereference(tp->root);
557 558
	struct flow_filter *f = (struct flow_filter *)arg;

J
John Fastabend 已提交
559 560
	list_del_rcu(&f->list);
	call_rcu(&f->rcu, flow_destroy_filter);
561
	*last = list_empty(&head->filters);
562 563 564 565 566 567 568 569 570 571 572
	return 0;
}

static int flow_init(struct tcf_proto *tp)
{
	struct flow_head *head;

	head = kzalloc(sizeof(*head), GFP_KERNEL);
	if (head == NULL)
		return -ENOBUFS;
	INIT_LIST_HEAD(&head->filters);
J
John Fastabend 已提交
573
	rcu_assign_pointer(tp->root, head);
574 575 576
	return 0;
}

577
static void flow_destroy(struct tcf_proto *tp)
578
{
J
John Fastabend 已提交
579
	struct flow_head *head = rtnl_dereference(tp->root);
580 581 582
	struct flow_filter *f, *next;

	list_for_each_entry_safe(f, next, &head->filters, list) {
J
John Fastabend 已提交
583 584
		list_del_rcu(&f->list);
		call_rcu(&f->rcu, flow_destroy_filter);
585
	}
J
John Fastabend 已提交
586
	kfree_rcu(head, rcu);
587 588 589 590
}

static unsigned long flow_get(struct tcf_proto *tp, u32 handle)
{
J
John Fastabend 已提交
591
	struct flow_head *head = rtnl_dereference(tp->root);
592 593
	struct flow_filter *f;

594
	list_for_each_entry(f, &head->filters, list)
595 596 597 598 599
		if (f->handle == handle)
			return (unsigned long)f;
	return 0;
}

600
static int flow_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
601 602 603 604 605 606 607 608 609 610 611 612 613 614
		     struct sk_buff *skb, struct tcmsg *t)
{
	struct flow_filter *f = (struct flow_filter *)fh;
	struct nlattr *nest;

	if (f == NULL)
		return skb->len;

	t->tcm_handle = f->handle;

	nest = nla_nest_start(skb, TCA_OPTIONS);
	if (nest == NULL)
		goto nla_put_failure;

615 616 617
	if (nla_put_u32(skb, TCA_FLOW_KEYS, f->keymask) ||
	    nla_put_u32(skb, TCA_FLOW_MODE, f->mode))
		goto nla_put_failure;
618 619

	if (f->mask != ~0 || f->xor != 0) {
620 621 622
		if (nla_put_u32(skb, TCA_FLOW_MASK, f->mask) ||
		    nla_put_u32(skb, TCA_FLOW_XOR, f->xor))
			goto nla_put_failure;
623
	}
624 625 626 627 628 629
	if (f->rshift &&
	    nla_put_u32(skb, TCA_FLOW_RSHIFT, f->rshift))
		goto nla_put_failure;
	if (f->addend &&
	    nla_put_u32(skb, TCA_FLOW_ADDEND, f->addend))
		goto nla_put_failure;
630

631 632 633 634 635 636
	if (f->divisor &&
	    nla_put_u32(skb, TCA_FLOW_DIVISOR, f->divisor))
		goto nla_put_failure;
	if (f->baseclass &&
	    nla_put_u32(skb, TCA_FLOW_BASECLASS, f->baseclass))
		goto nla_put_failure;
637

638 639 640
	if (f->perturb_period &&
	    nla_put_u32(skb, TCA_FLOW_PERTURB, f->perturb_period / HZ))
		goto nla_put_failure;
641

642
	if (tcf_exts_dump(skb, &f->exts) < 0)
643
		goto nla_put_failure;
644
#ifdef CONFIG_NET_EMATCH
645 646 647
	if (f->ematches.hdr.nmatches &&
	    tcf_em_tree_dump(skb, &f->ematches, TCA_FLOW_EMATCHES) < 0)
		goto nla_put_failure;
648
#endif
649 650
	nla_nest_end(skb, nest);

651
	if (tcf_exts_dump_stats(skb, &f->exts) < 0)
652 653 654 655 656
		goto nla_put_failure;

	return skb->len;

nla_put_failure:
657
	nla_nest_cancel(skb, nest);
658 659 660 661 662
	return -1;
}

static void flow_walk(struct tcf_proto *tp, struct tcf_walker *arg)
{
J
John Fastabend 已提交
663
	struct flow_head *head = rtnl_dereference(tp->root);
664 665
	struct flow_filter *f;

666
	list_for_each_entry(f, &head->filters, list) {
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
		if (arg->count < arg->skip)
			goto skip;
		if (arg->fn(tp, (unsigned long)f, arg) < 0) {
			arg->stop = 1;
			break;
		}
skip:
		arg->count++;
	}
}

static struct tcf_proto_ops cls_flow_ops __read_mostly = {
	.kind		= "flow",
	.classify	= flow_classify,
	.init		= flow_init,
	.destroy	= flow_destroy,
	.change		= flow_change,
	.delete		= flow_delete,
	.get		= flow_get,
	.dump		= flow_dump,
	.walk		= flow_walk,
	.owner		= THIS_MODULE,
};

static int __init cls_flow_init(void)
{
	return register_tcf_proto_ops(&cls_flow_ops);
}

static void __exit cls_flow_exit(void)
{
	unregister_tcf_proto_ops(&cls_flow_ops);
}

module_init(cls_flow_init);
module_exit(cls_flow_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
MODULE_DESCRIPTION("TC flow classifier");