Przeglądaj źródła

modules_k/dispatcher: Added new feature that enables routes to be run when destinations fail/recover

- Two new exported parameters ds_dst_unavailable_route and
  ds_dst_available_route allow you to specify routes to run when
  a destination is marked PROBING and unmarked PROBING respectively.

  This is useful for integration with NMC and alarms equipment as
  these routes can be used to trigger/log these status changes.
pd 14 lat temu
rodzic
commit
0856382995

+ 82 - 32
modules_k/dispatcher/README

@@ -62,6 +62,8 @@ Carsten Bock
               3.25. ds_hash_expire (int)
               3.26. ds_hash_initexpire (int)
               3.27. ds_hash_check_interval (int)
+              3.28. ds_dst_unavailable_route (string)
+              3.29. ds_dst_available_route (string)
 
         4. Exported Functions
 
@@ -125,10 +127,12 @@ Carsten Bock
    1.26. Set the “ds_hash_expire” parameter
    1.27. Set the “ds_hash_initexpire” parameter
    1.28. Set the “ds_hash_check_interval” parameter
-   1.29. ds_select_dst usage
-   1.30. ds_load_unset usage
-   1.31. dispatcher list file
-   1.32. Kamailio config script - sample dispatcher usage
+   1.29. Set the “ds_dst_unavailable_route” parameter
+   1.30. Set the “ds_dst_available_route” parameter
+   1.31. ds_select_dst usage
+   1.32. ds_load_unset usage
+   1.33. dispatcher list file
+   1.34. Kamailio config script - sample dispatcher usage
 
 Chapter 1. Admin Guide
 
@@ -169,6 +173,8 @@ Chapter 1. Admin Guide
         3.25. ds_hash_expire (int)
         3.26. ds_hash_initexpire (int)
         3.27. ds_hash_check_interval (int)
+        3.28. ds_dst_unavailable_route (string)
+        3.29. ds_dst_available_route (string)
 
    4. Exported Functions
 
@@ -263,6 +269,8 @@ Chapter 1. Admin Guide
    3.25. ds_hash_expire (int)
    3.26. ds_hash_initexpire (int)
    3.27. ds_hash_check_interval (int)
+   3.28. ds_dst_unavailable_route (string)
+   3.29. ds_dst_available_route (string)
 
 3.1. list_file (string)
 
@@ -646,6 +654,48 @@ Note
  modparam("dispatcher", "ds_hash_check_interval", 60)
  ...
 
+3.28. ds_dst_unavailable_route (string)
+
+   Optional parameter that specifies a route to run when a destination is
+   marked as PROBING. Destinations are marked PROBING after threshhold
+   number of OPTIONS ping failures or calls to ds_mark_dst("p").
+
+   This setting can be used to log desination failures. It may be used (in
+   conjunction with other modules like exec) to run external commands to
+   update NMC equipment, generate SNMP traps, and so on.
+
+   Default value is “null”.
+
+   Example 1.29. Set the “ds_dst_unavailable_route” parameter
+ ...
+ modparam("dispatcher", "ds_dst_unavailable_route", "DST_FAILED")
+ ...
+ route[DST_FAILED] {
+     xlog("L_ERR", "Destination failed: $rm $ru ($du)\n");
+ }
+ ...
+
+3.29. ds_dst_available_route (string)
+
+   Optional parameter that specifies a route to run when a destination
+   leaves the PROBING state. Destinations leave the PROBING state after an
+   OPTIONS ping succeeds.
+
+   This setting can be used to log desination recoveries. It may be used
+   (in conjunction with other modules like exec) to run external commands
+   to update NMC equipment, generate SNMP traps, and so on.
+
+   Default value is “null”.
+
+   Example 1.30. Set the “ds_dst_available_route” parameter
+ ...
+ modparam("dispatcher", "ds_dst_available_route", "DST_RESTORED")
+ ...
+ route[DST_RESTORED] {
+     xlog("L_ERR", "Destination restored: $rm $ru ($du)\n");
+ }
+ ...
+
 4. Exported Functions
 
    4.1. ds_select_dst(set, alg)
@@ -708,7 +758,7 @@ Note
 
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
 
-   Example 1.29. ds_select_dst usage
+   Example 1.31. ds_select_dst usage
 ...
 ds_select_dst("1", "0");
 ...
@@ -805,7 +855,7 @@ ds_select_dst("1", "$var(a)");
    This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
    BRANCH_ROUTE and ONREPLY_ROUTE.
 
