neels has submitted this change. ( https://gerrit.osmocom.org/c/osmo-upf/+/30831 )
Change subject: tunend: choose local GTP addr by Network Instance IEs ......................................................................
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 --- M include/osmocom/upf/upf_gtp.h M src/osmo-upf/up_gtp_action.c M src/osmo-upf/upf_gtp.c M src/osmo-upf/upf_vty.c M tests/upf.vty 5 files changed, 64 insertions(+), 27 deletions(-)
Approvals: Jenkins Builder: Verified fixeria: Looks good to me, but someone else must approve pespin: Looks good to me, approved
diff --git a/include/osmocom/upf/upf_gtp.h b/include/osmocom/upf/upf_gtp.h index 1a358ba..e3db918 100644 --- a/include/osmocom/upf/upf_gtp.h +++ b/include/osmocom/upf/upf_gtp.h @@ -83,6 +83,7 @@ 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); diff --git a/src/osmo-upf/up_gtp_action.c b/src/osmo-upf/up_gtp_action.c index 8ce8a6f..3b3da86 100644 --- a/src/osmo-upf/up_gtp_action.c +++ b/src/osmo-upf/up_gtp_action.c @@ -79,6 +79,7 @@ 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 @@ 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 @@ 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: diff --git a/src/osmo-upf/upf_gtp.c b/src/osmo-upf/upf_gtp.c index adac836..2c37bc4 100644 --- a/src/osmo-upf/upf_gtp.c +++ b/src/osmo-upf/upf_gtp.c @@ -73,6 +73,26 @@ 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); diff --git a/src/osmo-upf/upf_vty.c b/src/osmo-upf/upf_vty.c index 4c683c8..afea28d 100644 --- a/src/osmo-upf/upf_vty.c +++ b/src/osmo-upf/upf_vty.c @@ -137,37 +137,44 @@ 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; }
diff --git a/tests/upf.vty b/tests/upf.vty index 51ebeb3..bfaa0cc 100644 --- a/tests/upf.vty +++ b/tests/upf.vty @@ -20,7 +20,7 @@ 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)# 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