9p: VFS switches for 9p2000.L: protocol and client changes
[safe/jmp/linux-2.6] / net / sched / act_mirred.c
index 4fcccbd..c0b6863 100644 (file)
  *
  */
 
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
 #include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <linux/rtnetlink.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/proc_fs.h>
-#include <net/sock.h>
+#include <linux/gfp.h>
+#include <net/net_namespace.h>
+#include <net/netlink.h>
 #include <net/pkt_sched.h>
 #include <linux/tc_act/tc_mirred.h>
 #include <net/tc_act/tc_mirred.h>
 
-#include <linux/etherdevice.h>
 #include <linux/if_arp.h>
 
-
-/* use generic hash table */
-#define MY_TAB_SIZE     8
-#define MY_TAB_MASK     (MY_TAB_SIZE - 1)
-static u32 idx_gen;
-static struct tcf_mirred *tcf_mirred_ht[MY_TAB_SIZE];
+#define MIRRED_TAB_MASK     7
+static struct tcf_common *tcf_mirred_ht[MIRRED_TAB_MASK + 1];
+static u32 mirred_idx_gen;
 static DEFINE_RWLOCK(mirred_lock);
 
-/* ovewrride the defaults */
-#define tcf_st         tcf_mirred
-#define tc_st          tc_mirred
-#define tcf_t_lock     mirred_lock
-#define tcf_ht         tcf_mirred_ht
-
-#define CONFIG_NET_ACT_INIT 1
-#include <net/pkt_act.h>
+static struct tcf_hashinfo mirred_hash_info = {
+       .htab   =       tcf_mirred_ht,
+       .hmask  =       MIRRED_TAB_MASK,
+       .lock   =       &mirred_lock,
+};
 
