aboutsummaryrefslogtreecommitdiffstats
path: root/src/gbproxy/gb_proxy_peer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gbproxy/gb_proxy_peer.c')
-rw-r--r--src/gbproxy/gb_proxy_peer.c67
1 files changed, 66 insertions, 1 deletions
diff --git a/src/gbproxy/gb_proxy_peer.c b/src/gbproxy/gb_proxy_peer.c
index 863ec5017..3b120467f 100644
--- a/src/gbproxy/gb_proxy_peer.c
+++ b/src/gbproxy/gb_proxy_peer.c
@@ -343,7 +343,15 @@ struct gbproxy_nse *gbproxy_nse_by_nsei_or_new(struct gbproxy_config *cfg, uint1
return nse;
}
-/* SGSN */
+/***********************************************************************
+ * SGSN - Serving GPRS Support Node
+ ***********************************************************************/
+
+/*! Allocate a new SGSN. This ensures the corresponding gbproxy_nse is allocated as well
+ * \param[in] cfg The gbproxy configuration
+ * \param[in] nsei The nsei where the SGSN can be reached
+ * \return The SGSN, NULL if it couldn't be allocated
+ */
struct gbproxy_sgsn *gbproxy_sgsn_alloc(struct gbproxy_config *cfg, uint16_t nsei)
{
struct gbproxy_sgsn *sgsn;
@@ -381,6 +389,9 @@ static void _sgsn_free(struct gbproxy_sgsn *sgsn) {
talloc_free(sgsn);
}
+/*! Free the SGSN. This ensures the corresponding gbproxy_nse is freed as well
+ * \param[in] sgsn The SGSN
+ */
void gbproxy_sgsn_free(struct gbproxy_sgsn *sgsn)
{
if (!sgsn)
@@ -392,6 +403,11 @@ void gbproxy_sgsn_free(struct gbproxy_sgsn *sgsn)
_sgsn_free(sgsn);
}
+/*! Return the SGSN for a given NSEI
+ * \param[in] cfg The gbproxy configuration
+ * \param[in] nsei The nsei where the SGSN can be reached
+ * \return Returns the matching SGSN or NULL if it couldn't be found
+ */
struct gbproxy_sgsn *gbproxy_sgsn_by_nsei(struct gbproxy_config *cfg, uint16_t nsei)
{
struct gbproxy_sgsn *sgsn;
@@ -405,6 +421,11 @@ struct gbproxy_sgsn *gbproxy_sgsn_by_nsei(struct gbproxy_config *cfg, uint16_t n
return NULL;
}
+/*! Return the SGSN for a given NSEI, creating a new one if none exists
+ * \param[in] cfg The gbproxy configuration
+ * \param[in] nsei The nsei where the SGSN can be reached
+ * \return Returns the SGSN
+ */
struct gbproxy_sgsn *gbproxy_sgsn_by_nsei_or_new(struct gbproxy_config *cfg, uint16_t nsei)
{
struct gbproxy_sgsn *sgsn;
@@ -443,3 +464,47 @@ struct gbproxy_sgsn *gbproxy_sgsn_by_nri(struct gbproxy_config *cfg, uint16_t nr
return NULL;
}
+
+/*! Seleect a pseudo-random SGSN for a given TLLI, ignoring any SGSN that is not accepting connections
+ * \param[in] cfg The gbproxy configuration
+ * \param[in] sgsn_avoid If not NULL then avoid this SGSN when selecting a new one. Use for load redistribution
+ * \param[in] tlli The tlli to choose an SGSN for. The same tlli will map to the same SGSN as long as no SGSN is
+ added/removed or allow_attach changes.
+ * \return Returns the sgsn on success, NULL if no SGSN that allows new connections could be found
+ */
+struct gbproxy_sgsn *gbproxy_sgsn_by_tlli(struct gbproxy_config *cfg, struct gbproxy_sgsn *sgsn_avoid,
+ uint32_t tlli)
+{
+ uint32_t i = 0;
+ uint32_t index, num_sgsns;
+ struct gbproxy_sgsn *sgsn;
+ OSMO_ASSERT(cfg);
+
+ // TODO: We should keep track of count in cfg
+ num_sgsns = llist_count(&cfg->sgsns);
+
+ if (num_sgsns == 0)
+ return NULL;
+
+ // FIXME: 256 SGSNs ought to be enough for everyone
+ index = hash_32(tlli, 8) % num_sgsns;
+
+ // Get the first enabled SGSN after index
+ llist_for_each_entry(sgsn, &cfg->sgsns, list) {
+ if (i >= index && sgsn->pool.allow_attach) {
+ return sgsn;
+ }
+ i++;
+ }
+ // Start again from the beginning
+ llist_for_each_entry(sgsn, &cfg->sgsns, list) {
+ if (i > index) {
+ break;
+ } else if (sgsn->pool.allow_attach) {
+ return sgsn;
+ }
+ i++;
+ }
+
+ return NULL;
+}