pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-upf/+/41470?usp=email )
Change subject: Split up_peer into pfcp_{node,entity}_peer ......................................................................
Split up_peer into pfcp_{node,entity}_peer
Match our data domain with the specifications in 3GPP TS 29.244: """ CP function: A node with a Control Plane function (see 3GPP TS 23.214 [2]) supporting one or more PFCP entities. A Control Plane function, i.e. a Control Plane Node, is identified by the Node ID that is set to either an FQDN or an IP address.
UP function: A node with a User Plane function (see 3GPP TS 23.214 [2]) supporting one or more PFCP entities. A User Plane function, i.e. a User Plane Node, is identified by the Node ID that is set to either a FQDN or an IP address.
Node: Either a CP function or an UP function supporting one or more PFCP entities. A Node is identified by the Node ID, which is set to either an FQDN or an IP address.
PFCP Entity: An endpoint in a CP (or UP) function supporting PFCP, that is identified by the IP address. The IP address of a PFCP entity may or may not be the IP address included in the Node ID. """
In general, we have a "pfcp_node_peer 1-1 pfcp_entity_peer" relation, and this is what so far is implemented here. In the future we can improve code to support a "pfcp_node_peer 1-* pfcp_entity_peer" relation, which can actually be implemented in 2 different ways (2 different features) as explained in 3GPP TS 29.244 section 5.22.
Due to those 2 different features, it's actually difficult to figure out where to install the FSM with the association state (entity vs node). For now, leave it at the pfcp_entity_peer level, in order to simplify the implementation and make the changes in this patch easier to follow. Hence, pfcp_node_peer is so far only used to track Node-Id changes, and is released as soon as all its PFCP Entities are released.
Related: SYS#7719 Change-Id: Ie64be4fd55157e9646e250f8cbe93ba3f3c19b17 --- M include/osmocom/upf/Makefile.am A include/osmocom/upf/pfcp_entity_peer.h A include/osmocom/upf/pfcp_node_peer.h M include/osmocom/upf/up_endpoint.h D include/osmocom/upf/up_peer.h M include/osmocom/upf/up_session.h M src/osmo-upf/Makefile.am A src/osmo-upf/pfcp_entity_peer.c A src/osmo-upf/pfcp_node_peer.c M src/osmo-upf/up_endpoint.c M src/osmo-upf/up_gtp_action.c D src/osmo-upf/up_peer.c M src/osmo-upf/up_session.c M src/osmo-upf/upf.c M src/osmo-upf/upf_vty.c M tests/unique_ids/unique_ids_test.c M tests/unique_ids/unique_ids_test.err 17 files changed, 1,152 insertions(+), 850 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-upf refs/changes/70/41470/1
diff --git a/include/osmocom/upf/Makefile.am b/include/osmocom/upf/Makefile.am index e8eda55..9350ee8 100644 --- a/include/osmocom/upf/Makefile.am +++ b/include/osmocom/upf/Makefile.am @@ -1,7 +1,8 @@ noinst_HEADERS = \ + pfcp_entity_peer.h \ + pfcp_node_peer.h \ netinst.h \ up_endpoint.h \ - up_peer.h \ up_session.h \ upf.h \ upf_gtp.h \ diff --git a/include/osmocom/upf/pfcp_entity_peer.h b/include/osmocom/upf/pfcp_entity_peer.h new file mode 100644 index 0000000..d2727e5 --- /dev/null +++ b/include/osmocom/upf/pfcp_entity_peer.h @@ -0,0 +1,82 @@ +/* 3GPP TS 29.244 PFCP Entity + * (C) 2021-2025 by sysmocom - s.f.m.c. GmbH info@sysmocom.de + * All Rights Reserved. + * + * Author: Neels Janosch Hofmeyr nhofmeyr@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 <stdint.h> + +#include <osmocom/core/linuxlist.h> +#include <osmocom/core/hashtable.h> +#include <osmocom/core/socket.h> +#include <osmocom/core/use_count.h> + +#include <osmocom/pfcp/pfcp_msg.h> + +enum pfcp_entity_peer_event { + PFCP_ENTITY_PEER_EV_RX_ASSOC_SETUP_REQ, + PFCP_ENTITY_PEER_EV_RX_ASSOC_UPD_REQ, + PFCP_ENTITY_PEER_EV_RX_ASSOC_REL_REQ, + PFCP_ENTITY_PEER_EV_RX_SESSION_EST_REQ, + PFCP_ENTITY_PEER_EV_HEARTBEAT_FAILURE, + PFCP_ENTITY_PEER_EV_USE_COUNT_ZERO, + PFCP_ENTITY_PEER_EV_SESSION_TERM, +}; + +struct pfcp_entity_peer { + /* item in pfcp_node_peer->entity_list */ + struct llist_head entry; + + struct osmo_fsm_inst *fi; + /* backpointer */ + struct pfcp_node_peer *node_peer; + + /* peer's remote address */ + struct osmo_sockaddr remote_addr; + uint32_t remote_recovery_timestamp; + + uint32_t next_seq_nr; + + struct osmo_fsm_inst *heartbeat_fi; + + struct osmo_use_count use_count; + struct osmo_use_count_entry use_count_buf[5]; + + DECLARE_HASHTABLE(sessions_by_up_seid, 10); + DECLARE_HASHTABLE(sessions_by_cp_seid, 10); +}; + +struct pfcp_entity_peer *pfcp_entity_peer_alloc(struct pfcp_node_peer *node_peer, const struct osmo_sockaddr *remote_addr); +void pfcp_entity_peer_free(struct pfcp_entity_peer *peer); + +void pfcp_entity_peer_set_msg_ctx(struct pfcp_entity_peer *entity_peer, struct osmo_pfcp_msg *m); +void pfcp_entity_peer_remove_msg_ctx(struct pfcp_entity_peer *peer, struct osmo_pfcp_msg *m); + +char *pfcp_entity_peer_remote_addr_str(struct pfcp_entity_peer *entity_peer); + +struct osmo_pfcp_msg *pfcp_entity_peer_init_tx(struct pfcp_entity_peer *entity_peer, + struct osmo_pfcp_msg *in_reply_to, + enum osmo_pfcp_message_type message_type); + +struct up_session *pfcp_entity_peer_find_up_session_by_up_seid(struct pfcp_entity_peer *entity_peer, uint64_t up_seid); +struct up_session *pfcp_entity_peer_find_up_session_by_cp_f_seid(struct pfcp_entity_peer *entity_peer, const struct osmo_pfcp_ie_f_seid *cp_f_seid); + diff --git a/include/osmocom/upf/pfcp_node_peer.h b/include/osmocom/upf/pfcp_node_peer.h new file mode 100644 index 0000000..a28eea9 --- /dev/null +++ b/include/osmocom/upf/pfcp_node_peer.h @@ -0,0 +1,64 @@ +/* 3GPP TS 29.244 PFCP Node + * (C) 2021-2025 by sysmocom - s.f.m.c. GmbH info@sysmocom.de + * All Rights Reserved. + * + * Author: Neels Janosch Hofmeyr nhofmeyr@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/hashtable.h> +#include <osmocom/core/socket.h> +#include <osmocom/core/use_count.h> + +#include <osmocom/pfcp/pfcp_msg.h> + +struct pfcp_node_peer { + /* item in up_endpoint->pfcp_node_peer_list */ + struct llist_head entry; + + /* list of struct pfcp_entity_peer. */ + struct llist_head entity_list; + + struct osmo_fsm_inst *fi; + /* backpointer */ + struct up_endpoint *up_endpoint; + + /* peer's remote address */ + struct osmo_pfcp_ie_node_id node_id; + + struct osmo_pfcp_ie_up_function_features local_up_features; + struct osmo_pfcp_ie_cp_function_features peer_cp_features; + + struct osmo_use_count use_count; + struct osmo_use_count_entry use_count_buf[5]; +}; + +struct pfcp_node_peer *pfcp_node_peer_alloc(struct up_endpoint *up_endpoint, const struct osmo_pfcp_ie_node_id *node_id); +void pfcp_node_peer_free(struct pfcp_node_peer *peer); + +struct pfcp_entity_peer *pfcp_node_peer_find_entity_by_remote_addr(struct pfcp_node_peer *peer, const struct osmo_sockaddr *remote_addr); +char *pfcp_node_peer_node_id_str(struct pfcp_node_peer *node_peer); + +#define pfcp_node_peer_get(PFCP_NODE_PEER, USE) OSMO_ASSERT(osmo_use_count_get_put(&(PFCP_NODE_PEER)->use_count, USE, 1) == 0) +#define pfcp_node_peer_put(PFCP_NODE_PEER, USE) OSMO_ASSERT(osmo_use_count_get_put(&(PFCP_NODE_PEER)->use_count, USE, -1) == 0) + +#define LOG_PNP(PFCP_NODE_PEER, LEVEL, FMT, ARGS...) \ + LOGP(DGTP, LEVEL, "pfcp_node_peer(%s): " FMT, pfcp_node_peer_node_id_str(PFCP_NODE_PEER), ##ARGS) diff --git a/include/osmocom/upf/up_endpoint.h b/include/osmocom/upf/up_endpoint.h index 2aed25a..03fd23d 100644 --- a/include/osmocom/upf/up_endpoint.h +++ b/include/osmocom/upf/up_endpoint.h @@ -1,5 +1,5 @@ /* - * (C) 2021-2022 by sysmocom - s.f.m.c. GmbH info@sysmocom.de + * (C) 2021-2025 by sysmocom - s.f.m.c. GmbH info@sysmocom.de * All Rights Reserved. * * Author: Neels Janosch Hofmeyr nhofmeyr@sysmocom.de @@ -30,14 +30,16 @@ struct osmo_pfcp_endpoint; struct osmo_sockaddr;
+struct pfcp_node_peer; + #define UP_USE_MSG_RX "msg-rx" #define UP_USE_MSG_TX "msg-tx"
struct up_endpoint { struct osmo_pfcp_endpoint *pfcp_ep;
- /* list of struct up_peer. */ - struct llist_head peers; + /* list of struct pfcp_node_peer. */ + struct llist_head pfcp_node_peer_list; /* hashtable of (struct up_session) with key up_seid. * Allows quick access to sessions (and its endpoint as backpointer) * with a given up_seid. */ @@ -50,4 +52,6 @@ int up_endpoint_bind(struct up_endpoint *up_ep); void up_endpoint_free(struct up_endpoint **ep);
+struct pfcp_node_peer *up_endpoint_find_pfcp_node_peer(const struct up_endpoint *up_ep, + const struct osmo_pfcp_ie_node_id *node_id); uint64_t up_endpoint_next_up_seid(struct up_endpoint *ep); diff --git a/include/osmocom/upf/up_peer.h b/include/osmocom/upf/up_peer.h deleted file mode 100644 index 559b87c..0000000 --- a/include/osmocom/upf/up_peer.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * (C) 2021-2022 by sysmocom - s.f.m.c. GmbH info@sysmocom.de - * All Rights Reserved. - * - * Author: Neels Janosch Hofmeyr nhofmeyr@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/hashtable.h> -#include <osmocom/core/socket.h> -#include <osmocom/core/use_count.h> - -#include <osmocom/pfcp/pfcp_msg.h> - -enum up_peer_event { - UP_PEER_EV_RX_ASSOC_SETUP_REQ, - UP_PEER_EV_RX_ASSOC_UPD_REQ, - UP_PEER_EV_RX_ASSOC_REL_REQ, - UP_PEER_EV_RX_SESSION_EST_REQ, - UP_PEER_EV_HEARTBEAT_FAILURE, - UP_PEER_EV_USE_COUNT_ZERO, - UP_PEER_EV_SESSION_TERM, -}; - -struct up_peer { - /* item in up_endpoint->peers */ - struct llist_head entry; - - struct osmo_fsm_inst *fi; - /* backpointer */ - struct up_endpoint *up_endpoint; - - /* peer's remote address */ - struct osmo_sockaddr remote_addr; - struct osmo_pfcp_ie_node_id remote_node_id; - uint32_t remote_recovery_timestamp; - - struct osmo_pfcp_ie_up_function_features local_up_features; - struct osmo_pfcp_ie_cp_function_features peer_cp_features; - - uint32_t next_seq_nr; - - struct osmo_fsm_inst *heartbeat_fi; - - struct osmo_use_count use_count; - struct osmo_use_count_entry use_count_buf[5]; - - DECLARE_HASHTABLE(sessions_by_up_seid, 10); - DECLARE_HASHTABLE(sessions_by_cp_seid, 10); -}; - -struct up_peer *up_peer_find_or_add(struct up_endpoint *up_ep, const struct osmo_sockaddr *remote_addr); -struct up_peer *up_peer_find(struct up_endpoint *up_ep, const struct osmo_sockaddr *remote_addr); - -void up_peer_set_msg_ctx(struct up_peer *peer, struct osmo_pfcp_msg *m); - -char *up_peer_remote_addr_str(struct up_peer *peer); - -struct osmo_pfcp_msg *up_peer_init_tx(struct up_peer *peer, struct osmo_pfcp_msg *in_reply_to, - enum osmo_pfcp_message_type message_type); - -void up_peer_free(struct up_peer *peer); diff --git a/include/osmocom/upf/up_session.h b/include/osmocom/upf/up_session.h index a20ae06..d08a95e 100644 --- a/include/osmocom/upf/up_session.h +++ b/include/osmocom/upf/up_session.h @@ -32,7 +32,7 @@
struct osmo_fsm_inst; struct osmo_pfcp_msg; -struct up_peer; +struct pfcp_entity_peer;
enum up_session_fsm_event { UP_SESSION_EV_RX_SESSION_EST_REQ, @@ -50,7 +50,7 @@
struct osmo_fsm_inst *fi; /* backpointer */ - struct up_peer *up_peer; + struct pfcp_entity_peer *entity_peer;
struct osmo_pfcp_ie_f_seid cp_f_seid; uint64_t up_seid; @@ -69,10 +69,7 @@ struct llist_head active_gtp_actions; };
-struct up_session *up_session_find_or_add(struct up_peer *peer, const struct osmo_pfcp_ie_f_seid *cp_f_seid); -struct up_session *up_session_find_by_up_seid(struct up_peer *peer, uint64_t up_seid); -struct up_session *up_session_find_by_cp_f_seid(struct up_peer *peer, const struct osmo_pfcp_ie_f_seid *cp_f_seid); - +struct up_session *up_session_alloc(struct pfcp_entity_peer *entity_peer, const struct osmo_pfcp_ie_f_seid *cp_f_seid); void up_session_set_msg_ctx(struct up_session *session, struct osmo_pfcp_msg *m);
char *up_session_gtp_status(struct up_session *session); diff --git a/src/osmo-upf/Makefile.am b/src/osmo-upf/Makefile.am index be72bc2..21ca4b7 100644 --- a/src/osmo-upf/Makefile.am +++ b/src/osmo-upf/Makefile.am @@ -26,10 +26,11 @@ $(NULL)
libupf_la_SOURCES = \ + pfcp_entity_peer.c \ + pfcp_node_peer.c \ netinst.c \ up_endpoint.c \ up_gtp_action.c \ - up_peer.c \ up_session.c \ upf.c \ upf_gtp.c \ diff --git a/src/osmo-upf/pfcp_entity_peer.c b/src/osmo-upf/pfcp_entity_peer.c new file mode 100644 index 0000000..db02f78 --- /dev/null +++ b/src/osmo-upf/pfcp_entity_peer.c @@ -0,0 +1,557 @@ +/* + * (C) 2021-2025 by sysmocom - s.f.m.c. GmbH info@sysmocom.de + * All Rights Reserved. + * + * Author: Neels Janosch Hofmeyr nhofmeyr@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 <errno.h> + +#include <osmocom/core/fsm.h> +#include <osmocom/core/logging.h> +#include <osmocom/core/tdef.h> +#include <osmocom/core/utils.h> + +#include <osmocom/pfcp/pfcp_msg.h> +#include <osmocom/pfcp/pfcp_endpoint.h> + +#include <osmocom/upf/upf.h> +#include <osmocom/upf/pfcp_entity_peer.h> +#include <osmocom/upf/pfcp_node_peer.h> +#include <osmocom/upf/up_endpoint.h> +#include <osmocom/upf/up_session.h> + +enum pfcp_entity_peer_fsm_state { + PFCP_ENTITY_PEER_ST_NOT_ASSOCIATED, + PFCP_ENTITY_PEER_ST_ASSOCIATED, + PFCP_ENTITY_PEER_ST_GRACEFUL_RELEASE, + PFCP_ENTITY_PEER_ST_WAIT_USE_COUNT, +}; + +static const struct value_string pfcp_entity_peer_fsm_event_names[] = { + OSMO_VALUE_STRING(PFCP_ENTITY_PEER_EV_RX_ASSOC_SETUP_REQ), + OSMO_VALUE_STRING(PFCP_ENTITY_PEER_EV_RX_ASSOC_UPD_REQ), + OSMO_VALUE_STRING(PFCP_ENTITY_PEER_EV_RX_ASSOC_REL_REQ), + OSMO_VALUE_STRING(PFCP_ENTITY_PEER_EV_RX_SESSION_EST_REQ), + OSMO_VALUE_STRING(PFCP_ENTITY_PEER_EV_HEARTBEAT_FAILURE), + OSMO_VALUE_STRING(PFCP_ENTITY_PEER_EV_USE_COUNT_ZERO), + OSMO_VALUE_STRING(PFCP_ENTITY_PEER_EV_SESSION_TERM), + {} +}; + +static struct osmo_fsm pfcp_entity_peer_fsm; + +static const struct osmo_tdef_state_timeout pfcp_entity_peer_fsm_timeouts[32] = { + [PFCP_ENTITY_PEER_ST_GRACEFUL_RELEASE] = { .T = -21 }, +}; + +/* Transition to a state, using the T timer defined in pfcp_entity_peer_fsm_timeouts. + * Assumes local variable fi exists. */ +#define pfcp_entity_peer_fsm_state_chg(state) \ + osmo_tdef_fsm_inst_state_chg(fi, state, \ + pfcp_entity_peer_fsm_timeouts, \ + osmo_pfcp_tdefs, \ + 5) + +static int pfcp_entity_peer_use_cb(struct osmo_use_count_entry *e, int32_t old_use_count, const char *file, int line) +{ + struct pfcp_entity_peer *peer = e->use_count->talloc_object; + int32_t total; + int level; + + if (!e->use) + return -EINVAL; + + total = osmo_use_count_total(&peer->use_count); + + if (total == 0 + || (total == 1 && old_use_count == 0 && e->count == 1)) + level = LOGL_INFO; + else + level = LOGL_DEBUG; + + LOGPFSMSLSRC(peer->fi, DREF, level, file, line, + "%s %s: now used by %s\n", + (e->count - old_use_count) > 0 ? "+" : "-", e->use, + osmo_use_count_to_str_c(OTC_SELECT, &peer->use_count)); + + if (e->count < 0) + return -ERANGE; + + if (total == 0) + osmo_fsm_inst_dispatch(peer->fi, PFCP_ENTITY_PEER_EV_USE_COUNT_ZERO, NULL); + return 0; +} + +char *pfcp_entity_peer_remote_addr_str(struct pfcp_entity_peer *peer) +{ + struct osmo_sockaddr remote_addr = peer->remote_addr; + + /* Zero the port, it is not interesting information. The port for PFCP is defined fixed, and there is no use + * printing it in the logs */ + osmo_sockaddr_set_port(&remote_addr.u.sa, 0); + + return osmo_sockaddr_to_str_c(OTC_SELECT, &remote_addr); +} + +static void pfcp_entity_peer_update_id(struct pfcp_entity_peer *peer) +{ + osmo_fsm_inst_update_id_f_sanitize(peer->fi, '-', "%s", pfcp_entity_peer_remote_addr_str(peer)); + LOGPFSML(peer->fi, LOGL_DEBUG, "Updated id\n"); +} + +struct pfcp_entity_peer *pfcp_entity_peer_alloc(struct pfcp_node_peer *node_peer, const struct osmo_sockaddr *remote_addr) +{ + struct pfcp_entity_peer *entity_peer; + + struct osmo_fsm_inst *fi = osmo_fsm_inst_alloc(&pfcp_entity_peer_fsm, node_peer, NULL, LOGL_DEBUG, NULL); + OSMO_ASSERT(fi); + + entity_peer = talloc(fi, struct pfcp_entity_peer); + OSMO_ASSERT(entity_peer); + fi->priv = entity_peer; + + *entity_peer = (struct pfcp_entity_peer) { + .fi = fi, + .node_peer = node_peer, + .remote_addr = *remote_addr, + .heartbeat_fi = NULL /* FIXME */, + .use_count = { + .talloc_object = entity_peer, + .use_cb = pfcp_entity_peer_use_cb, + }, + }; + osmo_use_count_make_static_entries(&entity_peer->use_count, entity_peer->use_count_buf, ARRAY_SIZE(entity_peer->use_count_buf)); + hash_init(entity_peer->sessions_by_up_seid); + hash_init(entity_peer->sessions_by_cp_seid); + + pfcp_entity_peer_update_id(entity_peer); + + pfcp_node_peer_get(node_peer, fi->id); + llist_add(&entity_peer->entry, &node_peer->entity_list); + return entity_peer; +} + +struct up_session *pfcp_entity_peer_find_up_session_by_up_seid(struct pfcp_entity_peer *entity_peer, uint64_t up_seid) +{ + struct up_session *session; + hash_for_each_possible(entity_peer->sessions_by_up_seid, session, node_by_up_seid, up_seid) { + if (up_seid == session->up_seid) + return session; + } + return NULL; +} + +struct up_session *pfcp_entity_peer_find_up_session_by_cp_f_seid(struct pfcp_entity_peer *entity_peer, const struct osmo_pfcp_ie_f_seid *cp_f_seid) +{ + struct up_session *session; + hash_for_each_possible(entity_peer->sessions_by_cp_seid, session, node_by_cp_seid, cp_f_seid->seid) { + if (osmo_pfcp_ie_f_seid_cmp(&session->cp_f_seid, cp_f_seid) == 0) + return session; + } + return NULL; +} + +static int pfcp_entity_peer_fsm_timer_cb(struct osmo_fsm_inst *fi) +{ + //struct pfcp_entity_peer *peer = fi->priv; + /* Return 1 to terminate FSM instance, 0 to keep running */ + return 1; +} + +void pfcp_entity_peer_set_msg_ctx(struct pfcp_entity_peer *peer, struct osmo_pfcp_msg *m) +{ + OSMO_ASSERT(!m->ctx.peer_fi); + + m->ctx.peer_fi = peer->fi; + m->ctx.peer_use_count = &peer->use_count; + m->ctx.peer_use_token = (m->rx ? UP_USE_MSG_RX : UP_USE_MSG_TX); + OSMO_ASSERT(osmo_use_count_get_put(m->ctx.peer_use_count, m->ctx.peer_use_token, 1) == 0); +} + +void pfcp_entity_peer_remove_msg_ctx(struct pfcp_entity_peer *peer, struct osmo_pfcp_msg *m) +{ + OSMO_ASSERT(m->ctx.peer_fi && m->ctx.peer_fi == peer->fi); + OSMO_ASSERT(osmo_use_count_get_put(m->ctx.peer_use_count, m->ctx.peer_use_token, -1) == 0); + m->ctx.peer_fi = NULL; + m->ctx.peer_use_count = NULL; + m->ctx.peer_use_token = NULL; +} + +struct osmo_pfcp_msg *pfcp_entity_peer_init_tx(struct pfcp_entity_peer *peer, + struct osmo_pfcp_msg *in_reply_to, + enum osmo_pfcp_message_type message_type) +{ + struct osmo_pfcp_msg *tx; + if (in_reply_to) + tx = osmo_pfcp_msg_alloc_tx_resp(OTC_SELECT, in_reply_to, message_type); + else + tx = osmo_pfcp_msg_alloc_tx_req(OTC_SELECT, &peer->remote_addr, message_type); + pfcp_entity_peer_set_msg_ctx(peer, tx); + return tx; +} + +static int pfcp_entity_peer_tx_assoc_setup_resp(struct pfcp_entity_peer *entity_peer, struct osmo_pfcp_msg *m, enum osmo_pfcp_cause cause) +{ + struct osmo_pfcp_msg *resp; + + resp = pfcp_entity_peer_init_tx(entity_peer, m, OSMO_PFCP_MSGT_ASSOC_SETUP_RESP); + + resp->ies.assoc_setup_resp = (struct osmo_pfcp_msg_assoc_setup_resp) { + .cause = cause, + .recovery_time_stamp = osmo_pfcp_endpoint_get_recovery_timestamp(g_upf->pfcp.ep->pfcp_ep), + .up_function_features_present = true, + .up_function_features = entity_peer->node_peer->local_up_features, + }; + + if (osmo_pfcp_endpoint_tx(entity_peer->node_peer->up_endpoint->pfcp_ep, resp)) { + OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "Error sending response to this message," + " cannot associate with peer\n"); + return -EIO; + } + return 0; +} + +static int pfcp_entity_peer_tx_assoc_rel_resp(struct pfcp_entity_peer *peer, struct osmo_pfcp_msg *m, enum osmo_pfcp_cause cause) +{ + struct osmo_pfcp_msg *resp; + + resp = pfcp_entity_peer_init_tx(peer, m, OSMO_PFCP_MSGT_ASSOC_RELEASE_RESP); + + resp->ies.assoc_release_resp = (struct osmo_pfcp_msg_assoc_release_resp) { + .cause = cause, + }; + + if (osmo_pfcp_endpoint_tx(peer->node_peer->up_endpoint->pfcp_ep, resp)) { + OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "Error sending response to this message\n"); + return -EIO; + } + return 0; +} + +static void pfcp_entity_peer_clear_sessions(struct pfcp_entity_peer *peer) +{ + struct up_session *session; + int bkt; + struct hlist_node *tmp; + int count = 0; + hash_for_each_safe(peer->sessions_by_up_seid, bkt, tmp, session, node_by_up_seid) { + count += up_session_discard(session); + } + if (count) + LOGPFSML(peer->fi, LOGL_NOTICE, "terminated %d sessions\n", count); +} + +static void pfcp_entity_peer_rx_assoc_setup_req(struct pfcp_entity_peer *peer, struct osmo_pfcp_msg *m) +{ + struct osmo_fsm_inst *fi = peer->fi; + enum osmo_pfcp_cause cause = OSMO_PFCP_CAUSE_REQUEST_ACCEPTED; + + if (fi->state == PFCP_ENTITY_PEER_ST_ASSOCIATED) { + /* Retransmissions of the ACK response happen in pfcp_endpoint.c. So if we get this, it is a genuine + * duplicate association setup request. We could reject it. But why. Just "replace" with the new + * association. Continue. */ + /* If the peer has restarted, it has forgotten about all sessions. */ + if (peer->remote_recovery_timestamp != m->ies.assoc_setup_req.recovery_time_stamp) { + LOGPFSML(fi, LOGL_NOTICE, "another Association Setup Request, with different Recovery Timestamp." + " Clearing sessions, sending ACK.\n"); + pfcp_entity_peer_clear_sessions(peer); + } else { + LOGPFSML(fi, LOGL_NOTICE, "another Association Setup Request, with same Recovery Timestamp." + " Keeping sessions, sending ACK.\n"); + } + } else if (pfcp_entity_peer_fsm_state_chg(PFCP_ENTITY_PEER_ST_ASSOCIATED)) { + /* Not allowed to transition to ST_ASSOCIATED */ + cause = OSMO_PFCP_CAUSE_REQUEST_REJECTED; + } else { + /* Successfully transitioned to ST_ASSOCIATED */ + peer->remote_recovery_timestamp = m->ies.assoc_setup_req.recovery_time_stamp; + if (m->ies.assoc_setup_req.cp_function_features_present) + peer->node_peer->peer_cp_features = m->ies.assoc_setup_req.cp_function_features; + } + + if (pfcp_entity_peer_tx_assoc_setup_resp(peer, m, cause) + || cause != OSMO_PFCP_CAUSE_REQUEST_ACCEPTED) + pfcp_entity_peer_fsm_state_chg(PFCP_ENTITY_PEER_ST_WAIT_USE_COUNT); + + LOGPFSML(fi, LOGL_NOTICE, "Peer associated, Node-Id=%s. Local UP features: [%s]; Peer CP features: [%s]\n", + osmo_pfcp_ie_node_id_to_str_c(OTC_SELECT, &peer->node_peer->node_id), + osmo_pfcp_bits_to_str_c(OTC_SELECT, peer->node_peer->local_up_features.bits, osmo_pfcp_up_feature_strs), + osmo_pfcp_bits_to_str_c(OTC_SELECT, peer->node_peer->peer_cp_features.bits, osmo_pfcp_cp_feature_strs)); +} + +static void pfcp_entity_peer_rx_assoc_rel_req(struct pfcp_entity_peer *peer, struct osmo_pfcp_msg *m) +{ + struct osmo_fsm_inst *fi = peer->fi; + pfcp_entity_peer_tx_assoc_rel_resp(peer, m, OSMO_PFCP_CAUSE_REQUEST_ACCEPTED); + pfcp_entity_peer_fsm_state_chg(PFCP_ENTITY_PEER_ST_WAIT_USE_COUNT); +} + +static void pfcp_entity_peer_rx_session_est_req(struct pfcp_entity_peer *peer, struct osmo_pfcp_msg *m) +{ + enum osmo_pfcp_cause cause = OSMO_PFCP_CAUSE_REQUEST_ACCEPTED; + struct osmo_pfcp_msg *resp; + struct up_session *session = pfcp_entity_peer_find_up_session_by_cp_f_seid(peer, &m->ies.session_est_req.cp_f_seid); + if (!session) + session = up_session_alloc(peer, &m->ies.session_est_req.cp_f_seid); + if (!session) { + cause = OSMO_PFCP_CAUSE_NO_RESOURCES_AVAILABLE; + goto nack_response; + } + + up_session_set_msg_ctx(session, m); + + if (osmo_fsm_inst_dispatch(session->fi, UP_SESSION_EV_RX_SESSION_EST_REQ, m)) { + cause = OSMO_PFCP_CAUSE_REQUEST_REJECTED; + goto nack_response; + } + return; + +nack_response: + resp = pfcp_entity_peer_init_tx(peer, m, OSMO_PFCP_MSGT_SESSION_EST_RESP); + resp->h.seid = m->ies.session_est_req.cp_f_seid.seid; + resp->h.seid_present = true; + resp->ies.session_est_resp = (struct osmo_pfcp_msg_session_est_resp){ + .cause = cause, + }; + osmo_pfcp_endpoint_tx(peer->node_peer->up_endpoint->pfcp_ep, resp); + if (session) + up_session_discard(session); +} + +static void pfcp_entity_peer_not_associated_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct pfcp_entity_peer *peer = fi->priv; + + switch (event) { + + case PFCP_ENTITY_PEER_EV_RX_ASSOC_SETUP_REQ: + pfcp_entity_peer_rx_assoc_setup_req(peer, data); + break; + + case PFCP_ENTITY_PEER_EV_USE_COUNT_ZERO: + /* Not associated and no pending messages. discard peer. */ + pfcp_entity_peer_fsm_state_chg(PFCP_ENTITY_PEER_ST_WAIT_USE_COUNT); + return; + + default: + OSMO_ASSERT(false); + } +} + +static void pfcp_entity_peer_associated_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct pfcp_entity_peer *peer = fi->priv; + + switch (event) { + + case PFCP_ENTITY_PEER_EV_RX_ASSOC_SETUP_REQ: + pfcp_entity_peer_rx_assoc_setup_req(peer, data); + break; + + case PFCP_ENTITY_PEER_EV_RX_ASSOC_UPD_REQ: + // FIXME + break; + + case PFCP_ENTITY_PEER_EV_RX_SESSION_EST_REQ: + pfcp_entity_peer_rx_session_est_req(peer, data); + break; + + case PFCP_ENTITY_PEER_EV_HEARTBEAT_FAILURE: + // FIXME + break; + + case PFCP_ENTITY_PEER_EV_USE_COUNT_ZERO: + /* Stay associated. */ + return; + + default: + OSMO_ASSERT(false); + } +} + +static void pfcp_entity_peer_associated_onleave(struct osmo_fsm_inst *fi, uint32_t next_state) +{ + struct pfcp_entity_peer *peer = fi->priv; + if (next_state != PFCP_ENTITY_PEER_ST_ASSOCIATED) + LOGPFSML(fi, LOGL_NOTICE, "Peer %s released\n", + osmo_pfcp_ie_node_id_to_str_c(OTC_SELECT, &peer->node_peer->node_id)); +} + +static void pfcp_entity_peer_graceful_release_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state) +{ + //struct pfcp_entity_peer *peer = fi->priv; + // FIXME +} + +static void pfcp_entity_peer_graceful_release_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct pfcp_entity_peer *peer = fi->priv; + + switch (event) { + + case PFCP_ENTITY_PEER_EV_HEARTBEAT_FAILURE: + pfcp_entity_peer_fsm_state_chg(PFCP_ENTITY_PEER_ST_WAIT_USE_COUNT); + break; + + case PFCP_ENTITY_PEER_EV_USE_COUNT_ZERO: + /* When there are still sessions, stay around. */ + if (!hash_empty(peer->sessions_by_up_seid)) + return; + pfcp_entity_peer_fsm_state_chg(PFCP_ENTITY_PEER_ST_WAIT_USE_COUNT); + return; + + default: + OSMO_ASSERT(false); + } +} + +static void pfcp_entity_peer_wait_use_count_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state) +{ + struct pfcp_entity_peer *peer = fi->priv; + pfcp_entity_peer_clear_sessions(peer); + if (!osmo_use_count_total(&peer->use_count)) + osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL); +} + +static void pfcp_entity_peer_wait_use_count_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct pfcp_entity_peer *peer = fi->priv; + switch (event) { + + case PFCP_ENTITY_PEER_EV_USE_COUNT_ZERO: + osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL); + return; + + case PFCP_ENTITY_PEER_EV_RX_ASSOC_SETUP_REQ: + pfcp_entity_peer_rx_assoc_setup_req(peer, data); + break; + + default: + OSMO_ASSERT(false); + } +} + +#define S(x) (1 << (x)) + +static const struct osmo_fsm_state pfcp_entity_peer_fsm_states[] = { + [PFCP_ENTITY_PEER_ST_NOT_ASSOCIATED] = { + .name = "NOT_ASSOCIATED", + .in_event_mask = 0 + | S(PFCP_ENTITY_PEER_EV_RX_ASSOC_SETUP_REQ) + | S(PFCP_ENTITY_PEER_EV_USE_COUNT_ZERO) + , + .out_state_mask = 0 + | S(PFCP_ENTITY_PEER_ST_ASSOCIATED) + | S(PFCP_ENTITY_PEER_ST_WAIT_USE_COUNT) + , + .action = pfcp_entity_peer_not_associated_action, + }, + [PFCP_ENTITY_PEER_ST_ASSOCIATED] = { + .name = "ASSOCIATED", + .in_event_mask = 0 + | S(PFCP_ENTITY_PEER_EV_RX_ASSOC_SETUP_REQ) + | S(PFCP_ENTITY_PEER_EV_RX_ASSOC_UPD_REQ) + | S(PFCP_ENTITY_PEER_EV_RX_SESSION_EST_REQ) + | S(PFCP_ENTITY_PEER_EV_HEARTBEAT_FAILURE) + | S(PFCP_ENTITY_PEER_EV_USE_COUNT_ZERO) + , + .out_state_mask = 0 + | S(PFCP_ENTITY_PEER_ST_ASSOCIATED) + | S(PFCP_ENTITY_PEER_ST_GRACEFUL_RELEASE) + | S(PFCP_ENTITY_PEER_ST_WAIT_USE_COUNT) + , + .action = pfcp_entity_peer_associated_action, + .onleave = pfcp_entity_peer_associated_onleave, + }, + [PFCP_ENTITY_PEER_ST_GRACEFUL_RELEASE] = { + .name = "GRACEFUL_RELEASE", + .in_event_mask = 0 + | S(PFCP_ENTITY_PEER_EV_HEARTBEAT_FAILURE) + | S(PFCP_ENTITY_PEER_EV_USE_COUNT_ZERO) + , + .out_state_mask = 0 + | S(PFCP_ENTITY_PEER_ST_WAIT_USE_COUNT) + , + .onenter = pfcp_entity_peer_graceful_release_onenter, + .action = pfcp_entity_peer_graceful_release_action, + }, + [PFCP_ENTITY_PEER_ST_WAIT_USE_COUNT] = { + .name = "WAIT_USE_COUNT", + .in_event_mask = 0 + | S(PFCP_ENTITY_PEER_EV_USE_COUNT_ZERO) + | S(PFCP_ENTITY_PEER_EV_RX_ASSOC_SETUP_REQ) + , + .out_state_mask = 0 + | S(PFCP_ENTITY_PEER_ST_ASSOCIATED) + , + .onenter = pfcp_entity_peer_wait_use_count_onenter, + .action = pfcp_entity_peer_wait_use_count_action, + }, +}; + +void pfcp_entity_peer_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause) +{ + struct pfcp_entity_peer *entity_peer = fi->priv; + LOGPFSML(fi, LOGL_NOTICE, "Peer removed\n"); + llist_del(&entity_peer->entry); + osmo_pfcp_endpoint_invalidate_ctx(entity_peer->node_peer->up_endpoint->pfcp_ep, fi); + pfcp_node_peer_put(entity_peer->node_peer, fi->id); +} + +static void pfcp_entity_peer_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + switch (event) { + case PFCP_ENTITY_PEER_EV_SESSION_TERM: + /* ignore */ + return; + case PFCP_ENTITY_PEER_EV_RX_ASSOC_REL_REQ: + pfcp_entity_peer_rx_assoc_rel_req(fi->priv, data); + return; + default: + OSMO_ASSERT(false); + } +} + +static struct osmo_fsm pfcp_entity_peer_fsm = { + .name = "pfcp_entity_peer", + .log_subsys = DPEER, + .states = pfcp_entity_peer_fsm_states, + .num_states = ARRAY_SIZE(pfcp_entity_peer_fsm_states), + .event_names = pfcp_entity_peer_fsm_event_names, + .timer_cb = pfcp_entity_peer_fsm_timer_cb, + .cleanup = pfcp_entity_peer_fsm_cleanup, + .allstate_event_mask = 0 + | S(PFCP_ENTITY_PEER_EV_RX_ASSOC_REL_REQ) + | S(PFCP_ENTITY_PEER_EV_SESSION_TERM) + , + .allstate_action = pfcp_entity_peer_allstate_action, +}; + +static __attribute__((constructor)) void pfcp_entity_peer_fsm_register(void) +{ + OSMO_ASSERT(osmo_fsm_register(&pfcp_entity_peer_fsm) == 0); +} + +void pfcp_entity_peer_free(struct pfcp_entity_peer *peer) +{ + if (!peer) + return; + osmo_fsm_inst_term(peer->fi, OSMO_FSM_TERM_REGULAR, NULL); +} diff --git a/src/osmo-upf/pfcp_node_peer.c b/src/osmo-upf/pfcp_node_peer.c new file mode 100644 index 0000000..f4c7025 --- /dev/null +++ b/src/osmo-upf/pfcp_node_peer.c @@ -0,0 +1,144 @@ +/* + * (C) 2021-2025 by sysmocom - s.f.m.c. GmbH info@sysmocom.de + * All Rights Reserved. + * + * Author: Neels Janosch Hofmeyr nhofmeyr@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 <errno.h> + +#include <osmocom/core/logging.h> +#include <osmocom/core/tdef.h> +#include <osmocom/core/utils.h> + +#include <osmocom/pfcp/pfcp_msg.h> +#include <osmocom/pfcp/pfcp_endpoint.h> + +#include <osmocom/upf/upf.h> +#include <osmocom/upf/pfcp_entity_peer.h> +#include <osmocom/upf/pfcp_node_peer.h> +#include <osmocom/upf/up_endpoint.h> +#include <osmocom/upf/up_session.h> + + +static int pfcp_node_peer_use_cb(struct osmo_use_count_entry *e, int32_t old_use_count, const char *file, int line) +{ + struct pfcp_node_peer *peer = e->use_count->talloc_object; + int32_t total; + int level; + + if (!peer) /* already in pfcp_node_peer_free() */ + return 0; + + if (!e->use) + return -EINVAL; + + total = osmo_use_count_total(&peer->use_count); + + if (total == 0 + || (total == 1 && old_use_count == 0 && e->count == 1)) + level = LOGL_INFO; + else + level = LOGL_DEBUG; + + LOGPSRC(DREF, level, file, line, + "pfcp_node_peer(%s): %s %s: now used by %s\n", + pfcp_node_peer_node_id_str(peer), + (e->count - old_use_count) > 0 ? "+" : "-", e->use, + osmo_use_count_to_str_c(OTC_SELECT, &peer->use_count)); + + if (e->count < 0) + return -ERANGE; + + if (total == 0) + pfcp_node_peer_free(peer); + return 0; +} + +char *pfcp_node_peer_node_id_str(struct pfcp_node_peer *node_peer) +{ + struct osmo_pfcp_ie_node_id node_id = node_peer->node_id; + + switch (node_id.type) { + case OSMO_PFCP_NODE_ID_T_IPV4: + case OSMO_PFCP_NODE_ID_T_IPV6: + /* Zero the port, it is not interesting information. The port for PFCP is defined fixed, and there is no use + * printing it in the logs */ + osmo_sockaddr_set_port(&node_id.ip.u.sa, 0); + break; + default: + break; + } + + return osmo_pfcp_ie_node_id_to_str_c(OTC_SELECT, &node_id); +} + + +struct pfcp_node_peer *pfcp_node_peer_alloc(struct up_endpoint *up_endpoint, const struct osmo_pfcp_ie_node_id *node_id) +{ + struct pfcp_node_peer *node_peer; + + node_peer = talloc(up_endpoint, struct pfcp_node_peer); + OSMO_ASSERT(node_peer); + + *node_peer = (struct pfcp_node_peer) { + .up_endpoint = up_endpoint, + .node_id = *node_id, + .use_count = { + .talloc_object = node_peer, + .use_cb = pfcp_node_peer_use_cb, + }, + }; + osmo_use_count_make_static_entries(&node_peer->use_count, node_peer->use_count_buf, ARRAY_SIZE(node_peer->use_count_buf)); + INIT_LLIST_HEAD(&node_peer->entity_list); + + osmo_pfcp_bits_set(node_peer->local_up_features.bits, OSMO_PFCP_UP_FEAT_BUNDL, true); + osmo_pfcp_bits_set(node_peer->local_up_features.bits, OSMO_PFCP_UP_FEAT_RTTL, true); + osmo_pfcp_bits_set(node_peer->local_up_features.bits, OSMO_PFCP_UP_FEAT_FTUP, true); + + llist_add(&node_peer->entry, &up_endpoint->pfcp_node_peer_list); + return node_peer; +} + +struct pfcp_entity_peer *pfcp_node_peer_find_entity_by_remote_addr(struct pfcp_node_peer *node_peer, const struct osmo_sockaddr *remote_addr) +{ + struct pfcp_entity_peer *entity_peer; + llist_for_each_entry(entity_peer, &node_peer->entity_list, entry) { + if (osmo_sockaddr_cmp(&entity_peer->remote_addr, remote_addr)) + continue; + return entity_peer; + } + return NULL; +} + +void pfcp_node_peer_free(struct pfcp_node_peer *node_peer) +{ + if (!node_peer) + return; + + LOG_PNP(node_peer, LOGL_NOTICE, "removed\n"); + + struct pfcp_entity_peer *entity_peer; + /* Avoid recursive free over user_count reaching zero while removing last pfcp_entity_peer: */ + node_peer->use_count.talloc_object = NULL; + while ((entity_peer = llist_first_entry_or_null(&node_peer->entity_list, struct pfcp_entity_peer, entry))) + pfcp_entity_peer_free(entity_peer); + + llist_del(&node_peer->entry); +} diff --git a/src/osmo-upf/up_endpoint.c b/src/osmo-upf/up_endpoint.c index f400bdc..f53dc50 100644 --- a/src/osmo-upf/up_endpoint.c +++ b/src/osmo-upf/up_endpoint.c @@ -24,37 +24,54 @@ #include <osmocom/pfcp/pfcp_endpoint.h> #include <osmocom/pfcp/pfcp_msg.h>
+#include <osmocom/upf/pfcp_entity_peer.h> +#include <osmocom/upf/pfcp_node_peer.h> #include <osmocom/upf/up_endpoint.h> -#include <osmocom/upf/up_peer.h> #include <osmocom/upf/up_session.h>
+static struct pfcp_entity_peer *up_endp_find_msg_entity_peer(const struct up_endpoint *up_ep, struct osmo_pfcp_msg *m) +{ + struct pfcp_node_peer *node_peer; + + /* Look up over remote PFCP Entity identified by remote IP address and our local PFCP Entity */ + llist_for_each_entry(node_peer, &up_ep->pfcp_node_peer_list, entry) { + struct pfcp_entity_peer *entity_peer; + llist_for_each_entry(entity_peer, &node_peer->entity_list, entry) { + if (osmo_sockaddr_cmp(&entity_peer->remote_addr, &m->remote_addr)) + continue; + return entity_peer; + } + } + return NULL; +} + static void up_endpoint_set_msg_ctx(struct osmo_pfcp_endpoint *ep, struct osmo_pfcp_msg *m, struct osmo_pfcp_msg *req) { struct up_endpoint *up_ep = osmo_pfcp_endpoint_get_cfg(ep)->priv; - struct up_peer *peer; + struct pfcp_entity_peer *entity_peer = NULL;
/* If this is a response to an earlier request, just take the msg context from the request message. */ if (req) { if (!m->ctx.peer_fi && req->ctx.peer_fi) - up_peer_set_msg_ctx(req->ctx.peer_fi->priv, m); + pfcp_entity_peer_set_msg_ctx(req->ctx.peer_fi->priv, m); if (!m->ctx.session_fi && req->ctx.session_fi) - up_session_set_msg_ctx(req->ctx.session_fi->priv, m); + pfcp_entity_peer_set_msg_ctx(req->ctx.session_fi->priv, m); }
- /* From the remote address, find the matching peer instance */ - if (!m->ctx.peer_fi) { - peer = up_peer_find(up_ep, &m->remote_addr); - if (peer) { - up_peer_set_msg_ctx(peer, m); - } + /* From the Node Id, find the matching PFCP Node */ + if (m->ctx.peer_fi) { + entity_peer = m->ctx.peer_fi->priv; } else { - peer = m->ctx.peer_fi->priv; + entity_peer = up_endp_find_msg_entity_peer(up_ep, m); + if (entity_peer) + pfcp_entity_peer_set_msg_ctx(entity_peer, m); }
+ /* Find a session, if the header is parsed yet and contains a SEID */ - if (peer && !m->ctx.session_fi && m->h.seid_present) { + if (entity_peer && !m->ctx.session_fi && m->h.seid_present) { struct up_session *session; - session = up_session_find_by_up_seid(peer, m->h.seid); + session = pfcp_entity_peer_find_up_session_by_up_seid(entity_peer, m->h.seid); if (session) { up_session_set_msg_ctx(session, m); } @@ -79,14 +96,39 @@ up_ep_rx_not_impl_req(up_ep, m, OSMO_PFCP_MSGT_PFD_MGMT_RESP, OSMO_PFCP_CAUSE_SERVICE_NOT_SUPPORTED); }
-static void up_ep_rx_assoc_setup_req(struct up_endpoint *up_ep, const struct osmo_pfcp_msg *m) +static void up_ep_rx_assoc_setup_req(struct up_endpoint *up_ep, struct osmo_pfcp_msg *m) { - struct up_peer *peer = m->ctx.peer_fi ? m->ctx.peer_fi->priv : NULL; - if (!peer) { - peer = up_peer_find_or_add(up_ep, &m->remote_addr); - OSMO_ASSERT(peer); + struct pfcp_entity_peer *entity_peer = m->ctx.peer_fi ? m->ctx.peer_fi->priv : NULL; + struct osmo_pfcp_ie_node_id *node_id = osmo_pfcp_msg_node_id(m); + struct pfcp_node_peer *node_peer; + OSMO_ASSERT(node_id); + + /* If PFCP entity belonged to a different PFCP Node (ie. Node Id changed), drop + * old entity and re-create a new one on the new Node: */ + if (entity_peer && osmo_pfcp_ie_node_id_cmp(&entity_peer->node_peer->node_id, node_id)) { + OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "PFCP Entity Node-Id changed: %s -> %s!\n", + osmo_pfcp_ie_node_id_to_str_c(OTC_SELECT, &entity_peer->node_peer->node_id), + osmo_pfcp_ie_node_id_to_str_c(OTC_SELECT, node_id)); + pfcp_entity_peer_remove_msg_ctx(entity_peer, m); + pfcp_entity_peer_free(entity_peer); + entity_peer = NULL; } - osmo_fsm_inst_dispatch(peer->fi, UP_PEER_EV_RX_ASSOC_SETUP_REQ, (void *)m); + + if (!entity_peer) { + OSMO_ASSERT(node_id); + node_peer = up_endpoint_find_pfcp_node_peer(up_ep, node_id); + if (!node_peer) { + node_peer = pfcp_node_peer_alloc(up_ep, node_id); + OSMO_ASSERT(node_peer); + } + entity_peer = pfcp_node_peer_find_entity_by_remote_addr(node_peer, &m->remote_addr); + if (!entity_peer) { + entity_peer = pfcp_entity_peer_alloc(node_peer, &m->remote_addr); + OSMO_ASSERT(entity_peer); + } + pfcp_entity_peer_set_msg_ctx(entity_peer, m); + } + osmo_fsm_inst_dispatch(entity_peer->fi, PFCP_ENTITY_PEER_EV_RX_ASSOC_SETUP_REQ, (void *)m); }
static void up_ep_rx_assoc_upd_req(struct up_endpoint *up_ep, const struct osmo_pfcp_msg *m) @@ -98,7 +140,7 @@ osmo_pfcp_endpoint_tx(up_ep->pfcp_ep, tx); return; } - osmo_fsm_inst_dispatch(m->ctx.peer_fi, UP_PEER_EV_RX_ASSOC_UPD_REQ, (void *)m); + osmo_fsm_inst_dispatch(m->ctx.peer_fi, PFCP_ENTITY_PEER_EV_RX_ASSOC_UPD_REQ, (void *)m); }
static void up_ep_rx_assoc_rel_req(struct up_endpoint *up_ep, const struct osmo_pfcp_msg *m) @@ -110,7 +152,7 @@ osmo_pfcp_endpoint_tx(up_ep->pfcp_ep, tx); return; } - osmo_fsm_inst_dispatch(m->ctx.peer_fi, UP_PEER_EV_RX_ASSOC_REL_REQ, (void *)m); + osmo_fsm_inst_dispatch(m->ctx.peer_fi, PFCP_ENTITY_PEER_EV_RX_ASSOC_REL_REQ, (void *)m); }
static void up_ep_rx_node_report_req(struct up_endpoint *up_ep, const struct osmo_pfcp_msg *m) @@ -134,7 +176,7 @@ osmo_pfcp_endpoint_tx(up_ep->pfcp_ep, tx); return; } - osmo_fsm_inst_dispatch(m->ctx.peer_fi, UP_PEER_EV_RX_SESSION_EST_REQ, (void *)m); + osmo_fsm_inst_dispatch(m->ctx.peer_fi, PFCP_ENTITY_PEER_EV_RX_SESSION_EST_REQ, (void *)m); }
static void up_ep_rx_session_mod_req(struct up_endpoint *up_ep, const struct osmo_pfcp_msg *m) @@ -238,7 +280,7 @@ struct osmo_pfcp_endpoint_cfg cfg; struct up_endpoint *up_ep; up_ep = talloc_zero(ctx, struct up_endpoint); - INIT_LLIST_HEAD(&up_ep->peers); + INIT_LLIST_HEAD(&up_ep->pfcp_node_peer_list); hash_init(up_ep->sessions_by_up_seid);
cfg = (struct osmo_pfcp_endpoint_cfg){ @@ -262,6 +304,18 @@ return osmo_pfcp_endpoint_bind(up_ep->pfcp_ep); }
+struct pfcp_node_peer *up_endpoint_find_pfcp_node_peer(const struct up_endpoint *up_ep, + const struct osmo_pfcp_ie_node_id *node_id) +{ + struct pfcp_node_peer *node_peer; + llist_for_each_entry(node_peer, &up_ep->pfcp_node_peer_list, entry) { + if (osmo_pfcp_ie_node_id_cmp(&node_peer->node_id, node_id)) + continue; + return node_peer; + } + return NULL; +} + static struct up_session *up_endpoint_find_session(struct up_endpoint *ep, uint64_t up_seid) { struct up_session *session; @@ -286,11 +340,11 @@
void up_endpoint_free(struct up_endpoint **_ep) { - struct up_peer *peer; + struct pfcp_node_peer *node_peer; struct up_endpoint *ep = *_ep;
- while ((peer = llist_first_entry_or_null(&ep->peers, struct up_peer, entry))) - up_peer_free(peer); + while ((node_peer = llist_first_entry_or_null(&ep->pfcp_node_peer_list, struct pfcp_node_peer, entry))) + pfcp_node_peer_free(node_peer);
osmo_pfcp_endpoint_free(&ep->pfcp_ep); *_ep = NULL; diff --git a/src/osmo-upf/up_gtp_action.c b/src/osmo-upf/up_gtp_action.c index f8b8e58..8ae2c3e 100644 --- a/src/osmo-upf/up_gtp_action.c +++ b/src/osmo-upf/up_gtp_action.c @@ -28,7 +28,7 @@
#include <osmocom/upf/upf.h> #include <osmocom/upf/up_gtp_action.h> -#include <osmocom/upf/up_peer.h> +#include <osmocom/upf/pfcp_entity_peer.h> #include <osmocom/upf/up_session.h>
int up_gtp_action_cmp(const struct up_gtp_action *a, const struct up_gtp_action *b) @@ -188,7 +188,7 @@ } if (a->session) OSMO_STRBUF_PRINTF(sb, " PFCP-peer:%s SEID-l:0x%"PRIx64, - up_peer_remote_addr_str(a->session->up_peer), a->session->up_seid); + pfcp_entity_peer_remote_addr_str(a->session->entity_peer), a->session->up_seid); OSMO_STRBUF_PRINTF(sb, " PDR-access:%d", a->pdr_access); OSMO_STRBUF_PRINTF(sb, " PDR-core:%d", a->pdr_core); return sb.chars_needed; diff --git a/src/osmo-upf/up_peer.c b/src/osmo-upf/up_peer.c deleted file mode 100644 index 08f7d12..0000000 --- a/src/osmo-upf/up_peer.c +++ /dev/null @@ -1,544 +0,0 @@ -/* - * (C) 2021-2022 by sysmocom - s.f.m.c. GmbH info@sysmocom.de - * All Rights Reserved. - * - * Author: Neels Janosch Hofmeyr nhofmeyr@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 <errno.h> - -#include <osmocom/core/fsm.h> -#include <osmocom/core/logging.h> -#include <osmocom/core/tdef.h> -#include <osmocom/core/utils.h> - -#include <osmocom/pfcp/pfcp_msg.h> -#include <osmocom/pfcp/pfcp_endpoint.h> - -#include <osmocom/upf/upf.h> -#include <osmocom/upf/up_peer.h> -#include <osmocom/upf/up_endpoint.h> -#include <osmocom/upf/up_session.h> - -enum up_peer_fsm_state { - UP_PEER_ST_NOT_ASSOCIATED, - UP_PEER_ST_ASSOCIATED, - UP_PEER_ST_GRACEFUL_RELEASE, - UP_PEER_ST_WAIT_USE_COUNT, -}; - -static const struct value_string up_peer_fsm_event_names[] = { - OSMO_VALUE_STRING(UP_PEER_EV_RX_ASSOC_SETUP_REQ), - OSMO_VALUE_STRING(UP_PEER_EV_RX_ASSOC_UPD_REQ), - OSMO_VALUE_STRING(UP_PEER_EV_RX_ASSOC_REL_REQ), - OSMO_VALUE_STRING(UP_PEER_EV_RX_SESSION_EST_REQ), - OSMO_VALUE_STRING(UP_PEER_EV_HEARTBEAT_FAILURE), - OSMO_VALUE_STRING(UP_PEER_EV_USE_COUNT_ZERO), - OSMO_VALUE_STRING(UP_PEER_EV_SESSION_TERM), - {} -}; - -static struct osmo_fsm up_peer_fsm; - -static const struct osmo_tdef_state_timeout up_peer_fsm_timeouts[32] = { - [UP_PEER_ST_GRACEFUL_RELEASE] = { .T = -21 }, -}; - -/* Transition to a state, using the T timer defined in up_peer_fsm_timeouts. - * Assumes local variable fi exists. */ -#define up_peer_fsm_state_chg(state) \ - osmo_tdef_fsm_inst_state_chg(fi, state, \ - up_peer_fsm_timeouts, \ - osmo_pfcp_tdefs, \ - 5) - -static int up_peer_use_cb(struct osmo_use_count_entry *e, int32_t old_use_count, const char *file, int line) -{ - struct up_peer *peer = e->use_count->talloc_object; - int32_t total; - int level; - - if (!e->use) - return -EINVAL; - - total = osmo_use_count_total(&peer->use_count); - - if (total == 0 - || (total == 1 && old_use_count == 0 && e->count == 1)) - level = LOGL_INFO; - else - level = LOGL_DEBUG; - - LOGPFSMSLSRC(peer->fi, DREF, level, file, line, - "%s %s: now used by %s\n", - (e->count - old_use_count) > 0 ? "+" : "-", e->use, - osmo_use_count_to_str_c(OTC_SELECT, &peer->use_count)); - - if (e->count < 0) - return -ERANGE; - - if (total == 0) - osmo_fsm_inst_dispatch(peer->fi, UP_PEER_EV_USE_COUNT_ZERO, NULL); - return 0; -} - -char *up_peer_remote_addr_str(struct up_peer *peer) -{ - struct osmo_sockaddr remote_addr = peer->remote_addr; - - /* Zero the port, it is not interesting information. The port for PFCP is defined fixed, and there is no use - * printing it in the logs */ - osmo_sockaddr_set_port(&remote_addr.u.sa, 0); - - return osmo_sockaddr_to_str_c(OTC_SELECT, &remote_addr); -} - -static void up_peer_update_id(struct up_peer *peer) -{ - osmo_fsm_inst_update_id_f_sanitize(peer->fi, '-', "%s", up_peer_remote_addr_str(peer)); - LOGPFSML(peer->fi, LOGL_DEBUG, "Updated id\n"); -} - -static struct up_peer *up_peer_add(struct up_endpoint *up_endpoint, const struct osmo_sockaddr *remote_addr) -{ - struct up_peer *peer; - - struct osmo_fsm_inst *fi = osmo_fsm_inst_alloc(&up_peer_fsm, up_endpoint, NULL, LOGL_DEBUG, NULL); - OSMO_ASSERT(fi); - - peer = talloc(fi, struct up_peer); - OSMO_ASSERT(peer); - fi->priv = peer; - - *peer = (struct up_peer) { - .fi = fi, - .up_endpoint = up_endpoint, - .remote_addr = *remote_addr, - .heartbeat_fi = NULL /* FIXME */, - .use_count = { - .talloc_object = peer, - .use_cb = up_peer_use_cb, - }, - }; - osmo_use_count_make_static_entries(&peer->use_count, peer->use_count_buf, ARRAY_SIZE(peer->use_count_buf)); - hash_init(peer->sessions_by_up_seid); - hash_init(peer->sessions_by_cp_seid); - - osmo_pfcp_bits_set(peer->local_up_features.bits, OSMO_PFCP_UP_FEAT_BUNDL, true); - osmo_pfcp_bits_set(peer->local_up_features.bits, OSMO_PFCP_UP_FEAT_RTTL, true); - osmo_pfcp_bits_set(peer->local_up_features.bits, OSMO_PFCP_UP_FEAT_FTUP, true); - - up_peer_update_id(peer); - - llist_add(&peer->entry, &up_endpoint->peers); - return peer; -} - -struct up_peer *up_peer_find(struct up_endpoint *up_endpoint, const struct osmo_sockaddr *remote_addr) -{ - struct up_peer *peer; - llist_for_each_entry(peer, &up_endpoint->peers, entry) { - if (osmo_sockaddr_cmp(&peer->remote_addr, remote_addr)) - continue; - return peer; - } - return NULL; -} - -struct up_peer *up_peer_find_or_add(struct up_endpoint *up_endpoint, const struct osmo_sockaddr *remote_addr) -{ - struct up_peer *peer = up_peer_find(up_endpoint, remote_addr); - if (peer) - return peer; - return up_peer_add(up_endpoint, remote_addr); -} - -static int up_peer_fsm_timer_cb(struct osmo_fsm_inst *fi) -{ - //struct up_peer *peer = fi->priv; - /* Return 1 to terminate FSM instance, 0 to keep running */ - return 1; -} - -void up_peer_set_msg_ctx(struct up_peer *peer, struct osmo_pfcp_msg *m) -{ - OSMO_ASSERT(!m->ctx.peer_fi); - - m->ctx.peer_fi = peer->fi; - m->ctx.peer_use_count = &peer->use_count; - m->ctx.peer_use_token = (m->rx ? UP_USE_MSG_RX : UP_USE_MSG_TX); - OSMO_ASSERT(osmo_use_count_get_put(m->ctx.peer_use_count, m->ctx.peer_use_token, 1) == 0); -} - -struct osmo_pfcp_msg *up_peer_init_tx(struct up_peer *peer, struct osmo_pfcp_msg *in_reply_to, - enum osmo_pfcp_message_type message_type) -{ - struct osmo_pfcp_msg *tx; - if (in_reply_to) - tx = osmo_pfcp_msg_alloc_tx_resp(OTC_SELECT, in_reply_to, message_type); - else - tx = osmo_pfcp_msg_alloc_tx_req(OTC_SELECT, &peer->remote_addr, message_type); - up_peer_set_msg_ctx(peer, tx); - return tx; -} - -static int up_peer_tx_assoc_setup_resp(struct up_peer *peer, struct osmo_pfcp_msg *m, enum osmo_pfcp_cause cause) -{ - struct osmo_pfcp_msg *resp; - - resp = up_peer_init_tx(peer, m, OSMO_PFCP_MSGT_ASSOC_SETUP_RESP); - - resp->ies.assoc_setup_resp = (struct osmo_pfcp_msg_assoc_setup_resp) { - .cause = cause, - .recovery_time_stamp = osmo_pfcp_endpoint_get_recovery_timestamp(g_upf->pfcp.ep->pfcp_ep), - .up_function_features_present = true, - .up_function_features = peer->local_up_features, - }; - - if (osmo_pfcp_endpoint_tx(peer->up_endpoint->pfcp_ep, resp)) { - OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "Error sending response to this message," - " cannot associate with peer\n"); - return -EIO; - } - return 0; -} - -static int up_peer_tx_assoc_rel_resp(struct up_peer *peer, struct osmo_pfcp_msg *m, enum osmo_pfcp_cause cause) -{ - struct osmo_pfcp_msg *resp; - - resp = up_peer_init_tx(peer, m, OSMO_PFCP_MSGT_ASSOC_RELEASE_RESP); - - resp->ies.assoc_release_resp = (struct osmo_pfcp_msg_assoc_release_resp) { - .cause = cause, - }; - - if (osmo_pfcp_endpoint_tx(peer->up_endpoint->pfcp_ep, resp)) { - OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "Error sending response to this message\n"); - return -EIO; - } - return 0; -} - -static void up_peer_clear_sessions(struct up_peer *peer) -{ - struct up_session *session; - int bkt; - struct hlist_node *tmp; - int count = 0; - hash_for_each_safe(peer->sessions_by_up_seid, bkt, tmp, session, node_by_up_seid) { - count += up_session_discard(session); - } - if (count) - LOGPFSML(peer->fi, LOGL_NOTICE, "terminated %d sessions\n", count); -} - -static void up_peer_rx_assoc_setup_req(struct up_peer *peer, struct osmo_pfcp_msg *m) -{ - struct osmo_fsm_inst *fi = peer->fi; - enum osmo_pfcp_cause cause = OSMO_PFCP_CAUSE_REQUEST_ACCEPTED; - - if (fi->state == UP_PEER_ST_ASSOCIATED) { - /* Retransmissions of the ACK response happen in pfcp_endpoint.c. So if we get this, it is a genuine - * duplicate association setup request. We could reject it. But why. Just "replace" with the new - * association. Continue. */ - /* If the peer has restarted, it has forgotten about all sessions. */ - if (peer->remote_recovery_timestamp != m->ies.assoc_setup_req.recovery_time_stamp) { - LOGPFSML(fi, LOGL_NOTICE, "another Association Setup Request, with different Recovery Timestamp." - " Clearing sessions, sending ACK.\n"); - up_peer_clear_sessions(peer); - } else { - LOGPFSML(fi, LOGL_NOTICE, "another Association Setup Request, with same Recovery Timestamp." - " Keeping sessions, sending ACK.\n"); - } - } else if (up_peer_fsm_state_chg(UP_PEER_ST_ASSOCIATED)) { - /* Not allowed to transition to ST_ASSOCIATED */ - cause = OSMO_PFCP_CAUSE_REQUEST_REJECTED; - } else { - /* Successfully transitioned to ST_ASSOCIATED */ - peer->remote_recovery_timestamp = m->ies.assoc_setup_req.recovery_time_stamp; - peer->remote_node_id = m->ies.assoc_setup_req.node_id; - if (m->ies.assoc_setup_req.cp_function_features_present) - peer->peer_cp_features = m->ies.assoc_setup_req.cp_function_features; - } - - if (up_peer_tx_assoc_setup_resp(peer, m, cause) - || cause != OSMO_PFCP_CAUSE_REQUEST_ACCEPTED) - up_peer_fsm_state_chg(UP_PEER_ST_WAIT_USE_COUNT); - - LOGPFSML(fi, LOGL_NOTICE, "Peer associated, Node-Id=%s. Local UP features: [%s]; Peer CP features: [%s]\n", - osmo_pfcp_ie_node_id_to_str_c(OTC_SELECT, &peer->remote_node_id), - osmo_pfcp_bits_to_str_c(OTC_SELECT, peer->local_up_features.bits, osmo_pfcp_up_feature_strs), - osmo_pfcp_bits_to_str_c(OTC_SELECT, peer->peer_cp_features.bits, osmo_pfcp_cp_feature_strs)); -} - -static void up_peer_rx_assoc_rel_req(struct up_peer *peer, struct osmo_pfcp_msg *m) -{ - struct osmo_fsm_inst *fi = peer->fi; - up_peer_tx_assoc_rel_resp(peer, m, OSMO_PFCP_CAUSE_REQUEST_ACCEPTED); - up_peer_fsm_state_chg(UP_PEER_ST_WAIT_USE_COUNT); -} - -static void up_peer_rx_session_est_req(struct up_peer *peer, struct osmo_pfcp_msg *m) -{ - enum osmo_pfcp_cause cause = OSMO_PFCP_CAUSE_REQUEST_ACCEPTED; - struct osmo_pfcp_msg *resp; - struct up_session *session = up_session_find_or_add(peer, &m->ies.session_est_req.cp_f_seid); - - if (!session) { - cause = OSMO_PFCP_CAUSE_NO_RESOURCES_AVAILABLE; - goto nack_response; - } - - up_session_set_msg_ctx(session, m); - - if (osmo_fsm_inst_dispatch(session->fi, UP_SESSION_EV_RX_SESSION_EST_REQ, m)) { - cause = OSMO_PFCP_CAUSE_REQUEST_REJECTED; - goto nack_response; - } - return; - -nack_response: - resp = up_peer_init_tx(peer, m, OSMO_PFCP_MSGT_SESSION_EST_RESP); - resp->h.seid = m->ies.session_est_req.cp_f_seid.seid; - resp->h.seid_present = true; - resp->ies.session_est_resp = (struct osmo_pfcp_msg_session_est_resp){ - .cause = cause, - }; - osmo_pfcp_endpoint_tx(peer->up_endpoint->pfcp_ep, resp); - if (session) - up_session_discard(session); -} - -static void up_peer_not_associated_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct up_peer *peer = fi->priv; - - switch (event) { - - case UP_PEER_EV_RX_ASSOC_SETUP_REQ: - up_peer_rx_assoc_setup_req(peer, data); - break; - - case UP_PEER_EV_USE_COUNT_ZERO: - /* Not associated and no pending messages. discard peer. */ - up_peer_fsm_state_chg(UP_PEER_ST_WAIT_USE_COUNT); - return; - - default: - OSMO_ASSERT(false); - } -} - -static void up_peer_associated_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct up_peer *peer = fi->priv; - - switch (event) { - - case UP_PEER_EV_RX_ASSOC_SETUP_REQ: - up_peer_rx_assoc_setup_req(peer, data); - break; - - case UP_PEER_EV_RX_ASSOC_UPD_REQ: - // FIXME - break; - - case UP_PEER_EV_RX_SESSION_EST_REQ: - up_peer_rx_session_est_req(peer, data); - break; - - case UP_PEER_EV_HEARTBEAT_FAILURE: - // FIXME - break; - - case UP_PEER_EV_USE_COUNT_ZERO: - /* Stay associated. */ - return; - - default: - OSMO_ASSERT(false); - } -} - -static void up_peer_associated_onleave(struct osmo_fsm_inst *fi, uint32_t next_state) -{ - struct up_peer *peer = fi->priv; - if (next_state != UP_PEER_ST_ASSOCIATED) - LOGPFSML(fi, LOGL_NOTICE, "Peer %s released\n", - osmo_pfcp_ie_node_id_to_str_c(OTC_SELECT, &peer->remote_node_id)); -} - -static void up_peer_graceful_release_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state) -{ - //struct up_peer *peer = fi->priv; - // FIXME -} - -static void up_peer_graceful_release_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct up_peer *peer = fi->priv; - - switch (event) { - - case UP_PEER_EV_HEARTBEAT_FAILURE: - up_peer_fsm_state_chg(UP_PEER_ST_WAIT_USE_COUNT); - break; - - case UP_PEER_EV_USE_COUNT_ZERO: - /* When there are still sessions, stay around. */ - if (!hash_empty(peer->sessions_by_up_seid)) - return; - up_peer_fsm_state_chg(UP_PEER_ST_WAIT_USE_COUNT); - return; - - default: - OSMO_ASSERT(false); - } -} - -static void up_peer_wait_use_count_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state) -{ - struct up_peer *peer = fi->priv; - up_peer_clear_sessions(peer); - if (!osmo_use_count_total(&peer->use_count)) - osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL); -} - -static void up_peer_wait_use_count_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct up_peer *peer = fi->priv; - switch (event) { - - case UP_PEER_EV_USE_COUNT_ZERO: - osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL); - return; - - case UP_PEER_EV_RX_ASSOC_SETUP_REQ: - up_peer_rx_assoc_setup_req(peer, data); - break; - - default: - OSMO_ASSERT(false); - } -} - -#define S(x) (1 << (x)) - -static const struct osmo_fsm_state up_peer_fsm_states[] = { - [UP_PEER_ST_NOT_ASSOCIATED] = { - .name = "NOT_ASSOCIATED", - .in_event_mask = 0 - | S(UP_PEER_EV_RX_ASSOC_SETUP_REQ) - | S(UP_PEER_EV_USE_COUNT_ZERO) - , - .out_state_mask = 0 - | S(UP_PEER_ST_ASSOCIATED) - | S(UP_PEER_ST_WAIT_USE_COUNT) - , - .action = up_peer_not_associated_action, - }, - [UP_PEER_ST_ASSOCIATED] = { - .name = "ASSOCIATED", - .in_event_mask = 0 - | S(UP_PEER_EV_RX_ASSOC_SETUP_REQ) - | S(UP_PEER_EV_RX_ASSOC_UPD_REQ) - | S(UP_PEER_EV_RX_SESSION_EST_REQ) - | S(UP_PEER_EV_HEARTBEAT_FAILURE) - | S(UP_PEER_EV_USE_COUNT_ZERO) - , - .out_state_mask = 0 - | S(UP_PEER_ST_ASSOCIATED) - | S(UP_PEER_ST_GRACEFUL_RELEASE) - | S(UP_PEER_ST_WAIT_USE_COUNT) - , - .action = up_peer_associated_action, - .onleave = up_peer_associated_onleave, - }, - [UP_PEER_ST_GRACEFUL_RELEASE] = { - .name = "GRACEFUL_RELEASE", - .in_event_mask = 0 - | S(UP_PEER_EV_HEARTBEAT_FAILURE) - | S(UP_PEER_EV_USE_COUNT_ZERO) - , - .out_state_mask = 0 - | S(UP_PEER_ST_WAIT_USE_COUNT) - , - .onenter = up_peer_graceful_release_onenter, - .action = up_peer_graceful_release_action, - }, - [UP_PEER_ST_WAIT_USE_COUNT] = { - .name = "WAIT_USE_COUNT", - .in_event_mask = 0 - | S(UP_PEER_EV_USE_COUNT_ZERO) - | S(UP_PEER_EV_RX_ASSOC_SETUP_REQ) - , - .out_state_mask = 0 - | S(UP_PEER_ST_ASSOCIATED) - , - .onenter = up_peer_wait_use_count_onenter, - .action = up_peer_wait_use_count_action, - }, -}; - -void up_peer_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause) -{ - struct up_peer *peer = fi->priv; - LOGPFSML(fi, LOGL_NOTICE, "Peer removed\n"); - llist_del(&peer->entry); -} - -static void up_peer_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - switch (event) { - case UP_PEER_EV_SESSION_TERM: - /* ignore */ - return; - case UP_PEER_EV_RX_ASSOC_REL_REQ: - up_peer_rx_assoc_rel_req(fi->priv, data); - return; - default: - OSMO_ASSERT(false); - } -} - -static struct osmo_fsm up_peer_fsm = { - .name = "up_peer", - .log_subsys = DPEER, - .states = up_peer_fsm_states, - .num_states = ARRAY_SIZE(up_peer_fsm_states), - .event_names = up_peer_fsm_event_names, - .timer_cb = up_peer_fsm_timer_cb, - .cleanup = up_peer_fsm_cleanup, - .allstate_event_mask = 0 - | S(UP_PEER_EV_RX_ASSOC_REL_REQ) - | S(UP_PEER_EV_SESSION_TERM) - , - .allstate_action = up_peer_allstate_action, -}; - -static __attribute__((constructor)) void up_peer_fsm_register(void) -{ - OSMO_ASSERT(osmo_fsm_register(&up_peer_fsm) == 0); -} - -void up_peer_free(struct up_peer *peer) -{ - osmo_fsm_inst_term(peer->fi, OSMO_FSM_TERM_REGULAR, NULL); -} diff --git a/src/osmo-upf/up_session.c b/src/osmo-upf/up_session.c index b96fd49..5f406d5 100644 --- a/src/osmo-upf/up_session.c +++ b/src/osmo-upf/up_session.c @@ -31,7 +31,8 @@
#include <osmocom/upf/upf.h> #include <osmocom/upf/up_endpoint.h> -#include <osmocom/upf/up_peer.h> +#include <osmocom/upf/pfcp_entity_peer.h> +#include <osmocom/upf/pfcp_node_peer.h> #include <osmocom/upf/up_session.h> #include <osmocom/upf/up_gtp_action.h> #include <osmocom/upf/netinst.h> @@ -41,7 +42,7 @@ void up_session_set_msg_ctx(struct up_session *session, struct osmo_pfcp_msg *m) { if (!m->ctx.peer_fi) - up_peer_set_msg_ctx(session->up_peer, m); + pfcp_entity_peer_set_msg_ctx(session->entity_peer, m);
OSMO_ASSERT(!m->ctx.session_fi);
@@ -92,7 +93,7 @@ struct osmo_pfcp_msg *up_session_init_tx(struct up_session *session, struct osmo_pfcp_msg *in_reply_to, enum osmo_pfcp_message_type message_type) { - struct osmo_pfcp_msg *tx = up_peer_init_tx(session->up_peer, in_reply_to, message_type); + struct osmo_pfcp_msg *tx = pfcp_entity_peer_init_tx(session->entity_peer, in_reply_to, message_type); tx->h.seid = session->cp_f_seid.seid; tx->h.seid_present = true; up_session_set_msg_ctx(session, tx); @@ -130,7 +131,7 @@ * 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))) { + osmo_pfcp_endpoint_get_local_addr(session->entity_peer->node_peer->up_endpoint->pfcp_ep))) { LOGPFSML(session->fi, LOGL_ERROR, "Invalid local address in pfcp_endpoint cfg\n"); return OSMO_PFCP_CAUSE_SYSTEM_FAILURE; } @@ -600,7 +601,7 @@ static void up_session_est(struct up_session *session, struct osmo_pfcp_msg *m) { struct osmo_fsm_inst *fi = session->fi; - struct up_peer *peer = session->up_peer; + struct pfcp_entity_peer *peer = session->entity_peer; struct osmo_pfcp_msg_session_est_req *req = &m->ies.session_est_req; struct osmo_pfcp_msg_session_est_resp *resp; struct osmo_pfcp_msg *tx; @@ -632,10 +633,10 @@
/* Success, send ACK */ osmo_pfcp_ie_f_seid_set(&resp->up_f_seid, session->up_seid, - osmo_pfcp_endpoint_get_local_addr(peer->up_endpoint->pfcp_ep)); + osmo_pfcp_endpoint_get_local_addr(peer->node_peer->up_endpoint->pfcp_ep)); resp->up_f_seid_present = true;
- rc = osmo_pfcp_endpoint_tx(peer->up_endpoint->pfcp_ep, tx); + rc = osmo_pfcp_endpoint_tx(peer->node_peer->up_endpoint->pfcp_ep, tx); if (rc) { /* sending ACK failed, discard session. It might seem like a good idea to keep the session around, * because the creation succeeded, only the ACK failed. But in the greater scheme of things, if we @@ -648,7 +649,7 @@
nack_response: resp->created_pdr_count = 0; - osmo_pfcp_endpoint_tx(peer->up_endpoint->pfcp_ep, tx); + osmo_pfcp_endpoint_tx(peer->node_peer->up_endpoint->pfcp_ep, tx); /* No matter if sending the NACK succeeded or not, discard the session. */ up_session_fsm_state_chg(UP_SESSION_ST_WAIT_USE_COUNT); } @@ -656,7 +657,7 @@ static void up_session_mod(struct up_session *session, struct osmo_pfcp_msg *m) { struct osmo_fsm_inst *fi = session->fi; - struct up_peer *peer = session->up_peer; + struct pfcp_entity_peer *peer = session->entity_peer; struct osmo_pfcp_msg_session_mod_req *req = &m->ies.session_mod_req; struct osmo_pfcp_msg_session_mod_resp *resp; struct osmo_pfcp_msg *tx; @@ -730,7 +731,7 @@ goto nack_response;
/* Success, send ACK */ - if (osmo_pfcp_endpoint_tx(peer->up_endpoint->pfcp_ep, tx)) { + if (osmo_pfcp_endpoint_tx(peer->node_peer->up_endpoint->pfcp_ep, tx)) { /* sending ACK failed, discard session. It might seem like a good idea to keep the session around, * because the modification succeeded, only the ACK failed. But in the greater scheme of things, if we * cannot ACK to the PFCP peer, all is lost. Rather not keep stale sessions around. */ @@ -743,7 +744,7 @@
nack_response: resp->created_pdr_count = 0; - osmo_pfcp_endpoint_tx(peer->up_endpoint->pfcp_ep, tx); + osmo_pfcp_endpoint_tx(peer->node_peer->up_endpoint->pfcp_ep, tx); /* No matter if sending the NACK succeeded or not, discard the session. */ up_session_fsm_state_chg(UP_SESSION_ST_WAIT_USE_COUNT); } @@ -751,14 +752,14 @@ static void up_session_del(struct up_session *session, struct osmo_pfcp_msg *m) { struct osmo_fsm_inst *fi = session->fi; - struct up_peer *peer = session->up_peer; + struct pfcp_entity_peer *peer = session->entity_peer; struct osmo_pfcp_msg *tx;
tx = up_session_init_tx(session, m, OSMO_PFCP_MSGT_SESSION_DEL_RESP); tx->ies.session_del_resp = (struct osmo_pfcp_msg_session_del_resp){ .cause = OSMO_PFCP_CAUSE_REQUEST_ACCEPTED }; - osmo_pfcp_endpoint_tx(peer->up_endpoint->pfcp_ep, tx); + osmo_pfcp_endpoint_tx(peer->node_peer->up_endpoint->pfcp_ep, tx); /* No matter if sending the deletion ACK succeeded or not, discard the session. */ up_session_fsm_state_chg(UP_SESSION_ST_WAIT_USE_COUNT); } @@ -978,7 +979,7 @@ static void up_session_update_id(struct up_session *session) { osmo_fsm_inst_update_id_f_sanitize(session->fi, '-', "%s-0x%" PRIx64, - up_peer_remote_addr_str(session->up_peer), + pfcp_entity_peer_remote_addr_str(session->entity_peer), session->up_seid); LOGPFSML(session->fi, LOGL_DEBUG, "Updated id\n"); } @@ -988,15 +989,15 @@ return cp_seid + up_seid; }
-static struct up_session *up_session_add(struct up_peer *peer, const struct osmo_pfcp_ie_f_seid *cp_f_seid) +struct up_session *up_session_alloc(struct pfcp_entity_peer *entity_peer, const struct osmo_pfcp_ie_f_seid *cp_f_seid) { struct up_session *session; - uint64_t up_seid = up_endpoint_next_up_seid(peer->up_endpoint); + uint64_t up_seid = up_endpoint_next_up_seid(entity_peer->node_peer->up_endpoint);
if (!up_seid) return NULL;
- struct osmo_fsm_inst *fi = osmo_fsm_inst_alloc_child(&up_session_fsm, peer->fi, UP_PEER_EV_SESSION_TERM); + struct osmo_fsm_inst *fi = osmo_fsm_inst_alloc_child(&up_session_fsm, entity_peer->fi, PFCP_ENTITY_PEER_EV_SESSION_TERM); OSMO_ASSERT(fi);
session = talloc(fi, struct up_session); @@ -1005,7 +1006,7 @@
*session = (struct up_session) { .fi = fi, - .up_peer = peer, + .entity_peer = entity_peer, .cp_f_seid = *cp_f_seid, .up_seid = up_seid, .use_count = { @@ -1021,43 +1022,12 @@ LOGPFSML(session->fi, LOGL_INFO, "Allocated new UP-SEID: 0x%" PRIx64 "\n", session->up_seid); up_session_update_id(session);
- hash_add(peer->sessions_by_up_seid, &session->node_by_up_seid, session->up_seid); - hash_add(peer->sessions_by_cp_seid, &session->node_by_cp_seid, session->cp_f_seid.seid); - hash_add(peer->up_endpoint->sessions_by_up_seid, &session->ep_node_by_up_seid, session->up_seid); + hash_add(entity_peer->sessions_by_up_seid, &session->node_by_up_seid, session->up_seid); + hash_add(entity_peer->sessions_by_cp_seid, &session->node_by_cp_seid, session->cp_f_seid.seid); + hash_add(entity_peer->node_peer->up_endpoint->sessions_by_up_seid, &session->ep_node_by_up_seid, session->up_seid); return session; }
-struct up_session *up_session_find_or_add(struct up_peer *peer, const struct osmo_pfcp_ie_f_seid *cp_f_seid) -{ - struct up_session *session; - OSMO_ASSERT(cp_f_seid); - session = up_session_find_by_cp_f_seid(peer, cp_f_seid); - if (session) - return session; - - return up_session_add(peer, cp_f_seid); -} - -struct up_session *up_session_find_by_up_seid(struct up_peer *peer, uint64_t up_seid) -{ - struct up_session *session; - hash_for_each_possible(peer->sessions_by_up_seid, session, node_by_up_seid, up_seid) { - if (up_seid == session->up_seid) - return session; - } - return NULL; -} - -struct up_session *up_session_find_by_cp_f_seid(struct up_peer *peer, const struct osmo_pfcp_ie_f_seid *cp_f_seid) -{ - struct up_session *session; - hash_for_each_possible(peer->sessions_by_cp_seid, session, node_by_cp_seid, cp_f_seid->seid) { - if (osmo_pfcp_ie_f_seid_cmp(&session->cp_f_seid, cp_f_seid) == 0) - return session; - } - return NULL; -} - static bool action_is_forw(const struct osmo_pfcp_ie_apply_action *aa) { return osmo_pfcp_bits_get(aa->bits, OSMO_PFCP_APPLY_ACTION_FORW) @@ -1519,7 +1489,7 @@ return sb.chars_needed; } OSMO_STRBUF_PRINTF(sb, "peer:%s SEID-r:0x%"PRIx64" SEID-l:0x%"PRIx64" state:%s", - up_peer_remote_addr_str(session->up_peer), + pfcp_entity_peer_remote_addr_str(session->entity_peer), session->cp_f_seid.seid, session->up_seid, osmo_fsm_inst_state_name(session->fi)); return sb.chars_needed; diff --git a/src/osmo-upf/upf.c b/src/osmo-upf/upf.c index e442d1c..0c3a364 100644 --- a/src/osmo-upf/upf.c +++ b/src/osmo-upf/upf.c @@ -29,7 +29,6 @@
#include <osmocom/upf/upf.h> #include <osmocom/upf/up_endpoint.h> -#include <osmocom/upf/up_peer.h> #include <osmocom/upf/up_session.h> #include <osmocom/upf/up_gtp_action.h> #include <osmocom/upf/upf_gtp.h> diff --git a/src/osmo-upf/upf_vty.c b/src/osmo-upf/upf_vty.c index 9c5f7f0..cc446b3 100644 --- a/src/osmo-upf/upf_vty.c +++ b/src/osmo-upf/upf_vty.c @@ -31,10 +31,11 @@ #include <osmocom/vty/vty.h> #include <osmocom/vty/command.h>
+#include <osmocom/upf/pfcp_entity_peer.h> +#include <osmocom/upf/pfcp_node_peer.h> #include <osmocom/upf/upf.h> #include <osmocom/upf/upf_gtp.h> #include <osmocom/upf/up_endpoint.h> -#include <osmocom/upf/up_peer.h> #include <osmocom/upf/up_session.h> #include <osmocom/upf/up_gtp_action.h> #include <osmocom/upf/netinst.h> @@ -403,27 +404,31 @@ SHOW_STR "List all sessions' PDR and FAR status\n") { - struct up_peer *peer; + struct pfcp_node_peer *node_peer; int active_count = 0; int inactive_count = 0; - llist_for_each_entry(peer, &g_upf->pfcp.ep->peers, entry) { - struct up_session *session; - int bkt; - hash_for_each(peer->sessions_by_up_seid, bkt, session, node_by_up_seid) { - struct pdr *pdr; - llist_for_each_entry(pdr, &session->pdrs, entry) { - if (!pdr->active) { - vty_out(vty, "%s: inactive: %s%s%s%s", - session->fi->id, pdr_to_str_c(OTC_SELECT, pdr), - pdr->inactive_reason ? ": " : "", - pdr->inactive_reason ? : "", - VTY_NEWLINE); - inactive_count++; - } else { - vty_out(vty, "%s: active: %s%s", - session->fi->id, pdr_to_str_c(OTC_SELECT, pdr), - VTY_NEWLINE); - active_count++; + + llist_for_each_entry(node_peer, &g_upf->pfcp.ep->pfcp_node_peer_list, entry) { + struct pfcp_entity_peer *entity_peer; + llist_for_each_entry(entity_peer, &node_peer->entity_list, entry) { + struct up_session *session; + int bkt; + hash_for_each(entity_peer->sessions_by_up_seid, bkt, session, node_by_up_seid) { + struct pdr *pdr; + llist_for_each_entry(pdr, &session->pdrs, entry) { + if (!pdr->active) { + vty_out(vty, "%s: inactive: %s%s%s%s", + session->fi->id, pdr_to_str_c(OTC_SELECT, pdr), + pdr->inactive_reason ? ": " : "", + pdr->inactive_reason ? : "", + VTY_NEWLINE); + inactive_count++; + } else { + vty_out(vty, "%s: active: %s%s", + session->fi->id, pdr_to_str_c(OTC_SELECT, pdr), + VTY_NEWLINE); + active_count++; + } } } } @@ -437,17 +442,20 @@ SHOW_STR "Active GTP tunnels, both tunend and tunmap\n") { - struct up_peer *peer; + struct pfcp_node_peer *node_peer; int count = 0;
- llist_for_each_entry(peer, &g_upf->pfcp.ep->peers, entry) { - struct up_session *session; - int bkt; - hash_for_each(peer->sessions_by_up_seid, bkt, session, node_by_up_seid) { - struct up_gtp_action *a; - llist_for_each_entry(a, &session->active_gtp_actions, entry) { - vty_out(vty, "%s%s", up_gtp_action_to_str_c(OTC_SELECT, a), VTY_NEWLINE); - count++; + llist_for_each_entry(node_peer, &g_upf->pfcp.ep->pfcp_node_peer_list, entry) { + struct pfcp_entity_peer *entity_peer; + llist_for_each_entry(entity_peer, &node_peer->entity_list, entry) { + struct up_session *session; + int bkt; + hash_for_each(entity_peer->sessions_by_up_seid, bkt, session, node_by_up_seid) { + struct up_gtp_action *a; + llist_for_each_entry(a, &session->active_gtp_actions, entry) { + vty_out(vty, "%s%s", up_gtp_action_to_str_c(OTC_SELECT, a), VTY_NEWLINE); + count++; + } } } } @@ -460,25 +468,28 @@ SHOW_STR "PFCP Session status\n") { - struct up_peer *peer; + struct pfcp_node_peer *node_peer; int inactive_count = 0; int active_count = 0; int fully_active_count = 0;
- llist_for_each_entry(peer, &g_upf->pfcp.ep->peers, entry) { - struct up_session *session; - int bkt; - hash_for_each(peer->sessions_by_up_seid, bkt, session, node_by_up_seid) { - vty_out(vty, "%s %s%s", - up_session_to_str_c(OTC_SELECT, session), - up_session_gtp_status(session), VTY_NEWLINE); - if (up_session_is_active(session)) { - if (up_session_is_fully_active(session, NULL, NULL)) - fully_active_count++; - else - active_count++; - } else { - inactive_count++; + llist_for_each_entry(node_peer, &g_upf->pfcp.ep->pfcp_node_peer_list, entry) { + struct pfcp_entity_peer *entity_peer; + llist_for_each_entry(entity_peer, &node_peer->entity_list, entry) { + struct up_session *session; + int bkt; + hash_for_each(entity_peer->sessions_by_up_seid, bkt, session, node_by_up_seid) { + vty_out(vty, "%s %s%s", + up_session_to_str_c(OTC_SELECT, session), + up_session_gtp_status(session), VTY_NEWLINE); + if (up_session_is_active(session)) { + if (up_session_is_fully_active(session, NULL, NULL)) + fully_active_count++; + else + active_count++; + } else { + inactive_count++; + } } } } diff --git a/tests/unique_ids/unique_ids_test.c b/tests/unique_ids/unique_ids_test.c index 1a9b2b3..6dcc825 100644 --- a/tests/unique_ids/unique_ids_test.c +++ b/tests/unique_ids/unique_ids_test.c @@ -32,10 +32,11 @@
#include <osmocom/pfcp/pfcp_endpoint.h>
+#include <osmocom/upf/pfcp_entity_peer.h> +#include <osmocom/upf/pfcp_node_peer.h> #include <osmocom/upf/upf.h> #include <osmocom/upf/netinst.h> #include <osmocom/upf/up_endpoint.h> -#include <osmocom/upf/up_peer.h> #include <osmocom/upf/up_session.h> #include <osmocom/upf/up_gtp_action.h>
@@ -105,12 +106,48 @@ return &osa; }
-static struct up_peer *have_peer(const char *remote_addr, uint16_t port) +static struct osmo_pfcp_ie_node_id *str2node_id(enum osmo_pfcp_node_id_type type, const char *addr) { - return up_peer_find_or_add(g_upf->pfcp.ep, str2addr(remote_addr, port)); + static struct osmo_pfcp_ie_node_id node_id; + + node_id.type = type; + switch (node_id.type) { + case OSMO_PFCP_NODE_ID_T_IPV4: + case OSMO_PFCP_NODE_ID_T_IPV6: + node_id.ip = *str2addr(addr, 0); + break; + case OSMO_PFCP_NODE_ID_T_FQDN: + OSMO_STRLCPY_ARRAY(node_id.fqdn, addr); + break; + default: + OSMO_ASSERT(0); + break; + } + return &node_id; }
-static struct osmo_pfcp_msg *new_pfcp_msg_for_osmo_upf_rx(struct up_peer *from_peer, enum osmo_pfcp_message_type msg_type) +static struct pfcp_entity_peer *have_pfcp_entity_peer(enum osmo_pfcp_node_id_type type, const char *remote_addr) +{ + struct pfcp_node_peer *node_peer; + struct pfcp_entity_peer *entity_peer; + struct osmo_pfcp_ie_node_id *node_id = str2node_id(type, remote_addr); + struct osmo_sockaddr *osa = str2addr(remote_addr, 0); + + node_peer = up_endpoint_find_pfcp_node_peer(g_upf->pfcp.ep, node_id); + if (!node_peer) { + node_peer = pfcp_node_peer_alloc(g_upf->pfcp.ep, node_id); + OSMO_ASSERT(node_peer); + } + + entity_peer = pfcp_node_peer_find_entity_by_remote_addr(node_peer, osa); + if (!entity_peer) { + entity_peer = pfcp_entity_peer_alloc(node_peer, osa); + OSMO_ASSERT(entity_peer); + } + return entity_peer; +} + +static struct osmo_pfcp_msg *new_pfcp_msg_for_osmo_upf_rx(struct pfcp_entity_peer *from_peer, enum osmo_pfcp_message_type msg_type) { /* pfcp_endpoint discards received messages immediately after dispatching; in this test, allocate them in * OTC_SELECT so they get discarded on the next select_poll(). @@ -122,11 +159,11 @@ return m; }
-static void peer_assoc(struct up_peer *peer) +static void peer_assoc(struct pfcp_entity_peer *peer) { struct osmo_pfcp_msg *m = new_pfcp_msg_for_osmo_upf_rx(peer, OSMO_PFCP_MSGT_ASSOC_SETUP_REQ); m->ies.assoc_setup_req.recovery_time_stamp = 1234; - osmo_fsm_inst_dispatch(peer->fi, UP_PEER_EV_RX_ASSOC_SETUP_REQ, m); + osmo_fsm_inst_dispatch(peer->fi, PFCP_ENTITY_PEER_EV_RX_ASSOC_SETUP_REQ, m); select_poll(); }
@@ -134,7 +171,7 @@ static int next_cp_seid = 0x100;
/* Send a PFCP Session Establishment Request, and return the created session */ -static struct up_session *session_est_tunmap(struct up_peer *peer) +static struct up_session *session_est_tunmap(struct pfcp_entity_peer *peer) { struct osmo_pfcp_msg *m;
@@ -255,10 +292,10 @@ }, };
- osmo_fsm_inst_dispatch(peer->fi, UP_PEER_EV_RX_SESSION_EST_REQ, m); + osmo_fsm_inst_dispatch(peer->fi, PFCP_ENTITY_PEER_EV_RX_SESSION_EST_REQ, m); select_poll();
- return up_session_find_by_up_seid(peer, last_up_seid); + return pfcp_entity_peer_find_up_session_by_up_seid(peer, last_up_seid); }
static void session_del(struct up_session *session) @@ -267,7 +304,7 @@
log_assert(session);
- m = new_pfcp_msg_for_osmo_upf_rx(session->up_peer, OSMO_PFCP_MSGT_SESSION_DEL_REQ); + m = new_pfcp_msg_for_osmo_upf_rx(session->entity_peer, OSMO_PFCP_MSGT_SESSION_DEL_REQ); m->h.seid_present = true; m->h.seid = session->up_seid;
@@ -277,23 +314,26 @@
static void dump_state(void) { - struct up_peer *peer; + struct pfcp_node_peer *node_peer; log("\n state:\n"); - llist_for_each_entry(peer, &g_upf->pfcp.ep->peers, entry) { - struct up_session *session; - int bkt; - log(" | peer %s %s\n", peer->fi->name, osmo_fsm_inst_state_name(peer->fi)); - hash_for_each(peer->sessions_by_up_seid, bkt, session, node_by_up_seid) { - struct up_gtp_action *a; - llist_for_each_entry(a, &session->active_gtp_actions, entry) { - if (a->kind != UP_GTP_U_TUNMAP) - continue; - log(" | session[%s]: UP-SEID 0x%"PRIx64"; chain_id access=%u core=%u;" - " local TEID access=0x%x core=0x%x\n", - osmo_fsm_inst_state_name(session->fi), - session->up_seid, - a->tunmap.access.chain_id, a->tunmap.core.chain_id, - a->tunmap.access.tun.local.teid, a->tunmap.core.tun.local.teid); + llist_for_each_entry(node_peer, &g_upf->pfcp.ep->pfcp_node_peer_list, entry) { + struct pfcp_entity_peer *entity_peer; + llist_for_each_entry(entity_peer, &node_peer->entity_list, entry) { + struct up_session *session; + int bkt; + log(" | peer %s %s\n", entity_peer->fi->name, osmo_fsm_inst_state_name(entity_peer->fi)); + hash_for_each(entity_peer->sessions_by_up_seid, bkt, session, node_by_up_seid) { + struct up_gtp_action *a; + llist_for_each_entry(a, &session->active_gtp_actions, entry) { + if (a->kind != UP_GTP_U_TUNMAP) + continue; + log(" | session[%s]: UP-SEID 0x%"PRIx64"; chain_id access=%u core=%u;" + " local TEID access=0x%x core=0x%x\n", + osmo_fsm_inst_state_name(session->fi), + session->up_seid, + a->tunmap.access.chain_id, a->tunmap.core.chain_id, + a->tunmap.access.tun.local.teid, a->tunmap.core.tun.local.teid); + } } } } @@ -302,7 +342,7 @@
static void test_skip_used_id(void) { - struct up_peer *peer; + struct pfcp_entity_peer *entity_peer; struct up_session *s1; uint64_t s1_up_seid; struct up_session *s2; @@ -313,8 +353,8 @@ setup(__func__);
log("PFCP Associate peer\n"); - peer = have_peer("1.2.3.4", 1234); - peer_assoc(peer); + entity_peer = have_pfcp_entity_peer(OSMO_PFCP_NODE_ID_T_IPV4, "1.2.3.4"); + peer_assoc(entity_peer); dump_state();
/* Make sure to start out all IDs with 1 */ @@ -323,7 +363,7 @@ g_upf->tunmap.next_chain_id_state = 0;
log("set up tunmap, which assigns first UP-SEID 0x1, local-TEID 0x1 and 0x2, chain_ids 1 and 2\n"); - s1 = session_est_tunmap(peer); + s1 = session_est_tunmap(entity_peer); dump_state();
log_assert(s1->up_seid == 1); @@ -342,7 +382,7 @@ g_upf->tunmap.next_chain_id_state = 0;
log("set up second tunmap, should use distinct IDs\n"); - s2 = session_est_tunmap(peer); + s2 = session_est_tunmap(entity_peer); dump_state();
log_assert(s2->up_seid == 2); @@ -359,7 +399,7 @@ s1_up_seid = s1->up_seid; session_del(s1); dump_state(); - log_assert(up_session_find_by_up_seid(peer, s1_up_seid) == NULL); + log_assert(pfcp_entity_peer_find_up_session_by_up_seid(entity_peer, s1_up_seid) == NULL); log("\n");
log("again wrap all ID state back to 1\n"); @@ -368,7 +408,7 @@ g_upf->tunmap.next_chain_id_state = 0;
log("set up third tunmap, should now re-use same IDs as the first session\n"); - s3 = session_est_tunmap(peer); + s3 = session_est_tunmap(entity_peer); dump_state();
log_assert(s3->up_seid == 1); @@ -382,7 +422,7 @@ log("\n");
log("set up 4th tunmap; chain_id state would use 3 and 4, but they are in use, so should assign 5 and 6\n"); - s4 = session_est_tunmap(peer); + s4 = session_est_tunmap(entity_peer); dump_state();
log_assert(s4->up_seid == 3); diff --git a/tests/unique_ids/unique_ids_test.err b/tests/unique_ids/unique_ids_test.err index 7ac7e59..2083dac 100644 --- a/tests/unique_ids/unique_ids_test.err +++ b/tests/unique_ids/unique_ids_test.err @@ -22,32 +22,33 @@ DNFT DEBUG ran nft ruleset, 465 chars: "add chain inet osmo-upf pre { type filter hook prerouting priority -300; policy accept; };\nadd chain inet osmo-upf post { type filter hook postrouting priority 400; policy accept; };\nadd map inet osmo-upf tunmap-pre { typeof ip daddr . @ih,32,32 : verdict;..."
PFCP Associate peer -DPEER DEBUG up_peer{NOT_ASSOCIATED}: Allocated -DPEER DEBUG up_peer(1-2-3-4){NOT_ASSOCIATED}: Updated id -DPEER DEBUG up_peer(1-2-3-4){NOT_ASSOCIATED}: Received Event UP_PEER_EV_RX_ASSOC_SETUP_REQ -DPEER DEBUG up_peer(1-2-3-4){NOT_ASSOCIATED}: State change to ASSOCIATED (no timeout) -DREF INFO up_peer(1-2-3-4){ASSOCIATED}: + msg-tx: now used by 1 (msg-tx) +DPEER DEBUG pfcp_entity_peer{NOT_ASSOCIATED}: Allocated +DPEER DEBUG pfcp_entity_peer(1-2-3-4){NOT_ASSOCIATED}: Updated id +DREF INFO pfcp_node_peer(v4:1.2.3.4): + 1-2-3-4: now used by 1 (1-2-3-4) +DPEER DEBUG pfcp_entity_peer(1-2-3-4){NOT_ASSOCIATED}: Received Event PFCP_ENTITY_PEER_EV_RX_ASSOC_SETUP_REQ +DPEER DEBUG pfcp_entity_peer(1-2-3-4){NOT_ASSOCIATED}: State change to ASSOCIATED (no timeout) +DREF INFO pfcp_entity_peer(1-2-3-4){ASSOCIATED}: + msg-tx: now used by 1 (msg-tx)
[test override] PFCP tx: PFCPv1 ASSOC_SETUP_RESP hdr={seq=0} ies={ 'Node ID'=v4:unsupported family 0 'Cause'=Request accepted (success) 'Recovery Time Stamp'=2208988800 'UP Function Features'=FTUP+BUNDL+RTTL }
-DREF INFO up_peer(1-2-3-4){ASSOCIATED}: - msg-tx: now used by 0 (-) -DPEER DEBUG up_peer(1-2-3-4){ASSOCIATED}: Received Event UP_PEER_EV_USE_COUNT_ZERO -DPEER NOTICE up_peer(1-2-3-4){ASSOCIATED}: Peer associated, Node-Id=v4:unsupported family 0. Local UP features: [FTUP+BUNDL+RTTL]; Peer CP features: [-] +DREF INFO pfcp_entity_peer(1-2-3-4){ASSOCIATED}: - msg-tx: now used by 0 (-) +DPEER DEBUG pfcp_entity_peer(1-2-3-4){ASSOCIATED}: Received Event PFCP_ENTITY_PEER_EV_USE_COUNT_ZERO +DPEER NOTICE pfcp_entity_peer(1-2-3-4){ASSOCIATED}: Peer associated, Node-Id=v4:1.2.3.4. Local UP features: [FTUP+BUNDL+RTTL]; Peer CP features: [-]
state: - | peer up_peer(1-2-3-4) ASSOCIATED + | peer pfcp_entity_peer(1-2-3-4) ASSOCIATED
set up tunmap, which assigns first UP-SEID 0x1, local-TEID 0x1 and 0x2, chain_ids 1 and 2 -DPEER DEBUG up_peer(1-2-3-4){ASSOCIATED}: Received Event UP_PEER_EV_RX_SESSION_EST_REQ +DPEER DEBUG pfcp_entity_peer(1-2-3-4){ASSOCIATED}: Received Event PFCP_ENTITY_PEER_EV_RX_SESSION_EST_REQ DSESSION DEBUG up_session(1-2-3-4){INIT}: Allocated -DSESSION DEBUG up_session(1-2-3-4){INIT}: is child of up_peer(1-2-3-4) +DSESSION DEBUG up_session(1-2-3-4){INIT}: is child of pfcp_entity_peer(1-2-3-4) DSESSION INFO up_session(1-2-3-4){INIT}: Allocated new UP-SEID: 0x1 DSESSION DEBUG up_session(1-2-3-4-0x1){INIT}: Updated id -DREF INFO up_peer(1-2-3-4){ASSOCIATED}: + msg-rx: now used by 1 (msg-rx) +DREF INFO pfcp_entity_peer(1-2-3-4){ASSOCIATED}: + msg-rx: now used by 1 (msg-rx) DREF INFO up_session(1-2-3-4-0x1){INIT}: + msg-rx: now used by 1 (msg-rx) DSESSION DEBUG up_session(1-2-3-4-0x1){INIT}: Received Event UP_SESSION_EV_RX_SESSION_EST_REQ -DREF DEBUG up_peer(1-2-3-4){ASSOCIATED}: + msg-tx: now used by 2 (msg-rx,msg-tx) +DREF DEBUG pfcp_entity_peer(1-2-3-4){ASSOCIATED}: + msg-tx: now used by 2 (msg-rx,msg-tx) DREF DEBUG up_session(1-2-3-4-0x1){INIT}: + msg-tx: now used by 2 (msg-rx,msg-tx) DSESSION INFO up_session(1-2-3-4-0x1){INIT}: Allocated new local F-TEID TEID-0x1,v4:1.1.1.1 DSESSION INFO up_session(1-2-3-4-0x1){INIT}: New PDR-1{src:Core TEID-0x1,v4:1.1.1.1 decaps-GTP_U_UDP_IPV4} --> FAR-1{FORW dst:Access,GTP_U_UDP_IPV4,TEID:0x100,v4:5.6.7.8} @@ -85,16 +86,16 @@ osmo-upf created session 0x1
DREF DEBUG up_session(1-2-3-4-0x1){INIT}: - msg-tx: now used by 1 (msg-rx) -DREF DEBUG up_peer(1-2-3-4){ASSOCIATED}: - msg-tx: now used by 1 (msg-rx) +DREF DEBUG pfcp_entity_peer(1-2-3-4){ASSOCIATED}: - msg-tx: now used by 1 (msg-rx) DSESSION DEBUG up_session(1-2-3-4-0x1){INIT}: State change to ESTABLISHED (no timeout) DSESSION INFO up_session(1-2-3-4-0x1){ESTABLISHED}: Session established: peer:1.2.3.4 SEID-r:0x100 SEID-l:0x1 state:ESTABLISHED PDR-active:2/2 FAR-active:2/2 GTP-active:1 DREF INFO up_session(1-2-3-4-0x1){ESTABLISHED}: - msg-rx: now used by 0 (-) DSESSION DEBUG up_session(1-2-3-4-0x1){ESTABLISHED}: Received Event UP_SESSION_EV_USE_COUNT_ZERO -DREF INFO up_peer(1-2-3-4){ASSOCIATED}: - msg-rx: now used by 0 (-) -DPEER DEBUG up_peer(1-2-3-4){ASSOCIATED}: Received Event UP_PEER_EV_USE_COUNT_ZERO +DREF INFO pfcp_entity_peer(1-2-3-4){ASSOCIATED}: - msg-rx: now used by 0 (-) +DPEER DEBUG pfcp_entity_peer(1-2-3-4){ASSOCIATED}: Received Event PFCP_ENTITY_PEER_EV_USE_COUNT_ZERO
state: - | peer up_peer(1-2-3-4) ASSOCIATED + | peer pfcp_entity_peer(1-2-3-4) ASSOCIATED | session[ESTABLISHED]: UP-SEID 0x1; chain_id access=1 core=2; local TEID access=0x2 core=0x1
assert(s1->up_seid == 1) @@ -107,15 +108,15 @@
simulate wrapping of IDs back to 1 set up second tunmap, should use distinct IDs -DPEER DEBUG up_peer(1-2-3-4){ASSOCIATED}: Received Event UP_PEER_EV_RX_SESSION_EST_REQ +DPEER DEBUG pfcp_entity_peer(1-2-3-4){ASSOCIATED}: Received Event PFCP_ENTITY_PEER_EV_RX_SESSION_EST_REQ DSESSION DEBUG up_session(1-2-3-4){INIT}: Allocated -DSESSION DEBUG up_session(1-2-3-4){INIT}: is child of up_peer(1-2-3-4) +DSESSION DEBUG up_session(1-2-3-4){INIT}: is child of pfcp_entity_peer(1-2-3-4) DSESSION INFO up_session(1-2-3-4){INIT}: Allocated new UP-SEID: 0x2 DSESSION DEBUG up_session(1-2-3-4-0x2){INIT}: Updated id -DREF INFO up_peer(1-2-3-4){ASSOCIATED}: + msg-rx: now used by 1 (msg-rx) +DREF INFO pfcp_entity_peer(1-2-3-4){ASSOCIATED}: + msg-rx: now used by 1 (msg-rx) DREF INFO up_session(1-2-3-4-0x2){INIT}: + msg-rx: now used by 1 (msg-rx) DSESSION DEBUG up_session(1-2-3-4-0x2){INIT}: Received Event UP_SESSION_EV_RX_SESSION_EST_REQ -DREF DEBUG up_peer(1-2-3-4){ASSOCIATED}: + msg-tx: now used by 2 (msg-rx,msg-tx) +DREF DEBUG pfcp_entity_peer(1-2-3-4){ASSOCIATED}: + msg-tx: now used by 2 (msg-rx,msg-tx) DREF DEBUG up_session(1-2-3-4-0x2){INIT}: + msg-tx: now used by 2 (msg-rx,msg-tx) DSESSION INFO up_session(1-2-3-4-0x2){INIT}: Allocated new local F-TEID TEID-0x3,v4:1.1.1.1 DSESSION INFO up_session(1-2-3-4-0x2){INIT}: New PDR-1{src:Core TEID-0x3,v4:1.1.1.1 decaps-GTP_U_UDP_IPV4} --> FAR-1{FORW dst:Access,GTP_U_UDP_IPV4,TEID:0x102,v4:5.6.7.8} @@ -153,16 +154,16 @@ osmo-upf created session 0x2
DREF DEBUG up_session(1-2-3-4-0x2){INIT}: - msg-tx: now used by 1 (msg-rx) -DREF DEBUG up_peer(1-2-3-4){ASSOCIATED}: - msg-tx: now used by 1 (msg-rx) +DREF DEBUG pfcp_entity_peer(1-2-3-4){ASSOCIATED}: - msg-tx: now used by 1 (msg-rx) DSESSION DEBUG up_session(1-2-3-4-0x2){INIT}: State change to ESTABLISHED (no timeout) DSESSION INFO up_session(1-2-3-4-0x2){ESTABLISHED}: Session established: peer:1.2.3.4 SEID-r:0x101 SEID-l:0x2 state:ESTABLISHED PDR-active:2/2 FAR-active:2/2 GTP-active:1 DREF INFO up_session(1-2-3-4-0x2){ESTABLISHED}: - msg-rx: now used by 0 (-) DSESSION DEBUG up_session(1-2-3-4-0x2){ESTABLISHED}: Received Event UP_SESSION_EV_USE_COUNT_ZERO -DREF INFO up_peer(1-2-3-4){ASSOCIATED}: - msg-rx: now used by 0 (-) -DPEER DEBUG up_peer(1-2-3-4){ASSOCIATED}: Received Event UP_PEER_EV_USE_COUNT_ZERO +DREF INFO pfcp_entity_peer(1-2-3-4){ASSOCIATED}: - msg-rx: now used by 0 (-) +DPEER DEBUG pfcp_entity_peer(1-2-3-4){ASSOCIATED}: Received Event PFCP_ENTITY_PEER_EV_USE_COUNT_ZERO
state: - | peer up_peer(1-2-3-4) ASSOCIATED + | peer pfcp_entity_peer(1-2-3-4) ASSOCIATED | session[ESTABLISHED]: UP-SEID 0x1; chain_id access=1 core=2; local TEID access=0x2 core=0x1 | session[ESTABLISHED]: UP-SEID 0x2; chain_id access=3 core=4; local TEID access=0x4 core=0x3
@@ -177,7 +178,7 @@ drop first tunmap (up_session(1-2-3-4-0x1)) assert(session) DSESSION DEBUG up_session(1-2-3-4-0x1){ESTABLISHED}: Received Event UP_SESSION_EV_RX_SESSION_DEL_REQ -DREF INFO up_peer(1-2-3-4){ASSOCIATED}: + msg-tx: now used by 1 (msg-tx) +DREF INFO pfcp_entity_peer(1-2-3-4){ASSOCIATED}: + msg-tx: now used by 1 (msg-tx) DREF INFO up_session(1-2-3-4-0x1){ESTABLISHED}: + msg-tx: now used by 1 (msg-tx)
[test override] PFCP tx: @@ -185,8 +186,8 @@
DREF INFO up_session(1-2-3-4-0x1){ESTABLISHED}: - msg-tx: now used by 0 (-) DSESSION DEBUG up_session(1-2-3-4-0x1){ESTABLISHED}: Received Event UP_SESSION_EV_USE_COUNT_ZERO -DREF INFO up_peer(1-2-3-4){ASSOCIATED}: - msg-tx: now used by 0 (-) -DPEER DEBUG up_peer(1-2-3-4){ASSOCIATED}: Received Event UP_PEER_EV_USE_COUNT_ZERO +DREF INFO pfcp_entity_peer(1-2-3-4){ASSOCIATED}: - msg-tx: now used by 0 (-) +DPEER DEBUG pfcp_entity_peer(1-2-3-4){ASSOCIATED}: Received Event PFCP_ENTITY_PEER_EV_USE_COUNT_ZERO DSESSION INFO up_session(1-2-3-4-0x1){ESTABLISHED}: Session releasing: peer:1.2.3.4 SEID-r:0x100 SEID-l:0x1 state:ESTABLISHED PDR-active:2/2 FAR-active:2/2 GTP-active:1 DNFT INFO Added NFT ruleset to queue: n:1 strlen:381 DNFT INFO Flushing NFT ruleset queue: reached max nr of rules: n:1 strlen:381 (flush count: 3 avg rules per flush: 1) @@ -207,29 +208,29 @@ DSESSION DEBUG up_session(1-2-3-4-0x1){ESTABLISHED}: State change to WAIT_USE_COUNT (no timeout) DSESSION DEBUG up_session(1-2-3-4-0x1){WAIT_USE_COUNT}: GTP actions: 0 previously active; want active: 0 DSESSION DEBUG up_session(1-2-3-4-0x1){WAIT_USE_COUNT}: Terminating (cause = OSMO_FSM_TERM_REGULAR) -DSESSION DEBUG up_session(1-2-3-4-0x1){WAIT_USE_COUNT}: Removing from parent up_peer(1-2-3-4) +DSESSION DEBUG up_session(1-2-3-4-0x1){WAIT_USE_COUNT}: Removing from parent pfcp_entity_peer(1-2-3-4) DSESSION DEBUG up_session(1-2-3-4-0x1){WAIT_USE_COUNT}: GTP actions: 0 previously active; want active: 0 DSESSION DEBUG up_session(1-2-3-4-0x1){WAIT_USE_COUNT}: Freeing instance DSESSION DEBUG up_session(1-2-3-4-0x1){WAIT_USE_COUNT}: Deallocated -DPEER DEBUG up_peer(1-2-3-4){ASSOCIATED}: Received Event UP_PEER_EV_SESSION_TERM +DPEER DEBUG pfcp_entity_peer(1-2-3-4){ASSOCIATED}: Received Event PFCP_ENTITY_PEER_EV_SESSION_TERM
state: - | peer up_peer(1-2-3-4) ASSOCIATED + | peer pfcp_entity_peer(1-2-3-4) ASSOCIATED | session[ESTABLISHED]: UP-SEID 0x2; chain_id access=3 core=4; local TEID access=0x4 core=0x3
-assert(up_session_find_by_up_seid(peer, s1_up_seid) == NULL) +assert(pfcp_entity_peer_find_up_session_by_up_seid(entity_peer, s1_up_seid) == NULL)
again wrap all ID state back to 1 set up third tunmap, should now re-use same IDs as the first session -DPEER DEBUG up_peer(1-2-3-4){ASSOCIATED}: Received Event UP_PEER_EV_RX_SESSION_EST_REQ +DPEER DEBUG pfcp_entity_peer(1-2-3-4){ASSOCIATED}: Received Event PFCP_ENTITY_PEER_EV_RX_SESSION_EST_REQ DSESSION DEBUG up_session(1-2-3-4){INIT}: Allocated -DSESSION DEBUG up_session(1-2-3-4){INIT}: is child of up_peer(1-2-3-4) +DSESSION DEBUG up_session(1-2-3-4){INIT}: is child of pfcp_entity_peer(1-2-3-4) DSESSION INFO up_session(1-2-3-4){INIT}: Allocated new UP-SEID: 0x1 DSESSION DEBUG up_session(1-2-3-4-0x1){INIT}: Updated id -DREF INFO up_peer(1-2-3-4){ASSOCIATED}: + msg-rx: now used by 1 (msg-rx) +DREF INFO pfcp_entity_peer(1-2-3-4){ASSOCIATED}: + msg-rx: now used by 1 (msg-rx) DREF INFO up_session(1-2-3-4-0x1){INIT}: + msg-rx: now used by 1 (msg-rx) DSESSION DEBUG up_session(1-2-3-4-0x1){INIT}: Received Event UP_SESSION_EV_RX_SESSION_EST_REQ -DREF DEBUG up_peer(1-2-3-4){ASSOCIATED}: + msg-tx: now used by 2 (msg-rx,msg-tx) +DREF DEBUG pfcp_entity_peer(1-2-3-4){ASSOCIATED}: + msg-tx: now used by 2 (msg-rx,msg-tx) DREF DEBUG up_session(1-2-3-4-0x1){INIT}: + msg-tx: now used by 2 (msg-rx,msg-tx) DSESSION INFO up_session(1-2-3-4-0x1){INIT}: Allocated new local F-TEID TEID-0x1,v4:1.1.1.1 DSESSION INFO up_session(1-2-3-4-0x1){INIT}: New PDR-1{src:Core TEID-0x1,v4:1.1.1.1 decaps-GTP_U_UDP_IPV4} --> FAR-1{FORW dst:Access,GTP_U_UDP_IPV4,TEID:0x104,v4:5.6.7.8} @@ -267,16 +268,16 @@ osmo-upf created session 0x1
DREF DEBUG up_session(1-2-3-4-0x1){INIT}: - msg-tx: now used by 1 (msg-rx) -DREF DEBUG up_peer(1-2-3-4){ASSOCIATED}: - msg-tx: now used by 1 (msg-rx) +DREF DEBUG pfcp_entity_peer(1-2-3-4){ASSOCIATED}: - msg-tx: now used by 1 (msg-rx) DSESSION DEBUG up_session(1-2-3-4-0x1){INIT}: State change to ESTABLISHED (no timeout) DSESSION INFO up_session(1-2-3-4-0x1){ESTABLISHED}: Session established: peer:1.2.3.4 SEID-r:0x102 SEID-l:0x1 state:ESTABLISHED PDR-active:2/2 FAR-active:2/2 GTP-active:1 DREF INFO up_session(1-2-3-4-0x1){ESTABLISHED}: - msg-rx: now used by 0 (-) DSESSION DEBUG up_session(1-2-3-4-0x1){ESTABLISHED}: Received Event UP_SESSION_EV_USE_COUNT_ZERO -DREF INFO up_peer(1-2-3-4){ASSOCIATED}: - msg-rx: now used by 0 (-) -DPEER DEBUG up_peer(1-2-3-4){ASSOCIATED}: Received Event UP_PEER_EV_USE_COUNT_ZERO +DREF INFO pfcp_entity_peer(1-2-3-4){ASSOCIATED}: - msg-rx: now used by 0 (-) +DPEER DEBUG pfcp_entity_peer(1-2-3-4){ASSOCIATED}: Received Event PFCP_ENTITY_PEER_EV_USE_COUNT_ZERO
state: - | peer up_peer(1-2-3-4) ASSOCIATED + | peer pfcp_entity_peer(1-2-3-4) ASSOCIATED | session[ESTABLISHED]: UP-SEID 0x1; chain_id access=1 core=2; local TEID access=0x2 core=0x1 | session[ESTABLISHED]: UP-SEID 0x2; chain_id access=3 core=4; local TEID access=0x4 core=0x3
@@ -289,15 +290,15 @@ assert(a->tunmap.core.chain_id == 2)
set up 4th tunmap; chain_id state would use 3 and 4, but they are in use, so should assign 5 and 6 -DPEER DEBUG up_peer(1-2-3-4){ASSOCIATED}: Received Event UP_PEER_EV_RX_SESSION_EST_REQ +DPEER DEBUG pfcp_entity_peer(1-2-3-4){ASSOCIATED}: Received Event PFCP_ENTITY_PEER_EV_RX_SESSION_EST_REQ DSESSION DEBUG up_session(1-2-3-4){INIT}: Allocated -DSESSION DEBUG up_session(1-2-3-4){INIT}: is child of up_peer(1-2-3-4) +DSESSION DEBUG up_session(1-2-3-4){INIT}: is child of pfcp_entity_peer(1-2-3-4) DSESSION INFO up_session(1-2-3-4){INIT}: Allocated new UP-SEID: 0x3 DSESSION DEBUG up_session(1-2-3-4-0x3){INIT}: Updated id -DREF INFO up_peer(1-2-3-4){ASSOCIATED}: + msg-rx: now used by 1 (msg-rx) +DREF INFO pfcp_entity_peer(1-2-3-4){ASSOCIATED}: + msg-rx: now used by 1 (msg-rx) DREF INFO up_session(1-2-3-4-0x3){INIT}: + msg-rx: now used by 1 (msg-rx) DSESSION DEBUG up_session(1-2-3-4-0x3){INIT}: Received Event UP_SESSION_EV_RX_SESSION_EST_REQ -DREF DEBUG up_peer(1-2-3-4){ASSOCIATED}: + msg-tx: now used by 2 (msg-rx,msg-tx) +DREF DEBUG pfcp_entity_peer(1-2-3-4){ASSOCIATED}: + msg-tx: now used by 2 (msg-rx,msg-tx) DREF DEBUG up_session(1-2-3-4-0x3){INIT}: + msg-tx: now used by 2 (msg-rx,msg-tx) DSESSION INFO up_session(1-2-3-4-0x3){INIT}: Allocated new local F-TEID TEID-0x5,v4:1.1.1.1 DSESSION INFO up_session(1-2-3-4-0x3){INIT}: New PDR-1{src:Core TEID-0x5,v4:1.1.1.1 decaps-GTP_U_UDP_IPV4} --> FAR-1{FORW dst:Access,GTP_U_UDP_IPV4,TEID:0x106,v4:5.6.7.8} @@ -335,16 +336,16 @@ osmo-upf created session 0x3
DREF DEBUG up_session(1-2-3-4-0x3){INIT}: - msg-tx: now used by 1 (msg-rx) -DREF DEBUG up_peer(1-2-3-4){ASSOCIATED}: - msg-tx: now used by 1 (msg-rx) +DREF DEBUG pfcp_entity_peer(1-2-3-4){ASSOCIATED}: - msg-tx: now used by 1 (msg-rx) DSESSION DEBUG up_session(1-2-3-4-0x3){INIT}: State change to ESTABLISHED (no timeout) DSESSION INFO up_session(1-2-3-4-0x3){ESTABLISHED}: Session established: peer:1.2.3.4 SEID-r:0x103 SEID-l:0x3 state:ESTABLISHED PDR-active:2/2 FAR-active:2/2 GTP-active:1 DREF INFO up_session(1-2-3-4-0x3){ESTABLISHED}: - msg-rx: now used by 0 (-) DSESSION DEBUG up_session(1-2-3-4-0x3){ESTABLISHED}: Received Event UP_SESSION_EV_USE_COUNT_ZERO -DREF INFO up_peer(1-2-3-4){ASSOCIATED}: - msg-rx: now used by 0 (-) -DPEER DEBUG up_peer(1-2-3-4){ASSOCIATED}: Received Event UP_PEER_EV_USE_COUNT_ZERO +DREF INFO pfcp_entity_peer(1-2-3-4){ASSOCIATED}: - msg-rx: now used by 0 (-) +DPEER DEBUG pfcp_entity_peer(1-2-3-4){ASSOCIATED}: Received Event PFCP_ENTITY_PEER_EV_USE_COUNT_ZERO
state: - | peer up_peer(1-2-3-4) ASSOCIATED + | peer pfcp_entity_peer(1-2-3-4) ASSOCIATED | session[ESTABLISHED]: UP-SEID 0x3; chain_id access=5 core=6; local TEID access=0x6 core=0x5 | session[ESTABLISHED]: UP-SEID 0x1; chain_id access=1 core=2; local TEID access=0x2 core=0x1 | session[ESTABLISHED]: UP-SEID 0x2; chain_id access=3 core=4; local TEID access=0x4 core=0x3 @@ -357,9 +358,10 @@ assert(a->tunmap.access.chain_id == 5) assert(a->tunmap.core.chain_id == 6)
-DPEER DEBUG up_peer(1-2-3-4){ASSOCIATED}: Terminating (cause = OSMO_FSM_TERM_REGULAR) +DGTP NOTICE pfcp_node_peer(v4:1.2.3.4): removed +DPEER DEBUG pfcp_entity_peer(1-2-3-4){ASSOCIATED}: Terminating (cause = OSMO_FSM_TERM_REGULAR) DSESSION DEBUG up_session(1-2-3-4-0x3){ESTABLISHED}: Terminating (cause = OSMO_FSM_TERM_PARENT) -DSESSION DEBUG up_session(1-2-3-4-0x3){ESTABLISHED}: Removing from parent up_peer(1-2-3-4) +DSESSION DEBUG up_session(1-2-3-4-0x3){ESTABLISHED}: Removing from parent pfcp_entity_peer(1-2-3-4) DSESSION DEBUG up_session(1-2-3-4-0x3){ESTABLISHED}: GTP actions: 1 previously active; want active: 0 DSESSION DEBUG up_session(1-2-3-4-0x3){ESTABLISHED}: active: GTP:tunmap GTP-access-r:5.6.7.8 TEID-access-r:0x106 GTP-access-l:1.1.1.1 TEID-access-l:0x6 GTP-core-r:13.14.15.16 TEID-core-r:0x107 GTP-core-l:1.1.1.1 TEID-core-l:0x5 PFCP-peer:1.2.3.4 SEID-l:0x3 PDR-access:2 PDR-core:1 DSESSION DEBUG up_session(1-2-3-4-0x3){ESTABLISHED}: disabling: GTP:tunmap GTP-access-r:5.6.7.8 TEID-access-r:0x106 GTP-access-l:1.1.1.1 TEID-access-l:0x6 GTP-core-r:13.14.15.16 TEID-core-r:0x107 GTP-core-l:1.1.1.1 TEID-core-l:0x5 PFCP-peer:1.2.3.4 SEID-l:0x3 PDR-access:2 PDR-core:1 @@ -382,7 +384,7 @@ DSESSION DEBUG up_session(1-2-3-4-0x3){ESTABLISHED}: Freeing instance DSESSION DEBUG up_session(1-2-3-4-0x3){ESTABLISHED}: Deallocated DSESSION DEBUG up_session(1-2-3-4-0x1){ESTABLISHED}: Terminating (cause = OSMO_FSM_TERM_PARENT) -DSESSION DEBUG up_session(1-2-3-4-0x1){ESTABLISHED}: Removing from parent up_peer(1-2-3-4) +DSESSION DEBUG up_session(1-2-3-4-0x1){ESTABLISHED}: Removing from parent pfcp_entity_peer(1-2-3-4) DSESSION DEBUG up_session(1-2-3-4-0x1){ESTABLISHED}: GTP actions: 1 previously active; want active: 0 DSESSION DEBUG up_session(1-2-3-4-0x1){ESTABLISHED}: active: GTP:tunmap GTP-access-r:5.6.7.8 TEID-access-r:0x104 GTP-access-l:1.1.1.1 TEID-access-l:0x2 GTP-core-r:13.14.15.16 TEID-core-r:0x105 GTP-core-l:1.1.1.1 TEID-core-l:0x1 PFCP-peer:1.2.3.4 SEID-l:0x1 PDR-access:2 PDR-core:1 DSESSION DEBUG up_session(1-2-3-4-0x1){ESTABLISHED}: disabling: GTP:tunmap GTP-access-r:5.6.7.8 TEID-access-r:0x104 GTP-access-l:1.1.1.1 TEID-access-l:0x2 GTP-core-r:13.14.15.16 TEID-core-r:0x105 GTP-core-l:1.1.1.1 TEID-core-l:0x1 PFCP-peer:1.2.3.4 SEID-l:0x1 PDR-access:2 PDR-core:1 @@ -405,7 +407,7 @@ DSESSION DEBUG up_session(1-2-3-4-0x1){ESTABLISHED}: Freeing instance DSESSION DEBUG up_session(1-2-3-4-0x1){ESTABLISHED}: Deallocated DSESSION DEBUG up_session(1-2-3-4-0x2){ESTABLISHED}: Terminating (cause = OSMO_FSM_TERM_PARENT) -DSESSION DEBUG up_session(1-2-3-4-0x2){ESTABLISHED}: Removing from parent up_peer(1-2-3-4) +DSESSION DEBUG up_session(1-2-3-4-0x2){ESTABLISHED}: Removing from parent pfcp_entity_peer(1-2-3-4) DSESSION DEBUG up_session(1-2-3-4-0x2){ESTABLISHED}: GTP actions: 1 previously active; want active: 0 DSESSION DEBUG up_session(1-2-3-4-0x2){ESTABLISHED}: active: GTP:tunmap GTP-access-r:5.6.7.8 TEID-access-r:0x102 GTP-access-l:1.1.1.1 TEID-access-l:0x4 GTP-core-r:13.14.15.16 TEID-core-r:0x103 GTP-core-l:1.1.1.1 TEID-core-l:0x3 PFCP-peer:1.2.3.4 SEID-l:0x2 PDR-access:2 PDR-core:1 DSESSION DEBUG up_session(1-2-3-4-0x2){ESTABLISHED}: disabling: GTP:tunmap GTP-access-r:5.6.7.8 TEID-access-r:0x102 GTP-access-l:1.1.1.1 TEID-access-l:0x4 GTP-core-r:13.14.15.16 TEID-core-r:0x103 GTP-core-l:1.1.1.1 TEID-core-l:0x3 PFCP-peer:1.2.3.4 SEID-l:0x2 PDR-access:2 PDR-core:1 @@ -427,9 +429,9 @@ DGTP INFO GTP:tunmap GTP-access-r:5.6.7.8 TEID-access-r:0x102 GTP-access-l:1.1.1.1 TEID-access-l:0x4 GTP-core-r:13.14.15.16 TEID-core-r:0x103 GTP-core-l:1.1.1.1 TEID-core-l:0x3 PFCP-peer:1.2.3.4 SEID-l:0x2 PDR-access:2 PDR-core:1: Disabled tunmap, nft chain IDs: access--3-> <-4--core DSESSION DEBUG up_session(1-2-3-4-0x2){ESTABLISHED}: Freeing instance DSESSION DEBUG up_session(1-2-3-4-0x2){ESTABLISHED}: Deallocated -DPEER NOTICE up_peer(1-2-3-4){ASSOCIATED}: Peer removed -DPEER DEBUG up_peer(1-2-3-4){ASSOCIATED}: Freeing instance -DPEER DEBUG up_peer(1-2-3-4){ASSOCIATED}: Deallocated +DPEER NOTICE pfcp_entity_peer(1-2-3-4){ASSOCIATED}: Peer removed +DPEER DEBUG pfcp_entity_peer(1-2-3-4){ASSOCIATED}: Freeing instance +DPEER DEBUG pfcp_entity_peer(1-2-3-4){ASSOCIATED}: Deallocated [test override] nft_ctx_free() assert(ctx == fake_nft_ctx)