-   Example 1.30. ds_load_unset usage
+   Example 1.32. ds_load_unset usage
 ...
 route {
     ...
@@ -969,7 +1019,7 @@ setid(int) destination(sip uri) flags(int,opt) priority(int,opt) attrs(str,opt)
    For database, each element of a line resides in a different column.
    Next is a dispatcher.list file example:
 
-   Example 1.31. dispatcher list file
+   Example 1.33. dispatcher list file
 ...
 # $Id$
 # dispatcher destination sets
@@ -994,7 +1044,7 @@ r,opt)
 
    Next picture displays a sample usage of dispatcher.
 
-   Example 1.32. Kamailio config script - sample dispatcher usage
+   Example 1.34. Kamailio config script - sample dispatcher usage
 ...
 # $Id$
 # sample config file for dispatcher module
@@ -1080,46 +1130,46 @@ Chapter 2. Frequently Asked Questions
 
    2.1.
 
-       Does dispatcher provide a fair distribution?
+   Does dispatcher provide a fair distribution?
 
-       There is no guarantee of that. You should do some measurements to
-       decide what distribution algorithm fits better in your environment.
+   There is no guarantee of that. You should do some measurements to
+   decide what distribution algorithm fits better in your environment.
 
    2.2.
 
-       Is dispatcher dialog stateful?
+   Is dispatcher dialog stateful?
 
-       No. Dispatcher is stateless, although some distribution algorithms are
-       designed to select same destination for subsequent requests of the same
-       dialog (e.g., hashing the call-id).
+   No. Dispatcher is stateless, although some distribution algorithms are
+   designed to select same destination for subsequent requests of the same
+   dialog (e.g., hashing the call-id).
 
    2.3.
 
-       Where can I find more about Kamailio?
+   Where can I find more about Kamailio?
 
-       Take a look at http://www.kamailio.org/.
+   Take a look at http://www.kamailio.org/.
 
    2.4.
 
-       Where can I post a question about this module?
+   Where can I post a question about this module?
 
-       First at all check if your question was already answered on one of our
-       mailing lists:
-         * User Mailing List -
-           http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-users
-         * Developer Mailing List -
-           http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
+   First at all check if your question was already answered on one of our
+   mailing lists:
+     * User Mailing List -
+       http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-users
+     * Developer Mailing List -
+       http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
 
-       E-mails regarding any stable version should be sent to
-       <[email protected]> and e-mail regarding development
-       versions or CVS snapshots should be send to
-       <[email protected]>.
+   E-mails regarding any stable version should be sent to
+   <[email protected]> and e-mail regarding development
+   versions or CVS snapshots should be send to
+   <[email protected]>.
 
-       If you want to keep the mail private, send it to
-       <[email protected]>.
+   If you want to keep the mail private, send it to
+   <[email protected]>.
 
    2.5.
 
-       How can I report a bug?
+   How can I report a bug?
 
-       Please follow the guidelines provided at: http://sip-router.org/tracker
+   Please follow the guidelines provided at: http://sip-router.org/tracker

+ 56 - 8
modules_k/dispatcher/dispatch.c

@@ -69,6 +69,7 @@
 #include "../../lib/srdb1/db.h"
 #include "../../lib/srdb1/db_res.h"
 #include "../../str.h"
+#include "../../script_cb.h"
 
 #include "ds_ht.h"
 #include "api.h"
@@ -98,9 +99,13 @@ int *ds_list_nr = NULL;
 int *crt_idx    = NULL;
 int *next_idx   = NULL;
 
+int ds_tmp_msg_no = 1;
+
 #define _ds_list 	(ds_lists[*crt_idx])
 #define _ds_list_nr (*ds_list_nr)
 
