Move timezone settings up to network level

Time zone used to be configurable per-BTS. In the upcoming MSC-split, no BTS
structures will be available on the MSC level. To simplify, drop the ability to
manage several time zones in a core network and place the time zone config on
the network VTY level, i.e. in gsm_network. If we are going to re-add fine
grained time zone settings, it should probably be tied to the LAC.

Adjust time zone VTY config code (to be moved to libcommon-cs in subsequent commit).

Adjust time zone Ctrl Interface code.

Change-Id: I69848887d92990f3d6f969be80f6ef91f6bdbbe8
This commit is contained in:
Neels Hofmeyr 2016-05-10 13:29:33 +02:00 committed by Harald Welte
parent 1a60644eb2
commit 7398395cc0
9 changed files with 98 additions and 99 deletions

View File

@ -273,6 +273,13 @@ enum gsm_auth_policy {
#define GSM_T3113_DEFAULT 60 #define GSM_T3113_DEFAULT 60
#define GSM_T3122_DEFAULT 10 #define GSM_T3122_DEFAULT 10
struct gsm_tz {
int override; /* if 0, use system's time zone instead. */
int hr; /* hour */
int mn; /* minute */
int dst; /* daylight savings */
};
struct gsm_network { struct gsm_network {
/* global parameters */ /* global parameters */
uint16_t country_code; uint16_t country_code;
@ -367,6 +374,13 @@ struct gsm_network {
/* all active subscriber connections. */ /* all active subscriber connections. */
struct llist_head subscr_conns; struct llist_head subscr_conns;
/* if override is nonzero, this timezone data is used for all MM
* contexts. */
/* TODO: in OsmoNITB, tz-override used to be BTS-specific. To enable
* BTS|RNC specific timezone overrides for multi-tz networks in
* OsmoCSCN, this should be tied to the location area code (LAC). */
struct gsm_tz tz;
}; };
struct osmo_esme; struct osmo_esme;

View File

@ -679,14 +679,6 @@ struct gsm_bts {
/* buffers where we put the pre-computed SI */ /* buffers where we put the pre-computed SI */
sysinfo_buf_t si_buf[_MAX_SYSINFO_TYPE]; sysinfo_buf_t si_buf[_MAX_SYSINFO_TYPE];
/* TimeZone hours, mins, and bts specific */
struct {
int hr;
int mn;
int override;
int dst;
} tz;
/* ip.accesss Unit ID's have Site/BTS/TRX layout */ /* ip.accesss Unit ID's have Site/BTS/TRX layout */
union { union {
struct { struct {

View File

@ -554,14 +554,6 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
if (bts->dtxd) if (bts->dtxd)
vty_out(vty, " dtx downlink%s", VTY_NEWLINE); vty_out(vty, " dtx downlink%s", VTY_NEWLINE);
vty_out(vty, " base_station_id_code %u%s", bts->bsic, VTY_NEWLINE); vty_out(vty, " base_station_id_code %u%s", bts->bsic, VTY_NEWLINE);
if (bts->tz.override != 0) {
if (bts->tz.dst)
vty_out(vty, " timezone %d %d %d%s",
bts->tz.hr, bts->tz.mn, bts->tz.dst, VTY_NEWLINE);
else
vty_out(vty, " timezone %d %d%s",
bts->tz.hr, bts->tz.mn, VTY_NEWLINE);
}
vty_out(vty, " ms max power %u%s", bts->ms_max_power, VTY_NEWLINE); vty_out(vty, " ms max power %u%s", bts->ms_max_power, VTY_NEWLINE);
vty_out(vty, " cell reselection hysteresis %u%s", vty_out(vty, " cell reselection hysteresis %u%s",
bts->si_common.cell_sel_par.cell_resel_hyst*2, VTY_NEWLINE); bts->si_common.cell_sel_par.cell_resel_hyst*2, VTY_NEWLINE);
@ -817,6 +809,15 @@ static int config_write_net(struct vty *vty)
vty_out(vty, " timer t3141 %u%s", gsmnet->T3141, VTY_NEWLINE); vty_out(vty, " timer t3141 %u%s", gsmnet->T3141, VTY_NEWLINE);
vty_out(vty, " subscriber-keep-in-ram %d%s", vty_out(vty, " subscriber-keep-in-ram %d%s",
gsmnet->subscr_group->keep_subscr, VTY_NEWLINE); gsmnet->subscr_group->keep_subscr, VTY_NEWLINE);
if (gsmnet->tz.override != 0) {
if (gsmnet->tz.dst)
vty_out(vty, " timezone %d %d %d%s",
gsmnet->tz.hr, gsmnet->tz.mn, gsmnet->tz.dst,
VTY_NEWLINE);
else
vty_out(vty, " timezone %d %d%s",
gsmnet->tz.hr, gsmnet->tz.mn, VTY_NEWLINE);
}
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -1735,10 +1736,10 @@ DEFUN(cfg_bts_bsic,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN(cfg_bts_timezone, DEFUN(cfg_net_timezone,
cfg_bts_timezone_cmd, cfg_net_timezone_cmd,
"timezone <-19-19> (0|15|30|45)", "timezone <-19-19> (0|15|30|45)",
"Set the Timezone Offset of this BTS\n" "Set the Timezone Offset of the network\n"
"Timezone offset (hours)\n" "Timezone offset (hours)\n"
"Timezone offset (00 minutes)\n" "Timezone offset (00 minutes)\n"
"Timezone offset (15 minutes)\n" "Timezone offset (15 minutes)\n"
@ -1746,22 +1747,22 @@ DEFUN(cfg_bts_timezone,
"Timezone offset (45 minutes)\n" "Timezone offset (45 minutes)\n"
) )
{ {
struct gsm_bts *bts = vty->index; struct gsm_network *net = vty->index;
int tzhr = atoi(argv[0]); int tzhr = atoi(argv[0]);
int tzmn = atoi(argv[1]); int tzmn = atoi(argv[1]);
bts->tz.hr = tzhr; net->tz.hr = tzhr;
bts->tz.mn = tzmn; net->tz.mn = tzmn;
bts->tz.dst = 0; net->tz.dst = 0;
bts->tz.override = 1; net->tz.override = 1;
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN(cfg_bts_timezone_dst, DEFUN(cfg_net_timezone_dst,
cfg_bts_timezone_dst_cmd, cfg_net_timezone_dst_cmd,
"timezone <-19-19> (0|15|30|45) <0-2>", "timezone <-19-19> (0|15|30|45) <0-2>",
"Set the Timezone Offset of this BTS\n" "Set the Timezone Offset of the network\n"
"Timezone offset (hours)\n" "Timezone offset (hours)\n"
"Timezone offset (00 minutes)\n" "Timezone offset (00 minutes)\n"
"Timezone offset (15 minutes)\n" "Timezone offset (15 minutes)\n"
@ -1770,28 +1771,28 @@ DEFUN(cfg_bts_timezone_dst,
"DST offset (hours)\n" "DST offset (hours)\n"
) )
{ {
struct gsm_bts *bts = vty->index; struct gsm_network *net = vty->index;
int tzhr = atoi(argv[0]); int tzhr = atoi(argv[0]);
int tzmn = atoi(argv[1]); int tzmn = atoi(argv[1]);
int tzdst = atoi(argv[2]); int tzdst = atoi(argv[2]);
bts->tz.hr = tzhr; net->tz.hr = tzhr;
bts->tz.mn = tzmn; net->tz.mn = tzmn;
bts->tz.dst = tzdst; net->tz.dst = tzdst;
bts->tz.override = 1; net->tz.override = 1;
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN(cfg_bts_no_timezone, DEFUN(cfg_net_no_timezone,
cfg_bts_no_timezone_cmd, cfg_net_no_timezone_cmd,
"no timezone", "no timezone",
NO_STR NO_STR
"Disable BTS specific timezone\n") "Disable network timezone override, use system tz\n")
{ {
struct gsm_bts *bts = vty->index; struct gsm_network *net = vty->index;
bts->tz.override = 0; net->tz.override = 0;
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -3949,6 +3950,9 @@ int bsc_vty_init(const struct log_info *cat, struct gsm_network *network)
install_element(GSMNET_NODE, &cfg_net_T3141_cmd); install_element(GSMNET_NODE, &cfg_net_T3141_cmd);
install_element(GSMNET_NODE, &cfg_net_dtx_cmd); install_element(GSMNET_NODE, &cfg_net_dtx_cmd);
install_element(GSMNET_NODE, &cfg_net_pag_any_tch_cmd); install_element(GSMNET_NODE, &cfg_net_pag_any_tch_cmd);
install_element(GSMNET_NODE, &cfg_net_timezone_cmd);
install_element(GSMNET_NODE, &cfg_net_timezone_dst_cmd);
install_element(GSMNET_NODE, &cfg_net_no_timezone_cmd);
install_element(GSMNET_NODE, &cfg_bts_cmd); install_element(GSMNET_NODE, &cfg_bts_cmd);
install_node(&bts_node, config_write_bts); install_node(&bts_node, config_write_bts);
@ -3967,9 +3971,6 @@ int bsc_vty_init(const struct log_info *cat, struct gsm_network *network)
install_element(BTS_NODE, &cfg_bts_bsic_cmd); install_element(BTS_NODE, &cfg_bts_bsic_cmd);
install_element(BTS_NODE, &cfg_bts_unit_id_cmd); install_element(BTS_NODE, &cfg_bts_unit_id_cmd);
install_element(BTS_NODE, &cfg_bts_rsl_ip_cmd); install_element(BTS_NODE, &cfg_bts_rsl_ip_cmd);
install_element(BTS_NODE, &cfg_bts_timezone_cmd);
install_element(BTS_NODE, &cfg_bts_timezone_dst_cmd);
install_element(BTS_NODE, &cfg_bts_no_timezone_cmd);
install_element(BTS_NODE, &cfg_bts_nokia_site_skip_reset_cmd); install_element(BTS_NODE, &cfg_bts_nokia_site_skip_reset_cmd);
install_element(BTS_NODE, &cfg_bts_nokia_site_no_loc_rel_cnf_cmd); install_element(BTS_NODE, &cfg_bts_nokia_site_no_loc_rel_cnf_cmd);
install_element(BTS_NODE, &cfg_bts_nokia_site_bts_reset_timer_cnf_cmd); install_element(BTS_NODE, &cfg_bts_nokia_site_bts_reset_timer_cnf_cmd);

View File

@ -733,7 +733,6 @@ int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn)
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 MM INF"); struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 MM INF");
struct gsm48_hdr *gh; struct gsm48_hdr *gh;
struct gsm_network *net = conn->network; struct gsm_network *net = conn->network;
struct gsm_bts *bts = conn->bts;
uint8_t *ptr8; uint8_t *ptr8;
int name_len, name_pad; int name_len, name_pad;
@ -821,23 +820,23 @@ int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn)
ptr8[5] = bcdify(gmt_time->tm_min); ptr8[5] = bcdify(gmt_time->tm_min);
ptr8[6] = bcdify(gmt_time->tm_sec); ptr8[6] = bcdify(gmt_time->tm_sec);
if (bts->tz.override) { if (net->tz.override) {
/* Convert tz.hr and tz.mn to units */ /* Convert tz.hr and tz.mn to units */
if (bts->tz.hr < 0) { if (net->tz.hr < 0) {
tzunits = ((bts->tz.hr/-1)*4); tzunits = ((net->tz.hr/-1)*4);
tzunits = tzunits + (bts->tz.mn/15); tzunits = tzunits + (net->tz.mn/15);
ptr8[7] = bcdify(tzunits); ptr8[7] = bcdify(tzunits);
/* Set negative time */ /* Set negative time */
ptr8[7] |= 0x08; ptr8[7] |= 0x08;
} }
else { else {
tzunits = bts->tz.hr*4; tzunits = net->tz.hr*4;
tzunits = tzunits + (bts->tz.mn/15); tzunits = tzunits + (net->tz.mn/15);
ptr8[7] = bcdify(tzunits); ptr8[7] = bcdify(tzunits);
} }
/* Convert DST value */ /* Convert DST value */
if (bts->tz.dst >= 0 && bts->tz.dst <= 2) if (net->tz.dst >= 0 && net->tz.dst <= 2)
dst = bts->tz.dst; dst = net->tz.dst;
} }
else { else {
/* Need to get GSM offset and convert into 15 min units */ /* Need to get GSM offset and convert into 15 min units */

View File

@ -362,18 +362,15 @@ err:
return 1; return 1;
} }
CTRL_CMD_DEFINE(bts_timezone, "timezone"); CTRL_CMD_DEFINE(net_timezone, "timezone");
static int get_bts_timezone(struct ctrl_cmd *cmd, void *data) static int get_net_timezone(struct ctrl_cmd *cmd, void *data)
{ {
struct gsm_bts *bts = (struct gsm_bts *) cmd->node; struct gsm_network *net = (struct gsm_network*)cmd->node;
if (!bts) {
cmd->reply = "bts not found.";
return CTRL_CMD_ERROR;
}
if (bts->tz.override) struct gsm_tz *tz = &net->tz;
if (tz->override)
cmd->reply = talloc_asprintf(cmd, "%d,%d,%d", cmd->reply = talloc_asprintf(cmd, "%d,%d,%d",
bts->tz.hr, bts->tz.mn, bts->tz.dst); tz->hr, tz->mn, tz->dst);
else else
cmd->reply = talloc_asprintf(cmd, "off"); cmd->reply = talloc_asprintf(cmd, "off");
@ -385,16 +382,11 @@ static int get_bts_timezone(struct ctrl_cmd *cmd, void *data)
return CTRL_CMD_REPLY; return CTRL_CMD_REPLY;
} }
static int set_bts_timezone(struct ctrl_cmd *cmd, void *data) static int set_net_timezone(struct ctrl_cmd *cmd, void *data)
{ {
char *saveptr, *hourstr, *minstr, *dststr, *tmp = 0; char *saveptr, *hourstr, *minstr, *dststr, *tmp = 0;
int override; int override;
struct gsm_bts *bts = (struct gsm_bts *) cmd->node; struct gsm_network *net = (struct gsm_network*)cmd->node;
if (!bts) {
cmd->reply = "bts not found.";
return CTRL_CMD_ERROR;
}
tmp = talloc_strdup(cmd, cmd->value); tmp = talloc_strdup(cmd, cmd->value);
if (!tmp) if (!tmp)
@ -409,25 +401,26 @@ static int set_bts_timezone(struct ctrl_cmd *cmd, void *data)
if (hourstr != NULL) if (hourstr != NULL)
override = strcasecmp(hourstr, "off") != 0; override = strcasecmp(hourstr, "off") != 0;
bts->tz.override = override; struct gsm_tz *tz = &net->tz;
tz->override = override;
if (override) { if (override) {
bts->tz.hr = hourstr ? atol(hourstr) : 0; tz->hr = hourstr ? atol(hourstr) : 0;
bts->tz.mn = minstr ? atol(minstr) : 0; tz->mn = minstr ? atol(minstr) : 0;
bts->tz.dst = dststr ? atol(dststr) : 0; tz->dst = dststr ? atol(dststr) : 0;
} }
talloc_free(tmp); talloc_free(tmp);
tmp = NULL; tmp = NULL;
return get_bts_timezone(cmd, data); return get_net_timezone(cmd, data);
oom: oom:
cmd->reply = "OOM"; cmd->reply = "OOM";
return CTRL_CMD_ERROR; return CTRL_CMD_ERROR;
} }
static int verify_bts_timezone(struct ctrl_cmd *cmd, const char *value, void *data) static int verify_net_timezone(struct ctrl_cmd *cmd, const char *value, void *data)
{ {
char *saveptr, *hourstr, *minstr, *dststr, *tmp; char *saveptr, *hourstr, *minstr, *dststr, *tmp;
int override, tz_hours, tz_mins, tz_dst; int override, tz_hours, tz_mins, tz_dst;
@ -655,7 +648,7 @@ int bsc_ctrl_cmds_install(struct gsm_network *net)
rc = ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_loc); rc = ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_loc);
if (rc) if (rc)
goto end; goto end;
rc = ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_timezone); rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_timezone);
if (rc) if (rc)
goto end; goto end;
rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_msc_connection_status); rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_msc_connection_status);

View File

@ -270,23 +270,24 @@ static int bsc_patch_mm_info(struct gsm_subscriber_connection *conn,
return 0; return 0;
/* Is TZ patching enabled? */ /* Is TZ patching enabled? */
if (!bts->tz.override) struct gsm_tz *tz = &bts->network->tz;
if (!tz->override)
return 0; return 0;
/* Convert tz.hr and tz.mn to units */ /* Convert tz.hr and tz.mn to units */
if (bts->tz.hr < 0) { if (tz->hr < 0) {
tzunits = -bts->tz.hr*4; tzunits = -tz->hr*4;
tzbsd |= 0x08; tzbsd |= 0x08;
} else } else
tzunits = bts->tz.hr*4; tzunits = tz->hr*4;
tzunits = tzunits + (bts->tz.mn/15); tzunits = tzunits + (tz->mn/15);
tzbsd |= (tzunits % 10)*0x10 + (tzunits / 10); tzbsd |= (tzunits % 10)*0x10 + (tzunits / 10);
/* Convert DST value */ /* Convert DST value */
if (bts->tz.dst >= 0 && bts->tz.dst <= 2) if (tz->dst >= 0 && tz->dst <= 2)
dst = bts->tz.dst; dst = tz->dst;
if (TLVP_PRESENT(&tp, GSM48_IE_UTC)) { if (TLVP_PRESENT(&tp, GSM48_IE_UTC)) {
LOGP(DMSC, LOGL_DEBUG, LOGP(DMSC, LOGL_DEBUG,

View File

@ -147,10 +147,10 @@ static void test_scan(void)
struct msgb *msg = msgb_alloc(4096, "test-message"); struct msgb *msg = msgb_alloc(4096, "test-message");
int is_set = 0; int is_set = 0;
bts->tz.hr = get_int(test_def->params, test_def->n_params, "tz_hr", 0, &is_set); net->tz.hr = get_int(test_def->params, test_def->n_params, "tz_hr", 0, &is_set);
bts->tz.mn = get_int(test_def->params, test_def->n_params, "tz_mn", 0, &is_set); net->tz.mn = get_int(test_def->params, test_def->n_params, "tz_mn", 0, &is_set);
bts->tz.dst = get_int(test_def->params, test_def->n_params, "tz_dst", 0, &is_set); net->tz.dst = get_int(test_def->params, test_def->n_params, "tz_dst", 0, &is_set);
bts->tz.override = 1; net->tz.override = 1;
printf("Going to test item: %d\n", i); printf("Going to test item: %d\n", i);
msg->l3h = msgb_put(msg, test_def->length); msg->l3h = msgb_put(msg, test_def->length);

View File

@ -331,41 +331,41 @@ class TestCtrlBSC(TestCtrlBase):
self.assertEquals(r['value'], 'state=off,policy=on') self.assertEquals(r['value'], 'state=off,policy=on')
def testTimezone(self): def testTimezone(self):
r = self.do_get('bts.0.timezone') r = self.do_get('timezone')
self.assertEquals(r['mtype'], 'GET_REPLY') self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'bts.0.timezone') self.assertEquals(r['var'], 'timezone')
self.assertEquals(r['value'], 'off') self.assertEquals(r['value'], 'off')
r = self.do_set('bts.0.timezone', '-2,15,2') r = self.do_set('timezone', '-2,15,2')
self.assertEquals(r['mtype'], 'SET_REPLY') self.assertEquals(r['mtype'], 'SET_REPLY')
self.assertEquals(r['var'], 'bts.0.timezone') self.assertEquals(r['var'], 'timezone')
self.assertEquals(r['value'], '-2,15,2') self.assertEquals(r['value'], '-2,15,2')
r = self.do_get('bts.0.timezone') r = self.do_get('timezone')
self.assertEquals(r['mtype'], 'GET_REPLY') self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'bts.0.timezone') self.assertEquals(r['var'], 'timezone')
self.assertEquals(r['value'], '-2,15,2') self.assertEquals(r['value'], '-2,15,2')
# Test invalid input # Test invalid input
r = self.do_set('bts.0.timezone', '-2,15,2,5,6,7') r = self.do_set('timezone', '-2,15,2,5,6,7')
self.assertEquals(r['mtype'], 'SET_REPLY') self.assertEquals(r['mtype'], 'SET_REPLY')
self.assertEquals(r['var'], 'bts.0.timezone') self.assertEquals(r['var'], 'timezone')
self.assertEquals(r['value'], '-2,15,2') self.assertEquals(r['value'], '-2,15,2')
r = self.do_set('bts.0.timezone', '-2,15') r = self.do_set('timezone', '-2,15')
self.assertEquals(r['mtype'], 'ERROR') self.assertEquals(r['mtype'], 'ERROR')
r = self.do_set('bts.0.timezone', '-2') r = self.do_set('timezone', '-2')
self.assertEquals(r['mtype'], 'ERROR') self.assertEquals(r['mtype'], 'ERROR')
r = self.do_set('bts.0.timezone', '1') r = self.do_set('timezone', '1')
r = self.do_set('bts.0.timezone', 'off') r = self.do_set('timezone', 'off')
self.assertEquals(r['mtype'], 'SET_REPLY') self.assertEquals(r['mtype'], 'SET_REPLY')
self.assertEquals(r['var'], 'bts.0.timezone') self.assertEquals(r['var'], 'timezone')
self.assertEquals(r['value'], 'off') self.assertEquals(r['value'], 'off')
r = self.do_get('bts.0.timezone') r = self.do_get('timezone')
self.assertEquals(r['mtype'], 'GET_REPLY') self.assertEquals(r['mtype'], 'GET_REPLY')
self.assertEquals(r['var'], 'bts.0.timezone') self.assertEquals(r['var'], 'timezone')
self.assertEquals(r['value'], 'off') self.assertEquals(r['value'], 'off')
def testMcc(self): def testMcc(self):

View File

@ -651,7 +651,6 @@ class TestVTYBSC(TestVTYGenericBSC):
self.vty.enable() self.vty.enable()
self.vty.verify("configure terminal", ['']) self.vty.verify("configure terminal", [''])
self.vty.verify("network", ['']) self.vty.verify("network", [''])
self.vty.verify("bts 0", [''])
# Test invalid input # Test invalid input
self.vty.verify("timezone", ['% Command incomplete.']) self.vty.verify("timezone", ['% Command incomplete.'])