aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@osmocom.org>2020-06-29 16:57:09 +0200
committerHarald Welte <laforge@osmocom.org>2020-06-29 22:12:42 +0200
commit9144ba03738504d770a8cf3a644f64a14ebd7e8b (patch)
treef935808384ed4f7c7075e645b63f0887828f4907
parent0b621b43e75f45a9c64eef42b5aae83f248a42d5 (diff)
VTY interface support
Let's add a VTY interface on TCP port 4269. The purpose is - for now - not for configuration storage, but for state introspection. Change-Id: I47b6e4efaad52e68e2b50a7993076f3706f86628
-rw-r--r--configure.ac1
-rw-r--r--src/Makefile.am7
-rw-r--r--src/ctl.c12
-rw-r--r--src/e1d.h6
-rw-r--r--src/osmo-e1d.c82
-rw-r--r--src/vty.c139
6 files changed, 238 insertions, 9 deletions
diff --git a/configure.ac b/configure.ac
index c0508eb..5be845b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -33,6 +33,7 @@ PKG_PROG_PKG_CONFIG([0.20])
PKG_CHECK_MODULES(TALLOC, [talloc >= 2.0.1])
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.0.1.120)
+PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty)
PKG_CHECK_MODULES(LIBOSMOUSB, libosmousb)
PKG_CHECK_MODULES(LIBUSB, libusb-1.0 >= 1.0.21)
diff --git a/src/Makefile.am b/src/Makefile.am
index bc05998..aa796f2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -4,7 +4,8 @@
LIBVERSION=0:0:0
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
-AM_CFLAGS=-Wall -Wno-unused-result $(LIBOSMOCORE_CFLAGS) $(LIBOSMOUSB_LIBS) $(LIBUSB_CFLAGS)
+AM_CFLAGS=-Wall -Wno-unused-result $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOVTY_LIBS) $(LIBOSMOUSB_LIBS) $(LIBUSB_CFLAGS)
lib_LTLIBRARIES = libosmo-e1d.la
@@ -34,6 +35,8 @@ osmo_e1d_SOURCES = \
log.c \
osmo-e1d.c \
usb.c \
+ vty.c \
$(NULL)
-osmo_e1d_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOUSB_LIBS) $(LIBUSB_LIBS) libosmo-e1d.la
+osmo_e1d_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) \
+ $(LIBOSMOUSB_LIBS) $(LIBUSB_LIBS) libosmo-e1d.la
diff --git a/src/ctl.c b/src/ctl.c
index 835811f..a70556d 100644
--- a/src/ctl.c
+++ b/src/ctl.c
@@ -38,8 +38,8 @@
#include "e1d.h"
-static struct e1_intf *
-_e1d_find_intf(struct e1_daemon *e1d, uint8_t id)
+struct e1_intf *
+e1d_find_intf(struct e1_daemon *e1d, uint8_t id)
{
struct e1_intf *intf;
@@ -137,7 +137,7 @@ _e1d_ctl_intf_query(void *data, struct msgb *msgb, struct msgb *rmsgb, int *rfd)
/* Process query and find interface */
if (hdr->intf != E1DP_INVALID) {
- intf = _e1d_find_intf(e1d, hdr->intf);
+ intf = e1d_find_intf(e1d, hdr->intf);
n = intf ? 1 : 0;
} else {
n = llist_count(&e1d->interfaces);
@@ -174,7 +174,7 @@ _e1d_ctl_line_query(void *data, struct msgb *msgb, struct msgb *rmsgb, int *rfd)
int n;
/* Process query and find line */
- intf = _e1d_find_intf(e1d, hdr->intf);
+ intf = e1d_find_intf(e1d, hdr->intf);
if (!intf)
return 0;
@@ -216,7 +216,7 @@ _e1d_ctl_ts_query(void *data, struct msgb *msgb, struct msgb *rmsgb, int *rfd)
int n;
/* Process query and find timeslot */
- intf = _e1d_find_intf(e1d, hdr->intf);
+ intf = e1d_find_intf(e1d, hdr->intf);
if (!intf)
return 0;
@@ -262,7 +262,7 @@ _e1d_ctl_ts_open(void *data, struct msgb *msgb, struct msgb *rmsgb, int *rfd)
int ret;
/* Process query and find timeslot */
- intf = _e1d_find_intf(e1d, hdr->intf);
+ intf = e1d_find_intf(e1d, hdr->intf);
if (!intf)
return 0;
diff --git a/src/e1d.h b/src/e1d.h
index 5b7ba83..303757f 100644
--- a/src/e1d.h
+++ b/src/e1d.h
@@ -84,6 +84,9 @@ struct e1_daemon {
struct e1_intf *
e1_intf_new(struct e1_daemon *e1d, void *drv_data);
+struct e1_intf *
+e1d_find_intf(struct e1_daemon *e1d, uint8_t id);
+
struct e1_line *
e1_line_new(struct e1_intf *intf, void *drv_data);
@@ -92,3 +95,6 @@ e1_line_mux_out(struct e1_line *line, uint8_t *buf, int fts);
int
e1_line_demux_in(struct e1_line *line, const uint8_t *buf, int size);
+
+void
+e1d_vty_init(struct e1_daemon *e1d);
diff --git a/src/osmo-e1d.c b/src/osmo-e1d.c
index 92d98d3..808bd68 100644
--- a/src/osmo-e1d.c
+++ b/src/osmo-e1d.c
@@ -28,23 +28,30 @@
#include <stdio.h>
#include <string.h>
+#define _GNU_SOURCE
+#include <getopt.h>
+
#include <talloc.h>
#include <osmocom/core/application.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/select.h>
+#include <osmocom/vty/telnet_interface.h>
#include <osmocom/e1d/proto_srv.h>
#include "e1d.h"
#include "log.h"
+#ifndef OSMO_VTY_PORT_E1D
+#define OSMO_VTY_PORT_E1D 4269
+#endif
extern struct osmo_e1dp_server_handler e1d_ctl_handlers[];
extern int e1_usb_probe(struct e1_daemon *e1d);
-
+static const char *g_config_file = "osmo-e1d.cfg";
static void *g_e1d_ctx = NULL;
static int g_shutdown = 0;
@@ -71,6 +78,61 @@ static void sig_handler(int signo)
}
}
+static struct vty_app_info vty_info = {
+ .name = "osmo-e1d",
+ .version = PACKAGE_VERSION,
+ .copyright =
+ "(C) 2019 by Sylvain Munaut <tnt@246tNt.com>\r\n",
+ "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl-2.0.html>\r\n"
+ "This is free software: you are free to change and redistribute it.\r\n"
+ "There is NO WARRANTY, to the extent permitted by law.\r\n",
+};
+
+static void print_help(void)
+{
+ printf(" Some useful help...\n");
+ printf(" -h --help This text.\n");
+ printf(" -d --debug option --debug=DE1D:DXFR enable debugging.\n");
+ printf(" -c --config-file filename The config file to use.\n");
+}
+
+static void handle_options(int argc, char **argv)
+{
+ while (1) {
+ int option_index = 0, c;
+ static const struct option long_options[] = {
+ {"help", 0, 0, 'h'},
+ {"debug", 1, 0, 'd'},
+ {"config-file", 1, 0, 'c'},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long(argc, argv, "hd:c:", long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'h':
+ print_help();
+ exit(0);
+ break;
+ case 'd':
+ log_parse_category_mask(osmo_stderr_target, optarg);
+ break;
+ case 'c':
+ g_config_file = optarg;
+ break;
+ default:
+ fprintf(stderr, "Error in command line options. Exiting.\n");
+ exit(-1);
+ }
+ }
+
+ if (argc > optind) {
+ fprintf(stderr, "Unsupported positional arguments on command line\n");
+ exit(2);
+ }
+}
int main(int argc, char *argv[])
{
@@ -82,6 +144,7 @@ int main(int argc, char *argv[])
/* talloc init */
g_e1d_ctx = talloc_named_const(NULL, 0, "osmo-e1d");
msgb_talloc_ctx_init(g_e1d_ctx, 0);
+ vty_info.tall_ctx = g_e1d_ctx;
/* logging init */
osmo_init_logging2(g_e1d_ctx, &log_info);
@@ -108,6 +171,23 @@ int main(int argc, char *argv[])
OSMO_ASSERT(e1d);
INIT_LLIST_HEAD(&e1d->interfaces);
+ vty_init(&vty_info);
+ e1d_vty_init(e1d);
+
+ handle_options(argc, argv);
+
+ rv = vty_read_config_file(g_config_file, NULL);
+ if (rv < 0) {
+ LOGP(DE1D, LOGL_FATAL, "Failed to parse the config file '%s'\n", g_config_file);
+ exit(2);
+ }
+
+ rv = telnet_init_dynif(g_e1d_ctx, e1d, vty_get_bind_addr(), OSMO_VTY_PORT_E1D);
+ if (rv != 0) {
+ LOGP(DE1D, LOGL_FATAL, "Failed to bind VTY interface to %s:%u\n",
+ vty_get_bind_addr(), OSMO_VTY_PORT_E1D);
+ exit(1);
+ }
/* probe devices */
rv = e1_usb_probe(e1d);
diff --git a/src/vty.c b/src/vty.c
new file mode 100644
index 0000000..88b6257
--- /dev/null
+++ b/src/vty.c
@@ -0,0 +1,139 @@
+/* osmo-e1d VTY interface */
+/* (C) 2020 by Harald Welte <laforge@osmocom.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#define _GNU_SOURCE /* struct ucred */
+#include <sys/socket.h>
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <osmocom/core/linuxlist.h>
+
+#include <osmocom/vty/command.h>
+#include <osmocom/vty/buffer.h>
+#include <osmocom/vty/vty.h>
+#include <osmocom/vty/logging.h>
+#include <osmocom/vty/stats.h>
+#include <osmocom/vty/telnet_interface.h>
+#include <osmocom/vty/misc.h>
+#include <osmocom/vty/tdef_vty.h>
+
+#include <osmocom/e1d/proto.h>
+#include "e1d.h"
+
+static struct e1_daemon *vty_e1d;
+
+#if 0
+static void vty_dump_ts(struct vty *vty, const struct e1_ts *ts)
+{
+}
+#endif
+
+static void vty_dump_intf(struct vty *vty, const struct e1_intf *intf)
+{
+ vty_out(vty, "Interface #%u, Driver: FIXME%s", intf->id, VTY_NEWLINE);
+}
+
+DEFUN(show_intf, show_intf_cmd, "show interface [<0-255>]",
+ SHOW_STR "Display information about an E1 Interface/Card\n")
+{
+ struct e1_intf *intf;
+
+ if (argc) {
+ int id = atoi(argv[0]);
+ intf = e1d_find_intf(vty_e1d, id);
+ if (!intf) {
+ vty_out(vty, "%% Unknown interface %u%s\n", id, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ vty_dump_intf(vty, intf);
+ } else {
+ llist_for_each_entry(intf, &vty_e1d->interfaces, list)
+ vty_dump_intf(vty, intf);
+ }
+
+ return CMD_SUCCESS;
+}
+
+static int get_remote_pid(int fd)
+{
+ struct ucred uc;
+ socklen_t len = sizeof(uc);
+ int rc;
+
+ rc = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &uc, &len);
+ if (rc != 0)
+ return -1;
+ return uc.pid;
+}
+
+static const struct value_string e1_ts_mode_names[] = {
+ { E1_TS_MODE_OFF, "OFF" },
+ { E1_TS_MODE_RAW, "RAW" },
+ { E1_TS_MODE_HDLCFCS, "HDLC-FCS" },
+ { 0, NULL }
+};
+
+static void vty_dump_line(struct vty *vty, const struct e1_line *line)
+{
+ int tn;
+
+ vty_out(vty, "Interface #%u, Line #%u:%s", line->intf->id, line->id, VTY_NEWLINE);
+
+ for (tn = 0; tn < ARRAY_SIZE(line->ts); tn++) {
+ const struct e1_ts *ts = &line->ts[tn];
+ vty_out(vty, " TS%02u: Mode %s, FD %d, Peer PID %d%s",
+ ts->id, get_value_string(e1_ts_mode_names, ts->mode),
+ ts->fd, get_remote_pid(ts->fd), VTY_NEWLINE);
+ }
+}
+
+DEFUN(show_line, show_line_cmd, "show line [<0-255>]",
+ SHOW_STR "Display information about an E1 Line\n")
+{
+ struct e1_line *line;
+ struct e1_intf *intf;
+
+ if (argc) {
+ int id = atoi(argv[0]);
+ intf = e1d_find_intf(vty_e1d, id);
+ if (!intf) {
+ vty_out(vty, "%% Unknown interface %u%s\n", id, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ llist_for_each_entry(line, &intf->lines, list)
+ vty_dump_line(vty, line);
+ } else {
+ llist_for_each_entry(intf, &vty_e1d->interfaces, list) {
+ llist_for_each_entry(line, &intf->lines, list)
+ vty_dump_line(vty, line);
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+void e1d_vty_init(struct e1_daemon *e1d)
+{
+ vty_e1d = e1d;
+ install_element_ve(&show_intf_cmd);
+ install_element_ve(&show_line_cmd);
+}