{pktgen, xfrm} Introduce xfrm_state_lookup_byspi for pktgen
authorFan Du <fan.du@windriver.com>
Fri, 3 Jan 2014 03:18:32 +0000 (11:18 +0800)
committerSteffen Klassert <steffen.klassert@secunet.com>
Fri, 3 Jan 2014 06:29:12 +0000 (07:29 +0100)
Introduce xfrm_state_lookup_byspi to find user specified by custom
from "pgset spi xxx". Using this scheme, any flow regardless its
saddr/daddr could be transform by SA specified with configurable
spi.

Signed-off-by: Fan Du <fan.du@windriver.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
include/net/xfrm.h
net/core/pktgen.c
net/xfrm/xfrm_state.c

index b7635ef4d4364a16c6340234a69e969970ed689b..cd7c46ff6f1f41e7a6449c912fb7e0419e281e8f 100644 (file)
@@ -1421,6 +1421,8 @@ struct xfrm_state *xfrm_stateonly_find(struct net *net, u32 mark,
                                       xfrm_address_t *saddr,
                                       unsigned short family,
                                       u8 mode, u8 proto, u32 reqid);
+struct xfrm_state *xfrm_state_lookup_byspi(struct net *net, __be32 spi,
+                                             unsigned short family);
 int xfrm_state_check_expire(struct xfrm_state *x);
 void xfrm_state_insert(struct xfrm_state *x);
 int xfrm_state_add(struct xfrm_state *x);
index 628f7c572c6ef72c463a6f8d99ba2a2695cd80ad..b553c36ea0caefab51633d989dad673651a4509f 100644 (file)
@@ -2247,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);
index 300744094ad86095f6663e4f474d1f0db39acd4a..62181486ead85fa1d2858dc7143bd099ee5094a9 100644 (file)
@@ -915,6 +915,28 @@ xfrm_stateonly_find(struct net *net, u32 mark,
 }
 EXPORT_SYMBOL(xfrm_stateonly_find);
 
+struct xfrm_state *xfrm_state_lookup_byspi(struct net *net, __be32 spi,
+                                             unsigned short family)
+{
+       struct xfrm_state *x;
+       struct xfrm_state_walk *w;
+
+       spin_lock_bh(&net->xfrm.xfrm_state_lock);
+       list_for_each_entry(w, &net->xfrm.state_all, all) {
+               x = container_of(w, struct xfrm_state, km);
+               if (x->props.family != family ||
+                       x->id.spi != spi)
+                       continue;
+
+               spin_unlock_bh(&net->xfrm.xfrm_state_lock);
+               xfrm_state_hold(x);
+               return x;
+       }
+       spin_unlock_bh(&net->xfrm.xfrm_state_lock);
+       return NULL;
+}
+EXPORT_SYMBOL(xfrm_state_lookup_byspi);
+
 static void __xfrm_state_insert(struct xfrm_state *x)
 {
        struct net *net = xs_net(x);