summaryrefslogtreecommitdiff
path: root/src/lib
Commit message (Collapse)AuthorAgeFilesLines
* lib: Add support for Linux RTT estimatorDimitri Staessens2022-04-033-2/+13
| | | | | | | | | | | | | This adds the option to use the Round-Trip-Time (RTT) estimation algorithm as it is implemented in the TCP implementation in Linux. It looks like it outperforms the TCP default algorithm, so I enabled this one by default. Also adds the option to change the RTO timeout calculation to include more (or less) than 4 times the mdev (specified as a power of 2. Left the default value to 2 (so, 4 mdevs), but 3 (8 mdevs) gives better results in my tests. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Fix fqueue_next handling of deallocated flowsDimitri Staessens2022-04-012-3/+8
| | | | | | | | | If a flow was deallocated while there were still unprocessed events in an fqueue, it would cause a SEGV in fqueue_next because it was not checking the validity of the returned flow descriptor. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Fix timing of delayed ACKsDimitri Staessens2022-04-012-7/+26
| | | | | | | | | | Delayed ACKs are now sent after twice the internal tick time. Fixes initial ACK record (rcv_cr.seqno) being uninitialized (0) when the first ACK was to be sent. Adds some FRCT metrics for number of received delayed (bare) ACKs and the RTT estimator. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Use struct portevent internallyDimitri Staessens2022-03-302-22/+26
| | | | | | | | The fqueues were relying on the fact that the portevent were two integers. This cleans that up a bit. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Fix use-after-free of recv_msgDimitri Staessens2022-03-301-10/+7
| | | | | | | The protobuf message was free'd before usage in flow_init. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Fix unidirectional FRCT traffic handlingDimitri Staessens2022-03-302-9/+9
| | | | | | | | | | | | | Unidirectional traffic has one of the peers only send bare FRCT packets. These never set a DRF, since they have no sequence number. At the receiver, all these ACKs and window updates were always dropped as the receiver connection record was timed out. Also fixes a SEGV if flow control kicks in (passing NULL timeout to pthread_cond_timedwait). Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Move incoming FRCT handling to own threadDimitri Staessens2022-03-301-24/+67
| | | | | | | | | | | | | | | | The application will now handle incoming FRCT packets even if the application never reads data from the flow (for instance servers). To do this, it reserves an fset_t (id 0). When an FRCT-enabled flow is created, it is automatically added to this fset. An rx thread will listen for incoming events and perform necessary actions on the flow if needed. If the FRCT flow is added to another user fset, it will be handled by that user fset (and if the flow is removed from a user fset, it will be re-added to the set with id 0 to be handled by the rx_flow thread. The flow monitoring is handled by the same thread, replacing the previous monitoring thread. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Iterate over monitored flowsDimitri Staessens2022-03-301-49/+49
| | | | | | | | | | Now the instance keeps all flows for an application in a linked list to easily iterate over all allocated flows, which is needed by the keepalive monitoring. This is more efficient that tracking min and max fd. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Remove flows list from fsetDimitri Staessens2022-03-301-62/+2
| | | | | | | We don't need to iterate fsets anymore since the removal of fset_keepalive. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Fix filtering encrypted packetsDimitri Staessens2022-03-302-54/+54
| | | | | | | | | | | | The frcti_filter was reading raw data from the buffers, causing the frcti_rcv to operate directly on encrypted packets. It decrypt and filter for invalid packets. I moved the function from frct to the fqueue implementation and renamed it fqueue_filter as it filters fqueues. Should be extended to filter out keepalives on non-FRCT flows, as these will now still cause spurious wakeups. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Move flow monitoring to its own threadDimitri Staessens2022-03-301-174/+130
| | | | | | | | | This adds a monitoring thread to handle flow keepalive management in the application and removes the thread interruptions to schedule FRCT calls within the regular IPC calls. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Add np1_flow_read and np1_flow_write callsDimitri Staessens2022-03-301-11/+80
| | | | | | | | | | | | | | | | Reading/writing to (N + 1)-flows from the IPCP was using a raw QoS flow to bypass some functions in the ipcp_flow_read call. But this call was broken for keepalive packets. Fixing the ipcp_flow_read call for (N - 1) flows causes the IPCPs to drop 0-byte keepalive packets coming from (N + 1) client flows. >From now on, there is a dedicated call for (N + 1) reads/writes from the IPCPs that's more efficient and cleaner. The (N + 1) flow internal QoS is now also defaulted to a qos_np1 qosspec, instead of tampering with the qosspec requested by the (N + 1) client. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Add rbuff support for FLOWPEER stateDimitri Staessens2022-03-302-15/+32
| | | | | | | | This allows setting the FLOWPEER state on a flow to signal a peer is unresponsive. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Move timerwheel processing to its own threadDimitri Staessens2022-03-303-27/+34
| | | | | | | | | | | | | | | This is the first step moving away from scheduling the FRCT and flow monitoring functions as part of the IPC calls (flow_read / flow_write / fevent) and towards the more scalable (and far less complicated) implementation to take care of these functions in separate threads. If a process creates the first flow that requires FRCT, it will spin up a thread to process events on the timerwheel (retransmissions and delayed ACKs). This single thread lives until the last flow with FRCT is deallocated. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Create FRCT instance when initializing flowDimitri Staessens2022-03-301-59/+46
| | | | | | | | The creation of FRCT instances (if needed) is now part of flow_init() call instead of an addition after the flow is initialized. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Refactor writing to rbuffDimitri Staessens2022-03-301-69/+57
| | | | | | | | Writing valid packets to the rbuff (add crc check, encrypt) is now extracted into a function. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Remove prog name and pid from instanceDimitri Staessens2022-03-301-25/+10
| | | | | | | | Prog name is not used anymore, probably a remnant from the early days, when we were passing rina_name_t tuples all over the place. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Refactor reading packet from rbuffDimitri Staessens2022-03-306-70/+87
| | | | | | | | | | | | Reading packets from the rbuff and checking their validity (non-zero size, pass crc check, pass decryption) is now extracted into a function. Also adds a function to get the length of an sdu_du_buff instead of subtracting the tail and head pointers. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Notify once for packets in new fsetDimitri Staessens2022-03-301-4/+1
| | | | | | | | The fset add function was notifying for each packet already stored in the rx rbuff, which isn't needed. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Non-configurable delayed acks in FRCPDimitri Staessens2022-03-304-30/+24
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | It doesn't really make sense to manually and one-sidedly configure the timeout of delayed acknowledgements, as setting it too high upsets the peer's sRTT estimates. Even worse, it also causes a lot of spurious retransmissions if it exceeds the sRTT mean deviation calculated by the receiver. Compensating on bare acknowledgment for the ack delay could improve the RTT estimate deviation, but not the spurious retransmissions if it was set too high. This sets the delayed ack to wait for a single RTT mean deviation. Probably needs more tweaking to further reduce differences between the RTT estimates at the sender and receiver, e.g. compensate the RTT estimate for delayed acks, or increase the RTO to add 8 mdevs to sRTT instead of 4. However, it looks like the mdev estimate is the trickiest one to get to sync, not the RTT average. Linux reduces the sample weight for mdev from 1/4 to 1/32 in some cases, will give that a shot some day too to see if that further align sRTT estimates. In any case, this patch already improves things a lot. Also fixes a bug where the sender was sending acknowlegments on the first packets in flight for the 0 sequence number. The receiver activity was measured in seconds but compared to a timeout value in nanoseconds. There's still a lot of spurious retransmissions that start after actual packet loss occurs, I'm still investigating what causes it. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Expose flow control metrics to RIB0.19.1Dimitri Staessens2022-03-162-14/+48
| | | | | | | | | | This exposes some additional metrics relating to FRCT / Flow control: the number of duplicate packets received, number of packets received out of the flow control window and / or reordering queue, and the number of rendez-vous messages sent. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Fix retransmission schedulingDimitri Staessens2022-03-161-72/+60
| | | | | | | | | | | | | There still were a couple of bugs in the timerwheel. If the future schedule was coinciding with the slot currently being processed (i.e. exactly RXMQ_SLOTS in the future), the list_add_tail caused an infinite loop. Another bug was causing the slots at higher levels to be processed too soon. Retransmissions should now schedule correctly. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Fix buffer allocation when retransmitting0.19.0Dimitri Staessens2022-03-114-18/+47
| | | | | | | | | | | | | | | The timerwheel was retransmitting packets and the error check for negative values of the rbuff allocation was instead checking for non-zero values, causing a buffer allocation to succeed but the program to continue down the unhappy path leaving that packet stuck in the buffer unattended. Also fixes wrongly scheduled retransmissions that cause packet storms. FRCP is much more stable now. Still needs some work for high bandwidth-delay products (fast-retransmit). Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* ipdpd: Pass MPL to application at flow_allocationDimitri Staessens2022-03-083-8/+23
| | | | | | | | | | | | The maximum packet lifetime (MPL) is a property of the flow that needs to be passed to the reliable transmission protocol (FRCP) for its correct operation. Previously, the value of MPL was set fixed as one of the (fixed) Delta-t parameters. This patch makes the MPL a property of the layer, and it can now be set per layer-type at build time. This is a step towards a proper MPL estimator in the flow allocator. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Pass Delta-t params to frcti_create()Dimitri Staessens2022-03-082-9/+9
| | | | | | | | | The parameters were set directly from the build configs. A first step to making FRCP configurable at runtime, is to pass the parameters to the frcti_create() function. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Fix RTT estimator invocation in FRCTDimitri Staessens2022-03-031-1/+1
| | | | | | | The notorious off-by-one hit again. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Fix underflow in keepalive timerDimitri Staessens2022-03-031-1/+1
| | | | | | | If the keepalive would underflow if set to 1-3 ms. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Flag all flows down as the IRMd exitsDimitri Staessens2022-03-033-13/+26
| | | | | | | | | | | | | | On exit of the IRMd all flows will now be flagged as down, so external applications will not hang anymore. Note: reads keep work from flows that are down until there are no more remaining packets in the buffer, but no more packets can be written. When the RIB is used, the external application may exit a bit later than the IRMd, so I added a brief sleep before the IRMd tries to remove the fuse main directory. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Fix lock reversal in timerwheelDimitri Staessens2022-03-031-5/+0
| | | | | | | | | There was a lock reversal in the timerwheel. There still is a thorough revision needed of the locking in dev.c after the FRCP logic is completed and tuned. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Cleanup RIB mount nameDimitri Staessens2022-03-031-1/+3
| | | | | | | | | | IPCPs would call rib_fini() twice, once after cleaning up their managed RIB, and once again for the program-generic RIB, which is not initialized for IPCPs. rib_fini() checked if the mount name was valid, but it didn't unset it after execution. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Check return value of rib_initDimitri Staessens2022-03-031-1/+6
| | | | | | | The rib_init return value wasn't checked. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Encrypt bare FRCP messages on encrypted flowsDimitri Staessens2022-03-033-44/+29
| | | | | | | | Bare FRCP messages (ACKs without data, Rendez-vous packets) were not encrypted on encrypted flows, causing the receiver to fail decryption. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Make flow liveness timeout configurableDimitri Staessens2022-03-033-28/+57
| | | | | | | | | The qosspec_t now has a timeout value that sets the timeout value of the flow. Flows with a peer that has timed out will now return -EFLOWPEER on flow_read() or flow_write(). Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Remove dead code in timerwheelDimitri Staessens2022-03-031-6/+0
| | | | | | | The checked condition can't happen. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Add initial flow liveness monitoringDimitri Staessens2022-02-243-23/+163
| | | | | | | | | | | | | | | | | | This adds flow liveness monitoring for flows, with a fixed timeout of 120s. I will make it configurable at flow allocation later on (timeout needs to be communicated to the peer). If one peer dies, or doesn't call any IPC calls (flow_write/flow_read/fevent) it will stop sending keepalives and the other peer's read/writes will error on an -EFLOWDOWN after the timeout expires. Packets without a payload (0 length packets) are interpreted as keepalive packets for the flow. They can be sent from any application, but they will not trigger a message read at the receiver side (0 as a return value on flow_read indicates a previous partial read has completed at exactly the buffer size). Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Maintain a list of flows in flow_setDimitri Staessens2022-02-241-26/+99
| | | | | | | | | The flow_set will now keep a list of the flows in the set, this makes it more efficient to iterate over the flows. Extending the public API for fset_t with an iterator will also be useful. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Handle FLOWDOWN during blocking readDimitri Staessens2022-02-211-3/+7
| | | | | | | | | | The blocking read from the rbuff was not correctly handling flow down states, returning a valid index. The attempt to fetch the header then failed on an assertion. The blocking read will now return -EFLOWDOWN if the flow is marked down by the IPCP. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* ipcpd: Fix free in fail path of readdirDimitri Staessens2022-02-171-0/+9
| | | | | | | | | The free of the buffer in the failure path of the readdir RIB functions was taking the wrong pointer in a couple of places. The FRCT RIB readdir was missing error handling for malloc and strdup. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Don't use pointer to set FRCT flagsDimitri Staessens2021-12-291-5/+4
| | | | | | | | | | | | | | | | | | The fccntl call FRCTSFLAGS was using a pointer to a flags so set flags, which should just be a regular uint16_t. For instance, the FRCTLINGER flags can now be turned off using fccntl(fd, FRCTSFLAGS, FRCTFRESCNTL | FRCTFRTX) leaving only resource control (flow control, FRCTFRESCNTL) and retransmission enabled. Note that retransmission (FRCTFRTX) can't be enabled or disabled on a live flow, it will be set on flow allocation. Updates the man page for fccntl to add these FRCT options. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Ease lock in timerwheel0.18.4Dimitri Staessens2021-12-221-2/+2
| | | | | | | It was taking a write lock when a read lock was sufficient. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Fix waiting for FRCT at deallocationDimitri Staessens2021-12-221-6/+6
| | | | | | | | | | This is a fix to wait for outstanding retransmissions when a flow is deallocated. Instead of waiting the full timeout, it will now wait in the same tic increments used within FRCT. Bit of a stopgap at the moment, FRCT and the flows are in need of a serious refactor. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Add missing rwlock unlock in FRCTDimitri Staessens2021-12-221-2/+4
| | | | | | | There was a missing unlock in FRCT. Also fixes some indentation. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Fix flow dealloc after expired FRCT timeoutDimitri Staessens2021-12-221-0/+1
| | | | | | | | | | If the timeout is already expired, the wait variable would be negative and return a negative value for the __frcti_dealloc function, thinking that the timeout was not expired causing an unnecessary wait even if all packets are acknowledged. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Set initial sender rwe to sender seqnoDimitri Staessens2021-12-221-1/+1
| | | | | | | | | | | The initial sender right window edge (indicating acknowledged packet sequence number) was initialized to seqno - 1. This should be the same as seqno, since we acknowledge with the next expected sequence number. It also indicates that a flow without traffic has no outstanding acknowledgements. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Remove old rib_fini codeDimitri Staessens2021-12-061-3/+0
| | | | | | | | There was some leftover code in dev.c wrt to the process RIB that is not needed anymore. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Fix undefined behaviour in sha3Dimitri Staessens2021-12-061-2/+1
| | | | | | | | | Arithmetic with NULL pointers is undefined behaviour. Caught by clang 13. Fixed by using uintptr_t, which is guaranteed to be the size of a pointer. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Don't initialize process RIB for IPCPsDimitri Staessens2021-07-102-10/+5
| | | | | | | | | | | | | This will skip rib_init() at __init() for IPCPs (or at least, processes that have "ipcpd" in the executable name). The previous code tried to unmount the generic mount and then remount under the ipcp name, but it often failed because fuse_mount() is asynchronous and the mount was not up at the time of the unmount() call. Renaming the mount instead of unmounting failed for the same reason. This is a better fix for now. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Application RIB with FRCT statisticsDimitri Staessens2021-06-305-17/+173
| | | | | | | | | | Application flows can now be monitored from the RIB, exposing FRCT statistics (window edges, retransmission timeout, rtt estimate, etc). Application RIB requires user permissions to be able to access /dev/fuse. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Pass full path for RIB entriesDimitri Staessens2021-06-291-10/+9
| | | | | | | | | | | | | | | | | | | | | | | | | | | The read functions for the RIB will now receive the full path, instead of only the entry name. For IPCPs, we organized the RIB in an /<ipcp>/<component>/entries structure with a directory per component, so we don't need the full path at this point. For process flow information, it's a lot more convenient to organize it the following way /<pid>/<fd>/stat We can then register/unregister the flow descriptor when the frct instance is created, and for getting the stats, we'd know the flow descriptor from the fuse file path. If we would create a file per flow instead of a directory per flow, something like /<pid>/flows/<fd> we'd need to do additional bookkeeping to list the contents of that directory (we would need to track all flows with an active FRCT instance), that fuse knows because it tracks the directories. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
* lib: Remove struct stat from RIB APIDimitri Staessens2021-06-281-5/+14
| | | | | | | | | | The RIB API had a struct stat in the getattr() function, which made all components that exposed variables via the RIB dependent on <sys/stat.h>. The rib now has its own struct rib_attr to set attributes such as size and last modified time. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>