diff -x '*.mod.c' -x '*.cmd' -x '*.o' -x '*.ko' --new-file -upr linux-2.6.5-rc2-orig/net/sched/Kconfig linux-2.6.5-rc2/net/sched/Kconfig --- linux-2.6.5-rc2-orig/net/sched/Kconfig 2004-03-22 10:16:28.000000000 +0200 +++ linux-2.6.5-rc2/net/sched/Kconfig 2004-03-29 12:08:28.000000000 +0300 @@ -175,6 +175,16 @@ config NET_SCH_DELAY To compile this driver as a module, choose M here: the module will be called sch_delay. +config NET_SCH_DUP + tristate "Duplicate simulator" + depends on NET_SCHED + help + Say Y if you want to simulate duplicate packets. + This is intended mainly for testing. + + To compile this driver as a module, choose M here: the module + will be called sch_dup. + config NET_SCH_INGRESS tristate "Ingress Qdisc" depends on NET_SCHED && NETFILTER diff -x '*.mod.c' -x '*.cmd' -x '*.o' -x '*.ko' --new-file -upr linux-2.6.5-rc2-orig/net/sched/Makefile linux-2.6.5-rc2/net/sched/Makefile --- linux-2.6.5-rc2-orig/net/sched/Makefile 2004-03-22 10:16:28.000000000 +0200 +++ linux-2.6.5-rc2/net/sched/Makefile 2004-03-29 12:08:40.000000000 +0300 @@ -23,6 +23,7 @@ obj-$(CONFIG_NET_SCH_TEQL) += sch_teql.o obj-$(CONFIG_NET_SCH_PRIO) += sch_prio.o obj-$(CONFIG_NET_SCH_ATM) += sch_atm.o obj-$(CONFIG_NET_SCH_DELAY) += sch_delay.o +obj-$(CONFIG_NET_SCH_DELAY) += sch_dup.o obj-$(CONFIG_NET_CLS_U32) += cls_u32.o obj-$(CONFIG_NET_CLS_ROUTE4) += cls_route.o obj-$(CONFIG_NET_CLS_FW) += cls_fw.o diff -x '*.mod.c' -x '*.cmd' -x '*.o' -x '*.ko' --new-file -upr linux-2.6.5-rc2-orig/net/sched/sch_dup.c linux-2.6.5-rc2/net/sched/sch_dup.c --- linux-2.6.5-rc2-orig/net/sched/sch_dup.c 1970-01-01 02:00:00.000000000 +0200 +++ linux-2.6.5-rc2/net/sched/sch_dup.c 2004-03-29 12:59:42.000000000 +0300 @@ -0,0 +1,228 @@ +/* + * net/sched/sch_dup.c Duplicate packet scheduler routines. + * + * 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: Catalin(ux aka Dino) BOIE, + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#define MODULE_NAME "dup v0.1" +#if 0 +#define DPRINTK(format,args...) printk(KERN_DEBUG MODULE_NAME ": " format, ##args) +#else +#define DPRINTK(format,args...) +#endif + +/* global variables */ + +/* qdisc internal data */ +struct dup_sched_data { + __u32 limit; /* in packets */ + __u32 gap; /* gap + 1 between duplicate packets */ + /* 0 = disable */ + /* 1 = dup every packet */ + /* 2 = 1 normal, one duplicated */ + __u32 counter; +}; + +static int dup_init(struct Qdisc *sch, struct rtattr *opt) +{ + struct dup_sched_data *q = (struct dup_sched_data *)sch->data; + + q->counter = 0; + + if (!opt) { + q->limit = sch->dev->tx_queue_len; + q->gap = 0; + } else { + struct tc_dup_qopt *ctl = RTA_DATA(opt); + + if (opt->rta_len < RTA_LENGTH(sizeof(*ctl))) + return -EINVAL; + + q->limit = ctl->limit > 0 ? ctl->limit : 100; + q->gap = ctl->gap; + } + + return 0; +} + +static int dup_enqueue(struct sk_buff *skb, struct Qdisc *sch) +{ + struct dup_sched_data *q = (struct dup_sched_data *)sch->data; + + /* increment counter */ + q->counter++; + + DPRINTK("enqueue: len=%d Q%X:%X gap=%d counter=%d\n", + skb->len, sch->handle >> 16, sch->handle & 0xffff, + q->gap, q->counter); + + /* normal send */ + if (sch->q.qlen < q->limit) { + struct sk_buff *clone; + + __skb_queue_tail(&sch->q, skb); + sch->stats.bytes += skb->len; + sch->stats.packets++; + + /* clone skb */ + clone = skb_clone(skb, GFP_ATOMIC); + if (clone) { + /* Ignore queue size. We really need to send a duplicate. :) */ + if ((q->gap > 0) && (q->counter >= q->gap)) { + DPRINTK("duplicate!\n"); + + /* reset counter */ + q->counter = 0; + + /* send duplicate */ + __skb_queue_tail(&sch->q, clone); + sch->stats.bytes += clone->len; + sch->stats.packets++; + } else { + kfree_skb(clone); + } + } + + return 0; + } + + sch->stats.drops++; + kfree_skb(skb); + + return NET_XMIT_DROP; +} + +static int dup_requeue(struct sk_buff *skb, struct Qdisc *sch) +{ + + __skb_queue_head(&sch->q, skb); + + return 0; +} + +static struct sk_buff *dup_dequeue(struct Qdisc *sch) +{ + struct sk_buff *skb; + + skb = __skb_dequeue(&sch->q); + + return skb; +} + +static unsigned int dup_drop(struct Qdisc *sch) +{ + struct sk_buff *skb; + + skb = __skb_dequeue_tail(&sch->q); + if (skb) { + unsigned int len = skb->len; + + sch->stats.backlog -= len; + kfree_skb(skb); + return len; + } + + return 0; +} + +static void dup_reset(struct Qdisc *sch) +{ + + skb_queue_purge(&sch->q); + sch->stats.backlog = 0; +} + +static int dup_dump(struct Qdisc *sch, struct sk_buff *skb) +{ + struct dup_sched_data *q = (struct dup_sched_data *)sch->data; + struct tc_dup_qopt opt; + unsigned char *b = skb->tail; + + opt.limit = q->limit; + opt.gap = q->gap; + RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); + + return skb->len; + + rtattr_failure: + skb_trim(skb, b - skb->data); + return -1; +} + +static struct Qdisc_ops dup_qdisc_ops = { + .next = NULL, + .cl_ops = NULL, + .id = "dup", + .priv_size = sizeof(struct dup_sched_data), + .enqueue = dup_enqueue, + .dequeue = dup_dequeue, + .requeue = dup_requeue, + .drop = dup_drop, + .init = dup_init, + .reset = dup_reset, + .destroy = NULL, + .change = dup_init, + .dump = dup_dump, + .owner = THIS_MODULE, +}; + +static int __init init_dup(void) +{ + int ret; + + printk(KERN_INFO "%s: (C)opyright Catalin(ux) BOIE 2002-2003\n", MODULE_NAME); + + ret = register_qdisc(&dup_qdisc_ops); + if (ret != 0) { + printk(KERN_DEBUG "%s: cannot register qdisc dup. Sorry!\n", + MODULE_NAME); + return -ENOMEM; + } + + return 0; +} + +static void __exit exit_dup(void) +{ + int ret; + + printk(KERN_DEBUG "%s: Goodbye!\n", MODULE_NAME); + + ret = unregister_qdisc(&dup_qdisc_ops); + if (ret != 0) { + printk(KERN_DEBUG "%s: Cannot unregister qdisc dup. Sorry!\n", + MODULE_NAME); + } +} + +module_init(init_dup); +module_exit(exit_dup); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Catalin(ux) BOIE - "); +MODULE_DESCRIPTION("sch_dup - Duplicate every n packet");