aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJamal Hadi Salim <hadi@cyberus.ca>2007-07-03 01:41:59 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-07-11 01:16:36 -0400
commita553e4a6317b2cfc7659542c10fe43184ffe53da (patch)
treeac0f046c4e0a40513e0f8405c3e628a6e515b83f
parent628529b6ee334fedc8d25ce56205bb99566572b9 (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>
-rw-r--r--net/core/pktgen.c154
1 files changed, 152 insertions, 2 deletions
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 683da706588..75215331b04 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;
208struct flow_state { 212struct 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
2095static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev) 2115static 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*/
2159inline
2160void 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
2384static 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
2411error:
2412 spin_unlock(&x->lock);
2413 return err;
2414}
2415
2416static 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
2431static 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
2332static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev) 2467static 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);
3502out2: 3646out2:
3503 dev_put(pkt_dev->odev); 3647 dev_put(pkt_dev->odev);
3504out1: 3648out1:
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);