net/rds/tcp_listen.c

Source file repositories/reference/linux-study-clean/net/rds/tcp_listen.c

File Facts

System
Linux kernel
Corpus path
net/rds/tcp_listen.c
Extension
.c
Size
13368 bytes
Lines
465
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: implementation source
Status
source implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

rds_addr_cmp(&conn->c_laddr, &conn->c_faddr) > 0) {
		/* cp->cp_index is encoded in lowest bits of source-port */
		sport = rds_tcp_get_peer_sport(sock);
		npaths = max_t(int, 1, conn->c_npaths);
		if (sport >= 0 && sport % npaths != 0)
			/* peer initiated with a non-#0 lane first */
			rds_conn_path_drop(conn->c_path, 0);
	}

	/* As soon as a connection went down,
	 * it is safe to schedule a "rds_tcp_accept_one"
	 * attempt even if there are no connections pending:
	 * Function "rds_tcp_accept_one" won't block
	 * but simply return -EAGAIN in that case.
	 *
	 * Doing so is necessary to address the case where an
	 * incoming connection on "rds_tcp_listen_sock" is ready
	 * to be accepted prior to a free slot being available:
	 * the -ENOBUFS case in "rds_tcp_accept_one".
	 */
	rds_tcp_accept_work(rtn);
}

int rds_tcp_accept_one(struct rds_tcp_net *rtn)
{
	struct socket *listen_sock = rtn->rds_tcp_listen_sock;
	struct socket *new_sock = NULL;
	struct rds_connection *conn;
	int ret;
	struct inet_sock *inet;
	struct rds_tcp_connection *rs_tcp = NULL;
	int conn_state;
	struct rds_conn_path *cp;
	struct sock *sk;
	struct in6_addr *my_addr, *peer_addr;
#if !IS_ENABLED(CONFIG_IPV6)
	struct in6_addr saddr, daddr;
#endif
	int dev_if = 0;

	if (!listen_sock) /* module unload or netns delete in progress */
		return -ENETUNREACH;

	mutex_lock(&rtn->rds_tcp_accept_lock);
	new_sock = rtn->rds_tcp_accepted_sock;
	rtn->rds_tcp_accepted_sock = NULL;

	if (!new_sock) {
		ret = kernel_accept(listen_sock, &new_sock, O_NONBLOCK);
		if (ret)
			goto out;

		rds_tcp_keepalive(new_sock);
		if (!rds_tcp_tune(new_sock)) {
			ret = -EINVAL;
			goto out;
		}
	}

	inet = inet_sk(new_sock->sk);

#if IS_ENABLED(CONFIG_IPV6)
	my_addr = &new_sock->sk->sk_v6_rcv_saddr;
	peer_addr = &new_sock->sk->sk_v6_daddr;
#else
	ipv6_addr_set_v4mapped(inet->inet_saddr, &saddr);
	ipv6_addr_set_v4mapped(inet->inet_daddr, &daddr);
	my_addr = &saddr;
	peer_addr = &daddr;
#endif
	rdsdebug("accepted family %d tcp %pI6c:%u -> %pI6c:%u\n",
		 listen_sock->sk->sk_family,
		 my_addr, ntohs(inet->inet_sport),
		 peer_addr, ntohs(inet->inet_dport));

#if IS_ENABLED(CONFIG_IPV6)
	/* sk_bound_dev_if is not set if the peer address is not link local
	 * address.  In this case, it happens that mcast_oif is set.  So
	 * just use it.
	 */
	if ((ipv6_addr_type(my_addr) & IPV6_ADDR_LINKLOCAL) &&
	    !(ipv6_addr_type(peer_addr) & IPV6_ADDR_LINKLOCAL)) {
		struct ipv6_pinfo *inet6;

		inet6 = inet6_sk(new_sock->sk);
		dev_if = READ_ONCE(inet6->mcast_oif);
	} else {
		dev_if = new_sock->sk->sk_bound_dev_if;
	}
#endif

Annotation

Implementation Notes