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
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)
------------------------
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
- 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:
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
=================================================================
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.
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
-# 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
-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; \
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
---------------------
* 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
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])])
-# 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.
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])
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
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])
#include "datapath.h"
#include "flow.h"
+#include "flow_table.h"
#include "flow_netlink.h"
#include "vlan.h"
#include "vport-internal_dev.h"
{
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);
#endif
.snd_portid = upcall_info->portid,
};
- size_t len;
+ size_t len, plen;
unsigned int hlen;
int err, dp_ifindex;
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);
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);
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);
}
}
return flow;
err:
- kfree(flow);
+ kmem_cache_free(flow_cache, flow);
return ERR_PTR(-ENOMEM);
}
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);
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);
}
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,
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)
{
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;
}
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,
#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)
{
/openvswitch-switch
/openvswitch-switch.copyright
/openvswitch-test
-/ovsdbmonitor
/python-openvswitch
/tmp
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 \
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/
.
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
+++ /dev/null
-usr/bin/ovsdbmonitor
-usr/share/ovsdbmonitor
+++ /dev/null
-ovsdb/ovsdbmonitor/ovsdbmonitor.1
# 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
typedef uint64_t __bitwise__ __be64;
#endif /* no <linux/types.h> */
+#ifndef _WIN32
+typedef __u32 HANDLE;
+#endif
+
#endif /* <linux/types.h> */
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
--- /dev/null
+/*
+ * 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 */
};
enum {
+ SOL_PACKET,
SOL_SOCKET
};
-# 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
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 \
lib/jsonrpc.h \
lib/lacp.c \
lib/lacp.h \
- lib/latch.c \
lib/latch.h \
lib/learn.c \
lib/learn.h \
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
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.
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;
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;
}
{
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;
}
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);
}
}
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;
}
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. */
};
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);
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;
}
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);
}
{
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;
}
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;
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
free(partition);
}
hmap_destroy(&cls->partitions);
- ovs_rwlock_destroy(&cls->rwlock);
+ fat_rwlock_destroy(&cls->rwlock);
}
}
* 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"
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;
};
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)
{
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,
/*
- * 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.
#include "dynamic-string.h"
#include "flow.h"
#include "hmap.h"
+#include "latch.h"
#include "list.h"
#include "meta-flow.h"
#include "netdev.h"
#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
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. */
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)
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);
* 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;
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;
}
}
- 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);
}
}
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;
{
int i;
+ ovs_mutex_lock(&dp->queue_mutex);
for (i = 0; i < N_QUEUES; i++) {
struct dp_netdev_queue *q = &dp->queues[i];
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
{
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;
}
{
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;
}
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;
struct netdev_rx *rx;
enum netdev_flags flags;
const char *open_type;
- int mtu;
int error;
/* XXX reject devices already in some dp_netdev. */
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;
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;
*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;
}
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;
}
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;
}
}
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;
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;
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);
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;
}
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
{
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
{
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;
};
{
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
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;
} else {
error = EAGAIN;
}
- ovs_mutex_unlock(&dp_netdev_mutex);
return error;
}
{
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;
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;
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) {
} 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;
}
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;
}
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;
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;
*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;
}
{
struct dp_netdev_flow_state *state = state_;
- free(state->actions);
+ dp_netdev_actions_unref(state->actions);
free(state);
return 0;
}
/* 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;
}
}
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++) {
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];
} else {
error = EAGAIN;
}
- ovs_mutex_unlock(&dp_netdev_mutex);
+ ovs_mutex_unlock(&dp->queue_mutex);
return error;
}
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);
}
}
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;
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 {
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: {
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};
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, \
{
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
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'.
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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 */
}
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)) {
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 {
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);
{
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;
}
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);
hmap_destroy(&lacp->slaves);
list_remove(&lacp->node);
free(lacp->name);
+ ovs_refcount_destroy(&lacp->ref_cnt);
free(lacp);
ovs_mutex_unlock(&mutex);
}
--- /dev/null
+/*
+ * 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);
+}
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);
}
#include "util.h"
struct latch {
+#ifndef _WIN32
int fds[2];
+#else
+ HANDLE wevent;
+ bool is_set;
+#endif
};
void latch_init(struct latch *);
/*
- * 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.
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;
}
{
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;
}
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) {
bitmap_free(ml->flood_vlans);
ovs_rwlock_destroy(&ml->rwlock);
+ ovs_refcount_destroy(&ml->ref_cnt);
free(ml);
}
}
/*
- * 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.
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;
};
* 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) {
}
}
- return -EAGAIN;
+ return EAGAIN;
}
}
* '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));
}
/*
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;
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;
list_remove(&rx->node);
ofpbuf_list_delete(&rx->recv_queue);
ovs_mutex_unlock(&netdev->mutex);
+ seq_destroy(rx->seq);
}
static void
}
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);
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);
{
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);
}
rx->recv_queue_len = 0;
ovs_mutex_unlock(&netdev->mutex);
+ seq_change(rx->seq);
+
return 0;
}
{
list_push_back(&rx->recv_queue, &packet->list_node);
rx->recv_queue_len++;
+ seq_change(rx->seq);
}
static void
/*
- * 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.
#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,
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] */
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) {
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)",
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
}
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;
netdev_pltap_update_flags,
- netdev_pltap_change_seq,
-
netdev_pltap_rx_alloc,
netdev_pltap_rx_construct,
netdev_pltap_rx_destruct,
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()
}
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);
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 {
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,
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 {
}
}
+/* 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)
return error;
}
+/* Closes 'rx'. */
void
netdev_rx_close(struct netdev_rx *rx)
OVS_EXCLUDED(netdev_mutex)
}
}
+/* 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)
{
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)
{
/*
- * 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.
* 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)
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;
}
(*(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. */
+}
#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. */
} 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)
\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)
} 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)
{
#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
/*
- * 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_)
{
((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)
} 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);
* 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 */
/*
- * 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 <stdlib.h>
#include <unistd.h>
#include "compiler.h"
+#include "hash.h"
#include "poll-loop.h"
#include "socket-util.h"
#include "util.h"
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
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.
*
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
/*
- * 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.
#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 *);
\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
* 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
* 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:
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.
*
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)
*
* 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;
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;
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);
/*
- * 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. */
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'
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. */
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. */
}
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);
} 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();
{
struct poll_loop *loop = loop_;
- free(loop->pollfds);
- free(loop->where);
+ free_poll_nodes(loop);
+ hmap_destroy(&loop->poll_nodes);
free(loop);
}
loop = pthread_getspecific(key);
if (!loop) {
loop = xzalloc(sizeof *loop);
+ hmap_init(&loop->poll_nodes);
xpthread_setspecific(key, loop);
}
return loop;
* 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)
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) {
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;
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);
{
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;
}
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);
}
}
/*
- * 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.
*
* 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();
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);
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 *);
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);
# -*- 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.
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])
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])
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;
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;
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;
}
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;
}
free(bond->hash);
free(bond->name);
+ ovs_refcount_destroy(&bond->ref_cnt);
free(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;
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 *);
static void
update_fail_open(struct connmgr *mgr)
+ OVS_EXCLUDED(ofproto_mutex)
{
if (connmgr_has_controllers(mgr)
&& mgr->fail_mode == OFPROTO_FAIL_STANDALONE) {
* 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)) {
static void
fail_open_recover(struct fail_open *fo)
+ OVS_EXCLUDED(ofproto_mutex)
{
struct match match;
/* Destroys 'fo'. */
void
fail_open_destroy(struct fail_open *fo)
+ OVS_EXCLUDED(ofproto_mutex)
{
if (fo) {
if (fail_open_is_active(fo)) {
}
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 */
/*
- * 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.
struct hmap flows; /* Contains 'netflow_flows'. */
- atomic_int ref_cnt;
+ struct ovs_refcount ref_cnt;
};
struct netflow_flow {
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;
{
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;
}
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);
}
}
/*
- * 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.
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
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;
}
{
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;
}
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);
}
/*
- * 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.
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;
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);
/* 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);
/* 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);
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)
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
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,
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;
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 *,
hmap_init(&ds->ports);
ds->probability = 0;
route_table_register();
- atomic_init(&ds->ref_cnt, 1);
+ ovs_refcount_init(&ds->ref_cnt);
return 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;
}
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();
dpif_sflow_del_port__(ds, dsp);
}
hmap_destroy(&ds->ports);
+ ovs_refcount_destroy(&ds->ref_cnt);
free(ds);
}
}
-/* 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.
struct odputil_keybuf mask_buf;
struct xlate_out xout;
+
+ bool put;
};
static void upcall_destroy(struct upcall *);
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);
}
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);
}
coverage_clear();
}
+
+ return NULL;
}
static void *
miss->stats.used = time_msec();
miss->stats.tcp_flags = 0;
miss->odp_in_port = odp_in_port;
+ miss->put = false;
n_misses++;
} else {
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;
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;
}
}
+ /*
+ * 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;
-/* 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.
* 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;
* 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;
/* 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);
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) {
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. */
}
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);
}
/*
- * 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.
#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"
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);
}
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. */
*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;
}
struct xlate_out xout;
struct xlate_in xin;
struct flow flow;
+ struct flow_wildcards wc;
struct ds *result;
};
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)
{
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);
}
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) {
}
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;
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,
-/* 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.
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
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 *);
* 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);
* '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. */
/*
- * 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");
}
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
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
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);
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
eviction_group_add_rule(rule);
}
}
- ovs_rwlock_unlock(&table->cls.rwlock);
+ fat_rwlock_unlock(&table->cls.rwlock);
ovs_mutex_unlock(&ofproto_mutex);
}
}
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);
/* 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) {
} 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
/* 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;
}
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);
}
}
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);
}
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
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);
}
}
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);
}
}
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);
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);
break;
}
}
- ovs_rwlock_unlock(&table->cls.rwlock);
+ fat_rwlock_unlock(&table->cls.rwlock);
}
}
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) {
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);
}
}
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)) {
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);
/* 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();
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) {
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
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. */
{
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);
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
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;
}
}
}
- ovs_rwlock_unlock(&oftable->cls.rwlock);
+ fat_rwlock_unlock(&oftable->cls.rwlock);
}
}
-/* 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.
{
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)) {
noinst_SCRIPTS += ovsdb/ovsdb-dot
DISTCLEANFILES += ovsdb/ovsdb-dot
OVSDB_DOT = $(run_python) $(srcdir)/ovsdb/ovsdb-dot.in
-
-include ovsdb/ovsdbmonitor/automake.mk
+++ /dev/null
-/ovsdbmonitor
+++ /dev/null
-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.
+++ /dev/null
-<?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>
+++ /dev/null
-<?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>
+++ /dev/null
-<?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>
+++ /dev/null
-<?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>
+++ /dev/null
-<?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>
+++ /dev/null
-# 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
+++ /dev/null
-# 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()
-
+++ /dev/null
-# 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()"))
+++ /dev/null
-# 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()
-
-
+++ /dev/null
-# 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')
+++ /dev/null
-# 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)
+++ /dev/null
-# 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())
- }
-
+++ /dev/null
-# 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()
+++ /dev/null
-# 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)
-
+++ /dev/null
-# 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)
+++ /dev/null
-# 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
-
+++ /dev/null
-# 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)]
+++ /dev/null
-# -*- 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))
-
+++ /dev/null
-# -*- 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))
-
+++ /dev/null
-# -*- 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))
-
+++ /dev/null
-# -*- 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))
-
+++ /dev/null
-# -*- 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))
-
+++ /dev/null
-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/' > $@
+++ /dev/null
-.\" -*- 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.
+++ /dev/null
-[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;
+++ /dev/null
-#! @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)
+++ /dev/null
-# 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)
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 <==
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') \
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)
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)
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
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
$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
%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
--- /dev/null
+[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
[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]
--- /dev/null
+### 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=""
%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}
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)
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
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"])
ovs_assert(orig == 2); \
atomic_read(&x, &value); \
ovs_assert(value == 8); \
+ \
+ atomic_destroy(&x); \
}
static void
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);
}
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);
}
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);
compare_classifiers(&cls, &tcls);
free_rule(rule);
- ovs_rwlock_unlock(&cls.rwlock);
+ fat_rwlock_unlock(&cls.rwlock);
classifier_destroy(&cls);
tcls_destroy(&tcls);
}
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);
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);
}
}
}
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);
compare_classifiers(&cls, &tcls);
}
- ovs_rwlock_unlock(&cls.rwlock);
+ fat_rwlock_unlock(&cls.rwlock);
classifier_destroy(&cls);
tcls_destroy(&tcls);
} 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);
compare_classifiers(&cls, &tcls);
}
- ovs_rwlock_unlock(&cls.rwlock);
+ fat_rwlock_unlock(&cls.rwlock);
classifier_destroy(&cls);
tcls_destroy(&tcls);
}
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);
free_rule(target);
}
- ovs_rwlock_unlock(&cls.rwlock);
+ fat_rwlock_unlock(&cls.rwlock);
destroy_classifier(&cls);
tcls_destroy(&tcls);
}
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_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
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
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
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
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);
}
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];
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];
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);
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];
}
}
}
- ovs_rwlock_unlock(&cls.rwlock);
+ fat_rwlock_unlock(&cls.rwlock);
ds_destroy(&a_s);
ds_destroy(&b_s);
.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
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 *);
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);
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);
}
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'. */
/* 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));