[PATCH] osmo-bsc[master]: HO prep: introduce per-BTS handover config, with defaults on...

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Neels Hofmeyr gerrit-no-reply at lists.osmocom.org
Wed Nov 29 17:42:19 UTC 2017


Hello Jenkins Builder,

I'd like you to reexamine a change.  Please visit

    https://gerrit.osmocom.org/5050

to look at the new patch set (#7).

HO prep: introduce per-BTS handover config, with defaults on net node

It is desirable to allow configuring handover for each individual network cell.
At the same time, it is desirable to set global defaults.

Treat the 'network' node handover parameters as global defaults, add another
set of parameters for each individual BTS.

This raises questions on how the 'network' node should affect the individual
BTS. The simplistic solution would have been: on creating a BTS in the config,
just copy the current defaults; with serious drawbacks:
- tweaking any parameter in the telnet VTY on network node will never affect
  any running BTS.
- network node defaults *must* be issued before the bts sections in the config
  file.
- when writing a config back to file, we would copy all net node defaults to
  each BTS node, making the network node configs pointless.

Instead, add a handover_cfg API that tracks whether a given node has a value
set or not. A bts node ho_cfg gets a pointer to the network node config and
returns those values if locally unset. If no value is set on any node, use the
"factory" defaults, which are hardcoded in the API. Only write back exactly
those config items that were actually issued in a config file / on the telnet
VTY. (ho_cfg API wise, we could trivially add another ho_cfg level per TRX if
we so desire in the future.)

Implement ho parameters as an opaque config struct with getters and setters to
ensure the tracking is always heeded. Opaqueness dictates allocating instead of
direct embedding in gsm_network and gsm_bts structs, ctx is gsm_net / bts.

This is 100% backwards compatible to
old configs.
- No VTY command syntax changes (only the online help).
- If a 'bts' sets nothing, it will use the 'network' defaults.
- The 'show network' output only changes in presence of individual BTS configs.

On 'show network', say "Handover: On|Off" as before, iff all BTS reflect
identical behavior. Otherwise, output BTS counts of handover being enabled or
not.

Use the same set of VTY commands (same VTY cmd syntax as before) on network and
BTS nodes, i.e. don't duplicate VTY code. From the current vty->node, figure
out which ho_cfg to modify.

For linking, add handover_cfg.c (the value API) in libcommon, while the
handover_vty.c is in libbsc. This is mainly because some utility programs use
gsm_network and hence suck in the ho stuff, but don't need the VTY commands.

Review the VTY online help strings.

Add VTY transcript test for handover options, testing config propagation from
network to bts nodes, 'show network' output and VTY online help strings.
(Needs recent addition of '... !' wildcard to osmo_interact_common.py.)

Though the ho_cfg value getter/setter function definitions are made by a macro,
the declarations in handover_cfg.h are written out in full for better API
readability.

Inspired-by: jolly/new_handover branch, which moves the config to 'bts' level
Depends: I7c1ebb2e7f059047903a53de26a0ec1ce7fa9b98 (osmo-python-tests)
Change-Id: I00870a5828703cf397776668d3301c0c3a4e033a
---
M include/osmocom/bsc/Makefile.am
M include/osmocom/bsc/gsm_data.h
M include/osmocom/bsc/gsm_data_shared.h
A include/osmocom/bsc/handover_cfg.h
A include/osmocom/bsc/handover_vty.h
M src/libbsc/Makefile.am
M src/libbsc/bsc_vty.c
M src/libbsc/handover_decision.c
A src/libbsc/handover_vty.c
M src/libbsc/net_init.c
M src/libcommon/Makefile.am
M src/libcommon/gsm_data.c
M src/libcommon/gsm_data_shared.c
A src/libcommon/handover_cfg.c
M tests/Makefile.am
A tests/handover_cfg.vty
16 files changed, 639 insertions(+), 148 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/osmo-bsc refs/changes/50/5050/7

diff --git a/include/osmocom/bsc/Makefile.am b/include/osmocom/bsc/Makefile.am
index 9d2ee6e..10467c5 100644
--- a/include/osmocom/bsc/Makefile.am
+++ b/include/osmocom/bsc/Makefile.am
@@ -28,7 +28,9 @@
 	gsm_data_shared.h \
 	gsm_subscriber.h \
 	handover.h \
+	handover_cfg.h \
 	handover_decision.h \
+	handover_vty.h \
 	ipaccess.h \
 	meas_feed.h \
 	meas_rep.h \
diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h
index 857dd4f..120537e 100644
--- a/include/osmocom/bsc/gsm_data.h
+++ b/include/osmocom/bsc/gsm_data.h
@@ -373,22 +373,7 @@
 	bool authentication_required;
 	int neci;
 	int send_mm_info;
-	struct {
-		int active;
-		/* Window RXLEV averaging */
-		unsigned int win_rxlev_avg;	/* number of SACCH frames */
-		/* Window RXQUAL averaging */
-		unsigned int win_rxqual_avg;	/* number of SACCH frames */
-		/* Window RXLEV neighbouring cells averaging */
-		unsigned int win_rxlev_avg_neigh; /* number of SACCH frames */
-
-		/* how often should we check for power budget HO */
-		unsigned int pwr_interval;	/* SACCH frames */
-		/* how much better does a neighbor cell have to be ? */
-		unsigned int pwr_hysteresis;	/* dBm */
-		/* maximum distacne before we try a handover */
-		unsigned int max_distance;	/* TA values */
-	} handover;
+	struct handover_cfg *ho;
 
 	struct rate_ctr_group *bsc_ctrs;
 	struct rate_ctr_group *msc_ctrs;
diff --git a/include/osmocom/bsc/gsm_data_shared.h b/include/osmocom/bsc/gsm_data_shared.h
index d7514ca..cc465e9 100644
--- a/include/osmocom/bsc/gsm_data_shared.h
+++ b/include/osmocom/bsc/gsm_data_shared.h
@@ -807,6 +807,8 @@
 	/* PCU socket state */
 	char *pcu_sock_path;
 	struct pcu_sock_state *pcu_state;
+
+	struct handover_cfg *ho;
 };
 
 
