blob: 3a46e817d5ad6133f09543b8f84ed21c2d9de6cd [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
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020033#include <osmocom/sgsn/vty.h>
34#include <osmocom/sgsn/gtphub.h>
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020035
Neels Hofmeyrb6c2db52015-11-18 18:11:32 +010036/* TODO split GRX ares from sgsn into a separate struct and allow use without
37 * globals. */
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020038#include <osmocom/sgsn/sgsn.h>
Neels Hofmeyrb6c2db52015-11-18 18:11:32 +010039extern struct sgsn_instance *sgsn;
Neels Hofmeyree6cfdc2017-07-13 02:03:50 +020040extern void *tall_bsc_ctx;
Neels Hofmeyrb6c2db52015-11-18 18:11:32 +010041
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +010042static struct gtphub *g_hub = 0;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020043static struct gtphub_cfg *g_cfg = 0;
44
45static struct cmd_node gtphub_node = {
46 GTPHUB_NODE,
47 "%s(config-gtphub)# ",
48 1,
49};
50
51#define GTPH_DEFAULT_CONTROL_PORT 2123
52#define GTPH_DEFAULT_USER_PORT 2152
53
54static void write_addrs(struct vty *vty, const char *name,
55 struct gtphub_cfg_addr *c, struct gtphub_cfg_addr *u)
56{
57 if ((c->port == GTPH_DEFAULT_CONTROL_PORT)
58 && (u->port == GTPH_DEFAULT_USER_PORT)
59 && (strcmp(c->addr_str, u->addr_str) == 0)) {
60 /* Default port numbers and same IP address: write "short"
61 * variant. */
62 vty_out(vty, " %s %s%s",
63 name,
64 c->addr_str,
65 VTY_NEWLINE);
66 return;
67 }
68
69 vty_out(vty, " %s ctrl %s %d user %s %d%s",
70 name,
71 c->addr_str, (int)c->port,
72 u->addr_str, (int)u->port,
73 VTY_NEWLINE);
Neels Hofmeyrb6c2db52015-11-18 18:11:32 +010074
75 struct ares_addr_node *server;
76 for (server = sgsn->ares_servers; server; server = server->next)
77 vty_out(vty, " grx-dns-add %s%s", inet_ntoa(server->addr.addr4), VTY_NEWLINE);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020078}
79
80static int config_write_gtphub(struct vty *vty)
81{
82 vty_out(vty, "gtphub%s", VTY_NEWLINE);
83
84 write_addrs(vty, "bind-to-sgsns",
Neels Hofmeyra9905a52015-11-29 23:49:48 +010085 &g_cfg->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].bind,
86 &g_cfg->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_USER].bind);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020087
88 write_addrs(vty, "bind-to-ggsns",
Neels Hofmeyra9905a52015-11-29 23:49:48 +010089 &g_cfg->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].bind,
90 &g_cfg->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_USER].bind);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020091
Neels Hofmeyrca2361c2015-12-03 14:12:44 +010092 if (g_cfg->sgsn_use_sender) {
93 vty_out(vty, "sgsn-use-sender%s", VTY_NEWLINE);
94 }
95
Neels Hofmeyr817bc322015-11-29 23:50:45 +010096 if (g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].addr_str) {
97 write_addrs(vty, "sgsn-proxy",
98 &g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL],
99 &g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_USER]);
100 }
101
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100102 if (g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].addr_str) {
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200103 write_addrs(vty, "ggsn-proxy",
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100104 &g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL],
105 &g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_USER]);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200106 }
107
108 return CMD_SUCCESS;
109}
110
111DEFUN(cfg_gtphub, cfg_gtphub_cmd,
112 "gtphub",
Neels Hofmeyrcdc548c2015-12-14 16:11:47 +0100113 "Configure the GTP hub\n")
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200114{
115 vty->node = GTPHUB_NODE;
116 return CMD_SUCCESS;
117}
118
119#define BIND_ARGS "ctrl ADDR <0-65535> user ADDR <0-65535>"
120#define BIND_DOCS \
121 "Set GTP-C bind\n" \
122 "GTP-C local IP address (v4 or v6)\n" \
123 "GTP-C local port\n" \
124 "Set GTP-U bind\n" \
125 "GTP-U local IP address (v4 or v6)\n" \
126 "GTP-U local port\n"
127
128
129DEFUN(cfg_gtphub_bind_to_sgsns_short, cfg_gtphub_bind_to_sgsns_short_cmd,
130 "bind-to-sgsns ADDR",
131 "GTP Hub Parameters\n"
132 "Set the local bind address to listen for SGSNs, for both GTP-C and GTP-U\n"
133 "Local IP address (v4 or v6)\n"
134 )
135{
136 int i;
Neels Hofmeyrf9773202015-11-27 00:05:56 +0100137 for_each_plane(i)
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100138 g_cfg->to_gsns[GTPH_SIDE_SGSN][i].bind.addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
139 g_cfg->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].bind.port = GTPH_DEFAULT_CONTROL_PORT;
140 g_cfg->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_USER].bind.port = GTPH_DEFAULT_USER_PORT;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200141 return CMD_SUCCESS;
142}
143
144DEFUN(cfg_gtphub_bind_to_ggsns_short, cfg_gtphub_bind_to_ggsns_short_cmd,
145 "bind-to-ggsns ADDR",
146 "GTP Hub Parameters\n"
147 "Set the local bind address to listen for GGSNs, for both GTP-C and GTP-U\n"
148 "Local IP address (v4 or v6)\n"
149 )
150{
151 int i;
Neels Hofmeyrf9773202015-11-27 00:05:56 +0100152 for_each_plane(i)
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100153 g_cfg->to_gsns[GTPH_SIDE_GGSN][i].bind.addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
154 g_cfg->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].bind.port = GTPH_DEFAULT_CONTROL_PORT;
155 g_cfg->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_USER].bind.port = GTPH_DEFAULT_USER_PORT;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200156 return CMD_SUCCESS;
157}
158
159
160static int handle_binds(struct gtphub_cfg_bind *b, const char **argv)
161{
162 b[GTPH_PLANE_CTRL].bind.addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
163 b[GTPH_PLANE_CTRL].bind.port = atoi(argv[1]);
164 b[GTPH_PLANE_USER].bind.addr_str = talloc_strdup(tall_vty_ctx, argv[2]);
165 b[GTPH_PLANE_USER].bind.port = atoi(argv[3]);
166 return CMD_SUCCESS;
167}
168
169DEFUN(cfg_gtphub_bind_to_sgsns, cfg_gtphub_bind_to_sgsns_cmd,
170 "bind-to-sgsns " BIND_ARGS,
171 "GTP Hub Parameters\n"
172 "Set the local bind addresses and ports to listen for SGSNs\n"
173 BIND_DOCS
174 )
175{
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100176 return handle_binds(g_cfg->to_gsns[GTPH_SIDE_SGSN], argv);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200177}
178
179DEFUN(cfg_gtphub_bind_to_ggsns, cfg_gtphub_bind_to_ggsns_cmd,
180 "bind-to-ggsns " BIND_ARGS,
181 "GTP Hub Parameters\n"
182 "Set the local bind addresses and ports to listen for GGSNs\n"
183 BIND_DOCS
184 )
185{
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100186 return handle_binds(g_cfg->to_gsns[GTPH_SIDE_GGSN], argv);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200187}
188
189DEFUN(cfg_gtphub_ggsn_proxy_short, cfg_gtphub_ggsn_proxy_short_cmd,
190 "ggsn-proxy ADDR",
191 "GTP Hub Parameters\n"
192 "Redirect all GGSN bound traffic to default ports on this address (another gtphub)\n"
193 "Remote IP address (v4 or v6)\n"
194 )
195{
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100196 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
197 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].port = GTPH_DEFAULT_CONTROL_PORT;
198 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_USER].addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
199 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_USER].port = GTPH_DEFAULT_USER_PORT;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200200 return CMD_SUCCESS;
201}
202
203DEFUN(cfg_gtphub_ggsn_proxy, cfg_gtphub_ggsn_proxy_cmd,
204 "ggsn-proxy " BIND_ARGS,
205 "GTP Hub Parameters\n"
206 "Redirect all GGSN bound traffic to these addresses and ports (another gtphub)\n"
207 BIND_DOCS
208 )
209{
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100210 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
211 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].port = atoi(argv[1]);
212 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_USER].addr_str = talloc_strdup(tall_vty_ctx, argv[2]);
213 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_USER].port = atoi(argv[3]);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200214 return CMD_SUCCESS;
215}
216
217DEFUN(cfg_gtphub_sgsn_proxy_short, cfg_gtphub_sgsn_proxy_short_cmd,
218 "sgsn-proxy ADDR",
219 "GTP Hub Parameters\n"
220 "Redirect all SGSN bound traffic to default ports on this address (another gtphub)\n"
221 "Remote IP address (v4 or v6)\n"
222 )
223{
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100224 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
225 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].port = GTPH_DEFAULT_CONTROL_PORT;
226 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_USER].addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
227 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_USER].port = GTPH_DEFAULT_USER_PORT;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200228 return CMD_SUCCESS;
229}
230
231DEFUN(cfg_gtphub_sgsn_proxy, cfg_gtphub_sgsn_proxy_cmd,
232 "sgsn-proxy " BIND_ARGS,
233 "GTP Hub Parameters\n"
234 "Redirect all SGSN bound traffic to these addresses and ports (another gtphub)\n"
235 BIND_DOCS
236 )
237{
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100238 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
239 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].port = atoi(argv[1]);
240 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_USER].addr_str = talloc_strdup(tall_vty_ctx, argv[2]);
241 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_USER].port = atoi(argv[3]);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200242 return CMD_SUCCESS;
243}
244
Neels Hofmeyrb6c2db52015-11-18 18:11:32 +0100245
Neels Hofmeyrca2361c2015-12-03 14:12:44 +0100246#define SGSN_USE_SENDER_STR \
247 "Ignore SGSN's Address IEs, use sender address and port (useful over NAT)\n"
248
249DEFUN(cfg_gtphub_sgsn_use_sender,
250 cfg_gtphub_sgsn_use_sender_cmd,
251 "sgsn-use-sender",
252 SGSN_USE_SENDER_STR)
253{
254 g_cfg->sgsn_use_sender = 1;
255 return CMD_SUCCESS;
256}
257
258DEFUN(cfg_gtphub_no_sgsn_use_sender,
259 cfg_gtphub_no_sgsn_use_sender_cmd,
260 "no sgsn-use-sender",
261 NO_STR SGSN_USE_SENDER_STR)
262{
263 g_cfg->sgsn_use_sender = 0;
264 return CMD_SUCCESS;
265}
266
267
Neels Hofmeyrb6c2db52015-11-18 18:11:32 +0100268/* Copied from sgsn_vty.h */
269DEFUN(cfg_grx_ggsn, cfg_grx_ggsn_cmd,
270 "grx-dns-add A.B.C.D",
271 "Add DNS server\nIPv4 address\n")
272{
273 struct ares_addr_node *node = talloc_zero(tall_bsc_ctx, struct ares_addr_node);
274 node->family = AF_INET;
275 inet_aton(argv[0], &node->addr.addr4);
276
277 node->next = sgsn->ares_servers;
278 sgsn->ares_servers = node;
279 return CMD_SUCCESS;
280}
281
282
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100283static void show_bind_stats_all(struct vty *vty)
284{
285 int plane_idx;
Neels Hofmeyrf9773202015-11-27 00:05:56 +0100286 for_each_plane(plane_idx) {
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100287 vty_out(vty, "- %s Plane:%s",
288 gtphub_plane_idx_names[plane_idx], VTY_NEWLINE);
289
Neels Hofmeyrba0525e2015-12-06 16:39:23 +0100290 int side_idx;
291 for_each_side(side_idx) {
292 struct gtphub_bind *b = &g_hub->to_gsns[side_idx][plane_idx];
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +0100293 vty_out(vty, " - local addr to/from %ss: %s port %d%s",
Neels Hofmeyrba0525e2015-12-06 16:39:23 +0100294 gtphub_side_idx_names[side_idx],
295 gsn_addr_to_str(&b->local_addr), (int)b->local_port,
296 VTY_NEWLINE);
297 vty_out_rate_ctr_group(vty, " ", b->counters_io);
298 }
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100299 }
300}
301
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100302static void show_tunnel_stats(struct vty *vty, struct gtphub_tunnel *tun)
303{
304 int plane_idx;
305 for_each_plane(plane_idx) {
306 vty_out(vty, "- %s Plane:%s",
307 gtphub_plane_idx_names[plane_idx], VTY_NEWLINE);
308
309 int side_idx;
310 for_each_side(side_idx) {
311 struct gtphub_tunnel_endpoint *te = &tun->endpoint[side_idx][plane_idx];
312 vty_out(vty, " - to/from %s:%s",
313 gtphub_side_idx_names[side_idx],
314 VTY_NEWLINE);
315 vty_out_rate_ctr_group(vty, " ", te->counters_io);
316 }
317 }
318}
319
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +0100320static void show_peer_summary(struct vty *vty, const char *prefix,
321 int side_idx, int plane_idx,
322 struct gtphub_peer *p, int with_io_stats)
323{
324 struct gtphub_peer_addr *pa;
325 int p2l = strlen(prefix) + 4 + 1;
326 char prefix2[p2l];
327 memset(prefix2, ' ', p2l - 1);
328 prefix2[p2l - 1] = '\0';
329
330 if (with_io_stats) {
331 llist_for_each_entry(pa, &p->addresses, entry) {
332 vty_out(vty, "%s- %s %s %s%s", prefix,
333 gtphub_side_idx_names[side_idx],
334 gtphub_plane_idx_names[plane_idx],
335 gsn_addr_to_str(&pa->addr),
336 VTY_NEWLINE);
337
338
339 struct gtphub_peer_port *pp;
340 llist_for_each_entry(pp, &pa->ports, entry) {
341 vty_out(vty, "%s Port %" PRIu16 "%s", prefix, pp->port, VTY_NEWLINE);
342 vty_out_rate_ctr_group(vty, prefix2, pp->counters_io);
343 }
344 }
345 } else {
346 llist_for_each_entry(pa, &p->addresses, entry) {
347 vty_out(vty, "%s- %s %s %s", prefix,
348 gtphub_side_idx_names[side_idx],
349 gtphub_plane_idx_names[plane_idx],
350 gsn_addr_to_str(&pa->addr));
351 struct gtphub_peer_port *pp;
352 llist_for_each_entry(pp, &pa->ports, entry) {
353 vty_out(vty, ":%" PRIu16, pp->port);
354 }
355 vty_out(vty, VTY_NEWLINE);
356 }
357 }
358}
359
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100360static void show_peers_summary(struct vty *vty)
361{
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +0100362 int side_idx;
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100363 int plane_idx;
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +0100364
365 int count[GTPH_SIDE_N][GTPH_PLANE_N] = {{0}};
366
367 for_each_side(side_idx) {
368 for_each_plane(plane_idx) {
369 struct gtphub_peer *p;
370 llist_for_each_entry(p, &g_hub->to_gsns[side_idx][plane_idx].peers, entry) {
371 count[side_idx][plane_idx] ++;
372 }
373 }
374 }
375
376 vty_out(vty, "Peers Count:%s", VTY_NEWLINE);
377 for_each_side_and_plane(side_idx, plane_idx) {
378 vty_out(vty, " %s %s peers: %d%s",
379 gtphub_side_idx_names[side_idx],
380 gtphub_plane_idx_names[plane_idx],
381 count[side_idx][plane_idx],
382 VTY_NEWLINE);
383 }
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100384}
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +0100385
386static void show_peers_all(struct vty *vty, int with_io_stats)
387{
388 int side_idx;
389 int plane_idx;
390
391 int count[GTPH_SIDE_N][GTPH_PLANE_N] = {{0}};
392
393 vty_out(vty, "All Peers%s%s",
394 with_io_stats? " with I/O stats" : "",
395 VTY_NEWLINE);
396 for_each_side(side_idx) {
397 vty_out(vty, "- %s%s", gtphub_side_idx_names[side_idx], VTY_NEWLINE);
398 for_each_plane(plane_idx) {
399 struct gtphub_peer *p;
400 llist_for_each_entry(p, &g_hub->to_gsns[side_idx][plane_idx].peers, entry) {
401 count[side_idx][plane_idx] ++;
402 show_peer_summary(vty, " ", side_idx, plane_idx, p, with_io_stats);
403 }
404 }
405 }
406 for_each_side_and_plane(side_idx, plane_idx) {
407 vty_out(vty, "%s %s peers: %d%s",
408 gtphub_side_idx_names[side_idx],
409 gtphub_plane_idx_names[plane_idx],
410 count[side_idx][plane_idx],
411 VTY_NEWLINE);
412 }
413}
414
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100415
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100416static void show_tunnels_summary(struct vty *vty)
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100417{
418 time_t now = gtphub_now();
419
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100420 const int w = 36;
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100421 int max_expiry = g_hub->expire_slowly.expiry_in_seconds;
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100422 float seconds_per_step = ((float)max_expiry) / w;
423
424 /* Print TEI mapping expiry in an ASCII histogram, like:
425 TEI map summary
426 Legend: '_'=0 '.'<=1% ':'<=2% '|'<=10% '#'>10% (10.0 m/step)
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100427 CTRL: 30 mappings, valid for 360m[# :. | . : . ]1m
428 USER: 30 mappings, valid for 360m[# :. | . : . ]1m
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100429 4 TEI mappings in total, last expiry in 359.4 min
430 */
431 vty_out(vty,
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100432 "Tunnels summary%s"
433 " Legend: ' '=0 '.'<=1%% ':'<=2%% '|'<=10%% '#'>10%% (%.1f m/step)%s",
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100434 VTY_NEWLINE,
435 seconds_per_step / 60.,
436 VTY_NEWLINE);
437
438 int last_expiry = 0;
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100439
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100440 unsigned int count = 0;
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100441
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100442 int histogram[w];
443 memset(histogram, 0, sizeof(histogram));
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100444
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100445 struct gtphub_tunnel *t;
446 llist_for_each_entry(t, &g_hub->tunnels, entry) {
447 count ++;
448 int expiry = t->expiry_entry.expiry - now;
449 last_expiry = (last_expiry > expiry) ? last_expiry : expiry;
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100450
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100451 int hi = ((float)expiry) / seconds_per_step;
452 if (hi < 0)
453 hi = 0;
454 if (hi > (w - 1))
455 hi = w - 1;
456 histogram[hi] ++;
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100457 }
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100458
459 vty_out(vty,
460 " %u tunnels, valid for %dm[",
461 count, max_expiry / 60);
462
463 int i;
464 for (i = w - 1; i >= 0; i--) {
465 char c;
466 int val = histogram[i];
467 int percent = 100. * val / count;
468 if (!val)
469 c = ' ';
470 else if (percent <= 1)
471 c = '.';
472 else if (percent <= 2)
473 c = ':';
474 else if (percent <= 10)
475 c = '|';
476 else c = '#';
477 vty_out(vty, "%c", c);
478 }
479 vty_out(vty, "]1m%s", VTY_NEWLINE);
480
481 vty_out(vty, " last expiry in %.1f min%s",
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100482 ((float)last_expiry) / 60.,
483 VTY_NEWLINE);
484}
485
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100486static void show_tunnels_all(struct vty *vty, int with_io_stats)
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100487{
488 time_t now = gtphub_now();
489
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100490 vty_out(vty, "All tunnels%s:%s"
Neels Hofmeyree07e4f2015-12-06 19:11:45 +0100491 "Legend: TEI=<hex>: SGSN <-> GGSN (expiry in minutes), with each:%s"
492 " <IP-Ctrl>[/<IP-User>] (TEI C=<TEI-Ctrl-hex> U=<TEI-User-hex>)%s",
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100493 with_io_stats? "with I/O stats" : "",
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100494 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100495
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100496 unsigned int count = 0;
497 unsigned int incomplete = 0;
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100498 struct gtphub_tunnel *tun;
499 llist_for_each_entry(tun, &g_hub->tunnels, entry) {
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100500 vty_out(vty,
Neels Hofmeyree07e4f2015-12-06 19:11:45 +0100501 "%s (expiry in %dm)%s",
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100502 gtphub_tunnel_str(tun),
Neels Hofmeyree07e4f2015-12-06 19:11:45 +0100503 (int)((tun->expiry_entry.expiry - now) / 60),
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100504 VTY_NEWLINE);
505 count ++;
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100506 if (!gtphub_tunnel_complete(tun))
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100507 incomplete ++;
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100508 if (with_io_stats)
509 show_tunnel_stats(vty, tun);
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100510 }
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100511 vty_out(vty, "Total: %u tunnels (of which %u incomplete)%s",
512 count, incomplete, VTY_NEWLINE);
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100513}
514
Neels Hofmeyr69a720f2015-12-14 15:51:31 +0100515#define SHOW_GTPHUB_STRS SHOW_STR "Show info on running GTP hub\n"
516#define SHOW_GTPHUB_PEERS_STRS SHOW_GTPHUB_STRS "Active peers\n"
517#define SHOW_GTPHUB_TUNS_STRS SHOW_GTPHUB_STRS "Active tunnels\n"
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +0100518
519DEFUN(show_gtphub_peers_summary, show_gtphub_peers_summary_cmd, "show gtphub peers summary",
Neels Hofmeyrcdc548c2015-12-14 16:11:47 +0100520 SHOW_GTPHUB_PEERS_STRS "Summary of all peers\n")
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +0100521{
522 show_peers_summary(vty);
523 return CMD_SUCCESS;
524}
525
526DEFUN(show_gtphub_peers_list, show_gtphub_peers_list_cmd, "show gtphub peers list",
Neels Hofmeyrcdc548c2015-12-14 16:11:47 +0100527 SHOW_GTPHUB_PEERS_STRS "List all peers\n")
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +0100528{
529 show_peers_all(vty, 0);
530 return CMD_SUCCESS;
531}
532
533DEFUN(show_gtphub_peers_stats, show_gtphub_peers_stats_cmd, "show gtphub peers stats",
Neels Hofmeyrcdc548c2015-12-14 16:11:47 +0100534 SHOW_GTPHUB_PEERS_STRS "List all peers with I/O stats\n")
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +0100535{
536 show_peers_all(vty, 1);
537 return CMD_SUCCESS;
538}
539
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100540DEFUN(show_gtphub_tunnels_summary, show_gtphub_tunnels_summary_cmd, "show gtphub tunnels summary",
Neels Hofmeyrcdc548c2015-12-14 16:11:47 +0100541 SHOW_GTPHUB_TUNS_STRS "Summary of all tunnels\n")
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100542{
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100543 show_tunnels_summary(vty);
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100544 return CMD_SUCCESS;
545}
546
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100547DEFUN(show_gtphub_tunnels_list, show_gtphub_tunnels_list_cmd, "show gtphub tunnels list",
Neels Hofmeyrcdc548c2015-12-14 16:11:47 +0100548 SHOW_GTPHUB_TUNS_STRS "List all tunnels\n")
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100549{
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100550 show_tunnels_all(vty, 0);
551 return CMD_SUCCESS;
552}
553
554DEFUN(show_gtphub_tunnels_stats, show_gtphub_tunnels_stats_cmd, "show gtphub tunnels stats",
Neels Hofmeyrcdc548c2015-12-14 16:11:47 +0100555 SHOW_GTPHUB_TUNS_STRS "List all tunnels with I/O stats\n")
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100556{
557 show_tunnels_all(vty, 1);
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100558 return CMD_SUCCESS;
559}
560
561DEFUN(show_gtphub, show_gtphub_cmd, "show gtphub all",
Neels Hofmeyrcdc548c2015-12-14 16:11:47 +0100562 SHOW_GTPHUB_STRS "Summarize everything about the GTP hub\n")
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200563{
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100564 show_bind_stats_all(vty);
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +0100565 show_peers_summary(vty);
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100566 show_tunnels_summary(vty);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200567 return CMD_SUCCESS;
568}
569
570
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100571int gtphub_vty_init(struct gtphub *global_hub, struct gtphub_cfg *global_cfg)
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200572{
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100573 g_hub = global_hub;
574 g_cfg = global_cfg;
575
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200576 install_element_ve(&show_gtphub_cmd);
Neels Hofmeyr4d2b3ff2015-12-07 01:13:47 +0100577 install_element_ve(&show_gtphub_peers_summary_cmd);
578 install_element_ve(&show_gtphub_peers_list_cmd);
579 install_element_ve(&show_gtphub_peers_stats_cmd);
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100580 install_element_ve(&show_gtphub_tunnels_summary_cmd);
581 install_element_ve(&show_gtphub_tunnels_list_cmd);
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100582 install_element_ve(&show_gtphub_tunnels_stats_cmd);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200583
584 install_element(CONFIG_NODE, &cfg_gtphub_cmd);
585 install_node(&gtphub_node, config_write_gtphub);
586 vty_install_default(GTPHUB_NODE);
587
588 install_element(GTPHUB_NODE, &cfg_gtphub_bind_to_sgsns_short_cmd);
589 install_element(GTPHUB_NODE, &cfg_gtphub_bind_to_sgsns_cmd);
590 install_element(GTPHUB_NODE, &cfg_gtphub_bind_to_ggsns_short_cmd);
591 install_element(GTPHUB_NODE, &cfg_gtphub_bind_to_ggsns_cmd);
592 install_element(GTPHUB_NODE, &cfg_gtphub_ggsn_proxy_short_cmd);
593 install_element(GTPHUB_NODE, &cfg_gtphub_ggsn_proxy_cmd);
594 install_element(GTPHUB_NODE, &cfg_gtphub_sgsn_proxy_short_cmd);
595 install_element(GTPHUB_NODE, &cfg_gtphub_sgsn_proxy_cmd);
Neels Hofmeyrca2361c2015-12-03 14:12:44 +0100596 install_element(GTPHUB_NODE, &cfg_gtphub_sgsn_use_sender_cmd);
597 install_element(GTPHUB_NODE, &cfg_gtphub_no_sgsn_use_sender_cmd);
Neels Hofmeyrb6c2db52015-11-18 18:11:32 +0100598 install_element(GTPHUB_NODE, &cfg_grx_ggsn_cmd);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200599
600 return 0;
601}
602
603int gtphub_cfg_read(struct gtphub_cfg *cfg, const char *config_file)
604{
605 int rc;
606
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200607 rc = vty_read_config_file(config_file, NULL);
608 if (rc < 0) {
609 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
610 return rc;
611 }
612
613 return 0;
614}