diff options
author | Imre Kaloz <kaloz@openwrt.org> | 2008-06-02 08:22:56 +0000 |
---|---|---|
committer | Imre Kaloz <kaloz@openwrt.org> | 2008-06-02 08:22:56 +0000 |
commit | 9ca16cf1b6246d99df192aa0131d39bb0aa31998 (patch) | |
tree | a3141c916b391658ab197350ee398aace4ad9f35 /target/linux/generic-2.6/patches-2.6.26/150-netfilter_imq.patch | |
parent | ed893cab23c6b9ffa02a6515969ceb2e5cde13c7 (diff) | |
download | upstream-9ca16cf1b6246d99df192aa0131d39bb0aa31998.tar.gz upstream-9ca16cf1b6246d99df192aa0131d39bb0aa31998.tar.bz2 upstream-9ca16cf1b6246d99df192aa0131d39bb0aa31998.zip |
add generic 2.6.26 patches/files
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@11323 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/generic-2.6/patches-2.6.26/150-netfilter_imq.patch')
-rw-r--r-- | target/linux/generic-2.6/patches-2.6.26/150-netfilter_imq.patch | 855 |
1 files changed, 855 insertions, 0 deletions
diff --git a/target/linux/generic-2.6/patches-2.6.26/150-netfilter_imq.patch b/target/linux/generic-2.6/patches-2.6.26/150-netfilter_imq.patch new file mode 100644 index 0000000000..f3c3735482 --- /dev/null +++ b/target/linux/generic-2.6/patches-2.6.26/150-netfilter_imq.patch @@ -0,0 +1,855 @@ +--- /dev/null ++++ b/drivers/net/imq.c +@@ -0,0 +1,409 @@ ++/* ++ * Pseudo-driver for the intermediate queue device. ++ * ++ * 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: Patrick McHardy, <kaber@trash.net> ++ * ++ * The first version was written by Martin Devera, <devik@cdi.cz> ++ * ++ * Credits: Jan Rafaj <imq2t@cedric.vabo.cz> ++ * - Update patch to 2.4.21 ++ * Sebastian Strollo <sstrollo@nortelnetworks.com> ++ * - Fix "Dead-loop on netdevice imq"-issue ++ * Marcel Sebek <sebek64@post.cz> ++ * - Update to 2.6.2-rc1 ++ * ++ * After some time of inactivity there is a group taking care ++ * of IMQ again: http://www.linuximq.net ++ * ++ * ++ * 2004/06/30 - New version of IMQ patch to kernels <=2.6.7 including ++ * the following changes: ++ * ++ * - Correction of ipv6 support "+"s issue (Hasso Tepper) ++ * - Correction of imq_init_devs() issue that resulted in ++ * kernel OOPS unloading IMQ as module (Norbert Buchmuller) ++ * - Addition of functionality to choose number of IMQ devices ++ * during kernel config (Andre Correa) ++ * - Addition of functionality to choose how IMQ hooks on ++ * PRE and POSTROUTING (after or before NAT) (Andre Correa) ++ * - Cosmetic corrections (Norbert Buchmuller) (Andre Correa) ++ * ++ * ++ * 2005/12/16 - IMQ versions between 2.6.7 and 2.6.13 were ++ * released with almost no problems. 2.6.14-x was released ++ * with some important changes: nfcache was removed; After ++ * some weeks of trouble we figured out that some IMQ fields ++ * in skb were missing in skbuff.c - skb_clone and copy_skb_header. ++ * These functions are correctly patched by this new patch version. ++ * ++ * Thanks for all who helped to figure out all the problems with ++ * 2.6.14.x: Patrick McHardy, Rune Kock, VeNoMouS, Max CtRiX, ++ * Kevin Shanahan, Richard Lucassen, Valery Dachev (hopefully ++ * I didn't forget anybody). I apologize again for my lack of time. ++ * ++ * More info at: http://www.linuximq.net/ (Andre Correa) ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/moduleparam.h> ++#include <linux/skbuff.h> ++#include <linux/netdevice.h> ++#include <linux/rtnetlink.h> ++#include <linux/if_arp.h> ++#include <linux/netfilter.h> ++#include <linux/netfilter_ipv4.h> ++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) ++ #include <linux/netfilter_ipv6.h> ++#endif ++#include <linux/imq.h> ++#include <net/pkt_sched.h> ++ ++extern int qdisc_restart1(struct net_device *dev); ++ ++static nf_hookfn imq_nf_hook; ++ ++static struct nf_hook_ops imq_ingress_ipv4 = { ++ .hook = imq_nf_hook, ++ .owner = THIS_MODULE, ++ .pf = PF_INET, ++ .hooknum = NF_INET_PRE_ROUTING, ++#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB) ++ .priority = NF_IP_PRI_MANGLE + 1 ++#else ++ .priority = NF_IP_PRI_NAT_DST + 1 ++#endif ++}; ++ ++static struct nf_hook_ops imq_egress_ipv4 = { ++ .hook = imq_nf_hook, ++ .owner = THIS_MODULE, ++ .pf = PF_INET, ++ .hooknum = NF_INET_POST_ROUTING, ++#if defined(CONFIG_IMQ_BEHAVIOR_AA) || defined(CONFIG_IMQ_BEHAVIOR_BA) ++ .priority = NF_IP_PRI_LAST ++#else ++ .priority = NF_IP_PRI_NAT_SRC - 1 ++#endif ++}; ++ ++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) ++static struct nf_hook_ops imq_ingress_ipv6 = { ++ .hook = imq_nf_hook, ++ .owner = THIS_MODULE, ++ .pf = PF_INET6, ++ .hooknum = NF_INET_PRE_ROUTING, ++#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB) ++ .priority = NF_IP6_PRI_MANGLE + 1 ++#else ++ .priority = NF_IP6_PRI_NAT_DST + 1 ++#endif ++}; ++ ++static struct nf_hook_ops imq_egress_ipv6 = { ++ .hook = imq_nf_hook, ++ .owner = THIS_MODULE, ++ .pf = PF_INET6, ++ .hooknum = NF_INET_POST_ROUTING, ++#if defined(CONFIG_IMQ_BEHAVIOR_AA) || defined(CONFIG_IMQ_BEHAVIOR_BA) ++ .priority = NF_IP6_PRI_LAST ++#else ++ .priority = NF_IP6_PRI_NAT_SRC - 1 ++#endif ++}; ++#endif ++ ++#if defined(CONFIG_IMQ_NUM_DEVS) ++static unsigned int numdevs = CONFIG_IMQ_NUM_DEVS; ++#else ++static unsigned int numdevs = 16; ++#endif ++ ++static struct net_device *imq_devs; ++ ++static struct net_device_stats *imq_get_stats(struct net_device *dev) ++{ ++ return (struct net_device_stats *)dev->priv; ++} ++ ++/* called for packets kfree'd in qdiscs at places other than enqueue */ ++static void imq_skb_destructor(struct sk_buff *skb) ++{ ++ struct nf_info *info = skb->nf_info; ++ ++ if (info) { ++ if (info->indev) ++ dev_put(info->indev); ++ if (info->outdev) ++ dev_put(info->outdev); ++ kfree(info); ++ } ++} ++ ++static int imq_dev_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct net_device_stats *stats = (struct net_device_stats*) dev->priv; ++ ++ stats->tx_bytes += skb->len; ++ stats->tx_packets++; ++ ++ skb->imq_flags = 0; ++ skb->destructor = NULL; ++ ++ dev->trans_start = jiffies; ++ nf_reinject(skb, skb->nf_info, NF_ACCEPT); ++ return 0; ++} ++ ++static int imq_nf_queue(struct sk_buff *skb, struct nf_info *info, unsigned queue_num, void *data) ++{ ++ struct net_device *dev; ++ struct net_device_stats *stats; ++ struct sk_buff *skb2 = NULL; ++ struct Qdisc *q; ++ unsigned int index = skb->imq_flags&IMQ_F_IFMASK; ++ int ret = -1; ++ ++ if (index > numdevs) ++ return -1; ++ ++ dev = imq_devs + index; ++ if (!(dev->flags & IFF_UP)) { ++ skb->imq_flags = 0; ++ nf_reinject(skb, info, NF_ACCEPT); ++ return 0; ++ } ++ dev->last_rx = jiffies; ++ ++ if (skb->destructor) { ++ skb2 = skb; ++ skb = skb_clone(skb, GFP_ATOMIC); ++ if (!skb) ++ return -1; ++ } ++ skb->nf_info = info; ++ ++ stats = (struct net_device_stats *)dev->priv; ++ stats->rx_bytes+= skb->len; ++ stats->rx_packets++; ++ ++ spin_lock_bh(&dev->queue_lock); ++ q = dev->qdisc; ++ if (q->enqueue) { ++ q->enqueue(skb_get(skb), q); ++ if (skb_shared(skb)) { ++ skb->destructor = imq_skb_destructor; ++ kfree_skb(skb); ++ ret = 0; ++ } ++ } ++ if (spin_is_locked(&dev->_xmit_lock)) ++ netif_schedule(dev); ++ else ++ while (!netif_queue_stopped(dev) && qdisc_restart1(dev) < 0) ++ /* NOTHING */; ++ ++ spin_unlock_bh(&dev->queue_lock); ++ ++ if (skb2) ++ kfree_skb(ret ? skb : skb2); ++ ++ return ret; ++} ++ ++static struct nf_queue_handler nfqh = { ++ .name = "imq", ++ .outfn = imq_nf_queue, ++}; ++ ++static unsigned int imq_nf_hook(unsigned int hook, struct sk_buff *pskb, ++ const struct net_device *indev, ++ const struct net_device *outdev, ++ int (*okfn)(struct sk_buff *)) ++{ ++ if (pskb->imq_flags & IMQ_F_ENQUEUE) ++ return NF_QUEUE; ++ ++ return NF_ACCEPT; ++} ++ ++ ++static int __init imq_init_hooks(void) ++{ ++ int err; ++ ++ err = nf_register_queue_handler(PF_INET, &nfqh); ++ if (err > 0) ++ goto err1; ++ if ((err = nf_register_hook(&imq_ingress_ipv4))) ++ goto err2; ++ if ((err = nf_register_hook(&imq_egress_ipv4))) ++ goto err3; ++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) ++ if ((err = nf_register_queue_handler(PF_INET6, &nfqh))) ++ goto err4; ++ if ((err = nf_register_hook(&imq_ingress_ipv6))) ++ goto err5; ++ if ((err = nf_register_hook(&imq_egress_ipv6))) ++ goto err6; ++#endif ++ ++ return 0; ++ ++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) ++err6: ++ nf_unregister_hook(&imq_ingress_ipv6); ++err5: ++ nf_unregister_queue_handler(PF_INET6, &nfqh); ++err4: ++ nf_unregister_hook(&imq_egress_ipv4); ++#endif ++err3: ++ nf_unregister_hook(&imq_ingress_ipv4); ++err2: ++ nf_unregister_queue_handler(PF_INET, &nfqh); ++err1: ++ return err; ++} ++ ++static void __exit imq_unhook(void) ++{ ++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) ++ nf_unregister_hook(&imq_ingress_ipv6); ++ nf_unregister_hook(&imq_egress_ipv6); ++ nf_unregister_queue_handler(PF_INET6, &nfqh); ++#endif ++ nf_unregister_hook(&imq_ingress_ipv4); ++ nf_unregister_hook(&imq_egress_ipv4); ++ nf_unregister_queue_handler(PF_INET, &nfqh); ++} ++ ++static int __init imq_dev_init(struct net_device *dev) ++{ ++ dev->hard_start_xmit = imq_dev_xmit; ++ dev->type = ARPHRD_VOID; ++ dev->mtu = 16000; ++ dev->tx_queue_len = 11000; ++ dev->flags = IFF_NOARP; ++ dev->priv = kzalloc(sizeof(struct net_device_stats), GFP_KERNEL); ++ if (dev->priv == NULL) ++ return -ENOMEM; ++ dev->get_stats = imq_get_stats; ++ ++ return 0; ++} ++ ++static void imq_dev_uninit(struct net_device *dev) ++{ ++ kfree(dev->priv); ++} ++ ++static int __init imq_init_devs(struct net *net) ++{ ++ struct net_device *dev; ++ int i,j; ++ j = numdevs; ++ ++ if (!numdevs || numdevs > IMQ_MAX_DEVS) { ++ printk(KERN_ERR "IMQ: numdevs has to be betweed 1 and %u\n", ++ IMQ_MAX_DEVS); ++ return -EINVAL; ++ } ++ ++ imq_devs = kzalloc(sizeof(struct net_device) * numdevs, GFP_KERNEL); ++ if (!imq_devs) ++ return -ENOMEM; ++ ++ /* we start counting at zero */ ++ numdevs--; ++ ++ for (i = 0, dev = imq_devs; i <= numdevs; i++, dev++) { ++ strcpy(dev->name, "imq%d"); ++ dev->init = imq_dev_init; ++ dev->uninit = imq_dev_uninit; ++ dev->nd_net = net; ++ ++ if (register_netdev(dev) < 0) ++ goto err_register; ++ } ++ printk(KERN_INFO "IMQ starting with %u devices...\n", j); ++ return 0; ++ ++err_register: ++ for (; i; i--) ++ unregister_netdev(--dev); ++ kfree(imq_devs); ++ return -EIO; ++} ++ ++static void imq_cleanup_devs(void) ++{ ++ int i; ++ struct net_device *dev = imq_devs; ++ ++ for (i = 0; i <= numdevs; i++) ++ unregister_netdev(dev++); ++ ++ kfree(imq_devs); ++} ++ ++static __net_init int imq_init_module(struct net *net) ++{ ++ int err; ++ ++ if ((err = imq_init_devs(net))) { ++ printk(KERN_ERR "IMQ: Error trying imq_init_devs(net)\n"); ++ return err; ++ } ++ if ((err = imq_init_hooks())) { ++ printk(KERN_ERR "IMQ: Error trying imq_init_hooks()\n"); ++ imq_cleanup_devs(); ++ return err; ++ } ++ ++ printk(KERN_INFO "IMQ driver loaded successfully.\n"); ++ ++#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB) ++ printk(KERN_INFO "\tHooking IMQ before NAT on PREROUTING.\n"); ++#else ++ printk(KERN_INFO "\tHooking IMQ after NAT on PREROUTING.\n"); ++#endif ++#if defined(CONFIG_IMQ_BEHAVIOR_AB) || defined(CONFIG_IMQ_BEHAVIOR_BB) ++ printk(KERN_INFO "\tHooking IMQ before NAT on POSTROUTING.\n"); ++#else ++ printk(KERN_INFO "\tHooking IMQ after NAT on POSTROUTING.\n"); ++#endif ++ ++ return 0; ++} ++ ++static __net_exit void imq_exit_module(struct net *net) ++{ ++ imq_unhook(); ++ imq_cleanup_devs(); ++ printk(KERN_INFO "IMQ driver unloaded successfully.\n"); ++} ++ ++static struct pernet_operations __net_initdata imq_net_ops = { ++ .init = imq_init_module, ++ .exit = imq_exit_module, ++}; ++ ++static int __init imq_init(void) ++{ ++ return register_pernet_device(&imq_net_ops); ++} ++ ++module_init(imq_init); ++//module_exit(imq_cleanup_module); ++ ++module_param(numdevs, int, 0); ++MODULE_PARM_DESC(numdevs, "number of IMQ devices (how many imq* devices will be created)"); ++MODULE_AUTHOR("http://www.linuximq.net"); ++MODULE_DESCRIPTION("Pseudo-driver for the intermediate queue device. See http://www.linuximq.net/ for more information."); ++MODULE_LICENSE("GPL"); +--- a/drivers/net/Kconfig ++++ b/drivers/net/Kconfig +@@ -117,6 +117,129 @@ + To compile this driver as a module, choose M here: the module + will be called eql. If unsure, say N. + ++config IMQ ++ tristate "IMQ (intermediate queueing device) support" ++ depends on NETDEVICES && NETFILTER ++ ---help--- ++ The IMQ device(s) is used as placeholder for QoS queueing ++ disciplines. Every packet entering/leaving the IP stack can be ++ directed through the IMQ device where it's enqueued/dequeued to the ++ attached qdisc. This allows you to treat network devices as classes ++ and distribute bandwidth among them. Iptables is used to specify ++ through which IMQ device, if any, packets travel. ++ ++ More information at: http://www.linuximq.net/ ++ ++ To compile this driver as a module, choose M here: the module ++ will be called imq. If unsure, say N. ++ ++choice ++ prompt "IMQ behavior (PRE/POSTROUTING)" ++ depends on IMQ ++ default IMQ_BEHAVIOR_BB ++ help ++ ++ This settings defines how IMQ behaves in respect to its ++ hooking in PREROUTING and POSTROUTING. ++ ++ IMQ can work in any of the following ways: ++ ++ PREROUTING | POSTROUTING ++ -----------------|------------------- ++ #1 After NAT | After NAT ++ #2 After NAT | Before NAT ++ #3 Before NAT | After NAT ++ #4 Before NAT | Before NAT ++ ++ The default behavior is to hook before NAT on PREROUTING ++ and after NAT on POSTROUTING (#3). ++ ++ This settings are specially usefull when trying to use IMQ ++ to shape NATed clients. ++ ++ More information can be found at: www.linuximq.net ++ ++ If not sure leave the default settings alone. ++ ++config IMQ_BEHAVIOR_AA ++ bool "IMQ AA" ++ help ++ This settings defines how IMQ behaves in respect to its ++ hooking in PREROUTING and POSTROUTING. ++ ++ Choosing this option will make IMQ hook like this: ++ ++ PREROUTING: After NAT ++ POSTROUTING: After NAT ++ ++ More information can be found at: www.linuximq.net ++ ++ If not sure leave the default settings alone. ++ ++config IMQ_BEHAVIOR_AB ++ bool "IMQ AB" ++ help ++ This settings defines how IMQ behaves in respect to its ++ hooking in PREROUTING and POSTROUTING. ++ ++ Choosing this option will make IMQ hook like this: ++ ++ PREROUTING: After NAT ++ POSTROUTING: Before NAT ++ ++ More information can be found at: www.linuximq.net ++ ++ If not sure leave the default settings alone. ++ ++config IMQ_BEHAVIOR_BA ++ bool "IMQ BA" ++ help ++ This settings defines how IMQ behaves in respect to its ++ hooking in PREROUTING and POSTROUTING. ++ ++ Choosing this option will make IMQ hook like this: ++ ++ PREROUTING: Before NAT ++ POSTROUTING: After NAT ++ ++ More information can be found at: www.linuximq.net ++ ++ If not sure leave the default settings alone. ++ ++config IMQ_BEHAVIOR_BB ++ bool "IMQ BB" ++ help ++ This settings defines how IMQ behaves in respect to its ++ hooking in PREROUTING and POSTROUTING. ++ ++ Choosing this option will make IMQ hook like this: ++ ++ PREROUTING: Before NAT ++ POSTROUTING: Before NAT ++ ++ More information can be found at: www.linuximq.net ++ ++ If not sure leave the default settings alone. ++ ++endchoice ++ ++config IMQ_NUM_DEVS ++ ++ int "Number of IMQ devices" ++ range 2 16 ++ depends on IMQ ++ default "16" ++ help ++ ++ This settings defines how many IMQ devices will be ++ created. ++ ++ The default value is 16. ++ ++ More information can be found at: www.linuximq.net ++ ++ If not sure leave the default settings alone. ++ + config TUN + tristate "Universal TUN/TAP device driver support" + select CRC32 +--- a/drivers/net/Makefile ++++ b/drivers/net/Makefile +@@ -143,6 +143,7 @@ + obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o + + obj-$(CONFIG_DUMMY) += dummy.o ++obj-$(CONFIG_IMQ) += imq.o + obj-$(CONFIG_IFB) += ifb.o + obj-$(CONFIG_MACVLAN) += macvlan.o + obj-$(CONFIG_DE600) += de600.o +--- /dev/null ++++ b/include/linux/imq.h +@@ -0,0 +1,9 @@ ++#ifndef _IMQ_H ++#define _IMQ_H ++ ++#define IMQ_MAX_DEVS 16 ++ ++#define IMQ_F_IFMASK 0x7f ++#define IMQ_F_ENQUEUE 0x80 ++ ++#endif /* _IMQ_H */ +--- /dev/null ++++ b/include/linux/netfilter_ipv4/ipt_IMQ.h +@@ -0,0 +1,8 @@ ++#ifndef _IPT_IMQ_H ++#define _IPT_IMQ_H ++ ++struct ipt_imq_info { ++ unsigned int todev; /* target imq device */ ++}; ++ ++#endif /* _IPT_IMQ_H */ +--- /dev/null ++++ b/include/linux/netfilter_ipv6/ip6t_IMQ.h +@@ -0,0 +1,8 @@ ++#ifndef _IP6T_IMQ_H ++#define _IP6T_IMQ_H ++ ++struct ip6t_imq_info { ++ unsigned int todev; /* target imq device */ ++}; ++ ++#endif /* _IP6T_IMQ_H */ +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -296,6 +296,10 @@ + struct nf_conntrack *nfct; + struct sk_buff *nfct_reasm; + #endif ++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) ++ unsigned char imq_flags; ++ struct nf_info *nf_info; ++#endif + #ifdef CONFIG_BRIDGE_NETFILTER + struct nf_bridge_info *nf_bridge; + #endif +@@ -1736,6 +1740,10 @@ + dst->nfct_reasm = src->nfct_reasm; + nf_conntrack_get_reasm(src->nfct_reasm); + #endif ++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) ++ dst->imq_flags = src->imq_flags; ++ dst->nf_info = src->nf_info; ++#endif + #ifdef CONFIG_BRIDGE_NETFILTER + dst->nf_bridge = src->nf_bridge; + nf_bridge_get(src->nf_bridge); +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -95,6 +95,9 @@ + #include <net/net_namespace.h> + #include <net/sock.h> + #include <linux/rtnetlink.h> ++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) ++#include <linux/imq.h> ++#endif + #include <linux/proc_fs.h> + #include <linux/seq_file.h> + #include <linux/stat.h> +@@ -1537,7 +1540,11 @@ + int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) + { + if (likely(!skb->next)) { +- if (!list_empty(&ptype_all)) ++ if (!list_empty(&ptype_all) ++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) ++ && !(skb->imq_flags & IMQ_F_ENQUEUE) ++#endif ++ ) + dev_queue_xmit_nit(skb, dev); + + if (netif_needs_gso(dev, skb)) { +--- /dev/null ++++ b/net/ipv4/netfilter/ipt_IMQ.c +@@ -0,0 +1,69 @@ ++/* ++ * This target marks packets to be enqueued to an imq device ++ */ ++#include <linux/module.h> ++#include <linux/skbuff.h> ++#include <linux/netfilter_ipv4/ip_tables.h> ++#include <linux/netfilter_ipv4/ipt_IMQ.h> ++#include <linux/imq.h> ++ ++static unsigned int imq_target(struct sk_buff *pskb, ++ const struct net_device *in, ++ const struct net_device *out, ++ unsigned int hooknum, ++ const struct xt_target *target, ++ const void *targinfo) ++{ ++ struct ipt_imq_info *mr = (struct ipt_imq_info*)targinfo; ++ ++ pskb->imq_flags = mr->todev | IMQ_F_ENQUEUE; ++ ++ return XT_CONTINUE; ++} ++ ++static bool imq_checkentry(const char *tablename, ++ const void *e, ++ const struct xt_target *target, ++ void *targinfo, ++ unsigned int hook_mask) ++{ ++ struct ipt_imq_info *mr; ++ ++ mr = (struct ipt_imq_info*)targinfo; ++ ++ if (mr->todev > IMQ_MAX_DEVS) { ++ printk(KERN_WARNING ++ "IMQ: invalid device specified, highest is %u\n", ++ IMQ_MAX_DEVS); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct xt_target ipt_imq_reg = { ++ .name = "IMQ", ++ .family = AF_INET, ++ .target = imq_target, ++ .targetsize = sizeof(struct ipt_imq_info), ++ .checkentry = imq_checkentry, ++ .me = THIS_MODULE, ++ .table = "mangle" ++}; ++ ++static int __init init(void) ++{ ++ return xt_register_target(&ipt_imq_reg); ++} ++ ++static void __exit fini(void) ++{ ++ xt_unregister_target(&ipt_imq_reg); ++} ++ ++module_init(init); ++module_exit(fini); ++ ++MODULE_AUTHOR("http://www.linuximq.net"); ++MODULE_DESCRIPTION("Pseudo-driver for the intermediate queue device. See http://www.linuximq.net/ for more information."); ++MODULE_LICENSE("GPL"); +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -315,6 +315,17 @@ + + To compile it as a module, choose M here. If unsure, say N. + ++config IP_NF_TARGET_IMQ ++ tristate "IMQ target support" ++ depends on IP_NF_MANGLE && IMQ ++ help ++ This option adds a `IMQ' target which is used to specify if and ++ to which IMQ device packets should get enqueued/dequeued. ++ ++ For more information visit: http://www.linuximq.net/ ++ ++ To compile it as a module, choose M here. If unsure, say N. ++ + config IP_NF_TARGET_ECN + tristate "ECN target support" + depends on IP_NF_MANGLE +--- a/net/ipv4/netfilter/Makefile ++++ b/net/ipv4/netfilter/Makefile +@@ -55,6 +55,7 @@ + obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o + obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o + obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o ++obj-$(CONFIG_IP_NF_TARGET_IMQ) += ipt_IMQ.o + obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o + obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o + obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o +--- /dev/null ++++ b/net/ipv6/netfilter/ip6t_IMQ.c +@@ -0,0 +1,69 @@ ++/* ++ * This target marks packets to be enqueued to an imq device ++ */ ++#include <linux/module.h> ++#include <linux/skbuff.h> ++#include <linux/netfilter_ipv6/ip6_tables.h> ++#include <linux/netfilter_ipv6/ip6t_IMQ.h> ++#include <linux/imq.h> ++ ++static unsigned int imq_target(struct sk_buff *pskb, ++ const struct net_device *in, ++ const struct net_device *out, ++ unsigned int hooknum, ++ const struct xt_target *target, ++ const void *targinfo) ++{ ++ struct ip6t_imq_info *mr = (struct ip6t_imq_info*)targinfo; ++ ++ pskb->imq_flags = mr->todev | IMQ_F_ENQUEUE; ++ ++ return XT_CONTINUE; ++} ++ ++static bool imq_checkentry(const char *tablename, ++ const void *entry, ++ const struct xt_target *target, ++ void *targinfo, ++ unsigned int hook_mask) ++{ ++ struct ip6t_imq_info *mr; ++ ++ mr = (struct ip6t_imq_info*)targinfo; ++ ++ if (mr->todev > IMQ_MAX_DEVS) { ++ printk(KERN_WARNING ++ "IMQ: invalid device specified, highest is %u\n", ++ IMQ_MAX_DEVS); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct xt_target ip6t_imq_reg = { ++ .name = "IMQ", ++ .family = AF_INET6, ++ .target = imq_target, ++ .targetsize = sizeof(struct ip6t_imq_info), ++ .table = "mangle", ++ .checkentry = imq_checkentry, ++ .me = THIS_MODULE ++}; ++ ++static int __init init(void) ++{ ++ return xt_register_target(&ip6t_imq_reg); ++} ++ ++static void __exit fini(void) ++{ ++ xt_unregister_target(&ip6t_imq_reg); ++} ++ ++module_init(init); ++module_exit(fini); ++ ++MODULE_AUTHOR("http://www.linuximq.net"); ++MODULE_DESCRIPTION("Pseudo-driver for the intermediate queue device. See http://www.linuximq.net/ for more information."); ++MODULE_LICENSE("GPL"); +--- a/net/ipv6/netfilter/Kconfig ++++ b/net/ipv6/netfilter/Kconfig +@@ -179,6 +179,15 @@ + + To compile it as a module, choose M here. If unsure, say N. + ++config IP6_NF_TARGET_IMQ ++ tristate "IMQ target support" ++ depends on IP6_NF_MANGLE ++ help ++ This option adds a `IMQ' target which is used to specify if and ++ to which imq device packets should get enqueued/dequeued. ++ ++ To compile it as a module, choose M here. If unsure, say N. ++ + config IP6_NF_TARGET_HL + tristate 'HL (hoplimit) target support' + depends on IP6_NF_MANGLE +--- a/net/ipv6/netfilter/Makefile ++++ b/net/ipv6/netfilter/Makefile +@@ -6,6 +6,7 @@ + obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o + obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o + obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o ++obj-$(CONFIG_IP6_NF_TARGET_IMQ) += ip6t_IMQ.o + obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o + obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o + +--- a/net/sched/sch_generic.c ++++ b/net/sched/sch_generic.c +@@ -182,6 +182,13 @@ + return ret; + } + ++int qdisc_restart1(struct net_device *dev) ++{ ++ return qdisc_restart(dev); ++} ++ ++EXPORT_SYMBOL(qdisc_restart1); ++ + void __qdisc_run(struct net_device *dev) + { + unsigned long start_time = jiffies; |