Skip to content

Commit fb74c27

Browse files
dsaherndavem330
authored andcommitted
net: ipv4: add second dif to udp socket lookups
Add a second device index, sdif, to udp socket lookups. sdif is the index for ingress devices enslaved to an l3mdev. It allows the lookups to consider the enslaved device as well as the L3 domain when searching for a socket. Early demux lookups are handled in the next patch as part of INET_MATCH changes. Signed-off-by: David Ahern <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 46d4b68 commit fb74c27

File tree

4 files changed

+48
-28
lines changed

4 files changed

+48
-28
lines changed

include/net/ip.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,16 @@ struct ipcm_cookie {
7878
#define IPCB(skb) ((struct inet_skb_parm*)((skb)->cb))
7979
#define PKTINFO_SKB_CB(skb) ((struct in_pktinfo *)((skb)->cb))
8080

81+
/* return enslaved device index if relevant */
82+
static inline int inet_sdif(struct sk_buff *skb)
83+
{
84+
#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
85+
if (skb && ipv4_l3mdev_skb(IPCB(skb)->flags))
86+
return IPCB(skb)->iif;
87+
#endif
88+
return 0;
89+
}
90+
8191
struct ip_ra_chain {
8292
struct ip_ra_chain __rcu *next;
8393
struct sock *sk;

include/net/udp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
287287
struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport,
288288
__be32 daddr, __be16 dport, int dif);
289289
struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport,
290-
__be32 daddr, __be16 dport, int dif,
290+
__be32 daddr, __be16 dport, int dif, int sdif,
291291
struct udp_table *tbl, struct sk_buff *skb);
292292
struct sock *udp4_lib_lookup_skb(struct sk_buff *skb,
293293
__be16 sport, __be16 dport);

net/ipv4/udp.c

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -380,8 +380,8 @@ int udp_v4_get_port(struct sock *sk, unsigned short snum)
380380

