net/ipv4/tcp_output.c

Source file repositories/reference/linux-study-clean/net/ipv4/tcp_output.c

File Facts

System
Linux kernel
Corpus path
net/ipv4/tcp_output.c
Extension
.c
Size
139462 bytes
Lines
4661
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: exported/initcall integration point
Status
integration 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

struct tcp_out_options {
	/* Following group is cleared in __tcp_transmit_skb() */
	struct_group(cleared,
		u16 mss;		/* 0 to disable */
		u8 bpf_opt_len;		/* length of BPF hdr option */
		u8 num_sack_blocks;	/* number of SACK blocks to include */
	);

	/* Caution: following fields are not cleared in __tcp_transmit_skb() */
	u16 options;		/* bit field of OPTION_* */
	u8 ws;			/* window scale, 0 to disable */
	u8 num_accecn_fields:7,	/* number of AccECN fields needed */
	   use_synack_ecn_bytes:1; /* Use synack_ecn_bytes or not */
	__u8 *hash_location;	/* temporary pointer, overloaded */
	__u32 tsval, tsecr;	/* need to include OPTION_TS */
	struct tcp_fastopen_cookie *fastopen_cookie;	/* Fast open cookie */
	struct mptcp_out_options mptcp;
};

static void mptcp_options_write(struct tcphdr *th, __be32 *ptr,
				struct tcp_sock *tp,
				struct tcp_out_options *opts)
{
#if IS_ENABLED(CONFIG_MPTCP)
	if (unlikely(OPTION_MPTCP & opts->options))
		mptcp_write_options(th, ptr, tp, &opts->mptcp);
#endif
}

#ifdef CONFIG_CGROUP_BPF
static int bpf_skops_write_hdr_opt_arg0(struct sk_buff *skb,
					enum tcp_synack_type synack_type)
{
	if (unlikely(!skb))
		return BPF_WRITE_HDR_TCP_CURRENT_MSS;

	if (unlikely(synack_type == TCP_SYNACK_COOKIE))
		return BPF_WRITE_HDR_TCP_SYNACK_COOKIE;

	return 0;
}

/* req, syn_skb and synack_type are used when writing synack */
static u32 bpf_skops_hdr_opt_len(struct sock *sk, struct sk_buff *skb,
				 struct request_sock *req,
				 struct sk_buff *syn_skb,
				 enum tcp_synack_type synack_type,
				 struct tcp_out_options *opts,
				 u32 remaining)
{
	struct bpf_sock_ops_kern sock_ops;
	int err;

	if (likely(!BPF_SOCK_OPS_TEST_FLAG(tcp_sk(sk),
					   BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG)) ||
	    !remaining)
		return remaining;

	/* remaining has already been aligned to 4 bytes, so remaining >= 4 */

	/* init sock_ops */
	memset(&sock_ops, 0, offsetof(struct bpf_sock_ops_kern, temp));

	sock_ops.op = BPF_SOCK_OPS_HDR_OPT_LEN_CB;

	if (req) {
		/* The listen "sk" cannot be passed here because
		 * it is not locked.  It would not make too much
		 * sense to do bpf_setsockopt(listen_sk) based
		 * on individual connection request also.
		 *
		 * Thus, "req" is passed here and the cgroup-bpf-progs
		 * of the listen "sk" will be run.
		 *
		 * "req" is also used here for fastopen even the "sk" here is
		 * a fullsock "child" sk.  It is to keep the behavior
		 * consistent between fastopen and non-fastopen on
		 * the bpf programming side.
		 */
		sock_ops.sk = (struct sock *)req;
		sock_ops.syn_skb = syn_skb;
	} else {
		sock_owned_by_me(sk);

		sock_ops.is_fullsock = 1;
		sock_ops.is_locked_tcp_sock = 1;
		sock_ops.sk = sk;
	}

	sock_ops.args[0] = bpf_skops_write_hdr_opt_arg0(skb, synack_type);

Annotation

Implementation Notes