41RCSID(
"$Id: fe09d366ede2ac29afa925986e19b050a548add7 $")
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>
389 .pair.dflt =
"reply.IP-Pool.Range", .pair.dflt_quote =
T_BARE_WORD },
408 .pair.dflt =
"reply.IP-Pool.Range", .pair.dflt_quote =
T_BARE_WORD },
477 "local address_key" EOL
478 "local owner_key" EOL
483 "local wall_time = tonumber(ARGV[1])" EOL
492 "exists = redis.call('GET', owner_key)" EOL
494 " local expires = tonumber(redis.call('ZSCORE', pool_key, exists))" EOL
497 " ip = redis.call('HMGET', '{' .. KEYS[1] .. '}:"IPPOOL_ADDRESS_KEY":' .. exists, 'device', 'range', 'counter', 'gateway')" EOL
498 " if ip and (ip[1] == ARGV[3]) then" EOL
499 " if expires_in < tonumber(ARGV[2]) then" EOL
501 " expires_in = tonumber(ARGV[2])" EOL
502 " if not static then" EOL
503 " redis.call('EXPIRE', owner_key, ARGV[4])" EOL
510 " if ARGV[5] ~= ip[4] then" EOL
522 "if ARGV[6] and ARGV[6] ~= '' then" EOL
523 " local expires = tonumber(redis.call('ZSCORE', pool_key, ARGV[6]))" EOL
524 " if expires and tonumber(expires) < wall_time then" EOL
525 " ip = { ARGV[6] }" EOL
533 " ip = redis.call('ZREVRANGE', pool_key, -1, -1, 'WITHSCORES')" EOL
534 " if not ip or not ip[1] then" EOL
537 " if tonumber(ip[2]) >= wall_time then" EOL
541 "redis.call('ZADD', pool_key, 'XX', ARGV[1] + ARGV[2], ip[1])" EOL
547 "redis.call('HMSET', address_key, 'device', ARGV[3], 'gateway', ARGV[5])" EOL
548 "redis.call('SET', owner_key, ip[1])" EOL
549 "redis.call('EXPIRE', owner_key, ARGV[4])" EOL
553 " redis.call('HGET', address_key, 'range'), " EOL
554 " tonumber(ARGV[2]), " EOL
555 " redis.call('HINCRBY', address_key, 'counter', 1)" EOL
580 "local address_key" EOL
581 "local owner_key" EOL
588 "found = redis.call('HMGET', address_key, 'range', 'device', 'gateway', 'counter' )" EOL
592 "if not found[2] then" EOL
595 "if found[2] ~= ARGV[4] then" EOL
603 "local expires = tonumber(redis.call('ZSCORE', pool_key, ARGV[3]))" EOL
614 "if not static and (redis.call('EXPIRE', owner_key, ARGV[2]) == 0) then" EOL
615 " redis.call('SET', owner_key, ARGV[3])" EOL
616 " redis.call('EXPIRE', owner_key, ARGV[5])" EOL
622 "if ARGV[6] ~= found[3] then" EOL
623 " redis.call('HSET', address_key, 'gateway', ARGV[6])" EOL
649 "local address_key" EOL
650 "local owner_key" EOL
657 "found = redis.call('HGET', address_key, 'device')" EOL
658 "if not found then" EOL
661 "if found and found ~= ARGV[3] then" EOL
669 "found = tonumber(redis.call('ZSCORE', pool_key, ARGV[2]))" EOL
678 "if not static then" EOL
680 " if tonumber(ARGV[4]) > 0 then" EOL
681 " redis.call('EXPIRE', owner_key, ARGV[4])" EOL
683 " redis.call('DEL', owner_key)" EOL
688 " redis.call('HINCRBY', address_key, 'counter', 1) - 1" EOL
710 "local address_key" EOL
714 "found = redis.call('HGET', address_key, 'device')" EOL
715 "redis.call('DEL', address_key)" EOL
716 "if not found then" EOL
747 "ret = redis.call('ZADD', '{' .. KEYS[1] .. '}:"IPPOOL_POOL_KEY"', 'XX', 'CH', 0, ARGV[1])" EOL
748 "if ret == 0 then" EOL
752 " .. ARGV[1], 'device')" EOL
753 "if not found then" EOL
789 "local expires = tonumber(redis.call('ZSCORE', pool_key, ARGV[1]))" EOL
797 "local found = redis.call('GET', owner_key)" EOL
798 "if found and found ~= ARGV[1] then" EOL
806 "if expires and expires > tonumber(ARGV[4]) then" EOL
807 " found = redis.call('HGET', ip_key, 'device')"
808 " if found and found ~= ARGV[2] then" EOL
817 "redis.call('ZADD', pool_key, 'CH', expires, ARGV[1])" EOL
818 "redis.call('SET', owner_key, ARGV[1])" EOL
819 "redis.call('HSET', ip_key, 'device', ARGV[2], 'counter', 0)" EOL
820 "if ARGV[3] then" EOL
821 " redis.call('HSET', ip_key, 'range', ARGV[3])" EOL
849 "found = redis.call('GET', owner_key)" EOL
850 "if not found or found ~= ARGV[1] then" EOL
857 "local expires = tonumber(redis.call('ZSCORE', pool_key, ARGV[1]))" EOL
859 "if not static then" EOL
867 "redis.call('ZADD', pool_key, 'XX', expires, ARGV[1])" EOL
873 "if expires > tonumber(ARGV[3]) then" EOL
874 " redis.call('EXPIRE', owner_key, expires - tonumber(ARGV[3]))" EOL
876 " redis.call('DEL', owner_key)" EOL
882 if (bits >= 32)
return 0xffffffff;
883 return (1U << bits) - 1;
898 if (reply->type != REDIS_REPLY_INTEGER) {
899 REDEBUG(
"WAIT result is wrong type, expected integer got %s",
901 wait_rctx->
fail =
true;
904 if (reply->integer < wait_rctx->
wait_num) {
905 REDEBUG(
"Too few slaves acknowledged allocation, needed %i, got %lli",
906 wait_rctx->
wait_num, reply->integer);
907 wait_rctx->
fail =
true;
920 char *device_str = NULL, *gateway_str = NULL;
922 if (gateway_id && gateway_id->vb_length > 0) gateway_str =
fr_asprint(request, gateway_id->vb_strvalue,
923 gateway_id->vb_length,
'"');
924 if (owner && owner->vb_length > 0) device_str =
fr_asprint(request, owner->vb_strvalue, owner->vb_length,
'"');
928 RDEBUGX(lvl,
"Allocating lease from pool \"%pV\"%s%s%s%s%s%s, expires in %us",
930 device_str ?
", to \"" :
"", device_str ? device_str :
"",
931 device_str ?
"\"" :
"",
932 gateway_str ?
", on \"" :
"", gateway_str ? gateway_str :
"",
933 gateway_str ?
"\"" :
"",
938 RDEBUGX(lvl,
"Updating %pV in pool \"%pV\"%s%s%s%s%s%s, expires in %us",
940 device_str ?
", device \"" :
"", device_str ? device_str :
"",
941 device_str ?
"\"" :
"",
942 gateway_str ?
", gateway \"" :
"", gateway_str ? gateway_str :
"",
943 gateway_str ?
"\"" :
"",
948 RDEBUGX(lvl,
"Releasing %pV%s%s%s to pool \"%pV\"",
950 device_str ?
" leased by \"" :
"", device_str ? device_str :
"",
951 device_str ?
"\"" :
"",
1011 if (out_cmds) *out_cmds = cmds;
1024 if (reply->type != REDIS_REPLY_ARRAY) {
1025 REDEBUG(
"Expected result to be array got \"%s\"",
1031 if (reply->elements == 0) {
1032 REDEBUG(
"Got empty result array");
1040 if (reply->element[0]->type != REDIS_REPLY_INTEGER) {
1041 REDEBUG(
"Server returned unexpected type \"%s\" for rcode element (result[0])",
1046 alloc_rctx->
ret = reply->element[0]->integer;
1047 if (alloc_rctx->
ret < 0)
return;
1052 if (reply->elements > 1) {
1061 switch (reply->element[1]->type) {
1068 case REDIS_REPLY_INTEGER:
1076 RPEDEBUG(
"Failed converting integer to IPv4 address");
1087 case REDIS_REPLY_STRING:
1089 NULL, reply->element[1]->str, reply->element[1]->len,
false);
1098 REDEBUG(
"Server returned unexpected type \"%s\" for IP element (result[1])",
1108 if (reply->elements > 2) {
1109 switch (reply->element[2]->type) {
1113 case REDIS_REPLY_STRING:
1124 NULL, reply->element[2]->str, reply->element[2]->len,
true);
1132 case REDIS_REPLY_NIL:
1136 REDEBUG(
"Server returned unexpected type \"%s\" for range element (result[2])",
1148 map_t expiry_map = {
1155 if (reply->element[3]->type != REDIS_REPLY_INTEGER) {
1156 REDEBUG(
"Server returned unexpected type \"%s\" for expiry element (result[3])",
1179 if (reply->type != REDIS_REPLY_ARRAY) {
1180 REDEBUG(
"Expected result to be array got \"%s\"",
1186 if (reply->elements == 0) {
1187 REDEBUG(
"Got empty result array");
1195 if (reply->element[0]->type != REDIS_REPLY_INTEGER) {
1196 REDEBUG(
"Server returned unexpected type \"%s\" for rcode element (result[0])",
1201 update_rctx->
ret = reply->element[0]->integer;
1202 if (update_rctx->
ret < 0)
return;
1207 if (reply->elements > 1) {
1208 switch (reply->element[1]->type) {
1212 case REDIS_REPLY_STRING:
1219 reply->element[1]->str, reply->element[1]->len,
true);
1227 case REDIS_REPLY_NIL:
1231 REDEBUG(
"Server returned unexpected type \"%s\" for range element (result[1])",
1243 map_t expiry_map = {
1269 if (reply->type != REDIS_REPLY_ARRAY) {
1270 REDEBUG(
"Expected result to be array got \"%s\"",
1276 if (reply->elements == 0) {
1277 REDEBUG(
"Got empty result array");
1285 if (reply->element[0]->type != REDIS_REPLY_INTEGER) {
1286 REDEBUG(
"Server returned unexpected type \"%s\" for rcode element (result[0])",
1291 release_rctx->
ret = reply->element[0]->integer;
1294#define CHECK_POOL_NAME \
1295 if (env->pool_name.vb_length > IPPOOL_MAX_KEY_PREFIX_SIZE) { \
1296 REDEBUG("Pool name too long. Expected %u bytes, got %ld bytes", \
1297 IPPOOL_MAX_KEY_PREFIX_SIZE, env->pool_name.vb_length); \
1298 RETURN_UNLANG_FAIL; \
1300 if (env->pool_name.vb_length == 0) { \
1301 RDEBUG2("Empty pool name. Doing nothing"); \
1302 RETURN_UNLANG_NOOP; \
1309 RDEBUG2(
"Forcibly cancelling Redis script load command");
1324 RERROR(
"Failed loading Redis lua script");
1334 redisReply *reply,
UNUSED void *rctx)
1338 if (reply->type != REDIS_REPLY_STRING) {
1339 ERROR(
"Unexpected reply type after loading function");
1342 DEBUG2(
"Loaded lua function with hash \"%s\" onto node", reply->str);
1345#define REDIS_IPPOOL_SCRIPT_LOAD(_cmds, _script, _script_len, _ret) do { \
1346 char const **argv; \
1348 MEM(argv = talloc_array(_cmds, char const *, 3)); \
1349 MEM(argv_len = talloc_array(_cmds, size_t, 3)); \
1350 argv[0] = "SCRIPT"; \
1352 argv[2] = _script; \
1353 argv_len[0] = (sizeof("SCRIPT") - 1); \
1354 argv_len[1] = (sizeof("LOAD") - 1); \
1355 argv_len[2] = _script_len; \
1356 if (fr_redis_command_argv_add(_cmds, 3, argv, argv_len, lua_script_load_results, NULL) != FR_REDIS_PIPELINE_OK) { \
1357 talloc_free(_cmds); \
1369 char const *script,
size_t script_len)
1392 .eval_rctx = mctx->
rctx
1407 inst->coord_pair_reg,
false);
1429 RDEBUG2(
"Forcibly cancelling Redis alloc command");
1443 switch (rctx->
ret) {
1447 RDEBUG2(
"IP address lease allocated");
1451 RWDEBUG(
"Pool contains no free addresses");
1455 RPERROR(
"Allocating IP address failed");
1463 redisFreeCommand(rctx->
cmd_str);
1504 cmd_len = redisFormatCommand(&rctx->
cmd_str,
"EVALSHA %s 1 %b %u %u %b %u %b %u",
1507 (
unsigned int)now.tv_sec, lease_time,
1514 RERROR(
"Failed formatting redis command");
1525 cmd_len = redisFormatCommand(&rctx->
cmd_str,
"EVALSHA %s 1 %b %u %u %b %u %b %s",
1528 (
unsigned int)now.tv_sec, lease_time,
1533 if (cmd_len < 0)
goto format_error;
1546 RDEBUG2(
"Forcibly cancelling Redis update command");
1562 switch (rctx->
ret) {
1571 if (
inst->copy_on_update) {
1584 RPEDEBUG(
"Failed copying IP address to reply attribute");
1598 REDEBUG(
"Requested IP address \"%pV\" is not a member of the specified pool",
1603 REDEBUG(
"Requested IP address' \"%pV\" lease already expired at time of renewal",
1608 REDEBUG(
"Requested IP address' \"%pV\" lease allocated to another device",
1613 RPERROR(
"Failed updating IP address");
1621 redisFreeCommand(rctx->
cmd_str);
1652 if ((ip->
af == AF_INET) &&
inst->ipv4_integer) {
1655 (
unsigned int)now.tv_sec, expires, htonl(ip->
addr.v4.s_addr),
1660 RERROR(
"Failed formatting redis command");
1669 (
unsigned int)now.tv_sec, expires, ip_buff,
1672 if (cmd_len < 0)
goto format_error;
1685 RDEBUG2(
"Forcibly cancelling Redis release command");
1700 switch (rctx->
ret) {
1713 REDEBUG(
"Requested IP address \"%pV\" is not a member of the specified pool",
1718 REDEBUG(
"Requested IP address' \"%pV\" lease allocated to another device",
1723 RPERROR(
"Failed releasing IP address");
1731 redisFreeCommand(rctx->
cmd_str);
1756 if ((ip->af == AF_INET) &&
inst->ipv4_integer) {
1759 (
unsigned int)now.tv_sec, htonl(ip->addr.v4.s_addr),
1764 RERROR(
"Failed formatting redis command");
1773 (
unsigned int)now.tv_sec, ip_buff,
1776 if (cmd_len < 0)
goto format_error;
1788 RDEBUG2(
"Bulk release not yet implemented");
1802 if (reply->type != REDIS_REPLY_ARRAY) {
1803 ERROR(
"Failed retrieving result, expected array got %s",
1808 if (reply->elements != 2) {
1809 ERROR(
"Failed retrieving result, expected array with two elements, got %zu elements",
1814 if (reply->element[0]->type != REDIS_REPLY_STRING) {
1815 ERROR(
"Failed retrieving result, expected string got %s",
1820 if (reply->element[1]->type != REDIS_REPLY_ARRAY) {
1821 ERROR(
"Failed retrieving result, expected array got %s",
1828 for (k = 0; k < reply->element[1]->elements; k++) {
1830 redisReply *pool_key = reply->element[1]->element[k];
1835 if (pool_key->len < 7)
continue;
1837 if ((pool_key->str[0]) !=
'{')
continue;
1838 p = memchr(pool_key->str + 1,
'}', pool_key->len - 1);
1841 len = (pool_key->len - ((p + 1) - pool_key->str));
1850 fr_value_box_list_insert_tail(&pools_rctx->
pools, vb);
1861 RDEBUG2(
"Forcefully cancelling Redis SCAN command");
1877 fr_value_box_list_talloc_free(&rctx->
pools);
1889 if ((rctx->
cursor[0] ==
'0') && rctx->
cursor[1] ==
'\0') {
1895 fr_value_box_list_remove(&rctx->
pools, vb);
1932 redisFreeCommand(rctx->
cmd_str);
1985 redisFreeCommand(rctx->
cmd_str);
1996 fr_value_box_list_init(&rctx->
pools);
2013 while (i < talloc_array_length(rctx->
cmd_str)) {
2015 if (!cmd_str)
break;
2016 redisFreeCommand(cmd_str);
2027 for (i = 0; i < talloc_array_length(rctx->
cmd_str); i++) {
2028 if (!rctx->
cmd_str[i])
return 0;
2029 redisFreeCommand(rctx->
cmd_str[i]);
2039 RDEBUG2(
"Forcibly cancelling Redis command");
2063 redisReply *ip_reply;
2074 if (reply->type != REDIS_REPLY_ARRAY)
return;
2075 if (reply->elements < 2)
return;
2077 if (reply->element[0]->type == REDIS_REPLY_NIL)
return;
2078 if (reply->element[0]->type != REDIS_REPLY_STRING)
return;
2079 if (reply->element[1]->type != REDIS_REPLY_ARRAY)
return;
2092 vp->vp_bool = active;
2095 ip_reply = reply->element[1];
2096 if (ip_reply->element[0]->type == REDIS_REPLY_STRING) {
2101 if (ip_reply->element[1]->type == REDIS_REPLY_STRING) {
2106 if (ip_reply->element[2]->type == REDIS_REPLY_STRING) {
2113#define ADD_REDIS_COMMAND(_fmt, ...) cmd_len = redisFormatCommand(&rctx->cmd_str[cmd_no], _fmt, __VA_ARGS__); \
2114if (cmd_len < 0) RETURN_UNLANG_FAIL; \
2115if (fr_redis_command_preformatted_add(cmds, rctx->cmd_str[cmd_no++], cmd_len, NULL, NULL) != FR_REDIS_PIPELINE_OK) goto error
2125 size_t cmd_no = 0, lookup_no = 0;
2156 rctx->
lookup[lookup_no++] = addr;
2166 rctx->
cmds,
false, NULL);
2177 fr_pair_t *stats_vp, *dynamic_vp, *static_vp, *
vp;
2182 if (reply->type != REDIS_REPLY_ARRAY)
return;
2183 if (reply->elements != 12)
return;
2185 for (i = 0; i < reply->elements; i++)
if (reply->element[i]->type != REDIS_REPLY_INTEGER)
return;
2191#define POPULATE_PAIR(_da, _i, _parent) MEM(vp = fr_pair_afrom_da(_parent, _da)); \
2192 vp->vp_uint64 = reply->element[_i]->integer; \
2193 fr_pair_append(&_parent->vp_group, vp)
2201 vp->vp_uint64 = reply->element[0]->integer - reply->element[6]->integer;
2241 MEM(rctx->
cmd_str = talloc_zero_array(rctx,
char *, 12));
2275 rctx->
cmds,
false, NULL);
2289 addr->
addr.v4.s_addr = htonl(ntohl(addr->
addr.v4.s_addr) + inc);
2296 memcpy(&ip_curr, addr->
addr.v6.s6_addr,
sizeof(ip_curr));
2297 ip_curr = ntohlll(ip_curr);
2301 ip_curr = htonlll(ip_curr);
2302 memcpy(&addr->
addr.v6.s6_addr, &ip_curr,
sizeof(addr->
addr.v6.s6_addr));
2320 uint8_t *prefix_out,
size_t *step,
size_t *num_addr,
2323 uint8_t prefix, subnetlen = subnet->vb_ip.prefix;
2325 switch (subnet->vb_ip.af) {
2327 prefix = (prefix_in && prefix_in->type ==
FR_TYPE_UINT8) ? prefix_in->vb_uint8 : 32;
2328 if ((prefix < 1) || (prefix > 32)) {
2329 RERROR(
"Prefix %d out of range (1-32)", prefix);
2332 *step = 1 << (32 - prefix);
2336 prefix = (prefix_in && prefix_in->type ==
FR_TYPE_UINT8) ? prefix_in->vb_uint8 : 128;
2337 if ((prefix < 1) || (prefix > 128)) {
2338 RERROR(
"Prefix %d out of range (1-128)", prefix);
2341 *step = 1 << (128 - prefix);
2349 *prefix_out = prefix;
2351 if (prefix < subnetlen) {
2352 ERROR(
"Prefix len must be greater than or equal to subnet length (%u)", subnetlen);
2356 switch (subnet->vb_ip.af) {
2361#ifdef __clang_analyzer__
2367 subnet->vb_ip.prefix = 32;
2369 if (subnetlen == 32) {
2375 ip = ntohl(start->vb_ip.addr.v4.s_addr);
2381 if (prefix == 32) ip--;
2384 end->vb_ipv4addr = htonl(ip);
2390 uint128_t ip, p_mask;
2392#ifdef __clang_analyzer__
2398 subnet->vb_ip.prefix = 128;
2400 if (subnetlen == 128) {
2406 memcpy(&ip, start->vb_ipv6addr,
sizeof(ip));
2412 memcpy(&end->vb_ipv6addr, &ip,
sizeof(end->vb_ipv6addr));
2421 *num_addr = (
size_t)1 << (prefix - subnetlen);
2440 if (start->vb_ip.af != end->vb_ip.af) {
2441 RERROR(
"Mis-matched start and end IP address types");
2445 switch (start->vb_ip.af) {
2449 start_ip = ntohl(start->vb_ipv4addr);
2450 end_ip = ntohl(end->vb_ipv4addr);
2452 prefix = (prefix_in && prefix_in->type ==
FR_TYPE_UINT8) ? prefix_in->vb_uint8 : 32;
2453 if ((prefix < 1) || (prefix > 32)) {
2454 RERROR(
"Prefix %d out of range (1-32)", prefix);
2457 *step = 1 << (32 - prefix);
2458 *num_addr = (end_ip - start_ip + 1) / *step;
2464 uint128_t start_ip, end_ip;
2466 memcpy(&start_ip, start->vb_ipv6addr,
sizeof(start_ip));
2467 memcpy(&end_ip, end->vb_ipv6addr,
sizeof(end_ip));
2469 start_ip = ntohlll(start_ip);
2470 end_ip = ntohlll(end_ip);
2472 prefix = (prefix_in && prefix_in->type ==
FR_TYPE_UINT8) ? prefix_in->vb_uint8 : 128;
2473 if ((prefix < 1) || (prefix > 128)) {
2474 RERROR(
"Prefix %d out of range (1-127)", prefix);
2477 *step = 1 << (128 - prefix);
2478 *num_addr =
uint128_sub(end_ip, start_ip) + 1 / *step;
2488 *prefix_out = prefix;
2499 RDEBUG2(
"Forcibly cancelling pending IP pool command");
2523 inst->coord_pair_reg,
false);
2536 PERROR(
"Server returned error");
2544 vb->vb_uint32 = rctx->
changes;
2558 if (reply->type != REDIS_REPLY_INTEGER) {
2559 RERROR(
"Unexpected reply type");
2563 xlat_rctx->
changes += reply->integer;
2578 if (reply->type != REDIS_REPLY_ARRAY) {
2580 RERROR(
"Unexpected reply type");
2584 if ((reply->elements > 0) && (reply->element[0]->type == REDIS_REPLY_INTEGER)) {
2585 xlat_rctx->
changes += reply->element[0]->integer;
2603 bool use_range =
false;
2606 char ipaddr[INET6_ADDRSTRLEN + 1];
2610 if (prefix != (curr_addr.vb_ip.af == AF_INET ? 32 : 128)) {
2613 curr_addr.vb_ip.prefix = prefix;
2625 MEM(rctx->
cmd_str = talloc_zero_array(rctx,
char *, num_addr * (use_range ? 2 : 1)));
2628 DEBUG3(
"Adding %pV to pool \"%pV\"", &curr_addr, pool);
2631 cmd_len = redisFormatCommand(&rctx->
cmd_str[cmd_no],
"ZADD %b NX %u %s", key, p - key, 0,
2649 cmd_len = redisFormatCommand(&rctx->
cmd_str[cmd_no],
"HSET %b range %b", ip_key, ip_key_p - ip_key,
2650 range->vb_strvalue, range->vb_length);
2664 }
while (
fr_ipaddr_cmp(&curr_addr.vb_ip, &end->vb_ip) != 1);
2667 pool->vb_length, rctx->
cmds,
false, NULL);
2691 size_t num_addr, step;
2693 XLAT_ARGS(
in, &pool, &subnet, &prefix_in, &range);
2717 size_t num_addr = 1, step = 1;
2719 XLAT_ARGS(
in, &pool, &start, &end, &prefix_in, &range);
2731 uint8_t prefix,
size_t num_addr,
size_t step)
2738 char ipaddr[INET6_ADDRSTRLEN + 1];
2742 if (prefix != (curr_addr.vb_ip.af == AF_INET ? 32 : 128)) {
2745 curr_addr.vb_ip.prefix = prefix;
2752 MEM(rctx->
cmd_str = talloc_zero_array(rctx,
char *, num_addr));
2755 DEBUG3(
"Removing %pV from pool \"%pV\"", &curr_addr, pool);
2759 pool->vb_strvalue, pool->vb_length, ipaddr);
2769 }
while (
fr_ipaddr_cmp(&curr_addr.vb_ip, &end->vb_ip) != 1);
2772 pool->vb_length, rctx->
cmds,
false, NULL);
2795 size_t num_addr, step;
2820 size_t num_addr = 1, step = 1;
2834 uint8_t prefix,
size_t num_addr,
size_t step)
2841 char ipaddr[INET6_ADDRSTRLEN + 1];
2845 if (prefix != (curr_addr.vb_ip.af == AF_INET ? 32 : 128)) {
2848 curr_addr.vb_ip.prefix = prefix;
2855 MEM(rctx->
cmd_str = talloc_zero_array(rctx,
char *, num_addr));
2858 DEBUG3(
"Releasing %pV to pool \"%pV\"", &curr_addr, pool);
2862 pool->vb_strvalue, pool->vb_length, ipaddr);
2872 }
while (
fr_ipaddr_cmp(&curr_addr.vb_ip, &end->vb_ip) != 1);
2875 pool->vb_length, rctx->
cmds,
false, NULL);
2898 size_t num_addr, step;
2923 size_t num_addr = 1, step = 1;
2948 if (prefix != (curr_addr.vb_ip.af == AF_INET ? 32 : 128)) {
2951 curr_addr.vb_ip.prefix = prefix;
2958 MEM(rctx->
cmd_str = talloc_zero_array(rctx,
char *, num_addr));
2964 DEBUG3(
"Modifying %pV in pool \"%pV\"", &curr_addr, pool);
2969 cmd_len = redisFormatCommand(&rctx->
cmd_str[cmd_no],
"HSET %b range %b", ip_key, ip_key_p - ip_key,
2970 (
uint8_t const *)range->vb_strvalue, range->vb_length);
2980 }
while (
fr_ipaddr_cmp(&curr_addr.vb_ip, &end->vb_ip) != 1);
2983 pool->vb_length, rctx->
cmds,
false, NULL);
3007 size_t num_addr, step;
3009 XLAT_ARGS(
in, &pool, &subnet, &range, &prefix_in);
3033 size_t num_addr = 1, step = 1;
3035 XLAT_ARGS(
in, &pool, &start, &end, &range, &prefix_in);
3061 uint8_t const *range_str = NULL;
3062 size_t range_len = 0;
3067 range_str = (
uint8_t const *)range->vb_strvalue;
3068 range_len = range->vb_length;
3075 MEM(rctx->
cmd_str = talloc_zero_array(rctx,
char *, 1));
3079 (
uint8_t const *)pool->vb_strvalue, pool->vb_length, ip_buff,
3080 (
uint8_t const *)owner->vb_strvalue, owner->vb_length,
3091 pool->vb_length, rctx->
cmds,
false, NULL);
3124 MEM(rctx->
cmd_str = talloc_zero_array(rctx,
char *, 1));
3128 (
uint8_t const *)pool->vb_strvalue, pool->vb_length, ip_buff,
3129 (
uint8_t const *)owner->vb_strvalue, owner->vb_length,
3140 pool->vb_length, rctx->
cmds,
false, NULL);
3160 ERROR(
"Failed to enqueue lua function loading");
3183 if (!
inst->conf.use_cluster_map)
return 0;
3188 ERROR(
"Failed to attach to coordinator");
3201 static bool done_hash =
false;
3208 inst->conf.module_name = mctx->
mi->module->
name;
3211 if (
inst->conf.use_tls) {
3214 if (!
inst->tls_conf) {
3220 if (!
inst->conf.use_cluster_map)
goto cmds;
3222 if (
inst->conf.database) {
3223 cf_log_err(mctx->
mi->
conf,
"Cannot set Redis database number when cluster in use");
3229 .worker_cb = worker_pair_callbacks,
3230 .cb_id = REDIS_COORD_PAIR_CALLBACK_ID,
3235 if (!
inst->coord_pair_reg)
return -1;
3241 .coord_cb = coord_callbacks,
3242 .worker_cb = worker_callbacks,
3246 if (!
inst->coord_reg)
return -1;
3249 if (
inst->wait_num) {
3250 inst->wait_cmd_len = redisFormatCommand(&
inst->wait_cmd,
"WAIT %i %i",
inst->wait_num,
3252 if (
inst->wait_cmd_len < 0)
return -1;
3286 if (!t->
cw)
return 0;
3300 if (
inst->wait_cmd) redisFreeCommand(
inst->wait_cmd);
3377 .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)
#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_parser_t const * env
Parsing rules for call method env.
@ 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.
#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_DEPRECATED(_name, _struct, _field)
conf_parser_t entry which raises an error if a matching CONF_PAIR 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
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
@ CONF_FLAG_SUBSECTION
Instead of putting the information into a configuration structure, the configuration file routines MA...
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_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.
fr_redis_ct_t * fr_redis_ct_alloc(TALLOC_CTX *ctx, CONF_SECTION *tls_cs, 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.
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.
union fr_ipaddr_t::@154 addr
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.
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)
Represents a single command.
Represents a collection of pipelined commands.
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.
@ FR_REDIS_PIPELINE_OK
No failure.
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
void fr_redis_reply_print(fr_log_lvl_t lvl, redisReply *reply, request_t *request, int idx, fr_redis_rcode_t status)
Print the response data in a useful treelike form.
#define REDIS_COMMON_CONFIG
@ 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.
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_RCODE_SUCCESS
Operation was successful.
Configuration parameters for a redis connection.
#define IPPOOL_STATIC_BIT
#define _IPPOOL_RCODE_NOT_FOUND
#define IPPOOL_MAX_POOL_KEY_SIZE
{prefix}:pool
#define _IPPOOL_RCODE_POOL_EMPTY
@ IPPOOL_RCODE_DEVICE_MISMATCH
@ 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 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
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.
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.
#define POPULATE_PAIR(_da, _i, _parent)
fr_value_box_t lease_time
How long an IP address should be allocated for.
static xlat_action_t redis_ippool_list_resume(UNUSED TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
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.
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
Number of changes reported by redis.
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
CONF_SECTION * tls_conf
TLS CONF_SECTION.
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.
static xlat_action_t redis_ippool_common_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
Common resume function for pool manipulation xlats.
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)
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
static unlang_action_t mod_show(unlang_result_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
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)
static unlang_action_t mod_stats(unlang_result_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
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 mod_thread_detach(module_thread_inst_ctx_t const *mctx)
static int _redis_ippool_alloc_ctx_free(redis_ippool_alloc_rctx_t *rctx)
static int mod_instantiate(module_inst_ctx_t const *mctx)
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.
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
fr_signal_t
Signals that can be generated/processed by request signal handlers.
@ 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.
#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
@ XLAT_ACTION_FAIL
An xlat function failed.
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
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.
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.
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.
ssize_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)
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.
#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)
static size_t char ** out
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