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
This commit is contained in:
Harald Welte 2020-06-29 16:57:09 +02:00
parent 0b621b43e7
commit 9144ba0373
6 changed files with 238 additions and 9 deletions

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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);

139
src/vty.c Normal file
View File

@ -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);
}