Skip to content

Commit

Permalink
mptcp: optimize out option generation
Browse files Browse the repository at this point in the history
Currently we have several protocol constraints on MPTCP options
generation (e.g. MPC and MPJ subopt are mutually exclusive)
and some additional ones required by our implementation
(e.g. almost all ADD_ADDR variant are mutually exclusive with
everything else).

We can leverage the above to optimize the out option generation:
we check DSS/MPC/MPJ presence in a mutually exclusive way,
avoiding many unneeded conditionals in the common cases.

Additionally extend the existing constraints on ADD_ADDR opt on
all subvariants, so that it becomes fully mutually exclusive with
the above and we can skip another conditional statement for the
common case.

This change is also needed by the next patch.

Signed-off-by: Paolo Abeni <[email protected]>
Signed-off-by: Mat Martineau <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Paolo Abeni authored and davem330 committed Aug 25, 2021
1 parent d484dc2 commit 1bff1e4
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 109 deletions.
229 changes: 120 additions & 109 deletions net/mptcp/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,7 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
dss_size = map_size;
if (skb && snd_data_fin_enable)
mptcp_write_data_fin(subflow, skb, &opts->ext_copy);
opts->suboptions = OPTION_MPTCP_DSS;
ret = true;
}

Expand All @@ -615,6 +616,7 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
opts->ext_copy.ack64 = 0;
}
opts->ext_copy.use_ack = 1;
opts->suboptions = OPTION_MPTCP_DSS;
WRITE_ONCE(msk->old_wspace, __mptcp_space((struct sock *)msk));

