Skip to content

Commit b4bf245

Browse files
Stuart Clarkmeta-codesync[bot]
authored andcommitted
AF_XDP/XSK UDP client transport (fleet-safe re-land)
Summary: Re-land of the AF_XDP/XSK UDP client transport for the ucache fast path (originally D109703046), now with a fix for the fleet-wide breakage that forced the backout (D110310180, see T277941128). What this adds: the `mc_xdp_protocol` transport plumbing — `XdpTransport` (single-threaded, per-EVB, AsyncUDPSocket-based, fiber/baton reply demux under `facebook/`), the `xdp` protocol enum + parse cases, the `xdp_tx_truncate_bytes` mcrouter option, and the `McRouteHandleProvider` wiring. Why the first version broke the fleet: `McRouteHandleProvider` (linked by nearly everything via memcache/ServiceRouter) instantiates `createDestinationRoute<XdpTransport>`, which pulls in `UdpWireFormat.h`. That single header unconditionally included the generated TAO and Ucache carbon message codegen, so via `mcrouter-core -> xdp_transport -> udp_wire_format -> carbon-Ucache-messages` every mcrouter dependent was forced to build the Ucache protocol codegen. Ucache protocol sits architecturally above mcrouter, so this dragged a heavy, effectively-cyclic subtree into the fleet and broke 100+ unrelated targets. (TAO codegen was already reachable fleet-wide via `carbon-Memcache-messages`, so it was not part of the regression; the new fleet edge was `carbon-Ucache-messages`.) The fix: split `UdpWireFormat.h` by protocol family. The core header keeps framing, the `MessageType` enum, the generic `serializeWithId`/`deserializeWithId`/`peek` helpers, and the Memcache `MessageTypeTag` specialisations (Memcache is the only family reachable through the universal `MemcacheRouterInfo` path). The TAO and Ucache tags move to `UdpWireFormatTao.h` / `UdpWireFormatUcache.h` behind their own `udp_wire_format_tao` / `udp_wire_format_ucache` targets, taken only by consumers that actually (de)serialise those families (the ucache XSK server). No ODR risk: each type tag is defined in exactly one header. Net effect: `mcrouter-core -> xdp_transport -> udp_wire_format` adds zero new codegen to mcrouter dependents. Reviewed By: lenar-f Differential Revision: D110316229 fbshipit-source-id: 533b603b4c57c4a5330340424b2e0b1a388eec7f
1 parent 852eee7 commit b4bf245

7 files changed

Lines changed: 49 additions & 0 deletions

File tree

mcrouter/ProxyDestination-inl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ void ProxyDestination<Transport>::initializeTransport() {
303303
options.qosPath = qosPath();
304304
}
305305
options.useJemallocNodumpAllocator = opts.jemalloc_nodump_buffers;
306+
options.xdpTxTruncateBytes = opts.xdp_tx_truncate_bytes;
306307
if (accessPoint()->compressed()) {
307308
if (auto codecManager = proxy().router().getCodecManager()) {
308309
options.compressionCodecMap =

mcrouter/lib/mc/protocol.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ typedef enum mc_protocol_e {
1919
mc_binary_protocol = 2,
2020
mc_caret_protocol = 4,
2121
mc_thrift_protocol = 5,
22+
mc_xdp_protocol = 6,
2223
mc_nprotocols, // placeholder
2324
} mc_protocol_t;
2425

@@ -31,6 +32,8 @@ static inline mc_protocol_t mc_string_to_protocol(const char* str) {
3132
return mc_caret_protocol;
3233
} else if (!strcmp(str, "thrift")) {
3334
return mc_thrift_protocol;
35+
} else if (!strcmp(str, "xdp")) {
36+
return mc_xdp_protocol;
3437
} else {
3538
return mc_unknown_protocol;
3639
}
@@ -46,6 +49,8 @@ static inline const char* mc_protocol_to_string(const mc_protocol_t value) {
4649
return "caret";
4750
case mc_thrift_protocol:
4851
return "thrift";
52+
case mc_xdp_protocol:
53+
return "xdp";
4954
case mc_unknown_protocol:
5055
case mc_nprotocols:
5156
default:

mcrouter/lib/network/AccessPoint.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ mc_protocol_t parseProtocol(folly::StringPiece str) {
5959
return mc_caret_protocol;
6060
} else if (str == "thrift") {
6161
return mc_thrift_protocol;
62+
} else if (str == "xdp") {
63+
return mc_xdp_protocol;
6264
}
6365
throw std::runtime_error("Invalid protocol");
6466
}

mcrouter/lib/network/ConnectionOptions.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,13 @@ struct ConnectionOptions {
146146
* iff thriftCompression is enabled.
147147
*/
148148
size_t thriftCompressionThreshold{0};
149+
150+
/**
151+
* AF_XDP/XSK client: max request datagram payload in bytes before the
152+
* request is rejected with LOCAL_ERROR. 0 means no cap (clamp to the jumbo
153+
* buffer size). Plumbed from the xdp_tx_truncate_bytes mcrouter option.
154+
*/
155+
size_t xdpTxTruncateBytes{0};
149156
};
150157
} // namespace memcache
151158
} // namespace facebook

