⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cls_u32.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * net/sched/cls_u32.c	Ugly (or Universal) 32bit key Packet Classifier. * *		This program is free software; you can redistribute it and/or *		modify it under the terms of the GNU General Public License *		as published by the Free Software Foundation; either version *		2 of the License, or (at your option) any later version. * * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * *	The filters are packed to hash tables of key nodes *	with a set of 32bit key/mask pairs at every node. *	Nodes reference next level hash tables etc. * *	This scheme is the best universal classifier I managed to *	invent; it is not super-fast, but it is not slow (provided you *	program it correctly), and general enough.  And its relative *	speed grows as the number of rules becomes larger. * *	It seems that it represents the best middle point between *	speed and manageability both by human and by machine. * *	It is especially useful for link sharing combined with QoS; *	pure RSVP doesn't need such a general approach and can use *	much simpler (and faster) schemes, sort of cls_rsvp.c. * *	JHS: We should remove the CONFIG_NET_CLS_IND from here *	eventually when the meta match extension is made available * *	nfmark match added by Catalin(ux aka Dino) BOIE <catab at umbrella.ro> */#include <linux/module.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/rtnetlink.h>#include <linux/skbuff.h>#include <net/netlink.h>#include <net/act_api.h>#include <net/pkt_cls.h>struct tc_u_knode{	struct tc_u_knode	*next;	u32			handle;	struct tc_u_hnode	*ht_up;	struct tcf_exts		exts;#ifdef CONFIG_NET_CLS_IND	char                     indev[IFNAMSIZ];#endif	u8			fshift;	struct tcf_result	res;	struct tc_u_hnode	*ht_down;#ifdef CONFIG_CLS_U32_PERF	struct tc_u32_pcnt	*pf;#endif#ifdef CONFIG_CLS_U32_MARK	struct tc_u32_mark	mark;#endif	struct tc_u32_sel	sel;};struct tc_u_hnode{	struct tc_u_hnode	*next;	u32			handle;	u32			prio;	struct tc_u_common	*tp_c;	int			refcnt;	unsigned		divisor;	struct tc_u_knode	*ht[1];};struct tc_u_common{	struct tc_u_common	*next;	struct tc_u_hnode	*hlist;	struct Qdisc		*q;	int			refcnt;	u32			hgenerator;};static struct tcf_ext_map u32_ext_map = {	.action = TCA_U32_ACT,	.police = TCA_U32_POLICE};static struct tc_u_common *u32_list;static __inline__ unsigned u32_hash_fold(u32 key, struct tc_u32_sel *sel, u8 fshift){	unsigned h = ntohl(key & sel->hmask)>>fshift;	return h;}static int u32_classify(struct sk_buff *skb, struct tcf_proto *tp, struct tcf_result *res){	struct {		struct tc_u_knode *knode;		u8		  *ptr;	} stack[TC_U32_MAXDEPTH];	struct tc_u_hnode *ht = (struct tc_u_hnode*)tp->root;	u8 *ptr = skb_network_header(skb);	struct tc_u_knode *n;	int sdepth = 0;	int off2 = 0;	int sel = 0;#ifdef CONFIG_CLS_U32_PERF	int j;#endif	int i, r;next_ht:	n = ht->ht[sel];next_knode:	if (n) {		struct tc_u32_key *key = n->sel.keys;#ifdef CONFIG_CLS_U32_PERF		n->pf->rcnt +=1;		j = 0;#endif#ifdef CONFIG_CLS_U32_MARK		if ((skb->mark & n->mark.mask) != n->mark.val) {			n = n->next;			goto next_knode;		} else {			n->mark.success++;		}#endif		for (i = n->sel.nkeys; i>0; i--, key++) {			if ((*(u32*)(ptr+key->off+(off2&key->offmask))^key->val)&key->mask) {				n = n->next;				goto next_knode;			}#ifdef CONFIG_CLS_U32_PERF			n->pf->kcnts[j] +=1;			j++;#endif		}		if (n->ht_down == NULL) {check_terminal:			if (n->sel.flags&TC_U32_TERMINAL) {				*res = n->res;#ifdef CONFIG_NET_CLS_IND				if (!tcf_match_indev(skb, n->indev)) {					n = n->next;					goto next_knode;				}#endif#ifdef CONFIG_CLS_U32_PERF				n->pf->rhit +=1;#endif				r = tcf_exts_exec(skb, &n->exts, res);				if (r < 0) {					n = n->next;					goto next_knode;				}				return r;			}			n = n->next;			goto next_knode;		}		/* PUSH */		if (sdepth >= TC_U32_MAXDEPTH)			goto deadloop;		stack[sdepth].knode = n;		stack[sdepth].ptr = ptr;		sdepth++;		ht = n->ht_down;		sel = 0;		if (ht->divisor)			sel = ht->divisor&u32_hash_fold(*(u32*)(ptr+n->sel.hoff), &n->sel,n->fshift);		if (!(n->sel.flags&(TC_U32_VAROFFSET|TC_U32_OFFSET|TC_U32_EAT)))			goto next_ht;		if (n->sel.flags&(TC_U32_OFFSET|TC_U32_VAROFFSET)) {			off2 = n->sel.off + 3;			if (n->sel.flags&TC_U32_VAROFFSET)				off2 += ntohs(n->sel.offmask & *(u16*)(ptr+n->sel.offoff)) >>n->sel.offshift;			off2 &= ~3;		}		if (n->sel.flags&TC_U32_EAT) {			ptr += off2;			off2 = 0;		}		if (ptr < skb_tail_pointer(skb))			goto next_ht;	}	/* POP */	if (sdepth--) {		n = stack[sdepth].knode;		ht = n->ht_up;		ptr = stack[sdepth].ptr;		goto check_terminal;	}	return -1;deadloop:	if (net_ratelimit())		printk("cls_u32: dead loop\n");	return -1;}static __inline__ struct tc_u_hnode *u32_lookup_ht(struct tc_u_common *tp_c, u32 handle){	struct tc_u_hnode *ht;	for (ht = tp_c->hlist; ht; ht = ht->next)		if (ht->handle == handle)			break;	return ht;}static __inline__ struct tc_u_knode *u32_lookup_key(struct tc_u_hnode *ht, u32 handle){	unsigned sel;	struct tc_u_knode *n = NULL;	sel = TC_U32_HASH(handle);	if (sel > ht->divisor)		goto out;	for (n = ht->ht[sel]; n; n = n->next)		if (n->handle == handle)			break;out:	return n;}static unsigned long u32_get(struct tcf_proto *tp, u32 handle){	struct tc_u_hnode *ht;	struct tc_u_common *tp_c = tp->data;	if (TC_U32_HTID(handle) == TC_U32_ROOT)		ht = tp->root;	else		ht = u32_lookup_ht(tp_c, TC_U32_HTID(handle));	if (!ht)		return 0;	if (TC_U32_KEY(handle) == 0)		return (unsigned long)ht;	return (unsigned long)u32_lookup_key(ht, handle);}static void u32_put(struct tcf_proto *tp, unsigned long f){}static u32 gen_new_htid(struct tc_u_common *tp_c){	int i = 0x800;	do {		if (++tp_c->hgenerator == 0x7FF)			tp_c->hgenerator = 1;	} while (--i>0 && u32_lookup_ht(tp_c, (tp_c->hgenerator|0x800)<<20));	return i > 0 ? (tp_c->hgenerator|0x800)<<20 : 0;}static int u32_init(struct tcf_proto *tp){	struct tc_u_hnode *root_ht;	struct tc_u_common *tp_c;	for (tp_c = u32_list; tp_c; tp_c = tp_c->next)		if (tp_c->q == tp->q)			break;	root_ht = kzalloc(sizeof(*root_ht), GFP_KERNEL);	if (root_ht == NULL)		return -ENOBUFS;	root_ht->divisor = 0;	root_ht->refcnt++;	root_ht->handle = tp_c ? gen_new_htid(tp_c) : 0x80000000;	root_ht->prio = tp->prio;	if (tp_c == NULL) {		tp_c = kzalloc(sizeof(*tp_c), GFP_KERNEL);		if (tp_c == NULL) {			kfree(root_ht);			return -ENOBUFS;		}		tp_c->q = tp->q;		tp_c->next = u32_list;		u32_list = tp_c;	}	tp_c->refcnt++;	root_ht->next = tp_c->hlist;	tp_c->hlist = root_ht;	root_ht->tp_c = tp_c;	tp->root = root_ht;	tp->data = tp_c;	return 0;}static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n){	tcf_unbind_filter(tp, &n->res);	tcf_exts_destroy(tp, &n->exts);	if (n->ht_down)		n->ht_down->refcnt--;#ifdef CONFIG_CLS_U32_PERF	kfree(n->pf);#endif	kfree(n);	return 0;}static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode* key){	struct tc_u_knode **kp;	struct tc_u_hnode *ht = key->ht_up;	if (ht) {		for (kp = &ht->ht[TC_U32_HASH(key->handle)]; *kp; kp = &(*kp)->next) {			if (*kp == key) {				tcf_tree_lock(tp);				*kp = key->next;				tcf_tree_unlock(tp);				u32_destroy_key(tp, key);				return 0;			}		}	}	BUG_TRAP(0);	return 0;}static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht){	struct tc_u_knode *n;	unsigned h;	for (h=0; h<=ht->divisor; h++) {		while ((n = ht->ht[h]) != NULL) {			ht->ht[h] = n->next;			u32_destroy_key(tp, n);		}	}}static int u32_destroy_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht){	struct tc_u_common *tp_c = tp->data;	struct tc_u_hnode **hn;	BUG_TRAP(!ht->refcnt);	u32_clear_hnode(tp, ht);	for (hn = &tp_c->hlist; *hn; hn = &(*hn)->next) {		if (*hn == ht) {			*hn = ht->next;			kfree(ht);			return 0;		}	}	BUG_TRAP(0);	return -ENOENT;}static void u32_destroy(struct tcf_proto *tp){	struct tc_u_common *tp_c = tp->data;	struct tc_u_hnode *root_ht = xchg(&tp->root, NULL);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -