41RCSID(
"$Id: 888f0b6bb0c20f99e28a59551a596fb256cffa83 $")
43#include <freeradius-devel/server/base.h>
44#include <freeradius-devel/server/module_rlm.h>
45#include <freeradius-devel/server/modpriv.h>
47#include <freeradius-devel/unlang/xlat_func.h>
49#include <freeradius-devel/util/debug.h>
50#include <freeradius-devel/util/base16.h>
51#include <freeradius-devel/util/token.h>
53#include <freeradius-devel/redis/base.h>
54#include <freeradius-devel/redis/cluster_async.h>
391 .pair.dflt =
"reply.IP-Pool.Range", .pair.dflt_quote =
T_BARE_WORD },
410 .pair.dflt =
"reply.IP-Pool.Range", .pair.dflt_quote =
T_BARE_WORD },
479 "local address_key" EOL
480 "local owner_key" EOL
485 "local wall_time = tonumber(ARGV[1])" EOL
494 "exists = redis.call('GET', owner_key)" EOL
496 " local expires = tonumber(redis.call('ZSCORE', pool_key, exists))" EOL
499 " ip = redis.call('HMGET', '{' .. KEYS[1] .. '}:"IPPOOL_ADDRESS_KEY":' .. exists, 'device', 'range', 'counter', 'gateway')" EOL
500 " if ip and (ip[1] == ARGV[3]) then" EOL
501 " if expires_in < tonumber(ARGV[2]) then" EOL
503 " expires_in = tonumber(ARGV[2])" EOL
504 " if not static then" EOL
505 " redis.call('EXPIRE', owner_key, ARGV[4])" EOL
512 " if ARGV[5] ~= ip[4] then" EOL
524 "if ARGV[6] and ARGV[6] ~= '' then" EOL
525 " local expires = tonumber(redis.call('ZSCORE', pool_key, ARGV[6]))" EOL
526 " if expires and tonumber(expires) < wall_time then" EOL
527 " ip = { ARGV[6] }" EOL
535 " ip = redis.call('ZREVRANGE', pool_key, -1, -1, 'WITHSCORES')" EOL
536 " if not ip or not ip[1] then" EOL
539 " if tonumber(ip[2]) >= wall_time then" EOL
543 "redis.call('ZADD', pool_key, 'XX', ARGV[1] + ARGV[2], ip[1])" EOL
549 "redis.call('HMSET', address_key, 'device', ARGV[3], 'gateway', ARGV[5])" EOL
550 "redis.call('SET', owner_key, ip[1])" EOL
551 "redis.call('EXPIRE', owner_key, ARGV[4])" EOL
555 " redis.call('HGET', address_key, 'range'), " EOL
556 " tonumber(ARGV[2]), " EOL
557 " redis.call('HINCRBY', address_key, 'counter', 1)" EOL
582 "local address_key" EOL
583 "local owner_key" EOL
590 "found = redis.call('HMGET', address_key, 'range', 'device', 'gateway', 'counter' )" EOL
594 "if not found[2] then" EOL
597 "if found[2] ~= ARGV[4] then" EOL
605 "local expires = tonumber(redis.call('ZSCORE', pool_key, ARGV[3]))" EOL
616 "if not static and (redis.call('EXPIRE', owner_key, ARGV[2]) == 0) then" EOL
617 " redis.call('SET', owner_key, ARGV[3])" EOL
618 " redis.call('EXPIRE', owner_key, ARGV[5])" EOL
624 "if ARGV[6] ~= found[3] then" EOL
625 " redis.call('HSET', address_key, 'gateway', ARGV[6])" EOL
651 "local address_key" EOL
652 "local owner_key" EOL
659 "found = redis.call('HGET', address_key, 'device')" EOL
660 "if not found then" EOL
663 "if found and found ~= ARGV[3] then" EOL
671 "found = tonumber(redis.call('ZSCORE', pool_key, ARGV[2]))" EOL
680 "if not static then" EOL
682 " if tonumber(ARGV[4]) > 0 then" EOL
683 " redis.call('EXPIRE', owner_key, ARGV[4])" EOL
685 " redis.call('DEL', owner_key)" EOL
690 " redis.call('HINCRBY', address_key, 'counter', 1) - 1" EOL
712 "local address_key" EOL
716 "found = redis.call('HGET', address_key, 'device')" EOL
717 "redis.call('DEL', address_key)" EOL
718 "if not found then" EOL
749 "ret = redis.call('ZADD', '{' .. KEYS[1] .. '}:"IPPOOL_POOL_KEY"', 'XX', 'CH', 0, ARGV[1])" EOL
750 "if ret == 0 then" EOL
754 " .. ARGV[1], 'device')" EOL
755 "if not found then" EOL
791 "local expires = tonumber(redis.call('ZSCORE', pool_key, ARGV[1]))" EOL
799 "local found = redis.call('GET', owner_key)" EOL
800 "if found and found ~= ARGV[1] then" EOL
808 "if expires and expires > tonumber(ARGV[4]) then" EOL
809 " found = redis.call('HGET', ip_key, 'device')"
810 " if found and found ~= ARGV[2] then" EOL
819 "redis.call('ZADD', pool_key, 'CH', expires, ARGV[1])" EOL
820 "redis.call('SET', owner_key, ARGV[1])" EOL
821 "redis.call('HSET', ip_key, 'device', ARGV[2], 'counter', 0)" EOL
822 "if ARGV[3] then" EOL
823 " redis.call('HSET', ip_key, 'range', ARGV[3])" EOL
851 "found = redis.call('GET', owner_key)" EOL
852 "if not found or found ~= ARGV[1] then" EOL
859 "local expires = tonumber(redis.call('ZSCORE', pool_key, ARGV[1]))" EOL
861 "if not static then" EOL
869 "redis.call('ZADD', pool_key, 'XX', expires, ARGV[1])" EOL
875 "if expires > tonumber(ARGV[3]) then" EOL
876 " redis.call('EXPIRE', owner_key, expires - tonumber(ARGV[3]))" EOL
878 " redis.call('DEL', owner_key)" EOL
884 if (bits >= 32)
return 0xffffffff;
885 return (1U << bits) - 1;
900 if (
reply->type != REDIS_REPLY_INTEGER) {
901 REDEBUG(
"WAIT result is wrong type, expected integer got %s",
903 wait_rctx->
fail =
true;
907 REDEBUG(
"Too few slaves acknowledged allocation, needed %i, got %lli",
909 wait_rctx->
fail =
true;
922 char *device_str = NULL, *gateway_str = NULL;
924 if (gateway_id && gateway_id->vb_length > 0) gateway_str =
fr_asprint(
request, gateway_id->vb_strvalue,
925 gateway_id->vb_length,
'"');
926 if (owner && owner->vb_length > 0) device_str =
fr_asprint(
request, owner->vb_strvalue, owner->vb_length,
'"');
930 RDEBUGX(lvl,
"Allocating lease from pool \"%pV\"%s%s%s%s%s%s, expires in %us",
932 device_str ?
", to \"" :
"", device_str ? device_str :
"",
933 device_str ?
"\"" :
"",
934 gateway_str ?
", on \"" :
"", gateway_str ? gateway_str :
"",
935 gateway_str ?
"\"" :
"",
940 RDEBUGX(lvl,
"Updating %pV in pool \"%pV\"%s%s%s%s%s%s, expires in %us",
942 device_str ?
", device \"" :
"", device_str ? device_str :
"",
943 device_str ?
"\"" :
"",
944 gateway_str ?
", gateway \"" :
"", gateway_str ? gateway_str :
"",
945 gateway_str ?
"\"" :
"",
950 RDEBUGX(lvl,
"Releasing %pV%s%s%s to pool \"%pV\"",
952 device_str ?
" leased by \"" :
"", device_str ? device_str :
"",
953 device_str ?
"\"" :
"",
1013 if (out_cmds) *out_cmds = cmds;
1029 REDEBUG(
"Server returned unknown rcode %lld", rcode);
1045 if (
reply->type != REDIS_REPLY_ARRAY) {
1046 REDEBUG(
"Expected result to be array got \"%s\"",
1052 if (
reply->elements == 0) {
1053 REDEBUG(
"Got empty result array");
1061 if (
reply->element[0]->type != REDIS_REPLY_INTEGER) {
1062 REDEBUG(
"Server returned unexpected type \"%s\" for rcode element (result[0])",
1068 if (alloc_rctx->
ret < 0)
return;
1073 if (
reply->elements > 1) {
1082 switch (
reply->element[1]->type) {
1089 case REDIS_REPLY_INTEGER:
1097 RPEDEBUG(
"Failed converting integer to IPv4 address");
1108 case REDIS_REPLY_STRING:
1110 NULL,
reply->element[1]->str,
reply->element[1]->len,
false);
1119 REDEBUG(
"Server returned unexpected type \"%s\" for IP element (result[1])",
1129 if (
reply->elements > 2) {
1130 switch (
reply->element[2]->type) {
1134 case REDIS_REPLY_STRING:
1145 NULL,
reply->element[2]->str,
reply->element[2]->len,
true);
1153 case REDIS_REPLY_NIL:
1157 REDEBUG(
"Server returned unexpected type \"%s\" for range element (result[2])",
1169 map_t expiry_map = {
1176 if (
reply->element[3]->type != REDIS_REPLY_INTEGER) {
1177 REDEBUG(
"Server returned unexpected type \"%s\" for expiry element (result[3])",
1200 if (
reply->type != REDIS_REPLY_ARRAY) {
1201 REDEBUG(
"Expected result to be array got \"%s\"",
1207 if (
reply->elements == 0) {
1208 REDEBUG(
"Got empty result array");
1216 if (
reply->element[0]->type != REDIS_REPLY_INTEGER) {
1217 REDEBUG(
"Server returned unexpected type \"%s\" for rcode element (result[0])",
1223 if (update_rctx->
ret < 0)
return;
1228 if (
reply->elements > 1) {
1229 switch (
reply->element[1]->type) {
1233 case REDIS_REPLY_STRING:
1240 reply->element[1]->str,
reply->element[1]->len,
true);
1248 case REDIS_REPLY_NIL:
1252 REDEBUG(
"Server returned unexpected type \"%s\" for range element (result[1])",
1264 map_t expiry_map = {
1290 if (
reply->type != REDIS_REPLY_ARRAY) {
1291 REDEBUG(
"Expected result to be array got \"%s\"",
1297 if (
reply->elements == 0) {
1298 REDEBUG(
"Got empty result array");
1306 if (
reply->element[0]->type != REDIS_REPLY_INTEGER) {
1307 REDEBUG(
"Server returned unexpected type \"%s\" for rcode element (result[0])",
1315#define CHECK_POOL_NAME \
1316 if (env->pool_name.vb_length > IPPOOL_MAX_KEY_PREFIX_SIZE) { \
1317 REDEBUG("Pool name too long. Expected %u bytes, got %zu bytes", \
1318 IPPOOL_MAX_KEY_PREFIX_SIZE, env->pool_name.vb_length); \
1319 RETURN_UNLANG_FAIL; \
1321 if (env->pool_name.vb_length == 0) { \
1322 RDEBUG2("Empty pool name. Doing nothing"); \
1323 RETURN_UNLANG_NOOP; \
1330 RDEBUG2(
"Forcibly cancelling Redis script load command");
1345 RERROR(
"Failed loading Redis lua script");
1359 if (
reply->type != REDIS_REPLY_STRING) {
1360 ERROR(
"Unexpected reply type after loading function");
1363 DEBUG2(
"Loaded lua function with hash \"%s\" onto node",
reply->str);
1366#define REDIS_IPPOOL_SCRIPT_LOAD(_cmds, _script, _script_len, _ret) do { \
1367 char const **argv; \
1369 MEM(argv = talloc_array(_cmds, char const *, 3)); \
1370 MEM(argv_len = talloc_array(_cmds, size_t, 3)); \
1371 argv[0] = "SCRIPT"; \
1373 argv[2] = _script; \
1374 argv_len[0] = (sizeof("SCRIPT") - 1); \
1375 argv_len[1] = (sizeof("LOAD") - 1); \
1376 argv_len[2] = _script_len; \
1377 if (fr_redis_command_argv_add(_cmds, 3, argv, argv_len, lua_script_load_results, NULL) != FR_REDIS_PIPELINE_OK) { \
1378 talloc_free(_cmds); \
1390 char const *script,
size_t script_len)
1413 .eval_rctx = mctx->
rctx
1428 inst->coord_pair_reg,
false);
1450 RDEBUG2(
"Forcibly cancelling Redis alloc command");
1464 switch (rctx->
ret) {
1468 RDEBUG2(
"IP address lease allocated");
1472 RWDEBUG(
"Pool contains no free addresses");
1476 RPERROR(
"Allocating IP address failed");
1484 redisFreeCommand(rctx->
cmd_str);
1525 cmd_len = redisFormatCommand(&rctx->
cmd_str,
"EVALSHA %s 1 %b %u %u %b %u %b %u",
1528 (
unsigned int)now.tv_sec, lease_time,
1535 RERROR(
"Failed formatting redis command");
1546 cmd_len = redisFormatCommand(&rctx->
cmd_str,
"EVALSHA %s 1 %b %u %u %b %u %b %s",
1549 (
unsigned int)now.tv_sec, lease_time,
1554 if (cmd_len < 0)
goto format_error;
1567 RDEBUG2(
"Forcibly cancelling Redis update command");
1583 switch (rctx->
ret) {
1592 if (
inst->copy_on_update) {
1605 RPEDEBUG(
"Failed copying IP address to reply attribute");
1619 REDEBUG(
"Requested IP address \"%pV\" is not a member of the specified pool",
1624 REDEBUG(
"Requested IP address' \"%pV\" lease already expired at time of renewal",
1629 REDEBUG(
"Requested IP address' \"%pV\" lease allocated to another device",
1634 RPERROR(
"Failed updating IP address");
1642 redisFreeCommand(rctx->
cmd_str);
1673 if ((ip->
af == AF_INET) &&
inst->ipv4_integer) {
1676 (
unsigned int)now.tv_sec, expires, htonl(ip->
addr.v4.s_addr),
1681 RERROR(
"Failed formatting redis command");
1690 (
unsigned int)now.tv_sec, expires, ip_buff,
1693 if (cmd_len < 0)
goto format_error;
1706 RDEBUG2(
"Forcibly cancelling Redis release command");
1721 switch (rctx->
ret) {
1734 REDEBUG(
"Requested IP address \"%pV\" is not a member of the specified pool",
1739 REDEBUG(
"Requested IP address' \"%pV\" lease allocated to another device",
1744 RPERROR(
"Failed releasing IP address");
1752 redisFreeCommand(rctx->
cmd_str);
1777 if ((ip->af == AF_INET) &&
inst->ipv4_integer) {
1780 (
unsigned int)now.tv_sec, htonl(ip->addr.v4.s_addr),
1785 RERROR(
"Failed formatting redis command");
1794 (
unsigned int)now.tv_sec, ip_buff,
1797 if (cmd_len < 0)
goto format_error;
1809 RDEBUG2(
"Bulk release not yet implemented");
1823 if (
reply->type != REDIS_REPLY_ARRAY) {
1824 ERROR(
"Failed retrieving result, expected array got %s",
1829 if (
reply->elements != 2) {
1830 ERROR(
"Failed retrieving result, expected array with two elements, got %zu elements",
1835 if (
reply->element[0]->type != REDIS_REPLY_STRING) {
1836 ERROR(
"Failed retrieving result, expected string got %s",
1841 if (
reply->element[1]->type != REDIS_REPLY_ARRAY) {
1842 ERROR(
"Failed retrieving result, expected array got %s",
1849 for (k = 0; k <
reply->element[1]->elements; k++) {
1851 redisReply *pool_key =
reply->element[1]->element[k];
1856 if (pool_key->len < 7)
continue;
1858 if ((pool_key->str[0]) !=
'{')
continue;
1859 p = memchr(pool_key->str + 1,
'}', pool_key->len - 1);
1862 len = (pool_key->len - ((p + 1) - pool_key->str));
1871 fr_value_box_list_insert_tail(&pools_rctx->
pools, vb);
1882 RDEBUG2(
"Forcefully cancelling Redis SCAN command");
1898 fr_value_box_list_talloc_free(&rctx->
pools);
1910 if ((rctx->
cursor[0] ==
'0') && rctx->
cursor[1] ==
'\0') {
1916 fr_value_box_list_remove(&rctx->
pools, vb);
1953 redisFreeCommand(rctx->
cmd_str);
2006 redisFreeCommand(rctx->
cmd_str);
2017 fr_value_box_list_init(&rctx->
pools);
2034 while (i < talloc_array_length(rctx->
cmd_str)) {
2036 if (!cmd_str)
break;
2037 redisFreeCommand(cmd_str);
2048 for (i = 0; i < talloc_array_length(rctx->
cmd_str); i++) {
2049 if (!rctx->
cmd_str[i])
return 0;
2050 redisFreeCommand(rctx->
cmd_str[i]);
2060 RDEBUG2(
"Forcibly cancelling Redis command");
2084 redisReply *ip_reply;
2086 bool active, staticip =
false;
2096 if (
reply->type != REDIS_REPLY_ARRAY)
return;
2097 if (
reply->elements < 2)
return;
2099 if (
reply->element[0]->type == REDIS_REPLY_NIL)
return;
2100 if (
reply->element[0]->type != REDIS_REPLY_STRING)
return;
2101 if (
reply->element[1]->type != REDIS_REPLY_ARRAY)
return;
2123 vp->vp_bool = active;
2127 vp->vp_bool = staticip;
2130 ip_reply =
reply->element[1];
2131 if (ip_reply->element[0]->type == REDIS_REPLY_STRING) {
2136 if (ip_reply->element[1]->type == REDIS_REPLY_STRING) {
2141 if (ip_reply->element[2]->type == REDIS_REPLY_STRING) {
2148#define ADD_REDIS_COMMAND(_fmt, ...) cmd_len = redisFormatCommand(&rctx->cmd_str[cmd_no], _fmt, __VA_ARGS__); \
2149if (cmd_len < 0) RETURN_UNLANG_FAIL; \
2150if (fr_redis_command_preformatted_add(cmds, rctx->cmd_str[cmd_no++], cmd_len, NULL, NULL) != FR_REDIS_PIPELINE_OK) goto error
2160 size_t cmd_no = 0, lookup_no = 0;
2191 rctx->
lookup[lookup_no++] = addr;
2201 rctx->
cmds,
false, NULL);
2212 fr_pair_t *stats_vp, *dynamic_vp, *static_vp, *
vp;
2217 if (
reply->type != REDIS_REPLY_ARRAY)
return;
2218 if (
reply->elements != 12)
return;
2220 for (i = 0; i <
reply->elements; i++)
if (
reply->element[i]->type != REDIS_REPLY_INTEGER)
return;
2226#define POPULATE_PAIR(_da, _i, _parent) MEM(vp = fr_pair_afrom_da(_parent, _da)); \
2227 vp->vp_uint64 = reply->element[_i]->integer; \
2228 fr_pair_append(&_parent->vp_group, vp)
2236 vp->vp_uint64 =
reply->element[0]->integer -
reply->element[6]->integer;
2276 MEM(rctx->
cmd_str = talloc_zero_array(rctx,
char *, 12));
2310 rctx->
cmds,
false, NULL);
2324 addr->
addr.v4.s_addr = htonl(ntohl(addr->
addr.v4.s_addr) + inc);
2331 memcpy(&ip_curr, addr->
addr.v6.s6_addr,
sizeof(ip_curr));
2332 ip_curr = ntohlll(ip_curr);
2336 ip_curr = htonlll(ip_curr);
2337 memcpy(&addr->
addr.v6.s6_addr, &ip_curr,
sizeof(addr->
addr.v6.s6_addr));
2355 uint8_t *prefix_out,
size_t *step,
size_t *num_addr,
2358 uint8_t prefix, subnetlen = subnet->vb_ip.prefix;
2360 switch (subnet->vb_ip.af) {
2362 prefix = (prefix_in && prefix_in->type ==
FR_TYPE_UINT8) ? prefix_in->vb_uint8 : 32;
2363 if ((prefix < 1) || (prefix > 32)) {
2364 RERROR(
"Prefix %d out of range (1-32)", prefix);
2367 *step = 1 << (32 - prefix);
2371 prefix = (prefix_in && prefix_in->type ==
FR_TYPE_UINT8) ? prefix_in->vb_uint8 : 128;
2372 if ((prefix < 1) || (prefix > 128)) {
2373 RERROR(
"Prefix %d out of range (1-128)", prefix);
2376 *step = 1 << (128 - prefix);
2384 *prefix_out = prefix;
2386 if (prefix < subnetlen) {
2387 ERROR(
"Prefix len must be greater than or equal to subnet length (%u)", subnetlen);
2391 switch (subnet->vb_ip.af) {
2396#ifdef __clang_analyzer__
2402 subnet->vb_ip.prefix = 32;
2404 if (subnetlen == 32) {
2410 ip = ntohl(start->vb_ip.addr.v4.s_addr);
2416 if (prefix == 32) ip--;
2419 end->vb_ipv4addr = htonl(ip);
2425 uint128_t ip, p_mask;
2427#ifdef __clang_analyzer__
2433 subnet->vb_ip.prefix = 128;
2435 if (subnetlen == 128) {
2441 memcpy(&ip, start->vb_ipv6addr,
sizeof(ip));
2447 memcpy(&end->vb_ipv6addr, &ip,
sizeof(end->vb_ipv6addr));
2456 *num_addr = (
size_t)1 << (prefix - subnetlen);
2475 if (start->vb_ip.af != end->vb_ip.af) {
2476 RERROR(
"Mis-matched start and end IP address types");
2480 switch (start->vb_ip.af) {
2484 start_ip = ntohl(start->vb_ipv4addr);
2485 end_ip = ntohl(end->vb_ipv4addr);
2487 prefix = (prefix_in && prefix_in->type ==
FR_TYPE_UINT8) ? prefix_in->vb_uint8 : 32;
2488 if ((prefix < 1) || (prefix > 32)) {
2489 RERROR(
"Prefix %d out of range (1-32)", prefix);
2492 *step = 1 << (32 - prefix);
2493 *num_addr = (end_ip - start_ip + 1) / *step;
2499 uint128_t start_ip, end_ip;
2501 memcpy(&start_ip, start->vb_ipv6addr,
sizeof(start_ip));
2502 memcpy(&end_ip, end->vb_ipv6addr,
sizeof(end_ip));
2504 start_ip = ntohlll(start_ip);
2505 end_ip = ntohlll(end_ip);
2507 prefix = (prefix_in && prefix_in->type ==
FR_TYPE_UINT8) ? prefix_in->vb_uint8 : 128;
2508 if ((prefix < 1) || (prefix > 128)) {
2509 RERROR(
"Prefix %d out of range (1-127)", prefix);
2512 *step = 1 << (128 - prefix);
2513 *num_addr =
uint128_sub(end_ip, start_ip) + 1 / *step;
2523 *prefix_out = prefix;
2534 RDEBUG2(
"Forcibly cancelling pending IP pool command");
2558 inst->coord_pair_reg,
false);
2571 PERROR(
"Server returned error");
2579 vb->vb_uint32 = rctx->
changed;
2597 if (
reply->type != REDIS_REPLY_INTEGER) {
2598 RERROR(
"Unexpected reply type");
2617 if (
reply->type != REDIS_REPLY_ARRAY) {
2619 RERROR(
"Unexpected reply type");
2623 if ((
reply->elements > 0) && (
reply->element[0]->type == REDIS_REPLY_INTEGER)) {
2642 bool use_range =
false;
2645 char ipaddr[INET6_ADDRSTRLEN + 1];
2649 if (prefix != (curr_addr.vb_ip.af == AF_INET ? 32 : 128)) {
2652 curr_addr.vb_ip.prefix = prefix;
2664 MEM(rctx->
cmd_str = talloc_zero_array(rctx,
char *, num_addr * (use_range ? 2 : 1)));
2667 DEBUG3(
"Adding %pV to pool \"%pV\"", &curr_addr, pool);
2670 cmd_len = redisFormatCommand(&rctx->
cmd_str[cmd_no],
"ZADD %b NX %u %s", key, p - key, 0,
2688 cmd_len = redisFormatCommand(&rctx->
cmd_str[cmd_no],
"HSET %b range %b", ip_key, ip_key_p - ip_key,
2689 range->vb_strvalue, range->vb_length);
2704 }
while (
fr_ipaddr_cmp(&curr_addr.vb_ip, &end->vb_ip) != 1);
2707 pool->vb_length, rctx->
cmds,
false, NULL);
2731 size_t num_addr, step;
2733 XLAT_ARGS(
in, &pool, &subnet, &prefix_in, &range);
2757 size_t num_addr = 1, step = 1;
2759 XLAT_ARGS(
in, &pool, &start, &end, &prefix_in, &range);
2771 uint8_t prefix,
size_t num_addr,
size_t step)
2778 char ipaddr[INET6_ADDRSTRLEN + 1];
2782 if (prefix != (curr_addr.vb_ip.af == AF_INET ? 32 : 128)) {
2785 curr_addr.vb_ip.prefix = prefix;
2792 MEM(rctx->
cmd_str = talloc_zero_array(rctx,
char *, num_addr));
2795 DEBUG3(
"Removing %pV from pool \"%pV\"", &curr_addr, pool);
2799 pool->vb_strvalue, pool->vb_length, ipaddr);
2810 }
while (
fr_ipaddr_cmp(&curr_addr.vb_ip, &end->vb_ip) != 1);
2813 pool->vb_length, rctx->
cmds,
false, NULL);
2836 size_t num_addr, step;
2861 size_t num_addr = 1, step = 1;
2875 uint8_t prefix,
size_t num_addr,
size_t step)
2882 char ipaddr[INET6_ADDRSTRLEN + 1];
2886 if (prefix != (curr_addr.vb_ip.af == AF_INET ? 32 : 128)) {
2889 curr_addr.vb_ip.prefix = prefix;
2896 MEM(rctx->
cmd_str = talloc_zero_array(rctx,
char *, num_addr));
2899 DEBUG3(
"Releasing %pV to pool \"%pV\"", &curr_addr, pool);
2903 pool->vb_strvalue, pool->vb_length, ipaddr);
2914 }
while (
fr_ipaddr_cmp(&curr_addr.vb_ip, &end->vb_ip) != 1);
2917 pool->vb_length, rctx->
cmds,
false, NULL);
2940 size_t num_addr, step;
2965 size_t num_addr = 1, step = 1;
2990 if (prefix != (curr_addr.vb_ip.af == AF_INET ? 32 : 128)) {
2993 curr_addr.vb_ip.prefix = prefix;
3000 MEM(rctx->
cmd_str = talloc_zero_array(rctx,
char *, num_addr));
3006 DEBUG3(
"Modifying %pV in pool \"%pV\"", &curr_addr, pool);
3011 cmd_len = redisFormatCommand(&rctx->
cmd_str[cmd_no],
"HSET %b range %b", ip_key, ip_key_p - ip_key,
3012 (
uint8_t const *)range->vb_strvalue, range->vb_length);
3023 }
while (
fr_ipaddr_cmp(&curr_addr.vb_ip, &end->vb_ip) != 1);
3026 pool->vb_length, rctx->
cmds,
false, NULL);
3050 size_t num_addr, step;
3052 XLAT_ARGS(
in, &pool, &subnet, &range, &prefix_in);
3076 size_t num_addr = 1, step = 1;
3078 XLAT_ARGS(
in, &pool, &start, &end, &range, &prefix_in);
3104 uint8_t const *range_str = NULL;
3105 size_t range_len = 0;
3110 range_str = (
uint8_t const *)range->vb_strvalue;
3111 range_len = range->vb_length;
3118 MEM(rctx->
cmd_str = talloc_zero_array(rctx,
char *, 1));
3122 (
uint8_t const *)pool->vb_strvalue, pool->vb_length, ip_buff,
3123 (
uint8_t const *)owner->vb_strvalue, owner->vb_length,
3135 pool->vb_length, rctx->
cmds,
false, NULL);
3168 MEM(rctx->
cmd_str = talloc_zero_array(rctx,
char *, 1));
3172 (
uint8_t const *)pool->vb_strvalue, pool->vb_length, ip_buff,
3173 (
uint8_t const *)owner->vb_strvalue, owner->vb_length,
3185 pool->vb_length, rctx->
cmds,
false, NULL);
3205 ERROR(
"Failed to enqueue lua function loading");
3228 if (!
inst->conf.use_cluster_map)
return 0;
3233 ERROR(
"Failed to attach to coordinator");
3246 static bool done_hash =
false;
3253 inst->conf.module_name = mctx->
mi->module->
name;
3256#ifdef HAVE_REDIS_SSL
3257 if (
inst->conf.use_tls && !
inst->conf.tls) {
3263 if (!
inst->conf.use_cluster_map)
goto cmds;
3265 if (
inst->conf.database) {
3266 cf_log_err(mctx->
mi->
conf,
"Cannot set Redis database number when cluster in use");
3272 .worker_cb = worker_pair_callbacks,
3273 .cb_id = REDIS_COORD_PAIR_CALLBACK_ID,
3278 if (!
inst->coord_pair_reg)
return -1;
3284 .coord_cb = coord_callbacks,
3285 .worker_cb = worker_callbacks,
3289 if (!
inst->coord_reg)
return -1;
3292 if (
inst->wait_num) {
3293 inst->wait_cmd_len = redisFormatCommand(&
inst->wait_cmd,
"WAIT %i %i",
inst->wait_num,
3295 if (
inst->wait_cmd_len < 0)
return -1;
3329 if (!t->
cw)
return 0;
3343 if (
inst->wait_cmd) redisFreeCommand(
inst->wait_cmd);
3420 .name =
"redis_ippool",
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
@ UNLANG_ACTION_YIELD
Temporarily pause execution until an event occurs.
strcpy(log_entry->msg, buffer)
#define fr_base16_encode(_out, _in)
static uint8_t request[4]
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
#define CALL_ENV_TERMINATOR
#define FR_CALL_ENV_METHOD_OUT(_inst)
Helper macro for populating the size/type fields of a call_env_method_t from the output structure typ...
@ CALL_ENV_FLAG_CONCAT
If the tmpl produced multiple boxes they should be concatenated.
@ CALL_ENV_FLAG_ATTRIBUTE
Tmpl MUST contain an attribute reference.
@ CALL_ENV_FLAG_REQUIRED
Associated conf pair or section is required.
@ CALL_ENV_FLAG_BARE_WORD_ATTRIBUTE
bare words are treated as an attribute, but strings may be xlats.
@ CALL_ENV_FLAG_NULLABLE
Tmpl expansions are allowed to produce no output.
call_env_parser_t const * env
Parsing rules for call method env.
#define FR_CALL_ENV_OFFSET(_name, _cast_type, _flags, _struct, _field)
Specify a call_env_parser_t which writes out runtime results to the specified field.
#define FR_CALL_ENV_PARSE_ONLY_OFFSET(_name, _cast_type, _flags, _struct, _parse_field)
Specify a call_env_parser_t which writes out the result of the parsing phase to the field specified.
#define CONF_PARSER_TERMINATOR
#define FR_CONF_V3_DEPRECATED(_name, _struct, _field)
conf_parser_t entry which raises an error if a deprecated v3 item is found
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
@ CONF_FLAG_SUBSECTION
Instead of putting the information into a configuration structure, the configuration file routines MA...
fr_token_t quote
Quoting around the default value. Only used for templates.
#define FR_CONF_POINTER(_name, _type, _flags, _res_p)
conf_parser_t which parses a single CONF_PAIR producing a single global result
Defines a CONF_PAIR to C data type mapping.
A section grouping multiple CONF_PAIR.
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
#define cf_log_err(_cf, _fmt,...)
void fr_redis_ct_request_yield(TALLOC_CTX *ctx, fr_redis_ct_t *rtcluster, request_t *request)
Add a request to the list of those waiting for the cluster map.
int fr_redis_ct_map_bootstrap(fr_redis_ct_t *rtcluster, fr_coord_worker_t *cw, fr_coord_pair_reg_t *coord_pair_reg)
Initiate bootstrapping of the cluster map.
fr_redis_ct_t * fr_redis_ct_alloc(TALLOC_CTX *ctx, fr_event_list_t *el, fr_redis_conf_t *conf, fr_redis_trunk_active_t active, void *active_uctx, bool active_oneshot)
Allocate per-thread, per-cluster instance.
fr_redis_async_cmd_t * fr_redis_async_cmd_start(TALLOC_CTX *ctx, request_t *request, fr_redis_async_rcode_t *rcode, fr_redis_ct_t *rtcluster, uint8_t const *key, size_t key_len, fr_redis_command_set_t *cmds, bool read_only, fr_redis_ct_node_t *node)
Start running a command set on an async redis cluster.
fr_redis_async_rcode_t fr_redis_ct_node_addr_by_role(TALLOC_CTX *ctx, fr_redis_io_conf_t *out[], uint8_t *count_out, fr_redis_ct_t *rtcluster, bool is_master, bool is_replica)
fr_redis_async_rcode_t fr_redis_ct_map_get(fr_redis_ct_t *rtcluster, fr_coord_worker_t *cw, fr_coord_pair_reg_t *coord_pair_reg, bool force)
Initiate updating of the cluster map.
void fr_redis_async_cmd_cancel(fr_redis_async_cmd_t *cmd)
Cancel a Redis async command.
fr_redis_ct_node_t * fr_redis_ct_node_by_addr(fr_redis_ct_t *rtcluster, fr_redis_io_conf_t *ioconf)
fr_redis_async_rcode_t fr_redis_async_cmd_resend(fr_redis_async_cmd_t *cmd)
Re-submit a redis async command set.
fr_redis_ct_node_t * fr_redis_async_cmd_node(fr_redis_async_cmd_t *cmd)
Fetch the cluster node a command was last sent to.
fr_redis_async_rcode_t fr_redis_async_cmd_redirect(fr_redis_async_cmd_t *cmd)
Re-submit a redis async command set on a different node.
Structure for holding the state of an async redis command set.
Thread local state for a cluster.
#define REDIS_ASYNC_COORD_CALLBACKS(_thread_type)
#define REDIS_ASYNC_START_RCODE_PROCESS(_rcode, _cluster, _cw, _coord_pair_reg, _error_msg, _error_ret)
Convenience macro to reduce boilerplate.
fr_coord_reg_t * fr_coord_register(fr_coord_reg_ctx_t *reg_ctx)
Register a coordinator.
fr_coord_worker_t * fr_coord_attach(TALLOC_CTX *ctx, fr_event_list_t *el, fr_coord_reg_t *coord_reg)
Attach a worker to a coordinator.
void fr_coord_deregister(fr_coord_reg_t *coord_reg)
De-register a coordinator.
int fr_coord_detach(fr_coord_worker_t *cw, bool exiting)
Signal a coordinator that a worker wants to detach.
A coordinator registration.
The worker end of worker <-> coordinator communication.
fr_coord_pair_reg_t * fr_coord_pair_register(fr_coord_pair_reg_ctx_t *reg_ctx)
Register a set of callbacks for pair list based coordinator messages.
struct fr_coord_pair_reg_s fr_coord_pair_reg_t
#define FR_COORD_PAIR_CB_CTX_SET(_in_cb, _out_cb, _reg)
Set up ctx on pair list callbacks.
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
#define DICT_AUTOLOAD_TERMINATOR
Specifies an attribute which must be present for the module to function.
Specifies a dictionary which must be loaded/loadable for the module to function.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
fr_cmp_ret_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
#define FR_IPADDR_PREFIX_STRLEN
Like FR_IPADDR_STRLEN but with space for a prefix.
union fr_ipaddr_t::@162 addr
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
#define RDEBUGX(_l, fmt,...)
#define RPEDEBUG(fmt,...)
int map_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, map_t const *map, UNUSED void *uctx)
Convert a map to a fr_pair_t.
int map_to_request(request_t *request, map_t const *map, radius_map_getvalue_t func, void *ctx)
Convert map_t to fr_pair_t (s) and add them to a request_t.
@ L_DBG_LVL_3
3rd highest priority debug messages (-xxx | -Xx).
@ L_DBG_LVL_2
2nd highest priority debug messages (-xx | -X).
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
@ FR_TYPE_COMBO_IP_PREFIX
IPv4 or IPv6 address prefix depending on length.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
void * env_data
Per call environment data.
module_instance_t const * mi
Instance of the module being instantiated.
void * thread
Thread specific instance data.
void * rctx
Resume ctx that a module previously set.
fr_event_list_t * el
Event list to register any IO handlers and timers against.
module_instance_t * mi
Module instance to detach.
void * thread
Thread instance data.
module_instance_t const * mi
Instance of the module being instantiated.
module_instance_t * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for module calls.
Temporary structure to hold arguments for detach calls.
Temporary structure to hold arguments for instantiation calls.
Temporary structure to hold arguments for thread_instantiation calls.
xlat_t * module_rlm_xlat_register(TALLOC_CTX *ctx, module_inst_ctx_t const *mctx, char const *name, xlat_func_t func, fr_type_t return_type)
module_t common
Common fields presented by all modules.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
fr_pair_t * fr_pair_afrom_da_nested(TALLOC_CTX *ctx, fr_pair_list_t *list, fr_dict_attr_t const *da)
Create a pair (and all intermediate parents), and append it to the list.
fr_redis_async_rcode_t fr_redis_command_set_rcode(fr_redis_command_set_t *cmds)
Extract the rcode from a command set.
fr_redis_pipeline_status_t fr_redis_command_preformatted_add(fr_redis_command_set_t *cmds, char const *cmd_str, size_t cmd_len, fr_redis_command_complete_t complete, void *rctx)
Add an preformatted command to the command set as formatted by redisCommandFormat or it's variants.
fr_redis_pipeline_status_t redis_command_set_enqueue(fr_redis_trunk_t *rtrunk, fr_redis_command_set_t *cmds)
Enqueue a command set on a specific trunk.
fr_redis_command_set_t * fr_redis_command_set_alloc(TALLOC_CTX *ctx, request_t *request, fr_redis_command_set_complete_t complete, fr_redis_command_set_fail_t fail, void *rctx, bool autofree)
Allocate a new command set.
fr_redis_pipeline_status_t fr_redis_command_literal_add(fr_redis_command_set_t *cmds, char const *cmd_str, fr_redis_command_complete_t complete, void *rctx)
Add a literal command to the command set.
int fr_redis_command_set_clear(fr_redis_command_set_t *cmds)
Reinitialise a command set so that it can be used again.
Represents a single command.
Represents a collection of pipelined commands.
@ FR_REDIS_PIPELINE_OK
No failure.
void(* fr_redis_command_complete_t)(request_t *request, fr_redis_command_t *cmd, redisReply *reply, void *rctx)
Process the reply from a single command.
char * fr_asprint(TALLOC_CTX *ctx, char const *in, ssize_t inlen, char quote)
Escape string that may contain binary data, and write it to a new buffer.
static const conf_parser_t config[]
#define RETURN_UNLANG_UPDATED
#define RETURN_UNLANG_INVALID
#define RETURN_UNLANG_NOTFOUND
#define RETURN_UNLANG_FAIL
#define RETURN_UNLANG_NOOP
@ REDIS_RCODE_SUCCESS
Operation was successful.
void fr_redis_reply_print(fr_log_lvl_t lvl, redisReply *reply, request_t *request, size_t idx, fr_redis_rcode_t status)
Print the response data in a useful treelike form.
#define REDIS_COMMON_CONFIG
void fr_redis_version_print(void)
Print the version of libhiredis the server was built against.
fr_table_num_sorted_t const redis_reply_types[]
@ REDIS_ASYNC_RCODE_BOOTSTRAP
The caller should issue a request to bootstrap the cluster map.
@ REDIS_ASYNC_RCODE_MOVE
Attempt operation on an alternative node with remap.
@ REDIS_ASYNC_RCODE_ERROR
Unrecoverable error.
@ REDIS_ASYNC_RCODE_ASK
Attempt operation on an alternative node.
@ REDIS_ASYNC_RCODE_FAIL
The command set trunk request has been failed.
@ REDIS_ASYNC_RCODE_TRY_AGAIN
Try the operation again.
@ REDIS_ASYNC_RCODE_NO_SCRIPT
Script doesn't exist.
@ REDIS_ASYNC_RCODE_SUCCESS
Operation was successful.
Configuration parameters for a redis connection.
#define IPPOOL_STATIC_BIT
#define _IPPOOL_RCODE_NOT_FOUND
@ IPPOOL_RCODE_DEVICE_MISMATCH
@ IPPOOL_RCODE_POOL_EMPTY
#define IPPOOL_MAX_POOL_KEY_SIZE
{prefix}:pool
#define _IPPOOL_RCODE_POOL_EMPTY
#define _IPPOOL_RCODE_DEVICE_MISMATCH
#define _IPPOOL_RCODE_SUCCESS
#define IPPOOL_SPRINT_IP(_buff, _ip, _prefix)
If the prefix is as wide as the AF data size then print it without CIDR notation.
#define IPPOOL_ADDRESS_KEY
#define IPPOOL_BUILD_IP_KEY_FROM_STR(_buff, _p, _key, _key_len, _ip_str)
#define IPPOOL_BUILD_IP_KEY(_buff, _p, _key, _key_len, _ip)
Build the IP key {prefix}:ip.
#define IPPOOL_MAX_IP_KEY_SIZE
{prefix}:ipaddr/prefix
#define IPPOOL_BUILD_KEY(_buff, _p, _key, _key_len)
Wrap the prefix in {} and add the pool suffix.
static void ippool_action_print(request_t *request, ippool_action_t action, fr_log_lvl_t lvl, fr_value_box_t const *key_prefix, fr_value_box_t const *ip, fr_value_box_t const *owner, fr_value_box_t const *gateway_id, uint32_t expires)
fr_dict_attr_autoload_t rlm_redis_ippool_dict_attr[]
tmpl_t * expiry_attr
Time at which the lease will expire.
static fr_dict_attr_t const * attr_ippool_stats_dynamic_expire1d
static void ippool_wait_check(request_t *request, UNUSED fr_redis_command_t *cmd, redisReply *reply, void *rctx)
Check the requisite number of slaves replicated the lease info.
fr_redis_command_set_t * cmds
Redis command set to run.
static unlang_action_t mod_release_resume(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
#define ADD_REDIS_COMMAND(_fmt,...)
static int mod_detach(module_detach_ctx_t const *mctx)
static int mod_load(void)
static char lua_remove_cmd[]
Lua script for removing a lease.
unlang_module_signal_t cancel
Cancel function for EVAL command.
static void redis_ippool_update_results(request_t *request, UNUSED fr_redis_command_t *cmd, redisReply *reply, void *rctx)
Callback to process results from allocation script.
ippool_rcode_t ret
Return code for the allocation result.
fr_value_box_list_t pools
Temporary list to store pool names.
fr_value_box_list_t requested_address
Address(es) to fetch details of.
static char lua_update_cmd[]
Lua script for updating leases.
fr_redis_async_cmd_t * cmd
Redis async command.
static fr_dict_attr_t const * attr_ippool_stats_static_renew1m
static fr_dict_attr_t const * attr_ippool_stats_static
static unlang_action_t mod_show_resume(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static void lua_script_load_results(request_t *request, UNUSED fr_redis_command_t *cmd, redisReply *reply, UNUSED void *rctx)
fr_redis_command_set_t * cmds
Command set to be run.
fr_value_box_t pool_name
Name of the pool we're allocating IP addresses from.
static xlat_action_t redis_ippool_add_common(request_t *request, rlm_redis_ippool_t *inst, rlm_redis_ippool_thread_t *t, fr_value_box_t *pool, fr_value_box_t *start, fr_value_box_t *end, fr_value_box_t *range, uint8_t prefix, size_t num_addr, size_t step)
Common code for adding addresses to a pool.
char cursor[19]
Cursor value returned in last result.
static fr_dict_attr_t const * attr_ippool_stats_static_renew1h
static unlang_action_t ippool_script_enqueue(TALLOC_CTX *ctx, fr_redis_command_set_t **out_cmds, fr_redis_async_cmd_t **out_cmd, request_t *request, rlm_redis_ippool_thread_t *thread, uint8_t const *key, size_t key_len, char const *cmd, int cmd_len, fr_redis_command_complete_t complete, module_method_t resume, unlang_module_signal_t cancel, void *rctx, redis_wait_rctx_t *wait_rctx)
Enqueue a script to run against a redis cluster.
static char lua_release_digest[(SHA1_DIGEST_LENGTH *2)+1]
static fr_dict_attr_t const * attr_ippool_stats_dynamic_free
static const call_env_method_t redis_ippool_stats_method_env
static void ipaddr_inc(fr_ipaddr_t *addr, size_t inc)
Increment an IP address by a given number of addresses.
static fr_dict_attr_t const * attr_ippool_stats_static_renew30m
static int mod_coord_attach(module_thread_inst_ctx_t const *mctx)
static char lua_assign_cmd[]
Lua script for assigning a static lease.
module_method_t resume
Resume function for EVAL command.
static void redis_xlat_array_results(request_t *request, UNUSED fr_redis_command_t *cmd, redisReply *reply, void *rctx)
Callback to be used when Redis commands are expected to return an array.
static char lua_alloc_digest[(SHA1_DIGEST_LENGTH *2)+1]
char const * name
Instance name.
fr_value_box_t gateway_id
Gateway identifier, usually NAS-Identifier or Option 82 gateway.
tmpl_t * range_attr
Attribute to write the range ID to.
module_rlm_t rlm_redis_ippool
fr_redis_ct_t * rtcluster
Per thread Redis cluster.
static xlat_action_t redis_ippool_addresses_remove_xlat(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
fr_redis_io_conf_t * nodes
List of nodes to query.
static fr_dict_attr_t const * attr_ippool_stats_dynamic_expire1m
fr_redis_command_set_t * cmds
Command set to be run.
static int _redis_ippool_update_rctx_free(redis_ippool_update_rctx_t *rctx)
static xlat_action_t redis_ippool_list_start(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *in)
fr_value_box_t offer_time
How long we should reserve a lease for during the pre-allocation stage (typically responding to DHCP ...
static fr_dict_attr_t const * attr_ippool_lease_device
static xlat_action_t redis_ippool_addresses_modify_xlat(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
fr_coord_pair_reg_t * coord_pair_reg
Coord pair registration.
static unlang_action_t redis_ippool_load_resume(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static void redis_ippool_common_cancel(xlat_ctx_t const *xctx, request_t *request, UNUSED fr_signal_t action)
Common cancellation function for xlats using redi_ippool_tool_rctx_t.
uint8_t current_node
Node number currently being queried.
fr_value_box_t gateway_id
Gateway identifier, usually NAS-Identifier or Option 82 gateway.
redis_ippool_release_call_env_t * env
Callenv for the current allocation.
char * cmd_str
Formatted redis command.
static xlat_action_t redis_ippool_remove_common(request_t *request, rlm_redis_ippool_t *inst, rlm_redis_ippool_thread_t *t, fr_value_box_t *pool, fr_value_box_t *start, fr_value_box_t *end, uint8_t prefix, size_t num_addr, size_t step)
Common code for removing addresses from a pool.
static fr_dict_attr_t const * attr_ippool_stats_dynamic_expire30m
static xlat_action_t redis_ippool_assign_xlat(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
static fr_dict_attr_t const * attr_ippool_lease_gateway
fr_redis_command_set_t * cmds
Command set to be run.
static xlat_action_t redis_ippool_subnet_modify_xlat(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
static unlang_action_t mod_update(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static unlang_action_t mod_bulk_release(unlang_result_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
static unlang_action_t mod_alloc(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static fr_dict_t const * dict_freeradius
static void redis_ippool_list_cancel(xlat_ctx_t const *xctx, request_t *request, UNUSED fr_signal_t action)
char ** cmd_str
Formatted redis commands.
static void redis_ippool_release_results(request_t *request, UNUSED fr_redis_command_t *cmd, redisReply *reply, void *rctx)
Callback to process results from release script.
static fr_dict_attr_t const * attr_ippool_stats_static_total
static const call_env_method_t redis_ippool_update_method_env
fr_value_box_t owner
Unique lease owner identifier.
static xlat_action_t redis_ippool_subnet_remove_xlat(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
static void mod_alloc_cancel(module_ctx_t const *mctx, request_t *request, UNUSED fr_signal_t action)
static unlang_action_t mod_stats(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static void lua_script_load(fr_redis_trunk_t *rtrunk, UNUSED void *uctx)
static void mod_info_cancel(module_ctx_t const *mctx, request_t *request, UNUSED fr_signal_t action)
static const call_env_method_t redis_ippool_show_method_env
static fr_dict_attr_t const * attr_ippool_name
static xlat_action_t redis_ippool_list_resume(UNUSED TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *in)
ippool_rcode_t ret
Return code for the allocation result.
static fr_dict_attr_t const * attr_ippool_stats_static_free
static fr_dict_attr_t const * attr_ippool_lease
fr_value_box_t pool_name
Name of the pool we're allocating IP addresses from.
rlm_redis_ippool_t * inst
Module instance.
char * cmd_str
Current preformatted Redis command.
static xlat_arg_parser_t const redis_ippool_subnet_remove_args[]
static uint32_t uint32_gen_mask(uint8_t bits)
fr_value_box_t association_time
How long should a device be associated with an IP address.
static fr_dict_attr_t const * attr_ippool_lease_active
static xlat_arg_parser_t const redis_ippool_subnet_modify_args[]
static xlat_arg_parser_t const redis_ippool_addresses_remove_args[]
static unlang_action_t mod_release(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static int mod_bootstrap(module_inst_ctx_t const *mctx)
static xlat_arg_parser_t const redis_ippool_subnet_add_args[]
fr_value_box_t pool_name
Name of the pool we're allocating IP addresses from.
static unlang_action_t mod_show(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
ippool_rcode_t ret
Return code for the allocation result.
static char lua_unassign_cmd[]
Lua script for un-assigning a static lease.
fr_redis_command_set_t * cmds
Command set for loading script.
uint32_t changed
Number of changes reported by redis.
#define POPULATE_PAIR(_da, _i, _parent)
fr_value_box_t lease_time
How long an IP address should be allocated for.
fr_value_box_t gateway_id
Gateway identifier, usually NAS-Identifier or Option 82 gateway.
static conf_parser_t redis_config[]
fr_value_box_t requested_address
Address being updated.
fr_value_box_t pool_name
Name of the pool we're looking up the address in.
static xlat_arg_parser_t const redis_ippool_addresses_release_args[]
fr_redis_async_cmd_t * cmd
Redis async command.
static xlat_action_t redis_ippool_list_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
fr_dict_autoload_t rlm_redis_ippool_dict[]
static int _redis_ippool_release_rctx_free(redis_ippool_release_rctx_t *rctx)
static xlat_action_t redis_ippool_subnet_release_xlat(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
static int redis_ippool_addresses_arg_parse(request_t *request, uint8_t *prefix_out, size_t *step, size_t *num_addr, fr_value_box_t *start, fr_value_box_t *end, fr_value_box_t *prefix_in)
Parse argments provided to IP pool manipulation xlats which work on start and end addresses.
static xlat_action_t redis_ippool_list_next_scan(request_t *request, rlm_redis_ippool_thread_t *thread, redis_pools_list_rctx_t *rctx)
Enqueue the next SCAN command.
static void redis_ippool_allocate_results(request_t *request, UNUSED fr_redis_command_t *cmd, redisReply *reply, void *rctx)
Callback to process results from allocation script.
fr_value_box_t requested_address
The address the client is requesting.
static fr_dict_attr_t const * attr_ippool_stats_dynamic
fr_value_box_t association_time
How long should a device be associated with an IP address.
redis_ippool_update_call_env_t * env
Callenv for the current allocation.
static int _redis_ippool_info_rctx_free(redis_ippool_info_rctx_t *rctx)
char * cmd_str
Formatted redis command.
fr_value_box_t ** lookup
Value boxes holding lookup keys.
static xlat_action_t redis_ippool_common_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *in)
Common resume function for pool manipulation xlats.
redis_wait_rctx_t wait_rctx
WAIT resume context.
static char lua_release_cmd[]
Lua script for releasing leases.
static xlat_action_t redis_ippool_unassign_xlat(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
static fr_dict_t const * dict_redis
fr_redis_conf_t conf
Connection parameters for the Redis server.
fr_coord_reg_t * coord_reg
Coordinator registration.
static xlat_action_t redis_ippool_release_common(request_t *request, rlm_redis_ippool_t *inst, rlm_redis_ippool_thread_t *t, fr_value_box_t *pool, fr_value_box_t *start, fr_value_box_t *end, uint8_t prefix, size_t num_addr, size_t step)
Common code for releasing address assignments.
uint32_t changes
How many changes are submitted.
static unlang_action_t mod_alloc_resume(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static void mod_release_cancel(module_ctx_t const *mctx, request_t *request, UNUSED fr_signal_t action)
static xlat_action_t redis_ippool_addresses_add_xlat(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
uint32_t wait_num
How many slaves we want to acknowledge allocations or updates.
static xlat_arg_parser_t const redis_ippool_assign_args[]
redis_wait_rctx_t wait_rctx
WAIT resume context.
static const call_env_method_t redis_ippool_release_method_env
static fr_dict_attr_t const * attr_ippool_lease_address
static fr_dict_attr_t const * attr_ippool_lease_expires
static int redis_ippool_subnet_arg_parse(request_t *request, fr_value_box_t *start, fr_value_box_t *end, uint8_t *prefix_out, size_t *step, size_t *num_addr, fr_value_box_t *subnet, fr_value_box_t *prefix_in)
Parse argments provided to IP pool manipulation xlats which work on subnets.
fr_time_delta_t wait_timeout
How long we wait for slaves to acknowledge writing.
fr_redis_async_cmd_t * cmd
Async command for loading script.
size_t lookup_no
Incremented on processing each reply.
fr_pair_list_t results
Temporary list to hold results.
bool copy_on_update
Copy the address provided by ip_address to the allocated_address_attr if updates are successful.
fr_redis_async_cmd_t * cmd
Redis async command.
static void mod_stats_result(request_t *request, UNUSED fr_redis_command_t *cmd, redisReply *reply, void *rctx)
fr_value_box_t association_time
How log should a device be associated with an IP address.
static char lua_release_xlat_cmd[]
Lua script for releasing a lease.
tmpl_t * expiry_attr
Time at which the lease will expire.
static char lua_alloc_cmd[]
Lua script for allocating new leases.
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
tmpl_t * range_attr
Attribute to write the range ID to.
fr_coord_worker_t * cw
Coord-worker for fetching cluster map.
static void mod_show_result(request_t *request, UNUSED fr_redis_command_t *cmd, redisReply *reply, void *rctx)
static xlat_arg_parser_t const redis_ippool_subnet_release_args[]
static xlat_arg_parser_t const redis_ippool_addresses_add_args[]
#define REDIS_IPPOOL_SCRIPT_LOAD(_cmds, _script, _script_len, _ret)
static void mod_update_cancel(module_ctx_t const *mctx, request_t *request, UNUSED fr_signal_t action)
char ** cmd_str
Formatted redis commands for this xlat.
fr_redis_async_cmd_t * cmd
Redis async command.
static void redis_ippool_load_cancel(module_ctx_t const *mctx, request_t *request, UNUSED fr_signal_t action)
tmpl_t * allocated_address_attr
Attribute to populate with allocated IP.
redis_ippool_alloc_call_env_t * env
Callenv for the current allocation.
bool ipv4_integer
Whether IPv4 addresses should be cast to integers, for renew operations.
static xlat_action_t redis_ippool_subnet_add_xlat(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
static int mod_coord_detach(module_thread_inst_ctx_t const *mctx)
fr_value_box_t owner
Unique lease owner identifier.
fr_redis_command_set_t * cmds
Command set to be run.
tmpl_t * allocated_address_attr
Attribute to populate with allocated IP.
static fr_dict_attr_t const * attr_ippool_lease_range
fr_redis_async_cmd_t * cmd
Redis async command.
static xlat_action_t redis_ippool_modify_common(request_t *request, rlm_redis_ippool_t *inst, rlm_redis_ippool_thread_t *t, fr_value_box_t *pool, fr_value_box_t *start, fr_value_box_t *end, fr_value_box_t *range, uint8_t prefix, size_t num_addr, size_t step)
Common code for modifying the range assigned to addresses.
fr_value_box_t gateway_id
Gateway identifier, usually NAS-Identifier or Option 82 gateway.
TALLOC_CTX * ctx
Context to allocate pool names in.
static fr_dict_attr_t const * attr_ippool_stats
static fr_dict_attr_t const * attr_ippool_stats_dynamic_expire1h
static fr_dict_attr_t const * attr_ippool_stats_static_renew1d
fr_value_box_t pool_name
Name of the pool we're getting stats for.
static unlang_action_t mod_update_resume(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
uint8_t node_count
How many nodes are in nodes.
fr_value_box_t lease_time
How long an IP address should be allocated for.
static xlat_arg_parser_t const redis_ippool_unassign_args[]
static xlat_action_t redis_ippool_addresses_release_xlat(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
void * eval_rctx
Resume context for original EVAL command.
static int _redis_pools_list_rctx_free(redis_pools_list_rctx_t *rctx)
fr_redis_command_set_t * cmds
Command set to run.
char * wait_cmd
Preformatted redis "WAIT" command.
fr_redis_async_cmd_t * cmd
Redis async command.
static fr_dict_attr_t const * attr_ippool_stats_dynamic_total
static int _redis_ippool_tool_rctx_free(redis_ippool_tool_rctx_t *rctx)
fr_redis_async_cmd_t * eval_cmd
Original EVAL async command which returned NOSCRIPT.
static unlang_action_t redis_ippool_rcode_check(request_t *request, fr_redis_command_set_t *cmds, fr_redis_async_cmd_t *cmd, module_ctx_t const *mctx, module_method_t resume, unlang_module_signal_t cancel, char const *script, size_t script_len)
Check the return code from an async redis command.
static void mod_pools_list_result(request_t *request, UNUSED fr_redis_command_t *cmd, redisReply *reply, void *rctx)
Parse the results from Redis SCAN command used to list pools.
static int _redis_ippool_alloc_ctx_free(redis_ippool_alloc_rctx_t *rctx)
static int mod_instantiate(module_inst_ctx_t const *mctx)
static fr_dict_attr_t const * attr_ippool_lease_static
fr_value_box_t pool_name
Name of the pool we're releasing the IP addresses to.
static const call_env_method_t redis_ippool_bulk_release_method_env
static char lua_update_digest[(SHA1_DIGEST_LENGTH *2)+1]
fr_value_box_t owner
Unique lease owner identifier.
static conf_parser_t module_config[]
static void redis_xlat_common_results(request_t *request, UNUSED fr_redis_command_t *cmd, redisReply *reply, void *rctx)
Callback to be used when Redis commands are expected to return a single integer.
static xlat_arg_parser_t const redis_ippool_addresses_modify_args[]
int wait_cmd_len
Length of wait_cmd.
static ippool_rcode_t ippool_rcode_from_reply(request_t *request, long long rcode)
Convert the rcode element of a Lua script reply to an ippool_rcode_t.
redis_wait_rctx_t wait_rctx
WAIT resume context.
static fr_dict_attr_t const * attr_ippool_stats_total
fr_value_box_t requested_address
Address being released.
static const call_env_method_t redis_ippool_alloc_method_env
char * cmd_str
Formatted redis command.
Call environment used when calling redis_ippool allocate method.
Resume context for async calls to alloc script.
Call environment used when calling redis_ippool bulk release method.
Resume context for methods which retrieve info and produce pairs.
Resume context for loading scripts in response to NOSCRIPT reply.
Call environment used when calling redis_ippool release method.
Resume context for async calls to update script.
Call environment used when calling redis_ippool show method.
Call environment used when calling redis_ippool stats method.
Call environment used when calling redis_ippool update method.
Resume context for async calls to update script.
Resume context for pool list module method.
Resume context for validating WAIT replies.
rlm_redis module instance
#define FR_SBUFF_OUT(_start, _len_or_end)
int fr_schedule_worker_id(void)
Return the worker id for the current thread.
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
#define MODULE_THREAD_INST(_ctype)
char const * name
Instance name e.g. user_database.
CONF_SECTION * conf
Module's instance configuration.
size_t inst_size
Size of the module's instance data.
void * data
Module's instance data.
unlang_action_t(* module_method_t)(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Module section callback.
void * boot
Data allocated during the boostrap phase.
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Named methods exported by a module.
#define tmpl_value(_tmpl)
@ TMPL_TYPE_DATA
Value in native boxed format.
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
tmpl_t * tmpl_init_shallow(tmpl_t *vpt, tmpl_type_t type, fr_token_t quote, char const *name, ssize_t len, tmpl_rules_t const *t_rules))
Initialise a tmpl without copying the input name string.
void fr_sha1_init(fr_sha1_ctx *context)
void fr_sha1_final(uint8_t digest[static SHA1_DIGEST_LENGTH], fr_sha1_ctx *context)
void fr_sha1_update(fr_sha1_ctx *context, uint8_t const *in, size_t len)
#define SHA1_DIGEST_LENGTH
#define FR_SIGNAL_ALLOW(_signals)
Signal mask which blocks every signal except the ones in _signals.
fr_signal_t
Signals that can be generated/processed by request signal handlers.
@ FR_SIGNAL_NONE
No signals.
@ FR_SIGNAL_CANCEL
Request has been cancelled.
unlang_action_t unlang_module_yield(request_t *request, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
eap_aka_sim_process_conf_t * inst
size_t strlcpy(char *dst, char const *src, size_t siz)
tmpl_t * lhs
Typically describes the attribute to add, modify or compare.
tmpl_t * rhs
Typically describes a literal value or a src attribute to copy or compare.
Stores an attribute, a value and various bits of other data.
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
#define talloc_get_type_abort_const
static int64_t fr_time_to_sec(fr_time_t when)
Convert an fr_time_t (internal time) to number of sec since the unix epoch (wallclock time)
static int64_t fr_unix_time_to_sec(fr_unix_time_t delta)
#define fr_time_to_timeval(_when)
Convert server epoch time to unix epoch time.
static int64_t fr_time_delta_to_msec(fr_time_delta_t delta)
A time delta, a difference in time measured in nanoseconds.
static uint128_t uint128_gen_mask(uint8_t bits)
Create a 128 bit integer value with n bits high.
static uint128_t uint128_bor(uint128_t a, uint128_t b)
Perform bitwise | of two 128bit unsigned integers.
static uint128_t uint128_lshift(uint128_t num, uint8_t bits)
Left shift 128 bit integer.
static uint128_t uint128_sub(uint128_t a, uint128_t b)
Subtract one 128bit integer from another.
static uint128_t uint128_add(uint128_t a, uint128_t b)
Add two 128bit unsigned integers.
void(* unlang_module_signal_t)(module_ctx_t const *mctx, request_t *request, fr_signal_t action)
A callback when the request gets a fr_signal_t.
xlat_action_t unlang_xlat_yield(request_t *request, xlat_func_t resume, xlat_func_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
@ XLAT_ACTION_FAIL
An xlat function failed.
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
#define XLAT_ARGS(_list,...)
Populate local variables with value boxes from the input list.
unsigned int required
Argument must be present, and non-empty.
#define XLAT_ARG_PARSER_TERMINATOR
Definition for a single argument consumed by an xlat function.
void fr_pair_list_append(fr_pair_list_t *dst, fr_pair_list_t *src)
Appends a list of fr_pair_t from a temporary list to a destination list.
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
size_t fr_pair_list_num_elements(fr_pair_list_t const *list)
Get the length of a list of fr_pair_t.
fr_slen_t fr_value_box_from_str(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, char const *in, size_t inlen, fr_sbuff_unescape_rules_t const *erules)
ssize_t fr_value_box_print(fr_sbuff_t *out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules)
Print one boxed value to a string.
int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert one type of fr_value_box_t to another.
int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
int fr_value_box_cast_in_place(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv)
Convert one type of fr_value_box_t to another in place.
int fr_value_box_strdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Copy a nul terminated string to a fr_value_box_t.
int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Copy a string to to a fr_value_box_t.
void fr_value_box_bstrndup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Assign a string to to a fr_value_box_t.
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
static fr_sbuff_err_t char size_t fr_sbuff_t * in
static fr_sbuff_err_t char ** out
static fr_sbuff_err_t char size_t * len
#define fr_value_box(_box, _var, _tainted)
Automagically fill in a box, determining the value type from the type of the C variable.
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
#define fr_value_box_list_foreach(_list_head, _iter)
void * rctx
Resume context.
xlat_exp_t const * ex
Tokenized expression.
void const * inst
xlat instance data.
#define XLAT_CTX(_inst, _thread, _ex, _mctx, _env_data, _rctx)
Wrapper to create a xlat_ctx_t as a compound literal.
module_ctx_t const * mctx
Synthesised module calling ctx.
void xlat_func_flags_set(xlat_t *x, xlat_func_flags_t flags)
Specify flags that alter the xlat's behaviour.
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
@ XLAT_FUNC_FLAG_MODULE_STATUS