diff --git a/include/osmocom/bsc/handover_cfg.h b/include/osmocom/bsc/handover_cfg.h
new file mode 100644
index 0000000..9b0ad5e
--- /dev/null
+++ b/include/osmocom/bsc/handover_cfg.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include <stdbool.h>
+
+struct vty;
+
+/* handover_cfg is an opaque struct to manage several levels of configuration. There is an overall handover
+ * config on 'network' level and a per-'bts' specific handover config. If the 'bts' level sets no values,
+ * the defaults from 'network' level are used implicitly, and changes take effect immediately. */
+struct handover_cfg;
+
+struct handover_cfg *ho_cfg_init(void *ctx, struct handover_cfg *higher_level_cfg);
+
+bool ho_get_active(struct handover_cfg *ho);
+void ho_set_active(struct handover_cfg *ho, bool val);
+bool ho_isset_active(struct handover_cfg *ho);
+void ho_clear_active(struct handover_cfg *ho);
+
+unsigned int ho_get_win_rxlev_avg(struct handover_cfg *ho);
+void ho_set_win_rxlev_avg(struct handover_cfg *ho, unsigned int val);
+bool ho_isset_win_rxlev_avg(struct handover_cfg *ho);
+void ho_clear_win_rxlev_avg(struct handover_cfg *ho);
+
+unsigned int ho_get_win_rxqual_avg(struct handover_cfg *ho);
+void ho_set_win_rxqual_avg(struct handover_cfg *ho, unsigned int val);
+bool ho_isset_win_rxqual_avg(struct handover_cfg *ho);
+void ho_clear_win_rxqual_avg(struct handover_cfg *ho);
+
+unsigned int ho_get_win_rxlev_avg_neigh(struct handover_cfg *ho);
+void ho_set_win_rxlev_avg_neigh(struct handover_cfg *ho, unsigned int val);
+bool ho_isset_win_rxlev_avg_neigh(struct handover_cfg *ho);
+void ho_clear_win_rxlev_avg_neigh(struct handover_cfg *ho);
+
+unsigned int ho_get_pwr_interval(struct handover_cfg *ho);
+void ho_set_pwr_interval(struct handover_cfg *ho, unsigned int val);
+bool ho_isset_pwr_interval(struct handover_cfg *ho);
+void ho_clear_pwr_interval(struct handover_cfg *ho);
+
+unsigned int ho_get_pwr_hysteresis(struct handover_cfg *ho);
+void ho_set_pwr_hysteresis(struct handover_cfg *ho, unsigned int val);
+bool ho_isset_pwr_hysteresis(struct handover_cfg *ho);
+void ho_clear_pwr_hysteresis(struct handover_cfg *ho);
+
+unsigned int ho_get_max_distance(struct handover_cfg *ho);
+void ho_set_max_distance(struct handover_cfg *ho, unsigned int val);
+bool ho_isset_max_distance(struct handover_cfg *ho);
+void ho_clear_max_distance(struct handover_cfg *ho);
diff --git a/include/osmocom/bsc/handover_vty.h b/include/osmocom/bsc/handover_vty.h
new file mode 100644
index 0000000..48af136
--- /dev/null
+++ b/include/osmocom/bsc/handover_vty.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <osmocom/vty/vty.h>
+#include <osmocom/bsc/handover_cfg.h>
+
+void ho_vty_init();
+void ho_vty_write(struct vty *vty, const char *indent, struct handover_cfg *ho);
diff --git a/src/libbsc/Makefile.am b/src/libbsc/Makefile.am
index e78bde6..79a3739 100644
--- a/src/libbsc/Makefile.am
+++ b/src/libbsc/Makefile.am
@@ -53,5 +53,6 @@
 	net_init.c \
 	bsc_dyn_ts.c \
 	bts_ipaccess_nanobts_omlattr.c \
+	handover_vty.c \
 	$(NULL)
 
diff --git a/src/libbsc/bsc_vty.c b/src/libbsc/bsc_vty.c
index c5dedb3..231527d 100644
--- a/src/libbsc/bsc_vty.c
+++ b/src/libbsc/bsc_vty.c
@@ -58,6 +58,8 @@
 #include <osmocom/bsc/pcu_if.h>
 #include <osmocom/bsc/common_cs.h>
 #include <osmocom/bsc/handover.h>
+#include <osmocom/bsc/handover_cfg.h>
+#include <osmocom/bsc/handover_vty.h>
 #include <osmocom/bsc/gsm_04_08_utils.h>
 
 #include <inttypes.h>
@@ -184,8 +186,27 @@
 		VTY_NEWLINE);
 	vty_out(vty, "  MM Info: %s%s", net->send_mm_info ? "On" : "Off",
 		VTY_NEWLINE);
-	vty_out(vty, "  Handover: %s%s", net->handover.active ? "On" : "Off",
-		VTY_NEWLINE);
+
+	{
+		struct gsm_bts *bts;
+		unsigned int ho_active_count = 0;
+		unsigned int ho_inactive_count = 0;
+
+		llist_for_each_entry(bts, &net->bts_list, list) {
+			if (ho_get_active(bts->ho))
+				ho_active_count ++;
+			else
+				ho_inactive_count ++;
+		}
+
+		if (ho_active_count && ho_inactive_count)
+			vty_out(vty, "  Handover: On at %u BTS, Off at %u BTS%s",
+				ho_active_count, ho_inactive_count, VTY_NEWLINE);
+		else
+			vty_out(vty, "  Handover: %s%s", ho_active_count ? "On" : "Off",
+				VTY_NEWLINE);
+	}
+
 	network_chan_load(&pl, net);
 	vty_out(vty, "  Current Channel Load:%s", VTY_NEWLINE);
 	dump_pchan_load_vty(vty, "    ", &pl);
@@ -771,6 +792,8 @@
 	if (bts->pcu_sock_path)
 		vty_out(vty, "  pcu-socket %s%s", bts->pcu_sock_path, VTY_NEWLINE);
 
