blob: a30ad2a54442d3f4f8a785bb62887c4121cb7dcf [file] [log] [blame]
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +02001/* (C) 2015 by sysmocom s.f.m.c. GmbH
2 * All Rights Reserved
3 *
4 * Author: Neels Hofmeyr
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include <string.h>
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +010022#include <inttypes.h>
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020023
Neels Hofmeyrb6c2db52015-11-18 18:11:32 +010024#include <ares.h>
25#include <sys/socket.h>
26#include <netinet/in.h>
27#include <arpa/inet.h>
28
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020029#include <osmocom/core/talloc.h>
30#include <osmocom/vty/command.h>
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +010031#include <osmocom/vty/misc.h>
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020032
33#include <openbsc/vty.h>
34#include <openbsc/gtphub.h>
35
Neels Hofmeyrb6c2db52015-11-18 18:11:32 +010036/* TODO split GRX ares from sgsn into a separate struct and allow use without
37 * globals. */
38#include <openbsc/sgsn.h>
39extern struct sgsn_instance *sgsn;
40
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +010041static struct gtphub *g_hub = 0;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020042static struct gtphub_cfg *g_cfg = 0;
43
44static struct cmd_node gtphub_node = {
45 GTPHUB_NODE,
46 "%s(config-gtphub)# ",
47 1,
48};
49
50#define GTPH_DEFAULT_CONTROL_PORT 2123
51#define GTPH_DEFAULT_USER_PORT 2152
52
53static void write_addrs(struct vty *vty, const char *name,
54 struct gtphub_cfg_addr *c, struct gtphub_cfg_addr *u)
55{
56 if ((c->port == GTPH_DEFAULT_CONTROL_PORT)
57 && (u->port == GTPH_DEFAULT_USER_PORT)
58 && (strcmp(c->addr_str, u->addr_str) == 0)) {
59 /* Default port numbers and same IP address: write "short"
60 * variant. */
61 vty_out(vty, " %s %s%s",
62 name,
63 c->addr_str,
64 VTY_NEWLINE);
65 return;
66 }
67
68 vty_out(vty, " %s ctrl %s %d user %s %d%s",
69 name,
70 c->addr_str, (int)c->port,
71 u->addr_str, (int)u->port,
72 VTY_NEWLINE);
Neels Hofmeyrb6c2db52015-11-18 18:11:32 +010073
74 struct ares_addr_node *server;
75 for (server = sgsn->ares_servers; server; server = server->next)
76 vty_out(vty, " grx-dns-add %s%s", inet_ntoa(server->addr.addr4), VTY_NEWLINE);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020077}
78
79static int config_write_gtphub(struct vty *vty)
80{
81 vty_out(vty, "gtphub%s", VTY_NEWLINE);
82
83 write_addrs(vty, "bind-to-sgsns",
Neels Hofmeyra9905a52015-11-29 23:49:48 +010084 &g_cfg->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].bind,
85 &g_cfg->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_USER].bind);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020086
87 write_addrs(vty, "bind-to-ggsns",
Neels Hofmeyra9905a52015-11-29 23:49:48 +010088 &g_cfg->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].bind,
89 &g_cfg->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_USER].bind);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020090
Neels Hofmeyrca2361c2015-12-03 14:12:44 +010091 if (g_cfg->sgsn_use_sender) {
92 vty_out(vty, "sgsn-use-sender%s", VTY_NEWLINE);
93 }
94
Neels Hofmeyr817bc322015-11-29 23:50:45 +010095 if (g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].addr_str) {
96 write_addrs(vty, "sgsn-proxy",
97 &g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL],
98 &g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_USER]);
99 }
100
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100101 if (g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].addr_str) {
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200102 write_addrs(vty, "ggsn-proxy",
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100103 &g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL],
104 &g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_USER]);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200105 }
106
107 return CMD_SUCCESS;
108}
109
110DEFUN(cfg_gtphub, cfg_gtphub_cmd,
111 "gtphub",
Neels Hofmeyrcdc548c2015-12-14 16:11:47 +0100112 "Configure the GTP hub\n")
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200113{
114 vty->node = GTPHUB_NODE;
115 return CMD_SUCCESS;
116}
117
118#define BIND_ARGS "ctrl ADDR <0-65535> user ADDR <0-65535>"
119#define BIND_DOCS \
120 "Set GTP-C bind\n" \
121 "GTP-C local IP address (v4 or v6)\n" \
122 "GTP-C local port\n" \
123 "Set GTP-U bind\n" \
124 "GTP-U local IP address (v4 or v6)\n" \
125 "GTP-U local port\n"
126
127
128DEFUN(cfg_gtphub_bind_to_sgsns_short, cfg_gtphub_bind_to_sgsns_short_cmd,
129 "bind-to-sgsns ADDR",
130 "GTP Hub Parameters\n"
131 "Set the local bind address to listen for SGSNs, for both GTP-C and GTP-U\n"
132 "Local IP address (v4 or v6)\n"
133 )
134{
135 int i;
Neels Hofmeyrf9773202015-11-27 00:05:56 +0100136 for_each_plane(i)
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100137 g_cfg->to_gsns[GTPH_SIDE_SGSN][i].bind.addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
138 g_cfg->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].bind.port = GTPH_DEFAULT_CONTROL_PORT;
139 g_cfg->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_USER].bind.port = GTPH_DEFAULT_USER_PORT;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200140 return CMD_SUCCESS;
141}
142
143DEFUN(cfg_gtphub_bind_to_ggsns_short, cfg_gtphub_bind_to_ggsns_short_cmd,
144 "bind-to-ggsns ADDR",
145 "GTP Hub Parameters\n"
146 "Set the local bind address to listen for GGSNs, for both GTP-C and GTP-U\n"
147 "Local IP address (v4 or v6)\n"
148 )
149{
150 int i;
Neels Hofmeyrf9773202015-11-27 00:05:56 +0100151 for_each_plane(i)
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100152 g_cfg->to_gsns[GTPH_SIDE_GGSN][i].bind.addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
153 g_cfg->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].bind.port = GTPH_DEFAULT_CONTROL_PORT;
154 g_cfg->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_USER].bind.port = GTPH_DEFAULT_USER_PORT;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200155 return CMD_SUCCESS;
156}
157
158
159static int handle_binds(struct gtphub_cfg_bind *b, const char **argv)
160{
161 b[GTPH_PLANE_CTRL].bind.addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
162 b[GTPH_PLANE_CTRL].bind.port = atoi(argv[1]);
163 b[GTPH_PLANE_USER].bind.addr_str = talloc_strdup(tall_vty_ctx, argv[2]);
164 b[GTPH_PLANE_USER].bind.port = atoi(argv[3]);
165 return CMD_SUCCESS;
166}
167
168DEFUN(cfg_gtphub_bind_to_sgsns, cfg_gtphub_bind_to_sgsns_cmd,
169 "bind-to-sgsns " BIND_ARGS,
170 "GTP Hub Parameters\n"
171 "Set the local bind addresses and ports to listen for SGSNs\n"
172 BIND_DOCS
173 )
174{
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100175 return handle_binds(g_cfg->to_gsns[GTPH_SIDE_SGSN], argv);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200176}
177
178DEFUN(cfg_gtphub_bind_to_ggsns, cfg_gtphub_bind_to_ggsns_cmd,
179 "bind-to-ggsns " BIND_ARGS,
180 "GTP Hub Parameters\n"
181 "Set the local bind addresses and ports to listen for GGSNs\n"
182 BIND_DOCS
183 )
184{
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100185 return handle_binds(g_cfg->to_gsns[GTPH_SIDE_GGSN], argv);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200186}
187
188DEFUN(cfg_gtphub_ggsn_proxy_short, cfg_gtphub_ggsn_proxy_short_cmd,
189 "ggsn-proxy ADDR",
190 "GTP Hub Parameters\n"
191 "Redirect all GGSN bound traffic to default ports on this address (another gtphub)\n"
192 "Remote IP address (v4 or v6)\n"
193 )
194{
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100195 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
196 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].port = GTPH_DEFAULT_CONTROL_PORT;
197 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_USER].addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
198 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_USER].port = GTPH_DEFAULT_USER_PORT;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200199 return CMD_SUCCESS;
200}
201
202DEFUN(cfg_gtphub_ggsn_proxy, cfg_gtphub_ggsn_proxy_cmd,
203 "ggsn-proxy " BIND_ARGS,
204 "GTP Hub Parameters\n"
205 "Redirect all GGSN bound traffic to these addresses and ports (another gtphub)\n"
206 BIND_DOCS
207 )
208{
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100209 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
210 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].port = atoi(argv[1]);
211 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_USER].addr_str = talloc_strdup(tall_vty_ctx, argv[2]);
212 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_USER].port = atoi(argv[3]);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200213 return CMD_SUCCESS;
214}
215
216DEFUN(cfg_gtphub_sgsn_proxy_short, cfg_gtphub_sgsn_proxy_short_cmd,
217 "sgsn-proxy ADDR",
218 "GTP Hub Parameters\n"
219 "Redirect all SGSN bound traffic to default ports on this address (another gtphub)\n"
220 "Remote IP address (v4 or v6)\n"
221 )
222{
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100223 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
224 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].port = GTPH_DEFAULT_CONTROL_PORT;
225 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_USER].addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
226 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_USER].port = GTPH_DEFAULT_USER_PORT;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200227 return CMD_SUCCESS;
228}
229
230DEFUN(cfg_gtphub_sgsn_proxy, cfg_gtphub_sgsn_proxy_cmd,
231 "sgsn-proxy " BIND_ARGS,
232 "GTP Hub Parameters\n"
233 "Redirect all SGSN bound traffic to these addresses and ports (another gtphub)\n"
234 BIND_DOCS
235 )
236{
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100237 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
238 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].port = atoi(argv[1]);
239 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_USER].addr_str = talloc_strdup(tall_vty_ctx, argv[2]);
240 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_USER].port = atoi(argv[3]);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200241 return CMD_SUCCESS;
242}
243
Neels Hofmeyrb6c2db52015-11-18 18:11:32 +0100244
Neels Hofmeyrca2361c2015-12-03 14:12:44 +0100245#define SGSN_USE_SENDER_STR \
246 "Ignore SGSN's Address IEs, use sender address and port (useful over NAT)\n"
247
248DEFUN(cfg_gtphub_sgsn_use_sender,
249 cfg_gtphub_sgsn_use_sender_cmd,
250 "sgsn-use-sender",
251 SGSN_USE_SENDER_STR)
252{
253 g_cfg->sgsn_use_sender = 1;
254 return CMD_SUCCESS;
255}
256
257DEFUN(cfg_gtphub_no_sgsn_use_sender,
258 cfg_gtphub_no_sgsn_use_sender_cmd,
259 "no sgsn-use-sender",
260 NO_STR SGSN_USE_SENDER_STR)
261{
262 g_cfg->sgsn_use_sender = 0;
263 return CMD_SUCCESS;
264}
265
266
Neels Hofmeyrb6c2db52015-11-18 18:11:32 +0100267/* Copied from sgsn_vty.h */
268DEFUN(cfg_grx_ggsn, cfg_grx_ggsn_cmd,
269 "grx-dns-add A.B.C.D",
270 "Add DNS server\nIPv4 address\n")
271{
272 struct ares_addr_node *node = talloc_zero(tall_bsc_ctx, struct ares_addr_node);
273 node->family = AF_INET;
274 inet_aton(argv[0], &node->addr.addr4);
275
276 node->next = sgsn->ares_servers;
277 sgsn->ares_servers = node;
278 return CMD_SUCCESS;
279}
280
281
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100282static void show_bind_stats_all(struct vty *vty)
283{
284 int plane_idx;
Neels Hofmeyrf9773202015-11-27 00:05:56 +0100285 for_each_plane(plane_idx) {
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100286 vty_out(vty, "- %s Plane:%s",
287 gtphub_plane_idx_names[plane_idx], VTY_NEWLINE);
288
Neels Hofmeyrba0525e2015-12-06 16:39:23 +0100289 int side_idx;
290 for_each_side(side_idx) {
291 struct gtphub_bind *b = &g_hub->to_gsns[side_idx][plane_idx];
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +0100292 vty_out(vty, " - local addr to/from %ss: %s port %d%s",
Neels Hofmeyrba0525e2015-12-06 16:39:23 +0100293 gtphub_side_idx_names[side_idx],
294 gsn_addr_to_str(&b->local_addr), (int)b->local_port,
295 VTY_NEWLINE);
296 vty_out_rate_ctr_group(vty, " ", b->counters_io);
297 }
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100298 }
299}
300
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100301static void show_tunnel_stats(struct vty *vty, struct gtphub_tunnel *tun)
302{
303 int plane_idx;
304 for_each_plane(plane_idx) {
305 vty_out(vty, "- %s Plane:%s",
306 gtphub_plane_idx_names[plane_idx], VTY_NEWLINE);
307
308 int side_idx;
309 for_each_side(side_idx) {
310 struct gtphub_tunnel_endpoint *te = &tun->endpoint[side_idx][plane_idx];
311 vty_out(vty, " - to/from %s:%s",
312 gtphub_side_idx_names[side_idx],
313 VTY_NEWLINE);
314 vty_out_rate_ctr_group(vty, " ", te->counters_io);
315 }
316 }
317}
318
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +0100319static void show_peer_summary(struct vty *vty, const char *prefix,
320 int side_idx, int plane_idx,
321 struct gtphub_peer *p, int with_io_stats)
322{
323 struct gtphub_peer_addr *pa;
324 int p2l = strlen(prefix) + 4 + 1;
325 char prefix2[p2l];
326 memset(prefix2, ' ', p2l - 1);
327 prefix2[p2l - 1] = '\0';
328
329 if (with_io_stats) {
330 llist_for_each_entry(pa, &p->addresses, entry) {
331 vty_out(vty, "%s- %s %s %s%s", prefix,
332 gtphub_side_idx_names[side_idx],
333 gtphub_plane_idx_names[plane_idx],
334 gsn_addr_to_str(&pa->addr),
335 VTY_NEWLINE);
336
337
338 struct gtphub_peer_port *pp;
339 llist_for_each_entry(pp, &pa->ports, entry) {
340 vty_out(vty, "%s Port %" PRIu16 "%s", prefix, pp->port, VTY_NEWLINE);
341 vty_out_rate_ctr_group(vty, prefix2, pp->counters_io);
342 }
343 }
344 } else {
345 llist_for_each_entry(pa, &p->addresses, entry) {
346 vty_out(vty, "%s- %s %s %s", prefix,
347 gtphub_side_idx_names[side_idx],
348 gtphub_plane_idx_names[plane_idx],
349 gsn_addr_to_str(&pa->addr));
350 struct gtphub_peer_port *pp;
351 llist_for_each_entry(pp, &pa->ports, entry) {
352 vty_out(vty, ":%" PRIu16, pp->port);
353 }
354 vty_out(vty, VTY_NEWLINE);
355 }
356 }
357}
358
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100359static void show_peers_summary(struct vty *vty)
360{
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +0100361 int side_idx;
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100362 int plane_idx;
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +0100363
364 int count[GTPH_SIDE_N][GTPH_PLANE_N] = {{0}};
365
366 for_each_side(side_idx) {
367 for_each_plane(plane_idx) {
368 struct gtphub_peer *p;
369 llist_for_each_entry(p, &g_hub->to_gsns[side_idx][plane_idx].peers, entry) {
370 count[side_idx][plane_idx] ++;
371 }
372 }
373 }
374
375 vty_out(vty, "Peers Count:%s", VTY_NEWLINE);
376 for_each_side_and_plane(side_idx, plane_idx) {
377 vty_out(vty, " %s %s peers: %d%s",
378 gtphub_side_idx_names[side_idx],
379 gtphub_plane_idx_names[plane_idx],
380 count[side_idx][plane_idx],
381 VTY_NEWLINE);
382 }
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100383}
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +0100384
385static void show_peers_all(struct vty *vty, int with_io_stats)
386{
387 int side_idx;
388 int plane_idx;
389
390 int count[GTPH_SIDE_N][GTPH_PLANE_N] = {{0}};
391
392 vty_out(vty, "All Peers%s%s",
393 with_io_stats? " with I/O stats" : "",
394 VTY_NEWLINE);
395 for_each_side(side_idx) {
396 vty_out(vty, "- %s%s", gtphub_side_idx_names[side_idx], VTY_NEWLINE);
397 for_each_plane(plane_idx) {
398 struct gtphub_peer *p;
399 llist_for_each_entry(p, &g_hub->to_gsns[side_idx][plane_idx].peers, entry) {
400 count[side_idx][plane_idx] ++;
401 show_peer_summary(vty, " ", side_idx, plane_idx, p, with_io_stats);
402 }
403 }
404 }
405 for_each_side_and_plane(side_idx, plane_idx) {
406 vty_out(vty, "%s %s peers: %d%s",
407 gtphub_side_idx_names[side_idx],
408 gtphub_plane_idx_names[plane_idx],
409 count[side_idx][plane_idx],
410 VTY_NEWLINE);
411 }
412}
413
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100414
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100415static void show_tunnels_summary(struct vty *vty)
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100416{
417 time_t now = gtphub_now();
418
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100419 const int w = 36;
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100420 int max_expiry = g_hub->expire_slowly.expiry_in_seconds;
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100421 float seconds_per_step = ((float)max_expiry) / w;
422
423 /* Print TEI mapping expiry in an ASCII histogram, like:
424 TEI map summary
425 Legend: '_'=0 '.'<=1% ':'<=2% '|'<=10% '#'>10% (10.0 m/step)
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100426 CTRL: 30 mappings, valid for 360m[# :. | . : . ]1m
427 USER: 30 mappings, valid for 360m[# :. | . : . ]1m
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100428 4 TEI mappings in total, last expiry in 359.4 min
429 */
430 vty_out(vty,
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100431 "Tunnels summary%s"
432 " Legend: ' '=0 '.'<=1%% ':'<=2%% '|'<=10%% '#'>10%% (%.1f m/step)%s",
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100433 VTY_NEWLINE,
434 seconds_per_step / 60.,
435 VTY_NEWLINE);
436
437 int last_expiry = 0;
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100438
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100439 unsigned int count = 0;
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100440
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100441 int histogram[w];
442 memset(histogram, 0, sizeof(histogram));
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100443
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100444 struct gtphub_tunnel *t;
445 llist_for_each_entry(t, &g_hub->tunnels, entry) {
446 count ++;
447 int expiry = t->expiry_entry.expiry - now;
448 last_expiry = (last_expiry > expiry) ? last_expiry : expiry;
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100449
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100450 int hi = ((float)expiry) / seconds_per_step;
451 if (hi < 0)
452 hi = 0;
453 if (hi > (w - 1))
454 hi = w - 1;
455 histogram[hi] ++;
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100456 }
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100457
458 vty_out(vty,
459 " %u tunnels, valid for %dm[",
460 count, max_expiry / 60);
461
462 int i;
463 for (i = w - 1; i >= 0; i--) {
464 char c;
465 int val = histogram[i];
466 int percent = 100. * val / count;
467 if (!val)
468 c = ' ';
469 else if (percent <= 1)
470 c = '.';
471 else if (percent <= 2)
472 c = ':';
473 else if (percent <= 10)
474 c = '|';
475 else c = '#';
476 vty_out(vty, "%c", c);
477 }
478 vty_out(vty, "]1m%s", VTY_NEWLINE);
479
480 vty_out(vty, " last expiry in %.1f min%s",
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100481 ((float)last_expiry) / 60.,
482 VTY_NEWLINE);
483}
484
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100485static void show_tunnels_all(struct vty *vty, int with_io_stats)
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100486{
487 time_t now = gtphub_now();
488
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100489 vty_out(vty, "All tunnels%s:%s"
Neels Hofmeyree07e4f2015-12-06 19:11:45 +0100490 "Legend: TEI=<hex>: SGSN <-> GGSN (expiry in minutes), with each:%s"
491 " <IP-Ctrl>[/<IP-User>] (TEI C=<TEI-Ctrl-hex> U=<TEI-User-hex>)%s",
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100492 with_io_stats? "with I/O stats" : "",
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100493 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100494
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100495 unsigned int count = 0;
496 unsigned int incomplete = 0;
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100497 struct gtphub_tunnel *tun;
498 llist_for_each_entry(tun, &g_hub->tunnels, entry) {
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100499 vty_out(vty,
Neels Hofmeyree07e4f2015-12-06 19:11:45 +0100500 "%s (expiry in %dm)%s",
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100501 gtphub_tunnel_str(tun),
Neels Hofmeyree07e4f2015-12-06 19:11:45 +0100502 (int)((tun->expiry_entry.expiry - now) / 60),
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100503 VTY_NEWLINE);
504 count ++;
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100505 if (!gtphub_tunnel_complete(tun))
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100506 incomplete ++;
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100507 if (with_io_stats)
508 show_tunnel_stats(vty, tun);
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100509 }
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100510 vty_out(vty, "Total: %u tunnels (of which %u incomplete)%s",
511 count, incomplete, VTY_NEWLINE);
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100512}
513
Neels Hofmeyr69a720f2015-12-14 15:51:31 +0100514#define SHOW_GTPHUB_STRS SHOW_STR "Show info on running GTP hub\n"
515#define SHOW_GTPHUB_PEERS_STRS SHOW_GTPHUB_STRS "Active peers\n"
516#define SHOW_GTPHUB_TUNS_STRS SHOW_GTPHUB_STRS "Active tunnels\n"
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +0100517
518DEFUN(show_gtphub_peers_summary, show_gtphub_peers_summary_cmd, "show gtphub peers summary",
Neels Hofmeyrcdc548c2015-12-14 16:11:47 +0100519 SHOW_GTPHUB_PEERS_STRS "Summary of all peers\n")
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +0100520{
521 show_peers_summary(vty);
522 return CMD_SUCCESS;
523}
524
525DEFUN(show_gtphub_peers_list, show_gtphub_peers_list_cmd, "show gtphub peers list",
Neels Hofmeyrcdc548c2015-12-14 16:11:47 +0100526 SHOW_GTPHUB_PEERS_STRS "List all peers\n")
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +0100527{
528 show_peers_all(vty, 0);
529 return CMD_SUCCESS;
530}
531
532DEFUN(show_gtphub_peers_stats, show_gtphub_peers_stats_cmd, "show gtphub peers stats",
Neels Hofmeyrcdc548c2015-12-14 16:11:47 +0100533 SHOW_GTPHUB_PEERS_STRS "List all peers with I/O stats\n")
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +0100534{
535 show_peers_all(vty, 1);
536 return CMD_SUCCESS;
537}
538
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100539DEFUN(show_gtphub_tunnels_summary, show_gtphub_tunnels_summary_cmd, "show gtphub tunnels summary",
Neels Hofmeyrcdc548c2015-12-14 16:11:47 +0100540 SHOW_GTPHUB_TUNS_STRS "Summary of all tunnels\n")
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100541{
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100542 show_tunnels_summary(vty);
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100543 return CMD_SUCCESS;
544}
545
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100546DEFUN(show_gtphub_tunnels_list, show_gtphub_tunnels_list_cmd, "show gtphub tunnels list",
Neels Hofmeyrcdc548c2015-12-14 16:11:47 +0100547 SHOW_GTPHUB_TUNS_STRS "List all tunnels\n")
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100548{
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100549 show_tunnels_all(vty, 0);
550 return CMD_SUCCESS;
551}
552
553DEFUN(show_gtphub_tunnels_stats, show_gtphub_tunnels_stats_cmd, "show gtphub tunnels stats",
Neels Hofmeyrcdc548c2015-12-14 16:11:47 +0100554 SHOW_GTPHUB_TUNS_STRS "List all tunnels with I/O stats\n")
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100555{
556 show_tunnels_all(vty, 1);
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100557 return CMD_SUCCESS;
558}
559
560DEFUN(show_gtphub, show_gtphub_cmd, "show gtphub all",
Neels Hofmeyrcdc548c2015-12-14 16:11:47 +0100561 SHOW_GTPHUB_STRS "Summarize everything about the GTP hub\n")
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200562{
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100563 show_bind_stats_all(vty);
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +0100564 show_peers_summary(vty);
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100565 show_tunnels_summary(vty);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200566 return CMD_SUCCESS;
567}
568
569
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100570int gtphub_vty_init(struct gtphub *global_hub, struct gtphub_cfg *global_cfg)
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200571{
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100572 g_hub = global_hub;
573 g_cfg = global_cfg;
574
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200575 install_element_ve(&show_gtphub_cmd);
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +0100576 install_element_ve(&show_gtphub_peers_summary_cmd);
577 install_element_ve(&show_gtphub_peers_list_cmd);
578 install_element_ve(&show_gtphub_peers_stats_cmd);
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100579 install_element_ve(&show_gtphub_tunnels_summary_cmd);
580 install_element_ve(&show_gtphub_tunnels_list_cmd);
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100581 install_element_ve(&show_gtphub_tunnels_stats_cmd);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200582
583 install_element(CONFIG_NODE, &cfg_gtphub_cmd);
584 install_node(&gtphub_node, config_write_gtphub);
585 vty_install_default(GTPHUB_NODE);
586
587 install_element(GTPHUB_NODE, &cfg_gtphub_bind_to_sgsns_short_cmd);
588 install_element(GTPHUB_NODE, &cfg_gtphub_bind_to_sgsns_cmd);
589 install_element(GTPHUB_NODE, &cfg_gtphub_bind_to_ggsns_short_cmd);
590 install_element(GTPHUB_NODE, &cfg_gtphub_bind_to_ggsns_cmd);
591 install_element(GTPHUB_NODE, &cfg_gtphub_ggsn_proxy_short_cmd);
592 install_element(GTPHUB_NODE, &cfg_gtphub_ggsn_proxy_cmd);
593 install_element(GTPHUB_NODE, &cfg_gtphub_sgsn_proxy_short_cmd);
594 install_element(GTPHUB_NODE, &cfg_gtphub_sgsn_proxy_cmd);
Neels Hofmeyrca2361c2015-12-03 14:12:44 +0100595 install_element(GTPHUB_NODE, &cfg_gtphub_sgsn_use_sender_cmd);
596 install_element(GTPHUB_NODE, &cfg_gtphub_no_sgsn_use_sender_cmd);
Neels Hofmeyrb6c2db52015-11-18 18:11:32 +0100597 install_element(GTPHUB_NODE, &cfg_grx_ggsn_cmd);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200598
599 return 0;
600}
601
602int gtphub_cfg_read(struct gtphub_cfg *cfg, const char *config_file)
603{
604 int rc;
605
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200606 rc = vty_read_config_file(config_file, NULL);
607 if (rc < 0) {
608 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
609 return rc;
610 }
611
612 return 0;
613}