xref: /linux/net/sched/cls_flower.c (revision a577d8f793ff2fd514915686079e3c09bcf0df11)
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>
21*a577d8f7SBenjamin 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;
51*a577d8f7SBenjamin LaHaise 	struct flow_dissector_key_mpls mpls;
5277b9900eSJiri Pirko } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
5377b9900eSJiri Pirko 
5477b9900eSJiri Pirko struct fl_flow_mask_range {
5577b9900eSJiri Pirko 	unsigned short int start;
5677b9900eSJiri Pirko 	unsigned short int end;
5777b9900eSJiri Pirko };
5877b9900eSJiri Pirko 
5977b9900eSJiri Pirko struct fl_flow_mask {
6077b9900eSJiri Pirko 	struct fl_flow_key key;
6177b9900eSJiri Pirko 	struct fl_flow_mask_range range;
6277b9900eSJiri Pirko 	struct rcu_head	rcu;
6377b9900eSJiri Pirko };
6477b9900eSJiri Pirko 
6577b9900eSJiri Pirko struct cls_fl_head {
6677b9900eSJiri Pirko 	struct rhashtable ht;
6777b9900eSJiri Pirko 	struct fl_flow_mask mask;
6877b9900eSJiri Pirko 	struct flow_dissector dissector;
6977b9900eSJiri Pirko 	u32 hgen;
7077b9900eSJiri Pirko 	bool mask_assigned;
7177b9900eSJiri Pirko 	struct list_head filters;
7277b9900eSJiri Pirko 	struct rhashtable_params ht_params;
73d9363774SDaniel Borkmann 	union {
74d9363774SDaniel Borkmann 		struct work_struct work;
7577b9900eSJiri Pirko 		struct rcu_head	rcu;
7677b9900eSJiri Pirko 	};
77d9363774SDaniel Borkmann };
7877b9900eSJiri Pirko 
7977b9900eSJiri Pirko struct cls_fl_filter {
8077b9900eSJiri Pirko 	struct rhash_head ht_node;
8177b9900eSJiri Pirko 	struct fl_flow_key mkey;
8277b9900eSJiri Pirko 	struct tcf_exts exts;
8377b9900eSJiri Pirko 	struct tcf_result res;
8477b9900eSJiri Pirko 	struct fl_flow_key key;
8577b9900eSJiri Pirko 	struct list_head list;
8677b9900eSJiri Pirko 	u32 handle;
87e69985c6SAmir Vadai 	u32 flags;
8877b9900eSJiri Pirko 	struct rcu_head	rcu;
897091d8c7SHadar Hen Zion 	struct tc_to_netdev tc;
907091d8c7SHadar Hen Zion 	struct net_device *hw_dev;
9177b9900eSJiri Pirko };
9277b9900eSJiri Pirko 
9377b9900eSJiri Pirko static unsigned short int fl_mask_range(const struct fl_flow_mask *mask)
9477b9900eSJiri Pirko {
9577b9900eSJiri Pirko 	return mask->range.end - mask->range.start;
9677b9900eSJiri Pirko }
9777b9900eSJiri Pirko 
9877b9900eSJiri Pirko static void fl_mask_update_range(struct fl_flow_mask *mask)
9977b9900eSJiri Pirko {
10077b9900eSJiri Pirko 	const u8 *bytes = (const u8 *) &mask->key;
10177b9900eSJiri Pirko 	size_t size = sizeof(mask->key);
10277b9900eSJiri Pirko 	size_t i, first = 0, last = size - 1;
10377b9900eSJiri Pirko 
10477b9900eSJiri Pirko 	for (i = 0; i < sizeof(mask->key); i++) {
10577b9900eSJiri Pirko 		if (bytes[i]) {
10677b9900eSJiri Pirko 			if (!first && i)
10777b9900eSJiri Pirko 				first = i;
10877b9900eSJiri Pirko 			last = i;
10977b9900eSJiri Pirko 		}
11077b9900eSJiri Pirko 	}
11177b9900eSJiri Pirko 	mask->range.start = rounddown(first, sizeof(long));
11277b9900eSJiri Pirko 	mask->range.end = roundup(last + 1, sizeof(long));
11377b9900eSJiri Pirko }
11477b9900eSJiri Pirko 
11577b9900eSJiri Pirko static void *fl_key_get_start(struct fl_flow_key *key,
11677b9900eSJiri Pirko 			      const struct fl_flow_mask *mask)
11777b9900eSJiri Pirko {
11877b9900eSJiri Pirko 	return (u8 *) key + mask->range.start;
11977b9900eSJiri Pirko }
12077b9900eSJiri Pirko 
12177b9900eSJiri Pirko static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key,
12277b9900eSJiri Pirko 			      struct fl_flow_mask *mask)
12377b9900eSJiri Pirko {
12477b9900eSJiri Pirko 	const long *lkey = fl_key_get_start(key, mask);
12577b9900eSJiri Pirko 	const long *lmask = fl_key_get_start(&mask->key, mask);
12677b9900eSJiri Pirko 	long *lmkey = fl_key_get_start(mkey, mask);
12777b9900eSJiri Pirko 	int i;
12877b9900eSJiri Pirko 
12977b9900eSJiri Pirko 	for (i = 0; i < fl_mask_range(mask); i += sizeof(long))
13077b9900eSJiri Pirko 		*lmkey++ = *lkey++ & *lmask++;
13177b9900eSJiri Pirko }
13277b9900eSJiri Pirko 
13377b9900eSJiri Pirko static void fl_clear_masked_range(struct fl_flow_key *key,
13477b9900eSJiri Pirko 				  struct fl_flow_mask *mask)
13577b9900eSJiri Pirko {
13677b9900eSJiri Pirko 	memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask));
13777b9900eSJiri Pirko }
13877b9900eSJiri Pirko 
139a3308d8fSPaul Blakey static struct cls_fl_filter *fl_lookup(struct cls_fl_head *head,
140a3308d8fSPaul Blakey 				       struct fl_flow_key *mkey)
141a3308d8fSPaul Blakey {
142a3308d8fSPaul Blakey 	return rhashtable_lookup_fast(&head->ht,
143a3308d8fSPaul Blakey 				      fl_key_get_start(mkey, &head->mask),
144a3308d8fSPaul Blakey 				      head->ht_params);
145a3308d8fSPaul Blakey }
146a3308d8fSPaul Blakey 
14777b9900eSJiri Pirko static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp,
14877b9900eSJiri Pirko 		       struct tcf_result *res)
14977b9900eSJiri Pirko {
15077b9900eSJiri Pirko 	struct cls_fl_head *head = rcu_dereference_bh(tp->root);
15177b9900eSJiri Pirko 	struct cls_fl_filter *f;
15277b9900eSJiri Pirko 	struct fl_flow_key skb_key;
15377b9900eSJiri Pirko 	struct fl_flow_key skb_mkey;
154bc3103f1SAmir Vadai 	struct ip_tunnel_info *info;
15577b9900eSJiri Pirko 
156e69985c6SAmir Vadai 	if (!atomic_read(&head->ht.nelems))
157e69985c6SAmir Vadai 		return -1;
158e69985c6SAmir Vadai 
15977b9900eSJiri Pirko 	fl_clear_masked_range(&skb_key, &head->mask);
160bc3103f1SAmir Vadai 
161bc3103f1SAmir Vadai 	info = skb_tunnel_info(skb);
162bc3103f1SAmir Vadai 	if (info) {
163bc3103f1SAmir Vadai 		struct ip_tunnel_key *key = &info->key;
164bc3103f1SAmir Vadai 
165bc3103f1SAmir Vadai 		switch (ip_tunnel_info_af(info)) {
166bc3103f1SAmir Vadai 		case AF_INET:
1670df0f207SPaul Blakey 			skb_key.enc_control.addr_type =
1680df0f207SPaul Blakey 				FLOW_DISSECTOR_KEY_IPV4_ADDRS;
169bc3103f1SAmir Vadai 			skb_key.enc_ipv4.src = key->u.ipv4.src;
170bc3103f1SAmir Vadai 			skb_key.enc_ipv4.dst = key->u.ipv4.dst;
171bc3103f1SAmir Vadai 			break;
172bc3103f1SAmir Vadai 		case AF_INET6:
1730df0f207SPaul Blakey 			skb_key.enc_control.addr_type =
1740df0f207SPaul Blakey 				FLOW_DISSECTOR_KEY_IPV6_ADDRS;
175bc3103f1SAmir Vadai 			skb_key.enc_ipv6.src = key->u.ipv6.src;
176bc3103f1SAmir Vadai 			skb_key.enc_ipv6.dst = key->u.ipv6.dst;
177bc3103f1SAmir Vadai 			break;
178bc3103f1SAmir Vadai 		}
179bc3103f1SAmir Vadai 
180bc3103f1SAmir Vadai 		skb_key.enc_key_id.keyid = tunnel_id_to_key32(key->tun_id);
181f4d997fdSHadar Hen Zion 		skb_key.enc_tp.src = key->tp_src;
182f4d997fdSHadar Hen Zion 		skb_key.enc_tp.dst = key->tp_dst;
183bc3103f1SAmir Vadai 	}
184bc3103f1SAmir Vadai 
18577b9900eSJiri Pirko 	skb_key.indev_ifindex = skb->skb_iif;
18677b9900eSJiri Pirko 	/* skb_flow_dissect() does not set n_proto in case an unknown protocol,
18777b9900eSJiri Pirko 	 * so do it rather here.
18877b9900eSJiri Pirko 	 */
18977b9900eSJiri Pirko 	skb_key.basic.n_proto = skb->protocol;
190cd79a238STom Herbert 	skb_flow_dissect(skb, &head->dissector, &skb_key, 0);
19177b9900eSJiri Pirko 
19277b9900eSJiri Pirko 	fl_set_masked_key(&skb_mkey, &skb_key, &head->mask);
19377b9900eSJiri Pirko 
194a3308d8fSPaul Blakey 	f = fl_lookup(head, &skb_mkey);
195e8eb36cdSAmir Vadai 	if (f && !tc_skip_sw(f->flags)) {
19677b9900eSJiri Pirko 		*res = f->res;
19777b9900eSJiri Pirko 		return tcf_exts_exec(skb, &f->exts, res);
19877b9900eSJiri Pirko 	}
19977b9900eSJiri Pirko 	return -1;
20077b9900eSJiri Pirko }
20177b9900eSJiri Pirko 
20277b9900eSJiri Pirko static int fl_init(struct tcf_proto *tp)
20377b9900eSJiri Pirko {
20477b9900eSJiri Pirko 	struct cls_fl_head *head;
20577b9900eSJiri Pirko 
20677b9900eSJiri Pirko 	head = kzalloc(sizeof(*head), GFP_KERNEL);
20777b9900eSJiri Pirko 	if (!head)
20877b9900eSJiri Pirko 		return -ENOBUFS;
20977b9900eSJiri Pirko 
21077b9900eSJiri Pirko 	INIT_LIST_HEAD_RCU(&head->filters);
21177b9900eSJiri Pirko 	rcu_assign_pointer(tp->root, head);
21277b9900eSJiri Pirko 
21377b9900eSJiri Pirko 	return 0;
21477b9900eSJiri Pirko }
21577b9900eSJiri Pirko 
21677b9900eSJiri Pirko static void fl_destroy_filter(struct rcu_head *head)
21777b9900eSJiri Pirko {
21877b9900eSJiri Pirko 	struct cls_fl_filter *f = container_of(head, struct cls_fl_filter, rcu);
21977b9900eSJiri Pirko 
22077b9900eSJiri Pirko 	tcf_exts_destroy(&f->exts);
22177b9900eSJiri Pirko 	kfree(f);
22277b9900eSJiri Pirko }
22377b9900eSJiri Pirko 
2243036dab6SHadar Hen Zion static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f)
2255b33f488SAmir Vadai {
2265b33f488SAmir Vadai 	struct tc_cls_flower_offload offload = {0};
2277091d8c7SHadar Hen Zion 	struct net_device *dev = f->hw_dev;
2287091d8c7SHadar Hen Zion 	struct tc_to_netdev *tc = &f->tc;
2295b33f488SAmir Vadai 
23079685219SHadar Hen Zion 	if (!tc_can_offload(dev, tp))
2315b33f488SAmir Vadai 		return;
2325b33f488SAmir Vadai 
2335b33f488SAmir Vadai 	offload.command = TC_CLSFLOWER_DESTROY;
23469ca05ceSJiri Pirko 	offload.prio = tp->prio;
2353036dab6SHadar Hen Zion 	offload.cookie = (unsigned long)f;
2365b33f488SAmir Vadai 
2377091d8c7SHadar Hen Zion 	tc->type = TC_SETUP_CLSFLOWER;
2387091d8c7SHadar Hen Zion 	tc->cls_flower = &offload;
2395b33f488SAmir Vadai 
2407091d8c7SHadar Hen Zion 	dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, tc);
2415b33f488SAmir Vadai }
2425b33f488SAmir Vadai 
243e8eb36cdSAmir Vadai static int fl_hw_replace_filter(struct tcf_proto *tp,
2445b33f488SAmir Vadai 				struct flow_dissector *dissector,
2455b33f488SAmir Vadai 				struct fl_flow_key *mask,
2463036dab6SHadar Hen Zion 				struct cls_fl_filter *f)
2475b33f488SAmir Vadai {
2485b33f488SAmir Vadai 	struct net_device *dev = tp->q->dev_queue->dev;
2495b33f488SAmir Vadai 	struct tc_cls_flower_offload offload = {0};
2507091d8c7SHadar Hen Zion 	struct tc_to_netdev *tc = &f->tc;
251e8eb36cdSAmir Vadai 	int err;
2525b33f488SAmir Vadai 
2537091d8c7SHadar Hen Zion 	if (!tc_can_offload(dev, tp)) {
254a6e16931SHadar Hen Zion 		if (tcf_exts_get_dev(dev, &f->exts, &f->hw_dev) ||
255a6e16931SHadar Hen Zion 		    (f->hw_dev && !tc_can_offload(f->hw_dev, tp))) {
256a6e16931SHadar Hen Zion 			f->hw_dev = dev;
2573036dab6SHadar Hen Zion 			return tc_skip_sw(f->flags) ? -EINVAL : 0;
258a6e16931SHadar Hen Zion 		}
2597091d8c7SHadar Hen Zion 		dev = f->hw_dev;
2607091d8c7SHadar Hen Zion 		tc->egress_dev = true;
2617091d8c7SHadar Hen Zion 	} else {
2627091d8c7SHadar Hen Zion 		f->hw_dev = dev;
2637091d8c7SHadar Hen Zion 	}
2645b33f488SAmir Vadai 
2655b33f488SAmir Vadai 	offload.command = TC_CLSFLOWER_REPLACE;
26669ca05ceSJiri Pirko 	offload.prio = tp->prio;
2673036dab6SHadar Hen Zion 	offload.cookie = (unsigned long)f;
2685b33f488SAmir Vadai 	offload.dissector = dissector;
2695b33f488SAmir Vadai 	offload.mask = mask;
270f93bd17bSPaul Blakey 	offload.key = &f->mkey;
2713036dab6SHadar Hen Zion 	offload.exts = &f->exts;
2725b33f488SAmir Vadai 
2737091d8c7SHadar Hen Zion 	tc->type = TC_SETUP_CLSFLOWER;
2747091d8c7SHadar Hen Zion 	tc->cls_flower = &offload;
2755b33f488SAmir Vadai 
2765a7a5555SJamal Hadi Salim 	err = dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol,
2777091d8c7SHadar Hen Zion 					    tc);
27855593960SOr Gerlitz 	if (!err)
27955593960SOr Gerlitz 		f->flags |= TCA_CLS_FLAGS_IN_HW;
280e8eb36cdSAmir Vadai 
2813036dab6SHadar Hen Zion 	if (tc_skip_sw(f->flags))
282e8eb36cdSAmir Vadai 		return err;
283e8eb36cdSAmir Vadai 	return 0;
2845b33f488SAmir Vadai }
2855b33f488SAmir Vadai 
28610cbc684SAmir Vadai static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
28710cbc684SAmir Vadai {
28810cbc684SAmir Vadai 	struct tc_cls_flower_offload offload = {0};
2897091d8c7SHadar Hen Zion 	struct net_device *dev = f->hw_dev;
2907091d8c7SHadar Hen Zion 	struct tc_to_netdev *tc = &f->tc;
29110cbc684SAmir Vadai 
29279685219SHadar Hen Zion 	if (!tc_can_offload(dev, tp))
29310cbc684SAmir Vadai 		return;
29410cbc684SAmir Vadai 
29510cbc684SAmir Vadai 	offload.command = TC_CLSFLOWER_STATS;
29669ca05ceSJiri Pirko 	offload.prio = tp->prio;
29710cbc684SAmir Vadai 	offload.cookie = (unsigned long)f;
29810cbc684SAmir Vadai 	offload.exts = &f->exts;
29910cbc684SAmir Vadai 
3007091d8c7SHadar Hen Zion 	tc->type = TC_SETUP_CLSFLOWER;
3017091d8c7SHadar Hen Zion 	tc->cls_flower = &offload;
30210cbc684SAmir Vadai 
3037091d8c7SHadar Hen Zion 	dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, tc);
30410cbc684SAmir Vadai }
30510cbc684SAmir Vadai 
30613fa876eSRoi Dayan static void __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f)
30713fa876eSRoi Dayan {
30813fa876eSRoi Dayan 	list_del_rcu(&f->list);
30979685219SHadar Hen Zion 	if (!tc_skip_hw(f->flags))
3103036dab6SHadar Hen Zion 		fl_hw_destroy_filter(tp, f);
31113fa876eSRoi Dayan 	tcf_unbind_filter(tp, &f->res);
31213fa876eSRoi Dayan 	call_rcu(&f->rcu, fl_destroy_filter);
31313fa876eSRoi Dayan }
31413fa876eSRoi Dayan 
315d9363774SDaniel Borkmann static void fl_destroy_sleepable(struct work_struct *work)
316d9363774SDaniel Borkmann {
317d9363774SDaniel Borkmann 	struct cls_fl_head *head = container_of(work, struct cls_fl_head,
318d9363774SDaniel Borkmann 						work);
319d9363774SDaniel Borkmann 	if (head->mask_assigned)
320d9363774SDaniel Borkmann 		rhashtable_destroy(&head->ht);
321d9363774SDaniel Borkmann 	kfree(head);
322d9363774SDaniel Borkmann 	module_put(THIS_MODULE);
323d9363774SDaniel Borkmann }
324d9363774SDaniel Borkmann 
325d9363774SDaniel Borkmann static void fl_destroy_rcu(struct rcu_head *rcu)
326d9363774SDaniel Borkmann {
327d9363774SDaniel Borkmann 	struct cls_fl_head *head = container_of(rcu, struct cls_fl_head, rcu);
328d9363774SDaniel Borkmann 
329d9363774SDaniel Borkmann 	INIT_WORK(&head->work, fl_destroy_sleepable);
330d9363774SDaniel Borkmann 	schedule_work(&head->work);
331d9363774SDaniel Borkmann }
332d9363774SDaniel Borkmann 
333763dbf63SWANG Cong static void fl_destroy(struct tcf_proto *tp)
33477b9900eSJiri Pirko {
33577b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
33677b9900eSJiri Pirko 	struct cls_fl_filter *f, *next;
33777b9900eSJiri Pirko 
33813fa876eSRoi Dayan 	list_for_each_entry_safe(f, next, &head->filters, list)
33913fa876eSRoi Dayan 		__fl_delete(tp, f);
340d9363774SDaniel Borkmann 
341d9363774SDaniel Borkmann 	__module_get(THIS_MODULE);
342d9363774SDaniel Borkmann 	call_rcu(&head->rcu, fl_destroy_rcu);
34377b9900eSJiri Pirko }
34477b9900eSJiri Pirko 
34577b9900eSJiri Pirko static unsigned long fl_get(struct tcf_proto *tp, u32 handle)
34677b9900eSJiri Pirko {
34777b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
34877b9900eSJiri Pirko 	struct cls_fl_filter *f;
34977b9900eSJiri Pirko 
35077b9900eSJiri Pirko 	list_for_each_entry(f, &head->filters, list)
35177b9900eSJiri Pirko 		if (f->handle == handle)
35277b9900eSJiri Pirko 			return (unsigned long) f;
35377b9900eSJiri Pirko 	return 0;
35477b9900eSJiri Pirko }
35577b9900eSJiri Pirko 
35677b9900eSJiri Pirko static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
35777b9900eSJiri Pirko 	[TCA_FLOWER_UNSPEC]		= { .type = NLA_UNSPEC },
35877b9900eSJiri Pirko 	[TCA_FLOWER_CLASSID]		= { .type = NLA_U32 },
35977b9900eSJiri Pirko 	[TCA_FLOWER_INDEV]		= { .type = NLA_STRING,
36077b9900eSJiri Pirko 					    .len = IFNAMSIZ },
36177b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_DST]	= { .len = ETH_ALEN },
36277b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_DST_MASK]	= { .len = ETH_ALEN },
36377b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_SRC]	= { .len = ETH_ALEN },
36477b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_SRC_MASK]	= { .len = ETH_ALEN },
36577b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_TYPE]	= { .type = NLA_U16 },
36677b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IP_PROTO]	= { .type = NLA_U8 },
36777b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_SRC]	= { .type = NLA_U32 },
36877b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_SRC_MASK]	= { .type = NLA_U32 },
36977b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_DST]	= { .type = NLA_U32 },
37077b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_DST_MASK]	= { .type = NLA_U32 },
37177b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
37277b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_SRC_MASK]	= { .len = sizeof(struct in6_addr) },
37377b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
37477b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_DST_MASK]	= { .len = sizeof(struct in6_addr) },
37577b9900eSJiri Pirko 	[TCA_FLOWER_KEY_TCP_SRC]	= { .type = NLA_U16 },
37677b9900eSJiri Pirko 	[TCA_FLOWER_KEY_TCP_DST]	= { .type = NLA_U16 },
377b175c3a4SJamal Hadi Salim 	[TCA_FLOWER_KEY_UDP_SRC]	= { .type = NLA_U16 },
378b175c3a4SJamal Hadi Salim 	[TCA_FLOWER_KEY_UDP_DST]	= { .type = NLA_U16 },
3799399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_ID]	= { .type = NLA_U16 },
3809399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_PRIO]	= { .type = NLA_U8 },
3819399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_ETH_TYPE]	= { .type = NLA_U16 },
382bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_KEY_ID]	= { .type = NLA_U32 },
383bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_SRC]	= { .type = NLA_U32 },
384bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NLA_U32 },
385bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_DST]	= { .type = NLA_U32 },
386bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NLA_U32 },
387bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
388bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) },
389bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
390bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) },
391aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_TCP_SRC_MASK]	= { .type = NLA_U16 },
392aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_TCP_DST_MASK]	= { .type = NLA_U16 },
393aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_UDP_SRC_MASK]	= { .type = NLA_U16 },
394aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_UDP_DST_MASK]	= { .type = NLA_U16 },
3955976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_SRC_MASK]	= { .type = NLA_U16 },
3965976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_DST_MASK]	= { .type = NLA_U16 },
3975976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_SRC]	= { .type = NLA_U16 },
3985976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_DST]	= { .type = NLA_U16 },
399f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT]	= { .type = NLA_U16 },
400f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK]	= { .type = NLA_U16 },
401f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]	= { .type = NLA_U16 },
402f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK]	= { .type = NLA_U16 },
403faa3ffceSOr Gerlitz 	[TCA_FLOWER_KEY_FLAGS]		= { .type = NLA_U32 },
404faa3ffceSOr Gerlitz 	[TCA_FLOWER_KEY_FLAGS_MASK]	= { .type = NLA_U32 },
4057b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_TYPE]	= { .type = NLA_U8 },
4067b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_TYPE_MASK] = { .type = NLA_U8 },
4077b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_CODE]	= { .type = NLA_U8 },
4087b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_CODE_MASK] = { .type = NLA_U8 },
4097b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_TYPE]	= { .type = NLA_U8 },
4107b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_TYPE_MASK] = { .type = NLA_U8 },
4117b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_CODE]	= { .type = NLA_U8 },
4127b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_CODE_MASK] = { .type = NLA_U8 },
41399d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SIP]	= { .type = NLA_U32 },
41499d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SIP_MASK]	= { .type = NLA_U32 },
41599d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_TIP]	= { .type = NLA_U32 },
41699d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_TIP_MASK]	= { .type = NLA_U32 },
41799d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_OP]		= { .type = NLA_U8 },
41899d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_OP_MASK]	= { .type = NLA_U8 },
41999d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SHA]	= { .len = ETH_ALEN },
42099d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_SHA_MASK]	= { .len = ETH_ALEN },
42199d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_THA]	= { .len = ETH_ALEN },
42299d31326SSimon Horman 	[TCA_FLOWER_KEY_ARP_THA_MASK]	= { .len = ETH_ALEN },
423*a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_TTL]	= { .type = NLA_U8 },
424*a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_BOS]	= { .type = NLA_U8 },
425*a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_TC]	= { .type = NLA_U8 },
426*a577d8f7SBenjamin LaHaise 	[TCA_FLOWER_KEY_MPLS_LABEL]	= { .type = NLA_U32 },
42777b9900eSJiri Pirko };
42877b9900eSJiri Pirko 
42977b9900eSJiri Pirko static void fl_set_key_val(struct nlattr **tb,
43077b9900eSJiri Pirko 			   void *val, int val_type,
43177b9900eSJiri Pirko 			   void *mask, int mask_type, int len)
43277b9900eSJiri Pirko {
43377b9900eSJiri Pirko 	if (!tb[val_type])
43477b9900eSJiri Pirko 		return;
43577b9900eSJiri Pirko 	memcpy(val, nla_data(tb[val_type]), len);
43677b9900eSJiri Pirko 	if (mask_type == TCA_FLOWER_UNSPEC || !tb[mask_type])
43777b9900eSJiri Pirko 		memset(mask, 0xff, len);
43877b9900eSJiri Pirko 	else
43977b9900eSJiri Pirko 		memcpy(mask, nla_data(tb[mask_type]), len);
44077b9900eSJiri Pirko }
44177b9900eSJiri Pirko 
442*a577d8f7SBenjamin LaHaise static void fl_set_key_mpls(struct nlattr **tb,
443*a577d8f7SBenjamin LaHaise 			    struct flow_dissector_key_mpls *key_val,
444*a577d8f7SBenjamin LaHaise 			    struct flow_dissector_key_mpls *key_mask)
445*a577d8f7SBenjamin LaHaise {
446*a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_TTL]) {
447*a577d8f7SBenjamin LaHaise 		key_val->mpls_ttl = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TTL]);
448*a577d8f7SBenjamin LaHaise 		key_mask->mpls_ttl = MPLS_TTL_MASK;
449*a577d8f7SBenjamin LaHaise 	}
450*a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_BOS]) {
451*a577d8f7SBenjamin LaHaise 		key_val->mpls_bos = nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_BOS]);
452*a577d8f7SBenjamin LaHaise 		key_mask->mpls_bos = MPLS_BOS_MASK;
453*a577d8f7SBenjamin LaHaise 	}
454*a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_TC]) {
455*a577d8f7SBenjamin LaHaise 		key_val->mpls_tc =
456*a577d8f7SBenjamin LaHaise 			nla_get_u8(tb[TCA_FLOWER_KEY_MPLS_TC]) & MPLS_TC_MASK;
457*a577d8f7SBenjamin LaHaise 		key_mask->mpls_tc = MPLS_TC_MASK;
458*a577d8f7SBenjamin LaHaise 	}
459*a577d8f7SBenjamin LaHaise 	if (tb[TCA_FLOWER_KEY_MPLS_LABEL]) {
460*a577d8f7SBenjamin LaHaise 		key_val->mpls_label =
461*a577d8f7SBenjamin LaHaise 			nla_get_u32(tb[TCA_FLOWER_KEY_MPLS_LABEL]) &
462*a577d8f7SBenjamin LaHaise 			MPLS_LABEL_MASK;
463*a577d8f7SBenjamin LaHaise 		key_mask->mpls_label = MPLS_LABEL_MASK;
464*a577d8f7SBenjamin LaHaise 	}
465*a577d8f7SBenjamin LaHaise }
466*a577d8f7SBenjamin 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 
51877b9900eSJiri Pirko static int fl_set_key(struct net *net, struct nlattr **tb,
51977b9900eSJiri Pirko 		      struct fl_flow_key *key, struct fl_flow_key *mask)
52077b9900eSJiri Pirko {
5219399ae9aSHadar Hen Zion 	__be16 ethertype;
522d9724772SOr Gerlitz 	int ret = 0;
523dd3aa3b5SBrian Haley #ifdef CONFIG_NET_CLS_IND
52477b9900eSJiri Pirko 	if (tb[TCA_FLOWER_INDEV]) {
525dd3aa3b5SBrian Haley 		int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV]);
52677b9900eSJiri Pirko 		if (err < 0)
52777b9900eSJiri Pirko 			return err;
52877b9900eSJiri Pirko 		key->indev_ifindex = err;
52977b9900eSJiri Pirko 		mask->indev_ifindex = 0xffffffff;
53077b9900eSJiri Pirko 	}
531dd3aa3b5SBrian Haley #endif
53277b9900eSJiri Pirko 
53377b9900eSJiri Pirko 	fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
53477b9900eSJiri Pirko 		       mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
53577b9900eSJiri Pirko 		       sizeof(key->eth.dst));
53677b9900eSJiri Pirko 	fl_set_key_val(tb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
53777b9900eSJiri Pirko 		       mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
53877b9900eSJiri Pirko 		       sizeof(key->eth.src));
53966530bdfSJamal Hadi Salim 
5400b498a52SArnd Bergmann 	if (tb[TCA_FLOWER_KEY_ETH_TYPE]) {
5419399ae9aSHadar Hen Zion 		ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_ETH_TYPE]);
5429399ae9aSHadar Hen Zion 
5439399ae9aSHadar Hen Zion 		if (ethertype == htons(ETH_P_8021Q)) {
5449399ae9aSHadar Hen Zion 			fl_set_key_vlan(tb, &key->vlan, &mask->vlan);
5459399ae9aSHadar Hen Zion 			fl_set_key_val(tb, &key->basic.n_proto,
5469399ae9aSHadar Hen Zion 				       TCA_FLOWER_KEY_VLAN_ETH_TYPE,
54777b9900eSJiri Pirko 				       &mask->basic.n_proto, TCA_FLOWER_UNSPEC,
54877b9900eSJiri Pirko 				       sizeof(key->basic.n_proto));
5499399ae9aSHadar Hen Zion 		} else {
5509399ae9aSHadar Hen Zion 			key->basic.n_proto = ethertype;
5519399ae9aSHadar Hen Zion 			mask->basic.n_proto = cpu_to_be16(~0);
5529399ae9aSHadar Hen Zion 		}
5530b498a52SArnd Bergmann 	}
55466530bdfSJamal Hadi Salim 
55577b9900eSJiri Pirko 	if (key->basic.n_proto == htons(ETH_P_IP) ||
55677b9900eSJiri Pirko 	    key->basic.n_proto == htons(ETH_P_IPV6)) {
55777b9900eSJiri Pirko 		fl_set_key_val(tb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
55877b9900eSJiri Pirko 			       &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
55977b9900eSJiri Pirko 			       sizeof(key->basic.ip_proto));
56077b9900eSJiri Pirko 	}
56166530bdfSJamal Hadi Salim 
56266530bdfSJamal Hadi Salim 	if (tb[TCA_FLOWER_KEY_IPV4_SRC] || tb[TCA_FLOWER_KEY_IPV4_DST]) {
56366530bdfSJamal Hadi Salim 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
564970bfcd0SPaul Blakey 		mask->control.addr_type = ~0;
56577b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
56677b9900eSJiri Pirko 			       &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
56777b9900eSJiri Pirko 			       sizeof(key->ipv4.src));
56877b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
56977b9900eSJiri Pirko 			       &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
57077b9900eSJiri Pirko 			       sizeof(key->ipv4.dst));
57166530bdfSJamal Hadi Salim 	} else if (tb[TCA_FLOWER_KEY_IPV6_SRC] || tb[TCA_FLOWER_KEY_IPV6_DST]) {
57266530bdfSJamal Hadi Salim 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
573970bfcd0SPaul Blakey 		mask->control.addr_type = ~0;
57477b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
57577b9900eSJiri Pirko 			       &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
57677b9900eSJiri Pirko 			       sizeof(key->ipv6.src));
57777b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
57877b9900eSJiri Pirko 			       &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
57977b9900eSJiri Pirko 			       sizeof(key->ipv6.dst));
58077b9900eSJiri Pirko 	}
58166530bdfSJamal Hadi Salim 
58277b9900eSJiri Pirko 	if (key->basic.ip_proto == IPPROTO_TCP) {
58377b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
584aa72d708SOr Gerlitz 			       &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
58577b9900eSJiri Pirko 			       sizeof(key->tp.src));
58677b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
587aa72d708SOr Gerlitz 			       &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
58877b9900eSJiri Pirko 			       sizeof(key->tp.dst));
58977b9900eSJiri Pirko 	} else if (key->basic.ip_proto == IPPROTO_UDP) {
59077b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
591aa72d708SOr Gerlitz 			       &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
59277b9900eSJiri Pirko 			       sizeof(key->tp.src));
59377b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
594aa72d708SOr Gerlitz 			       &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
59577b9900eSJiri Pirko 			       sizeof(key->tp.dst));
5965976c5f4SSimon Horman 	} else if (key->basic.ip_proto == IPPROTO_SCTP) {
5975976c5f4SSimon Horman 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
5985976c5f4SSimon Horman 			       &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
5995976c5f4SSimon Horman 			       sizeof(key->tp.src));
6005976c5f4SSimon Horman 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
6015976c5f4SSimon Horman 			       &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
6025976c5f4SSimon Horman 			       sizeof(key->tp.dst));
6037b684884SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_IP) &&
6047b684884SSimon Horman 		   key->basic.ip_proto == IPPROTO_ICMP) {
6057b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV4_TYPE,
6067b684884SSimon Horman 			       &mask->icmp.type,
6077b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,
6087b684884SSimon Horman 			       sizeof(key->icmp.type));
6097b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE,
6107b684884SSimon Horman 			       &mask->icmp.code,
6117b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
6127b684884SSimon Horman 			       sizeof(key->icmp.code));
6137b684884SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_IPV6) &&
6147b684884SSimon Horman 		   key->basic.ip_proto == IPPROTO_ICMPV6) {
6157b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV6_TYPE,
6167b684884SSimon Horman 			       &mask->icmp.type,
6177b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
6187b684884SSimon Horman 			       sizeof(key->icmp.type));
619040587afSSimon Horman 		fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV6_CODE,
6207b684884SSimon Horman 			       &mask->icmp.code,
621040587afSSimon Horman 			       TCA_FLOWER_KEY_ICMPV6_CODE_MASK,
6227b684884SSimon Horman 			       sizeof(key->icmp.code));
623*a577d8f7SBenjamin LaHaise 	} else if (key->basic.n_proto == htons(ETH_P_MPLS_UC) ||
624*a577d8f7SBenjamin LaHaise 		   key->basic.n_proto == htons(ETH_P_MPLS_MC)) {
625*a577d8f7SBenjamin LaHaise 		fl_set_key_mpls(tb, &key->mpls, &mask->mpls);
62699d31326SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_ARP) ||
62799d31326SSimon Horman 		   key->basic.n_proto == htons(ETH_P_RARP)) {
62899d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.sip, TCA_FLOWER_KEY_ARP_SIP,
62999d31326SSimon Horman 			       &mask->arp.sip, TCA_FLOWER_KEY_ARP_SIP_MASK,
63099d31326SSimon Horman 			       sizeof(key->arp.sip));
63199d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.tip, TCA_FLOWER_KEY_ARP_TIP,
63299d31326SSimon Horman 			       &mask->arp.tip, TCA_FLOWER_KEY_ARP_TIP_MASK,
63399d31326SSimon Horman 			       sizeof(key->arp.tip));
63499d31326SSimon Horman 		fl_set_key_val(tb, &key->arp.op, TCA_FLOWER_KEY_ARP_OP,
63599d31326SSimon Horman 			       &mask->arp.op, TCA_FLOWER_KEY_ARP_OP_MASK,
63699d31326SSimon Horman 			       sizeof(key->arp.op));
63799d31326SSimon Horman 		fl_set_key_val(tb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA,
63899d31326SSimon Horman 			       mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK,
63999d31326SSimon Horman 			       sizeof(key->arp.sha));
64099d31326SSimon Horman 		fl_set_key_val(tb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA,
64199d31326SSimon Horman 			       mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK,
64299d31326SSimon Horman 			       sizeof(key->arp.tha));
64377b9900eSJiri Pirko 	}
64477b9900eSJiri Pirko 
645bc3103f1SAmir Vadai 	if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] ||
646bc3103f1SAmir Vadai 	    tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) {
647bc3103f1SAmir Vadai 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
648970bfcd0SPaul Blakey 		mask->enc_control.addr_type = ~0;
649bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv4.src,
650bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_SRC,
651bc3103f1SAmir Vadai 			       &mask->enc_ipv4.src,
652bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
653bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv4.src));
654bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv4.dst,
655bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_DST,
656bc3103f1SAmir Vadai 			       &mask->enc_ipv4.dst,
657bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
658bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv4.dst));
659bc3103f1SAmir Vadai 	}
660bc3103f1SAmir Vadai 
661bc3103f1SAmir Vadai 	if (tb[TCA_FLOWER_KEY_ENC_IPV6_SRC] ||
662bc3103f1SAmir Vadai 	    tb[TCA_FLOWER_KEY_ENC_IPV6_DST]) {
663bc3103f1SAmir Vadai 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
664970bfcd0SPaul Blakey 		mask->enc_control.addr_type = ~0;
665bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv6.src,
666bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_SRC,
667bc3103f1SAmir Vadai 			       &mask->enc_ipv6.src,
668bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
669bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv6.src));
670bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv6.dst,
671bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_DST,
672bc3103f1SAmir Vadai 			       &mask->enc_ipv6.dst,
673bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
674bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv6.dst));
675bc3103f1SAmir Vadai 	}
676bc3103f1SAmir Vadai 
677bc3103f1SAmir Vadai 	fl_set_key_val(tb, &key->enc_key_id.keyid, TCA_FLOWER_KEY_ENC_KEY_ID,
678eb523f42SHadar Hen Zion 		       &mask->enc_key_id.keyid, TCA_FLOWER_UNSPEC,
679bc3103f1SAmir Vadai 		       sizeof(key->enc_key_id.keyid));
680bc3103f1SAmir Vadai 
681f4d997fdSHadar Hen Zion 	fl_set_key_val(tb, &key->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
682f4d997fdSHadar Hen Zion 		       &mask->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
683f4d997fdSHadar Hen Zion 		       sizeof(key->enc_tp.src));
684f4d997fdSHadar Hen Zion 
685f4d997fdSHadar Hen Zion 	fl_set_key_val(tb, &key->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
686f4d997fdSHadar Hen Zion 		       &mask->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
687f4d997fdSHadar Hen Zion 		       sizeof(key->enc_tp.dst));
688f4d997fdSHadar Hen Zion 
689d9724772SOr Gerlitz 	if (tb[TCA_FLOWER_KEY_FLAGS])
690d9724772SOr Gerlitz 		ret = fl_set_key_flags(tb, &key->control.flags, &mask->control.flags);
691faa3ffceSOr Gerlitz 
692d9724772SOr Gerlitz 	return ret;
69377b9900eSJiri Pirko }
69477b9900eSJiri Pirko 
69577b9900eSJiri Pirko static bool fl_mask_eq(struct fl_flow_mask *mask1,
69677b9900eSJiri Pirko 		       struct fl_flow_mask *mask2)
69777b9900eSJiri Pirko {
69877b9900eSJiri Pirko 	const long *lmask1 = fl_key_get_start(&mask1->key, mask1);
69977b9900eSJiri Pirko 	const long *lmask2 = fl_key_get_start(&mask2->key, mask2);
70077b9900eSJiri Pirko 
70177b9900eSJiri Pirko 	return !memcmp(&mask1->range, &mask2->range, sizeof(mask1->range)) &&
70277b9900eSJiri Pirko 	       !memcmp(lmask1, lmask2, fl_mask_range(mask1));
70377b9900eSJiri Pirko }
70477b9900eSJiri Pirko 
70577b9900eSJiri Pirko static const struct rhashtable_params fl_ht_params = {
70677b9900eSJiri Pirko 	.key_offset = offsetof(struct cls_fl_filter, mkey), /* base offset */
70777b9900eSJiri Pirko 	.head_offset = offsetof(struct cls_fl_filter, ht_node),
70877b9900eSJiri Pirko 	.automatic_shrinking = true,
70977b9900eSJiri Pirko };
71077b9900eSJiri Pirko 
71177b9900eSJiri Pirko static int fl_init_hashtable(struct cls_fl_head *head,
71277b9900eSJiri Pirko 			     struct fl_flow_mask *mask)
71377b9900eSJiri Pirko {
71477b9900eSJiri Pirko 	head->ht_params = fl_ht_params;
71577b9900eSJiri Pirko 	head->ht_params.key_len = fl_mask_range(mask);
71677b9900eSJiri Pirko 	head->ht_params.key_offset += mask->range.start;
71777b9900eSJiri Pirko 
71877b9900eSJiri Pirko 	return rhashtable_init(&head->ht, &head->ht_params);
71977b9900eSJiri Pirko }
72077b9900eSJiri Pirko 
72177b9900eSJiri Pirko #define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member)
72277b9900eSJiri Pirko #define FL_KEY_MEMBER_SIZE(member) (sizeof(((struct fl_flow_key *) 0)->member))
72377b9900eSJiri Pirko 
724339ba878SHadar Hen Zion #define FL_KEY_IS_MASKED(mask, member)						\
725339ba878SHadar Hen Zion 	memchr_inv(((char *)mask) + FL_KEY_MEMBER_OFFSET(member),		\
726339ba878SHadar Hen Zion 		   0, FL_KEY_MEMBER_SIZE(member))				\
72777b9900eSJiri Pirko 
72877b9900eSJiri Pirko #define FL_KEY_SET(keys, cnt, id, member)					\
72977b9900eSJiri Pirko 	do {									\
73077b9900eSJiri Pirko 		keys[cnt].key_id = id;						\
73177b9900eSJiri Pirko 		keys[cnt].offset = FL_KEY_MEMBER_OFFSET(member);		\
73277b9900eSJiri Pirko 		cnt++;								\
73377b9900eSJiri Pirko 	} while(0);
73477b9900eSJiri Pirko 
735339ba878SHadar Hen Zion #define FL_KEY_SET_IF_MASKED(mask, keys, cnt, id, member)			\
73677b9900eSJiri Pirko 	do {									\
737339ba878SHadar Hen Zion 		if (FL_KEY_IS_MASKED(mask, member))				\
73877b9900eSJiri Pirko 			FL_KEY_SET(keys, cnt, id, member);			\
73977b9900eSJiri Pirko 	} while(0);
74077b9900eSJiri Pirko 
74177b9900eSJiri Pirko static void fl_init_dissector(struct cls_fl_head *head,
74277b9900eSJiri Pirko 			      struct fl_flow_mask *mask)
74377b9900eSJiri Pirko {
74477b9900eSJiri Pirko 	struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX];
74577b9900eSJiri Pirko 	size_t cnt = 0;
74677b9900eSJiri Pirko 
74742aecaa9STom Herbert 	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control);
74877b9900eSJiri Pirko 	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic);
749339ba878SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
75077b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_ETH_ADDRS, eth);
751339ba878SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
75277b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4);
753339ba878SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
75477b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6);
755339ba878SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
75677b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_PORTS, tp);
7579399ae9aSHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
7587b684884SSimon Horman 			     FLOW_DISSECTOR_KEY_ICMP, icmp);
7597b684884SSimon Horman 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
76099d31326SSimon Horman 			     FLOW_DISSECTOR_KEY_ARP, arp);
76199d31326SSimon Horman 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
762*a577d8f7SBenjamin LaHaise 			     FLOW_DISSECTOR_KEY_MPLS, mpls);
763*a577d8f7SBenjamin LaHaise 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
7649399ae9aSHadar Hen Zion 			     FLOW_DISSECTOR_KEY_VLAN, vlan);
765519d1052SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
766519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_KEYID, enc_key_id);
767519d1052SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
768519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, enc_ipv4);
769519d1052SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
770519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, enc_ipv6);
771519d1052SHadar Hen Zion 	if (FL_KEY_IS_MASKED(&mask->key, enc_ipv4) ||
772519d1052SHadar Hen Zion 	    FL_KEY_IS_MASKED(&mask->key, enc_ipv6))
773519d1052SHadar Hen Zion 		FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_ENC_CONTROL,
774519d1052SHadar Hen Zion 			   enc_control);
775f4d997fdSHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
776f4d997fdSHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp);
77777b9900eSJiri Pirko 
77877b9900eSJiri Pirko 	skb_flow_dissector_init(&head->dissector, keys, cnt);
77977b9900eSJiri Pirko }
78077b9900eSJiri Pirko 
78177b9900eSJiri Pirko static int fl_check_assign_mask(struct cls_fl_head *head,
78277b9900eSJiri Pirko 				struct fl_flow_mask *mask)
78377b9900eSJiri Pirko {
78477b9900eSJiri Pirko 	int err;
78577b9900eSJiri Pirko 
78677b9900eSJiri Pirko 	if (head->mask_assigned) {
78777b9900eSJiri Pirko 		if (!fl_mask_eq(&head->mask, mask))
78877b9900eSJiri Pirko 			return -EINVAL;
78977b9900eSJiri Pirko 		else
79077b9900eSJiri Pirko 			return 0;
79177b9900eSJiri Pirko 	}
79277b9900eSJiri Pirko 
79377b9900eSJiri Pirko 	/* Mask is not assigned yet. So assign it and init hashtable
79477b9900eSJiri Pirko 	 * according to that.
79577b9900eSJiri Pirko 	 */
79677b9900eSJiri Pirko 	err = fl_init_hashtable(head, mask);
79777b9900eSJiri Pirko 	if (err)
79877b9900eSJiri Pirko 		return err;
79977b9900eSJiri Pirko 	memcpy(&head->mask, mask, sizeof(head->mask));
80077b9900eSJiri Pirko 	head->mask_assigned = true;
80177b9900eSJiri Pirko 
80277b9900eSJiri Pirko 	fl_init_dissector(head, mask);
80377b9900eSJiri Pirko 
80477b9900eSJiri Pirko 	return 0;
80577b9900eSJiri Pirko }
80677b9900eSJiri Pirko 
80777b9900eSJiri Pirko static int fl_set_parms(struct net *net, struct tcf_proto *tp,
80877b9900eSJiri Pirko 			struct cls_fl_filter *f, struct fl_flow_mask *mask,
80977b9900eSJiri Pirko 			unsigned long base, struct nlattr **tb,
81077b9900eSJiri Pirko 			struct nlattr *est, bool ovr)
81177b9900eSJiri Pirko {
81277b9900eSJiri Pirko 	struct tcf_exts e;
81377b9900eSJiri Pirko 	int err;
81477b9900eSJiri Pirko 
815b9a24bb7SWANG Cong 	err = tcf_exts_init(&e, TCA_FLOWER_ACT, 0);
81677b9900eSJiri Pirko 	if (err < 0)
81777b9900eSJiri Pirko 		return err;
818b9a24bb7SWANG Cong 	err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
819b9a24bb7SWANG Cong 	if (err < 0)
820b9a24bb7SWANG Cong 		goto errout;
82177b9900eSJiri Pirko 
82277b9900eSJiri Pirko 	if (tb[TCA_FLOWER_CLASSID]) {
82377b9900eSJiri Pirko 		f->res.classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]);
82477b9900eSJiri Pirko 		tcf_bind_filter(tp, &f->res, base);
82577b9900eSJiri Pirko 	}
82677b9900eSJiri Pirko 
82777b9900eSJiri Pirko 	err = fl_set_key(net, tb, &f->key, &mask->key);
82877b9900eSJiri Pirko 	if (err)
82977b9900eSJiri Pirko 		goto errout;
83077b9900eSJiri Pirko 
83177b9900eSJiri Pirko 	fl_mask_update_range(mask);
83277b9900eSJiri Pirko 	fl_set_masked_key(&f->mkey, &f->key, mask);
83377b9900eSJiri Pirko 
83477b9900eSJiri Pirko 	tcf_exts_change(tp, &f->exts, &e);
83577b9900eSJiri Pirko 
83677b9900eSJiri Pirko 	return 0;
83777b9900eSJiri Pirko errout:
83877b9900eSJiri Pirko 	tcf_exts_destroy(&e);
83977b9900eSJiri Pirko 	return err;
84077b9900eSJiri Pirko }
84177b9900eSJiri Pirko 
84277b9900eSJiri Pirko static u32 fl_grab_new_handle(struct tcf_proto *tp,
84377b9900eSJiri Pirko 			      struct cls_fl_head *head)
84477b9900eSJiri Pirko {
84577b9900eSJiri Pirko 	unsigned int i = 0x80000000;
84677b9900eSJiri Pirko 	u32 handle;
84777b9900eSJiri Pirko 
84877b9900eSJiri Pirko 	do {
84977b9900eSJiri Pirko 		if (++head->hgen == 0x7FFFFFFF)
85077b9900eSJiri Pirko 			head->hgen = 1;
85177b9900eSJiri Pirko 	} while (--i > 0 && fl_get(tp, head->hgen));
85277b9900eSJiri Pirko 
85377b9900eSJiri Pirko 	if (unlikely(i == 0)) {
85477b9900eSJiri Pirko 		pr_err("Insufficient number of handles\n");
85577b9900eSJiri Pirko 		handle = 0;
85677b9900eSJiri Pirko 	} else {
85777b9900eSJiri Pirko 		handle = head->hgen;
85877b9900eSJiri Pirko 	}
85977b9900eSJiri Pirko 
86077b9900eSJiri Pirko 	return handle;
86177b9900eSJiri Pirko }
86277b9900eSJiri Pirko 
86377b9900eSJiri Pirko static int fl_change(struct net *net, struct sk_buff *in_skb,
86477b9900eSJiri Pirko 		     struct tcf_proto *tp, unsigned long base,
86577b9900eSJiri Pirko 		     u32 handle, struct nlattr **tca,
86677b9900eSJiri Pirko 		     unsigned long *arg, bool ovr)
86777b9900eSJiri Pirko {
86877b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
86977b9900eSJiri Pirko 	struct cls_fl_filter *fold = (struct cls_fl_filter *) *arg;
87077b9900eSJiri Pirko 	struct cls_fl_filter *fnew;
87139b7b6a6SArnd Bergmann 	struct nlattr **tb;
87277b9900eSJiri Pirko 	struct fl_flow_mask mask = {};
87377b9900eSJiri Pirko 	int err;
87477b9900eSJiri Pirko 
87577b9900eSJiri Pirko 	if (!tca[TCA_OPTIONS])
87677b9900eSJiri Pirko 		return -EINVAL;
87777b9900eSJiri Pirko 
87839b7b6a6SArnd Bergmann 	tb = kcalloc(TCA_FLOWER_MAX + 1, sizeof(struct nlattr *), GFP_KERNEL);
87939b7b6a6SArnd Bergmann 	if (!tb)
88039b7b6a6SArnd Bergmann 		return -ENOBUFS;
88139b7b6a6SArnd Bergmann 
882fceb6435SJohannes Berg 	err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS],
883fceb6435SJohannes Berg 			       fl_policy, NULL);
88477b9900eSJiri Pirko 	if (err < 0)
88539b7b6a6SArnd Bergmann 		goto errout_tb;
88677b9900eSJiri Pirko 
88739b7b6a6SArnd Bergmann 	if (fold && handle && fold->handle != handle) {
88839b7b6a6SArnd Bergmann 		err = -EINVAL;
88939b7b6a6SArnd Bergmann 		goto errout_tb;
89039b7b6a6SArnd Bergmann 	}
89177b9900eSJiri Pirko 
89277b9900eSJiri Pirko 	fnew = kzalloc(sizeof(*fnew), GFP_KERNEL);
89339b7b6a6SArnd Bergmann 	if (!fnew) {
89439b7b6a6SArnd Bergmann 		err = -ENOBUFS;
89539b7b6a6SArnd Bergmann 		goto errout_tb;
89639b7b6a6SArnd Bergmann 	}
89777b9900eSJiri Pirko 
898b9a24bb7SWANG Cong 	err = tcf_exts_init(&fnew->exts, TCA_FLOWER_ACT, 0);
899b9a24bb7SWANG Cong 	if (err < 0)
900b9a24bb7SWANG Cong 		goto errout;
90177b9900eSJiri Pirko 
90277b9900eSJiri Pirko 	if (!handle) {
90377b9900eSJiri Pirko 		handle = fl_grab_new_handle(tp, head);
90477b9900eSJiri Pirko 		if (!handle) {
90577b9900eSJiri Pirko 			err = -EINVAL;
90677b9900eSJiri Pirko 			goto errout;
90777b9900eSJiri Pirko 		}
90877b9900eSJiri Pirko 	}
90977b9900eSJiri Pirko 	fnew->handle = handle;
91077b9900eSJiri Pirko 
911e69985c6SAmir Vadai 	if (tb[TCA_FLOWER_FLAGS]) {
912e69985c6SAmir Vadai 		fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
913e69985c6SAmir Vadai 
914e69985c6SAmir Vadai 		if (!tc_flags_valid(fnew->flags)) {
915e69985c6SAmir Vadai 			err = -EINVAL;
916e69985c6SAmir Vadai 			goto errout;
917e69985c6SAmir Vadai 		}
918e69985c6SAmir Vadai 	}
9195b33f488SAmir Vadai 
92077b9900eSJiri Pirko 	err = fl_set_parms(net, tp, fnew, &mask, base, tb, tca[TCA_RATE], ovr);
92177b9900eSJiri Pirko 	if (err)
92277b9900eSJiri Pirko 		goto errout;
92377b9900eSJiri Pirko 
92477b9900eSJiri Pirko 	err = fl_check_assign_mask(head, &mask);
92577b9900eSJiri Pirko 	if (err)
92677b9900eSJiri Pirko 		goto errout;
92777b9900eSJiri Pirko 
928e8eb36cdSAmir Vadai 	if (!tc_skip_sw(fnew->flags)) {
929a3308d8fSPaul Blakey 		if (!fold && fl_lookup(head, &fnew->mkey)) {
930a3308d8fSPaul Blakey 			err = -EEXIST;
931a3308d8fSPaul Blakey 			goto errout;
932a3308d8fSPaul Blakey 		}
933a3308d8fSPaul Blakey 
93477b9900eSJiri Pirko 		err = rhashtable_insert_fast(&head->ht, &fnew->ht_node,
93577b9900eSJiri Pirko 					     head->ht_params);
93677b9900eSJiri Pirko 		if (err)
93777b9900eSJiri Pirko 			goto errout;
938e69985c6SAmir Vadai 	}
9395b33f488SAmir Vadai 
94079685219SHadar Hen Zion 	if (!tc_skip_hw(fnew->flags)) {
941e8eb36cdSAmir Vadai 		err = fl_hw_replace_filter(tp,
9425b33f488SAmir Vadai 					   &head->dissector,
9435b33f488SAmir Vadai 					   &mask.key,
9443036dab6SHadar Hen Zion 					   fnew);
945e8eb36cdSAmir Vadai 		if (err)
946e8eb36cdSAmir Vadai 			goto errout;
94779685219SHadar Hen Zion 	}
9485b33f488SAmir Vadai 
94955593960SOr Gerlitz 	if (!tc_in_hw(fnew->flags))
95055593960SOr Gerlitz 		fnew->flags |= TCA_CLS_FLAGS_NOT_IN_HW;
95155593960SOr Gerlitz 
9525b33f488SAmir Vadai 	if (fold) {
953725cbb62SJiri Pirko 		if (!tc_skip_sw(fold->flags))
95477b9900eSJiri Pirko 			rhashtable_remove_fast(&head->ht, &fold->ht_node,
95577b9900eSJiri Pirko 					       head->ht_params);
95679685219SHadar Hen Zion 		if (!tc_skip_hw(fold->flags))
9573036dab6SHadar Hen Zion 			fl_hw_destroy_filter(tp, fold);
9585b33f488SAmir Vadai 	}
95977b9900eSJiri Pirko 
96077b9900eSJiri Pirko 	*arg = (unsigned long) fnew;
96177b9900eSJiri Pirko 
96277b9900eSJiri Pirko 	if (fold) {
963ff3532f2SDaniel Borkmann 		list_replace_rcu(&fold->list, &fnew->list);
96477b9900eSJiri Pirko 		tcf_unbind_filter(tp, &fold->res);
96577b9900eSJiri Pirko 		call_rcu(&fold->rcu, fl_destroy_filter);
96677b9900eSJiri Pirko 	} else {
96777b9900eSJiri Pirko 		list_add_tail_rcu(&fnew->list, &head->filters);
96877b9900eSJiri Pirko 	}
96977b9900eSJiri Pirko 
97039b7b6a6SArnd Bergmann 	kfree(tb);
97177b9900eSJiri Pirko 	return 0;
97277b9900eSJiri Pirko 
97377b9900eSJiri Pirko errout:
974b9a24bb7SWANG Cong 	tcf_exts_destroy(&fnew->exts);
97577b9900eSJiri Pirko 	kfree(fnew);
97639b7b6a6SArnd Bergmann errout_tb:
97739b7b6a6SArnd Bergmann 	kfree(tb);
97877b9900eSJiri Pirko 	return err;
97977b9900eSJiri Pirko }
98077b9900eSJiri Pirko 
981763dbf63SWANG Cong static int fl_delete(struct tcf_proto *tp, unsigned long arg, bool *last)
98277b9900eSJiri Pirko {
98377b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
98477b9900eSJiri Pirko 	struct cls_fl_filter *f = (struct cls_fl_filter *) arg;
98577b9900eSJiri Pirko 
986725cbb62SJiri Pirko 	if (!tc_skip_sw(f->flags))
98777b9900eSJiri Pirko 		rhashtable_remove_fast(&head->ht, &f->ht_node,
98877b9900eSJiri Pirko 				       head->ht_params);
98913fa876eSRoi Dayan 	__fl_delete(tp, f);
990763dbf63SWANG Cong 	*last = list_empty(&head->filters);
99177b9900eSJiri Pirko 	return 0;
99277b9900eSJiri Pirko }
99377b9900eSJiri Pirko 
99477b9900eSJiri Pirko static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg)
99577b9900eSJiri Pirko {
99677b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
99777b9900eSJiri Pirko 	struct cls_fl_filter *f;
99877b9900eSJiri Pirko 
99977b9900eSJiri Pirko 	list_for_each_entry_rcu(f, &head->filters, list) {
100077b9900eSJiri Pirko 		if (arg->count < arg->skip)
100177b9900eSJiri Pirko 			goto skip;
100277b9900eSJiri Pirko 		if (arg->fn(tp, (unsigned long) f, arg) < 0) {
100377b9900eSJiri Pirko 			arg->stop = 1;
100477b9900eSJiri Pirko 			break;
100577b9900eSJiri Pirko 		}
100677b9900eSJiri Pirko skip:
100777b9900eSJiri Pirko 		arg->count++;
100877b9900eSJiri Pirko 	}
100977b9900eSJiri Pirko }
101077b9900eSJiri Pirko 
101177b9900eSJiri Pirko static int fl_dump_key_val(struct sk_buff *skb,
101277b9900eSJiri Pirko 			   void *val, int val_type,
101377b9900eSJiri Pirko 			   void *mask, int mask_type, int len)
101477b9900eSJiri Pirko {
101577b9900eSJiri Pirko 	int err;
101677b9900eSJiri Pirko 
101777b9900eSJiri Pirko 	if (!memchr_inv(mask, 0, len))
101877b9900eSJiri Pirko 		return 0;
101977b9900eSJiri Pirko 	err = nla_put(skb, val_type, len, val);
102077b9900eSJiri Pirko 	if (err)
102177b9900eSJiri Pirko 		return err;
102277b9900eSJiri Pirko 	if (mask_type != TCA_FLOWER_UNSPEC) {
102377b9900eSJiri Pirko 		err = nla_put(skb, mask_type, len, mask);
102477b9900eSJiri Pirko 		if (err)
102577b9900eSJiri Pirko 			return err;
102677b9900eSJiri Pirko 	}
102777b9900eSJiri Pirko 	return 0;
102877b9900eSJiri Pirko }
102977b9900eSJiri Pirko 
1030*a577d8f7SBenjamin LaHaise static int fl_dump_key_mpls(struct sk_buff *skb,
1031*a577d8f7SBenjamin LaHaise 			    struct flow_dissector_key_mpls *mpls_key,
1032*a577d8f7SBenjamin LaHaise 			    struct flow_dissector_key_mpls *mpls_mask)
1033*a577d8f7SBenjamin LaHaise {
1034*a577d8f7SBenjamin LaHaise 	int err;
1035*a577d8f7SBenjamin LaHaise 
1036*a577d8f7SBenjamin LaHaise 	if (!memchr_inv(mpls_mask, 0, sizeof(*mpls_mask)))
1037*a577d8f7SBenjamin LaHaise 		return 0;
1038*a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_ttl) {
1039*a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TTL,
1040*a577d8f7SBenjamin LaHaise 				 mpls_key->mpls_ttl);
1041*a577d8f7SBenjamin LaHaise 		if (err)
1042*a577d8f7SBenjamin LaHaise 			return err;
1043*a577d8f7SBenjamin LaHaise 	}
1044*a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_tc) {
1045*a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_TC,
1046*a577d8f7SBenjamin LaHaise 				 mpls_key->mpls_tc);
1047*a577d8f7SBenjamin LaHaise 		if (err)
1048*a577d8f7SBenjamin LaHaise 			return err;
1049*a577d8f7SBenjamin LaHaise 	}
1050*a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_label) {
1051*a577d8f7SBenjamin LaHaise 		err = nla_put_u32(skb, TCA_FLOWER_KEY_MPLS_LABEL,
1052*a577d8f7SBenjamin LaHaise 				  mpls_key->mpls_label);
1053*a577d8f7SBenjamin LaHaise 		if (err)
1054*a577d8f7SBenjamin LaHaise 			return err;
1055*a577d8f7SBenjamin LaHaise 	}
1056*a577d8f7SBenjamin LaHaise 	if (mpls_mask->mpls_bos) {
1057*a577d8f7SBenjamin LaHaise 		err = nla_put_u8(skb, TCA_FLOWER_KEY_MPLS_BOS,
1058*a577d8f7SBenjamin LaHaise 				 mpls_key->mpls_bos);
1059*a577d8f7SBenjamin LaHaise 		if (err)
1060*a577d8f7SBenjamin LaHaise 			return err;
1061*a577d8f7SBenjamin LaHaise 	}
1062*a577d8f7SBenjamin LaHaise 	return 0;
1063*a577d8f7SBenjamin LaHaise }
1064*a577d8f7SBenjamin LaHaise 
10659399ae9aSHadar Hen Zion static int fl_dump_key_vlan(struct sk_buff *skb,
10669399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *vlan_key,
10679399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *vlan_mask)
10689399ae9aSHadar Hen Zion {
10699399ae9aSHadar Hen Zion 	int err;
10709399ae9aSHadar Hen Zion 
10719399ae9aSHadar Hen Zion 	if (!memchr_inv(vlan_mask, 0, sizeof(*vlan_mask)))
10729399ae9aSHadar Hen Zion 		return 0;
10739399ae9aSHadar Hen Zion 	if (vlan_mask->vlan_id) {
10749399ae9aSHadar Hen Zion 		err = nla_put_u16(skb, TCA_FLOWER_KEY_VLAN_ID,
10759399ae9aSHadar Hen Zion 				  vlan_key->vlan_id);
10769399ae9aSHadar Hen Zion 		if (err)
10779399ae9aSHadar Hen Zion 			return err;
10789399ae9aSHadar Hen Zion 	}
10799399ae9aSHadar Hen Zion 	if (vlan_mask->vlan_priority) {
10809399ae9aSHadar Hen Zion 		err = nla_put_u8(skb, TCA_FLOWER_KEY_VLAN_PRIO,
10819399ae9aSHadar Hen Zion 				 vlan_key->vlan_priority);
10829399ae9aSHadar Hen Zion 		if (err)
10839399ae9aSHadar Hen Zion 			return err;
10849399ae9aSHadar Hen Zion 	}
10859399ae9aSHadar Hen Zion 	return 0;
10869399ae9aSHadar Hen Zion }
10879399ae9aSHadar Hen Zion 
1088faa3ffceSOr Gerlitz static void fl_get_key_flag(u32 dissector_key, u32 dissector_mask,
1089faa3ffceSOr Gerlitz 			    u32 *flower_key, u32 *flower_mask,
1090faa3ffceSOr Gerlitz 			    u32 flower_flag_bit, u32 dissector_flag_bit)
1091faa3ffceSOr Gerlitz {
1092faa3ffceSOr Gerlitz 	if (dissector_mask & dissector_flag_bit) {
1093faa3ffceSOr Gerlitz 		*flower_mask |= flower_flag_bit;
1094faa3ffceSOr Gerlitz 		if (dissector_key & dissector_flag_bit)
1095faa3ffceSOr Gerlitz 			*flower_key |= flower_flag_bit;
1096faa3ffceSOr Gerlitz 	}
1097faa3ffceSOr Gerlitz }
1098faa3ffceSOr Gerlitz 
1099faa3ffceSOr Gerlitz static int fl_dump_key_flags(struct sk_buff *skb, u32 flags_key, u32 flags_mask)
1100faa3ffceSOr Gerlitz {
1101faa3ffceSOr Gerlitz 	u32 key, mask;
1102faa3ffceSOr Gerlitz 	__be32 _key, _mask;
1103faa3ffceSOr Gerlitz 	int err;
1104faa3ffceSOr Gerlitz 
1105faa3ffceSOr Gerlitz 	if (!memchr_inv(&flags_mask, 0, sizeof(flags_mask)))
1106faa3ffceSOr Gerlitz 		return 0;
1107faa3ffceSOr Gerlitz 
1108faa3ffceSOr Gerlitz 	key = 0;
1109faa3ffceSOr Gerlitz 	mask = 0;
1110faa3ffceSOr Gerlitz 
1111faa3ffceSOr Gerlitz 	fl_get_key_flag(flags_key, flags_mask, &key, &mask,
1112faa3ffceSOr Gerlitz 			TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT);
1113faa3ffceSOr Gerlitz 
1114faa3ffceSOr Gerlitz 	_key = cpu_to_be32(key);
1115faa3ffceSOr Gerlitz 	_mask = cpu_to_be32(mask);
1116faa3ffceSOr Gerlitz 
1117faa3ffceSOr Gerlitz 	err = nla_put(skb, TCA_FLOWER_KEY_FLAGS, 4, &_key);
1118faa3ffceSOr Gerlitz 	if (err)
1119faa3ffceSOr Gerlitz 		return err;
1120faa3ffceSOr Gerlitz 
1121faa3ffceSOr Gerlitz 	return nla_put(skb, TCA_FLOWER_KEY_FLAGS_MASK, 4, &_mask);
1122faa3ffceSOr Gerlitz }
1123faa3ffceSOr Gerlitz 
112477b9900eSJiri Pirko static int fl_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
112577b9900eSJiri Pirko 		   struct sk_buff *skb, struct tcmsg *t)
112677b9900eSJiri Pirko {
112777b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
112877b9900eSJiri Pirko 	struct cls_fl_filter *f = (struct cls_fl_filter *) fh;
112977b9900eSJiri Pirko 	struct nlattr *nest;
113077b9900eSJiri Pirko 	struct fl_flow_key *key, *mask;
113177b9900eSJiri Pirko 
113277b9900eSJiri Pirko 	if (!f)
113377b9900eSJiri Pirko 		return skb->len;
113477b9900eSJiri Pirko 
113577b9900eSJiri Pirko 	t->tcm_handle = f->handle;
113677b9900eSJiri Pirko 
113777b9900eSJiri Pirko 	nest = nla_nest_start(skb, TCA_OPTIONS);
113877b9900eSJiri Pirko 	if (!nest)
113977b9900eSJiri Pirko 		goto nla_put_failure;
114077b9900eSJiri Pirko 
114177b9900eSJiri Pirko 	if (f->res.classid &&
114277b9900eSJiri Pirko 	    nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid))
114377b9900eSJiri Pirko 		goto nla_put_failure;
114477b9900eSJiri Pirko 
114577b9900eSJiri Pirko 	key = &f->key;
114677b9900eSJiri Pirko 	mask = &head->mask.key;
114777b9900eSJiri Pirko 
114877b9900eSJiri Pirko 	if (mask->indev_ifindex) {
114977b9900eSJiri Pirko 		struct net_device *dev;
115077b9900eSJiri Pirko 
115177b9900eSJiri Pirko 		dev = __dev_get_by_index(net, key->indev_ifindex);
115277b9900eSJiri Pirko 		if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name))
115377b9900eSJiri Pirko 			goto nla_put_failure;
115477b9900eSJiri Pirko 	}
115577b9900eSJiri Pirko 
115679685219SHadar Hen Zion 	if (!tc_skip_hw(f->flags))
115710cbc684SAmir Vadai 		fl_hw_update_stats(tp, f);
115810cbc684SAmir Vadai 
115977b9900eSJiri Pirko 	if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
116077b9900eSJiri Pirko 			    mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
116177b9900eSJiri Pirko 			    sizeof(key->eth.dst)) ||
116277b9900eSJiri Pirko 	    fl_dump_key_val(skb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
116377b9900eSJiri Pirko 			    mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
116477b9900eSJiri Pirko 			    sizeof(key->eth.src)) ||
116577b9900eSJiri Pirko 	    fl_dump_key_val(skb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE,
116677b9900eSJiri Pirko 			    &mask->basic.n_proto, TCA_FLOWER_UNSPEC,
116777b9900eSJiri Pirko 			    sizeof(key->basic.n_proto)))
116877b9900eSJiri Pirko 		goto nla_put_failure;
11699399ae9aSHadar Hen Zion 
1170*a577d8f7SBenjamin LaHaise 	if (fl_dump_key_mpls(skb, &key->mpls, &mask->mpls))
1171*a577d8f7SBenjamin LaHaise 		goto nla_put_failure;
1172*a577d8f7SBenjamin LaHaise 
11739399ae9aSHadar Hen Zion 	if (fl_dump_key_vlan(skb, &key->vlan, &mask->vlan))
11749399ae9aSHadar Hen Zion 		goto nla_put_failure;
11759399ae9aSHadar Hen Zion 
117677b9900eSJiri Pirko 	if ((key->basic.n_proto == htons(ETH_P_IP) ||
117777b9900eSJiri Pirko 	     key->basic.n_proto == htons(ETH_P_IPV6)) &&
117877b9900eSJiri Pirko 	    fl_dump_key_val(skb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
117977b9900eSJiri Pirko 			    &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
118077b9900eSJiri Pirko 			    sizeof(key->basic.ip_proto)))
118177b9900eSJiri Pirko 		goto nla_put_failure;
118277b9900eSJiri Pirko 
1183c3f83241STom Herbert 	if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
118477b9900eSJiri Pirko 	    (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
118577b9900eSJiri Pirko 			     &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
118677b9900eSJiri Pirko 			     sizeof(key->ipv4.src)) ||
118777b9900eSJiri Pirko 	     fl_dump_key_val(skb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
118877b9900eSJiri Pirko 			     &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
118977b9900eSJiri Pirko 			     sizeof(key->ipv4.dst))))
119077b9900eSJiri Pirko 		goto nla_put_failure;
1191c3f83241STom Herbert 	else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
119277b9900eSJiri Pirko 		 (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
119377b9900eSJiri Pirko 				  &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
119477b9900eSJiri Pirko 				  sizeof(key->ipv6.src)) ||
119577b9900eSJiri Pirko 		  fl_dump_key_val(skb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
119677b9900eSJiri Pirko 				  &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
119777b9900eSJiri Pirko 				  sizeof(key->ipv6.dst))))
119877b9900eSJiri Pirko 		goto nla_put_failure;
119977b9900eSJiri Pirko 
120077b9900eSJiri Pirko 	if (key->basic.ip_proto == IPPROTO_TCP &&
120177b9900eSJiri Pirko 	    (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
1202aa72d708SOr Gerlitz 			     &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
120377b9900eSJiri Pirko 			     sizeof(key->tp.src)) ||
120477b9900eSJiri Pirko 	     fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
1205aa72d708SOr Gerlitz 			     &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
120677b9900eSJiri Pirko 			     sizeof(key->tp.dst))))
120777b9900eSJiri Pirko 		goto nla_put_failure;
120877b9900eSJiri Pirko 	else if (key->basic.ip_proto == IPPROTO_UDP &&
120977b9900eSJiri Pirko 		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
1210aa72d708SOr Gerlitz 				  &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
121177b9900eSJiri Pirko 				  sizeof(key->tp.src)) ||
121277b9900eSJiri Pirko 		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
1213aa72d708SOr Gerlitz 				  &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
121477b9900eSJiri Pirko 				  sizeof(key->tp.dst))))
121577b9900eSJiri Pirko 		goto nla_put_failure;
12165976c5f4SSimon Horman 	else if (key->basic.ip_proto == IPPROTO_SCTP &&
12175976c5f4SSimon Horman 		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
12185976c5f4SSimon Horman 				  &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
12195976c5f4SSimon Horman 				  sizeof(key->tp.src)) ||
12205976c5f4SSimon Horman 		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
12215976c5f4SSimon Horman 				  &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
12225976c5f4SSimon Horman 				  sizeof(key->tp.dst))))
12235976c5f4SSimon Horman 		goto nla_put_failure;
12247b684884SSimon Horman 	else if (key->basic.n_proto == htons(ETH_P_IP) &&
12257b684884SSimon Horman 		 key->basic.ip_proto == IPPROTO_ICMP &&
12267b684884SSimon Horman 		 (fl_dump_key_val(skb, &key->icmp.type,
12277b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_TYPE, &mask->icmp.type,
12287b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,
12297b684884SSimon Horman 				  sizeof(key->icmp.type)) ||
12307b684884SSimon Horman 		  fl_dump_key_val(skb, &key->icmp.code,
12317b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_CODE, &mask->icmp.code,
12327b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
12337b684884SSimon Horman 				  sizeof(key->icmp.code))))
12347b684884SSimon Horman 		goto nla_put_failure;
12357b684884SSimon Horman 	else if (key->basic.n_proto == htons(ETH_P_IPV6) &&
12367b684884SSimon Horman 		 key->basic.ip_proto == IPPROTO_ICMPV6 &&
12377b684884SSimon Horman 		 (fl_dump_key_val(skb, &key->icmp.type,
12387b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_TYPE, &mask->icmp.type,
12397b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
12407b684884SSimon Horman 				  sizeof(key->icmp.type)) ||
12417b684884SSimon Horman 		  fl_dump_key_val(skb, &key->icmp.code,
12427b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_CODE, &mask->icmp.code,
12437b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_CODE_MASK,
12447b684884SSimon Horman 				  sizeof(key->icmp.code))))
12457b684884SSimon Horman 		goto nla_put_failure;
124699d31326SSimon Horman 	else if ((key->basic.n_proto == htons(ETH_P_ARP) ||
124799d31326SSimon Horman 		  key->basic.n_proto == htons(ETH_P_RARP)) &&
124899d31326SSimon Horman 		 (fl_dump_key_val(skb, &key->arp.sip,
124999d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_SIP, &mask->arp.sip,
125099d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_SIP_MASK,
125199d31326SSimon Horman 				  sizeof(key->arp.sip)) ||
125299d31326SSimon Horman 		  fl_dump_key_val(skb, &key->arp.tip,
125399d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_TIP, &mask->arp.tip,
125499d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_TIP_MASK,
125599d31326SSimon Horman 				  sizeof(key->arp.tip)) ||
125699d31326SSimon Horman 		  fl_dump_key_val(skb, &key->arp.op,
125799d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_OP, &mask->arp.op,
125899d31326SSimon Horman 				  TCA_FLOWER_KEY_ARP_OP_MASK,
125999d31326SSimon Horman 				  sizeof(key->arp.op)) ||
126099d31326SSimon Horman 		  fl_dump_key_val(skb, key->arp.sha, TCA_FLOWER_KEY_ARP_SHA,
126199d31326SSimon Horman 				  mask->arp.sha, TCA_FLOWER_KEY_ARP_SHA_MASK,
126299d31326SSimon Horman 				  sizeof(key->arp.sha)) ||
126399d31326SSimon Horman 		  fl_dump_key_val(skb, key->arp.tha, TCA_FLOWER_KEY_ARP_THA,
126499d31326SSimon Horman 				  mask->arp.tha, TCA_FLOWER_KEY_ARP_THA_MASK,
126599d31326SSimon Horman 				  sizeof(key->arp.tha))))
126699d31326SSimon Horman 		goto nla_put_failure;
126777b9900eSJiri Pirko 
1268bc3103f1SAmir Vadai 	if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
1269bc3103f1SAmir Vadai 	    (fl_dump_key_val(skb, &key->enc_ipv4.src,
1270bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV4_SRC, &mask->enc_ipv4.src,
1271bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
1272bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv4.src)) ||
1273bc3103f1SAmir Vadai 	     fl_dump_key_val(skb, &key->enc_ipv4.dst,
1274bc3103f1SAmir Vadai 			     TCA_FLOWER_KEY_ENC_IPV4_DST, &mask->enc_ipv4.dst,
1275bc3103f1SAmir Vadai 			     TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
1276bc3103f1SAmir Vadai 			     sizeof(key->enc_ipv4.dst))))
1277bc3103f1SAmir Vadai 		goto nla_put_failure;
1278bc3103f1SAmir Vadai 	else if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
1279bc3103f1SAmir Vadai 		 (fl_dump_key_val(skb, &key->enc_ipv6.src,
1280bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV6_SRC, &mask->enc_ipv6.src,
1281bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
1282bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv6.src)) ||
1283bc3103f1SAmir Vadai 		 fl_dump_key_val(skb, &key->enc_ipv6.dst,
1284bc3103f1SAmir Vadai 				 TCA_FLOWER_KEY_ENC_IPV6_DST,
1285bc3103f1SAmir Vadai 				 &mask->enc_ipv6.dst,
1286bc3103f1SAmir Vadai 				 TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
1287bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv6.dst))))
1288bc3103f1SAmir Vadai 		goto nla_put_failure;
1289bc3103f1SAmir Vadai 
1290bc3103f1SAmir Vadai 	if (fl_dump_key_val(skb, &key->enc_key_id, TCA_FLOWER_KEY_ENC_KEY_ID,
1291eb523f42SHadar Hen Zion 			    &mask->enc_key_id, TCA_FLOWER_UNSPEC,
1292f4d997fdSHadar Hen Zion 			    sizeof(key->enc_key_id)) ||
1293f4d997fdSHadar Hen Zion 	    fl_dump_key_val(skb, &key->enc_tp.src,
1294f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
1295f4d997fdSHadar Hen Zion 			    &mask->enc_tp.src,
1296f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
1297f4d997fdSHadar Hen Zion 			    sizeof(key->enc_tp.src)) ||
1298f4d997fdSHadar Hen Zion 	    fl_dump_key_val(skb, &key->enc_tp.dst,
1299f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
1300f4d997fdSHadar Hen Zion 			    &mask->enc_tp.dst,
1301f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
1302f4d997fdSHadar Hen Zion 			    sizeof(key->enc_tp.dst)))
1303bc3103f1SAmir Vadai 		goto nla_put_failure;
1304bc3103f1SAmir Vadai 
1305faa3ffceSOr Gerlitz 	if (fl_dump_key_flags(skb, key->control.flags, mask->control.flags))
1306faa3ffceSOr Gerlitz 		goto nla_put_failure;
1307faa3ffceSOr Gerlitz 
1308749e6720SOr Gerlitz 	if (f->flags && nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags))
1309749e6720SOr Gerlitz 		goto nla_put_failure;
1310e69985c6SAmir Vadai 
131177b9900eSJiri Pirko 	if (tcf_exts_dump(skb, &f->exts))
131277b9900eSJiri Pirko 		goto nla_put_failure;
131377b9900eSJiri Pirko 
131477b9900eSJiri Pirko 	nla_nest_end(skb, nest);
131577b9900eSJiri Pirko 
131677b9900eSJiri Pirko 	if (tcf_exts_dump_stats(skb, &f->exts) < 0)
131777b9900eSJiri Pirko 		goto nla_put_failure;
131877b9900eSJiri Pirko 
131977b9900eSJiri Pirko 	return skb->len;
132077b9900eSJiri Pirko 
132177b9900eSJiri Pirko nla_put_failure:
132277b9900eSJiri Pirko 	nla_nest_cancel(skb, nest);
132377b9900eSJiri Pirko 	return -1;
132477b9900eSJiri Pirko }
132577b9900eSJiri Pirko 
132677b9900eSJiri Pirko static struct tcf_proto_ops cls_fl_ops __read_mostly = {
132777b9900eSJiri Pirko 	.kind		= "flower",
132877b9900eSJiri Pirko 	.classify	= fl_classify,
132977b9900eSJiri Pirko 	.init		= fl_init,
133077b9900eSJiri Pirko 	.destroy	= fl_destroy,
133177b9900eSJiri Pirko 	.get		= fl_get,
133277b9900eSJiri Pirko 	.change		= fl_change,
133377b9900eSJiri Pirko 	.delete		= fl_delete,
133477b9900eSJiri Pirko 	.walk		= fl_walk,
133577b9900eSJiri Pirko 	.dump		= fl_dump,
133677b9900eSJiri Pirko 	.owner		= THIS_MODULE,
133777b9900eSJiri Pirko };
133877b9900eSJiri Pirko 
133977b9900eSJiri Pirko static int __init cls_fl_init(void)
134077b9900eSJiri Pirko {
134177b9900eSJiri Pirko 	return register_tcf_proto_ops(&cls_fl_ops);
134277b9900eSJiri Pirko }
134377b9900eSJiri Pirko 
134477b9900eSJiri Pirko static void __exit cls_fl_exit(void)
134577b9900eSJiri Pirko {
134677b9900eSJiri Pirko 	unregister_tcf_proto_ops(&cls_fl_ops);
134777b9900eSJiri Pirko }
134877b9900eSJiri Pirko 
134977b9900eSJiri Pirko module_init(cls_fl_init);
135077b9900eSJiri Pirko module_exit(cls_fl_exit);
135177b9900eSJiri Pirko 
135277b9900eSJiri Pirko MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>");
135377b9900eSJiri Pirko MODULE_DESCRIPTION("Flower classifier");
135477b9900eSJiri Pirko MODULE_LICENSE("GPL v2");
1355