pespin has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/osmo-ggsn/+/38480?usp=email )


Change subject: ggsn: use libosmocore tundev API to create apn tun device
......................................................................

ggsn: use libosmocore tundev API to create apn tun device

This way we can start dropping old osmo-ggsn specific API, avoiding
duplication of code.
Moreover, the osmo-ggsn code is using older ioctl APIs, which are
discouraged nowadays in favour of netlink, which osmo_tundev/osmo_netdev
from libosmocore is used.

While doing this, BSD code is dropped since anyway it's not been
maintained for a long time.
If needed, the BSD support can be added to libosmocore
osmo_tundev/osmo_netdev API.

This is a first step (already working). Follow-up commits will replace
the APIs to set up routes and addresses, and later on osmo-ggsn will win
support to set MTU on the interface.

Furthermore, this will allow easily adding netns support to osmo-ggsn
later on if ever needed.

Change-Id: I4d99ba147ac0f3b414d2efef0068b6b8d6cf0014
---
M TODO-RELEASE
M ggsn/ggsn.c
M ggsn/ggsn.h
M lib/tun.c
M lib/tun.h
M sgsnemu/sgsnemu.c
6 files changed, 90 insertions(+), 148 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-ggsn refs/changes/80/38480/1

diff --git a/TODO-RELEASE b/TODO-RELEASE
index 905c234..194885d 100644
--- a/TODO-RELEASE
+++ b/TODO-RELEASE
@@ -9,4 +9,5 @@
 #library       what                    description / commit summary line
 libgtp    append new field  dir_tun_flags in struct pdp_t (older users not 
using the field should be fine since struct pdp_t is allocated internally)
 libgtp    ABI break  new field cb_create_context_ind in struct gsn_t
-libgtp    new API    gtp_set_cb_update_context_ind(), gtp_update_context_resp()
\ No newline at end of file
+libgtp    new API    gtp_set_cb_update_context_ind(), gtp_update_context_resp()
+libosmocore >1.10.0   osmo_tundev_get_fd()
\ No newline at end of file
diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c
index 19b0132..7967f42 100644
--- a/ggsn/ggsn.c
+++ b/ggsn/ggsn.c
@@ -62,7 +62,6 @@

 LLIST_HEAD(g_ggsn_list);

-static int ggsn_tun_fd_cb(struct osmo_fd *fd, unsigned int what);
 static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len);

 void ggsn_close_one_pdp(struct pdp_t *pdp)
@@ -150,7 +149,6 @@
                if (apn->cfg.gtpu_mode == APN_GTPU_MODE_TUN) {
                        /* release tun device */
                        LOGPAPN(LOGL_INFO, apn, "Closing TUN device %s\n", 
apn->tun.tun->devname);
-                       osmo_fd_unregister(&apn->tun.fd);
                }
                tun_free(apn->tun.tun);
                apn->tun.tun = NULL;
@@ -234,10 +232,6 @@
                }
                LOGPAPN(LOGL_INFO, apn, "Opened TUN device %s\n", 
apn->tun.tun->devname);

-               /* Register with libosmocore */
-               osmo_fd_setup(&apn->tun.fd, apn->tun.tun->fd, OSMO_FD_READ, 
ggsn_tun_fd_cb, apn, 0);
-               osmo_fd_register(&apn->tun.fd);
-
                /* Set TUN library callback */
                tun_set_cb_ind(apn->tun.tun, cb_tun_ind);
                break;
@@ -799,16 +793,6 @@
        return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
 }
 
-/* callback for tun device osmocom select loop integration */
-static int ggsn_tun_fd_cb(struct osmo_fd *fd, unsigned int what)
-{
-       struct apn_ctx *apn = fd->data;
-
-       OSMO_ASSERT(what & OSMO_FD_READ);
-
-       return tun_decaps(apn->tun.tun);
-}
-
 /* callback for libgtp osmocom select loop integration */
 static int ggsn_gtp_fd_cb(struct osmo_fd *fd, unsigned int what)
 {
diff --git a/ggsn/ggsn.h b/ggsn/ggsn.h
index a212a06..28f9d04 100644
--- a/ggsn/ggsn.h
+++ b/ggsn/ggsn.h
@@ -103,7 +103,6 @@
                        char *ipdown_script;
                } cfg;
                struct tun_t *tun;