381381
static int compute_score(struct sock *sk, struct net *net,
382382
__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)
385385
{
386386
int score;
387387
struct inet_sock *inet;
@@ -413,10 +413,15 @@ static int compute_score(struct sock *sk, struct net *net,
413413
}
414414

415415
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)
417420
return -1;
418-
score += 4;
421+
if (sk->sk_bound_dev_if && dev_match)
422+
score += 4;
419423
}
424+
420425
if (sk->sk_incoming_cpu == raw_smp_processor_id())
421426
score++;
422427
return score;
@@ -436,10 +441,11 @@ static u32 udp_ehashfn(const struct net *net, const __be32 laddr,
436441

437442
/* called with rcu_read_lock() */
438443
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)
443449
{
444450
struct sock *sk, *result;
445451
int score, badness, matches = 0, reuseport = 0;
@@ -449,7 +455,7 @@ static struct sock *udp4_lib_lookup2(struct net *net,
449455
badness = 0;
450456
udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) {
451457
score = compute_score(sk, net, saddr, sport,
452-
daddr, hnum, dif, exact_dif);
458+
daddr, hnum, dif, sdif, exact_dif);
453459
if (score > badness) {
454460
reuseport = sk->sk_reuseport;
455461
if (reuseport) {
@@ -477,8 +483,8 @@ static struct sock *udp4_lib_lookup2(struct net *net,
477483
* harder than this. -DaveM
478484
*/
479485
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)
482488
{
483489
struct sock *sk, *result;
484490
unsigned short hnum = ntohs(dport);
@@ -496,7 +502,7 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
496502
goto begin;
497503

498504
result = udp4_lib_lookup2(net, saddr, sport,
499-
daddr, hnum, dif,
505+
daddr, hnum, dif, sdif,
500506
exact_dif, hslot2, skb);
501507
if (!result) {
502508
unsigned int old_slot2 = slot2;
@@ -511,7 +517,7 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
511517
goto begin;
512518

513519
result = udp4_lib_lookup2(net, saddr, sport,
514-
daddr, hnum, dif,
520+
daddr, hnum, dif, sdif,
515521
exact_dif, hslot2, skb);
516522
}
517523
return result;
@@ -521,7 +527,7 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
521527
badness = 0;
522528
sk_for_each_rcu(sk, &hslot->head) {
523529
score = compute_score(sk, net, saddr, sport,
524-
daddr, hnum, dif, exact_dif);
530+
daddr, hnum, dif, sdif, exact_dif);
525531
if (score > badness) {
526532
reuseport = sk->sk_reuseport;
527533
if (reuseport) {
@@ -554,7 +560,7 @@ static inline struct sock *__udp4_lib_lookup_skb(struct sk_buff *skb,
554560

555561
return __udp4_lib_lookup(dev_net(skb->dev), iph->saddr, sport,
556562
iph->daddr, dport, inet_iif(skb),
557-
udptable, skb);
563+
inet_sdif(skb), udptable, skb);
558564
}
559565

560566
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,
576582
struct sock *sk;
577583

578584
sk = __udp4_lib_lookup(net, saddr, sport, daddr, dport,
579-
dif, &udp_table, NULL);
585+
dif, 0, &udp_table, NULL);
580586
if (sk && !refcount_inc_not_zero(&sk->sk_refcnt))
581587
sk = NULL;
582588
return sk;
@@ -587,7 +593,7 @@ EXPORT_SYMBOL_GPL(udp4_lib_lookup);
587593
static inline bool __udp_is_mcast_sock(struct net *net, struct sock *sk,
588594
__be16 loc_port, __be32 loc_addr,
589595
__be16 rmt_port, __be32 rmt_addr,
590-
int dif, unsigned short hnum)
596+
int dif, int sdif, unsigned short hnum)
591597
{
592598
struct inet_sock *inet = inet_sk(sk);
593599

@@ -597,7 +603,8 @@ static inline bool __udp_is_mcast_sock(struct net *net, struct sock *sk,
597603
(inet->inet_dport != rmt_port && inet->inet_dport) ||
598604
(inet->inet_rcv_saddr && inet->inet_rcv_saddr != loc_addr) ||
599605
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))
601608
return false;
602609
if (!ip_mc_sf_allow(sk, loc_addr, rmt_addr, dif))
603610
return false;
@@ -628,8 +635,8 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
628635
struct net *net = dev_net(skb->dev);
629636

630637
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);
633640
if (!sk) {
634641
__ICMP_INC_STATS(net, ICMP_MIB_INERRORS);
635642
return; /* No socket for error */
@@ -1953,6 +1960,7 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
19531960
unsigned int hash2 = 0, hash2_any = 0, use_hash2 = (hslot->count > 10);
19541961
unsigned int offset = offsetof(typeof(*sk), sk_node);
19551962
int dif = skb->dev->ifindex;
1963+
int sdif = inet_sdif(skb);
19561964
struct hlist_node *node;
19571965
struct sk_buff *nskb;
19581966

@@ -1967,7 +1975,7 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
19671975

19681976
sk_for_each_entry_offset_rcu(sk, node, &hslot->head, offset) {
19691977
if (!__udp_is_mcast_sock(net, sk, uh->dest, daddr,
1970-
uh->source, saddr, dif, hnum))
1978+
uh->source, saddr, dif, sdif, hnum))
19711979
continue;
19721980

19731981
if (!first) {
@@ -2157,7 +2165,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
21572165
static struct sock *__udp4_lib_mcast_demux_lookup(struct net *net,
21582166
__be16 loc_port, __be32 loc_addr,
21592167
__be16 rmt_port, __be32 rmt_addr,
2160-
int dif)
2168+
int dif, int sdif)
21612169
{
21622170
struct sock *sk, *result;
21632171
unsigned short hnum = ntohs(loc_port);
@@ -2171,7 +2179,7 @@ static struct sock *__udp4_lib_mcast_demux_lookup(struct net *net,
21712179
result = NULL;
21722180
sk_for_each_rcu(sk, &hslot->head) {
21732181
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)) {
21752183
if (result)
21762184
return NULL;
21772185
result = sk;
@@ -2216,6 +2224,7 @@ void udp_v4_early_demux(struct sk_buff *skb)
22162224
struct sock *sk = NULL;
22172225
struct dst_entry *dst;
22182226
int dif = skb->dev->ifindex;
2227+
int sdif = inet_sdif(skb);
22192228
int ours;
22202229

22212230
/* validate the packet */
@@ -2241,7 +2250,8 @@ void udp_v4_early_demux(struct sk_buff *skb)
22412250
}
22422251

22432252
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);
22452255
} else if (skb->pkt_type == PACKET_HOST) {
22462256
sk = __udp4_lib_demux_lookup(net, uh->dest, iph->daddr,
22472257
uh->source, iph->saddr, dif);

net/ipv4/udp_diag.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb,
4545
sk = __udp4_lib_lookup(net,
4646
req->id.idiag_src[0], req->id.idiag_sport,
4747
req->id.idiag_dst[0], req->id.idiag_dport,
48-
req->id.idiag_if, tbl, NULL);
48+
req->id.idiag_if, 0, tbl, NULL);
4949
#if IS_ENABLED(CONFIG_IPV6)
5050
else if (req->sdiag_family == AF_INET6)
5151
sk = __udp6_lib_lookup(net,
@@ -182,15 +182,15 @@ static int __udp_diag_destroy(struct sk_buff *in_skb,
182182
sk = __udp4_lib_lookup(net,
183183
req->id.idiag_dst[0], req->id.idiag_dport,
184184
req->id.idiag_src[0], req->id.idiag_sport,
185-
req->id.idiag_if, tbl, NULL);
185+
req->id.idiag_if, 0, tbl, NULL);
186186
#if IS_ENABLED(CONFIG_IPV6)
187187
else if (req->sdiag_family == AF_INET6) {
188188
if (ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_dst) &&
189189
ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_src))
190190
sk = __udp4_lib_lookup(net,
191191
req->id.idiag_dst[3], req->id.idiag_dport,
192192
req->id.idiag_src[3], req->id.idiag_sport,
193-
req->id.idiag_if, tbl, NULL);
193+
req->id.idiag_if, 0, tbl, NULL);
194194

195195
else
196196
sk = __udp6_lib_lookup(net,

0 commit comments

Comments
 (0)