xref: /openbmc/linux/net/sched/cls_u32.c (revision f6d73b12ca9fd3b1c29a6a725cd751b972c740cf)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * net/sched/cls_u32.c	Ugly (or Universal) 32bit key Packet Classifier.
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  *	The filters are packed to hash tables of key nodes
81da177e4SLinus Torvalds  *	with a set of 32bit key/mask pairs at every node.
91da177e4SLinus Torvalds  *	Nodes reference next level hash tables etc.
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  *	This scheme is the best universal classifier I managed to
121da177e4SLinus Torvalds  *	invent; it is not super-fast, but it is not slow (provided you
131da177e4SLinus Torvalds  *	program it correctly), and general enough.  And its relative
141da177e4SLinus Torvalds  *	speed grows as the number of rules becomes larger.
151da177e4SLinus Torvalds  *
161da177e4SLinus Torvalds  *	It seems that it represents the best middle point between
171da177e4SLinus Torvalds  *	speed and manageability both by human and by machine.
181da177e4SLinus Torvalds  *
191da177e4SLinus Torvalds  *	It is especially useful for link sharing combined with QoS;
201da177e4SLinus Torvalds  *	pure RSVP doesn't need such a general approach and can use
211da177e4SLinus Torvalds  *	much simpler (and faster) schemes, sort of cls_rsvp.c.
221da177e4SLinus Torvalds  *
231da177e4SLinus Torvalds  *	nfmark match added by Catalin(ux aka Dino) BOIE <catab at umbrella.ro>
241da177e4SLinus Torvalds  */
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds #include <linux/module.h>
275a0e3ad6STejun Heo #include <linux/slab.h>
281da177e4SLinus Torvalds #include <linux/types.h>
291da177e4SLinus Torvalds #include <linux/kernel.h>
301da177e4SLinus Torvalds #include <linux/string.h>
311da177e4SLinus Torvalds #include <linux/errno.h>
321ce87720SJohn Fastabend #include <linux/percpu.h>
331da177e4SLinus Torvalds #include <linux/rtnetlink.h>
341da177e4SLinus Torvalds #include <linux/skbuff.h>
357801db8aSCong Wang #include <linux/bitmap.h>
363cd904ecSWANG Cong #include <linux/netdevice.h>
373cd904ecSWANG Cong #include <linux/hash.h>
380ba48053SPatrick McHardy #include <net/netlink.h>
391da177e4SLinus Torvalds #include <net/act_api.h>
401da177e4SLinus Torvalds #include <net/pkt_cls.h>
41e7614370SCong Wang #include <linux/idr.h>
429f3101dcSPedro Tammela #include <net/tc_wrapper.h>
431da177e4SLinus Torvalds 
44cc7ec456SEric Dumazet struct tc_u_knode {
451ce87720SJohn Fastabend 	struct tc_u_knode __rcu	*next;
461da177e4SLinus Torvalds 	u32			handle;
471ce87720SJohn Fastabend 	struct tc_u_hnode __rcu	*ht_up;
481da177e4SLinus Torvalds 	struct tcf_exts		exts;
492519a602SWANG Cong 	int			ifindex;
501da177e4SLinus Torvalds 	u8			fshift;
511da177e4SLinus Torvalds 	struct tcf_result	res;
521ce87720SJohn Fastabend 	struct tc_u_hnode __rcu	*ht_down;
531da177e4SLinus Torvalds #ifdef CONFIG_CLS_U32_PERF
54459d5f62SJohn Fastabend 	struct tc_u32_pcnt __percpu *pf;
551da177e4SLinus Torvalds #endif
569e8ce79cSJohn Fastabend 	u32			flags;
57530d9951SJohn Hurley 	unsigned int		in_hw_count;
581da177e4SLinus Torvalds #ifdef CONFIG_CLS_U32_MARK
59459d5f62SJohn Fastabend 	u32			val;
60459d5f62SJohn Fastabend 	u32			mask;
61459d5f62SJohn Fastabend 	u32 __percpu		*pcpu_success;
621da177e4SLinus Torvalds #endif
63aaa908ffSCong Wang 	struct rcu_work		rwork;
644e2840eeSJohn Fastabend 	/* The 'sel' field MUST be the last field in structure to allow for
654e2840eeSJohn Fastabend 	 * tc_u32_keys allocated at end of structure.
664e2840eeSJohn Fastabend 	 */
674e2840eeSJohn Fastabend 	struct tc_u32_sel	sel;
681da177e4SLinus Torvalds };
691da177e4SLinus Torvalds 
70cc7ec456SEric Dumazet struct tc_u_hnode {
711ce87720SJohn Fastabend 	struct tc_u_hnode __rcu	*next;
721da177e4SLinus Torvalds 	u32			handle;
731da177e4SLinus Torvalds 	u32			prio;
749fd5661aSPedro Tammela 	refcount_t		refcnt;
75cc7ec456SEric Dumazet 	unsigned int		divisor;
76e7614370SCong Wang 	struct idr		handle_idr;
77b44ef845SAl Viro 	bool			is_root;
781ce87720SJohn Fastabend 	struct rcu_head		rcu;
79f40fe58dSJakub Kicinski 	u32			flags;
805778d39dSWANG Cong 	/* The 'ht' field MUST be the last field in structure to allow for
815778d39dSWANG Cong 	 * more entries allocated at end of structure.
825778d39dSWANG Cong 	 */
83d61491a5SGustavo A. R. Silva 	struct tc_u_knode __rcu	*ht[];
841da177e4SLinus Torvalds };
851da177e4SLinus Torvalds 
86cc7ec456SEric Dumazet struct tc_u_common {
871ce87720SJohn Fastabend 	struct tc_u_hnode __rcu	*hlist;
88339c21d7SJiri Pirko 	void			*ptr;
899fd5661aSPedro Tammela 	refcount_t		refcnt;
90e7614370SCong Wang 	struct idr		handle_idr;
913cd904ecSWANG Cong 	struct hlist_node	hnode;
92b245d32cSAl Viro 	long			knodes;
931da177e4SLinus Torvalds };
941da177e4SLinus Torvalds 
handle2id(u32 h)95*789f9963SAlexandre Ferrieux static u32 handle2id(u32 h)
96*789f9963SAlexandre Ferrieux {
97*789f9963SAlexandre Ferrieux 	return ((h & 0x80000000) ? ((h >> 20) & 0x7FF) : h);
98*789f9963SAlexandre Ferrieux }
99*789f9963SAlexandre Ferrieux 
id2handle(u32 id)100*789f9963SAlexandre Ferrieux static u32 id2handle(u32 id)
101*789f9963SAlexandre Ferrieux {
102*789f9963SAlexandre Ferrieux 	return (id | 0x800U) << 20;
103*789f9963SAlexandre Ferrieux }
104*789f9963SAlexandre Ferrieux 
u32_hash_fold(__be32 key,const struct tc_u32_sel * sel,u8 fshift)105cc7ec456SEric Dumazet static inline unsigned int u32_hash_fold(__be32 key,
106cc7ec456SEric Dumazet 					 const struct tc_u32_sel *sel,
107cc7ec456SEric Dumazet 					 u8 fshift)
1081da177e4SLinus Torvalds {
109cc7ec456SEric Dumazet 	unsigned int h = ntohl(key & sel->hmask) >> fshift;
1101da177e4SLinus Torvalds 
1111da177e4SLinus Torvalds 	return h;
1121da177e4SLinus Torvalds }
1131da177e4SLinus Torvalds 
u32_classify(struct sk_buff * skb,const struct tcf_proto * tp,struct tcf_result * res)1149f3101dcSPedro Tammela TC_INDIRECT_SCOPE int u32_classify(struct sk_buff *skb,
1159f3101dcSPedro Tammela 				   const struct tcf_proto *tp,
1165a7a5555SJamal Hadi Salim 				   struct tcf_result *res)
1171da177e4SLinus Torvalds {
1181da177e4SLinus Torvalds 	struct {
1191da177e4SLinus Torvalds 		struct tc_u_knode *knode;
120fbc2e7d9SChangli Gao 		unsigned int	  off;
1211da177e4SLinus Torvalds 	} stack[TC_U32_MAXDEPTH];
1221da177e4SLinus Torvalds 
1231ce87720SJohn Fastabend 	struct tc_u_hnode *ht = rcu_dereference_bh(tp->root);
124fbc2e7d9SChangli Gao 	unsigned int off = skb_network_offset(skb);
1251da177e4SLinus Torvalds 	struct tc_u_knode *n;
1261da177e4SLinus Torvalds 	int sdepth = 0;
1271da177e4SLinus Torvalds 	int off2 = 0;
1281da177e4SLinus Torvalds 	int sel = 0;
1291da177e4SLinus Torvalds #ifdef CONFIG_CLS_U32_PERF
1301da177e4SLinus Torvalds 	int j;
1311da177e4SLinus Torvalds #endif
1321da177e4SLinus Torvalds 	int i, r;
1331da177e4SLinus Torvalds 
1341da177e4SLinus Torvalds next_ht:
1351ce87720SJohn Fastabend 	n = rcu_dereference_bh(ht->ht[sel]);
1361da177e4SLinus Torvalds 
1371da177e4SLinus Torvalds next_knode:
1381da177e4SLinus Torvalds 	if (n) {
1391da177e4SLinus Torvalds 		struct tc_u32_key *key = n->sel.keys;
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds #ifdef CONFIG_CLS_U32_PERF
142459d5f62SJohn Fastabend 		__this_cpu_inc(n->pf->rcnt);
1431da177e4SLinus Torvalds 		j = 0;
1441da177e4SLinus Torvalds #endif
1451da177e4SLinus Torvalds 
146d34e3e18SSamudrala, Sridhar 		if (tc_skip_sw(n->flags)) {
147d34e3e18SSamudrala, Sridhar 			n = rcu_dereference_bh(n->next);
148d34e3e18SSamudrala, Sridhar 			goto next_knode;
149d34e3e18SSamudrala, Sridhar 		}
150d34e3e18SSamudrala, Sridhar 
1511da177e4SLinus Torvalds #ifdef CONFIG_CLS_U32_MARK
152459d5f62SJohn Fastabend 		if ((skb->mark & n->mask) != n->val) {
1531ce87720SJohn Fastabend 			n = rcu_dereference_bh(n->next);
1541da177e4SLinus Torvalds 			goto next_knode;
1551da177e4SLinus Torvalds 		} else {
156459d5f62SJohn Fastabend 			__this_cpu_inc(*n->pcpu_success);
1571da177e4SLinus Torvalds 		}
1581da177e4SLinus Torvalds #endif
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds 		for (i = n->sel.nkeys; i > 0; i--, key++) {
16166d50d25Sstephen hemminger 			int toff = off + key->off + (off2 & key->offmask);
16286fce3baSstephen hemminger 			__be32 *data, hdata;
1631da177e4SLinus Torvalds 
1644e18b3edSDan Carpenter 			if (skb_headroom(skb) + toff > INT_MAX)
16566d50d25Sstephen hemminger 				goto out;
16666d50d25Sstephen hemminger 
16786fce3baSstephen hemminger 			data = skb_header_pointer(skb, toff, 4, &hdata);
168fbc2e7d9SChangli Gao 			if (!data)
169fbc2e7d9SChangli Gao 				goto out;
170fbc2e7d9SChangli Gao 			if ((*data ^ key->val) & key->mask) {
1711ce87720SJohn Fastabend 				n = rcu_dereference_bh(n->next);
1721da177e4SLinus Torvalds 				goto next_knode;
1731da177e4SLinus Torvalds 			}
1741da177e4SLinus Torvalds #ifdef CONFIG_CLS_U32_PERF
175459d5f62SJohn Fastabend 			__this_cpu_inc(n->pf->kcnts[j]);
1761da177e4SLinus Torvalds 			j++;
1771da177e4SLinus Torvalds #endif
1781da177e4SLinus Torvalds 		}
1791ce87720SJohn Fastabend 
1801ce87720SJohn Fastabend 		ht = rcu_dereference_bh(n->ht_down);
1811ce87720SJohn Fastabend 		if (!ht) {
1821da177e4SLinus Torvalds check_terminal:
1831da177e4SLinus Torvalds 			if (n->sel.flags & TC_U32_TERMINAL) {
1841da177e4SLinus Torvalds 
1851da177e4SLinus Torvalds 				*res = n->res;
1862519a602SWANG Cong 				if (!tcf_match_indev(skb, n->ifindex)) {
1871ce87720SJohn Fastabend 					n = rcu_dereference_bh(n->next);
1881da177e4SLinus Torvalds 					goto next_knode;
1891da177e4SLinus Torvalds 				}
1901da177e4SLinus Torvalds #ifdef CONFIG_CLS_U32_PERF
191459d5f62SJohn Fastabend 				__this_cpu_inc(n->pf->rhit);
1921da177e4SLinus Torvalds #endif
1931da177e4SLinus Torvalds 				r = tcf_exts_exec(skb, &n->exts, res);
1941da177e4SLinus Torvalds 				if (r < 0) {
1951ce87720SJohn Fastabend 					n = rcu_dereference_bh(n->next);
1961da177e4SLinus Torvalds 					goto next_knode;
1971da177e4SLinus Torvalds 				}
1981da177e4SLinus Torvalds 
1991da177e4SLinus Torvalds 				return r;
2001da177e4SLinus Torvalds 			}
2011ce87720SJohn Fastabend 			n = rcu_dereference_bh(n->next);
2021da177e4SLinus Torvalds 			goto next_knode;
2031da177e4SLinus Torvalds 		}
2041da177e4SLinus Torvalds 
2051da177e4SLinus Torvalds 		/* PUSH */
2061da177e4SLinus Torvalds 		if (sdepth >= TC_U32_MAXDEPTH)
2071da177e4SLinus Torvalds 			goto deadloop;
2081da177e4SLinus Torvalds 		stack[sdepth].knode = n;
209fbc2e7d9SChangli Gao 		stack[sdepth].off = off;
2101da177e4SLinus Torvalds 		sdepth++;
2111da177e4SLinus Torvalds 
2121ce87720SJohn Fastabend 		ht = rcu_dereference_bh(n->ht_down);
2131da177e4SLinus Torvalds 		sel = 0;
214fbc2e7d9SChangli Gao 		if (ht->divisor) {
21586fce3baSstephen hemminger 			__be32 *data, hdata;
2161da177e4SLinus Torvalds 
217fbc2e7d9SChangli Gao 			data = skb_header_pointer(skb, off + n->sel.hoff, 4,
21886fce3baSstephen hemminger 						  &hdata);
219fbc2e7d9SChangli Gao 			if (!data)
220fbc2e7d9SChangli Gao 				goto out;
221fbc2e7d9SChangli Gao 			sel = ht->divisor & u32_hash_fold(*data, &n->sel,
222fbc2e7d9SChangli Gao 							  n->fshift);
223fbc2e7d9SChangli Gao 		}
2241da177e4SLinus Torvalds 		if (!(n->sel.flags & (TC_U32_VAROFFSET | TC_U32_OFFSET | TC_U32_EAT)))
2251da177e4SLinus Torvalds 			goto next_ht;
2261da177e4SLinus Torvalds 
2271da177e4SLinus Torvalds 		if (n->sel.flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
2281da177e4SLinus Torvalds 			off2 = n->sel.off + 3;
229fbc2e7d9SChangli Gao 			if (n->sel.flags & TC_U32_VAROFFSET) {
23086fce3baSstephen hemminger 				__be16 *data, hdata;
231fbc2e7d9SChangli Gao 
232fbc2e7d9SChangli Gao 				data = skb_header_pointer(skb,
233fbc2e7d9SChangli Gao 							  off + n->sel.offoff,
23486fce3baSstephen hemminger 							  2, &hdata);
235fbc2e7d9SChangli Gao 				if (!data)
236fbc2e7d9SChangli Gao 					goto out;
237fbc2e7d9SChangli Gao 				off2 += ntohs(n->sel.offmask & *data) >>
238fbc2e7d9SChangli Gao 					n->sel.offshift;
239fbc2e7d9SChangli Gao 			}
2401da177e4SLinus Torvalds 			off2 &= ~3;
2411da177e4SLinus Torvalds 		}
2421da177e4SLinus Torvalds 		if (n->sel.flags & TC_U32_EAT) {
243fbc2e7d9SChangli Gao 			off += off2;
2441da177e4SLinus Torvalds 			off2 = 0;
2451da177e4SLinus Torvalds 		}
2461da177e4SLinus Torvalds 
247fbc2e7d9SChangli Gao 		if (off < skb->len)
2481da177e4SLinus Torvalds 			goto next_ht;
2491da177e4SLinus Torvalds 	}
2501da177e4SLinus Torvalds 
2511da177e4SLinus Torvalds 	/* POP */
2521da177e4SLinus Torvalds 	if (sdepth--) {
2531da177e4SLinus Torvalds 		n = stack[sdepth].knode;
2541ce87720SJohn Fastabend 		ht = rcu_dereference_bh(n->ht_up);
255fbc2e7d9SChangli Gao 		off = stack[sdepth].off;
2561da177e4SLinus Torvalds 		goto check_terminal;
2571da177e4SLinus Torvalds 	}
258fbc2e7d9SChangli Gao out:
2591da177e4SLinus Torvalds 	return -1;
2601da177e4SLinus Torvalds 
2611da177e4SLinus Torvalds deadloop:
262e87cc472SJoe Perches 	net_warn_ratelimited("cls_u32: dead loop\n");
2631da177e4SLinus Torvalds 	return -1;
2641da177e4SLinus Torvalds }
2651da177e4SLinus Torvalds 
u32_lookup_ht(struct tc_u_common * tp_c,u32 handle)2665a7a5555SJamal Hadi Salim static struct tc_u_hnode *u32_lookup_ht(struct tc_u_common *tp_c, u32 handle)
2671da177e4SLinus Torvalds {
2681da177e4SLinus Torvalds 	struct tc_u_hnode *ht;
2691da177e4SLinus Torvalds 
2701ce87720SJohn Fastabend 	for (ht = rtnl_dereference(tp_c->hlist);
2711ce87720SJohn Fastabend 	     ht;
2721ce87720SJohn Fastabend 	     ht = rtnl_dereference(ht->next))
2731da177e4SLinus Torvalds 		if (ht->handle == handle)
2741da177e4SLinus Torvalds 			break;
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds 	return ht;
2771da177e4SLinus Torvalds }
2781da177e4SLinus Torvalds 
u32_lookup_key(struct tc_u_hnode * ht,u32 handle)2795a7a5555SJamal Hadi Salim static struct tc_u_knode *u32_lookup_key(struct tc_u_hnode *ht, u32 handle)
2801da177e4SLinus Torvalds {
281cc7ec456SEric Dumazet 	unsigned int sel;
2821da177e4SLinus Torvalds 	struct tc_u_knode *n = NULL;
2831da177e4SLinus Torvalds 
2841da177e4SLinus Torvalds 	sel = TC_U32_HASH(handle);
2851da177e4SLinus Torvalds 	if (sel > ht->divisor)
2861da177e4SLinus Torvalds 		goto out;
2871da177e4SLinus Torvalds 
2881ce87720SJohn Fastabend 	for (n = rtnl_dereference(ht->ht[sel]);
2891ce87720SJohn Fastabend 	     n;
2901ce87720SJohn Fastabend 	     n = rtnl_dereference(n->next))
2911da177e4SLinus Torvalds 		if (n->handle == handle)
2921da177e4SLinus Torvalds 			break;
2931da177e4SLinus Torvalds out:
2941da177e4SLinus Torvalds 	return n;
2951da177e4SLinus Torvalds }
2961da177e4SLinus Torvalds 
2971da177e4SLinus Torvalds 
u32_get(struct tcf_proto * tp,u32 handle)2988113c095SWANG Cong static void *u32_get(struct tcf_proto *tp, u32 handle)
2991da177e4SLinus Torvalds {
3001da177e4SLinus Torvalds 	struct tc_u_hnode *ht;
3011da177e4SLinus Torvalds 	struct tc_u_common *tp_c = tp->data;
3021da177e4SLinus Torvalds 
3031da177e4SLinus Torvalds 	if (TC_U32_HTID(handle) == TC_U32_ROOT)
3041ce87720SJohn Fastabend 		ht = rtnl_dereference(tp->root);
3051da177e4SLinus Torvalds 	else
3061da177e4SLinus Torvalds 		ht = u32_lookup_ht(tp_c, TC_U32_HTID(handle));
3071da177e4SLinus Torvalds 
3081da177e4SLinus Torvalds 	if (!ht)
3098113c095SWANG Cong 		return NULL;
3101da177e4SLinus Torvalds 
3111da177e4SLinus Torvalds 	if (TC_U32_KEY(handle) == 0)
3128113c095SWANG Cong 		return ht;
3131da177e4SLinus Torvalds 
3148113c095SWANG Cong 	return u32_lookup_key(ht, handle);
3151da177e4SLinus Torvalds }
3161da177e4SLinus Torvalds 
317ffdc2d9eSMatthew Wilcox /* Protected by rtnl lock */
gen_new_htid(struct tc_u_common * tp_c,struct tc_u_hnode * ptr)318e7614370SCong Wang static u32 gen_new_htid(struct tc_u_common *tp_c, struct tc_u_hnode *ptr)
3191da177e4SLinus Torvalds {
320ffdc2d9eSMatthew Wilcox 	int id = idr_alloc_cyclic(&tp_c->handle_idr, ptr, 1, 0x7FF, GFP_KERNEL);
321ffdc2d9eSMatthew Wilcox 	if (id < 0)
322e7614370SCong Wang 		return 0;
323*789f9963SAlexandre Ferrieux 	return id2handle(id);
3241da177e4SLinus Torvalds }
3251da177e4SLinus Torvalds 
3263cd904ecSWANG Cong static struct hlist_head *tc_u_common_hash;
3273cd904ecSWANG Cong 
3283cd904ecSWANG Cong #define U32_HASH_SHIFT 10
3293cd904ecSWANG Cong #define U32_HASH_SIZE (1 << U32_HASH_SHIFT)
3303cd904ecSWANG Cong 
tc_u_common_ptr(const struct tcf_proto * tp)331339c21d7SJiri Pirko static void *tc_u_common_ptr(const struct tcf_proto *tp)
332339c21d7SJiri Pirko {
333339c21d7SJiri Pirko 	struct tcf_block *block = tp->chain->block;
334339c21d7SJiri Pirko 
335339c21d7SJiri Pirko 	/* The block sharing is currently supported only
336339c21d7SJiri Pirko 	 * for classless qdiscs. In that case we use block
337339c21d7SJiri Pirko 	 * for tc_u_common identification. In case the
338339c21d7SJiri Pirko 	 * block is not shared, block->q is a valid pointer
339339c21d7SJiri Pirko 	 * and we can use that. That works for classful qdiscs.
340339c21d7SJiri Pirko 	 */
341339c21d7SJiri Pirko 	if (tcf_block_shared(block))
342339c21d7SJiri Pirko 		return block;
343339c21d7SJiri Pirko 	else
344339c21d7SJiri Pirko 		return block->q;
345339c21d7SJiri Pirko }
346339c21d7SJiri Pirko 
tc_u_hash(void * key)3474895c42fSAl Viro static struct hlist_head *tc_u_hash(void *key)
3483cd904ecSWANG Cong {
3494895c42fSAl Viro 	return tc_u_common_hash + hash_ptr(key, U32_HASH_SHIFT);
3503cd904ecSWANG Cong }
3513cd904ecSWANG Cong 
tc_u_common_find(void * key)3524895c42fSAl Viro static struct tc_u_common *tc_u_common_find(void *key)
3533cd904ecSWANG Cong {
3543cd904ecSWANG Cong 	struct tc_u_common *tc;
3554895c42fSAl Viro 	hlist_for_each_entry(tc, tc_u_hash(key), hnode) {
3564895c42fSAl Viro 		if (tc->ptr == key)
3573cd904ecSWANG Cong 			return tc;
3583cd904ecSWANG Cong 	}
3593cd904ecSWANG Cong 	return NULL;
3603cd904ecSWANG Cong }
3613cd904ecSWANG Cong 
u32_init(struct tcf_proto * tp)3621da177e4SLinus Torvalds static int u32_init(struct tcf_proto *tp)
3631da177e4SLinus Torvalds {
3641da177e4SLinus Torvalds 	struct tc_u_hnode *root_ht;
3654895c42fSAl Viro 	void *key = tc_u_common_ptr(tp);
3664895c42fSAl Viro 	struct tc_u_common *tp_c = tc_u_common_find(key);
3671da177e4SLinus Torvalds 
368d61491a5SGustavo A. R. Silva 	root_ht = kzalloc(struct_size(root_ht, ht, 1), GFP_KERNEL);
3691da177e4SLinus Torvalds 	if (root_ht == NULL)
3701da177e4SLinus Torvalds 		return -ENOBUFS;
3711da177e4SLinus Torvalds 
3729fd5661aSPedro Tammela 	refcount_set(&root_ht->refcnt, 1);
373*789f9963SAlexandre Ferrieux 	root_ht->handle = tp_c ? gen_new_htid(tp_c, root_ht) : id2handle(0);
3741da177e4SLinus Torvalds 	root_ht->prio = tp->prio;
375b44ef845SAl Viro 	root_ht->is_root = true;
376e7614370SCong Wang 	idr_init(&root_ht->handle_idr);
3771da177e4SLinus Torvalds 
3781da177e4SLinus Torvalds 	if (tp_c == NULL) {
379c4d49196SGustavo A. R. Silva 		tp_c = kzalloc(sizeof(*tp_c), GFP_KERNEL);
3801da177e4SLinus Torvalds 		if (tp_c == NULL) {
3811da177e4SLinus Torvalds 			kfree(root_ht);
3821da177e4SLinus Torvalds 			return -ENOBUFS;
3831da177e4SLinus Torvalds 		}
3849fd5661aSPedro Tammela 		refcount_set(&tp_c->refcnt, 1);
3854895c42fSAl Viro 		tp_c->ptr = key;
3863cd904ecSWANG Cong 		INIT_HLIST_NODE(&tp_c->hnode);
387e7614370SCong Wang 		idr_init(&tp_c->handle_idr);
3883cd904ecSWANG Cong 
3894895c42fSAl Viro 		hlist_add_head(&tp_c->hnode, tc_u_hash(key));
3909fd5661aSPedro Tammela 	} else {
3919fd5661aSPedro Tammela 		refcount_inc(&tp_c->refcnt);
3921da177e4SLinus Torvalds 	}
3931da177e4SLinus Torvalds 
3941ce87720SJohn Fastabend 	RCU_INIT_POINTER(root_ht->next, tp_c->hlist);
3951ce87720SJohn Fastabend 	rcu_assign_pointer(tp_c->hlist, root_ht);
3961da177e4SLinus Torvalds 
3979fd5661aSPedro Tammela 	/* root_ht must be destroyed when tcf_proto is destroyed */
3981ce87720SJohn Fastabend 	rcu_assign_pointer(tp->root, root_ht);
3991da177e4SLinus Torvalds 	tp->data = tp_c;
4001da177e4SLinus Torvalds 	return 0;
4011da177e4SLinus Torvalds }
4021da177e4SLinus Torvalds 
__u32_destroy_key(struct tc_u_knode * n)4033db09e76SEric Dumazet static void __u32_destroy_key(struct tc_u_knode *n)
4041da177e4SLinus Torvalds {
405d7cdee5eSPaolo Abeni 	struct tc_u_hnode *ht = rtnl_dereference(n->ht_down);
406d7cdee5eSPaolo Abeni 
40718d0264fSWANG Cong 	tcf_exts_destroy(&n->exts);
4089fd5661aSPedro Tammela 	if (ht && refcount_dec_and_test(&ht->refcnt))
409d7cdee5eSPaolo Abeni 		kfree(ht);
4103db09e76SEric Dumazet 	kfree(n);
4113db09e76SEric Dumazet }
4123db09e76SEric Dumazet 
u32_destroy_key(struct tc_u_knode * n,bool free_pf)4133db09e76SEric Dumazet static void u32_destroy_key(struct tc_u_knode *n, bool free_pf)
4143db09e76SEric Dumazet {
4153db09e76SEric Dumazet 	tcf_exts_put_net(&n->exts);
4161da177e4SLinus Torvalds #ifdef CONFIG_CLS_U32_PERF
417de5df632SJohn Fastabend 	if (free_pf)
418459d5f62SJohn Fastabend 		free_percpu(n->pf);
4191da177e4SLinus Torvalds #endif
420a1ddcfeeSJohn Fastabend #ifdef CONFIG_CLS_U32_MARK
421de5df632SJohn Fastabend 	if (free_pf)
422a1ddcfeeSJohn Fastabend 		free_percpu(n->pcpu_success);
423a1ddcfeeSJohn Fastabend #endif
4243db09e76SEric Dumazet 	__u32_destroy_key(n);
4251da177e4SLinus Torvalds }
4261da177e4SLinus Torvalds 
427de5df632SJohn Fastabend /* u32_delete_key_rcu should be called when free'ing a copied
428de5df632SJohn Fastabend  * version of a tc_u_knode obtained from u32_init_knode(). When
429de5df632SJohn Fastabend  * copies are obtained from u32_init_knode() the statistics are
430de5df632SJohn Fastabend  * shared between the old and new copies to allow readers to
431de5df632SJohn Fastabend  * continue to update the statistics during the copy. To support
432de5df632SJohn Fastabend  * this the u32_delete_key_rcu variant does not free the percpu
433de5df632SJohn Fastabend  * statistics.
434de5df632SJohn Fastabend  */
u32_delete_key_work(struct work_struct * work)435c0d378efSCong Wang static void u32_delete_key_work(struct work_struct *work)
436c0d378efSCong Wang {
437aaa908ffSCong Wang 	struct tc_u_knode *key = container_of(to_rcu_work(work),
438aaa908ffSCong Wang 					      struct tc_u_knode,
439aaa908ffSCong Wang 					      rwork);
440c0d378efSCong Wang 	rtnl_lock();
441dc07c573SAl Viro 	u32_destroy_key(key, false);
442c0d378efSCong Wang 	rtnl_unlock();
443c0d378efSCong Wang }
444c0d378efSCong Wang 
445de5df632SJohn Fastabend /* u32_delete_key_freepf_rcu is the rcu callback variant
446de5df632SJohn Fastabend  * that free's the entire structure including the statistics
447de5df632SJohn Fastabend  * percpu variables. Only use this if the key is not a copy
448de5df632SJohn Fastabend  * returned by u32_init_knode(). See u32_delete_key_rcu()
449de5df632SJohn Fastabend  * for the variant that should be used with keys return from
450de5df632SJohn Fastabend  * u32_init_knode()
451de5df632SJohn Fastabend  */
u32_delete_key_freepf_work(struct work_struct * work)452c0d378efSCong Wang static void u32_delete_key_freepf_work(struct work_struct *work)
453c0d378efSCong Wang {
454aaa908ffSCong Wang 	struct tc_u_knode *key = container_of(to_rcu_work(work),
455aaa908ffSCong Wang 					      struct tc_u_knode,
456aaa908ffSCong Wang 					      rwork);
457c0d378efSCong Wang 	rtnl_lock();
458dc07c573SAl Viro 	u32_destroy_key(key, true);
459c0d378efSCong Wang 	rtnl_unlock();
460c0d378efSCong Wang }
461c0d378efSCong Wang 
u32_delete_key(struct tcf_proto * tp,struct tc_u_knode * key)4621da177e4SLinus Torvalds static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key)
4631da177e4SLinus Torvalds {
464b245d32cSAl Viro 	struct tc_u_common *tp_c = tp->data;
4651ce87720SJohn Fastabend 	struct tc_u_knode __rcu **kp;
4661ce87720SJohn Fastabend 	struct tc_u_knode *pkp;
467a96366bfSJohn Fastabend 	struct tc_u_hnode *ht = rtnl_dereference(key->ht_up);
4681da177e4SLinus Torvalds 
4691da177e4SLinus Torvalds 	if (ht) {
4701ce87720SJohn Fastabend 		kp = &ht->ht[TC_U32_HASH(key->handle)];
4711ce87720SJohn Fastabend 		for (pkp = rtnl_dereference(*kp); pkp;
4721ce87720SJohn Fastabend 		     kp = &pkp->next, pkp = rtnl_dereference(*kp)) {
4731ce87720SJohn Fastabend 			if (pkp == key) {
4741ce87720SJohn Fastabend 				RCU_INIT_POINTER(*kp, key->next);
475b245d32cSAl Viro 				tp_c->knodes--;
4761da177e4SLinus Torvalds 
477a0efb80cSWANG Cong 				tcf_unbind_filter(tp, &key->res);
478f12c6432SCong Wang 				idr_remove(&ht->handle_idr, key->handle);
47935c55fc1SCong Wang 				tcf_exts_get_net(&key->exts);
480aaa908ffSCong Wang 				tcf_queue_work(&key->rwork, u32_delete_key_freepf_work);
4811da177e4SLinus Torvalds 				return 0;
4821da177e4SLinus Torvalds 			}
4831da177e4SLinus Torvalds 		}
4841da177e4SLinus Torvalds 	}
485547b792cSIlpo Järvinen 	WARN_ON(1);
4861da177e4SLinus Torvalds 	return 0;
4871da177e4SLinus Torvalds }
4881da177e4SLinus Torvalds 
u32_clear_hw_hnode(struct tcf_proto * tp,struct tc_u_hnode * h,struct netlink_ext_ack * extack)489458e704dSJakub Kicinski static void u32_clear_hw_hnode(struct tcf_proto *tp, struct tc_u_hnode *h,
490458e704dSJakub Kicinski 			       struct netlink_ext_ack *extack)
491a1b7c5fdSJohn Fastabend {
492245dc512SJiri Pirko 	struct tcf_block *block = tp->chain->block;
493de4784caSJiri Pirko 	struct tc_cls_u32_offload cls_u32 = {};
494a1b7c5fdSJohn Fastabend 
495d6787147SPieter Jansen van Vuuren 	tc_cls_common_offload_init(&cls_u32.common, tp, h->flags, extack);
49677460411SJiri Pirko 	cls_u32.command = TC_CLSU32_DELETE_HNODE;
49777460411SJiri Pirko 	cls_u32.hnode.divisor = h->divisor;
49877460411SJiri Pirko 	cls_u32.hnode.handle = h->handle;
49977460411SJiri Pirko 	cls_u32.hnode.prio = h->prio;
500de4784caSJiri Pirko 
50140119211SVlad Buslov 	tc_setup_cb_call(block, TC_SETUP_CLSU32, &cls_u32, false, true);
502a1b7c5fdSJohn Fastabend }
503a1b7c5fdSJohn Fastabend 
u32_replace_hw_hnode(struct tcf_proto * tp,struct tc_u_hnode * h,u32 flags,struct netlink_ext_ack * extack)5045a7a5555SJamal Hadi Salim static int u32_replace_hw_hnode(struct tcf_proto *tp, struct tc_u_hnode *h,
50510a47e0fSQuentin Monnet 				u32 flags, struct netlink_ext_ack *extack)
506a1b7c5fdSJohn Fastabend {
507245dc512SJiri Pirko 	struct tcf_block *block = tp->chain->block;
508de4784caSJiri Pirko 	struct tc_cls_u32_offload cls_u32 = {};
509245dc512SJiri Pirko 	bool skip_sw = tc_skip_sw(flags);
510245dc512SJiri Pirko 	bool offloaded = false;
511d34e3e18SSamudrala, Sridhar 	int err;
512a1b7c5fdSJohn Fastabend 
513d6787147SPieter Jansen van Vuuren 	tc_cls_common_offload_init(&cls_u32.common, tp, flags, extack);
514de4784caSJiri Pirko 	cls_u32.command = TC_CLSU32_NEW_HNODE;
515de4784caSJiri Pirko 	cls_u32.hnode.divisor = h->divisor;
516de4784caSJiri Pirko 	cls_u32.hnode.handle = h->handle;
517de4784caSJiri Pirko 	cls_u32.hnode.prio = h->prio;
518a1b7c5fdSJohn Fastabend 
51940119211SVlad Buslov 	err = tc_setup_cb_call(block, TC_SETUP_CLSU32, &cls_u32, skip_sw, true);
520245dc512SJiri Pirko 	if (err < 0) {
521458e704dSJakub Kicinski 		u32_clear_hw_hnode(tp, h, NULL);
522245dc512SJiri Pirko 		return err;
523245dc512SJiri Pirko 	} else if (err > 0) {
524245dc512SJiri Pirko 		offloaded = true;
525245dc512SJiri Pirko 	}
526245dc512SJiri Pirko 
527245dc512SJiri Pirko 	if (skip_sw && !offloaded)
528245dc512SJiri Pirko 		return -EINVAL;
529d34e3e18SSamudrala, Sridhar 
530d34e3e18SSamudrala, Sridhar 	return 0;
531a1b7c5fdSJohn Fastabend }
532a1b7c5fdSJohn Fastabend 
u32_remove_hw_knode(struct tcf_proto * tp,struct tc_u_knode * n,struct netlink_ext_ack * extack)533458e704dSJakub Kicinski static void u32_remove_hw_knode(struct tcf_proto *tp, struct tc_u_knode *n,
534458e704dSJakub Kicinski 				struct netlink_ext_ack *extack)
535a1b7c5fdSJohn Fastabend {
536245dc512SJiri Pirko 	struct tcf_block *block = tp->chain->block;
537de4784caSJiri Pirko 	struct tc_cls_u32_offload cls_u32 = {};
538a1b7c5fdSJohn Fastabend 
539d6787147SPieter Jansen van Vuuren 	tc_cls_common_offload_init(&cls_u32.common, tp, n->flags, extack);
54077460411SJiri Pirko 	cls_u32.command = TC_CLSU32_DELETE_KNODE;
541caa72601SJiri Pirko 	cls_u32.knode.handle = n->handle;
542a1b7c5fdSJohn Fastabend 
54340119211SVlad Buslov 	tc_setup_cb_destroy(block, tp, TC_SETUP_CLSU32, &cls_u32, false,
54440119211SVlad Buslov 			    &n->flags, &n->in_hw_count, true);
545a1b7c5fdSJohn Fastabend }
546a1b7c5fdSJohn Fastabend 
u32_replace_hw_knode(struct tcf_proto * tp,struct tc_u_knode * n,u32 flags,struct netlink_ext_ack * extack)5475a7a5555SJamal Hadi Salim static int u32_replace_hw_knode(struct tcf_proto *tp, struct tc_u_knode *n,
54810a47e0fSQuentin Monnet 				u32 flags, struct netlink_ext_ack *extack)
549a1b7c5fdSJohn Fastabend {
550058a6c03SPaolo Abeni 	struct tc_u_hnode *ht = rtnl_dereference(n->ht_down);
551245dc512SJiri Pirko 	struct tcf_block *block = tp->chain->block;
552de4784caSJiri Pirko 	struct tc_cls_u32_offload cls_u32 = {};
553245dc512SJiri Pirko 	bool skip_sw = tc_skip_sw(flags);
554d34e3e18SSamudrala, Sridhar 	int err;
555a1b7c5fdSJohn Fastabend 
556d6787147SPieter Jansen van Vuuren 	tc_cls_common_offload_init(&cls_u32.common, tp, flags, extack);
557de4784caSJiri Pirko 	cls_u32.command = TC_CLSU32_REPLACE_KNODE;
558de4784caSJiri Pirko 	cls_u32.knode.handle = n->handle;
559de4784caSJiri Pirko 	cls_u32.knode.fshift = n->fshift;
560a1b7c5fdSJohn Fastabend #ifdef CONFIG_CLS_U32_MARK
561de4784caSJiri Pirko 	cls_u32.knode.val = n->val;
562de4784caSJiri Pirko 	cls_u32.knode.mask = n->mask;
563a1b7c5fdSJohn Fastabend #else
564de4784caSJiri Pirko 	cls_u32.knode.val = 0;
565de4784caSJiri Pirko 	cls_u32.knode.mask = 0;
566a1b7c5fdSJohn Fastabend #endif
567de4784caSJiri Pirko 	cls_u32.knode.sel = &n->sel;
568068ceb35SJakub Kicinski 	cls_u32.knode.res = &n->res;
569de4784caSJiri Pirko 	cls_u32.knode.exts = &n->exts;
570a1b7c5fdSJohn Fastabend 	if (n->ht_down)
571058a6c03SPaolo Abeni 		cls_u32.knode.link_handle = ht->handle;
572a1b7c5fdSJohn Fastabend 
57340119211SVlad Buslov 	err = tc_setup_cb_add(block, tp, TC_SETUP_CLSU32, &cls_u32, skip_sw,
57440119211SVlad Buslov 			      &n->flags, &n->in_hw_count, true);
57540119211SVlad Buslov 	if (err) {
576458e704dSJakub Kicinski 		u32_remove_hw_knode(tp, n, NULL);
577245dc512SJiri Pirko 		return err;
578245dc512SJiri Pirko 	}
579245dc512SJiri Pirko 
5800f04d057SColin Ian King 	if (skip_sw && !(n->flags & TCA_CLS_FLAGS_IN_HW))
581245dc512SJiri Pirko 		return -EINVAL;
582d34e3e18SSamudrala, Sridhar 
583d34e3e18SSamudrala, Sridhar 	return 0;
584a1b7c5fdSJohn Fastabend }
585a1b7c5fdSJohn Fastabend 
u32_clear_hnode(struct tcf_proto * tp,struct tc_u_hnode * ht,struct netlink_ext_ack * extack)586458e704dSJakub Kicinski static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht,
587458e704dSJakub Kicinski 			    struct netlink_ext_ack *extack)
5881da177e4SLinus Torvalds {
589b245d32cSAl Viro 	struct tc_u_common *tp_c = tp->data;
5901da177e4SLinus Torvalds 	struct tc_u_knode *n;
591cc7ec456SEric Dumazet 	unsigned int h;
5921da177e4SLinus Torvalds 
5931da177e4SLinus Torvalds 	for (h = 0; h <= ht->divisor; h++) {
5941ce87720SJohn Fastabend 		while ((n = rtnl_dereference(ht->ht[h])) != NULL) {
5951ce87720SJohn Fastabend 			RCU_INIT_POINTER(ht->ht[h],
5961ce87720SJohn Fastabend 					 rtnl_dereference(n->next));
597b245d32cSAl Viro 			tp_c->knodes--;
598a0efb80cSWANG Cong 			tcf_unbind_filter(tp, &n->res);
599458e704dSJakub Kicinski 			u32_remove_hw_knode(tp, n, extack);
6009c160941SMatthew Wilcox 			idr_remove(&ht->handle_idr, n->handle);
60135c55fc1SCong Wang 			if (tcf_exts_get_net(&n->exts))
602aaa908ffSCong Wang 				tcf_queue_work(&n->rwork, u32_delete_key_freepf_work);
60335c55fc1SCong Wang 			else
604dc07c573SAl Viro 				u32_destroy_key(n, true);
6051da177e4SLinus Torvalds 		}
6061da177e4SLinus Torvalds 	}
6071da177e4SLinus Torvalds }
6081da177e4SLinus Torvalds 
u32_destroy_hnode(struct tcf_proto * tp,struct tc_u_hnode * ht,struct netlink_ext_ack * extack)609458e704dSJakub Kicinski static int u32_destroy_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht,
610458e704dSJakub Kicinski 			     struct netlink_ext_ack *extack)
6111da177e4SLinus Torvalds {
6121da177e4SLinus Torvalds 	struct tc_u_common *tp_c = tp->data;
6131ce87720SJohn Fastabend 	struct tc_u_hnode __rcu **hn;
6141ce87720SJohn Fastabend 	struct tc_u_hnode *phn;
6151da177e4SLinus Torvalds 
616458e704dSJakub Kicinski 	u32_clear_hnode(tp, ht, extack);
6171da177e4SLinus Torvalds 
6181ce87720SJohn Fastabend 	hn = &tp_c->hlist;
6191ce87720SJohn Fastabend 	for (phn = rtnl_dereference(*hn);
6201ce87720SJohn Fastabend 	     phn;
6211ce87720SJohn Fastabend 	     hn = &phn->next, phn = rtnl_dereference(*hn)) {
6221ce87720SJohn Fastabend 		if (phn == ht) {
623458e704dSJakub Kicinski 			u32_clear_hw_hnode(tp, ht, extack);
624e7614370SCong Wang 			idr_destroy(&ht->handle_idr);
625*789f9963SAlexandre Ferrieux 			idr_remove(&tp_c->handle_idr, handle2id(ht->handle));
6261ce87720SJohn Fastabend 			RCU_INIT_POINTER(*hn, ht->next);
6271ce87720SJohn Fastabend 			kfree_rcu(ht, rcu);
6281da177e4SLinus Torvalds 			return 0;
6291da177e4SLinus Torvalds 		}
6301da177e4SLinus Torvalds 	}
6311da177e4SLinus Torvalds 
6321da177e4SLinus Torvalds 	return -ENOENT;
6331da177e4SLinus Torvalds }
6341da177e4SLinus Torvalds 
u32_destroy(struct tcf_proto * tp,bool rtnl_held,struct netlink_ext_ack * extack)63512db03b6SVlad Buslov static void u32_destroy(struct tcf_proto *tp, bool rtnl_held,
63612db03b6SVlad Buslov 			struct netlink_ext_ack *extack)
6371da177e4SLinus Torvalds {
6381da177e4SLinus Torvalds 	struct tc_u_common *tp_c = tp->data;
6391ce87720SJohn Fastabend 	struct tc_u_hnode *root_ht = rtnl_dereference(tp->root);
6401da177e4SLinus Torvalds 
641547b792cSIlpo Järvinen 	WARN_ON(root_ht == NULL);
6421da177e4SLinus Torvalds 
6439fd5661aSPedro Tammela 	if (root_ht && refcount_dec_and_test(&root_ht->refcnt))
644458e704dSJakub Kicinski 		u32_destroy_hnode(tp, root_ht, extack);
6451da177e4SLinus Torvalds 
6469fd5661aSPedro Tammela 	if (refcount_dec_and_test(&tp_c->refcnt)) {
6471da177e4SLinus Torvalds 		struct tc_u_hnode *ht;
6481da177e4SLinus Torvalds 
6493cd904ecSWANG Cong 		hlist_del(&tp_c->hnode);
6501da177e4SLinus Torvalds 
6511ce87720SJohn Fastabend 		while ((ht = rtnl_dereference(tp_c->hlist)) != NULL) {
652d7cdee5eSPaolo Abeni 			u32_clear_hnode(tp, ht, extack);
6531ce87720SJohn Fastabend 			RCU_INIT_POINTER(tp_c->hlist, ht->next);
654d7cdee5eSPaolo Abeni 
655d7cdee5eSPaolo Abeni 			/* u32_destroy_key() will later free ht for us, if it's
656d7cdee5eSPaolo Abeni 			 * still referenced by some knode
657d7cdee5eSPaolo Abeni 			 */
6589fd5661aSPedro Tammela 			if (refcount_dec_and_test(&ht->refcnt))
6591ce87720SJohn Fastabend 				kfree_rcu(ht, rcu);
6603ff50b79SStephen Hemminger 		}
6611da177e4SLinus Torvalds 
662e7614370SCong Wang 		idr_destroy(&tp_c->handle_idr);
6631da177e4SLinus Torvalds 		kfree(tp_c);
6641da177e4SLinus Torvalds 	}
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds 	tp->data = NULL;
6671da177e4SLinus Torvalds }
6681da177e4SLinus Torvalds 
u32_delete(struct tcf_proto * tp,void * arg,bool * last,bool rtnl_held,struct netlink_ext_ack * extack)669571acf21SAlexander Aring static int u32_delete(struct tcf_proto *tp, void *arg, bool *last,
67012db03b6SVlad Buslov 		      bool rtnl_held, struct netlink_ext_ack *extack)
6711da177e4SLinus Torvalds {
6728113c095SWANG Cong 	struct tc_u_hnode *ht = arg;
673763dbf63SWANG Cong 	struct tc_u_common *tp_c = tp->data;
674763dbf63SWANG Cong 	int ret = 0;
6751da177e4SLinus Torvalds 
676a1b7c5fdSJohn Fastabend 	if (TC_U32_KEY(ht->handle)) {
677458e704dSJakub Kicinski 		u32_remove_hw_knode(tp, (struct tc_u_knode *)ht, extack);
678763dbf63SWANG Cong 		ret = u32_delete_key(tp, (struct tc_u_knode *)ht);
679763dbf63SWANG Cong 		goto out;
680a1b7c5fdSJohn Fastabend 	}
6811da177e4SLinus Torvalds 
682b44ef845SAl Viro 	if (ht->is_root) {
6834b981dbcSAlexander Aring 		NL_SET_ERR_MSG_MOD(extack, "Not allowed to delete root node");
6841da177e4SLinus Torvalds 		return -EINVAL;
6854b981dbcSAlexander Aring 	}
6861da177e4SLinus Torvalds 
6879fd5661aSPedro Tammela 	if (refcount_dec_if_one(&ht->refcnt)) {
688458e704dSJakub Kicinski 		u32_destroy_hnode(tp, ht, extack);
689e56cfad1SJarek Poplawski 	} else {
6904b981dbcSAlexander Aring 		NL_SET_ERR_MSG_MOD(extack, "Can not delete in-use filter");
691e56cfad1SJarek Poplawski 		return -EBUSY;
692e56cfad1SJarek Poplawski 	}
6931da177e4SLinus Torvalds 
694763dbf63SWANG Cong out:
6959fd5661aSPedro Tammela 	*last = refcount_read(&tp_c->refcnt) == 1 && tp_c->knodes == 0;
696763dbf63SWANG Cong 	return ret;
6971da177e4SLinus Torvalds }
6981da177e4SLinus Torvalds 
gen_new_kid(struct tc_u_hnode * ht,u32 htid)699e7614370SCong Wang static u32 gen_new_kid(struct tc_u_hnode *ht, u32 htid)
7001da177e4SLinus Torvalds {
701f730cb93SMatthew Wilcox 	u32 index = htid | 0x800;
702e7614370SCong Wang 	u32 max = htid | 0xFFF;
7031da177e4SLinus Torvalds 
704f730cb93SMatthew Wilcox 	if (idr_alloc_u32(&ht->handle_idr, NULL, &index, max, GFP_KERNEL)) {
705f730cb93SMatthew Wilcox 		index = htid + 1;
706f730cb93SMatthew Wilcox 		if (idr_alloc_u32(&ht->handle_idr, NULL, &index, max,
707f730cb93SMatthew Wilcox 				 GFP_KERNEL))
708f730cb93SMatthew Wilcox 			index = max;
709e7614370SCong Wang 	}
7101da177e4SLinus Torvalds 
711f730cb93SMatthew Wilcox 	return index;
7121da177e4SLinus Torvalds }
7131da177e4SLinus Torvalds 
7146fa8c014SPatrick McHardy static const struct nla_policy u32_policy[TCA_U32_MAX + 1] = {
7156fa8c014SPatrick McHardy 	[TCA_U32_CLASSID]	= { .type = NLA_U32 },
7166fa8c014SPatrick McHardy 	[TCA_U32_HASH]		= { .type = NLA_U32 },
7176fa8c014SPatrick McHardy 	[TCA_U32_LINK]		= { .type = NLA_U32 },
7186fa8c014SPatrick McHardy 	[TCA_U32_DIVISOR]	= { .type = NLA_U32 },
7196fa8c014SPatrick McHardy 	[TCA_U32_SEL]		= { .len = sizeof(struct tc_u32_sel) },
7206fa8c014SPatrick McHardy 	[TCA_U32_INDEV]		= { .type = NLA_STRING, .len = IFNAMSIZ },
7216fa8c014SPatrick McHardy 	[TCA_U32_MARK]		= { .len = sizeof(struct tc_u32_mark) },
7229e8ce79cSJohn Fastabend 	[TCA_U32_FLAGS]		= { .type = NLA_U32 },
7236fa8c014SPatrick McHardy };
7246fa8c014SPatrick McHardy 
u32_unbind_filter(struct tcf_proto * tp,struct tc_u_knode * n,struct nlattr ** tb)7259cb36faeSVictor Nogueira static void u32_unbind_filter(struct tcf_proto *tp, struct tc_u_knode *n,
7269cb36faeSVictor Nogueira 			      struct nlattr **tb)
7279cb36faeSVictor Nogueira {
7289cb36faeSVictor Nogueira 	if (tb[TCA_U32_CLASSID])
7299cb36faeSVictor Nogueira 		tcf_unbind_filter(tp, &n->res);
7309cb36faeSVictor Nogueira }
7319cb36faeSVictor Nogueira 
u32_bind_filter(struct tcf_proto * tp,struct tc_u_knode * n,unsigned long base,struct nlattr ** tb)7329cb36faeSVictor Nogueira static void u32_bind_filter(struct tcf_proto *tp, struct tc_u_knode *n,
7339cb36faeSVictor Nogueira 			    unsigned long base, struct nlattr **tb)
7349cb36faeSVictor Nogueira {
7359cb36faeSVictor Nogueira 	if (tb[TCA_U32_CLASSID]) {
7369cb36faeSVictor Nogueira 		n->res.classid = nla_get_u32(tb[TCA_U32_CLASSID]);
7379cb36faeSVictor Nogueira 		tcf_bind_filter(tp, &n->res, base);
7389cb36faeSVictor Nogueira 	}
7399cb36faeSVictor Nogueira }
7409cb36faeSVictor Nogueira 
u32_set_parms(struct net * net,struct tcf_proto * tp,struct tc_u_knode * n,struct nlattr ** tb,struct nlattr * est,u32 flags,u32 fl_flags,struct netlink_ext_ack * extack)741c1b52739SBenjamin LaHaise static int u32_set_parms(struct net *net, struct tcf_proto *tp,
742add93b61SPatrick McHardy 			 struct tc_u_knode *n, struct nlattr **tb,
743c86e0209SBaowen Zheng 			 struct nlattr *est, u32 flags, u32 fl_flags,
74450a56190SAlexander Aring 			 struct netlink_ext_ack *extack)
7451da177e4SLinus Torvalds {
74604c55383SLee Jones 	int err, ifindex = -1;
7471da177e4SLinus Torvalds 
748c86e0209SBaowen Zheng 	err = tcf_exts_validate_ex(net, tp, tb, est, &n->exts, flags,
749c86e0209SBaowen Zheng 				   fl_flags, extack);
7501da177e4SLinus Torvalds 	if (err < 0)
7511da177e4SLinus Torvalds 		return err;
7521da177e4SLinus Torvalds 
75304c55383SLee Jones 	if (tb[TCA_U32_INDEV]) {
75404c55383SLee Jones 		ifindex = tcf_change_indev(net, tb[TCA_U32_INDEV], extack);
75504c55383SLee Jones 		if (ifindex < 0)
75604c55383SLee Jones 			return -EINVAL;
75704c55383SLee Jones 	}
75804c55383SLee Jones 
759add93b61SPatrick McHardy 	if (tb[TCA_U32_LINK]) {
7601587bac4SPatrick McHardy 		u32 handle = nla_get_u32(tb[TCA_U32_LINK]);
76147a1a1d4SPatrick McHardy 		struct tc_u_hnode *ht_down = NULL, *ht_old;
7621da177e4SLinus Torvalds 
7634b981dbcSAlexander Aring 		if (TC_U32_KEY(handle)) {
7644b981dbcSAlexander Aring 			NL_SET_ERR_MSG_MOD(extack, "u32 Link handle must be a hash table");
765705c7091SJiri Pirko 			return -EINVAL;
7664b981dbcSAlexander Aring 		}
7671da177e4SLinus Torvalds 
7681da177e4SLinus Torvalds 		if (handle) {
7698a8065f6SAl Viro 			ht_down = u32_lookup_ht(tp->data, handle);
7701da177e4SLinus Torvalds 
7714b981dbcSAlexander Aring 			if (!ht_down) {
7724b981dbcSAlexander Aring 				NL_SET_ERR_MSG_MOD(extack, "Link hash table not found");
773705c7091SJiri Pirko 				return -EINVAL;
7744b981dbcSAlexander Aring 			}
77527594ec4SAl Viro 			if (ht_down->is_root) {
77627594ec4SAl Viro 				NL_SET_ERR_MSG_MOD(extack, "Not linking to root node");
77727594ec4SAl Viro 				return -EINVAL;
77827594ec4SAl Viro 			}
7799fd5661aSPedro Tammela 			refcount_inc(&ht_down->refcnt);
7801da177e4SLinus Torvalds 		}
7811da177e4SLinus Torvalds 
7821ce87720SJohn Fastabend 		ht_old = rtnl_dereference(n->ht_down);
7831ce87720SJohn Fastabend 		rcu_assign_pointer(n->ht_down, ht_down);
7841da177e4SLinus Torvalds 
78547a1a1d4SPatrick McHardy 		if (ht_old)
7869fd5661aSPedro Tammela 			refcount_dec(&ht_old->refcnt);
7871da177e4SLinus Torvalds 	}
7881da177e4SLinus Torvalds 
78904c55383SLee Jones 	if (ifindex >= 0)
79004c55383SLee Jones 		n->ifindex = ifindex;
79104c55383SLee Jones 
7921da177e4SLinus Torvalds 	return 0;
7931da177e4SLinus Torvalds }
7941da177e4SLinus Torvalds 
u32_replace_knode(struct tcf_proto * tp,struct tc_u_common * tp_c,struct tc_u_knode * n)7955a7a5555SJamal Hadi Salim static void u32_replace_knode(struct tcf_proto *tp, struct tc_u_common *tp_c,
796de5df632SJohn Fastabend 			      struct tc_u_knode *n)
797de5df632SJohn Fastabend {
798de5df632SJohn Fastabend 	struct tc_u_knode __rcu **ins;
799de5df632SJohn Fastabend 	struct tc_u_knode *pins;
800de5df632SJohn Fastabend 	struct tc_u_hnode *ht;
801de5df632SJohn Fastabend 
802de5df632SJohn Fastabend 	if (TC_U32_HTID(n->handle) == TC_U32_ROOT)
803de5df632SJohn Fastabend 		ht = rtnl_dereference(tp->root);
804de5df632SJohn Fastabend 	else
805de5df632SJohn Fastabend 		ht = u32_lookup_ht(tp_c, TC_U32_HTID(n->handle));
806de5df632SJohn Fastabend 
807de5df632SJohn Fastabend 	ins = &ht->ht[TC_U32_HASH(n->handle)];
808de5df632SJohn Fastabend 
809de5df632SJohn Fastabend 	/* The node must always exist for it to be replaced if this is not the
810de5df632SJohn Fastabend 	 * case then something went very wrong elsewhere.
811de5df632SJohn Fastabend 	 */
812de5df632SJohn Fastabend 	for (pins = rtnl_dereference(*ins); ;
813de5df632SJohn Fastabend 	     ins = &pins->next, pins = rtnl_dereference(*ins))
814de5df632SJohn Fastabend 		if (pins->handle == n->handle)
815de5df632SJohn Fastabend 			break;
816de5df632SJohn Fastabend 
817234a4624SMatthew Wilcox 	idr_replace(&ht->handle_idr, n, n->handle);
818de5df632SJohn Fastabend 	RCU_INIT_POINTER(n->next, pins->next);
819de5df632SJohn Fastabend 	rcu_assign_pointer(*ins, n);
820de5df632SJohn Fastabend }
821de5df632SJohn Fastabend 
u32_init_knode(struct net * net,struct tcf_proto * tp,struct tc_u_knode * n)82214215108SCong Wang static struct tc_u_knode *u32_init_knode(struct net *net, struct tcf_proto *tp,
823de5df632SJohn Fastabend 					 struct tc_u_knode *n)
824de5df632SJohn Fastabend {
825058a6c03SPaolo Abeni 	struct tc_u_hnode *ht = rtnl_dereference(n->ht_down);
826de5df632SJohn Fastabend 	struct tc_u32_sel *s = &n->sel;
827058a6c03SPaolo Abeni 	struct tc_u_knode *new;
828de5df632SJohn Fastabend 
829c5eb179eSGustavo A. R. Silva 	new = kzalloc(struct_size(new, sel.keys, s->nkeys), GFP_KERNEL);
830de5df632SJohn Fastabend 	if (!new)
831de5df632SJohn Fastabend 		return NULL;
832de5df632SJohn Fastabend 
833de5df632SJohn Fastabend 	RCU_INIT_POINTER(new->next, n->next);
834de5df632SJohn Fastabend 	new->handle = n->handle;
835de5df632SJohn Fastabend 	RCU_INIT_POINTER(new->ht_up, n->ht_up);
836de5df632SJohn Fastabend 
837de5df632SJohn Fastabend 	new->ifindex = n->ifindex;
838de5df632SJohn Fastabend 	new->fshift = n->fshift;
8399e8ce79cSJohn Fastabend 	new->flags = n->flags;
840058a6c03SPaolo Abeni 	RCU_INIT_POINTER(new->ht_down, ht);
841de5df632SJohn Fastabend 
842de5df632SJohn Fastabend #ifdef CONFIG_CLS_U32_PERF
843de5df632SJohn Fastabend 	/* Statistics may be incremented by readers during update
844de5df632SJohn Fastabend 	 * so we must keep them in tact. When the node is later destroyed
845de5df632SJohn Fastabend 	 * a special destroy call must be made to not free the pf memory.
846de5df632SJohn Fastabend 	 */
847de5df632SJohn Fastabend 	new->pf = n->pf;
848de5df632SJohn Fastabend #endif
849de5df632SJohn Fastabend 
850de5df632SJohn Fastabend #ifdef CONFIG_CLS_U32_MARK
851de5df632SJohn Fastabend 	new->val = n->val;
852de5df632SJohn Fastabend 	new->mask = n->mask;
853de5df632SJohn Fastabend 	/* Similarly success statistics must be moved as pointers */
854de5df632SJohn Fastabend 	new->pcpu_success = n->pcpu_success;
855de5df632SJohn Fastabend #endif
856e512fcf0SGustavo A. R. Silva 	memcpy(&new->sel, s, struct_size(s, keys, s->nkeys));
857de5df632SJohn Fastabend 
85814215108SCong Wang 	if (tcf_exts_init(&new->exts, net, TCA_U32_ACT, TCA_U32_POLICE)) {
859b9a24bb7SWANG Cong 		kfree(new);
860b9a24bb7SWANG Cong 		return NULL;
861b9a24bb7SWANG Cong 	}
862de5df632SJohn Fastabend 
863ec5b0f60SEric Dumazet 	/* bump reference count as long as we hold pointer to structure */
864ec5b0f60SEric Dumazet 	if (ht)
8659fd5661aSPedro Tammela 		refcount_inc(&ht->refcnt);
866ec5b0f60SEric Dumazet 
867de5df632SJohn Fastabend 	return new;
868de5df632SJohn Fastabend }
869de5df632SJohn Fastabend 
u32_change(struct net * net,struct sk_buff * in_skb,struct tcf_proto * tp,unsigned long base,u32 handle,struct nlattr ** tca,void ** arg,u32 flags,struct netlink_ext_ack * extack)870c1b52739SBenjamin LaHaise static int u32_change(struct net *net, struct sk_buff *in_skb,
871af4c6641SEric W. Biederman 		      struct tcf_proto *tp, unsigned long base, u32 handle,
872695176bfSCong Wang 		      struct nlattr **tca, void **arg, u32 flags,
8737306db38SAlexander Aring 		      struct netlink_ext_ack *extack)
8741da177e4SLinus Torvalds {
8751da177e4SLinus Torvalds 	struct tc_u_common *tp_c = tp->data;
8761da177e4SLinus Torvalds 	struct tc_u_hnode *ht;
8771da177e4SLinus Torvalds 	struct tc_u_knode *n;
8781da177e4SLinus Torvalds 	struct tc_u32_sel *s;
879add93b61SPatrick McHardy 	struct nlattr *opt = tca[TCA_OPTIONS];
880add93b61SPatrick McHardy 	struct nlattr *tb[TCA_U32_MAX + 1];
881695176bfSCong Wang 	u32 htid, userflags = 0;
88298c8f125SKees Cook 	size_t sel_size;
8831da177e4SLinus Torvalds 	int err;
8841da177e4SLinus Torvalds 
8854b981dbcSAlexander Aring 	if (!opt) {
8864b981dbcSAlexander Aring 		if (handle) {
8874b981dbcSAlexander Aring 			NL_SET_ERR_MSG_MOD(extack, "Filter handle requires options");
8884b981dbcSAlexander Aring 			return -EINVAL;
8894b981dbcSAlexander Aring 		} else {
8904b981dbcSAlexander Aring 			return 0;
8914b981dbcSAlexander Aring 		}
8924b981dbcSAlexander Aring 	}
8931da177e4SLinus Torvalds 
8948cb08174SJohannes Berg 	err = nla_parse_nested_deprecated(tb, TCA_U32_MAX, opt, u32_policy,
8958cb08174SJohannes Berg 					  extack);
896cee63723SPatrick McHardy 	if (err < 0)
897cee63723SPatrick McHardy 		return err;
8981da177e4SLinus Torvalds 
899d34e3e18SSamudrala, Sridhar 	if (tb[TCA_U32_FLAGS]) {
900695176bfSCong Wang 		userflags = nla_get_u32(tb[TCA_U32_FLAGS]);
901695176bfSCong Wang 		if (!tc_flags_valid(userflags)) {
9024b981dbcSAlexander Aring 			NL_SET_ERR_MSG_MOD(extack, "Invalid filter flags");
9031a0f7d29SJakub Kicinski 			return -EINVAL;
904d34e3e18SSamudrala, Sridhar 		}
9054b981dbcSAlexander Aring 	}
9069e8ce79cSJohn Fastabend 
9078113c095SWANG Cong 	n = *arg;
908cc7ec456SEric Dumazet 	if (n) {
909de5df632SJohn Fastabend 		struct tc_u_knode *new;
910de5df632SJohn Fastabend 
9114b981dbcSAlexander Aring 		if (TC_U32_KEY(n->handle) == 0) {
9124b981dbcSAlexander Aring 			NL_SET_ERR_MSG_MOD(extack, "Key node id cannot be zero");
9131da177e4SLinus Torvalds 			return -EINVAL;
9144b981dbcSAlexander Aring 		}
9151da177e4SLinus Torvalds 
916695176bfSCong Wang 		if ((n->flags ^ userflags) &
917eb53f7afSIvan Vecera 		    ~(TCA_CLS_FLAGS_IN_HW | TCA_CLS_FLAGS_NOT_IN_HW)) {
9184b981dbcSAlexander Aring 			NL_SET_ERR_MSG_MOD(extack, "Key node flags do not match passed flags");
9199e8ce79cSJohn Fastabend 			return -EINVAL;
9204b981dbcSAlexander Aring 		}
9219e8ce79cSJohn Fastabend 
92214215108SCong Wang 		new = u32_init_knode(net, tp, n);
923de5df632SJohn Fastabend 		if (!new)
924de5df632SJohn Fastabend 			return -ENOMEM;
925de5df632SJohn Fastabend 
9269cb36faeSVictor Nogueira 		err = u32_set_parms(net, tp, new, tb, tca[TCA_RATE],
9279cb36faeSVictor Nogueira 				    flags, new->flags, extack);
928de5df632SJohn Fastabend 
929de5df632SJohn Fastabend 		if (err) {
9303db09e76SEric Dumazet 			__u32_destroy_key(new);
931de5df632SJohn Fastabend 			return err;
932de5df632SJohn Fastabend 		}
933de5df632SJohn Fastabend 
9349cb36faeSVictor Nogueira 		u32_bind_filter(tp, new, base, tb);
9359cb36faeSVictor Nogueira 
93610a47e0fSQuentin Monnet 		err = u32_replace_hw_knode(tp, new, flags, extack);
937d34e3e18SSamudrala, Sridhar 		if (err) {
9389cb36faeSVictor Nogueira 			u32_unbind_filter(tp, new, tb);
9399cb36faeSVictor Nogueira 
940e8d3d78cSVictor Nogueira 			if (tb[TCA_U32_LINK]) {
941e8d3d78cSVictor Nogueira 				struct tc_u_hnode *ht_old;
942e8d3d78cSVictor Nogueira 
943e8d3d78cSVictor Nogueira 				ht_old = rtnl_dereference(n->ht_down);
944e8d3d78cSVictor Nogueira 				if (ht_old)
9459fd5661aSPedro Tammela 					refcount_inc(&ht_old->refcnt);
946e8d3d78cSVictor Nogueira 			}
9473db09e76SEric Dumazet 			__u32_destroy_key(new);
948d34e3e18SSamudrala, Sridhar 			return err;
949d34e3e18SSamudrala, Sridhar 		}
950d34e3e18SSamudrala, Sridhar 
95124d3dc6dSOr Gerlitz 		if (!tc_in_hw(new->flags))
95224d3dc6dSOr Gerlitz 			new->flags |= TCA_CLS_FLAGS_NOT_IN_HW;
95324d3dc6dSOr Gerlitz 
954de5df632SJohn Fastabend 		u32_replace_knode(tp, tp_c, new);
955a0efb80cSWANG Cong 		tcf_unbind_filter(tp, &n->res);
95635c55fc1SCong Wang 		tcf_exts_get_net(&n->exts);
957aaa908ffSCong Wang 		tcf_queue_work(&n->rwork, u32_delete_key_work);
958de5df632SJohn Fastabend 		return 0;
9591da177e4SLinus Torvalds 	}
9601da177e4SLinus Torvalds 
961add93b61SPatrick McHardy 	if (tb[TCA_U32_DIVISOR]) {
962cc7ec456SEric Dumazet 		unsigned int divisor = nla_get_u32(tb[TCA_U32_DIVISOR]);
9631da177e4SLinus Torvalds 
9642f0c982dSAl Viro 		if (!is_power_of_2(divisor)) {
9652f0c982dSAl Viro 			NL_SET_ERR_MSG_MOD(extack, "Divisor is not a power of 2");
9662f0c982dSAl Viro 			return -EINVAL;
9672f0c982dSAl Viro 		}
9682f0c982dSAl Viro 		if (divisor-- > 0x100) {
9694b981dbcSAlexander Aring 			NL_SET_ERR_MSG_MOD(extack, "Exceeded maximum 256 hash buckets");
9701da177e4SLinus Torvalds 			return -EINVAL;
9714b981dbcSAlexander Aring 		}
9724b981dbcSAlexander Aring 		if (TC_U32_KEY(handle)) {
9734b981dbcSAlexander Aring 			NL_SET_ERR_MSG_MOD(extack, "Divisor can only be used on a hash table");
9741da177e4SLinus Torvalds 			return -EINVAL;
9754b981dbcSAlexander Aring 		}
976d61491a5SGustavo A. R. Silva 		ht = kzalloc(struct_size(ht, ht, divisor + 1), GFP_KERNEL);
9771da177e4SLinus Torvalds 		if (ht == NULL)
9781da177e4SLinus Torvalds 			return -ENOBUFS;
979e7614370SCong Wang 		if (handle == 0) {
980e7614370SCong Wang 			handle = gen_new_htid(tp->data, ht);
981e7614370SCong Wang 			if (handle == 0) {
982e7614370SCong Wang 				kfree(ht);
983e7614370SCong Wang 				return -ENOMEM;
984e7614370SCong Wang 			}
985e7614370SCong Wang 		} else {
986f730cb93SMatthew Wilcox 			err = idr_alloc_u32(&tp_c->handle_idr, ht, &handle,
987f730cb93SMatthew Wilcox 					    handle, GFP_KERNEL);
988e7614370SCong Wang 			if (err) {
989e7614370SCong Wang 				kfree(ht);
990e7614370SCong Wang 				return err;
991e7614370SCong Wang 			}
992e7614370SCong Wang 		}
9939fd5661aSPedro Tammela 		refcount_set(&ht->refcnt, 1);
9941da177e4SLinus Torvalds 		ht->divisor = divisor;
9951da177e4SLinus Torvalds 		ht->handle = handle;
9961da177e4SLinus Torvalds 		ht->prio = tp->prio;
997e7614370SCong Wang 		idr_init(&ht->handle_idr);
998695176bfSCong Wang 		ht->flags = userflags;
9996eef3801SJakub Kicinski 
1000695176bfSCong Wang 		err = u32_replace_hw_hnode(tp, ht, userflags, extack);
10016eef3801SJakub Kicinski 		if (err) {
1002*789f9963SAlexandre Ferrieux 			idr_remove(&tp_c->handle_idr, handle2id(handle));
10036eef3801SJakub Kicinski 			kfree(ht);
10046eef3801SJakub Kicinski 			return err;
10056eef3801SJakub Kicinski 		}
10066eef3801SJakub Kicinski 
10071ce87720SJohn Fastabend 		RCU_INIT_POINTER(ht->next, tp_c->hlist);
10081ce87720SJohn Fastabend 		rcu_assign_pointer(tp_c->hlist, ht);
10098113c095SWANG Cong 		*arg = ht;
1010a1b7c5fdSJohn Fastabend 
10111da177e4SLinus Torvalds 		return 0;
10121da177e4SLinus Torvalds 	}
10131da177e4SLinus Torvalds 
1014add93b61SPatrick McHardy 	if (tb[TCA_U32_HASH]) {
10151587bac4SPatrick McHardy 		htid = nla_get_u32(tb[TCA_U32_HASH]);
10161da177e4SLinus Torvalds 		if (TC_U32_HTID(htid) == TC_U32_ROOT) {
10171ce87720SJohn Fastabend 			ht = rtnl_dereference(tp->root);
10181da177e4SLinus Torvalds 			htid = ht->handle;
10191da177e4SLinus Torvalds 		} else {
10201da177e4SLinus Torvalds 			ht = u32_lookup_ht(tp->data, TC_U32_HTID(htid));
10214b981dbcSAlexander Aring 			if (!ht) {
10224b981dbcSAlexander Aring 				NL_SET_ERR_MSG_MOD(extack, "Specified hash table not found");
10231da177e4SLinus Torvalds 				return -EINVAL;
10241da177e4SLinus Torvalds 			}
10254b981dbcSAlexander Aring 		}
10261da177e4SLinus Torvalds 	} else {
10271ce87720SJohn Fastabend 		ht = rtnl_dereference(tp->root);
10281da177e4SLinus Torvalds 		htid = ht->handle;
10291da177e4SLinus Torvalds 	}
10301da177e4SLinus Torvalds 
10314b981dbcSAlexander Aring 	if (ht->divisor < TC_U32_HASH(htid)) {
10324b981dbcSAlexander Aring 		NL_SET_ERR_MSG_MOD(extack, "Specified hash table buckets exceed configured value");
10331da177e4SLinus Torvalds 		return -EINVAL;
10344b981dbcSAlexander Aring 	}
10351da177e4SLinus Torvalds 
1036e68409dbSJamal Hadi Salim 	/* At this point, we need to derive the new handle that will be used to
1037e68409dbSJamal Hadi Salim 	 * uniquely map the identity of this table match entry. The
1038e68409dbSJamal Hadi Salim 	 * identity of the entry that we need to construct is 32 bits made of:
1039e68409dbSJamal Hadi Salim 	 *     htid(12b):bucketid(8b):node/entryid(12b)
1040e68409dbSJamal Hadi Salim 	 *
1041e68409dbSJamal Hadi Salim 	 * At this point _we have the table(ht)_ in which we will insert this
1042e68409dbSJamal Hadi Salim 	 * entry. We carry the table's id in variable "htid".
1043e68409dbSJamal Hadi Salim 	 * Note that earlier code picked the ht selection either by a) the user
1044e68409dbSJamal Hadi Salim 	 * providing the htid specified via TCA_U32_HASH attribute or b) when
1045e68409dbSJamal Hadi Salim 	 * no such attribute is passed then the root ht, is default to at ID
1046e68409dbSJamal Hadi Salim 	 * 0x[800][00][000]. Rule: the root table has a single bucket with ID 0.
1047e68409dbSJamal Hadi Salim 	 * If OTOH the user passed us the htid, they may also pass a bucketid of
1048e68409dbSJamal Hadi Salim 	 * choice. 0 is fine. For example a user htid is 0x[600][01][000] it is
1049e68409dbSJamal Hadi Salim 	 * indicating hash bucketid of 1. Rule: the entry/node ID _cannot_ be
1050e68409dbSJamal Hadi Salim 	 * passed via the htid, so even if it was non-zero it will be ignored.
1051e68409dbSJamal Hadi Salim 	 *
1052e68409dbSJamal Hadi Salim 	 * We may also have a handle, if the user passed one. The handle also
1053e68409dbSJamal Hadi Salim 	 * carries the same addressing of htid(12b):bucketid(8b):node/entryid(12b).
1054e68409dbSJamal Hadi Salim 	 * Rule: the bucketid on the handle is ignored even if one was passed;
1055e68409dbSJamal Hadi Salim 	 * rather the value on "htid" is always assumed to be the bucketid.
1056e68409dbSJamal Hadi Salim 	 */
10571da177e4SLinus Torvalds 	if (handle) {
1058e68409dbSJamal Hadi Salim 		/* Rule: The htid from handle and tableid from htid must match */
10594b981dbcSAlexander Aring 		if (TC_U32_HTID(handle) && TC_U32_HTID(handle ^ htid)) {
10604b981dbcSAlexander Aring 			NL_SET_ERR_MSG_MOD(extack, "Handle specified hash table address mismatch");
10611da177e4SLinus Torvalds 			return -EINVAL;
10624b981dbcSAlexander Aring 		}
1063e68409dbSJamal Hadi Salim 		/* Ok, so far we have a valid htid(12b):bucketid(8b) but we
1064e68409dbSJamal Hadi Salim 		 * need to finalize the table entry identification with the last
1065e68409dbSJamal Hadi Salim 		 * part - the node/entryid(12b)). Rule: Nodeid _cannot be 0_ for
1066e68409dbSJamal Hadi Salim 		 * entries. Rule: nodeid of 0 is reserved only for tables(see
1067e68409dbSJamal Hadi Salim 		 * earlier code which processes TC_U32_DIVISOR attribute).
1068e68409dbSJamal Hadi Salim 		 * Rule: The nodeid can only be derived from the handle (and not
1069e68409dbSJamal Hadi Salim 		 * htid).
1070e68409dbSJamal Hadi Salim 		 * Rule: if the handle specified zero for the node id example
1071e68409dbSJamal Hadi Salim 		 * 0x60000000, then pick a new nodeid from the pool of IDs
1072e68409dbSJamal Hadi Salim 		 * this hash table has been allocating from.
1073e68409dbSJamal Hadi Salim 		 * If OTOH it is specified (i.e for example the user passed a
1074e68409dbSJamal Hadi Salim 		 * handle such as 0x60000123), then we use it generate our final
1075e68409dbSJamal Hadi Salim 		 * handle which is used to uniquely identify the match entry.
1076e68409dbSJamal Hadi Salim 		 */
1077e68409dbSJamal Hadi Salim 		if (!TC_U32_NODE(handle)) {
1078e68409dbSJamal Hadi Salim 			handle = gen_new_kid(ht, htid);
1079e68409dbSJamal Hadi Salim 		} else {
10801da177e4SLinus Torvalds 			handle = htid | TC_U32_NODE(handle);
1081e68409dbSJamal Hadi Salim 			err = idr_alloc_u32(&ht->handle_idr, NULL, &handle,
1082e68409dbSJamal Hadi Salim 					    handle, GFP_KERNEL);
1083e7614370SCong Wang 			if (err)
1084e7614370SCong Wang 				return err;
1085e68409dbSJamal Hadi Salim 		}
1086e68409dbSJamal Hadi Salim 	} else {
1087e68409dbSJamal Hadi Salim 		/* The user did not give us a handle; lets just generate one
1088e68409dbSJamal Hadi Salim 		 * from the table's pool of nodeids.
1089e68409dbSJamal Hadi Salim 		 */
10901da177e4SLinus Torvalds 		handle = gen_new_kid(ht, htid);
1091e68409dbSJamal Hadi Salim 	}
10921da177e4SLinus Torvalds 
1093e7614370SCong Wang 	if (tb[TCA_U32_SEL] == NULL) {
10944b981dbcSAlexander Aring 		NL_SET_ERR_MSG_MOD(extack, "Selector not specified");
1095e7614370SCong Wang 		err = -EINVAL;
1096e7614370SCong Wang 		goto erridr;
1097e7614370SCong Wang 	}
10981da177e4SLinus Torvalds 
1099add93b61SPatrick McHardy 	s = nla_data(tb[TCA_U32_SEL]);
110098c8f125SKees Cook 	sel_size = struct_size(s, keys, s->nkeys);
110198c8f125SKees Cook 	if (nla_len(tb[TCA_U32_SEL]) < sel_size) {
110298c8f125SKees Cook 		err = -EINVAL;
110398c8f125SKees Cook 		goto erridr;
110498c8f125SKees Cook 	}
11051da177e4SLinus Torvalds 
110677aec5e1SGustavo A. R. Silva 	n = kzalloc(struct_size(n, sel.keys, s->nkeys), GFP_KERNEL);
1107e7614370SCong Wang 	if (n == NULL) {
1108e7614370SCong Wang 		err = -ENOBUFS;
1109e7614370SCong Wang 		goto erridr;
1110e7614370SCong Wang 	}
11111da177e4SLinus Torvalds 
11121da177e4SLinus Torvalds #ifdef CONFIG_CLS_U32_PERF
111377aec5e1SGustavo A. R. Silva 	n->pf = __alloc_percpu(struct_size(n->pf, kcnts, s->nkeys),
111477aec5e1SGustavo A. R. Silva 			       __alignof__(struct tc_u32_pcnt));
1115459d5f62SJohn Fastabend 	if (!n->pf) {
1116e7614370SCong Wang 		err = -ENOBUFS;
1117e7614370SCong Wang 		goto errfree;
11181da177e4SLinus Torvalds 	}
11191da177e4SLinus Torvalds #endif
11201da177e4SLinus Torvalds 
11217cba1833SKees Cook 	unsafe_memcpy(&n->sel, s, sel_size,
11227cba1833SKees Cook 		      /* A composite flex-array structure destination,
11237cba1833SKees Cook 		       * which was correctly sized with struct_size(),
11247cba1833SKees Cook 		       * bounds-checked against nla_len(), and allocated
11257cba1833SKees Cook 		       * above. */);
1126a96366bfSJohn Fastabend 	RCU_INIT_POINTER(n->ht_up, ht);
11271da177e4SLinus Torvalds 	n->handle = handle;
1128b2268016SRadu Rendec 	n->fshift = s->hmask ? ffs(ntohl(s->hmask)) - 1 : 0;
1129695176bfSCong Wang 	n->flags = userflags;
11301da177e4SLinus Torvalds 
113114215108SCong Wang 	err = tcf_exts_init(&n->exts, net, TCA_U32_ACT, TCA_U32_POLICE);
1132b9a24bb7SWANG Cong 	if (err < 0)
1133b9a24bb7SWANG Cong 		goto errout;
1134b9a24bb7SWANG Cong 
11351da177e4SLinus Torvalds #ifdef CONFIG_CLS_U32_MARK
1136459d5f62SJohn Fastabend 	n->pcpu_success = alloc_percpu(u32);
1137a1ddcfeeSJohn Fastabend 	if (!n->pcpu_success) {
1138a1ddcfeeSJohn Fastabend 		err = -ENOMEM;
1139a1ddcfeeSJohn Fastabend 		goto errout;
1140a1ddcfeeSJohn Fastabend 	}
1141459d5f62SJohn Fastabend 
1142add93b61SPatrick McHardy 	if (tb[TCA_U32_MARK]) {
11431da177e4SLinus Torvalds 		struct tc_u32_mark *mark;
11441da177e4SLinus Torvalds 
1145add93b61SPatrick McHardy 		mark = nla_data(tb[TCA_U32_MARK]);
1146459d5f62SJohn Fastabend 		n->val = mark->val;
1147459d5f62SJohn Fastabend 		n->mask = mark->mask;
11481da177e4SLinus Torvalds 	}
11491da177e4SLinus Torvalds #endif
11501da177e4SLinus Torvalds 
11519cb36faeSVictor Nogueira 	err = u32_set_parms(net, tp, n, tb, tca[TCA_RATE],
1152c86e0209SBaowen Zheng 			    flags, n->flags, extack);
11539cb36faeSVictor Nogueira 
11549cb36faeSVictor Nogueira 	u32_bind_filter(tp, n, base, tb);
11559cb36faeSVictor Nogueira 
11561da177e4SLinus Torvalds 	if (err == 0) {
11571ce87720SJohn Fastabend 		struct tc_u_knode __rcu **ins;
11581ce87720SJohn Fastabend 		struct tc_u_knode *pins;
11591ce87720SJohn Fastabend 
116010a47e0fSQuentin Monnet 		err = u32_replace_hw_knode(tp, n, flags, extack);
1161d34e3e18SSamudrala, Sridhar 		if (err)
11629cb36faeSVictor Nogueira 			goto errunbind;
1163d34e3e18SSamudrala, Sridhar 
116424d3dc6dSOr Gerlitz 		if (!tc_in_hw(n->flags))
116524d3dc6dSOr Gerlitz 			n->flags |= TCA_CLS_FLAGS_NOT_IN_HW;
116624d3dc6dSOr Gerlitz 
11671ce87720SJohn Fastabend 		ins = &ht->ht[TC_U32_HASH(handle)];
11681ce87720SJohn Fastabend 		for (pins = rtnl_dereference(*ins); pins;
11691ce87720SJohn Fastabend 		     ins = &pins->next, pins = rtnl_dereference(*ins))
11701ce87720SJohn Fastabend 			if (TC_U32_NODE(handle) < TC_U32_NODE(pins->handle))
11711da177e4SLinus Torvalds 				break;
11721da177e4SLinus Torvalds 
11731ce87720SJohn Fastabend 		RCU_INIT_POINTER(n->next, pins);
11741ce87720SJohn Fastabend 		rcu_assign_pointer(*ins, n);
1175b245d32cSAl Viro 		tp_c->knodes++;
11768113c095SWANG Cong 		*arg = n;
11771da177e4SLinus Torvalds 		return 0;
11781da177e4SLinus Torvalds 	}
1179a1ddcfeeSJohn Fastabend 
11809cb36faeSVictor Nogueira errunbind:
11819cb36faeSVictor Nogueira 	u32_unbind_filter(tp, n, tb);
11829cb36faeSVictor Nogueira 
1183a1ddcfeeSJohn Fastabend #ifdef CONFIG_CLS_U32_MARK
1184a1ddcfeeSJohn Fastabend 	free_percpu(n->pcpu_success);
1185a1ddcfeeSJohn Fastabend #endif
1186a1ddcfeeSJohn Fastabend 
1187b9a24bb7SWANG Cong errout:
1188b9a24bb7SWANG Cong 	tcf_exts_destroy(&n->exts);
11891da177e4SLinus Torvalds #ifdef CONFIG_CLS_U32_PERF
1190e7614370SCong Wang errfree:
11911ce87720SJohn Fastabend 	free_percpu(n->pf);
11921da177e4SLinus Torvalds #endif
11931da177e4SLinus Torvalds 	kfree(n);
1194e7614370SCong Wang erridr:
11959c160941SMatthew Wilcox 	idr_remove(&ht->handle_idr, handle);
11961da177e4SLinus Torvalds 	return err;
11971da177e4SLinus Torvalds }
11981da177e4SLinus Torvalds 
u32_walk(struct tcf_proto * tp,struct tcf_walker * arg,bool rtnl_held)119912db03b6SVlad Buslov static void u32_walk(struct tcf_proto *tp, struct tcf_walker *arg,
120012db03b6SVlad Buslov 		     bool rtnl_held)
12011da177e4SLinus Torvalds {
12021da177e4SLinus Torvalds 	struct tc_u_common *tp_c = tp->data;
12031da177e4SLinus Torvalds 	struct tc_u_hnode *ht;
12041da177e4SLinus Torvalds 	struct tc_u_knode *n;
1205cc7ec456SEric Dumazet 	unsigned int h;
12061da177e4SLinus Torvalds 
12071da177e4SLinus Torvalds 	if (arg->stop)
12081da177e4SLinus Torvalds 		return;
12091da177e4SLinus Torvalds 
12101ce87720SJohn Fastabend 	for (ht = rtnl_dereference(tp_c->hlist);
12111ce87720SJohn Fastabend 	     ht;
12121ce87720SJohn Fastabend 	     ht = rtnl_dereference(ht->next)) {
12131da177e4SLinus Torvalds 		if (ht->prio != tp->prio)
12141da177e4SLinus Torvalds 			continue;
12155508ff7cSZhengchao Shao 
12165508ff7cSZhengchao Shao 		if (!tc_cls_stats_dump(tp, arg, ht))
12171da177e4SLinus Torvalds 			return;
12185508ff7cSZhengchao Shao 
12191da177e4SLinus Torvalds 		for (h = 0; h <= ht->divisor; h++) {
12201ce87720SJohn Fastabend 			for (n = rtnl_dereference(ht->ht[h]);
12211ce87720SJohn Fastabend 			     n;
12221ce87720SJohn Fastabend 			     n = rtnl_dereference(n->next)) {
12235508ff7cSZhengchao Shao 				if (!tc_cls_stats_dump(tp, arg, n))
12241da177e4SLinus Torvalds 					return;
12251da177e4SLinus Torvalds 			}
12261da177e4SLinus Torvalds 		}
12271da177e4SLinus Torvalds 	}
12281da177e4SLinus Torvalds }
12291da177e4SLinus Torvalds 
u32_reoffload_hnode(struct tcf_proto * tp,struct tc_u_hnode * ht,bool add,flow_setup_cb_t * cb,void * cb_priv,struct netlink_ext_ack * extack)1230530d9951SJohn Hurley static int u32_reoffload_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht,
1231a7323311SPablo Neira Ayuso 			       bool add, flow_setup_cb_t *cb, void *cb_priv,
1232530d9951SJohn Hurley 			       struct netlink_ext_ack *extack)
1233530d9951SJohn Hurley {
1234530d9951SJohn Hurley 	struct tc_cls_u32_offload cls_u32 = {};
1235530d9951SJohn Hurley 	int err;
1236530d9951SJohn Hurley 
1237d6787147SPieter Jansen van Vuuren 	tc_cls_common_offload_init(&cls_u32.common, tp, ht->flags, extack);
1238530d9951SJohn Hurley 	cls_u32.command = add ? TC_CLSU32_NEW_HNODE : TC_CLSU32_DELETE_HNODE;
1239530d9951SJohn Hurley 	cls_u32.hnode.divisor = ht->divisor;
1240530d9951SJohn Hurley 	cls_u32.hnode.handle = ht->handle;
1241530d9951SJohn Hurley 	cls_u32.hnode.prio = ht->prio;
1242530d9951SJohn Hurley 
1243530d9951SJohn Hurley 	err = cb(TC_SETUP_CLSU32, &cls_u32, cb_priv);
1244530d9951SJohn Hurley 	if (err && add && tc_skip_sw(ht->flags))
1245530d9951SJohn Hurley 		return err;
1246530d9951SJohn Hurley 
1247530d9951SJohn Hurley 	return 0;
1248530d9951SJohn Hurley }
1249530d9951SJohn Hurley 
u32_reoffload_knode(struct tcf_proto * tp,struct tc_u_knode * n,bool add,flow_setup_cb_t * cb,void * cb_priv,struct netlink_ext_ack * extack)1250530d9951SJohn Hurley static int u32_reoffload_knode(struct tcf_proto *tp, struct tc_u_knode *n,
1251a7323311SPablo Neira Ayuso 			       bool add, flow_setup_cb_t *cb, void *cb_priv,
1252530d9951SJohn Hurley 			       struct netlink_ext_ack *extack)
1253530d9951SJohn Hurley {
1254530d9951SJohn Hurley 	struct tc_u_hnode *ht = rtnl_dereference(n->ht_down);
1255530d9951SJohn Hurley 	struct tcf_block *block = tp->chain->block;
1256530d9951SJohn Hurley 	struct tc_cls_u32_offload cls_u32 = {};
1257530d9951SJohn Hurley 
1258d6787147SPieter Jansen van Vuuren 	tc_cls_common_offload_init(&cls_u32.common, tp, n->flags, extack);
1259530d9951SJohn Hurley 	cls_u32.command = add ?
1260530d9951SJohn Hurley 		TC_CLSU32_REPLACE_KNODE : TC_CLSU32_DELETE_KNODE;
1261530d9951SJohn Hurley 	cls_u32.knode.handle = n->handle;
1262530d9951SJohn Hurley 
1263530d9951SJohn Hurley 	if (add) {
1264530d9951SJohn Hurley 		cls_u32.knode.fshift = n->fshift;
1265530d9951SJohn Hurley #ifdef CONFIG_CLS_U32_MARK
1266530d9951SJohn Hurley 		cls_u32.knode.val = n->val;
1267530d9951SJohn Hurley 		cls_u32.knode.mask = n->mask;
1268530d9951SJohn Hurley #else
1269530d9951SJohn Hurley 		cls_u32.knode.val = 0;
1270530d9951SJohn Hurley 		cls_u32.knode.mask = 0;
1271530d9951SJohn Hurley #endif
1272530d9951SJohn Hurley 		cls_u32.knode.sel = &n->sel;
1273068ceb35SJakub Kicinski 		cls_u32.knode.res = &n->res;
1274530d9951SJohn Hurley 		cls_u32.knode.exts = &n->exts;
1275530d9951SJohn Hurley 		if (n->ht_down)
1276530d9951SJohn Hurley 			cls_u32.knode.link_handle = ht->handle;
1277530d9951SJohn Hurley 	}
1278530d9951SJohn Hurley 
127957b0637dSZheng Yongjun 	return tc_setup_cb_reoffload(block, tp, add, cb, TC_SETUP_CLSU32,
128040119211SVlad Buslov 				     &cls_u32, cb_priv, &n->flags,
128140119211SVlad Buslov 				     &n->in_hw_count);
1282530d9951SJohn Hurley }
1283530d9951SJohn Hurley 
u32_reoffload(struct tcf_proto * tp,bool add,flow_setup_cb_t * cb,void * cb_priv,struct netlink_ext_ack * extack)1284a7323311SPablo Neira Ayuso static int u32_reoffload(struct tcf_proto *tp, bool add, flow_setup_cb_t *cb,
1285530d9951SJohn Hurley 			 void *cb_priv, struct netlink_ext_ack *extack)
1286530d9951SJohn Hurley {
1287530d9951SJohn Hurley 	struct tc_u_common *tp_c = tp->data;
1288530d9951SJohn Hurley 	struct tc_u_hnode *ht;
1289530d9951SJohn Hurley 	struct tc_u_knode *n;
1290530d9951SJohn Hurley 	unsigned int h;
1291530d9951SJohn Hurley 	int err;
1292530d9951SJohn Hurley 
1293530d9951SJohn Hurley 	for (ht = rtnl_dereference(tp_c->hlist);
1294530d9951SJohn Hurley 	     ht;
1295530d9951SJohn Hurley 	     ht = rtnl_dereference(ht->next)) {
1296530d9951SJohn Hurley 		if (ht->prio != tp->prio)
1297530d9951SJohn Hurley 			continue;
1298530d9951SJohn Hurley 
1299530d9951SJohn Hurley 		/* When adding filters to a new dev, try to offload the
1300530d9951SJohn Hurley 		 * hashtable first. When removing, do the filters before the
1301530d9951SJohn Hurley 		 * hashtable.
1302530d9951SJohn Hurley 		 */
1303530d9951SJohn Hurley 		if (add && !tc_skip_hw(ht->flags)) {
1304530d9951SJohn Hurley 			err = u32_reoffload_hnode(tp, ht, add, cb, cb_priv,
1305530d9951SJohn Hurley 						  extack);
1306530d9951SJohn Hurley 			if (err)
1307530d9951SJohn Hurley 				return err;
1308530d9951SJohn Hurley 		}
1309530d9951SJohn Hurley 
1310530d9951SJohn Hurley 		for (h = 0; h <= ht->divisor; h++) {
1311530d9951SJohn Hurley 			for (n = rtnl_dereference(ht->ht[h]);
1312530d9951SJohn Hurley 			     n;
1313530d9951SJohn Hurley 			     n = rtnl_dereference(n->next)) {
1314530d9951SJohn Hurley 				if (tc_skip_hw(n->flags))
1315530d9951SJohn Hurley 					continue;
1316530d9951SJohn Hurley 
1317530d9951SJohn Hurley 				err = u32_reoffload_knode(tp, n, add, cb,
1318530d9951SJohn Hurley 							  cb_priv, extack);
1319530d9951SJohn Hurley 				if (err)
1320530d9951SJohn Hurley 					return err;
1321530d9951SJohn Hurley 			}
1322530d9951SJohn Hurley 		}
1323530d9951SJohn Hurley 
1324530d9951SJohn Hurley 		if (!add && !tc_skip_hw(ht->flags))
1325530d9951SJohn Hurley 			u32_reoffload_hnode(tp, ht, add, cb, cb_priv, extack);
1326530d9951SJohn Hurley 	}
1327530d9951SJohn Hurley 
1328530d9951SJohn Hurley 	return 0;
1329530d9951SJohn Hurley }
1330530d9951SJohn Hurley 
u32_bind_class(void * fh,u32 classid,unsigned long cl,void * q,unsigned long base)13312e24cd75SCong Wang static void u32_bind_class(void *fh, u32 classid, unsigned long cl, void *q,
13322e24cd75SCong Wang 			   unsigned long base)
133307d79fc7SCong Wang {
133407d79fc7SCong Wang 	struct tc_u_knode *n = fh;
133507d79fc7SCong Wang 
1336cc9039a1SZhengchao Shao 	tc_cls_bind_class(classid, cl, q, &n->res, base);
133707d79fc7SCong Wang }
133807d79fc7SCong Wang 
u32_dump(struct net * net,struct tcf_proto * tp,void * fh,struct sk_buff * skb,struct tcmsg * t,bool rtnl_held)13398113c095SWANG Cong static int u32_dump(struct net *net, struct tcf_proto *tp, void *fh,
134012db03b6SVlad Buslov 		    struct sk_buff *skb, struct tcmsg *t, bool rtnl_held)
13411da177e4SLinus Torvalds {
13428113c095SWANG Cong 	struct tc_u_knode *n = fh;
13431ce87720SJohn Fastabend 	struct tc_u_hnode *ht_up, *ht_down;
13444b3550efSPatrick McHardy 	struct nlattr *nest;
13451da177e4SLinus Torvalds 
13461da177e4SLinus Torvalds 	if (n == NULL)
13471da177e4SLinus Torvalds 		return skb->len;
13481da177e4SLinus Torvalds 
13491da177e4SLinus Torvalds 	t->tcm_handle = n->handle;
13501da177e4SLinus Torvalds 
1351ae0be8deSMichal Kubecek 	nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
13524b3550efSPatrick McHardy 	if (nest == NULL)
13534b3550efSPatrick McHardy 		goto nla_put_failure;
13541da177e4SLinus Torvalds 
13551da177e4SLinus Torvalds 	if (TC_U32_KEY(n->handle) == 0) {
13568113c095SWANG Cong 		struct tc_u_hnode *ht = fh;
13571da177e4SLinus Torvalds 		u32 divisor = ht->divisor + 1;
1358cc7ec456SEric Dumazet 
13591b34ec43SDavid S. Miller 		if (nla_put_u32(skb, TCA_U32_DIVISOR, divisor))
13601b34ec43SDavid S. Miller 			goto nla_put_failure;
13611da177e4SLinus Torvalds 	} else {
1362459d5f62SJohn Fastabend #ifdef CONFIG_CLS_U32_PERF
1363459d5f62SJohn Fastabend 		struct tc_u32_pcnt *gpf;
1364459d5f62SJohn Fastabend 		int cpu;
136580aab73dSJohn Fastabend #endif
1366459d5f62SJohn Fastabend 
136777aec5e1SGustavo A. R. Silva 		if (nla_put(skb, TCA_U32_SEL, struct_size(&n->sel, keys, n->sel.nkeys),
13681b34ec43SDavid S. Miller 			    &n->sel))
13691b34ec43SDavid S. Miller 			goto nla_put_failure;
13701ce87720SJohn Fastabend 
13711ce87720SJohn Fastabend 		ht_up = rtnl_dereference(n->ht_up);
13721ce87720SJohn Fastabend 		if (ht_up) {
13731da177e4SLinus Torvalds 			u32 htid = n->handle & 0xFFFFF000;
13741b34ec43SDavid S. Miller 			if (nla_put_u32(skb, TCA_U32_HASH, htid))
13751b34ec43SDavid S. Miller 				goto nla_put_failure;
13761da177e4SLinus Torvalds 		}
13771b34ec43SDavid S. Miller 		if (n->res.classid &&
13781b34ec43SDavid S. Miller 		    nla_put_u32(skb, TCA_U32_CLASSID, n->res.classid))
13791b34ec43SDavid S. Miller 			goto nla_put_failure;
13801ce87720SJohn Fastabend 
13811ce87720SJohn Fastabend 		ht_down = rtnl_dereference(n->ht_down);
13821ce87720SJohn Fastabend 		if (ht_down &&
13831ce87720SJohn Fastabend 		    nla_put_u32(skb, TCA_U32_LINK, ht_down->handle))
13841b34ec43SDavid S. Miller 			goto nla_put_failure;
13851da177e4SLinus Torvalds 
13869e8ce79cSJohn Fastabend 		if (n->flags && nla_put_u32(skb, TCA_U32_FLAGS, n->flags))
13879e8ce79cSJohn Fastabend 			goto nla_put_failure;
13889e8ce79cSJohn Fastabend 
13891da177e4SLinus Torvalds #ifdef CONFIG_CLS_U32_MARK
1390459d5f62SJohn Fastabend 		if ((n->val || n->mask)) {
1391459d5f62SJohn Fastabend 			struct tc_u32_mark mark = {.val = n->val,
1392459d5f62SJohn Fastabend 						   .mask = n->mask,
1393459d5f62SJohn Fastabend 						   .success = 0};
139480aab73dSJohn Fastabend 			int cpum;
1395459d5f62SJohn Fastabend 
139680aab73dSJohn Fastabend 			for_each_possible_cpu(cpum) {
139780aab73dSJohn Fastabend 				__u32 cnt = *per_cpu_ptr(n->pcpu_success, cpum);
1398459d5f62SJohn Fastabend 
1399459d5f62SJohn Fastabend 				mark.success += cnt;
1400459d5f62SJohn Fastabend 			}
1401459d5f62SJohn Fastabend 
1402459d5f62SJohn Fastabend 			if (nla_put(skb, TCA_U32_MARK, sizeof(mark), &mark))
14031b34ec43SDavid S. Miller 				goto nla_put_failure;
1404459d5f62SJohn Fastabend 		}
14051da177e4SLinus Torvalds #endif
14061da177e4SLinus Torvalds 
14075da57f42SWANG Cong 		if (tcf_exts_dump(skb, &n->exts) < 0)
1408add93b61SPatrick McHardy 			goto nla_put_failure;
14091da177e4SLinus Torvalds 
14102519a602SWANG Cong 		if (n->ifindex) {
14112519a602SWANG Cong 			struct net_device *dev;
14122519a602SWANG Cong 			dev = __dev_get_by_index(net, n->ifindex);
14132519a602SWANG Cong 			if (dev && nla_put_string(skb, TCA_U32_INDEV, dev->name))
14141b34ec43SDavid S. Miller 				goto nla_put_failure;
14152519a602SWANG Cong 		}
14161da177e4SLinus Torvalds #ifdef CONFIG_CLS_U32_PERF
141777aec5e1SGustavo A. R. Silva 		gpf = kzalloc(struct_size(gpf, kcnts, n->sel.nkeys), GFP_KERNEL);
1418459d5f62SJohn Fastabend 		if (!gpf)
1419459d5f62SJohn Fastabend 			goto nla_put_failure;
1420459d5f62SJohn Fastabend 
1421459d5f62SJohn Fastabend 		for_each_possible_cpu(cpu) {
1422459d5f62SJohn Fastabend 			int i;
1423459d5f62SJohn Fastabend 			struct tc_u32_pcnt *pf = per_cpu_ptr(n->pf, cpu);
1424459d5f62SJohn Fastabend 
1425459d5f62SJohn Fastabend 			gpf->rcnt += pf->rcnt;
1426459d5f62SJohn Fastabend 			gpf->rhit += pf->rhit;
1427459d5f62SJohn Fastabend 			for (i = 0; i < n->sel.nkeys; i++)
1428459d5f62SJohn Fastabend 				gpf->kcnts[i] += pf->kcnts[i];
1429459d5f62SJohn Fastabend 		}
1430459d5f62SJohn Fastabend 
143177aec5e1SGustavo A. R. Silva 		if (nla_put_64bit(skb, TCA_U32_PCNT, struct_size(gpf, kcnts, n->sel.nkeys),
14329854518eSNicolas Dichtel 				  gpf, TCA_U32_PAD)) {
1433459d5f62SJohn Fastabend 			kfree(gpf);
14341b34ec43SDavid S. Miller 			goto nla_put_failure;
1435459d5f62SJohn Fastabend 		}
1436459d5f62SJohn Fastabend 		kfree(gpf);
14371da177e4SLinus Torvalds #endif
14381da177e4SLinus Torvalds 	}
14391da177e4SLinus Torvalds 
14404b3550efSPatrick McHardy 	nla_nest_end(skb, nest);
14414b3550efSPatrick McHardy 
14421da177e4SLinus Torvalds 	if (TC_U32_KEY(n->handle))
14435da57f42SWANG Cong 		if (tcf_exts_dump_stats(skb, &n->exts) < 0)
1444add93b61SPatrick McHardy 			goto nla_put_failure;
14451da177e4SLinus Torvalds 	return skb->len;
14461da177e4SLinus Torvalds 
1447add93b61SPatrick McHardy nla_put_failure:
14484b3550efSPatrick McHardy 	nla_nest_cancel(skb, nest);
14491da177e4SLinus Torvalds 	return -1;
14501da177e4SLinus Torvalds }
14511da177e4SLinus Torvalds 
14522eb9d75cSPatrick McHardy static struct tcf_proto_ops cls_u32_ops __read_mostly = {
14531da177e4SLinus Torvalds 	.kind		=	"u32",
14541da177e4SLinus Torvalds 	.classify	=	u32_classify,
14551da177e4SLinus Torvalds 	.init		=	u32_init,
14561da177e4SLinus Torvalds 	.destroy	=	u32_destroy,
14571da177e4SLinus Torvalds 	.get		=	u32_get,
14581da177e4SLinus Torvalds 	.change		=	u32_change,
14591da177e4SLinus Torvalds 	.delete		=	u32_delete,
14601da177e4SLinus Torvalds 	.walk		=	u32_walk,
1461530d9951SJohn Hurley 	.reoffload	=	u32_reoffload,
14621da177e4SLinus Torvalds 	.dump		=	u32_dump,
146307d79fc7SCong Wang 	.bind_class	=	u32_bind_class,
14641da177e4SLinus Torvalds 	.owner		=	THIS_MODULE,
14651da177e4SLinus Torvalds };
14661da177e4SLinus Torvalds 
init_u32(void)14671da177e4SLinus Torvalds static int __init init_u32(void)
14681da177e4SLinus Torvalds {
14693cd904ecSWANG Cong 	int i, ret;
14703cd904ecSWANG Cong 
14716ff9c364Sstephen hemminger 	pr_info("u32 classifier\n");
14721da177e4SLinus Torvalds #ifdef CONFIG_CLS_U32_PERF
14736ff9c364Sstephen hemminger 	pr_info("    Performance counters on\n");
14741da177e4SLinus Torvalds #endif
14756ff9c364Sstephen hemminger 	pr_info("    input device check on\n");
14761da177e4SLinus Torvalds #ifdef CONFIG_NET_CLS_ACT
14776ff9c364Sstephen hemminger 	pr_info("    Actions configured\n");
14781da177e4SLinus Torvalds #endif
14793cd904ecSWANG Cong 	tc_u_common_hash = kvmalloc_array(U32_HASH_SIZE,
14803cd904ecSWANG Cong 					  sizeof(struct hlist_head),
14813cd904ecSWANG Cong 					  GFP_KERNEL);
14823cd904ecSWANG Cong 	if (!tc_u_common_hash)
14833cd904ecSWANG Cong 		return -ENOMEM;
14843cd904ecSWANG Cong 
14853cd904ecSWANG Cong 	for (i = 0; i < U32_HASH_SIZE; i++)
14863cd904ecSWANG Cong 		INIT_HLIST_HEAD(&tc_u_common_hash[i]);
14873cd904ecSWANG Cong 
14883cd904ecSWANG Cong 	ret = register_tcf_proto_ops(&cls_u32_ops);
14893cd904ecSWANG Cong 	if (ret)
14903cd904ecSWANG Cong 		kvfree(tc_u_common_hash);
14913cd904ecSWANG Cong 	return ret;
14921da177e4SLinus Torvalds }
14931da177e4SLinus Torvalds 
exit_u32(void)14941da177e4SLinus Torvalds static void __exit exit_u32(void)
14951da177e4SLinus Torvalds {
14961da177e4SLinus Torvalds 	unregister_tcf_proto_ops(&cls_u32_ops);
14973cd904ecSWANG Cong 	kvfree(tc_u_common_hash);
14981da177e4SLinus Torvalds }
14991da177e4SLinus Torvalds 
15001da177e4SLinus Torvalds module_init(init_u32)
15011da177e4SLinus Torvalds module_exit(exit_u32)
15021da177e4SLinus Torvalds MODULE_LICENSE("GPL");
1503