From c6bc185c185e366e57beed99ddfe609f7b5507b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20L=C3=A9caille?= Date: Wed, 30 Jun 2021 14:25:10 +0200 Subject: [PATCH] MINOR: quic: Add a ring buffer implementation for QUIC This implementation is inspired from Linux kernel circular buffer implementation (see include/linux/circ-buf.h). Such buffers may be used at the same time both by writer and reader (lock-free). --- Makefile | 2 +- include/haproxy/cbuf-t.h | 46 +++++++++++++ include/haproxy/cbuf.h | 138 +++++++++++++++++++++++++++++++++++++++ src/cbuf.c | 55 ++++++++++++++++ 4 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 include/haproxy/cbuf-t.h create mode 100644 include/haproxy/cbuf.h create mode 100644 src/cbuf.c diff --git a/Makefile b/Makefile index 0cb154156..e586ba4d5 100644 --- a/Makefile +++ b/Makefile @@ -590,7 +590,7 @@ endif ifneq ($(USE_QUIC),) OPTIONS_OBJS += src/quic_sock.o src/proto_quic.o src/xprt_quic.o src/quic_tls.o \ src/quic_frame.o src/quic_cc.o src/quic_cc_newreno.o src/mux_quic.o \ - src/qpack-dec.o src/qpack-tbl.o src/h3.o + src/cbuf.o src/qpack-dec.o src/qpack-tbl.o src/h3.o endif ifneq ($(USE_LUA),) diff --git a/include/haproxy/cbuf-t.h b/include/haproxy/cbuf-t.h new file mode 100644 index 000000000..876c804b5 --- /dev/null +++ b/include/haproxy/cbuf-t.h @@ -0,0 +1,46 @@ +/* + * include/haprox/cbuf-t.h + * This file contains definition for circular buffers. + * + * Copyright 2021 HAProxy Technologies, Frédéric Lécaille + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, version 2.1 + * exclusively. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _HAPROXY_CBUF_T_H +#define _HAPROXY_CBUF_T_H +#ifdef USE_QUIC +#ifndef USE_OPENSSL +#error "Must define USE_OPENSSL" +#endif +#endif + +#include + +/* QUIC circular buffer internal buffer size (must be a power of 2) */ +#define CBUF_BUFSZ (1UL << 11) + +extern struct pool_head *pool_head_cbuf; + +struct cbuf { + /* buffer */ + unsigned char buf[CBUF_BUFSZ]; + /* Writer index */ + int wr; + /* Reader index */ + int rd; +}; + +#endif /* _HAPROXY_CBUF_T_H */ diff --git a/include/haproxy/cbuf.h b/include/haproxy/cbuf.h new file mode 100644 index 000000000..2b0ea656e --- /dev/null +++ b/include/haproxy/cbuf.h @@ -0,0 +1,138 @@ +/* + * include/haprox/cbuf.h + * This file contains definitions and prototypes for circular buffers. + * Inspired from Linux circular buffers (include/linux/circ_buf.h). + * + * Copyright 2021 HAProxy Technologies, Frédéric Lécaille + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, version 2.1 + * exclusively. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _HAPROXY_CBUF_H +#define _HAPROXY_CBUF_H +#ifdef USE_QUIC +#ifndef USE_OPENSSL +#error "Must define USE_OPENSSL" +#endif +#endif + +#include +#include +#include + +struct cbuf *cbuf_new(void); +void cbuf_free(struct cbuf *cbuf); + +/* Amount of data between and */ +#define CBUF_DATA(wr, rd, size) (((wr) - (rd)) & ((size) - 1)) + +/* Return the writer position in . + * To be used only by the writer! + */ +static inline unsigned char *cb_wr(struct cbuf *cbuf) +{ + return cbuf->buf + cbuf->wr; +} + +/* Reset the reader index. + * To be used by a reader! + */ +static inline void cb_rd_reset(struct cbuf *cbuf) +{ + cbuf->rd = 0; +} + +/* Reset the writer index. + * To be used by a writer! + */ +static inline void cb_wr_reset(struct cbuf *cbuf) +{ + cbuf->wr = 0; +} + +/* Increase circular buffer data by . + * To be used by a writer! + */ +static inline void cb_add(struct cbuf *cbuf, size_t count) +{ + cbuf->wr = (cbuf->wr + count) & (CBUF_BUFSZ - 1); +} + +/* Return the reader position in . + * To be used only by the reader! + */ +static inline unsigned char *cb_rd(struct cbuf *cbuf) +{ + return cbuf->buf + cbuf->rd; +} + +/* Skip byte in circular buffer. + * To be used by a reader! + */ +static inline void cb_del(struct cbuf *cbuf, size_t count) +{ + cbuf->rd = (cbuf->rd + count) & (CBUF_BUFSZ - 1); +} + +/* Return the amount of data left in . + * To be used only by the writer! + */ +static inline int cb_data(struct cbuf *cbuf) +{ + int rd; + + rd = HA_ATOMIC_LOAD(&cbuf->rd); + return CBUF_DATA(cbuf->wr, rd, CBUF_BUFSZ); +} + +/* Return the amount of room left in minus 1 to distinguish + * the case where the buffer is full from the case where is is empty + * To be used only by the write! + */ +static inline int cb_room(struct cbuf *cbuf) +{ + int rd; + + rd = HA_ATOMIC_LOAD(&cbuf->rd); + return CBUF_DATA(rd, cbuf->wr + 1, CBUF_BUFSZ); +} + +/* Return the amount of contiguous data left in . + * To be used only by the reader! + */ +static inline int cb_contig_data(struct cbuf *cbuf) +{ + int end, n; + + end = CBUF_BUFSZ - cbuf->rd; + n = (HA_ATOMIC_LOAD(&cbuf->wr) + end) & (CBUF_BUFSZ - 1); + + return n < end ? n : end; +} + +/* Return the amount of contiguous space left in . + * To be used only by the writer! + */ +static inline int cb_contig_space(struct cbuf *cbuf) +{ + int end, n; + + end = CBUF_BUFSZ - 1 - cbuf->wr; + n = (HA_ATOMIC_LOAD(&cbuf->rd) + end) & (CBUF_BUFSZ - 1); + + return n <= end ? n : end + 1; +} + +#endif /* _HAPROXY_CBUF_H */ diff --git a/src/cbuf.c b/src/cbuf.c new file mode 100644 index 000000000..d58ff973e --- /dev/null +++ b/src/cbuf.c @@ -0,0 +1,55 @@ +/* + * Circular buffer management + * + * Copyright 2021 HAProxy Technologies, Frédéric Lécaille + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, version 2.1 + * exclusively. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +DECLARE_POOL(pool_head_cbuf, "cbuf_pool", sizeof(struct cbuf)); + +/* Allocate and return a new circular buffer if succeeded, NULL if not. */ +struct cbuf *cbuf_new(void) +{ + struct cbuf *cbuf; + + cbuf = pool_alloc(pool_head_cbuf); + if (cbuf) { + cbuf->wr = 0; + cbuf->rd = 0; + } + + return cbuf; +} + +/* Free QUIC ring */ +void cbuf_free(struct cbuf *cbuf) +{ + if (!cbuf) + return; + + pool_free(pool_head_cbuf, cbuf); +} + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + */