tunend: choose local GTP addr by Network Instance IEs

Implement handling of the Network Instance IEs from PFCP for tunend,
like already done for tunmap.

In 'tunend' cfg, allow indicating a local GTP address for both 'dev
create' and 'dev use'. Select a GTP device by the local address the
Network Instance IE in PFCP PDR indicates.

Related: SYS#6192
Change-Id: I376c09bfc1844df1e61d2efac17561fac614858b
This commit is contained in:
Neels Hofmeyr 2022-12-09 03:18:33 +01:00
parent c4eb92d211
commit 2a2884fbbe
5 changed files with 64 additions and 27 deletions

View File

@ -83,6 +83,7 @@ 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,
bool sgsn_mode);
struct upf_gtp_dev *upf_gtp_dev_find_by_name(const char *name);
struct upf_gtp_dev *upf_gtp_dev_find_by_local_addr(const struct osmo_sockaddr *local_addr);
struct upf_gtp_dev *upf_gtp_dev_first();
int upf_gtp_dev_tunend_add(struct upf_gtp_dev *dev, const struct upf_gtp_tunend_desc *t);

View File

@ -79,6 +79,7 @@ int up_gtp_action_cmp(const struct up_gtp_action *a, const struct up_gtp_action
static int up_gtp_action_enable_disable(struct up_gtp_action *a, bool enable)
{
struct upf_gtp_dev *gtp_dev;
const struct osmo_sockaddr *gtp_addr;
int rc;
switch (a->kind) {
@ -89,12 +90,15 @@ static int up_gtp_action_enable_disable(struct up_gtp_action *a, bool enable)
return 0;
}
/* use the first available GTP device.
* TODO: select by interface name?
*/
gtp_dev = upf_gtp_dev_first();
/* Pick GTP device matching the local F-TEID set up for the GTP tunnel (it is on the Access side) */
gtp_addr = &a->tunend.access.gtp_local_addr;
gtp_dev = upf_gtp_dev_find_by_local_addr(gtp_addr);
if (!gtp_dev) {
LOG_UP_GTP_ACTION(a, LOGL_ERROR, "No GTP device open, cannot %s\n", enable ? "enable" : "disable");
LOG_UP_GTP_ACTION(a, LOGL_ERROR, "No GTP device open for local address %s, cannot %s"
" -- consider configuring 'tunend' / 'dev (create|use) foo %s'\n",
osmo_sockaddr_to_str_c(OTC_SELECT, gtp_addr),
enable ? "enable" : "disable",
osmo_sockaddr_to_str_c(OTC_SELECT, gtp_addr));
return -EIO;
}
@ -107,7 +111,8 @@ static int up_gtp_action_enable_disable(struct up_gtp_action *a, bool enable)
enable ? "enable" : "disable", rc, strerror(-rc));
return rc;
}
LOG_UP_GTP_ACTION(a, LOGL_NOTICE, "%s GTP tunnel\n", enable ? "Enabled" : "Disabled");
LOG_UP_GTP_ACTION(a, LOGL_NOTICE, "%s GTP tunnel on dev %s\n", enable ? "Enabled" : "Disabled",
gtp_dev->name);
return 0;
case UP_GTP_U_TUNMAP:

View File

