xref: /linux/net/sched/cls_flower.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
277b9900eSJiri Pirko /*
377b9900eSJiri Pirko  * net/sched/cls_flower.c		Flower classifier
477b9900eSJiri Pirko  *
577b9900eSJiri Pirko  * Copyright (c) 2015 Jiri Pirko <jiri@resnulli.us>
677b9900eSJiri Pirko  */
777b9900eSJiri Pirko 
877b9900eSJiri Pirko #include <linux/kernel.h>
977b9900eSJiri Pirko #include <linux/init.h>
1077b9900eSJiri Pirko #include <linux/module.h>
1177b9900eSJiri Pirko #include <linux/rhashtable.h>
12d9363774SDaniel Borkmann #include <linux/workqueue.h>
1306177558SVlad Buslov #include <linux/refcount.h>
147cfffd5fSZahari Doychev #include <linux/bitfield.h>
1577b9900eSJiri Pirko 
1677b9900eSJiri Pirko #include <linux/if_ether.h>
1777b9900eSJiri Pirko #include <linux/in6.h>
1877b9900eSJiri Pirko #include <linux/ip.h>
19a577d8f7SBenjamin LaHaise #include <linux/mpls.h>
205008750eSWojciech Drewek #include <linux/ppp_defs.h>
2177b9900eSJiri Pirko 
2277b9900eSJiri Pirko #include <net/sch_generic.h>
2377b9900eSJiri Pirko #include <net/pkt_cls.h>
24ec624fe7SPaul Blakey #include <net/pkt_sched.h>
2577b9900eSJiri Pirko #include <net/ip.h>
2677b9900eSJiri Pirko #include <net/flow_dissector.h>
270a6e7778SPieter Jansen van Vuuren #include <net/geneve.h>
28d8f9dfaeSXin Long #include <net/vxlan.h>
2979b1011cSXin Long #include <net/erspan.h>
30e3acda7aSWojciech Drewek #include <net/gtp.h>
316dd514f4SMichal Swiatkowski #include <net/pfcp.h>
329f3101dcSPedro Tammela #include <net/tc_wrapper.h>
3377b9900eSJiri Pirko 
34bc3103f1SAmir Vadai #include <net/dst.h>
35bc3103f1SAmir Vadai #include <net/dst_metadata.h>
36bc3103f1SAmir Vadai 
37e0ace68aSPaul Blakey #include <uapi/linux/netfilter/nf_conntrack_common.h>
38e0ace68aSPaul Blakey 
391bcc51acSwenxu #define TCA_FLOWER_KEY_CT_FLAGS_MAX \
401bcc51acSwenxu 		((__TCA_FLOWER_KEY_CT_FLAGS_MAX - 1) << 1)
411bcc51acSwenxu #define TCA_FLOWER_KEY_CT_FLAGS_MASK \
421bcc51acSwenxu 		(TCA_FLOWER_KEY_CT_FLAGS_MAX - 1)
431bcc51acSwenxu 
440e83a787SAsbjørn Sloth Tønnesen #define TCA_FLOWER_KEY_FLAGS_POLICY_MASK \
450e83a787SAsbjørn Sloth Tønnesen 		(TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT | \
460e83a787SAsbjørn Sloth Tønnesen 		TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST)
470e83a787SAsbjørn Sloth Tønnesen 
4811036bd7SAsbjørn Sloth Tønnesen #define TCA_FLOWER_KEY_ENC_FLAGS_POLICY_MASK \
4911036bd7SAsbjørn Sloth Tønnesen 		(TCA_FLOWER_KEY_FLAGS_TUNNEL_CSUM | \
5011036bd7SAsbjørn Sloth Tønnesen 		TCA_FLOWER_KEY_FLAGS_TUNNEL_DONT_FRAGMENT | \
5111036bd7SAsbjørn Sloth Tønnesen 		TCA_FLOWER_KEY_FLAGS_TUNNEL_OAM | \
5211036bd7SAsbjørn Sloth Tønnesen 		TCA_FLOWER_KEY_FLAGS_TUNNEL_CRIT_OPT)
531d17568eSDavide Caratti 
5477b9900eSJiri Pirko struct fl_flow_key {
558212ed77SJiri Pirko 	struct flow_dissector_key_meta meta;
5642aecaa9STom Herbert 	struct flow_dissector_key_control control;
57bc3103f1SAmir Vadai 	struct flow_dissector_key_control enc_control;
5877b9900eSJiri Pirko 	struct flow_dissector_key_basic basic;
5977b9900eSJiri Pirko 	struct flow_dissector_key_eth_addrs eth;
609399ae9aSHadar Hen Zion 	struct flow_dissector_key_vlan vlan;
61d64efd09SJianbo Liu 	struct flow_dissector_key_vlan cvlan;
6277b9900eSJiri Pirko 	union {
63c3f83241STom Herbert 		struct flow_dissector_key_ipv4_addrs ipv4;
6477b9900eSJiri Pirko 		struct flow_dissector_key_ipv6_addrs ipv6;
6577b9900eSJiri Pirko 	};
6677b9900eSJiri Pirko 	struct flow_dissector_key_ports tp;
677b684884SSimon Horman 	struct flow_dissector_key_icmp icmp;
6899d31326SSimon Horman 	struct flow_dissector_key_arp arp;
69bc3103f1SAmir Vadai 	struct flow_dissector_key_keyid enc_key_id;
70bc3103f1SAmir Vadai 	union {
71bc3103f1SAmir Vadai 		struct flow_dissector_key_ipv4_addrs enc_ipv4;
72bc3103f1SAmir Vadai 		struct flow_dissector_key_ipv6_addrs enc_ipv6;
73bc3103f1SAmir Vadai 	};
74f4d997fdSHadar Hen Zion 	struct flow_dissector_key_ports enc_tp;
75a577d8f7SBenjamin LaHaise 	struct flow_dissector_key_mpls mpls;
76fdfc7dd6SJiri Pirko 	struct flow_dissector_key_tcp tcp;
774d80cc0aSOr Gerlitz 	struct flow_dissector_key_ip ip;
780e2c17b6SOr Gerlitz 	struct flow_dissector_key_ip enc_ip;
790a6e7778SPieter Jansen van Vuuren 	struct flow_dissector_key_enc_opts enc_opts;
8083d85bb0SMaksym Glubokiy 	struct flow_dissector_key_ports_range tp_range;
81e0ace68aSPaul Blakey 	struct flow_dissector_key_ct ct;
825923b8f7SAriel Levkovich 	struct flow_dissector_key_hash hash;
83b4000312SBoris Sukholitko 	struct flow_dissector_key_num_of_vlans num_of_vlans;
845008750eSWojciech Drewek 	struct flow_dissector_key_pppoe pppoe;
858b189ea0SWojciech Drewek 	struct flow_dissector_key_l2tpv3 l2tpv3;
864c13eda7SRatheesh Kannoth 	struct flow_dissector_key_ipsec ipsec;
877cfffd5fSZahari Doychev 	struct flow_dissector_key_cfm cfm;
8877b9900eSJiri Pirko } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
8977b9900eSJiri Pirko 
9077b9900eSJiri Pirko struct fl_flow_mask_range {
9177b9900eSJiri Pirko 	unsigned short int start;
9277b9900eSJiri Pirko 	unsigned short int end;
9377b9900eSJiri Pirko };
9477b9900eSJiri Pirko 
9577b9900eSJiri Pirko struct fl_flow_mask {
9677b9900eSJiri Pirko 	struct fl_flow_key key;
9777b9900eSJiri Pirko 	struct fl_flow_mask_range range;
985c72299fSAmritha Nambiar 	u32 flags;
9905cd271fSPaul Blakey 	struct rhash_head ht_node;
10005cd271fSPaul Blakey 	struct rhashtable ht;
10105cd271fSPaul Blakey 	struct rhashtable_params filter_ht_params;
10205cd271fSPaul Blakey 	struct flow_dissector dissector;
10305cd271fSPaul Blakey 	struct list_head filters;
10444a5cd43SPaolo Abeni 	struct rcu_work rwork;
10505cd271fSPaul Blakey 	struct list_head list;
106f48ef4d5SVlad Buslov 	refcount_t refcnt;
10777b9900eSJiri Pirko };
10877b9900eSJiri Pirko 
109b95ec7ebSJiri Pirko struct fl_flow_tmplt {
110b95ec7ebSJiri Pirko 	struct fl_flow_key dummy_key;
111b95ec7ebSJiri Pirko 	struct fl_flow_key mask;
112b95ec7ebSJiri Pirko 	struct flow_dissector dissector;
113b95ec7ebSJiri Pirko 	struct tcf_chain *chain;
114b95ec7ebSJiri Pirko };
115b95ec7ebSJiri Pirko 
11677b9900eSJiri Pirko struct cls_fl_head {
11777b9900eSJiri Pirko 	struct rhashtable ht;
118259e60f9SVlad Buslov 	spinlock_t masks_lock; /* Protect masks list */
11905cd271fSPaul Blakey 	struct list_head masks;
120c049d56eSVlad Buslov 	struct list_head hw_filters;
121aaa908ffSCong Wang 	struct rcu_work rwork;
122c15ab236SChris Mi 	struct idr handle_idr;
123d9363774SDaniel Borkmann };
12477b9900eSJiri Pirko 
12577b9900eSJiri Pirko struct cls_fl_filter {
12605cd271fSPaul Blakey 	struct fl_flow_mask *mask;
12777b9900eSJiri Pirko 	struct rhash_head ht_node;
12877b9900eSJiri Pirko 	struct fl_flow_key mkey;
12977b9900eSJiri Pirko 	struct tcf_exts exts;
13077b9900eSJiri Pirko 	struct tcf_result res;
13177b9900eSJiri Pirko 	struct fl_flow_key key;
13277b9900eSJiri Pirko 	struct list_head list;
133c049d56eSVlad Buslov 	struct list_head hw_list;
13477b9900eSJiri Pirko 	u32 handle;
135e69985c6SAmir Vadai 	u32 flags;
13686c55361SVlad Buslov 	u32 in_hw_count;
1371a432018SIdo Schimmel 	u8 needs_tc_skb_ext:1;
138aaa908ffSCong Wang 	struct rcu_work rwork;
1397091d8c7SHadar Hen Zion 	struct net_device *hw_dev;
14006177558SVlad Buslov 	/* Flower classifier is unlocked, which means that its reference counter
14106177558SVlad Buslov 	 * can be changed concurrently without any kind of external
14206177558SVlad Buslov 	 * synchronization. Use atomic reference counter to be concurrency-safe.
14306177558SVlad Buslov 	 */
14406177558SVlad Buslov 	refcount_t refcnt;
145b2552b8cSVlad Buslov 	bool deleted;
14677b9900eSJiri Pirko };
14777b9900eSJiri Pirko 
14805cd271fSPaul Blakey static const struct rhashtable_params mask_ht_params = {
14905cd271fSPaul Blakey 	.key_offset = offsetof(struct fl_flow_mask, key),
15005cd271fSPaul Blakey 	.key_len = sizeof(struct fl_flow_key),
15105cd271fSPaul Blakey 	.head_offset = offsetof(struct fl_flow_mask, ht_node),
15205cd271fSPaul Blakey 	.automatic_shrinking = true,
15305cd271fSPaul Blakey };
15405cd271fSPaul Blakey 
fl_mask_range(const struct fl_flow_mask * mask)15577b9900eSJiri Pirko static unsigned short int fl_mask_range(const struct fl_flow_mask *mask)
15677b9900eSJiri Pirko {
15777b9900eSJiri Pirko 	return mask->range.end - mask->range.start;
15877b9900eSJiri Pirko }
15977b9900eSJiri Pirko 
fl_mask_update_range(struct fl_flow_mask * mask)16077b9900eSJiri Pirko static void fl_mask_update_range(struct fl_flow_mask *mask)
16177b9900eSJiri Pirko {
16277b9900eSJiri Pirko 	const u8 *bytes = (const u8 *) &mask->key;
16377b9900eSJiri Pirko 	size_t size = sizeof(mask->key);
16405cd271fSPaul Blakey 	size_t i, first = 0, last;
16577b9900eSJiri Pirko 
16605cd271fSPaul Blakey 	for (i = 0; i < size; i++) {
16777b9900eSJiri Pirko 		if (bytes[i]) {
16877b9900eSJiri Pirko 			first = i;
16905cd271fSPaul Blakey 			break;
17005cd271fSPaul Blakey 		}
17105cd271fSPaul Blakey 	}
17205cd271fSPaul Blakey 	last = first;
17305cd271fSPaul Blakey 	for (i = size - 1; i != first; i--) {
17405cd271fSPaul Blakey 		if (bytes[i]) {
17577b9900eSJiri Pirko 			last = i;
17605cd271fSPaul Blakey 			break;
17777b9900eSJiri Pirko 		}
17877b9900eSJiri Pirko 	}
17977b9900eSJiri Pirko 	mask->range.start = rounddown(first, sizeof(long));
18077b9900eSJiri Pirko 	mask->range.end = roundup(last + 1, sizeof(long));
18177b9900eSJiri Pirko }
18277b9900eSJiri Pirko 
fl_key_get_start(struct fl_flow_key * key,const struct fl_flow_mask * mask)18377b9900eSJiri Pirko static void *fl_key_get_start(struct fl_flow_key *key,
18477b9900eSJiri Pirko 			      const struct fl_flow_mask *mask)
18577b9900eSJiri Pirko {
18677b9900eSJiri Pirko 	return (u8 *) key + mask->range.start;
18777b9900eSJiri Pirko }
18877b9900eSJiri Pirko 
fl_set_masked_key(struct fl_flow_key * mkey,struct fl_flow_key * key,struct fl_flow_mask * mask)18977b9900eSJiri Pirko static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key,
19077b9900eSJiri Pirko 			      struct fl_flow_mask *mask)
19177b9900eSJiri Pirko {
19277b9900eSJiri Pirko 	const long *lkey = fl_key_get_start(key, mask);
19377b9900eSJiri Pirko 	const long *lmask = fl_key_get_start(&mask->key, mask);
19477b9900eSJiri Pirko 	long *lmkey = fl_key_get_start(mkey, mask);
19577b9900eSJiri Pirko 	int i;
19677b9900eSJiri Pirko 
19777b9900eSJiri Pirko 	for (i = 0; i < fl_mask_range(mask); i += sizeof(long))
19877b9900eSJiri Pirko 		*lmkey++ = *lkey++ & *lmask++;
19977b9900eSJiri Pirko }
20077b9900eSJiri Pirko 
fl_mask_fits_tmplt(struct fl_flow_tmplt * tmplt,struct fl_flow_mask * mask)201b95ec7ebSJiri Pirko static bool fl_mask_fits_tmplt(struct fl_flow_tmplt *tmplt,
202b95ec7ebSJiri Pirko 			       struct fl_flow_mask *mask)
203b95ec7ebSJiri Pirko {
204b95ec7ebSJiri Pirko 	const long *lmask = fl_key_get_start(&mask->key, mask);
205b95ec7ebSJiri Pirko 	const long *ltmplt;
206b95ec7ebSJiri Pirko 	int i;
207b95ec7ebSJiri Pirko 
208b95ec7ebSJiri Pirko 	if (!tmplt)
209b95ec7ebSJiri Pirko 		return true;
210b95ec7ebSJiri Pirko 	ltmplt = fl_key_get_start(&tmplt->mask, mask);
211b95ec7ebSJiri Pirko 	for (i = 0; i < fl_mask_range(mask); i += sizeof(long)) {
212b95ec7ebSJiri Pirko 		if (~*ltmplt++ & *lmask++)
213b95ec7ebSJiri Pirko 			return false;
214b95ec7ebSJiri Pirko 	}
215b95ec7ebSJiri Pirko 	return true;
216b95ec7ebSJiri Pirko }
217b95ec7ebSJiri Pirko 
fl_clear_masked_range(struct fl_flow_key * key,struct fl_flow_mask * mask)21877b9900eSJiri Pirko static void fl_clear_masked_range(struct fl_flow_key *key,
21977b9900eSJiri Pirko 				  struct fl_flow_mask *mask)
22077b9900eSJiri Pirko {
22177b9900eSJiri Pirko 	memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask));
22277b9900eSJiri Pirko }
22377b9900eSJiri Pirko 
fl_range_port_dst_cmp(struct cls_fl_filter * filter,struct fl_flow_key * key,struct fl_flow_key * mkey)2245c72299fSAmritha Nambiar static bool fl_range_port_dst_cmp(struct cls_fl_filter *filter,
2255c72299fSAmritha Nambiar 				  struct fl_flow_key *key,
2265c72299fSAmritha Nambiar 				  struct fl_flow_key *mkey)
2275c72299fSAmritha Nambiar {
2286215afcbSVladimir Oltean 	u16 min_mask, max_mask, min_val, max_val;
2295c72299fSAmritha Nambiar 
2306215afcbSVladimir Oltean 	min_mask = ntohs(filter->mask->key.tp_range.tp_min.dst);
2316215afcbSVladimir Oltean 	max_mask = ntohs(filter->mask->key.tp_range.tp_max.dst);
2326215afcbSVladimir Oltean 	min_val = ntohs(filter->key.tp_range.tp_min.dst);
2336215afcbSVladimir Oltean 	max_val = ntohs(filter->key.tp_range.tp_max.dst);
2345c72299fSAmritha Nambiar 
2355c72299fSAmritha Nambiar 	if (min_mask && max_mask) {
2366215afcbSVladimir Oltean 		if (ntohs(key->tp_range.tp.dst) < min_val ||
2376215afcbSVladimir Oltean 		    ntohs(key->tp_range.tp.dst) > max_val)
2385c72299fSAmritha Nambiar 			return false;
2395c72299fSAmritha Nambiar 
2405c72299fSAmritha Nambiar 		/* skb does not have min and max values */
2418ffb055bSYoshiki Komachi 		mkey->tp_range.tp_min.dst = filter->mkey.tp_range.tp_min.dst;
2428ffb055bSYoshiki Komachi 		mkey->tp_range.tp_max.dst = filter->mkey.tp_range.tp_max.dst;
2435c72299fSAmritha Nambiar 	}
2445c72299fSAmritha Nambiar 	return true;
2455c72299fSAmritha Nambiar }
2465c72299fSAmritha Nambiar 
fl_range_port_src_cmp(struct cls_fl_filter * filter,struct fl_flow_key * key,struct fl_flow_key * mkey)2475c72299fSAmritha Nambiar static bool fl_range_port_src_cmp(struct cls_fl_filter *filter,
2485c72299fSAmritha Nambiar 				  struct fl_flow_key *key,
2495c72299fSAmritha Nambiar 				  struct fl_flow_key *mkey)
2505c72299fSAmritha Nambiar {
2516215afcbSVladimir Oltean 	u16 min_mask, max_mask, min_val, max_val;
2525c72299fSAmritha Nambiar 
2536215afcbSVladimir Oltean 	min_mask = ntohs(filter->mask->key.tp_range.tp_min.src);
2546215afcbSVladimir Oltean 	max_mask = ntohs(filter->mask->key.tp_range.tp_max.src);
2556215afcbSVladimir Oltean 	min_val = ntohs(filter->key.tp_range.tp_min.src);
2566215afcbSVladimir Oltean 	max_val = ntohs(filter->key.tp_range.tp_max.src);
2575c72299fSAmritha Nambiar 
2585c72299fSAmritha Nambiar 	if (min_mask && max_mask) {
2596215afcbSVladimir Oltean 		if (ntohs(key->tp_range.tp.src) < min_val ||
2606215afcbSVladimir Oltean 		    ntohs(key->tp_range.tp.src) > max_val)
2615c72299fSAmritha Nambiar 			return false;
2625c72299fSAmritha Nambiar 
2635c72299fSAmritha Nambiar 		/* skb does not have min and max values */
2648ffb055bSYoshiki Komachi 		mkey->tp_range.tp_min.src = filter->mkey.tp_range.tp_min.src;
2658ffb055bSYoshiki Komachi 		mkey->tp_range.tp_max.src = filter->mkey.tp_range.tp_max.src;
2665c72299fSAmritha Nambiar 	}
2675c72299fSAmritha Nambiar 	return true;
2685c72299fSAmritha Nambiar }
2695c72299fSAmritha Nambiar 
__fl_lookup(struct fl_flow_mask * mask,struct fl_flow_key * mkey)2705c72299fSAmritha Nambiar static struct cls_fl_filter *__fl_lookup(struct fl_flow_mask *mask,
271a3308d8fSPaul Blakey 					 struct fl_flow_key *mkey)
272a3308d8fSPaul Blakey {
27305cd271fSPaul Blakey 	return rhashtable_lookup_fast(&mask->ht, fl_key_get_start(mkey, mask),
27405cd271fSPaul Blakey 				      mask->filter_ht_params);
275a3308d8fSPaul Blakey }
276a3308d8fSPaul Blakey 
fl_lookup_range(struct fl_flow_mask * mask,struct fl_flow_key * mkey,struct fl_flow_key * key)2775c72299fSAmritha Nambiar static struct cls_fl_filter *fl_lookup_range(struct fl_flow_mask *mask,
2785c72299fSAmritha Nambiar 					     struct fl_flow_key *mkey,
2795c72299fSAmritha Nambiar 					     struct fl_flow_key *key)
2805c72299fSAmritha Nambiar {
2815c72299fSAmritha Nambiar 	struct cls_fl_filter *filter, *f;
2825c72299fSAmritha Nambiar 
2835c72299fSAmritha Nambiar 	list_for_each_entry_rcu(filter, &mask->filters, list) {
2845c72299fSAmritha Nambiar 		if (!fl_range_port_dst_cmp(filter, key, mkey))
2855c72299fSAmritha Nambiar 			continue;
2865c72299fSAmritha Nambiar 
2875c72299fSAmritha Nambiar 		if (!fl_range_port_src_cmp(filter, key, mkey))
2885c72299fSAmritha Nambiar 			continue;
2895c72299fSAmritha Nambiar 
2905c72299fSAmritha Nambiar 		f = __fl_lookup(mask, mkey);
2915c72299fSAmritha Nambiar 		if (f)
2925c72299fSAmritha Nambiar 			return f;
2935c72299fSAmritha Nambiar 	}
2945c72299fSAmritha Nambiar 	return NULL;
2955c72299fSAmritha Nambiar }
2965c72299fSAmritha Nambiar 
2970af413bdSArnd Bergmann static noinline_for_stack
fl_mask_lookup(struct fl_flow_mask * mask,struct fl_flow_key * key)2980af413bdSArnd Bergmann struct cls_fl_filter *fl_mask_lookup(struct fl_flow_mask *mask, struct fl_flow_key *key)
2995c72299fSAmritha Nambiar {
3000af413bdSArnd Bergmann 	struct fl_flow_key mkey;
3015c72299fSAmritha Nambiar 
3020af413bdSArnd Bergmann 	fl_set_masked_key(&mkey, key, mask);
3030af413bdSArnd Bergmann 	if ((mask->flags & TCA_FLOWER_MASK_FLAGS_RANGE))
3040af413bdSArnd Bergmann 		return fl_lookup_range(mask, &mkey, key);
3050af413bdSArnd Bergmann 
3060af413bdSArnd Bergmann 	return __fl_lookup(mask, &mkey);
3075c72299fSAmritha Nambiar }
3085c72299fSAmritha Nambiar 
309e0ace68aSPaul Blakey static u16 fl_ct_info_to_flower_map[] = {
310e0ace68aSPaul Blakey 	[IP_CT_ESTABLISHED] =		TCA_FLOWER_KEY_CT_FLAGS_TRACKED |
311e0ace68aSPaul Blakey 					TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED,
312e0ace68aSPaul Blakey 	[IP_CT_RELATED] =		TCA_FLOWER_KEY_CT_FLAGS_TRACKED |
313e0ace68aSPaul Blakey 					TCA_FLOWER_KEY_CT_FLAGS_RELATED,
314e0ace68aSPaul Blakey 	[IP_CT_ESTABLISHED_REPLY] =	TCA_FLOWER_KEY_CT_FLAGS_TRACKED |
3158c85d18cSPaul Blakey 					TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED |
3168c85d18cSPaul Blakey 					TCA_FLOWER_KEY_CT_FLAGS_REPLY,
317e0ace68aSPaul Blakey 	[IP_CT_RELATED_REPLY] =		TCA_FLOWER_KEY_CT_FLAGS_TRACKED |
3188c85d18cSPaul Blakey 					TCA_FLOWER_KEY_CT_FLAGS_RELATED |
3198c85d18cSPaul Blakey 					TCA_FLOWER_KEY_CT_FLAGS_REPLY,
320e0ace68aSPaul Blakey 	[IP_CT_NEW] =			TCA_FLOWER_KEY_CT_FLAGS_TRACKED |
321e0ace68aSPaul Blakey 					TCA_FLOWER_KEY_CT_FLAGS_NEW,
322e0ace68aSPaul Blakey };
323e0ace68aSPaul Blakey 
fl_classify(struct sk_buff * skb,const struct tcf_proto * tp,struct tcf_result * res)3249f3101dcSPedro Tammela TC_INDIRECT_SCOPE int fl_classify(struct sk_buff *skb,
3259f3101dcSPedro Tammela 				  const struct tcf_proto *tp,
32677b9900eSJiri Pirko 				  struct tcf_result *res)
32777b9900eSJiri Pirko {
32877b9900eSJiri Pirko 	struct cls_fl_head *head = rcu_dereference_bh(tp->root);
329ec624fe7SPaul Blakey 	bool post_ct = tc_skb_cb(skb)->post_ct;
33038495958SPaul Blakey 	u16 zone = tc_skb_cb(skb)->zone;
331e0ace68aSPaul Blakey 	struct fl_flow_key skb_key;
332e0ace68aSPaul Blakey 	struct fl_flow_mask *mask;
333e0ace68aSPaul Blakey 	struct cls_fl_filter *f;
33477b9900eSJiri Pirko 
33505cd271fSPaul Blakey 	list_for_each_entry_rcu(mask, &head->masks, list) {
3368a9093c7SJason Baron 		flow_dissector_init_keys(&skb_key.control, &skb_key.basic);
33705cd271fSPaul Blakey 		fl_clear_masked_range(&skb_key, mask);
338bc3103f1SAmir Vadai 
3398212ed77SJiri Pirko 		skb_flow_dissect_meta(skb, &mask->dissector, &skb_key);
34005cd271fSPaul Blakey 		/* skb_flow_dissect() does not set n_proto in case an unknown
34105cd271fSPaul Blakey 		 * protocol, so do it rather here.
34277b9900eSJiri Pirko 		 */
343d7bf2ebeSToke Høiland-Jørgensen 		skb_key.basic.n_proto = skb_protocol(skb, false);
34405cd271fSPaul Blakey 		skb_flow_dissect_tunnel_info(skb, &mask->dissector, &skb_key);
345e0ace68aSPaul Blakey 		skb_flow_dissect_ct(skb, &mask->dissector, &skb_key,
346e0ace68aSPaul Blakey 				    fl_ct_info_to_flower_map,
3477baf2429Swenxu 				    ARRAY_SIZE(fl_ct_info_to_flower_map),
34838495958SPaul Blakey 				    post_ct, zone);
3495923b8f7SAriel Levkovich 		skb_flow_dissect_hash(skb, &mask->dissector, &skb_key);
3506de6e46dSYoshiki Komachi 		skb_flow_dissect(skb, &mask->dissector, &skb_key,
3516de6e46dSYoshiki Komachi 				 FLOW_DISSECTOR_F_STOP_BEFORE_ENCAP);
35277b9900eSJiri Pirko 
3530af413bdSArnd Bergmann 		f = fl_mask_lookup(mask, &skb_key);
354e8eb36cdSAmir Vadai 		if (f && !tc_skip_sw(f->flags)) {
35577b9900eSJiri Pirko 			*res = f->res;
35677b9900eSJiri Pirko 			return tcf_exts_exec(skb, &f->exts, res);
35777b9900eSJiri Pirko 		}
35805cd271fSPaul Blakey 	}
35977b9900eSJiri Pirko 	return -1;
36077b9900eSJiri Pirko }
36177b9900eSJiri Pirko 
fl_init(struct tcf_proto * tp)36277b9900eSJiri Pirko static int fl_init(struct tcf_proto *tp)
36377b9900eSJiri Pirko {
36477b9900eSJiri Pirko 	struct cls_fl_head *head;
36577b9900eSJiri Pirko 
36677b9900eSJiri Pirko 	head = kzalloc(sizeof(*head), GFP_KERNEL);
36777b9900eSJiri Pirko 	if (!head)
36877b9900eSJiri Pirko 		return -ENOBUFS;
36977b9900eSJiri Pirko 
370259e60f9SVlad Buslov 	spin_lock_init(&head->masks_lock);
37105cd271fSPaul Blakey 	INIT_LIST_HEAD_RCU(&head->masks);
372c049d56eSVlad Buslov 	INIT_LIST_HEAD(&head->hw_filters);
37377b9900eSJiri Pirko 	rcu_assign_pointer(tp->root, head);
374c15ab236SChris Mi 	idr_init(&head->handle_idr);
37577b9900eSJiri Pirko 
37605cd271fSPaul Blakey 	return rhashtable_init(&head->ht, &mask_ht_params);
37705cd271fSPaul Blakey }
37805cd271fSPaul Blakey 
fl_mask_free(struct fl_flow_mask * mask,bool mask_init_done)37999815f50SVlad Buslov static void fl_mask_free(struct fl_flow_mask *mask, bool mask_init_done)
38044a5cd43SPaolo Abeni {
38199815f50SVlad Buslov 	/* temporary masks don't have their filters list and ht initialized */
38299815f50SVlad Buslov 	if (mask_init_done) {
383f48ef4d5SVlad Buslov 		WARN_ON(!list_empty(&mask->filters));
38444a5cd43SPaolo Abeni 		rhashtable_destroy(&mask->ht);
38599815f50SVlad Buslov 	}
38644a5cd43SPaolo Abeni 	kfree(mask);
38744a5cd43SPaolo Abeni }
38844a5cd43SPaolo Abeni 
fl_mask_free_work(struct work_struct * work)38944a5cd43SPaolo Abeni static void fl_mask_free_work(struct work_struct *work)
39044a5cd43SPaolo Abeni {
39144a5cd43SPaolo Abeni 	struct fl_flow_mask *mask = container_of(to_rcu_work(work),
39244a5cd43SPaolo Abeni 						 struct fl_flow_mask, rwork);
39344a5cd43SPaolo Abeni 
39499815f50SVlad Buslov 	fl_mask_free(mask, true);
39599815f50SVlad Buslov }
39699815f50SVlad Buslov 
fl_uninit_mask_free_work(struct work_struct * work)39799815f50SVlad Buslov static void fl_uninit_mask_free_work(struct work_struct *work)
39899815f50SVlad Buslov {
39999815f50SVlad Buslov 	struct fl_flow_mask *mask = container_of(to_rcu_work(work),
40099815f50SVlad Buslov 						 struct fl_flow_mask, rwork);
40199815f50SVlad Buslov 
40299815f50SVlad Buslov 	fl_mask_free(mask, false);
40344a5cd43SPaolo Abeni }
40444a5cd43SPaolo Abeni 
fl_mask_put(struct cls_fl_head * head,struct fl_flow_mask * mask)4059994677cSVlad Buslov static bool fl_mask_put(struct cls_fl_head *head, struct fl_flow_mask *mask)
40605cd271fSPaul Blakey {
407f48ef4d5SVlad Buslov 	if (!refcount_dec_and_test(&mask->refcnt))
40805cd271fSPaul Blakey 		return false;
40905cd271fSPaul Blakey 
41005cd271fSPaul Blakey 	rhashtable_remove_fast(&head->ht, &mask->ht_node, mask_ht_params);
411259e60f9SVlad Buslov 
412259e60f9SVlad Buslov 	spin_lock(&head->masks_lock);
41305cd271fSPaul Blakey 	list_del_rcu(&mask->list);
414259e60f9SVlad Buslov 	spin_unlock(&head->masks_lock);
415259e60f9SVlad Buslov 
41644a5cd43SPaolo Abeni 	tcf_queue_work(&mask->rwork, fl_mask_free_work);
41705cd271fSPaul Blakey 
41805cd271fSPaul Blakey 	return true;
41977b9900eSJiri Pirko }
42077b9900eSJiri Pirko 
fl_head_dereference(struct tcf_proto * tp)421c049d56eSVlad Buslov static struct cls_fl_head *fl_head_dereference(struct tcf_proto *tp)
422c049d56eSVlad Buslov {
423c049d56eSVlad Buslov 	/* Flower classifier only changes root pointer during init and destroy.
424c049d56eSVlad Buslov 	 * Users must obtain reference to tcf_proto instance before calling its
425c049d56eSVlad Buslov 	 * API, so tp->root pointer is protected from concurrent call to
426c049d56eSVlad Buslov 	 * fl_destroy() by reference counting.
427c049d56eSVlad Buslov 	 */
428c049d56eSVlad Buslov 	return rcu_dereference_raw(tp->root);
429c049d56eSVlad Buslov }
430c049d56eSVlad Buslov 
__fl_destroy_filter(struct cls_fl_filter * f)4310dadc117SCong Wang static void __fl_destroy_filter(struct cls_fl_filter *f)
4320dadc117SCong Wang {
4331a432018SIdo Schimmel 	if (f->needs_tc_skb_ext)
4341a432018SIdo Schimmel 		tc_skb_ext_tc_disable();
4350dadc117SCong Wang 	tcf_exts_destroy(&f->exts);
4360dadc117SCong Wang 	tcf_exts_put_net(&f->exts);
4370dadc117SCong Wang 	kfree(f);
4380dadc117SCong Wang }
4390dadc117SCong Wang 
fl_destroy_filter_work(struct work_struct * work)4400552c8afSCong Wang static void fl_destroy_filter_work(struct work_struct *work)
4410552c8afSCong Wang {
442aaa908ffSCong Wang 	struct cls_fl_filter *f = container_of(to_rcu_work(work),
443aaa908ffSCong Wang 					struct cls_fl_filter, rwork);
4440552c8afSCong Wang 
4450dadc117SCong Wang 	__fl_destroy_filter(f);
4460552c8afSCong Wang }
4470552c8afSCong Wang 
fl_hw_destroy_filter(struct tcf_proto * tp,struct cls_fl_filter * f,bool rtnl_held,struct netlink_ext_ack * extack)4481b0f8037SJakub Kicinski static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f,
449c24e43d8SVlad Buslov 				 bool rtnl_held, struct netlink_ext_ack *extack)
4505b33f488SAmir Vadai {
451208c0f4bSJiri Pirko 	struct tcf_block *block = tp->chain->block;
452f9e30088SPablo Neira Ayuso 	struct flow_cls_offload cls_flower = {};
4535b33f488SAmir Vadai 
454d6787147SPieter Jansen van Vuuren 	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack);
455f9e30088SPablo Neira Ayuso 	cls_flower.command = FLOW_CLS_DESTROY;
456de4784caSJiri Pirko 	cls_flower.cookie = (unsigned long) f;
4575b33f488SAmir Vadai 
45840119211SVlad Buslov 	tc_setup_cb_destroy(block, tp, TC_SETUP_CLSFLOWER, &cls_flower, false,
459918190f5SVlad Buslov 			    &f->flags, &f->in_hw_count, rtnl_held);
460c24e43d8SVlad Buslov 
4615b33f488SAmir Vadai }
4625b33f488SAmir Vadai 
fl_hw_replace_filter(struct tcf_proto * tp,struct cls_fl_filter * f,bool rtnl_held,struct netlink_ext_ack * extack)463e8eb36cdSAmir Vadai static int fl_hw_replace_filter(struct tcf_proto *tp,
464c24e43d8SVlad Buslov 				struct cls_fl_filter *f, bool rtnl_held,
46541002038SQuentin Monnet 				struct netlink_ext_ack *extack)
4665b33f488SAmir Vadai {
467208c0f4bSJiri Pirko 	struct tcf_block *block = tp->chain->block;
468f9e30088SPablo Neira Ayuso 	struct flow_cls_offload cls_flower = {};
469717503b9SJiri Pirko 	bool skip_sw = tc_skip_sw(f->flags);
470c24e43d8SVlad Buslov 	int err = 0;
471c24e43d8SVlad Buslov 
472e3ab786bSPablo Neira Ayuso 	cls_flower.rule = flow_rule_alloc(tcf_exts_num_actions(&f->exts));
473918190f5SVlad Buslov 	if (!cls_flower.rule)
474918190f5SVlad Buslov 		return -ENOMEM;
4758f256622SPablo Neira Ayuso 
476d6787147SPieter Jansen van Vuuren 	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack);
477f9e30088SPablo Neira Ayuso 	cls_flower.command = FLOW_CLS_REPLACE;
478de4784caSJiri Pirko 	cls_flower.cookie = (unsigned long) f;
4798f256622SPablo Neira Ayuso 	cls_flower.rule->match.dissector = &f->mask->dissector;
4808f256622SPablo Neira Ayuso 	cls_flower.rule->match.mask = &f->mask->key;
4818f256622SPablo Neira Ayuso 	cls_flower.rule->match.key = &f->mkey;
482384c181eSAmritha Nambiar 	cls_flower.classid = f->res.classid;
4835b33f488SAmir Vadai 
484c2ccf84eSIdo Schimmel 	err = tc_setup_offload_action(&cls_flower.rule->action, &f->exts,
485c2ccf84eSIdo Schimmel 				      cls_flower.common.extack);
4863a7b6861SPablo Neira Ayuso 	if (err) {
4873a7b6861SPablo Neira Ayuso 		kfree(cls_flower.rule);
48811c95317SIdo Schimmel 
48911c95317SIdo Schimmel 		return skip_sw ? err : 0;
4901f15bb4fSVlad Buslov 	}
4913a7b6861SPablo Neira Ayuso 
49240119211SVlad Buslov 	err = tc_setup_cb_add(block, tp, TC_SETUP_CLSFLOWER, &cls_flower,
493918190f5SVlad Buslov 			      skip_sw, &f->flags, &f->in_hw_count, rtnl_held);
4949c1c0e12SBaowen Zheng 	tc_cleanup_offload_action(&cls_flower.rule->action);
4958f256622SPablo Neira Ayuso 	kfree(cls_flower.rule);
4968f256622SPablo Neira Ayuso 
49740119211SVlad Buslov 	if (err) {
498918190f5SVlad Buslov 		fl_hw_destroy_filter(tp, f, rtnl_held, NULL);
499c24e43d8SVlad Buslov 		return err;
500c24e43d8SVlad Buslov 	}
501c24e43d8SVlad Buslov 
502918190f5SVlad Buslov 	if (skip_sw && !(f->flags & TCA_CLS_FLAGS_IN_HW))
503918190f5SVlad Buslov 		return -EINVAL;
504918190f5SVlad Buslov 
505918190f5SVlad Buslov 	return 0;
506918190f5SVlad Buslov }
507918190f5SVlad Buslov 
fl_hw_update_stats(struct tcf_proto * tp,struct cls_fl_filter * f,bool rtnl_held)508c24e43d8SVlad Buslov static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f,
509c24e43d8SVlad Buslov 			       bool rtnl_held)
51010cbc684SAmir Vadai {
511208c0f4bSJiri Pirko 	struct tcf_block *block = tp->chain->block;
512f9e30088SPablo Neira Ayuso 	struct flow_cls_offload cls_flower = {};
51310cbc684SAmir Vadai 
514d6787147SPieter Jansen van Vuuren 	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, NULL);
515f9e30088SPablo Neira Ayuso 	cls_flower.command = FLOW_CLS_STATS;
516de4784caSJiri Pirko 	cls_flower.cookie = (unsigned long) f;
517384c181eSAmritha Nambiar 	cls_flower.classid = f->res.classid;
51810cbc684SAmir Vadai 
519918190f5SVlad Buslov 	tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, false,
520918190f5SVlad Buslov 			 rtnl_held);
5213b1903efSPablo Neira Ayuso 
5225246c896SOz Shlomo 	tcf_exts_hw_stats_update(&f->exts, &cls_flower.stats, cls_flower.use_act_stats);
52310cbc684SAmir Vadai }
52410cbc684SAmir Vadai 
__fl_put(struct cls_fl_filter * f)52506177558SVlad Buslov static void __fl_put(struct cls_fl_filter *f)
52606177558SVlad Buslov {
52706177558SVlad Buslov 	if (!refcount_dec_and_test(&f->refcnt))
52806177558SVlad Buslov 		return;
52906177558SVlad Buslov 
53006177558SVlad Buslov 	if (tcf_exts_get_net(&f->exts))
53106177558SVlad Buslov 		tcf_queue_work(&f->rwork, fl_destroy_filter_work);
53206177558SVlad Buslov 	else
53306177558SVlad Buslov 		__fl_destroy_filter(f);
53406177558SVlad Buslov }
53506177558SVlad Buslov 
__fl_get(struct cls_fl_head * head,u32 handle)53606177558SVlad Buslov static struct cls_fl_filter *__fl_get(struct cls_fl_head *head, u32 handle)
53706177558SVlad Buslov {
53806177558SVlad Buslov 	struct cls_fl_filter *f;
53906177558SVlad Buslov 
54006177558SVlad Buslov 	rcu_read_lock();
54106177558SVlad Buslov 	f = idr_find(&head->handle_idr, handle);
54206177558SVlad Buslov 	if (f && !refcount_inc_not_zero(&f->refcnt))
54306177558SVlad Buslov 		f = NULL;
54406177558SVlad Buslov 	rcu_read_unlock();
54506177558SVlad Buslov 
54606177558SVlad Buslov 	return f;
54706177558SVlad Buslov }
54806177558SVlad Buslov 
fl_get_exts(const struct tcf_proto * tp,u32 handle)549606c7c43SPaul Blakey static struct tcf_exts *fl_get_exts(const struct tcf_proto *tp, u32 handle)
550606c7c43SPaul Blakey {
551606c7c43SPaul Blakey 	struct cls_fl_head *head = rcu_dereference_bh(tp->root);
552606c7c43SPaul Blakey 	struct cls_fl_filter *f;
553606c7c43SPaul Blakey 
554606c7c43SPaul Blakey 	f = idr_find(&head->handle_idr, handle);
555606c7c43SPaul Blakey 	return f ? &f->exts : NULL;
556606c7c43SPaul Blakey }
557606c7c43SPaul Blakey 
__fl_delete(struct tcf_proto * tp,struct cls_fl_filter * f,bool * last,bool rtnl_held,struct netlink_ext_ack * extack)558b2552b8cSVlad Buslov static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,
559c24e43d8SVlad Buslov 		       bool *last, bool rtnl_held,
560c24e43d8SVlad Buslov 		       struct netlink_ext_ack *extack)
56113fa876eSRoi Dayan {
562e474619aSVlad Buslov 	struct cls_fl_head *head = fl_head_dereference(tp);
563c15ab236SChris Mi 
564b2552b8cSVlad Buslov 	*last = false;
565b2552b8cSVlad Buslov 
5663d81e711SVlad Buslov 	spin_lock(&tp->lock);
5673d81e711SVlad Buslov 	if (f->deleted) {
5683d81e711SVlad Buslov 		spin_unlock(&tp->lock);
569b2552b8cSVlad Buslov 		return -ENOENT;
5703d81e711SVlad Buslov 	}
571b2552b8cSVlad Buslov 
572b2552b8cSVlad Buslov 	f->deleted = true;
573b2552b8cSVlad Buslov 	rhashtable_remove_fast(&f->mask->ht, &f->ht_node,
574b2552b8cSVlad Buslov 			       f->mask->filter_ht_params);
5759c160941SMatthew Wilcox 	idr_remove(&head->handle_idr, f->handle);
57613fa876eSRoi Dayan 	list_del_rcu(&f->list);
5773d81e711SVlad Buslov 	spin_unlock(&tp->lock);
5783d81e711SVlad Buslov 
5799994677cSVlad Buslov 	*last = fl_mask_put(head, f->mask);
58079685219SHadar Hen Zion 	if (!tc_skip_hw(f->flags))
581c24e43d8SVlad Buslov 		fl_hw_destroy_filter(tp, f, rtnl_held, extack);
58213fa876eSRoi Dayan 	tcf_unbind_filter(tp, &f->res);
58306177558SVlad Buslov 	__fl_put(f);
58405cd271fSPaul Blakey 
585b2552b8cSVlad Buslov 	return 0;
58613fa876eSRoi Dayan }
58713fa876eSRoi Dayan 
fl_destroy_sleepable(struct work_struct * work)588d9363774SDaniel Borkmann static void fl_destroy_sleepable(struct work_struct *work)
589d9363774SDaniel Borkmann {
590aaa908ffSCong Wang 	struct cls_fl_head *head = container_of(to_rcu_work(work),
591aaa908ffSCong Wang 						struct cls_fl_head,
592aaa908ffSCong Wang 						rwork);
593de9dc650SPaul Blakey 
594de9dc650SPaul Blakey 	rhashtable_destroy(&head->ht);
595d9363774SDaniel Borkmann 	kfree(head);
596d9363774SDaniel Borkmann 	module_put(THIS_MODULE);
597d9363774SDaniel Borkmann }
598d9363774SDaniel Borkmann 
fl_destroy(struct tcf_proto * tp,bool rtnl_held,struct netlink_ext_ack * extack)59912db03b6SVlad Buslov static void fl_destroy(struct tcf_proto *tp, bool rtnl_held,
60012db03b6SVlad Buslov 		       struct netlink_ext_ack *extack)
60177b9900eSJiri Pirko {
602e474619aSVlad Buslov 	struct cls_fl_head *head = fl_head_dereference(tp);
60305cd271fSPaul Blakey 	struct fl_flow_mask *mask, *next_mask;
60477b9900eSJiri Pirko 	struct cls_fl_filter *f, *next;
605b2552b8cSVlad Buslov 	bool last;
60677b9900eSJiri Pirko 
60705cd271fSPaul Blakey 	list_for_each_entry_safe(mask, next_mask, &head->masks, list) {
60805cd271fSPaul Blakey 		list_for_each_entry_safe(f, next, &mask->filters, list) {
609c24e43d8SVlad Buslov 			__fl_delete(tp, f, &last, rtnl_held, extack);
610b2552b8cSVlad Buslov 			if (last)
61105cd271fSPaul Blakey 				break;
61205cd271fSPaul Blakey 		}
61305cd271fSPaul Blakey 	}
614c15ab236SChris Mi 	idr_destroy(&head->handle_idr);
615d9363774SDaniel Borkmann 
616d9363774SDaniel Borkmann 	__module_get(THIS_MODULE);
617aaa908ffSCong Wang 	tcf_queue_work(&head->rwork, fl_destroy_sleepable);
61877b9900eSJiri Pirko }
61977b9900eSJiri Pirko 
fl_put(struct tcf_proto * tp,void * arg)62006177558SVlad Buslov static void fl_put(struct tcf_proto *tp, void *arg)
62106177558SVlad Buslov {
62206177558SVlad Buslov 	struct cls_fl_filter *f = arg;
62306177558SVlad Buslov 
62406177558SVlad Buslov 	__fl_put(f);
62506177558SVlad Buslov }
62606177558SVlad Buslov 
fl_get(struct tcf_proto * tp,u32 handle)6278113c095SWANG Cong static void *fl_get(struct tcf_proto *tp, u32 handle)
62877b9900eSJiri Pirko {
629e474619aSVlad Buslov 	struct cls_fl_head *head = fl_head_dereference(tp);
63077b9900eSJiri Pirko 
63106177558SVlad Buslov 	return __fl_get(head, handle);
63277b9900eSJiri Pirko }
63377b9900eSJiri Pirko 
63477b9900eSJiri Pirko static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
6351a432018SIdo Schimmel 	[TCA_FLOWER_UNSPEC]		= { .strict_start_type =
6361a432018SIdo Schimmel 						TCA_FLOWER_L2_MISS },
63777b9900eSJiri Pirko 	[TCA_FLOWER_CLASSID]		= { .type = NLA_U32 },
63877b9900eSJiri Pirko 	[TCA_FLOWER_INDEV]		= { .type = NLA_STRING,
63977b9900eSJiri Pirko 					    .len = IFNAMSIZ },
64077b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_DST]	= { .len = ETH_ALEN },
64177b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_DST_MASK]	= { .len = ETH_ALEN },
64277b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_SRC]	= { .len = ETH_ALEN },
64377b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_SRC_MASK]	= { .len = ETH_ALEN },
64477b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_TYPE]	= { .type = NLA_U16 },
64577b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IP_PROTO]	= { .type = NLA_U8 },
64677b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_SRC]	= { .type = NLA_U32 },
64777b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_SRC_MASK]	= { .type = NLA_U32 },
64877b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_DST]	= { .type = NLA_U32 },
64977b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_DST_MASK]	= { .type = NLA_U32 },
65077b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
65177b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_SRC_MASK]	= { .len = sizeof(struct in6_addr) },
65277b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
65377b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_DST_MASK]	= { .len = sizeof(struct in6_addr) },
65477b9900eSJiri Pirko 	[TCA_FLOWER_KEY_TCP_SRC]	= { .type = NLA_U16 },
65577b9900eSJiri Pirko 	[TCA_FLOWER_KEY_TCP_DST]	= { .type = NLA_U16 },
656b175c3a4SJamal Hadi Salim 	[TCA_FLOWER_KEY_UDP_SRC]	= { .type = NLA_U16 },
657b175c3a4SJamal Hadi Salim 	[TCA_FLOWER_KEY_UDP_DST]	= { .type = NLA_U16 },
6589399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_ID]	= { .type = NLA_U16 },
6599399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_PRIO]	= { .type = NLA_U8 },
6609399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_ETH_TYPE]	= { .type = NLA_U16 },
661bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_KEY_ID]	= { .type = NLA_U32 },
662bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_SRC]	= { .type = NLA_U32 },
663bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NLA_U32 },
664bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_DST]	= { .type = NLA_U32 },
665bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NLA_U32 },
666bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
667bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) },
668bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
669bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) },
670aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_TCP_SRC_MASK]	= { .type = NLA_U16 },
671aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_TCP_DST_MASK]	= { .type = NLA_U16 },
672aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_UDP_SRC_MASK]	= { .type = NLA_U16 },
673aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_UDP_DST_MASK]	= { .type = NLA_U16 },
6745976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_SRC_MASK]	= { .type = NLA_U16 },
6755976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_DST_MASK]	= { .type = NLA_U16 },
6765976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_SRC]	= { .type = NLA_U16 },
6775976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_DST]	= { .type = NLA_U16 },
678f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT]	= { .type = NLA_U16 },
679f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK]	= { .type = NLA_U16 },
680f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]	= { .type = NLA_U16 },
681f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK]	= { .type = NLA_U16 },
6820e83a787SAsbjørn Sloth Tønnesen 	[TCA_FLOWER_KEY_FLAGS]		= NLA_POLICY_MASK(NLA_BE32,
6830e83a787SAsbjørn Sloth Tønnesen 							  TCA_FLOWER_KEY_FLAGS_POLICY_MASK),
6840e83a787SAsbjørn Sloth Tønnesen 	[TCA_FLOWER_KEY_FLAGS_MASK]	= NLA_POLICY_MASK(NLA_BE32,
6850e83a787SAsbjørn Sloth Tønnesen 							  TCA_FLOWER_KEY_FLAGS_POLICY_MASK),
6867b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_TYPE]	= { .type = NLA_U8 },
6877b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_TYPE_MASK] = { .type = NLA_U8 },
6887b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_CODE]	= { .type = NLA_U8 },
6897b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_CODE_MASK] = { .type = NLA_U8 },
6907b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_TYPE]	= { .type = NLA_U8 },
6917b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_TYPE_MASK] = { .type = NLA_U8 },
6927b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_CODE]	= { .type = NLA_U8 },
6937b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_CODE_MASK] = { .type = NLA_U8 },
69499d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SIP]	= { .type = NLA_U32 },
69599d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SIP_MASK]	= { .type = NLA_U32 },
69699d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_TIP]	= { .type = NLA_U32 },
69799d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_TIP_MASK]	= { .type = NLA_U32 },
69899d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_OP]		= { .type = NLA_U8 },
69999d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_OP_MASK]	= { .type = NLA_U8 },
70099d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SHA]	= { .len = ETH_ALEN },
70199d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SHA_MASK]	= { .len = ETH_ALEN },
70299d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_THA]	= { .len = ETH_ALEN },
70399d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_THA_MASK]	= { .len = ETH_ALEN },
704a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_TTL]	= { .type = NLA_U8 },
705a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_BOS]	= { .type = NLA_U8 },
706a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_TC]	= { .type = NLA_U8 },
707a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_LABEL]	= { .type = NLA_U32 },
70861aec25aSGuillaume Nault 	[TCA_FLOWER_KEY_MPLS_OPTS]	= { .type = NLA_NESTED },
709fdfc7dd6SJiri Pirko 	[TCA_FLOWER_KEY_TCP_FLAGS]	= { .type = NLA_U16 },
710fdfc7dd6SJiri Pirko 	[TCA_FLOWER_KEY_TCP_FLAGS_MASK]	= { .type = NLA_U16 },
7114d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TOS]		= { .type = NLA_U8 },
7124d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TOS_MASK]	= { .type = NLA_U8 },
7134d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TTL]		= { .type = NLA_U8 },
7144d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TTL_MASK]	= { .type = NLA_U8 },
715d64efd09SJianbo Liu 	[TCA_FLOWER_KEY_CVLAN_ID]	= { .type = NLA_U16 },
716d64efd09SJianbo Liu 	[TCA_FLOWER_KEY_CVLAN_PRIO]	= { .type = NLA_U8 },
717d64efd09SJianbo Liu 	[TCA_FLOWER_KEY_CVLAN_ETH_TYPE]	= { .type = NLA_U16 },
7180e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TOS]	= { .type = NLA_U8 },
7190e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TOS_MASK] = { .type = NLA_U8 },
7200e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TTL]	 = { .type = NLA_U8 },
7210e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TTL_MASK] = { .type = NLA_U8 },
7220a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPTS]	= { .type = NLA_NESTED },
7230a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPTS_MASK]	= { .type = NLA_NESTED },
7241bcc51acSwenxu 	[TCA_FLOWER_KEY_CT_STATE]	=
7251bcc51acSwenxu 		NLA_POLICY_MASK(NLA_U16, TCA_FLOWER_KEY_CT_FLAGS_MASK),
7261bcc51acSwenxu 	[TCA_FLOWER_KEY_CT_STATE_MASK]	=
7271bcc51acSwenxu 		NLA_POLICY_MASK(NLA_U16, TCA_FLOWER_KEY_CT_FLAGS_MASK),
728e0ace68aSPaul Blakey 	[TCA_FLOWER_KEY_CT_ZONE]	= { .type = NLA_U16 },
729e0ace68aSPaul Blakey 	[TCA_FLOWER_KEY_CT_ZONE_MASK]	= { .type = NLA_U16 },
730e0ace68aSPaul Blakey 	[TCA_FLOWER_KEY_CT_MARK]	= { .type = NLA_U32 },
731e0ace68aSPaul Blakey 	[TCA_FLOWER_KEY_CT_MARK_MASK]	= { .type = NLA_U32 },
732e0ace68aSPaul Blakey 	[TCA_FLOWER_KEY_CT_LABELS]	= { .type = NLA_BINARY,
733e0ace68aSPaul Blakey 					    .len = 128 / BITS_PER_BYTE },
734e0ace68aSPaul Blakey 	[TCA_FLOWER_KEY_CT_LABELS_MASK]	= { .type = NLA_BINARY,
735e0ace68aSPaul Blakey 					    .len = 128 / BITS_PER_BYTE },
736e2debf08SDavide Caratti 	[TCA_FLOWER_FLAGS]		= { .type = NLA_U32 },
7375923b8f7SAriel Levkovich 	[TCA_FLOWER_KEY_HASH]		= { .type = NLA_U32 },
7385923b8f7SAriel Levkovich 	[TCA_FLOWER_KEY_HASH_MASK]	= { .type = NLA_U32 },
739b4000312SBoris Sukholitko 	[TCA_FLOWER_KEY_NUM_OF_VLANS]	= { .type = NLA_U8 },
7405008750eSWojciech Drewek 	[TCA_FLOWER_KEY_PPPOE_SID]	= { .type = NLA_U16 },
7415008750eSWojciech Drewek 	[TCA_FLOWER_KEY_PPP_PROTO]	= { .type = NLA_U16 },
7428b189ea0SWojciech Drewek 	[TCA_FLOWER_KEY_L2TPV3_SID]	= { .type = NLA_U32 },
7434c13eda7SRatheesh Kannoth 	[TCA_FLOWER_KEY_SPI]		= { .type = NLA_U32 },
7444c13eda7SRatheesh Kannoth 	[TCA_FLOWER_KEY_SPI_MASK]	= { .type = NLA_U32 },
7451a432018SIdo Schimmel 	[TCA_FLOWER_L2_MISS]		= NLA_POLICY_MAX(NLA_U8, 1),
7467cfffd5fSZahari Doychev 	[TCA_FLOWER_KEY_CFM]		= { .type = NLA_NESTED },
74711036bd7SAsbjørn Sloth Tønnesen 	[TCA_FLOWER_KEY_ENC_FLAGS]	= NLA_POLICY_MASK(NLA_BE32,
74811036bd7SAsbjørn Sloth Tønnesen 							  TCA_FLOWER_KEY_ENC_FLAGS_POLICY_MASK),
74911036bd7SAsbjørn Sloth Tønnesen 	[TCA_FLOWER_KEY_ENC_FLAGS_MASK]	= NLA_POLICY_MASK(NLA_BE32,
75011036bd7SAsbjørn Sloth Tønnesen 							  TCA_FLOWER_KEY_ENC_FLAGS_POLICY_MASK),
7510a6e7778SPieter Jansen van Vuuren };
7520a6e7778SPieter Jansen van Vuuren 
7530a6e7778SPieter Jansen van Vuuren static const struct nla_policy
7540a6e7778SPieter Jansen van Vuuren enc_opts_policy[TCA_FLOWER_KEY_ENC_OPTS_MAX + 1] = {
755d8f9dfaeSXin Long 	[TCA_FLOWER_KEY_ENC_OPTS_UNSPEC]        = {
756d8f9dfaeSXin Long 		.strict_start_type = TCA_FLOWER_KEY_ENC_OPTS_VXLAN },
7570a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPTS_GENEVE]        = { .type = NLA_NESTED },
758d8f9dfaeSXin Long 	[TCA_FLOWER_KEY_ENC_OPTS_VXLAN]         = { .type = NLA_NESTED },
75979b1011cSXin Long 	[TCA_FLOWER_KEY_ENC_OPTS_ERSPAN]        = { .type = NLA_NESTED },
760e3acda7aSWojciech Drewek 	[TCA_FLOWER_KEY_ENC_OPTS_GTP]		= { .type = NLA_NESTED },
7616dd514f4SMichal Swiatkowski 	[TCA_FLOWER_KEY_ENC_OPTS_PFCP]		= { .type = NLA_NESTED },
7620a6e7778SPieter Jansen van Vuuren };
7630a6e7778SPieter Jansen van Vuuren 
7640a6e7778SPieter Jansen van Vuuren static const struct nla_policy
7650a6e7778SPieter Jansen van Vuuren geneve_opt_policy[TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX + 1] = {
7660a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS]      = { .type = NLA_U16 },
7670a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE]       = { .type = NLA_U8 },
7680a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA]       = { .type = NLA_BINARY,
7690a6e7778SPieter Jansen van Vuuren 						       .len = 128 },
77077b9900eSJiri Pirko };
77177b9900eSJiri Pirko 
772d8f9dfaeSXin Long static const struct nla_policy
773d8f9dfaeSXin Long vxlan_opt_policy[TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX + 1] = {
774d8f9dfaeSXin Long 	[TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP]         = { .type = NLA_U32 },
775d8f9dfaeSXin Long };
776d8f9dfaeSXin Long 
77779b1011cSXin Long static const struct nla_policy
77879b1011cSXin Long erspan_opt_policy[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX + 1] = {
77979b1011cSXin Long 	[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER]        = { .type = NLA_U8 },
78079b1011cSXin Long 	[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX]      = { .type = NLA_U32 },
78179b1011cSXin Long 	[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR]        = { .type = NLA_U8 },
78279b1011cSXin Long 	[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID]       = { .type = NLA_U8 },
78379b1011cSXin Long };
78479b1011cSXin Long 
78561aec25aSGuillaume Nault static const struct nla_policy
786e3acda7aSWojciech Drewek gtp_opt_policy[TCA_FLOWER_KEY_ENC_OPT_GTP_MAX + 1] = {
787e3acda7aSWojciech Drewek 	[TCA_FLOWER_KEY_ENC_OPT_GTP_PDU_TYPE]	   = { .type = NLA_U8 },
788e3acda7aSWojciech Drewek 	[TCA_FLOWER_KEY_ENC_OPT_GTP_QFI]	   = { .type = NLA_U8 },
789e3acda7aSWojciech Drewek };
790e3acda7aSWojciech Drewek 
791e3acda7aSWojciech Drewek static const struct nla_policy
7926dd514f4SMichal Swiatkowski pfcp_opt_policy[TCA_FLOWER_KEY_ENC_OPT_PFCP_MAX + 1] = {
7936dd514f4SMichal Swiatkowski 	[TCA_FLOWER_KEY_ENC_OPT_PFCP_TYPE]	   = { .type = NLA_U8 },
7946dd514f4SMichal Swiatkowski 	[TCA_FLOWER_KEY_ENC_OPT_PFCP_SEID]	   = { .type = NLA_U64 },
7956dd514f4SMichal Swiatkowski };
7966dd514f4SMichal Swiatkowski 
7976dd514f4SMichal Swiatkowski static const struct nla_policy
79861aec25aSGuillaume Nault mpls_stack_entry_policy[TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX + 1] = {
79961aec25aSGuillaume Nault 	[TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH]    = { .type = NLA_U8 },
80061aec25aSGuillaume Nault 	[TCA_FLOWER_KEY_MPLS_OPT_LSE_TTL]      = { .type = NLA_U8 },
80161aec25aSGuillaume Nault 	[TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS]      = { .type = NLA_U8 },
80261aec25aSGuillaume Nault 	[TCA_FLOWER_KEY_MPLS_OPT_LSE_TC]       = { .type = NLA_U8 },
80361aec25aSGuillaume Nault 	[TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL]    = { .type = NLA_U32 },
80461aec25aSGuillaume Nault };
80561aec25aSGuillaume Nault 
8064d50e500SEric Dumazet static const struct nla_policy
8074d50e500SEric Dumazet cfm_opt_policy[TCA_FLOWER_KEY_CFM_OPT_MAX + 1] = {
8087cfffd5fSZahari Doychev 	[TCA_FLOWER_KEY_CFM_MD_LEVEL]	= NLA_POLICY_MAX(NLA_U8,
8097cfffd5fSZahari Doychev 						FLOW_DIS_CFM_MDL_MAX),
8107cfffd5fSZahari Doychev 	[TCA_FLOWER_KEY_CFM_OPCODE]	= { .type = NLA_U8 },
8117cfffd5fSZahari Doychev };
8127cfffd5fSZahari Doychev 
fl_set_key_val(struct nlattr ** tb,void * val,int val_type,void * mask,int mask_type,int len)81377b9900eSJiri Pirko static void fl_set_key_val(struct nlattr **tb,
81477b9900eSJiri Pirko 			   void *val, int val_type,
81577b9900eSJiri Pirko 			   void *mask, int mask_type, int len)
81677b9900eSJiri Pirko {
81777b9900eSJiri Pirko 	if (!tb[val_type])
81877b9900eSJiri Pirko 		return;
819e0ace68aSPaul Blakey 	nla_memcpy(val, tb[val_type], len);
82077b9900eSJiri Pirko 	if (mask_type == TCA_FLOWER_UNSPEC || !tb[mask_type])
82177b9900eSJiri Pirko 		memset(mask, 0xff, len);
82277b9900eSJiri Pirko 	else
823e0ace68aSPaul Blakey 		nla_memcpy(mask, tb[mask_type], len);
82477b9900eSJiri Pirko }
82577b9900eSJiri Pirko 
fl_set_key_spi(struct nlattr ** tb,struct fl_flow_key * key,struct fl_flow_key * mask,struct netlink_ext_ack * extack)8264c13eda7SRatheesh Kannoth static int fl_set_key_spi(struct nlattr **tb, struct fl_flow_key *key,
8274c13eda7SRatheesh Kannoth 			  struct fl_flow_key *mask,
8284c13eda7SRatheesh Kannoth 			  struct netlink_ext_ack *extack)
8294c13eda7SRatheesh Kannoth {
8304c13eda7SRatheesh Kannoth 	if (key->basic.ip_proto != IPPROTO_ESP &&
8314c13eda7SRatheesh Kannoth 	    key->basic.ip_proto != IPPROTO_AH) {
8324c13eda7SRatheesh Kannoth 		NL_SET_ERR_MSG(extack,
8334c13eda7SRatheesh Kannoth 			       "Protocol must be either ESP or AH");
8344c13eda7SRatheesh Kannoth 		return -EINVAL;
8354c13eda7SRatheesh Kannoth 	}
8364c13eda7SRatheesh Kannoth 
8374c13eda7SRatheesh Kannoth 	fl_set_key_val(tb, &key->ipsec.spi,
8384c13eda7SRatheesh Kannoth 		       TCA_FLOWER_KEY_SPI,
8394c13eda7SRatheesh Kannoth 		       &mask->ipsec.spi, TCA_FLOWER_KEY_SPI_MASK,
8404c13eda7SRatheesh Kannoth 		       sizeof(key->ipsec.spi));
8414c13eda7SRatheesh Kannoth 	return 0;
8424c13eda7SRatheesh Kannoth }
8434c13eda7SRatheesh Kannoth 
fl_set_key_port_range(struct nlattr ** tb,struct fl_flow_key * key,struct fl_flow_key * mask,struct netlink_ext_ack * extack)8445c72299fSAmritha Nambiar static int fl_set_key_port_range(struct nlattr **tb, struct fl_flow_key *key,
845bd7d4c12SGuillaume Nault 				 struct fl_flow_key *mask,
846bd7d4c12SGuillaume Nault 				 struct netlink_ext_ack *extack)
8475c72299fSAmritha Nambiar {
8488ffb055bSYoshiki Komachi 	fl_set_key_val(tb, &key->tp_range.tp_min.dst,
8498ffb055bSYoshiki Komachi 		       TCA_FLOWER_KEY_PORT_DST_MIN, &mask->tp_range.tp_min.dst,
8508ffb055bSYoshiki Komachi 		       TCA_FLOWER_UNSPEC, sizeof(key->tp_range.tp_min.dst));
8518ffb055bSYoshiki Komachi 	fl_set_key_val(tb, &key->tp_range.tp_max.dst,
8528ffb055bSYoshiki Komachi 		       TCA_FLOWER_KEY_PORT_DST_MAX, &mask->tp_range.tp_max.dst,
8538ffb055bSYoshiki Komachi 		       TCA_FLOWER_UNSPEC, sizeof(key->tp_range.tp_max.dst));
8548ffb055bSYoshiki Komachi 	fl_set_key_val(tb, &key->tp_range.tp_min.src,
8558ffb055bSYoshiki Komachi 		       TCA_FLOWER_KEY_PORT_SRC_MIN, &mask->tp_range.tp_min.src,
8568ffb055bSYoshiki Komachi 		       TCA_FLOWER_UNSPEC, sizeof(key->tp_range.tp_min.src));
8578ffb055bSYoshiki Komachi 	fl_set_key_val(tb, &key->tp_range.tp_max.src,
8588ffb055bSYoshiki Komachi 		       TCA_FLOWER_KEY_PORT_SRC_MAX, &mask->tp_range.tp_max.src,
8598ffb055bSYoshiki Komachi 		       TCA_FLOWER_UNSPEC, sizeof(key->tp_range.tp_max.src));
8605c72299fSAmritha Nambiar 
861d3f87278SIdo Schimmel 	if (mask->tp_range.tp_min.dst != mask->tp_range.tp_max.dst) {
862d3f87278SIdo Schimmel 		NL_SET_ERR_MSG(extack,
863d3f87278SIdo Schimmel 			       "Both min and max destination ports must be specified");
864d3f87278SIdo Schimmel 		return -EINVAL;
865d3f87278SIdo Schimmel 	}
866d3f87278SIdo Schimmel 	if (mask->tp_range.tp_min.src != mask->tp_range.tp_max.src) {
867d3f87278SIdo Schimmel 		NL_SET_ERR_MSG(extack,
868d3f87278SIdo Schimmel 			       "Both min and max source ports must be specified");
869d3f87278SIdo Schimmel 		return -EINVAL;
870d3f87278SIdo Schimmel 	}
871bd7d4c12SGuillaume Nault 	if (mask->tp_range.tp_min.dst && mask->tp_range.tp_max.dst &&
8726215afcbSVladimir Oltean 	    ntohs(key->tp_range.tp_max.dst) <=
8736215afcbSVladimir Oltean 	    ntohs(key->tp_range.tp_min.dst)) {
874bd7d4c12SGuillaume Nault 		NL_SET_ERR_MSG_ATTR(extack,
875bd7d4c12SGuillaume Nault 				    tb[TCA_FLOWER_KEY_PORT_DST_MIN],
876bd7d4c12SGuillaume Nault 				    "Invalid destination port range (min must be strictly smaller than max)");
8775c72299fSAmritha Nambiar 		return -EINVAL;
878bd7d4c12SGuillaume Nault 	}
879bd7d4c12SGuillaume Nault 	if (mask->tp_range.tp_min.src && mask->tp_range.tp_max.src &&
8806215afcbSVladimir Oltean 	    ntohs(key->tp_range.tp_max.src) <=
8816215afcbSVladimir Oltean 	    ntohs(key->tp_range.tp_min.src)) {
882bd7d4c12SGuillaume Nault 		NL_SET_ERR_MSG_ATTR(extack,
883bd7d4c12SGuillaume Nault 				    tb[TCA_FLOWER_KEY_PORT_SRC_MIN],
884bd7d4c12SGuillaume Nault 				    "Invalid source port range (min must be strictly smaller than max)");
885bd7d4c12SGuillaume Nault 		return -EINVAL;
886bd7d4c12SGuillaume Nault 	}
8875c72299fSAmritha Nambiar 
8885c72299fSAmritha Nambiar 	return 0;
8895c72299fSAmritha Nambiar }
8905c72299fSAmritha Nambiar 
fl_set_key_mpls_lse(const struct nlattr * nla_lse,struct flow_dissector_key_mpls * key_val,struct flow_dissector_key_mpls * key_mask,struct netlink_ext_ack * extack)89161aec25aSGuillaume Nault static int fl_set_key_mpls_lse(const struct nlattr *nla_lse,
89261aec25aSGuillaume Nault 			       struct flow_dissector_key_mpls *key_val,
89361aec25aSGuillaume Nault 			       struct flow_dissector_key_mpls *key_mask,
89461aec25aSGuillaume Nault 			       struct netlink_ext_ack *extack)
89561aec25aSGuillaume Nault {
89661aec25aSGuillaume Nault 	struct nlattr *tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX + 1];
89761aec25aSGuillaume Nault 	struct flow_dissector_mpls_lse *lse_mask;
89861aec25aSGuillaume Nault 	struct flow_dissector_mpls_lse *lse_val;
89961aec25aSGuillaume Nault 	u8 lse_index;
90061aec25aSGuillaume Nault 	u8 depth;
90161aec25aSGuillaume Nault 	int err;
90261aec25aSGuillaume Nault 
90361aec25aSGuillaume Nault 	err = nla_parse_nested(tb, TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX, nla_lse,
90461aec25aSGuillaume Nault 			       mpls_stack_entry_policy, extack);
90561aec25aSGuillaume Nault 	if (err < 0)
90661aec25aSGuillaume Nault 		return err;
90761aec25aSGuillaume Nault 
90861aec25aSGuillaume Nault 	if (!tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH]) {
90961aec25aSGuillaume Nault 		NL_SET_ERR_MSG(extack, "Missing MPLS option \"depth\"");
91061aec25aSGuillaume Nault 		return -EINVAL;
91161aec25aSGuillaume Nault 	}
91261aec25aSGuillaume Nault 
91361aec25aSGuillaume Nault 	depth = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH]);
91461aec25aSGuillaume Nault 
91561aec25aSGuillaume Nault 	/* LSE depth starts at 1, for consistency with terminology used by
91661aec25aSGuillaume Nault 	 * RFC 3031 (section 3.9), where depth 0 refers to unlabeled packets.
91761aec25aSGuillaume Nault 	 */
91861aec25aSGuillaume Nault 	if (depth < 1 || depth > FLOW_DIS_MPLS_MAX) {
91961aec25aSGuillaume Nault 		NL_SET_ERR_MSG_ATTR(extack,
92061aec25aSGuillaume Nault 				    tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH],
92161aec25aSGuillaume Nault 				    "Invalid MPLS depth");
92261aec25aSGuillaume Nault 		return -EINVAL;
92361aec25aSGuillaume Nault 	}
92461aec25aSGuillaume Nault 	lse_index = depth - 1;
92561aec25aSGuillaume Nault 
92661aec25aSGuillaume Nault 	dissector_set_mpls_lse(key_val, lse_index);
92761aec25aSGuillaume Nault 	dissector_set_mpls_lse(key_mask, lse_index);
92861aec25aSGuillaume Nault 
92961aec25aSGuillaume Nault 	lse_val = &key_val->ls[lse_index];
93061aec25aSGuillaume Nault 	lse_mask = &key_mask->ls[lse_index];
93161aec25aSGuillaume Nault 
93261aec25aSGuillaume Nault 	if (tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_TTL]) {
93361aec25aSGuillaume Nault 		lse_val->mpls_ttl = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_TTL]);
93461aec25aSGuillaume Nault 		lse_mask->mpls_ttl = MPLS_TTL_MASK;
93561aec25aSGuillaume Nault 	}
93661aec25aSGuillaume Nault 	if (tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS]) {
93761aec25aSGuillaume Nault 		u8 bos = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS]);
93861aec25aSGuillaume Nault 
93961aec25aSGuillaume Nault 		if (bos & ~MPLS_BOS_MASK) {
94061aec25aSGuillaume Nault 			NL_SET_ERR_MSG_ATTR(extack,
94161aec25aSGuillaume Nault 					    tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS],
94261aec25aSGuillaume Nault 					    "Bottom Of Stack (BOS) must be 0 or 1");
94361aec25aSGuillaume Nault 			return -EINVAL;
94461aec25aSGuillaume Nault 		}
94561aec25aSGuillaume Nault 		lse_val->mpls_bos = bos;
94661aec25aSGuillaume Nault 		lse_mask->mpls_bos = MPLS_BOS_MASK;
94761aec25aSGuillaume Nault 	}
94861aec25aSGuillaume Nault 	if (tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_TC]) {
94961aec25aSGuillaume Nault 		u8 tc = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_TC]);
95061aec25aSGuillaume Nault 
95161aec25aSGuillaume Nault 		if (tc & ~MPLS_TC_MASK) {
95261aec25aSGuillaume Nault 			NL_SET_ERR_MSG_ATTR(extack,
95361aec25aSGuillaume Nault 					    tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_TC],
95461aec25aSGuillaume Nault 					    "Traffic Class (TC) must be between 0 and 7");
95561aec25aSGuillaume Nault 			return -EINVAL;
95661aec25aSGuillaume Nault 		}
95761aec25aSGuillaume Nault 		lse_val->mpls_tc = tc;
95861aec25aSGuillaume Nault 		lse_mask->mpls_tc = MPLS_TC_MASK;
95961aec25aSGuillaume Nault 	}
96061aec25aSGuillaume Nault 	if (tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL]) {
96161aec25aSGuillaume Nault 		u32 label = nla_get_u32(tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL]);
96261aec25aSGuillaume Nault 
96361aec25aSGuillaume Nault 		if (label & ~MPLS_LABEL_MASK) {
96461aec25aSGuillaume Nault 			NL_SET_ERR_MSG_ATTR(extack,
96561aec25aSGuillaume Nault 					    tb[TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL],
96661aec25aSGuillaume Nault 					    "Label must be between 0 and 1048575");
96761aec25aSGuillaume Nault 			return -EINVAL;
96861aec25aSGuillaume Nault 		}
96961aec25aSGuillaume Nault 		lse_val->mpls_label = label;
97061aec25aSGuillaume Nault 		lse_mask->mpls_label = MPLS_LABEL_MASK;
97161aec25aSGuillaume Nault 	}
97261aec25aSGuillaume Nault 
97361aec25aSGuillaume Nault 	return 0;
97461aec25aSGuillaume Nault }
97561aec25aSGuillaume Nault 
fl_set_key_mpls_opts(const struct nlattr * nla_mpls_opts,struct flow_dissector_key_mpls * key_val,struct flow_dissector_key_mpls * key_mask,struct netlink_ext_ack * extack)97661aec25aSGuillaume Nault static int fl_set_key_mpls_opts(const struct nlattr *nla_mpls_opts,
97761aec25aSGuillaume Nault 				struct flow_dissector_key_mpls *key_val,
97861aec25aSGuillaume Nault 				struct flow_dissector_key_mpls *key_mask,
97961aec25aSGuillaume Nault 				struct netlink_ext_ack *extack)
98061aec25aSGuillaume Nault {
98161aec25aSGuillaume Nault 	struct nlattr *nla_lse;
98261aec25aSGuillaume Nault 	int rem;
98361aec25aSGuillaume Nault 	int err;
98461aec25aSGuillaume Nault 
98561aec25aSGuillaume Nault 	if (!(nla_mpls_opts->nla_type & NLA_F_NESTED)) {
98661aec25aSGuillaume Nault 		NL_SET_ERR_MSG_ATTR(extack, nla_mpls_opts,
98761aec25aSGuillaume Nault 				    "NLA_F_NESTED is missing");
98861aec25aSGuillaume Nault 		return -EINVAL;
98961aec25aSGuillaume Nault 	}
99061aec25aSGuillaume Nault 
99161aec25aSGuillaume Nault 	nla_for_each_nested(nla_lse, nla_mpls_opts, rem) {
99261aec25aSGuillaume Nault 		if (nla_type(nla_lse) != TCA_FLOWER_KEY_MPLS_OPTS_LSE) {
99361aec25aSGuillaume Nault 			NL_SET_ERR_MSG_ATTR(extack, nla_lse,
99461aec25aSGuillaume Nault 					    "Invalid MPLS option type");
99561aec25aSGuillaume Nault 			return -EINVAL;
99661aec25aSGuillaume Nault 		}
99761aec25aSGuillaume Nault 
99861aec25aSGuillaume Nault 		err = fl_set_key_mpls_lse(nla_lse, key_val, key_mask, extack);
99961aec25aSGuillaume Nault 		if (err < 0)
100061aec25aSGuillaume Nault 			return err;
100161aec25aSGuillaume Nault 	}
100261aec25aSGuillaume Nault 	if (rem) {
100361aec25aSGuillaume Nault 		NL_SET_ERR_MSG(extack,
100461aec25aSGuillaume Nault 			       "Bytes leftover after parsing MPLS options");
100561aec25aSGuillaume Nault 		return -EINVAL;
100661aec25aSGuillaume Nault 	}
100761aec25aSGuillaume Nault 
100861aec25aSGuillaume Nault 	return 0;
100961aec25aSGuillaume Nault }
101061aec25aSGuillaume Nault 
fl_set_key_mpls(struct nlattr ** tb,struct flow_dissector_key_mpls * key_val,struct flow_dissector_key_mpls * key_mask,struct netlink_ext_ack * extack)10111a7fca63SBenjamin LaHaise static int fl_set_key_mpls(struct nlattr **tb,
1012a577d8f7SBenjamin LaHaise 			   struct flow_dissector_key_mpls *key_val,
1013442f730eSGuillaume Nault 			   struct flow_dissector_key_mpls *key_mask,
1014442f730eSGuillaume Nault 			   struct netlink_ext_ack *extack)
1015a577d8f7SBenjamin LaHaise {
101658cff782SGuillaume Nault 	struct flow_dissector_mpls_lse *lse_mask;
101758cff782SGuillaume Nault 	struct flow_dissector_mpls_lse *lse_val;
101858cff782SGuillaume Nault 
101961aec25aSGuillaume Nault 	if (tb[TCA_FLOWER_KEY_MPLS_OPTS]) {
102061aec25aSGuillaume Nault 		if (tb[TCA_FLOWER_KEY_MPLS_TTL] ||
102161aec25aSGuillaume Nault 		    tb[TCA_FLOWER_KEY_MPLS_BOS] ||
102261aec25aSGuillaume Nault 		    tb[TCA_FLOWER_KEY_MPLS_TC] ||
102361aec25aSGuillaume Nault 		    tb[TCA_FLOWER_KEY_MPLS_LABEL]) {
102461aec25aSGuillaume Nault 			NL_SET_ERR_MSG_ATTR(extack,
102561aec25aSGuillaume Nault 					    tb[TCA_FLOWER_KEY_MPLS_OPTS],
102661aec25aSGuillaume Nault 					    "MPLS label, Traffic Class, Bottom Of Stack and Time To Live must be encapsulated in the MPLS options attribute");
102761aec25aSGuillaume Nault 			return -EBADMSG;
102861aec25aSGuillaume Nault 		}
102961aec25aSGuillaume Nault 
103061aec25aSGuillaume Nault 		return fl_set_key_mpls_opts(tb[TCA_FLOWER_KEY_MPLS_OPTS],
103161aec25aSGuillaume Nault 					    key_val, key_mask, extack);
103261aec25aSGuillaume Nault 	}
103361aec25aSGuillaume Nault 
103458cff782SGuillaume Nault 	lse_val = &key_val->ls[0];
103558cff782SGuillaume Nault 	lse_mask = &key_mask->ls[0];
103658cff782SGuillaume Nault 
1037a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_TTL]) {
103858cff782SGuillaume Nault 		lse_val->mpls_ttl = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TTL]);
103958cff782SGuillaume Nault 		lse_mask->mpls_ttl = MPLS_TTL_MASK;
104058cff782SGuillaume Nault 		dissector_set_mpls_lse(key_val, 0);
104158cff782SGuillaume Nault 		dissector_set_mpls_lse(key_mask, 0);
1042a577d8f7SBenjamin LaHaise 	}
1043a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_BOS]) {
10441a7fca63SBenjamin LaHaise 		u8 bos = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_BOS]);
10451a7fca63SBenjamin LaHaise 
1046442f730eSGuillaume Nault 		if (bos & ~MPLS_BOS_MASK) {
1047442f730eSGuillaume Nault 			NL_SET_ERR_MSG_ATTR(extack,
1048442f730eSGuillaume Nault 					    tb[TCA_FLOWER_KEY_MPLS_BOS],
1049442f730eSGuillaume Nault 					    "Bottom Of Stack (BOS) must be 0 or 1");
10501a7fca63SBenjamin LaHaise 			return -EINVAL;
1051442f730eSGuillaume Nault 		}
105258cff782SGuillaume Nault 		lse_val->mpls_bos = bos;
105358cff782SGuillaume Nault 		lse_mask->mpls_bos = MPLS_BOS_MASK;
105458cff782SGuillaume Nault 		dissector_set_mpls_lse(key_val, 0);
105558cff782SGuillaume Nault 		dissector_set_mpls_lse(key_mask, 0);
1056a577d8f7SBenjamin LaHaise 	}
1057a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_TC]) {
10581a7fca63SBenjamin LaHaise 		u8 tc = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TC]);
10591a7fca63SBenjamin LaHaise 
1060442f730eSGuillaume Nault 		if (tc & ~MPLS_TC_MASK) {
1061442f730eSGuillaume Nault 			NL_SET_ERR_MSG_ATTR(extack,
1062442f730eSGuillaume Nault 					    tb[TCA_FLOWER_KEY_MPLS_TC],
1063442f730eSGuillaume Nault 					    "Traffic Class (TC) must be between 0 and 7");
10641a7fca63SBenjamin LaHaise 			return -EINVAL;
1065442f730eSGuillaume Nault 		}
106658cff782SGuillaume Nault 		lse_val->mpls_tc = tc;
106758cff782SGuillaume Nault 		lse_mask->mpls_tc = MPLS_TC_MASK;
106858cff782SGuillaume Nault 		dissector_set_mpls_lse(key_val, 0);
106958cff782SGuillaume Nault 		dissector_set_mpls_lse(key_mask, 0);
1070a577d8f7SBenjamin LaHaise 	}
1071a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_LABEL]) {
10721a7fca63SBenjamin LaHaise 		u32 label = nla_get_u32(tb[TCA_FLOWER_KEY_MPLS_LABEL]);
10731a7fca63SBenjamin LaHaise 
1074442f730eSGuillaume Nault 		if (label & ~MPLS_LABEL_MASK) {
1075442f730eSGuillaume Nault 			NL_SET_ERR_MSG_ATTR(extack,
1076442f730eSGuillaume Nault 					    tb[TCA_FLOWER_KEY_MPLS_LABEL],
1077442f730eSGuillaume Nault 					    "Label must be between 0 and 1048575");
10781a7fca63SBenjamin LaHaise 			return -EINVAL;
1079442f730eSGuillaume Nault 		}
108058cff782SGuillaume Nault 		lse_val->mpls_label = label;
108158cff782SGuillaume Nault 		lse_mask->mpls_label = MPLS_LABEL_MASK;
108258cff782SGuillaume Nault 		dissector_set_mpls_lse(key_val, 0);
108358cff782SGuillaume Nault 		dissector_set_mpls_lse(key_mask, 0);
1084a577d8f7SBenjamin LaHaise 	}
10851a7fca63SBenjamin LaHaise 	return 0;
1086a577d8f7SBenjamin LaHaise }
1087a577d8f7SBenjamin LaHaise 
fl_set_key_vlan(struct nlattr ** tb,__be16 ethertype,int vlan_id_key,int vlan_prio_key,int vlan_next_eth_type_key,struct flow_dissector_key_vlan * key_val,struct flow_dissector_key_vlan * key_mask)10889399ae9aSHadar Hen Zion static void fl_set_key_vlan(struct nlattr **tb,
1089aaab0834SJianbo Liu 			    __be16 ethertype,
1090d64efd09SJianbo Liu 			    int vlan_id_key, int vlan_prio_key,
10912105f700SVlad Buslov 			    int vlan_next_eth_type_key,
10929399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *key_val,
10939399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *key_mask)
10949399ae9aSHadar Hen Zion {
10959399ae9aSHadar Hen Zion #define VLAN_PRIORITY_MASK	0x7
10969399ae9aSHadar Hen Zion 
1097d64efd09SJianbo Liu 	if (tb[vlan_id_key]) {
10989399ae9aSHadar Hen Zion 		key_val->vlan_id =
1099d64efd09SJianbo Liu 			nla_get_u16(tb[vlan_id_key]) & VLAN_VID_MASK;
11009399ae9aSHadar Hen Zion 		key_mask->vlan_id = VLAN_VID_MASK;
11019399ae9aSHadar Hen Zion 	}
1102d64efd09SJianbo Liu 	if (tb[vlan_prio_key]) {
11039399ae9aSHadar Hen Zion 		key_val->vlan_priority =
1104d64efd09SJianbo Liu 			nla_get_u8(tb[vlan_prio_key]) &
11059399ae9aSHadar Hen Zion 			VLAN_PRIORITY_MASK;
11069399ae9aSHadar Hen Zion 		key_mask->vlan_priority = VLAN_PRIORITY_MASK;
11079399ae9aSHadar Hen Zion 	}
110899fdb22bSBoris Sukholitko 	if (ethertype) {
1109aaab0834SJianbo Liu 		key_val->vlan_tpid = ethertype;
1110aaab0834SJianbo Liu 		key_mask->vlan_tpid = cpu_to_be16(~0);
111199fdb22bSBoris Sukholitko 	}
11122105f700SVlad Buslov 	if (tb[vlan_next_eth_type_key]) {
11132105f700SVlad Buslov 		key_val->vlan_eth_type =
11142105f700SVlad Buslov 			nla_get_be16(tb[vlan_next_eth_type_key]);
11152105f700SVlad Buslov 		key_mask->vlan_eth_type = cpu_to_be16(~0);
11162105f700SVlad Buslov 	}
11179399ae9aSHadar Hen Zion }
11189399ae9aSHadar Hen Zion 
fl_set_key_pppoe(struct nlattr ** tb,struct flow_dissector_key_pppoe * key_val,struct flow_dissector_key_pppoe * key_mask,struct fl_flow_key * key,struct fl_flow_key * mask)11195008750eSWojciech Drewek static void fl_set_key_pppoe(struct nlattr **tb,
11205008750eSWojciech Drewek 			     struct flow_dissector_key_pppoe *key_val,
11215008750eSWojciech Drewek 			     struct flow_dissector_key_pppoe *key_mask,
11225008750eSWojciech Drewek 			     struct fl_flow_key *key,
11235008750eSWojciech Drewek 			     struct fl_flow_key *mask)
11245008750eSWojciech Drewek {
11255008750eSWojciech Drewek 	/* key_val::type must be set to ETH_P_PPP_SES
11265008750eSWojciech Drewek 	 * because ETH_P_PPP_SES was stored in basic.n_proto
11275008750eSWojciech Drewek 	 * which might get overwritten by ppp_proto
11285008750eSWojciech Drewek 	 * or might be set to 0, the role of key_val::type
11294170f0efSTaichi Nishimura 	 * is similar to vlan_key::tpid
11305008750eSWojciech Drewek 	 */
11315008750eSWojciech Drewek 	key_val->type = htons(ETH_P_PPP_SES);
11325008750eSWojciech Drewek 	key_mask->type = cpu_to_be16(~0);
11335008750eSWojciech Drewek 
11345008750eSWojciech Drewek 	if (tb[TCA_FLOWER_KEY_PPPOE_SID]) {
11355008750eSWojciech Drewek 		key_val->session_id =
11365008750eSWojciech Drewek 			nla_get_be16(tb[TCA_FLOWER_KEY_PPPOE_SID]);
11375008750eSWojciech Drewek 		key_mask->session_id = cpu_to_be16(~0);
11385008750eSWojciech Drewek 	}
11395008750eSWojciech Drewek 	if (tb[TCA_FLOWER_KEY_PPP_PROTO]) {
11405008750eSWojciech Drewek 		key_val->ppp_proto =
11415008750eSWojciech Drewek 			nla_get_be16(tb[TCA_FLOWER_KEY_PPP_PROTO]);
11425008750eSWojciech Drewek 		key_mask->ppp_proto = cpu_to_be16(~0);
11435008750eSWojciech Drewek 
11445008750eSWojciech Drewek 		if (key_val->ppp_proto == htons(PPP_IP)) {
11455008750eSWojciech Drewek 			key->basic.n_proto = htons(ETH_P_IP);
11465008750eSWojciech Drewek 			mask->basic.n_proto = cpu_to_be16(~0);
11475008750eSWojciech Drewek 		} else if (key_val->ppp_proto == htons(PPP_IPV6)) {
11485008750eSWojciech Drewek 			key->basic.n_proto = htons(ETH_P_IPV6);
11495008750eSWojciech Drewek 			mask->basic.n_proto = cpu_to_be16(~0);
11505008750eSWojciech Drewek 		} else if (key_val->ppp_proto == htons(PPP_MPLS_UC)) {
11515008750eSWojciech Drewek 			key->basic.n_proto = htons(ETH_P_MPLS_UC);
11525008750eSWojciech Drewek 			mask->basic.n_proto = cpu_to_be16(~0);
11535008750eSWojciech Drewek 		} else if (key_val->ppp_proto == htons(PPP_MPLS_MC)) {
11545008750eSWojciech Drewek 			key->basic.n_proto = htons(ETH_P_MPLS_MC);
11555008750eSWojciech Drewek 			mask->basic.n_proto = cpu_to_be16(~0);
11565008750eSWojciech Drewek 		}
11575008750eSWojciech Drewek 	} else {
11585008750eSWojciech Drewek 		key->basic.n_proto = 0;
11595008750eSWojciech Drewek 		mask->basic.n_proto = cpu_to_be16(0);
11605008750eSWojciech Drewek 	}
11615008750eSWojciech Drewek }
11625008750eSWojciech Drewek 
fl_set_key_flag(u32 flower_key,u32 flower_mask,u32 * dissector_key,u32 * dissector_mask,u32 flower_flag_bit,u32 dissector_flag_bit)1163faa3ffceSOr Gerlitz static void fl_set_key_flag(u32 flower_key, u32 flower_mask,
1164faa3ffceSOr Gerlitz 			    u32 *dissector_key, u32 *dissector_mask,
1165faa3ffceSOr Gerlitz 			    u32 flower_flag_bit, u32 dissector_flag_bit)
1166faa3ffceSOr Gerlitz {
1167faa3ffceSOr Gerlitz 	if (flower_mask & flower_flag_bit) {
1168faa3ffceSOr Gerlitz 		*dissector_mask |= dissector_flag_bit;
1169faa3ffceSOr Gerlitz 		if (flower_key & flower_flag_bit)
1170faa3ffceSOr Gerlitz 			*dissector_key |= dissector_flag_bit;
1171faa3ffceSOr Gerlitz 	}
1172faa3ffceSOr Gerlitz }
1173faa3ffceSOr Gerlitz 
fl_set_key_flags(struct nlattr * tca_opts,struct nlattr ** tb,bool encap,u32 * flags_key,u32 * flags_mask,struct netlink_ext_ack * extack)1174*536b97acSAsbjørn Sloth Tønnesen static int fl_set_key_flags(struct nlattr *tca_opts, struct nlattr **tb,
1175*536b97acSAsbjørn Sloth Tønnesen 			    bool encap, u32 *flags_key, u32 *flags_mask,
1176*536b97acSAsbjørn Sloth Tønnesen 			    struct netlink_ext_ack *extack)
1177faa3ffceSOr Gerlitz {
1178fcb4bb07SAsbjørn Sloth Tønnesen 	int fl_key, fl_mask;
1179faa3ffceSOr Gerlitz 	u32 key, mask;
1180faa3ffceSOr Gerlitz 
1181fcb4bb07SAsbjørn Sloth Tønnesen 	if (encap) {
1182fcb4bb07SAsbjørn Sloth Tønnesen 		fl_key = TCA_FLOWER_KEY_ENC_FLAGS;
1183fcb4bb07SAsbjørn Sloth Tønnesen 		fl_mask = TCA_FLOWER_KEY_ENC_FLAGS_MASK;
1184fcb4bb07SAsbjørn Sloth Tønnesen 	} else {
1185fcb4bb07SAsbjørn Sloth Tønnesen 		fl_key = TCA_FLOWER_KEY_FLAGS;
1186fcb4bb07SAsbjørn Sloth Tønnesen 		fl_mask = TCA_FLOWER_KEY_FLAGS_MASK;
1187fcb4bb07SAsbjørn Sloth Tønnesen 	}
1188fcb4bb07SAsbjørn Sloth Tønnesen 
1189d9724772SOr Gerlitz 	/* mask is mandatory for flags */
1190*536b97acSAsbjørn Sloth Tønnesen 	if (NL_REQ_ATTR_CHECK(extack, tca_opts, tb, fl_mask)) {
1191e304e21aSGuillaume Nault 		NL_SET_ERR_MSG(extack, "Missing flags mask");
1192d9724772SOr Gerlitz 		return -EINVAL;
1193e304e21aSGuillaume Nault 	}
1194faa3ffceSOr Gerlitz 
1195fcb4bb07SAsbjørn Sloth Tønnesen 	key = be32_to_cpu(nla_get_be32(tb[fl_key]));
1196fcb4bb07SAsbjørn Sloth Tønnesen 	mask = be32_to_cpu(nla_get_be32(tb[fl_mask]));
1197faa3ffceSOr Gerlitz 
1198faa3ffceSOr Gerlitz 	*flags_key  = 0;
1199faa3ffceSOr Gerlitz 	*flags_mask = 0;
1200faa3ffceSOr Gerlitz 
1201faa3ffceSOr Gerlitz 	fl_set_key_flag(key, mask, flags_key, flags_mask,
1202faa3ffceSOr Gerlitz 			TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT);
1203459d153dSPieter Jansen van Vuuren 	fl_set_key_flag(key, mask, flags_key, flags_mask,
1204459d153dSPieter Jansen van Vuuren 			TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST,
1205459d153dSPieter Jansen van Vuuren 			FLOW_DIS_FIRST_FRAG);
1206d9724772SOr Gerlitz 
1207988f8723SAsbjørn Sloth Tønnesen 	fl_set_key_flag(key, mask, flags_key, flags_mask,
1208988f8723SAsbjørn Sloth Tønnesen 			TCA_FLOWER_KEY_FLAGS_TUNNEL_CSUM,
1209988f8723SAsbjørn Sloth Tønnesen 			FLOW_DIS_F_TUNNEL_CSUM);
1210988f8723SAsbjørn Sloth Tønnesen 
1211988f8723SAsbjørn Sloth Tønnesen 	fl_set_key_flag(key, mask, flags_key, flags_mask,
1212988f8723SAsbjørn Sloth Tønnesen 			TCA_FLOWER_KEY_FLAGS_TUNNEL_DONT_FRAGMENT,
1213988f8723SAsbjørn Sloth Tønnesen 			FLOW_DIS_F_TUNNEL_DONT_FRAGMENT);
1214988f8723SAsbjørn Sloth Tønnesen 
1215988f8723SAsbjørn Sloth Tønnesen 	fl_set_key_flag(key, mask, flags_key, flags_mask,
1216988f8723SAsbjørn Sloth Tønnesen 			TCA_FLOWER_KEY_FLAGS_TUNNEL_OAM, FLOW_DIS_F_TUNNEL_OAM);
1217988f8723SAsbjørn Sloth Tønnesen 
1218988f8723SAsbjørn Sloth Tønnesen 	fl_set_key_flag(key, mask, flags_key, flags_mask,
1219988f8723SAsbjørn Sloth Tønnesen 			TCA_FLOWER_KEY_FLAGS_TUNNEL_CRIT_OPT,
1220988f8723SAsbjørn Sloth Tønnesen 			FLOW_DIS_F_TUNNEL_CRIT_OPT);
1221988f8723SAsbjørn Sloth Tønnesen 
1222d9724772SOr Gerlitz 	return 0;
1223faa3ffceSOr Gerlitz }
1224faa3ffceSOr Gerlitz 
fl_set_key_ip(struct nlattr ** tb,bool encap,struct flow_dissector_key_ip * key,struct flow_dissector_key_ip * mask)12250e2c17b6SOr Gerlitz static void fl_set_key_ip(struct nlattr **tb, bool encap,
12264d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *key,
12274d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *mask)
12284d80cc0aSOr Gerlitz {
12290e2c17b6SOr Gerlitz 	int tos_key = encap ? TCA_FLOWER_KEY_ENC_IP_TOS : TCA_FLOWER_KEY_IP_TOS;
12300e2c17b6SOr Gerlitz 	int ttl_key = encap ? TCA_FLOWER_KEY_ENC_IP_TTL : TCA_FLOWER_KEY_IP_TTL;
12310e2c17b6SOr Gerlitz 	int tos_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TOS_MASK : TCA_FLOWER_KEY_IP_TOS_MASK;
12320e2c17b6SOr Gerlitz 	int ttl_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TTL_MASK : TCA_FLOWER_KEY_IP_TTL_MASK;
12334d80cc0aSOr Gerlitz 
12340e2c17b6SOr Gerlitz 	fl_set_key_val(tb, &key->tos, tos_key, &mask->tos, tos_mask, sizeof(key->tos));
12350e2c17b6SOr Gerlitz 	fl_set_key_val(tb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl));
12364d80cc0aSOr Gerlitz }
12374d80cc0aSOr Gerlitz 
fl_set_geneve_opt(const struct nlattr * nla,struct fl_flow_key * key,int depth,int option_len,struct netlink_ext_ack * extack)12380a6e7778SPieter Jansen van Vuuren static int fl_set_geneve_opt(const struct nlattr *nla, struct fl_flow_key *key,
12390a6e7778SPieter Jansen van Vuuren 			     int depth, int option_len,
12400a6e7778SPieter Jansen van Vuuren 			     struct netlink_ext_ack *extack)
12410a6e7778SPieter Jansen van Vuuren {
12420a6e7778SPieter Jansen van Vuuren 	struct nlattr *tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX + 1];
12430a6e7778SPieter Jansen van Vuuren 	struct nlattr *class = NULL, *type = NULL, *data = NULL;
12440a6e7778SPieter Jansen van Vuuren 	struct geneve_opt *opt;
12450a6e7778SPieter Jansen van Vuuren 	int err, data_len = 0;
12460a6e7778SPieter Jansen van Vuuren 
12470a6e7778SPieter Jansen van Vuuren 	if (option_len > sizeof(struct geneve_opt))
12480a6e7778SPieter Jansen van Vuuren 		data_len = option_len - sizeof(struct geneve_opt);
12490a6e7778SPieter Jansen van Vuuren 
12504d56304eSHangyu Hua 	if (key->enc_opts.len > FLOW_DIS_TUN_OPTS_MAX - 4)
12514d56304eSHangyu Hua 		return -ERANGE;
12524d56304eSHangyu Hua 
12530a6e7778SPieter Jansen van Vuuren 	opt = (struct geneve_opt *)&key->enc_opts.data[key->enc_opts.len];
12540a6e7778SPieter Jansen van Vuuren 	memset(opt, 0xff, option_len);
12550a6e7778SPieter Jansen van Vuuren 	opt->length = data_len / 4;
12560a6e7778SPieter Jansen van Vuuren 	opt->r1 = 0;
12570a6e7778SPieter Jansen van Vuuren 	opt->r2 = 0;
12580a6e7778SPieter Jansen van Vuuren 	opt->r3 = 0;
12590a6e7778SPieter Jansen van Vuuren 
12600a6e7778SPieter Jansen van Vuuren 	/* If no mask has been prodived we assume an exact match. */
12610a6e7778SPieter Jansen van Vuuren 	if (!depth)
12620a6e7778SPieter Jansen van Vuuren 		return sizeof(struct geneve_opt) + data_len;
12630a6e7778SPieter Jansen van Vuuren 
12640a6e7778SPieter Jansen van Vuuren 	if (nla_type(nla) != TCA_FLOWER_KEY_ENC_OPTS_GENEVE) {
12650a6e7778SPieter Jansen van Vuuren 		NL_SET_ERR_MSG(extack, "Non-geneve option type for mask");
12660a6e7778SPieter Jansen van Vuuren 		return -EINVAL;
12670a6e7778SPieter Jansen van Vuuren 	}
12680a6e7778SPieter Jansen van Vuuren 
12698cb08174SJohannes Berg 	err = nla_parse_nested_deprecated(tb,
12708cb08174SJohannes Berg 					  TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX,
12710a6e7778SPieter Jansen van Vuuren 					  nla, geneve_opt_policy, extack);
12720a6e7778SPieter Jansen van Vuuren 	if (err < 0)
12730a6e7778SPieter Jansen van Vuuren 		return err;
12740a6e7778SPieter Jansen van Vuuren 
12750a6e7778SPieter Jansen van Vuuren 	/* We are not allowed to omit any of CLASS, TYPE or DATA
12760a6e7778SPieter Jansen van Vuuren 	 * fields from the key.
12770a6e7778SPieter Jansen van Vuuren 	 */
12780a6e7778SPieter Jansen van Vuuren 	if (!option_len &&
12790a6e7778SPieter Jansen van Vuuren 	    (!tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS] ||
12800a6e7778SPieter Jansen van Vuuren 	     !tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE] ||
12810a6e7778SPieter Jansen van Vuuren 	     !tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA])) {
12820a6e7778SPieter Jansen van Vuuren 		NL_SET_ERR_MSG(extack, "Missing tunnel key geneve option class, type or data");
12830a6e7778SPieter Jansen van Vuuren 		return -EINVAL;
12840a6e7778SPieter Jansen van Vuuren 	}
12850a6e7778SPieter Jansen van Vuuren 
12860a6e7778SPieter Jansen van Vuuren 	/* Omitting any of CLASS, TYPE or DATA fields is allowed
12870a6e7778SPieter Jansen van Vuuren 	 * for the mask.
12880a6e7778SPieter Jansen van Vuuren 	 */
12890a6e7778SPieter Jansen van Vuuren 	if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA]) {
12900a6e7778SPieter Jansen van Vuuren 		int new_len = key->enc_opts.len;
12910a6e7778SPieter Jansen van Vuuren 
12920a6e7778SPieter Jansen van Vuuren 		data = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA];
12930a6e7778SPieter Jansen van Vuuren 		data_len = nla_len(data);
12940a6e7778SPieter Jansen van Vuuren 		if (data_len < 4) {
12950a6e7778SPieter Jansen van Vuuren 			NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is less than 4 bytes long");
12960a6e7778SPieter Jansen van Vuuren 			return -ERANGE;
12970a6e7778SPieter Jansen van Vuuren 		}
12980a6e7778SPieter Jansen van Vuuren 		if (data_len % 4) {
12990a6e7778SPieter Jansen van Vuuren 			NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is not a multiple of 4 bytes long");
13000a6e7778SPieter Jansen van Vuuren 			return -ERANGE;
13010a6e7778SPieter Jansen van Vuuren 		}
13020a6e7778SPieter Jansen van Vuuren 
13030a6e7778SPieter Jansen van Vuuren 		new_len += sizeof(struct geneve_opt) + data_len;
13040a6e7778SPieter Jansen van Vuuren 		BUILD_BUG_ON(FLOW_DIS_TUN_OPTS_MAX != IP_TUNNEL_OPTS_MAX);
13050a6e7778SPieter Jansen van Vuuren 		if (new_len > FLOW_DIS_TUN_OPTS_MAX) {
13060a6e7778SPieter Jansen van Vuuren 			NL_SET_ERR_MSG(extack, "Tunnel options exceeds max size");
13070a6e7778SPieter Jansen van Vuuren 			return -ERANGE;
13080a6e7778SPieter Jansen van Vuuren 		}
13090a6e7778SPieter Jansen van Vuuren 		opt->length = data_len / 4;
13100a6e7778SPieter Jansen van Vuuren 		memcpy(opt->opt_data, nla_data(data), data_len);
13110a6e7778SPieter Jansen van Vuuren 	}
13120a6e7778SPieter Jansen van Vuuren 
13130a6e7778SPieter Jansen van Vuuren 	if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS]) {
13140a6e7778SPieter Jansen van Vuuren 		class = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS];
13150a6e7778SPieter Jansen van Vuuren 		opt->opt_class = nla_get_be16(class);
13160a6e7778SPieter Jansen van Vuuren 	}
13170a6e7778SPieter Jansen van Vuuren 
13180a6e7778SPieter Jansen van Vuuren 	if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE]) {
13190a6e7778SPieter Jansen van Vuuren 		type = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE];
13200a6e7778SPieter Jansen van Vuuren 		opt->type = nla_get_u8(type);
13210a6e7778SPieter Jansen van Vuuren 	}
13220a6e7778SPieter Jansen van Vuuren 
13230a6e7778SPieter Jansen van Vuuren 	return sizeof(struct geneve_opt) + data_len;
13240a6e7778SPieter Jansen van Vuuren }
13250a6e7778SPieter Jansen van Vuuren 
fl_set_vxlan_opt(const struct nlattr * nla,struct fl_flow_key * key,int depth,int option_len,struct netlink_ext_ack * extack)1326d8f9dfaeSXin Long static int fl_set_vxlan_opt(const struct nlattr *nla, struct fl_flow_key *key,
1327d8f9dfaeSXin Long 			    int depth, int option_len,
1328d8f9dfaeSXin Long 			    struct netlink_ext_ack *extack)
1329d8f9dfaeSXin Long {
1330d8f9dfaeSXin Long 	struct nlattr *tb[TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX + 1];
1331d8f9dfaeSXin Long 	struct vxlan_metadata *md;
1332d8f9dfaeSXin Long 	int err;
1333d8f9dfaeSXin Long 
1334d8f9dfaeSXin Long 	md = (struct vxlan_metadata *)&key->enc_opts.data[key->enc_opts.len];
1335d8f9dfaeSXin Long 	memset(md, 0xff, sizeof(*md));
1336d8f9dfaeSXin Long 
1337d8f9dfaeSXin Long 	if (!depth)
1338d8f9dfaeSXin Long 		return sizeof(*md);
1339d8f9dfaeSXin Long 
1340d8f9dfaeSXin Long 	if (nla_type(nla) != TCA_FLOWER_KEY_ENC_OPTS_VXLAN) {
1341d8f9dfaeSXin Long 		NL_SET_ERR_MSG(extack, "Non-vxlan option type for mask");
1342d8f9dfaeSXin Long 		return -EINVAL;
1343d8f9dfaeSXin Long 	}
1344d8f9dfaeSXin Long 
1345d8f9dfaeSXin Long 	err = nla_parse_nested(tb, TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX, nla,
1346d8f9dfaeSXin Long 			       vxlan_opt_policy, extack);
1347d8f9dfaeSXin Long 	if (err < 0)
1348d8f9dfaeSXin Long 		return err;
1349d8f9dfaeSXin Long 
1350d8f9dfaeSXin Long 	if (!option_len && !tb[TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP]) {
1351d8f9dfaeSXin Long 		NL_SET_ERR_MSG(extack, "Missing tunnel key vxlan option gbp");
1352d8f9dfaeSXin Long 		return -EINVAL;
1353d8f9dfaeSXin Long 	}
1354d8f9dfaeSXin Long 
135513e6ce98SXin Long 	if (tb[TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP]) {
1356d8f9dfaeSXin Long 		md->gbp = nla_get_u32(tb[TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP]);
135713e6ce98SXin Long 		md->gbp &= VXLAN_GBP_MASK;
135813e6ce98SXin Long 	}
1359d8f9dfaeSXin Long 
1360d8f9dfaeSXin Long 	return sizeof(*md);
1361d8f9dfaeSXin Long }
1362d8f9dfaeSXin Long 
fl_set_erspan_opt(const struct nlattr * nla,struct fl_flow_key * key,int depth,int option_len,struct netlink_ext_ack * extack)136379b1011cSXin Long static int fl_set_erspan_opt(const struct nlattr *nla, struct fl_flow_key *key,
136479b1011cSXin Long 			     int depth, int option_len,
136579b1011cSXin Long 			     struct netlink_ext_ack *extack)
136679b1011cSXin Long {
136779b1011cSXin Long 	struct nlattr *tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX + 1];
136879b1011cSXin Long 	struct erspan_metadata *md;
136979b1011cSXin Long 	int err;
137079b1011cSXin Long 
137179b1011cSXin Long 	md = (struct erspan_metadata *)&key->enc_opts.data[key->enc_opts.len];
137279b1011cSXin Long 	memset(md, 0xff, sizeof(*md));
137379b1011cSXin Long 	md->version = 1;
137479b1011cSXin Long 
137579b1011cSXin Long 	if (!depth)
137679b1011cSXin Long 		return sizeof(*md);
137779b1011cSXin Long 
137879b1011cSXin Long 	if (nla_type(nla) != TCA_FLOWER_KEY_ENC_OPTS_ERSPAN) {
137979b1011cSXin Long 		NL_SET_ERR_MSG(extack, "Non-erspan option type for mask");
138079b1011cSXin Long 		return -EINVAL;
138179b1011cSXin Long 	}
138279b1011cSXin Long 
138379b1011cSXin Long 	err = nla_parse_nested(tb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX, nla,
138479b1011cSXin Long 			       erspan_opt_policy, extack);
138579b1011cSXin Long 	if (err < 0)
138679b1011cSXin Long 		return err;
138779b1011cSXin Long 
138879b1011cSXin Long 	if (!option_len && !tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER]) {
138979b1011cSXin Long 		NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option ver");
139079b1011cSXin Long 		return -EINVAL;
139179b1011cSXin Long 	}
139279b1011cSXin Long 
139379b1011cSXin Long 	if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER])
139479b1011cSXin Long 		md->version = nla_get_u8(tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER]);
139579b1011cSXin Long 
139679b1011cSXin Long 	if (md->version == 1) {
139779b1011cSXin Long 		if (!option_len && !tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX]) {
139879b1011cSXin Long 			NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option index");
139979b1011cSXin Long 			return -EINVAL;
140079b1011cSXin Long 		}
140179b1011cSXin Long 		if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX]) {
140279b1011cSXin Long 			nla = tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX];
14038e1b3ac4SXin Long 			memset(&md->u, 0x00, sizeof(md->u));
140479b1011cSXin Long 			md->u.index = nla_get_be32(nla);
140579b1011cSXin Long 		}
140679b1011cSXin Long 	} else if (md->version == 2) {
140779b1011cSXin Long 		if (!option_len && (!tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR] ||
140879b1011cSXin Long 				    !tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID])) {
140979b1011cSXin Long 			NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option dir or hwid");
141079b1011cSXin Long 			return -EINVAL;
141179b1011cSXin Long 		}
141279b1011cSXin Long 		if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR]) {
141379b1011cSXin Long 			nla = tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR];
141479b1011cSXin Long 			md->u.md2.dir = nla_get_u8(nla);
141579b1011cSXin Long 		}
141679b1011cSXin Long 		if (tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID]) {
141779b1011cSXin Long 			nla = tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID];
141879b1011cSXin Long 			set_hwid(&md->u.md2, nla_get_u8(nla));
141979b1011cSXin Long 		}
142079b1011cSXin Long 	} else {
142179b1011cSXin Long 		NL_SET_ERR_MSG(extack, "Tunnel key erspan option ver is incorrect");
142279b1011cSXin Long 		return -EINVAL;
142379b1011cSXin Long 	}
142479b1011cSXin Long 
142579b1011cSXin Long 	return sizeof(*md);
142679b1011cSXin Long }
142779b1011cSXin Long 
fl_set_gtp_opt(const struct nlattr * nla,struct fl_flow_key * key,int depth,int option_len,struct netlink_ext_ack * extack)1428e3acda7aSWojciech Drewek static int fl_set_gtp_opt(const struct nlattr *nla, struct fl_flow_key *key,
1429e3acda7aSWojciech Drewek 			  int depth, int option_len,
1430e3acda7aSWojciech Drewek 			  struct netlink_ext_ack *extack)
1431e3acda7aSWojciech Drewek {
1432e3acda7aSWojciech Drewek 	struct nlattr *tb[TCA_FLOWER_KEY_ENC_OPT_GTP_MAX + 1];
1433e3acda7aSWojciech Drewek 	struct gtp_pdu_session_info *sinfo;
1434e3acda7aSWojciech Drewek 	u8 len = key->enc_opts.len;
1435e3acda7aSWojciech Drewek 	int err;
1436e3acda7aSWojciech Drewek 
1437e3acda7aSWojciech Drewek 	sinfo = (struct gtp_pdu_session_info *)&key->enc_opts.data[len];
1438e3acda7aSWojciech Drewek 	memset(sinfo, 0xff, option_len);
1439e3acda7aSWojciech Drewek 
1440e3acda7aSWojciech Drewek 	if (!depth)
1441e3acda7aSWojciech Drewek 		return sizeof(*sinfo);
1442e3acda7aSWojciech Drewek 
1443e3acda7aSWojciech Drewek 	if (nla_type(nla) != TCA_FLOWER_KEY_ENC_OPTS_GTP) {
1444e3acda7aSWojciech Drewek 		NL_SET_ERR_MSG_MOD(extack, "Non-gtp option type for mask");
1445e3acda7aSWojciech Drewek 		return -EINVAL;
1446e3acda7aSWojciech Drewek 	}
1447e3acda7aSWojciech Drewek 
1448e3acda7aSWojciech Drewek 	err = nla_parse_nested(tb, TCA_FLOWER_KEY_ENC_OPT_GTP_MAX, nla,
1449e3acda7aSWojciech Drewek 			       gtp_opt_policy, extack);
1450e3acda7aSWojciech Drewek 	if (err < 0)
1451e3acda7aSWojciech Drewek 		return err;
1452e3acda7aSWojciech Drewek 
1453e3acda7aSWojciech Drewek 	if (!option_len &&
1454e3acda7aSWojciech Drewek 	    (!tb[TCA_FLOWER_KEY_ENC_OPT_GTP_PDU_TYPE] ||
1455e3acda7aSWojciech Drewek 	     !tb[TCA_FLOWER_KEY_ENC_OPT_GTP_QFI])) {
1456e3acda7aSWojciech Drewek 		NL_SET_ERR_MSG_MOD(extack,
1457e3acda7aSWojciech Drewek 				   "Missing tunnel key gtp option pdu type or qfi");
1458e3acda7aSWojciech Drewek 		return -EINVAL;
1459e3acda7aSWojciech Drewek 	}
1460e3acda7aSWojciech Drewek 
1461e3acda7aSWojciech Drewek 	if (tb[TCA_FLOWER_KEY_ENC_OPT_GTP_PDU_TYPE])
1462e3acda7aSWojciech Drewek 		sinfo->pdu_type =
1463e3acda7aSWojciech Drewek 			nla_get_u8(tb[TCA_FLOWER_KEY_ENC_OPT_GTP_PDU_TYPE]);
1464e3acda7aSWojciech Drewek 
1465e3acda7aSWojciech Drewek 	if (tb[TCA_FLOWER_KEY_ENC_OPT_GTP_QFI])
1466e3acda7aSWojciech Drewek 		sinfo->qfi = nla_get_u8(tb[TCA_FLOWER_KEY_ENC_OPT_GTP_QFI]);
1467e3acda7aSWojciech Drewek 
1468e3acda7aSWojciech Drewek 	return sizeof(*sinfo);
1469e3acda7aSWojciech Drewek }
1470e3acda7aSWojciech Drewek 
fl_set_pfcp_opt(const struct nlattr * nla,struct fl_flow_key * key,int depth,int option_len,struct netlink_ext_ack * extack)14716dd514f4SMichal Swiatkowski static int fl_set_pfcp_opt(const struct nlattr *nla, struct fl_flow_key *key,
14726dd514f4SMichal Swiatkowski 			   int depth, int option_len,
14736dd514f4SMichal Swiatkowski 			   struct netlink_ext_ack *extack)
14746dd514f4SMichal Swiatkowski {
14756dd514f4SMichal Swiatkowski 	struct nlattr *tb[TCA_FLOWER_KEY_ENC_OPT_PFCP_MAX + 1];
14766dd514f4SMichal Swiatkowski 	struct pfcp_metadata *md;
14776dd514f4SMichal Swiatkowski 	int err;
14786dd514f4SMichal Swiatkowski 
14796dd514f4SMichal Swiatkowski 	md = (struct pfcp_metadata *)&key->enc_opts.data[key->enc_opts.len];
14806dd514f4SMichal Swiatkowski 	memset(md, 0xff, sizeof(*md));
14816dd514f4SMichal Swiatkowski 
14826dd514f4SMichal Swiatkowski 	if (!depth)
14836dd514f4SMichal Swiatkowski 		return sizeof(*md);
14846dd514f4SMichal Swiatkowski 
14856dd514f4SMichal Swiatkowski 	if (nla_type(nla) != TCA_FLOWER_KEY_ENC_OPTS_PFCP) {
14866dd514f4SMichal Swiatkowski 		NL_SET_ERR_MSG_MOD(extack, "Non-pfcp option type for mask");
14876dd514f4SMichal Swiatkowski 		return -EINVAL;
14886dd514f4SMichal Swiatkowski 	}
14896dd514f4SMichal Swiatkowski 
14906dd514f4SMichal Swiatkowski 	err = nla_parse_nested(tb, TCA_FLOWER_KEY_ENC_OPT_PFCP_MAX, nla,
14916dd514f4SMichal Swiatkowski 			       pfcp_opt_policy, extack);
14926dd514f4SMichal Swiatkowski 	if (err < 0)
14936dd514f4SMichal Swiatkowski 		return err;
14946dd514f4SMichal Swiatkowski 
14956dd514f4SMichal Swiatkowski 	if (!option_len && !tb[TCA_FLOWER_KEY_ENC_OPT_PFCP_TYPE]) {
14966dd514f4SMichal Swiatkowski 		NL_SET_ERR_MSG_MOD(extack, "Missing tunnel key pfcp option type");
14976dd514f4SMichal Swiatkowski 		return -EINVAL;
14986dd514f4SMichal Swiatkowski 	}
14996dd514f4SMichal Swiatkowski 
15006dd514f4SMichal Swiatkowski 	if (tb[TCA_FLOWER_KEY_ENC_OPT_PFCP_TYPE])
15016dd514f4SMichal Swiatkowski 		md->type = nla_get_u8(tb[TCA_FLOWER_KEY_ENC_OPT_PFCP_TYPE]);
15026dd514f4SMichal Swiatkowski 
15036dd514f4SMichal Swiatkowski 	if (tb[TCA_FLOWER_KEY_ENC_OPT_PFCP_SEID])
15046dd514f4SMichal Swiatkowski 		md->seid = nla_get_be64(tb[TCA_FLOWER_KEY_ENC_OPT_PFCP_SEID]);
15056dd514f4SMichal Swiatkowski 
15066dd514f4SMichal Swiatkowski 	return sizeof(*md);
15076dd514f4SMichal Swiatkowski }
15086dd514f4SMichal Swiatkowski 
fl_set_enc_opt(struct nlattr ** tb,struct fl_flow_key * key,struct fl_flow_key * mask,struct netlink_ext_ack * extack)15090a6e7778SPieter Jansen van Vuuren static int fl_set_enc_opt(struct nlattr **tb, struct fl_flow_key *key,
15100a6e7778SPieter Jansen van Vuuren 			  struct fl_flow_key *mask,
15110a6e7778SPieter Jansen van Vuuren 			  struct netlink_ext_ack *extack)
15120a6e7778SPieter Jansen van Vuuren {
15130a6e7778SPieter Jansen van Vuuren 	const struct nlattr *nla_enc_key, *nla_opt_key, *nla_opt_msk = NULL;
151463c82997SJakub Kicinski 	int err, option_len, key_depth, msk_depth = 0;
151563c82997SJakub Kicinski 
15168cb08174SJohannes Berg 	err = nla_validate_nested_deprecated(tb[TCA_FLOWER_KEY_ENC_OPTS],
151763c82997SJakub Kicinski 					     TCA_FLOWER_KEY_ENC_OPTS_MAX,
151863c82997SJakub Kicinski 					     enc_opts_policy, extack);
151963c82997SJakub Kicinski 	if (err)
152063c82997SJakub Kicinski 		return err;
15210a6e7778SPieter Jansen van Vuuren 
15220a6e7778SPieter Jansen van Vuuren 	nla_enc_key = nla_data(tb[TCA_FLOWER_KEY_ENC_OPTS]);
15230a6e7778SPieter Jansen van Vuuren 
15240a6e7778SPieter Jansen van Vuuren 	if (tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]) {
15258cb08174SJohannes Berg 		err = nla_validate_nested_deprecated(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK],
152663c82997SJakub Kicinski 						     TCA_FLOWER_KEY_ENC_OPTS_MAX,
152763c82997SJakub Kicinski 						     enc_opts_policy, extack);
152863c82997SJakub Kicinski 		if (err)
152963c82997SJakub Kicinski 			return err;
153063c82997SJakub Kicinski 
15310a6e7778SPieter Jansen van Vuuren 		nla_opt_msk = nla_data(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]);
15320a6e7778SPieter Jansen van Vuuren 		msk_depth = nla_len(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]);
1533c96adff9SCong Wang 		if (!nla_ok(nla_opt_msk, msk_depth)) {
1534c96adff9SCong Wang 			NL_SET_ERR_MSG(extack, "Invalid nested attribute for masks");
1535c96adff9SCong Wang 			return -EINVAL;
1536c96adff9SCong Wang 		}
15370a6e7778SPieter Jansen van Vuuren 	}
15380a6e7778SPieter Jansen van Vuuren 
15390a6e7778SPieter Jansen van Vuuren 	nla_for_each_attr(nla_opt_key, nla_enc_key,
15400a6e7778SPieter Jansen van Vuuren 			  nla_len(tb[TCA_FLOWER_KEY_ENC_OPTS]), key_depth) {
15410a6e7778SPieter Jansen van Vuuren 		switch (nla_type(nla_opt_key)) {
15420a6e7778SPieter Jansen van Vuuren 		case TCA_FLOWER_KEY_ENC_OPTS_GENEVE:
1543d8f9dfaeSXin Long 			if (key->enc_opts.dst_opt_type &&
15445832c4a7SAlexander Lobakin 			    key->enc_opts.dst_opt_type !=
15455832c4a7SAlexander Lobakin 			    IP_TUNNEL_GENEVE_OPT_BIT) {
1546d8f9dfaeSXin Long 				NL_SET_ERR_MSG(extack, "Duplicate type for geneve options");
1547d8f9dfaeSXin Long 				return -EINVAL;
1548d8f9dfaeSXin Long 			}
15490a6e7778SPieter Jansen van Vuuren 			option_len = 0;
15505832c4a7SAlexander Lobakin 			key->enc_opts.dst_opt_type = IP_TUNNEL_GENEVE_OPT_BIT;
15510a6e7778SPieter Jansen van Vuuren 			option_len = fl_set_geneve_opt(nla_opt_key, key,
15520a6e7778SPieter Jansen van Vuuren 						       key_depth, option_len,
15530a6e7778SPieter Jansen van Vuuren 						       extack);
15540a6e7778SPieter Jansen van Vuuren 			if (option_len < 0)
15550a6e7778SPieter Jansen van Vuuren 				return option_len;
15560a6e7778SPieter Jansen van Vuuren 
15570a6e7778SPieter Jansen van Vuuren 			key->enc_opts.len += option_len;
15580a6e7778SPieter Jansen van Vuuren 			/* At the same time we need to parse through the mask
15590a6e7778SPieter Jansen van Vuuren 			 * in order to verify exact and mask attribute lengths.
15600a6e7778SPieter Jansen van Vuuren 			 */
15615832c4a7SAlexander Lobakin 			mask->enc_opts.dst_opt_type = IP_TUNNEL_GENEVE_OPT_BIT;
15620a6e7778SPieter Jansen van Vuuren 			option_len = fl_set_geneve_opt(nla_opt_msk, mask,
15630a6e7778SPieter Jansen van Vuuren 						       msk_depth, option_len,
15640a6e7778SPieter Jansen van Vuuren 						       extack);
15650a6e7778SPieter Jansen van Vuuren 			if (option_len < 0)
15660a6e7778SPieter Jansen van Vuuren 				return option_len;
15670a6e7778SPieter Jansen van Vuuren 
15680a6e7778SPieter Jansen van Vuuren 			mask->enc_opts.len += option_len;
15690a6e7778SPieter Jansen van Vuuren 			if (key->enc_opts.len != mask->enc_opts.len) {
15700a6e7778SPieter Jansen van Vuuren 				NL_SET_ERR_MSG(extack, "Key and mask miss aligned");
15710a6e7778SPieter Jansen van Vuuren 				return -EINVAL;
15720a6e7778SPieter Jansen van Vuuren 			}
15730a6e7778SPieter Jansen van Vuuren 			break;
1574d8f9dfaeSXin Long 		case TCA_FLOWER_KEY_ENC_OPTS_VXLAN:
1575d8f9dfaeSXin Long 			if (key->enc_opts.dst_opt_type) {
1576d8f9dfaeSXin Long 				NL_SET_ERR_MSG(extack, "Duplicate type for vxlan options");
1577d8f9dfaeSXin Long 				return -EINVAL;
1578d8f9dfaeSXin Long 			}
1579d8f9dfaeSXin Long 			option_len = 0;
15805832c4a7SAlexander Lobakin 			key->enc_opts.dst_opt_type = IP_TUNNEL_VXLAN_OPT_BIT;
1581d8f9dfaeSXin Long 			option_len = fl_set_vxlan_opt(nla_opt_key, key,
1582d8f9dfaeSXin Long 						      key_depth, option_len,
1583d8f9dfaeSXin Long 						      extack);
1584d8f9dfaeSXin Long 			if (option_len < 0)
1585d8f9dfaeSXin Long 				return option_len;
1586d8f9dfaeSXin Long 
1587d8f9dfaeSXin Long 			key->enc_opts.len += option_len;
1588d8f9dfaeSXin Long 			/* At the same time we need to parse through the mask
1589d8f9dfaeSXin Long 			 * in order to verify exact and mask attribute lengths.
1590d8f9dfaeSXin Long 			 */
15915832c4a7SAlexander Lobakin 			mask->enc_opts.dst_opt_type = IP_TUNNEL_VXLAN_OPT_BIT;
1592d8f9dfaeSXin Long 			option_len = fl_set_vxlan_opt(nla_opt_msk, mask,
1593d8f9dfaeSXin Long 						      msk_depth, option_len,
1594d8f9dfaeSXin Long 						      extack);
1595d8f9dfaeSXin Long 			if (option_len < 0)
1596d8f9dfaeSXin Long 				return option_len;
1597d8f9dfaeSXin Long 
1598d8f9dfaeSXin Long 			mask->enc_opts.len += option_len;
1599d8f9dfaeSXin Long 			if (key->enc_opts.len != mask->enc_opts.len) {
1600d8f9dfaeSXin Long 				NL_SET_ERR_MSG(extack, "Key and mask miss aligned");
1601d8f9dfaeSXin Long 				return -EINVAL;
1602d8f9dfaeSXin Long 			}
1603d8f9dfaeSXin Long 			break;
160479b1011cSXin Long 		case TCA_FLOWER_KEY_ENC_OPTS_ERSPAN:
160579b1011cSXin Long 			if (key->enc_opts.dst_opt_type) {
160679b1011cSXin Long 				NL_SET_ERR_MSG(extack, "Duplicate type for erspan options");
160779b1011cSXin Long 				return -EINVAL;
160879b1011cSXin Long 			}
160979b1011cSXin Long 			option_len = 0;
16105832c4a7SAlexander Lobakin 			key->enc_opts.dst_opt_type = IP_TUNNEL_ERSPAN_OPT_BIT;
161179b1011cSXin Long 			option_len = fl_set_erspan_opt(nla_opt_key, key,
161279b1011cSXin Long 						       key_depth, option_len,
161379b1011cSXin Long 						       extack);
161479b1011cSXin Long 			if (option_len < 0)
161579b1011cSXin Long 				return option_len;
161679b1011cSXin Long 
161779b1011cSXin Long 			key->enc_opts.len += option_len;
161879b1011cSXin Long 			/* At the same time we need to parse through the mask
161979b1011cSXin Long 			 * in order to verify exact and mask attribute lengths.
162079b1011cSXin Long 			 */
16215832c4a7SAlexander Lobakin 			mask->enc_opts.dst_opt_type = IP_TUNNEL_ERSPAN_OPT_BIT;
162279b1011cSXin Long 			option_len = fl_set_erspan_opt(nla_opt_msk, mask,
162379b1011cSXin Long 						       msk_depth, option_len,
162479b1011cSXin Long 						       extack);
162579b1011cSXin Long 			if (option_len < 0)
162679b1011cSXin Long 				return option_len;
162779b1011cSXin Long 
162879b1011cSXin Long 			mask->enc_opts.len += option_len;
162979b1011cSXin Long 			if (key->enc_opts.len != mask->enc_opts.len) {
163079b1011cSXin Long 				NL_SET_ERR_MSG(extack, "Key and mask miss aligned");
163179b1011cSXin Long 				return -EINVAL;
163279b1011cSXin Long 			}
163379b1011cSXin Long 			break;
1634e3acda7aSWojciech Drewek 		case TCA_FLOWER_KEY_ENC_OPTS_GTP:
1635e3acda7aSWojciech Drewek 			if (key->enc_opts.dst_opt_type) {
1636e3acda7aSWojciech Drewek 				NL_SET_ERR_MSG_MOD(extack,
1637e3acda7aSWojciech Drewek 						   "Duplicate type for gtp options");
1638e3acda7aSWojciech Drewek 				return -EINVAL;
1639e3acda7aSWojciech Drewek 			}
1640e3acda7aSWojciech Drewek 			option_len = 0;
16415832c4a7SAlexander Lobakin 			key->enc_opts.dst_opt_type = IP_TUNNEL_GTP_OPT_BIT;
1642e3acda7aSWojciech Drewek 			option_len = fl_set_gtp_opt(nla_opt_key, key,
1643e3acda7aSWojciech Drewek 						    key_depth, option_len,
1644e3acda7aSWojciech Drewek 						    extack);
1645e3acda7aSWojciech Drewek 			if (option_len < 0)
1646e3acda7aSWojciech Drewek 				return option_len;
1647e3acda7aSWojciech Drewek 
1648e3acda7aSWojciech Drewek 			key->enc_opts.len += option_len;
1649e3acda7aSWojciech Drewek 			/* At the same time we need to parse through the mask
1650e3acda7aSWojciech Drewek 			 * in order to verify exact and mask attribute lengths.
1651e3acda7aSWojciech Drewek 			 */
16525832c4a7SAlexander Lobakin 			mask->enc_opts.dst_opt_type = IP_TUNNEL_GTP_OPT_BIT;
1653e3acda7aSWojciech Drewek 			option_len = fl_set_gtp_opt(nla_opt_msk, mask,
1654e3acda7aSWojciech Drewek 						    msk_depth, option_len,
1655e3acda7aSWojciech Drewek 						    extack);
1656e3acda7aSWojciech Drewek 			if (option_len < 0)
1657e3acda7aSWojciech Drewek 				return option_len;
1658e3acda7aSWojciech Drewek 
1659e3acda7aSWojciech Drewek 			mask->enc_opts.len += option_len;
1660e3acda7aSWojciech Drewek 			if (key->enc_opts.len != mask->enc_opts.len) {
1661e3acda7aSWojciech Drewek 				NL_SET_ERR_MSG_MOD(extack,
1662e3acda7aSWojciech Drewek 						   "Key and mask miss aligned");
1663e3acda7aSWojciech Drewek 				return -EINVAL;
1664e3acda7aSWojciech Drewek 			}
1665e3acda7aSWojciech Drewek 			break;
16666dd514f4SMichal Swiatkowski 		case TCA_FLOWER_KEY_ENC_OPTS_PFCP:
16676dd514f4SMichal Swiatkowski 			if (key->enc_opts.dst_opt_type) {
16686dd514f4SMichal Swiatkowski 				NL_SET_ERR_MSG_MOD(extack, "Duplicate type for pfcp options");
16696dd514f4SMichal Swiatkowski 				return -EINVAL;
16706dd514f4SMichal Swiatkowski 			}
16716dd514f4SMichal Swiatkowski 			option_len = 0;
16726dd514f4SMichal Swiatkowski 			key->enc_opts.dst_opt_type = IP_TUNNEL_PFCP_OPT_BIT;
16736dd514f4SMichal Swiatkowski 			option_len = fl_set_pfcp_opt(nla_opt_key, key,
16746dd514f4SMichal Swiatkowski 						     key_depth, option_len,
16756dd514f4SMichal Swiatkowski 						     extack);
16766dd514f4SMichal Swiatkowski 			if (option_len < 0)
16776dd514f4SMichal Swiatkowski 				return option_len;
16786dd514f4SMichal Swiatkowski 
16796dd514f4SMichal Swiatkowski 			key->enc_opts.len += option_len;
16806dd514f4SMichal Swiatkowski 			/* At the same time we need to parse through the mask
16816dd514f4SMichal Swiatkowski 			 * in order to verify exact and mask attribute lengths.
16826dd514f4SMichal Swiatkowski 			 */
16836dd514f4SMichal Swiatkowski 			mask->enc_opts.dst_opt_type = IP_TUNNEL_PFCP_OPT_BIT;
16846dd514f4SMichal Swiatkowski 			option_len = fl_set_pfcp_opt(nla_opt_msk, mask,
16856dd514f4SMichal Swiatkowski 						     msk_depth, option_len,
16866dd514f4SMichal Swiatkowski 						     extack);
16876dd514f4SMichal Swiatkowski 			if (option_len < 0)
16886dd514f4SMichal Swiatkowski 				return option_len;
16896dd514f4SMichal Swiatkowski 
16906dd514f4SMichal Swiatkowski 			mask->enc_opts.len += option_len;
16916dd514f4SMichal Swiatkowski 			if (key->enc_opts.len != mask->enc_opts.len) {
16926dd514f4SMichal Swiatkowski 				NL_SET_ERR_MSG_MOD(extack, "Key and mask miss aligned");
16936dd514f4SMichal Swiatkowski 				return -EINVAL;
16946dd514f4SMichal Swiatkowski 			}
16956dd514f4SMichal Swiatkowski 			break;
16960a6e7778SPieter Jansen van Vuuren 		default:
16970a6e7778SPieter Jansen van Vuuren 			NL_SET_ERR_MSG(extack, "Unknown tunnel option type");
16980a6e7778SPieter Jansen van Vuuren 			return -EINVAL;
16990a6e7778SPieter Jansen van Vuuren 		}
1700c96adff9SCong Wang 
1701c96adff9SCong Wang 		if (!msk_depth)
1702c96adff9SCong Wang 			continue;
1703c96adff9SCong Wang 
1704c96adff9SCong Wang 		if (!nla_ok(nla_opt_msk, msk_depth)) {
1705c96adff9SCong Wang 			NL_SET_ERR_MSG(extack, "A mask attribute is invalid");
1706c96adff9SCong Wang 			return -EINVAL;
1707c96adff9SCong Wang 		}
1708c96adff9SCong Wang 		nla_opt_msk = nla_next(nla_opt_msk, &msk_depth);
17090a6e7778SPieter Jansen van Vuuren 	}
17100a6e7778SPieter Jansen van Vuuren 
17110a6e7778SPieter Jansen van Vuuren 	return 0;
17120a6e7778SPieter Jansen van Vuuren }
17130a6e7778SPieter Jansen van Vuuren 
fl_validate_ct_state(u16 state,struct nlattr * tb,struct netlink_ext_ack * extack)17141bcc51acSwenxu static int fl_validate_ct_state(u16 state, struct nlattr *tb,
17151bcc51acSwenxu 				struct netlink_ext_ack *extack)
17161bcc51acSwenxu {
17171bcc51acSwenxu 	if (state && !(state & TCA_FLOWER_KEY_CT_FLAGS_TRACKED)) {
17181bcc51acSwenxu 		NL_SET_ERR_MSG_ATTR(extack, tb,
17191bcc51acSwenxu 				    "no trk, so no other flag can be set");
17201bcc51acSwenxu 		return -EINVAL;
17211bcc51acSwenxu 	}
17221bcc51acSwenxu 
17231bcc51acSwenxu 	if (state & TCA_FLOWER_KEY_CT_FLAGS_NEW &&
17241bcc51acSwenxu 	    state & TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED) {
17251bcc51acSwenxu 		NL_SET_ERR_MSG_ATTR(extack, tb,
17261bcc51acSwenxu 				    "new and est are mutually exclusive");
17271bcc51acSwenxu 		return -EINVAL;
17281bcc51acSwenxu 	}
17291bcc51acSwenxu 
17303aed8b63Swenxu 	if (state & TCA_FLOWER_KEY_CT_FLAGS_INVALID &&
17313aed8b63Swenxu 	    state & ~(TCA_FLOWER_KEY_CT_FLAGS_TRACKED |
17323aed8b63Swenxu 		      TCA_FLOWER_KEY_CT_FLAGS_INVALID)) {
17333aed8b63Swenxu 		NL_SET_ERR_MSG_ATTR(extack, tb,
17343aed8b63Swenxu 				    "when inv is set, only trk may be set");
17353aed8b63Swenxu 		return -EINVAL;
17363aed8b63Swenxu 	}
17373aed8b63Swenxu 
17383aed8b63Swenxu 	if (state & TCA_FLOWER_KEY_CT_FLAGS_NEW &&
17393aed8b63Swenxu 	    state & TCA_FLOWER_KEY_CT_FLAGS_REPLY) {
17403aed8b63Swenxu 		NL_SET_ERR_MSG_ATTR(extack, tb,
17413aed8b63Swenxu 				    "new and rpl are mutually exclusive");
17423aed8b63Swenxu 		return -EINVAL;
17433aed8b63Swenxu 	}
17443aed8b63Swenxu 
17451bcc51acSwenxu 	return 0;
17461bcc51acSwenxu }
17471bcc51acSwenxu 
fl_set_key_ct(struct nlattr ** tb,struct flow_dissector_key_ct * key,struct flow_dissector_key_ct * mask,struct netlink_ext_ack * extack)1748e0ace68aSPaul Blakey static int fl_set_key_ct(struct nlattr **tb,
1749e0ace68aSPaul Blakey 			 struct flow_dissector_key_ct *key,
1750e0ace68aSPaul Blakey 			 struct flow_dissector_key_ct *mask,
1751e0ace68aSPaul Blakey 			 struct netlink_ext_ack *extack)
1752e0ace68aSPaul Blakey {
1753e0ace68aSPaul Blakey 	if (tb[TCA_FLOWER_KEY_CT_STATE]) {
17541bcc51acSwenxu 		int err;
17551bcc51acSwenxu 
1756e0ace68aSPaul Blakey 		if (!IS_ENABLED(CONFIG_NF_CONNTRACK)) {
1757e0ace68aSPaul Blakey 			NL_SET_ERR_MSG(extack, "Conntrack isn't enabled");
1758e0ace68aSPaul Blakey 			return -EOPNOTSUPP;
1759e0ace68aSPaul Blakey 		}
1760e0ace68aSPaul Blakey 		fl_set_key_val(tb, &key->ct_state, TCA_FLOWER_KEY_CT_STATE,
1761e0ace68aSPaul Blakey 			       &mask->ct_state, TCA_FLOWER_KEY_CT_STATE_MASK,
1762e0ace68aSPaul Blakey 			       sizeof(key->ct_state));
17631bcc51acSwenxu 
1764afa536d8Swenxu 		err = fl_validate_ct_state(key->ct_state & mask->ct_state,
17651bcc51acSwenxu 					   tb[TCA_FLOWER_KEY_CT_STATE_MASK],
17661bcc51acSwenxu 					   extack);
17671bcc51acSwenxu 		if (err)
17681bcc51acSwenxu 			return err;
17691bcc51acSwenxu 
1770e0ace68aSPaul Blakey 	}
1771e0ace68aSPaul Blakey 	if (tb[TCA_FLOWER_KEY_CT_ZONE]) {
1772e0ace68aSPaul Blakey 		if (!IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES)) {
1773e0ace68aSPaul Blakey 			NL_SET_ERR_MSG(extack, "Conntrack zones isn't enabled");
1774e0ace68aSPaul Blakey 			return -EOPNOTSUPP;
1775e0ace68aSPaul Blakey 		}
1776e0ace68aSPaul Blakey 		fl_set_key_val(tb, &key->ct_zone, TCA_FLOWER_KEY_CT_ZONE,
1777e0ace68aSPaul Blakey 			       &mask->ct_zone, TCA_FLOWER_KEY_CT_ZONE_MASK,
1778e0ace68aSPaul Blakey 			       sizeof(key->ct_zone));
1779e0ace68aSPaul Blakey 	}
1780e0ace68aSPaul Blakey 	if (tb[TCA_FLOWER_KEY_CT_MARK]) {
1781e0ace68aSPaul Blakey 		if (!IS_ENABLED(CONFIG_NF_CONNTRACK_MARK)) {
1782e0ace68aSPaul Blakey 			NL_SET_ERR_MSG(extack, "Conntrack mark isn't enabled");
1783e0ace68aSPaul Blakey 			return -EOPNOTSUPP;
1784e0ace68aSPaul Blakey 		}
1785e0ace68aSPaul Blakey 		fl_set_key_val(tb, &key->ct_mark, TCA_FLOWER_KEY_CT_MARK,
1786e0ace68aSPaul Blakey 			       &mask->ct_mark, TCA_FLOWER_KEY_CT_MARK_MASK,
1787e0ace68aSPaul Blakey 			       sizeof(key->ct_mark));
1788e0ace68aSPaul Blakey 	}
1789e0ace68aSPaul Blakey 	if (tb[TCA_FLOWER_KEY_CT_LABELS]) {
1790e0ace68aSPaul Blakey 		if (!IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS)) {
1791e0ace68aSPaul Blakey 			NL_SET_ERR_MSG(extack, "Conntrack labels aren't enabled");
1792e0ace68aSPaul Blakey 			return -EOPNOTSUPP;
1793e0ace68aSPaul Blakey 		}
1794e0ace68aSPaul Blakey 		fl_set_key_val(tb, key->ct_labels, TCA_FLOWER_KEY_CT_LABELS,
1795e0ace68aSPaul Blakey 			       mask->ct_labels, TCA_FLOWER_KEY_CT_LABELS_MASK,
1796e0ace68aSPaul Blakey 			       sizeof(key->ct_labels));
1797e0ace68aSPaul Blakey 	}
1798e0ace68aSPaul Blakey 
1799e0ace68aSPaul Blakey 	return 0;
1800e0ace68aSPaul Blakey }
1801e0ace68aSPaul Blakey 
is_vlan_key(struct nlattr * tb,__be16 * ethertype,struct fl_flow_key * key,struct fl_flow_key * mask,int vthresh)1802285ba06bSBoris Sukholitko static bool is_vlan_key(struct nlattr *tb, __be16 *ethertype,
180399fdb22bSBoris Sukholitko 			struct fl_flow_key *key, struct fl_flow_key *mask,
180499fdb22bSBoris Sukholitko 			int vthresh)
1805285ba06bSBoris Sukholitko {
180699fdb22bSBoris Sukholitko 	const bool good_num_of_vlans = key->num_of_vlans.num_of_vlans > vthresh;
180799fdb22bSBoris Sukholitko 
180899fdb22bSBoris Sukholitko 	if (!tb) {
180999fdb22bSBoris Sukholitko 		*ethertype = 0;
181099fdb22bSBoris Sukholitko 		return good_num_of_vlans;
181199fdb22bSBoris Sukholitko 	}
1812285ba06bSBoris Sukholitko 
1813285ba06bSBoris Sukholitko 	*ethertype = nla_get_be16(tb);
181499fdb22bSBoris Sukholitko 	if (good_num_of_vlans || eth_type_vlan(*ethertype))
1815285ba06bSBoris Sukholitko 		return true;
1816285ba06bSBoris Sukholitko 
1817285ba06bSBoris Sukholitko 	key->basic.n_proto = *ethertype;
1818285ba06bSBoris Sukholitko 	mask->basic.n_proto = cpu_to_be16(~0);
1819285ba06bSBoris Sukholitko 	return false;
1820285ba06bSBoris Sukholitko }
1821285ba06bSBoris Sukholitko 
fl_set_key_cfm_md_level(struct nlattr ** tb,struct fl_flow_key * key,struct fl_flow_key * mask,struct netlink_ext_ack * extack)18227cfffd5fSZahari Doychev static void fl_set_key_cfm_md_level(struct nlattr **tb,
18237cfffd5fSZahari Doychev 				    struct fl_flow_key *key,
18247cfffd5fSZahari Doychev 				    struct fl_flow_key *mask,
18257cfffd5fSZahari Doychev 				    struct netlink_ext_ack *extack)
18267cfffd5fSZahari Doychev {
18277cfffd5fSZahari Doychev 	u8 level;
18287cfffd5fSZahari Doychev 
18297cfffd5fSZahari Doychev 	if (!tb[TCA_FLOWER_KEY_CFM_MD_LEVEL])
18307cfffd5fSZahari Doychev 		return;
18317cfffd5fSZahari Doychev 
18327cfffd5fSZahari Doychev 	level = nla_get_u8(tb[TCA_FLOWER_KEY_CFM_MD_LEVEL]);
18337cfffd5fSZahari Doychev 	key->cfm.mdl_ver = FIELD_PREP(FLOW_DIS_CFM_MDL_MASK, level);
18347cfffd5fSZahari Doychev 	mask->cfm.mdl_ver = FLOW_DIS_CFM_MDL_MASK;
18357cfffd5fSZahari Doychev }
18367cfffd5fSZahari Doychev 
fl_set_key_cfm_opcode(struct nlattr ** tb,struct fl_flow_key * key,struct fl_flow_key * mask,struct netlink_ext_ack * extack)18377cfffd5fSZahari Doychev static void fl_set_key_cfm_opcode(struct nlattr **tb,
18387cfffd5fSZahari Doychev 				  struct fl_flow_key *key,
18397cfffd5fSZahari Doychev 				  struct fl_flow_key *mask,
18407cfffd5fSZahari Doychev 				  struct netlink_ext_ack *extack)
18417cfffd5fSZahari Doychev {
18427cfffd5fSZahari Doychev 	fl_set_key_val(tb, &key->cfm.opcode, TCA_FLOWER_KEY_CFM_OPCODE,
18437cfffd5fSZahari Doychev 		       &mask->cfm.opcode, TCA_FLOWER_UNSPEC,
18447cfffd5fSZahari Doychev 		       sizeof(key->cfm.opcode));
18457cfffd5fSZahari Doychev }
18467cfffd5fSZahari Doychev 
fl_set_key_cfm(struct nlattr ** tb,struct fl_flow_key * key,struct fl_flow_key * mask,struct netlink_ext_ack * extack)18477cfffd5fSZahari Doychev static int fl_set_key_cfm(struct nlattr **tb,
18487cfffd5fSZahari Doychev 			  struct fl_flow_key *key,
18497cfffd5fSZahari Doychev 			  struct fl_flow_key *mask,
18507cfffd5fSZahari Doychev 			  struct netlink_ext_ack *extack)
18517cfffd5fSZahari Doychev {
18524d50e500SEric Dumazet 	struct nlattr *nla_cfm_opt[TCA_FLOWER_KEY_CFM_OPT_MAX + 1];
18537cfffd5fSZahari Doychev 	int err;
18547cfffd5fSZahari Doychev 
18557cfffd5fSZahari Doychev 	if (!tb[TCA_FLOWER_KEY_CFM])
18567cfffd5fSZahari Doychev 		return 0;
18577cfffd5fSZahari Doychev 
18587cfffd5fSZahari Doychev 	err = nla_parse_nested(nla_cfm_opt, TCA_FLOWER_KEY_CFM_OPT_MAX,
18597cfffd5fSZahari Doychev 			       tb[TCA_FLOWER_KEY_CFM], cfm_opt_policy, extack);
18607cfffd5fSZahari Doychev 	if (err < 0)
18617cfffd5fSZahari Doychev 		return err;
18627cfffd5fSZahari Doychev 
18637cfffd5fSZahari Doychev 	fl_set_key_cfm_opcode(nla_cfm_opt, key, mask, extack);
18647cfffd5fSZahari Doychev 	fl_set_key_cfm_md_level(nla_cfm_opt, key, mask, extack);
18657cfffd5fSZahari Doychev 
18667cfffd5fSZahari Doychev 	return 0;
18677cfffd5fSZahari Doychev }
18687cfffd5fSZahari Doychev 
fl_set_key(struct net * net,struct nlattr * tca_opts,struct nlattr ** tb,struct fl_flow_key * key,struct fl_flow_key * mask,struct netlink_ext_ack * extack)1869*536b97acSAsbjørn Sloth Tønnesen static int fl_set_key(struct net *net, struct nlattr *tca_opts,
1870*536b97acSAsbjørn Sloth Tønnesen 		      struct nlattr **tb, struct fl_flow_key *key,
1871*536b97acSAsbjørn Sloth Tønnesen 		      struct fl_flow_key *mask, struct netlink_ext_ack *extack)
187277b9900eSJiri Pirko {
18739399ae9aSHadar Hen Zion 	__be16 ethertype;
1874d9724772SOr Gerlitz 	int ret = 0;
1875a5148626SJiri Pirko 
187677b9900eSJiri Pirko 	if (tb[TCA_FLOWER_INDEV]) {
18771057c55fSAlexander Aring 		int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV], extack);
187877b9900eSJiri Pirko 		if (err < 0)
187977b9900eSJiri Pirko 			return err;
18808212ed77SJiri Pirko 		key->meta.ingress_ifindex = err;
18818212ed77SJiri Pirko 		mask->meta.ingress_ifindex = 0xffffffff;
188277b9900eSJiri Pirko 	}
188377b9900eSJiri Pirko 
18841a432018SIdo Schimmel 	fl_set_key_val(tb, &key->meta.l2_miss, TCA_FLOWER_L2_MISS,
18851a432018SIdo Schimmel 		       &mask->meta.l2_miss, TCA_FLOWER_UNSPEC,
18861a432018SIdo Schimmel 		       sizeof(key->meta.l2_miss));
18871a432018SIdo Schimmel 
188877b9900eSJiri Pirko 	fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
188977b9900eSJiri Pirko 		       mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
189077b9900eSJiri Pirko 		       sizeof(key->eth.dst));
189177b9900eSJiri Pirko 	fl_set_key_val(tb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
189277b9900eSJiri Pirko 		       mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
189377b9900eSJiri Pirko 		       sizeof(key->eth.src));
1894b4000312SBoris Sukholitko 	fl_set_key_val(tb, &key->num_of_vlans,
1895b4000312SBoris Sukholitko 		       TCA_FLOWER_KEY_NUM_OF_VLANS,
1896b4000312SBoris Sukholitko 		       &mask->num_of_vlans,
1897b4000312SBoris Sukholitko 		       TCA_FLOWER_UNSPEC,
1898b4000312SBoris Sukholitko 		       sizeof(key->num_of_vlans));
189966530bdfSJamal Hadi Salim 
190099fdb22bSBoris Sukholitko 	if (is_vlan_key(tb[TCA_FLOWER_KEY_ETH_TYPE], &ethertype, key, mask, 0)) {
1901d64efd09SJianbo Liu 		fl_set_key_vlan(tb, ethertype, TCA_FLOWER_KEY_VLAN_ID,
19022105f700SVlad Buslov 				TCA_FLOWER_KEY_VLAN_PRIO,
19032105f700SVlad Buslov 				TCA_FLOWER_KEY_VLAN_ETH_TYPE,
19042105f700SVlad Buslov 				&key->vlan, &mask->vlan);
1905d64efd09SJianbo Liu 
190699fdb22bSBoris Sukholitko 		if (is_vlan_key(tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE],
190799fdb22bSBoris Sukholitko 				&ethertype, key, mask, 1)) {
1908d64efd09SJianbo Liu 			fl_set_key_vlan(tb, ethertype,
1909d64efd09SJianbo Liu 					TCA_FLOWER_KEY_CVLAN_ID,
1910d64efd09SJianbo Liu 					TCA_FLOWER_KEY_CVLAN_PRIO,
19112105f700SVlad Buslov 					TCA_FLOWER_KEY_CVLAN_ETH_TYPE,
1912d64efd09SJianbo Liu 					&key->cvlan, &mask->cvlan);
19139399ae9aSHadar Hen Zion 			fl_set_key_val(tb, &key->basic.n_proto,
1914d64efd09SJianbo Liu 				       TCA_FLOWER_KEY_CVLAN_ETH_TYPE,
1915d64efd09SJianbo Liu 				       &mask->basic.n_proto,
1916d64efd09SJianbo Liu 				       TCA_FLOWER_UNSPEC,
191777b9900eSJiri Pirko 				       sizeof(key->basic.n_proto));
1918d64efd09SJianbo Liu 		}
19190b498a52SArnd Bergmann 	}
192066530bdfSJamal Hadi Salim 
19215008750eSWojciech Drewek 	if (key->basic.n_proto == htons(ETH_P_PPP_SES))
19225008750eSWojciech Drewek 		fl_set_key_pppoe(tb, &key->pppoe, &mask->pppoe, key, mask);
19235008750eSWojciech Drewek 
192477b9900eSJiri Pirko 	if (key->basic.n_proto == htons(ETH_P_IP) ||
192577b9900eSJiri Pirko 	    key->basic.n_proto == htons(ETH_P_IPV6)) {
192677b9900eSJiri Pirko 		fl_set_key_val(tb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
192777b9900eSJiri Pirko 			       &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
192877b9900eSJiri Pirko 			       sizeof(key->basic.ip_proto));
19290e2c17b6SOr Gerlitz 		fl_set_key_ip(tb, false, &key->ip, &mask->ip);
193077b9900eSJiri Pirko 	}
193166530bdfSJamal Hadi Salim 
193266530bdfSJamal Hadi Salim 	if (tb[TCA_FLOWER_KEY_IPV4_SRC] || tb[TCA_FLOWER_KEY_IPV4_DST]) {
193366530bdfSJamal Hadi Salim 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
1934970bfcd0SPaul Blakey 		mask->control.addr_type = ~0;
193577b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
193677b9900eSJiri Pirko 			       &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
193777b9900eSJiri Pirko 			       sizeof(key->ipv4.src));
193877b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
193977b9900eSJiri Pirko 			       &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
194077b9900eSJiri Pirko 			       sizeof(key->ipv4.dst));
194166530bdfSJamal Hadi Salim 	} else if (tb[TCA_FLOWER_KEY_IPV6_SRC] || tb[TCA_FLOWER_KEY_IPV6_DST]) {
194266530bdfSJamal Hadi Salim 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
1943970bfcd0SPaul Blakey 		mask->control.addr_type = ~0;
194477b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
194577b9900eSJiri Pirko 			       &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
194677b9900eSJiri Pirko 			       sizeof(key->ipv6.src));
194777b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
194877b9900eSJiri Pirko 			       &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
194977b9900eSJiri Pirko 			       sizeof(key->ipv6.dst));
195077b9900eSJiri Pirko 	}
195166530bdfSJamal Hadi Salim 
195277b9900eSJiri Pirko 	if (key->basic.ip_proto == IPPROTO_TCP) {
195377b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
1954aa72d708SOr Gerlitz 			       &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
195577b9900eSJiri Pirko 			       sizeof(key->tp.src));
195677b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
1957aa72d708SOr Gerlitz 			       &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
195877b9900eSJiri Pirko 			       sizeof(key->tp.dst));
1959fdfc7dd6SJiri Pirko 		fl_set_key_val(tb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS,
1960fdfc7dd6SJiri Pirko 			       &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK,
1961fdfc7dd6SJiri Pirko 			       sizeof(key->tcp.flags));
196277b9900eSJiri Pirko 	} else if (key->basic.ip_proto == IPPROTO_UDP) {
196377b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
1964aa72d708SOr Gerlitz 			       &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
196577b9900eSJiri Pirko 			       sizeof(key->tp.src));
196677b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
1967aa72d708SOr Gerlitz 			       &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
196877b9900eSJiri Pirko 			       sizeof(key->tp.dst));
19695976c5f4SSimon Horman 	} else if (key->basic.ip_proto == IPPROTO_SCTP) {
19705976c5f4SSimon Horman 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
19715976c5f4SSimon Horman 			       &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
19725976c5f4SSimon Horman 			       sizeof(key->tp.src));
19735976c5f4SSimon Horman 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
19745976c5f4SSimon Horman 			       &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
19755976c5f4SSimon Horman 			       sizeof(key->tp.dst));
19767b684884SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_IP) &&
19777b684884SSimon Horman 		   key->basic.ip_proto == IPPROTO_ICMP) {
19787b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV4_TYPE,
19797b684884SSimon Horman 			       &mask->icmp.type,
19807b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,
19817b684884SSimon Horman 			       sizeof(key->icmp.type));
19827b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE,
19837b684884SSimon Horman 			       &mask->icmp.code,
19847b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
19857b684884SSimon Horman 			       sizeof(key->icmp.code));
19867b684884SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_IPV6) &&
19877b684884SSimon Horman 		   key->basic.ip_proto == IPPROTO_ICMPV6) {
19887b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV6_TYPE,
19897b684884SSimon Horman 			       &mask->icmp.type,
19907b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
19917b684884SSimon Horman 			       sizeof(key->icmp.type));
1992040587afSSimon Horman 		fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV6_CODE,
19937b684884SSimon Horman 			       &mask->icmp.code,
1994040587afSSimon Horman 			       TCA_FLOWER_KEY_ICMPV6_CODE_MASK,
19957b684884SSimon Horman 			       sizeof(key->icmp.code));
1996a577d8f7SBenjamin LaHaise 	} else if (key->basic.n_proto == htons(ETH_P_MPLS_UC) ||
1997a577d8f7SBenjamin LaHaise 		   key->basic.n_proto == htons(ETH_P_MPLS_MC)) {
1998442f730eSGuillaume Nault 		ret = fl_set_key_mpls(tb, &key->mpls, &mask->mpls, extack);
19991a7fca63SBenjamin LaHaise 		if (ret)
20001a7fca63SBenjamin LaHaise 			return ret;
200199d31326SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_ARP) ||
200299d31326SSimon Horman 		   key->basic.n_proto == htons(ETH_P_RARP)) {
200399d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.sip, TCA_FLOWER_KEY_ARP_SIP,
200499d31326SSimon Horman 			       &mask->arp.sip, TCA_FLOWER_KEY_ARP_SIP_MASK,
200599d31326SSimon Horman 			       sizeof(key->arp.sip));
200699d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.tip, TCA_FLOWER_KEY_ARP_TIP,
200799d31326SSimon Horman 			       &mask->arp.tip, TCA_FLOWER_KEY_ARP_TIP_MASK,
200899d31326SSimon Horman 			       sizeof(key->arp.tip));
200999d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.op, TCA_FLOWER_KEY_ARP_OP,
201099d31326SSimon Horman 			       &mask->arp.op, TCA_FLOWER_KEY_ARP_OP_MASK,
201199d31326SSimon Horman 			       sizeof(key->arp.op));
201299d31326SSimon Horman 		fl_set_key_val(tb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA,
201399d31326SSimon Horman 			       mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK,
201499d31326SSimon Horman 			       sizeof(key->arp.sha));
201599d31326SSimon Horman 		fl_set_key_val(tb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA,
201699d31326SSimon Horman 			       mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK,
201799d31326SSimon Horman 			       sizeof(key->arp.tha));
20188b189ea0SWojciech Drewek 	} else if (key->basic.ip_proto == IPPROTO_L2TP) {
20198b189ea0SWojciech Drewek 		fl_set_key_val(tb, &key->l2tpv3.session_id,
20208b189ea0SWojciech Drewek 			       TCA_FLOWER_KEY_L2TPV3_SID,
20218b189ea0SWojciech Drewek 			       &mask->l2tpv3.session_id, TCA_FLOWER_UNSPEC,
20228b189ea0SWojciech Drewek 			       sizeof(key->l2tpv3.session_id));
20237cfffd5fSZahari Doychev 	} else if (key->basic.n_proto  == htons(ETH_P_CFM)) {
20247cfffd5fSZahari Doychev 		ret = fl_set_key_cfm(tb, key, mask, extack);
20257cfffd5fSZahari Doychev 		if (ret)
20267cfffd5fSZahari Doychev 			return ret;
202777b9900eSJiri Pirko 	}
202877b9900eSJiri Pirko 
20295c72299fSAmritha Nambiar 	if (key->basic.ip_proto == IPPROTO_TCP ||
20305c72299fSAmritha Nambiar 	    key->basic.ip_proto == IPPROTO_UDP ||
20315c72299fSAmritha Nambiar 	    key->basic.ip_proto == IPPROTO_SCTP) {
2032bd7d4c12SGuillaume Nault 		ret = fl_set_key_port_range(tb, key, mask, extack);
20335c72299fSAmritha Nambiar 		if (ret)
20345c72299fSAmritha Nambiar 			return ret;
20355c72299fSAmritha Nambiar 	}
20365c72299fSAmritha Nambiar 
20374c13eda7SRatheesh Kannoth 	if (tb[TCA_FLOWER_KEY_SPI]) {
20384c13eda7SRatheesh Kannoth 		ret = fl_set_key_spi(tb, key, mask, extack);
20394c13eda7SRatheesh Kannoth 		if (ret)
20404c13eda7SRatheesh Kannoth 			return ret;
20414c13eda7SRatheesh Kannoth 	}
20424c13eda7SRatheesh Kannoth 
2043bc3103f1SAmir Vadai 	if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] ||
2044bc3103f1SAmir Vadai 	    tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) {
2045bc3103f1SAmir Vadai 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
2046970bfcd0SPaul Blakey 		mask->enc_control.addr_type = ~0;
2047bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv4.src,
2048bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_SRC,
2049bc3103f1SAmir Vadai 			       &mask->enc_ipv4.src,
2050bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
2051bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv4.src));
2052bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv4.dst,
2053bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_DST,
2054bc3103f1SAmir Vadai 			       &mask->enc_ipv4.dst,
2055bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
2056bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv4.dst));
2057bc3103f1SAmir Vadai 	}
2058bc3103f1SAmir Vadai 
2059bc3103f1SAmir Vadai 	if (tb[TCA_FLOWER_KEY_ENC_IPV6_SRC] ||
2060bc3103f1SAmir Vadai 	    tb[TCA_FLOWER_KEY_ENC_IPV6_DST]) {
2061bc3103f1SAmir Vadai 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2062970bfcd0SPaul Blakey 		mask->enc_control.addr_type = ~0;
2063bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv6.src,
2064bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_SRC,
2065bc3103f1SAmir Vadai 			       &mask->enc_ipv6.src,
2066bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
2067bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv6.src));
2068bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv6.dst,
2069bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_DST,
2070bc3103f1SAmir Vadai 			       &mask->enc_ipv6.dst,
2071bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
2072bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv6.dst));
2073bc3103f1SAmir Vadai 	}
2074bc3103f1SAmir Vadai 
2075bc3103f1SAmir Vadai 	fl_set_key_val(tb, &key->enc_key_id.keyid, TCA_FLOWER_KEY_ENC_KEY_ID,
2076eb523f42SHadar Hen Zion 		       &mask->enc_key_id.keyid, TCA_FLOWER_UNSPEC,
2077bc3103f1SAmir Vadai 		       sizeof(key->enc_key_id.keyid));
2078bc3103f1SAmir Vadai 
2079f4d997fdSHadar Hen Zion 	fl_set_key_val(tb, &key->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
2080f4d997fdSHadar Hen Zion 		       &mask->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
2081f4d997fdSHadar Hen Zion 		       sizeof(key->enc_tp.src));
2082f4d997fdSHadar Hen Zion 
2083f4d997fdSHadar Hen Zion 	fl_set_key_val(tb, &key->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
2084f4d997fdSHadar Hen Zion 		       &mask->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
2085f4d997fdSHadar Hen Zion 		       sizeof(key->enc_tp.dst));
2086f4d997fdSHadar Hen Zion 
20870e2c17b6SOr Gerlitz 	fl_set_key_ip(tb, true, &key->enc_ip, &mask->enc_ip);
20880e2c17b6SOr Gerlitz 
20895923b8f7SAriel Levkovich 	fl_set_key_val(tb, &key->hash.hash, TCA_FLOWER_KEY_HASH,
20905923b8f7SAriel Levkovich 		       &mask->hash.hash, TCA_FLOWER_KEY_HASH_MASK,
20915923b8f7SAriel Levkovich 		       sizeof(key->hash.hash));
20925923b8f7SAriel Levkovich 
20930a6e7778SPieter Jansen van Vuuren 	if (tb[TCA_FLOWER_KEY_ENC_OPTS]) {
20940a6e7778SPieter Jansen van Vuuren 		ret = fl_set_enc_opt(tb, key, mask, extack);
20950a6e7778SPieter Jansen van Vuuren 		if (ret)
20960a6e7778SPieter Jansen van Vuuren 			return ret;
20970a6e7778SPieter Jansen van Vuuren 	}
20980a6e7778SPieter Jansen van Vuuren 
2099e0ace68aSPaul Blakey 	ret = fl_set_key_ct(tb, &key->ct, &mask->ct, extack);
2100e0ace68aSPaul Blakey 	if (ret)
2101e0ace68aSPaul Blakey 		return ret;
2102e0ace68aSPaul Blakey 
21031d17568eSDavide Caratti 	if (tb[TCA_FLOWER_KEY_FLAGS]) {
2104*536b97acSAsbjørn Sloth Tønnesen 		ret = fl_set_key_flags(tca_opts, tb, false,
2105*536b97acSAsbjørn Sloth Tønnesen 				       &key->control.flags,
2106e304e21aSGuillaume Nault 				       &mask->control.flags, extack);
21071d17568eSDavide Caratti 		if (ret)
21081d17568eSDavide Caratti 			return ret;
21091d17568eSDavide Caratti 	}
21101d17568eSDavide Caratti 
21111d17568eSDavide Caratti 	if (tb[TCA_FLOWER_KEY_ENC_FLAGS])
2112*536b97acSAsbjørn Sloth Tønnesen 		ret = fl_set_key_flags(tca_opts, tb, true,
2113*536b97acSAsbjørn Sloth Tønnesen 				       &key->enc_control.flags,
211411036bd7SAsbjørn Sloth Tønnesen 				       &mask->enc_control.flags, extack);
2115faa3ffceSOr Gerlitz 
2116d9724772SOr Gerlitz 	return ret;
211777b9900eSJiri Pirko }
211877b9900eSJiri Pirko 
fl_mask_copy(struct fl_flow_mask * dst,struct fl_flow_mask * src)211905cd271fSPaul Blakey static void fl_mask_copy(struct fl_flow_mask *dst,
212005cd271fSPaul Blakey 			 struct fl_flow_mask *src)
212177b9900eSJiri Pirko {
212205cd271fSPaul Blakey 	const void *psrc = fl_key_get_start(&src->key, src);
212305cd271fSPaul Blakey 	void *pdst = fl_key_get_start(&dst->key, src);
212477b9900eSJiri Pirko 
212505cd271fSPaul Blakey 	memcpy(pdst, psrc, fl_mask_range(src));
212605cd271fSPaul Blakey 	dst->range = src->range;
212777b9900eSJiri Pirko }
212877b9900eSJiri Pirko 
212977b9900eSJiri Pirko static const struct rhashtable_params fl_ht_params = {
213077b9900eSJiri Pirko 	.key_offset = offsetof(struct cls_fl_filter, mkey), /* base offset */
213177b9900eSJiri Pirko 	.head_offset = offsetof(struct cls_fl_filter, ht_node),
213277b9900eSJiri Pirko 	.automatic_shrinking = true,
213377b9900eSJiri Pirko };
213477b9900eSJiri Pirko 
fl_init_mask_hashtable(struct fl_flow_mask * mask)213505cd271fSPaul Blakey static int fl_init_mask_hashtable(struct fl_flow_mask *mask)
213677b9900eSJiri Pirko {
213705cd271fSPaul Blakey 	mask->filter_ht_params = fl_ht_params;
213805cd271fSPaul Blakey 	mask->filter_ht_params.key_len = fl_mask_range(mask);
213905cd271fSPaul Blakey 	mask->filter_ht_params.key_offset += mask->range.start;
214077b9900eSJiri Pirko 
214105cd271fSPaul Blakey 	return rhashtable_init(&mask->ht, &mask->filter_ht_params);
214277b9900eSJiri Pirko }
214377b9900eSJiri Pirko 
214477b9900eSJiri Pirko #define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member)
2145c593642cSPankaj Bharadiya #define FL_KEY_MEMBER_SIZE(member) sizeof_field(struct fl_flow_key, member)
214677b9900eSJiri Pirko 
2147339ba878SHadar Hen Zion #define FL_KEY_IS_MASKED(mask, member)						\
2148339ba878SHadar Hen Zion 	memchr_inv(((char *)mask) + FL_KEY_MEMBER_OFFSET(member),		\
2149339ba878SHadar Hen Zion 		   0, FL_KEY_MEMBER_SIZE(member))				\
215077b9900eSJiri Pirko 
215177b9900eSJiri Pirko #define FL_KEY_SET(keys, cnt, id, member)					\
215277b9900eSJiri Pirko 	do {									\
215377b9900eSJiri Pirko 		keys[cnt].key_id = id;						\
215477b9900eSJiri Pirko 		keys[cnt].offset = FL_KEY_MEMBER_OFFSET(member);		\
215577b9900eSJiri Pirko 		cnt++;								\
215677b9900eSJiri Pirko 	} while(0);
215777b9900eSJiri Pirko 
2158339ba878SHadar Hen Zion #define FL_KEY_SET_IF_MASKED(mask, keys, cnt, id, member)			\
215977b9900eSJiri Pirko 	do {									\
2160339ba878SHadar Hen Zion 		if (FL_KEY_IS_MASKED(mask, member))				\
216177b9900eSJiri Pirko 			FL_KEY_SET(keys, cnt, id, member);			\
216277b9900eSJiri Pirko 	} while(0);
216377b9900eSJiri Pirko 
fl_init_dissector(struct flow_dissector * dissector,struct fl_flow_key * mask)216433fb5cbaSJiri Pirko static void fl_init_dissector(struct flow_dissector *dissector,
216533fb5cbaSJiri Pirko 			      struct fl_flow_key *mask)
216677b9900eSJiri Pirko {
216777b9900eSJiri Pirko 	struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX];
216877b9900eSJiri Pirko 	size_t cnt = 0;
216977b9900eSJiri Pirko 
21708212ed77SJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
21718212ed77SJiri Pirko 			     FLOW_DISSECTOR_KEY_META, meta);
217242aecaa9STom Herbert 	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control);
217377b9900eSJiri Pirko 	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic);
217433fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
217577b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_ETH_ADDRS, eth);
217633fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
217777b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4);
217833fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
217977b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6);
21808ffb055bSYoshiki Komachi 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
21818ffb055bSYoshiki Komachi 			     FLOW_DISSECTOR_KEY_PORTS, tp);
21828ffb055bSYoshiki Komachi 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
21838ffb055bSYoshiki Komachi 			     FLOW_DISSECTOR_KEY_PORTS_RANGE, tp_range);
218433fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
21854d80cc0aSOr Gerlitz 			     FLOW_DISSECTOR_KEY_IP, ip);
218633fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
2187fdfc7dd6SJiri Pirko 			     FLOW_DISSECTOR_KEY_TCP, tcp);
218833fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
21897b684884SSimon Horman 			     FLOW_DISSECTOR_KEY_ICMP, icmp);
219033fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
219199d31326SSimon Horman 			     FLOW_DISSECTOR_KEY_ARP, arp);
219233fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
2193a577d8f7SBenjamin LaHaise 			     FLOW_DISSECTOR_KEY_MPLS, mpls);
219433fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
21959399ae9aSHadar Hen Zion 			     FLOW_DISSECTOR_KEY_VLAN, vlan);
219633fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
2197d64efd09SJianbo Liu 			     FLOW_DISSECTOR_KEY_CVLAN, cvlan);
219833fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
2199519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_KEYID, enc_key_id);
220033fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
2201519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, enc_ipv4);
220233fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
2203519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, enc_ipv6);
220433fb5cbaSJiri Pirko 	if (FL_KEY_IS_MASKED(mask, enc_ipv4) ||
2205706bf4f4SAsbjørn Sloth Tønnesen 	    FL_KEY_IS_MASKED(mask, enc_ipv6) ||
2206706bf4f4SAsbjørn Sloth Tønnesen 	    FL_KEY_IS_MASKED(mask, enc_control))
2207519d1052SHadar Hen Zion 		FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_ENC_CONTROL,
2208519d1052SHadar Hen Zion 			   enc_control);
220933fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
2210f4d997fdSHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp);
221133fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
22120e2c17b6SOr Gerlitz 			     FLOW_DISSECTOR_KEY_ENC_IP, enc_ip);
22130a6e7778SPieter Jansen van Vuuren 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
22140a6e7778SPieter Jansen van Vuuren 			     FLOW_DISSECTOR_KEY_ENC_OPTS, enc_opts);
2215e0ace68aSPaul Blakey 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
2216e0ace68aSPaul Blakey 			     FLOW_DISSECTOR_KEY_CT, ct);
22175923b8f7SAriel Levkovich 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
22185923b8f7SAriel Levkovich 			     FLOW_DISSECTOR_KEY_HASH, hash);
2219b4000312SBoris Sukholitko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
2220b4000312SBoris Sukholitko 			     FLOW_DISSECTOR_KEY_NUM_OF_VLANS, num_of_vlans);
22215008750eSWojciech Drewek 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
22225008750eSWojciech Drewek 			     FLOW_DISSECTOR_KEY_PPPOE, pppoe);
22238b189ea0SWojciech Drewek 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
22248b189ea0SWojciech Drewek 			     FLOW_DISSECTOR_KEY_L2TPV3, l2tpv3);
22257cfffd5fSZahari Doychev 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
22264c13eda7SRatheesh Kannoth 			     FLOW_DISSECTOR_KEY_IPSEC, ipsec);
22274c13eda7SRatheesh Kannoth 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
22287cfffd5fSZahari Doychev 			     FLOW_DISSECTOR_KEY_CFM, cfm);
222977b9900eSJiri Pirko 
223033fb5cbaSJiri Pirko 	skb_flow_dissector_init(dissector, keys, cnt);
223105cd271fSPaul Blakey }
223205cd271fSPaul Blakey 
fl_create_new_mask(struct cls_fl_head * head,struct fl_flow_mask * mask)223305cd271fSPaul Blakey static struct fl_flow_mask *fl_create_new_mask(struct cls_fl_head *head,
223405cd271fSPaul Blakey 					       struct fl_flow_mask *mask)
223505cd271fSPaul Blakey {
223605cd271fSPaul Blakey 	struct fl_flow_mask *newmask;
223705cd271fSPaul Blakey 	int err;
223805cd271fSPaul Blakey 
223905cd271fSPaul Blakey 	newmask = kzalloc(sizeof(*newmask), GFP_KERNEL);
224005cd271fSPaul Blakey 	if (!newmask)
224105cd271fSPaul Blakey 		return ERR_PTR(-ENOMEM);
224205cd271fSPaul Blakey 
224305cd271fSPaul Blakey 	fl_mask_copy(newmask, mask);
224405cd271fSPaul Blakey 
22458ffb055bSYoshiki Komachi 	if ((newmask->key.tp_range.tp_min.dst &&
22468ffb055bSYoshiki Komachi 	     newmask->key.tp_range.tp_max.dst) ||
22478ffb055bSYoshiki Komachi 	    (newmask->key.tp_range.tp_min.src &&
22488ffb055bSYoshiki Komachi 	     newmask->key.tp_range.tp_max.src))
22495c72299fSAmritha Nambiar 		newmask->flags |= TCA_FLOWER_MASK_FLAGS_RANGE;
22505c72299fSAmritha Nambiar 
225105cd271fSPaul Blakey 	err = fl_init_mask_hashtable(newmask);
225205cd271fSPaul Blakey 	if (err)
225305cd271fSPaul Blakey 		goto errout_free;
225405cd271fSPaul Blakey 
225533fb5cbaSJiri Pirko 	fl_init_dissector(&newmask->dissector, &newmask->key);
225605cd271fSPaul Blakey 
225705cd271fSPaul Blakey 	INIT_LIST_HEAD_RCU(&newmask->filters);
225805cd271fSPaul Blakey 
2259f48ef4d5SVlad Buslov 	refcount_set(&newmask->refcnt, 1);
2260195c234dSVlad Buslov 	err = rhashtable_replace_fast(&head->ht, &mask->ht_node,
2261195c234dSVlad Buslov 				      &newmask->ht_node, mask_ht_params);
226205cd271fSPaul Blakey 	if (err)
226305cd271fSPaul Blakey 		goto errout_destroy;
226405cd271fSPaul Blakey 
2265259e60f9SVlad Buslov 	spin_lock(&head->masks_lock);
226605cd271fSPaul Blakey 	list_add_tail_rcu(&newmask->list, &head->masks);
2267259e60f9SVlad Buslov 	spin_unlock(&head->masks_lock);
226805cd271fSPaul Blakey 
226905cd271fSPaul Blakey 	return newmask;
227005cd271fSPaul Blakey 
227105cd271fSPaul Blakey errout_destroy:
227205cd271fSPaul Blakey 	rhashtable_destroy(&newmask->ht);
227305cd271fSPaul Blakey errout_free:
227405cd271fSPaul Blakey 	kfree(newmask);
227505cd271fSPaul Blakey 
227605cd271fSPaul Blakey 	return ERR_PTR(err);
227777b9900eSJiri Pirko }
227877b9900eSJiri Pirko 
fl_check_assign_mask(struct cls_fl_head * head,struct cls_fl_filter * fnew,struct cls_fl_filter * fold,struct fl_flow_mask * mask)227977b9900eSJiri Pirko static int fl_check_assign_mask(struct cls_fl_head *head,
228005cd271fSPaul Blakey 				struct cls_fl_filter *fnew,
228105cd271fSPaul Blakey 				struct cls_fl_filter *fold,
228277b9900eSJiri Pirko 				struct fl_flow_mask *mask)
228377b9900eSJiri Pirko {
228405cd271fSPaul Blakey 	struct fl_flow_mask *newmask;
2285f48ef4d5SVlad Buslov 	int ret = 0;
228677b9900eSJiri Pirko 
2287f48ef4d5SVlad Buslov 	rcu_read_lock();
2288195c234dSVlad Buslov 
2289195c234dSVlad Buslov 	/* Insert mask as temporary node to prevent concurrent creation of mask
2290195c234dSVlad Buslov 	 * with same key. Any concurrent lookups with same key will return
229199815f50SVlad Buslov 	 * -EAGAIN because mask's refcnt is zero.
2292195c234dSVlad Buslov 	 */
2293195c234dSVlad Buslov 	fnew->mask = rhashtable_lookup_get_insert_fast(&head->ht,
2294195c234dSVlad Buslov 						       &mask->ht_node,
2295195c234dSVlad Buslov 						       mask_ht_params);
229605cd271fSPaul Blakey 	if (!fnew->mask) {
2297f48ef4d5SVlad Buslov 		rcu_read_unlock();
2298f48ef4d5SVlad Buslov 
2299195c234dSVlad Buslov 		if (fold) {
2300195c234dSVlad Buslov 			ret = -EINVAL;
2301195c234dSVlad Buslov 			goto errout_cleanup;
2302195c234dSVlad Buslov 		}
230305cd271fSPaul Blakey 
230405cd271fSPaul Blakey 		newmask = fl_create_new_mask(head, mask);
2305195c234dSVlad Buslov 		if (IS_ERR(newmask)) {
2306195c234dSVlad Buslov 			ret = PTR_ERR(newmask);
2307195c234dSVlad Buslov 			goto errout_cleanup;
2308195c234dSVlad Buslov 		}
230905cd271fSPaul Blakey 
231005cd271fSPaul Blakey 		fnew->mask = newmask;
231177b9900eSJiri Pirko 		return 0;
2312195c234dSVlad Buslov 	} else if (IS_ERR(fnew->mask)) {
2313195c234dSVlad Buslov 		ret = PTR_ERR(fnew->mask);
2314f48ef4d5SVlad Buslov 	} else if (fold && fold->mask != fnew->mask) {
2315f48ef4d5SVlad Buslov 		ret = -EINVAL;
2316f48ef4d5SVlad Buslov 	} else if (!refcount_inc_not_zero(&fnew->mask->refcnt)) {
2317f48ef4d5SVlad Buslov 		/* Mask was deleted concurrently, try again */
2318f48ef4d5SVlad Buslov 		ret = -EAGAIN;
2319f48ef4d5SVlad Buslov 	}
2320f48ef4d5SVlad Buslov 	rcu_read_unlock();
2321f48ef4d5SVlad Buslov 	return ret;
2322195c234dSVlad Buslov 
2323195c234dSVlad Buslov errout_cleanup:
2324195c234dSVlad Buslov 	rhashtable_remove_fast(&head->ht, &mask->ht_node,
2325195c234dSVlad Buslov 			       mask_ht_params);
2326195c234dSVlad Buslov 	return ret;
232777b9900eSJiri Pirko }
232877b9900eSJiri Pirko 
fl_needs_tc_skb_ext(const struct fl_flow_key * mask)23291a432018SIdo Schimmel static bool fl_needs_tc_skb_ext(const struct fl_flow_key *mask)
23301a432018SIdo Schimmel {
23311a432018SIdo Schimmel 	return mask->meta.l2_miss;
23321a432018SIdo Schimmel }
23331a432018SIdo Schimmel 
fl_ht_insert_unique(struct cls_fl_filter * fnew,struct cls_fl_filter * fold,bool * in_ht)23341f17f774SVlad Buslov static int fl_ht_insert_unique(struct cls_fl_filter *fnew,
23351f17f774SVlad Buslov 			       struct cls_fl_filter *fold,
23361f17f774SVlad Buslov 			       bool *in_ht)
23371f17f774SVlad Buslov {
23381f17f774SVlad Buslov 	struct fl_flow_mask *mask = fnew->mask;
23391f17f774SVlad Buslov 	int err;
23401f17f774SVlad Buslov 
23419e35552aSVlad Buslov 	err = rhashtable_lookup_insert_fast(&mask->ht,
23421f17f774SVlad Buslov 					    &fnew->ht_node,
23431f17f774SVlad Buslov 					    mask->filter_ht_params);
23441f17f774SVlad Buslov 	if (err) {
23451f17f774SVlad Buslov 		*in_ht = false;
23461f17f774SVlad Buslov 		/* It is okay if filter with same key exists when
23471f17f774SVlad Buslov 		 * overwriting.
23481f17f774SVlad Buslov 		 */
23491f17f774SVlad Buslov 		return fold && err == -EEXIST ? 0 : err;
23501f17f774SVlad Buslov 	}
23511f17f774SVlad Buslov 
23521f17f774SVlad Buslov 	*in_ht = true;
23531f17f774SVlad Buslov 	return 0;
23541f17f774SVlad Buslov }
23551f17f774SVlad Buslov 
fl_change(struct net * net,struct sk_buff * in_skb,struct tcf_proto * tp,unsigned long base,u32 handle,struct nlattr ** tca,void ** arg,u32 flags,struct netlink_ext_ack * extack)235677b9900eSJiri Pirko static int fl_change(struct net *net, struct sk_buff *in_skb,
235777b9900eSJiri Pirko 		     struct tcf_proto *tp, unsigned long base,
235877b9900eSJiri Pirko 		     u32 handle, struct nlattr **tca,
2359695176bfSCong Wang 		     void **arg, u32 flags,
236012db03b6SVlad Buslov 		     struct netlink_ext_ack *extack)
236177b9900eSJiri Pirko {
2362e474619aSVlad Buslov 	struct cls_fl_head *head = fl_head_dereference(tp);
2363695176bfSCong Wang 	bool rtnl_held = !(flags & TCA_ACT_FLAGS_NO_RTNL);
2364*536b97acSAsbjørn Sloth Tønnesen 	struct nlattr *tca_opts = tca[TCA_OPTIONS];
23658113c095SWANG Cong 	struct cls_fl_filter *fold = *arg;
2366ac177a33SVictor Nogueira 	bool bound_to_filter = false;
236777b9900eSJiri Pirko 	struct cls_fl_filter *fnew;
23682cddd201SIvan Vecera 	struct fl_flow_mask *mask;
236939b7b6a6SArnd Bergmann 	struct nlattr **tb;
23701f17f774SVlad Buslov 	bool in_ht;
237177b9900eSJiri Pirko 	int err;
237277b9900eSJiri Pirko 
2373*536b97acSAsbjørn Sloth Tønnesen 	if (!tca_opts) {
237406177558SVlad Buslov 		err = -EINVAL;
237506177558SVlad Buslov 		goto errout_fold;
237606177558SVlad Buslov 	}
237777b9900eSJiri Pirko 
23782cddd201SIvan Vecera 	mask = kzalloc(sizeof(struct fl_flow_mask), GFP_KERNEL);
237906177558SVlad Buslov 	if (!mask) {
238006177558SVlad Buslov 		err = -ENOBUFS;
238106177558SVlad Buslov 		goto errout_fold;
238206177558SVlad Buslov 	}
238339b7b6a6SArnd Bergmann 
23842cddd201SIvan Vecera 	tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL);
23852cddd201SIvan Vecera 	if (!tb) {
23862cddd201SIvan Vecera 		err = -ENOBUFS;
23872cddd201SIvan Vecera 		goto errout_mask_alloc;
23882cddd201SIvan Vecera 	}
23892cddd201SIvan Vecera 
23908cb08174SJohannes Berg 	err = nla_parse_nested_deprecated(tb, TCA_FLOWER_MAX,
2391*536b97acSAsbjørn Sloth Tønnesen 					  tca_opts, fl_policy, NULL);
239277b9900eSJiri Pirko 	if (err < 0)
239339b7b6a6SArnd Bergmann 		goto errout_tb;
239477b9900eSJiri Pirko 
239539b7b6a6SArnd Bergmann 	if (fold && handle && fold->handle != handle) {
239639b7b6a6SArnd Bergmann 		err = -EINVAL;
239739b7b6a6SArnd Bergmann 		goto errout_tb;
239839b7b6a6SArnd Bergmann 	}
239977b9900eSJiri Pirko 
240077b9900eSJiri Pirko 	fnew = kzalloc(sizeof(*fnew), GFP_KERNEL);
240139b7b6a6SArnd Bergmann 	if (!fnew) {
240239b7b6a6SArnd Bergmann 		err = -ENOBUFS;
240339b7b6a6SArnd Bergmann 		goto errout_tb;
240439b7b6a6SArnd Bergmann 	}
2405c049d56eSVlad Buslov 	INIT_LIST_HEAD(&fnew->hw_list);
240606177558SVlad Buslov 	refcount_set(&fnew->refcnt, 1);
240777b9900eSJiri Pirko 
2408ecb3dea4SVlad Buslov 	if (tb[TCA_FLOWER_FLAGS]) {
2409ecb3dea4SVlad Buslov 		fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
2410ecb3dea4SVlad Buslov 
2411ecb3dea4SVlad Buslov 		if (!tc_flags_valid(fnew->flags)) {
2412dfd2f0ebSEric Dumazet 			kfree(fnew);
2413ecb3dea4SVlad Buslov 			err = -EINVAL;
2414dfd2f0ebSEric Dumazet 			goto errout_tb;
2415ecb3dea4SVlad Buslov 		}
2416ecb3dea4SVlad Buslov 	}
2417ecb3dea4SVlad Buslov 
241808a0063dSPaul Blakey 	if (!fold) {
241908a0063dSPaul Blakey 		spin_lock(&tp->lock);
242008a0063dSPaul Blakey 		if (!handle) {
242108a0063dSPaul Blakey 			handle = 1;
2422dd4f6bbfSVlad Buslov 			err = idr_alloc_u32(&head->handle_idr, NULL, &handle,
242308a0063dSPaul Blakey 					    INT_MAX, GFP_ATOMIC);
242408a0063dSPaul Blakey 		} else {
2425dd4f6bbfSVlad Buslov 			err = idr_alloc_u32(&head->handle_idr, NULL, &handle,
242608a0063dSPaul Blakey 					    handle, GFP_ATOMIC);
242708a0063dSPaul Blakey 
242808a0063dSPaul Blakey 			/* Filter with specified handle was concurrently
242908a0063dSPaul Blakey 			 * inserted after initial check in cls_api. This is not
243008a0063dSPaul Blakey 			 * necessarily an error if NLM_F_EXCL is not set in
243108a0063dSPaul Blakey 			 * message flags. Returning EAGAIN will cause cls_api to
243208a0063dSPaul Blakey 			 * try to update concurrently inserted rule.
243308a0063dSPaul Blakey 			 */
243408a0063dSPaul Blakey 			if (err == -ENOSPC)
243508a0063dSPaul Blakey 				err = -EAGAIN;
243608a0063dSPaul Blakey 		}
243708a0063dSPaul Blakey 		spin_unlock(&tp->lock);
243808a0063dSPaul Blakey 
2439dfd2f0ebSEric Dumazet 		if (err) {
2440dfd2f0ebSEric Dumazet 			kfree(fnew);
2441dfd2f0ebSEric Dumazet 			goto errout_tb;
2442dfd2f0ebSEric Dumazet 		}
244332eff6baSIvan Vecera 	}
24445110f3ffSVlad Buslov 	fnew->handle = handle;
244508a0063dSPaul Blakey 
2446606c7c43SPaul Blakey 	err = tcf_exts_init_ex(&fnew->exts, net, TCA_FLOWER_ACT, 0, tp, handle,
2447606c7c43SPaul Blakey 			       !tc_skip_hw(fnew->flags));
244808a0063dSPaul Blakey 	if (err < 0)
244908a0063dSPaul Blakey 		goto errout_idr;
245008a0063dSPaul Blakey 
2451ac177a33SVictor Nogueira 	err = tcf_exts_validate_ex(net, tp, tb, tca[TCA_RATE],
2452ac177a33SVictor Nogueira 				   &fnew->exts, flags, fnew->flags,
2453c86e0209SBaowen Zheng 				   extack);
2454ac177a33SVictor Nogueira 	if (err < 0)
245508a0063dSPaul Blakey 		goto errout_idr;
2456ecb3dea4SVlad Buslov 
2457ac177a33SVictor Nogueira 	if (tb[TCA_FLOWER_CLASSID]) {
2458ac177a33SVictor Nogueira 		fnew->res.classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]);
2459ac177a33SVictor Nogueira 		if (flags & TCA_ACT_FLAGS_NO_RTNL)
2460ac177a33SVictor Nogueira 			rtnl_lock();
2461ac177a33SVictor Nogueira 		tcf_bind_filter(tp, &fnew->res, base);
2462ac177a33SVictor Nogueira 		if (flags & TCA_ACT_FLAGS_NO_RTNL)
2463ac177a33SVictor Nogueira 			rtnl_unlock();
2464ac177a33SVictor Nogueira 		bound_to_filter = true;
2465ac177a33SVictor Nogueira 	}
2466ac177a33SVictor Nogueira 
2467*536b97acSAsbjørn Sloth Tønnesen 	err = fl_set_key(net, tca_opts, tb, &fnew->key, &mask->key, extack);
2468ac177a33SVictor Nogueira 	if (err)
2469ac177a33SVictor Nogueira 		goto unbind_filter;
2470ac177a33SVictor Nogueira 
2471ac177a33SVictor Nogueira 	fl_mask_update_range(mask);
2472ac177a33SVictor Nogueira 	fl_set_masked_key(&fnew->mkey, &fnew->key, mask);
2473ac177a33SVictor Nogueira 
2474ac177a33SVictor Nogueira 	if (!fl_mask_fits_tmplt(tp->chain->tmplt_priv, mask)) {
2475ac177a33SVictor Nogueira 		NL_SET_ERR_MSG_MOD(extack, "Mask does not fit the template");
2476ac177a33SVictor Nogueira 		err = -EINVAL;
2477ac177a33SVictor Nogueira 		goto unbind_filter;
2478ac177a33SVictor Nogueira 	}
2479ac177a33SVictor Nogueira 
2480ac177a33SVictor Nogueira 	/* Enable tc skb extension if filter matches on data extracted from
2481ac177a33SVictor Nogueira 	 * this extension.
2482ac177a33SVictor Nogueira 	 */
2483ac177a33SVictor Nogueira 	if (fl_needs_tc_skb_ext(&mask->key)) {
2484ac177a33SVictor Nogueira 		fnew->needs_tc_skb_ext = 1;
2485ac177a33SVictor Nogueira 		tc_skb_ext_tc_enable();
2486ac177a33SVictor Nogueira 	}
2487ac177a33SVictor Nogueira 
2488ecb3dea4SVlad Buslov 	err = fl_check_assign_mask(head, fnew, fold, mask);
2489ecb3dea4SVlad Buslov 	if (err)
2490ac177a33SVictor Nogueira 		goto unbind_filter;
2491ecb3dea4SVlad Buslov 
24921f17f774SVlad Buslov 	err = fl_ht_insert_unique(fnew, fold, &in_ht);
24931f17f774SVlad Buslov 	if (err)
24941f17f774SVlad Buslov 		goto errout_mask;
24951f17f774SVlad Buslov 
249679685219SHadar Hen Zion 	if (!tc_skip_hw(fnew->flags)) {
2497c24e43d8SVlad Buslov 		err = fl_hw_replace_filter(tp, fnew, rtnl_held, extack);
2498e8eb36cdSAmir Vadai 		if (err)
24991f17f774SVlad Buslov 			goto errout_ht;
250079685219SHadar Hen Zion 	}
25015b33f488SAmir Vadai 
250255593960SOr Gerlitz 	if (!tc_in_hw(fnew->flags))
250355593960SOr Gerlitz 		fnew->flags |= TCA_CLS_FLAGS_NOT_IN_HW;
250455593960SOr Gerlitz 
25053d81e711SVlad Buslov 	spin_lock(&tp->lock);
25063d81e711SVlad Buslov 
2507272ffaadSVlad Buslov 	/* tp was deleted concurrently. -EAGAIN will cause caller to lookup
2508272ffaadSVlad Buslov 	 * proto again or create new one, if necessary.
2509272ffaadSVlad Buslov 	 */
2510272ffaadSVlad Buslov 	if (tp->deleting) {
2511272ffaadSVlad Buslov 		err = -EAGAIN;
2512272ffaadSVlad Buslov 		goto errout_hw;
2513272ffaadSVlad Buslov 	}
2514272ffaadSVlad Buslov 
25155b33f488SAmir Vadai 	if (fold) {
2516b2552b8cSVlad Buslov 		/* Fold filter was deleted concurrently. Retry lookup. */
2517b2552b8cSVlad Buslov 		if (fold->deleted) {
2518b2552b8cSVlad Buslov 			err = -EAGAIN;
2519b2552b8cSVlad Buslov 			goto errout_hw;
2520b2552b8cSVlad Buslov 		}
2521b2552b8cSVlad Buslov 
2522620da486SVlad Buslov 		fnew->handle = handle;
2523620da486SVlad Buslov 
25241f17f774SVlad Buslov 		if (!in_ht) {
25251f17f774SVlad Buslov 			struct rhashtable_params params =
25261f17f774SVlad Buslov 				fnew->mask->filter_ht_params;
25271f17f774SVlad Buslov 
25281f17f774SVlad Buslov 			err = rhashtable_insert_fast(&fnew->mask->ht,
25291f17f774SVlad Buslov 						     &fnew->ht_node,
25301f17f774SVlad Buslov 						     params);
2531620da486SVlad Buslov 			if (err)
2532620da486SVlad Buslov 				goto errout_hw;
25331f17f774SVlad Buslov 			in_ht = true;
25341f17f774SVlad Buslov 		}
2535620da486SVlad Buslov 
2536c049d56eSVlad Buslov 		refcount_inc(&fnew->refcnt);
253705cd271fSPaul Blakey 		rhashtable_remove_fast(&fold->mask->ht,
253805cd271fSPaul Blakey 				       &fold->ht_node,
253905cd271fSPaul Blakey 				       fold->mask->filter_ht_params);
2540234a4624SMatthew Wilcox 		idr_replace(&head->handle_idr, fnew, fnew->handle);
2541ff3532f2SDaniel Borkmann 		list_replace_rcu(&fold->list, &fnew->list);
2542b2552b8cSVlad Buslov 		fold->deleted = true;
2543620da486SVlad Buslov 
25443d81e711SVlad Buslov 		spin_unlock(&tp->lock);
25453d81e711SVlad Buslov 
25469994677cSVlad Buslov 		fl_mask_put(head, fold->mask);
2547620da486SVlad Buslov 		if (!tc_skip_hw(fold->flags))
2548c24e43d8SVlad Buslov 			fl_hw_destroy_filter(tp, fold, rtnl_held, NULL);
254977b9900eSJiri Pirko 		tcf_unbind_filter(tp, &fold->res);
255006177558SVlad Buslov 		/* Caller holds reference to fold, so refcnt is always > 0
255106177558SVlad Buslov 		 * after this.
255206177558SVlad Buslov 		 */
255306177558SVlad Buslov 		refcount_dec(&fold->refcnt);
255406177558SVlad Buslov 		__fl_put(fold);
255577b9900eSJiri Pirko 	} else {
255608a0063dSPaul Blakey 		idr_replace(&head->handle_idr, fnew, fnew->handle);
2557620da486SVlad Buslov 
2558c049d56eSVlad Buslov 		refcount_inc(&fnew->refcnt);
255905cd271fSPaul Blakey 		list_add_tail_rcu(&fnew->list, &fnew->mask->filters);
25603d81e711SVlad Buslov 		spin_unlock(&tp->lock);
256177b9900eSJiri Pirko 	}
256277b9900eSJiri Pirko 
2563620da486SVlad Buslov 	*arg = fnew;
2564620da486SVlad Buslov 
256539b7b6a6SArnd Bergmann 	kfree(tb);
256699815f50SVlad Buslov 	tcf_queue_work(&mask->rwork, fl_uninit_mask_free_work);
256777b9900eSJiri Pirko 	return 0;
256877b9900eSJiri Pirko 
2569c049d56eSVlad Buslov errout_ht:
2570c049d56eSVlad Buslov 	spin_lock(&tp->lock);
2571620da486SVlad Buslov errout_hw:
2572c049d56eSVlad Buslov 	fnew->deleted = true;
25733d81e711SVlad Buslov 	spin_unlock(&tp->lock);
2574620da486SVlad Buslov 	if (!tc_skip_hw(fnew->flags))
2575c24e43d8SVlad Buslov 		fl_hw_destroy_filter(tp, fnew, rtnl_held, NULL);
25761f17f774SVlad Buslov 	if (in_ht)
25771f17f774SVlad Buslov 		rhashtable_remove_fast(&fnew->mask->ht, &fnew->ht_node,
25781f17f774SVlad Buslov 				       fnew->mask->filter_ht_params);
2579ecb3dea4SVlad Buslov errout_mask:
25809994677cSVlad Buslov 	fl_mask_put(head, fnew->mask);
2581ac177a33SVictor Nogueira 
2582ac177a33SVictor Nogueira unbind_filter:
2583ac177a33SVictor Nogueira 	if (bound_to_filter) {
2584ac177a33SVictor Nogueira 		if (flags & TCA_ACT_FLAGS_NO_RTNL)
2585ac177a33SVictor Nogueira 			rtnl_lock();
2586ac177a33SVictor Nogueira 		tcf_unbind_filter(tp, &fnew->res);
2587ac177a33SVictor Nogueira 		if (flags & TCA_ACT_FLAGS_NO_RTNL)
2588ac177a33SVictor Nogueira 			rtnl_unlock();
2589ac177a33SVictor Nogueira 	}
2590ac177a33SVictor Nogueira 
259108a0063dSPaul Blakey errout_idr:
25921fde0ca3SJianbo Liu 	if (!fold) {
25931fde0ca3SJianbo Liu 		spin_lock(&tp->lock);
259408a0063dSPaul Blakey 		idr_remove(&head->handle_idr, fnew->handle);
25951fde0ca3SJianbo Liu 		spin_unlock(&tp->lock);
25961fde0ca3SJianbo Liu 	}
2597c049d56eSVlad Buslov 	__fl_put(fnew);
259839b7b6a6SArnd Bergmann errout_tb:
259939b7b6a6SArnd Bergmann 	kfree(tb);
26002cddd201SIvan Vecera errout_mask_alloc:
260199815f50SVlad Buslov 	tcf_queue_work(&mask->rwork, fl_uninit_mask_free_work);
260206177558SVlad Buslov errout_fold:
260306177558SVlad Buslov 	if (fold)
260406177558SVlad Buslov 		__fl_put(fold);
260577b9900eSJiri Pirko 	return err;
260677b9900eSJiri Pirko }
260777b9900eSJiri Pirko 
fl_delete(struct tcf_proto * tp,void * arg,bool * last,bool rtnl_held,struct netlink_ext_ack * extack)2608571acf21SAlexander Aring static int fl_delete(struct tcf_proto *tp, void *arg, bool *last,
260912db03b6SVlad Buslov 		     bool rtnl_held, struct netlink_ext_ack *extack)
261077b9900eSJiri Pirko {
2611e474619aSVlad Buslov 	struct cls_fl_head *head = fl_head_dereference(tp);
26128113c095SWANG Cong 	struct cls_fl_filter *f = arg;
2613b2552b8cSVlad Buslov 	bool last_on_mask;
2614b2552b8cSVlad Buslov 	int err = 0;
261577b9900eSJiri Pirko 
2616c24e43d8SVlad Buslov 	err = __fl_delete(tp, f, &last_on_mask, rtnl_held, extack);
261705cd271fSPaul Blakey 	*last = list_empty(&head->masks);
261806177558SVlad Buslov 	__fl_put(f);
261906177558SVlad Buslov 
2620b2552b8cSVlad Buslov 	return err;
262177b9900eSJiri Pirko }
262277b9900eSJiri Pirko 
fl_walk(struct tcf_proto * tp,struct tcf_walker * arg,bool rtnl_held)262312db03b6SVlad Buslov static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg,
262412db03b6SVlad Buslov 		    bool rtnl_held)
262577b9900eSJiri Pirko {
2626d39d7149SCong Wang 	struct cls_fl_head *head = fl_head_dereference(tp);
2627d39d7149SCong Wang 	unsigned long id = arg->cookie, tmp;
262877b9900eSJiri Pirko 	struct cls_fl_filter *f;
262977b9900eSJiri Pirko 
263001683a14SVlad Buslov 	arg->count = arg->skip;
263101683a14SVlad Buslov 
2632d5ef1906SVlad Buslov 	rcu_read_lock();
2633d39d7149SCong Wang 	idr_for_each_entry_continue_ul(&head->handle_idr, f, tmp, id) {
2634d39d7149SCong Wang 		/* don't return filters that are being deleted */
2635dd4f6bbfSVlad Buslov 		if (!f || !refcount_inc_not_zero(&f->refcnt))
2636d39d7149SCong Wang 			continue;
2637d5ef1906SVlad Buslov 		rcu_read_unlock();
2638d5ef1906SVlad Buslov 
26398113c095SWANG Cong 		if (arg->fn(tp, f, arg) < 0) {
264006177558SVlad Buslov 			__fl_put(f);
264177b9900eSJiri Pirko 			arg->stop = 1;
2642d5ef1906SVlad Buslov 			rcu_read_lock();
264377b9900eSJiri Pirko 			break;
264477b9900eSJiri Pirko 		}
264506177558SVlad Buslov 		__fl_put(f);
264677b9900eSJiri Pirko 		arg->count++;
2647d5ef1906SVlad Buslov 		rcu_read_lock();
264877b9900eSJiri Pirko 	}
2649d5ef1906SVlad Buslov 	rcu_read_unlock();
2650d39d7149SCong Wang 	arg->cookie = id;
265177b9900eSJiri Pirko }
265277b9900eSJiri Pirko 
2653c049d56eSVlad Buslov static struct cls_fl_filter *
fl_get_next_hw_filter(struct tcf_proto * tp,struct cls_fl_filter * f,bool add)2654c049d56eSVlad Buslov fl_get_next_hw_filter(struct tcf_proto *tp, struct cls_fl_filter *f, bool add)
2655c049d56eSVlad Buslov {
2656c049d56eSVlad Buslov 	struct cls_fl_head *head = fl_head_dereference(tp);
2657c049d56eSVlad Buslov 
2658c049d56eSVlad Buslov 	spin_lock(&tp->lock);
2659c049d56eSVlad Buslov 	if (list_empty(&head->hw_filters)) {
2660c049d56eSVlad Buslov 		spin_unlock(&tp->lock);
2661c049d56eSVlad Buslov 		return NULL;
2662c049d56eSVlad Buslov 	}
2663c049d56eSVlad Buslov 
2664c049d56eSVlad Buslov 	if (!f)
2665c049d56eSVlad Buslov 		f = list_entry(&head->hw_filters, struct cls_fl_filter,
2666c049d56eSVlad Buslov 			       hw_list);
2667c049d56eSVlad Buslov 	list_for_each_entry_continue(f, &head->hw_filters, hw_list) {
2668c049d56eSVlad Buslov 		if (!(add && f->deleted) && refcount_inc_not_zero(&f->refcnt)) {
2669c049d56eSVlad Buslov 			spin_unlock(&tp->lock);
2670c049d56eSVlad Buslov 			return f;
2671c049d56eSVlad Buslov 		}
2672c049d56eSVlad Buslov 	}
2673c049d56eSVlad Buslov 
2674c049d56eSVlad Buslov 	spin_unlock(&tp->lock);
2675c049d56eSVlad Buslov 	return NULL;
2676c049d56eSVlad Buslov }
2677c049d56eSVlad Buslov 
fl_reoffload(struct tcf_proto * tp,bool add,flow_setup_cb_t * cb,void * cb_priv,struct netlink_ext_ack * extack)2678a7323311SPablo Neira Ayuso static int fl_reoffload(struct tcf_proto *tp, bool add, flow_setup_cb_t *cb,
267931533cbaSJohn Hurley 			void *cb_priv, struct netlink_ext_ack *extack)
268031533cbaSJohn Hurley {
268131533cbaSJohn Hurley 	struct tcf_block *block = tp->chain->block;
2682f9e30088SPablo Neira Ayuso 	struct flow_cls_offload cls_flower = {};
2683c049d56eSVlad Buslov 	struct cls_fl_filter *f = NULL;
268431533cbaSJohn Hurley 	int err;
268531533cbaSJohn Hurley 
2686c049d56eSVlad Buslov 	/* hw_filters list can only be changed by hw offload functions after
2687c049d56eSVlad Buslov 	 * obtaining rtnl lock. Make sure it is not changed while reoffload is
2688c049d56eSVlad Buslov 	 * iterating it.
2689c049d56eSVlad Buslov 	 */
2690c049d56eSVlad Buslov 	ASSERT_RTNL();
269131533cbaSJohn Hurley 
2692c049d56eSVlad Buslov 	while ((f = fl_get_next_hw_filter(tp, f, add))) {
2693e3ab786bSPablo Neira Ayuso 		cls_flower.rule =
2694e3ab786bSPablo Neira Ayuso 			flow_rule_alloc(tcf_exts_num_actions(&f->exts));
269595e27a4dSJohn Hurley 		if (!cls_flower.rule) {
269695e27a4dSJohn Hurley 			__fl_put(f);
26978f256622SPablo Neira Ayuso 			return -ENOMEM;
269895e27a4dSJohn Hurley 		}
26998f256622SPablo Neira Ayuso 
270095e27a4dSJohn Hurley 		tc_cls_common_offload_init(&cls_flower.common, tp, f->flags,
2701d6787147SPieter Jansen van Vuuren 					   extack);
270231533cbaSJohn Hurley 		cls_flower.command = add ?
2703f9e30088SPablo Neira Ayuso 			FLOW_CLS_REPLACE : FLOW_CLS_DESTROY;
270431533cbaSJohn Hurley 		cls_flower.cookie = (unsigned long)f;
270595e27a4dSJohn Hurley 		cls_flower.rule->match.dissector = &f->mask->dissector;
270695e27a4dSJohn Hurley 		cls_flower.rule->match.mask = &f->mask->key;
27078f256622SPablo Neira Ayuso 		cls_flower.rule->match.key = &f->mkey;
27083a7b6861SPablo Neira Ayuso 
2709c2ccf84eSIdo Schimmel 		err = tc_setup_offload_action(&cls_flower.rule->action, &f->exts,
2710c2ccf84eSIdo Schimmel 					      cls_flower.common.extack);
27113a7b6861SPablo Neira Ayuso 		if (err) {
27123a7b6861SPablo Neira Ayuso 			kfree(cls_flower.rule);
27131f15bb4fSVlad Buslov 			if (tc_skip_sw(f->flags)) {
271495e27a4dSJohn Hurley 				__fl_put(f);
27153a7b6861SPablo Neira Ayuso 				return err;
27163a7b6861SPablo Neira Ayuso 			}
271795e27a4dSJohn Hurley 			goto next_flow;
27181f15bb4fSVlad Buslov 		}
27193a7b6861SPablo Neira Ayuso 
272031533cbaSJohn Hurley 		cls_flower.classid = f->res.classid;
272131533cbaSJohn Hurley 
272240119211SVlad Buslov 		err = tc_setup_cb_reoffload(block, tp, add, cb,
272340119211SVlad Buslov 					    TC_SETUP_CLSFLOWER, &cls_flower,
272440119211SVlad Buslov 					    cb_priv, &f->flags,
272540119211SVlad Buslov 					    &f->in_hw_count);
27269c1c0e12SBaowen Zheng 		tc_cleanup_offload_action(&cls_flower.rule->action);
27278f256622SPablo Neira Ayuso 		kfree(cls_flower.rule);
27288f256622SPablo Neira Ayuso 
272931533cbaSJohn Hurley 		if (err) {
273095e27a4dSJohn Hurley 			__fl_put(f);
273131533cbaSJohn Hurley 			return err;
273295e27a4dSJohn Hurley 		}
273395e27a4dSJohn Hurley next_flow:
273495e27a4dSJohn Hurley 		__fl_put(f);
273531533cbaSJohn Hurley 	}
273631533cbaSJohn Hurley 
273731533cbaSJohn Hurley 	return 0;
273831533cbaSJohn Hurley }
273931533cbaSJohn Hurley 
fl_hw_add(struct tcf_proto * tp,void * type_data)2740a449a3e7SVlad Buslov static void fl_hw_add(struct tcf_proto *tp, void *type_data)
2741a449a3e7SVlad Buslov {
2742a449a3e7SVlad Buslov 	struct flow_cls_offload *cls_flower = type_data;
2743a449a3e7SVlad Buslov 	struct cls_fl_filter *f =
2744a449a3e7SVlad Buslov 		(struct cls_fl_filter *) cls_flower->cookie;
2745a449a3e7SVlad Buslov 	struct cls_fl_head *head = fl_head_dereference(tp);
2746a449a3e7SVlad Buslov 
2747a449a3e7SVlad Buslov 	spin_lock(&tp->lock);
2748a449a3e7SVlad Buslov 	list_add(&f->hw_list, &head->hw_filters);
2749a449a3e7SVlad Buslov 	spin_unlock(&tp->lock);
2750a449a3e7SVlad Buslov }
2751a449a3e7SVlad Buslov 
fl_hw_del(struct tcf_proto * tp,void * type_data)2752a449a3e7SVlad Buslov static void fl_hw_del(struct tcf_proto *tp, void *type_data)
2753a449a3e7SVlad Buslov {
2754a449a3e7SVlad Buslov 	struct flow_cls_offload *cls_flower = type_data;
2755a449a3e7SVlad Buslov 	struct cls_fl_filter *f =
2756a449a3e7SVlad Buslov 		(struct cls_fl_filter *) cls_flower->cookie;
2757a449a3e7SVlad Buslov 
2758a449a3e7SVlad Buslov 	spin_lock(&tp->lock);
2759a449a3e7SVlad Buslov 	if (!list_empty(&f->hw_list))
2760a449a3e7SVlad Buslov 		list_del_init(&f->hw_list);
2761a449a3e7SVlad Buslov 	spin_unlock(&tp->lock);
2762a449a3e7SVlad Buslov }
2763a449a3e7SVlad Buslov 
fl_hw_create_tmplt(struct tcf_chain * chain,struct fl_flow_tmplt * tmplt)27648f256622SPablo Neira Ayuso static int fl_hw_create_tmplt(struct tcf_chain *chain,
276534738452SJiri Pirko 			      struct fl_flow_tmplt *tmplt)
276634738452SJiri Pirko {
2767f9e30088SPablo Neira Ayuso 	struct flow_cls_offload cls_flower = {};
276834738452SJiri Pirko 	struct tcf_block *block = chain->block;
276934738452SJiri Pirko 
2770e3ab786bSPablo Neira Ayuso 	cls_flower.rule = flow_rule_alloc(0);
27718f256622SPablo Neira Ayuso 	if (!cls_flower.rule)
27728f256622SPablo Neira Ayuso 		return -ENOMEM;
27738f256622SPablo Neira Ayuso 
277434738452SJiri Pirko 	cls_flower.common.chain_index = chain->index;
2775f9e30088SPablo Neira Ayuso 	cls_flower.command = FLOW_CLS_TMPLT_CREATE;
277634738452SJiri Pirko 	cls_flower.cookie = (unsigned long) tmplt;
27778f256622SPablo Neira Ayuso 	cls_flower.rule->match.dissector = &tmplt->dissector;
27788f256622SPablo Neira Ayuso 	cls_flower.rule->match.mask = &tmplt->mask;
27798f256622SPablo Neira Ayuso 	cls_flower.rule->match.key = &tmplt->dummy_key;
278034738452SJiri Pirko 
278134738452SJiri Pirko 	/* We don't care if driver (any of them) fails to handle this
278234738452SJiri Pirko 	 * call. It serves just as a hint for it.
278334738452SJiri Pirko 	 */
278440119211SVlad Buslov 	tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, false, true);
27858f256622SPablo Neira Ayuso 	kfree(cls_flower.rule);
27868f256622SPablo Neira Ayuso 
27878f256622SPablo Neira Ayuso 	return 0;
278834738452SJiri Pirko }
278934738452SJiri Pirko 
fl_hw_destroy_tmplt(struct tcf_chain * chain,struct fl_flow_tmplt * tmplt)279034738452SJiri Pirko static void fl_hw_destroy_tmplt(struct tcf_chain *chain,
279134738452SJiri Pirko 				struct fl_flow_tmplt *tmplt)
279234738452SJiri Pirko {
2793f9e30088SPablo Neira Ayuso 	struct flow_cls_offload cls_flower = {};
279434738452SJiri Pirko 	struct tcf_block *block = chain->block;
279534738452SJiri Pirko 
279634738452SJiri Pirko 	cls_flower.common.chain_index = chain->index;
2797f9e30088SPablo Neira Ayuso 	cls_flower.command = FLOW_CLS_TMPLT_DESTROY;
279834738452SJiri Pirko 	cls_flower.cookie = (unsigned long) tmplt;
279934738452SJiri Pirko 
280040119211SVlad Buslov 	tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, false, true);
280134738452SJiri Pirko }
280234738452SJiri Pirko 
fl_tmplt_create(struct net * net,struct tcf_chain * chain,struct nlattr ** tca,struct netlink_ext_ack * extack)2803b95ec7ebSJiri Pirko static void *fl_tmplt_create(struct net *net, struct tcf_chain *chain,
2804b95ec7ebSJiri Pirko 			     struct nlattr **tca,
2805b95ec7ebSJiri Pirko 			     struct netlink_ext_ack *extack)
2806b95ec7ebSJiri Pirko {
2807*536b97acSAsbjørn Sloth Tønnesen 	struct nlattr *tca_opts = tca[TCA_OPTIONS];
2808b95ec7ebSJiri Pirko 	struct fl_flow_tmplt *tmplt;
2809b95ec7ebSJiri Pirko 	struct nlattr **tb;
2810b95ec7ebSJiri Pirko 	int err;
2811b95ec7ebSJiri Pirko 
2812*536b97acSAsbjørn Sloth Tønnesen 	if (!tca_opts)
2813b95ec7ebSJiri Pirko 		return ERR_PTR(-EINVAL);
2814b95ec7ebSJiri Pirko 
2815b95ec7ebSJiri Pirko 	tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL);
2816b95ec7ebSJiri Pirko 	if (!tb)
2817b95ec7ebSJiri Pirko 		return ERR_PTR(-ENOBUFS);
28188cb08174SJohannes Berg 	err = nla_parse_nested_deprecated(tb, TCA_FLOWER_MAX,
2819*536b97acSAsbjørn Sloth Tønnesen 					  tca_opts, fl_policy, NULL);
2820b95ec7ebSJiri Pirko 	if (err)
2821b95ec7ebSJiri Pirko 		goto errout_tb;
2822b95ec7ebSJiri Pirko 
2823b95ec7ebSJiri Pirko 	tmplt = kzalloc(sizeof(*tmplt), GFP_KERNEL);
28241cbc36a5SDan Carpenter 	if (!tmplt) {
28251cbc36a5SDan Carpenter 		err = -ENOMEM;
2826b95ec7ebSJiri Pirko 		goto errout_tb;
28271cbc36a5SDan Carpenter 	}
2828b95ec7ebSJiri Pirko 	tmplt->chain = chain;
2829*536b97acSAsbjørn Sloth Tønnesen 	err = fl_set_key(net, tca_opts, tb, &tmplt->dummy_key,
2830*536b97acSAsbjørn Sloth Tønnesen 			 &tmplt->mask, extack);
2831b95ec7ebSJiri Pirko 	if (err)
2832b95ec7ebSJiri Pirko 		goto errout_tmplt;
2833b95ec7ebSJiri Pirko 
2834b95ec7ebSJiri Pirko 	fl_init_dissector(&tmplt->dissector, &tmplt->mask);
2835b95ec7ebSJiri Pirko 
28368f256622SPablo Neira Ayuso 	err = fl_hw_create_tmplt(chain, tmplt);
28378f256622SPablo Neira Ayuso 	if (err)
28388f256622SPablo Neira Ayuso 		goto errout_tmplt;
283934738452SJiri Pirko 
28408f256622SPablo Neira Ayuso 	kfree(tb);
2841b95ec7ebSJiri Pirko 	return tmplt;
2842b95ec7ebSJiri Pirko 
2843b95ec7ebSJiri Pirko errout_tmplt:
2844b95ec7ebSJiri Pirko 	kfree(tmplt);
2845b95ec7ebSJiri Pirko errout_tb:
2846b95ec7ebSJiri Pirko 	kfree(tb);
2847b95ec7ebSJiri Pirko 	return ERR_PTR(err);
2848b95ec7ebSJiri Pirko }
2849b95ec7ebSJiri Pirko 
fl_tmplt_destroy(void * tmplt_priv)2850b95ec7ebSJiri Pirko static void fl_tmplt_destroy(void *tmplt_priv)
2851b95ec7ebSJiri Pirko {
2852b95ec7ebSJiri Pirko 	struct fl_flow_tmplt *tmplt = tmplt_priv;
2853b95ec7ebSJiri Pirko 
285495278ddaSCong Wang 	fl_hw_destroy_tmplt(tmplt->chain, tmplt);
285595278ddaSCong Wang 	kfree(tmplt);
2856b95ec7ebSJiri Pirko }
2857b95ec7ebSJiri Pirko 
fl_tmplt_reoffload(struct tcf_chain * chain,bool add,flow_setup_cb_t * cb,void * cb_priv)285832f2a0afSIdo Schimmel static void fl_tmplt_reoffload(struct tcf_chain *chain, bool add,
285932f2a0afSIdo Schimmel 			       flow_setup_cb_t *cb, void *cb_priv)
286032f2a0afSIdo Schimmel {
286132f2a0afSIdo Schimmel 	struct fl_flow_tmplt *tmplt = chain->tmplt_priv;
286232f2a0afSIdo Schimmel 	struct flow_cls_offload cls_flower = {};
286332f2a0afSIdo Schimmel 
286432f2a0afSIdo Schimmel 	cls_flower.rule = flow_rule_alloc(0);
286532f2a0afSIdo Schimmel 	if (!cls_flower.rule)
286632f2a0afSIdo Schimmel 		return;
286732f2a0afSIdo Schimmel 
286832f2a0afSIdo Schimmel 	cls_flower.common.chain_index = chain->index;
286932f2a0afSIdo Schimmel 	cls_flower.command = add ? FLOW_CLS_TMPLT_CREATE :
287032f2a0afSIdo Schimmel 				   FLOW_CLS_TMPLT_DESTROY;
287132f2a0afSIdo Schimmel 	cls_flower.cookie = (unsigned long) tmplt;
287232f2a0afSIdo Schimmel 	cls_flower.rule->match.dissector = &tmplt->dissector;
287332f2a0afSIdo Schimmel 	cls_flower.rule->match.mask = &tmplt->mask;
287432f2a0afSIdo Schimmel 	cls_flower.rule->match.key = &tmplt->dummy_key;
287532f2a0afSIdo Schimmel 
287632f2a0afSIdo Schimmel 	cb(TC_SETUP_CLSFLOWER, &cls_flower, cb_priv);
287732f2a0afSIdo Schimmel 	kfree(cls_flower.rule);
287832f2a0afSIdo Schimmel }
287932f2a0afSIdo Schimmel 
fl_dump_key_val(struct sk_buff * skb,void * val,int val_type,void * mask,int mask_type,int len)288077b9900eSJiri Pirko static int fl_dump_key_val(struct sk_buff *skb,
288177b9900eSJiri Pirko 			   void *val, int val_type,
288277b9900eSJiri Pirko 			   void *mask, int mask_type, int len)
288377b9900eSJiri Pirko {
288477b9900eSJiri Pirko 	int err;
288577b9900eSJiri Pirko 
288677b9900eSJiri Pirko 	if (!memchr_inv(mask, 0, len))
288777b9900eSJiri Pirko 		return 0;
288877b9900eSJiri Pirko 	err = nla_put(skb, val_type, len, val);
288977b9900eSJiri Pirko 	if (err)
289077b9900eSJiri Pirko 		return err;
289177b9900eSJiri Pirko 	if (mask_type != TCA_FLOWER_UNSPEC) {
289277b9900eSJiri Pirko 		err = nla_put(skb, mask_type, len, mask);
289377b9900eSJiri Pirko 		if (err)
289477b9900eSJiri Pirko 			return err;
289577b9900eSJiri Pirko 	}
289677b9900eSJiri Pirko 	return 0;
289777b9900eSJiri Pirko }
289877b9900eSJiri Pirko 
fl_dump_key_port_range(struct sk_buff * skb,struct fl_flow_key * key,struct fl_flow_key * mask)28995c72299fSAmritha Nambiar static int fl_dump_key_port_range(struct sk_buff *skb, struct fl_flow_key *key,
29005c72299fSAmritha Nambiar 				  struct fl_flow_key *mask)
29015c72299fSAmritha Nambiar {
29028ffb055bSYoshiki Komachi 	if (fl_dump_key_val(skb, &key->tp_range.tp_min.dst,
29038ffb055bSYoshiki Komachi 			    TCA_FLOWER_KEY_PORT_DST_MIN,
29048ffb055bSYoshiki Komachi 			    &mask->tp_range.tp_min.dst, TCA_FLOWER_UNSPEC,
29058ffb055bSYoshiki Komachi 			    sizeof(key->tp_range.tp_min.dst)) ||
29068ffb055bSYoshiki Komachi 	    fl_dump_key_val(skb, &key->tp_range.tp_max.dst,
29078ffb055bSYoshiki Komachi 			    TCA_FLOWER_KEY_PORT_DST_MAX,
29088ffb055bSYoshiki Komachi 			    &mask->tp_range.tp_max.dst, TCA_FLOWER_UNSPEC,
29098ffb055bSYoshiki Komachi 			    sizeof(key->tp_range.tp_max.dst)) ||
29108ffb055bSYoshiki Komachi 	    fl_dump_key_val(skb, &key->tp_range.tp_min.src,
29118ffb055bSYoshiki Komachi 			    TCA_FLOWER_KEY_PORT_SRC_MIN,
29128ffb055bSYoshiki Komachi 			    &mask->tp_range.tp_min.src, TCA_FLOWER_UNSPEC,
29138ffb055bSYoshiki Komachi 			    sizeof(key->tp_range.tp_min.src)) ||
29148ffb055bSYoshiki Komachi 	    fl_dump_key_val(skb, &key->tp_range.tp_max.src,
29158ffb055bSYoshiki Komachi 			    TCA_FLOWER_KEY_PORT_SRC_MAX,
29168ffb055bSYoshiki Komachi 			    &mask->tp_range.tp_max.src, TCA_FLOWER_UNSPEC,
29178ffb055bSYoshiki Komachi 			    sizeof(key->tp_range.tp_max.src)))
29185c72299fSAmritha Nambiar 		return -1;
29195c72299fSAmritha Nambiar 
29205c72299fSAmritha Nambiar 	return 0;
29215c72299fSAmritha Nambiar }
29225c72299fSAmritha Nambiar 
fl_dump_key_mpls_opt_lse(struct sk_buff * skb,struct flow_dissector_key_mpls * mpls_key,struct flow_dissector_key_mpls * mpls_mask,u8 lse_index)292361aec25aSGuillaume Nault static int fl_dump_key_mpls_opt_lse(struct sk_buff *skb,
292461aec25aSGuillaume Nault 				    struct flow_dissector_key_mpls *mpls_key,
292561aec25aSGuillaume Nault 				    struct flow_dissector_key_mpls *mpls_mask,
292661aec25aSGuillaume Nault 				    u8 lse_index)
292761aec25aSGuillaume Nault {
292861aec25aSGuillaume Nault 	struct flow_dissector_mpls_lse *lse_mask = &mpls_mask->ls[lse_index];
292961aec25aSGuillaume Nault 	struct flow_dissector_mpls_lse *lse_key = &mpls_key->ls[lse_index];
293061aec25aSGuillaume Nault 	int err;
293161aec25aSGuillaume Nault 
293261aec25aSGuillaume Nault 	err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH,
293361aec25aSGuillaume Nault 			 lse_index + 1);
293461aec25aSGuillaume Nault 	if (err)
293561aec25aSGuillaume Nault 		return err;
293661aec25aSGuillaume Nault 
293761aec25aSGuillaume Nault 	if (lse_mask->mpls_ttl) {
293861aec25aSGuillaume Nault 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_OPT_LSE_TTL,
293961aec25aSGuillaume Nault 				 lse_key->mpls_ttl);
294061aec25aSGuillaume Nault 		if (err)
294161aec25aSGuillaume Nault 			return err;
294261aec25aSGuillaume Nault 	}
294361aec25aSGuillaume Nault 	if (lse_mask->mpls_bos) {
294461aec25aSGuillaume Nault 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS,
294561aec25aSGuillaume Nault 				 lse_key->mpls_bos);
294661aec25aSGuillaume Nault 		if (err)
294761aec25aSGuillaume Nault 			return err;
294861aec25aSGuillaume Nault 	}
294961aec25aSGuillaume Nault 	if (lse_mask->mpls_tc) {
295061aec25aSGuillaume Nault 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_OPT_LSE_TC,
295161aec25aSGuillaume Nault 				 lse_key->mpls_tc);
295261aec25aSGuillaume Nault 		if (err)
295361aec25aSGuillaume Nault 			return err;
295461aec25aSGuillaume Nault 	}
295561aec25aSGuillaume Nault 	if (lse_mask->mpls_label) {
29567fdd375eSGuillaume Nault 		err = nla_put_u32(skb, TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL,
295761aec25aSGuillaume Nault 				  lse_key->mpls_label);
295861aec25aSGuillaume Nault 		if (err)
295961aec25aSGuillaume Nault 			return err;
296061aec25aSGuillaume Nault 	}
296161aec25aSGuillaume Nault 
296261aec25aSGuillaume Nault 	return 0;
296361aec25aSGuillaume Nault }
296461aec25aSGuillaume Nault 
fl_dump_key_mpls_opts(struct sk_buff * skb,struct flow_dissector_key_mpls * mpls_key,struct flow_dissector_key_mpls * mpls_mask)296561aec25aSGuillaume Nault static int fl_dump_key_mpls_opts(struct sk_buff *skb,
296661aec25aSGuillaume Nault 				 struct flow_dissector_key_mpls *mpls_key,
296761aec25aSGuillaume Nault 				 struct flow_dissector_key_mpls *mpls_mask)
296861aec25aSGuillaume Nault {
296961aec25aSGuillaume Nault 	struct nlattr *opts;
297061aec25aSGuillaume Nault 	struct nlattr *lse;
297161aec25aSGuillaume Nault 	u8 lse_index;
297261aec25aSGuillaume Nault 	int err;
297361aec25aSGuillaume Nault 
297461aec25aSGuillaume Nault 	opts = nla_nest_start(skb, TCA_FLOWER_KEY_MPLS_OPTS);
297561aec25aSGuillaume Nault 	if (!opts)
297661aec25aSGuillaume Nault 		return -EMSGSIZE;
297761aec25aSGuillaume Nault 
297861aec25aSGuillaume Nault 	for (lse_index = 0; lse_index < FLOW_DIS_MPLS_MAX; lse_index++) {
297961aec25aSGuillaume Nault 		if (!(mpls_mask->used_lses & 1 << lse_index))
298061aec25aSGuillaume Nault 			continue;
298161aec25aSGuillaume Nault 
298261aec25aSGuillaume Nault 		lse = nla_nest_start(skb, TCA_FLOWER_KEY_MPLS_OPTS_LSE);
298361aec25aSGuillaume Nault 		if (!lse) {
298461aec25aSGuillaume Nault 			err = -EMSGSIZE;
298561aec25aSGuillaume Nault 			goto err_opts;
298661aec25aSGuillaume Nault 		}
298761aec25aSGuillaume Nault 
298861aec25aSGuillaume Nault 		err = fl_dump_key_mpls_opt_lse(skb, mpls_key, mpls_mask,
298961aec25aSGuillaume Nault 					       lse_index);
299061aec25aSGuillaume Nault 		if (err)
299161aec25aSGuillaume Nault 			goto err_opts_lse;
299261aec25aSGuillaume Nault 		nla_nest_end(skb, lse);
299361aec25aSGuillaume Nault 	}
299461aec25aSGuillaume Nault 	nla_nest_end(skb, opts);
299561aec25aSGuillaume Nault 
299661aec25aSGuillaume Nault 	return 0;
299761aec25aSGuillaume Nault 
299861aec25aSGuillaume Nault err_opts_lse:
299961aec25aSGuillaume Nault 	nla_nest_cancel(skb, lse);
300061aec25aSGuillaume Nault err_opts:
300161aec25aSGuillaume Nault 	nla_nest_cancel(skb, opts);
300261aec25aSGuillaume Nault 
300361aec25aSGuillaume Nault 	return err;
300461aec25aSGuillaume Nault }
300561aec25aSGuillaume Nault 
fl_dump_key_mpls(struct sk_buff * skb,struct flow_dissector_key_mpls * mpls_key,struct flow_dissector_key_mpls * mpls_mask)3006a577d8f7SBenjamin LaHaise static int fl_dump_key_mpls(struct sk_buff *skb,
3007a577d8f7SBenjamin LaHaise 			    struct flow_dissector_key_mpls *mpls_key,
3008a577d8f7SBenjamin LaHaise 			    struct flow_dissector_key_mpls *mpls_mask)
3009a577d8f7SBenjamin LaHaise {
301058cff782SGuillaume Nault 	struct flow_dissector_mpls_lse *lse_mask;
301158cff782SGuillaume Nault 	struct flow_dissector_mpls_lse *lse_key;
3012a577d8f7SBenjamin LaHaise 	int err;
3013a577d8f7SBenjamin LaHaise 
301461aec25aSGuillaume Nault 	if (!mpls_mask->used_lses)
3015a577d8f7SBenjamin LaHaise 		return 0;
301658cff782SGuillaume Nault 
301758cff782SGuillaume Nault 	lse_mask = &mpls_mask->ls[0];
301858cff782SGuillaume Nault 	lse_key = &mpls_key->ls[0];
301958cff782SGuillaume Nault 
302061aec25aSGuillaume Nault 	/* For backward compatibility, don't use the MPLS nested attributes if
302161aec25aSGuillaume Nault 	 * the rule can be expressed using the old attributes.
302261aec25aSGuillaume Nault 	 */
302361aec25aSGuillaume Nault 	if (mpls_mask->used_lses & ~1 ||
302461aec25aSGuillaume Nault 	    (!lse_mask->mpls_ttl && !lse_mask->mpls_bos &&
302561aec25aSGuillaume Nault 	     !lse_mask->mpls_tc && !lse_mask->mpls_label))
302661aec25aSGuillaume Nault 		return fl_dump_key_mpls_opts(skb, mpls_key, mpls_mask);
302761aec25aSGuillaume Nault 
302858cff782SGuillaume Nault 	if (lse_mask->mpls_ttl) {
3029a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TTL,
303058cff782SGuillaume Nault 				 lse_key->mpls_ttl);
3031a577d8f7SBenjamin LaHaise 		if (err)
3032a577d8f7SBenjamin LaHaise 			return err;
3033a577d8f7SBenjamin LaHaise 	}
303458cff782SGuillaume Nault 	if (lse_mask->mpls_tc) {
3035a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TC,
303658cff782SGuillaume Nault 				 lse_key->mpls_tc);
3037a577d8f7SBenjamin LaHaise 		if (err)
3038a577d8f7SBenjamin LaHaise 			return err;
3039a577d8f7SBenjamin LaHaise 	}
304058cff782SGuillaume Nault 	if (lse_mask->mpls_label) {
3041a577d8f7SBenjamin LaHaise 		err = nla_put_u32(skb, TCA_FLOWER_KEY_MPLS_LABEL,
304258cff782SGuillaume Nault 				  lse_key->mpls_label);
3043a577d8f7SBenjamin LaHaise 		if (err)
3044a577d8f7SBenjamin LaHaise 			return err;
3045a577d8f7SBenjamin LaHaise 	}
304658cff782SGuillaume Nault 	if (lse_mask->mpls_bos) {
3047a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_BOS,
304858cff782SGuillaume Nault 				 lse_key->mpls_bos);
3049a577d8f7SBenjamin LaHaise 		if (err)
3050a577d8f7SBenjamin LaHaise 			return err;
3051a577d8f7SBenjamin LaHaise 	}
3052a577d8f7SBenjamin LaHaise 	return 0;
3053a577d8f7SBenjamin LaHaise }
3054a577d8f7SBenjamin LaHaise 
fl_dump_key_ip(struct sk_buff * skb,bool encap,struct flow_dissector_key_ip * key,struct flow_dissector_key_ip * mask)30550e2c17b6SOr Gerlitz static int fl_dump_key_ip(struct sk_buff *skb, bool encap,
30564d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *key,
30574d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *mask)
30584d80cc0aSOr Gerlitz {
30590e2c17b6SOr Gerlitz 	int tos_key = encap ? TCA_FLOWER_KEY_ENC_IP_TOS : TCA_FLOWER_KEY_IP_TOS;
30600e2c17b6SOr Gerlitz 	int ttl_key = encap ? TCA_FLOWER_KEY_ENC_IP_TTL : TCA_FLOWER_KEY_IP_TTL;
30610e2c17b6SOr Gerlitz 	int tos_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TOS_MASK : TCA_FLOWER_KEY_IP_TOS_MASK;
30620e2c17b6SOr Gerlitz 	int ttl_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TTL_MASK : TCA_FLOWER_KEY_IP_TTL_MASK;
30630e2c17b6SOr Gerlitz 
30640e2c17b6SOr Gerlitz 	if (fl_dump_key_val(skb, &key->tos, tos_key, &mask->tos, tos_mask, sizeof(key->tos)) ||
30650e2c17b6SOr Gerlitz 	    fl_dump_key_val(skb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl)))
30664d80cc0aSOr Gerlitz 		return -1;
30674d80cc0aSOr Gerlitz 
30684d80cc0aSOr Gerlitz 	return 0;
30694d80cc0aSOr Gerlitz }
30704d80cc0aSOr Gerlitz 
fl_dump_key_vlan(struct sk_buff * skb,int vlan_id_key,int vlan_prio_key,struct flow_dissector_key_vlan * vlan_key,struct flow_dissector_key_vlan * vlan_mask)30719399ae9aSHadar Hen Zion static int fl_dump_key_vlan(struct sk_buff *skb,
3072d64efd09SJianbo Liu 			    int vlan_id_key, int vlan_prio_key,
30739399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *vlan_key,
30749399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *vlan_mask)
30759399ae9aSHadar Hen Zion {
30769399ae9aSHadar Hen Zion 	int err;
30779399ae9aSHadar Hen Zion 
30789399ae9aSHadar Hen Zion 	if (!memchr_inv(vlan_mask, 0, sizeof(*vlan_mask)))
30799399ae9aSHadar Hen Zion 		return 0;
30809399ae9aSHadar Hen Zion 	if (vlan_mask->vlan_id) {
3081d64efd09SJianbo Liu 		err = nla_put_u16(skb, vlan_id_key,
30829399ae9aSHadar Hen Zion 				  vlan_key->vlan_id);
30839399ae9aSHadar Hen Zion 		if (err)
30849399ae9aSHadar Hen Zion 			return err;
30859399ae9aSHadar Hen Zion 	}
30869399ae9aSHadar Hen Zion 	if (vlan_mask->vlan_priority) {
3087d64efd09SJianbo Liu 		err = nla_put_u8(skb, vlan_prio_key,
30889399ae9aSHadar Hen Zion 				 vlan_key->vlan_priority);
30899399ae9aSHadar Hen Zion 		if (err)
30909399ae9aSHadar Hen Zion 			return err;
30919399ae9aSHadar Hen Zion 	}
30929399ae9aSHadar Hen Zion 	return 0;
30939399ae9aSHadar Hen Zion }
30949399ae9aSHadar Hen Zion 
fl_get_key_flag(u32 dissector_key,u32 dissector_mask,u32 * flower_key,u32 * flower_mask,u32 flower_flag_bit,u32 dissector_flag_bit)3095faa3ffceSOr Gerlitz static void fl_get_key_flag(u32 dissector_key, u32 dissector_mask,
3096faa3ffceSOr Gerlitz 			    u32 *flower_key, u32 *flower_mask,
3097faa3ffceSOr Gerlitz 			    u32 flower_flag_bit, u32 dissector_flag_bit)
3098faa3ffceSOr Gerlitz {
3099faa3ffceSOr Gerlitz 	if (dissector_mask & dissector_flag_bit) {
3100faa3ffceSOr Gerlitz 		*flower_mask |= flower_flag_bit;
3101faa3ffceSOr Gerlitz 		if (dissector_key & dissector_flag_bit)
3102faa3ffceSOr Gerlitz 			*flower_key |= flower_flag_bit;
3103faa3ffceSOr Gerlitz 	}
3104faa3ffceSOr Gerlitz }
3105faa3ffceSOr Gerlitz 
fl_dump_key_flags(struct sk_buff * skb,bool encap,u32 flags_key,u32 flags_mask)3106fcb4bb07SAsbjørn Sloth Tønnesen static int fl_dump_key_flags(struct sk_buff *skb, bool encap,
3107fcb4bb07SAsbjørn Sloth Tønnesen 			     u32 flags_key, u32 flags_mask)
3108faa3ffceSOr Gerlitz {
3109fcb4bb07SAsbjørn Sloth Tønnesen 	int fl_key, fl_mask;
3110faa3ffceSOr Gerlitz 	__be32 _key, _mask;
3111fcb4bb07SAsbjørn Sloth Tønnesen 	u32 key, mask;
3112faa3ffceSOr Gerlitz 	int err;
3113faa3ffceSOr Gerlitz 
3114fcb4bb07SAsbjørn Sloth Tønnesen 	if (encap) {
3115fcb4bb07SAsbjørn Sloth Tønnesen 		fl_key = TCA_FLOWER_KEY_ENC_FLAGS;
3116fcb4bb07SAsbjørn Sloth Tønnesen 		fl_mask = TCA_FLOWER_KEY_ENC_FLAGS_MASK;
3117fcb4bb07SAsbjørn Sloth Tønnesen 	} else {
3118fcb4bb07SAsbjørn Sloth Tønnesen 		fl_key = TCA_FLOWER_KEY_FLAGS;
3119fcb4bb07SAsbjørn Sloth Tønnesen 		fl_mask = TCA_FLOWER_KEY_FLAGS_MASK;
3120fcb4bb07SAsbjørn Sloth Tønnesen 	}
3121fcb4bb07SAsbjørn Sloth Tønnesen 
3122faa3ffceSOr Gerlitz 	if (!memchr_inv(&flags_mask, 0, sizeof(flags_mask)))
3123faa3ffceSOr Gerlitz 		return 0;
3124faa3ffceSOr Gerlitz 
3125faa3ffceSOr Gerlitz 	key = 0;
3126faa3ffceSOr Gerlitz 	mask = 0;
3127faa3ffceSOr Gerlitz 
3128faa3ffceSOr Gerlitz 	fl_get_key_flag(flags_key, flags_mask, &key, &mask,
3129faa3ffceSOr Gerlitz 			TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT);
3130459d153dSPieter Jansen van Vuuren 	fl_get_key_flag(flags_key, flags_mask, &key, &mask,
3131459d153dSPieter Jansen van Vuuren 			TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST,
3132459d153dSPieter Jansen van Vuuren 			FLOW_DIS_FIRST_FRAG);
3133faa3ffceSOr Gerlitz 
3134988f8723SAsbjørn Sloth Tønnesen 	fl_get_key_flag(flags_key, flags_mask, &key, &mask,
3135988f8723SAsbjørn Sloth Tønnesen 			TCA_FLOWER_KEY_FLAGS_TUNNEL_CSUM,
3136988f8723SAsbjørn Sloth Tønnesen 			FLOW_DIS_F_TUNNEL_CSUM);
3137988f8723SAsbjørn Sloth Tønnesen 
3138988f8723SAsbjørn Sloth Tønnesen 	fl_get_key_flag(flags_key, flags_mask, &key, &mask,
3139988f8723SAsbjørn Sloth Tønnesen 			TCA_FLOWER_KEY_FLAGS_TUNNEL_DONT_FRAGMENT,
3140988f8723SAsbjørn Sloth Tønnesen 			FLOW_DIS_F_TUNNEL_DONT_FRAGMENT);
3141988f8723SAsbjørn Sloth Tønnesen 
3142988f8723SAsbjørn Sloth Tønnesen 	fl_get_key_flag(flags_key, flags_mask, &key, &mask,
3143988f8723SAsbjørn Sloth Tønnesen 			TCA_FLOWER_KEY_FLAGS_TUNNEL_OAM, FLOW_DIS_F_TUNNEL_OAM);
3144988f8723SAsbjørn Sloth Tønnesen 
3145988f8723SAsbjørn Sloth Tønnesen 	fl_get_key_flag(flags_key, flags_mask, &key, &mask,
3146988f8723SAsbjørn Sloth Tønnesen 			TCA_FLOWER_KEY_FLAGS_TUNNEL_CRIT_OPT,
3147988f8723SAsbjørn Sloth Tønnesen 			FLOW_DIS_F_TUNNEL_CRIT_OPT);
3148988f8723SAsbjørn Sloth Tønnesen 
3149faa3ffceSOr Gerlitz 	_key = cpu_to_be32(key);
3150faa3ffceSOr Gerlitz 	_mask = cpu_to_be32(mask);
3151faa3ffceSOr Gerlitz 
3152fcb4bb07SAsbjørn Sloth Tønnesen 	err = nla_put(skb, fl_key, 4, &_key);
3153faa3ffceSOr Gerlitz 	if (err)
3154faa3ffceSOr Gerlitz 		return err;
3155faa3ffceSOr Gerlitz 
3156fcb4bb07SAsbjørn Sloth Tønnesen 	return nla_put(skb, fl_mask, 4, &_mask);
3157faa3ffceSOr Gerlitz }
3158faa3ffceSOr Gerlitz 
fl_dump_key_geneve_opt(struct sk_buff * skb,struct flow_dissector_key_enc_opts * enc_opts)31590a6e7778SPieter Jansen van Vuuren static int fl_dump_key_geneve_opt(struct sk_buff *skb,
31600a6e7778SPieter Jansen van Vuuren 				  struct flow_dissector_key_enc_opts *enc_opts)
31610a6e7778SPieter Jansen van Vuuren {
31620a6e7778SPieter Jansen van Vuuren 	struct geneve_opt *opt;
31630a6e7778SPieter Jansen van Vuuren 	struct nlattr *nest;
31640a6e7778SPieter Jansen van Vuuren 	int opt_off = 0;
31650a6e7778SPieter Jansen van Vuuren 
3166ae0be8deSMichal Kubecek 	nest = nla_nest_start_noflag(skb, TCA_FLOWER_KEY_ENC_OPTS_GENEVE);
31670a6e7778SPieter Jansen van Vuuren 	if (!nest)
31680a6e7778SPieter Jansen van Vuuren 		goto nla_put_failure;
31690a6e7778SPieter Jansen van Vuuren 
31700a6e7778SPieter Jansen van Vuuren 	while (enc_opts->len > opt_off) {
31710a6e7778SPieter Jansen van Vuuren 		opt = (struct geneve_opt *)&enc_opts->data[opt_off];
31720a6e7778SPieter Jansen van Vuuren 
31730a6e7778SPieter Jansen van Vuuren 		if (nla_put_be16(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS,
31740a6e7778SPieter Jansen van Vuuren 				 opt->opt_class))
31750a6e7778SPieter Jansen van Vuuren 			goto nla_put_failure;
31760a6e7778SPieter Jansen van Vuuren 		if (nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE,
31770a6e7778SPieter Jansen van Vuuren 			       opt->type))
31780a6e7778SPieter Jansen van Vuuren 			goto nla_put_failure;
31790a6e7778SPieter Jansen van Vuuren 		if (nla_put(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA,
31800a6e7778SPieter Jansen van Vuuren 			    opt->length * 4, opt->opt_data))
31810a6e7778SPieter Jansen van Vuuren 			goto nla_put_failure;
31820a6e7778SPieter Jansen van Vuuren 
31830a6e7778SPieter Jansen van Vuuren 		opt_off += sizeof(struct geneve_opt) + opt->length * 4;
31840a6e7778SPieter Jansen van Vuuren 	}
31850a6e7778SPieter Jansen van Vuuren 	nla_nest_end(skb, nest);
31860a6e7778SPieter Jansen van Vuuren 	return 0;
31870a6e7778SPieter Jansen van Vuuren 
31880a6e7778SPieter Jansen van Vuuren nla_put_failure:
31890a6e7778SPieter Jansen van Vuuren 	nla_nest_cancel(skb, nest);
31900a6e7778SPieter Jansen van Vuuren 	return -EMSGSIZE;
31910a6e7778SPieter Jansen van Vuuren }
31920a6e7778SPieter Jansen van Vuuren 
fl_dump_key_vxlan_opt(struct sk_buff * skb,struct flow_dissector_key_enc_opts * enc_opts)3193d8f9dfaeSXin Long static int fl_dump_key_vxlan_opt(struct sk_buff *skb,
3194d8f9dfaeSXin Long 				 struct flow_dissector_key_enc_opts *enc_opts)
3195d8f9dfaeSXin Long {
3196d8f9dfaeSXin Long 	struct vxlan_metadata *md;
3197d8f9dfaeSXin Long 	struct nlattr *nest;
3198d8f9dfaeSXin Long 
3199d8f9dfaeSXin Long 	nest = nla_nest_start_noflag(skb, TCA_FLOWER_KEY_ENC_OPTS_VXLAN);
3200d8f9dfaeSXin Long 	if (!nest)
3201d8f9dfaeSXin Long 		goto nla_put_failure;
3202d8f9dfaeSXin Long 
3203d8f9dfaeSXin Long 	md = (struct vxlan_metadata *)&enc_opts->data[0];
3204d8f9dfaeSXin Long 	if (nla_put_u32(skb, TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP, md->gbp))
3205d8f9dfaeSXin Long 		goto nla_put_failure;
3206d8f9dfaeSXin Long 
3207d8f9dfaeSXin Long 	nla_nest_end(skb, nest);
3208d8f9dfaeSXin Long 	return 0;
3209d8f9dfaeSXin Long 
3210d8f9dfaeSXin Long nla_put_failure:
3211d8f9dfaeSXin Long 	nla_nest_cancel(skb, nest);
3212d8f9dfaeSXin Long 	return -EMSGSIZE;
3213d8f9dfaeSXin Long }
3214d8f9dfaeSXin Long 
fl_dump_key_erspan_opt(struct sk_buff * skb,struct flow_dissector_key_enc_opts * enc_opts)321579b1011cSXin Long static int fl_dump_key_erspan_opt(struct sk_buff *skb,
321679b1011cSXin Long 				  struct flow_dissector_key_enc_opts *enc_opts)
321779b1011cSXin Long {
321879b1011cSXin Long 	struct erspan_metadata *md;
321979b1011cSXin Long 	struct nlattr *nest;
322079b1011cSXin Long 
322179b1011cSXin Long 	nest = nla_nest_start_noflag(skb, TCA_FLOWER_KEY_ENC_OPTS_ERSPAN);
322279b1011cSXin Long 	if (!nest)
322379b1011cSXin Long 		goto nla_put_failure;
322479b1011cSXin Long 
322579b1011cSXin Long 	md = (struct erspan_metadata *)&enc_opts->data[0];
322679b1011cSXin Long 	if (nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER, md->version))
322779b1011cSXin Long 		goto nla_put_failure;
322879b1011cSXin Long 
322979b1011cSXin Long 	if (md->version == 1 &&
323079b1011cSXin Long 	    nla_put_be32(skb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX, md->u.index))
323179b1011cSXin Long 		goto nla_put_failure;
323279b1011cSXin Long 
323379b1011cSXin Long 	if (md->version == 2 &&
323479b1011cSXin Long 	    (nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR,
323579b1011cSXin Long 			md->u.md2.dir) ||
323679b1011cSXin Long 	     nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID,
323779b1011cSXin Long 			get_hwid(&md->u.md2))))
323879b1011cSXin Long 		goto nla_put_failure;
323979b1011cSXin Long 
324079b1011cSXin Long 	nla_nest_end(skb, nest);
324179b1011cSXin Long 	return 0;
324279b1011cSXin Long 
324379b1011cSXin Long nla_put_failure:
324479b1011cSXin Long 	nla_nest_cancel(skb, nest);
324579b1011cSXin Long 	return -EMSGSIZE;
324679b1011cSXin Long }
324779b1011cSXin Long 
fl_dump_key_gtp_opt(struct sk_buff * skb,struct flow_dissector_key_enc_opts * enc_opts)3248e3acda7aSWojciech Drewek static int fl_dump_key_gtp_opt(struct sk_buff *skb,
3249e3acda7aSWojciech Drewek 			       struct flow_dissector_key_enc_opts *enc_opts)
3250e3acda7aSWojciech Drewek 
3251e3acda7aSWojciech Drewek {
3252e3acda7aSWojciech Drewek 	struct gtp_pdu_session_info *session_info;
3253e3acda7aSWojciech Drewek 	struct nlattr *nest;
3254e3acda7aSWojciech Drewek 
3255e3acda7aSWojciech Drewek 	nest = nla_nest_start_noflag(skb, TCA_FLOWER_KEY_ENC_OPTS_GTP);
3256e3acda7aSWojciech Drewek 	if (!nest)
3257e3acda7aSWojciech Drewek 		goto nla_put_failure;
3258e3acda7aSWojciech Drewek 
3259e3acda7aSWojciech Drewek 	session_info = (struct gtp_pdu_session_info *)&enc_opts->data[0];
3260e3acda7aSWojciech Drewek 
3261e3acda7aSWojciech Drewek 	if (nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_GTP_PDU_TYPE,
3262e3acda7aSWojciech Drewek 		       session_info->pdu_type))
3263e3acda7aSWojciech Drewek 		goto nla_put_failure;
3264e3acda7aSWojciech Drewek 
3265e3acda7aSWojciech Drewek 	if (nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_GTP_QFI, session_info->qfi))
3266e3acda7aSWojciech Drewek 		goto nla_put_failure;
3267e3acda7aSWojciech Drewek 
3268e3acda7aSWojciech Drewek 	nla_nest_end(skb, nest);
3269e3acda7aSWojciech Drewek 	return 0;
3270e3acda7aSWojciech Drewek 
3271e3acda7aSWojciech Drewek nla_put_failure:
3272e3acda7aSWojciech Drewek 	nla_nest_cancel(skb, nest);
3273e3acda7aSWojciech Drewek 	return -EMSGSIZE;
3274e3acda7aSWojciech Drewek }
3275e3acda7aSWojciech Drewek 
fl_dump_key_pfcp_opt(struct sk_buff * skb,struct flow_dissector_key_enc_opts * enc_opts)32766dd514f4SMichal Swiatkowski static int fl_dump_key_pfcp_opt(struct sk_buff *skb,
32776dd514f4SMichal Swiatkowski 				struct flow_dissector_key_enc_opts *enc_opts)
32786dd514f4SMichal Swiatkowski {
32796dd514f4SMichal Swiatkowski 	struct pfcp_metadata *md;
32806dd514f4SMichal Swiatkowski 	struct nlattr *nest;
32816dd514f4SMichal Swiatkowski 
32826dd514f4SMichal Swiatkowski 	nest = nla_nest_start_noflag(skb, TCA_FLOWER_KEY_ENC_OPTS_PFCP);
32836dd514f4SMichal Swiatkowski 	if (!nest)
32846dd514f4SMichal Swiatkowski 		goto nla_put_failure;
32856dd514f4SMichal Swiatkowski 
32866dd514f4SMichal Swiatkowski 	md = (struct pfcp_metadata *)&enc_opts->data[0];
32876dd514f4SMichal Swiatkowski 	if (nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_PFCP_TYPE, md->type))
32886dd514f4SMichal Swiatkowski 		goto nla_put_failure;
32896dd514f4SMichal Swiatkowski 
32906dd514f4SMichal Swiatkowski 	if (nla_put_be64(skb, TCA_FLOWER_KEY_ENC_OPT_PFCP_SEID,
32916dd514f4SMichal Swiatkowski 			 md->seid, 0))
32926dd514f4SMichal Swiatkowski 		goto nla_put_failure;
32936dd514f4SMichal Swiatkowski 
32946dd514f4SMichal Swiatkowski 	nla_nest_end(skb, nest);
32956dd514f4SMichal Swiatkowski 	return 0;
32966dd514f4SMichal Swiatkowski 
32976dd514f4SMichal Swiatkowski nla_put_failure:
32986dd514f4SMichal Swiatkowski 	nla_nest_cancel(skb, nest);
32996dd514f4SMichal Swiatkowski 	return -EMSGSIZE;
33006dd514f4SMichal Swiatkowski }
33016dd514f4SMichal Swiatkowski 
fl_dump_key_ct(struct sk_buff * skb,struct flow_dissector_key_ct * key,struct flow_dissector_key_ct * mask)3302e0ace68aSPaul Blakey static int fl_dump_key_ct(struct sk_buff *skb,
3303e0ace68aSPaul Blakey 			  struct flow_dissector_key_ct *key,
3304e0ace68aSPaul Blakey 			  struct flow_dissector_key_ct *mask)
3305e0ace68aSPaul Blakey {
3306e0ace68aSPaul Blakey 	if (IS_ENABLED(CONFIG_NF_CONNTRACK) &&
3307e0ace68aSPaul Blakey 	    fl_dump_key_val(skb, &key->ct_state, TCA_FLOWER_KEY_CT_STATE,
3308e0ace68aSPaul Blakey 			    &mask->ct_state, TCA_FLOWER_KEY_CT_STATE_MASK,
3309e0ace68aSPaul Blakey 			    sizeof(key->ct_state)))
3310e0ace68aSPaul Blakey 		goto nla_put_failure;
3311e0ace68aSPaul Blakey 
3312e0ace68aSPaul Blakey 	if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) &&
3313e0ace68aSPaul Blakey 	    fl_dump_key_val(skb, &key->ct_zone, TCA_FLOWER_KEY_CT_ZONE,
3314e0ace68aSPaul Blakey 			    &mask->ct_zone, TCA_FLOWER_KEY_CT_ZONE_MASK,
3315e0ace68aSPaul Blakey 			    sizeof(key->ct_zone)))
3316e0ace68aSPaul Blakey 		goto nla_put_failure;
3317e0ace68aSPaul Blakey 
3318e0ace68aSPaul Blakey 	if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) &&
3319e0ace68aSPaul Blakey 	    fl_dump_key_val(skb, &key->ct_mark, TCA_FLOWER_KEY_CT_MARK,
3320e0ace68aSPaul Blakey 			    &mask->ct_mark, TCA_FLOWER_KEY_CT_MARK_MASK,
3321e0ace68aSPaul Blakey 			    sizeof(key->ct_mark)))
3322e0ace68aSPaul Blakey 		goto nla_put_failure;
3323e0ace68aSPaul Blakey 
3324e0ace68aSPaul Blakey 	if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) &&
3325e0ace68aSPaul Blakey 	    fl_dump_key_val(skb, &key->ct_labels, TCA_FLOWER_KEY_CT_LABELS,
3326e0ace68aSPaul Blakey 			    &mask->ct_labels, TCA_FLOWER_KEY_CT_LABELS_MASK,
3327e0ace68aSPaul Blakey 			    sizeof(key->ct_labels)))
3328e0ace68aSPaul Blakey 		goto nla_put_failure;
3329e0ace68aSPaul Blakey 
3330e0ace68aSPaul Blakey 	return 0;
3331e0ace68aSPaul Blakey 
3332e0ace68aSPaul Blakey nla_put_failure:
3333e0ace68aSPaul Blakey 	return -EMSGSIZE;
3334e0ace68aSPaul Blakey }
3335e0ace68aSPaul Blakey 
fl_dump_key_cfm(struct sk_buff * skb,struct flow_dissector_key_cfm * key,struct flow_dissector_key_cfm * mask)33367cfffd5fSZahari Doychev static int fl_dump_key_cfm(struct sk_buff *skb,
33377cfffd5fSZahari Doychev 			   struct flow_dissector_key_cfm *key,
33387cfffd5fSZahari Doychev 			   struct flow_dissector_key_cfm *mask)
33397cfffd5fSZahari Doychev {
33407cfffd5fSZahari Doychev 	struct nlattr *opts;
33417cfffd5fSZahari Doychev 	int err;
33427cfffd5fSZahari Doychev 	u8 mdl;
33437cfffd5fSZahari Doychev 
33447cfffd5fSZahari Doychev 	if (!memchr_inv(mask, 0, sizeof(*mask)))
33457cfffd5fSZahari Doychev 		return 0;
33467cfffd5fSZahari Doychev 
33477cfffd5fSZahari Doychev 	opts = nla_nest_start(skb, TCA_FLOWER_KEY_CFM);
33487cfffd5fSZahari Doychev 	if (!opts)
33497cfffd5fSZahari Doychev 		return -EMSGSIZE;
33507cfffd5fSZahari Doychev 
33517cfffd5fSZahari Doychev 	if (FIELD_GET(FLOW_DIS_CFM_MDL_MASK, mask->mdl_ver)) {
33527cfffd5fSZahari Doychev 		mdl = FIELD_GET(FLOW_DIS_CFM_MDL_MASK, key->mdl_ver);
33537cfffd5fSZahari Doychev 		err = nla_put_u8(skb, TCA_FLOWER_KEY_CFM_MD_LEVEL, mdl);
33547cfffd5fSZahari Doychev 		if (err)
33557cfffd5fSZahari Doychev 			goto err_cfm_opts;
33567cfffd5fSZahari Doychev 	}
33577cfffd5fSZahari Doychev 
33587cfffd5fSZahari Doychev 	if (mask->opcode) {
33597cfffd5fSZahari Doychev 		err = nla_put_u8(skb, TCA_FLOWER_KEY_CFM_OPCODE, key->opcode);
33607cfffd5fSZahari Doychev 		if (err)
33617cfffd5fSZahari Doychev 			goto err_cfm_opts;
33627cfffd5fSZahari Doychev 	}
33637cfffd5fSZahari Doychev 
33647cfffd5fSZahari Doychev 	nla_nest_end(skb, opts);
33657cfffd5fSZahari Doychev 
33667cfffd5fSZahari Doychev 	return 0;
33677cfffd5fSZahari Doychev 
33687cfffd5fSZahari Doychev err_cfm_opts:
33697cfffd5fSZahari Doychev 	nla_nest_cancel(skb, opts);
33707cfffd5fSZahari Doychev 	return err;
33717cfffd5fSZahari Doychev }
33727cfffd5fSZahari Doychev 
fl_dump_key_options(struct sk_buff * skb,int enc_opt_type,struct flow_dissector_key_enc_opts * enc_opts)33730a6e7778SPieter Jansen van Vuuren static int fl_dump_key_options(struct sk_buff *skb, int enc_opt_type,
33740a6e7778SPieter Jansen van Vuuren 			       struct flow_dissector_key_enc_opts *enc_opts)
33750a6e7778SPieter Jansen van Vuuren {
33760a6e7778SPieter Jansen van Vuuren 	struct nlattr *nest;
33770a6e7778SPieter Jansen van Vuuren 	int err;
33780a6e7778SPieter Jansen van Vuuren 
33790a6e7778SPieter Jansen van Vuuren 	if (!enc_opts->len)
33800a6e7778SPieter Jansen van Vuuren 		return 0;
33810a6e7778SPieter Jansen van Vuuren 
3382ae0be8deSMichal Kubecek 	nest = nla_nest_start_noflag(skb, enc_opt_type);
33830a6e7778SPieter Jansen van Vuuren 	if (!nest)
33840a6e7778SPieter Jansen van Vuuren 		goto nla_put_failure;
33850a6e7778SPieter Jansen van Vuuren 
33860a6e7778SPieter Jansen van Vuuren 	switch (enc_opts->dst_opt_type) {
33875832c4a7SAlexander Lobakin 	case IP_TUNNEL_GENEVE_OPT_BIT:
33880a6e7778SPieter Jansen van Vuuren 		err = fl_dump_key_geneve_opt(skb, enc_opts);
33890a6e7778SPieter Jansen van Vuuren 		if (err)
33900a6e7778SPieter Jansen van Vuuren 			goto nla_put_failure;
33910a6e7778SPieter Jansen van Vuuren 		break;
33925832c4a7SAlexander Lobakin 	case IP_TUNNEL_VXLAN_OPT_BIT:
3393d8f9dfaeSXin Long 		err = fl_dump_key_vxlan_opt(skb, enc_opts);
3394d8f9dfaeSXin Long 		if (err)
3395d8f9dfaeSXin Long 			goto nla_put_failure;
3396d8f9dfaeSXin Long 		break;
33975832c4a7SAlexander Lobakin 	case IP_TUNNEL_ERSPAN_OPT_BIT:
339879b1011cSXin Long 		err = fl_dump_key_erspan_opt(skb, enc_opts);
339979b1011cSXin Long 		if (err)
340079b1011cSXin Long 			goto nla_put_failure;
340179b1011cSXin Long 		break;
34025832c4a7SAlexander Lobakin 	case IP_TUNNEL_GTP_OPT_BIT:
3403e3acda7aSWojciech Drewek 		err = fl_dump_key_gtp_opt(skb, enc_opts);
3404e3acda7aSWojciech Drewek 		if (err)
3405e3acda7aSWojciech Drewek 			goto nla_put_failure;
3406e3acda7aSWojciech Drewek 		break;
34076dd514f4SMichal Swiatkowski 	case IP_TUNNEL_PFCP_OPT_BIT:
34086dd514f4SMichal Swiatkowski 		err = fl_dump_key_pfcp_opt(skb, enc_opts);
34096dd514f4SMichal Swiatkowski 		if (err)
34106dd514f4SMichal Swiatkowski 			goto nla_put_failure;
34116dd514f4SMichal Swiatkowski 		break;
34120a6e7778SPieter Jansen van Vuuren 	default:
34130a6e7778SPieter Jansen van Vuuren 		goto nla_put_failure;
34140a6e7778SPieter Jansen van Vuuren 	}
34150a6e7778SPieter Jansen van Vuuren 	nla_nest_end(skb, nest);
34160a6e7778SPieter Jansen van Vuuren 	return 0;
34170a6e7778SPieter Jansen van Vuuren 
34180a6e7778SPieter Jansen van Vuuren nla_put_failure:
34190a6e7778SPieter Jansen van Vuuren 	nla_nest_cancel(skb, nest);
34200a6e7778SPieter Jansen van Vuuren 	return -EMSGSIZE;
34210a6e7778SPieter Jansen van Vuuren }
34220a6e7778SPieter Jansen van Vuuren 
fl_dump_key_enc_opt(struct sk_buff * skb,struct flow_dissector_key_enc_opts * key_opts,struct flow_dissector_key_enc_opts * msk_opts)34230a6e7778SPieter Jansen van Vuuren static int fl_dump_key_enc_opt(struct sk_buff *skb,
34240a6e7778SPieter Jansen van Vuuren 			       struct flow_dissector_key_enc_opts *key_opts,
34250a6e7778SPieter Jansen van Vuuren 			       struct flow_dissector_key_enc_opts *msk_opts)
34260a6e7778SPieter Jansen van Vuuren {
34270a6e7778SPieter Jansen van Vuuren 	int err;
34280a6e7778SPieter Jansen van Vuuren 
34290a6e7778SPieter Jansen van Vuuren 	err = fl_dump_key_options(skb, TCA_FLOWER_KEY_ENC_OPTS, key_opts);
34300a6e7778SPieter Jansen van Vuuren 	if (err)
34310a6e7778SPieter Jansen van Vuuren 		return err;
34320a6e7778SPieter Jansen van Vuuren 
34330a6e7778SPieter Jansen van Vuuren 	return fl_dump_key_options(skb, TCA_FLOWER_KEY_ENC_OPTS_MASK, msk_opts);
34340a6e7778SPieter Jansen van Vuuren }
34350a6e7778SPieter Jansen van Vuuren 
fl_dump_key(struct sk_buff * skb,struct net * net,struct fl_flow_key * key,struct fl_flow_key * mask)3436f5749081SJiri Pirko static int fl_dump_key(struct sk_buff *skb, struct net *net,
3437f5749081SJiri Pirko 		       struct fl_flow_key *key, struct fl_flow_key *mask)
343877b9900eSJiri Pirko {
34398212ed77SJiri Pirko 	if (mask->meta.ingress_ifindex) {
344077b9900eSJiri Pirko 		struct net_device *dev;
344177b9900eSJiri Pirko 
34428212ed77SJiri Pirko 		dev = __dev_get_by_index(net, key->meta.ingress_ifindex);
344377b9900eSJiri Pirko 		if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name))
344477b9900eSJiri Pirko 			goto nla_put_failure;
344577b9900eSJiri Pirko 	}
344677b9900eSJiri Pirko 
34471a432018SIdo Schimmel 	if (fl_dump_key_val(skb, &key->meta.l2_miss,
34481a432018SIdo Schimmel 			    TCA_FLOWER_L2_MISS, &mask->meta.l2_miss,
34491a432018SIdo Schimmel 			    TCA_FLOWER_UNSPEC, sizeof(key->meta.l2_miss)))
34501a432018SIdo Schimmel 		goto nla_put_failure;
34511a432018SIdo Schimmel 
345277b9900eSJiri Pirko 	if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
345377b9900eSJiri Pirko 			    mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
345477b9900eSJiri Pirko 			    sizeof(key->eth.dst)) ||
345577b9900eSJiri Pirko 	    fl_dump_key_val(skb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
345677b9900eSJiri Pirko 			    mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
345777b9900eSJiri Pirko 			    sizeof(key->eth.src)) ||
345877b9900eSJiri Pirko 	    fl_dump_key_val(skb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE,
345977b9900eSJiri Pirko 			    &mask->basic.n_proto, TCA_FLOWER_UNSPEC,
346077b9900eSJiri Pirko 			    sizeof(key->basic.n_proto)))
346177b9900eSJiri Pirko 		goto nla_put_failure;
34629399ae9aSHadar Hen Zion 
3463b4000312SBoris Sukholitko 	if (mask->num_of_vlans.num_of_vlans) {
3464b4000312SBoris Sukholitko 		if (nla_put_u8(skb, TCA_FLOWER_KEY_NUM_OF_VLANS, key->num_of_vlans.num_of_vlans))
3465b4000312SBoris Sukholitko 			goto nla_put_failure;
3466b4000312SBoris Sukholitko 	}
3467b4000312SBoris Sukholitko 
3468a577d8f7SBenjamin LaHaise 	if (fl_dump_key_mpls(skb, &key->mpls, &mask->mpls))
3469a577d8f7SBenjamin LaHaise 		goto nla_put_failure;
3470a577d8f7SBenjamin LaHaise 
3471d64efd09SJianbo Liu 	if (fl_dump_key_vlan(skb, TCA_FLOWER_KEY_VLAN_ID,
3472d64efd09SJianbo Liu 			     TCA_FLOWER_KEY_VLAN_PRIO, &key->vlan, &mask->vlan))
34739399ae9aSHadar Hen Zion 		goto nla_put_failure;
34749399ae9aSHadar Hen Zion 
3475d64efd09SJianbo Liu 	if (fl_dump_key_vlan(skb, TCA_FLOWER_KEY_CVLAN_ID,
3476d64efd09SJianbo Liu 			     TCA_FLOWER_KEY_CVLAN_PRIO,
3477d64efd09SJianbo Liu 			     &key->cvlan, &mask->cvlan) ||
3478d64efd09SJianbo Liu 	    (mask->cvlan.vlan_tpid &&
3479158abbf1SJianbo Liu 	     nla_put_be16(skb, TCA_FLOWER_KEY_VLAN_ETH_TYPE,
3480d64efd09SJianbo Liu 			  key->cvlan.vlan_tpid)))
3481d3069512SJianbo Liu 		goto nla_put_failure;
3482d3069512SJianbo Liu 
34835e9a0fe4SJianbo Liu 	if (mask->basic.n_proto) {
34842105f700SVlad Buslov 		if (mask->cvlan.vlan_eth_type) {
3485d64efd09SJianbo Liu 			if (nla_put_be16(skb, TCA_FLOWER_KEY_CVLAN_ETH_TYPE,
3486d64efd09SJianbo Liu 					 key->basic.n_proto))
3487d64efd09SJianbo Liu 				goto nla_put_failure;
34882105f700SVlad Buslov 		} else if (mask->vlan.vlan_eth_type) {
3489d64efd09SJianbo Liu 			if (nla_put_be16(skb, TCA_FLOWER_KEY_VLAN_ETH_TYPE,
34902105f700SVlad Buslov 					 key->vlan.vlan_eth_type))
3491d64efd09SJianbo Liu 				goto nla_put_failure;
3492d64efd09SJianbo Liu 		}
34935e9a0fe4SJianbo Liu 	}
3494d64efd09SJianbo Liu 
349577b9900eSJiri Pirko 	if ((key->basic.n_proto == htons(ETH_P_IP) ||
349677b9900eSJiri Pirko 	     key->basic.n_proto == htons(ETH_P_IPV6)) &&
34974d80cc0aSOr Gerlitz 	    (fl_dump_key_val(skb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
349877b9900eSJiri Pirko 			    &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
34994d80cc0aSOr Gerlitz 			    sizeof(key->basic.ip_proto)) ||
35000e2c17b6SOr Gerlitz 	    fl_dump_key_ip(skb, false, &key->ip, &mask->ip)))
350177b9900eSJiri Pirko 		goto nla_put_failure;
350277b9900eSJiri Pirko 
35035008750eSWojciech Drewek 	if (mask->pppoe.session_id) {
35045008750eSWojciech Drewek 		if (nla_put_be16(skb, TCA_FLOWER_KEY_PPPOE_SID,
35055008750eSWojciech Drewek 				 key->pppoe.session_id))
35065008750eSWojciech Drewek 			goto nla_put_failure;
35075008750eSWojciech Drewek 	}
35085008750eSWojciech Drewek 	if (mask->basic.n_proto && mask->pppoe.ppp_proto) {
35095008750eSWojciech Drewek 		if (nla_put_be16(skb, TCA_FLOWER_KEY_PPP_PROTO,
35105008750eSWojciech Drewek 				 key->pppoe.ppp_proto))
35115008750eSWojciech Drewek 			goto nla_put_failure;
35125008750eSWojciech Drewek 	}
35135008750eSWojciech Drewek 
3514c3f83241STom Herbert 	if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
351577b9900eSJiri Pirko 	    (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
351677b9900eSJiri Pirko 			     &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
351777b9900eSJiri Pirko 			     sizeof(key->ipv4.src)) ||
351877b9900eSJiri Pirko 	     fl_dump_key_val(skb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
351977b9900eSJiri Pirko 			     &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
352077b9900eSJiri Pirko 			     sizeof(key->ipv4.dst))))
352177b9900eSJiri Pirko 		goto nla_put_failure;
3522c3f83241STom Herbert 	else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
352377b9900eSJiri Pirko 		 (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
352477b9900eSJiri Pirko 				  &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
352577b9900eSJiri Pirko 				  sizeof(key->ipv6.src)) ||
352677b9900eSJiri Pirko 		  fl_dump_key_val(skb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
352777b9900eSJiri Pirko 				  &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
352877b9900eSJiri Pirko 				  sizeof(key->ipv6.dst))))
352977b9900eSJiri Pirko 		goto nla_put_failure;
353077b9900eSJiri Pirko 
353177b9900eSJiri Pirko 	if (key->basic.ip_proto == IPPROTO_TCP &&
353277b9900eSJiri Pirko 	    (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
3533aa72d708SOr Gerlitz 			     &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
353477b9900eSJiri Pirko 			     sizeof(key->tp.src)) ||
353577b9900eSJiri Pirko 	     fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
3536aa72d708SOr Gerlitz 			     &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
3537fdfc7dd6SJiri Pirko 			     sizeof(key->tp.dst)) ||
3538fdfc7dd6SJiri Pirko 	     fl_dump_key_val(skb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS,
3539fdfc7dd6SJiri Pirko 			     &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK,
3540fdfc7dd6SJiri Pirko 			     sizeof(key->tcp.flags))))
354177b9900eSJiri Pirko 		goto nla_put_failure;
354277b9900eSJiri Pirko 	else if (key->basic.ip_proto == IPPROTO_UDP &&
354377b9900eSJiri Pirko 		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
3544aa72d708SOr Gerlitz 				  &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
354577b9900eSJiri Pirko 				  sizeof(key->tp.src)) ||
354677b9900eSJiri Pirko 		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
3547aa72d708SOr Gerlitz 				  &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
354877b9900eSJiri Pirko 				  sizeof(key->tp.dst))))
354977b9900eSJiri Pirko 		goto nla_put_failure;
35505976c5f4SSimon Horman 	else if (key->basic.ip_proto == IPPROTO_SCTP &&
35515976c5f4SSimon Horman 		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
35525976c5f4SSimon Horman 				  &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
35535976c5f4SSimon Horman 				  sizeof(key->tp.src)) ||
35545976c5f4SSimon Horman 		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
35555976c5f4SSimon Horman 				  &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
35565976c5f4SSimon Horman 				  sizeof(key->tp.dst))))
35575976c5f4SSimon Horman 		goto nla_put_failure;
35587b684884SSimon Horman 	else if (key->basic.n_proto == htons(ETH_P_IP) &&
35597b684884SSimon Horman 		 key->basic.ip_proto == IPPROTO_ICMP &&
35607b684884SSimon Horman 		 (fl_dump_key_val(skb, &key->icmp.type,
35617b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_TYPE, &mask->icmp.type,
35627b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,
35637b684884SSimon Horman 				  sizeof(key->icmp.type)) ||
35647b684884SSimon Horman 		  fl_dump_key_val(skb, &key->icmp.code,
35657b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_CODE, &mask->icmp.code,
35667b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
35677b684884SSimon Horman 				  sizeof(key->icmp.code))))
35687b684884SSimon Horman 		goto nla_put_failure;
35697b684884SSimon Horman 	else if (key->basic.n_proto == htons(ETH_P_IPV6) &&
35707b684884SSimon Horman 		 key->basic.ip_proto == IPPROTO_ICMPV6 &&
35717b684884SSimon Horman 		 (fl_dump_key_val(skb, &key->icmp.type,
35727b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_TYPE, &mask->icmp.type,
35737b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
35747b684884SSimon Horman 				  sizeof(key->icmp.type)) ||
35757b684884SSimon Horman 		  fl_dump_key_val(skb, &key->icmp.code,
35767b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_CODE, &mask->icmp.code,
35777b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_CODE_MASK,
35787b684884SSimon Horman 				  sizeof(key->icmp.code))))
35797b684884SSimon Horman 		goto nla_put_failure;
358099d31326SSimon Horman 	else if ((key->basic.n_proto == htons(ETH_P_ARP) ||
358199d31326SSimon Horman 		  key->basic.n_proto == htons(ETH_P_RARP)) &&
358299d31326SSimon Horman 		 (fl_dump_key_val(skb, &key->arp.sip,
358399d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_SIP, &mask->arp.sip,
358499d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_SIP_MASK,
358599d31326SSimon Horman 				  sizeof(key->arp.sip)) ||
358699d31326SSimon Horman 		  fl_dump_key_val(skb, &key->arp.tip,
358799d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_TIP, &mask->arp.tip,
358899d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_TIP_MASK,
358999d31326SSimon Horman 				  sizeof(key->arp.tip)) ||
359099d31326SSimon Horman 		  fl_dump_key_val(skb, &key->arp.op,
359199d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_OP, &mask->arp.op,
359299d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_OP_MASK,
359399d31326SSimon Horman 				  sizeof(key->arp.op)) ||
359499d31326SSimon Horman 		  fl_dump_key_val(skb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA,
359599d31326SSimon Horman 				  mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK,
359699d31326SSimon Horman 				  sizeof(key->arp.sha)) ||
359799d31326SSimon Horman 		  fl_dump_key_val(skb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA,
359899d31326SSimon Horman 				  mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK,
359999d31326SSimon Horman 				  sizeof(key->arp.tha))))
360099d31326SSimon Horman 		goto nla_put_failure;
36018b189ea0SWojciech Drewek 	else if (key->basic.ip_proto == IPPROTO_L2TP &&
36028b189ea0SWojciech Drewek 		 fl_dump_key_val(skb, &key->l2tpv3.session_id,
36038b189ea0SWojciech Drewek 				 TCA_FLOWER_KEY_L2TPV3_SID,
36048b189ea0SWojciech Drewek 				 &mask->l2tpv3.session_id,
36058b189ea0SWojciech Drewek 				 TCA_FLOWER_UNSPEC,
36068b189ea0SWojciech Drewek 				 sizeof(key->l2tpv3.session_id)))
36078b189ea0SWojciech Drewek 		goto nla_put_failure;
360877b9900eSJiri Pirko 
36094c13eda7SRatheesh Kannoth 	if (key->ipsec.spi &&
36104c13eda7SRatheesh Kannoth 	    fl_dump_key_val(skb, &key->ipsec.spi, TCA_FLOWER_KEY_SPI,
36114c13eda7SRatheesh Kannoth 			    &mask->ipsec.spi, TCA_FLOWER_KEY_SPI_MASK,
36124c13eda7SRatheesh Kannoth 			    sizeof(key->ipsec.spi)))
36134c13eda7SRatheesh Kannoth 		goto nla_put_failure;
36144c13eda7SRatheesh Kannoth 
36155c72299fSAmritha Nambiar 	if ((key->basic.ip_proto == IPPROTO_TCP ||
36165c72299fSAmritha Nambiar 	     key->basic.ip_proto == IPPROTO_UDP ||
36175c72299fSAmritha Nambiar 	     key->basic.ip_proto == IPPROTO_SCTP) &&
36185c72299fSAmritha Nambiar 	     fl_dump_key_port_range(skb, key, mask))
36195c72299fSAmritha Nambiar 		goto nla_put_failure;
36205c72299fSAmritha Nambiar 
3621bc3103f1SAmir Vadai 	if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
3622bc3103f1SAmir Vadai 	    (fl_dump_key_val(skb, &key->enc_ipv4.src,
3623bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV4_SRC, &mask->enc_ipv4.src,
3624bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
3625bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv4.src)) ||
3626bc3103f1SAmir Vadai 	     fl_dump_key_val(skb, &key->enc_ipv4.dst,
3627bc3103f1SAmir Vadai 			     TCA_FLOWER_KEY_ENC_IPV4_DST, &mask->enc_ipv4.dst,
3628bc3103f1SAmir Vadai 			     TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
3629bc3103f1SAmir Vadai 			     sizeof(key->enc_ipv4.dst))))
3630bc3103f1SAmir Vadai 		goto nla_put_failure;
3631bc3103f1SAmir Vadai 	else if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
3632bc3103f1SAmir Vadai 		 (fl_dump_key_val(skb, &key->enc_ipv6.src,
3633bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV6_SRC, &mask->enc_ipv6.src,
3634bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
3635bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv6.src)) ||
3636bc3103f1SAmir Vadai 		 fl_dump_key_val(skb, &key->enc_ipv6.dst,
3637bc3103f1SAmir Vadai 				 TCA_FLOWER_KEY_ENC_IPV6_DST,
3638bc3103f1SAmir Vadai 				 &mask->enc_ipv6.dst,
3639bc3103f1SAmir Vadai 				 TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
3640bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv6.dst))))
3641bc3103f1SAmir Vadai 		goto nla_put_failure;
3642bc3103f1SAmir Vadai 
3643bc3103f1SAmir Vadai 	if (fl_dump_key_val(skb, &key->enc_key_id, TCA_FLOWER_KEY_ENC_KEY_ID,
3644eb523f42SHadar Hen Zion 			    &mask->enc_key_id, TCA_FLOWER_UNSPEC,
3645f4d997fdSHadar Hen Zion 			    sizeof(key->enc_key_id)) ||
3646f4d997fdSHadar Hen Zion 	    fl_dump_key_val(skb, &key->enc_tp.src,
3647f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
3648f4d997fdSHadar Hen Zion 			    &mask->enc_tp.src,
3649f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
3650f4d997fdSHadar Hen Zion 			    sizeof(key->enc_tp.src)) ||
3651f4d997fdSHadar Hen Zion 	    fl_dump_key_val(skb, &key->enc_tp.dst,
3652f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
3653f4d997fdSHadar Hen Zion 			    &mask->enc_tp.dst,
3654f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
36550e2c17b6SOr Gerlitz 			    sizeof(key->enc_tp.dst)) ||
36560a6e7778SPieter Jansen van Vuuren 	    fl_dump_key_ip(skb, true, &key->enc_ip, &mask->enc_ip) ||
36570a6e7778SPieter Jansen van Vuuren 	    fl_dump_key_enc_opt(skb, &key->enc_opts, &mask->enc_opts))
3658bc3103f1SAmir Vadai 		goto nla_put_failure;
3659bc3103f1SAmir Vadai 
3660e0ace68aSPaul Blakey 	if (fl_dump_key_ct(skb, &key->ct, &mask->ct))
3661e0ace68aSPaul Blakey 		goto nla_put_failure;
3662e0ace68aSPaul Blakey 
3663fcb4bb07SAsbjørn Sloth Tønnesen 	if (fl_dump_key_flags(skb, false, key->control.flags,
3664fcb4bb07SAsbjørn Sloth Tønnesen 			      mask->control.flags))
3665faa3ffceSOr Gerlitz 		goto nla_put_failure;
3666faa3ffceSOr Gerlitz 
36675923b8f7SAriel Levkovich 	if (fl_dump_key_val(skb, &key->hash.hash, TCA_FLOWER_KEY_HASH,
36685923b8f7SAriel Levkovich 			     &mask->hash.hash, TCA_FLOWER_KEY_HASH_MASK,
36695923b8f7SAriel Levkovich 			     sizeof(key->hash.hash)))
36705923b8f7SAriel Levkovich 		goto nla_put_failure;
36715923b8f7SAriel Levkovich 
36727cfffd5fSZahari Doychev 	if (fl_dump_key_cfm(skb, &key->cfm, &mask->cfm))
36737cfffd5fSZahari Doychev 		goto nla_put_failure;
36747cfffd5fSZahari Doychev 
367511036bd7SAsbjørn Sloth Tønnesen 	if (fl_dump_key_flags(skb, true, key->enc_control.flags,
367611036bd7SAsbjørn Sloth Tønnesen 			      mask->enc_control.flags))
36771d17568eSDavide Caratti 		goto nla_put_failure;
36781d17568eSDavide Caratti 
3679f5749081SJiri Pirko 	return 0;
3680f5749081SJiri Pirko 
3681f5749081SJiri Pirko nla_put_failure:
3682f5749081SJiri Pirko 	return -EMSGSIZE;
3683f5749081SJiri Pirko }
3684f5749081SJiri Pirko 
fl_dump(struct net * net,struct tcf_proto * tp,void * fh,struct sk_buff * skb,struct tcmsg * t,bool rtnl_held)3685f5749081SJiri Pirko static int fl_dump(struct net *net, struct tcf_proto *tp, void *fh,
368612db03b6SVlad Buslov 		   struct sk_buff *skb, struct tcmsg *t, bool rtnl_held)
3687f5749081SJiri Pirko {
3688f5749081SJiri Pirko 	struct cls_fl_filter *f = fh;
3689f5749081SJiri Pirko 	struct nlattr *nest;
3690f5749081SJiri Pirko 	struct fl_flow_key *key, *mask;
36913d81e711SVlad Buslov 	bool skip_hw;
3692f5749081SJiri Pirko 
3693f5749081SJiri Pirko 	if (!f)
3694f5749081SJiri Pirko 		return skb->len;
3695f5749081SJiri Pirko 
3696f5749081SJiri Pirko 	t->tcm_handle = f->handle;
3697f5749081SJiri Pirko 
3698ae0be8deSMichal Kubecek 	nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
3699f5749081SJiri Pirko 	if (!nest)
3700f5749081SJiri Pirko 		goto nla_put_failure;
3701f5749081SJiri Pirko 
37023d81e711SVlad Buslov 	spin_lock(&tp->lock);
37033d81e711SVlad Buslov 
3704f5749081SJiri Pirko 	if (f->res.classid &&
3705f5749081SJiri Pirko 	    nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid))
37063d81e711SVlad Buslov 		goto nla_put_failure_locked;
3707f5749081SJiri Pirko 
3708f5749081SJiri Pirko 	key = &f->key;
3709f5749081SJiri Pirko 	mask = &f->mask->key;
37103d81e711SVlad Buslov 	skip_hw = tc_skip_hw(f->flags);
3711f5749081SJiri Pirko 
3712f5749081SJiri Pirko 	if (fl_dump_key(skb, net, key, mask))
37133d81e711SVlad Buslov 		goto nla_put_failure_locked;
3714f5749081SJiri Pirko 
3715749e6720SOr Gerlitz 	if (f->flags && nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags))
37163d81e711SVlad Buslov 		goto nla_put_failure_locked;
37173d81e711SVlad Buslov 
37183d81e711SVlad Buslov 	spin_unlock(&tp->lock);
37193d81e711SVlad Buslov 
37203d81e711SVlad Buslov 	if (!skip_hw)
3721c24e43d8SVlad Buslov 		fl_hw_update_stats(tp, f, rtnl_held);
3722e69985c6SAmir Vadai 
372386c55361SVlad Buslov 	if (nla_put_u32(skb, TCA_FLOWER_IN_HW_COUNT, f->in_hw_count))
372486c55361SVlad Buslov 		goto nla_put_failure;
372586c55361SVlad Buslov 
372677b9900eSJiri Pirko 	if (tcf_exts_dump(skb, &f->exts))
372777b9900eSJiri Pirko 		goto nla_put_failure;
372877b9900eSJiri Pirko 
372977b9900eSJiri Pirko 	nla_nest_end(skb, nest);
373077b9900eSJiri Pirko 
373177b9900eSJiri Pirko 	if (tcf_exts_dump_stats(skb, &f->exts) < 0)
373277b9900eSJiri Pirko 		goto nla_put_failure;
373377b9900eSJiri Pirko 
373477b9900eSJiri Pirko 	return skb->len;
373577b9900eSJiri Pirko 
37363d81e711SVlad Buslov nla_put_failure_locked:
37373d81e711SVlad Buslov 	spin_unlock(&tp->lock);
373877b9900eSJiri Pirko nla_put_failure:
373977b9900eSJiri Pirko 	nla_nest_cancel(skb, nest);
374077b9900eSJiri Pirko 	return -1;
374177b9900eSJiri Pirko }
374277b9900eSJiri Pirko 
fl_terse_dump(struct net * net,struct tcf_proto * tp,void * fh,struct sk_buff * skb,struct tcmsg * t,bool rtnl_held)37430348451dSVlad Buslov static int fl_terse_dump(struct net *net, struct tcf_proto *tp, void *fh,
37440348451dSVlad Buslov 			 struct sk_buff *skb, struct tcmsg *t, bool rtnl_held)
37450348451dSVlad Buslov {
37460348451dSVlad Buslov 	struct cls_fl_filter *f = fh;
37470348451dSVlad Buslov 	struct nlattr *nest;
37480348451dSVlad Buslov 	bool skip_hw;
37490348451dSVlad Buslov 
37500348451dSVlad Buslov 	if (!f)
37510348451dSVlad Buslov 		return skb->len;
37520348451dSVlad Buslov 
37530348451dSVlad Buslov 	t->tcm_handle = f->handle;
37540348451dSVlad Buslov 
37550348451dSVlad Buslov 	nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
37560348451dSVlad Buslov 	if (!nest)
37570348451dSVlad Buslov 		goto nla_put_failure;
37580348451dSVlad Buslov 
37590348451dSVlad Buslov 	spin_lock(&tp->lock);
37600348451dSVlad Buslov 
37610348451dSVlad Buslov 	skip_hw = tc_skip_hw(f->flags);
37620348451dSVlad Buslov 
37630348451dSVlad Buslov 	if (f->flags && nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags))
37640348451dSVlad Buslov 		goto nla_put_failure_locked;
37650348451dSVlad Buslov 
37660348451dSVlad Buslov 	spin_unlock(&tp->lock);
37670348451dSVlad Buslov 
37680348451dSVlad Buslov 	if (!skip_hw)
37690348451dSVlad Buslov 		fl_hw_update_stats(tp, f, rtnl_held);
37700348451dSVlad Buslov 
37710348451dSVlad Buslov 	if (tcf_exts_terse_dump(skb, &f->exts))
37720348451dSVlad Buslov 		goto nla_put_failure;
37730348451dSVlad Buslov 
37740348451dSVlad Buslov 	nla_nest_end(skb, nest);
37750348451dSVlad Buslov 
37760348451dSVlad Buslov 	return skb->len;
37770348451dSVlad Buslov 
37780348451dSVlad Buslov nla_put_failure_locked:
37790348451dSVlad Buslov 	spin_unlock(&tp->lock);
37800348451dSVlad Buslov nla_put_failure:
37810348451dSVlad Buslov 	nla_nest_cancel(skb, nest);
37820348451dSVlad Buslov 	return -1;
37830348451dSVlad Buslov }
37840348451dSVlad Buslov 
fl_tmplt_dump(struct sk_buff * skb,struct net * net,void * tmplt_priv)3785b95ec7ebSJiri Pirko static int fl_tmplt_dump(struct sk_buff *skb, struct net *net, void *tmplt_priv)
3786b95ec7ebSJiri Pirko {
3787b95ec7ebSJiri Pirko 	struct fl_flow_tmplt *tmplt = tmplt_priv;
3788b95ec7ebSJiri Pirko 	struct fl_flow_key *key, *mask;
3789b95ec7ebSJiri Pirko 	struct nlattr *nest;
3790b95ec7ebSJiri Pirko 
3791ae0be8deSMichal Kubecek 	nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
3792b95ec7ebSJiri Pirko 	if (!nest)
3793b95ec7ebSJiri Pirko 		goto nla_put_failure;
3794b95ec7ebSJiri Pirko 
3795b95ec7ebSJiri Pirko 	key = &tmplt->dummy_key;
3796b95ec7ebSJiri Pirko 	mask = &tmplt->mask;
3797b95ec7ebSJiri Pirko 
3798b95ec7ebSJiri Pirko 	if (fl_dump_key(skb, net, key, mask))
3799b95ec7ebSJiri Pirko 		goto nla_put_failure;
3800b95ec7ebSJiri Pirko 
3801b95ec7ebSJiri Pirko 	nla_nest_end(skb, nest);
3802b95ec7ebSJiri Pirko 
3803b95ec7ebSJiri Pirko 	return skb->len;
3804b95ec7ebSJiri Pirko 
3805b95ec7ebSJiri Pirko nla_put_failure:
3806b95ec7ebSJiri Pirko 	nla_nest_cancel(skb, nest);
3807b95ec7ebSJiri Pirko 	return -EMSGSIZE;
3808b95ec7ebSJiri Pirko }
3809b95ec7ebSJiri Pirko 
fl_bind_class(void * fh,u32 classid,unsigned long cl,void * q,unsigned long base)38102e24cd75SCong Wang static void fl_bind_class(void *fh, u32 classid, unsigned long cl, void *q,
38112e24cd75SCong Wang 			  unsigned long base)
381207d79fc7SCong Wang {
381307d79fc7SCong Wang 	struct cls_fl_filter *f = fh;
381407d79fc7SCong Wang 
3815cc9039a1SZhengchao Shao 	tc_cls_bind_class(classid, cl, q, &f->res, base);
381607d79fc7SCong Wang }
381707d79fc7SCong Wang 
fl_delete_empty(struct tcf_proto * tp)3818a5b72a08SDavide Caratti static bool fl_delete_empty(struct tcf_proto *tp)
3819a5b72a08SDavide Caratti {
3820a5b72a08SDavide Caratti 	struct cls_fl_head *head = fl_head_dereference(tp);
3821a5b72a08SDavide Caratti 
3822a5b72a08SDavide Caratti 	spin_lock(&tp->lock);
3823a5b72a08SDavide Caratti 	tp->deleting = idr_is_empty(&head->handle_idr);
3824a5b72a08SDavide Caratti 	spin_unlock(&tp->lock);
3825a5b72a08SDavide Caratti 
3826a5b72a08SDavide Caratti 	return tp->deleting;
3827a5b72a08SDavide Caratti }
3828a5b72a08SDavide Caratti 
382977b9900eSJiri Pirko static struct tcf_proto_ops cls_fl_ops __read_mostly = {
383077b9900eSJiri Pirko 	.kind		= "flower",
383177b9900eSJiri Pirko 	.classify	= fl_classify,
383277b9900eSJiri Pirko 	.init		= fl_init,
383377b9900eSJiri Pirko 	.destroy	= fl_destroy,
383477b9900eSJiri Pirko 	.get		= fl_get,
383506177558SVlad Buslov 	.put		= fl_put,
383677b9900eSJiri Pirko 	.change		= fl_change,
383777b9900eSJiri Pirko 	.delete		= fl_delete,
3838a5b72a08SDavide Caratti 	.delete_empty	= fl_delete_empty,
383977b9900eSJiri Pirko 	.walk		= fl_walk,
384031533cbaSJohn Hurley 	.reoffload	= fl_reoffload,
3841a449a3e7SVlad Buslov 	.hw_add		= fl_hw_add,
3842a449a3e7SVlad Buslov 	.hw_del		= fl_hw_del,
384377b9900eSJiri Pirko 	.dump		= fl_dump,
38440348451dSVlad Buslov 	.terse_dump	= fl_terse_dump,
384507d79fc7SCong Wang 	.bind_class	= fl_bind_class,
3846b95ec7ebSJiri Pirko 	.tmplt_create	= fl_tmplt_create,
3847b95ec7ebSJiri Pirko 	.tmplt_destroy	= fl_tmplt_destroy,
384832f2a0afSIdo Schimmel 	.tmplt_reoffload = fl_tmplt_reoffload,
3849b95ec7ebSJiri Pirko 	.tmplt_dump	= fl_tmplt_dump,
3850606c7c43SPaul Blakey 	.get_exts	= fl_get_exts,
385177b9900eSJiri Pirko 	.owner		= THIS_MODULE,
385292149190SVlad Buslov 	.flags		= TCF_PROTO_OPS_DOIT_UNLOCKED,
385377b9900eSJiri Pirko };
3854241a94abSMichal Koutný MODULE_ALIAS_NET_CLS("flower");
385577b9900eSJiri Pirko 
cls_fl_init(void)385677b9900eSJiri Pirko static int __init cls_fl_init(void)
385777b9900eSJiri Pirko {
385877b9900eSJiri Pirko 	return register_tcf_proto_ops(&cls_fl_ops);
385977b9900eSJiri Pirko }
386077b9900eSJiri Pirko 
cls_fl_exit(void)386177b9900eSJiri Pirko static void __exit cls_fl_exit(void)
386277b9900eSJiri Pirko {
386377b9900eSJiri Pirko 	unregister_tcf_proto_ops(&cls_fl_ops);
386477b9900eSJiri Pirko }
386577b9900eSJiri Pirko 
386677b9900eSJiri Pirko module_init(cls_fl_init);
386777b9900eSJiri Pirko module_exit(cls_fl_exit);
386877b9900eSJiri Pirko 
386977b9900eSJiri Pirko MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>");
387077b9900eSJiri Pirko MODULE_DESCRIPTION("Flower classifier");
387177b9900eSJiri Pirko MODULE_LICENSE("GPL v2");
3872