xref: /linux/net/sched/cls_flower.c (revision b2552b8c40fa89210070c6e3487b35f10608d6c5)
177b9900eSJiri Pirko /*
277b9900eSJiri Pirko  * net/sched/cls_flower.c		Flower classifier
377b9900eSJiri Pirko  *
477b9900eSJiri Pirko  * Copyright (c) 2015 Jiri Pirko <jiri@resnulli.us>
577b9900eSJiri Pirko  *
677b9900eSJiri Pirko  * This program is free software; you can redistribute it and/or modify
777b9900eSJiri Pirko  * it under the terms of the GNU General Public License as published by
877b9900eSJiri Pirko  * the Free Software Foundation; either version 2 of the License, or
977b9900eSJiri Pirko  * (at your option) any later version.
1077b9900eSJiri Pirko  */
1177b9900eSJiri Pirko 
1277b9900eSJiri Pirko #include <linux/kernel.h>
1377b9900eSJiri Pirko #include <linux/init.h>
1477b9900eSJiri Pirko #include <linux/module.h>
1577b9900eSJiri Pirko #include <linux/rhashtable.h>
16d9363774SDaniel Borkmann #include <linux/workqueue.h>
1706177558SVlad Buslov #include <linux/refcount.h>
1877b9900eSJiri Pirko 
1977b9900eSJiri Pirko #include <linux/if_ether.h>
2077b9900eSJiri Pirko #include <linux/in6.h>
2177b9900eSJiri Pirko #include <linux/ip.h>
22a577d8f7SBenjamin LaHaise #include <linux/mpls.h>
2377b9900eSJiri Pirko 
2477b9900eSJiri Pirko #include <net/sch_generic.h>
2577b9900eSJiri Pirko #include <net/pkt_cls.h>
2677b9900eSJiri Pirko #include <net/ip.h>
2777b9900eSJiri Pirko #include <net/flow_dissector.h>
280a6e7778SPieter Jansen van Vuuren #include <net/geneve.h>
2977b9900eSJiri Pirko 
30bc3103f1SAmir Vadai #include <net/dst.h>
31bc3103f1SAmir Vadai #include <net/dst_metadata.h>
32bc3103f1SAmir Vadai 
3377b9900eSJiri Pirko struct fl_flow_key {
3477b9900eSJiri Pirko 	int	indev_ifindex;
3542aecaa9STom Herbert 	struct flow_dissector_key_control control;
36bc3103f1SAmir Vadai 	struct flow_dissector_key_control enc_control;
3777b9900eSJiri Pirko 	struct flow_dissector_key_basic basic;
3877b9900eSJiri Pirko 	struct flow_dissector_key_eth_addrs eth;
399399ae9aSHadar Hen Zion 	struct flow_dissector_key_vlan vlan;
40d64efd09SJianbo Liu 	struct flow_dissector_key_vlan cvlan;
4177b9900eSJiri Pirko 	union {
42c3f83241STom Herbert 		struct flow_dissector_key_ipv4_addrs ipv4;
4377b9900eSJiri Pirko 		struct flow_dissector_key_ipv6_addrs ipv6;
4477b9900eSJiri Pirko 	};
4577b9900eSJiri Pirko 	struct flow_dissector_key_ports tp;
467b684884SSimon Horman 	struct flow_dissector_key_icmp icmp;
4799d31326SSimon Horman 	struct flow_dissector_key_arp arp;
48bc3103f1SAmir Vadai 	struct flow_dissector_key_keyid enc_key_id;
49bc3103f1SAmir Vadai 	union {
50bc3103f1SAmir Vadai 		struct flow_dissector_key_ipv4_addrs enc_ipv4;
51bc3103f1SAmir Vadai 		struct flow_dissector_key_ipv6_addrs enc_ipv6;
52bc3103f1SAmir Vadai 	};
53f4d997fdSHadar Hen Zion 	struct flow_dissector_key_ports enc_tp;
54a577d8f7SBenjamin LaHaise 	struct flow_dissector_key_mpls mpls;
55fdfc7dd6SJiri Pirko 	struct flow_dissector_key_tcp tcp;
564d80cc0aSOr Gerlitz 	struct flow_dissector_key_ip ip;
570e2c17b6SOr Gerlitz 	struct flow_dissector_key_ip enc_ip;
580a6e7778SPieter Jansen van Vuuren 	struct flow_dissector_key_enc_opts enc_opts;
595c72299fSAmritha Nambiar 	struct flow_dissector_key_ports tp_min;
605c72299fSAmritha Nambiar 	struct flow_dissector_key_ports tp_max;
6177b9900eSJiri Pirko } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
6277b9900eSJiri Pirko 
6377b9900eSJiri Pirko struct fl_flow_mask_range {
6477b9900eSJiri Pirko 	unsigned short int start;
6577b9900eSJiri Pirko 	unsigned short int end;
6677b9900eSJiri Pirko };
6777b9900eSJiri Pirko 
6877b9900eSJiri Pirko struct fl_flow_mask {
6977b9900eSJiri Pirko 	struct fl_flow_key key;
7077b9900eSJiri Pirko 	struct fl_flow_mask_range range;
715c72299fSAmritha Nambiar 	u32 flags;
7205cd271fSPaul Blakey 	struct rhash_head ht_node;
7305cd271fSPaul Blakey 	struct rhashtable ht;
7405cd271fSPaul Blakey 	struct rhashtable_params filter_ht_params;
7505cd271fSPaul Blakey 	struct flow_dissector dissector;
7605cd271fSPaul Blakey 	struct list_head filters;
7744a5cd43SPaolo Abeni 	struct rcu_work rwork;
7805cd271fSPaul Blakey 	struct list_head list;
7977b9900eSJiri Pirko };
8077b9900eSJiri Pirko 
81b95ec7ebSJiri Pirko struct fl_flow_tmplt {
82b95ec7ebSJiri Pirko 	struct fl_flow_key dummy_key;
83b95ec7ebSJiri Pirko 	struct fl_flow_key mask;
84b95ec7ebSJiri Pirko 	struct flow_dissector dissector;
85b95ec7ebSJiri Pirko 	struct tcf_chain *chain;
86b95ec7ebSJiri Pirko };
87b95ec7ebSJiri Pirko 
8877b9900eSJiri Pirko struct cls_fl_head {
8977b9900eSJiri Pirko 	struct rhashtable ht;
9005cd271fSPaul Blakey 	struct list_head masks;
91aaa908ffSCong Wang 	struct rcu_work rwork;
92c15ab236SChris Mi 	struct idr handle_idr;
93d9363774SDaniel Borkmann };
9477b9900eSJiri Pirko 
9577b9900eSJiri Pirko struct cls_fl_filter {
9605cd271fSPaul Blakey 	struct fl_flow_mask *mask;
9777b9900eSJiri Pirko 	struct rhash_head ht_node;
9877b9900eSJiri Pirko 	struct fl_flow_key mkey;
9977b9900eSJiri Pirko 	struct tcf_exts exts;
10077b9900eSJiri Pirko 	struct tcf_result res;
10177b9900eSJiri Pirko 	struct fl_flow_key key;
10277b9900eSJiri Pirko 	struct list_head list;
10377b9900eSJiri Pirko 	u32 handle;
104e69985c6SAmir Vadai 	u32 flags;
10586c55361SVlad Buslov 	u32 in_hw_count;
106aaa908ffSCong Wang 	struct rcu_work rwork;
1077091d8c7SHadar Hen Zion 	struct net_device *hw_dev;
10806177558SVlad Buslov 	/* Flower classifier is unlocked, which means that its reference counter
10906177558SVlad Buslov 	 * can be changed concurrently without any kind of external
11006177558SVlad Buslov 	 * synchronization. Use atomic reference counter to be concurrency-safe.
11106177558SVlad Buslov 	 */
11206177558SVlad Buslov 	refcount_t refcnt;
113*b2552b8cSVlad Buslov 	bool deleted;
11477b9900eSJiri Pirko };
11577b9900eSJiri Pirko 
11605cd271fSPaul Blakey static const struct rhashtable_params mask_ht_params = {
11705cd271fSPaul Blakey 	.key_offset = offsetof(struct fl_flow_mask, key),
11805cd271fSPaul Blakey 	.key_len = sizeof(struct fl_flow_key),
11905cd271fSPaul Blakey 	.head_offset = offsetof(struct fl_flow_mask, ht_node),
12005cd271fSPaul Blakey 	.automatic_shrinking = true,
12105cd271fSPaul Blakey };
12205cd271fSPaul Blakey 
12377b9900eSJiri Pirko static unsigned short int fl_mask_range(const struct fl_flow_mask *mask)
12477b9900eSJiri Pirko {
12577b9900eSJiri Pirko 	return mask->range.end - mask->range.start;
12677b9900eSJiri Pirko }
12777b9900eSJiri Pirko 
12877b9900eSJiri Pirko static void fl_mask_update_range(struct fl_flow_mask *mask)
12977b9900eSJiri Pirko {
13077b9900eSJiri Pirko 	const u8 *bytes = (const u8 *) &mask->key;
13177b9900eSJiri Pirko 	size_t size = sizeof(mask->key);
13205cd271fSPaul Blakey 	size_t i, first = 0, last;
13377b9900eSJiri Pirko 
13405cd271fSPaul Blakey 	for (i = 0; i < size; i++) {
13577b9900eSJiri Pirko 		if (bytes[i]) {
13677b9900eSJiri Pirko 			first = i;
13705cd271fSPaul Blakey 			break;
13805cd271fSPaul Blakey 		}
13905cd271fSPaul Blakey 	}
14005cd271fSPaul Blakey 	last = first;
14105cd271fSPaul Blakey 	for (i = size - 1; i != first; i--) {
14205cd271fSPaul Blakey 		if (bytes[i]) {
14377b9900eSJiri Pirko 			last = i;
14405cd271fSPaul Blakey 			break;
14577b9900eSJiri Pirko 		}
14677b9900eSJiri Pirko 	}
14777b9900eSJiri Pirko 	mask->range.start = rounddown(first, sizeof(long));
14877b9900eSJiri Pirko 	mask->range.end = roundup(last + 1, sizeof(long));
14977b9900eSJiri Pirko }
15077b9900eSJiri Pirko 
15177b9900eSJiri Pirko static void *fl_key_get_start(struct fl_flow_key *key,
15277b9900eSJiri Pirko 			      const struct fl_flow_mask *mask)
15377b9900eSJiri Pirko {
15477b9900eSJiri Pirko 	return (u8 *) key + mask->range.start;
15577b9900eSJiri Pirko }
15677b9900eSJiri Pirko 
15777b9900eSJiri Pirko static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key,
15877b9900eSJiri Pirko 			      struct fl_flow_mask *mask)
15977b9900eSJiri Pirko {
16077b9900eSJiri Pirko 	const long *lkey = fl_key_get_start(key, mask);
16177b9900eSJiri Pirko 	const long *lmask = fl_key_get_start(&mask->key, mask);
16277b9900eSJiri Pirko 	long *lmkey = fl_key_get_start(mkey, mask);
16377b9900eSJiri Pirko 	int i;
16477b9900eSJiri Pirko 
16577b9900eSJiri Pirko 	for (i = 0; i < fl_mask_range(mask); i += sizeof(long))
16677b9900eSJiri Pirko 		*lmkey++ = *lkey++ & *lmask++;
16777b9900eSJiri Pirko }
16877b9900eSJiri Pirko 
169b95ec7ebSJiri Pirko static bool fl_mask_fits_tmplt(struct fl_flow_tmplt *tmplt,
170b95ec7ebSJiri Pirko 			       struct fl_flow_mask *mask)
171b95ec7ebSJiri Pirko {
172b95ec7ebSJiri Pirko 	const long *lmask = fl_key_get_start(&mask->key, mask);
173b95ec7ebSJiri Pirko 	const long *ltmplt;
174b95ec7ebSJiri Pirko 	int i;
175b95ec7ebSJiri Pirko 
176b95ec7ebSJiri Pirko 	if (!tmplt)
177b95ec7ebSJiri Pirko 		return true;
178b95ec7ebSJiri Pirko 	ltmplt = fl_key_get_start(&tmplt->mask, mask);
179b95ec7ebSJiri Pirko 	for (i = 0; i < fl_mask_range(mask); i += sizeof(long)) {
180b95ec7ebSJiri Pirko 		if (~*ltmplt++ & *lmask++)
181b95ec7ebSJiri Pirko 			return false;
182b95ec7ebSJiri Pirko 	}
183b95ec7ebSJiri Pirko 	return true;
184b95ec7ebSJiri Pirko }
185b95ec7ebSJiri Pirko 
18677b9900eSJiri Pirko static void fl_clear_masked_range(struct fl_flow_key *key,
18777b9900eSJiri Pirko 				  struct fl_flow_mask *mask)
18877b9900eSJiri Pirko {
18977b9900eSJiri Pirko 	memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask));
19077b9900eSJiri Pirko }
19177b9900eSJiri Pirko 
1925c72299fSAmritha Nambiar static bool fl_range_port_dst_cmp(struct cls_fl_filter *filter,
1935c72299fSAmritha Nambiar 				  struct fl_flow_key *key,
1945c72299fSAmritha Nambiar 				  struct fl_flow_key *mkey)
1955c72299fSAmritha Nambiar {
1965c72299fSAmritha Nambiar 	__be16 min_mask, max_mask, min_val, max_val;
1975c72299fSAmritha Nambiar 
1985c72299fSAmritha Nambiar 	min_mask = htons(filter->mask->key.tp_min.dst);
1995c72299fSAmritha Nambiar 	max_mask = htons(filter->mask->key.tp_max.dst);
2005c72299fSAmritha Nambiar 	min_val = htons(filter->key.tp_min.dst);
2015c72299fSAmritha Nambiar 	max_val = htons(filter->key.tp_max.dst);
2025c72299fSAmritha Nambiar 
2035c72299fSAmritha Nambiar 	if (min_mask && max_mask) {
2045c72299fSAmritha Nambiar 		if (htons(key->tp.dst) < min_val ||
2055c72299fSAmritha Nambiar 		    htons(key->tp.dst) > max_val)
2065c72299fSAmritha Nambiar 			return false;
2075c72299fSAmritha Nambiar 
2085c72299fSAmritha Nambiar 		/* skb does not have min and max values */
2095c72299fSAmritha Nambiar 		mkey->tp_min.dst = filter->mkey.tp_min.dst;
2105c72299fSAmritha Nambiar 		mkey->tp_max.dst = filter->mkey.tp_max.dst;
2115c72299fSAmritha Nambiar 	}
2125c72299fSAmritha Nambiar 	return true;
2135c72299fSAmritha Nambiar }
2145c72299fSAmritha Nambiar 
2155c72299fSAmritha Nambiar static bool fl_range_port_src_cmp(struct cls_fl_filter *filter,
2165c72299fSAmritha Nambiar 				  struct fl_flow_key *key,
2175c72299fSAmritha Nambiar 				  struct fl_flow_key *mkey)
2185c72299fSAmritha Nambiar {
2195c72299fSAmritha Nambiar 	__be16 min_mask, max_mask, min_val, max_val;
2205c72299fSAmritha Nambiar 
2215c72299fSAmritha Nambiar 	min_mask = htons(filter->mask->key.tp_min.src);
2225c72299fSAmritha Nambiar 	max_mask = htons(filter->mask->key.tp_max.src);
2235c72299fSAmritha Nambiar 	min_val = htons(filter->key.tp_min.src);
2245c72299fSAmritha Nambiar 	max_val = htons(filter->key.tp_max.src);
2255c72299fSAmritha Nambiar 
2265c72299fSAmritha Nambiar 	if (min_mask && max_mask) {
2275c72299fSAmritha Nambiar 		if (htons(key->tp.src) < min_val ||
2285c72299fSAmritha Nambiar 		    htons(key->tp.src) > max_val)
2295c72299fSAmritha Nambiar 			return false;
2305c72299fSAmritha Nambiar 
2315c72299fSAmritha Nambiar 		/* skb does not have min and max values */
2325c72299fSAmritha Nambiar 		mkey->tp_min.src = filter->mkey.tp_min.src;
2335c72299fSAmritha Nambiar 		mkey->tp_max.src = filter->mkey.tp_max.src;
2345c72299fSAmritha Nambiar 	}
2355c72299fSAmritha Nambiar 	return true;
2365c72299fSAmritha Nambiar }
2375c72299fSAmritha Nambiar 
2385c72299fSAmritha Nambiar static struct cls_fl_filter *__fl_lookup(struct fl_flow_mask *mask,
239a3308d8fSPaul Blakey 					 struct fl_flow_key *mkey)
240a3308d8fSPaul Blakey {
24105cd271fSPaul Blakey 	return rhashtable_lookup_fast(&mask->ht, fl_key_get_start(mkey, mask),
24205cd271fSPaul Blakey 				      mask->filter_ht_params);
243a3308d8fSPaul Blakey }
244a3308d8fSPaul Blakey 
2455c72299fSAmritha Nambiar static struct cls_fl_filter *fl_lookup_range(struct fl_flow_mask *mask,
2465c72299fSAmritha Nambiar 					     struct fl_flow_key *mkey,
2475c72299fSAmritha Nambiar 					     struct fl_flow_key *key)
2485c72299fSAmritha Nambiar {
2495c72299fSAmritha Nambiar 	struct cls_fl_filter *filter, *f;
2505c72299fSAmritha Nambiar 
2515c72299fSAmritha Nambiar 	list_for_each_entry_rcu(filter, &mask->filters, list) {
2525c72299fSAmritha Nambiar 		if (!fl_range_port_dst_cmp(filter, key, mkey))
2535c72299fSAmritha Nambiar 			continue;
2545c72299fSAmritha Nambiar 
2555c72299fSAmritha Nambiar 		if (!fl_range_port_src_cmp(filter, key, mkey))
2565c72299fSAmritha Nambiar 			continue;
2575c72299fSAmritha Nambiar 
2585c72299fSAmritha Nambiar 		f = __fl_lookup(mask, mkey);
2595c72299fSAmritha Nambiar 		if (f)
2605c72299fSAmritha Nambiar 			return f;
2615c72299fSAmritha Nambiar 	}
2625c72299fSAmritha Nambiar 	return NULL;
2635c72299fSAmritha Nambiar }
2645c72299fSAmritha Nambiar 
2655c72299fSAmritha Nambiar static struct cls_fl_filter *fl_lookup(struct fl_flow_mask *mask,
2665c72299fSAmritha Nambiar 				       struct fl_flow_key *mkey,
2675c72299fSAmritha Nambiar 				       struct fl_flow_key *key)
2685c72299fSAmritha Nambiar {
2695c72299fSAmritha Nambiar 	if ((mask->flags & TCA_FLOWER_MASK_FLAGS_RANGE))
2705c72299fSAmritha Nambiar 		return fl_lookup_range(mask, mkey, key);
2715c72299fSAmritha Nambiar 
2725c72299fSAmritha Nambiar 	return __fl_lookup(mask, mkey);
2735c72299fSAmritha Nambiar }
2745c72299fSAmritha Nambiar 
27577b9900eSJiri Pirko static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp,
27677b9900eSJiri Pirko 		       struct tcf_result *res)
27777b9900eSJiri Pirko {
27877b9900eSJiri Pirko 	struct cls_fl_head *head = rcu_dereference_bh(tp->root);
27977b9900eSJiri Pirko 	struct cls_fl_filter *f;
28005cd271fSPaul Blakey 	struct fl_flow_mask *mask;
28177b9900eSJiri Pirko 	struct fl_flow_key skb_key;
28277b9900eSJiri Pirko 	struct fl_flow_key skb_mkey;
28377b9900eSJiri Pirko 
28405cd271fSPaul Blakey 	list_for_each_entry_rcu(mask, &head->masks, list) {
28505cd271fSPaul Blakey 		fl_clear_masked_range(&skb_key, mask);
286bc3103f1SAmir Vadai 
28777b9900eSJiri Pirko 		skb_key.indev_ifindex = skb->skb_iif;
28805cd271fSPaul Blakey 		/* skb_flow_dissect() does not set n_proto in case an unknown
28905cd271fSPaul Blakey 		 * protocol, so do it rather here.
29077b9900eSJiri Pirko 		 */
29177b9900eSJiri Pirko 		skb_key.basic.n_proto = skb->protocol;
29205cd271fSPaul Blakey 		skb_flow_dissect_tunnel_info(skb, &mask->dissector, &skb_key);
29305cd271fSPaul Blakey 		skb_flow_dissect(skb, &mask->dissector, &skb_key, 0);
29477b9900eSJiri Pirko 
29505cd271fSPaul Blakey 		fl_set_masked_key(&skb_mkey, &skb_key, mask);
29677b9900eSJiri Pirko 
2975c72299fSAmritha Nambiar 		f = fl_lookup(mask, &skb_mkey, &skb_key);
298e8eb36cdSAmir Vadai 		if (f && !tc_skip_sw(f->flags)) {
29977b9900eSJiri Pirko 			*res = f->res;
30077b9900eSJiri Pirko 			return tcf_exts_exec(skb, &f->exts, res);
30177b9900eSJiri Pirko 		}
30205cd271fSPaul Blakey 	}
30377b9900eSJiri Pirko 	return -1;
30477b9900eSJiri Pirko }
30577b9900eSJiri Pirko 
30677b9900eSJiri Pirko static int fl_init(struct tcf_proto *tp)
30777b9900eSJiri Pirko {
30877b9900eSJiri Pirko 	struct cls_fl_head *head;
30977b9900eSJiri Pirko 
31077b9900eSJiri Pirko 	head = kzalloc(sizeof(*head), GFP_KERNEL);
31177b9900eSJiri Pirko 	if (!head)
31277b9900eSJiri Pirko 		return -ENOBUFS;
31377b9900eSJiri Pirko 
31405cd271fSPaul Blakey 	INIT_LIST_HEAD_RCU(&head->masks);
31577b9900eSJiri Pirko 	rcu_assign_pointer(tp->root, head);
316c15ab236SChris Mi 	idr_init(&head->handle_idr);
31777b9900eSJiri Pirko 
31805cd271fSPaul Blakey 	return rhashtable_init(&head->ht, &mask_ht_params);
31905cd271fSPaul Blakey }
32005cd271fSPaul Blakey 
32144a5cd43SPaolo Abeni static void fl_mask_free(struct fl_flow_mask *mask)
32244a5cd43SPaolo Abeni {
32344a5cd43SPaolo Abeni 	rhashtable_destroy(&mask->ht);
32444a5cd43SPaolo Abeni 	kfree(mask);
32544a5cd43SPaolo Abeni }
32644a5cd43SPaolo Abeni 
32744a5cd43SPaolo Abeni static void fl_mask_free_work(struct work_struct *work)
32844a5cd43SPaolo Abeni {
32944a5cd43SPaolo Abeni 	struct fl_flow_mask *mask = container_of(to_rcu_work(work),
33044a5cd43SPaolo Abeni 						 struct fl_flow_mask, rwork);
33144a5cd43SPaolo Abeni 
33244a5cd43SPaolo Abeni 	fl_mask_free(mask);
33344a5cd43SPaolo Abeni }
33444a5cd43SPaolo Abeni 
33505cd271fSPaul Blakey static bool fl_mask_put(struct cls_fl_head *head, struct fl_flow_mask *mask,
33605cd271fSPaul Blakey 			bool async)
33705cd271fSPaul Blakey {
33805cd271fSPaul Blakey 	if (!list_empty(&mask->filters))
33905cd271fSPaul Blakey 		return false;
34005cd271fSPaul Blakey 
34105cd271fSPaul Blakey 	rhashtable_remove_fast(&head->ht, &mask->ht_node, mask_ht_params);
34205cd271fSPaul Blakey 	list_del_rcu(&mask->list);
34305cd271fSPaul Blakey 	if (async)
34444a5cd43SPaolo Abeni 		tcf_queue_work(&mask->rwork, fl_mask_free_work);
34505cd271fSPaul Blakey 	else
34644a5cd43SPaolo Abeni 		fl_mask_free(mask);
34705cd271fSPaul Blakey 
34805cd271fSPaul Blakey 	return true;
34977b9900eSJiri Pirko }
35077b9900eSJiri Pirko 
3510dadc117SCong Wang static void __fl_destroy_filter(struct cls_fl_filter *f)
3520dadc117SCong Wang {
3530dadc117SCong Wang 	tcf_exts_destroy(&f->exts);
3540dadc117SCong Wang 	tcf_exts_put_net(&f->exts);
3550dadc117SCong Wang 	kfree(f);
3560dadc117SCong Wang }
3570dadc117SCong Wang 
3580552c8afSCong Wang static void fl_destroy_filter_work(struct work_struct *work)
3590552c8afSCong Wang {
360aaa908ffSCong Wang 	struct cls_fl_filter *f = container_of(to_rcu_work(work),
361aaa908ffSCong Wang 					struct cls_fl_filter, rwork);
3620552c8afSCong Wang 
3630552c8afSCong Wang 	rtnl_lock();
3640dadc117SCong Wang 	__fl_destroy_filter(f);
3650552c8afSCong Wang 	rtnl_unlock();
3660552c8afSCong Wang }
3670552c8afSCong Wang 
3681b0f8037SJakub Kicinski static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f,
3691b0f8037SJakub Kicinski 				 struct netlink_ext_ack *extack)
3705b33f488SAmir Vadai {
371de4784caSJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
372208c0f4bSJiri Pirko 	struct tcf_block *block = tp->chain->block;
3735b33f488SAmir Vadai 
3741b0f8037SJakub Kicinski 	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack);
375de4784caSJiri Pirko 	cls_flower.command = TC_CLSFLOWER_DESTROY;
376de4784caSJiri Pirko 	cls_flower.cookie = (unsigned long) f;
3775b33f488SAmir Vadai 
378aeb3fecdSCong Wang 	tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, false);
379caa72601SJiri Pirko 	tcf_block_offload_dec(block, &f->flags);
3805b33f488SAmir Vadai }
3815b33f488SAmir Vadai 
382e8eb36cdSAmir Vadai static int fl_hw_replace_filter(struct tcf_proto *tp,
38341002038SQuentin Monnet 				struct cls_fl_filter *f,
38441002038SQuentin Monnet 				struct netlink_ext_ack *extack)
3855b33f488SAmir Vadai {
386de4784caSJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
387208c0f4bSJiri Pirko 	struct tcf_block *block = tp->chain->block;
388717503b9SJiri Pirko 	bool skip_sw = tc_skip_sw(f->flags);
389e8eb36cdSAmir Vadai 	int err;
3905b33f488SAmir Vadai 
391e3ab786bSPablo Neira Ayuso 	cls_flower.rule = flow_rule_alloc(tcf_exts_num_actions(&f->exts));
3928f256622SPablo Neira Ayuso 	if (!cls_flower.rule)
3938f256622SPablo Neira Ayuso 		return -ENOMEM;
3948f256622SPablo Neira Ayuso 
395ea205940SJakub Kicinski 	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack);
396de4784caSJiri Pirko 	cls_flower.command = TC_CLSFLOWER_REPLACE;
397de4784caSJiri Pirko 	cls_flower.cookie = (unsigned long) f;
3988f256622SPablo Neira Ayuso 	cls_flower.rule->match.dissector = &f->mask->dissector;
3998f256622SPablo Neira Ayuso 	cls_flower.rule->match.mask = &f->mask->key;
4008f256622SPablo Neira Ayuso 	cls_flower.rule->match.key = &f->mkey;
401384c181eSAmritha Nambiar 	cls_flower.classid = f->res.classid;
4025b33f488SAmir Vadai 
4033a7b6861SPablo Neira Ayuso 	err = tc_setup_flow_action(&cls_flower.rule->action, &f->exts);
4043a7b6861SPablo Neira Ayuso 	if (err) {
4053a7b6861SPablo Neira Ayuso 		kfree(cls_flower.rule);
4061f15bb4fSVlad Buslov 		if (skip_sw) {
4071f15bb4fSVlad Buslov 			NL_SET_ERR_MSG_MOD(extack, "Failed to setup flow action");
4083a7b6861SPablo Neira Ayuso 			return err;
4093a7b6861SPablo Neira Ayuso 		}
4101f15bb4fSVlad Buslov 		return 0;
4111f15bb4fSVlad Buslov 	}
4123a7b6861SPablo Neira Ayuso 
413aeb3fecdSCong Wang 	err = tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, skip_sw);
4148f256622SPablo Neira Ayuso 	kfree(cls_flower.rule);
4158f256622SPablo Neira Ayuso 
416717503b9SJiri Pirko 	if (err < 0) {
4171b0f8037SJakub Kicinski 		fl_hw_destroy_filter(tp, f, NULL);
418717503b9SJiri Pirko 		return err;
419717503b9SJiri Pirko 	} else if (err > 0) {
42031533cbaSJohn Hurley 		f->in_hw_count = err;
421caa72601SJiri Pirko 		tcf_block_offload_inc(block, &f->flags);
422717503b9SJiri Pirko 	}
423717503b9SJiri Pirko 
424717503b9SJiri Pirko 	if (skip_sw && !(f->flags & TCA_CLS_FLAGS_IN_HW))
425717503b9SJiri Pirko 		return -EINVAL;
426717503b9SJiri Pirko 
427e8eb36cdSAmir Vadai 	return 0;
4285b33f488SAmir Vadai }
4295b33f488SAmir Vadai 
43010cbc684SAmir Vadai static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
43110cbc684SAmir Vadai {
432de4784caSJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
433208c0f4bSJiri Pirko 	struct tcf_block *block = tp->chain->block;
43410cbc684SAmir Vadai 
435ea205940SJakub Kicinski 	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, NULL);
436de4784caSJiri Pirko 	cls_flower.command = TC_CLSFLOWER_STATS;
437de4784caSJiri Pirko 	cls_flower.cookie = (unsigned long) f;
438384c181eSAmritha Nambiar 	cls_flower.classid = f->res.classid;
43910cbc684SAmir Vadai 
440aeb3fecdSCong Wang 	tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, false);
4413b1903efSPablo Neira Ayuso 
4423b1903efSPablo Neira Ayuso 	tcf_exts_stats_update(&f->exts, cls_flower.stats.bytes,
4433b1903efSPablo Neira Ayuso 			      cls_flower.stats.pkts,
4443b1903efSPablo Neira Ayuso 			      cls_flower.stats.lastused);
44510cbc684SAmir Vadai }
44610cbc684SAmir Vadai 
447e474619aSVlad Buslov static struct cls_fl_head *fl_head_dereference(struct tcf_proto *tp)
448e474619aSVlad Buslov {
449e474619aSVlad Buslov 	/* Flower classifier only changes root pointer during init and destroy.
450e474619aSVlad Buslov 	 * Users must obtain reference to tcf_proto instance before calling its
451e474619aSVlad Buslov 	 * API, so tp->root pointer is protected from concurrent call to
452e474619aSVlad Buslov 	 * fl_destroy() by reference counting.
453e474619aSVlad Buslov 	 */
454e474619aSVlad Buslov 	return rcu_dereference_raw(tp->root);
455e474619aSVlad Buslov }
456e474619aSVlad Buslov 
45706177558SVlad Buslov static void __fl_put(struct cls_fl_filter *f)
45806177558SVlad Buslov {
45906177558SVlad Buslov 	if (!refcount_dec_and_test(&f->refcnt))
46006177558SVlad Buslov 		return;
46106177558SVlad Buslov 
462*b2552b8cSVlad Buslov 	WARN_ON(!f->deleted);
463*b2552b8cSVlad Buslov 
46406177558SVlad Buslov 	if (tcf_exts_get_net(&f->exts))
46506177558SVlad Buslov 		tcf_queue_work(&f->rwork, fl_destroy_filter_work);
46606177558SVlad Buslov 	else
46706177558SVlad Buslov 		__fl_destroy_filter(f);
46806177558SVlad Buslov }
46906177558SVlad Buslov 
47006177558SVlad Buslov static struct cls_fl_filter *__fl_get(struct cls_fl_head *head, u32 handle)
47106177558SVlad Buslov {
47206177558SVlad Buslov 	struct cls_fl_filter *f;
47306177558SVlad Buslov 
47406177558SVlad Buslov 	rcu_read_lock();
47506177558SVlad Buslov 	f = idr_find(&head->handle_idr, handle);
47606177558SVlad Buslov 	if (f && !refcount_inc_not_zero(&f->refcnt))
47706177558SVlad Buslov 		f = NULL;
47806177558SVlad Buslov 	rcu_read_unlock();
47906177558SVlad Buslov 
48006177558SVlad Buslov 	return f;
48106177558SVlad Buslov }
48206177558SVlad Buslov 
48306177558SVlad Buslov static struct cls_fl_filter *fl_get_next_filter(struct tcf_proto *tp,
48406177558SVlad Buslov 						unsigned long *handle)
48506177558SVlad Buslov {
48606177558SVlad Buslov 	struct cls_fl_head *head = fl_head_dereference(tp);
48706177558SVlad Buslov 	struct cls_fl_filter *f;
48806177558SVlad Buslov 
48906177558SVlad Buslov 	rcu_read_lock();
49006177558SVlad Buslov 	while ((f = idr_get_next_ul(&head->handle_idr, handle))) {
49106177558SVlad Buslov 		/* don't return filters that are being deleted */
49206177558SVlad Buslov 		if (refcount_inc_not_zero(&f->refcnt))
49306177558SVlad Buslov 			break;
49406177558SVlad Buslov 		++(*handle);
49506177558SVlad Buslov 	}
49606177558SVlad Buslov 	rcu_read_unlock();
49706177558SVlad Buslov 
49806177558SVlad Buslov 	return f;
49906177558SVlad Buslov }
50006177558SVlad Buslov 
501*b2552b8cSVlad Buslov static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,
502*b2552b8cSVlad Buslov 		       bool *last, struct netlink_ext_ack *extack)
50313fa876eSRoi Dayan {
504e474619aSVlad Buslov 	struct cls_fl_head *head = fl_head_dereference(tp);
50505cd271fSPaul Blakey 	bool async = tcf_exts_get_net(&f->exts);
506c15ab236SChris Mi 
507*b2552b8cSVlad Buslov 	*last = false;
508*b2552b8cSVlad Buslov 
509*b2552b8cSVlad Buslov 	if (f->deleted)
510*b2552b8cSVlad Buslov 		return -ENOENT;
511*b2552b8cSVlad Buslov 
512*b2552b8cSVlad Buslov 	f->deleted = true;
513*b2552b8cSVlad Buslov 	rhashtable_remove_fast(&f->mask->ht, &f->ht_node,
514*b2552b8cSVlad Buslov 			       f->mask->filter_ht_params);
5159c160941SMatthew Wilcox 	idr_remove(&head->handle_idr, f->handle);
51613fa876eSRoi Dayan 	list_del_rcu(&f->list);
517*b2552b8cSVlad Buslov 	*last = fl_mask_put(head, f->mask, async);
51879685219SHadar Hen Zion 	if (!tc_skip_hw(f->flags))
5191b0f8037SJakub Kicinski 		fl_hw_destroy_filter(tp, f, extack);
52013fa876eSRoi Dayan 	tcf_unbind_filter(tp, &f->res);
52106177558SVlad Buslov 	__fl_put(f);
52205cd271fSPaul Blakey 
523*b2552b8cSVlad Buslov 	return 0;
52413fa876eSRoi Dayan }
52513fa876eSRoi Dayan 
526d9363774SDaniel Borkmann static void fl_destroy_sleepable(struct work_struct *work)
527d9363774SDaniel Borkmann {
528aaa908ffSCong Wang 	struct cls_fl_head *head = container_of(to_rcu_work(work),
529aaa908ffSCong Wang 						struct cls_fl_head,
530aaa908ffSCong Wang 						rwork);
531de9dc650SPaul Blakey 
532de9dc650SPaul Blakey 	rhashtable_destroy(&head->ht);
533d9363774SDaniel Borkmann 	kfree(head);
534d9363774SDaniel Borkmann 	module_put(THIS_MODULE);
535d9363774SDaniel Borkmann }
536d9363774SDaniel Borkmann 
53712db03b6SVlad Buslov static void fl_destroy(struct tcf_proto *tp, bool rtnl_held,
53812db03b6SVlad Buslov 		       struct netlink_ext_ack *extack)
53977b9900eSJiri Pirko {
540e474619aSVlad Buslov 	struct cls_fl_head *head = fl_head_dereference(tp);
54105cd271fSPaul Blakey 	struct fl_flow_mask *mask, *next_mask;
54277b9900eSJiri Pirko 	struct cls_fl_filter *f, *next;
543*b2552b8cSVlad Buslov 	bool last;
54477b9900eSJiri Pirko 
54505cd271fSPaul Blakey 	list_for_each_entry_safe(mask, next_mask, &head->masks, list) {
54605cd271fSPaul Blakey 		list_for_each_entry_safe(f, next, &mask->filters, list) {
547*b2552b8cSVlad Buslov 			__fl_delete(tp, f, &last, extack);
548*b2552b8cSVlad Buslov 			if (last)
54905cd271fSPaul Blakey 				break;
55005cd271fSPaul Blakey 		}
55105cd271fSPaul Blakey 	}
552c15ab236SChris Mi 	idr_destroy(&head->handle_idr);
553d9363774SDaniel Borkmann 
554d9363774SDaniel Borkmann 	__module_get(THIS_MODULE);
555aaa908ffSCong Wang 	tcf_queue_work(&head->rwork, fl_destroy_sleepable);
55677b9900eSJiri Pirko }
55777b9900eSJiri Pirko 
55806177558SVlad Buslov static void fl_put(struct tcf_proto *tp, void *arg)
55906177558SVlad Buslov {
56006177558SVlad Buslov 	struct cls_fl_filter *f = arg;
56106177558SVlad Buslov 
56206177558SVlad Buslov 	__fl_put(f);
56306177558SVlad Buslov }
56406177558SVlad Buslov 
5658113c095SWANG Cong static void *fl_get(struct tcf_proto *tp, u32 handle)
56677b9900eSJiri Pirko {
567e474619aSVlad Buslov 	struct cls_fl_head *head = fl_head_dereference(tp);
56877b9900eSJiri Pirko 
56906177558SVlad Buslov 	return __fl_get(head, handle);
57077b9900eSJiri Pirko }
57177b9900eSJiri Pirko 
57277b9900eSJiri Pirko static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
57377b9900eSJiri Pirko 	[TCA_FLOWER_UNSPEC]		= { .type = NLA_UNSPEC },
57477b9900eSJiri Pirko 	[TCA_FLOWER_CLASSID]		= { .type = NLA_U32 },
57577b9900eSJiri Pirko 	[TCA_FLOWER_INDEV]		= { .type = NLA_STRING,
57677b9900eSJiri Pirko 					    .len = IFNAMSIZ },
57777b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_DST]	= { .len = ETH_ALEN },
57877b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_DST_MASK]	= { .len = ETH_ALEN },
57977b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_SRC]	= { .len = ETH_ALEN },
58077b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_SRC_MASK]	= { .len = ETH_ALEN },
58177b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_TYPE]	= { .type = NLA_U16 },
58277b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IP_PROTO]	= { .type = NLA_U8 },
58377b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_SRC]	= { .type = NLA_U32 },
58477b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_SRC_MASK]	= { .type = NLA_U32 },
58577b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_DST]	= { .type = NLA_U32 },
58677b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_DST_MASK]	= { .type = NLA_U32 },
58777b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
58877b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_SRC_MASK]	= { .len = sizeof(struct in6_addr) },
58977b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
59077b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_DST_MASK]	= { .len = sizeof(struct in6_addr) },
59177b9900eSJiri Pirko 	[TCA_FLOWER_KEY_TCP_SRC]	= { .type = NLA_U16 },
59277b9900eSJiri Pirko 	[TCA_FLOWER_KEY_TCP_DST]	= { .type = NLA_U16 },
593b175c3a4SJamal Hadi Salim 	[TCA_FLOWER_KEY_UDP_SRC]	= { .type = NLA_U16 },
594b175c3a4SJamal Hadi Salim 	[TCA_FLOWER_KEY_UDP_DST]	= { .type = NLA_U16 },
5959399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_ID]	= { .type = NLA_U16 },
5969399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_PRIO]	= { .type = NLA_U8 },
5979399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_ETH_TYPE]	= { .type = NLA_U16 },
598bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_KEY_ID]	= { .type = NLA_U32 },
599bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_SRC]	= { .type = NLA_U32 },
600bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NLA_U32 },
601bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_DST]	= { .type = NLA_U32 },
602bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NLA_U32 },
603bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
604bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) },
605bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
606bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) },
607aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_TCP_SRC_MASK]	= { .type = NLA_U16 },
608aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_TCP_DST_MASK]	= { .type = NLA_U16 },
609aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_UDP_SRC_MASK]	= { .type = NLA_U16 },
610aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_UDP_DST_MASK]	= { .type = NLA_U16 },
6115976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_SRC_MASK]	= { .type = NLA_U16 },
6125976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_DST_MASK]	= { .type = NLA_U16 },
6135976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_SRC]	= { .type = NLA_U16 },
6145976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_DST]	= { .type = NLA_U16 },
615f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT]	= { .type = NLA_U16 },
616f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK]	= { .type = NLA_U16 },
617f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]	= { .type = NLA_U16 },
618f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK]	= { .type = NLA_U16 },
619faa3ffceSOr Gerlitz 	[TCA_FLOWER_KEY_FLAGS]		= { .type = NLA_U32 },
620faa3ffceSOr Gerlitz 	[TCA_FLOWER_KEY_FLAGS_MASK]	= { .type = NLA_U32 },
6217b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_TYPE]	= { .type = NLA_U8 },
6227b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_TYPE_MASK] = { .type = NLA_U8 },
6237b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_CODE]	= { .type = NLA_U8 },
6247b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_CODE_MASK] = { .type = NLA_U8 },
6257b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_TYPE]	= { .type = NLA_U8 },
6267b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_TYPE_MASK] = { .type = NLA_U8 },
6277b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_CODE]	= { .type = NLA_U8 },
6287b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_CODE_MASK] = { .type = NLA_U8 },
62999d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SIP]	= { .type = NLA_U32 },
63099d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SIP_MASK]	= { .type = NLA_U32 },
63199d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_TIP]	= { .type = NLA_U32 },
63299d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_TIP_MASK]	= { .type = NLA_U32 },
63399d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_OP]		= { .type = NLA_U8 },
63499d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_OP_MASK]	= { .type = NLA_U8 },
63599d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SHA]	= { .len = ETH_ALEN },
63699d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SHA_MASK]	= { .len = ETH_ALEN },
63799d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_THA]	= { .len = ETH_ALEN },
63899d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_THA_MASK]	= { .len = ETH_ALEN },
639a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_TTL]	= { .type = NLA_U8 },
640a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_BOS]	= { .type = NLA_U8 },
641a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_TC]	= { .type = NLA_U8 },
642a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_LABEL]	= { .type = NLA_U32 },
643fdfc7dd6SJiri Pirko 	[TCA_FLOWER_KEY_TCP_FLAGS]	= { .type = NLA_U16 },
644fdfc7dd6SJiri Pirko 	[TCA_FLOWER_KEY_TCP_FLAGS_MASK]	= { .type = NLA_U16 },
6454d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TOS]		= { .type = NLA_U8 },
6464d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TOS_MASK]	= { .type = NLA_U8 },
6474d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TTL]		= { .type = NLA_U8 },
6484d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TTL_MASK]	= { .type = NLA_U8 },
649d64efd09SJianbo Liu 	[TCA_FLOWER_KEY_CVLAN_ID]	= { .type = NLA_U16 },
650d64efd09SJianbo Liu 	[TCA_FLOWER_KEY_CVLAN_PRIO]	= { .type = NLA_U8 },
651d64efd09SJianbo Liu 	[TCA_FLOWER_KEY_CVLAN_ETH_TYPE]	= { .type = NLA_U16 },
6520e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TOS]	= { .type = NLA_U8 },
6530e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TOS_MASK] = { .type = NLA_U8 },
6540e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TTL]	 = { .type = NLA_U8 },
6550e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TTL_MASK] = { .type = NLA_U8 },
6560a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPTS]	= { .type = NLA_NESTED },
6570a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPTS_MASK]	= { .type = NLA_NESTED },
6580a6e7778SPieter Jansen van Vuuren };
6590a6e7778SPieter Jansen van Vuuren 
6600a6e7778SPieter Jansen van Vuuren static const struct nla_policy
6610a6e7778SPieter Jansen van Vuuren enc_opts_policy[TCA_FLOWER_KEY_ENC_OPTS_MAX + 1] = {
6620a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPTS_GENEVE]        = { .type = NLA_NESTED },
6630a6e7778SPieter Jansen van Vuuren };
6640a6e7778SPieter Jansen van Vuuren 
6650a6e7778SPieter Jansen van Vuuren static const struct nla_policy
6660a6e7778SPieter Jansen van Vuuren geneve_opt_policy[TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX + 1] = {
6670a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS]      = { .type = NLA_U16 },
6680a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE]       = { .type = NLA_U8 },
6690a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA]       = { .type = NLA_BINARY,
6700a6e7778SPieter Jansen van Vuuren 						       .len = 128 },
67177b9900eSJiri Pirko };
67277b9900eSJiri Pirko 
67377b9900eSJiri Pirko static void fl_set_key_val(struct nlattr **tb,
67477b9900eSJiri Pirko 			   void *val, int val_type,
67577b9900eSJiri Pirko 			   void *mask, int mask_type, int len)
67677b9900eSJiri Pirko {
67777b9900eSJiri Pirko 	if (!tb[val_type])
67877b9900eSJiri Pirko 		return;
67977b9900eSJiri Pirko 	memcpy(val, nla_data(tb[val_type]), len);
68077b9900eSJiri Pirko 	if (mask_type == TCA_FLOWER_UNSPEC || !tb[mask_type])
68177b9900eSJiri Pirko 		memset(mask, 0xff, len);
68277b9900eSJiri Pirko 	else
68377b9900eSJiri Pirko 		memcpy(mask, nla_data(tb[mask_type]), len);
68477b9900eSJiri Pirko }
68577b9900eSJiri Pirko 
6865c72299fSAmritha Nambiar static int fl_set_key_port_range(struct nlattr **tb, struct fl_flow_key *key,
6875c72299fSAmritha Nambiar 				 struct fl_flow_key *mask)
6885c72299fSAmritha Nambiar {
6895c72299fSAmritha Nambiar 	fl_set_key_val(tb, &key->tp_min.dst,
6905c72299fSAmritha Nambiar 		       TCA_FLOWER_KEY_PORT_DST_MIN, &mask->tp_min.dst,
6915c72299fSAmritha Nambiar 		       TCA_FLOWER_UNSPEC, sizeof(key->tp_min.dst));
6925c72299fSAmritha Nambiar 	fl_set_key_val(tb, &key->tp_max.dst,
6935c72299fSAmritha Nambiar 		       TCA_FLOWER_KEY_PORT_DST_MAX, &mask->tp_max.dst,
6945c72299fSAmritha Nambiar 		       TCA_FLOWER_UNSPEC, sizeof(key->tp_max.dst));
6955c72299fSAmritha Nambiar 	fl_set_key_val(tb, &key->tp_min.src,
6965c72299fSAmritha Nambiar 		       TCA_FLOWER_KEY_PORT_SRC_MIN, &mask->tp_min.src,
6975c72299fSAmritha Nambiar 		       TCA_FLOWER_UNSPEC, sizeof(key->tp_min.src));
6985c72299fSAmritha Nambiar 	fl_set_key_val(tb, &key->tp_max.src,
6995c72299fSAmritha Nambiar 		       TCA_FLOWER_KEY_PORT_SRC_MAX, &mask->tp_max.src,
7005c72299fSAmritha Nambiar 		       TCA_FLOWER_UNSPEC, sizeof(key->tp_max.src));
7015c72299fSAmritha Nambiar 
7025c72299fSAmritha Nambiar 	if ((mask->tp_min.dst && mask->tp_max.dst &&
7035c72299fSAmritha Nambiar 	     htons(key->tp_max.dst) <= htons(key->tp_min.dst)) ||
7045c72299fSAmritha Nambiar 	     (mask->tp_min.src && mask->tp_max.src &&
7055c72299fSAmritha Nambiar 	      htons(key->tp_max.src) <= htons(key->tp_min.src)))
7065c72299fSAmritha Nambiar 		return -EINVAL;
7075c72299fSAmritha Nambiar 
7085c72299fSAmritha Nambiar 	return 0;
7095c72299fSAmritha Nambiar }
7105c72299fSAmritha Nambiar 
7111a7fca63SBenjamin LaHaise static int fl_set_key_mpls(struct nlattr **tb,
712a577d8f7SBenjamin LaHaise 			   struct flow_dissector_key_mpls *key_val,
713a577d8f7SBenjamin LaHaise 			   struct flow_dissector_key_mpls *key_mask)
714a577d8f7SBenjamin LaHaise {
715a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_TTL]) {
716a577d8f7SBenjamin LaHaise 		key_val->mpls_ttl = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TTL]);
717a577d8f7SBenjamin LaHaise 		key_mask->mpls_ttl = MPLS_TTL_MASK;
718a577d8f7SBenjamin LaHaise 	}
719a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_BOS]) {
7201a7fca63SBenjamin LaHaise 		u8 bos = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_BOS]);
7211a7fca63SBenjamin LaHaise 
7221a7fca63SBenjamin LaHaise 		if (bos & ~MPLS_BOS_MASK)
7231a7fca63SBenjamin LaHaise 			return -EINVAL;
7241a7fca63SBenjamin LaHaise 		key_val->mpls_bos = bos;
725a577d8f7SBenjamin LaHaise 		key_mask->mpls_bos = MPLS_BOS_MASK;
726a577d8f7SBenjamin LaHaise 	}
727a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_TC]) {
7281a7fca63SBenjamin LaHaise 		u8 tc = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TC]);
7291a7fca63SBenjamin LaHaise 
7301a7fca63SBenjamin LaHaise 		if (tc & ~MPLS_TC_MASK)
7311a7fca63SBenjamin LaHaise 			return -EINVAL;
7321a7fca63SBenjamin LaHaise 		key_val->mpls_tc = tc;
733a577d8f7SBenjamin LaHaise 		key_mask->mpls_tc = MPLS_TC_MASK;
734a577d8f7SBenjamin LaHaise 	}
735a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_LABEL]) {
7361a7fca63SBenjamin LaHaise 		u32 label = nla_get_u32(tb[TCA_FLOWER_KEY_MPLS_LABEL]);
7371a7fca63SBenjamin LaHaise 
7381a7fca63SBenjamin LaHaise 		if (label & ~MPLS_LABEL_MASK)
7391a7fca63SBenjamin LaHaise 			return -EINVAL;
7401a7fca63SBenjamin LaHaise 		key_val->mpls_label = label;
741a577d8f7SBenjamin LaHaise 		key_mask->mpls_label = MPLS_LABEL_MASK;
742a577d8f7SBenjamin LaHaise 	}
7431a7fca63SBenjamin LaHaise 	return 0;
744a577d8f7SBenjamin LaHaise }
745a577d8f7SBenjamin LaHaise 
7469399ae9aSHadar Hen Zion static void fl_set_key_vlan(struct nlattr **tb,
747aaab0834SJianbo Liu 			    __be16 ethertype,
748d64efd09SJianbo Liu 			    int vlan_id_key, int vlan_prio_key,
7499399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *key_val,
7509399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *key_mask)
7519399ae9aSHadar Hen Zion {
7529399ae9aSHadar Hen Zion #define VLAN_PRIORITY_MASK	0x7
7539399ae9aSHadar Hen Zion 
754d64efd09SJianbo Liu 	if (tb[vlan_id_key]) {
7559399ae9aSHadar Hen Zion 		key_val->vlan_id =
756d64efd09SJianbo Liu 			nla_get_u16(tb[vlan_id_key]) & VLAN_VID_MASK;
7579399ae9aSHadar Hen Zion 		key_mask->vlan_id = VLAN_VID_MASK;
7589399ae9aSHadar Hen Zion 	}
759d64efd09SJianbo Liu 	if (tb[vlan_prio_key]) {
7609399ae9aSHadar Hen Zion 		key_val->vlan_priority =
761d64efd09SJianbo Liu 			nla_get_u8(tb[vlan_prio_key]) &
7629399ae9aSHadar Hen Zion 			VLAN_PRIORITY_MASK;
7639399ae9aSHadar Hen Zion 		key_mask->vlan_priority = VLAN_PRIORITY_MASK;
7649399ae9aSHadar Hen Zion 	}
765aaab0834SJianbo Liu 	key_val->vlan_tpid = ethertype;
766aaab0834SJianbo Liu 	key_mask->vlan_tpid = cpu_to_be16(~0);
7679399ae9aSHadar Hen Zion }
7689399ae9aSHadar Hen Zion 
769faa3ffceSOr Gerlitz static void fl_set_key_flag(u32 flower_key, u32 flower_mask,
770faa3ffceSOr Gerlitz 			    u32 *dissector_key, u32 *dissector_mask,
771faa3ffceSOr Gerlitz 			    u32 flower_flag_bit, u32 dissector_flag_bit)
772faa3ffceSOr Gerlitz {
773faa3ffceSOr Gerlitz 	if (flower_mask & flower_flag_bit) {
774faa3ffceSOr Gerlitz 		*dissector_mask |= dissector_flag_bit;
775faa3ffceSOr Gerlitz 		if (flower_key & flower_flag_bit)
776faa3ffceSOr Gerlitz 			*dissector_key |= dissector_flag_bit;
777faa3ffceSOr Gerlitz 	}
778faa3ffceSOr Gerlitz }
779faa3ffceSOr Gerlitz 
780d9724772SOr Gerlitz static int fl_set_key_flags(struct nlattr **tb,
781faa3ffceSOr Gerlitz 			    u32 *flags_key, u32 *flags_mask)
782faa3ffceSOr Gerlitz {
783faa3ffceSOr Gerlitz 	u32 key, mask;
784faa3ffceSOr Gerlitz 
785d9724772SOr Gerlitz 	/* mask is mandatory for flags */
786d9724772SOr Gerlitz 	if (!tb[TCA_FLOWER_KEY_FLAGS_MASK])
787d9724772SOr Gerlitz 		return -EINVAL;
788faa3ffceSOr Gerlitz 
789faa3ffceSOr Gerlitz 	key = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS]));
790faa3ffceSOr Gerlitz 	mask = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS_MASK]));
791faa3ffceSOr Gerlitz 
792faa3ffceSOr Gerlitz 	*flags_key  = 0;
793faa3ffceSOr Gerlitz 	*flags_mask = 0;
794faa3ffceSOr Gerlitz 
795faa3ffceSOr Gerlitz 	fl_set_key_flag(key, mask, flags_key, flags_mask,
796faa3ffceSOr Gerlitz 			TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT);
797459d153dSPieter Jansen van Vuuren 	fl_set_key_flag(key, mask, flags_key, flags_mask,
798459d153dSPieter Jansen van Vuuren 			TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST,
799459d153dSPieter Jansen van Vuuren 			FLOW_DIS_FIRST_FRAG);
800d9724772SOr Gerlitz 
801d9724772SOr Gerlitz 	return 0;
802faa3ffceSOr Gerlitz }
803faa3ffceSOr Gerlitz 
8040e2c17b6SOr Gerlitz static void fl_set_key_ip(struct nlattr **tb, bool encap,
8054d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *key,
8064d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *mask)
8074d80cc0aSOr Gerlitz {
8080e2c17b6SOr Gerlitz 	int tos_key = encap ? TCA_FLOWER_KEY_ENC_IP_TOS : TCA_FLOWER_KEY_IP_TOS;
8090e2c17b6SOr Gerlitz 	int ttl_key = encap ? TCA_FLOWER_KEY_ENC_IP_TTL : TCA_FLOWER_KEY_IP_TTL;
8100e2c17b6SOr Gerlitz 	int tos_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TOS_MASK : TCA_FLOWER_KEY_IP_TOS_MASK;
8110e2c17b6SOr Gerlitz 	int ttl_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TTL_MASK : TCA_FLOWER_KEY_IP_TTL_MASK;
8124d80cc0aSOr Gerlitz 
8130e2c17b6SOr Gerlitz 	fl_set_key_val(tb, &key->tos, tos_key, &mask->tos, tos_mask, sizeof(key->tos));
8140e2c17b6SOr Gerlitz 	fl_set_key_val(tb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl));
8154d80cc0aSOr Gerlitz }
8164d80cc0aSOr Gerlitz 
8170a6e7778SPieter Jansen van Vuuren static int fl_set_geneve_opt(const struct nlattr *nla, struct fl_flow_key *key,
8180a6e7778SPieter Jansen van Vuuren 			     int depth, int option_len,
8190a6e7778SPieter Jansen van Vuuren 			     struct netlink_ext_ack *extack)
8200a6e7778SPieter Jansen van Vuuren {
8210a6e7778SPieter Jansen van Vuuren 	struct nlattr *tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX + 1];
8220a6e7778SPieter Jansen van Vuuren 	struct nlattr *class = NULL, *type = NULL, *data = NULL;
8230a6e7778SPieter Jansen van Vuuren 	struct geneve_opt *opt;
8240a6e7778SPieter Jansen van Vuuren 	int err, data_len = 0;
8250a6e7778SPieter Jansen van Vuuren 
8260a6e7778SPieter Jansen van Vuuren 	if (option_len > sizeof(struct geneve_opt))
8270a6e7778SPieter Jansen van Vuuren 		data_len = option_len - sizeof(struct geneve_opt);
8280a6e7778SPieter Jansen van Vuuren 
8290a6e7778SPieter Jansen van Vuuren 	opt = (struct geneve_opt *)&key->enc_opts.data[key->enc_opts.len];
8300a6e7778SPieter Jansen van Vuuren 	memset(opt, 0xff, option_len);
8310a6e7778SPieter Jansen van Vuuren 	opt->length = data_len / 4;
8320a6e7778SPieter Jansen van Vuuren 	opt->r1 = 0;
8330a6e7778SPieter Jansen van Vuuren 	opt->r2 = 0;
8340a6e7778SPieter Jansen van Vuuren 	opt->r3 = 0;
8350a6e7778SPieter Jansen van Vuuren 
8360a6e7778SPieter Jansen van Vuuren 	/* If no mask has been prodived we assume an exact match. */
8370a6e7778SPieter Jansen van Vuuren 	if (!depth)
8380a6e7778SPieter Jansen van Vuuren 		return sizeof(struct geneve_opt) + data_len;
8390a6e7778SPieter Jansen van Vuuren 
8400a6e7778SPieter Jansen van Vuuren 	if (nla_type(nla) != TCA_FLOWER_KEY_ENC_OPTS_GENEVE) {
8410a6e7778SPieter Jansen van Vuuren 		NL_SET_ERR_MSG(extack, "Non-geneve option type for mask");
8420a6e7778SPieter Jansen van Vuuren 		return -EINVAL;
8430a6e7778SPieter Jansen van Vuuren 	}
8440a6e7778SPieter Jansen van Vuuren 
8450a6e7778SPieter Jansen van Vuuren 	err = nla_parse_nested(tb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX,
8460a6e7778SPieter Jansen van Vuuren 			       nla, geneve_opt_policy, extack);
8470a6e7778SPieter Jansen van Vuuren 	if (err < 0)
8480a6e7778SPieter Jansen van Vuuren 		return err;
8490a6e7778SPieter Jansen van Vuuren 
8500a6e7778SPieter Jansen van Vuuren 	/* We are not allowed to omit any of CLASS, TYPE or DATA
8510a6e7778SPieter Jansen van Vuuren 	 * fields from the key.
8520a6e7778SPieter Jansen van Vuuren 	 */
8530a6e7778SPieter Jansen van Vuuren 	if (!option_len &&
8540a6e7778SPieter Jansen van Vuuren 	    (!tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS] ||
8550a6e7778SPieter Jansen van Vuuren 	     !tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE] ||
8560a6e7778SPieter Jansen van Vuuren 	     !tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA])) {
8570a6e7778SPieter Jansen van Vuuren 		NL_SET_ERR_MSG(extack, "Missing tunnel key geneve option class, type or data");
8580a6e7778SPieter Jansen van Vuuren 		return -EINVAL;
8590a6e7778SPieter Jansen van Vuuren 	}
8600a6e7778SPieter Jansen van Vuuren 
8610a6e7778SPieter Jansen van Vuuren 	/* Omitting any of CLASS, TYPE or DATA fields is allowed
8620a6e7778SPieter Jansen van Vuuren 	 * for the mask.
8630a6e7778SPieter Jansen van Vuuren 	 */
8640a6e7778SPieter Jansen van Vuuren 	if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA]) {
8650a6e7778SPieter Jansen van Vuuren 		int new_len = key->enc_opts.len;
8660a6e7778SPieter Jansen van Vuuren 
8670a6e7778SPieter Jansen van Vuuren 		data = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA];
8680a6e7778SPieter Jansen van Vuuren 		data_len = nla_len(data);
8690a6e7778SPieter Jansen van Vuuren 		if (data_len < 4) {
8700a6e7778SPieter Jansen van Vuuren 			NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is less than 4 bytes long");
8710a6e7778SPieter Jansen van Vuuren 			return -ERANGE;
8720a6e7778SPieter Jansen van Vuuren 		}
8730a6e7778SPieter Jansen van Vuuren 		if (data_len % 4) {
8740a6e7778SPieter Jansen van Vuuren 			NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is not a multiple of 4 bytes long");
8750a6e7778SPieter Jansen van Vuuren 			return -ERANGE;
8760a6e7778SPieter Jansen van Vuuren 		}
8770a6e7778SPieter Jansen van Vuuren 
8780a6e7778SPieter Jansen van Vuuren 		new_len += sizeof(struct geneve_opt) + data_len;
8790a6e7778SPieter Jansen van Vuuren 		BUILD_BUG_ON(FLOW_DIS_TUN_OPTS_MAX != IP_TUNNEL_OPTS_MAX);
8800a6e7778SPieter Jansen van Vuuren 		if (new_len > FLOW_DIS_TUN_OPTS_MAX) {
8810a6e7778SPieter Jansen van Vuuren 			NL_SET_ERR_MSG(extack, "Tunnel options exceeds max size");
8820a6e7778SPieter Jansen van Vuuren 			return -ERANGE;
8830a6e7778SPieter Jansen van Vuuren 		}
8840a6e7778SPieter Jansen van Vuuren 		opt->length = data_len / 4;
8850a6e7778SPieter Jansen van Vuuren 		memcpy(opt->opt_data, nla_data(data), data_len);
8860a6e7778SPieter Jansen van Vuuren 	}
8870a6e7778SPieter Jansen van Vuuren 
8880a6e7778SPieter Jansen van Vuuren 	if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS]) {
8890a6e7778SPieter Jansen van Vuuren 		class = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS];
8900a6e7778SPieter Jansen van Vuuren 		opt->opt_class = nla_get_be16(class);
8910a6e7778SPieter Jansen van Vuuren 	}
8920a6e7778SPieter Jansen van Vuuren 
8930a6e7778SPieter Jansen van Vuuren 	if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE]) {
8940a6e7778SPieter Jansen van Vuuren 		type = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE];
8950a6e7778SPieter Jansen van Vuuren 		opt->type = nla_get_u8(type);
8960a6e7778SPieter Jansen van Vuuren 	}
8970a6e7778SPieter Jansen van Vuuren 
8980a6e7778SPieter Jansen van Vuuren 	return sizeof(struct geneve_opt) + data_len;
8990a6e7778SPieter Jansen van Vuuren }
9000a6e7778SPieter Jansen van Vuuren 
9010a6e7778SPieter Jansen van Vuuren static int fl_set_enc_opt(struct nlattr **tb, struct fl_flow_key *key,
9020a6e7778SPieter Jansen van Vuuren 			  struct fl_flow_key *mask,
9030a6e7778SPieter Jansen van Vuuren 			  struct netlink_ext_ack *extack)
9040a6e7778SPieter Jansen van Vuuren {
9050a6e7778SPieter Jansen van Vuuren 	const struct nlattr *nla_enc_key, *nla_opt_key, *nla_opt_msk = NULL;
90663c82997SJakub Kicinski 	int err, option_len, key_depth, msk_depth = 0;
90763c82997SJakub Kicinski 
90863c82997SJakub Kicinski 	err = nla_validate_nested(tb[TCA_FLOWER_KEY_ENC_OPTS],
90963c82997SJakub Kicinski 				  TCA_FLOWER_KEY_ENC_OPTS_MAX,
91063c82997SJakub Kicinski 				  enc_opts_policy, extack);
91163c82997SJakub Kicinski 	if (err)
91263c82997SJakub Kicinski 		return err;
9130a6e7778SPieter Jansen van Vuuren 
9140a6e7778SPieter Jansen van Vuuren 	nla_enc_key = nla_data(tb[TCA_FLOWER_KEY_ENC_OPTS]);
9150a6e7778SPieter Jansen van Vuuren 
9160a6e7778SPieter Jansen van Vuuren 	if (tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]) {
91763c82997SJakub Kicinski 		err = nla_validate_nested(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK],
91863c82997SJakub Kicinski 					  TCA_FLOWER_KEY_ENC_OPTS_MAX,
91963c82997SJakub Kicinski 					  enc_opts_policy, extack);
92063c82997SJakub Kicinski 		if (err)
92163c82997SJakub Kicinski 			return err;
92263c82997SJakub Kicinski 
9230a6e7778SPieter Jansen van Vuuren 		nla_opt_msk = nla_data(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]);
9240a6e7778SPieter Jansen van Vuuren 		msk_depth = nla_len(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]);
9250a6e7778SPieter Jansen van Vuuren 	}
9260a6e7778SPieter Jansen van Vuuren 
9270a6e7778SPieter Jansen van Vuuren 	nla_for_each_attr(nla_opt_key, nla_enc_key,
9280a6e7778SPieter Jansen van Vuuren 			  nla_len(tb[TCA_FLOWER_KEY_ENC_OPTS]), key_depth) {
9290a6e7778SPieter Jansen van Vuuren 		switch (nla_type(nla_opt_key)) {
9300a6e7778SPieter Jansen van Vuuren 		case TCA_FLOWER_KEY_ENC_OPTS_GENEVE:
9310a6e7778SPieter Jansen van Vuuren 			option_len = 0;
9320a6e7778SPieter Jansen van Vuuren 			key->enc_opts.dst_opt_type = TUNNEL_GENEVE_OPT;
9330a6e7778SPieter Jansen van Vuuren 			option_len = fl_set_geneve_opt(nla_opt_key, key,
9340a6e7778SPieter Jansen van Vuuren 						       key_depth, option_len,
9350a6e7778SPieter Jansen van Vuuren 						       extack);
9360a6e7778SPieter Jansen van Vuuren 			if (option_len < 0)
9370a6e7778SPieter Jansen van Vuuren 				return option_len;
9380a6e7778SPieter Jansen van Vuuren 
9390a6e7778SPieter Jansen van Vuuren 			key->enc_opts.len += option_len;
9400a6e7778SPieter Jansen van Vuuren 			/* At the same time we need to parse through the mask
9410a6e7778SPieter Jansen van Vuuren 			 * in order to verify exact and mask attribute lengths.
9420a6e7778SPieter Jansen van Vuuren 			 */
9430a6e7778SPieter Jansen van Vuuren 			mask->enc_opts.dst_opt_type = TUNNEL_GENEVE_OPT;
9440a6e7778SPieter Jansen van Vuuren 			option_len = fl_set_geneve_opt(nla_opt_msk, mask,
9450a6e7778SPieter Jansen van Vuuren 						       msk_depth, option_len,
9460a6e7778SPieter Jansen van Vuuren 						       extack);
9470a6e7778SPieter Jansen van Vuuren 			if (option_len < 0)
9480a6e7778SPieter Jansen van Vuuren 				return option_len;
9490a6e7778SPieter Jansen van Vuuren 
9500a6e7778SPieter Jansen van Vuuren 			mask->enc_opts.len += option_len;
9510a6e7778SPieter Jansen van Vuuren 			if (key->enc_opts.len != mask->enc_opts.len) {
9520a6e7778SPieter Jansen van Vuuren 				NL_SET_ERR_MSG(extack, "Key and mask miss aligned");
9530a6e7778SPieter Jansen van Vuuren 				return -EINVAL;
9540a6e7778SPieter Jansen van Vuuren 			}
9550a6e7778SPieter Jansen van Vuuren 
9560a6e7778SPieter Jansen van Vuuren 			if (msk_depth)
9570a6e7778SPieter Jansen van Vuuren 				nla_opt_msk = nla_next(nla_opt_msk, &msk_depth);
9580a6e7778SPieter Jansen van Vuuren 			break;
9590a6e7778SPieter Jansen van Vuuren 		default:
9600a6e7778SPieter Jansen van Vuuren 			NL_SET_ERR_MSG(extack, "Unknown tunnel option type");
9610a6e7778SPieter Jansen van Vuuren 			return -EINVAL;
9620a6e7778SPieter Jansen van Vuuren 		}
9630a6e7778SPieter Jansen van Vuuren 	}
9640a6e7778SPieter Jansen van Vuuren 
9650a6e7778SPieter Jansen van Vuuren 	return 0;
9660a6e7778SPieter Jansen van Vuuren }
9670a6e7778SPieter Jansen van Vuuren 
96877b9900eSJiri Pirko static int fl_set_key(struct net *net, struct nlattr **tb,
9691057c55fSAlexander Aring 		      struct fl_flow_key *key, struct fl_flow_key *mask,
9701057c55fSAlexander Aring 		      struct netlink_ext_ack *extack)
97177b9900eSJiri Pirko {
9729399ae9aSHadar Hen Zion 	__be16 ethertype;
973d9724772SOr Gerlitz 	int ret = 0;
974dd3aa3b5SBrian Haley #ifdef CONFIG_NET_CLS_IND
97577b9900eSJiri Pirko 	if (tb[TCA_FLOWER_INDEV]) {
9761057c55fSAlexander Aring 		int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV], extack);
97777b9900eSJiri Pirko 		if (err < 0)
97877b9900eSJiri Pirko 			return err;
97977b9900eSJiri Pirko 		key->indev_ifindex = err;
98077b9900eSJiri Pirko 		mask->indev_ifindex = 0xffffffff;
98177b9900eSJiri Pirko 	}
982dd3aa3b5SBrian Haley #endif
98377b9900eSJiri Pirko 
98477b9900eSJiri Pirko 	fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
98577b9900eSJiri Pirko 		       mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
98677b9900eSJiri Pirko 		       sizeof(key->eth.dst));
98777b9900eSJiri Pirko 	fl_set_key_val(tb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
98877b9900eSJiri Pirko 		       mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
98977b9900eSJiri Pirko 		       sizeof(key->eth.src));
99066530bdfSJamal Hadi Salim 
9910b498a52SArnd Bergmann 	if (tb[TCA_FLOWER_KEY_ETH_TYPE]) {
9929399ae9aSHadar Hen Zion 		ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_ETH_TYPE]);
9939399ae9aSHadar Hen Zion 
994aaab0834SJianbo Liu 		if (eth_type_vlan(ethertype)) {
995d64efd09SJianbo Liu 			fl_set_key_vlan(tb, ethertype, TCA_FLOWER_KEY_VLAN_ID,
996d64efd09SJianbo Liu 					TCA_FLOWER_KEY_VLAN_PRIO, &key->vlan,
997d64efd09SJianbo Liu 					&mask->vlan);
998d64efd09SJianbo Liu 
9995e9a0fe4SJianbo Liu 			if (tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]) {
1000d64efd09SJianbo Liu 				ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]);
1001d64efd09SJianbo Liu 				if (eth_type_vlan(ethertype)) {
1002d64efd09SJianbo Liu 					fl_set_key_vlan(tb, ethertype,
1003d64efd09SJianbo Liu 							TCA_FLOWER_KEY_CVLAN_ID,
1004d64efd09SJianbo Liu 							TCA_FLOWER_KEY_CVLAN_PRIO,
1005d64efd09SJianbo Liu 							&key->cvlan, &mask->cvlan);
10069399ae9aSHadar Hen Zion 					fl_set_key_val(tb, &key->basic.n_proto,
1007d64efd09SJianbo Liu 						       TCA_FLOWER_KEY_CVLAN_ETH_TYPE,
1008d64efd09SJianbo Liu 						       &mask->basic.n_proto,
1009d64efd09SJianbo Liu 						       TCA_FLOWER_UNSPEC,
101077b9900eSJiri Pirko 						       sizeof(key->basic.n_proto));
10119399ae9aSHadar Hen Zion 				} else {
10129399ae9aSHadar Hen Zion 					key->basic.n_proto = ethertype;
10139399ae9aSHadar Hen Zion 					mask->basic.n_proto = cpu_to_be16(~0);
10149399ae9aSHadar Hen Zion 				}
10155e9a0fe4SJianbo Liu 			}
1016d64efd09SJianbo Liu 		} else {
1017d64efd09SJianbo Liu 			key->basic.n_proto = ethertype;
1018d64efd09SJianbo Liu 			mask->basic.n_proto = cpu_to_be16(~0);
1019d64efd09SJianbo Liu 		}
10200b498a52SArnd Bergmann 	}
102166530bdfSJamal Hadi Salim 
102277b9900eSJiri Pirko 	if (key->basic.n_proto == htons(ETH_P_IP) ||
102377b9900eSJiri Pirko 	    key->basic.n_proto == htons(ETH_P_IPV6)) {
102477b9900eSJiri Pirko 		fl_set_key_val(tb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
102577b9900eSJiri Pirko 			       &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
102677b9900eSJiri Pirko 			       sizeof(key->basic.ip_proto));
10270e2c17b6SOr Gerlitz 		fl_set_key_ip(tb, false, &key->ip, &mask->ip);
102877b9900eSJiri Pirko 	}
102966530bdfSJamal Hadi Salim 
103066530bdfSJamal Hadi Salim 	if (tb[TCA_FLOWER_KEY_IPV4_SRC] || tb[TCA_FLOWER_KEY_IPV4_DST]) {
103166530bdfSJamal Hadi Salim 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
1032970bfcd0SPaul Blakey 		mask->control.addr_type = ~0;
103377b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
103477b9900eSJiri Pirko 			       &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
103577b9900eSJiri Pirko 			       sizeof(key->ipv4.src));
103677b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
103777b9900eSJiri Pirko 			       &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
103877b9900eSJiri Pirko 			       sizeof(key->ipv4.dst));
103966530bdfSJamal Hadi Salim 	} else if (tb[TCA_FLOWER_KEY_IPV6_SRC] || tb[TCA_FLOWER_KEY_IPV6_DST]) {
104066530bdfSJamal Hadi Salim 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
1041970bfcd0SPaul Blakey 		mask->control.addr_type = ~0;
104277b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
104377b9900eSJiri Pirko 			       &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
104477b9900eSJiri Pirko 			       sizeof(key->ipv6.src));
104577b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
104677b9900eSJiri Pirko 			       &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
104777b9900eSJiri Pirko 			       sizeof(key->ipv6.dst));
104877b9900eSJiri Pirko 	}
104966530bdfSJamal Hadi Salim 
105077b9900eSJiri Pirko 	if (key->basic.ip_proto == IPPROTO_TCP) {
105177b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
1052aa72d708SOr Gerlitz 			       &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
105377b9900eSJiri Pirko 			       sizeof(key->tp.src));
105477b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
1055aa72d708SOr Gerlitz 			       &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
105677b9900eSJiri Pirko 			       sizeof(key->tp.dst));
1057fdfc7dd6SJiri Pirko 		fl_set_key_val(tb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS,
1058fdfc7dd6SJiri Pirko 			       &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK,
1059fdfc7dd6SJiri Pirko 			       sizeof(key->tcp.flags));
106077b9900eSJiri Pirko 	} else if (key->basic.ip_proto == IPPROTO_UDP) {
106177b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
1062aa72d708SOr Gerlitz 			       &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
106377b9900eSJiri Pirko 			       sizeof(key->tp.src));
106477b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
1065aa72d708SOr Gerlitz 			       &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
106677b9900eSJiri Pirko 			       sizeof(key->tp.dst));
10675976c5f4SSimon Horman 	} else if (key->basic.ip_proto == IPPROTO_SCTP) {
10685976c5f4SSimon Horman 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
10695976c5f4SSimon Horman 			       &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
10705976c5f4SSimon Horman 			       sizeof(key->tp.src));
10715976c5f4SSimon Horman 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
10725976c5f4SSimon Horman 			       &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
10735976c5f4SSimon Horman 			       sizeof(key->tp.dst));
10747b684884SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_IP) &&
10757b684884SSimon Horman 		   key->basic.ip_proto == IPPROTO_ICMP) {
10767b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV4_TYPE,
10777b684884SSimon Horman 			       &mask->icmp.type,
10787b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,
10797b684884SSimon Horman 			       sizeof(key->icmp.type));
10807b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE,
10817b684884SSimon Horman 			       &mask->icmp.code,
10827b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
10837b684884SSimon Horman 			       sizeof(key->icmp.code));
10847b684884SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_IPV6) &&
10857b684884SSimon Horman 		   key->basic.ip_proto == IPPROTO_ICMPV6) {
10867b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV6_TYPE,
10877b684884SSimon Horman 			       &mask->icmp.type,
10887b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
10897b684884SSimon Horman 			       sizeof(key->icmp.type));
1090040587afSSimon Horman 		fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV6_CODE,
10917b684884SSimon Horman 			       &mask->icmp.code,
1092040587afSSimon Horman 			       TCA_FLOWER_KEY_ICMPV6_CODE_MASK,
10937b684884SSimon Horman 			       sizeof(key->icmp.code));
1094a577d8f7SBenjamin LaHaise 	} else if (key->basic.n_proto == htons(ETH_P_MPLS_UC) ||
1095a577d8f7SBenjamin LaHaise 		   key->basic.n_proto == htons(ETH_P_MPLS_MC)) {
10961a7fca63SBenjamin LaHaise 		ret = fl_set_key_mpls(tb, &key->mpls, &mask->mpls);
10971a7fca63SBenjamin LaHaise 		if (ret)
10981a7fca63SBenjamin LaHaise 			return ret;
109999d31326SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_ARP) ||
110099d31326SSimon Horman 		   key->basic.n_proto == htons(ETH_P_RARP)) {
110199d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.sip, TCA_FLOWER_KEY_ARP_SIP,
110299d31326SSimon Horman 			       &mask->arp.sip, TCA_FLOWER_KEY_ARP_SIP_MASK,
110399d31326SSimon Horman 			       sizeof(key->arp.sip));
110499d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.tip, TCA_FLOWER_KEY_ARP_TIP,
110599d31326SSimon Horman 			       &mask->arp.tip, TCA_FLOWER_KEY_ARP_TIP_MASK,
110699d31326SSimon Horman 			       sizeof(key->arp.tip));
110799d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.op, TCA_FLOWER_KEY_ARP_OP,
110899d31326SSimon Horman 			       &mask->arp.op, TCA_FLOWER_KEY_ARP_OP_MASK,
110999d31326SSimon Horman 			       sizeof(key->arp.op));
111099d31326SSimon Horman 		fl_set_key_val(tb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA,
111199d31326SSimon Horman 			       mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK,
111299d31326SSimon Horman 			       sizeof(key->arp.sha));
111399d31326SSimon Horman 		fl_set_key_val(tb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA,
111499d31326SSimon Horman 			       mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK,
111599d31326SSimon Horman 			       sizeof(key->arp.tha));
111677b9900eSJiri Pirko 	}
111777b9900eSJiri Pirko 
11185c72299fSAmritha Nambiar 	if (key->basic.ip_proto == IPPROTO_TCP ||
11195c72299fSAmritha Nambiar 	    key->basic.ip_proto == IPPROTO_UDP ||
11205c72299fSAmritha Nambiar 	    key->basic.ip_proto == IPPROTO_SCTP) {
11215c72299fSAmritha Nambiar 		ret = fl_set_key_port_range(tb, key, mask);
11225c72299fSAmritha Nambiar 		if (ret)
11235c72299fSAmritha Nambiar 			return ret;
11245c72299fSAmritha Nambiar 	}
11255c72299fSAmritha Nambiar 
1126bc3103f1SAmir Vadai 	if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] ||
1127bc3103f1SAmir Vadai 	    tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) {
1128bc3103f1SAmir Vadai 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
1129970bfcd0SPaul Blakey 		mask->enc_control.addr_type = ~0;
1130bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv4.src,
1131bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_SRC,
1132bc3103f1SAmir Vadai 			       &mask->enc_ipv4.src,
1133bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
1134bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv4.src));
1135bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv4.dst,
1136bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_DST,
1137bc3103f1SAmir Vadai 			       &mask->enc_ipv4.dst,
1138bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
1139bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv4.dst));
1140bc3103f1SAmir Vadai 	}
1141bc3103f1SAmir Vadai 
1142bc3103f1SAmir Vadai 	if (tb[TCA_FLOWER_KEY_ENC_IPV6_SRC] ||
1143bc3103f1SAmir Vadai 	    tb[TCA_FLOWER_KEY_ENC_IPV6_DST]) {
1144bc3103f1SAmir Vadai 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
1145970bfcd0SPaul Blakey 		mask->enc_control.addr_type = ~0;
1146bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv6.src,
1147bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_SRC,
1148bc3103f1SAmir Vadai 			       &mask->enc_ipv6.src,
1149bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
1150bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv6.src));
1151bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv6.dst,
1152bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_DST,
1153bc3103f1SAmir Vadai 			       &mask->enc_ipv6.dst,
1154bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
1155bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv6.dst));
1156bc3103f1SAmir Vadai 	}
1157bc3103f1SAmir Vadai 
1158bc3103f1SAmir Vadai 	fl_set_key_val(tb, &key->enc_key_id.keyid, TCA_FLOWER_KEY_ENC_KEY_ID,
1159eb523f42SHadar Hen Zion 		       &mask->enc_key_id.keyid, TCA_FLOWER_UNSPEC,
1160bc3103f1SAmir Vadai 		       sizeof(key->enc_key_id.keyid));
1161bc3103f1SAmir Vadai 
1162f4d997fdSHadar Hen Zion 	fl_set_key_val(tb, &key->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
1163f4d997fdSHadar Hen Zion 		       &mask->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
1164f4d997fdSHadar Hen Zion 		       sizeof(key->enc_tp.src));
1165f4d997fdSHadar Hen Zion 
1166f4d997fdSHadar Hen Zion 	fl_set_key_val(tb, &key->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
1167f4d997fdSHadar Hen Zion 		       &mask->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
1168f4d997fdSHadar Hen Zion 		       sizeof(key->enc_tp.dst));
1169f4d997fdSHadar Hen Zion 
11700e2c17b6SOr Gerlitz 	fl_set_key_ip(tb, true, &key->enc_ip, &mask->enc_ip);
11710e2c17b6SOr Gerlitz 
11720a6e7778SPieter Jansen van Vuuren 	if (tb[TCA_FLOWER_KEY_ENC_OPTS]) {
11730a6e7778SPieter Jansen van Vuuren 		ret = fl_set_enc_opt(tb, key, mask, extack);
11740a6e7778SPieter Jansen van Vuuren 		if (ret)
11750a6e7778SPieter Jansen van Vuuren 			return ret;
11760a6e7778SPieter Jansen van Vuuren 	}
11770a6e7778SPieter Jansen van Vuuren 
1178d9724772SOr Gerlitz 	if (tb[TCA_FLOWER_KEY_FLAGS])
1179d9724772SOr Gerlitz 		ret = fl_set_key_flags(tb, &key->control.flags, &mask->control.flags);
1180faa3ffceSOr Gerlitz 
1181d9724772SOr Gerlitz 	return ret;
118277b9900eSJiri Pirko }
118377b9900eSJiri Pirko 
118405cd271fSPaul Blakey static void fl_mask_copy(struct fl_flow_mask *dst,
118505cd271fSPaul Blakey 			 struct fl_flow_mask *src)
118677b9900eSJiri Pirko {
118705cd271fSPaul Blakey 	const void *psrc = fl_key_get_start(&src->key, src);
118805cd271fSPaul Blakey 	void *pdst = fl_key_get_start(&dst->key, src);
118977b9900eSJiri Pirko 
119005cd271fSPaul Blakey 	memcpy(pdst, psrc, fl_mask_range(src));
119105cd271fSPaul Blakey 	dst->range = src->range;
119277b9900eSJiri Pirko }
119377b9900eSJiri Pirko 
119477b9900eSJiri Pirko static const struct rhashtable_params fl_ht_params = {
119577b9900eSJiri Pirko 	.key_offset = offsetof(struct cls_fl_filter, mkey), /* base offset */
119677b9900eSJiri Pirko 	.head_offset = offsetof(struct cls_fl_filter, ht_node),
119777b9900eSJiri Pirko 	.automatic_shrinking = true,
119877b9900eSJiri Pirko };
119977b9900eSJiri Pirko 
120005cd271fSPaul Blakey static int fl_init_mask_hashtable(struct fl_flow_mask *mask)
120177b9900eSJiri Pirko {
120205cd271fSPaul Blakey 	mask->filter_ht_params = fl_ht_params;
120305cd271fSPaul Blakey 	mask->filter_ht_params.key_len = fl_mask_range(mask);
120405cd271fSPaul Blakey 	mask->filter_ht_params.key_offset += mask->range.start;
120577b9900eSJiri Pirko 
120605cd271fSPaul Blakey 	return rhashtable_init(&mask->ht, &mask->filter_ht_params);
120777b9900eSJiri Pirko }
120877b9900eSJiri Pirko 
120977b9900eSJiri Pirko #define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member)
1210cb205a81Szhong jiang #define FL_KEY_MEMBER_SIZE(member) FIELD_SIZEOF(struct fl_flow_key, member)
121177b9900eSJiri Pirko 
1212339ba878SHadar Hen Zion #define FL_KEY_IS_MASKED(mask, member)						\
1213339ba878SHadar Hen Zion 	memchr_inv(((char *)mask) + FL_KEY_MEMBER_OFFSET(member),		\
1214339ba878SHadar Hen Zion 		   0, FL_KEY_MEMBER_SIZE(member))				\
121577b9900eSJiri Pirko 
121677b9900eSJiri Pirko #define FL_KEY_SET(keys, cnt, id, member)					\
121777b9900eSJiri Pirko 	do {									\
121877b9900eSJiri Pirko 		keys[cnt].key_id = id;						\
121977b9900eSJiri Pirko 		keys[cnt].offset = FL_KEY_MEMBER_OFFSET(member);		\
122077b9900eSJiri Pirko 		cnt++;								\
122177b9900eSJiri Pirko 	} while(0);
122277b9900eSJiri Pirko 
1223339ba878SHadar Hen Zion #define FL_KEY_SET_IF_MASKED(mask, keys, cnt, id, member)			\
122477b9900eSJiri Pirko 	do {									\
1225339ba878SHadar Hen Zion 		if (FL_KEY_IS_MASKED(mask, member))				\
122677b9900eSJiri Pirko 			FL_KEY_SET(keys, cnt, id, member);			\
122777b9900eSJiri Pirko 	} while(0);
122877b9900eSJiri Pirko 
122933fb5cbaSJiri Pirko static void fl_init_dissector(struct flow_dissector *dissector,
123033fb5cbaSJiri Pirko 			      struct fl_flow_key *mask)
123177b9900eSJiri Pirko {
123277b9900eSJiri Pirko 	struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX];
123377b9900eSJiri Pirko 	size_t cnt = 0;
123477b9900eSJiri Pirko 
123542aecaa9STom Herbert 	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control);
123677b9900eSJiri Pirko 	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic);
123733fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
123877b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_ETH_ADDRS, eth);
123933fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
124077b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4);
124133fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
124277b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6);
12435c72299fSAmritha Nambiar 	if (FL_KEY_IS_MASKED(mask, tp) ||
12445c72299fSAmritha Nambiar 	    FL_KEY_IS_MASKED(mask, tp_min) || FL_KEY_IS_MASKED(mask, tp_max))
12455c72299fSAmritha Nambiar 		FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_PORTS, tp);
124633fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
12474d80cc0aSOr Gerlitz 			     FLOW_DISSECTOR_KEY_IP, ip);
124833fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
1249fdfc7dd6SJiri Pirko 			     FLOW_DISSECTOR_KEY_TCP, tcp);
125033fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
12517b684884SSimon Horman 			     FLOW_DISSECTOR_KEY_ICMP, icmp);
125233fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
125399d31326SSimon Horman 			     FLOW_DISSECTOR_KEY_ARP, arp);
125433fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
1255a577d8f7SBenjamin LaHaise 			     FLOW_DISSECTOR_KEY_MPLS, mpls);
125633fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
12579399ae9aSHadar Hen Zion 			     FLOW_DISSECTOR_KEY_VLAN, vlan);
125833fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
1259d64efd09SJianbo Liu 			     FLOW_DISSECTOR_KEY_CVLAN, cvlan);
126033fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
1261519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_KEYID, enc_key_id);
126233fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
1263519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, enc_ipv4);
126433fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
1265519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, enc_ipv6);
126633fb5cbaSJiri Pirko 	if (FL_KEY_IS_MASKED(mask, enc_ipv4) ||
126733fb5cbaSJiri Pirko 	    FL_KEY_IS_MASKED(mask, enc_ipv6))
1268519d1052SHadar Hen Zion 		FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_ENC_CONTROL,
1269519d1052SHadar Hen Zion 			   enc_control);
127033fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
1271f4d997fdSHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp);
127233fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
12730e2c17b6SOr Gerlitz 			     FLOW_DISSECTOR_KEY_ENC_IP, enc_ip);
12740a6e7778SPieter Jansen van Vuuren 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
12750a6e7778SPieter Jansen van Vuuren 			     FLOW_DISSECTOR_KEY_ENC_OPTS, enc_opts);
127677b9900eSJiri Pirko 
127733fb5cbaSJiri Pirko 	skb_flow_dissector_init(dissector, keys, cnt);
127805cd271fSPaul Blakey }
127905cd271fSPaul Blakey 
128005cd271fSPaul Blakey static struct fl_flow_mask *fl_create_new_mask(struct cls_fl_head *head,
128105cd271fSPaul Blakey 					       struct fl_flow_mask *mask)
128205cd271fSPaul Blakey {
128305cd271fSPaul Blakey 	struct fl_flow_mask *newmask;
128405cd271fSPaul Blakey 	int err;
128505cd271fSPaul Blakey 
128605cd271fSPaul Blakey 	newmask = kzalloc(sizeof(*newmask), GFP_KERNEL);
128705cd271fSPaul Blakey 	if (!newmask)
128805cd271fSPaul Blakey 		return ERR_PTR(-ENOMEM);
128905cd271fSPaul Blakey 
129005cd271fSPaul Blakey 	fl_mask_copy(newmask, mask);
129105cd271fSPaul Blakey 
12925c72299fSAmritha Nambiar 	if ((newmask->key.tp_min.dst && newmask->key.tp_max.dst) ||
12935c72299fSAmritha Nambiar 	    (newmask->key.tp_min.src && newmask->key.tp_max.src))
12945c72299fSAmritha Nambiar 		newmask->flags |= TCA_FLOWER_MASK_FLAGS_RANGE;
12955c72299fSAmritha Nambiar 
129605cd271fSPaul Blakey 	err = fl_init_mask_hashtable(newmask);
129705cd271fSPaul Blakey 	if (err)
129805cd271fSPaul Blakey 		goto errout_free;
129905cd271fSPaul Blakey 
130033fb5cbaSJiri Pirko 	fl_init_dissector(&newmask->dissector, &newmask->key);
130105cd271fSPaul Blakey 
130205cd271fSPaul Blakey 	INIT_LIST_HEAD_RCU(&newmask->filters);
130305cd271fSPaul Blakey 
130405cd271fSPaul Blakey 	err = rhashtable_insert_fast(&head->ht, &newmask->ht_node,
130505cd271fSPaul Blakey 				     mask_ht_params);
130605cd271fSPaul Blakey 	if (err)
130705cd271fSPaul Blakey 		goto errout_destroy;
130805cd271fSPaul Blakey 
130905cd271fSPaul Blakey 	list_add_tail_rcu(&newmask->list, &head->masks);
131005cd271fSPaul Blakey 
131105cd271fSPaul Blakey 	return newmask;
131205cd271fSPaul Blakey 
131305cd271fSPaul Blakey errout_destroy:
131405cd271fSPaul Blakey 	rhashtable_destroy(&newmask->ht);
131505cd271fSPaul Blakey errout_free:
131605cd271fSPaul Blakey 	kfree(newmask);
131705cd271fSPaul Blakey 
131805cd271fSPaul Blakey 	return ERR_PTR(err);
131977b9900eSJiri Pirko }
132077b9900eSJiri Pirko 
132177b9900eSJiri Pirko static int fl_check_assign_mask(struct cls_fl_head *head,
132205cd271fSPaul Blakey 				struct cls_fl_filter *fnew,
132305cd271fSPaul Blakey 				struct cls_fl_filter *fold,
132477b9900eSJiri Pirko 				struct fl_flow_mask *mask)
132577b9900eSJiri Pirko {
132605cd271fSPaul Blakey 	struct fl_flow_mask *newmask;
132777b9900eSJiri Pirko 
132805cd271fSPaul Blakey 	fnew->mask = rhashtable_lookup_fast(&head->ht, mask, mask_ht_params);
132905cd271fSPaul Blakey 	if (!fnew->mask) {
133005cd271fSPaul Blakey 		if (fold)
133177b9900eSJiri Pirko 			return -EINVAL;
133205cd271fSPaul Blakey 
133305cd271fSPaul Blakey 		newmask = fl_create_new_mask(head, mask);
133405cd271fSPaul Blakey 		if (IS_ERR(newmask))
133505cd271fSPaul Blakey 			return PTR_ERR(newmask);
133605cd271fSPaul Blakey 
133705cd271fSPaul Blakey 		fnew->mask = newmask;
1338f6521c58SPaul Blakey 	} else if (fold && fold->mask != fnew->mask) {
133905cd271fSPaul Blakey 		return -EINVAL;
134077b9900eSJiri Pirko 	}
134177b9900eSJiri Pirko 
134277b9900eSJiri Pirko 	return 0;
134377b9900eSJiri Pirko }
134477b9900eSJiri Pirko 
134577b9900eSJiri Pirko static int fl_set_parms(struct net *net, struct tcf_proto *tp,
134677b9900eSJiri Pirko 			struct cls_fl_filter *f, struct fl_flow_mask *mask,
134777b9900eSJiri Pirko 			unsigned long base, struct nlattr **tb,
134850a56190SAlexander Aring 			struct nlattr *est, bool ovr,
1349b95ec7ebSJiri Pirko 			struct fl_flow_tmplt *tmplt,
135050a56190SAlexander Aring 			struct netlink_ext_ack *extack)
135177b9900eSJiri Pirko {
135277b9900eSJiri Pirko 	int err;
135377b9900eSJiri Pirko 
1354ec6743a1SVlad Buslov 	err = tcf_exts_validate(net, tp, tb, est, &f->exts, ovr, true,
1355ec6743a1SVlad Buslov 				extack);
135677b9900eSJiri Pirko 	if (err < 0)
135777b9900eSJiri Pirko 		return err;
135877b9900eSJiri Pirko 
135977b9900eSJiri Pirko 	if (tb[TCA_FLOWER_CLASSID]) {
136077b9900eSJiri Pirko 		f->res.classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]);
136177b9900eSJiri Pirko 		tcf_bind_filter(tp, &f->res, base);
136277b9900eSJiri Pirko 	}
136377b9900eSJiri Pirko 
13641057c55fSAlexander Aring 	err = fl_set_key(net, tb, &f->key, &mask->key, extack);
136577b9900eSJiri Pirko 	if (err)
136645507529SJiri Pirko 		return err;
136777b9900eSJiri Pirko 
136877b9900eSJiri Pirko 	fl_mask_update_range(mask);
136977b9900eSJiri Pirko 	fl_set_masked_key(&f->mkey, &f->key, mask);
137077b9900eSJiri Pirko 
1371b95ec7ebSJiri Pirko 	if (!fl_mask_fits_tmplt(tmplt, mask)) {
1372b95ec7ebSJiri Pirko 		NL_SET_ERR_MSG_MOD(extack, "Mask does not fit the template");
1373b95ec7ebSJiri Pirko 		return -EINVAL;
1374b95ec7ebSJiri Pirko 	}
1375b95ec7ebSJiri Pirko 
137677b9900eSJiri Pirko 	return 0;
137777b9900eSJiri Pirko }
137877b9900eSJiri Pirko 
137977b9900eSJiri Pirko static int fl_change(struct net *net, struct sk_buff *in_skb,
138077b9900eSJiri Pirko 		     struct tcf_proto *tp, unsigned long base,
138177b9900eSJiri Pirko 		     u32 handle, struct nlattr **tca,
138212db03b6SVlad Buslov 		     void **arg, bool ovr, bool rtnl_held,
138312db03b6SVlad Buslov 		     struct netlink_ext_ack *extack)
138477b9900eSJiri Pirko {
1385e474619aSVlad Buslov 	struct cls_fl_head *head = fl_head_dereference(tp);
13868113c095SWANG Cong 	struct cls_fl_filter *fold = *arg;
138777b9900eSJiri Pirko 	struct cls_fl_filter *fnew;
13882cddd201SIvan Vecera 	struct fl_flow_mask *mask;
138939b7b6a6SArnd Bergmann 	struct nlattr **tb;
139077b9900eSJiri Pirko 	int err;
139177b9900eSJiri Pirko 
139206177558SVlad Buslov 	if (!tca[TCA_OPTIONS]) {
139306177558SVlad Buslov 		err = -EINVAL;
139406177558SVlad Buslov 		goto errout_fold;
139506177558SVlad Buslov 	}
139677b9900eSJiri Pirko 
13972cddd201SIvan Vecera 	mask = kzalloc(sizeof(struct fl_flow_mask), GFP_KERNEL);
139806177558SVlad Buslov 	if (!mask) {
139906177558SVlad Buslov 		err = -ENOBUFS;
140006177558SVlad Buslov 		goto errout_fold;
140106177558SVlad Buslov 	}
140239b7b6a6SArnd Bergmann 
14032cddd201SIvan Vecera 	tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL);
14042cddd201SIvan Vecera 	if (!tb) {
14052cddd201SIvan Vecera 		err = -ENOBUFS;
14062cddd201SIvan Vecera 		goto errout_mask_alloc;
14072cddd201SIvan Vecera 	}
14082cddd201SIvan Vecera 
1409fceb6435SJohannes Berg 	err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS],
1410fceb6435SJohannes Berg 			       fl_policy, NULL);
141177b9900eSJiri Pirko 	if (err < 0)
141239b7b6a6SArnd Bergmann 		goto errout_tb;
141377b9900eSJiri Pirko 
141439b7b6a6SArnd Bergmann 	if (fold && handle && fold->handle != handle) {
141539b7b6a6SArnd Bergmann 		err = -EINVAL;
141639b7b6a6SArnd Bergmann 		goto errout_tb;
141739b7b6a6SArnd Bergmann 	}
141877b9900eSJiri Pirko 
141977b9900eSJiri Pirko 	fnew = kzalloc(sizeof(*fnew), GFP_KERNEL);
142039b7b6a6SArnd Bergmann 	if (!fnew) {
142139b7b6a6SArnd Bergmann 		err = -ENOBUFS;
142239b7b6a6SArnd Bergmann 		goto errout_tb;
142339b7b6a6SArnd Bergmann 	}
142406177558SVlad Buslov 	refcount_set(&fnew->refcnt, 1);
142577b9900eSJiri Pirko 
142614215108SCong Wang 	err = tcf_exts_init(&fnew->exts, net, TCA_FLOWER_ACT, 0);
1427b9a24bb7SWANG Cong 	if (err < 0)
1428b9a24bb7SWANG Cong 		goto errout;
142977b9900eSJiri Pirko 
1430ecb3dea4SVlad Buslov 	if (tb[TCA_FLOWER_FLAGS]) {
1431ecb3dea4SVlad Buslov 		fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
1432ecb3dea4SVlad Buslov 
1433ecb3dea4SVlad Buslov 		if (!tc_flags_valid(fnew->flags)) {
1434ecb3dea4SVlad Buslov 			err = -EINVAL;
1435ecb3dea4SVlad Buslov 			goto errout;
1436ecb3dea4SVlad Buslov 		}
1437ecb3dea4SVlad Buslov 	}
1438ecb3dea4SVlad Buslov 
1439ecb3dea4SVlad Buslov 	err = fl_set_parms(net, tp, fnew, mask, base, tb, tca[TCA_RATE], ovr,
1440ecb3dea4SVlad Buslov 			   tp->chain->tmplt_priv, extack);
1441ecb3dea4SVlad Buslov 	if (err)
1442ecb3dea4SVlad Buslov 		goto errout;
1443ecb3dea4SVlad Buslov 
1444ecb3dea4SVlad Buslov 	err = fl_check_assign_mask(head, fnew, fold, mask);
1445ecb3dea4SVlad Buslov 	if (err)
1446ecb3dea4SVlad Buslov 		goto errout;
1447ecb3dea4SVlad Buslov 
144879685219SHadar Hen Zion 	if (!tc_skip_hw(fnew->flags)) {
144905cd271fSPaul Blakey 		err = fl_hw_replace_filter(tp, fnew, extack);
1450e8eb36cdSAmir Vadai 		if (err)
1451620da486SVlad Buslov 			goto errout_mask;
145279685219SHadar Hen Zion 	}
14535b33f488SAmir Vadai 
145455593960SOr Gerlitz 	if (!tc_in_hw(fnew->flags))
145555593960SOr Gerlitz 		fnew->flags |= TCA_CLS_FLAGS_NOT_IN_HW;
145655593960SOr Gerlitz 
145706177558SVlad Buslov 	refcount_inc(&fnew->refcnt);
14585b33f488SAmir Vadai 	if (fold) {
1459*b2552b8cSVlad Buslov 		/* Fold filter was deleted concurrently. Retry lookup. */
1460*b2552b8cSVlad Buslov 		if (fold->deleted) {
1461*b2552b8cSVlad Buslov 			err = -EAGAIN;
1462*b2552b8cSVlad Buslov 			goto errout_hw;
1463*b2552b8cSVlad Buslov 		}
1464*b2552b8cSVlad Buslov 
1465620da486SVlad Buslov 		fnew->handle = handle;
1466620da486SVlad Buslov 
1467620da486SVlad Buslov 		err = rhashtable_insert_fast(&fnew->mask->ht, &fnew->ht_node,
1468620da486SVlad Buslov 					     fnew->mask->filter_ht_params);
1469620da486SVlad Buslov 		if (err)
1470620da486SVlad Buslov 			goto errout_hw;
1471620da486SVlad Buslov 
147205cd271fSPaul Blakey 		rhashtable_remove_fast(&fold->mask->ht,
147305cd271fSPaul Blakey 				       &fold->ht_node,
147405cd271fSPaul Blakey 				       fold->mask->filter_ht_params);
1475234a4624SMatthew Wilcox 		idr_replace(&head->handle_idr, fnew, fnew->handle);
1476ff3532f2SDaniel Borkmann 		list_replace_rcu(&fold->list, &fnew->list);
1477*b2552b8cSVlad Buslov 		fold->deleted = true;
1478620da486SVlad Buslov 
1479620da486SVlad Buslov 		if (!tc_skip_hw(fold->flags))
1480620da486SVlad Buslov 			fl_hw_destroy_filter(tp, fold, NULL);
148177b9900eSJiri Pirko 		tcf_unbind_filter(tp, &fold->res);
14820dadc117SCong Wang 		tcf_exts_get_net(&fold->exts);
148306177558SVlad Buslov 		/* Caller holds reference to fold, so refcnt is always > 0
148406177558SVlad Buslov 		 * after this.
148506177558SVlad Buslov 		 */
148606177558SVlad Buslov 		refcount_dec(&fold->refcnt);
148706177558SVlad Buslov 		__fl_put(fold);
148877b9900eSJiri Pirko 	} else {
1489620da486SVlad Buslov 		if (__fl_lookup(fnew->mask, &fnew->mkey)) {
1490620da486SVlad Buslov 			err = -EEXIST;
1491620da486SVlad Buslov 			goto errout_hw;
1492620da486SVlad Buslov 		}
1493620da486SVlad Buslov 
1494620da486SVlad Buslov 		if (handle) {
1495620da486SVlad Buslov 			/* user specifies a handle and it doesn't exist */
1496620da486SVlad Buslov 			err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
1497620da486SVlad Buslov 					    handle, GFP_ATOMIC);
1498620da486SVlad Buslov 		} else {
1499620da486SVlad Buslov 			handle = 1;
1500620da486SVlad Buslov 			err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
1501620da486SVlad Buslov 					    INT_MAX, GFP_ATOMIC);
1502620da486SVlad Buslov 		}
1503620da486SVlad Buslov 		if (err)
1504620da486SVlad Buslov 			goto errout_hw;
1505620da486SVlad Buslov 
1506620da486SVlad Buslov 		fnew->handle = handle;
1507620da486SVlad Buslov 
1508620da486SVlad Buslov 		err = rhashtable_insert_fast(&fnew->mask->ht, &fnew->ht_node,
1509620da486SVlad Buslov 					     fnew->mask->filter_ht_params);
1510620da486SVlad Buslov 		if (err)
1511620da486SVlad Buslov 			goto errout_idr;
1512620da486SVlad Buslov 
151305cd271fSPaul Blakey 		list_add_tail_rcu(&fnew->list, &fnew->mask->filters);
151477b9900eSJiri Pirko 	}
151577b9900eSJiri Pirko 
1516620da486SVlad Buslov 	*arg = fnew;
1517620da486SVlad Buslov 
151839b7b6a6SArnd Bergmann 	kfree(tb);
15192cddd201SIvan Vecera 	kfree(mask);
152077b9900eSJiri Pirko 	return 0;
152177b9900eSJiri Pirko 
1522fe2502e4SCong Wang errout_idr:
15239c160941SMatthew Wilcox 	idr_remove(&head->handle_idr, fnew->handle);
1524620da486SVlad Buslov errout_hw:
1525620da486SVlad Buslov 	if (!tc_skip_hw(fnew->flags))
1526620da486SVlad Buslov 		fl_hw_destroy_filter(tp, fnew, NULL);
1527ecb3dea4SVlad Buslov errout_mask:
1528ecb3dea4SVlad Buslov 	fl_mask_put(head, fnew->mask, false);
152977b9900eSJiri Pirko errout:
1530b9a24bb7SWANG Cong 	tcf_exts_destroy(&fnew->exts);
153177b9900eSJiri Pirko 	kfree(fnew);
153239b7b6a6SArnd Bergmann errout_tb:
153339b7b6a6SArnd Bergmann 	kfree(tb);
15342cddd201SIvan Vecera errout_mask_alloc:
15352cddd201SIvan Vecera 	kfree(mask);
153606177558SVlad Buslov errout_fold:
153706177558SVlad Buslov 	if (fold)
153806177558SVlad Buslov 		__fl_put(fold);
153977b9900eSJiri Pirko 	return err;
154077b9900eSJiri Pirko }
154177b9900eSJiri Pirko 
1542571acf21SAlexander Aring static int fl_delete(struct tcf_proto *tp, void *arg, bool *last,
154312db03b6SVlad Buslov 		     bool rtnl_held, struct netlink_ext_ack *extack)
154477b9900eSJiri Pirko {
1545e474619aSVlad Buslov 	struct cls_fl_head *head = fl_head_dereference(tp);
15468113c095SWANG Cong 	struct cls_fl_filter *f = arg;
1547*b2552b8cSVlad Buslov 	bool last_on_mask;
1548*b2552b8cSVlad Buslov 	int err = 0;
154977b9900eSJiri Pirko 
1550*b2552b8cSVlad Buslov 	err = __fl_delete(tp, f, &last_on_mask, extack);
155105cd271fSPaul Blakey 	*last = list_empty(&head->masks);
155206177558SVlad Buslov 	__fl_put(f);
155306177558SVlad Buslov 
1554*b2552b8cSVlad Buslov 	return err;
155577b9900eSJiri Pirko }
155677b9900eSJiri Pirko 
155712db03b6SVlad Buslov static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg,
155812db03b6SVlad Buslov 		    bool rtnl_held)
155977b9900eSJiri Pirko {
156077b9900eSJiri Pirko 	struct cls_fl_filter *f;
156177b9900eSJiri Pirko 
156201683a14SVlad Buslov 	arg->count = arg->skip;
156301683a14SVlad Buslov 
156406177558SVlad Buslov 	while ((f = fl_get_next_filter(tp, &arg->cookie)) != NULL) {
15658113c095SWANG Cong 		if (arg->fn(tp, f, arg) < 0) {
156606177558SVlad Buslov 			__fl_put(f);
156777b9900eSJiri Pirko 			arg->stop = 1;
156877b9900eSJiri Pirko 			break;
156977b9900eSJiri Pirko 		}
157006177558SVlad Buslov 		__fl_put(f);
157106177558SVlad Buslov 		arg->cookie++;
157277b9900eSJiri Pirko 		arg->count++;
157377b9900eSJiri Pirko 	}
157477b9900eSJiri Pirko }
157577b9900eSJiri Pirko 
157631533cbaSJohn Hurley static int fl_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb,
157731533cbaSJohn Hurley 			void *cb_priv, struct netlink_ext_ack *extack)
157831533cbaSJohn Hurley {
1579e474619aSVlad Buslov 	struct cls_fl_head *head = fl_head_dereference(tp);
158031533cbaSJohn Hurley 	struct tc_cls_flower_offload cls_flower = {};
158131533cbaSJohn Hurley 	struct tcf_block *block = tp->chain->block;
158231533cbaSJohn Hurley 	struct fl_flow_mask *mask;
158331533cbaSJohn Hurley 	struct cls_fl_filter *f;
158431533cbaSJohn Hurley 	int err;
158531533cbaSJohn Hurley 
158631533cbaSJohn Hurley 	list_for_each_entry(mask, &head->masks, list) {
158731533cbaSJohn Hurley 		list_for_each_entry(f, &mask->filters, list) {
158831533cbaSJohn Hurley 			if (tc_skip_hw(f->flags))
158931533cbaSJohn Hurley 				continue;
159031533cbaSJohn Hurley 
1591e3ab786bSPablo Neira Ayuso 			cls_flower.rule =
1592e3ab786bSPablo Neira Ayuso 				flow_rule_alloc(tcf_exts_num_actions(&f->exts));
15938f256622SPablo Neira Ayuso 			if (!cls_flower.rule)
15948f256622SPablo Neira Ayuso 				return -ENOMEM;
15958f256622SPablo Neira Ayuso 
159631533cbaSJohn Hurley 			tc_cls_common_offload_init(&cls_flower.common, tp,
159731533cbaSJohn Hurley 						   f->flags, extack);
159831533cbaSJohn Hurley 			cls_flower.command = add ?
159931533cbaSJohn Hurley 				TC_CLSFLOWER_REPLACE : TC_CLSFLOWER_DESTROY;
160031533cbaSJohn Hurley 			cls_flower.cookie = (unsigned long)f;
16018f256622SPablo Neira Ayuso 			cls_flower.rule->match.dissector = &mask->dissector;
16028f256622SPablo Neira Ayuso 			cls_flower.rule->match.mask = &mask->key;
16038f256622SPablo Neira Ayuso 			cls_flower.rule->match.key = &f->mkey;
16043a7b6861SPablo Neira Ayuso 
16053a7b6861SPablo Neira Ayuso 			err = tc_setup_flow_action(&cls_flower.rule->action,
16063a7b6861SPablo Neira Ayuso 						   &f->exts);
16073a7b6861SPablo Neira Ayuso 			if (err) {
16083a7b6861SPablo Neira Ayuso 				kfree(cls_flower.rule);
16091f15bb4fSVlad Buslov 				if (tc_skip_sw(f->flags)) {
16101f15bb4fSVlad Buslov 					NL_SET_ERR_MSG_MOD(extack, "Failed to setup flow action");
16113a7b6861SPablo Neira Ayuso 					return err;
16123a7b6861SPablo Neira Ayuso 				}
16131f15bb4fSVlad Buslov 				continue;
16141f15bb4fSVlad Buslov 			}
16153a7b6861SPablo Neira Ayuso 
161631533cbaSJohn Hurley 			cls_flower.classid = f->res.classid;
161731533cbaSJohn Hurley 
161831533cbaSJohn Hurley 			err = cb(TC_SETUP_CLSFLOWER, &cls_flower, cb_priv);
16198f256622SPablo Neira Ayuso 			kfree(cls_flower.rule);
16208f256622SPablo Neira Ayuso 
162131533cbaSJohn Hurley 			if (err) {
162231533cbaSJohn Hurley 				if (add && tc_skip_sw(f->flags))
162331533cbaSJohn Hurley 					return err;
162431533cbaSJohn Hurley 				continue;
162531533cbaSJohn Hurley 			}
162631533cbaSJohn Hurley 
162731533cbaSJohn Hurley 			tc_cls_offload_cnt_update(block, &f->in_hw_count,
162831533cbaSJohn Hurley 						  &f->flags, add);
162931533cbaSJohn Hurley 		}
163031533cbaSJohn Hurley 	}
163131533cbaSJohn Hurley 
163231533cbaSJohn Hurley 	return 0;
163331533cbaSJohn Hurley }
163431533cbaSJohn Hurley 
16358f256622SPablo Neira Ayuso static int fl_hw_create_tmplt(struct tcf_chain *chain,
163634738452SJiri Pirko 			      struct fl_flow_tmplt *tmplt)
163734738452SJiri Pirko {
163834738452SJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
163934738452SJiri Pirko 	struct tcf_block *block = chain->block;
164034738452SJiri Pirko 
1641e3ab786bSPablo Neira Ayuso 	cls_flower.rule = flow_rule_alloc(0);
16428f256622SPablo Neira Ayuso 	if (!cls_flower.rule)
16438f256622SPablo Neira Ayuso 		return -ENOMEM;
16448f256622SPablo Neira Ayuso 
164534738452SJiri Pirko 	cls_flower.common.chain_index = chain->index;
164634738452SJiri Pirko 	cls_flower.command = TC_CLSFLOWER_TMPLT_CREATE;
164734738452SJiri Pirko 	cls_flower.cookie = (unsigned long) tmplt;
16488f256622SPablo Neira Ayuso 	cls_flower.rule->match.dissector = &tmplt->dissector;
16498f256622SPablo Neira Ayuso 	cls_flower.rule->match.mask = &tmplt->mask;
16508f256622SPablo Neira Ayuso 	cls_flower.rule->match.key = &tmplt->dummy_key;
165134738452SJiri Pirko 
165234738452SJiri Pirko 	/* We don't care if driver (any of them) fails to handle this
165334738452SJiri Pirko 	 * call. It serves just as a hint for it.
165434738452SJiri Pirko 	 */
1655aeb3fecdSCong Wang 	tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, false);
16568f256622SPablo Neira Ayuso 	kfree(cls_flower.rule);
16578f256622SPablo Neira Ayuso 
16588f256622SPablo Neira Ayuso 	return 0;
165934738452SJiri Pirko }
166034738452SJiri Pirko 
166134738452SJiri Pirko static void fl_hw_destroy_tmplt(struct tcf_chain *chain,
166234738452SJiri Pirko 				struct fl_flow_tmplt *tmplt)
166334738452SJiri Pirko {
166434738452SJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
166534738452SJiri Pirko 	struct tcf_block *block = chain->block;
166634738452SJiri Pirko 
166734738452SJiri Pirko 	cls_flower.common.chain_index = chain->index;
166834738452SJiri Pirko 	cls_flower.command = TC_CLSFLOWER_TMPLT_DESTROY;
166934738452SJiri Pirko 	cls_flower.cookie = (unsigned long) tmplt;
167034738452SJiri Pirko 
1671aeb3fecdSCong Wang 	tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, false);
167234738452SJiri Pirko }
167334738452SJiri Pirko 
1674b95ec7ebSJiri Pirko static void *fl_tmplt_create(struct net *net, struct tcf_chain *chain,
1675b95ec7ebSJiri Pirko 			     struct nlattr **tca,
1676b95ec7ebSJiri Pirko 			     struct netlink_ext_ack *extack)
1677b95ec7ebSJiri Pirko {
1678b95ec7ebSJiri Pirko 	struct fl_flow_tmplt *tmplt;
1679b95ec7ebSJiri Pirko 	struct nlattr **tb;
1680b95ec7ebSJiri Pirko 	int err;
1681b95ec7ebSJiri Pirko 
1682b95ec7ebSJiri Pirko 	if (!tca[TCA_OPTIONS])
1683b95ec7ebSJiri Pirko 		return ERR_PTR(-EINVAL);
1684b95ec7ebSJiri Pirko 
1685b95ec7ebSJiri Pirko 	tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL);
1686b95ec7ebSJiri Pirko 	if (!tb)
1687b95ec7ebSJiri Pirko 		return ERR_PTR(-ENOBUFS);
1688b95ec7ebSJiri Pirko 	err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS],
1689b95ec7ebSJiri Pirko 			       fl_policy, NULL);
1690b95ec7ebSJiri Pirko 	if (err)
1691b95ec7ebSJiri Pirko 		goto errout_tb;
1692b95ec7ebSJiri Pirko 
1693b95ec7ebSJiri Pirko 	tmplt = kzalloc(sizeof(*tmplt), GFP_KERNEL);
16941cbc36a5SDan Carpenter 	if (!tmplt) {
16951cbc36a5SDan Carpenter 		err = -ENOMEM;
1696b95ec7ebSJiri Pirko 		goto errout_tb;
16971cbc36a5SDan Carpenter 	}
1698b95ec7ebSJiri Pirko 	tmplt->chain = chain;
1699b95ec7ebSJiri Pirko 	err = fl_set_key(net, tb, &tmplt->dummy_key, &tmplt->mask, extack);
1700b95ec7ebSJiri Pirko 	if (err)
1701b95ec7ebSJiri Pirko 		goto errout_tmplt;
1702b95ec7ebSJiri Pirko 
1703b95ec7ebSJiri Pirko 	fl_init_dissector(&tmplt->dissector, &tmplt->mask);
1704b95ec7ebSJiri Pirko 
17058f256622SPablo Neira Ayuso 	err = fl_hw_create_tmplt(chain, tmplt);
17068f256622SPablo Neira Ayuso 	if (err)
17078f256622SPablo Neira Ayuso 		goto errout_tmplt;
170834738452SJiri Pirko 
17098f256622SPablo Neira Ayuso 	kfree(tb);
1710b95ec7ebSJiri Pirko 	return tmplt;
1711b95ec7ebSJiri Pirko 
1712b95ec7ebSJiri Pirko errout_tmplt:
1713b95ec7ebSJiri Pirko 	kfree(tmplt);
1714b95ec7ebSJiri Pirko errout_tb:
1715b95ec7ebSJiri Pirko 	kfree(tb);
1716b95ec7ebSJiri Pirko 	return ERR_PTR(err);
1717b95ec7ebSJiri Pirko }
1718b95ec7ebSJiri Pirko 
1719b95ec7ebSJiri Pirko static void fl_tmplt_destroy(void *tmplt_priv)
1720b95ec7ebSJiri Pirko {
1721b95ec7ebSJiri Pirko 	struct fl_flow_tmplt *tmplt = tmplt_priv;
1722b95ec7ebSJiri Pirko 
172395278ddaSCong Wang 	fl_hw_destroy_tmplt(tmplt->chain, tmplt);
172495278ddaSCong Wang 	kfree(tmplt);
1725b95ec7ebSJiri Pirko }
1726b95ec7ebSJiri Pirko 
172777b9900eSJiri Pirko static int fl_dump_key_val(struct sk_buff *skb,
172877b9900eSJiri Pirko 			   void *val, int val_type,
172977b9900eSJiri Pirko 			   void *mask, int mask_type, int len)
173077b9900eSJiri Pirko {
173177b9900eSJiri Pirko 	int err;
173277b9900eSJiri Pirko 
173377b9900eSJiri Pirko 	if (!memchr_inv(mask, 0, len))
173477b9900eSJiri Pirko 		return 0;
173577b9900eSJiri Pirko 	err = nla_put(skb, val_type, len, val);
173677b9900eSJiri Pirko 	if (err)
173777b9900eSJiri Pirko 		return err;
173877b9900eSJiri Pirko 	if (mask_type != TCA_FLOWER_UNSPEC) {
173977b9900eSJiri Pirko 		err = nla_put(skb, mask_type, len, mask);
174077b9900eSJiri Pirko 		if (err)
174177b9900eSJiri Pirko 			return err;
174277b9900eSJiri Pirko 	}
174377b9900eSJiri Pirko 	return 0;
174477b9900eSJiri Pirko }
174577b9900eSJiri Pirko 
17465c72299fSAmritha Nambiar static int fl_dump_key_port_range(struct sk_buff *skb, struct fl_flow_key *key,
17475c72299fSAmritha Nambiar 				  struct fl_flow_key *mask)
17485c72299fSAmritha Nambiar {
17495c72299fSAmritha Nambiar 	if (fl_dump_key_val(skb, &key->tp_min.dst, TCA_FLOWER_KEY_PORT_DST_MIN,
17505c72299fSAmritha Nambiar 			    &mask->tp_min.dst, TCA_FLOWER_UNSPEC,
17515c72299fSAmritha Nambiar 			    sizeof(key->tp_min.dst)) ||
17525c72299fSAmritha Nambiar 	    fl_dump_key_val(skb, &key->tp_max.dst, TCA_FLOWER_KEY_PORT_DST_MAX,
17535c72299fSAmritha Nambiar 			    &mask->tp_max.dst, TCA_FLOWER_UNSPEC,
17545c72299fSAmritha Nambiar 			    sizeof(key->tp_max.dst)) ||
17555c72299fSAmritha Nambiar 	    fl_dump_key_val(skb, &key->tp_min.src, TCA_FLOWER_KEY_PORT_SRC_MIN,
17565c72299fSAmritha Nambiar 			    &mask->tp_min.src, TCA_FLOWER_UNSPEC,
17575c72299fSAmritha Nambiar 			    sizeof(key->tp_min.src)) ||
17585c72299fSAmritha Nambiar 	    fl_dump_key_val(skb, &key->tp_max.src, TCA_FLOWER_KEY_PORT_SRC_MAX,
17595c72299fSAmritha Nambiar 			    &mask->tp_max.src, TCA_FLOWER_UNSPEC,
17605c72299fSAmritha Nambiar 			    sizeof(key->tp_max.src)))
17615c72299fSAmritha Nambiar 		return -1;
17625c72299fSAmritha Nambiar 
17635c72299fSAmritha Nambiar 	return 0;
17645c72299fSAmritha Nambiar }
17655c72299fSAmritha Nambiar 
1766a577d8f7SBenjamin LaHaise static int fl_dump_key_mpls(struct sk_buff *skb,
1767a577d8f7SBenjamin LaHaise 			    struct flow_dissector_key_mpls *mpls_key,
1768a577d8f7SBenjamin LaHaise 			    struct flow_dissector_key_mpls *mpls_mask)
1769a577d8f7SBenjamin LaHaise {
1770a577d8f7SBenjamin LaHaise 	int err;
1771a577d8f7SBenjamin LaHaise 
1772a577d8f7SBenjamin LaHaise 	if (!memchr_inv(mpls_mask, 0, sizeof(*mpls_mask)))
1773a577d8f7SBenjamin LaHaise 		return 0;
1774a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_ttl) {
1775a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TTL,
1776a577d8f7SBenjamin LaHaise 				 mpls_key->mpls_ttl);
1777a577d8f7SBenjamin LaHaise 		if (err)
1778a577d8f7SBenjamin LaHaise 			return err;
1779a577d8f7SBenjamin LaHaise 	}
1780a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_tc) {
1781a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TC,
1782a577d8f7SBenjamin LaHaise 				 mpls_key->mpls_tc);
1783a577d8f7SBenjamin LaHaise 		if (err)
1784a577d8f7SBenjamin LaHaise 			return err;
1785a577d8f7SBenjamin LaHaise 	}
1786a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_label) {
1787a577d8f7SBenjamin LaHaise 		err = nla_put_u32(skb, TCA_FLOWER_KEY_MPLS_LABEL,
1788a577d8f7SBenjamin LaHaise 				  mpls_key->mpls_label);
1789a577d8f7SBenjamin LaHaise 		if (err)
1790a577d8f7SBenjamin LaHaise 			return err;
1791a577d8f7SBenjamin LaHaise 	}
1792a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_bos) {
1793a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_BOS,
1794a577d8f7SBenjamin LaHaise 				 mpls_key->mpls_bos);
1795a577d8f7SBenjamin LaHaise 		if (err)
1796a577d8f7SBenjamin LaHaise 			return err;
1797a577d8f7SBenjamin LaHaise 	}
1798a577d8f7SBenjamin LaHaise 	return 0;
1799a577d8f7SBenjamin LaHaise }
1800a577d8f7SBenjamin LaHaise 
18010e2c17b6SOr Gerlitz static int fl_dump_key_ip(struct sk_buff *skb, bool encap,
18024d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *key,
18034d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *mask)
18044d80cc0aSOr Gerlitz {
18050e2c17b6SOr Gerlitz 	int tos_key = encap ? TCA_FLOWER_KEY_ENC_IP_TOS : TCA_FLOWER_KEY_IP_TOS;
18060e2c17b6SOr Gerlitz 	int ttl_key = encap ? TCA_FLOWER_KEY_ENC_IP_TTL : TCA_FLOWER_KEY_IP_TTL;
18070e2c17b6SOr Gerlitz 	int tos_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TOS_MASK : TCA_FLOWER_KEY_IP_TOS_MASK;
18080e2c17b6SOr Gerlitz 	int ttl_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TTL_MASK : TCA_FLOWER_KEY_IP_TTL_MASK;
18090e2c17b6SOr Gerlitz 
18100e2c17b6SOr Gerlitz 	if (fl_dump_key_val(skb, &key->tos, tos_key, &mask->tos, tos_mask, sizeof(key->tos)) ||
18110e2c17b6SOr Gerlitz 	    fl_dump_key_val(skb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl)))
18124d80cc0aSOr Gerlitz 		return -1;
18134d80cc0aSOr Gerlitz 
18144d80cc0aSOr Gerlitz 	return 0;
18154d80cc0aSOr Gerlitz }
18164d80cc0aSOr Gerlitz 
18179399ae9aSHadar Hen Zion static int fl_dump_key_vlan(struct sk_buff *skb,
1818d64efd09SJianbo Liu 			    int vlan_id_key, int vlan_prio_key,
18199399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *vlan_key,
18209399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *vlan_mask)
18219399ae9aSHadar Hen Zion {
18229399ae9aSHadar Hen Zion 	int err;
18239399ae9aSHadar Hen Zion 
18249399ae9aSHadar Hen Zion 	if (!memchr_inv(vlan_mask, 0, sizeof(*vlan_mask)))
18259399ae9aSHadar Hen Zion 		return 0;
18269399ae9aSHadar Hen Zion 	if (vlan_mask->vlan_id) {
1827d64efd09SJianbo Liu 		err = nla_put_u16(skb, vlan_id_key,
18289399ae9aSHadar Hen Zion 				  vlan_key->vlan_id);
18299399ae9aSHadar Hen Zion 		if (err)
18309399ae9aSHadar Hen Zion 			return err;
18319399ae9aSHadar Hen Zion 	}
18329399ae9aSHadar Hen Zion 	if (vlan_mask->vlan_priority) {
1833d64efd09SJianbo Liu 		err = nla_put_u8(skb, vlan_prio_key,
18349399ae9aSHadar Hen Zion 				 vlan_key->vlan_priority);
18359399ae9aSHadar Hen Zion 		if (err)
18369399ae9aSHadar Hen Zion 			return err;
18379399ae9aSHadar Hen Zion 	}
18389399ae9aSHadar Hen Zion 	return 0;
18399399ae9aSHadar Hen Zion }
18409399ae9aSHadar Hen Zion 
1841faa3ffceSOr Gerlitz static void fl_get_key_flag(u32 dissector_key, u32 dissector_mask,
1842faa3ffceSOr Gerlitz 			    u32 *flower_key, u32 *flower_mask,
1843faa3ffceSOr Gerlitz 			    u32 flower_flag_bit, u32 dissector_flag_bit)
1844faa3ffceSOr Gerlitz {
1845faa3ffceSOr Gerlitz 	if (dissector_mask & dissector_flag_bit) {
1846faa3ffceSOr Gerlitz 		*flower_mask |= flower_flag_bit;
1847faa3ffceSOr Gerlitz 		if (dissector_key & dissector_flag_bit)
1848faa3ffceSOr Gerlitz 			*flower_key |= flower_flag_bit;
1849faa3ffceSOr Gerlitz 	}
1850faa3ffceSOr Gerlitz }
1851faa3ffceSOr Gerlitz 
1852faa3ffceSOr Gerlitz static int fl_dump_key_flags(struct sk_buff *skb, u32 flags_key, u32 flags_mask)
1853faa3ffceSOr Gerlitz {
1854faa3ffceSOr Gerlitz 	u32 key, mask;
1855faa3ffceSOr Gerlitz 	__be32 _key, _mask;
1856faa3ffceSOr Gerlitz 	int err;
1857faa3ffceSOr Gerlitz 
1858faa3ffceSOr Gerlitz 	if (!memchr_inv(&flags_mask, 0, sizeof(flags_mask)))
1859faa3ffceSOr Gerlitz 		return 0;
1860faa3ffceSOr Gerlitz 
1861faa3ffceSOr Gerlitz 	key = 0;
1862faa3ffceSOr Gerlitz 	mask = 0;
1863faa3ffceSOr Gerlitz 
1864faa3ffceSOr Gerlitz 	fl_get_key_flag(flags_key, flags_mask, &key, &mask,
1865faa3ffceSOr Gerlitz 			TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT);
1866459d153dSPieter Jansen van Vuuren 	fl_get_key_flag(flags_key, flags_mask, &key, &mask,
1867459d153dSPieter Jansen van Vuuren 			TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST,
1868459d153dSPieter Jansen van Vuuren 			FLOW_DIS_FIRST_FRAG);
1869faa3ffceSOr Gerlitz 
1870faa3ffceSOr Gerlitz 	_key = cpu_to_be32(key);
1871faa3ffceSOr Gerlitz 	_mask = cpu_to_be32(mask);
1872faa3ffceSOr Gerlitz 
1873faa3ffceSOr Gerlitz 	err = nla_put(skb, TCA_FLOWER_KEY_FLAGS, 4, &_key);
1874faa3ffceSOr Gerlitz 	if (err)
1875faa3ffceSOr Gerlitz 		return err;
1876faa3ffceSOr Gerlitz 
1877faa3ffceSOr Gerlitz 	return nla_put(skb, TCA_FLOWER_KEY_FLAGS_MASK, 4, &_mask);
1878faa3ffceSOr Gerlitz }
1879faa3ffceSOr Gerlitz 
18800a6e7778SPieter Jansen van Vuuren static int fl_dump_key_geneve_opt(struct sk_buff *skb,
18810a6e7778SPieter Jansen van Vuuren 				  struct flow_dissector_key_enc_opts *enc_opts)
18820a6e7778SPieter Jansen van Vuuren {
18830a6e7778SPieter Jansen van Vuuren 	struct geneve_opt *opt;
18840a6e7778SPieter Jansen van Vuuren 	struct nlattr *nest;
18850a6e7778SPieter Jansen van Vuuren 	int opt_off = 0;
18860a6e7778SPieter Jansen van Vuuren 
18870a6e7778SPieter Jansen van Vuuren 	nest = nla_nest_start(skb, TCA_FLOWER_KEY_ENC_OPTS_GENEVE);
18880a6e7778SPieter Jansen van Vuuren 	if (!nest)
18890a6e7778SPieter Jansen van Vuuren 		goto nla_put_failure;
18900a6e7778SPieter Jansen van Vuuren 
18910a6e7778SPieter Jansen van Vuuren 	while (enc_opts->len > opt_off) {
18920a6e7778SPieter Jansen van Vuuren 		opt = (struct geneve_opt *)&enc_opts->data[opt_off];
18930a6e7778SPieter Jansen van Vuuren 
18940a6e7778SPieter Jansen van Vuuren 		if (nla_put_be16(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS,
18950a6e7778SPieter Jansen van Vuuren 				 opt->opt_class))
18960a6e7778SPieter Jansen van Vuuren 			goto nla_put_failure;
18970a6e7778SPieter Jansen van Vuuren 		if (nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE,
18980a6e7778SPieter Jansen van Vuuren 			       opt->type))
18990a6e7778SPieter Jansen van Vuuren 			goto nla_put_failure;
19000a6e7778SPieter Jansen van Vuuren 		if (nla_put(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA,
19010a6e7778SPieter Jansen van Vuuren 			    opt->length * 4, opt->opt_data))
19020a6e7778SPieter Jansen van Vuuren 			goto nla_put_failure;
19030a6e7778SPieter Jansen van Vuuren 
19040a6e7778SPieter Jansen van Vuuren 		opt_off += sizeof(struct geneve_opt) + opt->length * 4;
19050a6e7778SPieter Jansen van Vuuren 	}
19060a6e7778SPieter Jansen van Vuuren 	nla_nest_end(skb, nest);
19070a6e7778SPieter Jansen van Vuuren 	return 0;
19080a6e7778SPieter Jansen van Vuuren 
19090a6e7778SPieter Jansen van Vuuren nla_put_failure:
19100a6e7778SPieter Jansen van Vuuren 	nla_nest_cancel(skb, nest);
19110a6e7778SPieter Jansen van Vuuren 	return -EMSGSIZE;
19120a6e7778SPieter Jansen van Vuuren }
19130a6e7778SPieter Jansen van Vuuren 
19140a6e7778SPieter Jansen van Vuuren static int fl_dump_key_options(struct sk_buff *skb, int enc_opt_type,
19150a6e7778SPieter Jansen van Vuuren 			       struct flow_dissector_key_enc_opts *enc_opts)
19160a6e7778SPieter Jansen van Vuuren {
19170a6e7778SPieter Jansen van Vuuren 	struct nlattr *nest;
19180a6e7778SPieter Jansen van Vuuren 	int err;
19190a6e7778SPieter Jansen van Vuuren 
19200a6e7778SPieter Jansen van Vuuren 	if (!enc_opts->len)
19210a6e7778SPieter Jansen van Vuuren 		return 0;
19220a6e7778SPieter Jansen van Vuuren 
19230a6e7778SPieter Jansen van Vuuren 	nest = nla_nest_start(skb, enc_opt_type);
19240a6e7778SPieter Jansen van Vuuren 	if (!nest)
19250a6e7778SPieter Jansen van Vuuren 		goto nla_put_failure;
19260a6e7778SPieter Jansen van Vuuren 
19270a6e7778SPieter Jansen van Vuuren 	switch (enc_opts->dst_opt_type) {
19280a6e7778SPieter Jansen van Vuuren 	case TUNNEL_GENEVE_OPT:
19290a6e7778SPieter Jansen van Vuuren 		err = fl_dump_key_geneve_opt(skb, enc_opts);
19300a6e7778SPieter Jansen van Vuuren 		if (err)
19310a6e7778SPieter Jansen van Vuuren 			goto nla_put_failure;
19320a6e7778SPieter Jansen van Vuuren 		break;
19330a6e7778SPieter Jansen van Vuuren 	default:
19340a6e7778SPieter Jansen van Vuuren 		goto nla_put_failure;
19350a6e7778SPieter Jansen van Vuuren 	}
19360a6e7778SPieter Jansen van Vuuren 	nla_nest_end(skb, nest);
19370a6e7778SPieter Jansen van Vuuren 	return 0;
19380a6e7778SPieter Jansen van Vuuren 
19390a6e7778SPieter Jansen van Vuuren nla_put_failure:
19400a6e7778SPieter Jansen van Vuuren 	nla_nest_cancel(skb, nest);
19410a6e7778SPieter Jansen van Vuuren 	return -EMSGSIZE;
19420a6e7778SPieter Jansen van Vuuren }
19430a6e7778SPieter Jansen van Vuuren 
19440a6e7778SPieter Jansen van Vuuren static int fl_dump_key_enc_opt(struct sk_buff *skb,
19450a6e7778SPieter Jansen van Vuuren 			       struct flow_dissector_key_enc_opts *key_opts,
19460a6e7778SPieter Jansen van Vuuren 			       struct flow_dissector_key_enc_opts *msk_opts)
19470a6e7778SPieter Jansen van Vuuren {
19480a6e7778SPieter Jansen van Vuuren 	int err;
19490a6e7778SPieter Jansen van Vuuren 
19500a6e7778SPieter Jansen van Vuuren 	err = fl_dump_key_options(skb, TCA_FLOWER_KEY_ENC_OPTS, key_opts);
19510a6e7778SPieter Jansen van Vuuren 	if (err)
19520a6e7778SPieter Jansen van Vuuren 		return err;
19530a6e7778SPieter Jansen van Vuuren 
19540a6e7778SPieter Jansen van Vuuren 	return fl_dump_key_options(skb, TCA_FLOWER_KEY_ENC_OPTS_MASK, msk_opts);
19550a6e7778SPieter Jansen van Vuuren }
19560a6e7778SPieter Jansen van Vuuren 
1957f5749081SJiri Pirko static int fl_dump_key(struct sk_buff *skb, struct net *net,
1958f5749081SJiri Pirko 		       struct fl_flow_key *key, struct fl_flow_key *mask)
195977b9900eSJiri Pirko {
196077b9900eSJiri Pirko 	if (mask->indev_ifindex) {
196177b9900eSJiri Pirko 		struct net_device *dev;
196277b9900eSJiri Pirko 
196377b9900eSJiri Pirko 		dev = __dev_get_by_index(net, key->indev_ifindex);
196477b9900eSJiri Pirko 		if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name))
196577b9900eSJiri Pirko 			goto nla_put_failure;
196677b9900eSJiri Pirko 	}
196777b9900eSJiri Pirko 
196877b9900eSJiri Pirko 	if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
196977b9900eSJiri Pirko 			    mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
197077b9900eSJiri Pirko 			    sizeof(key->eth.dst)) ||
197177b9900eSJiri Pirko 	    fl_dump_key_val(skb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
197277b9900eSJiri Pirko 			    mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
197377b9900eSJiri Pirko 			    sizeof(key->eth.src)) ||
197477b9900eSJiri Pirko 	    fl_dump_key_val(skb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE,
197577b9900eSJiri Pirko 			    &mask->basic.n_proto, TCA_FLOWER_UNSPEC,
197677b9900eSJiri Pirko 			    sizeof(key->basic.n_proto)))
197777b9900eSJiri Pirko 		goto nla_put_failure;
19789399ae9aSHadar Hen Zion 
1979a577d8f7SBenjamin LaHaise 	if (fl_dump_key_mpls(skb, &key->mpls, &mask->mpls))
1980a577d8f7SBenjamin LaHaise 		goto nla_put_failure;
1981a577d8f7SBenjamin LaHaise 
1982d64efd09SJianbo Liu 	if (fl_dump_key_vlan(skb, TCA_FLOWER_KEY_VLAN_ID,
1983d64efd09SJianbo Liu 			     TCA_FLOWER_KEY_VLAN_PRIO, &key->vlan, &mask->vlan))
19849399ae9aSHadar Hen Zion 		goto nla_put_failure;
19859399ae9aSHadar Hen Zion 
1986d64efd09SJianbo Liu 	if (fl_dump_key_vlan(skb, TCA_FLOWER_KEY_CVLAN_ID,
1987d64efd09SJianbo Liu 			     TCA_FLOWER_KEY_CVLAN_PRIO,
1988d64efd09SJianbo Liu 			     &key->cvlan, &mask->cvlan) ||
1989d64efd09SJianbo Liu 	    (mask->cvlan.vlan_tpid &&
1990158abbf1SJianbo Liu 	     nla_put_be16(skb, TCA_FLOWER_KEY_VLAN_ETH_TYPE,
1991d64efd09SJianbo Liu 			  key->cvlan.vlan_tpid)))
1992d3069512SJianbo Liu 		goto nla_put_failure;
1993d3069512SJianbo Liu 
19945e9a0fe4SJianbo Liu 	if (mask->basic.n_proto) {
1995d64efd09SJianbo Liu 		if (mask->cvlan.vlan_tpid) {
1996d64efd09SJianbo Liu 			if (nla_put_be16(skb, TCA_FLOWER_KEY_CVLAN_ETH_TYPE,
1997d64efd09SJianbo Liu 					 key->basic.n_proto))
1998d64efd09SJianbo Liu 				goto nla_put_failure;
1999d64efd09SJianbo Liu 		} else if (mask->vlan.vlan_tpid) {
2000d64efd09SJianbo Liu 			if (nla_put_be16(skb, TCA_FLOWER_KEY_VLAN_ETH_TYPE,
2001d64efd09SJianbo Liu 					 key->basic.n_proto))
2002d64efd09SJianbo Liu 				goto nla_put_failure;
2003d64efd09SJianbo Liu 		}
20045e9a0fe4SJianbo Liu 	}
2005d64efd09SJianbo Liu 
200677b9900eSJiri Pirko 	if ((key->basic.n_proto == htons(ETH_P_IP) ||
200777b9900eSJiri Pirko 	     key->basic.n_proto == htons(ETH_P_IPV6)) &&
20084d80cc0aSOr Gerlitz 	    (fl_dump_key_val(skb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
200977b9900eSJiri Pirko 			    &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
20104d80cc0aSOr Gerlitz 			    sizeof(key->basic.ip_proto)) ||
20110e2c17b6SOr Gerlitz 	    fl_dump_key_ip(skb, false, &key->ip, &mask->ip)))
201277b9900eSJiri Pirko 		goto nla_put_failure;
201377b9900eSJiri Pirko 
2014c3f83241STom Herbert 	if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
201577b9900eSJiri Pirko 	    (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
201677b9900eSJiri Pirko 			     &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
201777b9900eSJiri Pirko 			     sizeof(key->ipv4.src)) ||
201877b9900eSJiri Pirko 	     fl_dump_key_val(skb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
201977b9900eSJiri Pirko 			     &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
202077b9900eSJiri Pirko 			     sizeof(key->ipv4.dst))))
202177b9900eSJiri Pirko 		goto nla_put_failure;
2022c3f83241STom Herbert 	else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
202377b9900eSJiri Pirko 		 (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
202477b9900eSJiri Pirko 				  &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
202577b9900eSJiri Pirko 				  sizeof(key->ipv6.src)) ||
202677b9900eSJiri Pirko 		  fl_dump_key_val(skb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
202777b9900eSJiri Pirko 				  &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
202877b9900eSJiri Pirko 				  sizeof(key->ipv6.dst))))
202977b9900eSJiri Pirko 		goto nla_put_failure;
203077b9900eSJiri Pirko 
203177b9900eSJiri Pirko 	if (key->basic.ip_proto == IPPROTO_TCP &&
203277b9900eSJiri Pirko 	    (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
2033aa72d708SOr Gerlitz 			     &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
203477b9900eSJiri Pirko 			     sizeof(key->tp.src)) ||
203577b9900eSJiri Pirko 	     fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
2036aa72d708SOr Gerlitz 			     &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
2037fdfc7dd6SJiri Pirko 			     sizeof(key->tp.dst)) ||
2038fdfc7dd6SJiri Pirko 	     fl_dump_key_val(skb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS,
2039fdfc7dd6SJiri Pirko 			     &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK,
2040fdfc7dd6SJiri Pirko 			     sizeof(key->tcp.flags))))
204177b9900eSJiri Pirko 		goto nla_put_failure;
204277b9900eSJiri Pirko 	else if (key->basic.ip_proto == IPPROTO_UDP &&
204377b9900eSJiri Pirko 		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
2044aa72d708SOr Gerlitz 				  &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
204577b9900eSJiri Pirko 				  sizeof(key->tp.src)) ||
204677b9900eSJiri Pirko 		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
2047aa72d708SOr Gerlitz 				  &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
204877b9900eSJiri Pirko 				  sizeof(key->tp.dst))))
204977b9900eSJiri Pirko 		goto nla_put_failure;
20505976c5f4SSimon Horman 	else if (key->basic.ip_proto == IPPROTO_SCTP &&
20515976c5f4SSimon Horman 		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
20525976c5f4SSimon Horman 				  &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
20535976c5f4SSimon Horman 				  sizeof(key->tp.src)) ||
20545976c5f4SSimon Horman 		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
20555976c5f4SSimon Horman 				  &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
20565976c5f4SSimon Horman 				  sizeof(key->tp.dst))))
20575976c5f4SSimon Horman 		goto nla_put_failure;
20587b684884SSimon Horman 	else if (key->basic.n_proto == htons(ETH_P_IP) &&
20597b684884SSimon Horman 		 key->basic.ip_proto == IPPROTO_ICMP &&
20607b684884SSimon Horman 		 (fl_dump_key_val(skb, &key->icmp.type,
20617b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_TYPE, &mask->icmp.type,
20627b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,
20637b684884SSimon Horman 				  sizeof(key->icmp.type)) ||
20647b684884SSimon Horman 		  fl_dump_key_val(skb, &key->icmp.code,
20657b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_CODE, &mask->icmp.code,
20667b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
20677b684884SSimon Horman 				  sizeof(key->icmp.code))))
20687b684884SSimon Horman 		goto nla_put_failure;
20697b684884SSimon Horman 	else if (key->basic.n_proto == htons(ETH_P_IPV6) &&
20707b684884SSimon Horman 		 key->basic.ip_proto == IPPROTO_ICMPV6 &&
20717b684884SSimon Horman 		 (fl_dump_key_val(skb, &key->icmp.type,
20727b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_TYPE, &mask->icmp.type,
20737b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
20747b684884SSimon Horman 				  sizeof(key->icmp.type)) ||
20757b684884SSimon Horman 		  fl_dump_key_val(skb, &key->icmp.code,
20767b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_CODE, &mask->icmp.code,
20777b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_CODE_MASK,
20787b684884SSimon Horman 				  sizeof(key->icmp.code))))
20797b684884SSimon Horman 		goto nla_put_failure;
208099d31326SSimon Horman 	else if ((key->basic.n_proto == htons(ETH_P_ARP) ||
208199d31326SSimon Horman 		  key->basic.n_proto == htons(ETH_P_RARP)) &&
208299d31326SSimon Horman 		 (fl_dump_key_val(skb, &key->arp.sip,
208399d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_SIP, &mask->arp.sip,
208499d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_SIP_MASK,
208599d31326SSimon Horman 				  sizeof(key->arp.sip)) ||
208699d31326SSimon Horman 		  fl_dump_key_val(skb, &key->arp.tip,
208799d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_TIP, &mask->arp.tip,
208899d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_TIP_MASK,
208999d31326SSimon Horman 				  sizeof(key->arp.tip)) ||
209099d31326SSimon Horman 		  fl_dump_key_val(skb, &key->arp.op,
209199d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_OP, &mask->arp.op,
209299d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_OP_MASK,
209399d31326SSimon Horman 				  sizeof(key->arp.op)) ||
209499d31326SSimon Horman 		  fl_dump_key_val(skb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA,
209599d31326SSimon Horman 				  mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK,
209699d31326SSimon Horman 				  sizeof(key->arp.sha)) ||
209799d31326SSimon Horman 		  fl_dump_key_val(skb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA,
209899d31326SSimon Horman 				  mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK,
209999d31326SSimon Horman 				  sizeof(key->arp.tha))))
210099d31326SSimon Horman 		goto nla_put_failure;
210177b9900eSJiri Pirko 
21025c72299fSAmritha Nambiar 	if ((key->basic.ip_proto == IPPROTO_TCP ||
21035c72299fSAmritha Nambiar 	     key->basic.ip_proto == IPPROTO_UDP ||
21045c72299fSAmritha Nambiar 	     key->basic.ip_proto == IPPROTO_SCTP) &&
21055c72299fSAmritha Nambiar 	     fl_dump_key_port_range(skb, key, mask))
21065c72299fSAmritha Nambiar 		goto nla_put_failure;
21075c72299fSAmritha Nambiar 
2108bc3103f1SAmir Vadai 	if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
2109bc3103f1SAmir Vadai 	    (fl_dump_key_val(skb, &key->enc_ipv4.src,
2110bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV4_SRC, &mask->enc_ipv4.src,
2111bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
2112bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv4.src)) ||
2113bc3103f1SAmir Vadai 	     fl_dump_key_val(skb, &key->enc_ipv4.dst,
2114bc3103f1SAmir Vadai 			     TCA_FLOWER_KEY_ENC_IPV4_DST, &mask->enc_ipv4.dst,
2115bc3103f1SAmir Vadai 			     TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
2116bc3103f1SAmir Vadai 			     sizeof(key->enc_ipv4.dst))))
2117bc3103f1SAmir Vadai 		goto nla_put_failure;
2118bc3103f1SAmir Vadai 	else if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
2119bc3103f1SAmir Vadai 		 (fl_dump_key_val(skb, &key->enc_ipv6.src,
2120bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV6_SRC, &mask->enc_ipv6.src,
2121bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
2122bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv6.src)) ||
2123bc3103f1SAmir Vadai 		 fl_dump_key_val(skb, &key->enc_ipv6.dst,
2124bc3103f1SAmir Vadai 				 TCA_FLOWER_KEY_ENC_IPV6_DST,
2125bc3103f1SAmir Vadai 				 &mask->enc_ipv6.dst,
2126bc3103f1SAmir Vadai 				 TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
2127bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv6.dst))))
2128bc3103f1SAmir Vadai 		goto nla_put_failure;
2129bc3103f1SAmir Vadai 
2130bc3103f1SAmir Vadai 	if (fl_dump_key_val(skb, &key->enc_key_id, TCA_FLOWER_KEY_ENC_KEY_ID,
2131eb523f42SHadar Hen Zion 			    &mask->enc_key_id, TCA_FLOWER_UNSPEC,
2132f4d997fdSHadar Hen Zion 			    sizeof(key->enc_key_id)) ||
2133f4d997fdSHadar Hen Zion 	    fl_dump_key_val(skb, &key->enc_tp.src,
2134f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
2135f4d997fdSHadar Hen Zion 			    &mask->enc_tp.src,
2136f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
2137f4d997fdSHadar Hen Zion 			    sizeof(key->enc_tp.src)) ||
2138f4d997fdSHadar Hen Zion 	    fl_dump_key_val(skb, &key->enc_tp.dst,
2139f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
2140f4d997fdSHadar Hen Zion 			    &mask->enc_tp.dst,
2141f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
21420e2c17b6SOr Gerlitz 			    sizeof(key->enc_tp.dst)) ||
21430a6e7778SPieter Jansen van Vuuren 	    fl_dump_key_ip(skb, true, &key->enc_ip, &mask->enc_ip) ||
21440a6e7778SPieter Jansen van Vuuren 	    fl_dump_key_enc_opt(skb, &key->enc_opts, &mask->enc_opts))
2145bc3103f1SAmir Vadai 		goto nla_put_failure;
2146bc3103f1SAmir Vadai 
2147faa3ffceSOr Gerlitz 	if (fl_dump_key_flags(skb, key->control.flags, mask->control.flags))
2148faa3ffceSOr Gerlitz 		goto nla_put_failure;
2149faa3ffceSOr Gerlitz 
2150f5749081SJiri Pirko 	return 0;
2151f5749081SJiri Pirko 
2152f5749081SJiri Pirko nla_put_failure:
2153f5749081SJiri Pirko 	return -EMSGSIZE;
2154f5749081SJiri Pirko }
2155f5749081SJiri Pirko 
2156f5749081SJiri Pirko static int fl_dump(struct net *net, struct tcf_proto *tp, void *fh,
215712db03b6SVlad Buslov 		   struct sk_buff *skb, struct tcmsg *t, bool rtnl_held)
2158f5749081SJiri Pirko {
2159f5749081SJiri Pirko 	struct cls_fl_filter *f = fh;
2160f5749081SJiri Pirko 	struct nlattr *nest;
2161f5749081SJiri Pirko 	struct fl_flow_key *key, *mask;
2162f5749081SJiri Pirko 
2163f5749081SJiri Pirko 	if (!f)
2164f5749081SJiri Pirko 		return skb->len;
2165f5749081SJiri Pirko 
2166f5749081SJiri Pirko 	t->tcm_handle = f->handle;
2167f5749081SJiri Pirko 
2168f5749081SJiri Pirko 	nest = nla_nest_start(skb, TCA_OPTIONS);
2169f5749081SJiri Pirko 	if (!nest)
2170f5749081SJiri Pirko 		goto nla_put_failure;
2171f5749081SJiri Pirko 
2172f5749081SJiri Pirko 	if (f->res.classid &&
2173f5749081SJiri Pirko 	    nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid))
2174f5749081SJiri Pirko 		goto nla_put_failure;
2175f5749081SJiri Pirko 
2176f5749081SJiri Pirko 	key = &f->key;
2177f5749081SJiri Pirko 	mask = &f->mask->key;
2178f5749081SJiri Pirko 
2179f5749081SJiri Pirko 	if (fl_dump_key(skb, net, key, mask))
2180f5749081SJiri Pirko 		goto nla_put_failure;
2181f5749081SJiri Pirko 
2182f5749081SJiri Pirko 	if (!tc_skip_hw(f->flags))
2183f5749081SJiri Pirko 		fl_hw_update_stats(tp, f);
2184f5749081SJiri Pirko 
2185749e6720SOr Gerlitz 	if (f->flags && nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags))
2186749e6720SOr Gerlitz 		goto nla_put_failure;
2187e69985c6SAmir Vadai 
218886c55361SVlad Buslov 	if (nla_put_u32(skb, TCA_FLOWER_IN_HW_COUNT, f->in_hw_count))
218986c55361SVlad Buslov 		goto nla_put_failure;
219086c55361SVlad Buslov 
219177b9900eSJiri Pirko 	if (tcf_exts_dump(skb, &f->exts))
219277b9900eSJiri Pirko 		goto nla_put_failure;
219377b9900eSJiri Pirko 
219477b9900eSJiri Pirko 	nla_nest_end(skb, nest);
219577b9900eSJiri Pirko 
219677b9900eSJiri Pirko 	if (tcf_exts_dump_stats(skb, &f->exts) < 0)
219777b9900eSJiri Pirko 		goto nla_put_failure;
219877b9900eSJiri Pirko 
219977b9900eSJiri Pirko 	return skb->len;
220077b9900eSJiri Pirko 
220177b9900eSJiri Pirko nla_put_failure:
220277b9900eSJiri Pirko 	nla_nest_cancel(skb, nest);
220377b9900eSJiri Pirko 	return -1;
220477b9900eSJiri Pirko }
220577b9900eSJiri Pirko 
2206b95ec7ebSJiri Pirko static int fl_tmplt_dump(struct sk_buff *skb, struct net *net, void *tmplt_priv)
2207b95ec7ebSJiri Pirko {
2208b95ec7ebSJiri Pirko 	struct fl_flow_tmplt *tmplt = tmplt_priv;
2209b95ec7ebSJiri Pirko 	struct fl_flow_key *key, *mask;
2210b95ec7ebSJiri Pirko 	struct nlattr *nest;
2211b95ec7ebSJiri Pirko 
2212b95ec7ebSJiri Pirko 	nest = nla_nest_start(skb, TCA_OPTIONS);
2213b95ec7ebSJiri Pirko 	if (!nest)
2214b95ec7ebSJiri Pirko 		goto nla_put_failure;
2215b95ec7ebSJiri Pirko 
2216b95ec7ebSJiri Pirko 	key = &tmplt->dummy_key;
2217b95ec7ebSJiri Pirko 	mask = &tmplt->mask;
2218b95ec7ebSJiri Pirko 
2219b95ec7ebSJiri Pirko 	if (fl_dump_key(skb, net, key, mask))
2220b95ec7ebSJiri Pirko 		goto nla_put_failure;
2221b95ec7ebSJiri Pirko 
2222b95ec7ebSJiri Pirko 	nla_nest_end(skb, nest);
2223b95ec7ebSJiri Pirko 
2224b95ec7ebSJiri Pirko 	return skb->len;
2225b95ec7ebSJiri Pirko 
2226b95ec7ebSJiri Pirko nla_put_failure:
2227b95ec7ebSJiri Pirko 	nla_nest_cancel(skb, nest);
2228b95ec7ebSJiri Pirko 	return -EMSGSIZE;
2229b95ec7ebSJiri Pirko }
2230b95ec7ebSJiri Pirko 
223107d79fc7SCong Wang static void fl_bind_class(void *fh, u32 classid, unsigned long cl)
223207d79fc7SCong Wang {
223307d79fc7SCong Wang 	struct cls_fl_filter *f = fh;
223407d79fc7SCong Wang 
223507d79fc7SCong Wang 	if (f && f->res.classid == classid)
223607d79fc7SCong Wang 		f->res.class = cl;
223707d79fc7SCong Wang }
223807d79fc7SCong Wang 
223977b9900eSJiri Pirko static struct tcf_proto_ops cls_fl_ops __read_mostly = {
224077b9900eSJiri Pirko 	.kind		= "flower",
224177b9900eSJiri Pirko 	.classify	= fl_classify,
224277b9900eSJiri Pirko 	.init		= fl_init,
224377b9900eSJiri Pirko 	.destroy	= fl_destroy,
224477b9900eSJiri Pirko 	.get		= fl_get,
224506177558SVlad Buslov 	.put		= fl_put,
224677b9900eSJiri Pirko 	.change		= fl_change,
224777b9900eSJiri Pirko 	.delete		= fl_delete,
224877b9900eSJiri Pirko 	.walk		= fl_walk,
224931533cbaSJohn Hurley 	.reoffload	= fl_reoffload,
225077b9900eSJiri Pirko 	.dump		= fl_dump,
225107d79fc7SCong Wang 	.bind_class	= fl_bind_class,
2252b95ec7ebSJiri Pirko 	.tmplt_create	= fl_tmplt_create,
2253b95ec7ebSJiri Pirko 	.tmplt_destroy	= fl_tmplt_destroy,
2254b95ec7ebSJiri Pirko 	.tmplt_dump	= fl_tmplt_dump,
225577b9900eSJiri Pirko 	.owner		= THIS_MODULE,
225677b9900eSJiri Pirko };
225777b9900eSJiri Pirko 
225877b9900eSJiri Pirko static int __init cls_fl_init(void)
225977b9900eSJiri Pirko {
226077b9900eSJiri Pirko 	return register_tcf_proto_ops(&cls_fl_ops);
226177b9900eSJiri Pirko }
226277b9900eSJiri Pirko 
226377b9900eSJiri Pirko static void __exit cls_fl_exit(void)
226477b9900eSJiri Pirko {
226577b9900eSJiri Pirko 	unregister_tcf_proto_ops(&cls_fl_ops);
226677b9900eSJiri Pirko }
226777b9900eSJiri Pirko 
226877b9900eSJiri Pirko module_init(cls_fl_init);
226977b9900eSJiri Pirko module_exit(cls_fl_exit);
227077b9900eSJiri Pirko 
227177b9900eSJiri Pirko MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>");
227277b9900eSJiri Pirko MODULE_DESCRIPTION("Flower classifier");
227377b9900eSJiri Pirko MODULE_LICENSE("GPL v2");
2274