1dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat/*
2dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * f_flow.c		Flow filter
3dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *
4dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * 		This program is free software; you can redistribute it and/or
5dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * 		modify it under the terms of the GNU General Public License
6dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * 		as published by the Free Software Foundation; either version
7dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * 		2 of the License, or (at your option) any later version.
8dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *
9dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * Authors:	Patrick McHardy <kaber@trash.net>
10dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat */
11dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <stdio.h>
12dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <stdlib.h>
13dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <unistd.h>
14dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <string.h>
15dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <errno.h>
16dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
17dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include "utils.h"
18dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include "tc_util.h"
19dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include "m_ematch.h"
20dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
21dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic void explain(void)
22dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
23dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(stderr,
24dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat"Usage: ... flow ...\n"
25dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat"\n"
26dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat" [mapping mode]: map key KEY [ OPS ] ...\n"
27dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat" [hashing mode]: hash keys KEY-LIST ... [ perturb SECS ]\n"
28dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat"\n"
29dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat"                 [ divisor NUM ] [ baseclass ID ] [ match EMATCH_TREE ]\n"
30dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat"                 [ police POLICE_SPEC ] [ action ACTION_SPEC ]\n"
31dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat"\n"
32dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat"KEY-LIST := [ KEY-LIST , ] KEY\n"
33dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat"KEY      := [ src | dst | proto | proto-src | proto-dst | iif | priority | \n"
34dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat"              mark | nfct | nfct-src | nfct-dst | nfct-proto-src | \n"
35dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat"              nfct-proto-dst | rt-classid | sk-uid | sk-gid |\n"
36dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat"              vlan-tag ]\n"
37dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat"OPS      := [ or NUM | and NUM | xor NUM | rshift NUM | addend NUM ]\n"
38dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat"ID       := X:Y\n"
39dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	);
40dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
41dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
42dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic const char *flow_keys[FLOW_KEY_MAX+1] = {
43dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	[FLOW_KEY_SRC]			= "src",
44dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	[FLOW_KEY_DST]			= "dst",
45dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	[FLOW_KEY_PROTO]		= "proto",
46dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	[FLOW_KEY_PROTO_SRC]		= "proto-src",
47dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	[FLOW_KEY_PROTO_DST]		= "proto-dst",
48dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	[FLOW_KEY_IIF]			= "iif",
49dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	[FLOW_KEY_PRIORITY]		= "priority",
50dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	[FLOW_KEY_MARK]			= "mark",
51dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	[FLOW_KEY_NFCT]			= "nfct",
52dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	[FLOW_KEY_NFCT_SRC]		= "nfct-src",
53dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	[FLOW_KEY_NFCT_DST]		= "nfct-dst",
54dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	[FLOW_KEY_NFCT_PROTO_SRC]	= "nfct-proto-src",
55dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	[FLOW_KEY_NFCT_PROTO_DST]	= "nfct-proto-dst",
56dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	[FLOW_KEY_RTCLASSID]		= "rt-classid",
57dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	[FLOW_KEY_SKUID]		= "sk-uid",
58dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	[FLOW_KEY_SKGID]		= "sk-gid",
59dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	[FLOW_KEY_VLAN_TAG]		= "vlan-tag",
60dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat};
61dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
62dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic int flow_parse_keys(__u32 *keys, __u32 *nkeys, char *argv)
63dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
64dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	char *s, *sep;
65dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	unsigned int i;
66dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
67dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	*keys = 0;
68dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	*nkeys = 0;
69dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	s = argv;
70dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	while (s != NULL) {
71dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		sep = strchr(s, ',');
72dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (sep)
73dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			*sep = '\0';
74dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
75dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		for (i = 0; i <= FLOW_KEY_MAX; i++) {
76dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (matches(s, flow_keys[i]) == 0) {
77dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				*keys |= 1 << i;
78dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				(*nkeys)++;
79dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				break;
80dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
81dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
82dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (i > FLOW_KEY_MAX) {
83dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "Unknown flow key \"%s\"\n", s);
84dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return -1;
85dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
86dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		s = sep ? sep + 1 : NULL;
87dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
88dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
89dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
90dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
91dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic void transfer_bitop(__u32 *mask, __u32 *xor, __u32 m, __u32 x)
92dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
93dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	*xor = x ^ (*xor & m);
94dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	*mask &= m;
95dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
96dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
97dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic int get_addend(__u32 *addend, char *argv, __u32 keys)
98dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
99dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	inet_prefix addr;
100dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	int sign = 0;
101dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	__u32 tmp;
102dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
103dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (*argv == '-') {
104dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		sign = 1;
105dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		argv++;
106dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
107dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
108dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (get_u32(&tmp, argv, 0) == 0)
109dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		goto out;
110dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
111dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (keys & (FLOW_KEY_SRC | FLOW_KEY_DST |
112dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		    FLOW_KEY_NFCT_SRC | FLOW_KEY_NFCT_DST) &&
113dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	    get_addr(&addr, argv, AF_UNSPEC) == 0) {
114dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		switch (addr.family) {
115dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		case AF_INET:
116dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			tmp = ntohl(addr.data[0]);
117dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			goto out;
118dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		case AF_INET6:
119dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			tmp = ntohl(addr.data[3]);
120dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			goto out;
121dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
122dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
123dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
124dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return -1;
125dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatout:
126dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (sign)
127dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		tmp = -tmp;
128dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	*addend = tmp;
129dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
130dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
131dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
132dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic int flow_parse_opt(struct filter_util *fu, char *handle,
133dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			  int argc, char **argv, struct nlmsghdr *n)
134dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
135dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct tc_police tp;
136dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct tcmsg *t = NLMSG_DATA(n);
137dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct rtattr *tail;
138dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	__u32 mask = ~0U, xor = 0;
139dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	__u32 keys = 0, nkeys = 0;
140dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	__u32 mode = FLOW_MODE_MAP;
141dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	__u32 tmp;
142dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
143dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memset(&tp, 0, sizeof(tp));
144dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
145dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (handle) {
146dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (get_u32(&t->tcm_handle, handle, 0)) {
147dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "Illegal \"handle\"\n");
148dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return -1;
149dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
150dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
151dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
152dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	tail = NLMSG_TAIL(n);
153dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
154dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
155dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	while (argc > 0) {
156dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (matches(*argv, "map") == 0) {
157dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			mode = FLOW_MODE_MAP;
158dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "hash") == 0) {
159dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			mode = FLOW_MODE_HASH;
160dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "keys") == 0) {
161dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
162dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (flow_parse_keys(&keys, &nkeys, *argv))
163dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
164dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			addattr32(n, 4096, TCA_FLOW_KEYS, keys);
165dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "and") == 0) {
166dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
167dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (get_u32(&tmp, *argv, 0)) {
168dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "Illegal \"mask\"\n");
169dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
170dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
171dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			transfer_bitop(&mask, &xor, tmp, 0);
172dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "or") == 0) {
173dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
174dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (get_u32(&tmp, *argv, 0)) {
175dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "Illegal \"or\"\n");
176dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
177dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
178dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			transfer_bitop(&mask, &xor, ~tmp, tmp);
179dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "xor") == 0) {
180dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
181dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (get_u32(&tmp, *argv, 0)) {
182dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "Illegal \"xor\"\n");
183dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
184dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
185dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			transfer_bitop(&mask, &xor, ~0, tmp);
186dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "rshift") == 0) {
187dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
188dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (get_u32(&tmp, *argv, 0)) {
189dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "Illegal \"rshift\"\n");
190dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
191dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
192dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			addattr32(n, 4096, TCA_FLOW_RSHIFT, tmp);
193dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "addend") == 0) {
194dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
195dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (get_addend(&tmp, *argv, keys)) {
196dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "Illegal \"addend\"\n");
197dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
198dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
199dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			addattr32(n, 4096, TCA_FLOW_ADDEND, tmp);
200dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "divisor") == 0) {
201dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
202dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (get_u32(&tmp, *argv, 0)) {
203dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "Illegal \"divisor\"\n");
204dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
205dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
206dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			addattr32(n, 4096, TCA_FLOW_DIVISOR, tmp);
207dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "baseclass") == 0) {
208dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
209dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (get_tc_classid(&tmp, *argv) || TC_H_MIN(tmp) == 0) {
210dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "Illegal \"baseclass\"\n");
211dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
212dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
213dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			addattr32(n, 4096, TCA_FLOW_BASECLASS, tmp);
214dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "perturb") == 0) {
215dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
216dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (get_u32(&tmp, *argv, 0)) {
217dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "Illegal \"perturb\"\n");
218dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
219dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
220dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			addattr32(n, 4096, TCA_FLOW_PERTURB, tmp);
221dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "police") == 0) {
222dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
223dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (parse_police(&argc, &argv, TCA_FLOW_POLICE, n)) {
224dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "Illegal \"police\"\n");
225dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
226dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
227dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			continue;
228dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "action") == 0) {
229dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
230dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (parse_action(&argc, &argv, TCA_FLOW_ACT, n)) {
231dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "Illegal \"action\"\n");
232dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
233dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
234dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			continue;
235dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "match") == 0) {
236dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
237dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (parse_ematch(&argc, &argv, TCA_FLOW_EMATCHES, n)) {
238dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "Illegal \"ematch\"\n");
239dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
240dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
241dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			continue;
242dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "help") == 0) {
243dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			explain();
244dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return -1;
245dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else {
246dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "What is \"%s\"?\n", *argv);
247dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			explain();
248dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return -1;
249dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
250dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		argv++, argc--;
251dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
252dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
253dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (nkeys > 1 && mode != FLOW_MODE_HASH) {
254dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(stderr, "Invalid mode \"map\" for multiple keys\n");
255dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
256dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
257dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	addattr32(n, 4096, TCA_FLOW_MODE, mode);
258dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
259dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (mask != ~0 || xor != 0) {
260dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		addattr32(n, 4096, TCA_FLOW_MASK, mask);
261dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		addattr32(n, 4096, TCA_FLOW_XOR, xor);
262dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
263dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
264dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
265dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
266dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
267dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
268dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic int flow_print_opt(struct filter_util *fu, FILE *f, struct rtattr *opt,
269dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			  __u32 handle)
270dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
271dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct rtattr *tb[TCA_FLOW_MAX+1];
272dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	SPRINT_BUF(b1);
273dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	unsigned int i;
274dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	__u32 mask = ~0, val = 0;
275dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
276dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (opt == NULL)
277dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -EINVAL;
278dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
279dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	parse_rtattr_nested(tb, TCA_FLOW_MAX, opt);
280dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
281dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(f, "handle 0x%x ", handle);
282dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
283dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tb[TCA_FLOW_MODE]) {
284dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		__u32 mode = *(__u32 *)RTA_DATA(tb[TCA_FLOW_MODE]);
285dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
286dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		switch (mode) {
287dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		case FLOW_MODE_MAP:
288dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(f, "map ");
289dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			break;
290dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		case FLOW_MODE_HASH:
291dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(f, "hash ");
292dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			break;
293dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
294dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
295dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
296dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tb[TCA_FLOW_KEYS]) {
297dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		__u32 keymask = *(__u32 *)RTA_DATA(tb[TCA_FLOW_KEYS]);
298dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		char *sep = "";
299dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
300dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(f, "keys ");
301dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		for (i = 0; i <= FLOW_KEY_MAX; i++) {
302dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (keymask & (1 << i)) {
303dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(f, "%s%s", sep, flow_keys[i]);
304dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				sep = ",";
305dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
306dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
307dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(f, " ");
308dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
309dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
310dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tb[TCA_FLOW_MASK])
311dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		mask = *(__u32 *)RTA_DATA(tb[TCA_FLOW_MASK]);
312dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tb[TCA_FLOW_XOR])
313dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		val = *(__u32 *)RTA_DATA(tb[TCA_FLOW_XOR]);
314dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
315dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (mask != ~0 || val != 0) {
316dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		__u32 or = (mask & val) ^ val;
317dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		__u32 xor = mask & val;
318dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
319dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (mask != ~0)
320dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(f, "and 0x%.8x ", mask);
321dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (xor != 0)
322dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(f, "xor 0x%.8x ", xor);
323dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (or != 0)
324dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(f, "or 0x%.8x ", or);
325dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
326dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
327dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tb[TCA_FLOW_RSHIFT])
328dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(f, "rshift %u ",
329dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			*(__u32 *)RTA_DATA(tb[TCA_FLOW_RSHIFT]));
330dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tb[TCA_FLOW_ADDEND])
331dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(f, "addend 0x%x ",
332dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			*(__u32 *)RTA_DATA(tb[TCA_FLOW_ADDEND]));
333dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
334dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tb[TCA_FLOW_DIVISOR])
335dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(f, "divisor %u ",
336dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			*(__u32 *)RTA_DATA(tb[TCA_FLOW_DIVISOR]));
337dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tb[TCA_FLOW_BASECLASS])
338dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(f, "baseclass %s ",
339dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			sprint_tc_classid(*(__u32 *)RTA_DATA(tb[TCA_FLOW_BASECLASS]), b1));
340dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
341dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tb[TCA_FLOW_PERTURB])
342dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(f, "perturb %usec ",
343dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			*(__u32 *)RTA_DATA(tb[TCA_FLOW_PERTURB]));
344dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
345dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tb[TCA_FLOW_EMATCHES])
346dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		print_ematch(f, tb[TCA_FLOW_EMATCHES]);
347dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tb[TCA_FLOW_POLICE])
348dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		tc_print_police(f, tb[TCA_FLOW_POLICE]);
349dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tb[TCA_FLOW_ACT]) {
350dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(f, "\n");
351dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		tc_print_action(f, tb[TCA_FLOW_ACT]);
352dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
353dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
354dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
355dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
356dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstruct filter_util flow_filter_util = {
357dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	.id		= "flow",
358dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	.parse_fopt	= flow_parse_opt,
359dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	.print_fopt	= flow_print_opt,
360dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat};
361