Blame view

net/sched/cls_flower.c 57.2 KB
77b9900ef   Jiri Pirko   tc: introduce Flo...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /*
   * net/sched/cls_flower.c		Flower classifier
   *
   * Copyright (c) 2015 Jiri Pirko <jiri@resnulli.us>
   *
   * 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/module.h>
  #include <linux/rhashtable.h>
d93637741   Daniel Borkmann   net, sched: respe...
16
  #include <linux/workqueue.h>
77b9900ef   Jiri Pirko   tc: introduce Flo...
17
18
19
20
  
  #include <linux/if_ether.h>
  #include <linux/in6.h>
  #include <linux/ip.h>
a577d8f79   Benjamin LaHaise   cls_flower: add s...
21
  #include <linux/mpls.h>
77b9900ef   Jiri Pirko   tc: introduce Flo...
22
23
24
25
26
  
  #include <net/sch_generic.h>
  #include <net/pkt_cls.h>
  #include <net/ip.h>
  #include <net/flow_dissector.h>
0a6e77784   Pieter Jansen van Vuuren   net/sched: allow ...
27
  #include <net/geneve.h>
77b9900ef   Jiri Pirko   tc: introduce Flo...
28

bc3103f1e   Amir Vadai   net/sched: cls_fl...
29
30
  #include <net/dst.h>
  #include <net/dst_metadata.h>
77b9900ef   Jiri Pirko   tc: introduce Flo...
31
32
  struct fl_flow_key {
  	int	indev_ifindex;
42aecaa9b   Tom Herbert   net: Get skb hash...
33
  	struct flow_dissector_key_control control;
bc3103f1e   Amir Vadai   net/sched: cls_fl...
34
  	struct flow_dissector_key_control enc_control;
77b9900ef   Jiri Pirko   tc: introduce Flo...
35
36
  	struct flow_dissector_key_basic basic;
  	struct flow_dissector_key_eth_addrs eth;
9399ae9a6   Hadar Hen Zion   net_sched: flower...
37
  	struct flow_dissector_key_vlan vlan;
d64efd092   Jianbo Liu   net/sched: flower...
38
  	struct flow_dissector_key_vlan cvlan;
77b9900ef   Jiri Pirko   tc: introduce Flo...
39
  	union {
c3f832418   Tom Herbert   net: Add full IPv...
40
  		struct flow_dissector_key_ipv4_addrs ipv4;
77b9900ef   Jiri Pirko   tc: introduce Flo...
41
42
43
  		struct flow_dissector_key_ipv6_addrs ipv6;
  	};
  	struct flow_dissector_key_ports tp;
7b684884f   Simon Horman   net/sched: cls_fl...
44
  	struct flow_dissector_key_icmp icmp;
99d31326c   Simon Horman   net/sched: cls_fl...
45
  	struct flow_dissector_key_arp arp;
bc3103f1e   Amir Vadai   net/sched: cls_fl...
46
47
48
49
50
  	struct flow_dissector_key_keyid enc_key_id;
  	union {
  		struct flow_dissector_key_ipv4_addrs enc_ipv4;
  		struct flow_dissector_key_ipv6_addrs enc_ipv6;
  	};
f4d997fd6   Hadar Hen Zion   net/sched: cls_fl...
51
  	struct flow_dissector_key_ports enc_tp;
a577d8f79   Benjamin LaHaise   cls_flower: add s...
52
  	struct flow_dissector_key_mpls mpls;
fdfc7dd6c   Jiri Pirko   net/sched: flower...
53
  	struct flow_dissector_key_tcp tcp;
4d80cc0aa   Or Gerlitz   net/sched: cls_fl...
54
  	struct flow_dissector_key_ip ip;
0e2c17b64   Or Gerlitz   net/sched: cls_fl...
55
  	struct flow_dissector_key_ip enc_ip;
0a6e77784   Pieter Jansen van Vuuren   net/sched: allow ...
56
  	struct flow_dissector_key_enc_opts enc_opts;
77b9900ef   Jiri Pirko   tc: introduce Flo...
57
58
59
60
61
62
63
64
65
66
  } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
  
  struct fl_flow_mask_range {
  	unsigned short int start;
  	unsigned short int end;
  };
  
  struct fl_flow_mask {
  	struct fl_flow_key key;
  	struct fl_flow_mask_range range;
05cd271fd   Paul Blakey   cls_flower: Suppo...
67
68
69
70
71
  	struct rhash_head ht_node;
  	struct rhashtable ht;
  	struct rhashtable_params filter_ht_params;
  	struct flow_dissector dissector;
  	struct list_head filters;
44a5cd436   Paolo Abeni   cls_flower: fix u...
72
  	struct rcu_work rwork;
05cd271fd   Paul Blakey   cls_flower: Suppo...
73
  	struct list_head list;
77b9900ef   Jiri Pirko   tc: introduce Flo...
74
  };
b95ec7eb3   Jiri Pirko   net: sched: cls_f...
75
76
77
78
79
80
  struct fl_flow_tmplt {
  	struct fl_flow_key dummy_key;
  	struct fl_flow_key mask;
  	struct flow_dissector dissector;
  	struct tcf_chain *chain;
  };
77b9900ef   Jiri Pirko   tc: introduce Flo...
81
82
  struct cls_fl_head {
  	struct rhashtable ht;
05cd271fd   Paul Blakey   cls_flower: Suppo...
83
  	struct list_head masks;
aaa908ffb   Cong Wang   net_sched: switch...
84
  	struct rcu_work rwork;
c15ab236d   Chris Mi   net/sched: Change...
85
  	struct idr handle_idr;
77b9900ef   Jiri Pirko   tc: introduce Flo...
86
87
88
  };
  
  struct cls_fl_filter {
05cd271fd   Paul Blakey   cls_flower: Suppo...
89
  	struct fl_flow_mask *mask;
77b9900ef   Jiri Pirko   tc: introduce Flo...
90
91
92
93
94
95
96
  	struct rhash_head ht_node;
  	struct fl_flow_key mkey;
  	struct tcf_exts exts;
  	struct tcf_result res;
  	struct fl_flow_key key;
  	struct list_head list;
  	u32 handle;
e69985c67   Amir Vadai   net/sched: cls_fl...
97
  	u32 flags;
31533cba4   John Hurley   net: sched: cls_f...
98
  	unsigned int in_hw_count;
aaa908ffb   Cong Wang   net_sched: switch...
99
  	struct rcu_work rwork;
7091d8c70   Hadar Hen Zion   net/sched: cls_fl...
100
  	struct net_device *hw_dev;
77b9900ef   Jiri Pirko   tc: introduce Flo...
101
  };
05cd271fd   Paul Blakey   cls_flower: Suppo...
102
103
104
105
106
107
  static const struct rhashtable_params mask_ht_params = {
  	.key_offset = offsetof(struct fl_flow_mask, key),
  	.key_len = sizeof(struct fl_flow_key),
  	.head_offset = offsetof(struct fl_flow_mask, ht_node),
  	.automatic_shrinking = true,
  };
77b9900ef   Jiri Pirko   tc: introduce Flo...
108
109
110
111
112
113
114
115
116
  static unsigned short int fl_mask_range(const struct fl_flow_mask *mask)
  {
  	return mask->range.end - mask->range.start;
  }
  
  static void fl_mask_update_range(struct fl_flow_mask *mask)
  {
  	const u8 *bytes = (const u8 *) &mask->key;
  	size_t size = sizeof(mask->key);
05cd271fd   Paul Blakey   cls_flower: Suppo...
117
  	size_t i, first = 0, last;
77b9900ef   Jiri Pirko   tc: introduce Flo...
118

05cd271fd   Paul Blakey   cls_flower: Suppo...
119
120
121
122
123
124
125
126
  	for (i = 0; i < size; i++) {
  		if (bytes[i]) {
  			first = i;
  			break;
  		}
  	}
  	last = first;
  	for (i = size - 1; i != first; i--) {
77b9900ef   Jiri Pirko   tc: introduce Flo...
127
  		if (bytes[i]) {
77b9900ef   Jiri Pirko   tc: introduce Flo...
128
  			last = i;
05cd271fd   Paul Blakey   cls_flower: Suppo...
129
  			break;
77b9900ef   Jiri Pirko   tc: introduce Flo...
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
  		}
  	}
  	mask->range.start = rounddown(first, sizeof(long));
  	mask->range.end = roundup(last + 1, sizeof(long));
  }
  
  static void *fl_key_get_start(struct fl_flow_key *key,
  			      const struct fl_flow_mask *mask)
  {
  	return (u8 *) key + mask->range.start;
  }
  
  static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key,
  			      struct fl_flow_mask *mask)
  {
  	const long *lkey = fl_key_get_start(key, mask);
  	const long *lmask = fl_key_get_start(&mask->key, mask);
  	long *lmkey = fl_key_get_start(mkey, mask);
  	int i;
  
  	for (i = 0; i < fl_mask_range(mask); i += sizeof(long))
  		*lmkey++ = *lkey++ & *lmask++;
  }
b95ec7eb3   Jiri Pirko   net: sched: cls_f...
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
  static bool fl_mask_fits_tmplt(struct fl_flow_tmplt *tmplt,
  			       struct fl_flow_mask *mask)
  {
  	const long *lmask = fl_key_get_start(&mask->key, mask);
  	const long *ltmplt;
  	int i;
  
  	if (!tmplt)
  		return true;
  	ltmplt = fl_key_get_start(&tmplt->mask, mask);
  	for (i = 0; i < fl_mask_range(mask); i += sizeof(long)) {
  		if (~*ltmplt++ & *lmask++)
  			return false;
  	}
  	return true;
  }
77b9900ef   Jiri Pirko   tc: introduce Flo...
169
170
171
172
173
  static void fl_clear_masked_range(struct fl_flow_key *key,
  				  struct fl_flow_mask *mask)
  {
  	memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask));
  }
05cd271fd   Paul Blakey   cls_flower: Suppo...
174
  static struct cls_fl_filter *fl_lookup(struct fl_flow_mask *mask,
a3308d8fd   Paul Blakey   net/sched: cls_fl...
175
176
  				       struct fl_flow_key *mkey)
  {
05cd271fd   Paul Blakey   cls_flower: Suppo...
177
178
  	return rhashtable_lookup_fast(&mask->ht, fl_key_get_start(mkey, mask),
  				      mask->filter_ht_params);
a3308d8fd   Paul Blakey   net/sched: cls_fl...
179
  }
77b9900ef   Jiri Pirko   tc: introduce Flo...
180
181
182
183
184
  static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp,
  		       struct tcf_result *res)
  {
  	struct cls_fl_head *head = rcu_dereference_bh(tp->root);
  	struct cls_fl_filter *f;
05cd271fd   Paul Blakey   cls_flower: Suppo...
185
  	struct fl_flow_mask *mask;
77b9900ef   Jiri Pirko   tc: introduce Flo...
186
187
  	struct fl_flow_key skb_key;
  	struct fl_flow_key skb_mkey;
05cd271fd   Paul Blakey   cls_flower: Suppo...
188
189
  	list_for_each_entry_rcu(mask, &head->masks, list) {
  		fl_clear_masked_range(&skb_key, mask);
bc3103f1e   Amir Vadai   net/sched: cls_fl...
190

05cd271fd   Paul Blakey   cls_flower: Suppo...
191
192
193
194
195
196
197
  		skb_key.indev_ifindex = skb->skb_iif;
  		/* skb_flow_dissect() does not set n_proto in case an unknown
  		 * protocol, so do it rather here.
  		 */
  		skb_key.basic.n_proto = skb->protocol;
  		skb_flow_dissect_tunnel_info(skb, &mask->dissector, &skb_key);
  		skb_flow_dissect(skb, &mask->dissector, &skb_key, 0);
77b9900ef   Jiri Pirko   tc: introduce Flo...
198

05cd271fd   Paul Blakey   cls_flower: Suppo...
199
  		fl_set_masked_key(&skb_mkey, &skb_key, mask);
77b9900ef   Jiri Pirko   tc: introduce Flo...
200

05cd271fd   Paul Blakey   cls_flower: Suppo...
201
202
203
204
205
  		f = fl_lookup(mask, &skb_mkey);
  		if (f && !tc_skip_sw(f->flags)) {
  			*res = f->res;
  			return tcf_exts_exec(skb, &f->exts, res);
  		}
77b9900ef   Jiri Pirko   tc: introduce Flo...
206
207
208
209
210
211
212
213
214
215
216
  	}
  	return -1;
  }
  
  static int fl_init(struct tcf_proto *tp)
  {
  	struct cls_fl_head *head;
  
  	head = kzalloc(sizeof(*head), GFP_KERNEL);
  	if (!head)
  		return -ENOBUFS;
05cd271fd   Paul Blakey   cls_flower: Suppo...
217
  	INIT_LIST_HEAD_RCU(&head->masks);
77b9900ef   Jiri Pirko   tc: introduce Flo...
218
  	rcu_assign_pointer(tp->root, head);
c15ab236d   Chris Mi   net/sched: Change...
219
  	idr_init(&head->handle_idr);
77b9900ef   Jiri Pirko   tc: introduce Flo...
220

05cd271fd   Paul Blakey   cls_flower: Suppo...
221
222
  	return rhashtable_init(&head->ht, &mask_ht_params);
  }
44a5cd436   Paolo Abeni   cls_flower: fix u...
223
224
225
226
227
228
229
230
231
232
233
234
235
  static void fl_mask_free(struct fl_flow_mask *mask)
  {
  	rhashtable_destroy(&mask->ht);
  	kfree(mask);
  }
  
  static void fl_mask_free_work(struct work_struct *work)
  {
  	struct fl_flow_mask *mask = container_of(to_rcu_work(work),
  						 struct fl_flow_mask, rwork);
  
  	fl_mask_free(mask);
  }
05cd271fd   Paul Blakey   cls_flower: Suppo...
236
237
238
239
240
241
242
  static bool fl_mask_put(struct cls_fl_head *head, struct fl_flow_mask *mask,
  			bool async)
  {
  	if (!list_empty(&mask->filters))
  		return false;
  
  	rhashtable_remove_fast(&head->ht, &mask->ht_node, mask_ht_params);
05cd271fd   Paul Blakey   cls_flower: Suppo...
243
244
  	list_del_rcu(&mask->list);
  	if (async)
44a5cd436   Paolo Abeni   cls_flower: fix u...
245
  		tcf_queue_work(&mask->rwork, fl_mask_free_work);
05cd271fd   Paul Blakey   cls_flower: Suppo...
246
  	else
44a5cd436   Paolo Abeni   cls_flower: fix u...
247
  		fl_mask_free(mask);
05cd271fd   Paul Blakey   cls_flower: Suppo...
248
249
  
  	return true;
77b9900ef   Jiri Pirko   tc: introduce Flo...
250
  }
