[ANNOUNCE] sch_dup - duplicate packet queue discipline [2.6]

Linux Advanced Routing and Traffic Control

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello!

This is my first work for kernel, so please have mercy. :)

OK, I like to announce sch_dup, a new queue discipline that, attached to a
class (or a device, as root) duplicate packets that pass. Yes, you can
control the frequency of duplicates.

Example:
tc qdisc add dev eth0 root dup limit 100 gap 1
This means: create a pfifo queue and send packets with
a gap of 1 (0 = no dups) between duplicates:
gap=0: no duplication
gap=1: NDNDNDNDND
gap=2: NNDNNDNNDNNDNND
(N=not duplicated, D duplicated)

Attached are 3 patches: 1 patch for net/sched dir, other
for include/linux/pkg_sched.h, and the last for iproute2.

Any comments are appreciated.

David, please include it in 2.6.
Alexey, please include the third patch in iproute2.

Thank you!
---
Catalin(ux aka Dino) BOIE
catab at deuroconsult.ro
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, <catab at deuroconsult.ro>
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/capability.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/tcp.h>
+#include <linux/time.h>
+
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+
+#include <linux/string.h>
+#include <linux/netdevice.h>
+#include <net/pkt_sched.h>
+
+#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 - <catab at deuroconsult.ro>");
+MODULE_DESCRIPTION("sch_dup - Duplicate every n packet");
diff -x '*.o' -x '*.ko' -upr linux-2.6.5-rc2-orig/include/linux/pkt_sched.h linux-2.6.5-rc2/include/linux/pkt_sched.h
--- linux-2.6.5-rc2-orig/include/linux/pkt_sched.h	2004-03-22 10:16:27.000000000 +0200
+++ linux-2.6.5-rc2/include/linux/pkt_sched.h	2004-03-29 12:01:17.000000000 +0300
@@ -438,4 +438,13 @@ struct tc_dly_qopt
 	__u32	latency;
 	__u32   limit;
 };	
+
+
+/* Dup section */
+struct tc_dup_qopt
+{
+	__u32	gap;
+	__u32	limit;
+};
+
 #endif
diff -upr iproute2-2.4.7-now-ss020116-try/tc/Makefile iproute2-2.4.7-now-ss020116-try-dup/tc/Makefile
--- iproute2-2.4.7-now-ss020116-try/tc/Makefile	2002-01-10 05:08:18.000000000 +0200
+++ iproute2-2.4.7-now-ss020116-try-dup/tc/Makefile	2004-03-29 11:56:15.000000000 +0300
@@ -27,6 +27,7 @@ endif
 #TCMODULES += q_csz.o
 #TCMODULES += q_hpfq.o
 #TCMODULES += q_hfsc.o
+TCMODULES += q_dup.o
 
 TCOBJ += $(TCMODULES)
 
Only in iproute2-2.4.7-now-ss020116-try-dup/tc: q_dup.c
diff -upr iproute2-2.4.7-now-ss020116-try/tc/tc_qdisc.c iproute2-2.4.7-now-ss020116-try-dup/tc/tc_qdisc.c
--- iproute2-2.4.7-now-ss020116-try/tc/tc_qdisc.c	2002-01-15 13:15:23.000000000 +0200
+++ iproute2-2.4.7-now-ss020116-try-dup/tc/tc_qdisc.c	2004-03-29 11:56:56.000000000 +0300
@@ -36,7 +36,7 @@ static void usage(void)
 	fprintf(stderr, "\n");
 	fprintf(stderr, "       tc qdisc show [ dev STRING ] [ingress]\n");
 	fprintf(stderr, "Where:\n");
-	fprintf(stderr, "QDISC_KIND := { [p|b]fifo | tbf | prio | cbq | red | etc. }\n");
+	fprintf(stderr, "QDISC_KIND := { [p|b]fifo | tbf | prio | cbq | red | dup | etc. }\n");
 	fprintf(stderr, "OPTIONS := ... try tc qdisc add <desired QDISC_KIND> help\n");
 	exit(-1);
 }

[Index of Archives]     [LARTC Home Page]     [Netfilter]     [Netfilter Development]     [Network Development]     [Bugtraq]     [GCC Help]     [Yosemite News]     [Linux Kernel]     [Fedora Users]
  Powered by Linux