<p>laforge <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/libosmo-sccp/+/15797">View Change</a></p><div style="white-space:pre-wrap">Approvals:
laforge: Looks good to me, approved
Jenkins Builder: Verified
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">tests: Introduce test for multi-homing STP features<br><br>Config file sets omo-stp instance to bind on 2 IP addresses, and then<br>the test verfies through linux /proc/net/sctp/* that binding is done<br>correctly and that it can be reached from another remote address to one<br>of the configured addresses.<br><br>Change-Id: Ifa11b1fc882dff415405f62024e94bed67228866<br>---<br>M Makefile.am<br>M doc/examples/Makefile.am<br>A doc/examples/osmo-stp-multihome.cfg<br>M tests/vty/Makefile.am<br>A tests/vty/vty_test_runner.py<br>5 files changed, 211 insertions(+), 5 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/Makefile.am b/Makefile.am</span><br><span>index a3f76ab..ac68fcc 100644</span><br><span>--- a/Makefile.am</span><br><span>+++ b/Makefile.am</span><br><span>@@ -6,7 +6,7 @@</span><br><span> pkgconfigdir = $(libdir)/pkgconfig</span><br><span> pkgconfig_DATA = libosmo-sccp.pc libosmo-mtp.pc libosmo-sigtran.pc libosmo-xua.pc</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-EXTRA_DIST = .version git-version-gen osmoappdesc.py doc/examples/osmo-stp.cfg</span><br><span style="color: hsl(120, 100%, 40%);">+EXTRA_DIST = .version git-version-gen osmoappdesc.py</span><br><span> </span><br><span> AM_DISTCHECK_CONFIGURE_FLAGS = \</span><br><span> --with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)</span><br><span>diff --git a/doc/examples/Makefile.am b/doc/examples/Makefile.am</span><br><span>index a8e9991..ed92f24 100644</span><br><span>--- a/doc/examples/Makefile.am</span><br><span>+++ b/doc/examples/Makefile.am</span><br><span>@@ -1,7 +1,7 @@</span><br><span> examples_stpdir = $(docdir)/examples/osmo-stp</span><br><span style="color: hsl(0, 100%, 40%);">-examples_stp_DATA = osmo-stp.cfg</span><br><span style="color: hsl(120, 100%, 40%);">+examples_stp_DATA = osmo-stp.cfg osmo-stp-multihome.cfg</span><br><span> </span><br><span> osmoconfdir = $(sysconfdir)/osmocom</span><br><span> osmoconf_DATA = osmo-stp.cfg</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-EXTRA_DIST = osmo-stp.cfg</span><br><span style="color: hsl(120, 100%, 40%);">+EXTRA_DIST = osmo-stp.cfg osmo-stp-multihome.cfg</span><br><span>diff --git a/doc/examples/osmo-stp-multihome.cfg b/doc/examples/osmo-stp-multihome.cfg</span><br><span>new file mode 100644</span><br><span>index 0000000..dcdc19e</span><br><span>--- /dev/null</span><br><span>+++ b/doc/examples/osmo-stp-multihome.cfg</span><br><span>@@ -0,0 +1,22 @@</span><br><span style="color: hsl(120, 100%, 40%);">+!</span><br><span style="color: hsl(120, 100%, 40%);">+! osmo-stp (0.0.6.3.179-b248) configuration saved from vty</span><br><span style="color: hsl(120, 100%, 40%);">+!!</span><br><span style="color: hsl(120, 100%, 40%);">+!</span><br><span style="color: hsl(120, 100%, 40%);">+log stderr</span><br><span style="color: hsl(120, 100%, 40%);">+ logging filter all 1</span><br><span style="color: hsl(120, 100%, 40%);">+ logging color 1</span><br><span style="color: hsl(120, 100%, 40%);">+ logging print category 1</span><br><span style="color: hsl(120, 100%, 40%);">+ logging timestamp 0</span><br><span style="color: hsl(120, 100%, 40%);">+ logging level lss7 debug</span><br><span style="color: hsl(120, 100%, 40%);">+ logging level lsccp debug</span><br><span style="color: hsl(120, 100%, 40%);">+ logging level lsua debug</span><br><span style="color: hsl(120, 100%, 40%);">+ logging level lm3ua debug</span><br><span style="color: hsl(120, 100%, 40%);">+line vty</span><br><span style="color: hsl(120, 100%, 40%);">+ no login</span><br><span style="color: hsl(120, 100%, 40%);">+!</span><br><span style="color: hsl(120, 100%, 40%);">+cs7 instance 0</span><br><span style="color: hsl(120, 100%, 40%);">+ xua rkm routing-key-allocation dynamic-permitted</span><br><span style="color: hsl(120, 100%, 40%);">+ listen m3ua 2905</span><br><span style="color: hsl(120, 100%, 40%);">+ accept-asp-connections dynamic-permitted</span><br><span style="color: hsl(120, 100%, 40%);">+ local-ip 127.0.0.2</span><br><span style="color: hsl(120, 100%, 40%);">+ local-ip 127.0.0.1</span><br><span>diff --git a/tests/vty/Makefile.am b/tests/vty/Makefile.am</span><br><span>index 28e9dc2..be67293 100644</span><br><span>--- a/tests/vty/Makefile.am</span><br><span>+++ b/tests/vty/Makefile.am</span><br><span>@@ -5,7 +5,10 @@</span><br><span> LDADD = $(top_builddir)/src/libosmo-sigtran.la \</span><br><span> $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMONETIF_LIBS) $(LIBSCTP_LIBS)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-EXTRA_DIST = ss7_asp_test.vty</span><br><span style="color: hsl(120, 100%, 40%);">+EXTRA_DIST = \</span><br><span style="color: hsl(120, 100%, 40%);">+ ss7_asp_test.vty \</span><br><span style="color: hsl(120, 100%, 40%);">+ vty_test_runner.py \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(NULL)</span><br><span> </span><br><span> noinst_PROGRAMS = ss7_asp_vty_test</span><br><span> </span><br><span>@@ -19,14 +22,22 @@</span><br><span> echo "Not running python-based external tests (determined at configure-time)"</span><br><span> endif</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+vty-python-test: $(BUILT_SOURCES)</span><br><span style="color: hsl(120, 100%, 40%);">+ $(srcdir)/vty_test_runner.py -w $(abs_top_builddir) -v</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> # To update the VTY script from current application behavior,</span><br><span> # pass -u to osmo_verify_transcript_vty.py by doing:</span><br><span> # make vty-test U=-u</span><br><span style="color: hsl(0, 100%, 40%);">-vty-test: ss7_asp_vty_test</span><br><span style="color: hsl(120, 100%, 40%);">+vty-transcript-test: ss7_asp_vty_test</span><br><span> osmo_verify_transcript_vty.py -v \</span><br><span> -p 42043 \</span><br><span> -r "$(builddir)/ss7_asp_vty_test" \</span><br><span> $(U) $(srcdir)/ss7_asp_*.vty</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+# don't run multiple tests concurrently so that the ports don't conflict</span><br><span style="color: hsl(120, 100%, 40%);">+vty-test:</span><br><span style="color: hsl(120, 100%, 40%);">+ $(MAKE) vty-python-test</span><br><span style="color: hsl(120, 100%, 40%);">+ $(MAKE) vty-transcript-test</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> check-local:</span><br><span> $(MAKE) $(AM_MAKEFLAGS) ext-tests</span><br><span>diff --git a/tests/vty/vty_test_runner.py b/tests/vty/vty_test_runner.py</span><br><span>new file mode 100755</span><br><span>index 0000000..47ce23c</span><br><span>--- /dev/null</span><br><span>+++ b/tests/vty/vty_test_runner.py</span><br><span>@@ -0,0 +1,173 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#!/usr/bin/env python2</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# (C) 2013 by Katerina Barone-Adesi <kat.obsc@gmail.com></span><br><span style="color: hsl(120, 100%, 40%);">+# (C) 2013 by Holger Hans Peter Freyther</span><br><span style="color: hsl(120, 100%, 40%);">+# (C) 2019 by sysmocom s.f.m.c. GmbH</span><br><span style="color: hsl(120, 100%, 40%);">+# This program is free software: you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+# it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+# the Free Software Foundation, either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+# (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+# but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the</span><br><span style="color: hsl(120, 100%, 40%);">+# GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# You should have received a copy of the GNU General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+# along with this program. If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+import os, sys</span><br><span style="color: hsl(120, 100%, 40%);">+import time</span><br><span style="color: hsl(120, 100%, 40%);">+import unittest</span><br><span style="color: hsl(120, 100%, 40%);">+import socket</span><br><span style="color: hsl(120, 100%, 40%);">+import subprocess</span><br><span style="color: hsl(120, 100%, 40%);">+import time</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+import osmopy.obscvty as obscvty</span><br><span style="color: hsl(120, 100%, 40%);">+import osmopy.osmoutil as osmoutil</span><br><span style="color: hsl(120, 100%, 40%);">+from osmopy.osmo_ipa import IPA</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# to be able to find $top_srcdir/doc/...</span><br><span style="color: hsl(120, 100%, 40%);">+confpath = os.path.join(sys.path[0], '..')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class TestVTYBase(unittest.TestCase):</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def checkForEndAndExit(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ res = self.vty.command("list")</span><br><span style="color: hsl(120, 100%, 40%);">+ #print ('looking for "exit"\n')</span><br><span style="color: hsl(120, 100%, 40%);">+ self.assert_(res.find(' exit\r') > 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ #print 'found "exit"\nlooking for "end"\n'</span><br><span style="color: hsl(120, 100%, 40%);">+ self.assert_(res.find(' end\r') > 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ #print 'found "end"\n'</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def vty_command(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ raise Exception("Needs to be implemented by a subclass")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def vty_app(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ raise Exception("Needs to be implemented by a subclass")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def setUp(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_vty_cmd = self.vty_command()[:]</span><br><span style="color: hsl(120, 100%, 40%);">+ config_index = osmo_vty_cmd.index('-c')</span><br><span style="color: hsl(120, 100%, 40%);">+ if config_index:</span><br><span style="color: hsl(120, 100%, 40%);">+ cfi = config_index + 1</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_vty_cmd[cfi] = os.path.join(confpath, osmo_vty_cmd[cfi])</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ try:</span><br><span style="color: hsl(120, 100%, 40%);">+ self.proc = osmoutil.popen_devnull(osmo_vty_cmd)</span><br><span style="color: hsl(120, 100%, 40%);">+ except OSError:</span><br><span style="color: hsl(120, 100%, 40%);">+ print >> sys.stderr, "Current directory: %s" % os.getcwd()</span><br><span style="color: hsl(120, 100%, 40%);">+ print >> sys.stderr, "Consider setting -b"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ appstring = self.vty_app()[2]</span><br><span style="color: hsl(120, 100%, 40%);">+ appport = self.vty_app()[0]</span><br><span style="color: hsl(120, 100%, 40%);">+ self.vty = obscvty.VTYInteract(appstring, "127.0.0.1", appport)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def tearDown(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ if self.vty:</span><br><span style="color: hsl(120, 100%, 40%);">+ self.vty._close_socket()</span><br><span style="color: hsl(120, 100%, 40%);">+ self.vty = None</span><br><span style="color: hsl(120, 100%, 40%);">+ osmoutil.end_proc(self.proc)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class TestVTYSTP(TestVTYBase):</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def vty_command(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ return ["./stp/osmo-stp", "-c",</span><br><span style="color: hsl(120, 100%, 40%);">+ "../doc/examples/osmo-stp-multihome.cfg"]</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def vty_app(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ return (4239, "./stp/osmo-stp", "OsmoSTP", "stp")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def check_sctp_sock_local(self, laddr_list, lport):</span><br><span style="color: hsl(120, 100%, 40%);">+ path = "/proc/net/sctp/eps"</span><br><span style="color: hsl(120, 100%, 40%);">+ try:</span><br><span style="color: hsl(120, 100%, 40%);">+ with open(path, "r") as fp:</span><br><span style="color: hsl(120, 100%, 40%);">+ #drop first line, contains column names:</span><br><span style="color: hsl(120, 100%, 40%);">+ fp.readline()</span><br><span style="color: hsl(120, 100%, 40%);">+ while True:</span><br><span style="color: hsl(120, 100%, 40%);">+ # Read next line</span><br><span style="color: hsl(120, 100%, 40%);">+ line = fp.readline().strip()</span><br><span style="color: hsl(120, 100%, 40%);">+ if not line:</span><br><span style="color: hsl(120, 100%, 40%);">+ return False</span><br><span style="color: hsl(120, 100%, 40%);">+ print "%s: parsing line: %s" %(path, line)</span><br><span style="color: hsl(120, 100%, 40%);">+ it = line.split()</span><br><span style="color: hsl(120, 100%, 40%);">+ if lport == int(it[5]):</span><br><span style="color: hsl(120, 100%, 40%);">+ print "%s: local port %d found" %(path, lport)</span><br><span style="color: hsl(120, 100%, 40%);">+ itaddr_list = it[8:]</span><br><span style="color: hsl(120, 100%, 40%);">+ if len(itaddr_list) != len(laddr_list):</span><br><span style="color: hsl(120, 100%, 40%);">+ print "%s: addr list mismatch: %r vs %r" % (path, repr(itaddr_list), repr(laddr_list))</span><br><span style="color: hsl(120, 100%, 40%);">+ continue</span><br><span style="color: hsl(120, 100%, 40%);">+ for addr in laddr_list:</span><br><span style="color: hsl(120, 100%, 40%);">+ if addr not in itaddr_list:</span><br><span style="color: hsl(120, 100%, 40%);">+ print "%s: addr not found in list: %s vs %r" % (path, addr, repr(itaddr_list))</span><br><span style="color: hsl(120, 100%, 40%);">+ return False</span><br><span style="color: hsl(120, 100%, 40%);">+ return True</span><br><span style="color: hsl(120, 100%, 40%);">+ return False</span><br><span style="color: hsl(120, 100%, 40%);">+ except IOError as e:</span><br><span style="color: hsl(120, 100%, 40%);">+ print "I/O error({0}): {1}".format(e.errno, e.strerror)</span><br><span style="color: hsl(120, 100%, 40%);">+ return False</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def testMultiHome(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ # first check if STP is listening in required addresses:</span><br><span style="color: hsl(120, 100%, 40%);">+ found = False</span><br><span style="color: hsl(120, 100%, 40%);">+ for i in range(5):</span><br><span style="color: hsl(120, 100%, 40%);">+ if self.check_sctp_sock_local(['127.0.0.1', '127.0.0.2'], 2905):</span><br><span style="color: hsl(120, 100%, 40%);">+ found = True</span><br><span style="color: hsl(120, 100%, 40%);">+ break</span><br><span style="color: hsl(120, 100%, 40%);">+ else:</span><br><span style="color: hsl(120, 100%, 40%);">+ print "[%d] osmo-stp not yet available, retrying in a second" % i</span><br><span style="color: hsl(120, 100%, 40%);">+ time.sleep(1)</span><br><span style="color: hsl(120, 100%, 40%);">+ self.assert_(found)</span><br><span style="color: hsl(120, 100%, 40%);">+ try:</span><br><span style="color: hsl(120, 100%, 40%);">+ proto = socket.IPPROTO_SCTP</span><br><span style="color: hsl(120, 100%, 40%);">+ except AttributeError: # it seems to be not defined under python2?</span><br><span style="color: hsl(120, 100%, 40%);">+ proto = 132</span><br><span style="color: hsl(120, 100%, 40%);">+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, proto)</span><br><span style="color: hsl(120, 100%, 40%);">+ s.bind(('127.0.0.3', 0))</span><br><span style="color: hsl(120, 100%, 40%);">+ try:</span><br><span style="color: hsl(120, 100%, 40%);">+ s.connect(('127.0.0.2',2905))</span><br><span style="color: hsl(120, 100%, 40%);">+ except socket.error as msg:</span><br><span style="color: hsl(120, 100%, 40%);">+ s.close()</span><br><span style="color: hsl(120, 100%, 40%);">+ self.assert_(False)</span><br><span style="color: hsl(120, 100%, 40%);">+ print "Connected to STP through SCTP"</span><br><span style="color: hsl(120, 100%, 40%);">+ s.close()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+if __name__ == '__main__':</span><br><span style="color: hsl(120, 100%, 40%);">+ import argparse</span><br><span style="color: hsl(120, 100%, 40%);">+ import sys</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ workdir = '.'</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ parser = argparse.ArgumentParser()</span><br><span style="color: hsl(120, 100%, 40%);">+ parser.add_argument("-v", "--verbose", dest="verbose",</span><br><span style="color: hsl(120, 100%, 40%);">+ action="store_true", help="verbose mode")</span><br><span style="color: hsl(120, 100%, 40%);">+ parser.add_argument("-p", "--pythonconfpath", dest="p",</span><br><span style="color: hsl(120, 100%, 40%);">+ help="searchpath for config")</span><br><span style="color: hsl(120, 100%, 40%);">+ parser.add_argument("-w", "--workdir", dest="w",</span><br><span style="color: hsl(120, 100%, 40%);">+ help="Working directory")</span><br><span style="color: hsl(120, 100%, 40%);">+ parser.add_argument("test_name", nargs="*", help="(parts of) test names to run, case-insensitive")</span><br><span style="color: hsl(120, 100%, 40%);">+ args = parser.parse_args()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ verbose_level = 1</span><br><span style="color: hsl(120, 100%, 40%);">+ if args.verbose:</span><br><span style="color: hsl(120, 100%, 40%);">+ verbose_level = 2</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if args.w:</span><br><span style="color: hsl(120, 100%, 40%);">+ workdir = args.w</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if args.p:</span><br><span style="color: hsl(120, 100%, 40%);">+ confpath = args.p</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ print "confpath %s, workdir %s" % (confpath, workdir)</span><br><span style="color: hsl(120, 100%, 40%);">+ os.chdir(workdir)</span><br><span style="color: hsl(120, 100%, 40%);">+ print "Running tests for specific VTY commands"</span><br><span style="color: hsl(120, 100%, 40%);">+ suite = unittest.TestSuite()</span><br><span style="color: hsl(120, 100%, 40%);">+ suite.addTest(unittest.TestLoader().loadTestsFromTestCase(TestVTYSTP))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if args.test_name:</span><br><span style="color: hsl(120, 100%, 40%);">+ osmoutil.pick_tests(suite, *args.test_name)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ res = unittest.TextTestRunner(verbosity=verbose_level, stream=sys.stdout).run(suite)</span><br><span style="color: hsl(120, 100%, 40%);">+ sys.exit(len(res.errors) + len(res.failures))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# vim: shiftwidth=4 expandtab nocin ai</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/libosmo-sccp/+/15797">change 15797</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/libosmo-sccp/+/15797"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: libosmo-sccp </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ifa11b1fc882dff415405f62024e94bed67228866 </div>
<div style="display:none"> Gerrit-Change-Number: 15797 </div>
<div style="display:none"> Gerrit-PatchSet: 4 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>