[PATCH] mgcp: Send RTP keepalive dummy packets to net

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/OpenBSC@lists.osmocom.org/.

Jacob Erlbeck jerlbeck at sysmocom.de
Wed Jan 15 13:00:16 UTC 2014


So far, a single dummy packet has been sent immediately after the
reception of a MDCX message. There is no dedicated keep alive
mechanism (it just worked because the audio from the MS has always
been forwarded to the NAT until the 'mgcp: Set output_enabled flags
based on the MGCP mode' patch).

This patch adds explicit, timer based keep alive handling that can be
enable per trunk. A VTY command 'rtp keep-alive' command is added for
configuration which can be used to set the interval in seconds, to
send a single packet after the reception of a CRCX/MDCX when RTP data
from the net is expected ('once'), or to disable the feature
completely ('no rtp keep-alive'). In 'send-recv' connections, only
the initial packet is sent if enabled (even when an interval has been
configured). The default is 'once'.

Note that this removes the mgcp_change_cb() from mgcp_main.c.

Sponsored-by: On-Waves ehf
---
 openbsc/include/openbsc/mgcp.h        |    9 ++++
 openbsc/src/libmgcp/mgcp_protocol.c   |   43 ++++++++++++++++
 openbsc/src/libmgcp/mgcp_vty.c        |   91 +++++++++++++++++++++++++++++++++
 openbsc/src/osmo-bsc_mgcp/mgcp_main.c |   10 ----
 openbsc/tests/mgcp/mgcp_test.ok       |    6 +++
 5 files changed, 149 insertions(+), 10 deletions(-)

diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h
index 335c83d..1d74078 100644
--- a/openbsc/include/openbsc/mgcp.h
+++ b/openbsc/include/openbsc/mgcp.h
@@ -25,6 +25,7 @@
 
 #include <osmocom/core/msgb.h>
 #include <osmocom/core/write_queue.h>
+#include <osmocom/core/timer.h>
 
 #include "debug.h"
 
@@ -103,6 +104,8 @@ struct mgcp_port_range {
 	int last_port;
 };
 
+#define MGCP_KEEPALIVE_ONCE (-1)
+
 struct mgcp_trunk_config {
 	struct llist_head entry;
 
@@ -118,6 +121,7 @@ struct mgcp_trunk_config {
 	int audio_loop;
 
 	int omit_rtcp;
+	int keepalive_interval;
 
 	/* RTP patching */
 	int force_constant_ssrc; /* 0: don't, 1: once */
@@ -126,6 +130,9 @@ struct mgcp_trunk_config {
 	/* spec handling */
 	int force_realloc;
 
+	/* timer */
+	struct osmo_timer_list keepalive_timer;
+
 	unsigned int number_endpoints;
 	struct mgcp_endpoint *endpoints;
 };
@@ -187,6 +194,8 @@ int mgcp_reset_transcoder(struct mgcp_config *cfg);
 void mgcp_format_stats(struct mgcp_endpoint *endp, char *stats, size_t size);
 int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os, uint32_t *pr, uint32_t *_or, int *loss, uint32_t *jitter);
 
+void mgcp_trunk_set_keepalive(struct mgcp_trunk_config *tcfg, int interval);
+
 /*
  * format helper functions
  */
diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c
index b55da37..9996ba7 100644
--- a/openbsc/src/libmgcp/mgcp_protocol.c
+++ b/openbsc/src/libmgcp/mgcp_protocol.c
@@ -877,6 +877,9 @@ mgcp_header_done:
 	if (p->cfg->change_cb)
 		p->cfg->change_cb(tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
 
+	if (endp->bts_end.output_enabled && tcfg->keepalive_interval != 0)
+		mgcp_send_dummy(endp);
+
 	create_transcoder(endp);
 	return create_response_with_sdp(endp, "CRCX", p->trans);
 error2:
@@ -975,6 +978,10 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p)
 		ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
 	if (p->cfg->change_cb)
 		p->cfg->change_cb(endp->tcfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX);
+
+	if (endp->bts_end.output_enabled && endp->tcfg->keepalive_interval != 0)
+		mgcp_send_dummy(endp);
+
 	if (silent)
 		goto out_silent;
 
@@ -1127,6 +1134,40 @@ static struct msgb *handle_noti_req(struct mgcp_parse_data *p)
 		create_err_response(p->endp, res, "RQNT", p->trans);
 }
 
+static void mgcp_keepalive_timer_cb(void *_tcfg)
+{
+	struct mgcp_trunk_config *tcfg = _tcfg;
+	int i;
+	LOGP(DMGCP, LOGL_DEBUG, "Triggered trunk %d keepalive timer.\n",
+	     tcfg->trunk_nr);
+
+	if (tcfg->keepalive_interval <= 0)
+		return;
+
+	for (i = 1; i < tcfg->number_endpoints; ++i) {
+		struct mgcp_endpoint *endp = &tcfg->endpoints[i];
+		if (endp->conn_mode == MGCP_CONN_RECV_ONLY)
+			mgcp_send_dummy(endp);
+	}
+
+	LOGP(DMGCP, LOGL_DEBUG, "Rescheduling trunk %d keepalive timer.\n",
+	     tcfg->trunk_nr);
+	osmo_timer_schedule(&tcfg->keepalive_timer, tcfg->keepalive_interval, 0);
+}
+
+void mgcp_trunk_set_keepalive(struct mgcp_trunk_config *tcfg, int interval)
+{
+	tcfg->keepalive_interval = interval;
+	tcfg->keepalive_timer.data = tcfg;
+	tcfg->keepalive_timer.cb = mgcp_keepalive_timer_cb;
+
+	if (interval <= 0)
+		osmo_timer_del(&tcfg->keepalive_timer);
+	else
+		osmo_timer_schedule(&tcfg->keepalive_timer,
+				    tcfg->keepalive_interval, 0);
+}
+
 struct mgcp_config *mgcp_config_alloc(void)
 {
 	struct mgcp_config *cfg;
@@ -1153,6 +1194,7 @@ struct mgcp_config *mgcp_config_alloc(void)
 	cfg->trunk.audio_payload = 126;
 	cfg->trunk.audio_send_ptime = 1;
 	cfg->trunk.omit_rtcp = 0;
+	mgcp_trunk_set_keepalive(&cfg->trunk, MGCP_KEEPALIVE_ONCE);
 
 	INIT_LLIST_HEAD(&cfg->trunks);
 
@@ -1177,6 +1219,7 @@ struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int nr)
 	trunk->audio_send_ptime = 1;
 	trunk->number_endpoints = 33;
 	trunk->omit_rtcp = 0;
+	mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
 	llist_add_tail(&trunk->entry, &cfg->trunks);
 	return trunk;
 }
