diff options
Diffstat (limited to 'src/gbproxy/gb_proxy_peer.c')
-rw-r--r-- | src/gbproxy/gb_proxy_peer.c | 67 |
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; +} |