xref: /linux/net/sched/cls_flower.c (revision 1cbc36a53b60d43daa686280385b1ddbe51d5809)
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>
2777b9900eSJiri Pirko 
28bc3103f1SAmir Vadai #include <net/dst.h>
29bc3103f1SAmir Vadai #include <net/dst_metadata.h>
30bc3103f1SAmir Vadai 
3177b9900eSJiri Pirko struct fl_flow_key {
3277b9900eSJiri Pirko 	int	indev_ifindex;
3342aecaa9STom Herbert 	struct flow_dissector_key_control control;
34bc3103f1SAmir Vadai 	struct flow_dissector_key_control enc_control;
3577b9900eSJiri Pirko 	struct flow_dissector_key_basic basic;
3677b9900eSJiri Pirko 	struct flow_dissector_key_eth_addrs eth;
379399ae9aSHadar Hen Zion 	struct flow_dissector_key_vlan vlan;
38d64efd09SJianbo Liu 	struct flow_dissector_key_vlan cvlan;
3977b9900eSJiri Pirko 	union {
40c3f83241STom Herbert 		struct flow_dissector_key_ipv4_addrs ipv4;
4177b9900eSJiri Pirko 		struct flow_dissector_key_ipv6_addrs ipv6;
4277b9900eSJiri Pirko 	};
4377b9900eSJiri Pirko 	struct flow_dissector_key_ports tp;
447b684884SSimon Horman 	struct flow_dissector_key_icmp icmp;
4599d31326SSimon Horman 	struct flow_dissector_key_arp arp;
46bc3103f1SAmir Vadai 	struct flow_dissector_key_keyid enc_key_id;
47bc3103f1SAmir Vadai 	union {
48bc3103f1SAmir Vadai 		struct flow_dissector_key_ipv4_addrs enc_ipv4;
49bc3103f1SAmir Vadai 		struct flow_dissector_key_ipv6_addrs enc_ipv6;
50bc3103f1SAmir Vadai 	};
51f4d997fdSHadar Hen Zion 	struct flow_dissector_key_ports enc_tp;
52a577d8f7SBenjamin LaHaise 	struct flow_dissector_key_mpls mpls;
53fdfc7dd6SJiri Pirko 	struct flow_dissector_key_tcp tcp;
544d80cc0aSOr Gerlitz 	struct flow_dissector_key_ip ip;
550e2c17b6SOr Gerlitz 	struct flow_dissector_key_ip enc_ip;
5677b9900eSJiri Pirko } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
5777b9900eSJiri Pirko 
5877b9900eSJiri Pirko struct fl_flow_mask_range {
5977b9900eSJiri Pirko 	unsigned short int start;
6077b9900eSJiri Pirko 	unsigned short int end;
6177b9900eSJiri Pirko };
6277b9900eSJiri Pirko 
6377b9900eSJiri Pirko struct fl_flow_mask {
6477b9900eSJiri Pirko 	struct fl_flow_key key;
6577b9900eSJiri Pirko 	struct fl_flow_mask_range range;
6605cd271fSPaul Blakey 	struct rhash_head ht_node;
6705cd271fSPaul Blakey 	struct rhashtable ht;
6805cd271fSPaul Blakey 	struct rhashtable_params filter_ht_params;
6905cd271fSPaul Blakey 	struct flow_dissector dissector;
7005cd271fSPaul Blakey 	struct list_head filters;
7144a5cd43SPaolo Abeni 	struct rcu_work rwork;
7205cd271fSPaul Blakey 	struct list_head list;
7377b9900eSJiri Pirko };
7477b9900eSJiri Pirko 
75b95ec7ebSJiri Pirko struct fl_flow_tmplt {
76b95ec7ebSJiri Pirko 	struct fl_flow_key dummy_key;
77b95ec7ebSJiri Pirko 	struct fl_flow_key mask;
78b95ec7ebSJiri Pirko 	struct flow_dissector dissector;
79b95ec7ebSJiri Pirko 	struct tcf_chain *chain;
80b95ec7ebSJiri Pirko };
81b95ec7ebSJiri Pirko 
8277b9900eSJiri Pirko struct cls_fl_head {
8377b9900eSJiri Pirko 	struct rhashtable ht;
8405cd271fSPaul Blakey 	struct list_head masks;
85aaa908ffSCong Wang 	struct rcu_work rwork;
86c15ab236SChris Mi 	struct idr handle_idr;
87d9363774SDaniel Borkmann };
8877b9900eSJiri Pirko 
8977b9900eSJiri Pirko struct cls_fl_filter {
9005cd271fSPaul Blakey 	struct fl_flow_mask *mask;
9177b9900eSJiri Pirko 	struct rhash_head ht_node;
9277b9900eSJiri Pirko 	struct fl_flow_key mkey;
9377b9900eSJiri Pirko 	struct tcf_exts exts;
9477b9900eSJiri Pirko 	struct tcf_result res;
9577b9900eSJiri Pirko 	struct fl_flow_key key;
9677b9900eSJiri Pirko 	struct list_head list;
9777b9900eSJiri Pirko 	u32 handle;
98e69985c6SAmir Vadai 	u32 flags;
9931533cbaSJohn Hurley 	unsigned int in_hw_count;
100aaa908ffSCong Wang 	struct rcu_work rwork;
1017091d8c7SHadar Hen Zion 	struct net_device *hw_dev;
10277b9900eSJiri Pirko };
10377b9900eSJiri Pirko 
10405cd271fSPaul Blakey static const struct rhashtable_params mask_ht_params = {
10505cd271fSPaul Blakey 	.key_offset = offsetof(struct fl_flow_mask, key),
10605cd271fSPaul Blakey 	.key_len = sizeof(struct fl_flow_key),
10705cd271fSPaul Blakey 	.head_offset = offsetof(struct fl_flow_mask, ht_node),
10805cd271fSPaul Blakey 	.automatic_shrinking = true,
10905cd271fSPaul Blakey };
11005cd271fSPaul Blakey 
11177b9900eSJiri Pirko static unsigned short int fl_mask_range(const struct fl_flow_mask *mask)
11277b9900eSJiri Pirko {
11377b9900eSJiri Pirko 	return mask->range.end - mask->range.start;
11477b9900eSJiri Pirko }
11577b9900eSJiri Pirko 
11677b9900eSJiri Pirko static void fl_mask_update_range(struct fl_flow_mask *mask)
11777b9900eSJiri Pirko {
11877b9900eSJiri Pirko 	const u8 *bytes = (const u8 *) &mask->key;
11977b9900eSJiri Pirko 	size_t size = sizeof(mask->key);
12005cd271fSPaul Blakey 	size_t i, first = 0, last;
12177b9900eSJiri Pirko 
12205cd271fSPaul Blakey 	for (i = 0; i < size; i++) {
12377b9900eSJiri Pirko 		if (bytes[i]) {
12477b9900eSJiri Pirko 			first = i;
12505cd271fSPaul Blakey 			break;
12605cd271fSPaul Blakey 		}
12705cd271fSPaul Blakey 	}
12805cd271fSPaul Blakey 	last = first;
12905cd271fSPaul Blakey 	for (i = size - 1; i != first; i--) {
13005cd271fSPaul Blakey 		if (bytes[i]) {
13177b9900eSJiri Pirko 			last = i;
13205cd271fSPaul Blakey 			break;
13377b9900eSJiri Pirko 		}
13477b9900eSJiri Pirko 	}
13577b9900eSJiri Pirko 	mask->range.start = rounddown(first, sizeof(long));
13677b9900eSJiri Pirko 	mask->range.end = roundup(last + 1, sizeof(long));
13777b9900eSJiri Pirko }
13877b9900eSJiri Pirko 
13977b9900eSJiri Pirko static void *fl_key_get_start(struct fl_flow_key *key,
14077b9900eSJiri Pirko 			      const struct fl_flow_mask *mask)
14177b9900eSJiri Pirko {
14277b9900eSJiri Pirko 	return (u8 *) key + mask->range.start;
14377b9900eSJiri Pirko }
14477b9900eSJiri Pirko 
14577b9900eSJiri Pirko static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key,
14677b9900eSJiri Pirko 			      struct fl_flow_mask *mask)
14777b9900eSJiri Pirko {
14877b9900eSJiri Pirko 	const long *lkey = fl_key_get_start(key, mask);
14977b9900eSJiri Pirko 	const long *lmask = fl_key_get_start(&mask->key, mask);
15077b9900eSJiri Pirko 	long *lmkey = fl_key_get_start(mkey, mask);
15177b9900eSJiri Pirko 	int i;
15277b9900eSJiri Pirko 
15377b9900eSJiri Pirko 	for (i = 0; i < fl_mask_range(mask); i += sizeof(long))
15477b9900eSJiri Pirko 		*lmkey++ = *lkey++ & *lmask++;
15577b9900eSJiri Pirko }
15677b9900eSJiri Pirko 
157b95ec7ebSJiri Pirko static bool fl_mask_fits_tmplt(struct fl_flow_tmplt *tmplt,
158b95ec7ebSJiri Pirko 			       struct fl_flow_mask *mask)
159b95ec7ebSJiri Pirko {
160b95ec7ebSJiri Pirko 	const long *lmask = fl_key_get_start(&mask->key, mask);
161b95ec7ebSJiri Pirko 	const long *ltmplt;
162b95ec7ebSJiri Pirko 	int i;
163b95ec7ebSJiri Pirko 
164b95ec7ebSJiri Pirko 	if (!tmplt)
165b95ec7ebSJiri Pirko 		return true;
166b95ec7ebSJiri Pirko 	ltmplt = fl_key_get_start(&tmplt->mask, mask);
167b95ec7ebSJiri Pirko 	for (i = 0; i < fl_mask_range(mask); i += sizeof(long)) {
168b95ec7ebSJiri Pirko 		if (~*ltmplt++ & *lmask++)
169b95ec7ebSJiri Pirko 			return false;
170b95ec7ebSJiri Pirko 	}
171b95ec7ebSJiri Pirko 	return true;
172b95ec7ebSJiri Pirko }
173b95ec7ebSJiri Pirko 
17477b9900eSJiri Pirko static void fl_clear_masked_range(struct fl_flow_key *key,
17577b9900eSJiri Pirko 				  struct fl_flow_mask *mask)
17677b9900eSJiri Pirko {
17777b9900eSJiri Pirko 	memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask));
17877b9900eSJiri Pirko }
17977b9900eSJiri Pirko 
18005cd271fSPaul Blakey static struct cls_fl_filter *fl_lookup(struct fl_flow_mask *mask,
181a3308d8fSPaul Blakey 				       struct fl_flow_key *mkey)
182a3308d8fSPaul Blakey {
18305cd271fSPaul Blakey 	return rhashtable_lookup_fast(&mask->ht, fl_key_get_start(mkey, mask),
18405cd271fSPaul Blakey 				      mask->filter_ht_params);
185a3308d8fSPaul Blakey }
186a3308d8fSPaul Blakey 
18777b9900eSJiri Pirko static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp,
18877b9900eSJiri Pirko 		       struct tcf_result *res)
18977b9900eSJiri Pirko {
19077b9900eSJiri Pirko 	struct cls_fl_head *head = rcu_dereference_bh(tp->root);
19177b9900eSJiri Pirko 	struct cls_fl_filter *f;
19205cd271fSPaul Blakey 	struct fl_flow_mask *mask;
19377b9900eSJiri Pirko 	struct fl_flow_key skb_key;
19477b9900eSJiri Pirko 	struct fl_flow_key skb_mkey;
19577b9900eSJiri Pirko 
19605cd271fSPaul Blakey 	list_for_each_entry_rcu(mask, &head->masks, list) {
19705cd271fSPaul Blakey 		fl_clear_masked_range(&skb_key, mask);
198bc3103f1SAmir Vadai 
19977b9900eSJiri Pirko 		skb_key.indev_ifindex = skb->skb_iif;
20005cd271fSPaul Blakey 		/* skb_flow_dissect() does not set n_proto in case an unknown
20105cd271fSPaul Blakey 		 * protocol, so do it rather here.
20277b9900eSJiri Pirko 		 */
20377b9900eSJiri Pirko 		skb_key.basic.n_proto = skb->protocol;
20405cd271fSPaul Blakey 		skb_flow_dissect_tunnel_info(skb, &mask->dissector, &skb_key);
20505cd271fSPaul Blakey 		skb_flow_dissect(skb, &mask->dissector, &skb_key, 0);
20677b9900eSJiri Pirko 
20705cd271fSPaul Blakey 		fl_set_masked_key(&skb_mkey, &skb_key, mask);
20877b9900eSJiri Pirko 
20905cd271fSPaul Blakey 		f = fl_lookup(mask, &skb_mkey);
210e8eb36cdSAmir Vadai 		if (f && !tc_skip_sw(f->flags)) {
21177b9900eSJiri Pirko 			*res = f->res;
21277b9900eSJiri Pirko 			return tcf_exts_exec(skb, &f->exts, res);
21377b9900eSJiri Pirko 		}
21405cd271fSPaul Blakey 	}
21577b9900eSJiri Pirko 	return -1;
21677b9900eSJiri Pirko }
21777b9900eSJiri Pirko 
21877b9900eSJiri Pirko static int fl_init(struct tcf_proto *tp)
21977b9900eSJiri Pirko {
22077b9900eSJiri Pirko 	struct cls_fl_head *head;
22177b9900eSJiri Pirko 
22277b9900eSJiri Pirko 	head = kzalloc(sizeof(*head), GFP_KERNEL);
22377b9900eSJiri Pirko 	if (!head)
22477b9900eSJiri Pirko 		return -ENOBUFS;
22577b9900eSJiri Pirko 
22605cd271fSPaul Blakey 	INIT_LIST_HEAD_RCU(&head->masks);
22777b9900eSJiri Pirko 	rcu_assign_pointer(tp->root, head);
228c15ab236SChris Mi 	idr_init(&head->handle_idr);
22977b9900eSJiri Pirko 
23005cd271fSPaul Blakey 	return rhashtable_init(&head->ht, &mask_ht_params);
23105cd271fSPaul Blakey }
23205cd271fSPaul Blakey 
23344a5cd43SPaolo Abeni static void fl_mask_free(struct fl_flow_mask *mask)
23444a5cd43SPaolo Abeni {
23544a5cd43SPaolo Abeni 	rhashtable_destroy(&mask->ht);
23644a5cd43SPaolo Abeni 	kfree(mask);
23744a5cd43SPaolo Abeni }
23844a5cd43SPaolo Abeni 
23944a5cd43SPaolo Abeni static void fl_mask_free_work(struct work_struct *work)
24044a5cd43SPaolo Abeni {
24144a5cd43SPaolo Abeni 	struct fl_flow_mask *mask = container_of(to_rcu_work(work),
24244a5cd43SPaolo Abeni 						 struct fl_flow_mask, rwork);
24344a5cd43SPaolo Abeni 
24444a5cd43SPaolo Abeni 	fl_mask_free(mask);
24544a5cd43SPaolo Abeni }
24644a5cd43SPaolo Abeni 
24705cd271fSPaul Blakey static bool fl_mask_put(struct cls_fl_head *head, struct fl_flow_mask *mask,
24805cd271fSPaul Blakey 			bool async)
24905cd271fSPaul Blakey {
25005cd271fSPaul Blakey 	if (!list_empty(&mask->filters))
25105cd271fSPaul Blakey 		return false;
25205cd271fSPaul Blakey 
25305cd271fSPaul Blakey 	rhashtable_remove_fast(&head->ht, &mask->ht_node, mask_ht_params);
25405cd271fSPaul Blakey 	list_del_rcu(&mask->list);
25505cd271fSPaul Blakey 	if (async)
25644a5cd43SPaolo Abeni 		tcf_queue_work(&mask->rwork, fl_mask_free_work);
25705cd271fSPaul Blakey 	else
25844a5cd43SPaolo Abeni 		fl_mask_free(mask);
25905cd271fSPaul Blakey 
26005cd271fSPaul Blakey 	return true;
26177b9900eSJiri Pirko }
26277b9900eSJiri Pirko 
2630dadc117SCong Wang static void __fl_destroy_filter(struct cls_fl_filter *f)
2640dadc117SCong Wang {
2650dadc117SCong Wang 	tcf_exts_destroy(&f->exts);
2660dadc117SCong Wang 	tcf_exts_put_net(&f->exts);
2670dadc117SCong Wang 	kfree(f);
2680dadc117SCong Wang }
2690dadc117SCong Wang 
2700552c8afSCong Wang static void fl_destroy_filter_work(struct work_struct *work)
2710552c8afSCong Wang {
272aaa908ffSCong Wang 	struct cls_fl_filter *f = container_of(to_rcu_work(work),
273aaa908ffSCong Wang 					struct cls_fl_filter, rwork);
2740552c8afSCong Wang 
2750552c8afSCong Wang 	rtnl_lock();
2760dadc117SCong Wang 	__fl_destroy_filter(f);
2770552c8afSCong Wang 	rtnl_unlock();
2780552c8afSCong Wang }
2790552c8afSCong Wang 
2801b0f8037SJakub Kicinski static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f,
2811b0f8037SJakub Kicinski 				 struct netlink_ext_ack *extack)
2825b33f488SAmir Vadai {
283de4784caSJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
284208c0f4bSJiri Pirko 	struct tcf_block *block = tp->chain->block;
2855b33f488SAmir Vadai 
2861b0f8037SJakub Kicinski 	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack);
287de4784caSJiri Pirko 	cls_flower.command = TC_CLSFLOWER_DESTROY;
288de4784caSJiri Pirko 	cls_flower.cookie = (unsigned long) f;
2895b33f488SAmir Vadai 
290208c0f4bSJiri Pirko 	tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER,
291717503b9SJiri Pirko 			 &cls_flower, false);
292caa72601SJiri Pirko 	tcf_block_offload_dec(block, &f->flags);
2935b33f488SAmir Vadai }
2945b33f488SAmir Vadai 
295e8eb36cdSAmir Vadai static int fl_hw_replace_filter(struct tcf_proto *tp,
29641002038SQuentin Monnet 				struct cls_fl_filter *f,
29741002038SQuentin Monnet 				struct netlink_ext_ack *extack)
2985b33f488SAmir Vadai {
299de4784caSJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
300208c0f4bSJiri Pirko 	struct tcf_block *block = tp->chain->block;
301717503b9SJiri Pirko 	bool skip_sw = tc_skip_sw(f->flags);
302e8eb36cdSAmir Vadai 	int err;
3035b33f488SAmir Vadai 
304ea205940SJakub Kicinski 	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack);
305de4784caSJiri Pirko 	cls_flower.command = TC_CLSFLOWER_REPLACE;
306de4784caSJiri Pirko 	cls_flower.cookie = (unsigned long) f;
30705cd271fSPaul Blakey 	cls_flower.dissector = &f->mask->dissector;
30805cd271fSPaul Blakey 	cls_flower.mask = &f->mask->key;
309de4784caSJiri Pirko 	cls_flower.key = &f->mkey;
310de4784caSJiri Pirko 	cls_flower.exts = &f->exts;
311384c181eSAmritha Nambiar 	cls_flower.classid = f->res.classid;
3125b33f488SAmir Vadai 
313208c0f4bSJiri Pirko 	err = tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER,
314717503b9SJiri Pirko 			       &cls_flower, skip_sw);
315717503b9SJiri Pirko 	if (err < 0) {
3161b0f8037SJakub Kicinski 		fl_hw_destroy_filter(tp, f, NULL);
317717503b9SJiri Pirko 		return err;
318717503b9SJiri Pirko 	} else if (err > 0) {
31931533cbaSJohn Hurley 		f->in_hw_count = err;
320caa72601SJiri Pirko 		tcf_block_offload_inc(block, &f->flags);
321717503b9SJiri Pirko 	}
322717503b9SJiri Pirko 
323717503b9SJiri Pirko 	if (skip_sw && !(f->flags & TCA_CLS_FLAGS_IN_HW))
324717503b9SJiri Pirko 		return -EINVAL;
325717503b9SJiri Pirko 
326e8eb36cdSAmir Vadai 	return 0;
3275b33f488SAmir Vadai }
3285b33f488SAmir Vadai 
32910cbc684SAmir Vadai static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
33010cbc684SAmir Vadai {
331de4784caSJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
332208c0f4bSJiri Pirko 	struct tcf_block *block = tp->chain->block;
33310cbc684SAmir Vadai 
334ea205940SJakub Kicinski 	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, NULL);
335de4784caSJiri Pirko 	cls_flower.command = TC_CLSFLOWER_STATS;
336de4784caSJiri Pirko 	cls_flower.cookie = (unsigned long) f;
337de4784caSJiri Pirko 	cls_flower.exts = &f->exts;
338384c181eSAmritha Nambiar 	cls_flower.classid = f->res.classid;
33910cbc684SAmir Vadai 
340208c0f4bSJiri Pirko 	tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER,
341717503b9SJiri Pirko 			 &cls_flower, false);
34210cbc684SAmir Vadai }
34310cbc684SAmir Vadai 
34405cd271fSPaul Blakey static bool __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,
3451b0f8037SJakub Kicinski 			struct netlink_ext_ack *extack)
34613fa876eSRoi Dayan {
347c15ab236SChris Mi 	struct cls_fl_head *head = rtnl_dereference(tp->root);
34805cd271fSPaul Blakey 	bool async = tcf_exts_get_net(&f->exts);
34905cd271fSPaul Blakey 	bool last;
350c15ab236SChris Mi 
3519c160941SMatthew Wilcox 	idr_remove(&head->handle_idr, f->handle);
35213fa876eSRoi Dayan 	list_del_rcu(&f->list);
35305cd271fSPaul Blakey 	last = fl_mask_put(head, f->mask, async);
35479685219SHadar Hen Zion 	if (!tc_skip_hw(f->flags))
3551b0f8037SJakub Kicinski 		fl_hw_destroy_filter(tp, f, extack);
35613fa876eSRoi Dayan 	tcf_unbind_filter(tp, &f->res);
35705cd271fSPaul Blakey 	if (async)
358aaa908ffSCong Wang 		tcf_queue_work(&f->rwork, fl_destroy_filter_work);
3590dadc117SCong Wang 	else
3600dadc117SCong Wang 		__fl_destroy_filter(f);
36105cd271fSPaul Blakey 
36205cd271fSPaul Blakey 	return last;
36313fa876eSRoi Dayan }
36413fa876eSRoi Dayan 
365d9363774SDaniel Borkmann static void fl_destroy_sleepable(struct work_struct *work)
366d9363774SDaniel Borkmann {
367aaa908ffSCong Wang 	struct cls_fl_head *head = container_of(to_rcu_work(work),
368aaa908ffSCong Wang 						struct cls_fl_head,
369aaa908ffSCong Wang 						rwork);
370de9dc650SPaul Blakey 
371de9dc650SPaul Blakey 	rhashtable_destroy(&head->ht);
372d9363774SDaniel Borkmann 	kfree(head);
373d9363774SDaniel Borkmann 	module_put(THIS_MODULE);
374d9363774SDaniel Borkmann }
375d9363774SDaniel Borkmann 
376715df5ecSJakub Kicinski static void fl_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
37777b9900eSJiri Pirko {
37877b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
37905cd271fSPaul Blakey 	struct fl_flow_mask *mask, *next_mask;
38077b9900eSJiri Pirko 	struct cls_fl_filter *f, *next;
38177b9900eSJiri Pirko 
38205cd271fSPaul Blakey 	list_for_each_entry_safe(mask, next_mask, &head->masks, list) {
38305cd271fSPaul Blakey 		list_for_each_entry_safe(f, next, &mask->filters, list) {
38405cd271fSPaul Blakey 			if (__fl_delete(tp, f, extack))
38505cd271fSPaul Blakey 				break;
38605cd271fSPaul Blakey 		}
38705cd271fSPaul Blakey 	}
388c15ab236SChris Mi 	idr_destroy(&head->handle_idr);
389d9363774SDaniel Borkmann 
390d9363774SDaniel Borkmann 	__module_get(THIS_MODULE);
391aaa908ffSCong Wang 	tcf_queue_work(&head->rwork, fl_destroy_sleepable);
39277b9900eSJiri Pirko }
39377b9900eSJiri Pirko 
3948113c095SWANG Cong static void *fl_get(struct tcf_proto *tp, u32 handle)
39577b9900eSJiri Pirko {
39677b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
39777b9900eSJiri Pirko 
398322d884bSMatthew Wilcox 	return idr_find(&head->handle_idr, handle);
39977b9900eSJiri Pirko }
40077b9900eSJiri Pirko 
40177b9900eSJiri Pirko static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
40277b9900eSJiri Pirko 	[TCA_FLOWER_UNSPEC]		= { .type = NLA_UNSPEC },
40377b9900eSJiri Pirko 	[TCA_FLOWER_CLASSID]		= { .type = NLA_U32 },
40477b9900eSJiri Pirko 	[TCA_FLOWER_INDEV]		= { .type = NLA_STRING,
40577b9900eSJiri Pirko 					    .len = IFNAMSIZ },
40677b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_DST]	= { .len = ETH_ALEN },
40777b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_DST_MASK]	= { .len = ETH_ALEN },
40877b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_SRC]	= { .len = ETH_ALEN },
40977b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_SRC_MASK]	= { .len = ETH_ALEN },
41077b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_TYPE]	= { .type = NLA_U16 },
41177b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IP_PROTO]	= { .type = NLA_U8 },
41277b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_SRC]	= { .type = NLA_U32 },
41377b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_SRC_MASK]	= { .type = NLA_U32 },
41477b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_DST]	= { .type = NLA_U32 },
41577b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_DST_MASK]	= { .type = NLA_U32 },
41677b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
41777b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_SRC_MASK]	= { .len = sizeof(struct in6_addr) },
41877b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
41977b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_DST_MASK]	= { .len = sizeof(struct in6_addr) },
42077b9900eSJiri Pirko 	[TCA_FLOWER_KEY_TCP_SRC]	= { .type = NLA_U16 },
42177b9900eSJiri Pirko 	[TCA_FLOWER_KEY_TCP_DST]	= { .type = NLA_U16 },
422b175c3a4SJamal Hadi Salim 	[TCA_FLOWER_KEY_UDP_SRC]	= { .type = NLA_U16 },
423b175c3a4SJamal Hadi Salim 	[TCA_FLOWER_KEY_UDP_DST]	= { .type = NLA_U16 },
4249399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_ID]	= { .type = NLA_U16 },
4259399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_PRIO]	= { .type = NLA_U8 },
4269399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_ETH_TYPE]	= { .type = NLA_U16 },
427bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_KEY_ID]	= { .type = NLA_U32 },
428bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_SRC]	= { .type = NLA_U32 },
429bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NLA_U32 },
430bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_DST]	= { .type = NLA_U32 },
431bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NLA_U32 },
432bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
433bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) },
434bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
435bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) },
436aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_TCP_SRC_MASK]	= { .type = NLA_U16 },
437aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_TCP_DST_MASK]	= { .type = NLA_U16 },
438aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_UDP_SRC_MASK]	= { .type = NLA_U16 },
439aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_UDP_DST_MASK]	= { .type = NLA_U16 },
4405976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_SRC_MASK]	= { .type = NLA_U16 },
4415976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_DST_MASK]	= { .type = NLA_U16 },
4425976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_SRC]	= { .type = NLA_U16 },
4435976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_DST]	= { .type = NLA_U16 },
444f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT]	= { .type = NLA_U16 },
445f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK]	= { .type = NLA_U16 },
446f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]	= { .type = NLA_U16 },
447f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK]	= { .type = NLA_U16 },
448faa3ffceSOr Gerlitz 	[TCA_FLOWER_KEY_FLAGS]		= { .type = NLA_U32 },
449faa3ffceSOr Gerlitz 	[TCA_FLOWER_KEY_FLAGS_MASK]	= { .type = NLA_U32 },
4507b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_TYPE]	= { .type = NLA_U8 },
4517b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_TYPE_MASK] = { .type = NLA_U8 },
4527b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_CODE]	= { .type = NLA_U8 },
4537b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_CODE_MASK] = { .type = NLA_U8 },
4547b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_TYPE]	= { .type = NLA_U8 },
4557b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_TYPE_MASK] = { .type = NLA_U8 },
4567b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_CODE]	= { .type = NLA_U8 },
4577b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_CODE_MASK] = { .type = NLA_U8 },
45899d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SIP]	= { .type = NLA_U32 },
45999d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SIP_MASK]	= { .type = NLA_U32 },
46099d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_TIP]	= { .type = NLA_U32 },
46199d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_TIP_MASK]	= { .type = NLA_U32 },
46299d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_OP]		= { .type = NLA_U8 },
46399d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_OP_MASK]	= { .type = NLA_U8 },
46499d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SHA]	= { .len = ETH_ALEN },
46599d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SHA_MASK]	= { .len = ETH_ALEN },
46699d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_THA]	= { .len = ETH_ALEN },
46799d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_THA_MASK]	= { .len = ETH_ALEN },
468a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_TTL]	= { .type = NLA_U8 },
469a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_BOS]	= { .type = NLA_U8 },
470a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_TC]	= { .type = NLA_U8 },
471a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_LABEL]	= { .type = NLA_U32 },
472fdfc7dd6SJiri Pirko 	[TCA_FLOWER_KEY_TCP_FLAGS]	= { .type = NLA_U16 },
473fdfc7dd6SJiri Pirko 	[TCA_FLOWER_KEY_TCP_FLAGS_MASK]	= { .type = NLA_U16 },
4744d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TOS]		= { .type = NLA_U8 },
4754d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TOS_MASK]	= { .type = NLA_U8 },
4764d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TTL]		= { .type = NLA_U8 },
4774d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TTL_MASK]	= { .type = NLA_U8 },
478d64efd09SJianbo Liu 	[TCA_FLOWER_KEY_CVLAN_ID]	= { .type = NLA_U16 },
479d64efd09SJianbo Liu 	[TCA_FLOWER_KEY_CVLAN_PRIO]	= { .type = NLA_U8 },
480d64efd09SJianbo Liu 	[TCA_FLOWER_KEY_CVLAN_ETH_TYPE]	= { .type = NLA_U16 },
4810e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TOS]	= { .type = NLA_U8 },
4820e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TOS_MASK] = { .type = NLA_U8 },
4830e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TTL]	 = { .type = NLA_U8 },
4840e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TTL_MASK] = { .type = NLA_U8 },
48577b9900eSJiri Pirko };
48677b9900eSJiri Pirko 
48777b9900eSJiri Pirko static void fl_set_key_val(struct nlattr **tb,
48877b9900eSJiri Pirko 			   void *val, int val_type,
48977b9900eSJiri Pirko 			   void *mask, int mask_type, int len)
49077b9900eSJiri Pirko {
49177b9900eSJiri Pirko 	if (!tb[val_type])
49277b9900eSJiri Pirko 		return;
49377b9900eSJiri Pirko 	memcpy(val, nla_data(tb[val_type]), len);
49477b9900eSJiri Pirko 	if (mask_type == TCA_FLOWER_UNSPEC || !tb[mask_type])
49577b9900eSJiri Pirko 		memset(mask, 0xff, len);
49677b9900eSJiri Pirko 	else
49777b9900eSJiri Pirko 		memcpy(mask, nla_data(tb[mask_type]), len);
49877b9900eSJiri Pirko }
49977b9900eSJiri Pirko 
5001a7fca63SBenjamin LaHaise static int fl_set_key_mpls(struct nlattr **tb,
501a577d8f7SBenjamin LaHaise 			   struct flow_dissector_key_mpls *key_val,
502a577d8f7SBenjamin LaHaise 			   struct flow_dissector_key_mpls *key_mask)
503a577d8f7SBenjamin LaHaise {
504a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_TTL]) {
505a577d8f7SBenjamin LaHaise 		key_val->mpls_ttl = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TTL]);
506a577d8f7SBenjamin LaHaise 		key_mask->mpls_ttl = MPLS_TTL_MASK;
507a577d8f7SBenjamin LaHaise 	}
508a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_BOS]) {
5091a7fca63SBenjamin LaHaise 		u8 bos = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_BOS]);
5101a7fca63SBenjamin LaHaise 
5111a7fca63SBenjamin LaHaise 		if (bos & ~MPLS_BOS_MASK)
5121a7fca63SBenjamin LaHaise 			return -EINVAL;
5131a7fca63SBenjamin LaHaise 		key_val->mpls_bos = bos;
514a577d8f7SBenjamin LaHaise 		key_mask->mpls_bos = MPLS_BOS_MASK;
515a577d8f7SBenjamin LaHaise 	}
516a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_TC]) {
5171a7fca63SBenjamin LaHaise 		u8 tc = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TC]);
5181a7fca63SBenjamin LaHaise 
5191a7fca63SBenjamin LaHaise 		if (tc & ~MPLS_TC_MASK)
5201a7fca63SBenjamin LaHaise 			return -EINVAL;
5211a7fca63SBenjamin LaHaise 		key_val->mpls_tc = tc;
522a577d8f7SBenjamin LaHaise 		key_mask->mpls_tc = MPLS_TC_MASK;
523a577d8f7SBenjamin LaHaise 	}
524a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_LABEL]) {
5251a7fca63SBenjamin LaHaise 		u32 label = nla_get_u32(tb[TCA_FLOWER_KEY_MPLS_LABEL]);
5261a7fca63SBenjamin LaHaise 
5271a7fca63SBenjamin LaHaise 		if (label & ~MPLS_LABEL_MASK)
5281a7fca63SBenjamin LaHaise 			return -EINVAL;
5291a7fca63SBenjamin LaHaise 		key_val->mpls_label = label;
530a577d8f7SBenjamin LaHaise 		key_mask->mpls_label = MPLS_LABEL_MASK;
531a577d8f7SBenjamin LaHaise 	}
5321a7fca63SBenjamin LaHaise 	return 0;
533a577d8f7SBenjamin LaHaise }
534a577d8f7SBenjamin LaHaise 
5359399ae9aSHadar Hen Zion static void fl_set_key_vlan(struct nlattr **tb,
536aaab0834SJianbo Liu 			    __be16 ethertype,
537d64efd09SJianbo Liu 			    int vlan_id_key, int vlan_prio_key,
5389399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *key_val,
5399399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *key_mask)
5409399ae9aSHadar Hen Zion {
5419399ae9aSHadar Hen Zion #define VLAN_PRIORITY_MASK	0x7
5429399ae9aSHadar Hen Zion 
543d64efd09SJianbo Liu 	if (tb[vlan_id_key]) {
5449399ae9aSHadar Hen Zion 		key_val->vlan_id =
545d64efd09SJianbo Liu 			nla_get_u16(tb[vlan_id_key]) & VLAN_VID_MASK;
5469399ae9aSHadar Hen Zion 		key_mask->vlan_id = VLAN_VID_MASK;
5479399ae9aSHadar Hen Zion 	}
548d64efd09SJianbo Liu 	if (tb[vlan_prio_key]) {
5499399ae9aSHadar Hen Zion 		key_val->vlan_priority =
550d64efd09SJianbo Liu 			nla_get_u8(tb[vlan_prio_key]) &
5519399ae9aSHadar Hen Zion 			VLAN_PRIORITY_MASK;
5529399ae9aSHadar Hen Zion 		key_mask->vlan_priority = VLAN_PRIORITY_MASK;
5539399ae9aSHadar Hen Zion 	}
554aaab0834SJianbo Liu 	key_val->vlan_tpid = ethertype;
555aaab0834SJianbo Liu 	key_mask->vlan_tpid = cpu_to_be16(~0);
5569399ae9aSHadar Hen Zion }
5579399ae9aSHadar Hen Zion 
558faa3ffceSOr Gerlitz static void fl_set_key_flag(u32 flower_key, u32 flower_mask,
559faa3ffceSOr Gerlitz 			    u32 *dissector_key, u32 *dissector_mask,
560faa3ffceSOr Gerlitz 			    u32 flower_flag_bit, u32 dissector_flag_bit)
561faa3ffceSOr Gerlitz {
562faa3ffceSOr Gerlitz 	if (flower_mask & flower_flag_bit) {
563faa3ffceSOr Gerlitz 		*dissector_mask |= dissector_flag_bit;
564faa3ffceSOr Gerlitz 		if (flower_key & flower_flag_bit)
565faa3ffceSOr Gerlitz 			*dissector_key |= dissector_flag_bit;
566faa3ffceSOr Gerlitz 	}
567faa3ffceSOr Gerlitz }
568faa3ffceSOr Gerlitz 
569d9724772SOr Gerlitz static int fl_set_key_flags(struct nlattr **tb,
570faa3ffceSOr Gerlitz 			    u32 *flags_key, u32 *flags_mask)
571faa3ffceSOr Gerlitz {
572faa3ffceSOr Gerlitz 	u32 key, mask;
573faa3ffceSOr Gerlitz 
574d9724772SOr Gerlitz 	/* mask is mandatory for flags */
575d9724772SOr Gerlitz 	if (!tb[TCA_FLOWER_KEY_FLAGS_MASK])
576d9724772SOr Gerlitz 		return -EINVAL;
577faa3ffceSOr Gerlitz 
578faa3ffceSOr Gerlitz 	key = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS]));
579faa3ffceSOr Gerlitz 	mask = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS_MASK]));
580faa3ffceSOr Gerlitz 
581faa3ffceSOr Gerlitz 	*flags_key  = 0;
582faa3ffceSOr Gerlitz 	*flags_mask = 0;
583faa3ffceSOr Gerlitz 
584faa3ffceSOr Gerlitz 	fl_set_key_flag(key, mask, flags_key, flags_mask,
585faa3ffceSOr Gerlitz 			TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT);
586459d153dSPieter Jansen van Vuuren 	fl_set_key_flag(key, mask, flags_key, flags_mask,
587459d153dSPieter Jansen van Vuuren 			TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST,
588459d153dSPieter Jansen van Vuuren 			FLOW_DIS_FIRST_FRAG);
589d9724772SOr Gerlitz 
590d9724772SOr Gerlitz 	return 0;
591faa3ffceSOr Gerlitz }
592faa3ffceSOr Gerlitz 
5930e2c17b6SOr Gerlitz static void fl_set_key_ip(struct nlattr **tb, bool encap,
5944d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *key,
5954d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *mask)
5964d80cc0aSOr Gerlitz {
5970e2c17b6SOr Gerlitz 	int tos_key = encap ? TCA_FLOWER_KEY_ENC_IP_TOS : TCA_FLOWER_KEY_IP_TOS;
5980e2c17b6SOr Gerlitz 	int ttl_key = encap ? TCA_FLOWER_KEY_ENC_IP_TTL : TCA_FLOWER_KEY_IP_TTL;
5990e2c17b6SOr Gerlitz 	int tos_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TOS_MASK : TCA_FLOWER_KEY_IP_TOS_MASK;
6000e2c17b6SOr Gerlitz 	int ttl_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TTL_MASK : TCA_FLOWER_KEY_IP_TTL_MASK;
6014d80cc0aSOr Gerlitz 
6020e2c17b6SOr Gerlitz 	fl_set_key_val(tb, &key->tos, tos_key, &mask->tos, tos_mask, sizeof(key->tos));
6030e2c17b6SOr Gerlitz 	fl_set_key_val(tb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl));
6044d80cc0aSOr Gerlitz }
6054d80cc0aSOr Gerlitz 
60677b9900eSJiri Pirko static int fl_set_key(struct net *net, struct nlattr **tb,
6071057c55fSAlexander Aring 		      struct fl_flow_key *key, struct fl_flow_key *mask,
6081057c55fSAlexander Aring 		      struct netlink_ext_ack *extack)
60977b9900eSJiri Pirko {
6109399ae9aSHadar Hen Zion 	__be16 ethertype;
611d9724772SOr Gerlitz 	int ret = 0;
612dd3aa3b5SBrian Haley #ifdef CONFIG_NET_CLS_IND
61377b9900eSJiri Pirko 	if (tb[TCA_FLOWER_INDEV]) {
6141057c55fSAlexander Aring 		int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV], extack);
61577b9900eSJiri Pirko 		if (err < 0)
61677b9900eSJiri Pirko 			return err;
61777b9900eSJiri Pirko 		key->indev_ifindex = err;
61877b9900eSJiri Pirko 		mask->indev_ifindex = 0xffffffff;
61977b9900eSJiri Pirko 	}
620dd3aa3b5SBrian Haley #endif
62177b9900eSJiri Pirko 
62277b9900eSJiri Pirko 	fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
62377b9900eSJiri Pirko 		       mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
62477b9900eSJiri Pirko 		       sizeof(key->eth.dst));
62577b9900eSJiri Pirko 	fl_set_key_val(tb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
62677b9900eSJiri Pirko 		       mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
62777b9900eSJiri Pirko 		       sizeof(key->eth.src));
62866530bdfSJamal Hadi Salim 
6290b498a52SArnd Bergmann 	if (tb[TCA_FLOWER_KEY_ETH_TYPE]) {
6309399ae9aSHadar Hen Zion 		ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_ETH_TYPE]);
6319399ae9aSHadar Hen Zion 
632aaab0834SJianbo Liu 		if (eth_type_vlan(ethertype)) {
633d64efd09SJianbo Liu 			fl_set_key_vlan(tb, ethertype, TCA_FLOWER_KEY_VLAN_ID,
634d64efd09SJianbo Liu 					TCA_FLOWER_KEY_VLAN_PRIO, &key->vlan,
635d64efd09SJianbo Liu 					&mask->vlan);
636d64efd09SJianbo Liu 
6375e9a0fe4SJianbo Liu 			if (tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]) {
638d64efd09SJianbo Liu 				ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]);
639d64efd09SJianbo Liu 				if (eth_type_vlan(ethertype)) {
640d64efd09SJianbo Liu 					fl_set_key_vlan(tb, ethertype,
641d64efd09SJianbo Liu 							TCA_FLOWER_KEY_CVLAN_ID,
642d64efd09SJianbo Liu 							TCA_FLOWER_KEY_CVLAN_PRIO,
643d64efd09SJianbo Liu 							&key->cvlan, &mask->cvlan);
6449399ae9aSHadar Hen Zion 					fl_set_key_val(tb, &key->basic.n_proto,
645d64efd09SJianbo Liu 						       TCA_FLOWER_KEY_CVLAN_ETH_TYPE,
646d64efd09SJianbo Liu 						       &mask->basic.n_proto,
647d64efd09SJianbo Liu 						       TCA_FLOWER_UNSPEC,
64877b9900eSJiri Pirko 						       sizeof(key->basic.n_proto));
6499399ae9aSHadar Hen Zion 				} else {
6509399ae9aSHadar Hen Zion 					key->basic.n_proto = ethertype;
6519399ae9aSHadar Hen Zion 					mask->basic.n_proto = cpu_to_be16(~0);
6529399ae9aSHadar Hen Zion 				}
6535e9a0fe4SJianbo Liu 			}
654d64efd09SJianbo Liu 		} else {
655d64efd09SJianbo Liu 			key->basic.n_proto = ethertype;
656d64efd09SJianbo Liu 			mask->basic.n_proto = cpu_to_be16(~0);
657d64efd09SJianbo Liu 		}
6580b498a52SArnd Bergmann 	}
65966530bdfSJamal Hadi Salim 
66077b9900eSJiri Pirko 	if (key->basic.n_proto == htons(ETH_P_IP) ||
66177b9900eSJiri Pirko 	    key->basic.n_proto == htons(ETH_P_IPV6)) {
66277b9900eSJiri Pirko 		fl_set_key_val(tb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
66377b9900eSJiri Pirko 			       &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
66477b9900eSJiri Pirko 			       sizeof(key->basic.ip_proto));
6650e2c17b6SOr Gerlitz 		fl_set_key_ip(tb, false, &key->ip, &mask->ip);
66677b9900eSJiri Pirko 	}
66766530bdfSJamal Hadi Salim 
66866530bdfSJamal Hadi Salim 	if (tb[TCA_FLOWER_KEY_IPV4_SRC] || tb[TCA_FLOWER_KEY_IPV4_DST]) {
66966530bdfSJamal Hadi Salim 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
670970bfcd0SPaul Blakey 		mask->control.addr_type = ~0;
67177b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
67277b9900eSJiri Pirko 			       &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
67377b9900eSJiri Pirko 			       sizeof(key->ipv4.src));
67477b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
67577b9900eSJiri Pirko 			       &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
67677b9900eSJiri Pirko 			       sizeof(key->ipv4.dst));
67766530bdfSJamal Hadi Salim 	} else if (tb[TCA_FLOWER_KEY_IPV6_SRC] || tb[TCA_FLOWER_KEY_IPV6_DST]) {
67866530bdfSJamal Hadi Salim 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
679970bfcd0SPaul Blakey 		mask->control.addr_type = ~0;
68077b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
68177b9900eSJiri Pirko 			       &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
68277b9900eSJiri Pirko 			       sizeof(key->ipv6.src));
68377b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
68477b9900eSJiri Pirko 			       &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
68577b9900eSJiri Pirko 			       sizeof(key->ipv6.dst));
68677b9900eSJiri Pirko 	}
68766530bdfSJamal Hadi Salim 
68877b9900eSJiri Pirko 	if (key->basic.ip_proto == IPPROTO_TCP) {
68977b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
690aa72d708SOr Gerlitz 			       &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
69177b9900eSJiri Pirko 			       sizeof(key->tp.src));
69277b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
693aa72d708SOr Gerlitz 			       &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
69477b9900eSJiri Pirko 			       sizeof(key->tp.dst));
695fdfc7dd6SJiri Pirko 		fl_set_key_val(tb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS,
696fdfc7dd6SJiri Pirko 			       &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK,
697fdfc7dd6SJiri Pirko 			       sizeof(key->tcp.flags));
69877b9900eSJiri Pirko 	} else if (key->basic.ip_proto == IPPROTO_UDP) {
69977b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
700aa72d708SOr Gerlitz 			       &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
70177b9900eSJiri Pirko 			       sizeof(key->tp.src));
70277b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
703aa72d708SOr Gerlitz 			       &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
70477b9900eSJiri Pirko 			       sizeof(key->tp.dst));
7055976c5f4SSimon Horman 	} else if (key->basic.ip_proto == IPPROTO_SCTP) {
7065976c5f4SSimon Horman 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
7075976c5f4SSimon Horman 			       &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
7085976c5f4SSimon Horman 			       sizeof(key->tp.src));
7095976c5f4SSimon Horman 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
7105976c5f4SSimon Horman 			       &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
7115976c5f4SSimon Horman 			       sizeof(key->tp.dst));
7127b684884SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_IP) &&
7137b684884SSimon Horman 		   key->basic.ip_proto == IPPROTO_ICMP) {
7147b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV4_TYPE,
7157b684884SSimon Horman 			       &mask->icmp.type,
7167b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,
7177b684884SSimon Horman 			       sizeof(key->icmp.type));
7187b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE,
7197b684884SSimon Horman 			       &mask->icmp.code,
7207b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
7217b684884SSimon Horman 			       sizeof(key->icmp.code));
7227b684884SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_IPV6) &&
7237b684884SSimon Horman 		   key->basic.ip_proto == IPPROTO_ICMPV6) {
7247b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV6_TYPE,
7257b684884SSimon Horman 			       &mask->icmp.type,
7267b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
7277b684884SSimon Horman 			       sizeof(key->icmp.type));
728040587afSSimon Horman 		fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV6_CODE,
7297b684884SSimon Horman 			       &mask->icmp.code,
730040587afSSimon Horman 			       TCA_FLOWER_KEY_ICMPV6_CODE_MASK,
7317b684884SSimon Horman 			       sizeof(key->icmp.code));
732a577d8f7SBenjamin LaHaise 	} else if (key->basic.n_proto == htons(ETH_P_MPLS_UC) ||
733a577d8f7SBenjamin LaHaise 		   key->basic.n_proto == htons(ETH_P_MPLS_MC)) {
7341a7fca63SBenjamin LaHaise 		ret = fl_set_key_mpls(tb, &key->mpls, &mask->mpls);
7351a7fca63SBenjamin LaHaise 		if (ret)
7361a7fca63SBenjamin LaHaise 			return ret;
73799d31326SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_ARP) ||
73899d31326SSimon Horman 		   key->basic.n_proto == htons(ETH_P_RARP)) {
73999d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.sip, TCA_FLOWER_KEY_ARP_SIP,
74099d31326SSimon Horman 			       &mask->arp.sip, TCA_FLOWER_KEY_ARP_SIP_MASK,
74199d31326SSimon Horman 			       sizeof(key->arp.sip));
74299d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.tip, TCA_FLOWER_KEY_ARP_TIP,
74399d31326SSimon Horman 			       &mask->arp.tip, TCA_FLOWER_KEY_ARP_TIP_MASK,
74499d31326SSimon Horman 			       sizeof(key->arp.tip));
74599d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.op, TCA_FLOWER_KEY_ARP_OP,
74699d31326SSimon Horman 			       &mask->arp.op, TCA_FLOWER_KEY_ARP_OP_MASK,
74799d31326SSimon Horman 			       sizeof(key->arp.op));
74899d31326SSimon Horman 		fl_set_key_val(tb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA,
74999d31326SSimon Horman 			       mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK,
75099d31326SSimon Horman 			       sizeof(key->arp.sha));
75199d31326SSimon Horman 		fl_set_key_val(tb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA,
75299d31326SSimon Horman 			       mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK,
75399d31326SSimon Horman 			       sizeof(key->arp.tha));
75477b9900eSJiri Pirko 	}
75577b9900eSJiri Pirko 
756bc3103f1SAmir Vadai 	if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] ||
757bc3103f1SAmir Vadai 	    tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) {
758bc3103f1SAmir Vadai 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
759970bfcd0SPaul Blakey 		mask->enc_control.addr_type = ~0;
760bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv4.src,
761bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_SRC,
762bc3103f1SAmir Vadai 			       &mask->enc_ipv4.src,
763bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
764bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv4.src));
765bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv4.dst,
766bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_DST,
767bc3103f1SAmir Vadai 			       &mask->enc_ipv4.dst,
768bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
769bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv4.dst));
770bc3103f1SAmir Vadai 	}
771bc3103f1SAmir Vadai 
772bc3103f1SAmir Vadai 	if (tb[TCA_FLOWER_KEY_ENC_IPV6_SRC] ||
773bc3103f1SAmir Vadai 	    tb[TCA_FLOWER_KEY_ENC_IPV6_DST]) {
774bc3103f1SAmir Vadai 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
775970bfcd0SPaul Blakey 		mask->enc_control.addr_type = ~0;
776bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv6.src,
777bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_SRC,
778bc3103f1SAmir Vadai 			       &mask->enc_ipv6.src,
779bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
780bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv6.src));
781bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv6.dst,
782bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_DST,
783bc3103f1SAmir Vadai 			       &mask->enc_ipv6.dst,
784bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
785bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv6.dst));
786bc3103f1SAmir Vadai 	}
787bc3103f1SAmir Vadai 
788bc3103f1SAmir Vadai 	fl_set_key_val(tb, &key->enc_key_id.keyid, TCA_FLOWER_KEY_ENC_KEY_ID,
789eb523f42SHadar Hen Zion 		       &mask->enc_key_id.keyid, TCA_FLOWER_UNSPEC,
790bc3103f1SAmir Vadai 		       sizeof(key->enc_key_id.keyid));
791bc3103f1SAmir Vadai 
792f4d997fdSHadar Hen Zion 	fl_set_key_val(tb, &key->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
793f4d997fdSHadar Hen Zion 		       &mask->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
794f4d997fdSHadar Hen Zion 		       sizeof(key->enc_tp.src));
795f4d997fdSHadar Hen Zion 
796f4d997fdSHadar Hen Zion 	fl_set_key_val(tb, &key->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
797f4d997fdSHadar Hen Zion 		       &mask->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
798f4d997fdSHadar Hen Zion 		       sizeof(key->enc_tp.dst));
799f4d997fdSHadar Hen Zion 
8000e2c17b6SOr Gerlitz 	fl_set_key_ip(tb, true, &key->enc_ip, &mask->enc_ip);
8010e2c17b6SOr Gerlitz 
802d9724772SOr Gerlitz 	if (tb[TCA_FLOWER_KEY_FLAGS])
803d9724772SOr Gerlitz 		ret = fl_set_key_flags(tb, &key->control.flags, &mask->control.flags);
804faa3ffceSOr Gerlitz 
805d9724772SOr Gerlitz 	return ret;
80677b9900eSJiri Pirko }
80777b9900eSJiri Pirko 
80805cd271fSPaul Blakey static void fl_mask_copy(struct fl_flow_mask *dst,
80905cd271fSPaul Blakey 			 struct fl_flow_mask *src)
81077b9900eSJiri Pirko {
81105cd271fSPaul Blakey 	const void *psrc = fl_key_get_start(&src->key, src);
81205cd271fSPaul Blakey 	void *pdst = fl_key_get_start(&dst->key, src);
81377b9900eSJiri Pirko 
81405cd271fSPaul Blakey 	memcpy(pdst, psrc, fl_mask_range(src));
81505cd271fSPaul Blakey 	dst->range = src->range;
81677b9900eSJiri Pirko }
81777b9900eSJiri Pirko 
81877b9900eSJiri Pirko static const struct rhashtable_params fl_ht_params = {
81977b9900eSJiri Pirko 	.key_offset = offsetof(struct cls_fl_filter, mkey), /* base offset */
82077b9900eSJiri Pirko 	.head_offset = offsetof(struct cls_fl_filter, ht_node),
82177b9900eSJiri Pirko 	.automatic_shrinking = true,
82277b9900eSJiri Pirko };
82377b9900eSJiri Pirko 
82405cd271fSPaul Blakey static int fl_init_mask_hashtable(struct fl_flow_mask *mask)
82577b9900eSJiri Pirko {
82605cd271fSPaul Blakey 	mask->filter_ht_params = fl_ht_params;
82705cd271fSPaul Blakey 	mask->filter_ht_params.key_len = fl_mask_range(mask);
82805cd271fSPaul Blakey 	mask->filter_ht_params.key_offset += mask->range.start;
82977b9900eSJiri Pirko 
83005cd271fSPaul Blakey 	return rhashtable_init(&mask->ht, &mask->filter_ht_params);
83177b9900eSJiri Pirko }
83277b9900eSJiri Pirko 
83377b9900eSJiri Pirko #define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member)
83477b9900eSJiri Pirko #define FL_KEY_MEMBER_SIZE(member) (sizeof(((struct fl_flow_key *) 0)->member))
83577b9900eSJiri Pirko 
836339ba878SHadar Hen Zion #define FL_KEY_IS_MASKED(mask, member)						\
837339ba878SHadar Hen Zion 	memchr_inv(((char *)mask) + FL_KEY_MEMBER_OFFSET(member),		\
838339ba878SHadar Hen Zion 		   0, FL_KEY_MEMBER_SIZE(member))				\
83977b9900eSJiri Pirko 
84077b9900eSJiri Pirko #define FL_KEY_SET(keys, cnt, id, member)					\
84177b9900eSJiri Pirko 	do {									\
84277b9900eSJiri Pirko 		keys[cnt].key_id = id;						\
84377b9900eSJiri Pirko 		keys[cnt].offset = FL_KEY_MEMBER_OFFSET(member);		\
84477b9900eSJiri Pirko 		cnt++;								\
84577b9900eSJiri Pirko 	} while(0);
84677b9900eSJiri Pirko 
847339ba878SHadar Hen Zion #define FL_KEY_SET_IF_MASKED(mask, keys, cnt, id, member)			\
84877b9900eSJiri Pirko 	do {									\
849339ba878SHadar Hen Zion 		if (FL_KEY_IS_MASKED(mask, member))				\
85077b9900eSJiri Pirko 			FL_KEY_SET(keys, cnt, id, member);			\
85177b9900eSJiri Pirko 	} while(0);
85277b9900eSJiri Pirko 
85333fb5cbaSJiri Pirko static void fl_init_dissector(struct flow_dissector *dissector,
85433fb5cbaSJiri Pirko 			      struct fl_flow_key *mask)
85577b9900eSJiri Pirko {
85677b9900eSJiri Pirko 	struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX];
85777b9900eSJiri Pirko 	size_t cnt = 0;
85877b9900eSJiri Pirko 
85942aecaa9STom Herbert 	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control);
86077b9900eSJiri Pirko 	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic);
86133fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
86277b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_ETH_ADDRS, eth);
86333fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
86477b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4);
86533fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
86677b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6);
86733fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
86877b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_PORTS, tp);
86933fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
8704d80cc0aSOr Gerlitz 			     FLOW_DISSECTOR_KEY_IP, ip);
87133fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
872fdfc7dd6SJiri Pirko 			     FLOW_DISSECTOR_KEY_TCP, tcp);
87333fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
8747b684884SSimon Horman 			     FLOW_DISSECTOR_KEY_ICMP, icmp);
87533fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
87699d31326SSimon Horman 			     FLOW_DISSECTOR_KEY_ARP, arp);
87733fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
878a577d8f7SBenjamin LaHaise 			     FLOW_DISSECTOR_KEY_MPLS, mpls);
87933fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
8809399ae9aSHadar Hen Zion 			     FLOW_DISSECTOR_KEY_VLAN, vlan);
88133fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
882d64efd09SJianbo Liu 			     FLOW_DISSECTOR_KEY_CVLAN, cvlan);
88333fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
884519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_KEYID, enc_key_id);
88533fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
886519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, enc_ipv4);
88733fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
888519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, enc_ipv6);
88933fb5cbaSJiri Pirko 	if (FL_KEY_IS_MASKED(mask, enc_ipv4) ||
89033fb5cbaSJiri Pirko 	    FL_KEY_IS_MASKED(mask, enc_ipv6))
891519d1052SHadar Hen Zion 		FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_ENC_CONTROL,
892519d1052SHadar Hen Zion 			   enc_control);
89333fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
894f4d997fdSHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp);
89533fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
8960e2c17b6SOr Gerlitz 			     FLOW_DISSECTOR_KEY_ENC_IP, enc_ip);
89777b9900eSJiri Pirko 
89833fb5cbaSJiri Pirko 	skb_flow_dissector_init(dissector, keys, cnt);
89905cd271fSPaul Blakey }
90005cd271fSPaul Blakey 
90105cd271fSPaul Blakey static struct fl_flow_mask *fl_create_new_mask(struct cls_fl_head *head,
90205cd271fSPaul Blakey 					       struct fl_flow_mask *mask)
90305cd271fSPaul Blakey {
90405cd271fSPaul Blakey 	struct fl_flow_mask *newmask;
90505cd271fSPaul Blakey 	int err;
90605cd271fSPaul Blakey 
90705cd271fSPaul Blakey 	newmask = kzalloc(sizeof(*newmask), GFP_KERNEL);
90805cd271fSPaul Blakey 	if (!newmask)
90905cd271fSPaul Blakey 		return ERR_PTR(-ENOMEM);
91005cd271fSPaul Blakey 
91105cd271fSPaul Blakey 	fl_mask_copy(newmask, mask);
91205cd271fSPaul Blakey 
91305cd271fSPaul Blakey 	err = fl_init_mask_hashtable(newmask);
91405cd271fSPaul Blakey 	if (err)
91505cd271fSPaul Blakey 		goto errout_free;
91605cd271fSPaul Blakey 
91733fb5cbaSJiri Pirko 	fl_init_dissector(&newmask->dissector, &newmask->key);
91805cd271fSPaul Blakey 
91905cd271fSPaul Blakey 	INIT_LIST_HEAD_RCU(&newmask->filters);
92005cd271fSPaul Blakey 
92105cd271fSPaul Blakey 	err = rhashtable_insert_fast(&head->ht, &newmask->ht_node,
92205cd271fSPaul Blakey 				     mask_ht_params);
92305cd271fSPaul Blakey 	if (err)
92405cd271fSPaul Blakey 		goto errout_destroy;
92505cd271fSPaul Blakey 
92605cd271fSPaul Blakey 	list_add_tail_rcu(&newmask->list, &head->masks);
92705cd271fSPaul Blakey 
92805cd271fSPaul Blakey 	return newmask;
92905cd271fSPaul Blakey 
93005cd271fSPaul Blakey errout_destroy:
93105cd271fSPaul Blakey 	rhashtable_destroy(&newmask->ht);
93205cd271fSPaul Blakey errout_free:
93305cd271fSPaul Blakey 	kfree(newmask);
93405cd271fSPaul Blakey 
93505cd271fSPaul Blakey 	return ERR_PTR(err);
93677b9900eSJiri Pirko }
93777b9900eSJiri Pirko 
93877b9900eSJiri Pirko static int fl_check_assign_mask(struct cls_fl_head *head,
93905cd271fSPaul Blakey 				struct cls_fl_filter *fnew,
94005cd271fSPaul Blakey 				struct cls_fl_filter *fold,
94177b9900eSJiri Pirko 				struct fl_flow_mask *mask)
94277b9900eSJiri Pirko {
94305cd271fSPaul Blakey 	struct fl_flow_mask *newmask;
94477b9900eSJiri Pirko 
94505cd271fSPaul Blakey 	fnew->mask = rhashtable_lookup_fast(&head->ht, mask, mask_ht_params);
94605cd271fSPaul Blakey 	if (!fnew->mask) {
94705cd271fSPaul Blakey 		if (fold)
94877b9900eSJiri Pirko 			return -EINVAL;
94905cd271fSPaul Blakey 
95005cd271fSPaul Blakey 		newmask = fl_create_new_mask(head, mask);
95105cd271fSPaul Blakey 		if (IS_ERR(newmask))
95205cd271fSPaul Blakey 			return PTR_ERR(newmask);
95305cd271fSPaul Blakey 
95405cd271fSPaul Blakey 		fnew->mask = newmask;
955f6521c58SPaul Blakey 	} else if (fold && fold->mask != fnew->mask) {
95605cd271fSPaul Blakey 		return -EINVAL;
95777b9900eSJiri Pirko 	}
95877b9900eSJiri Pirko 
95977b9900eSJiri Pirko 	return 0;
96077b9900eSJiri Pirko }
96177b9900eSJiri Pirko 
96277b9900eSJiri Pirko static int fl_set_parms(struct net *net, struct tcf_proto *tp,
96377b9900eSJiri Pirko 			struct cls_fl_filter *f, struct fl_flow_mask *mask,
96477b9900eSJiri Pirko 			unsigned long base, struct nlattr **tb,
96550a56190SAlexander Aring 			struct nlattr *est, bool ovr,
966b95ec7ebSJiri Pirko 			struct fl_flow_tmplt *tmplt,
96750a56190SAlexander Aring 			struct netlink_ext_ack *extack)
96877b9900eSJiri Pirko {
96977b9900eSJiri Pirko 	int err;
97077b9900eSJiri Pirko 
97150a56190SAlexander Aring 	err = tcf_exts_validate(net, tp, tb, est, &f->exts, ovr, extack);
97277b9900eSJiri Pirko 	if (err < 0)
97377b9900eSJiri Pirko 		return err;
97477b9900eSJiri Pirko 
97577b9900eSJiri Pirko 	if (tb[TCA_FLOWER_CLASSID]) {
97677b9900eSJiri Pirko 		f->res.classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]);
97777b9900eSJiri Pirko 		tcf_bind_filter(tp, &f->res, base);
97877b9900eSJiri Pirko 	}
97977b9900eSJiri Pirko 
9801057c55fSAlexander Aring 	err = fl_set_key(net, tb, &f->key, &mask->key, extack);
98177b9900eSJiri Pirko 	if (err)
98245507529SJiri Pirko 		return err;
98377b9900eSJiri Pirko 
98477b9900eSJiri Pirko 	fl_mask_update_range(mask);
98577b9900eSJiri Pirko 	fl_set_masked_key(&f->mkey, &f->key, mask);
98677b9900eSJiri Pirko 
987b95ec7ebSJiri Pirko 	if (!fl_mask_fits_tmplt(tmplt, mask)) {
988b95ec7ebSJiri Pirko 		NL_SET_ERR_MSG_MOD(extack, "Mask does not fit the template");
989b95ec7ebSJiri Pirko 		return -EINVAL;
990b95ec7ebSJiri Pirko 	}
991b95ec7ebSJiri Pirko 
99277b9900eSJiri Pirko 	return 0;
99377b9900eSJiri Pirko }
99477b9900eSJiri Pirko 
99577b9900eSJiri Pirko static int fl_change(struct net *net, struct sk_buff *in_skb,
99677b9900eSJiri Pirko 		     struct tcf_proto *tp, unsigned long base,
99777b9900eSJiri Pirko 		     u32 handle, struct nlattr **tca,
9987306db38SAlexander Aring 		     void **arg, bool ovr, struct netlink_ext_ack *extack)
99977b9900eSJiri Pirko {
100077b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
10018113c095SWANG Cong 	struct cls_fl_filter *fold = *arg;
100277b9900eSJiri Pirko 	struct cls_fl_filter *fnew;
100339b7b6a6SArnd Bergmann 	struct nlattr **tb;
100477b9900eSJiri Pirko 	struct fl_flow_mask mask = {};
100577b9900eSJiri Pirko 	int err;
100677b9900eSJiri Pirko 
100777b9900eSJiri Pirko 	if (!tca[TCA_OPTIONS])
100877b9900eSJiri Pirko 		return -EINVAL;
100977b9900eSJiri Pirko 
101039b7b6a6SArnd Bergmann 	tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL);
101139b7b6a6SArnd Bergmann 	if (!tb)
101239b7b6a6SArnd Bergmann 		return -ENOBUFS;
101339b7b6a6SArnd Bergmann 
1014fceb6435SJohannes Berg 	err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS],
1015fceb6435SJohannes Berg 			       fl_policy, NULL);
101677b9900eSJiri Pirko 	if (err < 0)
101739b7b6a6SArnd Bergmann 		goto errout_tb;
101877b9900eSJiri Pirko 
101939b7b6a6SArnd Bergmann 	if (fold && handle && fold->handle != handle) {
102039b7b6a6SArnd Bergmann 		err = -EINVAL;
102139b7b6a6SArnd Bergmann 		goto errout_tb;
102239b7b6a6SArnd Bergmann 	}
102377b9900eSJiri Pirko 
102477b9900eSJiri Pirko 	fnew = kzalloc(sizeof(*fnew), GFP_KERNEL);
102539b7b6a6SArnd Bergmann 	if (!fnew) {
102639b7b6a6SArnd Bergmann 		err = -ENOBUFS;
102739b7b6a6SArnd Bergmann 		goto errout_tb;
102839b7b6a6SArnd Bergmann 	}
102977b9900eSJiri Pirko 
1030b9a24bb7SWANG Cong 	err = tcf_exts_init(&fnew->exts, TCA_FLOWER_ACT, 0);
1031b9a24bb7SWANG Cong 	if (err < 0)
1032b9a24bb7SWANG Cong 		goto errout;
103377b9900eSJiri Pirko 
103477b9900eSJiri Pirko 	if (!handle) {
103585bd0438SMatthew Wilcox 		handle = 1;
103685bd0438SMatthew Wilcox 		err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
103785bd0438SMatthew Wilcox 				    INT_MAX, GFP_KERNEL);
103885bd0438SMatthew Wilcox 	} else if (!fold) {
1039c15ab236SChris Mi 		/* user specifies a handle and it doesn't exist */
104085bd0438SMatthew Wilcox 		err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
104185bd0438SMatthew Wilcox 				    handle, GFP_KERNEL);
104285bd0438SMatthew Wilcox 	}
1043c15ab236SChris Mi 	if (err)
1044c15ab236SChris Mi 		goto errout;
104585bd0438SMatthew Wilcox 	fnew->handle = handle;
104677b9900eSJiri Pirko 
1047e69985c6SAmir Vadai 	if (tb[TCA_FLOWER_FLAGS]) {
1048e69985c6SAmir Vadai 		fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
1049e69985c6SAmir Vadai 
1050e69985c6SAmir Vadai 		if (!tc_flags_valid(fnew->flags)) {
1051e69985c6SAmir Vadai 			err = -EINVAL;
1052fe2502e4SCong Wang 			goto errout_idr;
1053e69985c6SAmir Vadai 		}
1054e69985c6SAmir Vadai 	}
10555b33f488SAmir Vadai 
105650a56190SAlexander Aring 	err = fl_set_parms(net, tp, fnew, &mask, base, tb, tca[TCA_RATE], ovr,
1057b95ec7ebSJiri Pirko 			   tp->chain->tmplt_priv, extack);
105877b9900eSJiri Pirko 	if (err)
1059fe2502e4SCong Wang 		goto errout_idr;
106077b9900eSJiri Pirko 
106105cd271fSPaul Blakey 	err = fl_check_assign_mask(head, fnew, fold, &mask);
106277b9900eSJiri Pirko 	if (err)
1063fe2502e4SCong Wang 		goto errout_idr;
106477b9900eSJiri Pirko 
1065e8eb36cdSAmir Vadai 	if (!tc_skip_sw(fnew->flags)) {
106605cd271fSPaul Blakey 		if (!fold && fl_lookup(fnew->mask, &fnew->mkey)) {
1067a3308d8fSPaul Blakey 			err = -EEXIST;
106805cd271fSPaul Blakey 			goto errout_mask;
1069a3308d8fSPaul Blakey 		}
1070a3308d8fSPaul Blakey 
107105cd271fSPaul Blakey 		err = rhashtable_insert_fast(&fnew->mask->ht, &fnew->ht_node,
107205cd271fSPaul Blakey 					     fnew->mask->filter_ht_params);
107377b9900eSJiri Pirko 		if (err)
107405cd271fSPaul Blakey 			goto errout_mask;
1075e69985c6SAmir Vadai 	}
10765b33f488SAmir Vadai 
107779685219SHadar Hen Zion 	if (!tc_skip_hw(fnew->flags)) {
107805cd271fSPaul Blakey 		err = fl_hw_replace_filter(tp, fnew, extack);
1079e8eb36cdSAmir Vadai 		if (err)
108005cd271fSPaul Blakey 			goto errout_mask;
108179685219SHadar Hen Zion 	}
10825b33f488SAmir Vadai 
108355593960SOr Gerlitz 	if (!tc_in_hw(fnew->flags))
108455593960SOr Gerlitz 		fnew->flags |= TCA_CLS_FLAGS_NOT_IN_HW;
108555593960SOr Gerlitz 
10865b33f488SAmir Vadai 	if (fold) {
1087725cbb62SJiri Pirko 		if (!tc_skip_sw(fold->flags))
108805cd271fSPaul Blakey 			rhashtable_remove_fast(&fold->mask->ht,
108905cd271fSPaul Blakey 					       &fold->ht_node,
109005cd271fSPaul Blakey 					       fold->mask->filter_ht_params);
109179685219SHadar Hen Zion 		if (!tc_skip_hw(fold->flags))
10921b0f8037SJakub Kicinski 			fl_hw_destroy_filter(tp, fold, NULL);
10935b33f488SAmir Vadai 	}
109477b9900eSJiri Pirko 
10958113c095SWANG Cong 	*arg = fnew;
109677b9900eSJiri Pirko 
109777b9900eSJiri Pirko 	if (fold) {
1098234a4624SMatthew Wilcox 		idr_replace(&head->handle_idr, fnew, fnew->handle);
1099ff3532f2SDaniel Borkmann 		list_replace_rcu(&fold->list, &fnew->list);
110077b9900eSJiri Pirko 		tcf_unbind_filter(tp, &fold->res);
11010dadc117SCong Wang 		tcf_exts_get_net(&fold->exts);
1102aaa908ffSCong Wang 		tcf_queue_work(&fold->rwork, fl_destroy_filter_work);
110377b9900eSJiri Pirko 	} else {
110405cd271fSPaul Blakey 		list_add_tail_rcu(&fnew->list, &fnew->mask->filters);
110577b9900eSJiri Pirko 	}
110677b9900eSJiri Pirko 
110739b7b6a6SArnd Bergmann 	kfree(tb);
110877b9900eSJiri Pirko 	return 0;
110977b9900eSJiri Pirko 
111005cd271fSPaul Blakey errout_mask:
111105cd271fSPaul Blakey 	fl_mask_put(head, fnew->mask, false);
111205cd271fSPaul Blakey 
1113fe2502e4SCong Wang errout_idr:
11148258d2daSPaul Blakey 	if (!fold)
11159c160941SMatthew Wilcox 		idr_remove(&head->handle_idr, fnew->handle);
111677b9900eSJiri Pirko errout:
1117b9a24bb7SWANG Cong 	tcf_exts_destroy(&fnew->exts);
111877b9900eSJiri Pirko 	kfree(fnew);
111939b7b6a6SArnd Bergmann errout_tb:
112039b7b6a6SArnd Bergmann 	kfree(tb);
112177b9900eSJiri Pirko 	return err;
112277b9900eSJiri Pirko }
112377b9900eSJiri Pirko 
1124571acf21SAlexander Aring static int fl_delete(struct tcf_proto *tp, void *arg, bool *last,
1125571acf21SAlexander Aring 		     struct netlink_ext_ack *extack)
112677b9900eSJiri Pirko {
112777b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
11288113c095SWANG Cong 	struct cls_fl_filter *f = arg;
112977b9900eSJiri Pirko 
1130725cbb62SJiri Pirko 	if (!tc_skip_sw(f->flags))
113105cd271fSPaul Blakey 		rhashtable_remove_fast(&f->mask->ht, &f->ht_node,
113205cd271fSPaul Blakey 				       f->mask->filter_ht_params);
11331b0f8037SJakub Kicinski 	__fl_delete(tp, f, extack);
113405cd271fSPaul Blakey 	*last = list_empty(&head->masks);
113577b9900eSJiri Pirko 	return 0;
113677b9900eSJiri Pirko }
113777b9900eSJiri Pirko 
113877b9900eSJiri Pirko static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg)
113977b9900eSJiri Pirko {
114077b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
114177b9900eSJiri Pirko 	struct cls_fl_filter *f;
114277b9900eSJiri Pirko 
114301683a14SVlad Buslov 	arg->count = arg->skip;
114401683a14SVlad Buslov 
114501683a14SVlad Buslov 	while ((f = idr_get_next_ul(&head->handle_idr,
114601683a14SVlad Buslov 				    &arg->cookie)) != NULL) {
11478113c095SWANG Cong 		if (arg->fn(tp, f, arg) < 0) {
114877b9900eSJiri Pirko 			arg->stop = 1;
114977b9900eSJiri Pirko 			break;
115077b9900eSJiri Pirko 		}
115101683a14SVlad Buslov 		arg->cookie = f->handle + 1;
115277b9900eSJiri Pirko 		arg->count++;
115377b9900eSJiri Pirko 	}
115477b9900eSJiri Pirko }
115577b9900eSJiri Pirko 
115631533cbaSJohn Hurley static int fl_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb,
115731533cbaSJohn Hurley 			void *cb_priv, struct netlink_ext_ack *extack)
115831533cbaSJohn Hurley {
115931533cbaSJohn Hurley 	struct cls_fl_head *head = rtnl_dereference(tp->root);
116031533cbaSJohn Hurley 	struct tc_cls_flower_offload cls_flower = {};
116131533cbaSJohn Hurley 	struct tcf_block *block = tp->chain->block;
116231533cbaSJohn Hurley 	struct fl_flow_mask *mask;
116331533cbaSJohn Hurley 	struct cls_fl_filter *f;
116431533cbaSJohn Hurley 	int err;
116531533cbaSJohn Hurley 
116631533cbaSJohn Hurley 	list_for_each_entry(mask, &head->masks, list) {
116731533cbaSJohn Hurley 		list_for_each_entry(f, &mask->filters, list) {
116831533cbaSJohn Hurley 			if (tc_skip_hw(f->flags))
116931533cbaSJohn Hurley 				continue;
117031533cbaSJohn Hurley 
117131533cbaSJohn Hurley 			tc_cls_common_offload_init(&cls_flower.common, tp,
117231533cbaSJohn Hurley 						   f->flags, extack);
117331533cbaSJohn Hurley 			cls_flower.command = add ?
117431533cbaSJohn Hurley 				TC_CLSFLOWER_REPLACE : TC_CLSFLOWER_DESTROY;
117531533cbaSJohn Hurley 			cls_flower.cookie = (unsigned long)f;
117631533cbaSJohn Hurley 			cls_flower.dissector = &mask->dissector;
117731533cbaSJohn Hurley 			cls_flower.mask = &f->mkey;
117831533cbaSJohn Hurley 			cls_flower.key = &f->key;
117931533cbaSJohn Hurley 			cls_flower.exts = &f->exts;
118031533cbaSJohn Hurley 			cls_flower.classid = f->res.classid;
118131533cbaSJohn Hurley 
118231533cbaSJohn Hurley 			err = cb(TC_SETUP_CLSFLOWER, &cls_flower, cb_priv);
118331533cbaSJohn Hurley 			if (err) {
118431533cbaSJohn Hurley 				if (add && tc_skip_sw(f->flags))
118531533cbaSJohn Hurley 					return err;
118631533cbaSJohn Hurley 				continue;
118731533cbaSJohn Hurley 			}
118831533cbaSJohn Hurley 
118931533cbaSJohn Hurley 			tc_cls_offload_cnt_update(block, &f->in_hw_count,
119031533cbaSJohn Hurley 						  &f->flags, add);
119131533cbaSJohn Hurley 		}
119231533cbaSJohn Hurley 	}
119331533cbaSJohn Hurley 
119431533cbaSJohn Hurley 	return 0;
119531533cbaSJohn Hurley }
119631533cbaSJohn Hurley 
119734738452SJiri Pirko static void fl_hw_create_tmplt(struct tcf_chain *chain,
119834738452SJiri Pirko 			       struct fl_flow_tmplt *tmplt)
119934738452SJiri Pirko {
120034738452SJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
120134738452SJiri Pirko 	struct tcf_block *block = chain->block;
120234738452SJiri Pirko 	struct tcf_exts dummy_exts = { 0, };
120334738452SJiri Pirko 
120434738452SJiri Pirko 	cls_flower.common.chain_index = chain->index;
120534738452SJiri Pirko 	cls_flower.command = TC_CLSFLOWER_TMPLT_CREATE;
120634738452SJiri Pirko 	cls_flower.cookie = (unsigned long) tmplt;
120734738452SJiri Pirko 	cls_flower.dissector = &tmplt->dissector;
120834738452SJiri Pirko 	cls_flower.mask = &tmplt->mask;
120934738452SJiri Pirko 	cls_flower.key = &tmplt->dummy_key;
121034738452SJiri Pirko 	cls_flower.exts = &dummy_exts;
121134738452SJiri Pirko 
121234738452SJiri Pirko 	/* We don't care if driver (any of them) fails to handle this
121334738452SJiri Pirko 	 * call. It serves just as a hint for it.
121434738452SJiri Pirko 	 */
121534738452SJiri Pirko 	tc_setup_cb_call(block, NULL, TC_SETUP_CLSFLOWER,
121634738452SJiri Pirko 			 &cls_flower, false);
121734738452SJiri Pirko }
121834738452SJiri Pirko 
121934738452SJiri Pirko static void fl_hw_destroy_tmplt(struct tcf_chain *chain,
122034738452SJiri Pirko 				struct fl_flow_tmplt *tmplt)
122134738452SJiri Pirko {
122234738452SJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
122334738452SJiri Pirko 	struct tcf_block *block = chain->block;
122434738452SJiri Pirko 
122534738452SJiri Pirko 	cls_flower.common.chain_index = chain->index;
122634738452SJiri Pirko 	cls_flower.command = TC_CLSFLOWER_TMPLT_DESTROY;
122734738452SJiri Pirko 	cls_flower.cookie = (unsigned long) tmplt;
122834738452SJiri Pirko 
122934738452SJiri Pirko 	tc_setup_cb_call(block, NULL, TC_SETUP_CLSFLOWER,
123034738452SJiri Pirko 			 &cls_flower, false);
123134738452SJiri Pirko }
123234738452SJiri Pirko 
1233b95ec7ebSJiri Pirko static void *fl_tmplt_create(struct net *net, struct tcf_chain *chain,
1234b95ec7ebSJiri Pirko 			     struct nlattr **tca,
1235b95ec7ebSJiri Pirko 			     struct netlink_ext_ack *extack)
1236b95ec7ebSJiri Pirko {
1237b95ec7ebSJiri Pirko 	struct fl_flow_tmplt *tmplt;
1238b95ec7ebSJiri Pirko 	struct nlattr **tb;
1239b95ec7ebSJiri Pirko 	int err;
1240b95ec7ebSJiri Pirko 
1241b95ec7ebSJiri Pirko 	if (!tca[TCA_OPTIONS])
1242b95ec7ebSJiri Pirko 		return ERR_PTR(-EINVAL);
1243b95ec7ebSJiri Pirko 
1244b95ec7ebSJiri Pirko 	tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL);
1245b95ec7ebSJiri Pirko 	if (!tb)
1246b95ec7ebSJiri Pirko 		return ERR_PTR(-ENOBUFS);
1247b95ec7ebSJiri Pirko 	err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS],
1248b95ec7ebSJiri Pirko 			       fl_policy, NULL);
1249b95ec7ebSJiri Pirko 	if (err)
1250b95ec7ebSJiri Pirko 		goto errout_tb;
1251b95ec7ebSJiri Pirko 
1252b95ec7ebSJiri Pirko 	tmplt = kzalloc(sizeof(*tmplt), GFP_KERNEL);
1253*1cbc36a5SDan Carpenter 	if (!tmplt) {
1254*1cbc36a5SDan Carpenter 		err = -ENOMEM;
1255b95ec7ebSJiri Pirko 		goto errout_tb;
1256*1cbc36a5SDan Carpenter 	}
1257b95ec7ebSJiri Pirko 	tmplt->chain = chain;
1258b95ec7ebSJiri Pirko 	err = fl_set_key(net, tb, &tmplt->dummy_key, &tmplt->mask, extack);
1259b95ec7ebSJiri Pirko 	if (err)
1260b95ec7ebSJiri Pirko 		goto errout_tmplt;
1261b95ec7ebSJiri Pirko 	kfree(tb);
1262b95ec7ebSJiri Pirko 
1263b95ec7ebSJiri Pirko 	fl_init_dissector(&tmplt->dissector, &tmplt->mask);
1264b95ec7ebSJiri Pirko 
126534738452SJiri Pirko 	fl_hw_create_tmplt(chain, tmplt);
126634738452SJiri Pirko 
1267b95ec7ebSJiri Pirko 	return tmplt;
1268b95ec7ebSJiri Pirko 
1269b95ec7ebSJiri Pirko errout_tmplt:
1270b95ec7ebSJiri Pirko 	kfree(tmplt);
1271b95ec7ebSJiri Pirko errout_tb:
1272b95ec7ebSJiri Pirko 	kfree(tb);
1273b95ec7ebSJiri Pirko 	return ERR_PTR(err);
1274b95ec7ebSJiri Pirko }
1275b95ec7ebSJiri Pirko 
1276b95ec7ebSJiri Pirko static void fl_tmplt_destroy(void *tmplt_priv)
1277b95ec7ebSJiri Pirko {
1278b95ec7ebSJiri Pirko 	struct fl_flow_tmplt *tmplt = tmplt_priv;
1279b95ec7ebSJiri Pirko 
128034738452SJiri Pirko 	fl_hw_destroy_tmplt(tmplt->chain, tmplt);
1281b95ec7ebSJiri Pirko 	kfree(tmplt);
1282b95ec7ebSJiri Pirko }
1283b95ec7ebSJiri Pirko 
128477b9900eSJiri Pirko static int fl_dump_key_val(struct sk_buff *skb,
128577b9900eSJiri Pirko 			   void *val, int val_type,
128677b9900eSJiri Pirko 			   void *mask, int mask_type, int len)
128777b9900eSJiri Pirko {
128877b9900eSJiri Pirko 	int err;
128977b9900eSJiri Pirko 
129077b9900eSJiri Pirko 	if (!memchr_inv(mask, 0, len))
129177b9900eSJiri Pirko 		return 0;
129277b9900eSJiri Pirko 	err = nla_put(skb, val_type, len, val);
129377b9900eSJiri Pirko 	if (err)
129477b9900eSJiri Pirko 		return err;
129577b9900eSJiri Pirko 	if (mask_type != TCA_FLOWER_UNSPEC) {
129677b9900eSJiri Pirko 		err = nla_put(skb, mask_type, len, mask);
129777b9900eSJiri Pirko 		if (err)
129877b9900eSJiri Pirko 			return err;
129977b9900eSJiri Pirko 	}
130077b9900eSJiri Pirko 	return 0;
130177b9900eSJiri Pirko }
130277b9900eSJiri Pirko 
1303a577d8f7SBenjamin LaHaise static int fl_dump_key_mpls(struct sk_buff *skb,
1304a577d8f7SBenjamin LaHaise 			    struct flow_dissector_key_mpls *mpls_key,
1305a577d8f7SBenjamin LaHaise 			    struct flow_dissector_key_mpls *mpls_mask)
1306a577d8f7SBenjamin LaHaise {
1307a577d8f7SBenjamin LaHaise 	int err;
1308a577d8f7SBenjamin LaHaise 
1309a577d8f7SBenjamin LaHaise 	if (!memchr_inv(mpls_mask, 0, sizeof(*mpls_mask)))
1310a577d8f7SBenjamin LaHaise 		return 0;
1311a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_ttl) {
1312a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TTL,
1313a577d8f7SBenjamin LaHaise 				 mpls_key->mpls_ttl);
1314a577d8f7SBenjamin LaHaise 		if (err)
1315a577d8f7SBenjamin LaHaise 			return err;
1316a577d8f7SBenjamin LaHaise 	}
1317a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_tc) {
1318a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TC,
1319a577d8f7SBenjamin LaHaise 				 mpls_key->mpls_tc);
1320a577d8f7SBenjamin LaHaise 		if (err)
1321a577d8f7SBenjamin LaHaise 			return err;
1322a577d8f7SBenjamin LaHaise 	}
1323a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_label) {
1324a577d8f7SBenjamin LaHaise 		err = nla_put_u32(skb, TCA_FLOWER_KEY_MPLS_LABEL,
1325a577d8f7SBenjamin LaHaise 				  mpls_key->mpls_label);
1326a577d8f7SBenjamin LaHaise 		if (err)
1327a577d8f7SBenjamin LaHaise 			return err;
1328a577d8f7SBenjamin LaHaise 	}
1329a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_bos) {
1330a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_BOS,
1331a577d8f7SBenjamin LaHaise 				 mpls_key->mpls_bos);
1332a577d8f7SBenjamin LaHaise 		if (err)
1333a577d8f7SBenjamin LaHaise 			return err;
1334a577d8f7SBenjamin LaHaise 	}
1335a577d8f7SBenjamin LaHaise 	return 0;
1336a577d8f7SBenjamin LaHaise }
1337a577d8f7SBenjamin LaHaise 
13380e2c17b6SOr Gerlitz static int fl_dump_key_ip(struct sk_buff *skb, bool encap,
13394d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *key,
13404d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *mask)
13414d80cc0aSOr Gerlitz {
13420e2c17b6SOr Gerlitz 	int tos_key = encap ? TCA_FLOWER_KEY_ENC_IP_TOS : TCA_FLOWER_KEY_IP_TOS;
13430e2c17b6SOr Gerlitz 	int ttl_key = encap ? TCA_FLOWER_KEY_ENC_IP_TTL : TCA_FLOWER_KEY_IP_TTL;
13440e2c17b6SOr Gerlitz 	int tos_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TOS_MASK : TCA_FLOWER_KEY_IP_TOS_MASK;
13450e2c17b6SOr Gerlitz 	int ttl_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TTL_MASK : TCA_FLOWER_KEY_IP_TTL_MASK;
13460e2c17b6SOr Gerlitz 
13470e2c17b6SOr Gerlitz 	if (fl_dump_key_val(skb, &key->tos, tos_key, &mask->tos, tos_mask, sizeof(key->tos)) ||
13480e2c17b6SOr Gerlitz 	    fl_dump_key_val(skb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl)))
13494d80cc0aSOr Gerlitz 		return -1;
13504d80cc0aSOr Gerlitz 
13514d80cc0aSOr Gerlitz 	return 0;
13524d80cc0aSOr Gerlitz }
13534d80cc0aSOr Gerlitz 
13549399ae9aSHadar Hen Zion static int fl_dump_key_vlan(struct sk_buff *skb,
1355d64efd09SJianbo Liu 			    int vlan_id_key, int vlan_prio_key,
13569399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *vlan_key,
13579399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *vlan_mask)
13589399ae9aSHadar Hen Zion {
13599399ae9aSHadar Hen Zion 	int err;
13609399ae9aSHadar Hen Zion 
13619399ae9aSHadar Hen Zion 	if (!memchr_inv(vlan_mask, 0, sizeof(*vlan_mask)))
13629399ae9aSHadar Hen Zion 		return 0;
13639399ae9aSHadar Hen Zion 	if (vlan_mask->vlan_id) {
1364d64efd09SJianbo Liu 		err = nla_put_u16(skb, vlan_id_key,
13659399ae9aSHadar Hen Zion 				  vlan_key->vlan_id);
13669399ae9aSHadar Hen Zion 		if (err)
13679399ae9aSHadar Hen Zion 			return err;
13689399ae9aSHadar Hen Zion 	}
13699399ae9aSHadar Hen Zion 	if (vlan_mask->vlan_priority) {
1370d64efd09SJianbo Liu 		err = nla_put_u8(skb, vlan_prio_key,
13719399ae9aSHadar Hen Zion 				 vlan_key->vlan_priority);
13729399ae9aSHadar Hen Zion 		if (err)
13739399ae9aSHadar Hen Zion 			return err;
13749399ae9aSHadar Hen Zion 	}
13759399ae9aSHadar Hen Zion 	return 0;
13769399ae9aSHadar Hen Zion }
13779399ae9aSHadar Hen Zion 
1378faa3ffceSOr Gerlitz static void fl_get_key_flag(u32 dissector_key, u32 dissector_mask,
1379faa3ffceSOr Gerlitz 			    u32 *flower_key, u32 *flower_mask,
1380faa3ffceSOr Gerlitz 			    u32 flower_flag_bit, u32 dissector_flag_bit)
1381faa3ffceSOr Gerlitz {
1382faa3ffceSOr Gerlitz 	if (dissector_mask & dissector_flag_bit) {
1383faa3ffceSOr Gerlitz 		*flower_mask |= flower_flag_bit;
1384faa3ffceSOr Gerlitz 		if (dissector_key & dissector_flag_bit)
1385faa3ffceSOr Gerlitz 			*flower_key |= flower_flag_bit;
1386faa3ffceSOr Gerlitz 	}
1387faa3ffceSOr Gerlitz }
1388faa3ffceSOr Gerlitz 
1389faa3ffceSOr Gerlitz static int fl_dump_key_flags(struct sk_buff *skb, u32 flags_key, u32 flags_mask)
1390faa3ffceSOr Gerlitz {
1391faa3ffceSOr Gerlitz 	u32 key, mask;
1392faa3ffceSOr Gerlitz 	__be32 _key, _mask;
1393faa3ffceSOr Gerlitz 	int err;
1394faa3ffceSOr Gerlitz 
1395faa3ffceSOr Gerlitz 	if (!memchr_inv(&flags_mask, 0, sizeof(flags_mask)))
1396faa3ffceSOr Gerlitz 		return 0;
1397faa3ffceSOr Gerlitz 
1398faa3ffceSOr Gerlitz 	key = 0;
1399faa3ffceSOr Gerlitz 	mask = 0;
1400faa3ffceSOr Gerlitz 
1401faa3ffceSOr Gerlitz 	fl_get_key_flag(flags_key, flags_mask, &key, &mask,
1402faa3ffceSOr Gerlitz 			TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT);
1403459d153dSPieter Jansen van Vuuren 	fl_get_key_flag(flags_key, flags_mask, &key, &mask,
1404459d153dSPieter Jansen van Vuuren 			TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST,
1405459d153dSPieter Jansen van Vuuren 			FLOW_DIS_FIRST_FRAG);
1406faa3ffceSOr Gerlitz 
1407faa3ffceSOr Gerlitz 	_key = cpu_to_be32(key);
1408faa3ffceSOr Gerlitz 	_mask = cpu_to_be32(mask);
1409faa3ffceSOr Gerlitz 
1410faa3ffceSOr Gerlitz 	err = nla_put(skb, TCA_FLOWER_KEY_FLAGS, 4, &_key);
1411faa3ffceSOr Gerlitz 	if (err)
1412faa3ffceSOr Gerlitz 		return err;
1413faa3ffceSOr Gerlitz 
1414faa3ffceSOr Gerlitz 	return nla_put(skb, TCA_FLOWER_KEY_FLAGS_MASK, 4, &_mask);
1415faa3ffceSOr Gerlitz }
1416faa3ffceSOr Gerlitz 
1417f5749081SJiri Pirko static int fl_dump_key(struct sk_buff *skb, struct net *net,
1418f5749081SJiri Pirko 		       struct fl_flow_key *key, struct fl_flow_key *mask)
141977b9900eSJiri Pirko {
142077b9900eSJiri Pirko 	if (mask->indev_ifindex) {
142177b9900eSJiri Pirko 		struct net_device *dev;
142277b9900eSJiri Pirko 
142377b9900eSJiri Pirko 		dev = __dev_get_by_index(net, key->indev_ifindex);
142477b9900eSJiri Pirko 		if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name))
142577b9900eSJiri Pirko 			goto nla_put_failure;
142677b9900eSJiri Pirko 	}
142777b9900eSJiri Pirko 
142877b9900eSJiri Pirko 	if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
142977b9900eSJiri Pirko 			    mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
143077b9900eSJiri Pirko 			    sizeof(key->eth.dst)) ||
143177b9900eSJiri Pirko 	    fl_dump_key_val(skb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
143277b9900eSJiri Pirko 			    mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
143377b9900eSJiri Pirko 			    sizeof(key->eth.src)) ||
143477b9900eSJiri Pirko 	    fl_dump_key_val(skb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE,
143577b9900eSJiri Pirko 			    &mask->basic.n_proto, TCA_FLOWER_UNSPEC,
143677b9900eSJiri Pirko 			    sizeof(key->basic.n_proto)))
143777b9900eSJiri Pirko 		goto nla_put_failure;
14389399ae9aSHadar Hen Zion 
1439a577d8f7SBenjamin LaHaise 	if (fl_dump_key_mpls(skb, &key->mpls, &mask->mpls))
1440a577d8f7SBenjamin LaHaise 		goto nla_put_failure;
1441a577d8f7SBenjamin LaHaise 
1442d64efd09SJianbo Liu 	if (fl_dump_key_vlan(skb, TCA_FLOWER_KEY_VLAN_ID,
1443d64efd09SJianbo Liu 			     TCA_FLOWER_KEY_VLAN_PRIO, &key->vlan, &mask->vlan))
14449399ae9aSHadar Hen Zion 		goto nla_put_failure;
14459399ae9aSHadar Hen Zion 
1446d64efd09SJianbo Liu 	if (fl_dump_key_vlan(skb, TCA_FLOWER_KEY_CVLAN_ID,
1447d64efd09SJianbo Liu 			     TCA_FLOWER_KEY_CVLAN_PRIO,
1448d64efd09SJianbo Liu 			     &key->cvlan, &mask->cvlan) ||
1449d64efd09SJianbo Liu 	    (mask->cvlan.vlan_tpid &&
1450158abbf1SJianbo Liu 	     nla_put_be16(skb, TCA_FLOWER_KEY_VLAN_ETH_TYPE,
1451d64efd09SJianbo Liu 			  key->cvlan.vlan_tpid)))
1452d3069512SJianbo Liu 		goto nla_put_failure;
1453d3069512SJianbo Liu 
14545e9a0fe4SJianbo Liu 	if (mask->basic.n_proto) {
1455d64efd09SJianbo Liu 		if (mask->cvlan.vlan_tpid) {
1456d64efd09SJianbo Liu 			if (nla_put_be16(skb, TCA_FLOWER_KEY_CVLAN_ETH_TYPE,
1457d64efd09SJianbo Liu 					 key->basic.n_proto))
1458d64efd09SJianbo Liu 				goto nla_put_failure;
1459d64efd09SJianbo Liu 		} else if (mask->vlan.vlan_tpid) {
1460d64efd09SJianbo Liu 			if (nla_put_be16(skb, TCA_FLOWER_KEY_VLAN_ETH_TYPE,
1461d64efd09SJianbo Liu 					 key->basic.n_proto))
1462d64efd09SJianbo Liu 				goto nla_put_failure;
1463d64efd09SJianbo Liu 		}
14645e9a0fe4SJianbo Liu 	}
1465d64efd09SJianbo Liu 
146677b9900eSJiri Pirko 	if ((key->basic.n_proto == htons(ETH_P_IP) ||
146777b9900eSJiri Pirko 	     key->basic.n_proto == htons(ETH_P_IPV6)) &&
14684d80cc0aSOr Gerlitz 	    (fl_dump_key_val(skb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
146977b9900eSJiri Pirko 			    &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
14704d80cc0aSOr Gerlitz 			    sizeof(key->basic.ip_proto)) ||
14710e2c17b6SOr Gerlitz 	    fl_dump_key_ip(skb, false, &key->ip, &mask->ip)))
147277b9900eSJiri Pirko 		goto nla_put_failure;
147377b9900eSJiri Pirko 
1474c3f83241STom Herbert 	if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
147577b9900eSJiri Pirko 	    (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
147677b9900eSJiri Pirko 			     &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
147777b9900eSJiri Pirko 			     sizeof(key->ipv4.src)) ||
147877b9900eSJiri Pirko 	     fl_dump_key_val(skb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
147977b9900eSJiri Pirko 			     &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
148077b9900eSJiri Pirko 			     sizeof(key->ipv4.dst))))
148177b9900eSJiri Pirko 		goto nla_put_failure;
1482c3f83241STom Herbert 	else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
148377b9900eSJiri Pirko 		 (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
148477b9900eSJiri Pirko 				  &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
148577b9900eSJiri Pirko 				  sizeof(key->ipv6.src)) ||
148677b9900eSJiri Pirko 		  fl_dump_key_val(skb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
148777b9900eSJiri Pirko 				  &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
148877b9900eSJiri Pirko 				  sizeof(key->ipv6.dst))))
148977b9900eSJiri Pirko 		goto nla_put_failure;
149077b9900eSJiri Pirko 
149177b9900eSJiri Pirko 	if (key->basic.ip_proto == IPPROTO_TCP &&
149277b9900eSJiri Pirko 	    (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
1493aa72d708SOr Gerlitz 			     &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
149477b9900eSJiri Pirko 			     sizeof(key->tp.src)) ||
149577b9900eSJiri Pirko 	     fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
1496aa72d708SOr Gerlitz 			     &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
1497fdfc7dd6SJiri Pirko 			     sizeof(key->tp.dst)) ||
1498fdfc7dd6SJiri Pirko 	     fl_dump_key_val(skb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS,
1499fdfc7dd6SJiri Pirko 			     &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK,
1500fdfc7dd6SJiri Pirko 			     sizeof(key->tcp.flags))))
150177b9900eSJiri Pirko 		goto nla_put_failure;
150277b9900eSJiri Pirko 	else if (key->basic.ip_proto == IPPROTO_UDP &&
150377b9900eSJiri Pirko 		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
1504aa72d708SOr Gerlitz 				  &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
150577b9900eSJiri Pirko 				  sizeof(key->tp.src)) ||
150677b9900eSJiri Pirko 		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
1507aa72d708SOr Gerlitz 				  &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
150877b9900eSJiri Pirko 				  sizeof(key->tp.dst))))
150977b9900eSJiri Pirko 		goto nla_put_failure;
15105976c5f4SSimon Horman 	else if (key->basic.ip_proto == IPPROTO_SCTP &&
15115976c5f4SSimon Horman 		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
15125976c5f4SSimon Horman 				  &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
15135976c5f4SSimon Horman 				  sizeof(key->tp.src)) ||
15145976c5f4SSimon Horman 		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
15155976c5f4SSimon Horman 				  &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
15165976c5f4SSimon Horman 				  sizeof(key->tp.dst))))
15175976c5f4SSimon Horman 		goto nla_put_failure;
15187b684884SSimon Horman 	else if (key->basic.n_proto == htons(ETH_P_IP) &&
15197b684884SSimon Horman 		 key->basic.ip_proto == IPPROTO_ICMP &&
15207b684884SSimon Horman 		 (fl_dump_key_val(skb, &key->icmp.type,
15217b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_TYPE, &mask->icmp.type,
15227b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,
15237b684884SSimon Horman 				  sizeof(key->icmp.type)) ||
15247b684884SSimon Horman 		  fl_dump_key_val(skb, &key->icmp.code,
15257b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_CODE, &mask->icmp.code,
15267b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
15277b684884SSimon Horman 				  sizeof(key->icmp.code))))
15287b684884SSimon Horman 		goto nla_put_failure;
15297b684884SSimon Horman 	else if (key->basic.n_proto == htons(ETH_P_IPV6) &&
15307b684884SSimon Horman 		 key->basic.ip_proto == IPPROTO_ICMPV6 &&
15317b684884SSimon Horman 		 (fl_dump_key_val(skb, &key->icmp.type,
15327b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_TYPE, &mask->icmp.type,
15337b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
15347b684884SSimon Horman 				  sizeof(key->icmp.type)) ||
15357b684884SSimon Horman 		  fl_dump_key_val(skb, &key->icmp.code,
15367b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_CODE, &mask->icmp.code,
15377b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_CODE_MASK,
15387b684884SSimon Horman 				  sizeof(key->icmp.code))))
15397b684884SSimon Horman 		goto nla_put_failure;
154099d31326SSimon Horman 	else if ((key->basic.n_proto == htons(ETH_P_ARP) ||
154199d31326SSimon Horman 		  key->basic.n_proto == htons(ETH_P_RARP)) &&
154299d31326SSimon Horman 		 (fl_dump_key_val(skb, &key->arp.sip,
154399d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_SIP, &mask->arp.sip,
154499d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_SIP_MASK,
154599d31326SSimon Horman 				  sizeof(key->arp.sip)) ||
154699d31326SSimon Horman 		  fl_dump_key_val(skb, &key->arp.tip,
154799d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_TIP, &mask->arp.tip,
154899d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_TIP_MASK,
154999d31326SSimon Horman 				  sizeof(key->arp.tip)) ||
155099d31326SSimon Horman 		  fl_dump_key_val(skb, &key->arp.op,
155199d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_OP, &mask->arp.op,
155299d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_OP_MASK,
155399d31326SSimon Horman 				  sizeof(key->arp.op)) ||
155499d31326SSimon Horman 		  fl_dump_key_val(skb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA,
155599d31326SSimon Horman 				  mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK,
155699d31326SSimon Horman 				  sizeof(key->arp.sha)) ||
155799d31326SSimon Horman 		  fl_dump_key_val(skb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA,
155899d31326SSimon Horman 				  mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK,
155999d31326SSimon Horman 				  sizeof(key->arp.tha))))
156099d31326SSimon Horman 		goto nla_put_failure;
156177b9900eSJiri Pirko 
1562bc3103f1SAmir Vadai 	if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
1563bc3103f1SAmir Vadai 	    (fl_dump_key_val(skb, &key->enc_ipv4.src,
1564bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV4_SRC, &mask->enc_ipv4.src,
1565bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
1566bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv4.src)) ||
1567bc3103f1SAmir Vadai 	     fl_dump_key_val(skb, &key->enc_ipv4.dst,
1568bc3103f1SAmir Vadai 			     TCA_FLOWER_KEY_ENC_IPV4_DST, &mask->enc_ipv4.dst,
1569bc3103f1SAmir Vadai 			     TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
1570bc3103f1SAmir Vadai 			     sizeof(key->enc_ipv4.dst))))
1571bc3103f1SAmir Vadai 		goto nla_put_failure;
1572bc3103f1SAmir Vadai 	else if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
1573bc3103f1SAmir Vadai 		 (fl_dump_key_val(skb, &key->enc_ipv6.src,
1574bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV6_SRC, &mask->enc_ipv6.src,
1575bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
1576bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv6.src)) ||
1577bc3103f1SAmir Vadai 		 fl_dump_key_val(skb, &key->enc_ipv6.dst,
1578bc3103f1SAmir Vadai 				 TCA_FLOWER_KEY_ENC_IPV6_DST,
1579bc3103f1SAmir Vadai 				 &mask->enc_ipv6.dst,
1580bc3103f1SAmir Vadai 				 TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
1581bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv6.dst))))
1582bc3103f1SAmir Vadai 		goto nla_put_failure;
1583bc3103f1SAmir Vadai 
1584bc3103f1SAmir Vadai 	if (fl_dump_key_val(skb, &key->enc_key_id, TCA_FLOWER_KEY_ENC_KEY_ID,
1585eb523f42SHadar Hen Zion 			    &mask->enc_key_id, TCA_FLOWER_UNSPEC,
1586f4d997fdSHadar Hen Zion 			    sizeof(key->enc_key_id)) ||
1587f4d997fdSHadar Hen Zion 	    fl_dump_key_val(skb, &key->enc_tp.src,
1588f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
1589f4d997fdSHadar Hen Zion 			    &mask->enc_tp.src,
1590f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
1591f4d997fdSHadar Hen Zion 			    sizeof(key->enc_tp.src)) ||
1592f4d997fdSHadar Hen Zion 	    fl_dump_key_val(skb, &key->enc_tp.dst,
1593f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
1594f4d997fdSHadar Hen Zion 			    &mask->enc_tp.dst,
1595f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
15960e2c17b6SOr Gerlitz 			    sizeof(key->enc_tp.dst)) ||
15970e2c17b6SOr Gerlitz 	    fl_dump_key_ip(skb, true, &key->enc_ip, &mask->enc_ip))
1598bc3103f1SAmir Vadai 		goto nla_put_failure;
1599bc3103f1SAmir Vadai 
1600faa3ffceSOr Gerlitz 	if (fl_dump_key_flags(skb, key->control.flags, mask->control.flags))
1601faa3ffceSOr Gerlitz 		goto nla_put_failure;
1602faa3ffceSOr Gerlitz 
1603f5749081SJiri Pirko 	return 0;
1604f5749081SJiri Pirko 
1605f5749081SJiri Pirko nla_put_failure:
1606f5749081SJiri Pirko 	return -EMSGSIZE;
1607f5749081SJiri Pirko }
1608f5749081SJiri Pirko 
1609f5749081SJiri Pirko static int fl_dump(struct net *net, struct tcf_proto *tp, void *fh,
1610f5749081SJiri Pirko 		   struct sk_buff *skb, struct tcmsg *t)
1611f5749081SJiri Pirko {
1612f5749081SJiri Pirko 	struct cls_fl_filter *f = fh;
1613f5749081SJiri Pirko 	struct nlattr *nest;
1614f5749081SJiri Pirko 	struct fl_flow_key *key, *mask;
1615f5749081SJiri Pirko 
1616f5749081SJiri Pirko 	if (!f)
1617f5749081SJiri Pirko 		return skb->len;
1618f5749081SJiri Pirko 
1619f5749081SJiri Pirko 	t->tcm_handle = f->handle;
1620f5749081SJiri Pirko 
1621f5749081SJiri Pirko 	nest = nla_nest_start(skb, TCA_OPTIONS);
1622f5749081SJiri Pirko 	if (!nest)
1623f5749081SJiri Pirko 		goto nla_put_failure;
1624f5749081SJiri Pirko 
1625f5749081SJiri Pirko 	if (f->res.classid &&
1626f5749081SJiri Pirko 	    nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid))
1627f5749081SJiri Pirko 		goto nla_put_failure;
1628f5749081SJiri Pirko 
1629f5749081SJiri Pirko 	key = &f->key;
1630f5749081SJiri Pirko 	mask = &f->mask->key;
1631f5749081SJiri Pirko 
1632f5749081SJiri Pirko 	if (fl_dump_key(skb, net, key, mask))
1633f5749081SJiri Pirko 		goto nla_put_failure;
1634f5749081SJiri Pirko 
1635f5749081SJiri Pirko 	if (!tc_skip_hw(f->flags))
1636f5749081SJiri Pirko 		fl_hw_update_stats(tp, f);
1637f5749081SJiri Pirko 
1638749e6720SOr Gerlitz 	if (f->flags && nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags))
1639749e6720SOr Gerlitz 		goto nla_put_failure;
1640e69985c6SAmir Vadai 
164177b9900eSJiri Pirko 	if (tcf_exts_dump(skb, &f->exts))
164277b9900eSJiri Pirko 		goto nla_put_failure;
164377b9900eSJiri Pirko 
164477b9900eSJiri Pirko 	nla_nest_end(skb, nest);
164577b9900eSJiri Pirko 
164677b9900eSJiri Pirko 	if (tcf_exts_dump_stats(skb, &f->exts) < 0)
164777b9900eSJiri Pirko 		goto nla_put_failure;
164877b9900eSJiri Pirko 
164977b9900eSJiri Pirko 	return skb->len;
165077b9900eSJiri Pirko 
165177b9900eSJiri Pirko nla_put_failure:
165277b9900eSJiri Pirko 	nla_nest_cancel(skb, nest);
165377b9900eSJiri Pirko 	return -1;
165477b9900eSJiri Pirko }
165577b9900eSJiri Pirko 
1656b95ec7ebSJiri Pirko static int fl_tmplt_dump(struct sk_buff *skb, struct net *net, void *tmplt_priv)
1657b95ec7ebSJiri Pirko {
1658b95ec7ebSJiri Pirko 	struct fl_flow_tmplt *tmplt = tmplt_priv;
1659b95ec7ebSJiri Pirko 	struct fl_flow_key *key, *mask;
1660b95ec7ebSJiri Pirko 	struct nlattr *nest;
1661b95ec7ebSJiri Pirko 
1662b95ec7ebSJiri Pirko 	nest = nla_nest_start(skb, TCA_OPTIONS);
1663b95ec7ebSJiri Pirko 	if (!nest)
1664b95ec7ebSJiri Pirko 		goto nla_put_failure;
1665b95ec7ebSJiri Pirko 
1666b95ec7ebSJiri Pirko 	key = &tmplt->dummy_key;
1667b95ec7ebSJiri Pirko 	mask = &tmplt->mask;
1668b95ec7ebSJiri Pirko 
1669b95ec7ebSJiri Pirko 	if (fl_dump_key(skb, net, key, mask))
1670b95ec7ebSJiri Pirko 		goto nla_put_failure;
1671b95ec7ebSJiri Pirko 
1672b95ec7ebSJiri Pirko 	nla_nest_end(skb, nest);
1673b95ec7ebSJiri Pirko 
1674b95ec7ebSJiri Pirko 	return skb->len;
1675b95ec7ebSJiri Pirko 
1676b95ec7ebSJiri Pirko nla_put_failure:
1677b95ec7ebSJiri Pirko 	nla_nest_cancel(skb, nest);
1678b95ec7ebSJiri Pirko 	return -EMSGSIZE;
1679b95ec7ebSJiri Pirko }
1680b95ec7ebSJiri Pirko 
168107d79fc7SCong Wang static void fl_bind_class(void *fh, u32 classid, unsigned long cl)
168207d79fc7SCong Wang {
168307d79fc7SCong Wang 	struct cls_fl_filter *f = fh;
168407d79fc7SCong Wang 
168507d79fc7SCong Wang 	if (f && f->res.classid == classid)
168607d79fc7SCong Wang 		f->res.class = cl;
168707d79fc7SCong Wang }
168807d79fc7SCong Wang 
168977b9900eSJiri Pirko static struct tcf_proto_ops cls_fl_ops __read_mostly = {
169077b9900eSJiri Pirko 	.kind		= "flower",
169177b9900eSJiri Pirko 	.classify	= fl_classify,
169277b9900eSJiri Pirko 	.init		= fl_init,
169377b9900eSJiri Pirko 	.destroy	= fl_destroy,
169477b9900eSJiri Pirko 	.get		= fl_get,
169577b9900eSJiri Pirko 	.change		= fl_change,
169677b9900eSJiri Pirko 	.delete		= fl_delete,
169777b9900eSJiri Pirko 	.walk		= fl_walk,
169831533cbaSJohn Hurley 	.reoffload	= fl_reoffload,
169977b9900eSJiri Pirko 	.dump		= fl_dump,
170007d79fc7SCong Wang 	.bind_class	= fl_bind_class,
1701b95ec7ebSJiri Pirko 	.tmplt_create	= fl_tmplt_create,
1702b95ec7ebSJiri Pirko 	.tmplt_destroy	= fl_tmplt_destroy,
1703b95ec7ebSJiri Pirko 	.tmplt_dump	= fl_tmplt_dump,
170477b9900eSJiri Pirko 	.owner		= THIS_MODULE,
170577b9900eSJiri Pirko };
170677b9900eSJiri Pirko 
170777b9900eSJiri Pirko static int __init cls_fl_init(void)
170877b9900eSJiri Pirko {
170977b9900eSJiri Pirko 	return register_tcf_proto_ops(&cls_fl_ops);
171077b9900eSJiri Pirko }
171177b9900eSJiri Pirko 
171277b9900eSJiri Pirko static void __exit cls_fl_exit(void)
171377b9900eSJiri Pirko {
171477b9900eSJiri Pirko 	unregister_tcf_proto_ops(&cls_fl_ops);
171577b9900eSJiri Pirko }
171677b9900eSJiri Pirko 
171777b9900eSJiri Pirko module_init(cls_fl_init);
171877b9900eSJiri Pirko module_exit(cls_fl_exit);
171977b9900eSJiri Pirko 
172077b9900eSJiri Pirko MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>");
172177b9900eSJiri Pirko MODULE_DESCRIPTION("Flower classifier");
172277b9900eSJiri Pirko MODULE_LICENSE("GPL v2");
1723