blob: d25123eae95ad4dd8fe4162b3ea9bece0b30895c [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>
Pau Espin Pedrol6aad14c2023-01-09 13:27:24 +010037#include <osmocom/core/msgb.h>
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020038
39#include <osmocom/vty/logging.h>
40#include <osmocom/vty/telnet_interface.h>
Neels Hofmeyr03933a42016-02-23 13:26:02 +010041#include <osmocom/vty/ports.h>
Harald Welte731930b2018-02-14 01:02:22 +010042#include <osmocom/vty/misc.h>
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020043
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020044#include <osmocom/sgsn/debug.h>
Pau Espin Pedrolf2307c42023-01-09 11:55:18 +010045#include <osmocom/gtphub/gtphub.h>
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020046#include <osmocom/sgsn/vty.h>
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020047
Pau Espin Pedrolf44dfa82023-01-09 13:01:00 +010048#include "../../config.h"
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020049
Max095de012017-10-26 15:27:12 +020050#if BUILD_IU
51#include <osmocom/sigtran/osmo_ss7.h>
52#endif
53
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020054extern void *osmo_gtphub_ctx;
Pau Espin Pedrolb1d1c242018-10-30 17:27:59 +010055void *tall_sgsn_ctx;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020056
57const char *gtphub_copyright =
58 "Copyright (C) 2015 sysmocom s.f.m.c GmbH <info@sysmocom.de>\r\n"
59 "License AGPLv3+: GNU AGPL version 2 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
60 "This is free software: you are free to change and redistribute it.\r\n"
61 "There is NO WARRANTY, to the extent permitted by law.\r\n";
62
63static struct log_info_cat gtphub_categories[] = {
64 [DGTPHUB] = {
65 .name = "DGTPHUB",
66 .description = "GTP Hub",
67 .color = "\033[1;33m",
Neels Hofmeyrd9b1d492015-11-18 18:11:09 +010068 .enabled = 1,
Neels Hofmeyr69da1d42016-02-23 13:28:04 +010069 .loglevel = LOGL_INFO,
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020070 },
71};
72
73int gtphub_log_filter_fn(const struct log_context *ctx,
74 struct log_target *tar)
75{
76 return 0;
77}
78
79static const struct log_info gtphub_log_info = {
80 .filter_fn = gtphub_log_filter_fn,
81 .cat = gtphub_categories,
82 .num_cat = ARRAY_SIZE(gtphub_categories),
83};
84
85void log_cfg(struct gtphub_cfg *cfg)
86{
Neels Hofmeyra9905a52015-11-29 23:49:48 +010087 int side_idx, plane_idx;
88 for_each_side_and_plane(side_idx, plane_idx) {
Neels Hofmeyr08550082015-11-30 12:19:50 +010089 struct gtphub_cfg_addr *a;
Neels Hofmeyra9905a52015-11-29 23:49:48 +010090 a = &cfg->to_gsns[side_idx][plane_idx].bind;
91 LOGP(DGTPHUB, LOGL_NOTICE,
92 "to-%ss bind, %s: %s port %d\n",
93 gtphub_side_idx_names[side_idx],
94 gtphub_plane_idx_names[plane_idx],
95 a->addr_str, a->port);
96 }
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020097}
98
Pau Espin Pedrol7ffc6602020-11-25 18:03:21 +010099static void signal_handler(int signum)
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200100{
Pau Espin Pedrol7ffc6602020-11-25 18:03:21 +0100101 fprintf(stdout, "signal %d received\n", signum);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200102
Pau Espin Pedrol7ffc6602020-11-25 18:03:21 +0100103 switch (signum) {
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200104 case SIGINT:
Harald Welte6f750e62017-08-20 20:50:06 +0200105 case SIGTERM:
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200106 osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
107 sleep(1);
108 exit(0);
109 break;
110 case SIGABRT:
Pau Espin Pedrol7ffc6602020-11-25 18:03:21 +0100111 /* in case of abort, we want to obtain a talloc report and
112 * then run default SIGABRT handler, who will generate coredump
113 * and abort the process. abort() should do this for us after we
114 * return, but program wouldn't exit if an external SIGABRT is
115 * received.
116 */
117 talloc_report_full(osmo_gtphub_ctx, stderr);
118 signal(SIGABRT, SIG_DFL);
119 raise(SIGABRT);
120 break;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200121 case SIGUSR1:
122 case SIGUSR2:
123 talloc_report_full(osmo_gtphub_ctx, stderr);
124 break;
125 default:
126 break;
127 }
128}
129
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200130static struct vty_app_info vty_info = {
131 .name = "OsmoGTPhub",
132 .version = PACKAGE_VERSION,
Philipp Maier4a547a12017-10-20 11:27:26 +0200133#if BUILD_IU
Daniel Willmann62fa6192020-11-03 09:07:45 +0100134 .go_parent_cb = osmo_ss7_vty_go_parent,
Philipp Maier4a547a12017-10-20 11:27:26 +0200135#endif
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200136};
137
138struct cmdline_cfg {
139 const char *config_file;
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100140 const char *restart_counter_file;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200141 int daemonize;
142};
143
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100144static uint8_t next_restart_count(const char *path)
145{
146 int umask_was = umask(022);
147
148 uint8_t counter = 0;
149
150 FILE *f = fopen(path, "r");
151 if (f) {
152 int rc = fscanf(f, "%hhu", &counter);
153
154 if (rc != 1)
155 goto failed_to_read;
156
157 char c;
158 while (fread(&c, 1, 1, f) > 0) {
159 switch (c) {
160 case ' ':
161 case '\t':
162 case '\n':
163 case '\r':
164 break;
165 default:
166 goto failed_to_read;
167 }
168 }
169 fclose(f);
170 }
171
172 counter ++;
173
174 f = fopen(path, "w");
175 if (!f)
176 goto failed_to_write;
177 if (fprintf(f, "%" PRIu8 "\n", counter) < 2)
178 goto failed_to_write;
Holger Hans Peter Freytherde766612016-01-23 10:28:09 +0100179 if (fclose(f)) {
180 f = NULL;
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100181 goto failed_to_write;
Holger Hans Peter Freytherde766612016-01-23 10:28:09 +0100182 }
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100183
184 umask(umask_was);
185
186 LOGP(DGTPHUB, LOGL_NOTICE, "Restarted with counter %hhu\n", counter);
187 return counter;
188
189failed_to_read:
190 fclose(f);
191 umask(umask_was);
192 LOGP(DGTPHUB, LOGL_FATAL, "Restart counter file cannot be parsed:"
193 " %s\n", path);
194 exit(1);
195
196failed_to_write:
197 if (f)
198 fclose(f);
199 umask(umask_was);
200 LOGP(DGTPHUB, LOGL_FATAL, "Restart counter file cannot be written:"
201 " %s\n", path);
202 exit(1);
203}
204
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200205static void print_help(struct cmdline_cfg *ccfg)
206{
207 printf("gtphub commandline options\n");
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100208 printf(" -h,--help This text.\n");
209 printf(" -D,--daemonize Fork the process into a background daemon.\n");
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200210 printf(" -d,--debug <cat> Enable Debugging for this category.\n");
211 printf(" Pass '-d list' to get a category listing.\n");
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100212 printf(" -s,--disable-color\n");
213 printf(" -c,--config-file <path> The config file to use [%s].\n",
214 ccfg->config_file);
215 printf(" -e,--log-level <nr> Set a global log level.\n");
216 printf(" -r,--restart-file <path> File for counting restarts [%s].\n",
217 ccfg->restart_counter_file);
Daniel Willmann03a2ed52019-07-26 11:56:31 +0200218 printf(" -V,--version Print the version.\n");
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200219}
220
221static void list_categories(void)
222{
Ruben Undheim55fcf112018-09-25 22:59:34 +0200223 printf("Available debug categories:\n");
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200224 int i;
225 for (i = 0; i < gtphub_log_info.num_cat; ++i) {
226 if (!gtphub_log_info.cat[i].name)
227 continue;
228
229 printf("%s\n", gtphub_log_info.cat[i].name);
230 }
231}
232
233static void handle_options(struct cmdline_cfg *ccfg, int argc, char **argv)
234{
235 while (1) {
236 int option_index = 0, c;
237 static struct option long_options[] = {
238 {"help", 0, 0, 'h'},
239 {"debug", 1, 0, 'd'},
240 {"daemonize", 0, 0, 'D'},
241 {"config-file", 1, 0, 'c'},
242 {"disable-color", 0, 0, 's'},
243 {"timestamp", 0, 0, 'T'},
244 {"log-level", 1, 0, 'e'},
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100245 {"restart-file", 1, 0, 'r'},
Oliver Smithe64f0ef2018-10-16 17:09:18 +0200246 { "version", 0, 0, 'V' },
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200247 {NULL, 0, 0, 0}
248 };
249
Oliver Smithe64f0ef2018-10-16 17:09:18 +0200250 c = getopt_long(argc, argv, "hd:Dc:sTe:r:V",
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200251 long_options, &option_index);
Neels Hofmeyr8d1ffbd2015-11-26 05:20:18 +0100252 if (c == -1) {
253 if (optind < argc) {
254 LOGP(DGTPHUB, LOGL_FATAL,
255 "Excess commandline arguments ('%s').\n",
256 argv[optind]);
257 exit(2);
258 }
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200259 break;
Neels Hofmeyr8d1ffbd2015-11-26 05:20:18 +0100260 }
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200261
262 switch (c) {
263 case 'h':
264 //print_usage();
265 print_help(ccfg);
266 exit(0);
267 case 's':
268 log_set_use_color(osmo_stderr_target, 0);
269 break;
270 case 'd':
271 if (strcmp("list", optarg) == 0) {
272 list_categories();
273 exit(0);
274 } else
275 log_parse_category_mask(osmo_stderr_target, optarg);
276 break;
277 case 'D':
278 ccfg->daemonize = 1;
279 break;
280 case 'c':
281 ccfg->config_file = optarg;
282 break;
283 case 'T':
284 log_set_print_timestamp(osmo_stderr_target, 1);
285 break;
286 case 'e':
287 log_set_log_level(osmo_stderr_target, atoi(optarg));
288 break;
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100289 case 'r':
290 ccfg->restart_counter_file = optarg;
291 break;
Oliver Smithe64f0ef2018-10-16 17:09:18 +0200292 case 'V':
293 print_version(1);
294 exit(EXIT_SUCCESS);
295 break;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200296 default:
Neels Hofmeyr956d8562015-12-06 16:40:24 +0100297 LOGP(DGTPHUB, LOGL_FATAL, "Invalid command line argument, abort.\n");
298 exit(1);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200299 break;
300 }
301 }
Harald Weltede67c002019-12-03 22:28:19 +0100302
303 if (argc > optind) {
304 fprintf(stderr, "Unsupported positional arguments on command line\n");
305 exit(2);
306 }
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200307}
308
309int main(int argc, char **argv)
310{
311 int rc;
312
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100313 struct cmdline_cfg _ccfg;
314 struct cmdline_cfg *ccfg = &_ccfg;
315 memset(ccfg, '\0', sizeof(*ccfg));
316 ccfg->config_file = "./gtphub.conf";
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100317 ccfg->restart_counter_file = "./gtphub_restart_count";
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100318
319 struct gtphub_cfg _cfg;
320 struct gtphub_cfg *cfg = &_cfg;
321 memset(cfg, '\0', sizeof(*cfg));
322
323 struct gtphub _hub;
324 struct gtphub *hub = &_hub;
325
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200326 osmo_gtphub_ctx = talloc_named_const(NULL, 0, "osmo_gtphub");
Neels Hofmeyr4c2d4ab2016-09-16 02:31:17 +0200327 msgb_talloc_ctx_init(osmo_gtphub_ctx, 0);
Harald Welte731930b2018-02-14 01:02:22 +0100328 vty_info.tall_ctx = osmo_gtphub_ctx;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200329
330 signal(SIGINT, &signal_handler);
Harald Welte6f750e62017-08-20 20:50:06 +0200331 signal(SIGTERM, &signal_handler);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200332 signal(SIGABRT, &signal_handler);
333 signal(SIGUSR1, &signal_handler);
334 signal(SIGUSR2, &signal_handler);
335 osmo_init_ignore_signals();
336
Neels Hofmeyr5bd340e2018-04-16 00:57:10 +0200337 osmo_init_logging2(osmo_gtphub_ctx, &gtphub_log_info);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200338
339 vty_info.copyright = gtphub_copyright;
340 vty_init(&vty_info);
Pau Espin Pedrole456e322019-08-05 16:03:39 +0200341 logging_vty_add_cmds();
Harald Welte731930b2018-02-14 01:02:22 +0100342 osmo_talloc_vty_add_cmds();
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100343 gtphub_vty_init(hub, cfg);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200344
345 rate_ctr_init(osmo_gtphub_ctx);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200346
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200347 handle_options(ccfg, argc, argv);
348
349 rc = gtphub_cfg_read(cfg, ccfg->config_file);
350 if (rc < 0) {
Neels Hofmeyrd9b1d492015-11-18 18:11:09 +0100351 LOGP(DGTPHUB, LOGL_FATAL, "Cannot parse config file '%s'\n",
352 ccfg->config_file);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200353 exit(2);
354 }
355
Neels Hofmeyrfa0f7152016-02-23 14:09:38 +0100356 /* start telnet after reading config for vty_get_bind_addr() */
Neels Hofmeyrfa0f7152016-02-23 14:09:38 +0100357 rc = telnet_init_dynif(osmo_gtphub_ctx, 0, vty_get_bind_addr(),
358 OSMO_VTY_PORT_GTPHUB);
359 if (rc < 0)
360 exit(1);
361
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100362 if (gtphub_start(hub, cfg,
363 next_restart_count(ccfg->restart_counter_file))
364 != 0)
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200365 return -1;
366
367 log_cfg(cfg);
368
369 if (ccfg->daemonize) {
370 rc = osmo_daemonize();
371 if (rc < 0) {
Neels Hofmeyrd9b1d492015-11-18 18:11:09 +0100372 LOGP(DGTPHUB, LOGL_FATAL, "Error during daemonize");
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200373 exit(1);
374 }
375 }
376
377 while (1) {
378 rc = osmo_select_main(0);
379 if (rc < 0)
380 exit(3);
381 }
382
383 /* not reached */
384 exit(0);
385}