# HG changeset patch # User Sebastien Decugis # Date 1282730425 -32400 # Node ID 179ef7de53de9a54b9aaf22a9ff8472753bed829 # Parent 662b1f9258c3d5f2d5269573033eafa11df6f0aa New extension: load-balancing based on numerical user-name AVP values diff -r 662b1f9258c3 -r 179ef7de53de extensions/CMakeLists.txt --- a/extensions/CMakeLists.txt Tue Aug 24 16:20:32 2010 +0900 +++ b/extensions/CMakeLists.txt Wed Aug 25 19:00:25 2010 +0900 @@ -76,6 +76,11 @@ SUBDIRS(rt_default) ENDIF (BUILD_RT_DEFAULT) +OPTION(BUILD_RT_UN_NUMBER "Build rt_un_number? (Load-balancing based on numerical User-Name AVP value)" OFF) + IF (BUILD_RT_UN_NUMBER) + SUBDIRS(rt_un_number) + ENDIF (BUILD_RT_UN_NUMBER) + #### # Peers security extensions diff -r 662b1f9258c3 -r 179ef7de53de extensions/rt_un_number/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extensions/rt_un_number/CMakeLists.txt Wed Aug 25 19:00:25 2010 +0900 @@ -0,0 +1,30 @@ +# The rt_default extension +PROJECT("Numeric User-Name AVP based load-balancing extension" C) + +# Parser files +BISON_FILE(rtun_conf.y) +FLEX_FILE(rtun_conf.l) +SET_SOURCE_FILES_PROPERTIES(lex.rtun_conf.c rtun_conf.tab.c PROPERTIES COMPILE_FLAGS "-I ${CMAKE_CURRENT_SOURCE_DIR}") + +# List of source files +SET( RTUN_SRC + rtun.c + rtun.h + lex.rtun_conf.c + rtun_conf.tab.c + rtun_conf.tab.h +) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) + +# Compile these files as a freeDiameter extension +FD_ADD_EXTENSION(rt_un_number ${RTUN_SRC}) + + +#### +## INSTALL section ## + +# We install with the daemon component because it is a base feature. +INSTALL(TARGETS rt_un_number + LIBRARY DESTINATION ${INSTALL_EXTENSIONS_SUFFIX} + COMPONENT freeDiameter-rt-un-number) diff -r 662b1f9258c3 -r 179ef7de53de extensions/rt_un_number/rtun.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extensions/rt_un_number/rtun.c Wed Aug 25 19:00:25 2010 +0900 @@ -0,0 +1,165 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2010, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +/* + * Load-balancing routing extension for numeric-based User-Name values + * + * This extension relies on a User-Name AVP in the format: " text". + * It will load-balance the messages between the servers defined in the configuration, + * based on the number. + * For example, if the configuratino contains 3 servers A, B, C, then: + * "1 first user" -> A + * "2 second user" -> B + * "3 third" -> C + * "4 fourth" -> A + * "99 and so on" -> C + * + * The message is sent to the server selected only if it is in OPEN state, of course. + * Otherwise, this extension has no effect, and the default routing behavior will be used. + * + * Note that the score added is FD_SCORE_LOAD_BALANCE, which mean any other routing + * indication will take precedence (for example Destination-Host AVP). + */ + +#include "rtun.h" + +/* The configuration structure */ +struct rtun_conf rtun_conf; + +/* The callback called on new messages */ +static int rtun_out(void * cbdata, struct msg * msg, struct fd_list * candidates) +{ + struct avp * avp = NULL; + + TRACE_ENTRY("%p %p %p", cbdata, msg, candidates); + + CHECK_PARAMS(msg && candidates); + + /* Check if it is worth processing the message */ + if (FD_IS_LIST_EMPTY(candidates)) { + return 0; + } + + /* Now search the user-name AVP */ + CHECK_FCT( fd_msg_search_avp ( msg, rtun_conf.username, &avp ) ); + if (avp != NULL) { + struct avp_hdr * ahdr = NULL; + CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) ); + if (ahdr->avp_value != NULL) { + int conv = 0; + int idx; + + /* We cannot use strtol or sscanf functions without copying the AVP value and \0-terminate it... */ + for (idx = 0; idx < ahdr->avp_value->os.len; idx++) { + char c = (char) ahdr->avp_value->os.data[idx]; + if (c == ' ') + continue; + if ((c >= '0') && (c <= '9')) { + conv *= 10; + conv += c - '0'; + continue; + } + /* we found a non-numeric character, stop */ + break; + } + + if (conv) { + /* We succeeded in reading a numerical value */ + struct fd_list * c; + char *s; + + idx = conv % rtun_conf.serv_nb; + s = rtun_conf.servs[idx]; + + /* We should send the message to 's', search in the candidates list */ + for (c = candidates->next; c != candidates; c = c->next) { + struct rtd_candidate * cand = (struct rtd_candidate *)c; + + if (strcmp(s, cand->diamid) == 0) { + cand->score += FD_SCORE_LOAD_BALANCE; + break; + } + } + } + } + } + + return 0; +} + +/* handler */ +static struct fd_rt_out_hdl * rtun_hdl = NULL; + +/* entry point */ +static int rtun_entry(char * conffile) +{ + TRACE_ENTRY("%p", conffile); + + /* Initialize the configuration */ + memset(&rtun_conf, 0, sizeof(rtun_conf)); + + /* Search the User-Name AVP in the dictionary */ + CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "User-Name", &rtun_conf.username, ENOENT )); + + /* Parse the configuration file */ + CHECK_FCT( rtun_conf_handle(conffile) ); + + /* Register the callback */ + CHECK_FCT( fd_rt_out_register( rtun_out, NULL, 1, &rtun_hdl ) ); + + /* We're done */ + return 0; +} + +/* Unload */ +void fd_ext_fini(void) +{ + int i; + TRACE_ENTRY(); + + /* Unregister the cb */ + CHECK_FCT_DO( fd_rt_out_unregister ( rtun_hdl, NULL ), /* continue */ ); + + /* Destroy the data */ + if (rtun_conf.servs) + for (i = 0; i < rtun_conf.serv_nb; i++) + free(rtun_conf.servs[i]); + free(rtun_conf.servs); + + /* Done */ + return ; +} + +EXTENSION_ENTRY("rt_un_number", rtun_entry); diff -r 662b1f9258c3 -r 179ef7de53de extensions/rt_un_number/rtun.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extensions/rt_un_number/rtun.h Wed Aug 25 19:00:25 2010 +0900 @@ -0,0 +1,53 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2010, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +/* + * See the rt_un_number.conf.sample file for the format of the configuration file. + */ + +/* FreeDiameter's common include file */ +#include + +/* Parse the configuration file */ +int rtun_conf_handle(char * conffile); + +/* The configuration structure */ +extern struct rtun_conf { + int serv_nb; /* Number of servers in the configuration */ + char **servs; /* The array of servers (their Diameter Identities) */ + + struct dict_object * username; /* cache the dictionary object */ +} rtun_conf; + diff -r 662b1f9258c3 -r 179ef7de53de extensions/rt_un_number/rtun_conf.l --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extensions/rt_un_number/rtun_conf.l Wed Aug 25 19:00:25 2010 +0900 @@ -0,0 +1,102 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2010, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +/* Tokenizer + * + */ + +%{ +#include "rtun.h" +/* Include yacc tokens definitions */ +#include "rtun_conf.tab.h" + +/* Update the column information */ +#define YY_USER_ACTION { \ + yylloc->first_column = yylloc->last_column + 1; \ + yylloc->last_column = yylloc->first_column + yyleng - 1; \ +} + +/* Avoid warning with newer flex */ +#define YY_NO_INPUT + +%} + +qstring \"[^\"\n]*\" + + +%option bison-bridge bison-locations +%option noyywrap +%option nounput + +%% + + /* Update the line count */ +\n { + yylloc->first_line++; + yylloc->last_line++; + yylloc->last_column=0; + } + + /* Eat all spaces but not new lines */ +([[:space:]]{-}[\n])+ ; + /* Eat all comments */ +#.*$ ; + + + /* Recognize quoted strings */ +{qstring} { + /* Match a quoted string. */ + CHECK_MALLOC_DO( yylval->string = strdup(yytext+1), + { + TRACE_DEBUG(INFO, "Unable to copy the string '%s': %s\n", yytext, strerror(errno)); + return LEX_ERROR; /* trig an error in yacc parser */ + } ); + yylval->string[strlen(yytext) - 2] = '\0'; + return QSTRING; + } + + /* The key words */ +(?i:"serv") { return SERV; } + + /* Valid single characters for yyparse */ +[=;] { return yytext[0]; } + + /* Unrecognized sequence, if it did not match any previous pattern */ +[^[:space:]\"=;\n]+ { + fd_log_debug("Unrecognized text on line %d col %d: '%s'.\n", yylloc->first_line, yylloc->first_column, yytext); + return LEX_ERROR; + } + +%% diff -r 662b1f9258c3 -r 179ef7de53de extensions/rt_un_number/rtun_conf.y --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extensions/rt_un_number/rtun_conf.y Wed Aug 25 19:00:25 2010 +0900 @@ -0,0 +1,145 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2010, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +/* Yacc extension's configuration parser. + * The configuration file consists in a list of two or more: + * serv = "a.server.diameter.id"; + */ + +/* For development only : */ +%debug +%error-verbose + +/* The parser receives the configuration file filename as parameter */ +%parse-param {char * conffile} + +/* Keep track of location */ +%locations +%pure-parser + +%{ +#include "rtun.h" +#include "rtun_conf.tab.h" /* bison is not smart enough to define the YYLTYPE before including this code, so... */ + +/* Forward declaration */ +int yyparse(char * conffile); + +/* Parse the configuration file */ +int rtun_conf_handle(char * conffile) +{ + extern FILE * rtun_confin; + int ret; + + TRACE_ENTRY("%p", conffile); + + TRACE_DEBUG (FULL, "Parsing configuration file: %s...", conffile); + + rtun_confin = fopen(conffile, "r"); + if (rtun_confin == NULL) { + ret = errno; + fd_log_debug("Unable to open extension configuration file %s for reading: %s\n", conffile, strerror(ret)); + TRACE_DEBUG (INFO, "Error occurred, message logged -- configuration file."); + return ret; + } + + ret = yyparse(conffile); + + fclose(rtun_confin); + + if (ret != 0) { + TRACE_DEBUG (INFO, "Unable to parse the configuration file."); + return EINVAL; + } else { + TRACE_DEBUG(FULL, "[rt-un-nb] Added %d servers successfully.", rtun_conf.serv_nb); + } + + return 0; +} + +/* The Lex parser prototype */ +int rtun_conflex(YYSTYPE *lvalp, YYLTYPE *llocp); + +/* Function to report the errors */ +void yyerror (YYLTYPE *ploc, char * conffile, char const *s) +{ + TRACE_DEBUG(INFO, "Error in configuration parsing"); + + if (ploc->first_line != ploc->last_line) + fd_log_debug("%s:%d.%d-%d.%d : %s\n", conffile, ploc->first_line, ploc->first_column, ploc->last_line, ploc->last_column, s); + else if (ploc->first_column != ploc->last_column) + fd_log_debug("%s:%d.%d-%d : %s\n", conffile, ploc->first_line, ploc->first_column, ploc->last_column, s); + else + fd_log_debug("%s:%d.%d : %s\n", conffile, ploc->first_line, ploc->first_column, s); +} + +%} + +/* Values returned by lex for token */ +%union { + char *string; /* The string is allocated by strdup in lex.*/ +} + +/* In case of error in the lexical analysis */ +%token LEX_ERROR + +/* A (de)quoted string (malloc'd in lex parser; it must be freed after use) */ +%token QSTRING + +/* Tokens */ +%token SERV + + +/* -------------------------------------- */ +%% + + /* The grammar definition */ +conffile: /* empty grammar is OK */ + | conffile serv + ; + + /* a server entry */ +serv: SERV '=' QSTRING ';' + { + /* Add this new server in the list */ + rtun_conf.serv_nb += 1; + CHECK_MALLOC_DO( rtun_conf.servs = realloc(rtun_conf.servs, rtun_conf.serv_nb * sizeof(char *)), + { + yyerror (&yylloc, conffile, "Not enough memory to store the configuration..."); + YYERROR; + } ); + + rtun_conf.servs[rtun_conf.serv_nb - 1] = $3; + } + ;