mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-upf.git
synced 2025-11-03 05:23:46 +00:00
add osmo-pfcp-tool
Related: SYS#5599 Change-Id: I34a80d43a14c7b68952c7d337d8042d6f28ceae7
This commit is contained in:
@@ -207,6 +207,7 @@ AC_OUTPUT(
|
||||
src/libosmo-gtlv/Makefile
|
||||
src/libosmo-pfcp/Makefile
|
||||
src/osmo-upf/Makefile
|
||||
src/osmo-pfcp-tool/Makefile
|
||||
tests/Makefile
|
||||
tests/atlocal
|
||||
tests/libosmo-gtlv/Makefile
|
||||
|
||||
3
contrib/osmo-pfcp-tool-scripts/assoc_setup.vty
Normal file
3
contrib/osmo-pfcp-tool-scripts/assoc_setup.vty
Normal file
@@ -0,0 +1,3 @@
|
||||
pfcp-peer 127.0.0.1
|
||||
tx assoc-setup-req
|
||||
sleep 1
|
||||
8
contrib/osmo-pfcp-tool-scripts/assoc_setup_retrans.vty
Normal file
8
contrib/osmo-pfcp-tool-scripts/assoc_setup_retrans.vty
Normal file
@@ -0,0 +1,8 @@
|
||||
pfcp-peer 127.0.0.1
|
||||
tx assoc-setup-req
|
||||
sleep 3
|
||||
retrans req
|
||||
sleep 5
|
||||
retrans req
|
||||
sleep 1
|
||||
retrans req
|
||||
30
contrib/osmo-pfcp-tool-scripts/encaps_plus_tunmap.vty
Normal file
30
contrib/osmo-pfcp-tool-scripts/encaps_plus_tunmap.vty
Normal file
@@ -0,0 +1,30 @@
|
||||
# ACCESS HOP CORE
|
||||
# session 23 = tunmap session 42 = encaps/decaps
|
||||
# GTP 127.0.0.13 127.0.0.12 127.0.0.11
|
||||
# TEID l:23 r:123 <---> r:23 l:123 | l:142 r:42 <---> r:142 l:42 | 192.168.100.42
|
||||
#
|
||||
# Run two UPF, one listening on / sending from 127.0.0.11, the other on 127.0.0.12.
|
||||
# (Each has to match on the sender address of incoming GTP packets.)
|
||||
|
||||
timer pfcp x23 0
|
||||
|
||||
pfcp-peer 127.0.0.11
|
||||
tx assoc-setup-req
|
||||
sleep 1
|
||||
session endecaps 42
|
||||
ue ip 192.168.100.42
|
||||
gtp access ip 127.0.0.12
|
||||
gtp access teid local 42 remote 142
|
||||
tx session-est-req
|
||||
sleep 1
|
||||
|
||||
pfcp-peer 127.0.0.12
|
||||
tx assoc-setup-req
|
||||
sleep 1
|
||||
session tunmap 23
|
||||
gtp core ip 127.0.0.11
|
||||
gtp core teid local 142 remote 42
|
||||
gtp access ip 127.0.0.13
|
||||
gtp access teid local 123 remote 23
|
||||
tx session-est-req
|
||||
sleep 1
|
||||
8
contrib/osmo-pfcp-tool-scripts/endecaps_session_est.vty
Normal file
8
contrib/osmo-pfcp-tool-scripts/endecaps_session_est.vty
Normal file
@@ -0,0 +1,8 @@
|
||||
timer pfcp x23 0
|
||||
pfcp-peer 127.0.0.1
|
||||
tx assoc-setup-req
|
||||
sleep 1
|
||||
session endecaps
|
||||
tx session-est-req forw
|
||||
sleep 5
|
||||
tx session-del-req
|
||||
10
contrib/osmo-pfcp-tool-scripts/heartbeat.vty
Normal file
10
contrib/osmo-pfcp-tool-scripts/heartbeat.vty
Normal file
@@ -0,0 +1,10 @@
|
||||
pfcp-peer 127.0.0.1
|
||||
tx heartbeat
|
||||
sleep 2
|
||||
tx heartbeat
|
||||
sleep 2
|
||||
tx heartbeat
|
||||
sleep 2
|
||||
tx heartbeat
|
||||
sleep 2
|
||||
tx heartbeat
|
||||
5
contrib/osmo-pfcp-tool-scripts/osmo-pfcp-tool.cfg
Normal file
5
contrib/osmo-pfcp-tool-scripts/osmo-pfcp-tool.cfg
Normal file
@@ -0,0 +1,5 @@
|
||||
log stderr
|
||||
logging level set-all info
|
||||
|
||||
local-addr 127.0.0.2
|
||||
listen
|
||||
27
contrib/osmo-pfcp-tool-scripts/osmo-upf-11.cfg
Normal file
27
contrib/osmo-pfcp-tool-scripts/osmo-upf-11.cfg
Normal file
@@ -0,0 +1,27 @@
|
||||
log stderr
|
||||
logging filter all 1
|
||||
logging color 1
|
||||
logging print level 1
|
||||
logging print category 1
|
||||
logging print category-hex 0
|
||||
logging print file basename last
|
||||
logging print extended-timestamp 1
|
||||
logging level set-all notice
|
||||
logging level set-all info
|
||||
logging level session debug
|
||||
logging level nft debug
|
||||
logging level gtp debug
|
||||
#logging level set-all debug
|
||||
|
||||
line vty
|
||||
bind 127.0.0.11
|
||||
ctrl
|
||||
bind 127.0.0.11
|
||||
|
||||
timer pfcp x24 5000
|
||||
pfcp
|
||||
local-addr 127.0.0.11
|
||||
gtp
|
||||
dev create apn11 127.0.0.11
|
||||
nft
|
||||
table-name osmo-upf-11
|
||||
27
contrib/osmo-pfcp-tool-scripts/osmo-upf-12.cfg
Normal file
27
contrib/osmo-pfcp-tool-scripts/osmo-upf-12.cfg
Normal file
@@ -0,0 +1,27 @@
|
||||
log stderr
|
||||
logging filter all 1
|
||||
logging color 1
|
||||
logging print level 1
|
||||
logging print category 1
|
||||
logging print category-hex 0
|
||||
logging print file basename last
|
||||
logging print extended-timestamp 1
|
||||
logging level set-all notice
|
||||
logging level set-all info
|
||||
logging level session debug
|
||||
logging level nft debug
|
||||
logging level gtp debug
|
||||
#logging level set-all debug
|
||||
|
||||
line vty
|
||||
bind 127.0.0.12
|
||||
ctrl
|
||||
bind 127.0.0.12
|
||||
|
||||
timer pfcp x24 5000
|
||||
pfcp
|
||||
local-addr 127.0.0.12
|
||||
gtp
|
||||
dev create apn12 127.0.0.12
|
||||
nft
|
||||
table-name osmo-upf-12
|
||||
@@ -0,0 +1,4 @@
|
||||
timer pfcp x23 0
|
||||
pfcp-peer 127.0.0.1
|
||||
session endecaps
|
||||
tx session-est-req
|
||||
14
contrib/osmo-pfcp-tool-scripts/session_mod.vty
Normal file
14
contrib/osmo-pfcp-tool-scripts/session_mod.vty
Normal file
@@ -0,0 +1,14 @@
|
||||
timer pfcp x23 0
|
||||
pfcp-peer 127.0.0.1
|
||||
tx assoc-setup-req
|
||||
sleep 1
|
||||
session
|
||||
tx session-est-req drop
|
||||
sleep 3
|
||||
tx session-mod-req forw
|
||||
sleep 5
|
||||
tx session-mod-req drop
|
||||
sleep 3
|
||||
tx session-mod-req forw
|
||||
sleep 3
|
||||
tx session-del-req
|
||||
8
contrib/osmo-pfcp-tool-scripts/tunmap_session_est.vty
Normal file
8
contrib/osmo-pfcp-tool-scripts/tunmap_session_est.vty
Normal file
@@ -0,0 +1,8 @@
|
||||
timer pfcp x23 0
|
||||
pfcp-peer 127.0.0.1
|
||||
tx assoc-setup-req
|
||||
sleep 1
|
||||
session tunmap
|
||||
tx session-est-req
|
||||
sleep 5
|
||||
tx session-del-req
|
||||
@@ -2,4 +2,5 @@ SUBDIRS = \
|
||||
libosmo-gtlv \
|
||||
libosmo-pfcp \
|
||||
osmo-upf \
|
||||
osmo-pfcp-tool \
|
||||
$(NULL)
|
||||
|
||||
41
src/osmo-pfcp-tool/Makefile.am
Normal file
41
src/osmo-pfcp-tool/Makefile.am
Normal file
@@ -0,0 +1,41 @@
|
||||
AM_CPPFLAGS = \
|
||||
$(all_includes) \
|
||||
-I$(top_srcdir)/include \
|
||||
-I$(top_builddir)/include \
|
||||
-I$(top_builddir) \
|
||||
$(NULL)
|
||||
|
||||
AM_CFLAGS = \
|
||||
-Wall \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(LIBOSMOVTY_CFLAGS) \
|
||||
$(LIBOSMOCTRL_CFLAGS) \
|
||||
$(COVERAGE_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
AM_LDFLAGS = \
|
||||
$(COVERAGE_LDFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
noinst_HEADERS = \
|
||||
pfcp_tool.h \
|
||||
$(NULL)
|
||||
|
||||
bin_PROGRAMS = \
|
||||
osmo-pfcp-tool \
|
||||
$(NULL)
|
||||
|
||||
osmo_pfcp_tool_SOURCES = \
|
||||
osmo_pfcp_tool_main.c \
|
||||
pfcp_tool.c \
|
||||
pfcp_tool_vty.c \
|
||||
$(NULL)
|
||||
|
||||
osmo_pfcp_tool_LDADD = \
|
||||
$(top_builddir)/src/libosmo-pfcp/libosmo-pfcp.a \
|
||||
$(top_builddir)/src/libosmo-gtlv/libosmo-gtlv.a \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOVTY_LIBS) \
|
||||
$(LIBOSMOCTRL_LIBS) \
|
||||
$(COVERAGE_LDFLAGS) \
|
||||
$(NULL)
|
||||
371
src/osmo-pfcp-tool/osmo_pfcp_tool_main.c
Normal file
371
src/osmo-pfcp-tool/osmo_pfcp_tool_main.c
Normal file
@@ -0,0 +1,371 @@
|
||||
/*
|
||||
* (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 <osmocom/core/application.h>
|
||||
#include <osmocom/core/signal.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/core/fsm.h>
|
||||
#include <osmocom/core/stats.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/vty/logging.h>
|
||||
#include <osmocom/vty/command.h>
|
||||
#include <osmocom/vty/misc.h>
|
||||
#include <osmocom/vty/cpu_sched_vty.h>
|
||||
#include <osmocom/vty/telnet_interface.h>
|
||||
#include <osmocom/vty/ports.h>
|
||||
#include <osmocom/vty/tdef_vty.h>
|
||||
#include <osmocom/ctrl/control_if.h>
|
||||
#include <osmocom/ctrl/control_vty.h>
|
||||
#include <osmocom/ctrl/ports.h>
|
||||
#include <osmocom/core/sockaddr_str.h>
|
||||
|
||||
#include <osmocom/pfcp/pfcp_endpoint.h>
|
||||
|
||||
#include "pfcp_tool.h"
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <getopt.h>
|
||||
|
||||
/* build switches from the configure script */
|
||||
#include "config.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
extern void *tall_vty_ctx;
|
||||
|
||||
void *tall_pfcp_tool_ctx = NULL;
|
||||
static int quit = 0;
|
||||
|
||||
static struct {
|
||||
const char *config_file;
|
||||
int daemonize;
|
||||
enum vty_ref_gen_mode vty_ref_gen_mode;
|
||||
const char *command_file;
|
||||
} pfcp_tool_cmdline_config = {
|
||||
.config_file = "osmo-pfcp-tool.cfg",
|
||||
.vty_ref_gen_mode = VTY_REF_GEN_MODE_DEFAULT,
|
||||
};
|
||||
|
||||
static void print_usage()
|
||||
{
|
||||
printf("Usage: osmo-pfcp-tool [command-file.vty]\n telnet localhost %d\n", OSMO_VTY_PORT_PFCP_TOOL);
|
||||
}
|
||||
|
||||
static void print_help()
|
||||
{
|
||||
const struct value_string *vty_ref_gen_mode_name;
|
||||
|
||||
printf("Some useful options:\n");
|
||||
printf(" -h --help This text.\n");
|
||||
printf(" -D --daemonize Fork the process into a background daemon.\n");
|
||||
printf(" -c --config-file filename The config file to use, for logging etc.\n");
|
||||
printf(" -V --version Print the version of OsmoMSC.\n");
|
||||
|
||||
printf("\nVTY reference generation:\n");
|
||||
printf(" --vty-ref-xml Generate the VTY reference XML output and exit.\n");
|
||||
printf(" --vty-ref-mode MODE Mode for --vty-ref-xml:\n");
|
||||
/* List all VTY ref gen modes */
|
||||
for (vty_ref_gen_mode_name = vty_ref_gen_mode_names; vty_ref_gen_mode_name->str; vty_ref_gen_mode_name++)
|
||||
printf(" %s: %s\n",
|
||||
vty_ref_gen_mode_name->str,
|
||||
get_value_string(vty_ref_gen_mode_desc, vty_ref_gen_mode_name->value));
|
||||
}
|
||||
|
||||
static void handle_long_options(const char *prog_name, const int long_option)
|
||||
{
|
||||
switch (long_option) {
|
||||
case 1:
|
||||
pfcp_tool_cmdline_config.vty_ref_gen_mode = get_string_value(vty_ref_gen_mode_names, optarg);
|
||||
if (pfcp_tool_cmdline_config.vty_ref_gen_mode < 0) {
|
||||
fprintf(stderr, "%s: Unknown VTY reference generation mode: '%s'\n", prog_name, optarg);
|
||||
exit(2);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
fprintf(stderr, "Generating the VTY reference in mode '%s' (%s)\n",
|
||||
get_value_string(vty_ref_gen_mode_names, pfcp_tool_cmdline_config.vty_ref_gen_mode),
|
||||
get_value_string(vty_ref_gen_mode_desc, pfcp_tool_cmdline_config.vty_ref_gen_mode));
|
||||
vty_dump_xml_ref_mode(stdout, pfcp_tool_cmdline_config.vty_ref_gen_mode);
|
||||
exit(0);
|
||||
default:
|
||||
fprintf(stderr, "%s: error parsing cmdline options\n", prog_name);
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_options(int argc, char **argv)
|
||||
{
|
||||
while (1) {
|
||||
int option_index = 0, c;
|
||||
static int long_option = 0;
|
||||
static struct option long_options[] = {
|
||||
{"help", 0, 0, 'h'},
|
||||
{"daemonize", 0, 0, 'D'},
|
||||
{"config-file", 1, 0, 'c'},
|
||||
{"version", 0, 0, 'V' },
|
||||
{"vty-ref-mode", 1, &long_option, 1},
|
||||
{"vty-ref-xml", 0, &long_option, 2},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
c = getopt_long(argc, argv, "hDc:V", long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'h':
|
||||
print_usage();
|
||||
print_help();
|
||||
exit(0);
|
||||
case 0:
|
||||
handle_long_options(argv[0], long_option);
|
||||
break;
|
||||
case 'D':
|
||||
pfcp_tool_cmdline_config.daemonize = 1;
|
||||
break;
|
||||
case 'c':
|
||||
pfcp_tool_cmdline_config.config_file = optarg;
|
||||
break;
|
||||
case 'V':
|
||||
print_version(1);
|
||||
exit(0);
|
||||
break;
|
||||
default:
|
||||
/* catch unknown options *as well as* missing arguments. */
|
||||
fprintf(stderr, "%s: Error in command line options. Exiting.\n", argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > optind) {
|
||||
pfcp_tool_cmdline_config.command_file = argv[optind];
|
||||
optind++;
|
||||
}
|
||||
|
||||
if (argc > optind) {
|
||||
fprintf(stderr, "%s: Unsupported positional arguments on command line\n", argv[optind]);
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
static void signal_handler(int signum)
|
||||
{
|
||||
fprintf(stdout, "signal %u received\n", signum);
|
||||
|
||||
switch (signum) {
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
LOGP(DLGLOBAL, LOGL_NOTICE, "Terminating due to signal %d\n", signum);
|
||||
quit++;
|
||||
break;
|
||||
case SIGABRT:
|
||||
osmo_generate_backtrace();
|
||||
/* in case of abort, we want to obtain a talloc report and
|
||||
* then run default SIGABRT handler, who will generate coredump
|
||||
* and abort the process. abort() should do this for us after we
|
||||
* return, but program wouldn't exit if an external SIGABRT is
|
||||
* received.
|
||||
*/
|
||||
talloc_report(tall_vty_ctx, stderr);
|
||||
talloc_report_full(tall_pfcp_tool_ctx, stderr);
|
||||
signal(SIGABRT, SIG_DFL);
|
||||
raise(SIGABRT);
|
||||
break;
|
||||
case SIGUSR1:
|
||||
talloc_report(tall_vty_ctx, stderr);
|
||||
talloc_report_full(tall_pfcp_tool_ctx, stderr);
|
||||
break;
|
||||
case SIGUSR2:
|
||||
talloc_report_full(tall_vty_ctx, stderr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const char * const osmo_pfcp_tool_copyright =
|
||||
"OsmoPFCPTool - Osmocom Packet Forwarding Control Protocol tool for testing\r\n"
|
||||
"Copyright (C) 2021-2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>\r\n"
|
||||
"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
|
||||
"This is free software: you are free to change and redistribute it.\r\n"
|
||||
"There is NO WARRANTY, to the extent permitted by law.\r\n";
|
||||
|
||||
static struct vty_app_info pfcp_tool_vty_app_info = {
|
||||
.name = "osmo-pfcp-tool",
|
||||
.version = PACKAGE_VERSION,
|
||||
.copyright = osmo_pfcp_tool_copyright,
|
||||
};
|
||||
|
||||
static const struct log_info_cat pfcp_tool_default_categories[] = {
|
||||
};
|
||||
|
||||
const struct log_info log_info = {
|
||||
.cat = pfcp_tool_default_categories,
|
||||
.num_cat = ARRAY_SIZE(pfcp_tool_default_categories),
|
||||
};
|
||||
|
||||
int pfcp_tool_mainloop()
|
||||
{
|
||||
log_reset_context();
|
||||
osmo_select_main_ctx(0);
|
||||
|
||||
/* If the user hits Ctrl-C the third time, just terminate immediately. */
|
||||
if (quit >= 3)
|
||||
return 1;
|
||||
|
||||
/* Has SIGTERM been received (and not yet been handled)? */
|
||||
if (quit && !osmo_select_shutdown_requested()) {
|
||||
osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
|
||||
|
||||
/* Request write-only mode in osmo_select_main_ctx() */
|
||||
osmo_select_shutdown_request();
|
||||
/* continue the main select loop until all write queues are serviced. */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Track the use of talloc NULL memory contexts */
|
||||
talloc_enable_null_tracking();
|
||||
|
||||
osmo_fsm_set_dealloc_ctx(OTC_SELECT);
|
||||
|
||||
tall_pfcp_tool_ctx = talloc_named_const(NULL, 1, "osmo-pfcp-tool");
|
||||
pfcp_tool_vty_app_info.tall_ctx = tall_pfcp_tool_ctx;
|
||||
|
||||
msgb_talloc_ctx_init(tall_pfcp_tool_ctx, 0);
|
||||
osmo_signal_talloc_ctx_init(tall_pfcp_tool_ctx);
|
||||
|
||||
osmo_init_logging2(tall_pfcp_tool_ctx, &log_info);
|
||||
log_set_print_category_hex(osmo_stderr_target, 0);
|
||||
log_set_print_category(osmo_stderr_target, 1);
|
||||
log_set_print_level(osmo_stderr_target, 1);
|
||||
log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_BASENAME);
|
||||
log_set_print_filename_pos(osmo_stderr_target, LOG_FILENAME_POS_LINE_END);
|
||||
log_set_print_extended_timestamp(osmo_stderr_target, 1);
|
||||
|
||||
osmo_fsm_log_timeouts(true);
|
||||
osmo_fsm_log_addr(true);
|
||||
|
||||
osmo_stats_init(tall_pfcp_tool_ctx);
|
||||
|
||||
g_pfcp_tool_alloc(tall_pfcp_tool_ctx);
|
||||
|
||||
/* For --version, vty_init() must be called before handling options */
|
||||
vty_init(&pfcp_tool_vty_app_info);
|
||||
|
||||
ctrl_vty_init(tall_pfcp_tool_ctx);
|
||||
logging_vty_add_cmds();
|
||||
osmo_talloc_vty_add_cmds();
|
||||
osmo_cpu_sched_vty_init(tall_pfcp_tool_ctx);
|
||||
osmo_fsm_vty_add_cmds();
|
||||
osmo_tdef_vty_groups_init(CONFIG_NODE, g_pfcp_tool_tdef_groups);
|
||||
|
||||
pfcp_tool_vty_init_cfg();
|
||||
|
||||
/* Parse options */
|
||||
handle_options(argc, argv);
|
||||
|
||||
if (pfcp_tool_cmdline_config.config_file) {
|
||||
rc = vty_read_config_file(pfcp_tool_cmdline_config.config_file, NULL);
|
||||
if (rc < 0) {
|
||||
LOGP(DLGLOBAL, LOGL_ERROR, "Failed to parse the config file: '%s'\n",
|
||||
pfcp_tool_cmdline_config.config_file);
|
||||
}
|
||||
}
|
||||
|
||||
/* start telnet, after reading config for vty_get_bind_addr() */
|
||||
rc = telnet_init_dynif(tall_pfcp_tool_ctx, &g_pfcp_tool, vty_get_bind_addr(), OSMO_VTY_PORT_PFCP_TOOL);
|
||||
if (rc < 0)
|
||||
return 2;
|
||||
|
||||
/* start control interface, after reading config for ctrl_vty_get_bind_addr() */
|
||||
g_pfcp_tool->ctrl = ctrl_interface_setup_dynip(g_pfcp_tool, ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_PFCP_TOOL, NULL);
|
||||
if (!g_pfcp_tool->ctrl) {
|
||||
fprintf(stderr, "Failed to initialize control interface. Exiting.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
signal(SIGINT, &signal_handler);
|
||||
signal(SIGTERM, &signal_handler);
|
||||
signal(SIGABRT, &signal_handler);
|
||||
signal(SIGUSR1, &signal_handler);
|
||||
signal(SIGUSR2, &signal_handler);
|
||||
osmo_init_ignore_signals();
|
||||
|
||||
if (pfcp_tool_cmdline_config.daemonize) {
|
||||
rc = osmo_daemonize();
|
||||
if (rc < 0) {
|
||||
perror("Error during daemonize");
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
|
||||
pfcp_tool_mainloop();
|
||||
|
||||
pfcp_tool_vty_init_cmds();
|
||||
|
||||
if (pfcp_tool_cmdline_config.command_file) {
|
||||
printf("Reading '%s'\n", pfcp_tool_cmdline_config.command_file);
|
||||
rc = vty_read_config_file(pfcp_tool_cmdline_config.command_file, NULL);
|
||||
if (rc < 0) {
|
||||
LOGP(DLGLOBAL, LOGL_FATAL, "Failed to parse the command file: '%s'\n",
|
||||
pfcp_tool_cmdline_config.command_file);
|
||||
return 1;
|
||||
}
|
||||
printf("Done reading '%s', waiting for retransmission queue...\n",
|
||||
pfcp_tool_cmdline_config.command_file);
|
||||
do {
|
||||
if (pfcp_tool_mainloop())
|
||||
break;
|
||||
} while (!llist_empty(&g_pfcp_tool->ep->retrans_queue));
|
||||
printf("Done\n");
|
||||
} else {
|
||||
printf("Listening for commands on VTY...\n");
|
||||
do {
|
||||
if (pfcp_tool_mainloop())
|
||||
break;
|
||||
} while (!osmo_select_shutdown_done());
|
||||
}
|
||||
|
||||
osmo_pfcp_endpoint_free(&g_pfcp_tool->ep);
|
||||
|
||||
log_fini();
|
||||
|
||||
/* Report the heap state of talloc contexts, then free, so both ASAN and Valgrind are happy... */
|
||||
//talloc_report_full(tall_pfcp_tool_ctx, stderr);
|
||||
talloc_free(tall_pfcp_tool_ctx);
|
||||
|
||||
//talloc_report_full(tall_vty_ctx, stderr);
|
||||
talloc_free(tall_vty_ctx);
|
||||
|
||||
//talloc_report_full(NULL, stderr);
|
||||
talloc_disable_null_tracking();
|
||||
return 0;
|
||||
}
|
||||
176
src/osmo-pfcp-tool/pfcp_tool.c
Normal file
176
src/osmo-pfcp-tool/pfcp_tool.c
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* (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 <osmocom/core/utils.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
|
||||
#include <osmocom/pfcp/pfcp_endpoint.h>
|
||||
|
||||
#include "pfcp_tool.h"
|
||||
|
||||
struct g_pfcp_tool *g_pfcp_tool = NULL;
|
||||
|
||||
struct osmo_tdef_group g_pfcp_tool_tdef_groups[] = {
|
||||
{ .name = "pfcp", .tdefs = osmo_pfcp_tdefs, .desc = "PFCP" },
|
||||
{}
|
||||
};
|
||||
|
||||
void g_pfcp_tool_alloc(void *ctx)
|
||||
{
|
||||
OSMO_ASSERT(g_pfcp_tool == NULL);
|
||||
g_pfcp_tool = talloc_zero(ctx, struct g_pfcp_tool);
|
||||
|
||||
*g_pfcp_tool = (struct g_pfcp_tool){
|
||||
.vty_cfg = {
|
||||
.local_ip = talloc_strdup(g_pfcp_tool, "0.0.0.0"),
|
||||
.local_port = OSMO_PFCP_PORT,
|
||||
},
|
||||
};
|
||||
|
||||
INIT_LLIST_HEAD(&g_pfcp_tool->peers);
|
||||
}
|
||||
|
||||
struct pfcp_tool_peer *pfcp_tool_peer_find(const struct osmo_sockaddr *remote_addr)
|
||||
{
|
||||
struct pfcp_tool_peer *peer;
|
||||
llist_for_each_entry(peer, &g_pfcp_tool->peers, entry) {
|
||||
if (osmo_sockaddr_cmp(&peer->remote_addr, remote_addr) == 0)
|
||||
return peer;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct pfcp_tool_peer *pfcp_tool_peer_find_or_create(const struct osmo_sockaddr *remote_addr)
|
||||
{
|
||||
struct pfcp_tool_peer *peer = pfcp_tool_peer_find(remote_addr);
|
||||
if (peer)
|
||||
return peer;
|
||||
|
||||
peer = talloc_zero(g_pfcp_tool, struct pfcp_tool_peer);
|
||||
peer->remote_addr = *remote_addr;
|
||||
peer->next_seid_state = 0x1234567;
|
||||
INIT_LLIST_HEAD(&peer->sessions);
|
||||
llist_add(&peer->entry, &g_pfcp_tool->peers);
|
||||
return peer;
|
||||
}
|
||||
|
||||
struct pfcp_tool_session *pfcp_tool_session_find(struct pfcp_tool_peer *peer, uint64_t cp_seid)
|
||||
{
|
||||
struct pfcp_tool_session *session;
|
||||
llist_for_each_entry(session, &peer->sessions, entry) {
|
||||
if (session->cp_seid == cp_seid)
|
||||
return session;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct pfcp_tool_session *pfcp_tool_session_find_or_create(struct pfcp_tool_peer *peer, uint64_t cp_seid,
|
||||
enum up_gtp_action_kind gtp_action)
|
||||
{
|
||||
struct pfcp_tool_session *session = pfcp_tool_session_find(peer, cp_seid);
|
||||
if (session)
|
||||
return session;
|
||||
|
||||
session = talloc(peer, struct pfcp_tool_session);
|
||||
*session = (struct pfcp_tool_session){
|
||||
.peer = peer,
|
||||
.cp_seid = cp_seid,
|
||||
.gtp_action = gtp_action,
|
||||
};
|
||||
llist_add(&session->entry, &peer->sessions);
|
||||
return session;
|
||||
}
|
||||
|
||||
static void rx_assoc_setup_resp(struct osmo_pfcp_endpoint *ep, struct osmo_pfcp_msg *m)
|
||||
{
|
||||
if (m->ies.assoc_setup_resp.up_function_features_present)
|
||||
OSMO_LOG_PFCP_MSG(m, LOGL_NOTICE, "Associated. UP Peer features: %s\n",
|
||||
osmo_pfcp_bits_to_str_c(OTC_SELECT,
|
||||
m->ies.assoc_setup_resp.up_function_features.bits,
|
||||
osmo_pfcp_up_feature_strs));
|
||||
|
||||
if (m->ies.assoc_setup_resp.cp_function_features_present)
|
||||
OSMO_LOG_PFCP_MSG(m, LOGL_NOTICE, "Associated. CP Peer features: %s\n",
|
||||
osmo_pfcp_bits_to_str_c(OTC_SELECT,
|
||||
m->ies.assoc_setup_resp.cp_function_features.bits,
|
||||
osmo_pfcp_cp_feature_strs));
|
||||
}
|
||||
|
||||
static void rx_session_est_resp(struct osmo_pfcp_endpoint *ep, struct osmo_pfcp_msg *m)
|
||||
{
|
||||
struct pfcp_tool_peer *peer;
|
||||
struct pfcp_tool_session *session;
|
||||
enum osmo_pfcp_cause *cause = osmo_pfcp_msg_cause(m);
|
||||
if (!cause) {
|
||||
OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "Session Establishment Response should contain a Cause\n");
|
||||
return;
|
||||
}
|
||||
if (*cause != OSMO_PFCP_CAUSE_REQUEST_ACCEPTED) {
|
||||
OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "Peer responds that Session Establishment failed\n");
|
||||
return;
|
||||
}
|
||||
if (!m->h.seid_present) {
|
||||
OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "Session Establishment Response should contain a SEID\n");
|
||||
return;
|
||||
}
|
||||
if (!m->ies.session_est_resp.up_f_seid_present) {
|
||||
OSMO_LOG_PFCP_MSG(m, LOGL_ERROR, "Session Establishment Response without UP F-SEID\n");
|
||||
return;
|
||||
}
|
||||
peer = pfcp_tool_peer_find(&m->remote_addr);
|
||||
if (!peer)
|
||||
return;
|
||||
session = pfcp_tool_session_find(peer, m->h.seid);
|
||||
if (!session)
|
||||
return;
|
||||
session->up_f_seid = m->ies.session_est_resp.up_f_seid;
|
||||
}
|
||||
|
||||
void pfcp_tool_rx_msg(struct osmo_pfcp_endpoint *ep, struct osmo_pfcp_msg *m)
|
||||
{
|
||||
switch (m->h.message_type) {
|
||||
case OSMO_PFCP_MSGT_ASSOC_SETUP_RESP:
|
||||
rx_assoc_setup_resp(ep, m);
|
||||
break;
|
||||
case OSMO_PFCP_MSGT_SESSION_EST_RESP:
|
||||
rx_session_est_resp(ep, m);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
int peer_tx(struct pfcp_tool_peer *peer, struct osmo_pfcp_msg *m)
|
||||
{
|
||||
int rc;
|
||||
rc = osmo_pfcp_endpoint_tx(g_pfcp_tool->ep, m);
|
||||
if (m->is_response)
|
||||
peer->last_resp = *m;
|
||||
else
|
||||
peer->last_req = *m;
|
||||
return rc;
|
||||
}
|
||||
|
||||
uint64_t peer_new_seid(struct pfcp_tool_peer *peer)
|
||||
{
|
||||
return peer->next_seid_state++;
|
||||
}
|
||||
106
src/osmo-pfcp-tool/pfcp_tool.h
Normal file
106
src/osmo-pfcp-tool/pfcp_tool.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/* Global definitions for osmo-pfcp-tool */
|
||||
/*
|
||||
* (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/tdef.h>
|
||||
#include <osmocom/core/socket.h>
|
||||
#include <osmocom/core/sockaddr_str.h>
|
||||
|
||||
#include <osmocom/pfcp/pfcp_msg.h>
|
||||
|
||||
#include <osmocom/upf/up_gtp_action.h>
|
||||
|
||||
struct osmo_tdef;
|
||||
struct ctrl_handle;
|
||||
|
||||
extern struct osmo_tdef g_pfcp_tool_tdefs[];
|
||||
extern struct osmo_tdef_group g_pfcp_tool_tdef_groups[];
|
||||
|
||||
struct pfcp_tool_peer {
|
||||
struct llist_head entry;
|
||||
|
||||
struct osmo_sockaddr remote_addr;
|
||||
struct osmo_pfcp_msg last_req;
|
||||
struct osmo_pfcp_msg last_resp;
|
||||
|
||||
uint64_t next_seid_state;
|
||||
|
||||
struct llist_head sessions;
|
||||
};
|
||||
|
||||
struct pfcp_tool_teid_pair {
|
||||
uint32_t local;
|
||||
uint32_t remote;
|
||||
};
|
||||
|
||||
struct pfcp_tool_session {
|
||||
struct llist_head entry;
|
||||
|
||||
enum up_gtp_action_kind gtp_action;
|
||||
|
||||
struct pfcp_tool_peer *peer;
|
||||
uint64_t cp_seid;
|
||||
struct osmo_pfcp_ie_f_seid up_f_seid;
|
||||
|
||||
struct {
|
||||
struct pfcp_tool_teid_pair teid;
|
||||
struct osmo_sockaddr_str gtp_ip;
|
||||
} access;
|
||||
|
||||
struct {
|
||||
struct pfcp_tool_teid_pair teid;
|
||||
struct osmo_sockaddr_str gtp_ip;
|
||||
struct osmo_sockaddr_str ue_addr;
|
||||
} core;
|
||||
};
|
||||
|
||||
struct g_pfcp_tool {
|
||||
struct ctrl_handle *ctrl;
|
||||
|
||||
struct {
|
||||
char *local_ip;
|
||||
uint16_t local_port;
|
||||
} vty_cfg;
|
||||
|
||||
struct osmo_pfcp_endpoint *ep;
|
||||
struct llist_head peers;
|
||||
};
|
||||
|
||||
extern struct g_pfcp_tool *g_pfcp_tool;
|
||||
|
||||
void g_pfcp_tool_alloc(void *ctx);
|
||||
void pfcp_tool_vty_init_cfg();
|
||||
void pfcp_tool_vty_init_cmds();
|
||||
|
||||
int pfcp_tool_mainloop();
|
||||
|
||||
struct pfcp_tool_peer *pfcp_tool_peer_find_or_create(const struct osmo_sockaddr *remote_addr);
|
||||
struct pfcp_tool_session *pfcp_tool_session_find_or_create(struct pfcp_tool_peer *peer, uint64_t cp_seid,
|
||||
enum up_gtp_action_kind kind);
|
||||
void pfcp_tool_rx_msg(struct osmo_pfcp_endpoint *ep, struct osmo_pfcp_msg *m);
|
||||
|
||||
int peer_tx(struct pfcp_tool_peer *peer, struct osmo_pfcp_msg *m);
|
||||
uint64_t peer_new_seid(struct pfcp_tool_peer *peer);
|
||||
785
src/osmo-pfcp-tool/pfcp_tool_vty.c
Normal file
785
src/osmo-pfcp-tool/pfcp_tool_vty.c
Normal file
@@ -0,0 +1,785 @@
|
||||
/* osmo-pfcp-tool interface to quagga VTY */
|
||||
/*
|
||||
* (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 <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <osmocom/core/sockaddr_str.h>
|
||||
#include <osmocom/core/socket.h>
|
||||
|
||||
#include <osmocom/pfcp/pfcp_endpoint.h>
|
||||
#include <osmocom/pfcp/pfcp_msg.h>
|
||||
|
||||
#include <osmocom/vty/vty.h>
|
||||
#include <osmocom/vty/command.h>
|
||||
|
||||
#include "pfcp_tool.h"
|
||||
|
||||
enum pfcp_tool_vty_node {
|
||||
PEER_NODE = _LAST_OSMOVTY_NODE + 1,
|
||||
SESSION_NODE,
|
||||
};
|
||||
|
||||
DEFUN(c_local_addr, c_local_addr_cmd,
|
||||
"local-addr IP_ADDR",
|
||||
"Set the local IP address to bind on for PFCP; see also 'listen'\n"
|
||||
"IP address\n")
|
||||
{
|
||||
if (g_pfcp_tool->ep != NULL) {
|
||||
vty_out(vty, "Already listening on %s%s",
|
||||
osmo_sockaddr_to_str_c(OTC_SELECT, &g_pfcp_tool->ep->cfg.local_addr),
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
osmo_talloc_replace_string(g_pfcp_tool, &g_pfcp_tool->vty_cfg.local_ip, argv[0]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(c_listen, c_listen_cmd,
|
||||
"listen",
|
||||
"Bind local PFCP port and listen; see also 'local-addr'\n")
|
||||
{
|
||||
struct osmo_sockaddr_str local_addr;
|
||||
int rc;
|
||||
|
||||
OSMO_ASSERT(g_pfcp_tool);
|
||||
if (g_pfcp_tool->ep != NULL) {
|
||||
vty_out(vty, "Already listening on %s%s",
|
||||
osmo_sockaddr_to_str_c(OTC_SELECT, &g_pfcp_tool->ep->cfg.local_addr),
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
g_pfcp_tool->ep = osmo_pfcp_endpoint_create(g_pfcp_tool, g_pfcp_tool);
|
||||
if (!g_pfcp_tool->ep) {
|
||||
vty_out(vty, "Failed to allocate PFCP endpoint.%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
g_pfcp_tool->ep->rx_msg = pfcp_tool_rx_msg;
|
||||
g_pfcp_tool->ep->seq_nr_state = rand();
|
||||
|
||||
/* Translate address string from VTY config to osmo_sockaddr: first read into osmo_sockaddr_str, then write to
|
||||
* osmo_sockaddr. */
|
||||
osmo_sockaddr_str_from_str(&local_addr, g_pfcp_tool->vty_cfg.local_ip,
|
||||
g_pfcp_tool->vty_cfg.local_port);
|
||||
osmo_sockaddr_str_to_sockaddr(&local_addr, &g_pfcp_tool->ep->cfg.local_addr.u.sas);
|
||||
|
||||
/* Store this address as the local PFCP Node Id */
|
||||
osmo_pfcp_ie_node_id_from_osmo_sockaddr(&g_pfcp_tool->ep->cfg.local_node_id, &g_pfcp_tool->ep->cfg.local_addr);
|
||||
|
||||
rc = osmo_pfcp_endpoint_bind(g_pfcp_tool->ep);
|
||||
if (rc) {
|
||||
vty_out(vty, "Failed to bind PFCP endpoint on %s: %s%s\n",
|
||||
osmo_sockaddr_to_str_c(OTC_SELECT, &g_pfcp_tool->ep->cfg.local_addr), strerror(rc),
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(c_sleep, c_sleep_cmd,
|
||||
"sleep <0-999999> [<0-999>]",
|
||||
"Let some time pass\n"
|
||||
"Seconds to wait\n")
|
||||
{
|
||||
int secs = atoi(argv[0]);
|
||||
int msecs = 0;
|
||||
struct osmo_timer_list t = {};
|
||||
if (argc > 1)
|
||||
msecs = atoi(argv[1]);
|
||||
|
||||
vty_out(vty, "zzZ %d.%03ds...%s", secs, msecs, VTY_NEWLINE);
|
||||
vty_flush(vty);
|
||||
|
||||
osmo_timer_setup(&t, NULL, NULL);
|
||||
osmo_timer_schedule(&t, secs, msecs * 1000);
|
||||
|
||||
/* Still operate the message pump while waiting for time to pass */
|
||||
while (t.active && !osmo_select_shutdown_done()) {
|
||||
if (pfcp_tool_mainloop())
|
||||
break;
|
||||
}
|
||||
|
||||
osmo_timer_del(&t);
|
||||
vty_out(vty, "...zzZ %d.%03ds%s", secs, msecs, VTY_NEWLINE);
|
||||
vty_flush(vty);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static struct cmd_node peer_node = {
|
||||
PEER_NODE,
|
||||
"%s(peer)# ",
|
||||
1,
|
||||
};
|
||||
|
||||
DEFUN(peer, peer_cmd,
|
||||
"pfcp-peer REMOTE_ADDR",
|
||||
"Enter the 'peer' node for the given remote address\n"
|
||||
"Remote PFCP peer's IP address\n")
|
||||
{
|
||||
struct pfcp_tool_peer *peer;
|
||||
struct osmo_sockaddr_str remote_addr_str;
|
||||
struct osmo_sockaddr remote_addr;
|
||||
|
||||
osmo_sockaddr_str_from_str(&remote_addr_str, argv[0], OSMO_PFCP_PORT);
|
||||
osmo_sockaddr_str_to_sockaddr(&remote_addr_str, (struct sockaddr_storage*)&remote_addr);
|
||||
|
||||
peer = pfcp_tool_peer_find_or_create(&remote_addr);
|
||||
|
||||
vty->index = peer;
|
||||
vty->node = PEER_NODE;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#define TX_STR "Send a PFCP message to a peer\n"
|
||||
|
||||
DEFUN(peer_tx_heartbeat, peer_tx_heartbeat_cmd,
|
||||
"tx heartbeat",
|
||||
TX_STR "Send a Heartbeat Request\n")
|
||||
{
|
||||
struct pfcp_tool_peer *peer = vty->index;
|
||||
int rc;
|
||||
|
||||
if (!g_pfcp_tool->ep) {
|
||||
vty_out(vty, "Endpoint not configured%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
vty_out(vty, "Tx Heartbeat Request to %s%s",
|
||||
osmo_sockaddr_to_str_c(OTC_SELECT, &peer->remote_addr), VTY_NEWLINE);
|
||||
|
||||
rc = osmo_pfcp_endpoint_tx_heartbeat_req(g_pfcp_tool->ep, &peer->remote_addr);
|
||||
if (rc) {
|
||||
vty_out(vty, "Failed to transmit: %s%s", strerror(-rc), VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(peer_tx_assoc_setup_req, peer_tx_assoc_setup_req_cmd,
|
||||
"tx assoc-setup-req",
|
||||
TX_STR "Send an Association Setup Request\n")
|
||||
{
|
||||
struct pfcp_tool_peer *peer = vty->index;
|
||||
int rc;
|
||||
struct osmo_pfcp_msg *m;
|
||||
|
||||
if (!g_pfcp_tool->ep) {
|
||||
vty_out(vty, "Endpoint not configured%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
m = osmo_pfcp_msg_alloc_tx(OTC_SELECT, &peer->remote_addr, &g_pfcp_tool->ep->cfg.local_node_id, NULL,
|
||||
OSMO_PFCP_MSGT_ASSOC_SETUP_REQ);
|
||||
m->ies.assoc_setup_req.recovery_time_stamp = g_pfcp_tool->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);
|
||||
|
||||
rc = peer_tx(peer, m);
|
||||
if (rc) {
|
||||
vty_out(vty, "Failed to transmit: %s%s", strerror(-rc), VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(peer_retrans_req, peer_retrans_req_cmd,
|
||||
"retrans (req|resp)",
|
||||
"Retransmit the last sent message\n" "Retransmit the last sent PFCP Request\n"
|
||||
"Retransmit the last sent PFCP Response\n")
|
||||
{
|
||||
struct pfcp_tool_peer *peer = vty->index;
|
||||
int rc;
|
||||
struct osmo_pfcp_msg *m;
|
||||
|
||||
if (!g_pfcp_tool->ep) {
|
||||
vty_out(vty, "Endpoint not configured%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
m = osmo_pfcp_msg_alloc_tx(OTC_SELECT, &peer->remote_addr, &g_pfcp_tool->ep->cfg.local_node_id, NULL, 0);
|
||||
if (strcmp(argv[0], "req") == 0)
|
||||
*m = peer->last_req;
|
||||
else
|
||||
*m = peer->last_resp;
|
||||
|
||||
OSMO_LOG_PFCP_MSG(m, LOGL_DEBUG, "retrans %s\n", argv[0]);
|
||||
|
||||
rc = osmo_pfcp_endpoint_tx_data(g_pfcp_tool->ep, m);
|
||||
if (rc) {
|
||||
vty_out(vty, "Failed to transmit: %s%s", strerror(-rc), VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static struct cmd_node session_node = {
|
||||
SESSION_NODE,
|
||||
"%s(session)# ",
|
||||
1,
|
||||
};
|
||||
|
||||
DEFUN(session, session_cmd,
|
||||
"session [(endecaps|tunmap)] [<0-18446744073709551615>]",
|
||||
"Enter the 'session' node for the given SEID\n"
|
||||
"Set up GTP tunnel encapsulation/decapsulation (default)\n"
|
||||
"Set up GTP tunnel mapping\n"
|
||||
"local Session Endpoint ID\n")
|
||||
{
|
||||
struct pfcp_tool_peer *peer = vty->index;
|
||||
struct pfcp_tool_session *session;
|
||||
enum up_gtp_action_kind gtp_action = UP_GTP_U_ENDECAPS;
|
||||
|
||||
if (argc > 0 && !strcmp(argv[0], "tunmap"))
|
||||
gtp_action = UP_GTP_U_TUNMAP;
|
||||
|
||||
if (argc > 1)
|
||||
session = pfcp_tool_session_find_or_create(peer, atoll(argv[1]), gtp_action);
|
||||
else
|
||||
session = pfcp_tool_session_find_or_create(peer, peer_new_seid(peer), gtp_action);
|
||||
|
||||
vty->index = session;
|
||||
vty->node = SESSION_NODE;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(s_ue, s_ue_cmd,
|
||||
"ue ip A.B.C.D",
|
||||
"Setup the UE as it appears towards the Core network in plain IP traffic\n"
|
||||
"IP address assigned to the UE\n")
|
||||
{
|
||||
struct pfcp_tool_session *session = vty->index;
|
||||
if (osmo_sockaddr_str_from_str2(&session->core.ue_addr, argv[0])) {
|
||||
vty_out(vty, "Error setting UE IP address%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(s_teid, s_teid_cmd,
|
||||
"gtp (access|core) teid local <0-4294967295> remote <0-4294967295>",
|
||||
"Setup TEID used in GTP\n"
|
||||
"Set the TEIDs towards the ACCESS network (towards the radio network and the actual UE)\n"
|
||||
"Set the TEIDs towards the CORE network (towards the internet)\n"
|
||||
"Local TEID, which the UPF expects to see in incoming GTP packets\n"
|
||||
"Local TEID, when 0 tell the UPF to choose (PFCP: FAR F-TEID: CHOOSE=1)\n"
|
||||
"Remote TEID, which the UPF sends out in GTP packets\n"
|
||||
"Remote TEID, which the GTP peer has assigned for itself\n")
|
||||
{
|
||||
struct pfcp_tool_session *session = vty->index;
|
||||
struct pfcp_tool_teid_pair *dst;
|
||||
if (!strcmp(argv[0], "access"))
|
||||
dst = &session->access.teid;
|
||||
else
|
||||
dst = &session->core.teid;
|
||||
*dst = (struct pfcp_tool_teid_pair){
|
||||
.local = atoi(argv[1]),
|
||||
.remote = atoi(argv[2]),
|
||||
};
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(s_gtp, s_gtp_cmd,
|
||||
"gtp (access|core) ip A.B.C.D",
|
||||
"Setup GTP peer\n"
|
||||
"Set the GTP peer towards the ACCESS network (towards the radio network and the actual UE)\n"
|
||||
"Set the GTP peer towards the CORE network (towards the internet)\n"
|
||||
"Set the GTP peer IP address, where to send GTP packets to / receive GTP packets from\n"
|
||||
"GTP peer IP address\n")
|
||||
{
|
||||
struct pfcp_tool_session *session = vty->index;
|
||||
struct osmo_sockaddr_str *dst;
|
||||
if (!strcmp(argv[0], "access"))
|
||||
dst = &session->access.gtp_ip;
|
||||
else
|
||||
dst = &session->core.gtp_ip;
|
||||
if (osmo_sockaddr_str_from_str2(dst, argv[1])) {
|
||||
vty_out(vty, "Error setting GTP IP address%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
int session_endecaps_tx_est_req(struct vty *vty, const char **argv, int argc)
|
||||
{
|
||||
struct pfcp_tool_session *session = vty->index;
|
||||
struct pfcp_tool_peer *peer = session->peer;
|
||||
int rc;
|
||||
struct osmo_pfcp_msg *m;
|
||||
struct osmo_pfcp_ie_f_teid f_teid_access_local;
|
||||
struct osmo_pfcp_ie_outer_header_creation ohc_access;
|
||||
struct osmo_pfcp_ie_apply_action aa = {};
|
||||
struct osmo_sockaddr ue_addr;
|
||||
struct osmo_pfcp_ie_f_seid cp_f_seid;
|
||||
|
||||
if (!g_pfcp_tool->ep) {
|
||||
vty_out(vty, "Endpoint not configured%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (argc > 0 && !strcmp("drop", argv[0]))
|
||||
osmo_pfcp_bits_set(aa.bits, OSMO_PFCP_APPLY_ACTION_DROP, true);
|
||||
else
|
||||
osmo_pfcp_bits_set(aa.bits, OSMO_PFCP_APPLY_ACTION_FORW, true);
|
||||
|
||||
if (osmo_sockaddr_str_to_sockaddr(&session->core.ue_addr, &ue_addr.u.sas)) {
|
||||
vty_out(vty, "Error in UE IP%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (session->access.teid.local == 0) {
|
||||
f_teid_access_local = (struct osmo_pfcp_ie_f_teid){
|
||||
.choose_flag = true,
|
||||
.choose = {
|
||||
.ipv4_addr = true,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
f_teid_access_local = (struct osmo_pfcp_ie_f_teid){
|
||||
.fixed = {
|
||||
.teid = session->access.teid.local,
|
||||
.ip_addr = {
|
||||
.v4_present = true,
|
||||
.v4 = g_pfcp_tool->ep->cfg.local_addr,
|
||||
},
|
||||
},
|
||||
};
|
||||
if (osmo_sockaddr_str_to_sockaddr(&session->access.gtp_ip, &f_teid_access_local.fixed.ip_addr.v4.u.sas)) {
|
||||
vty_out(vty, "Error in GTP IP towards Access%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
}
|
||||
|
||||
ohc_access = (struct osmo_pfcp_ie_outer_header_creation){
|
||||
.teid_present = true,
|
||||
.teid = session->access.teid.remote,
|
||||
.ip_addr.v4_present = true,
|
||||
};
|
||||
osmo_pfcp_bits_set(ohc_access.desc_bits, OSMO_PFCP_OUTER_HEADER_CREATION_GTP_U_UDP_IPV4, true);
|
||||
if (osmo_sockaddr_str_to_sockaddr(&session->access.gtp_ip, &ohc_access.ip_addr.v4.u.sas)) {
|
||||
vty_out(vty, "Error in GTP IP towards Access%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
cp_f_seid = (struct osmo_pfcp_ie_f_seid){
|
||||
.seid = session->cp_seid,
|
||||
};
|
||||
osmo_pfcp_ip_addrs_set(&cp_f_seid.ip_addr, &g_pfcp_tool->ep->cfg.local_addr);
|
||||
|
||||
m = osmo_pfcp_msg_alloc_tx(OTC_SELECT, &peer->remote_addr, &g_pfcp_tool->ep->cfg.local_node_id, NULL,
|
||||
OSMO_PFCP_MSGT_SESSION_EST_REQ);
|
||||
m->h.seid_present = true;
|
||||
/* the UPF has yet to assign a SEID for itself, no matter what SEID we (the CPF) use for this session */
|
||||
m->h.seid = 0;
|
||||
/* GTP encapsulation decapsulation: remove header from ACCESS to CORE, add header from CORE towards ACCESS */
|
||||
m->ies.session_est_req = (struct osmo_pfcp_msg_session_est_req){
|
||||
.node_id = m->ies.session_est_req.node_id,
|
||||
.cp_f_seid_present = true,
|
||||
.cp_f_seid = cp_f_seid,
|
||||
.create_pdr_count = 2,
|
||||
.create_pdr = {
|
||||
{
|
||||
.pdr_id = 1,
|
||||
.precedence = 255,
|
||||
.pdi = {
|
||||
.source_iface = OSMO_PFCP_SOURCE_IFACE_CORE,
|
||||
.ue_ip_address_present = true,
|
||||
.ue_ip_address = {
|
||||
.ip_is_destination = true,
|
||||
.ip_addr = {
|
||||
.v4_present = true,
|
||||
.v4 = ue_addr,
|
||||
},
|
||||
},
|
||||
},
|
||||
.far_id_present = true,
|
||||
.far_id = 1,
|
||||
},
|
||||
{
|
||||
.pdr_id = 2,
|
||||
.precedence = 255,
|
||||
.pdi = {
|
||||
.source_iface = OSMO_PFCP_SOURCE_IFACE_ACCESS,
|
||||
.local_f_teid_present = true,
|
||||
.local_f_teid = f_teid_access_local,
|
||||
},
|
||||
.outer_header_removal_present = true,
|
||||
.outer_header_removal = {
|
||||
.desc = OSMO_PFCP_OUTER_HEADER_REMOVAL_GTP_U_UDP_IPV4,
|
||||
},
|
||||
.far_id_present = true,
|
||||
.far_id = 2,
|
||||
},
|
||||
},
|
||||
.create_far_count = 2,
|
||||
.create_far = {
|
||||
{
|
||||
.far_id = 1,
|
||||
.forw_params_present = true,
|
||||
.forw_params = {
|
||||
.destination_iface = OSMO_PFCP_DEST_IFACE_ACCESS,
|
||||
.outer_header_creation_present = true,
|
||||
.outer_header_creation = ohc_access,
|
||||
},
|
||||
.apply_action = aa,
|
||||
},
|
||||
{
|
||||
.far_id = 2,
|
||||
.forw_params_present = true,
|
||||
.forw_params = {
|
||||
.destination_iface = OSMO_PFCP_DEST_IFACE_CORE,
|
||||
},
|
||||
.apply_action = aa,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
rc = peer_tx(peer, m);
|
||||
if (rc) {
|
||||
vty_out(vty, "Failed to transmit: %s%s", strerror(-rc), VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
int session_tunmap_tx_est_req(struct vty *vty, const char **argv, int argc)
|
||||
{
|
||||
struct pfcp_tool_session *session = vty->index;
|
||||
struct pfcp_tool_peer *peer = session->peer;
|
||||
int rc;
|
||||
struct osmo_pfcp_msg *m;
|
||||
|
||||
struct osmo_pfcp_ie_f_seid cp_f_seid;
|
||||
|
||||
struct osmo_pfcp_ie_f_teid f_teid_access_local;
|
||||
struct osmo_pfcp_ie_outer_header_creation ohc_access;
|
||||
|
||||
struct osmo_pfcp_ie_f_teid f_teid_core_local;
|
||||
struct osmo_pfcp_ie_outer_header_creation ohc_core;
|
||||
|
||||
struct osmo_pfcp_ie_apply_action aa = {};
|
||||
|
||||
if (!g_pfcp_tool->ep) {
|
||||
vty_out(vty, "Endpoint not configured%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (argc > 0 && !strcmp("drop", argv[0]))
|
||||
osmo_pfcp_bits_set(aa.bits, OSMO_PFCP_APPLY_ACTION_DROP, true);
|
||||
else
|
||||
osmo_pfcp_bits_set(aa.bits, OSMO_PFCP_APPLY_ACTION_FORW, true);
|
||||
|
||||
if (session->access.teid.local == 0) {
|
||||
f_teid_access_local = (struct osmo_pfcp_ie_f_teid){
|
||||
.choose_flag = true,
|
||||
.choose = {
|
||||
.ipv4_addr = true,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
f_teid_access_local = (struct osmo_pfcp_ie_f_teid){
|
||||
.fixed = {
|
||||
.teid = session->access.teid.local,
|
||||
.ip_addr = {
|
||||
.v4_present = true,
|
||||
.v4 = g_pfcp_tool->ep->cfg.local_addr,
|
||||
},
|
||||
},
|
||||
};
|
||||
if (osmo_sockaddr_str_to_sockaddr(&session->access.gtp_ip, &f_teid_access_local.fixed.ip_addr.v4.u.sas)) {
|
||||
vty_out(vty, "Error in GTP IP towards Access%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
}
|
||||
|
||||
ohc_access = (struct osmo_pfcp_ie_outer_header_creation){
|
||||
.teid_present = true,
|
||||
.teid = session->access.teid.remote,
|
||||
.ip_addr.v4_present = true,
|
||||
};
|
||||
osmo_pfcp_bits_set(ohc_access.desc_bits, OSMO_PFCP_OUTER_HEADER_CREATION_GTP_U_UDP_IPV4, true);
|
||||
if (osmo_sockaddr_str_to_sockaddr(&session->access.gtp_ip, &ohc_access.ip_addr.v4.u.sas)) {
|
||||
vty_out(vty, "Error in GTP IP towards Access%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (session->core.teid.local == 0) {
|
||||
f_teid_core_local = (struct osmo_pfcp_ie_f_teid){
|
||||
.choose_flag = true,
|
||||
.choose = {
|
||||
.ipv4_addr = true,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
f_teid_core_local = (struct osmo_pfcp_ie_f_teid){
|
||||
.fixed = {
|
||||
.teid = session->core.teid.local,
|
||||
.ip_addr = {
|
||||
.v4_present = true,
|
||||
.v4 = g_pfcp_tool->ep->cfg.local_addr,
|
||||
},
|
||||
},
|
||||
};
|
||||
if (osmo_sockaddr_str_to_sockaddr(&session->core.gtp_ip, &f_teid_core_local.fixed.ip_addr.v4.u.sas)) {
|
||||
vty_out(vty, "Error in GTP IP towards Core%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
}
|
||||
ohc_core = (struct osmo_pfcp_ie_outer_header_creation){
|
||||
.teid_present = true,
|
||||
.teid = session->core.teid.remote,
|
||||
.ip_addr.v4_present = true,
|
||||
};
|
||||
osmo_pfcp_bits_set(ohc_core.desc_bits, OSMO_PFCP_OUTER_HEADER_CREATION_GTP_U_UDP_IPV4, true);
|
||||
if (osmo_sockaddr_str_to_sockaddr(&session->core.gtp_ip, &ohc_core.ip_addr.v4.u.sas)) {
|
||||
vty_out(vty, "Error in GTP IP towards Core%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
cp_f_seid = (struct osmo_pfcp_ie_f_seid){
|
||||
.seid = session->cp_seid,
|
||||
};
|
||||
osmo_pfcp_ip_addrs_set(&cp_f_seid.ip_addr, &g_pfcp_tool->ep->cfg.local_addr);
|
||||
|
||||
m = osmo_pfcp_msg_alloc_tx(OTC_SELECT, &peer->remote_addr, &g_pfcp_tool->ep->cfg.local_node_id, NULL,
|
||||
OSMO_PFCP_MSGT_SESSION_EST_REQ);
|
||||
m->h.seid_present = true;
|
||||
m->h.seid = 0;
|
||||
/* GTP tunmap: remove header from both directions, and add header in both directions */
|
||||
m->ies.session_est_req = (struct osmo_pfcp_msg_session_est_req){
|
||||
.node_id = m->ies.session_est_req.node_id,
|
||||
.cp_f_seid_present = true,
|
||||
.cp_f_seid = cp_f_seid,
|
||||
.create_pdr_count = 2,
|
||||
.create_pdr = {
|
||||
{
|
||||
.pdr_id = 1,
|
||||
.precedence = 255,
|
||||
.pdi = {
|
||||
.source_iface = OSMO_PFCP_SOURCE_IFACE_CORE,
|
||||
.local_f_teid_present = true,
|
||||
.local_f_teid = f_teid_core_local,
|
||||
},
|
||||
.outer_header_removal_present = true,
|
||||
.outer_header_removal = {
|
||||
.desc = OSMO_PFCP_OUTER_HEADER_REMOVAL_GTP_U_UDP_IPV4,
|
||||
},
|
||||
.far_id_present = true,
|
||||
.far_id = 1,
|
||||
},
|
||||
{
|
||||
.pdr_id = 2,
|
||||
.precedence = 255,
|
||||
.pdi = {
|
||||
.source_iface = OSMO_PFCP_SOURCE_IFACE_ACCESS,
|
||||
.local_f_teid_present = true,
|
||||
.local_f_teid = f_teid_access_local,
|
||||
},
|
||||
.outer_header_removal_present = true,
|
||||
.outer_header_removal = {
|
||||
.desc = OSMO_PFCP_OUTER_HEADER_REMOVAL_GTP_U_UDP_IPV4,
|
||||
},
|
||||
.far_id_present = true,
|
||||
.far_id = 2,
|
||||
},
|
||||
},
|
||||
.create_far_count = 2,
|
||||
.create_far = {
|
||||
{
|
||||
.far_id = 1,
|
||||
.forw_params_present = true,
|
||||
.forw_params = {
|
||||
.destination_iface = OSMO_PFCP_DEST_IFACE_ACCESS,
|
||||
.outer_header_creation_present = true,
|
||||
.outer_header_creation = ohc_access,
|
||||
},
|
||||
.apply_action = aa,
|
||||
},
|
||||
{
|
||||
.far_id = 2,
|
||||
.forw_params_present = true,
|
||||
.forw_params = {
|
||||
.destination_iface = OSMO_PFCP_DEST_IFACE_CORE,
|
||||
.outer_header_creation_present = true,
|
||||
.outer_header_creation = ohc_core,
|
||||
},
|
||||
.apply_action = aa,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
rc = peer_tx(peer, m);
|
||||
if (rc) {
|
||||
vty_out(vty, "Failed to transmit: %s%s", strerror(-rc), VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(session_tx_est_req, session_tx_est_req_cmd,
|
||||
"tx session-est-req [(forw|drop)]",
|
||||
TX_STR "Send a Session Establishment Request\n"
|
||||
"Set FAR to FORW = 1 (default)\n"
|
||||
"Set FAR to DROP = 1\n")
|
||||
{
|
||||
struct pfcp_tool_session *session = vty->index;
|
||||
switch (session->gtp_action) {
|
||||
case UP_GTP_U_ENDECAPS:
|
||||
return session_endecaps_tx_est_req(vty, argv, argc);
|
||||
case UP_GTP_U_TUNMAP:
|
||||
return session_tunmap_tx_est_req(vty, argv, argc);
|
||||
default:
|
||||
vty_out(vty, "unknown gtp action%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
}
|
||||
|
||||
DEFUN(session_tx_mod_req, session_tx_mod_req_cmd,
|
||||
"tx session-mod-req far [(forw|drop)]",
|
||||
TX_STR "Send a Session Modification Request\n"
|
||||
"Set FAR to FORW = 1\n"
|
||||
"Set FAR to DROP = 1\n")
|
||||
{
|
||||
struct pfcp_tool_session *session = vty->index;
|
||||
struct pfcp_tool_peer *peer = session->peer;
|
||||
int rc;
|
||||
struct osmo_pfcp_msg *m;
|
||||
struct osmo_pfcp_ie_apply_action aa = {};
|
||||
struct osmo_pfcp_ie_f_seid cp_f_seid;
|
||||
|
||||
if (!g_pfcp_tool->ep) {
|
||||
vty_out(vty, "Endpoint not configured%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (argc > 0 && !strcmp("drop", argv[0]))
|
||||
osmo_pfcp_bits_set(aa.bits, OSMO_PFCP_APPLY_ACTION_DROP, true);
|
||||
else
|
||||
osmo_pfcp_bits_set(aa.bits, OSMO_PFCP_APPLY_ACTION_FORW, true);
|
||||
|
||||
cp_f_seid = (struct osmo_pfcp_ie_f_seid){
|
||||
.seid = session->cp_seid,
|
||||
};
|
||||
osmo_pfcp_ip_addrs_set(&cp_f_seid.ip_addr, &g_pfcp_tool->ep->cfg.local_addr);
|
||||
|
||||
m = osmo_pfcp_msg_alloc_tx(OTC_SELECT, &peer->remote_addr, &g_pfcp_tool->ep->cfg.local_node_id, NULL,
|
||||
OSMO_PFCP_MSGT_SESSION_MOD_REQ);
|
||||
m->h.seid_present = true;
|
||||
m->h.seid = session->up_f_seid.seid;
|
||||
m->ies.session_mod_req = (struct osmo_pfcp_msg_session_mod_req){
|
||||
.cp_f_seid_present = true,
|
||||
.cp_f_seid = cp_f_seid,
|
||||
.upd_far_count = 2,
|
||||
.upd_far = {
|
||||
{
|
||||
.far_id = 1,
|
||||
.apply_action_present = true,
|
||||
.apply_action = aa,
|
||||
},
|
||||
{
|
||||
.far_id = 2,
|
||||
.apply_action_present = true,
|
||||
.apply_action = aa,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
rc = peer_tx(peer, m);
|
||||
if (rc) {
|
||||
vty_out(vty, "Failed to transmit: %s%s", strerror(-rc), VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(session_tx_del_req, session_tx_del_req_cmd,
|
||||
"tx session-del-req",
|
||||
TX_STR "Send a Session Deletion Request\n")
|
||||
{
|
||||
struct pfcp_tool_session *session = vty->index;
|
||||
struct pfcp_tool_peer *peer = session->peer;
|
||||
int rc;
|
||||
struct osmo_pfcp_msg *m;
|
||||
|
||||
if (!g_pfcp_tool->ep) {
|
||||
vty_out(vty, "Endpoint not configured%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
m = osmo_pfcp_msg_alloc_tx(OTC_SELECT, &peer->remote_addr, &g_pfcp_tool->ep->cfg.local_node_id, NULL,
|
||||
OSMO_PFCP_MSGT_SESSION_DEL_REQ);
|
||||
m->h.seid_present = true;
|
||||
m->h.seid = session->up_f_seid.seid;
|
||||
|
||||
rc = peer_tx(peer, m);
|
||||
if (rc) {
|
||||
vty_out(vty, "Failed to transmit: %s%s", strerror(-rc), VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static void install_ve_and_config(struct cmd_element *cmd)
|
||||
{
|
||||
install_element_ve(cmd);
|
||||
install_element(CONFIG_NODE, cmd);
|
||||
}
|
||||
|
||||
void pfcp_tool_vty_init_cfg()
|
||||
{
|
||||
OSMO_ASSERT(g_pfcp_tool != NULL);
|
||||
|
||||
install_ve_and_config(&c_local_addr_cmd);
|
||||
install_ve_and_config(&c_listen_cmd);
|
||||
}
|
||||
|
||||
void pfcp_tool_vty_init_cmds()
|
||||
{
|
||||
OSMO_ASSERT(g_pfcp_tool != NULL);
|
||||
|
||||
install_ve_and_config(&c_sleep_cmd);
|
||||
|
||||
install_ve_and_config(&peer_cmd);
|
||||
install_node(&peer_node, NULL);
|
||||
|
||||
install_element(PEER_NODE, &c_sleep_cmd);
|
||||
install_element(PEER_NODE, &peer_tx_heartbeat_cmd);
|
||||
install_element(PEER_NODE, &peer_tx_assoc_setup_req_cmd);
|
||||
install_element(PEER_NODE, &peer_retrans_req_cmd);
|
||||
|
||||
install_element(PEER_NODE, &session_cmd);
|
||||
install_node(&session_node, NULL);
|
||||
install_element(SESSION_NODE, &c_sleep_cmd);
|
||||
install_element(SESSION_NODE, &session_tx_est_req_cmd);
|
||||
install_element(SESSION_NODE, &session_tx_mod_req_cmd);
|
||||
install_element(SESSION_NODE, &session_tx_del_req_cmd);
|
||||
install_element(SESSION_NODE, &s_ue_cmd);
|
||||
install_element(SESSION_NODE, &s_gtp_cmd);
|
||||
install_element(SESSION_NODE, &s_teid_cmd);
|
||||
}
|
||||
Reference in New Issue
Block a user