-               struct osmo_fd fd;
        } tun;

        /* ipv6 link-local address */
diff --git a/lib/tun.c b/lib/tun.c
index cb66fef..acc3927 100644
--- a/lib/tun.c
+++ b/lib/tun.c
@@ -41,20 +41,9 @@
 #include <net/route.h>
 #include <net/if.h>

-#if defined(__linux__)
 #include <linux/if_tun.h>

-#elif defined (__FreeBSD__)
-#include <net/if_tun.h>
-#include <net/if_var.h>
-#include <netinet/in_var.h>
-
-#elif defined (__APPLE__)
-#include <net/if.h>
-
-#else
-#error  "Unknown platform!"
-#endif
+#include <osmocom/core/msgb.h>

 #include "tun.h"
 #include "syserr.h"
@@ -155,121 +144,93 @@
        }
 }

+static int tun_tundev_data_ind_cb(struct osmo_tundev *tundev, struct msgb *msg)
+{
+       struct tun_t *tun = osmo_tundev_get_priv_data(tundev);
+       int rc = 0;
+       if (tun->cb_ind)
+               rc = tun->cb_ind(tun, msgb_data(msg), msgb_length(msg));
+       msgb_free(msg);
+       return rc;
+}
+
 int tun_new(struct tun_t **tun, const char *dev_name, bool use_kernel, int 
fd0, int fd1u)
 {
+       struct tun_t *t;
+       int rc;

-#if defined(__linux__)
-       struct ifreq ifr;
-
-#elif defined(__FreeBSD__) || defined (__APPLE__)
-       char devname[IFNAMSIZ + 5];     /* "/dev/" + ifname */
-       int devnum;
-       struct ifaliasreq areq;
-       int fd;
-#endif
-
-       if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
-               SYS_ERR(DTUN, LOGL_ERROR, errno, "calloc() failed");
+       t = talloc_zero(NULL, struct tun_t);
+       if (!t) {
+               SYS_ERR(DTUN, LOGL_ERROR, errno, "talloc_zero() failed");
                return EOF;
        }
+       *tun = t;

-       (*tun)->cb_ind = NULL;
-       (*tun)->addrs = 0;
-       (*tun)->routes = 0;
+       t->cb_ind = NULL;
+       t->addrs = 0;
+       t->routes = 0;
+       t->fd = -1;

-#if defined(__linux__)
        if (!use_kernel) {
-               /* Open the actual tun device */
-               if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
-                       SYS_ERR(DTUN, LOGL_ERROR, errno, "open() failed");
+               osmo_strlcpy(t->devname, dev_name, IFNAMSIZ);
+               t->devname[IFNAMSIZ - 1] = 0;
+
+               t->tundev = osmo_tundev_alloc(t, dev_name);
+               if (!t->tundev)
                        goto err_free;
-               }
+               osmo_tundev_set_priv_data(t->tundev, t);
+               osmo_tundev_set_data_ind_cb(t->tundev, tun_tundev_data_ind_cb);
+               rc = osmo_tundev_set_dev_name(t->tundev, dev_name);
+               if (rc < 0)
+                       goto err_free_tundev;

-               /* Set device flags. For some weird reason this is also the 
method
-                  used to obtain the network interface name */
-               memset(&ifr, 0, sizeof(ifr));
-               if (dev_name)
-                       strcpy(ifr.ifr_name, dev_name);
-               ifr.ifr_flags = IFF_TUN | IFF_NO_PI;    /* Tun device, no 
packet info */
-               if (ioctl((*tun)->fd, TUNSETIFF, (void *)&ifr) < 0) {
-                       SYS_ERR(DTUN, LOGL_ERROR, errno, "ioctl() failed");
-                       goto err_close;
-               }
-
-               strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
-               (*tun)->devname[IFNAMSIZ - 1] = 0;
+               /* Open the actual tun device */
+               rc = osmo_tundev_open(t->tundev);
+               if (rc < 0)
+                       goto err_free;
+               t->fd = osmo_tundev_get_fd(t->tundev);
+               t->netdev = osmo_tundev_get_netdev(t->tundev);

                /* Disable checksums */
-               if (ioctl((*tun)->fd, TUNSETNOCSUM, 1) < 0) {
-                       SYS_ERR(DTUN, LOGL_NOTICE, errno, "could not disable 
checksum on %s", (*tun)->devname);
+               if (ioctl(t->fd, TUNSETNOCSUM, 1) < 0) {
+                       SYS_ERR(DTUN, LOGL_NOTICE, errno, "could not disable 
checksum on %s", t->devname);
                }
+
+               LOGP(DTUN, LOGL_NOTICE, "tun %s configured\n", t->devname);
                return 0;
+err_free_tundev:
+       osmo_tundev_free(t->tundev);
+err_free:
+       talloc_free(t);
+       *tun = NULL;
+       return -1;
+
        } else {
-               strncpy((*tun)->devname, dev_name, IFNAMSIZ);
-               (*tun)->devname[IFNAMSIZ - 1] = 0;
-               (*tun)->fd = -1;
+               osmo_strlcpy(t->devname, dev_name, IFNAMSIZ);
+               t->devname[IFNAMSIZ - 1] = 0;

                if (gtp_kernel_create(-1, dev_name, fd0, fd1u) < 0) {
                        LOGP(DTUN, LOGL_ERROR, "cannot create GTP tunnel 
device: %s\n",
                                strerror(errno));
                        return -1;
                }
+               t->netdev = osmo_netdev_alloc(t, dev_name);
+               if (!t->netdev)
+                       goto err_kernel_create;
+               rc = osmo_netdev_set_ifindex(t->netdev, 
if_nametoindex(dev_name));
+               if (rc < 0)
+                       goto err_netdev_free;
+               rc = osmo_netdev_register(t->netdev);
+               if (rc < 0)
+                       goto err_netdev_free;
                LOGP(DTUN, LOGL_NOTICE, "GTP kernel configured\n");
                return 0;
-       }
-
-#elif defined(__FreeBSD__) || defined (__APPLE__)
-
-       if (use_kernel) {
-               LOGP(DTUN, LOGL_ERROR, "No kernel GTP-U support in FreeBSD!\n");
-               return -1;
-       }
-
-       /* Find suitable device */
-       for (devnum = 0; devnum < 255; devnum++) {      /* TODO 255 */
-               snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
-               if (((*tun)->fd = open(devname, O_RDWR)) >= 0)
-                       break;
-               if (errno != EBUSY)
-                       break;
-       }
-       if ((*tun)->fd < 0) {
-               SYS_ERR(DTUN, LOGL_ERROR, errno,
-                       "Can't find tunnel device");
-               goto err_free;
-       }
-
-       snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum);
-       (*tun)->devname[sizeof((*tun)->devname)-1] = 0;
-
-       /* The tun device we found might have "old" IP addresses allocated */
-       /* We need to delete those. This problem is not present on Linux */
-
-       memset(&areq, 0, sizeof(areq));
-
-       /* Set up interface name */
-       strncpy(areq.ifra_name, (*tun)->devname, IFNAMSIZ);
-       areq.ifra_name[IFNAMSIZ - 1] = 0;       /* Make sure to terminate */
-
-       /* Create a channel to the NET kernel. */
-       if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
-               SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
-               goto err_close;
-       }
-
-       /* Delete any IP addresses until SIOCDIFADDR fails */
-       while (ioctl(fd, SIOCDIFADDR, (void *)&areq) != -1) ;
-
-       close(fd);
-       return 0;
-#endif
-
-err_close:
-       close((*tun)->fd);
-err_free:
-       free(*tun);
-       *tun = NULL;
+err_netdev_free:
+       osmo_netdev_free(t->netdev);
+err_kernel_create:
+       gtp_kernel_stop(t->devname);
        return -1;
+       }
 }

 int tun_free(struct tun_t *tun)