0dadc117a   Cong Wang   cls_flower: use t...
251
252
253
254
255
256
  static void __fl_destroy_filter(struct cls_fl_filter *f)
  {
  	tcf_exts_destroy(&f->exts);
  	tcf_exts_put_net(&f->exts);
  	kfree(f);
  }
0552c8afa   Cong Wang   net_sched: use tc...
257
  static void fl_destroy_filter_work(struct work_struct *work)
77b9900ef   Jiri Pirko   tc: introduce Flo...
258
  {
aaa908ffb   Cong Wang   net_sched: switch...
259
260
  	struct cls_fl_filter *f = container_of(to_rcu_work(work),
  					struct cls_fl_filter, rwork);
77b9900ef   Jiri Pirko   tc: introduce Flo...
261

0552c8afa   Cong Wang   net_sched: use tc...
262
  	rtnl_lock();
0dadc117a   Cong Wang   cls_flower: use t...
263
  	__fl_destroy_filter(f);
0552c8afa   Cong Wang   net_sched: use tc...
264
265
  	rtnl_unlock();
  }
1b0f80375   Jakub Kicinski   cls_flower: propa...
266
267
  static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f,
  				 struct netlink_ext_ack *extack)
5b33f4884   Amir Vadai   net/flower: Intro...
268
  {
de4784ca0   Jiri Pirko   net: sched: get r...
269
  	struct tc_cls_flower_offload cls_flower = {};
208c0f4b5   Jiri Pirko   net: sched: use t...
270
  	struct tcf_block *block = tp->chain->block;
5b33f4884   Amir Vadai   net/flower: Intro...
271

1b0f80375   Jakub Kicinski   cls_flower: propa...
272
  	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack);
de4784ca0   Jiri Pirko   net: sched: get r...
273
274
  	cls_flower.command = TC_CLSFLOWER_DESTROY;
  	cls_flower.cookie = (unsigned long) f;
5b33f4884   Amir Vadai   net/flower: Intro...
275

208c0f4b5   Jiri Pirko   net: sched: use t...
276
  	tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER,
717503b9c   Jiri Pirko   net: sched: conve...
277
  			 &cls_flower, false);
caa726015   Jiri Pirko   net: sched: keep ...
278
  	tcf_block_offload_dec(block, &f->flags);
5b33f4884   Amir Vadai   net/flower: Intro...
279
  }
e8eb36cd8   Amir Vadai   net/sched: flower...
280
  static int fl_hw_replace_filter(struct tcf_proto *tp,
41002038f   Quentin Monnet   net: sched: cls_f...
281
282
  				struct cls_fl_filter *f,
  				struct netlink_ext_ack *extack)
5b33f4884   Amir Vadai   net/flower: Intro...
283
  {
de4784ca0   Jiri Pirko   net: sched: get r...
284
  	struct tc_cls_flower_offload cls_flower = {};
208c0f4b5   Jiri Pirko   net: sched: use t...
285
  	struct tcf_block *block = tp->chain->block;
717503b9c   Jiri Pirko   net: sched: conve...
286
  	bool skip_sw = tc_skip_sw(f->flags);
e8eb36cd8   Amir Vadai   net/sched: flower...
287
  	int err;
5b33f4884   Amir Vadai   net/flower: Intro...
288

ea2059409   Jakub Kicinski   cls_flower: pass ...
289
  	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack);
de4784ca0   Jiri Pirko   net: sched: get r...
290
291
  	cls_flower.command = TC_CLSFLOWER_REPLACE;
  	cls_flower.cookie = (unsigned long) f;
05cd271fd   Paul Blakey   cls_flower: Suppo...
292
293
  	cls_flower.dissector = &f->mask->dissector;
  	cls_flower.mask = &f->mask->key;
de4784ca0   Jiri Pirko   net: sched: get r...
294
295
  	cls_flower.key = &f->mkey;
  	cls_flower.exts = &f->exts;
384c181e3   Amritha Nambiar   net: sched: Ident...
296
  	cls_flower.classid = f->res.classid;
5b33f4884   Amir Vadai   net/flower: Intro...
297

208c0f4b5   Jiri Pirko   net: sched: use t...
298
  	err = tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER,
717503b9c   Jiri Pirko   net: sched: conve...
299
300
  			       &cls_flower, skip_sw);
  	if (err < 0) {
1b0f80375   Jakub Kicinski   cls_flower: propa...
301
  		fl_hw_destroy_filter(tp, f, NULL);
e8eb36cd8   Amir Vadai   net/sched: flower...
302
  		return err;
717503b9c   Jiri Pirko   net: sched: conve...
303
  	} else if (err > 0) {
31533cba4   John Hurley   net: sched: cls_f...
304
  		f->in_hw_count = err;
caa726015   Jiri Pirko   net: sched: keep ...
305
  		tcf_block_offload_inc(block, &f->flags);
717503b9c   Jiri Pirko   net: sched: conve...
306
307
308
309
  	}
  
  	if (skip_sw && !(f->flags & TCA_CLS_FLAGS_IN_HW))
  		return -EINVAL;
e8eb36cd8   Amir Vadai   net/sched: flower...
310
  	return 0;
5b33f4884   Amir Vadai   net/flower: Intro...
311
  }
10cbc6843   Amir Vadai   net/sched: cls_fl...
312
313
  static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
  {
de4784ca0   Jiri Pirko   net: sched: get r...
314
  	struct tc_cls_flower_offload cls_flower = {};
208c0f4b5   Jiri Pirko   net: sched: use t...
315
  	struct tcf_block *block = tp->chain->block;
10cbc6843   Amir Vadai   net/sched: cls_fl...
316

ea2059409   Jakub Kicinski   cls_flower: pass ...
317
  	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, NULL);
de4784ca0   Jiri Pirko   net: sched: get r...
318
319
320
  	cls_flower.command = TC_CLSFLOWER_STATS;
  	cls_flower.cookie = (unsigned long) f;
  	cls_flower.exts = &f->exts;
384c181e3   Amritha Nambiar   net: sched: Ident...
321
  	cls_flower.classid = f->res.classid;
10cbc6843   Amir Vadai   net/sched: cls_fl...
322

208c0f4b5   Jiri Pirko   net: sched: use t...
323
  	tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER,
717503b9c   Jiri Pirko   net: sched: conve...
324
  			 &cls_flower, false);
10cbc6843   Amir Vadai   net/sched: cls_fl...
325
  }
05cd271fd   Paul Blakey   cls_flower: Suppo...
326
  static bool __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,
1b0f80375   Jakub Kicinski   cls_flower: propa...
327
  			struct netlink_ext_ack *extack)
13fa876eb   Roi Dayan   net/sched: cls_fl...
328
  {
c15ab236d   Chris Mi   net/sched: Change...
329
  	struct cls_fl_head *head = rtnl_dereference(tp->root);
05cd271fd   Paul Blakey   cls_flower: Suppo...
330
331
  	bool async = tcf_exts_get_net(&f->exts);
  	bool last;
c15ab236d   Chris Mi   net/sched: Change...
332

9c1609414   Matthew Wilcox   idr: Delete idr_r...
333
  	idr_remove(&head->handle_idr, f->handle);
13fa876eb   Roi Dayan   net/sched: cls_fl...
334
  	list_del_rcu(&f->list);
05cd271fd   Paul Blakey   cls_flower: Suppo...
335
  	last = fl_mask_put(head, f->mask, async);
796852197   Hadar Hen Zion   net/sched: cls_fl...
336
  	if (!tc_skip_hw(f->flags))
1b0f80375   Jakub Kicinski   cls_flower: propa...
337
  		fl_hw_destroy_filter(tp, f, extack);
13fa876eb   Roi Dayan   net/sched: cls_fl...
338
  	tcf_unbind_filter(tp, &f->res);
05cd271fd   Paul Blakey   cls_flower: Suppo...
339
  	if (async)
aaa908ffb   Cong Wang   net_sched: switch...
340
  		tcf_queue_work(&f->rwork, fl_destroy_filter_work);
0dadc117a   Cong Wang   cls_flower: use t...
341
342
  	else
  		__fl_destroy_filter(f);
05cd271fd   Paul Blakey   cls_flower: Suppo...
343
344
  
  	return last;
13fa876eb   Roi Dayan   net/sched: cls_fl...
345
  }
d93637741   Daniel Borkmann   net, sched: respe...
346
347
  static void fl_destroy_sleepable(struct work_struct *work)
  {
aaa908ffb   Cong Wang   net_sched: switch...
348
349
350
  	struct cls_fl_head *head = container_of(to_rcu_work(work),
  						struct cls_fl_head,
  						rwork);
de9dc650f   Paul Blakey   cls_flower: Fix m...
351
352
  
  	rhashtable_destroy(&head->ht);
d93637741   Daniel Borkmann   net, sched: respe...
353
354
355
  	kfree(head);
  	module_put(THIS_MODULE);
  }
715df5eca   Jakub Kicinski   net: sched: propa...
356
  static void fl_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
77b9900ef   Jiri Pirko   tc: introduce Flo...
357
358
  {
  	struct cls_fl_head *head = rtnl_dereference(tp->root);
05cd271fd   Paul Blakey   cls_flower: Suppo...
359
  	struct fl_flow_mask *mask, *next_mask;
77b9900ef   Jiri Pirko   tc: introduce Flo...
360
  	struct cls_fl_filter *f, *next;
05cd271fd   Paul Blakey   cls_flower: Suppo...
361
362
363
364
365
366
  	list_for_each_entry_safe(mask, next_mask, &head->masks, list) {
  		list_for_each_entry_safe(f, next, &mask->filters, list) {
  			if (__fl_delete(tp, f, extack))
  				break;
  		}
  	}
c15ab236d   Chris Mi   net/sched: Change...
367
  	idr_destroy(&head->handle_idr);
d93637741   Daniel Borkmann   net, sched: respe...
368
369
  
  	__module_get(THIS_MODULE);
aaa908ffb   Cong Wang   net_sched: switch...
370
  	tcf_queue_work(&head->rwork, fl_destroy_sleepable);
77b9900ef   Jiri Pirko   tc: introduce Flo...
371
  }
8113c0956   WANG Cong   net_sched: use vo...
372
  static void *fl_get(struct tcf_proto *tp, u32 handle)
77b9900ef   Jiri Pirko   tc: introduce Flo...
373
374
  {
  	struct cls_fl_head *head = rtnl_dereference(tp->root);
77b9900ef   Jiri Pirko   tc: introduce Flo...
375

322d884ba   Matthew Wilcox   idr: Delete idr_f...
376
  	return idr_find(&head->handle_idr, handle);
77b9900ef   Jiri Pirko   tc: introduce Flo...
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
  }
  
  static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
  	[TCA_FLOWER_UNSPEC]		= { .type = NLA_UNSPEC },
  	[TCA_FLOWER_CLASSID]		= { .type = NLA_U32 },
  	[TCA_FLOWER_INDEV]		= { .type = NLA_STRING,
  					    .len = IFNAMSIZ },
  	[TCA_FLOWER_KEY_ETH_DST]	= { .len = ETH_ALEN },
  	[TCA_FLOWER_KEY_ETH_DST_MASK]	= { .len = ETH_ALEN },
  	[TCA_FLOWER_KEY_ETH_SRC]	= { .len = ETH_ALEN },
  	[TCA_FLOWER_KEY_ETH_SRC_MASK]	= { .len = ETH_ALEN },
  	[TCA_FLOWER_KEY_ETH_TYPE]	= { .type = NLA_U16 },
  	[TCA_FLOWER_KEY_IP_PROTO]	= { .type = NLA_U8 },
  	[TCA_FLOWER_KEY_IPV4_SRC]	= { .type = NLA_U32 },
  	[TCA_FLOWER_KEY_IPV4_SRC_MASK]	= { .type = NLA_U32 },
  	[TCA_FLOWER_KEY_IPV4_DST]	= { .type = NLA_U32 },
  	[TCA_FLOWER_KEY_IPV4_DST_MASK]	= { .type = NLA_U32 },
  	[TCA_FLOWER_KEY_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
  	[TCA_FLOWER_KEY_IPV6_SRC_MASK]	= { .len = sizeof(struct in6_addr) },
  	[TCA_FLOWER_KEY_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
  	[TCA_FLOWER_KEY_IPV6_DST_MASK]	= { .len = sizeof(struct in6_addr) },
  	[TCA_FLOWER_KEY_TCP_SRC]	= { .type = NLA_U16 },
  	[TCA_FLOWER_KEY_TCP_DST]	= { .type = NLA_U16 },
b175c3a44   Jamal Hadi Salim   net: sched: flowe...
400
401
  	[TCA_FLOWER_KEY_UDP_SRC]	= { .type = NLA_U16 },
  	[TCA_FLOWER_KEY_UDP_DST]	= { .type = NLA_U16 },
9399ae9a6   Hadar Hen Zion   net_sched: flower...
402
403
404
  	[TCA_FLOWER_KEY_VLAN_ID]	= { .type = NLA_U16 },
  	[TCA_FLOWER_KEY_VLAN_PRIO]	= { .type = NLA_U8 },
  	[TCA_FLOWER_KEY_VLAN_ETH_TYPE]	= { .type = NLA_U16 },
bc3103f1e   Amir Vadai   net/sched: cls_fl...
405
406
407
408
409
410
411
412
413
  	[TCA_FLOWER_KEY_ENC_KEY_ID]	= { .type = NLA_U32 },
  	[TCA_FLOWER_KEY_ENC_IPV4_SRC]	= { .type = NLA_U32 },
  	[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NLA_U32 },
  	[TCA_FLOWER_KEY_ENC_IPV4_DST]	= { .type = NLA_U32 },
  	[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NLA_U32 },
  	[TCA_FLOWER_KEY_ENC_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
  	[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) },
  	[TCA_FLOWER_KEY_ENC_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
  	[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) },
aa72d7083   Or Gerlitz   net/sched: cls_fl...
414
415
416
417
  	[TCA_FLOWER_KEY_TCP_SRC_MASK]	= { .type = NLA_U16 },
  	[TCA_FLOWER_KEY_TCP_DST_MASK]	= { .type = NLA_U16 },
  	[TCA_FLOWER_KEY_UDP_SRC_MASK]	= { .type = NLA_U16 },
  	[TCA_FLOWER_KEY_UDP_DST_MASK]	= { .type = NLA_U16 },
5976c5f45   Simon Horman   net/sched: cls_fl...
418
419
420
421
  	[TCA_FLOWER_KEY_SCTP_SRC_MASK]	= { .type = NLA_U16 },
  	[TCA_FLOWER_KEY_SCTP_DST_MASK]	= { .type = NLA_U16 },
  	[TCA_FLOWER_KEY_SCTP_SRC]	= { .type = NLA_U16 },
  	[TCA_FLOWER_KEY_SCTP_DST]	= { .type = NLA_U16 },
f4d997fd6   Hadar Hen Zion   net/sched: cls_fl...
422
423
424
425
  	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT]	= { .type = NLA_U16 },
  	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK]	= { .type = NLA_U16 },
  	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]	= { .type = NLA_U16 },
  	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK]	= { .type = NLA_U16 },
