return 0;
}
+ /*
+ * If we have affinity, then maybe update State. But
+ * only for Access-Request, and only if there's a State
+ * attribute in the reply.
+ */
+ if (request->home_pool->affinity_group &&
+ (request->packet->code == PW_CODE_ACCESS_REQUEST) &&
+ ((vp = fr_pair_find_by_num(request->reply->vps, PW_STATE, 0, TAG_ANY)) != NULL)) {
+ uint8_t *src;
+
+ src = talloc_array(vp, uint8_t, vp->vp_length + 1);
+ if (!src) return 0;
+
+ src[0] = request->home_server->affinity;
+ memcpy(&src[1], vp->vp_octets, vp->vp_length);
+ fr_pair_value_memsteal(vp, src);
+ }
+
return 1;
}
{ "username", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_NOT_EMPTY, home_server_t, ping_user_name), NULL },
{ "password", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_NOT_EMPTY, home_server_t, ping_user_password), NULL },
+ { "affinity", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, affinity), NULL},
+
#ifdef WITH_STATS
{ "historic_average_window", FR_CONF_OFFSET(PW_TYPE_INTEGER, home_server_t, ema.window), NULL },
#endif
if (parent && strcmp(cf_section_name1(parent), "server") == 0) {
home->parent_server = cf_section_name2(parent);
}
+
+ FR_INTEGER_BOUND_CHECK("coa_mrt", home->affinity, <=, 255);
}
/** Insert a new home server into the various internal lookup trees
}
}
+ if (home->affinity) {
+ if (home->virtual_server) {
+ ERROR("Home server %s is a virtual server, and cannot be used with 'affinity'", home->name);
+ goto error;
+ }
+
+ if (!pool->affinity_group) {
+ pool->affinity_group = talloc_zero_array(pool, home_server_t *, pool->num_home_servers);
+ if (!pool->affinity_group) {
+ ERROR("Out of memory");
+ goto error;
+ }
+ }
+
+ if (home->affinity >= (uint32_t) pool->num_home_servers) {
+ ERROR("Home server %s has invalid 'affinity' value %u. It must be less than %u",
+ home->name, home->affinity, home->affinity, pool->num_home_servers);
+ goto error;
+ }
+
+ if (pool->affinity_group[home->affinity]) {
+ ERROR("Home server %s has invalid 'affinity' value %u. That value is already used by home server %s",
+ home->name, home->affinity, pool->affinity_group[home->affinity]->name);
+ goto error;
+ }
+
+ pool->affinity_group[home->affinity] = home;
+ }
+
if (!home) {
ERROR("Failed to find home server %s", value);
goto error;
pool->servers[num_home_servers++] = home;
} /* loop over home_server's */
- if (pool->fallback && do_print) {
- cf_log_info(cs, "\tfallback = %s", pool->fallback->name);
+ if (pool->fallback) {
+ if (do_print) cf_log_info(cs, "\tfallback = %s", pool->fallback->name);
+
+ if (pool->affinity_group) {
+ ERROR("Cannot use home server pool 'fallback' when home server 'affinity' is set");
+ goto error;
+ }
}
if (!realm_pool_add(pool, cs)) goto error;
}
home_server_t *home_server_ldb(char const *realmname,
- home_pool_t *pool, REQUEST *request)
+ home_pool_t *pool, REQUEST *request)
{
int start;
int count;
VALUE_PAIR *vp;
uint32_t hash;
+ /*
+ * Over-ride the pool configuration if the pool is marked up as having affinity, AND the packet has a State attribute.
+ */
+ if (pool->affinity_group &&
+ (request->packet->code == PW_CODE_ACCESS_REQUEST) &&
+ ((vp = fr_pair_find_by_num(request->packet->vps, PW_STATE, 0, TAG_ANY)) != NULL) &&
+ (vp->vp_length > 1) &&
+ (vp->vp_octets[0] < (uint32_t) pool->num_home_servers) &&
+ (pool->affinity_group[vp->vp_octets[0]] != NULL)) {
+ found = pool->affinity_group[vp->vp_octets[0]];
+
+ if (HOME_SERVER_IS_DEAD(found)) return NULL;
+
+ /*
+ * Get rid of the extra octet that we added on the outbound proxying.
+ */
+ fr_pair_value_memcpy(vp, vp->vp_octets + 1, vp->vp_length - 1);
+ return found;
+ }
+
/*
* Determine how to pick choose the home server.
*/