mcrouter/mcrouter_options_list.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,16 @@ MCROUTER_OPTION_INTEGER(
881881
"Payloads >= thriftCompressionTreshold will be compressed "
882882
"iff thriftCompression is enabled.")
883883

884+
MCROUTER_OPTION_INTEGER(
885+
size_t,
886+
xdp_tx_truncate_bytes,
887+
3072,
888+
"xdp-tx-truncate-bytes",
889+
no_short,
890+
"AF_XDP/XSK client: max request datagram payload in bytes before the "
891+
"request is rejected with LOCAL_ERROR. 0 means no cap (clamp to the jumbo "
892+
"buffer size). Default 3072 (3K).")
893+
884894
MCROUTER_OPTION_TOGGLE(
885895
enable_axonlog,
886896
false,

mcrouter/routes/McRouteHandleProvider-inl.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
#include "mcrouter/lib/network/FailureDomains.h"
2929
#include "mcrouter/lib/network/SecurityOptions.h"
3030
#include "mcrouter/lib/network/ThriftTransport.h"
31+
#if defined(__linux__) && !defined(ANDROID) && !defined(MCROUTER_OSS_BUILD)
32+
#include "mcrouter/lib/network/facebook/XdpTransport.h"
33+
#endif
3134
#include "mcrouter/lib/network/gen/MemcacheRouterInfo.h"
3235
#include "mcrouter/routes/AllFastestRouteFactory.h"
3336
#include "mcrouter/routes/AsynclogRoute.h"
@@ -405,6 +408,25 @@ McRouteHandleProvider<RouterInfo>::makePool(
405408
idx);
406409
accessPointsSet.insert(destResult.second);
407410
addDestination(std::move(destResult.first));
411+
#if defined(__linux__) && !defined(ANDROID) && !defined(MCROUTER_OSS_BUILD)
412+
} else if (ap->getProtocol() == mc_xdp_protocol) {
413+
using Transport = XdpTransport;
414+
auto destResult = createDestinationRoute<Transport>(
415+
std::move(ap),
416+
timeout,
417+
connectTimeout,
418+
qosClass,
419+
qosPath,
420+
nameSp,
421+
i,
422+
poolStatIndex,
423+
disableRequestDeadlineCheck,
424+
poolTkoTracker,
425+
keepRoutingPrefix,
426+
idx);
427+
accessPointsSet.insert(destResult.second);
428+
addDestination(std::move(destResult.first));
429+
#endif
408430
} else {
409431
using Transport = AsyncMcClient;
410432
auto destResult = createDestinationRoute<Transport>(

mcrouter/routes/McRouteHandleProvider.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ std::shared_ptr<CommonAccessPointAttributes> getCommonAccessPointAttributes(
7979
protocol = mc_caret_protocol;
8080
} else if (equalStr("thrift", str, folly::AsciiCaseInsensitive())) {
8181
protocol = mc_thrift_protocol;
82+
} else if (equalStr("xdp", str, folly::AsciiCaseInsensitive())) {
83+
protocol = mc_xdp_protocol;
8284
} else {
8385
throwLogic("Unknown protocol '{}'", str);
8486
}

0 commit comments

Comments
 (0)