Linux: network:socket: inet_csk_bind_conflict相关的一个改进建议

内核在分配临时端口的时候,会使用一个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;
}

相关推荐

  1. 使用React Context一些优化建议

    2024-04-04 06:48:08       34 阅读
  2. 改善python程序91建议记录(学习记录)

    2024-04-04 06:48:08       58 阅读
  3. 关于MySQL源码学习 这里是一些建议

    2024-04-04 06:48:08       52 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-04 06:48:08       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-04 06:48:08       100 阅读
  3. 在Django里面运行非项目文件

    2024-04-04 06:48:08       82 阅读
  4. Python语言-面向对象

    2024-04-04 06:48:08       91 阅读

热门阅读

  1. 如何开启MySQL的binlog日志

    2024-04-04 06:48:08       35 阅读
  2. Mac 如何彻底卸载Python 环境?

    2024-04-04 06:48:08       39 阅读
  3. ffmpeg Android 笔记

    2024-04-04 06:48:08       37 阅读
  4. springboot如何编写gitlabrunner的部署文件

    2024-04-04 06:48:08       32 阅读
  5. pdf预览组件react-pdf,pdfjs-dist

    2024-04-04 06:48:08       31 阅读
  6. Spark面试整理-什么是Spark SQL?

    2024-04-04 06:48:08       37 阅读