@@ -279,17 +240,23 @@
                netdev_delroute4(&tun->dstaddr.v4, &tun->addr.v4, 
&tun->netmask);
        }

-       if (tun->fd >= 0) {
-               if (close(tun->fd)) {
+       if (tun->tundev) {
+               if (osmo_tundev_close(tun->tundev) < 0) {
                        SYS_ERR(DTUN, LOGL_ERROR, errno, "close() failed");
                }
+               osmo_tundev_free(tun->tundev);
+               tun->tundev = NULL;
+               /* netdev is owned by tundev: */
+               tun->netdev = NULL;
+       } else {
+               /* netdev was allocated directly, free it: */
+               osmo_netdev_free(tun->netdev);
+               tun->netdev = NULL;
        }

        gtp_kernel_stop(tun->devname);

-       /* TODO: For solaris we need to unlink streams */
-
-       free(tun);
+       talloc_free(tun);
        return 0;
 }

@@ -300,30 +267,16 @@
        return 0;
 }

-int tun_decaps(struct tun_t *this)
-{
-       unsigned char buffer[PACKET_MAX];
-       int status;
-
-       if ((status = read(this->fd, buffer, sizeof(buffer))) <= 0) {
-               SYS_ERR(DTUN, LOGL_ERROR, errno, "read() failed");
-               return -1;
-       }
-
-       if (this->cb_ind)
-               return this->cb_ind(this, buffer, status);
-
-       return 0;
-}
-
 int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
 {
+       struct msgb *msg = msgb_alloc(PACKET_MAX, "tun_tx");
        int rc;
-       rc = write(tun->fd, pack, len);
+
+       OSMO_ASSERT(msg);
+       memcpy(msgb_put(msg, len), pack, len);
+       rc = osmo_tundev_send(tun->tundev, msg);
        if (rc < 0) {
                SYS_ERR(DTUN, LOGL_ERROR, errno, "TUN(%s): write() failed", 
tun->devname);
-       } else if (rc < len) {
-               LOGTUN(LOGL_ERROR, tun, "short write() %d < %u\n", rc, len);
        }
        return rc;
 }
