xref: /linux/net/sched/cls_flower.c (revision 2745529ac7358fdac72e6b388da2e934bd9da82c)
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;
42bc3103f1SAmir Vadai 	struct flow_dissector_key_keyid enc_key_id;
43bc3103f1SAmir Vadai 	union {
44bc3103f1SAmir Vadai 		struct flow_dissector_key_ipv4_addrs enc_ipv4;
45bc3103f1SAmir Vadai 		struct flow_dissector_key_ipv6_addrs enc_ipv6;
46bc3103f1SAmir Vadai 	};
47f4d997fdSHadar Hen Zion 	struct flow_dissector_key_ports enc_tp;
4877b9900eSJiri Pirko } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
4977b9900eSJiri Pirko 
5077b9900eSJiri Pirko struct fl_flow_mask_range {
5177b9900eSJiri Pirko 	unsigned short int start;
5277b9900eSJiri Pirko 	unsigned short int end;
5377b9900eSJiri Pirko };
5477b9900eSJiri Pirko 
5577b9900eSJiri Pirko struct fl_flow_mask {
5677b9900eSJiri Pirko 	struct fl_flow_key key;
5777b9900eSJiri Pirko 	struct fl_flow_mask_range range;
5877b9900eSJiri Pirko 	struct rcu_head	rcu;
5977b9900eSJiri Pirko };
6077b9900eSJiri Pirko 
6177b9900eSJiri Pirko struct cls_fl_head {
6277b9900eSJiri Pirko 	struct rhashtable ht;
6377b9900eSJiri Pirko 	struct fl_flow_mask mask;
6477b9900eSJiri Pirko 	struct flow_dissector dissector;
6577b9900eSJiri Pirko 	u32 hgen;
6677b9900eSJiri Pirko 	bool mask_assigned;
6777b9900eSJiri Pirko 	struct list_head filters;
6877b9900eSJiri Pirko 	struct rhashtable_params ht_params;
69d9363774SDaniel Borkmann 	union {
70d9363774SDaniel Borkmann 		struct work_struct work;
7177b9900eSJiri Pirko 		struct rcu_head	rcu;
7277b9900eSJiri Pirko 	};
73d9363774SDaniel Borkmann };
7477b9900eSJiri Pirko 
7577b9900eSJiri Pirko struct cls_fl_filter {
7677b9900eSJiri Pirko 	struct rhash_head ht_node;
7777b9900eSJiri Pirko 	struct fl_flow_key mkey;
7877b9900eSJiri Pirko 	struct tcf_exts exts;
7977b9900eSJiri Pirko 	struct tcf_result res;
8077b9900eSJiri Pirko 	struct fl_flow_key key;
8177b9900eSJiri Pirko 	struct list_head list;
8277b9900eSJiri Pirko 	u32 handle;
83e69985c6SAmir Vadai 	u32 flags;
8477b9900eSJiri Pirko 	struct rcu_head	rcu;
857091d8c7SHadar Hen Zion 	struct tc_to_netdev tc;
867091d8c7SHadar Hen Zion 	struct net_device *hw_dev;
8777b9900eSJiri Pirko };
8877b9900eSJiri Pirko 
8977b9900eSJiri Pirko static unsigned short int fl_mask_range(const struct fl_flow_mask *mask)
9077b9900eSJiri Pirko {
9177b9900eSJiri Pirko 	return mask->range.end - mask->range.start;
9277b9900eSJiri Pirko }
9377b9900eSJiri Pirko 
9477b9900eSJiri Pirko static void fl_mask_update_range(struct fl_flow_mask *mask)
9577b9900eSJiri Pirko {
9677b9900eSJiri Pirko 	const u8 *bytes = (const u8 *) &mask->key;
9777b9900eSJiri Pirko 	size_t size = sizeof(mask->key);
9877b9900eSJiri Pirko 	size_t i, first = 0, last = size - 1;
9977b9900eSJiri Pirko 
10077b9900eSJiri Pirko 	for (i = 0; i < sizeof(mask->key); i++) {
10177b9900eSJiri Pirko 		if (bytes[i]) {
10277b9900eSJiri Pirko 			if (!first && i)
10377b9900eSJiri Pirko 				first = i;
10477b9900eSJiri Pirko 			last = i;
10577b9900eSJiri Pirko 		}
10677b9900eSJiri Pirko 	}
10777b9900eSJiri Pirko 	mask->range.start = rounddown(first, sizeof(long));
10877b9900eSJiri Pirko 	mask->range.end = roundup(last + 1, sizeof(long));
10977b9900eSJiri Pirko }
11077b9900eSJiri Pirko 
11177b9900eSJiri Pirko static void *fl_key_get_start(struct fl_flow_key *key,
11277b9900eSJiri Pirko 			      const struct fl_flow_mask *mask)
11377b9900eSJiri Pirko {
11477b9900eSJiri Pirko 	return (u8 *) key + mask->range.start;
11577b9900eSJiri Pirko }
11677b9900eSJiri Pirko 
11777b9900eSJiri Pirko static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key,
11877b9900eSJiri Pirko 			      struct fl_flow_mask *mask)
11977b9900eSJiri Pirko {
12077b9900eSJiri Pirko 	const long *lkey = fl_key_get_start(key, mask);
12177b9900eSJiri Pirko 	const long *lmask = fl_key_get_start(&mask->key, mask);
12277b9900eSJiri Pirko 	long *lmkey = fl_key_get_start(mkey, mask);
12377b9900eSJiri Pirko 	int i;
12477b9900eSJiri Pirko 
12577b9900eSJiri Pirko 	for (i = 0; i < fl_mask_range(mask); i += sizeof(long))
12677b9900eSJiri Pirko 		*lmkey++ = *lkey++ & *lmask++;
12777b9900eSJiri Pirko }
12877b9900eSJiri Pirko 
12977b9900eSJiri Pirko static void fl_clear_masked_range(struct fl_flow_key *key,
13077b9900eSJiri Pirko 				  struct fl_flow_mask *mask)
13177b9900eSJiri Pirko {
13277b9900eSJiri Pirko 	memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask));
13377b9900eSJiri Pirko }
13477b9900eSJiri Pirko 
13577b9900eSJiri Pirko static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp,
13677b9900eSJiri Pirko 		       struct tcf_result *res)
13777b9900eSJiri Pirko {
13877b9900eSJiri Pirko 	struct cls_fl_head *head = rcu_dereference_bh(tp->root);
13977b9900eSJiri Pirko 	struct cls_fl_filter *f;
14077b9900eSJiri Pirko 	struct fl_flow_key skb_key;
14177b9900eSJiri Pirko 	struct fl_flow_key skb_mkey;
142bc3103f1SAmir Vadai 	struct ip_tunnel_info *info;
14377b9900eSJiri Pirko 
144e69985c6SAmir Vadai 	if (!atomic_read(&head->ht.nelems))
145e69985c6SAmir Vadai 		return -1;
146e69985c6SAmir Vadai 
14777b9900eSJiri Pirko 	fl_clear_masked_range(&skb_key, &head->mask);
148bc3103f1SAmir Vadai 
149bc3103f1SAmir Vadai 	info = skb_tunnel_info(skb);
150bc3103f1SAmir Vadai 	if (info) {
151bc3103f1SAmir Vadai 		struct ip_tunnel_key *key = &info->key;
152bc3103f1SAmir Vadai 
153bc3103f1SAmir Vadai 		switch (ip_tunnel_info_af(info)) {
154bc3103f1SAmir Vadai 		case AF_INET:
155bc3103f1SAmir Vadai 			skb_key.enc_ipv4.src = key->u.ipv4.src;
156bc3103f1SAmir Vadai 			skb_key.enc_ipv4.dst = key->u.ipv4.dst;
157bc3103f1SAmir Vadai 			break;
158bc3103f1SAmir Vadai 		case AF_INET6:
159bc3103f1SAmir Vadai 			skb_key.enc_ipv6.src = key->u.ipv6.src;
160bc3103f1SAmir Vadai 			skb_key.enc_ipv6.dst = key->u.ipv6.dst;
161bc3103f1SAmir Vadai 			break;
162bc3103f1SAmir Vadai 		}
163bc3103f1SAmir Vadai 
164bc3103f1SAmir Vadai 		skb_key.enc_key_id.keyid = tunnel_id_to_key32(key->tun_id);
165f4d997fdSHadar Hen Zion 		skb_key.enc_tp.src = key->tp_src;
166f4d997fdSHadar Hen Zion 		skb_key.enc_tp.dst = key->tp_dst;
167bc3103f1SAmir Vadai 	}
168bc3103f1SAmir Vadai 
16977b9900eSJiri Pirko 	skb_key.indev_ifindex = skb->skb_iif;
17077b9900eSJiri Pirko 	/* skb_flow_dissect() does not set n_proto in case an unknown protocol,
17177b9900eSJiri Pirko 	 * so do it rather here.
17277b9900eSJiri Pirko 	 */
17377b9900eSJiri Pirko 	skb_key.basic.n_proto = skb->protocol;
174cd79a238STom Herbert 	skb_flow_dissect(skb, &head->dissector, &skb_key, 0);
17577b9900eSJiri Pirko 
17677b9900eSJiri Pirko 	fl_set_masked_key(&skb_mkey, &skb_key, &head->mask);
17777b9900eSJiri Pirko 
17877b9900eSJiri Pirko 	f = rhashtable_lookup_fast(&head->ht,
17977b9900eSJiri Pirko 				   fl_key_get_start(&skb_mkey, &head->mask),
18077b9900eSJiri Pirko 				   head->ht_params);
181e8eb36cdSAmir Vadai 	if (f && !tc_skip_sw(f->flags)) {
18277b9900eSJiri Pirko 		*res = f->res;
18377b9900eSJiri Pirko 		return tcf_exts_exec(skb, &f->exts, res);
18477b9900eSJiri Pirko 	}
18577b9900eSJiri Pirko 	return -1;
18677b9900eSJiri Pirko }
18777b9900eSJiri Pirko 
18877b9900eSJiri Pirko static int fl_init(struct tcf_proto *tp)
18977b9900eSJiri Pirko {
19077b9900eSJiri Pirko 	struct cls_fl_head *head;
19177b9900eSJiri Pirko 
19277b9900eSJiri Pirko 	head = kzalloc(sizeof(*head), GFP_KERNEL);
19377b9900eSJiri Pirko 	if (!head)
19477b9900eSJiri Pirko 		return -ENOBUFS;
19577b9900eSJiri Pirko 
19677b9900eSJiri Pirko 	INIT_LIST_HEAD_RCU(&head->filters);
19777b9900eSJiri Pirko 	rcu_assign_pointer(tp->root, head);
19877b9900eSJiri Pirko 
19977b9900eSJiri Pirko 	return 0;
20077b9900eSJiri Pirko }
20177b9900eSJiri Pirko 
20277b9900eSJiri Pirko static void fl_destroy_filter(struct rcu_head *head)
20377b9900eSJiri Pirko {
20477b9900eSJiri Pirko 	struct cls_fl_filter *f = container_of(head, struct cls_fl_filter, rcu);
20577b9900eSJiri Pirko 
20677b9900eSJiri Pirko 	tcf_exts_destroy(&f->exts);
20777b9900eSJiri Pirko 	kfree(f);
20877b9900eSJiri Pirko }
20977b9900eSJiri Pirko 
2103036dab6SHadar Hen Zion static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f)
2115b33f488SAmir Vadai {
2125b33f488SAmir Vadai 	struct tc_cls_flower_offload offload = {0};
2137091d8c7SHadar Hen Zion 	struct net_device *dev = f->hw_dev;
2147091d8c7SHadar Hen Zion 	struct tc_to_netdev *tc = &f->tc;
2155b33f488SAmir Vadai 
21679685219SHadar Hen Zion 	if (!tc_can_offload(dev, tp))
2175b33f488SAmir Vadai 		return;
2185b33f488SAmir Vadai 
2195b33f488SAmir Vadai 	offload.command = TC_CLSFLOWER_DESTROY;
2203036dab6SHadar Hen Zion 	offload.cookie = (unsigned long)f;
2215b33f488SAmir Vadai 
2227091d8c7SHadar Hen Zion 	tc->type = TC_SETUP_CLSFLOWER;
2237091d8c7SHadar Hen Zion 	tc->cls_flower = &offload;
2245b33f488SAmir Vadai 
2257091d8c7SHadar Hen Zion 	dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, tc);
2265b33f488SAmir Vadai }
2275b33f488SAmir Vadai 
228e8eb36cdSAmir Vadai static int fl_hw_replace_filter(struct tcf_proto *tp,
2295b33f488SAmir Vadai 				struct flow_dissector *dissector,
2305b33f488SAmir Vadai 				struct fl_flow_key *mask,
2313036dab6SHadar Hen Zion 				struct cls_fl_filter *f)
2325b33f488SAmir Vadai {
2335b33f488SAmir Vadai 	struct net_device *dev = tp->q->dev_queue->dev;
2345b33f488SAmir Vadai 	struct tc_cls_flower_offload offload = {0};
2357091d8c7SHadar Hen Zion 	struct tc_to_netdev *tc = &f->tc;
236e8eb36cdSAmir Vadai 	int err;
2375b33f488SAmir Vadai 
2387091d8c7SHadar Hen Zion 	if (!tc_can_offload(dev, tp)) {
2397091d8c7SHadar Hen Zion 		if (tcf_exts_get_dev(dev, &f->exts, &f->hw_dev))
2403036dab6SHadar Hen Zion 			return tc_skip_sw(f->flags) ? -EINVAL : 0;
2417091d8c7SHadar Hen Zion 		dev = f->hw_dev;
2427091d8c7SHadar Hen Zion 		tc->egress_dev = true;
2437091d8c7SHadar Hen Zion 	} else {
2447091d8c7SHadar Hen Zion 		f->hw_dev = dev;
2457091d8c7SHadar Hen Zion 	}
2465b33f488SAmir Vadai 
2475b33f488SAmir Vadai 	offload.command = TC_CLSFLOWER_REPLACE;
2483036dab6SHadar Hen Zion 	offload.cookie = (unsigned long)f;
2495b33f488SAmir Vadai 	offload.dissector = dissector;
2505b33f488SAmir Vadai 	offload.mask = mask;
2513036dab6SHadar Hen Zion 	offload.key = &f->key;
2523036dab6SHadar Hen Zion 	offload.exts = &f->exts;
2535b33f488SAmir Vadai 
2547091d8c7SHadar Hen Zion 	tc->type = TC_SETUP_CLSFLOWER;
2557091d8c7SHadar Hen Zion 	tc->cls_flower = &offload;
2565b33f488SAmir Vadai 
2575a7a5555SJamal Hadi Salim 	err = dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol,
2587091d8c7SHadar Hen Zion 					    tc);
259e8eb36cdSAmir Vadai 
2603036dab6SHadar Hen Zion 	if (tc_skip_sw(f->flags))
261e8eb36cdSAmir Vadai 		return err;
262e8eb36cdSAmir Vadai 	return 0;
2635b33f488SAmir Vadai }
2645b33f488SAmir Vadai 
26510cbc684SAmir Vadai static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
26610cbc684SAmir Vadai {
26710cbc684SAmir Vadai 	struct tc_cls_flower_offload offload = {0};
2687091d8c7SHadar Hen Zion 	struct net_device *dev = f->hw_dev;
2697091d8c7SHadar Hen Zion 	struct tc_to_netdev *tc = &f->tc;
27010cbc684SAmir Vadai 
27179685219SHadar Hen Zion 	if (!tc_can_offload(dev, tp))
27210cbc684SAmir Vadai 		return;
27310cbc684SAmir Vadai 
27410cbc684SAmir Vadai 	offload.command = TC_CLSFLOWER_STATS;
27510cbc684SAmir Vadai 	offload.cookie = (unsigned long)f;
27610cbc684SAmir Vadai 	offload.exts = &f->exts;
27710cbc684SAmir Vadai 
2787091d8c7SHadar Hen Zion 	tc->type = TC_SETUP_CLSFLOWER;
2797091d8c7SHadar Hen Zion 	tc->cls_flower = &offload;
28010cbc684SAmir Vadai 
2817091d8c7SHadar Hen Zion 	dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, tc);
28210cbc684SAmir Vadai }
28310cbc684SAmir Vadai 
28413fa876eSRoi Dayan static void __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f)
28513fa876eSRoi Dayan {
28613fa876eSRoi Dayan 	list_del_rcu(&f->list);
28779685219SHadar Hen Zion 	if (!tc_skip_hw(f->flags))
2883036dab6SHadar Hen Zion 		fl_hw_destroy_filter(tp, f);
28913fa876eSRoi Dayan 	tcf_unbind_filter(tp, &f->res);
29013fa876eSRoi Dayan 	call_rcu(&f->rcu, fl_destroy_filter);
29113fa876eSRoi Dayan }
29213fa876eSRoi Dayan 
293d9363774SDaniel Borkmann static void fl_destroy_sleepable(struct work_struct *work)
294d9363774SDaniel Borkmann {
295d9363774SDaniel Borkmann 	struct cls_fl_head *head = container_of(work, struct cls_fl_head,
296d9363774SDaniel Borkmann 						work);
297d9363774SDaniel Borkmann 	if (head->mask_assigned)
298d9363774SDaniel Borkmann 		rhashtable_destroy(&head->ht);
299d9363774SDaniel Borkmann 	kfree(head);
300d9363774SDaniel Borkmann 	module_put(THIS_MODULE);
301d9363774SDaniel Borkmann }
302d9363774SDaniel Borkmann 
303d9363774SDaniel Borkmann static void fl_destroy_rcu(struct rcu_head *rcu)
304d9363774SDaniel Borkmann {
305d9363774SDaniel Borkmann 	struct cls_fl_head *head = container_of(rcu, struct cls_fl_head, rcu);
306d9363774SDaniel Borkmann 
307d9363774SDaniel Borkmann 	INIT_WORK(&head->work, fl_destroy_sleepable);
308d9363774SDaniel Borkmann 	schedule_work(&head->work);
309d9363774SDaniel Borkmann }
310d9363774SDaniel Borkmann 
31177b9900eSJiri Pirko static bool fl_destroy(struct tcf_proto *tp, bool force)
31277b9900eSJiri Pirko {
31377b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
31477b9900eSJiri Pirko 	struct cls_fl_filter *f, *next;
31577b9900eSJiri Pirko 
31677b9900eSJiri Pirko 	if (!force && !list_empty(&head->filters))
31777b9900eSJiri Pirko 		return false;
31877b9900eSJiri Pirko 
31913fa876eSRoi Dayan 	list_for_each_entry_safe(f, next, &head->filters, list)
32013fa876eSRoi Dayan 		__fl_delete(tp, f);
321d9363774SDaniel Borkmann 
322d9363774SDaniel Borkmann 	__module_get(THIS_MODULE);
323d9363774SDaniel Borkmann 	call_rcu(&head->rcu, fl_destroy_rcu);
324*2745529aSDavid S. Miller 
32577b9900eSJiri Pirko 	return true;
32677b9900eSJiri Pirko }
32777b9900eSJiri Pirko 
32877b9900eSJiri Pirko static unsigned long fl_get(struct tcf_proto *tp, u32 handle)
32977b9900eSJiri Pirko {
33077b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
33177b9900eSJiri Pirko 	struct cls_fl_filter *f;
33277b9900eSJiri Pirko 
33377b9900eSJiri Pirko 	list_for_each_entry(f, &head->filters, list)
33477b9900eSJiri Pirko 		if (f->handle == handle)
33577b9900eSJiri Pirko 			return (unsigned long) f;
33677b9900eSJiri Pirko 	return 0;
33777b9900eSJiri Pirko }
33877b9900eSJiri Pirko 
33977b9900eSJiri Pirko static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
34077b9900eSJiri Pirko 	[TCA_FLOWER_UNSPEC]		= { .type = NLA_UNSPEC },
34177b9900eSJiri Pirko 	[TCA_FLOWER_CLASSID]		= { .type = NLA_U32 },
34277b9900eSJiri Pirko 	[TCA_FLOWER_INDEV]		= { .type = NLA_STRING,
34377b9900eSJiri Pirko 					    .len = IFNAMSIZ },
34477b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_DST]	= { .len = ETH_ALEN },
34577b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_DST_MASK]	= { .len = ETH_ALEN },
34677b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_SRC]	= { .len = ETH_ALEN },
34777b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_SRC_MASK]	= { .len = ETH_ALEN },
34877b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_TYPE]	= { .type = NLA_U16 },
34977b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IP_PROTO]	= { .type = NLA_U8 },
35077b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_SRC]	= { .type = NLA_U32 },
35177b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_SRC_MASK]	= { .type = NLA_U32 },
35277b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_DST]	= { .type = NLA_U32 },
35377b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_DST_MASK]	= { .type = NLA_U32 },
35477b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
35577b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_SRC_MASK]	= { .len = sizeof(struct in6_addr) },
35677b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
35777b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_DST_MASK]	= { .len = sizeof(struct in6_addr) },
35877b9900eSJiri Pirko 	[TCA_FLOWER_KEY_TCP_SRC]	= { .type = NLA_U16 },
35977b9900eSJiri Pirko 	[TCA_FLOWER_KEY_TCP_DST]	= { .type = NLA_U16 },
360b175c3a4SJamal Hadi Salim 	[TCA_FLOWER_KEY_UDP_SRC]	= { .type = NLA_U16 },
361b175c3a4SJamal Hadi Salim 	[TCA_FLOWER_KEY_UDP_DST]	= { .type = NLA_U16 },
3629399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_ID]	= { .type = NLA_U16 },
3639399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_PRIO]	= { .type = NLA_U8 },
3649399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_ETH_TYPE]	= { .type = NLA_U16 },
365bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_KEY_ID]	= { .type = NLA_U32 },
366bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_SRC]	= { .type = NLA_U32 },
367bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NLA_U32 },
368bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_DST]	= { .type = NLA_U32 },
369bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NLA_U32 },
370bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
371bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) },
372bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
373bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) },
374aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_TCP_SRC_MASK]	= { .type = NLA_U16 },
375aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_TCP_DST_MASK]	= { .type = NLA_U16 },
376aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_UDP_SRC_MASK]	= { .type = NLA_U16 },
377aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_UDP_DST_MASK]	= { .type = NLA_U16 },
3785976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_SRC_MASK]	= { .type = NLA_U16 },
3795976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_DST_MASK]	= { .type = NLA_U16 },
3805976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_SRC]	= { .type = NLA_U16 },
3815976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_DST]	= { .type = NLA_U16 },
382f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT]	= { .type = NLA_U16 },
383f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK]	= { .type = NLA_U16 },
384f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]	= { .type = NLA_U16 },
385f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK]	= { .type = NLA_U16 },
38677b9900eSJiri Pirko };
38777b9900eSJiri Pirko 
38877b9900eSJiri Pirko static void fl_set_key_val(struct nlattr **tb,
38977b9900eSJiri Pirko 			   void *val, int val_type,
39077b9900eSJiri Pirko 			   void *mask, int mask_type, int len)
39177b9900eSJiri Pirko {
39277b9900eSJiri Pirko 	if (!tb[val_type])
39377b9900eSJiri Pirko 		return;
39477b9900eSJiri Pirko 	memcpy(val, nla_data(tb[val_type]), len);
39577b9900eSJiri Pirko 	if (mask_type == TCA_FLOWER_UNSPEC || !tb[mask_type])
39677b9900eSJiri Pirko 		memset(mask, 0xff, len);
39777b9900eSJiri Pirko 	else
39877b9900eSJiri Pirko 		memcpy(mask, nla_data(tb[mask_type]), len);
39977b9900eSJiri Pirko }
40077b9900eSJiri Pirko 
4019399ae9aSHadar Hen Zion static void fl_set_key_vlan(struct nlattr **tb,
4029399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *key_val,
4039399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *key_mask)
4049399ae9aSHadar Hen Zion {
4059399ae9aSHadar Hen Zion #define VLAN_PRIORITY_MASK	0x7
4069399ae9aSHadar Hen Zion 
4079399ae9aSHadar Hen Zion 	if (tb[TCA_FLOWER_KEY_VLAN_ID]) {
4089399ae9aSHadar Hen Zion 		key_val->vlan_id =
4099399ae9aSHadar Hen Zion 			nla_get_u16(tb[TCA_FLOWER_KEY_VLAN_ID]) & VLAN_VID_MASK;
4109399ae9aSHadar Hen Zion 		key_mask->vlan_id = VLAN_VID_MASK;
4119399ae9aSHadar Hen Zion 	}
4129399ae9aSHadar Hen Zion 	if (tb[TCA_FLOWER_KEY_VLAN_PRIO]) {
4139399ae9aSHadar Hen Zion 		key_val->vlan_priority =
4149399ae9aSHadar Hen Zion 			nla_get_u8(tb[TCA_FLOWER_KEY_VLAN_PRIO]) &
4159399ae9aSHadar Hen Zion 			VLAN_PRIORITY_MASK;
4169399ae9aSHadar Hen Zion 		key_mask->vlan_priority = VLAN_PRIORITY_MASK;
4179399ae9aSHadar Hen Zion 	}
4189399ae9aSHadar Hen Zion }
4199399ae9aSHadar Hen Zion 
42077b9900eSJiri Pirko static int fl_set_key(struct net *net, struct nlattr **tb,
42177b9900eSJiri Pirko 		      struct fl_flow_key *key, struct fl_flow_key *mask)
42277b9900eSJiri Pirko {
4239399ae9aSHadar Hen Zion 	__be16 ethertype;
424dd3aa3b5SBrian Haley #ifdef CONFIG_NET_CLS_IND
42577b9900eSJiri Pirko 	if (tb[TCA_FLOWER_INDEV]) {
426dd3aa3b5SBrian Haley 		int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV]);
42777b9900eSJiri Pirko 		if (err < 0)
42877b9900eSJiri Pirko 			return err;
42977b9900eSJiri Pirko 		key->indev_ifindex = err;
43077b9900eSJiri Pirko 		mask->indev_ifindex = 0xffffffff;
43177b9900eSJiri Pirko 	}
432dd3aa3b5SBrian Haley #endif
43377b9900eSJiri Pirko 
43477b9900eSJiri Pirko 	fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
43577b9900eSJiri Pirko 		       mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
43677b9900eSJiri Pirko 		       sizeof(key->eth.dst));
43777b9900eSJiri Pirko 	fl_set_key_val(tb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
43877b9900eSJiri Pirko 		       mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
43977b9900eSJiri Pirko 		       sizeof(key->eth.src));
44066530bdfSJamal Hadi Salim 
4410b498a52SArnd Bergmann 	if (tb[TCA_FLOWER_KEY_ETH_TYPE]) {
4429399ae9aSHadar Hen Zion 		ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_ETH_TYPE]);
4439399ae9aSHadar Hen Zion 
4449399ae9aSHadar Hen Zion 		if (ethertype == htons(ETH_P_8021Q)) {
4459399ae9aSHadar Hen Zion 			fl_set_key_vlan(tb, &key->vlan, &mask->vlan);
4469399ae9aSHadar Hen Zion 			fl_set_key_val(tb, &key->basic.n_proto,
4479399ae9aSHadar Hen Zion 				       TCA_FLOWER_KEY_VLAN_ETH_TYPE,
44877b9900eSJiri Pirko 				       &mask->basic.n_proto, TCA_FLOWER_UNSPEC,
44977b9900eSJiri Pirko 				       sizeof(key->basic.n_proto));
4509399ae9aSHadar Hen Zion 		} else {
4519399ae9aSHadar Hen Zion 			key->basic.n_proto = ethertype;
4529399ae9aSHadar Hen Zion 			mask->basic.n_proto = cpu_to_be16(~0);
4539399ae9aSHadar Hen Zion 		}
4540b498a52SArnd Bergmann 	}
45566530bdfSJamal Hadi Salim 
45677b9900eSJiri Pirko 	if (key->basic.n_proto == htons(ETH_P_IP) ||
45777b9900eSJiri Pirko 	    key->basic.n_proto == htons(ETH_P_IPV6)) {
45877b9900eSJiri Pirko 		fl_set_key_val(tb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
45977b9900eSJiri Pirko 			       &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
46077b9900eSJiri Pirko 			       sizeof(key->basic.ip_proto));
46177b9900eSJiri Pirko 	}
46266530bdfSJamal Hadi Salim 
46366530bdfSJamal Hadi Salim 	if (tb[TCA_FLOWER_KEY_IPV4_SRC] || tb[TCA_FLOWER_KEY_IPV4_DST]) {
46466530bdfSJamal Hadi Salim 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
46577b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
46677b9900eSJiri Pirko 			       &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
46777b9900eSJiri Pirko 			       sizeof(key->ipv4.src));
46877b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
46977b9900eSJiri Pirko 			       &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
47077b9900eSJiri Pirko 			       sizeof(key->ipv4.dst));
47166530bdfSJamal Hadi Salim 	} else if (tb[TCA_FLOWER_KEY_IPV6_SRC] || tb[TCA_FLOWER_KEY_IPV6_DST]) {
47266530bdfSJamal Hadi Salim 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
47377b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
47477b9900eSJiri Pirko 			       &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
47577b9900eSJiri Pirko 			       sizeof(key->ipv6.src));
47677b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
47777b9900eSJiri Pirko 			       &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
47877b9900eSJiri Pirko 			       sizeof(key->ipv6.dst));
47977b9900eSJiri Pirko 	}
48066530bdfSJamal Hadi Salim 
48177b9900eSJiri Pirko 	if (key->basic.ip_proto == IPPROTO_TCP) {
48277b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
483aa72d708SOr Gerlitz 			       &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
48477b9900eSJiri Pirko 			       sizeof(key->tp.src));
48577b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
486aa72d708SOr Gerlitz 			       &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
48777b9900eSJiri Pirko 			       sizeof(key->tp.dst));
48877b9900eSJiri Pirko 	} else if (key->basic.ip_proto == IPPROTO_UDP) {
48977b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
490aa72d708SOr Gerlitz 			       &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
49177b9900eSJiri Pirko 			       sizeof(key->tp.src));
49277b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
493aa72d708SOr Gerlitz 			       &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
49477b9900eSJiri Pirko 			       sizeof(key->tp.dst));
4955976c5f4SSimon Horman 	} else if (key->basic.ip_proto == IPPROTO_SCTP) {
4965976c5f4SSimon Horman 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
4975976c5f4SSimon Horman 			       &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
4985976c5f4SSimon Horman 			       sizeof(key->tp.src));
4995976c5f4SSimon Horman 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
5005976c5f4SSimon Horman 			       &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
5015976c5f4SSimon Horman 			       sizeof(key->tp.dst));
50277b9900eSJiri Pirko 	}
50377b9900eSJiri Pirko 
504bc3103f1SAmir Vadai 	if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] ||
505bc3103f1SAmir Vadai 	    tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) {
506bc3103f1SAmir Vadai 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
507bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv4.src,
508bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_SRC,
509bc3103f1SAmir Vadai 			       &mask->enc_ipv4.src,
510bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
511bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv4.src));
512bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv4.dst,
513bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_DST,
514bc3103f1SAmir Vadai 			       &mask->enc_ipv4.dst,
515bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
516bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv4.dst));
517bc3103f1SAmir Vadai 	}
518bc3103f1SAmir Vadai 
519bc3103f1SAmir Vadai 	if (tb[TCA_FLOWER_KEY_ENC_IPV6_SRC] ||
520bc3103f1SAmir Vadai 	    tb[TCA_FLOWER_KEY_ENC_IPV6_DST]) {
521bc3103f1SAmir Vadai 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
522bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv6.src,
523bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_SRC,
524bc3103f1SAmir Vadai 			       &mask->enc_ipv6.src,
525bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
526bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv6.src));
527bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv6.dst,
528bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_DST,
529bc3103f1SAmir Vadai 			       &mask->enc_ipv6.dst,
530bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
531bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv6.dst));
532bc3103f1SAmir Vadai 	}
533bc3103f1SAmir Vadai 
534bc3103f1SAmir Vadai 	fl_set_key_val(tb, &key->enc_key_id.keyid, TCA_FLOWER_KEY_ENC_KEY_ID,
535eb523f42SHadar Hen Zion 		       &mask->enc_key_id.keyid, TCA_FLOWER_UNSPEC,
536bc3103f1SAmir Vadai 		       sizeof(key->enc_key_id.keyid));
537bc3103f1SAmir Vadai 
538f4d997fdSHadar Hen Zion 	fl_set_key_val(tb, &key->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
539f4d997fdSHadar Hen Zion 		       &mask->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
540f4d997fdSHadar Hen Zion 		       sizeof(key->enc_tp.src));
541f4d997fdSHadar Hen Zion 
542f4d997fdSHadar Hen Zion 	fl_set_key_val(tb, &key->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
543f4d997fdSHadar Hen Zion 		       &mask->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
544f4d997fdSHadar Hen Zion 		       sizeof(key->enc_tp.dst));
545f4d997fdSHadar Hen Zion 
54677b9900eSJiri Pirko 	return 0;
54777b9900eSJiri Pirko }
54877b9900eSJiri Pirko 
54977b9900eSJiri Pirko static bool fl_mask_eq(struct fl_flow_mask *mask1,
55077b9900eSJiri Pirko 		       struct fl_flow_mask *mask2)
55177b9900eSJiri Pirko {
55277b9900eSJiri Pirko 	const long *lmask1 = fl_key_get_start(&mask1->key, mask1);
55377b9900eSJiri Pirko 	const long *lmask2 = fl_key_get_start(&mask2->key, mask2);
55477b9900eSJiri Pirko 
55577b9900eSJiri Pirko 	return !memcmp(&mask1->range, &mask2->range, sizeof(mask1->range)) &&
55677b9900eSJiri Pirko 	       !memcmp(lmask1, lmask2, fl_mask_range(mask1));
55777b9900eSJiri Pirko }
55877b9900eSJiri Pirko 
55977b9900eSJiri Pirko static const struct rhashtable_params fl_ht_params = {
56077b9900eSJiri Pirko 	.key_offset = offsetof(struct cls_fl_filter, mkey), /* base offset */
56177b9900eSJiri Pirko 	.head_offset = offsetof(struct cls_fl_filter, ht_node),
56277b9900eSJiri Pirko 	.automatic_shrinking = true,
56377b9900eSJiri Pirko };
56477b9900eSJiri Pirko 
56577b9900eSJiri Pirko static int fl_init_hashtable(struct cls_fl_head *head,
56677b9900eSJiri Pirko 			     struct fl_flow_mask *mask)
56777b9900eSJiri Pirko {
56877b9900eSJiri Pirko 	head->ht_params = fl_ht_params;
56977b9900eSJiri Pirko 	head->ht_params.key_len = fl_mask_range(mask);
57077b9900eSJiri Pirko 	head->ht_params.key_offset += mask->range.start;
57177b9900eSJiri Pirko 
57277b9900eSJiri Pirko 	return rhashtable_init(&head->ht, &head->ht_params);
57377b9900eSJiri Pirko }
57477b9900eSJiri Pirko 
57577b9900eSJiri Pirko #define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member)
57677b9900eSJiri Pirko #define FL_KEY_MEMBER_SIZE(member) (sizeof(((struct fl_flow_key *) 0)->member))
57777b9900eSJiri Pirko 
578339ba878SHadar Hen Zion #define FL_KEY_IS_MASKED(mask, member)						\
579339ba878SHadar Hen Zion 	memchr_inv(((char *)mask) + FL_KEY_MEMBER_OFFSET(member),		\
580339ba878SHadar Hen Zion 		   0, FL_KEY_MEMBER_SIZE(member))				\
58177b9900eSJiri Pirko 
58277b9900eSJiri Pirko #define FL_KEY_SET(keys, cnt, id, member)					\
58377b9900eSJiri Pirko 	do {									\
58477b9900eSJiri Pirko 		keys[cnt].key_id = id;						\
58577b9900eSJiri Pirko 		keys[cnt].offset = FL_KEY_MEMBER_OFFSET(member);		\
58677b9900eSJiri Pirko 		cnt++;								\
58777b9900eSJiri Pirko 	} while(0);
58877b9900eSJiri Pirko 
589339ba878SHadar Hen Zion #define FL_KEY_SET_IF_MASKED(mask, keys, cnt, id, member)			\
59077b9900eSJiri Pirko 	do {									\
591339ba878SHadar Hen Zion 		if (FL_KEY_IS_MASKED(mask, member))				\
59277b9900eSJiri Pirko 			FL_KEY_SET(keys, cnt, id, member);			\
59377b9900eSJiri Pirko 	} while(0);
59477b9900eSJiri Pirko 
59577b9900eSJiri Pirko static void fl_init_dissector(struct cls_fl_head *head,
59677b9900eSJiri Pirko 			      struct fl_flow_mask *mask)
59777b9900eSJiri Pirko {
59877b9900eSJiri Pirko 	struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX];
59977b9900eSJiri Pirko 	size_t cnt = 0;
60077b9900eSJiri Pirko 
60142aecaa9STom Herbert 	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control);
60277b9900eSJiri Pirko 	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic);
603339ba878SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
60477b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_ETH_ADDRS, eth);
605339ba878SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
60677b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4);
607339ba878SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
60877b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6);
609339ba878SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
61077b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_PORTS, tp);
6119399ae9aSHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
6129399ae9aSHadar Hen Zion 			     FLOW_DISSECTOR_KEY_VLAN, vlan);
613519d1052SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
614519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_KEYID, enc_key_id);
615519d1052SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
616519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, enc_ipv4);
617519d1052SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
618519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, enc_ipv6);
619519d1052SHadar Hen Zion 	if (FL_KEY_IS_MASKED(&mask->key, enc_ipv4) ||
620519d1052SHadar Hen Zion 	    FL_KEY_IS_MASKED(&mask->key, enc_ipv6))
621519d1052SHadar Hen Zion 		FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_ENC_CONTROL,
622519d1052SHadar Hen Zion 			   enc_control);
623f4d997fdSHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
624f4d997fdSHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp);
62577b9900eSJiri Pirko 
62677b9900eSJiri Pirko 	skb_flow_dissector_init(&head->dissector, keys, cnt);
62777b9900eSJiri Pirko }
62877b9900eSJiri Pirko 
62977b9900eSJiri Pirko static int fl_check_assign_mask(struct cls_fl_head *head,
63077b9900eSJiri Pirko 				struct fl_flow_mask *mask)
63177b9900eSJiri Pirko {
63277b9900eSJiri Pirko 	int err;
63377b9900eSJiri Pirko 
63477b9900eSJiri Pirko 	if (head->mask_assigned) {
63577b9900eSJiri Pirko 		if (!fl_mask_eq(&head->mask, mask))
63677b9900eSJiri Pirko 			return -EINVAL;
63777b9900eSJiri Pirko 		else
63877b9900eSJiri Pirko 			return 0;
63977b9900eSJiri Pirko 	}
64077b9900eSJiri Pirko 
64177b9900eSJiri Pirko 	/* Mask is not assigned yet. So assign it and init hashtable
64277b9900eSJiri Pirko 	 * according to that.
64377b9900eSJiri Pirko 	 */
64477b9900eSJiri Pirko 	err = fl_init_hashtable(head, mask);
64577b9900eSJiri Pirko 	if (err)
64677b9900eSJiri Pirko 		return err;
64777b9900eSJiri Pirko 	memcpy(&head->mask, mask, sizeof(head->mask));
64877b9900eSJiri Pirko 	head->mask_assigned = true;
64977b9900eSJiri Pirko 
65077b9900eSJiri Pirko 	fl_init_dissector(head, mask);
65177b9900eSJiri Pirko 
65277b9900eSJiri Pirko 	return 0;
65377b9900eSJiri Pirko }
65477b9900eSJiri Pirko 
65577b9900eSJiri Pirko static int fl_set_parms(struct net *net, struct tcf_proto *tp,
65677b9900eSJiri Pirko 			struct cls_fl_filter *f, struct fl_flow_mask *mask,
65777b9900eSJiri Pirko 			unsigned long base, struct nlattr **tb,
65877b9900eSJiri Pirko 			struct nlattr *est, bool ovr)
65977b9900eSJiri Pirko {
66077b9900eSJiri Pirko 	struct tcf_exts e;
66177b9900eSJiri Pirko 	int err;
66277b9900eSJiri Pirko 
663b9a24bb7SWANG Cong 	err = tcf_exts_init(&e, TCA_FLOWER_ACT, 0);
66477b9900eSJiri Pirko 	if (err < 0)
66577b9900eSJiri Pirko 		return err;
666b9a24bb7SWANG Cong 	err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
667b9a24bb7SWANG Cong 	if (err < 0)
668b9a24bb7SWANG Cong 		goto errout;
66977b9900eSJiri Pirko 
67077b9900eSJiri Pirko 	if (tb[TCA_FLOWER_CLASSID]) {
67177b9900eSJiri Pirko 		f->res.classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]);
67277b9900eSJiri Pirko 		tcf_bind_filter(tp, &f->res, base);
67377b9900eSJiri Pirko 	}
67477b9900eSJiri Pirko 
67577b9900eSJiri Pirko 	err = fl_set_key(net, tb, &f->key, &mask->key);
67677b9900eSJiri Pirko 	if (err)
67777b9900eSJiri Pirko 		goto errout;
67877b9900eSJiri Pirko 
67977b9900eSJiri Pirko 	fl_mask_update_range(mask);
68077b9900eSJiri Pirko 	fl_set_masked_key(&f->mkey, &f->key, mask);
68177b9900eSJiri Pirko 
68277b9900eSJiri Pirko 	tcf_exts_change(tp, &f->exts, &e);
68377b9900eSJiri Pirko 
68477b9900eSJiri Pirko 	return 0;
68577b9900eSJiri Pirko errout:
68677b9900eSJiri Pirko 	tcf_exts_destroy(&e);
68777b9900eSJiri Pirko 	return err;
68877b9900eSJiri Pirko }
68977b9900eSJiri Pirko 
69077b9900eSJiri Pirko static u32 fl_grab_new_handle(struct tcf_proto *tp,
69177b9900eSJiri Pirko 			      struct cls_fl_head *head)
69277b9900eSJiri Pirko {
69377b9900eSJiri Pirko 	unsigned int i = 0x80000000;
69477b9900eSJiri Pirko 	u32 handle;
69577b9900eSJiri Pirko 
69677b9900eSJiri Pirko 	do {
69777b9900eSJiri Pirko 		if (++head->hgen == 0x7FFFFFFF)
69877b9900eSJiri Pirko 			head->hgen = 1;
69977b9900eSJiri Pirko 	} while (--i > 0 && fl_get(tp, head->hgen));
70077b9900eSJiri Pirko 
70177b9900eSJiri Pirko 	if (unlikely(i == 0)) {
70277b9900eSJiri Pirko 		pr_err("Insufficient number of handles\n");
70377b9900eSJiri Pirko 		handle = 0;
70477b9900eSJiri Pirko 	} else {
70577b9900eSJiri Pirko 		handle = head->hgen;
70677b9900eSJiri Pirko 	}
70777b9900eSJiri Pirko 
70877b9900eSJiri Pirko 	return handle;
70977b9900eSJiri Pirko }
71077b9900eSJiri Pirko 
71177b9900eSJiri Pirko static int fl_change(struct net *net, struct sk_buff *in_skb,
71277b9900eSJiri Pirko 		     struct tcf_proto *tp, unsigned long base,
71377b9900eSJiri Pirko 		     u32 handle, struct nlattr **tca,
71477b9900eSJiri Pirko 		     unsigned long *arg, bool ovr)
71577b9900eSJiri Pirko {
71677b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
71777b9900eSJiri Pirko 	struct cls_fl_filter *fold = (struct cls_fl_filter *) *arg;
71877b9900eSJiri Pirko 	struct cls_fl_filter *fnew;
71977b9900eSJiri Pirko 	struct nlattr *tb[TCA_FLOWER_MAX + 1];
72077b9900eSJiri Pirko 	struct fl_flow_mask mask = {};
72177b9900eSJiri Pirko 	int err;
72277b9900eSJiri Pirko 
72377b9900eSJiri Pirko 	if (!tca[TCA_OPTIONS])
72477b9900eSJiri Pirko 		return -EINVAL;
72577b9900eSJiri Pirko 
72677b9900eSJiri Pirko 	err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS], fl_policy);
72777b9900eSJiri Pirko 	if (err < 0)
72877b9900eSJiri Pirko 		return err;
72977b9900eSJiri Pirko 
73077b9900eSJiri Pirko 	if (fold && handle && fold->handle != handle)
73177b9900eSJiri Pirko 		return -EINVAL;
73277b9900eSJiri Pirko 
73377b9900eSJiri Pirko 	fnew = kzalloc(sizeof(*fnew), GFP_KERNEL);
73477b9900eSJiri Pirko 	if (!fnew)
73577b9900eSJiri Pirko 		return -ENOBUFS;
73677b9900eSJiri Pirko 
737b9a24bb7SWANG Cong 	err = tcf_exts_init(&fnew->exts, TCA_FLOWER_ACT, 0);
738b9a24bb7SWANG Cong 	if (err < 0)
739b9a24bb7SWANG Cong 		goto errout;
74077b9900eSJiri Pirko 
74177b9900eSJiri Pirko 	if (!handle) {
74277b9900eSJiri Pirko 		handle = fl_grab_new_handle(tp, head);
74377b9900eSJiri Pirko 		if (!handle) {
74477b9900eSJiri Pirko 			err = -EINVAL;
74577b9900eSJiri Pirko 			goto errout;
74677b9900eSJiri Pirko 		}
74777b9900eSJiri Pirko 	}
74877b9900eSJiri Pirko 	fnew->handle = handle;
74977b9900eSJiri Pirko 
750e69985c6SAmir Vadai 	if (tb[TCA_FLOWER_FLAGS]) {
751e69985c6SAmir Vadai 		fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
752e69985c6SAmir Vadai 
753e69985c6SAmir Vadai 		if (!tc_flags_valid(fnew->flags)) {
754e69985c6SAmir Vadai 			err = -EINVAL;
755e69985c6SAmir Vadai 			goto errout;
756e69985c6SAmir Vadai 		}
757e69985c6SAmir Vadai 	}
7585b33f488SAmir Vadai 
75977b9900eSJiri Pirko 	err = fl_set_parms(net, tp, fnew, &mask, base, tb, tca[TCA_RATE], ovr);
76077b9900eSJiri Pirko 	if (err)
76177b9900eSJiri Pirko 		goto errout;
76277b9900eSJiri Pirko 
76377b9900eSJiri Pirko 	err = fl_check_assign_mask(head, &mask);
76477b9900eSJiri Pirko 	if (err)
76577b9900eSJiri Pirko 		goto errout;
76677b9900eSJiri Pirko 
767e8eb36cdSAmir Vadai 	if (!tc_skip_sw(fnew->flags)) {
76877b9900eSJiri Pirko 		err = rhashtable_insert_fast(&head->ht, &fnew->ht_node,
76977b9900eSJiri Pirko 					     head->ht_params);
77077b9900eSJiri Pirko 		if (err)
77177b9900eSJiri Pirko 			goto errout;
772e69985c6SAmir Vadai 	}
7735b33f488SAmir Vadai 
77479685219SHadar Hen Zion 	if (!tc_skip_hw(fnew->flags)) {
775e8eb36cdSAmir Vadai 		err = fl_hw_replace_filter(tp,
7765b33f488SAmir Vadai 					   &head->dissector,
7775b33f488SAmir Vadai 					   &mask.key,
7783036dab6SHadar Hen Zion 					   fnew);
779e8eb36cdSAmir Vadai 		if (err)
780e8eb36cdSAmir Vadai 			goto errout;
78179685219SHadar Hen Zion 	}
7825b33f488SAmir Vadai 
7835b33f488SAmir Vadai 	if (fold) {
784725cbb62SJiri Pirko 		if (!tc_skip_sw(fold->flags))
78577b9900eSJiri Pirko 			rhashtable_remove_fast(&head->ht, &fold->ht_node,
78677b9900eSJiri Pirko 					       head->ht_params);
78779685219SHadar Hen Zion 		if (!tc_skip_hw(fold->flags))
7883036dab6SHadar Hen Zion 			fl_hw_destroy_filter(tp, fold);
7895b33f488SAmir Vadai 	}
79077b9900eSJiri Pirko 
79177b9900eSJiri Pirko 	*arg = (unsigned long) fnew;
79277b9900eSJiri Pirko 
79377b9900eSJiri Pirko 	if (fold) {
794ff3532f2SDaniel Borkmann 		list_replace_rcu(&fold->list, &fnew->list);
79577b9900eSJiri Pirko 		tcf_unbind_filter(tp, &fold->res);
79677b9900eSJiri Pirko 		call_rcu(&fold->rcu, fl_destroy_filter);
79777b9900eSJiri Pirko 	} else {
79877b9900eSJiri Pirko 		list_add_tail_rcu(&fnew->list, &head->filters);
79977b9900eSJiri Pirko 	}
80077b9900eSJiri Pirko 
80177b9900eSJiri Pirko 	return 0;
80277b9900eSJiri Pirko 
80377b9900eSJiri Pirko errout:
804b9a24bb7SWANG Cong 	tcf_exts_destroy(&fnew->exts);
80577b9900eSJiri Pirko 	kfree(fnew);
80677b9900eSJiri Pirko 	return err;
80777b9900eSJiri Pirko }
80877b9900eSJiri Pirko 
80977b9900eSJiri Pirko static int fl_delete(struct tcf_proto *tp, unsigned long arg)
81077b9900eSJiri Pirko {
81177b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
81277b9900eSJiri Pirko 	struct cls_fl_filter *f = (struct cls_fl_filter *) arg;
81377b9900eSJiri Pirko 
814725cbb62SJiri Pirko 	if (!tc_skip_sw(f->flags))
81577b9900eSJiri Pirko 		rhashtable_remove_fast(&head->ht, &f->ht_node,
81677b9900eSJiri Pirko 				       head->ht_params);
81713fa876eSRoi Dayan 	__fl_delete(tp, f);
81877b9900eSJiri Pirko 	return 0;
81977b9900eSJiri Pirko }
82077b9900eSJiri Pirko 
82177b9900eSJiri Pirko static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg)
82277b9900eSJiri Pirko {
82377b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
82477b9900eSJiri Pirko 	struct cls_fl_filter *f;
82577b9900eSJiri Pirko 
82677b9900eSJiri Pirko 	list_for_each_entry_rcu(f, &head->filters, list) {
82777b9900eSJiri Pirko 		if (arg->count < arg->skip)
82877b9900eSJiri Pirko 			goto skip;
82977b9900eSJiri Pirko 		if (arg->fn(tp, (unsigned long) f, arg) < 0) {
83077b9900eSJiri Pirko 			arg->stop = 1;
83177b9900eSJiri Pirko 			break;
83277b9900eSJiri Pirko 		}
83377b9900eSJiri Pirko skip:
83477b9900eSJiri Pirko 		arg->count++;
83577b9900eSJiri Pirko 	}
83677b9900eSJiri Pirko }
83777b9900eSJiri Pirko 
83877b9900eSJiri Pirko static int fl_dump_key_val(struct sk_buff *skb,
83977b9900eSJiri Pirko 			   void *val, int val_type,
84077b9900eSJiri Pirko 			   void *mask, int mask_type, int len)
84177b9900eSJiri Pirko {
84277b9900eSJiri Pirko 	int err;
84377b9900eSJiri Pirko 
84477b9900eSJiri Pirko 	if (!memchr_inv(mask, 0, len))
84577b9900eSJiri Pirko 		return 0;
84677b9900eSJiri Pirko 	err = nla_put(skb, val_type, len, val);
84777b9900eSJiri Pirko 	if (err)
84877b9900eSJiri Pirko 		return err;
84977b9900eSJiri Pirko 	if (mask_type != TCA_FLOWER_UNSPEC) {
85077b9900eSJiri Pirko 		err = nla_put(skb, mask_type, len, mask);
85177b9900eSJiri Pirko 		if (err)
85277b9900eSJiri Pirko 			return err;
85377b9900eSJiri Pirko 	}
85477b9900eSJiri Pirko 	return 0;
85577b9900eSJiri Pirko }
85677b9900eSJiri Pirko 
8579399ae9aSHadar Hen Zion static int fl_dump_key_vlan(struct sk_buff *skb,
8589399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *vlan_key,
8599399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *vlan_mask)
8609399ae9aSHadar Hen Zion {
8619399ae9aSHadar Hen Zion 	int err;
8629399ae9aSHadar Hen Zion 
8639399ae9aSHadar Hen Zion 	if (!memchr_inv(vlan_mask, 0, sizeof(*vlan_mask)))
8649399ae9aSHadar Hen Zion 		return 0;
8659399ae9aSHadar Hen Zion 	if (vlan_mask->vlan_id) {
8669399ae9aSHadar Hen Zion 		err = nla_put_u16(skb, TCA_FLOWER_KEY_VLAN_ID,
8679399ae9aSHadar Hen Zion 				  vlan_key->vlan_id);
8689399ae9aSHadar Hen Zion 		if (err)
8699399ae9aSHadar Hen Zion 			return err;
8709399ae9aSHadar Hen Zion 	}
8719399ae9aSHadar Hen Zion 	if (vlan_mask->vlan_priority) {
8729399ae9aSHadar Hen Zion 		err = nla_put_u8(skb, TCA_FLOWER_KEY_VLAN_PRIO,
8739399ae9aSHadar Hen Zion 				 vlan_key->vlan_priority);
8749399ae9aSHadar Hen Zion 		if (err)
8759399ae9aSHadar Hen Zion 			return err;
8769399ae9aSHadar Hen Zion 	}
8779399ae9aSHadar Hen Zion 	return 0;
8789399ae9aSHadar Hen Zion }
8799399ae9aSHadar Hen Zion 
88077b9900eSJiri Pirko static int fl_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
88177b9900eSJiri Pirko 		   struct sk_buff *skb, struct tcmsg *t)
88277b9900eSJiri Pirko {
88377b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
88477b9900eSJiri Pirko 	struct cls_fl_filter *f = (struct cls_fl_filter *) fh;
88577b9900eSJiri Pirko 	struct nlattr *nest;
88677b9900eSJiri Pirko 	struct fl_flow_key *key, *mask;
88777b9900eSJiri Pirko 
88877b9900eSJiri Pirko 	if (!f)
88977b9900eSJiri Pirko 		return skb->len;
89077b9900eSJiri Pirko 
89177b9900eSJiri Pirko 	t->tcm_handle = f->handle;
89277b9900eSJiri Pirko 
89377b9900eSJiri Pirko 	nest = nla_nest_start(skb, TCA_OPTIONS);
89477b9900eSJiri Pirko 	if (!nest)
89577b9900eSJiri Pirko 		goto nla_put_failure;
89677b9900eSJiri Pirko 
89777b9900eSJiri Pirko 	if (f->res.classid &&
89877b9900eSJiri Pirko 	    nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid))
89977b9900eSJiri Pirko 		goto nla_put_failure;
90077b9900eSJiri Pirko 
90177b9900eSJiri Pirko 	key = &f->key;
90277b9900eSJiri Pirko 	mask = &head->mask.key;
90377b9900eSJiri Pirko 
90477b9900eSJiri Pirko 	if (mask->indev_ifindex) {
90577b9900eSJiri Pirko 		struct net_device *dev;
90677b9900eSJiri Pirko 
90777b9900eSJiri Pirko 		dev = __dev_get_by_index(net, key->indev_ifindex);
90877b9900eSJiri Pirko 		if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name))
90977b9900eSJiri Pirko 			goto nla_put_failure;
91077b9900eSJiri Pirko 	}
91177b9900eSJiri Pirko 
91279685219SHadar Hen Zion 	if (!tc_skip_hw(f->flags))
91310cbc684SAmir Vadai 		fl_hw_update_stats(tp, f);
91410cbc684SAmir Vadai 
91577b9900eSJiri Pirko 	if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
91677b9900eSJiri Pirko 			    mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
91777b9900eSJiri Pirko 			    sizeof(key->eth.dst)) ||
91877b9900eSJiri Pirko 	    fl_dump_key_val(skb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
91977b9900eSJiri Pirko 			    mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
92077b9900eSJiri Pirko 			    sizeof(key->eth.src)) ||
92177b9900eSJiri Pirko 	    fl_dump_key_val(skb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE,
92277b9900eSJiri Pirko 			    &mask->basic.n_proto, TCA_FLOWER_UNSPEC,
92377b9900eSJiri Pirko 			    sizeof(key->basic.n_proto)))
92477b9900eSJiri Pirko 		goto nla_put_failure;
9259399ae9aSHadar Hen Zion 
9269399ae9aSHadar Hen Zion 	if (fl_dump_key_vlan(skb, &key->vlan, &mask->vlan))
9279399ae9aSHadar Hen Zion 		goto nla_put_failure;
9289399ae9aSHadar Hen Zion 
92977b9900eSJiri Pirko 	if ((key->basic.n_proto == htons(ETH_P_IP) ||
93077b9900eSJiri Pirko 	     key->basic.n_proto == htons(ETH_P_IPV6)) &&
93177b9900eSJiri Pirko 	    fl_dump_key_val(skb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
93277b9900eSJiri Pirko 			    &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
93377b9900eSJiri Pirko 			    sizeof(key->basic.ip_proto)))
93477b9900eSJiri Pirko 		goto nla_put_failure;
93577b9900eSJiri Pirko 
936c3f83241STom Herbert 	if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
93777b9900eSJiri Pirko 	    (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
93877b9900eSJiri Pirko 			     &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
93977b9900eSJiri Pirko 			     sizeof(key->ipv4.src)) ||
94077b9900eSJiri Pirko 	     fl_dump_key_val(skb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
94177b9900eSJiri Pirko 			     &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
94277b9900eSJiri Pirko 			     sizeof(key->ipv4.dst))))
94377b9900eSJiri Pirko 		goto nla_put_failure;
944c3f83241STom Herbert 	else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
94577b9900eSJiri Pirko 		 (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
94677b9900eSJiri Pirko 				  &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
94777b9900eSJiri Pirko 				  sizeof(key->ipv6.src)) ||
94877b9900eSJiri Pirko 		  fl_dump_key_val(skb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
94977b9900eSJiri Pirko 				  &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
95077b9900eSJiri Pirko 				  sizeof(key->ipv6.dst))))
95177b9900eSJiri Pirko 		goto nla_put_failure;
95277b9900eSJiri Pirko 
95377b9900eSJiri Pirko 	if (key->basic.ip_proto == IPPROTO_TCP &&
95477b9900eSJiri Pirko 	    (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
955aa72d708SOr Gerlitz 			     &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
95677b9900eSJiri Pirko 			     sizeof(key->tp.src)) ||
95777b9900eSJiri Pirko 	     fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
958aa72d708SOr Gerlitz 			     &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
95977b9900eSJiri Pirko 			     sizeof(key->tp.dst))))
96077b9900eSJiri Pirko 		goto nla_put_failure;
96177b9900eSJiri Pirko 	else if (key->basic.ip_proto == IPPROTO_UDP &&
96277b9900eSJiri Pirko 		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
963aa72d708SOr Gerlitz 				  &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
96477b9900eSJiri Pirko 				  sizeof(key->tp.src)) ||
96577b9900eSJiri Pirko 		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
966aa72d708SOr Gerlitz 				  &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
96777b9900eSJiri Pirko 				  sizeof(key->tp.dst))))
96877b9900eSJiri Pirko 		goto nla_put_failure;
9695976c5f4SSimon Horman 	else if (key->basic.ip_proto == IPPROTO_SCTP &&
9705976c5f4SSimon Horman 		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
9715976c5f4SSimon Horman 				  &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
9725976c5f4SSimon Horman 				  sizeof(key->tp.src)) ||
9735976c5f4SSimon Horman 		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
9745976c5f4SSimon Horman 				  &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
9755976c5f4SSimon Horman 				  sizeof(key->tp.dst))))
9765976c5f4SSimon Horman 		goto nla_put_failure;
97777b9900eSJiri Pirko 
978bc3103f1SAmir Vadai 	if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
979bc3103f1SAmir Vadai 	    (fl_dump_key_val(skb, &key->enc_ipv4.src,
980bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV4_SRC, &mask->enc_ipv4.src,
981bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
982bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv4.src)) ||
983bc3103f1SAmir Vadai 	     fl_dump_key_val(skb, &key->enc_ipv4.dst,
984bc3103f1SAmir Vadai 			     TCA_FLOWER_KEY_ENC_IPV4_DST, &mask->enc_ipv4.dst,
985bc3103f1SAmir Vadai 			     TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
986bc3103f1SAmir Vadai 			     sizeof(key->enc_ipv4.dst))))
987bc3103f1SAmir Vadai 		goto nla_put_failure;
988bc3103f1SAmir Vadai 	else if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
989bc3103f1SAmir Vadai 		 (fl_dump_key_val(skb, &key->enc_ipv6.src,
990bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV6_SRC, &mask->enc_ipv6.src,
991bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
992bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv6.src)) ||
993bc3103f1SAmir Vadai 		 fl_dump_key_val(skb, &key->enc_ipv6.dst,
994bc3103f1SAmir Vadai 				 TCA_FLOWER_KEY_ENC_IPV6_DST,
995bc3103f1SAmir Vadai 				 &mask->enc_ipv6.dst,
996bc3103f1SAmir Vadai 				 TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
997bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv6.dst))))
998bc3103f1SAmir Vadai 		goto nla_put_failure;
999bc3103f1SAmir Vadai 
1000bc3103f1SAmir Vadai 	if (fl_dump_key_val(skb, &key->enc_key_id, TCA_FLOWER_KEY_ENC_KEY_ID,
1001eb523f42SHadar Hen Zion 			    &mask->enc_key_id, TCA_FLOWER_UNSPEC,
1002f4d997fdSHadar Hen Zion 			    sizeof(key->enc_key_id)) ||
1003f4d997fdSHadar Hen Zion 	    fl_dump_key_val(skb, &key->enc_tp.src,
1004f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
1005f4d997fdSHadar Hen Zion 			    &mask->enc_tp.src,
1006f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
1007f4d997fdSHadar Hen Zion 			    sizeof(key->enc_tp.src)) ||
1008f4d997fdSHadar Hen Zion 	    fl_dump_key_val(skb, &key->enc_tp.dst,
1009f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
1010f4d997fdSHadar Hen Zion 			    &mask->enc_tp.dst,
1011f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
1012f4d997fdSHadar Hen Zion 			    sizeof(key->enc_tp.dst)))
1013bc3103f1SAmir Vadai 		goto nla_put_failure;
1014bc3103f1SAmir Vadai 
1015e69985c6SAmir Vadai 	nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags);
1016e69985c6SAmir Vadai 
101777b9900eSJiri Pirko 	if (tcf_exts_dump(skb, &f->exts))
101877b9900eSJiri Pirko 		goto nla_put_failure;
101977b9900eSJiri Pirko 
102077b9900eSJiri Pirko 	nla_nest_end(skb, nest);
102177b9900eSJiri Pirko 
102277b9900eSJiri Pirko 	if (tcf_exts_dump_stats(skb, &f->exts) < 0)
102377b9900eSJiri Pirko 		goto nla_put_failure;
102477b9900eSJiri Pirko 
102577b9900eSJiri Pirko 	return skb->len;
102677b9900eSJiri Pirko 
102777b9900eSJiri Pirko nla_put_failure:
102877b9900eSJiri Pirko 	nla_nest_cancel(skb, nest);
102977b9900eSJiri Pirko 	return -1;
103077b9900eSJiri Pirko }
103177b9900eSJiri Pirko 
103277b9900eSJiri Pirko static struct tcf_proto_ops cls_fl_ops __read_mostly = {
103377b9900eSJiri Pirko 	.kind		= "flower",
103477b9900eSJiri Pirko 	.classify	= fl_classify,
103577b9900eSJiri Pirko 	.init		= fl_init,
103677b9900eSJiri Pirko 	.destroy	= fl_destroy,
103777b9900eSJiri Pirko 	.get		= fl_get,
103877b9900eSJiri Pirko 	.change		= fl_change,
103977b9900eSJiri Pirko 	.delete		= fl_delete,
104077b9900eSJiri Pirko 	.walk		= fl_walk,
104177b9900eSJiri Pirko 	.dump		= fl_dump,
104277b9900eSJiri Pirko 	.owner		= THIS_MODULE,
104377b9900eSJiri Pirko };
104477b9900eSJiri Pirko 
104577b9900eSJiri Pirko static int __init cls_fl_init(void)
104677b9900eSJiri Pirko {
104777b9900eSJiri Pirko 	return register_tcf_proto_ops(&cls_fl_ops);
104877b9900eSJiri Pirko }
104977b9900eSJiri Pirko 
105077b9900eSJiri Pirko static void __exit cls_fl_exit(void)
105177b9900eSJiri Pirko {
105277b9900eSJiri Pirko 	unregister_tcf_proto_ops(&cls_fl_ops);
105377b9900eSJiri Pirko }
105477b9900eSJiri Pirko 
105577b9900eSJiri Pirko module_init(cls_fl_init);
105677b9900eSJiri Pirko module_exit(cls_fl_exit);
105777b9900eSJiri Pirko 
105877b9900eSJiri Pirko MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>");
105977b9900eSJiri Pirko MODULE_DESCRIPTION("Flower classifier");
106077b9900eSJiri Pirko MODULE_LICENSE("GPL v2");
1061