![]() |
The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
|
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/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.__unnamed20__ |
| struct | fr_bio_dedup_entry_s.__unnamed20__.__unnamed22__ |
| 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 : uint8_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 fr_cmp_ret_t | _entry_cmp (void const *one, void const *two) |
| 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. | |
| 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. | |
| 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". | |
| 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. | |
| static ssize_t | fr_bio_dedup_buffer_write (fr_bio_dedup_t *my) |
| Write data from our local buffer to the next bio. | |
| void | fr_bio_dedup_entry_cancel (fr_bio_t *bio, fr_bio_dedup_entry_t *item) |
| Cancel one item. | |
| 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. | |
| static ssize_t | fr_bio_dedup_flush_pending (fr_bio_dedup_t *my) |
| Flush any packets in the pending queue. | |
| 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. | |
| static void | fr_bio_dedup_replied (fr_bio_dedup_t *my, fr_bio_dedup_entry_t *item) |
| Move an item from active to replied. | |
| 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. | |
| static int | fr_bio_dedup_shutdown (fr_bio_t *bio) |
| Remove the dedup cache. | |
| static void | fr_bio_dedup_timer (UNUSED fr_timer_list_t *tl, fr_time_t now, void *uctx) |
| Expire an entry when its timer fires. | |
| static int | fr_bio_dedup_timer_reset (fr_bio_dedup_t *my) |
| Reset the timer after changing the rb tree. | |
| 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. | |
| 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. | |
| 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. | |
| static int | fr_bio_dedup_write_resume (fr_bio_t *bio) |
| Resume writes. | |
Binary IO abstractions for deduping packets.
The dedup BIO receives packets from the network, and allows for deduplication of requests, so that duplicate requests are only processed once. In addition, if a reply is available, a duplicate request will result in a duplicate reply. The actual deduplication tree / table has to be maintained by the calling application, as packet comparisons for deduplication is very protocol-specific. The purpose of the dedup BIO is to abstract all of the common support functions around this limitation.
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.
| struct fr_bio_dedup_entry_s |
Collaboration diagram for fr_bio_dedup_entry_s:| Data Fields | ||
|---|---|---|
| union fr_bio_dedup_entry_s.__unnamed20__ | __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 |
| union fr_bio_dedup_entry_s.__unnamed20__ |
| Data Fields | ||
|---|---|---|
| struct fr_bio_dedup_entry_s.__unnamed20__.__unnamed22__ | __unnamed__ | |
| struct fr_bio_dedup_entry_s.__unnamed20__.__unnamed22__ |
| Data Fields | ||
|---|---|---|
| fr_rb_node_t | node | for the expiry timers |
| struct fr_bio_dedup_s |
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_timer_t * | 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 |
| typedef struct fr_bio_dedup_list_s fr_bio_dedup_list_t |
| typedef struct fr_bio_dedup_s fr_bio_dedup_t |
| enum fr_bio_dedup_state_t : uint8_t |
|
static |
| 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 1117 of file dedup.c.
Here is the call graph for this function:
Here is the caller graph for this function:
|
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 676 of file dedup.c.
Here is the call graph for this function:
Here is the caller graph for this function:
|
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 769 of file dedup.c.
Here is the call graph for this function:
Here is the caller graph for this function:
|
static |
|
static |
| void fr_bio_dedup_entry_cancel | ( | fr_bio_t * | bio, |
| fr_bio_dedup_entry_t * | item | ||
| ) |
| 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.
| bio | the binary IO handler |
| item | the dedup context from #fr_bio_dedup_respond_t |
| expires | the new expiry time |
Definition at line 1031 of file dedup.c.
Here is the call graph for this function:
Here is the caller graph for this function:
|
static |
|
static |
|
static |
| 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.
| bio | the binary IO handler |
| item | the dedup context from #fr_bio_dedup_sent_t |
Definition at line 212 of file dedup.c.
Here is the call graph for this function:
Here is the caller graph for this function:
|
static |
|
static |
|
static |
|
inlinestatic |
|
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 866 of file dedup.c.
Here is the call graph for this function:
Here is the caller graph for this function:
|
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 589 of file dedup.c.
Here is the call graph for this function:
Here is the caller graph for this function:
|
static |
Resume writes.
Write the rest of any partly written reply or data, and then write the replies on the pending list.
Definition at line 798 of file dedup.c.
Here is the call graph for this function:
Here is the caller graph for this function:
1.9.8