xref: /linux/net/sched/cls_flower.c (revision 5c72299fba9df407c2f2994e194edebf878996ee)
177b9900eSJiri Pirko /*
277b9900eSJiri Pirko  * net/sched/cls_flower.c		Flower classifier
377b9900eSJiri Pirko  *
477b9900eSJiri Pirko  * Copyright (c) 2015 Jiri Pirko <jiri@resnulli.us>
577b9900eSJiri Pirko  *
677b9900eSJiri Pirko  * This program is free software; you can redistribute it and/or modify
777b9900eSJiri Pirko  * it under the terms of the GNU General Public License as published by
877b9900eSJiri Pirko  * the Free Software Foundation; either version 2 of the License, or
977b9900eSJiri Pirko  * (at your option) any later version.
1077b9900eSJiri Pirko  */
1177b9900eSJiri Pirko 
1277b9900eSJiri Pirko #include <linux/kernel.h>
1377b9900eSJiri Pirko #include <linux/init.h>
1477b9900eSJiri Pirko #include <linux/module.h>
1577b9900eSJiri Pirko #include <linux/rhashtable.h>
16d9363774SDaniel Borkmann #include <linux/workqueue.h>
1777b9900eSJiri Pirko 
1877b9900eSJiri Pirko #include <linux/if_ether.h>
1977b9900eSJiri Pirko #include <linux/in6.h>
2077b9900eSJiri Pirko #include <linux/ip.h>
21a577d8f7SBenjamin LaHaise #include <linux/mpls.h>
2277b9900eSJiri Pirko 
2377b9900eSJiri Pirko #include <net/sch_generic.h>
2477b9900eSJiri Pirko #include <net/pkt_cls.h>
2577b9900eSJiri Pirko #include <net/ip.h>
2677b9900eSJiri Pirko #include <net/flow_dissector.h>
270a6e7778SPieter Jansen van Vuuren #include <net/geneve.h>
2877b9900eSJiri Pirko 
29bc3103f1SAmir Vadai #include <net/dst.h>
30bc3103f1SAmir Vadai #include <net/dst_metadata.h>
31bc3103f1SAmir Vadai 
3277b9900eSJiri Pirko struct fl_flow_key {
3377b9900eSJiri Pirko 	int	indev_ifindex;
3442aecaa9STom Herbert 	struct flow_dissector_key_control control;
35bc3103f1SAmir Vadai 	struct flow_dissector_key_control enc_control;
3677b9900eSJiri Pirko 	struct flow_dissector_key_basic basic;
3777b9900eSJiri Pirko 	struct flow_dissector_key_eth_addrs eth;
389399ae9aSHadar Hen Zion 	struct flow_dissector_key_vlan vlan;
39d64efd09SJianbo Liu 	struct flow_dissector_key_vlan cvlan;
4077b9900eSJiri Pirko 	union {
41c3f83241STom Herbert 		struct flow_dissector_key_ipv4_addrs ipv4;
4277b9900eSJiri Pirko 		struct flow_dissector_key_ipv6_addrs ipv6;
4377b9900eSJiri Pirko 	};
4477b9900eSJiri Pirko 	struct flow_dissector_key_ports tp;
457b684884SSimon Horman 	struct flow_dissector_key_icmp icmp;
4699d31326SSimon Horman 	struct flow_dissector_key_arp arp;
47bc3103f1SAmir Vadai 	struct flow_dissector_key_keyid enc_key_id;
48bc3103f1SAmir Vadai 	union {
49bc3103f1SAmir Vadai 		struct flow_dissector_key_ipv4_addrs enc_ipv4;
50bc3103f1SAmir Vadai 		struct flow_dissector_key_ipv6_addrs enc_ipv6;
51bc3103f1SAmir Vadai 	};
52f4d997fdSHadar Hen Zion 	struct flow_dissector_key_ports enc_tp;
53a577d8f7SBenjamin LaHaise 	struct flow_dissector_key_mpls mpls;
54fdfc7dd6SJiri Pirko 	struct flow_dissector_key_tcp tcp;
554d80cc0aSOr Gerlitz 	struct flow_dissector_key_ip ip;
560e2c17b6SOr Gerlitz 	struct flow_dissector_key_ip enc_ip;
570a6e7778SPieter Jansen van Vuuren 	struct flow_dissector_key_enc_opts enc_opts;
58*5c72299fSAmritha Nambiar 	struct flow_dissector_key_ports tp_min;
59*5c72299fSAmritha Nambiar 	struct flow_dissector_key_ports tp_max;
6077b9900eSJiri Pirko } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
6177b9900eSJiri Pirko 
6277b9900eSJiri Pirko struct fl_flow_mask_range {
6377b9900eSJiri Pirko 	unsigned short int start;
6477b9900eSJiri Pirko 	unsigned short int end;
6577b9900eSJiri Pirko };
6677b9900eSJiri Pirko 
6777b9900eSJiri Pirko struct fl_flow_mask {
6877b9900eSJiri Pirko 	struct fl_flow_key key;
6977b9900eSJiri Pirko 	struct fl_flow_mask_range range;
70*5c72299fSAmritha Nambiar 	u32 flags;
7105cd271fSPaul Blakey 	struct rhash_head ht_node;
7205cd271fSPaul Blakey 	struct rhashtable ht;
7305cd271fSPaul Blakey 	struct rhashtable_params filter_ht_params;
7405cd271fSPaul Blakey 	struct flow_dissector dissector;
7505cd271fSPaul Blakey 	struct list_head filters;
7644a5cd43SPaolo Abeni 	struct rcu_work rwork;
7705cd271fSPaul Blakey 	struct list_head list;
7877b9900eSJiri Pirko };
7977b9900eSJiri Pirko 
80b95ec7ebSJiri Pirko struct fl_flow_tmplt {
81b95ec7ebSJiri Pirko 	struct fl_flow_key dummy_key;
82b95ec7ebSJiri Pirko 	struct fl_flow_key mask;
83b95ec7ebSJiri Pirko 	struct flow_dissector dissector;
84b95ec7ebSJiri Pirko 	struct tcf_chain *chain;
85b95ec7ebSJiri Pirko };
86b95ec7ebSJiri Pirko 
8777b9900eSJiri Pirko struct cls_fl_head {
8877b9900eSJiri Pirko 	struct rhashtable ht;
8905cd271fSPaul Blakey 	struct list_head masks;
90aaa908ffSCong Wang 	struct rcu_work rwork;
91c15ab236SChris Mi 	struct idr handle_idr;
92d9363774SDaniel Borkmann };
9377b9900eSJiri Pirko 
9477b9900eSJiri Pirko struct cls_fl_filter {
9505cd271fSPaul Blakey 	struct fl_flow_mask *mask;
9677b9900eSJiri Pirko 	struct rhash_head ht_node;
9777b9900eSJiri Pirko 	struct fl_flow_key mkey;
9877b9900eSJiri Pirko 	struct tcf_exts exts;
9977b9900eSJiri Pirko 	struct tcf_result res;
10077b9900eSJiri Pirko 	struct fl_flow_key key;
10177b9900eSJiri Pirko 	struct list_head list;
10277b9900eSJiri Pirko 	u32 handle;
103e69985c6SAmir Vadai 	u32 flags;
10486c55361SVlad Buslov 	u32 in_hw_count;
105aaa908ffSCong Wang 	struct rcu_work rwork;
1067091d8c7SHadar Hen Zion 	struct net_device *hw_dev;
10777b9900eSJiri Pirko };
10877b9900eSJiri Pirko 
10905cd271fSPaul Blakey static const struct rhashtable_params mask_ht_params = {
11005cd271fSPaul Blakey 	.key_offset = offsetof(struct fl_flow_mask, key),
11105cd271fSPaul Blakey 	.key_len = sizeof(struct fl_flow_key),
11205cd271fSPaul Blakey 	.head_offset = offsetof(struct fl_flow_mask, ht_node),
11305cd271fSPaul Blakey 	.automatic_shrinking = true,
11405cd271fSPaul Blakey };
11505cd271fSPaul Blakey 
11677b9900eSJiri Pirko static unsigned short int fl_mask_range(const struct fl_flow_mask *mask)
11777b9900eSJiri Pirko {
11877b9900eSJiri Pirko 	return mask->range.end - mask->range.start;
11977b9900eSJiri Pirko }
12077b9900eSJiri Pirko 
12177b9900eSJiri Pirko static void fl_mask_update_range(struct fl_flow_mask *mask)
12277b9900eSJiri Pirko {
12377b9900eSJiri Pirko 	const u8 *bytes = (const u8 *) &mask->key;
12477b9900eSJiri Pirko 	size_t size = sizeof(mask->key);
12505cd271fSPaul Blakey 	size_t i, first = 0, last;
12677b9900eSJiri Pirko 
12705cd271fSPaul Blakey 	for (i = 0; i < size; i++) {
12877b9900eSJiri Pirko 		if (bytes[i]) {
12977b9900eSJiri Pirko 			first = i;
13005cd271fSPaul Blakey 			break;
13105cd271fSPaul Blakey 		}
13205cd271fSPaul Blakey 	}
13305cd271fSPaul Blakey 	last = first;
13405cd271fSPaul Blakey 	for (i = size - 1; i != first; i--) {
13505cd271fSPaul Blakey 		if (bytes[i]) {
13677b9900eSJiri Pirko 			last = i;
13705cd271fSPaul Blakey 			break;
13877b9900eSJiri Pirko 		}
13977b9900eSJiri Pirko 	}
14077b9900eSJiri Pirko 	mask->range.start = rounddown(first, sizeof(long));
14177b9900eSJiri Pirko 	mask->range.end = roundup(last + 1, sizeof(long));
14277b9900eSJiri Pirko }
14377b9900eSJiri Pirko 
14477b9900eSJiri Pirko static void *fl_key_get_start(struct fl_flow_key *key,
14577b9900eSJiri Pirko 			      const struct fl_flow_mask *mask)
14677b9900eSJiri Pirko {
14777b9900eSJiri Pirko 	return (u8 *) key + mask->range.start;
14877b9900eSJiri Pirko }
14977b9900eSJiri Pirko 
15077b9900eSJiri Pirko static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key,
15177b9900eSJiri Pirko 			      struct fl_flow_mask *mask)
15277b9900eSJiri Pirko {
15377b9900eSJiri Pirko 	const long *lkey = fl_key_get_start(key, mask);
15477b9900eSJiri Pirko 	const long *lmask = fl_key_get_start(&mask->key, mask);
15577b9900eSJiri Pirko 	long *lmkey = fl_key_get_start(mkey, mask);
15677b9900eSJiri Pirko 	int i;
15777b9900eSJiri Pirko 
15877b9900eSJiri Pirko 	for (i = 0; i < fl_mask_range(mask); i += sizeof(long))
15977b9900eSJiri Pirko 		*lmkey++ = *lkey++ & *lmask++;
16077b9900eSJiri Pirko }
16177b9900eSJiri Pirko 
162b95ec7ebSJiri Pirko static bool fl_mask_fits_tmplt(struct fl_flow_tmplt *tmplt,
163b95ec7ebSJiri Pirko 			       struct fl_flow_mask *mask)
164b95ec7ebSJiri Pirko {
165b95ec7ebSJiri Pirko 	const long *lmask = fl_key_get_start(&mask->key, mask);
166b95ec7ebSJiri Pirko 	const long *ltmplt;
167b95ec7ebSJiri Pirko 	int i;
168b95ec7ebSJiri Pirko 
169b95ec7ebSJiri Pirko 	if (!tmplt)
170b95ec7ebSJiri Pirko 		return true;
171b95ec7ebSJiri Pirko 	ltmplt = fl_key_get_start(&tmplt->mask, mask);
172b95ec7ebSJiri Pirko 	for (i = 0; i < fl_mask_range(mask); i += sizeof(long)) {
173b95ec7ebSJiri Pirko 		if (~*ltmplt++ & *lmask++)
174b95ec7ebSJiri Pirko 			return false;
175b95ec7ebSJiri Pirko 	}
176b95ec7ebSJiri Pirko 	return true;
177b95ec7ebSJiri Pirko }
178b95ec7ebSJiri Pirko 
17977b9900eSJiri Pirko static void fl_clear_masked_range(struct fl_flow_key *key,
18077b9900eSJiri Pirko 				  struct fl_flow_mask *mask)
18177b9900eSJiri Pirko {
18277b9900eSJiri Pirko 	memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask));
18377b9900eSJiri Pirko }
18477b9900eSJiri Pirko 
185*5c72299fSAmritha Nambiar static bool fl_range_port_dst_cmp(struct cls_fl_filter *filter,
186*5c72299fSAmritha Nambiar 				  struct fl_flow_key *key,
187*5c72299fSAmritha Nambiar 				  struct fl_flow_key *mkey)
188*5c72299fSAmritha Nambiar {
189*5c72299fSAmritha Nambiar 	__be16 min_mask, max_mask, min_val, max_val;
190*5c72299fSAmritha Nambiar 
191*5c72299fSAmritha Nambiar 	min_mask = htons(filter->mask->key.tp_min.dst);
192*5c72299fSAmritha Nambiar 	max_mask = htons(filter->mask->key.tp_max.dst);
193*5c72299fSAmritha Nambiar 	min_val = htons(filter->key.tp_min.dst);
194*5c72299fSAmritha Nambiar 	max_val = htons(filter->key.tp_max.dst);
195*5c72299fSAmritha Nambiar 
196*5c72299fSAmritha Nambiar 	if (min_mask && max_mask) {
197*5c72299fSAmritha Nambiar 		if (htons(key->tp.dst) < min_val ||
198*5c72299fSAmritha Nambiar 		    htons(key->tp.dst) > max_val)
199*5c72299fSAmritha Nambiar 			return false;
200*5c72299fSAmritha Nambiar 
201*5c72299fSAmritha Nambiar 		/* skb does not have min and max values */
202*5c72299fSAmritha Nambiar 		mkey->tp_min.dst = filter->mkey.tp_min.dst;
203*5c72299fSAmritha Nambiar 		mkey->tp_max.dst = filter->mkey.tp_max.dst;
204*5c72299fSAmritha Nambiar 	}
205*5c72299fSAmritha Nambiar 	return true;
206*5c72299fSAmritha Nambiar }
207*5c72299fSAmritha Nambiar 
208*5c72299fSAmritha Nambiar static bool fl_range_port_src_cmp(struct cls_fl_filter *filter,
209*5c72299fSAmritha Nambiar 				  struct fl_flow_key *key,
210*5c72299fSAmritha Nambiar 				  struct fl_flow_key *mkey)
211*5c72299fSAmritha Nambiar {
212*5c72299fSAmritha Nambiar 	__be16 min_mask, max_mask, min_val, max_val;
213*5c72299fSAmritha Nambiar 
214*5c72299fSAmritha Nambiar 	min_mask = htons(filter->mask->key.tp_min.src);
215*5c72299fSAmritha Nambiar 	max_mask = htons(filter->mask->key.tp_max.src);
216*5c72299fSAmritha Nambiar 	min_val = htons(filter->key.tp_min.src);
217*5c72299fSAmritha Nambiar 	max_val = htons(filter->key.tp_max.src);
218*5c72299fSAmritha Nambiar 
219*5c72299fSAmritha Nambiar 	if (min_mask && max_mask) {
220*5c72299fSAmritha Nambiar 		if (htons(key->tp.src) < min_val ||
221*5c72299fSAmritha Nambiar 		    htons(key->tp.src) > max_val)
222*5c72299fSAmritha Nambiar 			return false;
223*5c72299fSAmritha Nambiar 
224*5c72299fSAmritha Nambiar 		/* skb does not have min and max values */
225*5c72299fSAmritha Nambiar 		mkey->tp_min.src = filter->mkey.tp_min.src;
226*5c72299fSAmritha Nambiar 		mkey->tp_max.src = filter->mkey.tp_max.src;
227*5c72299fSAmritha Nambiar 	}
228*5c72299fSAmritha Nambiar 	return true;
229*5c72299fSAmritha Nambiar }
230*5c72299fSAmritha Nambiar 
231*5c72299fSAmritha Nambiar static struct cls_fl_filter *__fl_lookup(struct fl_flow_mask *mask,
232a3308d8fSPaul Blakey 					 struct fl_flow_key *mkey)
233a3308d8fSPaul Blakey {
23405cd271fSPaul Blakey 	return rhashtable_lookup_fast(&mask->ht, fl_key_get_start(mkey, mask),
23505cd271fSPaul Blakey 				      mask->filter_ht_params);
236a3308d8fSPaul Blakey }
237a3308d8fSPaul Blakey 
238*5c72299fSAmritha Nambiar static struct cls_fl_filter *fl_lookup_range(struct fl_flow_mask *mask,
239*5c72299fSAmritha Nambiar 					     struct fl_flow_key *mkey,
240*5c72299fSAmritha Nambiar 					     struct fl_flow_key *key)
241*5c72299fSAmritha Nambiar {
242*5c72299fSAmritha Nambiar 	struct cls_fl_filter *filter, *f;
243*5c72299fSAmritha Nambiar 
244*5c72299fSAmritha Nambiar 	list_for_each_entry_rcu(filter, &mask->filters, list) {
245*5c72299fSAmritha Nambiar 		if (!fl_range_port_dst_cmp(filter, key, mkey))
246*5c72299fSAmritha Nambiar 			continue;
247*5c72299fSAmritha Nambiar 
248*5c72299fSAmritha Nambiar 		if (!fl_range_port_src_cmp(filter, key, mkey))
249*5c72299fSAmritha Nambiar 			continue;
250*5c72299fSAmritha Nambiar 
251*5c72299fSAmritha Nambiar 		f = __fl_lookup(mask, mkey);
252*5c72299fSAmritha Nambiar 		if (f)
253*5c72299fSAmritha Nambiar 			return f;
254*5c72299fSAmritha Nambiar 	}
255*5c72299fSAmritha Nambiar 	return NULL;
256*5c72299fSAmritha Nambiar }
257*5c72299fSAmritha Nambiar 
258*5c72299fSAmritha Nambiar static struct cls_fl_filter *fl_lookup(struct fl_flow_mask *mask,
259*5c72299fSAmritha Nambiar 				       struct fl_flow_key *mkey,
260*5c72299fSAmritha Nambiar 				       struct fl_flow_key *key)
261*5c72299fSAmritha Nambiar {
262*5c72299fSAmritha Nambiar 	if ((mask->flags & TCA_FLOWER_MASK_FLAGS_RANGE))
263*5c72299fSAmritha Nambiar 		return fl_lookup_range(mask, mkey, key);
264*5c72299fSAmritha Nambiar 
265*5c72299fSAmritha Nambiar 	return __fl_lookup(mask, mkey);
266*5c72299fSAmritha Nambiar }
267*5c72299fSAmritha Nambiar 
26877b9900eSJiri Pirko static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp,
26977b9900eSJiri Pirko 		       struct tcf_result *res)
27077b9900eSJiri Pirko {
27177b9900eSJiri Pirko 	struct cls_fl_head *head = rcu_dereference_bh(tp->root);
27277b9900eSJiri Pirko 	struct cls_fl_filter *f;
27305cd271fSPaul Blakey 	struct fl_flow_mask *mask;
27477b9900eSJiri Pirko 	struct fl_flow_key skb_key;
27577b9900eSJiri Pirko 	struct fl_flow_key skb_mkey;
27677b9900eSJiri Pirko 
27705cd271fSPaul Blakey 	list_for_each_entry_rcu(mask, &head->masks, list) {
27805cd271fSPaul Blakey 		fl_clear_masked_range(&skb_key, mask);
279bc3103f1SAmir Vadai 
28077b9900eSJiri Pirko 		skb_key.indev_ifindex = skb->skb_iif;
28105cd271fSPaul Blakey 		/* skb_flow_dissect() does not set n_proto in case an unknown
28205cd271fSPaul Blakey 		 * protocol, so do it rather here.
28377b9900eSJiri Pirko 		 */
28477b9900eSJiri Pirko 		skb_key.basic.n_proto = skb->protocol;
28505cd271fSPaul Blakey 		skb_flow_dissect_tunnel_info(skb, &mask->dissector, &skb_key);
28605cd271fSPaul Blakey 		skb_flow_dissect(skb, &mask->dissector, &skb_key, 0);
28777b9900eSJiri Pirko 
28805cd271fSPaul Blakey 		fl_set_masked_key(&skb_mkey, &skb_key, mask);
28977b9900eSJiri Pirko 
290*5c72299fSAmritha Nambiar 		f = fl_lookup(mask, &skb_mkey, &skb_key);
291e8eb36cdSAmir Vadai 		if (f && !tc_skip_sw(f->flags)) {
29277b9900eSJiri Pirko 			*res = f->res;
29377b9900eSJiri Pirko 			return tcf_exts_exec(skb, &f->exts, res);
29477b9900eSJiri Pirko 		}
29505cd271fSPaul Blakey 	}
29677b9900eSJiri Pirko 	return -1;
29777b9900eSJiri Pirko }
29877b9900eSJiri Pirko 
29977b9900eSJiri Pirko static int fl_init(struct tcf_proto *tp)
30077b9900eSJiri Pirko {
30177b9900eSJiri Pirko 	struct cls_fl_head *head;
30277b9900eSJiri Pirko 
30377b9900eSJiri Pirko 	head = kzalloc(sizeof(*head), GFP_KERNEL);
30477b9900eSJiri Pirko 	if (!head)
30577b9900eSJiri Pirko 		return -ENOBUFS;
30677b9900eSJiri Pirko 
30705cd271fSPaul Blakey 	INIT_LIST_HEAD_RCU(&head->masks);
30877b9900eSJiri Pirko 	rcu_assign_pointer(tp->root, head);
309c15ab236SChris Mi 	idr_init(&head->handle_idr);
31077b9900eSJiri Pirko 
31105cd271fSPaul Blakey 	return rhashtable_init(&head->ht, &mask_ht_params);
31205cd271fSPaul Blakey }
31305cd271fSPaul Blakey 
31444a5cd43SPaolo Abeni static void fl_mask_free(struct fl_flow_mask *mask)
31544a5cd43SPaolo Abeni {
31644a5cd43SPaolo Abeni 	rhashtable_destroy(&mask->ht);
31744a5cd43SPaolo Abeni 	kfree(mask);
31844a5cd43SPaolo Abeni }
31944a5cd43SPaolo Abeni 
32044a5cd43SPaolo Abeni static void fl_mask_free_work(struct work_struct *work)
32144a5cd43SPaolo Abeni {
32244a5cd43SPaolo Abeni 	struct fl_flow_mask *mask = container_of(to_rcu_work(work),
32344a5cd43SPaolo Abeni 						 struct fl_flow_mask, rwork);
32444a5cd43SPaolo Abeni 
32544a5cd43SPaolo Abeni 	fl_mask_free(mask);
32644a5cd43SPaolo Abeni }
32744a5cd43SPaolo Abeni 
32805cd271fSPaul Blakey static bool fl_mask_put(struct cls_fl_head *head, struct fl_flow_mask *mask,
32905cd271fSPaul Blakey 			bool async)
33005cd271fSPaul Blakey {
33105cd271fSPaul Blakey 	if (!list_empty(&mask->filters))
33205cd271fSPaul Blakey 		return false;
33305cd271fSPaul Blakey 
33405cd271fSPaul Blakey 	rhashtable_remove_fast(&head->ht, &mask->ht_node, mask_ht_params);
33505cd271fSPaul Blakey 	list_del_rcu(&mask->list);
33605cd271fSPaul Blakey 	if (async)
33744a5cd43SPaolo Abeni 		tcf_queue_work(&mask->rwork, fl_mask_free_work);
33805cd271fSPaul Blakey 	else
33944a5cd43SPaolo Abeni 		fl_mask_free(mask);
34005cd271fSPaul Blakey 
34105cd271fSPaul Blakey 	return true;
34277b9900eSJiri Pirko }
34377b9900eSJiri Pirko 
3440dadc117SCong Wang static void __fl_destroy_filter(struct cls_fl_filter *f)
3450dadc117SCong Wang {
3460dadc117SCong Wang 	tcf_exts_destroy(&f->exts);
3470dadc117SCong Wang 	tcf_exts_put_net(&f->exts);
3480dadc117SCong Wang 	kfree(f);
3490dadc117SCong Wang }
3500dadc117SCong Wang 
3510552c8afSCong Wang static void fl_destroy_filter_work(struct work_struct *work)
3520552c8afSCong Wang {
353aaa908ffSCong Wang 	struct cls_fl_filter *f = container_of(to_rcu_work(work),
354aaa908ffSCong Wang 					struct cls_fl_filter, rwork);
3550552c8afSCong Wang 
3560552c8afSCong Wang 	rtnl_lock();
3570dadc117SCong Wang 	__fl_destroy_filter(f);
3580552c8afSCong Wang 	rtnl_unlock();
3590552c8afSCong Wang }
3600552c8afSCong Wang 
3611b0f8037SJakub Kicinski static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f,
3621b0f8037SJakub Kicinski 				 struct netlink_ext_ack *extack)
3635b33f488SAmir Vadai {
364de4784caSJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
365208c0f4bSJiri Pirko 	struct tcf_block *block = tp->chain->block;
3665b33f488SAmir Vadai 
3671b0f8037SJakub Kicinski 	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack);
368de4784caSJiri Pirko 	cls_flower.command = TC_CLSFLOWER_DESTROY;
369de4784caSJiri Pirko 	cls_flower.cookie = (unsigned long) f;
3705b33f488SAmir Vadai 
371208c0f4bSJiri Pirko 	tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER,
372717503b9SJiri Pirko 			 &cls_flower, false);
373caa72601SJiri Pirko 	tcf_block_offload_dec(block, &f->flags);
3745b33f488SAmir Vadai }
3755b33f488SAmir Vadai 
376e8eb36cdSAmir Vadai static int fl_hw_replace_filter(struct tcf_proto *tp,
37741002038SQuentin Monnet 				struct cls_fl_filter *f,
37841002038SQuentin Monnet 				struct netlink_ext_ack *extack)
3795b33f488SAmir Vadai {
380de4784caSJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
381208c0f4bSJiri Pirko 	struct tcf_block *block = tp->chain->block;
382717503b9SJiri Pirko 	bool skip_sw = tc_skip_sw(f->flags);
383e8eb36cdSAmir Vadai 	int err;
3845b33f488SAmir Vadai 
385ea205940SJakub Kicinski 	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack);
386de4784caSJiri Pirko 	cls_flower.command = TC_CLSFLOWER_REPLACE;
387de4784caSJiri Pirko 	cls_flower.cookie = (unsigned long) f;
38805cd271fSPaul Blakey 	cls_flower.dissector = &f->mask->dissector;
38905cd271fSPaul Blakey 	cls_flower.mask = &f->mask->key;
390de4784caSJiri Pirko 	cls_flower.key = &f->mkey;
391de4784caSJiri Pirko 	cls_flower.exts = &f->exts;
392384c181eSAmritha Nambiar 	cls_flower.classid = f->res.classid;
3935b33f488SAmir Vadai 
394208c0f4bSJiri Pirko 	err = tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER,
395717503b9SJiri Pirko 			       &cls_flower, skip_sw);
396717503b9SJiri Pirko 	if (err < 0) {
3971b0f8037SJakub Kicinski 		fl_hw_destroy_filter(tp, f, NULL);
398717503b9SJiri Pirko 		return err;
399717503b9SJiri Pirko 	} else if (err > 0) {
40031533cbaSJohn Hurley 		f->in_hw_count = err;
401caa72601SJiri Pirko 		tcf_block_offload_inc(block, &f->flags);
402717503b9SJiri Pirko 	}
403717503b9SJiri Pirko 
404717503b9SJiri Pirko 	if (skip_sw && !(f->flags & TCA_CLS_FLAGS_IN_HW))
405717503b9SJiri Pirko 		return -EINVAL;
406717503b9SJiri Pirko 
407e8eb36cdSAmir Vadai 	return 0;
4085b33f488SAmir Vadai }
4095b33f488SAmir Vadai 
41010cbc684SAmir Vadai static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
41110cbc684SAmir Vadai {
412de4784caSJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
413208c0f4bSJiri Pirko 	struct tcf_block *block = tp->chain->block;
41410cbc684SAmir Vadai 
415ea205940SJakub Kicinski 	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, NULL);
416de4784caSJiri Pirko 	cls_flower.command = TC_CLSFLOWER_STATS;
417de4784caSJiri Pirko 	cls_flower.cookie = (unsigned long) f;
418de4784caSJiri Pirko 	cls_flower.exts = &f->exts;
419384c181eSAmritha Nambiar 	cls_flower.classid = f->res.classid;
42010cbc684SAmir Vadai 
421208c0f4bSJiri Pirko 	tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER,
422717503b9SJiri Pirko 			 &cls_flower, false);
42310cbc684SAmir Vadai }
42410cbc684SAmir Vadai 
42505cd271fSPaul Blakey static bool __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,
4261b0f8037SJakub Kicinski 			struct netlink_ext_ack *extack)
42713fa876eSRoi Dayan {
428c15ab236SChris Mi 	struct cls_fl_head *head = rtnl_dereference(tp->root);
42905cd271fSPaul Blakey 	bool async = tcf_exts_get_net(&f->exts);
43005cd271fSPaul Blakey 	bool last;
431c15ab236SChris Mi 
4329c160941SMatthew Wilcox 	idr_remove(&head->handle_idr, f->handle);
43313fa876eSRoi Dayan 	list_del_rcu(&f->list);
43405cd271fSPaul Blakey 	last = fl_mask_put(head, f->mask, async);
43579685219SHadar Hen Zion 	if (!tc_skip_hw(f->flags))
4361b0f8037SJakub Kicinski 		fl_hw_destroy_filter(tp, f, extack);
43713fa876eSRoi Dayan 	tcf_unbind_filter(tp, &f->res);
43805cd271fSPaul Blakey 	if (async)
439aaa908ffSCong Wang 		tcf_queue_work(&f->rwork, fl_destroy_filter_work);
4400dadc117SCong Wang 	else
4410dadc117SCong Wang 		__fl_destroy_filter(f);
44205cd271fSPaul Blakey 
44305cd271fSPaul Blakey 	return last;
44413fa876eSRoi Dayan }
44513fa876eSRoi Dayan 
446d9363774SDaniel Borkmann static void fl_destroy_sleepable(struct work_struct *work)
447d9363774SDaniel Borkmann {
448aaa908ffSCong Wang 	struct cls_fl_head *head = container_of(to_rcu_work(work),
449aaa908ffSCong Wang 						struct cls_fl_head,
450aaa908ffSCong Wang 						rwork);
451de9dc650SPaul Blakey 
452de9dc650SPaul Blakey 	rhashtable_destroy(&head->ht);
453d9363774SDaniel Borkmann 	kfree(head);
454d9363774SDaniel Borkmann 	module_put(THIS_MODULE);
455d9363774SDaniel Borkmann }
456d9363774SDaniel Borkmann 
457715df5ecSJakub Kicinski static void fl_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
45877b9900eSJiri Pirko {
45977b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
46005cd271fSPaul Blakey 	struct fl_flow_mask *mask, *next_mask;
46177b9900eSJiri Pirko 	struct cls_fl_filter *f, *next;
46277b9900eSJiri Pirko 
46305cd271fSPaul Blakey 	list_for_each_entry_safe(mask, next_mask, &head->masks, list) {
46405cd271fSPaul Blakey 		list_for_each_entry_safe(f, next, &mask->filters, list) {
46505cd271fSPaul Blakey 			if (__fl_delete(tp, f, extack))
46605cd271fSPaul Blakey 				break;
46705cd271fSPaul Blakey 		}
46805cd271fSPaul Blakey 	}
469c15ab236SChris Mi 	idr_destroy(&head->handle_idr);
470d9363774SDaniel Borkmann 
471d9363774SDaniel Borkmann 	__module_get(THIS_MODULE);
472aaa908ffSCong Wang 	tcf_queue_work(&head->rwork, fl_destroy_sleepable);
47377b9900eSJiri Pirko }
47477b9900eSJiri Pirko 
4758113c095SWANG Cong static void *fl_get(struct tcf_proto *tp, u32 handle)
47677b9900eSJiri Pirko {
47777b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
47877b9900eSJiri Pirko 
479322d884bSMatthew Wilcox 	return idr_find(&head->handle_idr, handle);
48077b9900eSJiri Pirko }
48177b9900eSJiri Pirko 
48277b9900eSJiri Pirko static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
48377b9900eSJiri Pirko 	[TCA_FLOWER_UNSPEC]		= { .type = NLA_UNSPEC },
48477b9900eSJiri Pirko 	[TCA_FLOWER_CLASSID]		= { .type = NLA_U32 },
48577b9900eSJiri Pirko 	[TCA_FLOWER_INDEV]		= { .type = NLA_STRING,
48677b9900eSJiri Pirko 					    .len = IFNAMSIZ },
48777b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_DST]	= { .len = ETH_ALEN },
48877b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_DST_MASK]	= { .len = ETH_ALEN },
48977b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_SRC]	= { .len = ETH_ALEN },
49077b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_SRC_MASK]	= { .len = ETH_ALEN },
49177b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_TYPE]	= { .type = NLA_U16 },
49277b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IP_PROTO]	= { .type = NLA_U8 },
49377b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_SRC]	= { .type = NLA_U32 },
49477b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_SRC_MASK]	= { .type = NLA_U32 },
49577b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_DST]	= { .type = NLA_U32 },
49677b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_DST_MASK]	= { .type = NLA_U32 },
49777b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
49877b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_SRC_MASK]	= { .len = sizeof(struct in6_addr) },
49977b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
50077b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_DST_MASK]	= { .len = sizeof(struct in6_addr) },
50177b9900eSJiri Pirko 	[TCA_FLOWER_KEY_TCP_SRC]	= { .type = NLA_U16 },
50277b9900eSJiri Pirko 	[TCA_FLOWER_KEY_TCP_DST]	= { .type = NLA_U16 },
503b175c3a4SJamal Hadi Salim 	[TCA_FLOWER_KEY_UDP_SRC]	= { .type = NLA_U16 },
504b175c3a4SJamal Hadi Salim 	[TCA_FLOWER_KEY_UDP_DST]	= { .type = NLA_U16 },
5059399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_ID]	= { .type = NLA_U16 },
5069399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_PRIO]	= { .type = NLA_U8 },
5079399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_ETH_TYPE]	= { .type = NLA_U16 },
508bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_KEY_ID]	= { .type = NLA_U32 },
509bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_SRC]	= { .type = NLA_U32 },
510bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NLA_U32 },
511bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_DST]	= { .type = NLA_U32 },
512bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NLA_U32 },
513bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
514bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) },
515bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
516bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) },
517aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_TCP_SRC_MASK]	= { .type = NLA_U16 },
518aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_TCP_DST_MASK]	= { .type = NLA_U16 },
519aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_UDP_SRC_MASK]	= { .type = NLA_U16 },
520aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_UDP_DST_MASK]	= { .type = NLA_U16 },
5215976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_SRC_MASK]	= { .type = NLA_U16 },
5225976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_DST_MASK]	= { .type = NLA_U16 },
5235976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_SRC]	= { .type = NLA_U16 },
5245976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_DST]	= { .type = NLA_U16 },
525f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT]	= { .type = NLA_U16 },
526f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK]	= { .type = NLA_U16 },
527f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]	= { .type = NLA_U16 },
528f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK]	= { .type = NLA_U16 },
529faa3ffceSOr Gerlitz 	[TCA_FLOWER_KEY_FLAGS]		= { .type = NLA_U32 },
530faa3ffceSOr Gerlitz 	[TCA_FLOWER_KEY_FLAGS_MASK]	= { .type = NLA_U32 },
5317b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_TYPE]	= { .type = NLA_U8 },
5327b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_TYPE_MASK] = { .type = NLA_U8 },
5337b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_CODE]	= { .type = NLA_U8 },
5347b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_CODE_MASK] = { .type = NLA_U8 },
5357b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_TYPE]	= { .type = NLA_U8 },
5367b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_TYPE_MASK] = { .type = NLA_U8 },
5377b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_CODE]	= { .type = NLA_U8 },
5387b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_CODE_MASK] = { .type = NLA_U8 },
53999d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SIP]	= { .type = NLA_U32 },
54099d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SIP_MASK]	= { .type = NLA_U32 },
54199d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_TIP]	= { .type = NLA_U32 },
54299d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_TIP_MASK]	= { .type = NLA_U32 },
54399d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_OP]		= { .type = NLA_U8 },
54499d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_OP_MASK]	= { .type = NLA_U8 },
54599d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SHA]	= { .len = ETH_ALEN },
54699d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SHA_MASK]	= { .len = ETH_ALEN },
54799d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_THA]	= { .len = ETH_ALEN },
54899d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_THA_MASK]	= { .len = ETH_ALEN },
549a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_TTL]	= { .type = NLA_U8 },
550a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_BOS]	= { .type = NLA_U8 },
551a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_TC]	= { .type = NLA_U8 },
552a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_LABEL]	= { .type = NLA_U32 },
553fdfc7dd6SJiri Pirko 	[TCA_FLOWER_KEY_TCP_FLAGS]	= { .type = NLA_U16 },
554fdfc7dd6SJiri Pirko 	[TCA_FLOWER_KEY_TCP_FLAGS_MASK]	= { .type = NLA_U16 },
5554d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TOS]		= { .type = NLA_U8 },
5564d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TOS_MASK]	= { .type = NLA_U8 },
5574d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TTL]		= { .type = NLA_U8 },
5584d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TTL_MASK]	= { .type = NLA_U8 },
559d64efd09SJianbo Liu 	[TCA_FLOWER_KEY_CVLAN_ID]	= { .type = NLA_U16 },
560d64efd09SJianbo Liu 	[TCA_FLOWER_KEY_CVLAN_PRIO]	= { .type = NLA_U8 },
561d64efd09SJianbo Liu 	[TCA_FLOWER_KEY_CVLAN_ETH_TYPE]	= { .type = NLA_U16 },
5620e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TOS]	= { .type = NLA_U8 },
5630e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TOS_MASK] = { .type = NLA_U8 },
5640e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TTL]	 = { .type = NLA_U8 },
5650e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TTL_MASK] = { .type = NLA_U8 },
5660a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPTS]	= { .type = NLA_NESTED },
5670a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPTS_MASK]	= { .type = NLA_NESTED },
5680a6e7778SPieter Jansen van Vuuren };
5690a6e7778SPieter Jansen van Vuuren 
5700a6e7778SPieter Jansen van Vuuren static const struct nla_policy
5710a6e7778SPieter Jansen van Vuuren enc_opts_policy[TCA_FLOWER_KEY_ENC_OPTS_MAX + 1] = {
5720a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPTS_GENEVE]        = { .type = NLA_NESTED },
5730a6e7778SPieter Jansen van Vuuren };
5740a6e7778SPieter Jansen van Vuuren 
5750a6e7778SPieter Jansen van Vuuren static const struct nla_policy
5760a6e7778SPieter Jansen van Vuuren geneve_opt_policy[TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX + 1] = {
5770a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS]      = { .type = NLA_U16 },
5780a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE]       = { .type = NLA_U8 },
5790a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA]       = { .type = NLA_BINARY,
5800a6e7778SPieter Jansen van Vuuren 						       .len = 128 },
58177b9900eSJiri Pirko };
58277b9900eSJiri Pirko 
58377b9900eSJiri Pirko static void fl_set_key_val(struct nlattr **tb,
58477b9900eSJiri Pirko 			   void *val, int val_type,
58577b9900eSJiri Pirko 			   void *mask, int mask_type, int len)
58677b9900eSJiri Pirko {
58777b9900eSJiri Pirko 	if (!tb[val_type])
58877b9900eSJiri Pirko 		return;
58977b9900eSJiri Pirko 	memcpy(val, nla_data(tb[val_type]), len);
59077b9900eSJiri Pirko 	if (mask_type == TCA_FLOWER_UNSPEC || !tb[mask_type])
59177b9900eSJiri Pirko 		memset(mask, 0xff, len);
59277b9900eSJiri Pirko 	else
59377b9900eSJiri Pirko 		memcpy(mask, nla_data(tb[mask_type]), len);
59477b9900eSJiri Pirko }
59577b9900eSJiri Pirko 
596*5c72299fSAmritha Nambiar static int fl_set_key_port_range(struct nlattr **tb, struct fl_flow_key *key,
597*5c72299fSAmritha Nambiar 				 struct fl_flow_key *mask)
598*5c72299fSAmritha Nambiar {
599*5c72299fSAmritha Nambiar 	fl_set_key_val(tb, &key->tp_min.dst,
600*5c72299fSAmritha Nambiar 		       TCA_FLOWER_KEY_PORT_DST_MIN, &mask->tp_min.dst,
601*5c72299fSAmritha Nambiar 		       TCA_FLOWER_UNSPEC, sizeof(key->tp_min.dst));
602*5c72299fSAmritha Nambiar 	fl_set_key_val(tb, &key->tp_max.dst,
603*5c72299fSAmritha Nambiar 		       TCA_FLOWER_KEY_PORT_DST_MAX, &mask->tp_max.dst,
604*5c72299fSAmritha Nambiar 		       TCA_FLOWER_UNSPEC, sizeof(key->tp_max.dst));
605*5c72299fSAmritha Nambiar 	fl_set_key_val(tb, &key->tp_min.src,
606*5c72299fSAmritha Nambiar 		       TCA_FLOWER_KEY_PORT_SRC_MIN, &mask->tp_min.src,
607*5c72299fSAmritha Nambiar 		       TCA_FLOWER_UNSPEC, sizeof(key->tp_min.src));
608*5c72299fSAmritha Nambiar 	fl_set_key_val(tb, &key->tp_max.src,
609*5c72299fSAmritha Nambiar 		       TCA_FLOWER_KEY_PORT_SRC_MAX, &mask->tp_max.src,
610*5c72299fSAmritha Nambiar 		       TCA_FLOWER_UNSPEC, sizeof(key->tp_max.src));
611*5c72299fSAmritha Nambiar 
612*5c72299fSAmritha Nambiar 	if ((mask->tp_min.dst && mask->tp_max.dst &&
613*5c72299fSAmritha Nambiar 	     htons(key->tp_max.dst) <= htons(key->tp_min.dst)) ||
614*5c72299fSAmritha Nambiar 	     (mask->tp_min.src && mask->tp_max.src &&
615*5c72299fSAmritha Nambiar 	      htons(key->tp_max.src) <= htons(key->tp_min.src)))
616*5c72299fSAmritha Nambiar 		return -EINVAL;
617*5c72299fSAmritha Nambiar 
618*5c72299fSAmritha Nambiar 	return 0;
619*5c72299fSAmritha Nambiar }
620*5c72299fSAmritha Nambiar 
6211a7fca63SBenjamin LaHaise static int fl_set_key_mpls(struct nlattr **tb,
622a577d8f7SBenjamin LaHaise 			   struct flow_dissector_key_mpls *key_val,
623a577d8f7SBenjamin LaHaise 			   struct flow_dissector_key_mpls *key_mask)
624a577d8f7SBenjamin LaHaise {
625a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_TTL]) {
626a577d8f7SBenjamin LaHaise 		key_val->mpls_ttl = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TTL]);
627a577d8f7SBenjamin LaHaise 		key_mask->mpls_ttl = MPLS_TTL_MASK;
628a577d8f7SBenjamin LaHaise 	}
629a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_BOS]) {
6301a7fca63SBenjamin LaHaise 		u8 bos = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_BOS]);
6311a7fca63SBenjamin LaHaise 
6321a7fca63SBenjamin LaHaise 		if (bos & ~MPLS_BOS_MASK)
6331a7fca63SBenjamin LaHaise 			return -EINVAL;
6341a7fca63SBenjamin LaHaise 		key_val->mpls_bos = bos;
635a577d8f7SBenjamin LaHaise 		key_mask->mpls_bos = MPLS_BOS_MASK;
636a577d8f7SBenjamin LaHaise 	}
637a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_TC]) {
6381a7fca63SBenjamin LaHaise 		u8 tc = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TC]);
6391a7fca63SBenjamin LaHaise 
6401a7fca63SBenjamin LaHaise 		if (tc & ~MPLS_TC_MASK)
6411a7fca63SBenjamin LaHaise 			return -EINVAL;
6421a7fca63SBenjamin LaHaise 		key_val->mpls_tc = tc;
643a577d8f7SBenjamin LaHaise 		key_mask->mpls_tc = MPLS_TC_MASK;
644a577d8f7SBenjamin LaHaise 	}
645a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_LABEL]) {
6461a7fca63SBenjamin LaHaise 		u32 label = nla_get_u32(tb[TCA_FLOWER_KEY_MPLS_LABEL]);
6471a7fca63SBenjamin LaHaise 
6481a7fca63SBenjamin LaHaise 		if (label & ~MPLS_LABEL_MASK)
6491a7fca63SBenjamin LaHaise 			return -EINVAL;
6501a7fca63SBenjamin LaHaise 		key_val->mpls_label = label;
651a577d8f7SBenjamin LaHaise 		key_mask->mpls_label = MPLS_LABEL_MASK;
652a577d8f7SBenjamin LaHaise 	}
6531a7fca63SBenjamin LaHaise 	return 0;
654a577d8f7SBenjamin LaHaise }
655a577d8f7SBenjamin LaHaise 
6569399ae9aSHadar Hen Zion static void fl_set_key_vlan(struct nlattr **tb,
657aaab0834SJianbo Liu 			    __be16 ethertype,
658d64efd09SJianbo Liu 			    int vlan_id_key, int vlan_prio_key,
6599399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *key_val,
6609399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *key_mask)
6619399ae9aSHadar Hen Zion {
6629399ae9aSHadar Hen Zion #define VLAN_PRIORITY_MASK	0x7
6639399ae9aSHadar Hen Zion 
664d64efd09SJianbo Liu 	if (tb[vlan_id_key]) {
6659399ae9aSHadar Hen Zion 		key_val->vlan_id =
666d64efd09SJianbo Liu 			nla_get_u16(tb[vlan_id_key]) & VLAN_VID_MASK;
6679399ae9aSHadar Hen Zion 		key_mask->vlan_id = VLAN_VID_MASK;
6689399ae9aSHadar Hen Zion 	}
669d64efd09SJianbo Liu 	if (tb[vlan_prio_key]) {
6709399ae9aSHadar Hen Zion 		key_val->vlan_priority =
671d64efd09SJianbo Liu 			nla_get_u8(tb[vlan_prio_key]) &
6729399ae9aSHadar Hen Zion 			VLAN_PRIORITY_MASK;
6739399ae9aSHadar Hen Zion 		key_mask->vlan_priority = VLAN_PRIORITY_MASK;
6749399ae9aSHadar Hen Zion 	}
675aaab0834SJianbo Liu 	key_val->vlan_tpid = ethertype;
676aaab0834SJianbo Liu 	key_mask->vlan_tpid = cpu_to_be16(~0);
6779399ae9aSHadar Hen Zion }
6789399ae9aSHadar Hen Zion 
679faa3ffceSOr Gerlitz static void fl_set_key_flag(u32 flower_key, u32 flower_mask,
680faa3ffceSOr Gerlitz 			    u32 *dissector_key, u32 *dissector_mask,
681faa3ffceSOr Gerlitz 			    u32 flower_flag_bit, u32 dissector_flag_bit)
682faa3ffceSOr Gerlitz {
683faa3ffceSOr Gerlitz 	if (flower_mask & flower_flag_bit) {
684faa3ffceSOr Gerlitz 		*dissector_mask |= dissector_flag_bit;
685faa3ffceSOr Gerlitz 		if (flower_key & flower_flag_bit)
686faa3ffceSOr Gerlitz 			*dissector_key |= dissector_flag_bit;
687faa3ffceSOr Gerlitz 	}
688faa3ffceSOr Gerlitz }
689faa3ffceSOr Gerlitz 
690d9724772SOr Gerlitz static int fl_set_key_flags(struct nlattr **tb,
691faa3ffceSOr Gerlitz 			    u32 *flags_key, u32 *flags_mask)
692faa3ffceSOr Gerlitz {
693faa3ffceSOr Gerlitz 	u32 key, mask;
694faa3ffceSOr Gerlitz 
695d9724772SOr Gerlitz 	/* mask is mandatory for flags */
696d9724772SOr Gerlitz 	if (!tb[TCA_FLOWER_KEY_FLAGS_MASK])
697d9724772SOr Gerlitz 		return -EINVAL;
698faa3ffceSOr Gerlitz 
699faa3ffceSOr Gerlitz 	key = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS]));
700faa3ffceSOr Gerlitz 	mask = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS_MASK]));
701faa3ffceSOr Gerlitz 
702faa3ffceSOr Gerlitz 	*flags_key  = 0;
703faa3ffceSOr Gerlitz 	*flags_mask = 0;
704faa3ffceSOr Gerlitz 
705faa3ffceSOr Gerlitz 	fl_set_key_flag(key, mask, flags_key, flags_mask,
706faa3ffceSOr Gerlitz 			TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT);
707459d153dSPieter Jansen van Vuuren 	fl_set_key_flag(key, mask, flags_key, flags_mask,
708459d153dSPieter Jansen van Vuuren 			TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST,
709459d153dSPieter Jansen van Vuuren 			FLOW_DIS_FIRST_FRAG);
710d9724772SOr Gerlitz 
711d9724772SOr Gerlitz 	return 0;
712faa3ffceSOr Gerlitz }
713faa3ffceSOr Gerlitz 
7140e2c17b6SOr Gerlitz static void fl_set_key_ip(struct nlattr **tb, bool encap,
7154d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *key,
7164d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *mask)
7174d80cc0aSOr Gerlitz {
7180e2c17b6SOr Gerlitz 	int tos_key = encap ? TCA_FLOWER_KEY_ENC_IP_TOS : TCA_FLOWER_KEY_IP_TOS;
7190e2c17b6SOr Gerlitz 	int ttl_key = encap ? TCA_FLOWER_KEY_ENC_IP_TTL : TCA_FLOWER_KEY_IP_TTL;
7200e2c17b6SOr Gerlitz 	int tos_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TOS_MASK : TCA_FLOWER_KEY_IP_TOS_MASK;
7210e2c17b6SOr Gerlitz 	int ttl_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TTL_MASK : TCA_FLOWER_KEY_IP_TTL_MASK;
7224d80cc0aSOr Gerlitz 
7230e2c17b6SOr Gerlitz 	fl_set_key_val(tb, &key->tos, tos_key, &mask->tos, tos_mask, sizeof(key->tos));
7240e2c17b6SOr Gerlitz 	fl_set_key_val(tb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl));
7254d80cc0aSOr Gerlitz }
7264d80cc0aSOr Gerlitz 
7270a6e7778SPieter Jansen van Vuuren static int fl_set_geneve_opt(const struct nlattr *nla, struct fl_flow_key *key,
7280a6e7778SPieter Jansen van Vuuren 			     int depth, int option_len,
7290a6e7778SPieter Jansen van Vuuren 			     struct netlink_ext_ack *extack)
7300a6e7778SPieter Jansen van Vuuren {
7310a6e7778SPieter Jansen van Vuuren 	struct nlattr *tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX + 1];
7320a6e7778SPieter Jansen van Vuuren 	struct nlattr *class = NULL, *type = NULL, *data = NULL;
7330a6e7778SPieter Jansen van Vuuren 	struct geneve_opt *opt;
7340a6e7778SPieter Jansen van Vuuren 	int err, data_len = 0;
7350a6e7778SPieter Jansen van Vuuren 
7360a6e7778SPieter Jansen van Vuuren 	if (option_len > sizeof(struct geneve_opt))
7370a6e7778SPieter Jansen van Vuuren 		data_len = option_len - sizeof(struct geneve_opt);
7380a6e7778SPieter Jansen van Vuuren 
7390a6e7778SPieter Jansen van Vuuren 	opt = (struct geneve_opt *)&key->enc_opts.data[key->enc_opts.len];
7400a6e7778SPieter Jansen van Vuuren 	memset(opt, 0xff, option_len);
7410a6e7778SPieter Jansen van Vuuren 	opt->length = data_len / 4;
7420a6e7778SPieter Jansen van Vuuren 	opt->r1 = 0;
7430a6e7778SPieter Jansen van Vuuren 	opt->r2 = 0;
7440a6e7778SPieter Jansen van Vuuren 	opt->r3 = 0;
7450a6e7778SPieter Jansen van Vuuren 
7460a6e7778SPieter Jansen van Vuuren 	/* If no mask has been prodived we assume an exact match. */
7470a6e7778SPieter Jansen van Vuuren 	if (!depth)
7480a6e7778SPieter Jansen van Vuuren 		return sizeof(struct geneve_opt) + data_len;
7490a6e7778SPieter Jansen van Vuuren 
7500a6e7778SPieter Jansen van Vuuren 	if (nla_type(nla) != TCA_FLOWER_KEY_ENC_OPTS_GENEVE) {
7510a6e7778SPieter Jansen van Vuuren 		NL_SET_ERR_MSG(extack, "Non-geneve option type for mask");
7520a6e7778SPieter Jansen van Vuuren 		return -EINVAL;
7530a6e7778SPieter Jansen van Vuuren 	}
7540a6e7778SPieter Jansen van Vuuren 
7550a6e7778SPieter Jansen van Vuuren 	err = nla_parse_nested(tb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX,
7560a6e7778SPieter Jansen van Vuuren 			       nla, geneve_opt_policy, extack);
7570a6e7778SPieter Jansen van Vuuren 	if (err < 0)
7580a6e7778SPieter Jansen van Vuuren 		return err;
7590a6e7778SPieter Jansen van Vuuren 
7600a6e7778SPieter Jansen van Vuuren 	/* We are not allowed to omit any of CLASS, TYPE or DATA
7610a6e7778SPieter Jansen van Vuuren 	 * fields from the key.
7620a6e7778SPieter Jansen van Vuuren 	 */
7630a6e7778SPieter Jansen van Vuuren 	if (!option_len &&
7640a6e7778SPieter Jansen van Vuuren 	    (!tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS] ||
7650a6e7778SPieter Jansen van Vuuren 	     !tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE] ||
7660a6e7778SPieter Jansen van Vuuren 	     !tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA])) {
7670a6e7778SPieter Jansen van Vuuren 		NL_SET_ERR_MSG(extack, "Missing tunnel key geneve option class, type or data");
7680a6e7778SPieter Jansen van Vuuren 		return -EINVAL;
7690a6e7778SPieter Jansen van Vuuren 	}
7700a6e7778SPieter Jansen van Vuuren 
7710a6e7778SPieter Jansen van Vuuren 	/* Omitting any of CLASS, TYPE or DATA fields is allowed
7720a6e7778SPieter Jansen van Vuuren 	 * for the mask.
7730a6e7778SPieter Jansen van Vuuren 	 */
7740a6e7778SPieter Jansen van Vuuren 	if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA]) {
7750a6e7778SPieter Jansen van Vuuren 		int new_len = key->enc_opts.len;
7760a6e7778SPieter Jansen van Vuuren 
7770a6e7778SPieter Jansen van Vuuren 		data = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA];
7780a6e7778SPieter Jansen van Vuuren 		data_len = nla_len(data);
7790a6e7778SPieter Jansen van Vuuren 		if (data_len < 4) {
7800a6e7778SPieter Jansen van Vuuren 			NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is less than 4 bytes long");
7810a6e7778SPieter Jansen van Vuuren 			return -ERANGE;
7820a6e7778SPieter Jansen van Vuuren 		}
7830a6e7778SPieter Jansen van Vuuren 		if (data_len % 4) {
7840a6e7778SPieter Jansen van Vuuren 			NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is not a multiple of 4 bytes long");
7850a6e7778SPieter Jansen van Vuuren 			return -ERANGE;
7860a6e7778SPieter Jansen van Vuuren 		}
7870a6e7778SPieter Jansen van Vuuren 
7880a6e7778SPieter Jansen van Vuuren 		new_len += sizeof(struct geneve_opt) + data_len;
7890a6e7778SPieter Jansen van Vuuren 		BUILD_BUG_ON(FLOW_DIS_TUN_OPTS_MAX != IP_TUNNEL_OPTS_MAX);
7900a6e7778SPieter Jansen van Vuuren 		if (new_len > FLOW_DIS_TUN_OPTS_MAX) {
7910a6e7778SPieter Jansen van Vuuren 			NL_SET_ERR_MSG(extack, "Tunnel options exceeds max size");
7920a6e7778SPieter Jansen van Vuuren 			return -ERANGE;
7930a6e7778SPieter Jansen van Vuuren 		}
7940a6e7778SPieter Jansen van Vuuren 		opt->length = data_len / 4;
7950a6e7778SPieter Jansen van Vuuren 		memcpy(opt->opt_data, nla_data(data), data_len);
7960a6e7778SPieter Jansen van Vuuren 	}
7970a6e7778SPieter Jansen van Vuuren 
7980a6e7778SPieter Jansen van Vuuren 	if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS]) {
7990a6e7778SPieter Jansen van Vuuren 		class = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS];
8000a6e7778SPieter Jansen van Vuuren 		opt->opt_class = nla_get_be16(class);
8010a6e7778SPieter Jansen van Vuuren 	}
8020a6e7778SPieter Jansen van Vuuren 
8030a6e7778SPieter Jansen van Vuuren 	if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE]) {
8040a6e7778SPieter Jansen van Vuuren 		type = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE];
8050a6e7778SPieter Jansen van Vuuren 		opt->type = nla_get_u8(type);
8060a6e7778SPieter Jansen van Vuuren 	}
8070a6e7778SPieter Jansen van Vuuren 
8080a6e7778SPieter Jansen van Vuuren 	return sizeof(struct geneve_opt) + data_len;
8090a6e7778SPieter Jansen van Vuuren }
8100a6e7778SPieter Jansen van Vuuren 
8110a6e7778SPieter Jansen van Vuuren static int fl_set_enc_opt(struct nlattr **tb, struct fl_flow_key *key,
8120a6e7778SPieter Jansen van Vuuren 			  struct fl_flow_key *mask,
8130a6e7778SPieter Jansen van Vuuren 			  struct netlink_ext_ack *extack)
8140a6e7778SPieter Jansen van Vuuren {
8150a6e7778SPieter Jansen van Vuuren 	const struct nlattr *nla_enc_key, *nla_opt_key, *nla_opt_msk = NULL;
81663c82997SJakub Kicinski 	int err, option_len, key_depth, msk_depth = 0;
81763c82997SJakub Kicinski 
81863c82997SJakub Kicinski 	err = nla_validate_nested(tb[TCA_FLOWER_KEY_ENC_OPTS],
81963c82997SJakub Kicinski 				  TCA_FLOWER_KEY_ENC_OPTS_MAX,
82063c82997SJakub Kicinski 				  enc_opts_policy, extack);
82163c82997SJakub Kicinski 	if (err)
82263c82997SJakub Kicinski 		return err;
8230a6e7778SPieter Jansen van Vuuren 
8240a6e7778SPieter Jansen van Vuuren 	nla_enc_key = nla_data(tb[TCA_FLOWER_KEY_ENC_OPTS]);
8250a6e7778SPieter Jansen van Vuuren 
8260a6e7778SPieter Jansen van Vuuren 	if (tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]) {
82763c82997SJakub Kicinski 		err = nla_validate_nested(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK],
82863c82997SJakub Kicinski 					  TCA_FLOWER_KEY_ENC_OPTS_MAX,
82963c82997SJakub Kicinski 					  enc_opts_policy, extack);
83063c82997SJakub Kicinski 		if (err)
83163c82997SJakub Kicinski 			return err;
83263c82997SJakub Kicinski 
8330a6e7778SPieter Jansen van Vuuren 		nla_opt_msk = nla_data(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]);
8340a6e7778SPieter Jansen van Vuuren 		msk_depth = nla_len(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]);
8350a6e7778SPieter Jansen van Vuuren 	}
8360a6e7778SPieter Jansen van Vuuren 
8370a6e7778SPieter Jansen van Vuuren 	nla_for_each_attr(nla_opt_key, nla_enc_key,
8380a6e7778SPieter Jansen van Vuuren 			  nla_len(tb[TCA_FLOWER_KEY_ENC_OPTS]), key_depth) {
8390a6e7778SPieter Jansen van Vuuren 		switch (nla_type(nla_opt_key)) {
8400a6e7778SPieter Jansen van Vuuren 		case TCA_FLOWER_KEY_ENC_OPTS_GENEVE:
8410a6e7778SPieter Jansen van Vuuren 			option_len = 0;
8420a6e7778SPieter Jansen van Vuuren 			key->enc_opts.dst_opt_type = TUNNEL_GENEVE_OPT;
8430a6e7778SPieter Jansen van Vuuren 			option_len = fl_set_geneve_opt(nla_opt_key, key,
8440a6e7778SPieter Jansen van Vuuren 						       key_depth, option_len,
8450a6e7778SPieter Jansen van Vuuren 						       extack);
8460a6e7778SPieter Jansen van Vuuren 			if (option_len < 0)
8470a6e7778SPieter Jansen van Vuuren 				return option_len;
8480a6e7778SPieter Jansen van Vuuren 
8490a6e7778SPieter Jansen van Vuuren 			key->enc_opts.len += option_len;
8500a6e7778SPieter Jansen van Vuuren 			/* At the same time we need to parse through the mask
8510a6e7778SPieter Jansen van Vuuren 			 * in order to verify exact and mask attribute lengths.
8520a6e7778SPieter Jansen van Vuuren 			 */
8530a6e7778SPieter Jansen van Vuuren 			mask->enc_opts.dst_opt_type = TUNNEL_GENEVE_OPT;
8540a6e7778SPieter Jansen van Vuuren 			option_len = fl_set_geneve_opt(nla_opt_msk, mask,
8550a6e7778SPieter Jansen van Vuuren 						       msk_depth, option_len,
8560a6e7778SPieter Jansen van Vuuren 						       extack);
8570a6e7778SPieter Jansen van Vuuren 			if (option_len < 0)
8580a6e7778SPieter Jansen van Vuuren 				return option_len;
8590a6e7778SPieter Jansen van Vuuren 
8600a6e7778SPieter Jansen van Vuuren 			mask->enc_opts.len += option_len;
8610a6e7778SPieter Jansen van Vuuren 			if (key->enc_opts.len != mask->enc_opts.len) {
8620a6e7778SPieter Jansen van Vuuren 				NL_SET_ERR_MSG(extack, "Key and mask miss aligned");
8630a6e7778SPieter Jansen van Vuuren 				return -EINVAL;
8640a6e7778SPieter Jansen van Vuuren 			}
8650a6e7778SPieter Jansen van Vuuren 
8660a6e7778SPieter Jansen van Vuuren 			if (msk_depth)
8670a6e7778SPieter Jansen van Vuuren 				nla_opt_msk = nla_next(nla_opt_msk, &msk_depth);
8680a6e7778SPieter Jansen van Vuuren 			break;
8690a6e7778SPieter Jansen van Vuuren 		default:
8700a6e7778SPieter Jansen van Vuuren 			NL_SET_ERR_MSG(extack, "Unknown tunnel option type");
8710a6e7778SPieter Jansen van Vuuren 			return -EINVAL;
8720a6e7778SPieter Jansen van Vuuren 		}
8730a6e7778SPieter Jansen van Vuuren 	}
8740a6e7778SPieter Jansen van Vuuren 
8750a6e7778SPieter Jansen van Vuuren 	return 0;
8760a6e7778SPieter Jansen van Vuuren }
8770a6e7778SPieter Jansen van Vuuren 
87877b9900eSJiri Pirko static int fl_set_key(struct net *net, struct nlattr **tb,
8791057c55fSAlexander Aring 		      struct fl_flow_key *key, struct fl_flow_key *mask,
8801057c55fSAlexander Aring 		      struct netlink_ext_ack *extack)
88177b9900eSJiri Pirko {
8829399ae9aSHadar Hen Zion 	__be16 ethertype;
883d9724772SOr Gerlitz 	int ret = 0;
884dd3aa3b5SBrian Haley #ifdef CONFIG_NET_CLS_IND
88577b9900eSJiri Pirko 	if (tb[TCA_FLOWER_INDEV]) {
8861057c55fSAlexander Aring 		int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV], extack);
88777b9900eSJiri Pirko 		if (err < 0)
88877b9900eSJiri Pirko 			return err;
88977b9900eSJiri Pirko 		key->indev_ifindex = err;
89077b9900eSJiri Pirko 		mask->indev_ifindex = 0xffffffff;
89177b9900eSJiri Pirko 	}
892dd3aa3b5SBrian Haley #endif
89377b9900eSJiri Pirko 
89477b9900eSJiri Pirko 	fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
89577b9900eSJiri Pirko 		       mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
89677b9900eSJiri Pirko 		       sizeof(key->eth.dst));
89777b9900eSJiri Pirko 	fl_set_key_val(tb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
89877b9900eSJiri Pirko 		       mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
89977b9900eSJiri Pirko 		       sizeof(key->eth.src));
90066530bdfSJamal Hadi Salim 
9010b498a52SArnd Bergmann 	if (tb[TCA_FLOWER_KEY_ETH_TYPE]) {
9029399ae9aSHadar Hen Zion 		ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_ETH_TYPE]);
9039399ae9aSHadar Hen Zion 
904aaab0834SJianbo Liu 		if (eth_type_vlan(ethertype)) {
905d64efd09SJianbo Liu 			fl_set_key_vlan(tb, ethertype, TCA_FLOWER_KEY_VLAN_ID,
906d64efd09SJianbo Liu 					TCA_FLOWER_KEY_VLAN_PRIO, &key->vlan,
907d64efd09SJianbo Liu 					&mask->vlan);
908d64efd09SJianbo Liu 
9095e9a0fe4SJianbo Liu 			if (tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]) {
910d64efd09SJianbo Liu 				ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]);
911d64efd09SJianbo Liu 				if (eth_type_vlan(ethertype)) {
912d64efd09SJianbo Liu 					fl_set_key_vlan(tb, ethertype,
913d64efd09SJianbo Liu 							TCA_FLOWER_KEY_CVLAN_ID,
914d64efd09SJianbo Liu 							TCA_FLOWER_KEY_CVLAN_PRIO,
915d64efd09SJianbo Liu 							&key->cvlan, &mask->cvlan);
9169399ae9aSHadar Hen Zion 					fl_set_key_val(tb, &key->basic.n_proto,
917d64efd09SJianbo Liu 						       TCA_FLOWER_KEY_CVLAN_ETH_TYPE,
918d64efd09SJianbo Liu 						       &mask->basic.n_proto,
919d64efd09SJianbo Liu 						       TCA_FLOWER_UNSPEC,
92077b9900eSJiri Pirko 						       sizeof(key->basic.n_proto));
9219399ae9aSHadar Hen Zion 				} else {
9229399ae9aSHadar Hen Zion 					key->basic.n_proto = ethertype;
9239399ae9aSHadar Hen Zion 					mask->basic.n_proto = cpu_to_be16(~0);
9249399ae9aSHadar Hen Zion 				}
9255e9a0fe4SJianbo Liu 			}
926d64efd09SJianbo Liu 		} else {
927d64efd09SJianbo Liu 			key->basic.n_proto = ethertype;
928d64efd09SJianbo Liu 			mask->basic.n_proto = cpu_to_be16(~0);
929d64efd09SJianbo Liu 		}
9300b498a52SArnd Bergmann 	}
93166530bdfSJamal Hadi Salim 
93277b9900eSJiri Pirko 	if (key->basic.n_proto == htons(ETH_P_IP) ||
93377b9900eSJiri Pirko 	    key->basic.n_proto == htons(ETH_P_IPV6)) {
93477b9900eSJiri Pirko 		fl_set_key_val(tb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
93577b9900eSJiri Pirko 			       &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
93677b9900eSJiri Pirko 			       sizeof(key->basic.ip_proto));
9370e2c17b6SOr Gerlitz 		fl_set_key_ip(tb, false, &key->ip, &mask->ip);
93877b9900eSJiri Pirko 	}
93966530bdfSJamal Hadi Salim 
94066530bdfSJamal Hadi Salim 	if (tb[TCA_FLOWER_KEY_IPV4_SRC] || tb[TCA_FLOWER_KEY_IPV4_DST]) {
94166530bdfSJamal Hadi Salim 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
942970bfcd0SPaul Blakey 		mask->control.addr_type = ~0;
94377b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
94477b9900eSJiri Pirko 			       &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
94577b9900eSJiri Pirko 			       sizeof(key->ipv4.src));
94677b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
94777b9900eSJiri Pirko 			       &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
94877b9900eSJiri Pirko 			       sizeof(key->ipv4.dst));
94966530bdfSJamal Hadi Salim 	} else if (tb[TCA_FLOWER_KEY_IPV6_SRC] || tb[TCA_FLOWER_KEY_IPV6_DST]) {
95066530bdfSJamal Hadi Salim 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
951970bfcd0SPaul Blakey 		mask->control.addr_type = ~0;
95277b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
95377b9900eSJiri Pirko 			       &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
95477b9900eSJiri Pirko 			       sizeof(key->ipv6.src));
95577b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
95677b9900eSJiri Pirko 			       &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
95777b9900eSJiri Pirko 			       sizeof(key->ipv6.dst));
95877b9900eSJiri Pirko 	}
95966530bdfSJamal Hadi Salim 
96077b9900eSJiri Pirko 	if (key->basic.ip_proto == IPPROTO_TCP) {
96177b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
962aa72d708SOr Gerlitz 			       &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
96377b9900eSJiri Pirko 			       sizeof(key->tp.src));
96477b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
965aa72d708SOr Gerlitz 			       &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
96677b9900eSJiri Pirko 			       sizeof(key->tp.dst));
967fdfc7dd6SJiri Pirko 		fl_set_key_val(tb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS,
968fdfc7dd6SJiri Pirko 			       &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK,
969fdfc7dd6SJiri Pirko 			       sizeof(key->tcp.flags));
97077b9900eSJiri Pirko 	} else if (key->basic.ip_proto == IPPROTO_UDP) {
97177b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
972aa72d708SOr Gerlitz 			       &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
97377b9900eSJiri Pirko 			       sizeof(key->tp.src));
97477b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
975aa72d708SOr Gerlitz 			       &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
97677b9900eSJiri Pirko 			       sizeof(key->tp.dst));
9775976c5f4SSimon Horman 	} else if (key->basic.ip_proto == IPPROTO_SCTP) {
9785976c5f4SSimon Horman 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
9795976c5f4SSimon Horman 			       &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
9805976c5f4SSimon Horman 			       sizeof(key->tp.src));
9815976c5f4SSimon Horman 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
9825976c5f4SSimon Horman 			       &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
9835976c5f4SSimon Horman 			       sizeof(key->tp.dst));
9847b684884SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_IP) &&
9857b684884SSimon Horman 		   key->basic.ip_proto == IPPROTO_ICMP) {
9867b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV4_TYPE,
9877b684884SSimon Horman 			       &mask->icmp.type,
9887b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,
9897b684884SSimon Horman 			       sizeof(key->icmp.type));
9907b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE,
9917b684884SSimon Horman 			       &mask->icmp.code,
9927b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
9937b684884SSimon Horman 			       sizeof(key->icmp.code));
9947b684884SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_IPV6) &&
9957b684884SSimon Horman 		   key->basic.ip_proto == IPPROTO_ICMPV6) {
9967b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV6_TYPE,
9977b684884SSimon Horman 			       &mask->icmp.type,
9987b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
9997b684884SSimon Horman 			       sizeof(key->icmp.type));
1000040587afSSimon Horman 		fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV6_CODE,
10017b684884SSimon Horman 			       &mask->icmp.code,
1002040587afSSimon Horman 			       TCA_FLOWER_KEY_ICMPV6_CODE_MASK,
10037b684884SSimon Horman 			       sizeof(key->icmp.code));
1004a577d8f7SBenjamin LaHaise 	} else if (key->basic.n_proto == htons(ETH_P_MPLS_UC) ||
1005a577d8f7SBenjamin LaHaise 		   key->basic.n_proto == htons(ETH_P_MPLS_MC)) {
10061a7fca63SBenjamin LaHaise 		ret = fl_set_key_mpls(tb, &key->mpls, &mask->mpls);
10071a7fca63SBenjamin LaHaise 		if (ret)
10081a7fca63SBenjamin LaHaise 			return ret;
100999d31326SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_ARP) ||
101099d31326SSimon Horman 		   key->basic.n_proto == htons(ETH_P_RARP)) {
101199d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.sip, TCA_FLOWER_KEY_ARP_SIP,
101299d31326SSimon Horman 			       &mask->arp.sip, TCA_FLOWER_KEY_ARP_SIP_MASK,
101399d31326SSimon Horman 			       sizeof(key->arp.sip));
101499d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.tip, TCA_FLOWER_KEY_ARP_TIP,
101599d31326SSimon Horman 			       &mask->arp.tip, TCA_FLOWER_KEY_ARP_TIP_MASK,
101699d31326SSimon Horman 			       sizeof(key->arp.tip));
101799d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.op, TCA_FLOWER_KEY_ARP_OP,
101899d31326SSimon Horman 			       &mask->arp.op, TCA_FLOWER_KEY_ARP_OP_MASK,
101999d31326SSimon Horman 			       sizeof(key->arp.op));
102099d31326SSimon Horman 		fl_set_key_val(tb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA,
102199d31326SSimon Horman 			       mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK,
102299d31326SSimon Horman 			       sizeof(key->arp.sha));
102399d31326SSimon Horman 		fl_set_key_val(tb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA,
102499d31326SSimon Horman 			       mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK,
102599d31326SSimon Horman 			       sizeof(key->arp.tha));
102677b9900eSJiri Pirko 	}
102777b9900eSJiri Pirko 
1028*5c72299fSAmritha Nambiar 	if (key->basic.ip_proto == IPPROTO_TCP ||
1029*5c72299fSAmritha Nambiar 	    key->basic.ip_proto == IPPROTO_UDP ||
1030*5c72299fSAmritha Nambiar 	    key->basic.ip_proto == IPPROTO_SCTP) {
1031*5c72299fSAmritha Nambiar 		ret = fl_set_key_port_range(tb, key, mask);
1032*5c72299fSAmritha Nambiar 		if (ret)
1033*5c72299fSAmritha Nambiar 			return ret;
1034*5c72299fSAmritha Nambiar 	}
1035*5c72299fSAmritha Nambiar 
1036bc3103f1SAmir Vadai 	if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] ||
1037bc3103f1SAmir Vadai 	    tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) {
1038bc3103f1SAmir Vadai 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
1039970bfcd0SPaul Blakey 		mask->enc_control.addr_type = ~0;
1040bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv4.src,
1041bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_SRC,
1042bc3103f1SAmir Vadai 			       &mask->enc_ipv4.src,
1043bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
1044bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv4.src));
1045bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv4.dst,
1046bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_DST,
1047bc3103f1SAmir Vadai 			       &mask->enc_ipv4.dst,
1048bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
1049bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv4.dst));
1050bc3103f1SAmir Vadai 	}
1051bc3103f1SAmir Vadai 
1052bc3103f1SAmir Vadai 	if (tb[TCA_FLOWER_KEY_ENC_IPV6_SRC] ||
1053bc3103f1SAmir Vadai 	    tb[TCA_FLOWER_KEY_ENC_IPV6_DST]) {
1054bc3103f1SAmir Vadai 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
1055970bfcd0SPaul Blakey 		mask->enc_control.addr_type = ~0;
1056bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv6.src,
1057bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_SRC,
1058bc3103f1SAmir Vadai 			       &mask->enc_ipv6.src,
1059bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
1060bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv6.src));
1061bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv6.dst,
1062bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_DST,
1063bc3103f1SAmir Vadai 			       &mask->enc_ipv6.dst,
1064bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
1065bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv6.dst));
1066bc3103f1SAmir Vadai 	}
1067bc3103f1SAmir Vadai 
1068bc3103f1SAmir Vadai 	fl_set_key_val(tb, &key->enc_key_id.keyid, TCA_FLOWER_KEY_ENC_KEY_ID,
1069eb523f42SHadar Hen Zion 		       &mask->enc_key_id.keyid, TCA_FLOWER_UNSPEC,
1070bc3103f1SAmir Vadai 		       sizeof(key->enc_key_id.keyid));
1071bc3103f1SAmir Vadai 
1072f4d997fdSHadar Hen Zion 	fl_set_key_val(tb, &key->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
1073f4d997fdSHadar Hen Zion 		       &mask->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
1074f4d997fdSHadar Hen Zion 		       sizeof(key->enc_tp.src));
1075f4d997fdSHadar Hen Zion 
1076f4d997fdSHadar Hen Zion 	fl_set_key_val(tb, &key->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
1077f4d997fdSHadar Hen Zion 		       &mask->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
1078f4d997fdSHadar Hen Zion 		       sizeof(key->enc_tp.dst));
1079f4d997fdSHadar Hen Zion 
10800e2c17b6SOr Gerlitz 	fl_set_key_ip(tb, true, &key->enc_ip, &mask->enc_ip);
10810e2c17b6SOr Gerlitz 
10820a6e7778SPieter Jansen van Vuuren 	if (tb[TCA_FLOWER_KEY_ENC_OPTS]) {
10830a6e7778SPieter Jansen van Vuuren 		ret = fl_set_enc_opt(tb, key, mask, extack);
10840a6e7778SPieter Jansen van Vuuren 		if (ret)
10850a6e7778SPieter Jansen van Vuuren 			return ret;
10860a6e7778SPieter Jansen van Vuuren 	}
10870a6e7778SPieter Jansen van Vuuren 
1088d9724772SOr Gerlitz 	if (tb[TCA_FLOWER_KEY_FLAGS])
1089d9724772SOr Gerlitz 		ret = fl_set_key_flags(tb, &key->control.flags, &mask->control.flags);
1090faa3ffceSOr Gerlitz 
1091d9724772SOr Gerlitz 	return ret;
109277b9900eSJiri Pirko }
109377b9900eSJiri Pirko 
109405cd271fSPaul Blakey static void fl_mask_copy(struct fl_flow_mask *dst,
109505cd271fSPaul Blakey 			 struct fl_flow_mask *src)
109677b9900eSJiri Pirko {
109705cd271fSPaul Blakey 	const void *psrc = fl_key_get_start(&src->key, src);
109805cd271fSPaul Blakey 	void *pdst = fl_key_get_start(&dst->key, src);
109977b9900eSJiri Pirko 
110005cd271fSPaul Blakey 	memcpy(pdst, psrc, fl_mask_range(src));
110105cd271fSPaul Blakey 	dst->range = src->range;
110277b9900eSJiri Pirko }
110377b9900eSJiri Pirko 
110477b9900eSJiri Pirko static const struct rhashtable_params fl_ht_params = {
110577b9900eSJiri Pirko 	.key_offset = offsetof(struct cls_fl_filter, mkey), /* base offset */
110677b9900eSJiri Pirko 	.head_offset = offsetof(struct cls_fl_filter, ht_node),
110777b9900eSJiri Pirko 	.automatic_shrinking = true,
110877b9900eSJiri Pirko };
110977b9900eSJiri Pirko 
111005cd271fSPaul Blakey static int fl_init_mask_hashtable(struct fl_flow_mask *mask)
111177b9900eSJiri Pirko {
111205cd271fSPaul Blakey 	mask->filter_ht_params = fl_ht_params;
111305cd271fSPaul Blakey 	mask->filter_ht_params.key_len = fl_mask_range(mask);
111405cd271fSPaul Blakey 	mask->filter_ht_params.key_offset += mask->range.start;
111577b9900eSJiri Pirko 
111605cd271fSPaul Blakey 	return rhashtable_init(&mask->ht, &mask->filter_ht_params);
111777b9900eSJiri Pirko }
111877b9900eSJiri Pirko 
111977b9900eSJiri Pirko #define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member)
1120cb205a81Szhong jiang #define FL_KEY_MEMBER_SIZE(member) FIELD_SIZEOF(struct fl_flow_key, member)
112177b9900eSJiri Pirko 
1122339ba878SHadar Hen Zion #define FL_KEY_IS_MASKED(mask, member)						\
1123339ba878SHadar Hen Zion 	memchr_inv(((char *)mask) + FL_KEY_MEMBER_OFFSET(member),		\
1124339ba878SHadar Hen Zion 		   0, FL_KEY_MEMBER_SIZE(member))				\
112577b9900eSJiri Pirko 
112677b9900eSJiri Pirko #define FL_KEY_SET(keys, cnt, id, member)					\
112777b9900eSJiri Pirko 	do {									\
112877b9900eSJiri Pirko 		keys[cnt].key_id = id;						\
112977b9900eSJiri Pirko 		keys[cnt].offset = FL_KEY_MEMBER_OFFSET(member);		\
113077b9900eSJiri Pirko 		cnt++;								\
113177b9900eSJiri Pirko 	} while(0);
113277b9900eSJiri Pirko 
1133339ba878SHadar Hen Zion #define FL_KEY_SET_IF_MASKED(mask, keys, cnt, id, member)			\
113477b9900eSJiri Pirko 	do {									\
1135339ba878SHadar Hen Zion 		if (FL_KEY_IS_MASKED(mask, member))				\
113677b9900eSJiri Pirko 			FL_KEY_SET(keys, cnt, id, member);			\
113777b9900eSJiri Pirko 	} while(0);
113877b9900eSJiri Pirko 
113933fb5cbaSJiri Pirko static void fl_init_dissector(struct flow_dissector *dissector,
114033fb5cbaSJiri Pirko 			      struct fl_flow_key *mask)
114177b9900eSJiri Pirko {
114277b9900eSJiri Pirko 	struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX];
114377b9900eSJiri Pirko 	size_t cnt = 0;
114477b9900eSJiri Pirko 
114542aecaa9STom Herbert 	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control);
114677b9900eSJiri Pirko 	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic);
114733fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
114877b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_ETH_ADDRS, eth);
114933fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
115077b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4);
115133fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
115277b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6);
1153*5c72299fSAmritha Nambiar 	if (FL_KEY_IS_MASKED(mask, tp) ||
1154*5c72299fSAmritha Nambiar 	    FL_KEY_IS_MASKED(mask, tp_min) || FL_KEY_IS_MASKED(mask, tp_max))
1155*5c72299fSAmritha Nambiar 		FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_PORTS, tp);
115633fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
11574d80cc0aSOr Gerlitz 			     FLOW_DISSECTOR_KEY_IP, ip);
115833fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
1159fdfc7dd6SJiri Pirko 			     FLOW_DISSECTOR_KEY_TCP, tcp);
116033fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
11617b684884SSimon Horman 			     FLOW_DISSECTOR_KEY_ICMP, icmp);
116233fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
116399d31326SSimon Horman 			     FLOW_DISSECTOR_KEY_ARP, arp);
116433fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
1165a577d8f7SBenjamin LaHaise 			     FLOW_DISSECTOR_KEY_MPLS, mpls);
116633fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
11679399ae9aSHadar Hen Zion 			     FLOW_DISSECTOR_KEY_VLAN, vlan);
116833fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
1169d64efd09SJianbo Liu 			     FLOW_DISSECTOR_KEY_CVLAN, cvlan);
117033fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
1171519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_KEYID, enc_key_id);
117233fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
1173519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, enc_ipv4);
117433fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
1175519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, enc_ipv6);
117633fb5cbaSJiri Pirko 	if (FL_KEY_IS_MASKED(mask, enc_ipv4) ||
117733fb5cbaSJiri Pirko 	    FL_KEY_IS_MASKED(mask, enc_ipv6))
1178519d1052SHadar Hen Zion 		FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_ENC_CONTROL,
1179519d1052SHadar Hen Zion 			   enc_control);
118033fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
1181f4d997fdSHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp);
118233fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
11830e2c17b6SOr Gerlitz 			     FLOW_DISSECTOR_KEY_ENC_IP, enc_ip);
11840a6e7778SPieter Jansen van Vuuren 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
11850a6e7778SPieter Jansen van Vuuren 			     FLOW_DISSECTOR_KEY_ENC_OPTS, enc_opts);
118677b9900eSJiri Pirko 
118733fb5cbaSJiri Pirko 	skb_flow_dissector_init(dissector, keys, cnt);
118805cd271fSPaul Blakey }
118905cd271fSPaul Blakey 
119005cd271fSPaul Blakey static struct fl_flow_mask *fl_create_new_mask(struct cls_fl_head *head,
119105cd271fSPaul Blakey 					       struct fl_flow_mask *mask)
119205cd271fSPaul Blakey {
119305cd271fSPaul Blakey 	struct fl_flow_mask *newmask;
119405cd271fSPaul Blakey 	int err;
119505cd271fSPaul Blakey 
119605cd271fSPaul Blakey 	newmask = kzalloc(sizeof(*newmask), GFP_KERNEL);
119705cd271fSPaul Blakey 	if (!newmask)
119805cd271fSPaul Blakey 		return ERR_PTR(-ENOMEM);
119905cd271fSPaul Blakey 
120005cd271fSPaul Blakey 	fl_mask_copy(newmask, mask);
120105cd271fSPaul Blakey 
1202*5c72299fSAmritha Nambiar 	if ((newmask->key.tp_min.dst && newmask->key.tp_max.dst) ||
1203*5c72299fSAmritha Nambiar 	    (newmask->key.tp_min.src && newmask->key.tp_max.src))
1204*5c72299fSAmritha Nambiar 		newmask->flags |= TCA_FLOWER_MASK_FLAGS_RANGE;
1205*5c72299fSAmritha Nambiar 
120605cd271fSPaul Blakey 	err = fl_init_mask_hashtable(newmask);
120705cd271fSPaul Blakey 	if (err)
120805cd271fSPaul Blakey 		goto errout_free;
120905cd271fSPaul Blakey 
121033fb5cbaSJiri Pirko 	fl_init_dissector(&newmask->dissector, &newmask->key);
121105cd271fSPaul Blakey 
121205cd271fSPaul Blakey 	INIT_LIST_HEAD_RCU(&newmask->filters);
121305cd271fSPaul Blakey 
121405cd271fSPaul Blakey 	err = rhashtable_insert_fast(&head->ht, &newmask->ht_node,
121505cd271fSPaul Blakey 				     mask_ht_params);
121605cd271fSPaul Blakey 	if (err)
121705cd271fSPaul Blakey 		goto errout_destroy;
121805cd271fSPaul Blakey 
121905cd271fSPaul Blakey 	list_add_tail_rcu(&newmask->list, &head->masks);
122005cd271fSPaul Blakey 
122105cd271fSPaul Blakey 	return newmask;
122205cd271fSPaul Blakey 
122305cd271fSPaul Blakey errout_destroy:
122405cd271fSPaul Blakey 	rhashtable_destroy(&newmask->ht);
122505cd271fSPaul Blakey errout_free:
122605cd271fSPaul Blakey 	kfree(newmask);
122705cd271fSPaul Blakey 
122805cd271fSPaul Blakey 	return ERR_PTR(err);
122977b9900eSJiri Pirko }
123077b9900eSJiri Pirko 
123177b9900eSJiri Pirko static int fl_check_assign_mask(struct cls_fl_head *head,
123205cd271fSPaul Blakey 				struct cls_fl_filter *fnew,
123305cd271fSPaul Blakey 				struct cls_fl_filter *fold,
123477b9900eSJiri Pirko 				struct fl_flow_mask *mask)
123577b9900eSJiri Pirko {
123605cd271fSPaul Blakey 	struct fl_flow_mask *newmask;
123777b9900eSJiri Pirko 
123805cd271fSPaul Blakey 	fnew->mask = rhashtable_lookup_fast(&head->ht, mask, mask_ht_params);
123905cd271fSPaul Blakey 	if (!fnew->mask) {
124005cd271fSPaul Blakey 		if (fold)
124177b9900eSJiri Pirko 			return -EINVAL;
124205cd271fSPaul Blakey 
124305cd271fSPaul Blakey 		newmask = fl_create_new_mask(head, mask);
124405cd271fSPaul Blakey 		if (IS_ERR(newmask))
124505cd271fSPaul Blakey 			return PTR_ERR(newmask);
124605cd271fSPaul Blakey 
124705cd271fSPaul Blakey 		fnew->mask = newmask;
1248f6521c58SPaul Blakey 	} else if (fold && fold->mask != fnew->mask) {
124905cd271fSPaul Blakey 		return -EINVAL;
125077b9900eSJiri Pirko 	}
125177b9900eSJiri Pirko 
125277b9900eSJiri Pirko 	return 0;
125377b9900eSJiri Pirko }
125477b9900eSJiri Pirko 
125577b9900eSJiri Pirko static int fl_set_parms(struct net *net, struct tcf_proto *tp,
125677b9900eSJiri Pirko 			struct cls_fl_filter *f, struct fl_flow_mask *mask,
125777b9900eSJiri Pirko 			unsigned long base, struct nlattr **tb,
125850a56190SAlexander Aring 			struct nlattr *est, bool ovr,
1259b95ec7ebSJiri Pirko 			struct fl_flow_tmplt *tmplt,
126050a56190SAlexander Aring 			struct netlink_ext_ack *extack)
126177b9900eSJiri Pirko {
126277b9900eSJiri Pirko 	int err;
126377b9900eSJiri Pirko 
126450a56190SAlexander Aring 	err = tcf_exts_validate(net, tp, tb, est, &f->exts, ovr, extack);
126577b9900eSJiri Pirko 	if (err < 0)
126677b9900eSJiri Pirko 		return err;
126777b9900eSJiri Pirko 
126877b9900eSJiri Pirko 	if (tb[TCA_FLOWER_CLASSID]) {
126977b9900eSJiri Pirko 		f->res.classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]);
127077b9900eSJiri Pirko 		tcf_bind_filter(tp, &f->res, base);
127177b9900eSJiri Pirko 	}
127277b9900eSJiri Pirko 
12731057c55fSAlexander Aring 	err = fl_set_key(net, tb, &f->key, &mask->key, extack);
127477b9900eSJiri Pirko 	if (err)
127545507529SJiri Pirko 		return err;
127677b9900eSJiri Pirko 
127777b9900eSJiri Pirko 	fl_mask_update_range(mask);
127877b9900eSJiri Pirko 	fl_set_masked_key(&f->mkey, &f->key, mask);
127977b9900eSJiri Pirko 
1280b95ec7ebSJiri Pirko 	if (!fl_mask_fits_tmplt(tmplt, mask)) {
1281b95ec7ebSJiri Pirko 		NL_SET_ERR_MSG_MOD(extack, "Mask does not fit the template");
1282b95ec7ebSJiri Pirko 		return -EINVAL;
1283b95ec7ebSJiri Pirko 	}
1284b95ec7ebSJiri Pirko 
128577b9900eSJiri Pirko 	return 0;
128677b9900eSJiri Pirko }
128777b9900eSJiri Pirko 
128877b9900eSJiri Pirko static int fl_change(struct net *net, struct sk_buff *in_skb,
128977b9900eSJiri Pirko 		     struct tcf_proto *tp, unsigned long base,
129077b9900eSJiri Pirko 		     u32 handle, struct nlattr **tca,
12917306db38SAlexander Aring 		     void **arg, bool ovr, struct netlink_ext_ack *extack)
129277b9900eSJiri Pirko {
129377b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
12948113c095SWANG Cong 	struct cls_fl_filter *fold = *arg;
129577b9900eSJiri Pirko 	struct cls_fl_filter *fnew;
129639b7b6a6SArnd Bergmann 	struct nlattr **tb;
129777b9900eSJiri Pirko 	struct fl_flow_mask mask = {};
129877b9900eSJiri Pirko 	int err;
129977b9900eSJiri Pirko 
130077b9900eSJiri Pirko 	if (!tca[TCA_OPTIONS])
130177b9900eSJiri Pirko 		return -EINVAL;
130277b9900eSJiri Pirko 
130339b7b6a6SArnd Bergmann 	tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL);
130439b7b6a6SArnd Bergmann 	if (!tb)
130539b7b6a6SArnd Bergmann 		return -ENOBUFS;
130639b7b6a6SArnd Bergmann 
1307fceb6435SJohannes Berg 	err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS],
1308fceb6435SJohannes Berg 			       fl_policy, NULL);
130977b9900eSJiri Pirko 	if (err < 0)
131039b7b6a6SArnd Bergmann 		goto errout_tb;
131177b9900eSJiri Pirko 
131239b7b6a6SArnd Bergmann 	if (fold && handle && fold->handle != handle) {
131339b7b6a6SArnd Bergmann 		err = -EINVAL;
131439b7b6a6SArnd Bergmann 		goto errout_tb;
131539b7b6a6SArnd Bergmann 	}
131677b9900eSJiri Pirko 
131777b9900eSJiri Pirko 	fnew = kzalloc(sizeof(*fnew), GFP_KERNEL);
131839b7b6a6SArnd Bergmann 	if (!fnew) {
131939b7b6a6SArnd Bergmann 		err = -ENOBUFS;
132039b7b6a6SArnd Bergmann 		goto errout_tb;
132139b7b6a6SArnd Bergmann 	}
132277b9900eSJiri Pirko 
1323b9a24bb7SWANG Cong 	err = tcf_exts_init(&fnew->exts, TCA_FLOWER_ACT, 0);
1324b9a24bb7SWANG Cong 	if (err < 0)
1325b9a24bb7SWANG Cong 		goto errout;
132677b9900eSJiri Pirko 
132777b9900eSJiri Pirko 	if (!handle) {
132885bd0438SMatthew Wilcox 		handle = 1;
132985bd0438SMatthew Wilcox 		err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
133085bd0438SMatthew Wilcox 				    INT_MAX, GFP_KERNEL);
133185bd0438SMatthew Wilcox 	} else if (!fold) {
1332c15ab236SChris Mi 		/* user specifies a handle and it doesn't exist */
133385bd0438SMatthew Wilcox 		err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
133485bd0438SMatthew Wilcox 				    handle, GFP_KERNEL);
133585bd0438SMatthew Wilcox 	}
1336c15ab236SChris Mi 	if (err)
1337c15ab236SChris Mi 		goto errout;
133885bd0438SMatthew Wilcox 	fnew->handle = handle;
133977b9900eSJiri Pirko 
1340e69985c6SAmir Vadai 	if (tb[TCA_FLOWER_FLAGS]) {
1341e69985c6SAmir Vadai 		fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
1342e69985c6SAmir Vadai 
1343e69985c6SAmir Vadai 		if (!tc_flags_valid(fnew->flags)) {
1344e69985c6SAmir Vadai 			err = -EINVAL;
1345fe2502e4SCong Wang 			goto errout_idr;
1346e69985c6SAmir Vadai 		}
1347e69985c6SAmir Vadai 	}
13485b33f488SAmir Vadai 
134950a56190SAlexander Aring 	err = fl_set_parms(net, tp, fnew, &mask, base, tb, tca[TCA_RATE], ovr,
1350b95ec7ebSJiri Pirko 			   tp->chain->tmplt_priv, extack);
135177b9900eSJiri Pirko 	if (err)
1352fe2502e4SCong Wang 		goto errout_idr;
135377b9900eSJiri Pirko 
135405cd271fSPaul Blakey 	err = fl_check_assign_mask(head, fnew, fold, &mask);
135577b9900eSJiri Pirko 	if (err)
1356fe2502e4SCong Wang 		goto errout_idr;
135777b9900eSJiri Pirko 
1358e8eb36cdSAmir Vadai 	if (!tc_skip_sw(fnew->flags)) {
1359*5c72299fSAmritha Nambiar 		if (!fold && __fl_lookup(fnew->mask, &fnew->mkey)) {
1360a3308d8fSPaul Blakey 			err = -EEXIST;
136105cd271fSPaul Blakey 			goto errout_mask;
1362a3308d8fSPaul Blakey 		}
1363a3308d8fSPaul Blakey 
136405cd271fSPaul Blakey 		err = rhashtable_insert_fast(&fnew->mask->ht, &fnew->ht_node,
136505cd271fSPaul Blakey 					     fnew->mask->filter_ht_params);
136677b9900eSJiri Pirko 		if (err)
136705cd271fSPaul Blakey 			goto errout_mask;
1368e69985c6SAmir Vadai 	}
13695b33f488SAmir Vadai 
137079685219SHadar Hen Zion 	if (!tc_skip_hw(fnew->flags)) {
137105cd271fSPaul Blakey 		err = fl_hw_replace_filter(tp, fnew, extack);
1372e8eb36cdSAmir Vadai 		if (err)
137305cd271fSPaul Blakey 			goto errout_mask;
137479685219SHadar Hen Zion 	}
13755b33f488SAmir Vadai 
137655593960SOr Gerlitz 	if (!tc_in_hw(fnew->flags))
137755593960SOr Gerlitz 		fnew->flags |= TCA_CLS_FLAGS_NOT_IN_HW;
137855593960SOr Gerlitz 
13795b33f488SAmir Vadai 	if (fold) {
1380725cbb62SJiri Pirko 		if (!tc_skip_sw(fold->flags))
138105cd271fSPaul Blakey 			rhashtable_remove_fast(&fold->mask->ht,
138205cd271fSPaul Blakey 					       &fold->ht_node,
138305cd271fSPaul Blakey 					       fold->mask->filter_ht_params);
138479685219SHadar Hen Zion 		if (!tc_skip_hw(fold->flags))
13851b0f8037SJakub Kicinski 			fl_hw_destroy_filter(tp, fold, NULL);
13865b33f488SAmir Vadai 	}
138777b9900eSJiri Pirko 
13888113c095SWANG Cong 	*arg = fnew;
138977b9900eSJiri Pirko 
139077b9900eSJiri Pirko 	if (fold) {
1391234a4624SMatthew Wilcox 		idr_replace(&head->handle_idr, fnew, fnew->handle);
1392ff3532f2SDaniel Borkmann 		list_replace_rcu(&fold->list, &fnew->list);
139377b9900eSJiri Pirko 		tcf_unbind_filter(tp, &fold->res);
13940dadc117SCong Wang 		tcf_exts_get_net(&fold->exts);
1395aaa908ffSCong Wang 		tcf_queue_work(&fold->rwork, fl_destroy_filter_work);
139677b9900eSJiri Pirko 	} else {
139705cd271fSPaul Blakey 		list_add_tail_rcu(&fnew->list, &fnew->mask->filters);
139877b9900eSJiri Pirko 	}
139977b9900eSJiri Pirko 
140039b7b6a6SArnd Bergmann 	kfree(tb);
140177b9900eSJiri Pirko 	return 0;
140277b9900eSJiri Pirko 
140305cd271fSPaul Blakey errout_mask:
140405cd271fSPaul Blakey 	fl_mask_put(head, fnew->mask, false);
140505cd271fSPaul Blakey 
1406fe2502e4SCong Wang errout_idr:
14078258d2daSPaul Blakey 	if (!fold)
14089c160941SMatthew Wilcox 		idr_remove(&head->handle_idr, fnew->handle);
140977b9900eSJiri Pirko errout:
1410b9a24bb7SWANG Cong 	tcf_exts_destroy(&fnew->exts);
141177b9900eSJiri Pirko 	kfree(fnew);
141239b7b6a6SArnd Bergmann errout_tb:
141339b7b6a6SArnd Bergmann 	kfree(tb);
141477b9900eSJiri Pirko 	return err;
141577b9900eSJiri Pirko }
141677b9900eSJiri Pirko 
1417571acf21SAlexander Aring static int fl_delete(struct tcf_proto *tp, void *arg, bool *last,
1418571acf21SAlexander Aring 		     struct netlink_ext_ack *extack)
141977b9900eSJiri Pirko {
142077b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
14218113c095SWANG Cong 	struct cls_fl_filter *f = arg;
142277b9900eSJiri Pirko 
1423725cbb62SJiri Pirko 	if (!tc_skip_sw(f->flags))
142405cd271fSPaul Blakey 		rhashtable_remove_fast(&f->mask->ht, &f->ht_node,
142505cd271fSPaul Blakey 				       f->mask->filter_ht_params);
14261b0f8037SJakub Kicinski 	__fl_delete(tp, f, extack);
142705cd271fSPaul Blakey 	*last = list_empty(&head->masks);
142877b9900eSJiri Pirko 	return 0;
142977b9900eSJiri Pirko }
143077b9900eSJiri Pirko 
143177b9900eSJiri Pirko static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg)
143277b9900eSJiri Pirko {
143377b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
143477b9900eSJiri Pirko 	struct cls_fl_filter *f;
143577b9900eSJiri Pirko 
143601683a14SVlad Buslov 	arg->count = arg->skip;
143701683a14SVlad Buslov 
143801683a14SVlad Buslov 	while ((f = idr_get_next_ul(&head->handle_idr,
143901683a14SVlad Buslov 				    &arg->cookie)) != NULL) {
14408113c095SWANG Cong 		if (arg->fn(tp, f, arg) < 0) {
144177b9900eSJiri Pirko 			arg->stop = 1;
144277b9900eSJiri Pirko 			break;
144377b9900eSJiri Pirko 		}
144401683a14SVlad Buslov 		arg->cookie = f->handle + 1;
144577b9900eSJiri Pirko 		arg->count++;
144677b9900eSJiri Pirko 	}
144777b9900eSJiri Pirko }
144877b9900eSJiri Pirko 
144931533cbaSJohn Hurley static int fl_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb,
145031533cbaSJohn Hurley 			void *cb_priv, struct netlink_ext_ack *extack)
145131533cbaSJohn Hurley {
145231533cbaSJohn Hurley 	struct cls_fl_head *head = rtnl_dereference(tp->root);
145331533cbaSJohn Hurley 	struct tc_cls_flower_offload cls_flower = {};
145431533cbaSJohn Hurley 	struct tcf_block *block = tp->chain->block;
145531533cbaSJohn Hurley 	struct fl_flow_mask *mask;
145631533cbaSJohn Hurley 	struct cls_fl_filter *f;
145731533cbaSJohn Hurley 	int err;
145831533cbaSJohn Hurley 
145931533cbaSJohn Hurley 	list_for_each_entry(mask, &head->masks, list) {
146031533cbaSJohn Hurley 		list_for_each_entry(f, &mask->filters, list) {
146131533cbaSJohn Hurley 			if (tc_skip_hw(f->flags))
146231533cbaSJohn Hurley 				continue;
146331533cbaSJohn Hurley 
146431533cbaSJohn Hurley 			tc_cls_common_offload_init(&cls_flower.common, tp,
146531533cbaSJohn Hurley 						   f->flags, extack);
146631533cbaSJohn Hurley 			cls_flower.command = add ?
146731533cbaSJohn Hurley 				TC_CLSFLOWER_REPLACE : TC_CLSFLOWER_DESTROY;
146831533cbaSJohn Hurley 			cls_flower.cookie = (unsigned long)f;
146931533cbaSJohn Hurley 			cls_flower.dissector = &mask->dissector;
14709ca61630SVlad Buslov 			cls_flower.mask = &mask->key;
14719ca61630SVlad Buslov 			cls_flower.key = &f->mkey;
147231533cbaSJohn Hurley 			cls_flower.exts = &f->exts;
147331533cbaSJohn Hurley 			cls_flower.classid = f->res.classid;
147431533cbaSJohn Hurley 
147531533cbaSJohn Hurley 			err = cb(TC_SETUP_CLSFLOWER, &cls_flower, cb_priv);
147631533cbaSJohn Hurley 			if (err) {
147731533cbaSJohn Hurley 				if (add && tc_skip_sw(f->flags))
147831533cbaSJohn Hurley 					return err;
147931533cbaSJohn Hurley 				continue;
148031533cbaSJohn Hurley 			}
148131533cbaSJohn Hurley 
148231533cbaSJohn Hurley 			tc_cls_offload_cnt_update(block, &f->in_hw_count,
148331533cbaSJohn Hurley 						  &f->flags, add);
148431533cbaSJohn Hurley 		}
148531533cbaSJohn Hurley 	}
148631533cbaSJohn Hurley 
148731533cbaSJohn Hurley 	return 0;
148831533cbaSJohn Hurley }
148931533cbaSJohn Hurley 
149034738452SJiri Pirko static void fl_hw_create_tmplt(struct tcf_chain *chain,
149134738452SJiri Pirko 			       struct fl_flow_tmplt *tmplt)
149234738452SJiri Pirko {
149334738452SJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
149434738452SJiri Pirko 	struct tcf_block *block = chain->block;
149534738452SJiri Pirko 	struct tcf_exts dummy_exts = { 0, };
149634738452SJiri Pirko 
149734738452SJiri Pirko 	cls_flower.common.chain_index = chain->index;
149834738452SJiri Pirko 	cls_flower.command = TC_CLSFLOWER_TMPLT_CREATE;
149934738452SJiri Pirko 	cls_flower.cookie = (unsigned long) tmplt;
150034738452SJiri Pirko 	cls_flower.dissector = &tmplt->dissector;
150134738452SJiri Pirko 	cls_flower.mask = &tmplt->mask;
150234738452SJiri Pirko 	cls_flower.key = &tmplt->dummy_key;
150334738452SJiri Pirko 	cls_flower.exts = &dummy_exts;
150434738452SJiri Pirko 
150534738452SJiri Pirko 	/* We don't care if driver (any of them) fails to handle this
150634738452SJiri Pirko 	 * call. It serves just as a hint for it.
150734738452SJiri Pirko 	 */
150834738452SJiri Pirko 	tc_setup_cb_call(block, NULL, TC_SETUP_CLSFLOWER,
150934738452SJiri Pirko 			 &cls_flower, false);
151034738452SJiri Pirko }
151134738452SJiri Pirko 
151234738452SJiri Pirko static void fl_hw_destroy_tmplt(struct tcf_chain *chain,
151334738452SJiri Pirko 				struct fl_flow_tmplt *tmplt)
151434738452SJiri Pirko {
151534738452SJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
151634738452SJiri Pirko 	struct tcf_block *block = chain->block;
151734738452SJiri Pirko 
151834738452SJiri Pirko 	cls_flower.common.chain_index = chain->index;
151934738452SJiri Pirko 	cls_flower.command = TC_CLSFLOWER_TMPLT_DESTROY;
152034738452SJiri Pirko 	cls_flower.cookie = (unsigned long) tmplt;
152134738452SJiri Pirko 
152234738452SJiri Pirko 	tc_setup_cb_call(block, NULL, TC_SETUP_CLSFLOWER,
152334738452SJiri Pirko 			 &cls_flower, false);
152434738452SJiri Pirko }
152534738452SJiri Pirko 
1526b95ec7ebSJiri Pirko static void *fl_tmplt_create(struct net *net, struct tcf_chain *chain,
1527b95ec7ebSJiri Pirko 			     struct nlattr **tca,
1528b95ec7ebSJiri Pirko 			     struct netlink_ext_ack *extack)
1529b95ec7ebSJiri Pirko {
1530b95ec7ebSJiri Pirko 	struct fl_flow_tmplt *tmplt;
1531b95ec7ebSJiri Pirko 	struct nlattr **tb;
1532b95ec7ebSJiri Pirko 	int err;
1533b95ec7ebSJiri Pirko 
1534b95ec7ebSJiri Pirko 	if (!tca[TCA_OPTIONS])
1535b95ec7ebSJiri Pirko 		return ERR_PTR(-EINVAL);
1536b95ec7ebSJiri Pirko 
1537b95ec7ebSJiri Pirko 	tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL);
1538b95ec7ebSJiri Pirko 	if (!tb)
1539b95ec7ebSJiri Pirko 		return ERR_PTR(-ENOBUFS);
1540b95ec7ebSJiri Pirko 	err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS],
1541b95ec7ebSJiri Pirko 			       fl_policy, NULL);
1542b95ec7ebSJiri Pirko 	if (err)
1543b95ec7ebSJiri Pirko 		goto errout_tb;
1544b95ec7ebSJiri Pirko 
1545b95ec7ebSJiri Pirko 	tmplt = kzalloc(sizeof(*tmplt), GFP_KERNEL);
15461cbc36a5SDan Carpenter 	if (!tmplt) {
15471cbc36a5SDan Carpenter 		err = -ENOMEM;
1548b95ec7ebSJiri Pirko 		goto errout_tb;
15491cbc36a5SDan Carpenter 	}
1550b95ec7ebSJiri Pirko 	tmplt->chain = chain;
1551b95ec7ebSJiri Pirko 	err = fl_set_key(net, tb, &tmplt->dummy_key, &tmplt->mask, extack);
1552b95ec7ebSJiri Pirko 	if (err)
1553b95ec7ebSJiri Pirko 		goto errout_tmplt;
1554b95ec7ebSJiri Pirko 	kfree(tb);
1555b95ec7ebSJiri Pirko 
1556b95ec7ebSJiri Pirko 	fl_init_dissector(&tmplt->dissector, &tmplt->mask);
1557b95ec7ebSJiri Pirko 
155834738452SJiri Pirko 	fl_hw_create_tmplt(chain, tmplt);
155934738452SJiri Pirko 
1560b95ec7ebSJiri Pirko 	return tmplt;
1561b95ec7ebSJiri Pirko 
1562b95ec7ebSJiri Pirko errout_tmplt:
1563b95ec7ebSJiri Pirko 	kfree(tmplt);
1564b95ec7ebSJiri Pirko errout_tb:
1565b95ec7ebSJiri Pirko 	kfree(tb);
1566b95ec7ebSJiri Pirko 	return ERR_PTR(err);
1567b95ec7ebSJiri Pirko }
1568b95ec7ebSJiri Pirko 
1569b95ec7ebSJiri Pirko static void fl_tmplt_destroy(void *tmplt_priv)
1570b95ec7ebSJiri Pirko {
1571b95ec7ebSJiri Pirko 	struct fl_flow_tmplt *tmplt = tmplt_priv;
1572b95ec7ebSJiri Pirko 
157395278ddaSCong Wang 	fl_hw_destroy_tmplt(tmplt->chain, tmplt);
157495278ddaSCong Wang 	kfree(tmplt);
1575b95ec7ebSJiri Pirko }
1576b95ec7ebSJiri Pirko 
157777b9900eSJiri Pirko static int fl_dump_key_val(struct sk_buff *skb,
157877b9900eSJiri Pirko 			   void *val, int val_type,
157977b9900eSJiri Pirko 			   void *mask, int mask_type, int len)
158077b9900eSJiri Pirko {
158177b9900eSJiri Pirko 	int err;
158277b9900eSJiri Pirko 
158377b9900eSJiri Pirko 	if (!memchr_inv(mask, 0, len))
158477b9900eSJiri Pirko 		return 0;
158577b9900eSJiri Pirko 	err = nla_put(skb, val_type, len, val);
158677b9900eSJiri Pirko 	if (err)
158777b9900eSJiri Pirko 		return err;
158877b9900eSJiri Pirko 	if (mask_type != TCA_FLOWER_UNSPEC) {
158977b9900eSJiri Pirko 		err = nla_put(skb, mask_type, len, mask);
159077b9900eSJiri Pirko 		if (err)
159177b9900eSJiri Pirko 			return err;
159277b9900eSJiri Pirko 	}
159377b9900eSJiri Pirko 	return 0;
159477b9900eSJiri Pirko }
159577b9900eSJiri Pirko 
1596*5c72299fSAmritha Nambiar static int fl_dump_key_port_range(struct sk_buff *skb, struct fl_flow_key *key,
1597*5c72299fSAmritha Nambiar 				  struct fl_flow_key *mask)
1598*5c72299fSAmritha Nambiar {
1599*5c72299fSAmritha Nambiar 	if (fl_dump_key_val(skb, &key->tp_min.dst, TCA_FLOWER_KEY_PORT_DST_MIN,
1600*5c72299fSAmritha Nambiar 			    &mask->tp_min.dst, TCA_FLOWER_UNSPEC,
1601*5c72299fSAmritha Nambiar 			    sizeof(key->tp_min.dst)) ||
1602*5c72299fSAmritha Nambiar 	    fl_dump_key_val(skb, &key->tp_max.dst, TCA_FLOWER_KEY_PORT_DST_MAX,
1603*5c72299fSAmritha Nambiar 			    &mask->tp_max.dst, TCA_FLOWER_UNSPEC,
1604*5c72299fSAmritha Nambiar 			    sizeof(key->tp_max.dst)) ||
1605*5c72299fSAmritha Nambiar 	    fl_dump_key_val(skb, &key->tp_min.src, TCA_FLOWER_KEY_PORT_SRC_MIN,
1606*5c72299fSAmritha Nambiar 			    &mask->tp_min.src, TCA_FLOWER_UNSPEC,
1607*5c72299fSAmritha Nambiar 			    sizeof(key->tp_min.src)) ||
1608*5c72299fSAmritha Nambiar 	    fl_dump_key_val(skb, &key->tp_max.src, TCA_FLOWER_KEY_PORT_SRC_MAX,
1609*5c72299fSAmritha Nambiar 			    &mask->tp_max.src, TCA_FLOWER_UNSPEC,
1610*5c72299fSAmritha Nambiar 			    sizeof(key->tp_max.src)))
1611*5c72299fSAmritha Nambiar 		return -1;
1612*5c72299fSAmritha Nambiar 
1613*5c72299fSAmritha Nambiar 	return 0;
1614*5c72299fSAmritha Nambiar }
1615*5c72299fSAmritha Nambiar 
1616a577d8f7SBenjamin LaHaise static int fl_dump_key_mpls(struct sk_buff *skb,
1617a577d8f7SBenjamin LaHaise 			    struct flow_dissector_key_mpls *mpls_key,
1618a577d8f7SBenjamin LaHaise 			    struct flow_dissector_key_mpls *mpls_mask)
1619a577d8f7SBenjamin LaHaise {
1620a577d8f7SBenjamin LaHaise 	int err;
1621a577d8f7SBenjamin LaHaise 
1622a577d8f7SBenjamin LaHaise 	if (!memchr_inv(mpls_mask, 0, sizeof(*mpls_mask)))
1623a577d8f7SBenjamin LaHaise 		return 0;
1624a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_ttl) {
1625a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TTL,
1626a577d8f7SBenjamin LaHaise 				 mpls_key->mpls_ttl);
1627a577d8f7SBenjamin LaHaise 		if (err)
1628a577d8f7SBenjamin LaHaise 			return err;
1629a577d8f7SBenjamin LaHaise 	}
1630a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_tc) {
1631a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TC,
1632a577d8f7SBenjamin LaHaise 				 mpls_key->mpls_tc);
1633a577d8f7SBenjamin LaHaise 		if (err)
1634a577d8f7SBenjamin LaHaise 			return err;
1635a577d8f7SBenjamin LaHaise 	}
1636a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_label) {
1637a577d8f7SBenjamin LaHaise 		err = nla_put_u32(skb, TCA_FLOWER_KEY_MPLS_LABEL,
1638a577d8f7SBenjamin LaHaise 				  mpls_key->mpls_label);
1639a577d8f7SBenjamin LaHaise 		if (err)
1640a577d8f7SBenjamin LaHaise 			return err;
1641a577d8f7SBenjamin LaHaise 	}
1642a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_bos) {
1643a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_BOS,
1644a577d8f7SBenjamin LaHaise 				 mpls_key->mpls_bos);
1645a577d8f7SBenjamin LaHaise 		if (err)
1646a577d8f7SBenjamin LaHaise 			return err;
1647a577d8f7SBenjamin LaHaise 	}
1648a577d8f7SBenjamin LaHaise 	return 0;
1649a577d8f7SBenjamin LaHaise }
1650a577d8f7SBenjamin LaHaise 
16510e2c17b6SOr Gerlitz static int fl_dump_key_ip(struct sk_buff *skb, bool encap,
16524d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *key,
16534d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *mask)
16544d80cc0aSOr Gerlitz {
16550e2c17b6SOr Gerlitz 	int tos_key = encap ? TCA_FLOWER_KEY_ENC_IP_TOS : TCA_FLOWER_KEY_IP_TOS;
16560e2c17b6SOr Gerlitz 	int ttl_key = encap ? TCA_FLOWER_KEY_ENC_IP_TTL : TCA_FLOWER_KEY_IP_TTL;
16570e2c17b6SOr Gerlitz 	int tos_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TOS_MASK : TCA_FLOWER_KEY_IP_TOS_MASK;
16580e2c17b6SOr Gerlitz 	int ttl_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TTL_MASK : TCA_FLOWER_KEY_IP_TTL_MASK;
16590e2c17b6SOr Gerlitz 
16600e2c17b6SOr Gerlitz 	if (fl_dump_key_val(skb, &key->tos, tos_key, &mask->tos, tos_mask, sizeof(key->tos)) ||
16610e2c17b6SOr Gerlitz 	    fl_dump_key_val(skb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl)))
16624d80cc0aSOr Gerlitz 		return -1;
16634d80cc0aSOr Gerlitz 
16644d80cc0aSOr Gerlitz 	return 0;
16654d80cc0aSOr Gerlitz }
16664d80cc0aSOr Gerlitz 
16679399ae9aSHadar Hen Zion static int fl_dump_key_vlan(struct sk_buff *skb,
1668d64efd09SJianbo Liu 			    int vlan_id_key, int vlan_prio_key,
16699399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *vlan_key,
16709399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *vlan_mask)
16719399ae9aSHadar Hen Zion {
16729399ae9aSHadar Hen Zion 	int err;
16739399ae9aSHadar Hen Zion 
16749399ae9aSHadar Hen Zion 	if (!memchr_inv(vlan_mask, 0, sizeof(*vlan_mask)))
16759399ae9aSHadar Hen Zion 		return 0;
16769399ae9aSHadar Hen Zion 	if (vlan_mask->vlan_id) {
1677d64efd09SJianbo Liu 		err = nla_put_u16(skb, vlan_id_key,
16789399ae9aSHadar Hen Zion 				  vlan_key->vlan_id);
16799399ae9aSHadar Hen Zion 		if (err)
16809399ae9aSHadar Hen Zion 			return err;
16819399ae9aSHadar Hen Zion 	}
16829399ae9aSHadar Hen Zion 	if (vlan_mask->vlan_priority) {
1683d64efd09SJianbo Liu 		err = nla_put_u8(skb, vlan_prio_key,
16849399ae9aSHadar Hen Zion 				 vlan_key->vlan_priority);
16859399ae9aSHadar Hen Zion 		if (err)
16869399ae9aSHadar Hen Zion 			return err;
16879399ae9aSHadar Hen Zion 	}
16889399ae9aSHadar Hen Zion 	return 0;
16899399ae9aSHadar Hen Zion }
16909399ae9aSHadar Hen Zion 
1691faa3ffceSOr Gerlitz static void fl_get_key_flag(u32 dissector_key, u32 dissector_mask,
1692faa3ffceSOr Gerlitz 			    u32 *flower_key, u32 *flower_mask,
1693faa3ffceSOr Gerlitz 			    u32 flower_flag_bit, u32 dissector_flag_bit)
1694faa3ffceSOr Gerlitz {
1695faa3ffceSOr Gerlitz 	if (dissector_mask & dissector_flag_bit) {
1696faa3ffceSOr Gerlitz 		*flower_mask |= flower_flag_bit;
1697faa3ffceSOr Gerlitz 		if (dissector_key & dissector_flag_bit)
1698faa3ffceSOr Gerlitz 			*flower_key |= flower_flag_bit;
1699faa3ffceSOr Gerlitz 	}
1700faa3ffceSOr Gerlitz }
1701faa3ffceSOr Gerlitz 
1702faa3ffceSOr Gerlitz static int fl_dump_key_flags(struct sk_buff *skb, u32 flags_key, u32 flags_mask)
1703faa3ffceSOr Gerlitz {
1704faa3ffceSOr Gerlitz 	u32 key, mask;
1705faa3ffceSOr Gerlitz 	__be32 _key, _mask;
1706faa3ffceSOr Gerlitz 	int err;
1707faa3ffceSOr Gerlitz 
1708faa3ffceSOr Gerlitz 	if (!memchr_inv(&flags_mask, 0, sizeof(flags_mask)))
1709faa3ffceSOr Gerlitz 		return 0;
1710faa3ffceSOr Gerlitz 
1711faa3ffceSOr Gerlitz 	key = 0;
1712faa3ffceSOr Gerlitz 	mask = 0;
1713faa3ffceSOr Gerlitz 
1714faa3ffceSOr Gerlitz 	fl_get_key_flag(flags_key, flags_mask, &key, &mask,
1715faa3ffceSOr Gerlitz 			TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT);
1716459d153dSPieter Jansen van Vuuren 	fl_get_key_flag(flags_key, flags_mask, &key, &mask,
1717459d153dSPieter Jansen van Vuuren 			TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST,
1718459d153dSPieter Jansen van Vuuren 			FLOW_DIS_FIRST_FRAG);
1719faa3ffceSOr Gerlitz 
1720faa3ffceSOr Gerlitz 	_key = cpu_to_be32(key);
1721faa3ffceSOr Gerlitz 	_mask = cpu_to_be32(mask);
1722faa3ffceSOr Gerlitz 
1723faa3ffceSOr Gerlitz 	err = nla_put(skb, TCA_FLOWER_KEY_FLAGS, 4, &_key);
1724faa3ffceSOr Gerlitz 	if (err)
1725faa3ffceSOr Gerlitz 		return err;
1726faa3ffceSOr Gerlitz 
1727faa3ffceSOr Gerlitz 	return nla_put(skb, TCA_FLOWER_KEY_FLAGS_MASK, 4, &_mask);
1728faa3ffceSOr Gerlitz }
1729faa3ffceSOr Gerlitz 
17300a6e7778SPieter Jansen van Vuuren static int fl_dump_key_geneve_opt(struct sk_buff *skb,
17310a6e7778SPieter Jansen van Vuuren 				  struct flow_dissector_key_enc_opts *enc_opts)
17320a6e7778SPieter Jansen van Vuuren {
17330a6e7778SPieter Jansen van Vuuren 	struct geneve_opt *opt;
17340a6e7778SPieter Jansen van Vuuren 	struct nlattr *nest;
17350a6e7778SPieter Jansen van Vuuren 	int opt_off = 0;
17360a6e7778SPieter Jansen van Vuuren 
17370a6e7778SPieter Jansen van Vuuren 	nest = nla_nest_start(skb, TCA_FLOWER_KEY_ENC_OPTS_GENEVE);
17380a6e7778SPieter Jansen van Vuuren 	if (!nest)
17390a6e7778SPieter Jansen van Vuuren 		goto nla_put_failure;
17400a6e7778SPieter Jansen van Vuuren 
17410a6e7778SPieter Jansen van Vuuren 	while (enc_opts->len > opt_off) {
17420a6e7778SPieter Jansen van Vuuren 		opt = (struct geneve_opt *)&enc_opts->data[opt_off];
17430a6e7778SPieter Jansen van Vuuren 
17440a6e7778SPieter Jansen van Vuuren 		if (nla_put_be16(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS,
17450a6e7778SPieter Jansen van Vuuren 				 opt->opt_class))
17460a6e7778SPieter Jansen van Vuuren 			goto nla_put_failure;
17470a6e7778SPieter Jansen van Vuuren 		if (nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE,
17480a6e7778SPieter Jansen van Vuuren 			       opt->type))
17490a6e7778SPieter Jansen van Vuuren 			goto nla_put_failure;
17500a6e7778SPieter Jansen van Vuuren 		if (nla_put(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA,
17510a6e7778SPieter Jansen van Vuuren 			    opt->length * 4, opt->opt_data))
17520a6e7778SPieter Jansen van Vuuren 			goto nla_put_failure;
17530a6e7778SPieter Jansen van Vuuren 
17540a6e7778SPieter Jansen van Vuuren 		opt_off += sizeof(struct geneve_opt) + opt->length * 4;
17550a6e7778SPieter Jansen van Vuuren 	}
17560a6e7778SPieter Jansen van Vuuren 	nla_nest_end(skb, nest);
17570a6e7778SPieter Jansen van Vuuren 	return 0;
17580a6e7778SPieter Jansen van Vuuren 
17590a6e7778SPieter Jansen van Vuuren nla_put_failure:
17600a6e7778SPieter Jansen van Vuuren 	nla_nest_cancel(skb, nest);
17610a6e7778SPieter Jansen van Vuuren 	return -EMSGSIZE;
17620a6e7778SPieter Jansen van Vuuren }
17630a6e7778SPieter Jansen van Vuuren 
17640a6e7778SPieter Jansen van Vuuren static int fl_dump_key_options(struct sk_buff *skb, int enc_opt_type,
17650a6e7778SPieter Jansen van Vuuren 			       struct flow_dissector_key_enc_opts *enc_opts)
17660a6e7778SPieter Jansen van Vuuren {
17670a6e7778SPieter Jansen van Vuuren 	struct nlattr *nest;
17680a6e7778SPieter Jansen van Vuuren 	int err;
17690a6e7778SPieter Jansen van Vuuren 
17700a6e7778SPieter Jansen van Vuuren 	if (!enc_opts->len)
17710a6e7778SPieter Jansen van Vuuren 		return 0;
17720a6e7778SPieter Jansen van Vuuren 
17730a6e7778SPieter Jansen van Vuuren 	nest = nla_nest_start(skb, enc_opt_type);
17740a6e7778SPieter Jansen van Vuuren 	if (!nest)
17750a6e7778SPieter Jansen van Vuuren 		goto nla_put_failure;
17760a6e7778SPieter Jansen van Vuuren 
17770a6e7778SPieter Jansen van Vuuren 	switch (enc_opts->dst_opt_type) {
17780a6e7778SPieter Jansen van Vuuren 	case TUNNEL_GENEVE_OPT:
17790a6e7778SPieter Jansen van Vuuren 		err = fl_dump_key_geneve_opt(skb, enc_opts);
17800a6e7778SPieter Jansen van Vuuren 		if (err)
17810a6e7778SPieter Jansen van Vuuren 			goto nla_put_failure;
17820a6e7778SPieter Jansen van Vuuren 		break;
17830a6e7778SPieter Jansen van Vuuren 	default:
17840a6e7778SPieter Jansen van Vuuren 		goto nla_put_failure;
17850a6e7778SPieter Jansen van Vuuren 	}
17860a6e7778SPieter Jansen van Vuuren 	nla_nest_end(skb, nest);
17870a6e7778SPieter Jansen van Vuuren 	return 0;
17880a6e7778SPieter Jansen van Vuuren 
17890a6e7778SPieter Jansen van Vuuren nla_put_failure:
17900a6e7778SPieter Jansen van Vuuren 	nla_nest_cancel(skb, nest);
17910a6e7778SPieter Jansen van Vuuren 	return -EMSGSIZE;
17920a6e7778SPieter Jansen van Vuuren }
17930a6e7778SPieter Jansen van Vuuren 
17940a6e7778SPieter Jansen van Vuuren static int fl_dump_key_enc_opt(struct sk_buff *skb,
17950a6e7778SPieter Jansen van Vuuren 			       struct flow_dissector_key_enc_opts *key_opts,
17960a6e7778SPieter Jansen van Vuuren 			       struct flow_dissector_key_enc_opts *msk_opts)
17970a6e7778SPieter Jansen van Vuuren {
17980a6e7778SPieter Jansen van Vuuren 	int err;
17990a6e7778SPieter Jansen van Vuuren 
18000a6e7778SPieter Jansen van Vuuren 	err = fl_dump_key_options(skb, TCA_FLOWER_KEY_ENC_OPTS, key_opts);
18010a6e7778SPieter Jansen van Vuuren 	if (err)
18020a6e7778SPieter Jansen van Vuuren 		return err;
18030a6e7778SPieter Jansen van Vuuren 
18040a6e7778SPieter Jansen van Vuuren 	return fl_dump_key_options(skb, TCA_FLOWER_KEY_ENC_OPTS_MASK, msk_opts);
18050a6e7778SPieter Jansen van Vuuren }
18060a6e7778SPieter Jansen van Vuuren 
1807f5749081SJiri Pirko static int fl_dump_key(struct sk_buff *skb, struct net *net,
1808f5749081SJiri Pirko 		       struct fl_flow_key *key, struct fl_flow_key *mask)
180977b9900eSJiri Pirko {
181077b9900eSJiri Pirko 	if (mask->indev_ifindex) {
181177b9900eSJiri Pirko 		struct net_device *dev;
181277b9900eSJiri Pirko 
181377b9900eSJiri Pirko 		dev = __dev_get_by_index(net, key->indev_ifindex);
181477b9900eSJiri Pirko 		if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name))
181577b9900eSJiri Pirko 			goto nla_put_failure;
181677b9900eSJiri Pirko 	}
181777b9900eSJiri Pirko 
181877b9900eSJiri Pirko 	if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
181977b9900eSJiri Pirko 			    mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
182077b9900eSJiri Pirko 			    sizeof(key->eth.dst)) ||
182177b9900eSJiri Pirko 	    fl_dump_key_val(skb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
182277b9900eSJiri Pirko 			    mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
182377b9900eSJiri Pirko 			    sizeof(key->eth.src)) ||
182477b9900eSJiri Pirko 	    fl_dump_key_val(skb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE,
182577b9900eSJiri Pirko 			    &mask->basic.n_proto, TCA_FLOWER_UNSPEC,
182677b9900eSJiri Pirko 			    sizeof(key->basic.n_proto)))
182777b9900eSJiri Pirko 		goto nla_put_failure;
18289399ae9aSHadar Hen Zion 
1829a577d8f7SBenjamin LaHaise 	if (fl_dump_key_mpls(skb, &key->mpls, &mask->mpls))
1830a577d8f7SBenjamin LaHaise 		goto nla_put_failure;
1831a577d8f7SBenjamin LaHaise 
1832d64efd09SJianbo Liu 	if (fl_dump_key_vlan(skb, TCA_FLOWER_KEY_VLAN_ID,
1833d64efd09SJianbo Liu 			     TCA_FLOWER_KEY_VLAN_PRIO, &key->vlan, &mask->vlan))
18349399ae9aSHadar Hen Zion 		goto nla_put_failure;
18359399ae9aSHadar Hen Zion 
1836d64efd09SJianbo Liu 	if (fl_dump_key_vlan(skb, TCA_FLOWER_KEY_CVLAN_ID,
1837d64efd09SJianbo Liu 			     TCA_FLOWER_KEY_CVLAN_PRIO,
1838d64efd09SJianbo Liu 			     &key->cvlan, &mask->cvlan) ||
1839d64efd09SJianbo Liu 	    (mask->cvlan.vlan_tpid &&
1840158abbf1SJianbo Liu 	     nla_put_be16(skb, TCA_FLOWER_KEY_VLAN_ETH_TYPE,
1841d64efd09SJianbo Liu 			  key->cvlan.vlan_tpid)))
1842d3069512SJianbo Liu 		goto nla_put_failure;
1843d3069512SJianbo Liu 
18445e9a0fe4SJianbo Liu 	if (mask->basic.n_proto) {
1845d64efd09SJianbo Liu 		if (mask->cvlan.vlan_tpid) {
1846d64efd09SJianbo Liu 			if (nla_put_be16(skb, TCA_FLOWER_KEY_CVLAN_ETH_TYPE,
1847d64efd09SJianbo Liu 					 key->basic.n_proto))
1848d64efd09SJianbo Liu 				goto nla_put_failure;
1849d64efd09SJianbo Liu 		} else if (mask->vlan.vlan_tpid) {
1850d64efd09SJianbo Liu 			if (nla_put_be16(skb, TCA_FLOWER_KEY_VLAN_ETH_TYPE,
1851d64efd09SJianbo Liu 					 key->basic.n_proto))
1852d64efd09SJianbo Liu 				goto nla_put_failure;
1853d64efd09SJianbo Liu 		}
18545e9a0fe4SJianbo Liu 	}
1855d64efd09SJianbo Liu 
185677b9900eSJiri Pirko 	if ((key->basic.n_proto == htons(ETH_P_IP) ||
185777b9900eSJiri Pirko 	     key->basic.n_proto == htons(ETH_P_IPV6)) &&
18584d80cc0aSOr Gerlitz 	    (fl_dump_key_val(skb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
185977b9900eSJiri Pirko 			    &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
18604d80cc0aSOr Gerlitz 			    sizeof(key->basic.ip_proto)) ||
18610e2c17b6SOr Gerlitz 	    fl_dump_key_ip(skb, false, &key->ip, &mask->ip)))
186277b9900eSJiri Pirko 		goto nla_put_failure;
186377b9900eSJiri Pirko 
1864c3f83241STom Herbert 	if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
186577b9900eSJiri Pirko 	    (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
186677b9900eSJiri Pirko 			     &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
186777b9900eSJiri Pirko 			     sizeof(key->ipv4.src)) ||
186877b9900eSJiri Pirko 	     fl_dump_key_val(skb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
186977b9900eSJiri Pirko 			     &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
187077b9900eSJiri Pirko 			     sizeof(key->ipv4.dst))))
187177b9900eSJiri Pirko 		goto nla_put_failure;
1872c3f83241STom Herbert 	else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
187377b9900eSJiri Pirko 		 (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
187477b9900eSJiri Pirko 				  &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
187577b9900eSJiri Pirko 				  sizeof(key->ipv6.src)) ||
187677b9900eSJiri Pirko 		  fl_dump_key_val(skb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
187777b9900eSJiri Pirko 				  &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
187877b9900eSJiri Pirko 				  sizeof(key->ipv6.dst))))
187977b9900eSJiri Pirko 		goto nla_put_failure;
188077b9900eSJiri Pirko 
188177b9900eSJiri Pirko 	if (key->basic.ip_proto == IPPROTO_TCP &&
188277b9900eSJiri Pirko 	    (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
1883aa72d708SOr Gerlitz 			     &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
188477b9900eSJiri Pirko 			     sizeof(key->tp.src)) ||
188577b9900eSJiri Pirko 	     fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
1886aa72d708SOr Gerlitz 			     &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
1887fdfc7dd6SJiri Pirko 			     sizeof(key->tp.dst)) ||
1888fdfc7dd6SJiri Pirko 	     fl_dump_key_val(skb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS,
1889fdfc7dd6SJiri Pirko 			     &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK,
1890fdfc7dd6SJiri Pirko 			     sizeof(key->tcp.flags))))
189177b9900eSJiri Pirko 		goto nla_put_failure;
189277b9900eSJiri Pirko 	else if (key->basic.ip_proto == IPPROTO_UDP &&
189377b9900eSJiri Pirko 		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
1894aa72d708SOr Gerlitz 				  &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
189577b9900eSJiri Pirko 				  sizeof(key->tp.src)) ||
189677b9900eSJiri Pirko 		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
1897aa72d708SOr Gerlitz 				  &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
189877b9900eSJiri Pirko 				  sizeof(key->tp.dst))))
189977b9900eSJiri Pirko 		goto nla_put_failure;
19005976c5f4SSimon Horman 	else if (key->basic.ip_proto == IPPROTO_SCTP &&
19015976c5f4SSimon Horman 		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
19025976c5f4SSimon Horman 				  &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
19035976c5f4SSimon Horman 				  sizeof(key->tp.src)) ||
19045976c5f4SSimon Horman 		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
19055976c5f4SSimon Horman 				  &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
19065976c5f4SSimon Horman 				  sizeof(key->tp.dst))))
19075976c5f4SSimon Horman 		goto nla_put_failure;
19087b684884SSimon Horman 	else if (key->basic.n_proto == htons(ETH_P_IP) &&
19097b684884SSimon Horman 		 key->basic.ip_proto == IPPROTO_ICMP &&
19107b684884SSimon Horman 		 (fl_dump_key_val(skb, &key->icmp.type,
19117b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_TYPE, &mask->icmp.type,
19127b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,
19137b684884SSimon Horman 				  sizeof(key->icmp.type)) ||
19147b684884SSimon Horman 		  fl_dump_key_val(skb, &key->icmp.code,
19157b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_CODE, &mask->icmp.code,
19167b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
19177b684884SSimon Horman 				  sizeof(key->icmp.code))))
19187b684884SSimon Horman 		goto nla_put_failure;
19197b684884SSimon Horman 	else if (key->basic.n_proto == htons(ETH_P_IPV6) &&
19207b684884SSimon Horman 		 key->basic.ip_proto == IPPROTO_ICMPV6 &&
19217b684884SSimon Horman 		 (fl_dump_key_val(skb, &key->icmp.type,
19227b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_TYPE, &mask->icmp.type,
19237b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
19247b684884SSimon Horman 				  sizeof(key->icmp.type)) ||
19257b684884SSimon Horman 		  fl_dump_key_val(skb, &key->icmp.code,
19267b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_CODE, &mask->icmp.code,
19277b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_CODE_MASK,
19287b684884SSimon Horman 				  sizeof(key->icmp.code))))
19297b684884SSimon Horman 		goto nla_put_failure;
193099d31326SSimon Horman 	else if ((key->basic.n_proto == htons(ETH_P_ARP) ||
193199d31326SSimon Horman 		  key->basic.n_proto == htons(ETH_P_RARP)) &&
193299d31326SSimon Horman 		 (fl_dump_key_val(skb, &key->arp.sip,
193399d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_SIP, &mask->arp.sip,
193499d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_SIP_MASK,
193599d31326SSimon Horman 				  sizeof(key->arp.sip)) ||
193699d31326SSimon Horman 		  fl_dump_key_val(skb, &key->arp.tip,
193799d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_TIP, &mask->arp.tip,
193899d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_TIP_MASK,
193999d31326SSimon Horman 				  sizeof(key->arp.tip)) ||
194099d31326SSimon Horman 		  fl_dump_key_val(skb, &key->arp.op,
194199d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_OP, &mask->arp.op,
194299d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_OP_MASK,
194399d31326SSimon Horman 				  sizeof(key->arp.op)) ||
194499d31326SSimon Horman 		  fl_dump_key_val(skb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA,
194599d31326SSimon Horman 				  mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK,
194699d31326SSimon Horman 				  sizeof(key->arp.sha)) ||
194799d31326SSimon Horman 		  fl_dump_key_val(skb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA,
194899d31326SSimon Horman 				  mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK,
194999d31326SSimon Horman 				  sizeof(key->arp.tha))))
195099d31326SSimon Horman 		goto nla_put_failure;
195177b9900eSJiri Pirko 
1952*5c72299fSAmritha Nambiar 	if ((key->basic.ip_proto == IPPROTO_TCP ||
1953*5c72299fSAmritha Nambiar 	     key->basic.ip_proto == IPPROTO_UDP ||
1954*5c72299fSAmritha Nambiar 	     key->basic.ip_proto == IPPROTO_SCTP) &&
1955*5c72299fSAmritha Nambiar 	     fl_dump_key_port_range(skb, key, mask))
1956*5c72299fSAmritha Nambiar 		goto nla_put_failure;
1957*5c72299fSAmritha Nambiar 
1958bc3103f1SAmir Vadai 	if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
1959bc3103f1SAmir Vadai 	    (fl_dump_key_val(skb, &key->enc_ipv4.src,
1960bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV4_SRC, &mask->enc_ipv4.src,
1961bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
1962bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv4.src)) ||
1963bc3103f1SAmir Vadai 	     fl_dump_key_val(skb, &key->enc_ipv4.dst,
1964bc3103f1SAmir Vadai 			     TCA_FLOWER_KEY_ENC_IPV4_DST, &mask->enc_ipv4.dst,
1965bc3103f1SAmir Vadai 			     TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
1966bc3103f1SAmir Vadai 			     sizeof(key->enc_ipv4.dst))))
1967bc3103f1SAmir Vadai 		goto nla_put_failure;
1968bc3103f1SAmir Vadai 	else if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
1969bc3103f1SAmir Vadai 		 (fl_dump_key_val(skb, &key->enc_ipv6.src,
1970bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV6_SRC, &mask->enc_ipv6.src,
1971bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
1972bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv6.src)) ||
1973bc3103f1SAmir Vadai 		 fl_dump_key_val(skb, &key->enc_ipv6.dst,
1974bc3103f1SAmir Vadai 				 TCA_FLOWER_KEY_ENC_IPV6_DST,
1975bc3103f1SAmir Vadai 				 &mask->enc_ipv6.dst,
1976bc3103f1SAmir Vadai 				 TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
1977bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv6.dst))))
1978bc3103f1SAmir Vadai 		goto nla_put_failure;
1979bc3103f1SAmir Vadai 
1980bc3103f1SAmir Vadai 	if (fl_dump_key_val(skb, &key->enc_key_id, TCA_FLOWER_KEY_ENC_KEY_ID,
1981eb523f42SHadar Hen Zion 			    &mask->enc_key_id, TCA_FLOWER_UNSPEC,
1982f4d997fdSHadar Hen Zion 			    sizeof(key->enc_key_id)) ||
1983f4d997fdSHadar Hen Zion 	    fl_dump_key_val(skb, &key->enc_tp.src,
1984f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
1985f4d997fdSHadar Hen Zion 			    &mask->enc_tp.src,
1986f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
1987f4d997fdSHadar Hen Zion 			    sizeof(key->enc_tp.src)) ||
1988f4d997fdSHadar Hen Zion 	    fl_dump_key_val(skb, &key->enc_tp.dst,
1989f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
1990f4d997fdSHadar Hen Zion 			    &mask->enc_tp.dst,
1991f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
19920e2c17b6SOr Gerlitz 			    sizeof(key->enc_tp.dst)) ||
19930a6e7778SPieter Jansen van Vuuren 	    fl_dump_key_ip(skb, true, &key->enc_ip, &mask->enc_ip) ||
19940a6e7778SPieter Jansen van Vuuren 	    fl_dump_key_enc_opt(skb, &key->enc_opts, &mask->enc_opts))
1995bc3103f1SAmir Vadai 		goto nla_put_failure;
1996bc3103f1SAmir Vadai 
1997faa3ffceSOr Gerlitz 	if (fl_dump_key_flags(skb, key->control.flags, mask->control.flags))
1998faa3ffceSOr Gerlitz 		goto nla_put_failure;
1999faa3ffceSOr Gerlitz 
2000f5749081SJiri Pirko 	return 0;
2001f5749081SJiri Pirko 
2002f5749081SJiri Pirko nla_put_failure:
2003f5749081SJiri Pirko 	return -EMSGSIZE;
2004f5749081SJiri Pirko }
2005f5749081SJiri Pirko 
2006f5749081SJiri Pirko static int fl_dump(struct net *net, struct tcf_proto *tp, void *fh,
2007f5749081SJiri Pirko 		   struct sk_buff *skb, struct tcmsg *t)
2008f5749081SJiri Pirko {
2009f5749081SJiri Pirko 	struct cls_fl_filter *f = fh;
2010f5749081SJiri Pirko 	struct nlattr *nest;
2011f5749081SJiri Pirko 	struct fl_flow_key *key, *mask;
2012f5749081SJiri Pirko 
2013f5749081SJiri Pirko 	if (!f)
2014f5749081SJiri Pirko 		return skb->len;
2015f5749081SJiri Pirko 
2016f5749081SJiri Pirko 	t->tcm_handle = f->handle;
2017f5749081SJiri Pirko 
2018f5749081SJiri Pirko 	nest = nla_nest_start(skb, TCA_OPTIONS);
2019f5749081SJiri Pirko 	if (!nest)
2020f5749081SJiri Pirko 		goto nla_put_failure;
2021f5749081SJiri Pirko 
2022f5749081SJiri Pirko 	if (f->res.classid &&
2023f5749081SJiri Pirko 	    nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid))
2024f5749081SJiri Pirko 		goto nla_put_failure;
2025f5749081SJiri Pirko 
2026f5749081SJiri Pirko 	key = &f->key;
2027f5749081SJiri Pirko 	mask = &f->mask->key;
2028f5749081SJiri Pirko 
2029f5749081SJiri Pirko 	if (fl_dump_key(skb, net, key, mask))
2030f5749081SJiri Pirko 		goto nla_put_failure;
2031f5749081SJiri Pirko 
2032f5749081SJiri Pirko 	if (!tc_skip_hw(f->flags))
2033f5749081SJiri Pirko 		fl_hw_update_stats(tp, f);
2034f5749081SJiri Pirko 
2035749e6720SOr Gerlitz 	if (f->flags && nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags))
2036749e6720SOr Gerlitz 		goto nla_put_failure;
2037e69985c6SAmir Vadai 
203886c55361SVlad Buslov 	if (nla_put_u32(skb, TCA_FLOWER_IN_HW_COUNT, f->in_hw_count))
203986c55361SVlad Buslov 		goto nla_put_failure;
204086c55361SVlad Buslov 
204177b9900eSJiri Pirko 	if (tcf_exts_dump(skb, &f->exts))
204277b9900eSJiri Pirko 		goto nla_put_failure;
204377b9900eSJiri Pirko 
204477b9900eSJiri Pirko 	nla_nest_end(skb, nest);
204577b9900eSJiri Pirko 
204677b9900eSJiri Pirko 	if (tcf_exts_dump_stats(skb, &f->exts) < 0)
204777b9900eSJiri Pirko 		goto nla_put_failure;
204877b9900eSJiri Pirko 
204977b9900eSJiri Pirko 	return skb->len;
205077b9900eSJiri Pirko 
205177b9900eSJiri Pirko nla_put_failure:
205277b9900eSJiri Pirko 	nla_nest_cancel(skb, nest);
205377b9900eSJiri Pirko 	return -1;
205477b9900eSJiri Pirko }
205577b9900eSJiri Pirko 
2056b95ec7ebSJiri Pirko static int fl_tmplt_dump(struct sk_buff *skb, struct net *net, void *tmplt_priv)
2057b95ec7ebSJiri Pirko {
2058b95ec7ebSJiri Pirko 	struct fl_flow_tmplt *tmplt = tmplt_priv;
2059b95ec7ebSJiri Pirko 	struct fl_flow_key *key, *mask;
2060b95ec7ebSJiri Pirko 	struct nlattr *nest;
2061b95ec7ebSJiri Pirko 
2062b95ec7ebSJiri Pirko 	nest = nla_nest_start(skb, TCA_OPTIONS);
2063b95ec7ebSJiri Pirko 	if (!nest)
2064b95ec7ebSJiri Pirko 		goto nla_put_failure;
2065b95ec7ebSJiri Pirko 
2066b95ec7ebSJiri Pirko 	key = &tmplt->dummy_key;
2067b95ec7ebSJiri Pirko 	mask = &tmplt->mask;
2068b95ec7ebSJiri Pirko 
2069b95ec7ebSJiri Pirko 	if (fl_dump_key(skb, net, key, mask))
2070b95ec7ebSJiri Pirko 		goto nla_put_failure;
2071b95ec7ebSJiri Pirko 
2072b95ec7ebSJiri Pirko 	nla_nest_end(skb, nest);
2073b95ec7ebSJiri Pirko 
2074b95ec7ebSJiri Pirko 	return skb->len;
2075b95ec7ebSJiri Pirko 
2076b95ec7ebSJiri Pirko nla_put_failure:
2077b95ec7ebSJiri Pirko 	nla_nest_cancel(skb, nest);
2078b95ec7ebSJiri Pirko 	return -EMSGSIZE;
2079b95ec7ebSJiri Pirko }
2080b95ec7ebSJiri Pirko 
208107d79fc7SCong Wang static void fl_bind_class(void *fh, u32 classid, unsigned long cl)
208207d79fc7SCong Wang {
208307d79fc7SCong Wang 	struct cls_fl_filter *f = fh;
208407d79fc7SCong Wang 
208507d79fc7SCong Wang 	if (f && f->res.classid == classid)
208607d79fc7SCong Wang 		f->res.class = cl;
208707d79fc7SCong Wang }
208807d79fc7SCong Wang 
208977b9900eSJiri Pirko static struct tcf_proto_ops cls_fl_ops __read_mostly = {
209077b9900eSJiri Pirko 	.kind		= "flower",
209177b9900eSJiri Pirko 	.classify	= fl_classify,
209277b9900eSJiri Pirko 	.init		= fl_init,
209377b9900eSJiri Pirko 	.destroy	= fl_destroy,
209477b9900eSJiri Pirko 	.get		= fl_get,
209577b9900eSJiri Pirko 	.change		= fl_change,
209677b9900eSJiri Pirko 	.delete		= fl_delete,
209777b9900eSJiri Pirko 	.walk		= fl_walk,
209831533cbaSJohn Hurley 	.reoffload	= fl_reoffload,
209977b9900eSJiri Pirko 	.dump		= fl_dump,
210007d79fc7SCong Wang 	.bind_class	= fl_bind_class,
2101b95ec7ebSJiri Pirko 	.tmplt_create	= fl_tmplt_create,
2102b95ec7ebSJiri Pirko 	.tmplt_destroy	= fl_tmplt_destroy,
2103b95ec7ebSJiri Pirko 	.tmplt_dump	= fl_tmplt_dump,
210477b9900eSJiri Pirko 	.owner		= THIS_MODULE,
210577b9900eSJiri Pirko };
210677b9900eSJiri Pirko 
210777b9900eSJiri Pirko static int __init cls_fl_init(void)
210877b9900eSJiri Pirko {
210977b9900eSJiri Pirko 	return register_tcf_proto_ops(&cls_fl_ops);
211077b9900eSJiri Pirko }
211177b9900eSJiri Pirko 
211277b9900eSJiri Pirko static void __exit cls_fl_exit(void)
211377b9900eSJiri Pirko {
211477b9900eSJiri Pirko 	unregister_tcf_proto_ops(&cls_fl_ops);
211577b9900eSJiri Pirko }
211677b9900eSJiri Pirko 
211777b9900eSJiri Pirko module_init(cls_fl_init);
211877b9900eSJiri Pirko module_exit(cls_fl_exit);
211977b9900eSJiri Pirko 
212077b9900eSJiri Pirko MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>");
212177b9900eSJiri Pirko MODULE_DESCRIPTION("Flower classifier");
212277b9900eSJiri Pirko MODULE_LICENSE("GPL v2");
2123