@ -73,6 +73,26 @@ struct upf_gtp_dev *upf_gtp_dev_find_by_name(const char *name)
return NULL;
}
struct upf_gtp_dev *upf_gtp_dev_find_by_local_addr(const struct osmo_sockaddr *local_addr)
{
struct upf_gtp_dev *dev;
struct upf_gtp_dev *dev_any = NULL;
struct osmo_sockaddr needle = *local_addr;
llist_for_each_entry(dev, &g_upf->gtp.devs, entry) {
/* To leave the port number out of the cmp, set the needle's port to match */
osmo_sockaddr_set_port(&needle.u.sa, osmo_sockaddr_port(&dev->gtpv1.local_addr.u.sa));
if (!osmo_sockaddr_cmp(&needle, &dev->gtpv1.local_addr))
return dev;
if (osmo_sockaddr_is_any(&dev->gtpv1.local_addr) == 1)
dev_any = dev;
}
/* No 1:1 match found, but there is a dev listening on ANY? Return that.
* If there is no such dev, return NULL. */
return dev_any;
}
struct upf_gtp_dev *upf_gtp_dev_first()
{
return llist_first_entry_or_null(&g_upf->gtp.devs, struct upf_gtp_dev, entry);

View File

@ -137,37 +137,44 @@ DEFUN(cfg_tunend_no_mockup, cfg_tunend_no_mockup_cmd,
return CMD_SUCCESS;
}
static struct tunend_vty_cfg_dev *tunend_dev_add(int argc, const char **argv, bool create)
{
struct tunend_vty_cfg_dev *d = talloc_zero(g_upf, struct tunend_vty_cfg_dev);
d->create = create;
d->dev_name = talloc_strdup(d, argv[0]);
if (argc > 1)
d->local_addr = talloc_strdup(d, argv[1]);
llist_add(&d->entry, &tunend_vty.devs);
return d;
}
DEFUN(cfg_tunend_dev_create, cfg_tunend_dev_create_cmd,
"dev create DEVNAME [LISTEN_ADDR]",
DEV_STR
"Add GTP device, creating a new Linux kernel GTP device. Will listen on GTPv1 port "
OSMO_STRINGIFY_VAL(PORT_GTP1_U)
" and GTPv0 port " OSMO_STRINGIFY_VAL(PORT_GTP0_U) " on the specified interface, or on ANY if LISTEN_ADDR is"
" omitted.\n"
" and GTPv0 port " OSMO_STRINGIFY_VAL(PORT_GTP0_U) " on the specified LISTEN_ADDR\n"
"device name, e.g. 'apn0'\n"
"IPv4 or IPv6 address to listen on, omit for ANY\n")
"IPv4 or IPv6 address to listen on, omit for ANY. LISTEN_ADDR is used to pick a GTP device matching the local"
" address for a PFCP Network Instance, which are configured in the 'netinst' node.\n")
{
struct tunend_vty_cfg_dev *d = talloc_zero(g_upf, struct tunend_vty_cfg_dev);
d->create = true;
d->dev_name = talloc_strdup(d, argv[0]);
if (argc > 1)
d->local_addr = talloc_strdup(d, argv[1]);
llist_add(&d->entry, &tunend_vty.devs);
vty_out(vty, "Added GTP device %s (create new)%s", d->dev_name, VTY_NEWLINE);
struct tunend_vty_cfg_dev *d = tunend_dev_add(argc, argv, true);
vty_out(vty, "Added GTP device %s on %s (create new)%s", d->dev_name, d->local_addr ? : "0.0.0.0", VTY_NEWLINE);
return CMD_SUCCESS;
}
DEFUN(cfg_tunend_dev_use, cfg_tunend_dev_use_cmd,
"dev use DEVNAME",
"dev use DEVNAME [LOCAL_ADDR]",
DEV_STR
"Add GTP device, using an existing Linux kernel GTP device, e.g. created by 'gtp-link'\n"
"device name, e.g. 'apn0'\n")
"device name, e.g. 'apn0'\n"
"The local GTP address this device listens on. It is assumed to be ANY when omitted."
" LOCAL_ADDR is used to pick a GTP device matching the local address for a PFCP Network Instance,"
" which are configured in the 'netinst' node.\n")
{
struct tunend_vty_cfg_dev *d = talloc_zero(g_upf, struct tunend_vty_cfg_dev);
d->create = false;
d->dev_name = talloc_strdup(d, argv[0]);
llist_add(&d->entry, &tunend_vty.devs);
vty_out(vty, "Added GTP device %s (use existing)%s", d->dev_name, VTY_NEWLINE);
struct tunend_vty_cfg_dev *d = tunend_dev_add(argc, argv, false);
vty_out(vty, "Added GTP device %s on %s (use existing)%s", d->dev_name, d->local_addr ? : "0.0.0.0",
VTY_NEWLINE);
return CMD_SUCCESS;
}

View File

@ -20,7 +20,7 @@ OsmoUPF(config-tunend)# list
mockup
no mockup
dev create DEVNAME [LISTEN_ADDR]
dev use DEVNAME
dev use DEVNAME [LOCAL_ADDR]
dev delete DEVNAME
OsmoUPF(config-tunend)# exit
@ -28,19 +28,23 @@ OsmoUPF(config)# tunend
OsmoUPF(config-tunend)# list
...
dev create DEVNAME [LISTEN_ADDR]
dev use DEVNAME
dev use DEVNAME [LOCAL_ADDR]
dev delete DEVNAME
OsmoUPF(config-tunend)# dev?
dev Configure the GTP device to use for encaps/decaps.
OsmoUPF(config-tunend)# 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.
create Add GTP device, creating a new Linux kernel GTP device. Will listen on GTPv1 port 2152 and GTPv0 port 3386 on the specified LISTEN_ADDR
use Add GTP device, using an existing Linux kernel GTP device, e.g. created by 'gtp-link'
delete Remove a GTP device from the configuration, and delete the Linux kernel GTP device if it was created here.
OsmoUPF(config-tunend)# dev create ?
DEVNAME device name, e.g. 'apn0'
OsmoUPF(config-tunend)# dev create foo ?
[LISTEN_ADDR] IPv4 or IPv6 address to listen on, omit for ANY
[LISTEN_ADDR] IPv4 or IPv6 address to listen on, omit for ANY. LISTEN_ADDR is used to pick a GTP device matching the local address for a PFCP Network Instance, which are configured in the 'netinst' node.
OsmoUPF(config-tunend)# dev use ?
DEVNAME device name, e.g. 'apn0'
OsmoUPF(config-tunend)# dev use foo ?
[LOCAL_ADDR] The local GTP address this device listens on. It is assumed to be ANY when omitted. LOCAL_ADDR is used to pick a GTP device matching the local address for a PFCP Network Instance, which are configured in the 'netinst' node.
OsmoUPF(config-tunend)# dev delete ?
DEVNAME device name, e.g. 'apn0'
OsmoUPF(config-tunend)# exit