changeset 514:179ef7de53de

New extension: load-balancing based on numerical user-name AVP values
author Sebastien Decugis <sdecugis@nict.go.jp>
date Wed, 25 Aug 2010 19:00:25 +0900
parents 662b1f9258c3
children b9167b4de7dc
files extensions/CMakeLists.txt extensions/rt_un_number/CMakeLists.txt extensions/rt_un_number/rtun.c extensions/rt_un_number/rtun.h extensions/rt_un_number/rtun_conf.l extensions/rt_un_number/rtun_conf.y
diffstat 6 files changed, 500 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- 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
--- /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)
--- /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 <sdecugis@nict.go.jp>							 *
+*													 *
+* 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: "<number> 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);
--- /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 <sdecugis@nict.go.jp>							 *
+*													 *
+* 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 <freeDiameter/extension.h>
+
+/* 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;
+
--- /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 <sdecugis@nict.go.jp>							 *
+*													 *
+* 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; 
+			}
+
+%%
--- /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 <sdecugis@nict.go.jp>							 *
+*													 *
+* 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 <string>	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;
+			}
+			;
"Welcome to our mercurial repository"