@@ -951,6 +951,49 @@ xfrm_init_tempstate(struct xfrm_state *x, const struct flowi *fl,
951
951
x -> props .family = tmpl -> encap_family ;
952
952
}
953
953
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
+
954
997
static struct xfrm_state * __xfrm_state_lookup (struct net * net , u32 mark ,
955
998
const xfrm_address_t * daddr ,
956
999
__be32 spi , u8 proto ,
@@ -1092,6 +1135,23 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
1092
1135
rcu_read_lock ();
1093
1136
h = xfrm_dst_hash (net , daddr , saddr , tmpl -> reqid , encap_family );
1094
1137
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
1095
1155
if (x -> props .family == encap_family &&
1096
1156
x -> props .reqid == tmpl -> reqid &&
1097
1157
(mark & x -> mark .m ) == x -> mark .v &&
@@ -1109,6 +1169,23 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
1109
1169
1110
1170
h_wildcard = xfrm_dst_hash (net , daddr , & saddr_wildcard , tmpl -> reqid , encap_family );
1111
1171
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
1112
1189
if (x -> props .family == encap_family &&
1113
1190
x -> props .reqid == tmpl -> reqid &&
1114
1191
(mark & x -> mark .m ) == x -> mark .v &&
@@ -1126,8 +1203,10 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
1126
1203
x = best ;
1127
1204
if (!x && !error && !acquire_in_progress ) {
1128
1205
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 ) {
1131
1210
to_put = x0 ;
1132
1211
error = - EEXIST ;
1133
1212
goto out ;
@@ -1161,7 +1240,31 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
1161
1240
x = NULL ;
1162
1241
goto out ;
1163
1242
}
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
1165
1268
if (km_query (x , tmpl , pol ) == 0 ) {
1166
1269
spin_lock_bh (& net -> xfrm .xfrm_state_lock );
1167
1270
x -> km .state = XFRM_STATE_ACQ ;
@@ -1185,6 +1288,18 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
1185
1288
xfrm_hash_grow_check (net , x -> bydst .next != NULL );
1186
1289
spin_unlock_bh (& net -> xfrm .xfrm_state_lock );
1187
1290
} 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
1188
1303
x -> km .state = XFRM_STATE_DEAD ;
1189
1304
to_put = x ;
1190
1305
x = NULL ;
0 commit comments