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