The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Data Structures | Macros | Functions | Variables
cluster.c File Reference
#include <freeradius-devel/util/debug.h>
#include <freeradius-devel/server/cf_parse.h>
#include <freeradius-devel/util/fifo.h>
#include <freeradius-devel/util/misc.h>
#include <freeradius-devel/util/rand.h>
#include <freeradius-devel/util/time.h>
#include "config.h"
#include "base.h"
#include "cluster.h"
#include "crc16.h"
+ Include dependency graph for cluster.c:

Go to the source code of this file.

Data Structures

struct  cluster_nodes_live_t
 Live nodes data, used to perform weighted random selection of alternative nodes. More...
 
struct  cluster_nodes_live_t.node
 
struct  fr_redis_cluster
 A redis cluster. More...
 
struct  fr_redis_cluster_key_slot_s
 Indexes in the fr_redis_cluster_node_t array for a single key slot. More...
 
struct  fr_redis_cluster_node_s
 A Redis cluster node. More...
 

Macros

#define CLOSED_PERIOD   10000
 How recently must the closed have. More...
 
#define CLOSED_WEIGHT   1
 What weight to give to nodes that. More...
 
#define FAILED_PERIOD   10000
 How recently must the spawn failure. More...
 
#define FAILED_WEIGHT   1
 What weight to give to nodes that. More...
 
#define KEY_SLOTS   16384
 Maximum number of keyslots (should not change). More...
 
#define MAX_SLAVES   5
 Maximum number of slaves associated. More...
 
#define RELEASED_MIN_WEIGHT   1000
 Minimum weight to assign to node. More...
 
#define RELEASED_PERIOD   10000
 Period after which we don't care. More...
 
#define SET_ACTIVE(_node)
 
#define SET_ADDR(_addr, _map)
 
#define SET_INACTIVE(_node)
 

Functions

static int _cluster_conn_free (fr_redis_conn_t *conn)
 Callback for freeing a Redis connection. More...
 
static int8_t _cluster_node_cmp (void const *one, void const *two)
 Compare two redis nodes to check equality. More...
 
static void _cluster_node_conf_apply (fr_pool_t *pool, void *opaque)
 Reconnect callback to apply new pool config. More...
 
static int _fr_redis_cluster_free (fr_redis_cluster_t *cluster)
 Destroy mutex associated with cluster slots structure. More...
 
static uint16_t cluster_key_hash (uint8_t const *key, size_t key_len)
 Resolve key to key slot. More...
 
static fr_redis_cluster_rcode_t cluster_map_apply (fr_redis_cluster_t *cluster, redisReply *reply)
 Apply a cluster map received from a cluster node. More...
 
static fr_redis_cluster_rcode_t cluster_map_get (redisReply **out, fr_redis_conn_t *conn)
 Learn a new cluster layout by querying the node that issued the -MOVE. More...
 
static int cluster_map_node_validate (redisReply *node, int map_idx, int node_idx)
 Validate a cluster map node entry. More...
 
static fr_redis_cluster_rcode_t cluster_node_conf_from_redirect (uint16_t *key_slot, fr_socket_t *node_addr, redisReply *redirect)
 Parse a -MOVED or -ASK redirect. More...
 
static fr_redis_cluster_rcode_t cluster_node_connect (fr_redis_cluster_t *cluster, fr_redis_cluster_node_t *node)
 Establish a connection to a cluster node. More...
 
static int cluster_node_find_live (fr_redis_cluster_node_t **live_node, fr_redis_conn_t **live_conn, request_t *request, fr_redis_cluster_t *cluster, fr_redis_cluster_node_t *skip)
 Attempt to find a live pool in the cluster. More...
 
static fr_redis_cluster_rcode_t cluster_node_ping (request_t *request, fr_redis_cluster_node_t *node, fr_redis_conn_t *conn)
 Issue a ping request against a cluster node. More...
 
static int cluster_node_pool_health (fr_time_t now, fr_pool_state_t const *state)
 Try to determine the health of a cluster node passively by examining its pool state. More...
 
static fr_redis_cluster_rcode_t cluster_redirect (fr_redis_cluster_node_t **out, fr_redis_cluster_t *cluster, redisReply *reply)
 Retrieve or associate a node with the server indicated in the redirect. More...
 
fr_redis_cluster_tfr_redis_cluster_alloc (TALLOC_CTX *ctx, CONF_SECTION *module, fr_redis_conf_t *conf, bool triggers_enabled, char const *log_prefix, char const *trigger_prefix, fr_pair_list_t *trigger_args)
 Allocate and initialise a new cluster structure. More...
 
void * fr_redis_cluster_conn_create (TALLOC_CTX *ctx, void *instance, fr_time_delta_t timeout)
 Create a new connection to a Redis node. More...
 
int fr_redis_cluster_ipaddr (fr_ipaddr_t *out, fr_redis_cluster_node_t const *node)
 Return the ipaddr of a particular node. More...
 
fr_redis_cluster_node_t const * fr_redis_cluster_master (fr_redis_cluster_t *cluster, fr_redis_cluster_key_slot_t const *key_slot)
 Return the master node that would be used for a particular key. More...
 
bool fr_redis_cluster_min_version (fr_redis_cluster_t *cluster, char const *min_version)
 Check if members of the cluster are above a certain version. More...
 
ssize_t fr_redis_cluster_node_addr_by_role (TALLOC_CTX *ctx, fr_socket_t *out[], fr_redis_cluster_t *cluster, bool is_master, bool is_slave)
 Return an array of IP addresses belonging to masters or slaves. More...
 
int fr_redis_cluster_pool_by_node_addr (fr_pool_t **pool, fr_redis_cluster_t *cluster, fr_socket_t *node_addr, bool create)
 Get the pool associated with a node in the cluster. More...
 
int fr_redis_cluster_port (uint16_t *out, fr_redis_cluster_node_t const *node)
 Return the port of a particular node. More...
 
fr_redis_cluster_rcode_t fr_redis_cluster_remap (request_t *request, fr_redis_cluster_t *cluster, fr_redis_conn_t *conn)
 Perform a runtime remap of the cluster. More...
 
fr_redis_cluster_node_t const * fr_redis_cluster_slave (fr_redis_cluster_t *cluster, fr_redis_cluster_key_slot_t const *key_slot, uint8_t slave_num)
 Return the slave node that would be used for a particular key. More...
 
fr_redis_cluster_key_slot_t const * fr_redis_cluster_slot_by_key (fr_redis_cluster_t *cluster, request_t *request, uint8_t const *key, size_t key_len)
 Implements the key slot selection scheme used by freeradius. More...
 
fr_redis_rcode_t fr_redis_cluster_state_init (fr_redis_cluster_state_t *state, fr_redis_conn_t **conn, fr_redis_cluster_t *cluster, request_t *request, uint8_t const *key, size_t key_len, bool read_only)
 Resolve a key to a pool, and reserve a connection in that pool. More...
 
fr_redis_rcode_t fr_redis_cluster_state_next (fr_redis_cluster_state_t *state, fr_redis_conn_t **conn, fr_redis_cluster_t *cluster, request_t *request, fr_redis_rcode_t status, redisReply **reply)
 Get the next connection to attempt a command against. More...
 

Variables

fr_table_num_sorted_t const fr_redis_cluster_rcodes_table []
 
size_t fr_redis_cluster_rcodes_table_len = NUM_ELEMENTS(fr_redis_cluster_rcodes_table)
 

Data Structure Documentation

◆ cluster_nodes_live_t

struct cluster_nodes_live_t

Live nodes data, used to perform weighted random selection of alternative nodes.

Definition at line 199 of file cluster.c.

Data Fields
uint8_t next Next index in live.
struct cluster_nodes_live_t node[UINT8_MAX - 1] Array of live node IDs (and weights).
uint8_t skip

◆ cluster_nodes_live_t.node

struct cluster_nodes_live_t.node

Definition at line 200 of file cluster.c.

Data Fields
unsigned int cumulative Cumulative weight.
uint8_t id Node ID.
fr_pool_state_t const * pool_state Connection pool stats.

◆ fr_redis_cluster

struct fr_redis_cluster

A redis cluster.

Holds all the structures and collections of nodes, to represent a Redis cluster.

Definition at line 251 of file cluster.c.

+ Collaboration diagram for fr_redis_cluster:
Data Fields
fr_redis_conf_t * conf Base configuration data such as the database number and passwords.
fr_fifo_t * free_nodes Queue of free nodes (or nodes waiting to be reused).
fr_redis_cluster_key_slot_t key_slot[KEY_SLOTS] Lookup table of slots to pools.
fr_redis_cluster_key_slot_t key_slot_pending[KEY_SLOTS] Pending key slot table.
fr_time_t last_updated Last time the cluster mappings were updated.
char const * log_prefix What to prepend to log messages.
CONF_SECTION * module Module configuration.
pthread_mutex_t mutex Mutex to synchronise cluster operations.
fr_redis_cluster_node_t * node Structure containing a node id, its address and a pool of its connections.
bool remap_needed Set true if at least one cluster node is definitely unreachable.

Set false on successful remap.

bool remapping True when cluster is being remapped.
fr_pair_list_t trigger_args Arguments to pass to triggers.
char const * trigger_prefix Trigger path.
bool triggers_enabled Whether triggers are enabled.
fr_rb_tree_t * used_nodes Tree of used nodes.

◆ fr_redis_cluster_key_slot_s

struct fr_redis_cluster_key_slot_s

Indexes in the fr_redis_cluster_node_t array for a single key slot.

When dealing with 16K entries, space is a concern. It's significantly more memory efficient to use 8bit indexes than 64bit pointers for each of the key slot to node mappings.

Definition at line 241 of file cluster.c.

Data Fields
uint8_t master R/W node (master) for this key slot.
uint8_t slave[MAX_SLAVES] R/O node (slave) for this key slot.
uint8_t slave_num Number of slaves associated with this key slot.

◆ fr_redis_cluster_node_s

struct fr_redis_cluster_node_s

A Redis cluster node.

Passed as opaque data to pools which open connection to nodes.

Definition at line 213 of file cluster.c.

+ Collaboration diagram for fr_redis_cluster_node_s:
Data Fields
fr_socket_t addr Current node address.
fr_redis_cluster_t * cluster Common configuration (database number, password, etc..).
uint8_t id Node ID (index in node array).
bool is_active Whether this node is in the active node set.
bool is_master Whether this node is a master.

This is needed for commands like 'KEYS', which we need to issue to every master in the cluster.

char name[INET6_ADDRSTRLEN] Buffer to hold IP string.

text for debug messages.

fr_socket_t pending_addr New node address to be applied when the pool is reconnected.
fr_pool_t * pool Pool associated with this node.
CONF_SECTION * pool_cs Pool configuration section associated with node.
fr_rb_node_t rbnode Entry into the tree of redis nodes.

Macro Definition Documentation

◆ CLOSED_PERIOD

#define CLOSED_PERIOD   10000

How recently must the closed have.

occurred for us to care.

Definition at line 180 of file cluster.c.

◆ CLOSED_WEIGHT

#define CLOSED_WEIGHT   1

What weight to give to nodes that.

had a connection closed recently.

Definition at line 183 of file cluster.c.

◆ FAILED_PERIOD

#define FAILED_PERIOD   10000

How recently must the spawn failure.

occurred for us to care.

Definition at line 186 of file cluster.c.

◆ FAILED_WEIGHT

#define FAILED_WEIGHT   1

What weight to give to nodes that.

had a spawn failure recently.

Definition at line 189 of file cluster.c.

◆ KEY_SLOTS

#define KEY_SLOTS   16384

Maximum number of keyslots (should not change).

Definition at line 171 of file cluster.c.

◆ MAX_SLAVES

#define MAX_SLAVES   5

Maximum number of slaves associated.

with a keyslot.

Definition at line 174 of file cluster.c.

◆ RELEASED_MIN_WEIGHT

#define RELEASED_MIN_WEIGHT   1000

Minimum weight to assign to node.

Definition at line 195 of file cluster.c.

◆ RELEASED_PERIOD

#define RELEASED_PERIOD   10000

Period after which we don't care.

about when the last connection was released.

Definition at line 193 of file cluster.c.

◆ SET_ACTIVE

#define SET_ACTIVE (   _node)
Value:
do { \
(_node)->is_active = true; \
fr_rb_insert(cluster->used_nodes, _node); \
fr_fifo_pop(cluster->free_nodes); \
active[(_node)->id] = true; \
rollback[r++] = (_node)->id; \
} while (0)

◆ SET_ADDR

#define SET_ADDR (   _addr,
  _map 
)
Value:
do { \
int _ret; \
_ret = fr_inet_pton(&_addr.inet.dst_ipaddr, _map->element[0]->str, _map->element[0]->len, AF_UNSPEC, true, true);\
fr_assert(_ret == 0);\
_addr.inet.dst_port = _map->element[1]->integer; \
} while (0)
int fr_inet_pton(fr_ipaddr_t *out, char const *value, ssize_t inlen, int af, bool resolve, bool mask)
Simple wrapper to decide whether an IP value is v4 or v6 and call the appropriate parser.
Definition: inet.c:778

◆ SET_INACTIVE

#define SET_INACTIVE (   _node)
Value:
do { \
(_node)->is_active = false; \
(_node)->is_master = false; \
fr_rb_delete(cluster->used_nodes, _node); \
fr_fifo_push(cluster->free_nodes, _node); \
} while (0)

Function Documentation

◆ _cluster_conn_free()

static int _cluster_conn_free ( fr_redis_conn_t conn)
static

Callback for freeing a Redis connection.

Parameters
[in]connto free.
Returns
0.

Definition at line 1452 of file cluster.c.

+ Here is the caller graph for this function:

◆ _cluster_node_cmp()

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

Compare two redis nodes to check equality.

Parameters
[in]onefirst node.
[in]twosecond node.
Returns
CMP(one, two)

Definition at line 323 of file cluster.c.

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

◆ _cluster_node_conf_apply()

static void _cluster_node_conf_apply ( fr_pool_t pool,
void *  opaque 
)
static

Reconnect callback to apply new pool config.

Parameters
[in]poolto apply new configuration to.
[in]opaquedata passed to the connection pool.

Definition at line 340 of file cluster.c.

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

◆ _fr_redis_cluster_free()

static int _fr_redis_cluster_free ( fr_redis_cluster_t cluster)
static

Destroy mutex associated with cluster slots structure.

Parameters
clusterbeing freed.
Returns
0

Definition at line 2185 of file cluster.c.

+ Here is the caller graph for this function:

◆ cluster_key_hash()

static uint16_t cluster_key_hash ( uint8_t const *  key,
size_t  key_len 
)
static

Resolve key to key slot.

Identical to the example implementation, except it uses memchr which will be faster, and isn't so needlessly complex.

Parameters
[in]keyto resolve.
[in]key_lenlength of key.
Returns
key slot index for the key.

Definition at line 299 of file cluster.c.

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

◆ cluster_map_apply()

static fr_redis_cluster_rcode_t cluster_map_apply ( fr_redis_cluster_t cluster,
redisReply *  reply 
)
static

Apply a cluster map received from a cluster node.

Note
Errors may be retrieved with fr_strerror().
Must be called with the cluster mutex held.

Key slot range structure

  [0] -> key slot range 0
      [0] -> key_slot_start
      [1] -> key_slot_end
      [2] -> master_node
          [0] -> master 0 ip (string)
          [1] -> master 0 port (number)
      [3..n] -> slave_node(s)
  [1] -> key slot range 1)
      [0]  -> key_slot_start
      [1] -> key_slot_end
      [2] -> master_node
          [0] -> master 1 ip (string)
          [1] -> master 1 port (number)
      [3..n] -> slave_node(s)
  [n] -> key slot range n
      [0] -> key_slot_start
      [1] -> key_slot_end
      [2] -> master_node
          [0] -> master n ip (string)
          [1] -> master n port (number)
      [3..n] -> slave_node(s)
Parameters
[in,out]clusterto apply map to.
[in]replyfrom cluster_map_get.
Returns
  • FR_REDIS_CLUSTER_RCODE_SUCCESS on success.
  • FR_REDIS_CLUSTER_RCODE_FAILED on failure.
  • FR_REDIS_CLUSTER_RCODE_NO_CONNECTION connection failure.
  • FR_REDIS_CLUSTER_RCODE_BAD_INPUT if the map didn't provide nodes for all keyslots.

Definition at line 538 of file cluster.c.

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

◆ cluster_map_get()

static fr_redis_cluster_rcode_t cluster_map_get ( redisReply **  out,
fr_redis_conn_t conn 
)
static

Learn a new cluster layout by querying the node that issued the -MOVE.

Also validates the response from the Redis cluster, so we can be sure that it's well formed, before doing more expensive operations.

Note
Errors may be retrieved with fr_strerror().
Parameters
[out]outWhere to write cluster map.
[in]connto use for learning the new cluster map.
Returns
  • FR_REDIS_CLUSTER_RCODE_IGNORED if 'cluster slots' returned an error (indicating clustering not supported).
  • FR_REDIS_CLUSTER_RCODE_SUCCESS on success.
  • FR_REDIS_CLUSTER_RCODE_FAILED if issuing the command resulted in an error.
  • FR_REDIS_CLUSTER_RCODE_NO_CONNECTION connection failure.
  • FR_REDIS_CLUSTER_RCODE_BAD_INPUT on validation failure (bad data returned from Redis).

Definition at line 864 of file cluster.c.

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

◆ cluster_map_node_validate()

static int cluster_map_node_validate ( redisReply *  node,
int  map_idx,
int  node_idx 
)
static

Validate a cluster map node entry.

Note
Errors may be retrieved with fr_strerror().
In a separate function, as it's called for both master and slave nodes.
Parameters
[in]nodewe're validating.
[in]map_idxwe're processing.
[in]node_idxwe're processing.
Returns
  • FR_REDIS_CLUSTER_RCODE_SUCCESS on success.
  • FR_REDIS_CLUSTER_RCODE_BAD_INPUT on validation failure (bad data returned from Redis).

Definition at line 786 of file cluster.c.

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

◆ cluster_node_conf_from_redirect()

static fr_redis_cluster_rcode_t cluster_node_conf_from_redirect ( uint16_t key_slot,
fr_socket_t node_addr,
redisReply *  redirect 
)
static

Parse a -MOVED or -ASK redirect.

Converts the body of the -MOVED or -ASK error into an IPv4/6 address and port.

