The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Data Structures | Macros | Typedefs | Enumerations | Functions
dedup.c File Reference

Binary IO abstractions for deduping packets. More...

#include <freeradius-devel/bio/bio_priv.h>
#include <freeradius-devel/bio/null.h>
#include <freeradius-devel/bio/buf.h>
#include <freeradius-devel/util/rb.h>
#include <freeradius-devel/util/dlist.h>
#include <freeradius-devel/bio/dedup.h>
+ Include dependency graph for dedup.c:

Go to the source code of this file.

Data Structures

struct  fr_bio_dedup_entry_s
 
union  fr_bio_dedup_entry_s.__unnamed5__
 
struct  fr_bio_dedup_entry_s.__unnamed5__.__unnamed7__
 
struct  fr_bio_dedup_s
 

Macros

#define _BIO_DEDUP_PRIVATE
 

Typedefs

typedef struct fr_bio_dedup_list_s fr_bio_dedup_list_t
 
typedef struct fr_bio_dedup_s fr_bio_dedup_t
 

Enumerations

enum  fr_bio_dedup_state_t {
  FR_BIO_DEDUP_STATE_FREE ,
  FR_BIO_DEDUP_STATE_ACTIVE ,
  FR_BIO_DEDUP_STATE_PENDING ,
  FR_BIO_DEDUP_STATE_REPLIED ,
  FR_BIO_DEDUP_STATE_PARTIAL ,
  FR_BIO_DEDUP_STATE_CANCELLED
}
 

Functions

static int8_t _entry_cmp (void const *one, void const *two)
 
fr_bio_tfr_bio_dedup_alloc (TALLOC_CTX *ctx, size_t max_saved, fr_bio_dedup_receive_t receive, fr_bio_dedup_release_t release, fr_bio_dedup_get_item_t get_item, fr_bio_dedup_config_t const *cfg, fr_bio_t *next)
 Allocate a fr_bio_dedup_t. More...
 
static ssize_t fr_bio_dedup_blocked (fr_bio_dedup_t *my, fr_bio_dedup_entry_t *item, ssize_t rcode)
 The write is blocked. More...
 
static ssize_t fr_bio_dedup_blocked_data (fr_bio_dedup_t *my, uint8_t const *buffer, size_t size, ssize_t rcode)
 The write is blocked, but we don't have "item". More...
 
static int fr_bio_dedup_buffer_save (fr_bio_dedup_t *my, uint8_t const *buffer, size_t size, ssize_t rcode)
 Save partially written data to our local buffer. More...
 
static ssize_t fr_bio_dedup_buffer_write (fr_bio_dedup_t *my)
 Write data from our local buffer to the next bio. More...
 
static int fr_bio_dedup_destructor (fr_bio_dedup_t *my)
 Remove the dedup cache. More...
 
void fr_bio_dedup_entry_cancel (fr_bio_t *bio, fr_bio_dedup_entry_t *item)
 Cancel one item. More...
 
int fr_bio_dedup_entry_extend (fr_bio_t *bio, fr_bio_dedup_entry_t *item, fr_time_t expires)
 Extend the expiry time for an entry. More...
 
static ssize_t fr_bio_dedup_flush_pending (fr_bio_dedup_t *my)
 Flush any packets in the pending queue. More...
 
