#include <linux/netdevice.h>
#include <linux/rtnetlink.h>
#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv6.h>
#include <linux/netfilter.h>
#include <linux/smp.h>
#include <net/pkt_sched.h>
#endif
-#define PRIV(sch) ((struct ingress_qdisc_data *) (sch)->data)
+#define PRIV(sch) qdisc_priv(sch)
/* Thanks to Doron Oz for this hack
*/
+#ifndef CONFIG_NET_CLS_ACT
+#ifdef CONFIG_NETFILTER
static int nf_registered;
+#endif
+#endif
struct ingress_qdisc_data {
struct Qdisc *q;
* Unlike normal "enqueue" functions, ingress_enqueue returns a
* firewall FW_* code.
*/
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
+ sch->bstats.packets++;
+ sch->bstats.bytes += skb->len;
switch (result) {
- case TC_POLICE_SHOT:
- result = NF_DROP;
- sch->stats.drops++;
+ case TC_ACT_SHOT:
+ result = TC_ACT_SHOT;
+ sch->qstats.drops++;
+ break;
+ case TC_ACT_STOLEN:
+ case TC_ACT_QUEUED:
+ result = TC_ACT_STOLEN;
break;
+ case TC_ACT_RECLASSIFY:
+ case TC_ACT_OK:
+ case TC_ACT_UNSPEC:
+ default:
+ skb->tc_index = TC_H_MIN(res.classid);
+ result = TC_ACT_OK;
+ break;
+ };
+/* backward compat */
+#else
+#ifdef CONFIG_NET_CLS_POLICE
+ switch (result) {
+ case TC_POLICE_SHOT:
+ result = NF_DROP;
+ sch->qstats.drops++;
+ break;
case TC_POLICE_RECLASSIFY: /* DSCP remarking here ? */
case TC_POLICE_OK:
case TC_POLICE_UNSPEC:
default:
- sch->stats.packets++;
- sch->stats.bytes += skb->len;
- result = NF_ACCEPT;
- break;
+ sch->bstats.packets++;
+ sch->bstats.bytes += skb->len;
+ result = NF_ACCEPT;
+ break;
};
+
#else
- sch->stats.packets++;
- sch->stats.bytes += skb->len;
+ D2PRINTK("Overriding result to ACCEPT\n");
+ result = NF_ACCEPT;
+ sch->bstats.packets++;
+ sch->bstats.bytes += skb->len;
+#endif
#endif
- skb->tc_index = TC_H_MIN(res.classid);
return result;
}
return 0;
}
+#ifndef CONFIG_NET_CLS_ACT
+#ifdef CONFIG_NETFILTER
static unsigned int
ing_hook(unsigned int hook, struct sk_buff **pskb,
const struct net_device *indev,
.priority = NF_IP_PRI_FILTER + 1,
};
-int ingress_init(struct Qdisc *sch,struct rtattr *opt)
+static struct nf_hook_ops ing6_ops = {
+ .hook = ing_hook,
+ .owner = THIS_MODULE,
+ .pf = PF_INET6,
+ .hooknum = NF_IP6_PRE_ROUTING,
+ .priority = NF_IP6_PRI_FILTER + 1,
+};
+
+#endif
+#endif
+
+static int ingress_init(struct Qdisc *sch,struct rtattr *opt)
{
struct ingress_qdisc_data *p = PRIV(sch);
+/* Make sure either netfilter or preferably CLS_ACT is
+* compiled in */
+#ifndef CONFIG_NET_CLS_ACT
+#ifndef CONFIG_NETFILTER
+ printk("You MUST compile classifier actions into the kernel\n");
+ return -EINVAL;
+#else
+ printk("Ingress scheduler: Classifier actions prefered over netfilter\n");
+#endif
+#endif
+
+#ifndef CONFIG_NET_CLS_ACT
+#ifdef CONFIG_NETFILTER
if (!nf_registered) {
if (nf_register_hook(&ing_ops) < 0) {
printk("ingress qdisc registration error \n");
- goto error;
+ return -EINVAL;
}
nf_registered++;
+
+ if (nf_register_hook(&ing6_ops) < 0) {
+ printk("IPv6 ingress qdisc registration error, " \
+ "disabling IPv6 support.\n");
+ } else
+ nf_registered++;
}
+#endif
+#endif
DPRINTK("ingress_init(sch %p,[qdisc %p],opt %p)\n",sch,p,opt);
- memset(p, 0, sizeof(*p));
- p->filter_list = NULL;
p->q = &noop_qdisc;
return 0;
-error:
- return -EINVAL;
}
p->filter_list = tp->next;
tcf_destroy(tp);
}
- memset(p, 0, sizeof(*p));
- p->filter_list = NULL;
-
#if 0
/* for future use */
qdisc_destroy(p->q);
static void __exit ingress_module_exit(void)
{
unregister_qdisc(&ingress_qdisc_ops);
- if (nf_registered)
+#ifndef CONFIG_NET_CLS_ACT
+#ifdef CONFIG_NETFILTER
+ if (nf_registered) {
nf_unregister_hook(&ing_ops);
+ if (nf_registered > 1)
+ nf_unregister_hook(&ing6_ops);
+ }
+#endif
+#endif
}
module_init(ingress_module_init)
module_exit(ingress_module_exit)