]> git.kaiwu.me - haproxy.git/commitdiff
OPTIM: log/tools: switch from function pointer design to dual mode HEX/BIN design...
authorAurelien DARRAGON <adarragon@haproxy.com>
Fri, 21 Aug 2026 13:34:54 +0000 (15:34 +0200)
committerAurelien DARRAGON <adarragon@haproxy.com>
Fri, 21 Aug 2026 15:54:46 +0000 (17:54 +0200)
Time has shown that only the HEX/BIN mode for cbor encoding were relevant
so far. And the current design based on function pointers was proved
to be a lot CPU consuming, reducing logging performances by a significant
amount (even when binary CBOR was used) compared to logs without encoding.

In order to try to recover as much logging performance as possible,
especially for the CBOR binary encoder, let's switch to a simpler design
where all cbor encoding functions are proposed in 2 distincts variants:
one for binary encoding, and the other for hex (ie: ascii compatible)
encoding. The cost of that is a code that contains a little bit of
duplication, although this was limited thanks to the use of static
inline helpers where possible to group common code. The benefit is that
no function pointers are used anymore during the encoding chain, making
the branches more predictable for CPU predictions and compiler
optimizations. To further improve the performance in CBOR binary mode
a special case was performed in cbor_encode_uint64_prefix_bin():
as suggested by Willy, for x86_64 systems we can actually directly
write int64 using memcpy() since bits are already in the correct order.

include/haproxy/tools-t.h
include/haproxy/tools.h
src/log.c
src/tools.c

index 792a0f650430f052832da4b45327a2482daf58c7..13cfe5d3f8c00cf409c19e30fbbe56e7752793d6 100644 (file)
@@ -160,22 +160,6 @@ struct net_addr_type {
        int xprt_type;  // transport layer
 };
 
-/* To easily pass context to cbor encode functions
- */
-struct cbor_encode_ctx {
-       /* function pointer that cbor encode functions will use to encode a
-        * single byte.
-        *
-        * The function needs to return the position of the last written byte
-        * on success and NULL on failure. The function cannot write past <stop>
-        */
-       char *(*e_fct_byte)(struct cbor_encode_ctx *ctx,
-                           char *start, char *stop, uint8_t byte);
-
-       /* to provide some user-context to the encode_fct_* funcs */
-       void *e_fct_ctx;
-};
-
 /* An indexed file name node, to be used at various places where a config file
  * location is expected. These elements live forever and are only released on
  * deinit. The goal is to use them in place of a regular "char* file" in many
index 0cb7f345e80147ace12fc9d5c89e7ffca442b1a3..4d57c395ffde7802f3deb02946f8d2c0a85a9884 100644 (file)
@@ -477,21 +477,26 @@ int chunk_escape_string(struct buffer *chunk, const char *str, size_t len);
 /* Below are RFC8949 compliant cbor encode helper functions, see source
  * file for functions descriptions
  */
-char *cbor_encode_uint64_prefix(struct cbor_encode_ctx *ctx,
-                                char *start, char *stop,
-                                uint64_t value, uint8_t prefix);
-char *cbor_encode_int64(struct cbor_encode_ctx *ctx,
-                        char *start, char *stop, int64_t value);
-char *cbor_encode_bytes_prefix(struct cbor_encode_ctx *ctx,
-                               char *start, char *stop,
-                               const char *bytes, size_t len,
-                               uint8_t prefix);
-char *cbor_encode_bytes(struct cbor_encode_ctx *ctx,
-                        char *start, char *stop,
-                        const char *bytes, size_t len);
-char *cbor_encode_text(struct cbor_encode_ctx *ctx,
-                       char *start, char *stop,
-                       const char *text, size_t len);
+char *cbor_encode_uint64_prefix_bin(char *start, char *stop,
+                                    uint64_t value, uint8_t prefix);
+char *cbor_encode_uint64_prefix_hex(char *start, char *stop,
+                                    uint64_t value, uint8_t prefix);
+char *cbor_encode_int64_bin(char *start, char *stop, int64_t value);
+char *cbor_encode_int64_hex(char *start, char *stop, int64_t value);
+char *cbor_encode_bytes_prefix_bin(char *start, char *stop,
+                                   const char *bytes, size_t len,
+                                   uint8_t prefix);
+char *cbor_encode_bytes_prefix_hex(char *start, char *stop,
+                                   const char *bytes, size_t len,
+                                   uint8_t prefix);
+char *cbor_encode_bytes_bin(char *start, char *stop,
+                            const char *bytes, size_t len);
+char *cbor_encode_bytes_hex(char *start, char *stop,
+                            const char *bytes, size_t len);
+char *cbor_encode_text_bin(char *start, char *stop,
+                           const char *text, size_t len);
+char *cbor_encode_text_hex(char *start, char *stop,
+                           const char *text, size_t len);
 
 /* Check a string for using it in a CSV output format. If the string contains
  * one of the following four char <">, <,>, CR or LF, the string is
index 240ff2eec9869549c9afa80f557ba7b845a14a62..349bd36611cdc75361f9a7eb1ff8988fd532bd75 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -2021,9 +2021,6 @@ struct lf_buildctx {
        int options;   /* LOG_OPT_* options */
        int typecast;  /* same as logformat_node->typecast */
        int in_text;   /* inside variable-length text */
