Patch to add support for a 'round_robin' load balancing distribution of
authorcparker <cparker>
Tue, 1 Oct 2002 22:18:50 +0000 (22:18 +0000)
committercparker <cparker>
Tue, 1 Oct 2002 22:18:50 +0000 (22:18 +0000)
radius requests to realms with multiple entries.  Configureable number
of 'max servers' per realm.  Default behaviour maintains backwards
compatability of simple 'fail-over'.

Contributed by <cbrotsos@starnetusa.net>

raddb/proxy.conf
src/include/radiusd.h
src/main/conffile.c
src/main/files.c
src/main/radiusd.c
src/main/radrelay.c
src/main/radwho.c
src/main/radzap.c

index 267cbe3..294c3ed 100644 (file)
@@ -69,6 +69,14 @@ proxy server {
 #
        dead_time = 120
 
+#  If you choose to list a realm more then once for fall-through or 
+#  round-robin, then specify the total number of alternates here. Specify
+#  a ldflag attribute for all realms to be included in a round-robin 
+#  setup. Currently (0 or fail_over) and (1 or round_robin) are the 
+#  supported values for ldflag. Fail-Over is the default setup.
+#
+       servers_per_realm = 5
+
 #
 #  If all exact matching realms did not respond, we can try the
 #  DEFAULT realm, too.  This is what the server normally does.
@@ -112,6 +120,49 @@ proxy server {
 #      nostrip
 #}
 
+#
+#  1st node serv.com...set up for round-robin.
+#  The ldflag attribute must be specified on all
+#  realms included in a rr scheme. ldflag may also
+#  be set as zero on realms using fail-over. Currently
+#  (0 or fail_over) and (1 or round_robin) are the only 
+#  accepted values for ldflag. Fail-Over is the default setup.
+#
+#realm serv.com {
+#      type        = radius
+#      authhost    = radius.serv.com:1645
+#      accthost    = radius.serv.com:1646
+#      secret      = TheirKey
+#      ldflag      = round_robin
+#      nostrip
+#}
+
+#
+#  Another node for serv.com
+#
+#realm serv.com {
+#      type        = radius
+#      authhost    = radius2.serv.com:1645
+#      accthost    = radius2.serv.com:1646
+#      secret      = TheirKey2
+#      ldflag      = round_robin
+#      nostrip
+#}
+
+#
+#  A third round-robin node realm for serv.com
+#
+#realm serv.com {
+#      type        = radius
+#      authhost    = radius3.serv.com:1645
+#      accthost    = radius3.serv.com:1646
+#      secret      = TheirKey2
+#      ldflag      = round_robin
+#      nostrip
+#}
+#
+#
+
 #realm company.com {
 #      type            = radius
 #      authhost        = radius.company.com:1600
index 47bc10f..2398f73 100644 (file)
@@ -110,6 +110,10 @@ typedef struct _realm {
        time_t                  wakeup;
        int                     acct_active;
        time_t                  acct_wakeup;
+       int                     ldflag;
+       int                     chose;
+       int                     node;
+       int                     total;
        struct _realm           *next;
 } REALM;
 
@@ -145,6 +149,7 @@ typedef struct main_config_t {
 #define RETRY_DELAY             5
 #define RETRY_COUNT             3
 #define DEAD_TIME               120
+#define MAX_PROXIES            15
 
 #define L_DBG                  1
 #define L_AUTH                 2
@@ -249,6 +254,7 @@ int         pairlist_read(const char *file, PAIR_LIST **list, int complain);
 void           pairlist_free(PAIR_LIST **);
 int            read_config_files(void);
 int            read_realms_file(const char *file);
+extern         void check_proxies(int);
 
 /* nas.c */
 int            read_naslist_file(char *);
index f326033..e2bff9a 100644 (file)
@@ -78,6 +78,7 @@ CONF_SECTION *config = NULL;
  */
 extern RADCLIENT *clients;
 extern REALM *realms;
+extern int max_proxies;
 
 static int generate_realms(const char *filename);
 static int generate_clients(const char *filename);
@@ -914,7 +915,7 @@ static int generate_realms(const char *filename)
        CONF_SECTION *cs;
        REALM *my_realms = NULL;
        REALM *c, **tail;
-       char *s, *authhost, *accthost;
+       char *s, *t, *authhost, *accthost;
 
        tail = &my_realms;
        for (cs = cf_subsection_find_next(config, NULL, "realm"); cs != NULL;
@@ -1034,6 +1035,25 @@ static int generate_realms(const char *filename)
                        c->notrealm = 1;
                if ((cf_section_value_find(cs, "notsuffix")) != NULL)
                        c->notrealm = 1;
+               if ((t = cf_section_value_find(cs,"ldflag")) != NULL) {
+                       if ((strcmp(t,"1") == 0) ||
+                           (strcasecmp(t,"round_robin") == 0)) {
+                               c->ldflag = 1;
+                       }
+                       else if ((strcmp(t,"0") == 0) ||
+                                 (strcasecmp(t,"fail_over") == 0)) {
+                               c->ldflag = 0;
+                       }
+                       else {
+                               /*  set to invalid value 
+                                 *  to be caught later
+                                 */
+                               c->ldflag = -1;
+                       }
+               }
+               else {
+                       c->ldflag = 0;
+               }
                c->active = TRUE;
                c->acct_active = TRUE;
 
@@ -1048,6 +1068,40 @@ static int generate_realms(const char *filename)
         */
        *tail = realms;
        realms = my_realms;
+       
+       /*Setup node and total info for multi-listed realms*/
+       for (c = realms; c; c = c->next) {
+               if(c->chose == 1) {
+                       continue;
+               }
+               else {
+                       int i = 0, b = 0;
+                       REALM *rptr, *r_array[max_proxies];
+                       for(rptr = c; rptr; rptr = rptr->next) {
+                               /*if realm matches*/
+                               if(strcasecmp(rptr->realm, c->realm) == 0) {
+                                       i++;
+                                       r_array[i] = rptr;
+                                       rptr->chose = 1;
+                                       rptr->node = i;
+                               }
+                       }
+                       if (i > 1) {
+                               for(b = 1; b <= i; b++) {
+                                       rptr = r_array[b];
+                                       rptr->total = i;
+                               }
+                       }
+                       else {
+                               c->total = 0;
+                       }
+               }
+       }
+       
+       /*Set chose flag back to default (0) on all realms*/
+       for (c = realms; c; c = c->next) {
+               c->chose = 0;
+       }
 
        return 0;
 }
index 0f3681f..194e0ff 100644 (file)
@@ -42,6 +42,7 @@ static const char rcsid[] = "$Id$";
 #include "radiusd.h"
 
 extern int proxy_dead_time;
+int maximum_proxies;
 
 REALM *realms = NULL;
 
@@ -521,13 +522,14 @@ void realm_disable(uint32_t ipaddr, int port)
  */
 REALM *realm_find(const char *realm, int acct)
 {
-       REALM *cl;
+       REALM *cl, *realmptr;
        REALM *default_realm = NULL;
+       REALM *rr_array[maximum_proxies];
        time_t now;
-       int dead_match = 0;
+       int dead_match = 0, efform = 0, p = 0, i = 0;
+       static int proxy_return;
 
        now = time(NULL);
-
        /*
         *      If we're passed a NULL realm pointer,
         *      then look for a "NULL" realm string.
@@ -535,7 +537,7 @@ REALM *realm_find(const char *realm, int acct)
        if (realm == NULL) {
                realm = "NULL";
        }
-
+       
        for (cl = realms; cl; cl = cl->next) {
                /*
                 *      Wake up any sleeping realm.
@@ -571,7 +573,106 @@ REALM *realm_find(const char *realm, int acct)
                 *      If it matches exactly, return it.
                 */
                if (strcasecmp(cl->realm, realm) == 0) {
-                       return cl;
+                        /*
+                         *    Seperate parsing of list for round-robin
+                         */
+                       if(cl->total > 1 && cl->ldflag == 1) {
+                               /*Get all of the realms from initial list*/
+                               for(i = 1; i <= cl->total; i++) {
+                                       for(realmptr = realms; realmptr; 
+                                            realmptr = realmptr->next) {
+                                               if((strcasecmp(realmptr->realm,
+                                                   cl->realm)) == 0 &&
+                                                  (realmptr->node == i)) {
+                                                       rr_array[i] = realmptr;
+                                                       if(realmptr->active == TRUE)
+                                                               p++;
+                                                       break;
+                                               }
+                                               else {
+                                                       continue;
+                                               }
+                                       }
+                               }
+                               /*if only one realm active, return it*/
+                               if(p == 1) {
+                                       for (p = 1; p < i; p++) {
+                                               realmptr = rr_array[p];
+                                               if(realmptr->active == TRUE) {
+                                                       return realmptr;
+                                               }
+                                       }
+                               }
+                               for(p = 1; p < i; p++) {
+                                       realmptr = rr_array[p];
+                                       if(realmptr->chose == 1) {
+                                               efform++;
+                                       }
+                               }
+
+                               /*    
+                                 *    if none available, 
+                                *    and last realm has
+                                *    been returned as access-reply
+                                 */
+
+                               if(efform == cl->total && proxy_return == 0) {
+                                       for(p = 1; p < i; p++) {
+                                               realmptr = rr_array[p];
+                                               realmptr->chose = 0;
+                                       }
+                               }
+
+                               /*    
+                                 *    if this realm hasn't been chosen and 
+                                *    this is not being returned for
+                                 *    access reply
+                                *    else if the realm has been chosen 
+                                 *    and this is for access-reply
+                                 *    else this realm is dead (reset if
+                                *    this is the last realm in the list)
+                                */
+
+                                for(p = 1; p < i; p++) {
+                                       realmptr = rr_array[p];
+                                       if((realmptr->chose == 0) &&
+                                           (proxy_return < realmptr->node) &&
+                                          (realmptr->active == TRUE && realmptr->acct_active == TRUE)
+                                        ) {
+                                               proxy_return = realmptr->node;
+                                               realmptr->chose = 1;
+                                               return realmptr;
+                                       }
+                                       else if ((realmptr->chose == 1) &&
+                                                (proxy_return == realmptr->node)
+                                        ) {
+                                               if(proxy_return + 1 > realmptr->total) {
+                                                       proxy_return = 0;
+                                               }
+                                               realmptr->chose = 0;
+                                               return realmptr;
+                                       }
+                                       else 
+                                       {
+                                               if((realmptr->active == FALSE ||
+                                                   realmptr->acct_active == FALSE ) &&
+                                                  (realmptr->node == realmptr->total)
+                                                ) {
+                                                       proxy_return = 0;
+                                               }
+                                               continue;
+                                       }
+                               }
+                       }
+                       
+                       /*    
+                        *    else we have single 
+                         *    realm or non-rr realm
+                         */
+                       
+                       else {
+                               return cl;
+                       }
                }
 
                /*
@@ -627,3 +728,40 @@ REALM *realm_findbyaddr(uint32_t ipaddr, int port)
 
        return NULL;
 }
+
+/*
+ *    Catch any errors in set-up of RR list or exceeding max_proxies
+ */
+void check_proxies(int max_config) {
+       REALM *next, *rptr;
+       if(max_config > 0) {
+               maximum_proxies = max_config;
+               for(rptr=realms; rptr; rptr = rptr->next) {
+                       if(rptr->total > max_config || rptr->total >= 1) {
+                               for(next = realms; next; next = next->next) {
+                                       if(next->ldflag != 0 &&
+                                           next->ldflag != 1) {
+                                               radlog(L_ERR,
+                                                   "Invalid load balance flag on realm: %s entry %d\n",
+                                                     next->realm, next->node);
+                                               exit(1);
+                                       }
+                                       else if((strcasecmp(rptr->realm, next->realm) == 0) && 
+                                            rptr->ldflag != next->ldflag){ 
+                                               radlog(L_ERR,
+                                                   "Inconsistent ldflag for realm: %s entries %d and %d.\n", 
+                                                    rptr->realm, rptr->node, next->node);
+                                              exit(1);
+                                       }
+                                       else if (next->total > max_config) {
+                                           radlog(L_ERR,
+                                               "Too many entries (%d) for realm: %s. Max is %d.\n",
+                                                next->total, next->realm, max_config);
+                                           exit(1);
+                                       }
+                               }
+                       }
+               }
+               maximum_proxies++;
+       }
+}
index 34b7238..e7a83f4 100644 (file)
@@ -108,6 +108,7 @@ int proxy_port;
 int proxy_retry_delay = RETRY_DELAY;
 int proxy_retry_count = RETRY_COUNT;
 int proxy_dead_time = DEAD_TIME;
+int max_proxies = MAX_PROXIES;
 int proxy_synchronous = FALSE;
 int proxy_fallback = FALSE;
 int need_reload = FALSE;
@@ -168,6 +169,7 @@ static CONF_PARSER proxy_config[] = {
        { "synchronous",  PW_TYPE_BOOLEAN, 0, &proxy_synchronous, "no" },
        { "default_fallback", PW_TYPE_BOOLEAN, 0, &proxy_fallback, "no" },
        { "dead_time",    PW_TYPE_INTEGER, 0, &proxy_dead_time, Stringify(DEAD_TIME) },
+       { "servers_per_realm",  PW_TYPE_INTEGER, 0, &max_proxies, Stringify(MAX_PROXIES) },
        { NULL, -1, 0, NULL, NULL }
 };
 
@@ -789,6 +791,7 @@ int main(int argc, char *argv[])
                /*
                 *  Open Proxy Socket.
                 */
+               check_proxies(max_proxies);
                proxyfd = socket (AF_INET, SOCK_DGRAM, 0);
                if (proxyfd < 0) {
                        perror ("proxy socket");
index 2258566..bb48d64 100644 (file)
@@ -73,6 +73,7 @@ uint32_t myip = INADDR_ANY;
 int proxy_retry_delay = RETRY_DELAY;
 int proxy_retry_count = RETRY_COUNT;
 int proxy_dead_time;
+int max_proxies = MAX_PROXIES;
 int log_stripped_names;
 struct main_config_t mainconfig;
 
index 687145b..3ca9652 100644 (file)
@@ -88,6 +88,7 @@ uint32_t myip = INADDR_ANY;
 int proxy_retry_delay = RETRY_DELAY;
 int proxy_retry_count = RETRY_COUNT;
 int proxy_dead_time;
+int max_proxies = MAX_PROXIES;
 int log_stripped_names;
 struct main_config_t mainconfig;
 
index d38c15a..4797fe7 100644 (file)
@@ -56,6 +56,7 @@ int acct_port;
 int proxy_retry_delay = RETRY_DELAY;
 int proxy_retry_count = RETRY_COUNT;
 int proxy_dead_time;
+int max_proxies = MAX_PROXIES;
 int log_stripped_names;
 radlog_dest_t radlog_dest = RADLOG_FILES;
 const char *radutmp_file = NULL;