gbproxy major rewrite for SGSN pool support

Rewrite of a large part of osmo-gbproxy in order to prepare
for SGSN pool support.  The amount of changes are of such fundamental
nature that it doesn't make sense to try to split this into hundreds
of individual changesets.

Related: OS#4472
Change-Id: Ie0746f17927a9509c3806cc80dc1a31d25df7937
diff --git a/include/osmocom/sgsn/gb_proxy.h b/include/osmocom/sgsn/gb_proxy.h
index ac03a11..e61b991 100644
--- a/include/osmocom/sgsn/gb_proxy.h
+++ b/include/osmocom/sgsn/gb_proxy.h
@@ -4,6 +4,7 @@
 
 #include <osmocom/core/msgb.h>
 #include <osmocom/core/timer.h>
+#include <osmocom/core/fsm.h>
 #include <osmocom/core/hashtable.h>
 #include <osmocom/gsm/gsm23003.h>
 
@@ -48,19 +49,43 @@
 
 /* global gb-proxy configuration */
 struct gbproxy_config {
-	/* parsed from config file */
-	uint16_t nsip_sgsn_nsei;
-
 	/* NS instance of libosmogb */
 	struct gprs_ns2_inst *nsi;
 
 	/* Linked list of all BSS side Gb peers */
 	DECLARE_HASHTABLE(bss_nses, 8);
 
+	/* hash table of all SGSN-side Gb peers */
+	DECLARE_HASHTABLE(sgsn_nses, 8);
+
+	/* hash table of all gbproxy_cell */
+	DECLARE_HASHTABLE(cells, 8);
+
 	/* Counter */
 	struct rate_ctr_group *ctrg;
 };
 
+/* One Cell within the BSS: Links BSS-side BVC to SGSN-side BVCs */
+struct gbproxy_cell {
+	/* linked to gbproxy_config.cells hashtable */
+	struct hlist_node list;
+
+	/* point back to the config */
+	struct gbproxy_config *cfg;
+
+	/*  BVCI of PTP BVCs associated to this cell */
+	uint16_t bvci;
+
+	/* Routing Area that this BVC is part of (raw 04.08 encoding) */
+	uint8_t ra[6];
+
+	/* pointer to the BSS-side BVC */
+	struct gbproxy_bvc *bss_bvc;
+
+	/* pointers to SGSN-side BVC (one for each pool member) */
+	struct gbproxy_bvc *sgsn_bvc[16];
+};
+
 /* One BVC inside an NSE */
 struct gbproxy_bvc {
 	/* linked to gbproxy_nse.bvcs */
@@ -75,11 +100,14 @@
 	/* Routing Area that this BVC is part of (raw 04.08 encoding) */
 	uint8_t ra[6];
 
-	/* true if this BVC is blocked */
-	bool blocked;
-
 	/* Counter */
 	struct rate_ctr_group *ctrg;
+
+	/* the cell to which this BVC belongs */
+	struct gbproxy_cell *cell;
+
+	/* per-BVC FSM instance */
+	struct osmo_fsm_inst *fi;
 };
 
 /* one NS Entity that we interact with (BSS/PCU) */
@@ -93,19 +121,24 @@
 	/* NSEI of the NSE */
 	uint16_t nsei;
 
+	/* Are we facing towards a SGSN (true) or BSS (false) */
+	bool sgsn_facing;
+
 	/* List of all BVCs in this NSE */
 	DECLARE_HASHTABLE(bvcs, 10);
 };
 
 /* Convenience logging macros for NSE/BVC */
 #define LOGPNSE_CAT(NSE, SUBSYS, LEVEL, FMT, ARGS...) \
