add generic PFCP CP peer implementation
Will be used by osmo-hnbgw, our first PFCP Control Plane entity. The implementation is generic enough that it can be re-used by other CP entities. Related: SYS#5895 Change-Id: If8c5f69f596ea6ba8bd1723f4dc57b91d3799795
This commit is contained in:
parent
3b8fc0d694
commit
6b458fa060
|
@ -5,6 +5,7 @@ pfcp_HEADERS = \
|
|||
pfcp_msg.h \
|
||||
pfcp_proto.h \
|
||||
pfcp_strs.h \
|
||||
pfcp_cp_peer.h \
|
||||
$(NULL)
|
||||
|
||||
pfcpdir = $(includedir)/osmocom/pfcp
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* (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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <osmocom/core/socket.h>
|
||||
#include <osmocom/core/use_count.h>
|
||||
#include <osmocom/pfcp/pfcp_proto.h>
|
||||
|
||||
struct osmo_fsm_inst;
|
||||
struct osmo_pfcp_endpoint;
|
||||
struct osmo_pfcp_cp_peer;
|
||||
|
||||
typedef void (*osmo_pfcp_cp_peer_assoc_cb)(struct osmo_pfcp_cp_peer *cp_peer, bool associated);
|
||||
|
||||
struct osmo_pfcp_cp_peer {
|
||||
struct osmo_fsm_inst *fi;
|
||||
struct osmo_pfcp_endpoint *ep;
|
||||
struct osmo_sockaddr remote_addr;
|
||||
uint64_t next_seid_state;
|
||||
|
||||
/* If non-NULL, called whenever the peer completes a PFCP Association, and when it loses association.
|
||||
* Argument associated == true means the peer has just associated;
|
||||
* associated == false means the association has been lost. */
|
||||
osmo_pfcp_cp_peer_assoc_cb assoc_cb;
|
||||
/* Application private data for assoc_cb, in case ep->priv does not suffice. */
|
||||
void *priv;
|
||||
|
||||
struct osmo_use_count use_count;
|
||||
struct osmo_use_count_entry use_count_buf[128];
|
||||
};
|
||||
|
||||
struct osmo_pfcp_cp_peer *osmo_pfcp_cp_peer_alloc(void *ctx,
|
||||
struct osmo_pfcp_endpoint *ep,
|
||||
const struct osmo_sockaddr *remote_addr);
|
||||
int osmo_pfcp_cp_peer_associate(struct osmo_pfcp_cp_peer *cp_peer);
|
||||
bool osmo_pfcp_cp_peer_is_associated(const struct osmo_pfcp_cp_peer *cp_peer);
|
||||
struct osmo_pfcp_msg *osmo_pfcp_cp_peer_new_msg_tx(struct osmo_pfcp_cp_peer *cp_peer,
|
||||
enum osmo_pfcp_message_type msg_type);
|
||||
void osmo_pfcp_cp_peer_set_msg_ctx(struct osmo_pfcp_cp_peer *cp_peer, struct osmo_pfcp_msg *m);
|
|
@ -28,6 +28,7 @@ libosmo_pfcp_la_SOURCES = \
|
|||
pfcp_ies_custom.c \
|
||||
pfcp_msg.c \
|
||||
pfcp_strs.c \
|
||||
pfcp_cp_peer.c \
|
||||
\
|
||||
pfcp_ies_auto.c \
|
||||
$(NULL)
|
||||
|
|
|
@ -0,0 +1,404 @@
|
|||
/*
|
||||
* (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/utils.h>
|
||||
#include <osmocom/core/fsm.h>
|
||||
#include <osmocom/core/tdef.h>
|
||||
|
||||
#include <osmocom/pfcp/pfcp_endpoint.h>
|
||||
#include <osmocom/pfcp/pfcp_cp_peer.h>
|
||||
|
||||
#define LOG_CP_PEER(CP_PEER, LOGLEVEL, FMT, ARGS...) \
|
||||
LOGPFSML((CP_PEER)->fi, LOGLEVEL, FMT, ##ARGS)
|
||||
|
||||
enum pfcp_cp_peer_fsm_state {
|
||||
PFCP_CP_PEER_ST_DISABLED,
|
||||
PFCP_CP_PEER_ST_WAIT_ASSOC_SETUP_RESP,
|
||||
PFCP_CP_PEER_ST_WAIT_RETRY,
|
||||
PFCP_CP_PEER_ST_ASSOCIATED,
|
||||
PFCP_CP_PEER_ST_GRACEFUL_RELEASE,
|
||||
PFCP_CP_PEER_ST_WAIT_USE_COUNT,
|
||||
};
|
||||
|
||||
enum pfcp_cp_peer_fsm_event {
|
||||
PFCP_CP_PEER_EV_RX_ASSOC_SETUP_RESP,
|
||||
PFCP_CP_PEER_EV_RX_ASSOC_UPDATE_REQ,
|
||||
PFCP_CP_PEER_EV_USE_COUNT_ZERO,
|
||||
};
|
||||
|
||||
static const struct value_string pfcp_cp_peer_fsm_event_names[] = {
|
||||
OSMO_VALUE_STRING(PFCP_CP_PEER_EV_RX_ASSOC_SETUP_RESP),
|
||||
OSMO_VALUE_STRING(PFCP_CP_PEER_EV_RX_ASSOC_UPDATE_REQ),
|
||||
OSMO_VALUE_STRING(PFCP_CP_PEER_EV_USE_COUNT_ZERO),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct osmo_fsm pfcp_cp_peer_fsm;
|
||||
|
||||
static const struct osmo_tdef_state_timeout pfcp_cp_peer_fsm_timeouts[32] = {
|
||||
[PFCP_CP_PEER_ST_WAIT_RETRY] = { .T = -26 },
|
||||
/* PFCP_CP_PEER_ST_WAIT_ASSOC_SETUP_RESP is terminated by the on_pfcp_assoc_resp() callback */
|
||||
[PFCP_CP_PEER_ST_GRACEFUL_RELEASE] = { .T = -21 },
|
||||
};
|
||||
|
||||
/* Transition to a state, using the T timer defined in pfcp_cp_peer_fsm_timeouts.
|
||||
* Assumes local variable fi exists. */
|
||||
#define osmo_pfcp_cp_peer_fsm_state_chg(state) \
|
||||
osmo_tdef_fsm_inst_state_chg(fi, state, \
|
||||
pfcp_cp_peer_fsm_timeouts, \
|
||||
osmo_pfcp_tdefs, \
|
||||
5)
|
||||
|
||||
static int pfcp_cp_peer_use_cb(struct osmo_use_count_entry *e, int32_t old_use_count, const char *file, int line)
|
||||
{
|
||||
struct osmo_pfcp_cp_peer *cp_peer = e->use_count->talloc_object;
|
||||
|
||||
if (!e->use)
|
||||
return -EINVAL;
|
||||
|
||||
LOGPFSMSLSRC(cp_peer->fi, DLPFCP, LOGL_DEBUG, file, line,
|
||||
"%s %s: now used by %s\n",
|
||||
e->count > old_use_count ? "+" : "-", e->use,
|
||||
osmo_use_count_to_str_c(OTC_SELECT, &cp_peer->use_count));
|
||||
|
||||
if (e->count < 0)
|
||||
return -ERANGE;
|
||||
|
||||
if (osmo_use_count_total(&cp_peer->use_count) == 0)
|
||||
osmo_fsm_inst_dispatch(cp_peer->fi, PFCP_CP_PEER_EV_USE_COUNT_ZERO, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate PFCP CP peer FSM and start sending PFCP Association Setup Request messages to remote_addr, using endpoint
|
||||
* ep. As soon as a successful response is received, change to state PFCP_CP_PEER_ST_ASSOCIATED.
|
||||
*/
|
||||
struct osmo_pfcp_cp_peer *osmo_pfcp_cp_peer_alloc(void *ctx,
|
||||
struct osmo_pfcp_endpoint *ep,
|
||||
const struct osmo_sockaddr *remote_addr)
|
||||
{
|
||||
struct osmo_pfcp_cp_peer *cp_peer;
|
||||
struct osmo_fsm_inst *fi = osmo_fsm_inst_alloc(&pfcp_cp_peer_fsm, ctx, NULL, LOGL_DEBUG, NULL);
|
||||
OSMO_ASSERT(fi);
|
||||
|
||||
cp_peer = talloc(fi, struct osmo_pfcp_cp_peer);
|
||||
OSMO_ASSERT(cp_peer);
|
||||
fi->priv = cp_peer;
|
||||
*cp_peer = (struct osmo_pfcp_cp_peer){
|
||||
.fi = fi,
|
||||
.ep = ep,
|
||||
.remote_addr = *remote_addr,
|
||||
.use_count = {
|
||||
.talloc_object = cp_peer,
|
||||
.use_cb = pfcp_cp_peer_use_cb,
|
||||
},
|
||||
};
|
||||
osmo_use_count_make_static_entries(&cp_peer->use_count, cp_peer->use_count_buf, ARRAY_SIZE(cp_peer->use_count_buf));
|
||||
|
||||
osmo_fsm_inst_update_id_f_sanitize(fi, '-', osmo_sockaddr_to_str_c(OTC_SELECT, &cp_peer->remote_addr));
|
||||
return cp_peer;
|
||||
}
|
||||
|
||||
int osmo_pfcp_cp_peer_associate(struct osmo_pfcp_cp_peer *cp_peer)
|
||||
{
|
||||
struct osmo_fsm_inst *fi = cp_peer->fi;
|
||||
|
||||
switch (fi->state) {
|
||||
case PFCP_CP_PEER_ST_DISABLED:
|
||||
case PFCP_CP_PEER_ST_WAIT_RETRY:
|
||||
/* Idling. Send Association Setup Request now. */
|
||||
return osmo_pfcp_cp_peer_fsm_state_chg(PFCP_CP_PEER_ST_WAIT_ASSOC_SETUP_RESP);
|
||||
default:
|
||||
/* Already associated, or busy associating. */
|
||||
return 0;
|
||||
case PFCP_CP_PEER_ST_WAIT_USE_COUNT:
|
||||
/* Already asked to deallocate. */
|
||||
return -ENOLINK;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pfcp_cp_peer_fsm_timer_cb(struct osmo_fsm_inst *fi)
|
||||
{
|
||||
switch (fi->state) {
|
||||
|
||||
case PFCP_CP_PEER_ST_WAIT_RETRY:
|
||||
osmo_pfcp_cp_peer_fsm_state_chg(PFCP_CP_PEER_ST_WAIT_ASSOC_SETUP_RESP);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int on_pfcp_assoc_resp(struct osmo_pfcp_msg *req, struct osmo_pfcp_msg *rx_resp, const char *errmsg);
|
||||
|
||||
/* Send PFCP Association Setup Request */
|
||||
static void pfcp_cp_peer_wait_assoc_setup_resp_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct osmo_pfcp_cp_peer *cp_peer = fi->priv;
|
||||
struct osmo_pfcp_msg *m;
|
||||
|
||||
m = osmo_pfcp_cp_peer_new_msg_tx(cp_peer, OSMO_PFCP_MSGT_ASSOC_SETUP_REQ);
|
||||
m->ies.assoc_setup_req.recovery_time_stamp = cp_peer->ep->recovery_time_stamp;
|
||||
|
||||
m->ies.assoc_setup_req.cp_function_features_present = true;
|
||||
osmo_pfcp_bits_set(m->ies.assoc_setup_req.cp_function_features.bits, OSMO_PFCP_CP_FEAT_BUNDL, true);
|
||||
|
||||
m->ctx.resp_cb = on_pfcp_assoc_resp;
|
||||
|
||||
LOG_CP_PEER(cp_peer, LOGL_NOTICE, "Associating with %s...\n",
|
||||
osmo_sockaddr_to_str_c(OTC_SELECT, &cp_peer->remote_addr));
|
||||
|
||||
if (osmo_pfcp_endpoint_tx(cp_peer->ep, m)) {
|
||||
LOG_CP_PEER(cp_peer, LOGL_ERROR, "Failed to transmit PFCP Association Setup Request to UPF at %s\n",
|
||||
osmo_sockaddr_to_str_c(OTC_SELECT, &cp_peer->remote_addr));
|
||||
osmo_pfcp_cp_peer_fsm_state_chg(PFCP_CP_PEER_ST_WAIT_RETRY);
|
||||
}
|
||||
}
|
||||
|
||||
static int on_pfcp_assoc_resp(struct osmo_pfcp_msg *req, struct osmo_pfcp_msg *rx_resp, const char *errmsg)
|
||||
{
|
||||
struct osmo_fsm_inst *fi = req->ctx.peer_fi;
|
||||
struct osmo_pfcp_cp_peer *cp_peer = fi->priv;
|
||||
enum osmo_pfcp_cause *cause;
|
||||
|
||||
if (!rx_resp) {
|
||||
LOG_CP_PEER(cp_peer, LOGL_ERROR, "Error: PFCP Association Setup Response: %s\n",
|
||||
errmsg ? : "no response received");
|
||||
goto assoc_failed;
|
||||
}
|
||||
|
||||
cause = osmo_pfcp_msg_cause(rx_resp);
|
||||
if (!cause) {
|
||||
LOG_CP_PEER(cp_peer, LOGL_ERROR, "Invalid PFCP Association Setup Response: no Cause value\n");
|
||||
goto assoc_failed;
|
||||
}
|
||||
if (*cause != OSMO_PFCP_CAUSE_REQUEST_ACCEPTED) {
|
||||
LOG_CP_PEER(cp_peer, LOGL_ERROR, "UPF rejected PFCP Association Setup Request with Cause: %s\n",
|
||||
osmo_pfcp_cause_str(*cause));
|
||||
goto assoc_failed;
|
||||
}
|
||||
|
||||
osmo_fsm_inst_dispatch(fi, PFCP_CP_PEER_EV_RX_ASSOC_SETUP_RESP, rx_resp);
|
||||
return 0;
|
||||
|
||||
assoc_failed:
|
||||
osmo_pfcp_cp_peer_fsm_state_chg(PFCP_CP_PEER_ST_WAIT_RETRY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pfcp_cp_peer_wait_assoc_setup_resp_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
switch (event) {
|
||||
|
||||
case PFCP_CP_PEER_EV_RX_ASSOC_SETUP_RESP:
|
||||
osmo_pfcp_cp_peer_fsm_state_chg(PFCP_CP_PEER_ST_ASSOCIATED);
|
||||
break;
|
||||
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
static void pfcp_cp_peer_associated_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct osmo_pfcp_cp_peer *cp_peer = fi->priv;
|
||||
LOG_CP_PEER(cp_peer, LOGL_NOTICE, "Associated with UPF %s\n",
|
||||
osmo_sockaddr_to_str_c(OTC_SELECT, &cp_peer->remote_addr));
|
||||
if (cp_peer->assoc_cb)
|
||||
cp_peer->assoc_cb(cp_peer, true);
|
||||
}
|
||||
|
||||
static void pfcp_cp_peer_associated_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct osmo_pfcp_cp_peer *cp_peer = fi->priv;
|
||||
|
||||
switch (event) {
|
||||
|
||||
case PFCP_CP_PEER_EV_RX_ASSOC_UPDATE_REQ:
|
||||
LOG_CP_PEER(cp_peer, LOGL_ERROR, "PFCP Association Update Request is not implemented\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
static void pfcp_cp_peer_associated_onleave(struct osmo_fsm_inst *fi, uint32_t next_state)
|
||||
{
|
||||
struct osmo_pfcp_cp_peer *cp_peer = fi->priv;
|
||||
LOG_CP_PEER(cp_peer, LOGL_NOTICE, "Disassociating from UPF %s\n",
|
||||
osmo_sockaddr_to_str_c(OTC_SELECT, &cp_peer->remote_addr));
|
||||
if (cp_peer->assoc_cb)
|
||||
cp_peer->assoc_cb(cp_peer, false);
|
||||
}
|
||||
|
||||
static void pfcp_cp_peer_graceful_release_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct osmo_pfcp_cp_peer *cp_peer = fi->priv;
|
||||
LOG_CP_PEER(cp_peer, LOGL_ERROR, "PFCP graceful release is not implemented\n");
|
||||
}
|
||||
|
||||
static void pfcp_cp_peer_graceful_release_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct osmo_pfcp_cp_peer *cp_peer = fi->priv;
|
||||
LOG_CP_PEER(cp_peer, LOGL_ERROR, "PFCP graceful release is not implemented\n");
|
||||
}
|
||||
|
||||
static void pfcp_cp_peer_wait_use_count_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct osmo_pfcp_cp_peer *cp_peer = fi->priv;
|
||||
if (!osmo_use_count_total(&cp_peer->use_count))
|
||||
osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
|
||||
}
|
||||
|
||||
static void pfcp_cp_peer_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
switch (event) {
|
||||
case PFCP_CP_PEER_EV_USE_COUNT_ZERO:
|
||||
switch (fi->state) {
|
||||
default:
|
||||
/* still busy, ignore. */
|
||||
return;
|
||||
case PFCP_CP_PEER_ST_WAIT_USE_COUNT:
|
||||
/* Waiting for deallocation; now there are no more users, deallocate. */
|
||||
osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
#define S(x) (1 << (x))
|
||||
|
||||
static const struct osmo_fsm_state pfcp_cp_peer_fsm_states[] = {
|
||||
[PFCP_CP_PEER_ST_DISABLED] = {
|
||||
.name = "disabled",
|
||||
.out_state_mask = 0
|
||||
| S(PFCP_CP_PEER_ST_WAIT_ASSOC_SETUP_RESP)
|
||||
| S(PFCP_CP_PEER_ST_WAIT_USE_COUNT)
|
||||
,
|
||||
},
|
||||
[PFCP_CP_PEER_ST_WAIT_ASSOC_SETUP_RESP] = {
|
||||
.name = "wait_assoc_setup_resp",
|
||||
.in_event_mask = 0
|
||||
| S(PFCP_CP_PEER_EV_RX_ASSOC_SETUP_RESP)
|
||||
,
|
||||
.out_state_mask = 0
|
||||
| S(PFCP_CP_PEER_ST_ASSOCIATED)
|
||||
| S(PFCP_CP_PEER_ST_WAIT_RETRY)
|
||||
| S(PFCP_CP_PEER_ST_WAIT_USE_COUNT)
|
||||
,
|
||||
.onenter = pfcp_cp_peer_wait_assoc_setup_resp_onenter,
|
||||
.action = pfcp_cp_peer_wait_assoc_setup_resp_action,
|
||||
},
|
||||
[PFCP_CP_PEER_ST_WAIT_RETRY] = {
|
||||
.name = "wait_retry",
|
||||
.out_state_mask = 0
|
||||
| S(PFCP_CP_PEER_ST_WAIT_ASSOC_SETUP_RESP)
|
||||
| S(PFCP_CP_PEER_ST_WAIT_USE_COUNT)
|
||||
,
|
||||
},
|
||||
[PFCP_CP_PEER_ST_ASSOCIATED] = {
|
||||
.name = "associated",
|
||||
.in_event_mask = 0
|
||||
| S(PFCP_CP_PEER_EV_RX_ASSOC_UPDATE_REQ)
|
||||
,
|
||||
.out_state_mask = 0
|
||||
| S(PFCP_CP_PEER_ST_WAIT_ASSOC_SETUP_RESP)
|
||||
| S(PFCP_CP_PEER_ST_GRACEFUL_RELEASE)
|
||||
| S(PFCP_CP_PEER_ST_WAIT_USE_COUNT)
|
||||
,
|
||||
.onenter = pfcp_cp_peer_associated_onenter,
|
||||
.action = pfcp_cp_peer_associated_action,
|
||||
.onleave = pfcp_cp_peer_associated_onleave,
|
||||
},
|
||||
[PFCP_CP_PEER_ST_GRACEFUL_RELEASE] = {
|
||||
.name = "graceful_release",
|
||||
.in_event_mask = 0
|
||||
,
|
||||
.out_state_mask = 0
|
||||
| S(PFCP_CP_PEER_ST_WAIT_RETRY)
|
||||
| S(PFCP_CP_PEER_ST_WAIT_USE_COUNT)
|
||||
,
|
||||
.onenter = pfcp_cp_peer_graceful_release_onenter,
|
||||
.action = pfcp_cp_peer_graceful_release_action,
|
||||
},
|
||||
[PFCP_CP_PEER_ST_WAIT_USE_COUNT] = {
|
||||
.name = "wait_use_count",
|
||||
.in_event_mask = 0
|
||||
| S(PFCP_CP_PEER_EV_USE_COUNT_ZERO)
|
||||
,
|
||||
.onenter = pfcp_cp_peer_wait_use_count_onenter,
|
||||
},
|
||||
};
|
||||
|
||||
static struct osmo_fsm pfcp_cp_peer_fsm = {
|
||||
.name = "pfcp_cp_peer",
|
||||
.states = pfcp_cp_peer_fsm_states,
|
||||
.num_states = ARRAY_SIZE(pfcp_cp_peer_fsm_states),
|
||||
.log_subsys = DLPFCP,
|
||||
.event_names = pfcp_cp_peer_fsm_event_names,
|
||||
.timer_cb = pfcp_cp_peer_fsm_timer_cb,
|
||||
.allstate_action = pfcp_cp_peer_allstate_action,
|
||||
.allstate_event_mask = 0
|
||||
| S(PFCP_CP_PEER_EV_USE_COUNT_ZERO)
|
||||
,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void pfcp_cp_peer_fsm_register(void)
|
||||
{
|
||||
OSMO_ASSERT(osmo_fsm_register(&pfcp_cp_peer_fsm) == 0);
|
||||
}
|
||||
|
||||
bool osmo_pfcp_cp_peer_is_associated(const struct osmo_pfcp_cp_peer *cp_peer)
|
||||
{
|
||||
return cp_peer && cp_peer->fi->state == PFCP_CP_PEER_ST_ASSOCIATED;
|
||||
}
|
||||
|
||||
void osmo_pfcp_cp_peer_set_msg_ctx(struct osmo_pfcp_cp_peer *cp_peer, struct osmo_pfcp_msg *m)
|
||||
{
|
||||
if (m->ctx.peer_fi)
|
||||
return;
|
||||
|
||||
m->ctx.peer_fi = cp_peer->fi;
|
||||
|
||||
m->ctx.peer_use_count = &cp_peer->use_count;
|
||||
m->ctx.peer_use_token = (m->rx ? "PFCPrx" : "PFCPtx");
|
||||
osmo_use_count_get_put(m->ctx.peer_use_count, m->ctx.peer_use_token, 1);
|
||||
}
|
||||
|
||||
struct osmo_pfcp_msg *osmo_pfcp_cp_peer_new_msg_tx(struct osmo_pfcp_cp_peer *cp_peer,
|
||||
enum osmo_pfcp_message_type msg_type)
|
||||
{
|
||||
struct osmo_pfcp_msg *m;
|
||||
m = osmo_pfcp_msg_alloc_tx(cp_peer->ep, &cp_peer->remote_addr, &cp_peer->ep->cfg.local_node_id, NULL,
|
||||
msg_type);
|
||||
if (!m)
|
||||
return m;
|
||||
osmo_pfcp_cp_peer_set_msg_ctx(cp_peer, m);
|
||||
return m;
|
||||
}
|
Loading…
Reference in New Issue