aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/act_ipt.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/act_ipt.c')
-rw-r--r--net/sched/act_ipt.c180
1 files changed, 80 insertions, 100 deletions
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index 37640c6fc014..d8c9310da6e5 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -14,7 +14,6 @@
14#include <asm/uaccess.h> 14#include <asm/uaccess.h>
15#include <asm/system.h> 15#include <asm/system.h>
16#include <asm/bitops.h> 16#include <asm/bitops.h>
17#include <linux/config.h>
18#include <linux/types.h> 17#include <linux/types.h>
19#include <linux/kernel.h> 18#include <linux/kernel.h>
20#include <linux/sched.h> 19#include <linux/sched.h>
@@ -39,25 +38,19 @@
39 38
40#include <linux/netfilter_ipv4/ip_tables.h> 39#include <linux/netfilter_ipv4/ip_tables.h>
41 40
42/* use generic hash table */
43#define MY_TAB_SIZE 16
44#define MY_TAB_MASK 15
45 41
46static u32 idx_gen; 42#define IPT_TAB_MASK 15
47static struct tcf_ipt *tcf_ipt_ht[MY_TAB_SIZE]; 43static struct tcf_common *tcf_ipt_ht[IPT_TAB_MASK + 1];
48/* ipt hash table lock */ 44static u32 ipt_idx_gen;
49static DEFINE_RWLOCK(ipt_lock); 45static DEFINE_RWLOCK(ipt_lock);
50 46
51/* ovewrride the defaults */ 47static struct tcf_hashinfo ipt_hash_info = {
52#define tcf_st tcf_ipt 48 .htab = tcf_ipt_ht,
53#define tcf_t_lock ipt_lock 49 .hmask = IPT_TAB_MASK,
54#define tcf_ht tcf_ipt_ht 50 .lock = &ipt_lock,
55 51};
56#define CONFIG_NET_ACT_INIT
57#include <net/pkt_act.h>
58 52
59static int 53static int ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook)
60ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook)
61{ 54{
62 struct ipt_target *target; 55 struct ipt_target *target;
63 int ret = 0; 56 int ret = 0;
@@ -66,7 +59,6 @@ ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook)
66 if (!target) 59 if (!target)
67 return -ENOENT; 60 return -ENOENT;
68 61
69 DPRINTK("ipt_init_target: found %s\n", target->name);
70 t->u.kernel.target = target; 62 t->u.kernel.target = target;
71 63
72 ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t), 64 ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
@@ -77,10 +69,7 @@ ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook)
77 if (t->u.kernel.target->checkentry 69 if (t->u.kernel.target->checkentry
78 && !t->u.kernel.target->checkentry(table, NULL, 70 && !t->u.kernel.target->checkentry(table, NULL,
79 t->u.kernel.target, t->data, 71 t->u.kernel.target, t->data,
80 t->u.target_size - sizeof(*t),
81 hook)) { 72 hook)) {
82 DPRINTK("ipt_init_target: check failed for `%s'.\n",
83 t->u.kernel.target->name);
84 module_put(t->u.kernel.target->me); 73 module_put(t->u.kernel.target->me);
85 ret = -EINVAL; 74 ret = -EINVAL;
86 } 75 }
@@ -88,40 +77,37 @@ ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook)
88 return ret; 77 return ret;
89} 78}
90 79
91static void 80static void ipt_destroy_target(struct ipt_entry_target *t)
92ipt_destroy_target(struct ipt_entry_target *t)
93{ 81{
94 if (t->u.kernel.target->destroy) 82 if (t->u.kernel.target->destroy)
95 t->u.kernel.target->destroy(t->u.kernel.target, t->data, 83 t->u.kernel.target->destroy(t->u.kernel.target, t->data);
96 t->u.target_size - sizeof(*t));
97 module_put(t->u.kernel.target->me); 84 module_put(t->u.kernel.target->me);
98} 85}
99 86
100static int 87static int tcf_ipt_release(struct tcf_ipt *ipt, int bind)
101tcf_ipt_release(struct tcf_ipt *p, int bind)
102{ 88{
103 int ret = 0; 89 int ret = 0;
104 if (p) { 90 if (ipt) {
105 if (bind) 91 if (bind)
106 p->bindcnt--; 92 ipt->tcf_bindcnt--;
107 p->refcnt--; 93 ipt->tcf_refcnt--;
108 if (p->bindcnt <= 0 && p->refcnt <= 0) { 94 if (ipt->tcf_bindcnt <= 0 && ipt->tcf_refcnt <= 0) {
109 ipt_destroy_target(p->t); 95 ipt_destroy_target(ipt->tcfi_t);
110 kfree(p->tname); 96 kfree(ipt->tcfi_tname);
111 kfree(p->t); 97 kfree(ipt->tcfi_t);
112 tcf_hash_destroy(p); 98 tcf_hash_destroy(&ipt->common, &ipt_hash_info);
113 ret = ACT_P_DELETED; 99 ret = ACT_P_DELETED;
114 } 100 }
115 } 101 }
116 return ret; 102 return ret;
117} 103}
118 104
119static int 105static int tcf_ipt_init(struct rtattr *rta, struct rtattr *est,
120tcf_ipt_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, 106 struct tc_action *a, int ovr, int bind)
121 int ovr, int bind)
122{ 107{
123 struct rtattr *tb[TCA_IPT_MAX]; 108 struct rtattr *tb[TCA_IPT_MAX];
124 struct tcf_ipt *p; 109 struct tcf_ipt *ipt;
110 struct tcf_common *pc;
125 struct ipt_entry_target *td, *t; 111 struct ipt_entry_target *td, *t;
126 char *tname; 112 char *tname;
127 int ret = 0, err; 113 int ret = 0, err;
@@ -145,49 +131,51 @@ tcf_ipt_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a,
145 RTA_PAYLOAD(tb[TCA_IPT_INDEX-1]) >= sizeof(u32)) 131 RTA_PAYLOAD(tb[TCA_IPT_INDEX-1]) >= sizeof(u32))
146 index = *(u32 *)RTA_DATA(tb[TCA_IPT_INDEX-1]); 132 index = *(u32 *)RTA_DATA(tb[TCA_IPT_INDEX-1]);
147 133
148 p = tcf_hash_check(index, a, ovr, bind); 134 pc = tcf_hash_check(index, a, bind, &ipt_hash_info);
149 if (p == NULL) { 135 if (!pc) {
150 p = tcf_hash_create(index, est, a, sizeof(*p), ovr, bind); 136 pc = tcf_hash_create(index, est, a, sizeof(*ipt), bind,
151 if (p == NULL) 137 &ipt_idx_gen, &ipt_hash_info);
138 if (unlikely(!pc))
152 return -ENOMEM; 139 return -ENOMEM;
153 ret = ACT_P_CREATED; 140 ret = ACT_P_CREATED;
154 } else { 141 } else {
155 if (!ovr) { 142 if (!ovr) {
156 tcf_ipt_release(p, bind); 143 tcf_ipt_release(to_ipt(pc), bind);
157 return -EEXIST; 144 return -EEXIST;
158 } 145 }
159 } 146 }
147 ipt = to_ipt(pc);
160 148
161 hook = *(u32 *)RTA_DATA(tb[TCA_IPT_HOOK-1]); 149 hook = *(u32 *)RTA_DATA(tb[TCA_IPT_HOOK-1]);
162 150
163 err = -ENOMEM; 151 err = -ENOMEM;
164 tname = kmalloc(IFNAMSIZ, GFP_KERNEL); 152 tname = kmalloc(IFNAMSIZ, GFP_KERNEL);
165 if (tname == NULL) 153 if (unlikely(!tname))
166 goto err1; 154 goto err1;
167 if (tb[TCA_IPT_TABLE - 1] == NULL || 155 if (tb[TCA_IPT_TABLE - 1] == NULL ||
168 rtattr_strlcpy(tname, tb[TCA_IPT_TABLE-1], IFNAMSIZ) >= IFNAMSIZ) 156 rtattr_strlcpy(tname, tb[TCA_IPT_TABLE-1], IFNAMSIZ) >= IFNAMSIZ)
169 strcpy(tname, "mangle"); 157 strcpy(tname, "mangle");
170 158
171 t = kmalloc(td->u.target_size, GFP_KERNEL); 159 t = kmalloc(td->u.target_size, GFP_KERNEL);
172 if (t == NULL) 160 if (unlikely(!t))
173 goto err2; 161 goto err2;
174 memcpy(t, td, td->u.target_size); 162 memcpy(t, td, td->u.target_size);
175 163
176 if ((err = ipt_init_target(t, tname, hook)) < 0) 164 if ((err = ipt_init_target(t, tname, hook)) < 0)
177 goto err3; 165 goto err3;
178 166
179 spin_lock_bh(&p->lock); 167 spin_lock_bh(&ipt->tcf_lock);
180 if (ret != ACT_P_CREATED) { 168 if (ret != ACT_P_CREATED) {
181 ipt_destroy_target(p->t); 169 ipt_destroy_target(ipt->tcfi_t);
182 kfree(p->tname); 170 kfree(ipt->tcfi_tname);
183 kfree(p->t); 171 kfree(ipt->tcfi_t);
184 } 172 }
185 p->tname = tname; 173 ipt->tcfi_tname = tname;
186 p->t = t; 174 ipt->tcfi_t = t;
187 p->hook = hook; 175 ipt->tcfi_hook = hook;
188 spin_unlock_bh(&p->lock); 176 spin_unlock_bh(&ipt->tcf_lock);
189 if (ret == ACT_P_CREATED) 177 if (ret == ACT_P_CREATED)
190 tcf_hash_insert(p); 178 tcf_hash_insert(pc, &ipt_hash_info);
191 return ret; 179 return ret;
192 180
193err3: 181err3:
@@ -195,33 +183,32 @@ err3:
195err2: 183err2:
196 kfree(tname); 184 kfree(tname);
197err1: 185err1:
198 kfree(p); 186 kfree(pc);
199 return err; 187 return err;
200} 188}
201 189
202static int 190static int tcf_ipt_cleanup(struct tc_action *a, int bind)
203tcf_ipt_cleanup(struct tc_action *a, int bind)
204{ 191{
205 struct tcf_ipt *p = PRIV(a, ipt); 192 struct tcf_ipt *ipt = a->priv;
206 return tcf_ipt_release(p, bind); 193 return tcf_ipt_release(ipt, bind);
207} 194}
208 195
209static int 196static int tcf_ipt(struct sk_buff *skb, struct tc_action *a,
210tcf_ipt(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res) 197 struct tcf_result *res)
211{ 198{
212 int ret = 0, result = 0; 199 int ret = 0, result = 0;
213 struct tcf_ipt *p = PRIV(a, ipt); 200 struct tcf_ipt *ipt = a->priv;
214 201
215 if (skb_cloned(skb)) { 202 if (skb_cloned(skb)) {
216 if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) 203 if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
217 return TC_ACT_UNSPEC; 204 return TC_ACT_UNSPEC;
218 } 205 }
219 206
220 spin_lock(&p->lock); 207 spin_lock(&ipt->tcf_lock);
221 208
222 p->tm.lastuse = jiffies; 209 ipt->tcf_tm.lastuse = jiffies;
223 p->bstats.bytes += skb->len; 210 ipt->tcf_bstats.bytes += skb->len;
224 p->bstats.packets++; 211 ipt->tcf_bstats.packets++;
225 212
226 /* yes, we have to worry about both in and out dev 213 /* yes, we have to worry about both in and out dev
227 worry later - danger - this API seems to have changed 214 worry later - danger - this API seems to have changed
@@ -230,16 +217,17 @@ tcf_ipt(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res)
230 /* iptables targets take a double skb pointer in case the skb 217 /* iptables targets take a double skb pointer in case the skb
231 * needs to be replaced. We don't own the skb, so this must not 218 * needs to be replaced. We don't own the skb, so this must not
232 * happen. The pskb_expand_head above should make sure of this */ 219 * happen. The pskb_expand_head above should make sure of this */
233 ret = p->t->u.kernel.target->target(&skb, skb->dev, NULL, p->hook, 220 ret = ipt->tcfi_t->u.kernel.target->target(&skb, skb->dev, NULL,
234 p->t->u.kernel.target, p->t->data, 221 ipt->tcfi_hook,
235 NULL); 222 ipt->tcfi_t->u.kernel.target,
223 ipt->tcfi_t->data);
236 switch (ret) { 224 switch (ret) {
237 case NF_ACCEPT: 225 case NF_ACCEPT:
238 result = TC_ACT_OK; 226 result = TC_ACT_OK;
239 break; 227 break;
240 case NF_DROP: 228 case NF_DROP:
241 result = TC_ACT_SHOT; 229 result = TC_ACT_SHOT;
242 p->qstats.drops++; 230 ipt->tcf_qstats.drops++;
243 break; 231 break;
244 case IPT_CONTINUE: 232 case IPT_CONTINUE:
245 result = TC_ACT_PIPE; 233 result = TC_ACT_PIPE;
@@ -250,53 +238,46 @@ tcf_ipt(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res)
250 result = TC_POLICE_OK; 238 result = TC_POLICE_OK;
251 break; 239 break;
252 } 240 }
253 spin_unlock(&p->lock); 241 spin_unlock(&ipt->tcf_lock);
254 return result; 242 return result;
255 243
256} 244}
257 245
258static int 246static int tcf_ipt_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
259tcf_ipt_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
260{ 247{
248 unsigned char *b = skb->tail;
249 struct tcf_ipt *ipt = a->priv;
261 struct ipt_entry_target *t; 250 struct ipt_entry_target *t;
262 struct tcf_t tm; 251 struct tcf_t tm;
263 struct tc_cnt c; 252 struct tc_cnt c;
264 unsigned char *b = skb->tail;
265 struct tcf_ipt *p = PRIV(a, ipt);
266 253
267 /* for simple targets kernel size == user size 254 /* for simple targets kernel size == user size
268 ** user name = target name 255 ** user name = target name
269 ** for foolproof you need to not assume this 256 ** for foolproof you need to not assume this
270 */ 257 */
271 258
272 t = kmalloc(p->t->u.user.target_size, GFP_ATOMIC); 259 t = kmalloc(ipt->tcfi_t->u.user.target_size, GFP_ATOMIC);
273 if (t == NULL) 260 if (unlikely(!t))
274 goto rtattr_failure; 261 goto rtattr_failure;
275 262
276 c.bindcnt = p->bindcnt - bind; 263 c.bindcnt = ipt->tcf_bindcnt - bind;
277 c.refcnt = p->refcnt - ref; 264 c.refcnt = ipt->tcf_refcnt - ref;
278 memcpy(t, p->t, p->t->u.user.target_size); 265 memcpy(t, ipt->tcfi_t, ipt->tcfi_t->u.user.target_size);
279 strcpy(t->u.user.name, p->t->u.kernel.target->name); 266 strcpy(t->u.user.name, ipt->tcfi_t->u.kernel.target->name);
280 267
281 DPRINTK("\ttcf_ipt_dump tablename %s length %d\n", p->tname, 268 RTA_PUT(skb, TCA_IPT_TARG, ipt->tcfi_t->u.user.target_size, t);
282 strlen(p->tname)); 269 RTA_PUT(skb, TCA_IPT_INDEX, 4, &ipt->tcf_index);
283 DPRINTK("\tdump target name %s size %d size user %d " 270 RTA_PUT(skb, TCA_IPT_HOOK, 4, &ipt->tcfi_hook);
284 "data[0] %x data[1] %x\n", p->t->u.kernel.target->name,
285 p->t->u.target_size, p->t->u.user.target_size,
286 p->t->data[0], p->t->data[1]);
287 RTA_PUT(skb, TCA_IPT_TARG, p->t->u.user.target_size, t);
288 RTA_PUT(skb, TCA_IPT_INDEX, 4, &p->index);
289 RTA_PUT(skb, TCA_IPT_HOOK, 4, &p->hook);
290 RTA_PUT(skb, TCA_IPT_CNT, sizeof(struct tc_cnt), &c); 271 RTA_PUT(skb, TCA_IPT_CNT, sizeof(struct tc_cnt), &c);
291 RTA_PUT(skb, TCA_IPT_TABLE, IFNAMSIZ, p->tname); 272 RTA_PUT(skb, TCA_IPT_TABLE, IFNAMSIZ, ipt->tcfi_tname);
292 tm.install = jiffies_to_clock_t(jiffies - p->tm.install); 273 tm.install = jiffies_to_clock_t(jiffies - ipt->tcf_tm.install);
293 tm.lastuse = jiffies_to_clock_t(jiffies - p->tm.lastuse); 274 tm.lastuse = jiffies_to_clock_t(jiffies - ipt->tcf_tm.lastuse);
294 tm.expires = jiffies_to_clock_t(p->tm.expires); 275 tm.expires = jiffies_to_clock_t(ipt->tcf_tm.expires);
295 RTA_PUT(skb, TCA_IPT_TM, sizeof (tm), &tm); 276 RTA_PUT(skb, TCA_IPT_TM, sizeof (tm), &tm);
296 kfree(t); 277 kfree(t);
297 return skb->len; 278 return skb->len;
298 279
299 rtattr_failure: 280rtattr_failure:
300 skb_trim(skb, b - skb->data); 281 skb_trim(skb, b - skb->data);
301 kfree(t); 282 kfree(t);
302 return -1; 283 return -1;
@@ -304,6 +285,7 @@ tcf_ipt_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
304 285
305static struct tc_action_ops act_ipt_ops = { 286static struct tc_action_ops act_ipt_ops = {
306 .kind = "ipt", 287 .kind = "ipt",
288 .hinfo = &ipt_hash_info,
307 .type = TCA_ACT_IPT, 289 .type = TCA_ACT_IPT,
308 .capab = TCA_CAP_NONE, 290 .capab = TCA_CAP_NONE,
309 .owner = THIS_MODULE, 291 .owner = THIS_MODULE,
@@ -319,14 +301,12 @@ MODULE_AUTHOR("Jamal Hadi Salim(2002-4)");
319MODULE_DESCRIPTION("Iptables target actions"); 301MODULE_DESCRIPTION("Iptables target actions");
320MODULE_LICENSE("GPL"); 302MODULE_LICENSE("GPL");
321 303
322static int __init 304static int __init ipt_init_module(void)
323ipt_init_module(void)
324{ 305{
325 return tcf_register_action(&act_ipt_ops); 306 return tcf_register_action(&act_ipt_ops);
326} 307}
327 308
328static void __exit 309static void __exit ipt_cleanup_module(void)
329ipt_cleanup_module(void)
330{ 310{
331 tcf_unregister_action(&act_ipt_ops); 311 tcf_unregister_action(&act_ipt_ops);
332} 312}