mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-upf.git
synced 2025-10-23 00:02:03 +00:00
Compare commits
2 Commits
7d2c272047
...
neels/gtp_
Author | SHA1 | Date | |
---|---|---|---|
|
3a43e59060 | ||
|
83e4e7a79e |
@@ -14,6 +14,6 @@ timer pfcp x24 5000
|
||||
pfcp
|
||||
local-addr 127.0.0.1
|
||||
gtp
|
||||
mockup
|
||||
dev mockup test_apn
|
||||
nft
|
||||
mockup
|
||||
|
@@ -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 pfcp_vty_cfg {
|
||||
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 @@ struct g_upf {
|
||||
|
||||
/* 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;
|
||||
|
||||
|
@@ -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 @@ struct upf_gtp_tun_desc {
|
||||
|
||||
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();
|
||||
|
@@ -331,9 +331,6 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (upf_gtp_genl_open())
|
||||
return -1;
|
||||
|
||||
if (upf_gtp_devs_open())
|
||||
return -1;
|
||||
|
||||
|
@@ -83,12 +83,6 @@ static int up_gtp_action_enable_disable(struct up_gtp_action *a, bool enable)
|
||||
|
||||
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?
|
||||
*/
|
||||
|
@@ -91,7 +91,7 @@ int upf_gtp_devs_open()
|
||||
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;
|
||||
|
@@ -46,6 +46,10 @@ int upf_gtp_dev_to_str_buf(char *buf, size_t buflen, const struct upf_gtp_dev *d
|
||||
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 @@ static int upf_gtp_dev_destruct(struct upf_gtp_dev *dev);
|
||||
|
||||
/* 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 @@ static struct upf_gtp_dev *upf_gtp_dev_alloc(const char *name, const char *local
|
||||
}
|
||||
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 @@ static int dev_resolve_ifidx(struct upf_gtp_dev *dev)
|
||||
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 upf_gtp_dev_open(const char *name, bool create_gtp_dev, const char *local_ad
|
||||
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 @@ int upf_gtp_dev_open(const char *name, bool create_gtp_dev, const char *local_ad
|
||||
}
|
||||
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 @@ int upf_gtp_dev_open(const char *name, bool create_gtp_dev, const char *local_ad
|
||||
}
|
||||
|
||||
LOG_GTP_DEV(dev, LOGL_NOTICE, "created GTP device\n");
|
||||
dev->created = true;
|
||||
}
|
||||
|
||||
rc = dev_resolve_ifidx(dev);
|
||||
@@ -255,13 +267,8 @@ void upf_gtp_genl_close()
|
||||
}
|
||||
|
||||
/* 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 @@ int upf_gtp_tun_activate(struct upf_gtp_tun *tun)
|
||||
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 @@ static int upf_gtp_tun_deactivate(struct upf_gtp_tun *tun)
|
||||
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 @@ static int upf_gtp_dev_destruct(struct upf_gtp_dev *dev)
|
||||
/* 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;
|
||||
}
|
||||
|
@@ -97,17 +97,21 @@ static int config_write_gtp(struct vty *vty)
|
||||
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 @@ static int config_write_gtp(struct vty *vty)
|
||||
|
||||
#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
|
||||
@@ -143,7 +130,7 @@ DEFUN(cfg_gtp_dev_create, cfg_gtp_dev_create_cmd,
|
||||
"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]);
|
||||
@@ -159,13 +146,27 @@ DEFUN(cfg_gtp_dev_use, cfg_gtp_dev_use_cmd,
|
||||
"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
|
||||
"Add GTP device, as an internal mockup that does not run actual Linux 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
|
||||
@@ -355,10 +356,9 @@ void upf_vty_init()
|
||||
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);
|
||||
|
@@ -18,6 +18,7 @@ OsmoUPF(config-gtp)# list
|
||||
...
|
||||
dev create DEVNAME [LISTEN_ADDR]
|
||||
dev use DEVNAME
|
||||
dev mockup DEVNAME
|
||||
dev delete DEVNAME
|
||||
|
||||
OsmoUPF(config-gtp)# dev?
|
||||
@@ -25,6 +26,7 @@ OsmoUPF(config-gtp)# dev?
|
||||
OsmoUPF(config-gtp)# dev ?
|
||||
create Add GTP device, creating a new Linux kernel GTP device. Will listen on GTPv1 port 2152 and GTPv0 port 3386 on the specified interface, or on ANY if LISTEN_ADDR is omitted.
|
||||
use Add GTP device, using an existing Linux kernel GTP device, e.g. created by 'gtp-link'
|
||||
mockup Add GTP device, as an internal mockup that does not run actual Linux kernel commands, just returns success
|
||||
delete Remove a GTP device from the configuration, and delete the Linux kernel GTP device if it was created here.
|
||||
OsmoUPF(config-gtp)# dev create ?
|
||||
DEVNAME device name, e.g. 'apn0'
|
||||
|
Reference in New Issue
Block a user