/* Add kind/length/subtype/flag overhead if mapping is not populated */
Expand Down Expand Up @@ -686,8 +688,13 @@ static bool mptcp_established_options_add_addr(struct sock *sk, struct sk_buff *
if (drop_other_suboptions) {
pr_debug("drop other suboptions");
opts->suboptions = 0;
opts->ext_copy.use_ack = 0;
opts->ext_copy.use_map = 0;

/* note that e.g. DSS could have written into the memory
* aliased by ahmac, we must reset the field here
* to avoid appending the hmac even for ADD_ADDR echo
* options
*/
opts->ahmac = 0;
*size -= opt_size;
}
opts->suboptions |= OPTION_MPTCP_ADD_ADDR;
Expand Down Expand Up @@ -739,7 +746,12 @@ static bool mptcp_established_options_mp_prio(struct sock *sk,
{
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);

if (!subflow->send_mp_prio)
/* can't send MP_PRIO with MPC, as they share the same option space:
* 'backup'. Also it makes no sense at all
*/
if (!subflow->send_mp_prio ||
((OPTION_MPTCP_MPC_SYN | OPTION_MPTCP_MPC_SYNACK |
OPTION_MPTCP_MPC_ACK) & opts->suboptions))
return false;

/* account for the trailing 'nop' option */
Expand Down Expand Up @@ -1198,8 +1210,74 @@ static u16 mptcp_make_csum(const struct mptcp_ext *mpext)
void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp,
struct mptcp_out_options *opts)
{
if ((OPTION_MPTCP_MPC_SYN | OPTION_MPTCP_MPC_SYNACK |
OPTION_MPTCP_MPC_ACK) & opts->suboptions) {
/* RST is mutually exclusive with everything else */
if (unlikely(OPTION_MPTCP_RST & opts->suboptions)) {
*ptr++ = mptcp_option(MPTCPOPT_RST,
TCPOLEN_MPTCP_RST,
opts->reset_transient,
opts->reset_reason);
return;
}

/* DSS, MPC, MPJ and ADD_ADDR are mutually exclusive, see
* mptcp_established_options*()
*/
if (likely(OPTION_MPTCP_DSS & opts->suboptions)) {
struct mptcp_ext *mpext = &opts->ext_copy;
u8 len = TCPOLEN_MPTCP_DSS_BASE;
u8 flags = 0;

if (mpext->use_ack) {
flags = MPTCP_DSS_HAS_ACK;
if (mpext->ack64) {
len += TCPOLEN_MPTCP_DSS_ACK64;
flags |= MPTCP_DSS_ACK64;
} else {
len += TCPOLEN_MPTCP_DSS_ACK32;
}
}

if (mpext->use_map) {
len += TCPOLEN_MPTCP_DSS_MAP64;

/* Use only 64-bit mapping flags for now, add
* support for optional 32-bit mappings later.
*/
flags |= MPTCP_DSS_HAS_MAP | MPTCP_DSS_DSN64;
if (mpext->data_fin)
flags |= MPTCP_DSS_DATA_FIN;

if (opts->csum_reqd)
len += TCPOLEN_MPTCP_DSS_CHECKSUM;
}

*ptr++ = mptcp_option(MPTCPOPT_DSS, len, 0, flags);

if (mpext->use_ack) {
if (mpext->ack64) {
put_unaligned_be64(mpext->data_ack, ptr);
ptr += 2;
} else {
put_unaligned_be32(mpext->data_ack32, ptr);
ptr += 1;
}
}

if (mpext->use_map) {
put_unaligned_be64(mpext->data_seq, ptr);
ptr += 2;
put_unaligned_be32(mpext->subflow_seq, ptr);
ptr += 1;
if (opts->csum_reqd) {
put_unaligned_be32(mpext->data_len << 16 |
mptcp_make_csum(mpext), ptr);
} else {
put_unaligned_be32(mpext->data_len << 16 |
TCPOPT_NOP << 8 | TCPOPT_NOP, ptr);
}
}
} else if ((OPTION_MPTCP_MPC_SYN | OPTION_MPTCP_MPC_SYNACK |
OPTION_MPTCP_MPC_ACK) & opts->suboptions) {
u8 len, flag = MPTCP_CAP_HMAC_SHA256;

if (OPTION_MPTCP_MPC_SYN & opts->suboptions) {
Expand Down Expand Up @@ -1246,10 +1324,31 @@ void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp,
TCPOPT_NOP << 8 | TCPOPT_NOP, ptr);
}
ptr += 1;
}

mp_capable_done:
if (OPTION_MPTCP_ADD_ADDR & opts->suboptions) {
/* MPC is additionally mutually exclusive with MP_PRIO */
goto mp_capable_done;
} else if (OPTION_MPTCP_MPJ_SYN & opts->suboptions) {
*ptr++ = mptcp_option(MPTCPOPT_MP_JOIN,
TCPOLEN_MPTCP_MPJ_SYN,
opts->backup, opts->join_id);
put_unaligned_be32(opts->token, ptr);
ptr += 1;
put_unaligned_be32(opts->nonce, ptr);
ptr += 1;
} else if (OPTION_MPTCP_MPJ_SYNACK & opts->suboptions) {
*ptr++ = mptcp_option(MPTCPOPT_MP_JOIN,
TCPOLEN_MPTCP_MPJ_SYNACK,
opts->backup, opts->join_id);
put_unaligned_be64(opts->thmac, ptr);
ptr += 2;
put_unaligned_be32(opts->nonce, ptr);
ptr += 1;
} else if (OPTION_MPTCP_MPJ_ACK & opts->suboptions) {
*ptr++ = mptcp_option(MPTCPOPT_MP_JOIN,
TCPOLEN_MPTCP_MPJ_ACK, 0, 0);
memcpy(ptr, opts->hmac, MPTCPOPT_HMAC_LEN);
ptr += 5;
} else if (OPTION_MPTCP_ADD_ADDR & opts->suboptions) {
u8 len = TCPOLEN_MPTCP_ADD_ADDR_BASE;
u8 echo = MPTCP_ADDR_ECHO;

Expand Down Expand Up @@ -1307,6 +1406,19 @@ void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp,
}
}

if (OPTION_MPTCP_PRIO & opts->suboptions) {
const struct sock *ssk = (const struct sock *)tp;
struct mptcp_subflow_context *subflow;

subflow = mptcp_subflow_ctx(ssk);
subflow->send_mp_prio = 0;

*ptr++ = mptcp_option(MPTCPOPT_MP_PRIO,
TCPOLEN_MPTCP_PRIO,
opts->backup, TCPOPT_NOP);
}

mp_capable_done:
if (OPTION_MPTCP_RM_ADDR & opts->suboptions) {
u8 i = 1;

Expand All @@ -1327,107 +1439,6 @@ void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp,
}
}

if (OPTION_MPTCP_PRIO & opts->suboptions) {
const struct sock *ssk = (const struct sock *)tp;
struct mptcp_subflow_context *subflow;

subflow = mptcp_subflow_ctx(ssk);
subflow->send_mp_prio = 0;

*ptr++ = mptcp_option(MPTCPOPT_MP_PRIO,
TCPOLEN_MPTCP_PRIO,
opts->backup, TCPOPT_NOP);
}

if (OPTION_MPTCP_MPJ_SYN & opts->suboptions) {
*ptr++ = mptcp_option(MPTCPOPT_MP_JOIN,
TCPOLEN_MPTCP_MPJ_SYN,
opts->backup, opts->join_id);
put_unaligned_be32(opts->token, ptr);
ptr += 1;
put_unaligned_be32(opts->nonce, ptr);
ptr += 1;
}

if (OPTION_MPTCP_MPJ_SYNACK & opts->suboptions) {
*ptr++ = mptcp_option(MPTCPOPT_MP_JOIN,
TCPOLEN_MPTCP_MPJ_SYNACK,
opts->backup, opts->join_id);
put_unaligned_be64(opts->thmac, ptr);
ptr += 2;
put_unaligned_be32(opts->nonce, ptr);
ptr += 1;
}

if (OPTION_MPTCP_MPJ_ACK & opts->suboptions) {
*ptr++ = mptcp_option(MPTCPOPT_MP_JOIN,
TCPOLEN_MPTCP_MPJ_ACK, 0, 0);
memcpy(ptr, opts->hmac, MPTCPOPT_HMAC_LEN);
ptr += 5;
}

if (OPTION_MPTCP_RST & opts->suboptions)
*ptr++ = mptcp_option(MPTCPOPT_RST,
TCPOLEN_MPTCP_RST,
opts->reset_transient,
opts->reset_reason);

if (opts->ext_copy.use_ack || opts->ext_copy.use_map) {
struct mptcp_ext *mpext = &opts->ext_copy;
u8 len = TCPOLEN_MPTCP_DSS_BASE;
u8 flags = 0;

if (mpext->use_ack) {
flags = MPTCP_DSS_HAS_ACK;
if (mpext->ack64) {
len += TCPOLEN_MPTCP_DSS_ACK64;
flags |= MPTCP_DSS_ACK64;
} else {
len += TCPOLEN_MPTCP_DSS_ACK32;
}
}

if (mpext->use_map) {
len += TCPOLEN_MPTCP_DSS_MAP64;

/* Use only 64-bit mapping flags for now, add
* support for optional 32-bit mappings later.
*/
flags |= MPTCP_DSS_HAS_MAP | MPTCP_DSS_DSN64;
if (mpext->data_fin)
flags |= MPTCP_DSS_DATA_FIN;

if (opts->csum_reqd)
len += TCPOLEN_MPTCP_DSS_CHECKSUM;
}

*ptr++ = mptcp_option(MPTCPOPT_DSS, len, 0, flags);

if (mpext->use_ack) {
if (mpext->ack64) {
put_unaligned_be64(mpext->data_ack, ptr);
ptr += 2;
} else {
put_unaligned_be32(mpext->data_ack32, ptr);
ptr += 1;
}
}

if (mpext->use_map) {
put_unaligned_be64(mpext->data_seq, ptr);
ptr += 2;
put_unaligned_be32(mpext->subflow_seq, ptr);
ptr += 1;
if (opts->csum_reqd) {
put_unaligned_be32(mpext->data_len << 16 |
mptcp_make_csum(mpext), ptr);
} else {
put_unaligned_be32(mpext->data_len << 16 |
TCPOPT_NOP << 8 | TCPOPT_NOP, ptr);
}
}
}

if (tp)
mptcp_set_rwin(tp);
}
Expand Down
1 change: 1 addition & 0 deletions net/mptcp/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#define OPTION_MPTCP_FASTCLOSE BIT(8)
#define OPTION_MPTCP_PRIO BIT(9)
#define OPTION_MPTCP_RST BIT(10)
#define OPTION_MPTCP_DSS BIT(11)

/* MPTCP option subtypes */
#define MPTCPOPT_MP_CAPABLE 0
Expand Down

0 comments on commit 1bff1e4

Please sign in to comment.