/* * (C) 2021-2025 by sysmocom - s.f.m.c. GmbH * All Rights Reserved. * * Author: Neels Janosch Hofmeyr * * 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 . * */ #include #include #include #include #include #include #include #include #include #include #include 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); }