faa3ffce7   Or Gerlitz   net/sched: cls_fl...
426
427
  	[TCA_FLOWER_KEY_FLAGS]		= { .type = NLA_U32 },
  	[TCA_FLOWER_KEY_FLAGS_MASK]	= { .type = NLA_U32 },
7b684884f   Simon Horman   net/sched: cls_fl...
428
429
430
431
432
433
434
435
  	[TCA_FLOWER_KEY_ICMPV4_TYPE]	= { .type = NLA_U8 },
  	[TCA_FLOWER_KEY_ICMPV4_TYPE_MASK] = { .type = NLA_U8 },
  	[TCA_FLOWER_KEY_ICMPV4_CODE]	= { .type = NLA_U8 },
  	[TCA_FLOWER_KEY_ICMPV4_CODE_MASK] = { .type = NLA_U8 },
  	[TCA_FLOWER_KEY_ICMPV6_TYPE]	= { .type = NLA_U8 },
  	[TCA_FLOWER_KEY_ICMPV6_TYPE_MASK] = { .type = NLA_U8 },
  	[TCA_FLOWER_KEY_ICMPV6_CODE]	= { .type = NLA_U8 },
  	[TCA_FLOWER_KEY_ICMPV6_CODE_MASK] = { .type = NLA_U8 },
99d31326c   Simon Horman   net/sched: cls_fl...
436
437
438
439
440
441
442
443
444
445
  	[TCA_FLOWER_KEY_ARP_SIP]	= { .type = NLA_U32 },
  	[TCA_FLOWER_KEY_ARP_SIP_MASK]	= { .type = NLA_U32 },
  	[TCA_FLOWER_KEY_ARP_TIP]	= { .type = NLA_U32 },
  	[TCA_FLOWER_KEY_ARP_TIP_MASK]	= { .type = NLA_U32 },
  	[TCA_FLOWER_KEY_ARP_OP]		= { .type = NLA_U8 },
  	[TCA_FLOWER_KEY_ARP_OP_MASK]	= { .type = NLA_U8 },
  	[TCA_FLOWER_KEY_ARP_SHA]	= { .len = ETH_ALEN },
  	[TCA_FLOWER_KEY_ARP_SHA_MASK]	= { .len = ETH_ALEN },
  	[TCA_FLOWER_KEY_ARP_THA]	= { .len = ETH_ALEN },
  	[TCA_FLOWER_KEY_ARP_THA_MASK]	= { .len = ETH_ALEN },
a577d8f79   Benjamin LaHaise   cls_flower: add s...
446
447
448
449
  	[TCA_FLOWER_KEY_MPLS_TTL]	= { .type = NLA_U8 },
  	[TCA_FLOWER_KEY_MPLS_BOS]	= { .type = NLA_U8 },
  	[TCA_FLOWER_KEY_MPLS_TC]	= { .type = NLA_U8 },
  	[TCA_FLOWER_KEY_MPLS_LABEL]	= { .type = NLA_U32 },
fdfc7dd6c   Jiri Pirko   net/sched: flower...
450
451
  	[TCA_FLOWER_KEY_TCP_FLAGS]	= { .type = NLA_U16 },
  	[TCA_FLOWER_KEY_TCP_FLAGS_MASK]	= { .type = NLA_U16 },
4d80cc0aa   Or Gerlitz   net/sched: cls_fl...
452
453
454
455
  	[TCA_FLOWER_KEY_IP_TOS]		= { .type = NLA_U8 },
  	[TCA_FLOWER_KEY_IP_TOS_MASK]	= { .type = NLA_U8 },
  	[TCA_FLOWER_KEY_IP_TTL]		= { .type = NLA_U8 },
  	[TCA_FLOWER_KEY_IP_TTL_MASK]	= { .type = NLA_U8 },
d64efd092   Jianbo Liu   net/sched: flower...
456
457
458
  	[TCA_FLOWER_KEY_CVLAN_ID]	= { .type = NLA_U16 },
  	[TCA_FLOWER_KEY_CVLAN_PRIO]	= { .type = NLA_U8 },
  	[TCA_FLOWER_KEY_CVLAN_ETH_TYPE]	= { .type = NLA_U16 },
0e2c17b64   Or Gerlitz   net/sched: cls_fl...
459
460
461
462
  	[TCA_FLOWER_KEY_ENC_IP_TOS]	= { .type = NLA_U8 },
  	[TCA_FLOWER_KEY_ENC_IP_TOS_MASK] = { .type = NLA_U8 },
  	[TCA_FLOWER_KEY_ENC_IP_TTL]	 = { .type = NLA_U8 },
  	[TCA_FLOWER_KEY_ENC_IP_TTL_MASK] = { .type = NLA_U8 },
0a6e77784   Pieter Jansen van Vuuren   net/sched: allow ...
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
  	[TCA_FLOWER_KEY_ENC_OPTS]	= { .type = NLA_NESTED },
  	[TCA_FLOWER_KEY_ENC_OPTS_MASK]	= { .type = NLA_NESTED },
  };
  
  static const struct nla_policy
  enc_opts_policy[TCA_FLOWER_KEY_ENC_OPTS_MAX + 1] = {
  	[TCA_FLOWER_KEY_ENC_OPTS_GENEVE]        = { .type = NLA_NESTED },
  };
  
  static const struct nla_policy
  geneve_opt_policy[TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX + 1] = {
  	[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS]      = { .type = NLA_U16 },
  	[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE]       = { .type = NLA_U8 },
  	[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA]       = { .type = NLA_BINARY,
  						       .len = 128 },
77b9900ef   Jiri Pirko   tc: introduce Flo...
478
479
480
481
482
483
484
485
486
487
488
489
490
491
  };
  
  static void fl_set_key_val(struct nlattr **tb,
  			   void *val, int val_type,
  			   void *mask, int mask_type, int len)
  {
  	if (!tb[val_type])
  		return;
  	memcpy(val, nla_data(tb[val_type]), len);
  	if (mask_type == TCA_FLOWER_UNSPEC || !tb[mask_type])
  		memset(mask, 0xff, len);
  	else
  		memcpy(mask, nla_data(tb[mask_type]), len);
  }
1a7fca63c   Benjamin LaHaise   flower: check unu...
492
493
494
  static int fl_set_key_mpls(struct nlattr **tb,
  			   struct flow_dissector_key_mpls *key_val,
  			   struct flow_dissector_key_mpls *key_mask)
a577d8f79   Benjamin LaHaise   cls_flower: add s...
495
496
497
498
499
500
  {
  	if (tb[TCA_FLOWER_KEY_MPLS_TTL]) {
  		key_val->mpls_ttl = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TTL]);
  		key_mask->mpls_ttl = MPLS_TTL_MASK;
  	}
  	if (tb[TCA_FLOWER_KEY_MPLS_BOS]) {
1a7fca63c   Benjamin LaHaise   flower: check unu...
501
502
503
504
505
  		u8 bos = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_BOS]);
  
  		if (bos & ~MPLS_BOS_MASK)
  			return -EINVAL;
  		key_val->mpls_bos = bos;
a577d8f79   Benjamin LaHaise   cls_flower: add s...
506
507
508
  		key_mask->mpls_bos = MPLS_BOS_MASK;
  	}
  	if (tb[TCA_FLOWER_KEY_MPLS_TC]) {
1a7fca63c   Benjamin LaHaise   flower: check unu...
509
510
511
512
513
  		u8 tc = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TC]);
  
  		if (tc & ~MPLS_TC_MASK)
  			return -EINVAL;
  		key_val->mpls_tc = tc;
a577d8f79   Benjamin LaHaise   cls_flower: add s...
514
515
516
  		key_mask->mpls_tc = MPLS_TC_MASK;
  	}
  	if (tb[TCA_FLOWER_KEY_MPLS_LABEL]) {
1a7fca63c   Benjamin LaHaise   flower: check unu...
517
518
519
520
521
  		u32 label = nla_get_u32(tb[TCA_FLOWER_KEY_MPLS_LABEL]);
  
  		if (label & ~MPLS_LABEL_MASK)
  			return -EINVAL;
  		key_val->mpls_label = label;
a577d8f79   Benjamin LaHaise   cls_flower: add s...
522
523
  		key_mask->mpls_label = MPLS_LABEL_MASK;
  	}
1a7fca63c   Benjamin LaHaise   flower: check unu...
524
  	return 0;
a577d8f79   Benjamin LaHaise   cls_flower: add s...
525
  }
9399ae9a6   Hadar Hen Zion   net_sched: flower...
526
  static void fl_set_key_vlan(struct nlattr **tb,
aaab08344   Jianbo Liu   net/sched: flower...
527
  			    __be16 ethertype,
d64efd092   Jianbo Liu   net/sched: flower...
528
  			    int vlan_id_key, int vlan_prio_key,
9399ae9a6   Hadar Hen Zion   net_sched: flower...
529
530
531
532
  			    struct flow_dissector_key_vlan *key_val,
  			    struct flow_dissector_key_vlan *key_mask)
  {
  #define VLAN_PRIORITY_MASK	0x7
d64efd092   Jianbo Liu   net/sched: flower...
533
  	if (tb[vlan_id_key]) {
9399ae9a6   Hadar Hen Zion   net_sched: flower...
534
  		key_val->vlan_id =
d64efd092   Jianbo Liu   net/sched: flower...
535
  			nla_get_u16(tb[vlan_id_key]) & VLAN_VID_MASK;
9399ae9a6   Hadar Hen Zion   net_sched: flower...
536
537
  		key_mask->vlan_id = VLAN_VID_MASK;
  	}
d64efd092   Jianbo Liu   net/sched: flower...
538
  	if (tb[vlan_prio_key]) {
9399ae9a6   Hadar Hen Zion   net_sched: flower...
539
  		key_val->vlan_priority =
d64efd092   Jianbo Liu   net/sched: flower...
540
  			nla_get_u8(tb[vlan_prio_key]) &
9399ae9a6   Hadar Hen Zion   net_sched: flower...
541
542
543
  			VLAN_PRIORITY_MASK;
  		key_mask->vlan_priority = VLAN_PRIORITY_MASK;
  	}
aaab08344   Jianbo Liu   net/sched: flower...
544
545
  	key_val->vlan_tpid = ethertype;
  	key_mask->vlan_tpid = cpu_to_be16(~0);
9399ae9a6   Hadar Hen Zion   net_sched: flower...
546
  }
faa3ffce7   Or Gerlitz   net/sched: cls_fl...
547
548
549
550
551
552
553
554
555
556
  static void fl_set_key_flag(u32 flower_key, u32 flower_mask,
  			    u32 *dissector_key, u32 *dissector_mask,
  			    u32 flower_flag_bit, u32 dissector_flag_bit)
  {
  	if (flower_mask & flower_flag_bit) {
  		*dissector_mask |= dissector_flag_bit;
  		if (flower_key & flower_flag_bit)
  			*dissector_key |= dissector_flag_bit;
  	}
  }
d9724772e   Or Gerlitz   net/sched: cls_fl...
557
558
  static int fl_set_key_flags(struct nlattr **tb,
  			    u32 *flags_key, u32 *flags_mask)
faa3ffce7   Or Gerlitz   net/sched: cls_fl...
559
560
  {
  	u32 key, mask;
d9724772e   Or Gerlitz   net/sched: cls_fl...
561
562
563
  	/* mask is mandatory for flags */
  	if (!tb[TCA_FLOWER_KEY_FLAGS_MASK])
  		return -EINVAL;
faa3ffce7   Or Gerlitz   net/sched: cls_fl...
564
565
  
  	key = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS]));
d9724772e   Or Gerlitz   net/sched: cls_fl...
566
  	mask = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS_MASK]));
faa3ffce7   Or Gerlitz   net/sched: cls_fl...
567
568
569
570
571
572
  
  	*flags_key  = 0;
  	*flags_mask = 0;
  
  	fl_set_key_flag(key, mask, flags_key, flags_mask,
  			TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT);
459d153d9   Pieter Jansen van Vuuren   net/sched: cls_fl...
573
574
575
  	fl_set_key_flag(key, mask, flags_key, flags_mask,
  			TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST,
  			FLOW_DIS_FIRST_FRAG);
d9724772e   Or Gerlitz   net/sched: cls_fl...
576
577
  
  	return 0;
faa3ffce7   Or Gerlitz   net/sched: cls_fl...
578
  }
0e2c17b64   Or Gerlitz   net/sched: cls_fl...
579
  static void fl_set_key_ip(struct nlattr **tb, bool encap,
4d80cc0aa   Or Gerlitz   net/sched: cls_fl...
580
581
582
  			  struct flow_dissector_key_ip *key,
  			  struct flow_dissector_key_ip *mask)
  {
0e2c17b64   Or Gerlitz   net/sched: cls_fl...
583
584
585
586
  	int tos_key = encap ? TCA_FLOWER_KEY_ENC_IP_TOS : TCA_FLOWER_KEY_IP_TOS;
  	int ttl_key = encap ? TCA_FLOWER_KEY_ENC_IP_TTL : TCA_FLOWER_KEY_IP_TTL;
  	int tos_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TOS_MASK : TCA_FLOWER_KEY_IP_TOS_MASK;
  	int ttl_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TTL_MASK : TCA_FLOWER_KEY_IP_TTL_MASK;
4d80cc0aa   Or Gerlitz   net/sched: cls_fl...
587

0e2c17b64   Or Gerlitz   net/sched: cls_fl...
588
589
  	fl_set_key_val(tb, &key->tos, tos_key, &mask->tos, tos_mask, sizeof(key->tos));
  	fl_set_key_val(tb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl));
4d80cc0aa   Or Gerlitz   net/sched: cls_fl...
590
  }
0a6e77784   Pieter Jansen van Vuuren   net/sched: allow ...
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
  static int fl_set_geneve_opt(const struct nlattr *nla, struct fl_flow_key *key,
  			     int depth, int option_len,
  			     struct netlink_ext_ack *extack)
  {
  	struct nlattr *tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX + 1];
  	struct nlattr *class = NULL, *type = NULL, *data = NULL;
  	struct geneve_opt *opt;
  	int err, data_len = 0;
  
  	if (option_len > sizeof(struct geneve_opt))
  		data_len = option_len - sizeof(struct geneve_opt);
  
  	opt = (struct geneve_opt *)&key->enc_opts.data[key->enc_opts.len];
  	memset(opt, 0xff, option_len);
  	opt->length = data_len / 4;
  	opt->r1 = 0;
  	opt->r2 = 0;
  	opt->r3 = 0;
  
  	/* If no mask has been prodived we assume an exact match. */
  	if (!depth)
  		return sizeof(struct geneve_opt) + data_len;
  
  	if (nla_type(nla) != TCA_FLOWER_KEY_ENC_OPTS_GENEVE) {
  		NL_SET_ERR_MSG(extack, "Non-geneve option type for mask");
  		return -EINVAL;
  	}
  
  	err = nla_parse_nested(tb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX,
  			       nla, geneve_opt_policy, extack);
  	if (err < 0)
  		return err;
  
  	/* We are not allowed to omit any of CLASS, TYPE or DATA
  	 * fields from the key.
  	 */
  	if (!option_len &&
  	    (!tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS] ||
  	     !tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE] ||
  	     !tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA])) {
  		NL_SET_ERR_MSG(extack, "Missing tunnel key geneve option class, type or data");
  		return -EINVAL;
  	}
  
  	/* Omitting any of CLASS, TYPE or DATA fields is allowed
  	 * for the mask.
  	 */
  	if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA]) {
  		int new_len = key->enc_opts.len;
  
  		data = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA];
  		data_len = nla_len(data);
  		if (data_len < 4) {
  			NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is less than 4 bytes long");
  			return -ERANGE;
  		}
  		if (data_len % 4) {
  			NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is not a multiple of 4 bytes long");
  			return -ERANGE;
  		}
  
  		new_len += sizeof(struct geneve_opt) + data_len;
  		BUILD_BUG_ON(FLOW_DIS_TUN_OPTS_MAX != IP_TUNNEL_OPTS_MAX);
  		if (new_len > FLOW_DIS_TUN_OPTS_MAX) {
  			NL_SET_ERR_MSG(extack, "Tunnel options exceeds max size");
  			return -ERANGE;
  		}
  		opt->length = data_len / 4;
  		memcpy(opt->opt_data, nla_data(data), data_len);
  	}
  
  	if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS]) {
  		class = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS];
  		opt->opt_class = nla_get_be16(class);
  	}
  
  	if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE]) {
  		type = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE];
  		opt->type = nla_get_u8(type);
  	}
  
  	return sizeof(struct geneve_opt) + data_len;
  }
  
  static int fl_set_enc_opt(struct nlattr **tb, struct fl_flow_key *key,
  			  struct fl_flow_key *mask,
  			  struct netlink_ext_ack *extack)
  {
  	const struct nlattr *nla_enc_key, *nla_opt_key, *nla_opt_msk = NULL;
ed25a2066   Jakub Kicinski   net: sched: cls_f...
680
681
682
683
684
685
686
  	int err, option_len, key_depth, msk_depth = 0;
  
  	err = nla_validate_nested(tb[TCA_FLOWER_KEY_ENC_OPTS],
  				  TCA_FLOWER_KEY_ENC_OPTS_MAX,
  				  enc_opts_policy, extack);
  	if (err)
  		return err;
0a6e77784   Pieter Jansen van Vuuren   net/sched: allow ...
687
688
689
690
  
  	nla_enc_key = nla_data(tb[TCA_FLOWER_KEY_ENC_OPTS]);
  
  	if (tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]) {
ed25a2066   Jakub Kicinski   net: sched: cls_f...
691
692
693
694
695
  		err = nla_validate_nested(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK],
  					  TCA_FLOWER_KEY_ENC_OPTS_MAX,
  					  enc_opts_policy, extack);
  		if (err)
  			return err;
0a6e77784   Pieter Jansen van Vuuren   net/sched: allow ...
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
  		nla_opt_msk = nla_data(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]);
  		msk_depth = nla_len(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]);
  	}
  
  	nla_for_each_attr(nla_opt_key, nla_enc_key,
  			  nla_len(tb[TCA_FLOWER_KEY_ENC_OPTS]), key_depth) {
  		switch (nla_type(nla_opt_key)) {
  		case TCA_FLOWER_KEY_ENC_OPTS_GENEVE:
  			option_len = 0;
  			key->enc_opts.dst_opt_type = TUNNEL_GENEVE_OPT;
  			option_len = fl_set_geneve_opt(nla_opt_key, key,
  						       key_depth, option_len,
  						       extack);
  			if (option_len < 0)
  				return option_len;
  
  			key->enc_opts.len += option_len;
  			/* At the same time we need to parse through the mask
  			 * in order to verify exact and mask attribute lengths.
  			 */
  			mask->enc_opts.dst_opt_type = TUNNEL_GENEVE_OPT;
  			option_len = fl_set_geneve_opt(nla_opt_msk, mask,
  						       msk_depth, option_len,
  						       extack);
  			if (option_len < 0)
  				return option_len;
  
  			mask->enc_opts.len += option_len;
  			if (key->enc_opts.len != mask->enc_opts.len) {
  				NL_SET_ERR_MSG(extack, "Key and mask miss aligned");
  				return -EINVAL;
  			}
  
  			if (msk_depth)
  				nla_opt_msk = nla_next(nla_opt_msk, &msk_depth);
  			break;
  		default:
  			NL_SET_ERR_MSG(extack, "Unknown tunnel option type");
  			return -EINVAL;
  		}
  	}
  
  	return 0;
  }
77b9900ef   Jiri Pirko   tc: introduce Flo...
740
  static int fl_set_key(struct net *net, struct nlattr **tb,
1057c55f6   Alexander Aring   net: sched: cls: ...
741
742
  		      struct fl_flow_key *key, struct fl_flow_key *mask,
  		      struct netlink_ext_ack *extack)
77b9900ef   Jiri Pirko   tc: introduce Flo...
743
  {
9399ae9a6   Hadar Hen Zion   net_sched: flower...
744
  	__be16 ethertype;
d9724772e   Or Gerlitz   net/sched: cls_fl...
745
  	int ret = 0;
dd3aa3b5f   Brian Haley   cls_flower: Fix c...
746
  #ifdef CONFIG_NET_CLS_IND
77b9900ef   Jiri Pirko   tc: introduce Flo...
747
  	if (tb[TCA_FLOWER_INDEV]) {
1057c55f6   Alexander Aring   net: sched: cls: ...
748
  		int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV], extack);
77b9900ef   Jiri Pirko   tc: introduce Flo...
749
750
751
752
753
  		if (err < 0)
  			return err;
  		key->indev_ifindex = err;
  		mask->indev_ifindex = 0xffffffff;
  	}
dd3aa3b5f   Brian Haley   cls_flower: Fix c...
754
  #endif
77b9900ef   Jiri Pirko   tc: introduce Flo...
755
756
757
758
759
760
761
  
  	fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
  		       mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
  		       sizeof(key->eth.dst));
  	fl_set_key_val(tb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
  		       mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
  		       sizeof(key->eth.src));
66530bdf8   Jamal Hadi Salim   sched,cls_flower:...
762

0b498a527   Arnd Bergmann   net_sched: fix us...
763
  	if (tb[TCA_FLOWER_KEY_ETH_TYPE]) {
9399ae9a6   Hadar Hen Zion   net_sched: flower...
764
  		ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_ETH_TYPE]);
aaab08344   Jianbo Liu   net/sched: flower...
765
  		if (eth_type_vlan(ethertype)) {
d64efd092   Jianbo Liu   net/sched: flower...
766
767
768
  			fl_set_key_vlan(tb, ethertype, TCA_FLOWER_KEY_VLAN_ID,
  					TCA_FLOWER_KEY_VLAN_PRIO, &key->vlan,
  					&mask->vlan);
5e9a0fe49   Jianbo Liu   net/sched: flower...
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
  			if (tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]) {
  				ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]);
  				if (eth_type_vlan(ethertype)) {
  					fl_set_key_vlan(tb, ethertype,
  							TCA_FLOWER_KEY_CVLAN_ID,
  							TCA_FLOWER_KEY_CVLAN_PRIO,
  							&key->cvlan, &mask->cvlan);
  					fl_set_key_val(tb, &key->basic.n_proto,
  						       TCA_FLOWER_KEY_CVLAN_ETH_TYPE,
  						       &mask->basic.n_proto,
  						       TCA_FLOWER_UNSPEC,
  						       sizeof(key->basic.n_proto));
  				} else {
  					key->basic.n_proto = ethertype;
  					mask->basic.n_proto = cpu_to_be16(~0);
  				}
d64efd092   Jianbo Liu   net/sched: flower...
785
  			}
0b498a527   Arnd Bergmann   net_sched: fix us...
786
787
788
789
  		} else {
  			key->basic.n_proto = ethertype;
  			mask->basic.n_proto = cpu_to_be16(~0);
  		}
9399ae9a6   Hadar Hen Zion   net_sched: flower...
790
  	}
66530bdf8   Jamal Hadi Salim   sched,cls_flower:...
791

77b9900ef   Jiri Pirko   tc: introduce Flo...
792
793
794
795
796
  	if (key->basic.n_proto == htons(ETH_P_IP) ||
  	    key->basic.n_proto == htons(ETH_P_IPV6)) {
  		fl_set_key_val(tb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
  			       &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
  			       sizeof(key->basic.ip_proto));
0e2c17b64   Or Gerlitz   net/sched: cls_fl...
797
  		fl_set_key_ip(tb, false, &key->ip, &mask->ip);
77b9900ef   Jiri Pirko   tc: introduce Flo...
798
  	}
66530bdf8   Jamal Hadi Salim   sched,cls_flower:...
799
800
801
  
  	if (tb[TCA_FLOWER_KEY_IPV4_SRC] || tb[TCA_FLOWER_KEY_IPV4_DST]) {
  		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
970bfcd09   Paul Blakey   net/sched: cls_fl...
802
  		mask->control.addr_type = ~0;
77b9900ef   Jiri Pirko   tc: introduce Flo...
803
804
805
806
807
808
  		fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
  			       &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
  			       sizeof(key->ipv4.src));
  		fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
  			       &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
  			       sizeof(key->ipv4.dst));
66530bdf8   Jamal Hadi Salim   sched,cls_flower:...
809
810
  	} else if (tb[TCA_FLOWER_KEY_IPV6_SRC] || tb[TCA_FLOWER_KEY_IPV6_DST]) {
  		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
970bfcd09   Paul Blakey   net/sched: cls_fl...
811
  		mask->control.addr_type = ~0;
77b9900ef   Jiri Pirko   tc: introduce Flo...
812
813
814
815
816
817
818
  		fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
  			       &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
  			       sizeof(key->ipv6.src));
  		fl_set_key_val(tb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
  			       &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
  			       sizeof(key->ipv6.dst));
  	}
66530bdf8   Jamal Hadi Salim   sched,cls_flower:...
819

77b9900ef   Jiri Pirko   tc: introduce Flo...
820
821
  	if (key->basic.ip_proto == IPPROTO_TCP) {
  		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
aa72d7083   Or Gerlitz   net/sched: cls_fl...
822
  			       &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
77b9900ef   Jiri Pirko   tc: introduce Flo...
823
824
  			       sizeof(key->tp.src));
  		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
aa72d7083   Or Gerlitz   net/sched: cls_fl...
825
  			       &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
77b9900ef   Jiri Pirko   tc: introduce Flo...
826
  			       sizeof(key->tp.dst));
fdfc7dd6c   Jiri Pirko   net/sched: flower...
827
828
829
  		fl_set_key_val(tb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS,
  			       &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK,
  			       sizeof(key->tcp.flags));
77b9900ef   Jiri Pirko   tc: introduce Flo...
830
831
  	} else if (key->basic.ip_proto == IPPROTO_UDP) {
  		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
aa72d7083   Or Gerlitz   net/sched: cls_fl...
832
  			       &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
77b9900ef   Jiri Pirko   tc: introduce Flo...
833
834
  			       sizeof(key->tp.src));
  		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
aa72d7083   Or Gerlitz   net/sched: cls_fl...
835
  			       &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
77b9900ef   Jiri Pirko   tc: introduce Flo...
836
  			       sizeof(key->tp.dst));
5976c5f45   Simon Horman   net/sched: cls_fl...
837
838
839
840
841
842
843
  	} else if (key->basic.ip_proto == IPPROTO_SCTP) {
  		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
  			       &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
  			       sizeof(key->tp.src));
  		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
  			       &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
  			       sizeof(key->tp.dst));
7b684884f   Simon Horman   net/sched: cls_fl...
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
  	} else if (key->basic.n_proto == htons(ETH_P_IP) &&
  		   key->basic.ip_proto == IPPROTO_ICMP) {
  		fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV4_TYPE,
  			       &mask->icmp.type,
  			       TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,
  			       sizeof(key->icmp.type));
  		fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE,
  			       &mask->icmp.code,
  			       TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
  			       sizeof(key->icmp.code));
  	} else if (key->basic.n_proto == htons(ETH_P_IPV6) &&
  		   key->basic.ip_proto == IPPROTO_ICMPV6) {
  		fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV6_TYPE,
  			       &mask->icmp.type,
  			       TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
  			       sizeof(key->icmp.type));
040587af3   Simon Horman   net/sched: cls_fl...
860
  		fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV6_CODE,
7b684884f   Simon Horman   net/sched: cls_fl...
861
  			       &mask->icmp.code,
040587af3   Simon Horman   net/sched: cls_fl...
862
  			       TCA_FLOWER_KEY_ICMPV6_CODE_MASK,
7b684884f   Simon Horman   net/sched: cls_fl...
863
  			       sizeof(key->icmp.code));
a577d8f79   Benjamin LaHaise   cls_flower: add s...
864
865
  	} else if (key->basic.n_proto == htons(ETH_P_MPLS_UC) ||
  		   key->basic.n_proto == htons(ETH_P_MPLS_MC)) {
1a7fca63c   Benjamin LaHaise   flower: check unu...
866
867
868
  		ret = fl_set_key_mpls(tb, &key->mpls, &mask->mpls);
  		if (ret)
  			return ret;
99d31326c   Simon Horman   net/sched: cls_fl...
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
  	} else if (key->basic.n_proto == htons(ETH_P_ARP) ||
  		   key->basic.n_proto == htons(ETH_P_RARP)) {
  		fl_set_key_val(tb, &key->arp.sip, TCA_FLOWER_KEY_ARP_SIP,
  			       &mask->arp.sip, TCA_FLOWER_KEY_ARP_SIP_MASK,
  			       sizeof(key->arp.sip));
  		fl_set_key_val(tb, &key->arp.tip, TCA_FLOWER_KEY_ARP_TIP,
  			       &mask->arp.tip, TCA_FLOWER_KEY_ARP_TIP_MASK,
  			       sizeof(key->arp.tip));
  		fl_set_key_val(tb, &key->arp.op, TCA_FLOWER_KEY_ARP_OP,
  			       &mask->arp.op, TCA_FLOWER_KEY_ARP_OP_MASK,
  			       sizeof(key->arp.op));
  		fl_set_key_val(tb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA,
  			       mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK,
  			       sizeof(key->arp.sha));
  		fl_set_key_val(tb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA,
  			       mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK,
  			       sizeof(key->arp.tha));
77b9900ef   Jiri Pirko   tc: introduce Flo...
886
  	}