diff --git a/lib/tun.h b/lib/tun.h
index 36a4f7e..8a3a2d4 100644
--- a/lib/tun.h
+++ b/lib/tun.h
@@ -16,6 +16,9 @@
 #include <stdbool.h>
 #include <net/if.h>

+#include <osmocom/core/netdev.h>
+#include <osmocom/core/tun.h>
+
 #include "../lib/in46_addr.h"

 #define PACKET_MAX      8196   /* Maximum packet size we receive */
@@ -30,6 +33,8 @@
  *************************************************************/

 struct tun_t {
+       struct osmo_tundev *tundev;
+       struct osmo_netdev *netdev;
        int fd;                 /* File descriptor to tun interface */
        struct in46_addr addr;
        struct in46_addr dstaddr;
diff --git a/sgsnemu/sgsnemu.c b/sgsnemu/sgsnemu.c
index 152b05b..d6d87b7 100644
--- a/sgsnemu/sgsnemu.c
+++ b/sgsnemu/sgsnemu.c
@@ -23,6 +23,7 @@

 #include <osmocom/core/application.h>
 #include <osmocom/core/msgb.h>
+#include <osmocom/core/select.h>

 #include <ctype.h>
 #include <netdb.h>
@@ -2186,9 +2187,8 @@

                if (!signal_received) {

-                       if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) 
< 0) {
-                               SYS_ERR(DSGSN, LOGL_ERROR, 0,
-                                       "TUN decaps failed");
+                       if ((tun) && FD_ISSET(tun->fd, &fds)) {
+                               osmo_select_main(1);
                        }

                        if (FD_ISSET(gsn->fd0, &fds))

--
To view, visit https://gerrit.osmocom.org/c/osmo-ggsn/+/38480?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings?usp=email

Gerrit-MessageType: newchange
Gerrit-Project: osmo-ggsn
Gerrit-Branch: master
Gerrit-Change-Id: I4d99ba147ac0f3b414d2efef0068b6b8d6cf0014
Gerrit-Change-Number: 38480
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <[email protected]>

Reply via email to