mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-02-19 20:27:01 +00:00
MINOR: quic: add GSO parameter on quic_sock send API
Add <gso_size> parameter to qc_snd_buf(). When non-null, this specifies the value for socket option SOL_UDP/UDP_SEGMENT. This allows to send several datagrams in a single call by splitting data multiple times at <gso_size> boundary. For now, <gso_size> remains set to 0 by caller, as such there should not be any functional change.
This commit is contained in:
parent
96a34d79d9
commit
448d3d388a
@ -44,7 +44,7 @@ struct connection *quic_sock_accept_conn(struct listener *l, int *status);
|
||||
struct task *quic_lstnr_dghdlr(struct task *t, void *ctx, unsigned int state);
|
||||
void quic_lstnr_sock_fd_iocb(int fd);
|
||||
int qc_snd_buf(struct quic_conn *qc, const struct buffer *buf, size_t count,
|
||||
int flags);
|
||||
int flags, uint16_t gso_size);
|
||||
int qc_rcv_buf(struct quic_conn *qc);
|
||||
void quic_conn_sock_fd_iocb(int fd);
|
||||
|
||||
|
@ -654,7 +654,7 @@ static struct task *quic_conn_closed_io_cb(struct task *t, void *context, unsign
|
||||
|
||||
buf = b_make(cc_qc->cc_buf_area + headlen,
|
||||
QUIC_MAX_CC_BUFSIZE - headlen, 0, cc_qc->cc_dgram_len);
|
||||
if (qc_snd_buf(qc, &buf, buf.data, 0) < 0) {
|
||||
if (qc_snd_buf(qc, &buf, buf.data, 0, 0) < 0) {
|
||||
TRACE_ERROR("sendto fatal error", QUIC_EV_CONN_IO_CB, qc);
|
||||
quic_release_cc_conn(cc_qc);
|
||||
cc_qc = NULL;
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
@ -652,8 +653,33 @@ static void cmsg_set_saddr(struct msghdr *msg, struct cmsghdr **cmsg,
|
||||
}
|
||||
}
|
||||
|
||||
/* Send a datagram stored into <buf> buffer with <sz> as size.
|
||||
* The caller must ensure there is at least <sz> bytes in this buffer.
|
||||
static void cmsg_set_gso(struct msghdr *msg, struct cmsghdr **cmsg,
|
||||
uint16_t gso_size)
|
||||
{
|
||||
#ifdef UDP_SEGMENT
|
||||
struct cmsghdr *c;
|
||||
size_t sz = sizeof(gso_size);
|
||||
|
||||
/* Set first msg_controllen to be able to use CMSG_* macros. */
|
||||
msg->msg_controllen += CMSG_SPACE(sz);
|
||||
|
||||
*cmsg = !(*cmsg) ? CMSG_FIRSTHDR(msg) : CMSG_NXTHDR(msg, *cmsg);
|
||||
ALREADY_CHECKED(*cmsg);
|
||||
c = *cmsg;
|
||||
c->cmsg_len = CMSG_LEN(sz);
|
||||
|
||||
c->cmsg_level = SOL_UDP;
|
||||
c->cmsg_type = UDP_SEGMENT;
|
||||
c->cmsg_len = CMSG_LEN(sz);
|
||||
*((uint16_t *)CMSG_DATA(c)) = gso_size;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Send a datagram stored into <buf> buffer with <sz> as size. The caller must
|
||||
* ensure there is at least <sz> bytes in this buffer.
|
||||
*
|
||||
* If <gso_size> is non null, it will be used as value for UDP_SEGMENT option.
|
||||
* This allows to transmit multiple datagrams in a single syscall.
|
||||
*
|
||||
* Returns the total bytes sent over the socket. 0 is returned if a transient
|
||||
* error is encountered which allows send to be retry later. A negative value
|
||||
@ -664,7 +690,7 @@ static void cmsg_set_saddr(struct msghdr *msg, struct cmsghdr **cmsg,
|
||||
* done by removing the <qc> arg and replace it with address/port.
|
||||
*/
|
||||
int qc_snd_buf(struct quic_conn *qc, const struct buffer *buf, size_t sz,
|
||||
int flags)
|
||||
int flags, uint16_t gso_size)
|
||||
{
|
||||
ssize_t ret;
|
||||
struct msghdr msg;
|
||||
@ -673,15 +699,25 @@ int qc_snd_buf(struct quic_conn *qc, const struct buffer *buf, size_t sz,
|
||||
|
||||
union {
|
||||
#ifdef IP_PKTINFO
|
||||
char buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
|
||||
char buf[CMSG_SPACE(sizeof(struct in_pktinfo)) + CMSG_SPACE(sizeof(gso_size))];
|
||||
#endif /* IP_PKTINFO */
|
||||
#ifdef IPV6_RECVPKTINFO
|
||||
char buf6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
|
||||
char buf6[CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(gso_size))];
|
||||
#endif /* IPV6_RECVPKTINFO */
|
||||
char bufaddr[CMSG_SPACE(sizeof(struct in_addr))];
|
||||
char bufaddr[CMSG_SPACE(sizeof(struct in_addr)) + CMSG_SPACE(sizeof(gso_size))];
|
||||
struct cmsghdr align;
|
||||
} ancillary_data;
|
||||
|
||||
/* man 3 cmsg
|
||||
*
|
||||
* When initializing a buffer that will contain a
|
||||
* series of cmsghdr structures (e.g., to be sent with
|
||||
* sendmsg(2)), that buffer should first be
|
||||
* zero-initialized to ensure the correct operation of
|
||||
* CMSG_NXTHDR().
|
||||
*/
|
||||
memset(&ancillary_data, 0, sizeof(ancillary_data));
|
||||
|
||||
vec.iov_base = b_peek(buf, b_head_ofs(buf));
|
||||
vec.iov_len = sz;
|
||||
|
||||
@ -717,6 +753,16 @@ int qc_snd_buf(struct quic_conn *qc, const struct buffer *buf, size_t sz,
|
||||
cmsg_set_saddr(&msg, &cmsg, &qc->local_addr);
|
||||
}
|
||||
|
||||
/* Set GSO parameter if datagram size is bigger than MTU. */
|
||||
if (gso_size) {
|
||||
/* GSO size must be less than total data to sent for multiple datagrams. */
|
||||
BUG_ON_HOT(b_data(buf) <= gso_size);
|
||||
|
||||
if (!msg.msg_control)
|
||||
msg.msg_control = ancillary_data.bufaddr;
|
||||
cmsg_set_gso(&msg, &cmsg, gso_size);
|
||||
}
|
||||
|
||||
do {
|
||||
ret = sendmsg(qc_fd(qc), &msg, MSG_DONTWAIT|MSG_NOSIGNAL);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
|
@ -300,7 +300,7 @@ static int qc_send_ppkts(struct buffer *buf, struct ssl_sock_ctx *ctx)
|
||||
|
||||
TRACE_PROTO("TX dgram", QUIC_EV_CONN_SPPKTS, qc);
|
||||
if (!skip_sendto) {
|
||||
int ret = qc_snd_buf(qc, &tmpbuf, tmpbuf.data, 0);
|
||||
int ret = qc_snd_buf(qc, &tmpbuf, tmpbuf.data, 0, 0);
|
||||
if (ret < 0) {
|
||||
TRACE_ERROR("sendto fatal error", QUIC_EV_CONN_SPPKTS, qc, first_pkt);
|
||||
qc_kill_conn(qc);
|
||||
|
Loading…
Reference in New Issue
Block a user