This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / include / net / pkt_cls.h
index 3dd2056..4de3ea7 100644 (file)
@@ -1,12 +1,36 @@
 #ifndef __NET_PKT_CLS_H
 #define __NET_PKT_CLS_H
 
+
 #include <linux/pkt_cls.h>
-#include <net/sch_generic.h>
-#include <net/act_api.h>
+
+struct rtattr;
+struct tcmsg;
 
 /* Basic packet classifier frontend definitions. */
 
+struct tcf_result
+{
+       unsigned long   class;
+       u32             classid;
+};
+
+struct tcf_proto
+{
+       /* Fast access part */
+       struct tcf_proto        *next;
+       void                    *root;
+       int                     (*classify)(struct sk_buff*, struct tcf_proto*, struct tcf_result *);
+       u32                     protocol;
+
+       /* All the rest */
+       u32                     prio;
+       u32                     classid;
+       struct Qdisc            *q;
+       void                    *data;
+       struct tcf_proto_ops    *ops;
+};
+
 struct tcf_walker
 {
        int     stop;
@@ -15,216 +39,86 @@ struct tcf_walker
        int     (*fn)(struct tcf_proto *, unsigned long node, struct tcf_walker *);
 };
 
-extern int register_tcf_proto_ops(struct tcf_proto_ops *ops);
-extern int unregister_tcf_proto_ops(struct tcf_proto_ops *ops);
-extern int ing_filter(struct sk_buff *skb);
-
-static inline unsigned long
-__cls_set_class(unsigned long *clp, unsigned long cl)
-{
-       unsigned long old_cl;
-       old_cl = *clp;
-       *clp = cl;
-       return old_cl;
-}
-
-static inline unsigned long
-cls_set_class(struct tcf_proto *tp, unsigned long *clp, 
-       unsigned long cl)
-{
-       unsigned long old_cl;
-       
-       tcf_tree_lock(tp);
-       old_cl = __cls_set_class(clp, cl);
-       tcf_tree_unlock(tp);
-       return old_cl;
-}
+struct module;
 
-static inline void
-tcf_bind_filter(struct tcf_proto *tp, struct tcf_result *r, unsigned long base)
+struct tcf_proto_ops
 {
-       unsigned long cl;
+       struct tcf_proto_ops    *next;
+       char                    kind[IFNAMSIZ];
 
-       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);
-}
+       int                     (*classify)(struct sk_buff*, struct tcf_proto*, struct tcf_result *);
+       int                     (*init)(struct tcf_proto*);
+       void                    (*destroy)(struct tcf_proto*);
 
-static inline void
-tcf_unbind_filter(struct tcf_proto *tp, struct tcf_result *r)
-{
-       unsigned long cl;
+       unsigned long           (*get)(struct tcf_proto*, u32 handle);
+       void                    (*put)(struct tcf_proto*, unsigned long);
+       int                     (*change)(struct tcf_proto*, unsigned long, u32 handle, struct rtattr **, unsigned long *);
+       int                     (*delete)(struct tcf_proto*, unsigned long);
+       void                    (*walk)(struct tcf_proto*, struct tcf_walker *arg);
 
-       if ((cl = __cls_set_class(&r->class, 0)) != 0)
-               tp->q->ops->cl_ops->unbind_tcf(tp->q, cl);
-}
+       /* rtnetlink specific */
+       int                     (*dump)(struct tcf_proto*, unsigned long, struct sk_buff *skb, struct tcmsg*);
 
-#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);
+       struct module           *owner;
+};
 
-               tcf_action_destroy(act, TCA_ACT_UNBIND);
-       } else
-               *action = act;
+/* Main classifier routine: scans classifier chain attached
+   to this qdisc, (optionally) tests for protocol and asks
+   specific classifiers.
+ */
 
-       return 0;
-}
-
-static inline int
-tcf_change_act(struct tcf_proto *tp, struct tc_action **action,
-       struct rtattr *act_tlv, struct rtattr *rate_tlv)
+static inline int tc_classify(struct sk_buff *skb, struct tcf_proto *tp, struct tcf_result *res)
 {
-       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;
+       int err = 0;
+       u32 protocol = skb->protocol;
+#ifdef CONFIG_NET_CLS_ACT
+       struct tcf_proto *otp = tp;
+reclassify:
+#endif
+       protocol = skb->protocol;
 
-       return 0;
-}
+       for ( ; tp; tp = tp->next) {
+               if ((tp->protocol == protocol ||
+                       tp->protocol == __constant_htons(ETH_P_ALL)) &&
+                       (err = tp->classify(skb, tp, res)) >= 0) {
+#ifdef CONFIG_NET_CLS_ACT
+                       if ( TC_ACT_RECLASSIFY == err) {
+                               __u32 verd = (__u32) G_TC_VERD(skb->tc_verd);
+                               tp = otp;
+
+                               if (MAX_REC_LOOP < verd++) {
+                                       printk("rule prio %d protocol %02x reclassify is buggy packet dropped\n",tp->prio&0xffff, ntohs(tp->protocol));
+                                       return TC_ACT_SHOT;
+                               }
+                               skb->tc_verd = SET_TC_VERD(skb->tc_verd,verd);
+                               goto reclassify;
+                       } else {
+                               if (skb->tc_verd) 
+                                       skb->tc_verd = SET_TC_VERD(skb->tc_verd,0);
+                               return err;
+                       }
+#else
+
+                       return err;
+#endif
+            }
 
-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)
+static inline void tcf_destroy(struct tcf_proto *tp)
 {
-       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;
+       tp->ops->destroy(tp);
+       module_put(tp->ops->owner);
+       kfree(tp);
 }
 
-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;
+extern int register_tcf_proto_ops(struct tcf_proto_ops *ops);
+extern int unregister_tcf_proto_ops(struct tcf_proto_ops *ops);
+extern int ing_filter(struct sk_buff *skb);
 
-               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