|
@@ -56,7 +56,7 @@ struct sock *__inet6_lookup_established(struct net *net,
|
|
|
const __be16 sport,
|
|
|
const struct in6_addr *daddr,
|
|
|
const u16 hnum,
|
|
|
- const int dif)
|
|
|
+ const int dif, const int sdif)
|
|
|
{
|
|
|
struct sock *sk;
|
|
|
const struct hlist_nulls_node *node;
|
|
@@ -73,12 +73,12 @@ begin:
|
|
|
sk_nulls_for_each_rcu(sk, node, &head->chain) {
|
|
|
if (sk->sk_hash != hash)
|
|
|
continue;
|
|
|
- if (!INET6_MATCH(sk, net, saddr, daddr, ports, dif))
|
|
|
+ if (!INET6_MATCH(sk, net, saddr, daddr, ports, dif, sdif))
|
|
|
continue;
|
|
|
if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt)))
|
|
|
goto out;
|
|
|
|
|
|
- if (unlikely(!INET6_MATCH(sk, net, saddr, daddr, ports, dif))) {
|
|
|
+ if (unlikely(!INET6_MATCH(sk, net, saddr, daddr, ports, dif, sdif))) {
|
|
|
sock_gen_put(sk);
|
|
|
goto begin;
|
|
|
}
|
|
@@ -96,7 +96,7 @@ EXPORT_SYMBOL(__inet6_lookup_established);
|
|
|
static inline int compute_score(struct sock *sk, struct net *net,
|
|
|
const unsigned short hnum,
|
|
|
const struct in6_addr *daddr,
|
|
|
- const int dif, bool exact_dif)
|
|
|
+ const int dif, const int sdif, bool exact_dif)
|
|
|
{
|
|
|
int score = -1;
|
|
|
|
|
@@ -110,9 +110,13 @@ static inline int compute_score(struct sock *sk, struct net *net,
|
|
|
score++;
|
|
|
}
|
|
|
if (sk->sk_bound_dev_if || exact_dif) {
|
|
|
- if (sk->sk_bound_dev_if != dif)
|
|
|
+ bool dev_match = (sk->sk_bound_dev_if == dif ||
|
|
|
+ sk->sk_bound_dev_if == sdif);
|
|
|
+
|
|
|
+ if (exact_dif && !dev_match)
|
|
|
return -1;
|
|
|
- score++;
|
|
|
+ if (sk->sk_bound_dev_if && dev_match)
|
|
|
+ score++;
|
|
|
}
|
|
|
if (sk->sk_incoming_cpu == raw_smp_processor_id())
|
|
|
score++;
|
|
@@ -126,7 +130,7 @@ struct sock *inet6_lookup_listener(struct net *net,
|
|
|
struct sk_buff *skb, int doff,
|
|
|
const struct in6_addr *saddr,
|
|
|
const __be16 sport, const struct in6_addr *daddr,
|
|
|
- const unsigned short hnum, const int dif)
|
|
|
+ const unsigned short hnum, const int dif, const int sdif)
|
|
|
{
|
|
|
unsigned int hash = inet_lhashfn(net, hnum);
|
|
|
struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash];
|
|
@@ -136,7 +140,7 @@ struct sock *inet6_lookup_listener(struct net *net,
|
|
|
u32 phash = 0;
|
|
|
|
|
|
sk_for_each(sk, &ilb->head) {
|
|
|
- score = compute_score(sk, net, hnum, daddr, dif, exact_dif);
|
|
|
+ score = compute_score(sk, net, hnum, daddr, dif, sdif, exact_dif);
|
|
|
if (score > hiscore) {
|
|
|
reuseport = sk->sk_reuseport;
|
|
|
if (reuseport) {
|
|
@@ -171,7 +175,7 @@ struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
|
|
|
bool refcounted;
|
|
|
|
|
|
sk = __inet6_lookup(net, hashinfo, skb, doff, saddr, sport, daddr,
|
|
|
- ntohs(dport), dif, &refcounted);
|
|
|
+ ntohs(dport), dif, 0, &refcounted);
|
|
|
if (sk && !refcounted && !refcount_inc_not_zero(&sk->sk_refcnt))
|
|
|
sk = NULL;
|
|
|
return sk;
|
|
@@ -187,8 +191,9 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
|
|
|
const struct in6_addr *daddr = &sk->sk_v6_rcv_saddr;
|
|
|
const struct in6_addr *saddr = &sk->sk_v6_daddr;
|
|
|
const int dif = sk->sk_bound_dev_if;
|
|
|
- const __portpair ports = INET_COMBINED_PORTS(inet->inet_dport, lport);
|
|
|
struct net *net = sock_net(sk);
|
|
|
+ const int sdif = l3mdev_master_ifindex_by_index(net, dif);
|
|
|
+ const __portpair ports = INET_COMBINED_PORTS(inet->inet_dport, lport);
|
|
|
const unsigned int hash = inet6_ehashfn(net, daddr, lport, saddr,
|
|
|
inet->inet_dport);
|
|
|
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,
|
|
|
if (sk2->sk_hash != hash)
|
|
|
continue;
|
|
|
|
|
|
- if (likely(INET6_MATCH(sk2, net, saddr, daddr, ports, dif))) {
|
|
|
+ if (likely(INET6_MATCH(sk2, net, saddr, daddr, ports,
|
|
|
+ dif, sdif))) {
|
|
|
if (sk2->sk_state == TCP_TIME_WAIT) {
|
|
|
tw = inet_twsk(sk2);
|
|
|
if (twsk_unique(sk, sk2, twp))
|