Currently the ovs-tcpdump utility creates a virtual tunnel to send packets to. This method functions perfectly fine, however, it can greatly impact performance of the monitored port.
It has been reported to reduce packet throughput significantly. I was able to reproduce a reduction in throughput of up 70 percent in some tests with a simple setup of two hosts communicating through a single bridge on Linux with the kernel module datapath. Another more complex test was configured for DPDK and the usermode datapath. This test involved a data path going from a VM, through a port into one OVS bridge, out through a network card which could be DPDK enabled for the relevant tests, in to a different network interface, then into a different OVS bridge, through another port, and then into a virtual machine. Using the dummy driver resulted in the following impact to performance compared to no ovs-tcpdump. Due to intra-test variance and fluctuations during the first few seconds after installing a tap; multiple samples were taken over multiple test runs. The first few seconds worth of results were discarded and then results were averaged out. Original Script =============== Category Impact on Throughput Kernel datapath - 65% Usermode datapath - 26% DPDK datapath - 37% New Script ========== Category Impact on Throughput Kernel datapath - 5% Usermode datapath - 16% DPDK datapath - 29% Signed-off-by: Mike Pattrick <m...@redhat.com> --- utilities/ovs-tcpdump.in | 42 +++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/utilities/ovs-tcpdump.in b/utilities/ovs-tcpdump.in index 5ec02383c..10989dfc1 100755 --- a/utilities/ovs-tcpdump.in +++ b/utilities/ovs-tcpdump.in @@ -14,12 +14,9 @@ # 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 @@ -52,8 +49,8 @@ except Exception: print(" the correct location.") sys.exit(1) -tapdev_fd = None _make_taps = {} +_del_taps = {} _make_mirror_name = {} IFNAMSIZ_LINUX = 15 # this is the max name size, excluding the null byte. @@ -67,21 +64,11 @@ def _doexec(*args, **kwargs): 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()) +def _install_dst_if_linux(tap_name, mtu_value=None): + _doexec( + *['ip', 'link', 'add', str(tap_name), 'type', 'dummy'] + ).wait() - 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', @@ -93,14 +80,22 @@ def _install_tap_linux(tap_name, mtu_value=None): pipe.wait() +def _remove_dst_if_linux(tap_name): + _doexec( + *['ip', 'link', 'del', str(tap_name)] + ).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_taps['linux'] = _install_dst_if_linux +_make_taps['linux2'] = _install_dst_if_linux +_del_taps['linux'] = _remove_dst_if_linux +_del_taps['linux2'] = _remove_dst_if_linux _make_mirror_name['linux'] = _make_linux_mirror_name _make_mirror_name['linux2'] = _make_linux_mirror_name @@ -455,6 +450,9 @@ def main(): mirror_interface not in interfaces(): _make_taps[sys.platform](mirror_interface, ovsdb.interface_mtu(interface)) + tap_created = True + else: + tap_created = False if mirror_interface not in interfaces(): print("ERROR: Please create an interface called `%s`" % @@ -480,6 +478,8 @@ def main(): print("ERROR: Unable to properly setup the mirror: %s." % str(oe)) try: ovsdb.destroy_port(mirror_interface, ovsdb.port_bridge(interface)) + if tap_created is True: + _del_taps[sys.platform](mirror_interface) except Exception: pass sys.exit(1) @@ -498,6 +498,8 @@ def main(): ovsdb.destroy_mirror(interface, ovsdb.port_bridge(interface)) ovsdb.destroy_port(mirror_interface, ovsdb.port_bridge(interface)) + if tap_created is True: + _del_taps[sys.platform](mirror_interface) except Exception: print("Unable to tear down the ports and mirrors.") print("Please use ovs-vsctl to remove the ports and mirrors created.") -- 2.30.2 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev