blob: c3e25d5222a2671869afe39fdc1edb06b3dddb9f [file] [log] [blame]
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +02001/* GTP Hub main program */
2
3/* (C) 2015 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
4 * All Rights Reserved
5 *
6 * Author: Neels Hofmeyr
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include <unistd.h>
23#include <signal.h>
24#include <string.h>
25#include <errno.h>
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +010026#include <inttypes.h>
27#include <sys/stat.h>
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020028
29#define _GNU_SOURCE
30#include <getopt.h>
31
32#include <osmocom/core/signal.h>
33#include <osmocom/core/application.h>
34#include <osmocom/core/logging.h>
35#include <osmocom/core/utils.h>
36#include <osmocom/core/rate_ctr.h>
37
38#include <osmocom/vty/logging.h>
39#include <osmocom/vty/telnet_interface.h>
Neels Hofmeyr03933a42016-02-23 13:26:02 +010040#include <osmocom/vty/ports.h>
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020041
Neels Hofmeyree6cfdc2017-07-13 02:03:50 +020042#include <osmocom/sigtran/osmo_ss7.h>
43
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020044#include <osmocom/sgsn/debug.h>
45#include <osmocom/sgsn/gtphub.h>
46#include <osmocom/sgsn/vty.h>
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020047
48#include "../../bscconfig.h"
49
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020050extern void *osmo_gtphub_ctx;
Neels Hofmeyree6cfdc2017-07-13 02:03:50 +020051void *tall_bsc_ctx;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020052
53const char *gtphub_copyright =
54 "Copyright (C) 2015 sysmocom s.f.m.c GmbH <info@sysmocom.de>\r\n"
55 "License AGPLv3+: GNU AGPL version 2 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
56 "This is free software: you are free to change and redistribute it.\r\n"
57 "There is NO WARRANTY, to the extent permitted by law.\r\n";
58
59static struct log_info_cat gtphub_categories[] = {
60 [DGTPHUB] = {
61 .name = "DGTPHUB",
62 .description = "GTP Hub",
63 .color = "\033[1;33m",
Neels Hofmeyrd9b1d492015-11-18 18:11:09 +010064 .enabled = 1,
Neels Hofmeyr69da1d42016-02-23 13:28:04 +010065 .loglevel = LOGL_INFO,
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020066 },
67};
68
69int gtphub_log_filter_fn(const struct log_context *ctx,
70 struct log_target *tar)
71{
72 return 0;
73}
74
75static const struct log_info gtphub_log_info = {
76 .filter_fn = gtphub_log_filter_fn,
77 .cat = gtphub_categories,
78 .num_cat = ARRAY_SIZE(gtphub_categories),
79};
80
81void log_cfg(struct gtphub_cfg *cfg)
82{
Neels Hofmeyra9905a52015-11-29 23:49:48 +010083 int side_idx, plane_idx;
84 for_each_side_and_plane(side_idx, plane_idx) {
Neels Hofmeyr08550082015-11-30 12:19:50 +010085 struct gtphub_cfg_addr *a;
Neels Hofmeyra9905a52015-11-29 23:49:48 +010086 a = &cfg->to_gsns[side_idx][plane_idx].bind;
87 LOGP(DGTPHUB, LOGL_NOTICE,
88 "to-%ss bind, %s: %s port %d\n",
89 gtphub_side_idx_names[side_idx],
90 gtphub_plane_idx_names[plane_idx],
91 a->addr_str, a->port);
92 }
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020093}
94
95static void signal_handler(int signal)
96{
Neels Hofmeyr08550082015-11-30 12:19:50 +010097 fprintf(stdout, "signal %d received\n", signal);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020098
99 switch (signal) {
100 case SIGINT:
Harald Welte6f750e62017-08-20 20:50:06 +0200101 case SIGTERM:
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200102 osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
103 sleep(1);
104 exit(0);
105 break;
106 case SIGABRT:
107 /* in case of abort, we want to obtain a talloc report
108 * and then return to the caller, who will abort the process */
109 case SIGUSR1:
110 case SIGUSR2:
111 talloc_report_full(osmo_gtphub_ctx, stderr);
112 break;
113 default:
114 break;
115 }
116}
117
Philipp Maier4a547a12017-10-20 11:27:26 +0200118#if BUILD_IU
Neels Hofmeyree6cfdc2017-07-13 02:03:50 +0200119int gtphub_vty_go_parent(struct vty *vty)
120{
121 switch (vty->node) {
122 default:
123 osmo_ss7_vty_go_parent(vty);
124 }
125
126 return vty->node;
127}
Philipp Maier4a547a12017-10-20 11:27:26 +0200128#endif
Neels Hofmeyree6cfdc2017-07-13 02:03:50 +0200129
130int gtphub_vty_is_config_node(struct vty *vty, int node)
131{
132 /* Check if libosmo-sccp declares the node in
133 * question as config node */
Philipp Maier4a547a12017-10-20 11:27:26 +0200134#if BUILD_IU
Neels Hofmeyree6cfdc2017-07-13 02:03:50 +0200135 if (osmo_ss7_is_config_node(vty, node))
136 return 1;
Philipp Maier4a547a12017-10-20 11:27:26 +0200137#endif
Neels Hofmeyree6cfdc2017-07-13 02:03:50 +0200138
139 switch (node) {
140 /* add items that are not config */
141 case CONFIG_NODE:
142 return 0;
143
144 default:
145 return 1;
146 }
147}
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200148
149static struct vty_app_info vty_info = {
150 .name = "OsmoGTPhub",
151 .version = PACKAGE_VERSION,
Philipp Maier4a547a12017-10-20 11:27:26 +0200152#if BUILD_IU
Neels Hofmeyree6cfdc2017-07-13 02:03:50 +0200153 .go_parent_cb = gtphub_vty_go_parent,
Philipp Maier4a547a12017-10-20 11:27:26 +0200154#endif
Neels Hofmeyree6cfdc2017-07-13 02:03:50 +0200155 .is_config_node = gtphub_vty_is_config_node,
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200156};
157
158struct cmdline_cfg {
159 const char *config_file;
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100160 const char *restart_counter_file;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200161 int daemonize;
162};
163
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100164static uint8_t next_restart_count(const char *path)
165{
166 int umask_was = umask(022);
167
168 uint8_t counter = 0;
169
170 FILE *f = fopen(path, "r");
171 if (f) {
172 int rc = fscanf(f, "%hhu", &counter);
173
174 if (rc != 1)
175 goto failed_to_read;
176
177 char c;
178 while (fread(&c, 1, 1, f) > 0) {
179 switch (c) {
180 case ' ':
181 case '\t':
182 case '\n':
183 case '\r':
184 break;
185 default:
186 goto failed_to_read;
187 }
188 }
189 fclose(f);
190 }
191
192 counter ++;
193
194 f = fopen(path, "w");
195 if (!f)
196 goto failed_to_write;
197 if (fprintf(f, "%" PRIu8 "\n", counter) < 2)
198 goto failed_to_write;
Holger Hans Peter Freytherde766612016-01-23 10:28:09 +0100199 if (fclose(f)) {
200 f = NULL;
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100201 goto failed_to_write;
Holger Hans Peter Freytherde766612016-01-23 10:28:09 +0100202 }
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100203
204 umask(umask_was);
205
206 LOGP(DGTPHUB, LOGL_NOTICE, "Restarted with counter %hhu\n", counter);
207 return counter;
208
209failed_to_read:
210 fclose(f);
211 umask(umask_was);
212 LOGP(DGTPHUB, LOGL_FATAL, "Restart counter file cannot be parsed:"
213 " %s\n", path);
214 exit(1);
215
216failed_to_write:
217 if (f)
218 fclose(f);
219 umask(umask_was);
220 LOGP(DGTPHUB, LOGL_FATAL, "Restart counter file cannot be written:"
221 " %s\n", path);
222 exit(1);
223}
224
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200225static void print_help(struct cmdline_cfg *ccfg)
226{
227 printf("gtphub commandline options\n");
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100228 printf(" -h,--help This text.\n");
229 printf(" -D,--daemonize Fork the process into a background daemon.\n");
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200230 printf(" -d,--debug <cat> Enable Debugging for this category.\n");
231 printf(" Pass '-d list' to get a category listing.\n");
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100232 printf(" -s,--disable-color\n");
233 printf(" -c,--config-file <path> The config file to use [%s].\n",
234 ccfg->config_file);
235 printf(" -e,--log-level <nr> Set a global log level.\n");
236 printf(" -r,--restart-file <path> File for counting restarts [%s].\n",
237 ccfg->restart_counter_file);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200238}
239
240static void list_categories(void)
241{
242 printf("Avaliable debug categories:\n");
243 int i;
244 for (i = 0; i < gtphub_log_info.num_cat; ++i) {
245 if (!gtphub_log_info.cat[i].name)
246 continue;
247
248 printf("%s\n", gtphub_log_info.cat[i].name);
249 }
250}
251
252static void handle_options(struct cmdline_cfg *ccfg, int argc, char **argv)
253{
254 while (1) {
255 int option_index = 0, c;
256 static struct option long_options[] = {
257 {"help", 0, 0, 'h'},
258 {"debug", 1, 0, 'd'},
259 {"daemonize", 0, 0, 'D'},
260 {"config-file", 1, 0, 'c'},
261 {"disable-color", 0, 0, 's'},
262 {"timestamp", 0, 0, 'T'},
263 {"log-level", 1, 0, 'e'},
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100264 {"restart-file", 1, 0, 'r'},
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200265 {NULL, 0, 0, 0}
266 };
267
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100268 c = getopt_long(argc, argv, "hd:Dc:sTe:r:",
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200269 long_options, &option_index);
Neels Hofmeyr8d1ffbd2015-11-26 05:20:18 +0100270 if (c == -1) {
271 if (optind < argc) {
272 LOGP(DGTPHUB, LOGL_FATAL,
273 "Excess commandline arguments ('%s').\n",
274 argv[optind]);
275 exit(2);
276 }
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200277 break;
Neels Hofmeyr8d1ffbd2015-11-26 05:20:18 +0100278 }
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200279
280 switch (c) {
281 case 'h':
282 //print_usage();
283 print_help(ccfg);
284 exit(0);
285 case 's':
286 log_set_use_color(osmo_stderr_target, 0);
287 break;
288 case 'd':
289 if (strcmp("list", optarg) == 0) {
290 list_categories();
291 exit(0);
292 } else
293 log_parse_category_mask(osmo_stderr_target, optarg);
294 break;
295 case 'D':
296 ccfg->daemonize = 1;
297 break;
298 case 'c':
299 ccfg->config_file = optarg;
300 break;
301 case 'T':
302 log_set_print_timestamp(osmo_stderr_target, 1);
303 break;
304 case 'e':
305 log_set_log_level(osmo_stderr_target, atoi(optarg));
306 break;
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100307 case 'r':
308 ccfg->restart_counter_file = optarg;
309 break;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200310 default:
Neels Hofmeyr956d8562015-12-06 16:40:24 +0100311 LOGP(DGTPHUB, LOGL_FATAL, "Invalid command line argument, abort.\n");
312 exit(1);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200313 break;
314 }
315 }
316}
317
318int main(int argc, char **argv)
319{
320 int rc;
321
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100322 struct cmdline_cfg _ccfg;
323 struct cmdline_cfg *ccfg = &_ccfg;
324 memset(ccfg, '\0', sizeof(*ccfg));
325 ccfg->config_file = "./gtphub.conf";
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100326 ccfg->restart_counter_file = "./gtphub_restart_count";
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100327
328 struct gtphub_cfg _cfg;
329 struct gtphub_cfg *cfg = &_cfg;
330 memset(cfg, '\0', sizeof(*cfg));
331
332 struct gtphub _hub;
333 struct gtphub *hub = &_hub;
334
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200335 osmo_gtphub_ctx = talloc_named_const(NULL, 0, "osmo_gtphub");
Neels Hofmeyr4c2d4ab2016-09-16 02:31:17 +0200336 msgb_talloc_ctx_init(osmo_gtphub_ctx, 0);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200337
338 signal(SIGINT, &signal_handler);
Harald Welte6f750e62017-08-20 20:50:06 +0200339 signal(SIGTERM, &signal_handler);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200340 signal(SIGABRT, &signal_handler);
341 signal(SIGUSR1, &signal_handler);
342 signal(SIGUSR2, &signal_handler);
343 osmo_init_ignore_signals();
344
345 osmo_init_logging(&gtphub_log_info);
346
347 vty_info.copyright = gtphub_copyright;
348 vty_init(&vty_info);
Maxdb0e3802017-01-12 19:35:11 +0100349 logging_vty_add_cmds(NULL);
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100350 gtphub_vty_init(hub, cfg);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200351
352 rate_ctr_init(osmo_gtphub_ctx);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200353
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200354 handle_options(ccfg, argc, argv);
355
356 rc = gtphub_cfg_read(cfg, ccfg->config_file);
357 if (rc < 0) {
Neels Hofmeyrd9b1d492015-11-18 18:11:09 +0100358 LOGP(DGTPHUB, LOGL_FATAL, "Cannot parse config file '%s'\n",
359 ccfg->config_file);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200360 exit(2);
361 }
362
Neels Hofmeyrfa0f7152016-02-23 14:09:38 +0100363 /* start telnet after reading config for vty_get_bind_addr() */
Neels Hofmeyrfa0f7152016-02-23 14:09:38 +0100364 rc = telnet_init_dynif(osmo_gtphub_ctx, 0, vty_get_bind_addr(),
365 OSMO_VTY_PORT_GTPHUB);
366 if (rc < 0)
367 exit(1);
368
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100369 if (gtphub_start(hub, cfg,
370 next_restart_count(ccfg->restart_counter_file))
371 != 0)
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200372 return -1;
373
374 log_cfg(cfg);
375
376 if (ccfg->daemonize) {
377 rc = osmo_daemonize();
378 if (rc < 0) {
Neels Hofmeyrd9b1d492015-11-18 18:11:09 +0100379 LOGP(DGTPHUB, LOGL_FATAL, "Error during daemonize");
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200380 exit(1);
381 }
382 }
383
384 while (1) {
385 rc = osmo_select_main(0);
386 if (rc < 0)
387 exit(3);
388 }
389
390 /* not reached */
391 exit(0);
392}