xref: /linux/net/sched/cls_flower.c (revision f93bd17b916959fc20fbb7dc578e1f2657a8c343)
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>
2177b9900eSJiri Pirko 
2277b9900eSJiri Pirko #include <net/sch_generic.h>
2377b9900eSJiri Pirko #include <net/pkt_cls.h>
2477b9900eSJiri Pirko #include <net/ip.h>
2577b9900eSJiri Pirko #include <net/flow_dissector.h>
2677b9900eSJiri Pirko 
27bc3103f1SAmir Vadai #include <net/dst.h>
28bc3103f1SAmir Vadai #include <net/dst_metadata.h>
29bc3103f1SAmir Vadai 
3077b9900eSJiri Pirko struct fl_flow_key {
3177b9900eSJiri Pirko 	int	indev_ifindex;
3242aecaa9STom Herbert 	struct flow_dissector_key_control control;
33bc3103f1SAmir Vadai 	struct flow_dissector_key_control enc_control;
3477b9900eSJiri Pirko 	struct flow_dissector_key_basic basic;
3577b9900eSJiri Pirko 	struct flow_dissector_key_eth_addrs eth;
369399ae9aSHadar Hen Zion 	struct flow_dissector_key_vlan vlan;
3777b9900eSJiri Pirko 	union {
38c3f83241STom Herbert 		struct flow_dissector_key_ipv4_addrs ipv4;
3977b9900eSJiri Pirko 		struct flow_dissector_key_ipv6_addrs ipv6;
4077b9900eSJiri Pirko 	};
4177b9900eSJiri Pirko 	struct flow_dissector_key_ports tp;
427b684884SSimon Horman 	struct flow_dissector_key_icmp icmp;
43bc3103f1SAmir Vadai 	struct flow_dissector_key_keyid enc_key_id;
44bc3103f1SAmir Vadai 	union {
45bc3103f1SAmir Vadai 		struct flow_dissector_key_ipv4_addrs enc_ipv4;
46bc3103f1SAmir Vadai 		struct flow_dissector_key_ipv6_addrs enc_ipv6;
47bc3103f1SAmir Vadai 	};
48f4d997fdSHadar Hen Zion 	struct flow_dissector_key_ports enc_tp;
4977b9900eSJiri Pirko } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
5077b9900eSJiri Pirko 
5177b9900eSJiri Pirko struct fl_flow_mask_range {
5277b9900eSJiri Pirko 	unsigned short int start;
5377b9900eSJiri Pirko 	unsigned short int end;
5477b9900eSJiri Pirko };
5577b9900eSJiri Pirko 
5677b9900eSJiri Pirko struct fl_flow_mask {
5777b9900eSJiri Pirko 	struct fl_flow_key key;
5877b9900eSJiri Pirko 	struct fl_flow_mask_range range;
5977b9900eSJiri Pirko 	struct rcu_head	rcu;
6077b9900eSJiri Pirko };
6177b9900eSJiri Pirko 
6277b9900eSJiri Pirko struct cls_fl_head {
6377b9900eSJiri Pirko 	struct rhashtable ht;
6477b9900eSJiri Pirko 	struct fl_flow_mask mask;
6577b9900eSJiri Pirko 	struct flow_dissector dissector;
6677b9900eSJiri Pirko 	u32 hgen;
6777b9900eSJiri Pirko 	bool mask_assigned;
6877b9900eSJiri Pirko 	struct list_head filters;
6977b9900eSJiri Pirko 	struct rhashtable_params ht_params;
70d9363774SDaniel Borkmann 	union {
71d9363774SDaniel Borkmann 		struct work_struct work;
7277b9900eSJiri Pirko 		struct rcu_head	rcu;
7377b9900eSJiri Pirko 	};
74d9363774SDaniel Borkmann };
7577b9900eSJiri Pirko 
7677b9900eSJiri Pirko struct cls_fl_filter {
7777b9900eSJiri Pirko 	struct rhash_head ht_node;
7877b9900eSJiri Pirko 	struct fl_flow_key mkey;
7977b9900eSJiri Pirko 	struct tcf_exts exts;
8077b9900eSJiri Pirko 	struct tcf_result res;
8177b9900eSJiri Pirko 	struct fl_flow_key key;
8277b9900eSJiri Pirko 	struct list_head list;
8377b9900eSJiri Pirko 	u32 handle;
84e69985c6SAmir Vadai 	u32 flags;
8577b9900eSJiri Pirko 	struct rcu_head	rcu;
867091d8c7SHadar Hen Zion 	struct tc_to_netdev tc;
877091d8c7SHadar Hen Zion 	struct net_device *hw_dev;
8877b9900eSJiri Pirko };
8977b9900eSJiri Pirko 
9077b9900eSJiri Pirko static unsigned short int fl_mask_range(const struct fl_flow_mask *mask)
9177b9900eSJiri Pirko {
9277b9900eSJiri Pirko 	return mask->range.end - mask->range.start;
9377b9900eSJiri Pirko }
9477b9900eSJiri Pirko 
9577b9900eSJiri Pirko static void fl_mask_update_range(struct fl_flow_mask *mask)
9677b9900eSJiri Pirko {
9777b9900eSJiri Pirko 	const u8 *bytes = (const u8 *) &mask->key;
9877b9900eSJiri Pirko 	size_t size = sizeof(mask->key);
9977b9900eSJiri Pirko 	size_t i, first = 0, last = size - 1;
10077b9900eSJiri Pirko 
10177b9900eSJiri Pirko 	for (i = 0; i < sizeof(mask->key); i++) {
10277b9900eSJiri Pirko 		if (bytes[i]) {
10377b9900eSJiri Pirko 			if (!first && i)
10477b9900eSJiri Pirko 				first = i;
10577b9900eSJiri Pirko 			last = i;
10677b9900eSJiri Pirko 		}
10777b9900eSJiri Pirko 	}
10877b9900eSJiri Pirko 	mask->range.start = rounddown(first, sizeof(long));
10977b9900eSJiri Pirko 	mask->range.end = roundup(last + 1, sizeof(long));
11077b9900eSJiri Pirko }
11177b9900eSJiri Pirko 
11277b9900eSJiri Pirko static void *fl_key_get_start(struct fl_flow_key *key,
11377b9900eSJiri Pirko 			      const struct fl_flow_mask *mask)
11477b9900eSJiri Pirko {
11577b9900eSJiri Pirko 	return (u8 *) key + mask->range.start;
11677b9900eSJiri Pirko }
11777b9900eSJiri Pirko 
11877b9900eSJiri Pirko static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key,
11977b9900eSJiri Pirko 			      struct fl_flow_mask *mask)
12077b9900eSJiri Pirko {
12177b9900eSJiri Pirko 	const long *lkey = fl_key_get_start(key, mask);
12277b9900eSJiri Pirko 	const long *lmask = fl_key_get_start(&mask->key, mask);
12377b9900eSJiri Pirko 	long *lmkey = fl_key_get_start(mkey, mask);
12477b9900eSJiri Pirko 	int i;
12577b9900eSJiri Pirko 
12677b9900eSJiri Pirko 	for (i = 0; i < fl_mask_range(mask); i += sizeof(long))
12777b9900eSJiri Pirko 		*lmkey++ = *lkey++ & *lmask++;
12877b9900eSJiri Pirko }
12977b9900eSJiri Pirko 
13077b9900eSJiri Pirko static void fl_clear_masked_range(struct fl_flow_key *key,
13177b9900eSJiri Pirko 				  struct fl_flow_mask *mask)
13277b9900eSJiri Pirko {
13377b9900eSJiri Pirko 	memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask));
13477b9900eSJiri Pirko }
13577b9900eSJiri Pirko 
13677b9900eSJiri Pirko static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp,
13777b9900eSJiri Pirko 		       struct tcf_result *res)
13877b9900eSJiri Pirko {
13977b9900eSJiri Pirko 	struct cls_fl_head *head = rcu_dereference_bh(tp->root);
14077b9900eSJiri Pirko 	struct cls_fl_filter *f;
14177b9900eSJiri Pirko 	struct fl_flow_key skb_key;
14277b9900eSJiri Pirko 	struct fl_flow_key skb_mkey;
143bc3103f1SAmir Vadai 	struct ip_tunnel_info *info;
14477b9900eSJiri Pirko 
145e69985c6SAmir Vadai 	if (!atomic_read(&head->ht.nelems))
146e69985c6SAmir Vadai 		return -1;
147e69985c6SAmir Vadai 
14877b9900eSJiri Pirko 	fl_clear_masked_range(&skb_key, &head->mask);
149bc3103f1SAmir Vadai 
150bc3103f1SAmir Vadai 	info = skb_tunnel_info(skb);
151bc3103f1SAmir Vadai 	if (info) {
152bc3103f1SAmir Vadai 		struct ip_tunnel_key *key = &info->key;
153bc3103f1SAmir Vadai 
154bc3103f1SAmir Vadai 		switch (ip_tunnel_info_af(info)) {
155bc3103f1SAmir Vadai 		case AF_INET:
156bc3103f1SAmir Vadai 			skb_key.enc_ipv4.src = key->u.ipv4.src;
157bc3103f1SAmir Vadai 			skb_key.enc_ipv4.dst = key->u.ipv4.dst;
158bc3103f1SAmir Vadai 			break;
159bc3103f1SAmir Vadai 		case AF_INET6:
160bc3103f1SAmir Vadai 			skb_key.enc_ipv6.src = key->u.ipv6.src;
161bc3103f1SAmir Vadai 			skb_key.enc_ipv6.dst = key->u.ipv6.dst;
162bc3103f1SAmir Vadai 			break;
163bc3103f1SAmir Vadai 		}
164bc3103f1SAmir Vadai 
165bc3103f1SAmir Vadai 		skb_key.enc_key_id.keyid = tunnel_id_to_key32(key->tun_id);
166f4d997fdSHadar Hen Zion 		skb_key.enc_tp.src = key->tp_src;
167f4d997fdSHadar Hen Zion 		skb_key.enc_tp.dst = key->tp_dst;
168bc3103f1SAmir Vadai 	}
169bc3103f1SAmir Vadai 
17077b9900eSJiri Pirko 	skb_key.indev_ifindex = skb->skb_iif;
17177b9900eSJiri Pirko 	/* skb_flow_dissect() does not set n_proto in case an unknown protocol,
17277b9900eSJiri Pirko 	 * so do it rather here.
17377b9900eSJiri Pirko 	 */
17477b9900eSJiri Pirko 	skb_key.basic.n_proto = skb->protocol;
175cd79a238STom Herbert 	skb_flow_dissect(skb, &head->dissector, &skb_key, 0);
17677b9900eSJiri Pirko 
17777b9900eSJiri Pirko 	fl_set_masked_key(&skb_mkey, &skb_key, &head->mask);
17877b9900eSJiri Pirko 
17977b9900eSJiri Pirko 	f = rhashtable_lookup_fast(&head->ht,
18077b9900eSJiri Pirko 				   fl_key_get_start(&skb_mkey, &head->mask),
18177b9900eSJiri Pirko 				   head->ht_params);
182e8eb36cdSAmir Vadai 	if (f && !tc_skip_sw(f->flags)) {
18377b9900eSJiri Pirko 		*res = f->res;
18477b9900eSJiri Pirko 		return tcf_exts_exec(skb, &f->exts, res);
18577b9900eSJiri Pirko 	}
18677b9900eSJiri Pirko 	return -1;
18777b9900eSJiri Pirko }
18877b9900eSJiri Pirko 
18977b9900eSJiri Pirko static int fl_init(struct tcf_proto *tp)
19077b9900eSJiri Pirko {
19177b9900eSJiri Pirko 	struct cls_fl_head *head;
19277b9900eSJiri Pirko 
19377b9900eSJiri Pirko 	head = kzalloc(sizeof(*head), GFP_KERNEL);
19477b9900eSJiri Pirko 	if (!head)
19577b9900eSJiri Pirko 		return -ENOBUFS;
19677b9900eSJiri Pirko 
19777b9900eSJiri Pirko 	INIT_LIST_HEAD_RCU(&head->filters);
19877b9900eSJiri Pirko 	rcu_assign_pointer(tp->root, head);
19977b9900eSJiri Pirko 
20077b9900eSJiri Pirko 	return 0;
20177b9900eSJiri Pirko }
20277b9900eSJiri Pirko 
20377b9900eSJiri Pirko static void fl_destroy_filter(struct rcu_head *head)
20477b9900eSJiri Pirko {
20577b9900eSJiri Pirko 	struct cls_fl_filter *f = container_of(head, struct cls_fl_filter, rcu);
20677b9900eSJiri Pirko 
20777b9900eSJiri Pirko 	tcf_exts_destroy(&f->exts);
20877b9900eSJiri Pirko 	kfree(f);
20977b9900eSJiri Pirko }
21077b9900eSJiri Pirko 
2113036dab6SHadar Hen Zion static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f)
2125b33f488SAmir Vadai {
2135b33f488SAmir Vadai 	struct tc_cls_flower_offload offload = {0};
2147091d8c7SHadar Hen Zion 	struct net_device *dev = f->hw_dev;
2157091d8c7SHadar Hen Zion 	struct tc_to_netdev *tc = &f->tc;
2165b33f488SAmir Vadai 
21779685219SHadar Hen Zion 	if (!tc_can_offload(dev, tp))
2185b33f488SAmir Vadai 		return;
2195b33f488SAmir Vadai 
2205b33f488SAmir Vadai 	offload.command = TC_CLSFLOWER_DESTROY;
2213036dab6SHadar Hen Zion 	offload.cookie = (unsigned long)f;
2225b33f488SAmir Vadai 
2237091d8c7SHadar Hen Zion 	tc->type = TC_SETUP_CLSFLOWER;
2247091d8c7SHadar Hen Zion 	tc->cls_flower = &offload;
2255b33f488SAmir Vadai 
2267091d8c7SHadar Hen Zion 	dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, tc);
2275b33f488SAmir Vadai }
2285b33f488SAmir Vadai 
229e8eb36cdSAmir Vadai static int fl_hw_replace_filter(struct tcf_proto *tp,
2305b33f488SAmir Vadai 				struct flow_dissector *dissector,
2315b33f488SAmir Vadai 				struct fl_flow_key *mask,
2323036dab6SHadar Hen Zion 				struct cls_fl_filter *f)
2335b33f488SAmir Vadai {
2345b33f488SAmir Vadai 	struct net_device *dev = tp->q->dev_queue->dev;
2355b33f488SAmir Vadai 	struct tc_cls_flower_offload offload = {0};
2367091d8c7SHadar Hen Zion 	struct tc_to_netdev *tc = &f->tc;
237e8eb36cdSAmir Vadai 	int err;
2385b33f488SAmir Vadai 
2397091d8c7SHadar Hen Zion 	if (!tc_can_offload(dev, tp)) {
240a6e16931SHadar Hen Zion 		if (tcf_exts_get_dev(dev, &f->exts, &f->hw_dev) ||
241a6e16931SHadar Hen Zion 		    (f->hw_dev && !tc_can_offload(f->hw_dev, tp))) {
242a6e16931SHadar Hen Zion 			f->hw_dev = dev;
2433036dab6SHadar Hen Zion 			return tc_skip_sw(f->flags) ? -EINVAL : 0;
244a6e16931SHadar Hen Zion 		}
2457091d8c7SHadar Hen Zion 		dev = f->hw_dev;
2467091d8c7SHadar Hen Zion 		tc->egress_dev = true;
2477091d8c7SHadar Hen Zion 	} else {
2487091d8c7SHadar Hen Zion 		f->hw_dev = dev;
2497091d8c7SHadar Hen Zion 	}
2505b33f488SAmir Vadai 
2515b33f488SAmir Vadai 	offload.command = TC_CLSFLOWER_REPLACE;
2523036dab6SHadar Hen Zion 	offload.cookie = (unsigned long)f;
2535b33f488SAmir Vadai 	offload.dissector = dissector;
2545b33f488SAmir Vadai 	offload.mask = mask;
255*f93bd17bSPaul Blakey 	offload.key = &f->mkey;
2563036dab6SHadar Hen Zion 	offload.exts = &f->exts;
2575b33f488SAmir Vadai 
2587091d8c7SHadar Hen Zion 	tc->type = TC_SETUP_CLSFLOWER;
2597091d8c7SHadar Hen Zion 	tc->cls_flower = &offload;
2605b33f488SAmir Vadai 
2615a7a5555SJamal Hadi Salim 	err = dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol,
2627091d8c7SHadar Hen Zion 					    tc);
263e8eb36cdSAmir Vadai 
2643036dab6SHadar Hen Zion 	if (tc_skip_sw(f->flags))
265e8eb36cdSAmir Vadai 		return err;
266e8eb36cdSAmir Vadai 	return 0;
2675b33f488SAmir Vadai }
2685b33f488SAmir Vadai 
26910cbc684SAmir Vadai static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
27010cbc684SAmir Vadai {
27110cbc684SAmir Vadai 	struct tc_cls_flower_offload offload = {0};
2727091d8c7SHadar Hen Zion 	struct net_device *dev = f->hw_dev;
2737091d8c7SHadar Hen Zion 	struct tc_to_netdev *tc = &f->tc;
27410cbc684SAmir Vadai 
27579685219SHadar Hen Zion 	if (!tc_can_offload(dev, tp))
27610cbc684SAmir Vadai 		return;
27710cbc684SAmir Vadai 
27810cbc684SAmir Vadai 	offload.command = TC_CLSFLOWER_STATS;
27910cbc684SAmir Vadai 	offload.cookie = (unsigned long)f;
28010cbc684SAmir Vadai 	offload.exts = &f->exts;
28110cbc684SAmir Vadai 
2827091d8c7SHadar Hen Zion 	tc->type = TC_SETUP_CLSFLOWER;
2837091d8c7SHadar Hen Zion 	tc->cls_flower = &offload;
28410cbc684SAmir Vadai 
2857091d8c7SHadar Hen Zion 	dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, tc);
28610cbc684SAmir Vadai }
28710cbc684SAmir Vadai 
28813fa876eSRoi Dayan static void __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f)
28913fa876eSRoi Dayan {
29013fa876eSRoi Dayan 	list_del_rcu(&f->list);
29179685219SHadar Hen Zion 	if (!tc_skip_hw(f->flags))
2923036dab6SHadar Hen Zion 		fl_hw_destroy_filter(tp, f);
29313fa876eSRoi Dayan 	tcf_unbind_filter(tp, &f->res);
29413fa876eSRoi Dayan 	call_rcu(&f->rcu, fl_destroy_filter);
29513fa876eSRoi Dayan }
29613fa876eSRoi Dayan 
297d9363774SDaniel Borkmann static void fl_destroy_sleepable(struct work_struct *work)
298d9363774SDaniel Borkmann {
299d9363774SDaniel Borkmann 	struct cls_fl_head *head = container_of(work, struct cls_fl_head,
300d9363774SDaniel Borkmann 						work);
301d9363774SDaniel Borkmann 	if (head->mask_assigned)
302d9363774SDaniel Borkmann 		rhashtable_destroy(&head->ht);
303d9363774SDaniel Borkmann 	kfree(head);
304d9363774SDaniel Borkmann 	module_put(THIS_MODULE);
305d9363774SDaniel Borkmann }
306d9363774SDaniel Borkmann 
307d9363774SDaniel Borkmann static void fl_destroy_rcu(struct rcu_head *rcu)
308d9363774SDaniel Borkmann {
309d9363774SDaniel Borkmann 	struct cls_fl_head *head = container_of(rcu, struct cls_fl_head, rcu);
310d9363774SDaniel Borkmann 
311d9363774SDaniel Borkmann 	INIT_WORK(&head->work, fl_destroy_sleepable);
312d9363774SDaniel Borkmann 	schedule_work(&head->work);
313d9363774SDaniel Borkmann }
314d9363774SDaniel Borkmann 
31577b9900eSJiri Pirko static bool fl_destroy(struct tcf_proto *tp, bool force)
31677b9900eSJiri Pirko {
31777b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
31877b9900eSJiri Pirko 	struct cls_fl_filter *f, *next;
31977b9900eSJiri Pirko 
32077b9900eSJiri Pirko 	if (!force && !list_empty(&head->filters))
32177b9900eSJiri Pirko 		return false;
32277b9900eSJiri Pirko 
32313fa876eSRoi Dayan 	list_for_each_entry_safe(f, next, &head->filters, list)
32413fa876eSRoi Dayan 		__fl_delete(tp, f);
325d9363774SDaniel Borkmann 
326d9363774SDaniel Borkmann 	__module_get(THIS_MODULE);
327d9363774SDaniel Borkmann 	call_rcu(&head->rcu, fl_destroy_rcu);
3282745529aSDavid S. Miller 
32977b9900eSJiri Pirko 	return true;
33077b9900eSJiri Pirko }
33177b9900eSJiri Pirko 
33277b9900eSJiri Pirko static unsigned long fl_get(struct tcf_proto *tp, u32 handle)
33377b9900eSJiri Pirko {
33477b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
33577b9900eSJiri Pirko 	struct cls_fl_filter *f;
33677b9900eSJiri Pirko 
33777b9900eSJiri Pirko 	list_for_each_entry(f, &head->filters, list)
33877b9900eSJiri Pirko 		if (f->handle == handle)
33977b9900eSJiri Pirko 			return (unsigned long) f;
34077b9900eSJiri Pirko 	return 0;
34177b9900eSJiri Pirko }
34277b9900eSJiri Pirko 
34377b9900eSJiri Pirko static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
34477b9900eSJiri Pirko 	[TCA_FLOWER_UNSPEC]		= { .type = NLA_UNSPEC },
34577b9900eSJiri Pirko 	[TCA_FLOWER_CLASSID]		= { .type = NLA_U32 },
34677b9900eSJiri Pirko 	[TCA_FLOWER_INDEV]		= { .type = NLA_STRING,
34777b9900eSJiri Pirko 					    .len = IFNAMSIZ },
34877b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_DST]	= { .len = ETH_ALEN },
34977b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_DST_MASK]	= { .len = ETH_ALEN },
35077b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_SRC]	= { .len = ETH_ALEN },
35177b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_SRC_MASK]	= { .len = ETH_ALEN },
35277b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_TYPE]	= { .type = NLA_U16 },
35377b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IP_PROTO]	= { .type = NLA_U8 },
35477b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_SRC]	= { .type = NLA_U32 },
35577b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_SRC_MASK]	= { .type = NLA_U32 },
35677b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_DST]	= { .type = NLA_U32 },
35777b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_DST_MASK]	= { .type = NLA_U32 },
35877b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
35977b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_SRC_MASK]	= { .len = sizeof(struct in6_addr) },
36077b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
36177b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_DST_MASK]	= { .len = sizeof(struct in6_addr) },
36277b9900eSJiri Pirko 	[TCA_FLOWER_KEY_TCP_SRC]	= { .type = NLA_U16 },
36377b9900eSJiri Pirko 	[TCA_FLOWER_KEY_TCP_DST]	= { .type = NLA_U16 },
364b175c3a4SJamal Hadi Salim 	[TCA_FLOWER_KEY_UDP_SRC]	= { .type = NLA_U16 },
365b175c3a4SJamal Hadi Salim 	[TCA_FLOWER_KEY_UDP_DST]	= { .type = NLA_U16 },
3669399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_ID]	= { .type = NLA_U16 },
3679399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_PRIO]	= { .type = NLA_U8 },
3689399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_ETH_TYPE]	= { .type = NLA_U16 },
369bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_KEY_ID]	= { .type = NLA_U32 },
370bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_SRC]	= { .type = NLA_U32 },
371bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NLA_U32 },
372bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_DST]	= { .type = NLA_U32 },
373bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NLA_U32 },
374bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
375bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) },
376bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
377bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) },
378aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_TCP_SRC_MASK]	= { .type = NLA_U16 },
379aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_TCP_DST_MASK]	= { .type = NLA_U16 },
380aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_UDP_SRC_MASK]	= { .type = NLA_U16 },
381aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_UDP_DST_MASK]	= { .type = NLA_U16 },
3825976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_SRC_MASK]	= { .type = NLA_U16 },
3835976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_DST_MASK]	= { .type = NLA_U16 },
3845976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_SRC]	= { .type = NLA_U16 },
3855976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_DST]	= { .type = NLA_U16 },
386f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT]	= { .type = NLA_U16 },
387f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK]	= { .type = NLA_U16 },
388f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]	= { .type = NLA_U16 },
389f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK]	= { .type = NLA_U16 },
390faa3ffceSOr Gerlitz 	[TCA_FLOWER_KEY_FLAGS]		= { .type = NLA_U32 },
391faa3ffceSOr Gerlitz 	[TCA_FLOWER_KEY_FLAGS_MASK]	= { .type = NLA_U32 },
3927b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_TYPE]	= { .type = NLA_U8 },
3937b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_TYPE_MASK] = { .type = NLA_U8 },
3947b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_CODE]	= { .type = NLA_U8 },
3957b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV4_CODE_MASK] = { .type = NLA_U8 },
3967b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_TYPE]	= { .type = NLA_U8 },
3977b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_TYPE_MASK] = { .type = NLA_U8 },
3987b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_CODE]	= { .type = NLA_U8 },
3997b684884SSimon Horman 	[TCA_FLOWER_KEY_ICMPV6_CODE_MASK] = { .type = NLA_U8 },
40077b9900eSJiri Pirko };
40177b9900eSJiri Pirko 
40277b9900eSJiri Pirko static void fl_set_key_val(struct nlattr **tb,
40377b9900eSJiri Pirko 			   void *val, int val_type,
40477b9900eSJiri Pirko 			   void *mask, int mask_type, int len)
40577b9900eSJiri Pirko {
40677b9900eSJiri Pirko 	if (!tb[val_type])
40777b9900eSJiri Pirko 		return;
40877b9900eSJiri Pirko 	memcpy(val, nla_data(tb[val_type]), len);
40977b9900eSJiri Pirko 	if (mask_type == TCA_FLOWER_UNSPEC || !tb[mask_type])
41077b9900eSJiri Pirko 		memset(mask, 0xff, len);
41177b9900eSJiri Pirko 	else
41277b9900eSJiri Pirko 		memcpy(mask, nla_data(tb[mask_type]), len);
41377b9900eSJiri Pirko }
41477b9900eSJiri Pirko 
4159399ae9aSHadar Hen Zion static void fl_set_key_vlan(struct nlattr **tb,
4169399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *key_val,
4179399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *key_mask)
4189399ae9aSHadar Hen Zion {
4199399ae9aSHadar Hen Zion #define VLAN_PRIORITY_MASK	0x7
4209399ae9aSHadar Hen Zion 
4219399ae9aSHadar Hen Zion 	if (tb[TCA_FLOWER_KEY_VLAN_ID]) {
4229399ae9aSHadar Hen Zion 		key_val->vlan_id =
4239399ae9aSHadar Hen Zion 			nla_get_u16(tb[TCA_FLOWER_KEY_VLAN_ID]) & VLAN_VID_MASK;
4249399ae9aSHadar Hen Zion 		key_mask->vlan_id = VLAN_VID_MASK;
4259399ae9aSHadar Hen Zion 	}
4269399ae9aSHadar Hen Zion 	if (tb[TCA_FLOWER_KEY_VLAN_PRIO]) {
4279399ae9aSHadar Hen Zion 		key_val->vlan_priority =
4289399ae9aSHadar Hen Zion 			nla_get_u8(tb[TCA_FLOWER_KEY_VLAN_PRIO]) &
4299399ae9aSHadar Hen Zion 			VLAN_PRIORITY_MASK;
4309399ae9aSHadar Hen Zion 		key_mask->vlan_priority = VLAN_PRIORITY_MASK;
4319399ae9aSHadar Hen Zion 	}
4329399ae9aSHadar Hen Zion }
4339399ae9aSHadar Hen Zion 
434faa3ffceSOr Gerlitz static void fl_set_key_flag(u32 flower_key, u32 flower_mask,
435faa3ffceSOr Gerlitz 			    u32 *dissector_key, u32 *dissector_mask,
436faa3ffceSOr Gerlitz 			    u32 flower_flag_bit, u32 dissector_flag_bit)
437faa3ffceSOr Gerlitz {
438faa3ffceSOr Gerlitz 	if (flower_mask & flower_flag_bit) {
439faa3ffceSOr Gerlitz 		*dissector_mask |= dissector_flag_bit;
440faa3ffceSOr Gerlitz 		if (flower_key & flower_flag_bit)
441faa3ffceSOr Gerlitz 			*dissector_key |= dissector_flag_bit;
442faa3ffceSOr Gerlitz 	}
443faa3ffceSOr Gerlitz }
444faa3ffceSOr Gerlitz 
445faa3ffceSOr Gerlitz static void fl_set_key_flags(struct nlattr **tb,
446faa3ffceSOr Gerlitz 			     u32 *flags_key, u32 *flags_mask)
447faa3ffceSOr Gerlitz {
448faa3ffceSOr Gerlitz 	u32 key, mask;
449faa3ffceSOr Gerlitz 
450faa3ffceSOr Gerlitz 	if (!tb[TCA_FLOWER_KEY_FLAGS])
451faa3ffceSOr Gerlitz 		return;
452faa3ffceSOr Gerlitz 
453faa3ffceSOr Gerlitz 	key = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS]));
454faa3ffceSOr Gerlitz 
455faa3ffceSOr Gerlitz 	if (!tb[TCA_FLOWER_KEY_FLAGS_MASK])
456faa3ffceSOr Gerlitz 		mask = ~0;
457faa3ffceSOr Gerlitz 	else
458faa3ffceSOr Gerlitz 		mask = be32_to_cpu(nla_get_u32(tb[TCA_FLOWER_KEY_FLAGS_MASK]));
459faa3ffceSOr Gerlitz 
460faa3ffceSOr Gerlitz 	*flags_key  = 0;
461faa3ffceSOr Gerlitz 	*flags_mask = 0;
462faa3ffceSOr Gerlitz 
463faa3ffceSOr Gerlitz 	fl_set_key_flag(key, mask, flags_key, flags_mask,
464faa3ffceSOr Gerlitz 			TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT);
465faa3ffceSOr Gerlitz }
466faa3ffceSOr Gerlitz 
46777b9900eSJiri Pirko static int fl_set_key(struct net *net, struct nlattr **tb,
46877b9900eSJiri Pirko 		      struct fl_flow_key *key, struct fl_flow_key *mask)
46977b9900eSJiri Pirko {
4709399ae9aSHadar Hen Zion 	__be16 ethertype;
471dd3aa3b5SBrian Haley #ifdef CONFIG_NET_CLS_IND
47277b9900eSJiri Pirko 	if (tb[TCA_FLOWER_INDEV]) {
473dd3aa3b5SBrian Haley 		int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV]);
47477b9900eSJiri Pirko 		if (err < 0)
47577b9900eSJiri Pirko 			return err;
47677b9900eSJiri Pirko 		key->indev_ifindex = err;
47777b9900eSJiri Pirko 		mask->indev_ifindex = 0xffffffff;
47877b9900eSJiri Pirko 	}
479dd3aa3b5SBrian Haley #endif
48077b9900eSJiri Pirko 
48177b9900eSJiri Pirko 	fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
48277b9900eSJiri Pirko 		       mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
48377b9900eSJiri Pirko 		       sizeof(key->eth.dst));
48477b9900eSJiri Pirko 	fl_set_key_val(tb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
48577b9900eSJiri Pirko 		       mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
48677b9900eSJiri Pirko 		       sizeof(key->eth.src));
48766530bdfSJamal Hadi Salim 
4880b498a52SArnd Bergmann 	if (tb[TCA_FLOWER_KEY_ETH_TYPE]) {
4899399ae9aSHadar Hen Zion 		ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_ETH_TYPE]);
4909399ae9aSHadar Hen Zion 
4919399ae9aSHadar Hen Zion 		if (ethertype == htons(ETH_P_8021Q)) {
4929399ae9aSHadar Hen Zion 			fl_set_key_vlan(tb, &key->vlan, &mask->vlan);
4939399ae9aSHadar Hen Zion 			fl_set_key_val(tb, &key->basic.n_proto,
4949399ae9aSHadar Hen Zion 				       TCA_FLOWER_KEY_VLAN_ETH_TYPE,
49577b9900eSJiri Pirko 				       &mask->basic.n_proto, TCA_FLOWER_UNSPEC,
49677b9900eSJiri Pirko 				       sizeof(key->basic.n_proto));
4979399ae9aSHadar Hen Zion 		} else {
4989399ae9aSHadar Hen Zion 			key->basic.n_proto = ethertype;
4999399ae9aSHadar Hen Zion 			mask->basic.n_proto = cpu_to_be16(~0);
5009399ae9aSHadar Hen Zion 		}
5010b498a52SArnd Bergmann 	}
50266530bdfSJamal Hadi Salim 
50377b9900eSJiri Pirko 	if (key->basic.n_proto == htons(ETH_P_IP) ||
50477b9900eSJiri Pirko 	    key->basic.n_proto == htons(ETH_P_IPV6)) {
50577b9900eSJiri Pirko 		fl_set_key_val(tb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
50677b9900eSJiri Pirko 			       &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
50777b9900eSJiri Pirko 			       sizeof(key->basic.ip_proto));
50877b9900eSJiri Pirko 	}
50966530bdfSJamal Hadi Salim 
51066530bdfSJamal Hadi Salim 	if (tb[TCA_FLOWER_KEY_IPV4_SRC] || tb[TCA_FLOWER_KEY_IPV4_DST]) {
51166530bdfSJamal Hadi Salim 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
512970bfcd0SPaul Blakey 		mask->control.addr_type = ~0;
51377b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
51477b9900eSJiri Pirko 			       &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
51577b9900eSJiri Pirko 			       sizeof(key->ipv4.src));
51677b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
51777b9900eSJiri Pirko 			       &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
51877b9900eSJiri Pirko 			       sizeof(key->ipv4.dst));
51966530bdfSJamal Hadi Salim 	} else if (tb[TCA_FLOWER_KEY_IPV6_SRC] || tb[TCA_FLOWER_KEY_IPV6_DST]) {
52066530bdfSJamal Hadi Salim 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
521970bfcd0SPaul Blakey 		mask->control.addr_type = ~0;
52277b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
52377b9900eSJiri Pirko 			       &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
52477b9900eSJiri Pirko 			       sizeof(key->ipv6.src));
52577b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
52677b9900eSJiri Pirko 			       &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
52777b9900eSJiri Pirko 			       sizeof(key->ipv6.dst));
52877b9900eSJiri Pirko 	}
52966530bdfSJamal Hadi Salim 
53077b9900eSJiri Pirko 	if (key->basic.ip_proto == IPPROTO_TCP) {
53177b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
532aa72d708SOr Gerlitz 			       &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
53377b9900eSJiri Pirko 			       sizeof(key->tp.src));
53477b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
535aa72d708SOr Gerlitz 			       &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
53677b9900eSJiri Pirko 			       sizeof(key->tp.dst));
53777b9900eSJiri Pirko 	} else if (key->basic.ip_proto == IPPROTO_UDP) {
53877b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
539aa72d708SOr Gerlitz 			       &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
54077b9900eSJiri Pirko 			       sizeof(key->tp.src));
54177b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
542aa72d708SOr Gerlitz 			       &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
54377b9900eSJiri Pirko 			       sizeof(key->tp.dst));
5445976c5f4SSimon Horman 	} else if (key->basic.ip_proto == IPPROTO_SCTP) {
5455976c5f4SSimon Horman 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
5465976c5f4SSimon Horman 			       &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
5475976c5f4SSimon Horman 			       sizeof(key->tp.src));
5485976c5f4SSimon Horman 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
5495976c5f4SSimon Horman 			       &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
5505976c5f4SSimon Horman 			       sizeof(key->tp.dst));
5517b684884SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_IP) &&
5527b684884SSimon Horman 		   key->basic.ip_proto == IPPROTO_ICMP) {
5537b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV4_TYPE,
5547b684884SSimon Horman 			       &mask->icmp.type,
5557b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,
5567b684884SSimon Horman 			       sizeof(key->icmp.type));
5577b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE,
5587b684884SSimon Horman 			       &mask->icmp.code,
5597b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
5607b684884SSimon Horman 			       sizeof(key->icmp.code));
5617b684884SSimon Horman 	} else if (key->basic.n_proto == htons(ETH_P_IPV6) &&
5627b684884SSimon Horman 		   key->basic.ip_proto == IPPROTO_ICMPV6) {
5637b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.type, TCA_FLOWER_KEY_ICMPV6_TYPE,
5647b684884SSimon Horman 			       &mask->icmp.type,
5657b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
5667b684884SSimon Horman 			       sizeof(key->icmp.type));
5677b684884SSimon Horman 		fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE,
5687b684884SSimon Horman 			       &mask->icmp.code,
5697b684884SSimon Horman 			       TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
5707b684884SSimon Horman 			       sizeof(key->icmp.code));
57177b9900eSJiri Pirko 	}
57277b9900eSJiri Pirko 
573bc3103f1SAmir Vadai 	if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] ||
574bc3103f1SAmir Vadai 	    tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) {
575bc3103f1SAmir Vadai 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
576970bfcd0SPaul Blakey 		mask->enc_control.addr_type = ~0;
577bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv4.src,
578bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_SRC,
579bc3103f1SAmir Vadai 			       &mask->enc_ipv4.src,
580bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
581bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv4.src));
582bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv4.dst,
583bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_DST,
584bc3103f1SAmir Vadai 			       &mask->enc_ipv4.dst,
585bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
586bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv4.dst));
587bc3103f1SAmir Vadai 	}
588bc3103f1SAmir Vadai 
589bc3103f1SAmir Vadai 	if (tb[TCA_FLOWER_KEY_ENC_IPV6_SRC] ||
590bc3103f1SAmir Vadai 	    tb[TCA_FLOWER_KEY_ENC_IPV6_DST]) {
591bc3103f1SAmir Vadai 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
592970bfcd0SPaul Blakey 		mask->enc_control.addr_type = ~0;
593bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv6.src,
594bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_SRC,
595bc3103f1SAmir Vadai 			       &mask->enc_ipv6.src,
596bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
597bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv6.src));
598bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv6.dst,
599bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_DST,
600bc3103f1SAmir Vadai 			       &mask->enc_ipv6.dst,
601bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
602bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv6.dst));
603bc3103f1SAmir Vadai 	}
604bc3103f1SAmir Vadai 
605bc3103f1SAmir Vadai 	fl_set_key_val(tb, &key->enc_key_id.keyid, TCA_FLOWER_KEY_ENC_KEY_ID,
606eb523f42SHadar Hen Zion 		       &mask->enc_key_id.keyid, TCA_FLOWER_UNSPEC,
607bc3103f1SAmir Vadai 		       sizeof(key->enc_key_id.keyid));
608bc3103f1SAmir Vadai 
609f4d997fdSHadar Hen Zion 	fl_set_key_val(tb, &key->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
610f4d997fdSHadar Hen Zion 		       &mask->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
611f4d997fdSHadar Hen Zion 		       sizeof(key->enc_tp.src));
612f4d997fdSHadar Hen Zion 
613f4d997fdSHadar Hen Zion 	fl_set_key_val(tb, &key->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
614f4d997fdSHadar Hen Zion 		       &mask->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
615f4d997fdSHadar Hen Zion 		       sizeof(key->enc_tp.dst));
616f4d997fdSHadar Hen Zion 
617faa3ffceSOr Gerlitz 	fl_set_key_flags(tb, &key->control.flags, &mask->control.flags);
618faa3ffceSOr Gerlitz 
61977b9900eSJiri Pirko 	return 0;
62077b9900eSJiri Pirko }
62177b9900eSJiri Pirko 
62277b9900eSJiri Pirko static bool fl_mask_eq(struct fl_flow_mask *mask1,
62377b9900eSJiri Pirko 		       struct fl_flow_mask *mask2)
62477b9900eSJiri Pirko {
62577b9900eSJiri Pirko 	const long *lmask1 = fl_key_get_start(&mask1->key, mask1);
62677b9900eSJiri Pirko 	const long *lmask2 = fl_key_get_start(&mask2->key, mask2);
62777b9900eSJiri Pirko 
62877b9900eSJiri Pirko 	return !memcmp(&mask1->range, &mask2->range, sizeof(mask1->range)) &&
62977b9900eSJiri Pirko 	       !memcmp(lmask1, lmask2, fl_mask_range(mask1));
63077b9900eSJiri Pirko }
63177b9900eSJiri Pirko 
63277b9900eSJiri Pirko static const struct rhashtable_params fl_ht_params = {
63377b9900eSJiri Pirko 	.key_offset = offsetof(struct cls_fl_filter, mkey), /* base offset */
63477b9900eSJiri Pirko 	.head_offset = offsetof(struct cls_fl_filter, ht_node),
63577b9900eSJiri Pirko 	.automatic_shrinking = true,
63677b9900eSJiri Pirko };
63777b9900eSJiri Pirko 
63877b9900eSJiri Pirko static int fl_init_hashtable(struct cls_fl_head *head,
63977b9900eSJiri Pirko 			     struct fl_flow_mask *mask)
64077b9900eSJiri Pirko {
64177b9900eSJiri Pirko 	head->ht_params = fl_ht_params;
64277b9900eSJiri Pirko 	head->ht_params.key_len = fl_mask_range(mask);
64377b9900eSJiri Pirko 	head->ht_params.key_offset += mask->range.start;
64477b9900eSJiri Pirko 
64577b9900eSJiri Pirko 	return rhashtable_init(&head->ht, &head->ht_params);
64677b9900eSJiri Pirko }
64777b9900eSJiri Pirko 
64877b9900eSJiri Pirko #define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member)
64977b9900eSJiri Pirko #define FL_KEY_MEMBER_SIZE(member) (sizeof(((struct fl_flow_key *) 0)->member))
65077b9900eSJiri Pirko 
651339ba878SHadar Hen Zion #define FL_KEY_IS_MASKED(mask, member)						\
652339ba878SHadar Hen Zion 	memchr_inv(((char *)mask) + FL_KEY_MEMBER_OFFSET(member),		\
653339ba878SHadar Hen Zion 		   0, FL_KEY_MEMBER_SIZE(member))				\
65477b9900eSJiri Pirko 
65577b9900eSJiri Pirko #define FL_KEY_SET(keys, cnt, id, member)					\
65677b9900eSJiri Pirko 	do {									\
65777b9900eSJiri Pirko 		keys[cnt].key_id = id;						\
65877b9900eSJiri Pirko 		keys[cnt].offset = FL_KEY_MEMBER_OFFSET(member);		\
65977b9900eSJiri Pirko 		cnt++;								\
66077b9900eSJiri Pirko 	} while(0);
66177b9900eSJiri Pirko 
662339ba878SHadar Hen Zion #define FL_KEY_SET_IF_MASKED(mask, keys, cnt, id, member)			\
66377b9900eSJiri Pirko 	do {									\
664339ba878SHadar Hen Zion 		if (FL_KEY_IS_MASKED(mask, member))				\
66577b9900eSJiri Pirko 			FL_KEY_SET(keys, cnt, id, member);			\
66677b9900eSJiri Pirko 	} while(0);
66777b9900eSJiri Pirko 
66877b9900eSJiri Pirko static void fl_init_dissector(struct cls_fl_head *head,
66977b9900eSJiri Pirko 			      struct fl_flow_mask *mask)
67077b9900eSJiri Pirko {
67177b9900eSJiri Pirko 	struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX];
67277b9900eSJiri Pirko 	size_t cnt = 0;
67377b9900eSJiri Pirko 
67442aecaa9STom Herbert 	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control);
67577b9900eSJiri Pirko 	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic);
676339ba878SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
67777b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_ETH_ADDRS, eth);
678339ba878SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
67977b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4);
680339ba878SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
68177b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6);
682339ba878SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
68377b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_PORTS, tp);
6849399ae9aSHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
6857b684884SSimon Horman 			     FLOW_DISSECTOR_KEY_ICMP, icmp);
6867b684884SSimon Horman 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
6879399ae9aSHadar Hen Zion 			     FLOW_DISSECTOR_KEY_VLAN, vlan);
688519d1052SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
689519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_KEYID, enc_key_id);
690519d1052SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
691519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, enc_ipv4);
692519d1052SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
693519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, enc_ipv6);
694519d1052SHadar Hen Zion 	if (FL_KEY_IS_MASKED(&mask->key, enc_ipv4) ||
695519d1052SHadar Hen Zion 	    FL_KEY_IS_MASKED(&mask->key, enc_ipv6))
696519d1052SHadar Hen Zion 		FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_ENC_CONTROL,
697519d1052SHadar Hen Zion 			   enc_control);
698f4d997fdSHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
699f4d997fdSHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp);
70077b9900eSJiri Pirko 
70177b9900eSJiri Pirko 	skb_flow_dissector_init(&head->dissector, keys, cnt);
70277b9900eSJiri Pirko }
70377b9900eSJiri Pirko 
70477b9900eSJiri Pirko static int fl_check_assign_mask(struct cls_fl_head *head,
70577b9900eSJiri Pirko 				struct fl_flow_mask *mask)
70677b9900eSJiri Pirko {
70777b9900eSJiri Pirko 	int err;
70877b9900eSJiri Pirko 
70977b9900eSJiri Pirko 	if (head->mask_assigned) {
71077b9900eSJiri Pirko 		if (!fl_mask_eq(&head->mask, mask))
71177b9900eSJiri Pirko 			return -EINVAL;
71277b9900eSJiri Pirko 		else
71377b9900eSJiri Pirko 			return 0;
71477b9900eSJiri Pirko 	}
71577b9900eSJiri Pirko 
71677b9900eSJiri Pirko 	/* Mask is not assigned yet. So assign it and init hashtable
71777b9900eSJiri Pirko 	 * according to that.
71877b9900eSJiri Pirko 	 */
71977b9900eSJiri Pirko 	err = fl_init_hashtable(head, mask);
72077b9900eSJiri Pirko 	if (err)
72177b9900eSJiri Pirko 		return err;
72277b9900eSJiri Pirko 	memcpy(&head->mask, mask, sizeof(head->mask));
72377b9900eSJiri Pirko 	head->mask_assigned = true;
72477b9900eSJiri Pirko 
72577b9900eSJiri Pirko 	fl_init_dissector(head, mask);
72677b9900eSJiri Pirko 
72777b9900eSJiri Pirko 	return 0;
72877b9900eSJiri Pirko }
72977b9900eSJiri Pirko 
73077b9900eSJiri Pirko static int fl_set_parms(struct net *net, struct tcf_proto *tp,
73177b9900eSJiri Pirko 			struct cls_fl_filter *f, struct fl_flow_mask *mask,
73277b9900eSJiri Pirko 			unsigned long base, struct nlattr **tb,
73377b9900eSJiri Pirko 			struct nlattr *est, bool ovr)
73477b9900eSJiri Pirko {
73577b9900eSJiri Pirko 	struct tcf_exts e;
73677b9900eSJiri Pirko 	int err;
73777b9900eSJiri Pirko 
738b9a24bb7SWANG Cong 	err = tcf_exts_init(&e, TCA_FLOWER_ACT, 0);
73977b9900eSJiri Pirko 	if (err < 0)
74077b9900eSJiri Pirko 		return err;
741b9a24bb7SWANG Cong 	err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
742b9a24bb7SWANG Cong 	if (err < 0)
743b9a24bb7SWANG Cong 		goto errout;
74477b9900eSJiri Pirko 
74577b9900eSJiri Pirko 	if (tb[TCA_FLOWER_CLASSID]) {
74677b9900eSJiri Pirko 		f->res.classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]);
74777b9900eSJiri Pirko 		tcf_bind_filter(tp, &f->res, base);
74877b9900eSJiri Pirko 	}
74977b9900eSJiri Pirko 
75077b9900eSJiri Pirko 	err = fl_set_key(net, tb, &f->key, &mask->key);
75177b9900eSJiri Pirko 	if (err)
75277b9900eSJiri Pirko 		goto errout;
75377b9900eSJiri Pirko 
75477b9900eSJiri Pirko 	fl_mask_update_range(mask);
75577b9900eSJiri Pirko 	fl_set_masked_key(&f->mkey, &f->key, mask);
75677b9900eSJiri Pirko 
75777b9900eSJiri Pirko 	tcf_exts_change(tp, &f->exts, &e);
75877b9900eSJiri Pirko 
75977b9900eSJiri Pirko 	return 0;
76077b9900eSJiri Pirko errout:
76177b9900eSJiri Pirko 	tcf_exts_destroy(&e);
76277b9900eSJiri Pirko 	return err;
76377b9900eSJiri Pirko }
76477b9900eSJiri Pirko 
76577b9900eSJiri Pirko static u32 fl_grab_new_handle(struct tcf_proto *tp,
76677b9900eSJiri Pirko 			      struct cls_fl_head *head)
76777b9900eSJiri Pirko {
76877b9900eSJiri Pirko 	unsigned int i = 0x80000000;
76977b9900eSJiri Pirko 	u32 handle;
77077b9900eSJiri Pirko 
77177b9900eSJiri Pirko 	do {
77277b9900eSJiri Pirko 		if (++head->hgen == 0x7FFFFFFF)
77377b9900eSJiri Pirko 			head->hgen = 1;
77477b9900eSJiri Pirko 	} while (--i > 0 && fl_get(tp, head->hgen));
77577b9900eSJiri Pirko 
77677b9900eSJiri Pirko 	if (unlikely(i == 0)) {
77777b9900eSJiri Pirko 		pr_err("Insufficient number of handles\n");
77877b9900eSJiri Pirko 		handle = 0;
77977b9900eSJiri Pirko 	} else {
78077b9900eSJiri Pirko 		handle = head->hgen;
78177b9900eSJiri Pirko 	}
78277b9900eSJiri Pirko 
78377b9900eSJiri Pirko 	return handle;
78477b9900eSJiri Pirko }
78577b9900eSJiri Pirko 
78677b9900eSJiri Pirko static int fl_change(struct net *net, struct sk_buff *in_skb,
78777b9900eSJiri Pirko 		     struct tcf_proto *tp, unsigned long base,
78877b9900eSJiri Pirko 		     u32 handle, struct nlattr **tca,
78977b9900eSJiri Pirko 		     unsigned long *arg, bool ovr)
79077b9900eSJiri Pirko {
79177b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
79277b9900eSJiri Pirko 	struct cls_fl_filter *fold = (struct cls_fl_filter *) *arg;
79377b9900eSJiri Pirko 	struct cls_fl_filter *fnew;
79477b9900eSJiri Pirko 	struct nlattr *tb[TCA_FLOWER_MAX + 1];
79577b9900eSJiri Pirko 	struct fl_flow_mask mask = {};
79677b9900eSJiri Pirko 	int err;
79777b9900eSJiri Pirko 
79877b9900eSJiri Pirko 	if (!tca[TCA_OPTIONS])
79977b9900eSJiri Pirko 		return -EINVAL;
80077b9900eSJiri Pirko 
80177b9900eSJiri Pirko 	err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS], fl_policy);
80277b9900eSJiri Pirko 	if (err < 0)
80377b9900eSJiri Pirko 		return err;
80477b9900eSJiri Pirko 
80577b9900eSJiri Pirko 	if (fold && handle && fold->handle != handle)
80677b9900eSJiri Pirko 		return -EINVAL;
80777b9900eSJiri Pirko 
80877b9900eSJiri Pirko 	fnew = kzalloc(sizeof(*fnew), GFP_KERNEL);
80977b9900eSJiri Pirko 	if (!fnew)
81077b9900eSJiri Pirko 		return -ENOBUFS;
81177b9900eSJiri Pirko 
812b9a24bb7SWANG Cong 	err = tcf_exts_init(&fnew->exts, TCA_FLOWER_ACT, 0);
813b9a24bb7SWANG Cong 	if (err < 0)
814b9a24bb7SWANG Cong 		goto errout;
81577b9900eSJiri Pirko 
81677b9900eSJiri Pirko 	if (!handle) {
81777b9900eSJiri Pirko 		handle = fl_grab_new_handle(tp, head);
81877b9900eSJiri Pirko 		if (!handle) {
81977b9900eSJiri Pirko 			err = -EINVAL;
82077b9900eSJiri Pirko 			goto errout;
82177b9900eSJiri Pirko 		}
82277b9900eSJiri Pirko 	}
82377b9900eSJiri Pirko 	fnew->handle = handle;
82477b9900eSJiri Pirko 
825e69985c6SAmir Vadai 	if (tb[TCA_FLOWER_FLAGS]) {
826e69985c6SAmir Vadai 		fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
827e69985c6SAmir Vadai 
828e69985c6SAmir Vadai 		if (!tc_flags_valid(fnew->flags)) {
829e69985c6SAmir Vadai 			err = -EINVAL;
830e69985c6SAmir Vadai 			goto errout;
831e69985c6SAmir Vadai 		}
832e69985c6SAmir Vadai 	}
8335b33f488SAmir Vadai 
83477b9900eSJiri Pirko 	err = fl_set_parms(net, tp, fnew, &mask, base, tb, tca[TCA_RATE], ovr);
83577b9900eSJiri Pirko 	if (err)
83677b9900eSJiri Pirko 		goto errout;
83777b9900eSJiri Pirko 
83877b9900eSJiri Pirko 	err = fl_check_assign_mask(head, &mask);
83977b9900eSJiri Pirko 	if (err)
84077b9900eSJiri Pirko 		goto errout;
84177b9900eSJiri Pirko 
842e8eb36cdSAmir Vadai 	if (!tc_skip_sw(fnew->flags)) {
84377b9900eSJiri Pirko 		err = rhashtable_insert_fast(&head->ht, &fnew->ht_node,
84477b9900eSJiri Pirko 					     head->ht_params);
84577b9900eSJiri Pirko 		if (err)
84677b9900eSJiri Pirko 			goto errout;
847e69985c6SAmir Vadai 	}
8485b33f488SAmir Vadai 
84979685219SHadar Hen Zion 	if (!tc_skip_hw(fnew->flags)) {
850e8eb36cdSAmir Vadai 		err = fl_hw_replace_filter(tp,
8515b33f488SAmir Vadai 					   &head->dissector,
8525b33f488SAmir Vadai 					   &mask.key,
8533036dab6SHadar Hen Zion 					   fnew);
854e8eb36cdSAmir Vadai 		if (err)
855e8eb36cdSAmir Vadai 			goto errout;
85679685219SHadar Hen Zion 	}
8575b33f488SAmir Vadai 
8585b33f488SAmir Vadai 	if (fold) {
859725cbb62SJiri Pirko 		if (!tc_skip_sw(fold->flags))
86077b9900eSJiri Pirko 			rhashtable_remove_fast(&head->ht, &fold->ht_node,
86177b9900eSJiri Pirko 					       head->ht_params);
86279685219SHadar Hen Zion 		if (!tc_skip_hw(fold->flags))
8633036dab6SHadar Hen Zion 			fl_hw_destroy_filter(tp, fold);
8645b33f488SAmir Vadai 	}
86577b9900eSJiri Pirko 
86677b9900eSJiri Pirko 	*arg = (unsigned long) fnew;
86777b9900eSJiri Pirko 
86877b9900eSJiri Pirko 	if (fold) {
869ff3532f2SDaniel Borkmann 		list_replace_rcu(&fold->list, &fnew->list);
87077b9900eSJiri Pirko 		tcf_unbind_filter(tp, &fold->res);
87177b9900eSJiri Pirko 		call_rcu(&fold->rcu, fl_destroy_filter);
87277b9900eSJiri Pirko 	} else {
87377b9900eSJiri Pirko 		list_add_tail_rcu(&fnew->list, &head->filters);
87477b9900eSJiri Pirko 	}
87577b9900eSJiri Pirko 
87677b9900eSJiri Pirko 	return 0;
87777b9900eSJiri Pirko 
87877b9900eSJiri Pirko errout:
879b9a24bb7SWANG Cong 	tcf_exts_destroy(&fnew->exts);
88077b9900eSJiri Pirko 	kfree(fnew);
88177b9900eSJiri Pirko 	return err;
88277b9900eSJiri Pirko }
88377b9900eSJiri Pirko 
88477b9900eSJiri Pirko static int fl_delete(struct tcf_proto *tp, unsigned long arg)
88577b9900eSJiri Pirko {
88677b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
88777b9900eSJiri Pirko 	struct cls_fl_filter *f = (struct cls_fl_filter *) arg;
88877b9900eSJiri Pirko 
889725cbb62SJiri Pirko 	if (!tc_skip_sw(f->flags))
89077b9900eSJiri Pirko 		rhashtable_remove_fast(&head->ht, &f->ht_node,
89177b9900eSJiri Pirko 				       head->ht_params);
89213fa876eSRoi Dayan 	__fl_delete(tp, f);
89377b9900eSJiri Pirko 	return 0;
89477b9900eSJiri Pirko }
89577b9900eSJiri Pirko 
89677b9900eSJiri Pirko static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg)
89777b9900eSJiri Pirko {
89877b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
89977b9900eSJiri Pirko 	struct cls_fl_filter *f;
90077b9900eSJiri Pirko 
90177b9900eSJiri Pirko 	list_for_each_entry_rcu(f, &head->filters, list) {
90277b9900eSJiri Pirko 		if (arg->count < arg->skip)
90377b9900eSJiri Pirko 			goto skip;
90477b9900eSJiri Pirko 		if (arg->fn(tp, (unsigned long) f, arg) < 0) {
90577b9900eSJiri Pirko 			arg->stop = 1;
90677b9900eSJiri Pirko 			break;
90777b9900eSJiri Pirko 		}
90877b9900eSJiri Pirko skip:
90977b9900eSJiri Pirko 		arg->count++;
91077b9900eSJiri Pirko 	}
91177b9900eSJiri Pirko }
91277b9900eSJiri Pirko 
91377b9900eSJiri Pirko static int fl_dump_key_val(struct sk_buff *skb,
91477b9900eSJiri Pirko 			   void *val, int val_type,
91577b9900eSJiri Pirko 			   void *mask, int mask_type, int len)
91677b9900eSJiri Pirko {
91777b9900eSJiri Pirko 	int err;
91877b9900eSJiri Pirko 
91977b9900eSJiri Pirko 	if (!memchr_inv(mask, 0, len))
92077b9900eSJiri Pirko 		return 0;
92177b9900eSJiri Pirko 	err = nla_put(skb, val_type, len, val);
92277b9900eSJiri Pirko 	if (err)
92377b9900eSJiri Pirko 		return err;
92477b9900eSJiri Pirko 	if (mask_type != TCA_FLOWER_UNSPEC) {
92577b9900eSJiri Pirko 		err = nla_put(skb, mask_type, len, mask);
92677b9900eSJiri Pirko 		if (err)
92777b9900eSJiri Pirko 			return err;
92877b9900eSJiri Pirko 	}
92977b9900eSJiri Pirko 	return 0;
93077b9900eSJiri Pirko }
93177b9900eSJiri Pirko 
9329399ae9aSHadar Hen Zion static int fl_dump_key_vlan(struct sk_buff *skb,
9339399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *vlan_key,
9349399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *vlan_mask)
9359399ae9aSHadar Hen Zion {
9369399ae9aSHadar Hen Zion 	int err;
9379399ae9aSHadar Hen Zion 
9389399ae9aSHadar Hen Zion 	if (!memchr_inv(vlan_mask, 0, sizeof(*vlan_mask)))
9399399ae9aSHadar Hen Zion 		return 0;
9409399ae9aSHadar Hen Zion 	if (vlan_mask->vlan_id) {
9419399ae9aSHadar Hen Zion 		err = nla_put_u16(skb, TCA_FLOWER_KEY_VLAN_ID,
9429399ae9aSHadar Hen Zion 				  vlan_key->vlan_id);
9439399ae9aSHadar Hen Zion 		if (err)
9449399ae9aSHadar Hen Zion 			return err;
9459399ae9aSHadar Hen Zion 	}
9469399ae9aSHadar Hen Zion 	if (vlan_mask->vlan_priority) {
9479399ae9aSHadar Hen Zion 		err = nla_put_u8(skb, TCA_FLOWER_KEY_VLAN_PRIO,
9489399ae9aSHadar Hen Zion 				 vlan_key->vlan_priority);
9499399ae9aSHadar Hen Zion 		if (err)
9509399ae9aSHadar Hen Zion 			return err;
9519399ae9aSHadar Hen Zion 	}
9529399ae9aSHadar Hen Zion 	return 0;
9539399ae9aSHadar Hen Zion }
9549399ae9aSHadar Hen Zion 
955faa3ffceSOr Gerlitz static void fl_get_key_flag(u32 dissector_key, u32 dissector_mask,
956faa3ffceSOr Gerlitz 			    u32 *flower_key, u32 *flower_mask,
957faa3ffceSOr Gerlitz 			    u32 flower_flag_bit, u32 dissector_flag_bit)
958faa3ffceSOr Gerlitz {
959faa3ffceSOr Gerlitz 	if (dissector_mask & dissector_flag_bit) {
960faa3ffceSOr Gerlitz 		*flower_mask |= flower_flag_bit;
961faa3ffceSOr Gerlitz 		if (dissector_key & dissector_flag_bit)
962faa3ffceSOr Gerlitz 			*flower_key |= flower_flag_bit;
963faa3ffceSOr Gerlitz 	}
964faa3ffceSOr Gerlitz }
965faa3ffceSOr Gerlitz 
966faa3ffceSOr Gerlitz static int fl_dump_key_flags(struct sk_buff *skb, u32 flags_key, u32 flags_mask)
967faa3ffceSOr Gerlitz {
968faa3ffceSOr Gerlitz 	u32 key, mask;
969faa3ffceSOr Gerlitz 	__be32 _key, _mask;
970faa3ffceSOr Gerlitz 	int err;
971faa3ffceSOr Gerlitz 
972faa3ffceSOr Gerlitz 	if (!memchr_inv(&flags_mask, 0, sizeof(flags_mask)))
973faa3ffceSOr Gerlitz 		return 0;
974faa3ffceSOr Gerlitz 
975faa3ffceSOr Gerlitz 	key = 0;
976faa3ffceSOr Gerlitz 	mask = 0;
977faa3ffceSOr Gerlitz 
978faa3ffceSOr Gerlitz 	fl_get_key_flag(flags_key, flags_mask, &key, &mask,
979faa3ffceSOr Gerlitz 			TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOW_DIS_IS_FRAGMENT);
980faa3ffceSOr Gerlitz 
981faa3ffceSOr Gerlitz 	_key = cpu_to_be32(key);
982faa3ffceSOr Gerlitz 	_mask = cpu_to_be32(mask);
983faa3ffceSOr Gerlitz 
984faa3ffceSOr Gerlitz 	err = nla_put(skb, TCA_FLOWER_KEY_FLAGS, 4, &_key);
985faa3ffceSOr Gerlitz 	if (err)
986faa3ffceSOr Gerlitz 		return err;
987faa3ffceSOr Gerlitz 
988faa3ffceSOr Gerlitz 	return nla_put(skb, TCA_FLOWER_KEY_FLAGS_MASK, 4, &_mask);
989faa3ffceSOr Gerlitz }
990faa3ffceSOr Gerlitz 
99177b9900eSJiri Pirko static int fl_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
99277b9900eSJiri Pirko 		   struct sk_buff *skb, struct tcmsg *t)
99377b9900eSJiri Pirko {
99477b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
99577b9900eSJiri Pirko 	struct cls_fl_filter *f = (struct cls_fl_filter *) fh;
99677b9900eSJiri Pirko 	struct nlattr *nest;
99777b9900eSJiri Pirko 	struct fl_flow_key *key, *mask;
99877b9900eSJiri Pirko 
99977b9900eSJiri Pirko 	if (!f)
100077b9900eSJiri Pirko 		return skb->len;
100177b9900eSJiri Pirko 
100277b9900eSJiri Pirko 	t->tcm_handle = f->handle;
100377b9900eSJiri Pirko 
100477b9900eSJiri Pirko 	nest = nla_nest_start(skb, TCA_OPTIONS);
100577b9900eSJiri Pirko 	if (!nest)
100677b9900eSJiri Pirko 		goto nla_put_failure;
100777b9900eSJiri Pirko 
100877b9900eSJiri Pirko 	if (f->res.classid &&
100977b9900eSJiri Pirko 	    nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid))
101077b9900eSJiri Pirko 		goto nla_put_failure;
101177b9900eSJiri Pirko 
101277b9900eSJiri Pirko 	key = &f->key;
101377b9900eSJiri Pirko 	mask = &head->mask.key;
101477b9900eSJiri Pirko 
101577b9900eSJiri Pirko 	if (mask->indev_ifindex) {
101677b9900eSJiri Pirko 		struct net_device *dev;
101777b9900eSJiri Pirko 
101877b9900eSJiri Pirko 		dev = __dev_get_by_index(net, key->indev_ifindex);
101977b9900eSJiri Pirko 		if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name))
102077b9900eSJiri Pirko 			goto nla_put_failure;
102177b9900eSJiri Pirko 	}
102277b9900eSJiri Pirko 
102379685219SHadar Hen Zion 	if (!tc_skip_hw(f->flags))
102410cbc684SAmir Vadai 		fl_hw_update_stats(tp, f);
102510cbc684SAmir Vadai 
102677b9900eSJiri Pirko 	if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
102777b9900eSJiri Pirko 			    mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
102877b9900eSJiri Pirko 			    sizeof(key->eth.dst)) ||
102977b9900eSJiri Pirko 	    fl_dump_key_val(skb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
103077b9900eSJiri Pirko 			    mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
103177b9900eSJiri Pirko 			    sizeof(key->eth.src)) ||
103277b9900eSJiri Pirko 	    fl_dump_key_val(skb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE,
103377b9900eSJiri Pirko 			    &mask->basic.n_proto, TCA_FLOWER_UNSPEC,
103477b9900eSJiri Pirko 			    sizeof(key->basic.n_proto)))
103577b9900eSJiri Pirko 		goto nla_put_failure;
10369399ae9aSHadar Hen Zion 
10379399ae9aSHadar Hen Zion 	if (fl_dump_key_vlan(skb, &key->vlan, &mask->vlan))
10389399ae9aSHadar Hen Zion 		goto nla_put_failure;
10399399ae9aSHadar Hen Zion 
104077b9900eSJiri Pirko 	if ((key->basic.n_proto == htons(ETH_P_IP) ||
104177b9900eSJiri Pirko 	     key->basic.n_proto == htons(ETH_P_IPV6)) &&
104277b9900eSJiri Pirko 	    fl_dump_key_val(skb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
104377b9900eSJiri Pirko 			    &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
104477b9900eSJiri Pirko 			    sizeof(key->basic.ip_proto)))
104577b9900eSJiri Pirko 		goto nla_put_failure;
104677b9900eSJiri Pirko 
1047c3f83241STom Herbert 	if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
104877b9900eSJiri Pirko 	    (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
104977b9900eSJiri Pirko 			     &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
105077b9900eSJiri Pirko 			     sizeof(key->ipv4.src)) ||
105177b9900eSJiri Pirko 	     fl_dump_key_val(skb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
105277b9900eSJiri Pirko 			     &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
105377b9900eSJiri Pirko 			     sizeof(key->ipv4.dst))))
105477b9900eSJiri Pirko 		goto nla_put_failure;
1055c3f83241STom Herbert 	else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
105677b9900eSJiri Pirko 		 (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
105777b9900eSJiri Pirko 				  &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
105877b9900eSJiri Pirko 				  sizeof(key->ipv6.src)) ||
105977b9900eSJiri Pirko 		  fl_dump_key_val(skb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
106077b9900eSJiri Pirko 				  &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
106177b9900eSJiri Pirko 				  sizeof(key->ipv6.dst))))
106277b9900eSJiri Pirko 		goto nla_put_failure;
106377b9900eSJiri Pirko 
106477b9900eSJiri Pirko 	if (key->basic.ip_proto == IPPROTO_TCP &&
106577b9900eSJiri Pirko 	    (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
1066aa72d708SOr Gerlitz 			     &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
106777b9900eSJiri Pirko 			     sizeof(key->tp.src)) ||
106877b9900eSJiri Pirko 	     fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
1069aa72d708SOr Gerlitz 			     &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
107077b9900eSJiri Pirko 			     sizeof(key->tp.dst))))
107177b9900eSJiri Pirko 		goto nla_put_failure;
107277b9900eSJiri Pirko 	else if (key->basic.ip_proto == IPPROTO_UDP &&
107377b9900eSJiri Pirko 		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
1074aa72d708SOr Gerlitz 				  &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
107577b9900eSJiri Pirko 				  sizeof(key->tp.src)) ||
107677b9900eSJiri Pirko 		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
1077aa72d708SOr Gerlitz 				  &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
107877b9900eSJiri Pirko 				  sizeof(key->tp.dst))))
107977b9900eSJiri Pirko 		goto nla_put_failure;
10805976c5f4SSimon Horman 	else if (key->basic.ip_proto == IPPROTO_SCTP &&
10815976c5f4SSimon Horman 		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
10825976c5f4SSimon Horman 				  &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
10835976c5f4SSimon Horman 				  sizeof(key->tp.src)) ||
10845976c5f4SSimon Horman 		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
10855976c5f4SSimon Horman 				  &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
10865976c5f4SSimon Horman 				  sizeof(key->tp.dst))))
10875976c5f4SSimon Horman 		goto nla_put_failure;
10887b684884SSimon Horman 	else if (key->basic.n_proto == htons(ETH_P_IP) &&
10897b684884SSimon Horman 		 key->basic.ip_proto == IPPROTO_ICMP &&
10907b684884SSimon Horman 		 (fl_dump_key_val(skb, &key->icmp.type,
10917b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_TYPE, &mask->icmp.type,
10927b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,
10937b684884SSimon Horman 				  sizeof(key->icmp.type)) ||
10947b684884SSimon Horman 		  fl_dump_key_val(skb, &key->icmp.code,
10957b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_CODE, &mask->icmp.code,
10967b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
10977b684884SSimon Horman 				  sizeof(key->icmp.code))))
10987b684884SSimon Horman 		goto nla_put_failure;
10997b684884SSimon Horman 	else if (key->basic.n_proto == htons(ETH_P_IPV6) &&
11007b684884SSimon Horman 		 key->basic.ip_proto == IPPROTO_ICMPV6 &&
11017b684884SSimon Horman 		 (fl_dump_key_val(skb, &key->icmp.type,
11027b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_TYPE, &mask->icmp.type,
11037b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
11047b684884SSimon Horman 				  sizeof(key->icmp.type)) ||
11057b684884SSimon Horman 		  fl_dump_key_val(skb, &key->icmp.code,
11067b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_CODE, &mask->icmp.code,
11077b684884SSimon Horman 				  TCA_FLOWER_KEY_ICMPV6_CODE_MASK,
11087b684884SSimon Horman 				  sizeof(key->icmp.code))))
11097b684884SSimon Horman 		goto nla_put_failure;
111077b9900eSJiri Pirko 
1111bc3103f1SAmir Vadai 	if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
1112bc3103f1SAmir Vadai 	    (fl_dump_key_val(skb, &key->enc_ipv4.src,
1113bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV4_SRC, &mask->enc_ipv4.src,
1114bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
1115bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv4.src)) ||
1116bc3103f1SAmir Vadai 	     fl_dump_key_val(skb, &key->enc_ipv4.dst,
1117bc3103f1SAmir Vadai 			     TCA_FLOWER_KEY_ENC_IPV4_DST, &mask->enc_ipv4.dst,
1118bc3103f1SAmir Vadai 			     TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
1119bc3103f1SAmir Vadai 			     sizeof(key->enc_ipv4.dst))))
1120bc3103f1SAmir Vadai 		goto nla_put_failure;
1121bc3103f1SAmir Vadai 	else if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
1122bc3103f1SAmir Vadai 		 (fl_dump_key_val(skb, &key->enc_ipv6.src,
1123bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV6_SRC, &mask->enc_ipv6.src,
1124bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
1125bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv6.src)) ||
1126bc3103f1SAmir Vadai 		 fl_dump_key_val(skb, &key->enc_ipv6.dst,
1127bc3103f1SAmir Vadai 				 TCA_FLOWER_KEY_ENC_IPV6_DST,
1128bc3103f1SAmir Vadai 				 &mask->enc_ipv6.dst,
1129bc3103f1SAmir Vadai 				 TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
1130bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv6.dst))))
1131bc3103f1SAmir Vadai 		goto nla_put_failure;
1132bc3103f1SAmir Vadai 
1133bc3103f1SAmir Vadai 	if (fl_dump_key_val(skb, &key->enc_key_id, TCA_FLOWER_KEY_ENC_KEY_ID,
1134eb523f42SHadar Hen Zion 			    &mask->enc_key_id, TCA_FLOWER_UNSPEC,
1135f4d997fdSHadar Hen Zion 			    sizeof(key->enc_key_id)) ||
1136f4d997fdSHadar Hen Zion 	    fl_dump_key_val(skb, &key->enc_tp.src,
1137f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
1138f4d997fdSHadar Hen Zion 			    &mask->enc_tp.src,
1139f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
1140f4d997fdSHadar Hen Zion 			    sizeof(key->enc_tp.src)) ||
1141f4d997fdSHadar Hen Zion 	    fl_dump_key_val(skb, &key->enc_tp.dst,
1142f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
1143f4d997fdSHadar Hen Zion 			    &mask->enc_tp.dst,
1144f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
1145f4d997fdSHadar Hen Zion 			    sizeof(key->enc_tp.dst)))
1146bc3103f1SAmir Vadai 		goto nla_put_failure;
1147bc3103f1SAmir Vadai 
1148faa3ffceSOr Gerlitz 	if (fl_dump_key_flags(skb, key->control.flags, mask->control.flags))
1149faa3ffceSOr Gerlitz 		goto nla_put_failure;
1150faa3ffceSOr Gerlitz 
1151e69985c6SAmir Vadai 	nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags);
1152e69985c6SAmir Vadai 
115377b9900eSJiri Pirko 	if (tcf_exts_dump(skb, &f->exts))
115477b9900eSJiri Pirko 		goto nla_put_failure;
115577b9900eSJiri Pirko 
115677b9900eSJiri Pirko 	nla_nest_end(skb, nest);
115777b9900eSJiri Pirko 
115877b9900eSJiri Pirko 	if (tcf_exts_dump_stats(skb, &f->exts) < 0)
115977b9900eSJiri Pirko 		goto nla_put_failure;
116077b9900eSJiri Pirko 
116177b9900eSJiri Pirko 	return skb->len;
116277b9900eSJiri Pirko 
116377b9900eSJiri Pirko nla_put_failure:
116477b9900eSJiri Pirko 	nla_nest_cancel(skb, nest);
116577b9900eSJiri Pirko 	return -1;
116677b9900eSJiri Pirko }
116777b9900eSJiri Pirko 
116877b9900eSJiri Pirko static struct tcf_proto_ops cls_fl_ops __read_mostly = {
116977b9900eSJiri Pirko 	.kind		= "flower",
117077b9900eSJiri Pirko 	.classify	= fl_classify,
117177b9900eSJiri Pirko 	.init		= fl_init,
117277b9900eSJiri Pirko 	.destroy	= fl_destroy,
117377b9900eSJiri Pirko 	.get		= fl_get,
117477b9900eSJiri Pirko 	.change		= fl_change,
117577b9900eSJiri Pirko 	.delete		= fl_delete,
117677b9900eSJiri Pirko 	.walk		= fl_walk,
117777b9900eSJiri Pirko 	.dump		= fl_dump,
117877b9900eSJiri Pirko 	.owner		= THIS_MODULE,
117977b9900eSJiri Pirko };
118077b9900eSJiri Pirko 
118177b9900eSJiri Pirko static int __init cls_fl_init(void)
118277b9900eSJiri Pirko {
118377b9900eSJiri Pirko 	return register_tcf_proto_ops(&cls_fl_ops);
118477b9900eSJiri Pirko }
118577b9900eSJiri Pirko 
118677b9900eSJiri Pirko static void __exit cls_fl_exit(void)
118777b9900eSJiri Pirko {
118877b9900eSJiri Pirko 	unregister_tcf_proto_ops(&cls_fl_ops);
118977b9900eSJiri Pirko }
119077b9900eSJiri Pirko 
119177b9900eSJiri Pirko module_init(cls_fl_init);
119277b9900eSJiri Pirko module_exit(cls_fl_exit);
119377b9900eSJiri Pirko 
119477b9900eSJiri Pirko MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>");
119577b9900eSJiri Pirko MODULE_DESCRIPTION("Flower classifier");
119677b9900eSJiri Pirko MODULE_LICENSE("GPL v2");
1197