Commit 651a6493ae5c055c78777bb7178c23b5565631da

Authored by Jamal Hadi Salim
Committed by David S. Miller
1 parent 382ca8a1ad

net_sched: Use default action walker methods

Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 8 changed files with 0 additions and 9 deletions Inline Diff

net/sched/act_csum.c
1 /* 1 /*
2 * Checksum updating actions 2 * Checksum updating actions
3 * 3 *
4 * Copyright (c) 2010 Gregoire Baron <baronchon@n7mm.org> 4 * Copyright (c) 2010 Gregoire Baron <baronchon@n7mm.org>
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify it 6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free 7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option) 8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version. 9 * any later version.
10 * 10 *
11 */ 11 */
12 12
13 #include <linux/types.h> 13 #include <linux/types.h>
14 #include <linux/init.h> 14 #include <linux/init.h>
15 #include <linux/kernel.h> 15 #include <linux/kernel.h>
16 #include <linux/module.h> 16 #include <linux/module.h>
17 #include <linux/spinlock.h> 17 #include <linux/spinlock.h>
18 18
19 #include <linux/netlink.h> 19 #include <linux/netlink.h>
20 #include <net/netlink.h> 20 #include <net/netlink.h>
21 #include <linux/rtnetlink.h> 21 #include <linux/rtnetlink.h>
22 22
23 #include <linux/skbuff.h> 23 #include <linux/skbuff.h>
24 24
25 #include <net/ip.h> 25 #include <net/ip.h>
26 #include <net/ipv6.h> 26 #include <net/ipv6.h>
27 #include <net/icmp.h> 27 #include <net/icmp.h>
28 #include <linux/icmpv6.h> 28 #include <linux/icmpv6.h>
29 #include <linux/igmp.h> 29 #include <linux/igmp.h>
30 #include <net/tcp.h> 30 #include <net/tcp.h>
31 #include <net/udp.h> 31 #include <net/udp.h>
32 #include <net/ip6_checksum.h> 32 #include <net/ip6_checksum.h>
33 33
34 #include <net/act_api.h> 34 #include <net/act_api.h>
35 35
36 #include <linux/tc_act/tc_csum.h> 36 #include <linux/tc_act/tc_csum.h>
37 #include <net/tc_act/tc_csum.h> 37 #include <net/tc_act/tc_csum.h>
38 38
39 #define CSUM_TAB_MASK 15 39 #define CSUM_TAB_MASK 15
40 static struct tcf_common *tcf_csum_ht[CSUM_TAB_MASK + 1]; 40 static struct tcf_common *tcf_csum_ht[CSUM_TAB_MASK + 1];
41 static u32 csum_idx_gen; 41 static u32 csum_idx_gen;
42 static DEFINE_RWLOCK(csum_lock); 42 static DEFINE_RWLOCK(csum_lock);
43 43
44 static struct tcf_hashinfo csum_hash_info = { 44 static struct tcf_hashinfo csum_hash_info = {
45 .htab = tcf_csum_ht, 45 .htab = tcf_csum_ht,
46 .hmask = CSUM_TAB_MASK, 46 .hmask = CSUM_TAB_MASK,
47 .lock = &csum_lock, 47 .lock = &csum_lock,
48 }; 48 };
49 49
50 static const struct nla_policy csum_policy[TCA_CSUM_MAX + 1] = { 50 static const struct nla_policy csum_policy[TCA_CSUM_MAX + 1] = {
51 [TCA_CSUM_PARMS] = { .len = sizeof(struct tc_csum), }, 51 [TCA_CSUM_PARMS] = { .len = sizeof(struct tc_csum), },
52 }; 52 };
53 53
54 static int tcf_csum_init(struct net *n, struct nlattr *nla, struct nlattr *est, 54 static int tcf_csum_init(struct net *n, struct nlattr *nla, struct nlattr *est,
55 struct tc_action *a, int ovr, int bind) 55 struct tc_action *a, int ovr, int bind)
56 { 56 {
57 struct nlattr *tb[TCA_CSUM_MAX + 1]; 57 struct nlattr *tb[TCA_CSUM_MAX + 1];
58 struct tc_csum *parm; 58 struct tc_csum *parm;
59 struct tcf_common *pc; 59 struct tcf_common *pc;
60 struct tcf_csum *p; 60 struct tcf_csum *p;
61 int ret = 0, err; 61 int ret = 0, err;
62 62
63 if (nla == NULL) 63 if (nla == NULL)
64 return -EINVAL; 64 return -EINVAL;
65 65
66 err = nla_parse_nested(tb, TCA_CSUM_MAX, nla, csum_policy); 66 err = nla_parse_nested(tb, TCA_CSUM_MAX, nla, csum_policy);
67 if (err < 0) 67 if (err < 0)
68 return err; 68 return err;
69 69
70 if (tb[TCA_CSUM_PARMS] == NULL) 70 if (tb[TCA_CSUM_PARMS] == NULL)
71 return -EINVAL; 71 return -EINVAL;
72 parm = nla_data(tb[TCA_CSUM_PARMS]); 72 parm = nla_data(tb[TCA_CSUM_PARMS]);
73 73
74 pc = tcf_hash_check(parm->index, a, bind, &csum_hash_info); 74 pc = tcf_hash_check(parm->index, a, bind, &csum_hash_info);
75 if (!pc) { 75 if (!pc) {
76 pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind, 76 pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind,
77 &csum_idx_gen, &csum_hash_info); 77 &csum_idx_gen, &csum_hash_info);
78 if (IS_ERR(pc)) 78 if (IS_ERR(pc))
79 return PTR_ERR(pc); 79 return PTR_ERR(pc);
80 p = to_tcf_csum(pc); 80 p = to_tcf_csum(pc);
81 ret = ACT_P_CREATED; 81 ret = ACT_P_CREATED;
82 } else { 82 } else {
83 p = to_tcf_csum(pc); 83 p = to_tcf_csum(pc);
84 if (!ovr) { 84 if (!ovr) {
85 tcf_hash_release(pc, bind, &csum_hash_info); 85 tcf_hash_release(pc, bind, &csum_hash_info);
86 return -EEXIST; 86 return -EEXIST;
87 } 87 }
88 } 88 }
89 89
90 spin_lock_bh(&p->tcf_lock); 90 spin_lock_bh(&p->tcf_lock);
91 p->tcf_action = parm->action; 91 p->tcf_action = parm->action;
92 p->update_flags = parm->update_flags; 92 p->update_flags = parm->update_flags;
93 spin_unlock_bh(&p->tcf_lock); 93 spin_unlock_bh(&p->tcf_lock);
94 94
95 if (ret == ACT_P_CREATED) 95 if (ret == ACT_P_CREATED)
96 tcf_hash_insert(pc, &csum_hash_info); 96 tcf_hash_insert(pc, &csum_hash_info);
97 97
98 return ret; 98 return ret;
99 } 99 }
100 100
101 static int tcf_csum_cleanup(struct tc_action *a, int bind) 101 static int tcf_csum_cleanup(struct tc_action *a, int bind)
102 { 102 {
103 struct tcf_csum *p = a->priv; 103 struct tcf_csum *p = a->priv;
104 return tcf_hash_release(&p->common, bind, &csum_hash_info); 104 return tcf_hash_release(&p->common, bind, &csum_hash_info);
105 } 105 }
106 106
107 /** 107 /**
108 * tcf_csum_skb_nextlayer - Get next layer pointer 108 * tcf_csum_skb_nextlayer - Get next layer pointer
109 * @skb: sk_buff to use 109 * @skb: sk_buff to use
110 * @ihl: previous summed headers length 110 * @ihl: previous summed headers length
111 * @ipl: complete packet length 111 * @ipl: complete packet length
112 * @jhl: next header length 112 * @jhl: next header length
113 * 113 *
114 * Check the expected next layer availability in the specified sk_buff. 114 * Check the expected next layer availability in the specified sk_buff.
115 * Return the next layer pointer if pass, NULL otherwise. 115 * Return the next layer pointer if pass, NULL otherwise.
116 */ 116 */
117 static void *tcf_csum_skb_nextlayer(struct sk_buff *skb, 117 static void *tcf_csum_skb_nextlayer(struct sk_buff *skb,
118 unsigned int ihl, unsigned int ipl, 118 unsigned int ihl, unsigned int ipl,
119 unsigned int jhl) 119 unsigned int jhl)
120 { 120 {
121 int ntkoff = skb_network_offset(skb); 121 int ntkoff = skb_network_offset(skb);
122 int hl = ihl + jhl; 122 int hl = ihl + jhl;
123 123
124 if (!pskb_may_pull(skb, ipl + ntkoff) || (ipl < hl) || 124 if (!pskb_may_pull(skb, ipl + ntkoff) || (ipl < hl) ||
125 (skb_cloned(skb) && 125 (skb_cloned(skb) &&
126 !skb_clone_writable(skb, hl + ntkoff) && 126 !skb_clone_writable(skb, hl + ntkoff) &&
127 pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) 127 pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
128 return NULL; 128 return NULL;
129 else 129 else
130 return (void *)(skb_network_header(skb) + ihl); 130 return (void *)(skb_network_header(skb) + ihl);
131 } 131 }
132 132
133 static int tcf_csum_ipv4_icmp(struct sk_buff *skb, 133 static int tcf_csum_ipv4_icmp(struct sk_buff *skb,
134 unsigned int ihl, unsigned int ipl) 134 unsigned int ihl, unsigned int ipl)
135 { 135 {
136 struct icmphdr *icmph; 136 struct icmphdr *icmph;
137 137
138 icmph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*icmph)); 138 icmph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*icmph));
139 if (icmph == NULL) 139 if (icmph == NULL)
140 return 0; 140 return 0;
141 141
142 icmph->checksum = 0; 142 icmph->checksum = 0;
143 skb->csum = csum_partial(icmph, ipl - ihl, 0); 143 skb->csum = csum_partial(icmph, ipl - ihl, 0);
144 icmph->checksum = csum_fold(skb->csum); 144 icmph->checksum = csum_fold(skb->csum);
145 145
146 skb->ip_summed = CHECKSUM_NONE; 146 skb->ip_summed = CHECKSUM_NONE;
147 147
148 return 1; 148 return 1;
149 } 149 }
150 150
151 static int tcf_csum_ipv4_igmp(struct sk_buff *skb, 151 static int tcf_csum_ipv4_igmp(struct sk_buff *skb,
152 unsigned int ihl, unsigned int ipl) 152 unsigned int ihl, unsigned int ipl)
153 { 153 {
154 struct igmphdr *igmph; 154 struct igmphdr *igmph;
155 155
156 igmph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*igmph)); 156 igmph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*igmph));
157 if (igmph == NULL) 157 if (igmph == NULL)
158 return 0; 158 return 0;
159 159
160 igmph->csum = 0; 160 igmph->csum = 0;
161 skb->csum = csum_partial(igmph, ipl - ihl, 0); 161 skb->csum = csum_partial(igmph, ipl - ihl, 0);
162 igmph->csum = csum_fold(skb->csum); 162 igmph->csum = csum_fold(skb->csum);
163 163
164 skb->ip_summed = CHECKSUM_NONE; 164 skb->ip_summed = CHECKSUM_NONE;
165 165
166 return 1; 166 return 1;
167 } 167 }
168 168
169 static int tcf_csum_ipv6_icmp(struct sk_buff *skb, 169 static int tcf_csum_ipv6_icmp(struct sk_buff *skb,
170 unsigned int ihl, unsigned int ipl) 170 unsigned int ihl, unsigned int ipl)
171 { 171 {
172 struct icmp6hdr *icmp6h; 172 struct icmp6hdr *icmp6h;
173 const struct ipv6hdr *ip6h; 173 const struct ipv6hdr *ip6h;
174 174
175 icmp6h = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*icmp6h)); 175 icmp6h = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*icmp6h));
176 if (icmp6h == NULL) 176 if (icmp6h == NULL)
177 return 0; 177 return 0;
178 178
179 ip6h = ipv6_hdr(skb); 179 ip6h = ipv6_hdr(skb);
180 icmp6h->icmp6_cksum = 0; 180 icmp6h->icmp6_cksum = 0;
181 skb->csum = csum_partial(icmp6h, ipl - ihl, 0); 181 skb->csum = csum_partial(icmp6h, ipl - ihl, 0);
182 icmp6h->icmp6_cksum = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, 182 icmp6h->icmp6_cksum = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
183 ipl - ihl, IPPROTO_ICMPV6, 183 ipl - ihl, IPPROTO_ICMPV6,
184 skb->csum); 184 skb->csum);
185 185
186 skb->ip_summed = CHECKSUM_NONE; 186 skb->ip_summed = CHECKSUM_NONE;
187 187
188 return 1; 188 return 1;
189 } 189 }
190 190
191 static int tcf_csum_ipv4_tcp(struct sk_buff *skb, 191 static int tcf_csum_ipv4_tcp(struct sk_buff *skb,
192 unsigned int ihl, unsigned int ipl) 192 unsigned int ihl, unsigned int ipl)
193 { 193 {
194 struct tcphdr *tcph; 194 struct tcphdr *tcph;
195 const struct iphdr *iph; 195 const struct iphdr *iph;
196 196
197 tcph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*tcph)); 197 tcph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*tcph));
198 if (tcph == NULL) 198 if (tcph == NULL)
199 return 0; 199 return 0;
200 200
201 iph = ip_hdr(skb); 201 iph = ip_hdr(skb);
202 tcph->check = 0; 202 tcph->check = 0;
203 skb->csum = csum_partial(tcph, ipl - ihl, 0); 203 skb->csum = csum_partial(tcph, ipl - ihl, 0);
204 tcph->check = tcp_v4_check(ipl - ihl, 204 tcph->check = tcp_v4_check(ipl - ihl,
205 iph->saddr, iph->daddr, skb->csum); 205 iph->saddr, iph->daddr, skb->csum);
206 206
207 skb->ip_summed = CHECKSUM_NONE; 207 skb->ip_summed = CHECKSUM_NONE;
208 208
209 return 1; 209 return 1;
210 } 210 }
211 211
212 static int tcf_csum_ipv6_tcp(struct sk_buff *skb, 212 static int tcf_csum_ipv6_tcp(struct sk_buff *skb,
213 unsigned int ihl, unsigned int ipl) 213 unsigned int ihl, unsigned int ipl)
214 { 214 {
215 struct tcphdr *tcph; 215 struct tcphdr *tcph;
216 const struct ipv6hdr *ip6h; 216 const struct ipv6hdr *ip6h;
217 217
218 tcph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*tcph)); 218 tcph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*tcph));
219 if (tcph == NULL) 219 if (tcph == NULL)
220 return 0; 220 return 0;
221 221
222 ip6h = ipv6_hdr(skb); 222 ip6h = ipv6_hdr(skb);
223 tcph->check = 0; 223 tcph->check = 0;
224 skb->csum = csum_partial(tcph, ipl - ihl, 0); 224 skb->csum = csum_partial(tcph, ipl - ihl, 0);
225 tcph->check = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, 225 tcph->check = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
226 ipl - ihl, IPPROTO_TCP, 226 ipl - ihl, IPPROTO_TCP,
227 skb->csum); 227 skb->csum);
228 228
229 skb->ip_summed = CHECKSUM_NONE; 229 skb->ip_summed = CHECKSUM_NONE;
230 230
231 return 1; 231 return 1;
232 } 232 }
233 233
234 static int tcf_csum_ipv4_udp(struct sk_buff *skb, 234 static int tcf_csum_ipv4_udp(struct sk_buff *skb,
235 unsigned int ihl, unsigned int ipl, int udplite) 235 unsigned int ihl, unsigned int ipl, int udplite)
236 { 236 {
237 struct udphdr *udph; 237 struct udphdr *udph;
238 const struct iphdr *iph; 238 const struct iphdr *iph;
239 u16 ul; 239 u16 ul;
240 240
241 /* 241 /*
242 * Support both UDP and UDPLITE checksum algorithms, Don't use 242 * Support both UDP and UDPLITE checksum algorithms, Don't use
243 * udph->len to get the real length without any protocol check, 243 * udph->len to get the real length without any protocol check,
244 * UDPLITE uses udph->len for another thing, 244 * UDPLITE uses udph->len for another thing,
245 * Use iph->tot_len, or just ipl. 245 * Use iph->tot_len, or just ipl.
246 */ 246 */
247 247
248 udph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*udph)); 248 udph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*udph));
249 if (udph == NULL) 249 if (udph == NULL)
250 return 0; 250 return 0;
251 251
252 iph = ip_hdr(skb); 252 iph = ip_hdr(skb);
253 ul = ntohs(udph->len); 253 ul = ntohs(udph->len);
254 254
255 if (udplite || udph->check) { 255 if (udplite || udph->check) {
256 256
257 udph->check = 0; 257 udph->check = 0;
258 258
259 if (udplite) { 259 if (udplite) {
260 if (ul == 0) 260 if (ul == 0)
261 skb->csum = csum_partial(udph, ipl - ihl, 0); 261 skb->csum = csum_partial(udph, ipl - ihl, 0);
262 else if ((ul >= sizeof(*udph)) && (ul <= ipl - ihl)) 262 else if ((ul >= sizeof(*udph)) && (ul <= ipl - ihl))
263 skb->csum = csum_partial(udph, ul, 0); 263 skb->csum = csum_partial(udph, ul, 0);
264 else 264 else
265 goto ignore_obscure_skb; 265 goto ignore_obscure_skb;
266 } else { 266 } else {
267 if (ul != ipl - ihl) 267 if (ul != ipl - ihl)
268 goto ignore_obscure_skb; 268 goto ignore_obscure_skb;
269 269
270 skb->csum = csum_partial(udph, ul, 0); 270 skb->csum = csum_partial(udph, ul, 0);
271 } 271 }
272 272
273 udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, 273 udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
274 ul, iph->protocol, 274 ul, iph->protocol,
275 skb->csum); 275 skb->csum);
276 276
277 if (!udph->check) 277 if (!udph->check)
278 udph->check = CSUM_MANGLED_0; 278 udph->check = CSUM_MANGLED_0;
279 } 279 }
280 280
281 skb->ip_summed = CHECKSUM_NONE; 281 skb->ip_summed = CHECKSUM_NONE;
282 282
283 ignore_obscure_skb: 283 ignore_obscure_skb:
284 return 1; 284 return 1;
285 } 285 }
286 286
287 static int tcf_csum_ipv6_udp(struct sk_buff *skb, 287 static int tcf_csum_ipv6_udp(struct sk_buff *skb,
288 unsigned int ihl, unsigned int ipl, int udplite) 288 unsigned int ihl, unsigned int ipl, int udplite)
289 { 289 {
290 struct udphdr *udph; 290 struct udphdr *udph;
291 const struct ipv6hdr *ip6h; 291 const struct ipv6hdr *ip6h;
292 u16 ul; 292 u16 ul;
293 293
294 /* 294 /*
295 * Support both UDP and UDPLITE checksum algorithms, Don't use 295 * Support both UDP and UDPLITE checksum algorithms, Don't use
296 * udph->len to get the real length without any protocol check, 296 * udph->len to get the real length without any protocol check,
297 * UDPLITE uses udph->len for another thing, 297 * UDPLITE uses udph->len for another thing,
298 * Use ip6h->payload_len + sizeof(*ip6h) ... , or just ipl. 298 * Use ip6h->payload_len + sizeof(*ip6h) ... , or just ipl.
299 */ 299 */
300 300
301 udph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*udph)); 301 udph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*udph));
302 if (udph == NULL) 302 if (udph == NULL)
303 return 0; 303 return 0;
304 304
305 ip6h = ipv6_hdr(skb); 305 ip6h = ipv6_hdr(skb);
306 ul = ntohs(udph->len); 306 ul = ntohs(udph->len);
307 307
308 udph->check = 0; 308 udph->check = 0;
309 309
310 if (udplite) { 310 if (udplite) {
311 if (ul == 0) 311 if (ul == 0)
312 skb->csum = csum_partial(udph, ipl - ihl, 0); 312 skb->csum = csum_partial(udph, ipl - ihl, 0);
313 313
314 else if ((ul >= sizeof(*udph)) && (ul <= ipl - ihl)) 314 else if ((ul >= sizeof(*udph)) && (ul <= ipl - ihl))
315 skb->csum = csum_partial(udph, ul, 0); 315 skb->csum = csum_partial(udph, ul, 0);
316 316
317 else 317 else
318 goto ignore_obscure_skb; 318 goto ignore_obscure_skb;
319 } else { 319 } else {
320 if (ul != ipl - ihl) 320 if (ul != ipl - ihl)
321 goto ignore_obscure_skb; 321 goto ignore_obscure_skb;
322 322
323 skb->csum = csum_partial(udph, ul, 0); 323 skb->csum = csum_partial(udph, ul, 0);
324 } 324 }
325 325
326 udph->check = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, ul, 326 udph->check = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, ul,
327 udplite ? IPPROTO_UDPLITE : IPPROTO_UDP, 327 udplite ? IPPROTO_UDPLITE : IPPROTO_UDP,
328 skb->csum); 328 skb->csum);
329 329
330 if (!udph->check) 330 if (!udph->check)
331 udph->check = CSUM_MANGLED_0; 331 udph->check = CSUM_MANGLED_0;
332 332
333 skb->ip_summed = CHECKSUM_NONE; 333 skb->ip_summed = CHECKSUM_NONE;
334 334
335 ignore_obscure_skb: 335 ignore_obscure_skb:
336 return 1; 336 return 1;
337 } 337 }
338 338
339 static int tcf_csum_ipv4(struct sk_buff *skb, u32 update_flags) 339 static int tcf_csum_ipv4(struct sk_buff *skb, u32 update_flags)
340 { 340 {
341 const struct iphdr *iph; 341 const struct iphdr *iph;
342 int ntkoff; 342 int ntkoff;
343 343
344 ntkoff = skb_network_offset(skb); 344 ntkoff = skb_network_offset(skb);
345 345
346 if (!pskb_may_pull(skb, sizeof(*iph) + ntkoff)) 346 if (!pskb_may_pull(skb, sizeof(*iph) + ntkoff))
347 goto fail; 347 goto fail;
348 348
349 iph = ip_hdr(skb); 349 iph = ip_hdr(skb);
350 350
351 switch (iph->frag_off & htons(IP_OFFSET) ? 0 : iph->protocol) { 351 switch (iph->frag_off & htons(IP_OFFSET) ? 0 : iph->protocol) {
352 case IPPROTO_ICMP: 352 case IPPROTO_ICMP:
353 if (update_flags & TCA_CSUM_UPDATE_FLAG_ICMP) 353 if (update_flags & TCA_CSUM_UPDATE_FLAG_ICMP)
354 if (!tcf_csum_ipv4_icmp(skb, iph->ihl * 4, 354 if (!tcf_csum_ipv4_icmp(skb, iph->ihl * 4,
355 ntohs(iph->tot_len))) 355 ntohs(iph->tot_len)))
356 goto fail; 356 goto fail;
357 break; 357 break;
358 case IPPROTO_IGMP: 358 case IPPROTO_IGMP:
359 if (update_flags & TCA_CSUM_UPDATE_FLAG_IGMP) 359 if (update_flags & TCA_CSUM_UPDATE_FLAG_IGMP)
360 if (!tcf_csum_ipv4_igmp(skb, iph->ihl * 4, 360 if (!tcf_csum_ipv4_igmp(skb, iph->ihl * 4,
361 ntohs(iph->tot_len))) 361 ntohs(iph->tot_len)))
362 goto fail; 362 goto fail;
363 break; 363 break;
364 case IPPROTO_TCP: 364 case IPPROTO_TCP:
365 if (update_flags & TCA_CSUM_UPDATE_FLAG_TCP) 365 if (update_flags & TCA_CSUM_UPDATE_FLAG_TCP)
366 if (!tcf_csum_ipv4_tcp(skb, iph->ihl * 4, 366 if (!tcf_csum_ipv4_tcp(skb, iph->ihl * 4,
367 ntohs(iph->tot_len))) 367 ntohs(iph->tot_len)))
368 goto fail; 368 goto fail;
369 break; 369 break;
370 case IPPROTO_UDP: 370 case IPPROTO_UDP:
371 if (update_flags & TCA_CSUM_UPDATE_FLAG_UDP) 371 if (update_flags & TCA_CSUM_UPDATE_FLAG_UDP)
372 if (!tcf_csum_ipv4_udp(skb, iph->ihl * 4, 372 if (!tcf_csum_ipv4_udp(skb, iph->ihl * 4,
373 ntohs(iph->tot_len), 0)) 373 ntohs(iph->tot_len), 0))
374 goto fail; 374 goto fail;
375 break; 375 break;
376 case IPPROTO_UDPLITE: 376 case IPPROTO_UDPLITE:
377 if (update_flags & TCA_CSUM_UPDATE_FLAG_UDPLITE) 377 if (update_flags & TCA_CSUM_UPDATE_FLAG_UDPLITE)
378 if (!tcf_csum_ipv4_udp(skb, iph->ihl * 4, 378 if (!tcf_csum_ipv4_udp(skb, iph->ihl * 4,
379 ntohs(iph->tot_len), 1)) 379 ntohs(iph->tot_len), 1))
380 goto fail; 380 goto fail;
381 break; 381 break;
382 } 382 }
383 383
384 if (update_flags & TCA_CSUM_UPDATE_FLAG_IPV4HDR) { 384 if (update_flags & TCA_CSUM_UPDATE_FLAG_IPV4HDR) {
385 if (skb_cloned(skb) && 385 if (skb_cloned(skb) &&
386 !skb_clone_writable(skb, sizeof(*iph) + ntkoff) && 386 !skb_clone_writable(skb, sizeof(*iph) + ntkoff) &&
387 pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) 387 pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
388 goto fail; 388 goto fail;
389 389
390 ip_send_check(ip_hdr(skb)); 390 ip_send_check(ip_hdr(skb));
391 } 391 }
392 392
393 return 1; 393 return 1;
394 394
395 fail: 395 fail:
396 return 0; 396 return 0;
397 } 397 }
398 398
399 static int tcf_csum_ipv6_hopopts(struct ipv6_opt_hdr *ip6xh, 399 static int tcf_csum_ipv6_hopopts(struct ipv6_opt_hdr *ip6xh,
400 unsigned int ixhl, unsigned int *pl) 400 unsigned int ixhl, unsigned int *pl)
401 { 401 {
402 int off, len, optlen; 402 int off, len, optlen;
403 unsigned char *xh = (void *)ip6xh; 403 unsigned char *xh = (void *)ip6xh;
404 404
405 off = sizeof(*ip6xh); 405 off = sizeof(*ip6xh);
406 len = ixhl - off; 406 len = ixhl - off;
407 407
408 while (len > 1) { 408 while (len > 1) {
409 switch (xh[off]) { 409 switch (xh[off]) {
410 case IPV6_TLV_PAD1: 410 case IPV6_TLV_PAD1:
411 optlen = 1; 411 optlen = 1;
412 break; 412 break;
413 case IPV6_TLV_JUMBO: 413 case IPV6_TLV_JUMBO:
414 optlen = xh[off + 1] + 2; 414 optlen = xh[off + 1] + 2;
415 if (optlen != 6 || len < 6 || (off & 3) != 2) 415 if (optlen != 6 || len < 6 || (off & 3) != 2)
416 /* wrong jumbo option length/alignment */ 416 /* wrong jumbo option length/alignment */
417 return 0; 417 return 0;
418 *pl = ntohl(*(__be32 *)(xh + off + 2)); 418 *pl = ntohl(*(__be32 *)(xh + off + 2));
419 goto done; 419 goto done;
420 default: 420 default:
421 optlen = xh[off + 1] + 2; 421 optlen = xh[off + 1] + 2;
422 if (optlen > len) 422 if (optlen > len)
423 /* ignore obscure options */ 423 /* ignore obscure options */
424 goto done; 424 goto done;
425 break; 425 break;
426 } 426 }
427 off += optlen; 427 off += optlen;
428 len -= optlen; 428 len -= optlen;
429 } 429 }
430 430
431 done: 431 done:
432 return 1; 432 return 1;
433 } 433 }
434 434
435 static int tcf_csum_ipv6(struct sk_buff *skb, u32 update_flags) 435 static int tcf_csum_ipv6(struct sk_buff *skb, u32 update_flags)
436 { 436 {
437 struct ipv6hdr *ip6h; 437 struct ipv6hdr *ip6h;
438 struct ipv6_opt_hdr *ip6xh; 438 struct ipv6_opt_hdr *ip6xh;
439 unsigned int hl, ixhl; 439 unsigned int hl, ixhl;
440 unsigned int pl; 440 unsigned int pl;
441 int ntkoff; 441 int ntkoff;
442 u8 nexthdr; 442 u8 nexthdr;
443 443
444 ntkoff = skb_network_offset(skb); 444 ntkoff = skb_network_offset(skb);
445 445
446 hl = sizeof(*ip6h); 446 hl = sizeof(*ip6h);
447 447
448 if (!pskb_may_pull(skb, hl + ntkoff)) 448 if (!pskb_may_pull(skb, hl + ntkoff))
449 goto fail; 449 goto fail;
450 450
451 ip6h = ipv6_hdr(skb); 451 ip6h = ipv6_hdr(skb);
452 452
453 pl = ntohs(ip6h->payload_len); 453 pl = ntohs(ip6h->payload_len);
454 nexthdr = ip6h->nexthdr; 454 nexthdr = ip6h->nexthdr;
455 455
456 do { 456 do {
457 switch (nexthdr) { 457 switch (nexthdr) {
458 case NEXTHDR_FRAGMENT: 458 case NEXTHDR_FRAGMENT:
459 goto ignore_skb; 459 goto ignore_skb;
460 case NEXTHDR_ROUTING: 460 case NEXTHDR_ROUTING:
461 case NEXTHDR_HOP: 461 case NEXTHDR_HOP:
462 case NEXTHDR_DEST: 462 case NEXTHDR_DEST:
463 if (!pskb_may_pull(skb, hl + sizeof(*ip6xh) + ntkoff)) 463 if (!pskb_may_pull(skb, hl + sizeof(*ip6xh) + ntkoff))
464 goto fail; 464 goto fail;
465 ip6xh = (void *)(skb_network_header(skb) + hl); 465 ip6xh = (void *)(skb_network_header(skb) + hl);
466 ixhl = ipv6_optlen(ip6xh); 466 ixhl = ipv6_optlen(ip6xh);
467 if (!pskb_may_pull(skb, hl + ixhl + ntkoff)) 467 if (!pskb_may_pull(skb, hl + ixhl + ntkoff))
468 goto fail; 468 goto fail;
469 ip6xh = (void *)(skb_network_header(skb) + hl); 469 ip6xh = (void *)(skb_network_header(skb) + hl);
470 if ((nexthdr == NEXTHDR_HOP) && 470 if ((nexthdr == NEXTHDR_HOP) &&
471 !(tcf_csum_ipv6_hopopts(ip6xh, ixhl, &pl))) 471 !(tcf_csum_ipv6_hopopts(ip6xh, ixhl, &pl)))
472 goto fail; 472 goto fail;
473 nexthdr = ip6xh->nexthdr; 473 nexthdr = ip6xh->nexthdr;
474 hl += ixhl; 474 hl += ixhl;
475 break; 475 break;
476 case IPPROTO_ICMPV6: 476 case IPPROTO_ICMPV6:
477 if (update_flags & TCA_CSUM_UPDATE_FLAG_ICMP) 477 if (update_flags & TCA_CSUM_UPDATE_FLAG_ICMP)
478 if (!tcf_csum_ipv6_icmp(skb, 478 if (!tcf_csum_ipv6_icmp(skb,
479 hl, pl + sizeof(*ip6h))) 479 hl, pl + sizeof(*ip6h)))
480 goto fail; 480 goto fail;
481 goto done; 481 goto done;
482 case IPPROTO_TCP: 482 case IPPROTO_TCP:
483 if (update_flags & TCA_CSUM_UPDATE_FLAG_TCP) 483 if (update_flags & TCA_CSUM_UPDATE_FLAG_TCP)
484 if (!tcf_csum_ipv6_tcp(skb, 484 if (!tcf_csum_ipv6_tcp(skb,
485 hl, pl + sizeof(*ip6h))) 485 hl, pl + sizeof(*ip6h)))
486 goto fail; 486 goto fail;
487 goto done; 487 goto done;
488 case IPPROTO_UDP: 488 case IPPROTO_UDP:
489 if (update_flags & TCA_CSUM_UPDATE_FLAG_UDP) 489 if (update_flags & TCA_CSUM_UPDATE_FLAG_UDP)
490 if (!tcf_csum_ipv6_udp(skb, hl, 490 if (!tcf_csum_ipv6_udp(skb, hl,
491 pl + sizeof(*ip6h), 0)) 491 pl + sizeof(*ip6h), 0))
492 goto fail; 492 goto fail;
493 goto done; 493 goto done;
494 case IPPROTO_UDPLITE: 494 case IPPROTO_UDPLITE:
495 if (update_flags & TCA_CSUM_UPDATE_FLAG_UDPLITE) 495 if (update_flags & TCA_CSUM_UPDATE_FLAG_UDPLITE)
496 if (!tcf_csum_ipv6_udp(skb, hl, 496 if (!tcf_csum_ipv6_udp(skb, hl,
497 pl + sizeof(*ip6h), 1)) 497 pl + sizeof(*ip6h), 1))
498 goto fail; 498 goto fail;
499 goto done; 499 goto done;
500 default: 500 default:
501 goto ignore_skb; 501 goto ignore_skb;
502 } 502 }
503 } while (pskb_may_pull(skb, hl + 1 + ntkoff)); 503 } while (pskb_may_pull(skb, hl + 1 + ntkoff));
504 504
505 done: 505 done:
506 ignore_skb: 506 ignore_skb:
507 return 1; 507 return 1;
508 508
509 fail: 509 fail:
510 return 0; 510 return 0;
511 } 511 }
512 512
513 static int tcf_csum(struct sk_buff *skb, 513 static int tcf_csum(struct sk_buff *skb,
514 const struct tc_action *a, struct tcf_result *res) 514 const struct tc_action *a, struct tcf_result *res)
515 { 515 {
516 struct tcf_csum *p = a->priv; 516 struct tcf_csum *p = a->priv;
517 int action; 517 int action;
518 u32 update_flags; 518 u32 update_flags;
519 519
520 spin_lock(&p->tcf_lock); 520 spin_lock(&p->tcf_lock);
521 p->tcf_tm.lastuse = jiffies; 521 p->tcf_tm.lastuse = jiffies;
522 bstats_update(&p->tcf_bstats, skb); 522 bstats_update(&p->tcf_bstats, skb);
523 action = p->tcf_action; 523 action = p->tcf_action;
524 update_flags = p->update_flags; 524 update_flags = p->update_flags;
525 spin_unlock(&p->tcf_lock); 525 spin_unlock(&p->tcf_lock);
526 526
527 if (unlikely(action == TC_ACT_SHOT)) 527 if (unlikely(action == TC_ACT_SHOT))
528 goto drop; 528 goto drop;
529 529
530 switch (skb->protocol) { 530 switch (skb->protocol) {
531 case cpu_to_be16(ETH_P_IP): 531 case cpu_to_be16(ETH_P_IP):
532 if (!tcf_csum_ipv4(skb, update_flags)) 532 if (!tcf_csum_ipv4(skb, update_flags))
533 goto drop; 533 goto drop;
534 break; 534 break;
535 case cpu_to_be16(ETH_P_IPV6): 535 case cpu_to_be16(ETH_P_IPV6):
536 if (!tcf_csum_ipv6(skb, update_flags)) 536 if (!tcf_csum_ipv6(skb, update_flags))
537 goto drop; 537 goto drop;
538 break; 538 break;
539 } 539 }
540 540
541 return action; 541 return action;
542 542
543 drop: 543 drop:
544 spin_lock(&p->tcf_lock); 544 spin_lock(&p->tcf_lock);
545 p->tcf_qstats.drops++; 545 p->tcf_qstats.drops++;
546 spin_unlock(&p->tcf_lock); 546 spin_unlock(&p->tcf_lock);
547 return TC_ACT_SHOT; 547 return TC_ACT_SHOT;
548 } 548 }
549 549
550 static int tcf_csum_dump(struct sk_buff *skb, 550 static int tcf_csum_dump(struct sk_buff *skb,
551 struct tc_action *a, int bind, int ref) 551 struct tc_action *a, int bind, int ref)
552 { 552 {
553 unsigned char *b = skb_tail_pointer(skb); 553 unsigned char *b = skb_tail_pointer(skb);
554 struct tcf_csum *p = a->priv; 554 struct tcf_csum *p = a->priv;
555 struct tc_csum opt = { 555 struct tc_csum opt = {
556 .update_flags = p->update_flags, 556 .update_flags = p->update_flags,
557 .index = p->tcf_index, 557 .index = p->tcf_index,
558 .action = p->tcf_action, 558 .action = p->tcf_action,
559 .refcnt = p->tcf_refcnt - ref, 559 .refcnt = p->tcf_refcnt - ref,
560 .bindcnt = p->tcf_bindcnt - bind, 560 .bindcnt = p->tcf_bindcnt - bind,
561 }; 561 };
562 struct tcf_t t; 562 struct tcf_t t;
563 563
564 if (nla_put(skb, TCA_CSUM_PARMS, sizeof(opt), &opt)) 564 if (nla_put(skb, TCA_CSUM_PARMS, sizeof(opt), &opt))
565 goto nla_put_failure; 565 goto nla_put_failure;
566 t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install); 566 t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install);
567 t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse); 567 t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse);
568 t.expires = jiffies_to_clock_t(p->tcf_tm.expires); 568 t.expires = jiffies_to_clock_t(p->tcf_tm.expires);
569 if (nla_put(skb, TCA_CSUM_TM, sizeof(t), &t)) 569 if (nla_put(skb, TCA_CSUM_TM, sizeof(t), &t))
570 goto nla_put_failure; 570 goto nla_put_failure;
571 571
572 return skb->len; 572 return skb->len;
573 573
574 nla_put_failure: 574 nla_put_failure:
575 nlmsg_trim(skb, b); 575 nlmsg_trim(skb, b);
576 return -1; 576 return -1;
577 } 577 }
578 578
579 static struct tc_action_ops act_csum_ops = { 579 static struct tc_action_ops act_csum_ops = {
580 .kind = "csum", 580 .kind = "csum",
581 .hinfo = &csum_hash_info, 581 .hinfo = &csum_hash_info,
582 .type = TCA_ACT_CSUM, 582 .type = TCA_ACT_CSUM,
583 .capab = TCA_CAP_NONE, 583 .capab = TCA_CAP_NONE,
584 .owner = THIS_MODULE, 584 .owner = THIS_MODULE,
585 .act = tcf_csum, 585 .act = tcf_csum,
586 .dump = tcf_csum_dump, 586 .dump = tcf_csum_dump,
587 .cleanup = tcf_csum_cleanup, 587 .cleanup = tcf_csum_cleanup,
588 .init = tcf_csum_init, 588 .init = tcf_csum_init,
589 .walk = tcf_generic_walker
590 }; 589 };
591 590
592 MODULE_DESCRIPTION("Checksum updating actions"); 591 MODULE_DESCRIPTION("Checksum updating actions");
593 MODULE_LICENSE("GPL"); 592 MODULE_LICENSE("GPL");
594 593
595 static int __init csum_init_module(void) 594 static int __init csum_init_module(void)
596 { 595 {
597 return tcf_register_action(&act_csum_ops); 596 return tcf_register_action(&act_csum_ops);
598 } 597 }
599 598
600 static void __exit csum_cleanup_module(void) 599 static void __exit csum_cleanup_module(void)
601 { 600 {
602 tcf_unregister_action(&act_csum_ops); 601 tcf_unregister_action(&act_csum_ops);
603 } 602 }
604 603
605 module_init(csum_init_module); 604 module_init(csum_init_module);
606 module_exit(csum_cleanup_module); 605 module_exit(csum_cleanup_module);
607 606
net/sched/act_gact.c
1 /* 1 /*
2 * net/sched/gact.c Generic actions 2 * net/sched/gact.c Generic actions
3 * 3 *
4 * This program is free software; you can redistribute it and/or 4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License 5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version. 7 * 2 of the License, or (at your option) any later version.
8 * 8 *
9 * copyright Jamal Hadi Salim (2002-4) 9 * copyright Jamal Hadi Salim (2002-4)
10 * 10 *
11 */ 11 */
12 12
13 #include <linux/types.h> 13 #include <linux/types.h>
14 #include <linux/kernel.h> 14 #include <linux/kernel.h>
15 #include <linux/string.h> 15 #include <linux/string.h>
16 #include <linux/errno.h> 16 #include <linux/errno.h>
17 #include <linux/skbuff.h> 17 #include <linux/skbuff.h>
18 #include <linux/rtnetlink.h> 18 #include <linux/rtnetlink.h>
19 #include <linux/module.h> 19 #include <linux/module.h>
20 #include <linux/init.h> 20 #include <linux/init.h>
21 #include <net/netlink.h> 21 #include <net/netlink.h>
22 #include <net/pkt_sched.h> 22 #include <net/pkt_sched.h>
23 #include <linux/tc_act/tc_gact.h> 23 #include <linux/tc_act/tc_gact.h>
24 #include <net/tc_act/tc_gact.h> 24 #include <net/tc_act/tc_gact.h>
25 25
26 #define GACT_TAB_MASK 15 26 #define GACT_TAB_MASK 15
27 static struct tcf_common *tcf_gact_ht[GACT_TAB_MASK + 1]; 27 static struct tcf_common *tcf_gact_ht[GACT_TAB_MASK + 1];
28 static u32 gact_idx_gen; 28 static u32 gact_idx_gen;
29 static DEFINE_RWLOCK(gact_lock); 29 static DEFINE_RWLOCK(gact_lock);
30 30
31 static struct tcf_hashinfo gact_hash_info = { 31 static struct tcf_hashinfo gact_hash_info = {
32 .htab = tcf_gact_ht, 32 .htab = tcf_gact_ht,
33 .hmask = GACT_TAB_MASK, 33 .hmask = GACT_TAB_MASK,
34 .lock = &gact_lock, 34 .lock = &gact_lock,
35 }; 35 };
36 36
37 #ifdef CONFIG_GACT_PROB 37 #ifdef CONFIG_GACT_PROB
38 static int gact_net_rand(struct tcf_gact *gact) 38 static int gact_net_rand(struct tcf_gact *gact)
39 { 39 {
40 if (!gact->tcfg_pval || net_random() % gact->tcfg_pval) 40 if (!gact->tcfg_pval || net_random() % gact->tcfg_pval)
41 return gact->tcf_action; 41 return gact->tcf_action;
42 return gact->tcfg_paction; 42 return gact->tcfg_paction;
43 } 43 }
44 44
45 static int gact_determ(struct tcf_gact *gact) 45 static int gact_determ(struct tcf_gact *gact)
46 { 46 {
47 if (!gact->tcfg_pval || gact->tcf_bstats.packets % gact->tcfg_pval) 47 if (!gact->tcfg_pval || gact->tcf_bstats.packets % gact->tcfg_pval)
48 return gact->tcf_action; 48 return gact->tcf_action;
49 return gact->tcfg_paction; 49 return gact->tcfg_paction;
50 } 50 }
51 51
52 typedef int (*g_rand)(struct tcf_gact *gact); 52 typedef int (*g_rand)(struct tcf_gact *gact);
53 static g_rand gact_rand[MAX_RAND] = { NULL, gact_net_rand, gact_determ }; 53 static g_rand gact_rand[MAX_RAND] = { NULL, gact_net_rand, gact_determ };
54 #endif /* CONFIG_GACT_PROB */ 54 #endif /* CONFIG_GACT_PROB */
55 55
56 static const struct nla_policy gact_policy[TCA_GACT_MAX + 1] = { 56 static const struct nla_policy gact_policy[TCA_GACT_MAX + 1] = {
57 [TCA_GACT_PARMS] = { .len = sizeof(struct tc_gact) }, 57 [TCA_GACT_PARMS] = { .len = sizeof(struct tc_gact) },
58 [TCA_GACT_PROB] = { .len = sizeof(struct tc_gact_p) }, 58 [TCA_GACT_PROB] = { .len = sizeof(struct tc_gact_p) },
59 }; 59 };
60 60
61 static int tcf_gact_init(struct net *net, struct nlattr *nla, 61 static int tcf_gact_init(struct net *net, struct nlattr *nla,
62 struct nlattr *est, struct tc_action *a, 62 struct nlattr *est, struct tc_action *a,
63 int ovr, int bind) 63 int ovr, int bind)
64 { 64 {
65 struct nlattr *tb[TCA_GACT_MAX + 1]; 65 struct nlattr *tb[TCA_GACT_MAX + 1];
66 struct tc_gact *parm; 66 struct tc_gact *parm;
67 struct tcf_gact *gact; 67 struct tcf_gact *gact;
68 struct tcf_common *pc; 68 struct tcf_common *pc;
69 int ret = 0; 69 int ret = 0;
70 int err; 70 int err;
71 #ifdef CONFIG_GACT_PROB 71 #ifdef CONFIG_GACT_PROB
72 struct tc_gact_p *p_parm = NULL; 72 struct tc_gact_p *p_parm = NULL;
73 #endif 73 #endif
74 74
75 if (nla == NULL) 75 if (nla == NULL)
76 return -EINVAL; 76 return -EINVAL;
77 77
78 err = nla_parse_nested(tb, TCA_GACT_MAX, nla, gact_policy); 78 err = nla_parse_nested(tb, TCA_GACT_MAX, nla, gact_policy);
79 if (err < 0) 79 if (err < 0)
80 return err; 80 return err;
81 81
82 if (tb[TCA_GACT_PARMS] == NULL) 82 if (tb[TCA_GACT_PARMS] == NULL)
83 return -EINVAL; 83 return -EINVAL;
84 parm = nla_data(tb[TCA_GACT_PARMS]); 84 parm = nla_data(tb[TCA_GACT_PARMS]);
85 85
86 #ifndef CONFIG_GACT_PROB 86 #ifndef CONFIG_GACT_PROB
87 if (tb[TCA_GACT_PROB] != NULL) 87 if (tb[TCA_GACT_PROB] != NULL)
88 return -EOPNOTSUPP; 88 return -EOPNOTSUPP;
89 #else 89 #else
90 if (tb[TCA_GACT_PROB]) { 90 if (tb[TCA_GACT_PROB]) {
91 p_parm = nla_data(tb[TCA_GACT_PROB]); 91 p_parm = nla_data(tb[TCA_GACT_PROB]);
92 if (p_parm->ptype >= MAX_RAND) 92 if (p_parm->ptype >= MAX_RAND)
93 return -EINVAL; 93 return -EINVAL;
94 } 94 }
95 #endif 95 #endif
96 96
97 pc = tcf_hash_check(parm->index, a, bind, &gact_hash_info); 97 pc = tcf_hash_check(parm->index, a, bind, &gact_hash_info);
98 if (!pc) { 98 if (!pc) {
99 pc = tcf_hash_create(parm->index, est, a, sizeof(*gact), 99 pc = tcf_hash_create(parm->index, est, a, sizeof(*gact),
100 bind, &gact_idx_gen, &gact_hash_info); 100 bind, &gact_idx_gen, &gact_hash_info);
101 if (IS_ERR(pc)) 101 if (IS_ERR(pc))
102 return PTR_ERR(pc); 102 return PTR_ERR(pc);
103 ret = ACT_P_CREATED; 103 ret = ACT_P_CREATED;
104 } else { 104 } else {
105 if (!ovr) { 105 if (!ovr) {
106 tcf_hash_release(pc, bind, &gact_hash_info); 106 tcf_hash_release(pc, bind, &gact_hash_info);
107 return -EEXIST; 107 return -EEXIST;
108 } 108 }
109 } 109 }
110 110
111 gact = to_gact(pc); 111 gact = to_gact(pc);
112 112
113 spin_lock_bh(&gact->tcf_lock); 113 spin_lock_bh(&gact->tcf_lock);
114 gact->tcf_action = parm->action; 114 gact->tcf_action = parm->action;
115 #ifdef CONFIG_GACT_PROB 115 #ifdef CONFIG_GACT_PROB
116 if (p_parm) { 116 if (p_parm) {
117 gact->tcfg_paction = p_parm->paction; 117 gact->tcfg_paction = p_parm->paction;
118 gact->tcfg_pval = p_parm->pval; 118 gact->tcfg_pval = p_parm->pval;
119 gact->tcfg_ptype = p_parm->ptype; 119 gact->tcfg_ptype = p_parm->ptype;
120 } 120 }
121 #endif 121 #endif
122 spin_unlock_bh(&gact->tcf_lock); 122 spin_unlock_bh(&gact->tcf_lock);
123 if (ret == ACT_P_CREATED) 123 if (ret == ACT_P_CREATED)
124 tcf_hash_insert(pc, &gact_hash_info); 124 tcf_hash_insert(pc, &gact_hash_info);
125 return ret; 125 return ret;
126 } 126 }
127 127
128 static int tcf_gact_cleanup(struct tc_action *a, int bind) 128 static int tcf_gact_cleanup(struct tc_action *a, int bind)
129 { 129 {
130 struct tcf_gact *gact = a->priv; 130 struct tcf_gact *gact = a->priv;
131 131
132 if (gact) 132 if (gact)
133 return tcf_hash_release(&gact->common, bind, &gact_hash_info); 133 return tcf_hash_release(&gact->common, bind, &gact_hash_info);
134 return 0; 134 return 0;
135 } 135 }
136 136
137 static int tcf_gact(struct sk_buff *skb, const struct tc_action *a, 137 static int tcf_gact(struct sk_buff *skb, const struct tc_action *a,
138 struct tcf_result *res) 138 struct tcf_result *res)
139 { 139 {
140 struct tcf_gact *gact = a->priv; 140 struct tcf_gact *gact = a->priv;
141 int action = TC_ACT_SHOT; 141 int action = TC_ACT_SHOT;
142 142
143 spin_lock(&gact->tcf_lock); 143 spin_lock(&gact->tcf_lock);
144 #ifdef CONFIG_GACT_PROB 144 #ifdef CONFIG_GACT_PROB
145 if (gact->tcfg_ptype) 145 if (gact->tcfg_ptype)
146 action = gact_rand[gact->tcfg_ptype](gact); 146 action = gact_rand[gact->tcfg_ptype](gact);
147 else 147 else
148 action = gact->tcf_action; 148 action = gact->tcf_action;
149 #else 149 #else
150 action = gact->tcf_action; 150 action = gact->tcf_action;
151 #endif 151 #endif
152 gact->tcf_bstats.bytes += qdisc_pkt_len(skb); 152 gact->tcf_bstats.bytes += qdisc_pkt_len(skb);
153 gact->tcf_bstats.packets++; 153 gact->tcf_bstats.packets++;
154 if (action == TC_ACT_SHOT) 154 if (action == TC_ACT_SHOT)
155 gact->tcf_qstats.drops++; 155 gact->tcf_qstats.drops++;
156 gact->tcf_tm.lastuse = jiffies; 156 gact->tcf_tm.lastuse = jiffies;
157 spin_unlock(&gact->tcf_lock); 157 spin_unlock(&gact->tcf_lock);
158 158
159 return action; 159 return action;
160 } 160 }
161 161
162 static int tcf_gact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) 162 static int tcf_gact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
163 { 163 {
164 unsigned char *b = skb_tail_pointer(skb); 164 unsigned char *b = skb_tail_pointer(skb);
165 struct tcf_gact *gact = a->priv; 165 struct tcf_gact *gact = a->priv;
166 struct tc_gact opt = { 166 struct tc_gact opt = {
167 .index = gact->tcf_index, 167 .index = gact->tcf_index,
168 .refcnt = gact->tcf_refcnt - ref, 168 .refcnt = gact->tcf_refcnt - ref,
169 .bindcnt = gact->tcf_bindcnt - bind, 169 .bindcnt = gact->tcf_bindcnt - bind,
170 .action = gact->tcf_action, 170 .action = gact->tcf_action,
171 }; 171 };
172 struct tcf_t t; 172 struct tcf_t t;
173 173
174 if (nla_put(skb, TCA_GACT_PARMS, sizeof(opt), &opt)) 174 if (nla_put(skb, TCA_GACT_PARMS, sizeof(opt), &opt))
175 goto nla_put_failure; 175 goto nla_put_failure;
176 #ifdef CONFIG_GACT_PROB 176 #ifdef CONFIG_GACT_PROB
177 if (gact->tcfg_ptype) { 177 if (gact->tcfg_ptype) {
178 struct tc_gact_p p_opt = { 178 struct tc_gact_p p_opt = {
179 .paction = gact->tcfg_paction, 179 .paction = gact->tcfg_paction,
180 .pval = gact->tcfg_pval, 180 .pval = gact->tcfg_pval,
181 .ptype = gact->tcfg_ptype, 181 .ptype = gact->tcfg_ptype,
182 }; 182 };
183 183
184 if (nla_put(skb, TCA_GACT_PROB, sizeof(p_opt), &p_opt)) 184 if (nla_put(skb, TCA_GACT_PROB, sizeof(p_opt), &p_opt))
185 goto nla_put_failure; 185 goto nla_put_failure;
186 } 186 }
187 #endif 187 #endif
188 t.install = jiffies_to_clock_t(jiffies - gact->tcf_tm.install); 188 t.install = jiffies_to_clock_t(jiffies - gact->tcf_tm.install);
189 t.lastuse = jiffies_to_clock_t(jiffies - gact->tcf_tm.lastuse); 189 t.lastuse = jiffies_to_clock_t(jiffies - gact->tcf_tm.lastuse);
190 t.expires = jiffies_to_clock_t(gact->tcf_tm.expires); 190 t.expires = jiffies_to_clock_t(gact->tcf_tm.expires);
191 if (nla_put(skb, TCA_GACT_TM, sizeof(t), &t)) 191 if (nla_put(skb, TCA_GACT_TM, sizeof(t), &t))
192 goto nla_put_failure; 192 goto nla_put_failure;
193 return skb->len; 193 return skb->len;
194 194
195 nla_put_failure: 195 nla_put_failure:
196 nlmsg_trim(skb, b); 196 nlmsg_trim(skb, b);
197 return -1; 197 return -1;
198 } 198 }
199 199
200 static struct tc_action_ops act_gact_ops = { 200 static struct tc_action_ops act_gact_ops = {
201 .kind = "gact", 201 .kind = "gact",
202 .hinfo = &gact_hash_info, 202 .hinfo = &gact_hash_info,
203 .type = TCA_ACT_GACT, 203 .type = TCA_ACT_GACT,
204 .capab = TCA_CAP_NONE, 204 .capab = TCA_CAP_NONE,
205 .owner = THIS_MODULE, 205 .owner = THIS_MODULE,
206 .act = tcf_gact, 206 .act = tcf_gact,
207 .dump = tcf_gact_dump, 207 .dump = tcf_gact_dump,
208 .cleanup = tcf_gact_cleanup, 208 .cleanup = tcf_gact_cleanup,
209 .init = tcf_gact_init, 209 .init = tcf_gact_init,
210 .walk = tcf_generic_walker
211 }; 210 };
212 211
213 MODULE_AUTHOR("Jamal Hadi Salim(2002-4)"); 212 MODULE_AUTHOR("Jamal Hadi Salim(2002-4)");
214 MODULE_DESCRIPTION("Generic Classifier actions"); 213 MODULE_DESCRIPTION("Generic Classifier actions");
215 MODULE_LICENSE("GPL"); 214 MODULE_LICENSE("GPL");
216 215
217 static int __init gact_init_module(void) 216 static int __init gact_init_module(void)
218 { 217 {
219 #ifdef CONFIG_GACT_PROB 218 #ifdef CONFIG_GACT_PROB
220 pr_info("GACT probability on\n"); 219 pr_info("GACT probability on\n");
221 #else 220 #else
222 pr_info("GACT probability NOT on\n"); 221 pr_info("GACT probability NOT on\n");
223 #endif 222 #endif
224 return tcf_register_action(&act_gact_ops); 223 return tcf_register_action(&act_gact_ops);
225 } 224 }
226 225
227 static void __exit gact_cleanup_module(void) 226 static void __exit gact_cleanup_module(void)
228 { 227 {
229 tcf_unregister_action(&act_gact_ops); 228 tcf_unregister_action(&act_gact_ops);
230 } 229 }
231 230
232 module_init(gact_init_module); 231 module_init(gact_init_module);
233 module_exit(gact_cleanup_module); 232 module_exit(gact_cleanup_module);
234 233
1 /* 1 /*
2 * net/sched/ipt.c iptables target interface 2 * net/sched/ipt.c iptables target interface
3 * 3 *
4 *TODO: Add other tables. For now we only support the ipv4 table targets 4 *TODO: Add other tables. For now we only support the ipv4 table targets
5 * 5 *
6 * This program is free software; you can redistribute it and/or 6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License 7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version. 9 * 2 of the License, or (at your option) any later version.
10 * 10 *
11 * Copyright: Jamal Hadi Salim (2002-13) 11 * Copyright: Jamal Hadi Salim (2002-13)
12 */ 12 */
13 13
14 #include <linux/types.h> 14 #include <linux/types.h>
15 #include <linux/kernel.h> 15 #include <linux/kernel.h>
16 #include <linux/string.h> 16 #include <linux/string.h>
17 #include <linux/errno.h> 17 #include <linux/errno.h>
18 #include <linux/skbuff.h> 18 #include <linux/skbuff.h>
19 #include <linux/rtnetlink.h> 19 #include <linux/rtnetlink.h>
20 #include <linux/module.h> 20 #include <linux/module.h>
21 #include <linux/init.h> 21 #include <linux/init.h>
22 #include <linux/slab.h> 22 #include <linux/slab.h>
23 #include <net/netlink.h> 23 #include <net/netlink.h>
24 #include <net/pkt_sched.h> 24 #include <net/pkt_sched.h>
25 #include <linux/tc_act/tc_ipt.h> 25 #include <linux/tc_act/tc_ipt.h>
26 #include <net/tc_act/tc_ipt.h> 26 #include <net/tc_act/tc_ipt.h>
27 27
28 #include <linux/netfilter_ipv4/ip_tables.h> 28 #include <linux/netfilter_ipv4/ip_tables.h>
29 29
30 30
31 #define IPT_TAB_MASK 15 31 #define IPT_TAB_MASK 15
32 static struct tcf_common *tcf_ipt_ht[IPT_TAB_MASK + 1]; 32 static struct tcf_common *tcf_ipt_ht[IPT_TAB_MASK + 1];
33 static u32 ipt_idx_gen; 33 static u32 ipt_idx_gen;
34 static DEFINE_RWLOCK(ipt_lock); 34 static DEFINE_RWLOCK(ipt_lock);
35 35
36 static struct tcf_hashinfo ipt_hash_info = { 36 static struct tcf_hashinfo ipt_hash_info = {
37 .htab = tcf_ipt_ht, 37 .htab = tcf_ipt_ht,
38 .hmask = IPT_TAB_MASK, 38 .hmask = IPT_TAB_MASK,
39 .lock = &ipt_lock, 39 .lock = &ipt_lock,
40 }; 40 };
41 41
42 static int ipt_init_target(struct xt_entry_target *t, char *table, unsigned int hook) 42 static int ipt_init_target(struct xt_entry_target *t, char *table, unsigned int hook)
43 { 43 {
44 struct xt_tgchk_param par; 44 struct xt_tgchk_param par;
45 struct xt_target *target; 45 struct xt_target *target;
46 int ret = 0; 46 int ret = 0;
47 47
48 target = xt_request_find_target(AF_INET, t->u.user.name, 48 target = xt_request_find_target(AF_INET, t->u.user.name,
49 t->u.user.revision); 49 t->u.user.revision);
50 if (IS_ERR(target)) 50 if (IS_ERR(target))
51 return PTR_ERR(target); 51 return PTR_ERR(target);
52 52
53 t->u.kernel.target = target; 53 t->u.kernel.target = target;
54 par.table = table; 54 par.table = table;
55 par.entryinfo = NULL; 55 par.entryinfo = NULL;
56 par.target = target; 56 par.target = target;
57 par.targinfo = t->data; 57 par.targinfo = t->data;
58 par.hook_mask = hook; 58 par.hook_mask = hook;
59 par.family = NFPROTO_IPV4; 59 par.family = NFPROTO_IPV4;
60 60
61 ret = xt_check_target(&par, t->u.target_size - sizeof(*t), 0, false); 61 ret = xt_check_target(&par, t->u.target_size - sizeof(*t), 0, false);
62 if (ret < 0) { 62 if (ret < 0) {
63 module_put(t->u.kernel.target->me); 63 module_put(t->u.kernel.target->me);
64 return ret; 64 return ret;
65 } 65 }
66 return 0; 66 return 0;
67 } 67 }
68 68
69 static void ipt_destroy_target(struct xt_entry_target *t) 69 static void ipt_destroy_target(struct xt_entry_target *t)
70 { 70 {
71 struct xt_tgdtor_param par = { 71 struct xt_tgdtor_param par = {
72 .target = t->u.kernel.target, 72 .target = t->u.kernel.target,
73 .targinfo = t->data, 73 .targinfo = t->data,
74 }; 74 };
75 if (par.target->destroy != NULL) 75 if (par.target->destroy != NULL)
76 par.target->destroy(&par); 76 par.target->destroy(&par);
77 module_put(par.target->me); 77 module_put(par.target->me);
78 } 78 }
79 79
80 static int tcf_ipt_release(struct tcf_ipt *ipt, int bind) 80 static int tcf_ipt_release(struct tcf_ipt *ipt, int bind)
81 { 81 {
82 int ret = 0; 82 int ret = 0;
83 if (ipt) { 83 if (ipt) {
84 if (bind) 84 if (bind)
85 ipt->tcf_bindcnt--; 85 ipt->tcf_bindcnt--;
86 ipt->tcf_refcnt--; 86 ipt->tcf_refcnt--;
87 if (ipt->tcf_bindcnt <= 0 && ipt->tcf_refcnt <= 0) { 87 if (ipt->tcf_bindcnt <= 0 && ipt->tcf_refcnt <= 0) {
88 ipt_destroy_target(ipt->tcfi_t); 88 ipt_destroy_target(ipt->tcfi_t);
89 kfree(ipt->tcfi_tname); 89 kfree(ipt->tcfi_tname);
90 kfree(ipt->tcfi_t); 90 kfree(ipt->tcfi_t);
91 tcf_hash_destroy(&ipt->common, &ipt_hash_info); 91 tcf_hash_destroy(&ipt->common, &ipt_hash_info);
92 ret = ACT_P_DELETED; 92 ret = ACT_P_DELETED;
93 } 93 }
94 } 94 }
95 return ret; 95 return ret;
96 } 96 }
97 97
98 static const struct nla_policy ipt_policy[TCA_IPT_MAX + 1] = { 98 static const struct nla_policy ipt_policy[TCA_IPT_MAX + 1] = {
99 [TCA_IPT_TABLE] = { .type = NLA_STRING, .len = IFNAMSIZ }, 99 [TCA_IPT_TABLE] = { .type = NLA_STRING, .len = IFNAMSIZ },
100 [TCA_IPT_HOOK] = { .type = NLA_U32 }, 100 [TCA_IPT_HOOK] = { .type = NLA_U32 },
101 [TCA_IPT_INDEX] = { .type = NLA_U32 }, 101 [TCA_IPT_INDEX] = { .type = NLA_U32 },
102 [TCA_IPT_TARG] = { .len = sizeof(struct xt_entry_target) }, 102 [TCA_IPT_TARG] = { .len = sizeof(struct xt_entry_target) },
103 }; 103 };
104 104
105 static int tcf_ipt_init(struct net *net, struct nlattr *nla, struct nlattr *est, 105 static int tcf_ipt_init(struct net *net, struct nlattr *nla, struct nlattr *est,
106 struct tc_action *a, int ovr, int bind) 106 struct tc_action *a, int ovr, int bind)
107 { 107 {
108 struct nlattr *tb[TCA_IPT_MAX + 1]; 108 struct nlattr *tb[TCA_IPT_MAX + 1];
109 struct tcf_ipt *ipt; 109 struct tcf_ipt *ipt;
110 struct tcf_common *pc; 110 struct tcf_common *pc;
111 struct xt_entry_target *td, *t; 111 struct xt_entry_target *td, *t;
112 char *tname; 112 char *tname;
113 int ret = 0, err; 113 int ret = 0, err;
114 u32 hook = 0; 114 u32 hook = 0;
115 u32 index = 0; 115 u32 index = 0;
116 116
117 if (nla == NULL) 117 if (nla == NULL)
118 return -EINVAL; 118 return -EINVAL;
119 119
120 err = nla_parse_nested(tb, TCA_IPT_MAX, nla, ipt_policy); 120 err = nla_parse_nested(tb, TCA_IPT_MAX, nla, ipt_policy);
121 if (err < 0) 121 if (err < 0)
122 return err; 122 return err;
123 123
124 if (tb[TCA_IPT_HOOK] == NULL) 124 if (tb[TCA_IPT_HOOK] == NULL)
125 return -EINVAL; 125 return -EINVAL;
126 if (tb[TCA_IPT_TARG] == NULL) 126 if (tb[TCA_IPT_TARG] == NULL)
127 return -EINVAL; 127 return -EINVAL;
128 128
129 td = (struct xt_entry_target *)nla_data(tb[TCA_IPT_TARG]); 129 td = (struct xt_entry_target *)nla_data(tb[TCA_IPT_TARG]);
130 if (nla_len(tb[TCA_IPT_TARG]) < td->u.target_size) 130 if (nla_len(tb[TCA_IPT_TARG]) < td->u.target_size)
131 return -EINVAL; 131 return -EINVAL;
132 132
133 if (tb[TCA_IPT_INDEX] != NULL) 133 if (tb[TCA_IPT_INDEX] != NULL)
134 index = nla_get_u32(tb[TCA_IPT_INDEX]); 134 index = nla_get_u32(tb[TCA_IPT_INDEX]);
135 135
136 pc = tcf_hash_check(index, a, bind, &ipt_hash_info); 136 pc = tcf_hash_check(index, a, bind, &ipt_hash_info);
137 if (!pc) { 137 if (!pc) {
138 pc = tcf_hash_create(index, est, a, sizeof(*ipt), bind, 138 pc = tcf_hash_create(index, est, a, sizeof(*ipt), bind,
139 &ipt_idx_gen, &ipt_hash_info); 139 &ipt_idx_gen, &ipt_hash_info);
140 if (IS_ERR(pc)) 140 if (IS_ERR(pc))
141 return PTR_ERR(pc); 141 return PTR_ERR(pc);
142 ret = ACT_P_CREATED; 142 ret = ACT_P_CREATED;
143 } else { 143 } else {
144 if (!ovr) { 144 if (!ovr) {
145 tcf_ipt_release(to_ipt(pc), bind); 145 tcf_ipt_release(to_ipt(pc), bind);
146 return -EEXIST; 146 return -EEXIST;
147 } 147 }
148 } 148 }
149 ipt = to_ipt(pc); 149 ipt = to_ipt(pc);
150 150
151 hook = nla_get_u32(tb[TCA_IPT_HOOK]); 151 hook = nla_get_u32(tb[TCA_IPT_HOOK]);
152 152
153 err = -ENOMEM; 153 err = -ENOMEM;
154 tname = kmalloc(IFNAMSIZ, GFP_KERNEL); 154 tname = kmalloc(IFNAMSIZ, GFP_KERNEL);
155 if (unlikely(!tname)) 155 if (unlikely(!tname))
156 goto err1; 156 goto err1;
157 if (tb[TCA_IPT_TABLE] == NULL || 157 if (tb[TCA_IPT_TABLE] == NULL ||
158 nla_strlcpy(tname, tb[TCA_IPT_TABLE], IFNAMSIZ) >= IFNAMSIZ) 158 nla_strlcpy(tname, tb[TCA_IPT_TABLE], IFNAMSIZ) >= IFNAMSIZ)
159 strcpy(tname, "mangle"); 159 strcpy(tname, "mangle");
160 160
161 t = kmemdup(td, td->u.target_size, GFP_KERNEL); 161 t = kmemdup(td, td->u.target_size, GFP_KERNEL);
162 if (unlikely(!t)) 162 if (unlikely(!t))
163 goto err2; 163 goto err2;
164 164
165 err = ipt_init_target(t, tname, hook); 165 err = ipt_init_target(t, tname, hook);
166 if (err < 0) 166 if (err < 0)
167 goto err3; 167 goto err3;
168 168
169 spin_lock_bh(&ipt->tcf_lock); 169 spin_lock_bh(&ipt->tcf_lock);
170 if (ret != ACT_P_CREATED) { 170 if (ret != ACT_P_CREATED) {
171 ipt_destroy_target(ipt->tcfi_t); 171 ipt_destroy_target(ipt->tcfi_t);
172 kfree(ipt->tcfi_tname); 172 kfree(ipt->tcfi_tname);
173 kfree(ipt->tcfi_t); 173 kfree(ipt->tcfi_t);
174 } 174 }
175 ipt->tcfi_tname = tname; 175 ipt->tcfi_tname = tname;
176 ipt->tcfi_t = t; 176 ipt->tcfi_t = t;
177 ipt->tcfi_hook = hook; 177 ipt->tcfi_hook = hook;
178 spin_unlock_bh(&ipt->tcf_lock); 178 spin_unlock_bh(&ipt->tcf_lock);
179 if (ret == ACT_P_CREATED) 179 if (ret == ACT_P_CREATED)
180 tcf_hash_insert(pc, &ipt_hash_info); 180 tcf_hash_insert(pc, &ipt_hash_info);
181 return ret; 181 return ret;
182 182
183 err3: 183 err3:
184 kfree(t); 184 kfree(t);
185 err2: 185 err2:
186 kfree(tname); 186 kfree(tname);
187 err1: 187 err1:
188 if (ret == ACT_P_CREATED) { 188 if (ret == ACT_P_CREATED) {
189 if (est) 189 if (est)
190 gen_kill_estimator(&pc->tcfc_bstats, 190 gen_kill_estimator(&pc->tcfc_bstats,
191 &pc->tcfc_rate_est); 191 &pc->tcfc_rate_est);
192 kfree_rcu(pc, tcfc_rcu); 192 kfree_rcu(pc, tcfc_rcu);
193 } 193 }
194 return err; 194 return err;
195 } 195 }
196 196
197 static int tcf_ipt_cleanup(struct tc_action *a, int bind) 197 static int tcf_ipt_cleanup(struct tc_action *a, int bind)
198 { 198 {
199 struct tcf_ipt *ipt = a->priv; 199 struct tcf_ipt *ipt = a->priv;
200 return tcf_ipt_release(ipt, bind); 200 return tcf_ipt_release(ipt, bind);
201 } 201 }
202 202
203 static int tcf_ipt(struct sk_buff *skb, const struct tc_action *a, 203 static int tcf_ipt(struct sk_buff *skb, const struct tc_action *a,
204 struct tcf_result *res) 204 struct tcf_result *res)
205 { 205 {
206 int ret = 0, result = 0; 206 int ret = 0, result = 0;
207 struct tcf_ipt *ipt = a->priv; 207 struct tcf_ipt *ipt = a->priv;
208 struct xt_action_param par; 208 struct xt_action_param par;
209 209
210 if (skb_unclone(skb, GFP_ATOMIC)) 210 if (skb_unclone(skb, GFP_ATOMIC))
211 return TC_ACT_UNSPEC; 211 return TC_ACT_UNSPEC;
212 212
213 spin_lock(&ipt->tcf_lock); 213 spin_lock(&ipt->tcf_lock);
214 214
215 ipt->tcf_tm.lastuse = jiffies; 215 ipt->tcf_tm.lastuse = jiffies;
216 bstats_update(&ipt->tcf_bstats, skb); 216 bstats_update(&ipt->tcf_bstats, skb);
217 217
218 /* yes, we have to worry about both in and out dev 218 /* yes, we have to worry about both in and out dev
219 * worry later - danger - this API seems to have changed 219 * worry later - danger - this API seems to have changed
220 * from earlier kernels 220 * from earlier kernels
221 */ 221 */
222 par.in = skb->dev; 222 par.in = skb->dev;
223 par.out = NULL; 223 par.out = NULL;
224 par.hooknum = ipt->tcfi_hook; 224 par.hooknum = ipt->tcfi_hook;
225 par.target = ipt->tcfi_t->u.kernel.target; 225 par.target = ipt->tcfi_t->u.kernel.target;
226 par.targinfo = ipt->tcfi_t->data; 226 par.targinfo = ipt->tcfi_t->data;
227 ret = par.target->target(skb, &par); 227 ret = par.target->target(skb, &par);
228 228
229 switch (ret) { 229 switch (ret) {
230 case NF_ACCEPT: 230 case NF_ACCEPT:
231 result = TC_ACT_OK; 231 result = TC_ACT_OK;
232 break; 232 break;
233 case NF_DROP: 233 case NF_DROP:
234 result = TC_ACT_SHOT; 234 result = TC_ACT_SHOT;
235 ipt->tcf_qstats.drops++; 235 ipt->tcf_qstats.drops++;
236 break; 236 break;
237 case XT_CONTINUE: 237 case XT_CONTINUE:
238 result = TC_ACT_PIPE; 238 result = TC_ACT_PIPE;
239 break; 239 break;
240 default: 240 default:
241 net_notice_ratelimited("tc filter: Bogus netfilter code %d assume ACCEPT\n", 241 net_notice_ratelimited("tc filter: Bogus netfilter code %d assume ACCEPT\n",
242 ret); 242 ret);
243 result = TC_POLICE_OK; 243 result = TC_POLICE_OK;
244 break; 244 break;
245 } 245 }
246 spin_unlock(&ipt->tcf_lock); 246 spin_unlock(&ipt->tcf_lock);
247 return result; 247 return result;
248 248
249 } 249 }
250 250
251 static int tcf_ipt_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) 251 static int tcf_ipt_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
252 { 252 {
253 unsigned char *b = skb_tail_pointer(skb); 253 unsigned char *b = skb_tail_pointer(skb);
254 struct tcf_ipt *ipt = a->priv; 254 struct tcf_ipt *ipt = a->priv;
255 struct xt_entry_target *t; 255 struct xt_entry_target *t;
256 struct tcf_t tm; 256 struct tcf_t tm;
257 struct tc_cnt c; 257 struct tc_cnt c;
258 258
259 /* for simple targets kernel size == user size 259 /* for simple targets kernel size == user size
260 * user name = target name 260 * user name = target name
261 * for foolproof you need to not assume this 261 * for foolproof you need to not assume this
262 */ 262 */
263 263
264 t = kmemdup(ipt->tcfi_t, ipt->tcfi_t->u.user.target_size, GFP_ATOMIC); 264 t = kmemdup(ipt->tcfi_t, ipt->tcfi_t->u.user.target_size, GFP_ATOMIC);
265 if (unlikely(!t)) 265 if (unlikely(!t))
266 goto nla_put_failure; 266 goto nla_put_failure;
267 267
268 c.bindcnt = ipt->tcf_bindcnt - bind; 268 c.bindcnt = ipt->tcf_bindcnt - bind;
269 c.refcnt = ipt->tcf_refcnt - ref; 269 c.refcnt = ipt->tcf_refcnt - ref;
270 strcpy(t->u.user.name, ipt->tcfi_t->u.kernel.target->name); 270 strcpy(t->u.user.name, ipt->tcfi_t->u.kernel.target->name);
271 271
272 if (nla_put(skb, TCA_IPT_TARG, ipt->tcfi_t->u.user.target_size, t) || 272 if (nla_put(skb, TCA_IPT_TARG, ipt->tcfi_t->u.user.target_size, t) ||
273 nla_put_u32(skb, TCA_IPT_INDEX, ipt->tcf_index) || 273 nla_put_u32(skb, TCA_IPT_INDEX, ipt->tcf_index) ||
274 nla_put_u32(skb, TCA_IPT_HOOK, ipt->tcfi_hook) || 274 nla_put_u32(skb, TCA_IPT_HOOK, ipt->tcfi_hook) ||
275 nla_put(skb, TCA_IPT_CNT, sizeof(struct tc_cnt), &c) || 275 nla_put(skb, TCA_IPT_CNT, sizeof(struct tc_cnt), &c) ||
276 nla_put_string(skb, TCA_IPT_TABLE, ipt->tcfi_tname)) 276 nla_put_string(skb, TCA_IPT_TABLE, ipt->tcfi_tname))
277 goto nla_put_failure; 277 goto nla_put_failure;
278 tm.install = jiffies_to_clock_t(jiffies - ipt->tcf_tm.install); 278 tm.install = jiffies_to_clock_t(jiffies - ipt->tcf_tm.install);
279 tm.lastuse = jiffies_to_clock_t(jiffies - ipt->tcf_tm.lastuse); 279 tm.lastuse = jiffies_to_clock_t(jiffies - ipt->tcf_tm.lastuse);
280 tm.expires = jiffies_to_clock_t(ipt->tcf_tm.expires); 280 tm.expires = jiffies_to_clock_t(ipt->tcf_tm.expires);
281 if (nla_put(skb, TCA_IPT_TM, sizeof (tm), &tm)) 281 if (nla_put(skb, TCA_IPT_TM, sizeof (tm), &tm))
282 goto nla_put_failure; 282 goto nla_put_failure;
283 kfree(t); 283 kfree(t);
284 return skb->len; 284 return skb->len;
285 285
286 nla_put_failure: 286 nla_put_failure:
287 nlmsg_trim(skb, b); 287 nlmsg_trim(skb, b);
288 kfree(t); 288 kfree(t);
289 return -1; 289 return -1;
290 } 290 }
291 291
292 static struct tc_action_ops act_ipt_ops = { 292 static struct tc_action_ops act_ipt_ops = {
293 .kind = "ipt", 293 .kind = "ipt",
294 .hinfo = &ipt_hash_info, 294 .hinfo = &ipt_hash_info,
295 .type = TCA_ACT_IPT, 295 .type = TCA_ACT_IPT,
296 .capab = TCA_CAP_NONE, 296 .capab = TCA_CAP_NONE,
297 .owner = THIS_MODULE, 297 .owner = THIS_MODULE,
298 .act = tcf_ipt, 298 .act = tcf_ipt,
299 .dump = tcf_ipt_dump, 299 .dump = tcf_ipt_dump,
300 .cleanup = tcf_ipt_cleanup, 300 .cleanup = tcf_ipt_cleanup,
301 .init = tcf_ipt_init, 301 .init = tcf_ipt_init,
302 .walk = tcf_generic_walker
303 }; 302 };
304 303
305 static struct tc_action_ops act_xt_ops = { 304 static struct tc_action_ops act_xt_ops = {
306 .kind = "xt", 305 .kind = "xt",
307 .hinfo = &ipt_hash_info, 306 .hinfo = &ipt_hash_info,
308 .type = TCA_ACT_IPT, 307 .type = TCA_ACT_IPT,
309 .capab = TCA_CAP_NONE, 308 .capab = TCA_CAP_NONE,
310 .owner = THIS_MODULE, 309 .owner = THIS_MODULE,
311 .act = tcf_ipt, 310 .act = tcf_ipt,
312 .dump = tcf_ipt_dump, 311 .dump = tcf_ipt_dump,
313 .cleanup = tcf_ipt_cleanup, 312 .cleanup = tcf_ipt_cleanup,
314 .init = tcf_ipt_init, 313 .init = tcf_ipt_init,
315 .walk = tcf_generic_walker
316 }; 314 };
317 315
318 MODULE_AUTHOR("Jamal Hadi Salim(2002-13)"); 316 MODULE_AUTHOR("Jamal Hadi Salim(2002-13)");
319 MODULE_DESCRIPTION("Iptables target actions"); 317 MODULE_DESCRIPTION("Iptables target actions");
320 MODULE_LICENSE("GPL"); 318 MODULE_LICENSE("GPL");
321 MODULE_ALIAS("act_xt"); 319 MODULE_ALIAS("act_xt");
322 320
323 static int __init ipt_init_module(void) 321 static int __init ipt_init_module(void)
324 { 322 {
325 int ret1, ret2; 323 int ret1, ret2;
326 ret1 = tcf_register_action(&act_xt_ops); 324 ret1 = tcf_register_action(&act_xt_ops);
327 if (ret1 < 0) 325 if (ret1 < 0)
328 printk("Failed to load xt action\n"); 326 printk("Failed to load xt action\n");
329 ret2 = tcf_register_action(&act_ipt_ops); 327 ret2 = tcf_register_action(&act_ipt_ops);
330 if (ret2 < 0) 328 if (ret2 < 0)
331 printk("Failed to load ipt action\n"); 329 printk("Failed to load ipt action\n");
332 330
333 if (ret1 < 0 && ret2 < 0) 331 if (ret1 < 0 && ret2 < 0)
334 return ret1; 332 return ret1;
335 else 333 else
336 return 0; 334 return 0;
337 } 335 }
338 336
339 static void __exit ipt_cleanup_module(void) 337 static void __exit ipt_cleanup_module(void)
340 { 338 {
341 tcf_unregister_action(&act_xt_ops); 339 tcf_unregister_action(&act_xt_ops);
342 tcf_unregister_action(&act_ipt_ops); 340 tcf_unregister_action(&act_ipt_ops);
343 } 341 }
344 342
345 module_init(ipt_init_module); 343 module_init(ipt_init_module);
346 module_exit(ipt_cleanup_module); 344 module_exit(ipt_cleanup_module);
347 345
net/sched/act_mirred.c
1 /* 1 /*
2 * net/sched/mirred.c packet mirroring and redirect actions 2 * net/sched/mirred.c packet mirroring and redirect actions
3 * 3 *
4 * This program is free software; you can redistribute it and/or 4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License 5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version. 7 * 2 of the License, or (at your option) any later version.
8 * 8 *
9 * Authors: Jamal Hadi Salim (2002-4) 9 * Authors: Jamal Hadi Salim (2002-4)
10 * 10 *
11 * TODO: Add ingress support (and socket redirect support) 11 * TODO: Add ingress support (and socket redirect support)
12 * 12 *
13 */ 13 */
14 14
15 #include <linux/types.h> 15 #include <linux/types.h>
16 #include <linux/kernel.h> 16 #include <linux/kernel.h>
17 #include <linux/string.h> 17 #include <linux/string.h>
18 #include <linux/errno.h> 18 #include <linux/errno.h>
19 #include <linux/skbuff.h> 19 #include <linux/skbuff.h>
20 #include <linux/rtnetlink.h> 20 #include <linux/rtnetlink.h>
21 #include <linux/module.h> 21 #include <linux/module.h>
22 #include <linux/init.h> 22 #include <linux/init.h>
23 #include <linux/gfp.h> 23 #include <linux/gfp.h>
24 #include <net/net_namespace.h> 24 #include <net/net_namespace.h>
25 #include <net/netlink.h> 25 #include <net/netlink.h>
26 #include <net/pkt_sched.h> 26 #include <net/pkt_sched.h>
27 #include <linux/tc_act/tc_mirred.h> 27 #include <linux/tc_act/tc_mirred.h>
28 #include <net/tc_act/tc_mirred.h> 28 #include <net/tc_act/tc_mirred.h>
29 29
30 #include <linux/if_arp.h> 30 #include <linux/if_arp.h>
31 31
32 #define MIRRED_TAB_MASK 7 32 #define MIRRED_TAB_MASK 7
33 static struct tcf_common *tcf_mirred_ht[MIRRED_TAB_MASK + 1]; 33 static struct tcf_common *tcf_mirred_ht[MIRRED_TAB_MASK + 1];
34 static u32 mirred_idx_gen; 34 static u32 mirred_idx_gen;
35 static DEFINE_RWLOCK(mirred_lock); 35 static DEFINE_RWLOCK(mirred_lock);
36 static LIST_HEAD(mirred_list); 36 static LIST_HEAD(mirred_list);
37 37
38 static struct tcf_hashinfo mirred_hash_info = { 38 static struct tcf_hashinfo mirred_hash_info = {
39 .htab = tcf_mirred_ht, 39 .htab = tcf_mirred_ht,
40 .hmask = MIRRED_TAB_MASK, 40 .hmask = MIRRED_TAB_MASK,
41 .lock = &mirred_lock, 41 .lock = &mirred_lock,
42 }; 42 };
43 43
44 static int tcf_mirred_release(struct tcf_mirred *m, int bind) 44 static int tcf_mirred_release(struct tcf_mirred *m, int bind)
45 { 45 {
46 if (m) { 46 if (m) {
47 if (bind) 47 if (bind)
48 m->tcf_bindcnt--; 48 m->tcf_bindcnt--;
49 m->tcf_refcnt--; 49 m->tcf_refcnt--;
50 if (!m->tcf_bindcnt && m->tcf_refcnt <= 0) { 50 if (!m->tcf_bindcnt && m->tcf_refcnt <= 0) {
51 list_del(&m->tcfm_list); 51 list_del(&m->tcfm_list);
52 if (m->tcfm_dev) 52 if (m->tcfm_dev)
53 dev_put(m->tcfm_dev); 53 dev_put(m->tcfm_dev);
54 tcf_hash_destroy(&m->common, &mirred_hash_info); 54 tcf_hash_destroy(&m->common, &mirred_hash_info);
55 return 1; 55 return 1;
56 } 56 }
57 } 57 }
58 return 0; 58 return 0;
59 } 59 }
60 60
61 static const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = { 61 static const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = {
62 [TCA_MIRRED_PARMS] = { .len = sizeof(struct tc_mirred) }, 62 [TCA_MIRRED_PARMS] = { .len = sizeof(struct tc_mirred) },
63 }; 63 };
64 64
65 static int tcf_mirred_init(struct net *net, struct nlattr *nla, 65 static int tcf_mirred_init(struct net *net, struct nlattr *nla,
66 struct nlattr *est, struct tc_action *a, int ovr, 66 struct nlattr *est, struct tc_action *a, int ovr,
67 int bind) 67 int bind)
68 { 68 {
69 struct nlattr *tb[TCA_MIRRED_MAX + 1]; 69 struct nlattr *tb[TCA_MIRRED_MAX + 1];
70 struct tc_mirred *parm; 70 struct tc_mirred *parm;
71 struct tcf_mirred *m; 71 struct tcf_mirred *m;
72 struct tcf_common *pc; 72 struct tcf_common *pc;
73 struct net_device *dev; 73 struct net_device *dev;
74 int ret, ok_push = 0; 74 int ret, ok_push = 0;
75 75
76 if (nla == NULL) 76 if (nla == NULL)
77 return -EINVAL; 77 return -EINVAL;
78 ret = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy); 78 ret = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy);
79 if (ret < 0) 79 if (ret < 0)
80 return ret; 80 return ret;
81 if (tb[TCA_MIRRED_PARMS] == NULL) 81 if (tb[TCA_MIRRED_PARMS] == NULL)
82 return -EINVAL; 82 return -EINVAL;
83 parm = nla_data(tb[TCA_MIRRED_PARMS]); 83 parm = nla_data(tb[TCA_MIRRED_PARMS]);
84 switch (parm->eaction) { 84 switch (parm->eaction) {
85 case TCA_EGRESS_MIRROR: 85 case TCA_EGRESS_MIRROR:
86 case TCA_EGRESS_REDIR: 86 case TCA_EGRESS_REDIR:
87 break; 87 break;
88 default: 88 default:
89 return -EINVAL; 89 return -EINVAL;
90 } 90 }
91 if (parm->ifindex) { 91 if (parm->ifindex) {
92 dev = __dev_get_by_index(net, parm->ifindex); 92 dev = __dev_get_by_index(net, parm->ifindex);
93 if (dev == NULL) 93 if (dev == NULL)
94 return -ENODEV; 94 return -ENODEV;
95 switch (dev->type) { 95 switch (dev->type) {
96 case ARPHRD_TUNNEL: 96 case ARPHRD_TUNNEL:
97 case ARPHRD_TUNNEL6: 97 case ARPHRD_TUNNEL6:
98 case ARPHRD_SIT: 98 case ARPHRD_SIT:
99 case ARPHRD_IPGRE: 99 case ARPHRD_IPGRE:
100 case ARPHRD_VOID: 100 case ARPHRD_VOID:
101 case ARPHRD_NONE: 101 case ARPHRD_NONE:
102 ok_push = 0; 102 ok_push = 0;
103 break; 103 break;
104 default: 104 default:
105 ok_push = 1; 105 ok_push = 1;
106 break; 106 break;
107 } 107 }
108 } else { 108 } else {
109 dev = NULL; 109 dev = NULL;
110 } 110 }
111 111
112 pc = tcf_hash_check(parm->index, a, bind, &mirred_hash_info); 112 pc = tcf_hash_check(parm->index, a, bind, &mirred_hash_info);
113 if (!pc) { 113 if (!pc) {
114 if (dev == NULL) 114 if (dev == NULL)
115 return -EINVAL; 115 return -EINVAL;
116 pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind, 116 pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind,
117 &mirred_idx_gen, &mirred_hash_info); 117 &mirred_idx_gen, &mirred_hash_info);
118 if (IS_ERR(pc)) 118 if (IS_ERR(pc))
119 return PTR_ERR(pc); 119 return PTR_ERR(pc);
120 ret = ACT_P_CREATED; 120 ret = ACT_P_CREATED;
121 } else { 121 } else {
122 if (!ovr) { 122 if (!ovr) {
123 tcf_mirred_release(to_mirred(pc), bind); 123 tcf_mirred_release(to_mirred(pc), bind);
124 return -EEXIST; 124 return -EEXIST;
125 } 125 }
126 } 126 }
127 m = to_mirred(pc); 127 m = to_mirred(pc);
128 128
129 spin_lock_bh(&m->tcf_lock); 129 spin_lock_bh(&m->tcf_lock);
130 m->tcf_action = parm->action; 130 m->tcf_action = parm->action;
131 m->tcfm_eaction = parm->eaction; 131 m->tcfm_eaction = parm->eaction;
132 if (dev != NULL) { 132 if (dev != NULL) {
133 m->tcfm_ifindex = parm->ifindex; 133 m->tcfm_ifindex = parm->ifindex;
134 if (ret != ACT_P_CREATED) 134 if (ret != ACT_P_CREATED)
135 dev_put(m->tcfm_dev); 135 dev_put(m->tcfm_dev);
136 dev_hold(dev); 136 dev_hold(dev);
137 m->tcfm_dev = dev; 137 m->tcfm_dev = dev;
138 m->tcfm_ok_push = ok_push; 138 m->tcfm_ok_push = ok_push;
139 } 139 }
140 spin_unlock_bh(&m->tcf_lock); 140 spin_unlock_bh(&m->tcf_lock);
141 if (ret == ACT_P_CREATED) { 141 if (ret == ACT_P_CREATED) {
142 list_add(&m->tcfm_list, &mirred_list); 142 list_add(&m->tcfm_list, &mirred_list);
143 tcf_hash_insert(pc, &mirred_hash_info); 143 tcf_hash_insert(pc, &mirred_hash_info);
144 } 144 }
145 145
146 return ret; 146 return ret;
147 } 147 }
148 148
149 static int tcf_mirred_cleanup(struct tc_action *a, int bind) 149 static int tcf_mirred_cleanup(struct tc_action *a, int bind)
150 { 150 {
151 struct tcf_mirred *m = a->priv; 151 struct tcf_mirred *m = a->priv;
152 152
153 if (m) 153 if (m)
154 return tcf_mirred_release(m, bind); 154 return tcf_mirred_release(m, bind);
155 return 0; 155 return 0;
156 } 156 }
157 157
158 static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a, 158 static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a,
159 struct tcf_result *res) 159 struct tcf_result *res)
160 { 160 {
161 struct tcf_mirred *m = a->priv; 161 struct tcf_mirred *m = a->priv;
162 struct net_device *dev; 162 struct net_device *dev;
163 struct sk_buff *skb2; 163 struct sk_buff *skb2;
164 u32 at; 164 u32 at;
165 int retval, err = 1; 165 int retval, err = 1;
166 166
167 spin_lock(&m->tcf_lock); 167 spin_lock(&m->tcf_lock);
168 m->tcf_tm.lastuse = jiffies; 168 m->tcf_tm.lastuse = jiffies;
169 bstats_update(&m->tcf_bstats, skb); 169 bstats_update(&m->tcf_bstats, skb);
170 170
171 dev = m->tcfm_dev; 171 dev = m->tcfm_dev;
172 if (!dev) { 172 if (!dev) {
173 printk_once(KERN_NOTICE "tc mirred: target device is gone\n"); 173 printk_once(KERN_NOTICE "tc mirred: target device is gone\n");
174 goto out; 174 goto out;
175 } 175 }
176 176
177 if (!(dev->flags & IFF_UP)) { 177 if (!(dev->flags & IFF_UP)) {
178 net_notice_ratelimited("tc mirred to Houston: device %s is down\n", 178 net_notice_ratelimited("tc mirred to Houston: device %s is down\n",
179 dev->name); 179 dev->name);
180 goto out; 180 goto out;
181 } 181 }
182 182
183 at = G_TC_AT(skb->tc_verd); 183 at = G_TC_AT(skb->tc_verd);
184 skb2 = skb_act_clone(skb, GFP_ATOMIC, m->tcf_action); 184 skb2 = skb_act_clone(skb, GFP_ATOMIC, m->tcf_action);
185 if (skb2 == NULL) 185 if (skb2 == NULL)
186 goto out; 186 goto out;
187 187
188 if (!(at & AT_EGRESS)) { 188 if (!(at & AT_EGRESS)) {
189 if (m->tcfm_ok_push) 189 if (m->tcfm_ok_push)
190 skb_push(skb2, skb2->dev->hard_header_len); 190 skb_push(skb2, skb2->dev->hard_header_len);
191 } 191 }
192 192
193 /* mirror is always swallowed */ 193 /* mirror is always swallowed */
194 if (m->tcfm_eaction != TCA_EGRESS_MIRROR) 194 if (m->tcfm_eaction != TCA_EGRESS_MIRROR)
195 skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at); 195 skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at);
196 196
197 skb2->skb_iif = skb->dev->ifindex; 197 skb2->skb_iif = skb->dev->ifindex;
198 skb2->dev = dev; 198 skb2->dev = dev;
199 err = dev_queue_xmit(skb2); 199 err = dev_queue_xmit(skb2);
200 200
201 out: 201 out:
202 if (err) { 202 if (err) {
203 m->tcf_qstats.overlimits++; 203 m->tcf_qstats.overlimits++;
204 if (m->tcfm_eaction != TCA_EGRESS_MIRROR) 204 if (m->tcfm_eaction != TCA_EGRESS_MIRROR)
205 retval = TC_ACT_SHOT; 205 retval = TC_ACT_SHOT;
206 else 206 else
207 retval = m->tcf_action; 207 retval = m->tcf_action;
208 } else 208 } else
209 retval = m->tcf_action; 209 retval = m->tcf_action;
210 spin_unlock(&m->tcf_lock); 210 spin_unlock(&m->tcf_lock);
211 211
212 return retval; 212 return retval;
213 } 213 }
214 214
215 static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) 215 static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
216 { 216 {
217 unsigned char *b = skb_tail_pointer(skb); 217 unsigned char *b = skb_tail_pointer(skb);
218 struct tcf_mirred *m = a->priv; 218 struct tcf_mirred *m = a->priv;
219 struct tc_mirred opt = { 219 struct tc_mirred opt = {
220 .index = m->tcf_index, 220 .index = m->tcf_index,
221 .action = m->tcf_action, 221 .action = m->tcf_action,
222 .refcnt = m->tcf_refcnt - ref, 222 .refcnt = m->tcf_refcnt - ref,
223 .bindcnt = m->tcf_bindcnt - bind, 223 .bindcnt = m->tcf_bindcnt - bind,
224 .eaction = m->tcfm_eaction, 224 .eaction = m->tcfm_eaction,
225 .ifindex = m->tcfm_ifindex, 225 .ifindex = m->tcfm_ifindex,
226 }; 226 };
227 struct tcf_t t; 227 struct tcf_t t;
228 228
229 if (nla_put(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt)) 229 if (nla_put(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt))
230 goto nla_put_failure; 230 goto nla_put_failure;
231 t.install = jiffies_to_clock_t(jiffies - m->tcf_tm.install); 231 t.install = jiffies_to_clock_t(jiffies - m->tcf_tm.install);
232 t.lastuse = jiffies_to_clock_t(jiffies - m->tcf_tm.lastuse); 232 t.lastuse = jiffies_to_clock_t(jiffies - m->tcf_tm.lastuse);
233 t.expires = jiffies_to_clock_t(m->tcf_tm.expires); 233 t.expires = jiffies_to_clock_t(m->tcf_tm.expires);
234 if (nla_put(skb, TCA_MIRRED_TM, sizeof(t), &t)) 234 if (nla_put(skb, TCA_MIRRED_TM, sizeof(t), &t))
235 goto nla_put_failure; 235 goto nla_put_failure;
236 return skb->len; 236 return skb->len;
237 237
238 nla_put_failure: 238 nla_put_failure:
239 nlmsg_trim(skb, b); 239 nlmsg_trim(skb, b);
240 return -1; 240 return -1;
241 } 241 }
242 242
243 static int mirred_device_event(struct notifier_block *unused, 243 static int mirred_device_event(struct notifier_block *unused,
244 unsigned long event, void *ptr) 244 unsigned long event, void *ptr)
245 { 245 {
246 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 246 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
247 struct tcf_mirred *m; 247 struct tcf_mirred *m;
248 248
249 if (event == NETDEV_UNREGISTER) 249 if (event == NETDEV_UNREGISTER)
250 list_for_each_entry(m, &mirred_list, tcfm_list) { 250 list_for_each_entry(m, &mirred_list, tcfm_list) {
251 if (m->tcfm_dev == dev) { 251 if (m->tcfm_dev == dev) {
252 dev_put(dev); 252 dev_put(dev);
253 m->tcfm_dev = NULL; 253 m->tcfm_dev = NULL;
254 } 254 }
255 } 255 }
256 256
257 return NOTIFY_DONE; 257 return NOTIFY_DONE;
258 } 258 }
259 259
260 static struct notifier_block mirred_device_notifier = { 260 static struct notifier_block mirred_device_notifier = {
261 .notifier_call = mirred_device_event, 261 .notifier_call = mirred_device_event,
262 }; 262 };
263 263
264 264
265 static struct tc_action_ops act_mirred_ops = { 265 static struct tc_action_ops act_mirred_ops = {
266 .kind = "mirred", 266 .kind = "mirred",
267 .hinfo = &mirred_hash_info, 267 .hinfo = &mirred_hash_info,
268 .type = TCA_ACT_MIRRED, 268 .type = TCA_ACT_MIRRED,
269 .capab = TCA_CAP_NONE, 269 .capab = TCA_CAP_NONE,
270 .owner = THIS_MODULE, 270 .owner = THIS_MODULE,
271 .act = tcf_mirred, 271 .act = tcf_mirred,
272 .dump = tcf_mirred_dump, 272 .dump = tcf_mirred_dump,
273 .cleanup = tcf_mirred_cleanup, 273 .cleanup = tcf_mirred_cleanup,
274 .init = tcf_mirred_init, 274 .init = tcf_mirred_init,
275 .walk = tcf_generic_walker
276 }; 275 };
277 276
278 MODULE_AUTHOR("Jamal Hadi Salim(2002)"); 277 MODULE_AUTHOR("Jamal Hadi Salim(2002)");
279 MODULE_DESCRIPTION("Device Mirror/redirect actions"); 278 MODULE_DESCRIPTION("Device Mirror/redirect actions");
280 MODULE_LICENSE("GPL"); 279 MODULE_LICENSE("GPL");
281 280
282 static int __init mirred_init_module(void) 281 static int __init mirred_init_module(void)
283 { 282 {
284 int err = register_netdevice_notifier(&mirred_device_notifier); 283 int err = register_netdevice_notifier(&mirred_device_notifier);
285 if (err) 284 if (err)
286 return err; 285 return err;
287 286
288 pr_info("Mirror/redirect action on\n"); 287 pr_info("Mirror/redirect action on\n");
289 return tcf_register_action(&act_mirred_ops); 288 return tcf_register_action(&act_mirred_ops);
290 } 289 }
291 290
292 static void __exit mirred_cleanup_module(void) 291 static void __exit mirred_cleanup_module(void)
293 { 292 {
294 unregister_netdevice_notifier(&mirred_device_notifier); 293 unregister_netdevice_notifier(&mirred_device_notifier);
295 tcf_unregister_action(&act_mirred_ops); 294 tcf_unregister_action(&act_mirred_ops);
296 } 295 }
297 296
298 module_init(mirred_init_module); 297 module_init(mirred_init_module);
299 module_exit(mirred_cleanup_module); 298 module_exit(mirred_cleanup_module);
300 299
1 /* 1 /*
2 * Stateless NAT actions 2 * Stateless NAT actions
3 * 3 *
4 * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au> 4 * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify it 6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free 7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option) 8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version. 9 * any later version.
10 */ 10 */
11 11
12 #include <linux/errno.h> 12 #include <linux/errno.h>
13 #include <linux/init.h> 13 #include <linux/init.h>
14 #include <linux/kernel.h> 14 #include <linux/kernel.h>
15 #include <linux/module.h> 15 #include <linux/module.h>
16 #include <linux/netfilter.h> 16 #include <linux/netfilter.h>
17 #include <linux/rtnetlink.h> 17 #include <linux/rtnetlink.h>
18 #include <linux/skbuff.h> 18 #include <linux/skbuff.h>
19 #include <linux/slab.h> 19 #include <linux/slab.h>
20 #include <linux/spinlock.h> 20 #include <linux/spinlock.h>
21 #include <linux/string.h> 21 #include <linux/string.h>
22 #include <linux/tc_act/tc_nat.h> 22 #include <linux/tc_act/tc_nat.h>
23 #include <net/act_api.h> 23 #include <net/act_api.h>
24 #include <net/icmp.h> 24 #include <net/icmp.h>
25 #include <net/ip.h> 25 #include <net/ip.h>
26 #include <net/netlink.h> 26 #include <net/netlink.h>
27 #include <net/tc_act/tc_nat.h> 27 #include <net/tc_act/tc_nat.h>
28 #include <net/tcp.h> 28 #include <net/tcp.h>
29 #include <net/udp.h> 29 #include <net/udp.h>
30 30
31 31
32 #define NAT_TAB_MASK 15 32 #define NAT_TAB_MASK 15
33 static struct tcf_common *tcf_nat_ht[NAT_TAB_MASK + 1]; 33 static struct tcf_common *tcf_nat_ht[NAT_TAB_MASK + 1];
34 static u32 nat_idx_gen; 34 static u32 nat_idx_gen;
35 static DEFINE_RWLOCK(nat_lock); 35 static DEFINE_RWLOCK(nat_lock);
36 36
37 static struct tcf_hashinfo nat_hash_info = { 37 static struct tcf_hashinfo nat_hash_info = {
38 .htab = tcf_nat_ht, 38 .htab = tcf_nat_ht,
39 .hmask = NAT_TAB_MASK, 39 .hmask = NAT_TAB_MASK,
40 .lock = &nat_lock, 40 .lock = &nat_lock,
41 }; 41 };
42 42
43 static const struct nla_policy nat_policy[TCA_NAT_MAX + 1] = { 43 static const struct nla_policy nat_policy[TCA_NAT_MAX + 1] = {
44 [TCA_NAT_PARMS] = { .len = sizeof(struct tc_nat) }, 44 [TCA_NAT_PARMS] = { .len = sizeof(struct tc_nat) },
45 }; 45 };
46 46
47 static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est, 47 static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
48 struct tc_action *a, int ovr, int bind) 48 struct tc_action *a, int ovr, int bind)
49 { 49 {
50 struct nlattr *tb[TCA_NAT_MAX + 1]; 50 struct nlattr *tb[TCA_NAT_MAX + 1];
51 struct tc_nat *parm; 51 struct tc_nat *parm;
52 int ret = 0, err; 52 int ret = 0, err;
53 struct tcf_nat *p; 53 struct tcf_nat *p;
54 struct tcf_common *pc; 54 struct tcf_common *pc;
55 55
56 if (nla == NULL) 56 if (nla == NULL)
57 return -EINVAL; 57 return -EINVAL;
58 58
59 err = nla_parse_nested(tb, TCA_NAT_MAX, nla, nat_policy); 59 err = nla_parse_nested(tb, TCA_NAT_MAX, nla, nat_policy);
60 if (err < 0) 60 if (err < 0)
61 return err; 61 return err;
62 62
63 if (tb[TCA_NAT_PARMS] == NULL) 63 if (tb[TCA_NAT_PARMS] == NULL)
64 return -EINVAL; 64 return -EINVAL;
65 parm = nla_data(tb[TCA_NAT_PARMS]); 65 parm = nla_data(tb[TCA_NAT_PARMS]);
66 66
67 pc = tcf_hash_check(parm->index, a, bind, &nat_hash_info); 67 pc = tcf_hash_check(parm->index, a, bind, &nat_hash_info);
68 if (!pc) { 68 if (!pc) {
69 pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind, 69 pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind,
70 &nat_idx_gen, &nat_hash_info); 70 &nat_idx_gen, &nat_hash_info);
71 if (IS_ERR(pc)) 71 if (IS_ERR(pc))
72 return PTR_ERR(pc); 72 return PTR_ERR(pc);
73 p = to_tcf_nat(pc); 73 p = to_tcf_nat(pc);
74 ret = ACT_P_CREATED; 74 ret = ACT_P_CREATED;
75 } else { 75 } else {
76 p = to_tcf_nat(pc); 76 p = to_tcf_nat(pc);
77 if (!ovr) { 77 if (!ovr) {
78 tcf_hash_release(pc, bind, &nat_hash_info); 78 tcf_hash_release(pc, bind, &nat_hash_info);
79 return -EEXIST; 79 return -EEXIST;
80 } 80 }
81 } 81 }
82 82
83 spin_lock_bh(&p->tcf_lock); 83 spin_lock_bh(&p->tcf_lock);
84 p->old_addr = parm->old_addr; 84 p->old_addr = parm->old_addr;
85 p->new_addr = parm->new_addr; 85 p->new_addr = parm->new_addr;
86 p->mask = parm->mask; 86 p->mask = parm->mask;
87 p->flags = parm->flags; 87 p->flags = parm->flags;
88 88
89 p->tcf_action = parm->action; 89 p->tcf_action = parm->action;
90 spin_unlock_bh(&p->tcf_lock); 90 spin_unlock_bh(&p->tcf_lock);
91 91
92 if (ret == ACT_P_CREATED) 92 if (ret == ACT_P_CREATED)
93 tcf_hash_insert(pc, &nat_hash_info); 93 tcf_hash_insert(pc, &nat_hash_info);
94 94
95 return ret; 95 return ret;
96 } 96 }
97 97
98 static int tcf_nat_cleanup(struct tc_action *a, int bind) 98 static int tcf_nat_cleanup(struct tc_action *a, int bind)
99 { 99 {
100 struct tcf_nat *p = a->priv; 100 struct tcf_nat *p = a->priv;
101 101
102 return tcf_hash_release(&p->common, bind, &nat_hash_info); 102 return tcf_hash_release(&p->common, bind, &nat_hash_info);
103 } 103 }
104 104
105 static int tcf_nat(struct sk_buff *skb, const struct tc_action *a, 105 static int tcf_nat(struct sk_buff *skb, const struct tc_action *a,
106 struct tcf_result *res) 106 struct tcf_result *res)
107 { 107 {
108 struct tcf_nat *p = a->priv; 108 struct tcf_nat *p = a->priv;
109 struct iphdr *iph; 109 struct iphdr *iph;
110 __be32 old_addr; 110 __be32 old_addr;
111 __be32 new_addr; 111 __be32 new_addr;
112 __be32 mask; 112 __be32 mask;
113 __be32 addr; 113 __be32 addr;
114 int egress; 114 int egress;
115 int action; 115 int action;
116 int ihl; 116 int ihl;
117 int noff; 117 int noff;
118 118
119 spin_lock(&p->tcf_lock); 119 spin_lock(&p->tcf_lock);
120 120
121 p->tcf_tm.lastuse = jiffies; 121 p->tcf_tm.lastuse = jiffies;
122 old_addr = p->old_addr; 122 old_addr = p->old_addr;
123 new_addr = p->new_addr; 123 new_addr = p->new_addr;
124 mask = p->mask; 124 mask = p->mask;
125 egress = p->flags & TCA_NAT_FLAG_EGRESS; 125 egress = p->flags & TCA_NAT_FLAG_EGRESS;
126 action = p->tcf_action; 126 action = p->tcf_action;
127 127
128 bstats_update(&p->tcf_bstats, skb); 128 bstats_update(&p->tcf_bstats, skb);
129 129
130 spin_unlock(&p->tcf_lock); 130 spin_unlock(&p->tcf_lock);
131 131
132 if (unlikely(action == TC_ACT_SHOT)) 132 if (unlikely(action == TC_ACT_SHOT))
133 goto drop; 133 goto drop;
134 134
135 noff = skb_network_offset(skb); 135 noff = skb_network_offset(skb);
136 if (!pskb_may_pull(skb, sizeof(*iph) + noff)) 136 if (!pskb_may_pull(skb, sizeof(*iph) + noff))
137 goto drop; 137 goto drop;
138 138
139 iph = ip_hdr(skb); 139 iph = ip_hdr(skb);
140 140
141 if (egress) 141 if (egress)
142 addr = iph->saddr; 142 addr = iph->saddr;
143 else 143 else
144 addr = iph->daddr; 144 addr = iph->daddr;
145 145
146 if (!((old_addr ^ addr) & mask)) { 146 if (!((old_addr ^ addr) & mask)) {
147 if (skb_cloned(skb) && 147 if (skb_cloned(skb) &&
148 !skb_clone_writable(skb, sizeof(*iph) + noff) && 148 !skb_clone_writable(skb, sizeof(*iph) + noff) &&
149 pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) 149 pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
150 goto drop; 150 goto drop;
151 151
152 new_addr &= mask; 152 new_addr &= mask;
153 new_addr |= addr & ~mask; 153 new_addr |= addr & ~mask;
154 154
155 /* Rewrite IP header */ 155 /* Rewrite IP header */
156 iph = ip_hdr(skb); 156 iph = ip_hdr(skb);
157 if (egress) 157 if (egress)
158 iph->saddr = new_addr; 158 iph->saddr = new_addr;
159 else 159 else
160 iph->daddr = new_addr; 160 iph->daddr = new_addr;
161 161
162 csum_replace4(&iph->check, addr, new_addr); 162 csum_replace4(&iph->check, addr, new_addr);
163 } else if ((iph->frag_off & htons(IP_OFFSET)) || 163 } else if ((iph->frag_off & htons(IP_OFFSET)) ||
164 iph->protocol != IPPROTO_ICMP) { 164 iph->protocol != IPPROTO_ICMP) {
165 goto out; 165 goto out;
166 } 166 }
167 167
168 ihl = iph->ihl * 4; 168 ihl = iph->ihl * 4;
169 169
170 /* It would be nice to share code with stateful NAT. */ 170 /* It would be nice to share code with stateful NAT. */
171 switch (iph->frag_off & htons(IP_OFFSET) ? 0 : iph->protocol) { 171 switch (iph->frag_off & htons(IP_OFFSET) ? 0 : iph->protocol) {
172 case IPPROTO_TCP: 172 case IPPROTO_TCP:
173 { 173 {
174 struct tcphdr *tcph; 174 struct tcphdr *tcph;
175 175
176 if (!pskb_may_pull(skb, ihl + sizeof(*tcph) + noff) || 176 if (!pskb_may_pull(skb, ihl + sizeof(*tcph) + noff) ||
177 (skb_cloned(skb) && 177 (skb_cloned(skb) &&
178 !skb_clone_writable(skb, ihl + sizeof(*tcph) + noff) && 178 !skb_clone_writable(skb, ihl + sizeof(*tcph) + noff) &&
179 pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) 179 pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
180 goto drop; 180 goto drop;
181 181
182 tcph = (void *)(skb_network_header(skb) + ihl); 182 tcph = (void *)(skb_network_header(skb) + ihl);
183 inet_proto_csum_replace4(&tcph->check, skb, addr, new_addr, 1); 183 inet_proto_csum_replace4(&tcph->check, skb, addr, new_addr, 1);
184 break; 184 break;
185 } 185 }
186 case IPPROTO_UDP: 186 case IPPROTO_UDP:
187 { 187 {
188 struct udphdr *udph; 188 struct udphdr *udph;
189 189
190 if (!pskb_may_pull(skb, ihl + sizeof(*udph) + noff) || 190 if (!pskb_may_pull(skb, ihl + sizeof(*udph) + noff) ||
191 (skb_cloned(skb) && 191 (skb_cloned(skb) &&
192 !skb_clone_writable(skb, ihl + sizeof(*udph) + noff) && 192 !skb_clone_writable(skb, ihl + sizeof(*udph) + noff) &&
193 pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) 193 pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
194 goto drop; 194 goto drop;
195 195
196 udph = (void *)(skb_network_header(skb) + ihl); 196 udph = (void *)(skb_network_header(skb) + ihl);
197 if (udph->check || skb->ip_summed == CHECKSUM_PARTIAL) { 197 if (udph->check || skb->ip_summed == CHECKSUM_PARTIAL) {
198 inet_proto_csum_replace4(&udph->check, skb, addr, 198 inet_proto_csum_replace4(&udph->check, skb, addr,
199 new_addr, 1); 199 new_addr, 1);
200 if (!udph->check) 200 if (!udph->check)
201 udph->check = CSUM_MANGLED_0; 201 udph->check = CSUM_MANGLED_0;
202 } 202 }
203 break; 203 break;
204 } 204 }
205 case IPPROTO_ICMP: 205 case IPPROTO_ICMP:
206 { 206 {
207 struct icmphdr *icmph; 207 struct icmphdr *icmph;
208 208
209 if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + noff)) 209 if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + noff))
210 goto drop; 210 goto drop;
211 211
212 icmph = (void *)(skb_network_header(skb) + ihl); 212 icmph = (void *)(skb_network_header(skb) + ihl);
213 213
214 if ((icmph->type != ICMP_DEST_UNREACH) && 214 if ((icmph->type != ICMP_DEST_UNREACH) &&
215 (icmph->type != ICMP_TIME_EXCEEDED) && 215 (icmph->type != ICMP_TIME_EXCEEDED) &&
216 (icmph->type != ICMP_PARAMETERPROB)) 216 (icmph->type != ICMP_PARAMETERPROB))
217 break; 217 break;
218 218
219 if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + sizeof(*iph) + 219 if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + sizeof(*iph) +
220 noff)) 220 noff))
221 goto drop; 221 goto drop;
222 222
223 icmph = (void *)(skb_network_header(skb) + ihl); 223 icmph = (void *)(skb_network_header(skb) + ihl);
224 iph = (void *)(icmph + 1); 224 iph = (void *)(icmph + 1);
225 if (egress) 225 if (egress)
226 addr = iph->daddr; 226 addr = iph->daddr;
227 else 227 else
228 addr = iph->saddr; 228 addr = iph->saddr;
229 229
230 if ((old_addr ^ addr) & mask) 230 if ((old_addr ^ addr) & mask)
231 break; 231 break;
232 232
233 if (skb_cloned(skb) && 233 if (skb_cloned(skb) &&
234 !skb_clone_writable(skb, ihl + sizeof(*icmph) + 234 !skb_clone_writable(skb, ihl + sizeof(*icmph) +
235 sizeof(*iph) + noff) && 235 sizeof(*iph) + noff) &&
236 pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) 236 pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
237 goto drop; 237 goto drop;
238 238
239 icmph = (void *)(skb_network_header(skb) + ihl); 239 icmph = (void *)(skb_network_header(skb) + ihl);
240 iph = (void *)(icmph + 1); 240 iph = (void *)(icmph + 1);
241 241
242 new_addr &= mask; 242 new_addr &= mask;
243 new_addr |= addr & ~mask; 243 new_addr |= addr & ~mask;
244 244
245 /* XXX Fix up the inner checksums. */ 245 /* XXX Fix up the inner checksums. */
246 if (egress) 246 if (egress)
247 iph->daddr = new_addr; 247 iph->daddr = new_addr;
248 else 248 else
249 iph->saddr = new_addr; 249 iph->saddr = new_addr;
250 250
251 inet_proto_csum_replace4(&icmph->checksum, skb, addr, new_addr, 251 inet_proto_csum_replace4(&icmph->checksum, skb, addr, new_addr,
252 0); 252 0);
253 break; 253 break;
254 } 254 }
255 default: 255 default:
256 break; 256 break;
257 } 257 }
258 258
259 out: 259 out:
260 return action; 260 return action;
261 261
262 drop: 262 drop:
263 spin_lock(&p->tcf_lock); 263 spin_lock(&p->tcf_lock);
264 p->tcf_qstats.drops++; 264 p->tcf_qstats.drops++;
265 spin_unlock(&p->tcf_lock); 265 spin_unlock(&p->tcf_lock);
266 return TC_ACT_SHOT; 266 return TC_ACT_SHOT;
267 } 267 }
268 268
269 static int tcf_nat_dump(struct sk_buff *skb, struct tc_action *a, 269 static int tcf_nat_dump(struct sk_buff *skb, struct tc_action *a,
270 int bind, int ref) 270 int bind, int ref)
271 { 271 {
272 unsigned char *b = skb_tail_pointer(skb); 272 unsigned char *b = skb_tail_pointer(skb);
273 struct tcf_nat *p = a->priv; 273 struct tcf_nat *p = a->priv;
274 struct tc_nat opt = { 274 struct tc_nat opt = {
275 .old_addr = p->old_addr, 275 .old_addr = p->old_addr,
276 .new_addr = p->new_addr, 276 .new_addr = p->new_addr,
277 .mask = p->mask, 277 .mask = p->mask,
278 .flags = p->flags, 278 .flags = p->flags,
279 279
280 .index = p->tcf_index, 280 .index = p->tcf_index,
281 .action = p->tcf_action, 281 .action = p->tcf_action,
282 .refcnt = p->tcf_refcnt - ref, 282 .refcnt = p->tcf_refcnt - ref,
283 .bindcnt = p->tcf_bindcnt - bind, 283 .bindcnt = p->tcf_bindcnt - bind,
284 }; 284 };
285 struct tcf_t t; 285 struct tcf_t t;
286 286
287 if (nla_put(skb, TCA_NAT_PARMS, sizeof(opt), &opt)) 287 if (nla_put(skb, TCA_NAT_PARMS, sizeof(opt), &opt))
288 goto nla_put_failure; 288 goto nla_put_failure;
289 t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install); 289 t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install);
290 t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse); 290 t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse);
291 t.expires = jiffies_to_clock_t(p->tcf_tm.expires); 291 t.expires = jiffies_to_clock_t(p->tcf_tm.expires);
292 if (nla_put(skb, TCA_NAT_TM, sizeof(t), &t)) 292 if (nla_put(skb, TCA_NAT_TM, sizeof(t), &t))
293 goto nla_put_failure; 293 goto nla_put_failure;
294 294
295 return skb->len; 295 return skb->len;
296 296
297 nla_put_failure: 297 nla_put_failure:
298 nlmsg_trim(skb, b); 298 nlmsg_trim(skb, b);
299 return -1; 299 return -1;
300 } 300 }
301 301
302 static struct tc_action_ops act_nat_ops = { 302 static struct tc_action_ops act_nat_ops = {
303 .kind = "nat", 303 .kind = "nat",
304 .hinfo = &nat_hash_info, 304 .hinfo = &nat_hash_info,
305 .type = TCA_ACT_NAT, 305 .type = TCA_ACT_NAT,
306 .capab = TCA_CAP_NONE, 306 .capab = TCA_CAP_NONE,
307 .owner = THIS_MODULE, 307 .owner = THIS_MODULE,
308 .act = tcf_nat, 308 .act = tcf_nat,
309 .dump = tcf_nat_dump, 309 .dump = tcf_nat_dump,
310 .cleanup = tcf_nat_cleanup, 310 .cleanup = tcf_nat_cleanup,
311 .init = tcf_nat_init, 311 .init = tcf_nat_init,
312 .walk = tcf_generic_walker
313 }; 312 };
314 313
315 MODULE_DESCRIPTION("Stateless NAT actions"); 314 MODULE_DESCRIPTION("Stateless NAT actions");
316 MODULE_LICENSE("GPL"); 315 MODULE_LICENSE("GPL");
317 316
318 static int __init nat_init_module(void) 317 static int __init nat_init_module(void)
319 { 318 {
320 return tcf_register_action(&act_nat_ops); 319 return tcf_register_action(&act_nat_ops);
321 } 320 }
322 321
323 static void __exit nat_cleanup_module(void) 322 static void __exit nat_cleanup_module(void)
324 { 323 {
325 tcf_unregister_action(&act_nat_ops); 324 tcf_unregister_action(&act_nat_ops);
326 } 325 }
327 326
328 module_init(nat_init_module); 327 module_init(nat_init_module);
329 module_exit(nat_cleanup_module); 328 module_exit(nat_cleanup_module);
330 329
net/sched/act_pedit.c
1 /* 1 /*
2 * net/sched/pedit.c Generic packet editor 2 * net/sched/pedit.c Generic packet editor
3 * 3 *
4 * This program is free software; you can redistribute it and/or 4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License 5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version. 7 * 2 of the License, or (at your option) any later version.
8 * 8 *
9 * Authors: Jamal Hadi Salim (2002-4) 9 * Authors: Jamal Hadi Salim (2002-4)
10 */ 10 */
11 11
12 #include <linux/types.h> 12 #include <linux/types.h>
13 #include <linux/kernel.h> 13 #include <linux/kernel.h>
14 #include <linux/string.h> 14 #include <linux/string.h>
15 #include <linux/errno.h> 15 #include <linux/errno.h>
16 #include <linux/skbuff.h> 16 #include <linux/skbuff.h>
17 #include <linux/rtnetlink.h> 17 #include <linux/rtnetlink.h>
18 #include <linux/module.h> 18 #include <linux/module.h>
19 #include <linux/init.h> 19 #include <linux/init.h>
20 #include <linux/slab.h> 20 #include <linux/slab.h>
21 #include <net/netlink.h> 21 #include <net/netlink.h>
22 #include <net/pkt_sched.h> 22 #include <net/pkt_sched.h>
23 #include <linux/tc_act/tc_pedit.h> 23 #include <linux/tc_act/tc_pedit.h>
24 #include <net/tc_act/tc_pedit.h> 24 #include <net/tc_act/tc_pedit.h>
25 25
26 #define PEDIT_TAB_MASK 15 26 #define PEDIT_TAB_MASK 15
27 static struct tcf_common *tcf_pedit_ht[PEDIT_TAB_MASK + 1]; 27 static struct tcf_common *tcf_pedit_ht[PEDIT_TAB_MASK + 1];
28 static u32 pedit_idx_gen; 28 static u32 pedit_idx_gen;
29 static DEFINE_RWLOCK(pedit_lock); 29 static DEFINE_RWLOCK(pedit_lock);
30 30
31 static struct tcf_hashinfo pedit_hash_info = { 31 static struct tcf_hashinfo pedit_hash_info = {
32 .htab = tcf_pedit_ht, 32 .htab = tcf_pedit_ht,
33 .hmask = PEDIT_TAB_MASK, 33 .hmask = PEDIT_TAB_MASK,
34 .lock = &pedit_lock, 34 .lock = &pedit_lock,
35 }; 35 };
36 36
37 static const struct nla_policy pedit_policy[TCA_PEDIT_MAX + 1] = { 37 static const struct nla_policy pedit_policy[TCA_PEDIT_MAX + 1] = {
38 [TCA_PEDIT_PARMS] = { .len = sizeof(struct tc_pedit) }, 38 [TCA_PEDIT_PARMS] = { .len = sizeof(struct tc_pedit) },
39 }; 39 };
40 40
41 static int tcf_pedit_init(struct net *net, struct nlattr *nla, 41 static int tcf_pedit_init(struct net *net, struct nlattr *nla,
42 struct nlattr *est, struct tc_action *a, 42 struct nlattr *est, struct tc_action *a,
43 int ovr, int bind) 43 int ovr, int bind)
44 { 44 {
45 struct nlattr *tb[TCA_PEDIT_MAX + 1]; 45 struct nlattr *tb[TCA_PEDIT_MAX + 1];
46 struct tc_pedit *parm; 46 struct tc_pedit *parm;
47 int ret = 0, err; 47 int ret = 0, err;
48 struct tcf_pedit *p; 48 struct tcf_pedit *p;
49 struct tcf_common *pc; 49 struct tcf_common *pc;
50 struct tc_pedit_key *keys = NULL; 50 struct tc_pedit_key *keys = NULL;
51 int ksize; 51 int ksize;
52 52
53 if (nla == NULL) 53 if (nla == NULL)
54 return -EINVAL; 54 return -EINVAL;
55 55
56 err = nla_parse_nested(tb, TCA_PEDIT_MAX, nla, pedit_policy); 56 err = nla_parse_nested(tb, TCA_PEDIT_MAX, nla, pedit_policy);
57 if (err < 0) 57 if (err < 0)
58 return err; 58 return err;
59 59
60 if (tb[TCA_PEDIT_PARMS] == NULL) 60 if (tb[TCA_PEDIT_PARMS] == NULL)
61 return -EINVAL; 61 return -EINVAL;
62 parm = nla_data(tb[TCA_PEDIT_PARMS]); 62 parm = nla_data(tb[TCA_PEDIT_PARMS]);
63 ksize = parm->nkeys * sizeof(struct tc_pedit_key); 63 ksize = parm->nkeys * sizeof(struct tc_pedit_key);
64 if (nla_len(tb[TCA_PEDIT_PARMS]) < sizeof(*parm) + ksize) 64 if (nla_len(tb[TCA_PEDIT_PARMS]) < sizeof(*parm) + ksize)
65 return -EINVAL; 65 return -EINVAL;
66 66
67 pc = tcf_hash_check(parm->index, a, bind, &pedit_hash_info); 67 pc = tcf_hash_check(parm->index, a, bind, &pedit_hash_info);
68 if (!pc) { 68 if (!pc) {
69 if (!parm->nkeys) 69 if (!parm->nkeys)
70 return -EINVAL; 70 return -EINVAL;
71 pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind, 71 pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind,
72 &pedit_idx_gen, &pedit_hash_info); 72 &pedit_idx_gen, &pedit_hash_info);
73 if (IS_ERR(pc)) 73 if (IS_ERR(pc))
74 return PTR_ERR(pc); 74 return PTR_ERR(pc);
75 p = to_pedit(pc); 75 p = to_pedit(pc);
76 keys = kmalloc(ksize, GFP_KERNEL); 76 keys = kmalloc(ksize, GFP_KERNEL);
77 if (keys == NULL) { 77 if (keys == NULL) {
78 if (est) 78 if (est)
79 gen_kill_estimator(&pc->tcfc_bstats, 79 gen_kill_estimator(&pc->tcfc_bstats,
80 &pc->tcfc_rate_est); 80 &pc->tcfc_rate_est);
81 kfree_rcu(pc, tcfc_rcu); 81 kfree_rcu(pc, tcfc_rcu);
82 return -ENOMEM; 82 return -ENOMEM;
83 } 83 }
84 ret = ACT_P_CREATED; 84 ret = ACT_P_CREATED;
85 } else { 85 } else {
86 p = to_pedit(pc); 86 p = to_pedit(pc);
87 if (!ovr) { 87 if (!ovr) {
88 tcf_hash_release(pc, bind, &pedit_hash_info); 88 tcf_hash_release(pc, bind, &pedit_hash_info);
89 return -EEXIST; 89 return -EEXIST;
90 } 90 }
91 if (p->tcfp_nkeys && p->tcfp_nkeys != parm->nkeys) { 91 if (p->tcfp_nkeys && p->tcfp_nkeys != parm->nkeys) {
92 keys = kmalloc(ksize, GFP_KERNEL); 92 keys = kmalloc(ksize, GFP_KERNEL);
93 if (keys == NULL) 93 if (keys == NULL)
94 return -ENOMEM; 94 return -ENOMEM;
95 } 95 }
96 } 96 }
97 97
98 spin_lock_bh(&p->tcf_lock); 98 spin_lock_bh(&p->tcf_lock);
99 p->tcfp_flags = parm->flags; 99 p->tcfp_flags = parm->flags;
100 p->tcf_action = parm->action; 100 p->tcf_action = parm->action;
101 if (keys) { 101 if (keys) {
102 kfree(p->tcfp_keys); 102 kfree(p->tcfp_keys);
103 p->tcfp_keys = keys; 103 p->tcfp_keys = keys;
104 p->tcfp_nkeys = parm->nkeys; 104 p->tcfp_nkeys = parm->nkeys;
105 } 105 }
106 memcpy(p->tcfp_keys, parm->keys, ksize); 106 memcpy(p->tcfp_keys, parm->keys, ksize);
107 spin_unlock_bh(&p->tcf_lock); 107 spin_unlock_bh(&p->tcf_lock);
108 if (ret == ACT_P_CREATED) 108 if (ret == ACT_P_CREATED)
109 tcf_hash_insert(pc, &pedit_hash_info); 109 tcf_hash_insert(pc, &pedit_hash_info);
110 return ret; 110 return ret;
111 } 111 }
112 112
113 static int tcf_pedit_cleanup(struct tc_action *a, int bind) 113 static int tcf_pedit_cleanup(struct tc_action *a, int bind)
114 { 114 {
115 struct tcf_pedit *p = a->priv; 115 struct tcf_pedit *p = a->priv;
116 116
117 if (p) { 117 if (p) {
118 struct tc_pedit_key *keys = p->tcfp_keys; 118 struct tc_pedit_key *keys = p->tcfp_keys;
119 if (tcf_hash_release(&p->common, bind, &pedit_hash_info)) { 119 if (tcf_hash_release(&p->common, bind, &pedit_hash_info)) {
120 kfree(keys); 120 kfree(keys);
121 return 1; 121 return 1;
122 } 122 }
123 } 123 }
124 return 0; 124 return 0;
125 } 125 }
126 126
127 static int tcf_pedit(struct sk_buff *skb, const struct tc_action *a, 127 static int tcf_pedit(struct sk_buff *skb, const struct tc_action *a,
128 struct tcf_result *res) 128 struct tcf_result *res)
129 { 129 {
130 struct tcf_pedit *p = a->priv; 130 struct tcf_pedit *p = a->priv;
131 int i, munged = 0; 131 int i, munged = 0;
132 unsigned int off; 132 unsigned int off;
133 133
134 if (skb_unclone(skb, GFP_ATOMIC)) 134 if (skb_unclone(skb, GFP_ATOMIC))
135 return p->tcf_action; 135 return p->tcf_action;
136 136
137 off = skb_network_offset(skb); 137 off = skb_network_offset(skb);
138 138
139 spin_lock(&p->tcf_lock); 139 spin_lock(&p->tcf_lock);
140 140
141 p->tcf_tm.lastuse = jiffies; 141 p->tcf_tm.lastuse = jiffies;
142 142
143 if (p->tcfp_nkeys > 0) { 143 if (p->tcfp_nkeys > 0) {
144 struct tc_pedit_key *tkey = p->tcfp_keys; 144 struct tc_pedit_key *tkey = p->tcfp_keys;
145 145
146 for (i = p->tcfp_nkeys; i > 0; i--, tkey++) { 146 for (i = p->tcfp_nkeys; i > 0; i--, tkey++) {
147 u32 *ptr, _data; 147 u32 *ptr, _data;
148 int offset = tkey->off; 148 int offset = tkey->off;
149 149
150 if (tkey->offmask) { 150 if (tkey->offmask) {
151 char *d, _d; 151 char *d, _d;
152 152
153 d = skb_header_pointer(skb, off + tkey->at, 1, 153 d = skb_header_pointer(skb, off + tkey->at, 1,
154 &_d); 154 &_d);
155 if (!d) 155 if (!d)
156 goto bad; 156 goto bad;
157 offset += (*d & tkey->offmask) >> tkey->shift; 157 offset += (*d & tkey->offmask) >> tkey->shift;
158 } 158 }
159 159
160 if (offset % 4) { 160 if (offset % 4) {
161 pr_info("tc filter pedit" 161 pr_info("tc filter pedit"
162 " offset must be on 32 bit boundaries\n"); 162 " offset must be on 32 bit boundaries\n");
163 goto bad; 163 goto bad;
164 } 164 }
165 if (offset > 0 && offset > skb->len) { 165 if (offset > 0 && offset > skb->len) {
166 pr_info("tc filter pedit" 166 pr_info("tc filter pedit"
167 " offset %d can't exceed pkt length %d\n", 167 " offset %d can't exceed pkt length %d\n",
168 offset, skb->len); 168 offset, skb->len);
169 goto bad; 169 goto bad;
170 } 170 }
171 171
172 ptr = skb_header_pointer(skb, off + offset, 4, &_data); 172 ptr = skb_header_pointer(skb, off + offset, 4, &_data);
173 if (!ptr) 173 if (!ptr)
174 goto bad; 174 goto bad;
175 /* just do it, baby */ 175 /* just do it, baby */
176 *ptr = ((*ptr & tkey->mask) ^ tkey->val); 176 *ptr = ((*ptr & tkey->mask) ^ tkey->val);
177 if (ptr == &_data) 177 if (ptr == &_data)
178 skb_store_bits(skb, off + offset, ptr, 4); 178 skb_store_bits(skb, off + offset, ptr, 4);
179 munged++; 179 munged++;
180 } 180 }
181 181
182 if (munged) 182 if (munged)
183 skb->tc_verd = SET_TC_MUNGED(skb->tc_verd); 183 skb->tc_verd = SET_TC_MUNGED(skb->tc_verd);
184 goto done; 184 goto done;
185 } else 185 } else
186 WARN(1, "pedit BUG: index %d\n", p->tcf_index); 186 WARN(1, "pedit BUG: index %d\n", p->tcf_index);
187 187
188 bad: 188 bad:
189 p->tcf_qstats.overlimits++; 189 p->tcf_qstats.overlimits++;
190 done: 190 done:
191 bstats_update(&p->tcf_bstats, skb); 191 bstats_update(&p->tcf_bstats, skb);
192 spin_unlock(&p->tcf_lock); 192 spin_unlock(&p->tcf_lock);
193 return p->tcf_action; 193 return p->tcf_action;
194 } 194 }
195 195
196 static int tcf_pedit_dump(struct sk_buff *skb, struct tc_action *a, 196 static int tcf_pedit_dump(struct sk_buff *skb, struct tc_action *a,
197 int bind, int ref) 197 int bind, int ref)
198 { 198 {
199 unsigned char *b = skb_tail_pointer(skb); 199 unsigned char *b = skb_tail_pointer(skb);
200 struct tcf_pedit *p = a->priv; 200 struct tcf_pedit *p = a->priv;
201 struct tc_pedit *opt; 201 struct tc_pedit *opt;
202 struct tcf_t t; 202 struct tcf_t t;
203 int s; 203 int s;
204 204
205 s = sizeof(*opt) + p->tcfp_nkeys * sizeof(struct tc_pedit_key); 205 s = sizeof(*opt) + p->tcfp_nkeys * sizeof(struct tc_pedit_key);
206 206
207 /* netlink spinlocks held above us - must use ATOMIC */ 207 /* netlink spinlocks held above us - must use ATOMIC */
208 opt = kzalloc(s, GFP_ATOMIC); 208 opt = kzalloc(s, GFP_ATOMIC);
209 if (unlikely(!opt)) 209 if (unlikely(!opt))
210 return -ENOBUFS; 210 return -ENOBUFS;
211 211
212 memcpy(opt->keys, p->tcfp_keys, 212 memcpy(opt->keys, p->tcfp_keys,
213 p->tcfp_nkeys * sizeof(struct tc_pedit_key)); 213 p->tcfp_nkeys * sizeof(struct tc_pedit_key));
214 opt->index = p->tcf_index; 214 opt->index = p->tcf_index;
215 opt->nkeys = p->tcfp_nkeys; 215 opt->nkeys = p->tcfp_nkeys;
216 opt->flags = p->tcfp_flags; 216 opt->flags = p->tcfp_flags;
217 opt->action = p->tcf_action; 217 opt->action = p->tcf_action;
218 opt->refcnt = p->tcf_refcnt - ref; 218 opt->refcnt = p->tcf_refcnt - ref;
219 opt->bindcnt = p->tcf_bindcnt - bind; 219 opt->bindcnt = p->tcf_bindcnt - bind;
220 220
221 if (nla_put(skb, TCA_PEDIT_PARMS, s, opt)) 221 if (nla_put(skb, TCA_PEDIT_PARMS, s, opt))
222 goto nla_put_failure; 222 goto nla_put_failure;
223 t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install); 223 t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install);
224 t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse); 224 t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse);
225 t.expires = jiffies_to_clock_t(p->tcf_tm.expires); 225 t.expires = jiffies_to_clock_t(p->tcf_tm.expires);
226 if (nla_put(skb, TCA_PEDIT_TM, sizeof(t), &t)) 226 if (nla_put(skb, TCA_PEDIT_TM, sizeof(t), &t))
227 goto nla_put_failure; 227 goto nla_put_failure;
228 kfree(opt); 228 kfree(opt);
229 return skb->len; 229 return skb->len;
230 230
231 nla_put_failure: 231 nla_put_failure:
232 nlmsg_trim(skb, b); 232 nlmsg_trim(skb, b);
233 kfree(opt); 233 kfree(opt);
234 return -1; 234 return -1;
235 } 235 }
236 236
237 static struct tc_action_ops act_pedit_ops = { 237 static struct tc_action_ops act_pedit_ops = {
238 .kind = "pedit", 238 .kind = "pedit",
239 .hinfo = &pedit_hash_info, 239 .hinfo = &pedit_hash_info,
240 .type = TCA_ACT_PEDIT, 240 .type = TCA_ACT_PEDIT,
241 .capab = TCA_CAP_NONE, 241 .capab = TCA_CAP_NONE,
242 .owner = THIS_MODULE, 242 .owner = THIS_MODULE,
243 .act = tcf_pedit, 243 .act = tcf_pedit,
244 .dump = tcf_pedit_dump, 244 .dump = tcf_pedit_dump,
245 .cleanup = tcf_pedit_cleanup, 245 .cleanup = tcf_pedit_cleanup,
246 .init = tcf_pedit_init, 246 .init = tcf_pedit_init,
247 .walk = tcf_generic_walker
248 }; 247 };
249 248
250 MODULE_AUTHOR("Jamal Hadi Salim(2002-4)"); 249 MODULE_AUTHOR("Jamal Hadi Salim(2002-4)");
251 MODULE_DESCRIPTION("Generic Packet Editor actions"); 250 MODULE_DESCRIPTION("Generic Packet Editor actions");
252 MODULE_LICENSE("GPL"); 251 MODULE_LICENSE("GPL");
253 252
254 static int __init pedit_init_module(void) 253 static int __init pedit_init_module(void)
255 { 254 {
256 return tcf_register_action(&act_pedit_ops); 255 return tcf_register_action(&act_pedit_ops);
257 } 256 }
258 257
259 static void __exit pedit_cleanup_module(void) 258 static void __exit pedit_cleanup_module(void)
260 { 259 {
261 tcf_unregister_action(&act_pedit_ops); 260 tcf_unregister_action(&act_pedit_ops);
262 } 261 }
263 262
264 module_init(pedit_init_module); 263 module_init(pedit_init_module);
265 module_exit(pedit_cleanup_module); 264 module_exit(pedit_cleanup_module);
266 265
267 266
net/sched/act_simple.c
1 /* 1 /*
2 * net/sched/simp.c Simple example of an action 2 * net/sched/simp.c Simple example of an action
3 * 3 *
4 * This program is free software; you can redistribute it and/or 4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License 5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version. 7 * 2 of the License, or (at your option) any later version.
8 * 8 *
9 * Authors: Jamal Hadi Salim (2005-8) 9 * Authors: Jamal Hadi Salim (2005-8)
10 * 10 *
11 */ 11 */
12 12
13 #include <linux/module.h> 13 #include <linux/module.h>
14 #include <linux/slab.h> 14 #include <linux/slab.h>
15 #include <linux/init.h> 15 #include <linux/init.h>
16 #include <linux/kernel.h> 16 #include <linux/kernel.h>
17 #include <linux/skbuff.h> 17 #include <linux/skbuff.h>
18 #include <linux/rtnetlink.h> 18 #include <linux/rtnetlink.h>
19 #include <net/netlink.h> 19 #include <net/netlink.h>
20 #include <net/pkt_sched.h> 20 #include <net/pkt_sched.h>
21 21
22 #define TCA_ACT_SIMP 22 22 #define TCA_ACT_SIMP 22
23 23
24 #include <linux/tc_act/tc_defact.h> 24 #include <linux/tc_act/tc_defact.h>
25 #include <net/tc_act/tc_defact.h> 25 #include <net/tc_act/tc_defact.h>
26 26
27 #define SIMP_TAB_MASK 7 27 #define SIMP_TAB_MASK 7
28 static struct tcf_common *tcf_simp_ht[SIMP_TAB_MASK + 1]; 28 static struct tcf_common *tcf_simp_ht[SIMP_TAB_MASK + 1];
29 static u32 simp_idx_gen; 29 static u32 simp_idx_gen;
30 static DEFINE_RWLOCK(simp_lock); 30 static DEFINE_RWLOCK(simp_lock);
31 31
32 static struct tcf_hashinfo simp_hash_info = { 32 static struct tcf_hashinfo simp_hash_info = {
33 .htab = tcf_simp_ht, 33 .htab = tcf_simp_ht,
34 .hmask = SIMP_TAB_MASK, 34 .hmask = SIMP_TAB_MASK,
35 .lock = &simp_lock, 35 .lock = &simp_lock,
36 }; 36 };
37 37
38 #define SIMP_MAX_DATA 32 38 #define SIMP_MAX_DATA 32
39 static int tcf_simp(struct sk_buff *skb, const struct tc_action *a, 39 static int tcf_simp(struct sk_buff *skb, const struct tc_action *a,
40 struct tcf_result *res) 40 struct tcf_result *res)
41 { 41 {
42 struct tcf_defact *d = a->priv; 42 struct tcf_defact *d = a->priv;
43 43
44 spin_lock(&d->tcf_lock); 44 spin_lock(&d->tcf_lock);
45 d->tcf_tm.lastuse = jiffies; 45 d->tcf_tm.lastuse = jiffies;
46 bstats_update(&d->tcf_bstats, skb); 46 bstats_update(&d->tcf_bstats, skb);
47 47
48 /* print policy string followed by _ then packet count 48 /* print policy string followed by _ then packet count
49 * Example if this was the 3rd packet and the string was "hello" 49 * Example if this was the 3rd packet and the string was "hello"
50 * then it would look like "hello_3" (without quotes) 50 * then it would look like "hello_3" (without quotes)
51 */ 51 */
52 pr_info("simple: %s_%d\n", 52 pr_info("simple: %s_%d\n",
53 (char *)d->tcfd_defdata, d->tcf_bstats.packets); 53 (char *)d->tcfd_defdata, d->tcf_bstats.packets);
54 spin_unlock(&d->tcf_lock); 54 spin_unlock(&d->tcf_lock);
55 return d->tcf_action; 55 return d->tcf_action;
56 } 56 }
57 57
58 static int tcf_simp_release(struct tcf_defact *d, int bind) 58 static int tcf_simp_release(struct tcf_defact *d, int bind)
59 { 59 {
60 int ret = 0; 60 int ret = 0;
61 if (d) { 61 if (d) {
62 if (bind) 62 if (bind)
63 d->tcf_bindcnt--; 63 d->tcf_bindcnt--;
64 d->tcf_refcnt--; 64 d->tcf_refcnt--;
65 if (d->tcf_bindcnt <= 0 && d->tcf_refcnt <= 0) { 65 if (d->tcf_bindcnt <= 0 && d->tcf_refcnt <= 0) {
66 kfree(d->tcfd_defdata); 66 kfree(d->tcfd_defdata);
67 tcf_hash_destroy(&d->common, &simp_hash_info); 67 tcf_hash_destroy(&d->common, &simp_hash_info);
68 ret = 1; 68 ret = 1;
69 } 69 }
70 } 70 }
71 return ret; 71 return ret;
72 } 72 }
73 73
74 static int alloc_defdata(struct tcf_defact *d, char *defdata) 74 static int alloc_defdata(struct tcf_defact *d, char *defdata)
75 { 75 {
76 d->tcfd_defdata = kzalloc(SIMP_MAX_DATA, GFP_KERNEL); 76 d->tcfd_defdata = kzalloc(SIMP_MAX_DATA, GFP_KERNEL);
77 if (unlikely(!d->tcfd_defdata)) 77 if (unlikely(!d->tcfd_defdata))
78 return -ENOMEM; 78 return -ENOMEM;
79 strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA); 79 strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA);
80 return 0; 80 return 0;
81 } 81 }
82 82
83 static void reset_policy(struct tcf_defact *d, char *defdata, 83 static void reset_policy(struct tcf_defact *d, char *defdata,
84 struct tc_defact *p) 84 struct tc_defact *p)
85 { 85 {
86 spin_lock_bh(&d->tcf_lock); 86 spin_lock_bh(&d->tcf_lock);
87 d->tcf_action = p->action; 87 d->tcf_action = p->action;
88 memset(d->tcfd_defdata, 0, SIMP_MAX_DATA); 88 memset(d->tcfd_defdata, 0, SIMP_MAX_DATA);
89 strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA); 89 strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA);
90 spin_unlock_bh(&d->tcf_lock); 90 spin_unlock_bh(&d->tcf_lock);
91 } 91 }
92 92
93 static const struct nla_policy simple_policy[TCA_DEF_MAX + 1] = { 93 static const struct nla_policy simple_policy[TCA_DEF_MAX + 1] = {
94 [TCA_DEF_PARMS] = { .len = sizeof(struct tc_defact) }, 94 [TCA_DEF_PARMS] = { .len = sizeof(struct tc_defact) },
95 [TCA_DEF_DATA] = { .type = NLA_STRING, .len = SIMP_MAX_DATA }, 95 [TCA_DEF_DATA] = { .type = NLA_STRING, .len = SIMP_MAX_DATA },
96 }; 96 };
97 97
98 static int tcf_simp_init(struct net *net, struct nlattr *nla, 98 static int tcf_simp_init(struct net *net, struct nlattr *nla,
99 struct nlattr *est, struct tc_action *a, 99 struct nlattr *est, struct tc_action *a,
100 int ovr, int bind) 100 int ovr, int bind)
101 { 101 {
102 struct nlattr *tb[TCA_DEF_MAX + 1]; 102 struct nlattr *tb[TCA_DEF_MAX + 1];
103 struct tc_defact *parm; 103 struct tc_defact *parm;
104 struct tcf_defact *d; 104 struct tcf_defact *d;
105 struct tcf_common *pc; 105 struct tcf_common *pc;
106 char *defdata; 106 char *defdata;
107 int ret = 0, err; 107 int ret = 0, err;
108 108
109 if (nla == NULL) 109 if (nla == NULL)
110 return -EINVAL; 110 return -EINVAL;
111 111
112 err = nla_parse_nested(tb, TCA_DEF_MAX, nla, simple_policy); 112 err = nla_parse_nested(tb, TCA_DEF_MAX, nla, simple_policy);
113 if (err < 0) 113 if (err < 0)
114 return err; 114 return err;
115 115
116 if (tb[TCA_DEF_PARMS] == NULL) 116 if (tb[TCA_DEF_PARMS] == NULL)
117 return -EINVAL; 117 return -EINVAL;
118 118
119 if (tb[TCA_DEF_DATA] == NULL) 119 if (tb[TCA_DEF_DATA] == NULL)
120 return -EINVAL; 120 return -EINVAL;
121 121
122 parm = nla_data(tb[TCA_DEF_PARMS]); 122 parm = nla_data(tb[TCA_DEF_PARMS]);
123 defdata = nla_data(tb[TCA_DEF_DATA]); 123 defdata = nla_data(tb[TCA_DEF_DATA]);
124 124
125 pc = tcf_hash_check(parm->index, a, bind, &simp_hash_info); 125 pc = tcf_hash_check(parm->index, a, bind, &simp_hash_info);
126 if (!pc) { 126 if (!pc) {
127 pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind, 127 pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind,
128 &simp_idx_gen, &simp_hash_info); 128 &simp_idx_gen, &simp_hash_info);
129 if (IS_ERR(pc)) 129 if (IS_ERR(pc))
130 return PTR_ERR(pc); 130 return PTR_ERR(pc);
131 131
132 d = to_defact(pc); 132 d = to_defact(pc);
133 ret = alloc_defdata(d, defdata); 133 ret = alloc_defdata(d, defdata);
134 if (ret < 0) { 134 if (ret < 0) {
135 if (est) 135 if (est)
136 gen_kill_estimator(&pc->tcfc_bstats, 136 gen_kill_estimator(&pc->tcfc_bstats,
137 &pc->tcfc_rate_est); 137 &pc->tcfc_rate_est);
138 kfree_rcu(pc, tcfc_rcu); 138 kfree_rcu(pc, tcfc_rcu);
139 return ret; 139 return ret;
140 } 140 }
141 d->tcf_action = parm->action; 141 d->tcf_action = parm->action;
142 ret = ACT_P_CREATED; 142 ret = ACT_P_CREATED;
143 } else { 143 } else {
144 d = to_defact(pc); 144 d = to_defact(pc);
145 if (!ovr) { 145 if (!ovr) {
146 tcf_simp_release(d, bind); 146 tcf_simp_release(d, bind);
147 return -EEXIST; 147 return -EEXIST;
148 } 148 }
149 reset_policy(d, defdata, parm); 149 reset_policy(d, defdata, parm);
150 } 150 }
151 151
152 if (ret == ACT_P_CREATED) 152 if (ret == ACT_P_CREATED)
153 tcf_hash_insert(pc, &simp_hash_info); 153 tcf_hash_insert(pc, &simp_hash_info);
154 return ret; 154 return ret;
155 } 155 }
156 156
157 static int tcf_simp_cleanup(struct tc_action *a, int bind) 157 static int tcf_simp_cleanup(struct tc_action *a, int bind)
158 { 158 {
159 struct tcf_defact *d = a->priv; 159 struct tcf_defact *d = a->priv;
160 160
161 if (d) 161 if (d)
162 return tcf_simp_release(d, bind); 162 return tcf_simp_release(d, bind);
163 return 0; 163 return 0;
164 } 164 }
165 165
166 static int tcf_simp_dump(struct sk_buff *skb, struct tc_action *a, 166 static int tcf_simp_dump(struct sk_buff *skb, struct tc_action *a,
167 int bind, int ref) 167 int bind, int ref)
168 { 168 {
169 unsigned char *b = skb_tail_pointer(skb); 169 unsigned char *b = skb_tail_pointer(skb);
170 struct tcf_defact *d = a->priv; 170 struct tcf_defact *d = a->priv;
171 struct tc_defact opt = { 171 struct tc_defact opt = {
172 .index = d->tcf_index, 172 .index = d->tcf_index,
173 .refcnt = d->tcf_refcnt - ref, 173 .refcnt = d->tcf_refcnt - ref,
174 .bindcnt = d->tcf_bindcnt - bind, 174 .bindcnt = d->tcf_bindcnt - bind,
175 .action = d->tcf_action, 175 .action = d->tcf_action,
176 }; 176 };
177 struct tcf_t t; 177 struct tcf_t t;
178 178
179 if (nla_put(skb, TCA_DEF_PARMS, sizeof(opt), &opt) || 179 if (nla_put(skb, TCA_DEF_PARMS, sizeof(opt), &opt) ||
180 nla_put_string(skb, TCA_DEF_DATA, d->tcfd_defdata)) 180 nla_put_string(skb, TCA_DEF_DATA, d->tcfd_defdata))
181 goto nla_put_failure; 181 goto nla_put_failure;
182 t.install = jiffies_to_clock_t(jiffies - d->tcf_tm.install); 182 t.install = jiffies_to_clock_t(jiffies - d->tcf_tm.install);
183 t.lastuse = jiffies_to_clock_t(jiffies - d->tcf_tm.lastuse); 183 t.lastuse = jiffies_to_clock_t(jiffies - d->tcf_tm.lastuse);
184 t.expires = jiffies_to_clock_t(d->tcf_tm.expires); 184 t.expires = jiffies_to_clock_t(d->tcf_tm.expires);
185 if (nla_put(skb, TCA_DEF_TM, sizeof(t), &t)) 185 if (nla_put(skb, TCA_DEF_TM, sizeof(t), &t))
186 goto nla_put_failure; 186 goto nla_put_failure;
187 return skb->len; 187 return skb->len;
188 188
189 nla_put_failure: 189 nla_put_failure:
190 nlmsg_trim(skb, b); 190 nlmsg_trim(skb, b);
191 return -1; 191 return -1;
192 } 192 }
193 193
194 static struct tc_action_ops act_simp_ops = { 194 static struct tc_action_ops act_simp_ops = {
195 .kind = "simple", 195 .kind = "simple",
196 .hinfo = &simp_hash_info, 196 .hinfo = &simp_hash_info,
197 .type = TCA_ACT_SIMP, 197 .type = TCA_ACT_SIMP,
198 .capab = TCA_CAP_NONE, 198 .capab = TCA_CAP_NONE,
199 .owner = THIS_MODULE, 199 .owner = THIS_MODULE,
200 .act = tcf_simp, 200 .act = tcf_simp,
201 .dump = tcf_simp_dump, 201 .dump = tcf_simp_dump,
202 .cleanup = tcf_simp_cleanup, 202 .cleanup = tcf_simp_cleanup,
203 .init = tcf_simp_init, 203 .init = tcf_simp_init,
204 .walk = tcf_generic_walker,
205 }; 204 };
206 205
207 MODULE_AUTHOR("Jamal Hadi Salim(2005)"); 206 MODULE_AUTHOR("Jamal Hadi Salim(2005)");
208 MODULE_DESCRIPTION("Simple example action"); 207 MODULE_DESCRIPTION("Simple example action");
209 MODULE_LICENSE("GPL"); 208 MODULE_LICENSE("GPL");
210 209
211 static int __init simp_init_module(void) 210 static int __init simp_init_module(void)
212 { 211 {
213 int ret = tcf_register_action(&act_simp_ops); 212 int ret = tcf_register_action(&act_simp_ops);
214 if (!ret) 213 if (!ret)
215 pr_info("Simple TC action Loaded\n"); 214 pr_info("Simple TC action Loaded\n");
216 return ret; 215 return ret;
217 } 216 }
218 217
219 static void __exit simp_cleanup_module(void) 218 static void __exit simp_cleanup_module(void)
220 { 219 {
221 tcf_unregister_action(&act_simp_ops); 220 tcf_unregister_action(&act_simp_ops);
222 } 221 }
223 222
224 module_init(simp_init_module); 223 module_init(simp_init_module);
225 module_exit(simp_cleanup_module); 224 module_exit(simp_cleanup_module);
226 225
net/sched/act_skbedit.c
1 /* 1 /*
2 * Copyright (c) 2008, Intel Corporation. 2 * Copyright (c) 2008, Intel Corporation.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify it 4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License, 5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation. 6 * version 2, as published by the Free Software Foundation.
7 * 7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT 8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details. 11 * more details.
12 * 12 *
13 * You should have received a copy of the GNU General Public License along with 13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple 14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15 * Place - Suite 330, Boston, MA 02111-1307 USA. 15 * Place - Suite 330, Boston, MA 02111-1307 USA.
16 * 16 *
17 * Author: Alexander Duyck <alexander.h.duyck@intel.com> 17 * Author: Alexander Duyck <alexander.h.duyck@intel.com>
18 */ 18 */
19 19
20 #include <linux/module.h> 20 #include <linux/module.h>
21 #include <linux/init.h> 21 #include <linux/init.h>
22 #include <linux/kernel.h> 22 #include <linux/kernel.h>
23 #include <linux/skbuff.h> 23 #include <linux/skbuff.h>
24 #include <linux/rtnetlink.h> 24 #include <linux/rtnetlink.h>
25 #include <net/netlink.h> 25 #include <net/netlink.h>
26 #include <net/pkt_sched.h> 26 #include <net/pkt_sched.h>
27 27
28 #include <linux/tc_act/tc_skbedit.h> 28 #include <linux/tc_act/tc_skbedit.h>
29 #include <net/tc_act/tc_skbedit.h> 29 #include <net/tc_act/tc_skbedit.h>
30 30
31 #define SKBEDIT_TAB_MASK 15 31 #define SKBEDIT_TAB_MASK 15
32 static struct tcf_common *tcf_skbedit_ht[SKBEDIT_TAB_MASK + 1]; 32 static struct tcf_common *tcf_skbedit_ht[SKBEDIT_TAB_MASK + 1];
33 static u32 skbedit_idx_gen; 33 static u32 skbedit_idx_gen;
34 static DEFINE_RWLOCK(skbedit_lock); 34 static DEFINE_RWLOCK(skbedit_lock);
35 35
36 static struct tcf_hashinfo skbedit_hash_info = { 36 static struct tcf_hashinfo skbedit_hash_info = {
37 .htab = tcf_skbedit_ht, 37 .htab = tcf_skbedit_ht,
38 .hmask = SKBEDIT_TAB_MASK, 38 .hmask = SKBEDIT_TAB_MASK,
39 .lock = &skbedit_lock, 39 .lock = &skbedit_lock,
40 }; 40 };
41 41
42 static int tcf_skbedit(struct sk_buff *skb, const struct tc_action *a, 42 static int tcf_skbedit(struct sk_buff *skb, const struct tc_action *a,
43 struct tcf_result *res) 43 struct tcf_result *res)
44 { 44 {
45 struct tcf_skbedit *d = a->priv; 45 struct tcf_skbedit *d = a->priv;
46 46
47 spin_lock(&d->tcf_lock); 47 spin_lock(&d->tcf_lock);
48 d->tcf_tm.lastuse = jiffies; 48 d->tcf_tm.lastuse = jiffies;
49 bstats_update(&d->tcf_bstats, skb); 49 bstats_update(&d->tcf_bstats, skb);
50 50
51 if (d->flags & SKBEDIT_F_PRIORITY) 51 if (d->flags & SKBEDIT_F_PRIORITY)
52 skb->priority = d->priority; 52 skb->priority = d->priority;
53 if (d->flags & SKBEDIT_F_QUEUE_MAPPING && 53 if (d->flags & SKBEDIT_F_QUEUE_MAPPING &&
54 skb->dev->real_num_tx_queues > d->queue_mapping) 54 skb->dev->real_num_tx_queues > d->queue_mapping)
55 skb_set_queue_mapping(skb, d->queue_mapping); 55 skb_set_queue_mapping(skb, d->queue_mapping);
56 if (d->flags & SKBEDIT_F_MARK) 56 if (d->flags & SKBEDIT_F_MARK)
57 skb->mark = d->mark; 57 skb->mark = d->mark;
58 58
59 spin_unlock(&d->tcf_lock); 59 spin_unlock(&d->tcf_lock);
60 return d->tcf_action; 60 return d->tcf_action;
61 } 61 }
62 62
63 static const struct nla_policy skbedit_policy[TCA_SKBEDIT_MAX + 1] = { 63 static const struct nla_policy skbedit_policy[TCA_SKBEDIT_MAX + 1] = {
64 [TCA_SKBEDIT_PARMS] = { .len = sizeof(struct tc_skbedit) }, 64 [TCA_SKBEDIT_PARMS] = { .len = sizeof(struct tc_skbedit) },
65 [TCA_SKBEDIT_PRIORITY] = { .len = sizeof(u32) }, 65 [TCA_SKBEDIT_PRIORITY] = { .len = sizeof(u32) },
66 [TCA_SKBEDIT_QUEUE_MAPPING] = { .len = sizeof(u16) }, 66 [TCA_SKBEDIT_QUEUE_MAPPING] = { .len = sizeof(u16) },
67 [TCA_SKBEDIT_MARK] = { .len = sizeof(u32) }, 67 [TCA_SKBEDIT_MARK] = { .len = sizeof(u32) },
68 }; 68 };
69 69
70 static int tcf_skbedit_init(struct net *net, struct nlattr *nla, 70 static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
71 struct nlattr *est, struct tc_action *a, 71 struct nlattr *est, struct tc_action *a,
72 int ovr, int bind) 72 int ovr, int bind)
73 { 73 {
74 struct nlattr *tb[TCA_SKBEDIT_MAX + 1]; 74 struct nlattr *tb[TCA_SKBEDIT_MAX + 1];
75 struct tc_skbedit *parm; 75 struct tc_skbedit *parm;
76 struct tcf_skbedit *d; 76 struct tcf_skbedit *d;
77 struct tcf_common *pc; 77 struct tcf_common *pc;
78 u32 flags = 0, *priority = NULL, *mark = NULL; 78 u32 flags = 0, *priority = NULL, *mark = NULL;
79 u16 *queue_mapping = NULL; 79 u16 *queue_mapping = NULL;
80 int ret = 0, err; 80 int ret = 0, err;
81 81
82 if (nla == NULL) 82 if (nla == NULL)
83 return -EINVAL; 83 return -EINVAL;
84 84
85 err = nla_parse_nested(tb, TCA_SKBEDIT_MAX, nla, skbedit_policy); 85 err = nla_parse_nested(tb, TCA_SKBEDIT_MAX, nla, skbedit_policy);
86 if (err < 0) 86 if (err < 0)
87 return err; 87 return err;
88 88
89 if (tb[TCA_SKBEDIT_PARMS] == NULL) 89 if (tb[TCA_SKBEDIT_PARMS] == NULL)
90 return -EINVAL; 90 return -EINVAL;
91 91
92 if (tb[TCA_SKBEDIT_PRIORITY] != NULL) { 92 if (tb[TCA_SKBEDIT_PRIORITY] != NULL) {
93 flags |= SKBEDIT_F_PRIORITY; 93 flags |= SKBEDIT_F_PRIORITY;
94 priority = nla_data(tb[TCA_SKBEDIT_PRIORITY]); 94 priority = nla_data(tb[TCA_SKBEDIT_PRIORITY]);
95 } 95 }
96 96
97 if (tb[TCA_SKBEDIT_QUEUE_MAPPING] != NULL) { 97 if (tb[TCA_SKBEDIT_QUEUE_MAPPING] != NULL) {
98 flags |= SKBEDIT_F_QUEUE_MAPPING; 98 flags |= SKBEDIT_F_QUEUE_MAPPING;
99 queue_mapping = nla_data(tb[TCA_SKBEDIT_QUEUE_MAPPING]); 99 queue_mapping = nla_data(tb[TCA_SKBEDIT_QUEUE_MAPPING]);
100 } 100 }
101 101
102 if (tb[TCA_SKBEDIT_MARK] != NULL) { 102 if (tb[TCA_SKBEDIT_MARK] != NULL) {
103 flags |= SKBEDIT_F_MARK; 103 flags |= SKBEDIT_F_MARK;
104 mark = nla_data(tb[TCA_SKBEDIT_MARK]); 104 mark = nla_data(tb[TCA_SKBEDIT_MARK]);
105 } 105 }
106 106
107 if (!flags) 107 if (!flags)
108 return -EINVAL; 108 return -EINVAL;
109 109
110 parm = nla_data(tb[TCA_SKBEDIT_PARMS]); 110 parm = nla_data(tb[TCA_SKBEDIT_PARMS]);
111 111
112 pc = tcf_hash_check(parm->index, a, bind, &skbedit_hash_info); 112 pc = tcf_hash_check(parm->index, a, bind, &skbedit_hash_info);
113 if (!pc) { 113 if (!pc) {
114 pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind, 114 pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind,
115 &skbedit_idx_gen, &skbedit_hash_info); 115 &skbedit_idx_gen, &skbedit_hash_info);
116 if (IS_ERR(pc)) 116 if (IS_ERR(pc))
117 return PTR_ERR(pc); 117 return PTR_ERR(pc);
118 118
119 d = to_skbedit(pc); 119 d = to_skbedit(pc);
120 ret = ACT_P_CREATED; 120 ret = ACT_P_CREATED;
121 } else { 121 } else {
122 d = to_skbedit(pc); 122 d = to_skbedit(pc);
123 if (!ovr) { 123 if (!ovr) {
124 tcf_hash_release(pc, bind, &skbedit_hash_info); 124 tcf_hash_release(pc, bind, &skbedit_hash_info);
125 return -EEXIST; 125 return -EEXIST;
126 } 126 }
127 } 127 }
128 128
129 spin_lock_bh(&d->tcf_lock); 129 spin_lock_bh(&d->tcf_lock);
130 130
131 d->flags = flags; 131 d->flags = flags;
132 if (flags & SKBEDIT_F_PRIORITY) 132 if (flags & SKBEDIT_F_PRIORITY)
133 d->priority = *priority; 133 d->priority = *priority;
134 if (flags & SKBEDIT_F_QUEUE_MAPPING) 134 if (flags & SKBEDIT_F_QUEUE_MAPPING)
135 d->queue_mapping = *queue_mapping; 135 d->queue_mapping = *queue_mapping;
136 if (flags & SKBEDIT_F_MARK) 136 if (flags & SKBEDIT_F_MARK)
137 d->mark = *mark; 137 d->mark = *mark;
138 138
139 d->tcf_action = parm->action; 139 d->tcf_action = parm->action;
140 140
141 spin_unlock_bh(&d->tcf_lock); 141 spin_unlock_bh(&d->tcf_lock);
142 142
143 if (ret == ACT_P_CREATED) 143 if (ret == ACT_P_CREATED)
144 tcf_hash_insert(pc, &skbedit_hash_info); 144 tcf_hash_insert(pc, &skbedit_hash_info);
145 return ret; 145 return ret;
146 } 146 }
147 147
148 static int tcf_skbedit_cleanup(struct tc_action *a, int bind) 148 static int tcf_skbedit_cleanup(struct tc_action *a, int bind)
149 { 149 {
150 struct tcf_skbedit *d = a->priv; 150 struct tcf_skbedit *d = a->priv;
151 151
152 if (d) 152 if (d)
153 return tcf_hash_release(&d->common, bind, &skbedit_hash_info); 153 return tcf_hash_release(&d->common, bind, &skbedit_hash_info);
154 return 0; 154 return 0;
155 } 155 }
156 156
157 static int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a, 157 static int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a,
158 int bind, int ref) 158 int bind, int ref)
159 { 159 {
160 unsigned char *b = skb_tail_pointer(skb); 160 unsigned char *b = skb_tail_pointer(skb);
161 struct tcf_skbedit *d = a->priv; 161 struct tcf_skbedit *d = a->priv;
162 struct tc_skbedit opt = { 162 struct tc_skbedit opt = {
163 .index = d->tcf_index, 163 .index = d->tcf_index,
164 .refcnt = d->tcf_refcnt - ref, 164 .refcnt = d->tcf_refcnt - ref,
165 .bindcnt = d->tcf_bindcnt - bind, 165 .bindcnt = d->tcf_bindcnt - bind,
166 .action = d->tcf_action, 166 .action = d->tcf_action,
167 }; 167 };
168 struct tcf_t t; 168 struct tcf_t t;
169 169
170 if (nla_put(skb, TCA_SKBEDIT_PARMS, sizeof(opt), &opt)) 170 if (nla_put(skb, TCA_SKBEDIT_PARMS, sizeof(opt), &opt))
171 goto nla_put_failure; 171 goto nla_put_failure;
172 if ((d->flags & SKBEDIT_F_PRIORITY) && 172 if ((d->flags & SKBEDIT_F_PRIORITY) &&
173 nla_put(skb, TCA_SKBEDIT_PRIORITY, sizeof(d->priority), 173 nla_put(skb, TCA_SKBEDIT_PRIORITY, sizeof(d->priority),
174 &d->priority)) 174 &d->priority))
175 goto nla_put_failure; 175 goto nla_put_failure;
176 if ((d->flags & SKBEDIT_F_QUEUE_MAPPING) && 176 if ((d->flags & SKBEDIT_F_QUEUE_MAPPING) &&
177 nla_put(skb, TCA_SKBEDIT_QUEUE_MAPPING, 177 nla_put(skb, TCA_SKBEDIT_QUEUE_MAPPING,
178 sizeof(d->queue_mapping), &d->queue_mapping)) 178 sizeof(d->queue_mapping), &d->queue_mapping))
179 goto nla_put_failure; 179 goto nla_put_failure;
180 if ((d->flags & SKBEDIT_F_MARK) && 180 if ((d->flags & SKBEDIT_F_MARK) &&
181 nla_put(skb, TCA_SKBEDIT_MARK, sizeof(d->mark), 181 nla_put(skb, TCA_SKBEDIT_MARK, sizeof(d->mark),
182 &d->mark)) 182 &d->mark))
183 goto nla_put_failure; 183 goto nla_put_failure;
184 t.install = jiffies_to_clock_t(jiffies - d->tcf_tm.install); 184 t.install = jiffies_to_clock_t(jiffies - d->tcf_tm.install);
185 t.lastuse = jiffies_to_clock_t(jiffies - d->tcf_tm.lastuse); 185 t.lastuse = jiffies_to_clock_t(jiffies - d->tcf_tm.lastuse);
186 t.expires = jiffies_to_clock_t(d->tcf_tm.expires); 186 t.expires = jiffies_to_clock_t(d->tcf_tm.expires);
187 if (nla_put(skb, TCA_SKBEDIT_TM, sizeof(t), &t)) 187 if (nla_put(skb, TCA_SKBEDIT_TM, sizeof(t), &t))
188 goto nla_put_failure; 188 goto nla_put_failure;
189 return skb->len; 189 return skb->len;
190 190
191 nla_put_failure: 191 nla_put_failure:
192 nlmsg_trim(skb, b); 192 nlmsg_trim(skb, b);
193 return -1; 193 return -1;
194 } 194 }
195 195
196 static struct tc_action_ops act_skbedit_ops = { 196 static struct tc_action_ops act_skbedit_ops = {
197 .kind = "skbedit", 197 .kind = "skbedit",
198 .hinfo = &skbedit_hash_info, 198 .hinfo = &skbedit_hash_info,
199 .type = TCA_ACT_SKBEDIT, 199 .type = TCA_ACT_SKBEDIT,
200 .capab = TCA_CAP_NONE, 200 .capab = TCA_CAP_NONE,
201 .owner = THIS_MODULE, 201 .owner = THIS_MODULE,
202 .act = tcf_skbedit, 202 .act = tcf_skbedit,
203 .dump = tcf_skbedit_dump, 203 .dump = tcf_skbedit_dump,
204 .cleanup = tcf_skbedit_cleanup, 204 .cleanup = tcf_skbedit_cleanup,
205 .init = tcf_skbedit_init, 205 .init = tcf_skbedit_init,
206 .walk = tcf_generic_walker,
207 }; 206 };
208 207
209 MODULE_AUTHOR("Alexander Duyck, <alexander.h.duyck@intel.com>"); 208 MODULE_AUTHOR("Alexander Duyck, <alexander.h.duyck@intel.com>");
210 MODULE_DESCRIPTION("SKB Editing"); 209 MODULE_DESCRIPTION("SKB Editing");
211 MODULE_LICENSE("GPL"); 210 MODULE_LICENSE("GPL");
212 211
213 static int __init skbedit_init_module(void) 212 static int __init skbedit_init_module(void)
214 { 213 {
215 return tcf_register_action(&act_skbedit_ops); 214 return tcf_register_action(&act_skbedit_ops);
216 } 215 }
217 216
218 static void __exit skbedit_cleanup_module(void) 217 static void __exit skbedit_cleanup_module(void)
219 { 218 {
220 tcf_unregister_action(&act_skbedit_ops); 219 tcf_unregister_action(&act_skbedit_ops);
221 } 220 }
222 221
223 module_init(skbedit_init_module); 222 module_init(skbedit_init_module);
224 module_exit(skbedit_cleanup_module); 223 module_exit(skbedit_cleanup_module);
225 224