Parameters
[out]key_slotvalue extracted from redirect string (may be NULL).
[out]node_addrRedis node ipaddr and port extracted from redirect string.
[in]redirectto process.
Returns
  • FR_REDIS_CLUSTER_RCODE_SUCCESS on success.
  • FR_REDIS_CLUSTER_RCODE_BAD_INPUT if the server returned an invalid redirect.

Definition at line 447 of file cluster.c.

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

◆ cluster_node_connect()

static fr_redis_cluster_rcode_t cluster_node_connect ( fr_redis_cluster_t cluster,
fr_redis_cluster_node_t node 
)
static

Establish a connection to a cluster node.

Note
Must be called with the cluster mutex locked.
Configuration to use for the connection must be set in node->pending_addr, not node->cluster->conf.
Parameters
[in]clusterto search in.
[in]nodeconfig.
Returns
  • FR_REDIS_CLUSTER_RCODE_SUCCESS on success.
  • FR_REDIS_CLUSTER_RCODE_FAILED if the operation failed.

Definition at line 372 of file cluster.c.

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

◆ cluster_node_find_live()

static int cluster_node_find_live ( fr_redis_cluster_node_t **  live_node,
fr_redis_conn_t **  live_conn,
request_t request,
fr_redis_cluster_t cluster,
fr_redis_cluster_node_t skip 
)
static

Attempt to find a live pool in the cluster.

The intent here is to find pools/nodes where a connection was released the shortest time ago. Having a connection be released (vs closed) indicates that the pool is live.

We don't want to have all workers try and grab a connection to this node however, as it may still be dead (we don't know).

So we use an inverse transform sample, to weight the nodes, based on time between now and when the connection was released. Connections released closest to the current time are given a higher weighting.

Weight range is between 1 - 11,000.

  • If released > 10.0 seconds ago,information is not valid, weight 500.
  • If closed < 10.0 seconds ago, it's a bad pool, weight 1.
  • If spawn failed < 10.0 seconds ago, it's a bad pool, weight 1.
  • If a connection was released 0.0 seconds ago, weight 11,000.
  • If a connection was released 10.0 seconds ago, weight 1000.

Using the above algorithm we use the experience of other workers using the cluster to inform our alternative node selection.

Suggestions on improving live node selection appreciated.

Inverse transform sampling based roughly on the solution from this post: http://stackoverflow.com/questions/17250568/randomly-choosing-from-a-list-with-weighted-probabilities

Wikipedia page here: https://en.wikipedia.org/wiki/Inverse_transform_sampling

