jolly has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmo-sigtran/+/42809?usp=email )
Change subject: Add test case to verify proper DSCP settings ......................................................................
Add test case to verify proper DSCP settings
Related: SYS#8071 Change-Id: I6ac965998433b4d8213cce30fc3fcf8fe485a092 --- M .gitignore M configure.ac M tests/Makefile.am A tests/dscp/Makefile.am A tests/dscp/dscp_test.ok A tests/dscp/dscp_test.py A tests/dscp/get_tos_diag.c A tests/dscp/osmo-stp-dscp.cfg M tests/testsuite.at 9 files changed, 248 insertions(+), 1 deletion(-)
git pull ssh://gerrit.osmocom.org:29418/libosmo-sigtran refs/changes/09/42809/1
diff --git a/.gitignore b/.gitignore index 99cb052..8988066 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,7 @@ tests/db/db_test tests/debug/debug_test tests/*/*_test +tests/dscp/get_tos_diag
tests/atconfig tests/package.m4 diff --git a/configure.ac b/configure.ac index f1e1888..0bbc233 100644 --- a/configure.ac +++ b/configure.ac @@ -209,6 +209,7 @@ tests/ss7/Makefile tests/tcap/Makefile tests/vty/Makefile + tests/dscp/Makefile examples/Makefile stp/Makefile doc/Makefile diff --git a/tests/Makefile.am b/tests/Makefile.am index 7927bbd..5e056d4 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = xua m2ua ss7 vty +SUBDIRS = xua m2ua ss7 vty dscp
if BUILD_WITH_TCAP_LOADSHARING SUBDIRS += tcap diff --git a/tests/dscp/Makefile.am b/tests/dscp/Makefile.am new file mode 100644 index 0000000..43b1fcd --- /dev/null +++ b/tests/dscp/Makefile.am @@ -0,0 +1,18 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall $(LIBOSMONETIF_CFLAGS) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) + +AM_LDFLAGS = -no-install +LDADD = $(top_builddir)/src/.libs/libosmo-sigtran.a \ + $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMONETIF_LIBS) $(LIBSCTP_LIBS) + +if BUILD_WITH_TCAP_LOADSHARING +LDADD += $(LIBOSMOASN1TCAP_LIBS) +endif + +EXTRA_DIST = dscp_test.ok dscp_test.py + +check_PROGRAMS = get_tos_diag + +get_tos_diag_SOURCES = get_tos_diag.c + + diff --git a/tests/dscp/dscp_test.ok b/tests/dscp/dscp_test.ok new file mode 100644 index 0000000..66c7bc4 --- /dev/null +++ b/tests/dscp/dscp_test.ok @@ -0,0 +1,9 @@ +starting osmo-stp +started osmo-stp +LISTEN 127.0.0.1:2905 0.0.0.0:0 23 +ESTAB 127.0.0.1:2905 127.0.0.2:2906 23 +OTHER 127.0.0.1:2905 127.0.0.2:2906 23 +ESTAB 127.0.0.2:2906 127.0.0.1:2905 42 +OTHER 127.0.0.2:2906 127.0.0.1:2905 42 +stopping osmo-stp +stopped osmo-stp diff --git a/tests/dscp/dscp_test.py b/tests/dscp/dscp_test.py new file mode 100755 index 0000000..0122257 --- /dev/null +++ b/tests/dscp/dscp_test.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 + +# (C) 2026 by sysmocom s.f.m.c. GmbH +# 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 3 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/. + +import subprocess +import time +import os +import sys +from pathlib import Path + +# Pfade definieren +SCRIPT_DIR = Path(__file__).parent.resolve() +STP_BINARY = SCRIPT_DIR / ".." / ".." / "stp" / "osmo-stp" +CONFIG_FILE = SCRIPT_DIR / "osmo-stp-dscp.cfg" +DIAG_BINARY = SCRIPT_DIR / "get_tos_diag" + + +def main(): + print(f"starting osmo-stp") + + # 1. osmo-stp im Hintergrund starten + try: + proc = subprocess.Popen( + [STP_BINARY, "-c", CONFIG_FILE], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True + ) + except FileNotFoundError: + print("File not found") + sys.exit(1) + + # wait to establish socket connection + time.sleep(1.0) + + # check process + if proc.poll() is not None: + print("Process failed") + stdout, stderr = proc.communicate() + print(f"STDOUT:\n{stdout}\nSTDERR:\n{stderr}", file=sys.stderr) + sys.exit(1) + + print("started osmo-stp") + + subprocess.run([DIAG_BINARY], check=True) + + print("stopping osmo-stp") + proc.terminate() + + try: + proc.wait(timeout=5) + print("stopped osmo-stp") + except subprocess.TimeoutExpired: + print("failed to stop, killing...") + proc.kill() + +if __name__ == "__main__": + main() diff --git a/tests/dscp/get_tos_diag.c b/tests/dscp/get_tos_diag.c new file mode 100644 index 0000000..d7bb2d8 --- /dev/null +++ b/tests/dscp/get_tos_diag.c @@ -0,0 +1,120 @@ +/* + * (C) 2026 by sysmocom s.f.m.c. GmbH + * 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 3 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <asm/types.h> +#include <sys/socket.h> +#include <linux/netlink.h> +#include <linux/rtnetlink.h> +#include <linux/sock_diag.h> +#include <linux/inet_diag.h> +#include <arpa/inet.h> +#include <netinet/tcp.h> + +#define BUFFER_SIZE 8192 + +int main() +{ + int nl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG); + if (nl_fd < 0) { + perror("Failed to open netlink socket."); + return 1; + } + + struct { + struct nlmsghdr nlh; + struct inet_diag_req_v2 req; + } req; + + memset(&req, 0, sizeof(req)); + req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct inet_diag_req_v2)); + req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + req.nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY; + + req.req.sdiag_family = AF_INET; + req.req.sdiag_protocol = IPPROTO_SCTP; + req.req.idiag_states = 0xFFFFFFFF; + + req.req.idiag_ext = (1 << (INET_DIAG_TOS - 1)); + + if (send(nl_fd, &req, req.nlh.nlmsg_len, 0) < 0) { + perror("Failed to sent netlink request."); + close(nl_fd); + return 1; + } + + char buffer[BUFFER_SIZE]; + + while (1) { + ssize_t num_bytes = recv(nl_fd, buffer, sizeof(buffer), 0); + if (num_bytes < 0) { + perror("Failed to receive netlink response."); + break; + } + + struct nlmsghdr *nlh = (struct nlmsghdr *)buffer; + while (NLMSG_OK(nlh, num_bytes)) { + if (nlh->nlmsg_type == NLMSG_DONE) { + close(nl_fd); + return 0; + } + if (nlh->nlmsg_type == NLMSG_ERROR) { + perror("Netlink error received."); + close(nl_fd); + return 1; + } + + struct inet_diag_msg *diag_msg = NLMSG_DATA(nlh); + + char src_ip[INET_ADDRSTRLEN], dst_ip[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &diag_msg->id.idiag_src, src_ip, sizeof(src_ip)); + inet_ntop(AF_INET, &diag_msg->id.idiag_dst, dst_ip, sizeof(dst_ip)); + + uint16_t src_port = ntohs(diag_msg->id.idiag_sport); + uint16_t dst_port = ntohs(diag_msg->id.idiag_dport); + + char src_addr[32], dst_addr[32]; + snprintf(src_addr, sizeof(src_addr), "%s:%d", src_ip, src_port); + snprintf(dst_addr, sizeof(dst_addr), "%s:%d", dst_ip, dst_port); + + const char *state_str = (diag_msg->idiag_state == TCP_ESTABLISHED) ? "ESTAB" : + (diag_msg->idiag_state == TCP_LISTEN) ? "LISTEN" : "OTHER"; + + uint8_t tos = 0; + + int rta_len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(struct inet_diag_msg)); + struct rtattr *attr = (struct rtattr *)(diag_msg + 1); + + while (RTA_OK(attr, rta_len)) { + if (attr->rta_type == INET_DIAG_TOS) { + tos = *(uint8_t *)RTA_DATA(attr); + break; + } + attr = RTA_NEXT(attr, rta_len); + } + + /* state local remote dscp */ + printf("%s %s %s %d\n", state_str, src_addr, dst_addr, tos>>2); + nlh = NLMSG_NEXT(nlh, num_bytes); + } + } + + close(nl_fd); + return 0; +} diff --git a/tests/dscp/osmo-stp-dscp.cfg b/tests/dscp/osmo-stp-dscp.cfg new file mode 100644 index 0000000..74f85ef --- /dev/null +++ b/tests/dscp/osmo-stp-dscp.cfg @@ -0,0 +1,22 @@ +log stderr + logging filter all 1 + logging color 1 + logging print category 1 + logging timestamp 0 + logging level set-all notice +line vty + no login +! +cs7 instance 0 + xua rkm routing-key-allocation dynamic-permitted + listen m3ua 2905 + accept-asp-connections dynamic-permitted + local-ip 127.0.0.1 + ip-dscp 23 + asp asp-clnt-m3ua 2905 2906 m3ua + local-ip 127.0.0.2 + remote-ip 127.0.0.1 + ip-dscp 42 + role asp + sctp-role client + no shutdown diff --git a/tests/testsuite.at b/tests/testsuite.at index 910fc0b..7812c93 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -26,3 +26,9 @@ cat $abs_srcdir/tcap/tcap_transaction_tracking_test.ok > expout AT_CHECK([$abs_top_builddir/tests/tcap/tcap_transaction_tracking_test], [], [expout], [ignore]) AT_CLEANUP + +AT_SETUP([dscp]) +AT_KEYWORDS([dscp]) +cat $abs_srcdir/dscp/dscp_test.ok > expout +AT_CHECK([python3 -u $abs_top_builddir/tests/dscp/dscp_test.py], [], [expout], [ignore]) +AT_CLEANUP