static ssize_t fr_bio_dedup_read (fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
 
static void fr_bio_dedup_release (fr_bio_dedup_t *my, fr_bio_dedup_entry_t *item, fr_bio_dedup_release_reason_t reason)
 Release an entry back to the free list. More...
 
static void fr_bio_dedup_replied (fr_bio_dedup_t *my, fr_bio_dedup_entry_t *item)
 Move an item from active to replied. More...
 
ssize_t fr_bio_dedup_respond (fr_bio_t *bio, fr_bio_dedup_entry_t *item)
 Resend a reply when we receive a duplicate request. More...
 
static void fr_bio_dedup_timer (UNUSED fr_event_list_t *el, fr_time_t now, void *uctx)
 Expire an entry when its timer fires. More...
 
static int fr_bio_dedup_timer_reset (fr_bio_dedup_t *my)
 Reset the timer after changing the rb tree. More...
 
static void fr_bio_dedup_timer_reset_item (fr_bio_dedup_t *my, fr_bio_dedup_entry_t *item)
 
static ssize_t fr_bio_dedup_write (fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
 Write raw data to the bio. More...
 
static ssize_t fr_bio_dedup_write_data (fr_bio_t *bio, void *packet_ctx, const void *buffer, size_t size)
 There's a partial block of data written. More...
 
static ssize_t fr_bio_dedup_write_partial (fr_bio_t *bio, void *packet_ctx, const void *buffer, size_t size)
 There's a partial packet written. More...
 

Detailed Description

Binary IO abstractions for deduping packets.

Id
fbf88c1a785fa0f8894f5029d0e2871a8c49f745

The dedup BIO receives packets from the network, and allows for deduplication of replies. The actual deduplication tree / table has to be maintained by the calling application, as packet dedup is very protocol-specific. The purpose of the dedup BIO is to abstract all of the common support functions around this requirement.

When packets are read() from the next bio, the fr_bio_dedup_receive_t callback is run. It tells the BIO whether or not the packet should be received, and whether or not the packet should be returned to the caller. The receive callback is also passed a fr_bio_dedup_entry_t pointer, where the packet_ctx, packet, and size are already filled out. This entry is used to correlate requests and replies.

When packets are write() to the network, the fr_bio_dedup_get_item_t callback is called to get the previously cached fr_bio_dedup_entry_t pointer. This is because there is no generic way to get an additional context to this BIO via the write() routine. i.e. the packet_ctx for write() may include things like src/dst ip/port, and therefore can't always be an fr_bio_dedup_entry_t. The caller should associate the fr_bio_dedup_entry_t with the packet_ctx for the reply. The get_item() routine can then return the entry.

For simplicity, the next bio should be a memory one. That way the read() can read more than one packet if necessary. And the write() can cache a partial packet if it blocks.

The entry needs to be cached in order to maintain the internal tracking used by the dedup BIO.

On client retransmit, the fr_bio_dedup_receive_t callback is run, just as if it is a new packet. The dedup BIO does not know if the received data is a new packet until the fr_bio_dedup_receive_t callback says so. On duplicate client request, the fr_bio_dedup_receive_t callback can call fr_bio_dedup_respond() to send a duplicate reply. That call bypasses the normal dedup stack, and writes directly to the next bio.

The calling application can also call fr_bio_dedup_respond() as soon as it has a reply. i.e. skip the BIO write() call. That works, and is safe.

The dedup BIO tracks a number of lists / trees internally. Packets which are received but which have no reply are in an "active" list. Packets which have a reply are in an "expired" RB tree, where a timer is set to expire packets. If a write() call results in a partial write, that packet is put into a "partially written" state. If multiple calls to write() are done when writing is blocked, the replies are put into a "pending" state.

The calling application can always call fr_bio_dedup_cancel() to cancel or expire a packet. This call is safe, and can be made at any time, no matter what state the packet is in.

Definition in file dedup.c.


Data Structure Documentation

◆ fr_bio_dedup_entry_s

struct fr_bio_dedup_entry_s

Definition at line 95 of file dedup.c.

+ Collaboration diagram for fr_bio_dedup_entry_s:
Data Fields
union fr_bio_dedup_entry_s __unnamed__
fr_rb_node_t dedup user managed dedup node
fr_time_t expires when this entry expires
fr_bio_dedup_t * my so we can get to it from the event timer callback
uint8_t * packet cached packet data for finding duplicates

cached packet data.

void * packet_ctx packet_ctx for dedup purposes
size_t packet_size size of the cached packet data
uint8_t * reply reply cached by the application
void * reply_ctx reply ctx
size_t reply_size size of the cached reply
fr_bio_dedup_state_t state which tree or list this item is in
void * uctx user-writable context

◆ fr_bio_dedup_entry_s.__unnamed5__

union fr_bio_dedup_entry_s.__unnamed5__

Definition at line 106 of file dedup.c.

Data Fields
__unnamed5__ __unnamed__

◆ fr_bio_dedup_entry_s.__unnamed5__.__unnamed7__

struct fr_bio_dedup_entry_s.__unnamed5__.__unnamed7__

Definition at line 107 of file dedup.c.

Data Fields
fr_rb_node_t node for the expiry timers

◆ fr_bio_dedup_s

struct fr_bio_dedup_s

Definition at line 121 of file dedup.c.

+ Collaboration diagram for fr_bio_dedup_s:
Data Fields
fr_bio_buf_t buffer
fr_bio_dedup_config_t config
fr_event_list_t * el
fr_event_timer_t const * ev
fr_bio_dedup_entry_t * first
FR_BIO_COMMON
fr_bio_dedup_get_item_t get_item turn a packet_ctx into a fr_bio_dedup_entry_t
fr_bio_dedup_entry_t * partial
fr_rb_tree_t rb expire list
fr_bio_dedup_receive_t receive called when we receive a potentially new packet
fr_bio_dedup_release_t release called to release a packet

Macro Definition Documentation

◆ _BIO_DEDUP_PRIVATE

#define _BIO_DEDUP_PRIVATE

Definition at line 69 of file dedup.c.

Typedef Documentation

◆ fr_bio_dedup_list_t

typedef struct fr_bio_dedup_list_s fr_bio_dedup_list_t

Definition at line 1 of file dedup.c.

◆ fr_bio_dedup_t

Definition at line 1 of file dedup.c.

Enumeration Type Documentation

◆ fr_bio_dedup_state_t

Enumerator
FR_BIO_DEDUP_STATE_FREE 
FR_BIO_DEDUP_STATE_ACTIVE 

Received, but not replied.

FR_BIO_DEDUP_STATE_PENDING 

Have a reply, but we're trying to write it out.

FR_BIO_DEDUP_STATE_REPLIED 

Replied, and waiting for it to expire.

FR_BIO_DEDUP_STATE_PARTIAL 

Partially written.

FR_BIO_DEDUP_STATE_CANCELLED 

Partially written, and then cancelled.

Definition at line 86 of file dedup.c.

Function Documentation

◆ _entry_cmp()

static int8_t _entry_cmp ( void const *  one,
void const *  two 
)
static

Definition at line 918 of file dedup.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_bio_dedup_alloc()

fr_bio_t* fr_bio_dedup_alloc ( TALLOC_CTX *  ctx,
size_t  max_saved,
fr_bio_dedup_receive_t  receive,
fr_bio_dedup_release_t  release,
fr_bio_dedup_get_item_t  get_item,
fr_bio_dedup_config_t const *  cfg,
fr_bio_t next 
)

Allocate a fr_bio_dedup_t.

Definition at line 1035 of file dedup.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_bio_dedup_blocked()

static ssize_t fr_bio_dedup_blocked ( fr_bio_dedup_t my,
fr_bio_dedup_entry_t item,
ssize_t  rcode 
)
static

The write is blocked.

We couldn't write out the entire packet, the bio is blocked. Don't write anything else until we become unblocked!

Do NOT free the timer. We can still expire old entries. This newly written entry usually ends up as the last item in the RB tree.

Definition at line 651 of file dedup.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_bio_dedup_blocked_data()

static ssize_t fr_bio_dedup_blocked_data ( fr_bio_dedup_t my,
uint8_t const *  buffer,
size_t  size,
ssize_t  rcode 
)
static

The write is blocked, but we don't have "item".

We couldn't write out the entire packet, the bio is blocked. Don't write anything else until we become unblocked!

Do NOT free the timer. We can still expire old entries. This newly written entry usually ends up as the last item in the RB tree.

Definition at line 739 of file dedup.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_bio_dedup_buffer_save()

static int fr_bio_dedup_buffer_save ( fr_bio_dedup_t my,
uint8_t const *  buffer,
size_t  size,
ssize_t  rcode 
)
static

Save partially written data to our local buffer.

Definition at line 509 of file dedup.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_bio_dedup_buffer_write()

static ssize_t fr_bio_dedup_buffer_write ( fr_bio_dedup_t my)
static

Write data from our local buffer to the next bio.

Definition at line 530 of file dedup.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_bio_dedup_destructor()

static int fr_bio_dedup_destructor ( fr_bio_dedup_t my)
static

Remove the dedup cache.

Definition at line 1008 of file dedup.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_bio_dedup_entry_cancel()

void fr_bio_dedup_entry_cancel ( fr_bio_t bio,
fr_bio_dedup_entry_t item 
)

Cancel one item.

Parameters
biothe binary IO handler
itemthe dedup context from #fr_bio_dedup_respond_t

Definition at line 934 of file dedup.c.

+ Here is the call graph for this function:

◆ fr_bio_dedup_entry_extend()

int fr_bio_dedup_entry_extend ( fr_bio_t bio,
fr_bio_dedup_entry_t item,
fr_time_t  expires 
)

Extend the expiry time for an entry.

Parameters
biothe binary IO handler
itemthe dedup context from #fr_bio_dedup_respond_t
expiresthe new expiry time
Returns
  • <0 error
  • 0 success

Definition at line 952 of file dedup.c.

+ Here is the call graph for this function:

◆ fr_bio_dedup_flush_pending()

static ssize_t fr_bio_dedup_flush_pending ( fr_bio_dedup_t my)
static

Flush any packets in the pending queue.

Definition at line 432 of file dedup.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_bio_dedup_read()

static ssize_t fr_bio_dedup_read ( fr_bio_t bio,
void *  packet_ctx,
void *  buffer,
size_t  size 
)
static

Definition at line 852 of file dedup.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_bio_dedup_release()

static void fr_bio_dedup_release ( fr_bio_dedup_t my,
fr_bio_dedup_entry_t item,
fr_bio_dedup_release_reason_t  reason 
)
static

Release an entry back to the free list.

Definition at line 375 of file dedup.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_bio_dedup_replied()

static void fr_bio_dedup_replied ( fr_bio_dedup_t my,
fr_bio_dedup_entry_t item 
)
static

Move an item from active to replied.

Note that we don't update any timers. The caller is responsible for that.

Definition at line 179 of file dedup.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_bio_dedup_respond()

ssize_t fr_bio_dedup_respond ( fr_bio_t bio,
fr_bio_dedup_entry_t item 
)

Resend a reply when we receive a duplicate request.

This function should be called by the respond() callback to re-send a duplicate reply.

It can also be called by the application when it first has a response to the request.

Parameters
biothe binary IO handler
itemthe dedup context from #fr_bio_dedup_sent_t
Returns
  • <0 on error
  • 0 for "wrote no data"
  • >0 for "wrote data".

Definition at line 213 of file dedup.c.

+ Here is the call graph for this function:

◆ fr_bio_dedup_timer()

static void fr_bio_dedup_timer ( UNUSED fr_event_list_t el,
fr_time_t  now,
void *  uctx 
)
static

Expire an entry when its timer fires.

Todo:
  • expire items from the pending list, too

Definition at line 763 of file dedup.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_bio_dedup_timer_reset()

static int fr_bio_dedup_timer_reset ( fr_bio_dedup_t my)
static

Reset the timer after changing the rb tree.

Definition at line 332 of file dedup.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_bio_dedup_timer_reset_item()

static void fr_bio_dedup_timer_reset_item ( fr_bio_dedup_t my,
fr_bio_dedup_entry_t item 
)
inlinestatic

Definition at line 167 of file dedup.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_bio_dedup_write()

static ssize_t fr_bio_dedup_write ( fr_bio_t bio,
void *  packet_ctx,
void const *  buffer,
size_t  size 
)
static

Write raw data to the bio.

This function is largely a duplicate of fr_bio_dedup_respond(). Except due to the BIO API, it can be passed a NULL buffer (for flushing the BIOs), and it can't be passed a fr_bio_dedup_entry_t, and instead has to be passed a "void *packet_ctx".

The caller is free to ignore this function,

Definition at line 799 of file dedup.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_bio_dedup_write_data()

static ssize_t fr_bio_dedup_write_data ( fr_bio_t bio,
void *  packet_ctx,
const void *  buffer,
size_t  size 
)
static

There's a partial block of data written.

Write all of that data first, before writing another packet.

Definition at line 704 of file dedup.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_bio_dedup_write_partial()

static ssize_t fr_bio_dedup_write_partial ( fr_bio_t bio,
void *  packet_ctx,
const void *  buffer,
size_t  size 
)
static

There's a partial packet written.

Write all of that one first, before writing another packet.

The packet can either be cancelled, or IO blocked. In either case, we must write this packet before we can write another one.

Definition at line 570 of file dedup.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function: