path: root/src/osmo_gsm_tester/
diff options
authorPau Espin Pedrol <>2018-10-25 17:37:23 +0200
committerPau Espin Pedrol <>2018-10-31 09:59:02 +0100
commitfd4c14404908c683a00e9132a50fdb9a91ccd698 (patch)
treec262c44b76b823ca322bcb61fda341e93be1964e /src/osmo_gsm_tester/
parent0aaf8e1c1ba92ce9d8167fc8be78122c908d8138 (diff)
Add support to test gprs IPv4 data plane
Since the modem iface and the GGSN iface are on the same host/netns, it's really difficult to conveniently test data plane without getting routing loops. As a result, either GGSN or modem iface must be moved to a different namespace. The decision after a few discussions was finally to move modem interfaces to a different netns. Expected setup: * ofono is patched to avoid removing modem if it detects through udev that its net iface was removed (due to for instance, net iface being moved to another netns and thus not being reachable anymore by systemd-udev process running in root netns). * After ofono is started (and successfully configured all the modems and detected its net ifaces through syfs/udev), script " start" which creates a netns for each modem, naming it after its usb path ID. net ifaces for that modem are moved into its netns. * Modem is configured to use 802-3 data format, and as a result the net iface is configured through DHCP (DHCP req only replied AFTER pdp ctx is activated!). * Since osmo-gsm-tester knowns the modem USB path ID (available in resources.conf), it can run required steps (ifup, DHCP) to configure the interface. The interface name is provided by ofono to osmo-gsm-tester. * As a result, any process willing to transmit data through the modem must be in the modem netns. Related: OS#2308 Change-Id: Icb06bdfcdd37c797be95ab5addb28da2d9f6681c
Diffstat (limited to 'src/osmo_gsm_tester/')
1 files changed, 27 insertions, 3 deletions
diff --git a/src/osmo_gsm_tester/ b/src/osmo_gsm_tester/
index fb5c6f6..a845f7f 100644
--- a/src/osmo_gsm_tester/
+++ b/src/osmo_gsm_tester/
@@ -100,6 +100,9 @@ class Process(log.Origin):
return False
+ def send_signal(self, sig):
+ os.kill(, sig)
def terminate(self):
if self.process_obj is None:
@@ -109,21 +112,21 @@ class Process(log.Origin):
while True:
# first try SIGINT to allow stdout+stderr flushing
self.log('Terminating (SIGINT)')
- os.kill(, signal.SIGINT)
+ self.send_signal(signal.SIGINT)
self.killed = signal.SIGINT
if self._poll_termination():
# SIGTERM maybe?
self.log('Terminating (SIGTERM)')
- self.process_obj.terminate()
+ self.send_signal(signal.SIGTERM)
self.killed = signal.SIGTERM
if self._poll_termination():
# out of patience
self.log('Terminating (SIGKILL)')
- self.process_obj.kill()
+ self.send_signal(signal.SIGKILL)
self.killed = signal.SIGKILL
@@ -236,6 +239,22 @@ class RemoteProcess(Process):
' '.join(self.popen_args))]
self.dbg(self.popen_args, dir=self.run_dir, conf=self.popen_kwargs)
+class NetNSProcess(Process):
+ def __init__(self, name, run_dir, netns, popen_args, **popen_kwargs):
+ super().__init__(name, run_dir, popen_args, **popen_kwargs)
+ self.netns = netns
+ self.popen_args = ['sudo', self.NETNS_EXEC_BIN, self.netns] + list(popen_args)
+ self.dbg(self.popen_args, dir=self.run_dir, conf=self.popen_kwargs)
+ # HACK: Since we run under sudo, only way to kill root-owned process is to kill as root...
+ # This function is overwritten from Process.
+ def send_signal(self, sig):
+ kill_cmd = ('kill', '-%d' % int(sig), str(
+ run_local_netns_sync(self.run_dir,"-kill", self.netns, kill_cmd)
def run_proc_sync(proc):
@@ -252,6 +271,11 @@ def run_local_sync(run_dir, name, popen_args):
proc = Process(name, run_dir, popen_args)
+def run_local_netns_sync(run_dir, name, netns, popen_args):
+ run_dir =run_dir.new_dir(name)
+ proc = NetNSProcess(name, run_dir, netns, popen_args)
+ run_proc_sync(proc)
def run_remote_sync(run_dir, remote_user, remote_addr, name, popen_args, remote_cwd=None):
run_dir = run_dir.new_dir(name)
proc = RemoteProcess(name, run_dir, remote_user, remote_addr, remote_cwd, popen_args)