2
0
mirror of https://github.com/openvswitch/ovs synced 2025-10-23 14:57:06 +00:00
Files
openvswitch/utilities/ovs-tcpdump.in
Ilya Maximets eeecd1b294 ovs-tcpdump: Fix E117 over-indented.
utilities/ovs-tcpdump.in:376:9: E117 over-indented
make[2]: *** [flake8-check] Error 1

CC: Liu Chang <txfh2007@aliyun.com>
Fixes: 2eeadf73d9 ("ovs-tcpdump: Improve error message when tcpdump is not available.")
Acked-by: Aaron Conole <aconole@redhat.com>
Signed-off-by: Ilya Maximets <i.maximets@samsung.com>
2019-04-30 10:48:46 +03:00

503 lines
16 KiB
Plaintext
Executable File

#! @PYTHON@
#
# Copyright (c) 2016 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import fcntl
import os
import pwd
from random import randint
import struct
import subprocess
import sys
import time
import netifaces
try:
from ovs.db import idl
from ovs import jsonrpc
from ovs.poller import Poller
from ovs.stream import Stream
except Exception:
print("ERROR: Please install the correct Open vSwitch python support")
print(" libraries (version @VERSION@).")
print(" Alternatively, check that your PYTHONPATH is pointing to")
print(" the correct location.")
sys.exit(1)
tapdev_fd = None
_make_taps = {}
_make_mirror_name = {}
IFNAMSIZ_LINUX = 15 # this is the max name size, excluding the null byte.
def _doexec(*args, **kwargs):
"""Executes an application and returns a set of pipes"""
shell = len(args) == 1
proc = subprocess.Popen(args, stdout=subprocess.PIPE, shell=shell,
bufsize=0)
return proc
def _install_tap_linux(tap_name, mtu_value=None):
"""Uses /dev/net/tun to create a tap device"""
global tapdev_fd
IFF_TAP = 0x0002
IFF_NO_PI = 0x1000
TUNSETIFF = 0x400454CA # This is derived by printf() of TUNSETIFF
TUNSETOWNER = TUNSETIFF + 2
tapdev_fd = os.open('/dev/net/tun', os.O_RDWR)
ifr = struct.pack('16sH', tap_name.encode('utf8'), IFF_TAP | IFF_NO_PI)
fcntl.ioctl(tapdev_fd, TUNSETIFF, ifr)
fcntl.ioctl(tapdev_fd, TUNSETOWNER, os.getegid())
time.sleep(1) # required to give the new device settling time
if mtu_value is not None:
pipe = _doexec(
*(['ip', 'link', 'set', 'dev', str(tap_name), 'mtu',
str(mtu_value)]))
pipe.wait()
pipe = _doexec(
*(['ip', 'link', 'set', 'dev', str(tap_name), 'up']))
pipe.wait()
def _make_linux_mirror_name(interface_name):
if len(interface_name) > IFNAMSIZ_LINUX - 2:
return "ovsmi%06d" % randint(1, 999999)
return "mi%s" % interface_name
_make_taps['linux'] = _install_tap_linux
_make_taps['linux2'] = _install_tap_linux
_make_mirror_name['linux'] = _make_linux_mirror_name
_make_mirror_name['linux2'] = _make_linux_mirror_name
def username():
return pwd.getpwuid(os.getuid())[0]
def usage():
print("""\
%(prog)s: Open vSwitch tcpdump helper.
usage: %(prog)s -i interface [TCPDUMP OPTIONS]
where TCPDUMP OPTIONS represents the options normally passed to tcpdump.
The following options are available:
-h, --help display this help message
-V, --version display version information
--db-sock A connection string to reach the Open vSwitch
ovsdb-server.
Default 'unix:@RUNDIR@/db.sock'
--dump-cmd Command to use for tcpdump (default 'tcpdump')
-i, --interface Open vSwitch interface to mirror and tcpdump
--mirror-to The name for the mirror port to use (optional)
Default 'miINTERFACE'
--span If specified, mirror all ports (optional)
""" % {'prog': sys.argv[0]})
sys.exit(0)
class OVSDBException(Exception):
pass
class OVSDB(object):
@staticmethod
def wait_for_db_change(idl):
seq = idl.change_seqno
stop = time.time() + 10
while idl.change_seqno == seq and not idl.run():
poller = Poller()
idl.wait(poller)
poller.block()
if time.time() >= stop:
raise Exception('Retry Timeout')
def __init__(self, db_sock):
self._db_sock = db_sock
self._txn = None
schema = self._get_schema()
schema.register_all()
self._idl_conn = idl.Idl(db_sock, schema)
OVSDB.wait_for_db_change(self._idl_conn) # Initial Sync with DB
def _get_schema(self):
error, strm = Stream.open_block(Stream.open(self._db_sock))
if error:
raise Exception("Unable to connect to %s" % self._db_sock)
rpc = jsonrpc.Connection(strm)
req = jsonrpc.Message.create_request('get_schema', ['Open_vSwitch'])
error, resp = rpc.transact_block(req)
rpc.close()
if error or resp.error:
raise Exception('Unable to retrieve schema.')
return idl.SchemaHelper(None, resp.result)
def get_table(self, table_name):
return self._idl_conn.tables[table_name]
def _start_txn(self):
if self._txn is not None:
raise OVSDBException("ERROR: A transaction was started already")
self._idl_conn.change_seqno += 1
self._txn = idl.Transaction(self._idl_conn)
return self._txn
def _complete_txn(self, try_again_fn):
if self._txn is None:
raise OVSDBException("ERROR: Not in a transaction")
status = self._txn.commit_block()
if status is idl.Transaction.TRY_AGAIN:
if self._idl_conn._session.rpc.status != 0:
self._idl_conn.force_reconnect()
OVSDB.wait_for_db_change(self._idl_conn)
return try_again_fn(self)
elif status is idl.Transaction.ERROR:
return False
def _find_row(self, table_name, find):
return next(
(row for row in self.get_table(table_name).rows.values()
if find(row)), None)
def _find_row_by_name(self, table_name, value):
return self._find_row(table_name, lambda row: row.name == value)
def port_exists(self, port_name):
return bool(self._find_row_by_name('Port', port_name))
def port_bridge(self, port_name):
try:
port = self._find_row_by_name('Port', port_name)
br = self._find_row('Bridge', lambda x: port in x.ports)
return br.name
except Exception:
raise OVSDBException('Unable to find port %s bridge' % port_name)
def interface_mtu(self, intf_name):
try:
intf = self._find_row_by_name('Interface', intf_name)
return intf.mtu[0]
except Exception:
return None
def interface_exists(self, intf_name):
return bool(self._find_row_by_name('Interface', intf_name))
def mirror_exists(self, mirror_name):
return bool(self._find_row_by_name('Mirror', mirror_name))
def interface_uuid(self, intf_name):
row = self._find_row_by_name('Interface', intf_name)
if bool(row):
return row.uuid
raise OVSDBException('No such interface: %s' % intf_name)
def make_interface(self, intf_name, execute_transaction=True):
if self.interface_exists(intf_name):
print("INFO: Interface exists.")
return self.interface_uuid(intf_name)
txn = self._start_txn()
tmp_row = txn.insert(self.get_table('Interface'))
tmp_row.name = intf_name
def try_again(db_entity):
db_entity.make_interface(intf_name)
if not execute_transaction:
return tmp_row
txn.add_comment("ovs-tcpdump: user=%s,create_intf=%s"
% (username(), intf_name))
status = self._complete_txn(try_again)
if status is False:
raise OVSDBException('Unable to create Interface %s: %s' %
(intf_name, txn.get_error()))
result = txn.get_insert_uuid(tmp_row.uuid)
self._txn = None
return result
def destroy_port(self, port_name, bridge_name):
if not self.interface_exists(port_name):
return
txn = self._start_txn()
br = self._find_row_by_name('Bridge', bridge_name)
ports = [port for port in br.ports if port.name != port_name]
br.ports = ports
def try_again(db_entity):
db_entity.destroy_port(port_name)
txn.add_comment("ovs-tcpdump: user=%s,destroy_port=%s"
% (username(), port_name))
status = self._complete_txn(try_again)
if status is False:
raise OVSDBException('unable to delete Port %s: %s' %
(port_name, txn.get_error()))
self._txn = None
def destroy_mirror(self, intf_name, bridge_name):
mirror_name = 'm_%s' % intf_name
if not self.mirror_exists(mirror_name):
return
txn = self._start_txn()
mirror_row = self._find_row_by_name('Mirror', mirror_name)
br = self._find_row_by_name('Bridge', bridge_name)
mirrors = [mirror for mirror in br.mirrors
if mirror.uuid != mirror_row.uuid]
br.mirrors = mirrors
def try_again(db_entity):
db_entity.destroy_mirror(mirror_name, bridge_name)
txn.add_comment("ovs-tcpdump: user=%s,destroy_mirror=%s"
% (username(), mirror_name))
status = self._complete_txn(try_again)
if status is False:
raise OVSDBException('Unable to delete Mirror %s: %s' %
(mirror_name, txn.get_error()))
self._txn = None
def make_port(self, port_name, bridge_name):
iface_row = self.make_interface(port_name, False)
txn = self._txn
br = self._find_row_by_name('Bridge', bridge_name)
if not br:
raise OVSDBException('Bad bridge name %s' % bridge_name)
port = txn.insert(self.get_table('Port'))
port.name = port_name
br.verify('ports')
ports = getattr(br, 'ports', [])
ports.append(port)
br.ports = ports
port.verify('interfaces')
ifaces = getattr(port, 'interfaces', [])
ifaces.append(iface_row)
port.interfaces = ifaces
def try_again(db_entity):
db_entity.make_port(port_name, bridge_name)
txn.add_comment("ovs-tcpdump: user=%s,create_port=%s"
% (username(), port_name))
status = self._complete_txn(try_again)
if status is False:
raise OVSDBException('Unable to create Port %s: %s' %
(port_name, txn.get_error()))
result = txn.get_insert_uuid(port.uuid)
self._txn = None
return result
def bridge_mirror(self, intf_name, mirror_intf_name, br_name,
mirror_select_all=False):
txn = self._start_txn()
mirror = txn.insert(self.get_table('Mirror'))
mirror.name = 'm_%s' % intf_name
mirror.select_all = mirror_select_all
mirrored_port = self._find_row_by_name('Port', intf_name)
mirror.verify('select_dst_port')
dst_port = getattr(mirror, 'select_dst_port', [])
dst_port.append(mirrored_port)
mirror.select_dst_port = dst_port
mirror.verify('select_src_port')
src_port = getattr(mirror, 'select_src_port', [])
src_port.append(mirrored_port)
mirror.select_src_port = src_port
output_port = self._find_row_by_name('Port', mirror_intf_name)
mirror.verify('output_port')
out_port = getattr(mirror, 'output_port', [])
out_port.append(output_port.uuid)
mirror.output_port = out_port
br = self._find_row_by_name('Bridge', br_name)
br.verify('mirrors')
mirrors = getattr(br, 'mirrors', [])
mirrors.append(mirror.uuid)
br.mirrors = mirrors
def try_again(db_entity):
db_entity.bridge_mirror(intf_name, mirror_intf_name, br_name)
txn.add_comment("ovs-tcpdump: user=%s,create_mirror=%s"
% (username(), mirror.name))
status = self._complete_txn(try_again)
if status is False:
raise OVSDBException('Unable to create Mirror %s: %s' %
(mirror_intf_name, txn.get_error()))
result = txn.get_insert_uuid(mirror.uuid)
self._txn = None
return result
def argv_tuples(lst):
cur, nxt = iter(lst), iter(lst)
next(nxt, None)
try:
while True:
yield next(cur), next(nxt, None)
except StopIteration:
pass
def py_which(executable):
return any(os.access(os.path.join(path, executable), os.X_OK)
for path in os.environ["PATH"].split(os.pathsep))
def main():
db_sock = 'unix:@RUNDIR@/db.sock'
interface = None
tcpdargs = []
skip_next = False
mirror_interface = None
mirror_select_all = False
dump_cmd = 'tcpdump'
for cur, nxt in argv_tuples(sys.argv[1:]):
if skip_next:
skip_next = False
continue
if cur in ['-h', '--help']:
usage()
elif cur in ['-V', '--version']:
print("ovs-tcpdump (Open vSwitch) @VERSION@")
sys.exit(0)
elif cur in ['--db-sock']:
db_sock = nxt
skip_next = True
continue
elif cur in ['--dump-cmd']:
dump_cmd = nxt
skip_next = True
continue
elif cur in ['-i', '--interface']:
interface = nxt
skip_next = True
continue
elif cur in ['--mirror-to']:
mirror_interface = nxt
skip_next = True
continue
elif cur in ['--span']:
mirror_select_all = True
continue
tcpdargs.append(cur)
if interface is None:
print("Error: must at least specify an interface with '-i' option")
sys.exit(1)
if not py_which(dump_cmd):
print("Error: unable to execute '%s' (check PATH)" % dump_cmd)
sys.exit(1)
if '-l' not in tcpdargs:
tcpdargs.insert(0, '-l')
if '-vv' in tcpdargs:
print("TCPDUMP Args: %s" % ' '.join(tcpdargs))
ovsdb = OVSDB(db_sock)
if mirror_interface is None:
mirror_interface = "mi%s" % interface
if sys.platform in _make_mirror_name:
mirror_interface = _make_mirror_name[sys.platform](interface)
if sys.platform in _make_taps and \
mirror_interface not in netifaces.interfaces():
_make_taps[sys.platform](mirror_interface,
ovsdb.interface_mtu(interface))
if mirror_interface not in netifaces.interfaces():
print("ERROR: Please create an interface called `%s`" %
mirror_interface)
print("See your OS guide for how to do this.")
print("Ex: ip link add %s type veth peer name %s" %
(mirror_interface, mirror_interface + "2"))
sys.exit(1)
if not ovsdb.port_exists(interface):
print("ERROR: Port %s does not exist." % interface)
sys.exit(1)
if ovsdb.port_exists(mirror_interface):
print("ERROR: Mirror port (%s) exists for port %s." %
(mirror_interface, interface))
sys.exit(1)
try:
ovsdb.make_port(mirror_interface, ovsdb.port_bridge(interface))
ovsdb.bridge_mirror(interface, mirror_interface,
ovsdb.port_bridge(interface),
mirror_select_all)
except OVSDBException as oe:
print("ERROR: Unable to properly setup the mirror: %s." % str(oe))
try:
ovsdb.destroy_port(mirror_interface, ovsdb.port_bridge(interface))
except Exception:
pass
sys.exit(1)
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 pipes.poll() is None:
pipes.terminate()
ovsdb.destroy_mirror(interface, ovsdb.port_bridge(interface))
ovsdb.destroy_port(mirror_interface, ovsdb.port_bridge(interface))
except Exception:
print("Unable to tear down the ports and mirrors.")
print("Please use ovs-vsctl to remove the ports and mirrors created.")
print(" ex: ovs-vsctl --db=%s del-port %s" % (db_sock,
mirror_interface))
sys.exit(1)
sys.exit(0)
if __name__ == '__main__':
main()
# Local variables:
# mode: python
# End: