blob: 9e3c5e012b10c783e4b3ade086aba4489add72e0 [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>
22
Neels Hofmeyrb6c2db52015-11-18 18:11:32 +010023#include <ares.h>
24#include <sys/socket.h>
25#include <netinet/in.h>
26#include <arpa/inet.h>
27
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020028#include <osmocom/core/talloc.h>
29#include <osmocom/vty/command.h>
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +010030#include <osmocom/vty/misc.h>
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020031
32#include <openbsc/vty.h>
33#include <openbsc/gtphub.h>
34
Neels Hofmeyrb6c2db52015-11-18 18:11:32 +010035/* TODO split GRX ares from sgsn into a separate struct and allow use without
36 * globals. */
37#include <openbsc/sgsn.h>
38extern struct sgsn_instance *sgsn;
39
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +010040static struct gtphub *g_hub = 0;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020041static struct gtphub_cfg *g_cfg = 0;
42
43static struct cmd_node gtphub_node = {
44 GTPHUB_NODE,
45 "%s(config-gtphub)# ",
46 1,
47};
48
49#define GTPH_DEFAULT_CONTROL_PORT 2123
50#define GTPH_DEFAULT_USER_PORT 2152
51
52static void write_addrs(struct vty *vty, const char *name,
53 struct gtphub_cfg_addr *c, struct gtphub_cfg_addr *u)
54{
55 if ((c->port == GTPH_DEFAULT_CONTROL_PORT)
56 && (u->port == GTPH_DEFAULT_USER_PORT)
57 && (strcmp(c->addr_str, u->addr_str) == 0)) {
58 /* Default port numbers and same IP address: write "short"
59 * variant. */
60 vty_out(vty, " %s %s%s",
61 name,
62 c->addr_str,
63 VTY_NEWLINE);
64 return;
65 }
66
67 vty_out(vty, " %s ctrl %s %d user %s %d%s",
68 name,
69 c->addr_str, (int)c->port,
70 u->addr_str, (int)u->port,
71 VTY_NEWLINE);
Neels Hofmeyrb6c2db52015-11-18 18:11:32 +010072
73 struct ares_addr_node *server;
74 for (server = sgsn->ares_servers; server; server = server->next)
75 vty_out(vty, " grx-dns-add %s%s", inet_ntoa(server->addr.addr4), VTY_NEWLINE);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020076}
77
78static int config_write_gtphub(struct vty *vty)
79{
80 vty_out(vty, "gtphub%s", VTY_NEWLINE);
81
82 write_addrs(vty, "bind-to-sgsns",
Neels Hofmeyra9905a52015-11-29 23:49:48 +010083 &g_cfg->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].bind,
84 &g_cfg->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_USER].bind);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020085
86 write_addrs(vty, "bind-to-ggsns",
Neels Hofmeyra9905a52015-11-29 23:49:48 +010087 &g_cfg->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].bind,
88 &g_cfg->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_USER].bind);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020089
Neels Hofmeyrca2361c2015-12-03 14:12:44 +010090 if (g_cfg->sgsn_use_sender) {
91 vty_out(vty, "sgsn-use-sender%s", VTY_NEWLINE);
92 }
93
Neels Hofmeyr817bc322015-11-29 23:50:45 +010094 if (g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].addr_str) {
95 write_addrs(vty, "sgsn-proxy",
96 &g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL],
97 &g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_USER]);
98 }
99
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100100 if (g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].addr_str) {
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200101 write_addrs(vty, "ggsn-proxy",
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100102 &g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL],
103 &g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_USER]);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200104 }
105
106 return CMD_SUCCESS;
107}
108
109DEFUN(cfg_gtphub, cfg_gtphub_cmd,
110 "gtphub",
111 "Configure the GTP hub")
112{
113 vty->node = GTPHUB_NODE;
114 return CMD_SUCCESS;
115}
116
117#define BIND_ARGS "ctrl ADDR <0-65535> user ADDR <0-65535>"
118#define BIND_DOCS \
119 "Set GTP-C bind\n" \
120 "GTP-C local IP address (v4 or v6)\n" \
121 "GTP-C local port\n" \
122 "Set GTP-U bind\n" \
123 "GTP-U local IP address (v4 or v6)\n" \
124 "GTP-U local port\n"
125
126
127DEFUN(cfg_gtphub_bind_to_sgsns_short, cfg_gtphub_bind_to_sgsns_short_cmd,
128 "bind-to-sgsns ADDR",
129 "GTP Hub Parameters\n"
130 "Set the local bind address to listen for SGSNs, for both GTP-C and GTP-U\n"
131 "Local IP address (v4 or v6)\n"
132 )
133{
134 int i;
Neels Hofmeyrf9773202015-11-27 00:05:56 +0100135 for_each_plane(i)
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100136 g_cfg->to_gsns[GTPH_SIDE_SGSN][i].bind.addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
137 g_cfg->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].bind.port = GTPH_DEFAULT_CONTROL_PORT;
138 g_cfg->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_USER].bind.port = GTPH_DEFAULT_USER_PORT;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200139 return CMD_SUCCESS;
140}
141
142DEFUN(cfg_gtphub_bind_to_ggsns_short, cfg_gtphub_bind_to_ggsns_short_cmd,
143 "bind-to-ggsns ADDR",
144 "GTP Hub Parameters\n"
145 "Set the local bind address to listen for GGSNs, for both GTP-C and GTP-U\n"
146 "Local IP address (v4 or v6)\n"
147 )
148{
149 int i;
Neels Hofmeyrf9773202015-11-27 00:05:56 +0100150 for_each_plane(i)
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100151 g_cfg->to_gsns[GTPH_SIDE_GGSN][i].bind.addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
152 g_cfg->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].bind.port = GTPH_DEFAULT_CONTROL_PORT;
153 g_cfg->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_USER].bind.port = GTPH_DEFAULT_USER_PORT;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200154 return CMD_SUCCESS;
155}
156
157
158static int handle_binds(struct gtphub_cfg_bind *b, const char **argv)
159{
160 b[GTPH_PLANE_CTRL].bind.addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
161 b[GTPH_PLANE_CTRL].bind.port = atoi(argv[1]);
162 b[GTPH_PLANE_USER].bind.addr_str = talloc_strdup(tall_vty_ctx, argv[2]);
163 b[GTPH_PLANE_USER].bind.port = atoi(argv[3]);
164 return CMD_SUCCESS;
165}
166
167DEFUN(cfg_gtphub_bind_to_sgsns, cfg_gtphub_bind_to_sgsns_cmd,
168 "bind-to-sgsns " BIND_ARGS,
169 "GTP Hub Parameters\n"
170 "Set the local bind addresses and ports to listen for SGSNs\n"
171 BIND_DOCS
172 )
173{
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100174 return handle_binds(g_cfg->to_gsns[GTPH_SIDE_SGSN], argv);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200175}
176
177DEFUN(cfg_gtphub_bind_to_ggsns, cfg_gtphub_bind_to_ggsns_cmd,
178 "bind-to-ggsns " BIND_ARGS,
179 "GTP Hub Parameters\n"
180 "Set the local bind addresses and ports to listen for GGSNs\n"
181 BIND_DOCS
182 )
183{
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100184 return handle_binds(g_cfg->to_gsns[GTPH_SIDE_GGSN], argv);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200185}
186
187DEFUN(cfg_gtphub_ggsn_proxy_short, cfg_gtphub_ggsn_proxy_short_cmd,
188 "ggsn-proxy ADDR",
189 "GTP Hub Parameters\n"
190 "Redirect all GGSN bound traffic to default ports on this address (another gtphub)\n"
191 "Remote IP address (v4 or v6)\n"
192 )
193{
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100194 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
195 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].port = GTPH_DEFAULT_CONTROL_PORT;
196 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_USER].addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
197 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_USER].port = GTPH_DEFAULT_USER_PORT;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200198 return CMD_SUCCESS;
199}
200
201DEFUN(cfg_gtphub_ggsn_proxy, cfg_gtphub_ggsn_proxy_cmd,
202 "ggsn-proxy " BIND_ARGS,
203 "GTP Hub Parameters\n"
204 "Redirect all GGSN bound traffic to these addresses and ports (another gtphub)\n"
205 BIND_DOCS
206 )
207{
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100208 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
209 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].port = atoi(argv[1]);
210 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_USER].addr_str = talloc_strdup(tall_vty_ctx, argv[2]);
211 g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_USER].port = atoi(argv[3]);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200212 return CMD_SUCCESS;
213}
214
215DEFUN(cfg_gtphub_sgsn_proxy_short, cfg_gtphub_sgsn_proxy_short_cmd,
216 "sgsn-proxy ADDR",
217 "GTP Hub Parameters\n"
218 "Redirect all SGSN bound traffic to default ports on this address (another gtphub)\n"
219 "Remote IP address (v4 or v6)\n"
220 )
221{
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100222 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
223 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].port = GTPH_DEFAULT_CONTROL_PORT;
224 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_USER].addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
225 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_USER].port = GTPH_DEFAULT_USER_PORT;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200226 return CMD_SUCCESS;
227}
228
229DEFUN(cfg_gtphub_sgsn_proxy, cfg_gtphub_sgsn_proxy_cmd,
230 "sgsn-proxy " BIND_ARGS,
231 "GTP Hub Parameters\n"
232 "Redirect all SGSN bound traffic to these addresses and ports (another gtphub)\n"
233 BIND_DOCS
234 )
235{
Neels Hofmeyra9905a52015-11-29 23:49:48 +0100236 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].addr_str = talloc_strdup(tall_vty_ctx, argv[0]);
237 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].port = atoi(argv[1]);
238 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_USER].addr_str = talloc_strdup(tall_vty_ctx, argv[2]);
239 g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_USER].port = atoi(argv[3]);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200240 return CMD_SUCCESS;
241}
242
Neels Hofmeyrb6c2db52015-11-18 18:11:32 +0100243
Neels Hofmeyrca2361c2015-12-03 14:12:44 +0100244#define SGSN_USE_SENDER_STR \
245 "Ignore SGSN's Address IEs, use sender address and port (useful over NAT)\n"
246
247DEFUN(cfg_gtphub_sgsn_use_sender,
248 cfg_gtphub_sgsn_use_sender_cmd,
249 "sgsn-use-sender",
250 SGSN_USE_SENDER_STR)
251{
252 g_cfg->sgsn_use_sender = 1;
253 return CMD_SUCCESS;
254}
255
256DEFUN(cfg_gtphub_no_sgsn_use_sender,
257 cfg_gtphub_no_sgsn_use_sender_cmd,
258 "no sgsn-use-sender",
259 NO_STR SGSN_USE_SENDER_STR)
260{
261 g_cfg->sgsn_use_sender = 0;
262 return CMD_SUCCESS;
263}
264
265
Neels Hofmeyrb6c2db52015-11-18 18:11:32 +0100266/* Copied from sgsn_vty.h */
267DEFUN(cfg_grx_ggsn, cfg_grx_ggsn_cmd,
268 "grx-dns-add A.B.C.D",
269 "Add DNS server\nIPv4 address\n")
270{
271 struct ares_addr_node *node = talloc_zero(tall_bsc_ctx, struct ares_addr_node);
272 node->family = AF_INET;
273 inet_aton(argv[0], &node->addr.addr4);
274
275 node->next = sgsn->ares_servers;
276 sgsn->ares_servers = node;
277 return CMD_SUCCESS;
278}
279
280
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100281static void show_bind_stats_all(struct vty *vty)
282{
283 int plane_idx;
Neels Hofmeyrf9773202015-11-27 00:05:56 +0100284 for_each_plane(plane_idx) {
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100285 vty_out(vty, "- %s Plane:%s",
286 gtphub_plane_idx_names[plane_idx], VTY_NEWLINE);
287
Neels Hofmeyrba0525e2015-12-06 16:39:23 +0100288 int side_idx;
289 for_each_side(side_idx) {
290 struct gtphub_bind *b = &g_hub->to_gsns[side_idx][plane_idx];
291 vty_out(vty, " - to/from %ss: %s port %d%s",
292 gtphub_side_idx_names[side_idx],
293 gsn_addr_to_str(&b->local_addr), (int)b->local_port,
294 VTY_NEWLINE);
295 vty_out_rate_ctr_group(vty, " ", b->counters_io);
296 }
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100297 }
298}
299
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100300static void show_tunnel_stats(struct vty *vty, struct gtphub_tunnel *tun)
301{
302 int plane_idx;
303 for_each_plane(plane_idx) {
304 vty_out(vty, "- %s Plane:%s",
305 gtphub_plane_idx_names[plane_idx], VTY_NEWLINE);
306
307 int side_idx;
308 for_each_side(side_idx) {
309 struct gtphub_tunnel_endpoint *te = &tun->endpoint[side_idx][plane_idx];
310 vty_out(vty, " - to/from %s:%s",
311 gtphub_side_idx_names[side_idx],
312 VTY_NEWLINE);
313 vty_out_rate_ctr_group(vty, " ", te->counters_io);
314 }
315 }
316}
317
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100318/*
319static void show_peers_summary(struct vty *vty)
320{
321 int c
322 int plane_idx;
323}
324*/
325
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100326static void show_tunnels_summary(struct vty *vty)
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100327{
328 time_t now = gtphub_now();
329
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100330 const int w = 36;
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100331 int max_expiry = g_hub->expire_slowly.expiry_in_seconds;
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100332 float seconds_per_step = ((float)max_expiry) / w;
333
334 /* Print TEI mapping expiry in an ASCII histogram, like:
335 TEI map summary
336 Legend: '_'=0 '.'<=1% ':'<=2% '|'<=10% '#'>10% (10.0 m/step)
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100337 CTRL: 30 mappings, valid for 360m[# :. | . : . ]1m
338 USER: 30 mappings, valid for 360m[# :. | . : . ]1m
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100339 4 TEI mappings in total, last expiry in 359.4 min
340 */
341 vty_out(vty,
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100342 "Tunnels summary%s"
343 " Legend: ' '=0 '.'<=1%% ':'<=2%% '|'<=10%% '#'>10%% (%.1f m/step)%s",
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100344 VTY_NEWLINE,
345 seconds_per_step / 60.,
346 VTY_NEWLINE);
347
348 int last_expiry = 0;
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100349
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100350 unsigned int count = 0;
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100351
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100352 int histogram[w];
353 memset(histogram, 0, sizeof(histogram));
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100354
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100355 struct gtphub_tunnel *t;
356 llist_for_each_entry(t, &g_hub->tunnels, entry) {
357 count ++;
358 int expiry = t->expiry_entry.expiry - now;
359 last_expiry = (last_expiry > expiry) ? last_expiry : expiry;
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100360
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100361 int hi = ((float)expiry) / seconds_per_step;
362 if (hi < 0)
363 hi = 0;
364 if (hi > (w - 1))
365 hi = w - 1;
366 histogram[hi] ++;
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100367 }
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100368
369 vty_out(vty,
370 " %u tunnels, valid for %dm[",
371 count, max_expiry / 60);
372
373 int i;
374 for (i = w - 1; i >= 0; i--) {
375 char c;
376 int val = histogram[i];
377 int percent = 100. * val / count;
378 if (!val)
379 c = ' ';
380 else if (percent <= 1)
381 c = '.';
382 else if (percent <= 2)
383 c = ':';
384 else if (percent <= 10)
385 c = '|';
386 else c = '#';
387 vty_out(vty, "%c", c);
388 }
389 vty_out(vty, "]1m%s", VTY_NEWLINE);
390
391 vty_out(vty, " last expiry in %.1f min%s",
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100392 ((float)last_expiry) / 60.,
393 VTY_NEWLINE);
394}
395
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100396static void show_tunnels_all(struct vty *vty, int with_io_stats)
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100397{
398 time_t now = gtphub_now();
399
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100400 vty_out(vty, "All tunnels%s:%s"
Neels Hofmeyree07e4f2015-12-06 19:11:45 +0100401 "Legend: TEI=<hex>: SGSN <-> GGSN (expiry in minutes), with each:%s"
402 " <IP-Ctrl>[/<IP-User>] (TEI C=<TEI-Ctrl-hex> U=<TEI-User-hex>)%s",
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100403 with_io_stats? "with I/O stats" : "",
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100404 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100405
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100406 unsigned int count = 0;
407 unsigned int incomplete = 0;
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100408 struct gtphub_tunnel *tun;
409 llist_for_each_entry(tun, &g_hub->tunnels, entry) {
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100410 vty_out(vty,
Neels Hofmeyree07e4f2015-12-06 19:11:45 +0100411 "%s (expiry in %dm)%s",
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100412 gtphub_tunnel_str(tun),
Neels Hofmeyree07e4f2015-12-06 19:11:45 +0100413 (int)((tun->expiry_entry.expiry - now) / 60),
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100414 VTY_NEWLINE);
415 count ++;
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100416 if (!gtphub_tunnel_complete(tun))
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100417 incomplete ++;
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100418 if (with_io_stats)
419 show_tunnel_stats(vty, tun);
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100420 }
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100421 vty_out(vty, "Total: %u tunnels (of which %u incomplete)%s",
422 count, incomplete, VTY_NEWLINE);
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100423}
424
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100425DEFUN(show_gtphub_tunnels_summary, show_gtphub_tunnels_summary_cmd, "show gtphub tunnels summary",
426 SHOW_STR "Summary of all tunnels")
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100427{
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100428 show_tunnels_summary(vty);
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100429 return CMD_SUCCESS;
430}
431
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100432DEFUN(show_gtphub_tunnels_list, show_gtphub_tunnels_list_cmd, "show gtphub tunnels list",
433 SHOW_STR "List all tunnels")
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100434{
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100435 show_tunnels_all(vty, 0);
436 return CMD_SUCCESS;
437}
438
439DEFUN(show_gtphub_tunnels_stats, show_gtphub_tunnels_stats_cmd, "show gtphub tunnels stats",
440 SHOW_STR "List all tunnels with I/O stats")
441{
442 show_tunnels_all(vty, 1);
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100443 return CMD_SUCCESS;
444}
445
446DEFUN(show_gtphub, show_gtphub_cmd, "show gtphub all",
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200447 SHOW_STR "Display information about the GTP hub")
448{
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100449 show_bind_stats_all(vty);
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100450 show_tunnels_summary(vty);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200451 return CMD_SUCCESS;
452}
453
454
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100455int gtphub_vty_init(struct gtphub *global_hub, struct gtphub_cfg *global_cfg)
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200456{
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100457 g_hub = global_hub;
458 g_cfg = global_cfg;
459
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200460 install_element_ve(&show_gtphub_cmd);
Neels Hofmeyre54cd152015-11-24 13:31:06 +0100461 install_element_ve(&show_gtphub_tunnels_summary_cmd);
462 install_element_ve(&show_gtphub_tunnels_list_cmd);
Neels Hofmeyre38fb662015-12-06 16:44:14 +0100463 install_element_ve(&show_gtphub_tunnels_stats_cmd);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200464
465 install_element(CONFIG_NODE, &cfg_gtphub_cmd);
466 install_node(&gtphub_node, config_write_gtphub);
467 vty_install_default(GTPHUB_NODE);
468
469 install_element(GTPHUB_NODE, &cfg_gtphub_bind_to_sgsns_short_cmd);
470 install_element(GTPHUB_NODE, &cfg_gtphub_bind_to_sgsns_cmd);
471 install_element(GTPHUB_NODE, &cfg_gtphub_bind_to_ggsns_short_cmd);
472 install_element(GTPHUB_NODE, &cfg_gtphub_bind_to_ggsns_cmd);
473 install_element(GTPHUB_NODE, &cfg_gtphub_ggsn_proxy_short_cmd);
474 install_element(GTPHUB_NODE, &cfg_gtphub_ggsn_proxy_cmd);
475 install_element(GTPHUB_NODE, &cfg_gtphub_sgsn_proxy_short_cmd);
476 install_element(GTPHUB_NODE, &cfg_gtphub_sgsn_proxy_cmd);
Neels Hofmeyrca2361c2015-12-03 14:12:44 +0100477 install_element(GTPHUB_NODE, &cfg_gtphub_sgsn_use_sender_cmd);
478 install_element(GTPHUB_NODE, &cfg_gtphub_no_sgsn_use_sender_cmd);
Neels Hofmeyrb6c2db52015-11-18 18:11:32 +0100479 install_element(GTPHUB_NODE, &cfg_grx_ggsn_cmd);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200480
481 return 0;
482}
483
484int gtphub_cfg_read(struct gtphub_cfg *cfg, const char *config_file)
485{
486 int rc;
487
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200488 rc = vty_read_config_file(config_file, NULL);
489 if (rc < 0) {
490 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
491 return rc;
492 }
493
494 return 0;
495}