git: 0679eb1f39aa - main - netlink: make snl(3) scratch buffer growable
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 08 Mar 2023 12:29:32 UTC
The branch main has been updated by melifaro: URL: https://cgit.FreeBSD.org/src/commit/?id=0679eb1f39aa798da6c4601bb06bab4c175c4b18 commit 0679eb1f39aa798da6c4601bb06bab4c175c4b18 Author: Alexander V. Chernikov <melifaro@FreeBSD.org> AuthorDate: 2023-03-08 11:17:43 +0000 Commit: Alexander V. Chernikov <melifaro@FreeBSD.org> CommitDate: 2023-03-08 12:28:55 +0000 netlink: make snl(3) scratch buffer growable Differential Revision: https://reviews.freebsd.org/D38946 MFC after: 2 weeks --- sys/netlink/netlink_snl.h | 90 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 69 insertions(+), 21 deletions(-) diff --git a/sys/netlink/netlink_snl.h b/sys/netlink/netlink_snl.h index d88808ea6d3b..3c63e3f95419 100644 --- a/sys/netlink/netlink_snl.h +++ b/sys/netlink/netlink_snl.h @@ -70,11 +70,31 @@ #define NL_ARRAY_LEN(_a) (sizeof(_a) / sizeof((_a)[0])) struct linear_buffer { - char *base; /* Base allocated memory pointer */ - uint32_t offset; /* Currently used offset */ - uint32_t size; /* Total buffer size */ + char *base; /* Base allocated memory pointer */ + uint32_t offset; /* Currently used offset */ + uint32_t size; /* Total buffer size */ + struct linear_buffer *next; /* Buffer chaining */ }; +static inline struct linear_buffer * +lb_init(uint32_t size) +{ + struct linear_buffer *lb = calloc(1, size); + + if (lb != NULL) { + lb->base = (char *)(lb + 1); + lb->size = size - sizeof(*lb); + } + + return (lb); +} + +static inline void +lb_free(struct linear_buffer *lb) +{ + free(lb); +} + static inline char * lb_allocz(struct linear_buffer *lb, int len) { @@ -101,7 +121,7 @@ struct snl_state { size_t datalen; uint32_t seq; bool init_done; - struct linear_buffer lb; + struct linear_buffer *lb; }; #define SCRATCH_BUFFER_SIZE 1024 @@ -145,6 +165,45 @@ static const struct snl_hdr_parser _name = { \ } +static inline void * +snl_allocz(struct snl_state *ss, int len) +{ + void *data = lb_allocz(ss->lb, len); + + if (data == NULL) { + uint32_t size = ss->lb->size * 2; + + while (size < len + sizeof(struct linear_buffer)) + size *= 2; + + struct linear_buffer *lb = lb_init(size); + + if (lb != NULL) { + lb->next = ss->lb; + ss->lb = lb; + data = lb_allocz(ss->lb, len); + } + } + + return (data); +} + +static inline void +snl_clear_lb(struct snl_state *ss) +{ + struct linear_buffer *lb = ss->lb; + + lb_clear(lb); + lb = lb->next; + ss->lb->next = NULL; + /* Remove all linear bufs except the largest one */ + while (lb != NULL) { + struct linear_buffer *lb_next = lb->next; + lb_free(lb); + lb = lb_next; + } +} + static void snl_free(struct snl_state *ss) { @@ -152,8 +211,10 @@ snl_free(struct snl_state *ss) close(ss->fd); if (ss->buf != NULL) free(ss->buf); - if (ss->lb.base != NULL) - free(ss->lb.base); + if (ss->lb != NULL) { + snl_clear_lb(ss); + lb_free(ss->lb); + } } } @@ -181,9 +242,8 @@ snl_init(struct snl_state *ss, int netlink_family) return (false); } - ss->lb.size = SCRATCH_BUFFER_SIZE; - ss->lb.base = calloc(1, ss->lb.size); - if (ss->lb.base == NULL) { + ss->lb = lb_init(SCRATCH_BUFFER_SIZE); + if (ss->lb == NULL) { snl_free(ss); return (false); } @@ -191,18 +251,6 @@ snl_init(struct snl_state *ss, int netlink_family) return (true); } -static inline void * -snl_allocz(struct snl_state *ss, int len) -{ - return (lb_allocz(&ss->lb, len)); -} - -static inline void -snl_clear_lb(struct snl_state *ss) -{ - lb_clear(&ss->lb); -} - static inline bool snl_send(struct snl_state *ss, void *data, int sz) {