Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mptcp: optimize out option generation

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 <pabeni@redhat.com>
Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Paolo Abeni and committed by
David S. Miller
1bff1e43 d484dc2b

+121 -109
+120 -109
net/mptcp/options.c
··· 592 592 dss_size = map_size; 593 593 if (skb && snd_data_fin_enable) 594 594 mptcp_write_data_fin(subflow, skb, &opts->ext_copy); 595 + opts->suboptions = OPTION_MPTCP_DSS; 595 596 ret = true; 596 597 } 597 598 ··· 616 615 opts->ext_copy.ack64 = 0; 617 616 } 618 617 opts->ext_copy.use_ack = 1; 618 + opts->suboptions = OPTION_MPTCP_DSS; 619 619 WRITE_ONCE(msk->old_wspace, __mptcp_space((struct sock *)msk)); 620 620 621 621 /* Add kind/length/subtype/flag overhead if mapping is not populated */ ··· 688 686 if (drop_other_suboptions) { 689 687 pr_debug("drop other suboptions"); 690 688 opts->suboptions = 0; 691 - opts->ext_copy.use_ack = 0; 692 - opts->ext_copy.use_map = 0; 689 + 690 + /* note that e.g. DSS could have written into the memory 691 + * aliased by ahmac, we must reset the field here 692 + * to avoid appending the hmac even for ADD_ADDR echo 693 + * options 694 + */ 695 + opts->ahmac = 0; 693 696 *size -= opt_size; 694 697 } 695 698 opts->suboptions |= OPTION_MPTCP_ADD_ADDR; ··· 746 739 { 747 740 struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); 748 741 749 - if (!subflow->send_mp_prio) 742 + /* can't send MP_PRIO with MPC, as they share the same option space: 743 + * 'backup'. Also it makes no sense at all 744 + */ 745 + if (!subflow->send_mp_prio || 746 + ((OPTION_MPTCP_MPC_SYN | OPTION_MPTCP_MPC_SYNACK | 747 + OPTION_MPTCP_MPC_ACK) & opts->suboptions)) 750 748 return false; 751 749 752 750 /* account for the trailing 'nop' option */ ··· 1210 1198 void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp, 1211 1199 struct mptcp_out_options *opts) 1212 1200 { 1213 - if ((OPTION_MPTCP_MPC_SYN | OPTION_MPTCP_MPC_SYNACK | 1214 - OPTION_MPTCP_MPC_ACK) & opts->suboptions) { 1201 + /* RST is mutually exclusive with everything else */ 1202 + if (unlikely(OPTION_MPTCP_RST & opts->suboptions)) { 1203 + *ptr++ = mptcp_option(MPTCPOPT_RST, 1204 + TCPOLEN_MPTCP_RST, 1205 + opts->reset_transient, 1206 + opts->reset_reason); 1207 + return; 1208 + } 1209 + 1210 + /* DSS, MPC, MPJ and ADD_ADDR are mutually exclusive, see 1211 + * mptcp_established_options*() 1212 + */ 1213 + if (likely(OPTION_MPTCP_DSS & opts->suboptions)) { 1214 + struct mptcp_ext *mpext = &opts->ext_copy; 1215 + u8 len = TCPOLEN_MPTCP_DSS_BASE; 1216 + u8 flags = 0; 1217 + 1218 + if (mpext->use_ack) { 1219 + flags = MPTCP_DSS_HAS_ACK; 1220 + if (mpext->ack64) { 1221 + len += TCPOLEN_MPTCP_DSS_ACK64; 1222 + flags |= MPTCP_DSS_ACK64; 1223 + } else { 1224 + len += TCPOLEN_MPTCP_DSS_ACK32; 1225 + } 1226 + } 1227 + 1228 + if (mpext->use_map) { 1229 + len += TCPOLEN_MPTCP_DSS_MAP64; 1230 + 1231 + /* Use only 64-bit mapping flags for now, add 1232 + * support for optional 32-bit mappings later. 1233 + */ 1234 + flags |= MPTCP_DSS_HAS_MAP | MPTCP_DSS_DSN64; 1235 + if (mpext->data_fin) 1236 + flags |= MPTCP_DSS_DATA_FIN; 1237 + 1238 + if (opts->csum_reqd) 1239 + len += TCPOLEN_MPTCP_DSS_CHECKSUM; 1240 + } 1241 + 1242 + *ptr++ = mptcp_option(MPTCPOPT_DSS, len, 0, flags); 1243 + 1244 + if (mpext->use_ack) { 1245 + if (mpext->ack64) { 1246 + put_unaligned_be64(mpext->data_ack, ptr); 1247 + ptr += 2; 1248 + } else { 1249 + put_unaligned_be32(mpext->data_ack32, ptr); 1250 + ptr += 1; 1251 + } 1252 + } 1253 + 1254 + if (mpext->use_map) { 1255 + put_unaligned_be64(mpext->data_seq, ptr); 1256 + ptr += 2; 1257 + put_unaligned_be32(mpext->subflow_seq, ptr); 1258 + ptr += 1; 1259 + if (opts->csum_reqd) { 1260 + put_unaligned_be32(mpext->data_len << 16 | 1261 + mptcp_make_csum(mpext), ptr); 1262 + } else { 1263 + put_unaligned_be32(mpext->data_len << 16 | 1264 + TCPOPT_NOP << 8 | TCPOPT_NOP, ptr); 1265 + } 1266 + } 1267 + } else if ((OPTION_MPTCP_MPC_SYN | OPTION_MPTCP_MPC_SYNACK | 1268 + OPTION_MPTCP_MPC_ACK) & opts->suboptions) { 1215 1269 u8 len, flag = MPTCP_CAP_HMAC_SHA256; 1216 1270 1217 1271 if (OPTION_MPTCP_MPC_SYN & opts->suboptions) { ··· 1324 1246 TCPOPT_NOP << 8 | TCPOPT_NOP, ptr); 1325 1247 } 1326 1248 ptr += 1; 1327 - } 1328 1249 1329 - mp_capable_done: 1330 - if (OPTION_MPTCP_ADD_ADDR & opts->suboptions) { 1250 + /* MPC is additionally mutually exclusive with MP_PRIO */ 1251 + goto mp_capable_done; 1252 + } else if (OPTION_MPTCP_MPJ_SYN & opts->suboptions) { 1253 + *ptr++ = mptcp_option(MPTCPOPT_MP_JOIN, 1254 + TCPOLEN_MPTCP_MPJ_SYN, 1255 + opts->backup, opts->join_id); 1256 + put_unaligned_be32(opts->token, ptr); 1257 + ptr += 1; 1258 + put_unaligned_be32(opts->nonce, ptr); 1259 + ptr += 1; 1260 + } else if (OPTION_MPTCP_MPJ_SYNACK & opts->suboptions) { 1261 + *ptr++ = mptcp_option(MPTCPOPT_MP_JOIN, 1262 + TCPOLEN_MPTCP_MPJ_SYNACK, 1263 + opts->backup, opts->join_id); 1264 + put_unaligned_be64(opts->thmac, ptr); 1265 + ptr += 2; 1266 + put_unaligned_be32(opts->nonce, ptr); 1267 + ptr += 1; 1268 + } else if (OPTION_MPTCP_MPJ_ACK & opts->suboptions) { 1269 + *ptr++ = mptcp_option(MPTCPOPT_MP_JOIN, 1270 + TCPOLEN_MPTCP_MPJ_ACK, 0, 0); 1271 + memcpy(ptr, opts->hmac, MPTCPOPT_HMAC_LEN); 1272 + ptr += 5; 1273 + } else if (OPTION_MPTCP_ADD_ADDR & opts->suboptions) { 1331 1274 u8 len = TCPOLEN_MPTCP_ADD_ADDR_BASE; 1332 1275 u8 echo = MPTCP_ADDR_ECHO; 1333 1276 ··· 1406 1307 } 1407 1308 } 1408 1309 1310 + if (OPTION_MPTCP_PRIO & opts->suboptions) { 1311 + const struct sock *ssk = (const struct sock *)tp; 1312 + struct mptcp_subflow_context *subflow; 1313 + 1314 + subflow = mptcp_subflow_ctx(ssk); 1315 + subflow->send_mp_prio = 0; 1316 + 1317 + *ptr++ = mptcp_option(MPTCPOPT_MP_PRIO, 1318 + TCPOLEN_MPTCP_PRIO, 1319 + opts->backup, TCPOPT_NOP); 1320 + } 1321 + 1322 + mp_capable_done: 1409 1323 if (OPTION_MPTCP_RM_ADDR & opts->suboptions) { 1410 1324 u8 i = 1; 1411 1325 ··· 1436 1324 put_unaligned_be32(id1 << 24 | id2 << 16 | id3 << 8 | id4, ptr); 1437 1325 ptr += 1; 1438 1326 i += 4; 1439 - } 1440 - } 1441 - 1442 - if (OPTION_MPTCP_PRIO & opts->suboptions) { 1443 - const struct sock *ssk = (const struct sock *)tp; 1444 - struct mptcp_subflow_context *subflow; 1445 - 1446 - subflow = mptcp_subflow_ctx(ssk); 1447 - subflow->send_mp_prio = 0; 1448 - 1449 - *ptr++ = mptcp_option(MPTCPOPT_MP_PRIO, 1450 - TCPOLEN_MPTCP_PRIO, 1451 - opts->backup, TCPOPT_NOP); 1452 - } 1453 - 1454 - if (OPTION_MPTCP_MPJ_SYN & opts->suboptions) { 1455 - *ptr++ = mptcp_option(MPTCPOPT_MP_JOIN, 1456 - TCPOLEN_MPTCP_MPJ_SYN, 1457 - opts->backup, opts->join_id); 1458 - put_unaligned_be32(opts->token, ptr); 1459 - ptr += 1; 1460 - put_unaligned_be32(opts->nonce, ptr); 1461 - ptr += 1; 1462 - } 1463 - 1464 - if (OPTION_MPTCP_MPJ_SYNACK & opts->suboptions) { 1465 - *ptr++ = mptcp_option(MPTCPOPT_MP_JOIN, 1466 - TCPOLEN_MPTCP_MPJ_SYNACK, 1467 - opts->backup, opts->join_id); 1468 - put_unaligned_be64(opts->thmac, ptr); 1469 - ptr += 2; 1470 - put_unaligned_be32(opts->nonce, ptr); 1471 - ptr += 1; 1472 - } 1473 - 1474 - if (OPTION_MPTCP_MPJ_ACK & opts->suboptions) { 1475 - *ptr++ = mptcp_option(MPTCPOPT_MP_JOIN, 1476 - TCPOLEN_MPTCP_MPJ_ACK, 0, 0); 1477 - memcpy(ptr, opts->hmac, MPTCPOPT_HMAC_LEN); 1478 - ptr += 5; 1479 - } 1480 - 1481 - if (OPTION_MPTCP_RST & opts->suboptions) 1482 - *ptr++ = mptcp_option(MPTCPOPT_RST, 1483 - TCPOLEN_MPTCP_RST, 1484 - opts->reset_transient, 1485 - opts->reset_reason); 1486 - 1487 - if (opts->ext_copy.use_ack || opts->ext_copy.use_map) { 1488 - struct mptcp_ext *mpext = &opts->ext_copy; 1489 - u8 len = TCPOLEN_MPTCP_DSS_BASE; 1490 - u8 flags = 0; 1491 - 1492 - if (mpext->use_ack) { 1493 - flags = MPTCP_DSS_HAS_ACK; 1494 - if (mpext->ack64) { 1495 - len += TCPOLEN_MPTCP_DSS_ACK64; 1496 - flags |= MPTCP_DSS_ACK64; 1497 - } else { 1498 - len += TCPOLEN_MPTCP_DSS_ACK32; 1499 - } 1500 - } 1501 - 1502 - if (mpext->use_map) { 1503 - len += TCPOLEN_MPTCP_DSS_MAP64; 1504 - 1505 - /* Use only 64-bit mapping flags for now, add 1506 - * support for optional 32-bit mappings later. 1507 - */ 1508 - flags |= MPTCP_DSS_HAS_MAP | MPTCP_DSS_DSN64; 1509 - if (mpext->data_fin) 1510 - flags |= MPTCP_DSS_DATA_FIN; 1511 - 1512 - if (opts->csum_reqd) 1513 - len += TCPOLEN_MPTCP_DSS_CHECKSUM; 1514 - } 1515 - 1516 - *ptr++ = mptcp_option(MPTCPOPT_DSS, len, 0, flags); 1517 - 1518 - if (mpext->use_ack) { 1519 - if (mpext->ack64) { 1520 - put_unaligned_be64(mpext->data_ack, ptr); 1521 - ptr += 2; 1522 - } else { 1523 - put_unaligned_be32(mpext->data_ack32, ptr); 1524 - ptr += 1; 1525 - } 1526 - } 1527 - 1528 - if (mpext->use_map) { 1529 - put_unaligned_be64(mpext->data_seq, ptr); 1530 - ptr += 2; 1531 - put_unaligned_be32(mpext->subflow_seq, ptr); 1532 - ptr += 1; 1533 - if (opts->csum_reqd) { 1534 - put_unaligned_be32(mpext->data_len << 16 | 1535 - mptcp_make_csum(mpext), ptr); 1536 - } else { 1537 - put_unaligned_be32(mpext->data_len << 16 | 1538 - TCPOPT_NOP << 8 | TCPOPT_NOP, ptr); 1539 - } 1540 1327 } 1541 1328 } 1542 1329
+1
net/mptcp/protocol.h
··· 26 26 #define OPTION_MPTCP_FASTCLOSE BIT(8) 27 27 #define OPTION_MPTCP_PRIO BIT(9) 28 28 #define OPTION_MPTCP_RST BIT(10) 29 + #define OPTION_MPTCP_DSS BIT(11) 29 30 30 31 /* MPTCP option subtypes */ 31 32 #define MPTCPOPT_MP_CAPABLE 0