bc3103f1e   Amir Vadai   net/sched: cls_fl...
887
888
889
  	if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] ||
  	    tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) {
  		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
970bfcd09   Paul Blakey   net/sched: cls_fl...
890
  		mask->enc_control.addr_type = ~0;
bc3103f1e   Amir Vadai   net/sched: cls_fl...
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
  		fl_set_key_val(tb, &key->enc_ipv4.src,
  			       TCA_FLOWER_KEY_ENC_IPV4_SRC,
  			       &mask->enc_ipv4.src,
  			       TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
  			       sizeof(key->enc_ipv4.src));
  		fl_set_key_val(tb, &key->enc_ipv4.dst,
  			       TCA_FLOWER_KEY_ENC_IPV4_DST,
  			       &mask->enc_ipv4.dst,
  			       TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
  			       sizeof(key->enc_ipv4.dst));
  	}
  
  	if (tb[TCA_FLOWER_KEY_ENC_IPV6_SRC] ||
  	    tb[TCA_FLOWER_KEY_ENC_IPV6_DST]) {
  		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
970bfcd09   Paul Blakey   net/sched: cls_fl...
906
  		mask->enc_control.addr_type = ~0;
bc3103f1e   Amir Vadai   net/sched: cls_fl...
907
908
909
910
911
912
913
914
915
916
917
918
919
  		fl_set_key_val(tb, &key->enc_ipv6.src,
  			       TCA_FLOWER_KEY_ENC_IPV6_SRC,
  			       &mask->enc_ipv6.src,
  			       TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
  			       sizeof(key->enc_ipv6.src));
  		fl_set_key_val(tb, &key->enc_ipv6.dst,
  			       TCA_FLOWER_KEY_ENC_IPV6_DST,
  			       &mask->enc_ipv6.dst,
  			       TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
  			       sizeof(key->enc_ipv6.dst));
  	}
  
  	fl_set_key_val(tb, &key->enc_key_id.keyid, TCA_FLOWER_KEY_ENC_KEY_ID,
eb523f42d   Hadar Hen Zion   net/sched: cls_fl...
920
  		       &mask->enc_key_id.keyid, TCA_FLOWER_UNSPEC,
bc3103f1e   Amir Vadai   net/sched: cls_fl...
921
  		       sizeof(key->enc_key_id.keyid));
f4d997fd6   Hadar Hen Zion   net/sched: cls_fl...
922
923
924
925
926
927
928
  	fl_set_key_val(tb, &key->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
  		       &mask->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
  		       sizeof(key->enc_tp.src));
  
  	fl_set_key_val(tb, &key->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
  		       &mask->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
  		       sizeof(key->enc_tp.dst));
0e2c17b64   Or Gerlitz   net/sched: cls_fl...
929
  	fl_set_key_ip(tb, true, &key->enc_ip, &mask->enc_ip);
0a6e77784   Pieter Jansen van Vuuren   net/sched: allow ...
930
931
932
933
934
  	if (tb[TCA_FLOWER_KEY_ENC_OPTS]) {
  		ret = fl_set_enc_opt(tb, key, mask, extack);
  		if (ret)
  			return ret;
  	}
d9724772e   Or Gerlitz   net/sched: cls_fl...
935
936
  	if (tb[TCA_FLOWER_KEY_FLAGS])
  		ret = fl_set_key_flags(tb, &key->control.flags, &mask->control.flags);
faa3ffce7   Or Gerlitz   net/sched: cls_fl...
937

d9724772e   Or Gerlitz   net/sched: cls_fl...
938
  	return ret;
77b9900ef   Jiri Pirko   tc: introduce Flo...
939
  }
05cd271fd   Paul Blakey   cls_flower: Suppo...
940
941
  static void fl_mask_copy(struct fl_flow_mask *dst,
  			 struct fl_flow_mask *src)
77b9900ef   Jiri Pirko   tc: introduce Flo...
942
  {
05cd271fd   Paul Blakey   cls_flower: Suppo...
943
944
  	const void *psrc = fl_key_get_start(&src->key, src);
  	void *pdst = fl_key_get_start(&dst->key, src);
77b9900ef   Jiri Pirko   tc: introduce Flo...
945

05cd271fd   Paul Blakey   cls_flower: Suppo...
946
947
  	memcpy(pdst, psrc, fl_mask_range(src));
  	dst->range = src->range;
77b9900ef   Jiri Pirko   tc: introduce Flo...
948
949
950
951
952
953
954
  }
  
  static const struct rhashtable_params fl_ht_params = {
  	.key_offset = offsetof(struct cls_fl_filter, mkey), /* base offset */
  	.head_offset = offsetof(struct cls_fl_filter, ht_node),
  	.automatic_shrinking = true,
  };
05cd271fd   Paul Blakey   cls_flower: Suppo...
955
  static int fl_init_mask_hashtable(struct fl_flow_mask *mask)
77b9900ef   Jiri Pirko   tc: introduce Flo...
956
  {
05cd271fd   Paul Blakey   cls_flower: Suppo...
957
958
959
  	mask->filter_ht_params = fl_ht_params;
  	mask->filter_ht_params.key_len = fl_mask_range(mask);
  	mask->filter_ht_params.key_offset += mask->range.start;
77b9900ef   Jiri Pirko   tc: introduce Flo...
960

05cd271fd   Paul Blakey   cls_flower: Suppo...
961
  	return rhashtable_init(&mask->ht, &mask->filter_ht_params);
77b9900ef   Jiri Pirko   tc: introduce Flo...
962
963
964
965
  }
  
  #define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member)
  #define FL_KEY_MEMBER_SIZE(member) (sizeof(((struct fl_flow_key *) 0)->member))
77b9900ef   Jiri Pirko   tc: introduce Flo...
966

339ba878c   Hadar Hen Zion   net_sched: flower...
967
968
969
  #define FL_KEY_IS_MASKED(mask, member)						\
  	memchr_inv(((char *)mask) + FL_KEY_MEMBER_OFFSET(member),		\
  		   0, FL_KEY_MEMBER_SIZE(member))				\
77b9900ef   Jiri Pirko   tc: introduce Flo...
970
971
972
973
974
975
976
  
  #define FL_KEY_SET(keys, cnt, id, member)					\
  	do {									\
  		keys[cnt].key_id = id;						\
  		keys[cnt].offset = FL_KEY_MEMBER_OFFSET(member);		\
  		cnt++;								\
  	} while(0);
339ba878c   Hadar Hen Zion   net_sched: flower...
977
  #define FL_KEY_SET_IF_MASKED(mask, keys, cnt, id, member)			\
77b9900ef   Jiri Pirko   tc: introduce Flo...
978
  	do {									\
339ba878c   Hadar Hen Zion   net_sched: flower...
979
  		if (FL_KEY_IS_MASKED(mask, member))				\
77b9900ef   Jiri Pirko   tc: introduce Flo...
980
981
  			FL_KEY_SET(keys, cnt, id, member);			\
  	} while(0);
33fb5cba1   Jiri Pirko   net: sched: cls_f...
982
983
  static void fl_init_dissector(struct flow_dissector *dissector,
  			      struct fl_flow_key *mask)
77b9900ef   Jiri Pirko   tc: introduce Flo...
984
985
986
  {
  	struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX];
  	size_t cnt = 0;
42aecaa9b   Tom Herbert   net: Get skb hash...
987
  	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control);
77b9900ef   Jiri Pirko   tc: introduce Flo...
988
  	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic);
33fb5cba1   Jiri Pirko   net: sched: cls_f...
989
  	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
339ba878c   Hadar Hen Zion   net_sched: flower...
990
  			     FLOW_DISSECTOR_KEY_ETH_ADDRS, eth);
33fb5cba1   Jiri Pirko   net: sched: cls_f...
991
  	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
339ba878c   Hadar Hen Zion   net_sched: flower...
992
  			     FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4);
33fb5cba1   Jiri Pirko   net: sched: cls_f...
993
  	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
339ba878c   Hadar Hen Zion   net_sched: flower...
994
  			     FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6);
33fb5cba1   Jiri Pirko   net: sched: cls_f...
995
  	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
339ba878c   Hadar Hen Zion   net_sched: flower...
996
  			     FLOW_DISSECTOR_KEY_PORTS, tp);
33fb5cba1   Jiri Pirko   net: sched: cls_f...
997
  	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
4d80cc0aa   Or Gerlitz   net/sched: cls_fl...
998
  			     FLOW_DISSECTOR_KEY_IP, ip);
33fb5cba1   Jiri Pirko   net: sched: cls_f...
999
  	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
fdfc7dd6c   Jiri Pirko   net/sched: flower...
1000
  			     FLOW_DISSECTOR_KEY_TCP, tcp);
33fb5cba1   Jiri Pirko   net: sched: cls_f...
1001
  	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
7b684884f   Simon Horman   net/sched: cls_fl...
1002
  			     FLOW_DISSECTOR_KEY_ICMP, icmp);
33fb5cba1   Jiri Pirko   net: sched: cls_f...
1003
  	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
99d31326c   Simon Horman   net/sched: cls_fl...
1004
  			     FLOW_DISSECTOR_KEY_ARP, arp);
33fb5cba1   Jiri Pirko   net: sched: cls_f...
1005
  	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
a577d8f79   Benjamin LaHaise   cls_flower: add s...
1006
  			     FLOW_DISSECTOR_KEY_MPLS, mpls);
33fb5cba1   Jiri Pirko   net: sched: cls_f...
1007
  	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
9399ae9a6   Hadar Hen Zion   net_sched: flower...
1008
  			     FLOW_DISSECTOR_KEY_VLAN, vlan);
33fb5cba1   Jiri Pirko   net: sched: cls_f...
1009
  	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
d64efd092   Jianbo Liu   net/sched: flower...
1010
  			     FLOW_DISSECTOR_KEY_CVLAN, cvlan);
33fb5cba1   Jiri Pirko   net: sched: cls_f...
1011
  	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
519d10521   Hadar Hen Zion   net/sched: cls_fl...
1012
  			     FLOW_DISSECTOR_KEY_ENC_KEYID, enc_key_id);
33fb5cba1   Jiri Pirko   net: sched: cls_f...
1013
  	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
519d10521   Hadar Hen Zion   net/sched: cls_fl...
1014
  			     FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, enc_ipv4);
33fb5cba1   Jiri Pirko   net: sched: cls_f...
1015
  	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
519d10521   Hadar Hen Zion   net/sched: cls_fl...
1016
  			     FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, enc_ipv6);
33fb5cba1   Jiri Pirko   net: sched: cls_f...
1017
1018
  	if (FL_KEY_IS_MASKED(mask, enc_ipv4) ||
  	    FL_KEY_IS_MASKED(mask, enc_ipv6))
519d10521   Hadar Hen Zion   net/sched: cls_fl...
1019
1020
  		FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_ENC_CONTROL,
  			   enc_control);
33fb5cba1   Jiri Pirko   net: sched: cls_f...
1021
  	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
f4d997fd6   Hadar Hen Zion   net/sched: cls_fl...
1022
  			     FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp);
33fb5cba1   Jiri Pirko   net: sched: cls_f...
1023
  	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
0e2c17b64   Or Gerlitz   net/sched: cls_fl...
1024
  			     FLOW_DISSECTOR_KEY_ENC_IP, enc_ip);
0a6e77784   Pieter Jansen van Vuuren   net/sched: allow ...
1025
1026
  	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
  			     FLOW_DISSECTOR_KEY_ENC_OPTS, enc_opts);
77b9900ef   Jiri Pirko   tc: introduce Flo...
1027

33fb5cba1   Jiri Pirko   net: sched: cls_f...
1028
  	skb_flow_dissector_init(dissector, keys, cnt);
05cd271fd   Paul Blakey   cls_flower: Suppo...
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
  }
  
  static struct fl_flow_mask *fl_create_new_mask(struct cls_fl_head *head,
  					       struct fl_flow_mask *mask)
  {
  	struct fl_flow_mask *newmask;
  	int err;
  
  	newmask = kzalloc(sizeof(*newmask), GFP_KERNEL);
  	if (!newmask)
  		return ERR_PTR(-ENOMEM);
  
  	fl_mask_copy(newmask, mask);
  
  	err = fl_init_mask_hashtable(newmask);
  	if (err)
  		goto errout_free;
33fb5cba1   Jiri Pirko   net: sched: cls_f...
1046
  	fl_init_dissector(&newmask->dissector, &newmask->key);
05cd271fd   Paul Blakey   cls_flower: Suppo...
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
  
  	INIT_LIST_HEAD_RCU(&newmask->filters);
  
  	err = rhashtable_insert_fast(&head->ht, &newmask->ht_node,
  				     mask_ht_params);
  	if (err)
  		goto errout_destroy;
  
  	list_add_tail_rcu(&newmask->list, &head->masks);
  
  	return newmask;
  
  errout_destroy:
  	rhashtable_destroy(&newmask->ht);
  errout_free:
  	kfree(newmask);
  
  	return ERR_PTR(err);
77b9900ef   Jiri Pirko   tc: introduce Flo...
1065
1066
1067
  }
  
  static int fl_check_assign_mask(struct cls_fl_head *head,
05cd271fd   Paul Blakey   cls_flower: Suppo...
1068
1069
  				struct cls_fl_filter *fnew,
  				struct cls_fl_filter *fold,
77b9900ef   Jiri Pirko   tc: introduce Flo...
1070
1071
  				struct fl_flow_mask *mask)
  {
05cd271fd   Paul Blakey   cls_flower: Suppo...
1072
  	struct fl_flow_mask *newmask;
77b9900ef   Jiri Pirko   tc: introduce Flo...
1073

05cd271fd   Paul Blakey   cls_flower: Suppo...
1074
1075
1076
  	fnew->mask = rhashtable_lookup_fast(&head->ht, mask, mask_ht_params);
  	if (!fnew->mask) {
  		if (fold)
77b9900ef   Jiri Pirko   tc: introduce Flo...
1077
  			return -EINVAL;
77b9900ef   Jiri Pirko   tc: introduce Flo...
1078

05cd271fd   Paul Blakey   cls_flower: Suppo...
1079
1080
1081
  		newmask = fl_create_new_mask(head, mask);
  		if (IS_ERR(newmask))
  			return PTR_ERR(newmask);
77b9900ef   Jiri Pirko   tc: introduce Flo...
1082

05cd271fd   Paul Blakey   cls_flower: Suppo...
1083
  		fnew->mask = newmask;
f6521c587   Paul Blakey   cls_flower: Fix c...
1084
  	} else if (fold && fold->mask != fnew->mask) {
05cd271fd   Paul Blakey   cls_flower: Suppo...
1085
1086
  		return -EINVAL;
  	}
77b9900ef   Jiri Pirko   tc: introduce Flo...
1087
1088
1089
1090
1091
1092
1093
  
  	return 0;
  }
  
  static int fl_set_parms(struct net *net, struct tcf_proto *tp,
  			struct cls_fl_filter *f, struct fl_flow_mask *mask,
  			unsigned long base, struct nlattr **tb,
50a561900   Alexander Aring   net: sched: cls: ...
1094
  			struct nlattr *est, bool ovr,
b95ec7eb3   Jiri Pirko   net: sched: cls_f...
1095
  			struct fl_flow_tmplt *tmplt,
50a561900   Alexander Aring   net: sched: cls: ...
1096
  			struct netlink_ext_ack *extack)
