|
@@ -129,7 +129,7 @@ static void udp_v6_rehash(struct sock *sk)
|
|
|
static int compute_score(struct sock *sk, struct net *net,
|
|
|
const struct in6_addr *saddr, __be16 sport,
|
|
|
const struct in6_addr *daddr, unsigned short hnum,
|
|
|
- int dif, bool exact_dif)
|
|
|
+ int dif, int sdif, bool exact_dif)
|
|
|
{
|
|
|
int score;
|
|
|
struct inet_sock *inet;
|
|
@@ -161,9 +161,13 @@ static int compute_score(struct sock *sk, struct net *net,
|
|
|
}
|
|
|
|
|
|
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())
|
|
@@ -175,9 +179,9 @@ static int compute_score(struct sock *sk, struct net *net,
|
|
|
/* called with rcu_read_lock() */
|
|
|
static struct sock *udp6_lib_lookup2(struct net *net,
|
|
|
const struct in6_addr *saddr, __be16 sport,
|
|
|
- const struct in6_addr *daddr, unsigned int hnum, int dif,
|
|
|
- bool exact_dif, struct udp_hslot *hslot2,
|
|
|
- struct sk_buff *skb)
|
|
|
+ const struct in6_addr *daddr, unsigned int hnum,
|
|
|
+ int dif, int sdif, bool exact_dif,
|
|
|
+ struct udp_hslot *hslot2, struct sk_buff *skb)
|
|
|
{
|
|
|
struct sock *sk, *result;
|
|
|
int score, badness, matches = 0, reuseport = 0;
|
|
@@ -187,7 +191,7 @@ static struct sock *udp6_lib_lookup2(struct net *net,
|
|
|
badness = -1;
|
|
|
udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) {
|
|
|
score = compute_score(sk, net, saddr, sport,
|
|
|
- daddr, hnum, dif, exact_dif);
|
|
|
+ daddr, hnum, dif, sdif, exact_dif);
|
|
|
if (score > badness) {
|
|
|
reuseport = sk->sk_reuseport;
|
|
|
if (reuseport) {
|
|
@@ -214,10 +218,10 @@ static struct sock *udp6_lib_lookup2(struct net *net,
|
|
|
|
|
|
/* rcu_read_lock() must be held */
|
|
|
struct sock *__udp6_lib_lookup(struct net *net,
|
|
|
- const struct in6_addr *saddr, __be16 sport,
|
|
|
- const struct in6_addr *daddr, __be16 dport,
|
|
|
- int dif, struct udp_table *udptable,
|
|
|
- struct sk_buff *skb)
|
|
|
+ const struct in6_addr *saddr, __be16 sport,
|
|
|
+ const struct in6_addr *daddr, __be16 dport,
|
|
|
+ int dif, int sdif, struct udp_table *udptable,
|
|
|
+ struct sk_buff *skb)
|
|
|
{
|
|
|
struct sock *sk, *result;
|
|
|
unsigned short hnum = ntohs(dport);
|
|
@@ -235,7 +239,7 @@ struct sock *__udp6_lib_lookup(struct net *net,
|
|
|
goto begin;
|
|
|
|
|
|
result = udp6_lib_lookup2(net, saddr, sport,
|
|
|
- daddr, hnum, dif, exact_dif,
|
|
|
+ daddr, hnum, dif, sdif, exact_dif,
|
|
|
hslot2, skb);
|
|
|
if (!result) {
|
|
|
unsigned int old_slot2 = slot2;
|
|
@@ -250,7 +254,7 @@ struct sock *__udp6_lib_lookup(struct net *net,
|
|
|
goto begin;
|
|
|
|
|
|
result = udp6_lib_lookup2(net, saddr, sport,
|
|
|
- daddr, hnum, dif,
|
|
|
+ daddr, hnum, dif, sdif,
|
|
|
exact_dif, hslot2,
|
|
|
skb);
|
|
|
}
|
|
@@ -261,7 +265,7 @@ begin:
|
|
|
badness = -1;
|
|
|
sk_for_each_rcu(sk, &hslot->head) {
|
|
|
score = compute_score(sk, net, saddr, sport, daddr, hnum, dif,
|
|
|
- exact_dif);
|
|
|
+ sdif, exact_dif);
|
|
|
if (score > badness) {
|
|
|
reuseport = sk->sk_reuseport;
|
|
|
if (reuseport) {
|
|
@@ -294,7 +298,7 @@ static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb,
|
|
|
|
|
|
return __udp6_lib_lookup(dev_net(skb->dev), &iph->saddr, sport,
|
|
|
&iph->daddr, dport, inet6_iif(skb),
|
|
|
- udptable, skb);
|
|
|
+ inet6_sdif(skb), udptable, skb);
|
|
|
}
|
|
|
|
|
|
struct sock *udp6_lib_lookup_skb(struct sk_buff *skb,
|
|
@@ -304,7 +308,7 @@ struct sock *udp6_lib_lookup_skb(struct sk_buff *skb,
|
|
|
|
|
|
return __udp6_lib_lookup(dev_net(skb->dev), &iph->saddr, sport,
|
|
|
&iph->daddr, dport, inet6_iif(skb),
|
|
|
- &udp_table, skb);
|
|
|
+ inet6_sdif(skb), &udp_table, skb);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(udp6_lib_lookup_skb);
|
|
|
|
|
@@ -320,7 +324,7 @@ struct sock *udp6_lib_lookup(struct net *net, const struct in6_addr *saddr, __be
|
|
|
struct sock *sk;
|
|
|
|
|
|
sk = __udp6_lib_lookup(net, saddr, sport, daddr, dport,
|
|
|
- dif, &udp_table, NULL);
|
|
|
+ dif, 0, &udp_table, NULL);
|
|
|
if (sk && !refcount_inc_not_zero(&sk->sk_refcnt))
|
|
|
sk = NULL;
|
|
|
return sk;
|
|
@@ -501,7 +505,7 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
|
|
struct net *net = dev_net(skb->dev);
|
|
|
|
|
|
sk = __udp6_lib_lookup(net, daddr, uh->dest, saddr, uh->source,
|
|
|
- inet6_iif(skb), udptable, skb);
|
|
|
+ inet6_iif(skb), 0, udptable, skb);
|
|
|
if (!sk) {
|
|
|
__ICMP6_INC_STATS(net, __in6_dev_get(skb->dev),
|
|
|
ICMP6_MIB_INERRORS);
|