From mboxrd@z Thu Jan 1 00:00:00 1970 From: jamal Subject: patch: Mirred action Date: 11 Oct 2004 08:49:32 -0400 Sender: netdev-bounce@oss.sgi.com Message-ID: <1097498972.15075.7.camel@jzny.localdomain> Reply-To: hadi@cyberus.ca Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-cIzlnaPz+z+AzlOKJHvT" Cc: netdev@oss.sgi.com Return-path: To: "David S. Miller" Errors-to: netdev-bounce@oss.sgi.com List-Id: netdev.vger.kernel.org --=-cIzlnaPz+z+AzlOKJHvT Content-Type: text/plain Content-Transfer-Encoding: 7bit Dave, I am gonna start trickling these actions/driver patches to you. signed off by me cheers, jamal --=-cIzlnaPz+z+AzlOKJHvT Content-Disposition: attachment; filename=269-rc3-mirred_kp Content-Type: text/plain; name=269-rc3-mirred_kp; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit --- /dev/null 1998-05-05 16:32:27.000000000 -0400 +++ b/include/net/tc_act/tc_mirred.h 2004-10-01 09:18:32.000000000 -0400 @@ -0,0 +1,15 @@ +#ifndef __NET_TC_MIR_H +#define __NET_TC_MIR_H + +#include + +struct tcf_mirred +{ + tca_gen(mirred); + int eaction; + int ifindex; + int ok_push; + struct net_device *dev; +}; + +#endif --- /dev/null 1998-05-05 16:32:27.000000000 -0400 +++ b/include/linux/tc_act/tc_mirred.h 2004-10-01 09:18:32.000000000 -0400 @@ -0,0 +1,28 @@ +#ifndef __LINUX_TC_MIR_H +#define __LINUX_TC_MIR_H + +#include + +#define TCA_ACT_MIRRED 8 +#define TCA_EGRESS_REDIR 1 /* packet redirect to EGRESS*/ +#define TCA_EGRESS_MIRROR 2 /* mirror packet to EGRESS */ +#define TCA_INGRESS_REDIR 3 /* packet redirect to INGRESS*/ +#define TCA_INGRESS_MIRROR 4 /* mirror packet to INGRESS */ + +struct tc_mirred +{ + tc_gen; + int eaction; /* one of IN/EGRESS_MIRROR/REDIR */ + __u32 ifindex; /* ifindex of egress port */ +}; + +enum +{ + TCA_MIRRED_UNSPEC, + TCA_MIRRED_TM, + TCA_MIRRED_PARMS, + __TCA_MIRRED_MAX +}; +#define TCA_MIRRED_MAX (__TCA_MIRRED_MAX - 1) + +#endif --- a/net/sched/Makefile 2004/10/01 13:16:40 1.1 +++ b/net/sched/Makefile 2004/10/01 13:17:34 @@ -11,6 +11,7 @@ obj-$(CONFIG_NET_ACT_POLICE) += police.o obj-$(CONFIG_NET_CLS_POLICE) += police.o obj-$(CONFIG_NET_ACT_GACT) += gact.o +obj-$(CONFIG_NET_ACT_MIRRED) += mirred.o obj-$(CONFIG_NET_SCH_CBQ) += sch_cbq.o obj-$(CONFIG_NET_SCH_HTB) += sch_htb.o obj-$(CONFIG_NET_SCH_HPFQ) += sch_hpfq.o --- a/net/sched/Kconfig 2004/10/01 13:13:33 1.1 +++ b/net/sched/Kconfig 2004/10/01 13:16:34 @@ -399,3 +399,10 @@ depends on NET_ACT_GACT ---help--- Allows generic actions to be randomly or deterministically used + +config NET_ACT_MIRRED + tristate "Packet In/Egress redirecton/mirror Actions" + depends on NET_CLS_ACT + ---help--- + requires new iproute2 + This allows packets to be mirrored or redirected to netdevices --- /dev/null 1998-05-05 16:32:27.000000000 -0400 +++ b/net/sched/mirred.c 2004-10-11 08:34:34.000000000 -0400 @@ -0,0 +1,318 @@ +/* + * net/sched/mirred.c packet mirroring and redirect actions + * + * 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: Jamal Hadi Salim (2002-4) + * + * TODO: Add ingress support (and socket redirect support) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* 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]; +static rwlock_t mirred_lock = RW_LOCK_UNLOCKED; + +/* 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 + +static inline int +tcf_mirred_release(struct tcf_mirred *p, int bind) +{ + if (p) { + if (bind) { + p->bindcnt--; + } + + p->refcnt--; + if(!p->bindcnt && p->refcnt <= 0) { + dev_put(p->dev); + tcf_hash_destroy(p); + return 1; + } + } + + return 0; +} + +int +tcf_mirred_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a,int ovr, int bind) +{ + struct rtattr *tb[TCA_MIRRED_MAX]; + struct tc_mirred *parm; + struct tcf_mirred *p; + struct net_device *dev = NULL; + int size = sizeof (*p), new = 0; + + + if (rtattr_parse(tb, TCA_MIRRED_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta)) < 0) { + DPRINTK("tcf_mirred_init BUG in user space couldnt parse properly\n"); + return -1; + } + + if (NULL == a || NULL == tb[TCA_MIRRED_PARMS - 1]) { + DPRINTK("BUG: tcf_mirred_init called with NULL params\n"); + return -1; + } + + parm = RTA_DATA(tb[TCA_MIRRED_PARMS - 1]); + + p = tcf_hash_check(parm, a, ovr, bind); + if (NULL == p) { /* new */ + p = tcf_hash_create(parm,est,a,size,ovr,bind); + new = 1; + if (NULL == p) + return -1; + } + + if (parm->ifindex) { + dev = dev_get_by_index(parm->ifindex); + if (NULL == dev) { + printk("BUG: tcf_mirred_init called with bad device\n"); + return -1; + } + switch (dev->type) { + case ARPHRD_TUNNEL: + case ARPHRD_TUNNEL6: + case ARPHRD_SIT: + case ARPHRD_IPGRE: + case ARPHRD_VOID: + case ARPHRD_NONE: + p->ok_push = 0; + break; + default: + p->ok_push = 1; + break; + } + } else { + if (new) { + kfree(p); + return -1; + } + } + + if (new || ovr) { + spin_lock(&p->lock); + p->action = parm->action; + p->eaction = parm->eaction; + if (parm->ifindex) { + p->ifindex = parm->ifindex; + p->dev = dev; + dev_hold(p->dev); + } + spin_unlock(&p->lock); + } + + + DPRINTK(" tcf_mirred_init index %d action %d eaction %d device %s ifndex %d\n",parm->index,parm->action,parm->eaction,dev->name,parm->ifindex); + return new; + +} + +int +tcf_mirred_cleanup(struct tc_action *a, int bind) +{ + struct tcf_mirred *p; + p = PRIV(a,mirred); + if (NULL != p) + return tcf_mirred_release(p, bind); + return 0; +} + +int +tcf_mirred(struct sk_buff **pskb, struct tc_action *a) +{ + struct tcf_mirred *p; + struct net_device *dev; + struct sk_buff *skb2 = NULL; + struct sk_buff *skb = *pskb; + __u32 at = G_TC_AT(skb->tc_verd); + + if (NULL == a) { + if (net_ratelimit()) + printk("BUG: tcf_mirred called with NULL action!\n"); + return -1; + } + + p = PRIV(a,mirred); + + if (NULL == p) { + if (net_ratelimit()) + printk("BUG: tcf_mirred called with NULL params\n"); + return -1; + } + + spin_lock(&p->lock); + + dev = p->dev; + p->tm.lastuse = jiffies; + + if (NULL == dev || !(dev->flags&IFF_UP) ) { + if (net_ratelimit()) + printk("mirred to Houston: device %s is gone!\n", + dev?dev->name:""); +bad_mirred: + if (NULL != skb2) + kfree_skb(skb2); + p->stats.overlimits++; + p->stats.bytes += skb->len; + p->stats.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; + } + + skb2 = skb_clone(skb, GFP_ATOMIC); + if (skb2 == NULL) { + goto bad_mirred; + } + if (TCA_EGRESS_MIRROR != p->eaction && + TCA_EGRESS_REDIR != p->eaction) { + if (net_ratelimit()) + printk("tcf_mirred unknown action %d\n",p->eaction); + goto bad_mirred; + } + + p->stats.bytes += skb2->len; + p->stats.packets++; + if ( !(at & AT_EGRESS)) { + if (p->ok_push) { + skb_push(skb2, skb2->dev->hard_header_len); + } + } + + /* mirror is always swallowed */ + if (TCA_EGRESS_MIRROR != p->eaction) + skb2->tc_verd = SET_TC_FROM(skb2->tc_verd,at); + + skb2->dev = dev; + skb2->input_dev = skb->dev; + dev_queue_xmit(skb2); + spin_unlock(&p->lock); + return p->action; +} + +int +tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a,int bind, int ref) +{ + unsigned char *b = skb->tail; + struct tc_mirred opt; + struct tcf_mirred *p; + struct tcf_t t; + + p = PRIV(a,mirred); + if (NULL == p) { + printk("BUG: tcf_mirred_dump called with NULL params\n"); + goto rtattr_failure; + } + + 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 ifndex %d\n",p->index,p->action,p->eaction,p->ifindex); + RTA_PUT(skb, TCA_MIRRED_PARMS, sizeof (opt), &opt); + t.install = jiffies - p->tm.install; + t.lastuse = jiffies - p->tm.lastuse; + t.expires = p->tm.expires; + RTA_PUT(skb, TCA_MIRRED_TM, sizeof (t), &t); + return skb->len; + + rtattr_failure: + skb_trim(skb, b - skb->data); + return -1; +} + +int +tcf_mirred_stats(struct sk_buff *skb, struct tc_action *a) +{ + struct tcf_mirred *p; + p = PRIV(a,mirred); + + if (NULL != p) + return qdisc_copy_stats(skb, &p->stats, p->stats_lock); + + return 1; +} + +static struct tc_action_ops act_mirred_ops = { + .next = NULL, + .kind = "mirred", + .type = TCA_ACT_MIRRED, + .capab = TCA_CAP_NONE, + .owner = THIS_MODULE, + .act = tcf_mirred, + .get_stats = tcf_mirred_stats, + .dump = tcf_mirred_dump, + .cleanup = tcf_mirred_cleanup, + .lookup = tcf_hash_search, + .init = tcf_mirred_init, + .walk = tcf_generic_walker +}; + +MODULE_AUTHOR("Jamal Hadi Salim(2002)"); +MODULE_DESCRIPTION("Device Mirror/redirect actions"); +MODULE_LICENSE("GPL"); + + +static int __init +mirred_init_module(void) +{ + printk("Mirror/redirect action on\n"); + return tcf_register_action(&act_mirred_ops); +} + +static void __exit +mirred_cleanup_module(void) +{ + tcf_unregister_action(&act_mirred_ops); +} + +module_init(mirred_init_module); +module_exit(mirred_cleanup_module); + --=-cIzlnaPz+z+AzlOKJHvT--