Skip to content

Commit

Permalink
net 2.0: interface table
Browse files Browse the repository at this point in the history
  • Loading branch information
riptl committed Jan 26, 2025
1 parent 7986381 commit 34e546b
Show file tree
Hide file tree
Showing 8 changed files with 578 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/disco/netlink/fd_netlink_tile_private.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef HEADER_fd_src_disco_netlink_fd_netlink_tile_private_h
#define HEADER_fd_src_disco_netlink_fd_netlink_tile_private_h

#include "fd_netlink_tile.h"
#include "../../waltz/mib/fd_netdev_tbl.h"
#include "../../waltz/ip/fd_netlink1.h"
#include "../metrics/generated/fd_metrics_netlink.h"

Expand All @@ -14,6 +16,8 @@ struct fd_netlink_tile_ctx {
fd_netlink_t nl_monitor[1];
fd_netlink_t nl_req[1];

fd_netdev_tbl_join_t netdev_tbl[1];

struct {
ulong update_cnt[ FD_METRICS_COUNTER_NETLINK_UPDATES_CNT ];
} metrics;
Expand Down
8 changes: 8 additions & 0 deletions src/waltz/mib/Local.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
$(call add-hdrs,fd_dbl_buf.h)
$(call add-objs,fd_dbl_buf,fd_waltz)
$(call add-hdrs,fd_netdev_tbl.h)
$(call add-objs,fd_netdev_tbl,fd_waltz)
ifdef FD_HAS_LINUX
$(call add-hdrs,fd_netdev_linux.h)
$(call add-objs,fd_netdev_linux,fd_waltz)
endif
135 changes: 135 additions & 0 deletions src/waltz/mib/fd_dbl_buf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#include "fd_dbl_buf.h"
#include "../../util/simd/fd_sse.h"
#include "../../util/log/fd_log.h"
#include "../../tango/fd_tango_base.h"

ulong
fd_dbl_buf_align( void ) {
return FD_DBL_BUF_ALIGN;
}

ulong
fd_dbl_buf_footprint( ulong mtu ) {
return FD_DBL_BUF_FOOTPRINT( mtu );
}

void *
fd_dbl_buf_new( void * shmem,
ulong mtu,
ulong seq0 ) {

if( FD_UNLIKELY( !shmem ) ) {
FD_LOG_WARNING(( "NULL shmem" ));
return NULL;
}

if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, FD_DBL_BUF_ALIGN ) ) ) {
FD_LOG_WARNING(( "misaligned shmem" ));
return NULL;
}

ulong mtu_align = fd_ulong_align_up( mtu, FD_DBL_BUF_ALIGN );
FD_SCRATCH_ALLOC_INIT( l, shmem );
fd_dbl_buf_t * dbl_buf = FD_SCRATCH_ALLOC_APPEND( l, FD_DBL_BUF_ALIGN, sizeof(fd_dbl_buf_t) );
void * buf0 = FD_SCRATCH_ALLOC_APPEND( l, FD_DBL_BUF_ALIGN, mtu_align );
void * buf1 = FD_SCRATCH_ALLOC_APPEND( l, FD_DBL_BUF_ALIGN, mtu_align );
FD_SCRATCH_ALLOC_FINI( l, FD_DBL_BUF_ALIGN );

*dbl_buf = (fd_dbl_buf_t) {
.magic = 0UL,
.seq = seq0,
.sz = 0UL,
.mtu = mtu,
.buf0 = (ulong)buf0 - (ulong)dbl_buf,
.buf1 = (ulong)buf1 - (ulong)dbl_buf
};

FD_COMPILER_MFENCE();
FD_VOLATILE( dbl_buf->magic ) = FD_DBL_BUF_MAGIC;
FD_COMPILER_MFENCE();

return dbl_buf;
}

fd_dbl_buf_t *
fd_dbl_buf_join( void * shbuf ) {

if( FD_UNLIKELY( !shbuf ) ) {
FD_LOG_WARNING(( "NULL shbuf" ));
return NULL;
}

if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shbuf, FD_DBL_BUF_ALIGN ) ) ) {
FD_LOG_WARNING(( "misaligned shbuf" ));
return NULL;
}

fd_dbl_buf_t * dbl_buf = shbuf;
if( FD_UNLIKELY( dbl_buf->magic!=FD_DBL_BUF_MAGIC ) ) {
FD_LOG_WARNING(( "bad magic" ));
return NULL;
}