-	LOGP(SUBSYS, LEVEL, "NSE(%05u/BSS) " FMT, (NSE)->nsei, ## ARGS)
+	LOGP(SUBSYS, LEVEL, "NSE(%05u/%s) " FMT, (NSE)->nsei, \
+		(NSE)->sgsn_facing ? "SGSN" : "BSS", ## ARGS)
 #define LOGPNSE(NSE, LEVEL, FMT, ARGS...) \
 	LOGPNSE_CAT(NSE, DGPRS, LEVEL, FMT, ## ARGS)
 
 #define LOGPBVC_CAT(BVC, SUBSYS, LEVEL, FMT, ARGS...) \
-	LOGP(SUBSYS, LEVEL, "NSE(%05u/BSS)-BVC(%05u/%s) " FMT, (BVC)->nse->nsei, (BVC)->bvci, \
-		(BVC)->blocked ? "BLOCKED" : "UNBLOCKED", ## ARGS)
+	LOGP(SUBSYS, LEVEL, "NSE(%05u/%s)-BVC(%05u/%s) " FMT, (BVC)->nse->nsei, \
+		(BVC)->nse->sgsn_facing ? "SGSN" : "BSS", (BVC)->bvci, \
+		osmo_fsm_inst_state_name((BVC)->fi), ## ARGS)
 #define LOGPBVC(BVC, LEVEL, FMT, ARGS...) \
 	LOGPBVC_CAT(BVC, DGPRS, LEVEL, FMT, ## ARGS)
 
@@ -133,21 +166,23 @@
 void gbprox_reset(struct gbproxy_config *cfg);
 
 /* Peer handling */
-struct gbproxy_bvc *gbproxy_bvc_by_bvci(
-	struct gbproxy_config *cfg, uint16_t bvci);
-struct gbproxy_bvc *gbproxy_bvc_by_nsei(
-	struct gbproxy_config *cfg, uint16_t nsei);
-struct gbproxy_bvc *gbproxy_bvc_by_rai(
-	struct gbproxy_config *cfg, const uint8_t *ra);
+#define NSE_F_SGSN	0x0001
+#define NSE_F_BSS	0x0002
+
+struct gbproxy_bvc *gbproxy_bvc_by_bvci(struct gbproxy_nse *nse, uint16_t bvci);
 struct gbproxy_bvc *gbproxy_bvc_alloc(struct gbproxy_nse *nse, uint16_t bvci);
 void gbproxy_bvc_free(struct gbproxy_bvc *bvc);
-void gbproxy_bvc_move(struct gbproxy_bvc *bvc, struct gbproxy_nse *nse);
-int gbproxy_cleanup_bvcs(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci);
+int gbproxy_cleanup_bvcs(struct gbproxy_nse *nse, uint16_t bvci);
+
+struct gbproxy_cell *gbproxy_cell_alloc(struct gbproxy_config *cfg, uint16_t bvci);
+struct gbproxy_cell *gbproxy_cell_by_bvci(struct gbproxy_config *cfg, uint16_t bvci);
+void gbproxy_cell_free(struct gbproxy_cell *cell);
+bool gbproxy_cell_add_sgsn_bvc(struct gbproxy_cell *cell, struct gbproxy_bvc *bvc);
 
 /* NSE handling */
-struct gbproxy_nse *gbproxy_nse_alloc(struct gbproxy_config *cfg, uint16_t nsei);
+struct gbproxy_nse *gbproxy_nse_alloc(struct gbproxy_config *cfg, uint16_t nsei, bool sgsn_facing);
 void gbproxy_nse_free(struct gbproxy_nse *nse);
-struct gbproxy_nse *gbproxy_nse_by_nsei(struct gbproxy_config *cfg, uint16_t nsei);
-struct gbproxy_nse *gbproxy_nse_by_nsei_or_new(struct gbproxy_config *cfg, uint16_t nsei);
+struct gbproxy_nse *gbproxy_nse_by_nsei(struct gbproxy_config *cfg, uint16_t nsei, uint32_t flags);
+struct gbproxy_nse *gbproxy_nse_by_nsei_or_new(struct gbproxy_config *cfg, uint16_t nsei, bool sgsn_facing);
 
 #endif