@@ -380,8 +380,8 @@ int udp_v4_get_port(struct sock *sk, unsigned short snum)
380
380
381
381
static int compute_score (struct sock * sk , struct net * net ,
382
382
__be32 saddr , __be16 sport ,
383
- __be32 daddr , unsigned short hnum , int dif ,
384
- bool exact_dif )
383
+ __be32 daddr , unsigned short hnum ,
384
+ int dif , int sdif , bool exact_dif )
385
385
{
386
386
int score ;
387
387
struct inet_sock * inet ;
@@ -413,10 +413,15 @@ static int compute_score(struct sock *sk, struct net *net,
413
413
}
414
414
415
415
if (sk -> sk_bound_dev_if || exact_dif ) {
416
- if (sk -> sk_bound_dev_if != dif )
416
+ bool dev_match = (sk -> sk_bound_dev_if == dif ||
417
+ sk -> sk_bound_dev_if == sdif );
418
+
419
+ if (exact_dif && !dev_match )
417
420
return -1 ;
418
- score += 4 ;
421
+ if (sk -> sk_bound_dev_if && dev_match )
422
+ score += 4 ;
419
423
}
424
+
420
425
if (sk -> sk_incoming_cpu == raw_smp_processor_id ())
421
426
score ++ ;
422
427
return score ;
@@ -436,10 +441,11 @@ static u32 udp_ehashfn(const struct net *net, const __be32 laddr,
436
441
437
442
/* called with rcu_read_lock() */
438
443
static struct sock * udp4_lib_lookup2 (struct net * net ,
439
- __be32 saddr , __be16 sport ,
440
- __be32 daddr , unsigned int hnum , int dif , bool exact_dif ,
441
- struct udp_hslot * hslot2 ,
442
- struct sk_buff * skb )
444
+ __be32 saddr , __be16 sport ,
445
+ __be32 daddr , unsigned int hnum ,
446
+ int dif , int sdif , bool exact_dif ,
447
+ struct udp_hslot * hslot2 ,
448
+ struct sk_buff * skb )
443
449
{
444
450
struct sock * sk , * result ;
445
451
int score , badness , matches = 0 , reuseport = 0 ;
@@ -449,7 +455,7 @@ static struct sock *udp4_lib_lookup2(struct net *net,
449
455
badness = 0 ;
450
456
udp_portaddr_for_each_entry_rcu (sk , & hslot2 -> head ) {
451
457
score = compute_score (sk , net , saddr , sport ,
452
- daddr , hnum , dif , exact_dif );
458
+ daddr , hnum , dif , sdif , exact_dif );
453
459
if (score > badness ) {
454
460
reuseport = sk -> sk_reuseport ;
455
461
if (reuseport ) {
@@ -477,8 +483,8 @@ static struct sock *udp4_lib_lookup2(struct net *net,
477
483
* harder than this. -DaveM
478
484
*/
479
485
struct sock * __udp4_lib_lookup (struct net * net , __be32 saddr ,
480
- __be16 sport , __be32 daddr , __be16 dport ,
481
- int dif , struct udp_table * udptable , struct sk_buff * skb )
486
+ __be16 sport , __be32 daddr , __be16 dport , int dif ,
487
+ int sdif , struct udp_table * udptable , struct sk_buff * skb )
482
488
{
483
489
struct sock * sk , * result ;
484
490
unsigned short hnum = ntohs (dport );
@@ -496,7 +502,7 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
496
502
goto begin ;
497
503
498
504
result = udp4_lib_lookup2 (net , saddr , sport ,
499
- daddr , hnum , dif ,
505
+ daddr , hnum , dif , sdif ,
500
506
exact_dif , hslot2 , skb );
501
507
if (!result ) {
502
508
unsigned int old_slot2 = slot2 ;
@@ -511,7 +517,7 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
511
517
goto begin ;
512
518
513
519
result = udp4_lib_lookup2 (net , saddr , sport ,
514
- daddr , hnum , dif ,
520
+ daddr , hnum , dif , sdif ,
515
521
exact_dif , hslot2 , skb );
516
522
}
517
523
return result ;
@@ -521,7 +527,7 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
521
527
badness = 0 ;
522
528
sk_for_each_rcu (sk , & hslot -> head ) {
523
529
score = compute_score (sk , net , saddr , sport ,
524
- daddr , hnum , dif , exact_dif );
530
+ daddr , hnum , dif , sdif , exact_dif );
525
531
if (score > badness ) {
526
532
reuseport = sk -> sk_reuseport ;
527
533
if (reuseport ) {
@@ -554,7 +560,7 @@ static inline struct sock *__udp4_lib_lookup_skb(struct sk_buff *skb,
554
560
555
561
return __udp4_lib_lookup (dev_net (skb -> dev ), iph -> saddr , sport ,
556
562
iph -> daddr , dport , inet_iif (skb ),
557
- udptable , skb );
563
+ inet_sdif ( skb ), udptable , skb );
558
564
}
559
565
560
566
struct sock * udp4_lib_lookup_skb (struct sk_buff * skb ,
@@ -576,7 +582,7 @@ struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport,
576
582
struct sock * sk ;
577
583
578
584
sk = __udp4_lib_lookup (net , saddr , sport , daddr , dport ,
579
- dif , & udp_table , NULL );
585
+ dif , 0 , & udp_table , NULL );
580
586
if (sk && !refcount_inc_not_zero (& sk -> sk_refcnt ))
581
587
sk = NULL ;
582
588
return sk ;
@@ -587,7 +593,7 @@ EXPORT_SYMBOL_GPL(udp4_lib_lookup);
587
593
static inline bool __udp_is_mcast_sock (struct net * net , struct sock * sk ,
588
594
__be16 loc_port , __be32 loc_addr ,
589
595
__be16 rmt_port , __be32 rmt_addr ,
590
- int dif , unsigned short hnum )
596
+ int dif , int sdif , unsigned short hnum )
591
597
{
592
598
struct inet_sock * inet = inet_sk (sk );
593
599
@@ -597,7 +603,8 @@ static inline bool __udp_is_mcast_sock(struct net *net, struct sock *sk,
597
603
(inet -> inet_dport != rmt_port && inet -> inet_dport ) ||
598
604
(inet -> inet_rcv_saddr && inet -> inet_rcv_saddr != loc_addr ) ||
599
605
ipv6_only_sock (sk ) ||
600
- (sk -> sk_bound_dev_if && sk -> sk_bound_dev_if != dif ))
606
+ (sk -> sk_bound_dev_if && sk -> sk_bound_dev_if != dif &&
607
+ sk -> sk_bound_dev_if != sdif ))
601
608
return false;
602
609
if (!ip_mc_sf_allow (sk , loc_addr , rmt_addr , dif ))
603
610
return false;
@@ -628,8 +635,8 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
628
635
struct net * net = dev_net (skb -> dev );
629
636
630
637
sk = __udp4_lib_lookup (net , iph -> daddr , uh -> dest ,
631
- iph -> saddr , uh -> source , skb -> dev -> ifindex , udptable ,
632
- NULL );
638
+ iph -> saddr , uh -> source , skb -> dev -> ifindex , 0 ,
639
+ udptable , NULL );
633
640
if (!sk ) {
634
641
__ICMP_INC_STATS (net , ICMP_MIB_INERRORS );
635
642
return ; /* No socket for error */
@@ -1953,6 +1960,7 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
1953
1960
unsigned int hash2 = 0 , hash2_any = 0 , use_hash2 = (hslot -> count > 10 );
1954
1961
unsigned int offset = offsetof(typeof (* sk ), sk_node );
1955
1962
int dif = skb -> dev -> ifindex ;
1963
+ int sdif = inet_sdif (skb );
1956
1964
struct hlist_node * node ;
1957
1965
struct sk_buff * nskb ;
1958
1966
@@ -1967,7 +1975,7 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
1967
1975
1968
1976
sk_for_each_entry_offset_rcu (sk , node , & hslot -> head , offset ) {
1969
1977
if (!__udp_is_mcast_sock (net , sk , uh -> dest , daddr ,
1970
- uh -> source , saddr , dif , hnum ))
1978
+ uh -> source , saddr , dif , sdif , hnum ))
1971
1979
continue ;
1972
1980
1973
1981
if (!first ) {
@@ -2157,7 +2165,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
2157
2165
static struct sock * __udp4_lib_mcast_demux_lookup (struct net * net ,
2158
2166
__be16 loc_port , __be32 loc_addr ,
2159
2167
__be16 rmt_port , __be32 rmt_addr ,
2160
- int dif )
2168
+ int dif , int sdif )
2161
2169
{
2162
2170
struct sock * sk , * result ;
2163
2171
unsigned short hnum = ntohs (loc_port );
@@ -2171,7 +2179,7 @@ static struct sock *__udp4_lib_mcast_demux_lookup(struct net *net,
2171
2179
result = NULL ;
2172
2180
sk_for_each_rcu (sk , & hslot -> head ) {
2173
2181
if (__udp_is_mcast_sock (net , sk , loc_port , loc_addr ,
2174
- rmt_port , rmt_addr , dif , hnum )) {
2182
+ rmt_port , rmt_addr , dif , sdif , hnum )) {
2175
2183
if (result )
2176
2184
return NULL ;
2177
2185
result = sk ;
@@ -2216,6 +2224,7 @@ void udp_v4_early_demux(struct sk_buff *skb)
2216
2224
struct sock * sk = NULL ;
2217
2225
struct dst_entry * dst ;
2218
2226
int dif = skb -> dev -> ifindex ;
2227
+ int sdif = inet_sdif (skb );
2219
2228
int ours ;
2220
2229
2221
2230
/* validate the packet */
@@ -2241,7 +2250,8 @@ void udp_v4_early_demux(struct sk_buff *skb)
2241
2250
}
2242
2251
2243
2252
sk = __udp4_lib_mcast_demux_lookup (net , uh -> dest , iph -> daddr ,
2244
- uh -> source , iph -> saddr , dif );
2253
+ uh -> source , iph -> saddr ,
2254
+ dif , sdif );
2245
2255
} else if (skb -> pkt_type == PACKET_HOST ) {
2246
2256
sk = __udp4_lib_demux_lookup (net , uh -> dest , iph -> daddr ,
2247
2257
uh -> source , iph -> saddr , dif );
0 commit comments