diff --git a/openbsc/src/libmgcp/mgcp_vty.c b/openbsc/src/libmgcp/mgcp_vty.c
index 3f1ebeb..408a059 100644
--- a/openbsc/src/libmgcp/mgcp_vty.c
+++ b/openbsc/src/libmgcp/mgcp_vty.c
@@ -32,6 +32,7 @@
 
 #define RTCP_OMIT_STR "Drop RTCP packets in both directions\n"
 #define RTP_PATCH_STR "Modify RTP packet header in both directions\n"
+#define RTP_KEEPALIVE_STR "Send dummy UDP packet to net RTP destination\n"
 
 static struct mgcp_config *g_cfg = NULL;
 
@@ -85,6 +86,14 @@ static int config_write_mgcp(struct vty *vty)
 			g_cfg->net_ports.range_start, g_cfg->net_ports.range_end, VTY_NEWLINE);
 
 	vty_out(vty, "  rtp ip-dscp %d%s", g_cfg->endp_dscp, VTY_NEWLINE);
+	if (g_cfg->trunk.keepalive_interval == MGCP_KEEPALIVE_ONCE)
+		vty_out(vty, "  rtp keep-alive once%s", VTY_NEWLINE);
+	else if (g_cfg->trunk.keepalive_interval)
+		vty_out(vty, "  rtp keep-alive %d%s",
+			g_cfg->trunk.keepalive_interval, VTY_NEWLINE);
+	else
+		vty_out(vty, "  no rtp keep-alive%s", VTY_NEWLINE);
+
 	if (g_cfg->trunk.omit_rtcp)
 		vty_out(vty, "  rtcp-omit%s", VTY_NEWLINE);
 	else
