neels has uploaded this change for review. (
https://gerrit.osmocom.org/c/osmo-upf/+/28986
)
Change subject: GTP mockup: allow single GTP devices in mockup mode
......................................................................
GTP mockup: allow single GTP devices in mockup mode
Drop the global GTP mockup mode, and instead allow single GTP devices to
be mockup devices.
Do not always open the mnl_socket, but only open it when an actual
non-mockup GTP device is being opened. (In the presence of non-mockup
GTP devices, this still happens directly upon program startup.)
The GTP mockup was first introduced for VTY tests during 'make check'.
So far, in mockup mode, all GTP tunnel actions were simply cut short,
and no tunnels were ever listed as active.
TTCN3 tests do query osmo-upf to list currently active tunnels, so the
GTP mockup fails these tests. To allow running TTCN3 tests without
cap_net_admin privileges, instead of a global GTP mockup mode, allow
creating single GTP device(s) in mockup mode, which then also list their
(fake) active GTP tunnels.
Also useful in a lab environment: send PFCP commands to osmo-upf and get
a listing of GTP tunnels that would have been active.
So far, osmo-upf always uses only the first GTP device configured, but
if we add support for multiple GTP devices, this patch allows putting
only single devices in mockup mode.
Related: SYS#5599
Change-Id: Ic09a5ccea24086eb04f46e6af669668e5fade752
---
M doc/examples/osmo-upf/osmo-upf-mockup.cfg
M include/osmocom/upf/upf.h
M include/osmocom/upf/upf_gtp.h
M src/osmo-upf/osmo_upf_main.c
M src/osmo-upf/up_gtp_action.c
M src/osmo-upf/upf.c
M src/osmo-upf/upf_gtp.c
M src/osmo-upf/upf_vty.c
8 files changed, 80 insertions(+), 66 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-upf refs/changes/86/28986/1
diff --git a/doc/examples/osmo-upf/osmo-upf-mockup.cfg
b/doc/examples/osmo-upf/osmo-upf-mockup.cfg
index e943a57..9608ef0 100644
--- a/doc/examples/osmo-upf/osmo-upf-mockup.cfg
+++ b/doc/examples/osmo-upf/osmo-upf-mockup.cfg
@@ -14,6 +14,6 @@
pfcp
local-addr 127.0.0.1
gtp
- mockup
+ dev mockup test_apn
nft
mockup
diff --git a/include/osmocom/upf/upf.h b/include/osmocom/upf/upf.h
index 1f8355d..b2f80d3 100644
--- a/include/osmocom/upf/upf.h
+++ b/include/osmocom/upf/upf.h
@@ -29,6 +29,8 @@
#include <osmocom/core/select.h>
#include <osmocom/core/linuxlist.h>
+#include <osmocom/upf/upf_gtp.h>
+
struct osmo_tdef;
struct ctrl_handle;
@@ -47,9 +49,7 @@
struct gtp_vty_cfg_dev {
struct llist_head entry;
- /* If true, osmo-upf creates the GTP device on startup. If false, the GTP device was
created by the user, and we
- * just plug into it. */
- bool create;
+ enum upf_gtp_dev_kind kind;
/* GTP device name as shown by 'ip link', e.g. 'apn0' */
char *dev_name;
@@ -76,9 +76,6 @@
/* Tunnel encaps decaps via GTP kernel module */
struct {
- /* if true, don't actually send commands to the GTP kernel module, just return
success. */
- bool mockup;
-
/* GTP devices as in osmo-upf.cfg */
struct gtp_vty_cfg vty_cfg;
diff --git a/include/osmocom/upf/upf_gtp.h b/include/osmocom/upf/upf_gtp.h
index a67c850..74d5ab1 100644
--- a/include/osmocom/upf/upf_gtp.h
+++ b/include/osmocom/upf/upf_gtp.h
@@ -36,12 +36,21 @@
#define PORT_GTP1_C 2123
#define PORT_GTP1_U 2152
+enum upf_gtp_dev_kind {
+ /* "use an existing GTP device" -- the kernel GTP device was created by the
user, and we just plug into it. */
+ UPF_GTP_DEV_USE = 0,
+ /* "create this GTP device" -- osmo-upf creates the kernel GTP device on
startup, and deletes it on shutdown. */
+ UPF_GTP_DEV_CREATE,
+ /* "test osmo-upf without requiring cap_net_admin privileges" -- act as if
using a GTP device, but no kernel
+ * device is actually opened, no commands will be sent out, all actions will simply noop
and return success, and
+ * GTP tunnels appear as if active but do not actually exist. */
+ UPF_GTP_DEV_MOCKUP,
+};
+
struct upf_gtp_dev {
struct llist_head entry;
- /* If true, osmo-upf created this GTP device on startup and will destroy it on program
exit. If false, the user
- * has created the device and osmo-upf will not destroy it. */
- bool created;
+ enum upf_gtp_dev_kind kind;
char *name;
struct {
@@ -69,10 +78,10 @@
int upf_gtp_tun_desc_cmp(const struct upf_gtp_tun_desc *a, const struct upf_gtp_tun_desc
*b);
-int upf_gtp_genl_open();
+int upf_gtp_genl_ensure_open();
void upf_gtp_genl_close();
-int upf_gtp_dev_open(const char *name, bool create_gtp_dev, const char *local_addr, bool
listen_for_gtpv0,
+int upf_gtp_dev_open(const char *name, enum upf_gtp_dev_kind kind, const char
*local_addr, bool listen_for_gtpv0,
bool sgsn_mode);
struct upf_gtp_dev *upf_gtp_dev_find_by_name(const char *name);
struct upf_gtp_dev *upf_gtp_dev_first();
diff --git a/src/osmo-upf/osmo_upf_main.c b/src/osmo-upf/osmo_upf_main.c
index b4888af..65a0e84 100644
--- a/src/osmo-upf/osmo_upf_main.c
+++ b/src/osmo-upf/osmo_upf_main.c
@@ -331,9 +331,6 @@
}
}
- if (upf_gtp_genl_open())
- return -1;
-
if (upf_gtp_devs_open())
return -1;
diff --git a/src/osmo-upf/up_gtp_action.c b/src/osmo-upf/up_gtp_action.c
index 9b8d528..da0c00c 100644
--- a/src/osmo-upf/up_gtp_action.c
+++ b/src/osmo-upf/up_gtp_action.c
@@ -83,12 +83,6 @@
switch (a->kind) {
case UP_GTP_U_ENDECAPS:
- if (g_upf->gtp.mockup) {
- LOG_UP_GTP_ACTION(a, LOGL_NOTICE, "gtp/mockup active, skipping GTP action
%s\n",
- enable ? "enable" : "disable");
- return 0;
- }
-
/* use the first available GTP device.
* TODO: select by interface name?
*/
diff --git a/src/osmo-upf/upf.c b/src/osmo-upf/upf.c
index db699c7..d3a9880 100644
--- a/src/osmo-upf/upf.c
+++ b/src/osmo-upf/upf.c
@@ -91,7 +91,7 @@
struct gtp_vty_cfg_dev *d;
llist_for_each_entry(d, &c->devs, entry) {
- if (upf_gtp_dev_open(d->dev_name, d->create, d->local_addr, false, false))
+ if (upf_gtp_dev_open(d->dev_name, d->kind, d->local_addr, false, false))
return -1;
}
return 0;
diff --git a/src/osmo-upf/upf_gtp.c b/src/osmo-upf/upf_gtp.c
index 6280e45..d5a6447 100644
--- a/src/osmo-upf/upf_gtp.c
+++ b/src/osmo-upf/upf_gtp.c
@@ -46,6 +46,10 @@
uint16_t v0_port;
struct osmo_strbuf sb = { .buf = buf, .len = buflen };
OSMO_STRBUF_PRINTF(sb, "%s", dev->name ? : "null");
+ if (dev->kind == UPF_GTP_DEV_MOCKUP) {
+ OSMO_STRBUF_PRINTF(sb, " [mockup]");
+ return sb.chars_needed;
+ }
if (dev->name && dev->ifidx)
OSMO_STRBUF_PRINTF(sb, " [%u]", dev->ifidx);
if (dev->sgsn_mode)
@@ -98,7 +102,7 @@
/* Allocate state for one GTP device, add to g_upf->gtp.devs and return the created
device. If state for the device of
* that name already exists, do nothing and return NULL. */
-static struct upf_gtp_dev *upf_gtp_dev_alloc(const char *name, const char *local_addr)
+static struct upf_gtp_dev *upf_gtp_dev_alloc(const char *name, enum upf_gtp_dev_kind
kind, const char *local_addr)
{
struct upf_gtp_dev *dev = upf_gtp_dev_find_by_name(name);
struct osmo_sockaddr_str addr_conv;
@@ -109,6 +113,7 @@
}
dev = talloc(g_upf, struct upf_gtp_dev);
*dev = (struct upf_gtp_dev){
+ .kind = kind,
.name = talloc_strdup(dev, name),
.gtpv0.ofd.fd = -1,
.gtpv1.ofd.fd = -1,
@@ -158,7 +163,8 @@
return 0;
}
-int upf_gtp_dev_open(const char *name, bool create_gtp_dev, const char *local_addr, bool
listen_for_gtpv0, bool sgsn_mode)
+int upf_gtp_dev_open(const char *name, enum upf_gtp_dev_kind kind, const char
*local_addr, bool listen_for_gtpv0,
+ bool sgsn_mode)
{
const struct osmo_sockaddr any = {
.u.sin = {
@@ -172,17 +178,24 @@
int rc;
struct upf_gtp_dev *dev;
- if (g_upf->gtp.mockup) {
- LOGP(DGTP, LOGL_NOTICE, "gtp/mockup active: not opening GTP device
'%s'\n", name);
- return 0;
- }
-
- dev = upf_gtp_dev_alloc(name, local_addr);
+ dev = upf_gtp_dev_alloc(name, kind, local_addr);
if (!dev)
return -EIO;
dev->sgsn_mode = sgsn_mode;
+ if (kind == UPF_GTP_DEV_MOCKUP) {
+ LOG_GTP_DEV(dev, LOGL_NOTICE,
+ "Created mockup GTP device: not opening kernel GTP device. FOR TESTING
PURPOSES ONLY.\n");
+ return 0;
+ }
+
+ rc = upf_gtp_genl_ensure_open();
+ if (rc) {
+ LOG_GTP_DEV(dev, LOGL_ERROR, "Cannot set up GTP device, failed to open
mnl_socket\n");
+ return rc;
+ }
+
if (listen_for_gtpv0) {
rc = osmo_sock_init_osa_ofd(&dev->gtpv0.ofd, SOCK_DGRAM, 0,
&dev->gtpv0.local_addr, &any,
OSMO_SOCK_F_BIND);
@@ -206,7 +219,7 @@
}
LOG_GTP_DEV(dev, LOGL_DEBUG, "GTPv1 bound\n");
- if (create_gtp_dev) {
+ if (kind == UPF_GTP_DEV_CREATE) {
int gtp0_fd = listen_for_gtpv0 ? dev->gtpv0.ofd.fd : -1;
int gtp1_fd = dev->gtpv1.ofd.fd;
if (dev->sgsn_mode)
@@ -222,7 +235,6 @@
}
LOG_GTP_DEV(dev, LOGL_NOTICE, "created GTP device\n");
- dev->created = true;
}
rc = dev_resolve_ifidx(dev);
@@ -255,13 +267,8 @@
}
/* Open an MNL socket which allows to create and remove GTP devices (requires
CAP_NET_ADMIN). */
-int upf_gtp_genl_open()
+int upf_gtp_genl_ensure_open()
{
- if (g_upf->gtp.mockup) {
- LOGP(DGTP, LOGL_NOTICE, "gtp/mockup active: not opening mnl_socket\n");
- return 0;
- }
-
/* Already open? */
if (g_upf->gtp.nl && g_upf->gtp.genl_id >= 0)
return 0;
@@ -362,6 +369,11 @@
if (tun->active)
return -EALREADY;
+ if (tun->dev->kind == UPF_GTP_DEV_MOCKUP) {
+ tun->active = true;
+ return 0;
+ }
+
t = upf_gtp_tun_to_gtp_tunnel(tun);
if (!t)
return -ENOTSUP;
@@ -428,6 +440,11 @@
return -EINVAL;
}
+ if (tun->dev->kind == UPF_GTP_DEV_MOCKUP) {
+ tun->active = false;
+ return 0;
+ }
+
t = upf_gtp_tun_to_gtp_tunnel(tun);
if (!t)
return -EINVAL;
@@ -452,7 +469,7 @@
/* osmo_fd_close() is a noop if ofd.fd == -1 */
osmo_fd_close(&dev->gtpv0.ofd);
osmo_fd_close(&dev->gtpv1.ofd);
- if (dev->created)
+ if (dev->kind == UPF_GTP_DEV_CREATE)
upf_gtp_dev_delete(dev);
return 0;
}
diff --git a/src/osmo-upf/upf_vty.c b/src/osmo-upf/upf_vty.c
index 386aa2f..8135d52 100644
--- a/src/osmo-upf/upf_vty.c
+++ b/src/osmo-upf/upf_vty.c
@@ -97,17 +97,21 @@
struct gtp_vty_cfg_dev *d;
vty_out(vty, "gtp%s", VTY_NEWLINE);
- if (g_upf->gtp.mockup)
- vty_out(vty, " mockup%s", VTY_NEWLINE);
-
llist_for_each_entry(d, >p_vty.devs, entry) {
- if (d->create) {
+ switch (d->kind) {
+ case UPF_GTP_DEV_USE:
+ vty_out(vty, " dev use %s%s", d->dev_name, VTY_NEWLINE);
+ break;
+ case UPF_GTP_DEV_CREATE:
vty_out(vty, " dev create %s", d->dev_name);
if (d->local_addr)
vty_out(vty, " %s", d->local_addr);
vty_out(vty, "%s", VTY_NEWLINE);
- } else {
- vty_out(vty, " dev use %s%s", d->dev_name, VTY_NEWLINE);
+ break;
+ default:
+ case UPF_GTP_DEV_MOCKUP:
+ vty_out(vty, " dev mockup %s%s", d->dev_name, VTY_NEWLINE);
+ break;
}
}
return CMD_SUCCESS;
@@ -115,23 +119,6 @@
#define DEV_STR "Configure the GTP device to use for encaps/decaps.\n"
-DEFUN(cfg_gtp_mockup, cfg_gtp_mockup_cmd,
- "mockup",
- "don't actually send commands to the GTP kernel module, just return
success\n")
-{
- g_upf->gtp.mockup = true;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_gtp_no_mockup, cfg_gtp_no_mockup_cmd,
- "no mockup",
- NO_STR
- "operate GTP kernel module normally\n")
-{
- g_upf->gtp.mockup = false;
- return CMD_SUCCESS;
-}
-
DEFUN(cfg_gtp_dev_create, cfg_gtp_dev_create_cmd,
"dev create DEVNAME [LISTEN_ADDR]",
DEV_STR
@@ -142,7 +129,7 @@
"IPv4 or IPv6 address to listen on, omit for ANY\n")
{
struct gtp_vty_cfg_dev *d = talloc_zero(g_upf, struct gtp_vty_cfg_dev);
- d->create = true;
+ d->kind = UPF_GTP_DEV_CREATE;
d->dev_name = talloc_strdup(d, argv[0]);
if (argc > 1)
d->local_addr = talloc_strdup(d, argv[1]);
@@ -158,13 +145,27 @@
"device name, e.g. 'apn0'\n")
{
struct gtp_vty_cfg_dev *d = talloc_zero(g_upf, struct gtp_vty_cfg_dev);
- d->create = false;
+ d->kind = UPF_GTP_DEV_USE;
d->dev_name = talloc_strdup(d, argv[0]);
llist_add(&d->entry, >p_vty.devs);
vty_out(vty, "Added GTP device %s (use existing)%s", d->dev_name,
VTY_NEWLINE);
return CMD_SUCCESS;
}
+DEFUN(cfg_gtp_dev_mockup, cfg_gtp_dev_mockup_cmd,
+ "dev mockup DEVNAME",
+ DEV_STR
+ "internally add a mockup GTP device that does not run actual kernel commands,
just returns success\n"
+ "device name, e.g. 'apn0'\n")
+{
+ struct gtp_vty_cfg_dev *d = talloc_zero(g_upf, struct gtp_vty_cfg_dev);
+ d->kind = UPF_GTP_DEV_MOCKUP;
+ d->dev_name = talloc_strdup(d, argv[0]);
+ llist_add(&d->entry, >p_vty.devs);
+ vty_out(vty, "Added GTP device %s (mockup)%s", d->dev_name, VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_gtp_dev_del, cfg_gtp_dev_del_cmd,
"dev delete DEVNAME",
DEV_STR
@@ -354,10 +355,9 @@
install_node(&cfg_gtp_node, config_write_gtp);
install_element(CONFIG_NODE, &cfg_gtp_cmd);
- install_element(GTP_NODE, &cfg_gtp_mockup_cmd);
- install_element(GTP_NODE, &cfg_gtp_no_mockup_cmd);
install_element(GTP_NODE, &cfg_gtp_dev_create_cmd);
install_element(GTP_NODE, &cfg_gtp_dev_use_cmd);
+ install_element(GTP_NODE, &cfg_gtp_dev_mockup_cmd);
install_element(GTP_NODE, &cfg_gtp_dev_del_cmd);
install_node(&cfg_nft_node, config_write_nft);
--
To view, visit
https://gerrit.osmocom.org/c/osmo-upf/+/28986
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-upf
Gerrit-Branch: master
Gerrit-Change-Id: Ic09a5ccea24086eb04f46e6af669668e5fade752
Gerrit-Change-Number: 28986
Gerrit-PatchSet: 1
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>
Gerrit-MessageType: newchange