+	ho_vty_write(vty, "  ", bts->ho);
+
 	config_write_bts_model(vty, bts);
 }
 
@@ -810,19 +833,9 @@
 	vty_out(vty, " rrlp mode %s%s", rrlp_mode_name(gsmnet->rrlp.mode),
 		VTY_NEWLINE);
 	vty_out(vty, " mm info %u%s", gsmnet->send_mm_info, VTY_NEWLINE);
-	vty_out(vty, " handover %u%s", gsmnet->handover.active, VTY_NEWLINE);
-	vty_out(vty, " handover window rxlev averaging %u%s",
-		gsmnet->handover.win_rxlev_avg, VTY_NEWLINE);
-	vty_out(vty, " handover window rxqual averaging %u%s",
-		gsmnet->handover.win_rxqual_avg, VTY_NEWLINE);
-	vty_out(vty, " handover window rxlev neighbor averaging %u%s",
-		gsmnet->handover.win_rxlev_avg_neigh, VTY_NEWLINE);
-	vty_out(vty, " handover power budget interval %u%s",
-		gsmnet->handover.pwr_interval, VTY_NEWLINE);
-	vty_out(vty, " handover power budget hysteresis %u%s",
-		gsmnet->handover.pwr_hysteresis, VTY_NEWLINE);
-	vty_out(vty, " handover maximum distance %u%s",
-		gsmnet->handover.max_distance, VTY_NEWLINE);
+
+	ho_vty_write(vty, " ", gsmnet->ho);
+
 	VTY_OUT_TIMER(3101);
 	VTY_OUT_TIMER(3103);
 	VTY_OUT_TIMER(3105);
@@ -1491,100 +1504,6 @@
 
 	gsmnet->neci = atoi(argv[0]);
 	gsm_net_update_ctype(gsmnet);
-	return CMD_SUCCESS;
-}
-
-#define HANDOVER_STR	"Handover Options\n"
-
-DEFUN(cfg_net_handover, cfg_net_handover_cmd,
-      "handover (0|1)",
-	HANDOVER_STR
-	"Don't perform in-call handover\n"
-	"Perform in-call handover\n")
-{
-	int enable = atoi(argv[0]);
-	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-
-	if (enable && ipacc_rtp_direct) {
-		vty_out(vty, "%% Cannot enable handover unless RTP Proxy mode "
-			"is enabled by using the -P command line option%s",
-			VTY_NEWLINE);
-		return CMD_WARNING;
-	}
-	gsmnet->handover.active = enable;
-
-	return CMD_SUCCESS;
-}
-
-#define HO_WIN_STR HANDOVER_STR "Measurement Window\n"
-#define HO_WIN_RXLEV_STR HO_WIN_STR "Received Level Averaging\n"
-#define HO_WIN_RXQUAL_STR HO_WIN_STR "Received Quality Averaging\n"
-#define HO_PBUDGET_STR HANDOVER_STR "Power Budget\n"
-#define HO_AVG_COUNT_STR "Amount to use for Averaging\n"
-
-DEFUN(cfg_net_ho_win_rxlev_avg, cfg_net_ho_win_rxlev_avg_cmd,
-      "handover window rxlev averaging <1-10>",
-	HO_WIN_RXLEV_STR
-	"How many RxLev measurements are used for averaging\n"
-	HO_AVG_COUNT_STR)
-{
-	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-	gsmnet->handover.win_rxlev_avg = atoi(argv[0]);
-	return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_ho_win_rxqual_avg, cfg_net_ho_win_rxqual_avg_cmd,
-      "handover window rxqual averaging <1-10>",
-	HO_WIN_RXQUAL_STR
-	"How many RxQual measurements are used for averaging\n"
-	HO_AVG_COUNT_STR)
-{
-	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-	gsmnet->handover.win_rxqual_avg = atoi(argv[0]);
-	return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_ho_win_rxlev_neigh_avg, cfg_net_ho_win_rxlev_avg_neigh_cmd,
-      "handover window rxlev neighbor averaging <1-10>",
-	HO_WIN_RXLEV_STR "Neighbor\n"
-	"How many RxQual measurements are used for averaging\n"
-	HO_AVG_COUNT_STR)
-{
-	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-	gsmnet->handover.win_rxlev_avg_neigh = atoi(argv[0]);
-	return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_ho_pwr_interval, cfg_net_ho_pwr_interval_cmd,
-      "handover power budget interval <1-99>",
-	HO_PBUDGET_STR
-	"How often to check if we have a better cell (SACCH frames)\n"
-	"Interval\n" "Number\n")
-{
-	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-	gsmnet->handover.pwr_interval = atoi(argv[0]);
-	return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_ho_pwr_hysteresis, cfg_net_ho_pwr_hysteresis_cmd,
-      "handover power budget hysteresis <0-999>",
-	HO_PBUDGET_STR
-	"How many dB does a neighbor to be stronger to become a HO candidate\n"
-	"Hysteresis\n" "Number\n")
-{
-	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-	gsmnet->handover.pwr_hysteresis = atoi(argv[0]);
-	return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_ho_max_distance, cfg_net_ho_max_distance_cmd,
-      "handover maximum distance <0-9999>",
-	HANDOVER_STR
-	"How big is the maximum timing advance before HO is forced\n"
-	"Distance\n" "Number\n")
-{
-	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-	gsmnet->handover.max_distance = atoi(argv[0]);
 	return CMD_SUCCESS;
 }
 
@@ -4241,13 +4160,6 @@
 	logging_vty_add_cmds(NULL);
 
 	install_element(GSMNET_NODE, &cfg_net_neci_cmd);
-	install_element(GSMNET_NODE, &cfg_net_handover_cmd);
-	install_element(GSMNET_NODE, &cfg_net_ho_win_rxlev_avg_cmd);
-	install_element(GSMNET_NODE, &cfg_net_ho_win_rxqual_avg_cmd);
-	install_element(GSMNET_NODE, &cfg_net_ho_win_rxlev_avg_neigh_cmd);
-	install_element(GSMNET_NODE, &cfg_net_ho_pwr_interval_cmd);
-	install_element(GSMNET_NODE, &cfg_net_ho_pwr_hysteresis_cmd);
-	install_element(GSMNET_NODE, &cfg_net_ho_max_distance_cmd);
 	install_element(GSMNET_NODE, &cfg_net_T3101_cmd);
 	install_element(GSMNET_NODE, &cfg_net_T3103_cmd);
 	install_element(GSMNET_NODE, &cfg_net_T3105_cmd);
@@ -4262,6 +4174,7 @@
 	install_element(GSMNET_NODE, &cfg_net_T3141_cmd);
 	install_element(GSMNET_NODE, &cfg_net_dtx_cmd);
 	install_element(GSMNET_NODE, &cfg_net_pag_any_tch_cmd);
+	/* See also handover commands added on net level from handover_vty.c */
 
 	install_element(GSMNET_NODE, &cfg_bts_cmd);
 	install_node(&bts_node, config_write_bts);
@@ -4367,6 +4280,7 @@
 	install_element(BTS_NODE, &cfg_bts_amr_hr_hyst3_cmd);
 	install_element(BTS_NODE, &cfg_bts_amr_hr_start_mode_cmd);
 	install_element(BTS_NODE, &cfg_bts_pcu_sock_cmd);
+	/* See also handover commands added on bts level from handover_vty.c */
 
 	install_element(BTS_NODE, &cfg_trx_cmd);
 	install_node(&trx_node, dummy_config_write);
@@ -4405,6 +4319,8 @@
 	e1inp_vty_init();
 	osmo_fsm_vty_add_cmds();
 
+	ho_vty_init();
+
 	bsc_vty_init_extra();
 
 	return 0;
diff --git a/src/libbsc/handover_decision.c b/src/libbsc/handover_decision.c
index 09c7eaa..a717653 100644
--- a/src/libbsc/handover_decision.c
+++ b/src/libbsc/handover_decision.c
@@ -30,8 +30,10 @@
 #include <osmocom/bsc/meas_rep.h>
 #include <osmocom/bsc/signal.h>
 #include <osmocom/core/talloc.h>
-#include <osmocom/bsc/handover.h>
 #include <osmocom/gsm/gsm_utils.h>
+
+#include <osmocom/bsc/handover.h>
+#include <osmocom/bsc/handover_cfg.h>
 
 /* Get reference to a neighbor cell on a given BCCH ARFCN */
 static struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts,