@@ -511,6 +520,39 @@ DEFUN(cfg_mgcp_no_patch_rtp,
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_mgcp_rtp_keepalive,
+      cfg_mgcp_rtp_keepalive_cmd,
+      "rtp keep-alive <1-120>",
+      RTP_STR RTP_KEEPALIVE_STR
+      "Keep alive interval in secs\n"
+      )
+{
+	mgcp_trunk_set_keepalive(&g_cfg->trunk, atoi(argv[0]));
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp_rtp_keepalive_once,
+      cfg_mgcp_rtp_keepalive_once_cmd,
+      "rtp keep-alive once",
+      RTP_STR RTP_KEEPALIVE_STR
+      "Send dummy packet only once after CRCX/MDCX\n"
+      )
+{
+	mgcp_trunk_set_keepalive(&g_cfg->trunk, MGCP_KEEPALIVE_ONCE);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp_no_rtp_keepalive,
+      cfg_mgcp_no_rtp_keepalive_cmd,
+      "no rtp keep-alive",
+      NO_STR RTP_STR RTP_KEEPALIVE_STR
+      )
+{
+	mgcp_trunk_set_keepalive(&g_cfg->trunk, 0);
+	return CMD_SUCCESS;
+}
+
+
 
 #define CALL_AGENT_STR "Callagent information\n"
 DEFUN(cfg_mgcp_agent_addr,
@@ -598,6 +640,15 @@ static int config_write_trunk(struct vty *vty)
 			trunk->audio_name, VTY_NEWLINE);
 		vty_out(vty, "  %ssdp audio-payload send-ptime%s",
 			trunk->audio_send_ptime ? "" : "no ", VTY_NEWLINE);
+
+		if (trunk->keepalive_interval == MGCP_KEEPALIVE_ONCE)
+			vty_out(vty, "  rtp keep-alive once%s", VTY_NEWLINE);
+		else if (trunk->keepalive_interval)
+			vty_out(vty, "  rtp keep-alive %d%s",
+				trunk->keepalive_interval, VTY_NEWLINE);
+		else
+			vty_out(vty, "  no rtp keep-alive%s", VTY_NEWLINE);
+
 		vty_out(vty, "  loop %d%s",
 			trunk->audio_loop, VTY_NEWLINE);
 		if (trunk->omit_rtcp)
@@ -780,6 +831,40 @@ DEFUN(cfg_trunk_no_patch_rtp,
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_trunk_rtp_keepalive,
+      cfg_trunk_rtp_keepalive_cmd,
+      "rtp keep-alive <1-120>",
+      RTP_STR RTP_KEEPALIVE_STR
+      "Keep-alive interval in secs\n"
+      )
+{
+	struct mgcp_trunk_config *trunk = vty->index;
+	mgcp_trunk_set_keepalive(trunk, atoi(argv[0]));
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_trunk_rtp_keepalive_once,
+      cfg_trunk_rtp_keepalive_once_cmd,
+      "rtp keep-alive once",
+      RTP_STR RTP_KEEPALIVE_STR
+      "Send dummy packet only once after CRCX/MDCX\n"
+      )
+{
+	struct mgcp_trunk_config *trunk = vty->index;
+	mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_trunk_no_rtp_keepalive,
+      cfg_trunk_no_rtp_keepalive_cmd,
+      "no rtp keep-alive",
+      NO_STR RTP_STR RTP_KEEPALIVE_STR
+      )
+{
+	struct mgcp_trunk_config *trunk = vty->index;
+	mgcp_trunk_set_keepalive(trunk, 0);
+	return CMD_SUCCESS;
+}
 
 DEFUN(loop_endp,
       loop_endp_cmd,
@@ -999,6 +1084,9 @@ int mgcp_vty_init(void)
 	install_element(MGCP_NODE, &cfg_mgcp_rtp_transcoder_base_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_dscp_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_tos_cmd);
+	install_element(MGCP_NODE, &cfg_mgcp_rtp_keepalive_cmd);
+	install_element(MGCP_NODE, &cfg_mgcp_rtp_keepalive_once_cmd);
+	install_element(MGCP_NODE, &cfg_mgcp_no_rtp_keepalive_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_agent_addr_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_agent_addr_cmd_old);
 	install_element(MGCP_NODE, &cfg_mgcp_transcoder_cmd);
@@ -1024,6 +1112,9 @@ int mgcp_vty_init(void)
 	install_element(MGCP_NODE, &cfg_mgcp_trunk_cmd);
 	install_node(&trunk_node, config_write_trunk);
 	vty_install_default(TRUNK_NODE);
+	install_element(TRUNK_NODE, &cfg_trunk_rtp_keepalive_cmd);
+	install_element(TRUNK_NODE, &cfg_trunk_rtp_keepalive_once_cmd);
+	install_element(TRUNK_NODE, &cfg_trunk_no_rtp_keepalive_cmd);
 	install_element(TRUNK_NODE, &cfg_trunk_payload_number_cmd);
 	install_element(TRUNK_NODE, &cfg_trunk_payload_name_cmd);
 	install_element(TRUNK_NODE, &cfg_trunk_payload_number_cmd_old);
diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_main.c b/openbsc/src/osmo-bsc_mgcp/mgcp_main.c
index 596ea8a..14ec221 100644
--- a/openbsc/src/osmo-bsc_mgcp/mgcp_main.c
+++ b/openbsc/src/osmo-bsc_mgcp/mgcp_main.c
@@ -137,15 +137,6 @@ static int mgcp_rsip_cb(struct mgcp_trunk_config *tcfg)
 	return 0;
 }
 
