From 8154266457616ca59dea4990f0e29fe0ea298662 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 7 Nov 2016 21:15:24 +0100 Subject: libosmogb: Support multiple instances also from VTY The NS code (part of libosmogb) already understands the concept of "NS instances", and each of those instances can be bound to different IP addresses with the gprs_ns_nsip_listen() call. The problem is the VTY code for NS. It is written with a single global ns-instance in mind. Having a second NS instance thus means that currently only one of the two would be configurable (or available for "show..." commands) from the VTY, which is of course of little usefulness. This patch addresses this by introducing the concept of "NS instance numbers" and a global array of a maximum of 256 NS instances. The VTY commands have been extended as needed. Change-Id: I483e9984f046e0e698c65b59034b3a6141e7ca73 --- TODO-RELEASE | 1 + include/osmocom/gprs/gprs_ns.h | 6 ++ src/gb/gprs_ns.c | 29 +++++++++ src/gb/gprs_ns_vty.c | 142 ++++++++++++++++++++++++++++++----------- src/gb/libosmogb.map | 1 + 5 files changed, 143 insertions(+), 36 deletions(-) diff --git a/TODO-RELEASE b/TODO-RELEASE index 648b6a6d..ec54135f 100644 --- a/TODO-RELEASE +++ b/TODO-RELEASE @@ -4,3 +4,4 @@ libosmocore change major external talloc dependency / internal talloc removal libosmocore change major size of ph_data_param struct changed / Extend L1SAP PH-DATA with presence information libosmocore change major size of ph_data_param struct changed / Extend L1SAP PH-DATA with measurement information libosmocore change major size of ph_tch_param struct changed / Extend with RTP Marker +libosmogb change major layout of 'struct gprs_ns_instance' changed, breaks ABI diff --git a/include/osmocom/gprs/gprs_ns.h b/include/osmocom/gprs/gprs_ns.h index 130d8c0f..d95924da 100644 --- a/include/osmocom/gprs/gprs_ns.h +++ b/include/osmocom/gprs/gprs_ns.h @@ -69,6 +69,9 @@ typedef int gprs_ns_cb_t(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, /*! \brief An instance of the NS protocol stack */ struct gprs_ns_inst { + /*! \brief the unique instance number of this NS instance */ + uint8_t nr; + /*! \brief callback to the user for incoming UNIT DATA IND */ gprs_ns_cb_t *cb; @@ -145,6 +148,9 @@ struct gprs_nsvc { /* Create a new NS protocol instance */ struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb, void *ctx); +/* Obtain a NS instance of a given ID */ +struct gprs_ns_inst *gprs_ns_instance_by_id(uint8_t inst_nr); + /* Close a NS protocol instance */ void gprs_ns_close(struct gprs_ns_inst *nsi); diff --git a/src/gb/gprs_ns.c b/src/gb/gprs_ns.c index 18845d4b..7105c4ab 100644 --- a/src/gb/gprs_ns.c +++ b/src/gb/gprs_ns.c @@ -85,6 +85,9 @@ #include "common_vty.h" +/* array of NS instance pointers */ +static struct gprs_ns_inst *g_ns_instances[256]; + static const struct tlv_definition ns_att_tlvdef = { .def = { [NS_IE_CAUSE] = { TLV_TYPE_TvLV, 0 }, @@ -1372,6 +1375,22 @@ int gprs_ns_process_msg(struct gprs_ns_inst *nsi, struct msgb *msg, return rc; } +static int find_next_free_instance_id(void) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(g_ns_instances); i++) { + if (!g_ns_instances[i]) + return i; + } + return -1; +} + +struct gprs_ns_inst *gprs_ns_instance_by_id(uint8_t id) +{ + return g_ns_instances[id]; +} + /*! \brief Create a new GPRS NS instance * \param[in] cb Call-back function for incoming BSSGP data * \returns dynamically allocated gprs_ns_inst @@ -1379,7 +1398,14 @@ int gprs_ns_process_msg(struct gprs_ns_inst *nsi, struct msgb *msg, struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb, void *ctx) { struct gprs_ns_inst *nsi = talloc_zero(ctx, struct gprs_ns_inst); + int rc; + rc = find_next_free_instance_id(); + if (rc < 0) { + talloc_free(nsi); + return NULL; + } + nsi->nr = rc; nsi->cb = cb; INIT_LLIST_HEAD(&nsi->gprs_nsvcs); nsi->timeout[NS_TOUT_TNS_BLOCK] = 3; @@ -1427,6 +1453,9 @@ void gprs_ns_close(struct gprs_ns_inst *nsi) void gprs_ns_destroy(struct gprs_ns_inst *nsi) { gprs_ns_close(nsi); + /* remove from global array of NS instances */ + OSMO_ASSERT(g_ns_instances[nsi->nr] == nsi); + g_ns_instances[nsi->nr] = NULL; /* free the NSI */ talloc_free(nsi); } diff --git a/src/gb/gprs_ns_vty.c b/src/gb/gprs_ns_vty.c index 5a951dca..2fe0c865 100644 --- a/src/gb/gprs_ns_vty.c +++ b/src/gb/gprs_ns_vty.c @@ -42,8 +42,6 @@ #include "common_vty.h" -static struct gprs_ns_inst *vty_nsi = NULL; - /* FIXME: this should go to some common file as it is copied * in vty_interface.c of the BSC */ static const struct value_string gprs_ns_timer_strs[] = { @@ -80,8 +78,9 @@ static int config_write_ns(struct vty *vty) struct gprs_nsvc *nsvc; unsigned int i; struct in_addr ia; + struct gprs_ns_inst *vty_nsi = vty->index; - vty_out(vty, "ns%s", VTY_NEWLINE); + vty_out(vty, "ns %u%s", vty_nsi->nr, VTY_NEWLINE); llist_for_each_entry(nsvc, &vty_nsi->gprs_nsvcs, list) { if (!nsvc->persistent) @@ -147,16 +146,33 @@ static int config_write_ns(struct vty *vty) } DEFUN(cfg_ns, cfg_ns_cmd, - "ns", + "ns [<0-255>]", "Configure the GPRS Network Service") { + struct gprs_ns_inst *nsi; + int inst_nr; + + if (argc < 1) { + vty_out(vty, "Implicitly selecting NS Instance 0%s", + VTY_NEWLINE); + inst_nr = 0; + } else + inst_nr = atoi(argv[0]); + nsi = gprs_ns_instance_by_id(inst_nr); + if (!nsi) { + vty_out(vty, "No such NS Instance%s", VTY_NEWLINE); + return CMD_WARNING; + } + vty->node = L_NS_NODE; + vty->index = nsi; + return CMD_SUCCESS; } static void dump_nse(struct vty *vty, struct gprs_nsvc *nsvc, int stats) { - vty_out(vty, "NSEI %5u, NS-VC %5u, Remote: %-4s, %5s %9s", + vty_out(vty, " NSEI %5u, NS-VC %5u, Remote: %-4s, %5s %9s", nsvc->nsei, nsvc->nsvci, nsvc->remote_end_is_sgsn ? "SGSN" : "BSS", nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD", @@ -178,12 +194,13 @@ static void dump_ns(struct vty *vty, struct gprs_ns_inst *nsi, int stats) struct gprs_nsvc *nsvc; struct in_addr ia; - ia.s_addr = htonl(vty_nsi->nsip.local_ip); - vty_out(vty, "Encapsulation NS-UDP-IP Local IP: %s, UDP Port: %u%s", - inet_ntoa(ia), vty_nsi->nsip.local_port, VTY_NEWLINE); + ia.s_addr = htonl(nsi->nsip.local_ip); + vty_out(vty, "NS Instance %u%s", nsi->nr, VTY_NEWLINE); + vty_out(vty, " Encapsulation NS-UDP-IP Local IP: %s, UDP Port: %u%s", + inet_ntoa(ia), nsi->nsip.local_port, VTY_NEWLINE); - ia.s_addr = htonl(vty_nsi->frgre.local_ip); - vty_out(vty, "Encapsulation NS-FR-GRE-IP Local IP: %s%s", + ia.s_addr = htonl(nsi->frgre.local_ip); + vty_out(vty, " Encapsulation NS-FR-GRE-IP Local IP: %s%s", inet_ntoa(ia), VTY_NEWLINE); llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { @@ -193,37 +210,65 @@ static void dump_ns(struct vty *vty, struct gprs_ns_inst *nsi, int stats) } } -DEFUN(show_ns, show_ns_cmd, "show ns", - SHOW_STR "Display information about the NS protocol") +DEFUN(show_ns, show_ns_cmd, "show ns all [stats]", + SHOW_STR "Display information about the NS protocol\n" + "Display information about all NS protocol instances\n" + "Include statistics\n") { - struct gprs_ns_inst *nsi = vty_nsi; - dump_ns(vty, nsi, 0); + struct gprs_ns_inst *nsi; + int stats = 0; + unsigned int i; + + if (argc > 0) + stats = 1; + + for (i = 0; i < 256; i++) { + nsi = gprs_ns_instance_by_id(i); + if (nsi) + dump_ns(vty, nsi, stats); + } return CMD_SUCCESS; } -DEFUN(show_ns_stats, show_ns_stats_cmd, "show ns stats", - SHOW_STR - "Display information about the NS protocol\n" +DEFUN(show_ns_stats, show_ns_stats_cmd, "show ns <0-255> [stats]", + SHOW_STR "Display information about the NS protocol\n" + "Information about one given NS Instance Number\n" "Include statistics\n") { - struct gprs_ns_inst *nsi = vty_nsi; - dump_ns(vty, nsi, 1); + struct gprs_ns_inst *nsi; + int stats = 0; + + if (argc > 1) + stats = 1; + + nsi = gprs_ns_instance_by_id(atoi(argv[0])); + if (!nsi) { + vty_out(vty, "No such NS Instance%s", VTY_NEWLINE); + return CMD_WARNING; + } + dump_ns(vty, nsi, stats); return CMD_SUCCESS; } -DEFUN(show_nse, show_nse_cmd, "show ns (nsei|nsvc) <0-65535> [stats]", +DEFUN(show_nse, show_nse_cmd, "show ns <0-255> (nsei|nsvc) <0-65535> [stats]", SHOW_STR "Display information about the NS protocol\n" + "NS Protocol Instance Number\n" "Select one NSE by its NSE Identifier\n" "Select one NSE by its NS-VC Identifier\n" "The Identifier of selected type\n" "Include Statistics\n") { - struct gprs_ns_inst *nsi = vty_nsi; + struct gprs_ns_inst *nsi = gprs_ns_instance_by_id(atoi(argv[0])); struct gprs_nsvc *nsvc; - uint16_t id = atoi(argv[1]); + uint16_t id = atoi(argv[2]); int show_stats = 0; - if (!strcmp(argv[0], "nsei")) + if (!nsi) { + vty_out(vty, "No such NS Instance%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (!strcmp(argv[1], "nsei")) nsvc = gprs_nsvc_by_nsei(nsi, id); else nsvc = gprs_nsvc_by_nsvci(nsi, id); @@ -249,6 +294,7 @@ DEFUN(cfg_nse_nsvc, cfg_nse_nsvci_cmd, "NS Virtual Connection ID (NSVCI)\n" ) { + struct gprs_ns_inst *vty_nsi = vty->index; uint16_t nsei = atoi(argv[0]); uint16_t nsvci = atoi(argv[1]); struct gprs_nsvc *nsvc; @@ -273,6 +319,7 @@ DEFUN(cfg_nse_remoteip, cfg_nse_remoteip_cmd, "Remote IP Address\n" "Remote IP Address\n") { + struct gprs_ns_inst *vty_nsi = vty->index; uint16_t nsei = atoi(argv[0]); struct gprs_nsvc *nsvc; @@ -293,6 +340,7 @@ DEFUN(cfg_nse_remoteport, cfg_nse_remoteport_cmd, "Remote UDP Port\n" "Remote UDP Port Number\n") { + struct gprs_ns_inst *vty_nsi = vty->index; uint16_t nsei = atoi(argv[0]); uint16_t port = atoi(argv[1]); struct gprs_nsvc *nsvc; @@ -320,6 +368,7 @@ DEFUN(cfg_nse_fr_dlci, cfg_nse_fr_dlci_cmd, "Frame Relay DLCI\n" "Frame Relay DLCI Number\n") { + struct gprs_ns_inst *vty_nsi = vty->index; uint16_t nsei = atoi(argv[0]); uint16_t dlci = atoi(argv[1]); struct gprs_nsvc *nsvc; @@ -347,6 +396,7 @@ DEFUN(cfg_nse_encaps, cfg_nse_encaps_cmd, "Encapsulation for NS\n" "UDP/IP Encapsulation\n" "Frame-Relay/GRE/IP Encapsulation\n") { + struct gprs_ns_inst *vty_nsi = vty->index; uint16_t nsei = atoi(argv[0]); struct gprs_nsvc *nsvc; @@ -372,6 +422,7 @@ DEFUN(cfg_nse_remoterole, cfg_nse_remoterole_cmd, "Remote Peer is SGSN\n" "Remote Peer is BSS\n") { + struct gprs_ns_inst *vty_nsi = vty->index; uint16_t nsei = atoi(argv[0]); struct gprs_nsvc *nsvc; @@ -394,6 +445,7 @@ DEFUN(cfg_no_nse, cfg_no_nse_cmd, "Delete Persistent NS Entity\n" "Delete " NSE_CMD_STR) { + struct gprs_ns_inst *vty_nsi = vty->index; uint16_t nsei = atoi(argv[0]); struct gprs_nsvc *nsvc; @@ -419,6 +471,7 @@ DEFUN(cfg_ns_timer, cfg_ns_timer_cmd, "Network Service Timer\n" NS_TIMERS_HELP "Timer Value\n") { + struct gprs_ns_inst *vty_nsi = vty->index; int idx = get_string_value(gprs_ns_timer_strs, argv[0]); int val = atoi(argv[1]); @@ -438,6 +491,7 @@ DEFUN(cfg_nsip_local_ip, cfg_nsip_local_ip_cmd, "Set the IP address on which we listen for NS/UDP\n" "IP Address\n") { + struct gprs_ns_inst *vty_nsi = vty->index; struct in_addr ia; inet_aton(argv[0], &ia); @@ -452,6 +506,7 @@ DEFUN(cfg_nsip_local_port, cfg_nsip_local_port_cmd, "Set the UDP port on which we listen for NS/UDP\n" "UDP port number\n") { + struct gprs_ns_inst *vty_nsi = vty->index; unsigned int port = atoi(argv[0]); vty_nsi->nsip.local_port = port; @@ -464,6 +519,7 @@ DEFUN(cfg_nsip_dscp, cfg_nsip_dscp_cmd, ENCAPS_STR "NS over UDP Encapsulation\n" "Set DSCP/TOS on the UDP socket\n" "DSCP Value\n") { + struct gprs_ns_inst *vty_nsi = vty->index; int dscp = atoi(argv[0]); vty_nsi->nsip.dscp = dscp; return CMD_SUCCESS; @@ -475,6 +531,7 @@ DEFUN(cfg_frgre_local_ip, cfg_frgre_local_ip_cmd, "Set the IP address on which we listen for NS/FR/GRE\n" "IP Address\n") { + struct gprs_ns_inst *vty_nsi = vty->index; struct in_addr ia; if (!vty_nsi->frgre.enabled) { @@ -493,6 +550,7 @@ DEFUN(cfg_frgre_enable, cfg_frgre_enable_cmd, "Enable or disable Frame Relay over GRE\n" "Enable\n" "Disable\n") { + struct gprs_ns_inst *vty_nsi = vty->index; int enabled = atoi(argv[0]); vty_nsi->frgre.enabled = enabled; @@ -501,8 +559,9 @@ DEFUN(cfg_frgre_enable, cfg_frgre_enable_cmd, } DEFUN(nsvc_nsei, nsvc_nsei_cmd, - "nsvc (nsei|nsvci) <0-65535> (block|unblock|reset)", + "ns <0-255> nsvc (nsei|nsvci) <0-65535> (block|unblock|reset)", "Perform an operation on a NSVC\n" + "NS Protocol Instance Number\n" "NSEI to identify NS-VC Identifier (NS-VCI)\n" "NS-VC Identifier (NS-VCI)\n" "The NSEI\n" @@ -510,15 +569,21 @@ DEFUN(nsvc_nsei, nsvc_nsei_cmd, "Initiate UNBLOCK procedure\n" "Initiate RESET procedure\n") { - const char *id_type = argv[0]; - uint16_t id = atoi(argv[1]); - const char *operation = argv[2]; + struct gprs_ns_inst *nsi = gprs_ns_instance_by_id(atoi(argv[0])); + const char *id_type = argv[1]; + uint16_t id = atoi(argv[2]); + const char *operation = argv[3]; struct gprs_nsvc *nsvc; + if (!nsi) { + vty_out(vty, "No such NS Instance%s", VTY_NEWLINE); + return CMD_WARNING; + } + if (!strcmp(id_type, "nsei")) - nsvc = gprs_nsvc_by_nsei(vty_nsi, id); + nsvc = gprs_nsvc_by_nsei(nsi, id); else if (!strcmp(id_type, "nsvci")) - nsvc = gprs_nsvc_by_nsvci(vty_nsi, id); + nsvc = gprs_nsvc_by_nsvci(nsi, id); else { vty_out(vty, "%%No such id_type '%s'%s", id_type, VTY_NEWLINE); return CMD_WARNING; @@ -543,24 +608,31 @@ DEFUN(nsvc_nsei, nsvc_nsei_cmd, DEFUN(logging_fltr_nsvc, logging_fltr_nsvc_cmd, - "logging filter nsvc (nsei|nsvci) <0-65535>", + "logging filter nsvc <0-255> (nsei|nsvci) <0-65535>", LOGGING_STR FILTER_STR "Filter based on NS Virtual Connection\n" + "Ns Instance Number\n" "Identify NS-VC by NSEI\n" "Identify NS-VC by NSVCI\n" "Numeric identifier\n") { + struct gprs_ns_inst *nsi = gprs_ns_instance_by_id(atoi(argv[0])); struct log_target *tgt = osmo_log_vty2tgt(vty); struct gprs_nsvc *nsvc; - uint16_t id = atoi(argv[1]); + uint16_t id = atoi(argv[2]); + + if (!nsi) { + vty_out(vty, "No such NS Instance%s", VTY_NEWLINE); + return CMD_WARNING; + } if (!tgt) return CMD_WARNING; - if (!strcmp(argv[0], "nsei")) - nsvc = gprs_nsvc_by_nsei(vty_nsi, id); + if (!strcmp(argv[1], "nsei")) + nsvc = gprs_nsvc_by_nsei(nsi, id); else - nsvc = gprs_nsvc_by_nsvci(vty_nsi, id); + nsvc = gprs_nsvc_by_nsvci(nsi, id); if (!nsvc) { vty_out(vty, "No NS-VC by that identifier%s", VTY_NEWLINE); @@ -573,8 +645,6 @@ DEFUN(logging_fltr_nsvc, int gprs_ns_vty_init(struct gprs_ns_inst *nsi) { - vty_nsi = nsi; - install_element_ve(&show_ns_cmd); install_element_ve(&show_ns_stats_cmd); install_element_ve(&show_nse_cmd); diff --git a/src/gb/libosmogb.map b/src/gb/libosmogb.map index 9aec2805..76ce3fba 100644 --- a/src/gb/libosmogb.map +++ b/src/gb/libosmogb.map @@ -44,6 +44,7 @@ gprs_ns_close; gprs_ns_frgre_listen; gprs_ns_frgre_sendmsg; gprs_ns_instantiate; +gprs_ns_instance_by_id; gprs_ns_nsip_listen; gprs_ns_nsip_connect; gprs_ns_rcvmsg; -- cgit v1.2.3