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

📄 cls_fw.c

📁 linux 内核源代码
💻 C
字号:
/* * net/sched/cls_fw.c	Classifier mapping ipchains' fwmark to traffic class. * *		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> * * Changes: * Karlis Peisenieks <karlis@mt.lv> : 990415 : fw_walk off by one * Karlis Peisenieks <karlis@mt.lv> : 990415 : fw_delete killed all the filter (and kernel). * Alex <alex@pilotsoft.com> : 2004xxyy: Added Action extension * * JHS: We should remove the CONFIG_NET_CLS_IND from here * eventually when the meta match extension is made available * */#include <linux/module.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/skbuff.h>#include <net/netlink.h>#include <net/act_api.h>#include <net/pkt_cls.h>#define HTSIZE (PAGE_SIZE/sizeof(struct fw_filter *))struct fw_head{	struct fw_filter *ht[HTSIZE];	u32 mask;};struct fw_filter{	struct fw_filter	*next;	u32			id;	struct tcf_result	res;#ifdef CONFIG_NET_CLS_IND	char			indev[IFNAMSIZ];#endif /* CONFIG_NET_CLS_IND */	struct tcf_exts		exts;};static struct tcf_ext_map fw_ext_map = {	.action = TCA_FW_ACT,	.police = TCA_FW_POLICE};static __inline__ int fw_hash(u32 handle){	if (HTSIZE == 4096)		return ((handle >> 24) & 0xFFF) ^		       ((handle >> 12) & 0xFFF) ^		       (handle & 0xFFF);	else if (HTSIZE == 2048)		return ((handle >> 22) & 0x7FF) ^		       ((handle >> 11) & 0x7FF) ^		       (handle & 0x7FF);	else if (HTSIZE == 1024)		return ((handle >> 20) & 0x3FF) ^		       ((handle >> 10) & 0x3FF) ^		       (handle & 0x3FF);	else if (HTSIZE == 512)		return (handle >> 27) ^		       ((handle >> 18) & 0x1FF) ^		       ((handle >> 9) & 0x1FF) ^		       (handle & 0x1FF);	else if (HTSIZE == 256) {		u8 *t = (u8 *) &handle;		return t[0] ^ t[1] ^ t[2] ^ t[3];	} else		return handle & (HTSIZE - 1);}static int fw_classify(struct sk_buff *skb, struct tcf_proto *tp,			  struct tcf_result *res){	struct fw_head *head = (struct fw_head*)tp->root;	struct fw_filter *f;	int r;	u32 id = skb->mark;	if (head != NULL) {		id &= head->mask;		for (f=head->ht[fw_hash(id)]; f; f=f->next) {			if (f->id == id) {				*res = f->res;#ifdef CONFIG_NET_CLS_IND				if (!tcf_match_indev(skb, f->indev))					continue;#endif /* CONFIG_NET_CLS_IND */				r = tcf_exts_exec(skb, &f->exts, res);				if (r < 0)					continue;				return r;			}		}	} else {		/* old method */		if (id && (TC_H_MAJ(id) == 0 || !(TC_H_MAJ(id^tp->q->handle)))) {			res->classid = id;			res->class = 0;			return 0;		}	}	return -1;}static unsigned long fw_get(struct tcf_proto *tp, u32 handle){	struct fw_head *head = (struct fw_head*)tp->root;	struct fw_filter *f;	if (head == NULL)		return 0;	for (f=head->ht[fw_hash(handle)]; f; f=f->next) {		if (f->id == handle)			return (unsigned long)f;	}	return 0;}static void fw_put(struct tcf_proto *tp, unsigned long f){}static int fw_init(struct tcf_proto *tp){	return 0;}static inline voidfw_delete_filter(struct tcf_proto *tp, struct fw_filter *f){	tcf_unbind_filter(tp, &f->res);	tcf_exts_destroy(tp, &f->exts);	kfree(f);}static void fw_destroy(struct tcf_proto *tp){	struct fw_head *head = (struct fw_head*)xchg(&tp->root, NULL);	struct fw_filter *f;	int h;	if (head == NULL)		return;	for (h=0; h<HTSIZE; h++) {		while ((f=head->ht[h]) != NULL) {			head->ht[h] = f->next;			fw_delete_filter(tp, f);		}	}	kfree(head);}static int fw_delete(struct tcf_proto *tp, unsigned long arg){	struct fw_head *head = (struct fw_head*)tp->root;	struct fw_filter *f = (struct fw_filter*)arg;	struct fw_filter **fp;	if (head == NULL || f == NULL)		goto out;	for (fp=&head->ht[fw_hash(f->id)]; *fp; fp = &(*fp)->next) {		if (*fp == f) {			tcf_tree_lock(tp);			*fp = f->next;			tcf_tree_unlock(tp);			fw_delete_filter(tp, f);			return 0;		}	}out:	return -EINVAL;}static intfw_change_attrs(struct tcf_proto *tp, struct fw_filter *f,	struct rtattr **tb, struct rtattr **tca, unsigned long base){	struct fw_head *head = (struct fw_head *)tp->root;	struct tcf_exts e;	u32 mask;	int err;	err = tcf_exts_validate(tp, tb, tca[TCA_RATE-1], &e, &fw_ext_map);	if (err < 0)		return err;	err = -EINVAL;	if (tb[TCA_FW_CLASSID-1]) {		if (RTA_PAYLOAD(tb[TCA_FW_CLASSID-1]) != sizeof(u32))			goto errout;		f->res.classid = *(u32*)RTA_DATA(tb[TCA_FW_CLASSID-1]);		tcf_bind_filter(tp, &f->res, base);	}#ifdef CONFIG_NET_CLS_IND	if (tb[TCA_FW_INDEV-1]) {		err = tcf_change_indev(tp, f->indev, tb[TCA_FW_INDEV-1]);		if (err < 0)			goto errout;	}#endif /* CONFIG_NET_CLS_IND */	if (tb[TCA_FW_MASK-1]) {		if (RTA_PAYLOAD(tb[TCA_FW_MASK-1]) != sizeof(u32))			goto errout;		mask = *(u32*)RTA_DATA(tb[TCA_FW_MASK-1]);		if (mask != head->mask)			goto errout;	} else if (head->mask != 0xFFFFFFFF)		goto errout;	tcf_exts_change(tp, &f->exts, &e);	return 0;errout:	tcf_exts_destroy(tp, &e);	return err;}static int fw_change(struct tcf_proto *tp, unsigned long base,		     u32 handle,		     struct rtattr **tca,		     unsigned long *arg){	struct fw_head *head = (struct fw_head*)tp->root;	struct fw_filter *f = (struct fw_filter *) *arg;	struct rtattr *opt = tca[TCA_OPTIONS-1];	struct rtattr *tb[TCA_FW_MAX];	int err;	if (!opt)		return handle ? -EINVAL : 0;	if (rtattr_parse_nested(tb, TCA_FW_MAX, opt) < 0)		return -EINVAL;	if (f != NULL) {		if (f->id != handle && handle)			return -EINVAL;		return fw_change_attrs(tp, f, tb, tca, base);	}	if (!handle)		return -EINVAL;	if (head == NULL) {		u32 mask = 0xFFFFFFFF;		if (tb[TCA_FW_MASK-1]) {			if (RTA_PAYLOAD(tb[TCA_FW_MASK-1]) != sizeof(u32))				return -EINVAL;			mask = *(u32*)RTA_DATA(tb[TCA_FW_MASK-1]);		}		head = kzalloc(sizeof(struct fw_head), GFP_KERNEL);		if (head == NULL)			return -ENOBUFS;		head->mask = mask;		tcf_tree_lock(tp);		tp->root = head;		tcf_tree_unlock(tp);	}	f = kzalloc(sizeof(struct fw_filter), GFP_KERNEL);	if (f == NULL)		return -ENOBUFS;	f->id = handle;	err = fw_change_attrs(tp, f, tb, tca, base);	if (err < 0)		goto errout;	f->next = head->ht[fw_hash(handle)];	tcf_tree_lock(tp);	head->ht[fw_hash(handle)] = f;	tcf_tree_unlock(tp);	*arg = (unsigned long)f;	return 0;errout:	kfree(f);	return err;}static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg){	struct fw_head *head = (struct fw_head*)tp->root;	int h;	if (head == NULL)		arg->stop = 1;	if (arg->stop)		return;	for (h = 0; h < HTSIZE; h++) {		struct fw_filter *f;		for (f = head->ht[h]; f; f = f->next) {			if (arg->count < arg->skip) {				arg->count++;				continue;			}			if (arg->fn(tp, (unsigned long)f, arg) < 0) {				arg->stop = 1;				return;			}			arg->count++;		}	}}static int fw_dump(struct tcf_proto *tp, unsigned long fh,		   struct sk_buff *skb, struct tcmsg *t){	struct fw_head *head = (struct fw_head *)tp->root;	struct fw_filter *f = (struct fw_filter*)fh;	unsigned char *b = skb_tail_pointer(skb);	struct rtattr *rta;	if (f == NULL)		return skb->len;	t->tcm_handle = f->id;	if (!f->res.classid && !tcf_exts_is_available(&f->exts))		return skb->len;	rta = (struct rtattr*)b;	RTA_PUT(skb, TCA_OPTIONS, 0, NULL);	if (f->res.classid)		RTA_PUT(skb, TCA_FW_CLASSID, 4, &f->res.classid);#ifdef CONFIG_NET_CLS_IND	if (strlen(f->indev))		RTA_PUT(skb, TCA_FW_INDEV, IFNAMSIZ, f->indev);#endif /* CONFIG_NET_CLS_IND */	if (head->mask != 0xFFFFFFFF)		RTA_PUT(skb, TCA_FW_MASK, 4, &head->mask);	if (tcf_exts_dump(skb, &f->exts, &fw_ext_map) < 0)		goto rtattr_failure;	rta->rta_len = skb_tail_pointer(skb) - b;	if (tcf_exts_dump_stats(skb, &f->exts, &fw_ext_map) < 0)		goto rtattr_failure;	return skb->len;rtattr_failure:	nlmsg_trim(skb, b);	return -1;}static struct tcf_proto_ops cls_fw_ops = {	.next		=	NULL,	.kind		=	"fw",	.classify	=	fw_classify,	.init		=	fw_init,	.destroy	=	fw_destroy,	.get		=	fw_get,	.put		=	fw_put,	.change		=	fw_change,	.delete		=	fw_delete,	.walk		=	fw_walk,	.dump		=	fw_dump,	.owner		=	THIS_MODULE,};static int __init init_fw(void){	return register_tcf_proto_ops(&cls_fw_ops);}static void __exit exit_fw(void){	unregister_tcf_proto_ops(&cls_fw_ops);}module_init(init_fw)module_exit(exit_fw)MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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