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