return dbl_buf;
}

void *
fd_dbl_buf_leave( fd_dbl_buf_t * buf ) {
return buf;
}

void *
fd_dbl_buf_delete( void * shbuf ) {

if( FD_UNLIKELY( !shbuf ) ) {
FD_LOG_WARNING(( "NULL shbuf" ));
return NULL;
}

if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shbuf, FD_DBL_BUF_ALIGN ) ) ) {
FD_LOG_WARNING(( "misaligned shbuf" ));
return NULL;
}

fd_dbl_buf_t * dbl_buf = shbuf;
FD_COMPILER_MFENCE();
FD_VOLATILE( dbl_buf->magic ) = 0UL;
FD_COMPILER_MFENCE();
return dbl_buf;
}

void
fd_dbl_buf_insert( fd_dbl_buf_t * buf,
void const * msg,
ulong sz ) {
/* */ sz = fd_ulong_min( sz, buf->mtu );
ulong seq = fd_seq_inc( buf->seq, 1UL );
void * dst = fd_dbl_buf_slot( buf, seq );

fd_memcpy( dst, msg, sz );

# if FD_HAS_SSE
FD_COMPILER_MFENCE();
vv_t seq_sz = vv( seq, sz );
_mm_store_si128( &buf->seq_sz, seq_sz );
FD_COMPILER_MFENCE();
# else
buf->sz = sz;
FD_COMPILER_MFENCE();
buf->seq = seq;
FD_COMPILER_MFENCE();
# endif
}

ulong
fd_dbl_buf_read( fd_dbl_buf_t * buf,
void * obj,
ulong * opt_seqp ) {
ulong _seq[1];
ulong * seqp = opt_seqp ? opt_seqp : _seq;
ulong sz;
do {
sz = fd_dbl_buf_try_read( buf, obj, seqp );
} while( FD_UNLIKELY( sz==ULONG_MAX ) );
return sz;
}
165 changes: 165 additions & 0 deletions src/waltz/mib/fd_dbl_buf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
#ifndef HEADER_fd_src_waltz_mib_fd_dbl_buf_h
#define HEADER_fd_src_waltz_mib_fd_dbl_buf_h

/* fd_dbl_buf.h provides a concurrent lock-free double buffer. A double
buffer contains two buffers that take turns holding a message for
consumers and receving a new message by a producer.
Supports a single producer thread and an arbitrary number of consumer
threads. Optimized for rare updates and frequent polling (e.g. config).
Use an fd_tango mcache/dcache pair if you need frequent updates.
Currently assumes a memory model that preserves store order across
threads (e.g. x86-TSO). Does not use atomics or hardware fences. */

#include "../../util/bits/fd_bits.h"
#if FD_HAS_SSE
#include <emmintrin.h>
#endif

/* FIXME COULD ALLOW FOR IN-PLACE READS WITH PODs BY ADDING A MSG ALIGN ARGUMENT */

/* fd_dbl_buf_t is the header of a dbl_buf object. May not be locally
declared. */

union __attribute__((aligned(16UL))) fd_dbl_buf {

struct {
ulong magic; /* ==FD_DBL_BUF_MAGIC */
ulong mtu;
ulong buf0; /* offset to first buffer from beginning of struct */
ulong buf1; /* — " — second — " — */
ulong seq; /* latest msg seq no */
ulong sz; /* latest msg size */
ulong pad[2];
/* objects follow here */
};

# if FD_HAS_SSE
struct {
__m128i magic_mtu;
__m128i buf0_buf1;
__m128i seq_sz;
__m128i pad2;
};
# endif

};

typedef union fd_dbl_buf fd_dbl_buf_t;

#define FD_DBL_BUF_MAGIC (0xa6c6f85d431c03ceUL) /* random */

#define FD_DBL_BUF_ALIGN (16UL)
#define FD_DBL_BUF_FOOTPRINT(mtu) \
FD_LAYOUT_FINI( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_INIT, \
FD_DBL_BUF_ALIGN, sizeof(fd_dbl_buf_t) ), \
FD_DBL_BUF_ALIGN, FD_ULONG_ALIGN_UP( mtu, FD_DBL_BUF_ALIGN )<<1UL ), \
FD_DBL_BUF_ALIGN )

FD_PROTOTYPES_BEGIN

