jamal writes: > 4 of 4 > [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 <[EMAIL PROTECTED]>
Signed-off-by: Robert Olsson <[EMAIL PROTECTED]> Cheers --ro > > diff --git a/net/core/pktgen.c b/net/core/pktgen.c > index bc4fb3b..bcec8e4 100644 > --- a/net/core/pktgen.c > +++ b/net/core/pktgen.c > @@ -152,6 +152,9 @@ > #include <net/checksum.h> > #include <net/ipv6.h> > #include <net/addrconf.h> > +#ifdef CONFIG_XFRM > +#include <net/xfrm.h> > +#endif > #include <asm/byteorder.h> > #include <linux/rcupdate.h> > #include <asm/bitops.h> > @@ -182,6 +185,7 @@ > #define F_VID_RND (1<<9) /* Random VLAN ID */ > #define F_SVID_RND (1<<10) /* Random SVLAN ID */ > #define F_FLOW_SEQ (1<<11) /* Sequential flows */ > +#define F_IPSEC_ON (1<<12) /* ipsec on for flows */ > > /* Thread control flag bits */ > #define T_TERMINATE (1<<0) > @@ -208,6 +212,9 @@ static struct proc_dir_entry *pg_proc_dir = NULL; > struct flow_state { > __be32 cur_daddr; > int count; > +#ifdef CONFIG_XFRM > + struct xfrm_state *x; > +#endif > __u32 flags; > }; > > @@ -348,7 +355,10 @@ struct pktgen_dev { > unsigned lflow; /* Flow length (config) */ > unsigned nflows; /* accumulated flows (stats) */ > unsigned curfl; /* current sequenced flow (state)*/ > - > +#ifdef CONFIG_XFRM > + __u8 ipsmode; /* IPSEC mode (config) */ > + __u8 ipsproto; /* IPSEC type (config) */ > +#endif > char result[512]; > }; > > @@ -704,6 +714,9 @@ static int pktgen_if_show(struct seq_file *seq, void *v) > seq_printf(seq, "FLOW_RND "); > } > > + if (pkt_dev->flags & F_IPSEC_ON) > + seq_printf(seq, "IPSEC "); > + > if (pkt_dev->flags & F_MACSRC_RND) > seq_printf(seq, "MACSRC_RND "); > > @@ -1198,6 +1211,11 @@ static ssize_t pktgen_if_write(struct file *file, > else if (strcmp(f, "FLOW_SEQ") == 0) > pkt_dev->flags |= F_FLOW_SEQ; > > +#ifdef CONFIG_XFRM > + else if (strcmp(f, "IPSEC") == 0) > + pkt_dev->flags |= F_IPSEC_ON; > +#endif > + > else if (strcmp(f, "!IPV6") == 0) > pkt_dev->flags &= ~F_IPV6; > > @@ -1206,7 +1224,7 @@ static ssize_t pktgen_if_write(struct file *file, > "Flag -:%s:- unknown\nAvailable flags, (prepend > ! to un-set flag):\n%s", > f, > "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, " > - "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, > MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ\n"); > + "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, > MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, IPSEC\n"); > return count; > } > sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags); > @@ -2094,6 +2112,7 @@ static void spin(struct pktgen_dev *pkt_dev, __u64 > spin_until_us) > > static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev) > { > + pkt_dev->pkt_overhead = 0; > pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32); > pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev); > pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev); > @@ -2130,6 +2149,31 @@ static inline int f_pick(struct pktgen_dev *pkt_dev) > return pkt_dev->curfl; > } > > + > +#ifdef CONFIG_XFRM > +/* If there was already an IPSEC SA, we keep it as is, else > + * we go look for it ... > +*/ > +inline > +void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow) > +{ > + 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, > + pkt_dev->ipsmode, > + pkt_dev->ipsproto, 0); > + if (x) { > + pkt_dev->flows[flow].x = x; > + set_pkt_overhead(pkt_dev); > + pkt_dev->pkt_overhead+=x->props.header_len; > + } > + > + } > +} > +#endif > /* Increment/randomize headers according to flags and current values > * for IP src/dest, UDP src/dst port, MAC-Addr src/dst > */ > @@ -2289,6 +2333,10 @@ static void mod_cur_headers(struct pktgen_dev > *pkt_dev) > pkt_dev->flows[flow].flags |= F_INIT; > pkt_dev->flows[flow].cur_daddr = > pkt_dev->cur_daddr; > +#ifdef CONFIG_XFRM > + if (pkt_dev->flags & F_IPSEC_ON) > + get_ipsec_sa(pkt_dev, flow); > +#endif > pkt_dev->nflows++; > } > } > @@ -2329,6 +2377,91 @@ static void mod_cur_headers(struct pktgen_dev > *pkt_dev) > pkt_dev->flows[flow].count++; > } > > + > +#ifdef CONFIG_XFRM > +static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev > *pkt_dev) > +{ > + struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; > + int err = 0; > + struct iphdr *iph; > + > + if (!x) > + return 0; > + /* XXX: we dont support tunnel mode for now until > + * we resolve the dst issue */ > + if (x->props.mode != XFRM_MODE_TRANSPORT) > + return 0; > + > + spin_lock(&x->lock); > + iph = ip_hdr(skb); > + > + 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 inline void free_SAs(struct pktgen_dev *pkt_dev) > +{ > + 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; > + } > + } > + } > +} > + > +static inline int process_ipsec(struct pktgen_dev *pkt_dev, > + struct sk_buff *skb, __be16 protocol) > +{ > + if (pkt_dev->flags & F_IPSEC_ON) { > + struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; > + int nhead = 0; > + if (x) { > + int ret; > + __u8 *eth; > + nhead = x->props.header_len - skb_headroom(skb); > + if (nhead >0) { > + ret = pskb_expand_head(skb, nhead, 0, > GFP_ATOMIC); > + if (ret < 0) { > + printk("Error expanding ipsec packet > %d\n",ret); > + return 0; > + } > + } > + > + /* ipsec is not expecting ll header */ > + skb_pull(skb, ETH_HLEN); > + ret = pktgen_output_ipsec(skb, pkt_dev); > + if (ret) { > + printk("Error creating ipsec packet %d\n",ret); > + kfree_skb(skb); > + return 0; > + } > + /* restore ll */ > + eth = (__u8 *) skb_push(skb, ETH_HLEN); > + memcpy(eth, pkt_dev->hh, 12); > + *(u16 *) & eth[12] = protocol; > + } > + } > + return 1; > +} > +#endif > + > static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev) > { > unsigned i; > @@ -2512,6 +2645,11 @@ static struct sk_buff *fill_packet_ipv4(struct > net_device *odev, > pgh->tv_usec = htonl(timestamp.tv_usec); > } > > +#ifdef CONFIG_XFRM > + if (!process_ipsec(pkt_dev, skb, protocol)) > + return NULL; > +#endif > + > return skb; > } > > @@ -3493,11 +3631,18 @@ static int pktgen_add_device(struct pktgen_thread > *t, const char *ifname) > } > pkt_dev->entry->proc_fops = &pktgen_if_fops; > pkt_dev->entry->data = pkt_dev; > +#ifdef CONFIG_XFRM > + pkt_dev->ipsmode = XFRM_MODE_TRANSPORT; > + pkt_dev->ipsproto = IPPROTO_ESP; > +#endif > > return add_dev_to_thread(t, pkt_dev); > out2: > dev_put(pkt_dev->odev); > out1: > +#ifdef CONFIG_XFRM > + free_SAs(pkt_dev); > +#endif > if (pkt_dev->flows) > vfree(pkt_dev->flows); > kfree(pkt_dev); > @@ -3592,6 +3737,9 @@ static int pktgen_remove_device(struct pktgen_thread > *t, > if (pkt_dev->entry) > remove_proc_entry(pkt_dev->entry->name, pg_proc_dir); > > +#ifdef CONFIG_XFRM > + free_SAs(pkt_dev); > +#endif > if (pkt_dev->flows) > vfree(pkt_dev->flows); > kfree(pkt_dev); - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html