blob: 92915fea00829bb7f2db39957bc94a9c6159d983 [file] [log] [blame]
Harald Welte799e0c92010-04-30 21:49:24 +02001/*
2 * (C) 2010 by Harald Welte <laforge@gnumonks.org>
3 * (C) 2010 by On-Waves
4 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01007 * 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
Harald Welte799e0c92010-04-30 21:49:24 +02009 * (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
Harald Welte9af6ddf2011-01-01 15:25:50 +010014 * GNU Affero General Public License for more details.
Harald Welte799e0c92010-04-30 21:49:24 +020015 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * 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/>.
Harald Welte799e0c92010-04-30 21:49:24 +020018 *
19 */
20
Harald Welte799e0c92010-04-30 21:49:24 +020021#include <sys/socket.h>
22#include <netinet/in.h>
23#include <arpa/inet.h>
Jacob Erlbeck73685282014-05-23 20:48:07 +020024#include <string.h>
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +020025#include <time.h>
Pau Espin Pedrol67f1d1e2018-08-16 12:11:46 +020026#include <inttypes.h>
Harald Welte799e0c92010-04-30 21:49:24 +020027
Daniel Willmannef3c9af2020-12-14 16:22:39 +010028#include <osmocom/core/hashtable.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010029#include <osmocom/core/talloc.h>
Alexander Couzens82182d02020-09-22 13:21:46 +020030#include <osmocom/core/timer.h>
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +020031#include <osmocom/core/rate_ctr.h>
Harald Welte799e0c92010-04-30 21:49:24 +020032
Alexander Couzens82182d02020-09-22 13:21:46 +020033#include <osmocom/gprs/gprs_ns2.h>
Harald Welte5687ae62020-12-05 19:59:45 +010034#include <osmocom/gprs/bssgp_bvc_fsm.h>
Daniel Willmannef3c9af2020-12-14 16:22:39 +010035
Harald Welte7e82b742017-08-12 13:43:54 +020036#include <osmocom/gsm/apn.h>
Daniel Willmannef3c9af2020-12-14 16:22:39 +010037#include <osmocom/gsm/gsm23236.h>
38#include <osmocom/gsm/gsm48.h>
Harald Welteea34a4e2012-06-16 14:59:56 +080039
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020040#include <osmocom/sgsn/debug.h>
41#include <osmocom/sgsn/gb_proxy.h>
42#include <osmocom/sgsn/gprs_utils.h>
43#include <osmocom/sgsn/vty.h>
Harald Welte799e0c92010-04-30 21:49:24 +020044
Harald Welte4b037e42010-05-19 19:45:32 +020045#include <osmocom/vty/command.h>
Daniel Willmanne8c8ec92020-12-02 19:33:50 +010046#include <osmocom/vty/logging.h>
Harald Welte4b037e42010-05-19 19:45:32 +020047#include <osmocom/vty/vty.h>
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +020048#include <osmocom/vty/misc.h>
Harald Welte799e0c92010-04-30 21:49:24 +020049
Daniel Willmannef3c9af2020-12-14 16:22:39 +010050#define NRI_STR "Mapping of Network Resource Indicators to this SGSN, for SGSN pooling\n"
51#define NULL_NRI_STR "Define NULL-NRI values that cause re-assignment of an MS to a different SGSN, for SGSN pooling.\n"
52#define NRI_FIRST_LAST_STR "First value of the NRI value range, should not surpass the configured 'nri bitlen'.\n" \
53 "Last value of the NRI value range, should not surpass the configured 'nri bitlen' and be larger than the" \
54 " first value; if omitted, apply only the first value.\n"
55#define NRI_ARGS_TO_STR_FMT "%s%s%s"
56#define NRI_ARGS_TO_STR_ARGS(ARGC, ARGV) ARGV[0], (ARGC>1)? ".." : "", (ARGC>1)? ARGV[1] : ""
57#define NRI_WARN(SGSN, FORMAT, args...) do { \
58 vty_out(vty, "%% Warning: NSE(%05d/SGSN): " FORMAT "%s", (SGSN)->nse->nsei, ##args, VTY_NEWLINE); \
59 LOGP(DLBSSGP, LOGL_ERROR, "NSE(%05d/SGSN): " FORMAT "\n", (SGSN)->nse->nsei, ##args); \
60 } while (0)
Harald Welte5687ae62020-12-05 19:59:45 +010061
Harald Welte799e0c92010-04-30 21:49:24 +020062static struct gbproxy_config *g_cfg = NULL;
63
64/*
Pau Espin Pedrol94998fa2018-06-20 23:55:22 +020065 * vty code for gbproxy below
Harald Welte799e0c92010-04-30 21:49:24 +020066 */
Harald Welteb77c6972010-05-01 11:28:43 +020067static struct cmd_node gbproxy_node = {
Harald Welte799e0c92010-04-30 21:49:24 +020068 GBPROXY_NODE,
Harald Welte570ce242012-08-17 13:16:10 +020069 "%s(config-gbproxy)# ",
Harald Welte799e0c92010-04-30 21:49:24 +020070 1,
71};
72
Harald Welte8cd74402020-12-04 22:24:47 +010073static void gbprox_vty_print_bvc(struct vty *vty, struct gbproxy_bvc *bvc)
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +020074{
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +020075
Harald Welte959f77e2020-12-12 14:17:51 +010076 if (bvc->bvci == 0) {
77 vty_out(vty, "NSEI %5u, SIG-BVCI %5u [%s]%s", bvc->nse->nsei, bvc->bvci,
78 osmo_fsm_inst_state_name(bvc->fi), VTY_NEWLINE);
79 } else {
80 struct gprs_ra_id raid;
81 gsm48_parse_ra(&raid, bvc->ra);
82 vty_out(vty, "NSEI %5u, PTP-BVCI %5u, RAI %s [%s]%s", bvc->nse->nsei, bvc->bvci,
83 osmo_rai_name(&raid), osmo_fsm_inst_state_name(bvc->fi), VTY_NEWLINE);
84 }
85}
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +020086
Harald Welte959f77e2020-12-12 14:17:51 +010087static void gbproxy_vty_print_nse(struct vty *vty, struct gbproxy_nse *nse, bool show_stats)
88{
89 struct gbproxy_bvc *bvc;
90 int j;
91
92 hash_for_each(nse->bvcs, j, bvc, list) {
93 gbprox_vty_print_bvc(vty, bvc);
94
95 if (show_stats)
96 vty_out_rate_ctr_group(vty, " ", bvc->ctrg);
97 }
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +020098}
99
Harald Welte5a21f072020-12-12 15:16:43 +0100100static void gbproxy_vty_print_cell(struct vty *vty, struct gbproxy_cell *cell, bool show_stats)
101{
102 struct gprs_ra_id raid;
103 gsm48_parse_ra(&raid, cell->ra);
104 unsigned int num_sgsn_bvc = 0;
105 unsigned int i;
106
107 vty_out(vty, "BVCI %5u RAI %s: ", cell->bvci, osmo_rai_name(&raid));
108 if (cell->bss_bvc)
109 vty_out(vty, "BSS NSEI %5u, SGSN NSEI ", cell->bss_bvc->nse->nsei);
110 else
111 vty_out(vty, "BSS NSEI <none>, SGSN NSEI ");
112
113 for (i = 0; i < ARRAY_SIZE(cell->sgsn_bvc); i++) {
114 struct gbproxy_bvc *sgsn_bvc = cell->sgsn_bvc[i];
115 if (sgsn_bvc) {
116 vty_out(vty, "%5u ", sgsn_bvc->nse->nsei);
117 num_sgsn_bvc++;
118 }
119 }
120 if (num_sgsn_bvc)
121 vty_out(vty, "%s", VTY_NEWLINE);
122 else
123 vty_out(vty, "<none>%s", VTY_NEWLINE);
124}
125
Harald Welte799e0c92010-04-30 21:49:24 +0200126static int config_write_gbproxy(struct vty *vty)
127{
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100128 struct osmo_nri_range *r;
Harald Welte5687ae62020-12-05 19:59:45 +0100129
Harald Welte799e0c92010-04-30 21:49:24 +0200130 vty_out(vty, "gbproxy%s", VTY_NEWLINE);
131
Harald Welte9e917642020-12-12 19:02:16 +0100132 if (g_cfg->pool.bvc_fc_ratio != 100)
133 vty_out(vty, " pool bvc-flow-control-ratio %u%s", g_cfg->pool.bvc_fc_ratio, VTY_NEWLINE);
134
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100135 if (g_cfg->pool.nri_bitlen != OSMO_NRI_BITLEN_DEFAULT)
136 vty_out(vty, " nri bitlen %u%s", g_cfg->pool.nri_bitlen, VTY_NEWLINE);
Harald Welte799e0c92010-04-30 21:49:24 +0200137
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100138 llist_for_each_entry(r, &g_cfg->pool.null_nri_ranges->entries, entry) {
139 vty_out(vty, " nri null add %d", r->first);
140 if (r->first != r->last)
141 vty_out(vty, " %d", r->last);
142 vty_out(vty, "%s", VTY_NEWLINE);
143 }
Harald Welte799e0c92010-04-30 21:49:24 +0200144 return CMD_SUCCESS;
145}
146
Harald Welte799e0c92010-04-30 21:49:24 +0200147DEFUN(cfg_gbproxy,
148 cfg_gbproxy_cmd,
149 "gbproxy",
150 "Configure the Gb proxy")
151{
152 vty->node = GBPROXY_NODE;
153 return CMD_SUCCESS;
154}
155
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100156/* VTY code for SGSN (pool) configuration */
Harald Welte5687ae62020-12-05 19:59:45 +0100157extern const struct bssgp_bvc_fsm_ops sgsn_sig_bvc_fsm_ops;
158#include <osmocom/gprs/protocol/gsm_08_18.h>
159
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100160static struct cmd_node sgsn_node = {
161 SGSN_NODE,
162 "%s(config-sgsn)# ",
163 1,
164};
165
166static void sgsn_write_nri(struct vty *vty, struct gbproxy_sgsn *sgsn, bool verbose)
167{
168 struct osmo_nri_range *r;
169
170 if (verbose) {
171 vty_out(vty, "sgsn nsei %d%s", sgsn->nse->nsei, VTY_NEWLINE);
172 if (llist_empty(&sgsn->pool.nri_ranges->entries)) {
173 vty_out(vty, " %% no NRI mappings%s", VTY_NEWLINE);
174 return;
175 }
176 }
177
178 llist_for_each_entry(r, &sgsn->pool.nri_ranges->entries, entry) {
179 if (osmo_nri_range_validate(r, 255))
180 vty_out(vty, " %% INVALID RANGE:");
181 vty_out(vty, " nri add %d", r->first);
182 if (r->first != r->last)
183 vty_out(vty, " %d", r->last);
184 vty_out(vty, "%s", VTY_NEWLINE);
185 }
186}
187
188static void write_sgsn(struct vty *vty, struct gbproxy_sgsn *sgsn)
189{
190 vty_out(vty, "sgsn nsei %u%s", sgsn->nse->nsei, VTY_NEWLINE);
191 vty_out(vty, " %sallow-attach%s", sgsn->pool.allow_attach ? "" : "no ", VTY_NEWLINE);
192 sgsn_write_nri(vty, sgsn, false);
193}
194
195static int config_write_sgsn(struct vty *vty)
196{
197 struct gbproxy_sgsn *sgsn;
198
199 llist_for_each_entry(sgsn, &g_cfg->sgsns, list)
200 write_sgsn(vty, sgsn);
201
202 return CMD_SUCCESS;
203}
204
205DEFUN(cfg_sgsn_nsei,
206 cfg_sgsn_nsei_cmd,
Harald Welteff3bde82010-05-19 15:09:09 +0200207 "sgsn nsei <0-65534>",
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100208 "Configure the SGSN\n"
Holger Hans Peter Freyther2eb6e2c2011-11-05 15:14:59 +0100209 "NSEI to be used in the connection with the SGSN\n"
210 "The NSEI\n")
Harald Welte799e0c92010-04-30 21:49:24 +0200211{
Harald Welte5687ae62020-12-05 19:59:45 +0100212 uint32_t features = 0; // FIXME: make configurable
Jacob Erlbeckcc8856f2014-10-08 13:37:28 +0200213 unsigned int nsei = atoi(argv[0]);
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100214 unsigned int num_sgsn = llist_count(&g_cfg->sgsns);
215 struct gbproxy_sgsn *sgsn;
Harald Welte5687ae62020-12-05 19:59:45 +0100216 struct gbproxy_nse *nse;
217 struct gbproxy_bvc *bvc;
Harald Welte799e0c92010-04-30 21:49:24 +0200218
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100219 if (num_sgsn >= GBPROXY_MAX_NR_SGSN) {
220 vty_out(vty, "%% Too many SGSN NSE defined (%d), increase GBPROXY_MAX_NR_SGSN%s",
221 num_sgsn, VTY_NEWLINE);
222 return CMD_WARNING;
223 }
224
225 /* This will have created the gbproxy_nse as well */
226 sgsn = gbproxy_sgsn_by_nsei_or_new(g_cfg, nsei);
227 if (!sgsn)
Harald Welte5687ae62020-12-05 19:59:45 +0100228 goto free_nothing;
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100229 nse = sgsn->nse;
230 if (num_sgsn > 1 && g_cfg->pool.nri_bitlen == 0)
231 vty_out(vty, "%% Multiple SGSNs defined, but no pooling enabled%s", VTY_NEWLINE);
232
Harald Welte5687ae62020-12-05 19:59:45 +0100233
234 if (!gbproxy_bvc_by_bvci(nse, 0)) {
235 uint8_t cause = BSSGP_CAUSE_OML_INTERV;
236 bvc = gbproxy_bvc_alloc(nse, 0);
237 if (!bvc)
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100238 goto free_sgsn;
Harald Welte5687ae62020-12-05 19:59:45 +0100239 bvc->fi = bssgp_bvc_fsm_alloc_sig_bss(bvc, nse->cfg->nsi, nsei, features);
240 if (!bvc->fi)
241 goto free_bvc;
242 bssgp_bvc_fsm_set_ops(bvc->fi, &sgsn_sig_bvc_fsm_ops, bvc);
243 osmo_fsm_inst_dispatch(bvc->fi, BSSGP_BVCFSM_E_REQ_RESET, &cause);
244 }
245
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100246 vty->node = SGSN_NODE;
247 vty->index = sgsn;
Harald Welte799e0c92010-04-30 21:49:24 +0200248 return CMD_SUCCESS;
Harald Welte5687ae62020-12-05 19:59:45 +0100249
250free_bvc:
251 gbproxy_bvc_free(bvc);
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100252free_sgsn:
253 gbproxy_sgsn_free(sgsn);
Harald Welte5687ae62020-12-05 19:59:45 +0100254free_nothing:
255 vty_out(vty, "%% Unable to create NSE for NSEI=%05u%s", nsei, VTY_NEWLINE);
256 return CMD_WARNING;
Harald Welte799e0c92010-04-30 21:49:24 +0200257}
258
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100259DEFUN_ATTR(cfg_sgsn_nri_add, cfg_sgsn_nri_add_cmd,
260 "nri add <0-32767> [<0-32767>]",
261 NRI_STR "Add NRI value or range to the NRI mapping for this MSC\n"
262 NRI_FIRST_LAST_STR,
263 CMD_ATTR_IMMEDIATE)
264{
265 struct gbproxy_sgsn *sgsn = vty->index;
266 struct gbproxy_sgsn *other_sgsn;
267 bool before;
268 int rc;
269 const char *message;
270 struct osmo_nri_range add_range;
271
272 rc = osmo_nri_ranges_vty_add(&message, &add_range, sgsn->pool.nri_ranges, argc, argv, g_cfg->pool.nri_bitlen);
273 if (message) {
274 NRI_WARN(sgsn, "%s: " NRI_ARGS_TO_STR_FMT, message, NRI_ARGS_TO_STR_ARGS(argc, argv));
275 }
276 if (rc < 0)
277 return CMD_WARNING;
278
279 /* Issue a warning about NRI range overlaps (but still allow them).
280 * Overlapping ranges will map to whichever SGSN comes fist in the gbproxy_config->sgsns llist,
281 * which should be the first one defined in the config */
282 before = true;
283
284 llist_for_each_entry(other_sgsn, &g_cfg->sgsns, list) {
285 if (other_sgsn == sgsn) {
286 before = false;
287 continue;
288 }
289 if (osmo_nri_range_overlaps_ranges(&add_range, other_sgsn->pool.nri_ranges)) {
290 uint16_t nsei = sgsn->nse->nsei;
291 uint16_t other_nsei = other_sgsn->nse->nsei;
292 NRI_WARN(sgsn, "NRI range [%d..%d] overlaps between NSE %05d and NSE %05d."
293 " For overlaps, NSE %05d has higher priority than NSE %05d",
294 add_range.first, add_range.last, nsei, other_nsei,
295 before ? other_nsei : nsei, before ? nsei : other_nsei);
296 }
297 }
298 return CMD_SUCCESS;
299}
300
301DEFUN_ATTR(cfg_sgsn_nri_del, cfg_sgsn_nri_del_cmd,
302 "nri del <0-32767> [<0-32767>]",
303 NRI_STR "Remove NRI value or range from the NRI mapping for this MSC\n"
304 NRI_FIRST_LAST_STR,
305 CMD_ATTR_IMMEDIATE)
306{
307 struct gbproxy_sgsn *sgsn = vty->index;
308 int rc;
309 const char *message;
310
311 rc = osmo_nri_ranges_vty_del(&message, NULL, sgsn->pool.nri_ranges, argc, argv);
312 if (message) {
313 NRI_WARN(sgsn, "%s: " NRI_ARGS_TO_STR_FMT, message, NRI_ARGS_TO_STR_ARGS(argc, argv));
314 }
315 if (rc < 0)
316 return CMD_WARNING;
317 return CMD_SUCCESS;
318}
319
320DEFUN_ATTR(cfg_sgsn_allow_attach, cfg_sgsn_allow_attach_cmd,
321 "allow-attach",
322 "Allow this SGSN to attach new subscribers (default).\n",
323 CMD_ATTR_IMMEDIATE)
324{
325 struct gbproxy_sgsn *sgsn = vty->index;
326 sgsn->pool.allow_attach = true;
327 return CMD_SUCCESS;
328}
329
330DEFUN_ATTR(cfg_sgsn_no_allow_attach, cfg_sgsn_no_allow_attach_cmd,
331 "no allow-attach",
332 NO_STR
333 "Do not assign new subscribers to this MSC."
334 " Useful if an MSC in an MSC pool is configured to off-load subscribers."
335 " The MSC will still be operational for already IMSI-Attached subscribers,"
336 " but the NAS node selection function will skip this MSC for new subscribers\n",
337 CMD_ATTR_IMMEDIATE)
338{
339 struct gbproxy_sgsn *sgsn = vty->index;
340 sgsn->pool.allow_attach = false;
341 return CMD_SUCCESS;
342}
343
344DEFUN(cfg_sgsn_show_nri_all, show_nri_all_cmd,
345 "show nri all",
346 SHOW_STR NRI_STR "Show all SGSNs\n")
347{
348 struct gbproxy_sgsn *sgsn;
349
350 llist_for_each_entry(sgsn, &g_cfg->sgsns, list)
351 sgsn_write_nri(vty, sgsn, true);
352
353 return CMD_SUCCESS;
354}
355
356DEFUN(show_nri, show_nri_nsei_cmd,
357 "show nri nsei <0-65535>",
358 SHOW_STR NRI_STR "Identify SGSN by NSEI\n"
359 "NSEI of the SGSN\n")
360{
361 struct gbproxy_sgsn *sgsn;
362 int nsei = atoi(argv[0]);
363
364 sgsn = gbproxy_sgsn_by_nsei(g_cfg, nsei);
365 if (!sgsn) {
366 vty_out(vty, "%% No SGSN with found for NSEI %05d%s", nsei, VTY_NEWLINE);
367 return CMD_SUCCESS;
368 }
369 sgsn_write_nri(vty, sgsn, true);
370
371 return CMD_SUCCESS;
372}
373
Harald Welte9e917642020-12-12 19:02:16 +0100374DEFUN(cfg_pool_bvc_fc_ratio,
375 cfg_pool_bvc_fc_ratio_cmd,
376 "pool bvc-flow-control-ratio <1-100>",
377 "SGSN Pool related configuration\n"
378 "Ratio of BSS-advertised bucket size + leak rate advertised to each SGSN\n"
379 "Ratio of BSS-advertised bucket size + leak rate advertised to each SGSN (Percent)\n")
380{
381 g_cfg->pool.bvc_fc_ratio = atoi(argv[0]);
382 return CMD_SUCCESS;
383}
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100384DEFUN_ATTR(cfg_gbproxy_nri_bitlen,
385 cfg_gbproxy_nri_bitlen_cmd,
386 "nri bitlen <0-15>",
387 NRI_STR
388 "Set number of bits that an NRI has, to extract from TMSI identities (always starting just after the TMSI's most significant octet).\n"
389 "bit count (0 disables) pooling)\n",
390 CMD_ATTR_IMMEDIATE)
391{
392 g_cfg->pool.nri_bitlen = atoi(argv[0]);
393
394 if (llist_count(&g_cfg->sgsns) > 1 && g_cfg->pool.nri_bitlen == 0)
395 vty_out(vty, "%% Pooling disabled, but multiple SGSNs defined%s", VTY_NEWLINE);
396
397 /* TODO: Verify all nri ranges and warn on mismatch */
398
399 return CMD_SUCCESS;
400}
401
402DEFUN_ATTR(cfg_gbproxy_nri_null_add,
403 cfg_gbproxy_nri_null_add_cmd,
404 "nri null add <0-32767> [<0-32767>]",
405 NRI_STR NULL_NRI_STR "Add NULL-NRI value (or range)\n"
406 NRI_FIRST_LAST_STR,
407 CMD_ATTR_IMMEDIATE)
408{
409 int rc;
410 const char *message;
411
412 rc = osmo_nri_ranges_vty_add(&message, NULL, g_cfg->pool.null_nri_ranges, argc, argv,
413 g_cfg->pool.nri_bitlen);
414 if (message) {
415 vty_out(vty, "%% nri null add: %s: " NRI_ARGS_TO_STR_FMT "%s", message, NRI_ARGS_TO_STR_ARGS(argc, argv),
416 VTY_NEWLINE);
417 vty_out(vty, "%s: \n" NRI_ARGS_TO_STR_FMT, message, NRI_ARGS_TO_STR_ARGS(argc, argv));
418 }
419 if (rc < 0)
420 return CMD_WARNING;
421 return CMD_SUCCESS;
422}
423
424DEFUN_ATTR(cfg_gbproxy_nri_null_del,
425 cfg_gbproxy_nri_null_del_cmd,
426 "nri null del <0-32767> [<0-32767>]",
427 NRI_STR NULL_NRI_STR "Remove NRI value or range from the NRI mapping for this MSC\n"
428 NRI_FIRST_LAST_STR,
429 CMD_ATTR_IMMEDIATE)
430{
431 int rc;
432 const char *message;
433 rc = osmo_nri_ranges_vty_del(&message, NULL, g_cfg->pool.null_nri_ranges, argc, argv);
434 if (message) {
435 vty_out(vty, "%% %s: " NRI_ARGS_TO_STR_FMT "%s", message, NRI_ARGS_TO_STR_ARGS(argc, argv),
436 VTY_NEWLINE);
437 }
438 if (rc < 0)
439 return CMD_WARNING;
440 return CMD_SUCCESS;
441}
Harald Welte9e917642020-12-12 19:02:16 +0100442
Daniel Willmanne8c8ec92020-12-02 19:33:50 +0100443static void log_set_bvc_filter(struct log_target *target,
444 const uint16_t *bvci)
445{
446 if (bvci) {
447 uintptr_t bvci_filter = *bvci | BVC_LOG_CTX_FLAG;
448 target->filter_map |= (1 << LOG_FLT_GB_BVC);
449 target->filter_data[LOG_FLT_GB_BVC] = (void *)bvci_filter;
450 } else if (target->filter_data[LOG_FLT_GB_BVC]) {
451 target->filter_map = ~(1 << LOG_FLT_GB_BVC);
452 target->filter_data[LOG_FLT_GB_BVC] = NULL;
453 }
454}
455
456DEFUN(logging_fltr_bvc,
457 logging_fltr_bvc_cmd,
458 "logging filter bvc bvci <0-65535>",
459 LOGGING_STR FILTER_STR
460 "Filter based on BSSGP VC\n"
461 "Identify BVC by BVCI\n"
462 "Numeric identifier\n")
463{
464 struct log_target *tgt;
465 uint16_t id = atoi(argv[0]);
466
467 log_tgt_mutex_lock();
468 tgt = osmo_log_vty2tgt(vty);
469 if (!tgt) {
470 log_tgt_mutex_unlock();
471 return CMD_WARNING;
472 }
473
474 log_set_bvc_filter(tgt, &id);
475 log_tgt_mutex_unlock();
476 return CMD_SUCCESS;
477}
Jacob Erlbeck7c101d92014-06-06 18:49:23 +0200478
Harald Welteb6b2f142020-12-12 15:15:34 +0100479DEFUN(show_gbproxy_bvc, show_gbproxy_bvc_cmd, "show gbproxy bvc (bss|sgsn) [stats]",
Harald Welte959f77e2020-12-12 14:17:51 +0100480 SHOW_STR "Display information about the Gb proxy\n"
Harald Welteb6b2f142020-12-12 15:15:34 +0100481 "Show BSSGP Virtual Connections\n"
Harald Welte959f77e2020-12-12 14:17:51 +0100482 "Display BSS-side BVCs\n"
483 "Display SGSN-side BVCs\n"
484 "Show statistics\n")
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200485{
Daniel Willmann447ad442020-11-26 18:19:21 +0100486 struct gbproxy_nse *nse;
Harald Welte959f77e2020-12-12 14:17:51 +0100487 bool show_stats = argc >= 2;
488 int i;
Jacob Erlbeck91fb6802014-05-28 10:59:10 +0200489
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200490 if (show_stats)
Holger Hans Peter Freythereece6272014-08-04 15:42:36 +0200491 vty_out_rate_ctr_group(vty, "", g_cfg->ctrg);
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200492
Harald Welte959f77e2020-12-12 14:17:51 +0100493 if (!strcmp(argv[0], "bss")) {
494 hash_for_each(g_cfg->bss_nses, i, nse, list)
495 gbproxy_vty_print_nse(vty, nse, show_stats);
496 } else {
497 hash_for_each(g_cfg->sgsn_nses, i, nse, list)
498 gbproxy_vty_print_nse(vty, nse, show_stats);
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200499 }
500 return CMD_SUCCESS;
501}
502
Harald Welte5a21f072020-12-12 15:16:43 +0100503DEFUN(show_gbproxy_cell, show_gbproxy_cell_cmd, "show gbproxy cell [stats]",
504 SHOW_STR "Display information about the Gb proxy\n"
505 "Show GPRS Cell Information\n"
506 "Show statistics\n")
507{
508 struct gbproxy_cell *cell;
509 bool show_stats = argc >= 1;
510 int i;
511
512 hash_for_each(g_cfg->cells, i, cell, list)
513 gbproxy_vty_print_cell(vty, cell, show_stats);
514
515 return CMD_SUCCESS;
516}
517
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200518DEFUN(show_gbproxy_links, show_gbproxy_links_cmd, "show gbproxy links",
519 SHOW_STR "Display information about the Gb proxy\n" "Show logical links\n")
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200520{
Daniel Willmann447ad442020-11-26 18:19:21 +0100521 struct gbproxy_nse *nse;
Harald Welte993d3f42020-12-05 10:14:49 +0100522 int i, j;
Jacob Erlbeckc6807c42014-09-19 16:34:01 +0200523
Harald Welte78db2442020-12-05 00:31:07 +0100524 hash_for_each(g_cfg->bss_nses, i, nse, list) {
Harald Welte8cd74402020-12-04 22:24:47 +0100525 struct gbproxy_bvc *bvc;
Harald Welte993d3f42020-12-05 10:14:49 +0100526 hash_for_each(nse->bvcs, j, bvc, list) {
Harald Welte8cd74402020-12-04 22:24:47 +0100527 gbprox_vty_print_bvc(vty, bvc);
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200528 }
529 }
530 return CMD_SUCCESS;
531}
532
533DEFUN(delete_gb_bvci, delete_gb_bvci_cmd,
534 "delete-gbproxy-peer <0-65534> bvci <2-65534>",
Harald Welte8cd74402020-12-04 22:24:47 +0100535 "Delete a GBProxy bvc by NSEI and optionally BVCI\n"
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200536 "NSEI number\n"
Harald Welte8cd74402020-12-04 22:24:47 +0100537 "Only delete bvc with a matching BVCI\n"
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200538 "BVCI number\n")
539{
540 const uint16_t nsei = atoi(argv[0]);
541 const uint16_t bvci = atoi(argv[1]);
Harald Welte5687ae62020-12-05 19:59:45 +0100542 struct gbproxy_nse *nse = gbproxy_nse_by_nsei(g_cfg, nsei, NSE_F_BSS);
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200543 int counter;
544
Harald Welte5687ae62020-12-05 19:59:45 +0100545 if (!nse) {
546 vty_out(vty, "NSE not found%s", VTY_NEWLINE);
547 return CMD_WARNING;
548 }
549
550 counter = gbproxy_cleanup_bvcs(nse, bvci);
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200551
552 if (counter == 0) {
553 vty_out(vty, "BVC not found%s", VTY_NEWLINE);
554 return CMD_WARNING;
555 }
556
557 return CMD_SUCCESS;
558}
559
560DEFUN(delete_gb_nsei, delete_gb_nsei_cmd,
561 "delete-gbproxy-peer <0-65534> (only-bvc|only-nsvc|all) [dry-run]",
Harald Welte8cd74402020-12-04 22:24:47 +0100562 "Delete a GBProxy bvc by NSEI and optionally BVCI\n"
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200563 "NSEI number\n"
564 "Only delete BSSGP connections (BVC)\n"
565 "Only delete dynamic NS connections (NS-VC)\n"
566 "Delete BVC and dynamic NS connections\n"
567 "Show what would be deleted instead of actually deleting\n"
568 )
569{
570 const uint16_t nsei = atoi(argv[0]);
571 const char *mode = argv[1];
572 int dry_run = argc > 2;
573 int delete_bvc = 0;
574 int delete_nsvc = 0;
575 int counter;
576
577 if (strcmp(mode, "only-bvc") == 0)
578 delete_bvc = 1;
579 else if (strcmp(mode, "only-nsvc") == 0)
580 delete_nsvc = 1;
581 else
582 delete_bvc = delete_nsvc = 1;
583
584 if (delete_bvc) {
Daniel Willmann9a2fc902020-12-04 17:43:27 +0100585 if (!dry_run) {
Harald Welte5687ae62020-12-05 19:59:45 +0100586 struct gbproxy_nse *nse = gbproxy_nse_by_nsei(g_cfg, nsei, NSE_F_BSS);
587 counter = gbproxy_cleanup_bvcs(nse, 0);
Daniel Willmann9a2fc902020-12-04 17:43:27 +0100588 gbproxy_nse_free(nse);
589 } else {
Daniel Willmann447ad442020-11-26 18:19:21 +0100590 struct gbproxy_nse *nse;
Harald Welte8cd74402020-12-04 22:24:47 +0100591 struct gbproxy_bvc *bvc;
Harald Welte993d3f42020-12-05 10:14:49 +0100592 int i, j;
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200593 counter = 0;
Harald Welte78db2442020-12-05 00:31:07 +0100594 hash_for_each(g_cfg->bss_nses, i, nse, list) {
Daniel Willmann447ad442020-11-26 18:19:21 +0100595 if (nse->nsei != nsei)
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200596 continue;
Harald Welte993d3f42020-12-05 10:14:49 +0100597 hash_for_each(nse->bvcs, j, bvc, list) {
Daniel Willmann447ad442020-11-26 18:19:21 +0100598 vty_out(vty, "BVC: ");
Harald Welte8cd74402020-12-04 22:24:47 +0100599 gbprox_vty_print_bvc(vty, bvc);
Daniel Willmann447ad442020-11-26 18:19:21 +0100600 counter += 1;
601 }
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200602 }
603 }
604 vty_out(vty, "%sDeleted %d BVC%s",
605 dry_run ? "Not " : "", counter, VTY_NEWLINE);
606 }
607
608 if (delete_nsvc) {
Alexander Couzens82182d02020-09-22 13:21:46 +0200609 struct gprs_ns2_inst *nsi = g_cfg->nsi;
610 struct gprs_ns2_nse *nse;
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200611
Alexander Couzens82182d02020-09-22 13:21:46 +0200612 nse = gprs_ns2_nse_by_nsei(nsi, nsei);
613 if (!nse) {
614 vty_out(vty, "NSEI not found%s", VTY_NEWLINE);
615 return CMD_WARNING;
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200616 }
Alexander Couzens82182d02020-09-22 13:21:46 +0200617
618 /* TODO: We should NOT delete a persistent NSEI/NSVC as soon as we can check for these */
619 if (!dry_run)
620 gprs_ns2_free_nse(nse);
621
622 vty_out(vty, "%sDeleted NS-VCs for NSEI %d%s",
623 dry_run ? "Not " : "", nsei, VTY_NEWLINE);
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200624 }
625
626 return CMD_SUCCESS;
627}
628
Harald Welte799e0c92010-04-30 21:49:24 +0200629int gbproxy_vty_init(void)
630{
Harald Welteb6b2f142020-12-12 15:15:34 +0100631 install_element_ve(&show_gbproxy_bvc_cmd);
Harald Welte5a21f072020-12-12 15:16:43 +0100632 install_element_ve(&show_gbproxy_cell_cmd);
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200633 install_element_ve(&show_gbproxy_links_cmd);
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100634 install_element_ve(&show_nri_all_cmd);
635 install_element_ve(&show_nri_nsei_cmd);
Daniel Willmanne8c8ec92020-12-02 19:33:50 +0100636 install_element_ve(&logging_fltr_bvc_cmd);
Harald Welte799e0c92010-04-30 21:49:24 +0200637
Jacob Erlbeck4211d792013-10-24 12:48:23 +0200638 install_element(ENABLE_NODE, &delete_gb_bvci_cmd);
639 install_element(ENABLE_NODE, &delete_gb_nsei_cmd);
Holger Hans Peter Freyther90267a92013-10-23 11:24:17 +0200640
Harald Welte799e0c92010-04-30 21:49:24 +0200641 install_element(CONFIG_NODE, &cfg_gbproxy_cmd);
642 install_node(&gbproxy_node, config_write_gbproxy);
Harald Welte9e917642020-12-12 19:02:16 +0100643 install_element(GBPROXY_NODE, &cfg_pool_bvc_fc_ratio_cmd);
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100644 install_element(GBPROXY_NODE, &cfg_gbproxy_nri_bitlen_cmd);
645 install_element(GBPROXY_NODE, &cfg_gbproxy_nri_null_add_cmd);
646 install_element(GBPROXY_NODE, &cfg_gbproxy_nri_null_del_cmd);
647
648 install_element(CONFIG_NODE, &cfg_sgsn_nsei_cmd);
649 install_node(&sgsn_node, config_write_sgsn);
650 install_element(SGSN_NODE, &cfg_sgsn_allow_attach_cmd);
651 install_element(SGSN_NODE, &cfg_sgsn_no_allow_attach_cmd);
652 install_element(SGSN_NODE, &cfg_sgsn_nri_add_cmd);
653 install_element(SGSN_NODE, &cfg_sgsn_nri_del_cmd);
654
Holger Hans Peter Freyther925504b2015-09-24 10:21:40 +0200655
Harald Welte799e0c92010-04-30 21:49:24 +0200656 return 0;
657}
658
659int gbproxy_parse_config(const char *config_file, struct gbproxy_config *cfg)
660{
661 int rc;
662
663 g_cfg = cfg;
Harald Weltedcccb182010-05-16 20:52:23 +0200664 rc = vty_read_config_file(config_file, NULL);
Harald Welte799e0c92010-04-30 21:49:24 +0200665 if (rc < 0) {
666 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
667 return rc;
668 }
669
670 return 0;
671}