QUIC UDP GSO
This commit is contained in:
parent
eb1607890a
commit
a37117a98b
|
@ -35,6 +35,7 @@
|
||||||
# include <fcntl.h>
|
# include <fcntl.h>
|
||||||
#endif // HAVE_FCNTL_H
|
#endif // HAVE_FCNTL_H
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
#include <netinet/udp.h>
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
@ -117,7 +118,8 @@ Config::Config()
|
||||||
timing_script(false),
|
timing_script(false),
|
||||||
base_uri_unix(false),
|
base_uri_unix(false),
|
||||||
unix_addr{},
|
unix_addr{},
|
||||||
rps(0.) {}
|
rps(0.),
|
||||||
|
no_udp_gso(false) {}
|
||||||
|
|
||||||
Config::~Config() {
|
Config::~Config() {
|
||||||
if (addrs) {
|
if (addrs) {
|
||||||
|
@ -1375,8 +1377,32 @@ int Client::write_tls() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int Client::write_udp(const sockaddr *addr, socklen_t addrlen,
|
int Client::write_udp(const sockaddr *addr, socklen_t addrlen,
|
||||||
const uint8_t *data, size_t datalen) {
|
const uint8_t *data, size_t datalen, size_t gso_size) {
|
||||||
auto nwrite = sendto(fd, data, datalen, MSG_DONTWAIT, addr, addrlen);
|
iovec msg_iov;
|
||||||
|
msg_iov.iov_base = const_cast<uint8_t *>(data);
|
||||||
|
msg_iov.iov_len = datalen;
|
||||||
|
|
||||||
|
msghdr msg{};
|
||||||
|
msg.msg_name = const_cast<sockaddr *>(addr);
|
||||||
|
msg.msg_namelen = addrlen;
|
||||||
|
msg.msg_iov = &msg_iov;
|
||||||
|
msg.msg_iovlen = 1;
|
||||||
|
|
||||||
|
#ifdef UDP_SEGMENT
|
||||||
|
std::array<uint8_t, CMSG_SPACE(sizeof(uint16_t))> msg_ctrl{};
|
||||||
|
if (gso_size && datalen > gso_size) {
|
||||||
|
msg.msg_control = msg_ctrl.data();
|
||||||
|
msg.msg_controllen = msg_ctrl.size();
|
||||||
|
|
||||||
|
auto cm = CMSG_FIRSTHDR(&msg);
|
||||||
|
cm->cmsg_level = SOL_UDP;
|
||||||
|
cm->cmsg_type = UDP_SEGMENT;
|
||||||
|
cm->cmsg_len = CMSG_LEN(sizeof(uint16_t));
|
||||||
|
*(reinterpret_cast<uint16_t *>(CMSG_DATA(cm))) = gso_size;
|
||||||
|
}
|
||||||
|
#endif // UDP_SEGMENT
|
||||||
|
|
||||||
|
auto nwrite = sendmsg(fd, &msg, 0);
|
||||||
if (nwrite < 0) {
|
if (nwrite < 0) {
|
||||||
std::cerr << "sendto: errno=" << errno << std::endl;
|
std::cerr << "sendto: errno=" << errno << std::endl;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2183,6 +2209,8 @@ Options:
|
||||||
Specify the supported groups.
|
Specify the supported groups.
|
||||||
Default: )"
|
Default: )"
|
||||||
<< config.groups << R"(
|
<< config.groups << R"(
|
||||||
|
--no-udp-gso
|
||||||
|
Disable UDP GSO.
|
||||||
-v, --verbose
|
-v, --verbose
|
||||||
Output debug information.
|
Output debug information.
|
||||||
--version Display version information and exit.
|
--version Display version information and exit.
|
||||||
|
@ -2245,6 +2273,7 @@ int main(int argc, char **argv) {
|
||||||
{"rps", required_argument, &flag, 12},
|
{"rps", required_argument, &flag, 12},
|
||||||
{"groups", required_argument, &flag, 13},
|
{"groups", required_argument, &flag, 13},
|
||||||
{"tls13-ciphers", required_argument, &flag, 14},
|
{"tls13-ciphers", required_argument, &flag, 14},
|
||||||
|
{"no-udp-gso", no_argument, &flag, 15},
|
||||||
{nullptr, 0, nullptr, 0}};
|
{nullptr, 0, nullptr, 0}};
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
auto c = getopt_long(argc, argv,
|
auto c = getopt_long(argc, argv,
|
||||||
|
@ -2503,6 +2532,10 @@ int main(int argc, char **argv) {
|
||||||
// --tls13-ciphers
|
// --tls13-ciphers
|
||||||
config.tls13_ciphers = optarg;
|
config.tls13_ciphers = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 15:
|
||||||
|
// --no-udp-gso
|
||||||
|
config.no_udp_gso = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -125,6 +125,8 @@ struct Config {
|
||||||
std::vector<std::string> npn_list;
|
std::vector<std::string> npn_list;
|
||||||
// The number of request per second for each client.
|
// The number of request per second for each client.
|
||||||
double rps;
|
double rps;
|
||||||
|
// Disables GSO for UDP connections.
|
||||||
|
bool no_udp_gso;
|
||||||
|
|
||||||
Config();
|
Config();
|
||||||
~Config();
|
~Config();
|
||||||
|
@ -458,7 +460,7 @@ struct Client {
|
||||||
int read_quic();
|
int read_quic();
|
||||||
int write_quic();
|
int write_quic();
|
||||||
int write_udp(const sockaddr *addr, socklen_t addrlen, const uint8_t *data,
|
int write_udp(const sockaddr *addr, socklen_t addrlen, const uint8_t *data,
|
||||||
size_t datalen);
|
size_t datalen, size_t gso_size);
|
||||||
void quic_close_connection();
|
void quic_close_connection();
|
||||||
|
|
||||||
int quic_recv_crypto_data(ngtcp2_crypto_level crypto_level,
|
int quic_recv_crypto_data(ngtcp2_crypto_level crypto_level,
|
||||||
|
|
|
@ -402,6 +402,15 @@ int Http3Session::block_stream(int64_t stream_id) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Http3Session::shutdown_stream_write(int64_t stream_id) {
|
||||||
|
auto rv = nghttp3_conn_shutdown_stream_write(conn_, stream_id);
|
||||||
|
if (rv != 0) {
|
||||||
|
client_->quic.last_error = quic::err_application(rv);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int Http3Session::add_write_offset(int64_t stream_id, size_t ndatalen) {
|
int Http3Session::add_write_offset(int64_t stream_id, size_t ndatalen) {
|
||||||
auto rv = nghttp3_conn_add_write_offset(conn_, stream_id, ndatalen);
|
auto rv = nghttp3_conn_add_write_offset(conn_, stream_id, ndatalen);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
|
|
|
@ -63,6 +63,7 @@ public:
|
||||||
ssize_t write_stream(int64_t &stream_id, int &fin, nghttp3_vec *vec,
|
ssize_t write_stream(int64_t &stream_id, int &fin, nghttp3_vec *vec,
|
||||||
size_t veccnt);
|
size_t veccnt);
|
||||||
int block_stream(int64_t stream_id);
|
int block_stream(int64_t stream_id);
|
||||||
|
int shutdown_stream_write(int64_t stream_id);
|
||||||
int add_write_offset(int64_t stream_id, size_t ndatalen);
|
int add_write_offset(int64_t stream_id, size_t ndatalen);
|
||||||
int add_ack_offset(int64_t stream_id, size_t datalen);
|
int add_ack_offset(int64_t stream_id, size_t datalen);
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
*/
|
*/
|
||||||
#include "h2load_quic.h"
|
#include "h2load_quic.h"
|
||||||
|
|
||||||
|
#include <netinet/udp.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <ngtcp2/ngtcp2_crypto_openssl.h>
|
#include <ngtcp2/ngtcp2_crypto_openssl.h>
|
||||||
|
@ -425,7 +427,7 @@ void Client::quic_close_connection() {
|
||||||
}
|
}
|
||||||
|
|
||||||
write_udp(reinterpret_cast<sockaddr *>(ps.path.remote.addr),
|
write_udp(reinterpret_cast<sockaddr *>(ps.path.remote.addr),
|
||||||
ps.path.remote.addrlen, buf.data(), nwrite);
|
ps.path.remote.addrlen, buf.data(), nwrite, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Client::quic_on_key(ngtcp2_crypto_level level, const uint8_t *rx_secret,
|
int Client::quic_on_key(ngtcp2_crypto_level level, const uint8_t *rx_secret,
|
||||||
|
@ -554,7 +556,18 @@ int Client::write_quic() {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<nghttp3_vec, 16> vec;
|
std::array<nghttp3_vec, 16> vec;
|
||||||
std::array<uint8_t, 1500> buf;
|
size_t pktcnt = 0;
|
||||||
|
size_t max_pktcnt =
|
||||||
|
#ifdef UDP_SEGMENT
|
||||||
|
worker->config->no_udp_gso
|
||||||
|
? 1
|
||||||
|
: std::min(static_cast<size_t>(10),
|
||||||
|
static_cast<size_t>(64_k / quic.max_pktlen));
|
||||||
|
#else // !UDP_SEGMENT
|
||||||
|
1;
|
||||||
|
#endif // !UDP_SEGMENT
|
||||||
|
std::array<uint8_t, 64_k> buf;
|
||||||
|
uint8_t *bufpos = buf.data();
|
||||||
ngtcp2_path_storage ps;
|
ngtcp2_path_storage ps;
|
||||||
|
|
||||||
ngtcp2_path_storage_zero(&ps);
|
ngtcp2_path_storage_zero(&ps);
|
||||||
|
@ -583,16 +596,20 @@ int Client::write_quic() {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto nwrite = ngtcp2_conn_writev_stream(
|
auto nwrite = ngtcp2_conn_writev_stream(
|
||||||
quic.conn, &ps.path, nullptr, buf.data(), quic.max_pktlen, &ndatalen,
|
quic.conn, &ps.path, nullptr, bufpos, quic.max_pktlen, &ndatalen, flags,
|
||||||
flags, stream_id, reinterpret_cast<const ngtcp2_vec *>(v), vcnt,
|
stream_id, reinterpret_cast<const ngtcp2_vec *>(v), vcnt,
|
||||||
timestamp(worker->loop));
|
timestamp(worker->loop));
|
||||||
if (nwrite < 0) {
|
if (nwrite < 0) {
|
||||||
switch (nwrite) {
|
switch (nwrite) {
|
||||||
case NGTCP2_ERR_STREAM_DATA_BLOCKED:
|
case NGTCP2_ERR_STREAM_DATA_BLOCKED:
|
||||||
|
assert(ndatalen == -1);
|
||||||
|
if (s->block_stream(stream_id) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
case NGTCP2_ERR_STREAM_SHUT_WR:
|
case NGTCP2_ERR_STREAM_SHUT_WR:
|
||||||
assert(ndatalen == -1);
|
assert(ndatalen == -1);
|
||||||
|
if (s->shutdown_stream_write(stream_id) != 0) {
|
||||||
if (s->block_stream(stream_id) != 0) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
@ -613,11 +630,23 @@ int Client::write_quic() {
|
||||||
quic_restart_pkt_timer();
|
quic_restart_pkt_timer();
|
||||||
|
|
||||||
if (nwrite == 0) {
|
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);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
write_udp(reinterpret_cast<sockaddr *>(ps.path.remote.addr),
|
bufpos += nwrite;
|
||||||
ps.path.remote.addrlen, buf.data(), nwrite);
|
|
||||||
|
// Assume that the path does not change.
|
||||||
|
if (++pktcnt == max_pktcnt ||
|
||||||
|
static_cast<size_t>(nwrite) < quic.max_pktlen) {
|
||||||
|
write_udp(ps.path.remote.addr, ps.path.remote.addrlen, buf.data(),
|
||||||
|
bufpos - buf.data(), quic.max_pktlen);
|
||||||
|
signal_write();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue