Merge branch 'master' of ssh://git.onelab.eu/git/sliver-openvswitch
authorGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Tue, 21 Jan 2014 15:40:17 +0000 (16:40 +0100)
committerGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Tue, 21 Jan 2014 15:40:17 +0000 (16:40 +0100)
Conflicts:
sliver-openvswitch.spec

132 files changed:
AUTHORS
FAQ
INSTALL
INSTALL.NetBSD
INSTALL.RHEL
Makefile.am
NEWS
README
acinclude.m4
configure.ac
datapath/datapath.c
datapath/flow_table.c
datapath/flow_table.h
datapath/linux/compat/include/net/sctp/checksum.h
debian/.gitignore
debian/automake.mk
debian/control
debian/ovsdbmonitor.install [deleted file]
debian/ovsdbmonitor.manpages [deleted file]
debian/rules
include/linux/types.h
include/sparse/automake.mk
include/sparse/netpacket/packet.h [new file with mode: 0644]
include/sparse/sys/socket.h
lib/automake.mk
lib/bfd.c
lib/cfm.c
lib/classifier.c
lib/classifier.h
lib/dpif-linux.c
lib/dpif-netdev.c
lib/dpif-provider.h
lib/fat-rwlock.c [new file with mode: 0644]
lib/fat-rwlock.h [new file with mode: 0644]
lib/flow.c
lib/lacp.c
lib/latch-windows.c [new file with mode: 0644]
lib/latch.c
lib/latch.h
lib/mac-learning.c
lib/mac-learning.h
lib/netdev-bsd.c
lib/netdev-dummy.c
lib/netdev-linux.c
lib/netdev-pltap.c
lib/netdev-provider.h
lib/netdev-tunnel.c
lib/netdev.c
lib/netlink-socket.c
lib/odp-execute.c
lib/ovs-atomic-c11.h
lib/ovs-atomic-clang.h
lib/ovs-atomic-flag-gcc4.7+.h
lib/ovs-atomic-gcc4+.h
lib/ovs-atomic-gcc4.7+.h
lib/ovs-atomic-pthreads.c
lib/ovs-atomic-pthreads.h
lib/ovs-atomic.h
lib/ovs-thread.c
lib/ovs-thread.h
lib/packets.c
lib/packets.h
lib/poll-loop.c
lib/poll-loop.h
lib/sflow_receiver.c
lib/stp.c
lib/timeval.c
lib/timeval.h
lib/util.c
m4/openvswitch.m4
ofproto/bond.c
ofproto/connmgr.c
ofproto/fail-open.c
ofproto/fail-open.h
ofproto/netflow.c
ofproto/ofproto-dpif-ipfix.c
ofproto/ofproto-dpif-monitor.c
ofproto/ofproto-dpif-sflow.c
ofproto/ofproto-dpif-upcall.c
ofproto/ofproto-dpif-xlate.c
ofproto/ofproto-dpif.c
ofproto/ofproto-dpif.h
ofproto/ofproto-provider.h
ofproto/ofproto.c
ofproto/tunnel.c
ovsdb/automake.mk
ovsdb/ovsdbmonitor/.gitignore [deleted file]
ovsdb/ovsdbmonitor/COPYING [deleted file]
ovsdb/ovsdbmonitor/ConfigWindow.ui [deleted file]
ovsdb/ovsdbmonitor/FlowWindow.ui [deleted file]
ovsdb/ovsdbmonitor/HostWindow.ui [deleted file]
ovsdb/ovsdbmonitor/LogWindow.ui [deleted file]
ovsdb/ovsdbmonitor/MainWindow.ui [deleted file]
ovsdb/ovsdbmonitor/OVEApp.py [deleted file]
ovsdb/ovsdbmonitor/OVECommonWindow.py [deleted file]
ovsdb/ovsdbmonitor/OVEConfig.py [deleted file]
ovsdb/ovsdbmonitor/OVEConfigWindow.py [deleted file]
ovsdb/ovsdbmonitor/OVEFetch.py [deleted file]
ovsdb/ovsdbmonitor/OVEFlowWindow.py [deleted file]
ovsdb/ovsdbmonitor/OVEHostWindow.py [deleted file]
ovsdb/ovsdbmonitor/OVELogWindow.py [deleted file]
ovsdb/ovsdbmonitor/OVELogger.py [deleted file]
ovsdb/ovsdbmonitor/OVEMainWindow.py [deleted file]
ovsdb/ovsdbmonitor/OVEStandard.py [deleted file]
ovsdb/ovsdbmonitor/OVEUtil.py [deleted file]
ovsdb/ovsdbmonitor/Ui_ConfigWindow.py [deleted file]
ovsdb/ovsdbmonitor/Ui_FlowWindow.py [deleted file]
ovsdb/ovsdbmonitor/Ui_HostWindow.py [deleted file]
ovsdb/ovsdbmonitor/Ui_LogWindow.py [deleted file]
ovsdb/ovsdbmonitor/Ui_MainWindow.py [deleted file]
ovsdb/ovsdbmonitor/automake.mk [deleted file]
ovsdb/ovsdbmonitor/ovsdbmonitor.1 [deleted file]
ovsdb/ovsdbmonitor/ovsdbmonitor.desktop [deleted file]
ovsdb/ovsdbmonitor/ovsdbmonitor.in [deleted file]
ovsdb/ovsdbmonitor/qt4reactor.py [deleted file]
rhel/README.RHEL
rhel/automake.mk
rhel/etc_sysconfig_network-scripts_ifdown-ovs
rhel/etc_sysconfig_network-scripts_ifup-ovs
rhel/openvswitch-fedora.spec.in
rhel/usr_lib_systemd_system_openvswitch-nonetwork.service [new file with mode: 0644]
rhel/usr_lib_systemd_system_openvswitch.service
rhel/usr_share_openvswitch_scripts_systemd_sysconfig.template [new file with mode: 0644]
sliver-openvswitch.spec
tests/automake.mk
tests/classifier.at
tests/test-atomic.c
tests/test-classifier.c
tests/tunnel.at
utilities/ovs-ofctl.c
utilities/ovs-vsctl.8.in
vswitchd/bridge.c

diff --git a/AUTHORS b/AUTHORS
index 5dccb6b..218fe76 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -27,6 +27,7 @@ Damien Millescamps      damien.millescamps@6wind.com
 Dan Carpenter           dan.carpenter@oracle.com
 Dan Wendlandt           dan@nicira.com
 Daniel Roman            droman@nicira.com
+Daniele Venturino       daniele.venturino@m3s.it
 Danny Kukawka           danny.kukawka@bisect.de
 David Erickson          derickso@stanford.edu
 David S. Miller         davem@davemloft.net
diff --git a/FAQ b/FAQ
index 1edcd94..75d9e6b 100644 (file)
--- a/FAQ
+++ b/FAQ
@@ -641,6 +641,17 @@ A: In version 1.9.0, OVS switched to using a single datapath that is
    shared by all bridges of that type.  The "ovs-appctl dpif/*"
    commands provide similar functionality that is scoped by the bridge.
 
+Q: I created a GRE port using ovs-vsctl so why can't I send traffic or
+   see the port in the datapath?
+
+A: On Linux kernels before 3.11, the OVS GRE module and Linux GRE module
+   cannot be loaded at the same time. It is likely that on your system the
+   Linux GRE module is already loaded and blocking OVS (to confirm, check
+   dmesg for errors regarding GRE registration). To fix this, unload all
+   GRE modules that appear in lsmod as well as the OVS kernel module. You
+   can then reload the OVS module following the directions in INSTALL,
+   which will ensure that dependencies are satisfied.
+
 
 Quality of Service (QoS)
 ------------------------
diff --git a/INSTALL b/INSTALL
index 95ee898..001d3cb 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -34,6 +34,8 @@ you will need the following software:
       libssl is installed, then Open vSwitch will automatically build
       with support for it.
 
+    - Python 2.x, for x >= 4.
+
 To compile the kernel module on Linux, you must also install the
 following.  If you cannot build or install the kernel module, you may
 use the userspace-only implementation, at a cost in performance.  The
@@ -82,12 +84,7 @@ or the database schema, you will also need the following software:
 
     - Automake version 1.10 or later.
 
-    - Python 2.x, for x >= 4.
-
-If you modify the ovsdbmonitor tool, then you will also need the
-following:
-
-    - pyuic4 from PyQt4 (http://www.riverbankcomputing.co.uk).
+    - libtool version 2.4 or later.  (Older versions might work too.)
 
 To run the unit tests, you also need:
 
@@ -136,22 +133,6 @@ following software:
 On Linux you should ensure that /dev/urandom exists.  To support TAP
 devices, you must also ensure that /dev/net/tun exists.
 
-To run the ovsdbmonitor tool, the machine must also have the following
-software:
-
-    - Python 2.x, for x >= 4.
-
-    - Python Twisted Conch.
-
-    - Python JSON.
-
-    - PySide or PyQt4.
-
-    - Python Zope interface module.
-
-(On Debian "lenny" the above can be installed with "apt-get install
-python-json python-qt4 python-zopeinterface python-twisted-conch".)
-
 Building and Installing Open vSwitch for Linux, FreeBSD or NetBSD
 =================================================================
 
index 49782a8..aab8793 100644 (file)
@@ -11,8 +11,7 @@ In that case, you need at least the following packages.
        py27-xml
        pkg_alternatives
 
-Some components (eg. ovsdbmonitor) have additional requirements.
-(See INSTALL)
+Some components have additional requirements.  (See INSTALL)
 
 Assuming you are running NetBSD/amd64 6.1.2, you can download and
 install pre-built binary packages as the following.
index 9ab5384..f46ad98 100644 (file)
@@ -34,8 +34,9 @@ RHEL.  On RHEL 5, the default RPM source directory is
 
 2. Install build prerequisites:
 
-   yum install gcc make python-devel openssl-devel kernel-devel, graphviz \
-       kernel-debug-devel autoconf automake rpm-build redhat-rpm-config
+   yum install gcc make python-devel openssl-devel kernel-devel graphviz \
+       kernel-debug-devel autoconf automake rpm-build redhat-rpm-config \
+       libtool
 
 3. Some versions of the RHEL 6 kernel-devel package contain a broken
    "build" symlink.  If you are using such a version, you must fix
index 670f5f0..c0e2787 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+# Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
 #
 # Copying and distribution of this file, with or without modification,
 # are permitted in any medium without royalty provided the copyright
@@ -140,7 +140,6 @@ SUFFIXES += .in
                 -e 's,[@]bindir[@],$(bindir),g' \
                 -e 's,[@]sbindir[@],$(sbindir),g' \
                 -e 's,[@]abs_top_srcdir[@],$(abs_top_srcdir),g' \
-                -e 's,[@]ovsdbmonitordir[@],$(ovsdbmonitordir),g' \
             > $@.tmp
        @if head -n 1 $@.tmp | grep '#!' > /dev/null; then \
            echo chmod +x $@.tmp; \
diff --git a/NEWS b/NEWS
index 515a236..8689f5c 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
 Post-v2.1.0
 ---------------------
-
+   - The "ovsdbmonitor" graphical tool has been removed, because it was
+     poorly maintained and not widely used.
 
 v2.1.0 - xx xxx xxxx
 ---------------------
diff --git a/README b/README
index 63f2933..f6d1a19 100644 (file)
--- a/README
+++ b/README
@@ -64,9 +64,6 @@ The main components of this distribution are:
     * ovs-appctl, a utility that sends commands to running Open
       vSwitch daemons.
 
-    * ovsdbmonitor, a GUI tool for remotely viewing OVS databases and
-      OpenFlow flow tables.
-
 Open vSwitch also provides some tools:
 
     * ovs-ofctl, a utility for querying and controlling OpenFlow
index 7078654..8ff5828 100644 (file)
@@ -281,6 +281,8 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
   OVS_GREP_IFELSE([$KSRC/include/net/netlink.h], [nla_put_be64])
   OVS_GREP_IFELSE([$KSRC/include/net/netlink.h], [nla_find_nested])
 
+  OVS_GREP_IFELSE([$KSRC/include/net/sctp/checksum.h], [sctp_compute_cksum])
+
   OVS_GREP_IFELSE([$KSRC/include/linux/if_vlan.h], [ADD_ALL_VLANS_CMD],
                   [OVS_DEFINE([HAVE_VLAN_BUG_WORKAROUND])])
 
index f6a11f0..9b6c69e 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+# Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -41,6 +41,8 @@ AC_C_BIGENDIAN
 AC_SYS_LARGEFILE
 
 LT_INIT([disable-shared])
+m4_pattern_forbid([LT_INIT]) dnl Make autoconf fail if libtool is missing.
+
 AC_SEARCH_LIBS([pow], [m])
 AC_SEARCH_LIBS([clock_gettime], [rt])
 AC_SEARCH_LIBS([timer_create], [rt])
@@ -55,8 +57,6 @@ OVS_CHECK_NETLINK
 OVS_CHECK_OPENSSL
 OVS_CHECK_LOGDIR
 OVS_CHECK_PYTHON
-OVS_CHECK_PYUIC4
-OVS_CHECK_OVSDBMONITOR
 OVS_CHECK_PYTHON_COMPAT
 OVS_CHECK_DOT
 OVS_CHECK_IF_PACKET
@@ -130,7 +130,6 @@ AC_CONFIG_FILES(tests/atlocal)
 dnl This makes sure that include/openflow gets created in the build directory.
 AC_CONFIG_COMMANDS([include/openflow/openflow.h.stamp])
 
-AC_CONFIG_COMMANDS([ovsdb/ovsdbmonitor/dummy], [:])
 AC_CONFIG_COMMANDS([utilities/bugtool/dummy], [:])
 
 AM_CONDITIONAL([LINUX_DATAPATH], [test "$HAVE_NETLINK" = yes && test "$ESX" = no])
index b42fd8b..c756e2f 100644 (file)
@@ -56,6 +56,7 @@
 
 #include "datapath.h"
 #include "flow.h"
+#include "flow_table.h"
 #include "flow_netlink.h"
 #include "vlan.h"
 #include "vport-internal_dev.h"
@@ -162,7 +163,6 @@ static void destroy_dp_rcu(struct rcu_head *rcu)
 {
        struct datapath *dp = container_of(rcu, struct datapath, rcu);
 
-       ovs_flow_tbl_destroy(&dp->table);
        free_percpu(dp->stats_percpu);
        release_net(ovs_dp_get_net(dp));
        kfree(dp->ports);
@@ -400,7 +400,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
 #endif
                .snd_portid = upcall_info->portid,
        };
-       size_t len;
+       size_t len, plen;
        unsigned int hlen;
        int err, dp_ifindex;
 
@@ -471,6 +471,11 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
 
        skb_zerocopy(user_skb, skb, skb->len, hlen);
 
+       /* Pad OVS_PACKET_ATTR_PACKET if linear copy was performed */
+       if (!(dp->user_features & OVS_DP_F_UNALIGNED) &&
+           (plen = (ALIGN(user_skb->len, NLA_ALIGNTO) - user_skb->len)) > 0)
+               memset(skb_put(user_skb, plen), 0, plen);
+
        ((struct nlmsghdr *) user_skb->data)->nlmsg_len = user_skb->len;
 
        err = genlmsg_unicast(ovs_dp_get_net(dp), user_skb, upcall_info->portid);
@@ -1278,7 +1283,7 @@ err_destroy_ports_array:
 err_destroy_percpu:
        free_percpu(dp->stats_percpu);
 err_destroy_table:
-       ovs_flow_tbl_destroy(&dp->table);
+       ovs_flow_tbl_destroy(&dp->table, false);
 err_free_dp:
        release_net(ovs_dp_get_net(dp));
        kfree(dp);
@@ -1305,10 +1310,13 @@ static void __dp_destroy(struct datapath *dp)
        list_del_rcu(&dp->list_node);
 
        /* OVSP_LOCAL is datapath internal port. We need to make sure that
-        * all port in datapath are destroyed first before freeing datapath.
-        */
+        * all ports in datapath are destroyed first before freeing datapath.
+        */
        ovs_dp_detach_port(ovs_vport_ovsl(dp, OVSP_LOCAL));
 
+       /* RCU destroy the flow table */
+       ovs_flow_tbl_destroy(&dp->table, true);
+
        call_rcu(&dp->rcu, destroy_dp_rcu);
 }
 
index cc0a8e4..2e8557c 100644 (file)
@@ -106,7 +106,7 @@ struct sw_flow *ovs_flow_alloc(bool percpu_stats)
        }
        return flow;
 err:
-       kfree(flow);
+       kmem_cache_free(flow_cache, flow);
        return ERR_PTR(-ENOMEM);
 }
 
@@ -162,29 +162,27 @@ static void rcu_free_sw_flow_mask_cb(struct rcu_head *rcu)
        kfree(mask);
 }
 
-static void flow_mask_del_ref(struct sw_flow_mask *mask, bool deferred)
+void ovs_flow_free(struct sw_flow *flow, bool deferred)
 {
-       if (!mask)
+       if (!flow)
                return;
 
-       BUG_ON(!mask->ref_count);
-       mask->ref_count--;
+       ASSERT_OVSL();
 
-       if (!mask->ref_count) {
-               list_del_rcu(&mask->list);
-               if (deferred)
-                       call_rcu(&mask->rcu, rcu_free_sw_flow_mask_cb);
-               else
-                       kfree(mask);
-       }
-}
+       if (flow->mask) {
+               struct sw_flow_mask *mask = flow->mask;
 
-void ovs_flow_free(struct sw_flow *flow, bool deferred)
-{
-       if (!flow)
-               return;
+               BUG_ON(!mask->ref_count);
+               mask->ref_count--;
 
-       flow_mask_del_ref(flow->mask, deferred);
+               if (!mask->ref_count) {
+                       list_del_rcu(&mask->list);
+                       if (deferred)
+                               call_rcu(&mask->rcu, rcu_free_sw_flow_mask_cb);
+                       else
+                               kfree(mask);
+               }
+       }
 
        if (deferred)
                call_rcu(&flow->rcu, rcu_free_flow_callback);
@@ -197,26 +195,9 @@ static void free_buckets(struct flex_array *buckets)
        flex_array_free(buckets);
 }
 
+
 static void __table_instance_destroy(struct table_instance *ti)
 {
-       int i;
-
-       if (ti->keep_flows)
-               goto skip_flows;
-
-       for (i = 0; i < ti->n_buckets; i++) {
-               struct sw_flow *flow;
-               struct hlist_head *head = flex_array_get(ti->buckets, i);
-               struct hlist_node *n;
-               int ver = ti->node_ver;
-
-               hlist_for_each_entry_safe(flow, n, head, hash_node[ver]) {
-                       hlist_del(&flow->hash_node[ver]);
-                       ovs_flow_free(flow, false);
-               }
-       }
-
-skip_flows:
        free_buckets(ti->buckets);
        kfree(ti);
 }
@@ -267,20 +248,38 @@ static void flow_tbl_destroy_rcu_cb(struct rcu_head *rcu)
 
 static void table_instance_destroy(struct table_instance *ti, bool deferred)
 {
+       int i;
+
        if (!ti)
                return;
 
+       if (ti->keep_flows)
+               goto skip_flows;
+
+       for (i = 0; i < ti->n_buckets; i++) {
+               struct sw_flow *flow;
+               struct hlist_head *head = flex_array_get(ti->buckets, i);
+               struct hlist_node *n;
+               int ver = ti->node_ver;
+
+               hlist_for_each_entry_safe(flow, n, head, hash_node[ver]) {
+                       hlist_del_rcu(&flow->hash_node[ver]);
+                       ovs_flow_free(flow, deferred);
+               }
+       }
+
+skip_flows:
        if (deferred)
                call_rcu(&ti->rcu, flow_tbl_destroy_rcu_cb);
        else
                __table_instance_destroy(ti);
 }
 
-void ovs_flow_tbl_destroy(struct flow_table *table)
+void ovs_flow_tbl_destroy(struct flow_table *table, bool deferred)
 {
        struct table_instance *ti = ovsl_dereference(table->ti);
 
-       table_instance_destroy(ti, false);
+       table_instance_destroy(ti, deferred);
 }
 
 struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *ti,
@@ -513,16 +512,11 @@ static struct sw_flow_mask *mask_alloc(void)
 
        mask = kmalloc(sizeof(*mask), GFP_KERNEL);
        if (mask)
-               mask->ref_count = 0;
+               mask->ref_count = 1;
 
        return mask;
 }
 
-static void mask_add_ref(struct sw_flow_mask *mask)
-{
-       mask->ref_count++;
-}
-
 static bool mask_equal(const struct sw_flow_mask *a,
                       const struct sw_flow_mask *b)
 {
@@ -563,9 +557,11 @@ static int flow_mask_insert(struct flow_table *tbl, struct sw_flow *flow,
                mask->key = new->key;
                mask->range = new->range;
                list_add_rcu(&mask->list, &tbl->mask_list);
+       } else {
+               BUG_ON(!mask->ref_count);
+               mask->ref_count++;
        }
 
-       mask_add_ref(mask);
        flow->mask = mask;
        return 0;
 }
index 1996e34..baaeb10 100644 (file)
@@ -60,7 +60,7 @@ void ovs_flow_free(struct sw_flow *, bool deferred);
 
 int ovs_flow_tbl_init(struct flow_table *);
 int ovs_flow_tbl_count(struct flow_table *table);
-void ovs_flow_tbl_destroy(struct flow_table *table);
+void ovs_flow_tbl_destroy(struct flow_table *table, bool deferred);
 int ovs_flow_tbl_flush(struct flow_table *flow_table);
 
 int ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow,
index 59d209b..7832abc 100644 (file)
@@ -1,10 +1,9 @@
 #ifndef __SCTP_CHECKSUM_WRAPPER_H
 #define __SCTP_CHECKSUM_WRAPPER_H 1
 
-#include <linux/version.h>
 #include_next <net/sctp/checksum.h>
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0)
+#ifndef HAVE_SCTP_COMPUTE_CKSUM
 static inline __le32 sctp_compute_cksum(const struct sk_buff *skb,
                                        unsigned int offset)
 {
index c1aa059..3d37698 100644 (file)
@@ -16,6 +16,5 @@
 /openvswitch-switch
 /openvswitch-switch.copyright
 /openvswitch-test
-/ovsdbmonitor
 /python-openvswitch
 /tmp
index 59db61d..948a619 100644 (file)
@@ -42,8 +42,6 @@ EXTRA_DIST += \
        debian/openvswitch-vtep.init \
        debian/openvswitch-vtep.install \
        debian/openvswitch-vtep.manpages \
-       debian/ovsdbmonitor.install \
-       debian/ovsdbmonitor.manpages \
        debian/ovs-monitor-ipsec \
        debian/python-openvswitch.dirs \
        debian/python-openvswitch.install \
index 4c439b6..b3e89df 100644 (file)
@@ -7,7 +7,7 @@ Build-Depends:
  debhelper (>= 8), autoconf (>= 2.64), automake (>= 1.10) | automake1.10, 
  libssl-dev, bzip2, openssl, graphviz,
  python-all (>= 2.6.6-3~), procps, python-qt4,
- python-zopeinterface, python-twisted-conch
+ python-zopeinterface, python-twisted-conch, libtool
 Standards-Version: 3.9.3
 Homepage: http://openvswitch.org/
 
@@ -152,25 +152,6 @@ Description: Python bindings for Open vSwitch
  .
  This package contains the full Python bindings for Open vSwitch database.
 
-Package: ovsdbmonitor
-Architecture: all
-Section: utils
-Depends: ${python:Depends}, python-openvswitch, ${misc:Depends}
-Description: Open vSwitch graphical monitoring tool
- Open vSwitch is a production quality, multilayer, software-based,
- Ethernet virtual switch. It is designed to enable massive network
- automation through programmatic extension, while still supporting
- standard management interfaces and protocols (e.g. NetFlow, IPFIX,
- sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag). In addition, it is designed
- to support distribution across multiple physical servers similar to
- VMware's vNetwork distributed vswitch or Cisco's Nexus 1000V.
- .
- This package is a GUI tool for monitoring and troubleshooting local
- or remote Open vSwitch installations.  It presents GUI tables that
- graphically represent an Open vSwitch kernel flow table (similar to
- "ovs-dpctl dump-flows") and Open vSwitch database contents (similar
- to "ovs-vsctl list <table>").
-
 Package: openvswitch-test
 Architecture: all
 Depends: ${misc:Depends}, ${python:Depends}, python-twisted-web, python (>= 2.7) | python-argparse
diff --git a/debian/ovsdbmonitor.install b/debian/ovsdbmonitor.install
deleted file mode 100644 (file)
index 0572be4..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-usr/bin/ovsdbmonitor
-usr/share/ovsdbmonitor
diff --git a/debian/ovsdbmonitor.manpages b/debian/ovsdbmonitor.manpages
deleted file mode 100644 (file)
index b30fc8e..0000000
+++ /dev/null
@@ -1 +0,0 @@
-ovsdb/ovsdbmonitor/ovsdbmonitor.1
index b21c8db..799bf2e 100755 (executable)
@@ -107,7 +107,6 @@ install-indep: build-indep
        # And we should also clean useless license files, which are already
        # descriped in our debian/copyright anyway.
        rm -f debian/$(pdkms)/usr/src/$(PACKAGE)-$(DEB_UPSTREAM_VERSION)/COPYING \
-               debian/$(pdkms)/usr/src/$(PACKAGE)-$(DEB_UPSTREAM_VERSION)/ovsdb/ovsdbmonitor/COPYING \
                debian/$(pdkms)/usr/src/$(PACKAGE)-$(DEB_UPSTREAM_VERSION)/xenserver/LICENSE
 
 install-arch: build-arch
index b88fb1c..d8b993b 100644 (file)
@@ -55,4 +55,8 @@ typedef uint32_t __bitwise__ __be32;
 typedef uint64_t __bitwise__ __be64;
 #endif /* no <linux/types.h> */
 
+#ifndef _WIN32
+typedef __u32 HANDLE;
+#endif
+
 #endif /* <linux/types.h> */
index 45ae1f5..572c7c2 100644 (file)
@@ -4,6 +4,7 @@ noinst_HEADERS += \
         include/sparse/math.h \
         include/sparse/netinet/in.h \
         include/sparse/netinet/ip6.h \
+        include/sparse/netpacket/packet.h \
         include/sparse/pthread.h \
         include/sparse/sys/socket.h \
         include/sparse/sys/wait.h
diff --git a/include/sparse/netpacket/packet.h b/include/sparse/netpacket/packet.h
new file mode 100644 (file)
index 0000000..21bdd2e
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014 Nicira, 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.
+ */
+
+#ifndef __CHECKER__
+#error "Use this header only with sparse.  It is not a correct implementation."
+#endif
+
+#ifndef __NETPACKET_PACKET_SPARSE
+#define __NETPACKET_PACKET_SPARSE 1
+
+#include "openvswitch/types.h"
+
+struct sockaddr_ll
+  {
+    unsigned short int sll_family;
+    ovs_be16 sll_protocol;
+    int sll_ifindex;
+    unsigned short int sll_hatype;
+    unsigned char sll_pkttype;
+    unsigned char sll_halen;
+    unsigned char sll_addr[8];
+  };
+
+#endif /* <netpacket/packet.h> sparse */
index 75ee43c..3212bf4 100644 (file)
@@ -87,6 +87,7 @@ enum {
 };
 
 enum {
+    SOL_PACKET,
     SOL_SOCKET
 };
 
index 5e90f9f..7900fa3 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
 #
 # Copying and distribution of this file, with or without modification,
 # are permitted in any medium without royalty provided the copyright
@@ -57,6 +57,8 @@ lib_libopenvswitch_la_SOURCES = \
        lib/dynamic-string.h \
        lib/entropy.c \
        lib/entropy.h \
+       lib/fat-rwlock.c \
+       lib/fat-rwlock.h \
        lib/fatal-signal.c \
        lib/fatal-signal.h \
        lib/flow.c \
@@ -79,7 +81,6 @@ lib_libopenvswitch_la_SOURCES = \
        lib/jsonrpc.h \
        lib/lacp.c \
        lib/lacp.h \
-       lib/latch.c \
        lib/latch.h \
        lib/learn.c \
        lib/learn.h \
@@ -239,6 +240,12 @@ lib_libopenvswitch_la_SOURCES = \
        lib/vswitch-idl.h \
        lib/vtep-idl.c \
        lib/vtep-idl.h
+if WIN32
+lib_libopenvswitch_la_SOURCES += lib/latch-windows.c
+else
+lib_libopenvswitch_la_SOURCES += lib/latch.c
+endif
+
 EXTRA_DIST += \
        lib/stdio.h.in \
        lib/string.h.in
index b8574d5..347444f 100644 (file)
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -193,7 +193,7 @@ struct bfd {
     int forwarding_override;      /* Manual override of 'forwarding' status. */
 
     atomic_bool check_tnl_key;    /* Verify tunnel key of inbound packets? */
-    atomic_int ref_cnt;
+    struct ovs_refcount ref_cnt;
 
     /* When forward_if_rx is true, bfd_forwarding() will return
      * true as long as there are incoming packets received.
@@ -341,7 +341,7 @@ bfd_configure(struct bfd *bfd, const char *name, const struct smap *cfg,
         bfd->diag = DIAG_NONE;
         bfd->min_tx = 1000;
         bfd->mult = 3;
-        atomic_init(&bfd->ref_cnt, 1);
+        ovs_refcount_init(&bfd->ref_cnt);
         bfd->netdev = netdev_ref(netdev);
         bfd->rx_packets = bfd_rx_packets(bfd);
         bfd->in_decay = false;
@@ -403,9 +403,7 @@ bfd_configure(struct bfd *bfd, const char *name, const struct smap *cfg,
     cpath_down = smap_get_bool(cfg, "cpath_down", false);
     if (bfd->cpath_down != cpath_down) {
         bfd->cpath_down = cpath_down;
-        if (bfd->diag == DIAG_NONE || bfd->diag == DIAG_CPATH_DOWN) {
-            bfd_set_state(bfd, bfd->state, DIAG_NONE);
-        }
+        bfd_set_state(bfd, bfd->state, DIAG_NONE);
         need_poll = true;
     }
 
@@ -440,9 +438,7 @@ bfd_ref(const struct bfd *bfd_)
 {
     struct bfd *bfd = CONST_CAST(struct bfd *, bfd_);
     if (bfd) {
-        int orig;
-        atomic_add(&bfd->ref_cnt, 1, &orig);
-        ovs_assert(orig > 0);
+        ovs_refcount_ref(&bfd->ref_cnt);
     }
     return bfd;
 }
@@ -450,19 +446,14 @@ bfd_ref(const struct bfd *bfd_)
 void
 bfd_unref(struct bfd *bfd) OVS_EXCLUDED(mutex)
 {
-    if (bfd) {
-        int orig;
-
-        atomic_sub(&bfd->ref_cnt, 1, &orig);
-        ovs_assert(orig > 0);
-        if (orig == 1) {
-            ovs_mutex_lock(&mutex);
-            hmap_remove(all_bfds, &bfd->node);
-            netdev_close(bfd->netdev);
-            free(bfd->name);
-            free(bfd);
-            ovs_mutex_unlock(&mutex);
-        }
+    if (bfd && ovs_refcount_unref(&bfd->ref_cnt) == 1) {
+        ovs_mutex_lock(&mutex);
+        hmap_remove(all_bfds, &bfd->node);
+        netdev_close(bfd->netdev);
+        ovs_refcount_destroy(&bfd->ref_cnt);
+        free(bfd->name);
+        free(bfd);
+        ovs_mutex_unlock(&mutex);
     }
 }
 
@@ -1022,7 +1013,7 @@ static void
 bfd_set_state(struct bfd *bfd, enum state state, enum diag diag)
     OVS_REQUIRES(mutex)
 {
-    if (diag == DIAG_NONE && bfd->cpath_down) {
+    if (bfd->cpath_down) {
         diag = DIAG_CPATH_DOWN;
     }
 
index 5ee94d5..583df1d 100644 (file)
--- a/lib/cfm.c
+++ b/lib/cfm.c
@@ -130,7 +130,7 @@ struct cfm {
 
     atomic_bool check_tnl_key; /* Verify the tunnel key of inbound packets? */
     atomic_bool extended;      /* Extended mode. */
-    atomic_int ref_cnt;
+    struct ovs_refcount ref_cnt;
 
     uint64_t flap_count;       /* Count the flaps since boot. */
 };
@@ -337,7 +337,7 @@ cfm_create(const struct netdev *netdev) OVS_EXCLUDED(mutex)
     cfm->flap_count = 0;
     atomic_init(&cfm->extended, false);
     atomic_init(&cfm->check_tnl_key, false);
-    atomic_init(&cfm->ref_cnt, 1);
+    ovs_refcount_init(&cfm->ref_cnt);
 
     ovs_mutex_lock(&mutex);
     cfm_generate_maid(cfm);
@@ -350,15 +350,12 @@ void
 cfm_unref(struct cfm *cfm) OVS_EXCLUDED(mutex)
 {
     struct remote_mp *rmp, *rmp_next;
-    int orig;
 
     if (!cfm) {
         return;
     }
 
-    atomic_sub(&cfm->ref_cnt, 1, &orig);
-    ovs_assert(orig > 0);
-    if (orig != 1) {
+    if (ovs_refcount_unref(&cfm->ref_cnt) != 1) {
         return;
     }
 
@@ -374,6 +371,11 @@ cfm_unref(struct cfm *cfm) OVS_EXCLUDED(mutex)
     hmap_destroy(&cfm->remote_mps);
     netdev_close(cfm->netdev);
     free(cfm->rmps_array);
+
+    atomic_destroy(&cfm->extended);
+    atomic_destroy(&cfm->check_tnl_key);
+    ovs_refcount_destroy(&cfm->ref_cnt);
+
     free(cfm);
 }
 
@@ -382,9 +384,7 @@ cfm_ref(const struct cfm *cfm_)
 {
     struct cfm *cfm = CONST_CAST(struct cfm *, cfm_);
     if (cfm) {
-        int orig;
-        atomic_add(&cfm->ref_cnt, 1, &orig);
-        ovs_assert(orig > 0);
+        ovs_refcount_ref(&cfm->ref_cnt);
     }
     return cfm;
 }
@@ -554,7 +554,7 @@ cfm_compose_ccm(struct cfm *cfm, struct ofpbuf *packet,
 
     if (ccm_vlan || cfm->ccm_pcp) {
         uint16_t tci = ccm_vlan | (cfm->ccm_pcp << VLAN_PCP_SHIFT);
-        eth_push_vlan(packet, htons(tci));
+        eth_push_vlan(packet, htons(ETH_TYPE_VLAN), htons(tci));
     }
 
     ccm = packet->l3;
index 1675283..30a91b7 100644 (file)
@@ -176,7 +176,7 @@ classifier_init(struct classifier *cls, const uint8_t *flow_segments)
     hmap_init(&cls->subtables);
     list_init(&cls->subtables_priority);
     hmap_init(&cls->partitions);
-    ovs_rwlock_init(&cls->rwlock);
+    fat_rwlock_init(&cls->rwlock);
     cls->n_flow_segments = 0;
     if (flow_segments) {
         while (cls->n_flow_segments < CLS_MAX_INDICES
@@ -213,7 +213,7 @@ classifier_destroy(struct classifier *cls)
             free(partition);
         }
         hmap_destroy(&cls->partitions);
-        ovs_rwlock_destroy(&cls->rwlock);
+        fat_rwlock_destroy(&cls->rwlock);
     }
 }
 
index b6b89a0..c3c1c3b 100644 (file)
  * The classifier may safely be accessed by many reader threads concurrently or
  * by a single writer. */
 
+#include "fat-rwlock.h"
 #include "flow.h"
 #include "hindex.h"
 #include "hmap.h"
@@ -254,7 +255,7 @@ struct classifier {
     struct list subtables_priority; /* Subtables in descending priority order.
                                      */
     struct hmap partitions;     /* Contains "struct cls_partition"s. */
-    struct ovs_rwlock rwlock OVS_ACQ_AFTER(ofproto_mutex);
+    struct fat_rwlock rwlock OVS_ACQ_AFTER(ofproto_mutex);
     struct cls_trie tries[CLS_MAX_TRIES]; /* Prefix tries. */
     unsigned int n_tries;
 };
index 3587bbd..497a5bd 100644 (file)
@@ -673,12 +673,6 @@ dpif_linux_port_query_by_name(const struct dpif *dpif, const char *devname,
     return dpif_linux_port_query__(dpif, 0, devname, dpif_port);
 }
 
-static uint32_t
-dpif_linux_get_max_ports(const struct dpif *dpif OVS_UNUSED)
-{
-    return MAX_PORTS;
-}
-
 static uint32_t
 dpif_linux_port_get_pid(const struct dpif *dpif_, odp_port_t port_no)
 {
@@ -1620,7 +1614,6 @@ const struct dpif_class dpif_linux_class = {
     dpif_linux_port_del,
     dpif_linux_port_query_by_number,
     dpif_linux_port_query_by_name,
-    dpif_linux_get_max_ports,
     dpif_linux_port_get_pid,
     dpif_linux_port_dump_start,
     dpif_linux_port_dump_next,
index 0de6027..d62949b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -39,6 +39,7 @@
 #include "dynamic-string.h"
 #include "flow.h"
 #include "hmap.h"
+#include "latch.h"
 #include "list.h"
 #include "meta-flow.h"
 #include "netdev.h"
@@ -65,7 +66,6 @@ VLOG_DEFINE_THIS_MODULE(dpif_netdev);
 #define NETDEV_RULE_PRIORITY 0x8000
 
 /* Configuration parameters. */
-enum { MAX_PORTS = 256 };       /* Maximum number of ports. */
 enum { MAX_FLOWS = 65536 };     /* Maximum number of flows in flow table. */
 
 /* Enough headroom to add a vlan tag, plus an extra 2 bytes to allow IP
@@ -78,68 +78,222 @@ enum { MAX_QUEUE_LEN = 128 };   /* Maximum number of packets per queue. */
 enum { QUEUE_MASK = MAX_QUEUE_LEN - 1 };
 BUILD_ASSERT_DECL(IS_POW2(MAX_QUEUE_LEN));
 
+/* Protects against changes to 'dp_netdevs'. */
+static struct ovs_mutex dp_netdev_mutex = OVS_MUTEX_INITIALIZER;
+
+/* Contains all 'struct dp_netdev's. */
+static struct shash dp_netdevs OVS_GUARDED_BY(dp_netdev_mutex)
+    = SHASH_INITIALIZER(&dp_netdevs);
+
 struct dp_netdev_upcall {
     struct dpif_upcall upcall;  /* Queued upcall information. */
     struct ofpbuf buf;          /* ofpbuf instance for upcall.packet. */
 };
 
+/* A queue passing packets from a struct dp_netdev to its clients.
+ *
+ *
+ * Thread-safety
+ * =============
+ *
+ * Any access at all requires the owning 'dp_netdev''s queue_mutex. */
 struct dp_netdev_queue {
-    struct dp_netdev_upcall upcalls[MAX_QUEUE_LEN];
-    unsigned int head, tail;
+    struct dp_netdev_upcall upcalls[MAX_QUEUE_LEN] OVS_GUARDED;
+    unsigned int head OVS_GUARDED;
+    unsigned int tail OVS_GUARDED;
 };
 
-/* Datapath based on the network device interface from netdev.h. */
+/* Datapath based on the network device interface from netdev.h.
+ *
+ *
+ * Thread-safety
+ * =============
+ *
+ * Some members, marked 'const', are immutable.  Accessing other members
+ * requires synchronization, as noted in more detail below.
+ *
+ * Acquisition order is, from outermost to innermost:
+ *
+ *    dp_netdev_mutex (global)
+ *    port_rwlock
+ *    flow_mutex
+ *    cls.rwlock
+ *    queue_mutex
+ */
 struct dp_netdev {
-    const struct dpif_class *class;
-    char *name;
-    int open_cnt;
-    bool destroyed;
-    int max_mtu;                /* Maximum MTU of any port added so far. */
+    const struct dpif_class *const class;
+    const char *const name;
+    struct ovs_refcount ref_cnt;
+    atomic_flag destroyed;
 
+    /* Flows.
+     *
+     * Readers of 'cls' and 'flow_table' must take a 'cls->rwlock' read lock.
+     *
+     * Writers of 'cls' and 'flow_table' must take the 'flow_mutex' and then
+     * the 'cls->rwlock' write lock.  (The outer 'flow_mutex' allows writers to
+     * atomically perform multiple operations on 'cls' and 'flow_table'.)
+     */
+    struct ovs_mutex flow_mutex;
+    struct classifier cls;      /* Classifier.  Protected by cls.rwlock. */
+    struct hmap flow_table OVS_GUARDED; /* Flow table. */
+
+    /* Queues.
+     *
+     * Everything in 'queues' is protected by 'queue_mutex'. */
+    struct ovs_mutex queue_mutex;
     struct dp_netdev_queue queues[N_QUEUES];
-    struct classifier cls;      /* Classifier. */
-    struct hmap flow_table;     /* Flow table. */
     struct seq *queue_seq;      /* Incremented whenever a packet is queued. */
 
-    /* Statistics. */
-    long long int n_hit;        /* Number of flow table matches. */
-    long long int n_missed;     /* Number of flow table misses. */
-    long long int n_lost;       /* Number of misses not passed to client. */
+    /* Statistics.
+     *
+     * ovsthread_counter is internally synchronized. */
+    struct ovsthread_counter *n_hit;    /* Number of flow table matches. */
+    struct ovsthread_counter *n_missed; /* Number of flow table misses. */
+    struct ovsthread_counter *n_lost;   /* Number of misses not passed up. */
 
-    /* Ports. */
-    struct dp_netdev_port *ports[MAX_PORTS];
-    struct list port_list;
+    /* Ports.
+     *
+     * Any lookup into 'ports' or any access to the dp_netdev_ports found
+     * through 'ports' requires taking 'port_rwlock'. */
+    struct ovs_rwlock port_rwlock;
+    struct hmap ports OVS_GUARDED;
     struct seq *port_seq;       /* Incremented whenever a port changes. */
+
+    /* Forwarding threads. */
+    struct latch exit_latch;
+    struct dp_forwarder *forwarders;
+    size_t n_forwarders;
 };
 
+static struct dp_netdev_port *dp_netdev_lookup_port(const struct dp_netdev *dp,
+                                                    odp_port_t)
+    OVS_REQ_RDLOCK(dp->port_rwlock);
+
 /* A port in a netdev-based datapath. */
 struct dp_netdev_port {
-    odp_port_t port_no;         /* Index into dp_netdev's 'ports'. */
-    struct list node;           /* Element in dp_netdev's 'port_list'. */
+    struct hmap_node node;      /* Node in dp_netdev's 'ports'. */
+    odp_port_t port_no;
     struct netdev *netdev;
     struct netdev_saved_flags *sf;
     struct netdev_rx *rx;
     char *type;                 /* Port type as requested by user. */
 };
 
-/* A flow in dp_netdev's 'flow_table'. */
+/* A flow in dp_netdev's 'flow_table'.
+ *
+ *
+ * Thread-safety
+ * =============
+ *
+ * Except near the beginning or ending of its lifespan, rule 'rule' belongs to
+ * its dp_netdev's classifier.  The text below calls this classifier 'cls'.
+ *
+ * Motivation
+ * ----------
+ *
+ * The thread safety rules described here for "struct dp_netdev_flow" are
+ * motivated by two goals:
+ *
+ *    - Prevent threads that read members of "struct dp_netdev_flow" from
+ *      reading bad data due to changes by some thread concurrently modifying
+ *      those members.
+ *
+ *    - Prevent two threads making changes to members of a given "struct
+ *      dp_netdev_flow" from interfering with each other.
+ *
+ *
+ * Rules
+ * -----
+ *
+ * A flow 'flow' may be accessed without a risk of being freed by code that
+ * holds a read-lock or write-lock on 'cls->rwlock' or that owns a reference to
+ * 'flow->ref_cnt' (or both).  Code that needs to hold onto a flow for a while
+ * should take 'cls->rwlock', find the flow it needs, increment 'flow->ref_cnt'
+ * with dpif_netdev_flow_ref(), and drop 'cls->rwlock'.
+ *
+ * 'flow->ref_cnt' protects 'flow' from being freed.  It doesn't protect the
+ * flow from being deleted from 'cls' (that's 'cls->rwlock') and it doesn't
+ * protect members of 'flow' from modification (that's 'flow->mutex').
+ *
+ * 'flow->mutex' protects the members of 'flow' from modification.  It doesn't
+ * protect the flow from being deleted from 'cls' (that's 'cls->rwlock') and it
+ * doesn't prevent the flow from being freed (that's 'flow->ref_cnt').
+ *
+ * Some members, marked 'const', are immutable.  Accessing other members
+ * requires synchronization, as noted in more detail below.
+ */
 struct dp_netdev_flow {
     /* Packet classification. */
-    struct cls_rule cr;         /* In owning dp_netdev's 'cls'. */
+    const struct cls_rule cr;   /* In owning dp_netdev's 'cls'. */
+
+    /* Hash table index by unmasked flow. */
+    const struct hmap_node node; /* In owning dp_netdev's 'flow_table'. */
+    const struct flow flow;      /* The flow that created this entry. */
 
-    /* Hash table index by unmasked flow.*/
-    struct hmap_node node;      /* In owning dp_netdev's 'flow_table'. */
-    struct flow flow;           /* The flow that created this entry. */
+    /* Number of references.
+     * The classifier owns one reference.
+     * Any thread trying to keep a rule from being freed should hold its own
+     * reference. */
+    struct ovs_refcount ref_cnt;
 
-    /* Statistics. */
-    long long int used;         /* Last used time, in monotonic msecs. */
-    long long int packet_count; /* Number of packets matched. */
-    long long int byte_count;   /* Number of bytes matched. */
-    uint16_t tcp_flags;         /* Bitwise-OR of seen tcp_flags values. */
+    /* Protects members marked OVS_GUARDED.
+     *
+     * Acquire after datapath's flow_mutex. */
+    struct ovs_mutex mutex OVS_ACQ_AFTER(dp_netdev_mutex);
 
-    /* Actions. */
-    struct nlattr *actions;
-    size_t actions_len;
+    /* Statistics.
+     *
+     * Reading or writing these members requires 'mutex'. */
+    long long int used OVS_GUARDED; /* Last used time, in monotonic msecs. */
+    long long int packet_count OVS_GUARDED; /* Number of packets matched. */
+    long long int byte_count OVS_GUARDED;   /* Number of bytes matched. */
+    uint16_t tcp_flags OVS_GUARDED; /* Bitwise-OR of seen tcp_flags values. */
+
+    /* Actions.
+     *
+     * Reading 'actions' requires 'mutex'.
+     * Writing 'actions' requires 'mutex' and (to allow for transactions) the
+     * datapath's flow_mutex. */
+    struct dp_netdev_actions *actions OVS_GUARDED;
+};
+
+static struct dp_netdev_flow *dp_netdev_flow_ref(
+    const struct dp_netdev_flow *);
+static void dp_netdev_flow_unref(struct dp_netdev_flow *);
+
+/* A set of datapath actions within a "struct dp_netdev_flow".
+ *
+ *
+ * Thread-safety
+ * =============
+ *
+ * A struct dp_netdev_actions 'actions' may be accessed without a risk of being
+ * freed by code that holds a read-lock or write-lock on 'flow->mutex' (where
+ * 'flow' is the dp_netdev_flow for which 'flow->actions == actions') or that
+ * owns a reference to 'actions->ref_cnt' (or both). */
+struct dp_netdev_actions {
+    struct ovs_refcount ref_cnt;
+
+    /* These members are immutable: they do not change during the struct's
+     * lifetime.  */
+    struct nlattr *actions;     /* Sequence of OVS_ACTION_ATTR_* attributes. */
+    unsigned int size;          /* Size of 'actions', in bytes. */
+};
+
+struct dp_netdev_actions *dp_netdev_actions_create(const struct nlattr *,
+                                                   size_t);
+struct dp_netdev_actions *dp_netdev_actions_ref(
+    const struct dp_netdev_actions *);
+void dp_netdev_actions_unref(struct dp_netdev_actions *);
+
+/* A thread that receives packets from some ports, looks them up in the flow
+ * table, and executes the actions it finds. */
+struct dp_forwarder {
+    struct dp_netdev *dp;
+    pthread_t thread;
+    char *name;
+    uint32_t min_hash, max_hash;
 };
 
 /* Interface to netdev-based datapath. */
@@ -149,32 +303,36 @@ struct dpif_netdev {
     uint64_t last_port_seq;
 };
 
-/* All netdev-based datapaths. */
-static struct shash dp_netdevs = SHASH_INITIALIZER(&dp_netdevs);
-
-/* Global lock for all data. */
-static struct ovs_mutex dp_netdev_mutex = OVS_MUTEX_INITIALIZER;
-
-static int get_port_by_number(struct dp_netdev *, odp_port_t port_no,
-                              struct dp_netdev_port **portp);
-static int get_port_by_name(struct dp_netdev *, const char *devname,
-                            struct dp_netdev_port **portp);
-static void dp_netdev_free(struct dp_netdev *);
+static int get_port_by_number(struct dp_netdev *dp, odp_port_t port_no,
+                              struct dp_netdev_port **portp)
+    OVS_REQ_RDLOCK(dp->port_rwlock);
+static int get_port_by_name(struct dp_netdev *dp, const char *devname,
+                            struct dp_netdev_port **portp)
+    OVS_REQ_RDLOCK(dp->port_rwlock);
+static void dp_netdev_free(struct dp_netdev *)
+    OVS_REQUIRES(dp_netdev_mutex);
 static void dp_netdev_flow_flush(struct dp_netdev *);
-static int do_add_port(struct dp_netdev *, const char *devname,
-                       const char *type, odp_port_t port_no);
-static int do_del_port(struct dp_netdev *, odp_port_t port_no);
+static int do_add_port(struct dp_netdev *dp, const char *devname,
+                       const char *type, odp_port_t port_no)
+    OVS_REQ_WRLOCK(dp->port_rwlock);
+static int do_del_port(struct dp_netdev *dp, odp_port_t port_no)
+    OVS_REQ_WRLOCK(dp->port_rwlock);
 static int dpif_netdev_open(const struct dpif_class *, const char *name,
                             bool create, struct dpif **);
-static int dp_netdev_output_userspace(struct dp_netdev *, struct ofpbuf *,
+static int dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *,
                                     int queue_no, const struct flow *,
-                                    const struct nlattr *userdata);
-static void dp_netdev_execute_actions(struct dp_netdev *, const struct flow *,
-                                      struct ofpbuf *, struct pkt_metadata *,
+                                    const struct nlattr *userdata)
+    OVS_EXCLUDED(dp->queue_mutex);
+static void dp_netdev_execute_actions(struct dp_netdev *dp,
+                                      const struct flow *, struct ofpbuf *,
+                                      struct pkt_metadata *,
                                       const struct nlattr *actions,
-                                      size_t actions_len);
+                                      size_t actions_len)
+    OVS_REQ_RDLOCK(dp->port_rwlock);
 static void dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet,
-                                 struct pkt_metadata *md);
+                                 struct pkt_metadata *)
+    OVS_REQ_RDLOCK(dp->port_rwlock);
+static void dp_netdev_set_threads(struct dp_netdev *, int n);
 
 static struct dpif_netdev *
 dpif_netdev_cast(const struct dpif *dpif)
@@ -230,7 +388,7 @@ create_dpif_netdev(struct dp_netdev *dp)
     uint16_t netflow_id = hash_string(dp->name, 0);
     struct dpif_netdev *dpif;
 
-    dp->open_cnt++;
+    ovs_refcount_ref(&dp->ref_cnt);
 
     dpif = xmalloc(sizeof *dpif);
     dpif_init(&dpif->dpif, dp->class, dp->name, netflow_id >> 8, netflow_id);
@@ -244,6 +402,7 @@ create_dpif_netdev(struct dp_netdev *dp)
  * Return ODPP_NONE on failure. */
 static odp_port_t
 choose_port(struct dp_netdev *dp, const char *name)
+    OVS_REQ_RDLOCK(dp->port_rwlock)
 {
     uint32_t port_no;
 
@@ -264,8 +423,8 @@ choose_port(struct dp_netdev *dp, const char *name)
         for (p = name; *p != '\0'; p++) {
             if (isdigit((unsigned char) *p)) {
                 port_no = start_no + strtol(p, NULL, 10);
-                if (port_no > 0 && port_no < MAX_PORTS
-                    && !dp->ports[port_no]) {
+                if (port_no > 0 && port_no != odp_to_u32(ODPP_NONE)
+                    && !dp_netdev_lookup_port(dp, u32_to_odp(port_no))) {
                     return u32_to_odp(port_no);
                 }
                 break;
@@ -273,8 +432,8 @@ choose_port(struct dp_netdev *dp, const char *name)
         }
     }
 
-    for (port_no = 1; port_no < MAX_PORTS; port_no++) {
-        if (!dp->ports[port_no]) {
+    for (port_no = 1; port_no <= UINT16_MAX; port_no++) {
+        if (!dp_netdev_lookup_port(dp, u32_to_odp(port_no))) {
             return u32_to_odp(port_no);
         }
     }
@@ -285,32 +444,49 @@ choose_port(struct dp_netdev *dp, const char *name)
 static int
 create_dp_netdev(const char *name, const struct dpif_class *class,
                  struct dp_netdev **dpp)
+    OVS_REQUIRES(dp_netdev_mutex)
 {
     struct dp_netdev *dp;
     int error;
     int i;
 
     dp = xzalloc(sizeof *dp);
-    dp->class = class;
-    dp->name = xstrdup(name);
-    dp->open_cnt = 0;
-    dp->max_mtu = ETH_PAYLOAD_MAX;
+    shash_add(&dp_netdevs, name, dp);
+
+    *CONST_CAST(const struct dpif_class **, &dp->class) = class;
+    *CONST_CAST(const char **, &dp->name) = xstrdup(name);
+    ovs_refcount_init(&dp->ref_cnt);
+    atomic_flag_init(&dp->destroyed);
+
+    ovs_mutex_init(&dp->flow_mutex);
+    classifier_init(&dp->cls, NULL);
+    hmap_init(&dp->flow_table);
+
+    ovs_mutex_init(&dp->queue_mutex);
+    ovs_mutex_lock(&dp->queue_mutex);
     for (i = 0; i < N_QUEUES; i++) {
         dp->queues[i].head = dp->queues[i].tail = 0;
     }
+    ovs_mutex_unlock(&dp->queue_mutex);
     dp->queue_seq = seq_create();
-    classifier_init(&dp->cls, NULL);
-    hmap_init(&dp->flow_table);
-    list_init(&dp->port_list);
+
+    dp->n_hit = ovsthread_counter_create();
+    dp->n_missed = ovsthread_counter_create();
+    dp->n_lost = ovsthread_counter_create();
+
+    ovs_rwlock_init(&dp->port_rwlock);
+    hmap_init(&dp->ports);
     dp->port_seq = seq_create();
+    latch_init(&dp->exit_latch);
 
+    ovs_rwlock_wrlock(&dp->port_rwlock);
     error = do_add_port(dp, name, "internal", ODPP_LOCAL);
+    ovs_rwlock_unlock(&dp->port_rwlock);
     if (error) {
         dp_netdev_free(dp);
         return error;
     }
-
-    shash_add(&dp_netdevs, name, dp);
+    dp_netdev_set_threads(dp, 2);
 
     *dpp = dp;
     return 0;
@@ -345,6 +521,7 @@ dp_netdev_purge_queues(struct dp_netdev *dp)
 {
     int i;
 
+    ovs_mutex_lock(&dp->queue_mutex);
     for (i = 0; i < N_QUEUES; i++) {
         struct dp_netdev_queue *q = &dp->queues[i];
 
@@ -354,41 +531,69 @@ dp_netdev_purge_queues(struct dp_netdev *dp)
             ofpbuf_uninit(&u->buf);
         }
     }
+    ovs_mutex_unlock(&dp->queue_mutex);
 }
 
+/* Requires dp_netdev_mutex so that we can't get a new reference to 'dp'
+ * through the 'dp_netdevs' shash while freeing 'dp'. */
 static void
 dp_netdev_free(struct dp_netdev *dp)
+    OVS_REQUIRES(dp_netdev_mutex)
 {
     struct dp_netdev_port *port, *next;
 
+    shash_find_and_delete(&dp_netdevs, dp->name);
+
+    dp_netdev_set_threads(dp, 0);
+    free(dp->forwarders);
+
     dp_netdev_flow_flush(dp);
-    LIST_FOR_EACH_SAFE (port, next, node, &dp->port_list) {
+    ovs_rwlock_wrlock(&dp->port_rwlock);
+    HMAP_FOR_EACH_SAFE (port, next, node, &dp->ports) {
         do_del_port(dp, port->port_no);
     }
+    ovs_rwlock_unlock(&dp->port_rwlock);
+    ovsthread_counter_destroy(dp->n_hit);
+    ovsthread_counter_destroy(dp->n_missed);
+    ovsthread_counter_destroy(dp->n_lost);
+
     dp_netdev_purge_queues(dp);
     seq_destroy(dp->queue_seq);
+    ovs_mutex_destroy(&dp->queue_mutex);
+
     classifier_destroy(&dp->cls);
     hmap_destroy(&dp->flow_table);
+    ovs_mutex_destroy(&dp->flow_mutex);
     seq_destroy(dp->port_seq);
-    free(dp->name);
+    hmap_destroy(&dp->ports);
+    atomic_flag_destroy(&dp->destroyed);
+    ovs_refcount_destroy(&dp->ref_cnt);
+    latch_destroy(&dp->exit_latch);
+    free(CONST_CAST(char *, dp->name));
     free(dp);
 }
 
+static void
+dp_netdev_unref(struct dp_netdev *dp)
+{
+    if (dp) {
+        /* Take dp_netdev_mutex so that, if dp->ref_cnt falls to zero, we can't
+         * get a new reference to 'dp' through the 'dp_netdevs' shash. */
+        ovs_mutex_lock(&dp_netdev_mutex);
+        if (ovs_refcount_unref(&dp->ref_cnt) == 1) {
+            dp_netdev_free(dp);
+        }
+        ovs_mutex_unlock(&dp_netdev_mutex);
+    }
+}
+
 static void
 dpif_netdev_close(struct dpif *dpif)
 {
     struct dp_netdev *dp = get_dp_netdev(dpif);
 
-    ovs_mutex_lock(&dp_netdev_mutex);
-
-    ovs_assert(dp->open_cnt > 0);
-    if (--dp->open_cnt == 0 && dp->destroyed) {
-        shash_find_and_delete(&dp_netdevs, dp->name);
-        dp_netdev_free(dp);
-    }
+    dp_netdev_unref(dp);
     free(dpif);
-
-    ovs_mutex_unlock(&dp_netdev_mutex);
 }
 
 static int
@@ -396,9 +601,12 @@ dpif_netdev_destroy(struct dpif *dpif)
 {
     struct dp_netdev *dp = get_dp_netdev(dpif);
 
-    ovs_mutex_lock(&dp_netdev_mutex);
-    dp->destroyed = true;
-    ovs_mutex_unlock(&dp_netdev_mutex);
+    if (!atomic_flag_test_and_set(&dp->destroyed)) {
+        if (ovs_refcount_unref(&dp->ref_cnt) == 1) {
+            /* Can't happen: 'dpif' still owns a reference to 'dp'. */
+            OVS_NOT_REACHED();
+        }
+    }
 
     return 0;
 }
@@ -408,14 +616,15 @@ dpif_netdev_get_stats(const struct dpif *dpif, struct dpif_dp_stats *stats)
 {
     struct dp_netdev *dp = get_dp_netdev(dpif);
 
-    ovs_mutex_lock(&dp_netdev_mutex);
+    fat_rwlock_rdlock(&dp->cls.rwlock);
     stats->n_flows = hmap_count(&dp->flow_table);
-    stats->n_hit = dp->n_hit;
-    stats->n_missed = dp->n_missed;
-    stats->n_lost = dp->n_lost;
+    fat_rwlock_unlock(&dp->cls.rwlock);
+
+    stats->n_hit = ovsthread_counter_read(dp->n_hit);
+    stats->n_missed = ovsthread_counter_read(dp->n_missed);
+    stats->n_lost = ovsthread_counter_read(dp->n_lost);
     stats->n_masks = UINT32_MAX;
     stats->n_mask_hit = UINT64_MAX;
-    ovs_mutex_unlock(&dp_netdev_mutex);
 
     return 0;
 }
@@ -423,6 +632,7 @@ dpif_netdev_get_stats(const struct dpif *dpif, struct dpif_dp_stats *stats)
 static int
 do_add_port(struct dp_netdev *dp, const char *devname, const char *type,
             odp_port_t port_no)
+    OVS_REQ_WRLOCK(dp->port_rwlock)
 {
     struct netdev_saved_flags *sf;
     struct dp_netdev_port *port;
@@ -430,7 +640,6 @@ do_add_port(struct dp_netdev *dp, const char *devname, const char *type,
     struct netdev_rx *rx;
     enum netdev_flags flags;
     const char *open_type;
-    int mtu;
     int error;
 
     /* XXX reject devices already in some dp_netdev. */
@@ -473,13 +682,7 @@ do_add_port(struct dp_netdev *dp, const char *devname, const char *type,
     port->rx = rx;
     port->type = xstrdup(type);
 
-    error = netdev_get_mtu(netdev, &mtu);
-    if (!error && mtu > dp->max_mtu) {
-        dp->max_mtu = mtu;
-    }
-
-    list_push_back(&dp->port_list, &port->node);
-    dp->ports[odp_to_u32(port_no)] = port;
+    hmap_insert(&dp->ports, &port->node, hash_int(odp_to_u32(port_no), 0));
     seq_change(dp->port_seq);
 
     return 0;
@@ -495,18 +698,11 @@ dpif_netdev_port_add(struct dpif *dpif, struct netdev *netdev,
     odp_port_t port_no;
     int error;
 
-    ovs_mutex_lock(&dp_netdev_mutex);
+    ovs_rwlock_wrlock(&dp->port_rwlock);
     dpif_port = netdev_vport_get_dpif_port(netdev, namebuf, sizeof namebuf);
     if (*port_nop != ODPP_NONE) {
-        uint32_t port_idx = odp_to_u32(*port_nop);
-        if (port_idx >= MAX_PORTS) {
-            error = EFBIG;
-        } else if (dp->ports[port_idx]) {
-            error = EBUSY;
-        } else {
-            error = 0;
-            port_no = *port_nop;
-        }
+        port_no = *port_nop;
+        error = dp_netdev_lookup_port(dp, *port_nop) ? EBUSY : 0;
     } else {
         port_no = choose_port(dp, dpif_port);
         error = port_no == ODPP_NONE ? EFBIG : 0;
@@ -515,7 +711,7 @@ dpif_netdev_port_add(struct dpif *dpif, struct netdev *netdev,
         *port_nop = port_no;
         error = do_add_port(dp, dpif_port, netdev_get_type(netdev), port_no);
     }
-    ovs_mutex_unlock(&dp_netdev_mutex);
+    ovs_rwlock_unlock(&dp->port_rwlock);
 
     return error;
 }
@@ -526,9 +722,9 @@ dpif_netdev_port_del(struct dpif *dpif, odp_port_t port_no)
     struct dp_netdev *dp = get_dp_netdev(dpif);
     int error;
 
-    ovs_mutex_lock(&dp_netdev_mutex);
+    ovs_rwlock_wrlock(&dp->port_rwlock);
     error = port_no == ODPP_LOCAL ? EINVAL : do_del_port(dp, port_no);
-    ovs_mutex_unlock(&dp_netdev_mutex);
+    ovs_rwlock_unlock(&dp->port_rwlock);
 
     return error;
 }
@@ -536,18 +732,34 @@ dpif_netdev_port_del(struct dpif *dpif, odp_port_t port_no)
 static bool
 is_valid_port_number(odp_port_t port_no)
 {
-    return odp_to_u32(port_no) < MAX_PORTS;
+    return port_no != ODPP_NONE;
+}
+
+static struct dp_netdev_port *
+dp_netdev_lookup_port(const struct dp_netdev *dp, odp_port_t port_no)
+    OVS_REQ_RDLOCK(dp->port_rwlock)
+{
+    struct dp_netdev_port *port;
+
+    HMAP_FOR_EACH_IN_BUCKET (port, node, hash_int(odp_to_u32(port_no), 0),
+                             &dp->ports) {
+        if (port->port_no == port_no) {
+            return port;
+        }
+    }
+    return NULL;
 }
 
 static int
 get_port_by_number(struct dp_netdev *dp,
                    odp_port_t port_no, struct dp_netdev_port **portp)
+    OVS_REQ_RDLOCK(dp->port_rwlock)
 {
     if (!is_valid_port_number(port_no)) {
         *portp = NULL;
         return EINVAL;
     } else {
-        *portp = dp->ports[odp_to_u32(port_no)];
+        *portp = dp_netdev_lookup_port(dp, port_no);
         return *portp ? 0 : ENOENT;
     }
 }
@@ -555,10 +767,11 @@ get_port_by_number(struct dp_netdev *dp,
 static int
 get_port_by_name(struct dp_netdev *dp,
                  const char *devname, struct dp_netdev_port **portp)
+    OVS_REQ_RDLOCK(dp->port_rwlock)
 {
     struct dp_netdev_port *port;
 
-    LIST_FOR_EACH (port, node, &dp->port_list) {
+    HMAP_FOR_EACH (port, node, &dp->ports) {
         if (!strcmp(netdev_get_name(port->netdev), devname)) {
             *portp = port;
             return 0;
@@ -569,6 +782,7 @@ get_port_by_name(struct dp_netdev *dp,
 
 static int
 do_del_port(struct dp_netdev *dp, odp_port_t port_no)
+    OVS_REQ_WRLOCK(dp->port_rwlock)
 {
     struct dp_netdev_port *port;
     int error;
@@ -578,8 +792,7 @@ do_del_port(struct dp_netdev *dp, odp_port_t port_no)
         return error;
     }
 
-    list_remove(&port->node);
-    dp->ports[odp_to_u32(port_no)] = NULL;
+    hmap_remove(&dp->ports, &port->node);
     seq_change(dp->port_seq);
 
     netdev_close(port->netdev);
@@ -608,12 +821,12 @@ dpif_netdev_port_query_by_number(const struct dpif *dpif, odp_port_t port_no,
     struct dp_netdev_port *port;
     int error;
 
-    ovs_mutex_lock(&dp_netdev_mutex);
+    ovs_rwlock_rdlock(&dp->port_rwlock);
     error = get_port_by_number(dp, port_no, &port);
     if (!error && dpif_port) {
         answer_port_query(port, dpif_port);
     }
-    ovs_mutex_unlock(&dp_netdev_mutex);
+    ovs_rwlock_unlock(&dp->port_rwlock);
 
     return error;
 }
@@ -626,33 +839,50 @@ dpif_netdev_port_query_by_name(const struct dpif *dpif, const char *devname,
     struct dp_netdev_port *port;
     int error;
 
-    ovs_mutex_lock(&dp_netdev_mutex);
+    ovs_rwlock_rdlock(&dp->port_rwlock);
     error = get_port_by_name(dp, devname, &port);
     if (!error && dpif_port) {
         answer_port_query(port, dpif_port);
     }
-    ovs_mutex_unlock(&dp_netdev_mutex);
+    ovs_rwlock_unlock(&dp->port_rwlock);
 
     return error;
 }
 
-static uint32_t
-dpif_netdev_get_max_ports(const struct dpif *dpif OVS_UNUSED)
+static void
+dp_netdev_remove_flow(struct dp_netdev *dp, struct dp_netdev_flow *flow)
+    OVS_REQ_WRLOCK(dp->cls.rwlock)
+    OVS_REQUIRES(dp->flow_mutex)
 {
-    return MAX_PORTS;
+    struct cls_rule *cr = CONST_CAST(struct cls_rule *, &flow->cr);
+    struct hmap_node *node = CONST_CAST(struct hmap_node *, &flow->node);
+
+    classifier_remove(&dp->cls, cr);
+    hmap_remove(&dp->flow_table, node);
+    dp_netdev_flow_unref(flow);
 }
 
-static void
-dp_netdev_free_flow(struct dp_netdev *dp, struct dp_netdev_flow *netdev_flow)
+static struct dp_netdev_flow *
+dp_netdev_flow_ref(const struct dp_netdev_flow *flow_)
 {
-    ovs_rwlock_wrlock(&dp->cls.rwlock);
-    classifier_remove(&dp->cls, &netdev_flow->cr);
-    ovs_rwlock_unlock(&dp->cls.rwlock);
-    cls_rule_destroy(&netdev_flow->cr);
+    struct dp_netdev_flow *flow = CONST_CAST(struct dp_netdev_flow *, flow_);
+    if (flow) {
+        ovs_refcount_ref(&flow->ref_cnt);
+    }
+    return flow;
+}
 
-    hmap_remove(&dp->flow_table, &netdev_flow->node);
-    free(netdev_flow->actions);
-    free(netdev_flow);
+static void
+dp_netdev_flow_unref(struct dp_netdev_flow *flow)
+{
+    if (flow && ovs_refcount_unref(&flow->ref_cnt) == 1) {
+        cls_rule_destroy(CONST_CAST(struct cls_rule *, &flow->cr));
+        ovs_mutex_lock(&flow->mutex);
+        dp_netdev_actions_unref(flow->actions);
+        ovs_mutex_unlock(&flow->mutex);
+        ovs_mutex_destroy(&flow->mutex);
+        free(flow);
+    }
 }
 
 static void
@@ -660,9 +890,13 @@ dp_netdev_flow_flush(struct dp_netdev *dp)
 {
     struct dp_netdev_flow *netdev_flow, *next;
 
+    ovs_mutex_lock(&dp->flow_mutex);
+    fat_rwlock_wrlock(&dp->cls.rwlock);
     HMAP_FOR_EACH_SAFE (netdev_flow, next, node, &dp->flow_table) {
-        dp_netdev_free_flow(dp, netdev_flow);
+        dp_netdev_remove_flow(dp, netdev_flow);
     }
+    fat_rwlock_unlock(&dp->cls.rwlock);
+    ovs_mutex_unlock(&dp->flow_mutex);
 }
 
 static int
@@ -670,15 +904,13 @@ dpif_netdev_flow_flush(struct dpif *dpif)
 {
     struct dp_netdev *dp = get_dp_netdev(dpif);
 
-    ovs_mutex_lock(&dp_netdev_mutex);
     dp_netdev_flow_flush(dp);
-    ovs_mutex_unlock(&dp_netdev_mutex);
-
     return 0;
 }
 
 struct dp_netdev_port_state {
-    odp_port_t port_no;
+    uint32_t bucket;
+    uint32_t offset;
     char *name;
 };
 
@@ -695,27 +927,29 @@ dpif_netdev_port_dump_next(const struct dpif *dpif, void *state_,
 {
     struct dp_netdev_port_state *state = state_;
     struct dp_netdev *dp = get_dp_netdev(dpif);
-    uint32_t port_idx;
+    struct hmap_node *node;
+    int retval;
 
-    ovs_mutex_lock(&dp_netdev_mutex);
-    for (port_idx = odp_to_u32(state->port_no);
-         port_idx < MAX_PORTS; port_idx++) {
-        struct dp_netdev_port *port = dp->ports[port_idx];
-        if (port) {
-            free(state->name);
-            state->name = xstrdup(netdev_get_name(port->netdev));
-            dpif_port->name = state->name;
-            dpif_port->type = port->type;
-            dpif_port->port_no = port->port_no;
-            state->port_no = u32_to_odp(port_idx + 1);
-            ovs_mutex_unlock(&dp_netdev_mutex);
+    ovs_rwlock_rdlock(&dp->port_rwlock);
+    node = hmap_at_position(&dp->ports, &state->bucket, &state->offset);
+    if (node) {
+        struct dp_netdev_port *port;
 
-            return 0;
-        }
+        port = CONTAINER_OF(node, struct dp_netdev_port, node);
+
+        free(state->name);
+        state->name = xstrdup(netdev_get_name(port->netdev));
+        dpif_port->name = state->name;
+        dpif_port->type = port->type;
+        dpif_port->port_no = port->port_no;
+
+        retval = 0;
+    } else {
+        retval = EOF;
     }
-    ovs_mutex_unlock(&dp_netdev_mutex);
+    ovs_rwlock_unlock(&dp->port_rwlock);
 
-    return EOF;
+    return retval;
 }
 
 static int
@@ -734,7 +968,6 @@ dpif_netdev_port_poll(const struct dpif *dpif_, char **devnamep OVS_UNUSED)
     uint64_t new_port_seq;
     int error;
 
-    ovs_mutex_lock(&dp_netdev_mutex);
     new_port_seq = seq_read(dpif->dp->port_seq);
     if (dpif->last_port_seq != new_port_seq) {
         dpif->last_port_seq = new_port_seq;
@@ -742,7 +975,6 @@ dpif_netdev_port_poll(const struct dpif *dpif_, char **devnamep OVS_UNUSED)
     } else {
         error = EAGAIN;
     }
-    ovs_mutex_unlock(&dp_netdev_mutex);
 
     return error;
 }
@@ -752,42 +984,49 @@ dpif_netdev_port_poll_wait(const struct dpif *dpif_)
 {
     struct dpif_netdev *dpif = dpif_netdev_cast(dpif_);
 
-    ovs_mutex_lock(&dp_netdev_mutex);
     seq_wait(dpif->dp->port_seq, dpif->last_port_seq);
-    ovs_mutex_unlock(&dp_netdev_mutex);
+}
+
+static struct dp_netdev_flow *
+dp_netdev_flow_cast(const struct cls_rule *cr)
+{
+    return cr ? CONTAINER_OF(cr, struct dp_netdev_flow, cr) : NULL;
 }
 
 static struct dp_netdev_flow *
 dp_netdev_lookup_flow(const struct dp_netdev *dp, const struct flow *flow)
+    OVS_EXCLUDED(dp->cls.rwlock)
 {
-    struct cls_rule *cr;
+    struct dp_netdev_flow *netdev_flow;
 
-    ovs_rwlock_wrlock(&dp->cls.rwlock);
-    cr = classifier_lookup(&dp->cls, flow, NULL);
-    ovs_rwlock_unlock(&dp->cls.rwlock);
+    fat_rwlock_rdlock(&dp->cls.rwlock);
+    netdev_flow = dp_netdev_flow_cast(classifier_lookup(&dp->cls, flow, NULL));
+    dp_netdev_flow_ref(netdev_flow);
+    fat_rwlock_unlock(&dp->cls.rwlock);
 
-    return (cr
-            ? CONTAINER_OF(cr, struct dp_netdev_flow, cr)
-            : NULL);
+    return netdev_flow;
 }
 
 static struct dp_netdev_flow *
 dp_netdev_find_flow(const struct dp_netdev *dp, const struct flow *flow)
+    OVS_REQ_RDLOCK(dp->cls.rwlock)
 {
     struct dp_netdev_flow *netdev_flow;
 
     HMAP_FOR_EACH_WITH_HASH (netdev_flow, node, flow_hash(flow, 0),
                              &dp->flow_table) {
         if (flow_equal(&netdev_flow->flow, flow)) {
-            return netdev_flow;
+            return dp_netdev_flow_ref(netdev_flow);
         }
     }
+
     return NULL;
 }
 
 static void
 get_dpif_flow_stats(struct dp_netdev_flow *netdev_flow,
                     struct dpif_flow_stats *stats)
+    OVS_REQ_RDLOCK(netdev_flow->mutex)
 {
     stats->n_packets = netdev_flow->packet_count;
     stats->n_bytes = netdev_flow->byte_count;
@@ -892,70 +1131,73 @@ dpif_netdev_flow_get(const struct dpif *dpif,
         return error;
     }
 
-    ovs_mutex_lock(&dp_netdev_mutex);
+    fat_rwlock_rdlock(&dp->cls.rwlock);
     netdev_flow = dp_netdev_find_flow(dp, &key);
+    fat_rwlock_unlock(&dp->cls.rwlock);
+
     if (netdev_flow) {
+        struct dp_netdev_actions *actions = NULL;
+
+        ovs_mutex_lock(&netdev_flow->mutex);
         if (stats) {
             get_dpif_flow_stats(netdev_flow, stats);
         }
         if (actionsp) {
-            *actionsp = ofpbuf_clone_data(netdev_flow->actions,
-                                          netdev_flow->actions_len);
+            actions = dp_netdev_actions_ref(netdev_flow->actions);
+        }
+        ovs_mutex_unlock(&netdev_flow->mutex);
+
+        dp_netdev_flow_unref(netdev_flow);
+
+        if (actionsp) {
+            *actionsp = ofpbuf_clone_data(actions->actions, actions->size);
+            dp_netdev_actions_unref(actions);
         }
     } else {
         error = ENOENT;
     }
-    ovs_mutex_unlock(&dp_netdev_mutex);
 
     return error;
 }
 
-static int
-set_flow_actions(struct dp_netdev_flow *netdev_flow,
-                 const struct nlattr *actions, size_t actions_len)
-{
-    netdev_flow->actions = xrealloc(netdev_flow->actions, actions_len);
-    netdev_flow->actions_len = actions_len;
-    memcpy(netdev_flow->actions, actions, actions_len);
-    return 0;
-}
-
 static int
 dp_netdev_flow_add(struct dp_netdev *dp, const struct flow *flow,
                    const struct flow_wildcards *wc,
                    const struct nlattr *actions,
                    size_t actions_len)
+    OVS_REQUIRES(dp->flow_mutex)
 {
     struct dp_netdev_flow *netdev_flow;
     struct match match;
-    int error;
 
     netdev_flow = xzalloc(sizeof *netdev_flow);
-    netdev_flow->flow = *flow;
+    *CONST_CAST(struct flow *, &netdev_flow->flow) = *flow;
+    ovs_refcount_init(&netdev_flow->ref_cnt);
 
-    match_init(&match, flow, wc);
-    cls_rule_init(&netdev_flow->cr, &match, NETDEV_RULE_PRIORITY);
-    ovs_rwlock_wrlock(&dp->cls.rwlock);
-    classifier_insert(&dp->cls, &netdev_flow->cr);
-    ovs_rwlock_unlock(&dp->cls.rwlock);
+    ovs_mutex_init(&netdev_flow->mutex);
+    ovs_mutex_lock(&netdev_flow->mutex);
 
-    error = set_flow_actions(netdev_flow, actions, actions_len);
-    if (error) {
-        ovs_rwlock_wrlock(&dp->cls.rwlock);
-        classifier_remove(&dp->cls, &netdev_flow->cr);
-        ovs_rwlock_unlock(&dp->cls.rwlock);
-        cls_rule_destroy(&netdev_flow->cr);
+    netdev_flow->actions = dp_netdev_actions_create(actions, actions_len);
 
-        free(netdev_flow);
-        return error;
-    }
+    match_init(&match, flow, wc);
+    cls_rule_init(CONST_CAST(struct cls_rule *, &netdev_flow->cr),
+                  &match, NETDEV_RULE_PRIORITY);
+    fat_rwlock_wrlock(&dp->cls.rwlock);
+    classifier_insert(&dp->cls,
+                      CONST_CAST(struct cls_rule *, &netdev_flow->cr));
+    hmap_insert(&dp->flow_table,
+                CONST_CAST(struct hmap_node *, &netdev_flow->node),
+                flow_hash(flow, 0));
+    fat_rwlock_unlock(&dp->cls.rwlock);
+
+    ovs_mutex_unlock(&netdev_flow->mutex);
 
-    hmap_insert(&dp->flow_table, &netdev_flow->node, flow_hash(flow, 0));
     return 0;
 }
 
 static void
 clear_stats(struct dp_netdev_flow *netdev_flow)
+    OVS_REQUIRES(netdev_flow->mutex)
 {
     netdev_flow->used = 0;
     netdev_flow->packet_count = 0;
@@ -983,7 +1225,7 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put)
         return error;
     }
 
-    ovs_mutex_lock(&dp_netdev_mutex);
+    ovs_mutex_lock(&dp->flow_mutex);
     netdev_flow = dp_netdev_lookup_flow(dp, &flow);
     if (!netdev_flow) {
         if (put->flags & DPIF_FP_CREATE) {
@@ -1002,24 +1244,33 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put)
     } else {
         if (put->flags & DPIF_FP_MODIFY
             && flow_equal(&flow, &netdev_flow->flow)) {
-            error = set_flow_actions(netdev_flow, put->actions,
-                                     put->actions_len);
-            if (!error) {
-                if (put->stats) {
-                    get_dpif_flow_stats(netdev_flow, put->stats);
-                }
-                if (put->flags & DPIF_FP_ZERO_STATS) {
-                    clear_stats(netdev_flow);
-                }
+            struct dp_netdev_actions *new_actions;
+            struct dp_netdev_actions *old_actions;
+
+            new_actions = dp_netdev_actions_create(put->actions,
+                                                   put->actions_len);
+
+            ovs_mutex_lock(&netdev_flow->mutex);
+            old_actions = netdev_flow->actions;
+            netdev_flow->actions = new_actions;
+            if (put->stats) {
+                get_dpif_flow_stats(netdev_flow, put->stats);
+            }
+            if (put->flags & DPIF_FP_ZERO_STATS) {
+                clear_stats(netdev_flow);
             }
+            ovs_mutex_unlock(&netdev_flow->mutex);
+
+            dp_netdev_actions_unref(old_actions);
         } else if (put->flags & DPIF_FP_CREATE) {
             error = EEXIST;
         } else {
             /* Overlapping flow. */
             error = EINVAL;
         }
+        dp_netdev_flow_unref(netdev_flow);
     }
-    ovs_mutex_unlock(&dp_netdev_mutex);
+    ovs_mutex_unlock(&dp->flow_mutex);
 
     return error;
 }
@@ -1037,17 +1288,21 @@ dpif_netdev_flow_del(struct dpif *dpif, const struct dpif_flow_del *del)
         return error;
     }
 
-    ovs_mutex_lock(&dp_netdev_mutex);
+    ovs_mutex_lock(&dp->flow_mutex);
+    fat_rwlock_wrlock(&dp->cls.rwlock);
     netdev_flow = dp_netdev_find_flow(dp, &key);
     if (netdev_flow) {
         if (del->stats) {
+            ovs_mutex_lock(&netdev_flow->mutex);
             get_dpif_flow_stats(netdev_flow, del->stats);
+            ovs_mutex_unlock(&netdev_flow->mutex);
         }
-        dp_netdev_free_flow(dp, netdev_flow);
+        dp_netdev_remove_flow(dp, netdev_flow);
     } else {
         error = ENOENT;
     }
-    ovs_mutex_unlock(&dp_netdev_mutex);
+    fat_rwlock_unlock(&dp->cls.rwlock);
+    ovs_mutex_unlock(&dp->flow_mutex);
 
     return error;
 }
@@ -1055,7 +1310,7 @@ dpif_netdev_flow_del(struct dpif *dpif, const struct dpif_flow_del *del)
 struct dp_netdev_flow_state {
     uint32_t bucket;
     uint32_t offset;
-    struct nlattr *actions;
+    struct dp_netdev_actions *actions;
     struct odputil_keybuf keybuf;
     struct odputil_keybuf maskbuf;
     struct dpif_flow_stats stats;
@@ -1085,15 +1340,17 @@ dpif_netdev_flow_dump_next(const struct dpif *dpif, void *state_,
     struct dp_netdev_flow *netdev_flow;
     struct hmap_node *node;
 
-    ovs_mutex_lock(&dp_netdev_mutex);
+    fat_rwlock_rdlock(&dp->cls.rwlock);
     node = hmap_at_position(&dp->flow_table, &state->bucket, &state->offset);
+    if (node) {
+        netdev_flow = CONTAINER_OF(node, struct dp_netdev_flow, node);
+        dp_netdev_flow_ref(netdev_flow);
+    }
+    fat_rwlock_unlock(&dp->cls.rwlock);
     if (!node) {
-        ovs_mutex_unlock(&dp_netdev_mutex);
         return EOF;
     }
 
-    netdev_flow = CONTAINER_OF(node, struct dp_netdev_flow, node);
-
     if (key) {
         struct ofpbuf buf;
 
@@ -1118,21 +1375,25 @@ dpif_netdev_flow_dump_next(const struct dpif *dpif, void *state_,
         *mask_len = buf.size;
     }
 
-    if (actions) {
-        free(state->actions);
-        state->actions = xmemdup(netdev_flow->actions,
-                         netdev_flow->actions_len);
+    if (actions || stats) {
+        dp_netdev_actions_unref(state->actions);
+        state->actions = NULL;
 
-        *actions = state->actions;
-        *actions_len = netdev_flow->actions_len;
+        ovs_mutex_lock(&netdev_flow->mutex);
+        if (actions) {
+            state->actions = dp_netdev_actions_ref(netdev_flow->actions);
+            *actions = state->actions->actions;
+            *actions_len = state->actions->size;
+        }
+        if (stats) {
+            get_dpif_flow_stats(netdev_flow, &state->stats);
+            *stats = &state->stats;
+        }
+        ovs_mutex_unlock(&netdev_flow->mutex);
     }
 
-    if (stats) {
-        get_dpif_flow_stats(netdev_flow, &state->stats);
-        *stats = &state->stats;
-    }
+    dp_netdev_flow_unref(netdev_flow);
 
-    ovs_mutex_unlock(&dp_netdev_mutex);
     return 0;
 }
 
@@ -1141,7 +1402,7 @@ dpif_netdev_flow_dump_done(const struct dpif *dpif OVS_UNUSED, void *state_)
 {
     struct dp_netdev_flow_state *state = state_;
 
-    free(state->actions);
+    dp_netdev_actions_unref(state->actions);
     free(state);
     return 0;
 }
@@ -1161,10 +1422,12 @@ dpif_netdev_execute(struct dpif *dpif, struct dpif_execute *execute)
     /* Extract flow key. */
     flow_extract(execute->packet, md->skb_priority, md->pkt_mark, &md->tunnel,
                  (union flow_in_port *)&md->in_port, &key);
-    ovs_mutex_lock(&dp_netdev_mutex);
+
+    ovs_rwlock_rdlock(&dp->port_rwlock);
     dp_netdev_execute_actions(dp, &key, execute->packet, md, execute->actions,
                               execute->actions_len);
-    ovs_mutex_unlock(&dp_netdev_mutex);
+    ovs_rwlock_unlock(&dp->port_rwlock);
+
     return 0;
 }
 
@@ -1183,9 +1446,9 @@ dpif_netdev_queue_to_priority(const struct dpif *dpif OVS_UNUSED,
 }
 
 static struct dp_netdev_queue *
-find_nonempty_queue(struct dpif *dpif)
+find_nonempty_queue(struct dp_netdev *dp)
+    OVS_REQUIRES(dp->queue_mutex)
 {
-    struct dp_netdev *dp = get_dp_netdev(dpif);
     int i;
 
     for (i = 0; i < N_QUEUES; i++) {
@@ -1201,11 +1464,12 @@ static int
 dpif_netdev_recv(struct dpif *dpif, struct dpif_upcall *upcall,
                  struct ofpbuf *buf)
 {
+    struct dp_netdev *dp = get_dp_netdev(dpif);
     struct dp_netdev_queue *q;
     int error;
 
-    ovs_mutex_lock(&dp_netdev_mutex);
-    q = find_nonempty_queue(dpif);
+    ovs_mutex_lock(&dp->queue_mutex);
+    q = find_nonempty_queue(dp);
     if (q) {
         struct dp_netdev_upcall *u = &q->upcalls[q->tail++ & QUEUE_MASK];
 
@@ -1218,7 +1482,7 @@ dpif_netdev_recv(struct dpif *dpif, struct dpif_upcall *upcall,
     } else {
         error = EAGAIN;
     }
-    ovs_mutex_unlock(&dp_netdev_mutex);
+    ovs_mutex_unlock(&dp->queue_mutex);
 
     return error;
 }
@@ -1229,130 +1493,224 @@ dpif_netdev_recv_wait(struct dpif *dpif)
     struct dp_netdev *dp = get_dp_netdev(dpif);
     uint64_t seq;
 
-    ovs_mutex_lock(&dp_netdev_mutex);
+    ovs_mutex_lock(&dp->queue_mutex);
     seq = seq_read(dp->queue_seq);
-    if (find_nonempty_queue(dpif)) {
+    if (find_nonempty_queue(dp)) {
         poll_immediate_wake();
     } else {
         seq_wait(dp->queue_seq, seq);
     }
-    ovs_mutex_unlock(&dp_netdev_mutex);
+    ovs_mutex_unlock(&dp->queue_mutex);
 }
 
 static void
 dpif_netdev_recv_purge(struct dpif *dpif)
 {
     struct dpif_netdev *dpif_netdev = dpif_netdev_cast(dpif);
-    ovs_mutex_lock(&dp_netdev_mutex);
+
     dp_netdev_purge_queues(dpif_netdev->dp);
-    ovs_mutex_unlock(&dp_netdev_mutex);
 }
 \f
-static void
-dp_netdev_flow_used(struct dp_netdev_flow *netdev_flow,
-                    const struct ofpbuf *packet)
+/* Creates and returns a new 'struct dp_netdev_actions', with a reference count
+ * of 1, whose actions are a copy of from the 'ofpacts_len' bytes of
+ * 'ofpacts'. */
+struct dp_netdev_actions *
+dp_netdev_actions_create(const struct nlattr *actions, size_t size)
 {
-    netdev_flow->used = time_msec();
-    netdev_flow->packet_count++;
-    netdev_flow->byte_count += packet->size;
-    netdev_flow->tcp_flags |= packet_get_tcp_flags(packet, &netdev_flow->flow);
+    struct dp_netdev_actions *netdev_actions;
+
+    netdev_actions = xmalloc(sizeof *netdev_actions);
+    ovs_refcount_init(&netdev_actions->ref_cnt);
+    netdev_actions->actions = xmemdup(actions, size);
+    netdev_actions->size = size;
+
+    return netdev_actions;
 }
 
-static void
-dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet,
-                     struct pkt_metadata *md)
+/* Increments 'actions''s refcount. */
+struct dp_netdev_actions *
+dp_netdev_actions_ref(const struct dp_netdev_actions *actions_)
 {
-    struct dp_netdev_flow *netdev_flow;
-    struct flow key;
+    struct dp_netdev_actions *actions;
 
-    if (packet->size < ETH_HEADER_LEN) {
-        return;
-    }
-    flow_extract(packet, md->skb_priority, md->pkt_mark, &md->tunnel,
-                 (union flow_in_port *)&md->in_port, &key);
-    netdev_flow = dp_netdev_lookup_flow(dp, &key);
-    if (netdev_flow) {
-        dp_netdev_flow_used(netdev_flow, packet);
-        dp_netdev_execute_actions(dp, &key, packet, md,
-                                  netdev_flow->actions,
-                                  netdev_flow->actions_len);
-        dp->n_hit++;
-    } else {
-        dp->n_missed++;
-        dp_netdev_output_userspace(dp, packet, DPIF_UC_MISS, &key, NULL);
+    actions = CONST_CAST(struct dp_netdev_actions *, actions_);
+    if (actions) {
+        ovs_refcount_ref(&actions->ref_cnt);
     }
+    return actions;
 }
 
-static void
-dpif_netdev_run(struct dpif *dpif)
+/* Decrements 'actions''s refcount and frees 'actions' if the refcount reaches
+ * 0. */
+void
+dp_netdev_actions_unref(struct dp_netdev_actions *actions)
 {
-    struct dp_netdev_port *port;
-    struct dp_netdev *dp;
+    if (actions && ovs_refcount_unref(&actions->ref_cnt) == 1) {
+        free(actions->actions);
+        free(actions);
+    }
+}
+\f
+static void *
+dp_forwarder_main(void *f_)
+{
+    struct dp_forwarder *f = f_;
+    struct dp_netdev *dp = f->dp;
     struct ofpbuf packet;
-    size_t buf_size;
-
-    ovs_mutex_lock(&dp_netdev_mutex);
-    dp = get_dp_netdev(dpif);
-    ofpbuf_init(&packet, 0);
 
-    buf_size = DP_NETDEV_HEADROOM + VLAN_ETH_HEADER_LEN + dp->max_mtu;
+    f->name = xasprintf("forwarder_%u", ovsthread_id_self());
+    set_subprogram_name("%s", f->name);
 
-    LIST_FOR_EACH (port, node, &dp->port_list) {
-        int error;
+    ofpbuf_init(&packet, 0);
+    while (!latch_is_set(&dp->exit_latch)) {
+        bool received_anything;
+        int i;
+
+        ovs_rwlock_rdlock(&dp->port_rwlock);
+        for (i = 0; i < 50; i++) {
+            struct dp_netdev_port *port;
+
+            received_anything = false;
+            HMAP_FOR_EACH (port, node, &f->dp->ports) {
+                if (port->rx
+                    && port->node.hash >= f->min_hash
+                    && port->node.hash <= f->max_hash) {
+                    int buf_size;
+                    int error;
+                    int mtu;
+
+                    if (netdev_get_mtu(port->netdev, &mtu)) {
+                        mtu = ETH_PAYLOAD_MAX;
+                    }
+                    buf_size = DP_NETDEV_HEADROOM + VLAN_ETH_HEADER_LEN + mtu;
+
+                    ofpbuf_clear(&packet);
+                    ofpbuf_reserve_with_tailroom(&packet, DP_NETDEV_HEADROOM,
+                                                 buf_size);
+
+                    error = netdev_rx_recv(port->rx, &packet);
+                    if (!error) {
+                        struct pkt_metadata md
+                            = PKT_METADATA_INITIALIZER(port->port_no);
+                        dp_netdev_port_input(dp, &packet, &md);
+
+                        received_anything = true;
+                    } else if (error != EAGAIN && error != EOPNOTSUPP) {
+                        static struct vlog_rate_limit rl
+                            = VLOG_RATE_LIMIT_INIT(1, 5);
+
+                        VLOG_ERR_RL(&rl, "error receiving data from %s: %s",
+                                    netdev_get_name(port->netdev),
+                                    ovs_strerror(error));
+                    }
+                }
+            }
 
-        /* Reset packet contents. Packet data may have been stolen. */
-        ofpbuf_clear(&packet);
-        ofpbuf_reserve_with_tailroom(&packet, DP_NETDEV_HEADROOM, buf_size);
+            if (!received_anything) {
+                break;
+            }
+        }
 
-        error = port->rx ? netdev_rx_recv(port->rx, &packet) : EOPNOTSUPP;
-        if (!error) {
-            struct pkt_metadata md = PKT_METADATA_INITIALIZER(port->port_no);
-            dp_netdev_port_input(dp, &packet, &md);
-        } else if (error != EAGAIN && error != EOPNOTSUPP) {
-            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+        if (received_anything) {
+            poll_immediate_wake();
+        } else {
+            struct dp_netdev_port *port;
 
-            VLOG_ERR_RL(&rl, "error receiving data from %s: %s",
-                        netdev_get_name(port->netdev), ovs_strerror(error));
+            HMAP_FOR_EACH (port, node, &f->dp->ports)
+                if (port->rx
+                    && port->node.hash >= f->min_hash
+                    && port->node.hash <= f->max_hash) {
+                    netdev_rx_wait(port->rx);
+                }
+            seq_wait(dp->port_seq, seq_read(dp->port_seq));
+            latch_wait(&dp->exit_latch);
         }
+        ovs_rwlock_unlock(&dp->port_rwlock);
+
+        poll_block();
     }
     ofpbuf_uninit(&packet);
-    ovs_mutex_unlock(&dp_netdev_mutex);
+
+    free(f->name);
+
+    return NULL;
 }
 
 static void
-dpif_netdev_wait(struct dpif *dpif)
+dp_netdev_set_threads(struct dp_netdev *dp, int n)
 {
-    struct dp_netdev_port *port;
+    int i;
 
-    /* There is a race here, if thread A calls dpif_netdev_wait(dpif) and
-     * thread B calls dpif_port_add(dpif) or dpif_port_remove(dpif) before
-     * A makes it to poll_block().
-     *
-     * But I think it doesn't matter:
-     *
-     *     - In the dpif_port_add() case, A will not wake up when a packet
-     *       arrives on the new port, but this would also happen if the
-     *       ordering were reversed.
-     *
-     *     - In the dpif_port_remove() case, A might wake up spuriously, but
-     *       that is harmless. */
+    if (n == dp->n_forwarders) {
+        return;
+    }
 
-    ovs_mutex_lock(&dp_netdev_mutex);
-    LIST_FOR_EACH (port, node, &get_dp_netdev(dpif)->port_list) {
-        if (port->rx) {
-            netdev_rx_wait(port->rx);
+    /* Stop existing threads. */
+    latch_set(&dp->exit_latch);
+    for (i = 0; i < dp->n_forwarders; i++) {
+        struct dp_forwarder *f = &dp->forwarders[i];
+
+        xpthread_join(f->thread, NULL);
+    }
+    latch_poll(&dp->exit_latch);
+    free(dp->forwarders);
+
+    /* Start new threads. */
+    dp->forwarders = xmalloc(n * sizeof *dp->forwarders);
+    dp->n_forwarders = n;
+    for (i = 0; i < n; i++) {
+        struct dp_forwarder *f = &dp->forwarders[i];
+
+        f->dp = dp;
+        f->min_hash = UINT32_MAX / n * i;
+        f->max_hash = UINT32_MAX / n * (i + 1) - 1;
+        if (i == n - 1) {
+            f->max_hash = UINT32_MAX;
         }
+        xpthread_create(&f->thread, NULL, dp_forwarder_main, f);
     }
-    ovs_mutex_unlock(&dp_netdev_mutex);
+}
+\f
+static void
+dp_netdev_flow_used(struct dp_netdev_flow *netdev_flow,
+                    const struct ofpbuf *packet)
+    OVS_REQUIRES(netdev_flow->mutex)
+{
+    netdev_flow->used = time_msec();
+    netdev_flow->packet_count++;
+    netdev_flow->byte_count += packet->size;
+    netdev_flow->tcp_flags |= packet_get_tcp_flags(packet, &netdev_flow->flow);
 }
 
 static void
-dp_netdev_output_port(struct dp_netdev *dp, struct ofpbuf *packet,
-                      odp_port_t out_port)
+dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet,
+                     struct pkt_metadata *md)
+    OVS_REQ_RDLOCK(dp->port_rwlock)
 {
-    struct dp_netdev_port *p = dp->ports[odp_to_u32(out_port)];
-    if (p) {
-        netdev_send(p->netdev, packet);
+    struct dp_netdev_flow *netdev_flow;
+    struct flow key;
+
+    if (packet->size < ETH_HEADER_LEN) {
+        return;
+    }
+    flow_extract(packet, md->skb_priority, md->pkt_mark, &md->tunnel,
+                 (union flow_in_port *)&md->in_port, &key);
+    netdev_flow = dp_netdev_lookup_flow(dp, &key);
+    if (netdev_flow) {
+        struct dp_netdev_actions *actions;
+
+        ovs_mutex_lock(&netdev_flow->mutex);
+        dp_netdev_flow_used(netdev_flow, packet);
+        actions = dp_netdev_actions_ref(netdev_flow->actions);
+        ovs_mutex_unlock(&netdev_flow->mutex);
+
+        dp_netdev_execute_actions(dp, &key, packet, md,
+                                  actions->actions, actions->size);
+        dp_netdev_actions_unref(actions);
+        ovsthread_counter_inc(dp->n_hit, 1);
+    } else {
+        ovsthread_counter_inc(dp->n_missed, 1);
+        dp_netdev_output_userspace(dp, packet, DPIF_UC_MISS, &key, NULL);
     }
 }
 
@@ -1360,8 +1718,12 @@ static int
 dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet,
                            int queue_no, const struct flow *flow,
                            const struct nlattr *userdata)
+    OVS_EXCLUDED(dp->queue_mutex)
 {
     struct dp_netdev_queue *q = &dp->queues[queue_no];
+    int error;
+
+    ovs_mutex_lock(&dp->queue_mutex);
     if (q->head - q->tail < MAX_QUEUE_LEN) {
         struct dp_netdev_upcall *u = &q->upcalls[q->head++ & QUEUE_MASK];
         struct dpif_upcall *upcall = &u->upcall;
@@ -1395,11 +1757,14 @@ dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet,
 
         seq_change(dp->queue_seq);
 
-        return 0;
+        error = 0;
     } else {
-        dp->n_lost++;
-        return ENOBUFS;
+        ovsthread_counter_inc(dp->n_lost, 1);
+        error = ENOBUFS;
     }
+    ovs_mutex_unlock(&dp->queue_mutex);
+
+    return error;
 }
 
 struct dp_netdev_execute_aux {
@@ -1411,13 +1776,18 @@ static void
 dp_execute_cb(void *aux_, struct ofpbuf *packet,
               const struct pkt_metadata *md OVS_UNUSED,
               const struct nlattr *a, bool may_steal)
+    OVS_NO_THREAD_SAFETY_ANALYSIS
 {
     struct dp_netdev_execute_aux *aux = aux_;
     int type = nl_attr_type(a);
+    struct dp_netdev_port *p;
 
     switch ((enum ovs_action_attr)type) {
     case OVS_ACTION_ATTR_OUTPUT:
-        dp_netdev_output_port(aux->dp, packet, u32_to_odp(nl_attr_get_u32(a)));
+        p = dp_netdev_lookup_port(aux->dp, u32_to_odp(nl_attr_get_u32(a)));
+        if (p) {
+            netdev_send(p->netdev, packet);
+        }
         break;
 
     case OVS_ACTION_ATTR_USERSPACE: {
@@ -1452,6 +1822,7 @@ static void
 dp_netdev_execute_actions(struct dp_netdev *dp, const struct flow *key,
                           struct ofpbuf *packet, struct pkt_metadata *md,
                           const struct nlattr *actions, size_t actions_len)
+    OVS_REQ_RDLOCK(dp->port_rwlock)
 {
     struct dp_netdev_execute_aux aux = {dp, key};
 
@@ -1464,14 +1835,13 @@ dp_netdev_execute_actions(struct dp_netdev *dp, const struct flow *key,
     dpif_netdev_open,                                  \
     dpif_netdev_close,                                 \
     dpif_netdev_destroy,                               \
-    dpif_netdev_run,                                   \
-    dpif_netdev_wait,                                  \
+    NULL,                                      \
+    NULL,                                      \
     dpif_netdev_get_stats,                             \
     dpif_netdev_port_add,                              \
     dpif_netdev_port_del,                              \
     dpif_netdev_port_query_by_number,                  \
     dpif_netdev_port_query_by_name,                    \
-    dpif_netdev_get_max_ports,                         \
     NULL,                       /* port_get_pid */     \
     dpif_netdev_port_dump_start,                       \
     dpif_netdev_port_dump_next,                                \
@@ -1509,33 +1879,42 @@ dpif_dummy_change_port_number(struct unixctl_conn *conn, int argc OVS_UNUSED,
 {
     struct dp_netdev_port *port;
     struct dp_netdev *dp;
-    int port_no;
+    odp_port_t port_no;
 
+    ovs_mutex_lock(&dp_netdev_mutex);
     dp = shash_find_data(&dp_netdevs, argv[1]);
     if (!dp || !dpif_netdev_class_is_dummy(dp->class)) {
+        ovs_mutex_unlock(&dp_netdev_mutex);
         unixctl_command_reply_error(conn, "unknown datapath or not a dummy");
         return;
     }
+    ovs_refcount_ref(&dp->ref_cnt);
+    ovs_mutex_unlock(&dp_netdev_mutex);
 
+    ovs_rwlock_wrlock(&dp->port_rwlock);
     if (get_port_by_name(dp, argv[2], &port)) {
         unixctl_command_reply_error(conn, "unknown port");
-        return;
+        goto exit;
     }
 
-    port_no = atoi(argv[3]);
-    if (port_no <= 0 || port_no >= MAX_PORTS) {
+    port_no = u32_to_odp(atoi(argv[3]));
+    if (!port_no || port_no == ODPP_NONE) {
         unixctl_command_reply_error(conn, "bad port number");
-        return;
+        goto exit;
     }
-    if (dp->ports[port_no]) {
+    if (dp_netdev_lookup_port(dp, port_no)) {
         unixctl_command_reply_error(conn, "port number already in use");
-        return;
+        goto exit;
     }
-    dp->ports[odp_to_u32(port->port_no)] = NULL;
-    dp->ports[port_no] = port;
-    port->port_no = u32_to_odp(port_no);
+    hmap_remove(&dp->ports, &port->node);
+    port->port_no = port_no;
+    hmap_insert(&dp->ports, &port->node, hash_int(odp_to_u32(port_no), 0));
     seq_change(dp->port_seq);
     unixctl_command_reply(conn, NULL);
+
+exit:
+    ovs_rwlock_unlock(&dp->port_rwlock);
+    dp_netdev_unref(dp);
 }
 
 static void
index 522a31d..f41ab6b 100644 (file)
@@ -144,10 +144,6 @@ struct dpif_class {
     int (*port_query_by_name)(const struct dpif *dpif, const char *devname,
                               struct dpif_port *port);
 
-    /* Returns one greater than the largest port number accepted in flow
-     * actions. */
-    uint32_t (*get_max_ports)(const struct dpif *dpif);
-
     /* Returns the Netlink PID value to supply in OVS_ACTION_ATTR_USERSPACE
      * actions as the OVS_USERSPACE_ATTR_PID attribute's value, for use in
      * flows whose packets arrived on port 'port_no'.
diff --git a/lib/fat-rwlock.c b/lib/fat-rwlock.c
new file mode 100644 (file)
index 0000000..9ffa37b
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2013, 2014 Nicira, 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.
+ */
+
+#include <config.h>
+
+#include "fat-rwlock.h"
+
+#include <errno.h>
+
+#include "hmap.h"
+#include "list.h"
+#include "ovs-thread.h"
+#include "random.h"
+
+/* This system's cache line size, in bytes.
+ * Being wrong hurts performance but not correctness. */
+#define CACHE_LINE_SIZE 64      /* Correct for most CPUs. */
+BUILD_ASSERT_DECL(IS_POW2(CACHE_LINE_SIZE));
+
+struct fat_rwlock_slot {
+    /* Membership in rwlock's list of "struct fat_rwlock_slot"s.
+     *
+     * fat_rwlock_destroy() sets 'rwlock' to NULL to indicate that this
+     * slot may be destroyed. */
+    struct list list_node;      /* In struct rwlock's 'threads' list. */
+    struct fat_rwlock *rwlock;  /* Owner. */
+
+    /* Mutex.
+     *
+     * A thread holding the read-lock holds its own mutex.
+     *
+     * A thread holding the write-lock holds every thread's mutex, plus
+     * 'rwlock->mutex'. */
+    struct ovs_mutex mutex;
+
+    /* This thread's locking status for 'rwlock':
+     *
+     *     - 0: This thread does not have any lock on 'rwlock'.  This thread
+     *       does not have 'mutex' locked.
+     *
+     *     - 1: This thread has a read-lock on 'rwlock' and holds 'mutex'.
+     *
+     *     - 2...UINT_MAX-1: This thread has recursively taken the read-lock on
+     *       'rwlock' to the level of 'depth'.  This thread holds 'mutex'.
+     *
+     *     - UINT_MAX: This thread has the write-lock on 'rwlock' and holds
+     *       'mutex' (plus the 'mutex' of all of 'rwlock''s other slots).
+     *
+     * Accessed only by the slot's own thread, so no synchronization is
+     * needed. */
+    unsigned int depth;
+
+    /* To prevent two of these structures from accidentally occupying the same
+     * cache line (causing "false sharing"), we cache-align each of these data
+     * structures.  That requires malloc()ing extra space and throwing away
+     * some space at the beginning, which means that the pointer to this struct
+     * isn't necessarily the pointer to the beginning of the block, and so we
+     * need to retain the original pointer to free later.
+     *
+     * Accessed only by a single thread, so no synchronization is needed. */
+    void *base;                /* Pointer to pass to free() for this block.  */
+};
+
+static void
+free_slot(struct fat_rwlock_slot *slot)
+{
+    if (slot->depth) {
+        abort();
+    }
+
+    list_remove(&slot->list_node);
+    free(slot->base);
+}
+
+static void
+slot_destructor(void *slot_)
+{
+    struct fat_rwlock_slot *slot = slot_;
+    struct fat_rwlock *rwlock = slot->rwlock;
+
+    ovs_mutex_lock(&rwlock->mutex);
+    free_slot(slot);
+    ovs_mutex_unlock(&rwlock->mutex);
+}
+
+/* Initialize 'rwlock' as a new fat_rwlock. */
+void
+fat_rwlock_init(struct fat_rwlock *rwlock)
+{
+    ovsthread_key_create(&rwlock->key, slot_destructor);
+    ovs_mutex_init(&rwlock->mutex);
+    ovs_mutex_lock(&rwlock->mutex);
+    list_init(&rwlock->threads);
+    ovs_mutex_unlock(&rwlock->mutex);
+}
+
+/* Destroys 'rwlock', which must not be locked or otherwise in use by any
+ * thread. */
+void
+fat_rwlock_destroy(struct fat_rwlock *rwlock)
+{
+    struct fat_rwlock_slot *slot, *next;
+
+    /* Order is important here.  By destroying the thread-specific data first,
+     * before we destroy the slots, we ensure that the thread-specific
+     * data destructor can't race with our loop below. */
+    ovsthread_key_delete(rwlock->key);
+
+    LIST_FOR_EACH_SAFE (slot, next, list_node, &rwlock->threads) {
+        free_slot(slot);
+    }
+    ovs_mutex_destroy(&rwlock->mutex);
+}
+
+static struct fat_rwlock_slot *
+fat_rwlock_get_slot__(struct fat_rwlock *rwlock)
+{
+    struct fat_rwlock_slot *slot;
+    void *base;
+
+    /* Fast path. */
+    slot = ovsthread_getspecific(rwlock->key);
+    if (slot) {
+        return slot;
+    }
+
+    /* Slow path: create a new slot for 'rwlock' in this thread. */
+
+    /* Allocate room for:
+     *
+     *     - Up to CACHE_LINE_SIZE - 1 bytes before the per-thread, so that
+     *       the start of the slot doesn't potentially share a cache line.
+     *
+     *     - The slot itself.
+     *
+     *     - Space following the slot up to the end of the cache line, so
+     *       that the end of the slot doesn't potentially share a cache
+     *       line. */
+    base = xmalloc((CACHE_LINE_SIZE - 1)
+                   + ROUND_UP(sizeof *slot, CACHE_LINE_SIZE));
+    slot = (void *) ROUND_UP((uintptr_t) base, CACHE_LINE_SIZE);
+
+    slot->base = base;
+    slot->rwlock = rwlock;
+    ovs_mutex_init(&slot->mutex);
+    slot->depth = 0;
+
+    ovs_mutex_lock(&rwlock->mutex);
+    list_push_back(&rwlock->threads, &slot->list_node);
+    ovs_mutex_unlock(&rwlock->mutex);
+
+    ovsthread_setspecific(rwlock->key, slot);
+
+    return slot;
+}
+
+/* Locks 'rwlock' for reading.  The read-lock is recursive: it may be acquired
+ * any number of times by a single thread (which must then release it the same
+ * number of times for it to truly be released). */
+void
+fat_rwlock_rdlock(const struct fat_rwlock *rwlock_)
+    OVS_ACQ_RDLOCK(rwlock_)
+    OVS_NO_THREAD_SAFETY_ANALYSIS
+{
+    struct fat_rwlock *rwlock = CONST_CAST(struct fat_rwlock *, rwlock_);
+    struct fat_rwlock_slot *this = fat_rwlock_get_slot__(rwlock);
+
+    switch (this->depth) {
+    case UINT_MAX:
+        /* This thread already holds the write-lock. */
+        abort();
+
+    case 0:
+        ovs_mutex_lock(&this->mutex);
+        /* fall through */
+    default:
+        this->depth++;
+        break;
+    }
+}
+
+/* Tries to lock 'rwlock' for reading.  If successful, returns 0.  If taking
+ * the lock would require blocking, returns EBUSY (without blocking). */
+int
+fat_rwlock_tryrdlock(const struct fat_rwlock *rwlock_)
+    OVS_TRY_RDLOCK(0, rwlock_)
+    OVS_NO_THREAD_SAFETY_ANALYSIS
+{
+    struct fat_rwlock *rwlock = CONST_CAST(struct fat_rwlock *, rwlock_);
+    struct fat_rwlock_slot *this = fat_rwlock_get_slot__(rwlock);
+    int error;
+
+    switch (this->depth) {
+    case UINT_MAX:
+        return EBUSY;
+
+    case 0:
+        error = ovs_mutex_trylock(&this->mutex);
+        if (error) {
+            return error;
+        }
+        /* fall through */
+    default:
+        this->depth++;
+        break;
+    }
+
+    return 0;
+}
+
+/* Locks 'rwlock' for writing.
+ *
+ * The write lock is not recursive. */
+void
+fat_rwlock_wrlock(const struct fat_rwlock *rwlock_)
+    OVS_ACQ_WRLOCK(rwlock_)
+    OVS_NO_THREAD_SAFETY_ANALYSIS
+{
+    struct fat_rwlock *rwlock = CONST_CAST(struct fat_rwlock *, rwlock_);
+    struct fat_rwlock_slot *this = fat_rwlock_get_slot__(rwlock);
+    struct fat_rwlock_slot *slot;
+
+    ovs_assert(!this->depth);
+    this->depth = UINT_MAX;
+
+    ovs_mutex_lock(&rwlock->mutex);
+    LIST_FOR_EACH (slot, list_node, &rwlock->threads) {
+        ovs_mutex_lock(&slot->mutex);
+    }
+}
+
+/* Unlocks 'rwlock', which the current thread must have locked for reading or
+ * for writing.  If the read lock has been taken recursively, it must be
+ * released the same number of times to be truly released. */
+void
+fat_rwlock_unlock(const struct fat_rwlock *rwlock_)
+    OVS_RELEASES(rwlock_)
+    OVS_NO_THREAD_SAFETY_ANALYSIS
+{
+    struct fat_rwlock *rwlock = CONST_CAST(struct fat_rwlock *, rwlock_);
+    struct fat_rwlock_slot *this = fat_rwlock_get_slot__(rwlock);
+    struct fat_rwlock_slot *slot;
+
+    switch (this->depth) {
+    case UINT_MAX:
+        LIST_FOR_EACH (slot, list_node, &rwlock->threads) {
+            ovs_mutex_unlock(&slot->mutex);
+        }
+        ovs_mutex_unlock(&rwlock->mutex);
+        this->depth = 0;
+        break;
+
+    case 0:
+        /* This thread doesn't hold any lock. */
+        abort();
+
+    case 1:
+        ovs_mutex_unlock(&this->mutex);
+    default:
+        this->depth--;
+        break;
+    }
+}
diff --git a/lib/fat-rwlock.h b/lib/fat-rwlock.h
new file mode 100644 (file)
index 0000000..27e3c22
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013, 2014 Nicira, 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.
+ */
+
+#ifndef FAT_RWLOCK_H
+#define FAT_RWLOCK_H 1
+
+#include "compiler.h"
+#include "list.h"
+#include "ovs-thread.h"
+
+/* "Fat rwlock".
+ *
+ * This implements a reader-writer lock that uses a lot of memory (128 to 192
+ * bytes per thread that takes the lock) but avoids cache line bouncing when
+ * taking the read side.  Thus, a fat_rwlock is a good choice for rwlocks taken
+ * frequently by readers.
+ */
+struct OVS_LOCKABLE fat_rwlock {
+    ovsthread_key_t key;
+
+    /* Contains "struct fat_rwlock_slot"s, one for each thread that has taken
+     * this lock.  Guarded by 'mutex'. */
+    struct list threads OVS_GUARDED;
+    struct ovs_mutex mutex;
+};
+
+void fat_rwlock_init(struct fat_rwlock *);
+void fat_rwlock_destroy(struct fat_rwlock *);
+
+void fat_rwlock_rdlock(const struct fat_rwlock *rwlock) OVS_ACQ_RDLOCK(rwlock);
+int fat_rwlock_tryrdlock(const struct fat_rwlock *rwlock)
+    OVS_TRY_RDLOCK(0, rwlock);
+void fat_rwlock_wrlock(const struct fat_rwlock *rwlock) OVS_ACQ_WRLOCK(rwlock);
+void fat_rwlock_unlock(const struct fat_rwlock *rwlock) OVS_RELEASES(rwlock);
+
+#endif /* fat-rwlock.h */
index f1d2cad..b1b9f98 100644 (file)
@@ -1168,7 +1168,7 @@ flow_compose(struct ofpbuf *b, const struct flow *flow)
     }
 
     if (flow->vlan_tci & htons(VLAN_CFI)) {
-        eth_push_vlan(b, flow->vlan_tci);
+        eth_push_vlan(b, htons(ETH_TYPE_VLAN), flow->vlan_tci);
     }
 
     if (flow->dl_type == htons(ETH_TYPE_IP)) {
index 9eec1f9..a3f72ed 100644 (file)
@@ -106,7 +106,7 @@ struct lacp {
     bool update;             /* True if lacp_update() needs to be called. */
     bool fallback_ab; /* True if fallback to active-backup on LACP failure. */
 
-    atomic_int ref_cnt;
+    struct ovs_refcount ref_cnt;
 };
 
 struct slave {
@@ -216,7 +216,7 @@ lacp_create(void) OVS_EXCLUDED(mutex)
 
     lacp = xzalloc(sizeof *lacp);
     hmap_init(&lacp->slaves);
-    atomic_init(&lacp->ref_cnt, 1);
+    ovs_refcount_init(&lacp->ref_cnt);
 
     ovs_mutex_lock(&mutex);
     list_push_back(all_lacps, &lacp->node);
@@ -229,9 +229,7 @@ lacp_ref(const struct lacp *lacp_)
 {
     struct lacp *lacp = CONST_CAST(struct lacp *, lacp_);
     if (lacp) {
-        int orig;
-        atomic_add(&lacp->ref_cnt, 1, &orig);
-        ovs_assert(orig > 0);
+        ovs_refcount_ref(&lacp->ref_cnt);
     }
     return lacp;
 }
@@ -240,15 +238,7 @@ lacp_ref(const struct lacp *lacp_)
 void
 lacp_unref(struct lacp *lacp) OVS_EXCLUDED(mutex)
 {
-    int orig;
-
-    if (!lacp) {
-        return;
-    }
-
-    atomic_sub(&lacp->ref_cnt, 1, &orig);
-    ovs_assert(orig > 0);
-    if (orig == 1) {
+    if (lacp && ovs_refcount_unref(&lacp->ref_cnt) == 1) {
         struct slave *slave, *next;
 
         ovs_mutex_lock(&mutex);
@@ -259,6 +249,7 @@ lacp_unref(struct lacp *lacp) OVS_EXCLUDED(mutex)
         hmap_destroy(&lacp->slaves);
         list_remove(&lacp->node);
         free(lacp->name);
+        ovs_refcount_destroy(&lacp->ref_cnt);
         free(lacp);
         ovs_mutex_unlock(&mutex);
     }
diff --git a/lib/latch-windows.c b/lib/latch-windows.c
new file mode 100644 (file)
index 0000000..34796d5
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2013 Nicira, 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.
+ */
+
+#include <config.h>
+
+#include "latch.h"
+#include <errno.h>
+#include <poll.h>
+#include <unistd.h>
+#include "poll-loop.h"
+#include "socket-util.h"
+
+/* Initializes 'latch' as initially unset. */
+void
+latch_init(struct latch *latch)
+{
+    latch->is_set = FALSE;
+    latch->wevent = CreateEvent(NULL, TRUE, FALSE, NULL);
+}
+
+/* Destroys 'latch'. */
+void
+latch_destroy(struct latch *latch)
+{
+    latch->is_set = FALSE;
+    CloseHandle(latch->wevent);
+}
+
+/* Resets 'latch' to the unset state.  Returns true if 'latch' was previously
+ * set, false otherwise. */
+bool
+latch_poll(struct latch *latch)
+{
+    bool is_set;
+
+    is_set = latch->is_set;
+    latch->is_set = FALSE;
+    ResetEvent(latch->wevent);
+    return is_set;
+}
+
+/* Sets 'latch'.
+ *
+ * Calls are not additive: a single latch_poll() clears out any number of
+ * latch_set(). */
+void
+latch_set(struct latch *latch)
+{
+    latch->is_set = TRUE;
+    SetEvent(latch->wevent);
+}
+
+/* Returns true if 'latch' is set, false otherwise.  Does not reset 'latch'
+ * to the unset state. */
+bool
+latch_is_set(const struct latch *latch)
+{
+    return latch->is_set;
+}
+
+/* Causes the next poll_block() to wake up when 'latch' is set.
+ *
+ * ('where' is used in debug logging.  Commonly one would use latch_wait() to
+ * automatically provide the caller's source file and line number for
+ * 'where'.) */
+void
+latch_wait_at(const struct latch *latch, const char *where)
+{
+    poll_fd_wait_at(0, latch->wevent, POLLIN, where);
+}
index bf518b9..20a6575 100644 (file)
@@ -83,5 +83,5 @@ latch_is_set(const struct latch *latch)
 void
 latch_wait_at(const struct latch *latch, const char *where)
 {
-    poll_fd_wait_at(latch->fds[0], POLLIN, where);
+    poll_fd_wait_at(latch->fds[0], 0, POLLIN, where);
 }
index 0b6e8a3..52829b1 100644 (file)
 #include "util.h"
 
 struct latch {
+#ifndef _WIN32
     int fds[2];
+#else
+    HANDLE wevent;
+    bool is_set;
+#endif
 };
 
 void latch_init(struct latch *);
index c9c1ae9..01a34f5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -111,7 +111,7 @@ mac_learning_create(unsigned int idle_time)
     ml->idle_time = normalize_idle_time(idle_time);
     ml->max_entries = MAC_DEFAULT_MAX;
     ml->need_revalidate = false;
-    atomic_init(&ml->ref_cnt, 1);
+    ovs_refcount_init(&ml->ref_cnt);
     ovs_rwlock_init(&ml->rwlock);
     return ml;
 }
@@ -121,9 +121,7 @@ mac_learning_ref(const struct mac_learning *ml_)
 {
     struct mac_learning *ml = CONST_CAST(struct mac_learning *, ml_);
     if (ml) {
-        int orig;
-        atomic_add(&ml->ref_cnt, 1, &orig);
-        ovs_assert(orig > 0);
+        ovs_refcount_ref(&ml->ref_cnt);
     }
     return ml;
 }
@@ -132,15 +130,7 @@ mac_learning_ref(const struct mac_learning *ml_)
 void
 mac_learning_unref(struct mac_learning *ml)
 {
-    int orig;
-
-    if (!ml) {
-        return;
-    }
-
-    atomic_sub(&ml->ref_cnt, 1, &orig);
-    ovs_assert(orig > 0);
-    if (orig == 1) {
+    if (ml && ovs_refcount_unref(&ml->ref_cnt) == 1) {
         struct mac_entry *e, *next;
 
         HMAP_FOR_EACH_SAFE (e, next, hmap_node, &ml->table) {
@@ -151,6 +141,7 @@ mac_learning_unref(struct mac_learning *ml)
 
         bitmap_free(ml->flood_vlans);
         ovs_rwlock_destroy(&ml->rwlock);
+        ovs_refcount_destroy(&ml->ref_cnt);
         free(ml);
     }
 }
index ba7f734..34dc12c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -80,7 +80,7 @@ struct mac_learning {
     unsigned long *flood_vlans; /* Bitmap of learning disabled VLANs. */
     unsigned int idle_time;     /* Max age before deleting an entry. */
     size_t max_entries;         /* Max number of learned MACs. */
-    atomic_int ref_cnt;
+    struct ovs_refcount ref_cnt;
     struct ovs_rwlock rwlock;
     bool need_revalidate;
 };
index 4a16e5c..689014b 100644 (file)
@@ -568,20 +568,21 @@ proc_pkt(u_char *args_, const struct pcap_pkthdr *hdr, const u_char *packet)
  * from rx->pcap.
  */
 static int
-netdev_rx_bsd_recv_pcap(struct netdev_rx_bsd *rx, void *data, size_t size)
+netdev_rx_bsd_recv_pcap(struct netdev_rx_bsd *rx, struct ofpbuf *buffer)
 {
     struct pcap_arg arg;
     int ret;
 
     /* prepare the pcap argument to store the packet */
-    arg.size = size;
-    arg.data = data;
+    arg.size = ofpbuf_tailroom(buffer);
+    arg.data = buffer->data;
 
     for (;;) {
         ret = pcap_dispatch(rx->pcap_handle, 1, proc_pkt, (u_char *) &arg);
 
         if (ret > 0) {
-            return arg.retval; /* arg.retval < 0 is handled in the caller */
+            buffer->size += arg.retval;
+            return 0;
         }
         if (ret == -1) {
             if (errno == EINTR) {
@@ -589,7 +590,7 @@ netdev_rx_bsd_recv_pcap(struct netdev_rx_bsd *rx, void *data, size_t size)
             }
         }
 
-        return -EAGAIN;
+        return EAGAIN;
     }
 }
 
@@ -599,30 +600,33 @@ netdev_rx_bsd_recv_pcap(struct netdev_rx_bsd *rx, void *data, size_t size)
  * 'rx->fd' is initialized with the tap file descriptor.
  */
 static int
-netdev_rx_bsd_recv_tap(struct netdev_rx_bsd *rx, void *data, size_t size)
+netdev_rx_bsd_recv_tap(struct netdev_rx_bsd *rx, struct ofpbuf *buffer)
 {
+    size_t size = ofpbuf_tailroom(buffer);
+
     for (;;) {
-        ssize_t retval = read(rx->fd, data, size);
+        ssize_t retval = read(rx->fd, buffer->data, size);
         if (retval >= 0) {
-            return retval;
+            buffer->size += retval;
+            return 0;
         } else if (errno != EINTR) {
             if (errno != EAGAIN) {
                 VLOG_WARN_RL(&rl, "error receiving Ethernet packet on %s: %s",
                              ovs_strerror(errno), netdev_rx_get_name(&rx->up));
             }
-            return -errno;
+            return errno;
         }
     }
 }
 
 static int
-netdev_bsd_rx_recv(struct netdev_rx *rx_, void *data, size_t size)
+netdev_bsd_rx_recv(struct netdev_rx *rx_, struct ofpbuf *buffer)
 {
     struct netdev_rx_bsd *rx = netdev_rx_bsd_cast(rx_);
 
     return (rx->pcap_handle
-            ? netdev_rx_bsd_recv_pcap(rx, data, size)
-            : netdev_rx_bsd_recv_tap(rx, data, size));
+            ? netdev_rx_bsd_recv_pcap(rx, buffer)
+            : netdev_rx_bsd_recv_tap(rx, buffer));
 }
 
 /*
index 9515021..b2a7572 100644 (file)
@@ -87,7 +87,7 @@ struct netdev_rx_dummy {
     struct list node;           /* In netdev_dummy's "rxes" list. */
     struct list recv_queue;
     int recv_queue_len;         /* list_size(&recv_queue). */
-    bool listening;
+    struct seq *seq;            /* Reports newly queued packets. */
 };
 
 static unixctl_cb_func netdev_dummy_set_admin_state;
@@ -419,6 +419,7 @@ netdev_dummy_rx_construct(struct netdev_rx *rx_)
     list_push_back(&netdev->rxes, &rx->node);
     list_init(&rx->recv_queue);
     rx->recv_queue_len = 0;
+    rx->seq = seq_create();
     ovs_mutex_unlock(&netdev->mutex);
 
     return 0;
@@ -434,6 +435,7 @@ netdev_dummy_rx_destruct(struct netdev_rx *rx_)
     list_remove(&rx->node);
     ofpbuf_list_delete(&rx->recv_queue);
     ovs_mutex_unlock(&netdev->mutex);
+    seq_destroy(rx->seq);
 }
 
 static void
@@ -445,7 +447,7 @@ netdev_dummy_rx_dealloc(struct netdev_rx *rx_)
 }
 
 static int
-netdev_dummy_rx_recv(struct netdev_rx *rx_, void *buffer, size_t size)
+netdev_dummy_rx_recv(struct netdev_rx *rx_, struct ofpbuf *buffer)
 {
     struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_);
     struct netdev_dummy *netdev = netdev_dummy_cast(rx->up.netdev);
@@ -462,19 +464,20 @@ netdev_dummy_rx_recv(struct netdev_rx *rx_, void *buffer, size_t size)
     ovs_mutex_unlock(&netdev->mutex);
 
     if (!packet) {
-        return -EAGAIN;
+        return EAGAIN;
     }
 
-    if (packet->size <= size) {
-        memcpy(buffer, packet->data, packet->size);
-        retval = packet->size;
+    if (packet->size <= ofpbuf_tailroom(buffer)) {
+        memcpy(buffer->data, packet->data, packet->size);
+        buffer->size += packet->size;
+        retval = 0;
 
         ovs_mutex_lock(&netdev->mutex);
         netdev->stats.rx_packets++;
         netdev->stats.rx_bytes += packet->size;
         ovs_mutex_unlock(&netdev->mutex);
     } else {
-        retval = -EMSGSIZE;
+        retval = EMSGSIZE;
     }
     ofpbuf_delete(packet);
 
@@ -486,10 +489,13 @@ netdev_dummy_rx_wait(struct netdev_rx *rx_)
 {
     struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_);
     struct netdev_dummy *netdev = netdev_dummy_cast(rx->up.netdev);
+    uint64_t seq = seq_read(rx->seq);
 
     ovs_mutex_lock(&netdev->mutex);
     if (!list_is_empty(&rx->recv_queue)) {
         poll_immediate_wake();
+    } else {
+        seq_wait(rx->seq, seq);
     }
     ovs_mutex_unlock(&netdev->mutex);
 }
@@ -505,6 +511,8 @@ netdev_dummy_rx_drain(struct netdev_rx *rx_)
     rx->recv_queue_len = 0;
     ovs_mutex_unlock(&netdev->mutex);
 
+    seq_change(rx->seq);
+
     return 0;
 }
 
@@ -796,6 +804,7 @@ netdev_dummy_queue_packet__(struct netdev_rx_dummy *rx, struct ofpbuf *packet)
 {
     list_push_back(&rx->recv_queue, &packet->list_node);
     rx->recv_queue_len++;
+    seq_change(rx->seq);
 }
 
 static void
index 68d476f..e756d88 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -109,6 +109,36 @@ COVERAGE_DEFINE(netdev_set_ethtool);
 #define TC_RTAB_SIZE 1024
 #endif
 
+/* Linux 2.6.21 introduced struct tpacket_auxdata.
+ * Linux 2.6.27 added the tp_vlan_tci member.
+ * Linux 3.0 defined TP_STATUS_VLAN_VALID.
+ * Linux 3.13 repurposed a padding member for tp_vlan_tpid and defined
+ * TP_STATUS_VLAN_TPID_VALID.
+ *
+ * With all this churn it's easiest to unconditionally define a replacement
+ * structure that has everything we want.
+ */
+#ifndef PACKET_AUXDATA
+#define PACKET_AUXDATA                  8
+#endif
+#ifndef TP_STATUS_VLAN_VALID
+#define TP_STATUS_VLAN_VALID            (1 << 4)
+#endif
+#ifndef TP_STATUS_VLAN_TPID_VALID
+#define TP_STATUS_VLAN_TPID_VALID       (1 << 6)
+#endif
+#undef tpacket_auxdata
+#define tpacket_auxdata rpl_tpacket_auxdata
+struct tpacket_auxdata {
+    uint32_t tp_status;
+    uint32_t tp_len;
+    uint32_t tp_snaplen;
+    uint16_t tp_mac;
+    uint16_t tp_net;
+    uint16_t tp_vlan_tci;
+    uint16_t tp_vlan_tpid;
+};
+
 enum {
     VALID_IFINDEX           = 1 << 0,
     VALID_ETHERADDR         = 1 << 1,
@@ -763,7 +793,7 @@ netdev_linux_rx_construct(struct netdev_rx *rx_)
         rx->fd = netdev->tap_fd;
     } else {
         struct sockaddr_ll sll;
-        int ifindex;
+        int ifindex, val;
         /* Result of tcpdump -dd inbound */
         static const struct sock_filter filt[] = {
             { 0x28, 0, 0, 0xfffff004 }, /* ldh [0] */
@@ -783,6 +813,14 @@ netdev_linux_rx_construct(struct netdev_rx *rx_)
             goto error;
         }
 
+        val = 1;
+        if (setsockopt(rx->fd, SOL_PACKET, PACKET_AUXDATA, &val, sizeof val)) {
+            error = errno;
+            VLOG_ERR("%s: failed to mark socket for auxdata (%s)",
+                     netdev_get_name(netdev_), ovs_strerror(error));
+            goto error;
+        }
+
         /* Set non-blocking mode. */
         error = set_nonblocking(rx->fd);
         if (error) {
@@ -799,7 +837,7 @@ netdev_linux_rx_construct(struct netdev_rx *rx_)
         memset(&sll, 0, sizeof sll);
         sll.sll_family = AF_PACKET;
         sll.sll_ifindex = ifindex;
-        sll.sll_protocol = (OVS_FORCE unsigned short int) htons(ETH_P_ALL);
+        sll.sll_protocol = htons(ETH_P_ALL);
         if (bind(rx->fd, (struct sockaddr *) &sll, sizeof sll) < 0) {
             error = errno;
             VLOG_ERR("%s: failed to bind raw socket (%s)",
@@ -847,27 +885,120 @@ netdev_linux_rx_dealloc(struct netdev_rx *rx_)
     free(rx);
 }
 
+static ovs_be16
+auxdata_to_vlan_tpid(const struct tpacket_auxdata *aux)
+{
+    if (aux->tp_status & TP_STATUS_VLAN_TPID_VALID) {
+        return htons(aux->tp_vlan_tpid);
+    } else {
+        return htons(ETH_TYPE_VLAN);
+    }
+}
+
+static bool
+auxdata_has_vlan_tci(const struct tpacket_auxdata *aux)
+{
+    return aux->tp_vlan_tci || aux->tp_status & TP_STATUS_VLAN_VALID;
+}
+
 static int
-netdev_linux_rx_recv(struct netdev_rx *rx_, void *data, size_t size)
+netdev_linux_rx_recv_sock(int fd, struct ofpbuf *buffer)
 {
-    struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_);
+    size_t size;
     ssize_t retval;
+    struct iovec iov;
+    struct cmsghdr *cmsg;
+    union {
+        struct cmsghdr cmsg;
+        char buffer[CMSG_SPACE(sizeof(struct tpacket_auxdata))];
+    } cmsg_buffer;
+    struct msghdr msgh;
+
+    /* Reserve headroom for a single VLAN tag */
+    ofpbuf_reserve(buffer, VLAN_HEADER_LEN);
+    size = ofpbuf_tailroom(buffer);
+
+    iov.iov_base = buffer->data;
+    iov.iov_len = size;
+    msgh.msg_name = NULL;
+    msgh.msg_namelen = 0;
+    msgh.msg_iov = &iov;
+    msgh.msg_iovlen = 1;
+    msgh.msg_control = &cmsg_buffer;
+    msgh.msg_controllen = sizeof cmsg_buffer;
+    msgh.msg_flags = 0;
 
     do {
-        retval = (rx->is_tap
-                  ? read(rx->fd, data, size)
-                  : recv(rx->fd, data, size, MSG_TRUNC));
+        retval = recvmsg(fd, &msgh, MSG_TRUNC);
     } while (retval < 0 && errno == EINTR);
 
-    if (retval >= 0) {
-        return retval > size ? -EMSGSIZE : retval;
-    } else {
-        if (errno != EAGAIN) {
-            VLOG_WARN_RL(&rl, "error receiving Ethernet packet on %s: %s",
-                         ovs_strerror(errno), netdev_rx_get_name(rx_));
+    if (retval < 0) {
+        return errno;
+    } else if (retval > size) {
+        return EMSGSIZE;
+    }
+
+    buffer->size += retval;
+
+    for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg; cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
+        const struct tpacket_auxdata *aux;
+
+        if (cmsg->cmsg_level != SOL_PACKET
+            || cmsg->cmsg_type != PACKET_AUXDATA
+            || cmsg->cmsg_len < CMSG_LEN(sizeof(struct tpacket_auxdata))) {
+            continue;
+        }
+
+        aux = ALIGNED_CAST(struct tpacket_auxdata *, CMSG_DATA(cmsg));
+        if (auxdata_has_vlan_tci(aux)) {
+            if (retval < ETH_HEADER_LEN) {
+                return EINVAL;
+            }
+
+            eth_push_vlan(buffer, auxdata_to_vlan_tpid(aux),
+                          htons(aux->tp_vlan_tci));
+            break;
         }
-        return -errno;
     }
+
+    return 0;
+}
+
+static int
+netdev_linux_rx_recv_tap(int fd, struct ofpbuf *buffer)
+{
+    ssize_t retval;
+    size_t size = ofpbuf_tailroom(buffer);
+
+    do {
+        retval = read(fd, buffer->data, size);
+    } while (retval < 0 && errno == EINTR);
+
+    if (retval < 0) {
+        return errno;
+    } else if (retval > size) {
+        return EMSGSIZE;
+    }
+
+    buffer->size += retval;
+    return 0;
+}
+
+static int
+netdev_linux_rx_recv(struct netdev_rx *rx_, struct ofpbuf *buffer)
+{
+    struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_);
+    int retval;
+
+    retval = (rx->is_tap
+              ? netdev_linux_rx_recv_tap(rx->fd, buffer)
+              : netdev_linux_rx_recv_sock(rx->fd, buffer));
+    if (retval && retval != EAGAIN && retval != EMSGSIZE) {
+        VLOG_WARN_RL(&rl, "error receiving Ethernet packet on %s: %s",
+                     ovs_strerror(errno), netdev_rx_get_name(rx_));
+    }
+
+    return retval;
 }
 
 static void
index 46ab2fd..04e68ba 100644 (file)
@@ -507,13 +507,14 @@ netdev_pltap_set_config(struct netdev *dev_, const struct smap *args)
 }
 
 static int
-netdev_pltap_rx_recv(struct netdev_rx *rx_, void *buffer, size_t size)
+netdev_pltap_rx_recv(struct netdev_rx *rx_, struct ofpbuf *buffer)
 {
+    size_t size = ofpbuf_tailroom(buffer);
     struct netdev_rx_pltap *rx = netdev_rx_pltap_cast(rx_);
     struct tun_pi pi;
     struct iovec iov[2] = {
         { .iov_base = &pi, .iov_len = sizeof(pi) },
-       { .iov_base = buffer, .iov_len = size }
+       { .iov_base = buffer->data, .iov_len = size }
     };
     for (;;) {
         ssize_t retval;
@@ -862,8 +863,6 @@ const struct netdev_class netdev_pltap_class = {
 
     netdev_pltap_update_flags,
 
-    netdev_pltap_change_seq,
-
     netdev_pltap_rx_alloc,
     netdev_pltap_rx_construct,
     netdev_pltap_rx_destruct,
index f1b8023..6f22356 100644 (file)
@@ -634,16 +634,28 @@ struct netdev_class {
     void (*rx_destruct)(struct netdev_rx *);
     void (*rx_dealloc)(struct netdev_rx *);
 
-    /* Attempts to receive a packet from 'rx' into the 'size' bytes in
-     * 'buffer'.  If successful, returns the number of bytes in the received
-     * packet, otherwise a negative errno value.  Returns -EAGAIN immediately
-     * if no packet is ready to be received.
+    /* Attempts to receive a packet from 'rx' into the tailroom of 'buffer',
+     * which should initially be empty.  If successful, returns 0 and
+     * increments 'buffer->size' by the number of bytes in the received packet,
+     * otherwise a positive errno value.  Returns EAGAIN immediately if no
+     * packet is ready to be received.
      *
-     * Must return -EMSGSIZE, and discard the packet, if the received packet
-     * is longer than 'size' bytes.
+     * Must return EMSGSIZE, and discard the packet, if the received packet
+     * is longer than 'ofpbuf_tailroom(buffer)'.
      *
-     * Specify NULL if this */
-    int (*rx_recv)(struct netdev_rx *rx, void *buffer, size_t size);
+     * Implementations may make use of VLAN_HEADER_LEN bytes of tailroom to
+     * add a VLAN header which is obtained out-of-band to the packet. If
+     * this occurs then VLAN_HEADER_LEN bytes of tailroom will no longer be
+     * available for the packet, otherwise it may be used for the packet
+     * itself.
+     *
+     * It is advised that the tailroom of 'buffer' should be
+     * VLAN_HEADER_LEN bytes longer than the MTU to allow space for an
+     * out-of-band VLAN header to be added to the packet.
+     *
+     * This function may be set to null if it would always return EOPNOTSUPP
+     * anyhow. */
+    int (*rx_recv)(struct netdev_rx *rx, struct ofpbuf *buffer);
 
     /* Registers with the poll loop to wake up from the next call to
      * poll_block() when a packet is ready to be received with netdev_rx_recv()
index a985ce9..b197e53 100644 (file)
@@ -264,8 +264,9 @@ netdev_tunnel_rx_dealloc(struct netdev_rx *rx_)
 }
 
 static int
-netdev_tunnel_rx_recv(struct netdev_rx *rx_, void *buffer, size_t size)
+netdev_tunnel_rx_recv(struct netdev_rx *rx_, struct ofpbuf *buffer)
 {
+    size_t size = ofpbuf_tailroom(buffer);
     struct netdev_rx_tunnel *rx = netdev_rx_tunnel_cast(rx_);
     struct netdev_tunnel *netdev =
         netdev_tunnel_cast(rx_->netdev);
@@ -273,12 +274,12 @@ netdev_tunnel_rx_recv(struct netdev_rx *rx_, void *buffer, size_t size)
         return -EAGAIN;
     for (;;) {
         ssize_t retval;
-        retval = recv(rx->fd, buffer, size, MSG_TRUNC);
+        retval = recv(rx->fd, buffer->data, size, MSG_TRUNC);
            VLOG_DBG("%s: recv(%"PRIxPTR", %"PRIuSIZE", MSG_TRUNC) = %"PRIdSIZE,
-                   netdev_rx_get_name(rx_), (uintptr_t)buffer, size, retval);
+                   netdev_rx_get_name(rx_), (uintptr_t)buffer->data, size, retval);
         if (retval >= 0) {
-           netdev->stats.rx_packets++;
-           netdev->stats.rx_bytes += retval;
+               netdev->stats.rx_packets++;
+               netdev->stats.rx_bytes += retval;
             if (retval <= size) {
                    return retval;
             } else {
@@ -614,13 +615,11 @@ const struct netdev_class netdev_tunnel_class = {
     NULL,                       /* get_in6 */
     NULL,                       /* add_router */
     NULL,                       /* get_next_hop */
-    NULL,                       /* get_drv_info */
+    NULL,                       /* get_status */
     NULL,                       /* arp_lookup */
 
     netdev_tunnel_update_flags,
 
-    netdev_tunnel_change_seq,
-
     netdev_tunnel_rx_alloc,
     netdev_tunnel_rx_construct,
     netdev_tunnel_rx_destruct,
index 25d32db..bcdc5ee 100644 (file)
@@ -226,6 +226,7 @@ netdev_unregister_provider(const char *type)
         atomic_read(&rc->ref_cnt, &ref_cnt);
         if (!ref_cnt) {
             hmap_remove(&netdev_classes, &rc->hmap_node);
+            atomic_destroy(&rc->ref_cnt);
             free(rc);
             error = 0;
         } else {
@@ -501,6 +502,13 @@ netdev_parse_name(const char *netdev_name_, char **name, char **type)
     }
 }
 
+/* Attempts to open a netdev_rx handle for obtaining packets received on
+ * 'netdev'.  On success, returns 0 and stores a nonnull 'netdev_rx *' into
+ * '*rxp'.  On failure, returns a positive errno value and stores NULL into
+ * '*rxp'.
+ *
+ * Some kinds of network devices might not support receiving packets.  This
+ * function returns EOPNOTSUPP in that case.*/
 int
 netdev_rx_open(struct netdev *netdev, struct netdev_rx **rxp)
     OVS_EXCLUDED(netdev_mutex)
@@ -532,6 +540,7 @@ netdev_rx_open(struct netdev *netdev, struct netdev_rx **rxp)
     return error;
 }
 
+/* Closes 'rx'. */
 void
 netdev_rx_close(struct netdev_rx *rx)
     OVS_EXCLUDED(netdev_mutex)
@@ -544,6 +553,29 @@ netdev_rx_close(struct netdev_rx *rx)
     }
 }
 
+/* Attempts to receive a packet from 'rx' into the tailroom of 'buffer', which
+ * must initially be empty.  If successful, returns 0 and increments
+ * 'buffer->size' by the number of bytes in the received packet, otherwise a
+ * positive errno value.
+ *
+ * Returns EAGAIN immediately if no packet is ready to be received.
+ *
+ * Returns EMSGSIZE, and discards the packet, if the received packet is longer
+ * than 'ofpbuf_tailroom(buffer)'.
+ *
+ * Implementations may make use of VLAN_HEADER_LEN bytes of tailroom to
+ * add a VLAN header which is obtained out-of-band to the packet. If
+ * this occurs then VLAN_HEADER_LEN bytes of tailroom will no longer be
+ * available for the packet, otherwise it may be used for the packet
+ * itself.
+ *
+ * It is advised that the tailroom of 'buffer' should be
+ * VLAN_HEADER_LEN bytes longer than the MTU to allow space for an
+ * out-of-band VLAN header to be added to the packet.  At the very least,
+ * 'buffer' must have at least ETH_TOTAL_MIN bytes of tailroom.
+ *
+ * This function may be set to null if it would always return EOPNOTSUPP
+ * anyhow. */
 int
 netdev_rx_recv(struct netdev_rx *rx, struct ofpbuf *buffer)
 {
@@ -552,26 +584,27 @@ netdev_rx_recv(struct netdev_rx *rx, struct ofpbuf *buffer)
     ovs_assert(buffer->size == 0);
     ovs_assert(ofpbuf_tailroom(buffer) >= ETH_TOTAL_MIN);
 
-    retval = rx->netdev->netdev_class->rx_recv(rx, buffer->data,
-                                               ofpbuf_tailroom(buffer));
-    if (retval >= 0) {
+    retval = rx->netdev->netdev_class->rx_recv(rx, buffer);
+    if (!retval) {
         COVERAGE_INC(netdev_received);
-        buffer->size += retval;
         if (buffer->size < ETH_TOTAL_MIN) {
             ofpbuf_put_zeros(buffer, ETH_TOTAL_MIN - buffer->size);
         }
         return 0;
     } else {
-        return -retval;
+        return retval;
     }
 }
 
+/* Arranges for poll_block() to wake up when a packet is ready to be received
+ * on 'rx'. */
 void
 netdev_rx_wait(struct netdev_rx *rx)
 {
     rx->netdev->netdev_class->rx_wait(rx);
 }
 
+/* Discards any packets ready to be received on 'rx'. */
 int
 netdev_rx_drain(struct netdev_rx *rx)
 {
index 4bd6d36..1463ff0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -675,16 +675,17 @@ nl_sock_drain(struct nl_sock *sock)
  * Netlink socket created with the given 'protocol', and initializes 'dump' to
  * reflect the state of the operation.
  *
- * nlmsg_len in 'msg' will be finalized to match msg->size, and nlmsg_pid will
- * be set to the Netlink socket's pid, before the message is sent.  NLM_F_DUMP
- * and NLM_F_ACK will be set in nlmsg_flags.
+ * 'request' must contain a Netlink message.  Before sending the message,
+ * nlmsg_len will be finalized to match request->size, and nlmsg_pid will be
+ * set to the Netlink socket's pid.  NLM_F_DUMP and NLM_F_ACK will be set in
+ * nlmsg_flags.
  *
  * The design of this Netlink socket library ensures that the dump is reliable.
  *
- * This function provides no status indication.  An error status for the entire
- * dump operation is provided when it is completed by calling nl_dump_done().
+ * This function provides no status indication.  nl_dump_done() provides an
+ * error status for the entire dump operation.
  *
- * The caller is responsible for destroying 'request'.
+ * The caller must eventually destroy 'request'.
  */
 void
 nl_dump_start(struct nl_dump *dump, int protocol, const struct ofpbuf *request)
index 5b77fa9..096c113 100644 (file)
@@ -205,7 +205,7 @@ odp_execute_actions__(void *dp, struct ofpbuf *packet, struct pkt_metadata *md,
 
         case OVS_ACTION_ATTR_PUSH_VLAN: {
             const struct ovs_action_push_vlan *vlan = nl_attr_get(a);
-            eth_push_vlan(packet, vlan->vlan_tci);
+            eth_push_vlan(packet, htons(ETH_TYPE_VLAN), vlan->vlan_tci);
             break;
         }
 
index 9dc687c..97262b2 100644 (file)
@@ -60,3 +60,15 @@ typedef _Atomic(int64_t)   atomic_int64_t;
     (*(ORIG) = atomic_fetch_xor_explicit(RMW, ARG, ORDER), (void) 0)
 #define atomic_and_explicit(RMW, ARG, ORIG, ORDER) \
     (*(ORIG) = atomic_fetch_and_explicit(RMW, ARG, ORDER), (void) 0)
+
+static inline void
+atomic_flag_init(volatile atomic_flag *object OVS_UNUSED)
+{
+    /* Nothing to do. */
+}
+
+static inline void
+atomic_flag_destroy(volatile atomic_flag *object OVS_UNUSED)
+{
+    /* Nothing to do. */
+}
index dbec956..7449428 100644 (file)
@@ -63,6 +63,7 @@ typedef _Atomic(int64_t)   atomic_int64_t;
 #define ATOMIC_VAR_INIT(VALUE) (VALUE)
 
 #define atomic_init(OBJECT, VALUE) __c11_atomic_init(OBJECT, VALUE)
+#define atomic_destroy(OBJECT) ((void) (OBJECT))
 
 /* Clang hard-codes these exact values internally but does not appear to
  * export any names for them. */
index c42c7ca..385d0de 100644 (file)
@@ -26,6 +26,18 @@ typedef struct {
 } atomic_flag;
 #define ATOMIC_FLAG_INIT { .b = false }
 
+static inline void
+atomic_flag_init(volatile atomic_flag *object OVS_UNUSED)
+{
+    /* Nothing to do. */
+}
+
+static inline void
+atomic_flag_destroy(volatile atomic_flag *object OVS_UNUSED)
+{
+    /* Nothing to do. */
+}
+
 static inline bool
 atomic_flag_test_and_set_explicit(volatile atomic_flag *object,
                                   memory_order order)
index 4476162..b465181 100644 (file)
@@ -150,6 +150,7 @@ int64_t locked_int64_and(struct locked_int64 *, int64_t arg);
 \f
 #define ATOMIC_VAR_INIT(VALUE) { .value = (VALUE) }
 #define atomic_init(OBJECT, VALUE) ((OBJECT)->value = (VALUE), (void) 0)
+#define atomic_destroy(OBJECT) ((void) (OBJECT))
 
 static inline void
 atomic_thread_fence(memory_order order)
@@ -238,6 +239,18 @@ typedef struct {
 } atomic_flag;
 #define ATOMIC_FLAG_INIT { false }
 
+static inline void
+atomic_flag_init(volatile atomic_flag *object OVS_UNUSED)
+{
+    /* Nothing to do. */
+}
+
+static inline void
+atomic_flag_destroy(volatile atomic_flag *object OVS_UNUSED)
+{
+    /* Nothing to do. */
+}
+
 static inline bool
 atomic_flag_test_and_set(volatile atomic_flag *object)
 {
index 52e167f..56d265f 100644 (file)
@@ -71,6 +71,7 @@ typedef enum {
 
 #define ATOMIC_VAR_INIT(VALUE) (VALUE)
 #define atomic_init(OBJECT, VALUE) (*(OBJECT) = (VALUE), (void) 0)
+#define atomic_destroy(OBJECT) ((void) (OBJECT))
 
 #define atomic_thread_fence __atomic_thread_fence
 #define atomic_signal_fence __atomic_signal_fence
index a501b82..7311135 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013 Nicira, Inc.
+ * Copyright (c) 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include "ovs-thread.h"
 
 #if OVS_ATOMIC_PTHREADS_IMPL
+void
+atomic_flag_init(volatile atomic_flag *flag_)
+{
+    atomic_flag *flag = CONST_CAST(atomic_flag *, flag_);
+
+    pthread_mutex_init(&flag->mutex, NULL);
+    atomic_flag_clear(flag_);
+}
+
+void
+atomic_flag_destroy(volatile atomic_flag *flag_)
+{
+    atomic_flag *flag = CONST_CAST(atomic_flag *, flag_);
+
+    pthread_mutex_destroy(&flag->mutex);
+}
+
 bool
 atomic_flag_test_and_set(volatile atomic_flag *flag_)
 {
index 2f47a9c..dc8f498 100644 (file)
@@ -85,6 +85,9 @@ typedef enum {
     ((OBJECT)->value = (VALUE),                         \
      pthread_mutex_init(&(OBJECT)->mutex, NULL),        \
      (void) 0)
+#define atomic_destroy(OBJECT)                  \
+    (pthread_mutex_destroy(&(OBJECT)->mutex),   \
+     (void) 0)
 
 static inline void
 atomic_thread_fence(memory_order order OVS_UNUSED)
@@ -148,6 +151,9 @@ typedef struct {
 } atomic_flag;
 #define ATOMIC_FLAG_INIT { false, PTHREAD_MUTEX_INITIALIZER }
 
+void atomic_flag_init(volatile atomic_flag *);
+void atomic_flag_destroy(volatile atomic_flag *);
+
 bool atomic_flag_test_and_set(volatile atomic_flag *);
 bool atomic_flag_test_and_set_explicit(volatile atomic_flag *, memory_order);
 
index a9ae4ae..4d43a42 100644 (file)
@@ -84,8 +84,8 @@
  * that.
  *
  *
- * Initialization
- * ==============
+ * Life Cycle
+ * ==========
  *
  * To initialize an atomic variable at its point of definition, use
  * ATOMIC_VAR_INIT:
  * ...
  *     atomic_init(&ai, 123);
  *
+ * C11 does not hav an destruction function for atomic types, but some
+ * implementations of the OVS atomics do need them.  Thus, the following
+ * function is provided for destroying non-static atomic objects (A is any
+ * atomic type):
+ *
+ *     void atomic_destroy(A *object);
+ *
+ *         Destroys 'object'.
+ *
  *
  * Barriers
  * ========
  * atomic_flag is a typedef for a type with two states, set and clear, that
  * provides atomic test-and-set functionality.
  *
+ *
+ * Life Cycle
+ * ----------
+ *
  * ATOMIC_FLAG_INIT is an initializer for atomic_flag.  The initial state is
  * "clear".
  *
+ * C11 does not have an initialization or destruction function for atomic_flag,
+ * because implementations should not need one (one may simply
+ * atomic_flag_clear() an uninitialized atomic_flag), but some implementations
+ * of the OVS atomics do need them.  Thus, the following two functions are
+ * provided for initializing and destroying non-static atomic_flags:
+ *
+ *     void atomic_flag_init(volatile atomic_flag *object);
+ *
+ *         Initializes 'object'.  The initial state is "clear".
+ *
+ *     void atomic_flag_destroy(volatile atomic_flag *object);
+ *
+ *         Destroys 'object'.
+ *
+ *
+ * Operations
+ * ----------
+ *
  * The following functions are available.
  *
  *     bool atomic_flag_test_and_set(atomic_flag *object)
     #endif
 #undef IN_OVS_ATOMIC_H
 
+/* Reference count. */
+struct ovs_refcount {
+    atomic_uint count;
+};
+
+/* Initializes 'refcount'.  The reference count is initially 1. */
+static inline void
+ovs_refcount_init(struct ovs_refcount *refcount)
+{
+    atomic_init(&refcount->count, 1);
+}
+
+/* Destroys 'refcount'. */
+static inline void
+ovs_refcount_destroy(struct ovs_refcount *refcount)
+{
+    atomic_destroy(&refcount->count);
+}
+
+/* Increments 'refcount'. */
+static inline void
+ovs_refcount_ref(struct ovs_refcount *refcount)
+{
+    unsigned int old_refcount;
+
+    atomic_add(&refcount->count, 1, &old_refcount);
+    ovs_assert(old_refcount > 0);
+}
+
+/* Decrements 'refcount' and returns the previous reference count.  Often used
+ * in this form:
+ *
+ * if (ovs_refcount_unref(&object->ref_cnt) == 1) {
+ *     // ...uninitialize object...
+ *     free(object);
+ * }
+ */
+static inline unsigned int
+ovs_refcount_unref(struct ovs_refcount *refcount)
+{
+    unsigned int old_refcount;
+
+    atomic_sub(&refcount->count, 1, &old_refcount);
+    ovs_assert(old_refcount > 0);
+    return old_refcount;
+}
+
+/* Reads and returns 'ref_count_''s current reference count.
+ *
+ * Rarely useful. */
+static inline unsigned int
+ovs_refcount_read(const struct ovs_refcount *refcount_)
+{
+    struct ovs_refcount *refcount
+        = CONST_CAST(struct ovs_refcount *, refcount_);
+    unsigned int count;
+
+    atomic_read(&refcount->count, &count);
+    return count;
+}
+
 #endif /* ovs-atomic.h */
index aa3ad15..a20b2fd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013 Nicira, Inc.
+ * Copyright (c) 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include "compiler.h"
+#include "hash.h"
 #include "poll-loop.h"
 #include "socket-util.h"
 #include "util.h"
@@ -133,6 +134,7 @@ XPTHREAD_FUNC2(pthread_join, pthread_t, void **);
 
 typedef void destructor_func(void *);
 XPTHREAD_FUNC2(pthread_key_create, pthread_key_t *, destructor_func *);
+XPTHREAD_FUNC1(pthread_key_delete, pthread_key_t);
 XPTHREAD_FUNC2(pthread_setspecific, pthread_key_t, const void *);
 
 static void
@@ -310,6 +312,84 @@ may_fork(void)
     return !must_not_fork;
 }
 \f
+/* ovsthread_counter.
+ *
+ * We implement the counter as an array of N_COUNTERS individual counters, each
+ * with its own lock.  Each thread uses one of the counters chosen based on a
+ * hash of the thread's ID, the idea being that, statistically, different
+ * threads will tend to use different counters and therefore avoid
+ * interfering with each other.
+ *
+ * Undoubtedly, better implementations are possible. */
+
+/* Basic counter structure. */
+struct ovsthread_counter__ {
+    struct ovs_mutex mutex;
+    unsigned long long int value;
+};
+
+/* Pad the basic counter structure to 64 bytes to avoid cache line
+ * interference. */
+struct ovsthread_counter {
+    struct ovsthread_counter__ c;
+    char pad[ROUND_UP(sizeof(struct ovsthread_counter__), 64)
+             - sizeof(struct ovsthread_counter__)];
+};
+
+#define N_COUNTERS 16
+
+struct ovsthread_counter *
+ovsthread_counter_create(void)
+{
+    struct ovsthread_counter *c;
+    int i;
+
+    c = xmalloc(N_COUNTERS * sizeof *c);
+    for (i = 0; i < N_COUNTERS; i++) {
+        ovs_mutex_init(&c[i].c.mutex);
+        c[i].c.value = 0;
+    }
+    return c;
+}
+
+void
+ovsthread_counter_destroy(struct ovsthread_counter *c)
+{
+    if (c) {
+        int i;
+
+        for (i = 0; i < N_COUNTERS; i++) {
+            ovs_mutex_destroy(&c[i].c.mutex);
+        }
+        free(c);
+    }
+}
+
+void
+ovsthread_counter_inc(struct ovsthread_counter *c, unsigned long long int n)
+{
+    c = &c[hash_int(ovsthread_id_self(), 0) % N_COUNTERS];
+
+    ovs_mutex_lock(&c->c.mutex);
+    c->c.value += n;
+    ovs_mutex_unlock(&c->c.mutex);
+}
+
+unsigned long long int
+ovsthread_counter_read(const struct ovsthread_counter *c)
+{
+    unsigned long long int sum;
+    int i;
+
+    sum = 0;
+    for (i = 0; i < N_COUNTERS; i++) {
+        ovs_mutex_lock(&c[i].c.mutex);
+        sum += c[i].c.value;
+        ovs_mutex_unlock(&c[i].c.mutex);
+    }
+    return sum;
+}
+\f
 /* Parses /proc/cpuinfo for the total number of physical cores on this system
  * across all CPU packages, not counting hyper-threads.
  *
@@ -387,4 +467,194 @@ count_cpu_cores(void)
 
     return n_cores > 0 ? n_cores : 0;
 }
+\f
+/* ovsthread_key. */
+
+#define L1_SIZE 1024
+#define L2_SIZE 1024
+#define MAX_KEYS (L1_SIZE * L2_SIZE)
+
+/* A piece of thread-specific data. */
+struct ovsthread_key {
+    struct list list_node;      /* In 'inuse_keys' or 'free_keys'. */
+    void (*destructor)(void *); /* Called at thread exit. */
+
+    /* Indexes into the per-thread array in struct ovsthread_key_slots.
+     * This key's data is stored in p1[index / L2_SIZE][index % L2_SIZE]. */
+    unsigned int index;
+};
+
+/* Per-thread data structure. */
+struct ovsthread_key_slots {
+    struct list list_node;      /* In 'slots_list'. */
+    void **p1[L1_SIZE];
+};
+
+/* Contains "struct ovsthread_key_slots *". */
+static pthread_key_t tsd_key;
+
+/* Guards data structures below. */
+static struct ovs_mutex key_mutex = OVS_MUTEX_INITIALIZER;
+
+/* 'inuse_keys' holds "struct ovsthread_key"s that have been created and not
+ * yet destroyed.
+ *
+ * 'free_keys' holds "struct ovsthread_key"s that have been deleted and are
+ * ready for reuse.  (We keep them around only to be able to easily locate
+ * free indexes.)
+ *
+ * Together, 'inuse_keys' and 'free_keys' hold an ovsthread_key for every index
+ * from 0 to n_keys - 1, inclusive. */
+static struct list inuse_keys OVS_GUARDED_BY(key_mutex)
+    = LIST_INITIALIZER(&inuse_keys);
+static struct list free_keys OVS_GUARDED_BY(key_mutex)
+    = LIST_INITIALIZER(&free_keys);
+static unsigned int n_keys OVS_GUARDED_BY(key_mutex);
+
+/* All existing struct ovsthread_key_slots. */
+static struct list slots_list OVS_GUARDED_BY(key_mutex)
+    = LIST_INITIALIZER(&slots_list);
+
+static void *
+clear_slot(struct ovsthread_key_slots *slots, unsigned int index)
+{
+    void **p2 = slots->p1[index / L2_SIZE];
+    if (p2) {
+        void **valuep = &p2[index % L2_SIZE];
+        void *value = *valuep;
+        *valuep = NULL;
+        return value;
+    } else {
+        return NULL;
+    }
+}
+
+static void
+ovsthread_key_destruct__(void *slots_)
+{
+    struct ovsthread_key_slots *slots = slots_;
+    struct ovsthread_key *key;
+    unsigned int n;
+    int i;
+
+    ovs_mutex_lock(&key_mutex);
+    list_remove(&slots->list_node);
+    LIST_FOR_EACH (key, list_node, &inuse_keys) {
+        void *value = clear_slot(slots, key->index);
+        if (value && key->destructor) {
+            key->destructor(value);
+        }
+    }
+    n = n_keys;
+    ovs_mutex_unlock(&key_mutex);
+
+    for (i = 0; i < n / L2_SIZE; i++) {
+        free(slots->p1[i]);
+    }
+    free(slots);
+}
+
+/* Initializes '*keyp' as a thread-specific data key.  The data items are
+ * initially null in all threads.
+ *
+ * If a thread exits with non-null data, then 'destructor', if nonnull, will be
+ * called passing the final data value as its argument.  'destructor' must not
+ * call any thread-specific data functions in this API.
+ *
+ * This function is similar to xpthread_key_create(). */
+void
+ovsthread_key_create(ovsthread_key_t *keyp, void (*destructor)(void *))
+{
+    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
+    struct ovsthread_key *key;
+
+    if (ovsthread_once_start(&once)) {
+        xpthread_key_create(&tsd_key, ovsthread_key_destruct__);
+        ovsthread_once_done(&once);
+    }
+
+    ovs_mutex_lock(&key_mutex);
+    if (list_is_empty(&free_keys)) {
+        key = xmalloc(sizeof *key);
+        key->index = n_keys++;
+        if (key->index >= MAX_KEYS) {
+            abort();
+        }
+    } else {
+        key = CONTAINER_OF(list_pop_back(&free_keys),
+                            struct ovsthread_key, list_node);
+    }
+    list_push_back(&inuse_keys, &key->list_node);
+    key->destructor = destructor;
+    ovs_mutex_unlock(&key_mutex);
+
+    *keyp = key;
+}
+
+/* Frees 'key'.  The destructor supplied to ovsthread_key_create(), if any, is
+ * not called.
+ *
+ * This function is similar to xpthread_key_delete(). */
+void
+ovsthread_key_delete(ovsthread_key_t key)
+{
+    struct ovsthread_key_slots *slots;
+
+    ovs_mutex_lock(&key_mutex);
+
+    /* Move 'key' from 'inuse_keys' to 'free_keys'. */
+    list_remove(&key->list_node);
+    list_push_back(&free_keys, &key->list_node);
+
+    /* Clear this slot in all threads. */
+    LIST_FOR_EACH (slots, list_node, &slots_list) {
+        clear_slot(slots, key->index);
+    }
+
+    ovs_mutex_unlock(&key_mutex);
+}
+
+static void **
+ovsthread_key_lookup__(const struct ovsthread_key *key)
+{
+    struct ovsthread_key_slots *slots;
+    void **p2;
+
+    slots = pthread_getspecific(tsd_key);
+    if (!slots) {
+        slots = xzalloc(sizeof *slots);
+
+        ovs_mutex_lock(&key_mutex);
+        pthread_setspecific(tsd_key, slots);
+        list_push_back(&slots_list, &slots->list_node);
+        ovs_mutex_unlock(&key_mutex);
+    }
+
+    p2 = slots->p1[key->index / L2_SIZE];
+    if (!p2) {
+        p2 = xzalloc(L2_SIZE * sizeof *p2);
+        slots->p1[key->index / L2_SIZE] = p2;
+    }
+
+    return &p2[key->index % L2_SIZE];
+}
+
+/* Sets the value of thread-specific data item 'key', in the current thread, to
+ * 'value'.
+ *
+ * This function is similar to pthread_setspecific(). */
+void
+ovsthread_setspecific(ovsthread_key_t key, const void *value)
+{
+    *ovsthread_key_lookup__(key) = CONST_CAST(void *, value);
+}
+
+/* Returns the value of thread-specific data item 'key' in the current thread.
+ *
+ * This function is similar to pthread_getspecific(). */
+void *
+ovsthread_getspecific(ovsthread_key_t key)
+{
+    return *ovsthread_key_lookup__(key);
+}
 #endif
index b6d973f..8cf2ecc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013 Nicira, Inc.
+ * Copyright (c) 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -127,6 +127,7 @@ void xpthread_cond_broadcast(pthread_cond_t *);
 #endif
 
 void xpthread_key_create(pthread_key_t *, void (*destructor)(void *));
+void xpthread_key_delete(pthread_key_t);
 void xpthread_setspecific(pthread_key_t, const void *);
 
 void xpthread_create(pthread_t *, pthread_attr_t *, void *(*)(void *), void *);
@@ -134,14 +135,21 @@ void xpthread_join(pthread_t, void **);
 \f
 /* Per-thread data.
  *
- * Multiple forms of per-thread data exist, each with its own pluses and
- * minuses:
+ *
+ * Standard Forms
+ * ==============
+ *
+ * Multiple forms of standard per-thread data exist, each with its own pluses
+ * and minuses.  In general, if one of these forms is appropriate, then it's a
+ * good idea to use it:
  *
  *     - POSIX per-thread data via pthread_key_t is portable to any pthreads
  *       implementation, and allows a destructor function to be defined.  It
  *       only (directly) supports per-thread pointers, which are always
  *       initialized to NULL.  It requires once-only allocation of a
- *       pthread_key_t value.  It is relatively slow.
+ *       pthread_key_t value.  It is relatively slow.  Typically few
+ *       "pthread_key_t"s are available (POSIX requires only at least 128,
+ *       glibc supplies only 1024).
  *
  *     - The thread_local feature newly defined in C11 <threads.h> works with
  *       any data type and initializer, and it is fast.  thread_local does not
@@ -149,7 +157,8 @@ void xpthread_join(pthread_t, void **);
  *       define what happens if one attempts to access a thread_local object
  *       from a thread other than the one to which that object belongs.  There
  *       is no provision to call a user-specified destructor when a thread
- *       ends.
+ *       ends.  Typical implementations allow for an arbitrary amount of
+ *       thread_local storage, but statically allocated only.
  *
  *     - The __thread keyword is a GCC extension similar to thread_local but
  *       with a longer history.  __thread is not portable to every GCC version
@@ -166,6 +175,25 @@ void xpthread_join(pthread_t, void **);
  * needs key allocation?    yes                no                 no
  * arbitrary initializer?    no               yes                yes
  * cross-thread access?     yes                no                yes
+ * amount available?        few            arbitrary         arbitrary
+ * dynamically allocated?   yes                no                 no
+ *
+ *
+ * Extensions
+ * ==========
+ *
+ * OVS provides some extensions and wrappers:
+ *
+ *     - In a situation where the performance of thread_local or __thread is
+ *       desirable, but portability is required, DEFINE_STATIC_PER_THREAD_DATA
+ *       and DECLARE_EXTERN_PER_THREAD_DATA/DEFINE_EXTERN_PER_THREAD_DATA may
+ *       be appropriate (see below).
+ *
+ *     - DEFINE_PER_THREAD_MALLOCED_DATA can be convenient for simple
+ *       per-thread malloc()'d buffers.
+ *
+ *     - struct ovs_tsd provides an alternative to pthread_key_t that isn't
+ *       limited to a small number of keys.
  */
 
 /* For static data, use this macro in a source file:
@@ -402,6 +430,31 @@ void xpthread_join(pthread_t, void **);
         NAME##_init();                                  \
         return NAME##_set_unsafe(value);                \
     }
+
+/* Dynamically allocated thread-specific data with lots of slots.
+ *
+ * pthread_key_t can provide as few as 128 pieces of thread-specific data (even
+ * glibc is limited to 1,024).  Thus, one must be careful to allocate only a
+ * few keys globally.  One cannot, for example, allocate a key for every
+ * instance of a data structure if there might be an arbitrary number of those
+ * data structures.
+ *
+ * This API is similar to the pthread one (simply search and replace pthread_
+ * by ovsthread_) but it a much larger limit that can be raised if necessary
+ * (by recompiling).  Thus, one may more freely use this form of
+ * thread-specific data.
+ *
+ * Compared to pthread_key_t, ovsthread_key_t has the follow limitations:
+ *
+ *    - Destructors must not access thread-specific data (via ovsthread_key).
+ */
+typedef struct ovsthread_key *ovsthread_key_t;
+
+void ovsthread_key_create(ovsthread_key_t *, void (*destructor)(void *));
+void ovsthread_key_delete(ovsthread_key_t);
+
+void ovsthread_setspecific(ovsthread_key_t, const void *);
+void *ovsthread_getspecific(ovsthread_key_t);
 \f
 /* Convenient once-only execution.
  *
@@ -494,6 +547,25 @@ ovsthread_id_self(void)
     return *ovsthread_id_get();
 }
 \f
+/* Simulated global counter.
+ *
+ * Incrementing such a counter is meant to be cheaper than incrementing a
+ * global counter protected by a lock.  It is probably more expensive than
+ * incrementing a truly thread-local variable, but such a variable has no
+ * straightforward way to get the sum.
+ *
+ *
+ * Thread-safety
+ * =============
+ *
+ * Fully thread-safe. */
+
+struct ovsthread_counter *ovsthread_counter_create(void);
+void ovsthread_counter_destroy(struct ovsthread_counter *);
+void ovsthread_counter_inc(struct ovsthread_counter *, unsigned long long int);
+unsigned long long int ovsthread_counter_read(
+    const struct ovsthread_counter *);
+\f
 void assert_single_threaded_at(const char *where);
 #define assert_single_threaded() assert_single_threaded_at(SOURCE_LOCATOR)
 
index d87aa8e..0d63841 100644 (file)
@@ -176,7 +176,7 @@ compose_rarp(struct ofpbuf *b, const uint8_t eth_src[ETH_ADDR_LEN])
  *
  * Also sets 'packet->l2' to point to the new Ethernet header. */
 void
-eth_push_vlan(struct ofpbuf *packet, ovs_be16 tci)
+eth_push_vlan(struct ofpbuf *packet, ovs_be16 tpid, ovs_be16 tci)
 {
     struct eth_header *eh = packet->data;
     struct vlan_eth_header *veh;
@@ -185,7 +185,7 @@ eth_push_vlan(struct ofpbuf *packet, ovs_be16 tci)
     struct vlan_eth_header tmp;
     memcpy(tmp.veth_dst, eh->eth_dst, ETH_ADDR_LEN);
     memcpy(tmp.veth_src, eh->eth_src, ETH_ADDR_LEN);
-    tmp.veth_type = htons(ETH_TYPE_VLAN);
+    tmp.veth_type = tpid;
     tmp.veth_tci = tci & htons(~VLAN_CFI);
     tmp.veth_next_type = eh->eth_type;
 
index 63873b0..8e21fa8 100644 (file)
@@ -151,7 +151,7 @@ bool eth_addr_from_string(const char *, uint8_t ea[ETH_ADDR_LEN]);
 
 void compose_rarp(struct ofpbuf *, const uint8_t eth_src[ETH_ADDR_LEN]);
 
-void eth_push_vlan(struct ofpbuf *, ovs_be16 tci);
+void eth_push_vlan(struct ofpbuf *, ovs_be16 tpid, ovs_be16 tci);
 void eth_pop_vlan(struct ofpbuf *);
 
 void set_ethertype(struct ofpbuf *packet, ovs_be16 eth_type);
index 5e3618b..abd44d1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include "socket-util.h"
 #include "timeval.h"
 #include "vlog.h"
+#include "hmap.h"
+#include "hash.h"
 
 VLOG_DEFINE_THIS_MODULE(poll_loop);
 
 COVERAGE_DEFINE(poll_fd_wait);
 COVERAGE_DEFINE(poll_zero_timeout);
 
+struct poll_node {
+    struct hmap_node hmap_node;
+    struct pollfd pollfd;       /* Events to pass to time_poll(). */
+    HANDLE wevent;              /* Events for WaitForMultipleObjects(). */
+    const char *where;          /* Where poll_node was created. */
+};
+
 struct poll_loop {
     /* All active poll waiters. */
-    struct pollfd *pollfds;     /* Events to pass to poll(). */
-    const char **where;         /* Where each pollfd was created. */
-    size_t n_waiters;           /* Number of elems in 'where' and 'pollfds'. */
-    size_t allocated_waiters;   /* Allocated elems in 'where' and 'pollfds'. */
+    struct hmap poll_nodes;
 
     /* Time at which to wake up the next call to poll_block(), LLONG_MIN to
      * wake up immediately, or LLONG_MAX to wait forever. */
@@ -51,35 +57,68 @@ struct poll_loop {
 
 static struct poll_loop *poll_loop(void);
 
-/* Registers 'fd' as waiting for the specified 'events' (which should be POLLIN
- * or POLLOUT or POLLIN | POLLOUT).  The following call to poll_block() will
- * wake up when 'fd' becomes ready for one or more of the requested events.
+/* Look up the node with same fd and wevent. */
+static struct poll_node *
+find_poll_node(struct poll_loop *loop, int fd, uint32_t wevent)
+{
+    struct poll_node *node;
+
+    HMAP_FOR_EACH_WITH_HASH (node, hmap_node, hash_2words(fd, wevent),
+                             &loop->poll_nodes) {
+        if (node->pollfd.fd == fd && node->wevent == wevent) {
+            return node;
+        }
+    }
+    return NULL;
+}
+
+/* On Unix based systems:
  *
- * The event registration is one-shot: only the following call to poll_block()
- * is affected.  The event will need to be re-registered after poll_block() is
- * called if it is to persist.
+ *     Registers 'fd' as waiting for the specified 'events' (which should be
+ *     POLLIN or POLLOUT or POLLIN | POLLOUT).  The following call to
+ *     poll_block() will wake up when 'fd' becomes ready for one or more of the
+ *     requested events.  the 'fd's are given to poll() function later.
+ *
+ * On Windows system:
+ *
+ *     Register 'wevent' handle for the specified 'events'.  These wevents are
+ *     given to the handleMultipleObjects() to be polled.  The event
+ *     registration is one-shot: only the following call to poll_block() is
+ *     affected.  The event will need to be re-registered after poll_block() is
+ *     called if it is to persist.
  *
  * ('where' is used in debug logging.  Commonly one would use poll_fd_wait() to
  * automatically provide the caller's source file and line number for
  * 'where'.) */
 void
-poll_fd_wait_at(int fd, short int events, const char *where)
+poll_fd_wait_at(int fd, HANDLE wevent, short int events, const char *where)
 {
     struct poll_loop *loop = poll_loop();
+    struct poll_node *node;
 
     COVERAGE_INC(poll_fd_wait);
-    if (loop->n_waiters >= loop->allocated_waiters) {
-        loop->where = x2nrealloc(loop->where, &loop->allocated_waiters,
-                                 sizeof *loop->where);
-        loop->pollfds = xrealloc(loop->pollfds,
-                                 (loop->allocated_waiters
-                                  * sizeof *loop->pollfds));
+
+#ifdef _WIN32
+    /* Null event cannot be polled. */
+    if (wevent == 0) {
+        VLOG_ERR("No event to wait fd %d", fd);
+        return;
     }
+#endif
 
-    loop->where[loop->n_waiters] = where;
-    loop->pollfds[loop->n_waiters].fd = fd;
-    loop->pollfds[loop->n_waiters].events = events;
-    loop->n_waiters++;
+    /* Check for duplicate.  If found, "or" the event. */
+    node = find_poll_node(loop, fd, wevent);
+    if (node) {
+        node->pollfd.events |= events;
+    } else {
+        node = xzalloc(sizeof *node);
+        hmap_insert(&loop->poll_nodes, &node->hmap_node,
+                    hash_2words(fd, wevent));
+        node->pollfd.fd = fd;
+        node->pollfd.events = events;
+        node->wevent = wevent;
+        node->where = where;
+    }
 }
 
 /* Causes the following call to poll_block() to block for no more than 'msec'
@@ -208,6 +247,17 @@ log_wakeup(const char *where, const struct pollfd *pollfd, int timeout)
     ds_destroy(&s);
 }
 
+static void
+free_poll_nodes(struct poll_loop *loop)
+{
+    struct poll_node *node, *next;
+
+    HMAP_FOR_EACH_SAFE (node, next, hmap_node, &loop->poll_nodes) {
+        hmap_remove(&loop->poll_nodes, &node->hmap_node);
+        free(node);
+    }
+}
+
 /* Blocks until one or more of the events registered with poll_fd_wait()
  * occurs, or until the minimum duration registered with poll_timer_wait()
  * elapses, or not at all if poll_immediate_wake() has been called. */
@@ -215,8 +265,12 @@ void
 poll_block(void)
 {
     struct poll_loop *loop = poll_loop();
+    struct poll_node *node;
+    struct pollfd *pollfds;
+    HANDLE *wevents = NULL;
     int elapsed;
     int retval;
+    int i;
 
     /* Register fatal signal events before actually doing any real work for
      * poll_block. */
@@ -227,7 +281,23 @@ poll_block(void)
     }
 
     timewarp_wait();
-    retval = time_poll(loop->pollfds, loop->n_waiters,
+    pollfds = xmalloc(hmap_count(&loop->poll_nodes) * sizeof *pollfds);
+
+#ifdef _WIN32
+    wevents = xmalloc(hmap_count(&loop->poll_nodes) * sizeof *wevents);
+#endif
+
+    /* Populate with all the fds and events. */
+    i = 0;
+    HMAP_FOR_EACH (node, hmap_node, &loop->poll_nodes) {
+        pollfds[i] = node->pollfd;
+#ifdef _WIN32
+        wevents[i] = node->wevent;
+#endif
+        i++;
+    }
+
+    retval = time_poll(pollfds, hmap_count(&loop->poll_nodes), wevents,
                        loop->timeout_when, &elapsed);
     if (retval < 0) {
         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
@@ -235,18 +305,20 @@ poll_block(void)
     } else if (!retval) {
         log_wakeup(loop->timeout_where, NULL, elapsed);
     } else if (get_cpu_usage() > 50 || VLOG_IS_DBG_ENABLED()) {
-        size_t i;
-
-        for (i = 0; i < loop->n_waiters; i++) {
-            if (loop->pollfds[i].revents) {
-                log_wakeup(loop->where[i], &loop->pollfds[i], 0);
+        i = 0;
+        HMAP_FOR_EACH (node, hmap_node, &loop->poll_nodes) {
+            if (pollfds[i].revents) {
+                log_wakeup(node->where, &pollfds[i], 0);
             }
+            i++;
         }
     }
 
+    free_poll_nodes(loop);
     loop->timeout_when = LLONG_MAX;
     loop->timeout_where = NULL;
-    loop->n_waiters = 0;
+    free(pollfds);
+    free(wevents);
 
     /* Handle any pending signals before doing anything else. */
     fatal_signal_run();
@@ -259,8 +331,8 @@ free_poll_loop(void *loop_)
 {
     struct poll_loop *loop = loop_;
 
-    free(loop->pollfds);
-    free(loop->where);
+    free_poll_nodes(loop);
+    hmap_destroy(&loop->poll_nodes);
     free(loop);
 }
 
@@ -279,6 +351,7 @@ poll_loop(void)
     loop = pthread_getspecific(key);
     if (!loop) {
         loop = xzalloc(sizeof *loop);
+        hmap_init(&loop->poll_nodes);
         xpthread_setspecific(key, loop);
     }
     return loop;
index 0397853..ae4c0c0 100644 (file)
@@ -50,8 +50,12 @@ extern "C" {
  * caller to supply a location explicitly, which is useful if the caller's own
  * caller would be more useful in log output.  See timer_wait_at() for an
  * example. */
-void poll_fd_wait_at(int fd, short int events, const char *where);
-#define poll_fd_wait(fd, events) poll_fd_wait_at(fd, events, SOURCE_LOCATOR)
+void poll_fd_wait_at(int fd, HANDLE wevent, short int events, const char *where);
+#ifndef _WIN32
+#define poll_fd_wait(fd, events) poll_fd_wait_at(fd, 0, events, SOURCE_LOCATOR)
+#else
+#define poll_fd_wait_event(fd, wevent, events) poll_fd_wait_at(fd, wevent, events, SOURCE_LOCATOR)
+#endif
 
 void poll_timer_wait_at(long long int msec, const char *where);
 #define poll_timer_wait(msec) poll_timer_wait_at(msec, SOURCE_LOCATOR)
index 3e5a67a..e6fc9a7 100644 (file)
@@ -198,6 +198,10 @@ inline static void putString(SFLReceiver *receiver, SFLString *s)
     putNet32(receiver, s->len);
     memcpy(receiver->sampleCollector.datap, s->str, s->len);
     receiver->sampleCollector.datap += (s->len + 3) / 4; /* pad to 4-byte boundary */
+    if ((s->len % 4) != 0){
+        u_int8_t padding = 4 - (s->len % 4);
+        memset(((u_int8_t*)receiver->sampleCollector.datap)-padding, 0, padding);
+    }
 }
 
 inline static u_int32_t stringEncodingLength(SFLString *s) {
index 8140263..e4ddf3c 100644 (file)
--- a/lib/stp.c
+++ b/lib/stp.c
@@ -143,7 +143,7 @@ struct stp {
     void (*send_bpdu)(struct ofpbuf *bpdu, int port_no, void *aux);
     void *aux;
 
-    atomic_int ref_cnt;
+    struct ovs_refcount ref_cnt;
 };
 
 static struct ovs_mutex mutex;
@@ -306,7 +306,7 @@ stp_create(const char *name, stp_identifier bridge_id,
         p->path_cost = 19;      /* Recommended default for 100 Mb/s link. */
         stp_initialize_port(p, STP_DISABLED);
     }
-    atomic_init(&stp->ref_cnt, 1);
+    ovs_refcount_init(&stp->ref_cnt);
 
     list_push_back(all_stps, &stp->node);
     ovs_mutex_unlock(&mutex);
@@ -318,9 +318,7 @@ stp_ref(const struct stp *stp_)
 {
     struct stp *stp = CONST_CAST(struct stp *, stp_);
     if (stp) {
-        int orig;
-        atomic_add(&stp->ref_cnt, 1, &orig);
-        ovs_assert(orig > 0);
+        ovs_refcount_ref(&stp->ref_cnt);
     }
     return stp;
 }
@@ -329,19 +327,12 @@ stp_ref(const struct stp *stp_)
 void
 stp_unref(struct stp *stp)
 {
-    int orig;
-
-    if (!stp) {
-        return;
-    }
-
-    atomic_sub(&stp->ref_cnt, 1, &orig);
-    ovs_assert(orig > 0);
-    if (orig == 1) {
+    if (stp && ovs_refcount_unref(&stp->ref_cnt) == 1) {
         ovs_mutex_lock(&mutex);
         list_remove(&stp->node);
         ovs_mutex_unlock(&mutex);
         free(stp->name);
+        ovs_refcount_destroy(&stp->ref_cnt);
         free(stp);
     }
 }
index 5d01708..691cf74 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -232,12 +232,12 @@ time_alarm(unsigned int secs)
  *
  * Stores the number of milliseconds elapsed during poll in '*elapsed'. */
 int
-time_poll(struct pollfd *pollfds, int n_pollfds, long long int timeout_when,
-          int *elapsed)
+time_poll(struct pollfd *pollfds, int n_pollfds, HANDLE *handles OVS_UNUSED,
+          long long int timeout_when, int *elapsed)
 {
     long long int *last_wakeup = last_wakeup_get();
     long long int start;
-    int retval;
+    int retval = 0;
 
     time_init();
     coverage_clear();
@@ -261,10 +261,25 @@ time_poll(struct pollfd *pollfds, int n_pollfds, long long int timeout_when,
             time_left = timeout_when - now;
         }
 
+#ifndef _WIN32
         retval = poll(pollfds, n_pollfds, time_left);
         if (retval < 0) {
             retval = -errno;
         }
+#else
+        if (n_pollfds > MAXIMUM_WAIT_OBJECTS) {
+            VLOG_ERR("Cannot handle more than maximum wait objects\n");
+        } else if (n_pollfds != 0) {
+            retval = WaitForMultipleObjects(n_pollfds, handles, FALSE,
+                                            time_left);
+        }
+        if (retval < 0) {
+            /* XXX This will be replace by a win error to errno
+               conversion function */
+            retval = -WSAGetLastError();
+            retval = -EINVAL;
+        }
+#endif
 
         if (deadline <= time_msec()) {
             fatal_signal_handler(SIGALRM);
index 1bbfd5c..c207f23 100644 (file)
@@ -52,8 +52,8 @@ long long int time_wall_msec(void);
 void time_timespec(struct timespec *);
 void time_wall_timespec(struct timespec *);
 void time_alarm(unsigned int secs);
-int time_poll(struct pollfd *, int n_pollfds, long long int timeout_when,
-              int *elapsed);
+int time_poll(struct pollfd *, int n_pollfds, HANDLE *handles,
+              long long int timeout_when, int *elapsed);
 
 long long int timespec_to_msec(const struct timespec *);
 long long int timeval_to_msec(const struct timeval *);
index 984ab45..0ebf085 100644 (file)
@@ -373,11 +373,18 @@ void
 set_program_name__(const char *argv0, const char *version, const char *date,
                    const char *time)
 {
+#ifdef _WIN32
+    char *basename;
+    size_t max_len = strlen(argv0) + 1;
+    basename = xmalloc(max_len);
+    _splitpath_s(argv0, NULL, 0, NULL, 0, basename, max_len, NULL, 0);
+    assert_single_threaded();
+    program_name = basename;
+#else
     const char *slash = strrchr(argv0, '/');
-
     assert_single_threaded();
-
     program_name = slash ? slash + 1 : argv0;
+#endif
 
     free(program_version);
 
index ee7e96a..c0af6d4 100644 (file)
@@ -1,6 +1,6 @@
 # -*- autoconf -*-
 
-# Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+# Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -242,21 +242,6 @@ AC_DEFUN([OVS_CHECK_DOT],
      fi])
    AM_CONDITIONAL([HAVE_DOT], [test "$ovs_cv_dot" = yes])])
 
-dnl Checks for pyuic4.
-AC_DEFUN([OVS_CHECK_PYUIC4],
-  [AC_CACHE_CHECK(
-    [for pyuic4],
-    [ovs_cv_pyuic4],
-    [if (pyuic4 --version) >/dev/null 2>&1; then
-       ovs_cv_pyuic4=pyuic4
-     else
-       ovs_cv_pyuic4=no
-     fi])
-   AM_MISSING_PROG([PYUIC4], [pyuic4])
-   if test $ovs_cv_pyuic4 != no; then
-     PYUIC4=$ovs_cv_pyuic4
-   fi])
-
 dnl Checks whether $PYTHON supports the module given as $1
 AC_DEFUN([OVS_CHECK_PYTHON_MODULE],
   [AC_REQUIRE([OVS_CHECK_PYTHON])
@@ -275,30 +260,6 @@ sys.exit(0)' >&AS_MESSAGE_LOG_FD 2>&1; then
         fi
       fi])])
 
-dnl Checks for Python modules needed by ovsdbmonitor.
-AC_DEFUN([OVS_CHECK_OVSDBMONITOR],
-  [OVS_CHECK_PYTHON_MODULE([PySide.QtCore])
-   OVS_CHECK_PYTHON_MODULE([PyQt4.QtCore])
-   OVS_CHECK_PYTHON_MODULE([twisted.conch.ssh])
-   OVS_CHECK_PYTHON_MODULE([twisted.internet])
-   OVS_CHECK_PYTHON_MODULE([twisted.application])
-   OVS_CHECK_PYTHON_MODULE([json])
-   OVS_CHECK_PYTHON_MODULE([zope.interface])
-   if (test $ovs_cv_py_PySide_QtCore = yes \
-       || test $ovs_cv_py_PyQt4_QtCore = yes) \
-      && test $ovs_cv_py_twisted_conch_ssh = yes \
-      && test $ovs_cv_py_twisted_internet = yes \
-      && test $ovs_cv_py_twisted_application = yes \
-      && test $ovs_cv_py_json = yes \
-      && test $ovs_cv_py_zope_interface = yes; then
-     BUILD_OVSDBMONITOR=yes
-   else
-     BUILD_OVSDBMONITOR=no
-   fi
-   AC_MSG_CHECKING([whether to build ovsdbmonitor])
-   AC_MSG_RESULT([$BUILD_OVSDBMONITOR])
-   AM_CONDITIONAL([BUILD_OVSDBMONITOR], [test $BUILD_OVSDBMONITOR = yes])])
-
 dnl Checks for missing python modules at build time
 AC_DEFUN([OVS_CHECK_PYTHON_COMPAT],
   [OVS_CHECK_PYTHON_MODULE([uuid])
index ff050f1..b4d9487 100644 (file)
@@ -103,7 +103,7 @@ struct bond {
     long long int next_fake_iface_update; /* LLONG_MAX if disabled. */
     bool lacp_fallback_ab; /* Fallback to active-backup on LACP failure. */
 
-    atomic_int ref_cnt;
+    struct ovs_refcount ref_cnt;
 };
 
 static struct ovs_rwlock rwlock = OVS_RWLOCK_INITIALIZER;
@@ -181,7 +181,7 @@ bond_create(const struct bond_settings *s)
     bond = xzalloc(sizeof *bond);
     hmap_init(&bond->slaves);
     bond->next_fake_iface_update = LLONG_MAX;
-    atomic_init(&bond->ref_cnt, 1);
+    ovs_refcount_init(&bond->ref_cnt);
 
     bond_reconfigure(bond, s);
     return bond;
@@ -193,9 +193,7 @@ bond_ref(const struct bond *bond_)
     struct bond *bond = CONST_CAST(struct bond *, bond_);
 
     if (bond) {
-        int orig;
-        atomic_add(&bond->ref_cnt, 1, &orig);
-        ovs_assert(orig > 0);
+        ovs_refcount_ref(&bond->ref_cnt);
     }
     return bond;
 }
@@ -205,15 +203,8 @@ void
 bond_unref(struct bond *bond)
 {
     struct bond_slave *slave, *next_slave;
-    int orig;
 
-    if (!bond) {
-        return;
-    }
-
-    atomic_sub(&bond->ref_cnt, 1, &orig);
-    ovs_assert(orig > 0);
-    if (orig != 1) {
+    if (!bond || ovs_refcount_unref(&bond->ref_cnt) != 1) {
         return;
     }
 
@@ -231,6 +222,7 @@ bond_unref(struct bond *bond)
 
     free(bond->hash);
     free(bond->name);
+    ovs_refcount_destroy(&bond->ref_cnt);
     free(bond);
 }
 
@@ -549,7 +541,7 @@ bond_compose_learning_packet(struct bond *bond,
     packet = ofpbuf_new(0);
     compose_rarp(packet, eth_src);
     if (vlan) {
-        eth_push_vlan(packet, htons(vlan));
+        eth_push_vlan(packet, htons(ETH_TYPE_VLAN), htons(vlan));
     }
 
     *port_aux = slave->aux;
index ea79795..b7c16d2 100644 (file)
@@ -454,7 +454,7 @@ static void add_controller(struct connmgr *, const char *target, uint8_t dscp,
     OVS_REQUIRES(ofproto_mutex);
 static struct ofconn *find_controller_by_target(struct connmgr *,
                                                 const char *target);
-static void update_fail_open(struct connmgr *);
+static void update_fail_open(struct connmgr *) OVS_EXCLUDED(ofproto_mutex);
 static int set_pvconns(struct pvconn ***pvconnsp, size_t *n_pvconnsp,
                        const struct sset *);
 
@@ -771,6 +771,7 @@ update_in_band_remotes(struct connmgr *mgr)
 
 static void
 update_fail_open(struct connmgr *mgr)
+    OVS_EXCLUDED(ofproto_mutex)
 {
     if (connmgr_has_controllers(mgr)
         && mgr->fail_mode == OFPROTO_FAIL_STANDALONE) {
index bae9dca..9ac80b6 100644 (file)
@@ -182,6 +182,7 @@ fail_open_run(struct fail_open *fo)
  * controller, exits fail open mode. */
 void
 fail_open_maybe_recover(struct fail_open *fo)
+    OVS_EXCLUDED(ofproto_mutex)
 {
     if (fail_open_is_active(fo)
         && connmgr_is_any_controller_admitted(fo->connmgr)) {
@@ -191,6 +192,7 @@ fail_open_maybe_recover(struct fail_open *fo)
 
 static void
 fail_open_recover(struct fail_open *fo)
+    OVS_EXCLUDED(ofproto_mutex)
 {
     struct match match;
 
@@ -250,6 +252,7 @@ fail_open_create(struct ofproto *ofproto, struct connmgr *mgr)
 /* Destroys 'fo'. */
 void
 fail_open_destroy(struct fail_open *fo)
+    OVS_EXCLUDED(ofproto_mutex)
 {
     if (fo) {
         if (fail_open_is_active(fo)) {
index c8e1f32..725b82d 100644 (file)
@@ -40,11 +40,11 @@ is_fail_open_rule(const struct rule *rule)
 }
 
 struct fail_open *fail_open_create(struct ofproto *, struct connmgr *);
-void fail_open_destroy(struct fail_open *);
+void fail_open_destroy(struct fail_open *) OVS_EXCLUDED(ofproto_mutex);
 void fail_open_wait(struct fail_open *);
 bool fail_open_is_active(const struct fail_open *);
 void fail_open_run(struct fail_open *);
-void fail_open_maybe_recover(struct fail_open *);
-void fail_open_flushed(struct fail_open *);
+void fail_open_maybe_recover(struct fail_open *) OVS_EXCLUDED(ofproto_mutex);
+void fail_open_flushed(struct fail_open *) OVS_EXCLUDED(ofproto_mutex);
 
 #endif /* fail-open.h */
index f79ad6a..8259ced 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -53,7 +53,7 @@ struct netflow {
 
     struct hmap flows;            /* Contains 'netflow_flows'. */
 
-    atomic_int ref_cnt;
+    struct ovs_refcount ref_cnt;
 };
 
 struct netflow_flow {
@@ -405,7 +405,7 @@ netflow_create(void)
     nf->add_id_to_iface = false;
     nf->netflow_cnt = 0;
     hmap_init(&nf->flows);
-    atomic_init(&nf->ref_cnt, 1);
+    ovs_refcount_init(&nf->ref_cnt);
     ofpbuf_init(&nf->packet, 1500);
     atomic_add(&netflow_count, 1, &junk);
     return nf;
@@ -416,9 +416,7 @@ netflow_ref(const struct netflow *nf_)
 {
     struct netflow *nf = CONST_CAST(struct netflow *, nf_);
     if (nf) {
-        int orig;
-        atomic_add(&nf->ref_cnt, 1, &orig);
-        ovs_assert(orig > 0);
+        ovs_refcount_ref(&nf->ref_cnt);
     }
     return nf;
 }
@@ -426,18 +424,13 @@ netflow_ref(const struct netflow *nf_)
 void
 netflow_unref(struct netflow *nf)
 {
-    int orig;
-
-    if (!nf) {
-        return;
-    }
+    if (nf && ovs_refcount_unref(&nf->ref_cnt) == 1) {
+        int orig;
 
-    atomic_sub(&nf->ref_cnt, 1, &orig);
-    ovs_assert(orig > 0);
-    if (orig == 1) {
         atomic_sub(&netflow_count, 1, &orig);
         collectors_destroy(nf->collectors);
         ofpbuf_uninit(&nf->packet);
+        ovs_refcount_destroy(&nf->ref_cnt);
         free(nf);
     }
 }
index a9cc73e..2500efd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Nicira, Inc.
+ * Copyright (c) 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -70,7 +70,7 @@ struct dpif_ipfix_flow_exporter_map_node {
 struct dpif_ipfix {
     struct dpif_ipfix_bridge_exporter bridge_exporter;
     struct hmap flow_exporter_map;  /* dpif_ipfix_flow_exporter_map_node. */
-    atomic_int ref_cnt;
+    struct ovs_refcount ref_cnt;
 };
 
 #define IPFIX_VERSION 0x000a
@@ -639,7 +639,7 @@ dpif_ipfix_create(void)
     di = xzalloc(sizeof *di);
     dpif_ipfix_bridge_exporter_init(&di->bridge_exporter);
     hmap_init(&di->flow_exporter_map);
-    atomic_init(&di->ref_cnt, 1);
+    ovs_refcount_init(&di->ref_cnt);
     return di;
 }
 
@@ -648,9 +648,7 @@ dpif_ipfix_ref(const struct dpif_ipfix *di_)
 {
     struct dpif_ipfix *di = CONST_CAST(struct dpif_ipfix *, di_);
     if (di) {
-        int orig;
-        atomic_add(&di->ref_cnt, 1, &orig);
-        ovs_assert(orig > 0);
+        ovs_refcount_ref(&di->ref_cnt);
     }
     return di;
 }
@@ -683,19 +681,12 @@ dpif_ipfix_clear(struct dpif_ipfix *di) OVS_REQUIRES(mutex)
 void
 dpif_ipfix_unref(struct dpif_ipfix *di) OVS_EXCLUDED(mutex)
 {
-    int orig;
-
-    if (!di) {
-        return;
-    }
-
-    atomic_sub(&di->ref_cnt, 1, &orig);
-    ovs_assert(orig > 0);
-    if (orig == 1) {
+    if (di && ovs_refcount_unref(&di->ref_cnt) == 1) {
         ovs_mutex_lock(&mutex);
         dpif_ipfix_clear(di);
         dpif_ipfix_bridge_exporter_destroy(&di->bridge_exporter);
         hmap_destroy(&di->flow_exporter_map);
+        ovs_refcount_destroy(&di->ref_cnt);
         free(di);
         ovs_mutex_unlock(&mutex);
     }
index 33115f3..b521735 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -64,25 +64,25 @@ static pthread_t monitor_tid;
 static bool monitor_running;
 
 static struct latch monitor_exit_latch;
-static struct ovs_rwlock monitor_rwlock = OVS_RWLOCK_INITIALIZER;
+static struct ovs_mutex monitor_mutex = OVS_MUTEX_INITIALIZER;
 
 static void *monitor_main(void *);
 static void monitor_run(void);
 
 static void mport_register(const struct ofport_dpif *, struct bfd *,
                            struct cfm *, uint8_t[ETH_ADDR_LEN])
-    OVS_REQ_WRLOCK(monitor_rwlock);
+    OVS_REQUIRES(monitor_mutex);
 static void mport_unregister(const struct ofport_dpif *)
-    OVS_REQ_WRLOCK(monitor_rwlock);
+    OVS_REQUIRES(monitor_mutex);
 static void mport_update(struct mport *, struct bfd *, struct cfm *,
-                         uint8_t[ETH_ADDR_LEN]) OVS_REQ_WRLOCK(monitor_rwlock);
+                         uint8_t[ETH_ADDR_LEN]) OVS_REQUIRES(monitor_mutex);
 static struct mport *mport_find(const struct ofport_dpif *)
-    OVS_REQ_WRLOCK(monitor_rwlock);
+    OVS_REQUIRES(monitor_mutex);
 
 /* Tries finding and returning the 'mport' from the monitor_hmap.
  * If there is no such 'mport', returns NULL. */
 static struct mport *
-mport_find(const struct ofport_dpif *ofport) OVS_REQ_WRLOCK(monitor_rwlock)
+mport_find(const struct ofport_dpif *ofport) OVS_REQUIRES(monitor_mutex)
 {
     struct mport *node;
 
@@ -100,7 +100,7 @@ mport_find(const struct ofport_dpif *ofport) OVS_REQ_WRLOCK(monitor_rwlock)
 static void
 mport_register(const struct ofport_dpif *ofport, struct bfd *bfd,
                struct cfm *cfm, uint8_t *hw_addr)
-    OVS_REQ_WRLOCK(monitor_rwlock)
+    OVS_REQUIRES(monitor_mutex)
 {
     struct mport *mport = mport_find(ofport);
 
@@ -116,7 +116,7 @@ mport_register(const struct ofport_dpif *ofport, struct bfd *bfd,
 /* Removes mport from monitor_hmap and monitor_heap and frees it. */
 static void
 mport_unregister(const struct ofport_dpif *ofport)
-    OVS_REQ_WRLOCK(monitor_rwlock)
+    OVS_REQUIRES(monitor_mutex)
 {
     struct mport *mport = mport_find(ofport);
 
@@ -131,7 +131,7 @@ mport_unregister(const struct ofport_dpif *ofport)
 /* Updates the fields of an existing mport struct. */
 static void
 mport_update(struct mport *mport, struct bfd *bfd, struct cfm *cfm,
-             uint8_t hw_addr[ETH_ADDR_LEN]) OVS_REQ_WRLOCK(monitor_rwlock)
+             uint8_t hw_addr[ETH_ADDR_LEN]) OVS_REQUIRES(monitor_mutex)
 {
     ovs_assert(mport);
 
@@ -184,7 +184,7 @@ monitor_run(void)
     struct ofpbuf packet;
 
     ofpbuf_use_stub(&packet, stub, sizeof stub);
-    ovs_rwlock_wrlock(&monitor_rwlock);
+    ovs_mutex_lock(&monitor_mutex);
     prio_now = MSEC_TO_PRIO(time_msec());
     /* Peeks the top of heap and checks if we should run this mport. */
     while (!heap_is_empty(&monitor_heap)
@@ -226,7 +226,7 @@ monitor_run(void)
         next_mport_wakeup = PRIO_TO_MSEC(heap_max(&monitor_heap)->priority);
         poll_timer_wait_until(MIN(next_timeout, next_mport_wakeup));
     }
-    ovs_rwlock_unlock(&monitor_rwlock);
+    ovs_mutex_unlock(&monitor_mutex);
     ofpbuf_uninit(&packet);
 }
 \f
@@ -240,13 +240,13 @@ ofproto_dpif_monitor_port_update(const struct ofport_dpif *ofport,
                                  struct bfd *bfd, struct cfm *cfm,
                                  uint8_t hw_addr[ETH_ADDR_LEN])
 {
-    ovs_rwlock_wrlock(&monitor_rwlock);
+    ovs_mutex_lock(&monitor_mutex);
     if (!cfm && !bfd) {
         mport_unregister(ofport);
     } else {
         mport_register(ofport, bfd, cfm, hw_addr);
     }
-    ovs_rwlock_unlock(&monitor_rwlock);
+    ovs_mutex_unlock(&monitor_mutex);
 
     /* If the monitor thread is not running and the hmap
      * is not empty, starts it.  If it is and the hmap is empty,
@@ -269,14 +269,14 @@ ofproto_dpif_monitor_port_update(const struct ofport_dpif *ofport,
 void
 ofproto_dpif_monitor_port_send_soon_safe(const struct ofport_dpif *ofport)
 {
-    ovs_rwlock_wrlock(&monitor_rwlock);
+    ovs_mutex_lock(&monitor_mutex);
     ofproto_dpif_monitor_port_send_soon(ofport);
-    ovs_rwlock_unlock(&monitor_rwlock);
+    ovs_mutex_unlock(&monitor_mutex);
 }
 
 void
 ofproto_dpif_monitor_port_send_soon(const struct ofport_dpif *ofport)
-    OVS_REQ_WRLOCK(monitor_rwlock)
+    OVS_REQUIRES(monitor_mutex)
 {
     struct mport *mport;
 
index 158887f..e9ef434 100644 (file)
@@ -59,7 +59,7 @@ struct dpif_sflow {
     size_t n_flood, n_all;
     struct hmap ports;          /* Contains "struct dpif_sflow_port"s. */
     uint32_t probability;
-    atomic_int ref_cnt;
+    struct ovs_refcount ref_cnt;
 };
 
 static void dpif_sflow_del_port__(struct dpif_sflow *,
@@ -327,7 +327,7 @@ dpif_sflow_create(void)
     hmap_init(&ds->ports);
     ds->probability = 0;
     route_table_register();
-    atomic_init(&ds->ref_cnt, 1);
+    ovs_refcount_init(&ds->ref_cnt);
 
     return ds;
 }
@@ -337,9 +337,7 @@ dpif_sflow_ref(const struct dpif_sflow *ds_)
 {
     struct dpif_sflow *ds = CONST_CAST(struct dpif_sflow *, ds_);
     if (ds) {
-        int orig;
-        atomic_add(&ds->ref_cnt, 1, &orig);
-        ovs_assert(orig > 0);
+        ovs_refcount_ref(&ds->ref_cnt);
     }
     return ds;
 }
@@ -360,15 +358,7 @@ dpif_sflow_get_probability(const struct dpif_sflow *ds) OVS_EXCLUDED(mutex)
 void
 dpif_sflow_unref(struct dpif_sflow *ds) OVS_EXCLUDED(mutex)
 {
-    int orig;
-
-    if (!ds) {
-        return;
-    }
-
-    atomic_sub(&ds->ref_cnt, 1, &orig);
-    ovs_assert(orig > 0);
-    if (orig == 1) {
+    if (ds && ovs_refcount_unref(&ds->ref_cnt) == 1) {
         struct dpif_sflow_port *dsp, *next;
 
         route_table_unregister();
@@ -377,6 +367,7 @@ dpif_sflow_unref(struct dpif_sflow *ds) OVS_EXCLUDED(mutex)
             dpif_sflow_del_port__(ds, dsp);
         }
         hmap_destroy(&ds->ports);
+        ovs_refcount_destroy(&ds->ref_cnt);
         free(ds);
     }
 }
index b57afdc..1e0c12c 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -208,6 +208,8 @@ struct flow_miss {
     struct odputil_keybuf mask_buf;
 
     struct xlate_out xout;
+
+    bool put;
 };
 
 static void upcall_destroy(struct upcall *);
@@ -273,6 +275,8 @@ udpif_destroy(struct udpif *udpif)
     latch_destroy(&udpif->exit_latch);
     seq_destroy(udpif->reval_seq);
     seq_destroy(udpif->dump_seq);
+    atomic_destroy(&udpif->max_idle);
+    atomic_destroy(&udpif->flow_limit);
     free(udpif);
 }
 
@@ -625,17 +629,11 @@ udpif_upcall_handler(void *arg)
     handler->name = xasprintf("handler_%u", ovsthread_id_self());
     set_subprogram_name("%s", handler->name);
 
-    for (;;) {
+    while (!latch_is_set(&handler->udpif->exit_latch)) {
         struct list misses = LIST_INITIALIZER(&misses);
         size_t i;
 
         ovs_mutex_lock(&handler->mutex);
-
-        if (latch_is_set(&handler->udpif->exit_latch)) {
-            ovs_mutex_unlock(&handler->mutex);
-            return NULL;
-        }
-
         if (!handler->n_upcalls) {
             ovs_mutex_cond_wait(&handler->wake_cond, &handler->mutex);
         }
@@ -654,6 +652,8 @@ udpif_upcall_handler(void *arg)
 
         coverage_clear();
     }
+
+    return NULL;
 }
 
 static void *
@@ -973,6 +973,7 @@ handle_upcalls(struct handler *handler, struct list *upcalls)
                 miss->stats.used = time_msec();
                 miss->stats.tcp_flags = 0;
                 miss->odp_in_port = odp_in_port;
+                miss->put = false;
 
                 n_misses++;
             } else {
@@ -1076,9 +1077,12 @@ handle_upcalls(struct handler *handler, struct list *upcalls)
     LIST_FOR_EACH (upcall, list_node, upcalls) {
         struct flow_miss *miss = upcall->flow_miss;
         struct ofpbuf *packet = &upcall->dpif_upcall.packet;
-        struct ofpbuf mask;
         struct dpif_op *op;
-        bool megaflow;
+        ovs_be16 flow_vlan_tci;
+
+        /* Save a copy of flow.vlan_tci in case it is changed to
+         * generate proper mega flow masks for VLAN splinter flows. */
+        flow_vlan_tci = miss->flow.vlan_tci;
 
         if (miss->xout.slow) {
             struct xlate_in xin;
@@ -1087,14 +1091,48 @@ handle_upcalls(struct handler *handler, struct list *upcalls)
             xlate_actions_for_side_effects(&xin);
         }
 
-        atomic_read(&enable_megaflows, &megaflow);
-        ofpbuf_use_stack(&mask, &miss->mask_buf, sizeof miss->mask_buf);
-        if (megaflow) {
-            odp_flow_key_from_mask(&mask, &miss->xout.wc.masks, &miss->flow,
-                                   UINT32_MAX);
+        if (miss->flow.in_port.ofp_port
+            != vsp_realdev_to_vlandev(miss->ofproto,
+                                      miss->flow.in_port.ofp_port,
+                                      miss->flow.vlan_tci)) {
+            /* This packet was received on a VLAN splinter port.  We
+             * added a VLAN to the packet to make the packet resemble
+             * the flow, but the actions were composed assuming that
+             * the packet contained no VLAN.  So, we must remove the
+             * VLAN header from the packet before trying to execute the
+             * actions. */
+            if (miss->xout.odp_actions.size) {
+                eth_pop_vlan(packet);
+            }
+
+            /* Remove the flow vlan tags inserted by vlan splinter logic
+             * to ensure megaflow masks generated match the data path flow. */
+            miss->flow.vlan_tci = 0;
         }
 
-        if (may_put) {
+        /* Do not install a flow into the datapath if:
+         *
+         *    - The datapath already has too many flows.
+         *
+         *    - An earlier iteration of this loop already put the same flow.
+         *
+         *    - We received this packet via some flow installed in the kernel
+         *      already. */
+        if (may_put
+            && !miss->put
+            && upcall->dpif_upcall.type == DPIF_UC_MISS) {
+            struct ofpbuf mask;
+            bool megaflow;
+
+            miss->put = true;
+
+            atomic_read(&enable_megaflows, &megaflow);
+            ofpbuf_use_stack(&mask, &miss->mask_buf, sizeof miss->mask_buf);
+            if (megaflow) {
+                odp_flow_key_from_mask(&mask, &miss->xout.wc.masks,
+                                       &miss->flow, UINT32_MAX);
+            }
+
             op = &ops[n_ops++];
             op->type = DPIF_OP_FLOW_PUT;
             op->u.flow_put.flags = DPIF_FP_CREATE | DPIF_FP_MODIFY;
@@ -1118,19 +1156,13 @@ handle_upcalls(struct handler *handler, struct list *upcalls)
             }
         }
 
+        /*
+         * The 'miss' may be shared by multiple upcalls. Restore
+         * the saved flow vlan_tci field before processing the next
+         * upcall. */
+        miss->flow.vlan_tci = flow_vlan_tci;
+
         if (miss->xout.odp_actions.size) {
-            if (miss->flow.in_port.ofp_port
-                != vsp_realdev_to_vlandev(miss->ofproto,
-                                          miss->flow.in_port.ofp_port,
-                                          miss->flow.vlan_tci)) {
-                /* This packet was received on a VLAN splinter port.  We
-                 * added a VLAN to the packet to make the packet resemble
-                 * the flow, but the actions were composed assuming that
-                 * the packet contained no VLAN.  So, we must remove the
-                 * VLAN header from the packet before trying to execute the
-                 * actions. */
-                eth_pop_vlan(packet);
-            }
 
             op = &ops[n_ops++];
             op->type = DPIF_OP_EXECUTE;
index 13a5d07..c5e6600 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -581,7 +581,7 @@ xlate_receive(const struct dpif_backer *backer, struct ofpbuf *packet,
              * an OpenFlow controller properly, so that it looks correct
              * for sFlow, and so that flow_extract() will get the correct
              * vlan_tci if it is called on 'packet'. */
-            eth_push_vlan(packet, flow->vlan_tci);
+            eth_push_vlan(packet, htons(ETH_TYPE_VLAN), flow->vlan_tci);
         }
         /* We can't reproduce 'key' from 'flow'. */
         fitness = fitness == ODP_FIT_PERFECT ? ODP_FIT_TOO_MUCH : fitness;
@@ -2754,7 +2754,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
              * applicable header fields.  Do nothing if no header exists. */
             if ((mf->id != MFF_VLAN_VID || flow->vlan_tci & htons(VLAN_CFI))
                 && ((mf->id != MFF_MPLS_LABEL && mf->id != MFF_MPLS_TC)
-                    || flow->mpls_lse)) {
+                    || eth_type_mpls(flow->dl_type))) {
                 mf_set_flow_value(mf, &set_field->value, flow);
             }
             break;
@@ -2999,6 +2999,7 @@ actions_output_to_local_port(const struct xlate_ctx *ctx)
 /* Thread safe call to xlate_actions__(). */
 void
 xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
+    OVS_EXCLUDED(xlate_rwlock)
 {
     ovs_rwlock_rdlock(&xlate_rwlock);
     xlate_actions__(xin, xout);
@@ -3077,7 +3078,9 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout)
     memset(&wc->masks.in_port, 0xff, sizeof wc->masks.in_port);
     memset(&wc->masks.skb_priority, 0xff, sizeof wc->masks.skb_priority);
     memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);
-    wc->masks.nw_frag |= FLOW_NW_FRAG_MASK;
+    if (is_ip_any(flow)) {
+        wc->masks.nw_frag |= FLOW_NW_FRAG_MASK;
+    }
 
     tnl_may_send = tnl_xlate_init(&ctx.base_flow, flow, wc);
     if (ctx.xbridge->netflow) {
@@ -3253,7 +3256,6 @@ xlate_send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet)
     struct ofpact_output output;
     struct flow flow;
     union flow_in_port in_port_;
-    int error;
 
     ofpact_init(&output.ofpact, OFPACT_OUTPUT, sizeof output);
     /* Use OFPP_NONE as the in_port to avoid special packet processing. */
@@ -3268,9 +3270,9 @@ xlate_send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet)
     }
     output.port = xport->ofp_port;
     output.max_len = 0;
-    error =  ofproto_dpif_execute_actions(xport->xbridge->ofproto, &flow, NULL,
-                                          &output.ofpact, sizeof output,
-                                          packet);
     ovs_rwlock_unlock(&xlate_rwlock);
-    return error;
+
+    return ofproto_dpif_execute_actions(xport->xbridge->ofproto, &flow, NULL,
+                                        &output.ofpact, sizeof output,
+                                        packet);
 }
index 91ffe23..cc1e9d5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -42,7 +42,6 @@
 #include "netdev-vport.h"
 #include "netdev.h"
 #include "netlink.h"
-#include "netlink-socket.h"
 #include "nx-match.h"
 #include "odp-util.h"
 #include "odp-execute.h"
@@ -1130,9 +1129,9 @@ destruct(struct ofproto *ofproto_)
     OFPROTO_FOR_EACH_TABLE (table, &ofproto->up) {
         struct cls_cursor cursor;
 
-        ovs_rwlock_rdlock(&table->cls.rwlock);
+        fat_rwlock_rdlock(&table->cls.rwlock);
         cls_cursor_init(&cursor, &table->cls, NULL);
-        ovs_rwlock_unlock(&table->cls.rwlock);
+        fat_rwlock_unlock(&table->cls.rwlock);
         CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, up.cr, &cursor) {
             ofproto_rule_delete(&ofproto->up, &rule->up);
         }
@@ -3009,11 +3008,13 @@ rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto,
 
     if (wc) {
         memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);
-        wc->masks.nw_frag |= FLOW_NW_FRAG_MASK;
+        if (is_ip_any(flow)) {
+            wc->masks.nw_frag |= FLOW_NW_FRAG_MASK;
+        }
     }
 
     cls = &ofproto->up.tables[table_id].cls;
-    ovs_rwlock_rdlock(&cls->rwlock);
+    fat_rwlock_rdlock(&cls->rwlock);
     frag = (flow->nw_frag & FLOW_NW_FRAG_ANY) != 0;
     if (frag && ofproto->up.frag_handling == OFPC_FRAG_NORMAL) {
         /* We must pretend that transport ports are unavailable. */
@@ -3030,7 +3031,7 @@ rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto,
 
     *rule = rule_dpif_cast(rule_from_cls_rule(cls_rule));
     rule_dpif_ref(*rule);
-    ovs_rwlock_unlock(&cls->rwlock);
+    fat_rwlock_unlock(&cls->rwlock);
 
     return *rule != NULL;
 }
@@ -3457,6 +3458,7 @@ struct trace_ctx {
     struct xlate_out xout;
     struct xlate_in xin;
     struct flow flow;
+    struct flow_wildcards wc;
     struct ds *result;
 };
 
@@ -3532,6 +3534,20 @@ trace_format_odp(struct ds *result, int level, const char *title,
     ds_put_char(result, '\n');
 }
 
+static void
+trace_format_megaflow(struct ds *result, int level, const char *title,
+                      struct trace_ctx *trace)
+{
+    struct match match;
+
+    ds_put_char_multiple(result, '\t', level);
+    ds_put_format(result, "%s: ", title);
+    flow_wildcards_or(&trace->wc, &trace->xout.wc, &trace->wc);
+    match_init(&match, &trace->flow, &trace->wc);
+    match_format(&match, result, OFP_DEFAULT_PRIORITY);
+    ds_put_char(result, '\n');
+}
+
 static void
 trace_resubmit(struct xlate_in *xin, struct rule_dpif *rule, int recurse)
 {
@@ -3542,6 +3558,7 @@ trace_resubmit(struct xlate_in *xin, struct rule_dpif *rule, int recurse)
     trace_format_flow(result, recurse + 1, "Resubmitted flow", trace);
     trace_format_regs(result, recurse + 1, "Resubmitted regs", trace);
     trace_format_odp(result,  recurse + 1, "Resubmitted  odp", trace);
+    trace_format_megaflow(result, recurse + 1, "Resubmitted megaflow", trace);
     trace_format_rule(result, recurse + 1, rule);
 }
 
@@ -3820,18 +3837,18 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
               struct ds *ds)
 {
     struct rule_dpif *rule;
-    struct flow_wildcards wc;
+    struct trace_ctx trace;
 
     ds_put_format(ds, "Bridge: %s\n", ofproto->up.name);
     ds_put_cstr(ds, "Flow: ");
     flow_format(ds, flow);
     ds_put_char(ds, '\n');
 
-    flow_wildcards_init_catchall(&wc);
+    flow_wildcards_init_catchall(&trace.wc);
     if (ofpacts) {
         rule = NULL;
     } else {
-        rule_dpif_lookup(ofproto, flow, &wc, &rule);
+        rule_dpif_lookup(ofproto, flow, &trace.wc, &rule);
 
         trace_format_rule(ds, 0, rule);
         if (rule == ofproto->miss_rule) {
@@ -3846,17 +3863,11 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
     }
 
     if (rule || ofpacts) {
-        uint64_t odp_actions_stub[1024 / 8];
-        struct ofpbuf odp_actions;
-        struct trace_ctx trace;
-        struct match match;
         uint16_t tcp_flags;
 
         tcp_flags = packet ? packet_get_tcp_flags(packet, flow) : 0;
         trace.result = ds;
         trace.flow = *flow;
-        ofpbuf_use_stub(&odp_actions,
-                        odp_actions_stub, sizeof odp_actions_stub);
         xlate_in_init(&trace.xin, ofproto, flow, rule, tcp_flags, packet);
         if (ofpacts) {
             trace.xin.ofpacts = ofpacts;
@@ -3866,15 +3877,10 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
         trace.xin.report_hook = trace_report;
 
         xlate_actions(&trace.xin, &trace.xout);
-        flow_wildcards_or(&trace.xout.wc, &trace.xout.wc, &wc);
 
         ds_put_char(ds, '\n');
         trace_format_flow(ds, 0, "Final flow", &trace);
-
-        match_init(&match, flow, &trace.xout.wc);
-        ds_put_cstr(ds, "Relevant fields: ");
-        match_format(&match, ds, OFP_DEFAULT_PRIORITY);
-        ds_put_char(ds, '\n');
+        trace_format_megaflow(ds, 0, "Megaflow", &trace);
 
         ds_put_cstr(ds, "Datapath actions: ");
         format_odp_actions(ds, trace.xout.odp_actions.data,
index 51cb38f..5da0b5d 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -34,6 +34,9 @@ struct dpif_backer;
 struct OVS_LOCKABLE rule_dpif;
 struct OVS_LOCKABLE group_dpif;
 
+/* For lock annotation below only. */
+extern struct ovs_rwlock xlate_rwlock;
+
 /* Ofproto-dpif -- DPIF based ofproto implementation.
  *
  * Ofproto-dpif provides an ofproto implementation for those platforms which
@@ -107,7 +110,8 @@ bool vsp_adjust_flow(const struct ofproto_dpif *, struct flow *);
 
 int ofproto_dpif_execute_actions(struct ofproto_dpif *, const struct flow *,
                                  struct rule_dpif *, const struct ofpact *,
-                                 size_t ofpacts_len, struct ofpbuf *);
+                                 size_t ofpacts_len, struct ofpbuf *)
+    OVS_EXCLUDED(xlate_rwlock);
 void ofproto_dpif_send_packet_in(struct ofproto_dpif *,
                                  struct ofproto_packet_in *);
 int ofproto_dpif_send_packet(const struct ofport_dpif *, struct ofpbuf *);
index cc318ee..19d1551 100644 (file)
@@ -346,7 +346,7 @@ struct rule {
      * The classifier owns one reference.
      * Any thread trying to keep a rule from being freed should hold its own
      * reference. */
-    atomic_uint ref_count;
+    struct ovs_refcount ref_count;
 
     /* Operation now in progress, if nonnull. */
     struct ofoperation *pending OVS_GUARDED_BY(ofproto_mutex);
@@ -426,7 +426,7 @@ rule_is_table_miss(const struct rule *rule)
  * 'rule' is the rule for which 'rule->actions == actions') or that owns a
  * reference to 'actions->ref_count' (or both). */
 struct rule_actions {
-    atomic_uint ref_count;
+    struct ovs_refcount ref_count;
 
     /* These members are immutable: they do not change during the struct's
      * lifetime.  */
index 676a6cb..b2cdb10 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  * Copyright (c) 2010 Jean Tourrilhes - HP-Labs.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -1168,7 +1168,7 @@ ofproto_configure_table(struct ofproto *ofproto, int table_id,
     }
 
     table->max_flows = s->max_flows;
-    ovs_rwlock_wrlock(&table->cls.rwlock);
+    fat_rwlock_wrlock(&table->cls.rwlock);
     if (classifier_count(&table->cls) > table->max_flows
         && table->eviction_fields) {
         /* 'table' contains more flows than allowed.  We might not be able to
@@ -1188,7 +1188,7 @@ ofproto_configure_table(struct ofproto *ofproto, int table_id,
     classifier_set_prefix_fields(&table->cls,
                                  s->prefix_fields, s->n_prefix_fields);
 
-    ovs_rwlock_unlock(&table->cls.rwlock);
+    fat_rwlock_unlock(&table->cls.rwlock);
 }
 \f
 bool
@@ -1263,9 +1263,9 @@ ofproto_flush__(struct ofproto *ofproto)
             continue;
         }
 
-        ovs_rwlock_rdlock(&table->cls.rwlock);
+        fat_rwlock_rdlock(&table->cls.rwlock);
         cls_cursor_init(&cursor, &table->cls, NULL);
-        ovs_rwlock_unlock(&table->cls.rwlock);
+        fat_rwlock_unlock(&table->cls.rwlock);
         CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, cr, &cursor) {
             if (!rule->pending) {
                 ofproto_rule_delete__(ofproto, rule, OFPRR_DELETE);
@@ -1454,7 +1454,7 @@ ofproto_run(struct ofproto *p)
                 heap_rebuild(&evg->rules);
             }
 
-            ovs_rwlock_rdlock(&table->cls.rwlock);
+            fat_rwlock_rdlock(&table->cls.rwlock);
             cls_cursor_init(&cursor, &table->cls, NULL);
             CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
                 if (!rule->eviction_group
@@ -1462,7 +1462,7 @@ ofproto_run(struct ofproto *p)
                     eviction_group_add_rule(rule);
                 }
             }
-            ovs_rwlock_unlock(&table->cls.rwlock);
+            fat_rwlock_unlock(&table->cls.rwlock);
             ovs_mutex_unlock(&ofproto_mutex);
         }
     }
@@ -1612,9 +1612,9 @@ ofproto_get_memory_usage(const struct ofproto *ofproto, struct simap *usage)
 
     n_rules = 0;
     OFPROTO_FOR_EACH_TABLE (table, ofproto) {
-        ovs_rwlock_rdlock(&table->cls.rwlock);
+        fat_rwlock_rdlock(&table->cls.rwlock);
         n_rules += classifier_count(&table->cls);
-        ovs_rwlock_unlock(&table->cls.rwlock);
+        fat_rwlock_unlock(&table->cls.rwlock);
     }
     simap_increase(usage, "rules", n_rules);
 
@@ -1901,7 +1901,7 @@ ofproto_add_flow(struct ofproto *ofproto, const struct match *match,
 
     /* First do a cheap check whether the rule we're looking for already exists
      * with the actions that we want.  If it does, then we're done. */
-    ovs_rwlock_rdlock(&ofproto->tables[0].cls.rwlock);
+    fat_rwlock_rdlock(&ofproto->tables[0].cls.rwlock);
     rule = rule_from_cls_rule(classifier_find_match_exactly(
                                   &ofproto->tables[0].cls, match, priority));
     if (rule) {
@@ -1913,7 +1913,7 @@ ofproto_add_flow(struct ofproto *ofproto, const struct match *match,
     } else {
         must_add = true;
     }
-    ovs_rwlock_unlock(&ofproto->tables[0].cls.rwlock);
+    fat_rwlock_unlock(&ofproto->tables[0].cls.rwlock);
 
     /* If there's no such rule or the rule doesn't have the actions we want,
      * fall back to a executing a full flow mod.  We can't optimize this at
@@ -1952,10 +1952,10 @@ ofproto_delete_flow(struct ofproto *ofproto,
 
     /* First do a cheap check whether the rule we're looking for has already
      * been deleted.  If so, then we're done. */
-    ovs_rwlock_rdlock(&cls->rwlock);
+    fat_rwlock_rdlock(&cls->rwlock);
     rule = rule_from_cls_rule(classifier_find_match_exactly(cls, target,
                                                             priority));
-    ovs_rwlock_unlock(&cls->rwlock);
+    fat_rwlock_unlock(&cls->rwlock);
     if (!rule) {
         return true;
     }
@@ -2527,26 +2527,16 @@ void
 ofproto_rule_ref(struct rule *rule)
 {
     if (rule) {
-        unsigned int orig;
-
-        atomic_add(&rule->ref_count, 1, &orig);
-        ovs_assert(orig != 0);
+        ovs_refcount_ref(&rule->ref_count);
     }
 }
 
 void
 ofproto_rule_unref(struct rule *rule)
 {
-    if (rule) {
-        unsigned int orig;
-
-        atomic_sub(&rule->ref_count, 1, &orig);
-        if (orig == 1) {
-            rule->ofproto->ofproto_class->rule_destruct(rule);
-            ofproto_rule_destroy__(rule);
-        } else {
-            ovs_assert(orig != 0);
-        }
+    if (rule && ovs_refcount_unref(&rule->ref_count) == 1) {
+        rule->ofproto->ofproto_class->rule_destruct(rule);
+        ofproto_rule_destroy__(rule);
     }
 }
 
@@ -2578,6 +2568,7 @@ ofproto_rule_destroy__(struct rule *rule)
     cls_rule_destroy(CONST_CAST(struct cls_rule *, &rule->cr));
     rule_actions_unref(rule->actions);
     ovs_mutex_destroy(&rule->mutex);
+    ovs_refcount_destroy(&rule->ref_count);
     rule->ofproto->ofproto_class->rule_dealloc(rule);
 }
 
@@ -2593,7 +2584,7 @@ rule_actions_create(const struct ofproto *ofproto,
     struct rule_actions *actions;
 
     actions = xmalloc(sizeof *actions);
-    atomic_init(&actions->ref_count, 1);
+    ovs_refcount_init(&actions->ref_count);
     actions->ofpacts = xmemdup(ofpacts, ofpacts_len);
     actions->ofpacts_len = ofpacts_len;
     actions->provider_meter_id
@@ -2608,10 +2599,7 @@ void
 rule_actions_ref(struct rule_actions *actions)
 {
     if (actions) {
-        unsigned int orig;
-
-        atomic_add(&actions->ref_count, 1, &orig);
-        ovs_assert(orig != 0);
+        ovs_refcount_ref(&actions->ref_count);
     }
 }
 
@@ -2620,16 +2608,10 @@ rule_actions_ref(struct rule_actions *actions)
 void
 rule_actions_unref(struct rule_actions *actions)
 {
-    if (actions) {
-        unsigned int orig;
-
-        atomic_sub(&actions->ref_count, 1, &orig);
-        if (orig == 1) {
-            free(actions->ofpacts);
-            free(actions);
-        } else {
-            ovs_assert(orig != 0);
-        }
+    if (actions && ovs_refcount_unref(&actions->ref_count) == 1) {
+        ovs_refcount_destroy(&actions->ref_count);
+        free(actions->ofpacts);
+        free(actions);
     }
 }
 
@@ -3078,9 +3060,9 @@ handle_table_stats_request(struct ofconn *ofconn,
         ots[i].instructions = htonl(OFPIT11_ALL);
         ots[i].config = htonl(OFPTC11_TABLE_MISS_MASK);
         ots[i].max_entries = htonl(1000000); /* An arbitrary big number. */
-        ovs_rwlock_rdlock(&p->tables[i].cls.rwlock);
+        fat_rwlock_rdlock(&p->tables[i].cls.rwlock);
         ots[i].active_count = htonl(classifier_count(&p->tables[i].cls));
-        ovs_rwlock_unlock(&p->tables[i].cls.rwlock);
+        fat_rwlock_unlock(&p->tables[i].cls.rwlock);
     }
 
     p->ofproto_class->get_tables(p, ots);
@@ -3442,7 +3424,7 @@ collect_rules_loose(struct ofproto *ofproto,
             struct cls_cursor cursor;
             struct rule *rule;
 
-            ovs_rwlock_rdlock(&table->cls.rwlock);
+            fat_rwlock_rdlock(&table->cls.rwlock);
             cls_cursor_init(&cursor, &table->cls, &criteria->cr);
             CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
                 error = collect_rule(rule, criteria, rules);
@@ -3450,7 +3432,7 @@ collect_rules_loose(struct ofproto *ofproto,
                     break;
                 }
             }
-            ovs_rwlock_unlock(&table->cls.rwlock);
+            fat_rwlock_unlock(&table->cls.rwlock);
         }
     }
 
@@ -3502,10 +3484,10 @@ collect_rules_strict(struct ofproto *ofproto,
         FOR_EACH_MATCHING_TABLE (table, criteria->table_id, ofproto) {
             struct rule *rule;
 
-            ovs_rwlock_rdlock(&table->cls.rwlock);
+            fat_rwlock_rdlock(&table->cls.rwlock);
             rule = rule_from_cls_rule(classifier_find_rule_exactly(
                                           &table->cls, &criteria->cr));
-            ovs_rwlock_unlock(&table->cls.rwlock);
+            fat_rwlock_unlock(&table->cls.rwlock);
             if (rule) {
                 error = collect_rule(rule, criteria, rules);
                 if (error) {
@@ -3653,12 +3635,12 @@ ofproto_get_all_flows(struct ofproto *p, struct ds *results)
         struct cls_cursor cursor;
         struct rule *rule;
 
-        ovs_rwlock_rdlock(&table->cls.rwlock);
+        fat_rwlock_rdlock(&table->cls.rwlock);
         cls_cursor_init(&cursor, &table->cls, NULL);
         CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
             flow_stats_ds(rule, results);
         }
-        ovs_rwlock_unlock(&table->cls.rwlock);
+        fat_rwlock_unlock(&table->cls.rwlock);
     }
 }
 
@@ -3969,9 +3951,9 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
     cls_rule_init(&cr, &fm->match, fm->priority);
 
     /* Transform "add" into "modify" if there's an existing identical flow. */
-    ovs_rwlock_rdlock(&table->cls.rwlock);
+    fat_rwlock_rdlock(&table->cls.rwlock);
     rule = rule_from_cls_rule(classifier_find_rule_exactly(&table->cls, &cr));
-    ovs_rwlock_unlock(&table->cls.rwlock);
+    fat_rwlock_unlock(&table->cls.rwlock);
     if (rule) {
         cls_rule_destroy(&cr);
         if (!rule_is_modifiable(rule)) {
@@ -4001,9 +3983,9 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
     if (fm->flags & OFPUTIL_FF_CHECK_OVERLAP) {
         bool overlaps;
 
-        ovs_rwlock_rdlock(&table->cls.rwlock);
+        fat_rwlock_rdlock(&table->cls.rwlock);
         overlaps = classifier_rule_overlaps(&table->cls, &cr);
-        ovs_rwlock_unlock(&table->cls.rwlock);
+        fat_rwlock_unlock(&table->cls.rwlock);
 
         if (overlaps) {
             cls_rule_destroy(&cr);
@@ -4030,7 +4012,7 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
     /* Initialize base state. */
     *CONST_CAST(struct ofproto **, &rule->ofproto) = ofproto;
     cls_rule_move(CONST_CAST(struct cls_rule *, &rule->cr), &cr);
-    atomic_init(&rule->ref_count, 1);
+    ovs_refcount_init(&rule->ref_count);
     rule->pending = NULL;
     rule->flow_cookie = fm->new_cookie;
     rule->created = rule->modified = rule->used = time_msec();
@@ -4824,13 +4806,13 @@ ofproto_collect_ofmonitor_refresh_rules(const struct ofmonitor *m,
         struct cls_cursor cursor;
         struct rule *rule;
 
-        ovs_rwlock_rdlock(&table->cls.rwlock);
+        fat_rwlock_rdlock(&table->cls.rwlock);
         cls_cursor_init(&cursor, &table->cls, &target);
         CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
             ovs_assert(!rule->pending); /* XXX */
             ofproto_collect_ofmonitor_refresh_rule(m, rule, seqno, rules);
         }
-        ovs_rwlock_unlock(&table->cls.rwlock);
+        fat_rwlock_unlock(&table->cls.rwlock);
     }
 
     HMAP_FOR_EACH (op, hmap_node, &ofproto->deletions) {
@@ -6659,12 +6641,13 @@ oftable_init(struct oftable *table)
 static void
 oftable_destroy(struct oftable *table)
 {
-    ovs_rwlock_rdlock(&table->cls.rwlock);
+    fat_rwlock_rdlock(&table->cls.rwlock);
     ovs_assert(classifier_is_empty(&table->cls));
-    ovs_rwlock_unlock(&table->cls.rwlock);
+    fat_rwlock_unlock(&table->cls.rwlock);
     oftable_disable_eviction(table);
     classifier_destroy(&table->cls);
     free(table->name);
+    atomic_destroy(&table->config);
 }
 
 /* Changes the name of 'table' to 'name'.  If 'name' is NULL or the empty
@@ -6743,12 +6726,12 @@ oftable_enable_eviction(struct oftable *table,
     hmap_init(&table->eviction_groups_by_id);
     heap_init(&table->eviction_groups_by_size);
 
-    ovs_rwlock_rdlock(&table->cls.rwlock);
+    fat_rwlock_rdlock(&table->cls.rwlock);
     cls_cursor_init(&cursor, &table->cls, NULL);
     CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
         eviction_group_add_rule(rule);
     }
-    ovs_rwlock_unlock(&table->cls.rwlock);
+    fat_rwlock_unlock(&table->cls.rwlock);
 }
 
 /* Removes 'rule' from the oftable that contains it. */
@@ -6758,9 +6741,9 @@ oftable_remove_rule__(struct ofproto *ofproto, struct rule *rule)
 {
     struct classifier *cls = &ofproto->tables[rule->table_id].cls;
 
-    ovs_rwlock_wrlock(&cls->rwlock);
+    fat_rwlock_wrlock(&cls->rwlock);
     classifier_remove(cls, CONST_CAST(struct cls_rule *, &rule->cr));
-    ovs_rwlock_unlock(&cls->rwlock);
+    fat_rwlock_unlock(&cls->rwlock);
 
     cookies_remove(ofproto, rule);
 
@@ -6807,9 +6790,9 @@ oftable_insert_rule(struct rule *rule)
         struct meter *meter = ofproto->meters[meter_id];
         list_insert(&meter->rules, &rule->meter_list_node);
     }
-    ovs_rwlock_wrlock(&table->cls.rwlock);
+    fat_rwlock_wrlock(&table->cls.rwlock);
     classifier_insert(&table->cls, CONST_CAST(struct cls_rule *, &rule->cr));
-    ovs_rwlock_unlock(&table->cls.rwlock);
+    fat_rwlock_unlock(&table->cls.rwlock);
     eviction_group_add_rule(rule);
 }
 \f
@@ -6878,7 +6861,7 @@ ofproto_get_vlan_usage(struct ofproto *ofproto, unsigned long int *vlan_bitmap)
     OFPROTO_FOR_EACH_TABLE (oftable, ofproto) {
         const struct cls_subtable *table;
 
-        ovs_rwlock_rdlock(&oftable->cls.rwlock);
+        fat_rwlock_rdlock(&oftable->cls.rwlock);
         HMAP_FOR_EACH (table, hmap_node, &oftable->cls.subtables) {
             if (minimask_get_vid_mask(&table->mask) == VLAN_VID_MASK) {
                 const struct cls_rule *rule;
@@ -6890,7 +6873,7 @@ ofproto_get_vlan_usage(struct ofproto *ofproto, unsigned long int *vlan_bitmap)
                 }
             }
         }
-        ovs_rwlock_unlock(&oftable->cls.rwlock);
+        fat_rwlock_unlock(&oftable->cls.rwlock);
     }
 }
 
index d55adde..09497a3 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013 Nicira, Inc.
+/* Copyright (c) 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -273,6 +273,9 @@ tnl_xlate_init(const struct flow *base_flow, struct flow *flow,
 {
     if (tnl_port_should_receive(flow)) {
         memset(&wc->masks.tunnel, 0xff, sizeof wc->masks.tunnel);
+        wc->masks.tunnel.flags = (FLOW_TNL_F_DONT_FRAGMENT |
+                                  FLOW_TNL_F_CSUM |
+                                  FLOW_TNL_F_KEY);
         memset(&wc->masks.pkt_mark, 0xff, sizeof wc->masks.pkt_mark);
 
         if (!tnl_ecn_ok(base_flow, flow)) {
index b97365e..69e7900 100644 (file)
@@ -101,5 +101,3 @@ EXTRA_DIST += ovsdb/ovsdb-dot.in ovsdb/dot2pic
 noinst_SCRIPTS += ovsdb/ovsdb-dot
 DISTCLEANFILES += ovsdb/ovsdb-dot
 OVSDB_DOT = $(run_python) $(srcdir)/ovsdb/ovsdb-dot.in
-
-include ovsdb/ovsdbmonitor/automake.mk
diff --git a/ovsdb/ovsdbmonitor/.gitignore b/ovsdb/ovsdbmonitor/.gitignore
deleted file mode 100644 (file)
index e02ced0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/ovsdbmonitor
diff --git a/ovsdb/ovsdbmonitor/COPYING b/ovsdb/ovsdbmonitor/COPYING
deleted file mode 100644 (file)
index f1c6e1c..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-Copyright (c) 2010 Citrix Systems, 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.
diff --git a/ovsdb/ovsdbmonitor/ConfigWindow.ui b/ovsdb/ovsdbmonitor/ConfigWindow.ui
deleted file mode 100644 (file)
index 6a1316e..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>ConfigWindow</class>
- <widget class="QDialog" name="ConfigWindow">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>386</width>
-    <height>303</height>
-   </rect>
-  </property>
-  <property name="focusPolicy">
-   <enum>Qt::TabFocus</enum>
-  </property>
-  <property name="windowTitle">
-   <string>OVSDB Monitor Configuration</string>
-  </property>
-  <layout class="QGridLayout" name="gridLayout">
-   <item row="0" column="0">
-    <layout class="QVBoxLayout" name="verticalLayout">
-     <item>
-      <widget class="QTabWidget" name="tabWidget">
-       <property name="currentIndex">
-        <number>0</number>
-       </property>
-       <widget class="QWidget" name="hosts">
-        <attribute name="title">
-         <string>Hosts</string>
-        </attribute>
-        <widget class="QWidget" name="layoutWidget">
-         <property name="geometry">
-          <rect>
-           <x>10</x>
-           <y>10</y>
-           <width>341</width>
-           <height>194</height>
-          </rect>
-         </property>
-         <layout class="QHBoxLayout" name="horizontalLayout_2">
-          <item>
-           <widget class="QListWidget" name="hostList"/>
-          </item>
-          <item>
-           <layout class="QVBoxLayout" name="verticalLayout_2">
-            <item>
-             <widget class="QPushButton" name="hostAddButton">
-              <property name="text">
-               <string>Add</string>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <widget class="QPushButton" name="hostEditButton">
-              <property name="text">
-               <string>Edit</string>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <widget class="QPushButton" name="hostDeleteButton">
-              <property name="text">
-               <string>Delete</string>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <spacer name="verticalSpacer">
-              <property name="orientation">
-               <enum>Qt::Vertical</enum>
-              </property>
-              <property name="sizeHint" stdset="0">
-               <size>
-                <width>20</width>
-                <height>40</height>
-               </size>
-              </property>
-             </spacer>
-            </item>
-           </layout>
-          </item>
-         </layout>
-        </widget>
-       </widget>
-       <widget class="QWidget" name="logging">
-        <attribute name="title">
-         <string>Logging</string>
-        </attribute>
-        <layout class="QGridLayout" name="gridLayout_2">
-         <item row="0" column="0">
-          <widget class="QCheckBox" name="logTrafficCheckBox">
-           <property name="toolTip">
-            <string>Whether to log traffic exchanges in the log window</string>
-           </property>
-           <property name="text">
-            <string>Log traffic</string>
-           </property>
-          </widget>
-         </item>
-         <item row="1" column="0">
-          <spacer name="verticalSpacer_2">
-           <property name="orientation">
-            <enum>Qt::Vertical</enum>
-           </property>
-           <property name="sizeHint" stdset="0">
-            <size>
-             <width>20</width>
-             <height>164</height>
-            </size>
-           </property>
-          </spacer>
-         </item>
-        </layout>
-       </widget>
-       <widget class="QWidget" name="view">
-        <attribute name="title">
-         <string>View</string>
-        </attribute>
-        <layout class="QVBoxLayout" name="verticalLayout_3">
-         <item>
-          <widget class="QCheckBox" name="truncateUuidsCheckBox">
-           <property name="toolTip">
-            <string>Replaces UUIDs with a shorter string of the first few characters.  The tooltip still contains the full value</string>
-           </property>
-           <property name="text">
-            <string>Truncate UUIDs</string>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <spacer name="verticalSpacer_3">
-           <property name="orientation">
-            <enum>Qt::Vertical</enum>
-           </property>
-           <property name="sizeHint" stdset="0">
-            <size>
-             <width>20</width>
-             <height>164</height>
-            </size>
-           </property>
-          </spacer>
-         </item>
-        </layout>
-       </widget>
-      </widget>
-     </item>
-     <item>
-      <layout class="QHBoxLayout" name="horizontalLayout">
-       <item>
-        <spacer name="horizontalSpacer">
-         <property name="orientation">
-          <enum>Qt::Horizontal</enum>
-         </property>
-         <property name="sizeHint" stdset="0">
-          <size>
-           <width>40</width>
-           <height>20</height>
-          </size>
-         </property>
-        </spacer>
-       </item>
-       <item>
-        <widget class="QDialogButtonBox" name="buttonBox">
-         <property name="standardButtons">
-          <set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
-         </property>
-        </widget>
-       </item>
-      </layout>
-     </item>
-    </layout>
-   </item>
-  </layout>
- </widget>
- <tabstops>
-  <tabstop>hostList</tabstop>
-  <tabstop>hostAddButton</tabstop>
-  <tabstop>hostEditButton</tabstop>
-  <tabstop>hostDeleteButton</tabstop>
-  <tabstop>buttonBox</tabstop>
-  <tabstop>tabWidget</tabstop>
- </tabstops>
- <resources/>
- <connections/>
-</ui>
diff --git a/ovsdb/ovsdbmonitor/FlowWindow.ui b/ovsdb/ovsdbmonitor/FlowWindow.ui
deleted file mode 100644 (file)
index f3605b4..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>FlowWindow</class>
- <widget class="QMainWindow" name="FlowWindow">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>800</width>
-    <height>600</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>OVSDB Monitor</string>
-  </property>
-  <widget class="QWidget" name="centralwidget">
-   <layout class="QGridLayout" name="gridLayout">
-    <item row="0" column="0">
-     <widget class="QTabWidget" name="tabWidget">
-      <property name="currentIndex">
-       <number>0</number>
-      </property>
-      <widget class="QWidget" name="unset">
-       <attribute name="title">
-        <string>Awaiting update...</string>
-       </attribute>
-       <layout class="QGridLayout" name="gridLayout_10"/>
-      </widget>
-     </widget>
-    </item>
-    <item row="1" column="0">
-     <layout class="QHBoxLayout" name="horizontalLayout_2">
-      <item>
-       <widget class="QCheckBox" name="ssgCheckBox">
-        <property name="text">
-         <string>Server-side grep</string>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QComboBox" name="ssgComboBox">
-        <property name="editable">
-         <bool>true</bool>
-        </property>
-        <property name="maxVisibleItems">
-         <number>20</number>
-        </property>
-        <property name="insertPolicy">
-         <enum>QComboBox::NoInsert</enum>
-        </property>
-        <property name="minimumContentsLength">
-         <number>32</number>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QPushButton" name="ssgSaveButton">
-        <property name="text">
-         <string>Save</string>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QPushButton" name="ssgDeleteButton">
-        <property name="text">
-         <string>Delete</string>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <spacer name="horizontalSpacer_2">
-        <property name="orientation">
-         <enum>Qt::Horizontal</enum>
-        </property>
-        <property name="sizeHint" stdset="0">
-         <size>
-          <width>40</width>
-          <height>20</height>
-         </size>
-        </property>
-       </spacer>
-      </item>
-     </layout>
-    </item>
-    <item row="3" column="0">
-     <layout class="QHBoxLayout" name="horizontalLayout">
-      <item>
-       <widget class="QLabel" name="hostLabel">
-        <property name="text">
-         <string>Host</string>
-        </property>
-        <property name="buddy">
-         <cstring>hostComboBox</cstring>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QComboBox" name="hostComboBox">
-        <property name="sizeAdjustPolicy">
-         <enum>QComboBox::AdjustToContents</enum>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QCheckBox" name="intervalCheckBox">
-        <property name="text">
-         <string>Auto-refetch every</string>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QSpinBox" name="intervalSpinBox">
-        <property name="suffix">
-         <string>s</string>
-        </property>
-        <property name="minimum">
-         <number>1</number>
-        </property>
-        <property name="maximum">
-         <number>1000000</number>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <spacer name="horizontalSpacer">
-        <property name="orientation">
-         <enum>Qt::Horizontal</enum>
-        </property>
-        <property name="sizeHint" stdset="0">
-         <size>
-          <width>40</width>
-          <height>20</height>
-         </size>
-        </property>
-       </spacer>
-      </item>
-      <item>
-       <widget class="QPushButton" name="fetchPathsButton">
-        <property name="toolTip">
-         <string>Refetches the datapath names and rebuilds the window tabs to reflect them.  Use when the network has been reconfigured, e.g. a bond has been created</string>
-        </property>
-        <property name="text">
-         <string>Refetch Datapath List</string>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QPushButton" name="fetchButton">
-        <property name="text">
-         <string>Refetch</string>
-        </property>
-       </widget>
-      </item>
-     </layout>
-    </item>
-    <item row="2" column="0">
-     <widget class="Line" name="line">
-      <property name="orientation">
-       <enum>Qt::Horizontal</enum>
-      </property>
-     </widget>
-    </item>
-   </layout>
-  </widget>
-  <widget class="QMenuBar" name="menubar">
-   <property name="geometry">
-    <rect>
-     <x>0</x>
-     <y>0</y>
-     <width>800</width>
-     <height>28</height>
-    </rect>
-   </property>
-   <widget class="QMenu" name="menuFile">
-    <property name="title">
-     <string>File</string>
-    </property>
-    <addaction name="actionNew_DB_Window"/>
-    <addaction name="actionNew_Flow_Window"/>
-    <addaction name="actionShow_Log"/>
-    <addaction name="actionPreferences"/>
-    <addaction name="separator"/>
-    <addaction name="actionQuit"/>
-   </widget>
-   <addaction name="menuFile"/>
-  </widget>
-  <widget class="QStatusBar" name="statusbar"/>
-  <action name="actionShow_Log">
-   <property name="text">
-    <string>Show Log</string>
-   </property>
-  </action>
-  <action name="actionNew_DB_Window">
-   <property name="text">
-    <string>New DB Window</string>
-   </property>
-  </action>
-  <action name="actionPreferences">
-   <property name="text">
-    <string>Preferences</string>
-   </property>
-  </action>
-  <action name="actionQuit">
-   <property name="text">
-    <string>Quit</string>
-   </property>
-  </action>
-  <action name="actionNew_Flow_Window">
-   <property name="text">
-    <string>New Flow Window</string>
-   </property>
-  </action>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/ovsdb/ovsdbmonitor/HostWindow.ui b/ovsdb/ovsdbmonitor/HostWindow.ui
deleted file mode 100644 (file)
index e72ac02..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>HostWindow</class>
- <widget class="QDialog" name="HostWindow">
-  <property name="windowModality">
-   <enum>Qt::WindowModal</enum>
-  </property>
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>400</width>
-    <height>300</height>
-   </rect>
-  </property>
-  <property name="sizePolicy">
-   <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
-    <horstretch>0</horstretch>
-    <verstretch>0</verstretch>
-   </sizepolicy>
-  </property>
-  <property name="windowTitle">
-   <string>Host Properties</string>
-  </property>
-  <layout class="QGridLayout" name="gridLayout_2">
-   <item row="0" column="0">
-    <layout class="QGridLayout" name="gridLayout">
-     <item row="0" column="0">
-      <widget class="QLabel" name="label">
-       <property name="text">
-        <string>Host name or IP</string>
-       </property>
-       <property name="buddy">
-        <cstring>hostAddressEdit</cstring>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="1">
-      <widget class="QLineEdit" name="hostAddressEdit">
-       <property name="minimumSize">
-        <size>
-         <width>256</width>
-         <height>0</height>
-        </size>
-       </property>
-      </widget>
-     </item>
-     <item row="1" column="0">
-      <widget class="QLabel" name="label_2">
-       <property name="text">
-        <string>SSH Password</string>
-       </property>
-       <property name="buddy">
-        <cstring>hostPasswordEdit</cstring>
-       </property>
-      </widget>
-     </item>
-     <item row="1" column="1">
-      <widget class="QLineEdit" name="hostPasswordEdit">
-       <property name="minimumSize">
-        <size>
-         <width>256</width>
-         <height>0</height>
-        </size>
-       </property>
-       <property name="echoMode">
-        <enum>QLineEdit::Password</enum>
-       </property>
-      </widget>
-     </item>
-     <item row="2" column="0">
-      <widget class="QLabel" name="label_3">
-       <property name="text">
-        <string>Connect target</string>
-       </property>
-       <property name="buddy">
-        <cstring>hostConnectTarget</cstring>
-       </property>
-      </widget>
-     </item>
-     <item row="2" column="1">
-      <widget class="QLineEdit" name="hostConnectTarget">
-       <property name="minimumSize">
-        <size>
-         <width>256</width>
-         <height>0</height>
-        </size>
-       </property>
-      </widget>
-     </item>
-    </layout>
-   </item>
-   <item row="1" column="0">
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <tabstops>
-  <tabstop>hostAddressEdit</tabstop>
-  <tabstop>hostPasswordEdit</tabstop>
-  <tabstop>buttonBox</tabstop>
- </tabstops>
- <resources/>
- <connections>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>accepted()</signal>
-   <receiver>HostWindow</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>rejected()</signal>
-   <receiver>HostWindow</receiver>
-   <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
-</ui>
diff --git a/ovsdb/ovsdbmonitor/LogWindow.ui b/ovsdb/ovsdbmonitor/LogWindow.ui
deleted file mode 100644 (file)
index f2ac7cd..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>LogWindow</class>
- <widget class="QDialog" name="LogWindow">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>735</width>
-    <height>558</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>OVSDB Monitor Log</string>
-  </property>
-  <layout class="QGridLayout" name="gridLayout">
-   <item row="0" column="0">
-    <layout class="QVBoxLayout" name="verticalLayout">
-     <item>
-      <widget class="QTextBrowser" name="textBrowser"/>
-     </item>
-     <item>
-      <widget class="QDialogButtonBox" name="buttonBox">
-       <property name="orientation">
-        <enum>Qt::Horizontal</enum>
-       </property>
-       <property name="standardButtons">
-        <set>QDialogButtonBox::Close|QDialogButtonBox::Reset</set>
-       </property>
-      </widget>
-     </item>
-    </layout>
-   </item>
-  </layout>
- </widget>
- <resources/>
- <connections>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>accepted()</signal>
-   <receiver>LogWindow</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>rejected()</signal>
-   <receiver>LogWindow</receiver>
-   <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
-</ui>
diff --git a/ovsdb/ovsdbmonitor/MainWindow.ui b/ovsdb/ovsdbmonitor/MainWindow.ui
deleted file mode 100644 (file)
index b49c85e..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>MainWindow</class>
- <widget class="QMainWindow" name="MainWindow">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>800</width>
-    <height>600</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>OVSDB Monitor</string>
-  </property>
-  <widget class="QWidget" name="centralwidget">
-   <layout class="QGridLayout" name="gridLayout">
-    <item row="0" column="0">
-     <layout class="QVBoxLayout" name="verticalLayout">
-      <item>
-       <widget class="QTabWidget" name="tabWidget">
-        <property name="currentIndex">
-         <number>0</number>
-        </property>
-        <widget class="QWidget" name="Bridge">
-         <attribute name="title">
-          <string>Bridge</string>
-         </attribute>
-         <layout class="QGridLayout" name="gridLayout_2">
-          <item row="0" column="0">
-           <widget class="QTableWidget" name="BridgeTable"/>
-          </item>
-         </layout>
-        </widget>
-        <widget class="QWidget" name="Controller">
-         <attribute name="title">
-          <string>Controller</string>
-         </attribute>
-         <layout class="QGridLayout" name="gridLayout_3">
-          <item row="0" column="0">
-           <widget class="QTableWidget" name="ControllerTable"/>
-          </item>
-         </layout>
-        </widget>
-        <widget class="QWidget" name="Interface">
-         <attribute name="title">
-          <string>Interface</string>
-         </attribute>
-         <layout class="QGridLayout" name="gridLayout_4">
-          <item row="0" column="0">
-           <widget class="QTableWidget" name="InterfaceTable"/>
-          </item>
-         </layout>
-        </widget>
-        <widget class="QWidget" name="Mirror">
-         <attribute name="title">
-          <string>Mirror</string>
-         </attribute>
-         <layout class="QGridLayout" name="gridLayout_5">
-          <item row="0" column="0">
-           <widget class="QTableWidget" name="MirrorTable"/>
-          </item>
-         </layout>
-        </widget>
-        <widget class="QWidget" name="NetFlow">
-         <attribute name="title">
-          <string>NetFlow</string>
-         </attribute>
-         <layout class="QGridLayout" name="gridLayout_6">
-          <item row="0" column="0">
-           <widget class="QTableWidget" name="NetFlowTable"/>
-          </item>
-         </layout>
-        </widget>
-        <widget class="QWidget" name="Open_vSwitch">
-         <attribute name="title">
-          <string>Open_vSwitch</string>
-         </attribute>
-         <layout class="QGridLayout" name="gridLayout_7">
-          <item row="0" column="0">
-           <widget class="QTableWidget" name="Open_vSwitchTable"/>
-          </item>
-         </layout>
-        </widget>
-        <widget class="QWidget" name="Port">
-         <attribute name="title">
-          <string>Port</string>
-         </attribute>
-         <layout class="QGridLayout" name="gridLayout_8">
-          <item row="0" column="0">
-           <widget class="QTableWidget" name="PortTable"/>
-          </item>
-         </layout>
-        </widget>
-        <widget class="QWidget" name="QoS">
-         <attribute name="title">
-          <string>QoS</string>
-         </attribute>
-         <layout class="QGridLayout" name="gridLayout_10">
-          <item row="0" column="0">
-           <widget class="QTableWidget" name="QoSTable"/>
-          </item>
-         </layout>
-        </widget>
-        <widget class="QWidget" name="Queue">
-         <attribute name="title">
-          <string>Queue</string>
-         </attribute>
-         <layout class="QGridLayout" name="gridLayout_11">
-          <item row="0" column="0">
-           <widget class="QTableWidget" name="QueueTable"/>
-          </item>
-         </layout>
-        </widget>
-        <widget class="QWidget" name="sFlow">
-         <attribute name="title">
-          <string>sFlow</string>
-         </attribute>
-         <layout class="QGridLayout" name="gridLayout_9">
-          <item row="0" column="0">
-           <widget class="QTableWidget" name="sFlowTable"/>
-          </item>
-         </layout>
-        </widget>
-        <widget class="QWidget" name="SSL">
-         <attribute name="title">
-          <string>SSL</string>
-         </attribute>
-         <layout class="QGridLayout" name="gridLayout_10">
-          <item row="0" column="0">
-           <widget class="QTableWidget" name="SSLTable"/>
-          </item>
-         </layout>
-        </widget>
-       </widget>
-      </item>
-      <item>
-       <layout class="QHBoxLayout" name="horizontalLayout">
-        <item>
-         <widget class="QLabel" name="hostLabel">
-          <property name="text">
-           <string>Host</string>
-          </property>
-          <property name="buddy">
-           <cstring>hostComboBox</cstring>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QComboBox" name="hostComboBox">
-          <property name="sizeAdjustPolicy">
-           <enum>QComboBox::AdjustToContents</enum>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QCheckBox" name="intervalCheckBox">
-          <property name="text">
-           <string>Auto-refetch every</string>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QSpinBox" name="intervalSpinBox">
-          <property name="suffix">
-           <string>s</string>
-          </property>
-          <property name="minimum">
-           <number>1</number>
-          </property>
-          <property name="maximum">
-           <number>1000000</number>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <spacer name="horizontalSpacer">
-          <property name="orientation">
-           <enum>Qt::Horizontal</enum>
-          </property>
-          <property name="sizeHint" stdset="0">
-           <size>
-            <width>40</width>
-            <height>20</height>
-           </size>
-          </property>
-         </spacer>
-        </item>
-        <item>
-         <widget class="QPushButton" name="fetchButton">
-          <property name="text">
-           <string>Refetch</string>
-          </property>
-         </widget>
-        </item>
-       </layout>
-      </item>
-     </layout>
-    </item>
-   </layout>
-  </widget>
-  <widget class="QMenuBar" name="menubar">
-   <property name="geometry">
-    <rect>
-     <x>0</x>
-     <y>0</y>
-     <width>800</width>
-     <height>28</height>
-    </rect>
-   </property>
-   <widget class="QMenu" name="menuFile">
-    <property name="title">
-     <string>File</string>
-    </property>
-    <addaction name="actionNew_DB_Window"/>
-    <addaction name="actionNew_Flow_Window"/>
-    <addaction name="actionShow_Log"/>
-    <addaction name="actionPreferences"/>
-    <addaction name="separator"/>
-    <addaction name="actionQuit"/>
-   </widget>
-   <addaction name="menuFile"/>
-  </widget>
-  <widget class="QStatusBar" name="statusbar"/>
-  <action name="actionShow_Log">
-   <property name="text">
-    <string>Show Log</string>
-   </property>
-  </action>
-  <action name="actionNew_DB_Window">
-   <property name="text">
-    <string>New DB Window</string>
-   </property>
-  </action>
-  <action name="actionPreferences">
-   <property name="text">
-    <string>Preferences</string>
-   </property>
-  </action>
-  <action name="actionQuit">
-   <property name="text">
-    <string>Quit</string>
-   </property>
-  </action>
-  <action name="actionNew_Flow_Window">
-   <property name="text">
-    <string>New Flow Window</string>
-   </property>
-  </action>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/ovsdb/ovsdbmonitor/OVEApp.py b/ovsdb/ovsdbmonitor/OVEApp.py
deleted file mode 100644 (file)
index 56b6b17..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-# Copyright (c) 2010 Citrix Systems, 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.
-#
-
-from OVEStandard import *
-from OVEConfig import *
-from OVEFetch import *
-
-from OVEConfigWindow import *
-from OVEFlowWindow import *
-from OVELogWindow import *
-from OVEMainWindow import *
-
-class OVEApp:
-    def __init__(self):
-        self.app = globalApp
-        self.app.setOrganizationName("Citrix_Systems_Inc")
-        self.app.setOrganizationDomain("citrix.com")
-        self.app.setApplicationName("ovsdbmonitor")
-        self.mainWindows = []
-        self.flowWindows = []
-        self.configWindow = None
-
-    def enter(self):
-        if len(OVEConfig.Inst().hosts) < 1:
-            self.showConfig(True)
-            QtGui.QMessageBox.information(
-                    None, "OVSDB Monitor",
-                    "This application browses openvswitch databases on remote hosts.  Please add one or more openvswitch hosts to continue")
-        self.loadMainWindows()
-        self.loadFlowWindows()
-        if len(self.mainWindows) == 0 and len(self.flowWindows) == 0:
-            self.newMainWindow()
-        self.newLogWindow()
-        # Reactor must be started after the event loop is running, so use a zero timeout
-        QtCore.QTimer.singleShot(0, OVEFetch.startReactor)
-        OVELog("Application started")
-        retCode = self.app.exec_()
-        index = 0
-        for mainWindow in self.mainWindows:
-            if mainWindow.isVisible():
-                mainWindow.saveSettings(index)
-                index += 1 # Indent intentional
-        OVEMainWindow.terminateSettings(index)
-        index = 0
-        for flowWindow in self.flowWindows:
-            if flowWindow.isVisible():
-                flowWindow.saveSettings(index)
-                index += 1 # Indent intentional            
-        OVEFlowWindow.terminateSettings(index)
-        self.logWindow.saveSettings()
-    
-    def quit(self):
-        self.app.quit()
-    
-    def showLog(self, value):
-        if value:
-            self.logWindow.hide()
-            self.logWindow.show()
-        else:
-            self.logWindow.hide()
-
-    def showConfig(self, value):
-        if value:
-            del self.configWindow
-            self.configWindow = OVEConfigWindow(self)
-            self.configWindow.show()
-        else:
-            self.configWindow.hide()
-
-    def newMainWindow(self, loadIndex = None):
-        self.mainWindows.append(OVEMainWindow(self, loadIndex))
-        self.mainWindows[-1].show()
-
-    def newFlowWindow(self, loadIndex = None):
-        self.flowWindows.append(OVEFlowWindow(self, loadIndex))
-        self.flowWindows[-1].show()
-
-    def newLogWindow(self):
-        self.logWindow = OVELogWindow(self)
-
-    def loadMainWindows(self):
-        for loadIndex in range(0, 100):
-            if OVEMainWindow.isLoadable(loadIndex):
-                self.newMainWindow(loadIndex)
-            else:
-                break
-
-    def loadFlowWindows(self):
-        for loadIndex in range(0, 100):
-            if OVEFlowWindow.isLoadable(loadIndex):
-                self.newFlowWindow(loadIndex)
-            else:
-                break
diff --git a/ovsdb/ovsdbmonitor/OVECommonWindow.py b/ovsdb/ovsdbmonitor/OVECommonWindow.py
deleted file mode 100644 (file)
index 5c014b7..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-# Copyright (c) 2010 Citrix Systems, 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.
-
-from OVEStandard import *
-from OVEConfig import *
-from OVEFetch import *
-from OVELogger import *
-from OVEUtil import *
-
-from Ui_MainWindow import *
-
-class OVECommonWindow:
-    def __init__(self, app, loadIndex = None):
-        self.app = app
-        self.intervalTimerId = None        
-        self.hostUuid = ''
-        self.intervalChecked = True
-        self.intervalSeconds = 5
-        self.fetchSkip = 0
-        self.currentRef = self.BASE_REF
-                
-        self.ui.setupUi(self)
-        
-        if loadIndex is not None:
-            self.loadSettings(loadIndex)
-        
-        self.connect(self.ui.actionNew_DB_Window, QtCore.SIGNAL("triggered()"), self.xon_actionNew_DB_Window_triggered)
-        self.connect(self.ui.actionNew_Flow_Window, QtCore.SIGNAL("triggered()"), self.xon_actionNew_Flow_Window_triggered)
-        self.connect(self.ui.actionShow_Log, QtCore.SIGNAL("triggered()"), self.xon_actionShow_Log_triggered)
-        self.connect(self.ui.actionPreferences, QtCore.SIGNAL("triggered()"), self.xon_actionPreferences_triggered)
-        self.connect(self.ui.actionQuit, QtCore.SIGNAL("triggered()"), self.xon_actionQuit_triggered)
-        self.connect(self.ui.fetchButton, QtCore.SIGNAL("clicked()"), self.xon_fetchButton_clicked)
-        self.connect(self.ui.tabWidget, QtCore.SIGNAL("currentChanged(int)"), self.xon_tabWidget_currentChanged)
-        self.connect(self.ui.hostComboBox, QtCore.SIGNAL("currentIndexChanged(int)"), self.xon_hostComboBox_currentIndexChanged)
-        self.connect(self.ui.intervalCheckBox, QtCore.SIGNAL("stateChanged(int)"), self.xon_intervalCheckBox_stateChanged)
-        self.connect(self.ui.intervalSpinBox, QtCore.SIGNAL("valueChanged(int)"), self.xon_intervalSpinBox_valueChanged)
-        self.connect(OVEConfig.Inst(), QtCore.SIGNAL("configUpdated()"), self.xon_configUpdated)
-        
-        self.updateHosts()
-        self.updateInterval()
-        self.updateIntervalState()
-        self.updateTable()
-        
-    def xon_actionNew_DB_Window_triggered(self):
-        self.app.newMainWindow()
-    def xon_actionNew_Flow_Window_triggered(self):
-        self.app.newFlowWindow()
-
-    def xon_actionShow_Log_triggered(self):
-        self.app.showLog(True)
-
-    def xon_actionPreferences_triggered(self):
-        self.app.showConfig(True)
-
-    def xon_actionQuit_triggered(self):
-        self.app.quit()
-    
-    def xon_tabWidget_currentChanged(self, value):
-        self.updateTable()
-        
-    def xon_fetchButton_clicked(self):
-        self.updateTable()
-    
-    def xon_configUpdated(self):
-        self.updateHosts()
-    
-    def xon_hostComboBox_currentIndexChanged(self, index):
-        if (index >= 0):
-            itemData = self.ui.hostComboBox.itemData(index)
-            self.hostUuid = str(itemData.toString())
-            self.deleteCurrentTable()
-            self.updateTable()
-    
-    def xon_intervalCheckBox_stateChanged(self, state):
-        self.intervalChecked = (state == Qt.Checked)
-        self.updateIntervalState()
-    
-    def xon_intervalSpinBox_valueChanged(self, value):
-        self.intervalSeconds = value
-        self.updateIntervalState()
-    
-    def updateIntervalState(self):
-        if self.intervalTimerId is not None:
-            self.killTimer(self.intervalTimerId)
-        if self.intervalChecked:
-            self.intervalTimerId = self.startTimer(1000*self.intervalSeconds)
-    
-    def updateHosts(self):
-        currentHostUuid = self.hostUuid # self.hostUuid will change due to currentIndexChanged events as we rebuild the combo box
-        self.hostUuid = ''
-        self.ui.hostComboBox.clear()
-        for i, host in enumerate(OVEConfig.Inst().hosts):
-            self.ui.hostComboBox.addItem(host['address'], QVariant(host['uuid']))
-            if host['uuid'] == currentHostUuid:
-                # This is the currently selected host
-                self.ui.hostComboBox.setCurrentIndex(i)
-        if len(OVEConfig.Inst().hosts) == 0:
-            self.ui.hostComboBox.addItem('(No hosts configured)', QVariant(''))
-            
-    def updateInterval(self):
-        self.ui.intervalCheckBox.setChecked(self.intervalChecked)
-        self.ui.intervalSpinBox.setValue(self.intervalSeconds)
-    def handleFetchEvent(self, ref, values):
-        OVELog('Unhandled FetchEvent')
-    def handleFetchFailEvent(self, ref, message):
-        OVELog('Unhandled FetchFailEvent')
-    def setFetchSkip(self):
-        # Call before sending a request via OVEFetch
-        self.fetchSkip = 6
-    def timerEvent(self, event):
-        if event.timerId() == self.intervalTimerId:
-            if self.fetchSkip > 0:
-                self.statusBar().showMessage('Fetch stalled... resend in '+str(self.fetchSkip*self.intervalSeconds)+'s') 
-                self.fetchSkip -= 1
-                if self.fetchSkip == 0:
-                    # Stall has timed out. The connection might have hung so reset.  Seems to happen with PySide only
-                    OVEFetch.Inst(self.hostUuid).resetTransport()
-            else:
-                self.updateTable()
-        else:
-            QtGui.QMainWindow.timerEvent(self, event)
-    def customEvent(self, event):
-        if event.type() == OVEFetchEvent.TYPE:
-            if isinstance(event, OVEFetchEvent):
-                # The right way to get data
-                ref = event.ref
-                values = event.data
-            else:
-                # Workaround for PySide issue
-                ref = OVEFetch.Inst(self.hostUuid).snoopRef(self)
-                values = OVEFetch.Inst(self.hostUuid).snoopValues(self)
-            try:
-                if ref == self.currentRef:
-                    self.fetchSkip = 0
-                    self.currentRef += 1 # PySide workaround
-                    self.handleFetchEvent(ref, values)
-                else:
-                    # If refs don't match this event relates to a request before the current one.  We've moved
-                    # on since then, e.g. changed the table we've viewing, so ignore it
-                    if OVEConfig.Inst().logTraffic:
-                        OVELog('FetchEvent ref mismatch '+str(ref)+' != '+str(self.currentRef))
-            except Exception, e:
-                OVELog("Error during data handling: "+str(e))
-
-        elif event.type() == OVEFetchFailEvent.TYPE:
-            if isinstance(event, OVEFetchFailEvent):
-                # The right way to get data
-                ref = event.ref
-                message = event.message
-            else:
-                # Workaround for PySide issue
-                ref = OVEFetch.Inst(self.hostUuid).snoopRef(self)
-                message = OVEFetch.Inst(self.hostUuid).snoopMessage(self)
-            if message is not None:
-                OVELog(message)
-            if ref == self.currentRef:
-                self.fetchSkip = 0
-                self.currentRef += 1 # PySide workaround
-                self.handleFetchFailEvent(ref, message)
-            else:
-                if OVEConfig.Inst().logTraffic:
-                    OVELog('FetchFailEvent ref mismatch '+str(ref)+' != '+str(self.currentRef))
-    def deleteCurrentTable(self):
-        pass
-    def saveSettings(self, index):
-        key = self.LOAD_KEY+str(index)
-        settings = QtCore.QSettings()
-        settings.setValue(key+"/loadable", QVariant(True))
-        settings.setValue(key+"/pos", QVariant(self.pos()))
-        settings.setValue(key+"/size", QVariant(self.size()))
-        settings.setValue(key+"/hostUuid", QVariant(self.hostUuid))
-        settings.setValue(key+"/intervalChecked", QVariant(self.intervalChecked))
-        settings.setValue(key+"/intervalSeconds", QVariant(self.intervalSeconds))
-
-        return settings, key
-    
-    def loadSettings(self, index):
-        key = self.LOAD_KEY+str(index)
-        settings = QtCore.QSettings()
-        pos = settings.value(key+"/pos", QVariant(QtCore.QPoint(200, 200))).toPoint()
-        size = settings.value(key+"/size", QVariant(QtCore.QSize(400, 400))).toSize();
-
-        self.hostUuid = str(settings.value(key+"/hostUuid", QVariant('Unloaded')).toString())
-        self.intervalChecked = settings.value(key+"/intervalChecked", QVariant(True)).toBool()
-        self.intervalSeconds = settings.value(key+"/intervalSeconds", QVariant(5)).toInt()[0]
-        self.resize(size)
-        self.move(pos)
-        return settings, key
-
-    @classmethod
-    def terminateSettings(self, index):
-        key = self.LOAD_KEY+str(index)
-        settings = QtCore.QSettings()
-        settings.setValue(key+"/loadable", QVariant(False))
-        settings.sync()
-        
-    @classmethod
-    def isLoadable(cls, index):
-        key = cls.LOAD_KEY+str(index)
-        settings = QtCore.QSettings()
-        return settings.value(key+"/loadable", QVariant(False)).toBool()
-        
diff --git a/ovsdb/ovsdbmonitor/OVEConfig.py b/ovsdb/ovsdbmonitor/OVEConfig.py
deleted file mode 100644 (file)
index 9520ae7..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-# Copyright (c) 2011 Nicira, Inc.
-# Copyright (c) 2010 Citrix Systems, 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.
-
-from OVEStandard import *
-from OVELogger import *
-import ovs.json
-
-def str_recursive(x):
-    t = type(x)
-    if t == unicode:
-        return str(x)
-    elif t == list:
-        return [str_recursive(_) for _ in x]
-    elif t == dict:
-        out = {}
-        for k,v in x.iteritems():
-            out[str_recursive(k)] = str_recursive(v)
-        return out
-    else:
-        return x
-
-class OVEConfig(QtCore.QObject):
-    instance = None
-    def __init__(self):
-        QtCore.QObject.__init__(self)
-        self.hosts = []
-        self.logTraffic = True
-        self.truncateUuids = True
-        self.ssgList = []
-        
-    @classmethod
-    def Inst(cls):
-        if cls.instance is None:
-            cls.instance = OVEConfig()
-            cls.instance.loadConfig()
-        return cls.instance
-
-    def hostFromUuid(self, uuid):
-        for host in self.hosts:
-            if host['uuid'] == uuid:
-                return host
-        OVELog("+++ Couldn't find host '"+str(uuid)+"' in "+str([x['uuid'] for x in self.hosts]))
-        return None
-
-    def saveConfig(self):
-        settings = QtCore.QSettings()
-        settings.setValue('config/hosts', QVariant(ovs.json.to_string((self.hosts))))
-        settings.setValue('config/logTraffic', QVariant(self.logTraffic))
-        settings.setValue('config/truncateUuids', QVariant(self.truncateUuids))
-        settings.setValue('config/ssgList', QVariant(ovs.json.to_string(self.ssgList)))
-        settings.sync()
-        self.emitUpdated()
-
-    def loadConfig(self):
-        settings = QtCore.QSettings()
-        jsonText = unicode(settings.value('config/hosts', QVariant('[]')).toString())
-        self.hosts = str_recursive(ovs.json.from_string(str(jsonText)))
-        self.logTraffic = settings.value('config/logTraffic', QVariant(False)).toBool()
-        self.truncateUuids = settings.value('config/truncateUuids', QVariant(False)).toBool()
-        jsonText = unicode(settings.value('config/ssgList', QVariant('[]')).toString())
-        self.ssgList = ovs.json.from_string(str(jsonText))
-        if len(self.ssgList) == 0:
-            self.ssgList = [
-                r'in_port0000',
-                r'in_port0001',
-                r'in_port0002',
-                r'in_port0003',
-                r'vlan65535',
-                r'type0800',
-                r'type0806',
-                r'proto0',
-                r'proto6',
-                r'proto17',
-                r'ff:ff:ff:ff:ff:ff',
-                r'!ff:ff:ff:ff:ff:ff',
-                r'0\.0\.0\.0',
-                r'!0\.0\.0\.0',
-                r'255\.255\.255\.255',
-                r'!255\.255\.255\.255',
-                r'never',
-                r'drop',
-                r'!never',
-                r'!drop',
-                r'(never|drop)',
-                r'!(never|drop)'
-            ]
-        
-    def emitUpdated(self):
-        self.emit(QtCore.SIGNAL("configUpdated()"))
diff --git a/ovsdb/ovsdbmonitor/OVEConfigWindow.py b/ovsdb/ovsdbmonitor/OVEConfigWindow.py
deleted file mode 100644 (file)
index b5b8d70..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-# Copyright (c) 2010 Citrix Systems, 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.
-
-from OVEStandard import *
-from OVEConfig import *
-from OVELogger import *
-from Ui_ConfigWindow import *
-
-from OVEHostWindow import *
-
-class OVEConfigWindow(QtGui.QDialog):
-    def __init__(self, app):
-        QtGui.QDialog.__init__(self)
-        self.app = app
-        self.ui = Ui_ConfigWindow()
-        self.ui.setupUi(self)
-
-        self.connect(self.ui.hostAddButton, QtCore.SIGNAL("clicked()"), self.xon_hostAddButton_clicked)
-        self.connect(self.ui.hostEditButton, QtCore.SIGNAL("clicked()"), self.xon_hostEditButton_clicked)
-        self.connect(self.ui.hostDeleteButton, QtCore.SIGNAL("clicked()"), self.xon_hostDeleteButton_clicked)
-        self.connect(self.ui.buttonBox, QtCore.SIGNAL("clicked(QAbstractButton *)"), self.xon_actionButton_Box_clicked)
-        self.connect(self.ui.hostList, QtCore.SIGNAL("currentItemChanged(QListWidgetItem *,  QListWidgetItem *)"), self.xon_hostList_currentItemChanged)
-        self.connect(self.ui.logTrafficCheckBox, QtCore.SIGNAL("stateChanged(int)"), self.xon_logTrafficCheckBox_stateChanged)
-        self.connect(self.ui.truncateUuidsCheckBox, QtCore.SIGNAL("stateChanged(int)"), self.xon_truncateUuidsCheckBox_stateChanged)
-        self.readConfig()
-        self.updateWidgets()
-    
-    def handleHostWindowRecord(self, record, isEdit):
-        if record['accepted'] and record['address'].strip() != '':
-            currentRow = self.ui.hostList.currentRow()
-            if isEdit:
-                self.configHosts[currentRow] = record
-            else:
-                self.configHosts.append(record)
-
-        self.updateWidgets()
-
-    def xon_hostAddButton_clicked(self):
-        hostWindow = OVEHostWindow(self)
-        hostWindow.exec_()
-        self.handleHostWindowRecord(hostWindow.record(), False)
-
-    def xon_hostEditButton_clicked(self):
-        if self.ui.hostList.currentItem() is None:
-            pass # OVELog('No item to edit')
-        else:
-            currentRow = self.ui.hostList.currentRow()
-            hostWindow = OVEHostWindow(self, self.configHosts[currentRow])
-            hostWindow.exec_()
-            self.handleHostWindowRecord(hostWindow.record(), True)
-
-    def xon_hostDeleteButton_clicked(self):
-        if self.ui.hostList.currentItem() is not None:
-            currentRow = self.ui.hostList.currentRow()
-            del self.configHosts[currentRow]
-            self.updateWidgets()
-
-    def xon_actionButton_Box_clicked(self, button):
-        role = self.ui.buttonBox.buttonRole(button)
-        if role == QtGui.QDialogButtonBox.AcceptRole:
-            self.writeConfig()
-            self.close()
-        elif role == QtGui.QDialogButtonBox.ApplyRole:
-            self.writeConfig()
-        elif role == QtGui.QDialogButtonBox.RejectRole:
-            if self.configChanged():
-                self.close()
-            else:
-                ret = QtGui.QMessageBox.warning(
-                    self, "OVSDB Monitor",
-                    "Changes not applied. Discard?",
-                    QtGui.QMessageBox.Discard | QtGui.QMessageBox.Cancel | QtGui.QMessageBox.Apply,
-                    QtGui.QMessageBox.Discard)
-                
-                if ret == QtGui.QMessageBox.Apply:
-                    self.writeConfig()
-                if ret != QtGui.QMessageBox.Cancel:
-                    self.close()
-
-    def xon_hostList_currentItemChanged(self, current, previous):
-        editable = (current is not None)
-        self.ui.hostEditButton.setEnabled(editable)
-        self.ui.hostDeleteButton.setEnabled(editable)
-
-    def xon_logTrafficCheckBox_stateChanged(self, value):
-        self.configLogTraffic = (value == Qt.Checked)
-    
-    def xon_truncateUuidsCheckBox_stateChanged(self, value):
-        self.configTruncateUuids = (value == Qt.Checked)
-    
-    def updateWidgets(self):
-        self.ui.hostList.clear()
-        for host in self.configHosts:
-            self.ui.hostList.addItem(host['address'])
-        self.ui.logTrafficCheckBox.setChecked(self.configLogTraffic)
-        self.ui.truncateUuidsCheckBox.setChecked(self.configTruncateUuids)
-
-    def configChanged(self):
-        return (
-            (self.configHosts == OVEConfig.Inst().hosts) and
-            (self.configLogTraffic == (OVEConfig.Inst().logTraffic))and
-            (self.configTruncateUuids == (OVEConfig.Inst().truncateUuids))
-        )
-        
-    def readConfig(self):
-        self.configHosts = deepcopy(OVEConfig.Inst().hosts)
-        self.configLogTraffic = OVEConfig.Inst().logTraffic
-        self.configTruncateUuids = OVEConfig.Inst().truncateUuids
-        
-    def writeConfig(self):
-        OVEConfig.Inst().hosts = deepcopy(self.configHosts)
-        OVEConfig.Inst().logTraffic = self.configLogTraffic
-        OVEConfig.Inst().truncateUuids = self.configTruncateUuids
-        OVEConfig.Inst().saveConfig()
-
-    
diff --git a/ovsdb/ovsdbmonitor/OVEFetch.py b/ovsdb/ovsdbmonitor/OVEFetch.py
deleted file mode 100644 (file)
index 0beafe7..0000000
+++ /dev/null
@@ -1,388 +0,0 @@
-# Copyright (c) 2011 Nicira, Inc.
-# Copyright (c) 2010 Citrix Systems, 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.
-
-from OVEStandard import *
-from OVEConfig import *
-from OVELogger import *
-import ovs.json
-
-# This sequence installs the qt4reactor before twisted gets a chance to install its reactor
-import qt4reactor
-globalApp = QtGui.QApplication([])
-qt4reactor.install()
-
-try:
-    from twisted.conch.ssh import transport, userauth, connection, common, keys, channel
-    from twisted.internet import defer, protocol, reactor
-    from twisted.application import reactors
-except Exception, e:
-    print('+++ Python Twisted Conch module is required\n')
-    raise
-
-class OVEFetchUserAuth(userauth.SSHUserAuthClient):
-    def __init__(self, fetch, *params):
-        userauth.SSHUserAuthClient.__init__(self, *params)
-        self.fetch = fetch
-        self.authFails = 0
-    
-    def getPassword(self):
-        return defer.succeed(self.fetch.config()['password'])
-
-    def ssh_USERAUTH_FAILURE(self, packet):
-        if self.authFails > 0: # We normally get one so ignore.  Real failures send these repeatedly
-            OVELog('Authentication failure for '+self.fetch.config()['address'])
-        self.authFails += 1
-        userauth.SSHUserAuthClient.ssh_USERAUTH_FAILURE(self, packet)
-
-class OVEFetchConnection(connection.SSHConnection, QtCore.QObject):
-    def __init__(self, fetch, *params):
-        connection.SSHConnection.__init__(self, *params)
-        QtCore.QObject.__init__(self)
-        self.fetch = fetch
-        self._channel = None
-        self._oldChannels = []
-        
-    def serviceStarted(self):
-        self.emit(QtCore.SIGNAL('connectionService(QObject)'), self)
-
-    def serviceStopped(self):
-        self.emit(QtCore.SIGNAL('connectionService(QObject)'), None)
-
-    def execCommand(self, requester, ref, command, commandType):
-        if self._channel is not None:
-            # Don't delete old channels immediately in case they're e.g. going to time out with a failure
-            self._oldChannels.append(self._channel)
-            if len(self._oldChannels) > 90:
-                # For 30 second timeouts at 1 second refresh interval and three windows open on a single host, need 90 channels
-                del self._oldChannels[1]
-        self._channel = OVECommandChannel(self.fetch, requester, ref, command, commandType, 2**16, 2**15, self)
-        self.openChannel(self._channel)
-
-    def connectionLost(self, reason):
-        if self._channel is not None:
-            self._channel.connectionLost(reason)
-
-class OVEFetchTransport(transport.SSHClientTransport, QtCore.QObject):
-    def __init__(self, fetch, *params):
-        # There is no __init__ method for this class
-        # transport.SSHClientTransport.__init__(self, *params)
-        
-        QtCore.QObject.__init__(self)
-        self.fetch = fetch
-        self._connection = None
-        self.connect(self, QtCore.SIGNAL('channelFailure(QObject, int, QString, QString, QString)'), self.fetch.xon_channelFailure)
-        
-    def verifyHostKey(self, hostKey, fingerprint):
-        return defer.succeed(1)
-
-    def connectionSecure(self):
-        self._connection = OVEFetchConnection(self.fetch)
-        QtCore.QObject.connect(self._connection, QtCore.SIGNAL('connectionService(QObject)'), self.fetch.xon_connectionService)
-        self.requestService(
-            OVEFetchUserAuth(self.fetch, self.fetch.config().get('username', 'root'),
-                self._connection))
-
-    def connectionLost(self, reason):
-        if self._connection is not None:
-            self._connection.connectionLost(reason)
-
-class OVEFetchWrapper:
-    def __init__(self, contents):
-        self.contents = contents
-
-class OVECommandChannel(channel.SSHChannel, QtCore.QObject):
-    name = 'session'
-    MSEC_TIMEOUT=10000
-    STATUS_CONNECTION_LOST = 100001
-    STATUS_TIMEOUT = 100002
-    END_MARKER='END-MARKER'
-    END_MARKER_RE=re.compile(r'^END-MARKER$', re.MULTILINE)
-    
-    def __init__(self, fetch, requester, ref, command, commandType, *params):
-        channel.SSHChannel.__init__(self, *params)
-        QtCore.QObject.__init__(self)        
-        self.fetch = fetch
-        self.requester = requester
-        self.ref = ref
-        self.command = command
-        self.commandType= commandType
-        self._data = ''
-        self._extData = ''
-        self._jsonValues = None
-        self._timerId = None
-        self._status = None
-        self.connect(self, QtCore.SIGNAL('channelData(QObject, int, QString)'), self.fetch.xon_channelData)
-        self.connect(self, QtCore.SIGNAL('channelExtData(QObject, int, QString)'), self.fetch.xon_channelExtData)
-        self.connect(self, QtCore.SIGNAL('channelSuccess(QObject, int, QString, QString, QVariant)'), self.fetch.xon_channelSuccess)
-        self.connect(self, QtCore.SIGNAL('channelFailure(QObject, int, QString, QString, QString)'), self.fetch.xon_channelFailure)
-        
-    def openFailed(self, reason):
-        if self._timerId is not None:
-            self.killTimer(self._timerId)
-        self.emit(QtCore.SIGNAL('channelFailure(QObject, int, QString, QString, QString)'), self.requester, self.ref,
-            'Open failed:'+str(reason), '', '')
-
-    def channelOpen(self, ignoredData):
-        try:
-            nsCommand = common.NS(str(self.command))
-            self._timerId = self.startTimer(self.MSEC_TIMEOUT)
-            self.conn.sendRequest(self, 'exec', nsCommand, wantReply=1)
-        except Exception, e:
-            self.emit(QtCore.SIGNAL('channelFailure(QObject, int, QString, QString, QString)'), self.requester, self.ref,
-                'Open failed:'+str(e), self._data, self._extData)
-            
-    def dataReceived(self, data):
-        self._data += data
-        if OVEConfig.Inst().logTraffic:
-            self.emit(QtCore.SIGNAL('channelData(QObject, int, QString)'), self.requester, self.ref, data)
-        self.testIfDone()
-        
-    def extDataReceived(self, extData):
-        self._extData += extData
-        if OVEConfig.Inst().logTraffic:
-            self.emit(QtCore.SIGNAL('channelExtData(QObject, int, QString)'), self.requester, self.ref, extData)
-
-    def request_exit_status(self, data):
-        # We can get the exit status before the data, so delay calling sendResult until we get both
-        self._status = struct.unpack('>L', data)[0]
-        self.testIfDone()
-        
-    def testIfDone(self):
-        if self._status is not None:
-            if self._status != 0:
-                self.sendResult() # Failed, so send what we have
-            elif len(self._data) > 0:
-                # Status == success and we have some data
-                if self.commandType == 'JSON':
-                    try:
-                        # Decode the JSON data, to confirm that we have all of the data
-                        self._jsonValues = ovs.json.from_string(str(self._data)) # FIXME: Should handle unicode
-                        self.sendResult()
-                    except:
-                        pass # Wait for more data
-                elif self.commandType == 'framed':
-                    match = self.END_MARKER_RE.search(self._data)
-                    if match:
-                        self._data = self._data[:match.start()] # Remove end marker
-                        self.sendResult()
-                else:
-                    OVELog('Bad command type')
-
-    def sendResult(self):
-        if self._timerId is not None:
-            self.killTimer(self._timerId)
-        if self.commandType == 'JSON' and self._status == 0 and self._jsonValues is not None:
-            self.emit(QtCore.SIGNAL('channelSuccess(QObject, int, QString, QString, QVariant)'), self.requester, self.ref, self._data, self._extData, QVariant(OVEFetchWrapper(self._jsonValues)))
-        elif self.commandType != 'JSON' and self._status == 0:
-            self.emit(QtCore.SIGNAL('channelSuccess(QObject, int, QString, QString, QVariant)'), self.requester, self.ref, self._data, self._extData, QVariant(None))
-        else:
-            self.emit(QtCore.SIGNAL('channelFailure(QObject, int, QString, QString, QString)'), self.requester, self.ref, 'Remote command failed (rc='+str(self._status)+')', self._data, self._extData)
-        if self._status != self.STATUS_CONNECTION_LOST:
-            try:
-                self.loseConnection()
-            except Exception, e:
-                OVELog('OVECommandChannel.sendResult loseConnection error: '+str(e))
-
-    def connectionLost(self, reason):
-        self._extData += '+++ Connection lost'
-        self._status = self.STATUS_CONNECTION_LOST
-        self.sendResult()
-
-    def timerEvent(self, event):
-        if event.timerId() == self._timerId:
-            self._extData += '+++ Timeout'
-            self._status = self.STATUS_TIMEOUT
-            self.sendResult()
-        else:
-            QtCore.QObject.timerEvent(self, event)
-
-class OVEFetchEvent(QtCore.QEvent):
-    TYPE = QtCore.QEvent.Type(QtCore.QEvent.registerEventType())
-    def __init__(self, ref, data):
-        QtCore.QEvent.__init__(self, self.TYPE)
-        self.ref = ref
-        self.data = data
-
-class OVEFetchFailEvent(QtCore.QEvent):
-    TYPE = QtCore.QEvent.Type(QtCore.QEvent.registerEventType())
-    def __init__(self, ref, message):
-        QtCore.QEvent.__init__(self, self.TYPE)
-        self.ref = ref
-        self.message = str(message)
-
-class OVEFetch(QtCore.QObject):
-    instances = {}
-    SEC_TIMEOUT = 10.0
-    
-    def __init__(self, uuid):
-        QtCore.QObject.__init__(self)
-        self._hostUuid = uuid
-        self._config = None
-        self._transport = None
-        self._connection = None
-        self._commandQueue = []
-        self._timerRef = 0
-        self.refs = {}
-        self.messages = {}
-        self.values = {}
-        self.connect(OVEConfig.Inst(), QtCore.SIGNAL("configUpdated()"), self.xon_configUpdated)
-        
-    @classmethod
-    def Inst(cls, uuid):
-        if uuid not in cls.instances:
-            cls.instances[uuid] = OVEFetch(uuid)
-        return cls.instances[uuid]
-
-    @classmethod
-    def startReactor(cls):
-        reactor.runReturn()
-
-    def xon_configUpdated(self):
-        self._config = None
-        self.resetTransport()
-        
-    def xon_connectionService(self, connection):
-        self._connection = connection
-        if self._connection is not None:
-            OVELog('SSH connection to '+self.config()['address'] +' established')
-            for command in self._commandQueue:
-                # OVELog('Unqueueing '+str(command))
-                self.execCommand2(*command)
-            self._commandQueue = []
-
-    def xon_channelData(self, requester, ref, data):
-        if OVEConfig.Inst().logTraffic:
-            OVELog('Channel data received: '+str(data))
-
-    def xon_channelExtData(self, requester, ref, data):
-        if OVEConfig.Inst().logTraffic:
-            OVELog('+++ Channel extData (stderr) received: '+str(data))
-
-    def xon_channelFailure(self, requester, ref, message, data, extData):
-        if OVEConfig.Inst().logTraffic:
-            OVELog('+++ Channel failure: '+str(message))
-            OVELog("Closing SSH session due to failure")
-
-        errMessage = message
-        if len(data) > 0:
-            errMessage += '\n+++ Failed command output: '+data
-        if len(extData) > 0:
-            errMessage += '\n+++ Failed command output (stderr): '+extData
-
-        self.refs[requester] = ref # For PySide workaround
-        self.messages[requester] = errMessage # For PySide workaround
-        event = OVEFetchFailEvent(ref, errMessage)
-        QtCore.QCoreApplication.postEvent(requester, event)
-        self.resetTransport()
-        
-    def xon_channelSuccess(self, requester, ref, data, extData, jsonValueVariant):
-        jsonValues = jsonValueVariant.toPyObject()
-        if OVEConfig.Inst().logTraffic:
-            OVELog('--- Channel success')
-        try:
-            if jsonValues is not None:
-                values = jsonValues.contents
-            else:
-                values = str(data)
-
-            self.refs[requester] = ref # For PySide workaround
-            self.values[requester] = values # For PySide workaround
-            event = OVEFetchEvent(ref, values)
-            QtCore.QCoreApplication.postEvent(requester, event)
-        except Exception, e:
-            message = ('+++ Failed to decode JSON reply: '+str(e))
-            if len(data) > 0: message += "\n++++++ Data (stdout): "+str(data)
-            if len(extData) > 0: message += '\n++++++ Error (stderr): '+str(extData)
-            self.refs[requester] = ref # For PySide workaround
-            self.messages[requester] = message # For PySide workaround
-            event = OVEFetchFailEvent(ref, message)
-            QtCore.QCoreApplication.postEvent(requester, event)
-
-    # Use for workaround only
-    def snoopRef(self, requester):
-        return self.refs.get(requester, None)
-
-    # Use for workaround only
-    def snoopValues(self, requester):
-        return self.values.get(requester, None)
-
-    # Use for workaround only
-    def snoopMessage(self, requester):
-        return self.messages.get(requester, None)
-
-    def config(self):
-        if self._config is None:
-            self._config = OVEConfig.Inst().hostFromUuid(self._hostUuid)
-
-        return self._config
-    
-    def resetTransport(self):
-        if OVEConfig.Inst().logTraffic:
-            OVELog('Transport reset for '+self.config()['address'])
-        del self._connection
-        del self._transport
-        self._connection = None
-        self._transport = None
-        
-    def transportErrback(self, failure, requester, ref, address):
-        self._timerRef += 1 # Prevent timeout handling
-        self.resetTransport()
-        message = 'Failure connecting to '+address+': '+failure.getErrorMessage()
-        self.refs[requester] = ref # For PySide workaround
-        self.messages[requester] = message # For PySide workaround
-        event = OVEFetchFailEvent(ref, message)
-        QtCore.QCoreApplication.postEvent(requester, event)        
-        
-    def transportTimeout(self, timerRef, requester, ref, address):
-        if self._timerRef == timerRef and self._transport is not None and self._connection is None:
-            message = 'Connection attempt to ' +address+' timed out'
-            self.refs[requester] = ref # For PySide workaround
-            self.messages[requester] = message # For PySide workaround
-            event = OVEFetchFailEvent(ref, message)
-            QtCore.QCoreApplication.postEvent(requester, event)        
-            self.resetTransport()
-
-    def execCommand(self, requester, ref, command, commandType):
-        if OVEConfig.Inst().logTraffic:
-            hostName = (self.config() or {}).get('address', '<Address not set>')
-            OVELog(str(QtCore.QTime.currentTime().toString())+' '+hostName+': Executing '+command)
-        if self._transport is None:
-            self._connection = None
-            self._commandQueue.append((requester, ref, command, commandType))
-            config = self.config()
-            creator = protocol.ClientCreator(reactor, OVEFetchTransport, self)
-            self._transport = creator.connectTCP(config['address'], config.get('port', 22), timeout = self.SEC_TIMEOUT)
-            self._transport.addErrback(self.transportErrback, requester, ref, config['address'])
-            self._timerRef += 1
-            # Set this timer slightly longer than the twisted.conch timeout, as transportErrback can cancel
-            # the timeout and prevent double handling
-            # lambda timerRef = self._timerRef: takes a copy of self._timerRef
-            QtCore.QTimer.singleShot(int((1+self.SEC_TIMEOUT) * 1000), lambda timerRef = self._timerRef: self.transportTimeout(timerRef, requester, ref, config['address']))
-        else:
-            self.execCommand2(requester, ref, command, commandType)
-
-    def execCommand2(self, requester, ref, command, commandType):
-        if self._connection is None:
-            self._commandQueue.append((requester, ref, command, commandType))
-        else:
-            self._connection.execCommand(requester, ref, command, commandType)
-
-    def getTable(self, requester, tableName, ref = QtCore.QObject()):
-        command = '/usr/bin/ovsdb-client transact '+self.config()['connectTarget']+' \'["Open_vSwitch", {"op":"select","table":"'+tableName+'", "where":[]}]\''
-
-        self.execCommand(requester, ref, command, 'JSON')
-        
-    def execCommandFramed(self, requester, ref, command):
-        self.execCommand(requester, ref, command + ' && echo ' + OVECommandChannel.END_MARKER, 'framed')
diff --git a/ovsdb/ovsdbmonitor/OVEFlowWindow.py b/ovsdb/ovsdbmonitor/OVEFlowWindow.py
deleted file mode 100644 (file)
index caf6533..0000000
+++ /dev/null
@@ -1,327 +0,0 @@
-# Copyright (c) 2011 Nicira, Inc.
-# Copyright (c) 2010 Citrix Systems, 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.
-
-from OVEStandard import *
-from OVEConfig import *
-from OVEFetch import *
-from OVELogger import *
-from OVEUtil import *
-
-from OVECommonWindow import *
-
-from Ui_FlowWindow import *
-
-import re
-
-class OVEFlowWindow(QtGui.QMainWindow, OVECommonWindow):
-    LOAD_KEY = 'FlowWindow/window'
-    COMMAND_OVS_DPCTL='/usr/bin/ovs-dpctl'
-    BASE_REF=200000
-    
-    def __init__(self, app, loadIndex = None):
-        QtGui.QMainWindow.__init__(self)
-        self.ui = Ui_FlowWindow()
-        self.dpNames = []
-        self.dpTables = []
-        self.currentOpIndex = None
-        self.resizeCount = []
-        self.ssgChecked = False
-        self.ssgText = ''
-        self.lastTime = None
-        self.lastByteCount = 0
-        OVECommonWindow.__init__(self, app, loadIndex)
-
-        self.updateSsgList()
-        self.updateDatapaths()
-        self.updateSsgState()
-
-        self.connect(self.ui.fetchPathsButton, QtCore.SIGNAL("clicked()"), self.xon_fetchPathsButton_clicked)
-        self.connect(self.ui.ssgSaveButton, QtCore.SIGNAL("clicked()"), self.xon_ssgSaveButton_clicked)
-        self.connect(self.ui.ssgDeleteButton, QtCore.SIGNAL("clicked()"), self.xon_ssgDeleteButton_clicked)
-        self.connect(self.ui.ssgComboBox, QtCore.SIGNAL("activated(int)"), self.xon_ssgComboBox_activated)
-        self.connect(self.ui.ssgComboBox, QtCore.SIGNAL("editTextChanged(QString)"), self.xon_ssgComboBox_editTextChanged)
-        self.connect(self.ui.ssgCheckBox, QtCore.SIGNAL("stateChanged(int)"), self.xon_ssgCheckBox_stateChanged)
-        
-    
-    def xon_fetchPathsButton_clicked(self):
-        self.updateDatapaths()
-    
-    def xon_hostComboBox_currentIndexChanged(self, index):
-        OVECommonWindow.xon_hostComboBox_currentIndexChanged(self, index)
-        if (index >= 0):
-            self.updateDatapaths()
-    
-    def xon_ssgSaveButton_clicked(self):
-        if self.ssgText not in OVEConfig.Inst().ssgList:
-            OVEConfig.Inst().ssgList.append(self.ssgText)
-            OVEConfig.Inst().saveConfig()
-        self.updateSsgList()
-        
-    def updateSsgList(self):
-        currentSsgText = self.ssgText
-        self.ui.ssgComboBox.clear()
-        isFound = False
-        for i, ssgText in enumerate(OVEConfig.Inst().ssgList):
-            self.ui.ssgComboBox.addItem(ssgText)
-            if ssgText == currentSsgText:
-                # This is the currently selected item
-                self.ui.ssgComboBox.setCurrentIndex(i)
-                isFound = True
-        
-        if not isFound:
-            self.ui.ssgComboBox.setCurrentIndex(-1)
-            self.ui.ssgComboBox.lineEdit().setText(currentSsgText)
-
-    def xon_ssgDeleteButton_clicked(self):
-        if self.ssgText in OVEConfig.Inst().ssgList:
-            OVEConfig.Inst().ssgList.remove(self.ssgText)
-            self.ssgText = ''
-            OVEConfig.Inst().saveConfig()
-        self.updateSsgList()
-
-    def xon_ssgComboBox_activated(self, index):
-        if (index >= 0):
-            itemData = self.ui.ssgComboBox.itemText(index)
-            self.ssgText = str(itemData)
-            self.updateTable()
-    
-    def xon_ssgComboBox_editTextChanged(self, text):
-        self.ssgText = str(text)
-        self.statusBar().showMessage('Remote command is: '+self.updateCommand())
-        present = (self.ssgText in OVEConfig.Inst().ssgList)
-        self.ui.ssgDeleteButton.setEnabled(present)
-        self.ui.ssgSaveButton.setEnabled(not present)
-    
-    def xon_ssgCheckBox_stateChanged(self, state):
-        self.ssgChecked = (state == Qt.Checked)
-        self.updateTable()
-    
-    def xon_configUpdated(self):
-        OVECommonWindow.xon_configUpdated(self)
-        self.updateSsgList()
-        self.updateDatapaths()
-    
-    def timerEvent(self, event):
-        OVECommonWindow.timerEvent(self, event)
-
-    def customEvent(self, event):
-        OVECommonWindow.customEvent(self, event)
-    
-    def updateDatapaths(self):
-        if self.hostUuid == '':
-            self.statusBar().showMessage('No host selected')
-        else:
-            self.currentRef += 1
-            self.currentOp = 'dump-dps'
-            command = self.COMMAND_OVS_DPCTL+' dump-dps'
-            OVEFetch.Inst(self.hostUuid).execCommandFramed(self, self.currentRef, command)
-    
-    def rebuildTables(self):
-        self.ui.tabWidget.clear() # Let the garbage collector delete the pages
-        self.dpTables = []
-        self.dpFlows = []
-        self.resizeCount = []
-        headings = OVEUtil.flowDecodeHeadings()
-        
-        for dpName in self.dpNames:
-            pageWidget = QtGui.QWidget()
-            pageWidget.setObjectName(dpName+'_page')
-            gridLayout = QtGui.QGridLayout(pageWidget)
-            gridLayout.setObjectName(dpName+"_gridLayout")
-            table = QtGui.QTableWidget(pageWidget)
-            table.setObjectName(dpName+"_table")
-            table.setColumnCount(len(headings))
-            table.setRowCount(0)
-            gridLayout.addWidget(table, 0, 0, 1, 1)
-            self.dpTables.append(table)
-            self.ui.tabWidget.addTab(pageWidget, dpName)
-            self.dpFlows.append([])
-            self.resizeCount.append(0)
-            for i, heading in enumerate(headings):
-                table.setHorizontalHeaderItem(i, QtGui.QTableWidgetItem(heading))
-
-            table.setSortingEnabled(True)
-            
-            table.sortItems(OVEUtil.getFlowColumn('source mac'))
-            table.setSelectionMode(QtGui.QAbstractItemView.NoSelection)
-    
-    def updateSsgState(self):
-        self.ui.ssgCheckBox.setChecked(self.ssgChecked)
-    
-    def updateCommand(self, overrideText = None):
-        command = self.COMMAND_OVS_DPCTL+' dump-flows '
-        if self.currentOpIndex is not None:
-            command += self.dpNames[self.currentOpIndex]
-        exp = None
-        if overrideText is not None:
-                exp = overrideText
-        elif self.ssgChecked:
-                exp = self.ssgText
-                
-        if exp is not None:
-            opts='-E '
-            if exp.startswith('!'):
-                exp =exp[1:]
-                opts += '-v '
-            command += " | grep "+opts+"'"+exp+"' ; test ${PIPESTATUS[0]} -eq 0 "
-
-        return command
-    
-    def updateTable(self):
-        if self.hostUuid == '':
-            self.statusBar().showMessage('No host selected')
-            self.setWindowTitle('OVS Flows')
-        elif len(self.dpNames) > 0:
-            config = OVEConfig.Inst().hostFromUuid(self.hostUuid)
-            self.setWindowTitle('OVS Flows - '+config.get('address', ''))
-            try:
-                self.setFetchSkip()
-                self.statusBar().showMessage('Fetching data...') 
-                self.currentRef += 1
-                self.currentOp = 'dump-flows'
-                self.currentOpIndex = self.ui.tabWidget.currentIndex()
-                OVEFetch.Inst(self.hostUuid).execCommandFramed(self, self.currentRef, self.updateCommand())
-            except Exception, e:
-                message = 'Update failed: '+str(e)
-                OVELog(message)
-                self.statusBar().showMessage(message)
-    
-    def writeCurrentTable(self):
-        index = self.ui.tabWidget.currentIndex()
-        actionsColumn = OVEUtil.getFlowColumn('actions')
-        usedColumn = OVEUtil.getFlowColumn('used')
-        srcMacColumn = OVEUtil.getFlowColumn('source mac')
-        destMacColumn = OVEUtil.getFlowColumn('destination mac')
-        srcIPColumn = OVEUtil.getFlowColumn('source ip')
-        destIPColumn = OVEUtil.getFlowColumn('destination ip')
-        inportColumn = OVEUtil.getFlowColumn('inport')
-        vlanColumn = OVEUtil.getFlowColumn('vlan')
-        bytesColumn = OVEUtil.getFlowColumn('bytes')
-        
-        byteCount = 0
-        try:
-            table = self.dpTables[index]
-            table.setUpdatesEnabled(False)
-            table.setSortingEnabled(False)
-            try:
-                flows = self.dpFlows[index]
-                table.setRowCount(len(flows))
-                if len(flows) > 0:
-                    table.setColumnCount(len(flows[0]))
-                for rowNum, flow in enumerate(flows):
-                    
-                    inport = flow[inportColumn]
-                    if flow[actionsColumn] == 'drop':
-                        baseLum=172
-                    else:
-                        baseLum=239
-                    background = QtGui.QColor(baseLum+16*(inport % 2), baseLum+8*(inport % 3), baseLum+4*(inport % 5))
-                    if flow[usedColumn] == 'never':
-                        colour = QtGui.QColor(112,112,112)
-                    else:
-                        colour = Qt.black
-                        
-                    for colNum, data in enumerate(flow):
-                        item = None
-                        try:
-                            item = table.takeItem(rowNum, colNum)
-                        except:
-                            pass
-                        if item is None:
-                            item = QtGui.QTableWidgetItem('')
-
-                        if colNum == vlanColumn:
-                            item.setBackground(QtGui.QColor(255-(10*data % 192), 255-((17*data) % 192), 255-((37*data) % 192)))
-                        elif colNum == srcMacColumn or colNum == destMacColumn:
-                            cols = [int(x, 16) for x in data.split(':')]
-                            item.setBackground(QtGui.QColor(255-cols[2]*cols[3] % 192, 255-cols[3]*cols[4] % 192, 255-cols[4]*cols[5] % 192))
-                        elif re.match(r'[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+', str(data)):
-                            cols = [int(x) for x in data.split('.')]
-                            item.setBackground(QtGui.QColor(255-cols[1]*cols[2] % 192, 255-cols[2]*cols[3] % 192, 255-cols[3]*cols[0] % 192))
-                        else:
-                            item.setBackground(background)
-                            item.setForeground(colour)
-                            
-                        if colNum == bytesColumn:
-                            byteCount += int(data)
-                            
-                        # PySide 0.2.3 fails to convert long ints to QVariants and logs 'long int too large to convert to int' errors
-                        try:
-                            item.setData(Qt.DisplayRole, QVariant(data))
-                            item.setToolTip(str(data))
-                        except Exception, e:
-                            item.setText('Error: See tooltip')
-                            item.setToolTip(str(e))
-                        table.setItem(rowNum, colNum, item)
-                
-                if self.resizeCount[index] < 2:
-                    self.resizeCount[index] += 1
-                    for i in range(0, table.columnCount()):
-                        table.resizeColumnToContents(i)
-
-            finally:
-                table.setUpdatesEnabled(True)
-                table.setSortingEnabled(True)
-
-            message = 'Updated at '+str(QtCore.QTime.currentTime().toString())
-            
-            if self.lastTime is not None:
-                timeDiff = time.time() - self.lastTime
-                byteDiff = byteCount - self.lastByteCount
-                bitRate = long(8 * byteDiff / timeDiff)
-                if abs(bitRate) < 10*2**20:
-                    message += ' ('+str(bitRate/2**10)+' kbit/s)'
-                elif abs(bitRate) < 10*2**30:
-                    message += ' ('+str(bitRate/2**20)+' Mbit/s)'
-                else:
-                    message += ' ('+str(bitRate/2**30)+' Gbit/s)'
-                
-            self.lastByteCount = byteCount
-            self.lastTime = time.time()
-            if table.rowCount() == 0:
-                message += ' - Table is empty'
-            self.statusBar().showMessage(message)
-
-        except Exception, e:
-            message = 'Table update failed: '+str(e)
-            OVELog(message)
-            self.statusBar().showMessage(message)
-
-    def handleFetchEvent(self, ref, values):
-        if self.currentOp == 'dump-dps':
-            self.dpNames =values.strip().split('\n')
-            self.rebuildTables()
-            self.updateTable()
-        elif self.currentOp == 'dump-flows':
-            self.dpFlows[self.currentOpIndex] = OVEUtil.decodeFlows(values)
-            self.writeCurrentTable()
-
-    def handleFetchFailEvent(self, ref, message):
-        self.statusBar().showMessage(message)
-        OVELog('Fetch ('+self.currentOp+') failed')
-
-    def customEvent(self, event):
-        OVECommonWindow.customEvent(self, event)
-        
-    def saveSettings(self, index):
-        settings, key = OVECommonWindow.saveSettings(self, index)
-        settings.setValue(key+"/ssgText", QVariant(self.ssgText))
-        settings.setValue(key+"/ssgChecked", QVariant(self.ssgChecked))
-        
-    def loadSettings(self, index):
-        settings, key = OVECommonWindow.loadSettings(self, index)
-        self.ssgText = str(settings.value(key+"/ssgText", QVariant('10\.80\.226\..*')).toString())
-        self.ssgChecked = settings.value(key+"/ssgChecked", QVariant(False)).toBool()
-        self.ssgRe = re.compile(self.ssgText)
diff --git a/ovsdb/ovsdbmonitor/OVEHostWindow.py b/ovsdb/ovsdbmonitor/OVEHostWindow.py
deleted file mode 100644 (file)
index e56b981..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-# Copyright (c) 2010 Citrix Systems, 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.
-
-from OVEStandard import *
-from OVELogger import *
-from Ui_HostWindow import *
-
-class OVEHostWindow(QtGui.QDialog):
-    DEFAULT_CONNECT_TARGET = 'unix:/var/run/openvswitch/db.sock'
-    def __init__(self, parent, currentValues = None):
-        QtGui.QDialog.__init__(self, parent)
-        self.ui = Ui_HostWindow()
-        self.ui.setupUi(self)
-        self.resize(-1, -1)
-        self.connect(self.ui.buttonBox, QtCore.SIGNAL("clicked(QAbstractButton *)"), self.xon_actionButton_Box_clicked)
-        if currentValues is not None:
-            self.ui.hostAddressEdit.setText(currentValues['address'])
-            self.ui.hostPasswordEdit.setText(currentValues['password'])
-            self.ui.hostConnectTarget.setText(currentValues.get('connectTarget', self.DEFAULT_CONNECT_TARGET))
-            self.uuid = currentValues.get('uuid', str(uuid.uuid4()))
-        else:
-            self.ui.hostConnectTarget.setText(self.DEFAULT_CONNECT_TARGET)
-            self.uuid = str(uuid.uuid4())
-            self.accepted = None
-    
-    def xon_actionButton_Box_clicked(self, button):
-        role = self.ui.buttonBox.buttonRole(button)
-        if role == QtGui.QDialogButtonBox.AcceptRole:
-            self.accepted = True
-            self.close()
-        elif role == QtGui.QDialogButtonBox.RejectRole:
-            self.accepted = False
-            self.close()
-
-    def record(self):
-        return {
-            'accepted' : self.accepted,
-            'uuid' : self.uuid,
-            'address' : str(self.ui.hostAddressEdit.text()),
-            'password' : str(self.ui.hostPasswordEdit.text()),
-            'connectTarget' : str(self.ui.hostConnectTarget.text())
-            }
-
diff --git a/ovsdb/ovsdbmonitor/OVELogWindow.py b/ovsdb/ovsdbmonitor/OVELogWindow.py
deleted file mode 100644 (file)
index 3c1a2ef..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-# Copyright (c) 2010 Citrix Systems, 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.
-
-from OVEStandard import *
-from OVELogger import *
-from Ui_LogWindow import *
-
-class OVELogWindow(QtGui.QDialog):
-    LOAD_KEY = 'LogWindow/window'
-    def __init__(self, app):
-        QtGui.QDialog.__init__(self)
-        self.app = app
-        self.ui = Ui_LogWindow()
-        self.ui.setupUi(self)
-        if self.isLoadable():
-            self.loadSettings()
-        self.connect(OVELogger.Inst(), QtCore.SIGNAL("logUpdated()"), self.logUpdated)
-        self.connect(self.ui.buttonBox, QtCore.SIGNAL("clicked(QAbstractButton *)"), self.xon_actionButton_Box_clicked)
-        
-    def xon_actionButton_Box_clicked(self, button):
-        role = self.ui.buttonBox.buttonRole(button)
-        if role == QtGui.QDialogButtonBox.ResetRole:
-            OVELogger.Inst().reset()
-            OVELog("Log reset")
-        
-    def logUpdated(self):
-        self.ui.textBrowser.setText("\n".join(OVELogger.Inst().contents))
-        self.ui.textBrowser.moveCursor(QtGui.QTextCursor.End)
-        self.ui.textBrowser.ensureCursorVisible()
-
-    def saveSettings(self):
-        key = self.LOAD_KEY
-        settings = QtCore.QSettings()
-        settings.setValue(key+"/loadable", QVariant(True))
-        settings.setValue(key+"/pos", QVariant(self.pos()))
-        settings.setValue(key+"/size", QVariant(self.size()))
-        settings.setValue(key+"/visible", QVariant(self.isVisible()))
-    
-    def loadSettings(self):
-        key = self.LOAD_KEY
-        settings = QtCore.QSettings()
-        pos = settings.value(key+"/pos", QVariant(QtCore.QPoint(200, 200))).toPoint()
-        size = settings.value(key+"/size", QVariant(QtCore.QSize(400, 400))).toSize()
-        visible = settings.value(key+"/visible", QVariant(True)).toBool()
-        self.resize(size)
-        self.move(pos)
-        self.setVisible(visible)
-
-    @classmethod
-    def isLoadable(cls):
-        key = cls.LOAD_KEY
-        settings = QtCore.QSettings()
-        return settings.value(key+"/loadable", QVariant(False)).toBool()
diff --git a/ovsdb/ovsdbmonitor/OVELogger.py b/ovsdb/ovsdbmonitor/OVELogger.py
deleted file mode 100644 (file)
index 5f39762..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright (c) 2010 Citrix Systems, 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.
-
-from OVEStandard import *
-
-class OVELogger(QtCore.QObject):
-    instance = None
-    def __init__(self):
-        QtCore.QObject.__init__(self)
-        self.contents = []
-        self.loggers = []
-        
-    @classmethod
-    def Inst(cls):
-        if cls.instance is None:
-            cls.instance = OVELogger()
-        return cls.instance
-    
-    def reset(self):
-        self.contents = []
-        self.update()
-    
-    def logString(self, message):
-        self.contents += [str(message)]
-        if len(self.contents) > 500:
-            self.contents = ['+++ Log truncated', ''] + self.contents[50:]
-        self.update()
-
-    def update(self):
-        self.emit(QtCore.SIGNAL("logUpdated()"))
-        
-def OVELog(message):
-    OVELogger.Inst().logString(message)
-    
diff --git a/ovsdb/ovsdbmonitor/OVEMainWindow.py b/ovsdb/ovsdbmonitor/OVEMainWindow.py
deleted file mode 100644 (file)
index 8d3d830..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-# Copyright (c) 2010 Citrix Systems, 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.
-
-from OVEStandard import *
-from OVEConfig import *
-from OVEFetch import *
-from OVELogger import *
-from OVEUtil import *
-
-from OVECommonWindow import *
-
-from Ui_MainWindow import *
-
-class OVEMainWindow(QtGui.QMainWindow, OVECommonWindow):
-    LOAD_KEY = 'MainWindow/window'
-    BASE_REF=100000
-    
-    def __init__(self, app, loadIndex = None):
-        QtGui.QMainWindow.__init__(self)
-        self.ui = Ui_MainWindow()
-        OVECommonWindow.__init__(self, app, loadIndex)
-    
-    def xon_tabWidget_currentChanged(self, value):
-        self.deleteCurrentTable()
-        OVECommonWindow.xon_tabWidget_currentChanged(self, value)
-
-    def updateTable(self):
-        if self.hostUuid == '':
-            self.setWindowTitle('OVS Database')
-            self.deleteCurrentTable()
-            self.statusBar().showMessage('No host selected.  Choose File->Preferences to add a host')
-        else:
-            config = OVEConfig.Inst().hostFromUuid(self.hostUuid)
-            self.setWindowTitle('OVS Database - '+config.get('address', ''))
-            self.invalidateCurrentTable('Fetching data...')
-            tabName = self.ui.tabWidget.currentWidget().objectName()
-            try:
-                self.setFetchSkip()
-                self.currentRef += 1
-                OVEFetch.Inst(self.hostUuid).getTable(self, tabName, self.currentRef)
-            except Exception, e:
-                OVELog("Error fetching data: "+str(e))
-                self.invalidateCurrentTable(str(e))
-
-    def timerEvent(self, event):
-        OVECommonWindow.timerEvent(self, event)
-
-    def customEvent(self, event):
-        OVECommonWindow.customEvent(self, event)
-
-    def handleFetchEvent(self, ref, values):
-        tabName = self.ui.tabWidget.currentWidget().objectName()
-        self.structToTable(getattr(self.ui, str(tabName)+'Table'), values)
-    def handleFetchFailEvent(self, ref, message):
-        self.invalidateCurrentTable(str(message))
-
-    def structToTable(self, table, values):
-        
-        table.setUpdatesEnabled(False)
-        table.setSortingEnabled(False)
-        
-        for result in values:
-            rowNum = 0
-            table.setRowCount(len(result['rows']))
-            for row in result['rows']:
-                table.setColumnCount(len(row))
-                colNum=0
-                for k in sorted(row.keys()):
-                    v = row[k]
-                    headerItem = QtGui.QTableWidgetItem(k)
-                    table.setHorizontalHeaderItem(colNum, headerItem)
-                    text = OVEUtil.paramToString(v)
-                    item = QtGui.QTableWidgetItem(text)
-                    longText = OVEUtil.paramToLongString(v)
-                    item.setToolTip(longText)
-
-                    table.setItem(rowNum, colNum, item)
-                    colNum+=1
-
-                rowNum+=1
-                
-        for i in range(0, table.columnCount()):
-            table.resizeColumnToContents(i)
-        for i in range(0, table.rowCount()):
-            table.resizeRowToContents(i)
-        
-        # table.setSortingEnabled(True)
-        table.setUpdatesEnabled(True)
-        
-        message = 'Updated at '+str(QtCore.QTime.currentTime().toString())
-        if table.rowCount() == 0:
-            message += ' - Table is empty'
-        self.statusBar().showMessage(message)
-
-    def invalidateCurrentTable(self, message):
-        tabName = self.ui.tabWidget.currentWidget().objectName()
-        self.invalidateTable(getattr(self.ui, str(tabName)+'Table'), message)
-
-    def invalidateTable(self, table, message):
-        table.setUpdatesEnabled(False)
-        table.setSortingEnabled(False)
-        
-        for rowNum in range(0, table.rowCount()):
-            for colNum in range(0, table.columnCount()):
-                item = table.takeItem(rowNum, colNum)
-                if item is not None:
-                    item.setForeground(Qt.darkGray)
-                    table.setItem(rowNum, colNum, item)
-        self.statusBar().showMessage(message)
-        # table.setSortingEnabled(True)
-        table.setUpdatesEnabled(True)
-
-    def deleteCurrentTable(self):
-        tabName = self.ui.tabWidget.currentWidget().objectName()
-        self.deleteTable(getattr(self.ui, str(tabName)+'Table'))
-
-    def deleteTable(self, table):
-        table.clear()
-        table.setRowCount(0)
-        table.setColumnCount(0)
-        
-    def saveSettings(self, index):
-        settings = OVECommonWindow.saveSettings(self, index)
-    
-    def loadSettings(self, index):
-        settings = OVECommonWindow.loadSettings(self, index)
diff --git a/ovsdb/ovsdbmonitor/OVEStandard.py b/ovsdb/ovsdbmonitor/OVEStandard.py
deleted file mode 100644 (file)
index c55a881..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (c) 2011 Nicira, Inc.
-# Copyright (c) 2010 Citrix Systems, 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 os, re, struct, sys, time, types, uuid
-from copy import deepcopy
-from pprint import pprint
-
-# Set globalForcePySide to True to use PySide instead of PyQt if both are installed
-globalForcePySide = False
-
-try:
-    import ovs.json
-except Exception, e:
-    print('+++ OVS JSON module is required\n')
-    raise
-
-try:
-    if globalForcePySide:
-        print('Forcing use of PySide')
-        raise Exception()
-    from PyQt4.QtCore import Qt, QVariant
-    from PyQt4 import QtCore, QtGui
-except:
-    try:
-        from PySide.QtCore import Qt, QVariant
-        from PySide import QtCore, QtGui
-    except Exception, e:
-        print('+++ This application requires either PyQt4 or PySide\n')
-        raise
-
diff --git a/ovsdb/ovsdbmonitor/OVEUtil.py b/ovsdb/ovsdbmonitor/OVEUtil.py
deleted file mode 100644 (file)
index d1b0692..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-# Copyright (c) 2011 Nicira, Inc.
-# Copyright (c) 2010 Citrix Systems, 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.
-
-from OVEStandard import *
-
-from OVEConfig import *
-import re
-
-class OVEUtil:
-    UUID_RE = re.compile(r'([a-f0-9]{8}-[a-f0-9]{2})[a-f0-9]{2}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}')
-    
-    @classmethod
-    def paramToLongString(cls, param):
-        if isinstance(param, (types.ListType, types.TupleType)) and len(param) > 1:
-            text = str(param[1])
-        else:
-            text = str(param)
-
-        return text.replace(', ', ',\n')
-        
-    @classmethod
-    def paramToString(cls, param):
-        if isinstance(param, (types.ListType, types.TupleType)) and len(param) > 1:
-            text = str(param[1])
-        else:
-            text = str(param)
-        if OVEConfig.Inst().truncateUuids:
-            text = cls.UUID_RE.sub('\\1...', text)
-            
-        return text.replace(', ', ',\n')
-
-    @classmethod
-    def flowDecodeHeadings(self):
-        return [
-                'Type',
-                'Proto',
-                'Inport',
-                'VLAN',
-                'Source MAC',
-                'Destination MAC',
-                'Source IP',
-                'Destination IP',
-                'Src port',
-                'Dest port',
-                'Packet count',
-                'Bytes',
-                'Used',
-                'Tos',
-                'PCP',
-                'Tunnel',
-                'Actions',
-                ]
-
-    @classmethod
-    def getFlowColumn(cls, name):
-        lowerName = name.lower()
-        for i, columnName in enumerate(cls.flowDecodeHeadings()):
-            if lowerName == columnName.lower():
-                return i
-        return None
-
-    ETHERTYPE_TRANS = {
-        '05ff':'ESX probe',
-        '0800':'IP',
-        '0806':'ARP',
-        '86dd':'IPv6',
-        '88cc':'LLDP'
-    }
-                  
-    ETHERPROTO_TRANS = {
-        '1':'ICMP',
-        '6':'TCP',
-        '17':'UDP'
-    }
-    
-    # Parsing of ovs-dpctl dump-flows output should be localised in this method and flowDecodeHeadings
-    @classmethod
-    def decodeFlows(cls, srcLines):
-        retVal = []
-        for line in srcLines.split('\n'):
-            if line != '':
-                fields = {}
-                for name, val in re.findall(r'([a-zA-Z0-9_+]+)\(([^)]+)\)', line):
-                    if '=' in val:
-                        for setting in val.split(','):
-                            k,v = setting.split('=')
-                            fields['%s.%s' % (name, k)] = v
-                    else:
-                        fields[name] = val
-                for setting in re.split(', ', line)[1:]:
-                    if ':' in setting:
-                        k,v = setting.split(':')
-                        fields[k] = v
-
-                tun_id = fields.get('tun_id', '')
-                in_port = int(fields.get('in_port', 0))
-                eth_src = fields.get('eth.src', '')
-                eth_dst = fields.get('eth.dst', '')
-                vlan_vid = int(fields.get('vlan.vid', 0))
-                vlan_pcp = int(fields.get('vlan.pcp', 0))
-                eth_type = fields.get('eth_type', '')
-                ip_src = fields.get('ipv4.src', fields.get('ipv6.src', ''))
-                ip_dst = fields.get('ipv4.dst', fields.get('ipv6.dst', ''))
-                ip_proto = fields.get('ipv4.proto', fields.get('ipv6.proto', ''))
-                ip_tos = fields.get('ipv4.tos', fields.get('ipv6.tos', ''))
-                tp_src = fields.get('tcp.src', fields.get('udp.src', fields.get('arp.sip', fields.get('icmp.type', fields.get('icmpv6.type', '')))))
-                tp_dst = fields.get('tcp.dst', fields.get('udp.dst', fields.get('arp.tip', fields.get('icmp.code', fields.get('icmpv6.code', '')))))
-
-                packets = fields.get('packets', '')
-                bytes = fields.get('bytes', '')
-                actions = fields.get('actions', '')
-                used = fields.get('used', '')
-
-                # Order below needs to match that in flowDecodeHeadings
-                retVal.append((eth_type, ip_proto, in_port, vlan_vid, eth_src, eth_dst, ip_src, ip_dst, tp_src, tp_dst, packets, bytes, used, ip_tos, vlan_pcp, tun_id, actions))
-                    
-        return retVal
-        
-    COLOURS = [Qt.black, Qt.darkBlue,  Qt.darkRed, Qt.darkGreen, Qt.darkMagenta, Qt.darkCyan, Qt.darkGray, Qt.darkYellow, Qt.blue, Qt.gray, Qt.magenta, Qt.red]
-        
-    @classmethod
-    def intToColour(cls, value):
-        return cls.COLOURS[value % len(cls.COLOURS)]
diff --git a/ovsdb/ovsdbmonitor/Ui_ConfigWindow.py b/ovsdb/ovsdbmonitor/Ui_ConfigWindow.py
deleted file mode 100644 (file)
index 461edc5..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Form implementation generated from reading ui file 'ConfigWindow.ui'
-#
-# Created: Fri May  7 17:20:33 2010
-#      by: PyQt4 UI code generator 4.4.2
-#
-# WARNING! All changes made in this file will be lost!
-
-try:
-    from OVEStandard import globalForcePySide
-    if globalForcePySide: raise Exception()
-    from PyQt4 import QtCore, QtGui
-except:
-    from PySide import QtCore, QtGui
-
-class Ui_ConfigWindow(object):
-    def setupUi(self, ConfigWindow):
-        ConfigWindow.setObjectName("ConfigWindow")
-        ConfigWindow.resize(386,303)
-        ConfigWindow.setFocusPolicy(QtCore.Qt.TabFocus)
-        self.gridLayout = QtGui.QGridLayout(ConfigWindow)
-        self.gridLayout.setObjectName("gridLayout")
-        self.verticalLayout = QtGui.QVBoxLayout()
-        self.verticalLayout.setObjectName("verticalLayout")
-        self.tabWidget = QtGui.QTabWidget(ConfigWindow)
-        self.tabWidget.setObjectName("tabWidget")
-        self.hosts = QtGui.QWidget()
-        self.hosts.setObjectName("hosts")
-        self.layoutWidget = QtGui.QWidget(self.hosts)
-        self.layoutWidget.setGeometry(QtCore.QRect(10,10,341,194))
-        self.layoutWidget.setObjectName("layoutWidget")
-        self.horizontalLayout_2 = QtGui.QHBoxLayout(self.layoutWidget)
-        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
-        self.hostList = QtGui.QListWidget(self.layoutWidget)
-        self.hostList.setObjectName("hostList")
-        self.horizontalLayout_2.addWidget(self.hostList)
-        self.verticalLayout_2 = QtGui.QVBoxLayout()
-        self.verticalLayout_2.setObjectName("verticalLayout_2")
-        self.hostAddButton = QtGui.QPushButton(self.layoutWidget)
-        self.hostAddButton.setObjectName("hostAddButton")
-        self.verticalLayout_2.addWidget(self.hostAddButton)
-        self.hostEditButton = QtGui.QPushButton(self.layoutWidget)
-        self.hostEditButton.setObjectName("hostEditButton")
-        self.verticalLayout_2.addWidget(self.hostEditButton)
-        self.hostDeleteButton = QtGui.QPushButton(self.layoutWidget)
-        self.hostDeleteButton.setObjectName("hostDeleteButton")
-        self.verticalLayout_2.addWidget(self.hostDeleteButton)
-        spacerItem = QtGui.QSpacerItem(20,40,QtGui.QSizePolicy.Minimum,QtGui.QSizePolicy.Expanding)
-        self.verticalLayout_2.addItem(spacerItem)
-        self.horizontalLayout_2.addLayout(self.verticalLayout_2)
-        self.tabWidget.addTab(self.hosts,"")
-        self.logging = QtGui.QWidget()
-        self.logging.setObjectName("logging")
-        self.gridLayout_2 = QtGui.QGridLayout(self.logging)
-        self.gridLayout_2.setObjectName("gridLayout_2")
-        self.logTrafficCheckBox = QtGui.QCheckBox(self.logging)
-        self.logTrafficCheckBox.setObjectName("logTrafficCheckBox")
-        self.gridLayout_2.addWidget(self.logTrafficCheckBox,0,0,1,1)
-        spacerItem1 = QtGui.QSpacerItem(20,164,QtGui.QSizePolicy.Minimum,QtGui.QSizePolicy.Expanding)
-        self.gridLayout_2.addItem(spacerItem1,1,0,1,1)
-        self.tabWidget.addTab(self.logging,"")
-        self.view = QtGui.QWidget()
-        self.view.setObjectName("view")
-        self.verticalLayout_3 = QtGui.QVBoxLayout(self.view)
-        self.verticalLayout_3.setObjectName("verticalLayout_3")
-        self.truncateUuidsCheckBox = QtGui.QCheckBox(self.view)
-        self.truncateUuidsCheckBox.setObjectName("truncateUuidsCheckBox")
-        self.verticalLayout_3.addWidget(self.truncateUuidsCheckBox)
-        spacerItem2 = QtGui.QSpacerItem(20,164,QtGui.QSizePolicy.Minimum,QtGui.QSizePolicy.Expanding)
-        self.verticalLayout_3.addItem(spacerItem2)
-        self.tabWidget.addTab(self.view,"")
-        self.verticalLayout.addWidget(self.tabWidget)
-        self.horizontalLayout = QtGui.QHBoxLayout()
-        self.horizontalLayout.setObjectName("horizontalLayout")
-        spacerItem3 = QtGui.QSpacerItem(40,20,QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Minimum)
-        self.horizontalLayout.addItem(spacerItem3)
-        self.buttonBox = QtGui.QDialogButtonBox(ConfigWindow)
-        self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Apply|QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
-        self.buttonBox.setObjectName("buttonBox")
-        self.horizontalLayout.addWidget(self.buttonBox)
-        self.verticalLayout.addLayout(self.horizontalLayout)
-        self.gridLayout.addLayout(self.verticalLayout,0,0,1,1)
-
-        self.retranslateUi(ConfigWindow)
-        self.tabWidget.setCurrentIndex(0)
-        QtCore.QMetaObject.connectSlotsByName(ConfigWindow)
-        ConfigWindow.setTabOrder(self.hostList,self.hostAddButton)
-        ConfigWindow.setTabOrder(self.hostAddButton,self.hostEditButton)
-        ConfigWindow.setTabOrder(self.hostEditButton,self.hostDeleteButton)
-        ConfigWindow.setTabOrder(self.hostDeleteButton,self.buttonBox)
-        ConfigWindow.setTabOrder(self.buttonBox,self.tabWidget)
-
-    def retranslateUi(self, ConfigWindow):
-        ConfigWindow.setWindowTitle(QtGui.QApplication.translate("ConfigWindow", "OVSDB Monitor Configuration", None, QtGui.QApplication.UnicodeUTF8))
-        self.hostAddButton.setText(QtGui.QApplication.translate("ConfigWindow", "Add", None, QtGui.QApplication.UnicodeUTF8))
-        self.hostEditButton.setText(QtGui.QApplication.translate("ConfigWindow", "Edit", None, QtGui.QApplication.UnicodeUTF8))
-        self.hostDeleteButton.setText(QtGui.QApplication.translate("ConfigWindow", "Delete", None, QtGui.QApplication.UnicodeUTF8))
-        self.tabWidget.setTabText(self.tabWidget.indexOf(self.hosts), QtGui.QApplication.translate("ConfigWindow", "Hosts", None, QtGui.QApplication.UnicodeUTF8))
-        self.logTrafficCheckBox.setToolTip(QtGui.QApplication.translate("ConfigWindow", "Whether to log traffic exchanges in the log window", None, QtGui.QApplication.UnicodeUTF8))
-        self.logTrafficCheckBox.setText(QtGui.QApplication.translate("ConfigWindow", "Log traffic", None, QtGui.QApplication.UnicodeUTF8))
-        self.tabWidget.setTabText(self.tabWidget.indexOf(self.logging), QtGui.QApplication.translate("ConfigWindow", "Logging", None, QtGui.QApplication.UnicodeUTF8))
-        self.truncateUuidsCheckBox.setToolTip(QtGui.QApplication.translate("ConfigWindow", "Replaces UUIDs with a shorter string of the first few characters.  The tooltip still contains the full value", None, QtGui.QApplication.UnicodeUTF8))
-        self.truncateUuidsCheckBox.setText(QtGui.QApplication.translate("ConfigWindow", "Truncate UUIDs", None, QtGui.QApplication.UnicodeUTF8))
-        self.tabWidget.setTabText(self.tabWidget.indexOf(self.view), QtGui.QApplication.translate("ConfigWindow", "View", None, QtGui.QApplication.UnicodeUTF8))
-
diff --git a/ovsdb/ovsdbmonitor/Ui_FlowWindow.py b/ovsdb/ovsdbmonitor/Ui_FlowWindow.py
deleted file mode 100644 (file)
index 351a0ca..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Form implementation generated from reading ui file 'FlowWindow.ui'
-#
-# Created: Fri May  7 17:20:33 2010
-#      by: PyQt4 UI code generator 4.4.2
-#
-# WARNING! All changes made in this file will be lost!
-
-try:
-    from OVEStandard import globalForcePySide
-    if globalForcePySide: raise Exception()
-    from PyQt4 import QtCore, QtGui
-except:
-    from PySide import QtCore, QtGui
-
-class Ui_FlowWindow(object):
-    def setupUi(self, FlowWindow):
-        FlowWindow.setObjectName("FlowWindow")
-        FlowWindow.resize(800,600)
-        self.centralwidget = QtGui.QWidget(FlowWindow)
-        self.centralwidget.setObjectName("centralwidget")
-        self.gridLayout = QtGui.QGridLayout(self.centralwidget)
-        self.gridLayout.setObjectName("gridLayout")
-        self.tabWidget = QtGui.QTabWidget(self.centralwidget)
-        self.tabWidget.setObjectName("tabWidget")
-        self.unset = QtGui.QWidget()
-        self.unset.setObjectName("unset")
-        self.gridLayout_10 = QtGui.QGridLayout(self.unset)
-        self.gridLayout_10.setObjectName("gridLayout_10")
-        self.tabWidget.addTab(self.unset,"")
-        self.gridLayout.addWidget(self.tabWidget,0,0,1,1)
-        self.horizontalLayout_2 = QtGui.QHBoxLayout()
-        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
-        self.ssgCheckBox = QtGui.QCheckBox(self.centralwidget)
-        self.ssgCheckBox.setObjectName("ssgCheckBox")
-        self.horizontalLayout_2.addWidget(self.ssgCheckBox)
-        self.ssgComboBox = QtGui.QComboBox(self.centralwidget)
-        self.ssgComboBox.setEditable(True)
-        self.ssgComboBox.setMaxVisibleItems(20)
-        self.ssgComboBox.setInsertPolicy(QtGui.QComboBox.NoInsert)
-        self.ssgComboBox.setMinimumContentsLength(32)
-        self.ssgComboBox.setObjectName("ssgComboBox")
-        self.horizontalLayout_2.addWidget(self.ssgComboBox)
-        self.ssgSaveButton = QtGui.QPushButton(self.centralwidget)
-        self.ssgSaveButton.setObjectName("ssgSaveButton")
-        self.horizontalLayout_2.addWidget(self.ssgSaveButton)
-        self.ssgDeleteButton = QtGui.QPushButton(self.centralwidget)
-        self.ssgDeleteButton.setObjectName("ssgDeleteButton")
-        self.horizontalLayout_2.addWidget(self.ssgDeleteButton)
-        spacerItem = QtGui.QSpacerItem(40,20,QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Minimum)
-        self.horizontalLayout_2.addItem(spacerItem)
-        self.gridLayout.addLayout(self.horizontalLayout_2,1,0,1,1)
-        self.horizontalLayout = QtGui.QHBoxLayout()
-        self.horizontalLayout.setObjectName("horizontalLayout")
-        self.hostLabel = QtGui.QLabel(self.centralwidget)
-        self.hostLabel.setObjectName("hostLabel")
-        self.horizontalLayout.addWidget(self.hostLabel)
-        self.hostComboBox = QtGui.QComboBox(self.centralwidget)
-        self.hostComboBox.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
-        self.hostComboBox.setObjectName("hostComboBox")
-        self.horizontalLayout.addWidget(self.hostComboBox)
-        self.intervalCheckBox = QtGui.QCheckBox(self.centralwidget)
-        self.intervalCheckBox.setObjectName("intervalCheckBox")
-        self.horizontalLayout.addWidget(self.intervalCheckBox)
-        self.intervalSpinBox = QtGui.QSpinBox(self.centralwidget)
-        self.intervalSpinBox.setMinimum(1)
-        self.intervalSpinBox.setMaximum(1000000)
-        self.intervalSpinBox.setObjectName("intervalSpinBox")
-        self.horizontalLayout.addWidget(self.intervalSpinBox)
-        spacerItem1 = QtGui.QSpacerItem(40,20,QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Minimum)
-        self.horizontalLayout.addItem(spacerItem1)
-        self.fetchPathsButton = QtGui.QPushButton(self.centralwidget)
-        self.fetchPathsButton.setObjectName("fetchPathsButton")
-        self.horizontalLayout.addWidget(self.fetchPathsButton)
-        self.fetchButton = QtGui.QPushButton(self.centralwidget)
-        self.fetchButton.setObjectName("fetchButton")
-        self.horizontalLayout.addWidget(self.fetchButton)
-        self.gridLayout.addLayout(self.horizontalLayout,3,0,1,1)
-        self.line = QtGui.QFrame(self.centralwidget)
-        self.line.setFrameShape(QtGui.QFrame.HLine)
-        self.line.setFrameShadow(QtGui.QFrame.Sunken)
-        self.line.setObjectName("line")
-        self.gridLayout.addWidget(self.line,2,0,1,1)
-        FlowWindow.setCentralWidget(self.centralwidget)
-        self.menubar = QtGui.QMenuBar(FlowWindow)
-        self.menubar.setGeometry(QtCore.QRect(0,0,800,28))
-        self.menubar.setObjectName("menubar")
-        self.menuFile = QtGui.QMenu(self.menubar)
-        self.menuFile.setObjectName("menuFile")
-        FlowWindow.setMenuBar(self.menubar)
-        self.statusbar = QtGui.QStatusBar(FlowWindow)
-        self.statusbar.setObjectName("statusbar")
-        FlowWindow.setStatusBar(self.statusbar)
-        self.actionShow_Log = QtGui.QAction(FlowWindow)
-        self.actionShow_Log.setObjectName("actionShow_Log")
-        self.actionNew_DB_Window = QtGui.QAction(FlowWindow)
-        self.actionNew_DB_Window.setObjectName("actionNew_DB_Window")
-        self.actionPreferences = QtGui.QAction(FlowWindow)
-        self.actionPreferences.setObjectName("actionPreferences")
-        self.actionQuit = QtGui.QAction(FlowWindow)
-        self.actionQuit.setObjectName("actionQuit")
-        self.actionNew_Flow_Window = QtGui.QAction(FlowWindow)
-        self.actionNew_Flow_Window.setObjectName("actionNew_Flow_Window")
-        self.menuFile.addAction(self.actionNew_DB_Window)
-        self.menuFile.addAction(self.actionNew_Flow_Window)
-        self.menuFile.addAction(self.actionShow_Log)
-        self.menuFile.addAction(self.actionPreferences)
-        self.menuFile.addSeparator()
-        self.menuFile.addAction(self.actionQuit)
-        self.menubar.addAction(self.menuFile.menuAction())
-        self.hostLabel.setBuddy(self.hostComboBox)
-
-        self.retranslateUi(FlowWindow)
-        self.tabWidget.setCurrentIndex(0)
-        QtCore.QMetaObject.connectSlotsByName(FlowWindow)
-
-    def retranslateUi(self, FlowWindow):
-        FlowWindow.setWindowTitle(QtGui.QApplication.translate("FlowWindow", "OVSDB Monitor", None, QtGui.QApplication.UnicodeUTF8))
-        self.tabWidget.setTabText(self.tabWidget.indexOf(self.unset), QtGui.QApplication.translate("FlowWindow", "Awaiting update...", None, QtGui.QApplication.UnicodeUTF8))
-        self.ssgCheckBox.setText(QtGui.QApplication.translate("FlowWindow", "Server-side grep", None, QtGui.QApplication.UnicodeUTF8))
-        self.ssgSaveButton.setText(QtGui.QApplication.translate("FlowWindow", "Save", None, QtGui.QApplication.UnicodeUTF8))
-        self.ssgDeleteButton.setText(QtGui.QApplication.translate("FlowWindow", "Delete", None, QtGui.QApplication.UnicodeUTF8))
-        self.hostLabel.setText(QtGui.QApplication.translate("FlowWindow", "Host", None, QtGui.QApplication.UnicodeUTF8))
-        self.intervalCheckBox.setText(QtGui.QApplication.translate("FlowWindow", "Auto-refetch every", None, QtGui.QApplication.UnicodeUTF8))
-        self.intervalSpinBox.setSuffix(QtGui.QApplication.translate("FlowWindow", "s", None, QtGui.QApplication.UnicodeUTF8))
-        self.fetchPathsButton.setToolTip(QtGui.QApplication.translate("FlowWindow", "Refetches the datapath names and rebuilds the window tabs to reflect them.  Use when the network has been reconfigured, e.g. a bond has been created", None, QtGui.QApplication.UnicodeUTF8))
-        self.fetchPathsButton.setText(QtGui.QApplication.translate("FlowWindow", "Refetch Datapath List", None, QtGui.QApplication.UnicodeUTF8))
-        self.fetchButton.setText(QtGui.QApplication.translate("FlowWindow", "Refetch", None, QtGui.QApplication.UnicodeUTF8))
-        self.menuFile.setTitle(QtGui.QApplication.translate("FlowWindow", "File", None, QtGui.QApplication.UnicodeUTF8))
-        self.actionShow_Log.setText(QtGui.QApplication.translate("FlowWindow", "Show Log", None, QtGui.QApplication.UnicodeUTF8))
-        self.actionNew_DB_Window.setText(QtGui.QApplication.translate("FlowWindow", "New DB Window", None, QtGui.QApplication.UnicodeUTF8))
-        self.actionPreferences.setText(QtGui.QApplication.translate("FlowWindow", "Preferences", None, QtGui.QApplication.UnicodeUTF8))
-        self.actionQuit.setText(QtGui.QApplication.translate("FlowWindow", "Quit", None, QtGui.QApplication.UnicodeUTF8))
-        self.actionNew_Flow_Window.setText(QtGui.QApplication.translate("FlowWindow", "New Flow Window", None, QtGui.QApplication.UnicodeUTF8))
-
diff --git a/ovsdb/ovsdbmonitor/Ui_HostWindow.py b/ovsdb/ovsdbmonitor/Ui_HostWindow.py
deleted file mode 100644 (file)
index 3cab49d..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Form implementation generated from reading ui file 'HostWindow.ui'
-#
-# Created: Fri May  7 17:20:33 2010
-#      by: PyQt4 UI code generator 4.4.2
-#
-# WARNING! All changes made in this file will be lost!
-
-try:
-    from OVEStandard import globalForcePySide
-    if globalForcePySide: raise Exception()
-    from PyQt4 import QtCore, QtGui
-except:
-    from PySide import QtCore, QtGui
-
-class Ui_HostWindow(object):
-    def setupUi(self, HostWindow):
-        HostWindow.setObjectName("HostWindow")
-        HostWindow.setWindowModality(QtCore.Qt.WindowModal)
-        HostWindow.resize(400,300)
-        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum,QtGui.QSizePolicy.Minimum)
-        sizePolicy.setHorizontalStretch(0)
-        sizePolicy.setVerticalStretch(0)
-        sizePolicy.setHeightForWidth(HostWindow.sizePolicy().hasHeightForWidth())
-        HostWindow.setSizePolicy(sizePolicy)
-        self.gridLayout_2 = QtGui.QGridLayout(HostWindow)
-        self.gridLayout_2.setObjectName("gridLayout_2")
-        self.gridLayout = QtGui.QGridLayout()
-        self.gridLayout.setObjectName("gridLayout")
-        self.label = QtGui.QLabel(HostWindow)
-        self.label.setObjectName("label")
-        self.gridLayout.addWidget(self.label,0,0,1,1)
-        self.hostAddressEdit = QtGui.QLineEdit(HostWindow)
-        self.hostAddressEdit.setMinimumSize(QtCore.QSize(256,0))
-        self.hostAddressEdit.setObjectName("hostAddressEdit")
-        self.gridLayout.addWidget(self.hostAddressEdit,0,1,1,1)
-        self.label_2 = QtGui.QLabel(HostWindow)
-        self.label_2.setObjectName("label_2")
-        self.gridLayout.addWidget(self.label_2,1,0,1,1)
-        self.hostPasswordEdit = QtGui.QLineEdit(HostWindow)
-        self.hostPasswordEdit.setMinimumSize(QtCore.QSize(256,0))
-        self.hostPasswordEdit.setEchoMode(QtGui.QLineEdit.Password)
-        self.hostPasswordEdit.setObjectName("hostPasswordEdit")
-        self.gridLayout.addWidget(self.hostPasswordEdit,1,1,1,1)
-        self.label_3 = QtGui.QLabel(HostWindow)
-        self.label_3.setObjectName("label_3")
-        self.gridLayout.addWidget(self.label_3,2,0,1,1)
-        self.hostConnectTarget = QtGui.QLineEdit(HostWindow)
-        self.hostConnectTarget.setMinimumSize(QtCore.QSize(256,0))
-        self.hostConnectTarget.setObjectName("hostConnectTarget")
-        self.gridLayout.addWidget(self.hostConnectTarget,2,1,1,1)
-        self.gridLayout_2.addLayout(self.gridLayout,0,0,1,1)
-        self.buttonBox = QtGui.QDialogButtonBox(HostWindow)
-        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
-        self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
-        self.buttonBox.setObjectName("buttonBox")
-        self.gridLayout_2.addWidget(self.buttonBox,1,0,1,1)
-        self.label.setBuddy(self.hostAddressEdit)
-        self.label_2.setBuddy(self.hostPasswordEdit)
-        self.label_3.setBuddy(self.hostConnectTarget)
-
-        self.retranslateUi(HostWindow)
-        QtCore.QObject.connect(self.buttonBox,QtCore.SIGNAL("accepted()"),HostWindow.accept)
-        QtCore.QObject.connect(self.buttonBox,QtCore.SIGNAL("rejected()"),HostWindow.reject)
-        QtCore.QMetaObject.connectSlotsByName(HostWindow)
-        HostWindow.setTabOrder(self.hostAddressEdit,self.hostPasswordEdit)
-        HostWindow.setTabOrder(self.hostPasswordEdit,self.buttonBox)
-
-    def retranslateUi(self, HostWindow):
-        HostWindow.setWindowTitle(QtGui.QApplication.translate("HostWindow", "Host Properties", None, QtGui.QApplication.UnicodeUTF8))
-        self.label.setText(QtGui.QApplication.translate("HostWindow", "Host name or IP", None, QtGui.QApplication.UnicodeUTF8))
-        self.label_2.setText(QtGui.QApplication.translate("HostWindow", "SSH Password", None, QtGui.QApplication.UnicodeUTF8))
-        self.label_3.setText(QtGui.QApplication.translate("HostWindow", "Connect target", None, QtGui.QApplication.UnicodeUTF8))
-
diff --git a/ovsdb/ovsdbmonitor/Ui_LogWindow.py b/ovsdb/ovsdbmonitor/Ui_LogWindow.py
deleted file mode 100644 (file)
index 0ddd651..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Form implementation generated from reading ui file 'LogWindow.ui'
-#
-# Created: Fri May  7 17:20:33 2010
-#      by: PyQt4 UI code generator 4.4.2
-#
-# WARNING! All changes made in this file will be lost!
-
-try:
-    from OVEStandard import globalForcePySide
-    if globalForcePySide: raise Exception()
-    from PyQt4 import QtCore, QtGui
-except:
-    from PySide import QtCore, QtGui
-
-class Ui_LogWindow(object):
-    def setupUi(self, LogWindow):
-        LogWindow.setObjectName("LogWindow")
-        LogWindow.resize(735,558)
-        self.gridLayout = QtGui.QGridLayout(LogWindow)
-        self.gridLayout.setObjectName("gridLayout")
-        self.verticalLayout = QtGui.QVBoxLayout()
-        self.verticalLayout.setObjectName("verticalLayout")
-        self.textBrowser = QtGui.QTextBrowser(LogWindow)
-        self.textBrowser.setObjectName("textBrowser")
-        self.verticalLayout.addWidget(self.textBrowser)
-        self.buttonBox = QtGui.QDialogButtonBox(LogWindow)
-        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
-        self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Close|QtGui.QDialogButtonBox.Reset)
-        self.buttonBox.setObjectName("buttonBox")
-        self.verticalLayout.addWidget(self.buttonBox)
-        self.gridLayout.addLayout(self.verticalLayout,0,0,1,1)
-
-        self.retranslateUi(LogWindow)
-        QtCore.QObject.connect(self.buttonBox,QtCore.SIGNAL("accepted()"),LogWindow.accept)
-        QtCore.QObject.connect(self.buttonBox,QtCore.SIGNAL("rejected()"),LogWindow.reject)
-        QtCore.QMetaObject.connectSlotsByName(LogWindow)
-
-    def retranslateUi(self, LogWindow):
-        LogWindow.setWindowTitle(QtGui.QApplication.translate("LogWindow", "OVSDB Monitor Log", None, QtGui.QApplication.UnicodeUTF8))
-
diff --git a/ovsdb/ovsdbmonitor/Ui_MainWindow.py b/ovsdb/ovsdbmonitor/Ui_MainWindow.py
deleted file mode 100644 (file)
index ee57805..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Form implementation generated from reading ui file '../ovsdb/ovsdbmonitor/MainWindow.ui'
-#
-# Created: Mon May 17 16:23:47 2010
-#      by: PyQt4 UI code generator 4.7.3
-#
-# WARNING! All changes made in this file will be lost!
-
-
-try:
-    from OVEStandard import globalForcePySide
-    if globalForcePySide:
-        raise Exception()
-    from PyQt4 import QtCore, QtGui
-except:
-    from PySide import QtCore, QtGui
-
-class Ui_MainWindow(object):
-    def setupUi(self, MainWindow):
-        MainWindow.setObjectName("MainWindow")
-        MainWindow.resize(800, 600)
-        self.centralwidget = QtGui.QWidget(MainWindow)
-        self.centralwidget.setObjectName("centralwidget")
-        self.gridLayout = QtGui.QGridLayout(self.centralwidget)
-        self.gridLayout.setObjectName("gridLayout")
-        self.verticalLayout = QtGui.QVBoxLayout()
-        self.verticalLayout.setObjectName("verticalLayout")
-        self.tabWidget = QtGui.QTabWidget(self.centralwidget)
-        self.tabWidget.setObjectName("tabWidget")
-        self.Bridge = QtGui.QWidget()
-        self.Bridge.setObjectName("Bridge")
-        self.gridLayout_2 = QtGui.QGridLayout(self.Bridge)
-        self.gridLayout_2.setObjectName("gridLayout_2")
-        self.BridgeTable = QtGui.QTableWidget(self.Bridge)
-        self.BridgeTable.setObjectName("BridgeTable")
-        self.BridgeTable.setColumnCount(0)
-        self.BridgeTable.setRowCount(0)
-        self.gridLayout_2.addWidget(self.BridgeTable, 0, 0, 1, 1)
-        self.tabWidget.addTab(self.Bridge, "")
-        self.Controller = QtGui.QWidget()
-        self.Controller.setObjectName("Controller")
-        self.gridLayout_3 = QtGui.QGridLayout(self.Controller)
-        self.gridLayout_3.setObjectName("gridLayout_3")
-        self.ControllerTable = QtGui.QTableWidget(self.Controller)
-        self.ControllerTable.setObjectName("ControllerTable")
-        self.ControllerTable.setColumnCount(0)
-        self.ControllerTable.setRowCount(0)
-        self.gridLayout_3.addWidget(self.ControllerTable, 0, 0, 1, 1)
-        self.tabWidget.addTab(self.Controller, "")
-        self.Interface = QtGui.QWidget()
-        self.Interface.setObjectName("Interface")
-        self.gridLayout_4 = QtGui.QGridLayout(self.Interface)
-        self.gridLayout_4.setObjectName("gridLayout_4")
-        self.InterfaceTable = QtGui.QTableWidget(self.Interface)
-        self.InterfaceTable.setObjectName("InterfaceTable")
-        self.InterfaceTable.setColumnCount(0)
-        self.InterfaceTable.setRowCount(0)
-        self.gridLayout_4.addWidget(self.InterfaceTable, 0, 0, 1, 1)
-        self.tabWidget.addTab(self.Interface, "")
-        self.Mirror = QtGui.QWidget()
-        self.Mirror.setObjectName("Mirror")
-        self.gridLayout_5 = QtGui.QGridLayout(self.Mirror)
-        self.gridLayout_5.setObjectName("gridLayout_5")
-        self.MirrorTable = QtGui.QTableWidget(self.Mirror)
-        self.MirrorTable.setObjectName("MirrorTable")
-        self.MirrorTable.setColumnCount(0)
-        self.MirrorTable.setRowCount(0)
-        self.gridLayout_5.addWidget(self.MirrorTable, 0, 0, 1, 1)
-        self.tabWidget.addTab(self.Mirror, "")
-        self.NetFlow = QtGui.QWidget()
-        self.NetFlow.setObjectName("NetFlow")
-        self.gridLayout_6 = QtGui.QGridLayout(self.NetFlow)
-        self.gridLayout_6.setObjectName("gridLayout_6")
-        self.NetFlowTable = QtGui.QTableWidget(self.NetFlow)
-        self.NetFlowTable.setObjectName("NetFlowTable")
-        self.NetFlowTable.setColumnCount(0)
-        self.NetFlowTable.setRowCount(0)
-        self.gridLayout_6.addWidget(self.NetFlowTable, 0, 0, 1, 1)
-        self.tabWidget.addTab(self.NetFlow, "")
-        self.Open_vSwitch = QtGui.QWidget()
-        self.Open_vSwitch.setObjectName("Open_vSwitch")
-        self.gridLayout_7 = QtGui.QGridLayout(self.Open_vSwitch)
-        self.gridLayout_7.setObjectName("gridLayout_7")
-        self.Open_vSwitchTable = QtGui.QTableWidget(self.Open_vSwitch)
-        self.Open_vSwitchTable.setObjectName("Open_vSwitchTable")
-        self.Open_vSwitchTable.setColumnCount(0)
-        self.Open_vSwitchTable.setRowCount(0)
-        self.gridLayout_7.addWidget(self.Open_vSwitchTable, 0, 0, 1, 1)
-        self.tabWidget.addTab(self.Open_vSwitch, "")
-        self.Port = QtGui.QWidget()
-        self.Port.setObjectName("Port")
-        self.gridLayout_8 = QtGui.QGridLayout(self.Port)
-        self.gridLayout_8.setObjectName("gridLayout_8")
-        self.PortTable = QtGui.QTableWidget(self.Port)
-        self.PortTable.setObjectName("PortTable")
-        self.PortTable.setColumnCount(0)
-        self.PortTable.setRowCount(0)
-        self.gridLayout_8.addWidget(self.PortTable, 0, 0, 1, 1)
-        self.tabWidget.addTab(self.Port, "")
-        self.QoS = QtGui.QWidget()
-        self.QoS.setObjectName("QoS")
-        self.gridLayout_10 = QtGui.QGridLayout(self.QoS)
-        self.gridLayout_10.setObjectName("gridLayout_10")
-        self.QoSTable = QtGui.QTableWidget(self.QoS)
-        self.QoSTable.setObjectName("QoSTable")
-        self.QoSTable.setColumnCount(0)
-        self.QoSTable.setRowCount(0)
-        self.gridLayout_10.addWidget(self.QoSTable, 0, 0, 1, 1)
-        self.tabWidget.addTab(self.QoS, "")
-        self.Queue = QtGui.QWidget()
-        self.Queue.setObjectName("Queue")
-        self.gridLayout_11 = QtGui.QGridLayout(self.Queue)
-        self.gridLayout_11.setObjectName("gridLayout_11")
-        self.QueueTable = QtGui.QTableWidget(self.Queue)
-        self.QueueTable.setObjectName("QueueTable")
-        self.QueueTable.setColumnCount(0)
-        self.QueueTable.setRowCount(0)
-        self.gridLayout_11.addWidget(self.QueueTable, 0, 0, 1, 1)
-        self.tabWidget.addTab(self.Queue, "")
-        self.sFlow = QtGui.QWidget()
-        self.sFlow.setObjectName("sFlow")
-        self.gridLayout_9 = QtGui.QGridLayout(self.sFlow)
-        self.gridLayout_9.setObjectName("gridLayout_9")
-        self.sFlowTable = QtGui.QTableWidget(self.sFlow)
-        self.sFlowTable.setObjectName("sFlowTable")
-        self.sFlowTable.setColumnCount(0)
-        self.sFlowTable.setRowCount(0)
-        self.gridLayout_9.addWidget(self.sFlowTable, 0, 0, 1, 1)
-        self.tabWidget.addTab(self.sFlow, "")
-        self.SSL = QtGui.QWidget()
-        self.SSL.setObjectName("SSL")
-        self.gridLayout_101 = QtGui.QGridLayout(self.SSL)
-        self.gridLayout_101.setObjectName("gridLayout_101")
-        self.SSLTable = QtGui.QTableWidget(self.SSL)
-        self.SSLTable.setObjectName("SSLTable")
-        self.SSLTable.setColumnCount(0)
-        self.SSLTable.setRowCount(0)
-        self.gridLayout_101.addWidget(self.SSLTable, 0, 0, 1, 1)
-        self.tabWidget.addTab(self.SSL, "")
-        self.verticalLayout.addWidget(self.tabWidget)
-        self.horizontalLayout = QtGui.QHBoxLayout()
-        self.horizontalLayout.setObjectName("horizontalLayout")
-        self.hostLabel = QtGui.QLabel(self.centralwidget)
-        self.hostLabel.setObjectName("hostLabel")
-        self.horizontalLayout.addWidget(self.hostLabel)
-        self.hostComboBox = QtGui.QComboBox(self.centralwidget)
-        self.hostComboBox.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
-        self.hostComboBox.setObjectName("hostComboBox")
-        self.horizontalLayout.addWidget(self.hostComboBox)
-        self.intervalCheckBox = QtGui.QCheckBox(self.centralwidget)
-        self.intervalCheckBox.setObjectName("intervalCheckBox")
-        self.horizontalLayout.addWidget(self.intervalCheckBox)
-        self.intervalSpinBox = QtGui.QSpinBox(self.centralwidget)
-        self.intervalSpinBox.setMinimum(1)
-        self.intervalSpinBox.setMaximum(1000000)
-        self.intervalSpinBox.setObjectName("intervalSpinBox")
-        self.horizontalLayout.addWidget(self.intervalSpinBox)
-        spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
-        self.horizontalLayout.addItem(spacerItem)
-        self.fetchButton = QtGui.QPushButton(self.centralwidget)
-        self.fetchButton.setObjectName("fetchButton")
-        self.horizontalLayout.addWidget(self.fetchButton)
-        self.verticalLayout.addLayout(self.horizontalLayout)
-        self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1)
-        MainWindow.setCentralWidget(self.centralwidget)
-        self.menubar = QtGui.QMenuBar(MainWindow)
-        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 28))
-        self.menubar.setObjectName("menubar")
-        self.menuFile = QtGui.QMenu(self.menubar)
-        self.menuFile.setObjectName("menuFile")
-        MainWindow.setMenuBar(self.menubar)
-        self.statusbar = QtGui.QStatusBar(MainWindow)
-        self.statusbar.setObjectName("statusbar")
-        MainWindow.setStatusBar(self.statusbar)
-        self.actionShow_Log = QtGui.QAction(MainWindow)
-        self.actionShow_Log.setObjectName("actionShow_Log")
-        self.actionNew_DB_Window = QtGui.QAction(MainWindow)
-        self.actionNew_DB_Window.setObjectName("actionNew_DB_Window")
-        self.actionPreferences = QtGui.QAction(MainWindow)
-        self.actionPreferences.setObjectName("actionPreferences")
-        self.actionQuit = QtGui.QAction(MainWindow)
-        self.actionQuit.setObjectName("actionQuit")
-        self.actionNew_Flow_Window = QtGui.QAction(MainWindow)
-        self.actionNew_Flow_Window.setObjectName("actionNew_Flow_Window")
-        self.menuFile.addAction(self.actionNew_DB_Window)
-        self.menuFile.addAction(self.actionNew_Flow_Window)
-        self.menuFile.addAction(self.actionShow_Log)
-        self.menuFile.addAction(self.actionPreferences)
-        self.menuFile.addSeparator()
-        self.menuFile.addAction(self.actionQuit)
-        self.menubar.addAction(self.menuFile.menuAction())
-        self.hostLabel.setBuddy(self.hostComboBox)
-
-        self.retranslateUi(MainWindow)
-        self.tabWidget.setCurrentIndex(0)
-        QtCore.QMetaObject.connectSlotsByName(MainWindow)
-
-    def retranslateUi(self, MainWindow):
-        MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "OVSDB Monitor", None, QtGui.QApplication.UnicodeUTF8))
-        self.tabWidget.setTabText(self.tabWidget.indexOf(self.Bridge), QtGui.QApplication.translate("MainWindow", "Bridge", None, QtGui.QApplication.UnicodeUTF8))
-        self.tabWidget.setTabText(self.tabWidget.indexOf(self.Controller), QtGui.QApplication.translate("MainWindow", "Controller", None, QtGui.QApplication.UnicodeUTF8))
-        self.tabWidget.setTabText(self.tabWidget.indexOf(self.Interface), QtGui.QApplication.translate("MainWindow", "Interface", None, QtGui.QApplication.UnicodeUTF8))
-        self.tabWidget.setTabText(self.tabWidget.indexOf(self.Mirror), QtGui.QApplication.translate("MainWindow", "Mirror", None, QtGui.QApplication.UnicodeUTF8))
-        self.tabWidget.setTabText(self.tabWidget.indexOf(self.NetFlow), QtGui.QApplication.translate("MainWindow", "NetFlow", None, QtGui.QApplication.UnicodeUTF8))
-        self.tabWidget.setTabText(self.tabWidget.indexOf(self.Open_vSwitch), QtGui.QApplication.translate("MainWindow", "Open_vSwitch", None, QtGui.QApplication.UnicodeUTF8))
-        self.tabWidget.setTabText(self.tabWidget.indexOf(self.Port), QtGui.QApplication.translate("MainWindow", "Port", None, QtGui.QApplication.UnicodeUTF8))
-        self.tabWidget.setTabText(self.tabWidget.indexOf(self.QoS), QtGui.QApplication.translate("MainWindow", "QoS", None, QtGui.QApplication.UnicodeUTF8))
-        self.tabWidget.setTabText(self.tabWidget.indexOf(self.Queue), QtGui.QApplication.translate("MainWindow", "Queue", None, QtGui.QApplication.UnicodeUTF8))
-        self.tabWidget.setTabText(self.tabWidget.indexOf(self.sFlow), QtGui.QApplication.translate("MainWindow", "sFlow", None, QtGui.QApplication.UnicodeUTF8))
-        self.tabWidget.setTabText(self.tabWidget.indexOf(self.SSL), QtGui.QApplication.translate("MainWindow", "SSL", None, QtGui.QApplication.UnicodeUTF8))
-        self.hostLabel.setText(QtGui.QApplication.translate("MainWindow", "Host", None, QtGui.QApplication.UnicodeUTF8))
-        self.intervalCheckBox.setText(QtGui.QApplication.translate("MainWindow", "Auto-refetch every", None, QtGui.QApplication.UnicodeUTF8))
-        self.intervalSpinBox.setSuffix(QtGui.QApplication.translate("MainWindow", "s", None, QtGui.QApplication.UnicodeUTF8))
-        self.fetchButton.setText(QtGui.QApplication.translate("MainWindow", "Refetch", None, QtGui.QApplication.UnicodeUTF8))
-        self.menuFile.setTitle(QtGui.QApplication.translate("MainWindow", "File", None, QtGui.QApplication.UnicodeUTF8))
-        self.actionShow_Log.setText(QtGui.QApplication.translate("MainWindow", "Show Log", None, QtGui.QApplication.UnicodeUTF8))
-        self.actionNew_DB_Window.setText(QtGui.QApplication.translate("MainWindow", "New DB Window", None, QtGui.QApplication.UnicodeUTF8))
-        self.actionPreferences.setText(QtGui.QApplication.translate("MainWindow", "Preferences", None, QtGui.QApplication.UnicodeUTF8))
-        self.actionQuit.setText(QtGui.QApplication.translate("MainWindow", "Quit", None, QtGui.QApplication.UnicodeUTF8))
-        self.actionNew_Flow_Window.setText(QtGui.QApplication.translate("MainWindow", "New Flow Window", None, QtGui.QApplication.UnicodeUTF8))
-
diff --git a/ovsdb/ovsdbmonitor/automake.mk b/ovsdb/ovsdbmonitor/automake.mk
deleted file mode 100644 (file)
index 14da10b..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-ovsdbmonitor_pyfiles = \
-       ovsdb/ovsdbmonitor/OVEApp.py \
-       ovsdb/ovsdbmonitor/OVECommonWindow.py \
-       ovsdb/ovsdbmonitor/OVEConfig.py \
-       ovsdb/ovsdbmonitor/OVEConfigWindow.py \
-       ovsdb/ovsdbmonitor/OVEFetch.py \
-       ovsdb/ovsdbmonitor/OVEFlowWindow.py \
-       ovsdb/ovsdbmonitor/OVEHostWindow.py \
-       ovsdb/ovsdbmonitor/OVELogWindow.py \
-       ovsdb/ovsdbmonitor/OVELogger.py \
-       ovsdb/ovsdbmonitor/OVEMainWindow.py \
-       ovsdb/ovsdbmonitor/OVEStandard.py \
-       ovsdb/ovsdbmonitor/OVEUtil.py \
-       ovsdb/ovsdbmonitor/Ui_ConfigWindow.py \
-       ovsdb/ovsdbmonitor/Ui_FlowWindow.py \
-       ovsdb/ovsdbmonitor/Ui_HostWindow.py \
-       ovsdb/ovsdbmonitor/Ui_LogWindow.py \
-       ovsdb/ovsdbmonitor/Ui_MainWindow.py \
-       ovsdb/ovsdbmonitor/qt4reactor.py
-EXTRA_DIST += \
-       $(ovsdbmonitor_pyfiles) \
-       ovsdb/ovsdbmonitor/COPYING \
-       ovsdb/ovsdbmonitor/ConfigWindow.ui \
-       ovsdb/ovsdbmonitor/FlowWindow.ui \
-       ovsdb/ovsdbmonitor/HostWindow.ui \
-       ovsdb/ovsdbmonitor/LogWindow.ui \
-       ovsdb/ovsdbmonitor/MainWindow.ui \
-       ovsdb/ovsdbmonitor/ovsdbmonitor.in \
-       ovsdb/ovsdbmonitor/ovsdbmonitor.desktop
-MAN_ROOTS += ovsdb/ovsdbmonitor/ovsdbmonitor.1
-
-ovsdbmonitordir = ${datadir}/ovsdbmonitor
-desktopdir = ${datadir}/applications
-if BUILD_OVSDBMONITOR
-noinst_SCRIPTS += ovsdb/ovsdbmonitor/ovsdbmonitor
-ovsdbmonitor_DATA = $(ovsdbmonitor_pyfiles)
-desktop_DATA = ovsdb/ovsdbmonitor/ovsdbmonitor.desktop
-install-exec-hook:
-       sed -e '/NOINSTALL/d' < ovsdb/ovsdbmonitor/ovsdbmonitor > ovsdb/ovsdbmonitor/ovsdbmonitor.tmp
-       chmod +x ovsdb/ovsdbmonitor/ovsdbmonitor.tmp
-       $(INSTALL_PROGRAM) ovsdb/ovsdbmonitor/ovsdbmonitor.tmp $(DESTDIR)$(bindir)/ovsdbmonitor
-       rm ovsdb/ovsdbmonitor/ovsdbmonitor.tmp
-DISTCLEANFILES += \
-       ovsdb/ovsdbmonitor/ovsdbmonitor \
-       ovsdb/ovsdbmonitor/ovsdbmonitor.tmp
-man_MANS += ovsdb/ovsdbmonitor/ovsdbmonitor.1
-endif
-
-UNINSTALL_LOCAL += ovsdbmonitor-uninstall-local
-ovsdbmonitor-uninstall-local:
-       rm -f $(DESTDIR)$(bindir)/ovsdbmonitor
-
-SUFFIXES += .ui .py
-.ui.py:
-       $(PYUIC4) $< | sed 's/from PyQt4 import QtCore, QtGui/\
-try:\
-    from OVEStandard import globalForcePySide\
-    if globalForcePySide:\
-        raise Exception()\
-    from PyQt4 import QtCore, QtGui\
-except:\
-    from PySide import QtCore, QtGui/' > $@
diff --git a/ovsdb/ovsdbmonitor/ovsdbmonitor.1 b/ovsdb/ovsdbmonitor/ovsdbmonitor.1
deleted file mode 100644 (file)
index aa2b0aa..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-.\" -*- nroff -*-
-.TH ovsdbmonitor 1 "May 2011" "Open vSwitch" "Open vSwitch Manual"
-.
-.SH NAME
-ovsdbmonitor \- GUI tool for monitoring Open vSwitch installations
-.
-.SH SYNOPSIS
-\fBovsdbmonitor\fR
-.
-.SH DESCRIPTION
-The \fBovsdbmonitor\fR program is a Qt-based GUI tool for monitoring
-and troubleshooting Open vSwitch.  It presents GUI tables that
-graphically represent an Open vSwitch kernel flow table (similar to
-\fBovs\-dpctl dump\-flows\fR) and Open vSwitch database contents
-(similar to \fBovs\-vsctl list \fItable\fR).
-.SH "SEE ALSO"
-.
-\fBovsdb\-server\fR(1),
-\fBovsdb\-client\fR(1),
-and the OVSDB specification.
diff --git a/ovsdb/ovsdbmonitor/ovsdbmonitor.desktop b/ovsdb/ovsdbmonitor/ovsdbmonitor.desktop
deleted file mode 100644 (file)
index b0f8253..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-[Desktop Entry]
-Name=Open vSwitch DB Monitor
-Comment=Monitor and troubleshoot local or remote Open vSwitch instances
-Exec=ovsdbmonitor
-Terminal=false
-Type=Application
-Categories=System;Monitor;
diff --git a/ovsdb/ovsdbmonitor/ovsdbmonitor.in b/ovsdb/ovsdbmonitor/ovsdbmonitor.in
deleted file mode 100755 (executable)
index e26130a..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#! @PYTHON@
-# Copyright (c) 2010 Citrix Systems, 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.
-#
-# Version 1.51
-# 2010-05-07
-
-import sys
-sys.path.insert(0, "@ovsdbmonitordir@")
-sys.path.insert(0, "@abs_top_srcdir@/ovsdb/ovsdbmonitor") # NOINSTALL
-
-import sys, traceback
-from pprint import pprint
-from OVEApp import *
-
-app = OVEApp()
-try:
-    retVal = app.enter()
-except Exception, e:
-    print str(e)
-    try:
-        trace = traceback.format_tb(sys.exc_info()[2])
-    except:
-        trace = ['Traceback not available']
-    print("".join(trace))
-    retVal = 1
-
-sys.exit(retVal)
diff --git a/ovsdb/ovsdbmonitor/qt4reactor.py b/ovsdb/ovsdbmonitor/qt4reactor.py
deleted file mode 100644 (file)
index 1379da7..0000000
+++ /dev/null
@@ -1,331 +0,0 @@
-# Copyright (c) 2001-2008 Twisted Matrix Laboratories.
-# See LICENSE for details.
-
-# The referred licence file contains:
-# 
-#Copyright (c) 2001-2010
-#Allen Short
-#Andy Gayton
-#Andrew Bennetts
-#Antoine Pitrou
-#Apple Computer, Inc.
-#Benjamin Bruheim
-#Bob Ippolito
-#Canonical Limited
-#Christopher Armstrong
-#David Reid
-#Donovan Preston
-#Eric Mangold
-#Eyal Lotem
-#Itamar Shtull-Trauring
-#James Knight
-#Jason A. Mobarak
-#Jean-Paul Calderone
-#Jessica McKellar
-#Jonathan Jacobs
-#Jonathan Lange
-#Jonathan D. Simms
-#Jurgen Hermann
-#Kevin Horn
-#Kevin Turner
-#Mary Gardiner
-#Matthew Lefkowitz
-#Massachusetts Institute of Technology
-#Moshe Zadka
-#Paul Swartz
-#Pavel Pergamenshchik
-#Ralph Meijer
-#Sean Riley
-#Software Freedom Conservancy
-#Travis B. Hartwell
-#Thijs Triemstra
-#Thomas Herve
-#Timothy Allen
-#
-#Permission is hereby granted, free of charge, to any person obtaining
-#a copy of this software and associated documentation files (the
-#"Software"), to deal in the Software without restriction, including
-#without limitation the rights to use, copy, modify, merge, publish,
-#distribute, sublicense, and/or sell copies of the Software, and to
-#permit persons to whom the Software is furnished to do so, subject to
-#the following conditions:
-#
-#The above copyright notice and this permission notice shall be
-#included in all copies or substantial portions of the Software.
-#
-#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-#EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-#MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-#NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-#LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-#OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-#WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-"""
-This module provides support for Twisted to be driven by the Qt mainloop.
-
-In order to use this support, simply do the following::
-    |  app = QApplication(sys.argv) # your code to init Qt
-    |  import qt4reactor
-    |  qt4reactor.install()
-    
-alternatively:
-
-    |  from twisted.application import reactors
-    |  reactors.installReactor('qt4')
-
-Then use twisted.internet APIs as usual.  The other methods here are not
-intended to be called directly.
-
-If you don't instantiate a QApplication or QCoreApplication prior to
-installing the reactor, a QCoreApplication will be constructed
-by the reactor.  QCoreApplication does not require a GUI so trial testing
-can occur normally.
-
-Twisted can be initialized after QApplication.exec_() with a call to
-reactor.runReturn().  calling reactor.stop() will unhook twisted but
-leave your Qt application running
-
-API Stability: stable
-
-Maintainer: U{Glenn H Tarbox, PhD<mailto:glenn@tarbox.org>}
-
-Previous maintainer: U{Itamar Shtull-Trauring<mailto:twisted@itamarst.org>}
-Original port to QT4: U{Gabe Rudy<mailto:rudy@goldenhelix.com>}
-Subsequent port by therve
-"""
-
-__all__ = ['install']
-
-
-import sys, time
-
-try:
-    from zope.interface import implements
-except:
-    print('+++ Python Zope interface module is required\n')
-    raise
-
-
-try:
-    from OVEStandard import globalForcePySide
-    if globalForcePySide: raise Exception()
-    from PyQt4.QtCore import QSocketNotifier, QObject, SIGNAL, QTimer, QCoreApplication
-    from PyQt4.QtCore import QEventLoop
-except:
-    from PySide.QtCore import QSocketNotifier, QObject, SIGNAL, QTimer, QCoreApplication
-    from PySide.QtCore import QEventLoop
-
-try:
-    from twisted.internet.interfaces import IReactorFDSet
-    from twisted.python import log
-    from twisted.internet.posixbase import PosixReactorBase
-except:
-    print('+++ Python Twisted Conch module is required\n')
-    raise
-    
-class TwistedSocketNotifier(QSocketNotifier):
-    """
-    Connection between an fd event and reader/writer callbacks.
-    """
-
-    def __init__(self, reactor, watcher, type):
-        QSocketNotifier.__init__(self, watcher.fileno(), type)
-        self.reactor = reactor
-        self.watcher = watcher
-        self.fn = None
-        if type == QSocketNotifier.Read:
-            self.fn = self.read
-        elif type == QSocketNotifier.Write:
-            self.fn = self.write
-        QObject.connect(self, SIGNAL("activated(int)"), self.fn)
-
-
-    def shutdown(self):
-        QObject.disconnect(self, SIGNAL("activated(int)"), self.fn)
-        self.setEnabled(False)
-        self.fn = self.watcher = None
-        self.deleteLater()
-
-
-    def read(self, sock):
-        w = self.watcher
-        #self.setEnabled(False)    # ??? do I need this?            
-        def _read():
-            why = None
-            try:
-                why = w.doRead()
-            except:
-                log.err()
-                why = sys.exc_info()[1]
-            if why:
-                self.reactor._disconnectSelectable(w, why, True)
-            elif self.watcher:
-                pass
-                #self.setEnabled(True)
-        log.callWithLogger(w, _read)
-        self.reactor.reactorInvocation()
-
-    def write(self, sock):
-        w = self.watcher
-        self.setEnabled(False)
-        def _write():
-            why = None
-            try:
-                why = w.doWrite()
-            except:
-                log.err()
-                why = sys.exc_info()[1]
-            if why:
-                self.reactor._disconnectSelectable(w, why, False)
-            elif self.watcher:
-                self.setEnabled(True)
-        log.callWithLogger(w, _write)
-        self.reactor.reactorInvocation()
-
-class fakeApplication(QEventLoop):
-    def __init__(self):
-        QEventLoop.__init__(self)
-        
-    def exec_(self):
-        QEventLoop.exec_(self)
-        
-class QTReactor(PosixReactorBase):
-    """
-    Qt based reactor.
-    """
-    implements(IReactorFDSet)
-
-    _timer = None
-
-    def __init__(self):
-        self._reads = {}
-        self._writes = {}
-        self._timer=QTimer()
-        self._timer.setSingleShot(True)
-        if QCoreApplication.startingUp():
-            self.qApp=QCoreApplication([])
-            self._ownApp=True
-        else:
-            self.qApp = QCoreApplication.instance()
-            self._ownApp=False
-        self._blockApp = None
-        self._readWriteQ=[]
-        
-        """ some debugging instrumentation """
-        self._doSomethingCount=0
-        
-        PosixReactorBase.__init__(self)
-
-    def addReader(self, reader):
-        if not reader in self._reads:
-            self._reads[reader] = TwistedSocketNotifier(self, reader,
-                                                       QSocketNotifier.Read)
-
-
-    def addWriter(self, writer):
-        if not writer in self._writes:
-            self._writes[writer] = TwistedSocketNotifier(self, writer,
-                                                        QSocketNotifier.Write)
-
-
-    def removeReader(self, reader):
-        if reader in self._reads:
-            #self._reads[reader].shutdown()
-            #del self._reads[reader]
-            self._reads.pop(reader).shutdown()
-
-    def removeWriter(self, writer):
-        if writer in self._writes:
-            self._writes[writer].shutdown()
-            #del self._writes[writer]
-            self._writes.pop(writer)
-
-
-    def removeAll(self):
-        return self._removeAll(self._reads, self._writes)
-
-
-    def getReaders(self):
-        return self._reads.keys()
-
-
-    def getWriters(self):
-        return self._writes.keys()
-    
-    def callLater(self,howlong, *args, **kargs):
-        rval = super(QTReactor,self).callLater(howlong, *args, **kargs)
-        self.reactorInvocation()
-        return rval
-    
-    def crash(self):
-        super(QTReactor,self).crash()
-        
-    def iterate(self,delay=0.0):
-        t=self.running # not sure I entirely get the state of running
-        self.running=True
-        self._timer.stop() # in case its not (rare?)
-        try:
-            if delay == 0.0:
-                self.reactorInvokePrivate()
-                self._timer.stop() # supports multiple invocations
-            else:
-                endTime = delay + time.time()
-                self.reactorInvokePrivate()
-                while True:
-                    t = endTime - time.time()
-                    if t <= 0.0: return
-                    self.qApp.processEvents(QEventLoop.AllEvents | 
-                                      QEventLoop.WaitForMoreEvents,t*1010)
-        finally:
-            self.running=t
-            
-    def addReadWrite(self,t):
-        self._readWriteQ.append(t)
-        
-    def runReturn(self, installSignalHandlers=True):
-        QObject.connect(self._timer, SIGNAL("timeout()"), 
-                        self.reactorInvokePrivate)
-        self.startRunning(installSignalHandlers=installSignalHandlers)
-        self._timer.start(0)
-        
-    def run(self, installSignalHandlers=True):
-        try:
-            if self._ownApp:
-                self._blockApp=self.qApp
-            else:
-                self._blockApp = fakeApplication()
-            self.runReturn(installSignalHandlers)
-            self._blockApp.exec_()
-        finally:
-            self._timer.stop() # should already be stopped
-
-    def reactorInvocation(self):
-        self._timer.setInterval(0)
-        
-    def reactorInvokePrivate(self):
-        if not self.running:
-            if self._blockApp is None:
-                # Andy's fix for Ctrl-C quit
-                self.qApp.quit()
-            else:
-                self._blockApp.quit()
-        self._doSomethingCount += 1
-        self.runUntilCurrent()
-        t = self.timeout()
-        if t is None: t=0.1
-        else: t = min(t,0.1)
-        self._timer.setInterval(int(t*1010))
-        self.qApp.processEvents() # could change interval
-        self._timer.start()
-                
-    def doIteration(self):
-        assert False, "doiteration is invalid call"
-            
-def install():
-    """
-    Configure the twisted mainloop to be run inside the qt mainloop.
-    """
-    from twisted.internet import main
-    reactor = QTReactor()
-    main.installReactor(reactor)
index 435772f..cb6ab88 100644 (file)
@@ -87,6 +87,44 @@ OVSBOOTPROTO="dhcp"
 OVSDHCPINTERFACES="eth0"
 HOTPLUG=no
 
+
+Adding Internal Port to ovsbridge0:
+
+==> ifcfg-intbr0 <==
+DEVICE=intbr0
+ONBOOT=yes
+DEVICETYPE=ovs
+TYPE=OVSIntPort
+OVS_BRIDGE=ovsbridge0
+HOTPLUG=no
+
+
+Internal Port with fixed IP address:
+
+DEVICE=intbr0
+ONBOOT=yes
+DEVICETYPE=ovs
+TYPE=OVSIntPort
+OVS_BRIDGE=ovsbridge0
+BOOTPROTO=static
+IPADDR=A.B.C.D
+NETMASK=X.Y.Z.0
+HOTPLUG=no
+
+Internal Port with DHCP:
+* Needs OVSBOOTPROTO or BOOTPROTO.
+* All the interfaces that can reach the DHCP server
+as a space separated list in OVSDHCPINTERFACES.
+
+DEVICE=intbr0
+ONBOOT=yes
+DEVICETYPE=ovs
+TYPE=OVSIntPort
+OVS_BRIDGE=ovsbridge0
+OVSBOOTPROTO="dhcp"
+OVSDHCPINTERFACES="eth0"
+HOTPLUG=no
+
 Adding physical eth0 to ovsbridge0 described above:
 
 ==> ifcfg-eth0 <==
index 2911e71..9cd9a41 100644 (file)
@@ -22,7 +22,9 @@ EXTRA_DIST += \
        rhel/openvswitch-fedora.spec \
        rhel/openvswitch-fedora.spec.in \
        rhel/usr_share_openvswitch_scripts_sysconfig.template \
-       rhel/usr_lib_systemd_system_openvswitch.service
+       rhel/usr_share_openvswitch_scripts_systemd_sysconfig.template \
+       rhel/usr_lib_systemd_system_openvswitch.service \
+       rhel/usr_lib_systemd_system_openvswitch-nonetwork.service
 
 update_rhel_spec = \
   ($(ro_shell) && sed -e 's,[@]VERSION[@],$(VERSION),g') \
index 8e768c8..daa5786 100755 (executable)
@@ -34,7 +34,16 @@ if [ ! -x ${OTHERSCRIPT} ]; then
     OTHERSCRIPT="/etc/sysconfig/network-scripts/ifdown-eth"
 fi
 
-[ -f /var/lock/subsys/openvswitch ] || /sbin/service openvswitch start
+SERVICE_UNIT=/usr/lib/systemd/system/openvswitch-nonetwork.service
+if [ -f $SERVICE_UNIT ] && [ -x /usr/bin/systemctl ]; then
+       if ! systemctl --quiet is-active openvswitch-nonetwork.service; then
+               systemctl start openvswitch-nonetwork.service
+       fi
+else
+       if [ ! -f /var/lock/subsys/openvswitch ]; then
+               /sbin/service openvswitch start
+       fi
+fi
 
 case "$TYPE" in
        OVSBridge)
index 017346d..0ee7b21 100755 (executable)
@@ -60,7 +60,16 @@ fi
        fi
 done
 
-[ -f /var/lock/subsys/openvswitch ] || /sbin/service openvswitch start
+SERVICE_UNIT=/usr/lib/systemd/system/openvswitch-nonetwork.service
+if [ -f $SERVICE_UNIT ] && [ -x /usr/bin/systemctl ]; then
+       if ! systemctl --quiet is-active openvswitch-nonetwork.service; then
+               systemctl start openvswitch-nonetwork.service
+       fi
+else
+       if [ ! -f /var/lock/subsys/openvswitch ]; then
+               /sbin/service openvswitch start
+       fi
+fi
 
 case "$TYPE" in
        OVSBridge)
@@ -106,7 +115,12 @@ case "$TYPE" in
        OVSIntPort)
                ifup_ovs_bridge
                ovs-vsctl -t ${TIMEOUT} -- --may-exist add-port "$OVS_BRIDGE" "$DEVICE" $OVS_OPTIONS -- set Interface "$DEVICE" type=internal ${OVS_EXTRA+-- $OVS_EXTRA}
-               ${OTHERSCRIPT} ${CONFIG} ${2}
+               if [ -n "${OVSDHCPINTERFACES}" ]; then
+                       for _iface in ${OVSDHCPINTERFACES}; do
+                               /sbin/ifup ${_iface}
+                       done
+               fi
+               BOOTPROTO="${OVSBOOTPROTO}" ${OTHERSCRIPT} ${CONFIG} ${2}
                ;;
        OVSBond)
                ifup_ovs_bridge
index 5cec1ff..19fa154 100644 (file)
@@ -45,6 +45,8 @@ install -d -m 755 $RPM_BUILD_ROOT/etc
 install -d -m 755 $RPM_BUILD_ROOT/etc/openvswitch
 install -p -D -m 0644 rhel/usr_lib_systemd_system_openvswitch.service \
         $RPM_BUILD_ROOT%{_unitdir}/openvswitch.service
+install -p -D -m 0644 rhel/usr_lib_systemd_system_openvswitch-nonetwork.service \
+        $RPM_BUILD_ROOT%{_unitdir}/openvswitch-nonetwork.service
 install -m 755 rhel/etc_init.d_openvswitch \
         $RPM_BUILD_ROOT%{_datadir}/openvswitch/scripts/openvswitch.init
 install -d -m 755 $RPM_BUILD_ROOT/etc/sysconfig
@@ -60,7 +62,7 @@ install -p -m 0755 rhel/etc_sysconfig_network-scripts_ifdown-ovs \
         $RPM_BUILD_ROOT/etc/sysconfig/network-scripts/ifdown-ovs
 install -p -m 0755 rhel/etc_sysconfig_network-scripts_ifup-ovs \
         $RPM_BUILD_ROOT/etc/sysconfig/network-scripts/ifup-ovs
-install -p -D -m 0644 rhel/usr_share_openvswitch_scripts_sysconfig.template \
+install -p -D -m 0644 rhel/usr_share_openvswitch_scripts_systemd_sysconfig.template \
         $RPM_BUILD_ROOT/etc/sysconfig/openvswitch
 install -d -m 755 $RPM_BUILD_ROOT/usr/share/openvswitch/scripts
 
@@ -104,6 +106,7 @@ systemctl start openvswitch.service
 %config /etc/sysconfig/openvswitch
 %config /etc/logrotate.d/openvswitch
 %{_unitdir}/openvswitch.service
+%{_unitdir}/openvswitch-nonetwork.service
 %{_datadir}/openvswitch/scripts/openvswitch.init
 %{_sysconfdir}/sysconfig/network-scripts/ifup-ovs
 %{_sysconfdir}/sysconfig/network-scripts/ifdown-ovs
diff --git a/rhel/usr_lib_systemd_system_openvswitch-nonetwork.service b/rhel/usr_lib_systemd_system_openvswitch-nonetwork.service
new file mode 100644 (file)
index 0000000..870b25e
--- /dev/null
@@ -0,0 +1,13 @@
+[Unit]
+Description=Open vSwitch Internal Unit
+After=syslog.target
+PartOf=openvswitch.service
+Wants=openvswitch.service
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+EnvironmentFile=-/etc/sysconfig/openvswitch
+ExecStart=/usr/share/openvswitch/scripts/ovs-ctl start \
+          --system-id=random $OPTIONS
+ExecStop=/usr/share/openvswitch/scripts/ovs-ctl stop
index f39d7e6..f0bc16f 100644 (file)
@@ -1,11 +1,12 @@
 [Unit]
 Description=Open vSwitch
-After=syslog.target network.target
+After=syslog.target network.target openvswitch-nonetwork.service
+Requires=openvswitch-nonetwork.service
 
 [Service]
 Type=oneshot
-ExecStart=/usr/share/openvswitch/scripts/openvswitch.init start
-ExecStop=/usr/share/openvswitch/scripts/openvswitch.init stop
+ExecStart=/bin/true
+ExecStop=/bin/true
 RemainAfterExit=yes
 
 [Install]
diff --git a/rhel/usr_share_openvswitch_scripts_systemd_sysconfig.template b/rhel/usr_share_openvswitch_scripts_systemd_sysconfig.template
new file mode 100644 (file)
index 0000000..3050a07
--- /dev/null
@@ -0,0 +1,23 @@
+### Configuration options for openvswitch
+#
+# Enable core files:
+# --force-corefiles=yes
+#
+# Set "nice" priority at which to run ovsdb-server:
+# --ovsdb-server-priority=-10
+#
+# Set "nice" priority at which to run ovsdb-vswitchd:
+# --ovs-vswitchd-priority=-10
+#
+# Pass or not --mlockall option to ovs-vswitchd.
+# This option should be set to "yes" or "no".  The default is "yes".
+# Enabling this option can avoid networking interruptions due to
+# system memory pressure in extraordinary situations, such as multiple
+# concurrent VM import operations.
+# --mlockall=yes
+#
+# Use valgrind:
+#   --ovs-vswitchd-wrapper=valgrind
+#   --ovsdb-server-wrapper=valgrind
+#
+OPTIONS=""
index 66fd05a..0c94daf 100644 (file)
@@ -1,8 +1,8 @@
 %define name sliver-openvswitch
 # to check for any change:
 # grep AC_INIT configure.ac 
-%define version 2.0.90
-%define taglevel 1
+%define version 2.1.90
+%define taglevel 0
 
 %define debug_package %{nil}
 
index 3f5198a..f78547b 100644 (file)
@@ -192,7 +192,7 @@ tests_test_classifier_LDADD = lib/libopenvswitch.la $(SSL_LIBS)
 
 noinst_PROGRAMS += tests/test-controller
 MAN_ROOTS += tests/test-controller.8.in
-DISTCLEANFILES += utilities/test-controller.8
+DISTCLEANFILES += tests/test-controller.8
 noinst_man_MANS += tests/test-controller.8
 tests_test_controller_SOURCES = tests/test-controller.c
 tests_test_controller_LDADD = lib/libopenvswitch.la $(SSL_LIBS)
index 0015544..a46c526 100644 (file)
@@ -40,22 +40,22 @@ table=0 in_port=3 priority=0,ip,action=drop
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=2,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
-  [Relevant fields: skb_priority=0,tcp,in_port=2,nw_dst=192.168.0.0/16,nw_frag=no
+  [Megaflow: skb_priority=0,tcp,in_port=2,nw_dst=192.168.0.0/16,nw_frag=no
 Datapath actions: 1
 ])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
-  [Relevant fields: skb_priority=0,tcp,in_port=1,nw_dst=192.168.0.2,nw_frag=no
+  [Megaflow: skb_priority=0,tcp,in_port=1,nw_dst=192.168.0.2,nw_frag=no
 Datapath actions: drop
 ])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=10.1.2.15,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
-  [Relevant fields: skb_priority=0,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_dst=80
+  [Megaflow: skb_priority=0,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_dst=80
 Datapath actions: drop
 ])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=10.1.2.15,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=79'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
-  [Relevant fields: skb_priority=0,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_dst=79
+  [Megaflow: skb_priority=0,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_dst=79
 Datapath actions: 2
 ])
 OVS_VSWITCHD_STOP
@@ -87,22 +87,22 @@ table=0 in_port=3 priority=0,ip,action=drop
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
-  [Relevant fields: skb_priority=0,tcp,in_port=1,nw_dst=192.168.0.0/16,nw_frag=no
+  [Megaflow: skb_priority=0,tcp,in_port=1,nw_dst=192.168.0.0/16,nw_frag=no
 Datapath actions: drop
 ])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=2,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
-  [Relevant fields: skb_priority=0,tcp,in_port=2,nw_dst=192.168.0.0/16,nw_frag=no
+  [Megaflow: skb_priority=0,tcp,in_port=2,nw_dst=192.168.0.0/16,nw_frag=no
 Datapath actions: 1
 ])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=10.1.2.15,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
-  [Relevant fields: skb_priority=0,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_dst=80
+  [Megaflow: skb_priority=0,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_dst=80
 Datapath actions: drop
 ])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=10.1.2.15,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=79'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
-  [Relevant fields: skb_priority=0,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_src=8,tp_dst=79
+  [Megaflow: skb_priority=0,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_src=8,tp_dst=79
 Datapath actions: 3
 ])
 OVS_VSWITCHD_STOP(["/'prefixes' with incompatible field: ipv6_label/d"])
index e6df1cd..bc00df1 100644 (file)
@@ -59,6 +59,8 @@
         ovs_assert(orig == 2);                          \
         atomic_read(&x, &value);                        \
         ovs_assert(value == 8);                         \
+                                                        \
+        atomic_destroy(&x);                             \
     }
 
 static void
index 93a2dc1..4282fd4 100644 (file)
@@ -449,13 +449,13 @@ destroy_classifier(struct classifier *cls)
     struct test_rule *rule, *next_rule;
     struct cls_cursor cursor;
 
-    ovs_rwlock_wrlock(&cls->rwlock);
+    fat_rwlock_wrlock(&cls->rwlock);
     cls_cursor_init(&cursor, cls, NULL);
     CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, cls_rule, &cursor) {
         classifier_remove(cls, &rule->cls_rule);
         free_rule(rule);
     }
-    ovs_rwlock_unlock(&cls->rwlock);
+    fat_rwlock_unlock(&cls->rwlock);
     classifier_destroy(cls);
 }
 
@@ -621,13 +621,13 @@ test_empty(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
     struct tcls tcls;
 
     classifier_init(&cls, flow_segment_u32s);
-    ovs_rwlock_wrlock(&cls.rwlock);
+    fat_rwlock_wrlock(&cls.rwlock);
     classifier_set_prefix_fields(&cls, trie_fields, ARRAY_SIZE(trie_fields));
     tcls_init(&tcls);
     assert(classifier_is_empty(&cls));
     assert(tcls_is_empty(&tcls));
     compare_classifiers(&cls, &tcls);
-    ovs_rwlock_unlock(&cls.rwlock);
+    fat_rwlock_unlock(&cls.rwlock);
     classifier_destroy(&cls);
     tcls_destroy(&tcls);
 }
@@ -654,7 +654,7 @@ test_single_rule(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
                          hash_bytes(&wc_fields, sizeof wc_fields, 0), 0);
 
         classifier_init(&cls, flow_segment_u32s);
-        ovs_rwlock_wrlock(&cls.rwlock);
+        fat_rwlock_wrlock(&cls.rwlock);
         classifier_set_prefix_fields(&cls, trie_fields,
                                      ARRAY_SIZE(trie_fields));
         tcls_init(&tcls);
@@ -671,7 +671,7 @@ test_single_rule(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         compare_classifiers(&cls, &tcls);
 
         free_rule(rule);
-        ovs_rwlock_unlock(&cls.rwlock);
+        fat_rwlock_unlock(&cls.rwlock);
         classifier_destroy(&cls);
         tcls_destroy(&tcls);
     }
@@ -695,7 +695,7 @@ test_rule_replacement(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         rule2->aux += 5;
 
         classifier_init(&cls, flow_segment_u32s);
-        ovs_rwlock_wrlock(&cls.rwlock);
+        fat_rwlock_wrlock(&cls.rwlock);
         classifier_set_prefix_fields(&cls, trie_fields,
                                      ARRAY_SIZE(trie_fields));
         tcls_init(&tcls);
@@ -713,7 +713,7 @@ test_rule_replacement(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         check_tables(&cls, 1, 1, 0);
         compare_classifiers(&cls, &tcls);
         tcls_destroy(&tcls);
-        ovs_rwlock_unlock(&cls.rwlock);
+        fat_rwlock_unlock(&cls.rwlock);
         destroy_classifier(&cls);
     }
 }
@@ -809,7 +809,7 @@ test_many_rules_in_one_list (int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
             }
 
             classifier_init(&cls, flow_segment_u32s);
-            ovs_rwlock_wrlock(&cls.rwlock);
+            fat_rwlock_wrlock(&cls.rwlock);
             classifier_set_prefix_fields(&cls, trie_fields,
                                          ARRAY_SIZE(trie_fields));
             tcls_init(&tcls);
@@ -850,7 +850,7 @@ test_many_rules_in_one_list (int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
                 compare_classifiers(&cls, &tcls);
             }
 
-            ovs_rwlock_unlock(&cls.rwlock);
+            fat_rwlock_unlock(&cls.rwlock);
             classifier_destroy(&cls);
             tcls_destroy(&tcls);
 
@@ -913,7 +913,7 @@ test_many_rules_in_one_table(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         } while ((1 << count_ones(value_mask)) < N_RULES);
 
         classifier_init(&cls, flow_segment_u32s);
-        ovs_rwlock_wrlock(&cls.rwlock);
+        fat_rwlock_wrlock(&cls.rwlock);
         classifier_set_prefix_fields(&cls, trie_fields,
                                      ARRAY_SIZE(trie_fields));
         tcls_init(&tcls);
@@ -942,7 +942,7 @@ test_many_rules_in_one_table(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
             compare_classifiers(&cls, &tcls);
         }
 
-        ovs_rwlock_unlock(&cls.rwlock);
+        fat_rwlock_unlock(&cls.rwlock);
         classifier_destroy(&cls);
         tcls_destroy(&tcls);
     }
@@ -977,7 +977,7 @@ test_many_rules_in_n_tables(int n_tables)
         shuffle(priorities, ARRAY_SIZE(priorities));
 
         classifier_init(&cls, flow_segment_u32s);
-        ovs_rwlock_wrlock(&cls.rwlock);
+        fat_rwlock_wrlock(&cls.rwlock);
         classifier_set_prefix_fields(&cls, trie_fields,
                                      ARRAY_SIZE(trie_fields));
         tcls_init(&tcls);
@@ -1012,7 +1012,7 @@ test_many_rules_in_n_tables(int n_tables)
             free_rule(target);
         }
 
-        ovs_rwlock_unlock(&cls.rwlock);
+        fat_rwlock_unlock(&cls.rwlock);
         destroy_classifier(&cls);
         tcls_destroy(&tcls);
     }
index 4f22b3f..8bfa94c 100644 (file)
@@ -312,7 +312,7 @@ OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=vxlan \
 
 AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
                br0 65534/100: (dummy)
-               p1 1/1: (vxlan: remote_ip=1.1.1.1)
+               p1 1/4789: (vxlan: remote_ip=1.1.1.1)
 ])
 
 OVS_VSWITCHD_STOP
@@ -324,7 +324,7 @@ OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=lisp \
 
 AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
                br0 65534/100: (dummy)
-               p1 1/1: (lisp: remote_ip=1.1.1.1)
+               p1 1/4341: (lisp: remote_ip=1.1.1.1)
 ])
 
 OVS_VSWITCHD_STOP
@@ -336,7 +336,7 @@ OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=vxlan \
 
 AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
                br0 65534/100: (dummy)
-               p1 1/1: (vxlan: dst_port=4341, remote_ip=1.1.1.1)
+               p1 1/4341: (vxlan: dst_port=4341, remote_ip=1.1.1.1)
 ])
 
 dnl change UDP port
@@ -345,7 +345,7 @@ AT_CHECK([ovs-vsctl -- set Interface p1 options:dst_port=5000])
 
 AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
                br0 65534/100: (dummy)
-               p1 1/2: (vxlan: dst_port=5000, remote_ip=1.1.1.1)
+               p1 1/5000: (vxlan: dst_port=5000, remote_ip=1.1.1.1)
 ])
 
 dnl change UDP port to default
@@ -354,7 +354,7 @@ AT_CHECK([ovs-vsctl -- set Interface p1 options:dst_port=4789])
 
 AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
                br0 65534/100: (dummy)
-               p1 1/1: (vxlan: remote_ip=1.1.1.1)
+               p1 1/4789: (vxlan: remote_ip=1.1.1.1)
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
index 9b02b25..e8453f3 100644 (file)
@@ -2252,13 +2252,13 @@ fte_free_all(struct classifier *cls)
     struct cls_cursor cursor;
     struct fte *fte, *next;
 
-    ovs_rwlock_wrlock(&cls->rwlock);
+    fat_rwlock_wrlock(&cls->rwlock);
     cls_cursor_init(&cursor, cls, NULL);
     CLS_CURSOR_FOR_EACH_SAFE (fte, next, rule, &cursor) {
         classifier_remove(cls, &fte->rule);
         fte_free(fte);
     }
-    ovs_rwlock_unlock(&cls->rwlock);
+    fat_rwlock_unlock(&cls->rwlock);
     classifier_destroy(cls);
 }
 
@@ -2277,9 +2277,9 @@ fte_insert(struct classifier *cls, const struct match *match,
     cls_rule_init(&fte->rule, match, priority);
     fte->versions[index] = version;
 
-    ovs_rwlock_wrlock(&cls->rwlock);
+    fat_rwlock_wrlock(&cls->rwlock);
     old = fte_from_cls_rule(classifier_replace(cls, &fte->rule));
-    ovs_rwlock_unlock(&cls->rwlock);
+    fat_rwlock_unlock(&cls->rwlock);
     if (old) {
         fte_version_free(old->versions[index]);
         fte->versions[!index] = old->versions[!index];
@@ -2490,7 +2490,7 @@ ofctl_replace_flows(int argc OVS_UNUSED, char *argv[])
     list_init(&requests);
 
     /* Delete flows that exist on the switch but not in the file. */
-    ovs_rwlock_rdlock(&cls.rwlock);
+    fat_rwlock_rdlock(&cls.rwlock);
     cls_cursor_init(&cursor, &cls, NULL);
     CLS_CURSOR_FOR_EACH (fte, rule, &cursor) {
         struct fte_version *file_ver = fte->versions[FILE_IDX];
@@ -2514,7 +2514,7 @@ ofctl_replace_flows(int argc OVS_UNUSED, char *argv[])
             fte_make_flow_mod(fte, FILE_IDX, OFPFC_ADD, protocol, &requests);
         }
     }
-    ovs_rwlock_unlock(&cls.rwlock);
+    fat_rwlock_unlock(&cls.rwlock);
     transact_multiple_noreply(vconn, &requests);
     vconn_close(vconn);
 
@@ -2556,7 +2556,7 @@ ofctl_diff_flows(int argc OVS_UNUSED, char *argv[])
     ds_init(&a_s);
     ds_init(&b_s);
 
-    ovs_rwlock_rdlock(&cls.rwlock);
+    fat_rwlock_rdlock(&cls.rwlock);
     cls_cursor_init(&cursor, &cls, NULL);
     CLS_CURSOR_FOR_EACH (fte, rule, &cursor) {
         struct fte_version *a = fte->versions[0];
@@ -2576,7 +2576,7 @@ ofctl_diff_flows(int argc OVS_UNUSED, char *argv[])
             }
         }
     }
-    ovs_rwlock_unlock(&cls.rwlock);
+    fat_rwlock_unlock(&cls.rwlock);
 
     ds_destroy(&a_s);
     ds_destroy(&b_s);
index 2223d04..5db0a70 100644 (file)
@@ -965,7 +965,7 @@ Set the path cost of port \fBeth0\fR to 10:
 .PP
 Deconfigure STP from above:
 .IP
-.B "ovs\-vsctl clear Bridge br0 stp_enable"
+.B "ovs\-vsctl set Bridge br0 stp_enable=false"
 .PP
 .SS "OpenFlow Version"
 .PP
index 746097f..e6be975 100644 (file)
@@ -252,7 +252,7 @@ static struct iface *iface_lookup(const struct bridge *, const char *name);
 static struct iface *iface_find(const char *name);
 static struct iface *iface_from_ofp_port(const struct bridge *,
                                          ofp_port_t ofp_port);
-static void iface_set_mac(struct iface *);
+static void iface_set_mac(struct iface *, const uint8_t *);
 static void iface_set_ofport(const struct ovsrec_interface *, ofp_port_t ofport);
 static void iface_clear_db_record(const struct ovsrec_interface *if_cfg);
 static void iface_configure_qos(struct iface *, const struct ovsrec_qos *);
@@ -355,7 +355,6 @@ bridge_init(const char *remote)
     ovsdb_idl_omit_alert(idl, &ovsrec_port_col_status);
     ovsdb_idl_omit_alert(idl, &ovsrec_port_col_statistics);
     ovsdb_idl_omit(idl, &ovsrec_port_col_external_ids);
-    ovsdb_idl_omit(idl, &ovsrec_port_col_fake_bridge);
 
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_admin_state);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_duplex);
@@ -578,7 +577,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
             LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
                 iface_configure_cfm(iface);
                 iface_configure_qos(iface, port->cfg->qos);
-                iface_set_mac(iface);
+                iface_set_mac(iface, port->cfg->fake_bridge ? br->ea : NULL);
                 ofproto_port_set_bfd(br->ofproto, iface->ofp_port,
                                      &iface->cfg->bfd);
             }
@@ -1402,10 +1401,8 @@ iface_set_netdev_config(const struct ovsrec_interface *iface_cfg,
     return netdev_set_config(netdev, &iface_cfg->options);
 }
 
-/* Opens a network device for 'if_cfg' and configures it.  If '*ofp_portp'
- * is OFPP_NONE, adds the network device to br->ofproto and stores the OpenFlow
- * port number in '*ofp_portp'; otherwise leaves br->ofproto and '*ofp_portp'
- * untouched.
+/* Opens a network device for 'if_cfg' and configures it.  Adds the network
+ * device to br->ofproto and stores the OpenFlow port number in '*ofp_portp'.
  *
  * If successful, returns 0 and stores the network device in '*netdevp'.  On
  * failure, returns a positive errno value and stores NULL in '*netdevp'. */
@@ -3493,21 +3490,28 @@ iface_from_ofp_port(const struct bridge *br, ofp_port_t ofp_port)
 /* Set Ethernet address of 'iface', if one is specified in the configuration
  * file. */
 static void
-iface_set_mac(struct iface *iface)
+iface_set_mac(struct iface *iface, const uint8_t *mac)
 {
     uint8_t ea[ETH_ADDR_LEN];
 
-    if (!strcmp(iface->type, "internal")
-        && iface->cfg->mac && eth_addr_from_string(iface->cfg->mac, ea)) {
+    if (strcmp(iface->type, "internal")) {
+        return;
+    }
+
+    if (iface->cfg->mac && eth_addr_from_string(iface->cfg->mac, ea)) {
+        mac = ea;
+    }
+
+    if (mac) {
         if (iface->ofp_port == OFPP_LOCAL) {
             VLOG_ERR("interface %s: ignoring mac in Interface record "
                      "(use Bridge record to set local port's mac)",
                      iface->name);
-        } else if (eth_addr_is_multicast(ea)) {
+        } else if (eth_addr_is_multicast(mac)) {
             VLOG_ERR("interface %s: cannot set MAC to multicast address",
                      iface->name);
         } else {
-            int error = netdev_set_etheraddr(iface->netdev, ea);
+            int error = netdev_set_etheraddr(iface->netdev, mac);
             if (error) {
                 VLOG_ERR("interface %s: setting MAC failed (%s)",
                          iface->name, ovs_strerror(error));