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

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">add "start_program" support<br><br>This allows the controlling instance (ttcn3 test case) to start<br>a process (shell command) within the namespace of a given tunnel<br>/ tun device.<br><br>The controlling instance is informed of the success/failure<br>of starting the process, as well as the exit code at time of<br>termination.<br><br>Change-Id: I94db625de9f5968e53bf67ce2f941673d9a15fbc<br>Depends: libosmocore.git If1431f930f72a8d6c1d102426874a11b7a2debd9<br>Depends: libosmocore.git If8d89dd1f6989e1cd9b9367fad954d65f91ada30<br>---<br>M daemon/internal.h<br>M daemon/main.c<br>M daemon/tun_device.c<br>M ttcn3/UECUPS_Types.ttcn<br>4 files changed, 233 insertions(+), 1 deletion(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/daemon/internal.h b/daemon/internal.h</span><br><span>index f0e1382..09ba52e 100644</span><br><span>--- a/daemon/internal.h</span><br><span>+++ b/daemon/internal.h</span><br><span>@@ -116,6 +116,9 @@</span><br><span> tun_device_find_or_create(struct gtp_daemon *d, const char *devname, const char *netns_name);</span><br><span> </span><br><span> struct tun_device *</span><br><span style="color: hsl(120, 100%, 40%);">+tun_device_find_netns(struct gtp_daemon *d, const char *netns_name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct tun_device *</span><br><span> _tun_device_find(struct gtp_daemon *d, const char *devname);</span><br><span> </span><br><span> void _tun_device_deref_destroy(struct tun_device *tun);</span><br><span>@@ -202,11 +205,14 @@</span><br><span> </span><br><span> #define UECUPS_SCTP_PORT    4268</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_signalfd;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct gtp_daemon {</span><br><span>     /* global lists of various objects */</span><br><span>        struct llist_head gtp_endpoints;</span><br><span>     struct llist_head tun_devices;</span><br><span>       struct llist_head gtp_tunnels;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct llist_head subprocesses;</span><br><span>      /* lock protecting all of the above lists */</span><br><span>         pthread_rwlock_t rwlock;</span><br><span>     /* main thread ID */</span><br><span>@@ -214,6 +220,7 @@</span><br><span>   /* client CUPS interface */</span><br><span>  struct llist_head cups_clients;</span><br><span>      struct osmo_stream_srv_link *cups_link;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_signalfd *signalfd;</span><br><span> </span><br><span>  struct {</span><br><span>             char *cups_local_ip;</span><br><span>diff --git a/daemon/main.c b/daemon/main.c</span><br><span>index c49b771..155d5d5 100644</span><br><span>--- a/daemon/main.c</span><br><span>+++ b/daemon/main.c</span><br><span>@@ -7,6 +7,7 @@</span><br><span> #include <stdio.h></span><br><span> #include <assert.h></span><br><span> #include <sys/types.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/signalfd.h></span><br><span> #include <signal.h></span><br><span> #include <errno.h></span><br><span> </span><br><span>@@ -20,6 +21,7 @@</span><br><span> #include <osmocom/core/stats.h></span><br><span> #include <osmocom/core/rate_ctr.h></span><br><span> #include <osmocom/core/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/exec.h></span><br><span> #include <osmocom/vty/telnet_interface.h></span><br><span> #include <osmocom/vty/logging.h></span><br><span> #include <osmocom/vty/stats.h></span><br><span>@@ -40,6 +42,8 @@</span><br><span>  * Client (Contol/User Plane Separation) Socket</span><br><span>  ***********************************************************************/</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include <pwd.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #define CUPS_MSGB_SIZE        1024</span><br><span> </span><br><span> #define LOGCC(cc, lvl, fmt, args ...)       \</span><br><span>@@ -55,6 +59,15 @@</span><br><span>       char sockname[OSMO_SOCK_NAME_MAXLEN];</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct subprocess {</span><br><span style="color: hsl(120, 100%, 40%);">+  /* member in daemon->cups_clients */</span><br><span style="color: hsl(120, 100%, 40%);">+       struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+       /* pointer to the client that started us */</span><br><span style="color: hsl(120, 100%, 40%);">+   struct cups_client *cups_client;</span><br><span style="color: hsl(120, 100%, 40%);">+      /* PID of the process */</span><br><span style="color: hsl(120, 100%, 40%);">+      pid_t pid;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Send JSON to a given client/connection */</span><br><span> static int cups_client_tx_json(struct cups_client *cc, json_t *jtx)</span><br><span> {</span><br><span>@@ -289,6 +302,151 @@</span><br><span>         return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static json_t *gen_uecups_term_ind(pid_t pid, int status)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      json_t *jterm = json_object();</span><br><span style="color: hsl(120, 100%, 40%);">+        json_t *jret = json_object();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       json_object_set_new(jterm, "pid", json_integer(pid));</span><br><span style="color: hsl(120, 100%, 40%);">+       json_object_set_new(jterm, "exit_code", json_integer(status));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    json_object_set_new(jret, "program_term_ind", jterm);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return jret;</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct subprocess *subprocess_by_pid(struct gtp_daemon *d, pid_t pid)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct subprocess *sproc;</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_for_each_entry(sproc, &d->subprocesses, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (sproc->pid == pid)</span><br><span style="color: hsl(120, 100%, 40%);">+                     return sproc;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     return NULL;</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 sigchild_cb(struct osmo_signalfd *osfd, const struct signalfd_siginfo *fdsi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gtp_daemon *d = osfd->data;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct subprocess *sproc;</span><br><span style="color: hsl(120, 100%, 40%);">+     json_t *jterm_ind;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(fdsi->ssi_signo == SIGCHLD);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DUECUPS, LOGL_DEBUG, "SIGCHLD receive from pid %u; status=%d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+               fdsi->ssi_pid, fdsi->ssi_status);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     sproc = subprocess_by_pid(d, fdsi->ssi_pid);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!sproc) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DUECUPS, LOGL_NOTICE, "subprocess %u terminated (status=%d) but we don't know it?\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      fdsi->ssi_pid, fdsi->ssi_status);</span><br><span style="color: hsl(120, 100%, 40%);">+               return;</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%);">+   /* FIXME: generate prog_term_ind towards control plane */</span><br><span style="color: hsl(120, 100%, 40%);">+     jterm_ind = gen_uecups_term_ind(fdsi->ssi_pid, fdsi->ssi_status);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!jterm_ind)</span><br><span style="color: hsl(120, 100%, 40%);">+               return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     cups_client_tx_json(sproc->cups_client, jterm_ind);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      llist_del(&sproc->list);</span><br><span style="color: hsl(120, 100%, 40%);">+       talloc_free(sproc);</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 json_t *gen_uecups_start_res(pid_t pid, const char *result)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       json_t *ret = gen_uecups_result("start_program_res", result);</span><br><span style="color: hsl(120, 100%, 40%);">+       json_object_set_new(json_object_get(ret, "start_program_res"), "pid", json_integer(pid));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return ret;</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 cups_client_handle_start_program(struct cups_client *cc, json_t *sprog)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       json_t *juser, *jcmd, *jenv, *jnetns, *jres;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gtp_daemon *d = cc->d;</span><br><span style="color: hsl(120, 100%, 40%);">+      const char *cmd, *user;</span><br><span style="color: hsl(120, 100%, 40%);">+       char **addl_env = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       sigset_t oldmask;</span><br><span style="color: hsl(120, 100%, 40%);">+     int nsfd, rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       juser = json_object_get(sprog, "run_as_user");</span><br><span style="color: hsl(120, 100%, 40%);">+      jcmd = json_object_get(sprog, "command");</span><br><span style="color: hsl(120, 100%, 40%);">+   jenv = json_object_get(sprog, "environment");</span><br><span style="color: hsl(120, 100%, 40%);">+       jnetns = json_object_get(sprog, "tun_netns_name");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* mandatory parts */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!juser || !jcmd)</span><br><span style="color: hsl(120, 100%, 40%);">+          return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!json_is_string(juser) || !json_is_string(jcmd))</span><br><span style="color: hsl(120, 100%, 40%);">+          return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* optional parts */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (jenv && !json_is_array(jenv))</span><br><span style="color: hsl(120, 100%, 40%);">+             return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (jnetns && !json_is_string(jnetns))</span><br><span style="color: hsl(120, 100%, 40%);">+                return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     cmd = json_string_value(jcmd);</span><br><span style="color: hsl(120, 100%, 40%);">+        user = json_string_value(juser);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (jnetns) {</span><br><span style="color: hsl(120, 100%, 40%);">+         struct tun_device *tun = tun_device_find_netns(d, json_string_value(jnetns));</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!tun)</span><br><span style="color: hsl(120, 100%, 40%);">+                     return -ENODEV;</span><br><span style="color: hsl(120, 100%, 40%);">+               nsfd = tun->netns_fd;</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%);">+   /* build environment */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (jenv) {</span><br><span style="color: hsl(120, 100%, 40%);">+           json_t *j;</span><br><span style="color: hsl(120, 100%, 40%);">+            int i;</span><br><span style="color: hsl(120, 100%, 40%);">+                addl_env = talloc_zero_array(cc, char *, json_array_size(jenv)+1);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!addl_env)</span><br><span style="color: hsl(120, 100%, 40%);">+                        return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+               json_array_foreach(jenv, i, j) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      addl_env[i] = talloc_strdup(addl_env, json_string_value(j));</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (jnetns) {</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = switch_ns(nsfd, &oldmask);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      talloc_free(addl_env);</span><br><span style="color: hsl(120, 100%, 40%);">+                        return -EIO;</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = osmo_system_nowait2(cmd, osmo_environment_whitelist, addl_env, user);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (jnetns) {</span><br><span style="color: hsl(120, 100%, 40%);">+         OSMO_ASSERT(restore_ns(&oldmask) == 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%);">+   talloc_free(addl_env);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (rc > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* create a record about the subprocess we started, so we can notify the</span><br><span style="color: hsl(120, 100%, 40%);">+               * client that crated it upon termination */</span><br><span style="color: hsl(120, 100%, 40%);">+          struct subprocess *sproc = talloc_zero(cc, struct subprocess);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!sproc)</span><br><span style="color: hsl(120, 100%, 40%);">+                   return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             sproc->cups_client = cc;</span><br><span style="color: hsl(120, 100%, 40%);">+           sproc->pid = rc;</span><br><span style="color: hsl(120, 100%, 40%);">+           llist_add_tail(&sproc->list, &d->subprocesses);</span><br><span style="color: hsl(120, 100%, 40%);">+         jres = gen_uecups_start_res(sproc->pid, "OK");</span><br><span style="color: hsl(120, 100%, 40%);">+   } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              jres = gen_uecups_start_res(0, "ERR_INVALID_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%);">+   cups_client_tx_json(cc, jres);</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%);">+</span><br><span> static int cups_client_handle_json(struct cups_client *cc, json_t *jroot)</span><br><span> {</span><br><span>   void *iter;</span><br><span>@@ -309,6 +467,8 @@</span><br><span>            rc = cups_client_handle_create_tun(cc, cmd);</span><br><span>         } else if (!strcmp(key, "destroy_tun")) {</span><br><span>          rc = cups_client_handle_destroy_tun(cc, cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (!strcmp(key, "start_program")) {</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = cups_client_handle_start_program(cc, cmd);</span><br><span>      } else {</span><br><span>             LOGCC(cc, LOGL_NOTICE, "Unknown command '%s' received\n", key);</span><br><span>            return -EINVAL;</span><br><span>@@ -387,6 +547,17 @@</span><br><span> static int cups_client_closed_cb(struct osmo_stream_srv *conn)</span><br><span> {</span><br><span>        struct cups_client *cc = osmo_stream_srv_get_data(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gtp_daemon *d = cc->d;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct subprocess *p, *p2;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* kill + forget about all subprocesses of this client */</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_for_each_entry_safe(p, p2, &d->subprocesses, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (p->cups_client == cc) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        kill(p->pid, SIGKILL);</span><br><span style="color: hsl(120, 100%, 40%);">+                     llist_del(&p->list);</span><br><span style="color: hsl(120, 100%, 40%);">+                   talloc_free(p);</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span> </span><br><span>        LOGCC(cc, LOGL_INFO, "UECUPS connection lost\n");</span><br><span>  llist_del(&cc->list);</span><br><span>@@ -404,6 +575,7 @@</span><br><span>   if (!cc)</span><br><span>             return -1;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+        cc->d = d;</span><br><span>        osmo_sock_get_name_buf(cc->sockname, sizeof(cc->sockname), fd);</span><br><span>        cc->srv = osmo_stream_srv_create(cc, link, fd, cups_client_read_cb, cups_client_closed_cb, cc);</span><br><span>   if (!cc->srv) {</span><br><span>@@ -439,6 +611,7 @@</span><br><span>     INIT_LLIST_HEAD(&d->gtp_endpoints);</span><br><span>   INIT_LLIST_HEAD(&d->tun_devices);</span><br><span>     INIT_LLIST_HEAD(&d->gtp_tunnels);</span><br><span style="color: hsl(120, 100%, 40%);">+      INIT_LLIST_HEAD(&d->subprocesses);</span><br><span>    pthread_rwlock_init(&d->rwlock, NULL);</span><br><span>        d->main_thread = pthread_self();</span><br><span> </span><br><span>@@ -528,6 +701,13 @@</span><br><span>       osmo_stream_srv_link_set_accept_cb(g_daemon->cups_link, cups_accept_cb);</span><br><span>  osmo_stream_srv_link_open(g_daemon->cups_link);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+        /* block SIGCHLD via normal delivery; redirect it to signalfd */</span><br><span style="color: hsl(120, 100%, 40%);">+      sigset_t sigset;</span><br><span style="color: hsl(120, 100%, 40%);">+      sigemptyset(&sigset);</span><br><span style="color: hsl(120, 100%, 40%);">+     sigaddset(&sigset, SIGCHLD);</span><br><span style="color: hsl(120, 100%, 40%);">+      sigprocmask(SIG_BLOCK, &sigset, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+    g_daemon->signalfd = osmo_signalfd_setup(g_daemon, sigset, sigchild_cb, g_daemon);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      if (g_daemonize) {</span><br><span>           rc = osmo_daemonize();</span><br><span>               if (rc < 0) {</span><br><span>diff --git a/daemon/tun_device.c b/daemon/tun_device.c</span><br><span>index f6553ca..e20607d 100644</span><br><span>--- a/daemon/tun_device.c</span><br><span>+++ b/daemon/tun_device.c</span><br><span>@@ -337,6 +337,23 @@</span><br><span>     return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* find the first tun device within given named netns */</span><br><span style="color: hsl(120, 100%, 40%);">+struct tun_device *</span><br><span style="color: hsl(120, 100%, 40%);">+tun_device_find_netns(struct gtp_daemon *d, const char *netns_name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct tun_device *tun;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     pthread_rwlock_rdlock(&d->rwlock);</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_for_each_entry(tun, &d->tun_devices, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!strcmp(tun->netns_name, netns_name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        pthread_rwlock_unlock(&d->rwlock);</span><br><span style="color: hsl(120, 100%, 40%);">+                     return tun;</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%);">+     pthread_rwlock_unlock(&d->rwlock);</span><br><span style="color: hsl(120, 100%, 40%);">+     return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct tun_device *</span><br><span> tun_device_find_or_create(struct gtp_daemon *d, const char *devname, const char *netns_name)</span><br><span> {</span><br><span>diff --git a/ttcn3/UECUPS_Types.ttcn b/ttcn3/UECUPS_Types.ttcn</span><br><span>index 3699dee..8861998 100644</span><br><span>--- a/ttcn3/UECUPS_Types.ttcn</span><br><span>+++ b/ttcn3/UECUPS_Types.ttcn</span><br><span>@@ -56,11 +56,39 @@</span><br><span>         UECUPS_Result   result</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* User requests deaemon to start a program in given network namespace */</span><br><span style="color: hsl(120, 100%, 40%);">+type record UECUPS_StartProgram {</span><br><span style="color: hsl(120, 100%, 40%);">+        /* the command to be started (with optional environment entries) */</span><br><span style="color: hsl(120, 100%, 40%);">+   charstring      command,</span><br><span style="color: hsl(120, 100%, 40%);">+      charstring_list environment optional,</span><br><span style="color: hsl(120, 100%, 40%);">+ /* user + group to use when starting command */</span><br><span style="color: hsl(120, 100%, 40%);">+       charstring      run_as_user,</span><br><span style="color: hsl(120, 100%, 40%);">+  /* network namespace in which to start the command */</span><br><span style="color: hsl(120, 100%, 40%);">+ charstring      tun_netns_name optional</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+type record of charstring charstring_list;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Daemon informs us that a program has been started */</span><br><span style="color: hsl(120, 100%, 40%);">+type record UECUPS_StartProgramRes {</span><br><span style="color: hsl(120, 100%, 40%);">+      UECUPS_Result   result,</span><br><span style="color: hsl(120, 100%, 40%);">+       integer         pid</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%);">+/* Daemon informs us that a program has terminated */</span><br><span style="color: hsl(120, 100%, 40%);">+type record UECUPS_ProgramTermInd {</span><br><span style="color: hsl(120, 100%, 40%);">+ integer         pid,</span><br><span style="color: hsl(120, 100%, 40%);">+  integer         exit_code</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%);">+</span><br><span> type union PDU_UECUPS {</span><br><span>         UECUPS_CreateTun        create_tun,</span><br><span>  UECUPS_CreateTunRes     create_tun_res,</span><br><span>      UECUPS_DestroyTun       destroy_tun,</span><br><span style="color: hsl(0, 100%, 40%);">-    UECUPS_DestroyTunRes    destroy_tun_res</span><br><span style="color: hsl(120, 100%, 40%);">+       UECUPS_DestroyTunRes    destroy_tun_res,</span><br><span style="color: hsl(120, 100%, 40%);">+      UECUPS_StartProgram     start_program,</span><br><span style="color: hsl(120, 100%, 40%);">+        UECUPS_StartProgramRes  start_program_res,</span><br><span style="color: hsl(120, 100%, 40%);">+    UECUPS_ProgramTermInd   program_term_ind</span><br><span> };</span><br><span> </span><br><span> </span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-uecups/+/17856">change 17856</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-uecups/+/17856"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-uecups </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I94db625de9f5968e53bf67ce2f941673d9a15fbc </div>
<div style="display:none"> Gerrit-Change-Number: 17856 </div>
<div style="display:none"> Gerrit-PatchSet: 3 </div>
<div style="display:none"> Gerrit-Owner: laforge <laforge@osmocom.org> </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-MessageType: merged </div>