From 13866f02a2ce49702152efb9191cbf71054f3f61 Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Fri, 12 Nov 2021 13:42:03 +0100 Subject: [PATCH] vty: Introduce command 'gsmtap-remote-host' and 'gsmtap-category enable-all' Related: OS#5306 Change-Id: Ibc6f78c46831b3c90ee3e97300fc13dc441df4c8 --- doc/manuals/chapters/configuration.adoc | 68 +++++++++++++++++++++++++ doc/manuals/chapters/running.adoc | 2 - src/gprs_pcu.h | 1 + src/pcu_main.cpp | 37 ++++++++++---- src/pcu_vty.c | 57 +++++++++++++++++++-- 5 files changed, 150 insertions(+), 15 deletions(-) diff --git a/doc/manuals/chapters/configuration.adoc b/doc/manuals/chapters/configuration.adoc index d7789297..ca3963d7 100644 --- a/doc/manuals/chapters/configuration.adoc +++ b/doc/manuals/chapters/configuration.adoc @@ -422,3 +422,71 @@ encoded in CS1, so in case any control block is sent from time to time it's accomplished and there's no penalty. However, if only EGPRS downlink data is sent over that time frame, then the scheduler will force sending a RLCMAC Dummy Block. + +[[gsmtap]] +=== Configuring GSMTAP tracing + +In addition to being able to obtain pcap protocol traces of the NS/BSSGP +communication and the text-based logging from the OsmoPCU software, there is +also the capability of tracing all communication on the radio interface related +to PS. To do so, OsmoPCU can encapsulate MAC blocks (23-155 byte messages at the +L2-L1 interface depending on coding scheme) into _GSMTAP_ and send them via +UDP/IP. At that point, they can be captured with utilities like *tcpdump* or +*tshark* for further analysis by the *wireshark* protocol analyzer. + +In order to activate this feature, you first need to make sure to specify +the remote address of _GSMTAP_ host in the configuration file. In most +cases, using 127.0.0.1 for passing the messages over the loopback (`lo`) +device will be sufficient: + +.Example: Enabling GSMTAP Um-frame logging to localhost +---- +pcu + gsmtap-remote-host 127.0.0.1 <1> +---- +<1> Destination address for _GSMTAP_ Um-frames + +NOTE: Changing this parameter at run-time will not affect the existing +_GSMTAP_ connection, full program restart is required. + +NOTE: Command line parameters `-i` and `--gsmtap-ip` have been deprecated. + +OsmoPCU can selectively trace such messages based on different categories, for +both Ul and Dl. For a complete list of cateogry values, please refer to the +_OsmoPCU VTY reference manual_ <>. + +For example, to enable GSMTAP tracing for all DL EGPRS rlcmac data blocks, you +can use the `gsmtap-category dl-data-egprs` command at the `pcu` node of the +OsmoPCU VTY. + +.Example: Enabling GSMTAP for for all DL EGPRS rlcmac data blocks +---- +OsmoPCU> enable +OsmoPCU# configure terminal +OsmoPCU(config)# pcu +OsmoPCU(pcu)# gsmtap-category dl-data-egprs +OsmoPCU(trx)# write <1> +---- +<1> the `write` command will make the configuration persistent in the +configuration file. This is not required if you wish to enable GSMTAP +only in the current session of OsmoPCU. + +De-activation can be performed similarly by using the `no gsmtap-category +dl-data-egprs` command at the `pcu` node of the OsmoPCU VTY. + +It may be useful to enable all categories with a few exceptions, or vice versa +disable everything using one command. For this purpose, the VTY provides +`gsmtap-category enable-all` and `gsmtap-category disable-all` commands. + +.Example: Enabling all categoriess except _dl-dummy_ +---- +pcu + gsmtap-category enable-all <1> + no gsmtap-category dl-dummy <2> +---- +<1> Enable all available SAPIs +<2> Exclude DL RLCMAC blocks + +From the moment they are enabled via VTY, GSMTAP messages will be +generated and sent in UDP encapsulation to the IANA-registered UDP port +for GSMTAP (4729) of the specified remote address. diff --git a/doc/manuals/chapters/running.adoc b/doc/manuals/chapters/running.adoc index 78f79b60..c7639746 100644 --- a/doc/manuals/chapters/running.adoc +++ b/doc/manuals/chapters/running.adoc @@ -25,5 +25,3 @@ options: Use the given MCC instead of that provided by BTS via PCU socket *-n, --mnc 'MNC'*:: Use the given MNC instead of that provided by BTS via PCU socket -*-i, --gsmtap-ip 'A.B.C.D'*:: - Send Um interface trace via GSMTAP to specified IP address diff --git a/src/gprs_pcu.h b/src/gprs_pcu.h index fdcf5f7a..ed002213 100644 --- a/src/gprs_pcu.h +++ b/src/gprs_pcu.h @@ -117,6 +117,7 @@ struct gprs_pcu { struct gsmtap_inst *gsmtap; uint32_t gsmtap_categ_mask; + char *gsmtap_remote_host; struct llist_head bts_list; /* list of gprs_rlcmac_bts */ diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 79928530..fe391b99 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -64,7 +64,7 @@ extern void *bv_tall_ctx; static int quit = 0; static int rt_prio = -1; static bool daemonize = false; -static const char *gsmtap_addr = "localhost"; // FIXME: use gengetopt's default value instead +static const char *gsmtap_addr; static void print_help() { @@ -75,7 +75,6 @@ static void print_help() " -n --mnc MNC Use given MNC instead of value provided by BTS\n" " -V --version Print version\n" " -D --daemonize Fork the process into a background daemon\n" - " -i --gsmtap-ip The destination IP used for GSMTAP\n" "\nVTY reference generation:\n" " --vty-ref-mode MODE VTY reference generation mode (e.g. 'expert').\n" " --vty-ref-xml Generate the VTY reference XML output and exit.\n" @@ -161,6 +160,8 @@ static void handle_options(int argc, char **argv) break; case 'i': gsmtap_addr = optarg; + fprintf(stderr, "Command line argument '-i' is deprecated, use VTY " + "parameter 'gsmtap-remote-host %s' instead.\n", gsmtap_addr); break; case 'r': rt_prio = atoi(optarg); @@ -258,13 +259,6 @@ int main(int argc, char *argv[]) exit(0); } - pcu->gsmtap = gsmtap_source_init(gsmtap_addr, GSMTAP_UDP_PORT, 1); - - if (pcu->gsmtap) - gsmtap_source_add_sink(pcu->gsmtap); - else - fprintf(stderr, "Failed to initialize GSMTAP for %s\n", gsmtap_addr); - pcu->nsi = gprs_ns2_instantiate(tall_pcu_ctx, gprs_ns_prim_cb, NULL); if (!pcu->nsi) { LOGP(DBSSGP, LOGL_ERROR, "Failed to create NS instance\n"); @@ -283,6 +277,31 @@ int main(int argc, char *argv[]) fprintf(stderr, "No config file: '%s' Using default config.\n", config_file); + /* Accept a GSMTAP host from VTY config, but a commandline option overrides that. */ + if (gsmtap_addr) { + if (pcu->gsmtap_remote_host != NULL) { + LOGP(DLGLOBAL, LOGL_NOTICE, + "Command line argument '-i %s' overrides " + "'gsmtap-remote-host %s' from the config file\n", + gsmtap_addr, pcu->gsmtap_remote_host); + talloc_free(pcu->gsmtap_remote_host); + } + pcu->gsmtap_remote_host = talloc_strdup(pcu, gsmtap_addr); + } + + if (pcu->gsmtap_remote_host) { + LOGP(DLGLOBAL, LOGL_NOTICE, + "Setting up GSMTAP Um forwarding to '%s:%u'\n", + pcu->gsmtap_remote_host, GSMTAP_UDP_PORT); + pcu->gsmtap = gsmtap_source_init(pcu->gsmtap_remote_host, + GSMTAP_UDP_PORT, 1); + if (pcu->gsmtap == NULL) { + fprintf(stderr, "Failed during gsmtap_source_init()\n"); + exit(1); + } + gsmtap_source_add_sink(pcu->gsmtap); + } + rc = telnet_init_dynif(tall_pcu_ctx, NULL, vty_get_bind_addr(), OSMO_VTY_PORT_PCU); if (rc < 0) { diff --git a/src/pcu_vty.c b/src/pcu_vty.c index c85e324b..6b33e297 100644 --- a/src/pcu_vty.c +++ b/src/pcu_vty.c @@ -70,6 +70,49 @@ static const struct value_string pcu_gsmtap_categ_help[] = { { 0, NULL } }; +DEFUN(cfg_pcu_gsmtap_remote_host, + cfg_pcu_gsmtap_remote_host_cmd, + "gsmtap-remote-host [HOSTNAME]", + "Enable GSMTAP Um logging (see also 'gsmtap-category')\n" + "Remote IP address or hostname ('localhost' if omitted)\n") +{ + osmo_talloc_replace_string(the_pcu, &the_pcu->gsmtap_remote_host, + argc > 0 ? argv[0] : "localhost"); + + if (vty->type != VTY_FILE) + vty_out(vty, "%% This command requires restart%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN(cfg_pcu_no_gsmtap_remote_host, + cfg_pcu_no_gsmtap_remote_host_cmd, + "no gsmtap-remote-host", + NO_STR "Disable GSMTAP Um logging\n") +{ + if (the_pcu->gsmtap_remote_host) + TALLOC_FREE(the_pcu->gsmtap_remote_host); + + if (vty->type != VTY_FILE) + vty_out(vty, "%% This command requires restart%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN(cfg_pcu_gsmtap_sapi_all, pcucfg_pcu_gsmtap_categ_all_cmd, + "gsmtap-category (enable-all|disable-all)", + "Enable/disable sending of UL/DL messages over GSMTAP\n" + "Enable all kinds of messages (all categories)\n" + "Disable all kinds of messages (all categories)\n") +{ + + if (strcmp(argv[0], "enable-all") == 0) + the_pcu->gsmtap_categ_mask = UINT32_MAX; + else + the_pcu->gsmtap_categ_mask = 0x00; + + return CMD_SUCCESS; +} DEFUN(cfg_pcu_gsmtap_categ, cfg_pcu_gsmtap_categ_cmd, "HIDDEN", "HIDDEN") { @@ -238,11 +281,14 @@ static int config_write_pcu(struct vty *vty) if (strcmp(the_pcu->pcu_sock_path, PCU_SOCK_DEFAULT)) vty_out(vty, " pcu-socket %s%s", the_pcu->pcu_sock_path, VTY_NEWLINE); + if (the_pcu->gsmtap_remote_host) + vty_out(vty, " gsmtap-remote-host %s%s", the_pcu->gsmtap_remote_host, VTY_NEWLINE); for (i = 0; i < 32; i++) { - uint32_t cs = ((uint32_t)1 << i); - if (the_pcu->gsmtap_categ_mask & cs) { - vty_out(vty, " gsmtap-category %s%s", - get_value_string(pcu_gsmtap_categ_names, i), VTY_NEWLINE); + if (the_pcu->gsmtap_categ_mask & ((uint32_t)1 << i)) { + const char *category_buf; + if (!(category_buf = get_value_string_or_null(pcu_gsmtap_categ_names, i))) + continue; + vty_out(vty, " gsmtap-category %s%s", category_buf, VTY_NEWLINE); } } @@ -1294,6 +1340,9 @@ int pcu_vty_init(void) install_element(PCU_NODE, &cfg_pcu_no_dl_tbf_preemptive_retransmission_cmd); install_element(PCU_NODE, &cfg_pcu_ms_idle_time_cmd); install_element(PCU_NODE, &cfg_pcu_no_ms_idle_time_cmd); + install_element(PCU_NODE, &cfg_pcu_gsmtap_remote_host_cmd); + install_element(PCU_NODE, &cfg_pcu_no_gsmtap_remote_host_cmd); + install_element(PCU_NODE, &pcucfg_pcu_gsmtap_categ_all_cmd); install_element(PCU_NODE, &cfg_pcu_gsmtap_categ_cmd); install_element(PCU_NODE, &cfg_pcu_no_gsmtap_categ_cmd); install_element(PCU_NODE, &cfg_pcu_sock_cmd);