赞
踩
内核在分配临时端口的时候,会使用一个hash bucket存放同一端口,在reuse的情况下所有socket。在下一次选择端口的时候,会做根据fastreuse的情况,来判断是否做conflict检查。这里有一个问题:https://mzhan017.blog.csdn.net/article/details/137108073。
其实可以加一个内核参数来控制,在选择下一个临时端口的时候,是否要找hash bucket已经存在的端口,如果设置不找,就跳过存在于这些hashbucket里的端口,直接走到下一个端口。可以解决缓解避免上面fastreuse被污染的情况。
static int inet_csk_bind_conflict(const struct sock *sk,
const struct inet_bind_bucket *tb,
bool relax, bool reuseport_ok)
{
struct sock *sk2;
bool reuse = sk->sk_reuse;
bool reuseport = !!sk->sk_reuseport && reuseport_ok;
kuid_t uid = sock_i_uid((struct sock *)sk);
/*
* Unlike other sk lookup places we do not check
* for sk_net here, since _all_ the socks listed
* in tb->owners list belong to the same net - the
* one this bucket belongs to.
*/
sk_for_each_bound(sk2, &tb->owners) {
if (sk != sk2 && // 这两个socket 不相同
(!sk->sk_bound_dev_if || //这个新建立的socket没有 bound dev if,有conflict的存在的可能
!sk2->sk_bound_dev_if || //或者这个table里的socket也没有 bound dev if,有conflict存在的可能
sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) { // 或者bound dev if 相同 就有conflict的可能,需要进一步的check
if ((!reuse || !sk2->sk_reuse || // 当前这个socket不可reuse,或者 table里socket有不可reuse的socket,就有conflict的可能
sk2->sk_state == TCP_LISTEN) && //
(!reuseport || !sk2->sk_reuseport ||
rcu_access_pointer(sk->sk_reuseport_cb) ||
(sk2->sk_state != TCP_TIME_WAIT &&
!uid_eq(uid, sock_i_uid(sk2))))) {
if (inet_rcv_saddr_equal(sk, sk2, true)) //需要进一步check。如果不相同的ip版本, 就直接判定无conflict。
break; ///这里有break,就代表有conflict
}
if (!relax && reuse && sk2->sk_reuse &&
sk2->sk_state != TCP_LISTEN) {
if (inet_rcv_saddr_equal(sk, sk2, true))
break; ///这里有break,就代表有conflict
}
}
}
return sk2 != NULL;
}
bool inet_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2,
bool match_wildcard)
{
//#if IS_ENABLED(CONFIG_IPV6)
if (sk->sk_family == AF_INET6)
return ipv6_rcv_saddr_equal(&sk->sk_v6_rcv_saddr,
inet6_rcv_saddr(sk2),
sk->sk_rcv_saddr,
sk2->sk_rcv_saddr,
ipv6_only_sock(sk),
ipv6_only_sock(sk2),
match_wildcard,
match_wildcard);
//#endif
return ipv4_rcv_saddr_equal(sk->sk_rcv_saddr, sk2->sk_rcv_saddr,
ipv6_only_sock(sk2), match_wildcard,
match_wildcard);
}
/* match_sk*_wildcard == true: 0.0.0.0 equals to any IPv4 addresses
* match_sk*_wildcard == false: addresses must be exactly the same, i.e.
* 0.0.0.0 only equals to 0.0.0.0
*/
static bool ipv4_rcv_saddr_equal(__be32 sk1_rcv_saddr, __be32 sk2_rcv_saddr,
bool sk2_ipv6only, bool match_sk1_wildcard,
bool match_sk2_wildcard)
{
if (!sk2_ipv6only) {
if (sk1_rcv_saddr == sk2_rcv_saddr)
return true;
return (match_sk1_wildcard && !sk1_rcv_saddr) ||
(match_sk2_wildcard && !sk2_rcv_saddr);
}
return false;
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。