77b9900ef   Jiri Pirko   tc: introduce Flo...
1097
  {
77b9900ef   Jiri Pirko   tc: introduce Flo...
1098
  	int err;
50a561900   Alexander Aring   net: sched: cls: ...
1099
  	err = tcf_exts_validate(net, tp, tb, est, &f->exts, ovr, extack);
77b9900ef   Jiri Pirko   tc: introduce Flo...
1100
1101
1102
1103
1104
1105
1106
  	if (err < 0)
  		return err;
  
  	if (tb[TCA_FLOWER_CLASSID]) {
  		f->res.classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]);
  		tcf_bind_filter(tp, &f->res, base);
  	}
1057c55f6   Alexander Aring   net: sched: cls: ...
1107
  	err = fl_set_key(net, tb, &f->key, &mask->key, extack);
77b9900ef   Jiri Pirko   tc: introduce Flo...
1108
  	if (err)
455075292   Jiri Pirko   net: sched: cls_f...
1109
  		return err;
77b9900ef   Jiri Pirko   tc: introduce Flo...
1110
1111
1112
  
  	fl_mask_update_range(mask);
  	fl_set_masked_key(&f->mkey, &f->key, mask);
b95ec7eb3   Jiri Pirko   net: sched: cls_f...
1113
1114
1115
1116
  	if (!fl_mask_fits_tmplt(tmplt, mask)) {
  		NL_SET_ERR_MSG_MOD(extack, "Mask does not fit the template");
  		return -EINVAL;
  	}
77b9900ef   Jiri Pirko   tc: introduce Flo...
1117
  	return 0;
77b9900ef   Jiri Pirko   tc: introduce Flo...
1118
  }
77b9900ef   Jiri Pirko   tc: introduce Flo...
1119
1120
1121
  static int fl_change(struct net *net, struct sk_buff *in_skb,
  		     struct tcf_proto *tp, unsigned long base,
  		     u32 handle, struct nlattr **tca,
7306db38a   Alexander Aring   net: sched: cls: ...
1122
  		     void **arg, bool ovr, struct netlink_ext_ack *extack)
77b9900ef   Jiri Pirko   tc: introduce Flo...
1123
1124
  {
  	struct cls_fl_head *head = rtnl_dereference(tp->root);
8113c0956   WANG Cong   net_sched: use vo...
1125
  	struct cls_fl_filter *fold = *arg;
77b9900ef   Jiri Pirko   tc: introduce Flo...
1126
  	struct cls_fl_filter *fnew;
84bf74307   Ivan Vecera   net/sched: cls_fl...
1127
  	struct fl_flow_mask *mask;
39b7b6a62   Arnd Bergmann   net/sched: cls_fl...
1128
  	struct nlattr **tb;
77b9900ef   Jiri Pirko   tc: introduce Flo...
1129
1130
1131
1132
  	int err;
  
  	if (!tca[TCA_OPTIONS])
  		return -EINVAL;
84bf74307   Ivan Vecera   net/sched: cls_fl...
1133
1134
  	mask = kzalloc(sizeof(struct fl_flow_mask), GFP_KERNEL);
  	if (!mask)
39b7b6a62   Arnd Bergmann   net/sched: cls_fl...
1135
  		return -ENOBUFS;
84bf74307   Ivan Vecera   net/sched: cls_fl...
1136
1137
1138
1139
1140
  	tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL);
  	if (!tb) {
  		err = -ENOBUFS;
  		goto errout_mask_alloc;
  	}
fceb6435e   Johannes Berg   netlink: pass ext...
1141
1142
  	err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS],
  			       fl_policy, NULL);
77b9900ef   Jiri Pirko   tc: introduce Flo...
1143
  	if (err < 0)
39b7b6a62   Arnd Bergmann   net/sched: cls_fl...
1144
  		goto errout_tb;
77b9900ef   Jiri Pirko   tc: introduce Flo...
1145

39b7b6a62   Arnd Bergmann   net/sched: cls_fl...
1146
1147
1148
1149
  	if (fold && handle && fold->handle != handle) {
  		err = -EINVAL;
  		goto errout_tb;
  	}
77b9900ef   Jiri Pirko   tc: introduce Flo...
1150
1151
  
  	fnew = kzalloc(sizeof(*fnew), GFP_KERNEL);
39b7b6a62   Arnd Bergmann   net/sched: cls_fl...
1152
1153
1154
1155
  	if (!fnew) {
  		err = -ENOBUFS;
  		goto errout_tb;
  	}
77b9900ef   Jiri Pirko   tc: introduce Flo...
1156

b9a24bb76   WANG Cong   net_sched: proper...
1157
1158
1159
  	err = tcf_exts_init(&fnew->exts, TCA_FLOWER_ACT, 0);
  	if (err < 0)
  		goto errout;
77b9900ef   Jiri Pirko   tc: introduce Flo...
1160

e69985c67   Amir Vadai   net/sched: cls_fl...
1161
1162
1163
1164
1165
  	if (tb[TCA_FLOWER_FLAGS]) {
  		fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
  
  		if (!tc_flags_valid(fnew->flags)) {
  			err = -EINVAL;
275a2c08c   Vlad Buslov   net: sched: flowe...
1166
  			goto errout;
e69985c67   Amir Vadai   net/sched: cls_fl...
1167
1168
  		}
  	}
5b33f4884   Amir Vadai   net/flower: Intro...
1169

84bf74307   Ivan Vecera   net/sched: cls_fl...
1170
  	err = fl_set_parms(net, tp, fnew, mask, base, tb, tca[TCA_RATE], ovr,
b95ec7eb3   Jiri Pirko   net: sched: cls_f...
1171
  			   tp->chain->tmplt_priv, extack);
77b9900ef   Jiri Pirko   tc: introduce Flo...
1172
  	if (err)
275a2c08c   Vlad Buslov   net: sched: flowe...
1173
  		goto errout;
77b9900ef   Jiri Pirko   tc: introduce Flo...
1174

84bf74307   Ivan Vecera   net/sched: cls_fl...
1175
  	err = fl_check_assign_mask(head, fnew, fold, mask);
77b9900ef   Jiri Pirko   tc: introduce Flo...
1176
  	if (err)
275a2c08c   Vlad Buslov   net: sched: flowe...
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
  		goto errout;
  
  	if (!handle) {
  		handle = 1;
  		err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
  				    INT_MAX, GFP_KERNEL);
  	} else if (!fold) {
  		/* user specifies a handle and it doesn't exist */
  		err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
  				    handle, GFP_KERNEL);
  	}
  	if (err)
  		goto errout_mask;
  	fnew->handle = handle;
77b9900ef   Jiri Pirko   tc: introduce Flo...
1191

e8eb36cd8   Amir Vadai   net/sched: flower...
1192
  	if (!tc_skip_sw(fnew->flags)) {
05cd271fd   Paul Blakey   cls_flower: Suppo...
1193
  		if (!fold && fl_lookup(fnew->mask, &fnew->mkey)) {
a3308d8fd   Paul Blakey   net/sched: cls_fl...
1194
  			err = -EEXIST;
275a2c08c   Vlad Buslov   net: sched: flowe...
1195
  			goto errout_idr;
a3308d8fd   Paul Blakey   net/sched: cls_fl...
1196
  		}
05cd271fd   Paul Blakey   cls_flower: Suppo...
1197
1198
  		err = rhashtable_insert_fast(&fnew->mask->ht, &fnew->ht_node,
  					     fnew->mask->filter_ht_params);
e69985c67   Amir Vadai   net/sched: cls_fl...
1199
  		if (err)
275a2c08c   Vlad Buslov   net: sched: flowe...
1200
  			goto errout_idr;
e69985c67   Amir Vadai   net/sched: cls_fl...
1201
  	}
5b33f4884   Amir Vadai   net/flower: Intro...
1202

796852197   Hadar Hen Zion   net/sched: cls_fl...
1203
  	if (!tc_skip_hw(fnew->flags)) {
05cd271fd   Paul Blakey   cls_flower: Suppo...
1204
  		err = fl_hw_replace_filter(tp, fnew, extack);
796852197   Hadar Hen Zion   net/sched: cls_fl...
1205
  		if (err)
05cd271fd   Paul Blakey   cls_flower: Suppo...
1206
  			goto errout_mask;
796852197   Hadar Hen Zion   net/sched: cls_fl...
1207
  	}
5b33f4884   Amir Vadai   net/flower: Intro...
1208

55593960d   Or Gerlitz   net/sched: cls_fl...
1209
1210
  	if (!tc_in_hw(fnew->flags))
  		fnew->flags |= TCA_CLS_FLAGS_NOT_IN_HW;
5b33f4884   Amir Vadai   net/flower: Intro...
1211
  	if (fold) {
725cbb62e   Jiri Pirko   sched: cls_flower...
1212
  		if (!tc_skip_sw(fold->flags))
05cd271fd   Paul Blakey   cls_flower: Suppo...
1213
1214
1215
  			rhashtable_remove_fast(&fold->mask->ht,
  					       &fold->ht_node,
  					       fold->mask->filter_ht_params);
796852197   Hadar Hen Zion   net/sched: cls_fl...
1216
  		if (!tc_skip_hw(fold->flags))
1b0f80375   Jakub Kicinski   cls_flower: propa...
1217
  			fl_hw_destroy_filter(tp, fold, NULL);
5b33f4884   Amir Vadai   net/flower: Intro...
1218
  	}
77b9900ef   Jiri Pirko   tc: introduce Flo...
1219

8113c0956   WANG Cong   net_sched: use vo...
1220
  	*arg = fnew;
77b9900ef   Jiri Pirko   tc: introduce Flo...
1221
1222
  
  	if (fold) {
234a4624e   Matthew Wilcox   idr: Delete idr_r...
1223
  		idr_replace(&head->handle_idr, fnew, fnew->handle);
ff3532f26   Daniel Borkmann   sched: cls_flower...
1224
  		list_replace_rcu(&fold->list, &fnew->list);
77b9900ef   Jiri Pirko   tc: introduce Flo...
1225
  		tcf_unbind_filter(tp, &fold->res);
0dadc117a   Cong Wang   cls_flower: use t...
1226
  		tcf_exts_get_net(&fold->exts);
aaa908ffb   Cong Wang   net_sched: switch...
1227
  		tcf_queue_work(&fold->rwork, fl_destroy_filter_work);
77b9900ef   Jiri Pirko   tc: introduce Flo...
1228
  	} else {
05cd271fd   Paul Blakey   cls_flower: Suppo...
1229
  		list_add_tail_rcu(&fnew->list, &fnew->mask->filters);
77b9900ef   Jiri Pirko   tc: introduce Flo...
1230
  	}
39b7b6a62   Arnd Bergmann   net/sched: cls_fl...
1231
  	kfree(tb);
84bf74307   Ivan Vecera   net/sched: cls_fl...
1232
  	kfree(mask);
77b9900ef   Jiri Pirko   tc: introduce Flo...
1233
  	return 0;
fe2502e49   Cong Wang   net_sched: remove...
1234
  errout_idr:
8258d2da9   Paul Blakey   cls_flower: Fix i...
1235
  	if (!fold)
9c1609414   Matthew Wilcox   idr: Delete idr_r...
1236
  		idr_remove(&head->handle_idr, fnew->handle);
275a2c08c   Vlad Buslov   net: sched: flowe...
1237
1238
1239
  
  errout_mask:
  	fl_mask_put(head, fnew->mask, false);
77b9900ef   Jiri Pirko   tc: introduce Flo...
1240
  errout:
b9a24bb76   WANG Cong   net_sched: proper...
1241
  	tcf_exts_destroy(&fnew->exts);
77b9900ef   Jiri Pirko   tc: introduce Flo...
1242
  	kfree(fnew);
39b7b6a62   Arnd Bergmann   net/sched: cls_fl...
1243
1244
  errout_tb:
  	kfree(tb);
84bf74307   Ivan Vecera   net/sched: cls_fl...
1245
1246
  errout_mask_alloc:
  	kfree(mask);
77b9900ef   Jiri Pirko   tc: introduce Flo...
1247
1248
  	return err;
  }
571acf210   Alexander Aring   net: sched: cls: ...
1249
1250
  static int fl_delete(struct tcf_proto *tp, void *arg, bool *last,
  		     struct netlink_ext_ack *extack)
77b9900ef   Jiri Pirko   tc: introduce Flo...
1251
1252
  {
  	struct cls_fl_head *head = rtnl_dereference(tp->root);
8113c0956   WANG Cong   net_sched: use vo...
1253
  	struct cls_fl_filter *f = arg;
77b9900ef   Jiri Pirko   tc: introduce Flo...
1254

725cbb62e   Jiri Pirko   sched: cls_flower...
1255
  	if (!tc_skip_sw(f->flags))
05cd271fd   Paul Blakey   cls_flower: Suppo...
1256
1257
  		rhashtable_remove_fast(&f->mask->ht, &f->ht_node,
  				       f->mask->filter_ht_params);
1b0f80375   Jakub Kicinski   cls_flower: propa...
1258
  	__fl_delete(tp, f, extack);
05cd271fd   Paul Blakey   cls_flower: Suppo...
1259
  	*last = list_empty(&head->masks);
77b9900ef   Jiri Pirko   tc: introduce Flo...
1260
1261
1262
1263
1264
1265
1266
  	return 0;
  }
  
  static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg)
  {
  	struct cls_fl_head *head = rtnl_dereference(tp->root);
  	struct cls_fl_filter *f;
05cd271fd   Paul Blakey   cls_flower: Suppo...
1267

01683a146   Vlad Buslov   net: sched: refac...
1268
1269
1270
1271
1272
1273
1274
  	arg->count = arg->skip;
  
  	while ((f = idr_get_next_ul(&head->handle_idr,
  				    &arg->cookie)) != NULL) {
  		if (arg->fn(tp, f, arg) < 0) {
  			arg->stop = 1;
  			break;
05cd271fd   Paul Blakey   cls_flower: Suppo...
1275
  		}
01683a146   Vlad Buslov   net: sched: refac...
1276
1277
  		arg->cookie = f->handle + 1;
  		arg->count++;
77b9900ef   Jiri Pirko   tc: introduce Flo...
1278
1279
  	}
  }
