neels has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-upf/+/30466 )
Change subject: fix tunmap: mixup of Access/Core side FAR rules
......................................................................
fix tunmap: mixup of Access/Core side FAR rules
For tunmap, forward to the correct side: when collecting PDR and FAR on
one side, we need to take its PDR and the *reverse* FAR, instead of the
FAR paired with that PDR:
Access --PDR-1->|--FAR-1-> Core
<-FAR-2--|<-PDR-2--
Related: SYS#6192
Change-Id: I66babdfe4c1746bd3bf259342ce80dae2661de8c
---
M src/osmo-upf/up_session.c
1 file changed, 4 insertions(+), 4 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-upf refs/changes/66/30466/1
diff --git a/src/osmo-upf/up_session.c b/src/osmo-upf/up_session.c
index d2a405d..fe3d359 100644
--- a/src/osmo-upf/up_session.c
+++ b/src/osmo-upf/up_session.c
@@ -1324,13 +1324,13 @@
.tunmap = {
.access = {
.local_teid = pdr->local_f_teid->fixed.teid,
- .remote_teid = far_forw->outer_header_creation.teid,
- .gtp_remote_addr = far_forw->outer_header_creation.ip_addr.v4,
+ .remote_teid = rfar_forw->outer_header_creation.teid,
+ .gtp_remote_addr = rfar_forw->outer_header_creation.ip_addr.v4,
},
.core = {
.local_teid = rpdr->local_f_teid->fixed.teid,
- .remote_teid = rfar_forw->outer_header_creation.teid,
- .gtp_remote_addr = rfar_forw->outer_header_creation.ip_addr.v4,
+ .remote_teid = far_forw->outer_header_creation.teid,
+ .gtp_remote_addr = far_forw->outer_header_creation.ip_addr.v4,
},
},
};
--
To view, visit https://gerrit.osmocom.org/c/osmo-upf/+/30466
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-upf
Gerrit-Branch: master
Gerrit-Change-Id: I66babdfe4c1746bd3bf259342ce80dae2661de8c
Gerrit-Change-Number: 30466
Gerrit-PatchSet: 1
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>
Gerrit-MessageType: newchange
neels has uploaded this change for review. ( 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, 56 insertions(+), 50 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-upf refs/changes/65/30465/1
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 915dd75..d2a405d 100644
--- a/src/osmo-upf/up_session.c
+++ b/src/osmo-upf/up_session.c
@@ -1071,8 +1071,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;
@@ -1084,10 +1084,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);
}
@@ -1107,6 +1107,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;
@@ -1132,7 +1137,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;
@@ -1143,18 +1148,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;
@@ -1172,8 +1179,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;
@@ -1221,13 +1227,12 @@
llist_add_tail(&a->entry, dst);
}
-/* A GTP tunnel on Access side, TODO TODO TODO plain IP on Core side.
- * The given PDR must have an outer-header-removal and a local F-TEID.
- * Its reverse-PDR must have a UE address flagged as "Destination" IP addr.
- * Its reverse-PDR's FAR must have an outer-header creation with a remote TEID.
+/* A GTP tunnel on Access side, mapping to another GTP tunnel on Core side and vice versa.
+ * The PDR and its reverse PDR must both have an outer-header-removal and a local F-TEID.
+ * 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;
@@ -1247,52 +1252,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;
}
@@ -1356,13 +1362,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;
@@ -1373,7 +1379,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
@@ -1396,14 +1402,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: 1
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>
Gerrit-MessageType: newchange
neels has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-upf/+/30456 )
Change subject: VTY: show gtp: still list tunmap if no tunend device is open
......................................................................
VTY: show gtp: still list tunmap if no tunend device is open
When there was only tunend implemented, it made sense to show on VTY
when no GTP kernel device was open. Since we now also have tunmap via
netfilter, drop the early exit.
Change-Id: I9a43a240f2ca55cf2ca237a83aa13e68a625d6ea
---
M src/osmo-upf/upf_vty.c
1 file changed, 0 insertions(+), 5 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-upf refs/changes/56/30456/1
diff --git a/src/osmo-upf/upf_vty.c b/src/osmo-upf/upf_vty.c
index f57429c..45f6dec 100644
--- a/src/osmo-upf/upf_vty.c
+++ b/src/osmo-upf/upf_vty.c
@@ -294,11 +294,6 @@
struct up_peer *peer;
int count = 0;
- if (!upf_gtp_dev_first()) {
- vty_out(vty, "No GTP device open%s", VTY_NEWLINE);
- return CMD_SUCCESS;
- }
-
llist_for_each_entry(peer, &g_upf->pfcp.ep->peers, entry) {
struct up_session *session;
int bkt;
--
To view, visit https://gerrit.osmocom.org/c/osmo-upf/+/30456
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-upf
Gerrit-Branch: master
Gerrit-Change-Id: I9a43a240f2ca55cf2ca237a83aa13e68a625d6ea
Gerrit-Change-Number: 30456
Gerrit-PatchSet: 1
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>
Gerrit-MessageType: newchange
neels has uploaded this change for review. ( 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, 409 insertions(+), 12 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-upf refs/changes/61/30461/1
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..039fd5c
--- /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(ctx, 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 195bd13..e17b319 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,73 @@
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\n",
+ osmo_quote_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 +192,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 +335,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 +439,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: 1
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>
Gerrit-MessageType: newchange
fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmocom-bb/+/30454 )
Change subject: mobile: clean up GAPK I/O state on channel release
......................................................................
mobile: clean up GAPK I/O state on channel release
Do not assert() in gsm_recv_voice(), because channel release does
not happen immediately and the PHY may be still sending TCH frames.
Change-Id: I8943ee9bd46afc96e6d7cfd52c95c34fd311ce11
Related: OS#3400
---
M src/host/layer23/src/mobile/gsm48_rr.c
M src/host/layer23/src/mobile/voice.c
2 files changed, 8 insertions(+), 4 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/54/30454/1
diff --git a/src/host/layer23/src/mobile/gsm48_rr.c b/src/host/layer23/src/mobile/gsm48_rr.c
index 610242c..4ecbcff 100644
--- a/src/host/layer23/src/mobile/gsm48_rr.c
+++ b/src/host/layer23/src/mobile/gsm48_rr.c
@@ -397,6 +397,10 @@
memset(&rr->cd_now, 0, sizeof(rr->cd_now));
/* reset ciphering */
rr->cipher_on = 0;
+#ifdef WITH_GAPK_IO
+ /* clean-up GAPK state */
+ gapk_io_clean_up_ms(rr->ms);
+#endif
/* reset audio mode */
/* tell cell selection process to return to idle mode
* NOTE: this must be sent unbuffered, because it will
diff --git a/src/host/layer23/src/mobile/voice.c b/src/host/layer23/src/mobile/voice.c
index c3c6a6a..260e1d2 100644
--- a/src/host/layer23/src/mobile/voice.c
+++ b/src/host/layer23/src/mobile/voice.c
@@ -82,11 +82,11 @@
return gsm_forward_mncc(ms, msg);
case AUDIO_IOH_GAPK:
#ifdef WITH_GAPK_IO
- /* Prevent null pointer dereference */
- OSMO_ASSERT(ms->gapk_io != NULL);
-
/* Enqueue a frame to the DL TCH buffer */
- gapk_io_enqueue_dl(ms->gapk_io, msg);
+ if (ms->gapk_io != NULL)
+ gapk_io_enqueue_dl(ms->gapk_io, msg);
+ else
+ msgb_free(msg);
break;
#endif
case AUDIO_IOH_L1PHY:
--
To view, visit https://gerrit.osmocom.org/c/osmocom-bb/+/30454
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmocom-bb
Gerrit-Branch: master
Gerrit-Change-Id: I8943ee9bd46afc96e6d7cfd52c95c34fd311ce11
Gerrit-Change-Number: 30454
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-MessageType: newchange