@@ -1257,10 +1257,13 @@ static void xfrm_hash_rebuild(struct work_struct *work)
1257
1257
{
1258
1258
struct net * net = container_of (work , struct net ,
1259
1259
xfrm .policy_hthresh .work );
1260
+ unsigned int hmask ;
1260
1261
struct xfrm_policy * pol ;
1261
1262
struct xfrm_policy * policy ;
1262
1263
struct hlist_head * chain ;
1264
+ struct hlist_head * odst ;
1263
1265
struct hlist_node * newpos ;
1266
+ int i ;
1264
1267
int dir ;
1265
1268
unsigned seq ;
1266
1269
u8 lbits4 , rbits4 , lbits6 , rbits6 ;
@@ -1321,7 +1324,23 @@ static void xfrm_hash_rebuild(struct work_struct *work)
1321
1324
goto out_unlock ;
1322
1325
}
1323
1326
1327
+ /* reset the bydst and inexact table in all directions */
1324
1328
for (dir = 0 ; dir < XFRM_POLICY_MAX ; dir ++ ) {
1329
+ struct hlist_node * n ;
1330
+
1331
+ hlist_for_each_entry_safe (policy , n ,
1332
+ & net -> xfrm .policy_inexact [dir ],
1333
+ bydst_inexact_list ) {
1334
+ hlist_del_rcu (& policy -> bydst );
1335
+ hlist_del_init (& policy -> bydst_inexact_list );
1336
+ }
1337
+
1338
+ hmask = net -> xfrm .policy_bydst [dir ].hmask ;
1339
+ odst = net -> xfrm .policy_bydst [dir ].table ;
1340
+ for (i = hmask ; i >= 0 ; i -- ) {
1341
+ hlist_for_each_entry_safe (policy , n , odst + i , bydst )
1342
+ hlist_del_rcu (& policy -> bydst );
1343
+ }
1325
1344
if ((dir & XFRM_POLICY_MASK ) == XFRM_POLICY_OUT ) {
1326
1345
/* dir out => dst = remote, src = local */
1327
1346
net -> xfrm .policy_bydst [dir ].dbits4 = rbits4 ;
@@ -4467,50 +4486,63 @@ EXPORT_SYMBOL_GPL(xfrm_audit_policy_delete);
4467
4486
#endif
4468
4487
4469
4488
#ifdef CONFIG_XFRM_MIGRATE
4489
+ static bool xfrm_migrate_selector_match (const struct xfrm_selector * sel_cmp ,
4490
+ const struct xfrm_selector * sel_tgt )
4491
+ {
4492
+ if (sel_cmp -> proto == IPSEC_ULPROTO_ANY ) {
4493
+ if (sel_tgt -> family == sel_cmp -> family &&
4494
+ xfrm_addr_equal (& sel_tgt -> daddr , & sel_cmp -> daddr ,
4495
+ sel_cmp -> family ) &&
4496
+ xfrm_addr_equal (& sel_tgt -> saddr , & sel_cmp -> saddr ,
4497
+ sel_cmp -> family ) &&
4498
+ sel_tgt -> prefixlen_d == sel_cmp -> prefixlen_d &&
4499
+ sel_tgt -> prefixlen_s == sel_cmp -> prefixlen_s ) {
4500
+ return true;
4501
+ }
4502
+ } else {
4503
+ if (memcmp (sel_tgt , sel_cmp , sizeof (* sel_tgt )) == 0 ) {
4504
+ return true;
4505
+ }
4506
+ }
4507
+ return false;
4508
+ }
4509
+
4470
4510
static struct xfrm_policy * xfrm_migrate_policy_find (const struct xfrm_selector * sel ,
4471
4511
u8 dir , u8 type , struct net * net , u32 if_id )
4472
4512
{
4473
- struct xfrm_policy * pol ;
4474
- struct flowi fl ;
4475
-
4476
- memset (& fl , 0 , sizeof (fl ));
4477
-
4478
- fl .flowi_proto = sel -> proto ;
4513
+ struct xfrm_policy * pol , * ret = NULL ;
4514
+ struct hlist_head * chain ;
4515
+ u32 priority = ~0U ;
4479
4516
4480
- switch (sel -> family ) {
4481
- case AF_INET :
4482
- fl .u .ip4 .saddr = sel -> saddr .a4 ;
4483
- fl .u .ip4 .daddr = sel -> daddr .a4 ;
4484
- if (sel -> proto == IPSEC_ULPROTO_ANY )
4517
+ spin_lock_bh (& net -> xfrm .xfrm_policy_lock );
4518
+ chain = policy_hash_direct (net , & sel -> daddr , & sel -> saddr , sel -> family , dir );
4519
+ hlist_for_each_entry (pol , chain , bydst ) {
4520
+ if ((if_id == 0 || pol -> if_id == if_id ) &&
4521
+ xfrm_migrate_selector_match (sel , & pol -> selector ) &&
4522
+ pol -> type == type ) {
4523
+ ret = pol ;
4524
+ priority = ret -> priority ;
4485
4525
break ;
4486
- fl .u .flowi4_oif = sel -> ifindex ;
4487
- fl .u .ip4 .fl4_sport = sel -> sport ;
4488
- fl .u .ip4 .fl4_dport = sel -> dport ;
4489
- break ;
4490
- case AF_INET6 :
4491
- fl .u .ip6 .saddr = sel -> saddr .in6 ;
4492
- fl .u .ip6 .daddr = sel -> daddr .in6 ;
4493
- if (sel -> proto == IPSEC_ULPROTO_ANY )
4526
+ }
4527
+ }
4528
+ chain = & net -> xfrm .policy_inexact [dir ];
4529
+ hlist_for_each_entry (pol , chain , bydst_inexact_list ) {
4530
+ if ((pol -> priority >= priority ) && ret )
4494
4531
break ;
4495
- fl .u .flowi6_oif = sel -> ifindex ;
4496
- fl .u .ip6 .fl4_sport = sel -> sport ;
4497
- fl .u .ip6 .fl4_dport = sel -> dport ;
4498
- break ;
4499
- default :
4500
- return ERR_PTR (- EAFNOSUPPORT );
4532
+
4533
+ if ((if_id == 0 || pol -> if_id == if_id ) &&
4534
+ xfrm_migrate_selector_match (sel , & pol -> selector ) &&
4535
+ pol -> type == type ) {
4536
+ ret = pol ;
4537
+ break ;
4538
+ }
4501
4539
}
4502
4540
4503
- rcu_read_lock ( );
4541
+ xfrm_pol_hold ( ret );
4504
4542
4505
- pol = xfrm_policy_lookup_bytype (net , type , & fl , sel -> family , dir , if_id );
4506
- if (IS_ERR_OR_NULL (pol ))
4507
- goto out_unlock ;
4543
+ spin_unlock_bh (& net -> xfrm .xfrm_policy_lock );
4508
4544
4509
- if (!xfrm_pol_hold_rcu (pol ))
4510
- pol = NULL ;
4511
- out_unlock :
4512
- rcu_read_unlock ();
4513
- return pol ;
4545
+ return ret ;
4514
4546
}
4515
4547
4516
4548
static int migrate_tmpl_match (const struct xfrm_migrate * m , const struct xfrm_tmpl * t )
@@ -4647,9 +4679,9 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
4647
4679
4648
4680
/* Stage 1 - find policy */
4649
4681
pol = xfrm_migrate_policy_find (sel , dir , type , net , if_id );
4650
- if (IS_ERR_OR_NULL ( pol ) ) {
4682
+ if (! pol ) {
4651
4683
NL_SET_ERR_MSG (extack , "Target policy not found" );
4652
- err = IS_ERR ( pol ) ? PTR_ERR ( pol ) : - ENOENT ;
4684
+ err = - ENOENT ;
4653
4685
goto out ;
4654
4686
}
4655
4687
0 commit comments