From: <kr...@us...> - 2007-10-24 01:57:32
|
Revision: 1311 http://astlinux.svn.sourceforge.net/astlinux/?rev=1311&view=rev Author: krisk84 Date: 2007-10-23 18:57:34 -0700 (Tue, 23 Oct 2007) Log Message: ----------- IMQ support for geni586 Modified Paths: -------------- trunk/target/device/geni586/linux.config Added Paths: ----------- trunk/package/iptables/iptables-imq.patch trunk/target/device/kernel-patches/linux-2.6.20.18-imq.patch Added: trunk/package/iptables/iptables-imq.patch =================================================================== --- trunk/package/iptables/iptables-imq.patch (rev 0) +++ trunk/package/iptables/iptables-imq.patch 2007-10-24 01:57:34 UTC (rev 1311) @@ -0,0 +1,221 @@ +--- iptables-1.3.6.orig/extensions.orig/.IMQ-test6 Thu Jan 1 01:00:00 1970 ++++ iptables-1.3.6/extensions/.IMQ-test6 Mon Jun 16 10:12:47 2003 +@@ -0,0 +1,3 @@ ++#!/bin/sh ++# True if IMQ target patch is applied. ++[ -f $KERNEL_DIR/net/ipv6/netfilter/ip6t_IMQ.c ] && echo IMQ +--- iptables-1.3.6.orig/extensions.orig/libip6t_IMQ.c Thu Jan 1 01:00:00 1970 ++++ iptables-1.3.6/extensions/libip6t_IMQ.c Mon Jun 16 10:12:47 2003 +@@ -0,0 +1,101 @@ ++/* Shared library add-on to iptables to add IMQ target support. */ ++#include <stdio.h> ++#include <string.h> ++#include <stdlib.h> ++#include <getopt.h> ++ ++#include <ip6tables.h> ++#include <linux/netfilter_ipv6/ip6_tables.h> ++#include <linux/netfilter_ipv6/ip6t_IMQ.h> ++ ++/* Function which prints out usage message. */ ++static void ++help(void) ++{ ++ printf( ++"IMQ target v%s options:\n" ++" --todev <N> enqueue to imq<N>, defaults to 0\n", ++IPTABLES_VERSION); ++} ++ ++static struct option opts[] = { ++ { "todev", 1, 0, '1' }, ++ { 0 } ++}; ++ ++/* Initialize the target. */ ++static void ++init(struct ip6t_entry_target *t, unsigned int *nfcache) ++{ ++ struct ip6t_imq_info *mr = (struct ip6t_imq_info*)t->data; ++ ++ mr->todev = 0; ++ *nfcache |= NFC_UNKNOWN; ++} ++ ++/* Function which parses command options; returns true if it ++ ate an option */ ++static int ++parse(int c, char **argv, int invert, unsigned int *flags, ++ const struct ip6t_entry *entry, ++ struct ip6t_entry_target **target) ++{ ++ struct ip6t_imq_info *mr = (struct ip6t_imq_info*)(*target)->data; ++ ++ switch(c) { ++ case '1': ++ if (check_inverse(optarg, &invert, NULL, 0)) ++ exit_error(PARAMETER_PROBLEM, ++ "Unexpected `!' after --todev"); ++ mr->todev=atoi(optarg); ++ break; ++ default: ++ return 0; ++ } ++ return 1; ++} ++ ++static void ++final_check(unsigned int flags) ++{ ++} ++ ++/* Prints out the targinfo. */ ++static void ++print(const struct ip6t_ip6 *ip, ++ const struct ip6t_entry_target *target, ++ int numeric) ++{ ++ struct ip6t_imq_info *mr = (struct ip6t_imq_info*)target->data; ++ ++ printf("IMQ: todev %u ", mr->todev); ++} ++ ++/* Saves the union ipt_targinfo in parsable form to stdout. */ ++static void ++save(const struct ip6t_ip6 *ip, const struct ip6t_entry_target *target) ++{ ++ struct ip6t_imq_info *mr = (struct ip6t_imq_info*)target->data; ++ ++ printf("--todev %u", mr->todev); ++} ++ ++static struct ip6tables_target imq = { ++ .next = NULL, ++ .name = "IMQ", ++ .version = IPTABLES_VERSION, ++ .size = IP6T_ALIGN(sizeof(struct ip6t_imq_info)), ++ .userspacesize = IP6T_ALIGN(sizeof(struct ip6t_imq_info)), ++ .help = &help, ++ .init = &init, ++ .parse = &parse, ++ .final_check = &final_check, ++ .print = &print, ++ .save = &save, ++ .extra_opts = opts ++}; ++ ++static __attribute__((constructor)) void _init(void) ++{ ++ register_target6(&imq); ++} +--- iptables-1.3.6.orig/extensions.orig/.IMQ-test Thu Jan 1 01:00:00 1970 ++++ iptables-1.3.6/extensions/.IMQ-test Mon Jun 16 10:12:47 2003 +@@ -0,0 +1,3 @@ ++#!/bin/sh ++# True if IMQ target patch is applied. ++[ -f $KERNEL_DIR/net/ipv4/netfilter/ipt_IMQ.c ] && echo IMQ +--- iptables-1.3.6.orig/extensions.orig/libipt_IMQ.c Thu Jan 1 01:00:00 1970 ++++ iptables-1.3.6/extensions/libipt_IMQ.c Mon Jun 16 10:12:47 2003 +@@ -0,0 +1,101 @@ ++/* Shared library add-on to iptables to add IMQ target support. */ ++#include <stdio.h> ++#include <string.h> ++#include <stdlib.h> ++#include <getopt.h> ++ ++#include <iptables.h> ++#include <linux/netfilter_ipv4/ip_tables.h> ++#include <linux/netfilter_ipv4/ipt_IMQ.h> ++ ++/* Function which prints out usage message. */ ++static void ++help(void) ++{ ++ printf( ++"IMQ target v%s options:\n" ++" --todev <N> enqueue to imq<N>, defaults to 0\n", ++IPTABLES_VERSION); ++} ++ ++static struct option opts[] = { ++ { "todev", 1, 0, '1' }, ++ { 0 } ++}; ++ ++/* Initialize the target. */ ++static void ++init(struct ipt_entry_target *t, unsigned int *nfcache) ++{ ++ struct ipt_imq_info *mr = (struct ipt_imq_info*)t->data; ++ ++ mr->todev = 0; ++ *nfcache |= NFC_UNKNOWN; ++} ++ ++/* Function which parses command options; returns true if it ++ ate an option */ ++static int ++parse(int c, char **argv, int invert, unsigned int *flags, ++ const struct ipt_entry *entry, ++ struct ipt_entry_target **target) ++{ ++ struct ipt_imq_info *mr = (struct ipt_imq_info*)(*target)->data; ++ ++ switch(c) { ++ case '1': ++ if (check_inverse(optarg, &invert, NULL, 0)) ++ exit_error(PARAMETER_PROBLEM, ++ "Unexpected `!' after --todev"); ++ mr->todev=atoi(optarg); ++ break; ++ default: ++ return 0; ++ } ++ return 1; ++} ++ ++static void ++final_check(unsigned int flags) ++{ ++} ++ ++/* Prints out the targinfo. */ ++static void ++print(const struct ipt_ip *ip, ++ const struct ipt_entry_target *target, ++ int numeric) ++{ ++ struct ipt_imq_info *mr = (struct ipt_imq_info*)target->data; ++ ++ printf("IMQ: todev %u ", mr->todev); ++} ++ ++/* Saves the union ipt_targinfo in parsable form to stdout. */ ++static void ++save(const struct ipt_ip *ip, const struct ipt_entry_target *target) ++{ ++ struct ipt_imq_info *mr = (struct ipt_imq_info*)target->data; ++ ++ printf("--todev %u", mr->todev); ++} ++ ++static struct iptables_target imq = { ++ .next = NULL, ++ .name = "IMQ", ++ .version = IPTABLES_VERSION, ++ .size = IPT_ALIGN(sizeof(struct ipt_imq_info)), ++ .userspacesize = IPT_ALIGN(sizeof(struct ipt_imq_info)), ++ .help = &help, ++ .init = &init, ++ .parse = &parse, ++ .final_check = &final_check, ++ .print = &print, ++ .save = &save, ++ .extra_opts = opts ++}; ++ ++static __attribute__((constructor)) void _init(void) ++{ ++ register_target(&imq); ++} + Modified: trunk/target/device/geni586/linux.config =================================================================== --- trunk/target/device/geni586/linux.config 2007-10-21 19:37:12 UTC (rev 1310) +++ trunk/target/device/geni586/linux.config 2007-10-24 01:57:34 UTC (rev 1311) @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.20.16 -# Thu Aug 23 11:08:42 2007 +# Linux kernel version: 2.6.20.18 +# Tue Oct 23 16:49:22 2007 # CONFIG_X86_32=y CONFIG_GENERIC_TIME=y @@ -460,6 +460,7 @@ CONFIG_NF_NAT_H323=m CONFIG_NF_NAT_SIP=m CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_IMQ=m CONFIG_IP_NF_TARGET_TOS=m CONFIG_IP_NF_TARGET_ECN=m CONFIG_IP_NF_TARGET_TTL=m @@ -932,6 +933,12 @@ # CONFIG_DUMMY is not set CONFIG_BONDING=m # CONFIG_EQUALIZER is not set +CONFIG_IMQ=m +# CONFIG_IMQ_BEHAVIOR_AA is not set +# CONFIG_IMQ_BEHAVIOR_AB is not set +CONFIG_IMQ_BEHAVIOR_BA=y +# CONFIG_IMQ_BEHAVIOR_BB is not set +CONFIG_IMQ_NUM_DEVS=2 CONFIG_TUN=m # CONFIG_NET_SB1000 is not set Added: trunk/target/device/kernel-patches/linux-2.6.20.18-imq.patch =================================================================== --- trunk/target/device/kernel-patches/linux-2.6.20.18-imq.patch (rev 0) +++ trunk/target/device/kernel-patches/linux-2.6.20.18-imq.patch 2007-10-24 01:57:34 UTC (rev 1311) @@ -0,0 +1,4483 @@ +diff -urN linux-2.6.20.18.orig/drivers/net/imq.c linux-2.6.20.18/drivers/net/imq.c +--- linux-2.6.20.18.orig/drivers/net/imq.c 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.20.18/drivers/net/imq.c 2007-10-23 16:36:54.000000000 -0400 +@@ -0,0 +1,402 @@ ++/* ++ * 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, <ka...@tr...> ++ * ++ * The first version was written by Martin Devera, <de...@cd...> ++ * ++ * Credits: Jan Rafaj <im...@ce...> ++ * - Update patch to 2.4.21 ++ * Sebastian Strollo <sst...@no...> ++ * - Fix "Dead-loop on netdevice imq"-issue ++ * Marcel Sebek <se...@po...> ++ * - 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_IP_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_IP_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_IP6_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_IP6_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 = 2; ++#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); ++err4: ++ nf_unregister_hook(&imq_egress_ipv6); ++#endif ++err3: ++ nf_unregister_hook(&imq_ingress_ipv4); ++err2: ++ nf_unregister_queue_handler(PF_INET); ++err1: ++ return err; ++} ++ ++static void __exit imq_unhook(void) ++{ ++ nf_unregister_hook(&imq_ingress_ipv4); ++ nf_unregister_hook(&imq_egress_ipv4); ++ nf_unregister_queue_handler(PF_INET); ++#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); ++#endif ++} ++ ++static int __init imq_dev_init(struct net_device *dev) ++{ ++ dev->hard_start_xmit = imq_dev_xmit; ++ dev->type = ARPHRD_VOID; ++ dev->mtu = 1500; ++ dev->tx_queue_len = 30; ++ dev->flags = IFF_NOARP; ++ dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); ++ if (dev->priv == NULL) ++ return -ENOMEM; ++ memset(dev->priv, 0, sizeof(struct net_device_stats)); ++ 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(void) ++{ ++ 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 = kmalloc(sizeof(struct net_device) * numdevs, GFP_KERNEL); ++ if (!imq_devs) ++ return -ENOMEM; ++ memset(imq_devs, 0, sizeof(struct net_device) * numdevs); ++ ++ /* we start counting at zero */ ++ numdevs--; ++ ++ for (i = 0, dev = imq_devs; i <= numdevs; i++, dev++) { ++ SET_MODULE_OWNER(dev); ++ strcpy(dev->name, "imq%d"); ++ dev->init = imq_dev_init; ++ dev->uninit = imq_dev_uninit; ++ ++ 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 int __init imq_init_module(void) ++{ ++ int err; ++ ++ if ((err = imq_init_devs())) { ++ printk(KERN_ERR "IMQ: Error trying imq_init_devs()\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 void __exit imq_cleanup_module(void) ++{ ++ imq_unhook(); ++ imq_cleanup_devs(); ++ printk(KERN_INFO "IMQ driver unloaded successfully.\n"); ++} ++ ++ ++module_init(imq_init_module); ++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"); +diff -urN linux-2.6.20.18.orig/drivers/net/Kconfig linux-2.6.20.18/drivers/net/Kconfig +--- linux-2.6.20.18.orig/drivers/net/Kconfig 2007-08-28 06:15:07.000000000 -0400 ++++ linux-2.6.20.18/drivers/net/Kconfig 2007-10-23 16:36:54.000000000 -0400 +@@ -96,6 +96,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_BA ++ 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 8 ++ depends on IMQ ++ default "2" ++ help ++ ++ This settings defines how many IMQ devices will be ++ created. ++ ++ The default value is 2. ++ ++ 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 +diff -urN linux-2.6.20.18.orig/drivers/net/Makefile linux-2.6.20.18/drivers/net/Makefile +--- linux-2.6.20.18.orig/drivers/net/Makefile 2007-08-28 06:15:07.000000000 -0400 ++++ linux-2.6.20.18/drivers/net/Makefile 2007-10-23 16:36:54.000000000 -0400 +@@ -124,6 +124,7 @@ + obj-$(CONFIG_SLHC) += slhc.o + + obj-$(CONFIG_DUMMY) += dummy.o ++obj-$(CONFIG_IMQ) += imq.o + obj-$(CONFIG_IFB) += ifb.o + obj-$(CONFIG_DE600) += de600.o + obj-$(CONFIG_DE620) += de620.o +diff -urN linux-2.6.20.18.orig/include/linux/imq.h linux-2.6.20.18/include/linux/imq.h +--- linux-2.6.20.18.orig/include/linux/imq.h 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.20.18/include/linux/imq.h 2007-10-23 16:36:54.000000000 -0400 +@@ -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 */ +diff -urN linux-2.6.20.18.orig/include/linux/netfilter_ipv4/ipt_IMQ.h linux-2.6.20.18/include/linux/netfilter_ipv4/ipt_IMQ.h +--- linux-2.6.20.18.orig/include/linux/netfilter_ipv4/ipt_IMQ.h 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.20.18/include/linux/netfilter_ipv4/ipt_IMQ.h 2007-10-23 16:36:54.000000000 -0400 +@@ -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 */ +diff -urN linux-2.6.20.18.orig/include/linux/netfilter_ipv6/ip6t_IMQ.h linux-2.6.20.18/include/linux/netfilter_ipv6/ip6t_IMQ.h +--- linux-2.6.20.18.orig/include/linux/netfilter_ipv6/ip6t_IMQ.h 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.20.18/include/linux/netfilter_ipv6/ip6t_IMQ.h 2007-10-23 16:36:54.000000000 -0400 +@@ -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 */ +diff -urN linux-2.6.20.18.orig/include/linux/skbuff.h linux-2.6.20.18/include/linux/skbuff.h +--- linux-2.6.20.18.orig/include/linux/skbuff.h 2007-08-28 06:15:07.000000000 -0400 ++++ linux-2.6.20.18/include/linux/skbuff.h 2007-10-23 16:36:54.000000000 -0400 +@@ -294,6 +294,10 @@ + #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) + 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 +diff -urN linux-2.6.20.18.orig/include/linux/skbuff.h.orig linux-2.6.20.18/include/linux/skbuff.h.orig +--- linux-2.6.20.18.orig/include/linux/skbuff.h.orig 1969-12-31 19:00:00.000000000 -0500 ++++ linux-2.6.20.18/include/linux/skbuff.h.orig 2007-08-28 06:15:07.000000000 -0400 +@@ -0,0 +1,1486 @@ ++/* ++ * Definitions for the 'struct sk_buff' memory handlers. ++ * ++ * Authors: ++ * Alan Cox, <gw...@gw...> ++ * Florian La Roche, <rz...@rz...> ++ * ++ * 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. ++ */ ++ ++#ifndef _LINUX_SKBUFF_H ++#define _LINUX_SKBUFF_H ++ ++#include <linux/kernel.h> ++#include <linux/compiler.h> ++#include <linux/time.h> ++#include <linux/cache.h> ++ ++#include <asm/atomic.h> ++#include <asm/types.h> ++#include <linux/spinlock.h> ++#include <linux/net.h> ++#include <linux/textsearch.h> ++#include <net/checksum.h> ++#include <linux/rcupdate.h> ++#include <linux/dmaengine.h> ++ ++#define HAVE_ALLOC_SKB /* For the drivers to know */ ++#define HAVE_ALIGNABLE_SKB /* Ditto 8) */ ++ ++#define CHECKSUM_NONE 0 ++#define CHECKSUM_PARTIAL 1 ++#define CHECKSUM_UNNECESSARY 2 ++#define CHECKSUM_COMPLETE 3 ++ ++#define SKB_DATA_ALIGN(X) (((X) + (SMP_CACHE_BYTES - 1)) & \ ++ ~(SMP_CACHE_BYTES - 1)) ++#define SKB_MAX_ORDER(X, ORDER) (((PAGE_SIZE << (ORDER)) - (X) - \ ++ sizeof(struct skb_shared_info)) & \ ++ ~(SMP_CACHE_BYTES - 1)) ++#define SKB_MAX_HEAD(X) (SKB_MAX_ORDER((X), 0)) ++#define SKB_MAX_ALLOC (SKB_MAX_ORDER(0, 2)) ++ ++/* A. Checksumming of received packets by device. ++ * ++ * NONE: device failed to checksum this packet. ++ * skb->csum is undefined. ++ * ++ * UNNECESSARY: device parsed packet and wouldbe verified checksum. ++ * skb->csum is undefined. ++ * It is bad option, but, unfortunately, many of vendors do this. ++ * Apparently with secret goal to sell you new device, when you ++ * will add new protocol to your host. F.e. IPv6. 8) ++ * ++ * COMPLETE: the most generic way. Device supplied checksum of _all_ ++ * the packet as seen by netif_rx in skb->csum. ++ * NOTE: Even if device supports only some protocols, but ++ * is able to produce some skb->csum, it MUST use COMPLETE, ++ * not UNNECESSARY. ++ * ++ * B. Checksumming on output. ++ * ++ * NONE: skb is checksummed by protocol or csum is not required. ++ * ++ * PARTIAL: device is required to csum packet as seen by hard_start_xmit ++ * from skb->h.raw to the end and to record the checksum ++ * at skb->h.raw+skb->csum. ++ * ++ * Device must show its capabilities in dev->features, set ++ * at device setup time. ++ * NETIF_F_HW_CSUM - it is clever device, it is able to checksum ++ * everything. ++ * NETIF_F_NO_CSUM - loopback or reliable single hop media. ++ * NETIF_F_IP_CSUM - device is dumb. It is able to csum only ++ * TCP/UDP over IPv4. Sigh. Vendors like this ++ * way by an unknown reason. Though, see comment above ++ * about CHECKSUM_UNNECESSARY. 8) ++ * ++ * Any questions? No questions, good. --ANK ++ */ ++ ++struct net_device; ++ ++#ifdef CONFIG_NETFILTER ++struct nf_conntrack { ++ atomic_t use; ++ void (*destroy)(struct nf_conntrack *); ++}; ++ ++#ifdef CONFIG_BRIDGE_NETFILTER ++struct nf_bridge_info { ++ atomic_t use; ++ struct net_device *physindev; ++ struct net_device *physoutdev; ++#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) ++ struct net_device *netoutdev; ++#endif ++ unsigned int mask; ++ unsigned long data[32 / sizeof(unsigned long)]; ++}; ++#endif ++ ++#endif ++ ++struct sk_buff_head { ++ /* These two members must be first. */ ++ struct sk_buff *next; ++ struct sk_buff *prev; ++ ++ __u32 qlen; ++ spinlock_t lock; ++}; ++ ++struct sk_buff; ++ ++/* To allow 64K frame to be packed as single skb without frag_list */ ++#define MAX_SKB_FRAGS (65536/PAGE_SIZE + 2) ++ ++typedef struct skb_frag_struct skb_frag_t; ++ ++struct skb_frag_struct { ++ struct page *page; ++ __u16 page_offset; ++ __u16 size; ++}; ++ ++/* This data is invariant across clones and lives at ++ * the end of the header data, ie. at skb->end. ++ */ ++struct skb_shared_info { ++ atomic_t dataref; ++ unsigned short nr_frags; ++ unsigned short gso_size; ++ /* Warning: this field is not always filled in (UFO)! */ ++ unsigned short gso_segs; ++ unsigned short gso_type; ++ __be32 ip6_frag_id; ++ struct sk_buff *frag_list; ++ skb_frag_t frags[MAX_SKB_FRAGS]; ++}; ++ ++/* We divide dataref into two halves. The higher 16 bits hold references ++ * to the payload part of skb->data. The lower 16 bits hold references to ++ * the entire skb->data. It is up to the users of the skb to agree on ++ * where the payload starts. ++ * ++ * All users must obey the rule that the skb->data reference count must be ++ * greater than or equal to the payload reference count. ++ * ++ * Holding a reference to the payload part means that the user does not ++ * care about modifications to the header part of skb->data. ++ */ ++#define SKB_DATAREF_SHIFT 16 ++#define SKB_DATAREF_MASK ((1 << SKB_DATAREF_SHIFT) - 1) ++ ++struct skb_timeval { ++ u32 off_sec; ++ u32 off_usec; ++}; ++ ++ ++enum { ++ SKB_FCLONE_UNAVAILABLE, ++ SKB_FCLONE_ORIG, ++ SKB_FCLONE_CLONE, ++}; ++ ++enum { ++ SKB_GSO_TCPV4 = 1 << 0, ++ SKB_GSO_UDP = 1 << 1, ++ ++ /* This indicates the skb is from an untrusted source. */ ++ SKB_GSO_DODGY = 1 << 2, ++ ++ /* This indicates the tcp segment has CWR set. */ ++ SKB_GSO_TCP_ECN = 1 << 3, ++ ++ SKB_GSO_TCPV6 = 1 << 4, ++}; ++ ++/** ++ * struct sk_buff - socket buffer ++ * @next: Next buffer in list ++ * @prev: Previous buffer in list ++ * @sk: Socket we are owned by ++ * @tstamp: Time we arrived ++ * @dev: Device we arrived on/are leaving by ++ * @iif: ifindex of device we arrived on ++ * @h: Transport layer header ++ * @nh: Network layer header ++ * @mac: Link layer header ++ * @dst: destination entry ++ * @sp: the security path, used for xfrm ++ * @cb: Control buffer. Free for use by every layer. Put private vars here ++ * @len: Length of actual data ++ * @data_len: Data length ++ * @mac_len: Length of link layer header ++ * @csum: Checksum ++ * @local_df: allow local fragmentation ++ * @cloned: Head may be cloned (check refcnt to be sure) ++ * @nohdr: Payload reference only, must not modify header ++ * @pkt_type: Packet class ++ * @fclone: skbuff clone status ++ * @ip_summed: Driver fed us an IP checksum ++ * @priority: Packet queueing priority ++ * @users: User count - see {datagram,tcp}.c ++ * @protocol: Packet protocol from driver ++ * @truesize: Buffer size ++ * @head: Head of buffer ++ * @data: Data head pointer ++ * @tail: Tail pointer ++ * @end: End pointer ++ * @destructor: Destruct function ++ * @mark: Generic packet mark ++ * @nfct: Associated connection, if any ++ * @ipvs_property: skbuff is owned by ipvs ++ * @nfctinfo: Relationship of this skb to the connection ++ * @nfct_reasm: netfilter conntrack re-assembly pointer ++ * @nf_bridge: Saved data about a bridged frame - see br_netfilter.c ++ * @tc_index: Traffic control index ++ * @tc_verd: traffic control verdict ++ * @dma_cookie: a cookie to one of several possible DMA operations ++ * done by skb DMA functions ++ * @secmark: security marking ++ */ ++ ++struct sk_buff { ++ /* These two members must be first. */ ++ struct sk_buff *next; ++ struct sk_buff *prev; ++ ++ struct sock *sk; ++ struct skb_timeval tstamp; ++ struct net_device *dev; ++ int iif; ++ /* 4 byte hole on 64 bit*/ ++ ++ union { ++ struct tcphdr *th; ++ struct udphdr *uh; ++ struct icmphdr *icmph; ++ struct igmphdr *igmph; ++ struct iphdr *ipiph; ++ struct ipv6hdr *ipv6h; ++ unsigned char *raw; ++ } h; ++ ++ union { ++ struct iphdr *iph; ++ struct ipv6hdr *ipv6h; ++ struct arphdr *arph; ++ unsigned char *raw; ++ } nh; ++ ++ union { ++ unsigned char *raw; ++ } mac; ++ ++ struct dst_entry *dst; ++ struct sec_path *sp; ++ ++ /* ++ * This is the control buffer. It is free to use for every ++ * layer. Please put your private variables there. If you ++ * want to keep them across layers you have to do a skb_clone() ++ * first. This is owned by whoever has the skb queued ATM. ++ */ ++ char cb[48]; ++ ++ unsigned int len, ++ data_len, ++ mac_len; ++ union { ++ __wsum csum; ++ __u32 csum_offset; ++ }; ++ __u32 priority; ++ __u8 local_df:1, ++ cloned:1, ++ ip_summed:2, ++ nohdr:1, ++ nfctinfo:3; ++ __u8 pkt_type:3, ++ fclone:2, ++ ipvs_property:1; ++ __be16 protocol; ++ ++ void (*destructor)(struct sk_buff *skb); ++#ifdef CONFIG_NETFILTER ++ struct nf_conntrack *nfct; ++#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) ++ struct sk_buff *nfct_reasm; ++#endif ++#ifdef CONFIG_BRIDGE_NETFILTER ++ struct nf_bridge_info *nf_bridge; ++#endif ++#endif /* CONFIG_NETFILTER */ ++#ifdef CONFIG_NET_SCHED ++ __u16 tc_index; /* traffic control index */ ++#ifdef CONFIG_NET_CLS_ACT ++ __u16 tc_verd; /* traffic control verdict */ ++#endif ++#endif ++#ifdef CONFIG_NET_DMA ++ dma_cookie_t dma_cookie; ++#endif ++#ifdef CONFIG_NETWORK_SECMARK ++ __u32 secmark; ++#endif ++ ++ __u32 mark; ++ ++ /* These elements must be at the end, see alloc_skb() for details. */ ++ unsigned int truesize; ++ atomic_t users; ++ unsigned char *head, ++ *data, ++ *tail, ++ *end; ++}; ++ ++#ifdef __KERNEL__ ++/* ++ * Handling routines are only of interest to the kernel ++ */ ++#include <linux/slab.h> ++ ++#include <asm/system.h> ++ ++extern void kfree_skb(struct sk_buff *skb); ++extern void __kfree_skb(struct sk_buff *skb); ++extern struct sk_buff *__alloc_skb(unsigned int size, ++ gfp_t priority, int fclone, int node); ++static inline struct sk_buff *alloc_skb(unsigned int size, ++ gfp_t priority) ++{ ++ return __alloc_skb(size, priority, 0, -1); ++} ++ ++static inline struct sk_buff *alloc_skb_fclone(unsigned int size, ++ gfp_t priority) ++{ ++ return __alloc_skb(size, priority, 1, -1); ++} ++ ++extern struct sk_buff *alloc_skb_from_cache(struct kmem_cache *cp, ++ unsigned int size, ++ gfp_t priority); ++extern void kfree_skbmem(struct sk_buff *skb); ++extern struct sk_buff *skb_clone(struct sk_buff *skb, ++ gfp_t priority); ++extern struct sk_buff *skb_copy(const struct sk_buff *skb, ++ gfp_t priority); ++extern struct sk_buff *pskb_copy(struct sk_buff *skb, ++ gfp_t gfp_mask); ++extern int pskb_expand_head(struct sk_buff *skb, ++ int nhead, int ntail, ++ gfp_t gfp_mask); ++extern struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, ++ unsigned int headroom); ++extern struct sk_buff *skb_copy_expand(const struct sk_buff *skb, ++ int newheadroom, int newtailroom, ++ gfp_t priority); ++extern int skb_pad(struct sk_buff *skb, int pad); ++#define dev_kfree_skb(a) kfree_skb(a) ++extern void skb_over_panic(struct sk_buff *skb, int len, ++ void *here); ++extern void skb_under_panic(struct sk_buff *skb, int len, ++ void *here); ++extern void skb_truesize_bug(struct sk_buff *skb); ++ ++static inline void skb_truesize_check(struct sk_buff *skb) ++{ ++ if (unlikely((int)skb->truesize < sizeof(struct sk_buff) + skb->len)) ++ skb_truesize_bug(skb); ++} ++ ++extern int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb, ++ int getfrag(void *from, char *to, int offset, ++ int len,int odd, struct sk_buff *skb), ++ void *from, int length); ++ ++struct skb_seq_state ++{ ++ __u32 lower_offset; ++ __u32 upper_offset; ++ __u32 frag_idx; ++ __u32 stepped_offset; ++ struct sk_buff *root_skb; ++ struct sk_buff *cur_skb; ++ __u8 *frag_data; ++}; ++ ++extern void skb_prepare_seq_read(struct sk_buff *skb, ++ unsigned int from, unsigned int to, ++ struct skb_seq_state *st); ++extern unsigned int skb_seq_read(unsigned int consumed, const u8 **data, ++ struct skb_seq_state *st); ++extern void skb_abort_seq_read(struct skb_seq_state *st); ++ ++extern unsigned int skb_find_text(struct sk_buff *skb, unsigned int from, ++ unsigned int to, struct ts_config *config, ++ struct ts_state *state); ++ ++/* Internal */ ++#define skb_shinfo(SKB) ((struct skb_shared_info *)((SKB)->end)) ++ ++/** ++ * skb_queue_empty - check if a queue is empty ++ * @list: queue head ++ * ++ * Returns true if the queue is empty, false otherwise. ++ */ ++static inline int skb_queue_empty(const struct sk_buff_head *list) ++{ ++ return list->next == (struct sk_buff *)list; ++} ++ ++/** ++ * skb_get - reference buffer ++ * @skb: buffer to reference ++ * ++ * Makes another reference to a socket buffer and returns a pointer ++ * to the buffer. ++ */ ++static inline struct sk_buff *skb_get(struct sk_buff *skb) ++{ ++ atomic_inc(&skb->users); ++ return skb; ++} ++ ++/* ++ * If users == 1, we are the only owner and are can avoid redundant ++ * atomic change. ++ */ ++ ++/** ++ * skb_cloned - is the buffer a clone ++ * @skb: buffer to check ++ * ++ * Returns true if the buffer was generated with skb_clone() and is ++ * one of multiple shared copies of the buffer. Cloned buffers are ++ * shared data so must not be written to under normal circumstances. ++ */ ++static inline int skb_cloned(const struct sk_buff *skb) ++{ ++ return skb->cloned && ++ (atomic_read(&skb_shinfo(skb)->dataref) & SKB_DATAREF_MASK) != 1; ++} ++ ++/** ++ * skb_header_cloned - is the header a clone ++ * @skb: buffer to check ++ * ++ * Returns true if modifying the header part of the buffer requires ++ * the data to be copied. ++ */ ++static inline int skb_header_cloned(const struct sk_buff *skb) ++{ ++ int dataref; ++ ++ if (!skb->cloned) ++ return 0; ++ ++ dataref = atomic_read(&skb_shinfo(skb)->dataref); ++ dataref = (dataref & SKB_DATAREF_MASK) - (dataref >> SKB_DATAREF_SHIFT); ++ return dataref != 1; ++} ++ ++/** ++ * skb_header_release - release reference to header ++ * @skb: buffer to operate on ++ * ++ * Drop a reference to the header part of the buffer. This is done ++ * by acquiring a payload reference. You must not read from the header ++ * part of skb->data after this. ++ */ ++static inline void skb_header_release(struct sk_buff *skb) ++{ ++ BUG_ON(skb->nohdr); ++ skb->nohdr = 1; ++ atomic_add(1 << SKB_DATAREF_SHIFT, &skb_shinfo(skb)->dataref); ++} ++ ++/** ++ * skb_shared - is the buffer shared ++ * @skb: buffer to check ++ * ++ * Returns true if more than one person has a reference to this ++ * buffer. ++ */ ++static inline int skb_shared(const struct sk_buff *skb) ++{ ++ return atomic_read(&skb->users) != 1; ++} ++ ++/** ++ * skb_share_check - check if buffer is shared and if so clone it ++ * @skb: buffer to check ++ * @pri: priority for memory allocation ++ * ++ * If the buffer is shared the buffer is cloned and the old copy ++ * drops a reference. A new clone with a single reference is returned. ++ * If the buffer is not shared the original buffer is returned. When ++ * being called from interrupt status or with spinlocks held pri must ++ * be GFP_ATOMIC. ++ * ++ * NULL is returned on a memory allocation failure. ++ */ ++static inline struct sk_buff *skb_share_check(struct sk_buff *skb, ++ gfp_t pri) ++{ ++ might_sleep_if(pri & __GFP_WAIT); ++ if (skb_shared(skb)) { ++ struct sk_buff *nskb = skb_clone(skb, pri); ++ kfree_skb(skb); ++ skb = nskb; ++ } ++ return skb; ++} ++ ++/* ++ * Copy shared buffers into a new sk_buff. We effectively do COW on ++ * packets to handle cases where we have a local reader and forward ++ * and a couple of other messy ones. The normal one is tcpdumping ++ * a packet thats being forwarded. ++ */ ++ ++/** ++ * skb_unshare - make a copy of a shared buffer ++ * @skb: buffer to check ++ * @pri: priority for memory allocation ++ * ++ * If the socket buffer is a clone then this function creates a new ++ * copy of the data, drops a reference count on the old copy and returns ++ * the new copy with the reference count at 1. If the buffer is not a clone ++ * the original buffer is returned. When called with a spinlock held or ++ * from interrupt state @pri must be %GFP_ATOMIC ++ * ++ * %NULL is returned on a memory allocation failure. ++ */ ++static inline struct sk_buff *skb_unshare(struct sk_buff *skb, ++ gfp_t pri) ++{ ++ might_sleep_if(pri & __GFP_WAIT); ++ if (skb_cloned(skb)) { ++ struct sk_buff *nskb = skb_copy(skb, pri); ++ kfree_skb(skb); /* Free our shared copy */ ++ skb = nskb; ++ } ++ return skb; ++} ++ ++/** ++ * skb_peek ++ * @list_: list to peek at ++ * ++ * Peek an &sk_buff. Unlike most other operations you _MUST_ ++ * be careful with this one. A peek leaves the buffer on the ++ * list and someone else may run off with it. You must hold ++ * the appropriate locks or have a private queue to do this. ++ * ++ * Returns %NULL for an empty list or a pointer to the head element. ++ * The reference count is not incremented and the reference is therefore ++ * volatile. Use with caution. ++ */ ++static inline struct sk_buff *skb_peek(struct sk_buff_head *list_) ++{ ++ struct sk_buff *list = ((struct sk_buff *)list_)->next; ++ if (list == (struct sk_buff *)list_) ++ list = NULL; ++ return list; ++} ++ ++/** ++ * skb_peek_tail ++ * @list_: list to peek at ++ * ++ * Peek an &sk_buff. Unlike most other operations you _MUST_ ++ * be careful with this one. A peek leaves the buffer on the ++ * list and someone else may run off with it. You must hold ++ * the appropriate locks or have a private queue to do this. ++ * ++ * Returns %NULL for an empty list or a pointer to the tail element. ++ * The reference count is not incremented and the reference is therefore ++ * volatile. Use with caution. ++ */ ++static inline struct sk_buff *skb_peek_tail(struct sk_buff_head *list_) ++{ ++ struct sk_buff *list = ((struct sk_buff *)list_)->prev; ++ if (list == (struct sk_buff *)list_) ++ list = NULL; ++ return list; ++} ++ ++/** ++ * skb_queue_len - get queue length ++ * @list_: list to measure ++ * ++ * Return the length of an &sk_buff queue. ++ */ ++static inline __u32 skb_queue_len(const struct sk_buff_head *list_) ++{ ++ return list_->qlen; ++} ++ ++/* ++ * This function creates a split out lock class for each invocation; ++ * this is needed for now since a whole lot of users of the skb-queue ++ * infrastructure in drivers have different locking usage (in hardirq) ++ * than the networking core (in softirq only). In the long run either the ++ * network layer or drivers should need annotation to consolidate the ++ * main types of usage into 3 classes. ++ */ ++static inline void skb_queue_head_init(struct sk_buff_head *list) ++{ ++ spin_lock_init(&list->lock); ++ list->prev = list->next = (struct sk_buff *)list; ++ list->qlen = 0; ++} ++ ++/* ++ * Insert an sk_buff at the start of a list. ++ * ++ * The "__skb_xxxx()" functions are the non-atomic ones that ++ * can only be called with interrupts disabled. ++ */ ++ ++/** ++ * __skb_queue_after - queue a buffer at the list head ++ * @list: list to use ++ * @prev: place after this buffer ++ * @newsk: buffer to queue ++ * ++ * Queue a buffer int the middle of a list. This function takes no locks ++ * and you must therefore hold required locks before calling it. ++ * ++ * A buffer cannot be placed on two lists at the same time. ++ */ ++static inline void __skb_queue_after(struct sk_buff_head *list, ++ struct sk_buff *prev, ++ struct sk_buff *newsk) ++{ ++ struct sk_buff *next; ++ list->qlen++; ++ ++ next = prev->next; ++ newsk->next = next; ++ newsk->prev = prev; ++ next->prev = prev->next = newsk; ++} ++ ++/** ++ * __skb_queue_head - queue a buffer at the list head ++ * @list: list to use ++ * @newsk: buffer to queue ++ * ++ * Queue a buffer at the start of a list. This function takes no locks ++ * and you must therefore hold required locks before calling it. ++ * ++ * A buffer cannot be placed on two lists at the same time. ++ */ ++extern void skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk); ++static inline void __skb_queue_head(struct sk_buff_head *list, ++ struct sk_buff *newsk) ++{ ++ __skb_queue_after(list, (struct sk_buff *)list, newsk); ++} ++ ++/** ++ * __skb_queue_tail - queue a buffer at the list tail ++ * @list: list to use ++ * @newsk: buffer to queue ++ * ++ * Queue a buffer at the end of a list. This function takes no locks ++ * and you must therefore hold required locks before calling it. ++ * ++ * A buffer cannot be placed on two lists at the same time. ++ */ ++extern void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk); ++static inline void __skb_queue_tail(struct sk_buff_head *list, ++ struct sk_buff *newsk) ++{ ++ struct sk_buff *prev, *next; ++ ++ list->qlen++; ++ next = (struct sk_buff *)list; ++ prev = next->prev; ++ newsk->next = next; ++ newsk->prev = prev; ++ next->prev = prev->next = newsk; ++} ++ ++ ++/** ++ * __skb_dequeue - remove from the head of the queue ++ * @list: list to dequeue from ++ * ++ * Remove the head of the list. This function does not take any locks ++ * so must be used with appropriate locks held only. The head item is ++ * returned or %NULL if the list is empty. ++ */ ++extern struct sk_buff *skb_dequeue(struct sk_buff_head *list); ++static inline struct sk_buff *__skb_dequeue(struct sk_buff_head *list) ++{ ++ struct sk_buff *next, *prev, *result; ++ ++ prev = (struct sk_buff *) list; ++ next = prev->next; ++ result = NULL; ++ if (next != prev) { ++ result = next; ++ next = next->next; ++ list->qlen--; ++ next->prev = prev; ++ prev->next = next; ++ result->next = result->prev = NULL; ++ } ++ return result; ++} ++ ++ ++/* ++ * Insert a packet on a list. ++ */ ++extern void skb_insert(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list); ++static inline void __skb_insert(struct sk_buff *newsk, ++ struct sk_buff *prev, struct sk_buff *next, ++ struct sk_buff_head *list) ++{ ++ newsk->next = next; ++ newsk->prev = prev; ++ next->prev = prev->next = newsk; ++ list->qlen++; ++} ++ ++/* ++ * Place a packet after a given packet in a list. ++ */ ++extern void skb_append(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list); ++static inline void __skb_append(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list) ++{ ++ __skb_insert(newsk, old, old->next, list); ++} ++ ++/* ++ * remove sk_buff from list. _Must_ be called atomically, and with ++ * the list known.. ++ */ ++extern void skb_unlink(struct sk_buff *skb, struct sk_buff_head *list); ++static inline void __skb_unlink(struct sk_buff *skb, struct sk_buff_head *list) ++{ ++ struct sk_buff *next, *prev; ++ ++ list->qlen--; ++ next = skb->next; ++ prev = skb->prev; ++ skb->next = skb->prev = NULL; ++ next->prev = prev; ++ prev->next = next; ++} ++ ++ ++/* XXX: more streamlined implementation */ ++ ++/** ++ * __skb_dequeue_tail - remove from the tail of the queue ++ * @list: list to dequeue from ++ * ++ * Remove the tail of the list. This function does not take any locks ++ * so must be used with appropriate locks held only. The tail item is ++ * returned or %NULL if the list is empty. ++ */ ++extern struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list); ++static inline struct sk_buff *__skb_dequeue_tail(struct sk_buff_head *list) ++{ ++ struct sk_buff *skb = skb_peek_tail(list); ++ if (skb) ++ __skb_unlink(skb, list); ++ return skb; ++} ++ ++ ++static inline int skb_is_nonlinear(const struct sk_buff *skb) ++{ ++ return skb->data_len; ++} ++ ++static inline unsigned int skb_headlen(const struct sk_buff *skb) ++{ ++ return skb->len - skb->data_len; ++} ++ ++static inline int skb_pagelen(const struct sk_buff *skb) ++{ ++ int i, len = 0; ++ ++ for (i = (int)skb_shinfo(skb)->nr_frags - 1; i >= 0; i--) ++ len += skb_shinfo(skb)->frags[i].size; ++ return len + skb_headlen(skb); ++} ++ ++static inline void skb_fill_page_desc(struct sk_buff *skb, int i, ++ struct page *page, int off, int size) ++{ ++ skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; ++ ++ frag->page = page; ++ frag->page_offset = off; ++ frag->size = size; ++ skb_shinfo(skb)->nr_frags = i + 1; ++} ++ ++#define SKB_PAGE_ASSERT(skb) BUG_ON(skb_shinfo(skb)->nr_frags) ++#define SKB_FRAG_ASSERT(skb) BUG_ON(skb_shinfo(skb)->frag_list) ++#define SKB_LINEAR_ASSERT(skb) BUG_ON(skb_is_nonlinear(skb)) ++ ++/* ++ * Add data to an sk_buff ++ */ ++static inline unsigned char *__skb_put(struct sk_buff *skb, unsigned int len) ++{ ++ unsigned char *tmp = skb->tail; ++ SKB_LINEAR_ASSERT(skb); ++ skb->tail += len; ++ skb->len += len; ++ return tmp; ++} ++ ++/** ++ * skb_put - add data to a buffer ++ * @skb: buffer to use ++ * @len: amount of data to add ++ * ++ * This function extends the used data area of the buffer. If this would ++ * exceed the total buffer size the kernel will panic. A pointer to the ++ * first byte of the extra data is returned. ++ */ ++static inline unsigned char *skb_put(struct sk_buff *skb, unsigned int len) ++{ ++ unsigned char *tmp = skb->tail; ++ SKB_LINEAR_ASSERT(skb); ++ skb->tail += len; ++ skb->len += len; ++ if (unlikely(skb->tail>skb->end)) ++ skb_over_panic(skb, len, current_text_addr()); ++ return tmp; ++} ++ ++static inline unsigned char *__skb_push(struct sk_buff *skb, unsigned int len) ++{ ++ skb->data -= len; ++ skb->len += len; ++ return skb->data; ++} ++ ++/** ++ * skb_push - add data to the start of a buffer ++ * @skb: buffer to use ++ * @len: amount of data to add ++ * ++ * This function extends the used data area of the buffer at the buffer ++ * start. If this would exceed the total buffer headroom the kernel will ++ * panic. A pointer to the first byte of the extra data is returned. ++ */ ++static inline unsigned char *skb_push(struct sk_buff *skb, unsigned int len) ++{ ++ skb->data -= len; ++ skb->len += len; ++ if (unlikely(skb->data<skb->head)) ++ skb_under_panic(skb, len, current_text_addr()); ++ return skb->data; ++} ++ ++static inline unsigned char *__skb_pull(struct sk_buff *skb, unsigned int len) ++{ ++ skb->len -= len; ++ BUG_ON(skb->len < skb->data_len); ++ return skb->data += len; ++} ++ ++/** ++ * skb_pull - remove data from the start of a buffer ++ * @skb: buffer to use ++ * @len: amount of data to remove ++ * ++ * This function removes data from the start of a buffer, returning ++ * the memory to the headroom. A pointer to the next data in the buffer ++ * is returned. Once the data has been pulled future pushes will overwrite ++ * the old data. ++ */ ++static inline unsigned char *skb_pull(struct sk_buff *skb, unsigned int len) ++{ ++ return unlikely(len > skb->len) ? NULL : __skb_pull(skb, len); ++} ++ ++extern unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta); ++ ++static inline unsigned char *__pskb_pull(struct sk_buff *skb, unsigned int len) ++{ ++ if (len > skb_headlen(skb) && ++ !__pskb_pull_tail(skb, len-skb_headlen(skb))) ++ return NULL; ++ skb->len -= len; ++ return skb->data += len; ++} ++ ++static inline unsigned char *pskb_pull(struct sk_buff *skb, unsigned int len) ++{ ++ return unlikely(len > skb->len) ? NULL : __pskb_pull(skb, len); ++} ++ ++static inline int pskb_may_pull(struct sk_buff *skb, unsigned int len) ++{ ++ if (likely(len <= skb_headlen(skb))) ++ return 1; ++ if (unlikely(len > skb->len)) ++ return 0; ++ return __pskb_pull_tail(skb, len-skb_headlen(skb)) != NULL; ++} ++ ++/** ++ * skb_headroom - bytes at buffer head ++ * @skb: buffer to check ++ * ++ * Return the number of bytes of free space at the head of an &sk_buff. ++ */ ++static inline int skb_headroom(const struct sk_buff *skb) ++{ ++ return skb->data - skb->head; ++} ++ ++/** ++ * skb_tailroom - bytes at buffer end ++ * @skb: buffer to check ++ * ++ * Return the number of bytes of free space at the tail of an sk_buff ++ */ ++static inline int skb_tailroom(const struct sk_buff *skb) ++{ ++ return skb_is_nonlinear(skb) ? 0 : skb->end - skb->tail; ++} ++ ++/** ++ * skb_reserve - adjust headroom ++ * @skb: buffer to alter ++ * @len: bytes to move ++ * ++ * Increase the headroom of an empty &sk_buff by reducing the tail ++ * room. This is only allowed for an empty buffer. ++ */ ++static inline void skb_reserve(struct sk_buff *skb, int len) ++{ ++ skb->data += len; ++ skb->tail += len; ++} ++ ++/* ++ * CPUs often take a performance hit when accessing unaligned memory ++ * locations. The actual performance hit varies, it can be small if the ++ * hardware handles it or large if we have to take an exception and fix it ++ * in software. ++ * ++ * Since an ethernet header is 14 bytes network drivers often end up with ++ * the IP header at an unaligned offset. The IP header can be aligned by ++ * shifting the start of the packet by 2 bytes. Drivers should do this ++ * with: ++ * ++ * skb_reserve(NET_IP_ALIGN); ++ * ++ * The downside to this alignment of the IP header is that the DMA is now ++ * unaligned. On some architectures the cost of an unaligned DMA is high ++ * and this cost outweighs the gains made by aligning the IP header. ++ * ++ * Since this trade off varies between architectures, we allow NET_IP_ALIGN ++ * to be overridden. ++ */ ++#ifndef NET_IP_ALIGN ++#define NET_IP_ALIGN 2 ++#endif ++ ++/* ++ * The networking layer reserves some headroom in skb data (via ++ * dev_alloc_skb). This is used to avoid having to reallocate skb data when ++ * the header has to grow. In the default case, if the header has to grow ++ * 16 bytes or less we avoid the reallocation. ++ * ++ * Unfortunately this headroom changes the DMA alignment of the resulting ++ * network packet. As for NET_IP_ALIGN, this unaligned DMA is expensive ++ * on some architectures. An architecture can override this value, ++ * perhaps setting it to a cacheline in size (since that will maintain ++ * cacheline alignment of the DMA). It must be a power of 2. ++ * ++ * Various parts of the networking layer expect at least 16 bytes of ++ * headroom, you should not reduce this. ++ */ ++#ifndef NET_SKB_PAD ++#define NET_SKB_PAD 16 ++#endif ++ ++extern int ___pskb_trim(struct sk_buff *skb, unsigned int len); ++ ++static inline void __skb_trim(struct sk_buff *skb, unsigned int len) ++{ ++ if (unlikely(skb->data_len)) { ++ WARN_ON(1); ++ return; ++ } ++ skb->len = len; ++ skb->tail = skb->data + len; ++} ++ ++/** ++ * skb_trim - remove end from a buffer ++ * @skb: buffer to alter ++ * @len: new length ++ * ++ * Cut the length of a buffer down by removing data from the tail. If ++ * the buffer is already under the length specified it is not modified. ++ * The skb must be linear. ++ */ ++static inline void skb_trim(struct sk_buff *skb, unsigned int len) ++{ ++ if (skb->len > len) ++ __skb_trim(skb, len); ++} ++ ++ ++static inline int __pskb_trim(struct sk_buff *skb, unsigned int len) ++{ ++ if (skb->data_len) ++ return ___pskb_trim(skb, len); ++ __skb_trim(skb, len); ++ return 0; ++} ++ ++static inline int pskb_trim(struct sk_buff *skb, unsigned int len) ++{ ++ return (len < skb->len) ? __pskb_trim(skb, len) : 0; ++} ++ ++/** ++ * pskb_trim_unique - remove end from a paged unique (not cloned) buffer ++ * @skb: buffer to alter ++ * @len: new length ++ * ++ * This is identical to pskb_trim except that the caller knows that ++ * the skb is not cloned so we should never get an error due to out- ++ * of-memory. ++ */ ++static inline void pskb_trim_unique(struct sk_buff *skb, unsigned int len) ++{ ++ int err = pskb_trim(skb, len); ++ BUG_ON(err); ++} ++ ++/** ++ * skb_orphan - orphan a buffer ++ * @skb: buffer to orphan ++ * ++ * If a buffer currently has an owner then we call the owner's ++ * destructor function and make the @skb unowned. The buffer continues ++ * to exist but is no longer charged to its former owner. ++ */ ++static inline void skb_orphan(struct sk_buff *skb) ++{ ++ if (skb->destructor) ++ skb->destructor(skb); ++ skb->destructor = NULL; ++ skb->sk = NULL; ++} ++ ++/** ++ * __skb_queue_purge - empty a list ++ * @list: list to empty ++ * ++ * Delete all buffers on an &sk_buff list. Each buffer is removed from ++ * the list and one reference dropped. This function does not take the ++ * list lock and the caller must hold the relevant locks to use it. ++ */ ++extern void skb_queue_purge(struct sk_buff_head *list); ++static inline void __skb_queue_purge(struct sk_buff_head *list) ++{ ++ struct sk_buff *skb; ++ while ((skb = __skb_dequeue(list)) != NULL) ++ kfree_skb(skb); ++} ++ ++/** ++ * __dev_alloc_skb - allocate an skbuff for receiving ++ * @length: length to allocate ++ * @gfp_mask: get_free_pages mask, passed to alloc_skb ++ * ++ * Allocate a new &sk_buff and assign it a usage count of one. The ++ * buffer has unspecified headroom built in. Users should allocate ++ * the headroom they think they need without accounting for the ++ * built in space. The built in space is used for optimisations. ++ * ++ * %NULL is returned if there is no free memory. ++ */ ++static inline struct sk_buff *__dev_alloc_skb(unsigned int length, ++ gfp_t gfp_mask) ++{ ++ struct sk_buff *skb = alloc_skb(length + NET_SKB_PAD, gfp_mask); ++ if (likely(skb)) ++ skb_reserve(skb, NET_SKB_PAD); ++ return skb; ++} ++ ++/** ++ * dev_alloc_skb - allocate an skbuff for receiving ++ * @length: length to allocate ++ * ++ * Allocate a new &sk_buff and assign it a usage count of one. The ++ * buffer has unspecified headroom built in. Users should allocate ++ * the headroom they think they need without accounting for the ++ * built in space. The built in space is used for optimisations. ++ * ++ * %NULL is returned if there is no free memory. Although this function ++ * allocates memory it can be called from an interrupt. ++ */ ++static inline struct sk_buff *dev_alloc_skb(unsigned int length) ++{ ++ return __dev_alloc_skb(length, GFP_ATOMIC); ++} ++ ++extern struct sk_buff *__netdev_alloc_skb(struct net_device *dev, ++ unsigned int length, gfp_t gfp_mask); ++ ++/** ++ * netdev_alloc_skb - allocate an skbuff for rx on a specific device ++ * @dev: network device to receive on ++ * @length: length to allocate ++ * ++ * Allocate a new &sk_buff and assign it a usage count of one. The ++ * buffer has unspecified headroom built in. Users should allocate ++ * the headroom they think they need without accounting for the ++ * built in space. The built in space is used for optimisations. ++ * ++ * %NULL is returned if there is no free memory. Although this function ++ * allocates memory it can be called from an interrupt. ++ */ ++static inline struct sk_buff *netdev_alloc_skb(struct net_device *dev, ++ unsigned int length) ++{ ++ return __netdev_alloc_skb(dev, length, GFP_ATOMIC); ++} ++ ++/** ++ * skb_cow - copy header of skb when it is required ++ * @skb: buffer to c... [truncated message content] |