blob: 976ac125b6906f3d3e1405ffedf6c399da7099a1 [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 Weltec6ecfad2020-12-12 14:17:51 +0100201DEFUN(show_gbproxy, show_gbproxy_cmd, "show gbproxy (bss|sgsn) [stats]",
202 SHOW_STR "Display information about the Gb proxy\n"
203 "Display BSS-side BVCs\n"
204 "Display SGSN-side BVCs\n"
205 "Show statistics\n")
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200206{
Daniel Willmanne50550e2020-11-26 18:19:21 +0100207 struct gbproxy_nse *nse;
Harald Weltec6ecfad2020-12-12 14:17:51 +0100208 bool show_stats = argc >= 2;
209 int i;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200210
211 if (show_stats)
212 vty_out_rate_ctr_group(vty, "", g_cfg->ctrg);
213
Harald Weltec6ecfad2020-12-12 14:17:51 +0100214 if (!strcmp(argv[0], "bss")) {
215 hash_for_each(g_cfg->bss_nses, i, nse, list)
216 gbproxy_vty_print_nse(vty, nse, show_stats);
217 } else {
218 hash_for_each(g_cfg->sgsn_nses, i, nse, list)
219 gbproxy_vty_print_nse(vty, nse, show_stats);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200220 }
221 return CMD_SUCCESS;
222}
223
224DEFUN(show_gbproxy_links, show_gbproxy_links_cmd, "show gbproxy links",
225 SHOW_STR "Display information about the Gb proxy\n" "Show logical links\n")
226{
Daniel Willmanne50550e2020-11-26 18:19:21 +0100227 struct gbproxy_nse *nse;
Harald Welte8b4c7942020-12-05 10:14:49 +0100228 int i, j;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200229
Harald Welted2fef952020-12-05 00:31:07 +0100230 hash_for_each(g_cfg->bss_nses, i, nse, list) {
Harald Welte560bdb32020-12-04 22:24:47 +0100231 struct gbproxy_bvc *bvc;
Harald Welte8b4c7942020-12-05 10:14:49 +0100232 hash_for_each(nse->bvcs, j, bvc, list) {
Harald Welte560bdb32020-12-04 22:24:47 +0100233 gbprox_vty_print_bvc(vty, bvc);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200234 }
235 }
236 return CMD_SUCCESS;
237}
238
239DEFUN(delete_gb_bvci, delete_gb_bvci_cmd,
240 "delete-gbproxy-peer <0-65534> bvci <2-65534>",
Harald Welte560bdb32020-12-04 22:24:47 +0100241 "Delete a GBProxy bvc by NSEI and optionally BVCI\n"
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200242 "NSEI number\n"
Harald Welte560bdb32020-12-04 22:24:47 +0100243 "Only delete bvc with a matching BVCI\n"
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200244 "BVCI number\n")
245{
246 const uint16_t nsei = atoi(argv[0]);
247 const uint16_t bvci = atoi(argv[1]);
Harald Weltee5209642020-12-05 19:59:45 +0100248 struct gbproxy_nse *nse = gbproxy_nse_by_nsei(g_cfg, nsei, NSE_F_BSS);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200249 int counter;
250
Harald Weltee5209642020-12-05 19:59:45 +0100251 if (!nse) {
252 vty_out(vty, "NSE not found%s", VTY_NEWLINE);
253 return CMD_WARNING;
254 }
255
256 counter = gbproxy_cleanup_bvcs(nse, bvci);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200257
258 if (counter == 0) {
259 vty_out(vty, "BVC not found%s", VTY_NEWLINE);
260 return CMD_WARNING;
261 }
262
263 return CMD_SUCCESS;
264}
265
266DEFUN(delete_gb_nsei, delete_gb_nsei_cmd,
267 "delete-gbproxy-peer <0-65534> (only-bvc|only-nsvc|all) [dry-run]",
Harald Welte560bdb32020-12-04 22:24:47 +0100268 "Delete a GBProxy bvc by NSEI and optionally BVCI\n"
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200269 "NSEI number\n"
270 "Only delete BSSGP connections (BVC)\n"
271 "Only delete dynamic NS connections (NS-VC)\n"
272 "Delete BVC and dynamic NS connections\n"
273 "Show what would be deleted instead of actually deleting\n"
274 )
275{
276 const uint16_t nsei = atoi(argv[0]);
277 const char *mode = argv[1];
278 int dry_run = argc > 2;
279 int delete_bvc = 0;
280 int delete_nsvc = 0;
281 int counter;
282
283 if (strcmp(mode, "only-bvc") == 0)
284 delete_bvc = 1;
285 else if (strcmp(mode, "only-nsvc") == 0)
286 delete_nsvc = 1;
287 else
288 delete_bvc = delete_nsvc = 1;
289
290 if (delete_bvc) {
Daniel Willmann5b897712020-12-04 17:43:27 +0100291 if (!dry_run) {
Harald Weltee5209642020-12-05 19:59:45 +0100292 struct gbproxy_nse *nse = gbproxy_nse_by_nsei(g_cfg, nsei, NSE_F_BSS);
293 counter = gbproxy_cleanup_bvcs(nse, 0);
Daniel Willmann5b897712020-12-04 17:43:27 +0100294 gbproxy_nse_free(nse);
295 } else {
Daniel Willmanne50550e2020-11-26 18:19:21 +0100296 struct gbproxy_nse *nse;
Harald Welte560bdb32020-12-04 22:24:47 +0100297 struct gbproxy_bvc *bvc;
Harald Welte8b4c7942020-12-05 10:14:49 +0100298 int i, j;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200299 counter = 0;
Harald Welted2fef952020-12-05 00:31:07 +0100300 hash_for_each(g_cfg->bss_nses, i, nse, list) {
Daniel Willmanne50550e2020-11-26 18:19:21 +0100301 if (nse->nsei != nsei)
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200302 continue;
Harald Welte8b4c7942020-12-05 10:14:49 +0100303 hash_for_each(nse->bvcs, j, bvc, list) {
Daniel Willmanne50550e2020-11-26 18:19:21 +0100304 vty_out(vty, "BVC: ");
Harald Welte560bdb32020-12-04 22:24:47 +0100305 gbprox_vty_print_bvc(vty, bvc);
Daniel Willmanne50550e2020-11-26 18:19:21 +0100306 counter += 1;
307 }
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200308 }
309 }
310 vty_out(vty, "%sDeleted %d BVC%s",
311 dry_run ? "Not " : "", counter, VTY_NEWLINE);
312 }
313
314 if (delete_nsvc) {
Alexander Couzens951e1332020-09-22 13:21:46 +0200315 struct gprs_ns2_inst *nsi = g_cfg->nsi;
316 struct gprs_ns2_nse *nse;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200317
Alexander Couzens951e1332020-09-22 13:21:46 +0200318 nse = gprs_ns2_nse_by_nsei(nsi, nsei);
319 if (!nse) {
320 vty_out(vty, "NSEI not found%s", VTY_NEWLINE);
321 return CMD_WARNING;
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200322 }
Alexander Couzens951e1332020-09-22 13:21:46 +0200323
324 /* TODO: We should NOT delete a persistent NSEI/NSVC as soon as we can check for these */
325 if (!dry_run)
326 gprs_ns2_free_nse(nse);
327
328 vty_out(vty, "%sDeleted NS-VCs for NSEI %d%s",
329 dry_run ? "Not " : "", nsei, VTY_NEWLINE);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200330 }
331
332 return CMD_SUCCESS;
333}
334
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200335int gbproxy_vty_init(void)
336{
337 install_element_ve(&show_gbproxy_cmd);
338 install_element_ve(&show_gbproxy_links_cmd);
Daniel Willmann8f407b12020-12-02 19:33:50 +0100339 install_element_ve(&logging_fltr_bvc_cmd);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200340
341 install_element(ENABLE_NODE, &delete_gb_bvci_cmd);
342 install_element(ENABLE_NODE, &delete_gb_nsei_cmd);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200343
344 install_element(CONFIG_NODE, &cfg_gbproxy_cmd);
345 install_node(&gbproxy_node, config_write_gbproxy);
346 install_element(GBPROXY_NODE, &cfg_nsip_sgsn_nsei_cmd);
Harald Welte209dc9f2020-12-12 19:02:16 +0100347 install_element(GBPROXY_NODE, &cfg_pool_bvc_fc_ratio_cmd);
Pau Espin Pedrol1ddefb12019-08-30 19:48:34 +0200348
349 return 0;
350}
351
352int gbproxy_parse_config(const char *config_file, struct gbproxy_config *cfg)
353{
354 int rc;
355
356 g_cfg = cfg;
357 rc = vty_read_config_file(config_file, NULL);
358 if (rc < 0) {
359 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
360 return rc;
361 }
362
363 return 0;
364}