mirror of
https://github.com/openvswitch/ovs
synced 2025-08-29 21:38:13 +00:00
ovs-tcpdump: Add a tcpdump wrapper utility
Currently, there is some documentation which describes setting up and using port mirrors for bridges. This documentation is helpful to setup a packet capture for specific ports. However, a utility to do such packet capture would be valuable, both as an exercise in documenting the steps an additional time, and as a way of providing an out-of-the-box experience for running a capture. This commit adds a tcpdump-wrapper utility for such purpose. It uses the Open vSwitch python library to add/remove ports and mirrors to/from the Open vSwitch database. It will create a tcpdump instance listening on the mirror port (allowing the user to specify additional arguments), and dump data to the screen (or otherwise). Signed-off-by: Aaron Conole <aconole@redhat.com> Signed-off-by: Ben Pfaff <blp@ovn.org> Acked-by: Flavio Leitner <fbl@sysclose.org>
This commit is contained in:
parent
8e2b26562c
commit
314ce6479a
2
NEWS
2
NEWS
@ -62,6 +62,8 @@ Post-v2.5.0
|
|||||||
* Flow based tunnel match and action can be used for IPv6 address using
|
* Flow based tunnel match and action can be used for IPv6 address using
|
||||||
tun_ipv6_src, tun_ipv6_dst fields.
|
tun_ipv6_src, tun_ipv6_dst fields.
|
||||||
* Added support for IPv6 tunnels to native tunneling.
|
* Added support for IPv6 tunnels to native tunneling.
|
||||||
|
- A wrapper script, 'ovs-tcpdump', to easily port-mirror an OVS port and
|
||||||
|
watch with tcpdump
|
||||||
|
|
||||||
v2.5.0 - 26 Feb 2016
|
v2.5.0 - 26 Feb 2016
|
||||||
---------------------
|
---------------------
|
||||||
|
@ -164,6 +164,12 @@ utilities/ovs-pki.8: \
|
|||||||
utilities/ovs-pki.8.in
|
utilities/ovs-pki.8.in
|
||||||
utilities/ovs-pki.8.in:
|
utilities/ovs-pki.8.in:
|
||||||
|
|
||||||
|
utilities/ovs-tcpdump.8: \
|
||||||
|
utilities/ovs-tcpdump.8.in \
|
||||||
|
lib/common.man
|
||||||
|
utilities/ovs-tcpdump.8.in:
|
||||||
|
lib/common.man:
|
||||||
|
|
||||||
utilities/ovs-tcpundump.1: \
|
utilities/ovs-tcpundump.1: \
|
||||||
utilities/ovs-tcpundump.1.in \
|
utilities/ovs-tcpundump.1.in \
|
||||||
lib/common-syn.man \
|
lib/common-syn.man \
|
||||||
|
2
utilities/.gitignore
vendored
2
utilities/.gitignore
vendored
@ -26,6 +26,8 @@
|
|||||||
/ovs-pki.8
|
/ovs-pki.8
|
||||||
/ovs-test
|
/ovs-test
|
||||||
/ovs-test.8
|
/ovs-test.8
|
||||||
|
/ovs-tcpdump
|
||||||
|
/ovs-tcpdump.8
|
||||||
/ovs-tcpundump
|
/ovs-tcpundump
|
||||||
/ovs-tcpundump.1
|
/ovs-tcpundump.1
|
||||||
/ovs-vlan-bug-workaround
|
/ovs-vlan-bug-workaround
|
||||||
|
@ -12,6 +12,7 @@ bin_SCRIPTS += \
|
|||||||
utilities/ovs-l3ping \
|
utilities/ovs-l3ping \
|
||||||
utilities/ovs-parse-backtrace \
|
utilities/ovs-parse-backtrace \
|
||||||
utilities/ovs-pcap \
|
utilities/ovs-pcap \
|
||||||
|
utilities/ovs-tcpdump \
|
||||||
utilities/ovs-tcpundump \
|
utilities/ovs-tcpundump \
|
||||||
utilities/ovs-test \
|
utilities/ovs-test \
|
||||||
utilities/ovs-vlan-test
|
utilities/ovs-vlan-test
|
||||||
@ -52,6 +53,7 @@ EXTRA_DIST += \
|
|||||||
utilities/ovs-pipegen.py \
|
utilities/ovs-pipegen.py \
|
||||||
utilities/ovs-pki.in \
|
utilities/ovs-pki.in \
|
||||||
utilities/ovs-save \
|
utilities/ovs-save \
|
||||||
|
utilities/ovs-tcpdump.in \
|
||||||
utilities/ovs-tcpundump.in \
|
utilities/ovs-tcpundump.in \
|
||||||
utilities/ovs-test.in \
|
utilities/ovs-test.in \
|
||||||
utilities/ovs-vlan-test.in \
|
utilities/ovs-vlan-test.in \
|
||||||
@ -69,6 +71,7 @@ MAN_ROOTS += \
|
|||||||
utilities/ovs-parse-backtrace.8 \
|
utilities/ovs-parse-backtrace.8 \
|
||||||
utilities/ovs-pcap.1.in \
|
utilities/ovs-pcap.1.in \
|
||||||
utilities/ovs-pki.8.in \
|
utilities/ovs-pki.8.in \
|
||||||
|
utilities/ovs-tcpdump.8.in \
|
||||||
utilities/ovs-tcpundump.1.in \
|
utilities/ovs-tcpundump.1.in \
|
||||||
utilities/ovs-vlan-bug-workaround.8.in \
|
utilities/ovs-vlan-bug-workaround.8.in \
|
||||||
utilities/ovs-test.8.in \
|
utilities/ovs-test.8.in \
|
||||||
@ -94,6 +97,8 @@ DISTCLEANFILES += \
|
|||||||
utilities/ovs-pki.8 \
|
utilities/ovs-pki.8 \
|
||||||
utilities/ovs-sim \
|
utilities/ovs-sim \
|
||||||
utilities/ovs-sim.1 \
|
utilities/ovs-sim.1 \
|
||||||
|
utilities/ovs-tcpdump \
|
||||||
|
utilities/ovs-tcpdump.8 \
|
||||||
utilities/ovs-tcpundump \
|
utilities/ovs-tcpundump \
|
||||||
utilities/ovs-tcpundump.1 \
|
utilities/ovs-tcpundump.1 \
|
||||||
utilities/ovs-test \
|
utilities/ovs-test \
|
||||||
@ -114,6 +119,7 @@ man_MANS += \
|
|||||||
utilities/ovs-parse-backtrace.8 \
|
utilities/ovs-parse-backtrace.8 \
|
||||||
utilities/ovs-pcap.1 \
|
utilities/ovs-pcap.1 \
|
||||||
utilities/ovs-pki.8 \
|
utilities/ovs-pki.8 \
|
||||||
|
utilities/ovs-tcpdump.8 \
|
||||||
utilities/ovs-tcpundump.1 \
|
utilities/ovs-tcpundump.1 \
|
||||||
utilities/ovs-vlan-bug-workaround.8 \
|
utilities/ovs-vlan-bug-workaround.8 \
|
||||||
utilities/ovs-test.8 \
|
utilities/ovs-test.8 \
|
||||||
@ -148,6 +154,7 @@ utilities_nlmon_LDADD = lib/libopenvswitch.la
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
FLAKE8_PYFILES += utilities/ovs-pcap.in \
|
FLAKE8_PYFILES += utilities/ovs-pcap.in \
|
||||||
utilities/checkpatch.py utilities/ovs-dev.py
|
utilities/checkpatch.py utilities/ovs-dev.py \
|
||||||
|
utilities/ovs-tcpdump.in
|
||||||
|
|
||||||
include utilities/bugtool/automake.mk
|
include utilities/bugtool/automake.mk
|
||||||
|
51
utilities/ovs-tcpdump.8.in
Normal file
51
utilities/ovs-tcpdump.8.in
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
.TH ovs\-tcpdump 8 "@VERSION@" "Open vSwitch" "Open vSwitch Manual"
|
||||||
|
.
|
||||||
|
.SH NAME
|
||||||
|
ovs\-tcpdump \- Dump traffic from an Open vSwitch port using \fBtcpdump\fR.
|
||||||
|
.
|
||||||
|
.SH SYNOPSIS
|
||||||
|
\fBovs\-tcpdump\fR \fB\-i\fR \fIport\fR \fBtcpdump options...\fR
|
||||||
|
.
|
||||||
|
.SH DESCRIPTION
|
||||||
|
\fBovs\-tcpdump\fR creates switch mirror ports in the \fBovs\-vswitchd\fR
|
||||||
|
daemon and executes \fBtcpdump\fR to listen against those ports. When the
|
||||||
|
\fBtcpdump\fR instance exits, it then cleans up the mirror port it created.
|
||||||
|
.PP
|
||||||
|
\fBovs\-tcpdump\fR will not allow multiple mirrors for the same port. It has
|
||||||
|
some logic to parse the current configuration and prevent duplicate mirrors.
|
||||||
|
.PP
|
||||||
|
The \fB\-i\fR option may not appear multiple times.
|
||||||
|
.PP
|
||||||
|
It is important to note that under \fBLinux\fR based kernels, tap devices do
|
||||||
|
not receive packets unless the specific tuntap device has been opened by an
|
||||||
|
application. This requires \fBCAP_NET_ADMIN\fR privileges, so the
|
||||||
|
\fBovs-tcpdump\fR command must be run as a user with such permissions (this
|
||||||
|
is usually a super-user).
|
||||||
|
.
|
||||||
|
.SH "OPTIONS"
|
||||||
|
.so lib/common.man
|
||||||
|
.
|
||||||
|
.IP "\fB\-\-db\-sock\fR"
|
||||||
|
The Open vSwitch database socket connection string. The default is
|
||||||
|
\fIunix:@RUNDIR@/db.sock\fR
|
||||||
|
.
|
||||||
|
.IP "\fB\-\-dump\-cmd\fR"
|
||||||
|
The command to run instead of \fBtcpdump\fR.
|
||||||
|
.
|
||||||
|
.IP "\fB\-i\fR"
|
||||||
|
.IQ "\fB\-\-interface\fR"
|
||||||
|
The interface for which a mirror port should be created, and packets should
|
||||||
|
be dumped.
|
||||||
|
.
|
||||||
|
.IP "\fB\-\-mirror\-to\fR"
|
||||||
|
The name of the interface which should be the destination of the mirrored
|
||||||
|
packets. The default is miINTERFACE
|
||||||
|
.
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.
|
||||||
|
.BR ovs\-appctl (8),
|
||||||
|
.BR ovs\-vswitchd (8),
|
||||||
|
.BR ovs\-pcap (1),
|
||||||
|
.BR ovs\-tcpundump (1),
|
||||||
|
.BR tcpdump (8),
|
||||||
|
.BR wireshark (8).
|
453
utilities/ovs-tcpdump.in
Executable file
453
utilities/ovs-tcpdump.in
Executable file
@ -0,0 +1,453 @@
|
|||||||
|
#! /usr/bin/env @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 netifaces
|
||||||
|
import os
|
||||||
|
import pwd
|
||||||
|
import select
|
||||||
|
import struct
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
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 = {}
|
||||||
|
|
||||||
|
|
||||||
|
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):
|
||||||
|
"""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 = open('/dev/net/tun', 'rw')
|
||||||
|
ifr = struct.pack('16sH', tap_name, 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
|
||||||
|
pipe = _doexec(
|
||||||
|
*(['ip', 'link', 'set', 'dev', str(tap_name), 'up']))
|
||||||
|
pipe.wait()
|
||||||
|
|
||||||
|
_make_taps['linux'] = _install_tap_linux
|
||||||
|
_make_taps['linux2'] = _install_tap_linux
|
||||||
|
|
||||||
|
|
||||||
|
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'
|
||||||
|
""" % {'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:
|
||||||
|
row = self._find_row_by_name('Interface', port_name)
|
||||||
|
port = self._find_row('Port', lambda x: row in x.interfaces)
|
||||||
|
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_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, mirror_name, bridge_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):
|
||||||
|
|
||||||
|
txn = self._start_txn()
|
||||||
|
mirror = txn.insert(self.get_table('Mirror'))
|
||||||
|
mirror.name = 'm_%s' % intf_name
|
||||||
|
|
||||||
|
mirror.select_all = False
|
||||||
|
|
||||||
|
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 main():
|
||||||
|
db_sock = 'unix:@RUNDIR@/db.sock'
|
||||||
|
interface = None
|
||||||
|
tcpdargs = []
|
||||||
|
|
||||||
|
skip_next = False
|
||||||
|
mirror_interface = None
|
||||||
|
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
|
||||||
|
tcpdargs.append(cur)
|
||||||
|
|
||||||
|
if interface is None:
|
||||||
|
print("Error: must at least specify an interface with '-i' option")
|
||||||
|
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)
|
||||||
|
mirror_interface = mirror_interface or "mi%s" % interface
|
||||||
|
|
||||||
|
if sys.platform in _make_taps and \
|
||||||
|
mirror_interface not in netifaces.interfaces():
|
||||||
|
_make_taps[sys.platform](mirror_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))
|
||||||
|
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 True:
|
||||||
|
print(pipes.stdout.readline())
|
||||||
|
if select.select([sys.stdin], [], [], 0.0)[0]:
|
||||||
|
data_in = sys.stdin.read()
|
||||||
|
pipes.stdin.write(data_in)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
pipes.terminate()
|
||||||
|
ovsdb.destroy_mirror('m%s' % 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:
|
Loading…
x
Reference in New Issue
Block a user