31533cba4   John Hurley   net: sched: cls_f...
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
  static int fl_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb,
  			void *cb_priv, struct netlink_ext_ack *extack)
  {
  	struct cls_fl_head *head = rtnl_dereference(tp->root);
  	struct tc_cls_flower_offload cls_flower = {};
  	struct tcf_block *block = tp->chain->block;
  	struct fl_flow_mask *mask;
  	struct cls_fl_filter *f;
  	int err;
  
  	list_for_each_entry(mask, &head->masks, list) {
  		list_for_each_entry(f, &mask->filters, list) {
  			if (tc_skip_hw(f->flags))
  				continue;
  
  			tc_cls_common_offload_init(&cls_flower.common, tp,
  						   f->flags, extack);
  			cls_flower.command = add ?
  				TC_CLSFLOWER_REPLACE : TC_CLSFLOWER_DESTROY;
  			cls_flower.cookie = (unsigned long)f;
  			cls_flower.dissector = &mask->dissector;
9ca616300   Vlad Buslov   net: sched: cls_f...
1301
1302
  			cls_flower.mask = &mask->key;
  			cls_flower.key = &f->mkey;
31533cba4   John Hurley   net: sched: cls_f...
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
  			cls_flower.exts = &f->exts;
  			cls_flower.classid = f->res.classid;
  
  			err = cb(TC_SETUP_CLSFLOWER, &cls_flower, cb_priv);
  			if (err) {
  				if (add && tc_skip_sw(f->flags))
  					return err;
  				continue;
  			}
  
  			tc_cls_offload_cnt_update(block, &f->in_hw_count,
  						  &f->flags, add);
  		}
  	}
  
  	return 0;
  }
347384527   Jiri Pirko   net: sched: cls_f...
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
  static void fl_hw_create_tmplt(struct tcf_chain *chain,
  			       struct fl_flow_tmplt *tmplt)
  {
  	struct tc_cls_flower_offload cls_flower = {};
  	struct tcf_block *block = chain->block;
  	struct tcf_exts dummy_exts = { 0, };
  
  	cls_flower.common.chain_index = chain->index;
  	cls_flower.command = TC_CLSFLOWER_TMPLT_CREATE;
  	cls_flower.cookie = (unsigned long) tmplt;
  	cls_flower.dissector = &tmplt->dissector;
  	cls_flower.mask = &tmplt->mask;
  	cls_flower.key = &tmplt->dummy_key;
  	cls_flower.exts = &dummy_exts;
  
  	/* We don't care if driver (any of them) fails to handle this
  	 * call. It serves just as a hint for it.
  	 */
  	tc_setup_cb_call(block, NULL, TC_SETUP_CLSFLOWER,
  			 &cls_flower, false);
  }
  
  static void fl_hw_destroy_tmplt(struct tcf_chain *chain,
  				struct fl_flow_tmplt *tmplt)
  {
  	struct tc_cls_flower_offload cls_flower = {};
  	struct tcf_block *block = chain->block;
  
  	cls_flower.common.chain_index = chain->index;
  	cls_flower.command = TC_CLSFLOWER_TMPLT_DESTROY;
  	cls_flower.cookie = (unsigned long) tmplt;
  
  	tc_setup_cb_call(block, NULL, TC_SETUP_CLSFLOWER,
  			 &cls_flower, false);
  }
b95ec7eb3   Jiri Pirko   net: sched: cls_f...
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
  static void *fl_tmplt_create(struct net *net, struct tcf_chain *chain,
  			     struct nlattr **tca,
  			     struct netlink_ext_ack *extack)
  {
  	struct fl_flow_tmplt *tmplt;
  	struct nlattr **tb;
  	int err;
  
  	if (!tca[TCA_OPTIONS])
  		return ERR_PTR(-EINVAL);
  
  	tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL);
  	if (!tb)
  		return ERR_PTR(-ENOBUFS);
  	err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS],
  			       fl_policy, NULL);
  	if (err)
  		goto errout_tb;
  
  	tmplt = kzalloc(sizeof(*tmplt), GFP_KERNEL);
1cbc36a53   Dan Carpenter   net: sched: cls_f...
1375
1376
  	if (!tmplt) {
  		err = -ENOMEM;
b95ec7eb3   Jiri Pirko   net: sched: cls_f...
1377
  		goto errout_tb;
1cbc36a53   Dan Carpenter   net: sched: cls_f...
1378
  	}
b95ec7eb3   Jiri Pirko   net: sched: cls_f...
1379
1380
1381
1382
1383
1384
1385
  	tmplt->chain = chain;
  	err = fl_set_key(net, tb, &tmplt->dummy_key, &tmplt->mask, extack);
  	if (err)
  		goto errout_tmplt;
  	kfree(tb);
  
  	fl_init_dissector(&tmplt->dissector, &tmplt->mask);
347384527   Jiri Pirko   net: sched: cls_f...
1386
  	fl_hw_create_tmplt(chain, tmplt);
b95ec7eb3   Jiri Pirko   net: sched: cls_f...
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
  	return tmplt;
  
  errout_tmplt:
  	kfree(tmplt);
  errout_tb:
  	kfree(tb);
  	return ERR_PTR(err);
  }
  
  static void fl_tmplt_destroy(void *tmplt_priv)
  {
  	struct fl_flow_tmplt *tmplt = tmplt_priv;
347384527   Jiri Pirko   net: sched: cls_f...
1399
  	fl_hw_destroy_tmplt(tmplt->chain, tmplt);
b95ec7eb3   Jiri Pirko   net: sched: cls_f...
1400
1401
  	kfree(tmplt);
  }
77b9900ef   Jiri Pirko   tc: introduce Flo...
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
  static int fl_dump_key_val(struct sk_buff *skb,
  			   void *val, int val_type,
  			   void *mask, int mask_type, int len)
  {
  	int err;
  
  	if (!memchr_inv(mask, 0, len))
  		return 0;
  	err = nla_put(skb, val_type, len, val);
  	if (err)
  		return err;
  	if (mask_type != TCA_FLOWER_UNSPEC) {
  		err = nla_put(skb, mask_type, len, mask);
  		if (err)
  			return err;
  	}
  	return 0;
  }
a577d8f79   Benjamin LaHaise   cls_flower: add s...
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
  static int fl_dump_key_mpls(struct sk_buff *skb,
  			    struct flow_dissector_key_mpls *mpls_key,
  			    struct flow_dissector_key_mpls *mpls_mask)
  {
  	int err;
  
  	if (!memchr_inv(mpls_mask, 0, sizeof(*mpls_mask)))
  		return 0;
  	if (mpls_mask->mpls_ttl) {
  		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TTL,
  				 mpls_key->mpls_ttl);
  		if (err)
  			return err;
  	}
  	if (mpls_mask->mpls_tc) {
  		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TC,
  				 mpls_key->mpls_tc);
  		if (err)
  			return err;
  	}
  	if (mpls_mask->mpls_label) {
  		err = nla_put_u32(skb, TCA_FLOWER_KEY_MPLS_LABEL,
  				  mpls_key->mpls_label);
  		if (err)
  			return err;
  	}
  	if (mpls_mask->mpls_bos) {
  		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_BOS,
  				 mpls_key->mpls_bos);
  		if (err)
  			return err;
  	}
  	return 0;
  }
0e2c17b64   Or Gerlitz   net/sched: cls_fl...
1454
  static int fl_dump_key_ip(struct sk_buff *skb, bool encap,
4d80cc0aa   Or Gerlitz   net/sched: cls_fl...
1455
1456
1457
  			  struct flow_dissector_key_ip *key,
  			  struct flow_dissector_key_ip *mask)
  {
0e2c17b64   Or Gerlitz   net/sched: cls_fl...
1458
1459
1460
1461
1462
1463
1464
  	int tos_key = encap ? TCA_FLOWER_KEY_ENC_IP_TOS : TCA_FLOWER_KEY_IP_TOS;
  	int ttl_key = encap ? TCA_FLOWER_KEY_ENC_IP_TTL : TCA_FLOWER_KEY_IP_TTL;
  	int tos_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TOS_MASK : TCA_FLOWER_KEY_IP_TOS_MASK;
  	int ttl_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TTL_MASK : TCA_FLOWER_KEY_IP_TTL_MASK;
  
  	if (fl_dump_key_val(skb, &key->tos, tos_key, &mask->tos, tos_mask, sizeof(key->tos)) ||
  	    fl_dump_key_val(skb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl)))
4d80cc0aa   Or Gerlitz   net/sched: cls_fl...
1465
1466
1467
1468
  		return -1;
  
  	return 0;
  }
9399ae9a6   Hadar Hen Zion   net_sched: flower...
1469
  static int fl_dump_key_vlan(struct sk_buff *skb,
d64efd092   Jianbo Liu   net/sched: flower...
1470
  			    int vlan_id_key, int vlan_prio_key,
9399ae9a6   Hadar Hen Zion   net_sched: flower...
1471
1472
1473
1474
1475
1476
1477
1478
  			    struct flow_dissector_key_vlan *vlan_key,
  			    struct flow_dissector_key_vlan *vlan_mask)
  {
  	int err;
  
  	if (!memchr_inv(vlan_mask, 0, sizeof(*vlan_mask)))
  		return 0;
  	if (vlan_mask->vlan_id) {
d64efd092   Jianbo Liu   net/sched: flower...
1479
  		err = nla_put_u16(skb, vlan_id_key,
9399ae9a6   Hadar Hen Zion   net_sched: flower...
1480
1481
1482
1483
1484
  				  vlan_key->vlan_id);
  		if (err)
  			return err;
  	}
  	if (vlan_mask->vlan_priority) {
d64efd092   Jianbo Liu   net/sched: flower...
1485
  		err = nla_put_u8(skb, vlan_prio_key,
9399ae9a6   Hadar Hen Zion   net_sched: flower...
1486
1487
1488
1489
1490
1491
  				 vlan_key->vlan_priority);
  		if (err)
  			return err;
  	}
  	return 0;
  }
faa3ffce7   Or Gerlitz   net/sched: cls_fl...
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
  static void fl_get_key_flag(u32 dissector_key, u32 dissector_mask,
  			    u32 *flower_key, u32 *flower_mask,
  			    u32 flower_flag_bit, u32 dissector_flag_bit)
  {
  	if (dissector_mask & dissector_flag_bit) {
  		*flower_mask |= flower_flag_bit;
  		if (dissector_key & dissector_flag_bit)
  			*flower_key |= flower_flag_bit;
  	}
  }
  
  static int fl_dump_key_flags(struct sk_buff *skb, u32 flags_key, u32 flags_mask)
  {
  	u32 key, mask;
  	__be32 _key, _mask;
  	int err;
  
  	if (!memchr_inv(&flags_mask, 0, sizeof(flags_mask)))
  		return 0;
  
  	key = 0;
  	mask = 0;
  
  	fl_get_key_flag(flags_key, flags_mask, &key, &mask,
  			TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT);
459d153d9   Pieter Jansen van Vuuren   net/sched: cls_fl...
1517
1518
1519
  	fl_get_key_flag(flags_key, flags_mask, &key, &mask,
  			TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST,
  			FLOW_DIS_FIRST_FRAG);
faa3ffce7   Or Gerlitz   net/sched: cls_fl...
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
  
  	_key = cpu_to_be32(key);
  	_mask = cpu_to_be32(mask);
  
  	err = nla_put(skb, TCA_FLOWER_KEY_FLAGS, 4, &_key);
  	if (err)
  		return err;
  
  	return nla_put(skb, TCA_FLOWER_KEY_FLAGS_MASK, 4, &_mask);
  }
0a6e77784   Pieter Jansen van Vuuren   net/sched: allow ...
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
  static int fl_dump_key_geneve_opt(struct sk_buff *skb,
  				  struct flow_dissector_key_enc_opts *enc_opts)
  {
  	struct geneve_opt *opt;
  	struct nlattr *nest;
  	int opt_off = 0;
  
  	nest = nla_nest_start(skb, TCA_FLOWER_KEY_ENC_OPTS_GENEVE);
  	if (!nest)
  		goto nla_put_failure;
  
  	while (enc_opts->len > opt_off) {
  		opt = (struct geneve_opt *)&enc_opts->data[opt_off];
  
  		if (nla_put_be16(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS,
  				 opt->opt_class))
  			goto nla_put_failure;
  		if (nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE,
  			       opt->type))
  			goto nla_put_failure;
  		if (nla_put(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA,
  			    opt->length * 4, opt->opt_data))
  			goto nla_put_failure;
  
  		opt_off += sizeof(struct geneve_opt) + opt->length * 4;
  	}
  	nla_nest_end(skb, nest);
  	return 0;
  
  nla_put_failure:
  	nla_nest_cancel(skb, nest);
  	return -EMSGSIZE;
  }
  
  static int fl_dump_key_options(struct sk_buff *skb, int enc_opt_type,
  			       struct flow_dissector_key_enc_opts *enc_opts)
  {
  	struct nlattr *nest;
  	int err;
  
  	if (!enc_opts->len)
  		return 0;
  
  	nest = nla_nest_start(skb, enc_opt_type);
  	if (!nest)
  		goto nla_put_failure;
  
  	switch (enc_opts->dst_opt_type) {
  	case TUNNEL_GENEVE_OPT:
  		err = fl_dump_key_geneve_opt(skb, enc_opts);
  		if (err)
  			goto nla_put_failure;
  		break;
  	default:
  		goto nla_put_failure;
  	}
  	nla_nest_end(skb, nest);
  	return 0;
  
  nla_put_failure:
  	nla_nest_cancel(skb, nest);
  	return -EMSGSIZE;
  }
  
  static int fl_dump_key_enc_opt(struct sk_buff *skb,
  			       struct flow_dissector_key_enc_opts *key_opts,
  			       struct flow_dissector_key_enc_opts *msk_opts)
  {
  	int err;
  
  	err = fl_dump_key_options(skb, TCA_FLOWER_KEY_ENC_OPTS, key_opts);
  	if (err)
  		return err;
  
  	return fl_dump_key_options(skb, TCA_FLOWER_KEY_ENC_OPTS_MASK, msk_opts);
  }
f5749081f   Jiri Pirko   net: sched: cls_f...
1606
1607
  static int fl_dump_key(struct sk_buff *skb, struct net *net,
  		       struct fl_flow_key *key, struct fl_flow_key *mask)
77b9900ef   Jiri Pirko   tc: introduce Flo...
1608
  {
77b9900ef   Jiri Pirko   tc: introduce Flo...
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
  	if (mask->indev_ifindex) {
  		struct net_device *dev;
  
  		dev = __dev_get_by_index(net, key->indev_ifindex);
  		if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name))
  			goto nla_put_failure;
  	}
  
  	if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
  			    mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
  			    sizeof(key->eth.dst)) ||
  	    fl_dump_key_val(skb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
  			    mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
  			    sizeof(key->eth.src)) ||
  	    fl_dump_key_val(skb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE,
  			    &mask->basic.n_proto, TCA_FLOWER_UNSPEC,
  			    sizeof(key->basic.n_proto)))
  		goto nla_put_failure;
9399ae9a6   Hadar Hen Zion   net_sched: flower...
1627

a577d8f79   Benjamin LaHaise   cls_flower: add s...
1628
1629
  	if (fl_dump_key_mpls(skb, &key->mpls, &mask->mpls))
  		goto nla_put_failure;
