2 * net/sched/em_ipset.c ipset ematch
4 * Copyright (c) 2012 Florian Westphal <fw@strlen.de>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * version 2 as published by the Free Software Foundation.
11 #include <linux/gfp.h>
12 #include <linux/module.h>
13 #include <linux/types.h>
14 #include <linux/kernel.h>
15 #include <linux/string.h>
16 #include <linux/skbuff.h>
17 #include <linux/netfilter/xt_set.h>
18 #include <linux/ipv6.h>
20 #include <net/pkt_cls.h>
22 static int em_ipset_change(struct tcf_proto
*tp
, void *data
, int data_len
,
23 struct tcf_ematch
*em
)
25 struct xt_set_info
*set
= data
;
28 if (data_len
!= sizeof(*set
))
31 index
= ip_set_nfnl_get_byindex(set
->index
);
32 if (index
== IPSET_INVALID_ID
)
35 em
->datalen
= sizeof(*set
);
36 em
->data
= (unsigned long)kmemdup(data
, em
->datalen
, GFP_KERNEL
);
40 ip_set_nfnl_put(index
);
44 static void em_ipset_destroy(struct tcf_proto
*p
, struct tcf_ematch
*em
)
46 const struct xt_set_info
*set
= (const void *) em
->data
;
48 ip_set_nfnl_put(set
->index
);
49 kfree((void *) em
->data
);
53 static int em_ipset_match(struct sk_buff
*skb
, struct tcf_ematch
*em
,
54 struct tcf_pkt_info
*info
)
56 struct ip_set_adt_opt opt
;
57 struct xt_action_param acpar
;
58 const struct xt_set_info
*set
= (const void *) em
->data
;
59 struct net_device
*dev
, *indev
= NULL
;
60 int ret
, network_offset
;
62 switch (skb
->protocol
) {
64 acpar
.family
= NFPROTO_IPV4
;
65 if (!pskb_network_may_pull(skb
, sizeof(struct iphdr
)))
67 acpar
.thoff
= ip_hdrlen(skb
);
69 case htons(ETH_P_IPV6
):
70 acpar
.family
= NFPROTO_IPV6
;
71 if (!pskb_network_may_pull(skb
, sizeof(struct ipv6hdr
)))
73 /* doesn't call ipv6_find_hdr() because ipset doesn't use thoff, yet */
74 acpar
.thoff
= sizeof(struct ipv6hdr
);
82 opt
.family
= acpar
.family
;
84 opt
.flags
= set
->flags
;
88 network_offset
= skb_network_offset(skb
);
89 skb_pull(skb
, network_offset
);
95 if (dev
&& skb
->skb_iif
)
96 indev
= dev_get_by_index_rcu(dev_net(dev
), skb
->skb_iif
);
98 acpar
.in
= indev
? indev
: dev
;
101 ret
= ip_set_test(set
->index
, skb
, &acpar
, &opt
);
105 skb_push(skb
, network_offset
);
109 static struct tcf_ematch_ops em_ipset_ops
= {
110 .kind
= TCF_EM_IPSET
,
111 .change
= em_ipset_change
,
112 .destroy
= em_ipset_destroy
,
113 .match
= em_ipset_match
,
114 .owner
= THIS_MODULE
,
115 .link
= LIST_HEAD_INIT(em_ipset_ops
.link
)
118 static int __init
init_em_ipset(void)
120 return tcf_em_register(&em_ipset_ops
);
123 static void __exit
exit_em_ipset(void)
125 tcf_em_unregister(&em_ipset_ops
);
128 MODULE_LICENSE("GPL");
129 MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
130 MODULE_DESCRIPTION("TC extended match for IP sets");
132 module_init(init_em_ipset
);
133 module_exit(exit_em_ipset
);
135 MODULE_ALIAS_TCF_EMATCH(TCF_EM_IPSET
);