Note
Must be called with the cluster mutex free.
Parameters
[out]live_nodewe found.
[out]live_connto that node.
[in]requestThe current request (used for logging).
[in]clusterto search for live pools in.
[in]skipthis node (it's bad).
Returns
0 (iterates over the whole tree).

Definition at line 1311 of file cluster.c.

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

◆ cluster_node_ping()

static fr_redis_cluster_rcode_t cluster_node_ping ( request_t request,
fr_redis_cluster_node_t node,
fr_redis_conn_t conn 
)
static

Issue a ping request against a cluster node.

Establishes whether the connection to the node we have is live.

Parameters
requestThe current request.
nodeto ping.
connthe connection to ping on.
Returns
  • FR_REDIS_CLUSTER_RCODE_BAD_INPUT if we got a bad response.
  • FR_REDIS_CLUSTER_RCODE_SUCCESS on success.
  • FR_REDIS_CLUSTER_RCODE_NO_CONNECTION on connection down.

Definition at line 1244 of file cluster.c.

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

◆ cluster_node_pool_health()

static int cluster_node_pool_health ( fr_time_t  now,
fr_pool_state_t const *  state 
)
static

Try to determine the health of a cluster node passively by examining its pool state.

Returns an integer value representing the likelihood that the pool is live. Range is between 1 and 11,000.

If a weight of 1 is returned, connections from the pool should be checked (by pinging) before use.

Parameters
nowThe current time.
stateof the connection pool.
Returns
  • 1 the pool is very likely to be bad.
  • 2-11000 the pool is likely to be good, with a higher number indicating higher probability of liveness.

Definition at line 1209 of file cluster.c.

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

◆ cluster_redirect()

static fr_redis_cluster_rcode_t cluster_redirect ( fr_redis_cluster_node_t **  out,
fr_redis_cluster_t cluster,
redisReply *  reply 
)
static

Retrieve or associate a node with the server indicated in the redirect.

Note
Errors may be retrieved with fr_strerror().
Parameters
[out]outWhere to write the node representing the redirect server.
[in]clusterto draw node from.
[in]replyRedis reply containing the redirect information.
Returns
  • FR_REDIS_CLUSTER_RCODE_SUCCESS on success.
  • FR_REDIS_CLUSTER_RCODE_FAILED no more nodes available.
  • FR_REDIS_CLUSTER_RCODE_NO_CONNECTION connection failure.
  • FR_REDIS_CLUSTER_RCODE_BAD_INPUT on validation failure (bad data returned from Redis).

Definition at line 1119 of file cluster.c.

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

◆ fr_redis_cluster_alloc()

fr_redis_cluster_t* fr_redis_cluster_alloc ( TALLOC_CTX *  ctx,
CONF_SECTION module,
fr_redis_conf_t conf,
bool  triggers_enabled,
char const *  log_prefix,
char const *  trigger_prefix,
fr_pair_list_t trigger_args 
)

Allocate and initialise a new cluster structure.

This holds all the data necessary to manage a pool of pools for a specific redis cluster.

Note
Will not error out unless cs.pool.start > 0. This is consistent with other pool based modules/code.
Parameters
ctxto link the lifetime of the cluster structure to.
moduleConfiguration section to search for 'server' conf pairs in.
confBase redis server configuration. Cluster nodes share database number and password.
triggers_enabledWhether triggers should be enabled.
log_prefixCustom log prefix. Defaults to
rlm_<module> (<instance>) 
.
trigger_prefixCustom trigger prefix. Defaults to
modules.<module>.pool 
.
trigger_argsArgument pairs to pass to the trigger in addition to Connection-Pool-Server, and Connection-Pool-Port (which are always set by the cluster code).
Returns

Definition at line 2261 of file cluster.c.

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

◆ fr_redis_cluster_conn_create()

void* fr_redis_cluster_conn_create ( TALLOC_CTX *  ctx,
void *  instance,
fr_time_delta_t  timeout 
)

Create a new connection to a Redis node.

Parameters
[in]ctxto allocate connection structure in. Will be freed at the same time as the pool.
[in]instancedata of type fr_redis_cluster_node_t. Holds parameters for establishing new connection.
[in]timeoutThe maximum time allowed to complete the connection.
Returns

Definition at line 1468 of file cluster.c.

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

◆ fr_redis_cluster_ipaddr()

int fr_redis_cluster_ipaddr ( fr_ipaddr_t out,
fr_redis_cluster_node_t const *  node 
)

Return the ipaddr of a particular node.

Parameters
[out]outIpaddr of the node.
[in]nodeto get ip address from.
Returns
  • 0 on success.
  • -1 on failure (node is NULL).

Definition at line 1672 of file cluster.c.

+ Here is the caller graph for this function:

◆ fr_redis_cluster_master()

fr_redis_cluster_node_t const* fr_redis_cluster_master ( fr_redis_cluster_t cluster,
fr_redis_cluster_key_slot_t const *  key_slot 
)

Return the master node that would be used for a particular key.

Parameters
[in]clusterTo resolve key in.
[in]key_slotto resolve to node.
Returns
  • The current master node.
  • NULL if no master node is currently assigned to a particular key slot.

Definition at line 1639 of file cluster.c.

+ Here is the caller graph for this function:

◆ fr_redis_cluster_min_version()

bool fr_redis_cluster_min_version ( fr_redis_cluster_t cluster,
char const *  min_version 
)

Check if members of the cluster are above a certain version.

Parameters
clusterto perform check on.
min_versionthat must be found on each node for the check to succeed. Must be in the format
<major>.<minor>.<release> 
.
Returns
  • true if all contactable members are above min_version.
  • false if at least one member if not above minimum version (use fr_strerror to retrieve node information).

Definition at line 2202 of file cluster.c.

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

◆ fr_redis_cluster_node_addr_by_role()

ssize_t fr_redis_cluster_node_addr_by_role ( TALLOC_CTX *  ctx,
fr_socket_t out[],
fr_redis_cluster_t cluster,
bool  is_master,
bool  is_slave 
)

Return an array of IP addresses belonging to masters or slaves.

Note
We return IP addresses as they're safe to use across cluster remaps.
Result array must be freed (talloc_free()) after use.
Parameters
[in]ctxto allocate array of IP addresses in.
[out]outWhere to write the addresses of the nodes.
[in]clusterto search for nodes in.
[in]is_masterIf true, include the addresses of all the master nodes.
[in]is_slaveIf true, include the addresses of all the slaves nodes.
Returns
the number of ip addresses written to out.

Definition at line 2138 of file cluster.c.

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

◆ fr_redis_cluster_pool_by_node_addr()

int fr_redis_cluster_pool_by_node_addr ( fr_pool_t **  pool,
fr_redis_cluster_t cluster,
fr_socket_t node_addr,
bool  create 
)

Get the pool associated with a node in the cluster.

Note
This is used for testing only. It's not ifdef'd out because tests need to run against production builds too.
Parameters
[out]poolassociated with the node.
[in]clusterto search for node in.
[in]node_addrto retrieve pool for. Specifies IP and port of node.
[in]createEstablish a connection to the specified node if it was previously unknown to the cluster client.
Returns
  • 0 on success.
  • -1 if no such node exists.

Definition at line 2070 of file cluster.c.

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

◆ fr_redis_cluster_port()

int fr_redis_cluster_port ( uint16_t out,
fr_redis_cluster_node_t const *  node 
)

Return the port of a particular node.

Parameters
[out]outPort of the node.
[in]nodeto get ip address from.
Returns
  • 0 on success.
  • -1 on failure (node is NULL).

Definition at line 1689 of file cluster.c.

+ Here is the caller graph for this function:

◆ fr_redis_cluster_remap()

fr_redis_cluster_rcode_t fr_redis_cluster_remap ( request_t request,
fr_redis_cluster_t cluster,
fr_redis_conn_t conn 
)

Perform a runtime remap of the cluster.

Note
Errors may be retrieved with fr_strerror().
Must be called with the cluster mutex free.
Parameters
[in]requestThe current request.
[in,out]clusterto remap.
[in]connto use to query the cluster.
Returns
  • FR_REDIS_CLUSTER_RCODE_IGNORED if 'cluster slots' returned an error (indicating clustering not supported).
  • FR_REDIS_CLUSTER_RCODE_SUCCESS on success.
  • FR_REDIS_CLUSTER_RCODE_FAILED if issuing the 'cluster slots' command resulted in a protocol error.
  • FR_REDIS_CLUSTER_RCODE_NO_CONNECTION connection failure.
  • FR_REDIS_CLUSTER_RCODE_BAD_INPUT on validation failure (bad data returned from Redis).

Definition at line 1009 of file cluster.c.

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

◆ fr_redis_cluster_slave()

fr_redis_cluster_node_t const* fr_redis_cluster_slave ( fr_redis_cluster_t cluster,
fr_redis_cluster_key_slot_t const *  key_slot,
uint8_t  slave_num 
)

Return the slave node that would be used for a particular key.

Parameters
[in]clusterTo resolve key in.
[in]key_slotTo resolve to node.
[in]slave_num0..n.
Returns
  • A slave node.
  • NULL if no slave node is assigned, or is at the specific key slot.

Definition at line 1655 of file cluster.c.

+ Here is the caller graph for this function:

◆ fr_redis_cluster_slot_by_key()

fr_redis_cluster_key_slot_t const* fr_redis_cluster_slot_by_key ( fr_redis_cluster_t cluster,
request_t request,
uint8_t const *  key,
size_t  key_len 
)

Implements the key slot selection scheme used by freeradius.

Like the scheme in the clustering specification but with some differences if the key is NULL or zero length, then a random keyslot is chosen.

If there's only a single node in the cluster, then we avoid the CRC16 and just use key slot 0.

Parameters
clusterto determine key slot for.
requestThe current request.
keythe key to resolve.
key_lenthe length of the key.
Returns
pointer to key slot key resolves to.

Definition at line 1603 of file cluster.c.

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

◆ fr_redis_cluster_state_init()

fr_redis_rcode_t fr_redis_cluster_state_init ( fr_redis_cluster_state_t state,
fr_redis_conn_t **  conn,
fr_redis_cluster_t cluster,
request_t request,
uint8_t const *  key,
size_t  key_len,
bool  read_only 
)

Resolve a key to a pool, and reserve a connection in that pool.

This should be used with fr_redis_cluster_state_next, and fr_redis_command_status, to transparently locate the cluster node we need to perform the operation on.

Example code below shows how this function is used in conjunction with fr_redis_cluster_state_next to follow redirects, and reconnect handles.

int s_ret;
redis_conn_state state;
redisReply *reply;
for (s_ret = fr_redis_cluster_state_init(&state, &conn, cluster, key, key_len, false);
s_ret = fr_redis_cluster_state_next(&state, &conn, cluster, request, status, &reply)) {
reply = redisCommand(conn->handle, "SET foo bar");
status = fr_redis_command_status(conn, reply);
}
// Reply is freed if ret == REDIS_RCODE_TRY_AGAIN, but left in all other cases to allow error
// processing, or extraction of results.
if (s_ret != REDIS_RCODE_SUCCESS) {
// Error
}
// Success
fr_redis_rcode_t fr_redis_cluster_state_next(fr_redis_cluster_state_t *state, fr_redis_conn_t **conn, fr_redis_cluster_t *cluster, request_t *request, fr_redis_rcode_t status, redisReply **reply)
Get the next connection to attempt a command against.
Definition: cluster.c:1863
fr_redis_rcode_t fr_redis_cluster_state_init(fr_redis_cluster_state_t *state, fr_redis_conn_t **conn, fr_redis_cluster_t *cluster, request_t *request, uint8_t const *key, size_t key_len, bool read_only)
Resolve a key to a pool, and reserve a connection in that pool.
Definition: cluster.c:1741
redisContext * handle
Hiredis context used when issuing commands.
Definition: base.h:101
static void fr_redis_reply_free(redisReply **reply)
Wrap freeReplyObject so we consistently check for NULL pointers.
Definition: base.h:64
fr_redis_rcode_t fr_redis_command_status(fr_redis_conn_t *conn, redisReply *reply)
Check the reply for errors.
Definition: redis.c:71
fr_redis_rcode_t
Codes are ordered inversely by priority.
Definition: base.h:87
@ REDIS_RCODE_SUCCESS
Operation was successful.
Definition: base.h:88
@ REDIS_RCODE_TRY_AGAIN
Try the operation again.
Definition: base.h:90
Connection handle, holding a redis context.
Definition: base.h:100
Parameters
[out]stateto track current pool and various counters, will be initialised.
[out]connWhere to write the reserved connection to.
[in]clusterof pools.
[in]requestThe current request.
[in]keyto resolve to a cluster node/pool. If no key is NULL or key_len is 0 a random slot will be chosen.
[in]key_lenLength of the key.
[in]read_onlyIf true, will use random slave pool in preference to the master, falling back to the master if no slaves are available.
Returns
  • REDIS_RCODE_TRY_AGAIN - try your command with this connection (provided via command).
  • REDIS_RCODE_RECONNECT - when no additional connections available.

Definition at line 1741 of file cluster.c.

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

◆ fr_redis_cluster_state_next()

fr_redis_rcode_t fr_redis_cluster_state_next ( fr_redis_cluster_state_t state,
fr_redis_conn_t **  conn,
fr_redis_cluster_t cluster,
request_t request,
fr_redis_rcode_t  status,
redisReply **  reply 
)

Get the next connection to attempt a command against.

Will process reconnect and redirect states performing the actions necessary.

If a remap is in progress, has occurred within the last second, has recently failed, or fails, the '-MOVE' will be treated as a temporary redirect (-ASK).

This allows the server to be more responsive during remaps, as unless the worker has been redirected to a node we don't currently have a pool for, it can grab a connection for the node it was redirected to, and continue.

Note
Irrespective of return code, the connection passed via conn will be released, A new connection to attempt command on will be provided via conn.
reply will be automatically freed and set to NULL if a new connection is provided in all other cases, the caller is responsible for freeing the reply.
Parameters
[in,out]statecontaining the current pool, and various counters which control retries, and limit redirects.
[in,out]connwe received the '-ASK' or '-MOVE' redirect on. Will be replaced with a connection in the new pool the key points to.
[in]requestThe current request.
[in]clusterof pools.
[in]statusof the last command, must be REDIS_RCODE_MOVE or REDIS_RCODE_ASK.
[in]replyfrom last command. Freed if 0 is returned, else caller must free.
Returns
  • REDIS_RCODE_SUCCESS - on success.
  • REDIS_RCODE_TRY_AGAIN - try new connection (provided via conn). Will free reply.
  • REDIS_RCODE_ERROR - on failure or command error.
  • REDIS_RCODE_RECONNECT - when no additional connections available.

Definition at line 1863 of file cluster.c.

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

Variable Documentation

◆ fr_redis_cluster_rcodes_table

fr_table_num_sorted_t const fr_redis_cluster_rcodes_table[]
Initial value:
= {
{ L("no-connection"), FR_REDIS_CLUSTER_RCODE_NO_CONNECTION },
}
#define L(_str)
Helper for initialising arrays of string literals.
Definition: build.h:207
@ FR_REDIS_CLUSTER_RCODE_IGNORED
Operation ignored.
Definition: cluster.h:68
@ FR_REDIS_CLUSTER_RCODE_FAILED
Operation failed.
Definition: cluster.h:70
@ FR_REDIS_CLUSTER_RCODE_SUCCESS
Operation completed successfully.
Definition: cluster.h:69
@ FR_REDIS_CLUSTER_RCODE_BAD_INPUT
Validation error.
Definition: cluster.h:73
@ FR_REDIS_CLUSTER_RCODE_NO_CONNECTION
Operation failed because we couldn't find a live connection.
Definition: cluster.h:71

Definition at line 281 of file cluster.c.

◆ fr_redis_cluster_rcodes_table_len

size_t fr_redis_cluster_rcodes_table_len = NUM_ELEMENTS(fr_redis_cluster_rcodes_table)

Definition at line 288 of file cluster.c.