diff options
author | Jamal Hadi Salim <hadi@cyberus.ca> | 2007-07-03 01:41:59 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-07-11 01:16:36 -0400 |
commit | a553e4a6317b2cfc7659542c10fe43184ffe53da (patch) | |
tree | ac0f046c4e0a40513e0f8405c3e628a6e515b83f /net | |
parent | 628529b6ee334fedc8d25ce56205bb99566572b9 (diff) |
[PKTGEN]: IPSEC support
Added transport mode ESP support for starters. I will send more of
these modes and types once i have resolved the tunnel mode isses.
Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
Signed-off-by: Robert Olsson <robert.olsson@its.uu.se>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/pktgen.c | 154 |
1 files changed, 152 insertions, 2 deletions
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 683da7065886..75215331b045 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c | |||
@@ -152,6 +152,9 @@ | |||
152 | #include <net/checksum.h> | 152 | #include <net/checksum.h> |
153 | #include <net/ipv6.h> | 153 | #include <net/ipv6.h> |
154 | #include <net/addrconf.h> | 154 | #include <net/addrconf.h> |
155 | #ifdef CONFIG_XFRM | ||
156 | #include <net/xfrm.h> | ||
157 | #endif | ||
155 | #include <asm/byteorder.h> | 158 | #include <asm/byteorder.h> |
156 | #include <linux/rcupdate.h> | 159 | #include <linux/rcupdate.h> |
157 | #include <asm/bitops.h> | 160 | #include <asm/bitops.h> |
@@ -182,6 +185,7 @@ | |||
182 | #define F_VID_RND (1<<9) /* Random VLAN ID */ | 185 | #define F_VID_RND (1<<9) /* Random VLAN ID */ |
183 | #define F_SVID_RND (1<<10) /* Random SVLAN ID */ | 186 | #define F_SVID_RND (1<<10) /* Random SVLAN ID */ |
184 | #define F_FLOW_SEQ (1<<11) /* Sequential flows */ | 187 | #define F_FLOW_SEQ (1<<11) /* Sequential flows */ |
188 | #define F_IPSEC_ON (1<<12) /* ipsec on for flows */ | ||
185 | 189 | ||
186 | /* Thread control flag bits */ | 190 | /* Thread control flag bits */ |
187 | #define T_TERMINATE (1<<0) | 191 | #define T_TERMINATE (1<<0) |
@@ -208,6 +212,9 @@ static struct proc_dir_entry *pg_proc_dir = NULL; | |||
208 | struct flow_state { | 212 | struct flow_state { |
209 | __be32 cur_daddr; | 213 | __be32 cur_daddr; |
210 | int count; | 214 | int count; |
215 | #ifdef CONFIG_XFRM | ||
216 | struct xfrm_state *x; | ||
217 | #endif | ||
211 | __u32 flags; | 218 | __u32 flags; |
212 | }; | 219 | }; |
213 | 220 | ||
@@ -348,7 +355,10 @@ struct pktgen_dev { | |||
348 | unsigned lflow; /* Flow length (config) */ | 355 | unsigned lflow; /* Flow length (config) */ |
349 | unsigned nflows; /* accumulated flows (stats) */ | 356 | unsigned nflows; /* accumulated flows (stats) */ |
350 | unsigned curfl; /* current sequenced flow (state)*/ | 357 | unsigned curfl; /* current sequenced flow (state)*/ |
351 | 358 | #ifdef CONFIG_XFRM | |
359 | __u8 ipsmode; /* IPSEC mode (config) */ | ||
360 | __u8 ipsproto; /* IPSEC type (config) */ | ||
361 | #endif | ||
352 | char result[512]; | 362 | char result[512]; |
353 | }; | 363 | }; |
354 | 364 | ||
@@ -704,6 +714,11 @@ static int pktgen_if_show(struct seq_file *seq, void *v) | |||
704 | seq_printf(seq, "FLOW_RND "); | 714 | seq_printf(seq, "FLOW_RND "); |
705 | } | 715 | } |
706 | 716 | ||
717 | #ifdef CONFIG_XFRM | ||
718 | if (pkt_dev->flags & F_IPSEC_ON) | ||
719 | seq_printf(seq, "IPSEC "); | ||
720 | #endif | ||
721 | |||
707 | if (pkt_dev->flags & F_MACSRC_RND) | 722 | if (pkt_dev->flags & F_MACSRC_RND) |
708 | seq_printf(seq, "MACSRC_RND "); | 723 | seq_printf(seq, "MACSRC_RND "); |
709 | 724 | ||
@@ -1198,6 +1213,11 @@ static ssize_t pktgen_if_write(struct file *file, | |||
1198 | else if (strcmp(f, "FLOW_SEQ") == 0) | 1213 | else if (strcmp(f, "FLOW_SEQ") == 0) |
1199 | pkt_dev->flags |= F_FLOW_SEQ; | 1214 | pkt_dev->flags |= F_FLOW_SEQ; |
1200 | 1215 | ||
1216 | #ifdef CONFIG_XFRM | ||
1217 | else if (strcmp(f, "IPSEC") == 0) | ||
1218 | pkt_dev->flags |= F_IPSEC_ON; | ||
1219 | #endif | ||
1220 | |||
1201 | else if (strcmp(f, "!IPV6") == 0) | 1221 | else if (strcmp(f, "!IPV6") == 0) |
1202 | pkt_dev->flags &= ~F_IPV6; | 1222 | pkt_dev->flags &= ~F_IPV6; |
1203 | 1223 | ||
@@ -1206,7 +1226,7 @@ static ssize_t pktgen_if_write(struct file *file, | |||
1206 | "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", | 1226 | "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", |
1207 | f, | 1227 | f, |
1208 | "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, " | 1228 | "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, " |
1209 | "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ\n"); | 1229 | "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, IPSEC\n"); |
1210 | return count; | 1230 | return count; |
1211 | } | 1231 | } |
1212 | sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags); | 1232 | sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags); |
@@ -2094,6 +2114,7 @@ static void spin(struct pktgen_dev *pkt_dev, __u64 spin_until_us) | |||
2094 | 2114 | ||
2095 | static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev) | 2115 | static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev) |
2096 | { | 2116 | { |
2117 | pkt_dev->pkt_overhead = 0; | ||
2097 | pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32); | 2118 | pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32); |
2098 | pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev); | 2119 | pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev); |
2099 | pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev); | 2120 | pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev); |
@@ -2130,6 +2151,31 @@ static inline int f_pick(struct pktgen_dev *pkt_dev) | |||
2130 | return pkt_dev->curfl; | 2151 | return pkt_dev->curfl; |
2131 | } | 2152 | } |
2132 | 2153 | ||
2154 | |||
2155 | #ifdef CONFIG_XFRM | ||
2156 | /* If there was already an IPSEC SA, we keep it as is, else | ||
2157 | * we go look for it ... | ||
2158 | */ | ||
2159 | inline | ||
2160 | void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow) | ||
2161 | { | ||
2162 | struct xfrm_state *x = pkt_dev->flows[flow].x; | ||
2163 | if (!x) { | ||
2164 | /*slow path: we dont already have xfrm_state*/ | ||
2165 | x = xfrm_stateonly_find((xfrm_address_t *)&pkt_dev->cur_daddr, | ||
2166 | (xfrm_address_t *)&pkt_dev->cur_saddr, | ||
2167 | AF_INET, | ||
2168 | pkt_dev->ipsmode, | ||
2169 | pkt_dev->ipsproto, 0); | ||
2170 | if (x) { | ||
2171 | pkt_dev->flows[flow].x = x; | ||
2172 | set_pkt_overhead(pkt_dev); | ||
2173 | pkt_dev->pkt_overhead+=x->props.header_len; | ||
2174 | } | ||
2175 | |||
2176 | } | ||
2177 | } | ||
2178 | #endif | ||
2133 | /* Increment/randomize headers according to flags and current values | 2179 | /* Increment/randomize headers according to flags and current values |
2134 | * for IP src/dest, UDP src/dst port, MAC-Addr src/dst | 2180 | * for IP src/dest, UDP src/dst port, MAC-Addr src/dst |
2135 | */ | 2181 | */ |
@@ -2289,6 +2335,10 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev) | |||
2289 | pkt_dev->flows[flow].flags |= F_INIT; | 2335 | pkt_dev->flows[flow].flags |= F_INIT; |
2290 | pkt_dev->flows[flow].cur_daddr = | 2336 | pkt_dev->flows[flow].cur_daddr = |
2291 | pkt_dev->cur_daddr; | 2337 | pkt_dev->cur_daddr; |
2338 | #ifdef CONFIG_XFRM | ||
2339 | if (pkt_dev->flags & F_IPSEC_ON) | ||
2340 | get_ipsec_sa(pkt_dev, flow); | ||
2341 | #endif | ||
2292 | pkt_dev->nflows++; | 2342 | pkt_dev->nflows++; |
2293 | } | 2343 | } |
2294 | } | 2344 | } |
@@ -2329,6 +2379,91 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev) | |||
2329 | pkt_dev->flows[flow].count++; | 2379 | pkt_dev->flows[flow].count++; |
2330 | } | 2380 | } |
2331 | 2381 | ||
2382 | |||
2383 | #ifdef CONFIG_XFRM | ||
2384 | static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) | ||
2385 | { | ||
2386 | struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; | ||
2387 | int err = 0; | ||
2388 | struct iphdr *iph; | ||
2389 | |||
2390 | if (!x) | ||
2391 | return 0; | ||
2392 | /* XXX: we dont support tunnel mode for now until | ||
2393 | * we resolve the dst issue */ | ||
2394 | if (x->props.mode != XFRM_MODE_TRANSPORT) | ||
2395 | return 0; | ||
2396 | |||
2397 | spin_lock(&x->lock); | ||
2398 | iph = ip_hdr(skb); | ||
2399 | |||
2400 | err = x->mode->output(x, skb); | ||
2401 | if (err) | ||
2402 | goto error; | ||
2403 | err = x->type->output(x, skb); | ||
2404 | if (err) | ||
2405 | goto error; | ||
2406 | |||
2407 | x->curlft.bytes +=skb->len; | ||
2408 | x->curlft.packets++; | ||
2409 | spin_unlock(&x->lock); | ||
2410 | |||
2411 | error: | ||
2412 | spin_unlock(&x->lock); | ||
2413 | return err; | ||
2414 | } | ||
2415 | |||
2416 | static inline void free_SAs(struct pktgen_dev *pkt_dev) | ||
2417 | { | ||
2418 | if (pkt_dev->cflows) { | ||
2419 | /* let go of the SAs if we have them */ | ||
2420 | int i = 0; | ||
2421 | for (; i < pkt_dev->nflows; i++){ | ||
2422 | struct xfrm_state *x = pkt_dev->flows[i].x; | ||
2423 | if (x) { | ||
2424 | xfrm_state_put(x); | ||
2425 | pkt_dev->flows[i].x = NULL; | ||
2426 | } | ||
2427 | } | ||
2428 | } | ||
2429 | } | ||
2430 | |||
2431 | static inline int process_ipsec(struct pktgen_dev *pkt_dev, | ||
2432 | struct sk_buff *skb, __be16 protocol) | ||
2433 | { | ||
2434 | if (pkt_dev->flags & F_IPSEC_ON) { | ||
2435 | struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; | ||
2436 | int nhead = 0; | ||
2437 | if (x) { | ||
2438 | int ret; | ||
2439 | __u8 *eth; | ||
2440 | nhead = x->props.header_len - skb_headroom(skb); | ||
2441 | if (nhead >0) { | ||
2442 | ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC); | ||
2443 | if (ret < 0) { | ||
2444 | printk("Error expanding ipsec packet %d\n",ret); | ||
2445 | return 0; | ||
2446 | } | ||
2447 | } | ||
2448 | |||
2449 | /* ipsec is not expecting ll header */ | ||
2450 | skb_pull(skb, ETH_HLEN); | ||
2451 | ret = pktgen_output_ipsec(skb, pkt_dev); | ||
2452 | if (ret) { | ||
2453 | printk("Error creating ipsec packet %d\n",ret); | ||
2454 | kfree_skb(skb); | ||
2455 | return 0; | ||
2456 | } | ||
2457 | /* restore ll */ | ||
2458 | eth = (__u8 *) skb_push(skb, ETH_HLEN); | ||
2459 | memcpy(eth, pkt_dev->hh, 12); | ||
2460 | *(u16 *) & eth[12] = protocol; | ||
2461 | } | ||
2462 | } | ||
2463 | return 1; | ||
2464 | } | ||
2465 | #endif | ||
2466 | |||
2332 | static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev) | 2467 | static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev) |
2333 | { | 2468 | { |
2334 | unsigned i; | 2469 | unsigned i; |
@@ -2512,6 +2647,11 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
2512 | pgh->tv_usec = htonl(timestamp.tv_usec); | 2647 | pgh->tv_usec = htonl(timestamp.tv_usec); |
2513 | } | 2648 | } |
2514 | 2649 | ||
2650 | #ifdef CONFIG_XFRM | ||
2651 | if (!process_ipsec(pkt_dev, skb, protocol)) | ||
2652 | return NULL; | ||
2653 | #endif | ||
2654 | |||
2515 | return skb; | 2655 | return skb; |
2516 | } | 2656 | } |
2517 | 2657 | ||
@@ -3497,11 +3637,18 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) | |||
3497 | } | 3637 | } |
3498 | pkt_dev->entry->proc_fops = &pktgen_if_fops; | 3638 | pkt_dev->entry->proc_fops = &pktgen_if_fops; |
3499 | pkt_dev->entry->data = pkt_dev; | 3639 | pkt_dev->entry->data = pkt_dev; |
3640 | #ifdef CONFIG_XFRM | ||
3641 | pkt_dev->ipsmode = XFRM_MODE_TRANSPORT; | ||
3642 | pkt_dev->ipsproto = IPPROTO_ESP; | ||
3643 | #endif | ||
3500 | 3644 | ||
3501 | return add_dev_to_thread(t, pkt_dev); | 3645 | return add_dev_to_thread(t, pkt_dev); |
3502 | out2: | 3646 | out2: |
3503 | dev_put(pkt_dev->odev); | 3647 | dev_put(pkt_dev->odev); |
3504 | out1: | 3648 | out1: |
3649 | #ifdef CONFIG_XFRM | ||
3650 | free_SAs(pkt_dev); | ||
3651 | #endif | ||
3505 | if (pkt_dev->flows) | 3652 | if (pkt_dev->flows) |
3506 | vfree(pkt_dev->flows); | 3653 | vfree(pkt_dev->flows); |
3507 | kfree(pkt_dev); | 3654 | kfree(pkt_dev); |
@@ -3596,6 +3743,9 @@ static int pktgen_remove_device(struct pktgen_thread *t, | |||
3596 | if (pkt_dev->entry) | 3743 | if (pkt_dev->entry) |
3597 | remove_proc_entry(pkt_dev->entry->name, pg_proc_dir); | 3744 | remove_proc_entry(pkt_dev->entry->name, pg_proc_dir); |
3598 | 3745 | ||
3746 | #ifdef CONFIG_XFRM | ||
3747 | free_SAs(pkt_dev); | ||
3748 | #endif | ||
3599 | if (pkt_dev->flows) | 3749 | if (pkt_dev->flows) |
3600 | vfree(pkt_dev->flows); | 3750 | vfree(pkt_dev->flows); |
3601 | kfree(pkt_dev); | 3751 | kfree(pkt_dev); |