D-GSM 3/n: implement roaming by mslookup in osmo-hlr

Add mslookup client to find remote home HLRs of unknown IMSIs, and
proxy/forward GSUP for those to the right remote HLR instances.

Add remote_hlr.c to manage one GSUP client per remote HLR GSUP address.

Add proxy.c to keep state about remotely handled IMSIs (remote GSUP address,
MSISDN, and probably more in future patches).  The mslookup_server that
determines whether a given MSISDN is attached locally now also needs to look in
the proxy record: it is always the osmo-hlr immediately peering for the MSC
that should respond to mslookup service address queries like SIP and SMPP.
(Only gsup.hlr service is always answered by the home HLR.)

Add dgsm.c to set up an mdns mslookup client, ask for IMSI homes, and to decide
which GSUP is handled locally and which needs to go to a remote HLR.

Add full VTY config and VTY tests.

For a detailed overview of the D-GSM and mslookup related files, please see the
elaborate comment at the top of mslookup.c (already added in an earlier patch).

Change-Id: I2fe453553c90e6ee527ed13a13089900efd488aa
diff --git a/src/hlr.c b/src/hlr.c
index 59ce4f5..0d8024f 100644
--- a/src/hlr.c
+++ b/src/hlr.c
@@ -36,6 +36,7 @@
 #include <osmocom/gsm/gsm48_ie.h>
 #include <osmocom/gsm/gsm_utils.h>
 #include <osmocom/gsm/gsm23003.h>
+#include <osmocom/mslookup/mslookup_client.h>
 
 #include <osmocom/gsupclient/gsup_peer_id.h>
 #include <osmocom/hlr/db.h>
@@ -47,6 +48,8 @@
 #include <osmocom/hlr/rand.h>
 #include <osmocom/hlr/hlr_vty.h>
 #include <osmocom/hlr/hlr_ussd.h>
+#include <osmocom/hlr/dgsm.h>
+#include <osmocom/hlr/proxy.h>
 #include <osmocom/hlr/lu_fsm.h>
 #include <osmocom/mslookup/mdns.h>
 
@@ -495,6 +498,15 @@
 		}
 	}
 
+	/* Distributed GSM: check whether to proxy for / lookup a remote HLR.
+	 * It would require less database hits to do this only if a local-only operation fails with "unknown IMSI", but
+	 * it becomes semantically easier if we do this once-off ahead of time. */
+	if (osmo_mslookup_client_active(g_hlr->mslookup.client.client)
+	    || osmo_sockaddr_str_is_nonzero(&g_hlr->mslookup.client.gsup_gateway_proxy)) {
+		if (dgsm_check_forward_gsup_msg(req))
+			return 0;
+	}
+
 	switch (req->gsup.message_type) {
 	/* requests sent to us */
 	case OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST:
@@ -695,6 +707,7 @@
 	INIT_LLIST_HEAD(&g_hlr->mslookup.server.local_site_services);
 	g_hlr->db_file_path = talloc_strdup(g_hlr, HLR_DEFAULT_DB_FILE_PATH);
 	g_hlr->mslookup.server.mdns.domain_suffix = talloc_strdup(g_hlr, OSMO_MDNS_DOMAIN_SUFFIX_DEFAULT);
+	g_hlr->mslookup.client.mdns.domain_suffix = talloc_strdup(g_hlr, OSMO_MDNS_DOMAIN_SUFFIX_DEFAULT);
 
 	/* Init default (call independent) SS session guard timeout value */
 	g_hlr->ncss_guard_timeout = NCSS_GUARD_TIMEOUT_DEFAULT;
@@ -705,6 +718,9 @@
 		exit(1);
 	}
 
+	/* Set up llists and objects, startup is happening from VTY commands. */
+	dgsm_init(hlr_ctx);
+
 	osmo_stats_init(hlr_ctx);
 	vty_init(&vty_info);
 	ctrl_vty_init(hlr_ctx);
@@ -760,10 +776,13 @@
 		LOGP(DMAIN, LOGL_FATAL, "Error starting GSUP server\n");
 		exit(1);
 	}
+	proxy_init(g_hlr->gs);
 
 	g_hlr->ctrl_bind_addr = ctrl_vty_get_bind_addr();
 	g_hlr->ctrl = hlr_controlif_setup(g_hlr);
 
+	dgsm_start(hlr_ctx);
+
 	osmo_init_ignore_signals();
 	signal(SIGINT, &signal_hdlr);
 	signal(SIGTERM, &signal_hdlr);
@@ -780,6 +799,7 @@
 	while (!quit)
 		osmo_select_main_ctx(0);
 
+	dgsm_stop();
 
 	osmo_gsup_server_destroy(g_hlr->gs);
 	db_close(g_hlr->dbc);