laforge has submitted this change. (
https://gerrit.osmocom.org/c/osmo-e1d/+/27016 )
Change subject: Allow configuration of interfaces/lines via VTY
......................................................................
Allow configuration of interfaces/lines via VTY
So far, osmo-e1d automatically opened all compatible icE1usb devices
and all E1 lines on those interfaces. Let's allow for 'interface' and
'line' configuration in the VTY. USB devices can be identified by
their serial number string.
If a given device (== E1 interface) has a VTY configuration, then only
those E1 lines with VTY configuration opened.
For each Line (icE1usb or vpair), the mode (channelized/superchannel)
can also be set via VTY.
Change-Id: I89b57b688b68901f87d9683ab9294772ee747d77
Closes: OS#5400
---
M src/e1d.h
M src/intf_line.c
M src/usb.c
M src/vty.c
4 files changed, 261 insertions(+), 14 deletions(-)
Approvals:
laforge: Looks good to me, approved; Verified
diff --git a/src/e1d.h b/src/e1d.h
index b76df7a..5d24c5a 100644
--- a/src/e1d.h
+++ b/src/e1d.h
@@ -34,7 +34,8 @@
enum e1d_vty_node {
E1D_NODE = _LAST_OSMOVTY_NODE + 1,
- LINE_NODE
+ INTF_NODE,
+ LINE_NODE,
};
#define line_ctr_add(line, idx, add) rate_ctr_add(rate_ctr_group_get_ctr((line)->ctrs,
idx), add)
@@ -147,6 +148,11 @@
struct e1_daemon *e1d;
uint8_t id;
+ struct {
+ char *serial_str;
+ } usb;
+
+ bool vty_created;
enum e1_driver drv;
void *drv_data;
@@ -171,6 +177,9 @@
struct e1_intf *
e1d_find_intf(struct e1_daemon *e1d, uint8_t id);
+struct e1_intf *
+e1d_find_intf_by_usb_serial(struct e1_daemon *e1d, const char *serial_str);
+
void
e1_intf_destroy(struct e1_intf *intf);
diff --git a/src/intf_line.c b/src/intf_line.c
index cb3f277..3fb9c9d 100644
--- a/src/intf_line.c
+++ b/src/intf_line.c
@@ -95,6 +95,18 @@
return NULL;
}
+struct e1_intf *
+e1d_find_intf_by_usb_serial(struct e1_daemon *e1d, const char *serial_str)
+{
+ struct e1_intf *intf;
+
+ llist_for_each_entry(intf, &e1d->interfaces, list)
+ if (intf->usb.serial_str && !strcmp(intf->usb.serial_str, serial_str))
+ return intf;
+
+ return NULL;
+}
+
struct e1_line *
e1_intf_find_line(struct e1_intf *intf, uint8_t id)
{
diff --git a/src/usb.c b/src/usb.c
index 0100c31..c8920e5 100644
--- a/src/usb.c
+++ b/src/usb.c
@@ -529,9 +529,13 @@
struct e1_line *line;
struct e1_usb_intf_data *intf_data;
struct e1_usb_line_data *line_data;
+ struct libusb_device_descriptor dd;
struct libusb_config_descriptor *cd;
const struct libusb_interface_descriptor *id;
+ bool auto_create_lines;
+ char serial_str[64];
libusb_device_handle *devh;
+ int line_nr = 0;
int i, j, ret;
ret = libusb_open(dev, &devh);
@@ -540,15 +544,57 @@
return ret;
}
- intf_data = talloc_zero(e1d->ctx, struct e1_usb_intf_data);
- intf_data->devh = devh;
+ ret = libusb_get_device_descriptor(dev, &dd);
+ if (ret) {
+ LOGP(DE1D, LOGL_ERROR, "Failed to get device descriptor\n");
+ libusb_close(devh);
+ return ret;
+ }
- intf = e1_intf_new(e1d, -1, intf_data);
- intf->drv = E1_DRIVER_USB;
+ /* this is actually a synchronous / blocking call, and if we detect a second icE1usb
device while the
+ * first one is running, we might be delaying/blocking any important USB transfers.
However, as we
+ * still only call this probe function once at start-up and don't support
hot-plugging yet, we can get
+ * away with it. */
+ ret = libusb_get_string_descriptor_ascii(devh, dd.iSerialNumber, (uint8_t *)serial_str,
sizeof(serial_str));
+ if (ret < 0) {
+ LOGP(DE1D, LOGL_ERROR, "Failed to get iSerialNumber string descriptor\n");
+ libusb_close(devh);
+ return ret;
+ }
+
+ /* try to find the matching interface config created by the vty */
+ intf = e1d_find_intf_by_usb_serial(e1d, serial_str);
+ if (intf) {
+ LOGP(DE1D, LOGL_INFO, "Configuration for icE1usb serial '%s'
found\n", serial_str);
+ auto_create_lines = false;
+ if (intf->drv_data) {
+ LOGP(DE1D, LOGL_ERROR, "New device with serial '%s', but E1 interface %u
busy\n",
+ serial_str, intf->id);
+ libusb_close(devh);
+ return -EBUSY;
+ }
+ intf_data = talloc_zero(e1d->ctx, struct e1_usb_intf_data);
+ intf_data->devh = devh;
+ intf->drv_data = intf_data;
+ } else {
+ LOGP(DE1D, LOGL_NOTICE, "No configuration for icE1usb serial '%s' found,
"
+ "auto-generating it\n", serial_str);
+ auto_create_lines = true;
+ intf_data = talloc_zero(e1d->ctx, struct e1_usb_intf_data);
+ intf_data->devh = devh;
+ intf = e1_intf_new(e1d, -1, intf_data);
+ intf->drv = E1_DRIVER_USB;
+ osmo_talloc_replace_string(intf, &intf->usb.serial_str, serial_str);
+ }
ret = libusb_get_active_config_descriptor(dev, &cd);
if (ret) {
LOGP(DE1D, LOGL_ERROR, "Failed to talk to usb device\n");
+ intf_data->devh = NULL;
+ talloc_free(intf_data);
+ if (auto_create_lines)
+ e1_intf_destroy(intf);
+ libusb_close(devh);
return ret;
}
@@ -561,17 +607,26 @@
if ((id->bInterfaceClass != 0xff) || (id->bInterfaceSubClass != 0xe1) ||
(id->bNumEndpoints < 3))
continue;
+ line = e1_intf_find_line(intf, line_nr);
+ if (line) {
+ OSMO_ASSERT(auto_create_lines == false);
+ if (line->drv_data) {
+ LOGPLI(line, DE1D, LOGL_ERROR, "line busy but we are trying to open it
again?\n");
+ goto next_interface;
+ }
+ }
+
/* Get interface and set it up */
ret = libusb_claim_interface(devh, id->bInterfaceNumber);
if (ret) {
LOGP(DE1D, LOGL_ERROR, "Failed to claim interface %d\n",
id->bInterfaceNumber);
- return ret;
+ goto next_interface;
}
ret = libusb_set_interface_alt_setting(devh, id->bInterfaceNumber, 1);
if (ret) {
LOGP(DE1D, LOGL_ERROR, "Failed to set interface %d altsetting\n",
id->bInterfaceNumber);
- return ret;
+ goto next_interface;
}
/* Setup driver data and find endpoints */
@@ -605,10 +660,20 @@
if (!line_data->ep_in || !line_data->ep_out || !line_data->ep_fb ||
!line_data->pkt_size) {
LOGP(DE1D, LOGL_ERROR, "Failed to use interface %d\n",
id->bInterfaceNumber);
- return -EINVAL;
+ goto next_interface;
}
- line = e1_line_new(intf, -1, line_data);
+ if (!line) {
+ if (!auto_create_lines) {
+ LOGPIF(intf, DE1D, LOGL_ERROR, "No configuration for line %d "
+ "iInterface=%d, skipping\n", line_nr, id->bInterfaceNumber);
+ goto next_interface;
+ }
+ line = e1_line_new(intf, line_nr, line_data);
+ } else {
+ OSMO_ASSERT(auto_create_lines == false);
+ line->drv_data = line_data;
+ }
line_data->flow_in = e1uf_create(line, e1_usb_xfer_in, line_data->ep_in, 4,
line_data->pkt_size, 4);
line_data->flow_out = e1uf_create(line, e1_usb_xfer_out, line_data->ep_out, 4,
line_data->pkt_size, 4);
@@ -620,6 +685,9 @@
if (line_data->ep_int)
resubmit_irq(line);
+
+next_interface:
+ line_nr++;
}
return 0;
diff --git a/src/vty.c b/src/vty.c
index 2f2425c..fca56a4 100644
--- a/src/vty.c
+++ b/src/vty.c
@@ -47,15 +47,35 @@
1,
};
+static struct cmd_node intf_node = {
+ (enum node_type) INTF_NODE,
+ "%s(config-e1d-intf)# ",
+ 1,
+};
+
+static struct cmd_node line_node = {
+ (enum node_type) LINE_NODE,
+ "%s(config-e1d-intf-line)# ",
+ 1,
+};
+
#if 0
static void vty_dump_ts(struct vty *vty, const struct e1_ts *ts)
{
}
#endif
+static const char *intf_serno(const struct e1_intf *intf)
+{
+ if (intf->usb.serial_str)
+ return intf->usb.serial_str;
+ else
+ return "unnamed";
+}
+
static void vty_dump_intf(struct vty *vty, const struct e1_intf *intf)
{
- vty_out(vty, "Interface #%u, Driver: %s%s", intf->id,
+ vty_out(vty, "Interface #%u (%s), Driver: %s%s", intf->id,
intf_serno(intf),
get_value_string(e1_driver_names, intf->drv), VTY_NEWLINE);
}
@@ -100,8 +120,8 @@
};
const struct value_string e1_line_mode_names[] = {
- { E1_LINE_MODE_CHANNELIZED, "CHANNELIZED" },
- { E1_LINE_MODE_SUPERCHANNEL, "SUPERCHANNEL" },
+ { E1_LINE_MODE_CHANNELIZED, "channelized" },
+ { E1_LINE_MODE_SUPERCHANNEL, "superchannel" },
{ 0, NULL }
};
@@ -109,8 +129,9 @@
{
unsigned int tn;
- vty_out(vty, "Interface #%u, Line #%u, Mode %s%s%s:%s", line->intf->id,
line->id,
- get_value_string(e1_line_mode_names, line->mode),
+ vty_out(vty, "Interface #%u (%s), Line #%u, Mode %s%s%s:%s",
line->intf->id,
+ intf_serno(line->intf), line->id,
+ osmo_str_toupper(get_value_string(e1_line_mode_names, line->mode)),
line->ts0.cur_errmask & E1L_TS0_RX_ALARM ? " [REMOTE-ALARM]" :
"",
line->ts0.cur_errmask & E1L_TS0_RX_CRC4_ERR ? " [REMOTE-CRC-ERROR]" :
"",
VTY_NEWLINE);
@@ -177,6 +198,109 @@
return CMD_SUCCESS;
}
+DEFUN(cfg_e1d_if_icE1usb, cfg_e1d_if_icE1usb_cmd, "interface <0-255>
icE1usb",
+ "Configure an icE1usb E1 interface\n"
+ "E1 Interface Number\n")
+{
+ struct e1_intf *intf;
+ int intf_nr = atoi(argv[0]);
+
+ intf = e1d_find_intf(vty_e1d, intf_nr);
+ if (!intf) {
+ intf = e1_intf_new(vty_e1d, intf_nr, NULL);
+ }
+ if (!intf) {
+ vty_out(vty, "%% Could not create interface%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ intf->drv = E1_DRIVER_USB;
+ intf->vty_created = true;
+
+ vty->index = intf;
+ vty->node = INTF_NODE;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_e1d_if_vpair, cfg_e1d_if_vpair_cmd, "interface <0-255> vpair",
+ "Configure a vpair member interface\n"
+ "E1 Interface Number\n")
+{
+ struct e1_intf *intf;
+ int intf_nr = atoi(argv[0]);
+
+ intf = e1d_find_intf(vty_e1d, intf_nr);
+ if (!intf) {
+ vty_out(vty, "%% Could not find E1 interface %u, ddi you create it "
+ "using viertual-e1-pair?%s", intf_nr, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (intf->drv != E1_DRIVER_VPAIR) {
+ vty_out(vty, "%% Interface %u is not a vpair interface%s", intf_nr,
VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ intf->vty_created = true;
+
+ vty->index = intf;
+ vty->node = INTF_NODE;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_e1d_if_usb_serial, cfg_e1d_if_usb_serial_cmd,
+ "usb-serial SERNO",
+ "Configure the USB serial number of an E1 interface device\n"
+ "iSerial string\n")
+{
+ struct e1_intf *intf = vty->index;
+
+ if (intf->drv != E1_DRIVER_USB)
+ return CMD_WARNING;
+
+ osmo_talloc_replace_string(intf, &intf->usb.serial_str, argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_e1d_if_line, cfg_e1d_if_line_cmd, "line <0-255>",
+ "Configure an E1 line\n"
+ "E1 Interface Number\n")
+{
+ struct e1_intf *intf = vty->index;
+ struct e1_line *line;
+ int line_nr = atoi(argv[0]);
+
+ line = e1_intf_find_line(intf, line_nr);
+ if (!line)
+ line = e1_line_new(intf, line_nr, NULL);
+ if (!line) {
+ vty_out(vty, "%% Could not create line%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ vty->index = line;
+ vty->node = LINE_NODE;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_e1d_if_line_mode, cfg_e1d_if_line_mode_cmd,
+ "mode (channelized|superchannel)",
+ "Configure the mode of the E1 line\n"
+ "Channelized (64kBps timeslot) mode\n"
+ "Superchannel (1xHDLC over 31x64kBps) mode\n")
+{
+ struct e1_line *line = vty->index;
+
+ line->mode = get_string_value(e1_line_mode_names, argv[0]);
+ return CMD_SUCCESS;
+}
+
+
+static int config_write_line(struct vty *vty, struct e1_line *line)
+{
+ vty_out(vty, " line %u%s", line->id, VTY_NEWLINE);
+ vty_out(vty, " mode %s%s", get_value_string(e1_line_mode_names,
line->mode), VTY_NEWLINE);
+
+ return 0;
+}
+
static int config_write_e1d(struct vty *vty)
{
struct e1_intf *intf;
@@ -204,6 +328,31 @@
vty_out(vty, " virtual-e1-pair %u%s", line_count, VTY_NEWLINE);
}
+
+ /* dump line config for those lines that were created by the vty */
+ llist_for_each_entry(intf, &vty_e1d->interfaces, list) {
+ struct e1_line *line;
+
+ if (!intf->vty_created)
+ continue;
+
+ switch (intf->drv) {
+ case E1_DRIVER_USB:
+ vty_out(vty, " interface %u icE1usb%s", intf->id, VTY_NEWLINE);
+ if (intf->usb.serial_str && strlen(intf->usb.serial_str))
+ vty_out(vty, " usb-serial %s%s", intf->usb.serial_str, VTY_NEWLINE);
+ break;
+ case E1_DRIVER_VPAIR:
+ vty_out(vty, " interface %u vpair%s", intf->id, VTY_NEWLINE);
+ break;
+ default:
+ break;
+ }
+
+ llist_for_each_entry(line, &intf->lines, list)
+ config_write_line(vty, line);
+ }
+
return 0;
}
@@ -216,4 +365,13 @@
install_node(&e1d_node, config_write_e1d);
install_element(CONFIG_NODE, &cfg_e1d_cmd);
install_element(E1D_NODE, &cfg_vpair_cmd);
+
+ install_node(&intf_node, NULL);
+ install_element(E1D_NODE, &cfg_e1d_if_icE1usb_cmd);
+ install_element(E1D_NODE, &cfg_e1d_if_vpair_cmd);
+ install_element(INTF_NODE, &cfg_e1d_if_line_cmd);
+ install_element(INTF_NODE, &cfg_e1d_if_usb_serial_cmd);
+
+ install_node(&line_node, NULL);
+ install_element(LINE_NODE, &cfg_e1d_if_line_mode_cmd);
}
--
To view, visit
https://gerrit.osmocom.org/c/osmo-e1d/+/27016
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-e1d
Gerrit-Branch: master
Gerrit-Change-Id: I89b57b688b68901f87d9683ab9294772ee747d77
Gerrit-Change-Number: 27016
Gerrit-PatchSet: 7
Gerrit-Owner: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: tnt <tnt(a)246tNt.com>
Gerrit-MessageType: merged