db v6: determine 3G AUC IND from VLR name

Each VLR requesting auth tuples should use a distinct IND pool for 3G auth.  So
far we tied the IND to the GSUP peer connection; MSC and SGSN were always
distinct GSUP peers, they ended up using distinct INDs.

However, we have implemented a GSUP proxy, so that, in a distributed setup, a
remotely roaming subscriber has only one direct GSUP peer proxying for both
remote MSC and SGSN. That means as soon as a subscriber roams to a different
site, we would use the GSUP proxy name to determine the IND instead of the
separate MSC and SGSN. The site's MSC and SGSN appear as the same client, get
the same IND bucket, waste SQNs rapidly and cause auth tuple generation load.

So instead of using the local client as IND, persistently keep a list of VLR
names and assign a different IND to each. Use the gsup_req->source_name as
indicator, which reflects the actual remote VLR's name (remote MSC or SGSN).

Persist the site <-> IND assignments in the database.

Add an IND test to db_test.c

There was an earlier patch version that separated the IND pools by cn_domain,
but it turned out to add complex semantics, while only solving one aspect of
the "adjacent VLR" problem. We need a solution not only for CS vs PS, but also
for 2,3G vs 4G, and for sites that are physically adjacent to each other. This
patch version does not offer any automatic solution for that -- as soon as more
than 2^IND_bitlen (usually 32) VLRs show up, it is the responsibility of the
admin to ensure the 'ind' table in the hlr.db does not have unfortunate IND
assignments. So far no VTY commands exist for that, they may be added in the
future.

Related: OS#4319
Change-Id: I6f0a6bbef3a27507605c3b4a0e1a89bdfd468374
diff --git a/src/db.c b/src/db.c
index 3cbd9c9..a2d2f84 100644
--- a/src/db.c
+++ b/src/db.c
@@ -30,7 +30,7 @@
 #include "db_bootstrap.h"
 
 /* This constant is currently duplicated in sql/hlr.sql and must be kept in sync! */
-#define CURRENT_SCHEMA_VERSION	5
+#define CURRENT_SCHEMA_VERSION	6
 
 #define SEL_COLUMNS \
 	"id," \
@@ -87,6 +87,9 @@
 	[DB_STMT_SET_LAST_LU_SEEN_PS] = "UPDATE subscriber SET last_lu_seen_ps = datetime($val, 'unixepoch') WHERE id = $subscriber_id",
 	[DB_STMT_EXISTS_BY_IMSI] = "SELECT 1 FROM subscriber WHERE imsi = $imsi",
 	[DB_STMT_EXISTS_BY_MSISDN] = "SELECT 1 FROM subscriber WHERE msisdn = $msisdn",
+	[DB_STMT_IND_ADD] = "INSERT INTO ind (vlr) VALUES ($vlr)",
+	[DB_STMT_IND_SELECT] = "SELECT ind FROM ind WHERE vlr = $vlr",
+	[DB_STMT_IND_DEL] = "DELETE FROM ind WHERE vlr = $vlr",
 };
 
 static void sql3_error_log_cb(void *arg, int err_code, const char *msg)
@@ -481,6 +484,30 @@
 	return rc;
 }
 
+static int db_upgrade_v6(struct db_context *dbc)
+{
+	int rc;
+	const char *statements[] = {
+		"CREATE TABLE ind (\n"
+		"	cn_domain INTEGER NOT NULL,\n"
+		"	-- 3G auth IND bucket to be used for this VLR, where IND = (idx << 1) + cn_domain -1\n"
+		"	ind     INTEGER PRIMARY KEY,\n"
+		"	-- VLR identification, usually the GSUP source_name\n"
+		"	vlr     TEXT NOT NULL,\n"
+		"	UNIQUE (cn_domain, vlr)\n"
+		")"
+		,
+		"PRAGMA user_version = 6",
+	};
+
+	rc = db_run_statements(dbc, statements, ARRAY_SIZE(statements));
+	if (rc != SQLITE_DONE) {
+		LOGP(DDB, LOGL_ERROR, "Unable to update HLR database schema to version 6\n");
+		return rc;
+	}
+	return rc;
+}
+
 typedef int (*db_upgrade_func_t)(struct db_context *dbc);
 static db_upgrade_func_t db_upgrade_path[] = {
 	db_upgrade_v1,
@@ -488,6 +515,7 @@
 	db_upgrade_v3,
 	db_upgrade_v4,
 	db_upgrade_v5,
+	db_upgrade_v6,
 };
 
 static int db_get_user_version(struct db_context *dbc)