/* fd_dbl_buf_{align,footprint} describe the memory region of a double
buffer. mtu is the largest possible message size. */

ulong
fd_dbl_buf_align( void );

ulong
fd_dbl_buf_footprint( ulong mtu );

/* fd_dbl_buf_new formats a memory region for use as a double buffer.
shmem points to the memory region matching fd_dbl_buf_{align,footprint}.
Initially, the active object of the double buffer will have sequence
number seq0 and zero byte size. */

void *
fd_dbl_buf_new( void * shmem,
ulong mtu,
ulong seq0 );

fd_dbl_buf_t *
fd_dbl_buf_join( void * shbuf );

void *
fd_dbl_buf_leave( fd_dbl_buf_t * buf );

/* fd_dbl_buf_delete unformats the memory region backing a dbl_buf and
releases ownership back to the caller. Returns shbuf. */

void *
fd_dbl_buf_delete( void * shbuf );

/* fd_dbl_buf_obj_mtu returns the max message size a dbl_buf can store. */

static inline ulong
fd_dbl_buf_obj_mtu( fd_dbl_buf_t * buf ) {
return buf->mtu;
}

/* fd_dbl_buf_seq_query peeks the current sequence number. */

static inline ulong
fd_dbl_buf_seq_query( fd_dbl_buf_t * buf ) {
FD_COMPILER_MFENCE();
ulong seq = FD_VOLATILE_CONST( buf->seq );
FD_COMPILER_MFENCE();
return seq;
}

/* fd_dbl_buf_slot returns a pointer to the buffer for the given sequence
number. */

FD_FN_PURE static inline void *
fd_dbl_buf_slot( fd_dbl_buf_t * buf,
ulong seq ) {
return (seq&1) ? buf+buf->buf1 : buf+buf->buf0;
}

/* fd_dbl_buf_insert appends a message to the double buffer.
Note: It is NOT safe to call this function from multiple threads. */

void
fd_dbl_buf_insert( fd_dbl_buf_t * buf,
void const * msg,
ulong sz );

/* fd_dbl_buf_try_read does a speculative read the most recent message
(from the caller's POV). The read may be overrun by a writer. out
points to a buffer of fd_dbl_buf_obj_mtu(buf) bytes. opt_seqp points to
a ulong or NULL.
On success:
- returns the size of the message read
- a copy of the message is stored at out
- *opt_seqp is set to the msg sequence number (if non-NULL)
On failure (due to overrun):
- returns ULONG_MAX
- out buffer is clobbered
- *opt_seq is clobbered (if non-NULL) */

static inline ulong
fd_dbl_buf_try_read( fd_dbl_buf_t * buf,
void * out,
ulong * opt_seqp ) {
ulong seq = fd_dbl_buf_seq_query( buf );
void * src = fd_dbl_buf_slot( buf, seq );
ulong sz = FD_VOLATILE_CONST( buf->sz );
fd_memcpy( out, src, sz );
if( FD_UNLIKELY( seq!=fd_dbl_buf_seq_query( buf ) ) ) return ULONG_MAX;
fd_ulong_store_if( !!opt_seqp, opt_seqp, seq );
return sz;
}

/* fd_dbl_buf_read does a blocking */

ulong
fd_dbl_buf_read( fd_dbl_buf_t * buf,
void * obj,
ulong * opt_seqp );

FD_PROTOTYPES_END

#endif /* HEADER_fd_src_waltz_mib_fd_dbl_buf_h */
9 changes: 9 additions & 0 deletions src/waltz/mib/fd_netdev_netlink.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#include "fd_netdev_netlink.h"

int
fd_netdev_netlink_load_table( fd_netdev_tbl_t * tbl,
fd_netlink_t * netlink ) {
(void)tbl; (void)netlink;
/* FIXME TODO */
return -1;
}
17 changes: 17 additions & 0 deletions src/waltz/mib/fd_netdev_netlink.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* fd_netdev_netlink.h provides APIs for importing network interfaces from
Linux netlink. */

#if defined(__linux__)

#include "fd_netdev_tbl.h"
#include "../ip/fd_netlink1.h"

FD_PROTOTYPES_BEGIN

int
fd_netdev_netlink_load_table( fd_netdev_tbl_t * tbl,
fd_netlink_t * netlink );

FD_PROTOTYPES_END

#endif /* defined(__linux__) */
Loading

0 comments on commit 34e546b

Please sign in to comment.