<p>laforge <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-e1d/+/19047">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  tnt: Looks good to me, but someone else must approve
  laforge: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Add virtual pair of E1 interfaces<br><br>The idea is to generate a pair of virtual E1 interfaces (each with<br>identical number of lines), where each line A:n is connected to line B:n<br>of the pair and vice-versa.<br><br>This allows to test E1 using applications back to back against each<br>other, without any physical E1 circuits in between.<br><br>Change-Id: If42c959556b17d543762546eb45dd69d25f715f2<br>---<br>M src/Makefile.am<br>M src/ctl.c<br>M src/e1d.h<br>M src/intf_line.c<br>A src/vpair.c<br>M src/vty.c<br>6 files changed, 232 insertions(+), 9 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/Makefile.am b/src/Makefile.am</span><br><span>index aa796f2..e811f0a 100644</span><br><span>--- a/src/Makefile.am</span><br><span>+++ b/src/Makefile.am</span><br><span>@@ -35,6 +35,7 @@</span><br><span>        log.c \</span><br><span>      osmo-e1d.c \</span><br><span>         usb.c \</span><br><span style="color: hsl(120, 100%, 40%);">+       vpair.c \</span><br><span>    vty.c \</span><br><span>      $(NULL)</span><br><span> </span><br><span>diff --git a/src/ctl.c b/src/ctl.c</span><br><span>index b29e990..0fb42de 100644</span><br><span>--- a/src/ctl.c</span><br><span>+++ b/src/ctl.c</span><br><span>@@ -52,8 +52,8 @@</span><br><span>     return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static struct e1_line *</span><br><span style="color: hsl(0, 100%, 40%);">-_e1d_find_line(struct e1_intf *intf, uint8_t id)</span><br><span style="color: hsl(120, 100%, 40%);">+struct e1_line *</span><br><span style="color: hsl(120, 100%, 40%);">+e1_intf_find_line(struct e1_intf *intf, uint8_t id)</span><br><span> {</span><br><span>     struct e1_line *line;</span><br><span> </span><br><span>@@ -185,7 +185,7 @@</span><br><span>              return 0;</span><br><span> </span><br><span>        if (hdr->line != E1DP_INVALID) {</span><br><span style="color: hsl(0, 100%, 40%);">-             line = _e1d_find_line(intf, hdr->line);</span><br><span style="color: hsl(120, 100%, 40%);">+            line = e1_intf_find_line(intf, hdr->line);</span><br><span>                n = line ? 1 : 0;</span><br><span>    } else{</span><br><span>              n = llist_count(&intf->lines);</span><br><span>@@ -226,7 +226,7 @@</span><br><span>  if (!intf)</span><br><span>           return 0;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   line = _e1d_find_line(intf, hdr->line);</span><br><span style="color: hsl(120, 100%, 40%);">+    line = e1_intf_find_line(intf, hdr->line);</span><br><span>        if (!line)</span><br><span>           return 0;</span><br><span> </span><br><span>@@ -272,7 +272,7 @@</span><br><span>  if (!intf)</span><br><span>           return 0;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   line = _e1d_find_line(intf, hdr->line);</span><br><span style="color: hsl(120, 100%, 40%);">+    line = e1_intf_find_line(intf, hdr->line);</span><br><span>        if (!line)</span><br><span>           return 0;</span><br><span> </span><br><span>diff --git a/src/e1d.h b/src/e1d.h</span><br><span>index 7803b2e..64e8f45 100644</span><br><span>--- a/src/e1d.h</span><br><span>+++ b/src/e1d.h</span><br><span>@@ -67,6 +67,7 @@</span><br><span> </span><br><span> enum e1_driver {</span><br><span>   E1_DRIVER_USB,</span><br><span style="color: hsl(120, 100%, 40%);">+        E1_DRIVER_VPAIR,</span><br><span> };</span><br><span> </span><br><span> extern const struct value_string e1_driver_names[];</span><br><span>@@ -97,6 +98,10 @@</span><br><span> void</span><br><span> e1_intf_destroy(struct e1_intf *intf);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct e1_line *</span><br><span style="color: hsl(120, 100%, 40%);">+e1_intf_find_line(struct e1_intf *intf, uint8_t id);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct e1_line *</span><br><span> e1_line_new(struct e1_intf *intf, void *drv_data);</span><br><span> </span><br><span>@@ -115,3 +120,5 @@</span><br><span> void</span><br><span> e1d_vty_init(struct e1_daemon *e1d);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+int</span><br><span style="color: hsl(120, 100%, 40%);">+e1d_vpair_create(struct e1_daemon *e1d, unsigned int num_lines);</span><br><span>diff --git a/src/intf_line.c b/src/intf_line.c</span><br><span>index afe477d..ce30b4f 100644</span><br><span>--- a/src/intf_line.c</span><br><span>+++ b/src/intf_line.c</span><br><span>@@ -36,6 +36,7 @@</span><br><span> </span><br><span> const struct value_string e1_driver_names[] = {</span><br><span>  { E1_DRIVER_USB, "usb" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { E1_DRIVER_VPAIR, "vpair" },</span><br><span>      { 0, NULL }</span><br><span> };</span><br><span> </span><br><span>diff --git a/src/vpair.c b/src/vpair.c</span><br><span>new file mode 100644</span><br><span>index 0000000..12452fe</span><br><span>--- /dev/null</span><br><span>+++ b/src/vpair.c</span><br><span>@@ -0,0 +1,196 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Virtual E1 interface pair: Two virtual interfaces with N lines each,</span><br><span style="color: hsl(120, 100%, 40%);">+ * where data written to A can be read from B and vice-versa.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2020 by Harald Welte <laforge@osmocom.org></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * SPDX-License-Identifier: GPL-2.0+</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 2 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU General Public License along</span><br><span style="color: hsl(120, 100%, 40%);">+ * with this program; if not, write to the Free Software Foundation, Inc.,</span><br><span style="color: hsl(120, 100%, 40%);">+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <limits.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <unistd.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <inttypes.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "e1d.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "log.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* number of bits in each frame */</span><br><span style="color: hsl(120, 100%, 40%);">+#define BITS_PER_FRAME           (32*8)</span><br><span style="color: hsl(120, 100%, 40%);">+/* overall bit-rate of E1 line in bits per second */</span><br><span style="color: hsl(120, 100%, 40%);">+#define BITRATE                   2048000</span><br><span style="color: hsl(120, 100%, 40%);">+/* number of frames per second (8000) */</span><br><span style="color: hsl(120, 100%, 40%);">+#define FRAME_RATE           (BITRATE / BITS_PER_FRAME)</span><br><span style="color: hsl(120, 100%, 40%);">+/* duration of one frame in nanoseconds (125000) */</span><br><span style="color: hsl(120, 100%, 40%);">+#define FRAME_DURATION_NS      (1000000000UL / FRAME_RATE)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* number of E1 frames (32bytes) to handle for each timer interval */</span><br><span style="color: hsl(120, 100%, 40%);">+#define FRAMES_PER_TIMER  10</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ve1_intf_data {</span><br><span style="color: hsl(120, 100%, 40%);">+  /* pointer to other side of the interface pair */</span><br><span style="color: hsl(120, 100%, 40%);">+     struct e1_intf *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_fd timerfd;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ve1_line_data {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* pointer to other side of the interface pair */</span><br><span style="color: hsl(120, 100%, 40%);">+     struct e1_line *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct e1_intf *</span><br><span style="color: hsl(120, 100%, 40%);">+vintf_create(struct e1_daemon *e1d, unsigned int num_lines)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct e1_intf *intf;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ve1_intf_data *intf_data;</span><br><span style="color: hsl(120, 100%, 40%);">+      unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     intf_data = talloc_zero(e1d->ctx, struct ve1_intf_data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ intf = e1_intf_new(e1d, intf_data);</span><br><span style="color: hsl(120, 100%, 40%);">+   intf->drv = E1_DRIVER_VPAIR;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     for (i = 0; i < num_lines; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+          struct ve1_line_data *line_data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            line_data = talloc_zero(e1d->ctx, struct ve1_line_data);</span><br><span style="color: hsl(120, 100%, 40%);">+           e1_line_new(intf, line_data);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return intf;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void</span><br><span style="color: hsl(120, 100%, 40%);">+vintf_destroy(struct e1_intf *intf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(intf->drv == E1_DRIVER_VPAIR);</span><br><span style="color: hsl(120, 100%, 40%);">+ e1_intf_destroy(intf);</span><br><span style="color: hsl(120, 100%, 40%);">+        talloc_free(intf->drv_data);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int</span><br><span style="color: hsl(120, 100%, 40%);">+ve1_timerfd_cb(struct osmo_fd *ofd, unsigned int what)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct e1_intf *intf = ofd->data;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct e1_line *line, *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint64_t expire_count;</span><br><span style="color: hsl(120, 100%, 40%);">+        unsigned int frames_expired;</span><br><span style="color: hsl(120, 100%, 40%);">+  int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!(what & OSMO_FD_READ))</span><br><span style="color: hsl(120, 100%, 40%);">+               return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = read(ofd->fd, (void *) &expire_count, sizeof(expire_count));</span><br><span style="color: hsl(120, 100%, 40%);">+      if (rc < 0 && errno == EAGAIN)</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(rc == sizeof(expire_count));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (expire_count > 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DE1D, LOGL_NOTICE, "vpair timer expire_count=%" PRIu64</span><br><span style="color: hsl(120, 100%, 40%);">+                 ": We missed %" PRIu64 " timers\n", expire_count, expire_count-1);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(expire_count < UINT_MAX/FRAMES_PER_TIMER);</span><br><span style="color: hsl(120, 100%, 40%);">+     frames_expired = expire_count * FRAMES_PER_TIMER;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_for_each_entry(line, &intf->lines, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+               uint8_t buf[32*frames_expired];</span><br><span style="color: hsl(120, 100%, 40%);">+               struct ve1_line_data *ldata = line->drv_data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            peer = ldata->peer;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              /* generate data on current line */</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = e1_line_mux_out(line, buf, frames_expired);</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(rc >= 0);</span><br><span style="color: hsl(120, 100%, 40%);">+              /* write data to peer */</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = e1_line_demux_in(peer, buf, rc);</span><br><span style="color: hsl(120, 100%, 40%);">+         OSMO_ASSERT(rc >= 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            /* generate data on peer line */</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = e1_line_mux_out(peer, buf, frames_expired);</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(rc >= 0);</span><br><span style="color: hsl(120, 100%, 40%);">+              /* write data to current line */</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = e1_line_demux_in(line, buf, rc);</span><br><span style="color: hsl(120, 100%, 40%);">+         OSMO_ASSERT(rc >= 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int</span><br><span style="color: hsl(120, 100%, 40%);">+e1d_vpair_create(struct e1_daemon *e1d, unsigned int num_lines)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct e1_intf *a, *b;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct e1_line *al, *bl;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ve1_intf_data *adata, *bdata;</span><br><span style="color: hsl(120, 100%, 40%);">+  int rc = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* create both interfaces, each with identical line count */</span><br><span style="color: hsl(120, 100%, 40%);">+  a = vintf_create(e1d, num_lines);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!a)</span><br><span style="color: hsl(120, 100%, 40%);">+               goto err;</span><br><span style="color: hsl(120, 100%, 40%);">+     adata = a->drv_data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     b = vintf_create(e1d, num_lines);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!b)</span><br><span style="color: hsl(120, 100%, 40%);">+               goto err_free_a;</span><br><span style="color: hsl(120, 100%, 40%);">+      bdata = b->drv_data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* point the interfaces at each other */</span><br><span style="color: hsl(120, 100%, 40%);">+      adata->peer = b;</span><br><span style="color: hsl(120, 100%, 40%);">+   bdata->peer = a;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* point the lines at each other */</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_for_each_entry(al, &a->lines, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+            struct ve1_line_data *aldata, *bldata;</span><br><span style="color: hsl(120, 100%, 40%);">+                bl = e1_intf_find_line(b, al->id);</span><br><span style="color: hsl(120, 100%, 40%);">+         OSMO_ASSERT(bl);</span><br><span style="color: hsl(120, 100%, 40%);">+              aldata = al->drv_data;</span><br><span style="color: hsl(120, 100%, 40%);">+             bldata = bl->drv_data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           aldata->peer = bl;</span><br><span style="color: hsl(120, 100%, 40%);">+         bldata->peer = al;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* schedule timer only for 'a' side; handles both directions */</span><br><span style="color: hsl(120, 100%, 40%);">+       struct timespec interval = {</span><br><span style="color: hsl(120, 100%, 40%);">+          .tv_sec = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+          .tv_nsec = FRAME_DURATION_NS*FRAMES_PER_TIMER,</span><br><span style="color: hsl(120, 100%, 40%);">+        };</span><br><span style="color: hsl(120, 100%, 40%);">+    adata->timerfd.fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    rc = osmo_timerfd_setup(&adata->timerfd, ve1_timerfd_cb, a);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                goto err_free_b;</span><br><span style="color: hsl(120, 100%, 40%);">+      rc = osmo_timerfd_schedule(&adata->timerfd, NULL, &interval);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                goto err_free_b;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+err_free_b:</span><br><span style="color: hsl(120, 100%, 40%);">+      vintf_destroy(b);</span><br><span style="color: hsl(120, 100%, 40%);">+err_free_a:</span><br><span style="color: hsl(120, 100%, 40%);">+        vintf_destroy(a);</span><br><span style="color: hsl(120, 100%, 40%);">+err:</span><br><span style="color: hsl(120, 100%, 40%);">+       return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/vty.c b/src/vty.c</span><br><span>index 88b6257..57a21bf 100644</span><br><span>--- a/src/vty.c</span><br><span>+++ b/src/vty.c</span><br><span>@@ -3,16 +3,16 @@</span><br><span>  * All Rights Reserved</span><br><span>  *</span><br><span>  * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(0, 100%, 40%);">- * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(0, 100%, 40%);">- * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 2 of the License, or</span><br><span>  * (at your option) any later version.</span><br><span>  *</span><br><span>  * This program is distributed in the hope that it will be useful,</span><br><span>  * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span>  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(0, 100%, 40%);">- * GNU Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span>  *</span><br><span style="color: hsl(0, 100%, 40%);">- * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU General Public License</span><br><span>  * along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span>  *</span><br><span>  */</span><br><span>@@ -131,9 +131,27 @@</span><br><span>    return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_vpair, cfg_vpair_cmd, "virtual-e1-pair <1-255>",</span><br><span style="color: hsl(120, 100%, 40%);">+      "Create a virtual E1 interface pair\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      "Number of E1 lines in virtual E1 interface pair\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     int num_lines = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = e1d_vpair_create(vty_e1d, num_lines);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, "%% Error creating virtual-e1-pair: %d%s", rc, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+           return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> void e1d_vty_init(struct e1_daemon *e1d)</span><br><span> {</span><br><span>    vty_e1d = e1d;</span><br><span>       install_element_ve(&show_intf_cmd);</span><br><span>      install_element_ve(&show_line_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     install_element(CONFIG_NODE, &cfg_vpair_cmd);</span><br><span> }</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-e1d/+/19047">change 19047</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-e1d/+/19047"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-e1d </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: If42c959556b17d543762546eb45dd69d25f715f2 </div>
<div style="display:none"> Gerrit-Change-Number: 19047 </div>
<div style="display:none"> Gerrit-PatchSet: 5 </div>
<div style="display:none"> Gerrit-Owner: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Assignee: tnt <tnt@246tNt.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: tnt <tnt@246tNt.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>