Ver código fonte

kernel: add a new scheduler action for restoring the connection tracking mark - useful for ingress shaping, will be used for replacing IMQ later

SVN-Revision: 25639
Felix Fietkau 15 anos atrás
pai
commit
c0f0316109

+ 84 - 0
package/iproute2/patches/200-act_connmark.patch

@@ -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 <[email protected]>
++ *
++ * 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,
++};

+ 1 - 0
package/kernel/modules/netsupport.mk

@@ -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 \

+ 171 - 0
target/linux/generic/patches-2.6.32/280-sched_act_connmark.patch

@@ -0,0 +1,171 @@
+--- /dev/null
++++ b/net/sched/act_connmark.c
+@@ -0,0 +1,137 @@
++/*
++ * Copyright (c) 2011 Felix Fietkau <[email protected]>
++ *
++ * 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 <[email protected]>");
++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

+ 171 - 0
target/linux/generic/patches-2.6.34/280-sched_act_connmark.patch

@@ -0,0 +1,171 @@
+--- /dev/null
++++ b/net/sched/act_connmark.c
+@@ -0,0 +1,137 @@
++/*
++ * Copyright (c) 2011 Felix Fietkau <[email protected]>
++ *
++ * 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 <[email protected]>");
++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

+ 171 - 0
target/linux/generic/patches-2.6.35/290-sched_act_connmark.patch

@@ -0,0 +1,171 @@
+--- /dev/null
++++ b/net/sched/act_connmark.c
+@@ -0,0 +1,137 @@
++/*
++ * Copyright (c) 2011 Felix Fietkau <[email protected]>
++ *
++ * 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 <[email protected]>");
++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

+ 171 - 0
target/linux/generic/patches-2.6.36/290-sched_act_connmark.patch

@@ -0,0 +1,171 @@
+--- /dev/null
++++ b/net/sched/act_connmark.c
+@@ -0,0 +1,137 @@
++/*
++ * Copyright (c) 2011 Felix Fietkau <[email protected]>
++ *
++ * 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 <[email protected]>");
++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

+ 171 - 0
target/linux/generic/patches-2.6.37/290-sched_act_connmark.patch

@@ -0,0 +1,171 @@
+--- /dev/null
++++ b/net/sched/act_connmark.c
+@@ -0,0 +1,137 @@
++/*
++ * Copyright (c) 2011 Felix Fietkau <[email protected]>
++ *
++ * 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 <[email protected]>");
++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

+ 171 - 0
target/linux/generic/patches-2.6.38/290-sched_act_connmark.patch

@@ -0,0 +1,171 @@
+--- /dev/null
++++ b/net/sched/act_connmark.c
+@@ -0,0 +1,137 @@
++/*
++ * Copyright (c) 2011 Felix Fietkau <[email protected]>
++ *
++ * 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 <[email protected]>");
++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