# HG changeset patch # User Sebastien Decugis # Date 1420222927 -28800 # Node ID 3eeb564e7bea9492e9e1a684ce1ec720118225eb # Parent c748e2439a3a918b2a9cfb1daeaedee8823c4c7e# Parent a1685a53fe971faabc5ae39f0e905e22642f07ae Merge updates from Thomas (thanks\!) diff -r c748e2439a3a -r 3eeb564e7bea contrib/test_Gx/main_gx.c --- a/contrib/test_Gx/main_gx.c Sat Jan 03 02:18:53 2015 +0800 +++ b/contrib/test_Gx/main_gx.c Sat Jan 03 02:22:07 2015 +0800 @@ -13,58 +13,13 @@ #define VENDOR_ID_3GPP 10415 /* The content of this file follows the same structure as dict_base_proto.c */ +#if 0 #define CHECK_dict_new( _type, _data, _parent, _ref ) \ CHECK_FCT( fd_dict_new( fd_g_config->cnf_dict, (_type), (_data), (_parent), (_ref)) ); - -#define CHECK_dict_search( _type, _criteria, _what, _result ) \ - CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, (_type), (_criteria), (_what), (_result), ENOENT) ); +#endif void dump_sess_eyec(struct session *sess, const char *); -struct local_rules_definition { - char *avp_name; - enum rule_position position; - int min; - int max; -}; -#define RULE_ORDER( _position ) ((((_position) == RULE_FIXED_HEAD) || ((_position) == RULE_FIXED_TAIL)) ? 1 : 0 ) - -#define PARSE_loc_rules( _rulearray, _parent) { \ - int __ar; \ - for (__ar=0; __ar < sizeof(_rulearray) / sizeof((_rulearray)[0]); __ar++) { \ - struct dict_rule_data __data = { NULL, \ - (_rulearray)[__ar].position, \ - 0, \ - (_rulearray)[__ar].min, \ - (_rulearray)[__ar].max}; \ - __data.rule_order = RULE_ORDER(__data.rule_position); \ - CHECK_FCT( fd_dict_search( \ - fd_g_config->cnf_dict, \ - DICT_AVP, \ - AVP_BY_NAME, \ - (_rulearray)[__ar].avp_name, \ - &__data.rule_avp, 0 ) ); \ - if ( !__data.rule_avp ) { \ - TRACE_DEBUG(INFO, "AVP Not found: '%s'", (_rulearray)[__ar].avp_name ); \ - return ENOENT; \ - } \ - CHECK_FCT_DO( fd_dict_new( fd_g_config->cnf_dict, DICT_RULE, &__data, _parent, NULL), \ - { \ - TRACE_DEBUG(INFO, "Error on rule with AVP '%s'", \ - (_rulearray)[__ar].avp_name ); \ - return EINVAL; \ - } ); \ - } \ -} - -#define enumval_def_u32( _val_, _str_ ) \ - { _str_, { .u32 = _val_ }} - -#define enumval_def_os( _len_, _val_, _str_ ) \ - { _str_, { .os = { .data = (unsigned char *)_val_, .len = _len_ }}} - - - static int ccr_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act); static int reauth_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act); static int cca_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act); @@ -287,7 +242,7 @@ CHECK_FCT( fd_event_trig_regcb(SIGUSR1, "app_gx", sig_hdlr ) ); - TRACE_DEBUG(INFO, "Extension 'Dictionary definitions for DCCA (rfc4006)' initialized"); + TRACE_DEBUG(INFO, "Extension 'Gx' initialized"); return 0; } @@ -860,5 +815,5 @@ { return 0; } -EXTENSION_ENTRY( "app_gx", app_gx_entry, "dict_dcca"); +EXTENSION_ENTRY( "app_gx", app_gx_entry, "dict_dcca_3gpp"); //EXTENSION_ENTRY( "app_gx", gx_entry); diff -r c748e2439a3a -r 3eeb564e7bea extensions/CMakeLists.txt --- a/extensions/CMakeLists.txt Sat Jan 03 02:18:53 2015 +0800 +++ b/extensions/CMakeLists.txt Sat Jan 03 02:22:07 2015 +0800 @@ -67,12 +67,13 @@ #### # Routing extensions +FD_EXTENSION_SUBDIR(rt_busypeers "Handling of Diameter TOO_BUSY messages and relay timeouts" ON) FD_EXTENSION_SUBDIR(rt_default "Configurable routing rules for freeDiameter" ON) -FD_EXTENSION_SUBDIR(rt_redirect "Handling of Diameter Redirect messages" ON) -FD_EXTENSION_SUBDIR(rt_busypeers "Handling of Diameter TOO_BUSY messages and relay timeouts" ON) FD_EXTENSION_SUBDIR(rt_ereg "Configurable routing based on regexp matching of AVP values" OFF) FD_EXTENSION_SUBDIR(rt_ignore_dh "Stow Destination-Host in Proxy-Info, restore to Origin-Host for answers" ON) FD_EXTENSION_SUBDIR(rt_load_balance "Balance load over multiple equal hosts, based on outstanding requests" ON) +FD_EXTENSION_SUBDIR(rt_randomize "Randomly choose one of the highest scored hosts and increase its score by one" ON) +FD_EXTENSION_SUBDIR(rt_redirect "Handling of Diameter Redirect messages" ON) #### diff -r c748e2439a3a -r 3eeb564e7bea extensions/dict_dcca_starent/dict_dcca_starent.c --- a/extensions/dict_dcca_starent/dict_dcca_starent.c Sat Jan 03 02:18:53 2015 +0800 +++ b/extensions/dict_dcca_starent/dict_dcca_starent.c Sat Jan 03 02:22:07 2015 +0800 @@ -87,10 +87,12 @@ /* The following is created automatically. Do not modify. */ /* Changes will be lost during the next update. Modify the source org file instead. */ - /* Cisco ASR 5000 Series AAA Interface */ - /* Administration and Reference */ - /* Release 8.x and 9.0 */ - /* Last Updated June 30, 2010 */ + /* Cisco ASR 5000 Series AAA Interface */ + /* Administration and Reference */ + /* Release 8.x and 9.0 */ + /* Last Updated June 30, 2010 */ + /* updated using v15 docs from Jan 2014 */ + /* www.cisco.com/c/dam/en/us/td/docs/wireless/asr_5000/15-0/15-0-AAA-Reference.pdf */ /* SN-Volume-Quota-Threshold */ { struct dict_avp_data data = { @@ -282,9 +284,159 @@ CHECK_dict_new(DICT_AVP, &data, type, NULL); }; + /* SN-Session-Start-Indicator */ + { + struct dict_avp_data data = { + 522, /* Code */ + 8164, /* Vendor */ + "SN-Session-Start-Indicator", /* Name */ + AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new(DICT_AVP, &data, NULL, NULL); + }; + + /* SN-Phase0-PSAPName */ + { + struct dict_avp_data data = { + 523, /* Code */ + 8164, /* Vendor */ + "SN-Phase0-PSAPName", /* Name */ + AVP_FLAG_VENDOR, /* Fixed flags */ + AVP_FLAG_VENDOR, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL); + }; + + /* SN-Charging-Id */ + { + struct dict_avp_data data = { + 525, /* Code */ + 8164, /* Vendor */ + "SN-Charging-Id", /* Name */ + AVP_FLAG_VENDOR, /* Fixed flags */ + AVP_FLAG_VENDOR, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new(DICT_AVP, &data, NULL, NULL); + }; + + /* SN-Remaining-Service-Unit */ + { + struct dict_avp_data data = { + 526, /* Code */ + 8164, /* Vendor */ + "SN-Remaining-Service-Unit", /* Name */ + AVP_FLAG_VENDOR, /* Fixed flags */ + AVP_FLAG_VENDOR, /* Fixed flag values */ + AVP_TYPE_GROUPED /* base type of data */ + }; + CHECK_dict_new(DICT_AVP, &data, NULL, NULL); + }; + + /* SN-Service-Start-Timestamp */ + { + struct dict_avp_data data = { + 527, /* Code */ + 8164, /* Vendor */ + "SN-Service-Start-Timestamp", /* Name */ + AVP_FLAG_VENDOR, /* Fixed flags */ + AVP_FLAG_VENDOR, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new(DICT_AVP, &data, Time_type, NULL); + }; + + /* SN-Rulebase-Id */ + { + struct dict_avp_data data = { + 528, /* Code */ + 8164, /* Vendor */ + "SN-Rulebase-Id", /* Name */ + AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL); + }; + + /* SN-CF-Policy-ID */ + { + struct dict_avp_data data = { + 529, /* Code */ + 8164, /* Vendor */ + "SN-CF-Policy-ID", /* Name */ + AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + CHECK_dict_new(DICT_AVP, &data, NULL, NULL); + }; + + /* SN-Charging-Collection-Function-Name */ + { + struct dict_avp_data data = { + 530, /* Code */ + 8164, /* Vendor */ + "SN-Charging-Collection-Function-Name", /* Name */ + AVP_FLAG_VENDOR, /* Fixed flags */ + AVP_FLAG_VENDOR, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL); + }; + + /* SN-Fast-Reauth-Username */ + { + struct dict_avp_data data = { + 11010, /* Code */ + 8164, /* Vendor */ + "SN-Fast-Reauth-Username", /* Name */ + AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new(DICT_AVP, &data, NULL, NULL); + }; + + /* SN-Pseudonym-Username */ + { + struct dict_avp_data data = { + 11011, /* Code */ + 8164, /* Vendor */ + "SN-Pseudonym-Username", /* Name */ + AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new(DICT_AVP, &data, NULL, NULL); + }; + + /* Rules section */ + /* SN-Remaining-Service-Unit */ + { + struct dict_object *rule_avp; + struct dict_avp_request vpa; + vpa.avp_vendor = 8164; + vpa.avp_name = "SN-Remaining-Service-Unit"; + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp); + struct local_rules_definition rules[] = { + { "Tariff-Change-Usage", RULE_OPTIONAL, -1, 1 }, + { "CC-Time", RULE_OPTIONAL, -1, 1 }, + { "CC-Total-Octets", RULE_OPTIONAL, -1, 1 }, + { "CC-Input-Octets", RULE_OPTIONAL, -1, 1 }, + { "CC-Output-Octets", RULE_OPTIONAL, -1, 1 }, + { "CC-Service-Specific-Units", RULE_OPTIONAL, -1, 1 }, + { "Reporting-Reason", RULE_OPTIONAL, -1, 1 } + }; + PARSE_loc_rules( rules, rule_avp ); + } + /* SN-Total-Used-Service-Unit */ { struct dict_object *rule_avp; diff -r c748e2439a3a -r 3eeb564e7bea extensions/dict_dcca_starent/dict_dcca_starent.org --- a/extensions/dict_dcca_starent/dict_dcca_starent.org Sat Jan 03 02:18:53 2015 +0800 +++ b/extensions/dict_dcca_starent/dict_dcca_starent.org Sat Jan 03 02:22:07 2015 +0800 @@ -1,19 +1,31 @@ -| Attribute Name | Code | Section defined | Value Type | MUST | MAY | SHLD NOT | MUST NOT | Encr | -| # Cisco ASR 5000 Series AAA Interface | | | | | | | | | -| # Administration and Reference | | | | | | | | | -| # Release 8.x and 9.0 | | | | | | | | | -| # Last Updated June 30, 2010 | | | | | | | | | -| SN-Volume-Quota-Threshold | 501 | | Unsigned32 | M,V | | | | | -| SN-Unit-Quota-Threshold | 502 | | Unsigned32 | M,V | | | | | -| SN-Time-Quota-Threshold | 503 | | Unsigned32 | M,V | | | | | -| SN-Total-Used-Service-Unit | 504 | | Grouped | V | | | | | -| SN-Absolute-Validity-Time | 505 | | Time | V | | | | | -| SN-Bandwidth-Control | 512 | | Enumerated | M,V | | | | | -| SN-Transparent-Data | 513 | | OctetString | V | | | | | -| SN-Traffic-Policy | 514 | | UTF8String | V | | | | | -| SN-Firewall-Policy | 515 | | UTF8String | V | | | | | -| SN-Usage-Monitoring-Control | 517 | | Grouped | V | | | | | -| SN-Monitoring-Key | 518 | | Unsigned32 | V | | | | | -| SN-Usage-Volume | 519 | | Unsigned64 | V | | | | | -| SN-Service-Flow-Detection | 520 | | Enumerated | V | | | | | -| SN-Usage-Monitoring | 521 | | Enumerated | V | | | | | +| Attribute Name | Code | Section defined | Value Type | MUST | MAY | SHLD NOT | MUST NOT | Encr | +| # Cisco ASR 5000 Series AAA Interface | | | | | | | | | +| # Administration and Reference | | | | | | | | | +| # Release 8.x and 9.0 | | | | | | | | | +| # Last Updated June 30, 2010 | | | | | | | | | +| # updated using v15 docs from Jan 2014 | | | | | | | | | +| # www.cisco.com/c/dam/en/us/td/docs/wireless/asr_5000/15-0/15-0-AAA-Reference.pdf | | | | | | | | | +| SN-Volume-Quota-Threshold | 501 | | Unsigned32 | M,V | | | | | +| SN-Unit-Quota-Threshold | 502 | | Unsigned32 | M,V | | | | | +| SN-Time-Quota-Threshold | 503 | | Unsigned32 | M,V | | | | | +| SN-Total-Used-Service-Unit | 504 | | Grouped | V | | | | | +| SN-Absolute-Validity-Time | 505 | | Time | V | | | | | +| SN-Bandwidth-Control | 512 | | Enumerated | M,V | | | | | +| SN-Transparent-Data | 513 | | OctetString | V | | | | | +| SN-Traffic-Policy | 514 | | UTF8String | V | | | | | +| SN-Firewall-Policy | 515 | | UTF8String | V | | | | | +| SN-Usage-Monitoring-Control | 517 | | Grouped | V | | | | | +| SN-Monitoring-Key | 518 | | Unsigned32 | V | | | | | +| SN-Usage-Volume | 519 | | Unsigned64 | V | | | | | +| SN-Service-Flow-Detection | 520 | | Enumerated | V | | | | | +| SN-Usage-Monitoring | 521 | | Enumerated | V | | | | | +| SN-Session-Start-Indicator | 522 | | OctetString | M,V | | | | | +| SN-Phase0-PSAPName | 523 | | UTF8String | V | | | | | +| SN-Charging-Id | 525 | | OctetString | V | | | | | +| SN-Remaining-Service-Unit | 526 | | Grouped | V | | | | | +| SN-Service-Start-Timestamp | 527 | | Time | V | | | | | +| SN-Rulebase-Id | 528 | | UTF8String | M,V | | | | | +| SN-CF-Policy-ID | 529 | | Unsigned32 | M,V | | | | | +| SN-Charging-Collection-Function-Name | 530 | | UTF8String | V | | | | | +| SN-Fast-Reauth-Username | 11010 | | OctetString | M,V | | | | | +| SN-Pseudonym-Username | 11011 | | OctetString | M,V | | | | | diff -r c748e2439a3a -r 3eeb564e7bea extensions/rt_busypeers/rtbusy.c --- a/extensions/rt_busypeers/rtbusy.c Sat Jan 03 02:18:53 2015 +0800 +++ b/extensions/rt_busypeers/rtbusy.c Sat Jan 03 02:22:07 2015 +0800 @@ -49,7 +49,7 @@ struct msg * qry = NULL; struct rt_data * rtd = NULL; struct fd_list * candidates = NULL; - int sendingattemtps; + int sendingattempts; int resend = 1; @@ -72,13 +72,13 @@ (uint8_t *)(oh ? (DiamId_t)oh->os.data : fd_g_config->cnf_diamid), oh ? oh->os.len : fd_g_config->cnf_diamid_len , ER_DIAMETER_TOO_BUSY, &candidates, - &sendingattemtps) ); + &sendingattempts) ); /* Now we need to decide if we re-send this query to a different peer or return an error to upstream */ /* First, are we exceeding the allowed attempts? */ if (rtbusy_conf.RetryMaxPeers != 0) { - if (sendingattemtps >= rtbusy_conf.RetryMaxPeers) { + if (sendingattempts >= rtbusy_conf.RetryMaxPeers) { TRACE_DEBUG(FULL, "Maximum number of sending attempts reached for message %p, returning an error upstream", qry); resend = 0; } @@ -106,10 +106,16 @@ } /* Send the query again. We need to re-associate the expirecb which was cleaned, if it is used */ if (rtbusy_conf.RelayTimeout) { + char *buf = NULL; + size_t len; struct timespec expire; CHECK_SYS( clock_gettime(CLOCK_REALTIME, &expire) ); expire.tv_sec += rtbusy_conf.RelayTimeout/1000 + ((expire.tv_nsec + (1000000LL * (rtbusy_conf.RelayTimeout % 1000))) / 1000000000LL); expire.tv_nsec = (expire.tv_nsec + (1000000LL * (rtbusy_conf.RelayTimeout % 1000))) % 1000000000LL; + CHECK_MALLOC_DO( fd_msg_dump_full(&buf, &len, NULL, *pmsg, fd_g_config->cnf_dict, 0, 1), /* nothing */); + TRACE_ERROR( "No answer received for message from peer '%.*s' before timeout (%dms), re-sending: %s", senttolen, sentto, + rtbusy_conf.RelayTimeout, buf); + free(buf); CHECK_FCT( fd_msg_send_timeout( pmsg, NULL, NULL, rtbusy_expirecb, &expire ) ); } else { CHECK_FCT( fd_msg_send(pmsg, NULL, NULL) ); @@ -117,6 +123,13 @@ } else { if (is_req) { + char *buf = NULL; + size_t len; + + CHECK_MALLOC_DO( fd_msg_dump_full(&buf, &len, NULL, *pmsg, fd_g_config->cnf_dict, 0, 1), /* nothing */); + TRACE_ERROR( "No answer received for message from peer '%.*s' before timeout (%dms), giving up and sending error reply: %s", senttolen, sentto, + rtbusy_conf.RelayTimeout, buf); + free(buf); /* We must create an answer */ CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, pmsg, MSGFL_ANSW_ERROR ) ); diff -r c748e2439a3a -r 3eeb564e7bea extensions/rt_ignore_dh/rt_ignore_dh.c --- a/extensions/rt_ignore_dh/rt_ignore_dh.c Sat Jan 03 02:18:53 2015 +0800 +++ b/extensions/rt_ignore_dh/rt_ignore_dh.c Sat Jan 03 02:22:07 2015 +0800 @@ -42,15 +42,6 @@ struct dict_object * pi_avp_do; /* cache the Proxy-Info dictionary object */ struct dict_object * ps_avp_do; /* cache the Proxy-State dictionary object */ -static void *memdup(void *data, size_t len) -{ - void *mem; - if ((mem=malloc(len)) == NULL) - return NULL; - memcpy(mem, data, len); - return mem; -} - static int restore_origin_host(struct msg **msg) { struct avp *avp, *child; struct avp *oh_avp = NULL; @@ -91,12 +82,8 @@ } break; case AC_PROXY_STATE: + ps = chdr->avp_value->os.data; ps_len = chdr->avp_value->os.len; - ps = memdup(chdr->avp_value->os.data, ps_len); - if (!ps) { - TRACE_ERROR("malloc failure"); - return 0; - } break; default: break; @@ -108,8 +95,7 @@ new_oh = ps; new_oh_len = ps_len; pi_avp = avp; - } else - free(ps); + } break; default: break; @@ -151,13 +137,13 @@ /* add Proxy-Info->{Proxy-Host, Proxy-State} using Destination-Host information */ CHECK_FCT(fd_msg_avp_new(ph_avp_do, 0, &ph_avp)); memset(&val, 0, sizeof(val)); - val.os.data = memdup(fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len); + val.os.data = fd_g_config->cnf_diamid; val.os.len = fd_g_config->cnf_diamid_len; CHECK_FCT(fd_msg_avp_setvalue(ph_avp, &val)); CHECK_FCT(fd_msg_avp_new(ps_avp_do, 0, &ps_avp)); memset(&val, 0, sizeof(val)); - val.os.data = memdup(ahdr->avp_value->os.data, ahdr->avp_value->os.len); + val.os.data = ahdr->avp_value->os.data; val.os.len = ahdr->avp_value->os.len; CHECK_FCT(fd_msg_avp_setvalue(ps_avp, &val)); diff -r c748e2439a3a -r 3eeb564e7bea extensions/rt_load_balance/CMakeLists.txt --- a/extensions/rt_load_balance/CMakeLists.txt Sat Jan 03 02:18:53 2015 +0800 +++ b/extensions/rt_load_balance/CMakeLists.txt Sat Jan 03 02:22:07 2015 +0800 @@ -2,14 +2,14 @@ PROJECT("Routing extension splits requests evenly over multiple hosts, using current load as routing indicator" C) # List of source files -SET(RT_IGNORE_DH_SRC +SET(RT_LOAD_BALANCE_SRC rt_load_balance.c ) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) # Compile these files as a freeDiameter extension -FD_ADD_EXTENSION(rt_load_balance ${RT_IGNORE_DH_SRC}) +FD_ADD_EXTENSION(rt_load_balance ${RT_LOAD_BALANCE_SRC}) #### ## INSTALL section ## diff -r c748e2439a3a -r 3eeb564e7bea extensions/rt_load_balance/rt_load_balance.c --- a/extensions/rt_load_balance/rt_load_balance.c Sat Jan 03 02:18:53 2015 +0800 +++ b/extensions/rt_load_balance/rt_load_balance.c Sat Jan 03 02:22:07 2015 +0800 @@ -2,7 +2,7 @@ * Software License Agreement (BSD License) * * Author: Thomas Klausner * * * -* Copyright (c) 2013, Thomas Klausner * +* Copyright (c) 2013, 2014 Thomas Klausner * * All rights reserved. * * * * Written under contract by nfotex IT GmbH, http://nfotex.com/ * @@ -58,12 +58,18 @@ CHECK_FCT(fd_peer_getbyid(cand->diamid, cand->diamidlen, 0, &peer)); CHECK_FCT(fd_peer_get_load_pending(peer, &to_receive, &to_send)); load = to_receive + to_send; - score = cand->score; - if ((cand->score > 0) && (load >= cand->score)) - cand->score = 1; - else - cand->score -= load; - TRACE_DEBUG(INFO, "evaluated peer `%.*s', score was %d, now %d", (int)cand->diamidlen, cand->diamid, score, cand->score); + /* other routing mechanisms need to add to the + * appropriate entries so their base value is high + * enough that they are considered */ + + /* logarithmic scaling */ + int load_log = 0; + while (load > 0) { + load_log++; + load /= 2; + } + cand->score -= load_log; + TRACE_DEBUG(FULL, "evaluated peer `%.*s', score was %d, now %d", (int)cand->diamidlen, cand->diamid, score, cand->score); } return 0; diff -r c748e2439a3a -r 3eeb564e7bea extensions/rt_randomize/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extensions/rt_randomize/CMakeLists.txt Sat Jan 03 02:22:07 2015 +0800 @@ -0,0 +1,20 @@ +# The rt_randomize extension +PROJECT("Routing extension randomly increases the routing count for one of the highest-rated hosts, if there are multiple ones" C) + +# List of source files +SET(RT_RANDOMIZE_SRC + rt_randomize.c +) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) + +# Compile these files as a freeDiameter extension +FD_ADD_EXTENSION(rt_randomize ${RT_RANDOMIZE_SRC}) + +#### +## INSTALL section ## + +# We install with the daemon component because it is a base feature. +INSTALL(TARGETS rt_randomize + LIBRARY DESTINATION ${INSTALL_EXTENSIONS_SUFFIX} + COMPONENT freeDiameter-daemon) diff -r c748e2439a3a -r 3eeb564e7bea extensions/rt_randomize/rt_randomize.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extensions/rt_randomize/rt_randomize.c Sat Jan 03 02:22:07 2015 +0800 @@ -0,0 +1,111 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Thomas Klausner * +* * +* Copyright (c) 2014 Thomas Klausner * +* All rights reserved. * +* * +* Written under contract by nfotex IT GmbH, http://nfotex.com/ * +* * +* 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. * +* * +* 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. * +*********************************************************************************************************/ + +#include + +/* + * Load balancing extension. If there are multiple highest-rated hosts with the same score, + * randomly increase the score of one of them. + */ + +#include + +static int seed; + +static int rt_randomizing(void * cbdata, struct msg ** pmsg, struct fd_list * candidates) +{ + struct fd_list *lic; + struct msg * msg = *pmsg; + int max_score = -1; + int max_score_count = 0; + + 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; + + /* find out maximal score and how many candidates have it */ + for (lic = candidates->next; lic != candidates; lic = lic->next) { + struct rtd_candidate * cand = (struct rtd_candidate *) lic; + if (max_score < cand->score) { + max_score = cand->score; + max_score_count = 1; + } + else if (cand->score == max_score) { + max_score_count++; + } + } + + /* if there is more than one with positive score, randomly increase one of their scores by one */ + if (max_score >= 0 && max_score_count > 1) { + int lucky_candidate = rand_r(&seed) % max_score_count; + int i = 0; + + for (lic = candidates->next; lic != candidates; lic = lic->next) { + struct rtd_candidate * cand = (struct rtd_candidate *) lic; + if (cand->score == max_score) { + if (i == lucky_candidate) { + cand->score++; + break; + } + i++; + } + } + } + + return 0; +} + +/* handler */ +static struct fd_rt_out_hdl * rt_randomizing_hdl = NULL; + +/* entry point */ +static int rt_randomize_entry(char * conffile) +{ + /* Register the callback */ + CHECK_FCT(fd_rt_out_register(rt_randomizing, NULL, 4, &rt_randomizing_hdl)); + seed = (int)time(NULL); + TRACE_DEBUG(INFO, "Extension 'Randomizing' initialized"); + return 0; +} + +/* Unload */ +void fd_ext_fini(void) +{ + /* Unregister the callbacks */ + CHECK_FCT_DO(fd_rt_out_unregister(rt_randomizing_hdl, NULL), /* continue */); + return ; +} + +EXTENSION_ENTRY("rt_randomize", rt_randomize_entry); diff -r c748e2439a3a -r 3eeb564e7bea libfdcore/routing_dispatch.c --- a/libfdcore/routing_dispatch.c Sat Jan 03 02:18:53 2015 +0800 +++ b/libfdcore/routing_dispatch.c Sat Jan 03 02:22:07 2015 +0800 @@ -878,7 +878,7 @@ /* Find the peer corresponding to this name */ CHECK_FCT( fd_peer_getbyid( qry_src, qry_src_len, 0, (void *) &peer ) ); - if (fd_peer_getstate(peer) != STATE_OPEN) { + if (fd_peer_getstate(peer) != STATE_OPEN && fd_peer_getstate(peer) != STATE_CLOSING_GRACE) { char buf[128]; snprintf(buf, sizeof(buf), "Unable to forward answer to deleted / closed peer '%s'.", qry_src); fd_hook_call(HOOK_MESSAGE_ROUTING_ERROR, msgptr, NULL, buf, fd_msg_pmdl_get(msgptr));