back to topotato report
topotato coverage report
Current view: top level - lib - stream.h (source / functions) Hit Total Coverage
Test: test_bgp_ecmp_enhe.py::BGP_Unnumbered_ECMP Lines: 0 16 0.0 %
Date: 2023-11-16 17:19:14 Functions: 0 0 -

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /*
       3             :  * Packet interface
       4             :  * Copyright (C) 1999 Kunihiro Ishiguro
       5             :  */
       6             : 
       7             : #ifndef _ZEBRA_STREAM_H
       8             : #define _ZEBRA_STREAM_H
       9             : 
      10             : #include <pthread.h>
      11             : 
      12             : #include "frratomic.h"
      13             : #include "mpls.h"
      14             : #include "prefix.h"
      15             : 
      16             : #ifdef __cplusplus
      17             : extern "C" {
      18             : #endif
      19             : 
      20             : /*
      21             :  * A stream is an arbitrary buffer, whose contents generally are assumed to
      22             :  * be in network order.
      23             :  *
      24             :  * A stream has the following attributes associated with it:
      25             :  *
      26             :  * - size: the allocated, invariant size of the buffer.
      27             :  *
      28             :  * - getp: the get position marker, denoting the offset in the stream where
      29             :  *         the next read (or 'get') will be from. This getp marker is
      30             :  *         automatically adjusted when data is read from the stream, the
      31             :  *         user may also manipulate this offset as they wish, within limits
      32             :  *         (see below)
      33             :  *
      34             :  * - endp: the end position marker, denoting the offset in the stream where
      35             :  *         valid data ends, and if the user attempted to write (or
      36             :  *         'put') data where that data would be written (or 'put') to.
      37             :  *
      38             :  * These attributes are all size_t values.
      39             :  *
      40             :  * Constraints:
      41             :  *
      42             :  * 1. getp can never exceed endp
      43             :  *
      44             :  * - hence if getp is equal to endp, there is no more valid data that can be
      45             :  *   gotten from the stream (though, the user may reposition getp to earlier in
      46             :  *   the stream, if they wish).
      47             :  *
      48             :  * 2. endp can never exceed size
      49             :  *
      50             :  * - hence, if endp is equal to size, then the stream is full, and no more
      51             :  *   data can be written to the stream.
      52             :  *
      53             :  * In other words the following must always be true, and the stream
      54             :  * abstraction is allowed internally to assert that the following property
      55             :  * holds true for a stream, as and when it wishes:
      56             :  *
      57             :  *        getp <= endp <= size
      58             :  *
      59             :  * It is the users responsibility to ensure this property is never violated.
      60             :  *
      61             :  * A stream therefore can be thought of like this:
      62             :  *
      63             :  *      ---------------------------------------------------
      64             :  *      |XXXXXXXXXXXXXXXXXXXXXXXX                         |
      65             :  *      ---------------------------------------------------
      66             :  *               ^               ^                        ^
      67             :  *               getp            endp                     size
      68             :  *
      69             :  * This shows a stream containing data (shown as 'X') up to the endp offset.
      70             :  * The stream is empty from endp to size. Without adjusting getp, there are
      71             :  * still endp-getp bytes of valid data to be read from the stream.
      72             :  *
      73             :  * Methods are provided to get and put to/from the stream, as well as
      74             :  * retrieve the values of the 3 markers and manipulate the getp marker.
      75             :  *
      76             :  * Note:
      77             :  * At the moment, newly allocated streams are zero filled. Hence, one can
      78             :  * use stream_forward_endp() to effectively create arbitrary zero-fill
      79             :  * padding. However, note that stream_reset() does *not* zero-out the
      80             :  * stream. This property should **not** be relied upon.
      81             :  *
      82             :  * Best practice is to use stream_put (<stream *>, NULL, <size>) to zero out
      83             :  * any part of a stream which isn't otherwise written to.
      84             :  */
      85             : 
      86             : /* Stream buffer. */
      87             : struct stream {
      88             :         struct stream *next;
      89             : 
      90             :         /*
      91             :          * Remainder is ***private*** to stream
      92             :          * direct access is frowned upon!
      93             :          * Use the appropriate functions/macros
      94             :          */
      95             :         size_t getp;           /* next get position */
      96             :         size_t endp;           /* last valid data position */
      97             :         size_t size;           /* size of data segment */
      98             :         unsigned char data[];  /* data pointer */
      99             : };
     100             : 
     101             : /* First in first out queue structure. */
     102             : struct stream_fifo {
     103             :         /* lock for mt-safe operations */
     104             :         pthread_mutex_t mtx;
     105             : 
     106             :         /* number of streams in this fifo */
     107             :         atomic_size_t count;
     108             : #if defined DEV_BUILD
     109             :         atomic_size_t max_count;
     110             : #endif
     111             : 
     112             :         struct stream *head;
     113             :         struct stream *tail;
     114             : };
     115             : 
     116             : /* Utility macros. */
     117             : #define STREAM_SIZE(S)  ((S)->size)
     118             : /* number of bytes which can still be written */
     119             : #define STREAM_WRITEABLE(S) ((S)->size - (S)->endp)
     120             : /* number of bytes still to be read */
     121             : #define STREAM_READABLE(S) ((S)->endp - (S)->getp)
     122             : 
     123             : #define STREAM_CONCAT_REMAIN(S1, S2, size) ((size) - (S1)->endp - (S2)->endp)
     124             : 
     125             : /* this macro is deprecated, but not slated for removal anytime soon */
     126             : #define STREAM_DATA(S)  ((S)->data)
     127             : 
     128             : /* Stream prototypes.
     129             :  * For stream_{put,get}S, the S suffix mean:
     130             :  *
     131             :  * c: character (unsigned byte)
     132             :  * w: word (two bytes)
     133             :  * l: long (two words)
     134             :  * q: quad (four words)
     135             :  */
     136             : extern struct stream *stream_new(size_t);
     137             : extern void stream_free(struct stream *);
     138             : /* Copy 'src' into 'dest', returns 'dest' */
     139             : extern struct stream *stream_copy(struct stream *dest,
     140             :                                   const struct stream *src);
     141             : extern struct stream *stream_dup(const struct stream *s);
     142             : 
     143             : extern size_t stream_resize_inplace(struct stream **sptr, size_t newsize);
     144             : 
     145             : extern size_t stream_get_getp(const struct stream *s);
     146             : extern size_t stream_get_endp(const struct stream *s);
     147             : extern size_t stream_get_size(const struct stream *s);
     148             : 
     149             : /**
     150             :  * Create a new stream structure; copy offset bytes from s1 to the new
     151             :  * stream; copy s2 data to the new stream; copy rest of s1 data to the
     152             :  * new stream.
     153             :  */
     154             : extern struct stream *stream_dupcat(const struct stream *s1,
     155             :                                     const struct stream *s2, size_t offset);
     156             : 
     157             : extern void stream_set_getp(struct stream *, size_t);
     158             : extern void stream_set_endp(struct stream *, size_t);
     159             : extern void stream_forward_getp(struct stream *, size_t);
     160             : extern bool stream_forward_getp2(struct stream *, size_t);
     161             : extern void stream_rewind_getp(struct stream *s, size_t size);
     162             : extern bool stream_rewind_getp2(struct stream *s, size_t size);
     163             : extern void stream_forward_endp(struct stream *, size_t);
     164             : extern bool stream_forward_endp2(struct stream *, size_t);
     165             : 
     166             : /* steam_put: NULL source zeroes out size_t bytes of stream */
     167             : extern void stream_put(struct stream *, const void *, size_t);
     168             : extern int stream_putc(struct stream *, uint8_t);
     169             : extern int stream_putc_at(struct stream *, size_t, uint8_t);
     170             : extern int stream_putw(struct stream *, uint16_t);
     171             : extern int stream_putw_at(struct stream *, size_t, uint16_t);
     172             : extern int stream_put3(struct stream *, uint32_t);
     173             : extern int stream_put3_at(struct stream *, size_t, uint32_t);
     174             : extern int stream_putl(struct stream *, uint32_t);
     175             : extern int stream_putl_at(struct stream *, size_t, uint32_t);
     176             : extern int stream_putq(struct stream *, uint64_t);
     177             : extern int stream_putq_at(struct stream *, size_t, uint64_t);
     178             : extern int stream_put_ipv4(struct stream *, uint32_t);
     179             : extern int stream_put_in_addr(struct stream *s, const struct in_addr *addr);
     180             : extern bool stream_put_ipaddr(struct stream *s, struct ipaddr *ip);
     181             : extern int stream_put_in_addr_at(struct stream *s, size_t putp,
     182             :                                  const struct in_addr *addr);
     183             : extern int stream_put_in6_addr_at(struct stream *s, size_t putp,
     184             :                                   const struct in6_addr *addr);
     185             : extern int stream_put_prefix_addpath(struct stream *s, const struct prefix *p,
     186             :                                      bool addpath_capable,
     187             :                                      uint32_t addpath_tx_id);
     188             : extern int stream_put_prefix(struct stream *s, const struct prefix *p);
     189             : extern int stream_put_labeled_prefix(struct stream *, const struct prefix *,
     190             :                                      mpls_label_t *, bool addpath_capable,
     191             :                                      uint32_t addpath_tx_id);
     192             : extern void stream_get(void *, struct stream *, size_t);
     193             : extern bool stream_get2(void *data, struct stream *s, size_t size);
     194             : extern void stream_get_from(void *, struct stream *, size_t, size_t);
     195             : extern uint8_t stream_getc(struct stream *);
     196             : extern bool stream_getc2(struct stream *s, uint8_t *byte);
     197             : extern uint8_t stream_getc_from(struct stream *, size_t);
     198             : extern uint16_t stream_getw(struct stream *);
     199             : extern bool stream_getw2(struct stream *s, uint16_t *word);
     200             : extern uint16_t stream_getw_from(struct stream *, size_t);
     201             : extern uint32_t stream_get3(struct stream *);
     202             : extern uint32_t stream_get3_from(struct stream *, size_t);
     203             : extern uint32_t stream_getl(struct stream *);
     204             : extern bool stream_getl2(struct stream *s, uint32_t *l);
     205             : extern uint32_t stream_getl_from(struct stream *, size_t);
     206             : extern uint64_t stream_getq(struct stream *);
     207             : extern uint64_t stream_getq_from(struct stream *, size_t);
     208             : bool stream_getq2(struct stream *s, uint64_t *q);
     209             : extern uint32_t stream_get_ipv4(struct stream *);
     210             : extern bool stream_get_ipaddr(struct stream *s, struct ipaddr *ip);
     211             : 
     212             : /* IEEE-754 floats */
     213             : extern float stream_getf(struct stream *);
     214             : extern double stream_getd(struct stream *);
     215             : extern int stream_putf(struct stream *, float);
     216             : extern int stream_putd(struct stream *, double);
     217             : 
     218             : #undef stream_read
     219             : #undef stream_write
     220             : 
     221             : /* Deprecated: assumes blocking I/O.  Will be removed.
     222             :    Use stream_read_try instead.  */
     223             : extern int stream_read(struct stream *, int, size_t);
     224             : 
     225             : /* Read up to size bytes into the stream.
     226             :    Return code:
     227             :      >0: number of bytes read
     228             :      0: end-of-file
     229             :      -1: fatal error
     230             :      -2: transient error, should retry later (i.e. EAGAIN or EINTR)
     231             :    This is suitable for use with non-blocking file descriptors.
     232             :  */
     233             : extern ssize_t stream_read_try(struct stream *s, int fd, size_t size);
     234             : 
     235             : extern ssize_t stream_recvmsg(struct stream *s, int fd, struct msghdr *,
     236             :                               int flags, size_t size);
     237             : extern ssize_t stream_recvfrom(struct stream *s, int fd, size_t len, int flags,
     238             :                                struct sockaddr *from, socklen_t *fromlen);
     239             : extern size_t stream_write(struct stream *, const void *, size_t);
     240             : 
     241             : /* reset the stream. See Note above */
     242             : extern void stream_reset(struct stream *);
     243             : extern int stream_flush(struct stream *, int);
     244             : extern int stream_empty(struct stream *); /* is the stream empty? */
     245             : 
     246             : /* debugging */
     247             : extern void stream_hexdump(const struct stream *s);
     248             : 
     249             : /**
     250             :  * Reorganize the buffer data so it can fit more. This function is normally
     251             :  * called right after stream data is consumed so we can read more data
     252             :  * (the functions that consume data start with `stream_get*()` and macros
     253             :  * `STREAM_GET*()`).
     254             :  *
     255             :  * \param s stream pointer.
     256             :  */
     257             : extern void stream_pulldown(struct stream *s);
     258             : 
     259             : /* deprecated */
     260             : extern uint8_t *stream_pnt(struct stream *);
     261             : 
     262             : /*
     263             :  * Operations on struct stream_fifo.
     264             :  *
     265             :  * Each function has a safe variant, which ensures that the operation performed
     266             :  * is atomic with respect to the operations performed by all other safe
     267             :  * variants. In other words, the safe variants lock the stream_fifo's mutex
     268             :  * before performing their action. These are provided for convenience when
     269             :  * using stream_fifo in a multithreaded context, to alleviate the need for the
     270             :  * caller to implement their own synchronization around the stream_fifo.
     271             :  *
     272             :  * The following functions do not have safe variants. The caller must ensure
     273             :  * that these operations are performed safely in a multithreaded context:
     274             :  * - stream_fifo_new
     275             :  * - stream_fifo_free
     276             :  */
     277             : 
     278             : /*
     279             :  * Create a new stream_fifo.
     280             :  *
     281             :  * Returns:
     282             :  *    newly created stream_fifo
     283             :  */
     284             : extern struct stream_fifo *stream_fifo_new(void);
     285             : 
     286             : /*
     287             :  * Init or re-init an on-stack fifo. This allows use of a fifo struct without
     288             :  * requiring a malloc/free cycle.
     289             :  * Note well that the fifo must be de-inited with the 'fifo_deinit' api.
     290             :  */
     291             : void stream_fifo_init(struct stream_fifo *fifo);
     292             : 
     293             : /*
     294             :  * Deinit an on-stack fifo.
     295             :  */
     296             : void stream_fifo_deinit(struct stream_fifo *fifo);
     297             : 
     298             : /*
     299             :  * Push a stream onto a stream_fifo.
     300             :  *
     301             :  * fifo
     302             :  *    the stream_fifo to push onto
     303             :  *
     304             :  * s
     305             :  *    the stream to push onto the stream_fifo
     306             :  */
     307             : extern void stream_fifo_push(struct stream_fifo *fifo, struct stream *s);
     308             : extern void stream_fifo_push_safe(struct stream_fifo *fifo, struct stream *s);
     309             : 
     310             : /*
     311             :  * Pop a stream off a stream_fifo.
     312             :  *
     313             :  * fifo
     314             :  *    the stream_fifo to pop from
     315             :  *
     316             :  * Returns:
     317             :  *    the next stream in the stream_fifo
     318             :  */
     319             : extern struct stream *stream_fifo_pop(struct stream_fifo *fifo);
     320             : extern struct stream *stream_fifo_pop_safe(struct stream_fifo *fifo);
     321             : 
     322             : /*
     323             :  * Retrieve the next stream from a stream_fifo without popping it.
     324             :  *
     325             :  * fifo
     326             :  *    the stream_fifo to operate on
     327             :  *
     328             :  * Returns:
     329             :  *    the next stream that would be returned from stream_fifo_pop
     330             :  */
     331             : extern struct stream *stream_fifo_head(struct stream_fifo *fifo);
     332             : extern struct stream *stream_fifo_head_safe(struct stream_fifo *fifo);
     333             : 
     334             : /*
     335             :  * Remove all streams from a stream_fifo.
     336             :  *
     337             :  * fifo
     338             :  *    the stream_fifo to clean
     339             :  */
     340             : extern void stream_fifo_clean(struct stream_fifo *fifo);
     341             : extern void stream_fifo_clean_safe(struct stream_fifo *fifo);
     342             : 
     343             : /*
     344             :  * Retrieve number of streams on a stream_fifo.
     345             :  *
     346             :  * fifo
     347             :  *    the stream_fifo to retrieve the count for
     348             :  *
     349             :  * Returns:
     350             :  *    the number of streams on the stream_fifo
     351             :  */
     352             : extern size_t stream_fifo_count_safe(struct stream_fifo *fifo);
     353             : 
     354             : /*
     355             :  * Free a stream_fifo.
     356             :  *
     357             :  * Calls stream_fifo_clean, then deinitializes the stream_fifo and frees it.
     358             :  *
     359             :  * fifo
     360             :  *    the stream_fifo to free
     361             :  */
     362             : extern void stream_fifo_free(struct stream_fifo *fifo);
     363             : 
     364             : /* This is here because "<< 24" is particularly problematic in C.
     365             :  * This is because the left operand of << is integer-promoted, which means
     366             :  * an uint8_t gets converted into a *signed* int.  Shifting into the sign
     367             :  * bit of a signed int is theoretically undefined behaviour, so - the left
     368             :  * operand needs to be cast to unsigned.
     369             :  *
     370             :  * This is not a problem for 16- or 8-bit values (they don't reach the sign
     371             :  * bit), for 64-bit values (you need to cast them anyway), and neither for
     372             :  * encoding (because it's downcasted.)
     373             :  */
     374           0 : static inline const uint8_t *ptr_get_be64(const uint8_t *ptr, uint64_t *out)
     375             : {
     376           0 :         uint32_t tmp1, tmp2;
     377             : 
     378           0 :         memcpy(&tmp1, ptr, sizeof(tmp1));
     379           0 :         memcpy(&tmp2, ptr + sizeof(tmp1), sizeof(tmp1));
     380             : 
     381           0 :         *out = (((uint64_t)ntohl(tmp1)) << 32) | ntohl(tmp2);
     382             : 
     383           0 :         return ptr + 8;
     384             : }
     385             : 
     386           0 : static inline const uint8_t *ptr_get_be32(const uint8_t *ptr, uint32_t *out)
     387             : {
     388           0 :         uint32_t tmp;
     389             : 
     390           0 :         memcpy(&tmp, ptr, sizeof(tmp));
     391           0 :         *out = ntohl(tmp);
     392           0 :         return ptr + 4;
     393             : }
     394             : 
     395           0 : static inline uint8_t *ptr_get_be16(uint8_t *ptr, uint16_t *out)
     396             : {
     397           0 :         uint16_t tmp;
     398             : 
     399           0 :         memcpy(&tmp, ptr, sizeof(tmp));
     400           0 :         *out = ntohs(tmp);
     401             : 
     402           0 :         return ptr + 2;
     403             : }
     404             : 
     405             : /*
     406             :  * so Normal stream_getX functions assert.  Which is anathema
     407             :  * to keeping a daemon up and running when something goes south
     408             :  * Provide a stream_getX2 functions that do not assert.
     409             :  * In addition provide these macro's that upon failure
     410             :  * goto stream_failure.  This is modeled upon some NL_XX
     411             :  * macros in the linux kernel.
     412             :  *
     413             :  * This change allows for proper memory freeing
     414             :  * after we've detected an error.
     415             :  *
     416             :  * In the future we will be removing the assert in
     417             :  * the stream functions but we need a transition
     418             :  * plan.
     419             :  */
     420             : #define STREAM_GETC(S, P)                                                      \
     421             :         do {                                                                   \
     422             :                 uint8_t _pval;                                                 \
     423             :                 if (!stream_getc2((S), &_pval))                                \
     424             :                         goto stream_failure;                                   \
     425             :                 (P) = _pval;                                                   \
     426             :         } while (0)
     427             : 
     428             : #define STREAM_GETW(S, P)                                                      \
     429             :         do {                                                                   \
     430             :                 uint16_t _pval;                                                \
     431             :                 if (!stream_getw2((S), &_pval))                                \
     432             :                         goto stream_failure;                                   \
     433             :                 (P) = _pval;                                                   \
     434             :         } while (0)
     435             : 
     436             : #define STREAM_GETL(S, P)                                                      \
     437             :         do {                                                                   \
     438             :                 uint32_t _pval;                                                \
     439             :                 if (!stream_getl2((S), &_pval))                                \
     440             :                         goto stream_failure;                                   \
     441             :                 (P) = _pval;                                                   \
     442             :         } while (0)
     443             : 
     444             : #define STREAM_GETF(S, P)                                                      \
     445             :         do {                                                                   \
     446             :                 union {                                                        \
     447             :                         float r;                                               \
     448             :                         uint32_t d;                                            \
     449             :                 } _pval;                                                       \
     450             :                 if (!stream_getl2((S), &_pval.d))                              \
     451             :                         goto stream_failure;                                   \
     452             :                 (P) = _pval.r;                                                 \
     453             :         } while (0)
     454             : 
     455             : #define STREAM_GETQ(S, P)                                                      \
     456             :         do {                                                                   \
     457             :                 uint64_t _pval;                                                \
     458             :                 if (!stream_getq2((S), &_pval))                                \
     459             :                         goto stream_failure;                                   \
     460             :                 (P) = _pval;                                                   \
     461             :         } while (0)
     462             : 
     463             : #define STREAM_GET_IPADDR(S, P)                                                \
     464             :         do {                                                                   \
     465             :                 if (!stream_get_ipaddr((S), (P)))                              \
     466             :                         goto stream_failure;                                   \
     467             :         } while (0)
     468             : 
     469             : #define STREAM_GET(P, STR, SIZE)                                               \
     470             :         do {                                                                   \
     471             :                 if (!stream_get2((P), (STR), (SIZE)))                          \
     472             :                         goto stream_failure;                                   \
     473             :         } while (0)
     474             : 
     475             : #define STREAM_FORWARD_GETP(STR, SIZE)                                         \
     476             :         do {                                                                   \
     477             :                 if (!stream_forward_getp2((STR), (SIZE)))                      \
     478             :                         goto stream_failure;                                   \
     479             :         } while (0)
     480             : 
     481             : #define STREAM_REWIND_GETP(STR, SIZE)                                          \
     482             :         do {                                                                   \
     483             :                 if (!stream_rewind_getp2((STR), (SIZE)))                       \
     484             :                         goto stream_failure;                                   \
     485             :         } while (0)
     486             : 
     487             : #define STREAM_FORWARD_ENDP(STR, SIZE)                                         \
     488             :         do {                                                                   \
     489             :                 if (!stream_forward_endp2((STR), (SIZE)))                      \
     490             :                         goto stream_failure;                                   \
     491             :         } while (0)
     492             : 
     493             : #ifdef __cplusplus
     494             : }
     495             : #endif
     496             : 
     497             : #endif /* _ZEBRA_STREAM_H */

Generated by: LCOV version v1.16-topotato