xref: /linux/net/sched/cls_flower.c (revision 33fb5cba11ff639c32f4f0104b04b2415fcd9ecc)
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 
7577b9900eSJiri Pirko struct cls_fl_head {
7677b9900eSJiri Pirko 	struct rhashtable ht;
7705cd271fSPaul Blakey 	struct list_head masks;
78aaa908ffSCong Wang 	struct rcu_work rwork;
79c15ab236SChris Mi 	struct idr handle_idr;
80d9363774SDaniel Borkmann };
8177b9900eSJiri Pirko 
8277b9900eSJiri Pirko struct cls_fl_filter {
8305cd271fSPaul Blakey 	struct fl_flow_mask *mask;
8477b9900eSJiri Pirko 	struct rhash_head ht_node;
8577b9900eSJiri Pirko 	struct fl_flow_key mkey;
8677b9900eSJiri Pirko 	struct tcf_exts exts;
8777b9900eSJiri Pirko 	struct tcf_result res;
8877b9900eSJiri Pirko 	struct fl_flow_key key;
8977b9900eSJiri Pirko 	struct list_head list;
9077b9900eSJiri Pirko 	u32 handle;
91e69985c6SAmir Vadai 	u32 flags;
9231533cbaSJohn Hurley 	unsigned int in_hw_count;
93aaa908ffSCong Wang 	struct rcu_work rwork;
947091d8c7SHadar Hen Zion 	struct net_device *hw_dev;
9577b9900eSJiri Pirko };
9677b9900eSJiri Pirko 
9705cd271fSPaul Blakey static const struct rhashtable_params mask_ht_params = {
9805cd271fSPaul Blakey 	.key_offset = offsetof(struct fl_flow_mask, key),
9905cd271fSPaul Blakey 	.key_len = sizeof(struct fl_flow_key),
10005cd271fSPaul Blakey 	.head_offset = offsetof(struct fl_flow_mask, ht_node),
10105cd271fSPaul Blakey 	.automatic_shrinking = true,
10205cd271fSPaul Blakey };
10305cd271fSPaul Blakey 
10477b9900eSJiri Pirko static unsigned short int fl_mask_range(const struct fl_flow_mask *mask)
10577b9900eSJiri Pirko {
10677b9900eSJiri Pirko 	return mask->range.end - mask->range.start;
10777b9900eSJiri Pirko }
10877b9900eSJiri Pirko 
10977b9900eSJiri Pirko static void fl_mask_update_range(struct fl_flow_mask *mask)
11077b9900eSJiri Pirko {
11177b9900eSJiri Pirko 	const u8 *bytes = (const u8 *) &mask->key;
11277b9900eSJiri Pirko 	size_t size = sizeof(mask->key);
11305cd271fSPaul Blakey 	size_t i, first = 0, last;
11477b9900eSJiri Pirko 
11505cd271fSPaul Blakey 	for (i = 0; i < size; i++) {
11677b9900eSJiri Pirko 		if (bytes[i]) {
11777b9900eSJiri Pirko 			first = i;
11805cd271fSPaul Blakey 			break;
11905cd271fSPaul Blakey 		}
12005cd271fSPaul Blakey 	}
12105cd271fSPaul Blakey 	last = first;
12205cd271fSPaul Blakey 	for (i = size - 1; i != first; i--) {
12305cd271fSPaul Blakey 		if (bytes[i]) {
12477b9900eSJiri Pirko 			last = i;
12505cd271fSPaul Blakey 			break;
12677b9900eSJiri Pirko 		}
12777b9900eSJiri Pirko 	}
12877b9900eSJiri Pirko 	mask->range.start = rounddown(first, sizeof(long));
12977b9900eSJiri Pirko 	mask->range.end = roundup(last + 1, sizeof(long));
13077b9900eSJiri Pirko }
13177b9900eSJiri Pirko 
13277b9900eSJiri Pirko static void *fl_key_get_start(struct fl_flow_key *key,
13377b9900eSJiri Pirko 			      const struct fl_flow_mask *mask)
13477b9900eSJiri Pirko {
13577b9900eSJiri Pirko 	return (u8 *) key + mask->range.start;
13677b9900eSJiri Pirko }
13777b9900eSJiri Pirko 
13877b9900eSJiri Pirko static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key,
13977b9900eSJiri Pirko 			      struct fl_flow_mask *mask)
14077b9900eSJiri Pirko {
14177b9900eSJiri Pirko 	const long *lkey = fl_key_get_start(key, mask);
14277b9900eSJiri Pirko 	const long *lmask = fl_key_get_start(&mask->key, mask);
14377b9900eSJiri Pirko 	long *lmkey = fl_key_get_start(mkey, mask);
14477b9900eSJiri Pirko 	int i;
14577b9900eSJiri Pirko 
14677b9900eSJiri Pirko 	for (i = 0; i < fl_mask_range(mask); i += sizeof(long))
14777b9900eSJiri Pirko 		*lmkey++ = *lkey++ & *lmask++;
14877b9900eSJiri Pirko }
14977b9900eSJiri Pirko 
15077b9900eSJiri Pirko static void fl_clear_masked_range(struct fl_flow_key *key,
15177b9900eSJiri Pirko 				  struct fl_flow_mask *mask)
15277b9900eSJiri Pirko {
15377b9900eSJiri Pirko 	memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask));
15477b9900eSJiri Pirko }
15577b9900eSJiri Pirko 
15605cd271fSPaul Blakey static struct cls_fl_filter *fl_lookup(struct fl_flow_mask *mask,
157a3308d8fSPaul Blakey 				       struct fl_flow_key *mkey)
158a3308d8fSPaul Blakey {
15905cd271fSPaul Blakey 	return rhashtable_lookup_fast(&mask->ht, fl_key_get_start(mkey, mask),
16005cd271fSPaul Blakey 				      mask->filter_ht_params);
161a3308d8fSPaul Blakey }
162a3308d8fSPaul Blakey 
16377b9900eSJiri Pirko static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp,
16477b9900eSJiri Pirko 		       struct tcf_result *res)
16577b9900eSJiri Pirko {
16677b9900eSJiri Pirko 	struct cls_fl_head *head = rcu_dereference_bh(tp->root);
16777b9900eSJiri Pirko 	struct cls_fl_filter *f;
16805cd271fSPaul Blakey 	struct fl_flow_mask *mask;
16977b9900eSJiri Pirko 	struct fl_flow_key skb_key;
17077b9900eSJiri Pirko 	struct fl_flow_key skb_mkey;
17177b9900eSJiri Pirko 
17205cd271fSPaul Blakey 	list_for_each_entry_rcu(mask, &head->masks, list) {
17305cd271fSPaul Blakey 		fl_clear_masked_range(&skb_key, mask);
174bc3103f1SAmir Vadai 
17577b9900eSJiri Pirko 		skb_key.indev_ifindex = skb->skb_iif;
17605cd271fSPaul Blakey 		/* skb_flow_dissect() does not set n_proto in case an unknown
17705cd271fSPaul Blakey 		 * protocol, so do it rather here.
17877b9900eSJiri Pirko 		 */
17977b9900eSJiri Pirko 		skb_key.basic.n_proto = skb->protocol;
18005cd271fSPaul Blakey 		skb_flow_dissect_tunnel_info(skb, &mask->dissector, &skb_key);
18105cd271fSPaul Blakey 		skb_flow_dissect(skb, &mask->dissector, &skb_key, 0);
18277b9900eSJiri Pirko 
18305cd271fSPaul Blakey 		fl_set_masked_key(&skb_mkey, &skb_key, mask);
18477b9900eSJiri Pirko 
18505cd271fSPaul Blakey 		f = fl_lookup(mask, &skb_mkey);
186e8eb36cdSAmir Vadai 		if (f && !tc_skip_sw(f->flags)) {
18777b9900eSJiri Pirko 			*res = f->res;
18877b9900eSJiri Pirko 			return tcf_exts_exec(skb, &f->exts, res);
18977b9900eSJiri Pirko 		}
19005cd271fSPaul Blakey 	}
19177b9900eSJiri Pirko 	return -1;
19277b9900eSJiri Pirko }
19377b9900eSJiri Pirko 
19477b9900eSJiri Pirko static int fl_init(struct tcf_proto *tp)
19577b9900eSJiri Pirko {
19677b9900eSJiri Pirko 	struct cls_fl_head *head;
19777b9900eSJiri Pirko 
19877b9900eSJiri Pirko 	head = kzalloc(sizeof(*head), GFP_KERNEL);
19977b9900eSJiri Pirko 	if (!head)
20077b9900eSJiri Pirko 		return -ENOBUFS;
20177b9900eSJiri Pirko 
20205cd271fSPaul Blakey 	INIT_LIST_HEAD_RCU(&head->masks);
20377b9900eSJiri Pirko 	rcu_assign_pointer(tp->root, head);
204c15ab236SChris Mi 	idr_init(&head->handle_idr);
20577b9900eSJiri Pirko 
20605cd271fSPaul Blakey 	return rhashtable_init(&head->ht, &mask_ht_params);
20705cd271fSPaul Blakey }
20805cd271fSPaul Blakey 
20944a5cd43SPaolo Abeni static void fl_mask_free(struct fl_flow_mask *mask)
21044a5cd43SPaolo Abeni {
21144a5cd43SPaolo Abeni 	rhashtable_destroy(&mask->ht);
21244a5cd43SPaolo Abeni 	kfree(mask);
21344a5cd43SPaolo Abeni }
21444a5cd43SPaolo Abeni 
21544a5cd43SPaolo Abeni static void fl_mask_free_work(struct work_struct *work)
21644a5cd43SPaolo Abeni {
21744a5cd43SPaolo Abeni 	struct fl_flow_mask *mask = container_of(to_rcu_work(work),
21844a5cd43SPaolo Abeni 						 struct fl_flow_mask, rwork);
21944a5cd43SPaolo Abeni 
22044a5cd43SPaolo Abeni 	fl_mask_free(mask);
22144a5cd43SPaolo Abeni }
22244a5cd43SPaolo Abeni 
22305cd271fSPaul Blakey static bool fl_mask_put(struct cls_fl_head *head, struct fl_flow_mask *mask,
22405cd271fSPaul Blakey 			bool async)
22505cd271fSPaul Blakey {
22605cd271fSPaul Blakey 	if (!list_empty(&mask->filters))
22705cd271fSPaul Blakey 		return false;
22805cd271fSPaul Blakey 
22905cd271fSPaul Blakey 	rhashtable_remove_fast(&head->ht, &mask->ht_node, mask_ht_params);
23005cd271fSPaul Blakey 	list_del_rcu(&mask->list);
23105cd271fSPaul Blakey 	if (async)
23244a5cd43SPaolo Abeni 		tcf_queue_work(&mask->rwork, fl_mask_free_work);
23305cd271fSPaul Blakey 	else
23444a5cd43SPaolo Abeni 		fl_mask_free(mask);
23505cd271fSPaul Blakey 
23605cd271fSPaul Blakey 	return true;
23777b9900eSJiri Pirko }
23877b9900eSJiri Pirko 
2390dadc117SCong Wang static void __fl_destroy_filter(struct cls_fl_filter *f)
2400dadc117SCong Wang {
2410dadc117SCong Wang 	tcf_exts_destroy(&f->exts);
2420dadc117SCong Wang 	tcf_exts_put_net(&f->exts);
2430dadc117SCong Wang 	kfree(f);
2440dadc117SCong Wang }
2450dadc117SCong Wang 
2460552c8afSCong Wang static void fl_destroy_filter_work(struct work_struct *work)
2470552c8afSCong Wang {
248aaa908ffSCong Wang 	struct cls_fl_filter *f = container_of(to_rcu_work(work),
249aaa908ffSCong Wang 					struct cls_fl_filter, rwork);
2500552c8afSCong Wang 
2510552c8afSCong Wang 	rtnl_lock();
2520dadc117SCong Wang 	__fl_destroy_filter(f);
2530552c8afSCong Wang 	rtnl_unlock();
2540552c8afSCong Wang }
2550552c8afSCong Wang 
2561b0f8037SJakub Kicinski static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f,
2571b0f8037SJakub Kicinski 				 struct netlink_ext_ack *extack)
2585b33f488SAmir Vadai {
259de4784caSJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
260208c0f4bSJiri Pirko 	struct tcf_block *block = tp->chain->block;
2615b33f488SAmir Vadai 
2621b0f8037SJakub Kicinski 	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack);
263de4784caSJiri Pirko 	cls_flower.command = TC_CLSFLOWER_DESTROY;
264de4784caSJiri Pirko 	cls_flower.cookie = (unsigned long) f;
2655b33f488SAmir Vadai 
266208c0f4bSJiri Pirko 	tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER,
267717503b9SJiri Pirko 			 &cls_flower, false);
268caa72601SJiri Pirko 	tcf_block_offload_dec(block, &f->flags);
2695b33f488SAmir Vadai }
2705b33f488SAmir Vadai 
271e8eb36cdSAmir Vadai static int fl_hw_replace_filter(struct tcf_proto *tp,
27241002038SQuentin Monnet 				struct cls_fl_filter *f,
27341002038SQuentin Monnet 				struct netlink_ext_ack *extack)
2745b33f488SAmir Vadai {
275de4784caSJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
276208c0f4bSJiri Pirko 	struct tcf_block *block = tp->chain->block;
277717503b9SJiri Pirko 	bool skip_sw = tc_skip_sw(f->flags);
278e8eb36cdSAmir Vadai 	int err;
2795b33f488SAmir Vadai 
280ea205940SJakub Kicinski 	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack);
281de4784caSJiri Pirko 	cls_flower.command = TC_CLSFLOWER_REPLACE;
282de4784caSJiri Pirko 	cls_flower.cookie = (unsigned long) f;
28305cd271fSPaul Blakey 	cls_flower.dissector = &f->mask->dissector;
28405cd271fSPaul Blakey 	cls_flower.mask = &f->mask->key;
285de4784caSJiri Pirko 	cls_flower.key = &f->mkey;
286de4784caSJiri Pirko 	cls_flower.exts = &f->exts;
287384c181eSAmritha Nambiar 	cls_flower.classid = f->res.classid;
2885b33f488SAmir Vadai 
289208c0f4bSJiri Pirko 	err = tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER,
290717503b9SJiri Pirko 			       &cls_flower, skip_sw);
291717503b9SJiri Pirko 	if (err < 0) {
2921b0f8037SJakub Kicinski 		fl_hw_destroy_filter(tp, f, NULL);
293717503b9SJiri Pirko 		return err;
294717503b9SJiri Pirko 	} else if (err > 0) {
29531533cbaSJohn Hurley 		f->in_hw_count = err;
296caa72601SJiri Pirko 		tcf_block_offload_inc(block, &f->flags);
297717503b9SJiri Pirko 	}
298717503b9SJiri Pirko 
299717503b9SJiri Pirko 	if (skip_sw && !(f->flags & TCA_CLS_FLAGS_IN_HW))
300717503b9SJiri Pirko 		return -EINVAL;
301717503b9SJiri Pirko 
302e8eb36cdSAmir Vadai 	return 0;
3035b33f488SAmir Vadai }
3045b33f488SAmir Vadai 
30510cbc684SAmir Vadai static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
30610cbc684SAmir Vadai {
307de4784caSJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
308208c0f4bSJiri Pirko 	struct tcf_block *block = tp->chain->block;
30910cbc684SAmir Vadai 
310ea205940SJakub Kicinski 	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, NULL);
311de4784caSJiri Pirko 	cls_flower.command = TC_CLSFLOWER_STATS;
312de4784caSJiri Pirko 	cls_flower.cookie = (unsigned long) f;
313de4784caSJiri Pirko 	cls_flower.exts = &f->exts;
314384c181eSAmritha Nambiar 	cls_flower.classid = f->res.classid;
31510cbc684SAmir Vadai 
316208c0f4bSJiri Pirko 	tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER,
317717503b9SJiri Pirko 			 &cls_flower, false);
31810cbc684SAmir Vadai }
31910cbc684SAmir Vadai 
32005cd271fSPaul Blakey static bool __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,
3211b0f8037SJakub Kicinski 			struct netlink_ext_ack *extack)
32213fa876eSRoi Dayan {
323c15ab236SChris Mi 	struct cls_fl_head *head = rtnl_dereference(tp->root);
32405cd271fSPaul Blakey 	bool async = tcf_exts_get_net(&f->exts);
32505cd271fSPaul Blakey 	bool last;
326c15ab236SChris Mi 
3279c160941SMatthew Wilcox 	idr_remove(&head->handle_idr, f->handle);
32813fa876eSRoi Dayan 	list_del_rcu(&f->list);
32905cd271fSPaul Blakey 	last = fl_mask_put(head, f->mask, async);
33079685219SHadar Hen Zion 	if (!tc_skip_hw(f->flags))
3311b0f8037SJakub Kicinski 		fl_hw_destroy_filter(tp, f, extack);
33213fa876eSRoi Dayan 	tcf_unbind_filter(tp, &f->res);
33305cd271fSPaul Blakey 	if (async)
334aaa908ffSCong Wang 		tcf_queue_work(&f->rwork, fl_destroy_filter_work);
3350dadc117SCong Wang 	else
3360dadc117SCong Wang 		__fl_destroy_filter(f);
33705cd271fSPaul Blakey 
33805cd271fSPaul Blakey 	return last;
33913fa876eSRoi Dayan }
34013fa876eSRoi Dayan 
341d9363774SDaniel Borkmann static void fl_destroy_sleepable(struct work_struct *work)
342d9363774SDaniel Borkmann {
343aaa908ffSCong Wang 	struct cls_fl_head *head = container_of(to_rcu_work(work),
344aaa908ffSCong Wang 						struct cls_fl_head,
345aaa908ffSCong Wang 						rwork);
346de9dc650SPaul Blakey 
347de9dc650SPaul Blakey 	rhashtable_destroy(&head->ht);
348d9363774SDaniel Borkmann 	kfree(head);
349d9363774SDaniel Borkmann 	module_put(THIS_MODULE);
350d9363774SDaniel Borkmann }
351d9363774SDaniel Borkmann 
352715df5ecSJakub Kicinski static void fl_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
35377b9900eSJiri Pirko {
35477b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
35505cd271fSPaul Blakey 	struct fl_flow_mask *mask, *next_mask;
35677b9900eSJiri Pirko 	struct cls_fl_filter *f, *next;
35777b9900eSJiri Pirko 
35805cd271fSPaul Blakey 	list_for_each_entry_safe(mask, next_mask, &head->masks, list) {
35905cd271fSPaul Blakey 		list_for_each_entry_safe(f, next, &mask->filters, list) {
36005cd271fSPaul Blakey 			if (__fl_delete(tp, f, extack))
36105cd271fSPaul Blakey 				break;
36205cd271fSPaul Blakey 		}
36305cd271fSPaul Blakey 	}
364c15ab236SChris Mi 	idr_destroy(&head->handle_idr);
365d9363774SDaniel Borkmann 
366d9363774SDaniel Borkmann 	__module_get(THIS_MODULE);
367aaa908ffSCong Wang 	tcf_queue_work(&head->rwork, fl_destroy_sleepable);
36877b9900eSJiri Pirko }
36977b9900eSJiri Pirko 
3708113c095SWANG Cong static void *fl_get(struct tcf_proto *tp, u32 handle)
37177b9900eSJiri Pirko {
37277b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
37377b9900eSJiri Pirko 
374322d884bSMatthew Wilcox 	return idr_find(&head->handle_idr, handle);
37577b9900eSJiri Pirko }
37677b9900eSJiri Pirko 
37777b9900eSJiri Pirko static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
37877b9900eSJiri Pirko 	[TCA_FLOWER_UNSPEC]		= { .type = NLA_UNSPEC },
37977b9900eSJiri Pirko 	[TCA_FLOWER_CLASSID]		= { .type = NLA_U32 },
38077b9900eSJiri Pirko 	[TCA_FLOWER_INDEV]		= { .type = NLA_STRING,
38177b9900eSJiri Pirko 					    .len = IFNAMSIZ },
38277b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_DST]	= { .len = ETH_ALEN },
38377b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_DST_MASK]	= { .len = ETH_ALEN },
38477b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_SRC]	= { .len = ETH_ALEN },
38577b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_SRC_MASK]	= { .len = ETH_ALEN },
38677b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_TYPE]	= { .type = NLA_U16 },
38777b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IP_PROTO]	= { .type = NLA_U8 },
38877b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_SRC]	= { .type = NLA_U32 },
38977b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_SRC_MASK]	= { .type = NLA_U32 },
39077b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_DST]	= { .type = NLA_U32 },
39177b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_DST_MASK]	= { .type = NLA_U32 },
39277b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
39377b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_SRC_MASK]	= { .len = sizeof(struct in6_addr) },
39477b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
39577b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_DST_MASK]	= { .len = sizeof(struct in6_addr) },
39677b9900eSJiri Pirko 	[TCA_FLOWER_KEY_TCP_SRC]	= { .type = NLA_U16 },
39777b9900eSJiri Pirko 	[TCA_FLOWER_KEY_TCP_DST]	= { .type = NLA_U16 },
398b175c3a4SJamal Hadi Salim 	[TCA_FLOWER_KEY_UDP_SRC]	= { .type = NLA_U16 },
399b175c3a4SJamal Hadi Salim 	[TCA_FLOWER_KEY_UDP_DST]	= { .type = NLA_U16 },
4009399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_ID]	= { .type = NLA_U16 },
4019399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_PRIO]	= { .type = NLA_U8 },
4029399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_ETH_TYPE]	= { .type = NLA_U16 },
403bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_KEY_ID]	= { .type = NLA_U32 },
404bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_SRC]	= { .type = NLA_U32 },
405bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NLA_U32 },
406bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_DST]	= { .type = NLA_U32 },
407bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NLA_U32 },
408bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
409bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) },
410bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
411bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) },
412aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_TCP_SRC_MASK]	= { .type = NLA_U16 },
413aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_TCP_DST_MASK]	= { .type = NLA_U16 },
414aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_UDP_SRC_MASK]	= { .type = NLA_U16 },
415aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_UDP_DST_MASK]	= { .type = NLA_U16 },
4165976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_SRC_MASK]	= { .type = NLA_U16 },
4175976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_DST_MASK]	= { .type = NLA_U16 },
4185976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_SRC]	= { .type = NLA_U16 },
4195976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_DST]	= { .type = NLA_U16 },
420f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT]	= { .type = NLA_U16 },
421f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK]	= { .type = NLA_U16 },
422f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]	= { .type = NLA_U16 },
423f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK]	= { .type = NLA_U16 },
424faa3ffceSOr Gerlitz 	[TCA_FLOWER_KEY_FLAGS]		= { .type = NLA_U32 },
425faa3ffceSOr Gerlitz 	[TCA_FLOWER_KEY_FLAGS_MASK]	= { .type = NLA_U32 },
4267b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_TYPE]	= { .type = NLA_U8 },
4277b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_TYPE_MASK] = { .type = NLA_U8 },
4287b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_CODE]	= { .type = NLA_U8 },
4297b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_CODE_MASK] = { .type = NLA_U8 },
4307b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_TYPE]	= { .type = NLA_U8 },
4317b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_TYPE_MASK] = { .type = NLA_U8 },
4327b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_CODE]	= { .type = NLA_U8 },
4337b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_CODE_MASK] = { .type = NLA_U8 },
43499d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SIP]	= { .type = NLA_U32 },
43599d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SIP_MASK]	= { .type = NLA_U32 },
43699d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_TIP]	= { .type = NLA_U32 },
43799d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_TIP_MASK]	= { .type = NLA_U32 },
43899d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_OP]		= { .type = NLA_U8 },
43999d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_OP_MASK]	= { .type = NLA_U8 },
44099d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SHA]	= { .len = ETH_ALEN },
44199d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SHA_MASK]	= { .len = ETH_ALEN },
44299d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_THA]	= { .len = ETH_ALEN },
44399d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_THA_MASK]	= { .len = ETH_ALEN },
444a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_TTL]	= { .type = NLA_U8 },
445a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_BOS]	= { .type = NLA_U8 },
446a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_TC]	= { .type = NLA_U8 },
447a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_LABEL]	= { .type = NLA_U32 },
448fdfc7dd6SJiri Pirko 	[TCA_FLOWER_KEY_TCP_FLAGS]	= { .type = NLA_U16 },
449fdfc7dd6SJiri Pirko 	[TCA_FLOWER_KEY_TCP_FLAGS_MASK]	= { .type = NLA_U16 },
4504d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TOS]		= { .type = NLA_U8 },
4514d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TOS_MASK]	= { .type = NLA_U8 },
4524d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TTL]		= { .type = NLA_U8 },
4534d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TTL_MASK]	= { .type = NLA_U8 },
454d64efd09SJianbo Liu 	[TCA_FLOWER_KEY_CVLAN_ID]	= { .type = NLA_U16 },
455d64efd09SJianbo Liu 	[TCA_FLOWER_KEY_CVLAN_PRIO]	= { .type = NLA_U8 },
456d64efd09SJianbo Liu 	[TCA_FLOWER_KEY_CVLAN_ETH_TYPE]	= { .type = NLA_U16 },
4570e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TOS]	= { .type = NLA_U8 },
4580e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TOS_MASK] = { .type = NLA_U8 },
4590e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TTL]	 = { .type = NLA_U8 },
4600e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TTL_MASK] = { .type = NLA_U8 },
46177b9900eSJiri Pirko };
46277b9900eSJiri Pirko 
46377b9900eSJiri Pirko static void fl_set_key_val(struct nlattr **tb,
46477b9900eSJiri Pirko 			   void *val, int val_type,
46577b9900eSJiri Pirko 			   void *mask, int mask_type, int len)
46677b9900eSJiri Pirko {
46777b9900eSJiri Pirko 	if (!tb[val_type])
46877b9900eSJiri Pirko 		return;
46977b9900eSJiri Pirko 	memcpy(val, nla_data(tb[val_type]), len);
47077b9900eSJiri Pirko 	if (mask_type == TCA_FLOWER_UNSPEC || !tb[mask_type])
47177b9900eSJiri Pirko 		memset(mask, 0xff, len);
47277b9900eSJiri Pirko 	else
47377b9900eSJiri Pirko 		memcpy(mask, nla_data(tb[mask_type]), len);
47477b9900eSJiri Pirko }
47577b9900eSJiri Pirko 
4761a7fca63SBenjamin LaHaise static int fl_set_key_mpls(struct nlattr **tb,
477a577d8f7SBenjamin LaHaise 			   struct flow_dissector_key_mpls *key_val,
478a577d8f7SBenjamin LaHaise 			   struct flow_dissector_key_mpls *key_mask)
479a577d8f7SBenjamin LaHaise {
480a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_TTL]) {
481a577d8f7SBenjamin LaHaise 		key_val->mpls_ttl = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TTL]);
482a577d8f7SBenjamin LaHaise 		key_mask->mpls_ttl = MPLS_TTL_MASK;
483a577d8f7SBenjamin LaHaise 	}
484a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_BOS]) {
4851a7fca63SBenjamin LaHaise 		u8 bos = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_BOS]);
4861a7fca63SBenjamin LaHaise 
4871a7fca63SBenjamin LaHaise 		if (bos & ~MPLS_BOS_MASK)
4881a7fca63SBenjamin LaHaise 			return -EINVAL;
4891a7fca63SBenjamin LaHaise 		key_val->mpls_bos = bos;
490a577d8f7SBenjamin LaHaise 		key_mask->mpls_bos = MPLS_BOS_MASK;
491a577d8f7SBenjamin LaHaise 	}
492a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_TC]) {
4931a7fca63SBenjamin LaHaise 		u8 tc = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TC]);
4941a7fca63SBenjamin LaHaise 
4951a7fca63SBenjamin LaHaise 		if (tc & ~MPLS_TC_MASK)
4961a7fca63SBenjamin LaHaise 			return -EINVAL;
4971a7fca63SBenjamin LaHaise 		key_val->mpls_tc = tc;
498a577d8f7SBenjamin LaHaise 		key_mask->mpls_tc = MPLS_TC_MASK;
499a577d8f7SBenjamin LaHaise 	}
500a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_LABEL]) {
5011a7fca63SBenjamin LaHaise 		u32 label = nla_get_u32(tb[TCA_FLOWER_KEY_MPLS_LABEL]);
5021a7fca63SBenjamin LaHaise 
5031a7fca63SBenjamin LaHaise 		if (label & ~MPLS_LABEL_MASK)
5041a7fca63SBenjamin LaHaise 			return -EINVAL;
5051a7fca63SBenjamin LaHaise 		key_val->mpls_label = label;
506a577d8f7SBenjamin LaHaise 		key_mask->mpls_label = MPLS_LABEL_MASK;
507a577d8f7SBenjamin LaHaise 	}
5081a7fca63SBenjamin LaHaise 	return 0;
509a577d8f7SBenjamin LaHaise }
510a577d8f7SBenjamin LaHaise 
5119399ae9aSHadar Hen Zion static void fl_set_key_vlan(struct nlattr **tb,
512aaab0834SJianbo Liu 			    __be16 ethertype,
513d64efd09SJianbo Liu 			    int vlan_id_key, int vlan_prio_key,
5149399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *key_val,
5159399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *key_mask)
5169399ae9aSHadar Hen Zion {
5179399ae9aSHadar Hen Zion #define VLAN_PRIORITY_MASK	0x7
5189399ae9aSHadar Hen Zion 
519d64efd09SJianbo Liu 	if (tb[vlan_id_key]) {
5209399ae9aSHadar Hen Zion 		key_val->vlan_id =
521d64efd09SJianbo Liu 			nla_get_u16(tb[vlan_id_key]) & VLAN_VID_MASK;
5229399ae9aSHadar Hen Zion 		key_mask->vlan_id = VLAN_VID_MASK;
5239399ae9aSHadar Hen Zion 	}
524d64efd09SJianbo Liu 	if (tb[vlan_prio_key]) {
5259399ae9aSHadar Hen Zion 		key_val->vlan_priority =
526d64efd09SJianbo Liu 			nla_get_u8(tb[vlan_prio_key]) &
5279399ae9aSHadar Hen Zion 			VLAN_PRIORITY_MASK;
5289399ae9aSHadar Hen Zion 		key_mask->vlan_priority = VLAN_PRIORITY_MASK;
5299399ae9aSHadar Hen Zion 	}
530aaab0834SJianbo Liu 	key_val->vlan_tpid = ethertype;
531aaab0834SJianbo Liu 	key_mask->vlan_tpid = cpu_to_be16(~0);
5329399ae9aSHadar Hen Zion }
5339399ae9aSHadar Hen Zion 
534faa3ffceSOr Gerlitz static void fl_set_key_flag(u32 flower_key, u32 flower_mask,
535faa3ffceSOr Gerlitz 			    u32 *dissector_key, u32 *dissector_mask,
536faa3ffceSOr Gerlitz 			    u32 flower_flag_bit, u32 dissector_flag_bit)
537faa3ffceSOr Gerlitz {
538faa3ffceSOr Gerlitz 	if (flower_mask & flower_flag_bit) {
539faa3ffceSOr Gerlitz 		*dissector_mask |= dissector_flag_bit;
540faa3ffceSOr Gerlitz 		if (flower_key & flower_flag_bit)
541faa3ffceSOr Gerlitz 			*dissector_key |= dissector_flag_bit;
542faa3ffceSOr Gerlitz 	}
543faa3ffceSOr Gerlitz }
544faa3ffceSOr Gerlitz 
545d9724772SOr Gerlitz static int fl_set_key_flags(struct nlattr **tb,
546faa3ffceSOr Gerlitz 			    u32 *flags_key, u32 *flags_mask)
547faa3ffceSOr Gerlitz {
548faa3ffceSOr Gerlitz 	u32 key, mask;
549faa3ffceSOr Gerlitz 
550d9724772SOr Gerlitz 	/* mask is mandatory for flags */
551d9724772SOr Gerlitz 	if (!tb[TCA_FLOWER_KEY_FLAGS_MASK])
552d9724772SOr Gerlitz 		return -EINVAL;
553faa3ffceSOr Gerlitz 
554faa3ffceSOr Gerlitz 	key = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS]));
555faa3ffceSOr Gerlitz 	mask = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS_MASK]));
556faa3ffceSOr Gerlitz 
557faa3ffceSOr Gerlitz 	*flags_key  = 0;
558faa3ffceSOr Gerlitz 	*flags_mask = 0;
559faa3ffceSOr Gerlitz 
560faa3ffceSOr Gerlitz 	fl_set_key_flag(key, mask, flags_key, flags_mask,
561faa3ffceSOr Gerlitz 			TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT);
562459d153dSPieter Jansen van Vuuren 	fl_set_key_flag(key, mask, flags_key, flags_mask,
563459d153dSPieter Jansen van Vuuren 			TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST,
564459d153dSPieter Jansen van Vuuren 			FLOW_DIS_FIRST_FRAG);
565d9724772SOr Gerlitz 
566d9724772SOr Gerlitz 	return 0;
567faa3ffceSOr Gerlitz }
568faa3ffceSOr Gerlitz 
5690e2c17b6SOr Gerlitz static void fl_set_key_ip(struct nlattr **tb, bool encap,
5704d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *key,
5714d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *mask)
5724d80cc0aSOr Gerlitz {
5730e2c17b6SOr Gerlitz 	int tos_key = encap ? TCA_FLOWER_KEY_ENC_IP_TOS : TCA_FLOWER_KEY_IP_TOS;
5740e2c17b6SOr Gerlitz 	int ttl_key = encap ? TCA_FLOWER_KEY_ENC_IP_TTL : TCA_FLOWER_KEY_IP_TTL;
5750e2c17b6SOr Gerlitz 	int tos_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TOS_MASK : TCA_FLOWER_KEY_IP_TOS_MASK;
5760e2c17b6SOr Gerlitz 	int ttl_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TTL_MASK : TCA_FLOWER_KEY_IP_TTL_MASK;
5774d80cc0aSOr Gerlitz 
5780e2c17b6SOr Gerlitz 	fl_set_key_val(tb, &key->tos, tos_key, &mask->tos, tos_mask, sizeof(key->tos));
5790e2c17b6SOr Gerlitz 	fl_set_key_val(tb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl));
5804d80cc0aSOr Gerlitz }
5814d80cc0aSOr Gerlitz 
58277b9900eSJiri Pirko static int fl_set_key(struct net *net, struct nlattr **tb,
5831057c55fSAlexander Aring 		      struct fl_flow_key *key, struct fl_flow_key *mask,
5841057c55fSAlexander Aring 		      struct netlink_ext_ack *extack)
58577b9900eSJiri Pirko {
5869399ae9aSHadar Hen Zion 	__be16 ethertype;
587d9724772SOr Gerlitz 	int ret = 0;
588dd3aa3b5SBrian Haley #ifdef CONFIG_NET_CLS_IND
58977b9900eSJiri Pirko 	if (tb[TCA_FLOWER_INDEV]) {
5901057c55fSAlexander Aring 		int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV], extack);
59177b9900eSJiri Pirko 		if (err < 0)
59277b9900eSJiri Pirko 			return err;
59377b9900eSJiri Pirko 		key->indev_ifindex = err;
59477b9900eSJiri Pirko 		mask->indev_ifindex = 0xffffffff;
59577b9900eSJiri Pirko 	}
596dd3aa3b5SBrian Haley #endif
59777b9900eSJiri Pirko 
59877b9900eSJiri Pirko 	fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
59977b9900eSJiri Pirko 		       mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
60077b9900eSJiri Pirko 		       sizeof(key->eth.dst));
60177b9900eSJiri Pirko 	fl_set_key_val(tb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
60277b9900eSJiri Pirko 		       mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
60377b9900eSJiri Pirko 		       sizeof(key->eth.src));
60466530bdfSJamal Hadi Salim 
6050b498a52SArnd Bergmann 	if (tb[TCA_FLOWER_KEY_ETH_TYPE]) {
6069399ae9aSHadar Hen Zion 		ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_ETH_TYPE]);
6079399ae9aSHadar Hen Zion 
608aaab0834SJianbo Liu 		if (eth_type_vlan(ethertype)) {
609d64efd09SJianbo Liu 			fl_set_key_vlan(tb, ethertype, TCA_FLOWER_KEY_VLAN_ID,
610d64efd09SJianbo Liu 					TCA_FLOWER_KEY_VLAN_PRIO, &key->vlan,
611d64efd09SJianbo Liu 					&mask->vlan);
612d64efd09SJianbo Liu 
6135e9a0fe4SJianbo Liu 			if (tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]) {
614d64efd09SJianbo Liu 				ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]);
615d64efd09SJianbo Liu 				if (eth_type_vlan(ethertype)) {
616d64efd09SJianbo Liu 					fl_set_key_vlan(tb, ethertype,
617d64efd09SJianbo Liu 							TCA_FLOWER_KEY_CVLAN_ID,
618d64efd09SJianbo Liu 							TCA_FLOWER_KEY_CVLAN_PRIO,
619d64efd09SJianbo Liu 							&key->cvlan, &mask->cvlan);
6209399ae9aSHadar Hen Zion 					fl_set_key_val(tb, &key->basic.n_proto,
621d64efd09SJianbo Liu 						       TCA_FLOWER_KEY_CVLAN_ETH_TYPE,
622d64efd09SJianbo Liu 						       &mask->basic.n_proto,
623d64efd09SJianbo Liu 						       TCA_FLOWER_UNSPEC,
62477b9900eSJiri Pirko 						       sizeof(key->basic.n_proto));
6259399ae9aSHadar Hen Zion 				} else {
6269399ae9aSHadar Hen Zion 					key->basic.n_proto = ethertype;
6279399ae9aSHadar Hen Zion 					mask->basic.n_proto = cpu_to_be16(~0);
6289399ae9aSHadar Hen Zion 				}
6295e9a0fe4SJianbo Liu 			}
630d64efd09SJianbo Liu 		} else {
631d64efd09SJianbo Liu 			key->basic.n_proto = ethertype;
632d64efd09SJianbo Liu 			mask->basic.n_proto = cpu_to_be16(~0);
633d64efd09SJianbo Liu 		}
6340b498a52SArnd Bergmann 	}
63566530bdfSJamal Hadi Salim 
63677b9900eSJiri Pirko 	if (key->basic.n_proto == htons(ETH_P_IP) ||
63777b9900eSJiri Pirko 	    key->basic.n_proto == htons(ETH_P_IPV6)) {
63877b9900eSJiri Pirko 		fl_set_key_val(tb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
63977b9900eSJiri Pirko 			       &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
64077b9900eSJiri Pirko 			       sizeof(key->basic.ip_proto));
6410e2c17b6SOr Gerlitz 		fl_set_key_ip(tb, false, &key->ip, &mask->ip);
64277b9900eSJiri Pirko 	}
64366530bdfSJamal Hadi Salim 
64466530bdfSJamal Hadi Salim 	if (tb[TCA_FLOWER_KEY_IPV4_SRC] || tb[TCA_FLOWER_KEY_IPV4_DST]) {
64566530bdfSJamal Hadi Salim 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
646970bfcd0SPaul Blakey 		mask->control.addr_type = ~0;
64777b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
64877b9900eSJiri Pirko 			       &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
64977b9900eSJiri Pirko 			       sizeof(key->ipv4.src));
65077b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
65177b9900eSJiri Pirko 			       &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
65277b9900eSJiri Pirko 			       sizeof(key->ipv4.dst));
65366530bdfSJamal Hadi Salim 	} else if (tb[TCA_FLOWER_KEY_IPV6_SRC] || tb[TCA_FLOWER_KEY_IPV6_DST]) {
65466530bdfSJamal Hadi Salim 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
655970bfcd0SPaul Blakey 		mask->control.addr_type = ~0;
65677b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
65777b9900eSJiri Pirko 			       &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
65877b9900eSJiri Pirko 			       sizeof(key->ipv6.src));
65977b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
66077b9900eSJiri Pirko 			       &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
66177b9900eSJiri Pirko 			       sizeof(key->ipv6.dst));
66277b9900eSJiri Pirko 	}
66366530bdfSJamal Hadi Salim 
66477b9900eSJiri Pirko 	if (key->basic.ip_proto == IPPROTO_TCP) {
66577b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
666aa72d708SOr Gerlitz 			       &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
66777b9900eSJiri Pirko 			       sizeof(key->tp.src));
66877b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
669aa72d708SOr Gerlitz 			       &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
67077b9900eSJiri Pirko 			       sizeof(key->tp.dst));
671fdfc7dd6SJiri Pirko 		fl_set_key_val(tb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS,
672fdfc7dd6SJiri Pirko 			       &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK,
673fdfc7dd6SJiri Pirko 			       sizeof(key->tcp.flags));
67477b9900eSJiri Pirko 	} else if (key->basic.ip_proto == IPPROTO_UDP) {
67577b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
676aa72d708SOr Gerlitz 			       &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
67777b9900eSJiri Pirko 			       sizeof(key->tp.src));
67877b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
679aa72d708SOr Gerlitz 			       &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
68077b9900eSJiri Pirko 			       sizeof(key->tp.dst));
6815976c5f4SSimon Horman 	} else if (key->basic.ip_proto == IPPROTO_SCTP) {
6825976c5f4SSimon Horman 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
6835976c5f4SSimon Horman 			       &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
6845976c5f4SSimon Horman 			       sizeof(key->tp.src));
6855976c5f4SSimon Horman 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
6865976c5f4SSimon Horman 			       &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
6875976c5f4SSimon Horman 			       sizeof(key->tp.dst));
6887b684884SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_IP) &&
6897b684884SSimon Horman 		   key->basic.ip_proto == IPPROTO_ICMP) {
6907b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV4_TYPE,
6917b684884SSimon Horman 			       &mask->icmp.type,
6927b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,
6937b684884SSimon Horman 			       sizeof(key->icmp.type));
6947b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE,
6957b684884SSimon Horman 			       &mask->icmp.code,
6967b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
6977b684884SSimon Horman 			       sizeof(key->icmp.code));
6987b684884SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_IPV6) &&
6997b684884SSimon Horman 		   key->basic.ip_proto == IPPROTO_ICMPV6) {
7007b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV6_TYPE,
7017b684884SSimon Horman 			       &mask->icmp.type,
7027b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
7037b684884SSimon Horman 			       sizeof(key->icmp.type));
704040587afSSimon Horman 		fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV6_CODE,
7057b684884SSimon Horman 			       &mask->icmp.code,
706040587afSSimon Horman 			       TCA_FLOWER_KEY_ICMPV6_CODE_MASK,
7077b684884SSimon Horman 			       sizeof(key->icmp.code));
708a577d8f7SBenjamin LaHaise 	} else if (key->basic.n_proto == htons(ETH_P_MPLS_UC) ||
709a577d8f7SBenjamin LaHaise 		   key->basic.n_proto == htons(ETH_P_MPLS_MC)) {
7101a7fca63SBenjamin LaHaise 		ret = fl_set_key_mpls(tb, &key->mpls, &mask->mpls);
7111a7fca63SBenjamin LaHaise 		if (ret)
7121a7fca63SBenjamin LaHaise 			return ret;
71399d31326SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_ARP) ||
71499d31326SSimon Horman 		   key->basic.n_proto == htons(ETH_P_RARP)) {
71599d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.sip, TCA_FLOWER_KEY_ARP_SIP,
71699d31326SSimon Horman 			       &mask->arp.sip, TCA_FLOWER_KEY_ARP_SIP_MASK,
71799d31326SSimon Horman 			       sizeof(key->arp.sip));
71899d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.tip, TCA_FLOWER_KEY_ARP_TIP,
71999d31326SSimon Horman 			       &mask->arp.tip, TCA_FLOWER_KEY_ARP_TIP_MASK,
72099d31326SSimon Horman 			       sizeof(key->arp.tip));
72199d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.op, TCA_FLOWER_KEY_ARP_OP,
72299d31326SSimon Horman 			       &mask->arp.op, TCA_FLOWER_KEY_ARP_OP_MASK,
72399d31326SSimon Horman 			       sizeof(key->arp.op));
72499d31326SSimon Horman 		fl_set_key_val(tb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA,
72599d31326SSimon Horman 			       mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK,
72699d31326SSimon Horman 			       sizeof(key->arp.sha));
72799d31326SSimon Horman 		fl_set_key_val(tb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA,
72899d31326SSimon Horman 			       mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK,
72999d31326SSimon Horman 			       sizeof(key->arp.tha));
73077b9900eSJiri Pirko 	}
73177b9900eSJiri Pirko 
732bc3103f1SAmir Vadai 	if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] ||
733bc3103f1SAmir Vadai 	    tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) {
734bc3103f1SAmir Vadai 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
735970bfcd0SPaul Blakey 		mask->enc_control.addr_type = ~0;
736bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv4.src,
737bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_SRC,
738bc3103f1SAmir Vadai 			       &mask->enc_ipv4.src,
739bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
740bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv4.src));
741bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv4.dst,
742bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_DST,
743bc3103f1SAmir Vadai 			       &mask->enc_ipv4.dst,
744bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
745bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv4.dst));
746bc3103f1SAmir Vadai 	}
747bc3103f1SAmir Vadai 
748bc3103f1SAmir Vadai 	if (tb[TCA_FLOWER_KEY_ENC_IPV6_SRC] ||
749bc3103f1SAmir Vadai 	    tb[TCA_FLOWER_KEY_ENC_IPV6_DST]) {
750bc3103f1SAmir Vadai 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
751970bfcd0SPaul Blakey 		mask->enc_control.addr_type = ~0;
752bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv6.src,
753bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_SRC,
754bc3103f1SAmir Vadai 			       &mask->enc_ipv6.src,
755bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
756bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv6.src));
757bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv6.dst,
758bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_DST,
759bc3103f1SAmir Vadai 			       &mask->enc_ipv6.dst,
760bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
761bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv6.dst));
762bc3103f1SAmir Vadai 	}
763bc3103f1SAmir Vadai 
764bc3103f1SAmir Vadai 	fl_set_key_val(tb, &key->enc_key_id.keyid, TCA_FLOWER_KEY_ENC_KEY_ID,
765eb523f42SHadar Hen Zion 		       &mask->enc_key_id.keyid, TCA_FLOWER_UNSPEC,
766bc3103f1SAmir Vadai 		       sizeof(key->enc_key_id.keyid));
767bc3103f1SAmir Vadai 
768f4d997fdSHadar Hen Zion 	fl_set_key_val(tb, &key->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
769f4d997fdSHadar Hen Zion 		       &mask->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
770f4d997fdSHadar Hen Zion 		       sizeof(key->enc_tp.src));
771f4d997fdSHadar Hen Zion 
772f4d997fdSHadar Hen Zion 	fl_set_key_val(tb, &key->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
773f4d997fdSHadar Hen Zion 		       &mask->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
774f4d997fdSHadar Hen Zion 		       sizeof(key->enc_tp.dst));
775f4d997fdSHadar Hen Zion 
7760e2c17b6SOr Gerlitz 	fl_set_key_ip(tb, true, &key->enc_ip, &mask->enc_ip);
7770e2c17b6SOr Gerlitz 
778d9724772SOr Gerlitz 	if (tb[TCA_FLOWER_KEY_FLAGS])
779d9724772SOr Gerlitz 		ret = fl_set_key_flags(tb, &key->control.flags, &mask->control.flags);
780faa3ffceSOr Gerlitz 
781d9724772SOr Gerlitz 	return ret;
78277b9900eSJiri Pirko }
78377b9900eSJiri Pirko 
78405cd271fSPaul Blakey static void fl_mask_copy(struct fl_flow_mask *dst,
78505cd271fSPaul Blakey 			 struct fl_flow_mask *src)
78677b9900eSJiri Pirko {
78705cd271fSPaul Blakey 	const void *psrc = fl_key_get_start(&src->key, src);
78805cd271fSPaul Blakey 	void *pdst = fl_key_get_start(&dst->key, src);
78977b9900eSJiri Pirko 
79005cd271fSPaul Blakey 	memcpy(pdst, psrc, fl_mask_range(src));
79105cd271fSPaul Blakey 	dst->range = src->range;
79277b9900eSJiri Pirko }
79377b9900eSJiri Pirko 
79477b9900eSJiri Pirko static const struct rhashtable_params fl_ht_params = {
79577b9900eSJiri Pirko 	.key_offset = offsetof(struct cls_fl_filter, mkey), /* base offset */
79677b9900eSJiri Pirko 	.head_offset = offsetof(struct cls_fl_filter, ht_node),
79777b9900eSJiri Pirko 	.automatic_shrinking = true,
79877b9900eSJiri Pirko };
79977b9900eSJiri Pirko 
80005cd271fSPaul Blakey static int fl_init_mask_hashtable(struct fl_flow_mask *mask)
80177b9900eSJiri Pirko {
80205cd271fSPaul Blakey 	mask->filter_ht_params = fl_ht_params;
80305cd271fSPaul Blakey 	mask->filter_ht_params.key_len = fl_mask_range(mask);
80405cd271fSPaul Blakey 	mask->filter_ht_params.key_offset += mask->range.start;
80577b9900eSJiri Pirko 
80605cd271fSPaul Blakey 	return rhashtable_init(&mask->ht, &mask->filter_ht_params);
80777b9900eSJiri Pirko }
80877b9900eSJiri Pirko 
80977b9900eSJiri Pirko #define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member)
81077b9900eSJiri Pirko #define FL_KEY_MEMBER_SIZE(member) (sizeof(((struct fl_flow_key *) 0)->member))
81177b9900eSJiri Pirko 
812339ba878SHadar Hen Zion #define FL_KEY_IS_MASKED(mask, member)						\
813339ba878SHadar Hen Zion 	memchr_inv(((char *)mask) + FL_KEY_MEMBER_OFFSET(member),		\
814339ba878SHadar Hen Zion 		   0, FL_KEY_MEMBER_SIZE(member))				\
81577b9900eSJiri Pirko 
81677b9900eSJiri Pirko #define FL_KEY_SET(keys, cnt, id, member)					\
81777b9900eSJiri Pirko 	do {									\
81877b9900eSJiri Pirko 		keys[cnt].key_id = id;						\
81977b9900eSJiri Pirko 		keys[cnt].offset = FL_KEY_MEMBER_OFFSET(member);		\
82077b9900eSJiri Pirko 		cnt++;								\
82177b9900eSJiri Pirko 	} while(0);
82277b9900eSJiri Pirko 
823339ba878SHadar Hen Zion #define FL_KEY_SET_IF_MASKED(mask, keys, cnt, id, member)			\
82477b9900eSJiri Pirko 	do {									\
825339ba878SHadar Hen Zion 		if (FL_KEY_IS_MASKED(mask, member))				\
82677b9900eSJiri Pirko 			FL_KEY_SET(keys, cnt, id, member);			\
82777b9900eSJiri Pirko 	} while(0);
82877b9900eSJiri Pirko 
829*33fb5cbaSJiri Pirko static void fl_init_dissector(struct flow_dissector *dissector,
830*33fb5cbaSJiri Pirko 			      struct fl_flow_key *mask)
83177b9900eSJiri Pirko {
83277b9900eSJiri Pirko 	struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX];
83377b9900eSJiri Pirko 	size_t cnt = 0;
83477b9900eSJiri Pirko 
83542aecaa9STom Herbert 	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control);
83677b9900eSJiri Pirko 	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic);
837*33fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
83877b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_ETH_ADDRS, eth);
839*33fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
84077b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4);
841*33fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
84277b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6);
843*33fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
84477b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_PORTS, tp);
845*33fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
8464d80cc0aSOr Gerlitz 			     FLOW_DISSECTOR_KEY_IP, ip);
847*33fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
848fdfc7dd6SJiri Pirko 			     FLOW_DISSECTOR_KEY_TCP, tcp);
849*33fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
8507b684884SSimon Horman 			     FLOW_DISSECTOR_KEY_ICMP, icmp);
851*33fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
85299d31326SSimon Horman 			     FLOW_DISSECTOR_KEY_ARP, arp);
853*33fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
854a577d8f7SBenjamin LaHaise 			     FLOW_DISSECTOR_KEY_MPLS, mpls);
855*33fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
8569399ae9aSHadar Hen Zion 			     FLOW_DISSECTOR_KEY_VLAN, vlan);
857*33fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
858d64efd09SJianbo Liu 			     FLOW_DISSECTOR_KEY_CVLAN, cvlan);
859*33fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
860519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_KEYID, enc_key_id);
861*33fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
862519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, enc_ipv4);
863*33fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
864519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, enc_ipv6);
865*33fb5cbaSJiri Pirko 	if (FL_KEY_IS_MASKED(mask, enc_ipv4) ||
866*33fb5cbaSJiri Pirko 	    FL_KEY_IS_MASKED(mask, enc_ipv6))
867519d1052SHadar Hen Zion 		FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_ENC_CONTROL,
868519d1052SHadar Hen Zion 			   enc_control);
869*33fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
870f4d997fdSHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp);
871*33fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
8720e2c17b6SOr Gerlitz 			     FLOW_DISSECTOR_KEY_ENC_IP, enc_ip);
87377b9900eSJiri Pirko 
874*33fb5cbaSJiri Pirko 	skb_flow_dissector_init(dissector, keys, cnt);
87505cd271fSPaul Blakey }
87605cd271fSPaul Blakey 
87705cd271fSPaul Blakey static struct fl_flow_mask *fl_create_new_mask(struct cls_fl_head *head,
87805cd271fSPaul Blakey 					       struct fl_flow_mask *mask)
87905cd271fSPaul Blakey {
88005cd271fSPaul Blakey 	struct fl_flow_mask *newmask;
88105cd271fSPaul Blakey 	int err;
88205cd271fSPaul Blakey 
88305cd271fSPaul Blakey 	newmask = kzalloc(sizeof(*newmask), GFP_KERNEL);
88405cd271fSPaul Blakey 	if (!newmask)
88505cd271fSPaul Blakey 		return ERR_PTR(-ENOMEM);
88605cd271fSPaul Blakey 
88705cd271fSPaul Blakey 	fl_mask_copy(newmask, mask);
88805cd271fSPaul Blakey 
88905cd271fSPaul Blakey 	err = fl_init_mask_hashtable(newmask);
89005cd271fSPaul Blakey 	if (err)
89105cd271fSPaul Blakey 		goto errout_free;
89205cd271fSPaul Blakey 
893*33fb5cbaSJiri Pirko 	fl_init_dissector(&newmask->dissector, &newmask->key);
89405cd271fSPaul Blakey 
89505cd271fSPaul Blakey 	INIT_LIST_HEAD_RCU(&newmask->filters);
89605cd271fSPaul Blakey 
89705cd271fSPaul Blakey 	err = rhashtable_insert_fast(&head->ht, &newmask->ht_node,
89805cd271fSPaul Blakey 				     mask_ht_params);
89905cd271fSPaul Blakey 	if (err)
90005cd271fSPaul Blakey 		goto errout_destroy;
90105cd271fSPaul Blakey 
90205cd271fSPaul Blakey 	list_add_tail_rcu(&newmask->list, &head->masks);
90305cd271fSPaul Blakey 
90405cd271fSPaul Blakey 	return newmask;
90505cd271fSPaul Blakey 
90605cd271fSPaul Blakey errout_destroy:
90705cd271fSPaul Blakey 	rhashtable_destroy(&newmask->ht);
90805cd271fSPaul Blakey errout_free:
90905cd271fSPaul Blakey 	kfree(newmask);
91005cd271fSPaul Blakey 
91105cd271fSPaul Blakey 	return ERR_PTR(err);
91277b9900eSJiri Pirko }
91377b9900eSJiri Pirko 
91477b9900eSJiri Pirko static int fl_check_assign_mask(struct cls_fl_head *head,
91505cd271fSPaul Blakey 				struct cls_fl_filter *fnew,
91605cd271fSPaul Blakey 				struct cls_fl_filter *fold,
91777b9900eSJiri Pirko 				struct fl_flow_mask *mask)
91877b9900eSJiri Pirko {
91905cd271fSPaul Blakey 	struct fl_flow_mask *newmask;
92077b9900eSJiri Pirko 
92105cd271fSPaul Blakey 	fnew->mask = rhashtable_lookup_fast(&head->ht, mask, mask_ht_params);
92205cd271fSPaul Blakey 	if (!fnew->mask) {
92305cd271fSPaul Blakey 		if (fold)
92477b9900eSJiri Pirko 			return -EINVAL;
92505cd271fSPaul Blakey 
92605cd271fSPaul Blakey 		newmask = fl_create_new_mask(head, mask);
92705cd271fSPaul Blakey 		if (IS_ERR(newmask))
92805cd271fSPaul Blakey 			return PTR_ERR(newmask);
92905cd271fSPaul Blakey 
93005cd271fSPaul Blakey 		fnew->mask = newmask;
931f6521c58SPaul Blakey 	} else if (fold && fold->mask != fnew->mask) {
93205cd271fSPaul Blakey 		return -EINVAL;
93377b9900eSJiri Pirko 	}
93477b9900eSJiri Pirko 
93577b9900eSJiri Pirko 	return 0;
93677b9900eSJiri Pirko }
93777b9900eSJiri Pirko 
93877b9900eSJiri Pirko static int fl_set_parms(struct net *net, struct tcf_proto *tp,
93977b9900eSJiri Pirko 			struct cls_fl_filter *f, struct fl_flow_mask *mask,
94077b9900eSJiri Pirko 			unsigned long base, struct nlattr **tb,
94150a56190SAlexander Aring 			struct nlattr *est, bool ovr,
94250a56190SAlexander Aring 			struct netlink_ext_ack *extack)
94377b9900eSJiri Pirko {
94477b9900eSJiri Pirko 	int err;
94577b9900eSJiri Pirko 
94650a56190SAlexander Aring 	err = tcf_exts_validate(net, tp, tb, est, &f->exts, ovr, extack);
94777b9900eSJiri Pirko 	if (err < 0)
94877b9900eSJiri Pirko 		return err;
94977b9900eSJiri Pirko 
95077b9900eSJiri Pirko 	if (tb[TCA_FLOWER_CLASSID]) {
95177b9900eSJiri Pirko 		f->res.classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]);
95277b9900eSJiri Pirko 		tcf_bind_filter(tp, &f->res, base);
95377b9900eSJiri Pirko 	}
95477b9900eSJiri Pirko 
9551057c55fSAlexander Aring 	err = fl_set_key(net, tb, &f->key, &mask->key, extack);
95677b9900eSJiri Pirko 	if (err)
95745507529SJiri Pirko 		return err;
95877b9900eSJiri Pirko 
95977b9900eSJiri Pirko 	fl_mask_update_range(mask);
96077b9900eSJiri Pirko 	fl_set_masked_key(&f->mkey, &f->key, mask);
96177b9900eSJiri Pirko 
96277b9900eSJiri Pirko 	return 0;
96377b9900eSJiri Pirko }
96477b9900eSJiri Pirko 
96577b9900eSJiri Pirko static int fl_change(struct net *net, struct sk_buff *in_skb,
96677b9900eSJiri Pirko 		     struct tcf_proto *tp, unsigned long base,
96777b9900eSJiri Pirko 		     u32 handle, struct nlattr **tca,
9687306db38SAlexander Aring 		     void **arg, bool ovr, struct netlink_ext_ack *extack)
96977b9900eSJiri Pirko {
97077b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
9718113c095SWANG Cong 	struct cls_fl_filter *fold = *arg;
97277b9900eSJiri Pirko 	struct cls_fl_filter *fnew;
97339b7b6a6SArnd Bergmann 	struct nlattr **tb;
97477b9900eSJiri Pirko 	struct fl_flow_mask mask = {};
97577b9900eSJiri Pirko 	int err;
97677b9900eSJiri Pirko 
97777b9900eSJiri Pirko 	if (!tca[TCA_OPTIONS])
97877b9900eSJiri Pirko 		return -EINVAL;
97977b9900eSJiri Pirko 
98039b7b6a6SArnd Bergmann 	tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL);
98139b7b6a6SArnd Bergmann 	if (!tb)
98239b7b6a6SArnd Bergmann 		return -ENOBUFS;
98339b7b6a6SArnd Bergmann 
984fceb6435SJohannes Berg 	err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS],
985fceb6435SJohannes Berg 			       fl_policy, NULL);
98677b9900eSJiri Pirko 	if (err < 0)
98739b7b6a6SArnd Bergmann 		goto errout_tb;
98877b9900eSJiri Pirko 
98939b7b6a6SArnd Bergmann 	if (fold && handle && fold->handle != handle) {
99039b7b6a6SArnd Bergmann 		err = -EINVAL;
99139b7b6a6SArnd Bergmann 		goto errout_tb;
99239b7b6a6SArnd Bergmann 	}
99377b9900eSJiri Pirko 
99477b9900eSJiri Pirko 	fnew = kzalloc(sizeof(*fnew), GFP_KERNEL);
99539b7b6a6SArnd Bergmann 	if (!fnew) {
99639b7b6a6SArnd Bergmann 		err = -ENOBUFS;
99739b7b6a6SArnd Bergmann 		goto errout_tb;
99839b7b6a6SArnd Bergmann 	}
99977b9900eSJiri Pirko 
1000b9a24bb7SWANG Cong 	err = tcf_exts_init(&fnew->exts, TCA_FLOWER_ACT, 0);
1001b9a24bb7SWANG Cong 	if (err < 0)
1002b9a24bb7SWANG Cong 		goto errout;
100377b9900eSJiri Pirko 
100477b9900eSJiri Pirko 	if (!handle) {
100585bd0438SMatthew Wilcox 		handle = 1;
100685bd0438SMatthew Wilcox 		err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
100785bd0438SMatthew Wilcox 				    INT_MAX, GFP_KERNEL);
100885bd0438SMatthew Wilcox 	} else if (!fold) {
1009c15ab236SChris Mi 		/* user specifies a handle and it doesn't exist */
101085bd0438SMatthew Wilcox 		err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
101185bd0438SMatthew Wilcox 				    handle, GFP_KERNEL);
101285bd0438SMatthew Wilcox 	}
1013c15ab236SChris Mi 	if (err)
1014c15ab236SChris Mi 		goto errout;
101585bd0438SMatthew Wilcox 	fnew->handle = handle;
101677b9900eSJiri Pirko 
1017e69985c6SAmir Vadai 	if (tb[TCA_FLOWER_FLAGS]) {
1018e69985c6SAmir Vadai 		fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
1019e69985c6SAmir Vadai 
1020e69985c6SAmir Vadai 		if (!tc_flags_valid(fnew->flags)) {
1021e69985c6SAmir Vadai 			err = -EINVAL;
1022fe2502e4SCong Wang 			goto errout_idr;
1023e69985c6SAmir Vadai 		}
1024e69985c6SAmir Vadai 	}
10255b33f488SAmir Vadai 
102650a56190SAlexander Aring 	err = fl_set_parms(net, tp, fnew, &mask, base, tb, tca[TCA_RATE], ovr,
102750a56190SAlexander Aring 			   extack);
102877b9900eSJiri Pirko 	if (err)
1029fe2502e4SCong Wang 		goto errout_idr;
103077b9900eSJiri Pirko 
103105cd271fSPaul Blakey 	err = fl_check_assign_mask(head, fnew, fold, &mask);
103277b9900eSJiri Pirko 	if (err)
1033fe2502e4SCong Wang 		goto errout_idr;
103477b9900eSJiri Pirko 
1035e8eb36cdSAmir Vadai 	if (!tc_skip_sw(fnew->flags)) {
103605cd271fSPaul Blakey 		if (!fold && fl_lookup(fnew->mask, &fnew->mkey)) {
1037a3308d8fSPaul Blakey 			err = -EEXIST;
103805cd271fSPaul Blakey 			goto errout_mask;
1039a3308d8fSPaul Blakey 		}
1040a3308d8fSPaul Blakey 
104105cd271fSPaul Blakey 		err = rhashtable_insert_fast(&fnew->mask->ht, &fnew->ht_node,
104205cd271fSPaul Blakey 					     fnew->mask->filter_ht_params);
104377b9900eSJiri Pirko 		if (err)
104405cd271fSPaul Blakey 			goto errout_mask;
1045e69985c6SAmir Vadai 	}
10465b33f488SAmir Vadai 
104779685219SHadar Hen Zion 	if (!tc_skip_hw(fnew->flags)) {
104805cd271fSPaul Blakey 		err = fl_hw_replace_filter(tp, fnew, extack);
1049e8eb36cdSAmir Vadai 		if (err)
105005cd271fSPaul Blakey 			goto errout_mask;
105179685219SHadar Hen Zion 	}
10525b33f488SAmir Vadai 
105355593960SOr Gerlitz 	if (!tc_in_hw(fnew->flags))
105455593960SOr Gerlitz 		fnew->flags |= TCA_CLS_FLAGS_NOT_IN_HW;
105555593960SOr Gerlitz 
10565b33f488SAmir Vadai 	if (fold) {
1057725cbb62SJiri Pirko 		if (!tc_skip_sw(fold->flags))
105805cd271fSPaul Blakey 			rhashtable_remove_fast(&fold->mask->ht,
105905cd271fSPaul Blakey 					       &fold->ht_node,
106005cd271fSPaul Blakey 					       fold->mask->filter_ht_params);
106179685219SHadar Hen Zion 		if (!tc_skip_hw(fold->flags))
10621b0f8037SJakub Kicinski 			fl_hw_destroy_filter(tp, fold, NULL);
10635b33f488SAmir Vadai 	}
106477b9900eSJiri Pirko 
10658113c095SWANG Cong 	*arg = fnew;
106677b9900eSJiri Pirko 
106777b9900eSJiri Pirko 	if (fold) {
1068234a4624SMatthew Wilcox 		idr_replace(&head->handle_idr, fnew, fnew->handle);
1069ff3532f2SDaniel Borkmann 		list_replace_rcu(&fold->list, &fnew->list);
107077b9900eSJiri Pirko 		tcf_unbind_filter(tp, &fold->res);
10710dadc117SCong Wang 		tcf_exts_get_net(&fold->exts);
1072aaa908ffSCong Wang 		tcf_queue_work(&fold->rwork, fl_destroy_filter_work);
107377b9900eSJiri Pirko 	} else {
107405cd271fSPaul Blakey 		list_add_tail_rcu(&fnew->list, &fnew->mask->filters);
107577b9900eSJiri Pirko 	}
107677b9900eSJiri Pirko 
107739b7b6a6SArnd Bergmann 	kfree(tb);
107877b9900eSJiri Pirko 	return 0;
107977b9900eSJiri Pirko 
108005cd271fSPaul Blakey errout_mask:
108105cd271fSPaul Blakey 	fl_mask_put(head, fnew->mask, false);
108205cd271fSPaul Blakey 
1083fe2502e4SCong Wang errout_idr:
10848258d2daSPaul Blakey 	if (!fold)
10859c160941SMatthew Wilcox 		idr_remove(&head->handle_idr, fnew->handle);
108677b9900eSJiri Pirko errout:
1087b9a24bb7SWANG Cong 	tcf_exts_destroy(&fnew->exts);
108877b9900eSJiri Pirko 	kfree(fnew);
108939b7b6a6SArnd Bergmann errout_tb:
109039b7b6a6SArnd Bergmann 	kfree(tb);
109177b9900eSJiri Pirko 	return err;
109277b9900eSJiri Pirko }
109377b9900eSJiri Pirko 
1094571acf21SAlexander Aring static int fl_delete(struct tcf_proto *tp, void *arg, bool *last,
1095571acf21SAlexander Aring 		     struct netlink_ext_ack *extack)
109677b9900eSJiri Pirko {
109777b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
10988113c095SWANG Cong 	struct cls_fl_filter *f = arg;
109977b9900eSJiri Pirko 
1100725cbb62SJiri Pirko 	if (!tc_skip_sw(f->flags))
110105cd271fSPaul Blakey 		rhashtable_remove_fast(&f->mask->ht, &f->ht_node,
110205cd271fSPaul Blakey 				       f->mask->filter_ht_params);
11031b0f8037SJakub Kicinski 	__fl_delete(tp, f, extack);
110405cd271fSPaul Blakey 	*last = list_empty(&head->masks);
110577b9900eSJiri Pirko 	return 0;
110677b9900eSJiri Pirko }
110777b9900eSJiri Pirko 
110877b9900eSJiri Pirko static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg)
110977b9900eSJiri Pirko {
111077b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
111177b9900eSJiri Pirko 	struct cls_fl_filter *f;
111277b9900eSJiri Pirko 
111301683a14SVlad Buslov 	arg->count = arg->skip;
111401683a14SVlad Buslov 
111501683a14SVlad Buslov 	while ((f = idr_get_next_ul(&head->handle_idr,
111601683a14SVlad Buslov 				    &arg->cookie)) != NULL) {
11178113c095SWANG Cong 		if (arg->fn(tp, f, arg) < 0) {
111877b9900eSJiri Pirko 			arg->stop = 1;
111977b9900eSJiri Pirko 			break;
112077b9900eSJiri Pirko 		}
112101683a14SVlad Buslov 		arg->cookie = f->handle + 1;
112277b9900eSJiri Pirko 		arg->count++;
112377b9900eSJiri Pirko 	}
112477b9900eSJiri Pirko }
112577b9900eSJiri Pirko 
112631533cbaSJohn Hurley static int fl_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb,
112731533cbaSJohn Hurley 			void *cb_priv, struct netlink_ext_ack *extack)
112831533cbaSJohn Hurley {
112931533cbaSJohn Hurley 	struct cls_fl_head *head = rtnl_dereference(tp->root);
113031533cbaSJohn Hurley 	struct tc_cls_flower_offload cls_flower = {};
113131533cbaSJohn Hurley 	struct tcf_block *block = tp->chain->block;
113231533cbaSJohn Hurley 	struct fl_flow_mask *mask;
113331533cbaSJohn Hurley 	struct cls_fl_filter *f;
113431533cbaSJohn Hurley 	int err;
113531533cbaSJohn Hurley 
113631533cbaSJohn Hurley 	list_for_each_entry(mask, &head->masks, list) {
113731533cbaSJohn Hurley 		list_for_each_entry(f, &mask->filters, list) {
113831533cbaSJohn Hurley 			if (tc_skip_hw(f->flags))
113931533cbaSJohn Hurley 				continue;
114031533cbaSJohn Hurley 
114131533cbaSJohn Hurley 			tc_cls_common_offload_init(&cls_flower.common, tp,
114231533cbaSJohn Hurley 						   f->flags, extack);
114331533cbaSJohn Hurley 			cls_flower.command = add ?
114431533cbaSJohn Hurley 				TC_CLSFLOWER_REPLACE : TC_CLSFLOWER_DESTROY;
114531533cbaSJohn Hurley 			cls_flower.cookie = (unsigned long)f;
114631533cbaSJohn Hurley 			cls_flower.dissector = &mask->dissector;
114731533cbaSJohn Hurley 			cls_flower.mask = &f->mkey;
114831533cbaSJohn Hurley 			cls_flower.key = &f->key;
114931533cbaSJohn Hurley 			cls_flower.exts = &f->exts;
115031533cbaSJohn Hurley 			cls_flower.classid = f->res.classid;
115131533cbaSJohn Hurley 
115231533cbaSJohn Hurley 			err = cb(TC_SETUP_CLSFLOWER, &cls_flower, cb_priv);
115331533cbaSJohn Hurley 			if (err) {
115431533cbaSJohn Hurley 				if (add && tc_skip_sw(f->flags))
115531533cbaSJohn Hurley 					return err;
115631533cbaSJohn Hurley 				continue;
115731533cbaSJohn Hurley 			}
115831533cbaSJohn Hurley 
115931533cbaSJohn Hurley 			tc_cls_offload_cnt_update(block, &f->in_hw_count,
116031533cbaSJohn Hurley 						  &f->flags, add);
116131533cbaSJohn Hurley 		}
116231533cbaSJohn Hurley 	}
116331533cbaSJohn Hurley 
116431533cbaSJohn Hurley 	return 0;
116531533cbaSJohn Hurley }
116631533cbaSJohn Hurley 
116777b9900eSJiri Pirko static int fl_dump_key_val(struct sk_buff *skb,
116877b9900eSJiri Pirko 			   void *val, int val_type,
116977b9900eSJiri Pirko 			   void *mask, int mask_type, int len)
117077b9900eSJiri Pirko {
117177b9900eSJiri Pirko 	int err;
117277b9900eSJiri Pirko 
117377b9900eSJiri Pirko 	if (!memchr_inv(mask, 0, len))
117477b9900eSJiri Pirko 		return 0;
117577b9900eSJiri Pirko 	err = nla_put(skb, val_type, len, val);
117677b9900eSJiri Pirko 	if (err)
117777b9900eSJiri Pirko 		return err;
117877b9900eSJiri Pirko 	if (mask_type != TCA_FLOWER_UNSPEC) {
117977b9900eSJiri Pirko 		err = nla_put(skb, mask_type, len, mask);
118077b9900eSJiri Pirko 		if (err)
118177b9900eSJiri Pirko 			return err;
118277b9900eSJiri Pirko 	}
118377b9900eSJiri Pirko 	return 0;
118477b9900eSJiri Pirko }
118577b9900eSJiri Pirko 
1186a577d8f7SBenjamin LaHaise static int fl_dump_key_mpls(struct sk_buff *skb,
1187a577d8f7SBenjamin LaHaise 			    struct flow_dissector_key_mpls *mpls_key,
1188a577d8f7SBenjamin LaHaise 			    struct flow_dissector_key_mpls *mpls_mask)
1189a577d8f7SBenjamin LaHaise {
1190a577d8f7SBenjamin LaHaise 	int err;
1191a577d8f7SBenjamin LaHaise 
1192a577d8f7SBenjamin LaHaise 	if (!memchr_inv(mpls_mask, 0, sizeof(*mpls_mask)))
1193a577d8f7SBenjamin LaHaise 		return 0;
1194a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_ttl) {
1195a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TTL,
1196a577d8f7SBenjamin LaHaise 				 mpls_key->mpls_ttl);
1197a577d8f7SBenjamin LaHaise 		if (err)
1198a577d8f7SBenjamin LaHaise 			return err;
1199a577d8f7SBenjamin LaHaise 	}
1200a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_tc) {
1201a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TC,
1202a577d8f7SBenjamin LaHaise 				 mpls_key->mpls_tc);
1203a577d8f7SBenjamin LaHaise 		if (err)
1204a577d8f7SBenjamin LaHaise 			return err;
1205a577d8f7SBenjamin LaHaise 	}
1206a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_label) {
1207a577d8f7SBenjamin LaHaise 		err = nla_put_u32(skb, TCA_FLOWER_KEY_MPLS_LABEL,
1208a577d8f7SBenjamin LaHaise 				  mpls_key->mpls_label);
1209a577d8f7SBenjamin LaHaise 		if (err)
1210a577d8f7SBenjamin LaHaise 			return err;
1211a577d8f7SBenjamin LaHaise 	}
1212a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_bos) {
1213a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_BOS,
1214a577d8f7SBenjamin LaHaise 				 mpls_key->mpls_bos);
1215a577d8f7SBenjamin LaHaise 		if (err)
1216a577d8f7SBenjamin LaHaise 			return err;
1217a577d8f7SBenjamin LaHaise 	}
1218a577d8f7SBenjamin LaHaise 	return 0;
1219a577d8f7SBenjamin LaHaise }
1220a577d8f7SBenjamin LaHaise 
12210e2c17b6SOr Gerlitz static int fl_dump_key_ip(struct sk_buff *skb, bool encap,
12224d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *key,
12234d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *mask)
12244d80cc0aSOr Gerlitz {
12250e2c17b6SOr Gerlitz 	int tos_key = encap ? TCA_FLOWER_KEY_ENC_IP_TOS : TCA_FLOWER_KEY_IP_TOS;
12260e2c17b6SOr Gerlitz 	int ttl_key = encap ? TCA_FLOWER_KEY_ENC_IP_TTL : TCA_FLOWER_KEY_IP_TTL;
12270e2c17b6SOr Gerlitz 	int tos_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TOS_MASK : TCA_FLOWER_KEY_IP_TOS_MASK;
12280e2c17b6SOr Gerlitz 	int ttl_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TTL_MASK : TCA_FLOWER_KEY_IP_TTL_MASK;
12290e2c17b6SOr Gerlitz 
12300e2c17b6SOr Gerlitz 	if (fl_dump_key_val(skb, &key->tos, tos_key, &mask->tos, tos_mask, sizeof(key->tos)) ||
12310e2c17b6SOr Gerlitz 	    fl_dump_key_val(skb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl)))
12324d80cc0aSOr Gerlitz 		return -1;
12334d80cc0aSOr Gerlitz 
12344d80cc0aSOr Gerlitz 	return 0;
12354d80cc0aSOr Gerlitz }
12364d80cc0aSOr Gerlitz 
12379399ae9aSHadar Hen Zion static int fl_dump_key_vlan(struct sk_buff *skb,
1238d64efd09SJianbo Liu 			    int vlan_id_key, int vlan_prio_key,
12399399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *vlan_key,
12409399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *vlan_mask)
12419399ae9aSHadar Hen Zion {
12429399ae9aSHadar Hen Zion 	int err;
12439399ae9aSHadar Hen Zion 
12449399ae9aSHadar Hen Zion 	if (!memchr_inv(vlan_mask, 0, sizeof(*vlan_mask)))
12459399ae9aSHadar Hen Zion 		return 0;
12469399ae9aSHadar Hen Zion 	if (vlan_mask->vlan_id) {
1247d64efd09SJianbo Liu 		err = nla_put_u16(skb, vlan_id_key,
12489399ae9aSHadar Hen Zion 				  vlan_key->vlan_id);
12499399ae9aSHadar Hen Zion 		if (err)
12509399ae9aSHadar Hen Zion 			return err;
12519399ae9aSHadar Hen Zion 	}
12529399ae9aSHadar Hen Zion 	if (vlan_mask->vlan_priority) {
1253d64efd09SJianbo Liu 		err = nla_put_u8(skb, vlan_prio_key,
12549399ae9aSHadar Hen Zion 				 vlan_key->vlan_priority);
12559399ae9aSHadar Hen Zion 		if (err)
12569399ae9aSHadar Hen Zion 			return err;
12579399ae9aSHadar Hen Zion 	}
12589399ae9aSHadar Hen Zion 	return 0;
12599399ae9aSHadar Hen Zion }
12609399ae9aSHadar Hen Zion 
1261faa3ffceSOr Gerlitz static void fl_get_key_flag(u32 dissector_key, u32 dissector_mask,
1262faa3ffceSOr Gerlitz 			    u32 *flower_key, u32 *flower_mask,
1263faa3ffceSOr Gerlitz 			    u32 flower_flag_bit, u32 dissector_flag_bit)
1264faa3ffceSOr Gerlitz {
1265faa3ffceSOr Gerlitz 	if (dissector_mask & dissector_flag_bit) {
1266faa3ffceSOr Gerlitz 		*flower_mask |= flower_flag_bit;
1267faa3ffceSOr Gerlitz 		if (dissector_key & dissector_flag_bit)
1268faa3ffceSOr Gerlitz 			*flower_key |= flower_flag_bit;
1269faa3ffceSOr Gerlitz 	}
1270faa3ffceSOr Gerlitz }
1271faa3ffceSOr Gerlitz 
1272faa3ffceSOr Gerlitz static int fl_dump_key_flags(struct sk_buff *skb, u32 flags_key, u32 flags_mask)
1273faa3ffceSOr Gerlitz {
1274faa3ffceSOr Gerlitz 	u32 key, mask;
1275faa3ffceSOr Gerlitz 	__be32 _key, _mask;
1276faa3ffceSOr Gerlitz 	int err;
1277faa3ffceSOr Gerlitz 
1278faa3ffceSOr Gerlitz 	if (!memchr_inv(&flags_mask, 0, sizeof(flags_mask)))
1279faa3ffceSOr Gerlitz 		return 0;
1280faa3ffceSOr Gerlitz 
1281faa3ffceSOr Gerlitz 	key = 0;
1282faa3ffceSOr Gerlitz 	mask = 0;
1283faa3ffceSOr Gerlitz 
1284faa3ffceSOr Gerlitz 	fl_get_key_flag(flags_key, flags_mask, &key, &mask,
1285faa3ffceSOr Gerlitz 			TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT);
1286459d153dSPieter Jansen van Vuuren 	fl_get_key_flag(flags_key, flags_mask, &key, &mask,
1287459d153dSPieter Jansen van Vuuren 			TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST,
1288459d153dSPieter Jansen van Vuuren 			FLOW_DIS_FIRST_FRAG);
1289faa3ffceSOr Gerlitz 
1290faa3ffceSOr Gerlitz 	_key = cpu_to_be32(key);
1291faa3ffceSOr Gerlitz 	_mask = cpu_to_be32(mask);
1292faa3ffceSOr Gerlitz 
1293faa3ffceSOr Gerlitz 	err = nla_put(skb, TCA_FLOWER_KEY_FLAGS, 4, &_key);
1294faa3ffceSOr Gerlitz 	if (err)
1295faa3ffceSOr Gerlitz 		return err;
1296faa3ffceSOr Gerlitz 
1297faa3ffceSOr Gerlitz 	return nla_put(skb, TCA_FLOWER_KEY_FLAGS_MASK, 4, &_mask);
1298faa3ffceSOr Gerlitz }
1299faa3ffceSOr Gerlitz 
1300f5749081SJiri Pirko static int fl_dump_key(struct sk_buff *skb, struct net *net,
1301f5749081SJiri Pirko 		       struct fl_flow_key *key, struct fl_flow_key *mask)
130277b9900eSJiri Pirko {
130377b9900eSJiri Pirko 	if (mask->indev_ifindex) {
130477b9900eSJiri Pirko 		struct net_device *dev;
130577b9900eSJiri Pirko 
130677b9900eSJiri Pirko 		dev = __dev_get_by_index(net, key->indev_ifindex);
130777b9900eSJiri Pirko 		if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name))
130877b9900eSJiri Pirko 			goto nla_put_failure;
130977b9900eSJiri Pirko 	}
131077b9900eSJiri Pirko 
131177b9900eSJiri Pirko 	if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
131277b9900eSJiri Pirko 			    mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
131377b9900eSJiri Pirko 			    sizeof(key->eth.dst)) ||
131477b9900eSJiri Pirko 	    fl_dump_key_val(skb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
131577b9900eSJiri Pirko 			    mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
131677b9900eSJiri Pirko 			    sizeof(key->eth.src)) ||
131777b9900eSJiri Pirko 	    fl_dump_key_val(skb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE,
131877b9900eSJiri Pirko 			    &mask->basic.n_proto, TCA_FLOWER_UNSPEC,
131977b9900eSJiri Pirko 			    sizeof(key->basic.n_proto)))
132077b9900eSJiri Pirko 		goto nla_put_failure;
13219399ae9aSHadar Hen Zion 
1322a577d8f7SBenjamin LaHaise 	if (fl_dump_key_mpls(skb, &key->mpls, &mask->mpls))
1323a577d8f7SBenjamin LaHaise 		goto nla_put_failure;
1324a577d8f7SBenjamin LaHaise 
1325d64efd09SJianbo Liu 	if (fl_dump_key_vlan(skb, TCA_FLOWER_KEY_VLAN_ID,
1326d64efd09SJianbo Liu 			     TCA_FLOWER_KEY_VLAN_PRIO, &key->vlan, &mask->vlan))
13279399ae9aSHadar Hen Zion 		goto nla_put_failure;
13289399ae9aSHadar Hen Zion 
1329d64efd09SJianbo Liu 	if (fl_dump_key_vlan(skb, TCA_FLOWER_KEY_CVLAN_ID,
1330d64efd09SJianbo Liu 			     TCA_FLOWER_KEY_CVLAN_PRIO,
1331d64efd09SJianbo Liu 			     &key->cvlan, &mask->cvlan) ||
1332d64efd09SJianbo Liu 	    (mask->cvlan.vlan_tpid &&
1333d64efd09SJianbo Liu 	     nla_put_u16(skb, TCA_FLOWER_KEY_VLAN_ETH_TYPE,
1334d64efd09SJianbo Liu 			 key->cvlan.vlan_tpid)))
1335d3069512SJianbo Liu 		goto nla_put_failure;
1336d3069512SJianbo Liu 
13375e9a0fe4SJianbo Liu 	if (mask->basic.n_proto) {
1338d64efd09SJianbo Liu 		if (mask->cvlan.vlan_tpid) {
1339d64efd09SJianbo Liu 			if (nla_put_be16(skb, TCA_FLOWER_KEY_CVLAN_ETH_TYPE,
1340d64efd09SJianbo Liu 					 key->basic.n_proto))
1341d64efd09SJianbo Liu 				goto nla_put_failure;
1342d64efd09SJianbo Liu 		} else if (mask->vlan.vlan_tpid) {
1343d64efd09SJianbo Liu 			if (nla_put_be16(skb, TCA_FLOWER_KEY_VLAN_ETH_TYPE,
1344d64efd09SJianbo Liu 					 key->basic.n_proto))
1345d64efd09SJianbo Liu 				goto nla_put_failure;
1346d64efd09SJianbo Liu 		}
13475e9a0fe4SJianbo Liu 	}
1348d64efd09SJianbo Liu 
134977b9900eSJiri Pirko 	if ((key->basic.n_proto == htons(ETH_P_IP) ||
135077b9900eSJiri Pirko 	     key->basic.n_proto == htons(ETH_P_IPV6)) &&
13514d80cc0aSOr Gerlitz 	    (fl_dump_key_val(skb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
135277b9900eSJiri Pirko 			    &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
13534d80cc0aSOr Gerlitz 			    sizeof(key->basic.ip_proto)) ||
13540e2c17b6SOr Gerlitz 	    fl_dump_key_ip(skb, false, &key->ip, &mask->ip)))
135577b9900eSJiri Pirko 		goto nla_put_failure;
135677b9900eSJiri Pirko 
1357c3f83241STom Herbert 	if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
135877b9900eSJiri Pirko 	    (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
135977b9900eSJiri Pirko 			     &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
136077b9900eSJiri Pirko 			     sizeof(key->ipv4.src)) ||
136177b9900eSJiri Pirko 	     fl_dump_key_val(skb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
136277b9900eSJiri Pirko 			     &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
136377b9900eSJiri Pirko 			     sizeof(key->ipv4.dst))))
136477b9900eSJiri Pirko 		goto nla_put_failure;
1365c3f83241STom Herbert 	else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
136677b9900eSJiri Pirko 		 (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
136777b9900eSJiri Pirko 				  &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
136877b9900eSJiri Pirko 				  sizeof(key->ipv6.src)) ||
136977b9900eSJiri Pirko 		  fl_dump_key_val(skb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
137077b9900eSJiri Pirko 				  &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
137177b9900eSJiri Pirko 				  sizeof(key->ipv6.dst))))
137277b9900eSJiri Pirko 		goto nla_put_failure;
137377b9900eSJiri Pirko 
137477b9900eSJiri Pirko 	if (key->basic.ip_proto == IPPROTO_TCP &&
137577b9900eSJiri Pirko 	    (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
1376aa72d708SOr Gerlitz 			     &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
137777b9900eSJiri Pirko 			     sizeof(key->tp.src)) ||
137877b9900eSJiri Pirko 	     fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
1379aa72d708SOr Gerlitz 			     &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
1380fdfc7dd6SJiri Pirko 			     sizeof(key->tp.dst)) ||
1381fdfc7dd6SJiri Pirko 	     fl_dump_key_val(skb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS,
1382fdfc7dd6SJiri Pirko 			     &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK,
1383fdfc7dd6SJiri Pirko 			     sizeof(key->tcp.flags))))
138477b9900eSJiri Pirko 		goto nla_put_failure;
138577b9900eSJiri Pirko 	else if (key->basic.ip_proto == IPPROTO_UDP &&
138677b9900eSJiri Pirko 		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
1387aa72d708SOr Gerlitz 				  &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
138877b9900eSJiri Pirko 				  sizeof(key->tp.src)) ||
138977b9900eSJiri Pirko 		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
1390aa72d708SOr Gerlitz 				  &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
139177b9900eSJiri Pirko 				  sizeof(key->tp.dst))))
139277b9900eSJiri Pirko 		goto nla_put_failure;
13935976c5f4SSimon Horman 	else if (key->basic.ip_proto == IPPROTO_SCTP &&
13945976c5f4SSimon Horman 		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
13955976c5f4SSimon Horman 				  &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
13965976c5f4SSimon Horman 				  sizeof(key->tp.src)) ||
13975976c5f4SSimon Horman 		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
13985976c5f4SSimon Horman 				  &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
13995976c5f4SSimon Horman 				  sizeof(key->tp.dst))))
14005976c5f4SSimon Horman 		goto nla_put_failure;
14017b684884SSimon Horman 	else if (key->basic.n_proto == htons(ETH_P_IP) &&
14027b684884SSimon Horman 		 key->basic.ip_proto == IPPROTO_ICMP &&
14037b684884SSimon Horman 		 (fl_dump_key_val(skb, &key->icmp.type,
14047b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_TYPE, &mask->icmp.type,
14057b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,
14067b684884SSimon Horman 				  sizeof(key->icmp.type)) ||
14077b684884SSimon Horman 		  fl_dump_key_val(skb, &key->icmp.code,
14087b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_CODE, &mask->icmp.code,
14097b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
14107b684884SSimon Horman 				  sizeof(key->icmp.code))))
14117b684884SSimon Horman 		goto nla_put_failure;
14127b684884SSimon Horman 	else if (key->basic.n_proto == htons(ETH_P_IPV6) &&
14137b684884SSimon Horman 		 key->basic.ip_proto == IPPROTO_ICMPV6 &&
14147b684884SSimon Horman 		 (fl_dump_key_val(skb, &key->icmp.type,
14157b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_TYPE, &mask->icmp.type,
14167b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
14177b684884SSimon Horman 				  sizeof(key->icmp.type)) ||
14187b684884SSimon Horman 		  fl_dump_key_val(skb, &key->icmp.code,
14197b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_CODE, &mask->icmp.code,
14207b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_CODE_MASK,
14217b684884SSimon Horman 				  sizeof(key->icmp.code))))
14227b684884SSimon Horman 		goto nla_put_failure;
142399d31326SSimon Horman 	else if ((key->basic.n_proto == htons(ETH_P_ARP) ||
142499d31326SSimon Horman 		  key->basic.n_proto == htons(ETH_P_RARP)) &&
142599d31326SSimon Horman 		 (fl_dump_key_val(skb, &key->arp.sip,
142699d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_SIP, &mask->arp.sip,
142799d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_SIP_MASK,
142899d31326SSimon Horman 				  sizeof(key->arp.sip)) ||
142999d31326SSimon Horman 		  fl_dump_key_val(skb, &key->arp.tip,
143099d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_TIP, &mask->arp.tip,
143199d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_TIP_MASK,
143299d31326SSimon Horman 				  sizeof(key->arp.tip)) ||
143399d31326SSimon Horman 		  fl_dump_key_val(skb, &key->arp.op,
143499d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_OP, &mask->arp.op,
143599d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_OP_MASK,
143699d31326SSimon Horman 				  sizeof(key->arp.op)) ||
143799d31326SSimon Horman 		  fl_dump_key_val(skb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA,
143899d31326SSimon Horman 				  mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK,
143999d31326SSimon Horman 				  sizeof(key->arp.sha)) ||
144099d31326SSimon Horman 		  fl_dump_key_val(skb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA,
144199d31326SSimon Horman 				  mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK,
144299d31326SSimon Horman 				  sizeof(key->arp.tha))))
144399d31326SSimon Horman 		goto nla_put_failure;
144477b9900eSJiri Pirko 
1445bc3103f1SAmir Vadai 	if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
1446bc3103f1SAmir Vadai 	    (fl_dump_key_val(skb, &key->enc_ipv4.src,
1447bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV4_SRC, &mask->enc_ipv4.src,
1448bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
1449bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv4.src)) ||
1450bc3103f1SAmir Vadai 	     fl_dump_key_val(skb, &key->enc_ipv4.dst,
1451bc3103f1SAmir Vadai 			     TCA_FLOWER_KEY_ENC_IPV4_DST, &mask->enc_ipv4.dst,
1452bc3103f1SAmir Vadai 			     TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
1453bc3103f1SAmir Vadai 			     sizeof(key->enc_ipv4.dst))))
1454bc3103f1SAmir Vadai 		goto nla_put_failure;
1455bc3103f1SAmir Vadai 	else if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
1456bc3103f1SAmir Vadai 		 (fl_dump_key_val(skb, &key->enc_ipv6.src,
1457bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV6_SRC, &mask->enc_ipv6.src,
1458bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
1459bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv6.src)) ||
1460bc3103f1SAmir Vadai 		 fl_dump_key_val(skb, &key->enc_ipv6.dst,
1461bc3103f1SAmir Vadai 				 TCA_FLOWER_KEY_ENC_IPV6_DST,
1462bc3103f1SAmir Vadai 				 &mask->enc_ipv6.dst,
1463bc3103f1SAmir Vadai 				 TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
1464bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv6.dst))))
1465bc3103f1SAmir Vadai 		goto nla_put_failure;
1466bc3103f1SAmir Vadai 
1467bc3103f1SAmir Vadai 	if (fl_dump_key_val(skb, &key->enc_key_id, TCA_FLOWER_KEY_ENC_KEY_ID,
1468eb523f42SHadar Hen Zion 			    &mask->enc_key_id, TCA_FLOWER_UNSPEC,
1469f4d997fdSHadar Hen Zion 			    sizeof(key->enc_key_id)) ||
1470f4d997fdSHadar Hen Zion 	    fl_dump_key_val(skb, &key->enc_tp.src,
1471f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
1472f4d997fdSHadar Hen Zion 			    &mask->enc_tp.src,
1473f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
1474f4d997fdSHadar Hen Zion 			    sizeof(key->enc_tp.src)) ||
1475f4d997fdSHadar Hen Zion 	    fl_dump_key_val(skb, &key->enc_tp.dst,
1476f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
1477f4d997fdSHadar Hen Zion 			    &mask->enc_tp.dst,
1478f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
14790e2c17b6SOr Gerlitz 			    sizeof(key->enc_tp.dst)) ||
14800e2c17b6SOr Gerlitz 	    fl_dump_key_ip(skb, true, &key->enc_ip, &mask->enc_ip))
1481bc3103f1SAmir Vadai 		goto nla_put_failure;
1482bc3103f1SAmir Vadai 
1483faa3ffceSOr Gerlitz 	if (fl_dump_key_flags(skb, key->control.flags, mask->control.flags))
1484faa3ffceSOr Gerlitz 		goto nla_put_failure;
1485faa3ffceSOr Gerlitz 
1486f5749081SJiri Pirko 	return 0;
1487f5749081SJiri Pirko 
1488f5749081SJiri Pirko nla_put_failure:
1489f5749081SJiri Pirko 	return -EMSGSIZE;
1490f5749081SJiri Pirko }
1491f5749081SJiri Pirko 
1492f5749081SJiri Pirko static int fl_dump(struct net *net, struct tcf_proto *tp, void *fh,
1493f5749081SJiri Pirko 		   struct sk_buff *skb, struct tcmsg *t)
1494f5749081SJiri Pirko {
1495f5749081SJiri Pirko 	struct cls_fl_filter *f = fh;
1496f5749081SJiri Pirko 	struct nlattr *nest;
1497f5749081SJiri Pirko 	struct fl_flow_key *key, *mask;
1498f5749081SJiri Pirko 
1499f5749081SJiri Pirko 	if (!f)
1500f5749081SJiri Pirko 		return skb->len;
1501f5749081SJiri Pirko 
1502f5749081SJiri Pirko 	t->tcm_handle = f->handle;
1503f5749081SJiri Pirko 
1504f5749081SJiri Pirko 	nest = nla_nest_start(skb, TCA_OPTIONS);
1505f5749081SJiri Pirko 	if (!nest)
1506f5749081SJiri Pirko 		goto nla_put_failure;
1507f5749081SJiri Pirko 
1508f5749081SJiri Pirko 	if (f->res.classid &&
1509f5749081SJiri Pirko 	    nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid))
1510f5749081SJiri Pirko 		goto nla_put_failure;
1511f5749081SJiri Pirko 
1512f5749081SJiri Pirko 	key = &f->key;
1513f5749081SJiri Pirko 	mask = &f->mask->key;
1514f5749081SJiri Pirko 
1515f5749081SJiri Pirko 	if (fl_dump_key(skb, net, key, mask))
1516f5749081SJiri Pirko 		goto nla_put_failure;
1517f5749081SJiri Pirko 
1518f5749081SJiri Pirko 	if (!tc_skip_hw(f->flags))
1519f5749081SJiri Pirko 		fl_hw_update_stats(tp, f);
1520f5749081SJiri Pirko 
1521749e6720SOr Gerlitz 	if (f->flags && nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags))
1522749e6720SOr Gerlitz 		goto nla_put_failure;
1523e69985c6SAmir Vadai 
152477b9900eSJiri Pirko 	if (tcf_exts_dump(skb, &f->exts))
152577b9900eSJiri Pirko 		goto nla_put_failure;
152677b9900eSJiri Pirko 
152777b9900eSJiri Pirko 	nla_nest_end(skb, nest);
152877b9900eSJiri Pirko 
152977b9900eSJiri Pirko 	if (tcf_exts_dump_stats(skb, &f->exts) < 0)
153077b9900eSJiri Pirko 		goto nla_put_failure;
153177b9900eSJiri Pirko 
153277b9900eSJiri Pirko 	return skb->len;
153377b9900eSJiri Pirko 
153477b9900eSJiri Pirko nla_put_failure:
153577b9900eSJiri Pirko 	nla_nest_cancel(skb, nest);
153677b9900eSJiri Pirko 	return -1;
153777b9900eSJiri Pirko }
153877b9900eSJiri Pirko 
153907d79fc7SCong Wang static void fl_bind_class(void *fh, u32 classid, unsigned long cl)
154007d79fc7SCong Wang {
154107d79fc7SCong Wang 	struct cls_fl_filter *f = fh;
154207d79fc7SCong Wang 
154307d79fc7SCong Wang 	if (f && f->res.classid == classid)
154407d79fc7SCong Wang 		f->res.class = cl;
154507d79fc7SCong Wang }
154607d79fc7SCong Wang 
154777b9900eSJiri Pirko static struct tcf_proto_ops cls_fl_ops __read_mostly = {
154877b9900eSJiri Pirko 	.kind		= "flower",
154977b9900eSJiri Pirko 	.classify	= fl_classify,
155077b9900eSJiri Pirko 	.init		= fl_init,
155177b9900eSJiri Pirko 	.destroy	= fl_destroy,
155277b9900eSJiri Pirko 	.get		= fl_get,
155377b9900eSJiri Pirko 	.change		= fl_change,
155477b9900eSJiri Pirko 	.delete		= fl_delete,
155577b9900eSJiri Pirko 	.walk		= fl_walk,
155631533cbaSJohn Hurley 	.reoffload	= fl_reoffload,
155777b9900eSJiri Pirko 	.dump		= fl_dump,
155807d79fc7SCong Wang 	.bind_class	= fl_bind_class,
155977b9900eSJiri Pirko 	.owner		= THIS_MODULE,
156077b9900eSJiri Pirko };
156177b9900eSJiri Pirko 
156277b9900eSJiri Pirko static int __init cls_fl_init(void)
156377b9900eSJiri Pirko {
156477b9900eSJiri Pirko 	return register_tcf_proto_ops(&cls_fl_ops);
156577b9900eSJiri Pirko }
156677b9900eSJiri Pirko 
156777b9900eSJiri Pirko static void __exit cls_fl_exit(void)
156877b9900eSJiri Pirko {
156977b9900eSJiri Pirko 	unregister_tcf_proto_ops(&cls_fl_ops);
157077b9900eSJiri Pirko }
157177b9900eSJiri Pirko 
157277b9900eSJiri Pirko module_init(cls_fl_init);
157377b9900eSJiri Pirko module_exit(cls_fl_exit);
157477b9900eSJiri Pirko 
157577b9900eSJiri Pirko MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>");
157677b9900eSJiri Pirko MODULE_DESCRIPTION("Flower classifier");
157777b9900eSJiri Pirko MODULE_LICENSE("GPL v2");
1578