+static void ds_run_route(struct sip_msg *msg, int route);
+
 void destroy_list(int);
 
 /**
@@ -1964,15 +1969,15 @@ int ds_mark_dst(struct sip_msg *msg, int mode)
 	
 	if(mode==1) {
 		ret = ds_set_state(group, &avp_value.s,
-				DS_INACTIVE_DST|DS_PROBING_DST|DS_RESET_FAIL_DST, 0);
+				DS_INACTIVE_DST|DS_PROBING_DST|DS_RESET_FAIL_DST, 0, msg);
 	} else if(mode==2) {
-		ret = ds_set_state(group, &avp_value.s, DS_PROBING_DST, 1);
+		ret = ds_set_state(group, &avp_value.s, DS_PROBING_DST, 1, msg);
 		if (ret == 0) ret = ds_set_state(group, &avp_value.s,
-				DS_INACTIVE_DST, 0);
+				DS_INACTIVE_DST, 0, msg);
 	} else {
-		ret = ds_set_state(group, &avp_value.s, DS_INACTIVE_DST, 1);
+		ret = ds_set_state(group, &avp_value.s, DS_INACTIVE_DST, 1, msg);
 		if (ret == 0) ret = ds_set_state(group, &avp_value.s,
-				DS_PROBING_DST, 0);
+				DS_PROBING_DST, 0, msg);
 	}
 	
 	LM_DBG("mode [%d] grp [%d] dst [%.*s]\n", mode, group, avp_value.s.len,
@@ -1984,7 +1989,7 @@ int ds_mark_dst(struct sip_msg *msg, int mode)
 /**
  *
  */
-int ds_set_state(int group, str *address, int state, int type)
+int ds_set_state(int group, str *address, int state, int type, struct sip_msg *msg)
 {
 	int i=0;
 	ds_set_t *idx = NULL;
@@ -2044,9 +2049,20 @@ int ds_set_state(int group, str *address, int state, int type)
 			}
 			
 			if(type)
+			{
+				if (state & DS_PROBING_DST && !(idx->dlist[i].flags & state))
+					ds_run_route(msg, ds_dst_unav_route);
+
 				idx->dlist[i].flags |= state;
+			}
 			else
+			{
+				if (state & DS_PROBING_DST && idx->dlist[i].flags & state)
+					ds_run_route(msg, ds_dst_av_route);
+
 				idx->dlist[i].flags &= ~state;
+
+			}
 				
 			return 0;
 		}
@@ -2056,6 +2072,32 @@ int ds_set_state(int group, str *address, int state, int type)
 	return -1;
 }
 
+static void ds_run_route(struct sip_msg *msg, int route)
+{
+	int backup_route_type = get_route_type();
+
+	LM_DBG("ds_run_route\n");
+
+	if (route == -1)
+		return;
+
+	if (exec_pre_script_cb(msg, LOCAL_CB_TYPE) == 0)
+	{
+		LM_ERR("exec_pre_script_cb failed\n");
+		goto error;
+	}
+	set_route_type(LOCAL_ROUTE);
+	if (run_top_route(main_rt.rlist[route], msg, 0) < 0)
+	{
+		LM_ERR("run_top_route failed\n");
+		goto error;
+	}
+	exec_post_script_cb(msg, LOCAL_CB_TYPE);
+
+error:
+	set_route_type(backup_route_type);
+}
+
 /**
  *
  */
