@@ -679,6 +679,7 @@ struct xfrm_state *xfrm_state_alloc(struct net *net)
679679 x -> lft .hard_packet_limit = XFRM_INF ;
680680 x -> replay_maxage = 0 ;
681681 x -> replay_maxdiff = 0 ;
682+ x -> pcpu_num = UINT_MAX ;
682683 spin_lock_init (& x -> lock );
683684 }
684685 return x ;
@@ -1155,6 +1156,12 @@ static void xfrm_state_look_at(struct xfrm_policy *pol, struct xfrm_state *x,
11551156 struct xfrm_state * * best , int * acq_in_progress ,
11561157 int * error )
11571158{
1159+ /* We need the cpu id just as a lookup key,
1160+ * we don't require it to be stable.
1161+ */
1162+ unsigned int pcpu_id = get_cpu ();
1163+ put_cpu ();
1164+
11581165 /* Resolution logic:
11591166 * 1. There is a valid state with matching selector. Done.
11601167 * 2. Valid state with inappropriate selector. Skip.
@@ -1174,13 +1181,18 @@ static void xfrm_state_look_at(struct xfrm_policy *pol, struct xfrm_state *x,
11741181 & fl -> u .__fl_common ))
11751182 return ;
11761183
1184+ if (x -> pcpu_num != UINT_MAX && x -> pcpu_num != pcpu_id )
1185+ return ;
1186+
11771187 if (!* best ||
1188+ ((* best )-> pcpu_num == UINT_MAX && x -> pcpu_num == pcpu_id ) ||
11781189 (* best )-> km .dying > x -> km .dying ||
11791190 ((* best )-> km .dying == x -> km .dying &&
11801191 (* best )-> curlft .add_time < x -> curlft .add_time ))
11811192 * best = x ;
11821193 } else if (x -> km .state == XFRM_STATE_ACQ ) {
1183- * acq_in_progress = 1 ;
1194+ if (!* best || x -> pcpu_num == pcpu_id )
1195+ * acq_in_progress = 1 ;
11841196 } else if (x -> km .state == XFRM_STATE_ERROR ||
11851197 x -> km .state == XFRM_STATE_EXPIRED ) {
11861198 if ((!x -> sel .family ||
@@ -1209,6 +1221,13 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
12091221 unsigned short encap_family = tmpl -> encap_family ;
12101222 unsigned int sequence ;
12111223 struct km_event c ;
1224+ unsigned int pcpu_id ;
1225+
1226+ /* We need the cpu id just as a lookup key,
1227+ * we don't require it to be stable.
1228+ */
1229+ pcpu_id = get_cpu ();
1230+ put_cpu ();
12121231
12131232 to_put = NULL ;
12141233
@@ -1282,7 +1301,10 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
12821301 }
12831302
12841303found :
1285- x = best ;
1304+ if (!(pol -> flags & XFRM_POLICY_CPU_ACQUIRE ) ||
1305+ (best && (best -> pcpu_num == pcpu_id )))
1306+ x = best ;
1307+
12861308 if (!x && !error && !acquire_in_progress ) {
12871309 if (tmpl -> id .spi &&
12881310 (x0 = __xfrm_state_lookup_all (net , mark , daddr ,
@@ -1314,6 +1336,8 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
13141336 xfrm_init_tempstate (x , fl , tmpl , daddr , saddr , family );
13151337 memcpy (& x -> mark , & pol -> mark , sizeof (x -> mark ));
13161338 x -> if_id = if_id ;
1339+ if ((pol -> flags & XFRM_POLICY_CPU_ACQUIRE ) && best )
1340+ x -> pcpu_num = pcpu_id ;
13171341
13181342 error = security_xfrm_state_alloc_acquire (x , pol -> security , fl -> flowi_secid );
13191343 if (error ) {
@@ -1392,6 +1416,11 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
13921416 x = NULL ;
13931417 error = - ESRCH ;
13941418 }
1419+
1420+ /* Use the already installed 'fallback' while the CPU-specific
1421+ * SA acquire is handled*/
1422+ if (best )
1423+ x = best ;
13951424 }
13961425out :
13971426 if (x ) {
@@ -1524,12 +1553,14 @@ static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
15241553 unsigned int h ;
15251554 u32 mark = xnew -> mark .v & xnew -> mark .m ;
15261555 u32 if_id = xnew -> if_id ;
1556+ u32 cpu_id = xnew -> pcpu_num ;
15271557
15281558 h = xfrm_dst_hash (net , & xnew -> id .daddr , & xnew -> props .saddr , reqid , family );
15291559 hlist_for_each_entry (x , net -> xfrm .state_bydst + h , bydst ) {
15301560 if (x -> props .family == family &&
15311561 x -> props .reqid == reqid &&
15321562 x -> if_id == if_id &&
1563+ x -> pcpu_num == cpu_id &&
15331564 (mark & x -> mark .m ) == x -> mark .v &&
15341565 xfrm_addr_equal (& x -> id .daddr , & xnew -> id .daddr , family ) &&
15351566 xfrm_addr_equal (& x -> props .saddr , & xnew -> props .saddr , family ))
@@ -1552,7 +1583,7 @@ EXPORT_SYMBOL(xfrm_state_insert);
15521583static struct xfrm_state * __find_acq_core (struct net * net ,
15531584 const struct xfrm_mark * m ,
15541585 unsigned short family , u8 mode ,
1555- u32 reqid , u32 if_id , u8 proto ,
1586+ u32 reqid , u32 if_id , u32 pcpu_num , u8 proto ,
15561587 const xfrm_address_t * daddr ,
15571588 const xfrm_address_t * saddr ,
15581589 int create )
@@ -1569,6 +1600,7 @@ static struct xfrm_state *__find_acq_core(struct net *net,
15691600 x -> id .spi != 0 ||
15701601 x -> id .proto != proto ||
15711602 (mark & x -> mark .m ) != x -> mark .v ||
1603+ x -> pcpu_num != pcpu_num ||
15721604 !xfrm_addr_equal (& x -> id .daddr , daddr , family ) ||
15731605 !xfrm_addr_equal (& x -> props .saddr , saddr , family ))
15741606 continue ;
@@ -1602,6 +1634,7 @@ static struct xfrm_state *__find_acq_core(struct net *net,
16021634 break ;
16031635 }
16041636
1637+ x -> pcpu_num = pcpu_num ;
16051638 x -> km .state = XFRM_STATE_ACQ ;
16061639 x -> id .proto = proto ;
16071640 x -> props .family = family ;
@@ -1630,7 +1663,7 @@ static struct xfrm_state *__find_acq_core(struct net *net,
16301663 return x ;
16311664}
16321665
1633- static struct xfrm_state * __xfrm_find_acq_byseq (struct net * net , u32 mark , u32 seq );
1666+ static struct xfrm_state * __xfrm_find_acq_byseq (struct net * net , u32 mark , u32 seq , u32 pcpu_num );
16341667
16351668int xfrm_state_add (struct xfrm_state * x )
16361669{
@@ -1656,7 +1689,7 @@ int xfrm_state_add(struct xfrm_state *x)
16561689 }
16571690
16581691 if (use_spi && x -> km .seq ) {
1659- x1 = __xfrm_find_acq_byseq (net , mark , x -> km .seq );
1692+ x1 = __xfrm_find_acq_byseq (net , mark , x -> km .seq , x -> pcpu_num );
16601693 if (x1 && ((x1 -> id .proto != x -> id .proto ) ||
16611694 !xfrm_addr_equal (& x1 -> id .daddr , & x -> id .daddr , family ))) {
16621695 to_put = x1 ;
@@ -1666,7 +1699,7 @@ int xfrm_state_add(struct xfrm_state *x)
16661699
16671700 if (use_spi && !x1 )
16681701 x1 = __find_acq_core (net , & x -> mark , family , x -> props .mode ,
1669- x -> props .reqid , x -> if_id , x -> id .proto ,
1702+ x -> props .reqid , x -> if_id , x -> pcpu_num , x -> id .proto ,
16701703 & x -> id .daddr , & x -> props .saddr , 0 );
16711704
16721705 __xfrm_state_bump_genids (x );
@@ -1791,6 +1824,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
17911824 x -> props .flags = orig -> props .flags ;
17921825 x -> props .extra_flags = orig -> props .extra_flags ;
17931826
1827+ x -> pcpu_num = orig -> pcpu_num ;
17941828 x -> if_id = orig -> if_id ;
17951829 x -> tfcpad = orig -> tfcpad ;
17961830 x -> replay_maxdiff = orig -> replay_maxdiff ;
@@ -2066,13 +2100,14 @@ EXPORT_SYMBOL(xfrm_state_lookup_byaddr);
20662100
20672101struct xfrm_state *
20682102xfrm_find_acq (struct net * net , const struct xfrm_mark * mark , u8 mode , u32 reqid ,
2069- u32 if_id , u8 proto , const xfrm_address_t * daddr ,
2103+ u32 if_id , u32 pcpu_num , u8 proto , const xfrm_address_t * daddr ,
20702104 const xfrm_address_t * saddr , int create , unsigned short family )
20712105{
20722106 struct xfrm_state * x ;
20732107
20742108 spin_lock_bh (& net -> xfrm .xfrm_state_lock );
2075- x = __find_acq_core (net , mark , family , mode , reqid , if_id , proto , daddr , saddr , create );
2109+ x = __find_acq_core (net , mark , family , mode , reqid , if_id , pcpu_num ,
2110+ proto , daddr , saddr , create );
20762111 spin_unlock_bh (& net -> xfrm .xfrm_state_lock );
20772112
20782113 return x ;
@@ -2207,14 +2242,15 @@ xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
22072242
22082243/* Silly enough, but I'm lazy to build resolution list */
22092244
2210- static struct xfrm_state * __xfrm_find_acq_byseq (struct net * net , u32 mark , u32 seq )
2245+ static struct xfrm_state * __xfrm_find_acq_byseq (struct net * net , u32 mark , u32 seq , u32 pcpu_num )
22112246{
22122247 unsigned int h = xfrm_seq_hash (net , seq );
22132248 struct xfrm_state * x ;
22142249
22152250 hlist_for_each_entry_rcu (x , net -> xfrm .state_byseq + h , byseq ) {
22162251 if (x -> km .seq == seq &&
22172252 (mark & x -> mark .m ) == x -> mark .v &&
2253+ x -> pcpu_num == pcpu_num &&
22182254 x -> km .state == XFRM_STATE_ACQ ) {
22192255 xfrm_state_hold (x );
22202256 return x ;
@@ -2224,12 +2260,12 @@ static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 s
22242260 return NULL ;
22252261}
22262262
2227- struct xfrm_state * xfrm_find_acq_byseq (struct net * net , u32 mark , u32 seq )
2263+ struct xfrm_state * xfrm_find_acq_byseq (struct net * net , u32 mark , u32 seq , u32 pcpu_num )
22282264{
22292265 struct xfrm_state * x ;
22302266
22312267 spin_lock_bh (& net -> xfrm .xfrm_state_lock );
2232- x = __xfrm_find_acq_byseq (net , mark , seq );
2268+ x = __xfrm_find_acq_byseq (net , mark , seq , pcpu_num );
22332269 spin_unlock_bh (& net -> xfrm .xfrm_state_lock );
22342270 return x ;
22352271}
0 commit comments