blob: 4d0fa3d9d93bf995ed0e09328b38addb168394ff [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>
Daniel Willmanndee0bcc2020-12-28 18:07:27 +010032#include <osmocom/core/utils.h>
Harald Welte799e0c92010-04-30 21:49:24 +020033
Alexander Couzens82182d02020-09-22 13:21:46 +020034#include <osmocom/gprs/gprs_ns2.h>
Harald Welte5687ae62020-12-05 19:59:45 +010035#include <osmocom/gprs/bssgp_bvc_fsm.h>
Daniel Willmannef3c9af2020-12-14 16:22:39 +010036
Harald Welte7e82b742017-08-12 13:43:54 +020037#include <osmocom/gsm/apn.h>
Daniel Willmannef3c9af2020-12-14 16:22:39 +010038#include <osmocom/gsm/gsm23236.h>
39#include <osmocom/gsm/gsm48.h>
Harald Welteea34a4e2012-06-16 14:59:56 +080040
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020041#include <osmocom/sgsn/debug.h>
42#include <osmocom/sgsn/gb_proxy.h>
43#include <osmocom/sgsn/gprs_utils.h>
44#include <osmocom/sgsn/vty.h>
Harald Welte799e0c92010-04-30 21:49:24 +020045
Harald Welte4b037e42010-05-19 19:45:32 +020046#include <osmocom/vty/command.h>
Daniel Willmanne8c8ec92020-12-02 19:33:50 +010047#include <osmocom/vty/logging.h>
Harald Welte4b037e42010-05-19 19:45:32 +020048#include <osmocom/vty/vty.h>
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +020049#include <osmocom/vty/misc.h>
Harald Welte799e0c92010-04-30 21:49:24 +020050
Daniel Willmannef3c9af2020-12-14 16:22:39 +010051#define NRI_STR "Mapping of Network Resource Indicators to this SGSN, for SGSN pooling\n"
52#define NULL_NRI_STR "Define NULL-NRI values that cause re-assignment of an MS to a different SGSN, for SGSN pooling.\n"
53#define NRI_FIRST_LAST_STR "First value of the NRI value range, should not surpass the configured 'nri bitlen'.\n" \
54 "Last value of the NRI value range, should not surpass the configured 'nri bitlen' and be larger than the" \
55 " first value; if omitted, apply only the first value.\n"
56#define NRI_ARGS_TO_STR_FMT "%s%s%s"
57#define NRI_ARGS_TO_STR_ARGS(ARGC, ARGV) ARGV[0], (ARGC>1)? ".." : "", (ARGC>1)? ARGV[1] : ""
58#define NRI_WARN(SGSN, FORMAT, args...) do { \
59 vty_out(vty, "%% Warning: NSE(%05d/SGSN): " FORMAT "%s", (SGSN)->nse->nsei, ##args, VTY_NEWLINE); \
60 LOGP(DLBSSGP, LOGL_ERROR, "NSE(%05d/SGSN): " FORMAT "\n", (SGSN)->nse->nsei, ##args); \
61 } while (0)
Harald Welte5687ae62020-12-05 19:59:45 +010062
Harald Welte799e0c92010-04-30 21:49:24 +020063static struct gbproxy_config *g_cfg = NULL;
64
65/*
Pau Espin Pedrol94998fa2018-06-20 23:55:22 +020066 * vty code for gbproxy below
Harald Welte799e0c92010-04-30 21:49:24 +020067 */
Harald Welteb77c6972010-05-01 11:28:43 +020068static struct cmd_node gbproxy_node = {
Harald Welte799e0c92010-04-30 21:49:24 +020069 GBPROXY_NODE,
Harald Welte570ce242012-08-17 13:16:10 +020070 "%s(config-gbproxy)# ",
Harald Welte799e0c92010-04-30 21:49:24 +020071 1,
72};
73
Harald Welte8cd74402020-12-04 22:24:47 +010074static void gbprox_vty_print_bvc(struct vty *vty, struct gbproxy_bvc *bvc)
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +020075{
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +020076
Harald Welte959f77e2020-12-12 14:17:51 +010077 if (bvc->bvci == 0) {
78 vty_out(vty, "NSEI %5u, SIG-BVCI %5u [%s]%s", bvc->nse->nsei, bvc->bvci,
79 osmo_fsm_inst_state_name(bvc->fi), VTY_NEWLINE);
80 } else {
81 struct gprs_ra_id raid;
82 gsm48_parse_ra(&raid, bvc->ra);
83 vty_out(vty, "NSEI %5u, PTP-BVCI %5u, RAI %s [%s]%s", bvc->nse->nsei, bvc->bvci,
84 osmo_rai_name(&raid), osmo_fsm_inst_state_name(bvc->fi), VTY_NEWLINE);
85 }
86}
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +020087
Harald Welte959f77e2020-12-12 14:17:51 +010088static void gbproxy_vty_print_nse(struct vty *vty, struct gbproxy_nse *nse, bool show_stats)
89{
90 struct gbproxy_bvc *bvc;
91 int j;
92
93 hash_for_each(nse->bvcs, j, bvc, list) {
94 gbprox_vty_print_bvc(vty, bvc);
95
96 if (show_stats)
97 vty_out_rate_ctr_group(vty, " ", bvc->ctrg);
98 }
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +020099}
100
Harald Welte5a21f072020-12-12 15:16:43 +0100101static void gbproxy_vty_print_cell(struct vty *vty, struct gbproxy_cell *cell, bool show_stats)
102{
103 struct gprs_ra_id raid;
104 gsm48_parse_ra(&raid, cell->ra);
105 unsigned int num_sgsn_bvc = 0;
106 unsigned int i;
107
108 vty_out(vty, "BVCI %5u RAI %s: ", cell->bvci, osmo_rai_name(&raid));
109 if (cell->bss_bvc)
110 vty_out(vty, "BSS NSEI %5u, SGSN NSEI ", cell->bss_bvc->nse->nsei);
111 else
112 vty_out(vty, "BSS NSEI <none>, SGSN NSEI ");
113
114 for (i = 0; i < ARRAY_SIZE(cell->sgsn_bvc); i++) {
115 struct gbproxy_bvc *sgsn_bvc = cell->sgsn_bvc[i];
116 if (sgsn_bvc) {
117 vty_out(vty, "%5u ", sgsn_bvc->nse->nsei);
118 num_sgsn_bvc++;
119 }
120 }
121 if (num_sgsn_bvc)
122 vty_out(vty, "%s", VTY_NEWLINE);
123 else
124 vty_out(vty, "<none>%s", VTY_NEWLINE);
125}
126
Harald Welte799e0c92010-04-30 21:49:24 +0200127static int config_write_gbproxy(struct vty *vty)
128{
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100129 struct osmo_nri_range *r;
Harald Welte5687ae62020-12-05 19:59:45 +0100130
Harald Welte799e0c92010-04-30 21:49:24 +0200131 vty_out(vty, "gbproxy%s", VTY_NEWLINE);
132
Harald Welte9e917642020-12-12 19:02:16 +0100133 if (g_cfg->pool.bvc_fc_ratio != 100)
134 vty_out(vty, " pool bvc-flow-control-ratio %u%s", g_cfg->pool.bvc_fc_ratio, VTY_NEWLINE);
135
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100136 if (g_cfg->pool.nri_bitlen != OSMO_NRI_BITLEN_DEFAULT)
137 vty_out(vty, " nri bitlen %u%s", g_cfg->pool.nri_bitlen, VTY_NEWLINE);
Harald Welte799e0c92010-04-30 21:49:24 +0200138
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100139 llist_for_each_entry(r, &g_cfg->pool.null_nri_ranges->entries, entry) {
140 vty_out(vty, " nri null add %d", r->first);
141 if (r->first != r->last)
142 vty_out(vty, " %d", r->last);
143 vty_out(vty, "%s", VTY_NEWLINE);
144 }
Harald Welte799e0c92010-04-30 21:49:24 +0200145 return CMD_SUCCESS;
146}
147
Harald Welte799e0c92010-04-30 21:49:24 +0200148DEFUN(cfg_gbproxy,
149 cfg_gbproxy_cmd,
150 "gbproxy",
151 "Configure the Gb proxy")
152{
153 vty->node = GBPROXY_NODE;
154 return CMD_SUCCESS;
155}
156
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100157/* VTY code for SGSN (pool) configuration */
Harald Welte5687ae62020-12-05 19:59:45 +0100158extern const struct bssgp_bvc_fsm_ops sgsn_sig_bvc_fsm_ops;
159#include <osmocom/gprs/protocol/gsm_08_18.h>
160
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100161static struct cmd_node sgsn_node = {
162 SGSN_NODE,
163 "%s(config-sgsn)# ",
164 1,
165};
166
167static void sgsn_write_nri(struct vty *vty, struct gbproxy_sgsn *sgsn, bool verbose)
168{
169 struct osmo_nri_range *r;
170
171 if (verbose) {
172 vty_out(vty, "sgsn nsei %d%s", sgsn->nse->nsei, VTY_NEWLINE);
173 if (llist_empty(&sgsn->pool.nri_ranges->entries)) {
174 vty_out(vty, " %% no NRI mappings%s", VTY_NEWLINE);
175 return;
176 }
177 }
178
179 llist_for_each_entry(r, &sgsn->pool.nri_ranges->entries, entry) {
180 if (osmo_nri_range_validate(r, 255))
181 vty_out(vty, " %% INVALID RANGE:");
182 vty_out(vty, " nri add %d", r->first);
183 if (r->first != r->last)
184 vty_out(vty, " %d", r->last);
185 vty_out(vty, "%s", VTY_NEWLINE);
186 }
187}
188
189static void write_sgsn(struct vty *vty, struct gbproxy_sgsn *sgsn)
190{
191 vty_out(vty, "sgsn nsei %u%s", sgsn->nse->nsei, VTY_NEWLINE);
Daniel Willmanndee0bcc2020-12-28 18:07:27 +0100192 vty_out(vty, " name %s%s", sgsn->name, VTY_NEWLINE);
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100193 vty_out(vty, " %sallow-attach%s", sgsn->pool.allow_attach ? "" : "no ", VTY_NEWLINE);
194 sgsn_write_nri(vty, sgsn, false);
195}
196
197static int config_write_sgsn(struct vty *vty)
198{
199 struct gbproxy_sgsn *sgsn;
200
201 llist_for_each_entry(sgsn, &g_cfg->sgsns, list)
202 write_sgsn(vty, sgsn);
203
204 return CMD_SUCCESS;
205}
206
207DEFUN(cfg_sgsn_nsei,
208 cfg_sgsn_nsei_cmd,
Harald Welteff3bde82010-05-19 15:09:09 +0200209 "sgsn nsei <0-65534>",
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100210 "Configure the SGSN\n"
Holger Hans Peter Freyther2eb6e2c2011-11-05 15:14:59 +0100211 "NSEI to be used in the connection with the SGSN\n"
212 "The NSEI\n")
Harald Welte799e0c92010-04-30 21:49:24 +0200213{
Harald Welte5687ae62020-12-05 19:59:45 +0100214 uint32_t features = 0; // FIXME: make configurable
Jacob Erlbeckcc8856f2014-10-08 13:37:28 +0200215 unsigned int nsei = atoi(argv[0]);
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100216 unsigned int num_sgsn = llist_count(&g_cfg->sgsns);
217 struct gbproxy_sgsn *sgsn;
Harald Welte5687ae62020-12-05 19:59:45 +0100218 struct gbproxy_nse *nse;
219 struct gbproxy_bvc *bvc;
Harald Welte799e0c92010-04-30 21:49:24 +0200220
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100221 if (num_sgsn >= GBPROXY_MAX_NR_SGSN) {
222 vty_out(vty, "%% Too many SGSN NSE defined (%d), increase GBPROXY_MAX_NR_SGSN%s",
223 num_sgsn, VTY_NEWLINE);
224 return CMD_WARNING;
225 }
226
227 /* This will have created the gbproxy_nse as well */
228 sgsn = gbproxy_sgsn_by_nsei_or_new(g_cfg, nsei);
229 if (!sgsn)
Harald Welte5687ae62020-12-05 19:59:45 +0100230 goto free_nothing;
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100231 nse = sgsn->nse;
232 if (num_sgsn > 1 && g_cfg->pool.nri_bitlen == 0)
233 vty_out(vty, "%% Multiple SGSNs defined, but no pooling enabled%s", VTY_NEWLINE);
234
Harald Welte5687ae62020-12-05 19:59:45 +0100235
236 if (!gbproxy_bvc_by_bvci(nse, 0)) {
237 uint8_t cause = BSSGP_CAUSE_OML_INTERV;
238 bvc = gbproxy_bvc_alloc(nse, 0);
239 if (!bvc)
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100240 goto free_sgsn;
Harald Welte5687ae62020-12-05 19:59:45 +0100241 bvc->fi = bssgp_bvc_fsm_alloc_sig_bss(bvc, nse->cfg->nsi, nsei, features);
242 if (!bvc->fi)
243 goto free_bvc;
244 bssgp_bvc_fsm_set_ops(bvc->fi, &sgsn_sig_bvc_fsm_ops, bvc);
245 osmo_fsm_inst_dispatch(bvc->fi, BSSGP_BVCFSM_E_REQ_RESET, &cause);
246 }
247
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100248 vty->node = SGSN_NODE;
249 vty->index = sgsn;
Harald Welte799e0c92010-04-30 21:49:24 +0200250 return CMD_SUCCESS;
Harald Welte5687ae62020-12-05 19:59:45 +0100251
252free_bvc:
253 gbproxy_bvc_free(bvc);
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100254free_sgsn:
255 gbproxy_sgsn_free(sgsn);
Harald Welte5687ae62020-12-05 19:59:45 +0100256free_nothing:
257 vty_out(vty, "%% Unable to create NSE for NSEI=%05u%s", nsei, VTY_NEWLINE);
258 return CMD_WARNING;
Harald Welte799e0c92010-04-30 21:49:24 +0200259}
260
Daniel Willmanndee0bcc2020-12-28 18:07:27 +0100261DEFUN(cfg_sgsn_name,
262 cfg_sgsn_name_cmd,
263 "name NAME",
264 "Configure the SGSN\n"
265 "Name the SGSN\n"
266 "The name\n")
267{
268 struct gbproxy_sgsn *sgsn = vty->index;
269 const char *name = argv[0];
270
271
272 osmo_talloc_replace_string(sgsn, &sgsn->name, name);
273 if (!sgsn->name) {
274 vty_out(vty, "%% Unable to set name for SGSN with nsei %05u%s", sgsn->nse->nsei, VTY_NEWLINE);
275 return CMD_WARNING;
276 }
277
278 return CMD_SUCCESS;
279}
280
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100281DEFUN_ATTR(cfg_sgsn_nri_add, cfg_sgsn_nri_add_cmd,
282 "nri add <0-32767> [<0-32767>]",
283 NRI_STR "Add NRI value or range to the NRI mapping for this MSC\n"
284 NRI_FIRST_LAST_STR,
285 CMD_ATTR_IMMEDIATE)
286{
287 struct gbproxy_sgsn *sgsn = vty->index;
288 struct gbproxy_sgsn *other_sgsn;
289 bool before;
290 int rc;
291 const char *message;
292 struct osmo_nri_range add_range;
293
294 rc = osmo_nri_ranges_vty_add(&message, &add_range, sgsn->pool.nri_ranges, argc, argv, g_cfg->pool.nri_bitlen);
295 if (message) {
296 NRI_WARN(sgsn, "%s: " NRI_ARGS_TO_STR_FMT, message, NRI_ARGS_TO_STR_ARGS(argc, argv));
297 }
298 if (rc < 0)
299 return CMD_WARNING;
300
301 /* Issue a warning about NRI range overlaps (but still allow them).
302 * Overlapping ranges will map to whichever SGSN comes fist in the gbproxy_config->sgsns llist,
303 * which should be the first one defined in the config */
304 before = true;
305
306 llist_for_each_entry(other_sgsn, &g_cfg->sgsns, list) {
307 if (other_sgsn == sgsn) {
308 before = false;
309 continue;
310 }
311 if (osmo_nri_range_overlaps_ranges(&add_range, other_sgsn->pool.nri_ranges)) {
312 uint16_t nsei = sgsn->nse->nsei;
313 uint16_t other_nsei = other_sgsn->nse->nsei;
314 NRI_WARN(sgsn, "NRI range [%d..%d] overlaps between NSE %05d and NSE %05d."
315 " For overlaps, NSE %05d has higher priority than NSE %05d",
316 add_range.first, add_range.last, nsei, other_nsei,
317 before ? other_nsei : nsei, before ? nsei : other_nsei);
318 }
319 }
320 return CMD_SUCCESS;
321}
322
323DEFUN_ATTR(cfg_sgsn_nri_del, cfg_sgsn_nri_del_cmd,
324 "nri del <0-32767> [<0-32767>]",
325 NRI_STR "Remove NRI value or range from the NRI mapping for this MSC\n"
326 NRI_FIRST_LAST_STR,
327 CMD_ATTR_IMMEDIATE)
328{
329 struct gbproxy_sgsn *sgsn = vty->index;
330 int rc;
331 const char *message;
332
333 rc = osmo_nri_ranges_vty_del(&message, NULL, sgsn->pool.nri_ranges, argc, argv);
334 if (message) {
335 NRI_WARN(sgsn, "%s: " NRI_ARGS_TO_STR_FMT, message, NRI_ARGS_TO_STR_ARGS(argc, argv));
336 }
337 if (rc < 0)
338 return CMD_WARNING;
339 return CMD_SUCCESS;
340}
341
342DEFUN_ATTR(cfg_sgsn_allow_attach, cfg_sgsn_allow_attach_cmd,
343 "allow-attach",
344 "Allow this SGSN to attach new subscribers (default).\n",
345 CMD_ATTR_IMMEDIATE)
346{
347 struct gbproxy_sgsn *sgsn = vty->index;
348 sgsn->pool.allow_attach = true;
349 return CMD_SUCCESS;
350}
351
352DEFUN_ATTR(cfg_sgsn_no_allow_attach, cfg_sgsn_no_allow_attach_cmd,
353 "no allow-attach",
354 NO_STR
355 "Do not assign new subscribers to this MSC."
356 " Useful if an MSC in an MSC pool is configured to off-load subscribers."
357 " The MSC will still be operational for already IMSI-Attached subscribers,"
358 " but the NAS node selection function will skip this MSC for new subscribers\n",
359 CMD_ATTR_IMMEDIATE)
360{
361 struct gbproxy_sgsn *sgsn = vty->index;
362 sgsn->pool.allow_attach = false;
363 return CMD_SUCCESS;
364}
365
366DEFUN(cfg_sgsn_show_nri_all, show_nri_all_cmd,
367 "show nri all",
368 SHOW_STR NRI_STR "Show all SGSNs\n")
369{
370 struct gbproxy_sgsn *sgsn;
371
372 llist_for_each_entry(sgsn, &g_cfg->sgsns, list)
373 sgsn_write_nri(vty, sgsn, true);
374
375 return CMD_SUCCESS;
376}
377
378DEFUN(show_nri, show_nri_nsei_cmd,
379 "show nri nsei <0-65535>",
380 SHOW_STR NRI_STR "Identify SGSN by NSEI\n"
381 "NSEI of the SGSN\n")
382{
383 struct gbproxy_sgsn *sgsn;
384 int nsei = atoi(argv[0]);
385
386 sgsn = gbproxy_sgsn_by_nsei(g_cfg, nsei);
387 if (!sgsn) {
388 vty_out(vty, "%% No SGSN with found for NSEI %05d%s", nsei, VTY_NEWLINE);
389 return CMD_SUCCESS;
390 }
391 sgsn_write_nri(vty, sgsn, true);
392
393 return CMD_SUCCESS;
394}
395
Harald Welte9e917642020-12-12 19:02:16 +0100396DEFUN(cfg_pool_bvc_fc_ratio,
397 cfg_pool_bvc_fc_ratio_cmd,
398 "pool bvc-flow-control-ratio <1-100>",
399 "SGSN Pool related configuration\n"
400 "Ratio of BSS-advertised bucket size + leak rate advertised to each SGSN\n"
401 "Ratio of BSS-advertised bucket size + leak rate advertised to each SGSN (Percent)\n")
402{
403 g_cfg->pool.bvc_fc_ratio = atoi(argv[0]);
404 return CMD_SUCCESS;
405}
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100406DEFUN_ATTR(cfg_gbproxy_nri_bitlen,
407 cfg_gbproxy_nri_bitlen_cmd,
408 "nri bitlen <0-15>",
409 NRI_STR
410 "Set number of bits that an NRI has, to extract from TMSI identities (always starting just after the TMSI's most significant octet).\n"
411 "bit count (0 disables) pooling)\n",
412 CMD_ATTR_IMMEDIATE)
413{
414 g_cfg->pool.nri_bitlen = atoi(argv[0]);
415
416 if (llist_count(&g_cfg->sgsns) > 1 && g_cfg->pool.nri_bitlen == 0)
417 vty_out(vty, "%% Pooling disabled, but multiple SGSNs defined%s", VTY_NEWLINE);
418
419 /* TODO: Verify all nri ranges and warn on mismatch */
420
421 return CMD_SUCCESS;
422}
423
424DEFUN_ATTR(cfg_gbproxy_nri_null_add,
425 cfg_gbproxy_nri_null_add_cmd,
426 "nri null add <0-32767> [<0-32767>]",
427 NRI_STR NULL_NRI_STR "Add NULL-NRI value (or range)\n"
428 NRI_FIRST_LAST_STR,
429 CMD_ATTR_IMMEDIATE)
430{
431 int rc;
432 const char *message;
433
434 rc = osmo_nri_ranges_vty_add(&message, NULL, g_cfg->pool.null_nri_ranges, argc, argv,
435 g_cfg->pool.nri_bitlen);
436 if (message) {
437 vty_out(vty, "%% nri null add: %s: " NRI_ARGS_TO_STR_FMT "%s", message, NRI_ARGS_TO_STR_ARGS(argc, argv),
438 VTY_NEWLINE);
439 vty_out(vty, "%s: \n" NRI_ARGS_TO_STR_FMT, message, NRI_ARGS_TO_STR_ARGS(argc, argv));
440 }
441 if (rc < 0)
442 return CMD_WARNING;
443 return CMD_SUCCESS;
444}
445
446DEFUN_ATTR(cfg_gbproxy_nri_null_del,
447 cfg_gbproxy_nri_null_del_cmd,
448 "nri null del <0-32767> [<0-32767>]",
449 NRI_STR NULL_NRI_STR "Remove NRI value or range from the NRI mapping for this MSC\n"
450 NRI_FIRST_LAST_STR,
451 CMD_ATTR_IMMEDIATE)
452{
453 int rc;
454 const char *message;
455 rc = osmo_nri_ranges_vty_del(&message, NULL, g_cfg->pool.null_nri_ranges, argc, argv);
456 if (message) {
457 vty_out(vty, "%% %s: " NRI_ARGS_TO_STR_FMT "%s", message, NRI_ARGS_TO_STR_ARGS(argc, argv),
458 VTY_NEWLINE);
459 }
460 if (rc < 0)
461 return CMD_WARNING;
462 return CMD_SUCCESS;
463}
Harald Welte9e917642020-12-12 19:02:16 +0100464
Daniel Willmanne8c8ec92020-12-02 19:33:50 +0100465static void log_set_bvc_filter(struct log_target *target,
466 const uint16_t *bvci)
467{
468 if (bvci) {
469 uintptr_t bvci_filter = *bvci | BVC_LOG_CTX_FLAG;
470 target->filter_map |= (1 << LOG_FLT_GB_BVC);
471 target->filter_data[LOG_FLT_GB_BVC] = (void *)bvci_filter;
472 } else if (target->filter_data[LOG_FLT_GB_BVC]) {
473 target->filter_map = ~(1 << LOG_FLT_GB_BVC);
474 target->filter_data[LOG_FLT_GB_BVC] = NULL;
475 }
476}
477
478DEFUN(logging_fltr_bvc,
479 logging_fltr_bvc_cmd,
480 "logging filter bvc bvci <0-65535>",
481 LOGGING_STR FILTER_STR
482 "Filter based on BSSGP VC\n"
483 "Identify BVC by BVCI\n"
484 "Numeric identifier\n")
485{
486 struct log_target *tgt;
487 uint16_t id = atoi(argv[0]);
488
489 log_tgt_mutex_lock();
490 tgt = osmo_log_vty2tgt(vty);
491 if (!tgt) {
492 log_tgt_mutex_unlock();
493 return CMD_WARNING;
494 }
495
496 log_set_bvc_filter(tgt, &id);
497 log_tgt_mutex_unlock();
498 return CMD_SUCCESS;
499}
Jacob Erlbeck7c101d92014-06-06 18:49:23 +0200500
Harald Welteb6b2f142020-12-12 15:15:34 +0100501DEFUN(show_gbproxy_bvc, show_gbproxy_bvc_cmd, "show gbproxy bvc (bss|sgsn) [stats]",
Harald Welte959f77e2020-12-12 14:17:51 +0100502 SHOW_STR "Display information about the Gb proxy\n"
Harald Welteb6b2f142020-12-12 15:15:34 +0100503 "Show BSSGP Virtual Connections\n"
Harald Welte959f77e2020-12-12 14:17:51 +0100504 "Display BSS-side BVCs\n"
505 "Display SGSN-side BVCs\n"
506 "Show statistics\n")
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200507{
Daniel Willmann447ad442020-11-26 18:19:21 +0100508 struct gbproxy_nse *nse;
Harald Welte959f77e2020-12-12 14:17:51 +0100509 bool show_stats = argc >= 2;
510 int i;
Jacob Erlbeck91fb6802014-05-28 10:59:10 +0200511
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200512 if (show_stats)
Holger Hans Peter Freythereece6272014-08-04 15:42:36 +0200513 vty_out_rate_ctr_group(vty, "", g_cfg->ctrg);
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200514
Harald Welte959f77e2020-12-12 14:17:51 +0100515 if (!strcmp(argv[0], "bss")) {
516 hash_for_each(g_cfg->bss_nses, i, nse, list)
517 gbproxy_vty_print_nse(vty, nse, show_stats);
518 } else {
519 hash_for_each(g_cfg->sgsn_nses, i, nse, list)
520 gbproxy_vty_print_nse(vty, nse, show_stats);
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200521 }
522 return CMD_SUCCESS;
523}
524
Harald Welte5a21f072020-12-12 15:16:43 +0100525DEFUN(show_gbproxy_cell, show_gbproxy_cell_cmd, "show gbproxy cell [stats]",
526 SHOW_STR "Display information about the Gb proxy\n"
527 "Show GPRS Cell Information\n"
528 "Show statistics\n")
529{
530 struct gbproxy_cell *cell;
531 bool show_stats = argc >= 1;
532 int i;
533
534 hash_for_each(g_cfg->cells, i, cell, list)
535 gbproxy_vty_print_cell(vty, cell, show_stats);
536
537 return CMD_SUCCESS;
538}
539
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200540DEFUN(show_gbproxy_links, show_gbproxy_links_cmd, "show gbproxy links",
541 SHOW_STR "Display information about the Gb proxy\n" "Show logical links\n")
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200542{
Daniel Willmann447ad442020-11-26 18:19:21 +0100543 struct gbproxy_nse *nse;
Harald Welte993d3f42020-12-05 10:14:49 +0100544 int i, j;
Jacob Erlbeckc6807c42014-09-19 16:34:01 +0200545
Harald Welte78db2442020-12-05 00:31:07 +0100546 hash_for_each(g_cfg->bss_nses, i, nse, list) {
Harald Welte8cd74402020-12-04 22:24:47 +0100547 struct gbproxy_bvc *bvc;
Harald Welte993d3f42020-12-05 10:14:49 +0100548 hash_for_each(nse->bvcs, j, bvc, list) {
Harald Welte8cd74402020-12-04 22:24:47 +0100549 gbprox_vty_print_bvc(vty, bvc);
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200550 }
551 }
552 return CMD_SUCCESS;
553}
554
555DEFUN(delete_gb_bvci, delete_gb_bvci_cmd,
556 "delete-gbproxy-peer <0-65534> bvci <2-65534>",
Harald Welte8cd74402020-12-04 22:24:47 +0100557 "Delete a GBProxy bvc by NSEI and optionally BVCI\n"
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200558 "NSEI number\n"
Harald Welte8cd74402020-12-04 22:24:47 +0100559 "Only delete bvc with a matching BVCI\n"
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200560 "BVCI number\n")
561{
562 const uint16_t nsei = atoi(argv[0]);
563 const uint16_t bvci = atoi(argv[1]);
Harald Welte5687ae62020-12-05 19:59:45 +0100564 struct gbproxy_nse *nse = gbproxy_nse_by_nsei(g_cfg, nsei, NSE_F_BSS);
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200565 int counter;
566
Harald Welte5687ae62020-12-05 19:59:45 +0100567 if (!nse) {
568 vty_out(vty, "NSE not found%s", VTY_NEWLINE);
569 return CMD_WARNING;
570 }
571
572 counter = gbproxy_cleanup_bvcs(nse, bvci);
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200573
574 if (counter == 0) {
575 vty_out(vty, "BVC not found%s", VTY_NEWLINE);
576 return CMD_WARNING;
577 }
578
579 return CMD_SUCCESS;
580}
581
582DEFUN(delete_gb_nsei, delete_gb_nsei_cmd,
583 "delete-gbproxy-peer <0-65534> (only-bvc|only-nsvc|all) [dry-run]",
Harald Welte8cd74402020-12-04 22:24:47 +0100584 "Delete a GBProxy bvc by NSEI and optionally BVCI\n"
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200585 "NSEI number\n"
586 "Only delete BSSGP connections (BVC)\n"
587 "Only delete dynamic NS connections (NS-VC)\n"
588 "Delete BVC and dynamic NS connections\n"
589 "Show what would be deleted instead of actually deleting\n"
590 )
591{
592 const uint16_t nsei = atoi(argv[0]);
593 const char *mode = argv[1];
594 int dry_run = argc > 2;
595 int delete_bvc = 0;
596 int delete_nsvc = 0;
597 int counter;
598
599 if (strcmp(mode, "only-bvc") == 0)
600 delete_bvc = 1;
601 else if (strcmp(mode, "only-nsvc") == 0)
602 delete_nsvc = 1;
603 else
604 delete_bvc = delete_nsvc = 1;
605
606 if (delete_bvc) {
Daniel Willmann9a2fc902020-12-04 17:43:27 +0100607 if (!dry_run) {
Harald Welte5687ae62020-12-05 19:59:45 +0100608 struct gbproxy_nse *nse = gbproxy_nse_by_nsei(g_cfg, nsei, NSE_F_BSS);
609 counter = gbproxy_cleanup_bvcs(nse, 0);
Daniel Willmann9a2fc902020-12-04 17:43:27 +0100610 gbproxy_nse_free(nse);
611 } else {
Daniel Willmann447ad442020-11-26 18:19:21 +0100612 struct gbproxy_nse *nse;
Harald Welte8cd74402020-12-04 22:24:47 +0100613 struct gbproxy_bvc *bvc;
Harald Welte993d3f42020-12-05 10:14:49 +0100614 int i, j;
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200615 counter = 0;
Harald Welte78db2442020-12-05 00:31:07 +0100616 hash_for_each(g_cfg->bss_nses, i, nse, list) {
Daniel Willmann447ad442020-11-26 18:19:21 +0100617 if (nse->nsei != nsei)
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200618 continue;
Harald Welte993d3f42020-12-05 10:14:49 +0100619 hash_for_each(nse->bvcs, j, bvc, list) {
Daniel Willmann447ad442020-11-26 18:19:21 +0100620 vty_out(vty, "BVC: ");
Harald Welte8cd74402020-12-04 22:24:47 +0100621 gbprox_vty_print_bvc(vty, bvc);
Daniel Willmann447ad442020-11-26 18:19:21 +0100622 counter += 1;
623 }
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200624 }
625 }
626 vty_out(vty, "%sDeleted %d BVC%s",
627 dry_run ? "Not " : "", counter, VTY_NEWLINE);
628 }
629
630 if (delete_nsvc) {
Alexander Couzens82182d02020-09-22 13:21:46 +0200631 struct gprs_ns2_inst *nsi = g_cfg->nsi;
632 struct gprs_ns2_nse *nse;
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200633
Alexander Couzens82182d02020-09-22 13:21:46 +0200634 nse = gprs_ns2_nse_by_nsei(nsi, nsei);
635 if (!nse) {
636 vty_out(vty, "NSEI not found%s", VTY_NEWLINE);
637 return CMD_WARNING;
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200638 }
Alexander Couzens82182d02020-09-22 13:21:46 +0200639
640 /* TODO: We should NOT delete a persistent NSEI/NSVC as soon as we can check for these */
641 if (!dry_run)
642 gprs_ns2_free_nse(nse);
643
644 vty_out(vty, "%sDeleted NS-VCs for NSEI %d%s",
645 dry_run ? "Not " : "", nsei, VTY_NEWLINE);
Holger Hans Peter Freyther18739ea2014-08-04 11:10:09 +0200646 }
647
648 return CMD_SUCCESS;
649}
650
Harald Welte799e0c92010-04-30 21:49:24 +0200651int gbproxy_vty_init(void)
652{
Harald Welteb6b2f142020-12-12 15:15:34 +0100653 install_element_ve(&show_gbproxy_bvc_cmd);
Harald Welte5a21f072020-12-12 15:16:43 +0100654 install_element_ve(&show_gbproxy_cell_cmd);
Jacob Erlbeckd4c79a42014-09-19 15:36:44 +0200655 install_element_ve(&show_gbproxy_links_cmd);
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100656 install_element_ve(&show_nri_all_cmd);
657 install_element_ve(&show_nri_nsei_cmd);
Daniel Willmanne8c8ec92020-12-02 19:33:50 +0100658 install_element_ve(&logging_fltr_bvc_cmd);
Harald Welte799e0c92010-04-30 21:49:24 +0200659
Jacob Erlbeck4211d792013-10-24 12:48:23 +0200660 install_element(ENABLE_NODE, &delete_gb_bvci_cmd);
661 install_element(ENABLE_NODE, &delete_gb_nsei_cmd);
Holger Hans Peter Freyther90267a92013-10-23 11:24:17 +0200662
Harald Welte799e0c92010-04-30 21:49:24 +0200663 install_element(CONFIG_NODE, &cfg_gbproxy_cmd);
664 install_node(&gbproxy_node, config_write_gbproxy);
Harald Welte9e917642020-12-12 19:02:16 +0100665 install_element(GBPROXY_NODE, &cfg_pool_bvc_fc_ratio_cmd);
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100666 install_element(GBPROXY_NODE, &cfg_gbproxy_nri_bitlen_cmd);
667 install_element(GBPROXY_NODE, &cfg_gbproxy_nri_null_add_cmd);
668 install_element(GBPROXY_NODE, &cfg_gbproxy_nri_null_del_cmd);
669
670 install_element(CONFIG_NODE, &cfg_sgsn_nsei_cmd);
671 install_node(&sgsn_node, config_write_sgsn);
Daniel Willmanndee0bcc2020-12-28 18:07:27 +0100672 install_element(SGSN_NODE, &cfg_sgsn_name_cmd);
Daniel Willmannef3c9af2020-12-14 16:22:39 +0100673 install_element(SGSN_NODE, &cfg_sgsn_allow_attach_cmd);
674 install_element(SGSN_NODE, &cfg_sgsn_no_allow_attach_cmd);
675 install_element(SGSN_NODE, &cfg_sgsn_nri_add_cmd);
676 install_element(SGSN_NODE, &cfg_sgsn_nri_del_cmd);
677
Holger Hans Peter Freyther925504b2015-09-24 10:21:40 +0200678
Harald Welte799e0c92010-04-30 21:49:24 +0200679 return 0;
680}
681
682int gbproxy_parse_config(const char *config_file, struct gbproxy_config *cfg)
683{
684 int rc;
685
686 g_cfg = cfg;
Harald Weltedcccb182010-05-16 20:52:23 +0200687 rc = vty_read_config_file(config_file, NULL);
Harald Welte799e0c92010-04-30 21:49:24 +0200688 if (rc < 0) {
689 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
690 return rc;
691 }
692
693 return 0;
694}