-static int mgcp_change_cb(struct mgcp_trunk_config *cfg, int endpoint, int state)
-{
-	if (state != MGCP_ENDP_MDCX)
-		return 0;
-
-	mgcp_send_dummy(&cfg->endpoints[endpoint]);
-	return 0;
-}
-
 static int read_call_agent(struct osmo_fd *fd, unsigned int what)
 {
 	struct sockaddr_in addr;
@@ -233,7 +224,6 @@ int main(int argc, char **argv)
 
 	/* set some callbacks */
 	cfg->reset_cb = mgcp_rsip_cb;
-	cfg->change_cb = mgcp_change_cb;
 
         /* we need to bind a socket */
         if (rc == 0) {
diff --git a/openbsc/tests/mgcp/mgcp_test.ok b/openbsc/tests/mgcp/mgcp_test.ok
index 6db7226..7e8aa5c 100644
--- a/openbsc/tests/mgcp/mgcp_test.ok
+++ b/openbsc/tests/mgcp/mgcp_test.ok
@@ -16,6 +16,7 @@ Testing AUEP2
 Testing MDCX1
 Testing MDCX2
 Testing CRCX
+Dummy packets: 1
 Detected packet duration: 40
 Requested packetetization period: 20-20
 Connection mode: 1, BTS output enabled, NET output disabled
@@ -24,18 +25,22 @@ Packet duration not set
 Requested packetization period not set
 Connection mode not set
 Testing MDCX4
+Dummy packets: 1
 Detected packet duration: 40
 Requested packetetization period: 20-20
 Connection mode: 3, BTS output enabled, NET output enabled
 Testing MDCX4_PT1
+Dummy packets: 1
 Detected packet duration: 40
 Requested packetetization period: 20-40
 Connection mode: 3, BTS output enabled, NET output enabled
 Testing MDCX4_PT2
+Dummy packets: 1
 Detected packet duration: 40
 Requested packetetization period: 20-20
 Connection mode: 3, BTS output enabled, NET output enabled
 Testing MDCX4_PT3
+Dummy packets: 1
 Detected packet duration: 40
 Requested packetization period not set
 Connection mode: 3, BTS output enabled, NET output enabled
@@ -48,6 +53,7 @@ Detected packet duration: 20
 Requested packetization period not set
 Connection mode: 0, BTS output enabled, NET output enabled
 Testing CRCX_ZYN
+Dummy packets: 1
 Packet duration not set
 Requested packetization period not set
 Connection mode: 1, BTS output enabled, NET output disabled
-- 
1.7.9.5





More information about the OpenBSC mailing list