xref: /linux/net/sched/cls_flower.c (revision 9c160941403ba833c8e67981806ccae73ff7aca7)
177b9900eSJiri Pirko /*
277b9900eSJiri Pirko  * net/sched/cls_flower.c		Flower classifier
377b9900eSJiri Pirko  *
477b9900eSJiri Pirko  * Copyright (c) 2015 Jiri Pirko <jiri@resnulli.us>
577b9900eSJiri Pirko  *
677b9900eSJiri Pirko  * This program is free software; you can redistribute it and/or modify
777b9900eSJiri Pirko  * it under the terms of the GNU General Public License as published by
877b9900eSJiri Pirko  * the Free Software Foundation; either version 2 of the License, or
977b9900eSJiri Pirko  * (at your option) any later version.
1077b9900eSJiri Pirko  */
1177b9900eSJiri Pirko 
1277b9900eSJiri Pirko #include <linux/kernel.h>
1377b9900eSJiri Pirko #include <linux/init.h>
1477b9900eSJiri Pirko #include <linux/module.h>
1577b9900eSJiri Pirko #include <linux/rhashtable.h>
16d9363774SDaniel Borkmann #include <linux/workqueue.h>
1777b9900eSJiri Pirko 
1877b9900eSJiri Pirko #include <linux/if_ether.h>
1977b9900eSJiri Pirko #include <linux/in6.h>
2077b9900eSJiri Pirko #include <linux/ip.h>
21a577d8f7SBenjamin LaHaise #include <linux/mpls.h>
2277b9900eSJiri Pirko 
2377b9900eSJiri Pirko #include <net/sch_generic.h>
2477b9900eSJiri Pirko #include <net/pkt_cls.h>
2577b9900eSJiri Pirko #include <net/ip.h>
2677b9900eSJiri Pirko #include <net/flow_dissector.h>
2777b9900eSJiri Pirko 
28bc3103f1SAmir Vadai #include <net/dst.h>
29bc3103f1SAmir Vadai #include <net/dst_metadata.h>
30bc3103f1SAmir Vadai 
3177b9900eSJiri Pirko struct fl_flow_key {
3277b9900eSJiri Pirko 	int	indev_ifindex;
3342aecaa9STom Herbert 	struct flow_dissector_key_control control;
34bc3103f1SAmir Vadai 	struct flow_dissector_key_control enc_control;
3577b9900eSJiri Pirko 	struct flow_dissector_key_basic basic;
3677b9900eSJiri Pirko 	struct flow_dissector_key_eth_addrs eth;
379399ae9aSHadar Hen Zion 	struct flow_dissector_key_vlan vlan;
3877b9900eSJiri Pirko 	union {
39c3f83241STom Herbert 		struct flow_dissector_key_ipv4_addrs ipv4;
4077b9900eSJiri Pirko 		struct flow_dissector_key_ipv6_addrs ipv6;
4177b9900eSJiri Pirko 	};
4277b9900eSJiri Pirko 	struct flow_dissector_key_ports tp;
437b684884SSimon Horman 	struct flow_dissector_key_icmp icmp;
4499d31326SSimon Horman 	struct flow_dissector_key_arp arp;
45bc3103f1SAmir Vadai 	struct flow_dissector_key_keyid enc_key_id;
46bc3103f1SAmir Vadai 	union {
47bc3103f1SAmir Vadai 		struct flow_dissector_key_ipv4_addrs enc_ipv4;
48bc3103f1SAmir Vadai 		struct flow_dissector_key_ipv6_addrs enc_ipv6;
49bc3103f1SAmir Vadai 	};
50f4d997fdSHadar Hen Zion 	struct flow_dissector_key_ports enc_tp;
51a577d8f7SBenjamin LaHaise 	struct flow_dissector_key_mpls mpls;
52fdfc7dd6SJiri Pirko 	struct flow_dissector_key_tcp tcp;
534d80cc0aSOr Gerlitz 	struct flow_dissector_key_ip ip;
5477b9900eSJiri Pirko } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
5577b9900eSJiri Pirko 
5677b9900eSJiri Pirko struct fl_flow_mask_range {
5777b9900eSJiri Pirko 	unsigned short int start;
5877b9900eSJiri Pirko 	unsigned short int end;
5977b9900eSJiri Pirko };
6077b9900eSJiri Pirko 
6177b9900eSJiri Pirko struct fl_flow_mask {
6277b9900eSJiri Pirko 	struct fl_flow_key key;
6377b9900eSJiri Pirko 	struct fl_flow_mask_range range;
6477b9900eSJiri Pirko 	struct rcu_head	rcu;
6577b9900eSJiri Pirko };
6677b9900eSJiri Pirko 
6777b9900eSJiri Pirko struct cls_fl_head {
6877b9900eSJiri Pirko 	struct rhashtable ht;
6977b9900eSJiri Pirko 	struct fl_flow_mask mask;
7077b9900eSJiri Pirko 	struct flow_dissector dissector;
7177b9900eSJiri Pirko 	bool mask_assigned;
7277b9900eSJiri Pirko 	struct list_head filters;
7377b9900eSJiri Pirko 	struct rhashtable_params ht_params;
74d9363774SDaniel Borkmann 	union {
75d9363774SDaniel Borkmann 		struct work_struct work;
7677b9900eSJiri Pirko 		struct rcu_head	rcu;
7777b9900eSJiri Pirko 	};
78c15ab236SChris Mi 	struct idr handle_idr;
79d9363774SDaniel Borkmann };
8077b9900eSJiri Pirko 
8177b9900eSJiri Pirko struct cls_fl_filter {
8277b9900eSJiri Pirko 	struct rhash_head ht_node;
8377b9900eSJiri Pirko 	struct fl_flow_key mkey;
8477b9900eSJiri Pirko 	struct tcf_exts exts;
8577b9900eSJiri Pirko 	struct tcf_result res;
8677b9900eSJiri Pirko 	struct fl_flow_key key;
8777b9900eSJiri Pirko 	struct list_head list;
8877b9900eSJiri Pirko 	u32 handle;
89e69985c6SAmir Vadai 	u32 flags;
900552c8afSCong Wang 	union {
910552c8afSCong Wang 		struct work_struct work;
9277b9900eSJiri Pirko 		struct rcu_head	rcu;
9377b9900eSJiri Pirko 	};
9477b9900eSJiri Pirko 	struct net_device *hw_dev;
9577b9900eSJiri Pirko };
9677b9900eSJiri Pirko 
9777b9900eSJiri Pirko static unsigned short int fl_mask_range(const struct fl_flow_mask *mask)
9877b9900eSJiri Pirko {
9977b9900eSJiri Pirko 	return mask->range.end - mask->range.start;
10077b9900eSJiri Pirko }
10177b9900eSJiri Pirko 
10277b9900eSJiri Pirko static void fl_mask_update_range(struct fl_flow_mask *mask)
10377b9900eSJiri Pirko {
10477b9900eSJiri Pirko 	const u8 *bytes = (const u8 *) &mask->key;
10577b9900eSJiri Pirko 	size_t size = sizeof(mask->key);
10677b9900eSJiri Pirko 	size_t i, first = 0, last = size - 1;
10777b9900eSJiri Pirko 
10877b9900eSJiri Pirko 	for (i = 0; i < sizeof(mask->key); i++) {
10977b9900eSJiri Pirko 		if (bytes[i]) {
11077b9900eSJiri Pirko 			if (!first && i)
11177b9900eSJiri Pirko 				first = i;
11277b9900eSJiri Pirko 			last = i;
11377b9900eSJiri Pirko 		}
11477b9900eSJiri Pirko 	}
11577b9900eSJiri Pirko 	mask->range.start = rounddown(first, sizeof(long));
11677b9900eSJiri Pirko 	mask->range.end = roundup(last + 1, sizeof(long));
11777b9900eSJiri Pirko }
11877b9900eSJiri Pirko 
11977b9900eSJiri Pirko static void *fl_key_get_start(struct fl_flow_key *key,
12077b9900eSJiri Pirko 			      const struct fl_flow_mask *mask)
12177b9900eSJiri Pirko {
12277b9900eSJiri Pirko 	return (u8 *) key + mask->range.start;
12377b9900eSJiri Pirko }
12477b9900eSJiri Pirko 
12577b9900eSJiri Pirko static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key,
12677b9900eSJiri Pirko 			      struct fl_flow_mask *mask)
12777b9900eSJiri Pirko {
12877b9900eSJiri Pirko 	const long *lkey = fl_key_get_start(key, mask);
12977b9900eSJiri Pirko 	const long *lmask = fl_key_get_start(&mask->key, mask);
13077b9900eSJiri Pirko 	long *lmkey = fl_key_get_start(mkey, mask);
13177b9900eSJiri Pirko 	int i;
13277b9900eSJiri Pirko 
13377b9900eSJiri Pirko 	for (i = 0; i < fl_mask_range(mask); i += sizeof(long))
13477b9900eSJiri Pirko 		*lmkey++ = *lkey++ & *lmask++;
13577b9900eSJiri Pirko }
13677b9900eSJiri Pirko 
13777b9900eSJiri Pirko static void fl_clear_masked_range(struct fl_flow_key *key,
13877b9900eSJiri Pirko 				  struct fl_flow_mask *mask)
13977b9900eSJiri Pirko {
14077b9900eSJiri Pirko 	memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask));
14177b9900eSJiri Pirko }
14277b9900eSJiri Pirko 
143a3308d8fSPaul Blakey static struct cls_fl_filter *fl_lookup(struct cls_fl_head *head,
144a3308d8fSPaul Blakey 				       struct fl_flow_key *mkey)
145a3308d8fSPaul Blakey {
146a3308d8fSPaul Blakey 	return rhashtable_lookup_fast(&head->ht,
147a3308d8fSPaul Blakey 				      fl_key_get_start(mkey, &head->mask),
148a3308d8fSPaul Blakey 				      head->ht_params);
149a3308d8fSPaul Blakey }
150a3308d8fSPaul Blakey 
15177b9900eSJiri Pirko static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp,
15277b9900eSJiri Pirko 		       struct tcf_result *res)
15377b9900eSJiri Pirko {
15477b9900eSJiri Pirko 	struct cls_fl_head *head = rcu_dereference_bh(tp->root);
15577b9900eSJiri Pirko 	struct cls_fl_filter *f;
15677b9900eSJiri Pirko 	struct fl_flow_key skb_key;
15777b9900eSJiri Pirko 	struct fl_flow_key skb_mkey;
15877b9900eSJiri Pirko 
159e69985c6SAmir Vadai 	if (!atomic_read(&head->ht.nelems))
160e69985c6SAmir Vadai 		return -1;
161e69985c6SAmir Vadai 
16277b9900eSJiri Pirko 	fl_clear_masked_range(&skb_key, &head->mask);
163bc3103f1SAmir Vadai 
16477b9900eSJiri Pirko 	skb_key.indev_ifindex = skb->skb_iif;
16577b9900eSJiri Pirko 	/* skb_flow_dissect() does not set n_proto in case an unknown protocol,
16677b9900eSJiri Pirko 	 * so do it rather here.
16777b9900eSJiri Pirko 	 */
16877b9900eSJiri Pirko 	skb_key.basic.n_proto = skb->protocol;
16962b32379SSimon Horman 	skb_flow_dissect_tunnel_info(skb, &head->dissector, &skb_key);
170cd79a238STom Herbert 	skb_flow_dissect(skb, &head->dissector, &skb_key, 0);
17177b9900eSJiri Pirko 
17277b9900eSJiri Pirko 	fl_set_masked_key(&skb_mkey, &skb_key, &head->mask);
17377b9900eSJiri Pirko 
174a3308d8fSPaul Blakey 	f = fl_lookup(head, &skb_mkey);
175e8eb36cdSAmir Vadai 	if (f && !tc_skip_sw(f->flags)) {
17677b9900eSJiri Pirko 		*res = f->res;
17777b9900eSJiri Pirko 		return tcf_exts_exec(skb, &f->exts, res);
17877b9900eSJiri Pirko 	}
17977b9900eSJiri Pirko 	return -1;
18077b9900eSJiri Pirko }
18177b9900eSJiri Pirko 
18277b9900eSJiri Pirko static int fl_init(struct tcf_proto *tp)
18377b9900eSJiri Pirko {
18477b9900eSJiri Pirko 	struct cls_fl_head *head;
18577b9900eSJiri Pirko 
18677b9900eSJiri Pirko 	head = kzalloc(sizeof(*head), GFP_KERNEL);
18777b9900eSJiri Pirko 	if (!head)
18877b9900eSJiri Pirko 		return -ENOBUFS;
18977b9900eSJiri Pirko 
19077b9900eSJiri Pirko 	INIT_LIST_HEAD_RCU(&head->filters);
19177b9900eSJiri Pirko 	rcu_assign_pointer(tp->root, head);
192c15ab236SChris Mi 	idr_init(&head->handle_idr);
19377b9900eSJiri Pirko 
19477b9900eSJiri Pirko 	return 0;
19577b9900eSJiri Pirko }
19677b9900eSJiri Pirko 
1970dadc117SCong Wang static void __fl_destroy_filter(struct cls_fl_filter *f)
1980dadc117SCong Wang {
1990dadc117SCong Wang 	tcf_exts_destroy(&f->exts);
2000dadc117SCong Wang 	tcf_exts_put_net(&f->exts);
2010dadc117SCong Wang 	kfree(f);
2020dadc117SCong Wang }
2030dadc117SCong Wang 
2040552c8afSCong Wang static void fl_destroy_filter_work(struct work_struct *work)
2050552c8afSCong Wang {
2060552c8afSCong Wang 	struct cls_fl_filter *f = container_of(work, struct cls_fl_filter, work);
2070552c8afSCong Wang 
2080552c8afSCong Wang 	rtnl_lock();
2090dadc117SCong Wang 	__fl_destroy_filter(f);
2100552c8afSCong Wang 	rtnl_unlock();
2110552c8afSCong Wang }
2120552c8afSCong Wang 
21377b9900eSJiri Pirko static void fl_destroy_filter(struct rcu_head *head)
21477b9900eSJiri Pirko {
21577b9900eSJiri Pirko 	struct cls_fl_filter *f = container_of(head, struct cls_fl_filter, rcu);
21677b9900eSJiri Pirko 
2170552c8afSCong Wang 	INIT_WORK(&f->work, fl_destroy_filter_work);
2180552c8afSCong Wang 	tcf_queue_work(&f->work);
21977b9900eSJiri Pirko }
22077b9900eSJiri Pirko 
2211b0f8037SJakub Kicinski static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f,
2221b0f8037SJakub Kicinski 				 struct netlink_ext_ack *extack)
2235b33f488SAmir Vadai {
224de4784caSJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
225208c0f4bSJiri Pirko 	struct tcf_block *block = tp->chain->block;
2265b33f488SAmir Vadai 
2271b0f8037SJakub Kicinski 	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack);
228de4784caSJiri Pirko 	cls_flower.command = TC_CLSFLOWER_DESTROY;
229de4784caSJiri Pirko 	cls_flower.cookie = (unsigned long) f;
2305b33f488SAmir Vadai 
231208c0f4bSJiri Pirko 	tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER,
232717503b9SJiri Pirko 			 &cls_flower, false);
233caa72601SJiri Pirko 	tcf_block_offload_dec(block, &f->flags);
2345b33f488SAmir Vadai }
2355b33f488SAmir Vadai 
236e8eb36cdSAmir Vadai static int fl_hw_replace_filter(struct tcf_proto *tp,
2375b33f488SAmir Vadai 				struct flow_dissector *dissector,
2385b33f488SAmir Vadai 				struct fl_flow_key *mask,
23941002038SQuentin Monnet 				struct cls_fl_filter *f,
24041002038SQuentin Monnet 				struct netlink_ext_ack *extack)
2415b33f488SAmir Vadai {
242de4784caSJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
243208c0f4bSJiri Pirko 	struct tcf_block *block = tp->chain->block;
244717503b9SJiri Pirko 	bool skip_sw = tc_skip_sw(f->flags);
245e8eb36cdSAmir Vadai 	int err;
2465b33f488SAmir Vadai 
247ea205940SJakub Kicinski 	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack);
248de4784caSJiri Pirko 	cls_flower.command = TC_CLSFLOWER_REPLACE;
249de4784caSJiri Pirko 	cls_flower.cookie = (unsigned long) f;
250de4784caSJiri Pirko 	cls_flower.dissector = dissector;
251de4784caSJiri Pirko 	cls_flower.mask = mask;
252de4784caSJiri Pirko 	cls_flower.key = &f->mkey;
253de4784caSJiri Pirko 	cls_flower.exts = &f->exts;
254384c181eSAmritha Nambiar 	cls_flower.classid = f->res.classid;
2555b33f488SAmir Vadai 
256208c0f4bSJiri Pirko 	err = tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER,
257717503b9SJiri Pirko 			       &cls_flower, skip_sw);
258717503b9SJiri Pirko 	if (err < 0) {
2591b0f8037SJakub Kicinski 		fl_hw_destroy_filter(tp, f, NULL);
260717503b9SJiri Pirko 		return err;
261717503b9SJiri Pirko 	} else if (err > 0) {
262caa72601SJiri Pirko 		tcf_block_offload_inc(block, &f->flags);
263717503b9SJiri Pirko 	}
264717503b9SJiri Pirko 
265717503b9SJiri Pirko 	if (skip_sw && !(f->flags & TCA_CLS_FLAGS_IN_HW))
266717503b9SJiri Pirko 		return -EINVAL;
267717503b9SJiri Pirko 
268e8eb36cdSAmir Vadai 	return 0;
2695b33f488SAmir Vadai }
2705b33f488SAmir Vadai 
27110cbc684SAmir Vadai static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
27210cbc684SAmir Vadai {
273de4784caSJiri Pirko 	struct tc_cls_flower_offload cls_flower = {};
274208c0f4bSJiri Pirko 	struct tcf_block *block = tp->chain->block;
27510cbc684SAmir Vadai 
276ea205940SJakub Kicinski 	tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, NULL);
277de4784caSJiri Pirko 	cls_flower.command = TC_CLSFLOWER_STATS;
278de4784caSJiri Pirko 	cls_flower.cookie = (unsigned long) f;
279de4784caSJiri Pirko 	cls_flower.exts = &f->exts;
280384c181eSAmritha Nambiar 	cls_flower.classid = f->res.classid;
28110cbc684SAmir Vadai 
282208c0f4bSJiri Pirko 	tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER,
283717503b9SJiri Pirko 			 &cls_flower, false);
28410cbc684SAmir Vadai }
28510cbc684SAmir Vadai 
2861b0f8037SJakub Kicinski static void __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,
2871b0f8037SJakub Kicinski 			struct netlink_ext_ack *extack)
28813fa876eSRoi Dayan {
289c15ab236SChris Mi 	struct cls_fl_head *head = rtnl_dereference(tp->root);
290c15ab236SChris Mi 
291*9c160941SMatthew Wilcox 	idr_remove(&head->handle_idr, f->handle);
29213fa876eSRoi Dayan 	list_del_rcu(&f->list);
29379685219SHadar Hen Zion 	if (!tc_skip_hw(f->flags))
2941b0f8037SJakub Kicinski 		fl_hw_destroy_filter(tp, f, extack);
29513fa876eSRoi Dayan 	tcf_unbind_filter(tp, &f->res);
2960dadc117SCong Wang 	if (tcf_exts_get_net(&f->exts))
29713fa876eSRoi Dayan 		call_rcu(&f->rcu, fl_destroy_filter);
2980dadc117SCong Wang 	else
2990dadc117SCong Wang 		__fl_destroy_filter(f);
30013fa876eSRoi Dayan }
30113fa876eSRoi Dayan 
302d9363774SDaniel Borkmann static void fl_destroy_sleepable(struct work_struct *work)
303d9363774SDaniel Borkmann {
304d9363774SDaniel Borkmann 	struct cls_fl_head *head = container_of(work, struct cls_fl_head,
305d9363774SDaniel Borkmann 						work);
306d9363774SDaniel Borkmann 	if (head->mask_assigned)
307d9363774SDaniel Borkmann 		rhashtable_destroy(&head->ht);
308d9363774SDaniel Borkmann 	kfree(head);
309d9363774SDaniel Borkmann 	module_put(THIS_MODULE);
310d9363774SDaniel Borkmann }
311d9363774SDaniel Borkmann 
312d9363774SDaniel Borkmann static void fl_destroy_rcu(struct rcu_head *rcu)
313d9363774SDaniel Borkmann {
314d9363774SDaniel Borkmann 	struct cls_fl_head *head = container_of(rcu, struct cls_fl_head, rcu);
315d9363774SDaniel Borkmann 
316d9363774SDaniel Borkmann 	INIT_WORK(&head->work, fl_destroy_sleepable);
317d9363774SDaniel Borkmann 	schedule_work(&head->work);
318d9363774SDaniel Borkmann }
319d9363774SDaniel Borkmann 
320715df5ecSJakub Kicinski static void fl_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
32177b9900eSJiri Pirko {
32277b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
32377b9900eSJiri Pirko 	struct cls_fl_filter *f, *next;
32477b9900eSJiri Pirko 
32513fa876eSRoi Dayan 	list_for_each_entry_safe(f, next, &head->filters, list)
3261b0f8037SJakub Kicinski 		__fl_delete(tp, f, extack);
327c15ab236SChris Mi 	idr_destroy(&head->handle_idr);
328d9363774SDaniel Borkmann 
329d9363774SDaniel Borkmann 	__module_get(THIS_MODULE);
330d9363774SDaniel Borkmann 	call_rcu(&head->rcu, fl_destroy_rcu);
33177b9900eSJiri Pirko }
33277b9900eSJiri Pirko 
3338113c095SWANG Cong static void *fl_get(struct tcf_proto *tp, u32 handle)
33477b9900eSJiri Pirko {
33577b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
33677b9900eSJiri Pirko 
337c15ab236SChris Mi 	return idr_find_ext(&head->handle_idr, handle);
33877b9900eSJiri Pirko }
33977b9900eSJiri Pirko 
34077b9900eSJiri Pirko static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
34177b9900eSJiri Pirko 	[TCA_FLOWER_UNSPEC]		= { .type = NLA_UNSPEC },
34277b9900eSJiri Pirko 	[TCA_FLOWER_CLASSID]		= { .type = NLA_U32 },
34377b9900eSJiri Pirko 	[TCA_FLOWER_INDEV]		= { .type = NLA_STRING,
34477b9900eSJiri Pirko 					    .len = IFNAMSIZ },
34577b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_DST]	= { .len = ETH_ALEN },
34677b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_DST_MASK]	= { .len = ETH_ALEN },
34777b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_SRC]	= { .len = ETH_ALEN },
34877b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_SRC_MASK]	= { .len = ETH_ALEN },
34977b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_TYPE]	= { .type = NLA_U16 },
35077b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IP_PROTO]	= { .type = NLA_U8 },
35177b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_SRC]	= { .type = NLA_U32 },
35277b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_SRC_MASK]	= { .type = NLA_U32 },
35377b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_DST]	= { .type = NLA_U32 },
35477b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_DST_MASK]	= { .type = NLA_U32 },
35577b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
35677b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_SRC_MASK]	= { .len = sizeof(struct in6_addr) },
35777b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
35877b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_DST_MASK]	= { .len = sizeof(struct in6_addr) },
35977b9900eSJiri Pirko 	[TCA_FLOWER_KEY_TCP_SRC]	= { .type = NLA_U16 },
36077b9900eSJiri Pirko 	[TCA_FLOWER_KEY_TCP_DST]	= { .type = NLA_U16 },
361b175c3a4SJamal Hadi Salim 	[TCA_FLOWER_KEY_UDP_SRC]	= { .type = NLA_U16 },
362b175c3a4SJamal Hadi Salim 	[TCA_FLOWER_KEY_UDP_DST]	= { .type = NLA_U16 },
3639399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_ID]	= { .type = NLA_U16 },
3649399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_PRIO]	= { .type = NLA_U8 },
3659399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_ETH_TYPE]	= { .type = NLA_U16 },
366bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_KEY_ID]	= { .type = NLA_U32 },
367bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_SRC]	= { .type = NLA_U32 },
368bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NLA_U32 },
369bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_DST]	= { .type = NLA_U32 },
370bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NLA_U32 },
371bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
372bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) },
373bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
374bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) },
375aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_TCP_SRC_MASK]	= { .type = NLA_U16 },
376aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_TCP_DST_MASK]	= { .type = NLA_U16 },
377aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_UDP_SRC_MASK]	= { .type = NLA_U16 },
378aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_UDP_DST_MASK]	= { .type = NLA_U16 },
3795976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_SRC_MASK]	= { .type = NLA_U16 },
3805976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_DST_MASK]	= { .type = NLA_U16 },
3815976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_SRC]	= { .type = NLA_U16 },
3825976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_DST]	= { .type = NLA_U16 },
383f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT]	= { .type = NLA_U16 },
384f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK]	= { .type = NLA_U16 },
385f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]	= { .type = NLA_U16 },
386f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK]	= { .type = NLA_U16 },
387faa3ffceSOr Gerlitz 	[TCA_FLOWER_KEY_FLAGS]		= { .type = NLA_U32 },
388faa3ffceSOr Gerlitz 	[TCA_FLOWER_KEY_FLAGS_MASK]	= { .type = NLA_U32 },
3897b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_TYPE]	= { .type = NLA_U8 },
3907b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_TYPE_MASK] = { .type = NLA_U8 },
3917b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_CODE]	= { .type = NLA_U8 },
3927b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_CODE_MASK] = { .type = NLA_U8 },
3937b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_TYPE]	= { .type = NLA_U8 },
3947b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_TYPE_MASK] = { .type = NLA_U8 },
3957b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_CODE]	= { .type = NLA_U8 },
3967b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_CODE_MASK] = { .type = NLA_U8 },
39799d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SIP]	= { .type = NLA_U32 },
39899d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SIP_MASK]	= { .type = NLA_U32 },
39999d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_TIP]	= { .type = NLA_U32 },
40099d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_TIP_MASK]	= { .type = NLA_U32 },
40199d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_OP]		= { .type = NLA_U8 },
40299d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_OP_MASK]	= { .type = NLA_U8 },
40399d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SHA]	= { .len = ETH_ALEN },
40499d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SHA_MASK]	= { .len = ETH_ALEN },
40599d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_THA]	= { .len = ETH_ALEN },
40699d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_THA_MASK]	= { .len = ETH_ALEN },
407a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_TTL]	= { .type = NLA_U8 },
408a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_BOS]	= { .type = NLA_U8 },
409a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_TC]	= { .type = NLA_U8 },
410a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_LABEL]	= { .type = NLA_U32 },
411fdfc7dd6SJiri Pirko 	[TCA_FLOWER_KEY_TCP_FLAGS]	= { .type = NLA_U16 },
412fdfc7dd6SJiri Pirko 	[TCA_FLOWER_KEY_TCP_FLAGS_MASK]	= { .type = NLA_U16 },
4134d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TOS]		= { .type = NLA_U8 },
4144d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TOS_MASK]	= { .type = NLA_U8 },
4154d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TTL]		= { .type = NLA_U8 },
4164d80cc0aSOr Gerlitz 	[TCA_FLOWER_KEY_IP_TTL_MASK]	= { .type = NLA_U8 },
41777b9900eSJiri Pirko };
41877b9900eSJiri Pirko 
41977b9900eSJiri Pirko static void fl_set_key_val(struct nlattr **tb,
42077b9900eSJiri Pirko 			   void *val, int val_type,
42177b9900eSJiri Pirko 			   void *mask, int mask_type, int len)
42277b9900eSJiri Pirko {
42377b9900eSJiri Pirko 	if (!tb[val_type])
42477b9900eSJiri Pirko 		return;
42577b9900eSJiri Pirko 	memcpy(val, nla_data(tb[val_type]), len);
42677b9900eSJiri Pirko 	if (mask_type == TCA_FLOWER_UNSPEC || !tb[mask_type])
42777b9900eSJiri Pirko 		memset(mask, 0xff, len);
42877b9900eSJiri Pirko 	else
42977b9900eSJiri Pirko 		memcpy(mask, nla_data(tb[mask_type]), len);
43077b9900eSJiri Pirko }
43177b9900eSJiri Pirko 
4321a7fca63SBenjamin LaHaise static int fl_set_key_mpls(struct nlattr **tb,
433a577d8f7SBenjamin LaHaise 			   struct flow_dissector_key_mpls *key_val,
434a577d8f7SBenjamin LaHaise 			   struct flow_dissector_key_mpls *key_mask)
435a577d8f7SBenjamin LaHaise {
436a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_TTL]) {
437a577d8f7SBenjamin LaHaise 		key_val->mpls_ttl = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TTL]);
438a577d8f7SBenjamin LaHaise 		key_mask->mpls_ttl = MPLS_TTL_MASK;
439a577d8f7SBenjamin LaHaise 	}
440a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_BOS]) {
4411a7fca63SBenjamin LaHaise 		u8 bos = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_BOS]);
4421a7fca63SBenjamin LaHaise 
4431a7fca63SBenjamin LaHaise 		if (bos & ~MPLS_BOS_MASK)
4441a7fca63SBenjamin LaHaise 			return -EINVAL;
4451a7fca63SBenjamin LaHaise 		key_val->mpls_bos = bos;
446a577d8f7SBenjamin LaHaise 		key_mask->mpls_bos = MPLS_BOS_MASK;
447a577d8f7SBenjamin LaHaise 	}
448a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_TC]) {
4491a7fca63SBenjamin LaHaise 		u8 tc = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TC]);
4501a7fca63SBenjamin LaHaise 
4511a7fca63SBenjamin LaHaise 		if (tc & ~MPLS_TC_MASK)
4521a7fca63SBenjamin LaHaise 			return -EINVAL;
4531a7fca63SBenjamin LaHaise 		key_val->mpls_tc = tc;
454a577d8f7SBenjamin LaHaise 		key_mask->mpls_tc = MPLS_TC_MASK;
455a577d8f7SBenjamin LaHaise 	}
456a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_LABEL]) {
4571a7fca63SBenjamin LaHaise 		u32 label = nla_get_u32(tb[TCA_FLOWER_KEY_MPLS_LABEL]);
4581a7fca63SBenjamin LaHaise 
4591a7fca63SBenjamin LaHaise 		if (label & ~MPLS_LABEL_MASK)
4601a7fca63SBenjamin LaHaise 			return -EINVAL;
4611a7fca63SBenjamin LaHaise 		key_val->mpls_label = label;
462a577d8f7SBenjamin LaHaise 		key_mask->mpls_label = MPLS_LABEL_MASK;
463a577d8f7SBenjamin LaHaise 	}
4641a7fca63SBenjamin LaHaise 	return 0;
465a577d8f7SBenjamin LaHaise }
466a577d8f7SBenjamin LaHaise 
4679399ae9aSHadar Hen Zion static void fl_set_key_vlan(struct nlattr **tb,
4689399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *key_val,
4699399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *key_mask)
4709399ae9aSHadar Hen Zion {
4719399ae9aSHadar Hen Zion #define VLAN_PRIORITY_MASK	0x7
4729399ae9aSHadar Hen Zion 
4739399ae9aSHadar Hen Zion 	if (tb[TCA_FLOWER_KEY_VLAN_ID]) {
4749399ae9aSHadar Hen Zion 		key_val->vlan_id =
4759399ae9aSHadar Hen Zion 			nla_get_u16(tb[TCA_FLOWER_KEY_VLAN_ID]) & VLAN_VID_MASK;
4769399ae9aSHadar Hen Zion 		key_mask->vlan_id = VLAN_VID_MASK;
4779399ae9aSHadar Hen Zion 	}
4789399ae9aSHadar Hen Zion 	if (tb[TCA_FLOWER_KEY_VLAN_PRIO]) {
4799399ae9aSHadar Hen Zion 		key_val->vlan_priority =
4809399ae9aSHadar Hen Zion 			nla_get_u8(tb[TCA_FLOWER_KEY_VLAN_PRIO]) &
4819399ae9aSHadar Hen Zion 			VLAN_PRIORITY_MASK;
4829399ae9aSHadar Hen Zion 		key_mask->vlan_priority = VLAN_PRIORITY_MASK;
4839399ae9aSHadar Hen Zion 	}
4849399ae9aSHadar Hen Zion }
4859399ae9aSHadar Hen Zion 
486faa3ffceSOr Gerlitz static void fl_set_key_flag(u32 flower_key, u32 flower_mask,
487faa3ffceSOr Gerlitz 			    u32 *dissector_key, u32 *dissector_mask,
488faa3ffceSOr Gerlitz 			    u32 flower_flag_bit, u32 dissector_flag_bit)
489faa3ffceSOr Gerlitz {
490faa3ffceSOr Gerlitz 	if (flower_mask & flower_flag_bit) {
491faa3ffceSOr Gerlitz 		*dissector_mask |= dissector_flag_bit;
492faa3ffceSOr Gerlitz 		if (flower_key & flower_flag_bit)
493faa3ffceSOr Gerlitz 			*dissector_key |= dissector_flag_bit;
494faa3ffceSOr Gerlitz 	}
495faa3ffceSOr Gerlitz }
496faa3ffceSOr Gerlitz 
497d9724772SOr Gerlitz static int fl_set_key_flags(struct nlattr **tb,
498faa3ffceSOr Gerlitz 			    u32 *flags_key, u32 *flags_mask)
499faa3ffceSOr Gerlitz {
500faa3ffceSOr Gerlitz 	u32 key, mask;
501faa3ffceSOr Gerlitz 
502d9724772SOr Gerlitz 	/* mask is mandatory for flags */
503d9724772SOr Gerlitz 	if (!tb[TCA_FLOWER_KEY_FLAGS_MASK])
504d9724772SOr Gerlitz 		return -EINVAL;
505faa3ffceSOr Gerlitz 
506faa3ffceSOr Gerlitz 	key = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS]));
507faa3ffceSOr Gerlitz 	mask = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS_MASK]));
508faa3ffceSOr Gerlitz 
509faa3ffceSOr Gerlitz 	*flags_key  = 0;
510faa3ffceSOr Gerlitz 	*flags_mask = 0;
511faa3ffceSOr Gerlitz 
512faa3ffceSOr Gerlitz 	fl_set_key_flag(key, mask, flags_key, flags_mask,
513faa3ffceSOr Gerlitz 			TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT);
514d9724772SOr Gerlitz 
515d9724772SOr Gerlitz 	return 0;
516faa3ffceSOr Gerlitz }
517faa3ffceSOr Gerlitz 
5184d80cc0aSOr Gerlitz static void fl_set_key_ip(struct nlattr **tb,
5194d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *key,
5204d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *mask)
5214d80cc0aSOr Gerlitz {
5224d80cc0aSOr Gerlitz 		fl_set_key_val(tb, &key->tos, TCA_FLOWER_KEY_IP_TOS,
5234d80cc0aSOr Gerlitz 			       &mask->tos, TCA_FLOWER_KEY_IP_TOS_MASK,
5244d80cc0aSOr Gerlitz 			       sizeof(key->tos));
5254d80cc0aSOr Gerlitz 
5264d80cc0aSOr Gerlitz 		fl_set_key_val(tb, &key->ttl, TCA_FLOWER_KEY_IP_TTL,
5274d80cc0aSOr Gerlitz 			       &mask->ttl, TCA_FLOWER_KEY_IP_TTL_MASK,
5284d80cc0aSOr Gerlitz 			       sizeof(key->ttl));
5294d80cc0aSOr Gerlitz }
5304d80cc0aSOr Gerlitz 
53177b9900eSJiri Pirko static int fl_set_key(struct net *net, struct nlattr **tb,
5321057c55fSAlexander Aring 		      struct fl_flow_key *key, struct fl_flow_key *mask,
5331057c55fSAlexander Aring 		      struct netlink_ext_ack *extack)
53477b9900eSJiri Pirko {
5359399ae9aSHadar Hen Zion 	__be16 ethertype;
536d9724772SOr Gerlitz 	int ret = 0;
537dd3aa3b5SBrian Haley #ifdef CONFIG_NET_CLS_IND
53877b9900eSJiri Pirko 	if (tb[TCA_FLOWER_INDEV]) {
5391057c55fSAlexander Aring 		int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV], extack);
54077b9900eSJiri Pirko 		if (err < 0)
54177b9900eSJiri Pirko 			return err;
54277b9900eSJiri Pirko 		key->indev_ifindex = err;
54377b9900eSJiri Pirko 		mask->indev_ifindex = 0xffffffff;
54477b9900eSJiri Pirko 	}
545dd3aa3b5SBrian Haley #endif
54677b9900eSJiri Pirko 
54777b9900eSJiri Pirko 	fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
54877b9900eSJiri Pirko 		       mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
54977b9900eSJiri Pirko 		       sizeof(key->eth.dst));
55077b9900eSJiri Pirko 	fl_set_key_val(tb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
55177b9900eSJiri Pirko 		       mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
55277b9900eSJiri Pirko 		       sizeof(key->eth.src));
55366530bdfSJamal Hadi Salim 
5540b498a52SArnd Bergmann 	if (tb[TCA_FLOWER_KEY_ETH_TYPE]) {
5559399ae9aSHadar Hen Zion 		ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_ETH_TYPE]);
5569399ae9aSHadar Hen Zion 
5579399ae9aSHadar Hen Zion 		if (ethertype == htons(ETH_P_8021Q)) {
5589399ae9aSHadar Hen Zion 			fl_set_key_vlan(tb, &key->vlan, &mask->vlan);
5599399ae9aSHadar Hen Zion 			fl_set_key_val(tb, &key->basic.n_proto,
5609399ae9aSHadar Hen Zion 				       TCA_FLOWER_KEY_VLAN_ETH_TYPE,
56177b9900eSJiri Pirko 				       &mask->basic.n_proto, TCA_FLOWER_UNSPEC,
56277b9900eSJiri Pirko 				       sizeof(key->basic.n_proto));
5639399ae9aSHadar Hen Zion 		} else {
5649399ae9aSHadar Hen Zion 			key->basic.n_proto = ethertype;
5659399ae9aSHadar Hen Zion 			mask->basic.n_proto = cpu_to_be16(~0);
5669399ae9aSHadar Hen Zion 		}
5670b498a52SArnd Bergmann 	}
56866530bdfSJamal Hadi Salim 
56977b9900eSJiri Pirko 	if (key->basic.n_proto == htons(ETH_P_IP) ||
57077b9900eSJiri Pirko 	    key->basic.n_proto == htons(ETH_P_IPV6)) {
57177b9900eSJiri Pirko 		fl_set_key_val(tb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
57277b9900eSJiri Pirko 			       &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
57377b9900eSJiri Pirko 			       sizeof(key->basic.ip_proto));
5744d80cc0aSOr Gerlitz 		fl_set_key_ip(tb, &key->ip, &mask->ip);
57577b9900eSJiri Pirko 	}
57666530bdfSJamal Hadi Salim 
57766530bdfSJamal Hadi Salim 	if (tb[TCA_FLOWER_KEY_IPV4_SRC] || tb[TCA_FLOWER_KEY_IPV4_DST]) {
57866530bdfSJamal Hadi Salim 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
579970bfcd0SPaul Blakey 		mask->control.addr_type = ~0;
58077b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
58177b9900eSJiri Pirko 			       &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
58277b9900eSJiri Pirko 			       sizeof(key->ipv4.src));
58377b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
58477b9900eSJiri Pirko 			       &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
58577b9900eSJiri Pirko 			       sizeof(key->ipv4.dst));
58666530bdfSJamal Hadi Salim 	} else if (tb[TCA_FLOWER_KEY_IPV6_SRC] || tb[TCA_FLOWER_KEY_IPV6_DST]) {
58766530bdfSJamal Hadi Salim 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
588970bfcd0SPaul Blakey 		mask->control.addr_type = ~0;
58977b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
59077b9900eSJiri Pirko 			       &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
59177b9900eSJiri Pirko 			       sizeof(key->ipv6.src));
59277b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
59377b9900eSJiri Pirko 			       &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
59477b9900eSJiri Pirko 			       sizeof(key->ipv6.dst));
59577b9900eSJiri Pirko 	}
59666530bdfSJamal Hadi Salim 
59777b9900eSJiri Pirko 	if (key->basic.ip_proto == IPPROTO_TCP) {
59877b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
599aa72d708SOr Gerlitz 			       &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
60077b9900eSJiri Pirko 			       sizeof(key->tp.src));
60177b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
602aa72d708SOr Gerlitz 			       &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
60377b9900eSJiri Pirko 			       sizeof(key->tp.dst));
604fdfc7dd6SJiri Pirko 		fl_set_key_val(tb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS,
605fdfc7dd6SJiri Pirko 			       &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK,
606fdfc7dd6SJiri Pirko 			       sizeof(key->tcp.flags));
60777b9900eSJiri Pirko 	} else if (key->basic.ip_proto == IPPROTO_UDP) {
60877b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
609aa72d708SOr Gerlitz 			       &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
61077b9900eSJiri Pirko 			       sizeof(key->tp.src));
61177b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
612aa72d708SOr Gerlitz 			       &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
61377b9900eSJiri Pirko 			       sizeof(key->tp.dst));
6145976c5f4SSimon Horman 	} else if (key->basic.ip_proto == IPPROTO_SCTP) {
6155976c5f4SSimon Horman 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
6165976c5f4SSimon Horman 			       &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
6175976c5f4SSimon Horman 			       sizeof(key->tp.src));
6185976c5f4SSimon Horman 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
6195976c5f4SSimon Horman 			       &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
6205976c5f4SSimon Horman 			       sizeof(key->tp.dst));
6217b684884SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_IP) &&
6227b684884SSimon Horman 		   key->basic.ip_proto == IPPROTO_ICMP) {
6237b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV4_TYPE,
6247b684884SSimon Horman 			       &mask->icmp.type,
6257b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,
6267b684884SSimon Horman 			       sizeof(key->icmp.type));
6277b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE,
6287b684884SSimon Horman 			       &mask->icmp.code,
6297b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
6307b684884SSimon Horman 			       sizeof(key->icmp.code));
6317b684884SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_IPV6) &&
6327b684884SSimon Horman 		   key->basic.ip_proto == IPPROTO_ICMPV6) {
6337b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV6_TYPE,
6347b684884SSimon Horman 			       &mask->icmp.type,
6357b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
6367b684884SSimon Horman 			       sizeof(key->icmp.type));
637040587afSSimon Horman 		fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV6_CODE,
6387b684884SSimon Horman 			       &mask->icmp.code,
639040587afSSimon Horman 			       TCA_FLOWER_KEY_ICMPV6_CODE_MASK,
6407b684884SSimon Horman 			       sizeof(key->icmp.code));
641a577d8f7SBenjamin LaHaise 	} else if (key->basic.n_proto == htons(ETH_P_MPLS_UC) ||
642a577d8f7SBenjamin LaHaise 		   key->basic.n_proto == htons(ETH_P_MPLS_MC)) {
6431a7fca63SBenjamin LaHaise 		ret = fl_set_key_mpls(tb, &key->mpls, &mask->mpls);
6441a7fca63SBenjamin LaHaise 		if (ret)
6451a7fca63SBenjamin LaHaise 			return ret;
64699d31326SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_ARP) ||
64799d31326SSimon Horman 		   key->basic.n_proto == htons(ETH_P_RARP)) {
64899d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.sip, TCA_FLOWER_KEY_ARP_SIP,
64999d31326SSimon Horman 			       &mask->arp.sip, TCA_FLOWER_KEY_ARP_SIP_MASK,
65099d31326SSimon Horman 			       sizeof(key->arp.sip));
65199d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.tip, TCA_FLOWER_KEY_ARP_TIP,
65299d31326SSimon Horman 			       &mask->arp.tip, TCA_FLOWER_KEY_ARP_TIP_MASK,
65399d31326SSimon Horman 			       sizeof(key->arp.tip));
65499d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.op, TCA_FLOWER_KEY_ARP_OP,
65599d31326SSimon Horman 			       &mask->arp.op, TCA_FLOWER_KEY_ARP_OP_MASK,
65699d31326SSimon Horman 			       sizeof(key->arp.op));
65799d31326SSimon Horman 		fl_set_key_val(tb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA,
65899d31326SSimon Horman 			       mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK,
65999d31326SSimon Horman 			       sizeof(key->arp.sha));
66099d31326SSimon Horman 		fl_set_key_val(tb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA,
66199d31326SSimon Horman 			       mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK,
66299d31326SSimon Horman 			       sizeof(key->arp.tha));
66377b9900eSJiri Pirko 	}
66477b9900eSJiri Pirko 
665bc3103f1SAmir Vadai 	if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] ||
666bc3103f1SAmir Vadai 	    tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) {
667bc3103f1SAmir Vadai 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
668970bfcd0SPaul Blakey 		mask->enc_control.addr_type = ~0;
669bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv4.src,
670bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_SRC,
671bc3103f1SAmir Vadai 			       &mask->enc_ipv4.src,
672bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
673bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv4.src));
674bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv4.dst,
675bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_DST,
676bc3103f1SAmir Vadai 			       &mask->enc_ipv4.dst,
677bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
678bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv4.dst));
679bc3103f1SAmir Vadai 	}
680bc3103f1SAmir Vadai 
681bc3103f1SAmir Vadai 	if (tb[TCA_FLOWER_KEY_ENC_IPV6_SRC] ||
682bc3103f1SAmir Vadai 	    tb[TCA_FLOWER_KEY_ENC_IPV6_DST]) {
683bc3103f1SAmir Vadai 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
684970bfcd0SPaul Blakey 		mask->enc_control.addr_type = ~0;
685bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv6.src,
686bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_SRC,
687bc3103f1SAmir Vadai 			       &mask->enc_ipv6.src,
688bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
689bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv6.src));
690bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv6.dst,
691bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_DST,
692bc3103f1SAmir Vadai 			       &mask->enc_ipv6.dst,
693bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
694bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv6.dst));
695bc3103f1SAmir Vadai 	}
696bc3103f1SAmir Vadai 
697bc3103f1SAmir Vadai 	fl_set_key_val(tb, &key->enc_key_id.keyid, TCA_FLOWER_KEY_ENC_KEY_ID,
698eb523f42SHadar Hen Zion 		       &mask->enc_key_id.keyid, TCA_FLOWER_UNSPEC,
699bc3103f1SAmir Vadai 		       sizeof(key->enc_key_id.keyid));
700bc3103f1SAmir Vadai 
701f4d997fdSHadar Hen Zion 	fl_set_key_val(tb, &key->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
702f4d997fdSHadar Hen Zion 		       &mask->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
703f4d997fdSHadar Hen Zion 		       sizeof(key->enc_tp.src));
704f4d997fdSHadar Hen Zion 
705f4d997fdSHadar Hen Zion 	fl_set_key_val(tb, &key->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
706f4d997fdSHadar Hen Zion 		       &mask->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
707f4d997fdSHadar Hen Zion 		       sizeof(key->enc_tp.dst));
708f4d997fdSHadar Hen Zion 
709d9724772SOr Gerlitz 	if (tb[TCA_FLOWER_KEY_FLAGS])
710d9724772SOr Gerlitz 		ret = fl_set_key_flags(tb, &key->control.flags, &mask->control.flags);
711faa3ffceSOr Gerlitz 
712d9724772SOr Gerlitz 	return ret;
71377b9900eSJiri Pirko }
71477b9900eSJiri Pirko 
71577b9900eSJiri Pirko static bool fl_mask_eq(struct fl_flow_mask *mask1,
71677b9900eSJiri Pirko 		       struct fl_flow_mask *mask2)
71777b9900eSJiri Pirko {
71877b9900eSJiri Pirko 	const long *lmask1 = fl_key_get_start(&mask1->key, mask1);
71977b9900eSJiri Pirko 	const long *lmask2 = fl_key_get_start(&mask2->key, mask2);
72077b9900eSJiri Pirko 
72177b9900eSJiri Pirko 	return !memcmp(&mask1->range, &mask2->range, sizeof(mask1->range)) &&
72277b9900eSJiri Pirko 	       !memcmp(lmask1, lmask2, fl_mask_range(mask1));
72377b9900eSJiri Pirko }
72477b9900eSJiri Pirko 
72577b9900eSJiri Pirko static const struct rhashtable_params fl_ht_params = {
72677b9900eSJiri Pirko 	.key_offset = offsetof(struct cls_fl_filter, mkey), /* base offset */
72777b9900eSJiri Pirko 	.head_offset = offsetof(struct cls_fl_filter, ht_node),
72877b9900eSJiri Pirko 	.automatic_shrinking = true,
72977b9900eSJiri Pirko };
73077b9900eSJiri Pirko 
73177b9900eSJiri Pirko static int fl_init_hashtable(struct cls_fl_head *head,
73277b9900eSJiri Pirko 			     struct fl_flow_mask *mask)
73377b9900eSJiri Pirko {
73477b9900eSJiri Pirko 	head->ht_params = fl_ht_params;
73577b9900eSJiri Pirko 	head->ht_params.key_len = fl_mask_range(mask);
73677b9900eSJiri Pirko 	head->ht_params.key_offset += mask->range.start;
73777b9900eSJiri Pirko 
73877b9900eSJiri Pirko 	return rhashtable_init(&head->ht, &head->ht_params);
73977b9900eSJiri Pirko }
74077b9900eSJiri Pirko 
74177b9900eSJiri Pirko #define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member)
74277b9900eSJiri Pirko #define FL_KEY_MEMBER_SIZE(member) (sizeof(((struct fl_flow_key *) 0)->member))
74377b9900eSJiri Pirko 
744339ba878SHadar Hen Zion #define FL_KEY_IS_MASKED(mask, member)						\
745339ba878SHadar Hen Zion 	memchr_inv(((char *)mask) + FL_KEY_MEMBER_OFFSET(member),		\
746339ba878SHadar Hen Zion 		   0, FL_KEY_MEMBER_SIZE(member))				\
74777b9900eSJiri Pirko 
74877b9900eSJiri Pirko #define FL_KEY_SET(keys, cnt, id, member)					\
74977b9900eSJiri Pirko 	do {									\
75077b9900eSJiri Pirko 		keys[cnt].key_id = id;						\
75177b9900eSJiri Pirko 		keys[cnt].offset = FL_KEY_MEMBER_OFFSET(member);		\
75277b9900eSJiri Pirko 		cnt++;								\
75377b9900eSJiri Pirko 	} while(0);
75477b9900eSJiri Pirko 
755339ba878SHadar Hen Zion #define FL_KEY_SET_IF_MASKED(mask, keys, cnt, id, member)			\
75677b9900eSJiri Pirko 	do {									\
757339ba878SHadar Hen Zion 		if (FL_KEY_IS_MASKED(mask, member))				\
75877b9900eSJiri Pirko 			FL_KEY_SET(keys, cnt, id, member);			\
75977b9900eSJiri Pirko 	} while(0);
76077b9900eSJiri Pirko 
76177b9900eSJiri Pirko static void fl_init_dissector(struct cls_fl_head *head,
76277b9900eSJiri Pirko 			      struct fl_flow_mask *mask)
76377b9900eSJiri Pirko {
76477b9900eSJiri Pirko 	struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX];
76577b9900eSJiri Pirko 	size_t cnt = 0;
76677b9900eSJiri Pirko 
76742aecaa9STom Herbert 	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control);
76877b9900eSJiri Pirko 	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic);
769339ba878SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
77077b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_ETH_ADDRS, eth);
771339ba878SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
77277b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4);
773339ba878SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
77477b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6);
775339ba878SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
77677b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_PORTS, tp);
7779399ae9aSHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
7784d80cc0aSOr Gerlitz 			     FLOW_DISSECTOR_KEY_IP, ip);
7794d80cc0aSOr Gerlitz 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
780fdfc7dd6SJiri Pirko 			     FLOW_DISSECTOR_KEY_TCP, tcp);
781fdfc7dd6SJiri Pirko 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
7827b684884SSimon Horman 			     FLOW_DISSECTOR_KEY_ICMP, icmp);
7837b684884SSimon Horman 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
78499d31326SSimon Horman 			     FLOW_DISSECTOR_KEY_ARP, arp);
78599d31326SSimon Horman 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
786a577d8f7SBenjamin LaHaise 			     FLOW_DISSECTOR_KEY_MPLS, mpls);
787a577d8f7SBenjamin LaHaise 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
7889399ae9aSHadar Hen Zion 			     FLOW_DISSECTOR_KEY_VLAN, vlan);
789519d1052SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
790519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_KEYID, enc_key_id);
791519d1052SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
792519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, enc_ipv4);
793519d1052SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
794519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, enc_ipv6);
795519d1052SHadar Hen Zion 	if (FL_KEY_IS_MASKED(&mask->key, enc_ipv4) ||
796519d1052SHadar Hen Zion 	    FL_KEY_IS_MASKED(&mask->key, enc_ipv6))
797519d1052SHadar Hen Zion 		FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_ENC_CONTROL,
798519d1052SHadar Hen Zion 			   enc_control);
799f4d997fdSHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
800f4d997fdSHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp);
80177b9900eSJiri Pirko 
80277b9900eSJiri Pirko 	skb_flow_dissector_init(&head->dissector, keys, cnt);
80377b9900eSJiri Pirko }
80477b9900eSJiri Pirko 
80577b9900eSJiri Pirko static int fl_check_assign_mask(struct cls_fl_head *head,
80677b9900eSJiri Pirko 				struct fl_flow_mask *mask)
80777b9900eSJiri Pirko {
80877b9900eSJiri Pirko 	int err;
80977b9900eSJiri Pirko 
81077b9900eSJiri Pirko 	if (head->mask_assigned) {
81177b9900eSJiri Pirko 		if (!fl_mask_eq(&head->mask, mask))
81277b9900eSJiri Pirko 			return -EINVAL;
81377b9900eSJiri Pirko 		else
81477b9900eSJiri Pirko 			return 0;
81577b9900eSJiri Pirko 	}
81677b9900eSJiri Pirko 
81777b9900eSJiri Pirko 	/* Mask is not assigned yet. So assign it and init hashtable
81877b9900eSJiri Pirko 	 * according to that.
81977b9900eSJiri Pirko 	 */
82077b9900eSJiri Pirko 	err = fl_init_hashtable(head, mask);
82177b9900eSJiri Pirko 	if (err)
82277b9900eSJiri Pirko 		return err;
82377b9900eSJiri Pirko 	memcpy(&head->mask, mask, sizeof(head->mask));
82477b9900eSJiri Pirko 	head->mask_assigned = true;
82577b9900eSJiri Pirko 
82677b9900eSJiri Pirko 	fl_init_dissector(head, mask);
82777b9900eSJiri Pirko 
82877b9900eSJiri Pirko 	return 0;
82977b9900eSJiri Pirko }
83077b9900eSJiri Pirko 
83177b9900eSJiri Pirko static int fl_set_parms(struct net *net, struct tcf_proto *tp,
83277b9900eSJiri Pirko 			struct cls_fl_filter *f, struct fl_flow_mask *mask,
83377b9900eSJiri Pirko 			unsigned long base, struct nlattr **tb,
83450a56190SAlexander Aring 			struct nlattr *est, bool ovr,
83550a56190SAlexander Aring 			struct netlink_ext_ack *extack)
83677b9900eSJiri Pirko {
83777b9900eSJiri Pirko 	int err;
83877b9900eSJiri Pirko 
83950a56190SAlexander Aring 	err = tcf_exts_validate(net, tp, tb, est, &f->exts, ovr, extack);
84077b9900eSJiri Pirko 	if (err < 0)
84177b9900eSJiri Pirko 		return err;
84277b9900eSJiri Pirko 
84377b9900eSJiri Pirko 	if (tb[TCA_FLOWER_CLASSID]) {
84477b9900eSJiri Pirko 		f->res.classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]);
84577b9900eSJiri Pirko 		tcf_bind_filter(tp, &f->res, base);
84677b9900eSJiri Pirko 	}
84777b9900eSJiri Pirko 
8481057c55fSAlexander Aring 	err = fl_set_key(net, tb, &f->key, &mask->key, extack);
84977b9900eSJiri Pirko 	if (err)
85045507529SJiri Pirko 		return err;
85177b9900eSJiri Pirko 
85277b9900eSJiri Pirko 	fl_mask_update_range(mask);
85377b9900eSJiri Pirko 	fl_set_masked_key(&f->mkey, &f->key, mask);
85477b9900eSJiri Pirko 
85577b9900eSJiri Pirko 	return 0;
85677b9900eSJiri Pirko }
85777b9900eSJiri Pirko 
85877b9900eSJiri Pirko static int fl_change(struct net *net, struct sk_buff *in_skb,
85977b9900eSJiri Pirko 		     struct tcf_proto *tp, unsigned long base,
86077b9900eSJiri Pirko 		     u32 handle, struct nlattr **tca,
8617306db38SAlexander Aring 		     void **arg, bool ovr, struct netlink_ext_ack *extack)
86277b9900eSJiri Pirko {
86377b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
8648113c095SWANG Cong 	struct cls_fl_filter *fold = *arg;
86577b9900eSJiri Pirko 	struct cls_fl_filter *fnew;
86639b7b6a6SArnd Bergmann 	struct nlattr **tb;
86777b9900eSJiri Pirko 	struct fl_flow_mask mask = {};
868c15ab236SChris Mi 	unsigned long idr_index;
86977b9900eSJiri Pirko 	int err;
87077b9900eSJiri Pirko 
87177b9900eSJiri Pirko 	if (!tca[TCA_OPTIONS])
87277b9900eSJiri Pirko 		return -EINVAL;
87377b9900eSJiri Pirko 
87439b7b6a6SArnd Bergmann 	tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL);
87539b7b6a6SArnd Bergmann 	if (!tb)
87639b7b6a6SArnd Bergmann 		return -ENOBUFS;
87739b7b6a6SArnd Bergmann 
878fceb6435SJohannes Berg 	err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS],
879fceb6435SJohannes Berg 			       fl_policy, NULL);
88077b9900eSJiri Pirko 	if (err < 0)
88139b7b6a6SArnd Bergmann 		goto errout_tb;
88277b9900eSJiri Pirko 
88339b7b6a6SArnd Bergmann 	if (fold && handle && fold->handle != handle) {
88439b7b6a6SArnd Bergmann 		err = -EINVAL;
88539b7b6a6SArnd Bergmann 		goto errout_tb;
88639b7b6a6SArnd Bergmann 	}
88777b9900eSJiri Pirko 
88877b9900eSJiri Pirko 	fnew = kzalloc(sizeof(*fnew), GFP_KERNEL);
88939b7b6a6SArnd Bergmann 	if (!fnew) {
89039b7b6a6SArnd Bergmann 		err = -ENOBUFS;
89139b7b6a6SArnd Bergmann 		goto errout_tb;
89239b7b6a6SArnd Bergmann 	}
89377b9900eSJiri Pirko 
894b9a24bb7SWANG Cong 	err = tcf_exts_init(&fnew->exts, TCA_FLOWER_ACT, 0);
895b9a24bb7SWANG Cong 	if (err < 0)
896b9a24bb7SWANG Cong 		goto errout;
89777b9900eSJiri Pirko 
89877b9900eSJiri Pirko 	if (!handle) {
899c15ab236SChris Mi 		err = idr_alloc_ext(&head->handle_idr, fnew, &idr_index,
900c15ab236SChris Mi 				    1, 0x80000000, GFP_KERNEL);
901c15ab236SChris Mi 		if (err)
90277b9900eSJiri Pirko 			goto errout;
903c15ab236SChris Mi 		fnew->handle = idr_index;
90477b9900eSJiri Pirko 	}
905c15ab236SChris Mi 
906c15ab236SChris Mi 	/* user specifies a handle and it doesn't exist */
907c15ab236SChris Mi 	if (handle && !fold) {
908c15ab236SChris Mi 		err = idr_alloc_ext(&head->handle_idr, fnew, &idr_index,
909c15ab236SChris Mi 				    handle, handle + 1, GFP_KERNEL);
910c15ab236SChris Mi 		if (err)
911c15ab236SChris Mi 			goto errout;
912c15ab236SChris Mi 		fnew->handle = idr_index;
91377b9900eSJiri Pirko 	}
91477b9900eSJiri Pirko 
915e69985c6SAmir Vadai 	if (tb[TCA_FLOWER_FLAGS]) {
916e69985c6SAmir Vadai 		fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
917e69985c6SAmir Vadai 
918e69985c6SAmir Vadai 		if (!tc_flags_valid(fnew->flags)) {
919e69985c6SAmir Vadai 			err = -EINVAL;
920fe2502e4SCong Wang 			goto errout_idr;
921e69985c6SAmir Vadai 		}
922e69985c6SAmir Vadai 	}
9235b33f488SAmir Vadai 
92450a56190SAlexander Aring 	err = fl_set_parms(net, tp, fnew, &mask, base, tb, tca[TCA_RATE], ovr,
92550a56190SAlexander Aring 			   extack);
92677b9900eSJiri Pirko 	if (err)
927fe2502e4SCong Wang 		goto errout_idr;
92877b9900eSJiri Pirko 
92977b9900eSJiri Pirko 	err = fl_check_assign_mask(head, &mask);
93077b9900eSJiri Pirko 	if (err)
931fe2502e4SCong Wang 		goto errout_idr;
93277b9900eSJiri Pirko 
933e8eb36cdSAmir Vadai 	if (!tc_skip_sw(fnew->flags)) {
934a3308d8fSPaul Blakey 		if (!fold && fl_lookup(head, &fnew->mkey)) {
935a3308d8fSPaul Blakey 			err = -EEXIST;
936fe2502e4SCong Wang 			goto errout_idr;
937a3308d8fSPaul Blakey 		}
938a3308d8fSPaul Blakey 
93977b9900eSJiri Pirko 		err = rhashtable_insert_fast(&head->ht, &fnew->ht_node,
94077b9900eSJiri Pirko 					     head->ht_params);
94177b9900eSJiri Pirko 		if (err)
942fe2502e4SCong Wang 			goto errout_idr;
943e69985c6SAmir Vadai 	}
9445b33f488SAmir Vadai 
94579685219SHadar Hen Zion 	if (!tc_skip_hw(fnew->flags)) {
946e8eb36cdSAmir Vadai 		err = fl_hw_replace_filter(tp,
9475b33f488SAmir Vadai 					   &head->dissector,
9485b33f488SAmir Vadai 					   &mask.key,
94941002038SQuentin Monnet 					   fnew,
95041002038SQuentin Monnet 					   extack);
951e8eb36cdSAmir Vadai 		if (err)
952fe2502e4SCong Wang 			goto errout_idr;
95379685219SHadar Hen Zion 	}
9545b33f488SAmir Vadai 
95555593960SOr Gerlitz 	if (!tc_in_hw(fnew->flags))
95655593960SOr Gerlitz 		fnew->flags |= TCA_CLS_FLAGS_NOT_IN_HW;
95755593960SOr Gerlitz 
9585b33f488SAmir Vadai 	if (fold) {
959725cbb62SJiri Pirko 		if (!tc_skip_sw(fold->flags))
96077b9900eSJiri Pirko 			rhashtable_remove_fast(&head->ht, &fold->ht_node,
96177b9900eSJiri Pirko 					       head->ht_params);
96279685219SHadar Hen Zion 		if (!tc_skip_hw(fold->flags))
9631b0f8037SJakub Kicinski 			fl_hw_destroy_filter(tp, fold, NULL);
9645b33f488SAmir Vadai 	}
96577b9900eSJiri Pirko 
9668113c095SWANG Cong 	*arg = fnew;
96777b9900eSJiri Pirko 
96877b9900eSJiri Pirko 	if (fold) {
969c15ab236SChris Mi 		fnew->handle = handle;
970c15ab236SChris Mi 		idr_replace_ext(&head->handle_idr, fnew, fnew->handle);
971ff3532f2SDaniel Borkmann 		list_replace_rcu(&fold->list, &fnew->list);
97277b9900eSJiri Pirko 		tcf_unbind_filter(tp, &fold->res);
9730dadc117SCong Wang 		tcf_exts_get_net(&fold->exts);
97477b9900eSJiri Pirko 		call_rcu(&fold->rcu, fl_destroy_filter);
97577b9900eSJiri Pirko 	} else {
97677b9900eSJiri Pirko 		list_add_tail_rcu(&fnew->list, &head->filters);
97777b9900eSJiri Pirko 	}
97877b9900eSJiri Pirko 
97939b7b6a6SArnd Bergmann 	kfree(tb);
98077b9900eSJiri Pirko 	return 0;
98177b9900eSJiri Pirko 
982fe2502e4SCong Wang errout_idr:
983fe2502e4SCong Wang 	if (fnew->handle)
984*9c160941SMatthew Wilcox 		idr_remove(&head->handle_idr, fnew->handle);
98577b9900eSJiri Pirko errout:
986b9a24bb7SWANG Cong 	tcf_exts_destroy(&fnew->exts);
98777b9900eSJiri Pirko 	kfree(fnew);
98839b7b6a6SArnd Bergmann errout_tb:
98939b7b6a6SArnd Bergmann 	kfree(tb);
99077b9900eSJiri Pirko 	return err;
99177b9900eSJiri Pirko }
99277b9900eSJiri Pirko 
993571acf21SAlexander Aring static int fl_delete(struct tcf_proto *tp, void *arg, bool *last,
994571acf21SAlexander Aring 		     struct netlink_ext_ack *extack)
99577b9900eSJiri Pirko {
99677b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
9978113c095SWANG Cong 	struct cls_fl_filter *f = arg;
99877b9900eSJiri Pirko 
999725cbb62SJiri Pirko 	if (!tc_skip_sw(f->flags))
100077b9900eSJiri Pirko 		rhashtable_remove_fast(&head->ht, &f->ht_node,
100177b9900eSJiri Pirko 				       head->ht_params);
10021b0f8037SJakub Kicinski 	__fl_delete(tp, f, extack);
1003763dbf63SWANG Cong 	*last = list_empty(&head->filters);
100477b9900eSJiri Pirko 	return 0;
100577b9900eSJiri Pirko }
100677b9900eSJiri Pirko 
100777b9900eSJiri Pirko static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg)
100877b9900eSJiri Pirko {
100977b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
101077b9900eSJiri Pirko 	struct cls_fl_filter *f;
101177b9900eSJiri Pirko 
101277b9900eSJiri Pirko 	list_for_each_entry_rcu(f, &head->filters, list) {
101377b9900eSJiri Pirko 		if (arg->count < arg->skip)
101477b9900eSJiri Pirko 			goto skip;
10158113c095SWANG Cong 		if (arg->fn(tp, f, arg) < 0) {
101677b9900eSJiri Pirko 			arg->stop = 1;
101777b9900eSJiri Pirko 			break;
101877b9900eSJiri Pirko 		}
101977b9900eSJiri Pirko skip:
102077b9900eSJiri Pirko 		arg->count++;
102177b9900eSJiri Pirko 	}
102277b9900eSJiri Pirko }
102377b9900eSJiri Pirko 
102477b9900eSJiri Pirko static int fl_dump_key_val(struct sk_buff *skb,
102577b9900eSJiri Pirko 			   void *val, int val_type,
102677b9900eSJiri Pirko 			   void *mask, int mask_type, int len)
102777b9900eSJiri Pirko {
102877b9900eSJiri Pirko 	int err;
102977b9900eSJiri Pirko 
103077b9900eSJiri Pirko 	if (!memchr_inv(mask, 0, len))
103177b9900eSJiri Pirko 		return 0;
103277b9900eSJiri Pirko 	err = nla_put(skb, val_type, len, val);
103377b9900eSJiri Pirko 	if (err)
103477b9900eSJiri Pirko 		return err;
103577b9900eSJiri Pirko 	if (mask_type != TCA_FLOWER_UNSPEC) {
103677b9900eSJiri Pirko 		err = nla_put(skb, mask_type, len, mask);
103777b9900eSJiri Pirko 		if (err)
103877b9900eSJiri Pirko 			return err;
103977b9900eSJiri Pirko 	}
104077b9900eSJiri Pirko 	return 0;
104177b9900eSJiri Pirko }
104277b9900eSJiri Pirko 
1043a577d8f7SBenjamin LaHaise static int fl_dump_key_mpls(struct sk_buff *skb,
1044a577d8f7SBenjamin LaHaise 			    struct flow_dissector_key_mpls *mpls_key,
1045a577d8f7SBenjamin LaHaise 			    struct flow_dissector_key_mpls *mpls_mask)
1046a577d8f7SBenjamin LaHaise {
1047a577d8f7SBenjamin LaHaise 	int err;
1048a577d8f7SBenjamin LaHaise 
1049a577d8f7SBenjamin LaHaise 	if (!memchr_inv(mpls_mask, 0, sizeof(*mpls_mask)))
1050a577d8f7SBenjamin LaHaise 		return 0;
1051a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_ttl) {
1052a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TTL,
1053a577d8f7SBenjamin LaHaise 				 mpls_key->mpls_ttl);
1054a577d8f7SBenjamin LaHaise 		if (err)
1055a577d8f7SBenjamin LaHaise 			return err;
1056a577d8f7SBenjamin LaHaise 	}
1057a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_tc) {
1058a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TC,
1059a577d8f7SBenjamin LaHaise 				 mpls_key->mpls_tc);
1060a577d8f7SBenjamin LaHaise 		if (err)
1061a577d8f7SBenjamin LaHaise 			return err;
1062a577d8f7SBenjamin LaHaise 	}
1063a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_label) {
1064a577d8f7SBenjamin LaHaise 		err = nla_put_u32(skb, TCA_FLOWER_KEY_MPLS_LABEL,
1065a577d8f7SBenjamin LaHaise 				  mpls_key->mpls_label);
1066a577d8f7SBenjamin LaHaise 		if (err)
1067a577d8f7SBenjamin LaHaise 			return err;
1068a577d8f7SBenjamin LaHaise 	}
1069a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_bos) {
1070a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_BOS,
1071a577d8f7SBenjamin LaHaise 				 mpls_key->mpls_bos);
1072a577d8f7SBenjamin LaHaise 		if (err)
1073a577d8f7SBenjamin LaHaise 			return err;
1074a577d8f7SBenjamin LaHaise 	}
1075a577d8f7SBenjamin LaHaise 	return 0;
1076a577d8f7SBenjamin LaHaise }
1077a577d8f7SBenjamin LaHaise 
10784d80cc0aSOr Gerlitz static int fl_dump_key_ip(struct sk_buff *skb,
10794d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *key,
10804d80cc0aSOr Gerlitz 			  struct flow_dissector_key_ip *mask)
10814d80cc0aSOr Gerlitz {
10824d80cc0aSOr Gerlitz 	if (fl_dump_key_val(skb, &key->tos, TCA_FLOWER_KEY_IP_TOS, &mask->tos,
10834d80cc0aSOr Gerlitz 			    TCA_FLOWER_KEY_IP_TOS_MASK, sizeof(key->tos)) ||
10844d80cc0aSOr Gerlitz 	    fl_dump_key_val(skb, &key->ttl, TCA_FLOWER_KEY_IP_TTL, &mask->ttl,
10854d80cc0aSOr Gerlitz 			    TCA_FLOWER_KEY_IP_TTL_MASK, sizeof(key->ttl)))
10864d80cc0aSOr Gerlitz 		return -1;
10874d80cc0aSOr Gerlitz 
10884d80cc0aSOr Gerlitz 	return 0;
10894d80cc0aSOr Gerlitz }
10904d80cc0aSOr Gerlitz 
10919399ae9aSHadar Hen Zion static int fl_dump_key_vlan(struct sk_buff *skb,
10929399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *vlan_key,
10939399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *vlan_mask)
10949399ae9aSHadar Hen Zion {
10959399ae9aSHadar Hen Zion 	int err;
10969399ae9aSHadar Hen Zion 
10979399ae9aSHadar Hen Zion 	if (!memchr_inv(vlan_mask, 0, sizeof(*vlan_mask)))
10989399ae9aSHadar Hen Zion 		return 0;
10999399ae9aSHadar Hen Zion 	if (vlan_mask->vlan_id) {
11009399ae9aSHadar Hen Zion 		err = nla_put_u16(skb, TCA_FLOWER_KEY_VLAN_ID,
11019399ae9aSHadar Hen Zion 				  vlan_key->vlan_id);
11029399ae9aSHadar Hen Zion 		if (err)
11039399ae9aSHadar Hen Zion 			return err;
11049399ae9aSHadar Hen Zion 	}
11059399ae9aSHadar Hen Zion 	if (vlan_mask->vlan_priority) {
11069399ae9aSHadar Hen Zion 		err = nla_put_u8(skb, TCA_FLOWER_KEY_VLAN_PRIO,
11079399ae9aSHadar Hen Zion 				 vlan_key->vlan_priority);
11089399ae9aSHadar Hen Zion 		if (err)
11099399ae9aSHadar Hen Zion 			return err;
11109399ae9aSHadar Hen Zion 	}
11119399ae9aSHadar Hen Zion 	return 0;
11129399ae9aSHadar Hen Zion }
11139399ae9aSHadar Hen Zion 
1114faa3ffceSOr Gerlitz static void fl_get_key_flag(u32 dissector_key, u32 dissector_mask,
1115faa3ffceSOr Gerlitz 			    u32 *flower_key, u32 *flower_mask,
1116faa3ffceSOr Gerlitz 			    u32 flower_flag_bit, u32 dissector_flag_bit)
1117faa3ffceSOr Gerlitz {
1118faa3ffceSOr Gerlitz 	if (dissector_mask & dissector_flag_bit) {
1119faa3ffceSOr Gerlitz 		*flower_mask |= flower_flag_bit;
1120faa3ffceSOr Gerlitz 		if (dissector_key & dissector_flag_bit)
1121faa3ffceSOr Gerlitz 			*flower_key |= flower_flag_bit;
1122faa3ffceSOr Gerlitz 	}
1123faa3ffceSOr Gerlitz }
1124faa3ffceSOr Gerlitz 
1125faa3ffceSOr Gerlitz static int fl_dump_key_flags(struct sk_buff *skb, u32 flags_key, u32 flags_mask)
1126faa3ffceSOr Gerlitz {
1127faa3ffceSOr Gerlitz 	u32 key, mask;
1128faa3ffceSOr Gerlitz 	__be32 _key, _mask;
1129faa3ffceSOr Gerlitz 	int err;
1130faa3ffceSOr Gerlitz 
1131faa3ffceSOr Gerlitz 	if (!memchr_inv(&flags_mask, 0, sizeof(flags_mask)))
1132faa3ffceSOr Gerlitz 		return 0;
1133faa3ffceSOr Gerlitz 
1134faa3ffceSOr Gerlitz 	key = 0;
1135faa3ffceSOr Gerlitz 	mask = 0;
1136faa3ffceSOr Gerlitz 
1137faa3ffceSOr Gerlitz 	fl_get_key_flag(flags_key, flags_mask, &key, &mask,
1138faa3ffceSOr Gerlitz 			TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT);
1139faa3ffceSOr Gerlitz 
1140faa3ffceSOr Gerlitz 	_key = cpu_to_be32(key);
1141faa3ffceSOr Gerlitz 	_mask = cpu_to_be32(mask);
1142faa3ffceSOr Gerlitz 
1143faa3ffceSOr Gerlitz 	err = nla_put(skb, TCA_FLOWER_KEY_FLAGS, 4, &_key);
1144faa3ffceSOr Gerlitz 	if (err)
1145faa3ffceSOr Gerlitz 		return err;
1146faa3ffceSOr Gerlitz 
1147faa3ffceSOr Gerlitz 	return nla_put(skb, TCA_FLOWER_KEY_FLAGS_MASK, 4, &_mask);
1148faa3ffceSOr Gerlitz }
1149faa3ffceSOr Gerlitz 
11508113c095SWANG Cong static int fl_dump(struct net *net, struct tcf_proto *tp, void *fh,
115177b9900eSJiri Pirko 		   struct sk_buff *skb, struct tcmsg *t)
115277b9900eSJiri Pirko {
115377b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
11548113c095SWANG Cong 	struct cls_fl_filter *f = fh;
115577b9900eSJiri Pirko 	struct nlattr *nest;
115677b9900eSJiri Pirko 	struct fl_flow_key *key, *mask;
115777b9900eSJiri Pirko 
115877b9900eSJiri Pirko 	if (!f)
115977b9900eSJiri Pirko 		return skb->len;
116077b9900eSJiri Pirko 
116177b9900eSJiri Pirko 	t->tcm_handle = f->handle;
116277b9900eSJiri Pirko 
116377b9900eSJiri Pirko 	nest = nla_nest_start(skb, TCA_OPTIONS);
116477b9900eSJiri Pirko 	if (!nest)
116577b9900eSJiri Pirko 		goto nla_put_failure;
116677b9900eSJiri Pirko 
116777b9900eSJiri Pirko 	if (f->res.classid &&
116877b9900eSJiri Pirko 	    nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid))
116977b9900eSJiri Pirko 		goto nla_put_failure;
117077b9900eSJiri Pirko 
117177b9900eSJiri Pirko 	key = &f->key;
117277b9900eSJiri Pirko 	mask = &head->mask.key;
117377b9900eSJiri Pirko 
117477b9900eSJiri Pirko 	if (mask->indev_ifindex) {
117577b9900eSJiri Pirko 		struct net_device *dev;
117677b9900eSJiri Pirko 
117777b9900eSJiri Pirko 		dev = __dev_get_by_index(net, key->indev_ifindex);
117877b9900eSJiri Pirko 		if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name))
117977b9900eSJiri Pirko 			goto nla_put_failure;
118077b9900eSJiri Pirko 	}
118177b9900eSJiri Pirko 
118279685219SHadar Hen Zion 	if (!tc_skip_hw(f->flags))
118310cbc684SAmir Vadai 		fl_hw_update_stats(tp, f);
118410cbc684SAmir Vadai 
118577b9900eSJiri Pirko 	if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
118677b9900eSJiri Pirko 			    mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
118777b9900eSJiri Pirko 			    sizeof(key->eth.dst)) ||
118877b9900eSJiri Pirko 	    fl_dump_key_val(skb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
118977b9900eSJiri Pirko 			    mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
119077b9900eSJiri Pirko 			    sizeof(key->eth.src)) ||
119177b9900eSJiri Pirko 	    fl_dump_key_val(skb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE,
119277b9900eSJiri Pirko 			    &mask->basic.n_proto, TCA_FLOWER_UNSPEC,
119377b9900eSJiri Pirko 			    sizeof(key->basic.n_proto)))
119477b9900eSJiri Pirko 		goto nla_put_failure;
11959399ae9aSHadar Hen Zion 
1196a577d8f7SBenjamin LaHaise 	if (fl_dump_key_mpls(skb, &key->mpls, &mask->mpls))
1197a577d8f7SBenjamin LaHaise 		goto nla_put_failure;
1198a577d8f7SBenjamin LaHaise 
11999399ae9aSHadar Hen Zion 	if (fl_dump_key_vlan(skb, &key->vlan, &mask->vlan))
12009399ae9aSHadar Hen Zion 		goto nla_put_failure;
12019399ae9aSHadar Hen Zion 
120277b9900eSJiri Pirko 	if ((key->basic.n_proto == htons(ETH_P_IP) ||
120377b9900eSJiri Pirko 	     key->basic.n_proto == htons(ETH_P_IPV6)) &&
12044d80cc0aSOr Gerlitz 	    (fl_dump_key_val(skb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
120577b9900eSJiri Pirko 			    &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
12064d80cc0aSOr Gerlitz 			    sizeof(key->basic.ip_proto)) ||
12074d80cc0aSOr Gerlitz 	    fl_dump_key_ip(skb, &key->ip, &mask->ip)))
120877b9900eSJiri Pirko 		goto nla_put_failure;
120977b9900eSJiri Pirko 
1210c3f83241STom Herbert 	if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
121177b9900eSJiri Pirko 	    (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
121277b9900eSJiri Pirko 			     &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
121377b9900eSJiri Pirko 			     sizeof(key->ipv4.src)) ||
121477b9900eSJiri Pirko 	     fl_dump_key_val(skb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
121577b9900eSJiri Pirko 			     &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
121677b9900eSJiri Pirko 			     sizeof(key->ipv4.dst))))
121777b9900eSJiri Pirko 		goto nla_put_failure;
1218c3f83241STom Herbert 	else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
121977b9900eSJiri Pirko 		 (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
122077b9900eSJiri Pirko 				  &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
122177b9900eSJiri Pirko 				  sizeof(key->ipv6.src)) ||
122277b9900eSJiri Pirko 		  fl_dump_key_val(skb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
122377b9900eSJiri Pirko 				  &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
122477b9900eSJiri Pirko 				  sizeof(key->ipv6.dst))))
122577b9900eSJiri Pirko 		goto nla_put_failure;
122677b9900eSJiri Pirko 
122777b9900eSJiri Pirko 	if (key->basic.ip_proto == IPPROTO_TCP &&
122877b9900eSJiri Pirko 	    (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
1229aa72d708SOr Gerlitz 			     &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
123077b9900eSJiri Pirko 			     sizeof(key->tp.src)) ||
123177b9900eSJiri Pirko 	     fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
1232aa72d708SOr Gerlitz 			     &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
1233fdfc7dd6SJiri Pirko 			     sizeof(key->tp.dst)) ||
1234fdfc7dd6SJiri Pirko 	     fl_dump_key_val(skb, &key->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS,
1235fdfc7dd6SJiri Pirko 			     &mask->tcp.flags, TCA_FLOWER_KEY_TCP_FLAGS_MASK,
1236fdfc7dd6SJiri Pirko 			     sizeof(key->tcp.flags))))
123777b9900eSJiri Pirko 		goto nla_put_failure;
123877b9900eSJiri Pirko 	else if (key->basic.ip_proto == IPPROTO_UDP &&
123977b9900eSJiri Pirko 		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
1240aa72d708SOr Gerlitz 				  &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
124177b9900eSJiri Pirko 				  sizeof(key->tp.src)) ||
124277b9900eSJiri Pirko 		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
1243aa72d708SOr Gerlitz 				  &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
124477b9900eSJiri Pirko 				  sizeof(key->tp.dst))))
124577b9900eSJiri Pirko 		goto nla_put_failure;
12465976c5f4SSimon Horman 	else if (key->basic.ip_proto == IPPROTO_SCTP &&
12475976c5f4SSimon Horman 		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
12485976c5f4SSimon Horman 				  &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
12495976c5f4SSimon Horman 				  sizeof(key->tp.src)) ||
12505976c5f4SSimon Horman 		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
12515976c5f4SSimon Horman 				  &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
12525976c5f4SSimon Horman 				  sizeof(key->tp.dst))))
12535976c5f4SSimon Horman 		goto nla_put_failure;
12547b684884SSimon Horman 	else if (key->basic.n_proto == htons(ETH_P_IP) &&
12557b684884SSimon Horman 		 key->basic.ip_proto == IPPROTO_ICMP &&
12567b684884SSimon Horman 		 (fl_dump_key_val(skb, &key->icmp.type,
12577b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_TYPE, &mask->icmp.type,
12587b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,
12597b684884SSimon Horman 				  sizeof(key->icmp.type)) ||
12607b684884SSimon Horman 		  fl_dump_key_val(skb, &key->icmp.code,
12617b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_CODE, &mask->icmp.code,
12627b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
12637b684884SSimon Horman 				  sizeof(key->icmp.code))))
12647b684884SSimon Horman 		goto nla_put_failure;
12657b684884SSimon Horman 	else if (key->basic.n_proto == htons(ETH_P_IPV6) &&
12667b684884SSimon Horman 		 key->basic.ip_proto == IPPROTO_ICMPV6 &&
12677b684884SSimon Horman 		 (fl_dump_key_val(skb, &key->icmp.type,
12687b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_TYPE, &mask->icmp.type,
12697b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
12707b684884SSimon Horman 				  sizeof(key->icmp.type)) ||
12717b684884SSimon Horman 		  fl_dump_key_val(skb, &key->icmp.code,
12727b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_CODE, &mask->icmp.code,
12737b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_CODE_MASK,
12747b684884SSimon Horman 				  sizeof(key->icmp.code))))
12757b684884SSimon Horman 		goto nla_put_failure;
127699d31326SSimon Horman 	else if ((key->basic.n_proto == htons(ETH_P_ARP) ||
127799d31326SSimon Horman 		  key->basic.n_proto == htons(ETH_P_RARP)) &&
127899d31326SSimon Horman 		 (fl_dump_key_val(skb, &key->arp.sip,
127999d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_SIP, &mask->arp.sip,
128099d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_SIP_MASK,
128199d31326SSimon Horman 				  sizeof(key->arp.sip)) ||
128299d31326SSimon Horman 		  fl_dump_key_val(skb, &key->arp.tip,
128399d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_TIP, &mask->arp.tip,
128499d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_TIP_MASK,
128599d31326SSimon Horman 				  sizeof(key->arp.tip)) ||
128699d31326SSimon Horman 		  fl_dump_key_val(skb, &key->arp.op,
128799d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_OP, &mask->arp.op,
128899d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_OP_MASK,
128999d31326SSimon Horman 				  sizeof(key->arp.op)) ||
129099d31326SSimon Horman 		  fl_dump_key_val(skb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA,
129199d31326SSimon Horman 				  mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK,
129299d31326SSimon Horman 				  sizeof(key->arp.sha)) ||
129399d31326SSimon Horman 		  fl_dump_key_val(skb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA,
129499d31326SSimon Horman 				  mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK,
129599d31326SSimon Horman 				  sizeof(key->arp.tha))))
129699d31326SSimon Horman 		goto nla_put_failure;
129777b9900eSJiri Pirko 
1298bc3103f1SAmir Vadai 	if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
1299bc3103f1SAmir Vadai 	    (fl_dump_key_val(skb, &key->enc_ipv4.src,
1300bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV4_SRC, &mask->enc_ipv4.src,
1301bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
1302bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv4.src)) ||
1303bc3103f1SAmir Vadai 	     fl_dump_key_val(skb, &key->enc_ipv4.dst,
1304bc3103f1SAmir Vadai 			     TCA_FLOWER_KEY_ENC_IPV4_DST, &mask->enc_ipv4.dst,
1305bc3103f1SAmir Vadai 			     TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
1306bc3103f1SAmir Vadai 			     sizeof(key->enc_ipv4.dst))))
1307bc3103f1SAmir Vadai 		goto nla_put_failure;
1308bc3103f1SAmir Vadai 	else if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
1309bc3103f1SAmir Vadai 		 (fl_dump_key_val(skb, &key->enc_ipv6.src,
1310bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV6_SRC, &mask->enc_ipv6.src,
1311bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
1312bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv6.src)) ||
1313bc3103f1SAmir Vadai 		 fl_dump_key_val(skb, &key->enc_ipv6.dst,
1314bc3103f1SAmir Vadai 				 TCA_FLOWER_KEY_ENC_IPV6_DST,
1315bc3103f1SAmir Vadai 				 &mask->enc_ipv6.dst,
1316bc3103f1SAmir Vadai 				 TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
1317bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv6.dst))))
1318bc3103f1SAmir Vadai 		goto nla_put_failure;
1319bc3103f1SAmir Vadai 
1320bc3103f1SAmir Vadai 	if (fl_dump_key_val(skb, &key->enc_key_id, TCA_FLOWER_KEY_ENC_KEY_ID,
1321eb523f42SHadar Hen Zion 			    &mask->enc_key_id, TCA_FLOWER_UNSPEC,
1322f4d997fdSHadar Hen Zion 			    sizeof(key->enc_key_id)) ||
1323f4d997fdSHadar Hen Zion 	    fl_dump_key_val(skb, &key->enc_tp.src,
1324f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
1325f4d997fdSHadar Hen Zion 			    &mask->enc_tp.src,
1326f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
1327f4d997fdSHadar Hen Zion 			    sizeof(key->enc_tp.src)) ||
1328f4d997fdSHadar Hen Zion 	    fl_dump_key_val(skb, &key->enc_tp.dst,
1329f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
1330f4d997fdSHadar Hen Zion 			    &mask->enc_tp.dst,
1331f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
1332f4d997fdSHadar Hen Zion 			    sizeof(key->enc_tp.dst)))
1333bc3103f1SAmir Vadai 		goto nla_put_failure;
1334bc3103f1SAmir Vadai 
1335faa3ffceSOr Gerlitz 	if (fl_dump_key_flags(skb, key->control.flags, mask->control.flags))
1336faa3ffceSOr Gerlitz 		goto nla_put_failure;
1337faa3ffceSOr Gerlitz 
1338749e6720SOr Gerlitz 	if (f->flags && nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags))
1339749e6720SOr Gerlitz 		goto nla_put_failure;
1340e69985c6SAmir Vadai 
134177b9900eSJiri Pirko 	if (tcf_exts_dump(skb, &f->exts))
134277b9900eSJiri Pirko 		goto nla_put_failure;
134377b9900eSJiri Pirko 
134477b9900eSJiri Pirko 	nla_nest_end(skb, nest);
134577b9900eSJiri Pirko 
134677b9900eSJiri Pirko 	if (tcf_exts_dump_stats(skb, &f->exts) < 0)
134777b9900eSJiri Pirko 		goto nla_put_failure;
134877b9900eSJiri Pirko 
134977b9900eSJiri Pirko 	return skb->len;
135077b9900eSJiri Pirko 
135177b9900eSJiri Pirko nla_put_failure:
135277b9900eSJiri Pirko 	nla_nest_cancel(skb, nest);
135377b9900eSJiri Pirko 	return -1;
135477b9900eSJiri Pirko }
135577b9900eSJiri Pirko 
135607d79fc7SCong Wang static void fl_bind_class(void *fh, u32 classid, unsigned long cl)
135707d79fc7SCong Wang {
135807d79fc7SCong Wang 	struct cls_fl_filter *f = fh;
135907d79fc7SCong Wang 
136007d79fc7SCong Wang 	if (f && f->res.classid == classid)
136107d79fc7SCong Wang 		f->res.class = cl;
136207d79fc7SCong Wang }
136307d79fc7SCong Wang 
136477b9900eSJiri Pirko static struct tcf_proto_ops cls_fl_ops __read_mostly = {
136577b9900eSJiri Pirko 	.kind		= "flower",
136677b9900eSJiri Pirko 	.classify	= fl_classify,
136777b9900eSJiri Pirko 	.init		= fl_init,
136877b9900eSJiri Pirko 	.destroy	= fl_destroy,
136977b9900eSJiri Pirko 	.get		= fl_get,
137077b9900eSJiri Pirko 	.change		= fl_change,
137177b9900eSJiri Pirko 	.delete		= fl_delete,
137277b9900eSJiri Pirko 	.walk		= fl_walk,
137377b9900eSJiri Pirko 	.dump		= fl_dump,
137407d79fc7SCong Wang 	.bind_class	= fl_bind_class,
137577b9900eSJiri Pirko 	.owner		= THIS_MODULE,
137677b9900eSJiri Pirko };
137777b9900eSJiri Pirko 
137877b9900eSJiri Pirko static int __init cls_fl_init(void)
137977b9900eSJiri Pirko {
138077b9900eSJiri Pirko 	return register_tcf_proto_ops(&cls_fl_ops);
138177b9900eSJiri Pirko }
138277b9900eSJiri Pirko 
138377b9900eSJiri Pirko static void __exit cls_fl_exit(void)
138477b9900eSJiri Pirko {
138577b9900eSJiri Pirko 	unregister_tcf_proto_ops(&cls_fl_ops);
138677b9900eSJiri Pirko }
138777b9900eSJiri Pirko 
138877b9900eSJiri Pirko module_init(cls_fl_init);
138977b9900eSJiri Pirko module_exit(cls_fl_exit);
139077b9900eSJiri Pirko 
139177b9900eSJiri Pirko MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>");
139277b9900eSJiri Pirko MODULE_DESCRIPTION("Flower classifier");
139377b9900eSJiri Pirko MODULE_LICENSE("GPL v2");
1394