neels has submitted this change. ( https://gerrit.osmocom.org/c/osmo-upf/+/30465 )
Change subject: clarify comments and naming around PDR+FAR classification
......................................................................
clarify comments and naming around PDR+FAR classification
No functional change.
Rename forw_to_core to access_to_core.
Rename forw_from_core to core_to_access.
Rename add_gtp_action_endecaps to add_gtp_action_tunend.
Rename add_gtp_action_forw to add_gtp_action_tunmap.
Add assertions to clearly indicate expected PDR and reverse PDR
directions.
Tweak various comments and log messages.
Fix some comments that have Access / Core flipped.
Change-Id: Ia199bb6944476eff6af89b5ab015a9a2f8ce330e
---
M include/osmocom/upf/up_session.h
M src/osmo-upf/up_session.c
2 files changed, 53 insertions(+), 46 deletions(-)
Approvals:
laforge: Looks good to me, approved
pespin: Looks good to me, but someone else must approve
Jenkins Builder: Verified
diff --git a/include/osmocom/upf/up_session.h b/include/osmocom/upf/up_session.h
index 10cc9ff..c459cd7 100644
--- a/include/osmocom/upf/up_session.h
+++ b/include/osmocom/upf/up_session.h
@@ -94,8 +94,8 @@
bool rx_decaps;
bool forw_encaps;
- bool forw_to_core;
- bool forw_from_core;
+ bool access_to_core;
+ bool core_to_access;
struct pdr *reverse_pdr;
bool active;
diff --git a/src/osmo-upf/up_session.c b/src/osmo-upf/up_session.c
index 7c59faa..76dc857 100644
--- a/src/osmo-upf/up_session.c
+++ b/src/osmo-upf/up_session.c
@@ -994,8 +994,8 @@
{
pdr->rx_decaps = false;
pdr->forw_encaps = false;
- pdr->forw_to_core = false;
- pdr->forw_from_core = false;
+ pdr->access_to_core = false;
+ pdr->core_to_access = false;
if (!pdr->far)
return;
@@ -1007,10 +1007,10 @@
if (!action_is_forw(&pdr->far->desc.apply_action))
return;
- pdr->forw_to_core = (pdr->desc.pdi.source_iface == OSMO_PFCP_SOURCE_IFACE_ACCESS
- && pdr->far->desc.forw_params.destination_iface == OSMO_PFCP_DEST_IFACE_CORE);
+ pdr->access_to_core = (pdr->desc.pdi.source_iface == OSMO_PFCP_SOURCE_IFACE_ACCESS
+ && pdr->far->desc.forw_params.destination_iface == OSMO_PFCP_DEST_IFACE_CORE);
- pdr->forw_from_core = (pdr->desc.pdi.source_iface == OSMO_PFCP_SOURCE_IFACE_CORE
+ pdr->core_to_access = (pdr->desc.pdi.source_iface == OSMO_PFCP_SOURCE_IFACE_CORE
&& pdr->far->desc.forw_params.destination_iface == OSMO_PFCP_DEST_IFACE_ACCESS);
}
@@ -1030,6 +1030,11 @@
pdr->reverse_pdr = NULL;
}
+/* Log that a PDR (and its reverse-PDR) is inactive.
+ * \param pdr The Access-to-Core PDR.
+ * \param desc Why it is inactive.
+ * \param pdr_to_str The PDR that desc describes, can be pdr or the reverse Core-to-Access PDR.
+ */
static void log_inactive_pdr_set(struct pdr *pdr, const char *desc, const struct pdr *pdr_to_str)
{
struct pdr *rpdr = pdr->reverse_pdr;
@@ -1055,7 +1060,7 @@
* Its reverse-PDR's FAR must have an outer-header creation with a remote TEID.
* \param pdr A rule detecting packets on Access, where pdr->reverse_pdr detects packets on Core.
*/
-static void add_gtp_action_endecaps(void *ctx, struct llist_head *dst, struct pdr *pdr)
+static void add_gtp_action_tunend(void *ctx, struct llist_head *dst, struct pdr *pdr)
{
struct up_session *session = pdr->session;
struct up_gtp_action *a;
@@ -1066,18 +1071,20 @@
OSMO_ASSERT(pdr->far);
OSMO_ASSERT(pdr->reverse_pdr);
OSMO_ASSERT(pdr->reverse_pdr->far);
-
- /* To decaps, we need to have a local TEID assigned for which to receive GTP packets. */
- if (!pdr->local_f_teid || pdr->local_f_teid->choose_flag) {
- log_inactive_pdr_set(pdr, "missing local TEID", pdr);
- return;
- }
-
- /* To encaps, we need to have a remote TEID assigned to send out in GTP packets, and we need to know where to
- * send GTP to. */
rpdr = pdr->reverse_pdr;
rfar = rpdr->far;
rfar_forw = &rfar->desc.forw_params;
+
+ OSMO_ASSERT(pdr->access_to_core);
+ OSMO_ASSERT(rpdr->core_to_access);
+
+ /* To decaps incoming on Access, we need to have a local F-TEID assigned for which to receive GTP packets. */
+ if (!pdr->local_f_teid || pdr->local_f_teid->choose_flag) {
+ log_inactive_pdr_set(pdr, "missing local F-TEID", pdr);
+ return;
+ }
+
+ /* To encaps outgoing on Access, we need to have a remote F-TEID assigned to send out in GTP packets */
if (!rfar->desc.forw_params_present) {
log_inactive_pdr_set(pdr, "missing FAR Forwarding Parameters", rpdr);
return;
@@ -1095,8 +1102,7 @@
return;
}
- /* To receive packets to be encapsulated, we need to know the assigned IP address for the UE, which receives the
- * IP packets that should be placed into GTP. */
+ /* To receive IP packets incoming on Core, we need to know the assigned IP address for the UE */
if (!rpdr->desc.pdi.ue_ip_address_present) {
log_inactive_pdr_set(pdr, "missing UE IP Address in PDI", rpdr);
return;
@@ -1149,7 +1155,7 @@
* Both FARs must have an outer-header creation with a remote F-TEID.
* \param pdr A rule detecting packets on Access, where pdr->reverse_pdr detects packets on Core.
*/
-static void add_gtp_action_forw(void *ctx, struct llist_head *dst, struct pdr *pdr)
+static void add_gtp_action_tunmap(void *ctx, struct llist_head *dst, struct pdr *pdr)
{
struct up_session *session = pdr->session;
struct up_gtp_action *a;
@@ -1169,52 +1175,53 @@
rfar = rpdr->far;
rfar_forw = &rfar->desc.forw_params;
- /* To decaps, we need to have a local TEID assigned for which to receive GTP packets. */
- /* decaps from CORE */
+ OSMO_ASSERT(pdr->access_to_core);
+ OSMO_ASSERT(rpdr->core_to_access);
+
+ /* To decaps incoming on Access, we need to have a local F-TEID assigned for which to receive GTP packets. */
if (!pdr->local_f_teid || pdr->local_f_teid->choose_flag) {
- log_inactive_pdr_set(pdr, "missing local TEID (CORE side)", pdr);
+ log_inactive_pdr_set(pdr, "missing local F-TEID (Access side)", pdr);
return;
}
- /* decaps from ACCESS */
+ /* To decaps incoming on Core, we need to have a local F-TEID assigned for which to receive GTP packets. */
if (!rpdr->local_f_teid || rpdr->local_f_teid->choose_flag) {
- log_inactive_pdr_set(pdr, "missing local TEID (ACCESS side)", pdr);
+ log_inactive_pdr_set(pdr, "missing local F-TEID (Core side)", pdr);
return;
}
- /* To encaps, we need to have a remote TEID assigned to send out in GTP packets, and we need to know where to
- * send GTP to. */
- /* encaps towards ACCESS */
+ /* To encaps outgoing on Core, we need to have a remote F-TEID assigned to send out in GTP packets */
if (!far->desc.forw_params_present) {
- log_inactive_pdr_set(pdr, "missing FAR Forwarding Parameters", pdr);
+ log_inactive_pdr_set(pdr, "missing FAR Forwarding Parameters (Access side)", pdr);
return;
}
if (!far_forw->outer_header_creation_present) {
- log_inactive_pdr_set(pdr, "missing FAR Outer Header Creation", pdr);
+ log_inactive_pdr_set(pdr, "missing FAR Outer Header Creation (Access side)", pdr);
return;
}
if (!far_forw->outer_header_creation.teid_present) {
- log_inactive_pdr_set(pdr, "missing TEID in FAR Outer Header Creation", pdr);
+ log_inactive_pdr_set(pdr, "missing TEID in FAR Outer Header Creation (Access side)", pdr);
return;
}
if (!far_forw->outer_header_creation.ip_addr.v4_present) {
- log_inactive_pdr_set(pdr, "missing IPv4 in FAR Outer Header Creation", pdr);
+ log_inactive_pdr_set(pdr, "missing IPv4 in FAR Outer Header Creation (Access side)", pdr);
return;
}
- /* encaps towards CORE */
+
+ /* To encaps outgoing on Access, we need to have a remote F-TEID assigned to send out in GTP packets */
if (!rfar->desc.forw_params_present) {
- log_inactive_pdr_set(pdr, "missing FAR Forwarding Parameters", rpdr);
+ log_inactive_pdr_set(pdr, "missing FAR Forwarding Parameters (Access side)", rpdr);
return;
}
if (!rfar_forw->outer_header_creation_present) {
- log_inactive_pdr_set(pdr, "missing FAR Outer Header Creation", rpdr);
+ log_inactive_pdr_set(pdr, "missing FAR Outer Header Creation (Access side)", rpdr);
return;
}
if (!rfar_forw->outer_header_creation.teid_present) {
- log_inactive_pdr_set(pdr, "missing TEID in FAR Outer Header Creation", rpdr);
+ log_inactive_pdr_set(pdr, "missing TEID in FAR Outer Header Creation (Access side)", rpdr);
return;
}
if (!rfar_forw->outer_header_creation.ip_addr.v4_present) {
- log_inactive_pdr_set(pdr, "missing IPv4 in FAR Outer Header Creation", rpdr);
+ log_inactive_pdr_set(pdr, "missing IPv4 in FAR Outer Header Creation (Access side)", rpdr);
return;
}
@@ -1278,13 +1285,13 @@
if (pdr->reverse_pdr)
continue;
- /* In this outer loop, only follow the forw_to_core directed PDRs, in the inner loop find the matching
- * forw_from_core PDR. i.e. we are looking only at PDRs detecting packets on the Access side, pairing up
+ /* In this outer loop, only follow the access_to_core directed PDRs, in the inner loop find the matching
+ * core_to_access PDR. i.e. we are looking only at PDRs detecting packets on the Access side, pairing up
* with "reverse PDRs" detecting packets on the Core side. */
- if (!pdr->forw_to_core)
+ if (!pdr->access_to_core)
continue;
- /* If a required TEID is not known, we cannot pair this PDR up */
+ /* If a required local addr + TEID is not known, we cannot pair this PDR up */
if (pdr->rx_decaps && !pdr->local_f_teid)
continue;
@@ -1295,7 +1302,7 @@
continue;
/* Looking for a PDR facing the other way */
- if (!other->forw_from_core)
+ if (!other->core_to_access)
continue;
/* GTP header-ness must match, in reverse. */
if (pdr->rx_decaps != other->forw_encaps
@@ -1318,14 +1325,14 @@
continue;
}
- /* Iterate in direction to-Core, where pdr->reverse_pdr will be the from-Core counterpart. */
- if (!pdr->forw_to_core)
+ /* Iterate in direction Access-to-Core, where pdr->reverse_pdr will be the Core-to-Access counterpart. */
+ if (!pdr->access_to_core)
continue;
if (pdr->rx_decaps && !pdr->forw_encaps)
- add_gtp_action_endecaps(ctx, dst, pdr);
+ add_gtp_action_tunend(ctx, dst, pdr);
else if (pdr->rx_decaps && pdr->forw_encaps)
- add_gtp_action_forw(ctx, dst, pdr);
+ add_gtp_action_tunmap(ctx, dst, pdr);
else {
/* log the details of both PDRs in two separate log lines */
log_inactive_pdr_set(pdr, "not implemented", pdr);
--
To view, visit https://gerrit.osmocom.org/c/osmo-upf/+/30465
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-upf
Gerrit-Branch: master
Gerrit-Change-Id: Ia199bb6944476eff6af89b5ab015a9a2f8ce330e
Gerrit-Change-Number: 30465
Gerrit-PatchSet: 3
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: neels <nhofmeyr(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: merged
neels has submitted this change. ( https://gerrit.osmocom.org/c/osmo-upf/+/30461 )
Change subject: tunmap: choose local GTP addr by Network Instance IEs
......................................................................
tunmap: choose local GTP addr by Network Instance IEs
Add 'netinst' config section to osmo-upf.cfg, to define Network Instance
name to local IP address mappings.
For the tunmap use case (forwarding GTP tunnels), heed the Network
Instance IEs in PFCP session creation and return IP addresses in F-TEIDs
accordingly.
Related: SYS#6192
Related: I37bebc7d6ef75c3e6ae05e81b83a1b5895839a64 (osmo-ttcn3-hacks)
Change-Id: I15ee046a1c37b83b8a83527a67a6215a30106d81
---
M include/osmocom/upf/Makefile.am
A include/osmocom/upf/netinst.h
M include/osmocom/upf/upf.h
M src/osmo-upf/Makefile.am
A src/osmo-upf/netinst.c
M src/osmo-upf/up_session.c
M src/osmo-upf/upf.c
M src/osmo-upf/upf_vty.c
A tests/netinst.vty
9 files changed, 411 insertions(+), 12 deletions(-)
Approvals:
laforge: Looks good to me, but someone else must approve
neels: Looks good to me, approved
arehbein: Looks good to me, but someone else must approve
Jenkins Builder: Verified
diff --git a/include/osmocom/upf/Makefile.am b/include/osmocom/upf/Makefile.am
index 127e03e..f418cb1 100644
--- a/include/osmocom/upf/Makefile.am
+++ b/include/osmocom/upf/Makefile.am
@@ -1,4 +1,5 @@
noinst_HEADERS = \
+ netinst.h \
up_endpoint.h \
up_peer.h \
up_session.h \
diff --git a/include/osmocom/upf/netinst.h b/include/osmocom/upf/netinst.h
new file mode 100644
index 0000000..fb659b6
--- /dev/null
+++ b/include/osmocom/upf/netinst.h
@@ -0,0 +1,44 @@
+/*
+ * (C) 2022 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
+ * All Rights Reserved.
+ *
+ * Author: Neels Janosch Hofmeyr <nhofmeyr(a)sysmocom.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/sockaddr_str.h>
+
+struct vty;
+
+struct network_instance {
+ struct llist_head entry;
+
+ char *name;
+ struct osmo_sockaddr_str addr;
+};
+
+const struct network_instance *netinst_add(void *ctx, struct llist_head *list, const char *name, const char *addr,
+ const char **errmsg);
+const struct network_instance *netinst_find(struct llist_head *list, const char *name);
+const struct network_instance *netinst_first(struct llist_head *list);
+int netinst_clear(struct llist_head *list);
+
+int netinst_vty_write(struct vty *vty, struct llist_head *list, const char *indent, const char *name_or_null);
diff --git a/include/osmocom/upf/upf.h b/include/osmocom/upf/upf.h
index 1597e2c..735a724 100644
--- a/include/osmocom/upf/upf.h
+++ b/include/osmocom/upf/upf.h
@@ -101,6 +101,8 @@
int priority;
uint32_t next_id_state;
} nft;
+
+ struct llist_head netinst;
};
extern struct g_upf *g_upf;
diff --git a/src/osmo-upf/Makefile.am b/src/osmo-upf/Makefile.am
index 1d43ee8..403fb06 100644
--- a/src/osmo-upf/Makefile.am
+++ b/src/osmo-upf/Makefile.am
@@ -30,6 +30,7 @@
$(NULL)
osmo_upf_SOURCES = \
+ netinst.c \
osmo_upf_main.c \
up_endpoint.c \
up_gtp_action.c \
diff --git a/src/osmo-upf/netinst.c b/src/osmo-upf/netinst.c
new file mode 100644
index 0000000..8cead8e
--- /dev/null
+++ b/src/osmo-upf/netinst.c
@@ -0,0 +1,124 @@
+/*
+ * (C) 2022 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
+ * All Rights Reserved.
+ *
+ * Author: Neels Janosch Hofmeyr <nhofmeyr(a)sysmocom.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <string.h>
+
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/vty/vty.h>
+
+#include <osmocom/upf/netinst.h>
+
+/* Add a new netinst entry to the given list.
+ * \param ctx talloc allocate new entry from ctx.
+ * \param list append to this list.
+ * \param name The Network Instance name as given in PFCP Network Instance IEs.
+ * \param addr IP address string of local interface to associate with the Network Instance.
+ * \param errmsg On error, an error description is returned in this out-argument.
+ * \return new network_instance entry, or NULL on error.
+ */
+const struct network_instance *netinst_add(void *ctx, struct llist_head *list, const char *name, const char *addr,
+ const char **errmsg)
+{
+ struct network_instance *netinst;
+ if (errmsg)
+ *errmsg = NULL;
+
+ if (!name || !*name) {
+ if (errmsg)
+ *errmsg = "Network Instance name must not be empty";
+ return NULL;
+ }
+
+ if (netinst_find(list, name)) {
+ if (errmsg)
+ *errmsg = "Network Instance entry with this name already exists";
+ return NULL;
+ }
+
+ netinst = talloc(ctx, struct network_instance);
+ *netinst = (struct network_instance){
+ .name = talloc_strdup(netinst, name),
+ };
+ if (osmo_sockaddr_str_from_str(&netinst->addr, addr, 0)) {
+ if (errmsg)
+ *errmsg = "Network Instance address is not a valid IP address string";
+ talloc_free(netinst);
+ return NULL;
+ }
+
+ llist_add_tail(&netinst->entry, list);
+
+ return netinst;
+}
+
+const struct network_instance *netinst_find(struct llist_head *list, const char *name)
+{
+ const struct network_instance *netinst;
+
+ if (!name)
+ return NULL;
+
+ llist_for_each_entry(netinst, list, entry)
+ if (!strcmp(netinst->name, name))
+ return netinst;
+
+ return NULL;
+}
+
+const struct network_instance *netinst_first(struct llist_head *list)
+{
+ return llist_first_entry_or_null(list, struct network_instance, entry);
+}
+
+/* Clear the list of Network Instance entries, return the nr of entries that were removed. */
+int netinst_clear(struct llist_head *list)
+{
+ int count = 0;
+ while (1) {
+ struct network_instance *netinst = llist_first_entry_or_null(list, struct network_instance, entry);
+ if (!netinst)
+ break;
+ llist_del(&netinst->entry);
+ talloc_free(netinst);
+ count++;
+ }
+ return count;
+}
+
+/* Write one or all netinst entries to the VTY output.
+ * If name_or_null is NULL, print all entries. Else, print only the entry matching that name.
+ * Return number of printed entries. */
+int netinst_vty_write(struct vty *vty, struct llist_head *list, const char *indent, const char *name_or_null)
+{
+ const struct network_instance *netinst;
+ int count = 0;
+
+ llist_for_each_entry(netinst, list, entry) {
+ if (name_or_null && strcmp(netinst->name, name_or_null))
+ continue;
+ vty_out(vty, "%sadd %s %s%s", indent, netinst->name, netinst->addr.ip, VTY_NEWLINE);
+ count++;
+ }
+ return count;
+}
diff --git a/src/osmo-upf/up_session.c b/src/osmo-upf/up_session.c
index 76dc857..36d20f2 100644
--- a/src/osmo-upf/up_session.c
+++ b/src/osmo-upf/up_session.c
@@ -34,6 +34,7 @@
#include <osmocom/upf/up_peer.h>
#include <osmocom/upf/up_session.h>
#include <osmocom/upf/up_gtp_action.h>
+#include <osmocom/upf/netinst.h>
static enum osmo_pfcp_cause up_session_setup_gtp(struct up_session *session);
@@ -114,12 +115,75 @@
return NULL;
}
+/* Find local interface's IP address by Network Instance name. Return 0 on success, or an OSMO_PFCP_CAUSE_* value on
+ * failure. */
+static int up_session_choose_local_ip(struct up_session *session, struct osmo_pfcp_ip_addrs *local_addr,
+ const char *netinst_name)
+{
+ const struct network_instance *netinst;
+ struct osmo_sockaddr osa = {};
+
+ if (llist_empty(&g_upf->netinst)) {
+ /* No network instances are configured in osmo-upf.cfg. Instead use the local address configured for
+ * PFCP, assuming that in a simplistic setup the host has only one interface. It is unlikely to be
+ * useful for a production environment where the entire point is to hand packet data from one interface
+ * to another, and where PFCP most probably happens on an entirely different interface, but may make
+ * things simpler for lab testing. */
+ if (osmo_pfcp_ip_addrs_set(local_addr,
+ osmo_pfcp_endpoint_get_local_addr(session->up_peer->up_endpoint->pfcp_ep))) {
+ LOGPFSML(session->fi, LOGL_ERROR, "Invalid local address in pfcp_endpoint cfg\n");
+ return OSMO_PFCP_CAUSE_SYSTEM_FAILURE;
+ }
+ LOGPFSML(session->fi, LOGL_NOTICE,
+ "Cannot look up Network Instance %s: No 'netinst' is configured, setting up GTP on same local"
+ " interface as PFCP: %s (makes sense only for lab testing)\n",
+ osmo_quote_str_c(OTC_SELECT, netinst_name, -1),
+ osmo_pfcp_ip_addrs_to_str_c(OTC_SELECT, local_addr));
+ return 0;
+ }
+
+ if (!netinst_name || !*netinst_name) {
+ /* Empty or no Network Instance IE in incoming PFCP request. Pick the first network instance; makes
+ * sense only in a simplistic lab setup where packet data is forwarded to the same interface that it is
+ * received on, and where no Network Instance is indicated by the CPF. Warn if more than one network
+ * instance is configured to choose from. */
+ if (llist_count(&g_upf->netinst) > 1)
+ LOGPFSML(session->fi, LOGL_NOTICE,
+ "Missing Network Instance in incoming request, using the first 'netinst' from cfg\n");
+ netinst = netinst_first(&g_upf->netinst);
+ /* there has to be a first entry, because we handled the empty list above. */
+ OSMO_ASSERT(netinst);
+ } else {
+ netinst = netinst_find(&g_upf->netinst, netinst_name);
+ if (!netinst) {
+ LOGPFSML(session->fi, LOGL_ERROR, "Network Instance from PFCP request not found: %s"
+ " -- ensure there is a 'netinst' / 'add %s <ip-addr>' entry in your config\n",
+ osmo_quote_str_c(OTC_SELECT, netinst_name, -1),
+ osmo_escape_str_c(OTC_SELECT, netinst_name, -1));
+ return OSMO_PFCP_CAUSE_RULE_CREATION_MOD_FAILURE;
+ }
+ }
+
+ /* Convert netinst IP address string first to osmo_sockaddr and then to osmo_pfcp_ip_addrs. */
+ if (osmo_sockaddr_str_to_sockaddr(&netinst->addr, &osa.u.sas)
+ || osmo_pfcp_ip_addrs_set(local_addr, &osa)) {
+ LOGPFSML(session->fi, LOGL_ERROR,
+ "Network Instance %s from PFCP request yields no valid IP address: "
+ OSMO_SOCKADDR_STR_FMT "\n",
+ osmo_quote_str_c(OTC_SELECT, netinst_name, -1),
+ OSMO_SOCKADDR_STR_FMT_ARGS(&netinst->addr));
+ return OSMO_PFCP_CAUSE_RULE_CREATION_MOD_FAILURE;
+ }
+ return 0;
+}
+
/* Choose an F-TEID (when the peer has sent CHOOSE = 1).
* If the peer also sent a CHOOSE_ID, then remember this F-TEID choice under the given ID, and re-use that choice when
* the same ID re-appears. The chosen IDs are saved in session->chosen_f_teids.
* Return 0 on success, or an OSMO_PFCP_CAUSE_* value on failure. */
static enum osmo_pfcp_cause up_session_choose_f_teid(struct up_session *session, struct osmo_pfcp_ie_f_teid *dst,
- bool choose_id_present, uint8_t choose_id)
+ bool choose_id_present, uint8_t choose_id,
+ const char *netinst_name)
{
struct up_endpoint *up_ep = session->up_peer->up_endpoint;
struct chosen_f_teid *chosen = NULL;
@@ -130,23 +194,26 @@
/* Re-use a previous F-TEID */
*dst = chosen->f_teid;
} else {
- /* Choose a new F-TEID */
+ int rc;
+
*dst = (struct osmo_pfcp_ie_f_teid){
- .fixed = {
- .teid = up_endpoint_next_teid(up_ep),
- },
+ .choose_flag = false,
};
+
+ /* Determine local IP address from Network Instance value received in PFCP request */
+ rc = up_session_choose_local_ip(session, &dst->fixed.ip_addr, netinst_name);
+ if (rc)
+ return rc;
+
+ /* Choose a new TEID */
+ dst->fixed.teid = up_endpoint_next_teid(up_ep);
if (dst->fixed.teid == 0) {
LOGPFSML(session->fi, LOGL_ERROR, "Failed to allocate an unused TEID\n");
return OSMO_PFCP_CAUSE_PFCP_ENTITY_IN_CONGESTION;
}
- LOGPFSML(session->fi, LOGL_INFO, "Allocated new local TEID 0x%x\n", dst->fixed.teid);
+ LOGPFSML(session->fi, LOGL_INFO, "Allocated new local F-TEID %s\n",
+ osmo_pfcp_ie_f_teid_to_str_c(OTC_SELECT, dst));
- if (osmo_pfcp_ip_addrs_set(&dst->fixed.ip_addr,
- osmo_pfcp_endpoint_get_local_addr(up_ep->pfcp_ep))) {
- LOGPFSML(session->fi, LOGL_ERROR, "Invalid local address in pfcp_endpoint cfg\n");
- return OSMO_PFCP_CAUSE_PFCP_ENTITY_IN_CONGESTION;
- }
/* Save this choice */
if (choose_id_present) {
chosen = talloc(session, struct chosen_f_teid);
@@ -270,6 +337,10 @@
OSMO_STRBUF_APPEND(sb, osmo_sockaddr_to_str_buf2, &pdr->desc.pdi.ue_ip_address.ip_addr.v6);
}
}
+ if (pdr->desc.pdi.network_inst_present) {
+ OSMO_STRBUF_PRINTF(sb, " netinst:");
+ OSMO_STRBUF_APPEND(sb, osmo_quote_str_buf3, pdr->desc.pdi.network_inst.str, -1);
+ }
if (pdr->local_f_teid) {
OSMO_STRBUF_PRINTF(sb, " ");
OSMO_STRBUF_APPEND(sb, osmo_pfcp_ie_f_teid_to_str_buf, pdr->local_f_teid);
@@ -370,9 +441,13 @@
if (pdr->desc.pdi.local_f_teid.choose_flag) {
/* CHOOSE = 1: we need to pick our own local F-TEID */
struct osmo_pfcp_ie_f_teid local_f_teid;
+ const char *netinst_name = NULL;
+ if (pdr->desc.pdi.network_inst_present)
+ netinst_name = pdr->desc.pdi.network_inst.str;
*cause = up_session_choose_f_teid(session, &local_f_teid,
pdr->desc.pdi.local_f_teid.choose.choose_id_present,
- pdr->desc.pdi.local_f_teid.choose.choose_id);
+ pdr->desc.pdi.local_f_teid.choose.choose_id,
+ netinst_name);
if (*cause != OSMO_PFCP_CAUSE_REQUEST_ACCEPTED) {
*offending_ie = OSMO_PFCP_IEI_F_TEID;
*offending_ie_present = true;
diff --git a/src/osmo-upf/upf.c b/src/osmo-upf/upf.c
index 3b8bfeb..0a84799 100644
--- a/src/osmo-upf/upf.c
+++ b/src/osmo-upf/upf.c
@@ -61,6 +61,7 @@
INIT_LLIST_HEAD(&g_upf->gtp.vty_cfg.devs);
INIT_LLIST_HEAD(&g_upf->gtp.devs);
+ INIT_LLIST_HEAD(&g_upf->netinst);
}
int upf_pfcp_listen()
diff --git a/src/osmo-upf/upf_vty.c b/src/osmo-upf/upf_vty.c
index 45f6dec..aff7590 100644
--- a/src/osmo-upf/upf_vty.c
+++ b/src/osmo-upf/upf_vty.c
@@ -37,11 +37,13 @@
#include <osmocom/upf/up_peer.h>
#include <osmocom/upf/up_session.h>
#include <osmocom/upf/up_gtp_action.h>
+#include <osmocom/upf/netinst.h>
enum upf_vty_node {
PFCP_NODE = _LAST_OSMOVTY_NODE + 1,
TUNEND_NODE,
TUNMAP_NODE,
+ NETINST_NODE,
};
static struct cmd_node cfg_pfcp_node = {
@@ -252,6 +254,67 @@
return CMD_SUCCESS;
}
+static struct cmd_node cfg_netinst_node = {
+ NETINST_NODE,
+ "%s(config-netinst)# ",
+ 1,
+};
+
+DEFUN(cfg_netinst, cfg_netinst_cmd,
+ "netinst",
+ "Enter the Network Instance configuration node\n")
+{
+ vty->node = NETINST_NODE;
+ return CMD_SUCCESS;
+}
+
+static int config_write_netinst(struct vty *vty)
+{
+ vty_out(vty, "netinst%s", VTY_NEWLINE);
+ netinst_vty_write(vty, &g_upf->netinst, " ", NULL);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_netinst_add, cfg_netinst_add_cmd,
+ "add NAME ADDR",
+ "add Network Instance: associate a PFCP Network Instance name with a local IP address\n"
+ "Network Instance name as received in PFCP Network Instance IE\n"
+ "IP address of a local interface\n")
+{
+ const char *errmsg;
+ if (!netinst_add(g_upf, &g_upf->netinst, argv[0], argv[1], &errmsg)) {
+ vty_out(vty, "%% Error: netinst: cannot add %s %s: %s%s", argv[0], argv[1],
+ errmsg ? : "(unknown error)", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN(show_netinst, show_netinst_cmd,
+ "show netinst [NAME]",
+ SHOW_STR "List configured Network Instance entries\n"
+ "Show the Network Instance with this name (show all when omitted)\n")
+{
+ const char *name_or_null = argc > 0 ? argv[0] : NULL;
+
+ if (!netinst_vty_write(vty, &g_upf->netinst, " ", name_or_null)) {
+ if (name_or_null)
+ vty_out(vty, "%% No such Network Instance entry%s", VTY_NEWLINE);
+ else
+ vty_out(vty, "%% No Network Instance entries configured%s", VTY_NEWLINE);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_netinst_clear, cfg_netinst_clear_cmd,
+ "clear",
+ "Remove all Network Instance entries\n")
+{
+ int count = netinst_clear(&g_upf->netinst);
+ vty_out(vty, "netinst entries removed: %d%s", count, VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
DEFUN(show_pdr, show_pdr_cmd,
"show pdr",
SHOW_STR
@@ -348,6 +411,7 @@
install_element_ve(&show_pdr_cmd);
install_element_ve(&show_gtp_cmd);
install_element_ve(&show_session_cmd);
+ install_element_ve(&show_netinst_cmd);
install_node(&cfg_pfcp_node, config_write_pfcp);
install_element(CONFIG_NODE, &cfg_pfcp_cmd);
@@ -371,4 +435,11 @@
install_element(TUNMAP_NODE, &cfg_tunmap_mockup_cmd);
install_element(TUNMAP_NODE, &cfg_tunmap_no_mockup_cmd);
install_element(TUNMAP_NODE, &cfg_tunmap_table_name_cmd);
+
+ install_node(&cfg_netinst_node, config_write_netinst);
+ install_element(CONFIG_NODE, &cfg_netinst_cmd);
+
+ install_element(NETINST_NODE, &cfg_netinst_clear_cmd);
+ install_element(NETINST_NODE, &cfg_netinst_add_cmd);
+ install_element(NETINST_NODE, &show_netinst_cmd);
}
diff --git a/tests/netinst.vty b/tests/netinst.vty
new file mode 100644
index 0000000..7b3c726
--- /dev/null
+++ b/tests/netinst.vty
@@ -0,0 +1,80 @@
+OsmoUPF> show ?
+...
+ netinst List configured Network Instance entries
+...
+OsmoUPF> show netinst?
+ netinst List configured Network Instance entries
+OsmoUPF> show netinst ?
+ [NAME] Show the Network Instance with this name (show all when omitted)
+
+OsmoUPF> show netinst
+% No Network Instance entries configured
+OsmoUPF> show netinst foo
+% No such Network Instance entry
+
+OsmoUPF> enable
+
+OsmoUPF# show netinst
+% No Network Instance entries configured
+
+OsmoUPF# configure terminal
+OsmoUPF(config)# netinst
+
+OsmoUPF(config-netinst)# list
+...
+ clear
+ add NAME ADDR
+ show netinst [NAME]
+
+OsmoUPF(config-netinst)# clear?
+ clear Remove all Network Instance entries
+OsmoUPF(config-netinst)# clear ?
+ <cr>
+
+OsmoUPF(config-netinst)# add?
+ add add Network Instance: associate a PFCP Network Instance name with a local IP address
+OsmoUPF(config-netinst)# add ?
+ NAME Network Instance name as received in PFCP Network Instance IE
+OsmoUPF(config-netinst)# add foo ?
+ ADDR IP address of a local interface
+
+OsmoUPF(config-netinst)# add foo bar
+% Error: netinst: cannot add foo bar: Network Instance address is not a valid IP address string
+OsmoUPF(config-netinst)# add foo 1.2.3.4
+OsmoUPF(config-netinst)# add foo 2.3.4.5
+% Error: netinst: cannot add foo 2.3.4.5: Network Instance entry with this name already exists
+OsmoUPF(config-netinst)# add bar 2.3.4.5
+OsmoUPF(config-netinst)# show netinst
+ add foo 1.2.3.4
+ add bar 2.3.4.5
+OsmoUPF(config-netinst)# add baz 1:2:3:4::0
+OsmoUPF(config-netinst)# show netinst
+ add foo 1.2.3.4
+ add bar 2.3.4.5
+ add baz 1:2:3:4::0
+OsmoUPF(config-netinst)# show netinst foo
+ add foo 1.2.3.4
+OsmoUPF(config-netinst)# show netinst bar
+ add bar 2.3.4.5
+OsmoUPF(config-netinst)# show netinst baz
+ add baz 1:2:3:4::0
+
+OsmoUPF(config-netinst)# show running-config
+...
+netinst
+ add foo 1.2.3.4
+ add bar 2.3.4.5
+ add baz 1:2:3:4::0
+...
+
+OsmoUPF(config-netinst)# clear
+netinst entries removed: 3
+OsmoUPF(config-netinst)# show netinst
+% No Network Instance entries configured
+OsmoUPF(config-netinst)# clear
+netinst entries removed: 0
+
+OsmoUPF(config-netinst)# show netinst?
+ netinst List configured Network Instance entries
+OsmoUPF(config-netinst)# show netinst ?
+ [NAME] Show the Network Instance with this name (show all when omitted)
--
To view, visit https://gerrit.osmocom.org/c/osmo-upf/+/30461
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-upf
Gerrit-Branch: master
Gerrit-Change-Id: I15ee046a1c37b83b8a83527a67a6215a30106d81
Gerrit-Change-Number: 30461
Gerrit-PatchSet: 3
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: arehbein <arehbein(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: neels <nhofmeyr(a)sysmocom.de>
Gerrit-MessageType: merged
neels has submitted this change. ( https://gerrit.osmocom.org/c/osmo-upf/+/30464 )
Change subject: fix PFCP Session Mod: Update FAR
......................................................................
fix PFCP Session Mod: Update FAR
Fix parsing of the Update FAR information so that a Session Modification
Request properly causes a GTP action to become active:
Add missing forw_params_present = true, and copy the information from
the incoming message instead of the current state.
Related: SYS#6192
Change-Id: I2a2c015d5615bb461b4d7b476a7c9830dc8e130f
---
M src/osmo-upf/up_session.c
1 file changed, 5 insertions(+), 4 deletions(-)
Approvals:
neels: Looks good to me, approved
pespin: Looks good to me, but someone else must approve
arehbein: Looks good to me, but someone else must approve
Jenkins Builder: Verified
diff --git a/src/osmo-upf/up_session.c b/src/osmo-upf/up_session.c
index b3b74f2..fe3d359 100644
--- a/src/osmo-upf/up_session.c
+++ b/src/osmo-upf/up_session.c
@@ -257,22 +257,23 @@
if (upd->upd_forw_params_present) {
const struct osmo_pfcp_ie_upd_forw_params *u = &upd->upd_forw_params;
struct osmo_pfcp_ie_forw_params *p = &far->desc.forw_params;
+ far->desc.forw_params_present = true;
if (u->destination_iface_present)
p->destination_iface = u->destination_iface;
if (u->network_inst_present) {
- p->network_inst = p->network_inst;
+ p->network_inst = u->network_inst;
p->network_inst_present = true;
}
if (u->outer_header_creation_present) {
- p->outer_header_creation = p->outer_header_creation;
+ p->outer_header_creation = u->outer_header_creation;
p->outer_header_creation_present = true;
}
if (u->linked_te_id_present) {
- p->linked_te_id = p->linked_te_id;
+ p->linked_te_id = u->linked_te_id;
p->linked_te_id_present = true;
}
if (u->destination_iface_type_present) {
- p->destination_iface_type = p->destination_iface_type;
+ p->destination_iface_type = u->destination_iface_type;
p->destination_iface_type_present = true;
}
}
1 is the latest approved patch-set.
No files were changed between the latest approved patch-set and the submitted one.
--
To view, visit https://gerrit.osmocom.org/c/osmo-upf/+/30464
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-upf
Gerrit-Branch: master
Gerrit-Change-Id: I2a2c015d5615bb461b4d7b476a7c9830dc8e130f
Gerrit-Change-Number: 30464
Gerrit-PatchSet: 3
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: arehbein <arehbein(a)sysmocom.de>
Gerrit-Reviewer: neels <nhofmeyr(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-CC: laforge <laforge(a)osmocom.org>
Gerrit-MessageType: merged
neels has submitted this change. ( https://gerrit.osmocom.org/c/osmo-upf/+/30524 )
Change subject: gtpu_echo: do not osmo_fd_register twice
......................................................................
gtpu_echo: do not osmo_fd_register twice
Change-Id: Ib498cc8d5252c05e12196f84bd1ea18d67e3052c
---
M src/osmo-upf/upf_gtpu_echo.c
1 file changed, 6 insertions(+), 1 deletion(-)
Approvals:
laforge: Looks good to me, approved
Jenkins Builder: Verified
diff --git a/src/osmo-upf/upf_gtpu_echo.c b/src/osmo-upf/upf_gtpu_echo.c
index f6dfe5c..60a8da8 100644
--- a/src/osmo-upf/upf_gtpu_echo.c
+++ b/src/osmo-upf/upf_gtpu_echo.c
@@ -155,7 +155,12 @@
return -EINVAL;
}
+ /* the caller should already have osmo_fd_register()ed when setting up the socket. */
+ OSMO_ASSERT(osmo_fd_is_registered(&dev->gtpv1.ofd));
+ /* make sure there is no cb yet that this would be replacing. */
+ OSMO_ASSERT(dev->gtpv1.ofd.cb == NULL);
+
dev->gtpv1.ofd.cb = upf_gtpu_echo_read_cb;
dev->gtpv1.ofd.data = dev;
- return osmo_fd_register(&dev->gtpv1.ofd);
+ return 0;
}
--
To view, visit https://gerrit.osmocom.org/c/osmo-upf/+/30524
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-upf
Gerrit-Branch: master
Gerrit-Change-Id: Ib498cc8d5252c05e12196f84bd1ea18d67e3052c
Gerrit-Change-Number: 30524
Gerrit-PatchSet: 2
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: neels <nhofmeyr(a)sysmocom.de>
Gerrit-MessageType: merged
Attention is currently required from: arehbein.
neels has posted comments on this change. ( https://gerrit.osmocom.org/c/osmo-upf/+/30461 )
Change subject: tunmap: choose local GTP addr by Network Instance IEs
......................................................................
Patch Set 2:
(1 comment)
File tests/netinst.vty:
https://gerrit.osmocom.org/c/osmo-upf/+/30461/comment/d53b05de_a908168e
PS2, Line 32: <cr>
> this trailing whitespace is returned from the telnet VTY, if we fix that the test will fail. […]
Done
--
To view, visit https://gerrit.osmocom.org/c/osmo-upf/+/30461
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-upf
Gerrit-Branch: master
Gerrit-Change-Id: I15ee046a1c37b83b8a83527a67a6215a30106d81
Gerrit-Change-Number: 30461
Gerrit-PatchSet: 2
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: arehbein <arehbein(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: neels <nhofmeyr(a)sysmocom.de>
Gerrit-Attention: arehbein <arehbein(a)sysmocom.de>
Gerrit-Comment-Date: Fri, 09 Dec 2022 17:23:19 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Comment-In-Reply-To: neels <nhofmeyr(a)sysmocom.de>
Comment-In-Reply-To: arehbein <arehbein(a)sysmocom.de>
Gerrit-MessageType: comment