rxrpc: Don't store the rxrpc header in the Tx queue sk_buffs
Don't store the rxrpc protocol header in sk_buffs on the transmit queue, but rather generate it on the fly and pass it to kernel_sendmsg() as a separate iov. This reduces the amount of storage required. Note that the security header is still stored in the sk_buff as it may get encrypted along with the data (and doesn't change with each transmission). Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
parent
2d7a892626
commit
5a924b8951
@ -385,10 +385,9 @@ struct rxrpc_connection {
|
|||||||
int debug_id; /* debug ID for printks */
|
int debug_id; /* debug ID for printks */
|
||||||
atomic_t serial; /* packet serial number counter */
|
atomic_t serial; /* packet serial number counter */
|
||||||
unsigned int hi_serial; /* highest serial number received */
|
unsigned int hi_serial; /* highest serial number received */
|
||||||
u8 size_align; /* data size alignment (for security) */
|
|
||||||
u8 header_size; /* rxrpc + security header size */
|
|
||||||
u8 security_size; /* security header size */
|
|
||||||
u32 security_nonce; /* response re-use preventer */
|
u32 security_nonce; /* response re-use preventer */
|
||||||
|
u8 size_align; /* data size alignment (for security) */
|
||||||
|
u8 security_size; /* security header size */
|
||||||
u8 security_ix; /* security type */
|
u8 security_ix; /* security type */
|
||||||
u8 out_clientflag; /* RXRPC_CLIENT_INITIATED if we are client */
|
u8 out_clientflag; /* RXRPC_CLIENT_INITIATED if we are client */
|
||||||
};
|
};
|
||||||
@ -946,7 +945,7 @@ extern const s8 rxrpc_ack_priority[];
|
|||||||
* output.c
|
* output.c
|
||||||
*/
|
*/
|
||||||
int rxrpc_send_call_packet(struct rxrpc_call *, u8);
|
int rxrpc_send_call_packet(struct rxrpc_call *, u8);
|
||||||
int rxrpc_send_data_packet(struct rxrpc_connection *, struct sk_buff *);
|
int rxrpc_send_data_packet(struct rxrpc_call *, struct sk_buff *);
|
||||||
void rxrpc_reject_packets(struct rxrpc_local *);
|
void rxrpc_reject_packets(struct rxrpc_local *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -139,7 +139,6 @@ void rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,
|
|||||||
*/
|
*/
|
||||||
static void rxrpc_resend(struct rxrpc_call *call)
|
static void rxrpc_resend(struct rxrpc_call *call)
|
||||||
{
|
{
|
||||||
struct rxrpc_wire_header *whdr;
|
|
||||||
struct rxrpc_skb_priv *sp;
|
struct rxrpc_skb_priv *sp;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
rxrpc_seq_t cursor, seq, top;
|
rxrpc_seq_t cursor, seq, top;
|
||||||
@ -201,15 +200,8 @@ static void rxrpc_resend(struct rxrpc_call *call)
|
|||||||
skb = call->rxtx_buffer[ix];
|
skb = call->rxtx_buffer[ix];
|
||||||
rxrpc_get_skb(skb, rxrpc_skb_tx_got);
|
rxrpc_get_skb(skb, rxrpc_skb_tx_got);
|
||||||
spin_unlock_bh(&call->lock);
|
spin_unlock_bh(&call->lock);
|
||||||
sp = rxrpc_skb(skb);
|
|
||||||
|
|
||||||
/* Each Tx packet needs a new serial number */
|
if (rxrpc_send_data_packet(call, skb) < 0) {
|
||||||
sp->hdr.serial = atomic_inc_return(&call->conn->serial);
|
|
||||||
|
|
||||||
whdr = (struct rxrpc_wire_header *)skb->head;
|
|
||||||
whdr->serial = htonl(sp->hdr.serial);
|
|
||||||
|
|
||||||
if (rxrpc_send_data_packet(call->conn, skb) < 0) {
|
|
||||||
call->resend_at = now + 2;
|
call->resend_at = now + 2;
|
||||||
rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
|
rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
|
||||||
return;
|
return;
|
||||||
@ -217,6 +209,7 @@ static void rxrpc_resend(struct rxrpc_call *call)
|
|||||||
|
|
||||||
if (rxrpc_is_client_call(call))
|
if (rxrpc_is_client_call(call))
|
||||||
rxrpc_expose_client_call(call);
|
rxrpc_expose_client_call(call);
|
||||||
|
sp = rxrpc_skb(skb);
|
||||||
sp->resend_at = now + rxrpc_resend_timeout;
|
sp->resend_at = now + rxrpc_resend_timeout;
|
||||||
|
|
||||||
rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
|
rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
|
||||||
|
@ -53,7 +53,6 @@ struct rxrpc_connection *rxrpc_alloc_connection(gfp_t gfp)
|
|||||||
spin_lock_init(&conn->state_lock);
|
spin_lock_init(&conn->state_lock);
|
||||||
conn->debug_id = atomic_inc_return(&rxrpc_debug_id);
|
conn->debug_id = atomic_inc_return(&rxrpc_debug_id);
|
||||||
conn->size_align = 4;
|
conn->size_align = 4;
|
||||||
conn->header_size = sizeof(struct rxrpc_wire_header);
|
|
||||||
conn->idle_timestamp = jiffies;
|
conn->idle_timestamp = jiffies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,19 +208,42 @@ int rxrpc_send_call_packet(struct rxrpc_call *call, u8 type)
|
|||||||
/*
|
/*
|
||||||
* send a packet through the transport endpoint
|
* send a packet through the transport endpoint
|
||||||
*/
|
*/
|
||||||
int rxrpc_send_data_packet(struct rxrpc_connection *conn, struct sk_buff *skb)
|
int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct kvec iov[1];
|
struct rxrpc_connection *conn = call->conn;
|
||||||
|
struct rxrpc_wire_header whdr;
|
||||||
|
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
|
struct kvec iov[2];
|
||||||
|
rxrpc_serial_t serial;
|
||||||
|
size_t len;
|
||||||
int ret, opt;
|
int ret, opt;
|
||||||
|
|
||||||
_enter(",{%d}", skb->len);
|
_enter(",{%d}", skb->len);
|
||||||
|
|
||||||
iov[0].iov_base = skb->head;
|
/* Each transmission of a Tx packet needs a new serial number */
|
||||||
iov[0].iov_len = skb->len;
|
serial = atomic_inc_return(&conn->serial);
|
||||||
|
|
||||||
msg.msg_name = &conn->params.peer->srx.transport;
|
whdr.epoch = htonl(conn->proto.epoch);
|
||||||
msg.msg_namelen = conn->params.peer->srx.transport_len;
|
whdr.cid = htonl(call->cid);
|
||||||
|
whdr.callNumber = htonl(call->call_id);
|
||||||
|
whdr.seq = htonl(sp->hdr.seq);
|
||||||
|
whdr.serial = htonl(serial);
|
||||||
|
whdr.type = RXRPC_PACKET_TYPE_DATA;
|
||||||
|
whdr.flags = sp->hdr.flags;
|
||||||
|
whdr.userStatus = 0;
|
||||||
|
whdr.securityIndex = call->security_ix;
|
||||||
|
whdr._rsvd = htons(sp->hdr._rsvd);
|
||||||
|
whdr.serviceId = htons(call->service_id);
|
||||||
|
|
||||||
|
iov[0].iov_base = &whdr;
|
||||||
|
iov[0].iov_len = sizeof(whdr);
|
||||||
|
iov[1].iov_base = skb->head;
|
||||||
|
iov[1].iov_len = skb->len;
|
||||||
|
len = iov[0].iov_len + iov[1].iov_len;
|
||||||
|
|
||||||
|
msg.msg_name = &call->peer->srx.transport;
|
||||||
|
msg.msg_namelen = call->peer->srx.transport_len;
|
||||||
msg.msg_control = NULL;
|
msg.msg_control = NULL;
|
||||||
msg.msg_controllen = 0;
|
msg.msg_controllen = 0;
|
||||||
msg.msg_flags = 0;
|
msg.msg_flags = 0;
|
||||||
@ -234,9 +257,13 @@ int rxrpc_send_data_packet(struct rxrpc_connection *conn, struct sk_buff *skb)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_proto("Tx DATA %%%u { #%u }", serial, sp->hdr.seq);
|
||||||
|
|
||||||
/* send the packet with the don't fragment bit set if we currently
|
/* send the packet with the don't fragment bit set if we currently
|
||||||
* think it's small enough */
|
* think it's small enough */
|
||||||
if (skb->len - sizeof(struct rxrpc_wire_header) < conn->params.peer->maxdata) {
|
if (iov[1].iov_len >= call->peer->maxdata)
|
||||||
|
goto send_fragmentable;
|
||||||
|
|
||||||
down_read(&conn->params.local->defrag_sem);
|
down_read(&conn->params.local->defrag_sem);
|
||||||
/* send the packet by UDP
|
/* send the packet by UDP
|
||||||
* - returns -EMSGSIZE if UDP would have to fragment the packet
|
* - returns -EMSGSIZE if UDP would have to fragment the packet
|
||||||
@ -244,16 +271,19 @@ int rxrpc_send_data_packet(struct rxrpc_connection *conn, struct sk_buff *skb)
|
|||||||
* - in which case, we'll have processed the ICMP error
|
* - in which case, we'll have processed the ICMP error
|
||||||
* message and update the peer record
|
* message and update the peer record
|
||||||
*/
|
*/
|
||||||
ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 1,
|
ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 2, len);
|
||||||
iov[0].iov_len);
|
|
||||||
|
|
||||||
up_read(&conn->params.local->defrag_sem);
|
up_read(&conn->params.local->defrag_sem);
|
||||||
if (ret == -EMSGSIZE)
|
if (ret == -EMSGSIZE)
|
||||||
goto send_fragmentable;
|
goto send_fragmentable;
|
||||||
|
|
||||||
_leave(" = %d [%u]", ret, conn->params.peer->maxdata);
|
done:
|
||||||
return ret;
|
if (ret == 0) {
|
||||||
|
sp->resend_at = jiffies + rxrpc_resend_timeout;
|
||||||
|
sp->hdr.serial = serial;
|
||||||
}
|
}
|
||||||
|
_leave(" = %d [%u]", ret, call->peer->maxdata);
|
||||||
|
return ret;
|
||||||
|
|
||||||
send_fragmentable:
|
send_fragmentable:
|
||||||
/* attempt to send this message with fragmentation enabled */
|
/* attempt to send this message with fragmentation enabled */
|
||||||
@ -268,8 +298,8 @@ int rxrpc_send_data_packet(struct rxrpc_connection *conn, struct sk_buff *skb)
|
|||||||
SOL_IP, IP_MTU_DISCOVER,
|
SOL_IP, IP_MTU_DISCOVER,
|
||||||
(char *)&opt, sizeof(opt));
|
(char *)&opt, sizeof(opt));
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 1,
|
ret = kernel_sendmsg(conn->params.local->socket, &msg,
|
||||||
iov[0].iov_len);
|
iov, 2, len);
|
||||||
|
|
||||||
opt = IP_PMTUDISC_DO;
|
opt = IP_PMTUDISC_DO;
|
||||||
kernel_setsockopt(conn->params.local->socket, SOL_IP,
|
kernel_setsockopt(conn->params.local->socket, SOL_IP,
|
||||||
@ -298,8 +328,7 @@ int rxrpc_send_data_packet(struct rxrpc_connection *conn, struct sk_buff *skb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
up_write(&conn->params.local->defrag_sem);
|
up_write(&conn->params.local->defrag_sem);
|
||||||
_leave(" = %d [frag %u]", ret, conn->params.peer->maxdata);
|
goto done;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -80,12 +80,10 @@ static int rxkad_init_connection_security(struct rxrpc_connection *conn)
|
|||||||
case RXRPC_SECURITY_AUTH:
|
case RXRPC_SECURITY_AUTH:
|
||||||
conn->size_align = 8;
|
conn->size_align = 8;
|
||||||
conn->security_size = sizeof(struct rxkad_level1_hdr);
|
conn->security_size = sizeof(struct rxkad_level1_hdr);
|
||||||
conn->header_size += sizeof(struct rxkad_level1_hdr);
|
|
||||||
break;
|
break;
|
||||||
case RXRPC_SECURITY_ENCRYPT:
|
case RXRPC_SECURITY_ENCRYPT:
|
||||||
conn->size_align = 8;
|
conn->size_align = 8;
|
||||||
conn->security_size = sizeof(struct rxkad_level2_hdr);
|
conn->security_size = sizeof(struct rxkad_level2_hdr);
|
||||||
conn->header_size += sizeof(struct rxkad_level2_hdr);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -EKEYREJECTED;
|
ret = -EKEYREJECTED;
|
||||||
@ -161,7 +159,7 @@ static int rxkad_secure_packet_auth(const struct rxrpc_call *call,
|
|||||||
|
|
||||||
_enter("");
|
_enter("");
|
||||||
|
|
||||||
check = sp->hdr.seq ^ sp->hdr.callNumber;
|
check = sp->hdr.seq ^ call->call_id;
|
||||||
data_size |= (u32)check << 16;
|
data_size |= (u32)check << 16;
|
||||||
|
|
||||||
hdr.data_size = htonl(data_size);
|
hdr.data_size = htonl(data_size);
|
||||||
@ -205,7 +203,7 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
|
|||||||
|
|
||||||
_enter("");
|
_enter("");
|
||||||
|
|
||||||
check = sp->hdr.seq ^ sp->hdr.callNumber;
|
check = sp->hdr.seq ^ call->call_id;
|
||||||
|
|
||||||
rxkhdr.data_size = htonl(data_size | (u32)check << 16);
|
rxkhdr.data_size = htonl(data_size | (u32)check << 16);
|
||||||
rxkhdr.checksum = 0;
|
rxkhdr.checksum = 0;
|
||||||
@ -277,7 +275,7 @@ static int rxkad_secure_packet(struct rxrpc_call *call,
|
|||||||
/* calculate the security checksum */
|
/* calculate the security checksum */
|
||||||
x = (call->cid & RXRPC_CHANNELMASK) << (32 - RXRPC_CIDSHIFT);
|
x = (call->cid & RXRPC_CHANNELMASK) << (32 - RXRPC_CIDSHIFT);
|
||||||
x |= sp->hdr.seq & 0x3fffffff;
|
x |= sp->hdr.seq & 0x3fffffff;
|
||||||
call->crypto_buf[0] = htonl(sp->hdr.callNumber);
|
call->crypto_buf[0] = htonl(call->call_id);
|
||||||
call->crypto_buf[1] = htonl(x);
|
call->crypto_buf[1] = htonl(x);
|
||||||
|
|
||||||
sg_init_one(&sg, call->crypto_buf, 8);
|
sg_init_one(&sg, call->crypto_buf, 8);
|
||||||
|
@ -134,13 +134,11 @@ static void rxrpc_queue_packet(struct rxrpc_call *call, struct sk_buff *skb,
|
|||||||
write_unlock_bh(&call->state_lock);
|
write_unlock_bh(&call->state_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
_proto("Tx DATA %%%u { #%u }", sp->hdr.serial, sp->hdr.seq);
|
|
||||||
|
|
||||||
if (seq == 1 && rxrpc_is_client_call(call))
|
if (seq == 1 && rxrpc_is_client_call(call))
|
||||||
rxrpc_expose_client_call(call);
|
rxrpc_expose_client_call(call);
|
||||||
|
|
||||||
sp->resend_at = jiffies + rxrpc_resend_timeout;
|
sp->resend_at = jiffies + rxrpc_resend_timeout;
|
||||||
ret = rxrpc_send_data_packet(call->conn, skb);
|
ret = rxrpc_send_data_packet(call, skb);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
_debug("need instant resend %d", ret);
|
_debug("need instant resend %d", ret);
|
||||||
rxrpc_instant_resend(call, ix);
|
rxrpc_instant_resend(call, ix);
|
||||||
@ -150,29 +148,6 @@ static void rxrpc_queue_packet(struct rxrpc_call *call, struct sk_buff *skb,
|
|||||||
_leave("");
|
_leave("");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Convert a host-endian header into a network-endian header.
|
|
||||||
*/
|
|
||||||
static void rxrpc_insert_header(struct sk_buff *skb)
|
|
||||||
{
|
|
||||||
struct rxrpc_wire_header whdr;
|
|
||||||
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
|
|
||||||
|
|
||||||
whdr.epoch = htonl(sp->hdr.epoch);
|
|
||||||
whdr.cid = htonl(sp->hdr.cid);
|
|
||||||
whdr.callNumber = htonl(sp->hdr.callNumber);
|
|
||||||
whdr.seq = htonl(sp->hdr.seq);
|
|
||||||
whdr.serial = htonl(sp->hdr.serial);
|
|
||||||
whdr.type = sp->hdr.type;
|
|
||||||
whdr.flags = sp->hdr.flags;
|
|
||||||
whdr.userStatus = sp->hdr.userStatus;
|
|
||||||
whdr.securityIndex = sp->hdr.securityIndex;
|
|
||||||
whdr._rsvd = htons(sp->hdr._rsvd);
|
|
||||||
whdr.serviceId = htons(sp->hdr.serviceId);
|
|
||||||
|
|
||||||
memcpy(skb->head, &whdr, sizeof(whdr));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* send data through a socket
|
* send data through a socket
|
||||||
* - must be called in process context
|
* - must be called in process context
|
||||||
@ -232,7 +207,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
|
|||||||
space = chunk + call->conn->size_align;
|
space = chunk + call->conn->size_align;
|
||||||
space &= ~(call->conn->size_align - 1UL);
|
space &= ~(call->conn->size_align - 1UL);
|
||||||
|
|
||||||
size = space + call->conn->header_size;
|
size = space + call->conn->security_size;
|
||||||
|
|
||||||
_debug("SIZE: %zu/%zu/%zu", chunk, space, size);
|
_debug("SIZE: %zu/%zu/%zu", chunk, space, size);
|
||||||
|
|
||||||
@ -248,9 +223,9 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
|
|||||||
|
|
||||||
ASSERTCMP(skb->mark, ==, 0);
|
ASSERTCMP(skb->mark, ==, 0);
|
||||||
|
|
||||||
_debug("HS: %u", call->conn->header_size);
|
_debug("HS: %u", call->conn->security_size);
|
||||||
skb_reserve(skb, call->conn->header_size);
|
skb_reserve(skb, call->conn->security_size);
|
||||||
skb->len += call->conn->header_size;
|
skb->len += call->conn->security_size;
|
||||||
|
|
||||||
sp = rxrpc_skb(skb);
|
sp = rxrpc_skb(skb);
|
||||||
sp->remain = chunk;
|
sp->remain = chunk;
|
||||||
@ -312,33 +287,23 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
|
|||||||
|
|
||||||
seq = call->tx_top + 1;
|
seq = call->tx_top + 1;
|
||||||
|
|
||||||
sp->hdr.epoch = conn->proto.epoch;
|
|
||||||
sp->hdr.cid = call->cid;
|
|
||||||
sp->hdr.callNumber = call->call_id;
|
|
||||||
sp->hdr.seq = seq;
|
sp->hdr.seq = seq;
|
||||||
sp->hdr.serial = atomic_inc_return(&conn->serial);
|
|
||||||
sp->hdr.type = RXRPC_PACKET_TYPE_DATA;
|
|
||||||
sp->hdr.userStatus = 0;
|
|
||||||
sp->hdr.securityIndex = call->security_ix;
|
|
||||||
sp->hdr._rsvd = 0;
|
sp->hdr._rsvd = 0;
|
||||||
sp->hdr.serviceId = call->service_id;
|
|
||||||
|
|
||||||
sp->hdr.flags = conn->out_clientflag;
|
sp->hdr.flags = conn->out_clientflag;
|
||||||
|
|
||||||
if (msg_data_left(msg) == 0 && !more)
|
if (msg_data_left(msg) == 0 && !more)
|
||||||
sp->hdr.flags |= RXRPC_LAST_PACKET;
|
sp->hdr.flags |= RXRPC_LAST_PACKET;
|
||||||
else if (call->tx_top - call->tx_hard_ack <
|
else if (call->tx_top - call->tx_hard_ack <
|
||||||
call->tx_winsize)
|
call->tx_winsize)
|
||||||
sp->hdr.flags |= RXRPC_MORE_PACKETS;
|
sp->hdr.flags |= RXRPC_MORE_PACKETS;
|
||||||
if (more && seq & 1)
|
if (seq & 1)
|
||||||
sp->hdr.flags |= RXRPC_REQUEST_ACK;
|
sp->hdr.flags |= RXRPC_REQUEST_ACK;
|
||||||
|
|
||||||
ret = conn->security->secure_packet(
|
ret = conn->security->secure_packet(
|
||||||
call, skb, skb->mark,
|
call, skb, skb->mark, skb->head);
|
||||||
skb->head + sizeof(struct rxrpc_wire_header));
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
rxrpc_insert_header(skb);
|
|
||||||
rxrpc_queue_packet(call, skb, !msg_data_left(msg) && !more);
|
rxrpc_queue_packet(call, skb, !msg_data_left(msg) && !more);
|
||||||
skb = NULL;
|
skb = NULL;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user