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;
 }

Reply via email to