@@ -951,6 +951,49 @@ xfrm_init_tempstate(struct xfrm_state *x, const struct flowi *fl,
951951 x -> props .family = tmpl -> encap_family ;
952952}
953953
954+ static struct xfrm_state * __xfrm_state_lookup_all (struct net * net , u32 mark ,
955+ const xfrm_address_t * daddr ,
956+ __be32 spi , u8 proto ,
957+ unsigned short family ,
958+ struct xfrm_dev_offload * xdo )
959+ {
960+ unsigned int h = xfrm_spi_hash (net , daddr , spi , proto , family );
961+ struct xfrm_state * x ;
962+
963+ hlist_for_each_entry_rcu (x , net -> xfrm .state_byspi + h , byspi ) {
964+ #ifdef CONFIG_XFRM_OFFLOAD
965+ if (xdo -> type == XFRM_DEV_OFFLOAD_PACKET ) {
966+ if (x -> xso .type != XFRM_DEV_OFFLOAD_PACKET )
967+ /* HW states are in the head of list, there is
968+ * no need to iterate further.
969+ */
970+ break ;
971+
972+ /* Packet offload: both policy and SA should
973+ * have same device.
974+ */
975+ if (xdo -> dev != x -> xso .dev )
976+ continue ;
977+ } else if (x -> xso .type == XFRM_DEV_OFFLOAD_PACKET )
978+ /* Skip HW policy for SW lookups */
979+ continue ;
980+ #endif
981+ if (x -> props .family != family ||
982+ x -> id .spi != spi ||
983+ x -> id .proto != proto ||
984+ !xfrm_addr_equal (& x -> id .daddr , daddr , family ))
985+ continue ;
986+
987+ if ((mark & x -> mark .m ) != x -> mark .v )
988+ continue ;
989+ if (!xfrm_state_hold_rcu (x ))
990+ continue ;
991+ return x ;
992+ }
993+
994+ return NULL ;
995+ }
996+
954997static struct xfrm_state * __xfrm_state_lookup (struct net * net , u32 mark ,
955998 const xfrm_address_t * daddr ,
956999 __be32 spi , u8 proto ,
@@ -1092,6 +1135,23 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
10921135 rcu_read_lock ();
10931136 h = xfrm_dst_hash (net , daddr , saddr , tmpl -> reqid , encap_family );
10941137 hlist_for_each_entry_rcu (x , net -> xfrm .state_bydst + h , bydst ) {
1138+ #ifdef CONFIG_XFRM_OFFLOAD
1139+ if (pol -> xdo .type == XFRM_DEV_OFFLOAD_PACKET ) {
1140+ if (x -> xso .type != XFRM_DEV_OFFLOAD_PACKET )
1141+ /* HW states are in the head of list, there is
1142+ * no need to iterate further.
1143+ */
1144+ break ;
1145+
1146+ /* Packet offload: both policy and SA should
1147+ * have same device.
1148+ */
1149+ if (pol -> xdo .dev != x -> xso .dev )
1150+ continue ;
1151+ } else if (x -> xso .type == XFRM_DEV_OFFLOAD_PACKET )
1152+ /* Skip HW policy for SW lookups */
1153+ continue ;
1154+ #endif
10951155 if (x -> props .family == encap_family &&
10961156 x -> props .reqid == tmpl -> reqid &&
10971157 (mark & x -> mark .m ) == x -> mark .v &&
@@ -1109,6 +1169,23 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
11091169
11101170 h_wildcard = xfrm_dst_hash (net , daddr , & saddr_wildcard , tmpl -> reqid , encap_family );
11111171 hlist_for_each_entry_rcu (x , net -> xfrm .state_bydst + h_wildcard , bydst ) {
1172+ #ifdef CONFIG_XFRM_OFFLOAD
1173+ if (pol -> xdo .type == XFRM_DEV_OFFLOAD_PACKET ) {
1174+ if (x -> xso .type != XFRM_DEV_OFFLOAD_PACKET )
1175+ /* HW states are in the head of list, there is
1176+ * no need to iterate further.
1177+ */
1178+ break ;
1179+
1180+ /* Packet offload: both policy and SA should
1181+ * have same device.
1182+ */
1183+ if (pol -> xdo .dev != x -> xso .dev )
1184+ continue ;
1185+ } else if (x -> xso .type == XFRM_DEV_OFFLOAD_PACKET )
1186+ /* Skip HW policy for SW lookups */
1187+ continue ;
1188+ #endif
11121189 if (x -> props .family == encap_family &&
11131190 x -> props .reqid == tmpl -> reqid &&
11141191 (mark & x -> mark .m ) == x -> mark .v &&
@@ -1126,8 +1203,10 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
11261203 x = best ;
11271204 if (!x && !error && !acquire_in_progress ) {
11281205 if (tmpl -> id .spi &&
1129- (x0 = __xfrm_state_lookup (net , mark , daddr , tmpl -> id .spi ,
1130- tmpl -> id .proto , encap_family )) != NULL ) {
1206+ (x0 = __xfrm_state_lookup_all (net , mark , daddr ,
1207+ tmpl -> id .spi , tmpl -> id .proto ,
1208+ encap_family ,
1209+ & pol -> xdo )) != NULL ) {
11311210 to_put = x0 ;
11321211 error = - EEXIST ;
11331212 goto out ;
@@ -1161,7 +1240,31 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
11611240 x = NULL ;
11621241 goto out ;
11631242 }
1164-
1243+ #ifdef CONFIG_XFRM_OFFLOAD
1244+ if (pol -> xdo .type == XFRM_DEV_OFFLOAD_PACKET ) {
1245+ struct xfrm_dev_offload * xdo = & pol -> xdo ;
1246+ struct xfrm_dev_offload * xso = & x -> xso ;
1247+
1248+ xso -> type = XFRM_DEV_OFFLOAD_PACKET ;
1249+ xso -> dir = xdo -> dir ;
1250+ xso -> dev = xdo -> dev ;
1251+ xso -> real_dev = xdo -> real_dev ;
1252+ netdev_tracker_alloc (xso -> dev , & xso -> dev_tracker ,
1253+ GFP_ATOMIC );
1254+ error = xso -> dev -> xfrmdev_ops -> xdo_dev_state_add (x );
1255+ if (error ) {
1256+ xso -> dir = 0 ;
1257+ netdev_put (xso -> dev , & xso -> dev_tracker );
1258+ xso -> dev = NULL ;
1259+ xso -> real_dev = NULL ;
1260+ xso -> type = XFRM_DEV_OFFLOAD_UNSPECIFIED ;
1261+ x -> km .state = XFRM_STATE_DEAD ;
1262+ to_put = x ;
1263+ x = NULL ;
1264+ goto out ;
1265+ }
1266+ }
1267+ #endif
11651268 if (km_query (x , tmpl , pol ) == 0 ) {
11661269 spin_lock_bh (& net -> xfrm .xfrm_state_lock );
11671270 x -> km .state = XFRM_STATE_ACQ ;
@@ -1185,6 +1288,18 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
11851288 xfrm_hash_grow_check (net , x -> bydst .next != NULL );
11861289 spin_unlock_bh (& net -> xfrm .xfrm_state_lock );
11871290 } else {
1291+ #ifdef CONFIG_XFRM_OFFLOAD
1292+ struct xfrm_dev_offload * xso = & x -> xso ;
1293+
1294+ if (xso -> type == XFRM_DEV_OFFLOAD_PACKET ) {
1295+ xso -> dev -> xfrmdev_ops -> xdo_dev_state_delete (x );
1296+ xso -> dir = 0 ;
1297+ netdev_put (xso -> dev , & xso -> dev_tracker );
1298+ xso -> dev = NULL ;
1299+ xso -> real_dev = NULL ;
1300+ xso -> type = XFRM_DEV_OFFLOAD_UNSPECIFIED ;
1301+ }
1302+ #endif
11881303 x -> km .state = XFRM_STATE_DEAD ;
11891304 to_put = x ;
11901305 x = NULL ;
0 commit comments