diff options
author | David S. Miller <davem@davemloft.net> | 2017-08-07 14:39:22 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-08-07 14:39:22 -0400 |
commit | 9bcb5a572fd6aed8fd1974ea24830f8a657cbfa2 (patch) | |
tree | 0eb95dbb9e503991b36468ccf4b00a010697f664 | |
parent | 46d4b68f891bee5d83a32508bfbd9778be6b1b63 (diff) | |
parent | 5108ab4bf446fa9ad2c71f5fc1d839067b72636f (diff) |
Merge branch 'net-l3mdev-Support-for-sockets-bound-to-enslaved-device'
David Ahern says:
====================
net: l3mdev: Support for sockets bound to enslaved device
A missing piece to the VRF puzzle is the ability to bind sockets to
devices enslaved to a VRF. This patch set adds the enslaved device
index, sdif, to IPv4 and IPv6 socket lookups. The end result for users
is the following scope options for services:
1. "global" services - sockets not bound to any device
Allows 1 service to work across all network interfaces with
connected sockets bound to the VRF the connection originates
(Requires net.ipv4.tcp_l3mdev_accept=1 for TCP and
net.ipv4.udp_l3mdev_accept=1 for UDP)
2. "VRF" local services - sockets bound to a VRF
Sockets work across all network interfaces enslaved to a VRF but
are limited to just the one VRF.
3. "device" services - sockets bound to a specific network interface
Service works only through the one specific interface.
v3
- convert __inet_lookup_established in dccp_v4_err; missed in v2
v2
- remove sk_lookup struct and add sdif as an argument to existing
functions
Changes since RFC:
- no significant logic changes; mainly whitespace cleanups
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/igmp.h | 3 | ||||
-rw-r--r-- | include/linux/ipv6.h | 10 | ||||
-rw-r--r-- | include/net/inet6_hashtables.h | 22 | ||||
-rw-r--r-- | include/net/inet_hashtables.h | 31 | ||||
-rw-r--r-- | include/net/ip.h | 10 | ||||
-rw-r--r-- | include/net/raw.h | 2 | ||||
-rw-r--r-- | include/net/rawv6.h | 2 | ||||
-rw-r--r-- | include/net/tcp.h | 20 | ||||
-rw-r--r-- | include/net/udp.h | 4 | ||||
-rw-r--r-- | net/dccp/ipv4.c | 4 | ||||
-rw-r--r-- | net/dccp/ipv6.c | 4 | ||||
-rw-r--r-- | net/ipv4/igmp.c | 6 | ||||
-rw-r--r-- | net/ipv4/inet_hashtables.c | 27 | ||||
-rw-r--r-- | net/ipv4/raw.c | 18 | ||||
-rw-r--r-- | net/ipv4/raw_diag.c | 4 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 13 | ||||
-rw-r--r-- | net/ipv4/udp.c | 66 | ||||
-rw-r--r-- | net/ipv4/udp_diag.c | 10 | ||||
-rw-r--r-- | net/ipv6/inet6_hashtables.c | 28 | ||||
-rw-r--r-- | net/ipv6/raw.c | 13 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 13 | ||||
-rw-r--r-- | net/ipv6/udp.c | 47 | ||||
-rw-r--r-- | net/netfilter/xt_TPROXY.c | 6 |
23 files changed, 228 insertions, 135 deletions
diff --git a/include/linux/igmp.h b/include/linux/igmp.h index 97caf1821de8..f8231854b5d6 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h | |||
@@ -118,7 +118,8 @@ extern int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, | |||
118 | struct ip_msfilter __user *optval, int __user *optlen); | 118 | struct ip_msfilter __user *optval, int __user *optlen); |
119 | extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, | 119 | extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, |
120 | struct group_filter __user *optval, int __user *optlen); | 120 | struct group_filter __user *optval, int __user *optlen); |
121 | extern int ip_mc_sf_allow(struct sock *sk, __be32 local, __be32 rmt, int dif); | 121 | extern int ip_mc_sf_allow(struct sock *sk, __be32 local, __be32 rmt, |
122 | int dif, int sdif); | ||
122 | extern void ip_mc_init_dev(struct in_device *); | 123 | extern void ip_mc_init_dev(struct in_device *); |
123 | extern void ip_mc_destroy_dev(struct in_device *); | 124 | extern void ip_mc_destroy_dev(struct in_device *); |
124 | extern void ip_mc_up(struct in_device *); | 125 | extern void ip_mc_up(struct in_device *); |
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 474d6bbc158c..ac2da4e11d5e 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h | |||
@@ -159,6 +159,16 @@ static inline bool inet6_is_jumbogram(const struct sk_buff *skb) | |||
159 | } | 159 | } |
160 | 160 | ||
161 | /* can not be used in TCP layer after tcp_v6_fill_cb */ | 161 | /* can not be used in TCP layer after tcp_v6_fill_cb */ |
162 | static inline int inet6_sdif(const struct sk_buff *skb) | ||
163 | { | ||
164 | #if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV) | ||
165 | if (skb && ipv6_l3mdev_skb(IP6CB(skb)->flags)) | ||
166 | return IP6CB(skb)->iif; | ||
167 | #endif | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | /* can not be used in TCP layer after tcp_v6_fill_cb */ | ||
162 | static inline bool inet6_exact_dif_match(struct net *net, struct sk_buff *skb) | 172 | static inline bool inet6_exact_dif_match(struct net *net, struct sk_buff *skb) |
163 | { | 173 | { |
164 | #if defined(CONFIG_NET_L3_MASTER_DEV) | 174 | #if defined(CONFIG_NET_L3_MASTER_DEV) |
diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h index b87becacd9d3..6e91e38a31da 100644 --- a/include/net/inet6_hashtables.h +++ b/include/net/inet6_hashtables.h | |||
@@ -49,7 +49,8 @@ struct sock *__inet6_lookup_established(struct net *net, | |||
49 | const struct in6_addr *saddr, | 49 | const struct in6_addr *saddr, |
50 | const __be16 sport, | 50 | const __be16 sport, |
51 | const struct in6_addr *daddr, | 51 | const struct in6_addr *daddr, |
52 | const u16 hnum, const int dif); | 52 | const u16 hnum, const int dif, |
53 | const int sdif); | ||
53 | 54 | ||
54 | struct sock *inet6_lookup_listener(struct net *net, | 55 | struct sock *inet6_lookup_listener(struct net *net, |
55 | struct inet_hashinfo *hashinfo, | 56 | struct inet_hashinfo *hashinfo, |
@@ -57,7 +58,8 @@ struct sock *inet6_lookup_listener(struct net *net, | |||
57 | const struct in6_addr *saddr, | 58 | const struct in6_addr *saddr, |
58 | const __be16 sport, | 59 | const __be16 sport, |
59 | const struct in6_addr *daddr, | 60 | const struct in6_addr *daddr, |
60 | const unsigned short hnum, const int dif); | 61 | const unsigned short hnum, |
62 | const int dif, const int sdif); | ||
61 | 63 | ||
62 | static inline struct sock *__inet6_lookup(struct net *net, | 64 | static inline struct sock *__inet6_lookup(struct net *net, |
63 | struct inet_hashinfo *hashinfo, | 65 | struct inet_hashinfo *hashinfo, |
@@ -66,24 +68,25 @@ static inline struct sock *__inet6_lookup(struct net *net, | |||
66 | const __be16 sport, | 68 | const __be16 sport, |
67 | const struct in6_addr *daddr, | 69 | const struct in6_addr *daddr, |
68 | const u16 hnum, | 70 | const u16 hnum, |
69 | const int dif, | 71 | const int dif, const int sdif, |
70 | bool *refcounted) | 72 | bool *refcounted) |
71 | { | 73 | { |
72 | struct sock *sk = __inet6_lookup_established(net, hashinfo, saddr, | 74 | struct sock *sk = __inet6_lookup_established(net, hashinfo, saddr, |
73 | sport, daddr, hnum, dif); | 75 | sport, daddr, hnum, |
76 | dif, sdif); | ||
74 | *refcounted = true; | 77 | *refcounted = true; |
75 | if (sk) | 78 | if (sk) |
76 | return sk; | 79 | return sk; |
77 | *refcounted = false; | 80 | *refcounted = false; |
78 | return inet6_lookup_listener(net, hashinfo, skb, doff, saddr, sport, | 81 | return inet6_lookup_listener(net, hashinfo, skb, doff, saddr, sport, |
79 | daddr, hnum, dif); | 82 | daddr, hnum, dif, sdif); |
80 | } | 83 | } |
81 | 84 | ||
82 | static inline struct sock *__inet6_lookup_skb(struct inet_hashinfo *hashinfo, | 85 | static inline struct sock *__inet6_lookup_skb(struct inet_hashinfo *hashinfo, |
83 | struct sk_buff *skb, int doff, | 86 | struct sk_buff *skb, int doff, |
84 | const __be16 sport, | 87 | const __be16 sport, |
85 | const __be16 dport, | 88 | const __be16 dport, |
86 | int iif, | 89 | int iif, int sdif, |
87 | bool *refcounted) | 90 | bool *refcounted) |
88 | { | 91 | { |
89 | struct sock *sk = skb_steal_sock(skb); | 92 | struct sock *sk = skb_steal_sock(skb); |
@@ -95,7 +98,7 @@ static inline struct sock *__inet6_lookup_skb(struct inet_hashinfo *hashinfo, | |||
95 | return __inet6_lookup(dev_net(skb_dst(skb)->dev), hashinfo, skb, | 98 | return __inet6_lookup(dev_net(skb_dst(skb)->dev), hashinfo, skb, |
96 | doff, &ipv6_hdr(skb)->saddr, sport, | 99 | doff, &ipv6_hdr(skb)->saddr, sport, |
97 | &ipv6_hdr(skb)->daddr, ntohs(dport), | 100 | &ipv6_hdr(skb)->daddr, ntohs(dport), |
98 | iif, refcounted); | 101 | iif, sdif, refcounted); |
99 | } | 102 | } |
100 | 103 | ||
101 | struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo, | 104 | struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo, |
@@ -107,13 +110,14 @@ struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo, | |||
107 | int inet6_hash(struct sock *sk); | 110 | int inet6_hash(struct sock *sk); |
108 | #endif /* IS_ENABLED(CONFIG_IPV6) */ | 111 | #endif /* IS_ENABLED(CONFIG_IPV6) */ |
109 | 112 | ||
110 | #define INET6_MATCH(__sk, __net, __saddr, __daddr, __ports, __dif) \ | 113 | #define INET6_MATCH(__sk, __net, __saddr, __daddr, __ports, __dif, __sdif) \ |
111 | (((__sk)->sk_portpair == (__ports)) && \ | 114 | (((__sk)->sk_portpair == (__ports)) && \ |
112 | ((__sk)->sk_family == AF_INET6) && \ | 115 | ((__sk)->sk_family == AF_INET6) && \ |
113 | ipv6_addr_equal(&(__sk)->sk_v6_daddr, (__saddr)) && \ | 116 | ipv6_addr_equal(&(__sk)->sk_v6_daddr, (__saddr)) && \ |
114 | ipv6_addr_equal(&(__sk)->sk_v6_rcv_saddr, (__daddr)) && \ | 117 | ipv6_addr_equal(&(__sk)->sk_v6_rcv_saddr, (__daddr)) && \ |
115 | (!(__sk)->sk_bound_dev_if || \ | 118 | (!(__sk)->sk_bound_dev_if || \ |
116 | ((__sk)->sk_bound_dev_if == (__dif))) && \ | 119 | ((__sk)->sk_bound_dev_if == (__dif)) || \ |
120 | ((__sk)->sk_bound_dev_if == (__sdif))) && \ | ||
117 | net_eq(sock_net(__sk), (__net))) | 121 | net_eq(sock_net(__sk), (__net))) |
118 | 122 | ||
119 | #endif /* _INET6_HASHTABLES_H */ | 123 | #endif /* _INET6_HASHTABLES_H */ |
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index 5026b1f08bb8..2dbbbff5e1e3 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h | |||
@@ -221,16 +221,16 @@ struct sock *__inet_lookup_listener(struct net *net, | |||
221 | const __be32 saddr, const __be16 sport, | 221 | const __be32 saddr, const __be16 sport, |
222 | const __be32 daddr, | 222 | const __be32 daddr, |
223 | const unsigned short hnum, | 223 | const unsigned short hnum, |
224 | const int dif); | 224 | const int dif, const int sdif); |
225 | 225 | ||
226 | static inline struct sock *inet_lookup_listener(struct net *net, | 226 | static inline struct sock *inet_lookup_listener(struct net *net, |
227 | struct inet_hashinfo *hashinfo, | 227 | struct inet_hashinfo *hashinfo, |
228 | struct sk_buff *skb, int doff, | 228 | struct sk_buff *skb, int doff, |
229 | __be32 saddr, __be16 sport, | 229 | __be32 saddr, __be16 sport, |
230 | __be32 daddr, __be16 dport, int dif) | 230 | __be32 daddr, __be16 dport, int dif, int sdif) |
231 | { | 231 | { |
232 | return __inet_lookup_listener(net, hashinfo, skb, doff, saddr, sport, | 232 | return __inet_lookup_listener(net, hashinfo, skb, doff, saddr, sport, |
233 | daddr, ntohs(dport), dif); | 233 | daddr, ntohs(dport), dif, sdif); |
234 | } | 234 | } |
235 | 235 | ||
236 | /* Socket demux engine toys. */ | 236 | /* Socket demux engine toys. */ |
@@ -262,22 +262,24 @@ static inline struct sock *inet_lookup_listener(struct net *net, | |||
262 | (((__force __u64)(__be32)(__daddr)) << 32) | \ | 262 | (((__force __u64)(__be32)(__daddr)) << 32) | \ |
263 | ((__force __u64)(__be32)(__saddr))) | 263 | ((__force __u64)(__be32)(__saddr))) |
264 | #endif /* __BIG_ENDIAN */ | 264 | #endif /* __BIG_ENDIAN */ |
265 | #define INET_MATCH(__sk, __net, __cookie, __saddr, __daddr, __ports, __dif) \ | 265 | #define INET_MATCH(__sk, __net, __cookie, __saddr, __daddr, __ports, __dif, __sdif) \ |
266 | (((__sk)->sk_portpair == (__ports)) && \ | 266 | (((__sk)->sk_portpair == (__ports)) && \ |
267 | ((__sk)->sk_addrpair == (__cookie)) && \ | 267 | ((__sk)->sk_addrpair == (__cookie)) && \ |
268 | (!(__sk)->sk_bound_dev_if || \ | 268 | (!(__sk)->sk_bound_dev_if || \ |
269 | ((__sk)->sk_bound_dev_if == (__dif))) && \ | 269 | ((__sk)->sk_bound_dev_if == (__dif)) || \ |
270 | ((__sk)->sk_bound_dev_if == (__sdif))) && \ | ||
270 | net_eq(sock_net(__sk), (__net))) | 271 | net_eq(sock_net(__sk), (__net))) |
271 | #else /* 32-bit arch */ | 272 | #else /* 32-bit arch */ |
272 | #define INET_ADDR_COOKIE(__name, __saddr, __daddr) \ | 273 | #define INET_ADDR_COOKIE(__name, __saddr, __daddr) \ |
273 | const int __name __deprecated __attribute__((unused)) | 274 | const int __name __deprecated __attribute__((unused)) |
274 | 275 | ||
275 | #define INET_MATCH(__sk, __net, __cookie, __saddr, __daddr, __ports, __dif) \ | 276 | #define INET_MATCH(__sk, __net, __cookie, __saddr, __daddr, __ports, __dif, __sdif) \ |
276 | (((__sk)->sk_portpair == (__ports)) && \ | 277 | (((__sk)->sk_portpair == (__ports)) && \ |
277 | ((__sk)->sk_daddr == (__saddr)) && \ | 278 | ((__sk)->sk_daddr == (__saddr)) && \ |
278 | ((__sk)->sk_rcv_saddr == (__daddr)) && \ | 279 | ((__sk)->sk_rcv_saddr == (__daddr)) && \ |
279 | (!(__sk)->sk_bound_dev_if || \ | 280 | (!(__sk)->sk_bound_dev_if || \ |
280 | ((__sk)->sk_bound_dev_if == (__dif))) && \ | 281 | ((__sk)->sk_bound_dev_if == (__dif)) || \ |
282 | ((__sk)->sk_bound_dev_if == (__sdif))) && \ | ||
281 | net_eq(sock_net(__sk), (__net))) | 283 | net_eq(sock_net(__sk), (__net))) |
282 | #endif /* 64-bit arch */ | 284 | #endif /* 64-bit arch */ |
283 | 285 | ||
@@ -288,7 +290,7 @@ struct sock *__inet_lookup_established(struct net *net, | |||
288 | struct inet_hashinfo *hashinfo, | 290 | struct inet_hashinfo *hashinfo, |
289 | const __be32 saddr, const __be16 sport, | 291 | const __be32 saddr, const __be16 sport, |
290 | const __be32 daddr, const u16 hnum, | 292 | const __be32 daddr, const u16 hnum, |
291 | const int dif); | 293 | const int dif, const int sdif); |
292 | 294 | ||
293 | static inline struct sock * | 295 | static inline struct sock * |
294 | inet_lookup_established(struct net *net, struct inet_hashinfo *hashinfo, | 296 | inet_lookup_established(struct net *net, struct inet_hashinfo *hashinfo, |
@@ -297,7 +299,7 @@ static inline struct sock * | |||
297 | const int dif) | 299 | const int dif) |
298 | { | 300 | { |
299 | return __inet_lookup_established(net, hashinfo, saddr, sport, daddr, | 301 | return __inet_lookup_established(net, hashinfo, saddr, sport, daddr, |
300 | ntohs(dport), dif); | 302 | ntohs(dport), dif, 0); |
301 | } | 303 | } |
302 | 304 | ||
303 | static inline struct sock *__inet_lookup(struct net *net, | 305 | static inline struct sock *__inet_lookup(struct net *net, |
@@ -305,20 +307,20 @@ static inline struct sock *__inet_lookup(struct net *net, | |||
305 | struct sk_buff *skb, int doff, | 307 | struct sk_buff *skb, int doff, |
306 | const __be32 saddr, const __be16 sport, | 308 | const __be32 saddr, const __be16 sport, |
307 | const __be32 daddr, const __be16 dport, | 309 | const __be32 daddr, const __be16 dport, |
308 | const int dif, | 310 | const int dif, const int sdif, |
309 | bool *refcounted) | 311 | bool *refcounted) |
310 | { | 312 | { |
311 | u16 hnum = ntohs(dport); | 313 | u16 hnum = ntohs(dport); |
312 | struct sock *sk; | 314 | struct sock *sk; |
313 | 315 | ||
314 | sk = __inet_lookup_established(net, hashinfo, saddr, sport, | 316 | sk = __inet_lookup_established(net, hashinfo, saddr, sport, |
315 | daddr, hnum, dif); | 317 | daddr, hnum, dif, sdif); |
316 | *refcounted = true; | 318 | *refcounted = true; |
317 | if (sk) | 319 | if (sk) |
318 | return sk; | 320 | return sk; |
319 | *refcounted = false; | 321 | *refcounted = false; |
320 | return __inet_lookup_listener(net, hashinfo, skb, doff, saddr, | 322 | return __inet_lookup_listener(net, hashinfo, skb, doff, saddr, |
321 | sport, daddr, hnum, dif); | 323 | sport, daddr, hnum, dif, sdif); |
322 | } | 324 | } |
323 | 325 | ||
324 | static inline struct sock *inet_lookup(struct net *net, | 326 | static inline struct sock *inet_lookup(struct net *net, |
@@ -332,7 +334,7 @@ static inline struct sock *inet_lookup(struct net *net, | |||
332 | bool refcounted; | 334 | bool refcounted; |
333 | 335 | ||
334 | sk = __inet_lookup(net, hashinfo, skb, doff, saddr, sport, daddr, | 336 | sk = __inet_lookup(net, hashinfo, skb, doff, saddr, sport, daddr, |
335 | dport, dif, &refcounted); | 337 | dport, dif, 0, &refcounted); |
336 | 338 | ||
337 | if (sk && !refcounted && !refcount_inc_not_zero(&sk->sk_refcnt)) | 339 | if (sk && !refcounted && !refcount_inc_not_zero(&sk->sk_refcnt)) |
338 | sk = NULL; | 340 | sk = NULL; |
@@ -344,6 +346,7 @@ static inline struct sock *__inet_lookup_skb(struct inet_hashinfo *hashinfo, | |||
344 | int doff, | 346 | int doff, |
345 | const __be16 sport, | 347 | const __be16 sport, |
346 | const __be16 dport, | 348 | const __be16 dport, |
349 | const int sdif, | ||
347 | bool *refcounted) | 350 | bool *refcounted) |
348 | { | 351 | { |
349 | struct sock *sk = skb_steal_sock(skb); | 352 | struct sock *sk = skb_steal_sock(skb); |
@@ -355,7 +358,7 @@ static inline struct sock *__inet_lookup_skb(struct inet_hashinfo *hashinfo, | |||
355 | 358 | ||
356 | return __inet_lookup(dev_net(skb_dst(skb)->dev), hashinfo, skb, | 359 | return __inet_lookup(dev_net(skb_dst(skb)->dev), hashinfo, skb, |
357 | doff, iph->saddr, sport, | 360 | doff, iph->saddr, sport, |
358 | iph->daddr, dport, inet_iif(skb), | 361 | iph->daddr, dport, inet_iif(skb), sdif, |
359 | refcounted); | 362 | refcounted); |
360 | } | 363 | } |
361 | 364 | ||
diff --git a/include/net/ip.h b/include/net/ip.h index 9e59dcf1787a..39db596eb89f 100644 --- a/include/net/ip.h +++ b/include/net/ip.h | |||
@@ -78,6 +78,16 @@ struct ipcm_cookie { | |||
78 | #define IPCB(skb) ((struct inet_skb_parm*)((skb)->cb)) | 78 | #define IPCB(skb) ((struct inet_skb_parm*)((skb)->cb)) |
79 | #define PKTINFO_SKB_CB(skb) ((struct in_pktinfo *)((skb)->cb)) | 79 | #define PKTINFO_SKB_CB(skb) ((struct in_pktinfo *)((skb)->cb)) |
80 | 80 | ||
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 | |||
81 | struct ip_ra_chain { | 91 | struct ip_ra_chain { |
82 | struct ip_ra_chain __rcu *next; | 92 | struct ip_ra_chain __rcu *next; |
83 | struct sock *sk; | 93 | struct sock *sk; |
diff --git a/include/net/raw.h b/include/net/raw.h index 57c33dd22ec4..99d26d0c4a19 100644 --- a/include/net/raw.h +++ b/include/net/raw.h | |||
@@ -26,7 +26,7 @@ extern struct proto raw_prot; | |||
26 | extern struct raw_hashinfo raw_v4_hashinfo; | 26 | extern struct raw_hashinfo raw_v4_hashinfo; |
27 | struct sock *__raw_v4_lookup(struct net *net, struct sock *sk, | 27 | struct sock *__raw_v4_lookup(struct net *net, struct sock *sk, |
28 | unsigned short num, __be32 raddr, | 28 | unsigned short num, __be32 raddr, |
29 | __be32 laddr, int dif); | 29 | __be32 laddr, int dif, int sdif); |
30 | 30 | ||
31 | int raw_abort(struct sock *sk, int err); | 31 | int raw_abort(struct sock *sk, int err); |
32 | void raw_icmp_error(struct sk_buff *, int, u32); | 32 | void raw_icmp_error(struct sk_buff *, int, u32); |
diff --git a/include/net/rawv6.h b/include/net/rawv6.h index cbe4e9de1894..4addc5c988e0 100644 --- a/include/net/rawv6.h +++ b/include/net/rawv6.h | |||
@@ -6,7 +6,7 @@ | |||
6 | extern struct raw_hashinfo raw_v6_hashinfo; | 6 | extern struct raw_hashinfo raw_v6_hashinfo; |
7 | struct sock *__raw_v6_lookup(struct net *net, struct sock *sk, | 7 | struct sock *__raw_v6_lookup(struct net *net, struct sock *sk, |
8 | unsigned short num, const struct in6_addr *loc_addr, | 8 | unsigned short num, const struct in6_addr *loc_addr, |
9 | const struct in6_addr *rmt_addr, int dif); | 9 | const struct in6_addr *rmt_addr, int dif, int sdif); |
10 | 10 | ||
11 | int raw_abort(struct sock *sk, int err); | 11 | int raw_abort(struct sock *sk, int err); |
12 | 12 | ||
diff --git a/include/net/tcp.h b/include/net/tcp.h index 5173fecde495..999f3efe572b 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
@@ -827,6 +827,16 @@ static inline int tcp_v6_iif(const struct sk_buff *skb) | |||
827 | 827 | ||
828 | return l3_slave ? skb->skb_iif : TCP_SKB_CB(skb)->header.h6.iif; | 828 | return l3_slave ? skb->skb_iif : TCP_SKB_CB(skb)->header.h6.iif; |
829 | } | 829 | } |
830 | |||
831 | /* TCP_SKB_CB reference means this can not be used from early demux */ | ||
832 | static inline int tcp_v6_sdif(const struct sk_buff *skb) | ||
833 | { | ||
834 | #if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV) | ||
835 | if (skb && ipv6_l3mdev_skb(TCP_SKB_CB(skb)->header.h6.flags)) | ||
836 | return TCP_SKB_CB(skb)->header.h6.iif; | ||
837 | #endif | ||
838 | return 0; | ||
839 | } | ||
830 | #endif | 840 | #endif |
831 | 841 | ||
832 | /* TCP_SKB_CB reference means this can not be used from early demux */ | 842 | /* TCP_SKB_CB reference means this can not be used from early demux */ |
@@ -840,6 +850,16 @@ static inline bool inet_exact_dif_match(struct net *net, struct sk_buff *skb) | |||
840 | return false; | 850 | return false; |
841 | } | 851 | } |
842 | 852 | ||
853 | /* TCP_SKB_CB reference means this can not be used from early demux */ | ||
854 | static inline int tcp_v4_sdif(struct sk_buff *skb) | ||
855 | { | ||
856 | #if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV) | ||
857 | if (skb && ipv4_l3mdev_skb(TCP_SKB_CB(skb)->header.h4.flags)) | ||
858 | return TCP_SKB_CB(skb)->header.h4.iif; | ||
859 | #endif | ||
860 | return 0; | ||
861 | } | ||
862 | |||
843 | /* Due to TSO, an SKB can be composed of multiple actual | 863 | /* Due to TSO, an SKB can be composed of multiple actual |
844 | * packets. To keep these tracked properly, we use this. | 864 | * packets. To keep these tracked properly, we use this. |
845 | */ | 865 | */ |
diff --git a/include/net/udp.h b/include/net/udp.h index cc8036987dcb..20dcdca4e85c 100644 --- a/include/net/udp.h +++ b/include/net/udp.h | |||
@@ -287,7 +287,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname, | |||
287 | struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport, | 287 | struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport, |
288 | __be32 daddr, __be16 dport, int dif); | 288 | __be32 daddr, __be16 dport, int dif); |
289 | struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport, | 289 | 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, |
291 | struct udp_table *tbl, struct sk_buff *skb); | 291 | struct udp_table *tbl, struct sk_buff *skb); |
292 | struct sock *udp4_lib_lookup_skb(struct sk_buff *skb, | 292 | struct sock *udp4_lib_lookup_skb(struct sk_buff *skb, |
293 | __be16 sport, __be16 dport); | 293 | __be16 sport, __be16 dport); |
@@ -298,7 +298,7 @@ struct sock *udp6_lib_lookup(struct net *net, | |||
298 | struct sock *__udp6_lib_lookup(struct net *net, | 298 | struct sock *__udp6_lib_lookup(struct net *net, |
299 | const struct in6_addr *saddr, __be16 sport, | 299 | const struct in6_addr *saddr, __be16 sport, |
300 | const struct in6_addr *daddr, __be16 dport, | 300 | const struct in6_addr *daddr, __be16 dport, |
301 | int dif, struct udp_table *tbl, | 301 | int dif, int sdif, struct udp_table *tbl, |
302 | struct sk_buff *skb); | 302 | struct sk_buff *skb); |
303 | struct sock *udp6_lib_lookup_skb(struct sk_buff *skb, | 303 | struct sock *udp6_lib_lookup_skb(struct sk_buff *skb, |
304 | __be16 sport, __be16 dport); | 304 | __be16 sport, __be16 dport); |
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 1b202f16531f..001c08696334 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
@@ -256,7 +256,7 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info) | |||
256 | sk = __inet_lookup_established(net, &dccp_hashinfo, | 256 | sk = __inet_lookup_established(net, &dccp_hashinfo, |
257 | iph->daddr, dh->dccph_dport, | 257 | iph->daddr, dh->dccph_dport, |
258 | iph->saddr, ntohs(dh->dccph_sport), | 258 | iph->saddr, ntohs(dh->dccph_sport), |
259 | inet_iif(skb)); | 259 | inet_iif(skb), 0); |
260 | if (!sk) { | 260 | if (!sk) { |
261 | __ICMP_INC_STATS(net, ICMP_MIB_INERRORS); | 261 | __ICMP_INC_STATS(net, ICMP_MIB_INERRORS); |
262 | return; | 262 | return; |
@@ -804,7 +804,7 @@ static int dccp_v4_rcv(struct sk_buff *skb) | |||
804 | 804 | ||
805 | lookup: | 805 | lookup: |
806 | sk = __inet_lookup_skb(&dccp_hashinfo, skb, __dccp_hdr_len(dh), | 806 | sk = __inet_lookup_skb(&dccp_hashinfo, skb, __dccp_hdr_len(dh), |
807 | dh->dccph_sport, dh->dccph_dport, &refcounted); | 807 | dh->dccph_sport, dh->dccph_dport, 0, &refcounted); |
808 | if (!sk) { | 808 | if (!sk) { |
809 | dccp_pr_debug("failed to look up flow ID in table and " | 809 | dccp_pr_debug("failed to look up flow ID in table and " |
810 | "get corresponding socket\n"); | 810 | "get corresponding socket\n"); |
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 1b58eac8aad3..47a7b59b355e 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c | |||
@@ -89,7 +89,7 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
89 | sk = __inet6_lookup_established(net, &dccp_hashinfo, | 89 | sk = __inet6_lookup_established(net, &dccp_hashinfo, |
90 | &hdr->daddr, dh->dccph_dport, | 90 | &hdr->daddr, dh->dccph_dport, |
91 | &hdr->saddr, ntohs(dh->dccph_sport), | 91 | &hdr->saddr, ntohs(dh->dccph_sport), |
92 | inet6_iif(skb)); | 92 | inet6_iif(skb), 0); |
93 | 93 | ||
94 | if (!sk) { | 94 | if (!sk) { |
95 | __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), | 95 | __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), |
@@ -687,7 +687,7 @@ static int dccp_v6_rcv(struct sk_buff *skb) | |||
687 | lookup: | 687 | lookup: |
688 | sk = __inet6_lookup_skb(&dccp_hashinfo, skb, __dccp_hdr_len(dh), | 688 | sk = __inet6_lookup_skb(&dccp_hashinfo, skb, __dccp_hdr_len(dh), |
689 | dh->dccph_sport, dh->dccph_dport, | 689 | dh->dccph_sport, dh->dccph_dport, |
690 | inet6_iif(skb), &refcounted); | 690 | inet6_iif(skb), 0, &refcounted); |
691 | if (!sk) { | 691 | if (!sk) { |
692 | dccp_pr_debug("failed to look up flow ID in table and " | 692 | dccp_pr_debug("failed to look up flow ID in table and " |
693 | "get corresponding socket\n"); | 693 | "get corresponding socket\n"); |
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 28f14afd0dd3..5bc8570c2ec3 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c | |||
@@ -2549,7 +2549,8 @@ done: | |||
2549 | /* | 2549 | /* |
2550 | * check if a multicast source filter allows delivery for a given <src,dst,intf> | 2550 | * check if a multicast source filter allows delivery for a given <src,dst,intf> |
2551 | */ | 2551 | */ |
2552 | int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif) | 2552 | int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, |
2553 | int dif, int sdif) | ||
2553 | { | 2554 | { |
2554 | struct inet_sock *inet = inet_sk(sk); | 2555 | struct inet_sock *inet = inet_sk(sk); |
2555 | struct ip_mc_socklist *pmc; | 2556 | struct ip_mc_socklist *pmc; |
@@ -2564,7 +2565,8 @@ int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif) | |||
2564 | rcu_read_lock(); | 2565 | rcu_read_lock(); |
2565 | for_each_pmc_rcu(inet, pmc) { | 2566 | for_each_pmc_rcu(inet, pmc) { |
2566 | if (pmc->multi.imr_multiaddr.s_addr == loc_addr && | 2567 | if (pmc->multi.imr_multiaddr.s_addr == loc_addr && |
2567 | pmc->multi.imr_ifindex == dif) | 2568 | (pmc->multi.imr_ifindex == dif || |
2569 | (sdif && pmc->multi.imr_ifindex == sdif))) | ||
2568 | break; | 2570 | break; |
2569 | } | 2571 | } |
2570 | ret = inet->mc_all; | 2572 | ret = inet->mc_all; |
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 2e3389d614d1..597bb4cfe805 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c | |||
@@ -170,7 +170,7 @@ EXPORT_SYMBOL_GPL(__inet_inherit_port); | |||
170 | 170 | ||
171 | static inline int compute_score(struct sock *sk, struct net *net, | 171 | static inline int compute_score(struct sock *sk, struct net *net, |
172 | const unsigned short hnum, const __be32 daddr, | 172 | const unsigned short hnum, const __be32 daddr, |
173 | const int dif, bool exact_dif) | 173 | const int dif, const int sdif, bool exact_dif) |
174 | { | 174 | { |
175 | int score = -1; | 175 | int score = -1; |
176 | struct inet_sock *inet = inet_sk(sk); | 176 | struct inet_sock *inet = inet_sk(sk); |
@@ -185,9 +185,13 @@ static inline int compute_score(struct sock *sk, struct net *net, | |||
185 | score += 4; | 185 | score += 4; |
186 | } | 186 | } |
187 | if (sk->sk_bound_dev_if || exact_dif) { | 187 | if (sk->sk_bound_dev_if || exact_dif) { |
188 | if (sk->sk_bound_dev_if != dif) | 188 | bool dev_match = (sk->sk_bound_dev_if == dif || |
189 | sk->sk_bound_dev_if == sdif); | ||
190 | |||
191 | if (exact_dif && !dev_match) | ||
189 | return -1; | 192 | return -1; |
190 | score += 4; | 193 | if (sk->sk_bound_dev_if && dev_match) |
194 | score += 4; | ||
191 | } | 195 | } |
192 | if (sk->sk_incoming_cpu == raw_smp_processor_id()) | 196 | if (sk->sk_incoming_cpu == raw_smp_processor_id()) |
193 | score++; | 197 | score++; |
@@ -208,7 +212,7 @@ struct sock *__inet_lookup_listener(struct net *net, | |||
208 | struct sk_buff *skb, int doff, | 212 | struct sk_buff *skb, int doff, |
209 | const __be32 saddr, __be16 sport, | 213 | const __be32 saddr, __be16 sport, |
210 | const __be32 daddr, const unsigned short hnum, | 214 | const __be32 daddr, const unsigned short hnum, |
211 | const int dif) | 215 | const int dif, const int sdif) |
212 | { | 216 | { |
213 | unsigned int hash = inet_lhashfn(net, hnum); | 217 | unsigned int hash = inet_lhashfn(net, hnum); |
214 | struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash]; | 218 | struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash]; |
@@ -218,7 +222,8 @@ struct sock *__inet_lookup_listener(struct net *net, | |||
218 | u32 phash = 0; | 222 | u32 phash = 0; |
219 | 223 | ||
220 | sk_for_each_rcu(sk, &ilb->head) { | 224 | sk_for_each_rcu(sk, &ilb->head) { |
221 | score = compute_score(sk, net, hnum, daddr, dif, exact_dif); | 225 | score = compute_score(sk, net, hnum, daddr, |
226 | dif, sdif, exact_dif); | ||
222 | if (score > hiscore) { | 227 | if (score > hiscore) { |
223 | reuseport = sk->sk_reuseport; | 228 | reuseport = sk->sk_reuseport; |
224 | if (reuseport) { | 229 | if (reuseport) { |
@@ -268,7 +273,7 @@ struct sock *__inet_lookup_established(struct net *net, | |||
268 | struct inet_hashinfo *hashinfo, | 273 | struct inet_hashinfo *hashinfo, |
269 | const __be32 saddr, const __be16 sport, | 274 | const __be32 saddr, const __be16 sport, |
270 | const __be32 daddr, const u16 hnum, | 275 | const __be32 daddr, const u16 hnum, |
271 | const int dif) | 276 | const int dif, const int sdif) |
272 | { | 277 | { |
273 | INET_ADDR_COOKIE(acookie, saddr, daddr); | 278 | INET_ADDR_COOKIE(acookie, saddr, daddr); |
274 | const __portpair ports = INET_COMBINED_PORTS(sport, hnum); | 279 | const __portpair ports = INET_COMBINED_PORTS(sport, hnum); |
@@ -286,11 +291,12 @@ begin: | |||
286 | if (sk->sk_hash != hash) | 291 | if (sk->sk_hash != hash) |
287 | continue; | 292 | continue; |
288 | if (likely(INET_MATCH(sk, net, acookie, | 293 | if (likely(INET_MATCH(sk, net, acookie, |
289 | saddr, daddr, ports, dif))) { | 294 | saddr, daddr, ports, dif, sdif))) { |
290 | if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt))) | 295 | if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt))) |
291 | goto out; | 296 | goto out; |
292 | if (unlikely(!INET_MATCH(sk, net, acookie, | 297 | if (unlikely(!INET_MATCH(sk, net, acookie, |
293 | saddr, daddr, ports, dif))) { | 298 | saddr, daddr, ports, |
299 | dif, sdif))) { | ||
294 | sock_gen_put(sk); | 300 | sock_gen_put(sk); |
295 | goto begin; | 301 | goto begin; |
296 | } | 302 | } |
@@ -321,9 +327,10 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row, | |||
321 | __be32 daddr = inet->inet_rcv_saddr; | 327 | __be32 daddr = inet->inet_rcv_saddr; |
322 | __be32 saddr = inet->inet_daddr; | 328 | __be32 saddr = inet->inet_daddr; |
323 | int dif = sk->sk_bound_dev_if; | 329 | int dif = sk->sk_bound_dev_if; |
330 | struct net *net = sock_net(sk); | ||
331 | int sdif = l3mdev_master_ifindex_by_index(net, dif); | ||
324 | INET_ADDR_COOKIE(acookie, saddr, daddr); | 332 | INET_ADDR_COOKIE(acookie, saddr, daddr); |
325 | const __portpair ports = INET_COMBINED_PORTS(inet->inet_dport, lport); | 333 | const __portpair ports = INET_COMBINED_PORTS(inet->inet_dport, lport); |
326 | struct net *net = sock_net(sk); | ||
327 | unsigned int hash = inet_ehashfn(net, daddr, lport, | 334 | unsigned int hash = inet_ehashfn(net, daddr, lport, |
328 | saddr, inet->inet_dport); | 335 | saddr, inet->inet_dport); |
329 | struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); | 336 | struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); |
@@ -339,7 +346,7 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row, | |||
339 | continue; | 346 | continue; |
340 | 347 | ||
341 | if (likely(INET_MATCH(sk2, net, acookie, | 348 | if (likely(INET_MATCH(sk2, net, acookie, |
342 | saddr, daddr, ports, dif))) { | 349 | saddr, daddr, ports, dif, sdif))) { |
343 | if (sk2->sk_state == TCP_TIME_WAIT) { | 350 | if (sk2->sk_state == TCP_TIME_WAIT) { |
344 | tw = inet_twsk(sk2); | 351 | tw = inet_twsk(sk2); |
345 | if (twsk_unique(sk, sk2, twp)) | 352 | if (twsk_unique(sk, sk2, twp)) |
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index b0bb5d0a30bd..33b70bfd1122 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c | |||
@@ -122,7 +122,8 @@ void raw_unhash_sk(struct sock *sk) | |||
122 | EXPORT_SYMBOL_GPL(raw_unhash_sk); | 122 | EXPORT_SYMBOL_GPL(raw_unhash_sk); |
123 | 123 | ||
124 | struct sock *__raw_v4_lookup(struct net *net, struct sock *sk, | 124 | struct sock *__raw_v4_lookup(struct net *net, struct sock *sk, |
125 | unsigned short num, __be32 raddr, __be32 laddr, int dif) | 125 | unsigned short num, __be32 raddr, __be32 laddr, |
126 | int dif, int sdif) | ||
126 | { | 127 | { |
127 | sk_for_each_from(sk) { | 128 | sk_for_each_from(sk) { |
128 | struct inet_sock *inet = inet_sk(sk); | 129 | struct inet_sock *inet = inet_sk(sk); |
@@ -130,7 +131,8 @@ struct sock *__raw_v4_lookup(struct net *net, struct sock *sk, | |||
130 | if (net_eq(sock_net(sk), net) && inet->inet_num == num && | 131 | if (net_eq(sock_net(sk), net) && inet->inet_num == num && |
131 | !(inet->inet_daddr && inet->inet_daddr != raddr) && | 132 | !(inet->inet_daddr && inet->inet_daddr != raddr) && |
132 | !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) && | 133 | !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) && |
133 | !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)) | 134 | !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif && |
135 | sk->sk_bound_dev_if != sdif)) | ||
134 | goto found; /* gotcha */ | 136 | goto found; /* gotcha */ |
135 | } | 137 | } |
136 | sk = NULL; | 138 | sk = NULL; |
@@ -171,6 +173,7 @@ static int icmp_filter(const struct sock *sk, const struct sk_buff *skb) | |||
171 | */ | 173 | */ |
172 | static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash) | 174 | static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash) |
173 | { | 175 | { |
176 | int sdif = inet_sdif(skb); | ||
174 | struct sock *sk; | 177 | struct sock *sk; |
175 | struct hlist_head *head; | 178 | struct hlist_head *head; |
176 | int delivered = 0; | 179 | int delivered = 0; |
@@ -184,13 +187,13 @@ static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash) | |||
184 | net = dev_net(skb->dev); | 187 | net = dev_net(skb->dev); |
185 | sk = __raw_v4_lookup(net, __sk_head(head), iph->protocol, | 188 | sk = __raw_v4_lookup(net, __sk_head(head), iph->protocol, |
186 | iph->saddr, iph->daddr, | 189 | iph->saddr, iph->daddr, |
187 | skb->dev->ifindex); | 190 | skb->dev->ifindex, sdif); |
188 | 191 | ||
189 | while (sk) { | 192 | while (sk) { |
190 | delivered = 1; | 193 | delivered = 1; |
191 | if ((iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) && | 194 | if ((iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) && |
192 | ip_mc_sf_allow(sk, iph->daddr, iph->saddr, | 195 | ip_mc_sf_allow(sk, iph->daddr, iph->saddr, |
193 | skb->dev->ifindex)) { | 196 | skb->dev->ifindex, sdif)) { |
194 | struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); | 197 | struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); |
195 | 198 | ||
196 | /* Not releasing hash table! */ | 199 | /* Not releasing hash table! */ |
@@ -199,7 +202,7 @@ static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash) | |||
199 | } | 202 | } |
200 | sk = __raw_v4_lookup(net, sk_next(sk), iph->protocol, | 203 | sk = __raw_v4_lookup(net, sk_next(sk), iph->protocol, |
201 | iph->saddr, iph->daddr, | 204 | iph->saddr, iph->daddr, |
202 | skb->dev->ifindex); | 205 | skb->dev->ifindex, sdif); |
203 | } | 206 | } |
204 | out: | 207 | out: |
205 | read_unlock(&raw_v4_hashinfo.lock); | 208 | read_unlock(&raw_v4_hashinfo.lock); |
@@ -297,12 +300,15 @@ void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info) | |||
297 | read_lock(&raw_v4_hashinfo.lock); | 300 | read_lock(&raw_v4_hashinfo.lock); |
298 | raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]); | 301 | raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]); |
299 | if (raw_sk) { | 302 | if (raw_sk) { |
303 | int dif = skb->dev->ifindex; | ||
304 | int sdif = inet_sdif(skb); | ||
305 | |||
300 | iph = (const struct iphdr *)skb->data; | 306 | iph = (const struct iphdr *)skb->data; |
301 | net = dev_net(skb->dev); | 307 | net = dev_net(skb->dev); |
302 | 308 | ||
303 | while ((raw_sk = __raw_v4_lookup(net, raw_sk, protocol, | 309 | while ((raw_sk = __raw_v4_lookup(net, raw_sk, protocol, |
304 | iph->daddr, iph->saddr, | 310 | iph->daddr, iph->saddr, |
305 | skb->dev->ifindex)) != NULL) { | 311 | dif, sdif)) != NULL) { |
306 | raw_err(raw_sk, skb, info); | 312 | raw_err(raw_sk, skb, info); |
307 | raw_sk = sk_next(raw_sk); | 313 | raw_sk = sk_next(raw_sk); |
308 | iph = (const struct iphdr *)skb->data; | 314 | iph = (const struct iphdr *)skb->data; |
diff --git a/net/ipv4/raw_diag.c b/net/ipv4/raw_diag.c index e1a51ca68d23..c200065ef9a5 100644 --- a/net/ipv4/raw_diag.c +++ b/net/ipv4/raw_diag.c | |||
@@ -46,13 +46,13 @@ static struct sock *raw_lookup(struct net *net, struct sock *from, | |||
46 | sk = __raw_v4_lookup(net, from, r->sdiag_raw_protocol, | 46 | sk = __raw_v4_lookup(net, from, r->sdiag_raw_protocol, |
47 | r->id.idiag_dst[0], | 47 | r->id.idiag_dst[0], |
48 | r->id.idiag_src[0], | 48 | r->id.idiag_src[0], |
49 | r->id.idiag_if); | 49 | r->id.idiag_if, 0); |
50 | #if IS_ENABLED(CONFIG_IPV6) | 50 | #if IS_ENABLED(CONFIG_IPV6) |
51 | else | 51 | else |
52 | sk = __raw_v6_lookup(net, from, r->sdiag_raw_protocol, | 52 | sk = __raw_v6_lookup(net, from, r->sdiag_raw_protocol, |
53 | (const struct in6_addr *)r->id.idiag_src, | 53 | (const struct in6_addr *)r->id.idiag_src, |
54 | (const struct in6_addr *)r->id.idiag_dst, | 54 | (const struct in6_addr *)r->id.idiag_dst, |
55 | r->id.idiag_if); | 55 | r->id.idiag_if, 0); |
56 | #endif | 56 | #endif |
57 | return sk; | 57 | return sk; |
58 | } | 58 | } |
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 5f708c85110e..c8784ab37852 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -383,7 +383,7 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) | |||
383 | 383 | ||
384 | sk = __inet_lookup_established(net, &tcp_hashinfo, iph->daddr, | 384 | sk = __inet_lookup_established(net, &tcp_hashinfo, iph->daddr, |
385 | th->dest, iph->saddr, ntohs(th->source), | 385 | th->dest, iph->saddr, ntohs(th->source), |
386 | inet_iif(icmp_skb)); | 386 | inet_iif(icmp_skb), 0); |
387 | if (!sk) { | 387 | if (!sk) { |
388 | __ICMP_INC_STATS(net, ICMP_MIB_INERRORS); | 388 | __ICMP_INC_STATS(net, ICMP_MIB_INERRORS); |
389 | return; | 389 | return; |
@@ -659,7 +659,8 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) | |||
659 | sk1 = __inet_lookup_listener(net, &tcp_hashinfo, NULL, 0, | 659 | sk1 = __inet_lookup_listener(net, &tcp_hashinfo, NULL, 0, |
660 | ip_hdr(skb)->saddr, | 660 | ip_hdr(skb)->saddr, |
661 | th->source, ip_hdr(skb)->daddr, | 661 | th->source, ip_hdr(skb)->daddr, |
662 | ntohs(th->source), inet_iif(skb)); | 662 | ntohs(th->source), inet_iif(skb), |
663 | tcp_v4_sdif(skb)); | ||
663 | /* don't send rst if it can't find key */ | 664 | /* don't send rst if it can't find key */ |
664 | if (!sk1) | 665 | if (!sk1) |
665 | goto out; | 666 | goto out; |
@@ -1523,7 +1524,7 @@ void tcp_v4_early_demux(struct sk_buff *skb) | |||
1523 | sk = __inet_lookup_established(dev_net(skb->dev), &tcp_hashinfo, | 1524 | sk = __inet_lookup_established(dev_net(skb->dev), &tcp_hashinfo, |
1524 | iph->saddr, th->source, | 1525 | iph->saddr, th->source, |
1525 | iph->daddr, ntohs(th->dest), | 1526 | iph->daddr, ntohs(th->dest), |
1526 | skb->skb_iif); | 1527 | skb->skb_iif, inet_sdif(skb)); |
1527 | if (sk) { | 1528 | if (sk) { |
1528 | skb->sk = sk; | 1529 | skb->sk = sk; |
1529 | skb->destructor = sock_edemux; | 1530 | skb->destructor = sock_edemux; |
@@ -1588,6 +1589,7 @@ EXPORT_SYMBOL(tcp_filter); | |||
1588 | int tcp_v4_rcv(struct sk_buff *skb) | 1589 | int tcp_v4_rcv(struct sk_buff *skb) |
1589 | { | 1590 | { |
1590 | struct net *net = dev_net(skb->dev); | 1591 | struct net *net = dev_net(skb->dev); |
1592 | int sdif = inet_sdif(skb); | ||
1591 | const struct iphdr *iph; | 1593 | const struct iphdr *iph; |
1592 | const struct tcphdr *th; | 1594 | const struct tcphdr *th; |
1593 | bool refcounted; | 1595 | bool refcounted; |
@@ -1638,7 +1640,7 @@ int tcp_v4_rcv(struct sk_buff *skb) | |||
1638 | 1640 | ||
1639 | lookup: | 1641 | lookup: |
1640 | sk = __inet_lookup_skb(&tcp_hashinfo, skb, __tcp_hdrlen(th), th->source, | 1642 | sk = __inet_lookup_skb(&tcp_hashinfo, skb, __tcp_hdrlen(th), th->source, |
1641 | th->dest, &refcounted); | 1643 | th->dest, sdif, &refcounted); |
1642 | if (!sk) | 1644 | if (!sk) |
1643 | goto no_tcp_socket; | 1645 | goto no_tcp_socket; |
1644 | 1646 | ||
@@ -1766,7 +1768,8 @@ do_time_wait: | |||
1766 | __tcp_hdrlen(th), | 1768 | __tcp_hdrlen(th), |
1767 | iph->saddr, th->source, | 1769 | iph->saddr, th->source, |
1768 | iph->daddr, th->dest, | 1770 | iph->daddr, th->dest, |
1769 | inet_iif(skb)); | 1771 | inet_iif(skb), |
1772 | sdif); | ||
1770 | if (sk2) { | 1773 | if (sk2) { |
1771 | inet_twsk_deschedule_put(inet_twsk(sk)); | 1774 | inet_twsk_deschedule_put(inet_twsk(sk)); |
1772 | sk = sk2; | 1775 | sk = sk2; |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 38bca2c4897d..cac59d7420cd 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -380,8 +380,8 @@ int udp_v4_get_port(struct sock *sk, unsigned short snum) | |||
380 | 380 | ||
381 | static int compute_score(struct sock *sk, struct net *net, | 381 | static int compute_score(struct sock *sk, struct net *net, |
382 | __be32 saddr, __be16 sport, | 382 | __be32 saddr, __be16 sport, |
383 | __be32 daddr, unsigned short hnum, int dif, | 383 | __be32 daddr, unsigned short hnum, |
384 | bool exact_dif) | 384 | int dif, int sdif, bool exact_dif) |
385 | { | 385 | { |
386 | int score; | 386 | int score; |
387 | struct inet_sock *inet; | 387 | struct inet_sock *inet; |
@@ -413,10 +413,15 @@ static int compute_score(struct sock *sk, struct net *net, | |||
413 | } | 413 | } |
414 | 414 | ||
415 | if (sk->sk_bound_dev_if || exact_dif) { | 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 | return -1; | 420 | return -1; |
418 | score += 4; | 421 | if (sk->sk_bound_dev_if && dev_match) |
422 | score += 4; | ||
419 | } | 423 | } |
424 | |||
420 | if (sk->sk_incoming_cpu == raw_smp_processor_id()) | 425 | if (sk->sk_incoming_cpu == raw_smp_processor_id()) |
421 | score++; | 426 | score++; |
422 | return score; | 427 | return score; |
@@ -436,10 +441,11 @@ static u32 udp_ehashfn(const struct net *net, const __be32 laddr, | |||
436 | 441 | ||
437 | /* called with rcu_read_lock() */ | 442 | /* called with rcu_read_lock() */ |
438 | static struct sock *udp4_lib_lookup2(struct net *net, | 443 | static struct sock *udp4_lib_lookup2(struct net *net, |
439 | __be32 saddr, __be16 sport, | 444 | __be32 saddr, __be16 sport, |
440 | __be32 daddr, unsigned int hnum, int dif, bool exact_dif, | 445 | __be32 daddr, unsigned int hnum, |
441 | struct udp_hslot *hslot2, | 446 | int dif, int sdif, bool exact_dif, |
442 | struct sk_buff *skb) | 447 | struct udp_hslot *hslot2, |
448 | struct sk_buff *skb) | ||
443 | { | 449 | { |
444 | struct sock *sk, *result; | 450 | struct sock *sk, *result; |
445 | int score, badness, matches = 0, reuseport = 0; | 451 | int score, badness, matches = 0, reuseport = 0; |
@@ -449,7 +455,7 @@ static struct sock *udp4_lib_lookup2(struct net *net, | |||
449 | badness = 0; | 455 | badness = 0; |
450 | udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) { | 456 | udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) { |
451 | score = compute_score(sk, net, saddr, sport, | 457 | score = compute_score(sk, net, saddr, sport, |
452 | daddr, hnum, dif, exact_dif); | 458 | daddr, hnum, dif, sdif, exact_dif); |
453 | if (score > badness) { | 459 | if (score > badness) { |
454 | reuseport = sk->sk_reuseport; | 460 | reuseport = sk->sk_reuseport; |
455 | if (reuseport) { | 461 | if (reuseport) { |
@@ -477,8 +483,8 @@ static struct sock *udp4_lib_lookup2(struct net *net, | |||
477 | * harder than this. -DaveM | 483 | * harder than this. -DaveM |
478 | */ | 484 | */ |
479 | struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, | 485 | struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, |
480 | __be16 sport, __be32 daddr, __be16 dport, | 486 | __be16 sport, __be32 daddr, __be16 dport, int dif, |
481 | int dif, struct udp_table *udptable, struct sk_buff *skb) | 487 | int sdif, struct udp_table *udptable, struct sk_buff *skb) |
482 | { | 488 | { |
483 | struct sock *sk, *result; | 489 | struct sock *sk, *result; |
484 | unsigned short hnum = ntohs(dport); | 490 | unsigned short hnum = ntohs(dport); |
@@ -496,7 +502,7 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, | |||
496 | goto begin; | 502 | goto begin; |
497 | 503 | ||
498 | result = udp4_lib_lookup2(net, saddr, sport, | 504 | result = udp4_lib_lookup2(net, saddr, sport, |
499 | daddr, hnum, dif, | 505 | daddr, hnum, dif, sdif, |
500 | exact_dif, hslot2, skb); | 506 | exact_dif, hslot2, skb); |
501 | if (!result) { | 507 | if (!result) { |
502 | unsigned int old_slot2 = slot2; | 508 | unsigned int old_slot2 = slot2; |
@@ -511,7 +517,7 @@ struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, | |||
511 | goto begin; | 517 | goto begin; |
512 | 518 | ||
513 | result = udp4_lib_lookup2(net, saddr, sport, | 519 | result = udp4_lib_lookup2(net, saddr, sport, |
514 | daddr, hnum, dif, | 520 | daddr, hnum, dif, sdif, |
515 | exact_dif, hslot2, skb); | 521 | exact_dif, hslot2, skb); |
516 | } | 522 | } |
517 | return result; | 523 | return result; |
@@ -521,7 +527,7 @@ begin: | |||
521 | badness = 0; | 527 | badness = 0; |
522 | sk_for_each_rcu(sk, &hslot->head) { | 528 | sk_for_each_rcu(sk, &hslot->head) { |
523 | score = compute_score(sk, net, saddr, sport, | 529 | score = compute_score(sk, net, saddr, sport, |
524 | daddr, hnum, dif, exact_dif); | 530 | daddr, hnum, dif, sdif, exact_dif); |
525 | if (score > badness) { | 531 | if (score > badness) { |
526 | reuseport = sk->sk_reuseport; | 532 | reuseport = sk->sk_reuseport; |
527 | if (reuseport) { | 533 | if (reuseport) { |
@@ -554,7 +560,7 @@ static inline struct sock *__udp4_lib_lookup_skb(struct sk_buff *skb, | |||
554 | 560 | ||
555 | return __udp4_lib_lookup(dev_net(skb->dev), iph->saddr, sport, | 561 | return __udp4_lib_lookup(dev_net(skb->dev), iph->saddr, sport, |
556 | iph->daddr, dport, inet_iif(skb), | 562 | iph->daddr, dport, inet_iif(skb), |
557 | udptable, skb); | 563 | inet_sdif(skb), udptable, skb); |
558 | } | 564 | } |
559 | 565 | ||
560 | struct sock *udp4_lib_lookup_skb(struct sk_buff *skb, | 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 | struct sock *sk; | 582 | struct sock *sk; |
577 | 583 | ||
578 | sk = __udp4_lib_lookup(net, saddr, sport, daddr, dport, | 584 | sk = __udp4_lib_lookup(net, saddr, sport, daddr, dport, |
579 | dif, &udp_table, NULL); | 585 | dif, 0, &udp_table, NULL); |
580 | if (sk && !refcount_inc_not_zero(&sk->sk_refcnt)) | 586 | if (sk && !refcount_inc_not_zero(&sk->sk_refcnt)) |
581 | sk = NULL; | 587 | sk = NULL; |
582 | return sk; | 588 | return sk; |
@@ -587,7 +593,7 @@ EXPORT_SYMBOL_GPL(udp4_lib_lookup); | |||
587 | static inline bool __udp_is_mcast_sock(struct net *net, struct sock *sk, | 593 | static inline bool __udp_is_mcast_sock(struct net *net, struct sock *sk, |
588 | __be16 loc_port, __be32 loc_addr, | 594 | __be16 loc_port, __be32 loc_addr, |
589 | __be16 rmt_port, __be32 rmt_addr, | 595 | __be16 rmt_port, __be32 rmt_addr, |
590 | int dif, unsigned short hnum) | 596 | int dif, int sdif, unsigned short hnum) |
591 | { | 597 | { |
592 | struct inet_sock *inet = inet_sk(sk); | 598 | struct inet_sock *inet = inet_sk(sk); |
593 | 599 | ||
@@ -597,9 +603,10 @@ static inline bool __udp_is_mcast_sock(struct net *net, struct sock *sk, | |||
597 | (inet->inet_dport != rmt_port && inet->inet_dport) || | 603 | (inet->inet_dport != rmt_port && inet->inet_dport) || |
598 | (inet->inet_rcv_saddr && inet->inet_rcv_saddr != loc_addr) || | 604 | (inet->inet_rcv_saddr && inet->inet_rcv_saddr != loc_addr) || |
599 | ipv6_only_sock(sk) || | 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 | return false; | 608 | return false; |
602 | if (!ip_mc_sf_allow(sk, loc_addr, rmt_addr, dif)) | 609 | if (!ip_mc_sf_allow(sk, loc_addr, rmt_addr, dif, sdif)) |
603 | return false; | 610 | return false; |
604 | return true; | 611 | return true; |
605 | } | 612 | } |
@@ -628,8 +635,8 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable) | |||
628 | struct net *net = dev_net(skb->dev); | 635 | struct net *net = dev_net(skb->dev); |
629 | 636 | ||
630 | sk = __udp4_lib_lookup(net, iph->daddr, uh->dest, | 637 | sk = __udp4_lib_lookup(net, iph->daddr, uh->dest, |
631 | iph->saddr, uh->source, skb->dev->ifindex, udptable, | 638 | iph->saddr, uh->source, skb->dev->ifindex, 0, |
632 | NULL); | 639 | udptable, NULL); |
633 | if (!sk) { | 640 | if (!sk) { |
634 | __ICMP_INC_STATS(net, ICMP_MIB_INERRORS); | 641 | __ICMP_INC_STATS(net, ICMP_MIB_INERRORS); |
635 | return; /* No socket for error */ | 642 | return; /* No socket for error */ |
@@ -1953,6 +1960,7 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb, | |||
1953 | unsigned int hash2 = 0, hash2_any = 0, use_hash2 = (hslot->count > 10); | 1960 | unsigned int hash2 = 0, hash2_any = 0, use_hash2 = (hslot->count > 10); |
1954 | unsigned int offset = offsetof(typeof(*sk), sk_node); | 1961 | unsigned int offset = offsetof(typeof(*sk), sk_node); |
1955 | int dif = skb->dev->ifindex; | 1962 | int dif = skb->dev->ifindex; |
1963 | int sdif = inet_sdif(skb); | ||
1956 | struct hlist_node *node; | 1964 | struct hlist_node *node; |
1957 | struct sk_buff *nskb; | 1965 | struct sk_buff *nskb; |
1958 | 1966 | ||
@@ -1967,7 +1975,7 @@ start_lookup: | |||
1967 | 1975 | ||
1968 | sk_for_each_entry_offset_rcu(sk, node, &hslot->head, offset) { | 1976 | sk_for_each_entry_offset_rcu(sk, node, &hslot->head, offset) { |
1969 | if (!__udp_is_mcast_sock(net, sk, uh->dest, daddr, | 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 | continue; | 1979 | continue; |
1972 | 1980 | ||
1973 | if (!first) { | 1981 | if (!first) { |
@@ -2157,7 +2165,7 @@ drop: | |||
2157 | static struct sock *__udp4_lib_mcast_demux_lookup(struct net *net, | 2165 | static struct sock *__udp4_lib_mcast_demux_lookup(struct net *net, |
2158 | __be16 loc_port, __be32 loc_addr, | 2166 | __be16 loc_port, __be32 loc_addr, |
2159 | __be16 rmt_port, __be32 rmt_addr, | 2167 | __be16 rmt_port, __be32 rmt_addr, |
2160 | int dif) | 2168 | int dif, int sdif) |
2161 | { | 2169 | { |
2162 | struct sock *sk, *result; | 2170 | struct sock *sk, *result; |
2163 | unsigned short hnum = ntohs(loc_port); | 2171 | unsigned short hnum = ntohs(loc_port); |
@@ -2171,7 +2179,7 @@ static struct sock *__udp4_lib_mcast_demux_lookup(struct net *net, | |||
2171 | result = NULL; | 2179 | result = NULL; |
2172 | sk_for_each_rcu(sk, &hslot->head) { | 2180 | sk_for_each_rcu(sk, &hslot->head) { |
2173 | if (__udp_is_mcast_sock(net, sk, loc_port, loc_addr, | 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 | if (result) | 2183 | if (result) |
2176 | return NULL; | 2184 | return NULL; |
2177 | result = sk; | 2185 | result = sk; |
@@ -2188,7 +2196,7 @@ static struct sock *__udp4_lib_mcast_demux_lookup(struct net *net, | |||
2188 | static struct sock *__udp4_lib_demux_lookup(struct net *net, | 2196 | static struct sock *__udp4_lib_demux_lookup(struct net *net, |
2189 | __be16 loc_port, __be32 loc_addr, | 2197 | __be16 loc_port, __be32 loc_addr, |
2190 | __be16 rmt_port, __be32 rmt_addr, | 2198 | __be16 rmt_port, __be32 rmt_addr, |
2191 | int dif) | 2199 | int dif, int sdif) |
2192 | { | 2200 | { |
2193 | unsigned short hnum = ntohs(loc_port); | 2201 | unsigned short hnum = ntohs(loc_port); |
2194 | unsigned int hash2 = udp4_portaddr_hash(net, loc_addr, hnum); | 2202 | unsigned int hash2 = udp4_portaddr_hash(net, loc_addr, hnum); |
@@ -2200,7 +2208,7 @@ static struct sock *__udp4_lib_demux_lookup(struct net *net, | |||
2200 | 2208 | ||
2201 | udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) { | 2209 | udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) { |
2202 | if (INET_MATCH(sk, net, acookie, rmt_addr, | 2210 | if (INET_MATCH(sk, net, acookie, rmt_addr, |
2203 | loc_addr, ports, dif)) | 2211 | loc_addr, ports, dif, sdif)) |
2204 | return sk; | 2212 | return sk; |
2205 | /* Only check first socket in chain */ | 2213 | /* Only check first socket in chain */ |
2206 | break; | 2214 | break; |
@@ -2216,6 +2224,7 @@ void udp_v4_early_demux(struct sk_buff *skb) | |||
2216 | struct sock *sk = NULL; | 2224 | struct sock *sk = NULL; |
2217 | struct dst_entry *dst; | 2225 | struct dst_entry *dst; |
2218 | int dif = skb->dev->ifindex; | 2226 | int dif = skb->dev->ifindex; |
2227 | int sdif = inet_sdif(skb); | ||
2219 | int ours; | 2228 | int ours; |
2220 | 2229 | ||
2221 | /* validate the packet */ | 2230 | /* validate the packet */ |
@@ -2241,10 +2250,11 @@ void udp_v4_early_demux(struct sk_buff *skb) | |||
2241 | } | 2250 | } |
2242 | 2251 | ||
2243 | sk = __udp4_lib_mcast_demux_lookup(net, uh->dest, iph->daddr, | 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 | } else if (skb->pkt_type == PACKET_HOST) { | 2255 | } else if (skb->pkt_type == PACKET_HOST) { |
2246 | sk = __udp4_lib_demux_lookup(net, uh->dest, iph->daddr, | 2256 | sk = __udp4_lib_demux_lookup(net, uh->dest, iph->daddr, |
2247 | uh->source, iph->saddr, dif); | 2257 | uh->source, iph->saddr, dif, sdif); |
2248 | } | 2258 | } |
2249 | 2259 | ||
2250 | if (!sk || !refcount_inc_not_zero(&sk->sk_refcnt)) | 2260 | if (!sk || !refcount_inc_not_zero(&sk->sk_refcnt)) |
diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c index 4515836d2a3a..d0390d844ac8 100644 --- a/net/ipv4/udp_diag.c +++ b/net/ipv4/udp_diag.c | |||
@@ -45,7 +45,7 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb, | |||
45 | sk = __udp4_lib_lookup(net, | 45 | sk = __udp4_lib_lookup(net, |
46 | req->id.idiag_src[0], req->id.idiag_sport, | 46 | req->id.idiag_src[0], req->id.idiag_sport, |
47 | req->id.idiag_dst[0], req->id.idiag_dport, | 47 | req->id.idiag_dst[0], req->id.idiag_dport, |
48 | req->id.idiag_if, tbl, NULL); | 48 | req->id.idiag_if, 0, tbl, NULL); |
49 | #if IS_ENABLED(CONFIG_IPV6) | 49 | #if IS_ENABLED(CONFIG_IPV6) |
50 | else if (req->sdiag_family == AF_INET6) | 50 | else if (req->sdiag_family == AF_INET6) |
51 | sk = __udp6_lib_lookup(net, | 51 | sk = __udp6_lib_lookup(net, |
@@ -53,7 +53,7 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb, | |||
53 | req->id.idiag_sport, | 53 | req->id.idiag_sport, |
54 | (struct in6_addr *)req->id.idiag_dst, | 54 | (struct in6_addr *)req->id.idiag_dst, |
55 | req->id.idiag_dport, | 55 | req->id.idiag_dport, |
56 | req->id.idiag_if, tbl, NULL); | 56 | req->id.idiag_if, 0, tbl, NULL); |
57 | #endif | 57 | #endif |
58 | if (sk && !refcount_inc_not_zero(&sk->sk_refcnt)) | 58 | if (sk && !refcount_inc_not_zero(&sk->sk_refcnt)) |
59 | sk = NULL; | 59 | sk = NULL; |
@@ -182,7 +182,7 @@ static int __udp_diag_destroy(struct sk_buff *in_skb, | |||
182 | sk = __udp4_lib_lookup(net, | 182 | sk = __udp4_lib_lookup(net, |
183 | req->id.idiag_dst[0], req->id.idiag_dport, | 183 | req->id.idiag_dst[0], req->id.idiag_dport, |
184 | req->id.idiag_src[0], req->id.idiag_sport, | 184 | req->id.idiag_src[0], req->id.idiag_sport, |
185 | req->id.idiag_if, tbl, NULL); | 185 | req->id.idiag_if, 0, tbl, NULL); |
186 | #if IS_ENABLED(CONFIG_IPV6) | 186 | #if IS_ENABLED(CONFIG_IPV6) |
187 | else if (req->sdiag_family == AF_INET6) { | 187 | else if (req->sdiag_family == AF_INET6) { |
188 | if (ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_dst) && | 188 | if (ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_dst) && |
@@ -190,7 +190,7 @@ static int __udp_diag_destroy(struct sk_buff *in_skb, | |||
190 | sk = __udp4_lib_lookup(net, | 190 | sk = __udp4_lib_lookup(net, |
191 | req->id.idiag_dst[3], req->id.idiag_dport, | 191 | req->id.idiag_dst[3], req->id.idiag_dport, |
192 | req->id.idiag_src[3], req->id.idiag_sport, | 192 | req->id.idiag_src[3], req->id.idiag_sport, |
193 | req->id.idiag_if, tbl, NULL); | 193 | req->id.idiag_if, 0, tbl, NULL); |
194 | 194 | ||
195 | else | 195 | else |
196 | sk = __udp6_lib_lookup(net, | 196 | sk = __udp6_lib_lookup(net, |
@@ -198,7 +198,7 @@ static int __udp_diag_destroy(struct sk_buff *in_skb, | |||
198 | req->id.idiag_dport, | 198 | req->id.idiag_dport, |
199 | (struct in6_addr *)req->id.idiag_src, | 199 | (struct in6_addr *)req->id.idiag_src, |
200 | req->id.idiag_sport, | 200 | req->id.idiag_sport, |
201 | req->id.idiag_if, tbl, NULL); | 201 | req->id.idiag_if, 0, tbl, NULL); |
202 | } | 202 | } |
203 | #endif | 203 | #endif |
204 | else { | 204 | else { |
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index b13b8f93079d..b01858f5deb1 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c | |||
@@ -56,7 +56,7 @@ struct sock *__inet6_lookup_established(struct net *net, | |||
56 | const __be16 sport, | 56 | const __be16 sport, |
57 | const struct in6_addr *daddr, | 57 | const struct in6_addr *daddr, |
58 | const u16 hnum, | 58 | const u16 hnum, |
59 | const int dif) | 59 | const int dif, const int sdif) |
60 | { | 60 | { |
61 | struct sock *sk; | 61 | struct sock *sk; |
62 | const struct hlist_nulls_node *node; | 62 | const struct hlist_nulls_node *node; |
@@ -73,12 +73,12 @@ begin: | |||
73 | sk_nulls_for_each_rcu(sk, node, &head->chain) { | 73 | sk_nulls_for_each_rcu(sk, node, &head->chain) { |
74 | if (sk->sk_hash != hash) | 74 | if (sk->sk_hash != hash) |
75 | continue; | 75 | continue; |
76 | if (!INET6_MATCH(sk, net, saddr, daddr, ports, dif)) | 76 | if (!INET6_MATCH(sk, net, saddr, daddr, ports, dif, sdif)) |
77 | continue; | 77 | continue; |
78 | if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt))) | 78 | if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt))) |
79 | goto out; | 79 | goto out; |
80 | 80 | ||
81 | if (unlikely(!INET6_MATCH(sk, net, saddr, daddr, ports, dif))) { | 81 | if (unlikely(!INET6_MATCH(sk, net, saddr, daddr, ports, dif, sdif))) { |
82 | sock_gen_put(sk); | 82 | sock_gen_put(sk); |
83 | goto begin; | 83 | goto begin; |
84 | } | 84 | } |
@@ -96,7 +96,7 @@ EXPORT_SYMBOL(__inet6_lookup_established); | |||
96 | static inline int compute_score(struct sock *sk, struct net *net, | 96 | static inline int compute_score(struct sock *sk, struct net *net, |
97 | const unsigned short hnum, | 97 | const unsigned short hnum, |
98 | const struct in6_addr *daddr, | 98 | const struct in6_addr *daddr, |
99 | const int dif, bool exact_dif) | 99 | const int dif, const int sdif, bool exact_dif) |
100 | { | 100 | { |
101 | int score = -1; | 101 | int score = -1; |
102 | 102 | ||
@@ -110,9 +110,13 @@ static inline int compute_score(struct sock *sk, struct net *net, | |||
110 | score++; | 110 | score++; |
111 | } | 111 | } |
112 | if (sk->sk_bound_dev_if || exact_dif) { | 112 | if (sk->sk_bound_dev_if || exact_dif) { |
113 | if (sk->sk_bound_dev_if != dif) | 113 | bool dev_match = (sk->sk_bound_dev_if == dif || |
114 | sk->sk_bound_dev_if == sdif); | ||
115 | |||
116 | if (exact_dif && !dev_match) | ||
114 | return -1; | 117 | return -1; |
115 | score++; | 118 | if (sk->sk_bound_dev_if && dev_match) |
119 | score++; | ||
116 | } | 120 | } |
117 | if (sk->sk_incoming_cpu == raw_smp_processor_id()) | 121 | if (sk->sk_incoming_cpu == raw_smp_processor_id()) |
118 | score++; | 122 | score++; |
@@ -126,7 +130,7 @@ struct sock *inet6_lookup_listener(struct net *net, | |||
126 | struct sk_buff *skb, int doff, | 130 | struct sk_buff *skb, int doff, |
127 | const struct in6_addr *saddr, | 131 | const struct in6_addr *saddr, |
128 | const __be16 sport, const struct in6_addr *daddr, | 132 | const __be16 sport, const struct in6_addr *daddr, |
129 | const unsigned short hnum, const int dif) | 133 | const unsigned short hnum, const int dif, const int sdif) |
130 | { | 134 | { |
131 | unsigned int hash = inet_lhashfn(net, hnum); | 135 | unsigned int hash = inet_lhashfn(net, hnum); |
132 | struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash]; | 136 | struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash]; |
@@ -136,7 +140,7 @@ struct sock *inet6_lookup_listener(struct net *net, | |||
136 | u32 phash = 0; | 140 | u32 phash = 0; |
137 | 141 | ||
138 | sk_for_each(sk, &ilb->head) { | 142 | sk_for_each(sk, &ilb->head) { |
139 | score = compute_score(sk, net, hnum, daddr, dif, exact_dif); | 143 | score = compute_score(sk, net, hnum, daddr, dif, sdif, exact_dif); |
140 | if (score > hiscore) { | 144 | if (score > hiscore) { |
141 | reuseport = sk->sk_reuseport; | 145 | reuseport = sk->sk_reuseport; |
142 | if (reuseport) { | 146 | if (reuseport) { |
@@ -171,7 +175,7 @@ struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo, | |||
171 | bool refcounted; | 175 | bool refcounted; |
172 | 176 | ||
173 | sk = __inet6_lookup(net, hashinfo, skb, doff, saddr, sport, daddr, | 177 | sk = __inet6_lookup(net, hashinfo, skb, doff, saddr, sport, daddr, |
174 | ntohs(dport), dif, &refcounted); | 178 | ntohs(dport), dif, 0, &refcounted); |
175 | if (sk && !refcounted && !refcount_inc_not_zero(&sk->sk_refcnt)) | 179 | if (sk && !refcounted && !refcount_inc_not_zero(&sk->sk_refcnt)) |
176 | sk = NULL; | 180 | sk = NULL; |
177 | return sk; | 181 | return sk; |
@@ -187,8 +191,9 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, | |||
187 | const struct in6_addr *daddr = &sk->sk_v6_rcv_saddr; | 191 | const struct in6_addr *daddr = &sk->sk_v6_rcv_saddr; |
188 | const struct in6_addr *saddr = &sk->sk_v6_daddr; | 192 | const struct in6_addr *saddr = &sk->sk_v6_daddr; |
189 | const int dif = sk->sk_bound_dev_if; | 193 | const int dif = sk->sk_bound_dev_if; |
190 | const __portpair ports = INET_COMBINED_PORTS(inet->inet_dport, lport); | ||
191 | struct net *net = sock_net(sk); | 194 | struct net *net = sock_net(sk); |
195 | const int sdif = l3mdev_master_ifindex_by_index(net, dif); | ||
196 | const __portpair ports = INET_COMBINED_PORTS(inet->inet_dport, lport); | ||
192 | const unsigned int hash = inet6_ehashfn(net, daddr, lport, saddr, | 197 | const unsigned int hash = inet6_ehashfn(net, daddr, lport, saddr, |
193 | inet->inet_dport); | 198 | inet->inet_dport); |
194 | struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); | 199 | struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); |
@@ -203,7 +208,8 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, | |||
203 | if (sk2->sk_hash != hash) | 208 | if (sk2->sk_hash != hash) |
204 | continue; | 209 | continue; |
205 | 210 | ||
206 | if (likely(INET6_MATCH(sk2, net, saddr, daddr, ports, dif))) { | 211 | if (likely(INET6_MATCH(sk2, net, saddr, daddr, ports, |
212 | dif, sdif))) { | ||
207 | if (sk2->sk_state == TCP_TIME_WAIT) { | 213 | if (sk2->sk_state == TCP_TIME_WAIT) { |
208 | tw = inet_twsk(sk2); | 214 | tw = inet_twsk(sk2); |
209 | if (twsk_unique(sk, sk2, twp)) | 215 | if (twsk_unique(sk, sk2, twp)) |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 60be012fe708..e4462b0ff801 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -72,7 +72,7 @@ EXPORT_SYMBOL_GPL(raw_v6_hashinfo); | |||
72 | 72 | ||
73 | struct sock *__raw_v6_lookup(struct net *net, struct sock *sk, | 73 | struct sock *__raw_v6_lookup(struct net *net, struct sock *sk, |
74 | unsigned short num, const struct in6_addr *loc_addr, | 74 | unsigned short num, const struct in6_addr *loc_addr, |
75 | const struct in6_addr *rmt_addr, int dif) | 75 | const struct in6_addr *rmt_addr, int dif, int sdif) |
76 | { | 76 | { |
77 | bool is_multicast = ipv6_addr_is_multicast(loc_addr); | 77 | bool is_multicast = ipv6_addr_is_multicast(loc_addr); |
78 | 78 | ||
@@ -86,7 +86,9 @@ struct sock *__raw_v6_lookup(struct net *net, struct sock *sk, | |||
86 | !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) | 86 | !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) |
87 | continue; | 87 | continue; |
88 | 88 | ||
89 | if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif) | 89 | if (sk->sk_bound_dev_if && |
90 | sk->sk_bound_dev_if != dif && | ||
91 | sk->sk_bound_dev_if != sdif) | ||
90 | continue; | 92 | continue; |
91 | 93 | ||
92 | if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) { | 94 | if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) { |
@@ -178,7 +180,8 @@ static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) | |||
178 | goto out; | 180 | goto out; |
179 | 181 | ||
180 | net = dev_net(skb->dev); | 182 | net = dev_net(skb->dev); |
181 | sk = __raw_v6_lookup(net, sk, nexthdr, daddr, saddr, inet6_iif(skb)); | 183 | sk = __raw_v6_lookup(net, sk, nexthdr, daddr, saddr, |
184 | inet6_iif(skb), inet6_sdif(skb)); | ||
182 | 185 | ||
183 | while (sk) { | 186 | while (sk) { |
184 | int filtered; | 187 | int filtered; |
@@ -222,7 +225,7 @@ static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) | |||
222 | } | 225 | } |
223 | } | 226 | } |
224 | sk = __raw_v6_lookup(net, sk_next(sk), nexthdr, daddr, saddr, | 227 | sk = __raw_v6_lookup(net, sk_next(sk), nexthdr, daddr, saddr, |
225 | inet6_iif(skb)); | 228 | inet6_iif(skb), inet6_sdif(skb)); |
226 | } | 229 | } |
227 | out: | 230 | out: |
228 | read_unlock(&raw_v6_hashinfo.lock); | 231 | read_unlock(&raw_v6_hashinfo.lock); |
@@ -378,7 +381,7 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr, | |||
378 | net = dev_net(skb->dev); | 381 | net = dev_net(skb->dev); |
379 | 382 | ||
380 | while ((sk = __raw_v6_lookup(net, sk, nexthdr, saddr, daddr, | 383 | while ((sk = __raw_v6_lookup(net, sk, nexthdr, saddr, daddr, |
381 | inet6_iif(skb)))) { | 384 | inet6_iif(skb), inet6_iif(skb)))) { |
382 | rawv6_err(sk, skb, NULL, type, code, | 385 | rawv6_err(sk, skb, NULL, type, code, |
383 | inner_offset, info); | 386 | inner_offset, info); |
384 | sk = sk_next(sk); | 387 | sk = sk_next(sk); |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index ced5dcf37465..f776ec4ecf6d 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -350,7 +350,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
350 | sk = __inet6_lookup_established(net, &tcp_hashinfo, | 350 | sk = __inet6_lookup_established(net, &tcp_hashinfo, |
351 | &hdr->daddr, th->dest, | 351 | &hdr->daddr, th->dest, |
352 | &hdr->saddr, ntohs(th->source), | 352 | &hdr->saddr, ntohs(th->source), |
353 | skb->dev->ifindex); | 353 | skb->dev->ifindex, inet6_sdif(skb)); |
354 | 354 | ||
355 | if (!sk) { | 355 | if (!sk) { |
356 | __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), | 356 | __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), |
@@ -918,7 +918,8 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) | |||
918 | &tcp_hashinfo, NULL, 0, | 918 | &tcp_hashinfo, NULL, 0, |
919 | &ipv6h->saddr, | 919 | &ipv6h->saddr, |
920 | th->source, &ipv6h->daddr, | 920 | th->source, &ipv6h->daddr, |
921 | ntohs(th->source), tcp_v6_iif(skb)); | 921 | ntohs(th->source), tcp_v6_iif(skb), |
922 | tcp_v6_sdif(skb)); | ||
922 | if (!sk1) | 923 | if (!sk1) |
923 | goto out; | 924 | goto out; |
924 | 925 | ||
@@ -1397,6 +1398,7 @@ static void tcp_v6_fill_cb(struct sk_buff *skb, const struct ipv6hdr *hdr, | |||
1397 | 1398 | ||
1398 | static int tcp_v6_rcv(struct sk_buff *skb) | 1399 | static int tcp_v6_rcv(struct sk_buff *skb) |
1399 | { | 1400 | { |
1401 | int sdif = inet6_sdif(skb); | ||
1400 | const struct tcphdr *th; | 1402 | const struct tcphdr *th; |
1401 | const struct ipv6hdr *hdr; | 1403 | const struct ipv6hdr *hdr; |
1402 | bool refcounted; | 1404 | bool refcounted; |
@@ -1430,7 +1432,7 @@ static int tcp_v6_rcv(struct sk_buff *skb) | |||
1430 | 1432 | ||
1431 | lookup: | 1433 | lookup: |
1432 | sk = __inet6_lookup_skb(&tcp_hashinfo, skb, __tcp_hdrlen(th), | 1434 | sk = __inet6_lookup_skb(&tcp_hashinfo, skb, __tcp_hdrlen(th), |
1433 | th->source, th->dest, inet6_iif(skb), | 1435 | th->source, th->dest, inet6_iif(skb), sdif, |
1434 | &refcounted); | 1436 | &refcounted); |
1435 | if (!sk) | 1437 | if (!sk) |
1436 | goto no_tcp_socket; | 1438 | goto no_tcp_socket; |
@@ -1563,7 +1565,8 @@ do_time_wait: | |||
1563 | skb, __tcp_hdrlen(th), | 1565 | skb, __tcp_hdrlen(th), |
1564 | &ipv6_hdr(skb)->saddr, th->source, | 1566 | &ipv6_hdr(skb)->saddr, th->source, |
1565 | &ipv6_hdr(skb)->daddr, | 1567 | &ipv6_hdr(skb)->daddr, |
1566 | ntohs(th->dest), tcp_v6_iif(skb)); | 1568 | ntohs(th->dest), tcp_v6_iif(skb), |
1569 | sdif); | ||
1567 | if (sk2) { | 1570 | if (sk2) { |
1568 | struct inet_timewait_sock *tw = inet_twsk(sk); | 1571 | struct inet_timewait_sock *tw = inet_twsk(sk); |
1569 | inet_twsk_deschedule_put(tw); | 1572 | inet_twsk_deschedule_put(tw); |
@@ -1610,7 +1613,7 @@ static void tcp_v6_early_demux(struct sk_buff *skb) | |||
1610 | sk = __inet6_lookup_established(dev_net(skb->dev), &tcp_hashinfo, | 1613 | sk = __inet6_lookup_established(dev_net(skb->dev), &tcp_hashinfo, |
1611 | &hdr->saddr, th->source, | 1614 | &hdr->saddr, th->source, |
1612 | &hdr->daddr, ntohs(th->dest), | 1615 | &hdr->daddr, ntohs(th->dest), |
1613 | inet6_iif(skb)); | 1616 | inet6_iif(skb), inet6_sdif(skb)); |
1614 | if (sk) { | 1617 | if (sk) { |
1615 | skb->sk = sk; | 1618 | skb->sk = sk; |
1616 | skb->destructor = sock_edemux; | 1619 | skb->destructor = sock_edemux; |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 578142b7ca3e..19afcaf4a22e 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -129,7 +129,7 @@ static void udp_v6_rehash(struct sock *sk) | |||
129 | static int compute_score(struct sock *sk, struct net *net, | 129 | static int compute_score(struct sock *sk, struct net *net, |
130 | const struct in6_addr *saddr, __be16 sport, | 130 | const struct in6_addr *saddr, __be16 sport, |
131 | const struct in6_addr *daddr, unsigned short hnum, | 131 | const struct in6_addr *daddr, unsigned short hnum, |
132 | int dif, bool exact_dif) | 132 | int dif, int sdif, bool exact_dif) |
133 | { | 133 | { |
134 | int score; | 134 | int score; |
135 | struct inet_sock *inet; | 135 | struct inet_sock *inet; |
@@ -161,9 +161,13 @@ static int compute_score(struct sock *sk, struct net *net, | |||
161 | } | 161 | } |
162 | 162 | ||
163 | if (sk->sk_bound_dev_if || exact_dif) { | 163 | if (sk->sk_bound_dev_if || exact_dif) { |
164 | if (sk->sk_bound_dev_if != dif) | 164 | bool dev_match = (sk->sk_bound_dev_if == dif || |
165 | sk->sk_bound_dev_if == sdif); | ||
166 | |||
167 | if (exact_dif && !dev_match) | ||
165 | return -1; | 168 | return -1; |
166 | score++; | 169 | if (sk->sk_bound_dev_if && dev_match) |
170 | score++; | ||
167 | } | 171 | } |
168 | 172 | ||
169 | if (sk->sk_incoming_cpu == raw_smp_processor_id()) | 173 | if (sk->sk_incoming_cpu == raw_smp_processor_id()) |
@@ -175,9 +179,9 @@ static int compute_score(struct sock *sk, struct net *net, | |||
175 | /* called with rcu_read_lock() */ | 179 | /* called with rcu_read_lock() */ |
176 | static struct sock *udp6_lib_lookup2(struct net *net, | 180 | static struct sock *udp6_lib_lookup2(struct net *net, |
177 | const struct in6_addr *saddr, __be16 sport, | 181 | const struct in6_addr *saddr, __be16 sport, |
178 | const struct in6_addr *daddr, unsigned int hnum, int dif, | 182 | const struct in6_addr *daddr, unsigned int hnum, |
179 | bool exact_dif, struct udp_hslot *hslot2, | 183 | int dif, int sdif, bool exact_dif, |
180 | struct sk_buff *skb) | 184 | struct udp_hslot *hslot2, struct sk_buff *skb) |
181 | { | 185 | { |
182 | struct sock *sk, *result; | 186 | struct sock *sk, *result; |
183 | int score, badness, matches = 0, reuseport = 0; | 187 | int score, badness, matches = 0, reuseport = 0; |
@@ -187,7 +191,7 @@ static struct sock *udp6_lib_lookup2(struct net *net, | |||
187 | badness = -1; | 191 | badness = -1; |
188 | udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) { | 192 | udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) { |
189 | score = compute_score(sk, net, saddr, sport, | 193 | score = compute_score(sk, net, saddr, sport, |
190 | daddr, hnum, dif, exact_dif); | 194 | daddr, hnum, dif, sdif, exact_dif); |
191 | if (score > badness) { | 195 | if (score > badness) { |
192 | reuseport = sk->sk_reuseport; | 196 | reuseport = sk->sk_reuseport; |
193 | if (reuseport) { | 197 | if (reuseport) { |
@@ -214,10 +218,10 @@ static struct sock *udp6_lib_lookup2(struct net *net, | |||
214 | 218 | ||
215 | /* rcu_read_lock() must be held */ | 219 | /* rcu_read_lock() must be held */ |
216 | struct sock *__udp6_lib_lookup(struct net *net, | 220 | struct sock *__udp6_lib_lookup(struct net *net, |
217 | const struct in6_addr *saddr, __be16 sport, | 221 | const struct in6_addr *saddr, __be16 sport, |
218 | const struct in6_addr *daddr, __be16 dport, | 222 | const struct in6_addr *daddr, __be16 dport, |
219 | int dif, struct udp_table *udptable, | 223 | int dif, int sdif, struct udp_table *udptable, |
220 | struct sk_buff *skb) | 224 | struct sk_buff *skb) |
221 | { | 225 | { |
222 | struct sock *sk, *result; | 226 | struct sock *sk, *result; |
223 | unsigned short hnum = ntohs(dport); | 227 | unsigned short hnum = ntohs(dport); |
@@ -235,7 +239,7 @@ struct sock *__udp6_lib_lookup(struct net *net, | |||
235 | goto begin; | 239 | goto begin; |
236 | 240 | ||
237 | result = udp6_lib_lookup2(net, saddr, sport, | 241 | result = udp6_lib_lookup2(net, saddr, sport, |
238 | daddr, hnum, dif, exact_dif, | 242 | daddr, hnum, dif, sdif, exact_dif, |
239 | hslot2, skb); | 243 | hslot2, skb); |
240 | if (!result) { | 244 | if (!result) { |
241 | unsigned int old_slot2 = slot2; | 245 | unsigned int old_slot2 = slot2; |
@@ -250,7 +254,7 @@ struct sock *__udp6_lib_lookup(struct net *net, | |||
250 | goto begin; | 254 | goto begin; |
251 | 255 | ||
252 | result = udp6_lib_lookup2(net, saddr, sport, | 256 | result = udp6_lib_lookup2(net, saddr, sport, |
253 | daddr, hnum, dif, | 257 | daddr, hnum, dif, sdif, |
254 | exact_dif, hslot2, | 258 | exact_dif, hslot2, |
255 | skb); | 259 | skb); |
256 | } | 260 | } |
@@ -261,7 +265,7 @@ begin: | |||
261 | badness = -1; | 265 | badness = -1; |
262 | sk_for_each_rcu(sk, &hslot->head) { | 266 | sk_for_each_rcu(sk, &hslot->head) { |
263 | score = compute_score(sk, net, saddr, sport, daddr, hnum, dif, | 267 | score = compute_score(sk, net, saddr, sport, daddr, hnum, dif, |
264 | exact_dif); | 268 | sdif, exact_dif); |
265 | if (score > badness) { | 269 | if (score > badness) { |
266 | reuseport = sk->sk_reuseport; | 270 | reuseport = sk->sk_reuseport; |
267 | if (reuseport) { | 271 | if (reuseport) { |
@@ -294,7 +298,7 @@ static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb, | |||
294 | 298 | ||
295 | return __udp6_lib_lookup(dev_net(skb->dev), &iph->saddr, sport, | 299 | return __udp6_lib_lookup(dev_net(skb->dev), &iph->saddr, sport, |
296 | &iph->daddr, dport, inet6_iif(skb), | 300 | &iph->daddr, dport, inet6_iif(skb), |
297 | udptable, skb); | 301 | inet6_sdif(skb), udptable, skb); |
298 | } | 302 | } |
299 | 303 | ||
300 | struct sock *udp6_lib_lookup_skb(struct sk_buff *skb, | 304 | struct sock *udp6_lib_lookup_skb(struct sk_buff *skb, |
@@ -304,7 +308,7 @@ struct sock *udp6_lib_lookup_skb(struct sk_buff *skb, | |||
304 | 308 | ||
305 | return __udp6_lib_lookup(dev_net(skb->dev), &iph->saddr, sport, | 309 | return __udp6_lib_lookup(dev_net(skb->dev), &iph->saddr, sport, |
306 | &iph->daddr, dport, inet6_iif(skb), | 310 | &iph->daddr, dport, inet6_iif(skb), |
307 | &udp_table, skb); | 311 | inet6_sdif(skb), &udp_table, skb); |
308 | } | 312 | } |
309 | EXPORT_SYMBOL_GPL(udp6_lib_lookup_skb); | 313 | EXPORT_SYMBOL_GPL(udp6_lib_lookup_skb); |
310 | 314 | ||
@@ -320,7 +324,7 @@ struct sock *udp6_lib_lookup(struct net *net, const struct in6_addr *saddr, __be | |||
320 | struct sock *sk; | 324 | struct sock *sk; |
321 | 325 | ||
322 | sk = __udp6_lib_lookup(net, saddr, sport, daddr, dport, | 326 | sk = __udp6_lib_lookup(net, saddr, sport, daddr, dport, |
323 | dif, &udp_table, NULL); | 327 | dif, 0, &udp_table, NULL); |
324 | if (sk && !refcount_inc_not_zero(&sk->sk_refcnt)) | 328 | if (sk && !refcount_inc_not_zero(&sk->sk_refcnt)) |
325 | sk = NULL; | 329 | sk = NULL; |
326 | return sk; | 330 | return sk; |
@@ -501,7 +505,7 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
501 | struct net *net = dev_net(skb->dev); | 505 | struct net *net = dev_net(skb->dev); |
502 | 506 | ||
503 | sk = __udp6_lib_lookup(net, daddr, uh->dest, saddr, uh->source, | 507 | sk = __udp6_lib_lookup(net, daddr, uh->dest, saddr, uh->source, |
504 | inet6_iif(skb), udptable, skb); | 508 | inet6_iif(skb), 0, udptable, skb); |
505 | if (!sk) { | 509 | if (!sk) { |
506 | __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), | 510 | __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), |
507 | ICMP6_MIB_INERRORS); | 511 | ICMP6_MIB_INERRORS); |
@@ -893,7 +897,7 @@ discard: | |||
893 | static struct sock *__udp6_lib_demux_lookup(struct net *net, | 897 | static struct sock *__udp6_lib_demux_lookup(struct net *net, |
894 | __be16 loc_port, const struct in6_addr *loc_addr, | 898 | __be16 loc_port, const struct in6_addr *loc_addr, |
895 | __be16 rmt_port, const struct in6_addr *rmt_addr, | 899 | __be16 rmt_port, const struct in6_addr *rmt_addr, |
896 | int dif) | 900 | int dif, int sdif) |
897 | { | 901 | { |
898 | unsigned short hnum = ntohs(loc_port); | 902 | unsigned short hnum = ntohs(loc_port); |
899 | unsigned int hash2 = udp6_portaddr_hash(net, loc_addr, hnum); | 903 | unsigned int hash2 = udp6_portaddr_hash(net, loc_addr, hnum); |
@@ -904,7 +908,7 @@ static struct sock *__udp6_lib_demux_lookup(struct net *net, | |||
904 | 908 | ||
905 | udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) { | 909 | udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) { |
906 | if (sk->sk_state == TCP_ESTABLISHED && | 910 | if (sk->sk_state == TCP_ESTABLISHED && |
907 | INET6_MATCH(sk, net, rmt_addr, loc_addr, ports, dif)) | 911 | INET6_MATCH(sk, net, rmt_addr, loc_addr, ports, dif, sdif)) |
908 | return sk; | 912 | return sk; |
909 | /* Only check first socket in chain */ | 913 | /* Only check first socket in chain */ |
910 | break; | 914 | break; |
@@ -919,6 +923,7 @@ static void udp_v6_early_demux(struct sk_buff *skb) | |||
919 | struct sock *sk; | 923 | struct sock *sk; |
920 | struct dst_entry *dst; | 924 | struct dst_entry *dst; |
921 | int dif = skb->dev->ifindex; | 925 | int dif = skb->dev->ifindex; |
926 | int sdif = inet6_sdif(skb); | ||
922 | 927 | ||
923 | if (!pskb_may_pull(skb, skb_transport_offset(skb) + | 928 | if (!pskb_may_pull(skb, skb_transport_offset(skb) + |
924 | sizeof(struct udphdr))) | 929 | sizeof(struct udphdr))) |
@@ -930,7 +935,7 @@ static void udp_v6_early_demux(struct sk_buff *skb) | |||
930 | sk = __udp6_lib_demux_lookup(net, uh->dest, | 935 | sk = __udp6_lib_demux_lookup(net, uh->dest, |
931 | &ipv6_hdr(skb)->daddr, | 936 | &ipv6_hdr(skb)->daddr, |
932 | uh->source, &ipv6_hdr(skb)->saddr, | 937 | uh->source, &ipv6_hdr(skb)->saddr, |
933 | dif); | 938 | dif, sdif); |
934 | else | 939 | else |
935 | return; | 940 | return; |
936 | 941 | ||
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c index d767e35fff6b..ade4c10c28c6 100644 --- a/net/netfilter/xt_TPROXY.c +++ b/net/netfilter/xt_TPROXY.c | |||
@@ -125,7 +125,7 @@ nf_tproxy_get_sock_v4(struct net *net, struct sk_buff *skb, void *hp, | |||
125 | __tcp_hdrlen(tcph), | 125 | __tcp_hdrlen(tcph), |
126 | saddr, sport, | 126 | saddr, sport, |
127 | daddr, dport, | 127 | daddr, dport, |
128 | in->ifindex); | 128 | in->ifindex, 0); |
129 | 129 | ||
130 | if (sk && !refcount_inc_not_zero(&sk->sk_refcnt)) | 130 | if (sk && !refcount_inc_not_zero(&sk->sk_refcnt)) |
131 | sk = NULL; | 131 | sk = NULL; |
@@ -195,7 +195,7 @@ nf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff, void *hp, | |||
195 | thoff + __tcp_hdrlen(tcph), | 195 | thoff + __tcp_hdrlen(tcph), |
196 | saddr, sport, | 196 | saddr, sport, |
197 | daddr, ntohs(dport), | 197 | daddr, ntohs(dport), |
198 | in->ifindex); | 198 | in->ifindex, 0); |
199 | 199 | ||
200 | if (sk && !refcount_inc_not_zero(&sk->sk_refcnt)) | 200 | if (sk && !refcount_inc_not_zero(&sk->sk_refcnt)) |
201 | sk = NULL; | 201 | sk = NULL; |
@@ -208,7 +208,7 @@ nf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff, void *hp, | |||
208 | case NFT_LOOKUP_ESTABLISHED: | 208 | case NFT_LOOKUP_ESTABLISHED: |
209 | sk = __inet6_lookup_established(net, &tcp_hashinfo, | 209 | sk = __inet6_lookup_established(net, &tcp_hashinfo, |
210 | saddr, sport, daddr, ntohs(dport), | 210 | saddr, sport, daddr, ntohs(dport), |
211 | in->ifindex); | 211 | in->ifindex, 0); |
212 | break; | 212 | break; |
213 | default: | 213 | default: |
214 | BUG(); | 214 | BUG(); |