Skip to content

Commit

Permalink
ovs-tcpdump: Fix cleanup mirror failed with twice fatal signals.
Browse files Browse the repository at this point in the history
After running ovs-tcpdump and inputs multiple CTRL+C, the program will
raise the following exception.

Error in atexit._run_exitfuncs:
Traceback (most recent call last):
  File "/usr/bin/ovs-tcpdump", line 421, in cleanup_mirror
    ovsdb = OVSDB(db_sock)
  File "/usr/bin/ovs-tcpdump", line 168, in __init__
    OVSDB.wait_for_db_change(self._idl_conn)  # Initial Sync with DB
  File "/usr/bin/ovs-tcpdump", line 155, in wait_for_db_change
    while idl.change_seqno == seq and not idl.run():

The default handler of SIGINT is default_int_handler, so it was not
registered to the signal handler. When received CTRL+C again, the program
was broken, and calling hook could not be executed completely.

Signed-off-by: Daniel Ding <[email protected]>
Signed-off-by: Ilya Maximets <[email protected]>
  • Loading branch information
danieldin95 authored and igsilya committed Mar 22, 2024
1 parent 9d0a401 commit 3388c34
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 32 deletions.
24 changes: 13 additions & 11 deletions python/ovs/fatal_signal.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import os
import signal
import sys
import threading

import ovs.vlog

Expand Down Expand Up @@ -112,29 +113,29 @@ def _unlink(file_):
def _signal_handler(signr, _):
_call_hooks(signr)

# Re-raise the signal with the default handling so that the program
# termination status reflects that we were killed by this signal.
signal.signal(signr, signal.SIG_DFL)
os.kill(os.getpid(), signr)


def _atexit_handler():
_call_hooks(0)


recurse = False
mutex = threading.Lock()


def _call_hooks(signr):
global recurse
if recurse:
global mutex
if not mutex.acquire(blocking=False):
return
recurse = True

for hook, cancel, run_at_exit in _hooks:
if signr != 0 or run_at_exit:
hook()

if signr != 0:
# Re-raise the signal with the default handling so that the program
# termination status reflects that we were killed by this signal.
signal.signal(signr, signal.SIG_DFL)
os.kill(os.getpid(), signr)


_inited = False

Expand All @@ -150,7 +151,9 @@ def _init():
signal.SIGALRM]

for signr in signals:
if signal.getsignal(signr) == signal.SIG_DFL:
handler = signal.getsignal(signr)
if (handler == signal.SIG_DFL or
handler == signal.default_int_handler):
signal.signal(signr, _signal_handler)
atexit.register(_atexit_handler)

Expand All @@ -165,7 +168,6 @@ def signal_alarm(timeout):

if sys.platform == "win32":
import time
import threading

class Alarm (threading.Thread):
def __init__(self, timeout):
Expand Down
32 changes: 11 additions & 21 deletions utilities/ovs-tcpdump.in
Original file line number Diff line number Diff line change
Expand Up @@ -534,29 +534,19 @@ def main():
ovsdb.close_idl()

pipes = _doexec(*([dump_cmd, '-i', mirror_interface] + tcpdargs))
try:
while pipes.poll() is None:
data = pipes.stdout.readline().strip(b'\n')
if len(data) == 0:
raise KeyboardInterrupt
print(data.decode('utf-8'))
raise KeyboardInterrupt
except KeyboardInterrupt:
# If there is a pipe behind ovs-tcpdump (such as ovs-tcpdump
# -i eth0 | grep "192.168.1.1"), the pipe is no longer available
# after received Ctrl+C.
# If we write data to an unavailable pipe, a pipe error will be
# reported, so we turn off stdout to avoid subsequent flushing
# of data into the pipe.
try:
sys.stdout.close()
except IOError:
pass
while pipes.poll() is None:
data = pipes.stdout.readline().strip(b'\n')
if len(data) == 0:
break
print(data.decode('utf-8'))

if pipes.poll() is None:
pipes.terminate()
try:
sys.stdout.close()
except IOError:
pass

sys.exit(0)
if pipes.poll() is None:
pipes.terminate()


if __name__ == '__main__':
Expand Down

0 comments on commit 3388c34

Please sign in to comment.