@@ -187,7 +189,7 @@
 /* attempt to do a handover */
 static int attempt_handover(struct gsm_meas_rep *mr)
 {
-	struct gsm_network *net = mr->lchan->ts->trx->bts->network;
+	struct gsm_bts *bts = mr->lchan->ts->trx->bts;
 	struct neigh_meas_proc *best_cell = NULL;
 	unsigned int best_better_db = 0;
 	int i, rc;
@@ -204,10 +206,10 @@
 			continue;
 
 		/* caculate average rxlev for this cell over the window */
-		avg = neigh_meas_avg(nmp, net->handover.win_rxlev_avg_neigh);
+		avg = neigh_meas_avg(nmp, ho_get_win_rxlev_avg_neigh(bts->ho));
 
 		/* check if hysteresis is fulfilled */
-		if (avg < mr->dl.full.rx_lev + net->handover.pwr_hysteresis)
+		if (avg < mr->dl.full.rx_lev + ho_get_pwr_hysteresis(bts->ho))
 			continue;
 
 		better = avg - mr->dl.full.rx_lev;
@@ -222,7 +224,7 @@
 
 	LOGP(DHO, LOGL_INFO, "%s: Cell on ARFCN %u is better: ",
 		gsm_ts_name(mr->lchan->ts), best_cell->arfcn);
-	if (!net->handover.active) {
+	if (!ho_get_active(bts->ho)) {
 		LOGPC(DHO, LOGL_INFO, "Skipping, Handover disabled\n");
 		return 0;
 	}
@@ -248,7 +250,7 @@
  * attempt a handover */
 static int process_meas_rep(struct gsm_meas_rep *mr)
 {
-	struct gsm_network *net = mr->lchan->ts->trx->bts->network;
+	struct gsm_bts *bts = mr->lchan->ts->trx->bts;
 	enum meas_rep_field dlev, dqual;
 	int av_rxlev;
 
@@ -274,7 +276,7 @@
 		process_meas_neigh(mr);
 
 	av_rxlev = get_meas_rep_avg(mr->lchan, dlev,
-				    net->handover.win_rxlev_avg);
+				    ho_get_win_rxlev_avg(bts->ho));
 
 	/* Interference HO */
 	if (rxlev2dbm(av_rxlev) > -85 &&
@@ -290,11 +292,11 @@
 		return attempt_handover(mr);
 
 	/* Distance */
-	if (mr->ms_l1.ta > net->handover.max_distance)
+	if (mr->ms_l1.ta > ho_get_max_distance(bts->ho))
 		return attempt_handover(mr);
 
 	/* Power Budget AKA Better Cell */
-	if ((mr->nr % net->handover.pwr_interval) == 0)
+	if ((mr->nr % ho_get_pwr_interval(bts->ho)) == 0)
 		return attempt_handover(mr);
 
 	return 0;
diff --git a/src/libbsc/handover_vty.c b/src/libbsc/handover_vty.c
new file mode 100644
index 0000000..fb37edc
--- /dev/null
+++ b/src/libbsc/handover_vty.c
@@ -0,0 +1,152 @@
+/* OsmoBSC interface to quagga VTY for handover parameters */
+/* (C) 2017 by sysmocom - s.f.m.c. GmbH <info at sysmocom.de>
+ * (C) 2009-2010 by Harald Welte <laforge at gnumonks.org>
+ * All Rights Reserved
+ *
+ * Author: Neels Hofmeyr <nhofmeyr at sysmocom.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <osmocom/bsc/gsm_data.h>
+#include <osmocom/bsc/vty.h>
+#include <osmocom/bsc/handover_cfg.h>
+
+static struct handover_cfg *ho_cfg_from_vty(struct vty *vty)
+{
+	switch (vty->node) {
+	case GSMNET_NODE:
+		return gsmnet_from_vty(vty)->ho;
+	case BTS_NODE:
+		OSMO_ASSERT(vty->index);
+		return ((struct gsm_bts *)vty->index)->ho;
+	default:
+		OSMO_ASSERT(false);
+	}
+}
+
+#define HANDOVER_STR "Handover options\n"
+#define HO_WIN_STR HANDOVER_STR "Measurement averaging settings\n"
+#define HO_WIN_RXLEV_STR HO_WIN_STR "Received-Level averaging\n"
+#define HO_WIN_RXQUAL_STR HO_WIN_STR "Received-Quality averaging\n"
+#define HO_POWER_BUDGET_STR HANDOVER_STR "Neighbor cell power triggering\n" "Neighbor cell power triggering\n"
+#define HO_AVG_COUNT_STR "Number of values to average over\n"
+#define DEFAULT_STR "Use default, remove explicit setting on this node\n"
+
+#define HO_COMMON_VTY(NAME, CMDSTR, DOCSTR) \
+DEFUN(cfg_ho_##NAME, cfg_ho_##NAME##_cmd, \
+      CMDSTR, DOCSTR) \
+{ \
+	struct handover_cfg *ho = ho_cfg_from_vty(vty); \
+	const char *val = argv[0]; \
+	if (!strcmp(val, "default")) \
+		ho_clear_##NAME(ho); \
+	else \
+		ho_set_##NAME(ho, atoi(val)); \
+	return CMD_SUCCESS; \
+}
+
+HO_COMMON_VTY(active,
+	      "handover (0|1|default)",
+	      HANDOVER_STR
+	      "Disable in-call handover\n"
+	      "Enable in-call handover\n"
+	      "Enable/Disable HO: " DEFAULT_STR)
+
+HO_COMMON_VTY(win_rxlev_avg,
+	      "handover window rxlev averaging (<1-10>|default)",
+	      HO_WIN_RXLEV_STR
+	      "How many RxLev measurements are used for averaging\n"
+	      "RxLev averaging: " HO_AVG_COUNT_STR
+	      DEFAULT_STR)
+
+HO_COMMON_VTY(win_rxqual_avg,
+	      "handover window rxqual averaging (<1-10>|default)",
+	      HO_WIN_RXQUAL_STR
+	      "How many RxQual measurements are used for averaging\n"
+	      "RxQual averaging: " HO_AVG_COUNT_STR
+	      DEFAULT_STR)
+
+HO_COMMON_VTY(win_rxlev_avg_neigh,
+	      "handover window rxlev neighbor averaging (<1-10>|default)",
+	      HO_WIN_RXLEV_STR
+	      "How many Neighbor RxLev measurements are used for averaging\n"
+	      "How many Neighbor RxLev measurements are used for averaging\n"
+	      "Neighbor RxLev averaging: " HO_AVG_COUNT_STR
+	      DEFAULT_STR)
+
+HO_COMMON_VTY(pwr_interval,
+	      "handover power budget interval (<1-99>|default)",
+	      HO_POWER_BUDGET_STR
+	      "How often to check for a better cell (SACCH frames)\n"
+	      "Check for stronger neighbor every N number of SACCH frames\n"
+	      DEFAULT_STR)
+
+HO_COMMON_VTY(pwr_hysteresis,
+	      "handover power budget hysteresis (<0-999>|default)",
+	      HO_POWER_BUDGET_STR
+	      "How many dBm stronger must a neighbor be to become a HO candidate\n"
+	      "Neighbor's strength difference in dBm\n"
+	      DEFAULT_STR)
+
+HO_COMMON_VTY(max_distance,
+	      "handover maximum distance (<0-9999>|default)",
+	      HANDOVER_STR
+	      "Timing-Advance (i.e. distance) triggering\n"
+	      "Timing-Advance (i.e. distance) triggering\n"
+	      "Maximum Timing-Advance value before forcing HO\n"
+	      DEFAULT_STR)
+
+void ho_vty_write(struct vty *vty, const char *indent, struct handover_cfg *ho)
+{
+	if (ho_isset_active(ho))
+		vty_out(vty, "%shandover %u%s", indent, ho_get_active(ho) ? 1 : 0, VTY_NEWLINE);
+	if (ho_isset_win_rxlev_avg(ho))
+		vty_out(vty, "%shandover window rxlev averaging %u%s",
+			indent, ho_get_win_rxlev_avg(ho), VTY_NEWLINE);
+	if (ho_isset_win_rxqual_avg(ho))
+		vty_out(vty, "%shandover window rxqual averaging %u%s",
+			indent, ho_get_win_rxqual_avg(ho), VTY_NEWLINE);
+	if (ho_isset_win_rxlev_avg_neigh(ho))
+		vty_out(vty, "%shandover window rxlev neighbor averaging %u%s",
+			indent, ho_get_win_rxlev_avg_neigh(ho), VTY_NEWLINE);
+	if (ho_isset_pwr_interval(ho))
+		vty_out(vty, "%shandover power budget interval %u%s",
+			indent, ho_get_pwr_interval(ho), VTY_NEWLINE);
+	if (ho_isset_pwr_hysteresis(ho))
+		vty_out(vty, "%shandover power budget hysteresis %u%s",
+			indent, ho_get_pwr_hysteresis(ho), VTY_NEWLINE);
+	if (ho_isset_max_distance(ho))
+		vty_out(vty, "%shandover maximum distance %u%s",
+			indent, ho_get_max_distance(ho), VTY_NEWLINE);
+}
+
+static void ho_vty_init_cmds(int parent_node)
+{
+	install_element(parent_node, &cfg_ho_active_cmd);
+	install_element(parent_node, &cfg_ho_win_rxlev_avg_cmd);
+	install_element(parent_node, &cfg_ho_win_rxqual_avg_cmd);
+	install_element(parent_node, &cfg_ho_win_rxlev_avg_neigh_cmd);
+	install_element(parent_node, &cfg_ho_pwr_interval_cmd);
+	install_element(parent_node, &cfg_ho_pwr_hysteresis_cmd);
+	install_element(parent_node, &cfg_ho_max_distance_cmd);
+}
+
+void ho_vty_init()
+{
+	ho_vty_init_cmds(GSMNET_NODE);
+	ho_vty_init_cmds(BTS_NODE);
+}
+
diff --git a/src/libbsc/net_init.c b/src/libbsc/net_init.c
index a71662c..3f05273 100644
--- a/src/libbsc/net_init.c
+++ b/src/libbsc/net_init.c
@@ -21,6 +21,7 @@
 #include <osmocom/bsc/osmo_bsc.h>
 #include <osmocom/bsc/bsc_msc_data.h>
 #include <osmocom/bsc/gsm_04_08_utils.h>
+#include <osmocom/bsc/handover_cfg.h>
 
 struct gsm_network *bsc_network_init(void *ctx,
 				     uint16_t country_code,
@@ -57,13 +58,7 @@
 	net->T3122 = GSM_T3122_DEFAULT;
 	net->T3141 = GSM_T3141_DEFAULT;
 
-	/* default set of handover parameters */
-	net->handover.win_rxlev_avg = 10;
-	net->handover.win_rxqual_avg = 1;
-	net->handover.win_rxlev_avg_neigh = 10;
-	net->handover.pwr_interval = 6;
-	net->handover.pwr_hysteresis = 3;
-	net->handover.max_distance = 9999;
+	net->ho = ho_cfg_init(net, NULL);
 
 	INIT_LLIST_HEAD(&net->bts_list);
 
diff --git a/src/libcommon/Makefile.am b/src/libcommon/Makefile.am
index 6cfebc2..d82b188 100644
--- a/src/libcommon/Makefile.am
+++ b/src/libcommon/Makefile.am
@@ -26,4 +26,5 @@
 	socket.c \
 	talloc_ctx.c \
 	gsm_subscriber_base.c \
+	handover_cfg.c \
 	$(NULL)
diff --git a/src/libcommon/gsm_data.c b/src/libcommon/gsm_data.c
index 6a78e3a..e38da14 100644
--- a/src/libcommon/gsm_data.c
+++ b/src/libcommon/gsm_data.c
@@ -37,6 +37,7 @@
 #include <osmocom/bsc/gsm_data.h>
 #include <osmocom/bsc/bsc_msc_data.h>
 #include <osmocom/bsc/abis_nm.h>
+#include <osmocom/bsc/handover_cfg.h>
 
 void *tall_bsc_ctx;
 
diff --git a/src/libcommon/gsm_data_shared.c b/src/libcommon/gsm_data_shared.c
index e4ae339..69230bc 100644
--- a/src/libcommon/gsm_data_shared.c
+++ b/src/libcommon/gsm_data_shared.c
@@ -33,6 +33,7 @@
 #include <osmocom/core/statistics.h>
 
 #include <osmocom/bsc/gsm_data.h>
+#include <osmocom/bsc/handover_cfg.h>
 
 void gsm_abis_mo_reset(struct gsm_abis_mo *mo)
 {
@@ -363,6 +364,8 @@
 	/* si handling */
 	bts->bcch_change_mark = 1;
 
+	bts->ho = ho_cfg_init(bts, net->ho);
+
 	return bts;
 }
 
diff --git a/src/libcommon/handover_cfg.c b/src/libcommon/handover_cfg.c
new file mode 100644
index 0000000..e36a738
--- /dev/null
+++ b/src/libcommon/handover_cfg.c
@@ -0,0 +1,93 @@
+/* OsmoBSC handover configuration implementation */
+/* (C) 2017 by sysmocom - s.f.m.c. GmbH <info at sysmocom.de>
+ * (C) 2009-2010 by Harald Welte <laforge at gnumonks.org>
+ * All Rights Reserved
+ *
+ * Author: Neels Hofmeyr <nhofmeyr at sysmocom.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdbool.h>
+#include <talloc.h>
+
+#include <osmocom/bsc/vty.h>
+#include <osmocom/bsc/handover_cfg.h>
+#include <osmocom/bsc/gsm_data.h>
+
+struct handover_cfg {
+	struct handover_cfg *higher_level_cfg;
+
+	bool has_active;
+	bool active;
+
+	/* Window parameters in number of SACCH frames */
+	bool has_win_rxlev_avg;
+	unsigned int win_rxlev_avg;
+	bool has_win_rxqual_avg;
+	unsigned int win_rxqual_avg;
+	bool has_win_rxlev_avg_neigh;
+	unsigned int win_rxlev_avg_neigh;
+
+	/* how often should we check for power budget HO */
+	bool has_pwr_interval;
+	unsigned int pwr_interval;	/* SACCH frames */
+	bool has_pwr_hysteresis;
+	unsigned int pwr_hysteresis;	/* dBm */
+	bool has_max_distance;
+	unsigned int max_distance;	/* TA values */
+};
+
+struct handover_cfg *ho_cfg_init(void *ctx, struct handover_cfg *higher_level_cfg)
+{
+	struct handover_cfg *ho = talloc_zero(ctx, struct handover_cfg);
+	OSMO_ASSERT(ho);
+	ho->higher_level_cfg = higher_level_cfg;
+	return ho;
+}
+
+#define HO_GETTER_SETTER_DEFS(TYPE, NAME, DEFAULT_VAL) \
+TYPE ho_get_##NAME(struct handover_cfg *ho) \
+{ \
+	if (ho->has_##NAME) \
+		return ho->NAME; \
+	if (ho->higher_level_cfg) \
+		return ho_get_##NAME(ho->higher_level_cfg); \
+	return DEFAULT_VAL; \
+} \
+\
+void ho_set_##NAME(struct handover_cfg *ho, TYPE value) \
+{ \
+	ho->NAME = value; \
+	ho->has_##NAME = true; \
+} \
+\
+bool ho_isset_##NAME(struct handover_cfg *ho) \
+{ \
+	return ho->has_##NAME; \
+} \
+\
+void ho_clear_##NAME(struct handover_cfg *ho) \
+{ \
+	ho->has_##NAME = false; \
+}
+
+HO_GETTER_SETTER_DEFS(bool, active, false)
+HO_GETTER_SETTER_DEFS(unsigned int, win_rxlev_avg, 10)
+HO_GETTER_SETTER_DEFS(unsigned int, win_rxqual_avg, 1)
+HO_GETTER_SETTER_DEFS(unsigned int, win_rxlev_avg_neigh, 10)
+HO_GETTER_SETTER_DEFS(unsigned int, pwr_interval, 6)
+HO_GETTER_SETTER_DEFS(unsigned int, pwr_hysteresis, 3)
+HO_GETTER_SETTER_DEFS(unsigned int, max_distance, 9999)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 7b4656b..d4390af 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -35,6 +35,7 @@
 	$(TESTSUITE) \
 	vty_test_runner.py \
 	ctrl_test_runner.py \
+	handover_cfg.vty \
 	$(NULL)
 
 TESTSUITE = $(srcdir)/testsuite
@@ -45,11 +46,21 @@
 
 if ENABLE_EXT_TESTS
 python-tests: $(BUILT_SOURCES)
+	$(MAKE) vty-test
 	osmotestvty.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
 	osmotestconfig.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v
 	$(srcdir)/vty_test_runner.py -w $(abs_top_builddir) -v
 	$(srcdir)/ctrl_test_runner.py -w $(abs_top_builddir) -v
 	rm -f $(top_builddir)/sms.db $(top_builddir)/gsn_restart $(top_builddir)/gtphub_restart_count
+
+# To update the VTY script from current application behavior,
+# pass -u to vty_script_runner.py by doing:
+#   make vty-test U=-u
+vty-test:
+	osmo_verify_transcript_vty.py -v \
+		-n OsmoBSC -p 4242 \
+		-r "$(top_builddir)/src/osmo-bsc/osmo-bsc -c $(top_srcdir)/doc/examples/osmo-bsc/osmo-bsc-minimal.cfg" \
+		$(U) $(srcdir)/*.vty
 else
 python-tests: $(BUILT_SOURCES)
 	echo "Not running python-based tests (determined at configure-time)"
diff --git a/tests/handover_cfg.vty b/tests/handover_cfg.vty
new file mode 100644
index 0000000..b65d5ae
--- /dev/null
+++ b/tests/handover_cfg.vty
@@ -0,0 +1,273 @@
+OsmoBSC> show network
+...
+  Handover: Off
+...
+OsmoBSC> enable
+
+OsmoBSC# ### No handover config present
+OsmoBSC# show running-config
+... !handover
+
+OsmoBSC# ### Toggling handover on network level affects 'show network':
+OsmoBSC# configure terminal
+OsmoBSC(config)# network
+OsmoBSC(config-net)# do show network
+...
+  Handover: Off
+...
+OsmoBSC(config-net)# handover 1
+OsmoBSC(config-net)# do show network
+...
+  Handover: On
+...
+
+OsmoBSC(config-net)# ### If network level default is 'on', bts level can still override to 'off':
+OsmoBSC(config-net)# bts 0
+OsmoBSC(config-net-bts)# handover 0
+OsmoBSC(config-net-bts)# do show network
+...
+  Handover: Off
+...
+OsmoBSC(config-net-bts)# exit
+
+OsmoBSC(config-net)# ### Create a *second* BTS that is not explicitly 'off':
+OsmoBSC(config-net)# bts 1
+OsmoBSC(config-net-bts)# do show network
+...
+  Handover: On at 1 BTS, Off at 1 BTS
+...
+
+OsmoBSC(config-net-bts)# ### Add arbitrary handover config item for bts 1:
+OsmoBSC(config-net-bts)# handover power budget interval 23
+OsmoBSC(config-net-bts)# exit
+OsmoBSC(config-net)# ### HO is 'on' globally, bts 0 disables it, bts 1 tweaks a param:
+OsmoBSC(config-net)# show running-config
+...
+network
+...
+ handover 1
+...
+ bts 0
+...
+  handover 0
+...
+ bts 1
+...
+  handover power budget interval 23
+...
+
+OsmoBSC(config-net)# ### Set global default to 'off', now bts 1 also uses the global default of 'off':
+OsmoBSC(config-net)# handover 0
+OsmoBSC(config-net)# do show network
+...
+  Handover: Off
+...
+OsmoBSC(config-net)# show running-config
+...
+network
+...
+ handover 0
+...
+ bts 0
+...
+  handover 0
+...
+ bts 1
+...
+  handover power budget interval 23
+...
+
+OsmoBSC(config-net)# ### Remove the global setting, i.e. use the factory default net level, with same effect:
+OsmoBSC(config-net)# handover default
+OsmoBSC(config-net)# do show network
+...
+  Handover: Off
+...
+OsmoBSC(config-net)# show running-config
+...
+network
+... !handover
+ bts 0
+...
+  handover 0
+...
+ bts 1
+...
+  handover power budget interval 23
+...
+
+OsmoBSC(config-net)# ### Re-enable net-level handover, but bts 0 remains disabled explicitly
+OsmoBSC(config-net)# handover 1
+OsmoBSC(config-net)# do show network
+...
+  Handover: On at 1 BTS, Off at 1 BTS
+...
+OsmoBSC(config-net)# show running-config
+...
+network
+...
+ handover 1
+...
+ bts 0
+...
+  handover 0
+...
+ bts 1
+...
+  handover power budget interval 23
+...
+
+OsmoBSC(config-net)# ### Remove explicit setting of bts 0 to also use the global setting:
+OsmoBSC(config-net)# bts 0
+OsmoBSC(config-net-bts)# handover default
+OsmoBSC(config-net-bts)# do show network
+...
+  Handover: On
+...
+OsmoBSC(config-net-bts)# show running-config
+...
+network
+...
+ handover 1
+...
+ bts 0
+... !handover
+ bts 1
+...
+  handover power budget interval 23
+...
+
+
+OsmoBSC(config-net-bts)# ### Checking online help
+OsmoBSC(config-net-bts)# exit
+OsmoBSC(config-net)# list
+...
+  handover (0|1|default)
+  handover window rxlev averaging (<1-10>|default)
+  handover window rxqual averaging (<1-10>|default)
+  handover window rxlev neighbor averaging (<1-10>|default)
+  handover power budget interval (<1-99>|default)
+  handover power budget hysteresis (<0-999>|default)
+  handover maximum distance (<0-9999>|default)
+...
+
+OsmoBSC(config-net)# handover?
+  handover  Handover options
+
+OsmoBSC(config-net)# handover ?
+  0        Disable in-call handover
+  1        Enable in-call handover
+  default  Enable/Disable HO: Use default, remove explicit setting on this node
+  window   Measurement averaging settings
+  power    Neighbor cell power triggering
+  maximum  Timing-Advance (i.e. distance) triggering
+
+OsmoBSC(config-net)# handover window ?
+  rxlev   Received-Level averaging
+  rxqual  Received-Quality averaging
+
+OsmoBSC(config-net)# handover window rxlev ?
+  averaging  How many RxLev measurements are used for averaging
+  neighbor   How many Neighbor RxLev measurements are used for averaging
+
+OsmoBSC(config-net)# handover window rxlev averaging ?
+  <1-10>   RxLev averaging: Number of values to average over
+  default  Use default, remove explicit setting on this node
+
+OsmoBSC(config-net)# handover window rxlev neighbor ?
+  averaging  How many Neighbor RxLev measurements are used for averaging
+
+OsmoBSC(config-net)# handover window rxlev neighbor averaging ?
+  <1-10>   Neighbor RxLev averaging: Number of values to average over
+  default  Use default, remove explicit setting on this node
+
+OsmoBSC(config-net)# handover window rxqual ?
+  averaging  How many RxQual measurements are used for averaging
+
+OsmoBSC(config-net)# handover window rxqual averaging ?
+  <1-10>   RxQual averaging: Number of values to average over
+  default  Use default, remove explicit setting on this node
+
+OsmoBSC(config-net)# handover power ?
+  budget  Neighbor cell power triggering
+
+OsmoBSC(config-net)# handover power budget ?
+  interval    How often to check for a better cell (SACCH frames)
+  hysteresis  How many dBm stronger must a neighbor be to become a HO candidate
+
+OsmoBSC(config-net)# handover power budget interval ?
+  <1-99>   Check for stronger neighbor every N number of SACCH frames
+  default  Use default, remove explicit setting on this node
+
+OsmoBSC(config-net)# handover power budget hysteresis ?
+  <0-999>  Neighbor's strength difference in dBm
+  default  Use default, remove explicit setting on this node
+
+OsmoBSC(config-net)# handover maximum ?
+  distance  Timing-Advance (i.e. distance) triggering
+
+OsmoBSC(config-net)# handover maximum distance ?
+  <0-9999>  Maximum Timing-Advance value before forcing HO
+  default   Use default, remove explicit setting on this node
+
+
+OsmoBSC(config-net)# ### Same on BTS level
+OsmoBSC(config-net)# bts 0
+OsmoBSC(config-net-bts)# handover?
+  handover  Handover options
+
+OsmoBSC(config-net-bts)# handover ?
+  0        Disable in-call handover
+  1        Enable in-call handover
+  default  Enable/Disable HO: Use default, remove explicit setting on this node
+  window   Measurement averaging settings
+  power    Neighbor cell power triggering
+  maximum  Timing-Advance (i.e. distance) triggering
+
+OsmoBSC(config-net-bts)# handover window ?
+  rxlev   Received-Level averaging
+  rxqual  Received-Quality averaging
+
+OsmoBSC(config-net-bts)# handover window rxlev ?
+  averaging  How many RxLev measurements are used for averaging
+  neighbor   How many Neighbor RxLev measurements are used for averaging
+
+OsmoBSC(config-net-bts)# handover window rxlev averaging ?
+  <1-10>   RxLev averaging: Number of values to average over
+  default  Use default, remove explicit setting on this node
+
+OsmoBSC(config-net-bts)# handover window rxlev neighbor ?
+  averaging  How many Neighbor RxLev measurements are used for averaging
+
+OsmoBSC(config-net-bts)# handover window rxlev neighbor averaging ?
+  <1-10>   Neighbor RxLev averaging: Number of values to average over
+  default  Use default, remove explicit setting on this node
+
+OsmoBSC(config-net-bts)# handover window rxqual ?
+  averaging  How many RxQual measurements are used for averaging
+
+OsmoBSC(config-net-bts)# handover window rxqual averaging ?
+  <1-10>   RxQual averaging: Number of values to average over
+  default  Use default, remove explicit setting on this node
+
+OsmoBSC(config-net-bts)# handover power ?
+  budget  Neighbor cell power triggering
+
+OsmoBSC(config-net-bts)# handover power budget ?
+  interval    How often to check for a better cell (SACCH frames)
+  hysteresis  How many dBm stronger must a neighbor be to become a HO candidate
+
+OsmoBSC(config-net-bts)# handover power budget interval ?
+  <1-99>   Check for stronger neighbor every N number of SACCH frames
+  default  Use default, remove explicit setting on this node
+
+OsmoBSC(config-net-bts)# handover power budget hysteresis ?
+  <0-999>  Neighbor's strength difference in dBm
+  default  Use default, remove explicit setting on this node
+
+OsmoBSC(config-net-bts)# handover maximum ?
+  distance  Timing-Advance (i.e. distance) triggering
+
+OsmoBSC(config-net-bts)# handover maximum distance ?
+  <0-9999>  Maximum Timing-Advance value before forcing HO
+  default   Use default, remove explicit setting on this node

-- 
To view, visit https://gerrit.osmocom.org/5050
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newpatchset
Gerrit-Change-Id: I00870a5828703cf397776668d3301c0c3a4e033a
Gerrit-PatchSet: 7
Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Owner: Neels Hofmeyr <nhofmeyr at sysmocom.de>
Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: Neels Hofmeyr <nhofmeyr at sysmocom.de>



More information about the gerrit-log mailing list