-       union {
-               struct cbor_encode_ctx cbor; /* cbor-encode specific ctx */
-       } encode;
 };
 
 static THREAD_LOCAL char lf_buildbuf[256]; /* fixed size buffer for building small strings */
@@ -2033,32 +2030,21 @@ static THREAD_LOCAL char lf_buildbuf[256]; /* fixed size buffer for building sma
  * Returns the address of the byte immediately after the last written byte
  * on success, or NULL on error. It will not append terminating NULL byte.
  */
-static char *_encode_byte_hex(char *start, char *stop, unsigned char byte)
+static inline char *_encode_byte_hex(char *start, char *stop, unsigned char byte)
 {
        /* hex form requires 2 bytes */
        if ((stop - start) < 2)
                return NULL;
        *start++ = hextab[(byte >> 4) & 15];
        *start++ = hextab[byte & 15];
-       return start;
+
+       return start;
 }
 
-/* lf cbor function ptr used to encode a single byte according to RFC8949
- *
- * The function may only be called under CBOR context (that is when
- * LOG_OPT_ENCODE_CBOR option is set).
- *
- * Returns the address of the byte immediately after the last written byte
- * on success, or NULL on error. It will not append terminating NULL byte.
- */
-static char *_lf_cbor_encode_byte(struct cbor_encode_ctx *cbor_ctx,
-                                  char *start, char *stop, unsigned char byte)
+/* lf_cbor helper to write a single byte according to CBOR options */
+static inline char *_lf_cbor_encode_byte(struct lf_buildctx *ctx,
+                                         char *start, char *stop, unsigned char byte)
 {
-       struct lf_buildctx *ctx;
-
-       BUG_ON(!cbor_ctx || !cbor_ctx->e_fct_ctx);
-       ctx = cbor_ctx->e_fct_ctx;
-
        if (ctx->options & LOG_OPT_BIN) {
                /* raw output */
                if ((stop - start) < 1)
@@ -2085,12 +2071,6 @@ static inline void lf_buildctx_prepare(struct lf_buildctx *ctx,
                ctx->options = g_options;
                ctx->typecast = SMP_T_SAME; /* default */
        }
-
-       if (ctx->options & LOG_OPT_ENCODE_CBOR) {
-               /* prepare cbor-specific encode ctx */
-               ctx->encode.cbor.e_fct_byte = _lf_cbor_encode_byte;
-               ctx->encode.cbor.e_fct_ctx = ctx;
-       }
 }
 
 /* helper function for _lf_encode_bytes() to escape a single byte
@@ -2128,9 +2108,14 @@ static inline char *_lf_cbor_escape_byte(char *start, char *stop,
        escaped_byte[1] = hextab[(byte >> 4) & 15];
        escaped_byte[2] = hextab[byte & 15];
 
-       start = cbor_encode_bytes_prefix(&ctx->encode.cbor, start, stop,
-                                        escaped_byte, 3,
-                                        cbor_string_prefix);
+       if (ctx->options & LOG_OPT_BIN)
+               start = cbor_encode_bytes_prefix_bin(start, stop,
+                                                    escaped_byte, 3,
+                                                    cbor_string_prefix);
+       else
+               start = cbor_encode_bytes_prefix_hex(start, stop,
+                                                    escaped_byte, 3,
+                                                    cbor_string_prefix);
 
        return start;
 }
@@ -2184,9 +2169,14 @@ static inline char *_lf_cbor_map_escape_byte(char *start, char *stop,
                 */
        } else {
                /* first, flush pending unescaped bytes */
-               start = cbor_encode_bytes_prefix(&ctx->encode.cbor, start, stop,
-                                                *pending, (byte - *pending),
-                                                cbor_string_prefix);
+               if (ctx->options & LOG_OPT_BIN)
+                       start = cbor_encode_bytes_prefix_bin(start, stop,
+                                                            *pending, (byte - *pending),
+                                                            cbor_string_prefix);
+               else
+                       start = cbor_encode_bytes_prefix_hex(start, stop,
+                                                            *pending, (byte - *pending),
+                                                            cbor_string_prefix);
                if (start == NULL)
                        return NULL;
 
@@ -2322,7 +2312,7 @@ static char *_lf_encode_bytes(char *start, char *stop,
 
                if ((ctx->options & LOG_OPT_ENCODE_CBOR) && !ctx->in_text) {
                        /* start indefinite-length cbor byte string or text */
-                       start = _lf_cbor_encode_byte(&ctx->encode.cbor, start, stop,
+                       start = _lf_cbor_encode_byte(ctx, start, stop,
                                                     (cbor_string_prefix | 0x1F));
                        if (start == NULL)
                                return NULL;
@@ -2357,15 +2347,20 @@ static char *_lf_encode_bytes(char *start, char *stop,
                if (ctx->options & LOG_OPT_ENCODE_CBOR) {
                        if (pending != bytes) {
                                /* flush pending unescaped bytes */
-                               start = cbor_encode_bytes_prefix(&ctx->encode.cbor, start, stop,
-                                                                pending, (bytes - pending),
-                                                                cbor_string_prefix);
+                               if (ctx->options & LOG_OPT_BIN)
+                                       start = cbor_encode_bytes_prefix_bin(start, stop,
+                                                                            pending, (bytes - pending),
+                                                                            cbor_string_prefix);
+                               else
+                                       start = cbor_encode_bytes_prefix_hex(start, stop,
+                                                                            pending, (bytes - pending),
+                                                                            cbor_string_prefix);
                                if (start == NULL)
                                        return NULL;
                        }
                        if (!ctx->in_text) {
                                /* cbor break (to end indefinite-length text or byte string) */
-                               start = _lf_cbor_encode_byte(&ctx->encode.cbor, start, stop, 0xFF);
+                               start = _lf_cbor_encode_byte(ctx, start, stop, 0xFF);
                                if (start == NULL)
                                        return NULL;
                        }
@@ -2437,7 +2432,10 @@ static inline char *_lf_text_len(char *dst, const char *src,
                        /* cbor_encode_text() doesn't append terminating NULL
                         * byte, we must reserve 1 byte for that.
                         */
-                       ret = cbor_encode_text(&ctx->encode.cbor, dst, dst + size - 1, src, len);
+                       if (ctx->options & LOG_OPT_BIN)
+                               ret = cbor_encode_text_bin(dst, dst + size - 1, src, len);
+                       else
+                               ret = cbor_encode_text_hex(dst, dst + size - 1, src, len);
                        if (ret == NULL)
                                return NULL;
                        len = ret - dst;
@@ -2624,8 +2622,8 @@ static char *lf_bool_encode(char *dst, size_t size, uint8_t value,
        }
        if (ctx->options & LOG_OPT_ENCODE_CBOR) {
                if (value)
-                       return _lf_cbor_encode_byte(&ctx->encode.cbor, dst, dst + size, 0xF5);
-               return _lf_cbor_encode_byte(&ctx->encode.cbor, dst, dst + size, 0xF4);
+                       return _lf_cbor_encode_byte(ctx, dst, dst + size, 0xF5);
+               return _lf_cbor_encode_byte(ctx, dst, dst + size, 0xF4);
        }
 
        return NULL; /* not supported */
@@ -2668,7 +2666,10 @@ static char *lf_int_encode(char *dst, size_t size, int64_t value,
                /* Always print as a regular int64 number (STR typecast isn't
                 * supported)
                 */
-               return cbor_encode_int64(&ctx->encode.cbor, dst, dst + size, value);
+               if (ctx->options & LOG_OPT_BIN)
+                       return cbor_encode_int64_bin(dst, dst + size, value);
+               else
+                       return cbor_encode_int64_hex(dst, dst + size, value);
        }
 
        return NULL; /* not supported */
@@ -3551,7 +3552,7 @@ const char sess_set_cookie[] = "NPDIRU67";        /* No set-cookie, Set-cookie found an
  * try to write a cbor byte if there is enough space, or goto out
  */
 #define LOG_CBOR_BYTE(x) do {                                          \
-                       ret = _lf_cbor_encode_byte(&ctx->encode.cbor,  \
+                       ret = _lf_cbor_encode_byte(ctx,                \
                                                   tmplog,             \
                                                   dst + maxsize - 1,  \
                                                   (x));               \
@@ -3572,10 +3573,14 @@ const char sess_set_cookie[] = "NPDIRU67";      /* No set-cookie, Set-cookie found an
                                 * cbor decoder to know how to handle them     \
                                 */                                            \
                                _x[0] = (x);                                   \
-                               ret = cbor_encode_text(&ctx->encode.cbor,      \
-                                                      tmplog,                 \
-                                                      dst + maxsize - 1,      \
-                                                      _x, sizeof(_x));        \
+                               if (ctx->options & LOG_OPT_BIN)                \
+                                       ret = cbor_encode_text_bin(tmplog,           \
+                                                                  dst + maxsize - 1,\
+                                                                  _x, sizeof(_x));  \
+                               else                                           \
+                                       ret = cbor_encode_text_hex(tmplog,           \
+                                                                  dst + maxsize - 1,\
+                                                                  _x, sizeof(_x));  \
                                if (ret == NULL)                               \
                                        goto out;                              \
                                tmplog = ret;                                  \
@@ -4145,9 +4150,12 @@ size_t sess_build_logline_orig(struct session *sess, struct stream *s,
                                LOGCHAR(' ');
                        }
                        else if (ctx->options & LOG_OPT_ENCODE_CBOR) {
-                               ret = cbor_encode_text(&ctx->encode.cbor, tmplog,
-                                                      dst + maxsize - 1, tmp->name,
-                                                      strlen(tmp->name));
+                               if (ctx->options & LOG_OPT_BIN)
+                                       ret = cbor_encode_text_bin(tmplog, dst + maxsize -1,
+                                                                  tmp->name, strlen(tmp->name));
+                               else
+                                       ret = cbor_encode_text_hex(tmplog, dst + maxsize - 1,
+                                                                  tmp->name, strlen(tmp->name));
                                if (ret == NULL)
                                        goto out;
                                tmplog = ret;
index 7783a89fc712b732ac29518b8416d66a8acf4c0f..0a41c7a3cfc75318fd47efcfc74a0fbfecaecc99 100644 (file)
@@ -2193,80 +2193,147 @@ int chunk_escape_string(struct buffer *chunk, const char *str, size_t len)
        return 0;
 }
 
-/* CBOR helper to encode an uint64 value with prefix (3bits MAJOR type)
- * according to RFC8949
- *
- * CBOR encode ctx is provided in <ctx>
+/* helper to encode a single byte in hex form
  *
  * Returns the address of the byte immediately after the last written byte
- * on success, or NULL on error. The function cannot write past <stop>.
- * It will not append terminating NULL byte.
+ * on success, or NULL on error. It will not append terminating NULL byte.
  */
-char *cbor_encode_uint64_prefix(struct cbor_encode_ctx *ctx,
-                                char *start, char *stop, uint64_t value,
-                                uint8_t prefix)
+static inline char *_encode_byte_hex(char *start, char *stop, unsigned char byte)
 {
-       int nb_bytes = 0;
+       /* hex form requires 2 bytes */
+       if ((stop - start) < 2)
+               return NULL;
+       *start++ = hextab[(byte >> 4) & 15];
+       *start++ = hextab[byte & 15];
+       return start;
+}
 
+static inline int _cbor_encode_uint64_prefix(uint64_t value, uint8_t *prefix)
+{
+
+       int nb_bytes = 0;
        /*
         * For encoding logic, see:
         * https://www.rfc-editor.org/rfc/rfc8949.html#name-specification-of-the-cbor-e
         */
        if (value < 24) {
                /* argument is the value itself */
-               prefix |= value;
+               *prefix |= value;
        }
        else {
                if (value <= 0xFFU) {
                        /* 1-byte */
                        nb_bytes = 1;
-                       prefix |= 24; // 0x18
+                       *prefix |= 24; // 0x18
                }
                else if (value <= 0xFFFFU) {
                        /* 2 bytes */
                        nb_bytes = 2;
-                       prefix |= 25; // 0x19
+                       *prefix |= 25; // 0x19
                }
                else if (value <= 0xFFFFFFFFU) {
                        /* 4 bytes */
                        nb_bytes = 4;
-                       prefix |= 26; // 0x1A
+                       *prefix |= 26; // 0x1A
                }
                else {
                        /* 8 bytes */
                        nb_bytes = 8;
-                       prefix |= 27; // 0x1B
+                       *prefix |= 27; // 0x1B
                }
        }
 
-       start = ctx->e_fct_byte(ctx, start, stop, prefix);
-       if (start == NULL)
+       return nb_bytes;
+}
+
+
+/* CBOR helper to encode an uint64 value with prefix (3bits MAJOR type)
+ * according to RFC8949 in bin form.
+ *
+ * Returns the address of the byte immediately after the last written byte
+ * on success, or NULL on error. The function cannot write past <stop>.
+ * It will not append terminating NULL byte.
+ */
+char *cbor_encode_uint64_prefix_bin(char *start, char *stop, uint64_t value,
+                                    uint8_t prefix)
+{
+       int nb_bytes;
+
+
+       nb_bytes = _cbor_encode_uint64_prefix(value, &prefix);
+
+       if (stop - start < 1)
                return NULL;
 
+       *start++ = prefix;
+
+       if (start + nb_bytes >= stop)
+               return NULL;
+
+#if defined(__x86_64__)
+       /* we can actually assume the bits are already in proper order
+        * so let's directly write them as-is on the wire to save CPU
+        * time.
+        */
+       memcpy(start, &value, nb_bytes);
+       start += nb_bytes;
+#else
        /* encode 1 byte at a time from higher bits to lower bits */
        while (nb_bytes) {
                uint8_t cur_byte = (value >> ((nb_bytes - 1) * 8)) & 0xFFU;
 
-               start = ctx->e_fct_byte(ctx, start, stop, cur_byte);
+               *start++ = cur_byte;
                if (start == NULL)
                        return NULL;
 
                nb_bytes--;
        }
+#endif
 
        return start;
 }
 
-/* CBOR helper to encode an int64 value according to RFC8949
+/* CBOR helper to encode an uint64 value with prefix (3bits MAJOR type)
+ * according to RFC8949 in hex form.
  *
- * CBOR encode ctx is provided in <ctx>
+ * Returns the address of the byte immediately after the last written byte
+ * on success, or NULL on error. The function cannot write past <stop>.
+ * It will not append terminating NULL byte.
+ */
+char *cbor_encode_uint64_prefix_hex(char *start, char *stop, uint64_t value,
+                                    uint8_t prefix)
+{
+       int nb_bytes;
+
+
+       nb_bytes = _cbor_encode_uint64_prefix(value, &prefix);
+
+       start = _encode_byte_hex(start, stop, prefix);
+       if (start == NULL)
+               return NULL;
+
+       /* encode 1 byte at a time from higher bits to lower bits */
+       while (nb_bytes) {
+               uint8_t cur_byte = (value >> ((nb_bytes - 1) * 8)) & 0xFFU;
+
+               start = _encode_byte_hex(start, stop, cur_byte);
+               if (start == NULL)
+                       return NULL;
+
+               nb_bytes--;
+       }
+
+       return start;
+}
+
+
+/* CBOR helper to encode an int64 value according to RFC8949 in bin form
  *
  * Returns the address of the byte immediately after the last written byte
  * on success, or NULL on error. The function cannot write past <stop>.
  * It will not append terminating NULL byte.
  */
-char *cbor_encode_int64(struct cbor_encode_ctx *ctx,
-                        char *start, char *stop, int64_t value)
+char *cbor_encode_int64_bin(char *start, char *stop, int64_t value)
 {
        uint64_t absolute_value = llabs(value);
        int cbor_prefix;
@@ -2282,38 +2349,71 @@ char *cbor_encode_int64(struct cbor_encode_ctx *ctx,
                /* N-1 for negative int */
                absolute_value -= 1;
        }
-       return cbor_encode_uint64_prefix(ctx, start, stop,
-                                        absolute_value, cbor_prefix);
+       return cbor_encode_uint64_prefix_bin(start, stop,
+                                            absolute_value, cbor_prefix);
 }
 
-/* CBOR helper to encode a <prefix> string chunk according to RFC8949
- *
- * if <bytes> is NULL, then only the <prefix> (with length) will be
- * emitted
- *
- * CBOR encode ctx is provided in <ctx>
+/* CBOR helper to encode an int64 value according to RFC8949 in hex form
  *
  * Returns the address of the byte immediately after the last written byte
  * on success, or NULL on error. The function cannot write past <stop>.
  * It will not append terminating NULL byte.
  */
-char *cbor_encode_bytes_prefix(struct cbor_encode_ctx *ctx,
-                               char *start, char *stop,
-                               const char *bytes, size_t len,
-                               uint8_t prefix)
+char *cbor_encode_int64_hex(char *start, char *stop, int64_t value)
+{
+       uint64_t absolute_value = llabs(value);
+       int cbor_prefix;
+
+       /*
+        * For encoding logic, see:
+        * https://www.rfc-editor.org/rfc/rfc8949.html#name-specification-of-the-cbor-e
+        */
+       if (value >= 0)
+               cbor_prefix = 0x00; // unsigned int
+       else {
+               cbor_prefix = 0x20; // negative int
+               /* N-1 for negative int */
+               absolute_value -= 1;
+       }
+       return cbor_encode_uint64_prefix_hex(start, stop,
+                                            absolute_value, cbor_prefix);
+}
+
+static inline char *_cbor_encode_bytes_prefix_bin(char *start, char *stop,
+                                                  const char *bytes, size_t len,
+                                                  uint8_t prefix)
+{
+       /* write prefix (with text length as argument) */
+       start = cbor_encode_uint64_prefix_bin(start, stop,
+                                             len, prefix);
+       if (start == NULL)
+               return NULL;
+
+       /* write actual bytes if provided */
+       if (start + len >= stop)
+               return NULL;
+       memcpy(start, bytes, len);
+       start += len;
+
+       return start;
+}
+
+static inline char *_cbor_encode_bytes_prefix_hex(char *start, char *stop,
+                                                  const char *bytes, size_t len,
+                                                  uint8_t prefix)
 {
 
        size_t it = 0;
 
        /* write prefix (with text length as argument) */
-       start = cbor_encode_uint64_prefix(ctx, start, stop,
-                                         len, prefix);
+       start = cbor_encode_uint64_prefix_hex(start, stop,
+                                             len, prefix);
        if (start == NULL)
                return NULL;
 
        /* write actual bytes if provided */
        while (bytes && it < len) {
-               start = ctx->e_fct_byte(ctx, start, stop, bytes[it]);
+               start = _encode_byte_hex(start, stop, bytes[it]);
                if (start == NULL)
                        return NULL;
                it++;
@@ -2321,9 +2421,11 @@ char *cbor_encode_bytes_prefix(struct cbor_encode_ctx *ctx,
        return start;
 }
 
-/* CBOR helper to encode a text chunk according to RFC8949
+/* CBOR helper to encode a <prefix> string chunk according to RFC8949 in
+ * bin form.
  *
- * if <text> is NULL, then only the text prefix (with length) will be emitted
+ * if <bytes> is NULL, then only the <prefix> (with length) will be
+ * emitted
  *
  * CBOR encode ctx is provided in <ctx>
  *
@@ -2331,16 +2433,17 @@ char *cbor_encode_bytes_prefix(struct cbor_encode_ctx *ctx,
  * on success, or NULL on error. The function cannot write past <stop>.
  * It will not append terminating NULL byte.
  */
-char *cbor_encode_text(struct cbor_encode_ctx *ctx,
-                       char *start, char *stop,
-                       const char *text, size_t len)
+char *cbor_encode_bytes_prefix_bin(char *start, char *stop,
+                                   const char *bytes, size_t len,
+                                   uint8_t prefix)
 {
-       return cbor_encode_bytes_prefix(ctx, start, stop, text, len, 0x60);
+       return _cbor_encode_bytes_prefix_bin(start, stop, bytes, len, prefix);
 }
 
-/* CBOR helper to encode a byte string chunk according to RFC8949
+/* CBOR helper to encode a <prefix> string chunk according to RFC8949 in
+ * hex form.
  *
- * if <bytes> is NULL, then only the byte string prefix (with length) will be
+ * if <bytes> is NULL, then only the <prefix> (with length) will be
  * emitted
  *
  * CBOR encode ctx is provided in <ctx>
@@ -2349,11 +2452,69 @@ char *cbor_encode_text(struct cbor_encode_ctx *ctx,
  * on success, or NULL on error. The function cannot write past <stop>.
  * It will not append terminating NULL byte.
  */
-char *cbor_encode_bytes(struct cbor_encode_ctx *ctx,
-                        char *start, char *stop,
-                        const char *bytes, size_t len)
+char *cbor_encode_bytes_prefix_hex(char *start, char *stop,
+                                   const char *bytes, size_t len,
+                                   uint8_t prefix)
+{
+       return _cbor_encode_bytes_prefix_hex(start, stop, bytes, len, prefix);
+}
+
+/* CBOR helper to encode a text chunk according to RFC8949 in bin form.
+ *
+ * if <text> is NULL, then only the text prefix (with length) will be emitted
+ *
+ * Returns the address of the byte immediately after the last written byte
+ * on success, or NULL on error. The function cannot write past <stop>.
+ * It will not append terminating NULL byte.
+ */
+char *cbor_encode_text_bin(char *start, char *stop,
+                           const char *text, size_t len)
+{
+       return _cbor_encode_bytes_prefix_bin(start, stop, text, len, 0x60);
+}
+
+/* CBOR helper to encode a text chunk according to RFC8949 in hex form.
+ *
+ * if <text> is NULL, then only the text prefix (with length) will be emitted
+ *
+ * Returns the address of the byte immediately after the last written byte
+ * on success, or NULL on error. The function cannot write past <stop>.
+ * It will not append terminating NULL byte.
+ */
+char *cbor_encode_text_hex(char *start, char *stop,
+                           const char *text, size_t len)
+{
+       return _cbor_encode_bytes_prefix_hex(start, stop, text, len, 0x60);
+}
+
+/* CBOR helper to encode a byte string chunk according to RFC8949 in bin form.
+ *
+ * if <bytes> is NULL, then only the byte string prefix (with length) will be
+ * emitted
+ *
+ * Returns the address of the byte immediately after the last written byte
+ * on success, or NULL on error. The function cannot write past <stop>.
+ * It will not append terminating NULL byte.
+ */
+char *cbor_encode_bytes_bin(char *start, char *stop,
+                            const char *bytes, size_t len)
+{
+       return _cbor_encode_bytes_prefix_bin(start, stop, bytes, len, 0x40);
+}
+
+/* CBOR helper to encode a byte string chunk according to RFC8949 in hex form.
+ *
+ * if <bytes> is NULL, then only the byte string prefix (with length) will be
+ * emitted
+ *
+ * Returns the address of the byte immediately after the last written byte
+ * on success, or NULL on error. The function cannot write past <stop>.
+ * It will not append terminating NULL byte.
+ */
+char *cbor_encode_bytes_hex(char *start, char *stop,
+                            const char *bytes, size_t len)
 {
-       return cbor_encode_bytes_prefix(ctx, start, stop, bytes, len, 0x40);
+       return _cbor_encode_bytes_prefix_hex(start, stop, bytes, len, 0x40);
 }
 
 /* Check a string for using it in a CSV output format. If the string contains