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 int ret
, network_offset
;
62 switch (tc_skb_protocol(skb
)) {
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
;
86 opt
.ext
.timeout
= ~0u;
88 network_offset
= skb_network_offset(skb
);
89 skb_pull(skb
, network_offset
);
96 indev
= dev_get_by_index_rcu(em
->net
, skb
->skb_iif
);
99 acpar
.in
= indev
? indev
: dev
;
102 ret
= ip_set_test(set
->index
, skb
, &acpar
, &opt
);
106 skb_push(skb
, network_offset
);
110 static struct tcf_ematch_ops em_ipset_ops
= {
111 .kind
= TCF_EM_IPSET
,
112 .change
= em_ipset_change
,
113 .destroy
= em_ipset_destroy
,
114 .match
= em_ipset_match
,
115 .owner
= THIS_MODULE
,
116 .link
= LIST_HEAD_INIT(em_ipset_ops
.link
)
119 static int __init
init_em_ipset(void)
121 return tcf_em_register(&em_ipset_ops
);
124 static void __exit
exit_em_ipset(void)
126 tcf_em_unregister(&em_ipset_ops
);
129 MODULE_LICENSE("GPL");
130 MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
131 MODULE_DESCRIPTION("TC extended match for IP sets");
133 module_init(init_em_ipset
);
134 module_exit(exit_em_ipset
);
136 MODULE_ALIAS_TCF_EMATCH(TCF_EM_IPSET
);