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 net
*net
, 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(net
, 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(net
, index
);
44 static void em_ipset_destroy(struct tcf_ematch
*em
)
46 const struct xt_set_info
*set
= (const void *) em
->data
;
48 ip_set_nfnl_put(em
->net
, 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 struct nf_hook_state state
= {
63 int ret
, network_offset
;
65 switch (tc_skb_protocol(skb
)) {
67 state
.pf
= NFPROTO_IPV4
;
68 if (!pskb_network_may_pull(skb
, sizeof(struct iphdr
)))
70 acpar
.thoff
= ip_hdrlen(skb
);
72 case htons(ETH_P_IPV6
):
73 state
.pf
= NFPROTO_IPV6
;
74 if (!pskb_network_may_pull(skb
, sizeof(struct ipv6hdr
)))
76 /* doesn't call ipv6_find_hdr() because ipset doesn't use thoff, yet */
77 acpar
.thoff
= sizeof(struct ipv6hdr
);
83 opt
.family
= state
.pf
;
85 opt
.flags
= set
->flags
;
87 opt
.ext
.timeout
= ~0u;
89 network_offset
= skb_network_offset(skb
);
90 skb_pull(skb
, network_offset
);
97 indev
= dev_get_by_index_rcu(em
->net
, skb
->skb_iif
);
99 state
.in
= indev
? indev
: dev
;
101 acpar
.state
= &state
;
103 ret
= ip_set_test(set
->index
, skb
, &acpar
, &opt
);
107 skb_push(skb
, network_offset
);
111 static struct tcf_ematch_ops em_ipset_ops
= {
112 .kind
= TCF_EM_IPSET
,
113 .change
= em_ipset_change
,
114 .destroy
= em_ipset_destroy
,
115 .match
= em_ipset_match
,
116 .owner
= THIS_MODULE
,
117 .link
= LIST_HEAD_INIT(em_ipset_ops
.link
)
120 static int __init
init_em_ipset(void)
122 return tcf_em_register(&em_ipset_ops
);
125 static void __exit
exit_em_ipset(void)
127 tcf_em_unregister(&em_ipset_ops
);
130 MODULE_LICENSE("GPL");
131 MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
132 MODULE_DESCRIPTION("TC extended match for IP sets");
134 module_init(init_em_ipset
);
135 module_exit(exit_em_ipset
);
137 MODULE_ALIAS_TCF_EMATCH(TCF_EM_IPSET
);