osmith has submitted this change. (
https://gerrit.osmocom.org/c/osmo-upf/+/37830?usp=email )
Change subject: osmo-upf: add VTY 'gtp-echo' command
......................................................................
osmo-upf: add VTY 'gtp-echo' command
Allow sending GTPv1-U Echo Requests to GTP peers via new VTY command
gtp1u-echo send to (A.B.C.D|X:X::X:X)
gtp1u-echo send to (A.B.C.D|X:X::X:X) local-ip (A.B.C.D|X:X::X:X)
gtp1u-echo send to (A.B.C.D|X:X::X:X) local-dev DEV_NAME
Related: OS#6541
Tweaked-by: Oliver Smith <osmith(a)sysmocom.de>
Change-Id: I970dccd7a27b098eea9e660822e24e2c4b059fc6
---
M include/osmocom/upf/upf.h
M include/osmocom/upf/upf_gtpu_echo.h
M src/osmo-upf/upf_gtpu_echo.c
M src/osmo-upf/upf_vty.c
A tests/gtp-echo.vty
5 files changed, 184 insertions(+), 0 deletions(-)
Approvals:
Jenkins Builder: Verified
fixeria: Looks good to me, approved
pespin: Looks good to me, but someone else must approve
diff --git a/include/osmocom/upf/upf.h b/include/osmocom/upf/upf.h
index 145567b..d558600 100644
--- a/include/osmocom/upf/upf.h
+++ b/include/osmocom/upf/upf.h
@@ -118,6 +118,7 @@
struct {
uint32_t next_local_teid_state;
+ uint16_t next_echo_seq_nr;
} gtp;
struct llist_head netinst;
diff --git a/include/osmocom/upf/upf_gtpu_echo.h b/include/osmocom/upf/upf_gtpu_echo.h
index 2575424..2bb7c31 100644
--- a/include/osmocom/upf/upf_gtpu_echo.h
+++ b/include/osmocom/upf/upf_gtpu_echo.h
@@ -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);
diff --git a/src/osmo-upf/upf_gtpu_echo.c b/src/osmo-upf/upf_gtpu_echo.c
index b234065..f4bbb76 100644
--- a/src/osmo-upf/upf_gtpu_echo.c
+++ b/src/osmo-upf/upf_gtpu_echo.c
@@ -122,6 +122,43 @@
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;
+ uint8_t msgbuf[sizeof(struct gtp1u_hdr) + 2];
+
+ 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(sizeof(msgbuf) - offsetof(struct gtp1u_hdr, data1),
&tx_h->length);
+
+ rc = sendto(dev->gtpv1.ofd.fd, msgbuf, sizeof(msgbuf), 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",
sizeof(msgbuf),
+ 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;
diff --git a/src/osmo-upf/upf_vty.c b/src/osmo-upf/upf_vty.c
index 44d14db..9c5f7f0 100644
--- a/src/osmo-upf/upf_vty.c
+++ b/src/osmo-upf/upf_vty.c
@@ -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 @@
return CMD_SUCCESS;
}
+/* variant:
+ * 0 "gtp1u-echo send to (A.B.C.D|X:X::X:X)"
+ * 1 "gtp1u-echo send to (A.B.C.D|X:X::X:X) local-ip (A.B.C.D|X:X::X:X)"
+ * 2 "gtp1u-echo send to (A.B.C.D|X:X::X:X) local-dev DEV_NAME"
+ */
+static 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,
+ "gtp1u-echo send to " VTY_IPV46_CMD,
+ GTP_ECHO_TX_STR)
+{
+ return _gtp_echo_tx(vty, 0, argc, argv);
+}
+
+DEFUN(gtp_echo_tx_local_ip, gtp_echo_tx_local_ip_cmd,
+ "gtp1u-echo send to " VTY_IPV46_CMD " local-ip "
VTY_IPV46_CMD,
+ 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,
+ "gtp1u-echo send to " VTY_IPV46_CMD " 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 @@
install_element_ve(&show_session_cmd);
install_element_ve(&show_netinst_cmd);
install_element_ve(&show_nft_rule_append_cmd);
+ install_element_ve(>p_echo_tx_cmd);
+ install_element_ve(>p_echo_tx_local_ip_cmd);
+ install_element_ve(>p_echo_tx_local_dev_cmd);
install_node(&cfg_pfcp_node, config_write_pfcp);
install_element(CONFIG_NODE, &cfg_pfcp_cmd);
diff --git a/tests/gtp-echo.vty b/tests/gtp-echo.vty
new file mode 100644
index 0000000..e8ffa9c
--- /dev/null
+++ b/tests/gtp-echo.vty
@@ -0,0 +1,42 @@
+OsmoUPF> list
+...
+ gtp1u-echo send to (A.B.C.D|X:X::X:X)
+ gtp1u-echo send to (A.B.C.D|X:X::X:X) local-ip (A.B.C.D|X:X::X:X)
+ gtp1u-echo send to (A.B.C.D|X:X::X:X) local-dev DEV_NAME
+...
+OsmoUPF> enable
+OsmoUPF# list
+...
+ gtp1u-echo send to (A.B.C.D|X:X::X:X)
+ gtp1u-echo send to (A.B.C.D|X:X::X:X) local-ip (A.B.C.D|X:X::X:X)
+ gtp1u-echo send to (A.B.C.D|X:X::X:X) local-dev DEV_NAME
+...
+OsmoUPF# configure terminal
+OsmoUPF(config)# list
+... !gtp1u-echo
+OsmoUPF(config)# end
+
+OsmoUPF# gtp1u-echo?
+ gtp1u-echo GTP1-U Echo probing
+OsmoUPF# gtp1u-echo ?
+ send Send a GTP1-U Echo Request to a remote peer
+OsmoUPF# gtp1u-echo send ?
+ to Send to remote peer's GTP address
+OsmoUPF# gtp1u-echo send to ?
+ A.B.C.D IPv4 address
+ X:X::X:X IPv6 address
+OsmoUPF# gtp1u-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# gtp1u-echo send to 1.2.3.4 local-ip ?
+ A.B.C.D IPv4 address
+ X:X::X:X IPv6 address
+OsmoUPF# gtp1u-echo send to 1.2.3.4 local-dev ?
+ DEV_NAME A GTP device name as it appears in the cfg
+OsmoUPF# gtp1u-echo send to 1.2.3.4
+% Error: cannot send Echo: there is no GTP device
+OsmoUPF# gtp1u-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# gtp1u-echo send to 1.2.3.4 local-dev apn0
+% Error: cannot send Echo: there is no GTP device by the name of 'apn0'
--
To view, visit
https://gerrit.osmocom.org/c/osmo-upf/+/37830?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: osmo-upf
Gerrit-Branch: master
Gerrit-Change-Id: I970dccd7a27b098eea9e660822e24e2c4b059fc6
Gerrit-Change-Number: 37830
Gerrit-PatchSet: 6
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>