xref: /linux/net/sched/cls_flower.c (revision 8f2566225ae2d62d532bb1810ed74fa4bbc5bbdb)
177b9900eSJiri Pirko /*
277b9900eSJiri Pirko  * net/sched/cls_flower.c		Flower classifier
377b9900eSJiri Pirko  *
477b9900eSJiri Pirko  * Copyright (c) 2015 Jiri Pirko <jiri@resnulli.us>
577b9900eSJiri Pirko  *
677b9900eSJiri Pirko  * This program is free software; you can redistribute it and/or modify
777b9900eSJiri Pirko  * it under the terms of the GNU General Public License as published by
877b9900eSJiri Pirko  * the Free Software Foundation; either version 2 of the License, or
977b9900eSJiri Pirko  * (at your option) any later version.
1077b9900eSJiri Pirko  */
1177b9900eSJiri Pirko 
1277b9900eSJiri Pirko #include <linux/kernel.h>
1377b9900eSJiri Pirko #include <linux/init.h>
1477b9900eSJiri Pirko #include <linux/module.h>
1577b9900eSJiri Pirko #include <linux/rhashtable.h>
16d9363774SDaniel Borkmann #include <linux/workqueue.h>
1777b9900eSJiri Pirko 
1877b9900eSJiri Pirko #include <linux/if_ether.h>
1977b9900eSJiri Pirko #include <linux/in6.h>
2077b9900eSJiri Pirko #include <linux/ip.h>
21a577d8f7SBenjamin LaHaise #include <linux/mpls.h>
2277b9900eSJiri Pirko 
2377b9900eSJiri Pirko #include <net/sch_generic.h>
2477b9900eSJiri Pirko #include <net/pkt_cls.h>
2577b9900eSJiri Pirko #include <net/ip.h>
2677b9900eSJiri Pirko #include <net/flow_dissector.h>
270a6e7778SPieter Jansen van Vuuren #include <net/geneve.h>
2877b9900eSJiri Pirko 
29bc3103f1SAmir Vadai #include <net/dst.h>
30bc3103f1SAmir Vadai #include <net/dst_metadata.h>
31bc3103f1SAmir Vadai 
3277b9900eSJiri Pirko struct fl_flow_key {
3377b9900eSJiri Pirko 	int	indev_ifindex;
3442aecaa9STom Herbert 	struct flow_dissector_key_control control;
35bc3103f1SAmir Vadai 	struct flow_dissector_key_control enc_control;
3677b9900eSJiri Pirko 	struct flow_dissector_key_basic basic;
3777b9900eSJiri Pirko 	struct flow_dissector_key_eth_addrs eth;
389399ae9aSHadar Hen Zion 	struct flow_dissector_key_vlan vlan;
39d64efd09SJianbo Liu 	struct flow_dissector_key_vlan cvlan;
4077b9900eSJiri Pirko 	union {
41c3f83241STom Herbert 		struct flow_dissector_key_ipv4_addrs ipv4;
4277b9900eSJiri Pirko 		struct flow_dissector_key_ipv6_addrs ipv6;
4377b9900eSJiri Pirko 	};
4477b9900eSJiri Pirko 	struct flow_dissector_key_ports tp;
457b684884SSimon Horman 	struct flow_dissector_key_icmp icmp;
4699d31326SSimon Horman 	struct flow_dissector_key_arp arp;
47bc3103f1SAmir Vadai 	struct flow_dissector_key_keyid enc_key_id;
48bc3103f1SAmir Vadai 	union {
49bc3103f1SAmir Vadai 		struct flow_dissector_key_ipv4_addrs enc_ipv4;
50bc3103f1SAmir Vadai 		struct flow_dissector_key_ipv6_addrs enc_ipv6;
51bc3103f1SAmir Vadai 	};
52f4d997fdSHadar Hen Zion 	struct flow_dissector_key_ports enc_tp;
53a577d8f7SBenjamin LaHaise 	struct flow_dissector_key_mpls mpls;
54fdfc7dd6SJiri Pirko 	struct flow_dissector_key_tcp tcp;
554d80cc0aSOr Gerlitz 	struct flow_dissector_key_ip ip;
560e2c17b6SOr Gerlitz 	struct flow_dissector_key_ip enc_ip;
570a6e7778SPieter Jansen van Vuuren 	struct flow_dissector_key_enc_opts enc_opts;
585c72299fSAmritha Nambiar 	struct flow_dissector_key_ports tp_min;
595c72299fSAmritha Nambiar 	struct flow_dissector_key_ports tp_max;
6077b9900eSJiri Pirko } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
6177b9900eSJiri Pirko 
6277b9900eSJiri Pirko struct fl_flow_mask_range {
6377b9900eSJiri Pirko 	unsigned short int start;
6477b9900eSJiri Pirko 	unsigned short int end;
6577b9900eSJiri Pirko };
6677b9900eSJiri Pirko 
6777b9900eSJiri Pirko struct fl_flow_mask {
6877b9900eSJiri Pirko 	struct fl_flow_key key;
6977b9900eSJiri Pirko 	struct fl_flow_mask_range range;
705c72299fSAmritha Nambiar 	u32 flags;
7105cd271fSPaul Blakey 	struct rhash_head ht_node;
7205cd271fSPaul Blakey 	struct rhashtable ht;
7305cd271fSPaul Blakey 	struct rhashtable_params filter_ht_params;
7405cd271fSPaul Blakey 	struct flow_dissector dissector;
7505cd271fSPaul Blakey 	struct list_head filters;
7644a5cd43SPaolo Abeni 	struct rcu_work rwork;
7705cd271fSPaul Blakey 	struct list_head list;
7877b9900eSJiri Pirko };
7977b9900eSJiri Pirko 
80b95ec7ebSJiri Pirko struct fl_flow_tmplt {
81b95ec7ebSJiri Pirko 	struct fl_flow_key dummy_key;
82b95ec7ebSJiri Pirko 	struct fl_flow_key mask;
83b95ec7ebSJiri Pirko 	struct flow_dissector dissector;
84b95ec7ebSJiri Pirko 	struct tcf_chain *chain;
85b95ec7ebSJiri Pirko };
86b95ec7ebSJiri Pirko 
8777b9900eSJiri Pirko struct cls_fl_head {
8877b9900eSJiri Pirko 	struct rhashtable ht;
8905cd271fSPaul Blakey 	struct list_head masks;
90aaa908ffSCong Wang 	struct rcu_work rwork;
91c15ab236SChris Mi 	struct idr handle_idr;
92d9363774SDaniel Borkmann };
9377b9900eSJiri Pirko 
9477b9900eSJiri Pirko struct cls_fl_filter {
9505cd271fSPaul Blakey 	struct fl_flow_mask *mask;
9677b9900eSJiri Pirko 	struct rhash_head ht_node;
9777b9900eSJiri Pirko 	struct fl_flow_key mkey;
9877b9900eSJiri Pirko 	struct tcf_exts exts;
9977b9900eSJiri Pirko 	struct tcf_result res;
10077b9900eSJiri Pirko 	struct fl_flow_key key;
10177b9900eSJiri Pirko 	struct list_head list;
10277b9900eSJiri Pirko 	u32 handle;
103e69985c6SAmir Vadai 	u32 flags;
10486c55361SVlad Buslov 	u32 in_hw_count;
105aaa908ffSCong Wang 	struct rcu_work rwork;
1067091d8c7SHadar Hen Zion 	struct net_device *hw_dev;
10777b9900eSJiri Pirko };
10877b9900eSJiri Pirko 
10905cd271fSPaul Blakey static const struct rhashtable_params mask_ht_params = {
11005cd271fSPaul Blakey 	.key_offset = offsetof(struct fl_flow_mask, key),
11105cd271fSPaul Blakey 	.key_len = sizeof(struct fl_flow_key),
11205cd271fSPaul Blakey 	.head_offset = offsetof(struct fl_flow_mask, ht_node),
11305cd271fSPaul Blakey 	.automatic_shrinking = true,
11405cd271fSPaul Blakey };
11505cd271fSPaul Blakey 
11677b9900eSJiri Pirko static unsigned short int fl_mask_range(const struct fl_flow_mask *mask)
11777b9900eSJiri Pirko {
11877b9900eSJiri Pirko 	return mask->range.end - mask->range.start;
11977b9900eSJiri Pirko }
12077b9900eSJiri Pirko 
12177b9900eSJiri Pirko static void fl_mask_update_range(struct fl_flow_mask *mask)
12277b9900eSJiri Pirko {
12377b9900eSJiri Pirko 	const u8 *bytes = (const u8 *) &mask->key;
12477b9900eSJiri Pirko 	size_t size = sizeof(mask->key);
12505cd271fSPaul Blakey 	size_t i, first = 0, last;
12677b9900eSJiri Pirko 
12705cd271fSPaul Blakey 	for (i = 0; i < size; i++) {
12877b9900eSJiri Pirko 		if (bytes[i]) {
12977b9900eSJiri Pirko 			first = i;
13005cd271fSPaul Blakey 			break;
13105cd271fSPaul Blakey 		}
13205cd271fSPaul Blakey 	}
13305cd271fSPaul Blakey 	last = first;
13405cd271fSPaul Blakey 	for (i = size - 1; i != first; i--) {
13505cd271fSPaul Blakey 		if (bytes[i]) {
13677b9900eSJiri Pirko 			last = i;
13705cd271fSPaul Blakey 			break;
13877b9900eSJiri Pirko 		}
13977b9900eSJiri Pirko 	}
14077b9900eSJiri Pirko 	mask->range.start = rounddown(first, sizeof(long));
14177b9900eSJiri Pirko 	mask->range.end = roundup(last + 1, sizeof(long));
14277b9900eSJiri Pirko }
14377b9900eSJiri Pirko 
14477b9900eSJiri Pirko static void *fl_key_get_start(struct fl_flow_key *key,
14577b9900eSJiri Pirko 			      const struct fl_flow_mask *mask)
14677b9900eSJiri Pirko {
14777b9900eSJiri Pirko 	return (u8 *) key + mask->range.start;
14877b9900eSJiri Pirko }
14977b9900eSJiri Pirko 
15077b9900eSJiri Pirko static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key,
15177b9900eSJiri Pirko 			      struct fl_flow_mask *mask)
15277b9900eSJiri Pirko {
15377b9900eSJiri Pirko 	const long *lkey = fl_key_get_start(key, mask);
15477b9900eSJiri Pirko 	const long *lmask = fl_key_get_start(&mask->key, mask);
15577b9900eSJiri Pirko 	long *lmkey = fl_key_get_start(mkey, mask);
15677b9900eSJiri Pirko 	int i;
15777b9900eSJiri Pirko 
15877b9900eSJiri Pirko 	for (i = 0; i < fl_mask_range(mask); i += sizeof(long))
15977b9900eSJiri Pirko 		*lmkey++ = *lkey++ & *lmask++;
16077b9900eSJiri Pirko }
16177b9900eSJiri Pirko 
162b95ec7ebSJiri Pirko static bool fl_mask_fits_tmplt(struct fl_flow_tmplt *tmplt,
163b95ec7ebSJiri Pirko 			       struct fl_flow_mask *mask)
164b95ec7ebSJiri Pirko {
165b95ec7ebSJiri Pirko 	const long *lmask = fl_key_get_start(&mask->key, mask);
166b95ec7ebSJiri Pirko 	const long *ltmplt;
167b95ec7ebSJiri Pirko 	int i;
168b95ec7ebSJiri Pirko 
169b95ec7ebSJiri Pirko 	if (!tmplt)
170b95ec7ebSJiri Pirko 		return true;
171b95ec7ebSJiri Pirko 	ltmplt = fl_key_get_start(&tmplt->mask, mask);
172b95ec7ebSJiri Pirko 	for (i = 0; i < fl_mask_range(mask); i += sizeof(long)) {
173b95ec7ebSJiri Pirko 		if (~*ltmplt++ & *lmask++)
174b95ec7ebSJiri Pirko 			return false;
175b95ec7ebSJiri Pirko 	}
176b95ec7ebSJiri Pirko 	return true;
177b95ec7ebSJiri Pirko }
178b95ec7ebSJiri Pirko 
17977b9900eSJiri Pirko static void fl_clear_masked_range(struct fl_flow_key *key,
18077b9900eSJiri Pirko 				  struct fl_flow_mask *mask)
18177b9900eSJiri Pirko {
18277b9900eSJiri Pirko 	memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask));
18377b9900eSJiri Pirko }
18477b9900eSJiri Pirko 
1855c72299fSAmritha Nambiar static bool fl_range_port_dst_cmp(struct cls_fl_filter *filter,
1865c72299fSAmritha Nambiar 				  struct fl_flow_key *key,
1875c72299fSAmritha Nambiar 				  struct fl_flow_key *mkey)
1885c72299fSAmritha Nambiar {
1895c72299fSAmritha Nambiar 	__be16 min_mask, max_mask, min_val, max_val;
1905c72299fSAmritha Nambiar 
1915c72299fSAmritha Nambiar 	min_mask = htons(filter->mask->key.tp_min.dst);
1925c72299fSAmritha Nambiar 	max_mask = htons(filter->mask->key.tp_max.dst);
1935c72299fSAmritha Nambiar 	min_val = htons(filter->key.tp_min.dst);
1945c72299fSAmritha Nambiar 	max_val = htons(filter->key.tp_max.dst);
1955c72299fSAmritha Nambiar 
1965c72299fSAmritha Nambiar 	if (min_mask && max_mask) {
1975c72299fSAmritha Nambiar 		if (htons(key->tp.dst) < min_val ||
1985c72299fSAmritha Nambiar 		    htons(key->tp.dst) > max_val)
1995c72299fSAmritha Nambiar 			return false;
2005c72299fSAmritha Nambiar 
2015c72299fSAmritha Nambiar 		/* skb does not have min and max values */
2025c72299fSAmritha Nambiar 		mkey->tp_min.dst = filter->mkey.tp_min.dst;
2035c72299fSAmritha Nambiar 		mkey->tp_max.dst = filter->mkey.tp_max.dst;
2045c72299fSAmritha Nambiar 	}
2055c72299fSAmritha Nambiar 	return true;
2065c72299fSAmritha Nambiar }
2075c72299fSAmritha Nambiar 
2085c72299fSAmritha Nambiar static bool fl_range_port_src_cmp(struct cls_fl_filter *filter,
2095c72299fSAmritha Nambiar 				  struct fl_flow_key *key,
2105c72299fSAmritha Nambiar 				  struct fl_flow_key *mkey)
2115c72299fSAmritha Nambiar {
2125c72299fSAmritha Nambiar 	__be16 min_mask, max_mask, min_val, max_val;
2135c72299fSAmritha Nambiar 
2145c72299fSAmritha Nambiar 	min_mask = htons(filter->mask->key.tp_min.src);
2155c72299fSAmritha Nambiar 	max_mask = htons(filter->mask->key.tp_max.src);
2165c72299fSAmritha Nambiar 	min_val = htons(filter->key.tp_min.src);
2175c72299fSAmritha Nambiar 	max_val = htons(filter->key.tp_max.src);
2185c72299fSAmritha Nambiar 
2195c72299fSAmritha Nambiar 	if (min_mask && max_mask) {
2205c72299fSAmritha Nambiar 		if (htons(key->tp.src) < min_val ||
2215c72299fSAmritha Nambiar 		    htons(key->tp.src) > max_val)
2225c72299fSAmritha Nambiar 			return false;
2235c72299fSAmritha Nambiar 
2245c72299fSAmritha Nambiar 		/* skb does not have min and max values */
2255c72299fSAmritha Nambiar 		mkey->tp_min.src = filter->mkey.tp_min.src;
2265c72299fSAmritha Nambiar 		mkey->tp_max.src = filter->mkey.tp_max.src;
2275c72299fSAmritha Nambiar 	}
2285c72299fSAmritha Nambiar 	return true;
2295c72299fSAmritha Nambiar }
2305c72299fSAmritha Nambiar 
2315c72299fSAmritha Nambiar static struct cls_fl_filter *__fl_lookup(struct fl_flow_mask *mask,
232a3308d8fSPaul Blakey 					 struct fl_flow_key *mkey)
233a3308d8fSPaul Blakey {
23405cd271fSPaul Blakey 	return rhashtable_lookup_fast(&mask->ht, fl_key_get_start(mkey, mask),
23505cd271fSPaul Blakey 				      mask->filter_ht_params);
236a3308d8fSPaul Blakey }
237a3308d8fSPaul Blakey 
2385c72299fSAmritha Nambiar static struct cls_fl_filter *fl_lookup_range(struct fl_flow_mask *mask,
2395c72299fSAmritha Nambiar 					     struct fl_flow_key *mkey,
2405c72299fSAmritha Nambiar 					     struct fl_flow_key *key)
2415c72299fSAmritha Nambiar {
2425c72299fSAmritha Nambiar 	struct cls_fl_filter *filter, *f;
2435c72299fSAmritha Nambiar 
2445c72299fSAmritha Nambiar 	list_for_each_entry_rcu(filter, &mask->filters, list) {
2455c72299fSAmritha Nambiar 		if (!fl_range_port_dst_cmp(filter, key, mkey))
2465c72299fSAmritha Nambiar 			continue;
2475c72299fSAmritha Nambiar 
2485c72299fSAmritha Nambiar 		if (!fl_range_port_src_cmp(filter, key, mkey))
2495c72299fSAmritha Nambiar 			continue;
2505c72299fSAmritha Nambiar 
2515c72299fSAmritha Nambiar 		f = __fl_lookup(mask, mkey);
2525c72299fSAmritha Nambiar 		if (f)
2535c72299fSAmritha Nambiar 			return f;
2545c72299fSAmritha Nambiar 	}
2555c72299fSAmritha Nambiar 	return NULL;
2565c72299fSAmritha Nambiar }
2575c72299fSAmritha Nambiar 
2585c72299fSAmritha Nambiar static struct cls_fl_filter *fl_lookup(struct fl_flow_mask *mask,
2595c72299fSAmritha Nambiar 				       struct fl_flow_key *mkey,
2605c72299fSAmritha Nambiar 				       struct fl_flow_key *key)
2615c72299fSAmritha Nambiar {
2625c72299fSAmritha Nambiar 	if ((mask->flags & TCA_FLOWER_MASK_FLAGS_RANGE))
2635c72299fSAmritha Nambiar 		return fl_lookup_range(mask, mkey, key);
2645c72299fSAmritha Nambiar 
2655c72299fSAmritha Nambiar 	return __fl_lookup(mask, mkey);
2665c72299fSAmritha Nambiar }
2675c72299fSAmritha Nambiar 
26877b9900eSJiri Pirko static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp,
26977b9900eSJiri Pirko 		       struct tcf_result *res)
27077b9900eSJiri Pirko {
27177b9900eSJiri Pirko 	struct cls_fl_head *head = rcu_dereference_bh(tp->root);
27277b9900eSJiri Pirko 	struct cls_fl_filter *f;
27305cd271fSPaul Blakey 	struct fl_flow_mask *mask;
27477b9900eSJiri Pirko 	struct fl_flow_key skb_key;
27577b9900eSJiri Pirko 	struct fl_flow_key skb_mkey;
27677b9900eSJiri Pirko 
27705cd271fSPaul Blakey 	list_for_each_entry_rcu(mask, &head->masks, list) {
27805cd271fSPaul Blakey 		fl_clear_masked_range(&skb_key, mask);
279bc3103f1SAmir Vadai 
28077b9900eSJiri Pirko 		skb_key.indev_ifindex = skb->skb_iif;
28105cd271fSPaul Blakey 		/* skb_flow_dissect() does not set n_proto in case an unknown
28205cd271fSPaul Blakey 		 * protocol, so do it rather here.
28377b9900eSJiri Pirko 		 */
28477b9900eSJiri Pirko 		skb_key.basic.n_proto = skb->protocol;
28505cd271fSPaul Blakey 		skb_flow_dissect_tunnel_info(skb, &mask->dissector, &skb_key);
28605cd271fSPaul Blakey 		skb_flow_dissect(skb, &mask->dissector, &skb_key, 0);
28777b9900eSJiri Pirko 
28805cd271fSPaul Blakey 		fl_set_masked_key(&skb_mkey, &skb_key, mask);
28977b9900eSJiri Pirko 
2905c72299fSAmritha Nambiar 		f = fl_lookup(mask, &skb_mkey, &skb_key);
291e8eb36cdSAmir Vadai 		if (f && !tc_skip_sw(f->flags)) {
29277b9900eSJiri Pirko 			*res = f->res;
29377b9900eSJiri Pirko 			return tcf_exts_exec(skb, &f->exts, res);
29477b9900eSJiri Pirko 		}
29505cd271fSPaul Blakey 	}
29677b9900eSJiri Pirko 	return -1;
29777b9900eSJiri Pirko }
29877b9900eSJiri Pirko 
29977b9900eSJiri Pirko static int fl_init(struct tcf_proto *tp)
30077b9900eSJiri Pirko {
30177b9900eSJiri Pirko 	struct cls_fl_head *head;
30277b9900eSJiri Pirko 
30377b9900eSJiri Pirko 	head = kzalloc(sizeof(*head), GFP_KERNEL);
30477b9900eSJiri Pirko 	if (!head)
30577b9900eSJiri Pirko 		return -ENOBUFS;
30677b9900eSJiri Pirko 
30705cd271fSPaul Blakey 	INIT_LIST_HEAD_RCU(&head->masks);
30877b9900eSJiri Pirko 	rcu_assign_pointer(tp->root, head);
309c15ab236SChris Mi 	idr_init(&head->handle_idr);
31077b9900eSJiri Pirko 
31105cd271fSPaul Blakey 	return rhashtable_init(&head->ht, &mask_ht_params);
31205cd271fSPaul Blakey }
31305cd271fSPaul Blakey 
31444a5cd43SPaolo Abeni static void fl_mask_free(struct fl_flow_mask *mask)
31544a5cd43SPaolo Abeni {
31644a5cd43SPaolo Abeni 	rhashtable_destroy(&mask->ht);
31744a5cd43SPaolo Abeni 	kfree(mask);
31844a5cd43SPaolo Abeni }
31944a5cd43SPaolo Abeni 
32044a5cd43SPaolo Abeni static void fl_mask_free_work(struct work_struct *work)
32144a5cd43SPaolo Abeni {
32244a5cd43SPaolo Abeni 	struct fl_flow_mask *mask = container_of(to_rcu_work(work),
32344a5cd43SPaolo Abeni 						 struct fl_flow_mask, rwork);
32444a5cd43SPaolo Abeni 
32544a5cd43SPaolo Abeni 	fl_mask_free(mask);
32644a5cd43SPaolo Abeni }
32744a5cd43SPaolo Abeni 
32805cd271fSPaul Blakey static bool fl_mask_put(struct cls_fl_head *head, struct fl_flow_mask *mask,
32905cd271fSPaul Blakey 			bool async)
33005cd271fSPaul Blakey {
33105cd271fSPaul Blakey 	if (!list_empty(&mask->filters))
33205cd271fSPaul Blakey 		return false;
33305cd271fSPaul Blakey 
33405cd271fSPaul Blakey 	rhashtable_remove_fast(&head->ht, &mask->ht_node, mask_ht_params);
33505cd271fSPaul Blakey 	list_del_rcu(&mask->list);
33605cd271fSPaul Blakey 	if (async)
33744a5cd43SPaolo Abeni 		tcf_queue_work(&mask->rwork, fl_mask_free_work);
33805cd271fSPaul Blakey 	else
33944a5cd43SPaolo Abeni 		fl_mask_free(mask);
34005cd271fSPaul Blakey 
34105cd271fSPaul Blakey 	return true;
34277b9900eSJiri Pirko }
34377b9900eSJiri Pirko 
3440dadc117SCong Wang static void __fl_destroy_filter(struct cls_fl_filter *f)
3450dadc117SCong Wang {
3460dadc117SCong Wang 	tcf_exts_destroy(&f->exts);
3470dadc117SCong Wang 	tcf_exts_put_net(&f->exts);
3480dadc117SCong Wang 	kfree(f);
3490dadc117SCong Wang }
3500dadc117SCong Wang 
3510552c8afSCong Wang static void fl_destroy_filter_work(struct work_struct *work)
3520552c8afSCong Wang {
353aaa908ffSCong Wang 	struct cls_fl_filter *f = container_of(to_rcu_work(work),
354aaa908ffSCong Wang 					struct cls_fl_filter, rwork);
3550552c8afSCong Wang 
3560552c8afSCong Wang 	rtnl_lock();
3570dadc117SCong Wang 	__fl_destroy_filter(f);
3580552c8afSCong Wang 	rtnl_unlock();
3590552c8afSCong Wang }
3600552c8afSCong Wang 
3611b0f8037SJakub Kicinski static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f,
3621b0f8037SJakub Kicinski 				 struct netlink_ext_ack *extack)
3635b33f488SAmir Vadai {
364de4784caSJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
365208c0f4bSJiri Pirko 	struct tcf_block *block = tp->chain->block;
3665b33f488SAmir Vadai 
3671b0f8037SJakub Kicinski 	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack);
368de4784caSJiri Pirko 	cls_flower.command = TC_CLSFLOWER_DESTROY;
369de4784caSJiri Pirko 	cls_flower.cookie = (unsigned long) f;
3705b33f488SAmir Vadai 
371aeb3fecdSCong Wang 	tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, false);
372caa72601SJiri Pirko 	tcf_block_offload_dec(block, &f->flags);
3735b33f488SAmir Vadai }
3745b33f488SAmir Vadai 
375e8eb36cdSAmir Vadai static int fl_hw_replace_filter(struct tcf_proto *tp,
37641002038SQuentin Monnet 				struct cls_fl_filter *f,
37741002038SQuentin Monnet 				struct netlink_ext_ack *extack)
3785b33f488SAmir Vadai {
379de4784caSJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
380208c0f4bSJiri Pirko 	struct tcf_block *block = tp->chain->block;
381717503b9SJiri Pirko 	bool skip_sw = tc_skip_sw(f->flags);
382e8eb36cdSAmir Vadai 	int err;
3835b33f488SAmir Vadai 
384*8f256622SPablo Neira Ayuso 	cls_flower.rule = flow_rule_alloc();
385*8f256622SPablo Neira Ayuso 	if (!cls_flower.rule)
386*8f256622SPablo Neira Ayuso 		return -ENOMEM;
387*8f256622SPablo Neira Ayuso 
388ea205940SJakub Kicinski 	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack);
389de4784caSJiri Pirko 	cls_flower.command = TC_CLSFLOWER_REPLACE;
390de4784caSJiri Pirko 	cls_flower.cookie = (unsigned long) f;
391*8f256622SPablo Neira Ayuso 	cls_flower.rule->match.dissector = &f->mask->dissector;
392*8f256622SPablo Neira Ayuso 	cls_flower.rule->match.mask = &f->mask->key;
393*8f256622SPablo Neira Ayuso 	cls_flower.rule->match.key = &f->mkey;
394de4784caSJiri Pirko 	cls_flower.exts = &f->exts;
395384c181eSAmritha Nambiar 	cls_flower.classid = f->res.classid;
3965b33f488SAmir Vadai 
397aeb3fecdSCong Wang 	err = tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, skip_sw);
398*8f256622SPablo Neira Ayuso 	kfree(cls_flower.rule);
399*8f256622SPablo Neira Ayuso 
400717503b9SJiri Pirko 	if (err < 0) {
4011b0f8037SJakub Kicinski 		fl_hw_destroy_filter(tp, f, NULL);
402717503b9SJiri Pirko 		return err;
403717503b9SJiri Pirko 	} else if (err > 0) {
40431533cbaSJohn Hurley 		f->in_hw_count = err;
405caa72601SJiri Pirko 		tcf_block_offload_inc(block, &f->flags);
406717503b9SJiri Pirko 	}
407717503b9SJiri Pirko 
408717503b9SJiri Pirko 	if (skip_sw && !(f->flags & TCA_CLS_FLAGS_IN_HW))
409717503b9SJiri Pirko 		return -EINVAL;
410717503b9SJiri Pirko 
411e8eb36cdSAmir Vadai 	return 0;
4125b33f488SAmir Vadai }
4135b33f488SAmir Vadai 
41410cbc684SAmir Vadai static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
41510cbc684SAmir Vadai {
416de4784caSJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
417208c0f4bSJiri Pirko 	struct tcf_block *block = tp->chain->block;
41810cbc684SAmir Vadai 
419ea205940SJakub Kicinski 	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, NULL);
420de4784caSJiri Pirko 	cls_flower.command = TC_CLSFLOWER_STATS;
421de4784caSJiri Pirko 	cls_flower.cookie = (unsigned long) f;
422de4784caSJiri Pirko 	cls_flower.exts = &f->exts;
423384c181eSAmritha Nambiar 	cls_flower.classid = f->res.classid;
42410cbc684SAmir Vadai 
425aeb3fecdSCong Wang 	tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, false);
42610cbc684SAmir Vadai }
42710cbc684SAmir Vadai 
42805cd271fSPaul Blakey static bool __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,
4291b0f8037SJakub Kicinski 			struct netlink_ext_ack *extack)
43013fa876eSRoi Dayan {
431c15ab236SChris Mi 	struct cls_fl_head *head = rtnl_dereference(tp->root);
43205cd271fSPaul Blakey 	bool async = tcf_exts_get_net(&f->exts);
43305cd271fSPaul Blakey 	bool last;
434c15ab236SChris Mi 
4359c160941SMatthew Wilcox 	idr_remove(&head->handle_idr, f->handle);
43613fa876eSRoi Dayan 	list_del_rcu(&f->list);
43705cd271fSPaul Blakey 	last = fl_mask_put(head, f->mask, async);
43879685219SHadar Hen Zion 	if (!tc_skip_hw(f->flags))
4391b0f8037SJakub Kicinski 		fl_hw_destroy_filter(tp, f, extack);
44013fa876eSRoi Dayan 	tcf_unbind_filter(tp, &f->res);
44105cd271fSPaul Blakey 	if (async)
442aaa908ffSCong Wang 		tcf_queue_work(&f->rwork, fl_destroy_filter_work);
4430dadc117SCong Wang 	else
4440dadc117SCong Wang 		__fl_destroy_filter(f);
44505cd271fSPaul Blakey 
44605cd271fSPaul Blakey 	return last;
44713fa876eSRoi Dayan }
44813fa876eSRoi Dayan 
449d9363774SDaniel Borkmann static void fl_destroy_sleepable(struct work_struct *work)
450d9363774SDaniel Borkmann {
451aaa908ffSCong Wang 	struct cls_fl_head *head = container_of(to_rcu_work(work),
452aaa908ffSCong Wang 						struct cls_fl_head,
453aaa908ffSCong Wang 						rwork);
454de9dc650SPaul Blakey 
455de9dc650SPaul Blakey 	rhashtable_destroy(&head->ht);
456d9363774SDaniel Borkmann 	kfree(head);
457d9363774SDaniel Borkmann 	module_put(THIS_MODULE);
458d9363774SDaniel Borkmann }
459d9363774SDaniel Borkmann 
460715df5ecSJakub Kicinski static void fl_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
46177b9900eSJiri Pirko {
46277b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
46305cd271fSPaul Blakey 	struct fl_flow_mask *mask, *next_mask;
46477b9900eSJiri Pirko 	struct cls_fl_filter *f, *next;
46577b9900eSJiri Pirko 
46605cd271fSPaul Blakey 	list_for_each_entry_safe(mask, next_mask, &head->masks, list) {
46705cd271fSPaul Blakey 		list_for_each_entry_safe(f, next, &mask->filters, list) {
46805cd271fSPaul Blakey 			if (__fl_delete(tp, f, extack))
46905cd271fSPaul Blakey 				break;
47005cd271fSPaul Blakey 		}
47105cd271fSPaul Blakey 	}
472c15ab236SChris Mi 	idr_destroy(&head->handle_idr);
473d9363774SDaniel Borkmann 
474d9363774SDaniel Borkmann 	__module_get(THIS_MODULE);
475aaa908ffSCong Wang 	tcf_queue_work(&head->rwork, fl_destroy_sleepable);
47677b9900eSJiri Pirko }
47777b9900eSJiri Pirko 
4788113c095SWANG Cong static void *fl_get(struct tcf_proto *tp, u32 handle)
47977b9900eSJiri Pirko {
48077b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
48177b9900eSJiri Pirko 
482322d884bSMatthew Wilcox 	return idr_find(&head->handle_idr, handle);
48377b9900eSJiri Pirko }
48477b9900eSJiri Pirko 
48577b9900eSJiri Pirko static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
48677b9900eSJiri Pirko 	[TCA_FLOWER_UNSPEC]		= { .type = NLA_UNSPEC },
48777b9900eSJiri Pirko 	[TCA_FLOWER_CLASSID]		= { .type = NLA_U32 },
48877b9900eSJiri Pirko 	[TCA_FLOWER_INDEV]		= { .type = NLA_STRING,
48977b9900eSJiri Pirko 					    .len = IFNAMSIZ },
49077b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_DST]	= { .len = ETH_ALEN },
49177b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_DST_MASK]	= { .len = ETH_ALEN },
49277b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_SRC]	= { .len = ETH_ALEN },
49377b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_SRC_MASK]	= { .len = ETH_ALEN },
49477b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_TYPE]	= { .type = NLA_U16 },
49577b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IP_PROTO]	= { .type = NLA_U8 },
49677b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_SRC]	= { .type = NLA_U32 },
49777b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_SRC_MASK]	= { .type = NLA_U32 },
49877b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_DST]	= { .type = NLA_U32 },
49977b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_DST_MASK]	= { .type = NLA_U32 },
50077b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
50177b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_SRC_MASK]	= { .len = sizeof(struct in6_addr) },
50277b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
50377b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_DST_MASK]	= { .len = sizeof(struct in6_addr) },
50477b9900eSJiri Pirko 	[TCA_FLOWER_KEY_TCP_SRC]	= { .type = NLA_U16 },
50577b9900eSJiri Pirko 	[TCA_FLOWER_KEY_TCP_DST]	= { .type = NLA_U16 },
506b175c3a4SJamal Hadi Salim 	[TCA_FLOWER_KEY_UDP_SRC]	= { .type = NLA_U16 },
507b175c3a4SJamal Hadi Salim 	[TCA_FLOWER_KEY_UDP_DST]	= { .type = NLA_U16 },
5089399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_ID]	= { .type = NLA_U16 },
5099399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_PRIO]	= { .type = NLA_U8 },
5109399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_ETH_TYPE]	= { .type = NLA_U16 },
511bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_KEY_ID]	= { .type = NLA_U32 },
512bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_SRC]	= { .type = NLA_U32 },
513bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NLA_U32 },
514bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_DST]	= { .type = NLA_U32 },
515bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NLA_U32 },
516bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
517bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) },
518bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
519bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) },
520aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_TCP_SRC_MASK]	= { .type = NLA_U16 },
521aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_TCP_DST_MASK]	= { .type = NLA_U16 },
522aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_UDP_SRC_MASK]	= { .type = NLA_U16 },
523aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_UDP_DST_MASK]	= { .type = NLA_U16 },
5245976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_SRC_MASK]	= { .type = NLA_U16 },
5255976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_DST_MASK]	= { .type = NLA_U16 },
5265976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_SRC]	= { .type = NLA_U16 },
5275976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_DST]	= { .type = NLA_U16 },
528f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT]	= { .type = NLA_U16 },
529f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK]	= { .type = NLA_U16 },
530f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]	= { .type = NLA_U16 },
531f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK]	= { .type = NLA_U16 },
532faa3ffceSOr Gerlitz 	[TCA_FLOWER_KEY_FLAGS]		= { .type = NLA_U32 },
533faa3ffceSOr Gerlitz 	[TCA_FLOWER_KEY_FLAGS_MASK]	= { .type = NLA_U32 },
5347b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_TYPE]	= { .type = NLA_U8 },
5357b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_TYPE_MASK] = { .type = NLA_U8 },
5367b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_CODE]	= { .type = NLA_U8 },
5377b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_CODE_MASK] = { .type = NLA_U8 },
5387b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_TYPE]	= { .type = NLA_U8 },
5397b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_TYPE_MASK] = { .type = NLA_U8 },
5407b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_CODE]	= { .type = NLA_U8 },
5417b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_CODE_MASK] = { .type = NLA_U8 },
54299d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SIP]	= { .type = NLA_U32 },
54399d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SIP_MASK]	= { .type = NLA_U32 },
54499d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_TIP]	= { .type = NLA_U32 },
54599d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_TIP_MASK]	= { .type = NLA_U32 },
54699d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_OP]		= { .type = NLA_U8 },
54799d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_OP_MASK]	= { .type = NLA_U8 },
54899d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SHA]	= { .len = ETH_ALEN },
54999d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SHA_MASK]	= { .len = ETH_ALEN },
55099d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_THA]	= { .len = ETH_ALEN },
55199d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_THA_MASK]	= { .len = ETH_ALEN },
552a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_TTL]	= { .type = NLA_U8 },
553a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_BOS]	= { .type = NLA_U8 },
554a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_TC]	= { .type = NLA_U8 },
555a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_LABEL]	= { .type = NLA_U32 },
556fdfc7dd6SJiri Pirko 	[TCA_FLOWER_KEY_TCP_FLAGS]	= { .type = NLA_U16 },
557fdfc7dd6SJiri Pirko 	[TCA_FLOWER_KEY_TCP_FLAGS_MASK]	= { .type = NLA_U16 },
5584d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TOS]		= { .type = NLA_U8 },
5594d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TOS_MASK]	= { .type = NLA_U8 },
5604d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TTL]		= { .type = NLA_U8 },
5614d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TTL_MASK]	= { .type = NLA_U8 },
562d64efd09SJianbo Liu 	[TCA_FLOWER_KEY_CVLAN_ID]	= { .type = NLA_U16 },
563d64efd09SJianbo Liu 	[TCA_FLOWER_KEY_CVLAN_PRIO]	= { .type = NLA_U8 },
564d64efd09SJianbo Liu 	[TCA_FLOWER_KEY_CVLAN_ETH_TYPE]	= { .type = NLA_U16 },
5650e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TOS]	= { .type = NLA_U8 },
5660e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TOS_MASK] = { .type = NLA_U8 },
5670e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TTL]	 = { .type = NLA_U8 },
5680e2c17b6SOr Gerlitz 	[TCA_FLOWER_KEY_ENC_IP_TTL_MASK] = { .type = NLA_U8 },
5690a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPTS]	= { .type = NLA_NESTED },
5700a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPTS_MASK]	= { .type = NLA_NESTED },
5710a6e7778SPieter Jansen van Vuuren };
5720a6e7778SPieter Jansen van Vuuren 
5730a6e7778SPieter Jansen van Vuuren static const struct nla_policy
5740a6e7778SPieter Jansen van Vuuren enc_opts_policy[TCA_FLOWER_KEY_ENC_OPTS_MAX + 1] = {
5750a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPTS_GENEVE]        = { .type = NLA_NESTED },
5760a6e7778SPieter Jansen van Vuuren };
5770a6e7778SPieter Jansen van Vuuren 
5780a6e7778SPieter Jansen van Vuuren static const struct nla_policy
5790a6e7778SPieter Jansen van Vuuren geneve_opt_policy[TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX + 1] = {
5800a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS]      = { .type = NLA_U16 },
5810a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE]       = { .type = NLA_U8 },
5820a6e7778SPieter Jansen van Vuuren 	[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA]       = { .type = NLA_BINARY,
5830a6e7778SPieter Jansen van Vuuren 						       .len = 128 },
58477b9900eSJiri Pirko };
58577b9900eSJiri Pirko 
58677b9900eSJiri Pirko static void fl_set_key_val(struct nlattr **tb,
58777b9900eSJiri Pirko 			   void *val, int val_type,
58877b9900eSJiri Pirko 			   void *mask, int mask_type, int len)
58977b9900eSJiri Pirko {
59077b9900eSJiri Pirko 	if (!tb[val_type])
59177b9900eSJiri Pirko 		return;
59277b9900eSJiri Pirko 	memcpy(val, nla_data(tb[val_type]), len);
59377b9900eSJiri Pirko 	if (mask_type == TCA_FLOWER_UNSPEC || !tb[mask_type])
59477b9900eSJiri Pirko 		memset(mask, 0xff, len);
59577b9900eSJiri Pirko 	else
59677b9900eSJiri Pirko 		memcpy(mask, nla_data(tb[mask_type]), len);
59777b9900eSJiri Pirko }
59877b9900eSJiri Pirko 
5995c72299fSAmritha Nambiar static int fl_set_key_port_range(struct nlattr **tb, struct fl_flow_key *key,
6005c72299fSAmritha Nambiar 				 struct fl_flow_key *mask)
6015c72299fSAmritha Nambiar {
6025c72299fSAmritha Nambiar 	fl_set_key_val(tb, &key->tp_min.dst,
6035c72299fSAmritha Nambiar 		       TCA_FLOWER_KEY_PORT_DST_MIN, &mask->tp_min.dst,
6045c72299fSAmritha Nambiar 		       TCA_FLOWER_UNSPEC, sizeof(key->tp_min.dst));
6055c72299fSAmritha Nambiar 	fl_set_key_val(tb, &key->tp_max.dst,
6065c72299fSAmritha Nambiar 		       TCA_FLOWER_KEY_PORT_DST_MAX, &mask->tp_max.dst,
6075c72299fSAmritha Nambiar 		       TCA_FLOWER_UNSPEC, sizeof(key->tp_max.dst));
6085c72299fSAmritha Nambiar 	fl_set_key_val(tb, &key->tp_min.src,
6095c72299fSAmritha Nambiar 		       TCA_FLOWER_KEY_PORT_SRC_MIN, &mask->tp_min.src,
6105c72299fSAmritha Nambiar 		       TCA_FLOWER_UNSPEC, sizeof(key->tp_min.src));
6115c72299fSAmritha Nambiar 	fl_set_key_val(tb, &key->tp_max.src,
6125c72299fSAmritha Nambiar 		       TCA_FLOWER_KEY_PORT_SRC_MAX, &mask->tp_max.src,
6135c72299fSAmritha Nambiar 		       TCA_FLOWER_UNSPEC, sizeof(key->tp_max.src));
6145c72299fSAmritha Nambiar 
6155c72299fSAmritha Nambiar 	if ((mask->tp_min.dst && mask->tp_max.dst &&
6165c72299fSAmritha Nambiar 	     htons(key->tp_max.dst) <= htons(key->tp_min.dst)) ||
6175c72299fSAmritha Nambiar 	     (mask->tp_min.src && mask->tp_max.src &&
6185c72299fSAmritha Nambiar 	      htons(key->tp_max.src) <= htons(key->tp_min.src)))
6195c72299fSAmritha Nambiar 		return -EINVAL;
6205c72299fSAmritha Nambiar 
6215c72299fSAmritha Nambiar 	return 0;
6225c72299fSAmritha Nambiar }
6235c72299fSAmritha Nambiar 
6241a7fca63SBenjamin LaHaise static int fl_set_key_mpls(struct nlattr **tb,
625a577d8f7SBenjamin LaHaise 			   struct flow_dissector_key_mpls *key_val,
626a577d8f7SBenjamin LaHaise 			   struct flow_dissector_key_mpls *key_mask)
627a577d8f7SBenjamin LaHaise {
628a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_TTL]) {
629a577d8f7SBenjamin LaHaise 		key_val->mpls_ttl = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TTL]);
630a577d8f7SBenjamin LaHaise 		key_mask->mpls_ttl = MPLS_TTL_MASK;
631a577d8f7SBenjamin LaHaise 	}
632a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_BOS]) {
6331a7fca63SBenjamin LaHaise 		u8 bos = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_BOS]);
6341a7fca63SBenjamin LaHaise 
6351a7fca63SBenjamin LaHaise 		if (bos & ~MPLS_BOS_MASK)
6361a7fca63SBenjamin LaHaise 			return -EINVAL;
6371a7fca63SBenjamin LaHaise 		key_val->mpls_bos = bos;
638a577d8f7SBenjamin LaHaise 		key_mask->mpls_bos = MPLS_BOS_MASK;
639a577d8f7SBenjamin LaHaise 	}
640a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_TC]) {
6411a7fca63SBenjamin LaHaise 		u8 tc = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TC]);
6421a7fca63SBenjamin LaHaise 
6431a7fca63SBenjamin LaHaise 		if (tc & ~MPLS_TC_MASK)
6441a7fca63SBenjamin LaHaise 			return -EINVAL;
6451a7fca63SBenjamin LaHaise 		key_val->mpls_tc = tc;
646a577d8f7SBenjamin LaHaise 		key_mask->mpls_tc = MPLS_TC_MASK;
647a577d8f7SBenjamin LaHaise 	}
648a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_LABEL]) {
6491a7fca63SBenjamin LaHaise 		u32 label = nla_get_u32(tb[TCA_FLOWER_KEY_MPLS_LABEL]);
6501a7fca63SBenjamin LaHaise 
6511a7fca63SBenjamin LaHaise 		if (label & ~MPLS_LABEL_MASK)
6521a7fca63SBenjamin LaHaise 			return -EINVAL;
6531a7fca63SBenjamin LaHaise 		key_val->mpls_label = label;
654a577d8f7SBenjamin LaHaise 		key_mask->mpls_label = MPLS_LABEL_MASK;
655a577d8f7SBenjamin LaHaise 	}
6561a7fca63SBenjamin LaHaise 	return 0;
657a577d8f7SBenjamin LaHaise }
658a577d8f7SBenjamin LaHaise 
6599399ae9aSHadar Hen Zion static void fl_set_key_vlan(struct nlattr **tb,
660aaab0834SJianbo Liu 			    __be16 ethertype,
661d64efd09SJianbo Liu 			    int vlan_id_key, int vlan_prio_key,
6629399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *key_val,
6639399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *key_mask)
6649399ae9aSHadar Hen Zion {
6659399ae9aSHadar Hen Zion #define VLAN_PRIORITY_MASK	0x7
6669399ae9aSHadar Hen Zion 
667d64efd09SJianbo Liu 	if (tb[vlan_id_key]) {
6689399ae9aSHadar Hen Zion 		key_val->vlan_id =
669d64efd09SJianbo Liu 			nla_get_u16(tb[vlan_id_key]) & VLAN_VID_MASK;
6709399ae9aSHadar Hen Zion 		key_mask->vlan_id = VLAN_VID_MASK;
6719399ae9aSHadar Hen Zion 	}
672d64efd09SJianbo Liu 	if (tb[vlan_prio_key]) {
6739399ae9aSHadar Hen Zion 		key_val->vlan_priority =
674d64efd09SJianbo Liu 			nla_get_u8(tb[vlan_prio_key]) &
6759399ae9aSHadar Hen Zion 			VLAN_PRIORITY_MASK;
6769399ae9aSHadar Hen Zion 		key_mask->vlan_priority = VLAN_PRIORITY_MASK;
6779399ae9aSHadar Hen Zion 	}
678aaab0834SJianbo Liu 	key_val->vlan_tpid = ethertype;
679aaab0834SJianbo Liu 	key_mask->vlan_tpid = cpu_to_be16(~0);
6809399ae9aSHadar Hen Zion }
6819399ae9aSHadar Hen Zion 
682faa3ffceSOr Gerlitz static void fl_set_key_flag(u32 flower_key, u32 flower_mask,
683faa3ffceSOr Gerlitz 			    u32 *dissector_key, u32 *dissector_mask,
684faa3ffceSOr Gerlitz 			    u32 flower_flag_bit, u32 dissector_flag_bit)
685faa3ffceSOr Gerlitz {
686faa3ffceSOr Gerlitz 	if (flower_mask & flower_flag_bit) {
687faa3ffceSOr Gerlitz 		*dissector_mask |= dissector_flag_bit;
688faa3ffceSOr Gerlitz 		if (flower_key & flower_flag_bit)
689faa3ffceSOr Gerlitz 			*dissector_key |= dissector_flag_bit;
690faa3ffceSOr Gerlitz 	}
691faa3ffceSOr Gerlitz }
692faa3ffceSOr Gerlitz 
693d9724772SOr Gerlitz static int fl_set_key_flags(struct nlattr **tb,
694faa3ffceSOr Gerlitz 			    u32 *flags_key, u32 *flags_mask)
695faa3ffceSOr Gerlitz {
696faa3ffceSOr Gerlitz 	u32 key, mask;
697faa3ffceSOr Gerlitz 
698d9724772SOr Gerlitz 	/* mask is mandatory for flags */
699d9724772SOr Gerlitz 	if (!tb[TCA_FLOWER_KEY_FLAGS_MASK])
700d9724772SOr Gerlitz 		return -EINVAL;
701faa3ffceSOr Gerlitz 
702faa3ffceSOr Gerlitz 	key = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS]));
703faa3ffceSOr Gerlitz 	mask = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS_MASK]));
704faa3ffceSOr Gerlitz 
705faa3ffceSOr Gerlitz 	*flags_key  = 0;
706faa3ffceSOr Gerlitz 	*flags_mask = 0;
707faa3ffceSOr Gerlitz 
708faa3ffceSOr Gerlitz 	fl_set_key_flag(key, mask, flags_key, flags_mask,
709faa3ffceSOr Gerlitz 			TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT);
710459d153dSPieter Jansen van Vuuren 	fl_set_key_flag(key, mask, flags_key, flags_mask,
711459d153dSPieter Jansen van Vuuren 			TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST,
712459d153dSPieter Jansen van Vuuren 			FLOW_DIS_FIRST_FRAG);
713d9724772SOr Gerlitz 
714d9724772SOr Gerlitz 	return 0;
715faa3ffceSOr Gerlitz }
716faa3ffceSOr Gerlitz 
7170e2c17b6SOr Gerlitz static void fl_set_key_ip(struct nlattr **tb, bool encap,
7184d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *key,
7194d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *mask)
7204d80cc0aSOr Gerlitz {
7210e2c17b6SOr Gerlitz 	int tos_key = encap ? TCA_FLOWER_KEY_ENC_IP_TOS : TCA_FLOWER_KEY_IP_TOS;
7220e2c17b6SOr Gerlitz 	int ttl_key = encap ? TCA_FLOWER_KEY_ENC_IP_TTL : TCA_FLOWER_KEY_IP_TTL;
7230e2c17b6SOr Gerlitz 	int tos_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TOS_MASK : TCA_FLOWER_KEY_IP_TOS_MASK;
7240e2c17b6SOr Gerlitz 	int ttl_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TTL_MASK : TCA_FLOWER_KEY_IP_TTL_MASK;
7254d80cc0aSOr Gerlitz 
7260e2c17b6SOr Gerlitz 	fl_set_key_val(tb, &key->tos, tos_key, &mask->tos, tos_mask, sizeof(key->tos));
7270e2c17b6SOr Gerlitz 	fl_set_key_val(tb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl));
7284d80cc0aSOr Gerlitz }
7294d80cc0aSOr Gerlitz 
7300a6e7778SPieter Jansen van Vuuren static int fl_set_geneve_opt(const struct nlattr *nla, struct fl_flow_key *key,
7310a6e7778SPieter Jansen van Vuuren 			     int depth, int option_len,
7320a6e7778SPieter Jansen van Vuuren 			     struct netlink_ext_ack *extack)
7330a6e7778SPieter Jansen van Vuuren {
7340a6e7778SPieter Jansen van Vuuren 	struct nlattr *tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX + 1];
7350a6e7778SPieter Jansen van Vuuren 	struct nlattr *class = NULL, *type = NULL, *data = NULL;
7360a6e7778SPieter Jansen van Vuuren 	struct geneve_opt *opt;
7370a6e7778SPieter Jansen van Vuuren 	int err, data_len = 0;
7380a6e7778SPieter Jansen van Vuuren 
7390a6e7778SPieter Jansen van Vuuren 	if (option_len > sizeof(struct geneve_opt))
7400a6e7778SPieter Jansen van Vuuren 		data_len = option_len - sizeof(struct geneve_opt);
7410a6e7778SPieter Jansen van Vuuren 
7420a6e7778SPieter Jansen van Vuuren 	opt = (struct geneve_opt *)&key->enc_opts.data[key->enc_opts.len];
7430a6e7778SPieter Jansen van Vuuren 	memset(opt, 0xff, option_len);
7440a6e7778SPieter Jansen van Vuuren 	opt->length = data_len / 4;
7450a6e7778SPieter Jansen van Vuuren 	opt->r1 = 0;
7460a6e7778SPieter Jansen van Vuuren 	opt->r2 = 0;
7470a6e7778SPieter Jansen van Vuuren 	opt->r3 = 0;
7480a6e7778SPieter Jansen van Vuuren 
7490a6e7778SPieter Jansen van Vuuren 	/* If no mask has been prodived we assume an exact match. */
7500a6e7778SPieter Jansen van Vuuren 	if (!depth)
7510a6e7778SPieter Jansen van Vuuren 		return sizeof(struct geneve_opt) + data_len;
7520a6e7778SPieter Jansen van Vuuren 
7530a6e7778SPieter Jansen van Vuuren 	if (nla_type(nla) != TCA_FLOWER_KEY_ENC_OPTS_GENEVE) {
7540a6e7778SPieter Jansen van Vuuren 		NL_SET_ERR_MSG(extack, "Non-geneve option type for mask");
7550a6e7778SPieter Jansen van Vuuren 		return -EINVAL;
7560a6e7778SPieter Jansen van Vuuren 	}
7570a6e7778SPieter Jansen van Vuuren 
7580a6e7778SPieter Jansen van Vuuren 	err = nla_parse_nested(tb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX,
7590a6e7778SPieter Jansen van Vuuren 			       nla, geneve_opt_policy, extack);
7600a6e7778SPieter Jansen van Vuuren 	if (err < 0)
7610a6e7778SPieter Jansen van Vuuren 		return err;
7620a6e7778SPieter Jansen van Vuuren 
7630a6e7778SPieter Jansen van Vuuren 	/* We are not allowed to omit any of CLASS, TYPE or DATA
7640a6e7778SPieter Jansen van Vuuren 	 * fields from the key.
7650a6e7778SPieter Jansen van Vuuren 	 */
7660a6e7778SPieter Jansen van Vuuren 	if (!option_len &&
7670a6e7778SPieter Jansen van Vuuren 	    (!tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS] ||
7680a6e7778SPieter Jansen van Vuuren 	     !tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE] ||
7690a6e7778SPieter Jansen van Vuuren 	     !tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA])) {
7700a6e7778SPieter Jansen van Vuuren 		NL_SET_ERR_MSG(extack, "Missing tunnel key geneve option class, type or data");
7710a6e7778SPieter Jansen van Vuuren 		return -EINVAL;
7720a6e7778SPieter Jansen van Vuuren 	}
7730a6e7778SPieter Jansen van Vuuren 
7740a6e7778SPieter Jansen van Vuuren 	/* Omitting any of CLASS, TYPE or DATA fields is allowed
7750a6e7778SPieter Jansen van Vuuren 	 * for the mask.
7760a6e7778SPieter Jansen van Vuuren 	 */
7770a6e7778SPieter Jansen van Vuuren 	if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA]) {
7780a6e7778SPieter Jansen van Vuuren 		int new_len = key->enc_opts.len;
7790a6e7778SPieter Jansen van Vuuren 
7800a6e7778SPieter Jansen van Vuuren 		data = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA];
7810a6e7778SPieter Jansen van Vuuren 		data_len = nla_len(data);
7820a6e7778SPieter Jansen van Vuuren 		if (data_len < 4) {
7830a6e7778SPieter Jansen van Vuuren 			NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is less than 4 bytes long");
7840a6e7778SPieter Jansen van Vuuren 			return -ERANGE;
7850a6e7778SPieter Jansen van Vuuren 		}
7860a6e7778SPieter Jansen van Vuuren 		if (data_len % 4) {
7870a6e7778SPieter Jansen van Vuuren 			NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is not a multiple of 4 bytes long");
7880a6e7778SPieter Jansen van Vuuren 			return -ERANGE;
7890a6e7778SPieter Jansen van Vuuren 		}
7900a6e7778SPieter Jansen van Vuuren 
7910a6e7778SPieter Jansen van Vuuren 		new_len += sizeof(struct geneve_opt) + data_len;
7920a6e7778SPieter Jansen van Vuuren 		BUILD_BUG_ON(FLOW_DIS_TUN_OPTS_MAX != IP_TUNNEL_OPTS_MAX);
7930a6e7778SPieter Jansen van Vuuren 		if (new_len > FLOW_DIS_TUN_OPTS_MAX) {
7940a6e7778SPieter Jansen van Vuuren 			NL_SET_ERR_MSG(extack, "Tunnel options exceeds max size");
7950a6e7778SPieter Jansen van Vuuren 			return -ERANGE;
7960a6e7778SPieter Jansen van Vuuren 		}
7970a6e7778SPieter Jansen van Vuuren 		opt->length = data_len / 4;
7980a6e7778SPieter Jansen van Vuuren 		memcpy(opt->opt_data, nla_data(data), data_len);
7990a6e7778SPieter Jansen van Vuuren 	}
8000a6e7778SPieter Jansen van Vuuren 
8010a6e7778SPieter Jansen van Vuuren 	if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS]) {
8020a6e7778SPieter Jansen van Vuuren 		class = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS];
8030a6e7778SPieter Jansen van Vuuren 		opt->opt_class = nla_get_be16(class);
8040a6e7778SPieter Jansen van Vuuren 	}
8050a6e7778SPieter Jansen van Vuuren 
8060a6e7778SPieter Jansen van Vuuren 	if (tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE]) {
8070a6e7778SPieter Jansen van Vuuren 		type = tb[TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE];
8080a6e7778SPieter Jansen van Vuuren 		opt->type = nla_get_u8(type);
8090a6e7778SPieter Jansen van Vuuren 	}
8100a6e7778SPieter Jansen van Vuuren 
8110a6e7778SPieter Jansen van Vuuren 	return sizeof(struct geneve_opt) + data_len;
8120a6e7778SPieter Jansen van Vuuren }
8130a6e7778SPieter Jansen van Vuuren 
8140a6e7778SPieter Jansen van Vuuren static int fl_set_enc_opt(struct nlattr **tb, struct fl_flow_key *key,
8150a6e7778SPieter Jansen van Vuuren 			  struct fl_flow_key *mask,
8160a6e7778SPieter Jansen van Vuuren 			  struct netlink_ext_ack *extack)
8170a6e7778SPieter Jansen van Vuuren {
8180a6e7778SPieter Jansen van Vuuren 	const struct nlattr *nla_enc_key, *nla_opt_key, *nla_opt_msk = NULL;
81963c82997SJakub Kicinski 	int err, option_len, key_depth, msk_depth = 0;
82063c82997SJakub Kicinski 
82163c82997SJakub Kicinski 	err = nla_validate_nested(tb[TCA_FLOWER_KEY_ENC_OPTS],
82263c82997SJakub Kicinski 				  TCA_FLOWER_KEY_ENC_OPTS_MAX,
82363c82997SJakub Kicinski 				  enc_opts_policy, extack);
82463c82997SJakub Kicinski 	if (err)
82563c82997SJakub Kicinski 		return err;
8260a6e7778SPieter Jansen van Vuuren 
8270a6e7778SPieter Jansen van Vuuren 	nla_enc_key = nla_data(tb[TCA_FLOWER_KEY_ENC_OPTS]);
8280a6e7778SPieter Jansen van Vuuren 
8290a6e7778SPieter Jansen van Vuuren 	if (tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]) {
83063c82997SJakub Kicinski 		err = nla_validate_nested(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK],
83163c82997SJakub Kicinski 					  TCA_FLOWER_KEY_ENC_OPTS_MAX,
83263c82997SJakub Kicinski 					  enc_opts_policy, extack);
83363c82997SJakub Kicinski 		if (err)
83463c82997SJakub Kicinski 			return err;
83563c82997SJakub Kicinski 
8360a6e7778SPieter Jansen van Vuuren 		nla_opt_msk = nla_data(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]);
8370a6e7778SPieter Jansen van Vuuren 		msk_depth = nla_len(tb[TCA_FLOWER_KEY_ENC_OPTS_MASK]);
8380a6e7778SPieter Jansen van Vuuren 	}
8390a6e7778SPieter Jansen van Vuuren 
8400a6e7778SPieter Jansen van Vuuren 	nla_for_each_attr(nla_opt_key, nla_enc_key,
8410a6e7778SPieter Jansen van Vuuren 			  nla_len(tb[TCA_FLOWER_KEY_ENC_OPTS]), key_depth) {
8420a6e7778SPieter Jansen van Vuuren 		switch (nla_type(nla_opt_key)) {
8430a6e7778SPieter Jansen van Vuuren 		case TCA_FLOWER_KEY_ENC_OPTS_GENEVE:
8440a6e7778SPieter Jansen van Vuuren 			option_len = 0;
8450a6e7778SPieter Jansen van Vuuren 			key->enc_opts.dst_opt_type = TUNNEL_GENEVE_OPT;
8460a6e7778SPieter Jansen van Vuuren 			option_len = fl_set_geneve_opt(nla_opt_key, key,
8470a6e7778SPieter Jansen van Vuuren 						       key_depth, option_len,
8480a6e7778SPieter Jansen van Vuuren 						       extack);
8490a6e7778SPieter Jansen van Vuuren 			if (option_len < 0)
8500a6e7778SPieter Jansen van Vuuren 				return option_len;
8510a6e7778SPieter Jansen van Vuuren 
8520a6e7778SPieter Jansen van Vuuren 			key->enc_opts.len += option_len;
8530a6e7778SPieter Jansen van Vuuren 			/* At the same time we need to parse through the mask
8540a6e7778SPieter Jansen van Vuuren 			 * in order to verify exact and mask attribute lengths.
8550a6e7778SPieter Jansen van Vuuren 			 */
8560a6e7778SPieter Jansen van Vuuren 			mask->enc_opts.dst_opt_type = TUNNEL_GENEVE_OPT;
8570a6e7778SPieter Jansen van Vuuren 			option_len = fl_set_geneve_opt(nla_opt_msk, mask,
8580a6e7778SPieter Jansen van Vuuren 						       msk_depth, option_len,
8590a6e7778SPieter Jansen van Vuuren 						       extack);
8600a6e7778SPieter Jansen van Vuuren 			if (option_len < 0)
8610a6e7778SPieter Jansen van Vuuren 				return option_len;
8620a6e7778SPieter Jansen van Vuuren 
8630a6e7778SPieter Jansen van Vuuren 			mask->enc_opts.len += option_len;
8640a6e7778SPieter Jansen van Vuuren 			if (key->enc_opts.len != mask->enc_opts.len) {
8650a6e7778SPieter Jansen van Vuuren 				NL_SET_ERR_MSG(extack, "Key and mask miss aligned");
8660a6e7778SPieter Jansen van Vuuren 				return -EINVAL;
8670a6e7778SPieter Jansen van Vuuren 			}
8680a6e7778SPieter Jansen van Vuuren 
8690a6e7778SPieter Jansen van Vuuren 			if (msk_depth)
8700a6e7778SPieter Jansen van Vuuren 				nla_opt_msk = nla_next(nla_opt_msk, &msk_depth);
8710a6e7778SPieter Jansen van Vuuren 			break;
8720a6e7778SPieter Jansen van Vuuren 		default:
8730a6e7778SPieter Jansen van Vuuren 			NL_SET_ERR_MSG(extack, "Unknown tunnel option type");
8740a6e7778SPieter Jansen van Vuuren 			return -EINVAL;
8750a6e7778SPieter Jansen van Vuuren 		}
8760a6e7778SPieter Jansen van Vuuren 	}
8770a6e7778SPieter Jansen van Vuuren 
8780a6e7778SPieter Jansen van Vuuren 	return 0;
8790a6e7778SPieter Jansen van Vuuren }
8800a6e7778SPieter Jansen van Vuuren 
88177b9900eSJiri Pirko static int fl_set_key(struct net *net, struct nlattr **tb,
8821057c55fSAlexander Aring 		      struct fl_flow_key *key, struct fl_flow_key *mask,
8831057c55fSAlexander Aring 		      struct netlink_ext_ack *extack)
88477b9900eSJiri Pirko {
8859399ae9aSHadar Hen Zion 	__be16 ethertype;
886d9724772SOr Gerlitz 	int ret = 0;
887dd3aa3b5SBrian Haley #ifdef CONFIG_NET_CLS_IND
88877b9900eSJiri Pirko 	if (tb[TCA_FLOWER_INDEV]) {
8891057c55fSAlexander Aring 		int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV], extack);
89077b9900eSJiri Pirko 		if (err < 0)
89177b9900eSJiri Pirko 			return err;
89277b9900eSJiri Pirko 		key->indev_ifindex = err;
89377b9900eSJiri Pirko 		mask->indev_ifindex = 0xffffffff;
89477b9900eSJiri Pirko 	}
895dd3aa3b5SBrian Haley #endif
89677b9900eSJiri Pirko 
89777b9900eSJiri Pirko 	fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
89877b9900eSJiri Pirko 		       mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
89977b9900eSJiri Pirko 		       sizeof(key->eth.dst));
90077b9900eSJiri Pirko 	fl_set_key_val(tb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
90177b9900eSJiri Pirko 		       mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
90277b9900eSJiri Pirko 		       sizeof(key->eth.src));
90366530bdfSJamal Hadi Salim 
9040b498a52SArnd Bergmann 	if (tb[TCA_FLOWER_KEY_ETH_TYPE]) {
9059399ae9aSHadar Hen Zion 		ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_ETH_TYPE]);
9069399ae9aSHadar Hen Zion 
907aaab0834SJianbo Liu 		if (eth_type_vlan(ethertype)) {
908d64efd09SJianbo Liu 			fl_set_key_vlan(tb, ethertype, TCA_FLOWER_KEY_VLAN_ID,
909d64efd09SJianbo Liu 					TCA_FLOWER_KEY_VLAN_PRIO, &key->vlan,
910d64efd09SJianbo Liu 					&mask->vlan);
911d64efd09SJianbo Liu 
9125e9a0fe4SJianbo Liu 			if (tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]) {
913d64efd09SJianbo Liu 				ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]);
914d64efd09SJianbo Liu 				if (eth_type_vlan(ethertype)) {
915d64efd09SJianbo Liu 					fl_set_key_vlan(tb, ethertype,
916d64efd09SJianbo Liu 							TCA_FLOWER_KEY_CVLAN_ID,
917d64efd09SJianbo Liu 							TCA_FLOWER_KEY_CVLAN_PRIO,
918d64efd09SJianbo Liu 							&key->cvlan, &mask->cvlan);
9199399ae9aSHadar Hen Zion 					fl_set_key_val(tb, &key->basic.n_proto,
920d64efd09SJianbo Liu 						       TCA_FLOWER_KEY_CVLAN_ETH_TYPE,
921d64efd09SJianbo Liu 						       &mask->basic.n_proto,
922d64efd09SJianbo Liu 						       TCA_FLOWER_UNSPEC,
92377b9900eSJiri Pirko 						       sizeof(key->basic.n_proto));
9249399ae9aSHadar Hen Zion 				} else {
9259399ae9aSHadar Hen Zion 					key->basic.n_proto = ethertype;
9269399ae9aSHadar Hen Zion 					mask->basic.n_proto = cpu_to_be16(~0);
9279399ae9aSHadar Hen Zion 				}
9285e9a0fe4SJianbo Liu 			}
929d64efd09SJianbo Liu 		} else {
930d64efd09SJianbo Liu 			key->basic.n_proto = ethertype;
931d64efd09SJianbo Liu 			mask->basic.n_proto = cpu_to_be16(~0);
932d64efd09SJianbo Liu 		}
9330b498a52SArnd Bergmann 	}
93466530bdfSJamal Hadi Salim 
93577b9900eSJiri Pirko 	if (key->basic.n_proto == htons(ETH_P_IP) ||
93677b9900eSJiri Pirko 	    key->basic.n_proto == htons(ETH_P_IPV6)) {
93777b9900eSJiri Pirko 		fl_set_key_val(tb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
93877b9900eSJiri Pirko 			       &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
93977b9900eSJiri Pirko 			       sizeof(key->basic.ip_proto));
9400e2c17b6SOr Gerlitz 		fl_set_key_ip(tb, false, &key->ip, &mask->ip);
94177b9900eSJiri Pirko 	}
94266530bdfSJamal Hadi Salim 
94366530bdfSJamal Hadi Salim 	if (tb[TCA_FLOWER_KEY_IPV4_SRC] || tb[TCA_FLOWER_KEY_IPV4_DST]) {
94466530bdfSJamal Hadi Salim 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
945970bfcd0SPaul Blakey 		mask->control.addr_type = ~0;
94677b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
94777b9900eSJiri Pirko 			       &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
94877b9900eSJiri Pirko 			       sizeof(key->ipv4.src));
94977b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
95077b9900eSJiri Pirko 			       &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
95177b9900eSJiri Pirko 			       sizeof(key->ipv4.dst));
95266530bdfSJamal Hadi Salim 	} else if (tb[TCA_FLOWER_KEY_IPV6_SRC] || tb[TCA_FLOWER_KEY_IPV6_DST]) {
95366530bdfSJamal Hadi Salim 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
954970bfcd0SPaul Blakey 		mask->control.addr_type = ~0;
95577b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
95677b9900eSJiri Pirko 			       &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
95777b9900eSJiri Pirko 			       sizeof(key->ipv6.src));
95877b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
95977b9900eSJiri Pirko 			       &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
96077b9900eSJiri Pirko 			       sizeof(key->ipv6.dst));
96177b9900eSJiri Pirko 	}
96266530bdfSJamal Hadi Salim 
96377b9900eSJiri Pirko 	if (key->basic.ip_proto == IPPROTO_TCP) {
96477b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
965aa72d708SOr Gerlitz 			       &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
96677b9900eSJiri Pirko 			       sizeof(key->tp.src));
96777b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
968aa72d708SOr Gerlitz 			       &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
96977b9900eSJiri Pirko 			       sizeof(key->tp.dst));
970fdfc7dd6SJiri Pirko 		fl_set_key_val(tb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS,
971fdfc7dd6SJiri Pirko 			       &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK,
972fdfc7dd6SJiri Pirko 			       sizeof(key->tcp.flags));
97377b9900eSJiri Pirko 	} else if (key->basic.ip_proto == IPPROTO_UDP) {
97477b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
975aa72d708SOr Gerlitz 			       &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
97677b9900eSJiri Pirko 			       sizeof(key->tp.src));
97777b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
978aa72d708SOr Gerlitz 			       &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
97977b9900eSJiri Pirko 			       sizeof(key->tp.dst));
9805976c5f4SSimon Horman 	} else if (key->basic.ip_proto == IPPROTO_SCTP) {
9815976c5f4SSimon Horman 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
9825976c5f4SSimon Horman 			       &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
9835976c5f4SSimon Horman 			       sizeof(key->tp.src));
9845976c5f4SSimon Horman 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
9855976c5f4SSimon Horman 			       &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
9865976c5f4SSimon Horman 			       sizeof(key->tp.dst));
9877b684884SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_IP) &&
9887b684884SSimon Horman 		   key->basic.ip_proto == IPPROTO_ICMP) {
9897b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV4_TYPE,
9907b684884SSimon Horman 			       &mask->icmp.type,
9917b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,
9927b684884SSimon Horman 			       sizeof(key->icmp.type));
9937b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE,
9947b684884SSimon Horman 			       &mask->icmp.code,
9957b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
9967b684884SSimon Horman 			       sizeof(key->icmp.code));
9977b684884SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_IPV6) &&
9987b684884SSimon Horman 		   key->basic.ip_proto == IPPROTO_ICMPV6) {
9997b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV6_TYPE,
10007b684884SSimon Horman 			       &mask->icmp.type,
10017b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
10027b684884SSimon Horman 			       sizeof(key->icmp.type));
1003040587afSSimon Horman 		fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV6_CODE,
10047b684884SSimon Horman 			       &mask->icmp.code,
1005040587afSSimon Horman 			       TCA_FLOWER_KEY_ICMPV6_CODE_MASK,
10067b684884SSimon Horman 			       sizeof(key->icmp.code));
1007a577d8f7SBenjamin LaHaise 	} else if (key->basic.n_proto == htons(ETH_P_MPLS_UC) ||
1008a577d8f7SBenjamin LaHaise 		   key->basic.n_proto == htons(ETH_P_MPLS_MC)) {
10091a7fca63SBenjamin LaHaise 		ret = fl_set_key_mpls(tb, &key->mpls, &mask->mpls);
10101a7fca63SBenjamin LaHaise 		if (ret)
10111a7fca63SBenjamin LaHaise 			return ret;
101299d31326SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_ARP) ||
101399d31326SSimon Horman 		   key->basic.n_proto == htons(ETH_P_RARP)) {
101499d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.sip, TCA_FLOWER_KEY_ARP_SIP,
101599d31326SSimon Horman 			       &mask->arp.sip, TCA_FLOWER_KEY_ARP_SIP_MASK,
101699d31326SSimon Horman 			       sizeof(key->arp.sip));
101799d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.tip, TCA_FLOWER_KEY_ARP_TIP,
101899d31326SSimon Horman 			       &mask->arp.tip, TCA_FLOWER_KEY_ARP_TIP_MASK,
101999d31326SSimon Horman 			       sizeof(key->arp.tip));
102099d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.op, TCA_FLOWER_KEY_ARP_OP,
102199d31326SSimon Horman 			       &mask->arp.op, TCA_FLOWER_KEY_ARP_OP_MASK,
102299d31326SSimon Horman 			       sizeof(key->arp.op));
102399d31326SSimon Horman 		fl_set_key_val(tb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA,
102499d31326SSimon Horman 			       mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK,
102599d31326SSimon Horman 			       sizeof(key->arp.sha));
102699d31326SSimon Horman 		fl_set_key_val(tb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA,
102799d31326SSimon Horman 			       mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK,
102899d31326SSimon Horman 			       sizeof(key->arp.tha));
102977b9900eSJiri Pirko 	}
103077b9900eSJiri Pirko 
10315c72299fSAmritha Nambiar 	if (key->basic.ip_proto == IPPROTO_TCP ||
10325c72299fSAmritha Nambiar 	    key->basic.ip_proto == IPPROTO_UDP ||
10335c72299fSAmritha Nambiar 	    key->basic.ip_proto == IPPROTO_SCTP) {
10345c72299fSAmritha Nambiar 		ret = fl_set_key_port_range(tb, key, mask);
10355c72299fSAmritha Nambiar 		if (ret)
10365c72299fSAmritha Nambiar 			return ret;
10375c72299fSAmritha Nambiar 	}
10385c72299fSAmritha Nambiar 
1039bc3103f1SAmir Vadai 	if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] ||
1040bc3103f1SAmir Vadai 	    tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) {
1041bc3103f1SAmir Vadai 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
1042970bfcd0SPaul Blakey 		mask->enc_control.addr_type = ~0;
1043bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv4.src,
1044bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_SRC,
1045bc3103f1SAmir Vadai 			       &mask->enc_ipv4.src,
1046bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
1047bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv4.src));
1048bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv4.dst,
1049bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_DST,
1050bc3103f1SAmir Vadai 			       &mask->enc_ipv4.dst,
1051bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
1052bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv4.dst));
1053bc3103f1SAmir Vadai 	}
1054bc3103f1SAmir Vadai 
1055bc3103f1SAmir Vadai 	if (tb[TCA_FLOWER_KEY_ENC_IPV6_SRC] ||
1056bc3103f1SAmir Vadai 	    tb[TCA_FLOWER_KEY_ENC_IPV6_DST]) {
1057bc3103f1SAmir Vadai 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
1058970bfcd0SPaul Blakey 		mask->enc_control.addr_type = ~0;
1059bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv6.src,
1060bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_SRC,
1061bc3103f1SAmir Vadai 			       &mask->enc_ipv6.src,
1062bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
1063bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv6.src));
1064bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv6.dst,
1065bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_DST,
1066bc3103f1SAmir Vadai 			       &mask->enc_ipv6.dst,
1067bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
1068bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv6.dst));
1069bc3103f1SAmir Vadai 	}
1070bc3103f1SAmir Vadai 
1071bc3103f1SAmir Vadai 	fl_set_key_val(tb, &key->enc_key_id.keyid, TCA_FLOWER_KEY_ENC_KEY_ID,
1072eb523f42SHadar Hen Zion 		       &mask->enc_key_id.keyid, TCA_FLOWER_UNSPEC,
1073bc3103f1SAmir Vadai 		       sizeof(key->enc_key_id.keyid));
1074bc3103f1SAmir Vadai 
1075f4d997fdSHadar Hen Zion 	fl_set_key_val(tb, &key->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
1076f4d997fdSHadar Hen Zion 		       &mask->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
1077f4d997fdSHadar Hen Zion 		       sizeof(key->enc_tp.src));
1078f4d997fdSHadar Hen Zion 
1079f4d997fdSHadar Hen Zion 	fl_set_key_val(tb, &key->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
1080f4d997fdSHadar Hen Zion 		       &mask->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
1081f4d997fdSHadar Hen Zion 		       sizeof(key->enc_tp.dst));
1082f4d997fdSHadar Hen Zion 
10830e2c17b6SOr Gerlitz 	fl_set_key_ip(tb, true, &key->enc_ip, &mask->enc_ip);
10840e2c17b6SOr Gerlitz 
10850a6e7778SPieter Jansen van Vuuren 	if (tb[TCA_FLOWER_KEY_ENC_OPTS]) {
10860a6e7778SPieter Jansen van Vuuren 		ret = fl_set_enc_opt(tb, key, mask, extack);
10870a6e7778SPieter Jansen van Vuuren 		if (ret)
10880a6e7778SPieter Jansen van Vuuren 			return ret;
10890a6e7778SPieter Jansen van Vuuren 	}
10900a6e7778SPieter Jansen van Vuuren 
1091d9724772SOr Gerlitz 	if (tb[TCA_FLOWER_KEY_FLAGS])
1092d9724772SOr Gerlitz 		ret = fl_set_key_flags(tb, &key->control.flags, &mask->control.flags);
1093faa3ffceSOr Gerlitz 
1094d9724772SOr Gerlitz 	return ret;
109577b9900eSJiri Pirko }
109677b9900eSJiri Pirko 
109705cd271fSPaul Blakey static void fl_mask_copy(struct fl_flow_mask *dst,
109805cd271fSPaul Blakey 			 struct fl_flow_mask *src)
109977b9900eSJiri Pirko {
110005cd271fSPaul Blakey 	const void *psrc = fl_key_get_start(&src->key, src);
110105cd271fSPaul Blakey 	void *pdst = fl_key_get_start(&dst->key, src);
110277b9900eSJiri Pirko 
110305cd271fSPaul Blakey 	memcpy(pdst, psrc, fl_mask_range(src));
110405cd271fSPaul Blakey 	dst->range = src->range;
110577b9900eSJiri Pirko }
110677b9900eSJiri Pirko 
110777b9900eSJiri Pirko static const struct rhashtable_params fl_ht_params = {
110877b9900eSJiri Pirko 	.key_offset = offsetof(struct cls_fl_filter, mkey), /* base offset */
110977b9900eSJiri Pirko 	.head_offset = offsetof(struct cls_fl_filter, ht_node),
111077b9900eSJiri Pirko 	.automatic_shrinking = true,
111177b9900eSJiri Pirko };
111277b9900eSJiri Pirko 
111305cd271fSPaul Blakey static int fl_init_mask_hashtable(struct fl_flow_mask *mask)
111477b9900eSJiri Pirko {
111505cd271fSPaul Blakey 	mask->filter_ht_params = fl_ht_params;
111605cd271fSPaul Blakey 	mask->filter_ht_params.key_len = fl_mask_range(mask);
111705cd271fSPaul Blakey 	mask->filter_ht_params.key_offset += mask->range.start;
111877b9900eSJiri Pirko 
111905cd271fSPaul Blakey 	return rhashtable_init(&mask->ht, &mask->filter_ht_params);
112077b9900eSJiri Pirko }
112177b9900eSJiri Pirko 
112277b9900eSJiri Pirko #define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member)
1123cb205a81Szhong jiang #define FL_KEY_MEMBER_SIZE(member) FIELD_SIZEOF(struct fl_flow_key, member)
112477b9900eSJiri Pirko 
1125339ba878SHadar Hen Zion #define FL_KEY_IS_MASKED(mask, member)						\
1126339ba878SHadar Hen Zion 	memchr_inv(((char *)mask) + FL_KEY_MEMBER_OFFSET(member),		\
1127339ba878SHadar Hen Zion 		   0, FL_KEY_MEMBER_SIZE(member))				\
112877b9900eSJiri Pirko 
112977b9900eSJiri Pirko #define FL_KEY_SET(keys, cnt, id, member)					\
113077b9900eSJiri Pirko 	do {									\
113177b9900eSJiri Pirko 		keys[cnt].key_id = id;						\
113277b9900eSJiri Pirko 		keys[cnt].offset = FL_KEY_MEMBER_OFFSET(member);		\
113377b9900eSJiri Pirko 		cnt++;								\
113477b9900eSJiri Pirko 	} while(0);
113577b9900eSJiri Pirko 
1136339ba878SHadar Hen Zion #define FL_KEY_SET_IF_MASKED(mask, keys, cnt, id, member)			\
113777b9900eSJiri Pirko 	do {									\
1138339ba878SHadar Hen Zion 		if (FL_KEY_IS_MASKED(mask, member))				\
113977b9900eSJiri Pirko 			FL_KEY_SET(keys, cnt, id, member);			\
114077b9900eSJiri Pirko 	} while(0);
114177b9900eSJiri Pirko 
114233fb5cbaSJiri Pirko static void fl_init_dissector(struct flow_dissector *dissector,
114333fb5cbaSJiri Pirko 			      struct fl_flow_key *mask)
114477b9900eSJiri Pirko {
114577b9900eSJiri Pirko 	struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX];
114677b9900eSJiri Pirko 	size_t cnt = 0;
114777b9900eSJiri Pirko 
114842aecaa9STom Herbert 	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control);
114977b9900eSJiri Pirko 	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic);
115033fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
115177b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_ETH_ADDRS, eth);
115233fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
115377b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4);
115433fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
115577b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6);
11565c72299fSAmritha Nambiar 	if (FL_KEY_IS_MASKED(mask, tp) ||
11575c72299fSAmritha Nambiar 	    FL_KEY_IS_MASKED(mask, tp_min) || FL_KEY_IS_MASKED(mask, tp_max))
11585c72299fSAmritha Nambiar 		FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_PORTS, tp);
115933fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
11604d80cc0aSOr Gerlitz 			     FLOW_DISSECTOR_KEY_IP, ip);
116133fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
1162fdfc7dd6SJiri Pirko 			     FLOW_DISSECTOR_KEY_TCP, tcp);
116333fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
11647b684884SSimon Horman 			     FLOW_DISSECTOR_KEY_ICMP, icmp);
116533fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
116699d31326SSimon Horman 			     FLOW_DISSECTOR_KEY_ARP, arp);
116733fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
1168a577d8f7SBenjamin LaHaise 			     FLOW_DISSECTOR_KEY_MPLS, mpls);
116933fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
11709399ae9aSHadar Hen Zion 			     FLOW_DISSECTOR_KEY_VLAN, vlan);
117133fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
1172d64efd09SJianbo Liu 			     FLOW_DISSECTOR_KEY_CVLAN, cvlan);
117333fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
1174519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_KEYID, enc_key_id);
117533fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
1176519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, enc_ipv4);
117733fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
1178519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, enc_ipv6);
117933fb5cbaSJiri Pirko 	if (FL_KEY_IS_MASKED(mask, enc_ipv4) ||
118033fb5cbaSJiri Pirko 	    FL_KEY_IS_MASKED(mask, enc_ipv6))
1181519d1052SHadar Hen Zion 		FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_ENC_CONTROL,
1182519d1052SHadar Hen Zion 			   enc_control);
118333fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
1184f4d997fdSHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp);
118533fb5cbaSJiri Pirko 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
11860e2c17b6SOr Gerlitz 			     FLOW_DISSECTOR_KEY_ENC_IP, enc_ip);
11870a6e7778SPieter Jansen van Vuuren 	FL_KEY_SET_IF_MASKED(mask, keys, cnt,
11880a6e7778SPieter Jansen van Vuuren 			     FLOW_DISSECTOR_KEY_ENC_OPTS, enc_opts);
118977b9900eSJiri Pirko 
119033fb5cbaSJiri Pirko 	skb_flow_dissector_init(dissector, keys, cnt);
119105cd271fSPaul Blakey }
119205cd271fSPaul Blakey 
119305cd271fSPaul Blakey static struct fl_flow_mask *fl_create_new_mask(struct cls_fl_head *head,
119405cd271fSPaul Blakey 					       struct fl_flow_mask *mask)
119505cd271fSPaul Blakey {
119605cd271fSPaul Blakey 	struct fl_flow_mask *newmask;
119705cd271fSPaul Blakey 	int err;
119805cd271fSPaul Blakey 
119905cd271fSPaul Blakey 	newmask = kzalloc(sizeof(*newmask), GFP_KERNEL);
120005cd271fSPaul Blakey 	if (!newmask)
120105cd271fSPaul Blakey 		return ERR_PTR(-ENOMEM);
120205cd271fSPaul Blakey 
120305cd271fSPaul Blakey 	fl_mask_copy(newmask, mask);
120405cd271fSPaul Blakey 
12055c72299fSAmritha Nambiar 	if ((newmask->key.tp_min.dst && newmask->key.tp_max.dst) ||
12065c72299fSAmritha Nambiar 	    (newmask->key.tp_min.src && newmask->key.tp_max.src))
12075c72299fSAmritha Nambiar 		newmask->flags |= TCA_FLOWER_MASK_FLAGS_RANGE;
12085c72299fSAmritha Nambiar 
120905cd271fSPaul Blakey 	err = fl_init_mask_hashtable(newmask);
121005cd271fSPaul Blakey 	if (err)
121105cd271fSPaul Blakey 		goto errout_free;
121205cd271fSPaul Blakey 
121333fb5cbaSJiri Pirko 	fl_init_dissector(&newmask->dissector, &newmask->key);
121405cd271fSPaul Blakey 
121505cd271fSPaul Blakey 	INIT_LIST_HEAD_RCU(&newmask->filters);
121605cd271fSPaul Blakey 
121705cd271fSPaul Blakey 	err = rhashtable_insert_fast(&head->ht, &newmask->ht_node,
121805cd271fSPaul Blakey 				     mask_ht_params);
121905cd271fSPaul Blakey 	if (err)
122005cd271fSPaul Blakey 		goto errout_destroy;
122105cd271fSPaul Blakey 
122205cd271fSPaul Blakey 	list_add_tail_rcu(&newmask->list, &head->masks);
122305cd271fSPaul Blakey 
122405cd271fSPaul Blakey 	return newmask;
122505cd271fSPaul Blakey 
122605cd271fSPaul Blakey errout_destroy:
122705cd271fSPaul Blakey 	rhashtable_destroy(&newmask->ht);
122805cd271fSPaul Blakey errout_free:
122905cd271fSPaul Blakey 	kfree(newmask);
123005cd271fSPaul Blakey 
123105cd271fSPaul Blakey 	return ERR_PTR(err);
123277b9900eSJiri Pirko }
123377b9900eSJiri Pirko 
123477b9900eSJiri Pirko static int fl_check_assign_mask(struct cls_fl_head *head,
123505cd271fSPaul Blakey 				struct cls_fl_filter *fnew,
123605cd271fSPaul Blakey 				struct cls_fl_filter *fold,
123777b9900eSJiri Pirko 				struct fl_flow_mask *mask)
123877b9900eSJiri Pirko {
123905cd271fSPaul Blakey 	struct fl_flow_mask *newmask;
124077b9900eSJiri Pirko 
124105cd271fSPaul Blakey 	fnew->mask = rhashtable_lookup_fast(&head->ht, mask, mask_ht_params);
124205cd271fSPaul Blakey 	if (!fnew->mask) {
124305cd271fSPaul Blakey 		if (fold)
124477b9900eSJiri Pirko 			return -EINVAL;
124505cd271fSPaul Blakey 
124605cd271fSPaul Blakey 		newmask = fl_create_new_mask(head, mask);
124705cd271fSPaul Blakey 		if (IS_ERR(newmask))
124805cd271fSPaul Blakey 			return PTR_ERR(newmask);
124905cd271fSPaul Blakey 
125005cd271fSPaul Blakey 		fnew->mask = newmask;
1251f6521c58SPaul Blakey 	} else if (fold && fold->mask != fnew->mask) {
125205cd271fSPaul Blakey 		return -EINVAL;
125377b9900eSJiri Pirko 	}
125477b9900eSJiri Pirko 
125577b9900eSJiri Pirko 	return 0;
125677b9900eSJiri Pirko }
125777b9900eSJiri Pirko 
125877b9900eSJiri Pirko static int fl_set_parms(struct net *net, struct tcf_proto *tp,
125977b9900eSJiri Pirko 			struct cls_fl_filter *f, struct fl_flow_mask *mask,
126077b9900eSJiri Pirko 			unsigned long base, struct nlattr **tb,
126150a56190SAlexander Aring 			struct nlattr *est, bool ovr,
1262b95ec7ebSJiri Pirko 			struct fl_flow_tmplt *tmplt,
126350a56190SAlexander Aring 			struct netlink_ext_ack *extack)
126477b9900eSJiri Pirko {
126577b9900eSJiri Pirko 	int err;
126677b9900eSJiri Pirko 
126750a56190SAlexander Aring 	err = tcf_exts_validate(net, tp, tb, est, &f->exts, ovr, extack);
126877b9900eSJiri Pirko 	if (err < 0)
126977b9900eSJiri Pirko 		return err;
127077b9900eSJiri Pirko 
127177b9900eSJiri Pirko 	if (tb[TCA_FLOWER_CLASSID]) {
127277b9900eSJiri Pirko 		f->res.classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]);
127377b9900eSJiri Pirko 		tcf_bind_filter(tp, &f->res, base);
127477b9900eSJiri Pirko 	}
127577b9900eSJiri Pirko 
12761057c55fSAlexander Aring 	err = fl_set_key(net, tb, &f->key, &mask->key, extack);
127777b9900eSJiri Pirko 	if (err)
127845507529SJiri Pirko 		return err;
127977b9900eSJiri Pirko 
128077b9900eSJiri Pirko 	fl_mask_update_range(mask);
128177b9900eSJiri Pirko 	fl_set_masked_key(&f->mkey, &f->key, mask);
128277b9900eSJiri Pirko 
1283b95ec7ebSJiri Pirko 	if (!fl_mask_fits_tmplt(tmplt, mask)) {
1284b95ec7ebSJiri Pirko 		NL_SET_ERR_MSG_MOD(extack, "Mask does not fit the template");
1285b95ec7ebSJiri Pirko 		return -EINVAL;
1286b95ec7ebSJiri Pirko 	}
1287b95ec7ebSJiri Pirko 
128877b9900eSJiri Pirko 	return 0;
128977b9900eSJiri Pirko }
129077b9900eSJiri Pirko 
129177b9900eSJiri Pirko static int fl_change(struct net *net, struct sk_buff *in_skb,
129277b9900eSJiri Pirko 		     struct tcf_proto *tp, unsigned long base,
129377b9900eSJiri Pirko 		     u32 handle, struct nlattr **tca,
12947306db38SAlexander Aring 		     void **arg, bool ovr, struct netlink_ext_ack *extack)
129577b9900eSJiri Pirko {
129677b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
12978113c095SWANG Cong 	struct cls_fl_filter *fold = *arg;
129877b9900eSJiri Pirko 	struct cls_fl_filter *fnew;
12992cddd201SIvan Vecera 	struct fl_flow_mask *mask;
130039b7b6a6SArnd Bergmann 	struct nlattr **tb;
130177b9900eSJiri Pirko 	int err;
130277b9900eSJiri Pirko 
130377b9900eSJiri Pirko 	if (!tca[TCA_OPTIONS])
130477b9900eSJiri Pirko 		return -EINVAL;
130577b9900eSJiri Pirko 
13062cddd201SIvan Vecera 	mask = kzalloc(sizeof(struct fl_flow_mask), GFP_KERNEL);
13072cddd201SIvan Vecera 	if (!mask)
130839b7b6a6SArnd Bergmann 		return -ENOBUFS;
130939b7b6a6SArnd Bergmann 
13102cddd201SIvan Vecera 	tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL);
13112cddd201SIvan Vecera 	if (!tb) {
13122cddd201SIvan Vecera 		err = -ENOBUFS;
13132cddd201SIvan Vecera 		goto errout_mask_alloc;
13142cddd201SIvan Vecera 	}
13152cddd201SIvan Vecera 
1316fceb6435SJohannes Berg 	err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS],
1317fceb6435SJohannes Berg 			       fl_policy, NULL);
131877b9900eSJiri Pirko 	if (err < 0)
131939b7b6a6SArnd Bergmann 		goto errout_tb;
132077b9900eSJiri Pirko 
132139b7b6a6SArnd Bergmann 	if (fold && handle && fold->handle != handle) {
132239b7b6a6SArnd Bergmann 		err = -EINVAL;
132339b7b6a6SArnd Bergmann 		goto errout_tb;
132439b7b6a6SArnd Bergmann 	}
132577b9900eSJiri Pirko 
132677b9900eSJiri Pirko 	fnew = kzalloc(sizeof(*fnew), GFP_KERNEL);
132739b7b6a6SArnd Bergmann 	if (!fnew) {
132839b7b6a6SArnd Bergmann 		err = -ENOBUFS;
132939b7b6a6SArnd Bergmann 		goto errout_tb;
133039b7b6a6SArnd Bergmann 	}
133177b9900eSJiri Pirko 
1332b9a24bb7SWANG Cong 	err = tcf_exts_init(&fnew->exts, TCA_FLOWER_ACT, 0);
1333b9a24bb7SWANG Cong 	if (err < 0)
1334b9a24bb7SWANG Cong 		goto errout;
133577b9900eSJiri Pirko 
133677b9900eSJiri Pirko 	if (!handle) {
133785bd0438SMatthew Wilcox 		handle = 1;
133885bd0438SMatthew Wilcox 		err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
133985bd0438SMatthew Wilcox 				    INT_MAX, GFP_KERNEL);
134085bd0438SMatthew Wilcox 	} else if (!fold) {
1341c15ab236SChris Mi 		/* user specifies a handle and it doesn't exist */
134285bd0438SMatthew Wilcox 		err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
134385bd0438SMatthew Wilcox 				    handle, GFP_KERNEL);
134485bd0438SMatthew Wilcox 	}
1345c15ab236SChris Mi 	if (err)
1346c15ab236SChris Mi 		goto errout;
134785bd0438SMatthew Wilcox 	fnew->handle = handle;
134877b9900eSJiri Pirko 
1349e69985c6SAmir Vadai 	if (tb[TCA_FLOWER_FLAGS]) {
1350e69985c6SAmir Vadai 		fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
1351e69985c6SAmir Vadai 
1352e69985c6SAmir Vadai 		if (!tc_flags_valid(fnew->flags)) {
1353e69985c6SAmir Vadai 			err = -EINVAL;
1354fe2502e4SCong Wang 			goto errout_idr;
1355e69985c6SAmir Vadai 		}
1356e69985c6SAmir Vadai 	}
13575b33f488SAmir Vadai 
13582cddd201SIvan Vecera 	err = fl_set_parms(net, tp, fnew, mask, base, tb, tca[TCA_RATE], ovr,
1359b95ec7ebSJiri Pirko 			   tp->chain->tmplt_priv, extack);
136077b9900eSJiri Pirko 	if (err)
1361fe2502e4SCong Wang 		goto errout_idr;
136277b9900eSJiri Pirko 
13632cddd201SIvan Vecera 	err = fl_check_assign_mask(head, fnew, fold, mask);
136477b9900eSJiri Pirko 	if (err)
1365fe2502e4SCong Wang 		goto errout_idr;
136677b9900eSJiri Pirko 
13675c72299fSAmritha Nambiar 	if (!fold && __fl_lookup(fnew->mask, &fnew->mkey)) {
1368a3308d8fSPaul Blakey 		err = -EEXIST;
136905cd271fSPaul Blakey 		goto errout_mask;
1370a3308d8fSPaul Blakey 	}
1371a3308d8fSPaul Blakey 
137205cd271fSPaul Blakey 	err = rhashtable_insert_fast(&fnew->mask->ht, &fnew->ht_node,
137305cd271fSPaul Blakey 				     fnew->mask->filter_ht_params);
137477b9900eSJiri Pirko 	if (err)
137505cd271fSPaul Blakey 		goto errout_mask;
13765b33f488SAmir Vadai 
137779685219SHadar Hen Zion 	if (!tc_skip_hw(fnew->flags)) {
137805cd271fSPaul Blakey 		err = fl_hw_replace_filter(tp, fnew, extack);
1379e8eb36cdSAmir Vadai 		if (err)
138005cd271fSPaul Blakey 			goto errout_mask;
138179685219SHadar Hen Zion 	}
13825b33f488SAmir Vadai 
138355593960SOr Gerlitz 	if (!tc_in_hw(fnew->flags))
138455593960SOr Gerlitz 		fnew->flags |= TCA_CLS_FLAGS_NOT_IN_HW;
138555593960SOr Gerlitz 
13865b33f488SAmir Vadai 	if (fold) {
138705cd271fSPaul Blakey 		rhashtable_remove_fast(&fold->mask->ht,
138805cd271fSPaul Blakey 				       &fold->ht_node,
138905cd271fSPaul Blakey 				       fold->mask->filter_ht_params);
139079685219SHadar Hen Zion 		if (!tc_skip_hw(fold->flags))
13911b0f8037SJakub Kicinski 			fl_hw_destroy_filter(tp, fold, NULL);
13925b33f488SAmir Vadai 	}
139377b9900eSJiri Pirko 
13948113c095SWANG Cong 	*arg = fnew;
139577b9900eSJiri Pirko 
139677b9900eSJiri Pirko 	if (fold) {
1397234a4624SMatthew Wilcox 		idr_replace(&head->handle_idr, fnew, fnew->handle);
1398ff3532f2SDaniel Borkmann 		list_replace_rcu(&fold->list, &fnew->list);
139977b9900eSJiri Pirko 		tcf_unbind_filter(tp, &fold->res);
14000dadc117SCong Wang 		tcf_exts_get_net(&fold->exts);
1401aaa908ffSCong Wang 		tcf_queue_work(&fold->rwork, fl_destroy_filter_work);
140277b9900eSJiri Pirko 	} else {
140305cd271fSPaul Blakey 		list_add_tail_rcu(&fnew->list, &fnew->mask->filters);
140477b9900eSJiri Pirko 	}
140577b9900eSJiri Pirko 
140639b7b6a6SArnd Bergmann 	kfree(tb);
14072cddd201SIvan Vecera 	kfree(mask);
140877b9900eSJiri Pirko 	return 0;
140977b9900eSJiri Pirko 
141005cd271fSPaul Blakey errout_mask:
141105cd271fSPaul Blakey 	fl_mask_put(head, fnew->mask, false);
141205cd271fSPaul Blakey 
1413fe2502e4SCong Wang errout_idr:
14148258d2daSPaul Blakey 	if (!fold)
14159c160941SMatthew Wilcox 		idr_remove(&head->handle_idr, fnew->handle);
141677b9900eSJiri Pirko errout:
1417b9a24bb7SWANG Cong 	tcf_exts_destroy(&fnew->exts);
141877b9900eSJiri Pirko 	kfree(fnew);
141939b7b6a6SArnd Bergmann errout_tb:
142039b7b6a6SArnd Bergmann 	kfree(tb);
14212cddd201SIvan Vecera errout_mask_alloc:
14222cddd201SIvan Vecera 	kfree(mask);
142377b9900eSJiri Pirko 	return err;
142477b9900eSJiri Pirko }
142577b9900eSJiri Pirko 
1426571acf21SAlexander Aring static int fl_delete(struct tcf_proto *tp, void *arg, bool *last,
1427571acf21SAlexander Aring 		     struct netlink_ext_ack *extack)
142877b9900eSJiri Pirko {
142977b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
14308113c095SWANG Cong 	struct cls_fl_filter *f = arg;
143177b9900eSJiri Pirko 
143205cd271fSPaul Blakey 	rhashtable_remove_fast(&f->mask->ht, &f->ht_node,
143305cd271fSPaul Blakey 			       f->mask->filter_ht_params);
14341b0f8037SJakub Kicinski 	__fl_delete(tp, f, extack);
143505cd271fSPaul Blakey 	*last = list_empty(&head->masks);
143677b9900eSJiri Pirko 	return 0;
143777b9900eSJiri Pirko }
143877b9900eSJiri Pirko 
143977b9900eSJiri Pirko static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg)
144077b9900eSJiri Pirko {
144177b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
144277b9900eSJiri Pirko 	struct cls_fl_filter *f;
144377b9900eSJiri Pirko 
144401683a14SVlad Buslov 	arg->count = arg->skip;
144501683a14SVlad Buslov 
144601683a14SVlad Buslov 	while ((f = idr_get_next_ul(&head->handle_idr,
144701683a14SVlad Buslov 				    &arg->cookie)) != NULL) {
14488113c095SWANG Cong 		if (arg->fn(tp, f, arg) < 0) {
144977b9900eSJiri Pirko 			arg->stop = 1;
145077b9900eSJiri Pirko 			break;
145177b9900eSJiri Pirko 		}
145201683a14SVlad Buslov 		arg->cookie = f->handle + 1;
145377b9900eSJiri Pirko 		arg->count++;
145477b9900eSJiri Pirko 	}
145577b9900eSJiri Pirko }
145677b9900eSJiri Pirko 
145731533cbaSJohn Hurley static int fl_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb,
145831533cbaSJohn Hurley 			void *cb_priv, struct netlink_ext_ack *extack)
145931533cbaSJohn Hurley {
146031533cbaSJohn Hurley 	struct cls_fl_head *head = rtnl_dereference(tp->root);
146131533cbaSJohn Hurley 	struct tc_cls_flower_offload cls_flower = {};
146231533cbaSJohn Hurley 	struct tcf_block *block = tp->chain->block;
146331533cbaSJohn Hurley 	struct fl_flow_mask *mask;
146431533cbaSJohn Hurley 	struct cls_fl_filter *f;
146531533cbaSJohn Hurley 	int err;
146631533cbaSJohn Hurley 
146731533cbaSJohn Hurley 	list_for_each_entry(mask, &head->masks, list) {
146831533cbaSJohn Hurley 		list_for_each_entry(f, &mask->filters, list) {
146931533cbaSJohn Hurley 			if (tc_skip_hw(f->flags))
147031533cbaSJohn Hurley 				continue;
147131533cbaSJohn Hurley 
1472*8f256622SPablo Neira Ayuso 			cls_flower.rule = flow_rule_alloc();
1473*8f256622SPablo Neira Ayuso 			if (!cls_flower.rule)
1474*8f256622SPablo Neira Ayuso 				return -ENOMEM;
1475*8f256622SPablo Neira Ayuso 
147631533cbaSJohn Hurley 			tc_cls_common_offload_init(&cls_flower.common, tp,
147731533cbaSJohn Hurley 						   f->flags, extack);
147831533cbaSJohn Hurley 			cls_flower.command = add ?
147931533cbaSJohn Hurley 				TC_CLSFLOWER_REPLACE : TC_CLSFLOWER_DESTROY;
148031533cbaSJohn Hurley 			cls_flower.cookie = (unsigned long)f;
1481*8f256622SPablo Neira Ayuso 			cls_flower.rule->match.dissector = &mask->dissector;
1482*8f256622SPablo Neira Ayuso 			cls_flower.rule->match.mask = &mask->key;
1483*8f256622SPablo Neira Ayuso 			cls_flower.rule->match.key = &f->mkey;
148431533cbaSJohn Hurley 			cls_flower.exts = &f->exts;
148531533cbaSJohn Hurley 			cls_flower.classid = f->res.classid;
148631533cbaSJohn Hurley 
148731533cbaSJohn Hurley 			err = cb(TC_SETUP_CLSFLOWER, &cls_flower, cb_priv);
1488*8f256622SPablo Neira Ayuso 			kfree(cls_flower.rule);
1489*8f256622SPablo Neira Ayuso 
149031533cbaSJohn Hurley 			if (err) {
149131533cbaSJohn Hurley 				if (add && tc_skip_sw(f->flags))
149231533cbaSJohn Hurley 					return err;
149331533cbaSJohn Hurley 				continue;
149431533cbaSJohn Hurley 			}
149531533cbaSJohn Hurley 
149631533cbaSJohn Hurley 			tc_cls_offload_cnt_update(block, &f->in_hw_count,
149731533cbaSJohn Hurley 						  &f->flags, add);
149831533cbaSJohn Hurley 		}
149931533cbaSJohn Hurley 	}
150031533cbaSJohn Hurley 
150131533cbaSJohn Hurley 	return 0;
150231533cbaSJohn Hurley }
150331533cbaSJohn Hurley 
1504*8f256622SPablo Neira Ayuso static int fl_hw_create_tmplt(struct tcf_chain *chain,
150534738452SJiri Pirko 			      struct fl_flow_tmplt *tmplt)
150634738452SJiri Pirko {
150734738452SJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
150834738452SJiri Pirko 	struct tcf_block *block = chain->block;
150934738452SJiri Pirko 	struct tcf_exts dummy_exts = { 0, };
151034738452SJiri Pirko 
1511*8f256622SPablo Neira Ayuso 	cls_flower.rule = flow_rule_alloc();
1512*8f256622SPablo Neira Ayuso 	if (!cls_flower.rule)
1513*8f256622SPablo Neira Ayuso 		return -ENOMEM;
1514*8f256622SPablo Neira Ayuso 
151534738452SJiri Pirko 	cls_flower.common.chain_index = chain->index;
151634738452SJiri Pirko 	cls_flower.command = TC_CLSFLOWER_TMPLT_CREATE;
151734738452SJiri Pirko 	cls_flower.cookie = (unsigned long) tmplt;
1518*8f256622SPablo Neira Ayuso 	cls_flower.rule->match.dissector = &tmplt->dissector;
1519*8f256622SPablo Neira Ayuso 	cls_flower.rule->match.mask = &tmplt->mask;
1520*8f256622SPablo Neira Ayuso 	cls_flower.rule->match.key = &tmplt->dummy_key;
152134738452SJiri Pirko 	cls_flower.exts = &dummy_exts;
152234738452SJiri Pirko 
152334738452SJiri Pirko 	/* We don't care if driver (any of them) fails to handle this
152434738452SJiri Pirko 	 * call. It serves just as a hint for it.
152534738452SJiri Pirko 	 */
1526aeb3fecdSCong Wang 	tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, false);
1527*8f256622SPablo Neira Ayuso 	kfree(cls_flower.rule);
1528*8f256622SPablo Neira Ayuso 
1529*8f256622SPablo Neira Ayuso 	return 0;
153034738452SJiri Pirko }
153134738452SJiri Pirko 
153234738452SJiri Pirko static void fl_hw_destroy_tmplt(struct tcf_chain *chain,
153334738452SJiri Pirko 				struct fl_flow_tmplt *tmplt)
153434738452SJiri Pirko {
153534738452SJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
153634738452SJiri Pirko 	struct tcf_block *block = chain->block;
153734738452SJiri Pirko 
153834738452SJiri Pirko 	cls_flower.common.chain_index = chain->index;
153934738452SJiri Pirko 	cls_flower.command = TC_CLSFLOWER_TMPLT_DESTROY;
154034738452SJiri Pirko 	cls_flower.cookie = (unsigned long) tmplt;
154134738452SJiri Pirko 
1542aeb3fecdSCong Wang 	tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, false);
154334738452SJiri Pirko }
154434738452SJiri Pirko 
1545b95ec7ebSJiri Pirko static void *fl_tmplt_create(struct net *net, struct tcf_chain *chain,
1546b95ec7ebSJiri Pirko 			     struct nlattr **tca,
1547b95ec7ebSJiri Pirko 			     struct netlink_ext_ack *extack)
1548b95ec7ebSJiri Pirko {
1549b95ec7ebSJiri Pirko 	struct fl_flow_tmplt *tmplt;
1550b95ec7ebSJiri Pirko 	struct nlattr **tb;
1551b95ec7ebSJiri Pirko 	int err;
1552b95ec7ebSJiri Pirko 
1553b95ec7ebSJiri Pirko 	if (!tca[TCA_OPTIONS])
1554b95ec7ebSJiri Pirko 		return ERR_PTR(-EINVAL);
1555b95ec7ebSJiri Pirko 
1556b95ec7ebSJiri Pirko 	tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL);
1557b95ec7ebSJiri Pirko 	if (!tb)
1558b95ec7ebSJiri Pirko 		return ERR_PTR(-ENOBUFS);
1559b95ec7ebSJiri Pirko 	err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS],
1560b95ec7ebSJiri Pirko 			       fl_policy, NULL);
1561b95ec7ebSJiri Pirko 	if (err)
1562b95ec7ebSJiri Pirko 		goto errout_tb;
1563b95ec7ebSJiri Pirko 
1564b95ec7ebSJiri Pirko 	tmplt = kzalloc(sizeof(*tmplt), GFP_KERNEL);
15651cbc36a5SDan Carpenter 	if (!tmplt) {
15661cbc36a5SDan Carpenter 		err = -ENOMEM;
1567b95ec7ebSJiri Pirko 		goto errout_tb;
15681cbc36a5SDan Carpenter 	}
1569b95ec7ebSJiri Pirko 	tmplt->chain = chain;
1570b95ec7ebSJiri Pirko 	err = fl_set_key(net, tb, &tmplt->dummy_key, &tmplt->mask, extack);
1571b95ec7ebSJiri Pirko 	if (err)
1572b95ec7ebSJiri Pirko 		goto errout_tmplt;
1573b95ec7ebSJiri Pirko 
1574b95ec7ebSJiri Pirko 	fl_init_dissector(&tmplt->dissector, &tmplt->mask);
1575b95ec7ebSJiri Pirko 
1576*8f256622SPablo Neira Ayuso 	err = fl_hw_create_tmplt(chain, tmplt);
1577*8f256622SPablo Neira Ayuso 	if (err)
1578*8f256622SPablo Neira Ayuso 		goto errout_tmplt;
157934738452SJiri Pirko 
1580*8f256622SPablo Neira Ayuso 	kfree(tb);
1581b95ec7ebSJiri Pirko 	return tmplt;
1582b95ec7ebSJiri Pirko 
1583b95ec7ebSJiri Pirko errout_tmplt:
1584b95ec7ebSJiri Pirko 	kfree(tmplt);
1585b95ec7ebSJiri Pirko errout_tb:
1586b95ec7ebSJiri Pirko 	kfree(tb);
1587b95ec7ebSJiri Pirko 	return ERR_PTR(err);
1588b95ec7ebSJiri Pirko }
1589b95ec7ebSJiri Pirko 
1590b95ec7ebSJiri Pirko static void fl_tmplt_destroy(void *tmplt_priv)
1591b95ec7ebSJiri Pirko {
1592b95ec7ebSJiri Pirko 	struct fl_flow_tmplt *tmplt = tmplt_priv;
1593b95ec7ebSJiri Pirko 
159495278ddaSCong Wang 	fl_hw_destroy_tmplt(tmplt->chain, tmplt);
159595278ddaSCong Wang 	kfree(tmplt);
1596b95ec7ebSJiri Pirko }
1597b95ec7ebSJiri Pirko 
159877b9900eSJiri Pirko static int fl_dump_key_val(struct sk_buff *skb,
159977b9900eSJiri Pirko 			   void *val, int val_type,
160077b9900eSJiri Pirko 			   void *mask, int mask_type, int len)
160177b9900eSJiri Pirko {
160277b9900eSJiri Pirko 	int err;
160377b9900eSJiri Pirko 
160477b9900eSJiri Pirko 	if (!memchr_inv(mask, 0, len))
160577b9900eSJiri Pirko 		return 0;
160677b9900eSJiri Pirko 	err = nla_put(skb, val_type, len, val);
160777b9900eSJiri Pirko 	if (err)
160877b9900eSJiri Pirko 		return err;
160977b9900eSJiri Pirko 	if (mask_type != TCA_FLOWER_UNSPEC) {
161077b9900eSJiri Pirko 		err = nla_put(skb, mask_type, len, mask);
161177b9900eSJiri Pirko 		if (err)
161277b9900eSJiri Pirko 			return err;
161377b9900eSJiri Pirko 	}
161477b9900eSJiri Pirko 	return 0;
161577b9900eSJiri Pirko }
161677b9900eSJiri Pirko 
16175c72299fSAmritha Nambiar static int fl_dump_key_port_range(struct sk_buff *skb, struct fl_flow_key *key,
16185c72299fSAmritha Nambiar 				  struct fl_flow_key *mask)
16195c72299fSAmritha Nambiar {
16205c72299fSAmritha Nambiar 	if (fl_dump_key_val(skb, &key->tp_min.dst, TCA_FLOWER_KEY_PORT_DST_MIN,
16215c72299fSAmritha Nambiar 			    &mask->tp_min.dst, TCA_FLOWER_UNSPEC,
16225c72299fSAmritha Nambiar 			    sizeof(key->tp_min.dst)) ||
16235c72299fSAmritha Nambiar 	    fl_dump_key_val(skb, &key->tp_max.dst, TCA_FLOWER_KEY_PORT_DST_MAX,
16245c72299fSAmritha Nambiar 			    &mask->tp_max.dst, TCA_FLOWER_UNSPEC,
16255c72299fSAmritha Nambiar 			    sizeof(key->tp_max.dst)) ||
16265c72299fSAmritha Nambiar 	    fl_dump_key_val(skb, &key->tp_min.src, TCA_FLOWER_KEY_PORT_SRC_MIN,
16275c72299fSAmritha Nambiar 			    &mask->tp_min.src, TCA_FLOWER_UNSPEC,
16285c72299fSAmritha Nambiar 			    sizeof(key->tp_min.src)) ||
16295c72299fSAmritha Nambiar 	    fl_dump_key_val(skb, &key->tp_max.src, TCA_FLOWER_KEY_PORT_SRC_MAX,
16305c72299fSAmritha Nambiar 			    &mask->tp_max.src, TCA_FLOWER_UNSPEC,
16315c72299fSAmritha Nambiar 			    sizeof(key->tp_max.src)))
16325c72299fSAmritha Nambiar 		return -1;
16335c72299fSAmritha Nambiar 
16345c72299fSAmritha Nambiar 	return 0;
16355c72299fSAmritha Nambiar }
16365c72299fSAmritha Nambiar 
1637a577d8f7SBenjamin LaHaise static int fl_dump_key_mpls(struct sk_buff *skb,
1638a577d8f7SBenjamin LaHaise 			    struct flow_dissector_key_mpls *mpls_key,
1639a577d8f7SBenjamin LaHaise 			    struct flow_dissector_key_mpls *mpls_mask)
1640a577d8f7SBenjamin LaHaise {
1641a577d8f7SBenjamin LaHaise 	int err;
1642a577d8f7SBenjamin LaHaise 
1643a577d8f7SBenjamin LaHaise 	if (!memchr_inv(mpls_mask, 0, sizeof(*mpls_mask)))
1644a577d8f7SBenjamin LaHaise 		return 0;
1645a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_ttl) {
1646a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TTL,
1647a577d8f7SBenjamin LaHaise 				 mpls_key->mpls_ttl);
1648a577d8f7SBenjamin LaHaise 		if (err)
1649a577d8f7SBenjamin LaHaise 			return err;
1650a577d8f7SBenjamin LaHaise 	}
1651a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_tc) {
1652a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TC,
1653a577d8f7SBenjamin LaHaise 				 mpls_key->mpls_tc);
1654a577d8f7SBenjamin LaHaise 		if (err)
1655a577d8f7SBenjamin LaHaise 			return err;
1656a577d8f7SBenjamin LaHaise 	}
1657a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_label) {
1658a577d8f7SBenjamin LaHaise 		err = nla_put_u32(skb, TCA_FLOWER_KEY_MPLS_LABEL,
1659a577d8f7SBenjamin LaHaise 				  mpls_key->mpls_label);
1660a577d8f7SBenjamin LaHaise 		if (err)
1661a577d8f7SBenjamin LaHaise 			return err;
1662a577d8f7SBenjamin LaHaise 	}
1663a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_bos) {
1664a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_BOS,
1665a577d8f7SBenjamin LaHaise 				 mpls_key->mpls_bos);
1666a577d8f7SBenjamin LaHaise 		if (err)
1667a577d8f7SBenjamin LaHaise 			return err;
1668a577d8f7SBenjamin LaHaise 	}
1669a577d8f7SBenjamin LaHaise 	return 0;
1670a577d8f7SBenjamin LaHaise }
1671a577d8f7SBenjamin LaHaise 
16720e2c17b6SOr Gerlitz static int fl_dump_key_ip(struct sk_buff *skb, bool encap,
16734d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *key,
16744d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *mask)
16754d80cc0aSOr Gerlitz {
16760e2c17b6SOr Gerlitz 	int tos_key = encap ? TCA_FLOWER_KEY_ENC_IP_TOS : TCA_FLOWER_KEY_IP_TOS;
16770e2c17b6SOr Gerlitz 	int ttl_key = encap ? TCA_FLOWER_KEY_ENC_IP_TTL : TCA_FLOWER_KEY_IP_TTL;
16780e2c17b6SOr Gerlitz 	int tos_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TOS_MASK : TCA_FLOWER_KEY_IP_TOS_MASK;
16790e2c17b6SOr Gerlitz 	int ttl_mask = encap ? TCA_FLOWER_KEY_ENC_IP_TTL_MASK : TCA_FLOWER_KEY_IP_TTL_MASK;
16800e2c17b6SOr Gerlitz 
16810e2c17b6SOr Gerlitz 	if (fl_dump_key_val(skb, &key->tos, tos_key, &mask->tos, tos_mask, sizeof(key->tos)) ||
16820e2c17b6SOr Gerlitz 	    fl_dump_key_val(skb, &key->ttl, ttl_key, &mask->ttl, ttl_mask, sizeof(key->ttl)))
16834d80cc0aSOr Gerlitz 		return -1;
16844d80cc0aSOr Gerlitz 
16854d80cc0aSOr Gerlitz 	return 0;
16864d80cc0aSOr Gerlitz }
16874d80cc0aSOr Gerlitz 
16889399ae9aSHadar Hen Zion static int fl_dump_key_vlan(struct sk_buff *skb,
1689d64efd09SJianbo Liu 			    int vlan_id_key, int vlan_prio_key,
16909399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *vlan_key,
16919399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *vlan_mask)
16929399ae9aSHadar Hen Zion {
16939399ae9aSHadar Hen Zion 	int err;
16949399ae9aSHadar Hen Zion 
16959399ae9aSHadar Hen Zion 	if (!memchr_inv(vlan_mask, 0, sizeof(*vlan_mask)))
16969399ae9aSHadar Hen Zion 		return 0;
16979399ae9aSHadar Hen Zion 	if (vlan_mask->vlan_id) {
1698d64efd09SJianbo Liu 		err = nla_put_u16(skb, vlan_id_key,
16999399ae9aSHadar Hen Zion 				  vlan_key->vlan_id);
17009399ae9aSHadar Hen Zion 		if (err)
17019399ae9aSHadar Hen Zion 			return err;
17029399ae9aSHadar Hen Zion 	}
17039399ae9aSHadar Hen Zion 	if (vlan_mask->vlan_priority) {
1704d64efd09SJianbo Liu 		err = nla_put_u8(skb, vlan_prio_key,
17059399ae9aSHadar Hen Zion 				 vlan_key->vlan_priority);
17069399ae9aSHadar Hen Zion 		if (err)
17079399ae9aSHadar Hen Zion 			return err;
17089399ae9aSHadar Hen Zion 	}
17099399ae9aSHadar Hen Zion 	return 0;
17109399ae9aSHadar Hen Zion }
17119399ae9aSHadar Hen Zion 
1712faa3ffceSOr Gerlitz static void fl_get_key_flag(u32 dissector_key, u32 dissector_mask,
1713faa3ffceSOr Gerlitz 			    u32 *flower_key, u32 *flower_mask,
1714faa3ffceSOr Gerlitz 			    u32 flower_flag_bit, u32 dissector_flag_bit)
1715faa3ffceSOr Gerlitz {
1716faa3ffceSOr Gerlitz 	if (dissector_mask & dissector_flag_bit) {
1717faa3ffceSOr Gerlitz 		*flower_mask |= flower_flag_bit;
1718faa3ffceSOr Gerlitz 		if (dissector_key & dissector_flag_bit)
1719faa3ffceSOr Gerlitz 			*flower_key |= flower_flag_bit;
1720faa3ffceSOr Gerlitz 	}
1721faa3ffceSOr Gerlitz }
1722faa3ffceSOr Gerlitz 
1723faa3ffceSOr Gerlitz static int fl_dump_key_flags(struct sk_buff *skb, u32 flags_key, u32 flags_mask)
1724faa3ffceSOr Gerlitz {
1725faa3ffceSOr Gerlitz 	u32 key, mask;
1726faa3ffceSOr Gerlitz 	__be32 _key, _mask;
1727faa3ffceSOr Gerlitz 	int err;
1728faa3ffceSOr Gerlitz 
1729faa3ffceSOr Gerlitz 	if (!memchr_inv(&flags_mask, 0, sizeof(flags_mask)))
1730faa3ffceSOr Gerlitz 		return 0;
1731faa3ffceSOr Gerlitz 
1732faa3ffceSOr Gerlitz 	key = 0;
1733faa3ffceSOr Gerlitz 	mask = 0;
1734faa3ffceSOr Gerlitz 
1735faa3ffceSOr Gerlitz 	fl_get_key_flag(flags_key, flags_mask, &key, &mask,
1736faa3ffceSOr Gerlitz 			TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT);
1737459d153dSPieter Jansen van Vuuren 	fl_get_key_flag(flags_key, flags_mask, &key, &mask,
1738459d153dSPieter Jansen van Vuuren 			TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST,
1739459d153dSPieter Jansen van Vuuren 			FLOW_DIS_FIRST_FRAG);
1740faa3ffceSOr Gerlitz 
1741faa3ffceSOr Gerlitz 	_key = cpu_to_be32(key);
1742faa3ffceSOr Gerlitz 	_mask = cpu_to_be32(mask);
1743faa3ffceSOr Gerlitz 
1744faa3ffceSOr Gerlitz 	err = nla_put(skb, TCA_FLOWER_KEY_FLAGS, 4, &_key);
1745faa3ffceSOr Gerlitz 	if (err)
1746faa3ffceSOr Gerlitz 		return err;
1747faa3ffceSOr Gerlitz 
1748faa3ffceSOr Gerlitz 	return nla_put(skb, TCA_FLOWER_KEY_FLAGS_MASK, 4, &_mask);
1749faa3ffceSOr Gerlitz }
1750faa3ffceSOr Gerlitz 
17510a6e7778SPieter Jansen van Vuuren static int fl_dump_key_geneve_opt(struct sk_buff *skb,
17520a6e7778SPieter Jansen van Vuuren 				  struct flow_dissector_key_enc_opts *enc_opts)
17530a6e7778SPieter Jansen van Vuuren {
17540a6e7778SPieter Jansen van Vuuren 	struct geneve_opt *opt;
17550a6e7778SPieter Jansen van Vuuren 	struct nlattr *nest;
17560a6e7778SPieter Jansen van Vuuren 	int opt_off = 0;
17570a6e7778SPieter Jansen van Vuuren 
17580a6e7778SPieter Jansen van Vuuren 	nest = nla_nest_start(skb, TCA_FLOWER_KEY_ENC_OPTS_GENEVE);
17590a6e7778SPieter Jansen van Vuuren 	if (!nest)
17600a6e7778SPieter Jansen van Vuuren 		goto nla_put_failure;
17610a6e7778SPieter Jansen van Vuuren 
17620a6e7778SPieter Jansen van Vuuren 	while (enc_opts->len > opt_off) {
17630a6e7778SPieter Jansen van Vuuren 		opt = (struct geneve_opt *)&enc_opts->data[opt_off];
17640a6e7778SPieter Jansen van Vuuren 
17650a6e7778SPieter Jansen van Vuuren 		if (nla_put_be16(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS,
17660a6e7778SPieter Jansen van Vuuren 				 opt->opt_class))
17670a6e7778SPieter Jansen van Vuuren 			goto nla_put_failure;
17680a6e7778SPieter Jansen van Vuuren 		if (nla_put_u8(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE,
17690a6e7778SPieter Jansen van Vuuren 			       opt->type))
17700a6e7778SPieter Jansen van Vuuren 			goto nla_put_failure;
17710a6e7778SPieter Jansen van Vuuren 		if (nla_put(skb, TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA,
17720a6e7778SPieter Jansen van Vuuren 			    opt->length * 4, opt->opt_data))
17730a6e7778SPieter Jansen van Vuuren 			goto nla_put_failure;
17740a6e7778SPieter Jansen van Vuuren 
17750a6e7778SPieter Jansen van Vuuren 		opt_off += sizeof(struct geneve_opt) + opt->length * 4;
17760a6e7778SPieter Jansen van Vuuren 	}
17770a6e7778SPieter Jansen van Vuuren 	nla_nest_end(skb, nest);
17780a6e7778SPieter Jansen van Vuuren 	return 0;
17790a6e7778SPieter Jansen van Vuuren 
17800a6e7778SPieter Jansen van Vuuren nla_put_failure:
17810a6e7778SPieter Jansen van Vuuren 	nla_nest_cancel(skb, nest);
17820a6e7778SPieter Jansen van Vuuren 	return -EMSGSIZE;
17830a6e7778SPieter Jansen van Vuuren }
17840a6e7778SPieter Jansen van Vuuren 
17850a6e7778SPieter Jansen van Vuuren static int fl_dump_key_options(struct sk_buff *skb, int enc_opt_type,
17860a6e7778SPieter Jansen van Vuuren 			       struct flow_dissector_key_enc_opts *enc_opts)
17870a6e7778SPieter Jansen van Vuuren {
17880a6e7778SPieter Jansen van Vuuren 	struct nlattr *nest;
17890a6e7778SPieter Jansen van Vuuren 	int err;
17900a6e7778SPieter Jansen van Vuuren 
17910a6e7778SPieter Jansen van Vuuren 	if (!enc_opts->len)
17920a6e7778SPieter Jansen van Vuuren 		return 0;
17930a6e7778SPieter Jansen van Vuuren 
17940a6e7778SPieter Jansen van Vuuren 	nest = nla_nest_start(skb, enc_opt_type);
17950a6e7778SPieter Jansen van Vuuren 	if (!nest)
17960a6e7778SPieter Jansen van Vuuren 		goto nla_put_failure;
17970a6e7778SPieter Jansen van Vuuren 
17980a6e7778SPieter Jansen van Vuuren 	switch (enc_opts->dst_opt_type) {
17990a6e7778SPieter Jansen van Vuuren 	case TUNNEL_GENEVE_OPT:
18000a6e7778SPieter Jansen van Vuuren 		err = fl_dump_key_geneve_opt(skb, enc_opts);
18010a6e7778SPieter Jansen van Vuuren 		if (err)
18020a6e7778SPieter Jansen van Vuuren 			goto nla_put_failure;
18030a6e7778SPieter Jansen van Vuuren 		break;
18040a6e7778SPieter Jansen van Vuuren 	default:
18050a6e7778SPieter Jansen van Vuuren 		goto nla_put_failure;
18060a6e7778SPieter Jansen van Vuuren 	}
18070a6e7778SPieter Jansen van Vuuren 	nla_nest_end(skb, nest);
18080a6e7778SPieter Jansen van Vuuren 	return 0;
18090a6e7778SPieter Jansen van Vuuren 
18100a6e7778SPieter Jansen van Vuuren nla_put_failure:
18110a6e7778SPieter Jansen van Vuuren 	nla_nest_cancel(skb, nest);
18120a6e7778SPieter Jansen van Vuuren 	return -EMSGSIZE;
18130a6e7778SPieter Jansen van Vuuren }
18140a6e7778SPieter Jansen van Vuuren 
18150a6e7778SPieter Jansen van Vuuren static int fl_dump_key_enc_opt(struct sk_buff *skb,
18160a6e7778SPieter Jansen van Vuuren 			       struct flow_dissector_key_enc_opts *key_opts,
18170a6e7778SPieter Jansen van Vuuren 			       struct flow_dissector_key_enc_opts *msk_opts)
18180a6e7778SPieter Jansen van Vuuren {
18190a6e7778SPieter Jansen van Vuuren 	int err;
18200a6e7778SPieter Jansen van Vuuren 
18210a6e7778SPieter Jansen van Vuuren 	err = fl_dump_key_options(skb, TCA_FLOWER_KEY_ENC_OPTS, key_opts);
18220a6e7778SPieter Jansen van Vuuren 	if (err)
18230a6e7778SPieter Jansen van Vuuren 		return err;
18240a6e7778SPieter Jansen van Vuuren 
18250a6e7778SPieter Jansen van Vuuren 	return fl_dump_key_options(skb, TCA_FLOWER_KEY_ENC_OPTS_MASK, msk_opts);
18260a6e7778SPieter Jansen van Vuuren }
18270a6e7778SPieter Jansen van Vuuren 
1828f5749081SJiri Pirko static int fl_dump_key(struct sk_buff *skb, struct net *net,
1829f5749081SJiri Pirko 		       struct fl_flow_key *key, struct fl_flow_key *mask)
183077b9900eSJiri Pirko {
183177b9900eSJiri Pirko 	if (mask->indev_ifindex) {
183277b9900eSJiri Pirko 		struct net_device *dev;
183377b9900eSJiri Pirko 
183477b9900eSJiri Pirko 		dev = __dev_get_by_index(net, key->indev_ifindex);
183577b9900eSJiri Pirko 		if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name))
183677b9900eSJiri Pirko 			goto nla_put_failure;
183777b9900eSJiri Pirko 	}
183877b9900eSJiri Pirko 
183977b9900eSJiri Pirko 	if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
184077b9900eSJiri Pirko 			    mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
184177b9900eSJiri Pirko 			    sizeof(key->eth.dst)) ||
184277b9900eSJiri Pirko 	    fl_dump_key_val(skb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
184377b9900eSJiri Pirko 			    mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
184477b9900eSJiri Pirko 			    sizeof(key->eth.src)) ||
184577b9900eSJiri Pirko 	    fl_dump_key_val(skb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE,
184677b9900eSJiri Pirko 			    &mask->basic.n_proto, TCA_FLOWER_UNSPEC,
184777b9900eSJiri Pirko 			    sizeof(key->basic.n_proto)))
184877b9900eSJiri Pirko 		goto nla_put_failure;
18499399ae9aSHadar Hen Zion 
1850a577d8f7SBenjamin LaHaise 	if (fl_dump_key_mpls(skb, &key->mpls, &mask->mpls))
1851a577d8f7SBenjamin LaHaise 		goto nla_put_failure;
1852a577d8f7SBenjamin LaHaise 
1853d64efd09SJianbo Liu 	if (fl_dump_key_vlan(skb, TCA_FLOWER_KEY_VLAN_ID,
1854d64efd09SJianbo Liu 			     TCA_FLOWER_KEY_VLAN_PRIO, &key->vlan, &mask->vlan))
18559399ae9aSHadar Hen Zion 		goto nla_put_failure;
18569399ae9aSHadar Hen Zion 
1857d64efd09SJianbo Liu 	if (fl_dump_key_vlan(skb, TCA_FLOWER_KEY_CVLAN_ID,
1858d64efd09SJianbo Liu 			     TCA_FLOWER_KEY_CVLAN_PRIO,
1859d64efd09SJianbo Liu 			     &key->cvlan, &mask->cvlan) ||
1860d64efd09SJianbo Liu 	    (mask->cvlan.vlan_tpid &&
1861158abbf1SJianbo Liu 	     nla_put_be16(skb, TCA_FLOWER_KEY_VLAN_ETH_TYPE,
1862d64efd09SJianbo Liu 			  key->cvlan.vlan_tpid)))
1863d3069512SJianbo Liu 		goto nla_put_failure;
1864d3069512SJianbo Liu 
18655e9a0fe4SJianbo Liu 	if (mask->basic.n_proto) {
1866d64efd09SJianbo Liu 		if (mask->cvlan.vlan_tpid) {
1867d64efd09SJianbo Liu 			if (nla_put_be16(skb, TCA_FLOWER_KEY_CVLAN_ETH_TYPE,
1868d64efd09SJianbo Liu 					 key->basic.n_proto))
1869d64efd09SJianbo Liu 				goto nla_put_failure;
1870d64efd09SJianbo Liu 		} else if (mask->vlan.vlan_tpid) {
1871d64efd09SJianbo Liu 			if (nla_put_be16(skb, TCA_FLOWER_KEY_VLAN_ETH_TYPE,
1872d64efd09SJianbo Liu 					 key->basic.n_proto))
1873d64efd09SJianbo Liu 				goto nla_put_failure;
1874d64efd09SJianbo Liu 		}
18755e9a0fe4SJianbo Liu 	}
1876d64efd09SJianbo Liu 
187777b9900eSJiri Pirko 	if ((key->basic.n_proto == htons(ETH_P_IP) ||
187877b9900eSJiri Pirko 	     key->basic.n_proto == htons(ETH_P_IPV6)) &&
18794d80cc0aSOr Gerlitz 	    (fl_dump_key_val(skb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
188077b9900eSJiri Pirko 			    &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
18814d80cc0aSOr Gerlitz 			    sizeof(key->basic.ip_proto)) ||
18820e2c17b6SOr Gerlitz 	    fl_dump_key_ip(skb, false, &key->ip, &mask->ip)))
188377b9900eSJiri Pirko 		goto nla_put_failure;
188477b9900eSJiri Pirko 
1885c3f83241STom Herbert 	if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
188677b9900eSJiri Pirko 	    (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
188777b9900eSJiri Pirko 			     &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
188877b9900eSJiri Pirko 			     sizeof(key->ipv4.src)) ||
188977b9900eSJiri Pirko 	     fl_dump_key_val(skb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
189077b9900eSJiri Pirko 			     &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
189177b9900eSJiri Pirko 			     sizeof(key->ipv4.dst))))
189277b9900eSJiri Pirko 		goto nla_put_failure;
1893c3f83241STom Herbert 	else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
189477b9900eSJiri Pirko 		 (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
189577b9900eSJiri Pirko 				  &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
189677b9900eSJiri Pirko 				  sizeof(key->ipv6.src)) ||
189777b9900eSJiri Pirko 		  fl_dump_key_val(skb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
189877b9900eSJiri Pirko 				  &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
189977b9900eSJiri Pirko 				  sizeof(key->ipv6.dst))))
190077b9900eSJiri Pirko 		goto nla_put_failure;
190177b9900eSJiri Pirko 
190277b9900eSJiri Pirko 	if (key->basic.ip_proto == IPPROTO_TCP &&
190377b9900eSJiri Pirko 	    (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
1904aa72d708SOr Gerlitz 			     &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
190577b9900eSJiri Pirko 			     sizeof(key->tp.src)) ||
190677b9900eSJiri Pirko 	     fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
1907aa72d708SOr Gerlitz 			     &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
1908fdfc7dd6SJiri Pirko 			     sizeof(key->tp.dst)) ||
1909fdfc7dd6SJiri Pirko 	     fl_dump_key_val(skb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS,
1910fdfc7dd6SJiri Pirko 			     &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK,
1911fdfc7dd6SJiri Pirko 			     sizeof(key->tcp.flags))))
191277b9900eSJiri Pirko 		goto nla_put_failure;
191377b9900eSJiri Pirko 	else if (key->basic.ip_proto == IPPROTO_UDP &&
191477b9900eSJiri Pirko 		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
1915aa72d708SOr Gerlitz 				  &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
191677b9900eSJiri Pirko 				  sizeof(key->tp.src)) ||
191777b9900eSJiri Pirko 		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
1918aa72d708SOr Gerlitz 				  &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
191977b9900eSJiri Pirko 				  sizeof(key->tp.dst))))
192077b9900eSJiri Pirko 		goto nla_put_failure;
19215976c5f4SSimon Horman 	else if (key->basic.ip_proto == IPPROTO_SCTP &&
19225976c5f4SSimon Horman 		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
19235976c5f4SSimon Horman 				  &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
19245976c5f4SSimon Horman 				  sizeof(key->tp.src)) ||
19255976c5f4SSimon Horman 		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
19265976c5f4SSimon Horman 				  &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
19275976c5f4SSimon Horman 				  sizeof(key->tp.dst))))
19285976c5f4SSimon Horman 		goto nla_put_failure;
19297b684884SSimon Horman 	else if (key->basic.n_proto == htons(ETH_P_IP) &&
19307b684884SSimon Horman 		 key->basic.ip_proto == IPPROTO_ICMP &&
19317b684884SSimon Horman 		 (fl_dump_key_val(skb, &key->icmp.type,
19327b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_TYPE, &mask->icmp.type,
19337b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,
19347b684884SSimon Horman 				  sizeof(key->icmp.type)) ||
19357b684884SSimon Horman 		  fl_dump_key_val(skb, &key->icmp.code,
19367b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_CODE, &mask->icmp.code,
19377b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
19387b684884SSimon Horman 				  sizeof(key->icmp.code))))
19397b684884SSimon Horman 		goto nla_put_failure;
19407b684884SSimon Horman 	else if (key->basic.n_proto == htons(ETH_P_IPV6) &&
19417b684884SSimon Horman 		 key->basic.ip_proto == IPPROTO_ICMPV6 &&
19427b684884SSimon Horman 		 (fl_dump_key_val(skb, &key->icmp.type,
19437b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_TYPE, &mask->icmp.type,
19447b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
19457b684884SSimon Horman 				  sizeof(key->icmp.type)) ||
19467b684884SSimon Horman 		  fl_dump_key_val(skb, &key->icmp.code,
19477b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_CODE, &mask->icmp.code,
19487b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_CODE_MASK,
19497b684884SSimon Horman 				  sizeof(key->icmp.code))))
19507b684884SSimon Horman 		goto nla_put_failure;
195199d31326SSimon Horman 	else if ((key->basic.n_proto == htons(ETH_P_ARP) ||
195299d31326SSimon Horman 		  key->basic.n_proto == htons(ETH_P_RARP)) &&
195399d31326SSimon Horman 		 (fl_dump_key_val(skb, &key->arp.sip,
195499d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_SIP, &mask->arp.sip,
195599d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_SIP_MASK,
195699d31326SSimon Horman 				  sizeof(key->arp.sip)) ||
195799d31326SSimon Horman 		  fl_dump_key_val(skb, &key->arp.tip,
195899d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_TIP, &mask->arp.tip,
195999d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_TIP_MASK,
196099d31326SSimon Horman 				  sizeof(key->arp.tip)) ||
196199d31326SSimon Horman 		  fl_dump_key_val(skb, &key->arp.op,
196299d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_OP, &mask->arp.op,
196399d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_OP_MASK,
196499d31326SSimon Horman 				  sizeof(key->arp.op)) ||
196599d31326SSimon Horman 		  fl_dump_key_val(skb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA,
196699d31326SSimon Horman 				  mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK,
196799d31326SSimon Horman 				  sizeof(key->arp.sha)) ||
196899d31326SSimon Horman 		  fl_dump_key_val(skb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA,
196999d31326SSimon Horman 				  mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK,
197099d31326SSimon Horman 				  sizeof(key->arp.tha))))
197199d31326SSimon Horman 		goto nla_put_failure;
197277b9900eSJiri Pirko 
19735c72299fSAmritha Nambiar 	if ((key->basic.ip_proto == IPPROTO_TCP ||
19745c72299fSAmritha Nambiar 	     key->basic.ip_proto == IPPROTO_UDP ||
19755c72299fSAmritha Nambiar 	     key->basic.ip_proto == IPPROTO_SCTP) &&
19765c72299fSAmritha Nambiar 	     fl_dump_key_port_range(skb, key, mask))
19775c72299fSAmritha Nambiar 		goto nla_put_failure;
19785c72299fSAmritha Nambiar 
1979bc3103f1SAmir Vadai 	if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
1980bc3103f1SAmir Vadai 	    (fl_dump_key_val(skb, &key->enc_ipv4.src,
1981bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV4_SRC, &mask->enc_ipv4.src,
1982bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
1983bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv4.src)) ||
1984bc3103f1SAmir Vadai 	     fl_dump_key_val(skb, &key->enc_ipv4.dst,
1985bc3103f1SAmir Vadai 			     TCA_FLOWER_KEY_ENC_IPV4_DST, &mask->enc_ipv4.dst,
1986bc3103f1SAmir Vadai 			     TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
1987bc3103f1SAmir Vadai 			     sizeof(key->enc_ipv4.dst))))
1988bc3103f1SAmir Vadai 		goto nla_put_failure;
1989bc3103f1SAmir Vadai 	else if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
1990bc3103f1SAmir Vadai 		 (fl_dump_key_val(skb, &key->enc_ipv6.src,
1991bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV6_SRC, &mask->enc_ipv6.src,
1992bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
1993bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv6.src)) ||
1994bc3103f1SAmir Vadai 		 fl_dump_key_val(skb, &key->enc_ipv6.dst,
1995bc3103f1SAmir Vadai 				 TCA_FLOWER_KEY_ENC_IPV6_DST,
1996bc3103f1SAmir Vadai 				 &mask->enc_ipv6.dst,
1997bc3103f1SAmir Vadai 				 TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
1998bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv6.dst))))
1999bc3103f1SAmir Vadai 		goto nla_put_failure;
2000bc3103f1SAmir Vadai 
2001bc3103f1SAmir Vadai 	if (fl_dump_key_val(skb, &key->enc_key_id, TCA_FLOWER_KEY_ENC_KEY_ID,
2002eb523f42SHadar Hen Zion 			    &mask->enc_key_id, TCA_FLOWER_UNSPEC,
2003f4d997fdSHadar Hen Zion 			    sizeof(key->enc_key_id)) ||
2004f4d997fdSHadar Hen Zion 	    fl_dump_key_val(skb, &key->enc_tp.src,
2005f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
2006f4d997fdSHadar Hen Zion 			    &mask->enc_tp.src,
2007f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
2008f4d997fdSHadar Hen Zion 			    sizeof(key->enc_tp.src)) ||
2009f4d997fdSHadar Hen Zion 	    fl_dump_key_val(skb, &key->enc_tp.dst,
2010f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
2011f4d997fdSHadar Hen Zion 			    &mask->enc_tp.dst,
2012f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
20130e2c17b6SOr Gerlitz 			    sizeof(key->enc_tp.dst)) ||
20140a6e7778SPieter Jansen van Vuuren 	    fl_dump_key_ip(skb, true, &key->enc_ip, &mask->enc_ip) ||
20150a6e7778SPieter Jansen van Vuuren 	    fl_dump_key_enc_opt(skb, &key->enc_opts, &mask->enc_opts))
2016bc3103f1SAmir Vadai 		goto nla_put_failure;
2017bc3103f1SAmir Vadai 
2018faa3ffceSOr Gerlitz 	if (fl_dump_key_flags(skb, key->control.flags, mask->control.flags))
2019faa3ffceSOr Gerlitz 		goto nla_put_failure;
2020faa3ffceSOr Gerlitz 
2021f5749081SJiri Pirko 	return 0;
2022f5749081SJiri Pirko 
2023f5749081SJiri Pirko nla_put_failure:
2024f5749081SJiri Pirko 	return -EMSGSIZE;
2025f5749081SJiri Pirko }
2026f5749081SJiri Pirko 
2027f5749081SJiri Pirko static int fl_dump(struct net *net, struct tcf_proto *tp, void *fh,
2028f5749081SJiri Pirko 		   struct sk_buff *skb, struct tcmsg *t)
2029f5749081SJiri Pirko {
2030f5749081SJiri Pirko 	struct cls_fl_filter *f = fh;
2031f5749081SJiri Pirko 	struct nlattr *nest;
2032f5749081SJiri Pirko 	struct fl_flow_key *key, *mask;
2033f5749081SJiri Pirko 
2034f5749081SJiri Pirko 	if (!f)
2035f5749081SJiri Pirko 		return skb->len;
2036f5749081SJiri Pirko 
2037f5749081SJiri Pirko 	t->tcm_handle = f->handle;
2038f5749081SJiri Pirko 
2039f5749081SJiri Pirko 	nest = nla_nest_start(skb, TCA_OPTIONS);
2040f5749081SJiri Pirko 	if (!nest)
2041f5749081SJiri Pirko 		goto nla_put_failure;
2042f5749081SJiri Pirko 
2043f5749081SJiri Pirko 	if (f->res.classid &&
2044f5749081SJiri Pirko 	    nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid))
2045f5749081SJiri Pirko 		goto nla_put_failure;
2046f5749081SJiri Pirko 
2047f5749081SJiri Pirko 	key = &f->key;
2048f5749081SJiri Pirko 	mask = &f->mask->key;
2049f5749081SJiri Pirko 
2050f5749081SJiri Pirko 	if (fl_dump_key(skb, net, key, mask))
2051f5749081SJiri Pirko 		goto nla_put_failure;
2052f5749081SJiri Pirko 
2053f5749081SJiri Pirko 	if (!tc_skip_hw(f->flags))
2054f5749081SJiri Pirko 		fl_hw_update_stats(tp, f);
2055f5749081SJiri Pirko 
2056749e6720SOr Gerlitz 	if (f->flags && nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags))
2057749e6720SOr Gerlitz 		goto nla_put_failure;
2058e69985c6SAmir Vadai 
205986c55361SVlad Buslov 	if (nla_put_u32(skb, TCA_FLOWER_IN_HW_COUNT, f->in_hw_count))
206086c55361SVlad Buslov 		goto nla_put_failure;
206186c55361SVlad Buslov 
206277b9900eSJiri Pirko 	if (tcf_exts_dump(skb, &f->exts))
206377b9900eSJiri Pirko 		goto nla_put_failure;
206477b9900eSJiri Pirko 
206577b9900eSJiri Pirko 	nla_nest_end(skb, nest);
206677b9900eSJiri Pirko 
206777b9900eSJiri Pirko 	if (tcf_exts_dump_stats(skb, &f->exts) < 0)
206877b9900eSJiri Pirko 		goto nla_put_failure;
206977b9900eSJiri Pirko 
207077b9900eSJiri Pirko 	return skb->len;
207177b9900eSJiri Pirko 
207277b9900eSJiri Pirko nla_put_failure:
207377b9900eSJiri Pirko 	nla_nest_cancel(skb, nest);
207477b9900eSJiri Pirko 	return -1;
207577b9900eSJiri Pirko }
207677b9900eSJiri Pirko 
2077b95ec7ebSJiri Pirko static int fl_tmplt_dump(struct sk_buff *skb, struct net *net, void *tmplt_priv)
2078b95ec7ebSJiri Pirko {
2079b95ec7ebSJiri Pirko 	struct fl_flow_tmplt *tmplt = tmplt_priv;
2080b95ec7ebSJiri Pirko 	struct fl_flow_key *key, *mask;
2081b95ec7ebSJiri Pirko 	struct nlattr *nest;
2082b95ec7ebSJiri Pirko 
2083b95ec7ebSJiri Pirko 	nest = nla_nest_start(skb, TCA_OPTIONS);
2084b95ec7ebSJiri Pirko 	if (!nest)
2085b95ec7ebSJiri Pirko 		goto nla_put_failure;
2086b95ec7ebSJiri Pirko 
2087b95ec7ebSJiri Pirko 	key = &tmplt->dummy_key;
2088b95ec7ebSJiri Pirko 	mask = &tmplt->mask;
2089b95ec7ebSJiri Pirko 
2090b95ec7ebSJiri Pirko 	if (fl_dump_key(skb, net, key, mask))
2091b95ec7ebSJiri Pirko 		goto nla_put_failure;
2092b95ec7ebSJiri Pirko 
2093b95ec7ebSJiri Pirko 	nla_nest_end(skb, nest);
2094b95ec7ebSJiri Pirko 
2095b95ec7ebSJiri Pirko 	return skb->len;
2096b95ec7ebSJiri Pirko 
2097b95ec7ebSJiri Pirko nla_put_failure:
2098b95ec7ebSJiri Pirko 	nla_nest_cancel(skb, nest);
2099b95ec7ebSJiri Pirko 	return -EMSGSIZE;
2100b95ec7ebSJiri Pirko }
2101b95ec7ebSJiri Pirko 
210207d79fc7SCong Wang static void fl_bind_class(void *fh, u32 classid, unsigned long cl)
210307d79fc7SCong Wang {
210407d79fc7SCong Wang 	struct cls_fl_filter *f = fh;
210507d79fc7SCong Wang 
210607d79fc7SCong Wang 	if (f && f->res.classid == classid)
210707d79fc7SCong Wang 		f->res.class = cl;
210807d79fc7SCong Wang }
210907d79fc7SCong Wang 
211077b9900eSJiri Pirko static struct tcf_proto_ops cls_fl_ops __read_mostly = {
211177b9900eSJiri Pirko 	.kind		= "flower",
211277b9900eSJiri Pirko 	.classify	= fl_classify,
211377b9900eSJiri Pirko 	.init		= fl_init,
211477b9900eSJiri Pirko 	.destroy	= fl_destroy,
211577b9900eSJiri Pirko 	.get		= fl_get,
211677b9900eSJiri Pirko 	.change		= fl_change,
211777b9900eSJiri Pirko 	.delete		= fl_delete,
211877b9900eSJiri Pirko 	.walk		= fl_walk,
211931533cbaSJohn Hurley 	.reoffload	= fl_reoffload,
212077b9900eSJiri Pirko 	.dump		= fl_dump,
212107d79fc7SCong Wang 	.bind_class	= fl_bind_class,
2122b95ec7ebSJiri Pirko 	.tmplt_create	= fl_tmplt_create,
2123b95ec7ebSJiri Pirko 	.tmplt_destroy	= fl_tmplt_destroy,
2124b95ec7ebSJiri Pirko 	.tmplt_dump	= fl_tmplt_dump,
212577b9900eSJiri Pirko 	.owner		= THIS_MODULE,
212677b9900eSJiri Pirko };
212777b9900eSJiri Pirko 
212877b9900eSJiri Pirko static int __init cls_fl_init(void)
212977b9900eSJiri Pirko {
213077b9900eSJiri Pirko 	return register_tcf_proto_ops(&cls_fl_ops);
213177b9900eSJiri Pirko }
213277b9900eSJiri Pirko 
213377b9900eSJiri Pirko static void __exit cls_fl_exit(void)
213477b9900eSJiri Pirko {
213577b9900eSJiri Pirko 	unregister_tcf_proto_ops(&cls_fl_ops);
213677b9900eSJiri Pirko }
213777b9900eSJiri Pirko 
213877b9900eSJiri Pirko module_init(cls_fl_init);
213977b9900eSJiri Pirko module_exit(cls_fl_exit);
214077b9900eSJiri Pirko 
214177b9900eSJiri Pirko MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>");
214277b9900eSJiri Pirko MODULE_DESCRIPTION("Flower classifier");
214377b9900eSJiri Pirko MODULE_LICENSE("GPL v2");
2144