blob: fc2e8f19972594311db4a5250f3231077bd7a9f4 [file] [log] [blame]
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +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
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 <sys/socket.h>
22#include <netinet/in.h>
23#include <arpa/inet.h>
24#include <string.h>
25#include <time.h>
26#include <inttypes.h>
27
28#include <osmocom/core/talloc.h>
Alexander Couzens951e1332020-09-22 13:21:46 +020029#include <osmocom/core/timer.h>
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020030#include <osmocom/core/rate_ctr.h>
31#include <osmocom/gsm/gsm48.h>
32
Alexander Couzens951e1332020-09-22 13:21:46 +020033#include <osmocom/gprs/gprs_ns2.h>
Harald Weltee5209642020-12-05 19:59:45 +010034#include <osmocom/gprs/bssgp_bvc_fsm.h>
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020035#include <osmocom/gsm/apn.h>
36
37#include <osmocom/sgsn/debug.h>
38#include <osmocom/sgsn/gb_proxy.h>
39#include <osmocom/sgsn/gprs_utils.h>
40#include <osmocom/sgsn/vty.h>
41
42#include <osmocom/vty/command.h>
Daniel Willmann8f407b12020-12-02 19:33:50 +010043#include <osmocom/vty/logging.h>
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020044#include <osmocom/vty/vty.h>
45#include <osmocom/vty/misc.h>
46
Harald Weltee5209642020-12-05 19:59:45 +010047
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020048static struct gbproxy_config *g_cfg = NULL;
49
50/*
51 * vty code for gbproxy below
52 */
53static struct cmd_node gbproxy_node = {
54 GBPROXY_NODE,
55 "%s(config-gbproxy)# ",
56 1,
57};
58
Harald Welte560bdb32020-12-04 22:24:47 +010059static void gbprox_vty_print_bvc(struct vty *vty, struct gbproxy_bvc *bvc)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020060{
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020061
Harald Weltec6ecfad2020-12-12 14:17:51 +010062 if (bvc->bvci == 0) {
63 vty_out(vty, "NSEI %5u, SIG-BVCI %5u [%s]%s", bvc->nse->nsei, bvc->bvci,
64 osmo_fsm_inst_state_name(bvc->fi), VTY_NEWLINE);
65 } else {
66 struct gprs_ra_id raid;
67 gsm48_parse_ra(&raid, bvc->ra);
68 vty_out(vty, "NSEI %5u, PTP-BVCI %5u, RAI %s [%s]%s", bvc->nse->nsei, bvc->bvci,
69 osmo_rai_name(&raid), osmo_fsm_inst_state_name(bvc->fi), VTY_NEWLINE);
70 }
71}
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020072
Harald Weltec6ecfad2020-12-12 14:17:51 +010073static void gbproxy_vty_print_nse(struct vty *vty, struct gbproxy_nse *nse, bool show_stats)
74{
75 struct gbproxy_bvc *bvc;
76 int j;
77
78 hash_for_each(nse->bvcs, j, bvc, list) {
79 gbprox_vty_print_bvc(vty, bvc);
80
81 if (show_stats)
82 vty_out_rate_ctr_group(vty, " ", bvc->ctrg);
83 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020084}
85
86static int config_write_gbproxy(struct vty *vty)
87{
Harald Weltee5209642020-12-05 19:59:45 +010088 struct gbproxy_nse *nse;
89 int i;
90
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020091 vty_out(vty, "gbproxy%s", VTY_NEWLINE);
92
Harald Welte209dc9f2020-12-12 19:02:16 +010093 if (g_cfg->pool.bvc_fc_ratio != 100)
94 vty_out(vty, " pool bvc-flow-control-ratio %u%s", g_cfg->pool.bvc_fc_ratio, VTY_NEWLINE);
95
Harald Weltee5209642020-12-05 19:59:45 +010096 hash_for_each(g_cfg->sgsn_nses, i, nse, list) {
97 vty_out(vty, " sgsn nsei %u%s", nse->nsei, VTY_NEWLINE);
98 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +020099
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200100 return CMD_SUCCESS;
101}
102
103DEFUN(cfg_gbproxy,
104 cfg_gbproxy_cmd,
105 "gbproxy",
106 "Configure the Gb proxy")
107{
108 vty->node = GBPROXY_NODE;
109 return CMD_SUCCESS;
110}
111
Harald Weltee5209642020-12-05 19:59:45 +0100112extern const struct bssgp_bvc_fsm_ops sgsn_sig_bvc_fsm_ops;
113#include <osmocom/gprs/protocol/gsm_08_18.h>
114
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200115DEFUN(cfg_nsip_sgsn_nsei,
116 cfg_nsip_sgsn_nsei_cmd,
117 "sgsn nsei <0-65534>",
118 "SGSN information\n"
119 "NSEI to be used in the connection with the SGSN\n"
120 "The NSEI\n")
121{
Harald Weltee5209642020-12-05 19:59:45 +0100122 uint32_t features = 0; // FIXME: make configurable
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200123 unsigned int nsei = atoi(argv[0]);
Harald Weltee5209642020-12-05 19:59:45 +0100124 struct gbproxy_nse *nse;
125 struct gbproxy_bvc *bvc;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200126
Harald Weltee5209642020-12-05 19:59:45 +0100127 nse = gbproxy_nse_by_nsei_or_new(g_cfg, nsei, true);
128 if (!nse)
129 goto free_nothing;
130
131 if (!gbproxy_bvc_by_bvci(nse, 0)) {
132 uint8_t cause = BSSGP_CAUSE_OML_INTERV;
133 bvc = gbproxy_bvc_alloc(nse, 0);
134 if (!bvc)
135 goto free_nse;
136 bvc->fi = bssgp_bvc_fsm_alloc_sig_bss(bvc, nse->cfg->nsi, nsei, features);
137 if (!bvc->fi)
138 goto free_bvc;
139 bssgp_bvc_fsm_set_ops(bvc->fi, &sgsn_sig_bvc_fsm_ops, bvc);
140 osmo_fsm_inst_dispatch(bvc->fi, BSSGP_BVCFSM_E_REQ_RESET, &cause);
141 }
142
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200143 return CMD_SUCCESS;
Harald Weltee5209642020-12-05 19:59:45 +0100144
145free_bvc:
146 gbproxy_bvc_free(bvc);
147free_nse:
148 gbproxy_nse_free(nse);
149free_nothing:
150 vty_out(vty, "%% Unable to create NSE for NSEI=%05u%s", nsei, VTY_NEWLINE);
151 return CMD_WARNING;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200152}
153
Harald Welte209dc9f2020-12-12 19:02:16 +0100154DEFUN(cfg_pool_bvc_fc_ratio,
155 cfg_pool_bvc_fc_ratio_cmd,
156 "pool bvc-flow-control-ratio <1-100>",
157 "SGSN Pool related configuration\n"
158 "Ratio of BSS-advertised bucket size + leak rate advertised to each SGSN\n"
159 "Ratio of BSS-advertised bucket size + leak rate advertised to each SGSN (Percent)\n")
160{
161 g_cfg->pool.bvc_fc_ratio = atoi(argv[0]);
162 return CMD_SUCCESS;
163}
164
Daniel Willmann8f407b12020-12-02 19:33:50 +0100165static void log_set_bvc_filter(struct log_target *target,
166 const uint16_t *bvci)
167{
168 if (bvci) {
169 uintptr_t bvci_filter = *bvci | BVC_LOG_CTX_FLAG;
170 target->filter_map |= (1 << LOG_FLT_GB_BVC);
171 target->filter_data[LOG_FLT_GB_BVC] = (void *)bvci_filter;
172 } else if (target->filter_data[LOG_FLT_GB_BVC]) {
173 target->filter_map = ~(1 << LOG_FLT_GB_BVC);
174 target->filter_data[LOG_FLT_GB_BVC] = NULL;
175 }
176}
177
178DEFUN(logging_fltr_bvc,
179 logging_fltr_bvc_cmd,
180 "logging filter bvc bvci <0-65535>",
181 LOGGING_STR FILTER_STR
182 "Filter based on BSSGP VC\n"
183 "Identify BVC by BVCI\n"
184 "Numeric identifier\n")
185{
186 struct log_target *tgt;
187 uint16_t id = atoi(argv[0]);
188
189 log_tgt_mutex_lock();
190 tgt = osmo_log_vty2tgt(vty);
191 if (!tgt) {
192 log_tgt_mutex_unlock();
193 return CMD_WARNING;
194 }
195
196 log_set_bvc_filter(tgt, &id);
197 log_tgt_mutex_unlock();
198 return CMD_SUCCESS;
199}
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200200
Harald Weltebefe1c32020-12-12 15:15:34 +0100201DEFUN(show_gbproxy_bvc, show_gbproxy_bvc_cmd, "show gbproxy bvc (bss|sgsn) [stats]",
Harald Weltec6ecfad2020-12-12 14:17:51 +0100202 SHOW_STR "Display information about the Gb proxy\n"
Harald Weltebefe1c32020-12-12 15:15:34 +0100203 "Show BSSGP Virtual Connections\n"
Harald Weltec6ecfad2020-12-12 14:17:51 +0100204 "Display BSS-side BVCs\n"
205 "Display SGSN-side BVCs\n"
206 "Show statistics\n")
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200207{
Daniel Willmanne50550e2020-11-26 18:19:21 +0100208 struct gbproxy_nse *nse;
Harald Weltec6ecfad2020-12-12 14:17:51 +0100209 bool show_stats = argc >= 2;
210 int i;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200211
212 if (show_stats)
213 vty_out_rate_ctr_group(vty, "", g_cfg->ctrg);
214
Harald Weltec6ecfad2020-12-12 14:17:51 +0100215 if (!strcmp(argv[0], "bss")) {
216 hash_for_each(g_cfg->bss_nses, i, nse, list)
217 gbproxy_vty_print_nse(vty, nse, show_stats);
218 } else {
219 hash_for_each(g_cfg->sgsn_nses, i, nse, list)
220 gbproxy_vty_print_nse(vty, nse, show_stats);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200221 }
222 return CMD_SUCCESS;
223}
224
225DEFUN(show_gbproxy_links, show_gbproxy_links_cmd, "show gbproxy links",
226 SHOW_STR "Display information about the Gb proxy\n" "Show logical links\n")
227{
Daniel Willmanne50550e2020-11-26 18:19:21 +0100228 struct gbproxy_nse *nse;
Harald Welte8b4c7942020-12-05 10:14:49 +0100229 int i, j;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200230
Harald Welted2fef952020-12-05 00:31:07 +0100231 hash_for_each(g_cfg->bss_nses, i, nse, list) {
Harald Welte560bdb32020-12-04 22:24:47 +0100232 struct gbproxy_bvc *bvc;
Harald Welte8b4c7942020-12-05 10:14:49 +0100233 hash_for_each(nse->bvcs, j, bvc, list) {
Harald Welte560bdb32020-12-04 22:24:47 +0100234 gbprox_vty_print_bvc(vty, bvc);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200235 }
236 }
237 return CMD_SUCCESS;
238}
239
240DEFUN(delete_gb_bvci, delete_gb_bvci_cmd,
241 "delete-gbproxy-peer <0-65534> bvci <2-65534>",
Harald Welte560bdb32020-12-04 22:24:47 +0100242 "Delete a GBProxy bvc by NSEI and optionally BVCI\n"
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200243 "NSEI number\n"
Harald Welte560bdb32020-12-04 22:24:47 +0100244 "Only delete bvc with a matching BVCI\n"
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200245 "BVCI number\n")
246{
247 const uint16_t nsei = atoi(argv[0]);
248 const uint16_t bvci = atoi(argv[1]);
Harald Weltee5209642020-12-05 19:59:45 +0100249 struct gbproxy_nse *nse = gbproxy_nse_by_nsei(g_cfg, nsei, NSE_F_BSS);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200250 int counter;
251
Harald Weltee5209642020-12-05 19:59:45 +0100252 if (!nse) {
253 vty_out(vty, "NSE not found%s", VTY_NEWLINE);
254 return CMD_WARNING;
255 }
256
257 counter = gbproxy_cleanup_bvcs(nse, bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200258
259 if (counter == 0) {
260 vty_out(vty, "BVC not found%s", VTY_NEWLINE);
261 return CMD_WARNING;
262 }
263
264 return CMD_SUCCESS;
265}
266
267DEFUN(delete_gb_nsei, delete_gb_nsei_cmd,
268 "delete-gbproxy-peer <0-65534> (only-bvc|only-nsvc|all) [dry-run]",
Harald Welte560bdb32020-12-04 22:24:47 +0100269 "Delete a GBProxy bvc by NSEI and optionally BVCI\n"
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200270 "NSEI number\n"
271 "Only delete BSSGP connections (BVC)\n"
272 "Only delete dynamic NS connections (NS-VC)\n"
273 "Delete BVC and dynamic NS connections\n"
274 "Show what would be deleted instead of actually deleting\n"
275 )
276{
277 const uint16_t nsei = atoi(argv[0]);
278 const char *mode = argv[1];
279 int dry_run = argc > 2;
280 int delete_bvc = 0;
281 int delete_nsvc = 0;
282 int counter;
283
284 if (strcmp(mode, "only-bvc") == 0)
285 delete_bvc = 1;
286 else if (strcmp(mode, "only-nsvc") == 0)
287 delete_nsvc = 1;
288 else
289 delete_bvc = delete_nsvc = 1;
290
291 if (delete_bvc) {
Daniel Willmann5b897712020-12-04 17:43:27 +0100292 if (!dry_run) {
Harald Weltee5209642020-12-05 19:59:45 +0100293 struct gbproxy_nse *nse = gbproxy_nse_by_nsei(g_cfg, nsei, NSE_F_BSS);
294 counter = gbproxy_cleanup_bvcs(nse, 0);
Daniel Willmann5b897712020-12-04 17:43:27 +0100295 gbproxy_nse_free(nse);
296 } else {
Daniel Willmanne50550e2020-11-26 18:19:21 +0100297 struct gbproxy_nse *nse;
Harald Welte560bdb32020-12-04 22:24:47 +0100298 struct gbproxy_bvc *bvc;
Harald Welte8b4c7942020-12-05 10:14:49 +0100299 int i, j;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200300 counter = 0;
Harald Welted2fef952020-12-05 00:31:07 +0100301 hash_for_each(g_cfg->bss_nses, i, nse, list) {
Daniel Willmanne50550e2020-11-26 18:19:21 +0100302 if (nse->nsei != nsei)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200303 continue;
Harald Welte8b4c7942020-12-05 10:14:49 +0100304 hash_for_each(nse->bvcs, j, bvc, list) {
Daniel Willmanne50550e2020-11-26 18:19:21 +0100305 vty_out(vty, "BVC: ");
Harald Welte560bdb32020-12-04 22:24:47 +0100306 gbprox_vty_print_bvc(vty, bvc);
Daniel Willmanne50550e2020-11-26 18:19:21 +0100307 counter += 1;
308 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200309 }
310 }
311 vty_out(vty, "%sDeleted %d BVC%s",
312 dry_run ? "Not " : "", counter, VTY_NEWLINE);
313 }
314
315 if (delete_nsvc) {
Alexander Couzens951e1332020-09-22 13:21:46 +0200316 struct gprs_ns2_inst *nsi = g_cfg->nsi;
317 struct gprs_ns2_nse *nse;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200318
Alexander Couzens951e1332020-09-22 13:21:46 +0200319 nse = gprs_ns2_nse_by_nsei(nsi, nsei);
320 if (!nse) {
321 vty_out(vty, "NSEI not found%s", VTY_NEWLINE);
322 return CMD_WARNING;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200323 }
Alexander Couzens951e1332020-09-22 13:21:46 +0200324
325 /* TODO: We should NOT delete a persistent NSEI/NSVC as soon as we can check for these */
326 if (!dry_run)
327 gprs_ns2_free_nse(nse);
328
329 vty_out(vty, "%sDeleted NS-VCs for NSEI %d%s",
330 dry_run ? "Not " : "", nsei, VTY_NEWLINE);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200331 }
332
333 return CMD_SUCCESS;
334}
335
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200336int gbproxy_vty_init(void)
337{
Harald Weltebefe1c32020-12-12 15:15:34 +0100338 install_element_ve(&show_gbproxy_bvc_cmd);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200339 install_element_ve(&show_gbproxy_links_cmd);
Daniel Willmann8f407b12020-12-02 19:33:50 +0100340 install_element_ve(&logging_fltr_bvc_cmd);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200341
342 install_element(ENABLE_NODE, &delete_gb_bvci_cmd);
343 install_element(ENABLE_NODE, &delete_gb_nsei_cmd);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200344
345 install_element(CONFIG_NODE, &cfg_gbproxy_cmd);
346 install_node(&gbproxy_node, config_write_gbproxy);
347 install_element(GBPROXY_NODE, &cfg_nsip_sgsn_nsei_cmd);
Harald Welte209dc9f2020-12-12 19:02:16 +0100348 install_element(GBPROXY_NODE, &cfg_pool_bvc_fc_ratio_cmd);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200349
350 return 0;
351}
352
353int gbproxy_parse_config(const char *config_file, struct gbproxy_config *cfg)
354{
355 int rc;
356
357 g_cfg = cfg;
358 rc = vty_read_config_file(config_file, NULL);
359 if (rc < 0) {
360 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
361 return rc;
362 }
363
364 return 0;
365}