net/rxrpc/output.c

Source file repositories/reference/linux-study-clean/net/rxrpc/output.c

File Facts

System
Linux kernel
Corpus path
net/rxrpc/output.c
Extension
.c
Size
27346 bytes
Lines
984
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

struct rxrpc_abort_buffer {
	struct rxrpc_wire_header whdr;
	__be32 abort_code;
};

static const char rxrpc_keepalive_string[] = "";

/*
 * Increase Tx backoff on transmission failure and clear it on success.
 */
static void rxrpc_tx_backoff(struct rxrpc_call *call, int ret)
{
	if (ret < 0) {
		if (call->tx_backoff < 1000)
			call->tx_backoff += 100;
	} else {
		call->tx_backoff = 0;
	}
}

/*
 * Arrange for a keepalive ping a certain time after we last transmitted.  This
 * lets the far side know we're still interested in this call and helps keep
 * the route through any intervening firewall open.
 *
 * Receiving a response to the ping will prevent the ->expect_rx_by timer from
 * expiring.
 */
static void rxrpc_set_keepalive(struct rxrpc_call *call, ktime_t now)
{
	ktime_t delay = ms_to_ktime(READ_ONCE(call->next_rx_timo) / 6);

	call->keepalive_at = ktime_add(ktime_get_real(), delay);
	trace_rxrpc_timer_set(call, delay, rxrpc_timer_trace_keepalive);
}

/*
 * Allocate transmission buffers for an ACK and attach them to local->kv[].
 */
static int rxrpc_alloc_ack(struct rxrpc_call *call, size_t sack_size)
{
	struct rxrpc_wire_header *whdr;
	struct rxrpc_acktrailer *trailer;
	struct rxrpc_ackpacket *ack;
	struct kvec *kv = call->local->kvec;
	gfp_t gfp = rcu_read_lock_held() ? GFP_ATOMIC | __GFP_NOWARN : GFP_NOFS;
	void *buf, *buf2 = NULL;
	u8 *filler;

	buf = page_frag_alloc(&call->local->tx_alloc,
			      sizeof(*whdr) + sizeof(*ack) + 1 + 3 + sizeof(*trailer), gfp);
	if (!buf)
		return -ENOMEM;

	if (sack_size) {
		buf2 = page_frag_alloc(&call->local->tx_alloc, sack_size, gfp);
		if (!buf2) {
			page_frag_free(buf);
			return -ENOMEM;
		}
	}

	whdr	= buf;
	ack	= buf + sizeof(*whdr);
	filler	= buf + sizeof(*whdr) + sizeof(*ack) + 1;
	trailer	= buf + sizeof(*whdr) + sizeof(*ack) + 1 + 3;

	kv[0].iov_base	= whdr;
	kv[0].iov_len	= sizeof(*whdr) + sizeof(*ack);
	kv[1].iov_base	= buf2;
	kv[1].iov_len	= sack_size;
	kv[2].iov_base	= filler;
	kv[2].iov_len	= 3 + sizeof(*trailer);
	return 3; /* Number of kvec[] used. */
}

static void rxrpc_free_ack(struct rxrpc_call *call)
{
	page_frag_free(call->local->kvec[0].iov_base);
	if (call->local->kvec[1].iov_base)
		page_frag_free(call->local->kvec[1].iov_base);
}

/*
 * Record the beginning of an RTT probe.
 */
static void rxrpc_begin_rtt_probe(struct rxrpc_call *call, rxrpc_serial_t serial,
				  ktime_t now, enum rxrpc_rtt_tx_trace why)
{
	unsigned long avail = call->rtt_avail;

Annotation

Implementation Notes