1 Commits

Author SHA1 Message Date
Neels Janosch Hofmeyr
c6c96707d3 osmo-upf: add VTY 'gtp-echo' command
Allow sending GTPv1-U Echo Requests to GTP peers via new VTY command

  gtp-echo send to (A.B.C.D|X:X::X:X)
  gtp-echo send to (A.B.C.D|X:X::X:X) local-ip (A.B.C.D|X:X::X:X)
  gtp-echo send to (A.B.C.D|X:X::X:X) local-dev DEV_NAME

Related: OS#6541
Change-Id: I970dccd7a27b098eea9e660822e24e2c4b059fc6
2024-08-23 03:40:04 +02:00
5 changed files with 186 additions and 0 deletions

View File

@@ -117,6 +117,7 @@ struct g_upf {
struct {
uint32_t next_local_teid_state;
uint16_t next_echo_seq_nr;
} gtp;
struct llist_head netinst;

View File

@@ -2,3 +2,4 @@
#pragma once
int upf_gtpu_echo_setup(struct upf_gtp_dev *dev);
int upf_gtpu_echo_req_tx(struct upf_gtp_dev *dev, const struct osmo_sockaddr *remote, uint16_t seq_nr);

View File

@@ -122,6 +122,45 @@ static int tx_echo_resp(struct upf_gtp_dev *dev, const struct osmo_sockaddr *rem
return rc;
}
int upf_gtpu_echo_req_tx(struct upf_gtp_dev *dev, const struct osmo_sockaddr *remote, uint16_t seq_nr)
{
struct gtp1u_hdr *tx_h;
int rc;
#define GTP_ECHO_REQ_SIZE ((size_t)(sizeof(struct gtp1u_hdr) + 2))
uint8_t msgbuf[GTP_ECHO_REQ_SIZE];
tx_h = (void *)msgbuf;
*tx_h = (struct gtp1u_hdr){
/* 3GPP TS 29.281 5.1 defines that the ECHO REQ & RESP shall contain a sequence nr */
.s = 1,
.pt = 1,
.version = 1,
.msg_type = GTP1U_MSGTYPE_ECHO_REQ,
.ext = {
.seq_nr = seq_nr,
},
};
/* ECHO REQUEST shall contain a recovery counter */
tx_h->data2[0] = GTP1U_IEI_RECOVERY;
tx_h->data2[1] = g_upf->tunend.recovery_count;
osmo_store16be(GTP_ECHO_REQ_SIZE - offsetof(struct gtp1u_hdr, data1), &tx_h->length);
rc = sendto(dev->gtpv1.ofd.fd, msgbuf, GTP_ECHO_REQ_SIZE, 0, &remote->u.sa, sizeof(*remote));
if (rc < 0) {
rc = -errno;
LOG_GTP_DEV(dev, LOGL_ERROR, "GTP1-U sendto(len=%zu, to=%s): %s\n", GTP_ECHO_REQ_SIZE,
osmo_sockaddr_to_str(remote), strerror(-rc));
} else {
rc = 0;
}
LOG_GTP_DEV(dev, LOGL_INFO, "<- %s: tx GTP1-U Echo Request: seq_nr=%u recovery_count=%u\n",
osmo_sockaddr_to_str(remote), seq_nr, g_upf->tunend.recovery_count);
return rc;
}
int upf_gtpu_echo_read_cb(struct osmo_fd *ofd, unsigned int what)
{
struct upf_gtp_dev *dev = ofd->data;

View File

@@ -38,6 +38,7 @@
#include <osmocom/upf/up_session.h>
#include <osmocom/upf/up_gtp_action.h>
#include <osmocom/upf/netinst.h>
#include <osmocom/upf/upf_gtpu_echo.h>
enum upf_vty_node {
PFCP_NODE = _LAST_OSMOVTY_NODE + 1,
@@ -486,6 +487,105 @@ DEFUN(show_session, show_session_cmd,
return CMD_SUCCESS;
}
/* variant:
* 0 "gtp-echo send to (A.B.C.D|X:X::X:X)"
* 1 "gtp-echo send to (A.B.C.D|X:X::X:X) local-ip (A.B.C.D|X:X::X:X)"
* 2 "gtp-echo send to (A.B.C.D|X:X::X:X) local-dev DEV_NAME"
*/
int _gtp_echo_tx(struct vty *vty, int variant, int argc, const char **argv)
{
struct osmo_sockaddr_str addr;
struct osmo_sockaddr osa_remote;
struct osmo_sockaddr osa_local;
struct upf_gtp_dev *gtp_dev = NULL;
const char *remote_str = argv[0];
const char *local_str = NULL;
if (argc > 1)
local_str = argv[1];
/* GTP can be received on port 2152 only, i.e. the remote port must be 2152. (The sending port is allowed to
* differ). */
if (osmo_sockaddr_str_from_str(&addr, remote_str, 2152)
|| osmo_sockaddr_str_to_osa(&addr, &osa_remote)) {
vty_out(vty, "%% Error: cannot send Echo: invalid IP address: %s%s",
osmo_quote_str(remote_str, -1), VTY_NEWLINE);
return CMD_WARNING;
}
switch (variant) {
case 0:
gtp_dev = llist_first_entry_or_null(&g_upf->tunend.devs, struct upf_gtp_dev, entry);
if (!gtp_dev) {
vty_out(vty, "%% Error: cannot send Echo: there is no GTP device%s",
VTY_NEWLINE);
return CMD_WARNING;
}
break;
case 1:
if (osmo_sockaddr_str_from_str(&addr, local_str, 2152)
|| osmo_sockaddr_str_to_osa(&addr, &osa_local)) {
vty_out(vty, "%% Error: cannot send Echo: invalid IP address: %s%s",
osmo_quote_str(local_str, -1), VTY_NEWLINE);
return CMD_WARNING;
}
gtp_dev = upf_gtp_dev_find_by_local_addr(&osa_local);
if (!gtp_dev) {
vty_out(vty, "%% Error: cannot send Echo: this does not seem to be a locally bound GTP address: %s%s",
osmo_sockaddr_to_str_c(OTC_SELECT, &osa_local), VTY_NEWLINE);
return CMD_WARNING;
}
break;
case 2:
gtp_dev = upf_gtp_dev_find_by_name(local_str);
if (!gtp_dev) {
vty_out(vty, "%% Error: cannot send Echo: there is no GTP device by the name of '%s'%s",
local_str, VTY_NEWLINE);
return CMD_WARNING;
}
break;
}
OSMO_ASSERT(gtp_dev);
if (upf_gtpu_echo_req_tx(gtp_dev, &osa_remote, g_upf->gtp.next_echo_seq_nr++)) {
vty_out(vty, "%% Error: Failed to transmit Echo Request (see DGTP logging)%s", VTY_NEWLINE);
return CMD_WARNING;
}
vty_out(vty, "%s -> %s tx Echo Request; for responses, see DGTP logging level INFO%s",
gtp_dev->name, osmo_sockaddr_to_str_c(OTC_SELECT, &osa_remote), VTY_NEWLINE);
return CMD_SUCCESS;
}
#define IP46_STR "IPv4 address\nIPv6 address\n"
#define GTP_ECHO_TX_STR \
"GTP1-U Echo probing\n" \
"Send a GTP1-U Echo Request to a remote peer\n" \
"Send to remote peer's GTP address\n" IP46_STR
DEFUN(gtp_echo_tx, gtp_echo_tx_cmd,
"gtp-echo send to (A.B.C.D|X:X::X:X)",
GTP_ECHO_TX_STR)
{
return _gtp_echo_tx(vty, 0, argc, argv);
}
DEFUN(gtp_echo_tx_local_ip, gtp_echo_tx_local_ip_cmd,
"gtp-echo send to (A.B.C.D|X:X::X:X) local-ip (A.B.C.D|X:X::X:X)",
GTP_ECHO_TX_STR
"Send from local GTP device, chosen by IP address\n"
IP46_STR)
{
return _gtp_echo_tx(vty, 1, argc, argv);
}
DEFUN(gtp_echo_tx_local_dev, gtp_echo_tx_local_dev_cmd,
"gtp-echo send to (A.B.C.D|X:X::X:X) local-dev DEV_NAME",
GTP_ECHO_TX_STR
"Send from local GTP device, chosen by name as configured in 'dev create' or 'dev use'.\n"
"A GTP device name as it appears in the cfg\n")
{
return _gtp_echo_tx(vty, 2, argc, argv);
}
void upf_vty_init()
{
OSMO_ASSERT(g_upf != NULL);
@@ -495,6 +595,9 @@ void upf_vty_init()
install_element_ve(&show_session_cmd);
install_element_ve(&show_netinst_cmd);
install_element_ve(&show_nft_rule_append_cmd);
install_element_ve(&gtp_echo_tx_cmd);
install_element_ve(&gtp_echo_tx_local_ip_cmd);
install_element_ve(&gtp_echo_tx_local_dev_cmd);
install_node(&cfg_pfcp_node, config_write_pfcp);
install_element(CONFIG_NODE, &cfg_pfcp_cmd);

42
tests/gtp-echo.vty Normal file
View File

@@ -0,0 +1,42 @@
OsmoUPF> list
...
gtp-echo send to (A.B.C.D|X:X::X:X)
gtp-echo send to (A.B.C.D|X:X::X:X) local-ip (A.B.C.D|X:X::X:X)
gtp-echo send to (A.B.C.D|X:X::X:X) local-dev DEV_NAME
...
OsmoUPF> enable
OsmoUPF# list
...
gtp-echo send to (A.B.C.D|X:X::X:X)
gtp-echo send to (A.B.C.D|X:X::X:X) local-ip (A.B.C.D|X:X::X:X)
gtp-echo send to (A.B.C.D|X:X::X:X) local-dev DEV_NAME
...
OsmoUPF# configure terminal
OsmoUPF(config)# list
... !gtp-echo
OsmoUPF(config)# end
OsmoUPF# gtp-echo?
gtp-echo GTP1-U Echo probing
OsmoUPF# gtp-echo ?
send Send a GTP1-U Echo Request to a remote peer
OsmoUPF# gtp-echo send ?
to Send to remote peer's GTP address
OsmoUPF# gtp-echo send to ?
A.B.C.D IPv4 address
X:X::X:X IPv6 address
OsmoUPF# gtp-echo send to 1.2.3.4 ?
local-ip Send from local GTP device, chosen by IP address
local-dev Send from local GTP device, chosen by name as configured in 'dev create' or 'dev use'.
<cr>
OsmoUPF# gtp-echo send to 1.2.3.4 local-ip ?
A.B.C.D IPv4 address
X:X::X:X IPv6 address
OsmoUPF# gtp-echo send to 1.2.3.4 local-dev ?
DEV_NAME A GTP device name as it appears in the cfg
OsmoUPF# gtp-echo send to 1.2.3.4
% Error: cannot send Echo: there is no GTP device
OsmoUPF# gtp-echo send to 1.2.3.4 local-ip 1.2.3.4
% Error: cannot send Echo: this does not seem to be a locally bound GTP address: 1.2.3.4:2152
OsmoUPF# gtp-echo send to 1.2.3.4 local-dev apn0
% Error: cannot send Echo: there is no GTP device by the name of 'apn0'