On Wed, 2006-06-09 at 21:26 +1000, Herbert Xu wrote: > On Wed, Sep 06, 2006 at 07:20:39AM -0400, jamal wrote: > > > > > Any reason why xfrm_state_find can't be used? > > > > xfrm_state_find is overkill (if you compare the two functionalities). > > Could you show me how you plan to use this in pktgen?
Older patch attached - has a few bugs; just ignore them. > Perhaps we can > move it to the slow path where it wouldn't matter whether it's an > overkill or not. There should be no reason to be looking up an SA > in the pktgen fast path. It is needed if you want replay protection - unless you can come with some clever way to handle it without violating the integrity. For non replay protection, thats easy: We just do one lookup and reclone the packet within pktgen - maybe thats what you meant by "slow path"? cheers, jamal
Add IPSEC support to pktgen. Currently only IPV4 and ESP/Transport mode. IPV6 next. And Tunnel mode to follow after some discussions with Herbert and Dave. --- commit 0721d8f9d3e1a9a8f5f038365ae12ec605a2d5d6 tree 3069707bec44c992c0bfdbe871c7e3bd68d37882 parent 1a4c28d2bd2fcf82b84bffdb7be47aa9224483d0 author Jamal Hadi Salim <[EMAIL PROTECTED]> Tue, 22 Aug 2006 21:43:37 -0400 committer Jamal Hadi Salim <[EMAIL PROTECTED](none)> Tue, 22 Aug 2006 21:43:37 -0400 net/core/pktgen.c | 169 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 files changed, 156 insertions(+), 13 deletions(-) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 67ed14d..5fc725d 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -148,6 +148,7 @@ #include <linux/etherdevice.h> #include <net/checksum.h> #include <net/ipv6.h> #include <net/addrconf.h> +#include <net/xfrm.h> #include <asm/byteorder.h> #include <linux/rcupdate.h> #include <asm/bitops.h> @@ -178,6 +179,8 @@ #define F_MACDST_RND (1<<5) /* MAC-Dst #define F_TXSIZE_RND (1<<6) /* Transmit size is random */ #define F_IPV6 (1<<7) /* Interface in IPV6 Mode */ #define F_MPLS_RND (1<<8) /* Random MPLS labels */ +#define F_FLOW_RND (1<<9) /* Random flows */ +#define F_IPSEC_ON (1<<10) /* Run ipsec when possible */ /* Thread control flag bits */ #define T_TERMINATE (1<<0) @@ -200,6 +203,7 @@ #define MAX_CFLOWS 65536 struct flow_state { __u32 cur_daddr; + struct xfrm_state *x; int count; }; @@ -226,6 +230,7 @@ struct pktgen_dev { int min_pkt_size; /* = ETH_ZLEN; */ int max_pkt_size; /* = ETH_ZLEN; */ + int pkt_overhead; /* overhead in case of MPLS or IPSEC */ int nfrags; __u32 delay_us; /* Default delay */ __u32 delay_ns; @@ -324,6 +329,8 @@ struct pktgen_dev { */ struct flow_state *flows; unsigned cflows; /* Concurrent flows (config) */ + unsigned nextfl; /* next flow when not random */ + unsigned curfl; /* current running flow */ unsigned lflow; /* Flow length (config) */ unsigned nflows; /* accumulated flows (stats) */ }; @@ -667,6 +674,14 @@ static int pktgen_if_show(struct seq_fil if (pkt_dev->flags & F_MPLS_RND) seq_printf(seq, "MPLS_RND "); + if (pkt_dev->flags & F_FLOW_RND) + seq_printf(seq, "FLOW_RND "); + else + seq_printf(seq, "FLOW_SQN "); /*in sequence */ + + if (pkt_dev->flags & F_IPSEC_ON) + seq_printf(seq, "IPSEC_ON "); + if (pkt_dev->flags & F_MACSRC_RND) seq_printf(seq, "MACSRC_RND "); @@ -1140,6 +1155,12 @@ static ssize_t pktgen_if_write(struct fi else if (strcmp(f, "!MPLS_RND") == 0) pkt_dev->flags &= ~F_MPLS_RND; + else if (strcmp(f, "IPSEC_ON") == 0) + pkt_dev->flags |= F_IPSEC_ON; + + else if (strcmp(f, "!IPSEC_ON") == 0) + pkt_dev->flags &= ~F_IPSEC_ON; + else { sprintf(pg_result, "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", @@ -1447,6 +1468,10 @@ static ssize_t pktgen_if_write(struct fi n == pkt_dev->nr_labels-1 ? "" : ","); return count; } + if (!strcmp(name, "ipsec")) { + /*XXX: Add the "OK: ipsec on" thing */ + pkt_dev->flags |= F_IPSEC_ON; + } sprintf(pkt_dev->result, "No such parameter \"%s\"", name); return -EINVAL; @@ -1879,11 +1904,26 @@ static void mod_cur_headers(struct pktge __u32 imx; int flow = 0; + pkt_dev->pkt_overhead = 0; if (pkt_dev->cflows) { - flow = pktgen_random() % pkt_dev->cflows; + if (pkt_dev->flags & F_FLOW_RND) { + flow = pktgen_random() % pkt_dev->cflows; + if (pkt_dev->flows[flow].count > pkt_dev->lflow) + pkt_dev->flows[flow].count = 0; + } else { + flow = pkt_dev->nextfl; + if (pkt_dev->flows[flow].count > pkt_dev->lflow) { + /* reset time */ + pkt_dev->nextfl+=1; + if (pkt_dev->nextfl > pkt_dev->cflows) + pkt_dev->nextfl = 0; /*reset */ + + flow = pkt_dev->nextfl; + } - if (pkt_dev->flows[flow].count > pkt_dev->lflow) - pkt_dev->flows[flow].count = 0; + } + pkt_dev->curfl = flow; + pkt_dev->nextfl+=1; } /* Deal with source MAC */ @@ -1947,6 +1987,9 @@ static void mod_cur_headers(struct pktge pkt_dev->labels[i] = MPLS_STACK_BOTTOM | (pktgen_random() & htonl(0x000fffff)); + + pkt_dev->pkt_overhead+=pkt_dev->nr_labels*sizeof(u32); + } if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) { @@ -2068,9 +2111,62 @@ static void mod_cur_headers(struct pktge pkt_dev->cur_pkt_size = t; } + if (pkt_dev->cflows && pkt_dev->flags & F_IPSEC_ON) { + struct xfrm_state *x = pkt_dev->flows[flow].x; + if (!x) { + /*slow path: we dont already have xfrm_state*/ + x = xfrm_stateonly_find((xfrm_address_t *)&pkt_dev->cur_daddr, (xfrm_address_t *)&pkt_dev->cur_saddr, AF_INET,XFRM_MODE_TRANSPORT, IPPROTO_ESP); + if (x) { + pkt_dev->flows[flow].x = x; + pkt_dev->pkt_overhead+=x->props.header_len; + } + + } + } + + /* XXX: Should this be moved into if stmt above? + * Talk to Monsieur Robert + */ pkt_dev->flows[flow].count++; } +/* In case of errors we are gonna bail out on the packet .. + * Also: We only support transport mode at the moment.. + * Talk to Herbert/Dave about making the tunnel mode pieces + * independent of dst .. + **/ +static int pktgen_handle_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) +{ + struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; + int err = 0; + + if (!x) + return 0; + /* XXX: we dont support tunnel mode for now until + * we resolve the dst issue */ + if (x->props.mode) + return 0; + /* error injection + return -1; + */ + spin_lock(&x->lock); + + err = x->mode->output(x, skb); + if (err) + goto error; + err = x->type->output(x, skb); + if (err) + goto error; + + x->curlft.bytes +=skb->len; + x->curlft.packets++; + spin_unlock(&x->lock); + +error: + spin_unlock(&x->lock); + return err; +} + static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev) { unsigned i; @@ -2092,9 +2188,7 @@ static struct sk_buff *fill_packet_ipv4( struct pktgen_hdr *pgh = NULL; __be16 protocol = __constant_htons(ETH_P_IP); __be32 *mpls; - - if (pkt_dev->nr_labels) - protocol = __constant_htons(ETH_P_MPLS_UC); + int nhead; /* Update any of the values, used when we're incrementing various * fields. @@ -2102,8 +2196,12 @@ static struct sk_buff *fill_packet_ipv4( mod_cur_headers(pkt_dev); datalen = (odev->hard_header_len + 16) & ~0xf; + skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + datalen + - pkt_dev->nr_labels*sizeof(u32), GFP_ATOMIC); + pkt_dev->pkt_overhead, GFP_ATOMIC); + /*XXX: We need to check for cases where the MTU maybe + * exceeded + */ if (!skb) { sprintf(pkt_dev->result, "No memory"); return NULL; @@ -2113,10 +2211,15 @@ static struct sk_buff *fill_packet_ipv4( /* Reserve for ethernet and IP header */ eth = (__u8 *) skb_push(skb, 14); - mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); - if (pkt_dev->nr_labels) + + if (pkt_dev->nr_labels) { + protocol = __constant_htons(ETH_P_MPLS_UC); + mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); mpls_push(mpls, pkt_dev); + } + iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr)); + skb->nh.iph = iph; udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); memcpy(eth, pkt_dev->hh, 12); @@ -2124,7 +2227,7 @@ static struct sk_buff *fill_packet_ipv4( /* Eth + IPh + UDPh + mpls */ datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 - - pkt_dev->nr_labels*sizeof(u32); + pkt_dev->pkt_overhead; if (datalen < sizeof(struct pktgen_hdr)) datalen = sizeof(struct pktgen_hdr); @@ -2146,10 +2249,11 @@ static struct sk_buff *fill_packet_ipv4( iph->check = 0; iph->check = ip_fast_csum((void *)iph, iph->ihl); skb->protocol = protocol; - skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32); + skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->pkt_overhead; skb->dev = odev; skb->pkt_type = PACKET_HOST; + if (pkt_dev->nfrags <= 0) pgh = (struct pktgen_hdr *)skb_put(skb, datalen); else { @@ -2216,6 +2320,30 @@ static struct sk_buff *fill_packet_ipv4( pgh->tv_sec = htonl(timestamp.tv_sec); pgh->tv_usec = htonl(timestamp.tv_usec); } + // Finally let ipsec at it ;-> + if (pkt_dev->flags & F_IPSEC_ON) { + struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; + if (x) { + int ret; + nhead = x->props.header_len - skb_headroom(skb); + if (nhead >0) + pskb_expand_head(skb, nhead, 0, GFP_ATOMIC); + /* ipsec is not expecting ll header */ + skb_pull(skb, 14); + ret = pktgen_handle_ipsec(skb, pkt_dev); + if (ret) { + printk("Error creating ipsec packet %d\n",ret); + kfree_skb(skb); + return NULL; + } + /* restore ll */ + eth = (__u8 *) skb_push(skb, 14); + memcpy(eth, pkt_dev->hh, 12); + *(u16 *) & eth[12] = protocol; + + } + } + pkt_dev->seq_num++; return skb; @@ -3177,8 +3305,9 @@ static int pktgen_add_device(struct pktg if (!pktgen_setup_dev(pkt_dev)) { printk("pktgen: ERROR: pktgen_setup_dev failed.\n"); - if (pkt_dev->flows) + if (pkt_dev->flows) { vfree(pkt_dev->flows); + } kfree(pkt_dev); return -ENODEV; } @@ -3187,8 +3316,9 @@ static int pktgen_add_device(struct pktg if (!pe) { printk("pktgen: cannot create %s/%s procfs entry.\n", PG_PROC_DIR, ifname); - if (pkt_dev->flows) + if (pkt_dev->flows) { vfree(pkt_dev->flows); + } kfree(pkt_dev); return -EINVAL; } @@ -3312,8 +3442,21 @@ static int pktgen_remove_device(struct p remove_proc_entry(pkt_dev->ifname, pg_proc_dir); + if (pkt_dev->cflows) { + /* let go of the SAs if we have them */ + int i = 0; + for (; i < pkt_dev->nflows; i++){ + struct xfrm_state *x = pkt_dev->flows[i].x; + if (x) { + xfrm_state_put(x); + pkt_dev->flows[i].x = NULL; + } + } + } + if (pkt_dev->flows) vfree(pkt_dev->flows); + kfree(pkt_dev); return 0; }