diff --git a/src/h2load.cc b/src/h2load.cc index 2b3f529b..4b479723 100644 --- a/src/h2load.cc +++ b/src/h2load.cc @@ -124,7 +124,8 @@ Config::Config() base_uri_unix(false), unix_addr{}, rps(0.), - no_udp_gso(false) {} + no_udp_gso(false), + max_udp_payload_size(0) {} Config::~Config() { if (addrs) { @@ -2247,6 +2248,8 @@ Options: << config.groups << R"( --no-udp-gso Disable UDP GSO. + --max-udp-payload-size= + Specify the maximum outgoing UDP datagram payload size. -v, --verbose Output debug information. --version Display version information and exit. @@ -2312,6 +2315,7 @@ int main(int argc, char **argv) { {"tls13-ciphers", required_argument, &flag, 14}, {"no-udp-gso", no_argument, &flag, 15}, {"qlog-file-base", required_argument, &flag, 16}, + {"max-udp-payload-size", required_argument, &flag, 17}, {nullptr, 0, nullptr, 0}}; int option_index = 0; auto c = getopt_long(argc, argv, @@ -2578,6 +2582,22 @@ int main(int argc, char **argv) { // --qlog-file-base qlog_base = optarg; break; + case 17: { + // --max-udp-payload-size + auto n = util::parse_uint_with_unit(optarg); + if (n == -1) { + std::cerr << "--max-udp-payload-size: bad option value: " << optarg + << std::endl; + exit(EXIT_FAILURE); + } + if (n > 64_k) { + std::cerr << "--max-udp-payload-size: must not exceed 65536" + << std::endl; + exit(EXIT_FAILURE); + } + config.max_udp_payload_size = n; + break; + } } break; default: diff --git a/src/h2load.h b/src/h2load.h index 92c0e2ac..895fb8eb 100644 --- a/src/h2load.h +++ b/src/h2load.h @@ -133,6 +133,8 @@ struct Config { double rps; // Disables GSO for UDP connections. bool no_udp_gso; + // The maximum UDP datagram payload size to send. + size_t max_udp_payload_size; Config(); ~Config(); @@ -336,7 +338,6 @@ struct Client { ev_timer pkt_timer; ngtcp2_conn *conn; quic::Error last_error; - size_t max_pktlen; bool close_requested; FILE *qlog_file; } quic; diff --git a/src/h2load_quic.cc b/src/h2load_quic.cc index 70610156..fd979cbf 100644 --- a/src/h2load_quic.cc +++ b/src/h2load_quic.cc @@ -305,8 +305,6 @@ int Client::quic_init(const sockaddr *local_addr, socklen_t local_addrlen, SSL_set_quic_use_legacy_codepoint(ssl, 0); } - quic.max_pktlen = NGTCP2_MAX_UDP_PAYLOAD_SIZE; - auto callbacks = ngtcp2_callbacks{ ngtcp2_crypto_client_initial_cb, nullptr, // recv_client_initial @@ -373,6 +371,10 @@ int Client::quic_init(const sockaddr *local_addr, socklen_t local_addrlen, } settings.qlog.write = qlog_write_cb; } + if (config->max_udp_payload_size) { + settings.max_udp_payload_size = config->max_udp_payload_size; + settings.no_udp_payload_size_shaping = 1; + } ngtcp2_transport_params params; ngtcp2_transport_params_default(¶ms); @@ -424,7 +426,7 @@ void Client::quic_close_connection() { return; } - std::array buf; + std::array buf; ngtcp2_ssize nwrite; ngtcp2_path_storage ps; ngtcp2_path_storage_zero(&ps); @@ -434,12 +436,12 @@ void Client::quic_close_connection() { return; case quic::ErrorType::Transport: nwrite = ngtcp2_conn_write_connection_close( - quic.conn, &ps.path, nullptr, buf.data(), quic.max_pktlen, + quic.conn, &ps.path, nullptr, buf.data(), buf.size(), quic.last_error.code, timestamp(worker->loop)); break; case quic::ErrorType::Application: nwrite = ngtcp2_conn_write_application_close( - quic.conn, &ps.path, nullptr, buf.data(), quic.max_pktlen, + quic.conn, &ps.path, nullptr, buf.data(), buf.size(), quic.last_error.code, timestamp(worker->loop)); break; default: @@ -575,12 +577,14 @@ int Client::write_quic() { std::array vec; size_t pktcnt = 0; + auto max_udp_payload_size = + ngtcp2_conn_get_path_max_udp_payload_size(quic.conn); size_t max_pktcnt = #ifdef UDP_SEGMENT worker->config->no_udp_gso ? 1 : std::min(static_cast(10), - static_cast(64_k / quic.max_pktlen)); + static_cast(64_k / max_udp_payload_size)); #else // !UDP_SEGMENT 1; #endif // !UDP_SEGMENT @@ -614,8 +618,8 @@ int Client::write_quic() { } auto nwrite = ngtcp2_conn_writev_stream( - quic.conn, &ps.path, nullptr, bufpos, quic.max_pktlen, &ndatalen, flags, - stream_id, reinterpret_cast(v), vcnt, + quic.conn, &ps.path, nullptr, bufpos, max_udp_payload_size, &ndatalen, + flags, stream_id, reinterpret_cast(v), vcnt, timestamp(worker->loop)); if (nwrite < 0) { switch (nwrite) { @@ -650,7 +654,7 @@ int Client::write_quic() { if (nwrite == 0) { if (bufpos - buf.data()) { write_udp(ps.path.remote.addr, ps.path.remote.addrlen, buf.data(), - bufpos - buf.data(), quic.max_pktlen); + bufpos - buf.data(), max_udp_payload_size); } return 0; } @@ -659,9 +663,9 @@ int Client::write_quic() { // Assume that the path does not change. if (++pktcnt == max_pktcnt || - static_cast(nwrite) < quic.max_pktlen) { + static_cast(nwrite) < max_udp_payload_size) { write_udp(ps.path.remote.addr, ps.path.remote.addrlen, buf.data(), - bufpos - buf.data(), quic.max_pktlen); + bufpos - buf.data(), max_udp_payload_size); signal_write(); return 0; }