@@ -754,6 +754,9 @@ int __xfrm_state_delete(struct xfrm_state *x)
754754 hlist_del_rcu (& x -> byseq );
755755 if (!hlist_unhashed (& x -> state_cache ))
756756 hlist_del_rcu (& x -> state_cache );
757+ if (!hlist_unhashed (& x -> state_cache_input ))
758+ hlist_del_rcu (& x -> state_cache_input );
759+
757760 if (x -> id .spi )
758761 hlist_del_rcu (& x -> byspi );
759762 net -> xfrm .state_num -- ;
@@ -1106,6 +1109,52 @@ static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark,
11061109 return NULL ;
11071110}
11081111
1112+ struct xfrm_state * xfrm_input_state_lookup (struct net * net , u32 mark ,
1113+ const xfrm_address_t * daddr ,
1114+ __be32 spi , u8 proto ,
1115+ unsigned short family )
1116+ {
1117+ struct hlist_head * state_cache_input ;
1118+ struct xfrm_state * x = NULL ;
1119+ int cpu = get_cpu ();
1120+
1121+ state_cache_input = per_cpu_ptr (net -> xfrm .state_cache_input , cpu );
1122+
1123+ rcu_read_lock ();
1124+ hlist_for_each_entry_rcu (x , state_cache_input , state_cache_input ) {
1125+ if (x -> props .family != family ||
1126+ x -> id .spi != spi ||
1127+ x -> id .proto != proto ||
1128+ !xfrm_addr_equal (& x -> id .daddr , daddr , family ))
1129+ continue ;
1130+
1131+ if ((mark & x -> mark .m ) != x -> mark .v )
1132+ continue ;
1133+ if (!xfrm_state_hold_rcu (x ))
1134+ continue ;
1135+ goto out ;
1136+ }
1137+
1138+ x = __xfrm_state_lookup (net , mark , daddr , spi , proto , family );
1139+
1140+ if (x && x -> km .state == XFRM_STATE_VALID ) {
1141+ spin_lock_bh (& net -> xfrm .xfrm_state_lock );
1142+ if (hlist_unhashed (& x -> state_cache_input )) {
1143+ hlist_add_head_rcu (& x -> state_cache_input , state_cache_input );
1144+ } else {
1145+ hlist_del_rcu (& x -> state_cache_input );
1146+ hlist_add_head_rcu (& x -> state_cache_input , state_cache_input );
1147+ }
1148+ spin_unlock_bh (& net -> xfrm .xfrm_state_lock );
1149+ }
1150+
1151+ out :
1152+ rcu_read_unlock ();
1153+ put_cpu ();
1154+ return x ;
1155+ }
1156+ EXPORT_SYMBOL (xfrm_input_state_lookup );
1157+
11091158static struct xfrm_state * __xfrm_state_lookup_byaddr (struct net * net , u32 mark ,
11101159 const xfrm_address_t * daddr ,
11111160 const xfrm_address_t * saddr ,
@@ -3079,6 +3128,11 @@ int __net_init xfrm_state_init(struct net *net)
30793128 net -> xfrm .state_byseq = xfrm_hash_alloc (sz );
30803129 if (!net -> xfrm .state_byseq )
30813130 goto out_byseq ;
3131+
3132+ net -> xfrm .state_cache_input = alloc_percpu (struct hlist_head );
3133+ if (!net -> xfrm .state_cache_input )
3134+ goto out_state_cache_input ;
3135+
30823136 net -> xfrm .state_hmask = ((sz / sizeof (struct hlist_head )) - 1 );
30833137
30843138 net -> xfrm .state_num = 0 ;
@@ -3088,6 +3142,8 @@ int __net_init xfrm_state_init(struct net *net)
30883142 & net -> xfrm .xfrm_state_lock );
30893143 return 0 ;
30903144
3145+ out_state_cache_input :
3146+ xfrm_hash_free (net -> xfrm .state_byseq , sz );
30913147out_byseq :
30923148 xfrm_hash_free (net -> xfrm .state_byspi , sz );
30933149out_byspi :
@@ -3117,6 +3173,7 @@ void xfrm_state_fini(struct net *net)
31173173 xfrm_hash_free (net -> xfrm .state_bysrc , sz );
31183174 WARN_ON (!hlist_empty (net -> xfrm .state_bydst ));
31193175 xfrm_hash_free (net -> xfrm .state_bydst , sz );
3176+ free_percpu (net -> xfrm .state_cache_input );
31203177}
31213178
31223179#ifdef CONFIG_AUDITSYSCALL
0 commit comments