{pktgen, xfrm} Introduce xfrm_state_lookup_byspi for pktgen
[deliverable/linux.git] / net / core / pktgen.c
index a797fff7f22213f3e5d1be6f97ab632a791079a4..b553c36ea0caefab51633d989dad673651a4509f 100644 (file)
@@ -389,6 +389,9 @@ struct pktgen_dev {
 #ifdef CONFIG_XFRM
        __u8    ipsmode;                /* IPSEC mode (config) */
        __u8    ipsproto;               /* IPSEC type (config) */
+       __u32   spi;
+       struct dst_entry dst;
+       struct dst_ops dstops;
 #endif
        char result[512];
 };
@@ -1477,6 +1480,17 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
 
+       if (!strcmp(name, "spi")) {
+               len = num_arg(&user_buffer[i], 10, &value);
+               if (len < 0)
+                       return len;
+
+               i += len;
+               pkt_dev->spi = value;
+               sprintf(pg_result, "OK: spi=%u", pkt_dev->spi);
+               return count;
+       }
+
        if (!strcmp(name, "flowlen")) {
                len = num_arg(&user_buffer[i], 10, &value);
                if (len < 0)
@@ -2233,13 +2247,21 @@ static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow)
        struct xfrm_state *x = pkt_dev->flows[flow].x;
        struct pktgen_net *pn = net_generic(dev_net(pkt_dev->odev), pg_net_id);
        if (!x) {
-               /*slow path: we dont already have xfrm_state*/
-               x = xfrm_stateonly_find(pn->net, DUMMY_MARK,
-                                       (xfrm_address_t *)&pkt_dev->cur_daddr,
-                                       (xfrm_address_t *)&pkt_dev->cur_saddr,
-                                       AF_INET,
-                                       pkt_dev->ipsmode,
-                                       pkt_dev->ipsproto, 0);
+
+               if (pkt_dev->spi) {
+                       /* We need as quick as possible to find the right SA
+                        * Searching with minimum criteria to archieve this.
+                        */
+                       x = xfrm_state_lookup_byspi(pn->net, htonl(pkt_dev->spi), AF_INET);
+               } else {
+                       /* slow path: we dont already have xfrm_state */
+                       x = xfrm_stateonly_find(pn->net, DUMMY_MARK,
+                                               (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);
@@ -2475,31 +2497,47 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
 
 
 #ifdef CONFIG_XFRM
+u32 pktgen_dst_metrics[RTAX_MAX + 1] = {
+
+       [RTAX_HOPLIMIT] = 0x5, /* Set a static hoplimit */
+};
+
 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 net *net = dev_net(pkt_dev->odev);
 
        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)
+       if ((x->props.mode != XFRM_MODE_TRANSPORT) && (pkt_dev->spi == 0))
                return 0;
 
-       spin_lock(&x->lock);
+       /* But when user specify an valid SPI, transformation
+        * supports both transport/tunnel mode + ESP/AH type.
+        */
+       if ((x->props.mode == XFRM_MODE_TUNNEL) && (pkt_dev->spi != 0))
+               skb->_skb_refdst = (unsigned long)&pkt_dev->dst | SKB_DST_NOREF;
 
+       rcu_read_lock_bh();
        err = x->outer_mode->output(x, skb);
-       if (err)
+       rcu_read_unlock_bh();
+       if (err) {
+               XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR);
                goto error;
+       }
        err = x->type->output(x, skb);
-       if (err)
+       if (err) {
+               XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEPROTOERROR);
                goto error;
-
+       }
+       spin_lock_bh(&x->lock);
        x->curlft.bytes += skb->len;
        x->curlft.packets++;
+       spin_unlock_bh(&x->lock);
 error:
-       spin_unlock(&x->lock);
        return err;
 }
 
@@ -3542,6 +3580,17 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
 #ifdef CONFIG_XFRM
        pkt_dev->ipsmode = XFRM_MODE_TRANSPORT;
        pkt_dev->ipsproto = IPPROTO_ESP;
+
+       /* xfrm tunnel mode needs additional dst to extract outter
+        * ip header protocol/ttl/id field, here creat a phony one.
+        * instead of looking for a valid rt, which definitely hurting
+        * performance under such circumstance.
+        */
+       pkt_dev->dstops.family = AF_INET;
+       pkt_dev->dst.dev = pkt_dev->odev;
+       dst_init_metrics(&pkt_dev->dst, pktgen_dst_metrics, false);
+       pkt_dev->dst.child = &pkt_dev->dst;
+       pkt_dev->dst.ops = &pkt_dev->dstops;
 #endif
 
        return add_dev_to_thread(t, pkt_dev);
This page took 0.049963 seconds and 5 git commands to generate.