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

Reply via email to