laforge has submitted this change. ( https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/42487?usp=email )
Change subject: pfcp_peer: implement periodic PFCP heartbeat ......................................................................
pfcp_peer: implement periodic PFCP heartbeat
Add a heartbeat_interval parameter to the pfcp_peer config section. When non-zero, pfcp_peer sends a periodic Heartbeat Request to the UPF at the configured interval using a named gen_statem timeout (hb_timer). The timer is started on entry to the connected state and cancelled on re-entry to the connecting state. Default is 10000 ms (10 seconds).
Change-Id: I306324f8eca325202a3fa23125854db9d5eaab38 --- M config/sys.config M contrib/openapi.yaml M doc/manuals/chapters/configuration.adoc M doc/manuals/chapters/rest.adoc M include/osmo_s1gw.hrl M priv/openapi.json M src/osmo_s1gw_sup.erl M src/pfcp_peer.erl M src/rest_server.erl 9 files changed, 46 insertions(+), 9 deletions(-)
Approvals: pespin: Looks good to me, but someone else must approve Jenkins Builder: Verified laforge: Looks good to me, approved
diff --git a/config/sys.config b/config/sys.config index 5bebbe6..a34837d 100644 --- a/config/sys.config +++ b/config/sys.config @@ -35,7 +35,9 @@ %% optional: PFCP Association Setup timeout in milliseconds (default: 2000) %% assoc_setup_timeout => 2000, %% optional: PFCP Heartbeat Request timeout in milliseconds (default: 2000) - %% heartbeat_req_timeout => 2000 + %% heartbeat_req_timeout => 2000, + %% optional: periodic PFCP heartbeat interval in milliseconds (default: 10000) + %% heartbeat_interval => 10000 }} %% Optional PFCP Network Instance IEs (omitted if not configured) %% {pfcp_net_inst_core, "core-side"}, %% PFCP Network Instance IE value (to core) diff --git a/contrib/openapi.yaml b/contrib/openapi.yaml index 8ca18aa..f6dae12 100644 --- a/contrib/openapi.yaml +++ b/contrib/openapi.yaml @@ -535,6 +535,9 @@ heartbeat_req_timeout: type: integer description: PFCP Heartbeat Request response timeout in milliseconds + heartbeat_interval: + type: integer + description: Periodic PFCP heartbeat interval in milliseconds
GtpuKpiCfg: type: object diff --git a/doc/manuals/chapters/configuration.adoc b/doc/manuals/chapters/configuration.adoc index a361730..62dbc87 100644 --- a/doc/manuals/chapters/configuration.adoc +++ b/doc/manuals/chapters/configuration.adoc @@ -138,7 +138,8 @@ laddr => "127.0.1.1", %% local address for PFCP (UDP) raddr => "127.0.1.2" %% remote address of the UPF %% assoc_setup_timeout => 2000, %% optional, milliseconds - %% heartbeat_req_timeout => 2000 %% optional, milliseconds + %% heartbeat_req_timeout => 2000, %% optional, milliseconds + %% heartbeat_interval => 0 %% optional, milliseconds (0 = disabled) }},
%% Optional Network Instance IEs: @@ -161,6 +162,11 @@ How long (in milliseconds) to wait for a PFCP Heartbeat Response before declaring the heartbeat timed out. Default: `2000`.
+`heartbeat_interval`:: + Interval (in milliseconds) between periodic PFCP Heartbeat Requests sent + by OsmoS1GW while associated with the UPF. Set to `0` to disable periodic + heartbeats entirely. Default: `10000`. + NOTE: The legacy flat keys `pfcp_loc_addr` and `pfcp_rem_addr` are still accepted for backwards compatibility. The `pfcp_peer` map takes priority if both are present. diff --git a/doc/manuals/chapters/rest.adoc b/doc/manuals/chapters/rest.adoc index c3f53af..2f3dd92 100644 --- a/doc/manuals/chapters/rest.adoc +++ b/doc/manuals/chapters/rest.adoc @@ -80,7 +80,8 @@ "laddr": "127.0.1.1", "raddr": "127.0.1.2", "assoc_setup_timeout": 2000, - "heartbeat_req_timeout": 2000 + "heartbeat_req_timeout": 2000, + "heartbeat_interval": 10000 }, "gtpu_kpi": { "enable": false, @@ -111,6 +112,7 @@ `raddr`::: Remote UPF (PFCP peer) address. `assoc_setup_timeout`::: PFCP Association Setup response timeout in milliseconds. `heartbeat_req_timeout`::: PFCP Heartbeat Request response timeout in milliseconds. + `heartbeat_interval`::: Periodic PFCP heartbeat interval in milliseconds (0 = disabled).
`gtpu_kpi`:: `enable`::: Whether GTP-U KPI reporting via nftables counters is active. diff --git a/include/osmo_s1gw.hrl b/include/osmo_s1gw.hrl index 692a6ff..87da075 100644 --- a/include/osmo_s1gw.hrl +++ b/include/osmo_s1gw.hrl @@ -43,6 +43,7 @@ -define(ENV_DEFAULT_PFCP_REM_ADDR, "127.0.1.2"). -define(ENV_DEFAULT_PFCP_ASSOC_SETUP_TIMEOUT, 2000). -define(ENV_DEFAULT_PFCP_HEARTBEAT_REQ_TIMEOUT, 2000). +-define(ENV_DEFAULT_PFCP_HEARTBEAT_INTERVAL, 10000). %% 10 seconds -define(ENV_DEFAULT_GTPU_KPI_ENABLE, false). -define(ENV_DEFAULT_GTPU_KPI_TABLE_NAME, "osmo-s1gw"). -define(ENV_DEFAULT_GTPU_KPI_INTERVAL, 3000). diff --git a/priv/openapi.json b/priv/openapi.json index 3153505..3bc27f9 100644 --- a/priv/openapi.json +++ b/priv/openapi.json @@ -771,6 +771,10 @@ "heartbeat_req_timeout": { "type": "integer", "description": "PFCP Heartbeat Request response timeout in milliseconds" + }, + "heartbeat_interval": { + "type": "integer", + "description": "Periodic PFCP heartbeat interval in milliseconds" } } }, diff --git a/src/osmo_s1gw_sup.erl b/src/osmo_s1gw_sup.erl index 9809fff..832d30f 100644 --- a/src/osmo_s1gw_sup.erl +++ b/src/osmo_s1gw_sup.erl @@ -163,7 +163,9 @@ assoc_setup_timeout => maps:get(assoc_setup_timeout, Cfg, ?ENV_DEFAULT_PFCP_ASSOC_SETUP_TIMEOUT), heartbeat_req_timeout => maps:get(heartbeat_req_timeout, Cfg, - ?ENV_DEFAULT_PFCP_HEARTBEAT_REQ_TIMEOUT)}. + ?ENV_DEFAULT_PFCP_HEARTBEAT_REQ_TIMEOUT), + heartbeat_interval => maps:get(heartbeat_interval, Cfg, + ?ENV_DEFAULT_PFCP_HEARTBEAT_INTERVAL)}.
-spec gtpu_kpi_cfg() -> gtpu_kpi:cfg(). diff --git a/src/pfcp_peer.erl b/src/pfcp_peer.erl index 30b45bd..9dd25ea 100644 --- a/src/pfcp_peer.erl +++ b/src/pfcp_peer.erl @@ -77,7 +77,8 @@ -type cfg() :: #{laddr := string() | inet:ip_address(), raddr := string() | inet:ip_address(), assoc_setup_timeout => pos_integer(), - heartbeat_req_timeout => pos_integer()}. + heartbeat_req_timeout => pos_integer(), + heartbeat_interval => non_neg_integer()}.
-type peer_info() :: #{state := atom(), laddr := inet:ip_address(), @@ -214,7 +215,8 @@ %% Tx PFCP Association Setup {ok, S1} = send_assoc_setup(S0), TVal = maps:get(assoc_setup_timeout, Cfg, ?ENV_DEFAULT_PFCP_ASSOC_SETUP_TIMEOUT), - {keep_state, S1, [{state_timeout, TVal, assoc_setup_timeout}]}; + {keep_state, S1, [{{timeout, hb_timer}, cancel}, + {state_timeout, TVal, assoc_setup_timeout}]};
%% Handle Association Setup timeout connecting(state_timeout, assoc_setup_timeout, S) -> @@ -269,10 +271,23 @@
%% CONNECTED state -connected(enter, OldState, S) -> +connected(enter, OldState, + #peer_state{cfg = Cfg} = S) -> ?LOG_INFO("State change: ~p -> ~p", [OldState, ?FUNCTION_NAME]), s1gw_metrics:gauge_set(?S1GW_GAUGE_PFCP_ASSOCIATED, 1), - {keep_state, S}; + case maps:get(heartbeat_interval, Cfg, ?ENV_DEFAULT_PFCP_HEARTBEAT_INTERVAL) of + 0 -> {keep_state, S}; %% periodic heartbeat is disabled + Interval -> + ?LOG_INFO("Starting periodic PFCP heartbeat (interval=~p ms)", [Interval]), + {keep_state, S, [{{timeout, hb_timer}, Interval, heartbeat}]} + end; + +%% Periodic heartbeat timer +connected({timeout, hb_timer}, heartbeat, + #peer_state{cfg = Cfg} = S0) -> + {_, S1} = send_heartbeat_request(undefined, S0), + Interval = maps:get(heartbeat_interval, Cfg, ?ENV_DEFAULT_PFCP_HEARTBEAT_INTERVAL), + {keep_state, S1, [{{timeout, hb_timer}, Interval, heartbeat}]};
connected({call, From}, {session_establish_req, SEID, PDRs, FARs}, diff --git a/src/rest_server.erl b/src/rest_server.erl index 7960ffa..bff37fc 100644 --- a/src/rest_server.erl +++ b/src/rest_server.erl @@ -285,7 +285,9 @@ <<"assoc_setup_timeout">> => maps:get(assoc_setup_timeout, Cfg, ?ENV_DEFAULT_PFCP_ASSOC_SETUP_TIMEOUT), <<"heartbeat_req_timeout">> => maps:get(heartbeat_req_timeout, Cfg, - ?ENV_DEFAULT_PFCP_HEARTBEAT_REQ_TIMEOUT)}. + ?ENV_DEFAULT_PFCP_HEARTBEAT_REQ_TIMEOUT), + <<"heartbeat_interval">> => maps:get(heartbeat_interval, Cfg, + ?ENV_DEFAULT_PFCP_HEARTBEAT_INTERVAL)}.
-spec config_gtpu_kpi() -> map().