@@ -2282,10 +2324,13 @@ static void ds_options_callback( struct cell *t, int type,
 	 * We accept both a "200 OK" or the configured reply as a valid response */
 	if ((ps->code == 200) || ds_ping_check_rplcode(ps->code))
 	{
+		ds_tmp_msg.new_uri = uri;
+		ds_tmp_msg.id = ds_tmp_msg_no++;
+	
 		/* Set the according entry back to "Active":
 		 *  remove the Probing/Inactive Flag and reset the failure counter. */
 		if (ds_set_state(group, &uri,
-					DS_INACTIVE_DST|DS_PROBING_DST|DS_RESET_FAIL_DST, 2) != 0)
+					DS_INACTIVE_DST|DS_PROBING_DST|DS_RESET_FAIL_DST, 2, &ds_tmp_msg) != 0)
 		{
 			LM_ERR("Setting the state failed (%.*s, group %d)\n", uri.len,
 					uri.s, group);
@@ -2293,7 +2338,10 @@ static void ds_options_callback( struct cell *t, int type,
 	}
 	if(ds_probing_mode==1 && ps->code == 408)
 	{
-		if (ds_set_state(group, &uri, DS_PROBING_DST, 1) != 0)
+
+		ds_tmp_msg.new_uri = uri;
+		ds_tmp_msg.id = ds_tmp_msg_no++;
+		if (ds_set_state(group, &uri, DS_PROBING_DST, 1, &ds_tmp_msg) != 0)
 		{
 			LM_ERR("Setting the probing state failed (%.*s, group %d)\n",
 					uri.len, uri.s, group);

+ 4 - 1
modules_k/dispatcher/dispatch.h

@@ -88,6 +88,9 @@ extern str ds_ping_from;
 extern int probing_threshhold; /*!< number of failed requests,
 						before a destination is taken into probing */ 
 extern int ds_probing_mode;
+extern struct sip_msg ds_tmp_msg;
+extern int ds_dst_unav_route;
+extern int ds_dst_av_route;
 
 int init_data(void);
 int init_ds_db(void);
@@ -98,7 +101,7 @@ int ds_load_db(void);
 int ds_destroy_list(void);
 int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode);
 int ds_next_dst(struct sip_msg *msg, int mode);
-int ds_set_state(int group, str *address, int state, int type);
+int ds_set_state(int group, str *address, int state, int type, struct sip_msg *msg);
 int ds_reinit_state(int group, str *address, int state);
 int ds_mark_dst(struct sip_msg *msg, int mode);
 int ds_print_list(FILE *fout);

+ 94 - 0
modules_k/dispatcher/dispatcher.c

@@ -119,6 +119,15 @@ int ds_hash_size = 0;
 int ds_hash_expire = 7200;
 int ds_hash_initexpire = 7200;
 int ds_hash_check_interval = 30;
+char *ds_dst_unavailable_route = NULL;
+int ds_dst_unav_route = -1;
+char *ds_dst_available_route = NULL;
+int ds_dst_av_route = -1;
+
+#define DS_TMP_MSG "OPTIONS sip:[email protected] SIP/2.0\r\nVia: SIP/2.0/UDP 127.0.0.1\r\nFrom: <[email protected]>;tag=123\r\nTo: <[email protected]>\r\nCall-ID: 123\r\nCSeq: 1 OPTIONS\r\nContent-Length: 0\r\n\r\n"
+#define DS_TMP_MSG_LEN (sizeof(DS_TMP_MSG)-1)
+struct sip_msg ds_tmp_msg;
+char ds_tmp_msg_buf[DS_TMP_MSG_LEN + 1];
 
 /* tm */
 struct tm_binds tmb;
@@ -219,6 +228,8 @@ static param_export_t params[]={
 	{"ds_hash_expire",     INT_PARAM, &ds_hash_expire},
 	{"ds_hash_initexpire", INT_PARAM, &ds_hash_initexpire},
 	{"ds_hash_check_interval", INT_PARAM, &ds_hash_check_interval},
+	{"ds_dst_unavailable_route", STR_PARAM, &ds_dst_unavailable_route},
+	{"ds_dst_available_route", STR_PARAM, &ds_dst_available_route},
 	{0,0,0}
 };
 
@@ -470,6 +481,8 @@ static int mod_init(void)
 	/* Only, if the Probing-Timer is enabled the TM-API needs to be loaded: */
 	if (ds_ping_interval > 0)
 	{
+		int c;
+
 		/*****************************************************
 		 * TM-Bindings
 	  	 *****************************************************/
@@ -482,6 +495,87 @@ static int mod_init(void)
 		 * Register the PING-Timer
 		 *****************************************************/
 		register_timer(ds_check_timer, NULL, ds_ping_interval);
+
+		/* Build a temporary message for later use */
+		memcpy(ds_tmp_msg_buf, DS_TMP_MSG, DS_TMP_MSG_LEN);
+		ds_tmp_msg_buf[DS_TMP_MSG_LEN] = '\0';
+		memset(&ds_tmp_msg, 0, sizeof(struct sip_msg));
+		ds_tmp_msg.buf = ds_tmp_msg_buf;
+		ds_tmp_msg.len = DS_TMP_MSG_LEN;
+		ds_tmp_msg.set_global_address = default_global_address;
+		ds_tmp_msg.set_global_port = default_global_port;
+		if (parse_msg(ds_tmp_msg.buf, ds_tmp_msg.len, &ds_tmp_msg) != 0)
+		{
+			LM_ERR("parse_msg failed\n");
+			return -1;
+		}
+		ds_tmp_msg.parsed_orig_ruri = ds_tmp_msg.parsed_uri;
+		ds_tmp_msg.parsed_orig_ruri_ok = 0;
+
+		if (ds_dst_unavailable_route != NULL)
+		{
+			int length = strlen(ds_dst_unavailable_route);
+			c = ds_dst_unavailable_route[length];
+			ds_dst_unavailable_route[length] = '\0';
+			ds_dst_unav_route = route_get(&main_rt, ds_dst_unavailable_route);
+			ds_dst_unavailable_route[length] = c;
+
+			if (ds_dst_unav_route == -1)
+			{
+				LM_ERR("failed to determine destination unavailable route\n");
+				return -1;
+			}
+
+			if (main_rt.rlist[ds_dst_unav_route] == 0)
+			{
+				LM_WARN("route[%s] is empty\n", ds_dst_unavailable_route);
+				ds_dst_unav_route = -1;
+			}
+			else
+			{
+				LM_INFO("destination unavailable route: route[%s] (%d)\n",
+					ds_dst_unavailable_route, ds_dst_unav_route);
+			}
+
+		}
+		else
+		{
+			LM_INFO("No destination unavailable route configured\n");
+			ds_dst_unav_route = -1;
+		}
+
+		if (ds_dst_available_route != NULL)
+		{
+			int length = strlen(ds_dst_available_route);
+			c = ds_dst_available_route[length];
+			ds_dst_available_route[length] = '\0';
+			ds_dst_av_route = route_get(&main_rt, ds_dst_available_route);
+			ds_dst_available_route[length] = c;
+
+			if (ds_dst_av_route == -1)
+			{
+				LM_ERR("failed to determine destination available route\n");
+				return -1;
+			}
+
+			if (main_rt.rlist[ds_dst_av_route] == 0)
+			{
+				LM_WARN("route[%s] is empty\n", ds_dst_available_route);
+				ds_dst_av_route = -1;
+			}
+			else
+			{
+				LM_INFO("destination available route: route[%s] (%d)\n",
+					ds_dst_available_route, ds_dst_av_route);
+			}
+
+		}
+		else
+		{
+			LM_INFO("No destination available route configured\n");
+			ds_dst_av_route = -1;
+		}
+
 	}
 
 	return 0;

+ 63 - 1
modules_k/dispatcher/doc/dispatcher_admin.xml

@@ -688,7 +688,69 @@ modparam("dispatcher", "force_dst", 1)
  </programlisting>
  		</example>
 	</section>
-
+ 	<section>
+ 		<title><varname>ds_dst_unavailable_route</varname> (string)</title>
+ 		<para>
+		Optional parameter that specifies a route to run when a destination
+		is marked as PROBING.  Destinations are marked PROBING after threshhold
+                number of OPTIONS ping failures or calls to
+		<emphasis>ds_mark_dst("p")</emphasis>.
+ 		</para>
+		<para>
+		This setting can be used to log desination failures.  It may be used
+		(in conjunction with other modules like <emphasis>exec</emphasis>) to
+		run external commands to update NMC equipment, generate SNMP traps,
+		and so on.
+		</para>
+ 		<para>
+ 		<emphasis>
+ 			Default value is <quote>null</quote>.
+ 		</emphasis>
+ 		</para>
+ 		<example>
+ 		<title>Set the <quote>ds_dst_unavailable_route</quote> parameter</title>
+ <programlisting format="linespecific">
+ ...
+ modparam("dispatcher", "ds_dst_unavailable_route", "DST_FAILED")
+ ...
+ route[DST_FAILED] {
+     xlog("L_ERR", "Destination failed: $rm $ru ($du)\n");
+ }
+ ...
+ </programlisting>
+ 		</example>
+	</section>
+ 	<section>
+ 		<title><varname>ds_dst_available_route</varname> (string)</title>
+ 		<para>
+		Optional parameter that specifies a route to run when a destination
+		leaves the PROBING state.  Destinations leave the PROBING state after
+                an OPTIONS ping succeeds.
+ 		</para>
+		<para>
+		This setting can be used to log desination recoveries.  It may be used
+		(in conjunction with other modules like <emphasis>exec</emphasis>) to
+		run external commands to update NMC equipment, generate SNMP traps,
+		and so on.
+		</para>
+ 		<para>
+ 		<emphasis>
+ 			Default value is <quote>null</quote>.
+ 		</emphasis>
+ 		</para>
+ 		<example>
+ 		<title>Set the <quote>ds_dst_available_route</quote> parameter</title>
+ <programlisting format="linespecific">
+ ...
+ modparam("dispatcher", "ds_dst_available_route", "DST_RESTORED")
+ ...
+ route[DST_RESTORED] {
+     xlog("L_ERR", "Destination restored: $rm $ru ($du)\n");
+ }
+ ...
+ </programlisting>
+ 		</example>
+	</section>
 	</section>
 
 	<section>