@@ -196,8 +196,6 @@ xfrm_policy_inexact_lookup_rcu(struct net *net,
196
196
static struct xfrm_policy *
197
197
xfrm_policy_insert_list (struct hlist_head * chain , struct xfrm_policy * policy ,
198
198
bool excl );
199
- static void xfrm_policy_insert_inexact_list (struct hlist_head * chain ,
200
- struct xfrm_policy * policy );
201
199
202
200
static bool
203
201
xfrm_policy_find_inexact_candidates (struct xfrm_pol_inexact_candidates * cand ,
@@ -410,7 +408,6 @@ struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp)
410
408
if (policy ) {
411
409
write_pnet (& policy -> xp_net , net );
412
410
INIT_LIST_HEAD (& policy -> walk .all );
413
- INIT_HLIST_NODE (& policy -> bydst_inexact_list );
414
411
INIT_HLIST_NODE (& policy -> bydst );
415
412
INIT_HLIST_NODE (& policy -> byidx );
416
413
rwlock_init (& policy -> lock );
@@ -1228,26 +1225,31 @@ xfrm_policy_inexact_insert(struct xfrm_policy *policy, u8 dir, int excl)
1228
1225
return ERR_PTR (- EEXIST );
1229
1226
}
1230
1227
1231
- chain = & net -> xfrm .policy_inexact [dir ];
1232
- xfrm_policy_insert_inexact_list (chain , policy );
1233
-
1234
1228
if (delpol )
1235
1229
__xfrm_policy_inexact_prune_bin (bin , false);
1236
1230
1237
1231
return delpol ;
1238
1232
}
1239
1233
1234
+ static bool xfrm_policy_is_dead_or_sk (const struct xfrm_policy * policy )
1235
+ {
1236
+ int dir ;
1237
+
1238
+ if (policy -> walk .dead )
1239
+ return true;
1240
+
1241
+ dir = xfrm_policy_id2dir (policy -> index );
1242
+ return dir >= XFRM_POLICY_MAX ;
1243
+ }
1244
+
1240
1245
static void xfrm_hash_rebuild (struct work_struct * work )
1241
1246
{
1242
1247
struct net * net = container_of (work , struct net ,
1243
1248
xfrm .policy_hthresh .work );
1244
- unsigned int hmask ;
1245
1249
struct xfrm_policy * pol ;
1246
1250
struct xfrm_policy * policy ;
1247
1251
struct hlist_head * chain ;
1248
- struct hlist_head * odst ;
1249
1252
struct hlist_node * newpos ;
1250
- int i ;
1251
1253
int dir ;
1252
1254
unsigned seq ;
1253
1255
u8 lbits4 , rbits4 , lbits6 , rbits6 ;
@@ -1311,23 +1313,7 @@ static void xfrm_hash_rebuild(struct work_struct *work)
1311
1313
goto out_unlock ;
1312
1314
}
1313
1315
1314
- /* reset the bydst and inexact table in all directions */
1315
1316
for (dir = 0 ; dir < XFRM_POLICY_MAX ; dir ++ ) {
1316
- struct hlist_node * n ;
1317
-
1318
- hlist_for_each_entry_safe (policy , n ,
1319
- & net -> xfrm .policy_inexact [dir ],
1320
- bydst_inexact_list ) {
1321
- hlist_del_rcu (& policy -> bydst );
1322
- hlist_del_init (& policy -> bydst_inexact_list );
1323
- }
1324
-
1325
- hmask = net -> xfrm .policy_bydst [dir ].hmask ;
1326
- odst = net -> xfrm .policy_bydst [dir ].table ;
1327
- for (i = hmask ; i >= 0 ; i -- ) {
1328
- hlist_for_each_entry_safe (policy , n , odst + i , bydst )
1329
- hlist_del_rcu (& policy -> bydst );
1330
- }
1331
1317
if ((dir & XFRM_POLICY_MASK ) == XFRM_POLICY_OUT ) {
1332
1318
/* dir out => dst = remote, src = local */
1333
1319
net -> xfrm .policy_bydst [dir ].dbits4 = rbits4 ;
@@ -1352,6 +1338,9 @@ static void xfrm_hash_rebuild(struct work_struct *work)
1352
1338
/* skip socket policies */
1353
1339
continue ;
1354
1340
}
1341
+
1342
+ hlist_del_rcu (& policy -> bydst );
1343
+
1355
1344
newpos = NULL ;
1356
1345
chain = policy_hash_bysel (net , & policy -> selector ,
1357
1346
policy -> family , dir );
@@ -1519,42 +1508,6 @@ static const struct rhashtable_params xfrm_pol_inexact_params = {
1519
1508
.automatic_shrinking = true,
1520
1509
};
1521
1510
1522
- static void xfrm_policy_insert_inexact_list (struct hlist_head * chain ,
1523
- struct xfrm_policy * policy )
1524
- {
1525
- struct xfrm_policy * pol , * delpol = NULL ;
1526
- struct hlist_node * newpos = NULL ;
1527
- int i = 0 ;
1528
-
1529
- hlist_for_each_entry (pol , chain , bydst_inexact_list ) {
1530
- if (pol -> type == policy -> type &&
1531
- pol -> if_id == policy -> if_id &&
1532
- !selector_cmp (& pol -> selector , & policy -> selector ) &&
1533
- xfrm_policy_mark_match (& policy -> mark , pol ) &&
1534
- xfrm_sec_ctx_match (pol -> security , policy -> security ) &&
1535
- !WARN_ON (delpol )) {
1536
- delpol = pol ;
1537
- if (policy -> priority > pol -> priority )
1538
- continue ;
1539
- } else if (policy -> priority >= pol -> priority ) {
1540
- newpos = & pol -> bydst_inexact_list ;
1541
- continue ;
1542
- }
1543
- if (delpol )
1544
- break ;
1545
- }
1546
-
1547
- if (newpos && policy -> xdo .type != XFRM_DEV_OFFLOAD_PACKET )
1548
- hlist_add_behind_rcu (& policy -> bydst_inexact_list , newpos );
1549
- else
1550
- hlist_add_head_rcu (& policy -> bydst_inexact_list , chain );
1551
-
1552
- hlist_for_each_entry (pol , chain , bydst_inexact_list ) {
1553
- pol -> pos = i ;
1554
- i ++ ;
1555
- }
1556
- }
1557
-
1558
1511
static struct xfrm_policy * xfrm_policy_insert_list (struct hlist_head * chain ,
1559
1512
struct xfrm_policy * policy ,
1560
1513
bool excl )
@@ -2294,10 +2247,52 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir,
2294
2247
return pol ;
2295
2248
}
2296
2249
2250
+ static u32 xfrm_gen_pos_slow (struct net * net )
2251
+ {
2252
+ struct xfrm_policy * policy ;
2253
+ u32 i = 0 ;
2254
+
2255
+ /* oldest entry is last in list */
2256
+ list_for_each_entry_reverse (policy , & net -> xfrm .policy_all , walk .all ) {
2257
+ if (!xfrm_policy_is_dead_or_sk (policy ))
2258
+ policy -> pos = ++ i ;
2259
+ }
2260
+
2261
+ return i ;
2262
+ }
2263
+
2264
+ static u32 xfrm_gen_pos (struct net * net )
2265
+ {
2266
+ const struct xfrm_policy * policy ;
2267
+ u32 i = 0 ;
2268
+
2269
+ /* most recently added policy is at the head of the list */
2270
+ list_for_each_entry (policy , & net -> xfrm .policy_all , walk .all ) {
2271
+ if (xfrm_policy_is_dead_or_sk (policy ))
2272
+ continue ;
2273
+
2274
+ if (policy -> pos == UINT_MAX )
2275
+ return xfrm_gen_pos_slow (net );
2276
+
2277
+ i = policy -> pos + 1 ;
2278
+ break ;
2279
+ }
2280
+
2281
+ return i ;
2282
+ }
2283
+
2297
2284
static void __xfrm_policy_link (struct xfrm_policy * pol , int dir )
2298
2285
{
2299
2286
struct net * net = xp_net (pol );
2300
2287
2288
+ switch (dir ) {
2289
+ case XFRM_POLICY_IN :
2290
+ case XFRM_POLICY_FWD :
2291
+ case XFRM_POLICY_OUT :
2292
+ pol -> pos = xfrm_gen_pos (net );
2293
+ break ;
2294
+ }
2295
+
2301
2296
list_add (& pol -> walk .all , & net -> xfrm .policy_all );
2302
2297
net -> xfrm .policy_count [dir ]++ ;
2303
2298
xfrm_pol_hold (pol );
@@ -2314,7 +2309,6 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
2314
2309
/* Socket policies are not hashed. */
2315
2310
if (!hlist_unhashed (& pol -> bydst )) {
2316
2311
hlist_del_rcu (& pol -> bydst );
2317
- hlist_del_init (& pol -> bydst_inexact_list );
2318
2312
hlist_del (& pol -> byidx );
2319
2313
}
2320
2314
@@ -4437,63 +4431,50 @@ EXPORT_SYMBOL_GPL(xfrm_audit_policy_delete);
4437
4431
#endif
4438
4432
4439
4433
#ifdef CONFIG_XFRM_MIGRATE
4440
- static bool xfrm_migrate_selector_match (const struct xfrm_selector * sel_cmp ,
4441
- const struct xfrm_selector * sel_tgt )
4442
- {
4443
- if (sel_cmp -> proto == IPSEC_ULPROTO_ANY ) {
4444
- if (sel_tgt -> family == sel_cmp -> family &&
4445
- xfrm_addr_equal (& sel_tgt -> daddr , & sel_cmp -> daddr ,
4446
- sel_cmp -> family ) &&
4447
- xfrm_addr_equal (& sel_tgt -> saddr , & sel_cmp -> saddr ,
4448
- sel_cmp -> family ) &&
4449
- sel_tgt -> prefixlen_d == sel_cmp -> prefixlen_d &&
4450
- sel_tgt -> prefixlen_s == sel_cmp -> prefixlen_s ) {
4451
- return true;
4452
- }
4453
- } else {
4454
- if (memcmp (sel_tgt , sel_cmp , sizeof (* sel_tgt )) == 0 ) {
4455
- return true;
4456
- }
4457
- }
4458
- return false;
4459
- }
4460
-
4461
4434
static struct xfrm_policy * xfrm_migrate_policy_find (const struct xfrm_selector * sel ,
4462
4435
u8 dir , u8 type , struct net * net , u32 if_id )
4463
4436
{
4464
4437
struct xfrm_policy * pol , * ret = NULL ;
4465
- struct hlist_head * chain ;
4466
- u32 priority = ~0U ;
4438
+ struct flowi fl ;
4467
4439
4468
- spin_lock_bh (& net -> xfrm .xfrm_policy_lock );
4469
- chain = policy_hash_direct (net , & sel -> daddr , & sel -> saddr , sel -> family , dir );
4470
- hlist_for_each_entry (pol , chain , bydst ) {
4471
- if ((if_id == 0 || pol -> if_id == if_id ) &&
4472
- xfrm_migrate_selector_match (sel , & pol -> selector ) &&
4473
- pol -> type == type ) {
4474
- ret = pol ;
4475
- priority = ret -> priority ;
4476
- break ;
4477
- }
4478
- }
4479
- chain = & net -> xfrm .policy_inexact [dir ];
4480
- hlist_for_each_entry (pol , chain , bydst_inexact_list ) {
4481
- if ((pol -> priority >= priority ) && ret )
4482
- break ;
4440
+ memset (& fl , 0 , sizeof (fl ));
4483
4441
4484
- if ((if_id == 0 || pol -> if_id == if_id ) &&
4485
- xfrm_migrate_selector_match (sel , & pol -> selector ) &&
4486
- pol -> type == type ) {
4487
- ret = pol ;
4442
+ fl .flowi_proto = sel -> proto ;
4443
+
4444
+ switch (sel -> family ) {
4445
+ case AF_INET :
4446
+ fl .u .ip4 .saddr = sel -> saddr .a4 ;
4447
+ fl .u .ip4 .daddr = sel -> daddr .a4 ;
4448
+ if (sel -> proto == IPSEC_ULPROTO_ANY )
4488
4449
break ;
4489
- }
4450
+ fl .u .flowi4_oif = sel -> ifindex ;
4451
+ fl .u .ip4 .fl4_sport = sel -> sport ;
4452
+ fl .u .ip4 .fl4_dport = sel -> dport ;
4453
+ break ;
4454
+ case AF_INET6 :
4455
+ fl .u .ip6 .saddr = sel -> saddr .in6 ;
4456
+ fl .u .ip6 .daddr = sel -> daddr .in6 ;
4457
+ if (sel -> proto == IPSEC_ULPROTO_ANY )
4458
+ break ;
4459
+ fl .u .flowi6_oif = sel -> ifindex ;
4460
+ fl .u .ip6 .fl4_sport = sel -> sport ;
4461
+ fl .u .ip6 .fl4_dport = sel -> dport ;
4462
+ break ;
4463
+ default :
4464
+ return ERR_PTR (- EAFNOSUPPORT );
4490
4465
}
4491
4466
4492
- xfrm_pol_hold ( ret );
4467
+ rcu_read_lock ( );
4493
4468
4494
- spin_unlock_bh (& net -> xfrm .xfrm_policy_lock );
4469
+ pol = xfrm_policy_lookup_bytype (net , type , & fl , sel -> family , dir , if_id );
4470
+ if (IS_ERR_OR_NULL (pol ))
4471
+ goto out_unlock ;
4495
4472
4496
- return ret ;
4473
+ if (!xfrm_pol_hold_rcu (ret ))
4474
+ pol = NULL ;
4475
+ out_unlock :
4476
+ rcu_read_unlock ();
4477
+ return pol ;
4497
4478
}
4498
4479
4499
4480
static int migrate_tmpl_match (const struct xfrm_migrate * m , const struct xfrm_tmpl * t )
@@ -4630,9 +4611,9 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
4630
4611
4631
4612
/* Stage 1 - find policy */
4632
4613
pol = xfrm_migrate_policy_find (sel , dir , type , net , if_id );
4633
- if (! pol ) {
4614
+ if (IS_ERR_OR_NULL ( pol ) ) {
4634
4615
NL_SET_ERR_MSG (extack , "Target policy not found" );
4635
- err = - ENOENT ;
4616
+ err = IS_ERR ( pol ) ? PTR_ERR ( pol ) : - ENOENT ;
4636
4617
goto out ;
4637
4618
}
4638
4619
0 commit comments