d64efd092   Jianbo Liu   net/sched: flower...
1630
1631
  	if (fl_dump_key_vlan(skb, TCA_FLOWER_KEY_VLAN_ID,
  			     TCA_FLOWER_KEY_VLAN_PRIO, &key->vlan, &mask->vlan))
9399ae9a6   Hadar Hen Zion   net_sched: flower...
1632
  		goto nla_put_failure;
d64efd092   Jianbo Liu   net/sched: flower...
1633
1634
1635
1636
  	if (fl_dump_key_vlan(skb, TCA_FLOWER_KEY_CVLAN_ID,
  			     TCA_FLOWER_KEY_CVLAN_PRIO,
  			     &key->cvlan, &mask->cvlan) ||
  	    (mask->cvlan.vlan_tpid &&
158abbf17   Jianbo Liu   net/sched: cls_fl...
1637
1638
  	     nla_put_be16(skb, TCA_FLOWER_KEY_VLAN_ETH_TYPE,
  			  key->cvlan.vlan_tpid)))
d30695126   Jianbo Liu   net/sched: flower...
1639
  		goto nla_put_failure;
5e9a0fe49   Jianbo Liu   net/sched: flower...
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
  	if (mask->basic.n_proto) {
  		if (mask->cvlan.vlan_tpid) {
  			if (nla_put_be16(skb, TCA_FLOWER_KEY_CVLAN_ETH_TYPE,
  					 key->basic.n_proto))
  				goto nla_put_failure;
  		} else if (mask->vlan.vlan_tpid) {
  			if (nla_put_be16(skb, TCA_FLOWER_KEY_VLAN_ETH_TYPE,
  					 key->basic.n_proto))
  				goto nla_put_failure;
  		}
d64efd092   Jianbo Liu   net/sched: flower...
1650
  	}
77b9900ef   Jiri Pirko   tc: introduce Flo...
1651
1652
  	if ((key->basic.n_proto == htons(ETH_P_IP) ||
  	     key->basic.n_proto == htons(ETH_P_IPV6)) &&
4d80cc0aa   Or Gerlitz   net/sched: cls_fl...
1653
  	    (fl_dump_key_val(skb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
77b9900ef   Jiri Pirko   tc: introduce Flo...
1654
  			    &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
4d80cc0aa   Or Gerlitz   net/sched: cls_fl...
1655
  			    sizeof(key->basic.ip_proto)) ||
0e2c17b64   Or Gerlitz   net/sched: cls_fl...
1656
  	    fl_dump_key_ip(skb, false, &key->ip, &mask->ip)))
77b9900ef   Jiri Pirko   tc: introduce Flo...
1657
  		goto nla_put_failure;
c3f832418   Tom Herbert   net: Add full IPv...
1658
  	if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
77b9900ef   Jiri Pirko   tc: introduce Flo...
1659
1660
1661
1662
1663
1664
1665
  	    (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
  			     &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
  			     sizeof(key->ipv4.src)) ||
  	     fl_dump_key_val(skb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
  			     &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
  			     sizeof(key->ipv4.dst))))
  		goto nla_put_failure;
c3f832418   Tom Herbert   net: Add full IPv...
1666
  	else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
77b9900ef   Jiri Pirko   tc: introduce Flo...
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
  		 (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
  				  &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
  				  sizeof(key->ipv6.src)) ||
  		  fl_dump_key_val(skb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
  				  &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
  				  sizeof(key->ipv6.dst))))
  		goto nla_put_failure;
  
  	if (key->basic.ip_proto == IPPROTO_TCP &&
  	    (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
aa72d7083   Or Gerlitz   net/sched: cls_fl...
1677
  			     &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
77b9900ef   Jiri Pirko   tc: introduce Flo...
1678
1679
  			     sizeof(key->tp.src)) ||
  	     fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
aa72d7083   Or Gerlitz   net/sched: cls_fl...
1680
  			     &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
fdfc7dd6c   Jiri Pirko   net/sched: flower...
1681
1682
1683
1684
  			     sizeof(key->tp.dst)) ||
  	     fl_dump_key_val(skb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS,
  			     &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK,
  			     sizeof(key->tcp.flags))))
77b9900ef   Jiri Pirko   tc: introduce Flo...
1685
1686
1687
  		goto nla_put_failure;
  	else if (key->basic.ip_proto == IPPROTO_UDP &&
  		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
aa72d7083   Or Gerlitz   net/sched: cls_fl...
1688
  				  &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
77b9900ef   Jiri Pirko   tc: introduce Flo...
1689
1690
  				  sizeof(key->tp.src)) ||
  		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
aa72d7083   Or Gerlitz   net/sched: cls_fl...
1691
  				  &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
5976c5f45   Simon Horman   net/sched: cls_fl...
1692
1693
1694
1695
1696
1697
1698
1699
  				  sizeof(key->tp.dst))))
  		goto nla_put_failure;
  	else if (key->basic.ip_proto == IPPROTO_SCTP &&
  		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
  				  &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
  				  sizeof(key->tp.src)) ||
  		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
  				  &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
77b9900ef   Jiri Pirko   tc: introduce Flo...
1700
1701
  				  sizeof(key->tp.dst))))
  		goto nla_put_failure;
7b684884f   Simon Horman   net/sched: cls_fl...
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
  	else if (key->basic.n_proto == htons(ETH_P_IP) &&
  		 key->basic.ip_proto == IPPROTO_ICMP &&
  		 (fl_dump_key_val(skb, &key->icmp.type,
  				  TCA_FLOWER_KEY_ICMPV4_TYPE, &mask->icmp.type,
  				  TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,
  				  sizeof(key->icmp.type)) ||
  		  fl_dump_key_val(skb, &key->icmp.code,
  				  TCA_FLOWER_KEY_ICMPV4_CODE, &mask->icmp.code,
  				  TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
  				  sizeof(key->icmp.code))))
  		goto nla_put_failure;
  	else if (key->basic.n_proto == htons(ETH_P_IPV6) &&
  		 key->basic.ip_proto == IPPROTO_ICMPV6 &&
  		 (fl_dump_key_val(skb, &key->icmp.type,
  				  TCA_FLOWER_KEY_ICMPV6_TYPE, &mask->icmp.type,
  				  TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
  				  sizeof(key->icmp.type)) ||
  		  fl_dump_key_val(skb, &key->icmp.code,
  				  TCA_FLOWER_KEY_ICMPV6_CODE, &mask->icmp.code,
  				  TCA_FLOWER_KEY_ICMPV6_CODE_MASK,
  				  sizeof(key->icmp.code))))
  		goto nla_put_failure;
99d31326c   Simon Horman   net/sched: cls_fl...
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
  	else if ((key->basic.n_proto == htons(ETH_P_ARP) ||
  		  key->basic.n_proto == htons(ETH_P_RARP)) &&
  		 (fl_dump_key_val(skb, &key->arp.sip,
  				  TCA_FLOWER_KEY_ARP_SIP, &mask->arp.sip,
  				  TCA_FLOWER_KEY_ARP_SIP_MASK,
  				  sizeof(key->arp.sip)) ||
  		  fl_dump_key_val(skb, &key->arp.tip,
  				  TCA_FLOWER_KEY_ARP_TIP, &mask->arp.tip,
  				  TCA_FLOWER_KEY_ARP_TIP_MASK,
  				  sizeof(key->arp.tip)) ||
  		  fl_dump_key_val(skb, &key->arp.op,
  				  TCA_FLOWER_KEY_ARP_OP, &mask->arp.op,
  				  TCA_FLOWER_KEY_ARP_OP_MASK,
  				  sizeof(key->arp.op)) ||
  		  fl_dump_key_val(skb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA,
  				  mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK,
  				  sizeof(key->arp.sha)) ||
  		  fl_dump_key_val(skb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA,
  				  mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK,
  				  sizeof(key->arp.tha))))
  		goto nla_put_failure;
77b9900ef   Jiri Pirko   tc: introduce Flo...
1745

bc3103f1e   Amir Vadai   net/sched: cls_fl...
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
  	if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
  	    (fl_dump_key_val(skb, &key->enc_ipv4.src,
  			    TCA_FLOWER_KEY_ENC_IPV4_SRC, &mask->enc_ipv4.src,
  			    TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
  			    sizeof(key->enc_ipv4.src)) ||
  	     fl_dump_key_val(skb, &key->enc_ipv4.dst,
  			     TCA_FLOWER_KEY_ENC_IPV4_DST, &mask->enc_ipv4.dst,
  			     TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
  			     sizeof(key->enc_ipv4.dst))))
  		goto nla_put_failure;
  	else if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
  		 (fl_dump_key_val(skb, &key->enc_ipv6.src,
  			    TCA_FLOWER_KEY_ENC_IPV6_SRC, &mask->enc_ipv6.src,
  			    TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
  			    sizeof(key->enc_ipv6.src)) ||
  		 fl_dump_key_val(skb, &key->enc_ipv6.dst,
  				 TCA_FLOWER_KEY_ENC_IPV6_DST,
  				 &mask->enc_ipv6.dst,
  				 TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
  			    sizeof(key->enc_ipv6.dst))))
  		goto nla_put_failure;
  
  	if (fl_dump_key_val(skb, &key->enc_key_id, TCA_FLOWER_KEY_ENC_KEY_ID,
eb523f42d   Hadar Hen Zion   net/sched: cls_fl...
1769
  			    &mask->enc_key_id, TCA_FLOWER_UNSPEC,
f4d997fd6   Hadar Hen Zion   net/sched: cls_fl...
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
  			    sizeof(key->enc_key_id)) ||
  	    fl_dump_key_val(skb, &key->enc_tp.src,
  			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
  			    &mask->enc_tp.src,
  			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
  			    sizeof(key->enc_tp.src)) ||
  	    fl_dump_key_val(skb, &key->enc_tp.dst,
  			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
  			    &mask->enc_tp.dst,
  			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
0e2c17b64   Or Gerlitz   net/sched: cls_fl...
1780
  			    sizeof(key->enc_tp.dst)) ||
0a6e77784   Pieter Jansen van Vuuren   net/sched: allow ...
1781
1782
  	    fl_dump_key_ip(skb, true, &key->enc_ip, &mask->enc_ip) ||
  	    fl_dump_key_enc_opt(skb, &key->enc_opts, &mask->enc_opts))
bc3103f1e   Amir Vadai   net/sched: cls_fl...
1783
  		goto nla_put_failure;
faa3ffce7   Or Gerlitz   net/sched: cls_fl...
1784
1785
  	if (fl_dump_key_flags(skb, key->control.flags, mask->control.flags))
  		goto nla_put_failure;
f5749081f   Jiri Pirko   net: sched: cls_f...
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
  	return 0;
  
  nla_put_failure:
  	return -EMSGSIZE;
  }
  
  static int fl_dump(struct net *net, struct tcf_proto *tp, void *fh,
  		   struct sk_buff *skb, struct tcmsg *t)
  {
  	struct cls_fl_filter *f = fh;
  	struct nlattr *nest;
  	struct fl_flow_key *key, *mask;
  
  	if (!f)
  		return skb->len;
  
  	t->tcm_handle = f->handle;
  
  	nest = nla_nest_start(skb, TCA_OPTIONS);
  	if (!nest)
  		goto nla_put_failure;
  
  	if (f->res.classid &&
  	    nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid))
  		goto nla_put_failure;
  
  	key = &f->key;
  	mask = &f->mask->key;
  
  	if (fl_dump_key(skb, net, key, mask))
  		goto nla_put_failure;
  
  	if (!tc_skip_hw(f->flags))
  		fl_hw_update_stats(tp, f);
749e6720d   Or Gerlitz   net/sched: cls_fl...
1820
1821
  	if (f->flags && nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags))
  		goto nla_put_failure;
e69985c67   Amir Vadai   net/sched: cls_fl...
1822

77b9900ef   Jiri Pirko   tc: introduce Flo...
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
  	if (tcf_exts_dump(skb, &f->exts))
  		goto nla_put_failure;
  
  	nla_nest_end(skb, nest);
  
  	if (tcf_exts_dump_stats(skb, &f->exts) < 0)
  		goto nla_put_failure;
  
  	return skb->len;
  
  nla_put_failure:
  	nla_nest_cancel(skb, nest);
  	return -1;
  }
b95ec7eb3   Jiri Pirko   net: sched: cls_f...
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
  static int fl_tmplt_dump(struct sk_buff *skb, struct net *net, void *tmplt_priv)
  {
  	struct fl_flow_tmplt *tmplt = tmplt_priv;
  	struct fl_flow_key *key, *mask;
  	struct nlattr *nest;
  
  	nest = nla_nest_start(skb, TCA_OPTIONS);
  	if (!nest)
  		goto nla_put_failure;
  
  	key = &tmplt->dummy_key;
  	mask = &tmplt->mask;
  
  	if (fl_dump_key(skb, net, key, mask))
  		goto nla_put_failure;
  
  	nla_nest_end(skb, nest);
  
  	return skb->len;
  
  nla_put_failure:
  	nla_nest_cancel(skb, nest);
  	return -EMSGSIZE;
  }
07d79fc7d   Cong Wang   net_sched: add re...
1861
1862
1863
1864
1865
1866
1867
  static void fl_bind_class(void *fh, u32 classid, unsigned long cl)
  {
  	struct cls_fl_filter *f = fh;
  
  	if (f && f->res.classid == classid)
  		f->res.class = cl;
  }
77b9900ef   Jiri Pirko   tc: introduce Flo...
1868
1869
1870
1871
1872
1873
1874
1875
1876
  static struct tcf_proto_ops cls_fl_ops __read_mostly = {
  	.kind		= "flower",
  	.classify	= fl_classify,
  	.init		= fl_init,
  	.destroy	= fl_destroy,
  	.get		= fl_get,
  	.change		= fl_change,
  	.delete		= fl_delete,
  	.walk		= fl_walk,
31533cba4   John Hurley   net: sched: cls_f...
1877
  	.reoffload	= fl_reoffload,
77b9900ef   Jiri Pirko   tc: introduce Flo...
1878
  	.dump		= fl_dump,
07d79fc7d   Cong Wang   net_sched: add re...
1879
  	.bind_class	= fl_bind_class,
b95ec7eb3   Jiri Pirko   net: sched: cls_f...
1880
1881
1882
  	.tmplt_create	= fl_tmplt_create,
  	.tmplt_destroy	= fl_tmplt_destroy,
  	.tmplt_dump	= fl_tmplt_dump,
77b9900ef   Jiri Pirko   tc: introduce Flo...
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
  	.owner		= THIS_MODULE,
  };
  
  static int __init cls_fl_init(void)
  {
  	return register_tcf_proto_ops(&cls_fl_ops);
  }
  
  static void __exit cls_fl_exit(void)
  {
  	unregister_tcf_proto_ops(&cls_fl_ops);
  }
  
  module_init(cls_fl_init);
  module_exit(cls_fl_exit);
  
  MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>");
  MODULE_DESCRIPTION("Flower classifier");
  MODULE_LICENSE("GPL v2");