xref: /linux/net/sched/cls_flower.c (revision f4d997fd613001e612543339e0275c037f94ffe9)
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>
1677b9900eSJiri Pirko 
1777b9900eSJiri Pirko #include <linux/if_ether.h>
1877b9900eSJiri Pirko #include <linux/in6.h>
1977b9900eSJiri Pirko #include <linux/ip.h>
2077b9900eSJiri Pirko 
2177b9900eSJiri Pirko #include <net/sch_generic.h>
2277b9900eSJiri Pirko #include <net/pkt_cls.h>
2377b9900eSJiri Pirko #include <net/ip.h>
2477b9900eSJiri Pirko #include <net/flow_dissector.h>
2577b9900eSJiri Pirko 
26bc3103f1SAmir Vadai #include <net/dst.h>
27bc3103f1SAmir Vadai #include <net/dst_metadata.h>
28bc3103f1SAmir Vadai 
2977b9900eSJiri Pirko struct fl_flow_key {
3077b9900eSJiri Pirko 	int	indev_ifindex;
3142aecaa9STom Herbert 	struct flow_dissector_key_control control;
32bc3103f1SAmir Vadai 	struct flow_dissector_key_control enc_control;
3377b9900eSJiri Pirko 	struct flow_dissector_key_basic basic;
3477b9900eSJiri Pirko 	struct flow_dissector_key_eth_addrs eth;
359399ae9aSHadar Hen Zion 	struct flow_dissector_key_vlan vlan;
3677b9900eSJiri Pirko 	union {
37c3f83241STom Herbert 		struct flow_dissector_key_ipv4_addrs ipv4;
3877b9900eSJiri Pirko 		struct flow_dissector_key_ipv6_addrs ipv6;
3977b9900eSJiri Pirko 	};
4077b9900eSJiri Pirko 	struct flow_dissector_key_ports tp;
41bc3103f1SAmir Vadai 	struct flow_dissector_key_keyid enc_key_id;
42bc3103f1SAmir Vadai 	union {
43bc3103f1SAmir Vadai 		struct flow_dissector_key_ipv4_addrs enc_ipv4;
44bc3103f1SAmir Vadai 		struct flow_dissector_key_ipv6_addrs enc_ipv6;
45bc3103f1SAmir Vadai 	};
46*f4d997fdSHadar Hen Zion 	struct flow_dissector_key_ports enc_tp;
4777b9900eSJiri Pirko } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
4877b9900eSJiri Pirko 
4977b9900eSJiri Pirko struct fl_flow_mask_range {
5077b9900eSJiri Pirko 	unsigned short int start;
5177b9900eSJiri Pirko 	unsigned short int end;
5277b9900eSJiri Pirko };
5377b9900eSJiri Pirko 
5477b9900eSJiri Pirko struct fl_flow_mask {
5577b9900eSJiri Pirko 	struct fl_flow_key key;
5677b9900eSJiri Pirko 	struct fl_flow_mask_range range;
5777b9900eSJiri Pirko 	struct rcu_head	rcu;
5877b9900eSJiri Pirko };
5977b9900eSJiri Pirko 
6077b9900eSJiri Pirko struct cls_fl_head {
6177b9900eSJiri Pirko 	struct rhashtable ht;
6277b9900eSJiri Pirko 	struct fl_flow_mask mask;
6377b9900eSJiri Pirko 	struct flow_dissector dissector;
6477b9900eSJiri Pirko 	u32 hgen;
6577b9900eSJiri Pirko 	bool mask_assigned;
6677b9900eSJiri Pirko 	struct list_head filters;
6777b9900eSJiri Pirko 	struct rhashtable_params ht_params;
6877b9900eSJiri Pirko 	struct rcu_head rcu;
6977b9900eSJiri Pirko };
7077b9900eSJiri Pirko 
7177b9900eSJiri Pirko struct cls_fl_filter {
7277b9900eSJiri Pirko 	struct rhash_head ht_node;
7377b9900eSJiri Pirko 	struct fl_flow_key mkey;
7477b9900eSJiri Pirko 	struct tcf_exts exts;
7577b9900eSJiri Pirko 	struct tcf_result res;
7677b9900eSJiri Pirko 	struct fl_flow_key key;
7777b9900eSJiri Pirko 	struct list_head list;
7877b9900eSJiri Pirko 	u32 handle;
79e69985c6SAmir Vadai 	u32 flags;
8077b9900eSJiri Pirko 	struct rcu_head	rcu;
8177b9900eSJiri Pirko };
8277b9900eSJiri Pirko 
8377b9900eSJiri Pirko static unsigned short int fl_mask_range(const struct fl_flow_mask *mask)
8477b9900eSJiri Pirko {
8577b9900eSJiri Pirko 	return mask->range.end - mask->range.start;
8677b9900eSJiri Pirko }
8777b9900eSJiri Pirko 
8877b9900eSJiri Pirko static void fl_mask_update_range(struct fl_flow_mask *mask)
8977b9900eSJiri Pirko {
9077b9900eSJiri Pirko 	const u8 *bytes = (const u8 *) &mask->key;
9177b9900eSJiri Pirko 	size_t size = sizeof(mask->key);
9277b9900eSJiri Pirko 	size_t i, first = 0, last = size - 1;
9377b9900eSJiri Pirko 
9477b9900eSJiri Pirko 	for (i = 0; i < sizeof(mask->key); i++) {
9577b9900eSJiri Pirko 		if (bytes[i]) {
9677b9900eSJiri Pirko 			if (!first && i)
9777b9900eSJiri Pirko 				first = i;
9877b9900eSJiri Pirko 			last = i;
9977b9900eSJiri Pirko 		}
10077b9900eSJiri Pirko 	}
10177b9900eSJiri Pirko 	mask->range.start = rounddown(first, sizeof(long));
10277b9900eSJiri Pirko 	mask->range.end = roundup(last + 1, sizeof(long));
10377b9900eSJiri Pirko }
10477b9900eSJiri Pirko 
10577b9900eSJiri Pirko static void *fl_key_get_start(struct fl_flow_key *key,
10677b9900eSJiri Pirko 			      const struct fl_flow_mask *mask)
10777b9900eSJiri Pirko {
10877b9900eSJiri Pirko 	return (u8 *) key + mask->range.start;
10977b9900eSJiri Pirko }
11077b9900eSJiri Pirko 
11177b9900eSJiri Pirko static void fl_set_masked_key(struct fl_flow_key *mkey, struct fl_flow_key *key,
11277b9900eSJiri Pirko 			      struct fl_flow_mask *mask)
11377b9900eSJiri Pirko {
11477b9900eSJiri Pirko 	const long *lkey = fl_key_get_start(key, mask);
11577b9900eSJiri Pirko 	const long *lmask = fl_key_get_start(&mask->key, mask);
11677b9900eSJiri Pirko 	long *lmkey = fl_key_get_start(mkey, mask);
11777b9900eSJiri Pirko 	int i;
11877b9900eSJiri Pirko 
11977b9900eSJiri Pirko 	for (i = 0; i < fl_mask_range(mask); i += sizeof(long))
12077b9900eSJiri Pirko 		*lmkey++ = *lkey++ & *lmask++;
12177b9900eSJiri Pirko }
12277b9900eSJiri Pirko 
12377b9900eSJiri Pirko static void fl_clear_masked_range(struct fl_flow_key *key,
12477b9900eSJiri Pirko 				  struct fl_flow_mask *mask)
12577b9900eSJiri Pirko {
12677b9900eSJiri Pirko 	memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask));
12777b9900eSJiri Pirko }
12877b9900eSJiri Pirko 
12977b9900eSJiri Pirko static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp,
13077b9900eSJiri Pirko 		       struct tcf_result *res)
13177b9900eSJiri Pirko {
13277b9900eSJiri Pirko 	struct cls_fl_head *head = rcu_dereference_bh(tp->root);
13377b9900eSJiri Pirko 	struct cls_fl_filter *f;
13477b9900eSJiri Pirko 	struct fl_flow_key skb_key;
13577b9900eSJiri Pirko 	struct fl_flow_key skb_mkey;
136bc3103f1SAmir Vadai 	struct ip_tunnel_info *info;
13777b9900eSJiri Pirko 
138e69985c6SAmir Vadai 	if (!atomic_read(&head->ht.nelems))
139e69985c6SAmir Vadai 		return -1;
140e69985c6SAmir Vadai 
14177b9900eSJiri Pirko 	fl_clear_masked_range(&skb_key, &head->mask);
142bc3103f1SAmir Vadai 
143bc3103f1SAmir Vadai 	info = skb_tunnel_info(skb);
144bc3103f1SAmir Vadai 	if (info) {
145bc3103f1SAmir Vadai 		struct ip_tunnel_key *key = &info->key;
146bc3103f1SAmir Vadai 
147bc3103f1SAmir Vadai 		switch (ip_tunnel_info_af(info)) {
148bc3103f1SAmir Vadai 		case AF_INET:
149bc3103f1SAmir Vadai 			skb_key.enc_ipv4.src = key->u.ipv4.src;
150bc3103f1SAmir Vadai 			skb_key.enc_ipv4.dst = key->u.ipv4.dst;
151bc3103f1SAmir Vadai 			break;
152bc3103f1SAmir Vadai 		case AF_INET6:
153bc3103f1SAmir Vadai 			skb_key.enc_ipv6.src = key->u.ipv6.src;
154bc3103f1SAmir Vadai 			skb_key.enc_ipv6.dst = key->u.ipv6.dst;
155bc3103f1SAmir Vadai 			break;
156bc3103f1SAmir Vadai 		}
157bc3103f1SAmir Vadai 
158bc3103f1SAmir Vadai 		skb_key.enc_key_id.keyid = tunnel_id_to_key32(key->tun_id);
159*f4d997fdSHadar Hen Zion 		skb_key.enc_tp.src = key->tp_src;
160*f4d997fdSHadar Hen Zion 		skb_key.enc_tp.dst = key->tp_dst;
161bc3103f1SAmir Vadai 	}
162bc3103f1SAmir Vadai 
16377b9900eSJiri Pirko 	skb_key.indev_ifindex = skb->skb_iif;
16477b9900eSJiri Pirko 	/* skb_flow_dissect() does not set n_proto in case an unknown protocol,
16577b9900eSJiri Pirko 	 * so do it rather here.
16677b9900eSJiri Pirko 	 */
16777b9900eSJiri Pirko 	skb_key.basic.n_proto = skb->protocol;
168cd79a238STom Herbert 	skb_flow_dissect(skb, &head->dissector, &skb_key, 0);
16977b9900eSJiri Pirko 
17077b9900eSJiri Pirko 	fl_set_masked_key(&skb_mkey, &skb_key, &head->mask);
17177b9900eSJiri Pirko 
17277b9900eSJiri Pirko 	f = rhashtable_lookup_fast(&head->ht,
17377b9900eSJiri Pirko 				   fl_key_get_start(&skb_mkey, &head->mask),
17477b9900eSJiri Pirko 				   head->ht_params);
175e8eb36cdSAmir Vadai 	if (f && !tc_skip_sw(f->flags)) {
17677b9900eSJiri Pirko 		*res = f->res;
17777b9900eSJiri Pirko 		return tcf_exts_exec(skb, &f->exts, res);
17877b9900eSJiri Pirko 	}
17977b9900eSJiri Pirko 	return -1;
18077b9900eSJiri Pirko }
18177b9900eSJiri Pirko 
18277b9900eSJiri Pirko static int fl_init(struct tcf_proto *tp)
18377b9900eSJiri Pirko {
18477b9900eSJiri Pirko 	struct cls_fl_head *head;
18577b9900eSJiri Pirko 
18677b9900eSJiri Pirko 	head = kzalloc(sizeof(*head), GFP_KERNEL);
18777b9900eSJiri Pirko 	if (!head)
18877b9900eSJiri Pirko 		return -ENOBUFS;
18977b9900eSJiri Pirko 
19077b9900eSJiri Pirko 	INIT_LIST_HEAD_RCU(&head->filters);
19177b9900eSJiri Pirko 	rcu_assign_pointer(tp->root, head);
19277b9900eSJiri Pirko 
19377b9900eSJiri Pirko 	return 0;
19477b9900eSJiri Pirko }
19577b9900eSJiri Pirko 
19677b9900eSJiri Pirko static void fl_destroy_filter(struct rcu_head *head)
19777b9900eSJiri Pirko {
19877b9900eSJiri Pirko 	struct cls_fl_filter *f = container_of(head, struct cls_fl_filter, rcu);
19977b9900eSJiri Pirko 
20077b9900eSJiri Pirko 	tcf_exts_destroy(&f->exts);
20177b9900eSJiri Pirko 	kfree(f);
20277b9900eSJiri Pirko }
20377b9900eSJiri Pirko 
2048208d21bSAmir Vadai static void fl_hw_destroy_filter(struct tcf_proto *tp, unsigned long cookie)
2055b33f488SAmir Vadai {
2065b33f488SAmir Vadai 	struct net_device *dev = tp->q->dev_queue->dev;
2075b33f488SAmir Vadai 	struct tc_cls_flower_offload offload = {0};
2085b33f488SAmir Vadai 	struct tc_to_netdev tc;
2095b33f488SAmir Vadai 
21092c075dbSDaniel Borkmann 	if (!tc_should_offload(dev, tp, 0))
2115b33f488SAmir Vadai 		return;
2125b33f488SAmir Vadai 
2135b33f488SAmir Vadai 	offload.command = TC_CLSFLOWER_DESTROY;
2145b33f488SAmir Vadai 	offload.cookie = cookie;
2155b33f488SAmir Vadai 
2165b33f488SAmir Vadai 	tc.type = TC_SETUP_CLSFLOWER;
2175b33f488SAmir Vadai 	tc.cls_flower = &offload;
2185b33f488SAmir Vadai 
2195b33f488SAmir Vadai 	dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, &tc);
2205b33f488SAmir Vadai }
2215b33f488SAmir Vadai 
222e8eb36cdSAmir Vadai static int fl_hw_replace_filter(struct tcf_proto *tp,
2235b33f488SAmir Vadai 				struct flow_dissector *dissector,
2245b33f488SAmir Vadai 				struct fl_flow_key *mask,
2255b33f488SAmir Vadai 				struct fl_flow_key *key,
2265b33f488SAmir Vadai 				struct tcf_exts *actions,
2278208d21bSAmir Vadai 				unsigned long cookie, u32 flags)
2285b33f488SAmir Vadai {
2295b33f488SAmir Vadai 	struct net_device *dev = tp->q->dev_queue->dev;
2305b33f488SAmir Vadai 	struct tc_cls_flower_offload offload = {0};
2315b33f488SAmir Vadai 	struct tc_to_netdev tc;
232e8eb36cdSAmir Vadai 	int err;
2335b33f488SAmir Vadai 
23492c075dbSDaniel Borkmann 	if (!tc_should_offload(dev, tp, flags))
235e8eb36cdSAmir Vadai 		return tc_skip_sw(flags) ? -EINVAL : 0;
2365b33f488SAmir Vadai 
2375b33f488SAmir Vadai 	offload.command = TC_CLSFLOWER_REPLACE;
2385b33f488SAmir Vadai 	offload.cookie = cookie;
2395b33f488SAmir Vadai 	offload.dissector = dissector;
2405b33f488SAmir Vadai 	offload.mask = mask;
2415b33f488SAmir Vadai 	offload.key = key;
2425b33f488SAmir Vadai 	offload.exts = actions;
2435b33f488SAmir Vadai 
2445b33f488SAmir Vadai 	tc.type = TC_SETUP_CLSFLOWER;
2455b33f488SAmir Vadai 	tc.cls_flower = &offload;
2465b33f488SAmir Vadai 
2475a7a5555SJamal Hadi Salim 	err = dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol,
2485a7a5555SJamal Hadi Salim 					    &tc);
249e8eb36cdSAmir Vadai 
250e8eb36cdSAmir Vadai 	if (tc_skip_sw(flags))
251e8eb36cdSAmir Vadai 		return err;
252e8eb36cdSAmir Vadai 
253e8eb36cdSAmir Vadai 	return 0;
2545b33f488SAmir Vadai }
2555b33f488SAmir Vadai 
25610cbc684SAmir Vadai static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
25710cbc684SAmir Vadai {
25810cbc684SAmir Vadai 	struct net_device *dev = tp->q->dev_queue->dev;
25910cbc684SAmir Vadai 	struct tc_cls_flower_offload offload = {0};
26010cbc684SAmir Vadai 	struct tc_to_netdev tc;
26110cbc684SAmir Vadai 
26292c075dbSDaniel Borkmann 	if (!tc_should_offload(dev, tp, 0))
26310cbc684SAmir Vadai 		return;
26410cbc684SAmir Vadai 
26510cbc684SAmir Vadai 	offload.command = TC_CLSFLOWER_STATS;
26610cbc684SAmir Vadai 	offload.cookie = (unsigned long)f;
26710cbc684SAmir Vadai 	offload.exts = &f->exts;
26810cbc684SAmir Vadai 
26910cbc684SAmir Vadai 	tc.type = TC_SETUP_CLSFLOWER;
27010cbc684SAmir Vadai 	tc.cls_flower = &offload;
27110cbc684SAmir Vadai 
27210cbc684SAmir Vadai 	dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, &tc);
27310cbc684SAmir Vadai }
27410cbc684SAmir Vadai 
27513fa876eSRoi Dayan static void __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f)
27613fa876eSRoi Dayan {
27713fa876eSRoi Dayan 	list_del_rcu(&f->list);
27813fa876eSRoi Dayan 	fl_hw_destroy_filter(tp, (unsigned long)f);
27913fa876eSRoi Dayan 	tcf_unbind_filter(tp, &f->res);
28013fa876eSRoi Dayan 	call_rcu(&f->rcu, fl_destroy_filter);
28113fa876eSRoi Dayan }
28213fa876eSRoi Dayan 
28377b9900eSJiri Pirko static bool fl_destroy(struct tcf_proto *tp, bool force)
28477b9900eSJiri Pirko {
28577b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
28677b9900eSJiri Pirko 	struct cls_fl_filter *f, *next;
28777b9900eSJiri Pirko 
28877b9900eSJiri Pirko 	if (!force && !list_empty(&head->filters))
28977b9900eSJiri Pirko 		return false;
29077b9900eSJiri Pirko 
29113fa876eSRoi Dayan 	list_for_each_entry_safe(f, next, &head->filters, list)
29213fa876eSRoi Dayan 		__fl_delete(tp, f);
29377b9900eSJiri Pirko 	RCU_INIT_POINTER(tp->root, NULL);
29477b9900eSJiri Pirko 	if (head->mask_assigned)
29577b9900eSJiri Pirko 		rhashtable_destroy(&head->ht);
29677b9900eSJiri Pirko 	kfree_rcu(head, rcu);
29777b9900eSJiri Pirko 	return true;
29877b9900eSJiri Pirko }
29977b9900eSJiri Pirko 
30077b9900eSJiri Pirko static unsigned long fl_get(struct tcf_proto *tp, u32 handle)
30177b9900eSJiri Pirko {
30277b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
30377b9900eSJiri Pirko 	struct cls_fl_filter *f;
30477b9900eSJiri Pirko 
30577b9900eSJiri Pirko 	list_for_each_entry(f, &head->filters, list)
30677b9900eSJiri Pirko 		if (f->handle == handle)
30777b9900eSJiri Pirko 			return (unsigned long) f;
30877b9900eSJiri Pirko 	return 0;
30977b9900eSJiri Pirko }
31077b9900eSJiri Pirko 
31177b9900eSJiri Pirko static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
31277b9900eSJiri Pirko 	[TCA_FLOWER_UNSPEC]		= { .type = NLA_UNSPEC },
31377b9900eSJiri Pirko 	[TCA_FLOWER_CLASSID]		= { .type = NLA_U32 },
31477b9900eSJiri Pirko 	[TCA_FLOWER_INDEV]		= { .type = NLA_STRING,
31577b9900eSJiri Pirko 					    .len = IFNAMSIZ },
31677b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_DST]	= { .len = ETH_ALEN },
31777b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_DST_MASK]	= { .len = ETH_ALEN },
31877b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_SRC]	= { .len = ETH_ALEN },
31977b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_SRC_MASK]	= { .len = ETH_ALEN },
32077b9900eSJiri Pirko 	[TCA_FLOWER_KEY_ETH_TYPE]	= { .type = NLA_U16 },
32177b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IP_PROTO]	= { .type = NLA_U8 },
32277b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_SRC]	= { .type = NLA_U32 },
32377b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_SRC_MASK]	= { .type = NLA_U32 },
32477b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_DST]	= { .type = NLA_U32 },
32577b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV4_DST_MASK]	= { .type = NLA_U32 },
32677b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
32777b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_SRC_MASK]	= { .len = sizeof(struct in6_addr) },
32877b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
32977b9900eSJiri Pirko 	[TCA_FLOWER_KEY_IPV6_DST_MASK]	= { .len = sizeof(struct in6_addr) },
33077b9900eSJiri Pirko 	[TCA_FLOWER_KEY_TCP_SRC]	= { .type = NLA_U16 },
33177b9900eSJiri Pirko 	[TCA_FLOWER_KEY_TCP_DST]	= { .type = NLA_U16 },
332b175c3a4SJamal Hadi Salim 	[TCA_FLOWER_KEY_UDP_SRC]	= { .type = NLA_U16 },
333b175c3a4SJamal Hadi Salim 	[TCA_FLOWER_KEY_UDP_DST]	= { .type = NLA_U16 },
3349399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_ID]	= { .type = NLA_U16 },
3359399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_PRIO]	= { .type = NLA_U8 },
3369399ae9aSHadar Hen Zion 	[TCA_FLOWER_KEY_VLAN_ETH_TYPE]	= { .type = NLA_U16 },
337bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_KEY_ID]	= { .type = NLA_U32 },
338bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_SRC]	= { .type = NLA_U32 },
339bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] = { .type = NLA_U32 },
340bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_DST]	= { .type = NLA_U32 },
341bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] = { .type = NLA_U32 },
342bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_SRC]	= { .len = sizeof(struct in6_addr) },
343bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK] = { .len = sizeof(struct in6_addr) },
344bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_DST]	= { .len = sizeof(struct in6_addr) },
345bc3103f1SAmir Vadai 	[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK] = { .len = sizeof(struct in6_addr) },
346aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_TCP_SRC_MASK]	= { .type = NLA_U16 },
347aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_TCP_DST_MASK]	= { .type = NLA_U16 },
348aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_UDP_SRC_MASK]	= { .type = NLA_U16 },
349aa72d708SOr Gerlitz 	[TCA_FLOWER_KEY_UDP_DST_MASK]	= { .type = NLA_U16 },
3505976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_SRC_MASK]	= { .type = NLA_U16 },
3515976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_DST_MASK]	= { .type = NLA_U16 },
3525976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_SRC]	= { .type = NLA_U16 },
3535976c5f4SSimon Horman 	[TCA_FLOWER_KEY_SCTP_DST]	= { .type = NLA_U16 },
354*f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT]	= { .type = NLA_U16 },
355*f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK]	= { .type = NLA_U16 },
356*f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]	= { .type = NLA_U16 },
357*f4d997fdSHadar Hen Zion 	[TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK]	= { .type = NLA_U16 },
35877b9900eSJiri Pirko };
35977b9900eSJiri Pirko 
36077b9900eSJiri Pirko static void fl_set_key_val(struct nlattr **tb,
36177b9900eSJiri Pirko 			   void *val, int val_type,
36277b9900eSJiri Pirko 			   void *mask, int mask_type, int len)
36377b9900eSJiri Pirko {
36477b9900eSJiri Pirko 	if (!tb[val_type])
36577b9900eSJiri Pirko 		return;
36677b9900eSJiri Pirko 	memcpy(val, nla_data(tb[val_type]), len);
36777b9900eSJiri Pirko 	if (mask_type == TCA_FLOWER_UNSPEC || !tb[mask_type])
36877b9900eSJiri Pirko 		memset(mask, 0xff, len);
36977b9900eSJiri Pirko 	else
37077b9900eSJiri Pirko 		memcpy(mask, nla_data(tb[mask_type]), len);
37177b9900eSJiri Pirko }
37277b9900eSJiri Pirko 
3739399ae9aSHadar Hen Zion static void fl_set_key_vlan(struct nlattr **tb,
3749399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *key_val,
3759399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *key_mask)
3769399ae9aSHadar Hen Zion {
3779399ae9aSHadar Hen Zion #define VLAN_PRIORITY_MASK	0x7
3789399ae9aSHadar Hen Zion 
3799399ae9aSHadar Hen Zion 	if (tb[TCA_FLOWER_KEY_VLAN_ID]) {
3809399ae9aSHadar Hen Zion 		key_val->vlan_id =
3819399ae9aSHadar Hen Zion 			nla_get_u16(tb[TCA_FLOWER_KEY_VLAN_ID]) & VLAN_VID_MASK;
3829399ae9aSHadar Hen Zion 		key_mask->vlan_id = VLAN_VID_MASK;
3839399ae9aSHadar Hen Zion 	}
3849399ae9aSHadar Hen Zion 	if (tb[TCA_FLOWER_KEY_VLAN_PRIO]) {
3859399ae9aSHadar Hen Zion 		key_val->vlan_priority =
3869399ae9aSHadar Hen Zion 			nla_get_u8(tb[TCA_FLOWER_KEY_VLAN_PRIO]) &
3879399ae9aSHadar Hen Zion 			VLAN_PRIORITY_MASK;
3889399ae9aSHadar Hen Zion 		key_mask->vlan_priority = VLAN_PRIORITY_MASK;
3899399ae9aSHadar Hen Zion 	}
3909399ae9aSHadar Hen Zion }
3919399ae9aSHadar Hen Zion 
39277b9900eSJiri Pirko static int fl_set_key(struct net *net, struct nlattr **tb,
39377b9900eSJiri Pirko 		      struct fl_flow_key *key, struct fl_flow_key *mask)
39477b9900eSJiri Pirko {
3959399ae9aSHadar Hen Zion 	__be16 ethertype;
396dd3aa3b5SBrian Haley #ifdef CONFIG_NET_CLS_IND
39777b9900eSJiri Pirko 	if (tb[TCA_FLOWER_INDEV]) {
398dd3aa3b5SBrian Haley 		int err = tcf_change_indev(net, tb[TCA_FLOWER_INDEV]);
39977b9900eSJiri Pirko 		if (err < 0)
40077b9900eSJiri Pirko 			return err;
40177b9900eSJiri Pirko 		key->indev_ifindex = err;
40277b9900eSJiri Pirko 		mask->indev_ifindex = 0xffffffff;
40377b9900eSJiri Pirko 	}
404dd3aa3b5SBrian Haley #endif
40577b9900eSJiri Pirko 
40677b9900eSJiri Pirko 	fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
40777b9900eSJiri Pirko 		       mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
40877b9900eSJiri Pirko 		       sizeof(key->eth.dst));
40977b9900eSJiri Pirko 	fl_set_key_val(tb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
41077b9900eSJiri Pirko 		       mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
41177b9900eSJiri Pirko 		       sizeof(key->eth.src));
41266530bdfSJamal Hadi Salim 
4130b498a52SArnd Bergmann 	if (tb[TCA_FLOWER_KEY_ETH_TYPE]) {
4149399ae9aSHadar Hen Zion 		ethertype = nla_get_be16(tb[TCA_FLOWER_KEY_ETH_TYPE]);
4159399ae9aSHadar Hen Zion 
4169399ae9aSHadar Hen Zion 		if (ethertype == htons(ETH_P_8021Q)) {
4179399ae9aSHadar Hen Zion 			fl_set_key_vlan(tb, &key->vlan, &mask->vlan);
4189399ae9aSHadar Hen Zion 			fl_set_key_val(tb, &key->basic.n_proto,
4199399ae9aSHadar Hen Zion 				       TCA_FLOWER_KEY_VLAN_ETH_TYPE,
42077b9900eSJiri Pirko 				       &mask->basic.n_proto, TCA_FLOWER_UNSPEC,
42177b9900eSJiri Pirko 				       sizeof(key->basic.n_proto));
4229399ae9aSHadar Hen Zion 		} else {
4239399ae9aSHadar Hen Zion 			key->basic.n_proto = ethertype;
4249399ae9aSHadar Hen Zion 			mask->basic.n_proto = cpu_to_be16(~0);
4259399ae9aSHadar Hen Zion 		}
4260b498a52SArnd Bergmann 	}
42766530bdfSJamal Hadi Salim 
42877b9900eSJiri Pirko 	if (key->basic.n_proto == htons(ETH_P_IP) ||
42977b9900eSJiri Pirko 	    key->basic.n_proto == htons(ETH_P_IPV6)) {
43077b9900eSJiri Pirko 		fl_set_key_val(tb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
43177b9900eSJiri Pirko 			       &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
43277b9900eSJiri Pirko 			       sizeof(key->basic.ip_proto));
43377b9900eSJiri Pirko 	}
43466530bdfSJamal Hadi Salim 
43566530bdfSJamal Hadi Salim 	if (tb[TCA_FLOWER_KEY_IPV4_SRC] || tb[TCA_FLOWER_KEY_IPV4_DST]) {
43666530bdfSJamal Hadi Salim 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
43777b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
43877b9900eSJiri Pirko 			       &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
43977b9900eSJiri Pirko 			       sizeof(key->ipv4.src));
44077b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
44177b9900eSJiri Pirko 			       &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
44277b9900eSJiri Pirko 			       sizeof(key->ipv4.dst));
44366530bdfSJamal Hadi Salim 	} else if (tb[TCA_FLOWER_KEY_IPV6_SRC] || tb[TCA_FLOWER_KEY_IPV6_DST]) {
44466530bdfSJamal Hadi Salim 		key->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
44577b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
44677b9900eSJiri Pirko 			       &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
44777b9900eSJiri Pirko 			       sizeof(key->ipv6.src));
44877b9900eSJiri Pirko 		fl_set_key_val(tb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
44977b9900eSJiri Pirko 			       &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
45077b9900eSJiri Pirko 			       sizeof(key->ipv6.dst));
45177b9900eSJiri Pirko 	}
45266530bdfSJamal Hadi Salim 
45377b9900eSJiri Pirko 	if (key->basic.ip_proto == IPPROTO_TCP) {
45477b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
455aa72d708SOr Gerlitz 			       &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
45677b9900eSJiri Pirko 			       sizeof(key->tp.src));
45777b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
458aa72d708SOr Gerlitz 			       &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
45977b9900eSJiri Pirko 			       sizeof(key->tp.dst));
46077b9900eSJiri Pirko 	} else if (key->basic.ip_proto == IPPROTO_UDP) {
46177b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
462aa72d708SOr Gerlitz 			       &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
46377b9900eSJiri Pirko 			       sizeof(key->tp.src));
46477b9900eSJiri Pirko 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
465aa72d708SOr Gerlitz 			       &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
46677b9900eSJiri Pirko 			       sizeof(key->tp.dst));
4675976c5f4SSimon Horman 	} else if (key->basic.ip_proto == IPPROTO_SCTP) {
4685976c5f4SSimon Horman 		fl_set_key_val(tb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
4695976c5f4SSimon Horman 			       &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
4705976c5f4SSimon Horman 			       sizeof(key->tp.src));
4715976c5f4SSimon Horman 		fl_set_key_val(tb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
4725976c5f4SSimon Horman 			       &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
4735976c5f4SSimon Horman 			       sizeof(key->tp.dst));
47477b9900eSJiri Pirko 	}
47577b9900eSJiri Pirko 
476bc3103f1SAmir Vadai 	if (tb[TCA_FLOWER_KEY_ENC_IPV4_SRC] ||
477bc3103f1SAmir Vadai 	    tb[TCA_FLOWER_KEY_ENC_IPV4_DST]) {
478bc3103f1SAmir Vadai 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
479bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv4.src,
480bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_SRC,
481bc3103f1SAmir Vadai 			       &mask->enc_ipv4.src,
482bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
483bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv4.src));
484bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv4.dst,
485bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_DST,
486bc3103f1SAmir Vadai 			       &mask->enc_ipv4.dst,
487bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
488bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv4.dst));
489bc3103f1SAmir Vadai 	}
490bc3103f1SAmir Vadai 
491bc3103f1SAmir Vadai 	if (tb[TCA_FLOWER_KEY_ENC_IPV6_SRC] ||
492bc3103f1SAmir Vadai 	    tb[TCA_FLOWER_KEY_ENC_IPV6_DST]) {
493bc3103f1SAmir Vadai 		key->enc_control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
494bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv6.src,
495bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_SRC,
496bc3103f1SAmir Vadai 			       &mask->enc_ipv6.src,
497bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
498bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv6.src));
499bc3103f1SAmir Vadai 		fl_set_key_val(tb, &key->enc_ipv6.dst,
500bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_DST,
501bc3103f1SAmir Vadai 			       &mask->enc_ipv6.dst,
502bc3103f1SAmir Vadai 			       TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
503bc3103f1SAmir Vadai 			       sizeof(key->enc_ipv6.dst));
504bc3103f1SAmir Vadai 	}
505bc3103f1SAmir Vadai 
506bc3103f1SAmir Vadai 	fl_set_key_val(tb, &key->enc_key_id.keyid, TCA_FLOWER_KEY_ENC_KEY_ID,
507eb523f42SHadar Hen Zion 		       &mask->enc_key_id.keyid, TCA_FLOWER_UNSPEC,
508bc3103f1SAmir Vadai 		       sizeof(key->enc_key_id.keyid));
509bc3103f1SAmir Vadai 
510*f4d997fdSHadar Hen Zion 	fl_set_key_val(tb, &key->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
511*f4d997fdSHadar Hen Zion 		       &mask->enc_tp.src, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
512*f4d997fdSHadar Hen Zion 		       sizeof(key->enc_tp.src));
513*f4d997fdSHadar Hen Zion 
514*f4d997fdSHadar Hen Zion 	fl_set_key_val(tb, &key->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
515*f4d997fdSHadar Hen Zion 		       &mask->enc_tp.dst, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
516*f4d997fdSHadar Hen Zion 		       sizeof(key->enc_tp.dst));
517*f4d997fdSHadar Hen Zion 
51877b9900eSJiri Pirko 	return 0;
51977b9900eSJiri Pirko }
52077b9900eSJiri Pirko 
52177b9900eSJiri Pirko static bool fl_mask_eq(struct fl_flow_mask *mask1,
52277b9900eSJiri Pirko 		       struct fl_flow_mask *mask2)
52377b9900eSJiri Pirko {
52477b9900eSJiri Pirko 	const long *lmask1 = fl_key_get_start(&mask1->key, mask1);
52577b9900eSJiri Pirko 	const long *lmask2 = fl_key_get_start(&mask2->key, mask2);
52677b9900eSJiri Pirko 
52777b9900eSJiri Pirko 	return !memcmp(&mask1->range, &mask2->range, sizeof(mask1->range)) &&
52877b9900eSJiri Pirko 	       !memcmp(lmask1, lmask2, fl_mask_range(mask1));
52977b9900eSJiri Pirko }
53077b9900eSJiri Pirko 
53177b9900eSJiri Pirko static const struct rhashtable_params fl_ht_params = {
53277b9900eSJiri Pirko 	.key_offset = offsetof(struct cls_fl_filter, mkey), /* base offset */
53377b9900eSJiri Pirko 	.head_offset = offsetof(struct cls_fl_filter, ht_node),
53477b9900eSJiri Pirko 	.automatic_shrinking = true,
53577b9900eSJiri Pirko };
53677b9900eSJiri Pirko 
53777b9900eSJiri Pirko static int fl_init_hashtable(struct cls_fl_head *head,
53877b9900eSJiri Pirko 			     struct fl_flow_mask *mask)
53977b9900eSJiri Pirko {
54077b9900eSJiri Pirko 	head->ht_params = fl_ht_params;
54177b9900eSJiri Pirko 	head->ht_params.key_len = fl_mask_range(mask);
54277b9900eSJiri Pirko 	head->ht_params.key_offset += mask->range.start;
54377b9900eSJiri Pirko 
54477b9900eSJiri Pirko 	return rhashtable_init(&head->ht, &head->ht_params);
54577b9900eSJiri Pirko }
54677b9900eSJiri Pirko 
54777b9900eSJiri Pirko #define FL_KEY_MEMBER_OFFSET(member) offsetof(struct fl_flow_key, member)
54877b9900eSJiri Pirko #define FL_KEY_MEMBER_SIZE(member) (sizeof(((struct fl_flow_key *) 0)->member))
54977b9900eSJiri Pirko 
550339ba878SHadar Hen Zion #define FL_KEY_IS_MASKED(mask, member)						\
551339ba878SHadar Hen Zion 	memchr_inv(((char *)mask) + FL_KEY_MEMBER_OFFSET(member),		\
552339ba878SHadar Hen Zion 		   0, FL_KEY_MEMBER_SIZE(member))				\
55377b9900eSJiri Pirko 
55477b9900eSJiri Pirko #define FL_KEY_SET(keys, cnt, id, member)					\
55577b9900eSJiri Pirko 	do {									\
55677b9900eSJiri Pirko 		keys[cnt].key_id = id;						\
55777b9900eSJiri Pirko 		keys[cnt].offset = FL_KEY_MEMBER_OFFSET(member);		\
55877b9900eSJiri Pirko 		cnt++;								\
55977b9900eSJiri Pirko 	} while(0);
56077b9900eSJiri Pirko 
561339ba878SHadar Hen Zion #define FL_KEY_SET_IF_MASKED(mask, keys, cnt, id, member)			\
56277b9900eSJiri Pirko 	do {									\
563339ba878SHadar Hen Zion 		if (FL_KEY_IS_MASKED(mask, member))				\
56477b9900eSJiri Pirko 			FL_KEY_SET(keys, cnt, id, member);			\
56577b9900eSJiri Pirko 	} while(0);
56677b9900eSJiri Pirko 
56777b9900eSJiri Pirko static void fl_init_dissector(struct cls_fl_head *head,
56877b9900eSJiri Pirko 			      struct fl_flow_mask *mask)
56977b9900eSJiri Pirko {
57077b9900eSJiri Pirko 	struct flow_dissector_key keys[FLOW_DISSECTOR_KEY_MAX];
57177b9900eSJiri Pirko 	size_t cnt = 0;
57277b9900eSJiri Pirko 
57342aecaa9STom Herbert 	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_CONTROL, control);
57477b9900eSJiri Pirko 	FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_BASIC, basic);
575339ba878SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
57677b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_ETH_ADDRS, eth);
577339ba878SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
57877b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4);
579339ba878SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
58077b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6);
581339ba878SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
58277b9900eSJiri Pirko 			     FLOW_DISSECTOR_KEY_PORTS, tp);
5839399ae9aSHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
5849399ae9aSHadar Hen Zion 			     FLOW_DISSECTOR_KEY_VLAN, vlan);
585519d1052SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
586519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_KEYID, enc_key_id);
587519d1052SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
588519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, enc_ipv4);
589519d1052SHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
590519d1052SHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, enc_ipv6);
591519d1052SHadar Hen Zion 	if (FL_KEY_IS_MASKED(&mask->key, enc_ipv4) ||
592519d1052SHadar Hen Zion 	    FL_KEY_IS_MASKED(&mask->key, enc_ipv6))
593519d1052SHadar Hen Zion 		FL_KEY_SET(keys, cnt, FLOW_DISSECTOR_KEY_ENC_CONTROL,
594519d1052SHadar Hen Zion 			   enc_control);
595*f4d997fdSHadar Hen Zion 	FL_KEY_SET_IF_MASKED(&mask->key, keys, cnt,
596*f4d997fdSHadar Hen Zion 			     FLOW_DISSECTOR_KEY_ENC_PORTS, enc_tp);
59777b9900eSJiri Pirko 
59877b9900eSJiri Pirko 	skb_flow_dissector_init(&head->dissector, keys, cnt);
59977b9900eSJiri Pirko }
60077b9900eSJiri Pirko 
60177b9900eSJiri Pirko static int fl_check_assign_mask(struct cls_fl_head *head,
60277b9900eSJiri Pirko 				struct fl_flow_mask *mask)
60377b9900eSJiri Pirko {
60477b9900eSJiri Pirko 	int err;
60577b9900eSJiri Pirko 
60677b9900eSJiri Pirko 	if (head->mask_assigned) {
60777b9900eSJiri Pirko 		if (!fl_mask_eq(&head->mask, mask))
60877b9900eSJiri Pirko 			return -EINVAL;
60977b9900eSJiri Pirko 		else
61077b9900eSJiri Pirko 			return 0;
61177b9900eSJiri Pirko 	}
61277b9900eSJiri Pirko 
61377b9900eSJiri Pirko 	/* Mask is not assigned yet. So assign it and init hashtable
61477b9900eSJiri Pirko 	 * according to that.
61577b9900eSJiri Pirko 	 */
61677b9900eSJiri Pirko 	err = fl_init_hashtable(head, mask);
61777b9900eSJiri Pirko 	if (err)
61877b9900eSJiri Pirko 		return err;
61977b9900eSJiri Pirko 	memcpy(&head->mask, mask, sizeof(head->mask));
62077b9900eSJiri Pirko 	head->mask_assigned = true;
62177b9900eSJiri Pirko 
62277b9900eSJiri Pirko 	fl_init_dissector(head, mask);
62377b9900eSJiri Pirko 
62477b9900eSJiri Pirko 	return 0;
62577b9900eSJiri Pirko }
62677b9900eSJiri Pirko 
62777b9900eSJiri Pirko static int fl_set_parms(struct net *net, struct tcf_proto *tp,
62877b9900eSJiri Pirko 			struct cls_fl_filter *f, struct fl_flow_mask *mask,
62977b9900eSJiri Pirko 			unsigned long base, struct nlattr **tb,
63077b9900eSJiri Pirko 			struct nlattr *est, bool ovr)
63177b9900eSJiri Pirko {
63277b9900eSJiri Pirko 	struct tcf_exts e;
63377b9900eSJiri Pirko 	int err;
63477b9900eSJiri Pirko 
635b9a24bb7SWANG Cong 	err = tcf_exts_init(&e, TCA_FLOWER_ACT, 0);
63677b9900eSJiri Pirko 	if (err < 0)
63777b9900eSJiri Pirko 		return err;
638b9a24bb7SWANG Cong 	err = tcf_exts_validate(net, tp, tb, est, &e, ovr);
639b9a24bb7SWANG Cong 	if (err < 0)
640b9a24bb7SWANG Cong 		goto errout;
64177b9900eSJiri Pirko 
64277b9900eSJiri Pirko 	if (tb[TCA_FLOWER_CLASSID]) {
64377b9900eSJiri Pirko 		f->res.classid = nla_get_u32(tb[TCA_FLOWER_CLASSID]);
64477b9900eSJiri Pirko 		tcf_bind_filter(tp, &f->res, base);
64577b9900eSJiri Pirko 	}
64677b9900eSJiri Pirko 
64777b9900eSJiri Pirko 	err = fl_set_key(net, tb, &f->key, &mask->key);
64877b9900eSJiri Pirko 	if (err)
64977b9900eSJiri Pirko 		goto errout;
65077b9900eSJiri Pirko 
65177b9900eSJiri Pirko 	fl_mask_update_range(mask);
65277b9900eSJiri Pirko 	fl_set_masked_key(&f->mkey, &f->key, mask);
65377b9900eSJiri Pirko 
65477b9900eSJiri Pirko 	tcf_exts_change(tp, &f->exts, &e);
65577b9900eSJiri Pirko 
65677b9900eSJiri Pirko 	return 0;
65777b9900eSJiri Pirko errout:
65877b9900eSJiri Pirko 	tcf_exts_destroy(&e);
65977b9900eSJiri Pirko 	return err;
66077b9900eSJiri Pirko }
66177b9900eSJiri Pirko 
66277b9900eSJiri Pirko static u32 fl_grab_new_handle(struct tcf_proto *tp,
66377b9900eSJiri Pirko 			      struct cls_fl_head *head)
66477b9900eSJiri Pirko {
66577b9900eSJiri Pirko 	unsigned int i = 0x80000000;
66677b9900eSJiri Pirko 	u32 handle;
66777b9900eSJiri Pirko 
66877b9900eSJiri Pirko 	do {
66977b9900eSJiri Pirko 		if (++head->hgen == 0x7FFFFFFF)
67077b9900eSJiri Pirko 			head->hgen = 1;
67177b9900eSJiri Pirko 	} while (--i > 0 && fl_get(tp, head->hgen));
67277b9900eSJiri Pirko 
67377b9900eSJiri Pirko 	if (unlikely(i == 0)) {
67477b9900eSJiri Pirko 		pr_err("Insufficient number of handles\n");
67577b9900eSJiri Pirko 		handle = 0;
67677b9900eSJiri Pirko 	} else {
67777b9900eSJiri Pirko 		handle = head->hgen;
67877b9900eSJiri Pirko 	}
67977b9900eSJiri Pirko 
68077b9900eSJiri Pirko 	return handle;
68177b9900eSJiri Pirko }
68277b9900eSJiri Pirko 
68377b9900eSJiri Pirko static int fl_change(struct net *net, struct sk_buff *in_skb,
68477b9900eSJiri Pirko 		     struct tcf_proto *tp, unsigned long base,
68577b9900eSJiri Pirko 		     u32 handle, struct nlattr **tca,
68677b9900eSJiri Pirko 		     unsigned long *arg, bool ovr)
68777b9900eSJiri Pirko {
68877b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
68977b9900eSJiri Pirko 	struct cls_fl_filter *fold = (struct cls_fl_filter *) *arg;
69077b9900eSJiri Pirko 	struct cls_fl_filter *fnew;
69177b9900eSJiri Pirko 	struct nlattr *tb[TCA_FLOWER_MAX + 1];
69277b9900eSJiri Pirko 	struct fl_flow_mask mask = {};
69377b9900eSJiri Pirko 	int err;
69477b9900eSJiri Pirko 
69577b9900eSJiri Pirko 	if (!tca[TCA_OPTIONS])
69677b9900eSJiri Pirko 		return -EINVAL;
69777b9900eSJiri Pirko 
69877b9900eSJiri Pirko 	err = nla_parse_nested(tb, TCA_FLOWER_MAX, tca[TCA_OPTIONS], fl_policy);
69977b9900eSJiri Pirko 	if (err < 0)
70077b9900eSJiri Pirko 		return err;
70177b9900eSJiri Pirko 
70277b9900eSJiri Pirko 	if (fold && handle && fold->handle != handle)
70377b9900eSJiri Pirko 		return -EINVAL;
70477b9900eSJiri Pirko 
70577b9900eSJiri Pirko 	fnew = kzalloc(sizeof(*fnew), GFP_KERNEL);
70677b9900eSJiri Pirko 	if (!fnew)
70777b9900eSJiri Pirko 		return -ENOBUFS;
70877b9900eSJiri Pirko 
709b9a24bb7SWANG Cong 	err = tcf_exts_init(&fnew->exts, TCA_FLOWER_ACT, 0);
710b9a24bb7SWANG Cong 	if (err < 0)
711b9a24bb7SWANG Cong 		goto errout;
71277b9900eSJiri Pirko 
71377b9900eSJiri Pirko 	if (!handle) {
71477b9900eSJiri Pirko 		handle = fl_grab_new_handle(tp, head);
71577b9900eSJiri Pirko 		if (!handle) {
71677b9900eSJiri Pirko 			err = -EINVAL;
71777b9900eSJiri Pirko 			goto errout;
71877b9900eSJiri Pirko 		}
71977b9900eSJiri Pirko 	}
72077b9900eSJiri Pirko 	fnew->handle = handle;
72177b9900eSJiri Pirko 
722e69985c6SAmir Vadai 	if (tb[TCA_FLOWER_FLAGS]) {
723e69985c6SAmir Vadai 		fnew->flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
724e69985c6SAmir Vadai 
725e69985c6SAmir Vadai 		if (!tc_flags_valid(fnew->flags)) {
726e69985c6SAmir Vadai 			err = -EINVAL;
727e69985c6SAmir Vadai 			goto errout;
728e69985c6SAmir Vadai 		}
729e69985c6SAmir Vadai 	}
7305b33f488SAmir Vadai 
73177b9900eSJiri Pirko 	err = fl_set_parms(net, tp, fnew, &mask, base, tb, tca[TCA_RATE], ovr);
73277b9900eSJiri Pirko 	if (err)
73377b9900eSJiri Pirko 		goto errout;
73477b9900eSJiri Pirko 
73577b9900eSJiri Pirko 	err = fl_check_assign_mask(head, &mask);
73677b9900eSJiri Pirko 	if (err)
73777b9900eSJiri Pirko 		goto errout;
73877b9900eSJiri Pirko 
739e8eb36cdSAmir Vadai 	if (!tc_skip_sw(fnew->flags)) {
74077b9900eSJiri Pirko 		err = rhashtable_insert_fast(&head->ht, &fnew->ht_node,
74177b9900eSJiri Pirko 					     head->ht_params);
74277b9900eSJiri Pirko 		if (err)
74377b9900eSJiri Pirko 			goto errout;
744e69985c6SAmir Vadai 	}
7455b33f488SAmir Vadai 
746e8eb36cdSAmir Vadai 	err = fl_hw_replace_filter(tp,
7475b33f488SAmir Vadai 				   &head->dissector,
7485b33f488SAmir Vadai 				   &mask.key,
7495b33f488SAmir Vadai 				   &fnew->key,
7505b33f488SAmir Vadai 				   &fnew->exts,
7518208d21bSAmir Vadai 				   (unsigned long)fnew,
752e69985c6SAmir Vadai 				   fnew->flags);
753e8eb36cdSAmir Vadai 	if (err)
754e8eb36cdSAmir Vadai 		goto errout;
7555b33f488SAmir Vadai 
7565b33f488SAmir Vadai 	if (fold) {
75777b9900eSJiri Pirko 		rhashtable_remove_fast(&head->ht, &fold->ht_node,
75877b9900eSJiri Pirko 				       head->ht_params);
7598208d21bSAmir Vadai 		fl_hw_destroy_filter(tp, (unsigned long)fold);
7605b33f488SAmir Vadai 	}
76177b9900eSJiri Pirko 
76277b9900eSJiri Pirko 	*arg = (unsigned long) fnew;
76377b9900eSJiri Pirko 
76477b9900eSJiri Pirko 	if (fold) {
765ff3532f2SDaniel Borkmann 		list_replace_rcu(&fold->list, &fnew->list);
76677b9900eSJiri Pirko 		tcf_unbind_filter(tp, &fold->res);
76777b9900eSJiri Pirko 		call_rcu(&fold->rcu, fl_destroy_filter);
76877b9900eSJiri Pirko 	} else {
76977b9900eSJiri Pirko 		list_add_tail_rcu(&fnew->list, &head->filters);
77077b9900eSJiri Pirko 	}
77177b9900eSJiri Pirko 
77277b9900eSJiri Pirko 	return 0;
77377b9900eSJiri Pirko 
77477b9900eSJiri Pirko errout:
775b9a24bb7SWANG Cong 	tcf_exts_destroy(&fnew->exts);
77677b9900eSJiri Pirko 	kfree(fnew);
77777b9900eSJiri Pirko 	return err;
77877b9900eSJiri Pirko }
77977b9900eSJiri Pirko 
78077b9900eSJiri Pirko static int fl_delete(struct tcf_proto *tp, unsigned long arg)
78177b9900eSJiri Pirko {
78277b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
78377b9900eSJiri Pirko 	struct cls_fl_filter *f = (struct cls_fl_filter *) arg;
78477b9900eSJiri Pirko 
78577b9900eSJiri Pirko 	rhashtable_remove_fast(&head->ht, &f->ht_node,
78677b9900eSJiri Pirko 			       head->ht_params);
78713fa876eSRoi Dayan 	__fl_delete(tp, f);
78877b9900eSJiri Pirko 	return 0;
78977b9900eSJiri Pirko }
79077b9900eSJiri Pirko 
79177b9900eSJiri Pirko static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg)
79277b9900eSJiri Pirko {
79377b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
79477b9900eSJiri Pirko 	struct cls_fl_filter *f;
79577b9900eSJiri Pirko 
79677b9900eSJiri Pirko 	list_for_each_entry_rcu(f, &head->filters, list) {
79777b9900eSJiri Pirko 		if (arg->count < arg->skip)
79877b9900eSJiri Pirko 			goto skip;
79977b9900eSJiri Pirko 		if (arg->fn(tp, (unsigned long) f, arg) < 0) {
80077b9900eSJiri Pirko 			arg->stop = 1;
80177b9900eSJiri Pirko 			break;
80277b9900eSJiri Pirko 		}
80377b9900eSJiri Pirko skip:
80477b9900eSJiri Pirko 		arg->count++;
80577b9900eSJiri Pirko 	}
80677b9900eSJiri Pirko }
80777b9900eSJiri Pirko 
80877b9900eSJiri Pirko static int fl_dump_key_val(struct sk_buff *skb,
80977b9900eSJiri Pirko 			   void *val, int val_type,
81077b9900eSJiri Pirko 			   void *mask, int mask_type, int len)
81177b9900eSJiri Pirko {
81277b9900eSJiri Pirko 	int err;
81377b9900eSJiri Pirko 
81477b9900eSJiri Pirko 	if (!memchr_inv(mask, 0, len))
81577b9900eSJiri Pirko 		return 0;
81677b9900eSJiri Pirko 	err = nla_put(skb, val_type, len, val);
81777b9900eSJiri Pirko 	if (err)
81877b9900eSJiri Pirko 		return err;
81977b9900eSJiri Pirko 	if (mask_type != TCA_FLOWER_UNSPEC) {
82077b9900eSJiri Pirko 		err = nla_put(skb, mask_type, len, mask);
82177b9900eSJiri Pirko 		if (err)
82277b9900eSJiri Pirko 			return err;
82377b9900eSJiri Pirko 	}
82477b9900eSJiri Pirko 	return 0;
82577b9900eSJiri Pirko }
82677b9900eSJiri Pirko 
8279399ae9aSHadar Hen Zion static int fl_dump_key_vlan(struct sk_buff *skb,
8289399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *vlan_key,
8299399ae9aSHadar Hen Zion 			    struct flow_dissector_key_vlan *vlan_mask)
8309399ae9aSHadar Hen Zion {
8319399ae9aSHadar Hen Zion 	int err;
8329399ae9aSHadar Hen Zion 
8339399ae9aSHadar Hen Zion 	if (!memchr_inv(vlan_mask, 0, sizeof(*vlan_mask)))
8349399ae9aSHadar Hen Zion 		return 0;
8359399ae9aSHadar Hen Zion 	if (vlan_mask->vlan_id) {
8369399ae9aSHadar Hen Zion 		err = nla_put_u16(skb, TCA_FLOWER_KEY_VLAN_ID,
8379399ae9aSHadar Hen Zion 				  vlan_key->vlan_id);
8389399ae9aSHadar Hen Zion 		if (err)
8399399ae9aSHadar Hen Zion 			return err;
8409399ae9aSHadar Hen Zion 	}
8419399ae9aSHadar Hen Zion 	if (vlan_mask->vlan_priority) {
8429399ae9aSHadar Hen Zion 		err = nla_put_u8(skb, TCA_FLOWER_KEY_VLAN_PRIO,
8439399ae9aSHadar Hen Zion 				 vlan_key->vlan_priority);
8449399ae9aSHadar Hen Zion 		if (err)
8459399ae9aSHadar Hen Zion 			return err;
8469399ae9aSHadar Hen Zion 	}
8479399ae9aSHadar Hen Zion 	return 0;
8489399ae9aSHadar Hen Zion }
8499399ae9aSHadar Hen Zion 
85077b9900eSJiri Pirko static int fl_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
85177b9900eSJiri Pirko 		   struct sk_buff *skb, struct tcmsg *t)
85277b9900eSJiri Pirko {
85377b9900eSJiri Pirko 	struct cls_fl_head *head = rtnl_dereference(tp->root);
85477b9900eSJiri Pirko 	struct cls_fl_filter *f = (struct cls_fl_filter *) fh;
85577b9900eSJiri Pirko 	struct nlattr *nest;
85677b9900eSJiri Pirko 	struct fl_flow_key *key, *mask;
85777b9900eSJiri Pirko 
85877b9900eSJiri Pirko 	if (!f)
85977b9900eSJiri Pirko 		return skb->len;
86077b9900eSJiri Pirko 
86177b9900eSJiri Pirko 	t->tcm_handle = f->handle;
86277b9900eSJiri Pirko 
86377b9900eSJiri Pirko 	nest = nla_nest_start(skb, TCA_OPTIONS);
86477b9900eSJiri Pirko 	if (!nest)
86577b9900eSJiri Pirko 		goto nla_put_failure;
86677b9900eSJiri Pirko 
86777b9900eSJiri Pirko 	if (f->res.classid &&
86877b9900eSJiri Pirko 	    nla_put_u32(skb, TCA_FLOWER_CLASSID, f->res.classid))
86977b9900eSJiri Pirko 		goto nla_put_failure;
87077b9900eSJiri Pirko 
87177b9900eSJiri Pirko 	key = &f->key;
87277b9900eSJiri Pirko 	mask = &head->mask.key;
87377b9900eSJiri Pirko 
87477b9900eSJiri Pirko 	if (mask->indev_ifindex) {
87577b9900eSJiri Pirko 		struct net_device *dev;
87677b9900eSJiri Pirko 
87777b9900eSJiri Pirko 		dev = __dev_get_by_index(net, key->indev_ifindex);
87877b9900eSJiri Pirko 		if (dev && nla_put_string(skb, TCA_FLOWER_INDEV, dev->name))
87977b9900eSJiri Pirko 			goto nla_put_failure;
88077b9900eSJiri Pirko 	}
88177b9900eSJiri Pirko 
88210cbc684SAmir Vadai 	fl_hw_update_stats(tp, f);
88310cbc684SAmir Vadai 
88477b9900eSJiri Pirko 	if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST,
88577b9900eSJiri Pirko 			    mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK,
88677b9900eSJiri Pirko 			    sizeof(key->eth.dst)) ||
88777b9900eSJiri Pirko 	    fl_dump_key_val(skb, key->eth.src, TCA_FLOWER_KEY_ETH_SRC,
88877b9900eSJiri Pirko 			    mask->eth.src, TCA_FLOWER_KEY_ETH_SRC_MASK,
88977b9900eSJiri Pirko 			    sizeof(key->eth.src)) ||
89077b9900eSJiri Pirko 	    fl_dump_key_val(skb, &key->basic.n_proto, TCA_FLOWER_KEY_ETH_TYPE,
89177b9900eSJiri Pirko 			    &mask->basic.n_proto, TCA_FLOWER_UNSPEC,
89277b9900eSJiri Pirko 			    sizeof(key->basic.n_proto)))
89377b9900eSJiri Pirko 		goto nla_put_failure;
8949399ae9aSHadar Hen Zion 
8959399ae9aSHadar Hen Zion 	if (fl_dump_key_vlan(skb, &key->vlan, &mask->vlan))
8969399ae9aSHadar Hen Zion 		goto nla_put_failure;
8979399ae9aSHadar Hen Zion 
89877b9900eSJiri Pirko 	if ((key->basic.n_proto == htons(ETH_P_IP) ||
89977b9900eSJiri Pirko 	     key->basic.n_proto == htons(ETH_P_IPV6)) &&
90077b9900eSJiri Pirko 	    fl_dump_key_val(skb, &key->basic.ip_proto, TCA_FLOWER_KEY_IP_PROTO,
90177b9900eSJiri Pirko 			    &mask->basic.ip_proto, TCA_FLOWER_UNSPEC,
90277b9900eSJiri Pirko 			    sizeof(key->basic.ip_proto)))
90377b9900eSJiri Pirko 		goto nla_put_failure;
90477b9900eSJiri Pirko 
905c3f83241STom Herbert 	if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
90677b9900eSJiri Pirko 	    (fl_dump_key_val(skb, &key->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC,
90777b9900eSJiri Pirko 			     &mask->ipv4.src, TCA_FLOWER_KEY_IPV4_SRC_MASK,
90877b9900eSJiri Pirko 			     sizeof(key->ipv4.src)) ||
90977b9900eSJiri Pirko 	     fl_dump_key_val(skb, &key->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST,
91077b9900eSJiri Pirko 			     &mask->ipv4.dst, TCA_FLOWER_KEY_IPV4_DST_MASK,
91177b9900eSJiri Pirko 			     sizeof(key->ipv4.dst))))
91277b9900eSJiri Pirko 		goto nla_put_failure;
913c3f83241STom Herbert 	else if (key->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
91477b9900eSJiri Pirko 		 (fl_dump_key_val(skb, &key->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC,
91577b9900eSJiri Pirko 				  &mask->ipv6.src, TCA_FLOWER_KEY_IPV6_SRC_MASK,
91677b9900eSJiri Pirko 				  sizeof(key->ipv6.src)) ||
91777b9900eSJiri Pirko 		  fl_dump_key_val(skb, &key->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST,
91877b9900eSJiri Pirko 				  &mask->ipv6.dst, TCA_FLOWER_KEY_IPV6_DST_MASK,
91977b9900eSJiri Pirko 				  sizeof(key->ipv6.dst))))
92077b9900eSJiri Pirko 		goto nla_put_failure;
92177b9900eSJiri Pirko 
92277b9900eSJiri Pirko 	if (key->basic.ip_proto == IPPROTO_TCP &&
92377b9900eSJiri Pirko 	    (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_TCP_SRC,
924aa72d708SOr Gerlitz 			     &mask->tp.src, TCA_FLOWER_KEY_TCP_SRC_MASK,
92577b9900eSJiri Pirko 			     sizeof(key->tp.src)) ||
92677b9900eSJiri Pirko 	     fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_TCP_DST,
927aa72d708SOr Gerlitz 			     &mask->tp.dst, TCA_FLOWER_KEY_TCP_DST_MASK,
92877b9900eSJiri Pirko 			     sizeof(key->tp.dst))))
92977b9900eSJiri Pirko 		goto nla_put_failure;
93077b9900eSJiri Pirko 	else if (key->basic.ip_proto == IPPROTO_UDP &&
93177b9900eSJiri Pirko 		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_UDP_SRC,
932aa72d708SOr Gerlitz 				  &mask->tp.src, TCA_FLOWER_KEY_UDP_SRC_MASK,
93377b9900eSJiri Pirko 				  sizeof(key->tp.src)) ||
93477b9900eSJiri Pirko 		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_UDP_DST,
935aa72d708SOr Gerlitz 				  &mask->tp.dst, TCA_FLOWER_KEY_UDP_DST_MASK,
93677b9900eSJiri Pirko 				  sizeof(key->tp.dst))))
93777b9900eSJiri Pirko 		goto nla_put_failure;
9385976c5f4SSimon Horman 	else if (key->basic.ip_proto == IPPROTO_SCTP &&
9395976c5f4SSimon Horman 		 (fl_dump_key_val(skb, &key->tp.src, TCA_FLOWER_KEY_SCTP_SRC,
9405976c5f4SSimon Horman 				  &mask->tp.src, TCA_FLOWER_KEY_SCTP_SRC_MASK,
9415976c5f4SSimon Horman 				  sizeof(key->tp.src)) ||
9425976c5f4SSimon Horman 		  fl_dump_key_val(skb, &key->tp.dst, TCA_FLOWER_KEY_SCTP_DST,
9435976c5f4SSimon Horman 				  &mask->tp.dst, TCA_FLOWER_KEY_SCTP_DST_MASK,
9445976c5f4SSimon Horman 				  sizeof(key->tp.dst))))
9455976c5f4SSimon Horman 		goto nla_put_failure;
94677b9900eSJiri Pirko 
947bc3103f1SAmir Vadai 	if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS &&
948bc3103f1SAmir Vadai 	    (fl_dump_key_val(skb, &key->enc_ipv4.src,
949bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV4_SRC, &mask->enc_ipv4.src,
950bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
951bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv4.src)) ||
952bc3103f1SAmir Vadai 	     fl_dump_key_val(skb, &key->enc_ipv4.dst,
953bc3103f1SAmir Vadai 			     TCA_FLOWER_KEY_ENC_IPV4_DST, &mask->enc_ipv4.dst,
954bc3103f1SAmir Vadai 			     TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
955bc3103f1SAmir Vadai 			     sizeof(key->enc_ipv4.dst))))
956bc3103f1SAmir Vadai 		goto nla_put_failure;
957bc3103f1SAmir Vadai 	else if (key->enc_control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS &&
958bc3103f1SAmir Vadai 		 (fl_dump_key_val(skb, &key->enc_ipv6.src,
959bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV6_SRC, &mask->enc_ipv6.src,
960bc3103f1SAmir Vadai 			    TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
961bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv6.src)) ||
962bc3103f1SAmir Vadai 		 fl_dump_key_val(skb, &key->enc_ipv6.dst,
963bc3103f1SAmir Vadai 				 TCA_FLOWER_KEY_ENC_IPV6_DST,
964bc3103f1SAmir Vadai 				 &mask->enc_ipv6.dst,
965bc3103f1SAmir Vadai 				 TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
966bc3103f1SAmir Vadai 			    sizeof(key->enc_ipv6.dst))))
967bc3103f1SAmir Vadai 		goto nla_put_failure;
968bc3103f1SAmir Vadai 
969bc3103f1SAmir Vadai 	if (fl_dump_key_val(skb, &key->enc_key_id, TCA_FLOWER_KEY_ENC_KEY_ID,
970eb523f42SHadar Hen Zion 			    &mask->enc_key_id, TCA_FLOWER_UNSPEC,
971*f4d997fdSHadar Hen Zion 			    sizeof(key->enc_key_id)) ||
972*f4d997fdSHadar Hen Zion 	    fl_dump_key_val(skb, &key->enc_tp.src,
973*f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT,
974*f4d997fdSHadar Hen Zion 			    &mask->enc_tp.src,
975*f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
976*f4d997fdSHadar Hen Zion 			    sizeof(key->enc_tp.src)) ||
977*f4d997fdSHadar Hen Zion 	    fl_dump_key_val(skb, &key->enc_tp.dst,
978*f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT,
979*f4d997fdSHadar Hen Zion 			    &mask->enc_tp.dst,
980*f4d997fdSHadar Hen Zion 			    TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
981*f4d997fdSHadar Hen Zion 			    sizeof(key->enc_tp.dst)))
982bc3103f1SAmir Vadai 		goto nla_put_failure;
983bc3103f1SAmir Vadai 
984e69985c6SAmir Vadai 	nla_put_u32(skb, TCA_FLOWER_FLAGS, f->flags);
985e69985c6SAmir Vadai 
98677b9900eSJiri Pirko 	if (tcf_exts_dump(skb, &f->exts))
98777b9900eSJiri Pirko 		goto nla_put_failure;
98877b9900eSJiri Pirko 
98977b9900eSJiri Pirko 	nla_nest_end(skb, nest);
99077b9900eSJiri Pirko 
99177b9900eSJiri Pirko 	if (tcf_exts_dump_stats(skb, &f->exts) < 0)
99277b9900eSJiri Pirko 		goto nla_put_failure;
99377b9900eSJiri Pirko 
99477b9900eSJiri Pirko 	return skb->len;
99577b9900eSJiri Pirko 
99677b9900eSJiri Pirko nla_put_failure:
99777b9900eSJiri Pirko 	nla_nest_cancel(skb, nest);
99877b9900eSJiri Pirko 	return -1;
99977b9900eSJiri Pirko }
100077b9900eSJiri Pirko 
100177b9900eSJiri Pirko static struct tcf_proto_ops cls_fl_ops __read_mostly = {
100277b9900eSJiri Pirko 	.kind		= "flower",
100377b9900eSJiri Pirko 	.classify	= fl_classify,
100477b9900eSJiri Pirko 	.init		= fl_init,
100577b9900eSJiri Pirko 	.destroy	= fl_destroy,
100677b9900eSJiri Pirko 	.get		= fl_get,
100777b9900eSJiri Pirko 	.change		= fl_change,
100877b9900eSJiri Pirko 	.delete		= fl_delete,
100977b9900eSJiri Pirko 	.walk		= fl_walk,
101077b9900eSJiri Pirko 	.dump		= fl_dump,
101177b9900eSJiri Pirko 	.owner		= THIS_MODULE,
101277b9900eSJiri Pirko };
101377b9900eSJiri Pirko 
101477b9900eSJiri Pirko static int __init cls_fl_init(void)
101577b9900eSJiri Pirko {
101677b9900eSJiri Pirko 	return register_tcf_proto_ops(&cls_fl_ops);
101777b9900eSJiri Pirko }
101877b9900eSJiri Pirko 
101977b9900eSJiri Pirko static void __exit cls_fl_exit(void)
102077b9900eSJiri Pirko {
102177b9900eSJiri Pirko 	unregister_tcf_proto_ops(&cls_fl_ops);
102277b9900eSJiri Pirko }
102377b9900eSJiri Pirko 
102477b9900eSJiri Pirko module_init(cls_fl_init);
102577b9900eSJiri Pirko module_exit(cls_fl_exit);
102677b9900eSJiri Pirko 
102777b9900eSJiri Pirko MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>");
102877b9900eSJiri Pirko MODULE_DESCRIPTION("Flower classifier");
102977b9900eSJiri Pirko MODULE_LICENSE("GPL v2");
1030