-static inline int
-tcf_mirred_release(struct tcf_mirred *p, int bind)
+static inline int tcf_mirred_release(struct tcf_mirred *m, int bind)
 {
-       if (p) {
+       if (m) {
                if (bind)
-                       p->bindcnt--;
-               p->refcnt--;
-               if(!p->bindcnt && p->refcnt <= 0) {
-                       dev_put(p->dev);
-                       tcf_hash_destroy(p);
+                       m->tcf_bindcnt--;
+               m->tcf_refcnt--;
+               if(!m->tcf_bindcnt && m->tcf_refcnt <= 0) {
+                       dev_put(m->tcfm_dev);
+                       tcf_hash_destroy(&m->common, &mirred_hash_info);
                        return 1;
                }
        }
        return 0;
 }
 
-static int
-tcf_mirred_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a,
-                int ovr, int bind)
+static const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = {
+       [TCA_MIRRED_PARMS]      = { .len = sizeof(struct tc_mirred) },
+};
+
+static int tcf_mirred_init(struct nlattr *nla, struct nlattr *est,
+                          struct tc_action *a, int ovr, int bind)
 {
-       struct rtattr *tb[TCA_MIRRED_MAX];
+       struct nlattr *tb[TCA_MIRRED_MAX + 1];
        struct tc_mirred *parm;
-       struct tcf_mirred *p;
-       struct net_device *dev = NULL;
-       int ret = 0;
-       int ok_push = 0;
+       struct tcf_mirred *m;
+       struct tcf_common *pc;
+       struct net_device *dev;
+       int ret, ok_push = 0;
 
-       if (rta == NULL || rtattr_parse_nested(tb, TCA_MIRRED_MAX, rta) < 0)
+       if (nla == NULL)
                return -EINVAL;
-
-       if (tb[TCA_MIRRED_PARMS-1] == NULL ||
-           RTA_PAYLOAD(tb[TCA_MIRRED_PARMS-1]) < sizeof(*parm))
+       ret = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy);
+       if (ret < 0)
+               return ret;
+       if (tb[TCA_MIRRED_PARMS] == NULL)
                return -EINVAL;
-       parm = RTA_DATA(tb[TCA_MIRRED_PARMS-1]);
-
+       parm = nla_data(tb[TCA_MIRRED_PARMS]);
+       switch (parm->eaction) {
+       case TCA_EGRESS_MIRROR:
+       case TCA_EGRESS_REDIR:
+               break;
+       default:
+               return -EINVAL;
+       }
        if (parm->ifindex) {
-               dev = __dev_get_by_index(parm->ifindex);
+               dev = __dev_get_by_index(&init_net, parm->ifindex);
                if (dev == NULL)
                        return -ENODEV;
                switch (dev->type) {
-                       case ARPHRD_TUNNEL:
-                       case ARPHRD_TUNNEL6:
-                       case ARPHRD_SIT:
-                       case ARPHRD_IPGRE:
-                       case ARPHRD_VOID:
-                       case ARPHRD_NONE:
-                               ok_push = 0;
-                               break;
-                       default:
-                               ok_push = 1;
-                               break;
+               case ARPHRD_TUNNEL:
+               case ARPHRD_TUNNEL6:
+               case ARPHRD_SIT:
+               case ARPHRD_IPGRE:
+               case ARPHRD_VOID:
+               case ARPHRD_NONE:
+                       ok_push = 0;
+                       break;
+               default:
+                       ok_push = 1;
+                       break;
                }
+       } else {
+               dev = NULL;
        }
 
-       p = tcf_hash_check(parm->index, a, ovr, bind);
-       if (p == NULL) {
-               if (!parm->ifindex)
+       pc = tcf_hash_check(parm->index, a, bind, &mirred_hash_info);
+       if (!pc) {
+               if (dev == NULL)
                        return -EINVAL;
-               p = tcf_hash_create(parm->index, est, a, sizeof(*p), ovr, bind);
-               if (p == NULL)
-                       return -ENOMEM;
+               pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind,
+                                    &mirred_idx_gen, &mirred_hash_info);
+               if (IS_ERR(pc))
+                       return PTR_ERR(pc);
                ret = ACT_P_CREATED;
        } else {
                if (!ovr) {
-                       tcf_mirred_release(p, bind);
+                       tcf_mirred_release(to_mirred(pc), bind);
                        return -EEXIST;
                }
        }
+       m = to_mirred(pc);
 
-       spin_lock_bh(&p->lock);
-       p->action = parm->action;
-       p->eaction = parm->eaction;
-       if (parm->ifindex) {
-               p->ifindex = parm->ifindex;
+       spin_lock_bh(&m->tcf_lock);
+       m->tcf_action = parm->action;
+       m->tcfm_eaction = parm->eaction;
+       if (dev != NULL) {
+               m->tcfm_ifindex = parm->ifindex;
                if (ret != ACT_P_CREATED)
-                       dev_put(p->dev);
-               p->dev = dev;
+                       dev_put(m->tcfm_dev);
                dev_hold(dev);
-               p->ok_push = ok_push;
+               m->tcfm_dev = dev;
+               m->tcfm_ok_push = ok_push;
        }
-       spin_unlock_bh(&p->lock);
+       spin_unlock_bh(&m->tcf_lock);
        if (ret == ACT_P_CREATED)
-               tcf_hash_insert(p);
+               tcf_hash_insert(pc, &mirred_hash_info);
 
-       DPRINTK("tcf_mirred_init index %d action %d eaction %d device %s "
-               "ifindex %d\n", parm->index, parm->action, parm->eaction,
-               dev->name, parm->ifindex);
        return ret;
 }
 
-static int
-tcf_mirred_cleanup(struct tc_action *a, int bind)
+static int tcf_mirred_cleanup(struct tc_action *a, int bind)
 {
-       struct tcf_mirred *p = PRIV(a, mirred);
+       struct tcf_mirred *m = a->priv;
 
-       if (p != NULL)
-               return tcf_mirred_release(p, bind);
+       if (m)
+               return tcf_mirred_release(m, bind);
        return 0;
 }
 
-static int
-tcf_mirred(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res)
+static int tcf_mirred(struct sk_buff *skb, struct tc_action *a,
+                     struct tcf_result *res)
 {
-       struct tcf_mirred *p = PRIV(a, mirred);
+       struct tcf_mirred *m = a->priv;
        struct net_device *dev;
-       struct sk_buff *skb2 = NULL;
-       u32 at = G_TC_AT(skb->tc_verd);
+       struct sk_buff *skb2;
+       u32 at;
+       int retval, err = 1;
 
-       spin_lock(&p->lock);
+       spin_lock(&m->tcf_lock);
+       m->tcf_tm.lastuse = jiffies;
 
-       dev = p->dev;
-       p->tm.lastuse = jiffies;
-
-       if (!(dev->flags&IFF_UP) ) {
+       dev = m->tcfm_dev;
+       if (!(dev->flags & IFF_UP)) {
                if (net_ratelimit())
-                       printk("mirred to Houston: device %s is gone!\n",
-                              dev->name);
-bad_mirred:
-               if (skb2 != NULL)
-                       kfree_skb(skb2);
-               p->qstats.overlimits++;
-               p->bstats.bytes += skb->len;
-               p->bstats.packets++;
-               spin_unlock(&p->lock);
-               /* should we be asking for packet to be dropped?
-                * may make sense for redirect case only
-               */
-               return TC_ACT_SHOT;
+                       pr_notice("tc mirred to Houston: device %s is gone!\n",
+                                 dev->name);
+               goto out;
        }
 
-       skb2 = skb_clone(skb, GFP_ATOMIC);
+       skb2 = skb_act_clone(skb, GFP_ATOMIC);
        if (skb2 == NULL)
-               goto bad_mirred;
-       if (p->eaction != TCA_EGRESS_MIRROR && p->eaction != TCA_EGRESS_REDIR) {
-               if (net_ratelimit())
-                       printk("tcf_mirred unknown action %d\n", p->eaction);
-               goto bad_mirred;
-       }
+               goto out;
 
-       p->bstats.bytes += skb2->len;
-       p->bstats.packets++;
-       if (!(at & AT_EGRESS))
-               if (p->ok_push)
+       m->tcf_bstats.bytes += qdisc_pkt_len(skb2);
+       m->tcf_bstats.packets++;
+       at = G_TC_AT(skb->tc_verd);
+       if (!(at & AT_EGRESS)) {
+               if (m->tcfm_ok_push)
                        skb_push(skb2, skb2->dev->hard_header_len);
+       }
 
        /* mirror is always swallowed */
-       if (p->eaction != TCA_EGRESS_MIRROR)
+       if (m->tcfm_eaction != TCA_EGRESS_MIRROR)
                skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at);
 
        skb2->dev = dev;
-       skb2->input_dev = skb->dev;
+       skb2->skb_iif = skb->dev->ifindex;
        dev_queue_xmit(skb2);
-       spin_unlock(&p->lock);
-       return p->action;
+       err = 0;
+
+out:
+       if (err) {
+               m->tcf_qstats.overlimits++;
+               m->tcf_bstats.bytes += qdisc_pkt_len(skb);
+               m->tcf_bstats.packets++;
+               /* should we be asking for packet to be dropped?
+                * may make sense for redirect case only
+                */
+               retval = TC_ACT_SHOT;
+       } else {
+               retval = m->tcf_action;
+       }
+       spin_unlock(&m->tcf_lock);
+
+       return retval;
 }
 
-static int
-tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
+static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
 {
-       unsigned char *b = skb->tail;
+       unsigned char *b = skb_tail_pointer(skb);
+       struct tcf_mirred *m = a->priv;
        struct tc_mirred opt;
-       struct tcf_mirred *p = PRIV(a, mirred);
        struct tcf_t t;
 
-       opt.index = p->index;
-       opt.action = p->action;
-       opt.refcnt = p->refcnt - ref;
-       opt.bindcnt = p->bindcnt - bind;
-       opt.eaction = p->eaction;
-       opt.ifindex = p->ifindex;
-       DPRINTK("tcf_mirred_dump index %d action %d eaction %d ifindex %d\n",
-                p->index, p->action, p->eaction, p->ifindex);
-       RTA_PUT(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt);
-       t.install = jiffies_to_clock_t(jiffies - p->tm.install);
-       t.lastuse = jiffies_to_clock_t(jiffies - p->tm.lastuse);
-       t.expires = jiffies_to_clock_t(p->tm.expires);
-       RTA_PUT(skb, TCA_MIRRED_TM, sizeof(t), &t);
+       opt.index = m->tcf_index;
+       opt.action = m->tcf_action;
+       opt.refcnt = m->tcf_refcnt - ref;
+       opt.bindcnt = m->tcf_bindcnt - bind;
+       opt.eaction = m->tcfm_eaction;
+       opt.ifindex = m->tcfm_ifindex;
+       NLA_PUT(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt);
+       t.install = jiffies_to_clock_t(jiffies - m->tcf_tm.install);
+       t.lastuse = jiffies_to_clock_t(jiffies - m->tcf_tm.lastuse);
+       t.expires = jiffies_to_clock_t(m->tcf_tm.expires);
+       NLA_PUT(skb, TCA_MIRRED_TM, sizeof(t), &t);
        return skb->len;
 
-      rtattr_failure:
-       skb_trim(skb, b - skb->data);
+nla_put_failure:
+       nlmsg_trim(skb, b);
        return -1;
 }
 
 static struct tc_action_ops act_mirred_ops = {
        .kind           =       "mirred",
+       .hinfo          =       &mirred_hash_info,
        .type           =       TCA_ACT_MIRRED,
        .capab          =       TCA_CAP_NONE,
        .owner          =       THIS_MODULE,
@@ -258,15 +250,13 @@ MODULE_AUTHOR("Jamal Hadi Salim(2002)");
 MODULE_DESCRIPTION("Device Mirror/redirect actions");
 MODULE_LICENSE("GPL");
 
-static int __init
-mirred_init_module(void)
+static int __init mirred_init_module(void)
 {
-       printk("Mirror/redirect action on\n");
+       pr_info("Mirror/redirect action on\n");
        return tcf_register_action(&act_mirred_ops);
 }
 
-static void __exit
-mirred_cleanup_module(void)
+static void __exit mirred_cleanup_module(void)
 {
        tcf_unregister_action(&act_mirred_ops);
 }