[RESEND 1/6] PKT_SCHED: Add generic classifier routines
From: Thomas Graf <tgraf@suug.ch>
Date: 2004-10-29 10:23:27
CONFIG_NET_CLS_IND was dependent on CONFIG_NET_CLS_ACT in cls_fw.c which is not correct according to Kconfig and wouldn't make sense. This is a revised patch which has this dependency removed. Adds generic routines used by classifier to: - bind/unbind to classes - configure action/police/indev - dump action/police Signed-off-by: Thomas Graf <tgraf@suug.ch>
--- linux-2.6.10-rc1-bk7.orig/include/net/pkt_cls.h 2004-10-28 22:03:20.000000000 +0200
+++ linux-2.6.10-rc1-bk7/include/net/pkt_cls.h 2004-10-29 12:11:54.000000000 +0200@@ -3,6 +3,7 @@ #include <linux/pkt_cls.h> #include <net/sch_generic.h> +#include <net/act_api.h> /* Basic packet classifier frontend definitions. */
@@ -41,4 +42,189 @@ return old_cl; } +static inline void +tcf_bind_filter(struct tcf_proto *tp, struct tcf_result *r, unsigned long base) +{ + unsigned long cl; + + cl = tp->q->ops->cl_ops->bind_tcf(tp->q, base, r->classid); + cl = cls_set_class(tp, &r->class, cl); + if (cl) + tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); +} + +static inline void +tcf_unbind_filter(struct tcf_proto *tp, struct tcf_result *r) +{ + unsigned long cl; + + if ((cl = __cls_set_class(&r->class, 0)) != 0) + tp->q->ops->cl_ops->unbind_tcf(tp->q, cl); +} + +#ifdef CONFIG_NET_CLS_ACT +static inline int +tcf_change_act_police(struct tcf_proto *tp, struct tc_action **action, + struct rtattr *act_police_tlv, struct rtattr *rate_tlv) +{ + int ret; + struct tc_action *act; + + act = kmalloc(sizeof(*act), GFP_KERNEL); + if (NULL == act) + return -ENOMEM; + memset(act, 0, sizeof(*act)); + + ret = tcf_action_init_1(act_police_tlv, rate_tlv, act, "police", + TCA_ACT_NOREPLACE, TCA_ACT_BIND); + if (ret < 0) { + tcf_action_destroy(act, TCA_ACT_UNBIND); + return ret; + } + + act->type = TCA_OLD_COMPAT; + + if (*action) { + tcf_tree_lock(tp); + act = xchg(action, act); + tcf_tree_unlock(tp); + + tcf_action_destroy(act, TCA_ACT_UNBIND); + } else + *action = act; + + return 0; +} + +static inline int +tcf_change_act(struct tcf_proto *tp, struct tc_action **action, + struct rtattr *act_tlv, struct rtattr *rate_tlv) +{ + int ret; + struct tc_action *act; + + act = kmalloc(sizeof(*act), GFP_KERNEL); + if (NULL == act) + return -ENOMEM; + memset(act, 0, sizeof(*act)); + + ret = tcf_action_init(act_tlv, rate_tlv, act, NULL, + TCA_ACT_NOREPLACE, TCA_ACT_BIND); + if (ret < 0) { + tcf_action_destroy(act, TCA_ACT_UNBIND); + return ret; + } + + if (*action) { + tcf_tree_lock(tp); + act = xchg(action, act); + tcf_tree_unlock(tp); + + tcf_action_destroy(act, TCA_ACT_UNBIND); + } else + *action = act; + + return 0; +} + +static inline int +tcf_dump_act(struct sk_buff *skb, struct tc_action *action, + int act_type, int compat_type) +{ + /* + * again for backward compatible mode - we want + * to work with both old and new modes of entering + * tc data even if iproute2 was newer - jhs + */ + if (action) { + struct rtattr * p_rta = (struct rtattr*) skb->tail; + + if (action->type != TCA_OLD_COMPAT) { + RTA_PUT(skb, act_type, 0, NULL); + if (tcf_action_dump(skb, action, 0, 0) < 0) + goto rtattr_failure; + } else { + RTA_PUT(skb, compat_type, 0, NULL); + if (tcf_action_dump_old(skb, action, 0, 0) < 0) + goto rtattr_failure; + } + + p_rta->rta_len = skb->tail - (u8*)p_rta; + } + return 0; + +rtattr_failure: + return -1; +} +#endif /* CONFIG_NET_CLS_ACT */ + +#ifdef CONFIG_NET_CLS_IND +static inline int +tcf_change_indev(struct tcf_proto *tp, char *indev, struct rtattr *indev_tlv) +{ + if (RTA_PAYLOAD(indev_tlv) >= IFNAMSIZ) { + printk("cls: bad indev name %s\n", (char *) RTA_DATA(indev_tlv)); + return -EINVAL; + } + + memset(indev, 0, IFNAMSIZ); + sprintf(indev, "%s", (char *) RTA_DATA(indev_tlv)); + + return 0; +} + +static inline int +tcf_match_indev(struct sk_buff *skb, char *indev) +{ + if (0 != indev[0]) { + if (NULL == skb->input_dev) + return 0; + else if (0 != strcmp(indev, skb->input_dev->name)) + return 0; + } + + return 1; +} +#endif /* CONFIG_NET_CLS_IND */ + +#ifdef CONFIG_NET_CLS_POLICE +static inline int +tcf_change_police(struct tcf_proto *tp, struct tcf_police **police, + struct rtattr *police_tlv, struct rtattr *rate_tlv) +{ + struct tcf_police *p = tcf_police_locate(police_tlv, rate_tlv); + + if (*police) { + tcf_tree_lock(tp); + p = xchg(police, p); + tcf_tree_unlock(tp); + + tcf_police_release(p, TCA_ACT_UNBIND); + } else + *police = p; + + return 0; +} + +static inline int +tcf_dump_police(struct sk_buff *skb, struct tcf_police *police, + int police_type) +{ + if (police) { + struct rtattr * p_rta = (struct rtattr*) skb->tail; + + RTA_PUT(skb, police_type, 0, NULL); + + if (tcf_police_dump(skb, police) < 0) + goto rtattr_failure; + + p_rta->rta_len = skb->tail - (u8*)p_rta; + } + return 0; + +rtattr_failure: + return -1; +} +#endif /* CONFIG_NET_CLS_POLICE */ + #endif