kernel: add a new scheduler action for restoring the connection tracking mark - usefu...
authorFelix Fietkau <nbd@openwrt.org>
Mon, 21 Feb 2011 00:03:20 +0000 (00:03 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Mon, 21 Feb 2011 00:03:20 +0000 (00:03 +0000)
SVN-Revision: 25639

package/iproute2/patches/200-act_connmark.patch [new file with mode: 0644]
package/kernel/modules/netsupport.mk
target/linux/generic/patches-2.6.32/280-sched_act_connmark.patch [new file with mode: 0644]
target/linux/generic/patches-2.6.34/280-sched_act_connmark.patch [new file with mode: 0644]
target/linux/generic/patches-2.6.35/290-sched_act_connmark.patch [new file with mode: 0644]
target/linux/generic/patches-2.6.36/290-sched_act_connmark.patch [new file with mode: 0644]
target/linux/generic/patches-2.6.37/290-sched_act_connmark.patch [new file with mode: 0644]
target/linux/generic/patches-2.6.38/290-sched_act_connmark.patch [new file with mode: 0644]

diff --git a/package/iproute2/patches/200-act_connmark.patch b/package/iproute2/patches/200-act_connmark.patch
new file mode 100644 (file)
index 0000000..561041f
--- /dev/null
@@ -0,0 +1,84 @@
+--- a/tc/Makefile
++++ b/tc/Makefile
+@@ -36,6 +36,7 @@ TCMODULES += m_mirred.o
+ TCMODULES += m_nat.o
+ TCMODULES += m_pedit.o
+ TCMODULES += m_skbedit.o
++TCMODULES += m_connmark.o
+ TCMODULES += p_ip.o
+ TCMODULES += p_icmp.o
+ TCMODULES += p_tcp.o
+--- /dev/null
++++ b/tc/m_connmark.c
+@@ -0,0 +1,71 @@
++/*
++ * m_connmark.c               Connection tracking marking import
++ *
++ * Copyright (c) 2011 Felix Fietkau <nbd@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
++ * Place - Suite 330, Boston, MA 02111-1307 USA.
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include "utils.h"
++#include "tc_util.h"
++
++static void
++explain(void)
++{
++      fprintf(stderr, "Usage: ... connmark\n");
++}
++
++static void
++usage(void)
++{
++      explain();
++      exit(-1);
++}
++
++static int
++parse_connmark(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
++            struct nlmsghdr *n)
++{
++      int argc = *argc_p;
++      char **argv = *argv_p;
++
++      if (matches(*argv, "connmark") != 0)
++              return -1;
++
++      NEXT_ARG();
++
++      *argc_p = argc;
++      *argv_p = argv;
++      return 0;
++}
++
++static int print_connmark(struct action_util *au, FILE *f, struct rtattr *arg)
++{
++      if (arg == NULL)
++              return -1;
++
++      fprintf(f, " connmark");
++
++      return 0;
++}
++
++struct action_util connmark_action_util = {
++      .id = "connmark",
++      .parse_aopt = parse_connmark,
++      .print_aopt = print_connmark,
++};
index e0e4238..c860034 100644 (file)
@@ -551,6 +551,7 @@ define KernelPackage/sched
        CONFIG_NET_ACT_MIRRED \
        CONFIG_NET_ACT_IPT \
        CONFIG_NET_ACT_POLICE \
+       CONFIG_NET_ACT_CONNMARK \
        CONFIG_NET_EMATCH=y \
        CONFIG_NET_EMATCH_CMP \
        CONFIG_NET_EMATCH_NBYTE \
diff --git a/target/linux/generic/patches-2.6.32/280-sched_act_connmark.patch b/target/linux/generic/patches-2.6.32/280-sched_act_connmark.patch
new file mode 100644 (file)
index 0000000..734fd1c
--- /dev/null
@@ -0,0 +1,171 @@
+--- /dev/null
++++ b/net/sched/act_connmark.c
+@@ -0,0 +1,137 @@
++/*
++ * Copyright (c) 2011 Felix Fietkau <nbd@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
++ * Place - Suite 330, Boston, MA 02111-1307 USA.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/skbuff.h>
++#include <linux/rtnetlink.h>
++#include <linux/pkt_cls.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++#include <net/netlink.h>
++#include <net/pkt_sched.h>
++#include <net/act_api.h>
++
++#include <net/netfilter/nf_conntrack.h>
++#include <net/netfilter/nf_conntrack_core.h>
++
++#define TCA_ACT_CONNMARK      20
++
++#define CONNMARK_TAB_MASK     3
++static struct tcf_common *tcf_connmark_ht[CONNMARK_TAB_MASK + 1];
++static u32 connmark_idx_gen;
++static DEFINE_RWLOCK(connmark_lock);
++
++static struct tcf_hashinfo connmark_hash_info = {
++      .htab   =       tcf_connmark_ht,
++      .hmask  =       CONNMARK_TAB_MASK,
++      .lock   =       &connmark_lock,
++};
++
++static int tcf_connmark(struct sk_buff *skb, struct tc_action *a,
++                     struct tcf_result *res)
++{
++      struct nf_conn *c;
++      enum ip_conntrack_info ctinfo;
++      int proto;
++      int r;
++
++      if (skb->protocol == htons(ETH_P_IP)) {
++              if (skb->len < sizeof(struct iphdr))
++                      goto out;
++              proto = PF_INET;
++      } else if (skb->protocol == htons(ETH_P_IPV6)) {
++              if (skb->len < sizeof(struct ipv6hdr))
++                      goto out;
++              proto = PF_INET6;
++      } else
++              goto out;
++
++      r = nf_conntrack_in(dev_net(skb->dev), proto, NF_INET_PRE_ROUTING, skb);
++      if (r != NF_ACCEPT)
++              goto out;
++
++      c = nf_ct_get(skb, &ctinfo);
++      if (!c)
++              goto out;
++
++      skb->mark = c->mark;
++      nf_conntrack_put(skb->nfct);
++      skb->nfct = NULL;
++
++out:
++      return TC_ACT_PIPE;
++}
++
++static int tcf_connmark_init(struct nlattr *nla, struct nlattr *est,
++                       struct tc_action *a, int ovr, int bind)
++{
++      struct tcf_common *pc;
++
++      pc = tcf_hash_create(0, est, a, sizeof(*pc), bind,
++                           &connmark_idx_gen, &connmark_hash_info);
++      if (IS_ERR(pc))
++          return PTR_ERR(pc);
++
++      tcf_hash_insert(pc, &connmark_hash_info);
++
++      return ACT_P_CREATED;
++}
++
++static inline int tcf_connmark_cleanup(struct tc_action *a, int bind)
++{
++      if (a->priv)
++              return tcf_hash_release(a->priv, bind, &connmark_hash_info);
++      return 0;
++}
++
++static inline int tcf_connmark_dump(struct sk_buff *skb, struct tc_action *a,
++                              int bind, int ref)
++{
++      return skb->len;
++}
++
++static struct tc_action_ops act_connmark_ops = {
++      .kind           =       "connmark",
++      .hinfo          =       &connmark_hash_info,
++      .type           =       TCA_ACT_CONNMARK,
++      .capab          =       TCA_CAP_NONE,
++      .owner          =       THIS_MODULE,
++      .act            =       tcf_connmark,
++      .dump           =       tcf_connmark_dump,
++      .cleanup        =       tcf_connmark_cleanup,
++      .init           =       tcf_connmark_init,
++      .walk           =       tcf_generic_walker,
++};
++
++MODULE_AUTHOR("Felix Fietkau <nbd@openwrt.org>");
++MODULE_DESCRIPTION("Connection tracking mark restoring");
++MODULE_LICENSE("GPL");
++
++static int __init connmark_init_module(void)
++{
++      return tcf_register_action(&act_connmark_ops);
++}
++
++static void __exit connmark_cleanup_module(void)
++{
++      tcf_unregister_action(&act_connmark_ops);
++}
++
++module_init(connmark_init_module);
++module_exit(connmark_cleanup_module);
+--- a/net/sched/Kconfig
++++ b/net/sched/Kconfig
+@@ -546,6 +546,18 @@ config NET_ACT_SKBEDIT
+         To compile this code as a module, choose M here: the
+         module will be called skbedit.
++config NET_ACT_CONNMARK
++        tristate "Connection Tracking Marking"
++        depends on NET_CLS_ACT
++        depends on NF_CONNTRACK
++        ---help---
++        Say Y here to restore the connmark from a scheduler action
++
++        If unsure, say N.
++
++        To compile this code as a module, choose M here: the
++        module will be called act_connmark.
++
+ config NET_CLS_IND
+       bool "Incoming device classification"
+       depends on NET_CLS_U32 || NET_CLS_FW
+--- a/net/sched/Makefile
++++ b/net/sched/Makefile
+@@ -15,6 +15,7 @@ obj-$(CONFIG_NET_ACT_NAT)    += act_nat.o
+ obj-$(CONFIG_NET_ACT_PEDIT)   += act_pedit.o
+ obj-$(CONFIG_NET_ACT_SIMP)    += act_simple.o
+ obj-$(CONFIG_NET_ACT_SKBEDIT) += act_skbedit.o
++obj-$(CONFIG_NET_ACT_CONNMARK)        += act_connmark.o
+ obj-$(CONFIG_NET_SCH_FIFO)    += sch_fifo.o
+ obj-$(CONFIG_NET_SCH_CBQ)     += sch_cbq.o
+ obj-$(CONFIG_NET_SCH_HTB)     += sch_htb.o
diff --git a/target/linux/generic/patches-2.6.34/280-sched_act_connmark.patch b/target/linux/generic/patches-2.6.34/280-sched_act_connmark.patch
new file mode 100644 (file)
index 0000000..e02d1bc
--- /dev/null
@@ -0,0 +1,171 @@
+--- /dev/null
++++ b/net/sched/act_connmark.c
+@@ -0,0 +1,137 @@
++/*
++ * Copyright (c) 2011 Felix Fietkau <nbd@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
++ * Place - Suite 330, Boston, MA 02111-1307 USA.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/skbuff.h>
++#include <linux/rtnetlink.h>
++#include <linux/pkt_cls.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++#include <net/netlink.h>
++#include <net/pkt_sched.h>
++#include <net/act_api.h>
++
++#include <net/netfilter/nf_conntrack.h>
++#include <net/netfilter/nf_conntrack_core.h>
++
++#define TCA_ACT_CONNMARK      20
++
++#define CONNMARK_TAB_MASK     3
++static struct tcf_common *tcf_connmark_ht[CONNMARK_TAB_MASK + 1];
++static u32 connmark_idx_gen;
++static DEFINE_RWLOCK(connmark_lock);
++
++static struct tcf_hashinfo connmark_hash_info = {
++      .htab   =       tcf_connmark_ht,
++      .hmask  =       CONNMARK_TAB_MASK,
++      .lock   =       &connmark_lock,
++};
++
++static int tcf_connmark(struct sk_buff *skb, struct tc_action *a,
++                     struct tcf_result *res)
++{
++      struct nf_conn *c;
++      enum ip_conntrack_info ctinfo;
++      int proto;
++      int r;
++
++      if (skb->protocol == htons(ETH_P_IP)) {
++              if (skb->len < sizeof(struct iphdr))
++                      goto out;
++              proto = PF_INET;
++      } else if (skb->protocol == htons(ETH_P_IPV6)) {
++              if (skb->len < sizeof(struct ipv6hdr))
++                      goto out;
++              proto = PF_INET6;
++      } else
++              goto out;
++
++      r = nf_conntrack_in(dev_net(skb->dev), proto, NF_INET_PRE_ROUTING, skb);
++      if (r != NF_ACCEPT)
++              goto out;
++
++      c = nf_ct_get(skb, &ctinfo);
++      if (!c)
++              goto out;
++
++      skb->mark = c->mark;
++      nf_conntrack_put(skb->nfct);
++      skb->nfct = NULL;
++
++out:
++      return TC_ACT_PIPE;
++}
++
++static int tcf_connmark_init(struct nlattr *nla, struct nlattr *est,
++                       struct tc_action *a, int ovr, int bind)
++{
++      struct tcf_common *pc;
++
++      pc = tcf_hash_create(0, est, a, sizeof(*pc), bind,
++                           &connmark_idx_gen, &connmark_hash_info);
++      if (IS_ERR(pc))
++          return PTR_ERR(pc);
++
++      tcf_hash_insert(pc, &connmark_hash_info);
++
++      return ACT_P_CREATED;
++}
++
++static inline int tcf_connmark_cleanup(struct tc_action *a, int bind)
++{
++      if (a->priv)
++              return tcf_hash_release(a->priv, bind, &connmark_hash_info);
++      return 0;
++}
++
++static inline int tcf_connmark_dump(struct sk_buff *skb, struct tc_action *a,
++                              int bind, int ref)
++{
++      return skb->len;
++}
++
++static struct tc_action_ops act_connmark_ops = {
++      .kind           =       "connmark",
++      .hinfo          =       &connmark_hash_info,
++      .type           =       TCA_ACT_CONNMARK,
++      .capab          =       TCA_CAP_NONE,
++      .owner          =       THIS_MODULE,
++      .act            =       tcf_connmark,
++      .dump           =       tcf_connmark_dump,
++      .cleanup        =       tcf_connmark_cleanup,
++      .init           =       tcf_connmark_init,
++      .walk           =       tcf_generic_walker,
++};
++
++MODULE_AUTHOR("Felix Fietkau <nbd@openwrt.org>");
++MODULE_DESCRIPTION("Connection tracking mark restoring");
++MODULE_LICENSE("GPL");
++
++static int __init connmark_init_module(void)
++{
++      return tcf_register_action(&act_connmark_ops);
++}
++
++static void __exit connmark_cleanup_module(void)
++{
++      tcf_unregister_action(&act_connmark_ops);
++}
++
++module_init(connmark_init_module);
++module_exit(connmark_cleanup_module);
+--- a/net/sched/Kconfig
++++ b/net/sched/Kconfig
+@@ -549,6 +549,18 @@
+         To compile this code as a module, choose M here: the
+         module will be called act_skbedit.
++config NET_ACT_CONNMARK
++        tristate "Connection Tracking Marking"
++        depends on NET_CLS_ACT
++        depends on NF_CONNTRACK
++        ---help---
++        Say Y here to restore the connmark from a scheduler action
++
++        If unsure, say N.
++
++        To compile this code as a module, choose M here: the
++        module will be called act_connmark.
++
+ config NET_CLS_IND
+       bool "Incoming device classification"
+       depends on NET_CLS_U32 || NET_CLS_FW
+--- a/net/sched/Makefile
++++ b/net/sched/Makefile
+@@ -15,6 +15,7 @@
+ obj-$(CONFIG_NET_ACT_PEDIT)   += act_pedit.o
+ obj-$(CONFIG_NET_ACT_SIMP)    += act_simple.o
+ obj-$(CONFIG_NET_ACT_SKBEDIT) += act_skbedit.o
++obj-$(CONFIG_NET_ACT_CONNMARK)        += act_connmark.o
+ obj-$(CONFIG_NET_SCH_FIFO)    += sch_fifo.o
+ obj-$(CONFIG_NET_SCH_CBQ)     += sch_cbq.o
+ obj-$(CONFIG_NET_SCH_HTB)     += sch_htb.o
diff --git a/target/linux/generic/patches-2.6.35/290-sched_act_connmark.patch b/target/linux/generic/patches-2.6.35/290-sched_act_connmark.patch
new file mode 100644 (file)
index 0000000..e02d1bc
--- /dev/null
@@ -0,0 +1,171 @@
+--- /dev/null
++++ b/net/sched/act_connmark.c
+@@ -0,0 +1,137 @@
++/*
++ * Copyright (c) 2011 Felix Fietkau <nbd@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
++ * Place - Suite 330, Boston, MA 02111-1307 USA.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/skbuff.h>
++#include <linux/rtnetlink.h>
++#include <linux/pkt_cls.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++#include <net/netlink.h>
++#include <net/pkt_sched.h>
++#include <net/act_api.h>
++
++#include <net/netfilter/nf_conntrack.h>
++#include <net/netfilter/nf_conntrack_core.h>
++
++#define TCA_ACT_CONNMARK      20
++
++#define CONNMARK_TAB_MASK     3
++static struct tcf_common *tcf_connmark_ht[CONNMARK_TAB_MASK + 1];
++static u32 connmark_idx_gen;
++static DEFINE_RWLOCK(connmark_lock);
++
++static struct tcf_hashinfo connmark_hash_info = {
++      .htab   =       tcf_connmark_ht,
++      .hmask  =       CONNMARK_TAB_MASK,
++      .lock   =       &connmark_lock,
++};
++
++static int tcf_connmark(struct sk_buff *skb, struct tc_action *a,
++                     struct tcf_result *res)
++{
++      struct nf_conn *c;
++      enum ip_conntrack_info ctinfo;
++      int proto;
++      int r;
++
++      if (skb->protocol == htons(ETH_P_IP)) {
++              if (skb->len < sizeof(struct iphdr))
++                      goto out;
++              proto = PF_INET;
++      } else if (skb->protocol == htons(ETH_P_IPV6)) {
++              if (skb->len < sizeof(struct ipv6hdr))
++                      goto out;
++              proto = PF_INET6;
++      } else
++              goto out;
++
++      r = nf_conntrack_in(dev_net(skb->dev), proto, NF_INET_PRE_ROUTING, skb);
++      if (r != NF_ACCEPT)
++              goto out;
++
++      c = nf_ct_get(skb, &ctinfo);
++      if (!c)
++              goto out;
++
++      skb->mark = c->mark;
++      nf_conntrack_put(skb->nfct);
++      skb->nfct = NULL;
++
++out:
++      return TC_ACT_PIPE;
++}
++
++static int tcf_connmark_init(struct nlattr *nla, struct nlattr *est,
++                       struct tc_action *a, int ovr, int bind)
++{
++      struct tcf_common *pc;
++
++      pc = tcf_hash_create(0, est, a, sizeof(*pc), bind,
++                           &connmark_idx_gen, &connmark_hash_info);
++      if (IS_ERR(pc))
++          return PTR_ERR(pc);
++
++      tcf_hash_insert(pc, &connmark_hash_info);
++
++      return ACT_P_CREATED;
++}
++
++static inline int tcf_connmark_cleanup(struct tc_action *a, int bind)
++{
++      if (a->priv)
++              return tcf_hash_release(a->priv, bind, &connmark_hash_info);
++      return 0;
++}
++
++static inline int tcf_connmark_dump(struct sk_buff *skb, struct tc_action *a,
++                              int bind, int ref)
++{
++      return skb->len;
++}
++
++static struct tc_action_ops act_connmark_ops = {
++      .kind           =       "connmark",
++      .hinfo          =       &connmark_hash_info,
++      .type           =       TCA_ACT_CONNMARK,
++      .capab          =       TCA_CAP_NONE,
++      .owner          =       THIS_MODULE,
++      .act            =       tcf_connmark,
++      .dump           =       tcf_connmark_dump,
++      .cleanup        =       tcf_connmark_cleanup,
++      .init           =       tcf_connmark_init,
++      .walk           =       tcf_generic_walker,
++};
++
++MODULE_AUTHOR("Felix Fietkau <nbd@openwrt.org>");
++MODULE_DESCRIPTION("Connection tracking mark restoring");
++MODULE_LICENSE("GPL");
++
++static int __init connmark_init_module(void)
++{
++      return tcf_register_action(&act_connmark_ops);
++}
++
++static void __exit connmark_cleanup_module(void)
++{
++      tcf_unregister_action(&act_connmark_ops);
++}
++
++module_init(connmark_init_module);
++module_exit(connmark_cleanup_module);
+--- a/net/sched/Kconfig
++++ b/net/sched/Kconfig
+@@ -549,6 +549,18 @@
+         To compile this code as a module, choose M here: the
+         module will be called act_skbedit.
++config NET_ACT_CONNMARK
++        tristate "Connection Tracking Marking"
++        depends on NET_CLS_ACT
++        depends on NF_CONNTRACK
++        ---help---
++        Say Y here to restore the connmark from a scheduler action
++
++        If unsure, say N.
++
++        To compile this code as a module, choose M here: the
++        module will be called act_connmark.
++
+ config NET_CLS_IND
+       bool "Incoming device classification"
+       depends on NET_CLS_U32 || NET_CLS_FW
+--- a/net/sched/Makefile
++++ b/net/sched/Makefile
+@@ -15,6 +15,7 @@
+ obj-$(CONFIG_NET_ACT_PEDIT)   += act_pedit.o
+ obj-$(CONFIG_NET_ACT_SIMP)    += act_simple.o
+ obj-$(CONFIG_NET_ACT_SKBEDIT) += act_skbedit.o
++obj-$(CONFIG_NET_ACT_CONNMARK)        += act_connmark.o
+ obj-$(CONFIG_NET_SCH_FIFO)    += sch_fifo.o
+ obj-$(CONFIG_NET_SCH_CBQ)     += sch_cbq.o
+ obj-$(CONFIG_NET_SCH_HTB)     += sch_htb.o
diff --git a/target/linux/generic/patches-2.6.36/290-sched_act_connmark.patch b/target/linux/generic/patches-2.6.36/290-sched_act_connmark.patch
new file mode 100644 (file)
index 0000000..e02d1bc
--- /dev/null
@@ -0,0 +1,171 @@
+--- /dev/null
++++ b/net/sched/act_connmark.c
+@@ -0,0 +1,137 @@
++/*
++ * Copyright (c) 2011 Felix Fietkau <nbd@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
++ * Place - Suite 330, Boston, MA 02111-1307 USA.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/skbuff.h>
++#include <linux/rtnetlink.h>
++#include <linux/pkt_cls.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++#include <net/netlink.h>
++#include <net/pkt_sched.h>
++#include <net/act_api.h>
++
++#include <net/netfilter/nf_conntrack.h>
++#include <net/netfilter/nf_conntrack_core.h>
++
++#define TCA_ACT_CONNMARK      20
++
++#define CONNMARK_TAB_MASK     3
++static struct tcf_common *tcf_connmark_ht[CONNMARK_TAB_MASK + 1];
++static u32 connmark_idx_gen;
++static DEFINE_RWLOCK(connmark_lock);
++
++static struct tcf_hashinfo connmark_hash_info = {
++      .htab   =       tcf_connmark_ht,
++      .hmask  =       CONNMARK_TAB_MASK,
++      .lock   =       &connmark_lock,
++};
++
++static int tcf_connmark(struct sk_buff *skb, struct tc_action *a,
++                     struct tcf_result *res)
++{
++      struct nf_conn *c;
++      enum ip_conntrack_info ctinfo;
++      int proto;
++      int r;
++
++      if (skb->protocol == htons(ETH_P_IP)) {
++              if (skb->len < sizeof(struct iphdr))
++                      goto out;
++              proto = PF_INET;
++      } else if (skb->protocol == htons(ETH_P_IPV6)) {
++              if (skb->len < sizeof(struct ipv6hdr))
++                      goto out;
++              proto = PF_INET6;
++      } else
++              goto out;
++
++      r = nf_conntrack_in(dev_net(skb->dev), proto, NF_INET_PRE_ROUTING, skb);
++      if (r != NF_ACCEPT)
++              goto out;
++
++      c = nf_ct_get(skb, &ctinfo);
++      if (!c)
++              goto out;
++
++      skb->mark = c->mark;
++      nf_conntrack_put(skb->nfct);
++      skb->nfct = NULL;
++
++out:
++      return TC_ACT_PIPE;
++}
++
++static int tcf_connmark_init(struct nlattr *nla, struct nlattr *est,
++                       struct tc_action *a, int ovr, int bind)
++{
++      struct tcf_common *pc;
++
++      pc = tcf_hash_create(0, est, a, sizeof(*pc), bind,
++                           &connmark_idx_gen, &connmark_hash_info);
++      if (IS_ERR(pc))
++          return PTR_ERR(pc);
++
++      tcf_hash_insert(pc, &connmark_hash_info);
++
++      return ACT_P_CREATED;
++}
++
++static inline int tcf_connmark_cleanup(struct tc_action *a, int bind)
++{
++      if (a->priv)
++              return tcf_hash_release(a->priv, bind, &connmark_hash_info);
++      return 0;
++}
++
++static inline int tcf_connmark_dump(struct sk_buff *skb, struct tc_action *a,
++                              int bind, int ref)
++{
++      return skb->len;
++}
++
++static struct tc_action_ops act_connmark_ops = {
++      .kind           =       "connmark",
++      .hinfo          =       &connmark_hash_info,
++      .type           =       TCA_ACT_CONNMARK,
++      .capab          =       TCA_CAP_NONE,
++      .owner          =       THIS_MODULE,
++      .act            =       tcf_connmark,
++      .dump           =       tcf_connmark_dump,
++      .cleanup        =       tcf_connmark_cleanup,
++      .init           =       tcf_connmark_init,
++      .walk           =       tcf_generic_walker,
++};
++
++MODULE_AUTHOR("Felix Fietkau <nbd@openwrt.org>");
++MODULE_DESCRIPTION("Connection tracking mark restoring");
++MODULE_LICENSE("GPL");
++
++static int __init connmark_init_module(void)
++{
++      return tcf_register_action(&act_connmark_ops);
++}
++
++static void __exit connmark_cleanup_module(void)
++{
++      tcf_unregister_action(&act_connmark_ops);
++}
++
++module_init(connmark_init_module);
++module_exit(connmark_cleanup_module);
+--- a/net/sched/Kconfig
++++ b/net/sched/Kconfig
+@@ -549,6 +549,18 @@
+         To compile this code as a module, choose M here: the
+         module will be called act_skbedit.
++config NET_ACT_CONNMARK
++        tristate "Connection Tracking Marking"
++        depends on NET_CLS_ACT
++        depends on NF_CONNTRACK
++        ---help---
++        Say Y here to restore the connmark from a scheduler action
++
++        If unsure, say N.
++
++        To compile this code as a module, choose M here: the
++        module will be called act_connmark.
++
+ config NET_CLS_IND
+       bool "Incoming device classification"
+       depends on NET_CLS_U32 || NET_CLS_FW
+--- a/net/sched/Makefile
++++ b/net/sched/Makefile
+@@ -15,6 +15,7 @@
+ obj-$(CONFIG_NET_ACT_PEDIT)   += act_pedit.o
+ obj-$(CONFIG_NET_ACT_SIMP)    += act_simple.o
+ obj-$(CONFIG_NET_ACT_SKBEDIT) += act_skbedit.o
++obj-$(CONFIG_NET_ACT_CONNMARK)        += act_connmark.o
+ obj-$(CONFIG_NET_SCH_FIFO)    += sch_fifo.o
+ obj-$(CONFIG_NET_SCH_CBQ)     += sch_cbq.o
+ obj-$(CONFIG_NET_SCH_HTB)     += sch_htb.o
diff --git a/target/linux/generic/patches-2.6.37/290-sched_act_connmark.patch b/target/linux/generic/patches-2.6.37/290-sched_act_connmark.patch
new file mode 100644 (file)
index 0000000..013c116
--- /dev/null
@@ -0,0 +1,171 @@
+--- /dev/null
++++ b/net/sched/act_connmark.c
+@@ -0,0 +1,137 @@
++/*
++ * Copyright (c) 2011 Felix Fietkau <nbd@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
++ * Place - Suite 330, Boston, MA 02111-1307 USA.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/skbuff.h>
++#include <linux/rtnetlink.h>
++#include <linux/pkt_cls.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++#include <net/netlink.h>
++#include <net/pkt_sched.h>
++#include <net/act_api.h>
++
++#include <net/netfilter/nf_conntrack.h>
++#include <net/netfilter/nf_conntrack_core.h>
++
++#define TCA_ACT_CONNMARK      20
++
++#define CONNMARK_TAB_MASK     3
++static struct tcf_common *tcf_connmark_ht[CONNMARK_TAB_MASK + 1];
++static u32 connmark_idx_gen;
++static DEFINE_RWLOCK(connmark_lock);
++
++static struct tcf_hashinfo connmark_hash_info = {
++      .htab   =       tcf_connmark_ht,
++      .hmask  =       CONNMARK_TAB_MASK,
++      .lock   =       &connmark_lock,
++};
++
++static int tcf_connmark(struct sk_buff *skb, struct tc_action *a,
++                     struct tcf_result *res)
++{
++      struct nf_conn *c;
++      enum ip_conntrack_info ctinfo;
++      int proto;
++      int r;
++
++      if (skb->protocol == htons(ETH_P_IP)) {
++              if (skb->len < sizeof(struct iphdr))
++                      goto out;
++              proto = PF_INET;
++      } else if (skb->protocol == htons(ETH_P_IPV6)) {
++              if (skb->len < sizeof(struct ipv6hdr))
++                      goto out;
++              proto = PF_INET6;
++      } else
++              goto out;
++
++      r = nf_conntrack_in(dev_net(skb->dev), proto, NF_INET_PRE_ROUTING, skb);
++      if (r != NF_ACCEPT)
++              goto out;
++
++      c = nf_ct_get(skb, &ctinfo);
++      if (!c)
++              goto out;
++
++      skb->mark = c->mark;
++      nf_conntrack_put(skb->nfct);
++      skb->nfct = NULL;
++
++out:
++      return TC_ACT_PIPE;
++}
++
++static int tcf_connmark_init(struct nlattr *nla, struct nlattr *est,
++                       struct tc_action *a, int ovr, int bind)
++{
++      struct tcf_common *pc;
++
++      pc = tcf_hash_create(0, est, a, sizeof(*pc), bind,
++                           &connmark_idx_gen, &connmark_hash_info);
++      if (IS_ERR(pc))
++          return PTR_ERR(pc);
++
++      tcf_hash_insert(pc, &connmark_hash_info);
++
++      return ACT_P_CREATED;
++}
++
++static inline int tcf_connmark_cleanup(struct tc_action *a, int bind)
++{
++      if (a->priv)
++              return tcf_hash_release(a->priv, bind, &connmark_hash_info);
++      return 0;
++}
++
++static inline int tcf_connmark_dump(struct sk_buff *skb, struct tc_action *a,
++                              int bind, int ref)
++{
++      return skb->len;
++}
++
++static struct tc_action_ops act_connmark_ops = {
++      .kind           =       "connmark",
++      .hinfo          =       &connmark_hash_info,
++      .type           =       TCA_ACT_CONNMARK,
++      .capab          =       TCA_CAP_NONE,
++      .owner          =       THIS_MODULE,
++      .act            =       tcf_connmark,
++      .dump           =       tcf_connmark_dump,
++      .cleanup        =       tcf_connmark_cleanup,
++      .init           =       tcf_connmark_init,
++      .walk           =       tcf_generic_walker,
++};
++
++MODULE_AUTHOR("Felix Fietkau <nbd@openwrt.org>");
++MODULE_DESCRIPTION("Connection tracking mark restoring");
++MODULE_LICENSE("GPL");
++
++static int __init connmark_init_module(void)
++{
++      return tcf_register_action(&act_connmark_ops);
++}
++
++static void __exit connmark_cleanup_module(void)
++{
++      tcf_unregister_action(&act_connmark_ops);
++}
++
++module_init(connmark_init_module);
++module_exit(connmark_cleanup_module);
+--- a/net/sched/Kconfig
++++ b/net/sched/Kconfig
+@@ -559,6 +559,18 @@
+         To compile this code as a module, choose M here: the
+         module will be called act_csum.
++config NET_ACT_CONNMARK
++        tristate "Connection Tracking Marking"
++        depends on NET_CLS_ACT
++        depends on NF_CONNTRACK
++        ---help---
++        Say Y here to restore the connmark from a scheduler action
++
++        If unsure, say N.
++
++        To compile this code as a module, choose M here: the
++        module will be called act_connmark.
++
+ config NET_CLS_IND
+       bool "Incoming device classification"
+       depends on NET_CLS_U32 || NET_CLS_FW
+--- a/net/sched/Makefile
++++ b/net/sched/Makefile
+@@ -16,6 +16,7 @@
+ obj-$(CONFIG_NET_ACT_SIMP)    += act_simple.o
+ obj-$(CONFIG_NET_ACT_SKBEDIT) += act_skbedit.o
+ obj-$(CONFIG_NET_ACT_CSUM)    += act_csum.o
++obj-$(CONFIG_NET_ACT_CONNMARK)        += act_connmark.o
+ obj-$(CONFIG_NET_SCH_FIFO)    += sch_fifo.o
+ obj-$(CONFIG_NET_SCH_CBQ)     += sch_cbq.o
+ obj-$(CONFIG_NET_SCH_HTB)     += sch_htb.o
diff --git a/target/linux/generic/patches-2.6.38/290-sched_act_connmark.patch b/target/linux/generic/patches-2.6.38/290-sched_act_connmark.patch
new file mode 100644 (file)
index 0000000..013c116
--- /dev/null
@@ -0,0 +1,171 @@
+--- /dev/null
++++ b/net/sched/act_connmark.c
+@@ -0,0 +1,137 @@
++/*
++ * Copyright (c) 2011 Felix Fietkau <nbd@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along with
++ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
++ * Place - Suite 330, Boston, MA 02111-1307 USA.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/skbuff.h>
++#include <linux/rtnetlink.h>
++#include <linux/pkt_cls.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++#include <net/netlink.h>
++#include <net/pkt_sched.h>
++#include <net/act_api.h>
++
++#include <net/netfilter/nf_conntrack.h>
++#include <net/netfilter/nf_conntrack_core.h>
++
++#define TCA_ACT_CONNMARK      20
++
++#define CONNMARK_TAB_MASK     3
++static struct tcf_common *tcf_connmark_ht[CONNMARK_TAB_MASK + 1];
++static u32 connmark_idx_gen;
++static DEFINE_RWLOCK(connmark_lock);
++
++static struct tcf_hashinfo connmark_hash_info = {
++      .htab   =       tcf_connmark_ht,
++      .hmask  =       CONNMARK_TAB_MASK,
++      .lock   =       &connmark_lock,
++};
++
++static int tcf_connmark(struct sk_buff *skb, struct tc_action *a,
++                     struct tcf_result *res)
++{
++      struct nf_conn *c;
++      enum ip_conntrack_info ctinfo;
++      int proto;
++      int r;
++
++      if (skb->protocol == htons(ETH_P_IP)) {
++              if (skb->len < sizeof(struct iphdr))
++                      goto out;
++              proto = PF_INET;
++      } else if (skb->protocol == htons(ETH_P_IPV6)) {
++              if (skb->len < sizeof(struct ipv6hdr))
++                      goto out;
++              proto = PF_INET6;
++      } else
++              goto out;
++
++      r = nf_conntrack_in(dev_net(skb->dev), proto, NF_INET_PRE_ROUTING, skb);
++      if (r != NF_ACCEPT)
++              goto out;
++
++      c = nf_ct_get(skb, &ctinfo);
++      if (!c)
++              goto out;
++
++      skb->mark = c->mark;
++      nf_conntrack_put(skb->nfct);
++      skb->nfct = NULL;
++
++out:
++      return TC_ACT_PIPE;
++}
++
++static int tcf_connmark_init(struct nlattr *nla, struct nlattr *est,
++                       struct tc_action *a, int ovr, int bind)
++{
++      struct tcf_common *pc;
++
++      pc = tcf_hash_create(0, est, a, sizeof(*pc), bind,
++                           &connmark_idx_gen, &connmark_hash_info);
++      if (IS_ERR(pc))
++          return PTR_ERR(pc);
++
++      tcf_hash_insert(pc, &connmark_hash_info);
++
++      return ACT_P_CREATED;
++}
++
++static inline int tcf_connmark_cleanup(struct tc_action *a, int bind)
++{
++      if (a->priv)
++              return tcf_hash_release(a->priv, bind, &connmark_hash_info);
++      return 0;
++}
++
++static inline int tcf_connmark_dump(struct sk_buff *skb, struct tc_action *a,
++                              int bind, int ref)
++{
++      return skb->len;
++}
++
++static struct tc_action_ops act_connmark_ops = {
++      .kind           =       "connmark",
++      .hinfo          =       &connmark_hash_info,
++      .type           =       TCA_ACT_CONNMARK,
++      .capab          =       TCA_CAP_NONE,
++      .owner          =       THIS_MODULE,
++      .act            =       tcf_connmark,
++      .dump           =       tcf_connmark_dump,
++      .cleanup        =       tcf_connmark_cleanup,
++      .init           =       tcf_connmark_init,
++      .walk           =       tcf_generic_walker,
++};
++
++MODULE_AUTHOR("Felix Fietkau <nbd@openwrt.org>");
++MODULE_DESCRIPTION("Connection tracking mark restoring");
++MODULE_LICENSE("GPL");
++
++static int __init connmark_init_module(void)
++{
++      return tcf_register_action(&act_connmark_ops);
++}
++
++static void __exit connmark_cleanup_module(void)
++{
++      tcf_unregister_action(&act_connmark_ops);
++}
++
++module_init(connmark_init_module);
++module_exit(connmark_cleanup_module);
+--- a/net/sched/Kconfig
++++ b/net/sched/Kconfig
+@@ -559,6 +559,18 @@
+         To compile this code as a module, choose M here: the
+         module will be called act_csum.
++config NET_ACT_CONNMARK
++        tristate "Connection Tracking Marking"
++        depends on NET_CLS_ACT
++        depends on NF_CONNTRACK
++        ---help---
++        Say Y here to restore the connmark from a scheduler action
++
++        If unsure, say N.
++
++        To compile this code as a module, choose M here: the
++        module will be called act_connmark.
++
+ config NET_CLS_IND
+       bool "Incoming device classification"
+       depends on NET_CLS_U32 || NET_CLS_FW
+--- a/net/sched/Makefile
++++ b/net/sched/Makefile
+@@ -16,6 +16,7 @@
+ obj-$(CONFIG_NET_ACT_SIMP)    += act_simple.o
+ obj-$(CONFIG_NET_ACT_SKBEDIT) += act_skbedit.o
+ obj-$(CONFIG_NET_ACT_CSUM)    += act_csum.o
++obj-$(CONFIG_NET_ACT_CONNMARK)        += act_connmark.o
+ obj-$(CONFIG_NET_SCH_FIFO)    += sch_fifo.o
+ obj-$(CONFIG_NET_SCH_CBQ)     += sch_cbq.o
+ obj-$(CONFIG_NET_SCH_HTB)     += sch_htb.o