Merge branch 'mainstream'
authorGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Mon, 29 Oct 2012 16:27:21 +0000 (17:27 +0100)
committerGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Mon, 29 Oct 2012 16:27:21 +0000 (17:27 +0100)
139 files changed:
AUTHORS
FAQ
INSTALL.Fedora [new file with mode: 0644]
Makefile.am
NEWS
configure.ac
datapath/actions.c
datapath/datapath.c
datapath/datapath.h
datapath/flow.c
datapath/flow.h
datapath/tunnel.c
datapath/tunnel.h
datapath/vport-capwap.c
datapath/vport-gre.c
datapath/vport-netdev.c
datapath/vport.c
datapath/vport.h
debian/changelog
debian/ifupdown.sh
debian/openvswitch-common.install
debian/openvswitch-common.manpages
debian/openvswitch-switch.init
debian/openvswitch-switch.postinst
debian/ovs-monitor-ipsec
include/linux/openvswitch.h
include/openflow/nicira-ext.h
include/openflow/openflow-1.2.h
lib/automake.mk
lib/autopath.c
lib/bundle.c
lib/cfm.c
lib/cfm.h
lib/command-line.c
lib/command-line.h
lib/daemon.c
lib/dpif-linux.c
lib/dpif-netdev.c
lib/dpif-provider.h
lib/dpif.c
lib/fatal-signal.c
lib/flow.c
lib/flow.h
lib/jsonrpc.c
lib/jsonrpc.h
lib/learning-switch.c
lib/match.c
lib/match.h
lib/meta-flow.c
lib/netdev-vport.c
lib/netdev.c
lib/nx-match.c
lib/odp-util.c
lib/odp-util.h
lib/ofp-actions.c
lib/ofp-actions.h
lib/ofp-errors.h
lib/ofp-msgs.h
lib/ofp-parse.c
lib/ofp-print.c
lib/ofp-util.c
lib/ofp-util.def
lib/ofp-util.h
lib/ovsdb-idl.c
lib/ovsdb-idl.h
lib/packets.h
lib/poll-loop.c
lib/process.c
lib/route-table-stub.c [new file with mode: 0644]
lib/signals.c
lib/socket-util.c
lib/socket-util.h
lib/stream-fd.c
lib/stream-fd.h
lib/stream-provider.h
lib/stream-ssl.c
lib/stream-tcp.c
lib/stream-unix.c
lib/stream.c
lib/stream.h
lib/timeval.c
lib/timeval.h
lib/vlandev.c
lib/worker.c
m4/openvswitch.m4
ofproto/ofproto-dpif.c
ofproto/ofproto-provider.h
ofproto/ofproto.c
ofproto/ofproto.h
ovsdb/jsonrpc-server.c
ovsdb/jsonrpc-server.h
ovsdb/ovsdb-server.1.in
ovsdb/ovsdb-server.c
ovsdb/server.c
ovsdb/server.h
ovsdb/trigger.c
ovsdb/trigger.h
python/ovs/db/idl.py
python/ovs/socket_util.py
python/ovs/stream.py
rhel/.gitignore
rhel/automake.mk
rhel/etc_init.d_openvswitch
rhel/openvswitch-fedora.spec.in [new file with mode: 0644]
rhel/openvswitch-kmod-fedora.spec.in [new file with mode: 0644]
rhel/openvswitch.spec.in
rhel/usr_lib_systemd_system_openvswitch.service [new file with mode: 0644]
tests/atlocal.in
tests/automake.mk
tests/ofp-actions.at
tests/ofp-print.at
tests/ofproto-dpif.at
tests/ofproto.at
tests/ovs-ofctl.at
tests/ovsdb-idl.at
tests/ovsdb-server.at
tests/test-classifier.c
tests/test-flows.c
tests/test-ovsdb.c
tests/test-ovsdb.py
tests/test-vconn.c
utilities/.gitignore
utilities/automake.mk
utilities/ovs-ctl.8
utilities/ovs-ctl.in
utilities/ovs-lib.in
utilities/ovs-ofctl.8.in
utilities/ovs-ofctl.c
utilities/ovs-parse-backtrace.8 [new file with mode: 0644]
utilities/ovs-parse-backtrace.in [new file with mode: 0755]
utilities/ovs-pki.in
utilities/ovs-save
utilities/ovs-vsctl.c
vswitchd/automake.mk
vswitchd/bridge.c
vswitchd/system-stats.c
vswitchd/vswitch.xml
xenserver/etc_init.d_openvswitch
xenserver/openvswitch-xen.spec.in

diff --git a/AUTHORS b/AUTHORS
index 1ed8676..4687865 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -30,6 +30,7 @@ Gaetano Catalli         gaetano.catalli@gmail.com
 Giuseppe Lettieri       g.lettieri@iet.unipi.it
 Glen Gibb               grg@stanford.edu
 Gurucharan Shetty       gshetty@nicira.com
+Henry Mai               hmai@nicira.com
 Hao Zheng               hzheng@nicira.com
 Ian Campbell            Ian.Campbell@citrix.com
 Isaku Yamahata          yamahata@valinux.co.jp
diff --git a/FAQ b/FAQ
index a98739c..b14bfa4 100644 (file)
--- a/FAQ
+++ b/FAQ
@@ -747,6 +747,27 @@ A: ovs-dpctl queries a kernel datapath, not an OpenFlow switch.  It
    won't display the information that you want.  You want to use
    "ovs-ofctl dump-flows" instead.
 
+Q: It looks like each of the interfaces in my bonded port shows up
+   as an individual OpenFlow port.  Is that right?
+
+A: Yes, Open vSwitch makes individual bond interfaces visible as
+   OpenFlow ports, rather than the bond as a whole.  The interfaces
+   are treated together as a bond for only a few purposes:
+
+       - Sending a packet to the OFPP_NORMAL port.  (When an OpenFlow
+         controller is not configured, this happens implicitly to
+         every packet.)
+
+       - The "autopath" Nicira extension action.  However, "autopath"
+         is deprecated and scheduled for removal in February 2013.
+
+       - Mirrors configured for output to a bonded port.
+
+   It would make a lot of sense for Open vSwitch to present a bond as
+   a single OpenFlow port.  If you want to contribute an
+   implementation of such a feature, please bring it up on the Open
+   vSwitch development mailing list at dev@openvswitch.org.
+
 Contact 
 -------
 
diff --git a/INSTALL.Fedora b/INSTALL.Fedora
new file mode 100644 (file)
index 0000000..708cae6
--- /dev/null
@@ -0,0 +1,52 @@
+       How to Install Open vSwitch on Fedora Linux
+       ===========================================
+
+This document describes how to build and install Open vSwitch on a Fedora
+Linux host.  If you want to install Open vSwitch on a generic Linux host,
+see INSTALL.Linux instead.
+
+We have tested these instructions with Fedora 16 and Fedora 17.
+
+Building Open vSwitch for Fedora
+--------------------------------
+
+You may build from an Open vSwitch distribution tarball or from an
+Open vSwitch Git tree.
+
+Before you begin, note the RPM source directory on your version of
+Fedora.  On Fedora 17, it is $HOME/rpmbuild/SOURCES.
+
+1. If you are building from an Open vSwitch Git tree, then you will
+   need to first create a distribution tarball by running "./boot.sh;
+   ./configure; make dist" in the Git tree.
+
+2. Copy the distribution tarball into the RPM source directory.
+
+3. Unpack the distribution tarball into a temporary directory and "cd"
+   into the root of the distribution tarball.
+
+4. To build Open vSwitch userspace, run:
+
+       rpmbuild -bb rhel/openvswitch-fedora.spec
+
+   This produces one RPM: "openvswitch".
+
+5. On Fedora 17, to build the Open vSwitch kernel module, run:
+
+       rpmbuild -bb rhel/openvswitch-kmod-fedora.spec
+
+    You might have to specify a kernel version and/or variants, e.g.:
+
+       rpmbuild -bb \
+               -D "kversion 2.6.32-131.6.1.el6.x86_64" \
+               -D "kflavors default debug kdump" \
+               rhel/openvswitch-kmod-rhel6.spec
+
+    This produces an "kmod-openvswitch" RPM for each kernel variant,
+    in this example: "kmod-openvswitch", "kmod-openvswitch-debug", and
+    "kmod-openvswitch-kdump".
+
+Reporting Bugs
+--------------
+
+Please report problems to bugs@openvswitch.org.
index 887b1d7..4da1bab 100644 (file)
@@ -43,6 +43,7 @@ EXTRA_DIST = \
        DESIGN \
        FAQ \
        INSTALL \
+       INSTALL.Fedora \
        INSTALL.KVM \
        INSTALL.Libvirt \
        INSTALL.RHEL \
diff --git a/NEWS b/NEWS
index 38e5129..fa0a249 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,12 @@
-post-v1.8.0
-------------------------
+post-v1.9.0
+--------------------
+
+
+v1.9.0 - xx xxx xxxx
+--------------------
+    - The tunneling code no longer assumes input and output keys are symmetric.
+      If they are not, PMTUD needs to be disabled for tunneling to work. Note
+      this only applies to flow-based keys.
     - FreeBSD is now a supported platform, thanks to code contributions from
       Gaetano Catalli, Ed Maste, and Giuseppe Lettieri.
     - ovs-bugtool: New --ovs option to report only OVS related information.
@@ -9,14 +16,13 @@ post-v1.8.0
     - OpenFlow:
       - Allow bitwise masking for SHA and THA fields in ARP, SLL and TLL
         fields in IPv6 neighbor discovery messages, and IPv6 flow label.
+      - Adds support for writing to the metadata field for a flow.
     - ovs-ofctl:
       - Commands and actions that accept port numbers now also accept keywords
         that represent those ports (such as LOCAL, NONE, and ALL).  This is
         also the recommended way to specify these ports, for compatibility
         with OpenFlow 1.1 and later (which use the OpenFlow 1.0 numbers
         for these ports for different purposes).
-      - Commands and actions that accept port numbers no longer accept port 0,
-        which is not a valid port number in OpenFlow 1.0 and later.
     - ovs-dpctl:
       - Support requesting the port number with the "port_no" option in
         the "add-if" command.
@@ -26,14 +32,17 @@ post-v1.8.0
       are true, but because we do not know of any users for this
       feature it seems better on balance to remove it.  (The ovs-pki-cgi
       program was not included in distribution packaging.)
+    - Tunnel Path MTU Discovery default value was set to 'disabled'.
     - ovsdb-server now enforces the immutability of immutable columns.  This
       was not enforced in earlier versions due to an oversight.
-    - Stable bond mode is deprecated and will be removed no earlier than
-      February 2013.  Please email dev@openvswitch.org with concerns.
-    - The autopath action is deprecated and will be removed no earlier than
-      February 2013.  Please email dev@openvswitch.org with concerns.
-    - The null interface type is deprecated and will be removed no earlier
-      than February 2013.  Please email dev@openvswitch.org with concerns.
+    - New support for a nonstandard form of GRE that supports a 64-bit key.
+    - The following features are now deprecated.  They will be removed no
+      earlier than February 2013.  Please email dev@openvswitch.org with
+      concerns.
+        - Stable bond mode.
+        - The autopath action.
+        - Interface type "null".
+        - Numeric values for reserved ports (see "ovs-ofctl" note above).
 
 
 v1.8.0 - xx xxx xxxx
index 9bdffea..32940a5 100644 (file)
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 AC_PREREQ(2.64)
-AC_INIT(openvswitch, 1.8.90, ovs-bugs@openvswitch.org)
+AC_INIT(openvswitch, 1.9.90, ovs-bugs@openvswitch.org)
 AC_CONFIG_SRCDIR([datapath/datapath.c])
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_AUX_DIR([build-aux])
@@ -34,6 +34,8 @@ if test "$PERL" = no; then
    AC_MSG_ERROR([Perl interpreter not found in $PATH or $PERL.])
 fi
 
+AM_MISSING_PROG([AUTOM4TE], [autom4te])
+
 AC_USE_SYSTEM_EXTENSIONS
 AC_C_BIGENDIAN
 AC_SYS_LARGEFILE
@@ -43,6 +45,7 @@ AC_SEARCH_LIBS([clock_gettime], [rt])
 AC_SEARCH_LIBS([timer_create], [rt])
 AC_SEARCH_LIBS([pcap_open_live], [pcap])
 
+OVS_CHECK_ESX
 OVS_CHECK_COVERAGE
 OVS_CHECK_NDEBUG
 OVS_CHECK_NETLINK
@@ -58,7 +61,7 @@ OVS_CHECK_STRTOK_R
 AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec, struct stat.st_mtimensec],
   [], [], [[#include <sys/stat.h>]])
 AC_CHECK_FUNCS([mlockall strnlen strsignal getloadavg statvfs setmntent])
-AC_CHECK_HEADERS([mntent.h sys/statvfs.h linux/types.h])
+AC_CHECK_HEADERS([mntent.h sys/statvfs.h linux/types.h execinfo.h])
 
 OVS_CHECK_PKIDIR
 OVS_CHECK_RUNDIR
@@ -72,6 +75,7 @@ OVS_CHECK_XENSERVER_VERSION
 OVS_CHECK_GROFF
 OVS_CHECK_BRCOMPAT
 OVS_CHECK_GNU_MAKE
+OVS_CHECK_CACHE_TIME
 
 OVS_ENABLE_OPTION([-Wall])
 OVS_ENABLE_OPTION([-Wno-sign-compare])
@@ -110,4 +114,9 @@ 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])
+if test "$HAVE_NETLINK" = yes && test "$ESX" = no; then
+    AC_DEFINE([LINUX_DATAPATH], [1], [System uses the linux datapath module.])
+fi
+
 AC_OUTPUT
index ec9b595..4649c05 100644 (file)
@@ -37,7 +37,8 @@
 #include "vport.h"
 
 static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
-                       const struct nlattr *attr, int len, bool keep_skb);
+                             const struct nlattr *attr, int len,
+                             struct ovs_key_ipv4_tunnel *tun_key, bool keep_skb);
 
 static int make_writable(struct sk_buff *skb, int write_len)
 {
@@ -308,7 +309,8 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb,
 }
 
 static int sample(struct datapath *dp, struct sk_buff *skb,
-                 const struct nlattr *attr)
+                 const struct nlattr *attr,
+                 struct ovs_key_ipv4_tunnel *tun_key)
 {
        const struct nlattr *acts_list = NULL;
        const struct nlattr *a;
@@ -329,11 +331,12 @@ static int sample(struct datapath *dp, struct sk_buff *skb,
        }
 
        return do_execute_actions(dp, skb, nla_data(acts_list),
-                                                nla_len(acts_list), true);
+                                 nla_len(acts_list), tun_key, true);
 }
 
 static int execute_set_action(struct sk_buff *skb,
-                                const struct nlattr *nested_attr)
+                                const struct nlattr *nested_attr,
+                                struct ovs_key_ipv4_tunnel *tun_key)
 {
        int err = 0;
 
@@ -343,7 +346,21 @@ static int execute_set_action(struct sk_buff *skb,
                break;
 
        case OVS_KEY_ATTR_TUN_ID:
-               OVS_CB(skb)->tun_id = nla_get_be64(nested_attr);
+               if (!OVS_CB(skb)->tun_key) {
+                       /* If tun_key is NULL for this skb, assign it to
+                        * a value the caller passed in for action processing
+                        * and output. This can disappear once we drop support
+                        * for setting tun_id outside of tun_key.
+                        */
+                       memset(tun_key, 0, sizeof(struct ovs_key_ipv4_tunnel));
+                       OVS_CB(skb)->tun_key = tun_key;
+               }
+
+               OVS_CB(skb)->tun_key->tun_id = nla_get_be64(nested_attr);
+               break;
+
+       case OVS_KEY_ATTR_IPV4_TUNNEL:
+               OVS_CB(skb)->tun_key = nla_data(nested_attr);
                break;
 
        case OVS_KEY_ATTR_ETHERNET:
@@ -368,7 +385,8 @@ static int execute_set_action(struct sk_buff *skb,
 
 /* Execute a list of actions against 'skb'. */
 static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
-                       const struct nlattr *attr, int len, bool keep_skb)
+                       const struct nlattr *attr, int len,
+                       struct ovs_key_ipv4_tunnel *tun_key, bool keep_skb)
 {
        /* Every output action needs a separate clone of 'skb', but the common
         * case is just a single output action, so that doing a clone and
@@ -407,11 +425,11 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
                        break;
 
                case OVS_ACTION_ATTR_SET:
-                       err = execute_set_action(skb, nla_data(a));
+                       err = execute_set_action(skb, nla_data(a), tun_key);
                        break;
 
                case OVS_ACTION_ATTR_SAMPLE:
-                       err = sample(dp, skb, a);
+                       err = sample(dp, skb, a, tun_key);
                        break;
                }
 
@@ -458,6 +476,7 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb)
        struct sw_flow_actions *acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts);
        struct loop_counter *loop;
        int error;
+       struct ovs_key_ipv4_tunnel tun_key;
 
        /* Check whether we've looped too much. */
        loop = &__get_cpu_var(loop_counters);
@@ -469,9 +488,9 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb)
                goto out_loop;
        }
 
-       OVS_CB(skb)->tun_id = 0;
+       OVS_CB(skb)->tun_key = NULL;
        error = do_execute_actions(dp, skb, acts->actions,
-                                        acts->actions_len, false);
+                                        acts->actions_len, &tun_key, false);
 
        /* Check whether sub-actions looped too much. */
        if (unlikely(loop->looping))
index a6915fb..65f4dc8 100644 (file)
@@ -587,12 +587,19 @@ static int validate_set(const struct nlattr *a,
 
        switch (key_type) {
        const struct ovs_key_ipv4 *ipv4_key;
+       const struct ovs_key_ipv4_tunnel *tun_key;
 
        case OVS_KEY_ATTR_PRIORITY:
        case OVS_KEY_ATTR_TUN_ID:
        case OVS_KEY_ATTR_ETHERNET:
                break;
 
+       case OVS_KEY_ATTR_IPV4_TUNNEL:
+               tun_key = nla_data(ovs_key);
+               if (!tun_key->ipv4_dst)
+                       return -EINVAL;
+               break;
+
        case OVS_KEY_ATTR_IPV4:
                if (flow_key->eth.type != htons(ETH_P_IP))
                        return -EINVAL;
@@ -783,10 +790,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
        if (err)
                goto err_flow_put;
 
-       err = ovs_flow_metadata_from_nlattrs(&flow->key.phy.priority,
-                                            &flow->key.phy.in_port,
-                                            &flow->key.phy.tun_id,
-                                            a[OVS_PACKET_ATTR_KEY]);
+       err = ovs_flow_metadata_from_nlattrs(flow, key_len, a[OVS_PACKET_ATTR_KEY]);
        if (err)
                goto err_flow_put;
 
@@ -794,8 +798,6 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
        if (err)
                goto err_flow_put;
 
-       flow->hash = ovs_flow_hash(&flow->key, key_len);
-
        acts = ovs_flow_actions_alloc(a[OVS_PACKET_ATTR_ACTIONS]);
        err = PTR_ERR(acts);
        if (IS_ERR(acts))
@@ -1066,7 +1068,6 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
                        error = PTR_ERR(flow);
                        goto error;
                }
-               flow->key = key;
                clear_stats(flow);
 
                /* Obtain actions. */
@@ -1077,8 +1078,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
                rcu_assign_pointer(flow->sf_acts, acts);
 
                /* Put flow in bucket. */
-               flow->hash = ovs_flow_hash(&key, key_len);
-               ovs_flow_tbl_insert(table, flow);
+               ovs_flow_tbl_insert(table, flow, &key, key_len);
 
                reply = ovs_flow_cmd_build_info(flow, dp, info->snd_pid,
                                                info->snd_seq,
index affbf0e..c5df12d 100644 (file)
@@ -96,7 +96,8 @@ struct datapath {
 /**
  * struct ovs_skb_cb - OVS data in skb CB
  * @flow: The flow associated with this packet.  May be %NULL if no flow.
- * @tun_id: ID of the tunnel that encapsulated this packet.  It is 0 if the
+ * @tun_key: Key for the tunnel that encapsulated this packet. NULL if the
+ * packet is not being tunneled.
  * @ip_summed: Consistently stores L4 checksumming status across different
  * kernel versions.
  * @csum_start: Stores the offset from which to start checksumming independent
@@ -107,7 +108,7 @@ struct datapath {
  */
 struct ovs_skb_cb {
        struct sw_flow          *flow;
-       __be64                  tun_id;
+       struct ovs_key_ipv4_tunnel  *tun_key;
 #ifdef NEED_CSUM_NORMALIZE
        enum csum_type          ip_summed;
        u16                     csum_start;
index d07337c..c70daee 100644 (file)
@@ -365,6 +365,14 @@ struct sw_flow *ovs_flow_tbl_next(struct flow_table *table, u32 *bucket, u32 *la
        return NULL;
 }
 
+static void __flow_tbl_insert(struct flow_table *table, struct sw_flow *flow)
+{
+       struct hlist_head *head;
+       head = find_bucket(table, flow->hash);
+       hlist_add_head_rcu(&flow->hash_node[table->node_ver], head);
+       table->count++;
+}
+
 static void flow_table_copy_flows(struct flow_table *old, struct flow_table *new)
 {
        int old_ver;
@@ -382,7 +390,7 @@ static void flow_table_copy_flows(struct flow_table *old, struct flow_table *new
                head = flex_array_get(old->buckets, i);
 
                hlist_for_each_entry(flow, n, head, hash_node[old_ver])
-                       ovs_flow_tbl_insert(new, flow);
+                       __flow_tbl_insert(new, flow);
        }
        old->keep_flows = true;
 }
@@ -629,7 +637,8 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
        memset(key, 0, sizeof(*key));
 
        key->phy.priority = skb->priority;
-       key->phy.tun_id = OVS_CB(skb)->tun_id;
+       if (OVS_CB(skb)->tun_key)
+               memcpy(&key->phy.tun.tun_key, OVS_CB(skb)->tun_key, sizeof(key->phy.tun.tun_key));
        key->phy.in_port = in_port;
 
        skb_reset_mac_header(skb);
@@ -729,15 +738,11 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
                        /* We only match on the lower 8 bits of the opcode. */
                        if (ntohs(arp->ar_op) <= 0xff)
                                key->ip.proto = ntohs(arp->ar_op);
-
-                       if (key->ip.proto == ARPOP_REQUEST
-                                       || key->ip.proto == ARPOP_REPLY) {
-                               memcpy(&key->ipv4.addr.src, arp->ar_sip, sizeof(key->ipv4.addr.src));
-                               memcpy(&key->ipv4.addr.dst, arp->ar_tip, sizeof(key->ipv4.addr.dst));
-                               memcpy(key->ipv4.arp.sha, arp->ar_sha, ETH_ALEN);
-                               memcpy(key->ipv4.arp.tha, arp->ar_tha, ETH_ALEN);
-                               key_len = SW_FLOW_KEY_OFFSET(ipv4.arp);
-                       }
+                       memcpy(&key->ipv4.addr.src, arp->ar_sip, sizeof(key->ipv4.addr.src));
+                       memcpy(&key->ipv4.addr.dst, arp->ar_tip, sizeof(key->ipv4.addr.dst));
+                       memcpy(key->ipv4.arp.sha, arp->ar_sha, ETH_ALEN);
+                       memcpy(key->ipv4.arp.tha, arp->ar_tha, ETH_ALEN);
+                       key_len = SW_FLOW_KEY_OFFSET(ipv4.arp);
                }
        } else if (key->eth.type == htons(ETH_P_IPV6)) {
                int nh_len;             /* IPv6 Header + Extensions */
@@ -786,9 +791,18 @@ out:
        return error;
 }
 
-u32 ovs_flow_hash(const struct sw_flow_key *key, int key_len)
+static u32 ovs_flow_hash(const struct sw_flow_key *key, int key_start, int key_len)
+{
+       return jhash2((u32 *)((u8 *)key + key_start),
+                     DIV_ROUND_UP(key_len - key_start, sizeof(u32)), 0);
+}
+
+static int flow_key_start(struct sw_flow_key *key)
 {
-       return jhash2((u32 *)key, DIV_ROUND_UP(key_len, sizeof(u32)), 0);
+       if (key->phy.tun.tun_key.ipv4_dst)
+               return 0;
+       else
+               return offsetof(struct sw_flow_key, phy.priority);
 }
 
 struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *table,
@@ -797,28 +811,31 @@ struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *table,
        struct sw_flow *flow;
        struct hlist_node *n;
        struct hlist_head *head;
+       u8 *_key;
+       int key_start;
        u32 hash;
 
-       hash = ovs_flow_hash(key, key_len);
+       key_start = flow_key_start(key);
+       hash = ovs_flow_hash(key, key_start, key_len);
 
+       _key = (u8 *) key + key_start;
        head = find_bucket(table, hash);
        hlist_for_each_entry_rcu(flow, n, head, hash_node[table->node_ver]) {
 
                if (flow->hash == hash &&
-                   !memcmp(&flow->key, key, key_len)) {
+                   !memcmp((u8 *)&flow->key + key_start, _key, key_len - key_start)) {
                        return flow;
                }
        }
        return NULL;
 }
 
-void ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow)
+void ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow,
+                        struct sw_flow_key *key, int key_len)
 {
-       struct hlist_head *head;
-
-       head = find_bucket(table, flow->hash);
-       hlist_add_head_rcu(&flow->hash_node[table->node_ver], head);
-       table->count++;
+       flow->hash = ovs_flow_hash(key, flow_key_start(key), key_len);
+       memcpy(&flow->key, key, sizeof(flow->key));
+       __flow_tbl_insert(table, flow);
 }
 
 void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow)
@@ -847,6 +864,7 @@ const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
 
        /* Not upstream. */
        [OVS_KEY_ATTR_TUN_ID] = sizeof(__be64),
+       [OVS_KEY_ATTR_IPV4_TUNNEL] = sizeof(struct ovs_key_ipv4_tunnel),
 };
 
 static int ipv4_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len,
@@ -1022,9 +1040,39 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
                swkey->phy.in_port = DP_MAX_PORTS;
        }
 
-       if (attrs & (1ULL << OVS_KEY_ATTR_TUN_ID)) {
-               swkey->phy.tun_id = nla_get_be64(a[OVS_KEY_ATTR_TUN_ID]);
+       if (attrs & (1ULL << OVS_KEY_ATTR_TUN_ID) &&
+           attrs & (1ULL << OVS_KEY_ATTR_IPV4_TUNNEL)) {
+               struct ovs_key_ipv4_tunnel *tun_key;
+               __be64 tun_id;
+
+               tun_key = nla_data(a[OVS_KEY_ATTR_IPV4_TUNNEL]);
+
+               if (!tun_key->ipv4_dst)
+                       return -EINVAL;
+               if (!(tun_key->tun_flags & OVS_FLOW_TNL_F_KEY))
+                       return -EINVAL;
+
+               tun_id = nla_get_be64(a[OVS_KEY_ATTR_TUN_ID]);
+               if (tun_id != tun_key->tun_id)
+                       return -EINVAL;
+
+               memcpy(&swkey->phy.tun.tun_key, tun_key, sizeof(swkey->phy.tun.tun_key));
                attrs &= ~(1ULL << OVS_KEY_ATTR_TUN_ID);
+               attrs &= ~(1ULL << OVS_KEY_ATTR_IPV4_TUNNEL);
+       } else if (attrs & (1ULL << OVS_KEY_ATTR_TUN_ID)) {
+               swkey->phy.tun.tun_key.tun_id = nla_get_be64(a[OVS_KEY_ATTR_TUN_ID]);
+               swkey->phy.tun.tun_key.tun_flags |= OVS_FLOW_TNL_F_KEY;
+
+               attrs &= ~(1ULL << OVS_KEY_ATTR_TUN_ID);
+       } else if (attrs & (1ULL << OVS_KEY_ATTR_IPV4_TUNNEL)) {
+               struct ovs_key_ipv4_tunnel *tun_key;
+               tun_key = nla_data(a[OVS_KEY_ATTR_IPV4_TUNNEL]);
+
+               if (!tun_key->ipv4_dst)
+                       return -EINVAL;
+
+               memcpy(&swkey->phy.tun.tun_key, tun_key, sizeof(swkey->phy.tun.tun_key));
+               attrs &= ~(1ULL << OVS_KEY_ATTR_IPV4_TUNNEL);
        }
 
        /* Data attributes. */
@@ -1162,15 +1210,17 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
  * get the metadata, that is, the parts of the flow key that cannot be
  * extracted from the packet itself.
  */
-int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, __be64 *tun_id,
-                                  const struct nlattr *attr)
+
+int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, const struct nlattr *attr)
 {
+       struct ovs_key_ipv4_tunnel *tun_key = &flow->key.phy.tun.tun_key;
        const struct nlattr *nla;
        int rem;
+       __be64 tun_id = 0;
 
-       *in_port = DP_MAX_PORTS;
-       *tun_id = 0;
-       *priority = 0;
+       flow->key.phy.in_port = DP_MAX_PORTS;
+       flow->key.phy.priority = 0;
+       memset(tun_key, 0, sizeof(flow->key.phy.tun.tun_key));
 
        nla_for_each_nested(nla, attr, rem) {
                int type = nla_type(nla);
@@ -1181,23 +1231,55 @@ int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, __be64 *tun_id,
 
                        switch (type) {
                        case OVS_KEY_ATTR_PRIORITY:
-                               *priority = nla_get_u32(nla);
+                               flow->key.phy.priority = nla_get_u32(nla);
                                break;
 
                        case OVS_KEY_ATTR_TUN_ID:
-                               *tun_id = nla_get_be64(nla);
+                               tun_id = nla_get_be64(nla);
+
+                               if (tun_key->ipv4_dst) {
+                                       if (!(tun_key->tun_flags & OVS_FLOW_TNL_F_KEY))
+                                               return -EINVAL;
+                                       if (tun_key->tun_id != tun_id)
+                                               return -EINVAL;
+                                       break;
+                               }
+                               tun_key->tun_id = tun_id;
+                               tun_key->tun_flags |= OVS_FLOW_TNL_F_KEY;
+
+                               break;
+
+                       case OVS_KEY_ATTR_IPV4_TUNNEL:
+                               if (tun_key->tun_flags & OVS_FLOW_TNL_F_KEY) {
+                                       tun_id = tun_key->tun_id;
+
+                                       memcpy(tun_key, nla_data(nla), sizeof(*tun_key));
+                                       if (!(tun_key->tun_flags & OVS_FLOW_TNL_F_KEY))
+                                               return -EINVAL;
+
+                                       if (tun_key->tun_id != tun_id)
+                                               return -EINVAL;
+                               } else
+                                       memcpy(tun_key, nla_data(nla), sizeof(*tun_key));
+
+                               if (!tun_key->ipv4_dst)
+                                       return -EINVAL;
                                break;
 
                        case OVS_KEY_ATTR_IN_PORT:
                                if (nla_get_u32(nla) >= DP_MAX_PORTS)
                                        return -EINVAL;
-                               *in_port = nla_get_u32(nla);
+                               flow->key.phy.in_port = nla_get_u32(nla);
                                break;
                        }
                }
        }
        if (rem)
                return -EINVAL;
+
+       flow->hash = ovs_flow_hash(&flow->key,
+                                  flow_key_start(&flow->key), key_len);
+
        return 0;
 }
 
@@ -1210,8 +1292,16 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb)
            nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, swkey->phy.priority))
                goto nla_put_failure;
 
-       if (swkey->phy.tun_id != cpu_to_be64(0) &&
-           nla_put_be64(skb, OVS_KEY_ATTR_TUN_ID, swkey->phy.tun_id))
+       if (swkey->phy.tun.tun_key.ipv4_dst) {
+               struct ovs_key_ipv4_tunnel *tun_key;
+               nla = nla_reserve(skb, OVS_KEY_ATTR_IPV4_TUNNEL, sizeof(*tun_key));
+               if (!nla)
+                       goto nla_put_failure;
+               tun_key = nla_data(nla);
+               memcpy(tun_key, &swkey->phy.tun.tun_key, sizeof(*tun_key));
+       }
+       if ((swkey->phy.tun.tun_key.tun_flags & OVS_FLOW_TNL_F_KEY) &&
+           nla_put_be64(skb, OVS_KEY_ATTR_TUN_ID, swkey->phy.tun.tun_key.tun_id))
                goto nla_put_failure;
 
        if (swkey->phy.in_port != DP_MAX_PORTS &&
index 02c563a..f4ef285 100644 (file)
@@ -42,7 +42,9 @@ struct sw_flow_actions {
 
 struct sw_flow_key {
        struct {
-               __be64  tun_id;         /* Encapsulating tunnel ID. */
+               union {
+                       struct ovs_key_ipv4_tunnel tun_key;  /* Encapsulating tunnel key. */
+               } tun;
                u32     priority;       /* Packet QoS priority. */
                u16     in_port;        /* Input switch port (or DP_MAX_PORTS). */
        } phy;
@@ -150,6 +152,7 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies);
  *                         ------  ---  ------  -----
  *  OVS_KEY_ATTR_PRIORITY      4    --     4      8
  *  OVS_KEY_ATTR_TUN_ID        8    --     4     12
+ *  OVS_KEY_ATTR_IPV4_TUNNEL  24    --     4     28
  *  OVS_KEY_ATTR_IN_PORT       4    --     4      8
  *  OVS_KEY_ATTR_ETHERNET     12    --     4     16
  *  OVS_KEY_ATTR_ETHERTYPE     2     2     4      8  (outer VLAN ethertype)
@@ -160,15 +163,15 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies);
  *  OVS_KEY_ATTR_ICMPV6        2     2     4      8
  *  OVS_KEY_ATTR_ND           28    --     4     32
  *  -------------------------------------------------
- *  total                                       156
+ *  total                                       184
  */
-#define FLOW_BUFSIZE 156
+#define FLOW_BUFSIZE 184
 
 int ovs_flow_to_nlattrs(const struct sw_flow_key *, struct sk_buff *);
 int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
                      const struct nlattr *);
-int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, __be64 *tun_id,
-                                  const struct nlattr *);
+int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len,
+                                  const struct nlattr *attr);
 
 #define MAX_ACTIONS_BUFSIZE    (16 * 1024)
 #define TBL_MIN_BUCKETS                1024
@@ -199,9 +202,9 @@ void ovs_flow_tbl_deferred_destroy(struct flow_table *table);
 struct flow_table *ovs_flow_tbl_alloc(int new_size);
 struct flow_table *ovs_flow_tbl_expand(struct flow_table *table);
 struct flow_table *ovs_flow_tbl_rehash(struct flow_table *table);
-void ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow);
+void ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow,
+                        struct sw_flow_key *key, int key_len);
 void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow);
-u32 ovs_flow_hash(const struct sw_flow_key *key, int key_len);
 
 struct sw_flow *ovs_flow_tbl_next(struct flow_table *table, u32 *bucket, u32 *idx);
 extern const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1];
index d651c11..bfb09ce 100644 (file)
@@ -100,6 +100,7 @@ static unsigned int key_remote_ports __read_mostly;
 static unsigned int key_multicast_ports __read_mostly;
 static unsigned int local_remote_ports __read_mostly;
 static unsigned int remote_ports __read_mostly;
+static unsigned int null_ports __read_mostly;
 static unsigned int multicast_ports __read_mostly;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
@@ -218,8 +219,10 @@ static unsigned int *find_port_pool(const struct tnl_mutable_config *mutable)
                        return &key_local_remote_ports;
                else if (is_multicast)
                        return &key_multicast_ports;
-               else
+               else if (mutable->key.daddr)
                        return &key_remote_ports;
+               else
+                       return &null_ports;
        }
 }
 
@@ -364,12 +367,20 @@ struct vport *ovs_tnl_find_port(struct net *net, __be32 saddr, __be32 daddr,
                }
        }
 
+       if (null_ports) {
+               lookup.daddr = 0;
+               lookup.saddr = 0;
+               lookup.tunnel_type = tunnel_type;
+               vport = port_table_lookup(&lookup, mutable);
+               if (vport)
+                       return vport;
+       }
        return NULL;
 }
 
-static void ecn_decapsulate(struct sk_buff *skb, u8 tos)
+static void ecn_decapsulate(struct sk_buff *skb)
 {
-       if (unlikely(INET_ECN_is_ce(tos))) {
+       if (unlikely(INET_ECN_is_ce(OVS_CB(skb)->tun_key->ipv4_tos))) {
                __be16 protocol = skb->protocol;
 
                skb_set_network_header(skb, ETH_HLEN);
@@ -416,7 +427,7 @@ static void ecn_decapsulate(struct sk_buff *skb, u8 tos)
  * - skb->csum does not include the inner Ethernet header.
  * - The layer pointers are undefined.
  */
-void ovs_tnl_rcv(struct vport *vport, struct sk_buff *skb, u8 tos)
+void ovs_tnl_rcv(struct vport *vport, struct sk_buff *skb)
 {
        struct ethhdr *eh;
 
@@ -433,7 +444,7 @@ void ovs_tnl_rcv(struct vport *vport, struct sk_buff *skb, u8 tos)
        skb_clear_rxhash(skb);
        secpath_reset(skb);
 
-       ecn_decapsulate(skb, tos);
+       ecn_decapsulate(skb);
        vlan_set_tci(skb, 0);
 
        if (unlikely(compute_ip_summed(skb, false))) {
@@ -613,7 +624,7 @@ static void ipv6_build_icmp(struct sk_buff *skb, struct sk_buff *nskb,
 
 bool ovs_tnl_frag_needed(struct vport *vport,
                         const struct tnl_mutable_config *mutable,
-                        struct sk_buff *skb, unsigned int mtu, __be64 flow_key)
+                        struct sk_buff *skb, unsigned int mtu)
 {
        unsigned int eth_hdr_len = ETH_HLEN;
        unsigned int total_length = 0, header_length = 0, payload_length;
@@ -697,17 +708,6 @@ bool ovs_tnl_frag_needed(struct vport *vport,
                ipv6_build_icmp(skb, nskb, mtu, payload_length);
 #endif
 
-       /*
-        * Assume that flow based keys are symmetric with respect to input
-        * and output and use the key that we were going to put on the
-        * outgoing packet for the fake received packet.  If the keys are
-        * not symmetric then PMTUD needs to be disabled since we won't have
-        * any way of synthesizing packets.
-        */
-       if ((mutable->flags & (TNL_F_IN_KEY_MATCH | TNL_F_OUT_KEY_ACTION)) ==
-           (TNL_F_IN_KEY_MATCH | TNL_F_OUT_KEY_ACTION))
-               OVS_CB(nskb)->tun_id = flow_key;
-
        if (unlikely(compute_ip_summed(nskb, false))) {
                kfree_skb(nskb);
                return false;
@@ -721,14 +721,26 @@ bool ovs_tnl_frag_needed(struct vport *vport,
 static bool check_mtu(struct sk_buff *skb,
                      struct vport *vport,
                      const struct tnl_mutable_config *mutable,
-                     const struct rtable *rt, __be16 *frag_offp)
+                     const struct rtable *rt, __be16 *frag_offp,
+                     int tunnel_hlen)
 {
-       bool df_inherit = mutable->flags & TNL_F_DF_INHERIT;
-       bool pmtud = mutable->flags & TNL_F_PMTUD;
-       __be16 frag_off = mutable->flags & TNL_F_DF_DEFAULT ? htons(IP_DF) : 0;
+       bool df_inherit;
+       bool pmtud;
+       __be16 frag_off;
        int mtu = 0;
        unsigned int packet_length = skb->len - ETH_HLEN;
 
+       if (OVS_CB(skb)->tun_key->ipv4_dst) {
+               df_inherit = false;
+               pmtud = false;
+               frag_off = OVS_CB(skb)->tun_key->tun_flags & OVS_FLOW_TNL_F_DONT_FRAGMENT ?
+                                 htons(IP_DF) : 0;
+       } else {
+               df_inherit = mutable->flags & TNL_F_DF_INHERIT;
+               pmtud = mutable->flags & TNL_F_PMTUD;
+               frag_off = mutable->flags & TNL_F_DF_DEFAULT ? htons(IP_DF) : 0;
+       }
+
        /* Allow for one level of tagging in the packet length. */
        if (!vlan_tx_tag_present(skb) &&
            eth_hdr(skb)->h_proto == htons(ETH_P_8021Q))
@@ -746,7 +758,7 @@ static bool check_mtu(struct sk_buff *skb,
 
                mtu = dst_mtu(&rt_dst(rt))
                        - ETH_HLEN
-                       - mutable->tunnel_hlen
+                       - tunnel_hlen
                        - vlan_header;
        }
 
@@ -760,8 +772,7 @@ static bool check_mtu(struct sk_buff *skb,
                        mtu = max(mtu, IP_MIN_MTU);
 
                        if (packet_length > mtu &&
-                           ovs_tnl_frag_needed(vport, mutable, skb, mtu,
-                                               OVS_CB(skb)->tun_id))
+                           ovs_tnl_frag_needed(vport, mutable, skb, mtu))
                                return false;
                }
        }
@@ -777,8 +788,7 @@ static bool check_mtu(struct sk_buff *skb,
                        mtu = max(mtu, IPV6_MIN_MTU);
 
                        if (packet_length > mtu &&
-                           ovs_tnl_frag_needed(vport, mutable, skb, mtu,
-                                               OVS_CB(skb)->tun_id))
+                           ovs_tnl_frag_needed(vport, mutable, skb, mtu))
                                return false;
                }
        }
@@ -790,6 +800,7 @@ static bool check_mtu(struct sk_buff *skb,
 
 static void create_tunnel_header(const struct vport *vport,
                                 const struct tnl_mutable_config *mutable,
+                                const struct ovs_key_ipv4_tunnel *tun_key,
                                 const struct rtable *rt, void *header)
 {
        struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
@@ -806,7 +817,7 @@ static void create_tunnel_header(const struct vport *vport,
        if (!iph->ttl)
                iph->ttl = ip4_dst_hoplimit(&rt_dst(rt));
 
-       tnl_vport->tnl_ops->build_header(vport, mutable, iph + 1);
+       tnl_vport->tnl_ops->build_header(vport, mutable, tun_key, iph + 1);
 }
 
 static void *get_cached_header(const struct tnl_cache *cache)
@@ -907,14 +918,22 @@ static struct tnl_cache *build_cache(struct vport *vport,
                                     struct rtable *rt)
 {
        struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
+       static const struct ovs_key_ipv4_tunnel tun_key;
        struct tnl_cache *cache;
        void *cache_data;
        int cache_len;
        struct hh_cache *hh;
+       int tunnel_hlen;
 
        if (!(mutable->flags & TNL_F_HDR_CACHE))
                return NULL;
 
+       tunnel_hlen = tnl_vport->tnl_ops->hdr_len(mutable, &tun_key);
+       if (tunnel_hlen < 0)
+               return NULL;
+
+       tunnel_hlen += sizeof(struct iphdr);
+
        /*
         * If there is no entry in the ARP cache or if this device does not
         * support hard header caching just fall back to the IP stack.
@@ -937,7 +956,7 @@ static struct tnl_cache *build_cache(struct vport *vport,
        else
                cache = NULL;
 
-       cache_len = LL_RESERVED_SPACE(rt_dst(rt).dev) + mutable->tunnel_hlen;
+       cache_len = LL_RESERVED_SPACE(rt_dst(rt).dev) + tunnel_hlen;
 
        cache = kzalloc(ALIGN(sizeof(struct tnl_cache), CACHE_DATA_ALIGN) +
                        cache_len, GFP_ATOMIC);
@@ -946,9 +965,9 @@ static struct tnl_cache *build_cache(struct vport *vport,
 
        create_eth_hdr(cache, hh);
        cache_data = get_cached_header(cache) + cache->hh_len;
-       cache->len = cache->hh_len + mutable->tunnel_hlen;
+       cache->len = cache->hh_len + tunnel_hlen;
 
-       create_tunnel_header(vport, mutable, rt, cache_data);
+       create_tunnel_header(vport, mutable, &tun_key, rt, cache_data);
 
        cache->mutable_seq = mutable->seq;
        cache->rt = rt;
@@ -1000,15 +1019,16 @@ unlock:
 }
 
 static struct rtable *__find_route(const struct tnl_mutable_config *mutable,
-                                  u8 ipproto, u8 tos)
+                                  __be32 saddr, __be32 daddr, u8 ipproto,
+                                  u8 tos)
 {
        /* Tunnel configuration keeps DSCP part of TOS bits, But Linux
         * router expect RT_TOS bits only. */
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39)
        struct flowi fl = { .nl_u = { .ip4_u = {
-                                       .daddr = mutable->key.daddr,
-                                       .saddr = mutable->key.saddr,
+                                       .daddr = daddr,
+                                       .saddr = saddr,
                                        .tos   = RT_TOS(tos) } },
                                        .proto = ipproto };
        struct rtable *rt;
@@ -1018,8 +1038,8 @@ static struct rtable *__find_route(const struct tnl_mutable_config *mutable,
 
        return rt;
 #else
-       struct flowi4 fl = { .daddr = mutable->key.daddr,
-                            .saddr = mutable->key.saddr,
+       struct flowi4 fl = { .daddr = daddr,
+                            .saddr = saddr,
                             .flowi4_tos = RT_TOS(tos),
                             .flowi4_proto = ipproto };
 
@@ -1029,7 +1049,8 @@ static struct rtable *__find_route(const struct tnl_mutable_config *mutable,
 
 static struct rtable *find_route(struct vport *vport,
                                 const struct tnl_mutable_config *mutable,
-                                u8 tos, struct tnl_cache **cache)
+                                __be32 saddr, __be32 daddr, u8 tos,
+                                struct tnl_cache **cache)
 {
        struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
        struct tnl_cache *cur_cache = rcu_dereference(tnl_vport->cache);
@@ -1037,17 +1058,17 @@ static struct rtable *find_route(struct vport *vport,
        *cache = NULL;
        tos = RT_TOS(tos);
 
-       if (likely(tos == RT_TOS(mutable->tos) &&
-           check_cache_valid(cur_cache, mutable))) {
+       if (tos == RT_TOS(mutable->tos) &&
+           check_cache_valid(cur_cache, mutable)) {
                *cache = cur_cache;
                return cur_cache->rt;
        } else {
                struct rtable *rt;
 
-               rt = __find_route(mutable, tnl_vport->tnl_ops->ipproto, tos);
+               rt = __find_route(mutable, saddr, daddr,
+                                 tnl_vport->tnl_ops->ipproto, tos);
                if (IS_ERR(rt))
                        return NULL;
-
                if (likely(tos == RT_TOS(mutable->tos)))
                        *cache = build_cache(vport, mutable, rt);
 
@@ -1076,13 +1097,14 @@ static bool need_linearize(const struct sk_buff *skb)
 
 static struct sk_buff *handle_offloads(struct sk_buff *skb,
                                       const struct tnl_mutable_config *mutable,
-                                      const struct rtable *rt)
+                                      const struct rtable *rt,
+                                      int tunnel_hlen)
 {
        int min_headroom;
        int err;
 
        min_headroom = LL_RESERVED_SPACE(rt_dst(rt).dev) + rt_dst(rt).header_len
-                       + mutable->tunnel_hlen
+                       + tunnel_hlen
                        + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0);
 
        if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) {
@@ -1137,14 +1159,14 @@ error:
 }
 
 static int send_frags(struct sk_buff *skb,
-                     const struct tnl_mutable_config *mutable)
+                     int tunnel_hlen)
 {
        int sent_len;
 
        sent_len = 0;
        while (skb) {
                struct sk_buff *next = skb->next;
-               int frag_len = skb->len - mutable->tunnel_hlen;
+               int frag_len = skb->len - tunnel_hlen;
                int err;
 
                skb->next = NULL;
@@ -1173,15 +1195,17 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb)
 {
        struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
        const struct tnl_mutable_config *mutable = rcu_dereference(tnl_vport->mutable);
-
        enum vport_err_type err = VPORT_E_TX_ERROR;
        struct rtable *rt;
        struct dst_entry *unattached_dst = NULL;
        struct tnl_cache *cache;
+       struct ovs_key_ipv4_tunnel tun_key;
        int sent_len = 0;
+       int tunnel_hlen;
        __be16 frag_off = 0;
+       __be32 daddr;
+       __be32 saddr;
        u8 ttl;
-       u8 inner_tos;
        u8 tos;
 
        /* Validate the protocol headers before we try to use them. */
@@ -1207,30 +1231,75 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb)
        }
 #endif
 
-       /* ToS */
-       if (skb->protocol == htons(ETH_P_IP))
-               inner_tos = ip_hdr(skb)->tos;
+       /* If OVS_CB(skb)->tun_key is NULL, point it at the local tun_key here,
+        * and zero it out.
+        */
+       if (!OVS_CB(skb)->tun_key) {
+               memset(&tun_key, 0, sizeof(tun_key));
+               OVS_CB(skb)->tun_key = &tun_key;
+       }
+
+       tunnel_hlen = tnl_vport->tnl_ops->hdr_len(mutable, OVS_CB(skb)->tun_key);
+       if (unlikely(tunnel_hlen < 0)) {
+               err = VPORT_E_TX_DROPPED;
+               goto error_free;
+       }
+       tunnel_hlen += sizeof(struct iphdr);
+
+       if (OVS_CB(skb)->tun_key->ipv4_dst) {
+               daddr = OVS_CB(skb)->tun_key->ipv4_dst;
+               saddr = OVS_CB(skb)->tun_key->ipv4_src;
+               tos = OVS_CB(skb)->tun_key->ipv4_tos;
+               ttl = OVS_CB(skb)->tun_key->ipv4_ttl;
+       } else {
+               u8 inner_tos;
+               daddr = mutable->key.daddr;
+               saddr = mutable->key.saddr;
+
+               if (unlikely(!daddr)) {
+                       /* Trying to sent packet from Null-port without
+                        * tunnel info? Drop this packet. */
+                       err = VPORT_E_TX_DROPPED;
+                       goto error_free;
+               }
+
+               /* ToS */
+               if (skb->protocol == htons(ETH_P_IP))
+                       inner_tos = ip_hdr(skb)->tos;
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-       else if (skb->protocol == htons(ETH_P_IPV6))
-               inner_tos = ipv6_get_dsfield(ipv6_hdr(skb));
+               else if (skb->protocol == htons(ETH_P_IPV6))
+                       inner_tos = ipv6_get_dsfield(ipv6_hdr(skb));
 #endif
-       else
-               inner_tos = 0;
+               else
+                       inner_tos = 0;
 
-       if (mutable->flags & TNL_F_TOS_INHERIT)
-               tos = inner_tos;
-       else
-               tos = mutable->tos;
+               if (mutable->flags & TNL_F_TOS_INHERIT)
+                       tos = inner_tos;
+               else
+                       tos = mutable->tos;
+
+               tos = INET_ECN_encapsulate(tos, inner_tos);
+
+               /* TTL */
+               ttl = mutable->ttl;
+               if (mutable->flags & TNL_F_TTL_INHERIT) {
+                       if (skb->protocol == htons(ETH_P_IP))
+                               ttl = ip_hdr(skb)->ttl;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+                       else if (skb->protocol == htons(ETH_P_IPV6))
+                               ttl = ipv6_hdr(skb)->hop_limit;
+#endif
+               }
+
+       }
 
        /* Route lookup */
-       rt = find_route(vport, mutable, tos, &cache);
+       rt = find_route(vport, mutable, saddr, daddr, tos, &cache);
        if (unlikely(!rt))
                goto error_free;
        if (unlikely(!cache))
                unattached_dst = &rt_dst(rt);
 
-       tos = INET_ECN_encapsulate(tos, inner_tos);
-
        /* Reset SKB */
        nf_reset(skb);
        secpath_reset(skb);
@@ -1238,12 +1307,12 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb)
        skb_clear_rxhash(skb);
 
        /* Offloading */
-       skb = handle_offloads(skb, mutable, rt);
+       skb = handle_offloads(skb, mutable, rt, tunnel_hlen);
        if (IS_ERR(skb))
                goto error;
 
        /* MTU */
-       if (unlikely(!check_mtu(skb, vport, mutable, rt, &frag_off))) {
+       if (unlikely(!check_mtu(skb, vport, mutable, rt, &frag_off, tunnel_hlen))) {
                err = VPORT_E_TX_DROPPED;
                goto error_free;
        }
@@ -1252,25 +1321,19 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb)
         * If we are over the MTU, allow the IP stack to handle fragmentation.
         * Fragmentation is a slow path anyways.
         */
-       if (unlikely(skb->len + mutable->tunnel_hlen > dst_mtu(&rt_dst(rt)) &&
+       if (unlikely(skb->len + tunnel_hlen > dst_mtu(&rt_dst(rt)) &&
                     cache)) {
                unattached_dst = &rt_dst(rt);
                dst_hold(unattached_dst);
                cache = NULL;
        }
 
-       /* TTL */
-       ttl = mutable->ttl;
-       if (!ttl)
-               ttl = ip4_dst_hoplimit(&rt_dst(rt));
-
-       if (mutable->flags & TNL_F_TTL_INHERIT) {
-               if (skb->protocol == htons(ETH_P_IP))
-                       ttl = ip_hdr(skb)->ttl;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-               else if (skb->protocol == htons(ETH_P_IPV6))
-                       ttl = ipv6_hdr(skb)->hop_limit;
-#endif
+       /* TTL Fixup. */
+       if (!OVS_CB(skb)->tun_key->ipv4_dst) {
+               if (!(mutable->flags & TNL_F_TTL_INHERIT)) {
+                       if (!ttl)
+                               ttl = ip4_dst_hoplimit(&rt_dst(rt));
+               }
        }
 
        while (skb) {
@@ -1288,8 +1351,8 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb)
                        skb_set_network_header(skb, cache->hh_len);
 
                } else {
-                       skb_push(skb, mutable->tunnel_hlen);
-                       create_tunnel_header(vport, mutable, rt, skb->data);
+                       skb_push(skb, tunnel_hlen);
+                       create_tunnel_header(vport, mutable, OVS_CB(skb)->tun_key, rt, skb->data);
                        skb_reset_network_header(skb);
 
                        if (next_skb)
@@ -1308,7 +1371,7 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb)
                ip_select_ident(iph, &rt_dst(rt), NULL);
 
                skb = tnl_vport->tnl_ops->update_header(vport, mutable,
-                                                       &rt_dst(rt), skb);
+                                                       &rt_dst(rt), skb, tunnel_hlen);
                if (unlikely(!skb))
                        goto next;
 
@@ -1341,7 +1404,7 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb)
                                        sent_len += orig_len;
                        }
                } else
-                       sent_len += send_frags(skb, mutable);
+                       sent_len += send_frags(skb, tunnel_hlen);
 
 next:
                skb = next_skb;
@@ -1383,8 +1446,10 @@ static int tnl_set_config(struct net *net, struct nlattr *options,
        struct nlattr *a[OVS_TUNNEL_ATTR_MAX + 1];
        int err;
 
+       port_key_set_net(&mutable->key, net);
+       mutable->key.tunnel_type = tnl_ops->tunnel_type;
        if (!options)
-               return -EINVAL;
+               goto out;
 
        err = nla_parse_nested(a, OVS_TUNNEL_ATTR_MAX, options, tnl_policy);
        if (err)
@@ -1394,9 +1459,8 @@ static int tnl_set_config(struct net *net, struct nlattr *options,
                return -EINVAL;
 
        mutable->flags = nla_get_u32(a[OVS_TUNNEL_ATTR_FLAGS]) & TNL_F_PUBLIC;
-
-       port_key_set_net(&mutable->key, net);
        mutable->key.daddr = nla_get_be32(a[OVS_TUNNEL_ATTR_DST_IPV4]);
+
        if (a[OVS_TUNNEL_ATTR_SRC_IPV4]) {
                if (ipv4_is_multicast(mutable->key.daddr))
                        return -EINVAL;
@@ -1413,7 +1477,6 @@ static int tnl_set_config(struct net *net, struct nlattr *options,
        if (a[OVS_TUNNEL_ATTR_TTL])
                mutable->ttl = nla_get_u8(a[OVS_TUNNEL_ATTR_TTL]);
 
-       mutable->key.tunnel_type = tnl_ops->tunnel_type;
        if (!a[OVS_TUNNEL_ATTR_IN_KEY]) {
                mutable->key.tunnel_type |= TNL_T_KEY_MATCH;
                mutable->flags |= TNL_F_IN_KEY_MATCH;
@@ -1427,22 +1490,13 @@ static int tnl_set_config(struct net *net, struct nlattr *options,
        else
                mutable->out_key = nla_get_be64(a[OVS_TUNNEL_ATTR_OUT_KEY]);
 
-       mutable->tunnel_hlen = tnl_ops->hdr_len(mutable);
-       if (mutable->tunnel_hlen < 0)
-               return mutable->tunnel_hlen;
-
-       mutable->tunnel_hlen += sizeof(struct iphdr);
-
-       old_vport = port_table_lookup(&mutable->key, &old_mutable);
-       if (old_vport && old_vport != cur_vport)
-               return -EEXIST;
-
        mutable->mlink = 0;
        if (ipv4_is_multicast(mutable->key.daddr)) {
                struct net_device *dev;
                struct rtable *rt;
 
-               rt = __find_route(mutable, tnl_ops->ipproto, mutable->tos);
+               rt = __find_route(mutable, mutable->key.saddr, mutable->key.daddr,
+                                 tnl_ops->ipproto, mutable->tos);
                if (IS_ERR(rt))
                        return -EADDRNOTAVAIL;
                dev = rt_dst(rt).dev;
@@ -1453,6 +1507,11 @@ static int tnl_set_config(struct net *net, struct nlattr *options,
                ip_mc_inc_group(__in_dev_get_rtnl(dev), mutable->key.daddr);
        }
 
+out:
+       old_vport = port_table_lookup(&mutable->key, &old_mutable);
+       if (old_vport && old_vport != cur_vport)
+               return -EEXIST;
+
        return 0;
 }
 
@@ -1521,6 +1580,10 @@ int ovs_tnl_set_options(struct vport *vport, struct nlattr *options)
        struct tnl_mutable_config *mutable;
        int err;
 
+       old_mutable = rtnl_dereference(tnl_vport->mutable);
+       if (!old_mutable->key.daddr)
+               return -EINVAL;
+
        mutable = kzalloc(sizeof(struct tnl_mutable_config), GFP_KERNEL);
        if (!mutable) {
                err = -ENOMEM;
@@ -1528,7 +1591,6 @@ int ovs_tnl_set_options(struct vport *vport, struct nlattr *options)
        }
 
        /* Copy fields whose values should be retained. */
-       old_mutable = rtnl_dereference(tnl_vport->mutable);
        mutable->seq = old_mutable->seq + 1;
        memcpy(mutable->eth_addr, old_mutable->eth_addr, ETH_ALEN);
 
index 1924017..951a6f1 100644 (file)
@@ -40,7 +40,8 @@
  * identifiers.
  */
 #define TNL_T_PROTO_GRE                0
-#define TNL_T_PROTO_CAPWAP     1
+#define TNL_T_PROTO_GRE64      1
+#define TNL_T_PROTO_CAPWAP     2
 
 /* These flags are only needed when calling tnl_find_port(). */
 #define TNL_T_KEY_EXACT                (1 << 10)
@@ -108,8 +109,6 @@ struct tnl_mutable_config {
 
        unsigned seq;
 
-       unsigned tunnel_hlen;
-
        unsigned char eth_addr[ETH_ALEN];
 
        /* Configured via OVS_TUNNEL_ATTR_* attributes. */
@@ -131,7 +130,8 @@ struct tnl_ops {
         * build_header() (i.e. excludes the IP header).  Returns a negative
         * error code if the configuration is invalid.
         */
-       int (*hdr_len)(const struct tnl_mutable_config *);
+       int (*hdr_len)(const struct tnl_mutable_config *,
+                      const struct ovs_key_ipv4_tunnel *);
 
        /*
         * Builds the static portion of the tunnel header, which is stored in
@@ -142,7 +142,8 @@ struct tnl_ops {
         * called for every packet, so try not to make it too slow.
         */
        void (*build_header)(const struct vport *,
-                            const struct tnl_mutable_config *, void *header);
+                            const struct tnl_mutable_config *,
+                            const struct ovs_key_ipv4_tunnel *, void *header);
 
        /*
         * Updates the cached header of a packet to match the actual packet
@@ -154,7 +155,8 @@ struct tnl_ops {
         */
        struct sk_buff *(*update_header)(const struct vport *,
                                         const struct tnl_mutable_config *,
-                                        struct dst_entry *, struct sk_buff *);
+                                        struct dst_entry *, struct sk_buff *,
+                                        int tunnel_hlen);
 };
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
@@ -269,14 +271,14 @@ int ovs_tnl_set_addr(struct vport *vport, const unsigned char *addr);
 const char *ovs_tnl_get_name(const struct vport *vport);
 const unsigned char *ovs_tnl_get_addr(const struct vport *vport);
 int ovs_tnl_send(struct vport *vport, struct sk_buff *skb);
-void ovs_tnl_rcv(struct vport *vport, struct sk_buff *skb, u8 tos);
+void ovs_tnl_rcv(struct vport *vport, struct sk_buff *skb);
 
 struct vport *ovs_tnl_find_port(struct net *net, __be32 saddr, __be32 daddr,
                                __be64 key, int tunnel_type,
                                const struct tnl_mutable_config **mutable);
 bool ovs_tnl_frag_needed(struct vport *vport,
                         const struct tnl_mutable_config *mutable,
-                        struct sk_buff *skb, unsigned int mtu, __be64 flow_key);
+                        struct sk_buff *skb, unsigned int mtu);
 void ovs_tnl_free_linked_skbs(struct sk_buff *skb);
 
 int ovs_tnl_init(void);
@@ -286,4 +288,15 @@ static inline struct tnl_vport *tnl_vport_priv(const struct vport *vport)
        return vport_priv(vport);
 }
 
+static inline void tnl_tun_key_init(struct ovs_key_ipv4_tunnel *tun_key,
+                                   const struct iphdr *iph, __be64 tun_id, u32 tun_flags)
+{
+       tun_key->tun_id = tun_id;
+       tun_key->ipv4_src = iph->saddr;
+       tun_key->ipv4_dst = iph->daddr;
+       tun_key->ipv4_tos = iph->tos;
+       tun_key->ipv4_ttl = iph->ttl;
+       tun_key->tun_flags = tun_flags;
+}
+
 #endif /* tunnel.h */
index 05a099d..39aec42 100644 (file)
@@ -155,16 +155,43 @@ static struct inet_frags frag_state = {
        .secret_interval = CAPWAP_FRAG_SECRET_INTERVAL,
 };
 
-static int capwap_hdr_len(const struct tnl_mutable_config *mutable)
+static void get_capwap_param(const struct tnl_mutable_config *mutable,
+                       const struct ovs_key_ipv4_tunnel *tun_key,
+                       u32 *flags,  __be64 *out_key)
+{
+       if (tun_key->ipv4_dst) {
+               *flags = 0;
+
+               if (tun_key->tun_flags & OVS_FLOW_TNL_F_KEY)
+                       *flags = TNL_F_OUT_KEY_ACTION;
+               if (tun_key->tun_flags & OVS_FLOW_TNL_F_CSUM)
+                       *flags |= TNL_F_CSUM;
+               *out_key = tun_key->tun_id;
+       } else {
+               *flags = mutable->flags;
+               if (mutable->flags & TNL_F_OUT_KEY_ACTION)
+                       *out_key = tun_key->tun_id;
+               else
+                       *out_key = mutable->out_key;
+
+       }
+}
+
+static int capwap_hdr_len(const struct tnl_mutable_config *mutable,
+                         const struct ovs_key_ipv4_tunnel *tun_key)
 {
        int size = CAPWAP_MIN_HLEN;
+       u32 flags;
+       __be64 out_key;
+
+       get_capwap_param(mutable, tun_key, &flags, &out_key);
 
        /* CAPWAP has no checksums. */
-       if (mutable->flags & TNL_F_CSUM)
+       if (flags & TNL_F_CSUM)
                return -EINVAL;
 
        /* if keys are specified, then add WSI field */
-       if (mutable->out_key || (mutable->flags & TNL_F_OUT_KEY_ACTION)) {
+       if (out_key || (flags & TNL_F_OUT_KEY_ACTION)) {
                size += sizeof(struct capwaphdr_wsi) +
                        sizeof(struct capwaphdr_wsi_key);
        }
@@ -174,10 +201,15 @@ static int capwap_hdr_len(const struct tnl_mutable_config *mutable)
 
 static void capwap_build_header(const struct vport *vport,
                                const struct tnl_mutable_config *mutable,
+                               const struct ovs_key_ipv4_tunnel *tun_key,
                                void *header)
 {
        struct udphdr *udph = header;
        struct capwaphdr *cwh = (struct capwaphdr *)(udph + 1);
+       u32 flags;
+       __be64 out_key;
+
+       get_capwap_param(mutable, tun_key, &flags, &out_key);
 
        udph->source = htons(CAPWAP_SRC_PORT);
        udph->dest = htons(CAPWAP_DST_PORT);
@@ -186,7 +218,7 @@ static void capwap_build_header(const struct vport *vport,
        cwh->frag_id = 0;
        cwh->frag_off = 0;
 
-       if (mutable->out_key || (mutable->flags & TNL_F_OUT_KEY_ACTION)) {
+       if (out_key || (flags & TNL_F_OUT_KEY_ACTION)) {
                struct capwaphdr_wsi *wsi = (struct capwaphdr_wsi *)(cwh + 1);
 
                cwh->begin = CAPWAP_KEYED;
@@ -197,9 +229,9 @@ static void capwap_build_header(const struct vport *vport,
                wsi->flags = CAPWAP_WSI_F_KEY64;
                wsi->reserved_padding = 0;
 
-               if (mutable->out_key) {
+               if (out_key) {
                        struct capwaphdr_wsi_key *opt = (struct capwaphdr_wsi_key *)(wsi + 1);
-                       opt->key = mutable->out_key;
+                       opt->key = out_key;
                }
        } else {
                /* make packet readable by old capwap code */
@@ -210,30 +242,36 @@ static void capwap_build_header(const struct vport *vport,
 static struct sk_buff *capwap_update_header(const struct vport *vport,
                                            const struct tnl_mutable_config *mutable,
                                            struct dst_entry *dst,
-                                           struct sk_buff *skb)
+                                           struct sk_buff *skb,
+                                           int tunnel_hlen)
 {
+       const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key;
        struct udphdr *udph = udp_hdr(skb);
+       u32 flags;
+       __be64 out_key;
+
+       get_capwap_param(mutable, tun_key, &flags, &out_key);
 
-       if (mutable->flags & TNL_F_OUT_KEY_ACTION) {
+       if (flags & TNL_F_OUT_KEY_ACTION) {
                /* first field in WSI is key */
                struct capwaphdr *cwh = (struct capwaphdr *)(udph + 1);
                struct capwaphdr_wsi *wsi = (struct capwaphdr_wsi *)(cwh + 1);
                struct capwaphdr_wsi_key *opt = (struct capwaphdr_wsi_key *)(wsi + 1);
 
-               opt->key = OVS_CB(skb)->tun_id;
+               opt->key = out_key;
        }
 
        udph->len = htons(skb->len - skb_transport_offset(skb));
 
        if (unlikely(skb->len - skb_network_offset(skb) > dst_mtu(dst))) {
-               unsigned int hlen = skb_transport_offset(skb) + capwap_hdr_len(mutable);
+               unsigned int hlen = skb_transport_offset(skb) + capwap_hdr_len(mutable, tun_key);
                skb = fragment(skb, vport, dst, hlen);
        }
 
        return skb;
 }
 
-static int process_capwap_wsi(struct sk_buff *skb, __be64 *key)
+static int process_capwap_wsi(struct sk_buff *skb, __be64 *key, bool *key_present)
 {
        struct capwaphdr *cwh = capwap_hdr(skb);
        struct capwaphdr_wsi *wsi;
@@ -270,12 +308,15 @@ static int process_capwap_wsi(struct sk_buff *skb, __be64 *key)
 
                opt = (struct capwaphdr_wsi_key *)(wsi + 1);
                *key = opt->key;
+               *key_present = true;
+       } else {
+               *key_present = false;
        }
 
        return 0;
 }
 
-static struct sk_buff *process_capwap_proto(struct sk_buff *skb, __be64 *key)
+static struct sk_buff *process_capwap_proto(struct sk_buff *skb, __be64 *key, bool *key_present)
 {
        struct capwaphdr *cwh = capwap_hdr(skb);
        int hdr_len = sizeof(struct udphdr);
@@ -301,7 +342,7 @@ static struct sk_buff *process_capwap_proto(struct sk_buff *skb, __be64 *key)
                cwh = capwap_hdr(skb);
        }
 
-       if ((cwh->begin & CAPWAP_F_WSI) && process_capwap_wsi(skb, key))
+       if ((cwh->begin & CAPWAP_F_WSI) && process_capwap_wsi(skb, key, key_present))
                goto error;
 
        return skb;
@@ -316,12 +357,14 @@ static int capwap_rcv(struct sock *sk, struct sk_buff *skb)
        struct vport *vport;
        const struct tnl_mutable_config *mutable;
        struct iphdr *iph;
+       struct ovs_key_ipv4_tunnel tun_key;
        __be64 key = 0;
+       bool key_present = false;
 
        if (unlikely(!pskb_may_pull(skb, CAPWAP_MIN_HLEN + ETH_HLEN)))
                goto error;
 
-       skb = process_capwap_proto(skb, &key);
+       skb = process_capwap_proto(skb, &key, &key_present);
        if (unlikely(!skb))
                goto out;
 
@@ -333,12 +376,14 @@ static int capwap_rcv(struct sock *sk, struct sk_buff *skb)
                goto error;
        }
 
-       if (mutable->flags & TNL_F_IN_KEY_MATCH)
-               OVS_CB(skb)->tun_id = key;
-       else
-               OVS_CB(skb)->tun_id = 0;
+       if (key_present && mutable->key.daddr &&
+                        !(mutable->flags & TNL_F_IN_KEY_MATCH))
+               key_present = false;
+
+       tnl_tun_key_init(&tun_key, iph, key, key_present ? OVS_FLOW_TNL_F_KEY : 0);
+       OVS_CB(skb)->tun_key = &tun_key;
 
-       ovs_tnl_rcv(vport, skb, iph->tos);
+       ovs_tnl_rcv(vport, skb);
        goto out;
 
 error:
index ab89c5b..d02d4ec 100644 (file)
@@ -45,21 +45,57 @@ struct gre_base_hdr {
        __be16 protocol;
 };
 
-static int gre_hdr_len(const struct tnl_mutable_config *mutable)
+static void get_gre_param(const struct tnl_mutable_config *mutable,
+                       const struct ovs_key_ipv4_tunnel *tun_key,
+                       u32 *flags, u32 *tunnel_type, __be64 *out_key)
+{
+       if (tun_key->ipv4_dst) {
+               *flags = 0;
+
+               if (tun_key->tun_flags & OVS_FLOW_TNL_F_KEY)
+                       *flags = TNL_F_OUT_KEY_ACTION;
+               if (tun_key->tun_flags & OVS_FLOW_TNL_F_CSUM)
+                       *flags |= TNL_F_CSUM;
+               *tunnel_type = TNL_T_PROTO_GRE;
+               *out_key = tun_key->tun_id;
+       } else {
+               *flags = mutable->flags;
+               *tunnel_type = mutable->key.tunnel_type;
+               if (mutable->flags & TNL_F_OUT_KEY_ACTION)
+                       *out_key = tun_key->tun_id;
+               else
+                       *out_key = mutable->out_key;
+
+       }
+}
+
+static int gre_hdr_len(const struct tnl_mutable_config *mutable,
+                      const struct ovs_key_ipv4_tunnel *tun_key)
 {
        int len;
+       u32 flags;
+       u32 tunnel_type;
+       __be64 out_key;
 
+       get_gre_param(mutable, tun_key, &flags, &tunnel_type, &out_key);
        len = GRE_HEADER_SECTION;
 
-       if (mutable->flags & TNL_F_CSUM)
+       if (flags & TNL_F_CSUM)
                len += GRE_HEADER_SECTION;
 
-       if (mutable->out_key || mutable->flags & TNL_F_OUT_KEY_ACTION)
-               len += GRE_HEADER_SECTION;
+       /* Set key for GRE64 tunnels, even when key if is zero. */
+       if (out_key ||
+           tunnel_type & TNL_T_PROTO_GRE64 ||
+           flags & TNL_F_OUT_KEY_ACTION) {
 
+               len += GRE_HEADER_SECTION;
+               if (tunnel_type & TNL_T_PROTO_GRE64)
+                       len += GRE_HEADER_SECTION;
+       }
        return len;
 }
 
+
 /* Returns the least-significant 32 bits of a __be64. */
 static __be32 be64_get_low32(__be64 x)
 {
@@ -70,45 +106,85 @@ static __be32 be64_get_low32(__be64 x)
 #endif
 }
 
+static __be32 be64_get_high32(__be64 x)
+{
+#ifdef __BIG_ENDIAN
+       return (__force __be32)((__force u64)x >> 32);
+#else
+       return (__force __be32)x;
+#endif
+}
+
 static void gre_build_header(const struct vport *vport,
                             const struct tnl_mutable_config *mutable,
+                            const struct ovs_key_ipv4_tunnel *tun_key,
                             void *header)
 {
        struct gre_base_hdr *greh = header;
        __be32 *options = (__be32 *)(greh + 1);
+       u32 flags;
+       u32 tunnel_type;
+       __be64 out_key;
+
+       get_gre_param(mutable, tun_key, &flags, &tunnel_type, &out_key);
 
        greh->protocol = htons(ETH_P_TEB);
        greh->flags = 0;
 
-       if (mutable->flags & TNL_F_CSUM) {
+       if (flags & TNL_F_CSUM) {
                greh->flags |= GRE_CSUM;
                *options = 0;
                options++;
        }
 
-       if (mutable->out_key || mutable->flags & TNL_F_OUT_KEY_ACTION)
+       if (flags & TNL_F_OUT_KEY_ACTION) {
                greh->flags |= GRE_KEY;
+               if (tunnel_type & TNL_T_PROTO_GRE64)
+                       greh->flags |= GRE_SEQ;
 
-       if (mutable->out_key)
-               *options = be64_get_low32(mutable->out_key);
+       } else if (out_key ||
+                  tunnel_type & TNL_T_PROTO_GRE64) {
+               greh->flags |= GRE_KEY;
+               *options = be64_get_low32(out_key);
+               if (tunnel_type & TNL_T_PROTO_GRE64) {
+                       options++;
+                       *options = be64_get_high32(out_key);
+                       greh->flags |= GRE_SEQ;
+               }
+       }
 }
 
 static struct sk_buff *gre_update_header(const struct vport *vport,
                                         const struct tnl_mutable_config *mutable,
                                         struct dst_entry *dst,
-                                        struct sk_buff *skb)
+                                        struct sk_buff *skb,
+                                        int tunnel_hlen)
 {
-       __be32 *options = (__be32 *)(skb_network_header(skb) + mutable->tunnel_hlen
+       u32 flags;
+       u32 tunnel_type;
+       __be64 out_key;
+       const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key;
+       __be32 *options = (__be32 *)(skb_network_header(skb) + tunnel_hlen
                                               - GRE_HEADER_SECTION);
 
-       /* Work backwards over the options so the checksum is last. */
-       if (mutable->flags & TNL_F_OUT_KEY_ACTION)
-               *options = be64_get_low32(OVS_CB(skb)->tun_id);
+       get_gre_param(mutable, tun_key, &flags, &tunnel_type, &out_key);
 
-       if (mutable->out_key || mutable->flags & TNL_F_OUT_KEY_ACTION)
+       /* Work backwards over the options so the checksum is last. */
+       if (flags & TNL_F_OUT_KEY_ACTION) {
+               if (tunnel_type & TNL_T_PROTO_GRE64) {
+                       /* Set higher 32 bits to seq. */
+                       *options = be64_get_high32(out_key);
+                       options--;
+               }
+               *options = be64_get_low32(out_key);
+               options--;
+       } else if (out_key || tunnel_type & TNL_T_PROTO_GRE64) {
                options--;
+               if (tunnel_type & TNL_T_PROTO_GRE64)
+                       options--;
+       }
 
-       if (mutable->flags & TNL_F_CSUM)
+       if (flags & TNL_F_CSUM)
                *(__sum16 *)options = csum_fold(skb_checksum(skb,
                                                skb_transport_offset(skb),
                                                skb->len - skb_transport_offset(skb),
@@ -125,17 +201,17 @@ static struct sk_buff *gre_update_header(const struct vport *vport,
        return skb;
 }
 
-/* Zero-extends a __be32 into the least-significant 32 bits of a __be64. */
-static __be64 be32_extend_to_be64(__be32 x)
+static __be64 key_to_tunnel_id(__be32 key, __be32 seq)
 {
 #ifdef __BIG_ENDIAN
-       return (__force __be64)x;
+       return (__force __be64)((__force u64)seq << 32 | (__force u32)key);
 #else
-       return (__force __be64)((__force u64)x << 32);
+       return (__force __be64)((__force u64)key << 32 | (__force u32)seq);
 #endif
 }
 
-static int parse_header(struct iphdr *iph, __be16 *flags, __be64 *key)
+static int parse_header(struct iphdr *iph, __be16 *flags, __be64 *tun_id,
+                       u32 *tunnel_type)
 {
        /* IP and ICMP protocol handlers check that the IHL is valid. */
        struct gre_base_hdr *greh = (struct gre_base_hdr *)((u8 *)iph + (iph->ihl << 2));
@@ -158,14 +234,28 @@ static int parse_header(struct iphdr *iph, __be16 *flags, __be64 *key)
        }
 
        if (greh->flags & GRE_KEY) {
-               hdr_len += GRE_HEADER_SECTION;
+               __be32 seq;
+               __be32 gre_key;
 
-               *key = be32_extend_to_be64(*options);
+               gre_key = *options;
+               hdr_len += GRE_HEADER_SECTION;
                options++;
-       } else
-               *key = 0;
 
-       if (unlikely(greh->flags & GRE_SEQ))
+               if (greh->flags & GRE_SEQ) {
+                       seq = *options;
+                       *tunnel_type = TNL_T_PROTO_GRE64;
+               } else {
+                       seq = 0;
+                       *tunnel_type = TNL_T_PROTO_GRE;
+               }
+               *tun_id = key_to_tunnel_id(gre_key, seq);
+       } else {
+               *tun_id = 0;
+               /* Ignore GRE seq if there is no key present. */
+               *tunnel_type = TNL_T_PROTO_GRE;
+       }
+
+       if (greh->flags & GRE_SEQ)
                hdr_len += GRE_HEADER_SECTION;
 
        return hdr_len;
@@ -179,6 +269,7 @@ static void gre_err(struct sk_buff *skb, u32 info)
        const int type = icmp_hdr(skb)->type;
        const int code = icmp_hdr(skb)->code;
        int mtu = ntohs(icmp_hdr(skb)->un.frag.mtu);
+       u32 tunnel_type;
 
        struct iphdr *iph;
        __be16 flags;
@@ -203,12 +294,12 @@ static void gre_err(struct sk_buff *skb, u32 info)
        if (ipv4_is_multicast(iph->daddr))
                return;
 
-       tunnel_hdr_len = parse_header(iph, &flags, &key);
+       tunnel_hdr_len = parse_header(iph, &flags, &key, &tunnel_type);
        if (tunnel_hdr_len < 0)
                return;
 
        vport = ovs_tnl_find_port(dev_net(skb->dev), iph->saddr, iph->daddr, key,
-                                 TNL_T_PROTO_GRE, &mutable);
+                                 tunnel_type, &mutable);
        if (!vport)
                return;
 
@@ -285,7 +376,7 @@ static void gre_err(struct sk_buff *skb, u32 info)
 #endif
 
        __skb_pull(skb, tunnel_hdr_len);
-       ovs_tnl_frag_needed(vport, mutable, skb, mtu, key);
+       ovs_tnl_frag_needed(vport, mutable, skb, mtu);
        __skb_push(skb, tunnel_hdr_len);
 
 out:
@@ -320,6 +411,24 @@ static bool check_checksum(struct sk_buff *skb)
        return (csum == 0);
 }
 
+static u32 gre_flags_to_tunnel_flags(const struct tnl_mutable_config *mutable,
+                                    __be16 gre_flags)
+{
+       u32 tunnel_flags = 0;
+
+       if (gre_flags & GRE_KEY) {
+               if (mutable->key.daddr && (mutable->flags & TNL_F_IN_KEY_MATCH))
+                       tunnel_flags = OVS_FLOW_TNL_F_KEY;
+               else if (!mutable->key.daddr)
+                       tunnel_flags = OVS_FLOW_TNL_F_KEY;
+       }
+
+       if (gre_flags & GRE_CSUM)
+               tunnel_flags |= OVS_FLOW_TNL_F_CSUM;
+
+       return tunnel_flags;
+}
+
 /* Called with rcu_read_lock and BH disabled. */
 static int gre_rcv(struct sk_buff *skb)
 {
@@ -327,16 +436,17 @@ static int gre_rcv(struct sk_buff *skb)
        const struct tnl_mutable_config *mutable;
        int hdr_len;
        struct iphdr *iph;
+       struct ovs_key_ipv4_tunnel tun_key;
        __be16 flags;
        __be64 key;
+       u32 tunnel_type;
 
        if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr) + ETH_HLEN)))
                goto error;
-
        if (unlikely(!check_checksum(skb)))
                goto error;
 
-       hdr_len = parse_header(ip_hdr(skb), &flags, &key);
+       hdr_len = parse_header(ip_hdr(skb), &flags, &key, &tunnel_type);
        if (unlikely(hdr_len < 0))
                goto error;
 
@@ -345,21 +455,19 @@ static int gre_rcv(struct sk_buff *skb)
 
        iph = ip_hdr(skb);
        vport = ovs_tnl_find_port(dev_net(skb->dev), iph->daddr, iph->saddr, key,
-                                 TNL_T_PROTO_GRE, &mutable);
+                                 tunnel_type, &mutable);
        if (unlikely(!vport)) {
                icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
                goto error;
        }
 
-       if (mutable->flags & TNL_F_IN_KEY_MATCH)
-               OVS_CB(skb)->tun_id = key;
-       else
-               OVS_CB(skb)->tun_id = 0;
+       tnl_tun_key_init(&tun_key, iph, key, gre_flags_to_tunnel_flags(mutable, flags));
+       OVS_CB(skb)->tun_key = &tun_key;
 
        __skb_pull(skb, hdr_len);
        skb_postpull_rcsum(skb, skb_transport_header(skb), hdr_len + ETH_HLEN);
 
-       ovs_tnl_rcv(vport, skb, iph->tos);
+       ovs_tnl_rcv(vport, skb);
        return 0;
 
 error:
@@ -380,6 +488,19 @@ static struct vport *gre_create(const struct vport_parms *parms)
        return ovs_tnl_create(parms, &ovs_gre_vport_ops, &gre_tnl_ops);
 }
 
+static const struct tnl_ops gre64_tnl_ops = {
+       .tunnel_type    = TNL_T_PROTO_GRE64,
+       .ipproto        = IPPROTO_GRE,
+       .hdr_len        = gre_hdr_len,
+       .build_header   = gre_build_header,
+       .update_header  = gre_update_header,
+};
+
+static struct vport *gre_create64(const struct vport_parms *parms)
+{
+       return ovs_tnl_create(parms, &ovs_gre64_vport_ops, &gre64_tnl_ops);
+}
+
 static const struct net_protocol gre_protocol_handlers = {
        .handler        =       gre_rcv,
        .err_handler    =       gre_err,
@@ -388,10 +509,16 @@ static const struct net_protocol gre_protocol_handlers = {
 #endif
 };
 
+static bool inited;
+
 static int gre_init(void)
 {
        int err;
 
+       if (inited)
+               return 0;
+
+       inited = true;
        err = inet_add_protocol(&gre_protocol_handlers, IPPROTO_GRE);
        if (err)
                pr_warn("cannot register gre protocol handler\n");
@@ -401,6 +528,11 @@ static int gre_init(void)
 
 static void gre_exit(void)
 {
+       if (!inited)
+               return;
+
+       inited = false;
+
        inet_del_protocol(&gre_protocol_handlers, IPPROTO_GRE);
 }
 
@@ -421,3 +553,21 @@ const struct vport_ops ovs_gre_vport_ops = {
        .get_operstate  = ovs_vport_gen_get_operstate,
        .send           = ovs_tnl_send,
 };
+
+const struct vport_ops ovs_gre64_vport_ops = {
+       .type           = OVS_VPORT_TYPE_GRE64,
+       .flags          = VPORT_F_TUN_ID,
+       .init           = gre_init,
+       .exit           = gre_exit,
+       .create         = gre_create64,
+       .destroy        = ovs_tnl_destroy,
+       .set_addr       = ovs_tnl_set_addr,
+       .get_name       = ovs_tnl_get_name,
+       .get_addr       = ovs_tnl_get_addr,
+       .get_options    = ovs_tnl_get_options,
+       .set_options    = ovs_tnl_set_options,
+       .get_dev_flags  = ovs_vport_gen_get_dev_flags,
+       .is_running     = ovs_vport_gen_is_running,
+       .get_operstate  = ovs_vport_gen_get_operstate,
+       .send           = ovs_tnl_send,
+};
index 0098554..f1ecfdb 100644 (file)
@@ -304,7 +304,7 @@ static int netdev_send(struct vport *vport, struct sk_buff *skb)
 
        if (unlikely(packet_length(skb) > mtu && !skb_is_gso(skb))) {
                net_warn_ratelimited("%s: dropped over-mtu packet: %d > %d\n",
-                                    ovs_dp_name(vport->dp),
+                                    netdev_vport->dev->name,
                                     packet_length(skb), mtu);
                goto error;
        }
index dc7adfa..d9c8cfd 100644 (file)
@@ -41,6 +41,7 @@ static const struct vport_ops *base_vport_ops_list[] = {
        &ovs_internal_vport_ops,
        &ovs_patch_vport_ops,
        &ovs_gre_vport_ops,
+       &ovs_gre64_vport_ops,
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
        &ovs_capwap_vport_ops,
 #endif
@@ -462,7 +463,7 @@ void ovs_vport_receive(struct vport *vport, struct sk_buff *skb)
                OVS_CB(skb)->flow = NULL;
 
        if (!(vport->ops->flags & VPORT_F_TUN_ID))
-               OVS_CB(skb)->tun_id = 0;
+               OVS_CB(skb)->tun_key = NULL;
 
        ovs_dp_process_received_packet(vport, skb);
 }
index 5cd3c18..61d5274 100644 (file)
@@ -254,6 +254,7 @@ extern const struct vport_ops ovs_netdev_vport_ops;
 extern const struct vport_ops ovs_internal_vport_ops;
 extern const struct vport_ops ovs_patch_vport_ops;
 extern const struct vport_ops ovs_gre_vport_ops;
+extern const struct vport_ops ovs_gre64_vport_ops;
 extern const struct vport_ops ovs_capwap_vport_ops;
 
 #endif /* vport.h */
index 7b8bedb..9ac3d5d 100644 (file)
@@ -1,9 +1,53 @@
-openvswitch (1.8.90-1) unstable; urgency=low
+openvswitch (1.9.90-1) unstable; urgency=low
    [ Open vSwitch team ]
    * New upstream version
-    - Nothing yet!  Try NEWS...
+     - Nothing yet!  Try NEWS...
 
- -- Open vSwitch team <dev@openvswitch.org>  Mon, 07 May 2012 14:14:52 +0900
+ -- Open vSwitch team <dev@openvswitch.org>  Wed, 24 Oct 2012 16:12:57 -0700
+
+openvswitch (1.9.0-1) unstable; urgency=low
+   [ Open vSwitch team ]
+   * New upstream version
+    - The tunneling code no longer assumes input and output keys are symmetric.
+      If they are not, PMTUD needs to be disabled for tunneling to work. Note
+      this only applies to flow-based keys.
+    - FreeBSD is now a supported platform, thanks to code contributions from
+      Gaetano Catalli, Ed Maste, and Giuseppe Lettieri.
+    - ovs-bugtool: New --ovs option to report only OVS related information.
+    - New %t and %T log escapes to identify the subprogram within a
+      cooperating group of processes or threads that emitted a log message.
+      The default log patterns now include this information.
+    - OpenFlow:
+      - Allow bitwise masking for SHA and THA fields in ARP, SLL and TLL
+        fields in IPv6 neighbor discovery messages, and IPv6 flow label.
+      - Adds support for writing to the metadata field for a flow.
+    - ovs-ofctl:
+      - Commands and actions that accept port numbers now also accept keywords
+        that represent those ports (such as LOCAL, NONE, and ALL).  This is
+        also the recommended way to specify these ports, for compatibility
+        with OpenFlow 1.1 and later (which use the OpenFlow 1.0 numbers
+        for these ports for different purposes).
+    - ovs-dpctl:
+      - Support requesting the port number with the "port_no" option in
+        the "add-if" command.
+    - ovs-pki: The "online PKI" features have been removed, along with
+      the ovs-pki-cgi program that facilitated it, because of some
+      alarmist insecurity claims.  We do not believe that these claims
+      are true, but because we do not know of any users for this
+      feature it seems better on balance to remove it.  (The ovs-pki-cgi
+      program was not included in distribution packaging.)
+    - ovsdb-server now enforces the immutability of immutable columns.  This
+      was not enforced in earlier versions due to an oversight.
+    - New support for a nonstandard form of GRE that supports a 64-bit key.
+    - The following features are now deprecated.  They will be removed no
+      earlier than February 2013.  Please email dev@openvswitch.org with
+      concerns.
+        - Stable bond mode.
+        - The autopath action.
+        - Interface type "null".
+        - Numeric values for reserved ports (see "ovs-ofctl" note above).
+
+ -- Open vSwitch team <dev@openvswitch.org>  Wed, 24 Oct 2012 16:10:39 -0700
 
 openvswitch (1.8.0-1) unstable; urgency=low
    [ Open vSwitch team ]
index bd6aec8..f6a7750 100755 (executable)
@@ -61,6 +61,10 @@ if [ "${MODE}" = "start" ]; then
                     ${OVS_EXTRA+-- $OVS_EXTRA}
 
                 ifconfig "${IFACE}" up
+                for slave in ${IF_OVS_BONDS}
+                do
+                    ifconfig "${slave}" up
+                done
                 ;;
         *)
                 exit 0
index 3b1fd93..e2c0454 100644 (file)
@@ -1,6 +1,7 @@
 usr/bin/ovs-appctl
 usr/bin/ovs-benchmark
 usr/bin/ovs-ofctl
+usr/bin/ovs-parse-backtrace
 usr/bin/ovs-parse-leaks
 usr/bin/ovs-pki
 usr/bin/ovsdb-client
index 1e99479..05e93a8 100644 (file)
@@ -5,4 +5,5 @@ _debian/utilities/ovs-benchmark.1
 _debian/utilities/ovs-ofctl.8
 _debian/utilities/ovs-pki.8
 utilities/bugtool/ovs-bugtool.8
+utilities/ovs-parse-backtrace.8
 utilities/ovs-parse-leaks.8
index f650f87..301bc73 100755 (executable)
@@ -78,6 +78,17 @@ stop () {
     ovs_ctl stop
 }
 
+restart () {
+    # OVS_RESTART_SAVE_FLOWS can be set by package postinst script.
+    if [ "$OVS_RESTART_SAVE_FLOWS" = "yes" ] || \
+       [ "$1" = "--save-flows=yes" ]; then
+        start restart
+    else
+        stop
+        start
+    fi
+}
+
 case $1 in
     start)
         start
@@ -89,8 +100,8 @@ case $1 in
         # The OVS daemons keep up-to-date.
         ;;
     restart)
-        stop
-        start
+        shift
+        restart "$@"
         ;;
     status)
         ovs_ctl status
index 7b9d7bc..ac6ed65 100755 (executable)
@@ -49,6 +49,10 @@ esac
 OVS_MISSING_KMOD_OK=yes
 export OVS_MISSING_KMOD_OK
 
+# Save and restore openflow flows during a package upgrade.
+OVS_RESTART_SAVE_FLOWS=yes
+export OVS_RESTART_SAVE_FLOWS
+
 #DEBHELPER#
 
 exit 0
index ffaa979..414d18b 100755 (executable)
@@ -441,7 +441,7 @@ def main():
 
         new_interfaces = {}
         for rec in idl.tables["Interface"].rows.itervalues():
-            if rec.type == "ipsec_gre":
+            if rec.type == "ipsec_gre" or rec.type == "ipsec_gre64":
                 name = rec.name
                 options = rec.options
                 peer_cert_name = "ovs-%s.pem" % (options.get("remote_ip"))
index f5c9cca..89feb61 100644 (file)
@@ -185,6 +185,7 @@ enum ovs_vport_type {
        OVS_VPORT_TYPE_PATCH = 100, /* virtual tunnel connecting two vports */
        OVS_VPORT_TYPE_GRE,      /* GRE tunnel */
        OVS_VPORT_TYPE_CAPWAP,   /* CAPWAP tunnel */
+       OVS_VPORT_TYPE_GRE64 = 104, /* GRE tunnel with 64-bit keys */
        __OVS_VPORT_TYPE_MAX
 };
 
@@ -278,7 +279,8 @@ enum ovs_key_attr {
        OVS_KEY_ATTR_ICMPV6,    /* struct ovs_key_icmpv6 */
        OVS_KEY_ATTR_ARP,       /* struct ovs_key_arp */
        OVS_KEY_ATTR_ND,        /* struct ovs_key_nd */
-       OVS_KEY_ATTR_TUN_ID = 63, /* be64 tunnel ID */
+       OVS_KEY_ATTR_IPV4_TUNNEL = 62,  /* struct ovs_key_ipv4_tunnel */
+       OVS_KEY_ATTR_TUN_ID = 63,  /* be64 tunnel ID */
        __OVS_KEY_ATTR_MAX
 };
 
@@ -360,6 +362,21 @@ struct ovs_key_nd {
        __u8  nd_tll[6];
 };
 
+/* Values for ovs_key_ipv4_tunnel->tun_flags */
+#define OVS_FLOW_TNL_F_DONT_FRAGMENT (1 << 0)
+#define OVS_FLOW_TNL_F_CSUM (1 << 1)
+#define OVS_FLOW_TNL_F_KEY (1 << 2)
+
+struct ovs_key_ipv4_tunnel {
+       __be64 tun_id;
+       __u32  tun_flags;
+       __be32 ipv4_src;
+       __be32 ipv4_dst;
+       __u8   ipv4_tos;
+       __u8   ipv4_ttl;
+       __u8   pad[2];
+};
+
 /**
  * enum ovs_flow_attr - attributes for %OVS_FLOW_* commands.
  * @OVS_FLOW_ATTR_KEY: Nested %OVS_KEY_ATTR_* attributes specifying the flow
index 75bf6db..e9790fd 100644 (file)
@@ -129,10 +129,9 @@ enum nx_hash_fields {
  *      table.  If an identical flow already exists in that table only, then it
  *      is replaced.  If the flow cannot be placed in the specified table,
  *      either because the table is full or because the table cannot support
- *      flows of the given type, the switch replies with an
- *      OFPFMFC_ALL_TABLES_FULL error.  (A controller can distinguish these
- *      cases by comparing the current and maximum number of entries reported
- *      in ofp_table_stats.)
+ *      flows of the given type, the switch replies with an OFPFMFC_TABLE_FULL
+ *      error.  (A controller can distinguish these cases by comparing the
+ *      current and maximum number of entries reported in ofp_table_stats.)
  *
  *      If the table ID is wildcarded, the switch picks an appropriate table
  *      itself.  If an identical flow already exist in the selected flow table,
@@ -304,6 +303,7 @@ enum nx_action_subtype {
     NXAST_FIN_TIMEOUT,          /* struct nx_action_fin_timeout */
     NXAST_CONTROLLER,           /* struct nx_action_controller */
     NXAST_DEC_TTL_CNT_IDS,      /* struct nx_action_cnt_ids */
+    NXAST_WRITE_METADATA,       /* struct nx_action_write_metadata */
 };
 
 /* Header for Nicira-defined actions. */
@@ -503,6 +503,10 @@ OFP_ASSERT(sizeof(struct nx_action_pop_queue) == 16);
  * The switch will reject actions for which src_ofs+n_bits is greater than the
  * width of 'src' or dst_ofs+n_bits is greater than the width of 'dst' with
  * error type OFPET_BAD_ACTION, code OFPBAC_BAD_ARGUMENT.
+ *
+ * This action behaves properly when 'src' overlaps with 'dst', that is, it
+ * behaves as if 'src' were copied out to a temporary buffer, then the
+ * temporary buffer copied to 'dst'.
  */
 struct nx_action_reg_move {
     ovs_be16 type;                  /* OFPAT_VENDOR. */
@@ -2173,10 +2177,10 @@ OFP_ASSERT(sizeof(struct nx_flow_update_full) == 24);
  * change in future versions of Open vSwitch.
  *
  * OVS will always send the notifications for a given flow table change before
- * the reply to a OFPT_BARRIER_REQUEST request that precedes the flow table
- * change.  Thus, if the controller does not receive an abbreviated
- * notification for a flow_mod before the next OFPT_BARRIER_REPLY, it will
- * never receive one. */
+ * the reply to a OFPT_BARRIER_REQUEST request that follows the flow table
+ * change.  Thus, if the controller does not receive an abbreviated (or
+ * unabbreviated) notification for a flow_mod before the next
+ * OFPT_BARRIER_REPLY, it will never receive one. */
 struct nx_flow_update_abbrev {
     ovs_be16 length;            /* Length is 8. */
     ovs_be16 event;             /* NXFME_ABBREV. */
@@ -2192,4 +2196,18 @@ struct nx_flow_monitor_cancel {
 };
 OFP_ASSERT(sizeof(struct nx_flow_monitor_cancel) == 4);
 
+/* Action structure for NXAST_WRITE_METADATA.
+ *
+ * Modifies the 'mask' bits of the metadata value. */
+struct nx_action_write_metadata {
+    ovs_be16 type;                  /* OFPAT_VENDOR. */
+    ovs_be16 len;                   /* Length is 32. */
+    ovs_be32 vendor;                /* NX_VENDOR_ID. */
+    ovs_be16 subtype;               /* NXAST_WRITE_METADATA. */
+    uint8_t zeros[6];               /* Must be zero. */
+    ovs_be64 metadata;              /* Metadata register. */
+    ovs_be64 mask;                  /* Metadata mask. */
+};
+OFP_ASSERT(sizeof(struct nx_action_write_metadata) == 32);
+
 #endif /* openflow/nicira-ext.h */
index f6befdb..1c3f017 100644 (file)
@@ -190,23 +190,7 @@ struct ofp12_oxm_experimenter_header {
 OFP_ASSERT(sizeof(struct ofp12_oxm_experimenter_header) == 8);
 
 enum ofp12_action_type {
-    OFPAT12_OUTPUT       = 0,  /* Output to switch port. */
-    OFPAT12_COPY_TTL_OUT = 11, /* Copy TTL "outwards" -- from next-to-outermost
-                                  to outermost */
-    OFPAT12_COPY_TTL_IN,       /* Copy TTL "inwards" -- from outermost to
-                                  next-to-outermost */
-    OFPAT12_SET_MPLS_TTL = 15, /* MPLS TTL */
-    OFPAT12_DEC_MPLS_TTL,      /* Decrement MPLS TTL */
-    OFPAT12_PUSH_VLAN,         /* Push a new VLAN tag */
-    OFPAT12_POP_VLAN,          /* Pop the outer VLAN tag */
-    OFPAT12_PUSH_MPLS,         /* Push a new MPLS tag */
-    OFPAT12_POP_MPLS,          /* Pop the outer MPLS tag */
-    OFPAT12_SET_QUEUE,         /* Set queue id when outputting to a port */
-    OFPAT12_GROUP,             /* Apply group. */
-    OFPAT12_SET_NW_TTL,        /* IP TTL. */
-    OFPAT12_DEC_NW_TTL,        /* Decrement IP TTL. */
-    OFPAT12_SET_FIELD,         /* Set a header field using OXM TLV format. */
-    OFPAT12_EXPERIMENTER = 0xffff
+    OFPAT12_SET_FIELD = 25,     /* Set a header field using OXM TLV format. */
 };
 
 enum ofp12_controller_max_len {
index 238ba34..4a25137 100644 (file)
@@ -231,7 +231,7 @@ if HAVE_WNO_UNUSED_PARAMETER
 lib_libsflow_a_CFLAGS += -Wno-unused-parameter
 endif
 
-if HAVE_NETLINK
+if LINUX_DATAPATH
 lib_libopenvswitch_a_SOURCES += \
        lib/dpif-linux.c \
        lib/dpif-linux.h \
@@ -250,6 +250,11 @@ lib_libopenvswitch_a_SOURCES += \
        lib/route-table.h
 endif
 
+if ESX
+lib_libopenvswitch_a_SOURCES += \
+        lib/route-table-stub.c
+endif
+
 if HAVE_IF_DL
 lib_libopenvswitch_a_SOURCES += \
        lib/netdev-bsd.c \
@@ -304,14 +309,16 @@ MAN_FRAGMENTS += \
 
 # vswitch IDL
 OVSIDL_BUILT += \
-       lib/vswitch-idl.c \
-       lib/vswitch-idl.h \
-       lib/vswitch-idl.ovsidl
+       $(srcdir)/lib/vswitch-idl.c \
+       $(srcdir)/lib/vswitch-idl.h \
+       $(srcdir)/lib/vswitch-idl.ovsidl
 
-EXTRA_DIST += lib/vswitch-idl.ann
-VSWITCH_IDL_FILES = vswitchd/vswitch.ovsschema lib/vswitch-idl.ann
-lib/vswitch-idl.ovsidl: $(VSWITCH_IDL_FILES)
-       $(OVSDB_IDLC) -C $(srcdir) annotate $(VSWITCH_IDL_FILES) > $@.tmp
+EXTRA_DIST += $(srcdir)/lib/vswitch-idl.ann
+VSWITCH_IDL_FILES = \
+       $(srcdir)/vswitchd/vswitch.ovsschema \
+       $(srcdir)/lib/vswitch-idl.ann
+$(srcdir)/lib/vswitch-idl.ovsidl: $(VSWITCH_IDL_FILES)
+       $(OVSDB_IDLC) annotate $(VSWITCH_IDL_FILES) > $@.tmp
        mv $@.tmp $@
 
 lib/dirs.c: lib/dirs.c.in Makefile
index b204e84..9da6463 100644 (file)
@@ -37,6 +37,7 @@ autopath_parse(struct ofpact_autopath *ap, const char *s_)
 {
     char *s;
     char *id_str, *dst, *save_ptr;
+    uint16_t port;
 
     ofpact_init_AUTOPATH(ap);
 
@@ -49,10 +50,10 @@ autopath_parse(struct ofpact_autopath *ap, const char *s_)
         ovs_fatal(0, "%s: not enough arguments to autopath action", s_);
     }
 
-    ap->port = ofputil_port_from_string(id_str);
-    if (!ap->port) {
+    if (!ofputil_port_from_string(id_str, &port)) {
         ovs_fatal(0, "%s: bad port number", s_);
     }
+    ap->port = port;
 
     mf_parse_subfield(&ap->dst, dst);
     if (ap->dst.n_bits < 16) {
index b68ebab..92ac1e1 100644 (file)
@@ -272,8 +272,7 @@ bundle_parse__(const char *s, char **save_ptr,
             break;
         }
 
-        slave_port = ofputil_port_from_string(slave);
-        if (!slave_port) {
+        if (!ofputil_port_from_string(slave, &slave_port)) {
             ovs_fatal(0, "%s: bad port number", slave);
         }
         ofpbuf_put(ofpacts, &slave_port, sizeof slave_port);
index fc999ab..b71c242 100644 (file)
--- a/lib/cfm.c
+++ b/lib/cfm.c
@@ -86,6 +86,7 @@ struct cfm {
     struct hmap_node hmap_node; /* Node in all_cfms list. */
 
     uint64_t mpid;
+    bool check_tnl_key;    /* Verify the tunnel key of inbound packets? */
     bool extended;         /* Extended mode. */
     bool booted;           /* A full fault interval has occured. */
     enum cfm_fault_reason fault;  /* Connectivity fault status. */
@@ -505,6 +506,7 @@ cfm_configure(struct cfm *cfm, const struct cfm_settings *s)
     }
 
     cfm->mpid = s->mpid;
+    cfm->check_tnl_key = s->check_tnl_key;
     cfm->extended = s->extended;
     cfm->opup = s->opup;
     interval = ms_to_ccm_interval(s->interval);
@@ -533,7 +535,8 @@ bool
 cfm_should_process_flow(const struct cfm *cfm, const struct flow *flow)
 {
     return (ntohs(flow->dl_type) == ETH_TYPE_CFM
-            && eth_addr_equals(flow->dl_dst, cfm_ccm_addr(cfm)));
+            && eth_addr_equals(flow->dl_dst, cfm_ccm_addr(cfm))
+            && (!cfm->check_tnl_key || flow->tunnel.tun_id == htonll(0)));
 }
 
 /* Updates internal statistics relevant to packet 'p'.  Should be called on
index de4c299..8bb6778 100644 (file)
--- a/lib/cfm.h
+++ b/lib/cfm.h
@@ -57,6 +57,8 @@ struct cfm_settings {
     uint16_t ccm_vlan;          /* CCM Vlan tag. Zero if none.
                                    CFM_RANDOM_VLAN if random. */
     uint8_t ccm_pcp;            /* CCM Priority. Zero if none. */
+
+    bool check_tnl_key;         /* Verify inbound packet key? */
 };
 
 void cfm_init(void);
index ca443a3..b881c04 100644 (file)
@@ -92,7 +92,7 @@ run_command(int argc, char *argv[], const struct command commands[])
 \f
 /* Process title. */
 
-#ifdef __linux__
+#ifdef LINUX_DATAPATH
 static char *argv_start;       /* Start of command-line arguments in memory. */
 static size_t argv_size;       /* Number of bytes of command-line arguments. */
 static char *saved_proctitle;  /* Saved command-line arguments. */
@@ -140,8 +140,8 @@ proctitle_init(int argc, char **argv)
     }
 }
 
-/* Changes the name of the process, as shown by "ps", to 'format', which is
- * formatted as if by printf(). */
+/* Changes the name of the process, as shown by "ps", to the program name
+ * followed by 'format', which is formatted as if by printf(). */
 void
 proctitle_set(const char *format, ...)
 {
@@ -157,7 +157,10 @@ proctitle_set(const char *format, ...)
     }
 
     va_start(args, format);
-    n = vsnprintf(argv_start, argv_size, format, args);
+    n = snprintf(argv_start, argv_size, "%s: ", program_name);
+    if (n < argv_size) {
+        n += vsnprintf(argv_start + n, argv_size - n, format, args);
+    }
     if (n >= argv_size) {
         /* The name is too long, so add an ellipsis at the end. */
         strcpy(&argv_start[argv_size - 4], "...");
@@ -179,7 +182,7 @@ proctitle_restore(void)
         saved_proctitle = NULL;
     }
 }
-#else  /* !__linux__ */
+#else  /* !LINUX_DATAPATH*/
 /* Stubs that don't do anything on non-Linux systems. */
 
 void
@@ -187,13 +190,16 @@ proctitle_init(int argc OVS_UNUSED, char **argv OVS_UNUSED)
 {
 }
 
+#ifndef __FreeBSD__
+/* On FreeBSD we #define this to setproctitle. */
 void
 proctitle_set(const char *format OVS_UNUSED, ...)
 {
 }
+#endif
 
 void
 proctitle_restore(void)
 {
 }
-#endif  /* !__linux__ */
+#endif  /* !LINUX_DATAPATH */
index 803f433..2592b79 100644 (file)
@@ -34,8 +34,12 @@ char *long_options_to_short_options(const struct option *options);
 void run_command(int argc, char *argv[], const struct command[]);
 
 void proctitle_init(int argc, char **argv);
+#ifdef __FreeBSD__
+#define proctitle_set setproctitle
+#else
 void proctitle_set(const char *, ...)
     PRINTF_FORMAT(1, 2);
+#endif
 void proctitle_restore(void);
 
 #endif /* command-line.h */
index 84ed614..71f6f81 100644 (file)
@@ -385,9 +385,8 @@ monitor_daemon(pid_t daemon_pid)
         int retval;
         int status;
 
-        proctitle_set("%s: monitoring pid %lu (%s)",
-                      program_name, (unsigned long int) daemon_pid,
-                      status_msg);
+        proctitle_set("monitoring pid %lu (%s)",
+                      (unsigned long int) daemon_pid, status_msg);
 
         do {
             retval = waitpid(daemon_pid, &status, 0);
index a2eb490..3a4a4e6 100644 (file)
@@ -1399,7 +1399,7 @@ dpif_linux_vport_send(int dp_ifindex, uint32_t port_no,
     uint64_t action;
 
     ofpbuf_use_const(&packet, data, size);
-    flow_extract(&packet, 0, htonll(0), 0, &flow);
+    flow_extract(&packet, 0, NULL, 0, &flow);
 
     ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
     odp_flow_key_from_flow(&key, &flow);
index 28f64b1..9f7bb6e 100644 (file)
@@ -925,7 +925,7 @@ dpif_netdev_execute(struct dpif *dpif, const struct dpif_execute *execute)
     ofpbuf_reserve(&copy, DP_NETDEV_HEADROOM);
     ofpbuf_put(&copy, execute->packet->data, execute->packet->size);
 
-    flow_extract(&copy, 0, 0, -1, &key);
+    flow_extract(&copy, 0, NULL, -1, &key);
     error = dpif_netdev_flow_from_nlattrs(execute->key, execute->key_len,
                                           &key);
     if (!error) {
@@ -1005,13 +1005,12 @@ dpif_netdev_recv_purge(struct dpif *dpif)
 }
 \f
 static void
-dp_netdev_flow_used(struct dp_netdev_flow *flow, struct flow *key,
-                    const struct ofpbuf *packet)
+dp_netdev_flow_used(struct dp_netdev_flow *flow, const struct ofpbuf *packet)
 {
     flow->used = time_msec();
     flow->packet_count++;
     flow->byte_count += packet->size;
-    flow->tcp_flags |= packet_get_tcp_flags(packet, key);
+    flow->tcp_flags |= packet_get_tcp_flags(packet, &flow->key);
 }
 
 static void
@@ -1024,10 +1023,10 @@ dp_netdev_port_input(struct dp_netdev *dp, struct dp_netdev_port *port,
     if (packet->size < ETH_HEADER_LEN) {
         return;
     }
-    flow_extract(packet, 0, 0, odp_port_to_ofp_port(port->port_no), &key);
+    flow_extract(packet, 0, NULL, odp_port_to_ofp_port(port->port_no), &key);
     flow = dp_netdev_lookup_flow(dp, &key);
     if (flow) {
-        dp_netdev_flow_used(flow, &key, packet);
+        dp_netdev_flow_used(flow, packet);
         dp_netdev_execute_actions(dp, packet, &key,
                                   flow->actions, flow->actions_len);
         dp->n_hit++;
@@ -1189,6 +1188,7 @@ execute_set_action(struct ofpbuf *packet, const struct nlattr *a)
     case OVS_KEY_ATTR_TUN_ID:
     case OVS_KEY_ATTR_PRIORITY:
     case OVS_KEY_ATTR_IPV6:
+    case OVS_KEY_ATTR_IPV4_TUNNEL:
         /* not implemented */
         break;
 
index f264e1b..70fb9cd 100644 (file)
@@ -292,7 +292,7 @@ struct dpif_class {
      * taken from the flow specified in the 'execute->key_len' bytes of
      * 'execute->key'.  ('execute->key' is mostly redundant with
      * 'execute->packet', but it contains some metadata that cannot be
-     * recovered from 'execute->packet', such as tun_id and in_port.) */
+     * recovered from 'execute->packet', such as tunnel and in_port.) */
     int (*execute)(struct dpif *dpif, const struct dpif_execute *execute);
 
     /* Executes each of the 'n_ops' operations in 'ops' on 'dpif', in the order
index 7be7b2a..68af298 100644 (file)
@@ -58,7 +58,7 @@ COVERAGE_DEFINE(dpif_execute);
 COVERAGE_DEFINE(dpif_purge);
 
 static const struct dpif_class *base_dpif_classes[] = {
-#ifdef HAVE_NETLINK
+#ifdef LINUX_DATAPATH
     &dpif_linux_class,
 #endif
     &dpif_netdev_class,
@@ -978,7 +978,7 @@ dpif_execute__(struct dpif *dpif, const struct dpif_execute *execute)
  * the Ethernet frame specified in 'packet' taken from the flow specified in
  * the 'key_len' bytes of 'key'.  ('key' is mostly redundant with 'packet', but
  * it contains some metadata that cannot be recovered from 'packet', such as
- * tun_id and in_port.)
+ * tunnel and in_port.)
  *
  * Returns 0 if successful, otherwise a positive errno value. */
 int
index 21ebb5a..7cfbd05 100644 (file)
@@ -74,9 +74,7 @@ fatal_signal_init(void)
 
         inited = true;
 
-        xpipe(signal_fds);
-        xset_nonblocking(signal_fds[0]);
-        xset_nonblocking(signal_fds[1]);
+        xpipe_nonblocking(signal_fds);
 
         sigemptyset(&fatal_signal_set);
         for (i = 0; i < ARRAY_SIZE(fatal_signals); i++) {
index e517a03..06478da 100644 (file)
@@ -31,6 +31,7 @@
 #include "csum.h"
 #include "dynamic-string.h"
 #include "hash.h"
+#include "match.h"
 #include "ofpbuf.h"
 #include "openflow/openflow.h"
 #include "packets.h"
@@ -316,7 +317,7 @@ invalid:
 
 }
 
-/* Initializes 'flow' members from 'packet', 'skb_priority', 'tun_id', and
+/* Initializes 'flow' members from 'packet', 'skb_priority', 'tnl', and
  * 'ofp_in_port'.
  *
  * Initializes 'packet' header pointers as follows:
@@ -334,8 +335,9 @@ invalid:
  *      present and has a correct length, and otherwise NULL.
  */
 void
-flow_extract(struct ofpbuf *packet, uint32_t skb_priority, ovs_be64 tun_id,
-             uint16_t ofp_in_port, struct flow *flow)
+flow_extract(struct ofpbuf *packet, uint32_t skb_priority,
+             const struct flow_tnl *tnl, uint16_t ofp_in_port,
+             struct flow *flow)
 {
     struct ofpbuf b = *packet;
     struct eth_header *eth;
@@ -343,7 +345,11 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority, ovs_be64 tun_id,
     COVERAGE_INC(flow_extract);
 
     memset(flow, 0, sizeof *flow);
-    flow->tun_id = tun_id;
+
+    if (tnl) {
+        assert(tnl != &flow->tunnel);
+        flow->tunnel = *tnl;
+    }
     flow->in_port = ofp_in_port;
     flow->skb_priority = skb_priority;
 
@@ -429,13 +435,10 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority, ovs_be64 tun_id,
                 flow->nw_proto = ntohs(arp->ar_op);
             }
 
-            if ((flow->nw_proto == ARP_OP_REQUEST)
-                || (flow->nw_proto == ARP_OP_REPLY)) {
-                flow->nw_src = arp->ar_spa;
-                flow->nw_dst = arp->ar_tpa;
-                memcpy(flow->arp_sha, arp->ar_sha, ETH_ADDR_LEN);
-                memcpy(flow->arp_tha, arp->ar_tha, ETH_ADDR_LEN);
-            }
+            flow->nw_src = arp->ar_spa;
+            flow->nw_dst = arp->ar_tpa;
+            memcpy(flow->arp_sha, arp->ar_sha, ETH_ADDR_LEN);
+            memcpy(flow->arp_tha, arp->ar_tha, ETH_ADDR_LEN);
         }
     }
 }
@@ -460,7 +463,7 @@ flow_get_metadata(const struct flow *flow, struct flow_metadata *fmd)
 {
     BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
 
-    fmd->tun_id = flow->tun_id;
+    fmd->tun_id = flow->tunnel.tun_id;
     fmd->metadata = flow->metadata;
     memcpy(fmd->regs, flow->regs, sizeof fmd->regs);
     fmd->in_port = flow->in_port;
@@ -477,60 +480,10 @@ flow_to_string(const struct flow *flow)
 void
 flow_format(struct ds *ds, const struct flow *flow)
 {
-    ds_put_format(ds, "priority:%"PRIu32
-                      ",tunnel:%#"PRIx64
-                      ",metadata:%#"PRIx64
-                      ",in_port:%04"PRIx16,
-                      flow->skb_priority,
-                      ntohll(flow->tun_id),
-                      ntohll(flow->metadata),
-                      flow->in_port);
-
-    ds_put_format(ds, ",tci(");
-    if (flow->vlan_tci) {
-        ds_put_format(ds, "vlan:%"PRIu16",pcp:%d",
-                      vlan_tci_to_vid(flow->vlan_tci),
-                      vlan_tci_to_pcp(flow->vlan_tci));
-    } else {
-        ds_put_char(ds, '0');
-    }
-    ds_put_format(ds, ") mac("ETH_ADDR_FMT"->"ETH_ADDR_FMT
-                      ") type:%04"PRIx16,
-                  ETH_ADDR_ARGS(flow->dl_src),
-                  ETH_ADDR_ARGS(flow->dl_dst),
-                  ntohs(flow->dl_type));
-
-    if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
-        ds_put_format(ds, " label:%#"PRIx32" proto:%"PRIu8" tos:%#"PRIx8
-                          " ttl:%"PRIu8" ipv6(",
-                      ntohl(flow->ipv6_label), flow->nw_proto,
-                      flow->nw_tos, flow->nw_ttl);
-        print_ipv6_addr(ds, &flow->ipv6_src);
-        ds_put_cstr(ds, "->");
-        print_ipv6_addr(ds, &flow->ipv6_dst);
-        ds_put_char(ds, ')');
-    } else if (flow->dl_type == htons(ETH_TYPE_IP) ||
-               flow->dl_type == htons(ETH_TYPE_ARP)) {
-        ds_put_format(ds, " proto:%"PRIu8" tos:%#"PRIx8" ttl:%"PRIu8
-                          " ip("IP_FMT"->"IP_FMT")",
-                          flow->nw_proto, flow->nw_tos, flow->nw_ttl,
-                          IP_ARGS(&flow->nw_src), IP_ARGS(&flow->nw_dst));
-    }
-    if (flow->nw_frag) {
-        ds_put_format(ds, " frag(%s)",
-                      flow->nw_frag == FLOW_NW_FRAG_ANY ? "first"
-                      : flow->nw_frag == (FLOW_NW_FRAG_ANY | FLOW_NW_FRAG_LATER)
-                      ? "later" : "<error>");
-    }
-    if (flow->tp_src || flow->tp_dst) {
-        ds_put_format(ds, " port(%"PRIu16"->%"PRIu16")",
-                ntohs(flow->tp_src), ntohs(flow->tp_dst));
-    }
-    if (!eth_addr_is_zero(flow->arp_sha) || !eth_addr_is_zero(flow->arp_tha)) {
-        ds_put_format(ds, " arp_ha("ETH_ADDR_FMT"->"ETH_ADDR_FMT")",
-                ETH_ADDR_ARGS(flow->arp_sha),
-                ETH_ADDR_ARGS(flow->arp_tha));
-    }
+    struct match match;
+
+    match_wc_init(&match, flow);
+    match_format(&match, ds, flow->skb_priority);
 }
 
 void
index fc62222..9388f20 100644 (file)
@@ -53,8 +53,20 @@ BUILD_ASSERT_DECL(FLOW_N_REGS <= NXM_NX_MAX_REGS);
 BUILD_ASSERT_DECL(FLOW_NW_FRAG_ANY == NX_IP_FRAG_ANY);
 BUILD_ASSERT_DECL(FLOW_NW_FRAG_LATER == NX_IP_FRAG_LATER);
 
+#define FLOW_TNL_F_DONT_FRAGMENT (1 << 0)
+#define FLOW_TNL_F_CSUM (1 << 1)
+#define FLOW_TNL_F_KEY (1 << 2)
+struct flow_tnl {
+    ovs_be64 tun_id;
+    ovs_be32 ip_src;
+    ovs_be32 ip_dst;
+    uint16_t flags;
+    uint8_t ip_tos;
+    uint8_t ip_ttl;
+};
+
 struct flow {
-    ovs_be64 tun_id;            /* Encapsulating tunnel ID. */
+    struct flow_tnl tunnel;     /* Encapsulating tunnel parameters. */
     ovs_be64 metadata;          /* OpenFlow Metadata. */
     struct in6_addr ipv6_src;   /* IPv6 source address. */
     struct in6_addr ipv6_dst;   /* IPv6 destination address. */
@@ -79,12 +91,13 @@ struct flow {
     uint8_t nw_frag;            /* FLOW_FRAG_* flags. */
     uint8_t zeros[2];           /* Must be zero. */
 };
-BUILD_ASSERT_DECL(sizeof(struct flow) % 8 == 0);
+BUILD_ASSERT_DECL(sizeof(struct flow) % 4 == 0);
 
 #define FLOW_U32S (sizeof(struct flow) / 4)
 
 /* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
-BUILD_ASSERT_DECL(sizeof(struct flow) == 152 && FLOW_WC_SEQ == 17);
+BUILD_ASSERT_DECL(sizeof(struct flow) == sizeof(struct flow_tnl) + 144 &&
+                  FLOW_WC_SEQ == 17);
 
 /* Represents the metadata fields of struct flow. */
 struct flow_metadata {
@@ -94,7 +107,7 @@ struct flow_metadata {
     uint16_t in_port;                /* OpenFlow port or zero. */
 };
 
-void flow_extract(struct ofpbuf *, uint32_t priority, ovs_be64 tun_id,
+void flow_extract(struct ofpbuf *, uint32_t priority, const struct flow_tnl *,
                   uint16_t in_port, struct flow *);
 void flow_zero_wildcards(struct flow *, const struct flow_wildcards *);
 void flow_get_metadata(const struct flow *, struct flow_metadata *);
index 0e1788c..552de04 100644 (file)
@@ -791,7 +791,7 @@ jsonrpc_session_open(const char *name)
  * On the assumption that such connections are likely to be short-lived
  * (e.g. from ovs-vsctl), informational logging for them is suppressed. */
 struct jsonrpc_session *
-jsonrpc_session_open_unreliably(struct jsonrpc *jsonrpc)
+jsonrpc_session_open_unreliably(struct jsonrpc *jsonrpc, uint8_t dscp)
 {
     struct jsonrpc_session *s;
 
@@ -801,7 +801,7 @@ jsonrpc_session_open_unreliably(struct jsonrpc *jsonrpc)
     reconnect_set_name(s->reconnect, jsonrpc_get_name(jsonrpc));
     reconnect_set_max_tries(s->reconnect, 0);
     reconnect_connected(s->reconnect, time_msec());
-    s->dscp = 0;
+    s->dscp = dscp;
     s->rpc = jsonrpc;
     s->stream = NULL;
     s->pstream = NULL;
@@ -1093,6 +1093,20 @@ jsonrpc_session_set_dscp(struct jsonrpc_session *s,
                          uint8_t dscp)
 {
     if (s->dscp != dscp) {
+        if (s->pstream) {
+            int error;
+
+            error = pstream_set_dscp(s->pstream, dscp);
+            if (error) {
+                VLOG_ERR("%s: failed set_dscp %s",
+                         reconnect_get_name(s->reconnect), strerror(error));
+            }
+            /*
+             * TODO:XXX race window between setting dscp to listening socket
+             * and accepting socket. accepted socket may have old dscp value.
+             * Ignore this race window for now.
+             */
+        }
         s->dscp = dscp;
         jsonrpc_session_force_reconnect(s);
     }
index 44ae06f..b5acf89 100644 (file)
@@ -99,7 +99,8 @@ struct json *jsonrpc_msg_to_json(struct jsonrpc_msg *);
 /* A JSON-RPC session with reconnection. */
 
 struct jsonrpc_session *jsonrpc_session_open(const char *name);
-struct jsonrpc_session *jsonrpc_session_open_unreliably(struct jsonrpc *);
+struct jsonrpc_session *jsonrpc_session_open_unreliably(struct jsonrpc *,
+                                                        uint8_t);
 void jsonrpc_session_close(struct jsonrpc_session *);
 
 void jsonrpc_session_run(struct jsonrpc_session *);
index dc19aa5..7a60f3c 100644 (file)
@@ -535,7 +535,8 @@ process_packet_in(struct lswitch *sw, const struct ofp_header *oh)
 
     /* Extract flow data from 'opi' into 'flow'. */
     ofpbuf_use_const(&pkt, pi.packet, pi.packet_len);
-    flow_extract(&pkt, 0, pi.fmd.tun_id, pi.fmd.in_port, &flow);
+    flow_extract(&pkt, 0, NULL, pi.fmd.in_port, &flow);
+    flow.tunnel.tun_id = pi.fmd.tun_id;
 
     /* Choose output port. */
     out_port = lswitch_choose_destination(sw, &flow);
index 69129d4..6a4fec7 100644 (file)
 #include "byte-order.h"
 #include "dynamic-string.h"
 #include "packets.h"
+#include "vlog.h"
+
+VLOG_DEFINE_THIS_MODULE(match);
+
 
 /* Converts the flow in 'flow' into a match in 'match', with the given
  * 'wildcards'. */
@@ -33,12 +37,94 @@ match_init(struct match *match,
     match_zero_wildcarded_fields(match);
 }
 
+/* Converts a flow into a match.  It sets the wildcard masks based on
+ * the packet contents.  It will not set the mask for fields that do not
+ * make sense for the packet type. */
+void
+match_wc_init(struct match *match, const struct flow *flow)
+{
+    struct flow_wildcards *wc;
+    int i;
+
+    match->flow = *flow;
+    wc = &match->wc;
+    memset(&wc->masks, 0x0, sizeof wc->masks);
+
+    memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);
+
+    if (flow->nw_proto) {
+        memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
+    }
+
+    for (i = 0; i < FLOW_N_REGS; i++) {
+        if (flow->regs[i]) {
+            memset(&wc->masks.regs[i], 0xff, sizeof wc->masks.regs[i]);
+        }
+    }
+
+    if (flow->tunnel.ip_dst || flow->tunnel.tun_id) {
+        memset(&wc->masks.tunnel.tun_id, 0xff, sizeof wc->masks.tunnel.tun_id);
+        memset(&wc->masks.tunnel.ip_src, 0xff, sizeof wc->masks.tunnel.ip_src);
+        memset(&wc->masks.tunnel.ip_dst, 0xff, sizeof wc->masks.tunnel.ip_dst);
+        memset(&wc->masks.tunnel.flags, 0xff, sizeof wc->masks.tunnel.flags);
+        memset(&wc->masks.tunnel.ip_tos, 0xff, sizeof wc->masks.tunnel.ip_tos);
+        memset(&wc->masks.tunnel.ip_ttl, 0xff, sizeof wc->masks.tunnel.ip_ttl);
+    }
+    memset(&wc->masks.metadata, 0xff, sizeof wc->masks.metadata);
+    memset(&wc->masks.in_port, 0xff, sizeof wc->masks.in_port);
+    memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci);
+    memset(&wc->masks.dl_src, 0xff, sizeof wc->masks.dl_src);
+    memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
+
+    if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
+        memset(&wc->masks.ipv6_src, 0xff, sizeof wc->masks.ipv6_src);
+        memset(&wc->masks.ipv6_dst, 0xff, sizeof wc->masks.ipv6_dst);
+        memset(&wc->masks.ipv6_label, 0xff, sizeof wc->masks.ipv6_label);
+    } else if (flow->dl_type == htons(ETH_TYPE_IP) ||
+               (flow->dl_type == htons(ETH_TYPE_ARP))) {
+        memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
+        memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst);
+    }
+
+    if (flow->dl_type == htons(ETH_TYPE_ARP)) {
+        memset(&wc->masks.arp_sha, 0xff, sizeof wc->masks.arp_sha);
+        memset(&wc->masks.arp_tha, 0xff, sizeof wc->masks.arp_tha);
+    }
+
+    if (flow->dl_type == htons(ETH_TYPE_IPV6) ||
+        flow->dl_type == htons(ETH_TYPE_IP)) {
+        memset(&wc->masks.nw_tos, 0xff, sizeof wc->masks.nw_tos);
+        memset(&wc->masks.nw_ttl, 0xff, sizeof wc->masks.nw_ttl);
+    }
+
+    if (flow->nw_frag) {
+        memset(&wc->masks.nw_frag, 0xff, sizeof wc->masks.nw_frag);
+    }
+
+    if (flow->nw_proto == IPPROTO_ICMP || flow->nw_proto == IPPROTO_ICMPV6 ||
+        (flow->tp_src || flow->tp_dst)) {
+        memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
+        memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst);
+    }
+
+    if (flow->nw_proto == IPPROTO_ICMPV6) {
+        memset(&wc->masks.arp_sha, 0xff, sizeof wc->masks.arp_sha);
+        memset(&wc->masks.arp_tha, 0xff, sizeof wc->masks.arp_tha);
+    }
+
+    return;
+}
+
 /* Converts the flow in 'flow' into an exact-match match in 'match'. */
 void
 match_init_exact(struct match *match, const struct flow *flow)
 {
+    ovs_be64 tun_id = flow->tunnel.tun_id;
+
     match->flow = *flow;
     match->flow.skb_priority = 0;
+    memset(&match->flow.tunnel, 0, sizeof match->flow.tunnel);
+    match->flow.tunnel.tun_id = tun_id;
     flow_wildcards_init_exact(&match->wc);
 }
 
@@ -102,8 +188,8 @@ match_set_tun_id(struct match *match, ovs_be64 tun_id)
 void
 match_set_tun_id_masked(struct match *match, ovs_be64 tun_id, ovs_be64 mask)
 {
-    match->wc.masks.tun_id = mask;
-    match->flow.tun_id = tun_id & mask;
+    match->wc.masks.tunnel.tun_id = mask;
+    match->flow.tunnel.tun_id = tun_id & mask;
 }
 
 void
@@ -626,15 +712,16 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
             break;
         }
     }
-    switch (wc->masks.tun_id) {
+    switch (wc->masks.tunnel.tun_id) {
     case 0:
         break;
     case CONSTANT_HTONLL(UINT64_MAX):
-        ds_put_format(s, "tun_id=%#"PRIx64",", ntohll(f->tun_id));
+        ds_put_format(s, "tun_id=%#"PRIx64",", ntohll(f->tunnel.tun_id));
         break;
     default:
         ds_put_format(s, "tun_id=%#"PRIx64"/%#"PRIx64",",
-                      ntohll(f->tun_id), ntohll(wc->masks.tun_id));
+                      ntohll(f->tunnel.tun_id),
+                      ntohll(wc->masks.tunnel.tun_id));
         break;
     }
     switch (wc->masks.metadata) {
@@ -693,6 +780,9 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
                               ntohl(wc->masks.ipv6_label));
             }
         }
+    } else if (f->dl_type == htons(ETH_TYPE_ARP)) {
+        format_ip_netmask(s, "arp_spa", f->nw_src, wc->masks.nw_src);
+        format_ip_netmask(s, "arp_tpa", f->nw_dst, wc->masks.nw_dst);
     } else {
         format_ip_netmask(s, "nw_src", f->nw_src, wc->masks.nw_src);
         format_ip_netmask(s, "nw_dst", f->nw_dst, wc->masks.nw_dst);
@@ -735,10 +825,12 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
                       f->nw_frag & FLOW_NW_FRAG_LATER ? "later" : "not_later");
         break;
     }
-    if (f->nw_proto == IPPROTO_ICMP) {
+    if (f->dl_type == htons(ETH_TYPE_IP) &&
+        f->nw_proto == IPPROTO_ICMP) {
         format_be16_masked(s, "icmp_type", f->tp_src, wc->masks.tp_src);
         format_be16_masked(s, "icmp_code", f->tp_dst, wc->masks.tp_dst);
-    } else if (f->nw_proto == IPPROTO_ICMPV6) {
+    } else if (f->dl_type == htons(ETH_TYPE_IPV6) &&
+               f->nw_proto == IPPROTO_ICMPV6) {
         format_be16_masked(s, "icmp_type", f->tp_src, wc->masks.tp_src);
         format_be16_masked(s, "icmp_code", f->tp_dst, wc->masks.tp_dst);
         format_ipv6_netmask(s, "nd_target", &f->nd_target,
index 2d05819..28433b9 100644 (file)
@@ -36,6 +36,7 @@ struct match {
 
 void match_init(struct match *,
                 const struct flow *, const struct flow_wildcards *);
+void match_wc_init(struct match *match, const struct flow *flow);
 void match_init_catchall(struct match *);
 void match_init_exact(struct match *, const struct flow *);
 
index 38c9a27..4fa05ae 100644 (file)
@@ -574,7 +574,7 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
 {
     switch (mf->id) {
     case MFF_TUN_ID:
-        return !wc->masks.tun_id;
+        return !wc->masks.tunnel.tun_id;
     case MFF_METADATA:
         return !wc->masks.metadata;
     case MFF_IN_PORT:
@@ -671,7 +671,7 @@ mf_get_mask(const struct mf_field *mf, const struct flow_wildcards *wc,
 {
     switch (mf->id) {
     case MFF_TUN_ID:
-        mask->be64 = wc->masks.tun_id;
+        mask->be64 = wc->masks.tunnel.tun_id;
         break;
     case MFF_METADATA:
         mask->be64 = wc->masks.metadata;
@@ -952,7 +952,7 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
 {
     switch (mf->id) {
     case MFF_TUN_ID:
-        value->be64 = flow->tun_id;
+        value->be64 = flow->tunnel.tun_id;
         break;
     case MFF_METADATA:
         value->be64 = flow->metadata;
@@ -1238,7 +1238,7 @@ mf_set_flow_value(const struct mf_field *mf,
 {
     switch (mf->id) {
     case MFF_TUN_ID:
-        flow->tun_id = value->be64;
+        flow->tunnel.tun_id = value->be64;
         break;
     case MFF_METADATA:
         flow->metadata = value->be64;
@@ -1941,8 +1941,7 @@ mf_from_ofp_port_string(const struct mf_field *mf, const char *s,
     uint16_t port;
 
     assert(mf->n_bytes == sizeof(ovs_be16));
-    port = ofputil_port_from_string(s);
-    if (port) {
+    if (ofputil_port_from_string(s, &port)) {
         *valuep = htons(port);
         *maskp = htons(UINT16_MAX);
         return NULL;
index db5c3db..4168959 100644 (file)
@@ -162,6 +162,14 @@ netdev_vport_get_netdev_type(const struct dpif_linux_vport *vport)
         return (nl_attr_get_u32(a[OVS_TUNNEL_ATTR_FLAGS]) & TNL_F_IPSEC
                 ? "ipsec_gre" : "gre");
 
+    case OVS_VPORT_TYPE_GRE64:
+        if (tnl_port_config_from_nlattr(vport->options, vport->options_len,
+                                        a)) {
+            break;
+        }
+        return (nl_attr_get_u32(a[OVS_TUNNEL_ATTR_FLAGS]) & TNL_F_IPSEC
+                ? "ipsec_gre64" : "gre64");
+
     case OVS_VPORT_TYPE_CAPWAP:
         return "capwap";
 
@@ -582,10 +590,10 @@ parse_tunnel_config(const char *name, const char *type,
     ovs_be32 saddr = htonl(0);
     uint32_t flags;
 
-    flags = TNL_F_DF_DEFAULT | TNL_F_PMTUD | TNL_F_HDR_CACHE;
-    if (!strcmp(type, "gre")) {
+    flags = TNL_F_DF_DEFAULT | TNL_F_HDR_CACHE;
+    if (!strcmp(type, "gre") || !strcmp(type, "gre64")) {
         is_gre = true;
-    } else if (!strcmp(type, "ipsec_gre")) {
+    } else if (!strcmp(type, "ipsec_gre") || !strcmp(type, "ipsec_gre64")) {
         is_gre = true;
         is_ipsec = true;
         flags |= TNL_F_IPSEC;
@@ -639,8 +647,8 @@ parse_tunnel_config(const char *name, const char *type,
                 flags &= ~TNL_F_DF_DEFAULT;
             }
         } else if (!strcmp(node->key, "pmtud")) {
-            if (!strcmp(node->value, "false")) {
-                flags &= ~TNL_F_PMTUD;
+            if (!strcmp(node->value, "true")) {
+                flags |= TNL_F_PMTUD;
             }
         } else if (!strcmp(node->key, "header_cache")) {
             if (!strcmp(node->value, "false")) {
@@ -814,10 +822,10 @@ unparse_tunnel_config(const char *name OVS_UNUSED, const char *type OVS_UNUSED,
     }
 
     if (flags & TNL_F_TTL_INHERIT) {
-        smap_add(args, "tos", "inherit");
+        smap_add(args, "ttl", "inherit");
     } else if (a[OVS_TUNNEL_ATTR_TTL]) {
         int ttl = nl_attr_get_u8(a[OVS_TUNNEL_ATTR_TTL]);
-        smap_add_format(args, "tos", "%d", ttl);
+        smap_add_format(args, "ttl", "%d", ttl);
     }
 
     if (flags & TNL_F_TOS_INHERIT) {
@@ -836,8 +844,8 @@ unparse_tunnel_config(const char *name OVS_UNUSED, const char *type OVS_UNUSED,
     if (!(flags & TNL_F_DF_DEFAULT)) {
         smap_add(args, "df_default", "false");
     }
-    if (!(flags & TNL_F_PMTUD)) {
-        smap_add(args, "pmtud", "false");
+    if (flags & TNL_F_PMTUD) {
+        smap_add(args, "pmtud", "true");
     }
 
     return 0;
@@ -970,6 +978,14 @@ netdev_vport_register(void)
           { "ipsec_gre", VPORT_FUNCTIONS(netdev_vport_get_drv_info) },
           parse_tunnel_config, unparse_tunnel_config },
 
+        { OVS_VPORT_TYPE_GRE64,
+          { "gre64", VPORT_FUNCTIONS(netdev_vport_get_drv_info) },
+          parse_tunnel_config, unparse_tunnel_config },
+
+        { OVS_VPORT_TYPE_GRE64,
+          { "ipsec_gre64", VPORT_FUNCTIONS(netdev_vport_get_drv_info) },
+          parse_tunnel_config, unparse_tunnel_config },
+
         { OVS_VPORT_TYPE_CAPWAP,
           { "capwap", VPORT_FUNCTIONS(netdev_vport_get_drv_info) },
           parse_tunnel_config, unparse_tunnel_config },
index f86068a..cf1d691 100644 (file)
@@ -75,7 +75,7 @@ netdev_initialize(void)
 
         fatal_signal_add_hook(close_all_netdevs, NULL, NULL, true);
 
-#ifdef HAVE_NETLINK
+#ifdef LINUX_DATAPATH
         netdev_register_provider(&netdev_linux_class);
         netdev_register_provider(&netdev_internal_class);
         netdev_register_provider(&netdev_tap_class);
index 6ea0642..9918994 100644 (file)
@@ -643,7 +643,8 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match *match,
     }
 
     /* Tunnel ID. */
-    nxm_put_64m(b, NXM_NX_TUN_ID, flow->tun_id, match->wc.masks.tun_id);
+    nxm_put_64m(b, NXM_NX_TUN_ID, flow->tunnel.tun_id,
+                match->wc.masks.tunnel.tun_id);
 
     /* Registers. */
     for (i = 0; i < FLOW_N_REGS; i++) {
@@ -1119,12 +1120,7 @@ nxm_reg_load_from_openflow12_set_field(
         return OFPERR_OFPBAC_BAD_ARGUMENT;
     }
     load = ofpact_put_REG_LOAD(ofpacts);
-    load->ofpact.compat = OFPUTIL_OFPAT12_SET_FIELD;
-    load->dst.field = mf;
-    load->dst.ofs = 0;
-    load->dst.n_bits = mf->n_bits;
-    bitwise_copy(oasf + 1, mf->n_bytes, load->dst.ofs,
-                 &load->subvalue, sizeof load->subvalue, 0, mf->n_bits);
+    ofpact_set_field_init(load, mf, oasf + 1);
 
     return nxm_reg_load_check(load, NULL);
 }
index 901dac3..9ed17ed 100644 (file)
@@ -93,6 +93,8 @@ ovs_key_attr_to_string(enum ovs_key_attr attr)
     case OVS_KEY_ATTR_UNSPEC: return "unspec";
     case OVS_KEY_ATTR_ENCAP: return "encap";
     case OVS_KEY_ATTR_PRIORITY: return "priority";
+    case OVS_KEY_ATTR_TUN_ID: return "tun_id";
+    case OVS_KEY_ATTR_IPV4_TUNNEL: return "ipv4_tunnel";
     case OVS_KEY_ATTR_IN_PORT: return "in_port";
     case OVS_KEY_ATTR_ETHERNET: return "eth";
     case OVS_KEY_ATTR_VLAN: return "vlan";
@@ -105,7 +107,6 @@ ovs_key_attr_to_string(enum ovs_key_attr attr)
     case OVS_KEY_ATTR_ICMPV6: return "icmpv6";
     case OVS_KEY_ATTR_ARP: return "arp";
     case OVS_KEY_ATTR_ND: return "nd";
-    case OVS_KEY_ATTR_TUN_ID: return "tun_id";
 
     case __OVS_KEY_ATTR_MAX:
     default:
@@ -602,6 +603,7 @@ odp_flow_key_attr_len(uint16_t type)
     case OVS_KEY_ATTR_ENCAP: return -2;
     case OVS_KEY_ATTR_PRIORITY: return 4;
     case OVS_KEY_ATTR_TUN_ID: return 8;
+    case OVS_KEY_ATTR_IPV4_TUNNEL: return sizeof(struct ovs_key_ipv4_tunnel);
     case OVS_KEY_ATTR_IN_PORT: return 4;
     case OVS_KEY_ATTR_ETHERNET: return sizeof(struct ovs_key_ethernet);
     case OVS_KEY_ATTR_VLAN: return sizeof(ovs_be16);
@@ -668,6 +670,7 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds)
     const struct ovs_key_icmpv6 *icmpv6_key;
     const struct ovs_key_arp *arp_key;
     const struct ovs_key_nd *nd_key;
+    const struct ovs_key_ipv4_tunnel *ipv4_tun_key;
     enum ovs_key_attr attr = nl_attr_type(a);
     int expected_len;
 
@@ -698,6 +701,16 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds)
         ds_put_format(ds, "(%#"PRIx64")", ntohll(nl_attr_get_be64(a)));
         break;
 
+    case OVS_KEY_ATTR_IPV4_TUNNEL:
+        ipv4_tun_key = nl_attr_get(a);
+        ds_put_format(ds, "(tun_id=0x%"PRIx64",flags=0x%"PRIx32
+                      ",src="IP_FMT",dst="IP_FMT",tos=0x%"PRIx8",ttl=%"PRIu8")",
+                      ntohll(ipv4_tun_key->tun_id), ipv4_tun_key->tun_flags,
+                      IP_ARGS(&ipv4_tun_key->ipv4_src),
+                      IP_ARGS(&ipv4_tun_key->ipv4_dst),
+                      ipv4_tun_key->ipv4_tos, ipv4_tun_key->ipv4_ttl);
+        break;
+
     case OVS_KEY_ATTR_IN_PORT:
         ds_put_format(ds, "(%"PRIu32")", nl_attr_get_u32(a));
         break;
@@ -1260,8 +1273,8 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow)
         nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, flow->skb_priority);
     }
 
-    if (flow->tun_id != htonll(0)) {
-        nl_msg_put_be64(buf, OVS_KEY_ATTR_TUN_ID, flow->tun_id);
+    if (flow->tunnel.tun_id != htonll(0)) {
+        nl_msg_put_be64(buf, OVS_KEY_ATTR_TUN_ID, flow->tunnel.tun_id);
     }
 
     if (flow->in_port != OFPP_NONE && flow->in_port != OFPP_CONTROLLER) {
@@ -1753,7 +1766,7 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t key_len,
     }
 
     if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_TUN_ID)) {
-        flow->tun_id = nl_attr_get_be64(attrs[OVS_KEY_ATTR_TUN_ID]);
+        flow->tunnel.tun_id = nl_attr_get_be64(attrs[OVS_KEY_ATTR_TUN_ID]);
         expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_TUN_ID;
     }
 
@@ -1848,13 +1861,13 @@ static void
 commit_set_tun_id_action(const struct flow *flow, struct flow *base,
                          struct ofpbuf *odp_actions)
 {
-    if (base->tun_id == flow->tun_id) {
+    if (base->tunnel.tun_id == flow->tunnel.tun_id) {
         return;
     }
-    base->tun_id = flow->tun_id;
+    base->tunnel.tun_id = flow->tunnel.tun_id;
 
     commit_set_action(odp_actions, OVS_KEY_ATTR_TUN_ID,
-                      &base->tun_id, sizeof(base->tun_id));
+                      &base->tunnel.tun_id, sizeof(base->tunnel.tun_id));
 }
 
 static void
index 16f2b15..57073ba 100644 (file)
@@ -80,6 +80,7 @@ int odp_actions_from_string(const char *, const struct simap *port_names,
  *                         ------  ---  ------  -----
  *  OVS_KEY_ATTR_PRIORITY      4    --     4      8
  *  OVS_KEY_ATTR_TUN_ID        8    --     4     12
+ *  OVS_KEY_ATTR_IPV4_TUNNEL  24    --     4     28
  *  OVS_KEY_ATTR_IN_PORT       4    --     4      8
  *  OVS_KEY_ATTR_ETHERNET     12    --     4     16
  *  OVS_KEY_ATTR_ETHERTYPE     2     2     4      8  (outer VLAN ethertype)
@@ -90,7 +91,7 @@ int odp_actions_from_string(const char *, const struct simap *port_names,
  *  OVS_KEY_ATTR_ICMPV6        2     2     4      8
  *  OVS_KEY_ATTR_ND           28    --     4     32
  *  -------------------------------------------------
- *  total                                       156
+ *  total                                       184
  *
  * We include some slack space in case the calculation isn't quite right or we
  * add another field and forget to adjust this value.
index 19ed7a0..170e796 100644 (file)
@@ -135,6 +135,23 @@ controller_from_openflow(const struct nx_action_controller *nac,
     oc->reason = nac->reason;
 }
 
+static enum ofperr
+metadata_from_nxast(const struct nx_action_write_metadata *nawm,
+                    struct ofpbuf *out)
+{
+    struct ofpact_metadata *om;
+
+    if (!is_all_zeros(nawm->zeros, sizeof nawm->zeros)) {
+        return OFPERR_NXBRC_MUST_BE_ZERO;
+    }
+
+    om = ofpact_put_WRITE_METADATA(out);
+    om->metadata = nawm->metadata;
+    om->mask = nawm->mask;
+
+    return 0;
+}
+
 static void
 note_from_openflow(const struct nx_action_note *nan, struct ofpbuf *out)
 {
@@ -149,14 +166,14 @@ note_from_openflow(const struct nx_action_note *nan, struct ofpbuf *out)
 }
 
 static enum ofperr
-dec_ttl_from_openflow(struct ofpbuf *out)
+dec_ttl_from_openflow(struct ofpbuf *out, enum ofputil_action_code compat)
 {
     uint16_t id = 0;
     struct ofpact_cnt_ids *ids;
     enum ofperr error = 0;
 
     ids = ofpact_put_DEC_TTL(out);
-    ids->ofpact.compat = OFPUTIL_NXAST_DEC_TTL;
+    ids->ofpact.compat = compat;
     ids->n_controllers = 1;
     ofpbuf_put(out, &id, sizeof id);
     ids = out->l2;
@@ -276,14 +293,14 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
     const struct nx_action_set_queue *nasq;
     const struct nx_action_note *nan;
     const struct nx_action_set_tunnel64 *nast64;
+    const struct nx_action_write_metadata *nawm;
     struct ofpact_tunnel *tunnel;
     enum ofperr error = 0;
 
     switch (code) {
     case OFPUTIL_ACTION_INVALID:
 #define OFPAT10_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
-#define OFPAT11_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
-#define OFPAT12_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
+#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
 #include "ofp-util.def"
         NOT_REACHED();
 
@@ -298,6 +315,11 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
         tunnel->tun_id = ntohl(nast->tun_id);
         break;
 
+    case OFPUTIL_NXAST_WRITE_METADATA:
+        nawm = (const struct nx_action_write_metadata *) a;
+        error = metadata_from_nxast(nawm, out);
+        break;
+
     case OFPUTIL_NXAST_SET_QUEUE:
         nasq = (const struct nx_action_set_queue *) a;
         ofpact_put_SET_QUEUE(out)->queue_id = ntohl(nasq->queue_id);
@@ -363,7 +385,7 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
         break;
 
     case OFPUTIL_NXAST_DEC_TTL:
-        error = dec_ttl_from_openflow(out);
+        error = dec_ttl_from_openflow(out, code);
         break;
 
     case OFPUTIL_NXAST_DEC_TTL_CNT_IDS:
@@ -397,8 +419,7 @@ ofpact_from_openflow10(const union ofp_action *a, struct ofpbuf *out)
 
     switch (code) {
     case OFPUTIL_ACTION_INVALID:
-#define OFPAT11_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
-#define OFPAT12_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
+#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
 #include "ofp-util.def"
         NOT_REACHED();
 
@@ -569,6 +590,12 @@ ofpacts_pull_actions(struct ofpbuf *openflow, unsigned int actions_len,
     }
 
     error = translate(actions, actions_len / OFP_ACTION_ALIGN, ofpacts);
+    if (error) {
+        ofpbuf_clear(ofpacts);
+        return error;
+    }
+
+    error = ofpacts_verify(ofpacts->data, ofpacts->size);
     if (error) {
         ofpbuf_clear(ofpacts);
     }
@@ -609,19 +636,24 @@ static enum ofperr
 decode_openflow11_action(const union ofp_action *a,
                          enum ofputil_action_code *code)
 {
+    uint16_t len;
+
     switch (a->type) {
     case CONSTANT_HTONS(OFPAT11_EXPERIMENTER):
         return decode_nxast_action(a, code);
 
-#define OFPAT11_ACTION(ENUM, STRUCT, NAME)                          \
-        case CONSTANT_HTONS(ENUM):                                  \
-            if (a->header.len == htons(sizeof(struct STRUCT))) {    \
-                *code = OFPUTIL_##ENUM;                             \
-                return 0;                                           \
-            } else {                                                \
-                return OFPERR_OFPBAC_BAD_LEN;                       \
-            }                                                       \
-            break;
+#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)  \
+        case CONSTANT_HTONS(ENUM):                      \
+            len = ntohs(a->header.len);                 \
+            if (EXTENSIBLE                              \
+                ? len >= sizeof(struct STRUCT)          \
+                : len == sizeof(struct STRUCT)) {       \
+                *code = OFPUTIL_##ENUM;                 \
+                return 0;                               \
+            } else {                                    \
+                return OFPERR_OFPBAC_BAD_LEN;           \
+            }                                           \
+            NOT_REACHED();
 #include "ofp-util.def"
 
     default:
@@ -661,7 +693,6 @@ ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out)
     switch (code) {
     case OFPUTIL_ACTION_INVALID:
 #define OFPAT10_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
-#define OFPAT12_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
 #include "ofp-util.def"
         NOT_REACHED();
 
@@ -683,6 +714,19 @@ ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out)
         ofpact_put_SET_VLAN_PCP(out)->vlan_pcp = a->vlan_pcp.vlan_pcp;
         break;
 
+    case OFPUTIL_OFPAT11_PUSH_VLAN:
+        if (((const struct ofp11_action_push *)a)->ethertype !=
+            htons(ETH_TYPE_VLAN_8021Q)) {
+            /* TODO:XXX 802.1AD(QinQ) isn't supported at the moment */
+            return OFPERR_OFPET_BAD_ACTION;
+        }
+        ofpact_put_PUSH_VLAN(out);
+        break;
+
+    case OFPUTIL_OFPAT11_POP_VLAN:
+        ofpact_put_STRIP_VLAN(out);
+        break;
+
     case OFPUTIL_OFPAT11_SET_DL_SRC:
         memcpy(ofpact_put_SET_ETH_SRC(out)->mac,
                ((const struct ofp_action_dl_addr *) a)->dl_addr, ETH_ADDR_LEN);
@@ -693,6 +737,10 @@ ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out)
                ((const struct ofp_action_dl_addr *) a)->dl_addr, ETH_ADDR_LEN);
         break;
 
+    case OFPUTIL_OFPAT11_DEC_NW_TTL:
+        dec_ttl_from_openflow(out, code);
+        break;
+
     case OFPUTIL_OFPAT11_SET_NW_SRC:
         ofpact_put_SET_IPV4_SRC(out)->ipv4 = a->nw_addr.nw_addr;
         break;
@@ -716,6 +764,10 @@ ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out)
         ofpact_put_SET_L4_DST_PORT(out)->port = ntohs(a->tp_port.tp_port);
         break;
 
+    case OFPUTIL_OFPAT12_SET_FIELD:
+        return nxm_reg_load_from_openflow12_set_field(
+            (const struct ofp12_action_set_field *)a, out);
+
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
 #include "ofp-util.def"
         return ofpact_from_nxast(a, code, out);
@@ -952,15 +1004,39 @@ ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
             goto exit;
         }
     }
+    if (insts[OVSINST_OFPIT11_CLEAR_ACTIONS]) {
+        instruction_get_OFPIT11_CLEAR_ACTIONS(
+            insts[OVSINST_OFPIT11_CLEAR_ACTIONS]);
+        ofpact_put_CLEAR_ACTIONS(ofpacts);
+    }
+    /* TODO:XXX Write-Actions */
+    if (insts[OVSINST_OFPIT11_WRITE_METADATA]) {
+        const struct ofp11_instruction_write_metadata *oiwm;
+        struct ofpact_metadata *om;
 
-    if (insts[OVSINST_OFPIT11_GOTO_TABLE] ||
-        insts[OVSINST_OFPIT11_WRITE_METADATA] ||
-        insts[OVSINST_OFPIT11_WRITE_ACTIONS] ||
-        insts[OVSINST_OFPIT11_CLEAR_ACTIONS]) {
+        oiwm = (const struct ofp11_instruction_write_metadata *)
+            insts[OVSINST_OFPIT11_WRITE_METADATA];
+
+        om = ofpact_put_WRITE_METADATA(ofpacts);
+        om->metadata = oiwm->metadata;
+        om->mask = oiwm->metadata_mask;
+    }
+    if (insts[OVSINST_OFPIT11_GOTO_TABLE]) {
+        const struct ofp11_instruction_goto_table *oigt;
+        struct ofpact_goto_table *ogt;
+
+        oigt = instruction_get_OFPIT11_GOTO_TABLE(
+            insts[OVSINST_OFPIT11_GOTO_TABLE]);
+        ogt = ofpact_put_GOTO_TABLE(ofpacts);
+        ogt->table_id = oigt->table_id;
+    }
+
+    if (insts[OVSINST_OFPIT11_WRITE_ACTIONS]) {
         error = OFPERR_OFPBIC_UNSUP_INST;
         goto exit;
     }
 
+    error = ofpacts_verify(ofpacts->data, ofpacts->size);
 exit:
     if (error) {
         ofpbuf_clear(ofpacts);
@@ -998,6 +1074,7 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports)
     case OFPACT_SET_VLAN_VID:
     case OFPACT_SET_VLAN_PCP:
     case OFPACT_STRIP_VLAN:
+    case OFPACT_PUSH_VLAN:
     case OFPACT_SET_ETH_SRC:
     case OFPACT_SET_ETH_DST:
     case OFPACT_SET_IPV4_SRC:
@@ -1034,6 +1111,11 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports)
     case OFPACT_EXIT:
         return 0;
 
+    case OFPACT_CLEAR_ACTIONS:
+    case OFPACT_WRITE_METADATA:
+    case OFPACT_GOTO_TABLE:
+        return 0;
+
     default:
         NOT_REACHED();
     }
@@ -1057,6 +1139,35 @@ ofpacts_check(const struct ofpact ofpacts[], size_t ofpacts_len,
 
     return 0;
 }
+
+/* Verifies that the 'ofpacts_len' bytes of actions in 'ofpacts' are
+ * in the appropriate order as defined by the OpenFlow spec. */
+enum ofperr
+ofpacts_verify(const struct ofpact ofpacts[], size_t ofpacts_len)
+{
+    const struct ofpact *a;
+    const struct ofpact_metadata *om = NULL;
+
+    OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
+        if (om) {
+            if (a->type == OFPACT_WRITE_METADATA) {
+                VLOG_WARN("duplicate write_metadata instruction specified");
+                /* should be OFPERR_OFPET_BAD_ACTION? */
+                return OFPERR_OFPBAC_UNSUPPORTED_ORDER;
+            } else {
+                VLOG_WARN("write_metadata instruction must be specified after "
+                          "other instructions/actions");
+                return OFPERR_OFPBAC_UNSUPPORTED_ORDER;
+            }
+        }
+
+        if (a->type == OFPACT_WRITE_METADATA) {
+            om = (const struct ofpact_metadata *) a;
+        }
+    }
+
+    return 0;
+}
 \f
 /* Converting ofpacts to Nicira OpenFlow extensions. */
 
@@ -1102,6 +1213,17 @@ ofpact_set_tunnel_to_nxast(const struct ofpact_tunnel *tunnel,
     }
 }
 
+static void
+ofpact_write_metadata_to_nxast(const struct ofpact_metadata *om,
+                               struct ofpbuf *out)
+{
+    struct nx_action_write_metadata *nawm;
+
+    nawm = ofputil_put_NXAST_WRITE_METADATA(out);
+    nawm->metadata = om->metadata;
+    nawm->mask = om->mask;
+}
+
 static void
 ofpact_note_to_nxast(const struct ofpact_note *note, struct ofpbuf *out)
 {
@@ -1200,6 +1322,10 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
         ofpact_set_tunnel_to_nxast(ofpact_get_SET_TUNNEL(a), out);
         break;
 
+    case OFPACT_WRITE_METADATA:
+        ofpact_write_metadata_to_nxast(ofpact_get_WRITE_METADATA(a), out);
+        break;
+
     case OFPACT_SET_QUEUE:
         ofputil_put_NXAST_SET_QUEUE(out)->queue_id
             = htonl(ofpact_get_SET_QUEUE(a)->queue_id);
@@ -1242,6 +1368,7 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_SET_VLAN_VID:
     case OFPACT_SET_VLAN_PCP:
     case OFPACT_STRIP_VLAN:
+    case OFPACT_PUSH_VLAN:
     case OFPACT_SET_ETH_SRC:
     case OFPACT_SET_ETH_DST:
     case OFPACT_SET_IPV4_SRC:
@@ -1249,6 +1376,8 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_SET_IPV4_DSCP:
     case OFPACT_SET_L4_SRC_PORT:
     case OFPACT_SET_L4_DST_PORT:
+    case OFPACT_CLEAR_ACTIONS:
+    case OFPACT_GOTO_TABLE:
         NOT_REACHED();
     }
 }
@@ -1338,6 +1467,12 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out)
             = htons(ofpact_get_SET_L4_DST_PORT(a)->port);
         break;
 
+    case OFPACT_PUSH_VLAN:
+    case OFPACT_CLEAR_ACTIONS:
+    case OFPACT_GOTO_TABLE:
+        /* TODO:XXX */
+        break;
+
     case OFPACT_CONTROLLER:
     case OFPACT_OUTPUT_REG:
     case OFPACT_BUNDLE:
@@ -1345,6 +1480,7 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_REG_LOAD:
     case OFPACT_DEC_TTL:
     case OFPACT_SET_TUNNEL:
+    case OFPACT_WRITE_METADATA:
     case OFPACT_SET_QUEUE:
     case OFPACT_POP_QUEUE:
     case OFPACT_FIN_TIMEOUT:
@@ -1386,6 +1522,19 @@ ofpact_output_to_openflow11(const struct ofpact_output *output,
     oao->max_len = htons(output->max_len);
 }
 
+static void
+ofpact_dec_ttl_to_openflow11(const struct ofpact_cnt_ids *dec_ttl,
+                             struct ofpbuf *out)
+{
+    if (dec_ttl->n_controllers == 1 && dec_ttl->cnt_ids[0] == 0
+        && (!dec_ttl->ofpact.compat ||
+            dec_ttl->ofpact.compat == OFPUTIL_OFPAT11_DEC_NW_TTL)) {
+        ofputil_put_OFPAT11_DEC_NW_TTL(out);
+    } else {
+        ofpact_dec_ttl_to_nxast(dec_ttl, out);
+    }
+}
+
 static void
 ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
 {
@@ -1408,7 +1557,13 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
         break;
 
     case OFPACT_STRIP_VLAN:
-        /* XXX */
+        ofputil_put_OFPAT11_POP_VLAN(out);
+        break;
+
+    case OFPACT_PUSH_VLAN:
+        /* TODO:XXX ETH_TYPE_VLAN_8021AD case */
+        ofputil_put_OFPAT11_PUSH_VLAN(out)->ethertype =
+            htons(ETH_TYPE_VLAN_8021Q);
         break;
 
     case OFPACT_SET_ETH_SRC:
@@ -1446,12 +1601,23 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
             = htons(ofpact_get_SET_L4_DST_PORT(a)->port);
         break;
 
+    case OFPACT_DEC_TTL:
+        ofpact_dec_ttl_to_openflow11(ofpact_get_DEC_TTL(a), out);
+        break;
+
+    case OFPACT_WRITE_METADATA:
+        /* OpenFlow 1.1 uses OFPIT_WRITE_METADATA to express this action. */
+        break;
+
+    case OFPACT_CLEAR_ACTIONS:
+    case OFPACT_GOTO_TABLE:
+        NOT_REACHED();
+
     case OFPACT_CONTROLLER:
     case OFPACT_OUTPUT_REG:
     case OFPACT_BUNDLE:
     case OFPACT_REG_MOVE:
     case OFPACT_REG_LOAD:
-    case OFPACT_DEC_TTL:
     case OFPACT_SET_TUNNEL:
     case OFPACT_SET_QUEUE:
     case OFPACT_POP_QUEUE:
@@ -1484,18 +1650,10 @@ ofpacts_put_openflow11_actions(const struct ofpact ofpacts[],
     return openflow->size - start_size;
 }
 
-void
-ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[],
-                                    size_t ofpacts_len,
-                                    struct ofpbuf *openflow)
+static void
+ofpacts_update_instruction_actions(struct ofpbuf *openflow, size_t ofs)
 {
     struct ofp11_instruction_actions *oia;
-    size_t ofs;
-
-    /* Put an OFPIT11_APPLY_ACTIONS instruction and fill it in. */
-    ofs = openflow->size;
-    instruction_put_OFPIT11_APPLY_ACTIONS(openflow);
-    ofpacts_put_openflow11_actions(ofpacts, ofpacts_len, openflow);
 
     /* Update the instruction's length (or, if it's empty, delete it). */
     oia = ofpbuf_at_assert(openflow, ofs, sizeof *oia);
@@ -1505,6 +1663,54 @@ ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[],
         openflow->size = ofs;
     }
 }
+
+void
+ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[],
+                                    size_t ofpacts_len,
+                                    struct ofpbuf *openflow)
+{
+    const struct ofpact *a;
+
+    OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
+        /* TODO:XXX Write-Actions */
+
+        if (a->type == OFPACT_CLEAR_ACTIONS) {
+            instruction_put_OFPIT11_CLEAR_ACTIONS(openflow);
+        } else if (a->type == OFPACT_GOTO_TABLE) {
+            struct ofp11_instruction_goto_table *oigt;
+
+            oigt = instruction_put_OFPIT11_GOTO_TABLE(openflow);
+            oigt->table_id = ofpact_get_GOTO_TABLE(a)->table_id;
+            memset(oigt->pad, 0, sizeof oigt->pad);
+        } else if (a->type == OFPACT_WRITE_METADATA) {
+            const struct ofpact_metadata *om;
+            struct ofp11_instruction_write_metadata *oiwm;
+
+            om = ofpact_get_WRITE_METADATA(a);
+            oiwm = instruction_put_OFPIT11_WRITE_METADATA(openflow);
+            oiwm->metadata = om->metadata;
+            oiwm->metadata_mask = om->mask;
+        } else if (!ofpact_is_instruction(a)) {
+            /* Apply-actions */
+            const size_t ofs = openflow->size;
+            const size_t ofpacts_len_left =
+                (uint8_t*)ofpact_end(ofpacts, ofpacts_len) - (uint8_t*)a;
+            const struct ofpact *action;
+            const struct ofpact *processed = a;
+
+            instruction_put_OFPIT11_APPLY_ACTIONS(openflow);
+            OFPACT_FOR_EACH(action, a, ofpacts_len_left) {
+                if (ofpact_is_instruction(action)) {
+                    break;
+                }
+                ofpact_to_openflow11(action, openflow);
+                processed = action;
+            }
+            ofpacts_update_instruction_actions(openflow, ofs);
+            a = processed;
+        }
+    }
+}
 \f
 /* Returns true if 'action' outputs to 'port', false otherwise. */
 static bool
@@ -1523,6 +1729,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port)
     case OFPACT_SET_VLAN_VID:
     case OFPACT_SET_VLAN_PCP:
     case OFPACT_STRIP_VLAN:
+    case OFPACT_PUSH_VLAN:
     case OFPACT_SET_ETH_SRC:
     case OFPACT_SET_ETH_DST:
     case OFPACT_SET_IPV4_SRC:
@@ -1534,6 +1741,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port)
     case OFPACT_REG_LOAD:
     case OFPACT_DEC_TTL:
     case OFPACT_SET_TUNNEL:
+    case OFPACT_WRITE_METADATA:
     case OFPACT_SET_QUEUE:
     case OFPACT_POP_QUEUE:
     case OFPACT_FIN_TIMEOUT:
@@ -1543,6 +1751,8 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port)
     case OFPACT_AUTOPATH:
     case OFPACT_NOTE:
     case OFPACT_EXIT:
+    case OFPACT_CLEAR_ACTIONS:
+    case OFPACT_GOTO_TABLE:
     default:
         return false;
     }
@@ -1631,6 +1841,7 @@ ofpact_format(const struct ofpact *a, struct ds *s)
     const struct ofpact_resubmit *resubmit;
     const struct ofpact_autopath *autopath;
     const struct ofpact_controller *controller;
+    const struct ofpact_metadata *metadata;
     const struct ofpact_tunnel *tunnel;
     uint16_t port;
 
@@ -1702,6 +1913,11 @@ ofpact_format(const struct ofpact *a, struct ds *s)
         ds_put_cstr(s, "strip_vlan");
         break;
 
+    case OFPACT_PUSH_VLAN:
+        /* TODO:XXX 802.1AD case*/
+        ds_put_format(s, "push_vlan:%#"PRIx16, ETH_TYPE_VLAN_8021Q);
+        break;
+
     case OFPACT_SET_ETH_SRC:
         ds_put_format(s, "mod_dl_src:"ETH_ADDR_FMT,
                       ETH_ADDR_ARGS(ofpact_get_SET_ETH_SRC(a)->mac));
@@ -1809,6 +2025,30 @@ ofpact_format(const struct ofpact *a, struct ds *s)
     case OFPACT_EXIT:
         ds_put_cstr(s, "exit");
         break;
+
+    case OFPACT_CLEAR_ACTIONS:
+        ds_put_format(s, "%s",
+                      ofpact_instruction_name_from_type(
+                          OVSINST_OFPIT11_CLEAR_ACTIONS));
+        break;
+
+    case OFPACT_WRITE_METADATA:
+        metadata = ofpact_get_WRITE_METADATA(a);
+        ds_put_format(s, "%s:%#"PRIx64,
+                      ofpact_instruction_name_from_type(
+                          OVSINST_OFPIT11_WRITE_METADATA),
+                      ntohll(metadata->metadata));
+        if (metadata->mask != htonll(UINT64_MAX)) {
+            ds_put_format(s, "/%#"PRIx64, ntohll(metadata->mask));
+        }
+        break;
+
+    case OFPACT_GOTO_TABLE:
+        ds_put_format(s, "%s:%"PRIu8,
+                      ofpact_instruction_name_from_type(
+                          OVSINST_OFPIT11_GOTO_TABLE),
+                      ofpact_get_GOTO_TABLE(a)->table_id);
+        break;
     }
 }
 
@@ -1828,6 +2068,8 @@ ofpacts_format(const struct ofpact *ofpacts, size_t ofpacts_len,
             if (a != ofpacts) {
                 ds_put_cstr(string, ",");
             }
+
+            /* TODO:XXX write-actions */
             ofpact_format(a, string);
         }
     }
@@ -1886,3 +2128,15 @@ ofpact_pad(struct ofpbuf *ofpacts)
         ofpbuf_put_zeros(ofpacts, OFPACT_ALIGNTO - rem);
     }
 }
+
+void
+ofpact_set_field_init(struct ofpact_reg_load *load, const struct mf_field *mf,
+                      const void *src)
+{
+    load->ofpact.compat = OFPUTIL_OFPAT12_SET_FIELD;
+    load->dst.field = mf;
+    load->dst.ofs = 0;
+    load->dst.n_bits = mf->n_bits;
+    bitwise_copy(src, mf->n_bytes, load->dst.ofs,
+                 &load->subvalue, sizeof load->subvalue, 0, mf->n_bits);
+}
index 46e2d79..b6cf4ba 100644 (file)
@@ -60,6 +60,7 @@
     DEFINE_OFPACT(SET_VLAN_VID,    ofpact_vlan_vid,      ofpact)    \
     DEFINE_OFPACT(SET_VLAN_PCP,    ofpact_vlan_pcp,      ofpact)    \
     DEFINE_OFPACT(STRIP_VLAN,      ofpact_null,          ofpact)    \
+    DEFINE_OFPACT(PUSH_VLAN,       ofpact_null,          ofpact)    \
     DEFINE_OFPACT(SET_ETH_SRC,     ofpact_mac,           ofpact)    \
     DEFINE_OFPACT(SET_ETH_DST,     ofpact_mac,           ofpact)    \
     DEFINE_OFPACT(SET_IPV4_SRC,    ofpact_ipv4,          ofpact)    \
                                                                     \
     /* Other. */                                                    \
     DEFINE_OFPACT(NOTE,            ofpact_note,          data)      \
-    DEFINE_OFPACT(EXIT,            ofpact_null,          ofpact)
+    DEFINE_OFPACT(EXIT,            ofpact_null,          ofpact)    \
+                                                                    \
+    /* Instructions */                                              \
+    /* TODO:XXX Write-Actions */                                    \
+    DEFINE_OFPACT(WRITE_METADATA,  ofpact_metadata,      ofpact)    \
+    DEFINE_OFPACT(CLEAR_ACTIONS,   ofpact_null,          ofpact)    \
+    DEFINE_OFPACT(GOTO_TABLE,      ofpact_goto_table,    ofpact)
 
 /* enum ofpact_type, with a member OFPACT_<ENUM> for each action. */
 enum OVS_PACKED_ENUM ofpact_type {
@@ -169,9 +176,10 @@ ofpact_end(const struct ofpact *ofpacts, size_t ofpacts_len)
 \f
 /* Action structure for each OFPACT_*. */
 
-/* OFPACT_STRIP_VLAN, OFPACT_POP_QUEUE, OFPACT_EXIT.
+/* OFPACT_STRIP_VLAN, OFPACT_POP_QUEUE, OFPACT_EXIT, OFPACT_CLEAR_ACTIONS.
  *
- * Used for OFPAT10_STRIP_VLAN, NXAST_DEC_TTL, NXAST_POP_QUEUE, NXAST_EXIT.
+ * Used for OFPAT10_STRIP_VLAN, NXAST_POP_QUEUE, NXAST_EXIT,
+ * OFPAT11_POP_VLAN, OFPIT11_CLEAR_ACTIONS.
  *
  * Action structure for actions that do not have any extra data beyond the
  * action type. */
@@ -327,6 +335,15 @@ struct ofpact_fin_timeout {
     uint16_t fin_hard_timeout;
 };
 
+/* OFPACT_WRITE_METADATA.
+ *
+ * Used for NXAST_WRITE_METADATA. */
+struct ofpact_metadata {
+    struct ofpact ofpact;
+    ovs_be64 metadata;
+    ovs_be64 mask;
+};
+
 /* OFPACT_RESUBMIT.
  *
  * Used for NXAST_RESUBMIT, NXAST_RESUBMIT_TABLE. */
@@ -406,14 +423,21 @@ struct ofpact_note {
 
 /* OFPACT_DEC_TTL.
  *
- * Used for NXAST_DEC_TTL and NXAST_DEC_TTL_CNT_IDS. */
+ * Used for OFPAT11_DEC_NW_TTL, NXAST_DEC_TTL and NXAST_DEC_TTL_CNT_IDS. */
 struct ofpact_cnt_ids {
     struct ofpact ofpact;
 
     /* Controller ids. */
     unsigned int n_controllers;
     uint16_t cnt_ids[];
+};
 
+/* OFPACT_GOTO_TABLE
+ *
+ * Used for OFPIT11_GOTO_TABLE */
+struct ofpact_goto_table {
+    struct ofpact ofpact;
+    uint8_t table_id;
 };
 
 /* Converting OpenFlow to ofpacts. */
@@ -428,6 +452,7 @@ enum ofperr ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
                                                  struct ofpbuf *ofpacts);
 enum ofperr ofpacts_check(const struct ofpact[], size_t ofpacts_len,
                           const struct flow *, int max_ports);
+enum ofperr ofpacts_verify(const struct ofpact ofpacts[], size_t ofpacts_len);
 
 /* Converting ofpacts to OpenFlow. */
 void ofpacts_put_openflow10(const struct ofpact[], size_t ofpacts_len,
@@ -566,7 +591,20 @@ enum {
 #undef DEFINE_INST
 };
 
+
+static inline bool
+ofpact_is_instruction(const struct ofpact *a)
+{
+    /* TODO:XXX Write-Actions */
+    return a->type == OFPACT_CLEAR_ACTIONS
+        || a->type == OFPACT_WRITE_METADATA
+        || a->type == OFPACT_GOTO_TABLE;
+}
+
 const char *ofpact_instruction_name_from_type(enum ovs_instruction_type type);
 int ofpact_instruction_type_from_name(const char *name);
 
+void ofpact_set_field_init(struct ofpact_reg_load *load,
+                           const struct mf_field *mf, const void *src);
+
 #endif /* ofp-actions.h */
index a883e20..ffac8aa 100644 (file)
@@ -309,10 +309,7 @@ enum ofperr {
     /* OF1.1+(5,0).  Unspecified error. */
     OFPERR_OFPFMFC_UNKNOWN,
 
-    /* OF1.0(3,0).  Flow not added because of full tables. */
-    OFPERR_OFPFMFC_ALL_TABLES_FULL,
-
-    /* OF1.1+(5,1).  Flow not added because table was full. */
+    /* OF1.0(3,0), OF1.1+(5,1).  Flow not added because of full table(s). */
     OFPERR_OFPFMFC_TABLE_FULL,
 
     /* OF1.1+(5,2).  Table does not exist */
index 752d12c..f8ac4cd 100644 (file)
@@ -216,22 +216,32 @@ enum ofpraw {
     OFPRAW_OFPST12_TABLE_REPLY,
 
     /* OFPST 1.0 (4): struct ofp10_port_stats_request. */
-    OFPRAW_OFPST_PORT_REQUEST,
+    OFPRAW_OFPST10_PORT_REQUEST,
+    /* OFPST 1.1+ (4): struct ofp11_port_stats_request. */
+    OFPRAW_OFPST11_PORT_REQUEST,
 
     /* OFPST 1.0 (4): struct ofp10_port_stats[]. */
-    OFPRAW_OFPST_PORT_REPLY,
+    OFPRAW_OFPST10_PORT_REPLY,
+    /* OFPST 1.1+ (4): struct ofp11_port_stats[]. */
+    OFPRAW_OFPST11_PORT_REPLY,
 
     /* OFPST 1.0 (5): struct ofp10_queue_stats_request. */
-    OFPRAW_OFPST_QUEUE_REQUEST,
+    OFPRAW_OFPST10_QUEUE_REQUEST,
+    /* OFPST 1.1+ (5): struct ofp11_queue_stats_request. */
+    OFPRAW_OFPST11_QUEUE_REQUEST,
 
     /* OFPST 1.0 (5): struct ofp10_queue_stats[]. */
-    OFPRAW_OFPST_QUEUE_REPLY,
+    OFPRAW_OFPST10_QUEUE_REPLY,
+    /* OFPST 1.1+ (5): struct ofp11_queue_stats[]. */
+    OFPRAW_OFPST11_QUEUE_REPLY,
 
-    /* OFPST 1.0 (13): void. */
+    /* OFPST 1.0+ (13): void. */
     OFPRAW_OFPST_PORT_DESC_REQUEST,
 
     /* OFPST 1.0 (13): struct ofp10_phy_port[]. */
-    OFPRAW_OFPST_PORT_DESC_REPLY,
+    OFPRAW_OFPST10_PORT_DESC_REPLY,
+    /* OFPST 1.1+ (13): struct ofp11_port[]. */
+    OFPRAW_OFPST11_PORT_DESC_REPLY,
 
 /* Nicira extension messages.
  *
@@ -382,12 +392,18 @@ enum ofptype {
     OFPTYPE_TABLE_STATS_REPLY,       /* OFPRAW_OFPST10_TABLE_REPLY.
                                       * OFPRAW_OFPST11_TABLE_REPLY.
                                       * OFPRAW_OFPST12_TABLE_REPLY. */
-    OFPTYPE_PORT_STATS_REQUEST,      /* OFPRAW_OFPST_PORT_REQUEST. */
-    OFPTYPE_PORT_STATS_REPLY,        /* OFPRAW_OFPST_PORT_REPLY. */
-    OFPTYPE_QUEUE_STATS_REQUEST,     /* OFPRAW_OFPST_QUEUE_REQUEST. */
-    OFPTYPE_QUEUE_STATS_REPLY,       /* OFPRAW_OFPST_QUEUE_REPLY. */
+    OFPTYPE_PORT_STATS_REQUEST,      /* OFPRAW_OFPST10_PORT_REQUEST.
+                                      * OFPRAW_OFPST11_PORT_REQUEST. */
+    OFPTYPE_PORT_STATS_REPLY,        /* OFPRAW_OFPST10_PORT_REPLY.
+                                      * OFPRAW_OFPST11_PORT_REPLY. */
+    OFPTYPE_QUEUE_STATS_REQUEST,     /* OFPRAW_OFPST10_QUEUE_REQUEST.
+                                      * OFPRAW_OFPST11_QUEUE_REQUEST. */
+    OFPTYPE_QUEUE_STATS_REPLY,       /* OFPRAW_OFPST10_QUEUE_REPLY.
+                                      * OFPRAW_OFPST11_QUEUE_REPLY. */
     OFPTYPE_PORT_DESC_STATS_REQUEST, /* OFPRAW_OFPST_PORT_DESC_REQUEST. */
-    OFPTYPE_PORT_DESC_STATS_REPLY,   /* OFPRAW_OFPST_PORT_DESC_REPLY. */
+
+    OFPTYPE_PORT_DESC_STATS_REPLY,   /* OFPRAW_OFPST10_PORT_DESC_REPLY.
+                                      * OFPRAW_OFPST11_PORT_DESC_REPLY. */
 
     /* Nicira extensions. */
     OFPTYPE_ROLE_REQUEST,         /* OFPRAW_NXT_ROLE_REQUEST. */
index e3b7dc1..dedfb7e 100644 (file)
@@ -168,8 +168,7 @@ parse_resubmit(char *arg, struct ofpbuf *ofpacts)
 
     in_port_s = strsep(&arg, ",");
     if (in_port_s && in_port_s[0]) {
-        resubmit->in_port = ofputil_port_from_string(in_port_s);
-        if (!resubmit->in_port) {
+        if (!ofputil_port_from_string(in_port_s, &resubmit->in_port)) {
             ovs_fatal(0, "%s: resubmit to unknown port", in_port_s);
         }
     } else {
@@ -280,22 +279,28 @@ parse_controller(struct ofpbuf *b, char *arg)
 }
 
 static void
-parse_dec_ttl(struct ofpbuf *b, char *arg)
+parse_noargs_dec_ttl(struct ofpbuf *b)
 {
     struct ofpact_cnt_ids *ids;
+    uint16_t id = 0;
 
     ids = ofpact_put_DEC_TTL(b);
+    ofpbuf_put(b, &id, sizeof id);
+    ids = b->l2;
+    ids->n_controllers++;
+    ofpact_update_len(b, &ids->ofpact);
+}
 
+static void
+parse_dec_ttl(struct ofpbuf *b, char *arg)
+{
     if (*arg == '\0') {
-        uint16_t id = 0;
-
-        ids->ofpact.compat = OFPUTIL_NXAST_DEC_TTL;
-        ofpbuf_put(b, &id, sizeof id);
-        ids = b->l2;
-        ids->n_controllers++;
+        parse_noargs_dec_ttl(b);
     } else {
+        struct ofpact_cnt_ids *ids;
         char *cntr;
 
+        ids = ofpact_put_DEC_TTL(b);
         ids->ofpact.compat = OFPUTIL_NXAST_DEC_TTL_CNT_IDS;
         for (cntr = strtok_r(arg, ", ", &arg); cntr != NULL;
              cntr = strtok_r(NULL, ", ", &arg)) {
@@ -309,9 +314,68 @@ parse_dec_ttl(struct ofpbuf *b, char *arg)
             ovs_fatal(0, "dec_ttl_cnt_ids: expected at least one controller "
                       "id.");
         }
+        ofpact_update_len(b, &ids->ofpact);
+    }
+}
 
+static void
+set_field_parse(const char *arg, struct ofpbuf *ofpacts)
+{
+    char *orig = xstrdup(arg);
+    struct ofpact_reg_load *load = ofpact_put_REG_LOAD(ofpacts);
+    char *value;
+    char *delim;
+    char *key;
+    const struct mf_field *mf;
+    const char *error;
+    union mf_value mf_value;
+
+    value = orig;
+    delim = strstr(orig, "->");
+    if (!delim) {
+        ovs_fatal(0, "%s: missing `->'", orig);
     }
-    ofpact_update_len(b, &ids->ofpact);
+    if (strlen(delim) <= strlen("->")) {
+        ovs_fatal(0, "%s: missing field name following `->'", orig);
+    }
+
+    key = delim + strlen("->");
+    mf = mf_from_name(key);
+    if (!mf) {
+        ovs_fatal(0, "%s is not valid oxm field name", key);
+    }
+    if (!mf->writable) {
+        ovs_fatal(0, "%s is not allowed to set", key);
+    }
+
+    delim[0] = '\0';
+    error = mf_parse_value(mf, value, &mf_value);
+    if (error) {
+        ovs_fatal(0, "%s", error);
+    }
+    if (!mf_is_value_valid(mf, &mf_value)) {
+        ovs_fatal(0, "%s is not valid valid for field %s", value, key);
+    }
+    ofpact_set_field_init(load, mf, &mf_value);
+    free(orig);
+}
+
+static void
+parse_metadata(struct ofpbuf *b, char *arg)
+{
+    struct ofpact_metadata *om;
+    char *mask = strchr(arg, '/');
+
+    om = ofpact_put_WRITE_METADATA(b);
+
+    if (mask) {
+        *mask = '\0';
+        om->mask = htonll(str_to_u64(mask + 1));
+    } else {
+        om->mask = htonll(UINT64_MAX);
+    }
+
+    om->metadata = htonll(str_to_u64(arg));
 }
 
 static void
@@ -320,6 +384,7 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
 {
     struct ofpact_tunnel *tunnel;
     uint16_t vid;
+    uint16_t ethertype;
     ovs_be32 ip;
     uint8_t pcp;
     uint8_t tos;
@@ -352,15 +417,23 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
         break;
 
     case OFPUTIL_OFPAT12_SET_FIELD:
-        NOT_REACHED();  /* This will be implemented by later patch and
-                         * enabled using a non-NULL name in
-                         * OFPAT12_ACTION(OFPAT12_SET_FIELD, ...) */
+        set_field_parse(arg, ofpacts);
         break;
 
     case OFPUTIL_OFPAT10_STRIP_VLAN:
+    case OFPUTIL_OFPAT11_POP_VLAN:
         ofpact_put_STRIP_VLAN(ofpacts);
         break;
 
+    case OFPUTIL_OFPAT11_PUSH_VLAN:
+        ethertype = str_to_u16(arg, "ethertype");
+        if (ethertype != ETH_TYPE_VLAN_8021Q) {
+            /* TODO:XXXX ETH_TYPE_VLAN_8021AD case isn't supported */
+            ovs_fatal(0, "%s: not a valid VLAN ethertype", arg);
+        }
+        ofpact_put_PUSH_VLAN(ofpacts);
+        break;
+
     case OFPUTIL_OFPAT10_SET_DL_SRC:
     case OFPUTIL_OFPAT11_SET_DL_SRC:
         str_to_mac(arg, ofpact_put_SET_ETH_SRC(ofpacts)->mac);
@@ -392,6 +465,9 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
         ofpact_put_SET_IPV4_DSCP(ofpacts)->dscp = tos;
         break;
 
+    case OFPUTIL_OFPAT11_DEC_NW_TTL:
+        NOT_REACHED();
+
     case OFPUTIL_OFPAT10_SET_TP_SRC:
     case OFPUTIL_OFPAT11_SET_TP_SRC:
         ofpact_put_SET_L4_SRC_PORT(ofpacts)->port = str_to_u32(arg);
@@ -417,6 +493,10 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
         tunnel->tun_id = str_to_u64(arg);
         break;
 
+    case OFPUTIL_NXAST_WRITE_METADATA:
+        parse_metadata(ofpacts, arg);
+        break;
+
     case OFPUTIL_NXAST_SET_QUEUE:
         ofpact_put_SET_QUEUE(ofpacts)->queue_id = str_to_u32(arg);
         break;
@@ -480,35 +560,141 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
     }
 }
 
+static bool
+str_to_ofpact__(const struct flow *flow, char *pos, char *act, char *arg,
+                struct ofpbuf *ofpacts, int n_actions)
+{
+    int code = ofputil_action_code_from_name(act);
+    if (code >= 0) {
+        parse_named_action(code, flow, arg, ofpacts);
+    } else if (!strcasecmp(act, "drop")) {
+        if (n_actions) {
+            ovs_fatal(0, "Drop actions must not be preceded by other "
+                      "actions");
+        } else if (ofputil_parse_key_value(&pos, &act, &arg)) {
+            ovs_fatal(0, "Drop actions must not be followed by other "
+                      "actions");
+        }
+        return false;
+    } else {
+        uint16_t port;
+        if (ofputil_port_from_string(act, &port)) {
+            ofpact_put_OUTPUT(ofpacts)->port = port;
+        } else {
+            ovs_fatal(0, "Unknown action: %s", act);
+        }
+    }
+
+    return true;
+}
+
 static void
 str_to_ofpacts(const struct flow *flow, char *str, struct ofpbuf *ofpacts)
 {
     char *pos, *act, *arg;
+    enum ofperr error;
     int n_actions;
 
     pos = str;
     n_actions = 0;
     while (ofputil_parse_key_value(&pos, &act, &arg)) {
-        int code = ofputil_action_code_from_name(act);
-        if (code >= 0) {
-            parse_named_action(code, flow, arg, ofpacts);
-        } else if (!strcasecmp(act, "drop")) {
-            if (n_actions) {
-                ovs_fatal(0, "Drop actions must not be preceded by other "
-                          "actions");
-            } else if (ofputil_parse_key_value(&pos, &act, &arg)) {
-                ovs_fatal(0, "Drop actions must not be followed by other "
-                          "actions");
-            }
+        if (!str_to_ofpact__(flow, pos, act, arg, ofpacts, n_actions)) {
             break;
-        } else {
-            uint16_t port = ofputil_port_from_string(act);
-            if (port) {
-                ofpact_put_OUTPUT(ofpacts)->port = port;
-            } else {
-                ovs_fatal(0, "Unknown action: %s", act);
+        }
+        n_actions++;
+    }
+
+    error = ofpacts_verify(ofpacts->data, ofpacts->size);
+    if (error) {
+        ovs_fatal(0, "Incorrect action ordering");
+    }
+
+    ofpact_pad(ofpacts);
+}
+
+static void
+parse_named_instruction(enum ovs_instruction_type type,
+                        char *arg, struct ofpbuf *ofpacts)
+{
+    enum ofperr error;
+
+    switch (type) {
+    case OVSINST_OFPIT11_APPLY_ACTIONS:
+        NOT_REACHED();  /* This case is handled by str_to_inst_ofpacts() */
+        break;
+
+    case OVSINST_OFPIT11_WRITE_ACTIONS:
+        /* TODO:XXX */
+        ovs_fatal(0, "instruction write-actions is not supported yet");
+        break;
+
+    case OVSINST_OFPIT11_CLEAR_ACTIONS:
+        ofpact_put_CLEAR_ACTIONS(ofpacts);
+        break;
+
+    case OVSINST_OFPIT11_WRITE_METADATA:
+        parse_metadata(ofpacts, arg);
+        break;
+
+    case OVSINST_OFPIT11_GOTO_TABLE: {
+        struct ofpact_goto_table *ogt = ofpact_put_GOTO_TABLE(ofpacts);
+        char *table_s = strsep(&arg, ",");
+        if (!table_s || !table_s[0]) {
+            ovs_fatal(0, "instruction goto-table needs table id");
+        }
+        ogt->table_id = str_to_table_id(table_s);
+        break;
+    }
+    }
+
+    /* If write_metadata is specified as an action AND an instruction, ofpacts
+       could be invalid. */
+    error = ofpacts_verify(ofpacts->data, ofpacts->size);
+    if (error) {
+        ovs_fatal(0, "Incorrect instruction ordering");
+    }
+}
+
+static void
+str_to_inst_ofpacts(const struct flow *flow, char *str, struct ofpbuf *ofpacts)
+{
+    char *pos, *inst, *arg;
+    int type;
+    const char *prev_inst = NULL;
+    int prev_type = -1;
+    int n_actions = 0;
+
+    pos = str;
+    while (ofputil_parse_key_value(&pos, &inst, &arg)) {
+        type = ofpact_instruction_type_from_name(inst);
+        if (type < 0) {
+            if (!str_to_ofpact__(flow, pos, inst, arg, ofpacts, n_actions)) {
+                break;
+            }
+
+            type = OVSINST_OFPIT11_APPLY_ACTIONS;
+            if (prev_type == type) {
+                n_actions++;
+                continue;
             }
+        } else if (type == OVSINST_OFPIT11_APPLY_ACTIONS) {
+            ovs_fatal(0, "%s isn't supported. Just write actions then "
+                      "it is interpreted as apply_actions", inst);
+        } else {
+            parse_named_instruction(type, arg, ofpacts);
+        }
+
+        if (type == prev_type) {
+            ovs_fatal(0, "instruction can be specified at most once: %s",
+                      inst);
         }
+        if (type <= prev_type) {
+            ovs_fatal(0, "Instruction %s must be specified before %s",
+                      inst, prev_inst);
+        }
+
+        prev_inst = inst;
+        prev_type = type;
         n_actions++;
     }
     ofpact_pad(ofpacts);
@@ -682,8 +868,7 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
             if (!strcmp(name, "table")) {
                 fm->table_id = str_to_table_id(value);
             } else if (!strcmp(name, "out_port")) {
-                fm->out_port = ofputil_port_from_string(name);
-                if (!fm->out_port) {
+                if (!ofputil_port_from_string(name, &fm->out_port)) {
                     ofp_fatal(str_, verbose, "%s is not a valid OpenFlow port",
                               name);
                 }
@@ -737,7 +922,7 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
         struct ofpbuf ofpacts;
 
         ofpbuf_init(&ofpacts, 32);
-        str_to_ofpacts(&fm->match.flow, act_str, &ofpacts);
+        str_to_inst_ofpacts(&fm->match.flow, act_str, &ofpacts);
         fm->ofpacts_len = ofpacts.size;
         fm->ofpacts = ofpbuf_steal_data(&ofpacts);
     } else {
index 6789625..8654783 100644 (file)
@@ -63,7 +63,7 @@ ofp_packet_to_string(const void *data, size_t len)
     struct flow flow;
 
     ofpbuf_use_const(&buf, data, len);
-    flow_extract(&buf, 0, 0, 0, &flow);
+    flow_extract(&buf, 0, NULL, 0, &flow);
     flow_format(&ds, &flow);
 
     if (buf.l7) {
@@ -743,7 +743,7 @@ ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh, int verbosity)
     if (ds_last(s) != ' ') {
         ds_put_char(s, ' ');
     }
-    if (fm.new_cookie != htonll(0)) {
+    if (fm.new_cookie != htonll(0) && fm.new_cookie != htonll(UINT64_MAX)) {
         ds_put_format(s, "cookie:0x%"PRIx64" ", ntohll(fm.new_cookie));
     }
     if (fm.cookie_mask != htonll(0)) {
@@ -843,6 +843,10 @@ ofp_print_flow_removed(struct ds *string, const struct ofp_header *oh)
     ds_put_format(string, " reason=%s",
                   ofp_flow_removed_reason_to_string(fr.reason));
 
+    if (fr.table_id != 255) {
+        ds_put_format(string, " table_id=%"PRIu8, fr.table_id);
+    }
+
     if (fr.cookie != htonll(0)) {
         ds_put_format(string, " cookie:0x%"PRIx64, ntohll(fr.cookie));
     }
@@ -1061,11 +1065,9 @@ ofp_print_aggregate_stats_reply(struct ds *string, const struct ofp_header *oh)
     ds_put_format(string, " flow_count=%"PRIu32, as.flow_count);
 }
 
-static void print_port_stat(struct ds *string, const char *leader,
-                            const ovs_32aligned_be64 *statp, int more)
+static void
+print_port_stat(struct ds *string, const char *leader, uint64_t stat, int more)
 {
-    uint64_t stat = ntohll(get_32aligned_be64(statp));
-
     ds_put_cstr(string, leader);
     if (stat != UINT64_MAX) {
         ds_put_format(string, "%"PRIu64, stat);
@@ -1082,50 +1084,59 @@ static void print_port_stat(struct ds *string, const char *leader,
 static void
 ofp_print_ofpst_port_request(struct ds *string, const struct ofp_header *oh)
 {
-    const struct ofp10_port_stats_request *psr = ofpmsg_body(oh);
-    ds_put_format(string, " port_no=%"PRIu16, ntohs(psr->port_no));
+    uint16_t ofp10_port;
+    enum ofperr error;
+
+    error = ofputil_decode_port_stats_request(oh, &ofp10_port);
+    if (error) {
+        ofp_print_error(string, error);
+        return;
+    }
+
+    ds_put_format(string, " port_no=%2"PRIu16, ofp10_port);
 }
 
 static void
 ofp_print_ofpst_port_reply(struct ds *string, const struct ofp_header *oh,
                            int verbosity)
 {
-    struct ofp10_port_stats *ps;
     struct ofpbuf b;
-    size_t n;
-
-    ofpbuf_use_const(&b, oh, ntohs(oh->length));
-    ofpraw_pull_assert(&b);
 
-    n = b.size / sizeof *ps;
-    ds_put_format(string, " %zu ports\n", n);
+    ds_put_format(string, " %zu ports\n", ofputil_count_port_stats(oh));
     if (verbosity < 1) {
         return;
     }
 
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
     for (;;) {
-        ps = ofpbuf_try_pull(&b, sizeof *ps);
-        if (!ps) {
+        struct ofputil_port_stats ps;
+        int retval;
+
+        retval = ofputil_decode_port_stats(&ps, &b);
+        if (retval) {
+            if (retval != EOF) {
+                ds_put_cstr(string, " ***parse error***");
+            }
             return;
         }
 
-        ds_put_format(string, "  port %2"PRIu16": ", ntohs(ps->port_no));
+        ds_put_format(string, "  port %2"PRIu16, ps.port_no);
 
-        ds_put_cstr(string, "rx ");
-        print_port_stat(string, "pkts=", &ps->rx_packets, 1);
-        print_port_stat(string, "bytes=", &ps->rx_bytes, 1);
-        print_port_stat(string, "drop=", &ps->rx_dropped, 1);
-        print_port_stat(string, "errs=", &ps->rx_errors, 1);
-        print_port_stat(string, "frame=", &ps->rx_frame_err, 1);
-        print_port_stat(string, "over=", &ps->rx_over_err, 1);
-        print_port_stat(string, "crc=", &ps->rx_crc_err, 0);
+        ds_put_cstr(string, "rx ");
+        print_port_stat(string, "pkts=", ps.stats.rx_packets, 1);
+        print_port_stat(string, "bytes=", ps.stats.rx_bytes, 1);
+        print_port_stat(string, "drop=", ps.stats.rx_dropped, 1);
+        print_port_stat(string, "errs=", ps.stats.rx_errors, 1);
+        print_port_stat(string, "frame=", ps.stats.rx_frame_errors, 1);
+        print_port_stat(string, "over=", ps.stats.rx_over_errors, 1);
+        print_port_stat(string, "crc=", ps.stats.rx_crc_errors, 0);
 
         ds_put_cstr(string, "           tx ");
-        print_port_stat(string, "pkts=", &ps->tx_packets, 1);
-        print_port_stat(string, "bytes=", &ps->tx_bytes, 1);
-        print_port_stat(string, "drop=", &ps->tx_dropped, 1);
-        print_port_stat(string, "errs=", &ps->tx_errors, 1);
-        print_port_stat(string, "coll=", &ps->collisions, 0);
+        print_port_stat(string, "pkts=", ps.stats.tx_packets, 1);
+        print_port_stat(string, "bytes=", ps.stats.tx_bytes, 1);
+        print_port_stat(string, "drop=", ps.stats.tx_dropped, 1);
+        print_port_stat(string, "errs=", ps.stats.tx_errors, 1);
+        print_port_stat(string, "coll=", ps.stats.collisions, 0);
     }
 }
 
@@ -1315,47 +1326,55 @@ ofp_print_queue_name(struct ds *string, uint32_t queue_id)
 static void
 ofp_print_ofpst_queue_request(struct ds *string, const struct ofp_header *oh)
 {
-    const struct ofp10_queue_stats_request *qsr = ofpmsg_body(oh);
+    struct ofputil_queue_stats_request oqsr;
+    enum ofperr error;
+
+    error = ofputil_decode_queue_stats_request(oh, &oqsr);
+    if (error) {
+        ds_put_format(string, "***decode error: %s***\n", ofperr_get_name(error));
+        return;
+    }
 
     ds_put_cstr(string, "port=");
-    ofputil_format_port(ntohs(qsr->port_no), string);
+    ofputil_format_port(oqsr.port_no, string);
 
     ds_put_cstr(string, " queue=");
-    ofp_print_queue_name(string, ntohl(qsr->queue_id));
+    ofp_print_queue_name(string, oqsr.queue_id);
 }
 
 static void
 ofp_print_ofpst_queue_reply(struct ds *string, const struct ofp_header *oh,
                             int verbosity)
 {
-    struct ofp10_queue_stats *qs;
     struct ofpbuf b;
-    size_t n;
 
-    ofpbuf_use_const(&b, oh, ntohs(oh->length));
-    ofpraw_pull_assert(&b);
-
-    n = b.size / sizeof *qs;
-    ds_put_format(string, " %zu queues\n", n);
+    ds_put_format(string, " %zu queues\n", ofputil_count_queue_stats(oh));
     if (verbosity < 1) {
         return;
     }
 
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
     for (;;) {
-        qs = ofpbuf_try_pull(&b, sizeof *qs);
-        if (!qs) {
+        struct ofputil_queue_stats qs;
+        int retval;
+
+        retval = ofputil_decode_queue_stats(&qs, &b);
+        if (retval) {
+            if (retval != EOF) {
+                ds_put_cstr(string, " ***parse error***");
+            }
             return;
         }
 
         ds_put_cstr(string, "  port ");
-        ofputil_format_port(ntohs(qs->port_no), string);
+        ofputil_format_port(qs.port_no, string);
         ds_put_cstr(string, " queue ");
-        ofp_print_queue_name(string, ntohl(qs->queue_id));
+        ofp_print_queue_name(string, qs.queue_id);
         ds_put_cstr(string, ": ");
 
-        print_port_stat(string, "bytes=", &qs->tx_bytes, 1);
-        print_port_stat(string, "pkts=", &qs->tx_packets, 1);
-        print_port_stat(string, "errors=", &qs->tx_errors, 0);
+        print_port_stat(string, "bytes=", qs.stats.tx_bytes, 1);
+        print_port_stat(string, "pkts=", qs.stats.tx_packets, 1);
+        print_port_stat(string, "errors=", qs.stats.tx_errors, 0);
     }
 }
 
index fc98894..34255da 100644 (file)
@@ -139,7 +139,7 @@ ofputil_match_from_ofp10_match(const struct ofp10_match *ofmatch,
     uint32_t ofpfw = ntohl(ofmatch->wildcards) & OFPFW10_ALL;
 
     /* Initialize match->wc. */
-    memset(match->flow.zeros, 0, sizeof match->flow.zeros);
+    memset(&match->flow, 0, sizeof match->flow);
     ofputil_wildcard_from_ofpfw10(ofpfw, &match->wc);
 
     /* Initialize most of match->flow. */
@@ -934,7 +934,7 @@ ofputil_usable_protocols(const struct match *match)
     }
 
     /* Only NXM supports matching tun_id. */
-    if (wc->masks.tun_id != htonll(0)) {
+    if (wc->masks.tunnel.tun_id != htonll(0)) {
         return OFPUTIL_P_NXM_ANY;
     }
 
@@ -1084,12 +1084,13 @@ ofputil_nx_flow_format_to_string(enum nx_flow_format flow_format)
 }
 
 struct ofpbuf *
-ofputil_make_set_packet_in_format(enum nx_packet_in_format packet_in_format)
+ofputil_make_set_packet_in_format(enum ofp_version ofp_version,
+                                  enum nx_packet_in_format packet_in_format)
 {
     struct nx_set_packet_in_format *spif;
     struct ofpbuf *msg;
 
-    msg = ofpraw_alloc(OFPRAW_NXT_SET_PACKET_IN_FORMAT, OFP10_VERSION, 0);
+    msg = ofpraw_alloc(OFPRAW_NXT_SET_PACKET_IN_FORMAT, ofp_version, 0);
     spif = ofpbuf_put_zeros(msg, sizeof *spif);
     spif->format = htonl(packet_in_format);
 
@@ -1156,7 +1157,6 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
             fm->cookie_mask = htonll(0);
             fm->new_cookie = ofm->cookie;
         } else {
-            /* XXX */
             fm->cookie = ofm->cookie;
             fm->cookie_mask = ofm->cookie_mask;
             fm->new_cookie = htonll(UINT64_MAX);
@@ -1283,7 +1283,11 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
         msg = ofpraw_alloc(OFPRAW_OFPT11_FLOW_MOD, OFP12_VERSION,
                            NXM_TYPICAL_LEN + fm->ofpacts_len);
         ofm = ofpbuf_put_zeros(msg, sizeof *ofm);
-        ofm->cookie = fm->new_cookie;
+        if (fm->command == OFPFC_ADD) {
+            ofm->cookie = fm->new_cookie;
+        } else {
+            ofm->cookie = fm->cookie;
+        }
         ofm->cookie_mask = fm->cookie_mask;
         ofm->table_id = fm->table_id;
         ofm->command = fm->command;
@@ -1913,7 +1917,7 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
         fr->priority = ntohs(ofr->priority);
         fr->cookie = ofr->cookie;
         fr->reason = ofr->reason;
-        /* XXX: ofr->table_id is ignored */
+        fr->table_id = ofr->table_id;
         fr->duration_sec = ntohl(ofr->duration_sec);
         fr->duration_nsec = ntohl(ofr->duration_nsec);
         fr->idle_timeout = ntohs(ofr->idle_timeout);
@@ -1929,6 +1933,7 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
         fr->priority = ntohs(ofr->priority);
         fr->cookie = ofr->cookie;
         fr->reason = ofr->reason;
+        fr->table_id = 255;
         fr->duration_sec = ntohl(ofr->duration_sec);
         fr->duration_nsec = ntohl(ofr->duration_nsec);
         fr->idle_timeout = ntohs(ofr->idle_timeout);
@@ -1937,7 +1942,7 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
         fr->byte_count = ntohll(ofr->byte_count);
     } else if (raw == OFPRAW_NXT_FLOW_REMOVED) {
         struct nx_flow_removed *nfr;
-        int error;
+        enum ofperr error;
 
         nfr = ofpbuf_pull(&b, sizeof *nfr);
         error = nx_pull_match(&b, ntohs(nfr->match_len), &fr->match,
@@ -1952,6 +1957,7 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
         fr->priority = ntohs(nfr->priority);
         fr->cookie = nfr->cookie;
         fr->reason = nfr->reason;
+        fr->table_id = 255;
         fr->duration_sec = ntohl(nfr->duration_sec);
         fr->duration_nsec = ntohl(nfr->duration_nsec);
         fr->idle_timeout = ntohs(nfr->idle_timeout);
@@ -1985,7 +1991,7 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
         ofr->cookie = fr->cookie;
         ofr->priority = htons(fr->priority);
         ofr->reason = fr->reason;
-        ofr->table_id = 0;
+        ofr->table_id = fr->table_id;
         ofr->duration_sec = htonl(fr->duration_sec);
         ofr->duration_nsec = htonl(fr->duration_nsec);
         ofr->idle_timeout = htons(fr->idle_timeout);
@@ -2053,7 +2059,7 @@ ofputil_decode_packet_in_finish(struct ofputil_packet_in *pin,
     pin->packet_len = b->size;
 
     pin->fmd.in_port = match->flow.in_port;
-    pin->fmd.tun_id = match->flow.tun_id;
+    pin->fmd.tun_id = match->flow.tunnel.tun_id;
     pin->fmd.metadata = match->flow.metadata;
     memcpy(pin->fmd.regs, match->flow.regs, sizeof pin->fmd.regs);
 }
@@ -3536,52 +3542,55 @@ ofputil_check_output_port(uint16_t port, int max_ports)
         OFPUTIL_NAMED_PORT(LOCAL)               \
         OFPUTIL_NAMED_PORT(NONE)
 
-/* Returns the port number represented by 's', which may be an integer or, for
- * reserved ports, the standard OpenFlow name for the port (e.g. "LOCAL").
+/* Stores the port number represented by 's' into '*portp'.  's' may be an
+ * integer or, for reserved ports, the standard OpenFlow name for the port
+ * (e.g. "LOCAL").
  *
- * Returns 0 if 's' is not a valid OpenFlow port number or name.  The caller
- * should issue an error message in this case, because this function usually
- * does not.  (This gives the caller an opportunity to look up the port name
- * another way, e.g. by contacting the switch and listing the names of all its
- * ports).
+ * Returns true if successful, false if 's' is not a valid OpenFlow port number
+ * or name.  The caller should issue an error message in this case, because
+ * this function usually does not.  (This gives the caller an opportunity to
+ * look up the port name another way, e.g. by contacting the switch and listing
+ * the names of all its ports).
  *
  * This function accepts OpenFlow 1.0 port numbers.  It also accepts a subset
  * of OpenFlow 1.1+ port numbers, mapping those port numbers into the 16-bit
  * range as described in include/openflow/openflow-1.1.h. */
-uint16_t
-ofputil_port_from_string(const char *s)
+bool
+ofputil_port_from_string(const char *s, uint16_t *portp)
 {
     unsigned int port32;
 
+    *portp = 0;
     if (str_to_uint(s, 10, &port32)) {
-        if (port32 == 0) {
-            VLOG_WARN("port 0 is not a valid OpenFlow port number");
-            return 0;
-        } else if (port32 < OFPP_MAX) {
-            return port32;
+        if (port32 < OFPP_MAX) {
+            *portp = port32;
+            return true;
         } else if (port32 < OFPP_FIRST_RESV) {
             VLOG_WARN("port %u is a reserved OF1.0 port number that will "
                       "be translated to %u when talking to an OF1.1 or "
                       "later controller", port32, port32 + OFPP11_OFFSET);
-            return port32;
+            *portp = port32;
+            return true;
         } else if (port32 <= OFPP_LAST_RESV) {
             struct ds s;
 
             ds_init(&s);
             ofputil_format_port(port32, &s);
-            VLOG_WARN("port %u is better referred to as %s, for compatibility "
-                      "with future versions of OpenFlow",
-                      port32, ds_cstr(&s));
+            VLOG_WARN_ONCE("referring to port %s as %u is deprecated for "
+                           "compatibility with future versions of OpenFlow",
+                           ds_cstr(&s), port32);
             ds_destroy(&s);
 
-            return port32;
+            *portp = port32;
+            return true;
         } else if (port32 < OFPP11_MAX) {
             VLOG_WARN("port %u is outside the supported range 0 through "
                       "%"PRIx16"or 0x%x through 0x%"PRIx32, port32,
                       UINT16_MAX, (unsigned int) OFPP11_MAX, UINT32_MAX);
-            return 0;
+            return false;
         } else {
-            return port32 - OFPP11_OFFSET;
+            *portp = port32 - OFPP11_OFFSET;
+            return true;
         }
     } else {
         struct pair {
@@ -3597,10 +3606,11 @@ ofputil_port_from_string(const char *s)
 
         for (p = pairs; p < &pairs[ARRAY_SIZE(pairs)]; p++) {
             if (!strcasecmp(s, p->name)) {
-                return p->value;
+                *portp = p->value;
+                return true;
             }
         }
-        return 0;
+        return false;
     }
 }
 
@@ -3665,10 +3675,9 @@ ofputil_action_code_from_name(const char *name)
 {
     static const char *names[OFPUTIL_N_ACTIONS] = {
         NULL,
-#define OFPAT10_ACTION(ENUM, STRUCT, NAME)           NAME,
-#define OFPAT11_ACTION(ENUM, STRUCT, NAME)           NAME,
-#define OFPAT12_ACTION(ENUM, STRUCT, NAME)           NAME,
-#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME,
+#define OFPAT10_ACTION(ENUM, STRUCT, NAME)             NAME,
+#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME,
+#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)   NAME,
 #include "ofp-util.def"
     };
 
@@ -3694,10 +3703,10 @@ ofputil_put_action(enum ofputil_action_code code, struct ofpbuf *buf)
     case OFPUTIL_ACTION_INVALID:
         NOT_REACHED();
 
-#define OFPAT10_ACTION(ENUM, STRUCT, NAME)                    \
+#define OFPAT10_ACTION(ENUM, STRUCT, NAME)                  \
+    case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf);
+#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)      \
     case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf);
-#define OFPAT11_ACTION OFPAT10_ACTION
-#define OFPAT12_ACTION OFPAT10_ACTION
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)        \
     case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf);
 #include "ofp-util.def"
@@ -3721,8 +3730,8 @@ ofputil_put_action(enum ofputil_action_code code, struct ofpbuf *buf)
         ofputil_init_##ENUM(s);                                 \
         return s;                                               \
     }
-#define OFPAT11_ACTION OFPAT10_ACTION
-#define OFPAT12_ACTION OFPAT10_ACTION
+#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
+    OFPAT10_ACTION(ENUM, STRUCT, NAME)
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)            \
     void                                                        \
     ofputil_init_##ENUM(struct STRUCT *s)                       \
@@ -3936,3 +3945,451 @@ ofputil_parse_key_value(char **stringp, char **keyp, char **valuep)
     *valuep = value;
     return true;
 }
+
+/* Encode a dump ports request for 'port', the encoded message
+ * will be fore Open Flow version 'ofp_version'. Returns message
+ * as a struct ofpbuf. Returns encoded message on success, NULL on error */
+struct ofpbuf *
+ofputil_encode_dump_ports_request(enum ofp_version ofp_version, int16_t port)
+{
+    struct ofpbuf *request;
+
+    switch (ofp_version) {
+    case OFP10_VERSION: {
+        struct ofp10_port_stats_request *req;
+        request = ofpraw_alloc(OFPRAW_OFPST10_PORT_REQUEST, ofp_version, 0);
+        req = ofpbuf_put_zeros(request, sizeof *req);
+        req->port_no = htons(port);
+        break;
+    }
+    case OFP11_VERSION:
+    case OFP12_VERSION: {
+        struct ofp11_port_stats_request *req;
+        request = ofpraw_alloc(OFPRAW_OFPST11_PORT_REQUEST, ofp_version, 0);
+        req = ofpbuf_put_zeros(request, sizeof *req);
+        req->port_no = ofputil_port_to_ofp11(port);
+        break;
+    }
+    default:
+        NOT_REACHED();
+    }
+
+    return request;
+}
+
+static void
+ofputil_port_stats_to_ofp10(const struct ofputil_port_stats *ops,
+                            struct ofp10_port_stats *ps10)
+{
+    ps10->port_no = htons(ops->port_no);
+    memset(ps10->pad, 0, sizeof ps10->pad);
+    put_32aligned_be64(&ps10->rx_packets, htonll(ops->stats.rx_packets));
+    put_32aligned_be64(&ps10->tx_packets, htonll(ops->stats.tx_packets));
+    put_32aligned_be64(&ps10->rx_bytes, htonll(ops->stats.rx_bytes));
+    put_32aligned_be64(&ps10->tx_bytes, htonll(ops->stats.tx_bytes));
+    put_32aligned_be64(&ps10->rx_dropped, htonll(ops->stats.rx_dropped));
+    put_32aligned_be64(&ps10->tx_dropped, htonll(ops->stats.tx_dropped));
+    put_32aligned_be64(&ps10->rx_errors, htonll(ops->stats.rx_errors));
+    put_32aligned_be64(&ps10->tx_errors, htonll(ops->stats.tx_errors));
+    put_32aligned_be64(&ps10->rx_frame_err, htonll(ops->stats.rx_frame_errors));
+    put_32aligned_be64(&ps10->rx_over_err, htonll(ops->stats.rx_over_errors));
+    put_32aligned_be64(&ps10->rx_crc_err, htonll(ops->stats.rx_crc_errors));
+    put_32aligned_be64(&ps10->collisions, htonll(ops->stats.collisions));
+}
+
+static void
+ofputil_port_stats_to_ofp11(const struct ofputil_port_stats *ops,
+                            struct ofp11_port_stats *ps11)
+{
+    ps11->port_no = ofputil_port_to_ofp11(ops->port_no);
+    memset(ps11->pad, 0, sizeof ps11->pad);
+    ps11->rx_packets = htonll(ops->stats.rx_packets);
+    ps11->tx_packets = htonll(ops->stats.tx_packets);
+    ps11->rx_bytes = htonll(ops->stats.rx_bytes);
+    ps11->tx_bytes = htonll(ops->stats.tx_bytes);
+    ps11->rx_dropped = htonll(ops->stats.rx_dropped);
+    ps11->tx_dropped = htonll(ops->stats.tx_dropped);
+    ps11->rx_errors = htonll(ops->stats.rx_errors);
+    ps11->tx_errors = htonll(ops->stats.tx_errors);
+    ps11->rx_frame_err = htonll(ops->stats.rx_frame_errors);
+    ps11->rx_over_err = htonll(ops->stats.rx_over_errors);
+    ps11->rx_crc_err = htonll(ops->stats.rx_crc_errors);
+    ps11->collisions = htonll(ops->stats.collisions);
+}
+
+/* Encode a ports stat for 'ops' and append it to 'replies'. */
+void
+ofputil_append_port_stat(struct list *replies,
+                         const struct ofputil_port_stats *ops)
+{
+    struct ofpbuf *msg = ofpbuf_from_list(list_back(replies));
+    struct ofp_header *oh = msg->data;
+
+    switch ((enum ofp_version)oh->version) {
+    case OFP12_VERSION:
+    case OFP11_VERSION: {
+        struct ofp11_port_stats *reply = ofpmp_append(replies, sizeof *reply);
+        ofputil_port_stats_to_ofp11(ops, reply);
+        break;
+    }
+
+    case OFP10_VERSION: {
+        struct ofp10_port_stats *reply = ofpmp_append(replies, sizeof *reply);
+        ofputil_port_stats_to_ofp10(ops, reply);
+        break;
+    }
+
+    default:
+        NOT_REACHED();
+    }
+}
+
+static enum ofperr
+ofputil_port_stats_from_ofp10(struct ofputil_port_stats *ops,
+                              const struct ofp10_port_stats *ps10)
+{
+    memset(ops, 0, sizeof *ops);
+
+    ops->port_no = ntohs(ps10->port_no);
+    ops->stats.rx_packets = ntohll(get_32aligned_be64(&ps10->rx_packets));
+    ops->stats.tx_packets = ntohll(get_32aligned_be64(&ps10->tx_packets));
+    ops->stats.rx_bytes = ntohll(get_32aligned_be64(&ps10->rx_bytes));
+    ops->stats.tx_bytes = ntohll(get_32aligned_be64(&ps10->tx_bytes));
+    ops->stats.rx_dropped = ntohll(get_32aligned_be64(&ps10->rx_dropped));
+    ops->stats.tx_dropped = ntohll(get_32aligned_be64(&ps10->tx_dropped));
+    ops->stats.rx_errors = ntohll(get_32aligned_be64(&ps10->rx_errors));
+    ops->stats.tx_errors = ntohll(get_32aligned_be64(&ps10->tx_errors));
+    ops->stats.rx_frame_errors =
+        ntohll(get_32aligned_be64(&ps10->rx_frame_err));
+    ops->stats.rx_over_errors = ntohll(get_32aligned_be64(&ps10->rx_over_err));
+    ops->stats.rx_crc_errors = ntohll(get_32aligned_be64(&ps10->rx_crc_err));
+    ops->stats.collisions = ntohll(get_32aligned_be64(&ps10->collisions));
+
+    return 0;
+}
+
+static enum ofperr
+ofputil_port_stats_from_ofp11(struct ofputil_port_stats *ops,
+                              const struct ofp11_port_stats *ps11)
+{
+    enum ofperr error;
+
+    memset(ops, 0, sizeof *ops);
+    error = ofputil_port_from_ofp11(ps11->port_no, &ops->port_no);
+    if (error) {
+        return error;
+    }
+
+    ops->stats.rx_packets = ntohll(ps11->rx_packets);
+    ops->stats.tx_packets = ntohll(ps11->tx_packets);
+    ops->stats.rx_bytes = ntohll(ps11->rx_bytes);
+    ops->stats.tx_bytes = ntohll(ps11->tx_bytes);
+    ops->stats.rx_dropped = ntohll(ps11->rx_dropped);
+    ops->stats.tx_dropped = ntohll(ps11->tx_dropped);
+    ops->stats.rx_errors = ntohll(ps11->rx_errors);
+    ops->stats.tx_errors = ntohll(ps11->tx_errors);
+    ops->stats.rx_frame_errors = ntohll(ps11->rx_frame_err);
+    ops->stats.rx_over_errors = ntohll(ps11->rx_over_err);
+    ops->stats.rx_crc_errors = ntohll(ps11->rx_crc_err);
+    ops->stats.collisions = ntohll(ps11->collisions);
+
+    return 0;
+}
+
+/* Returns the number of port stats elements in OFPTYPE_PORT_STATS_REPLY
+ * message 'oh'. */
+size_t
+ofputil_count_port_stats(const struct ofp_header *oh)
+{
+    struct ofpbuf b;
+
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
+    ofpraw_pull_assert(&b);
+
+    BUILD_ASSERT(sizeof(struct ofp10_port_stats) ==
+                 sizeof(struct ofp11_port_stats));
+    return b.size / sizeof(struct ofp10_port_stats);
+}
+
+/* Converts an OFPST_PORT_STATS reply in 'msg' into an abstract
+ * ofputil_port_stats in 'ps'.
+ *
+ * Multiple OFPST_PORT_STATS replies can be packed into a single OpenFlow
+ * message.  Calling this function multiple times for a single 'msg' iterates
+ * through the replies.  The caller must initially leave 'msg''s layer pointers
+ * null and not modify them between calls.
+ *
+ * Returns 0 if successful, EOF if no replies were left in this 'msg',
+ * otherwise a positive errno value. */
+int
+ofputil_decode_port_stats(struct ofputil_port_stats *ps, struct ofpbuf *msg)
+{
+    enum ofperr error;
+    enum ofpraw raw;
+
+    error = (msg->l2
+             ? ofpraw_decode(&raw, msg->l2)
+             : ofpraw_pull(&raw, msg));
+    if (error) {
+        return error;
+    }
+
+    if (!msg->size) {
+        return EOF;
+    } else if (raw == OFPRAW_OFPST11_PORT_REPLY) {
+        const struct ofp11_port_stats *ps11;
+
+        ps11 = ofpbuf_try_pull(msg, sizeof *ps11);
+        if (!ps11) {
+            VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_PORT reply has %zu leftover "
+                         "bytes at end", msg->size);
+            return OFPERR_OFPBRC_BAD_LEN;
+        }
+        return ofputil_port_stats_from_ofp11(ps, ps11);
+    } else if (raw == OFPRAW_OFPST10_PORT_REPLY) {
+        const struct ofp10_port_stats *ps10;
+
+        ps10 = ofpbuf_try_pull(msg, sizeof *ps10);
+        if (!ps10) {
+            VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_PORT reply has %zu leftover "
+                         "bytes at end", msg->size);
+            return OFPERR_OFPBRC_BAD_LEN;
+        }
+        return ofputil_port_stats_from_ofp10(ps, ps10);
+    } else {
+        NOT_REACHED();
+    }
+
+}
+
+/* Parse a port status request message into a 16 bit OpenFlow 1.0
+ * port number and stores the latter in '*ofp10_port'.
+ * Returns 0 if successful, otherwise an OFPERR_* number. */
+enum ofperr
+ofputil_decode_port_stats_request(const struct ofp_header *request,
+                                  uint16_t *ofp10_port)
+{
+    switch ((enum ofp_version)request->version) {
+    case OFP12_VERSION:
+    case OFP11_VERSION: {
+        const struct ofp11_port_stats_request *psr11 = ofpmsg_body(request);
+        return ofputil_port_from_ofp11(psr11->port_no, ofp10_port);
+    }
+
+    case OFP10_VERSION: {
+        const struct ofp10_port_stats_request *psr10 = ofpmsg_body(request);
+        *ofp10_port = ntohs(psr10->port_no);
+        return 0;
+    }
+
+    default:
+        NOT_REACHED();
+    }
+}
+
+/* Parse a queue status request message into 'oqsr'.
+ * Returns 0 if successful, otherwise an OFPERR_* number. */
+enum ofperr
+ofputil_decode_queue_stats_request(const struct ofp_header *request,
+                                   struct ofputil_queue_stats_request *oqsr)
+{
+    switch ((enum ofp_version)request->version) {
+    case OFP12_VERSION:
+    case OFP11_VERSION: {
+        const struct ofp11_queue_stats_request *qsr11 = ofpmsg_body(request);
+        oqsr->queue_id = ntohl(qsr11->queue_id);
+        return ofputil_port_from_ofp11(qsr11->port_no, &oqsr->port_no);
+    }
+
+    case OFP10_VERSION: {
+        const struct ofp10_queue_stats_request *qsr11 = ofpmsg_body(request);
+        oqsr->queue_id = ntohl(qsr11->queue_id);
+        oqsr->port_no = ntohs(qsr11->port_no);
+        return 0;
+    }
+
+    default:
+        NOT_REACHED();
+    }
+}
+
+/* Encode a queue statsrequest for 'oqsr', the encoded message
+ * will be fore Open Flow version 'ofp_version'. Returns message
+ * as a struct ofpbuf. Returns encoded message on success, NULL on error */
+struct ofpbuf *
+ofputil_encode_queue_stats_request(enum ofp_version ofp_version,
+                                   const struct ofputil_queue_stats_request *oqsr)
+{
+    struct ofpbuf *request;
+
+    switch (ofp_version) {
+    case OFP11_VERSION:
+    case OFP12_VERSION: {
+        struct ofp11_queue_stats_request *req;
+        request = ofpraw_alloc(OFPRAW_OFPST11_QUEUE_REQUEST, ofp_version, 0);
+        req = ofpbuf_put_zeros(request, sizeof *req);
+        req->port_no = ofputil_port_to_ofp11(oqsr->port_no);
+        req->queue_id = htonl(oqsr->queue_id);
+        break;
+    }
+    case OFP10_VERSION: {
+        struct ofp10_queue_stats_request *req;
+        request = ofpraw_alloc(OFPRAW_OFPST10_QUEUE_REQUEST, ofp_version, 0);
+        req = ofpbuf_put_zeros(request, sizeof *req);
+        req->port_no = htons(oqsr->port_no);
+        req->queue_id = htonl(oqsr->queue_id);
+        break;
+    }
+    default:
+        NOT_REACHED();
+    }
+
+    return request;
+}
+
+/* Returns the number of queue stats elements in OFPTYPE_QUEUE_STATS_REPLY
+ * message 'oh'. */
+size_t
+ofputil_count_queue_stats(const struct ofp_header *oh)
+{
+    struct ofpbuf b;
+
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
+    ofpraw_pull_assert(&b);
+
+    BUILD_ASSERT(sizeof(struct ofp10_queue_stats) ==
+                 sizeof(struct ofp11_queue_stats));
+    return b.size / sizeof(struct ofp10_queue_stats);
+}
+
+static enum ofperr
+ofputil_queue_stats_from_ofp10(struct ofputil_queue_stats *oqs,
+                               const struct ofp10_queue_stats *qs10)
+{
+    oqs->port_no = ntohs(qs10->port_no);
+    oqs->queue_id = ntohl(qs10->queue_id);
+    oqs->stats.tx_bytes = ntohll(get_32aligned_be64(&qs10->tx_bytes));
+    oqs->stats.tx_packets = ntohll(get_32aligned_be64(&qs10->tx_packets));
+    oqs->stats.tx_errors = ntohll(get_32aligned_be64(&qs10->tx_errors));
+
+    return 0;
+}
+
+static enum ofperr
+ofputil_queue_stats_from_ofp11(struct ofputil_queue_stats *oqs,
+                               const struct ofp11_queue_stats *qs11)
+{
+    enum ofperr error;
+
+    error = ofputil_port_from_ofp11(qs11->port_no, &oqs->port_no);
+    if (error) {
+        return error;
+    }
+
+    oqs->queue_id = ntohl(qs11->queue_id);
+    oqs->stats.tx_bytes = ntohll(qs11->tx_bytes);
+    oqs->stats.tx_packets = ntohll(qs11->tx_packets);
+    oqs->stats.tx_errors = ntohll(qs11->tx_errors);
+
+    return 0;
+}
+
+/* Converts an OFPST_QUEUE_STATS reply in 'msg' into an abstract
+ * ofputil_queue_stats in 'qs'.
+ *
+ * Multiple OFPST_QUEUE_STATS replies can be packed into a single OpenFlow
+ * message.  Calling this function multiple times for a single 'msg' iterates
+ * through the replies.  The caller must initially leave 'msg''s layer pointers
+ * null and not modify them between calls.
+ *
+ * Returns 0 if successful, EOF if no replies were left in this 'msg',
+ * otherwise a positive errno value. */
+int
+ofputil_decode_queue_stats(struct ofputil_queue_stats *qs, struct ofpbuf *msg)
+{
+    enum ofperr error;
+    enum ofpraw raw;
+
+    error = (msg->l2
+             ? ofpraw_decode(&raw, msg->l2)
+             : ofpraw_pull(&raw, msg));
+    if (error) {
+        return error;
+    }
+
+    if (!msg->size) {
+        return EOF;
+    } else if (raw == OFPRAW_OFPST11_QUEUE_REPLY) {
+        const struct ofp11_queue_stats *qs11;
+
+        qs11 = ofpbuf_try_pull(msg, sizeof *qs11);
+        if (!qs11) {
+            VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_QUEUE reply has %zu leftover "
+                         "bytes at end", msg->size);
+            return OFPERR_OFPBRC_BAD_LEN;
+        }
+        return ofputil_queue_stats_from_ofp11(qs, qs11);
+    } else if (raw == OFPRAW_OFPST10_QUEUE_REPLY) {
+        const struct ofp10_queue_stats *qs10;
+
+        qs10 = ofpbuf_try_pull(msg, sizeof *qs10);
+        if (!qs10) {
+            VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_QUEUE reply has %zu leftover "
+                         "bytes at end", msg->size);
+            return OFPERR_OFPBRC_BAD_LEN;
+        }
+        return ofputil_queue_stats_from_ofp10(qs, qs10);
+    } else {
+        NOT_REACHED();
+    }
+}
+
+static void
+ofputil_queue_stats_to_ofp10(const struct ofputil_queue_stats *oqs,
+                             struct ofp10_queue_stats *qs10)
+{
+    qs10->port_no = htons(oqs->port_no);
+    memset(qs10->pad, 0, sizeof qs10->pad);
+    qs10->queue_id = htonl(oqs->queue_id);
+    put_32aligned_be64(&qs10->tx_bytes, htonll(oqs->stats.tx_bytes));
+    put_32aligned_be64(&qs10->tx_packets, htonll(oqs->stats.tx_packets));
+    put_32aligned_be64(&qs10->tx_errors, htonll(oqs->stats.tx_errors));
+}
+
+static void
+ofputil_queue_stats_to_ofp11(const struct ofputil_queue_stats *oqs,
+                             struct ofp11_queue_stats *qs11)
+{
+    qs11->port_no = ofputil_port_to_ofp11(oqs->port_no);
+    qs11->queue_id = htonl(oqs->queue_id);
+    qs11->tx_bytes = htonll(oqs->stats.tx_bytes);
+    qs11->tx_packets = htonll(oqs->stats.tx_packets);
+    qs11->tx_errors = htonll(oqs->stats.tx_errors);
+}
+
+/* Encode a queue stat for 'oqs' and append it to 'replies'. */
+void
+ofputil_append_queue_stat(struct list *replies,
+                          const struct ofputil_queue_stats *oqs)
+{
+    struct ofpbuf *msg = ofpbuf_from_list(list_back(replies));
+    struct ofp_header *oh = msg->data;
+
+    switch ((enum ofp_version)oh->version) {
+    case OFP12_VERSION:
+    case OFP11_VERSION: {
+        struct ofp11_queue_stats *reply = ofpmp_append(replies, sizeof *reply);;
+        ofputil_queue_stats_to_ofp11(oqs, reply);
+        break;
+    }
+
+    case OFP10_VERSION: {
+        struct ofp10_queue_stats *reply = ofpmp_append(replies, sizeof *reply);;
+        ofputil_queue_stats_to_ofp10(oqs, reply);
+        break;
+    }
+
+    default:
+        NOT_REACHED();
+    }
+}
index 6f5113e..39575ba 100644 (file)
@@ -17,46 +17,25 @@ OFPAT10_ACTION(OFPAT10_SET_TP_DST,   ofp_action_tp_port,  "mod_tp_dst")
 OFPAT10_ACTION(OFPAT10_ENQUEUE,      ofp_action_enqueue,  "enqueue")
 
 #ifndef OFPAT11_ACTION
-#define OFPAT11_ACTION(ENUM, STRUCT, NAME)
+#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)
 #endif
-OFPAT11_ACTION(OFPAT11_OUTPUT,       ofp11_action_output, "output")
-OFPAT11_ACTION(OFPAT11_SET_VLAN_VID, ofp_action_vlan_vid, "mod_vlan_vid")
-OFPAT11_ACTION(OFPAT11_SET_VLAN_PCP, ofp_action_vlan_pcp, "mod_vlan_pcp")
-OFPAT11_ACTION(OFPAT11_SET_DL_SRC,   ofp_action_dl_addr,  "mod_dl_src")
-OFPAT11_ACTION(OFPAT11_SET_DL_DST,   ofp_action_dl_addr,  "mod_dl_dst")
-OFPAT11_ACTION(OFPAT11_SET_NW_SRC,   ofp_action_nw_addr,  "mod_nw_src")
-OFPAT11_ACTION(OFPAT11_SET_NW_DST,   ofp_action_nw_addr,  "mod_nw_dst")
-OFPAT11_ACTION(OFPAT11_SET_NW_TOS,   ofp_action_nw_tos,   "mod_nw_tos")
-//OFPAT11_ACTION(OFPAT11_SET_NW_ECN,   ofp11_action_nw_ecn, "mod_nw_ecn")
-OFPAT11_ACTION(OFPAT11_SET_TP_SRC,   ofp_action_tp_port,  "mod_tp_src")
-OFPAT11_ACTION(OFPAT11_SET_TP_DST,   ofp_action_tp_port,  "mod_tp_dst")
-//OFPAT11_ACTION(OFPAT11_PUSH_VLAN,    ofp11_action_push,   "push_vlan")
-//OFPAT11_ACTION(OFPAT11_POP_VLAN,     ofp_action_header,   "pop_vlan")
-//OFPAT11_ACTION(OFPAT11_SET_QUEUE,    ofp11_action_set_queue, "set_queue")
-//OFPAT11_ACTION(OFPAT11_SET_NW_TTL,   ofp11_action_nw_ttl, "set_nw_ttl")
-//OFPAT11_ACTION(OFPAT11_DEC_NW_TTL,   ofp_action_header,   "dec_ttl")
-
-#ifndef OFPAT12_ACTION
-#define OFPAT12_ACTION(ENUM, STRUCT, NAME)
-#endif
-//OFPAT12_ACTION(OFPAT12_OUTPUT, , "output")
-//OFPAT12_ACTION(OFPAT12_COPY_TTL_OUT, ofp_action_header, "copy_ttl_out")
-//OFPAT12_ACTION(OFPAT12_COPY_TTL_IN, ofp_action_header, "copy_ttl_in")
-//OFPAT12_ACTION(OFPAT12_SET_MPLS_TTL, , "set_mpls_ttl")
-//OFPAT12_ACTION(OFPAT12_DEC_MPLS_TTL, ofp_action_header, "dec_mpls_ttl")
-//OFPAT12_ACTION(OFPAT12_PUSH_VLAN, , "push_vlan")
-//OFPAT12_ACTION(OFPAT12_POP_VLAN, ofp_action_header, "pop_vlan")
-//OFPAT12_ACTION(OFPAT12_PUSH_MPLS, , "push_mpls")
-//OFPAT12_ACTION(OFPAT12_POP_MPLS, , "pop_mpls")
-//OFPAT12_ACTION(OFPAT12_SET_QUEUE, , "set_queue")
-//OFPAT12_ACTION(OFPAT12_GROUP, , "group")
-//OFPAT12_ACTION(OFPAT12_SET_NW_TTL, , "set_nw_ttl")
-//OFPAT12_ACTION(OFPAT12_DEC_NW_TTL, ofp_action_header, "dec_ttl")
-//Use non-NULL name for OFPAT12_SET_FIELD once the code for
-//the OFPUTIL_OFPAT12_SET_FIELD case in parse_named_action() is implemented
-//OFPAT12_ACTION(OFPAT12_SET_FIELD, ofp12_action_set_field, "set_field")
-OFPAT12_ACTION(OFPAT12_SET_FIELD, ofp12_action_set_field, NULL)
-//OFPAT12_ACTION(OFPAT12_EXPERIMENTER, , )
+OFPAT11_ACTION(OFPAT11_OUTPUT,       ofp11_action_output, 0, "output")
+OFPAT11_ACTION(OFPAT11_SET_VLAN_VID, ofp_action_vlan_vid, 0, "mod_vlan_vid")
+OFPAT11_ACTION(OFPAT11_SET_VLAN_PCP, ofp_action_vlan_pcp, 0, "mod_vlan_pcp")
+OFPAT11_ACTION(OFPAT11_SET_DL_SRC,   ofp_action_dl_addr,  0, "mod_dl_src")
+OFPAT11_ACTION(OFPAT11_SET_DL_DST,   ofp_action_dl_addr,  0, "mod_dl_dst")
+OFPAT11_ACTION(OFPAT11_SET_NW_SRC,   ofp_action_nw_addr,  0, "mod_nw_src")
+OFPAT11_ACTION(OFPAT11_SET_NW_DST,   ofp_action_nw_addr,  0, "mod_nw_dst")
+OFPAT11_ACTION(OFPAT11_SET_NW_TOS,   ofp_action_nw_tos,   0, "mod_nw_tos")
+//OFPAT11_ACTION(OFPAT11_SET_NW_ECN,   ofp11_action_nw_ecn, "0, mod_nw_ecn")
+OFPAT11_ACTION(OFPAT11_SET_TP_SRC,   ofp_action_tp_port,  0, "mod_tp_src")
+OFPAT11_ACTION(OFPAT11_SET_TP_DST,   ofp_action_tp_port,  0, "mod_tp_dst")
+OFPAT11_ACTION(OFPAT11_PUSH_VLAN,    ofp11_action_push,   0, "push_vlan")
+OFPAT11_ACTION(OFPAT11_POP_VLAN,     ofp_action_header,   0, "pop_vlan")
+//OFPAT11_ACTION(OFPAT11_SET_QUEUE,    ofp11_action_set_queue, 0, "set_queue")
+//OFPAT11_ACTION(OFPAT11_SET_NW_TTL,   ofp11_action_nw_ttl, 0, "set_nw_ttl")
+OFPAT11_ACTION(OFPAT11_DEC_NW_TTL,   ofp_action_header,   0, NULL)
+OFPAT11_ACTION(OFPAT12_SET_FIELD,    ofp12_action_set_field, 1, "set_field")
 
 #ifndef NXAST_ACTION
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)
@@ -81,8 +60,9 @@ NXAST_ACTION(NXAST_DEC_TTL,         nx_action_header,       0, "dec_ttl")
 NXAST_ACTION(NXAST_FIN_TIMEOUT,     nx_action_fin_timeout,  0, "fin_timeout")
 NXAST_ACTION(NXAST_CONTROLLER,      nx_action_controller,   0, "controller")
 NXAST_ACTION(NXAST_DEC_TTL_CNT_IDS, nx_action_cnt_ids,      1, NULL)
+NXAST_ACTION(NXAST_WRITE_METADATA,  nx_action_write_metadata, 0,
+             "write_metadata")
 
 #undef OFPAT10_ACTION
 #undef OFPAT11_ACTION
-#undef OFPAT12_ACTION
 #undef NXAST_ACTION
index 4e9f946..b6268da 100644 (file)
@@ -36,7 +36,7 @@ enum ofperr ofputil_port_from_ofp11(ovs_be32 ofp11_port, uint16_t *ofp10_port);
 ovs_be32 ofputil_port_to_ofp11(uint16_t ofp10_port);
 
 enum ofperr ofputil_check_output_port(uint16_t ofp_port, int max_ports);
-uint16_t ofputil_port_from_string(const char *);
+bool ofputil_port_from_string(const char *, uint16_t *portp);
 void ofputil_format_port(uint16_t port, struct ds *);
 
 /* Converting OFPFW10_NW_SRC_MASK and OFPFW10_NW_DST_MASK wildcard bit counts
@@ -131,7 +131,8 @@ ovs_be16 ofputil_dl_type_from_openflow(ovs_be16 ofp_dl_type);
 bool ofputil_packet_in_format_is_valid(enum nx_packet_in_format);
 int ofputil_packet_in_format_from_string(const char *);
 const char *ofputil_packet_in_format_to_string(enum nx_packet_in_format);
-struct ofpbuf *ofputil_make_set_packet_in_format(enum nx_packet_in_format);
+struct ofpbuf *ofputil_make_set_packet_in_format(enum ofp_version,
+                                                 enum nx_packet_in_format);
 
 /* NXT_FLOW_MOD_TABLE_ID extension. */
 struct ofpbuf *ofputil_make_flow_mod_table_id(bool flow_mod_table_id);
@@ -243,6 +244,7 @@ struct ofputil_flow_removed {
     uint16_t priority;
     ovs_be64 cookie;
     uint8_t reason;             /* One of OFPRR_*. */
+    uint8_t table_id;           /* 255 if message didn't include table ID. */
     uint32_t duration_sec;
     uint32_t duration_nsec;
     uint16_t idle_timeout;
@@ -538,6 +540,7 @@ bool ofputil_frag_handling_from_string(const char *, enum ofp_config_flags *);
  * OFPUTIL_OFPAT10_ENQUEUE
  * OFPUTIL_NXAST_RESUBMIT
  * OFPUTIL_NXAST_SET_TUNNEL
+ * OFPUTIL_NXAST_SET_METADATA
  * OFPUTIL_NXAST_SET_QUEUE
  * OFPUTIL_NXAST_POP_QUEUE
  * OFPUTIL_NXAST_REG_MOVE
@@ -558,19 +561,17 @@ bool ofputil_frag_handling_from_string(const char *, enum ofp_config_flags *);
  */
 enum OVS_PACKED_ENUM ofputil_action_code {
     OFPUTIL_ACTION_INVALID,
-#define OFPAT10_ACTION(ENUM, STRUCT, NAME)           OFPUTIL_##ENUM,
-#define OFPAT11_ACTION(ENUM, STRUCT, NAME)           OFPUTIL_##ENUM,
-#define OFPAT12_ACTION(ENUM, STRUCT, NAME)           OFPUTIL_##ENUM,
-#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) OFPUTIL_##ENUM,
+#define OFPAT10_ACTION(ENUM, STRUCT, NAME)             OFPUTIL_##ENUM,
+#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) OFPUTIL_##ENUM,
+#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)   OFPUTIL_##ENUM,
 #include "ofp-util.def"
 };
 
 /* The number of values of "enum ofputil_action_code". */
 enum {
-#define OFPAT10_ACTION(ENUM, STRUCT, NAME)           + 1
-#define OFPAT11_ACTION(ENUM, STRUCT, NAME)           + 1
-#define OFPAT12_ACTION(ENUM, STRUCT, NAME)           + 1
-#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) + 1
+#define OFPAT10_ACTION(ENUM, STRUCT, NAME)             + 1
+#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) + 1
+#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)   + 1
     OFPUTIL_N_ACTIONS = 1
 #include "ofp-util.def"
 };
@@ -596,10 +597,7 @@ void *ofputil_put_action(enum ofputil_action_code, struct ofpbuf *buf);
 #define OFPAT10_ACTION(ENUM, STRUCT, NAME)              \
     void ofputil_init_##ENUM(struct STRUCT *);          \
     struct STRUCT *ofputil_put_##ENUM(struct ofpbuf *);
-#define OFPAT11_ACTION(ENUM, STRUCT, NAME)              \
-    void ofputil_init_##ENUM(struct STRUCT *);          \
-    struct STRUCT *ofputil_put_##ENUM(struct ofpbuf *);
-#define OFPAT12_ACTION(ENUM, STRUCT, NAME)              \
+#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)  \
     void ofputil_init_##ENUM(struct STRUCT *);          \
     struct STRUCT *ofputil_put_##ENUM(struct ofpbuf *);
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)    \
@@ -623,4 +621,43 @@ union ofp_action *ofputil_actions_clone(const union ofp_action *, size_t n);
 /* Handy utility for parsing flows and actions. */
 bool ofputil_parse_key_value(char **stringp, char **keyp, char **valuep);
 
+struct ofpbuf *ofputlil_dump_ports(enum ofp_version ofp_version, int16_t port);
+
+struct ofputil_port_stats {
+    uint16_t port_no;
+    struct netdev_stats stats;
+};
+
+struct ofpbuf *ofputil_encode_dump_ports_request(enum ofp_version ofp_version,
+                                                 int16_t port);
+void ofputil_append_port_stat(struct list *replies,
+                              const struct ofputil_port_stats *ops);
+size_t ofputil_count_port_stats(const struct ofp_header *);
+int ofputil_decode_port_stats(struct ofputil_port_stats *, struct ofpbuf *msg);
+enum ofperr ofputil_decode_port_stats_request(const struct ofp_header *request,
+                                              uint16_t *ofp10_port);
+
+struct ofputil_queue_stats_request {
+    uint16_t port_no;
+    uint32_t queue_id;
+};
+
+enum ofperr
+ofputil_decode_queue_stats_request(const struct ofp_header *request,
+                                   struct ofputil_queue_stats_request *oqsr);
+struct ofpbuf *
+ofputil_encode_queue_stats_request(enum ofp_version ofp_version,
+                                   const struct ofputil_queue_stats_request *oqsr);
+
+struct ofputil_queue_stats {
+    uint16_t port_no;
+    uint32_t queue_id;
+    struct netdev_queue_stats stats;
+};
+
+size_t ofputil_count_queue_stats(const struct ofp_header *);
+int ofputil_decode_queue_stats(struct ofputil_queue_stats *qs, struct ofpbuf *msg);
+void ofputil_append_queue_stat(struct list *replies,
+                               const struct ofputil_queue_stats *oqs);
+
 #endif /* ofp-util.h */
index 6118852..be4b255 100644 (file)
@@ -70,6 +70,7 @@ struct ovsdb_idl {
     struct json *monitor_request_id;
     unsigned int last_monitor_request_seqno;
     unsigned int change_seqno;
+    bool verify_write_only;
 
     /* Database locking. */
     char *lock_name;            /* Name of lock we need, NULL if none. */
@@ -402,6 +403,16 @@ ovsdb_idl_force_reconnect(struct ovsdb_idl *idl)
 {
     jsonrpc_session_force_reconnect(idl->session);
 }
+
+/* Some IDL users should only write to write-only columns.  Furthermore,
+ * writing to a column which is not write-only can cause serious performance
+ * degradations for these users.  This function causes 'idl' to reject writes
+ * to columns which are not marked write only using ovsdb_idl_omit_alert(). */
+void
+ovsdb_idl_verify_write_only(struct ovsdb_idl *idl)
+{
+    idl->verify_write_only = true;
+}
 \f
 static unsigned char *
 ovsdb_idl_get_mode(struct ovsdb_idl *idl,
@@ -1824,6 +1835,7 @@ ovsdb_idl_txn_write(const struct ovsdb_idl_row *row_,
     struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
     const struct ovsdb_idl_table_class *class;
     size_t column_idx;
+    bool write_only;
 
     if (ovsdb_idl_row_is_synthetic(row)) {
         ovsdb_datum_destroy(datum, &column->type);
@@ -1832,12 +1844,20 @@ ovsdb_idl_txn_write(const struct ovsdb_idl_row *row_,
 
     class = row->table->class;
     column_idx = column - class->columns;
+    write_only = row->table->modes[column_idx] == OVSDB_IDL_MONITOR;
 
     assert(row->new != NULL);
     assert(column_idx < class->n_columns);
     assert(row->old == NULL ||
            row->table->modes[column_idx] & OVSDB_IDL_MONITOR);
 
+    if (row->table->idl->verify_write_only && !write_only) {
+        VLOG_ERR("Bug: Attempt to write to a read/write column (%s:%s) when"
+                 " explicitly configured not to.", class->name, column->name);
+        ovsdb_datum_destroy(datum, &column->type);
+        return;
+    }
+
     /* If this is a write-only column and the datum being written is the same
      * as the one already there, just skip the update entirely.  This is worth
      * optimizing because we have a lot of columns that get periodically
@@ -1849,9 +1869,8 @@ ovsdb_idl_txn_write(const struct ovsdb_idl_row *row_,
      * transaction only does writes of existing values, without making any real
      * changes, we will drop the whole transaction later in
      * ovsdb_idl_txn_commit().) */
-    if (row->table->modes[column_idx] == OVSDB_IDL_MONITOR
-        && ovsdb_datum_equals(ovsdb_idl_read(row, column),
-                              datum, &column->type)) {
+    if (write_only && ovsdb_datum_equals(ovsdb_idl_read(row, column),
+                                         datum, &column->type)) {
         ovsdb_datum_destroy(datum, &column->type);
         return;
     }
index c48ad1b..27008b7 100644 (file)
@@ -57,6 +57,7 @@ bool ovsdb_idl_is_lock_contended(const struct ovsdb_idl *);
 unsigned int ovsdb_idl_get_seqno(const struct ovsdb_idl *);
 bool ovsdb_idl_has_ever_connected(const struct ovsdb_idl *);
 void ovsdb_idl_force_reconnect(struct ovsdb_idl *);
+void ovsdb_idl_verify_write_only(struct ovsdb_idl *);
 \f
 /* Choosing columns and tables to replicate. */
 
index e5be1cb..e550be0 100644 (file)
@@ -177,7 +177,9 @@ void eth_addr_bitand(const uint8_t src[ETH_ADDR_LEN],
 
 #define ETH_TYPE_IP            0x0800
 #define ETH_TYPE_ARP           0x0806
-#define ETH_TYPE_VLAN          0x8100
+#define ETH_TYPE_VLAN_8021Q    0x8100
+#define ETH_TYPE_VLAN          ETH_TYPE_VLAN_8021Q
+#define ETH_TYPE_VLAN_8021AD   0x88a8
 #define ETH_TYPE_IPV6          0x86dd
 #define ETH_TYPE_LACP          0x8809
 #define ETH_TYPE_RARP          0x8035
@@ -325,6 +327,10 @@ void ip_format_masked(ovs_be32 ip, ovs_be32 mask, struct ds *);
 #endif
 
 /* TOS fields. */
+#define IP_ECN_NOT_ECT 0x0
+#define IP_ECN_ECT_1 0x01
+#define IP_ECN_ECT_0 0x02
+#define IP_ECN_CE 0x03
 #define IP_ECN_MASK 0x03
 #define IP_DSCP_MASK 0xfc
 
index 516cf13..7e328bc 100644 (file)
@@ -157,6 +157,7 @@ poll_immediate_wake(const char *where)
 static void
 log_wakeup(const char *where, const struct pollfd *pollfd, int timeout)
 {
+    static struct vlog_rate_limit trace_rl = VLOG_RATE_LIMIT_INIT(1, 1);
     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(10, 10);
     enum vlog_level level;
     int cpu_usage;
@@ -200,6 +201,11 @@ log_wakeup(const char *where, const struct pollfd *pollfd, int timeout)
     }
     if (cpu_usage >= 0) {
         ds_put_format(&s, " (%d%% CPU usage)", cpu_usage);
+
+        if (!vlog_should_drop(THIS_MODULE, level, &trace_rl)) {
+            ds_put_char(&s, '\n');
+            format_backtraces(&s, 2);
+        }
     }
     VLOG(level, "%s", ds_cstr(&s));
     ds_destroy(&s);
index 91dfc06..9f5c35f 100644 (file)
@@ -82,9 +82,7 @@ process_init(void)
     inited = true;
 
     /* Create notification pipe. */
-    xpipe(fds);
-    xset_nonblocking(fds[0]);
-    xset_nonblocking(fds[1]);
+    xpipe_nonblocking(fds);
 
     /* Set up child termination signal handler. */
     memset(&sa, 0, sizeof sa);
diff --git a/lib/route-table-stub.c b/lib/route-table-stub.c
new file mode 100644 (file)
index 0000000..fafad28
--- /dev/null
@@ -0,0 +1,47 @@
+/* Copyright (c) 2012 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 "route-table.h"
+
+#include "compiler.h"
+
+bool
+route_table_get_name(ovs_be32 ip OVS_UNUSED, char name[IFNAMSIZ] OVS_UNUSED)
+{
+    name[0] = '\0';
+    return false;
+}
+
+bool
+route_table_get_ifindex(ovs_be32 ip OVS_UNUSED, int *ifindex)
+{
+    *ifindex = 0;
+    return false;
+}
+
+void
+route_table_register(void)
+{
+}
+
+void
+route_table_unregister(void)
+{
+}
+
+void
+route_table_run(void)
+{
+}
index b712f7e..152afcf 100644 (file)
@@ -63,9 +63,7 @@ signal_init(void)
     static bool inited;
     if (!inited) {
         inited = true;
-        xpipe(fds);
-        xset_nonblocking(fds[0]);
-        xset_nonblocking(fds[1]);
+        xpipe_nonblocking(fds);
     }
 }
 
index 7c40ab8..a37dfe4 100644 (file)
@@ -39,7 +39,7 @@
 #include "poll-loop.h"
 #include "util.h"
 #include "vlog.h"
-#if AF_PACKET && __linux__
+#if AF_PACKET && LINUX_DATAPATH
 #include <linux/if_packet.h>
 #endif
 #ifdef HAVE_NETLINK
@@ -51,11 +51,9 @@ VLOG_DEFINE_THIS_MODULE(socket_util);
 
 /* #ifdefs make it a pain to maintain code: you have to try to build both ways.
  * Thus, this file compiles all of the code regardless of the target, by
- * writing "if (LINUX)" instead of "#ifdef __linux__". */
-#ifdef __linux__
-#define LINUX 1
-#else
-#define LINUX 0
+ * writing "if (LINUX_DATAPATH)" instead of "#ifdef __linux__". */
+#ifndef LINUX_DATAPATH
+#define LINUX_DATAPATH 0
 #endif
 
 #ifndef O_DIRECTORY
@@ -92,7 +90,7 @@ xset_nonblocking(int fd)
     }
 }
 
-static int
+int
 set_dscp(int fd, uint8_t dscp)
 {
     int val;
@@ -266,7 +264,7 @@ drain_rcvbuf(int fd)
          *
          * On other Unix-like OSes, MSG_TRUNC has no effect in the flags
          * argument. */
-        char buffer[LINUX ? 1 : 2048];
+        char buffer[LINUX_DATAPATH ? 1 : 2048];
         ssize_t n_bytes = recv(fd, buffer, sizeof buffer,
                                MSG_TRUNC | MSG_DONTWAIT);
         if (n_bytes <= 0 || n_bytes >= rcvbuf) {
@@ -335,7 +333,7 @@ make_sockaddr_un(const char *name, struct sockaddr_un *un, socklen_t *un_len,
     if (strlen(name) > MAX_UN_LEN) {
         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
 
-        if (LINUX) {
+        if (LINUX_DATAPATH) {
             /* 'name' is too long to fit in a sockaddr_un, but we have a
              * workaround for that on Linux: shorten it by opening a file
              * descriptor for the directory part of the name and indirecting
@@ -893,6 +891,14 @@ xpipe(int fds[2])
     }
 }
 
+void
+xpipe_nonblocking(int fds[2])
+{
+    xpipe(fds);
+    xset_nonblocking(fds[0]);
+    xset_nonblocking(fds[1]);
+}
+
 void
 xsocketpair(int domain, int type, int protocol, int fds[2])
 {
@@ -980,7 +986,7 @@ describe_sockaddr(struct ds *string, int fd,
             }
         }
 #endif
-#if AF_PACKET && __linux__
+#if AF_PACKET && LINUX_DATAPATH
         else if (ss.ss_family == AF_PACKET) {
             struct sockaddr_ll sll;
 
@@ -1010,7 +1016,7 @@ describe_sockaddr(struct ds *string, int fd,
 }
 
 
-#ifdef __linux__
+#ifdef LINUX_DATAPATH
 static void
 put_fd_filename(struct ds *string, int fd)
 {
@@ -1054,7 +1060,7 @@ describe_fd(int fd)
                               : S_ISFIFO(s.st_mode) ? "FIFO"
                               : S_ISLNK(s.st_mode) ? "symbolic link"
                               : "unknown"));
-#ifdef __linux__
+#ifdef LINUX_DATAPATH
         put_fd_filename(&string, fd);
 #endif
     }
index a0e7970..a00b32e 100644 (file)
@@ -27,6 +27,7 @@
 
 int set_nonblocking(int fd);
 void xset_nonblocking(int fd);
+int set_dscp(int fd, uint8_t dscp);
 
 int get_max_fds(void);
 
@@ -63,6 +64,7 @@ int fsync_parent_dir(const char *file_name);
 int get_mtime(const char *file_name, struct timespec *mtime);
 
 void xpipe(int fds[2]);
+void xpipe_nonblocking(int fds[2]);
 
 char *describe_fd(int fd);
 
index 6b782ec..f7e1234 100644 (file)
@@ -169,6 +169,7 @@ struct fd_pstream
     int fd;
     int (*accept_cb)(int fd, const struct sockaddr *, size_t sa_len,
                      struct stream **);
+    int (*set_dscp_cb)(int fd, uint8_t dscp);
     char *unlink_path;
 };
 
@@ -199,12 +200,14 @@ int
 new_fd_pstream(const char *name, int fd,
                int (*accept_cb)(int fd, const struct sockaddr *sa,
                                 size_t sa_len, struct stream **streamp),
+               int (*set_dscp_cb)(int fd, uint8_t dscp),
                char *unlink_path, struct pstream **pstreamp)
 {
     struct fd_pstream *ps = xmalloc(sizeof *ps);
     pstream_init(&ps->pstream, &fd_pstream_class, name);
     ps->fd = fd;
     ps->accept_cb = accept_cb;
+    ps->set_dscp_cb = set_dscp_cb;
     ps->unlink_path = unlink_path;
     *pstreamp = &ps->pstream;
     return 0;
@@ -254,13 +257,24 @@ pfd_wait(struct pstream *pstream)
     poll_fd_wait(ps->fd, POLLIN);
 }
 
+static int
+pfd_set_dscp(struct pstream *pstream, uint8_t dscp)
+{
+    struct fd_pstream *ps = fd_pstream_cast(pstream);
+    if (ps->set_dscp_cb) {
+        return ps->set_dscp_cb(ps->fd, dscp);
+    }
+    return 0;
+}
+
 static struct pstream_class fd_pstream_class = {
     "pstream",
     false,
     NULL,
     pfd_close,
     pfd_accept,
-    pfd_wait
+    pfd_wait,
+    pfd_set_dscp,
 };
 \f
 /* Helper functions. */
index 8026953..8b8b48f 100644 (file)
@@ -30,6 +30,7 @@ int new_fd_stream(const char *name, int fd, int connect_status,
 int new_fd_pstream(const char *name, int fd,
                    int (*accept_cb)(int fd, const struct sockaddr *,
                                     size_t sa_len, struct stream **),
+                   int (*set_dscp_cb)(int fd, uint8_t dscp),
                    char *unlink_path,
                    struct pstream **pstreamp);
 
index 0708c72..b39dcf0 100644 (file)
@@ -40,7 +40,6 @@ struct stream {
 void stream_init(struct stream *, const struct stream_class *,
                  int connect_status, const char *name);
 void stream_set_remote_ip(struct stream *, ovs_be32 remote_ip);
-void stream_set_dscp(struct stream *, uint8_t dscp);
 void stream_set_remote_port(struct stream *, ovs_be16 remote_port);
 void stream_set_local_ip(struct stream *, ovs_be32 local_ip);
 void stream_set_local_port(struct stream *, ovs_be16 local_port);
@@ -191,6 +190,9 @@ struct pstream_class {
     /* Arranges for the poll loop to wake up when a connection is ready to be
      * accepted on 'pstream'. */
     void (*wait)(struct pstream *pstream);
+
+    /* Set DSCP value of the listening socket. */
+    int (*set_dscp)(struct pstream *pstream, uint8_t dscp);
 };
 
 /* Active and passive stream classes. */
index 4a9dd4f..0ca5b18 100644 (file)
@@ -862,6 +862,13 @@ pssl_wait(struct pstream *pstream)
     poll_fd_wait(pssl->fd, POLLIN);
 }
 
+static int
+pssl_set_dscp(struct pstream *pstream, uint8_t dscp)
+{
+    struct pssl_pstream *pssl = pssl_pstream_cast(pstream);
+    return set_dscp(pssl->fd, dscp);
+}
+
 const struct pstream_class pssl_pstream_class = {
     "pssl",
     true,
@@ -869,6 +876,7 @@ const struct pstream_class pssl_pstream_class = {
     pssl_close,
     pssl_accept,
     pssl_wait,
+    pssl_set_dscp,
 };
 \f
 /*
index 9749293..05601e1 100644 (file)
@@ -117,7 +117,8 @@ ptcp_open(const char *name OVS_UNUSED, char *suffix, struct pstream **pstreamp,
 
     sprintf(bound_name, "ptcp:%"PRIu16":"IP_FMT,
             ntohs(sin.sin_port), IP_ARGS(&sin.sin_addr.s_addr));
-    return new_fd_pstream(bound_name, fd, ptcp_accept, NULL, pstreamp);
+    return new_fd_pstream(bound_name, fd, ptcp_accept, set_dscp, NULL,
+                          pstreamp);
 }
 
 static int
@@ -142,6 +143,7 @@ const struct pstream_class ptcp_pstream_class = {
     ptcp_open,
     NULL,
     NULL,
-    NULL
+    NULL,
+    NULL,
 };
 
index dde5996..4feefdf 100644 (file)
@@ -92,7 +92,7 @@ punix_open(const char *name OVS_UNUSED, char *suffix,
         return error;
     }
 
-    return new_fd_pstream(name, fd, punix_accept,
+    return new_fd_pstream(name, fd, punix_accept, NULL,
                           xstrdup(suffix), pstreamp);
 }
 
@@ -118,6 +118,7 @@ const struct pstream_class punix_pstream_class = {
     punix_open,
     NULL,
     NULL,
-    NULL
+    NULL,
+    NULL,
 };
 
index 2c7bfc3..2ee5731 100644 (file)
@@ -613,6 +613,15 @@ pstream_wait(struct pstream *pstream)
 {
     (pstream->class->wait)(pstream);
 }
+
+int
+pstream_set_dscp(struct pstream *pstream, uint8_t dscp)
+{
+    if (pstream->class->set_dscp) {
+        return pstream->class->set_dscp(pstream, dscp);
+    }
+    return 0;
+}
 \f
 /* Initializes 'stream' as a new stream named 'name', implemented via 'class'.
  * The initial connection status, supplied as 'connect_status', is interpreted
index 8ed0ff5..d2f2ebb 100644 (file)
@@ -65,6 +65,7 @@ void pstream_close(struct pstream *);
 int pstream_accept(struct pstream *, struct stream **);
 int pstream_accept_block(struct pstream *, struct stream **);
 void pstream_wait(struct pstream *);
+int pstream_set_dscp(struct pstream *, uint8_t dscp);
 \f
 /* Convenience functions. */
 
index 3d339e4..d853989 100644 (file)
@@ -18,6 +18,9 @@
 #include "timeval.h"
 #include <assert.h>
 #include <errno.h>
+#if HAVE_EXECINFO_H
+#include <execinfo.h>
+#endif
 #include <poll.h>
 #include <signal.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include "coverage.h"
 #include "dummy.h"
+#include "dynamic-string.h"
 #include "fatal-signal.h"
+#include "hash.h"
+#include "hmap.h"
 #include "signals.h"
 #include "unixctl.h"
 #include "util.h"
@@ -40,7 +46,7 @@ VLOG_DEFINE_THIS_MODULE(timeval);
  * to CLOCK_REALTIME. */
 static clockid_t monotonic_clock;
 
-/* Has a timer tick occurred? Only relevant if CACHE_TIME is 1.
+/* Has a timer tick occurred? Only relevant if CACHE_TIME is true.
  *
  * We initialize these to true to force time_init() to get called on the first
  * call to time_msec() or another function that queries the current time. */
@@ -58,15 +64,27 @@ static long long int boot_time;
 static struct timespec warp_offset; /* Offset added to monotonic_time. */
 static bool time_stopped;           /* Disables real-time updates, if true. */
 
-/* Time at which to die with SIGALRM (if not TIME_MIN). */
-static time_t deadline = TIME_MIN;
+/* Time in milliseconds at which to die with SIGALRM (if not LLONG_MAX). */
+static long long int deadline = LLONG_MAX;
+
+struct trace {
+    void *backtrace[32]; /* Populated by backtrace(). */
+    size_t n_frames;     /* Number of frames in 'backtrace'. */
+
+    /* format_backtraces() helper data. */
+    struct hmap_node node;
+    size_t count;
+};
+
+#define MAX_TRACES 50
+static struct trace traces[MAX_TRACES];
+static size_t trace_head = 0;
 
 static void set_up_timer(void);
 static void set_up_signal(int flags);
 static void sigalrm_handler(int);
 static void refresh_wall_if_ticked(void);
 static void refresh_monotonic_if_ticked(void);
-static time_t time_add(time_t, time_t);
 static void block_sigalrm(sigset_t *);
 static void unblock_sigalrm(const sigset_t *);
 static void log_poll_interval(long long int last_wakeup);
@@ -74,17 +92,51 @@ static struct rusage *get_recent_rusage(void);
 static void refresh_rusage(void);
 static void timespec_add(struct timespec *sum,
                          const struct timespec *a, const struct timespec *b);
+static unixctl_cb_func backtrace_cb;
+
+#ifndef HAVE_EXECINFO_H
+#define HAVE_EXECINFO_H 0
+
+static int
+backtrace(void **buffer OVS_UNUSED, int size OVS_UNUSED)
+{
+    NOT_REACHED();
+}
+
+static char **
+backtrace_symbols(void *const *buffer OVS_UNUSED, int size OVS_UNUSED)
+{
+    NOT_REACHED();
+}
+#endif
 
 /* Initializes the timetracking module, if not already initialized. */
 static void
 time_init(void)
 {
     static bool inited;
+
     if (inited) {
         return;
     }
     inited = true;
 
+    /* The implementation of backtrace() in glibc does some one time
+     * initialization which is not signal safe.  This can cause deadlocks if
+     * run from the signal handler.  As a workaround, force the initialization
+     * to happen here. */
+    if (HAVE_EXECINFO_H) {
+        void *bt[1];
+
+        backtrace(bt, ARRAY_SIZE(bt));
+    }
+
+    memset(traces, 0, sizeof traces);
+
+    if (HAVE_EXECINFO_H && CACHE_TIME) {
+        unixctl_command_register("backtrace", "", 0, 0, backtrace_cb, NULL);
+    }
+
     coverage_init();
 
     if (!clock_gettime(CLOCK_MONOTONIC, &monotonic_time)) {
@@ -94,10 +146,8 @@ time_init(void)
         VLOG_DBG("monotonic timer not available");
     }
 
-    if (CACHE_TIME) {
-        set_up_signal(SA_RESTART);
-        set_up_timer();
-    }
+    set_up_signal(SA_RESTART);
+    set_up_timer();
 
     boot_time = time_msec();
 }
@@ -149,6 +199,10 @@ set_up_timer(void)
     static timer_t timer_id;    /* "static" to avoid apparent memory leak. */
     struct itimerspec itimer;
 
+    if (!CACHE_TIME) {
+        return;
+    }
+
     if (timer_create(monotonic_clock, NULL, &timer_id)) {
         VLOG_FATAL("timer_create failed (%s)", strerror(errno));
     }
@@ -171,16 +225,7 @@ void
 time_postfork(void)
 {
     time_init();
-
-    if (CACHE_TIME) {
-        set_up_timer();
-    } else {
-        /* If we are not caching  kernel time, the only reason the timer should
-         * exist is if time_alarm() was called and deadline is set */
-        if (deadline != TIME_MIN) {
-            set_up_timer();
-        }
-    }
+    set_up_timer();
 }
 
 static void
@@ -212,7 +257,7 @@ refresh_monotonic(void)
 /* Forces a refresh of the current time from the kernel.  It is not usually
  * necessary to call this function, since the time will be refreshed
  * automatically at least every TIME_UPDATE_INTERVAL milliseconds.  If
- * CACHE_TIME is 0, we will always refresh the current time so this
+ * CACHE_TIME is false, we will always refresh the current time so this
  * function has no effect. */
 void
 time_refresh(void)
@@ -228,17 +273,6 @@ time_now(void)
     return monotonic_time.tv_sec;
 }
 
-/* Same as time_now() except does not write to static variables, for use in
- * signal handlers.  */
-static time_t
-time_now_sig(void)
-{
-    struct timespec cur_time;
-
-    clock_gettime(monotonic_clock, &cur_time);
-    return cur_time.tv_sec;
-}
-
 /* Returns the current time, in seconds. */
 time_t
 time_wall(void)
@@ -286,20 +320,20 @@ time_wall_timespec(struct timespec *ts)
 void
 time_alarm(unsigned int secs)
 {
+    long long int now;
+    long long int msecs;
+
     sigset_t oldsigs;
 
     time_init();
+    time_refresh();
+
+    now = time_msec();
+    msecs = secs * 1000;
 
     block_sigalrm(&oldsigs);
-    deadline = secs ? time_add(time_now(), secs) : TIME_MIN;
+    deadline = now < LLONG_MAX - msecs ? now + msecs : LLONG_MAX;
     unblock_sigalrm(&oldsigs);
-
-    if (!CACHE_TIME) {
-        /* If we aren't timing the gaps between kernel time refreshes we need to
-         * to start the timer up now */
-        set_up_signal(SA_RESTART);
-        set_up_timer();
-    }
 }
 
 /* Like poll(), except:
@@ -320,17 +354,22 @@ int
 time_poll(struct pollfd *pollfds, int n_pollfds, long long int timeout_when,
           int *elapsed)
 {
-    static long long int last_wakeup;
+    static long long int last_wakeup = 0;
     long long int start;
     sigset_t oldsigs;
     bool blocked;
     int retval;
 
     time_refresh();
-    log_poll_interval(last_wakeup);
+    if (last_wakeup) {
+        log_poll_interval(last_wakeup);
+    }
     coverage_clear();
     start = time_msec();
     blocked = false;
+
+    timeout_when = MIN(timeout_when, deadline);
+
     for (;;) {
         long long int now = time_msec();
         int time_left;
@@ -347,12 +386,21 @@ time_poll(struct pollfd *pollfds, int n_pollfds, long long int timeout_when,
         if (retval < 0) {
             retval = -errno;
         }
+
         time_refresh();
+        if (deadline <= time_msec()) {
+            fatal_signal_handler(SIGALRM);
+            if (retval < 0) {
+                retval = 0;
+            }
+            break;
+        }
+
         if (retval != -EINTR) {
             break;
         }
 
-        if (!blocked && deadline == TIME_MIN) {
+        if (!blocked && CACHE_TIME) {
             block_sigalrm(&oldsigs);
             blocked = true;
         }
@@ -366,22 +414,18 @@ time_poll(struct pollfd *pollfds, int n_pollfds, long long int timeout_when,
     return retval;
 }
 
-/* Returns the sum of 'a' and 'b', with saturation on overflow or underflow. */
-static time_t
-time_add(time_t a, time_t b)
-{
-    return (a >= 0
-            ? (b > TIME_MAX - a ? TIME_MAX : a + b)
-            : (b < TIME_MIN - a ? TIME_MIN : a + b));
-}
-
 static void
-sigalrm_handler(int sig_nr)
+sigalrm_handler(int sig_nr OVS_UNUSED)
 {
     wall_tick = true;
     monotonic_tick = true;
-    if (deadline != TIME_MIN && time_now_sig() > deadline) {
-        fatal_signal_handler(sig_nr);
+
+    if (HAVE_EXECINFO_H && CACHE_TIME) {
+        struct trace *trace = &traces[trace_head];
+
+        trace->n_frames = backtrace(trace->backtrace,
+                                    ARRAY_SIZE(trace->backtrace));
+        trace_head = (trace_head + 1) % MAX_TRACES;
     }
 }
 
@@ -471,66 +515,40 @@ timespec_add(struct timespec *sum,
 static void
 log_poll_interval(long long int last_wakeup)
 {
-    static unsigned int mean_interval; /* In 16ths of a millisecond. */
-    static unsigned int n_samples;
-
-    long long int now;
-    unsigned int interval;      /* In 16ths of a millisecond. */
-
-    /* Compute interval from last wakeup to now in 16ths of a millisecond,
-     * capped at 10 seconds (16000 in this unit). */
-    now = time_msec();
-    interval = MIN(10000, now - last_wakeup) << 4;
-
-    /* Warn if we took too much time between polls: at least 50 ms and at least
-     * 8X the mean interval. */
-    if (n_samples > 10 && interval > mean_interval * 8 && interval > 50 * 16) {
-        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 3);
-
-        if (!VLOG_DROP_WARN(&rl)) {
-            const struct rusage *last_rusage = get_recent_rusage();
-            struct rusage rusage;
-
-            getrusage(RUSAGE_SELF, &rusage);
-            VLOG_WARN("%lld ms poll interval (%lld ms user, %lld ms system) "
-                      "is over %u times the weighted mean interval %u ms "
-                      "(%u samples)",
-                      now - last_wakeup,
-                      timeval_diff_msec(&rusage.ru_utime,
-                                        &last_rusage->ru_utime),
-                      timeval_diff_msec(&rusage.ru_stime,
-                                        &last_rusage->ru_stime),
-                      interval / mean_interval,
-                      (mean_interval + 8) / 16, n_samples);
-            if (rusage.ru_minflt > last_rusage->ru_minflt
-                || rusage.ru_majflt > last_rusage->ru_majflt) {
-                VLOG_WARN("faults: %ld minor, %ld major",
-                          rusage.ru_minflt - last_rusage->ru_minflt,
-                          rusage.ru_majflt - last_rusage->ru_majflt);
-            }
-            if (rusage.ru_inblock > last_rusage->ru_inblock
-                || rusage.ru_oublock > last_rusage->ru_oublock) {
-                VLOG_WARN("disk: %ld reads, %ld writes",
-                          rusage.ru_inblock - last_rusage->ru_inblock,
-                          rusage.ru_oublock - last_rusage->ru_oublock);
-            }
-            if (rusage.ru_nvcsw > last_rusage->ru_nvcsw
-                || rusage.ru_nivcsw > last_rusage->ru_nivcsw) {
-                VLOG_WARN("context switches: %ld voluntary, %ld involuntary",
-                          rusage.ru_nvcsw - last_rusage->ru_nvcsw,
-                          rusage.ru_nivcsw - last_rusage->ru_nivcsw);
-            }
+    long long int interval = time_msec() - last_wakeup;
+
+    if (interval >= 1000) {
+        const struct rusage *last_rusage = get_recent_rusage();
+        struct rusage rusage;
+
+        getrusage(RUSAGE_SELF, &rusage);
+        VLOG_WARN("Unreasonably long %lldms poll interval"
+                  " (%lldms user, %lldms system)",
+                  interval,
+                  timeval_diff_msec(&rusage.ru_utime,
+                                    &last_rusage->ru_utime),
+                  timeval_diff_msec(&rusage.ru_stime,
+                                    &last_rusage->ru_stime));
+        if (rusage.ru_minflt > last_rusage->ru_minflt
+            || rusage.ru_majflt > last_rusage->ru_majflt) {
+            VLOG_WARN("faults: %ld minor, %ld major",
+                      rusage.ru_minflt - last_rusage->ru_minflt,
+                      rusage.ru_majflt - last_rusage->ru_majflt);
+        }
+        if (rusage.ru_inblock > last_rusage->ru_inblock
+            || rusage.ru_oublock > last_rusage->ru_oublock) {
+            VLOG_WARN("disk: %ld reads, %ld writes",
+                      rusage.ru_inblock - last_rusage->ru_inblock,
+                      rusage.ru_oublock - last_rusage->ru_oublock);
+        }
+        if (rusage.ru_nvcsw > last_rusage->ru_nvcsw
+            || rusage.ru_nivcsw > last_rusage->ru_nivcsw) {
+            VLOG_WARN("context switches: %ld voluntary, %ld involuntary",
+                      rusage.ru_nvcsw - last_rusage->ru_nvcsw,
+                      rusage.ru_nivcsw - last_rusage->ru_nivcsw);
         }
         coverage_log();
     }
-
-    /* Update exponentially weighted moving average.  With these parameters, a
-     * given value decays to 1% of its value in about 100 time steps.  */
-    if (n_samples++) {
-        mean_interval = (mean_interval * 122 + interval * 6 + 64) / 128;
-    } else {
-        mean_interval = interval;
-    }
 }
 \f
 /* CPU usage tracking. */
@@ -584,6 +602,89 @@ get_cpu_usage(void)
 {
     return cpu_usage;
 }
+
+static uint32_t
+hash_trace(struct trace *trace)
+{
+    return hash_bytes(trace->backtrace,
+                      trace->n_frames * sizeof *trace->backtrace, 0);
+}
+
+static struct trace *
+trace_map_lookup(struct hmap *trace_map, struct trace *key)
+{
+    struct trace *value;
+
+    HMAP_FOR_EACH_WITH_HASH (value, node, hash_trace(key), trace_map) {
+        if (key->n_frames == value->n_frames
+            && !memcmp(key->backtrace, value->backtrace,
+                       key->n_frames * sizeof *key->backtrace)) {
+            return value;
+        }
+    }
+    return NULL;
+}
+
+/*  Appends a string to 'ds' representing backtraces recorded at regular
+ *  intervals in the recent past.  This information can be used to get a sense
+ *  of what the process has been spending the majority of time doing.  Will
+ *  ommit any backtraces which have not occurred at least 'min_count' times. */
+void
+format_backtraces(struct ds *ds, size_t min_count)
+{
+    time_init();
+
+    if (HAVE_EXECINFO_H && CACHE_TIME) {
+        struct hmap trace_map = HMAP_INITIALIZER(&trace_map);
+        struct trace *trace, *next;
+        sigset_t oldsigs;
+        size_t i;
+
+        block_sigalrm(&oldsigs);
+
+        for (i = 0; i < MAX_TRACES; i++) {
+            struct trace *trace = &traces[i];
+            struct trace *map_trace;
+
+            if (!trace->n_frames) {
+                continue;
+            }
+
+            map_trace = trace_map_lookup(&trace_map, trace);
+            if (map_trace) {
+                map_trace->count++;
+            } else {
+                hmap_insert(&trace_map, &trace->node, hash_trace(trace));
+                trace->count = 1;
+            }
+        }
+
+        HMAP_FOR_EACH_SAFE (trace, next, node, &trace_map) {
+            char **frame_strs;
+            size_t j;
+
+            hmap_remove(&trace_map, &trace->node);
+
+            if (trace->count < min_count) {
+                continue;
+            }
+
+            frame_strs = backtrace_symbols(trace->backtrace, trace->n_frames);
+
+            ds_put_format(ds, "Count %zu\n", trace->count);
+            for (j = 0; j < trace->n_frames; j++) {
+                ds_put_format(ds, "%s\n", frame_strs[j]);
+            }
+            ds_put_cstr(ds, "\n");
+
+            free(frame_strs);
+        }
+        hmap_destroy(&trace_map);
+
+        ds_chomp(ds, '\n');
+        unblock_sigalrm(&oldsigs);
+    }
+}
 \f
 /* Unixctl interface. */
 
@@ -623,6 +724,19 @@ timeval_warp_cb(struct unixctl_conn *conn,
     unixctl_command_reply(conn, "warped");
 }
 
+static void
+backtrace_cb(struct unixctl_conn *conn,
+             int argc OVS_UNUSED, const char *argv[] OVS_UNUSED,
+             void *aux OVS_UNUSED)
+{
+    struct ds ds = DS_EMPTY_INITIALIZER;
+
+    assert(HAVE_EXECINFO_H && CACHE_TIME);
+    format_backtraces(&ds, 0);
+    unixctl_command_reply(conn, ds_cstr(&ds));
+    ds_destroy(&ds);
+}
+
 void
 timeval_dummy_register(void)
 {
index 1384848..5a7b6e2 100644 (file)
@@ -25,6 +25,7 @@
 extern "C" {
 #endif
 
+struct ds;
 struct pollfd;
 struct timespec;
 struct timeval;
@@ -36,21 +37,6 @@ BUILD_ASSERT_DECL(TYPE_IS_INTEGER(time_t));
  * ever encounter such a platform. */
 BUILD_ASSERT_DECL(TYPE_IS_SIGNED(time_t));
 
-/* On x86-64 systems, Linux avoids using syscalls for clock_gettime().
- *
- * For systems which do invoke a system call we wait at least
- * TIME_UPDATE_INTERVAL ms between clock_gettime() calls and cache the time for
- * the interim.
- *
- * For systems which do not invoke a system call, we just call clock_gettime()
- * whenever the time is requested.  As a result we don't start the background
- * SIGALRM timer unless explicitly needed by time_alarm() */
-#if defined __x86_64__ && defined __linux__
-#define CACHE_TIME 0
-#else
-#define CACHE_TIME 1
-#endif
-
 #define TIME_MAX TYPE_MAXIMUM(time_t)
 #define TIME_MIN TYPE_MINIMUM(time_t)
 
@@ -59,6 +45,24 @@ BUILD_ASSERT_DECL(TYPE_IS_SIGNED(time_t));
  * much time will be wasted in signal handlers and calls to clock_gettime(). */
 #define TIME_UPDATE_INTERVAL 100
 
+/* True on systems (particularly x86-64 Linux) where clock_gettime() is
+ * inexpensive.  On these systems, we don't bother caching the current time.
+ * Instead, we consult clock_gettime() directly when needed.
+ *
+ * False on systems where clock_gettime() is relatively expensive.  On these
+ * systems, we cache the current time and set up a periodic SIGALRM to remind
+ * us to update it.
+ *
+ * Also false on systems (e.g. ESX) that don't support setting up timers based
+ * on a monotonically increasing clock. */
+#ifndef CACHE_TIME
+#if defined ESX || (defined __x86_64__ && defined LINUX_DATAPATH)
+#define CACHE_TIME 0
+#else
+#define CACHE_TIME 1
+#endif
+#endif /* ifndef CACHE_TIME */
+
 void time_disable_restart(void);
 void time_enable_restart(void);
 void time_postfork(void);
@@ -72,6 +76,7 @@ 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);
+bool time_cached(void);
 
 long long int timespec_to_msec(const struct timespec *);
 long long int timeval_to_msec(const struct timeval *);
@@ -79,6 +84,7 @@ long long int timeval_to_msec(const struct timeval *);
 void xgettimeofday(struct timeval *);
 
 int get_cpu_usage(void);
+void format_backtraces(struct ds *, size_t min_count);
 
 long long int time_boot_msec(void);
 
index ffb8e73..2440def 100644 (file)
@@ -28,7 +28,7 @@
 
 VLOG_DEFINE_THIS_MODULE(vlandev);
 
-#ifdef __linux__
+#ifdef LINUX_DATAPATH
 #include "rtnetlink-link.h"
 #include <linux/if_vlan.h>
 #include <linux/sockios.h>
@@ -208,7 +208,7 @@ vlandev_del(const char *vlan_dev)
     }
     return error;
 }
-#else  /* !__linux__ */
+#else  /* !LINUX_DATAPATH */
 /* Stubs. */
 
 int
index bc44885..f2b896e 100644 (file)
@@ -335,8 +335,7 @@ worker_main(int fd)
     server_sock = fd;
 
     subprogram_name = "worker";
-    proctitle_set("%s: worker process for pid %lu",
-                  program_name, (unsigned long int) getppid());
+    proctitle_set("worker process for pid %lu", (unsigned long int) getppid());
     VLOG_INFO("worker process started");
 
     rxbuf_init(&rx);
index 939f296..7469011 100644 (file)
@@ -19,7 +19,7 @@ AC_DEFUN([OVS_CHECK_COVERAGE],
   [AC_REQUIRE([AC_PROG_CC])
    AC_ARG_ENABLE(
      [coverage],
-     [AC_HELP_STRING([--enable-coverage], 
+     [AC_HELP_STRING([--enable-coverage],
                      [Enable gcov coverage tool.])],
      [case "${enableval}" in
         (yes) coverage=true ;;
@@ -36,7 +36,7 @@ dnl Checks for --enable-ndebug and defines NDEBUG if it is specified.
 AC_DEFUN([OVS_CHECK_NDEBUG],
   [AC_ARG_ENABLE(
      [ndebug],
-     [AC_HELP_STRING([--enable-ndebug], 
+     [AC_HELP_STRING([--enable-ndebug],
                      [Disable debugging features for max performance])],
      [case "${enableval}" in
         (yes) ndebug=true ;;
@@ -46,6 +46,32 @@ AC_DEFUN([OVS_CHECK_NDEBUG],
      [ndebug=false])
    AM_CONDITIONAL([NDEBUG], [test x$ndebug = xtrue])])
 
+dnl Checks for --enable-cache-time and defines CACHE_TIME if it is specified.
+AC_DEFUN([OVS_CHECK_CACHE_TIME],
+  [AC_ARG_ENABLE(
+     [cache-time],
+     [AC_HELP_STRING([--enable-cache-time],
+                     [Override time caching default (for testing only)])],
+     [case "${enableval}" in
+        (yes) cache_time=1;;
+        (no)  cache_time=0;;
+        (*) AC_MSG_ERROR([bad value ${enableval} for --enable-cache-time]) ;;
+      esac
+      AC_DEFINE_UNQUOTED([CACHE_TIME], [$cache_time],
+          [Define to 1 to enable time caching, to 0 to disable time caching, or
+           leave undefined to use the default (as one should
+           ordinarily do).])])])
+
+dnl Checks for ESX.
+AC_DEFUN([OVS_CHECK_ESX],
+  [AC_CHECK_HEADER([vmware.h],
+                   [ESX=yes],
+                   [ESX=no])
+   AM_CONDITIONAL([ESX], [test "$ESX" = yes])
+   if test "$ESX" = yes; then
+      AC_DEFINE([ESX], [1], [Define to 1 if building on ESX.])
+   fi])
+
 dnl Checks for Netlink support.
 AC_DEFUN([OVS_CHECK_NETLINK],
   [AC_CHECK_HEADER([linux/netlink.h],
@@ -74,7 +100,7 @@ AC_DEFUN([OVS_CHECK_OPENSSL],
 
    if test "$ssl" != false; then
        m4_ifndef([PKG_CHECK_MODULES], [m4_fatal([Please install pkg-config.])])
-       PKG_CHECK_MODULES([SSL], [openssl], 
+       PKG_CHECK_MODULES([SSL], [openssl],
          [HAVE_OPENSSL=yes],
          [HAVE_OPENSSL=no
           if test "$ssl" = check; then
@@ -104,8 +130,8 @@ AC_DEFUN([OVS_CHECK_SOCKET_LIBS],
 dnl Checks for the directory in which to store the PKI.
 AC_DEFUN([OVS_CHECK_PKIDIR],
   [AC_ARG_WITH(
-     [pkidir], 
-     AC_HELP_STRING([--with-pkidir=DIR], 
+     [pkidir],
+     AC_HELP_STRING([--with-pkidir=DIR],
                     [PKI hierarchy directory [[LOCALSTATEDIR/lib/openvswitch/pki]]]),
      [PKIDIR=$withval],
      [PKIDIR='${localstatedir}/lib/openvswitch/pki'])
@@ -114,8 +140,8 @@ AC_DEFUN([OVS_CHECK_PKIDIR],
 dnl Checks for the directory in which to store pidfiles.
 AC_DEFUN([OVS_CHECK_RUNDIR],
   [AC_ARG_WITH(
-     [rundir], 
-     AC_HELP_STRING([--with-rundir=DIR], 
+     [rundir],
+     AC_HELP_STRING([--with-rundir=DIR],
                     [directory used for pidfiles
                     [[LOCALSTATEDIR/run/openvswitch]]]),
      [RUNDIR=$withval],
@@ -125,8 +151,8 @@ AC_DEFUN([OVS_CHECK_RUNDIR],
 dnl Checks for the directory in which to store logs.
 AC_DEFUN([OVS_CHECK_LOGDIR],
   [AC_ARG_WITH(
-     [logdir], 
-     AC_HELP_STRING([--with-logdir=DIR], 
+     [logdir],
+     AC_HELP_STRING([--with-logdir=DIR],
                     [directory used for logs [[LOCALSTATEDIR/log/PACKAGE]]]),
      [LOGDIR=$withval],
      [LOGDIR='${localstatedir}/log/${PACKAGE}'])
@@ -155,20 +181,20 @@ AC_DEFUN([OVS_CHECK_MALLOC_HOOKS],
     [AC_COMPILE_IFELSE(
       [AC_LANG_PROGRAM(
          [#include <malloc.h>
-         ], 
+         ],
          [(void) __malloc_hook;
           (void) __realloc_hook;
           (void) __free_hook;])],
       [ovs_cv_malloc_hooks=yes],
       [ovs_cv_malloc_hooks=no])])
    if test $ovs_cv_malloc_hooks = yes; then
-     AC_DEFINE([HAVE_MALLOC_HOOKS], [1], 
+     AC_DEFINE([HAVE_MALLOC_HOOKS], [1],
                [Define to 1 if you have __malloc_hook, __realloc_hook, and
                 __free_hook in <malloc.h>.])
    fi])
 
 dnl Checks for valgrind/valgrind.h.
-AC_DEFUN([OVS_CHECK_VALGRIND], 
+AC_DEFUN([OVS_CHECK_VALGRIND],
   [AC_CHECK_HEADERS([valgrind/valgrind.h])])
 
 dnl Checks for Python 2.x, x >= 4.
index 9f7acd1..fea4dac 100644 (file)
@@ -3106,18 +3106,19 @@ handle_miss_upcalls(struct ofproto_dpif *ofproto, struct dpif_upcall *upcalls,
     for (upcall = upcalls; upcall < &upcalls[n_upcalls]; upcall++) {
         struct flow_miss *miss = &misses[n_misses];
         struct flow_miss *existing_miss;
+        struct flow flow;
         uint32_t hash;
 
         /* Obtain metadata and check userspace/kernel agreement on flow match,
          * then set 'flow''s header pointers. */
         miss->key_fitness = ofproto_dpif_extract_flow_key(
             ofproto, upcall->key, upcall->key_len,
-            &miss->flow, &miss->initial_tci, upcall->packet);
+            &flow, &miss->initial_tci, upcall->packet);
         if (miss->key_fitness == ODP_FIT_ERROR) {
             continue;
         }
-        flow_extract(upcall->packet, miss->flow.skb_priority,
-                     miss->flow.tun_id, miss->flow.in_port, &miss->flow);
+        flow_extract(upcall->packet, flow.skb_priority,
+                     &flow.tunnel, flow.in_port, &miss->flow);
 
         /* Add other packets to a to-do list. */
         hash = flow_hash(&miss->flow, 0);
@@ -4763,7 +4764,7 @@ send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet)
     struct flow flow;
     int error;
 
-    flow_extract(packet, 0, 0, 0, &flow);
+    flow_extract(packet, 0, NULL, 0, &flow);
     odp_port = vsp_realdev_to_vlandev(ofproto, ofport->odp_port,
                                       flow.vlan_tci);
     if (odp_port != ofport->odp_port) {
@@ -4957,8 +4958,11 @@ compose_output_action__(struct action_xlate_ctx *ctx, uint16_t ofp_port,
     if (ofport) {
         struct priority_to_dscp *pdscp;
 
-        if (ofport->up.pp.config & OFPUTIL_PC_NO_FWD
-            || (check_stp && !stp_forward_in_state(ofport->stp_state))) {
+        if (ofport->up.pp.config & OFPUTIL_PC_NO_FWD) {
+            xlate_report(ctx, "OFPPC_NO_FWD set, skipping output");
+            return;
+        } else if (check_stp && !stp_forward_in_state(ofport->stp_state)) {
+            xlate_report(ctx, "STP not in forwarding state, skipping output");
             return;
         }
 
@@ -5232,6 +5236,8 @@ xlate_output_action(struct action_xlate_ctx *ctx,
     default:
         if (port != ctx->flow.in_port) {
             compose_output_action(ctx, port);
+        } else {
+            xlate_report(ctx, "skipping output to input port");
         }
         break;
     }
@@ -5454,6 +5460,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
     }
     OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
         struct ofpact_controller *controller;
+        const struct ofpact_metadata *metadata;
 
         if (ctx->exit) {
             break;
@@ -5493,6 +5500,11 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             ctx->flow.vlan_tci = htons(0);
             break;
 
+        case OFPACT_PUSH_VLAN:
+            /* TODO:XXX 802.1AD(QinQ) */
+            ctx->flow.vlan_tci = htons(VLAN_CFI);
+            break;
+
         case OFPACT_SET_ETH_SRC:
             memcpy(ctx->flow.dl_src, ofpact_get_SET_ETH_SRC(a)->mac,
                    ETH_ADDR_LEN);
@@ -5532,7 +5544,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             break;
 
         case OFPACT_SET_TUNNEL:
-            ctx->flow.tun_id = htonll(ofpact_get_SET_TUNNEL(a)->tun_id);
+            ctx->flow.tunnel.tun_id = htonll(ofpact_get_SET_TUNNEL(a)->tun_id);
             break;
 
         case OFPACT_SET_QUEUE:
@@ -5593,6 +5605,29 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             ctx->has_fin_timeout = true;
             xlate_fin_timeout(ctx, ofpact_get_FIN_TIMEOUT(a));
             break;
+
+        case OFPACT_CLEAR_ACTIONS:
+            /* TODO:XXX
+             * Nothing to do because writa-actions is not supported for now.
+             * When writa-actions is supported, clear-actions also must
+             * be supported at the same time.
+             */
+            break;
+
+        case OFPACT_WRITE_METADATA:
+            metadata = ofpact_get_WRITE_METADATA(a);
+            ctx->flow.metadata &= ~metadata->mask;
+            ctx->flow.metadata |= metadata->metadata & metadata->mask;
+            break;
+
+        case OFPACT_GOTO_TABLE: {
+            /* TODO:XXX remove recursion */
+            /* It is assumed that goto-table is last action */
+            struct ofpact_goto_table *ogt = ofpact_get_GOTO_TABLE(a);
+            assert(ctx->table_id < ogt->table_id);
+            xlate_table_action(ctx, ctx->flow.in_port, ogt->table_id, true);
+            break;
+        }
         }
     }
 
@@ -5617,7 +5652,7 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx,
     ctx->ofproto = ofproto;
     ctx->flow = *flow;
     ctx->base_flow = ctx->flow;
-    ctx->base_flow.tun_id = 0;
+    memset(&ctx->base_flow.tunnel, 0, sizeof ctx->base_flow.tunnel);
     ctx->base_flow.vlan_tci = initial_tci;
     ctx->rule = rule;
     ctx->packet = packet;
@@ -6776,7 +6811,8 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
         ds_put_cstr(&result, s);
         free(s);
 
-        flow_extract(packet, priority, tun_id, in_port, &flow);
+        flow_extract(packet, priority, NULL, in_port, &flow);
+        flow.tunnel.tun_id = tun_id;
         initial_tci = flow.vlan_tci;
     } else {
         unixctl_command_reply_error(conn, "Bad command syntax");
index 0ade586..a62473b 100644 (file)
@@ -893,7 +893,7 @@ struct ofproto_class {
      *
      * 'flow' reflects the flow information for 'packet'.  All of the
      * information in 'flow' is extracted from 'packet', except for
-     * flow->tun_id and flow->in_port, which are assigned the correct values
+     * flow->tunnel and flow->in_port, which are assigned the correct values
      * for the incoming packet.  The register values are zeroed.  'packet''s
      * header pointers (e.g. packet->l3) are appropriately initialized.
      *
@@ -968,7 +968,7 @@ struct ofproto_class {
      *
      * 'flow' reflects the flow information for 'packet'.  All of the
      * information in 'flow' is extracted from 'packet', except for
-     * flow->in_port (see below).  flow->tun_id and its register values are
+     * flow->in_port (see below).  flow->tunnel and its register values are
      * zeroed.
      *
      * flow->in_port comes from the OpenFlow OFPT_PACKET_OUT message.  The
index e3b24c1..2fb2fc8 100644 (file)
@@ -379,7 +379,7 @@ ofproto_create(const char *datapath_name, const char *datapath_type,
                 hash_string(ofproto->name, 0));
     ofproto->datapath_id = 0;
     ofproto_set_flow_eviction_threshold(ofproto,
-                                        OFPROTO_FLOW_EVICTON_THRESHOLD_DEFAULT);
+                                        OFPROTO_FLOW_EVICTION_THRESHOLD_DEFAULT);
     ofproto->forward_bpdu = false;
     ofproto->fallback_dpid = pick_fallback_dpid();
     ofproto->mfr_desc = xstrdup(DEFAULT_MFR_DESC);
@@ -1970,7 +1970,7 @@ rule_execute(struct rule *rule, uint16_t in_port, struct ofpbuf *packet)
 
     assert(ofpbuf_headroom(packet) >= sizeof(struct ofp_packet_in));
 
-    flow_extract(packet, 0, 0, in_port, &flow);
+    flow_extract(packet, 0, NULL, in_port, &flow);
     return rule->ofproto->ofproto_class->rule_execute(rule, &flow, packet);
 }
 
@@ -2147,7 +2147,7 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh)
     }
 
     /* Verify actions against packet, then send packet if successful. */
-    flow_extract(payload, 0, 0, po.in_port, &flow);
+    flow_extract(payload, 0, NULL, po.in_port, &flow);
     error = ofpacts_check(po.ofpacts, po.ofpacts_len, &flow, p->max_ports);
     if (!error) {
         error = p->ofproto_class->packet_out(p, payload, &flow,
@@ -2258,8 +2258,8 @@ handle_table_stats_request(struct ofconn *ofconn,
         sprintf(ots[i].name, "table%zu", i);
         ots[i].match = htonll(OFPXMT12_MASK);
         ots[i].wildcards = htonll(OFPXMT12_MASK);
-        ots[i].write_actions = htonl(OFPAT12_OUTPUT);
-        ots[i].apply_actions = htonl(OFPAT12_OUTPUT);
+        ots[i].write_actions = htonl(OFPAT11_OUTPUT);
+        ots[i].apply_actions = htonl(OFPAT11_OUTPUT);
         ots[i].write_setfields = htonll(OFPXMT12_MASK);
         ots[i].apply_setfields = htonll(OFPXMT12_MASK);
         ots[i].metadata_match = htonll(UINT64_MAX);
@@ -2295,29 +2295,14 @@ handle_table_stats_request(struct ofconn *ofconn,
 static void
 append_port_stat(struct ofport *port, struct list *replies)
 {
-    struct netdev_stats stats;
-    struct ofp10_port_stats *ops;
+    struct ofputil_port_stats ops = { .port_no = port->pp.port_no };
 
     /* Intentionally ignore return value, since errors will set
      * 'stats' to all-1s, which is correct for OpenFlow, and
      * netdev_get_stats() will log errors. */
-    ofproto_port_get_stats(port, &stats);
-
-    ops = ofpmp_append(replies, sizeof *ops);
-    ops->port_no = htons(port->pp.port_no);
-    memset(ops->pad, 0, sizeof ops->pad);
-    put_32aligned_be64(&ops->rx_packets, htonll(stats.rx_packets));
-    put_32aligned_be64(&ops->tx_packets, htonll(stats.tx_packets));
-    put_32aligned_be64(&ops->rx_bytes, htonll(stats.rx_bytes));
-    put_32aligned_be64(&ops->tx_bytes, htonll(stats.tx_bytes));
-    put_32aligned_be64(&ops->rx_dropped, htonll(stats.rx_dropped));
-    put_32aligned_be64(&ops->tx_dropped, htonll(stats.tx_dropped));
-    put_32aligned_be64(&ops->rx_errors, htonll(stats.rx_errors));
-    put_32aligned_be64(&ops->tx_errors, htonll(stats.tx_errors));
-    put_32aligned_be64(&ops->rx_frame_err, htonll(stats.rx_frame_errors));
-    put_32aligned_be64(&ops->rx_over_err, htonll(stats.rx_over_errors));
-    put_32aligned_be64(&ops->rx_crc_err, htonll(stats.rx_crc_errors));
-    put_32aligned_be64(&ops->collisions, htonll(stats.collisions));
+    ofproto_port_get_stats(port, &ops.stats);
+
+    ofputil_append_port_stat(replies, &ops);
 }
 
 static enum ofperr
@@ -2325,13 +2310,19 @@ handle_port_stats_request(struct ofconn *ofconn,
                           const struct ofp_header *request)
 {
     struct ofproto *p = ofconn_get_ofproto(ofconn);
-    const struct ofp10_port_stats_request *psr = ofpmsg_body(request);
     struct ofport *port;
     struct list replies;
+    uint16_t port_no;
+    enum ofperr error;
+
+    error = ofputil_decode_port_stats_request(request, &port_no);
+    if (error) {
+        return error;
+    }
 
     ofpmp_init(&replies, request);
-    if (psr->port_no != htons(OFPP_NONE)) {
-        port = ofproto_get_port(p, ntohs(psr->port_no));
+    if (port_no != OFPP_NONE) {
+        port = ofproto_get_port(p, port_no);
         if (port) {
             append_port_stat(port, &replies);
         }
@@ -2784,15 +2775,13 @@ static void
 put_queue_stats(struct queue_stats_cbdata *cbdata, uint32_t queue_id,
                 const struct netdev_queue_stats *stats)
 {
-    struct ofp10_queue_stats *reply;
 
-    reply = ofpmp_append(&cbdata->replies, sizeof *reply);
-    reply->port_no = htons(cbdata->ofport->pp.port_no);
-    memset(reply->pad, 0, sizeof reply->pad);
-    reply->queue_id = htonl(queue_id);
-    put_32aligned_be64(&reply->tx_bytes, htonll(stats->tx_bytes));
-    put_32aligned_be64(&reply->tx_packets, htonll(stats->tx_packets));
-    put_32aligned_be64(&reply->tx_errors, htonll(stats->tx_errors));
+    struct ofputil_queue_stats oqs = {
+        .port_no = cbdata->ofport->pp.port_no,
+        .queue_id = queue_id,
+        .stats = *stats,
+    };
+    ofputil_append_queue_stat(&cbdata->replies, &oqs);
 }
 
 static void
@@ -2830,30 +2819,31 @@ handle_queue_stats_request(struct ofconn *ofconn,
                            const struct ofp_header *rq)
 {
     struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
-    const struct ofp10_queue_stats_request *qsr = ofpmsg_body(rq);
     struct queue_stats_cbdata cbdata;
-    unsigned int port_no;
     struct ofport *port;
-    uint32_t queue_id;
     enum ofperr error;
+    struct ofputil_queue_stats_request oqsr;
 
     COVERAGE_INC(ofproto_queue_req);
 
     ofpmp_init(&cbdata.replies, rq);
 
-    port_no = ntohs(qsr->port_no);
-    queue_id = ntohl(qsr->queue_id);
-    if (port_no == OFPP_ALL) {
+    error = ofputil_decode_queue_stats_request(rq, &oqsr);
+    if (error) {
+        return error;
+    }
+
+    if (oqsr.port_no == OFPP_ALL) {
         error = OFPERR_OFPQOFC_BAD_QUEUE;
         HMAP_FOR_EACH (port, hmap_node, &ofproto->ports) {
-            if (!handle_queue_stats_for_port(port, queue_id, &cbdata)) {
+            if (!handle_queue_stats_for_port(port, oqsr.queue_id, &cbdata)) {
                 error = 0;
             }
         }
     } else {
-        port = ofproto_get_port(ofproto, port_no);
+        port = ofproto_get_port(ofproto, oqsr.port_no);
         error = (port
-                 ? handle_queue_stats_for_port(port, queue_id, &cbdata)
+                 ? handle_queue_stats_for_port(port, oqsr.queue_id, &cbdata)
                  : OFPERR_OFPQOFC_BAD_PORT);
     }
     if (!error) {
@@ -2998,7 +2988,7 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
             rule->evictable = was_evictable;
 
             if (!evict) {
-                error = OFPERR_OFPFMFC_ALL_TABLES_FULL;
+                error = OFPERR_OFPFMFC_TABLE_FULL;
                 goto exit;
             } else if (evict->pending) {
                 error = OFPROTO_POSTPONE;
@@ -3090,6 +3080,17 @@ modify_flows__(struct ofproto *ofproto, struct ofconn *ofconn,
     return error;
 }
 
+static enum ofperr
+modify_flows_add(struct ofproto *ofproto, struct ofconn *ofconn,
+                 const struct ofputil_flow_mod *fm,
+                 const struct ofp_header *request)
+{
+    if (fm->cookie_mask != htonll(0) || fm->new_cookie == htonll(UINT64_MAX)) {
+        return 0;
+    }
+    return add_flow(ofproto, ofconn, fm, request);
+}
+
 /* Implements OFPFC_MODIFY.  Returns 0 on success or an OpenFlow error code on
  * failure.
  *
@@ -3109,7 +3110,7 @@ modify_flows_loose(struct ofproto *ofproto, struct ofconn *ofconn,
     if (error) {
         return error;
     } else if (list_is_empty(&rules)) {
-        return fm->cookie_mask ? 0 : add_flow(ofproto, ofconn, fm, request);
+        return modify_flows_add(ofproto, ofconn, fm, request);
     } else {
         return modify_flows__(ofproto, ofconn, fm, request, &rules);
     }
@@ -3135,7 +3136,7 @@ modify_flow_strict(struct ofproto *ofproto, struct ofconn *ofconn,
     if (error) {
         return error;
     } else if (list_is_empty(&rules)) {
-        return fm->cookie_mask ? 0 : add_flow(ofproto, ofconn, fm, request);
+        return modify_flows_add(ofproto, ofconn, fm, request);
     } else {
         return list_is_singleton(&rules) ? modify_flows__(ofproto, ofconn,
                                                           fm, request, &rules)
@@ -3225,6 +3226,7 @@ ofproto_rule_send_removed(struct rule *rule, uint8_t reason)
     fr.priority = rule->cr.priority;
     fr.cookie = rule->flow_cookie;
     fr.reason = reason;
+    fr.table_id = rule->table_id;
     calc_flow_duration__(rule->created, time_msec(),
                          &fr.duration_sec, &fr.duration_nsec);
     fr.idle_timeout = rule->idle_timeout;
@@ -3298,12 +3300,11 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh)
     }
 
     if (fm.flags & OFPFF10_EMERG) {
-    /* We do not support the OpenFlow 1.0 emergency flow cache, which is not
-     * required in OpenFlow 1.0.1 and removed from OpenFlow 1.1. */
-        /* We do not support the emergency flow cache.  It will hopefully get
-         * dropped from OpenFlow in the near future.  There is no good error
-         * code, so just state that the flow table is full. */
-        error = OFPERR_OFPFMFC_ALL_TABLES_FULL;
+        /* We do not support the OpenFlow 1.0 emergency flow cache, which
+         * is not required in OpenFlow 1.0.1 and removed from OpenFlow 1.1.
+         * There is no good error code, so just state that the flow table
+         * is full. */
+        error = OFPERR_OFPFMFC_TABLE_FULL;
     }
     if (!error) {
         error = ofpacts_check(fm.ofpacts, fm.ofpacts_len,
index 32a00f2..5599cd6 100644 (file)
@@ -190,7 +190,7 @@ int ofproto_port_dump_done(struct ofproto_port_dump *);
           : (ofproto_port_dump_done(DUMP), false));         \
         )
 
-#define OFPROTO_FLOW_EVICTON_THRESHOLD_DEFAULT  1000
+#define OFPROTO_FLOW_EVICTION_THRESHOLD_DEFAULT  1000
 #define OFPROTO_FLOW_EVICTION_THRESHOLD_MIN 100
 
 int ofproto_port_add(struct ofproto *, struct netdev *, uint16_t *ofp_portp);
index bb887d0..1149efd 100644 (file)
@@ -66,6 +66,7 @@ static void ovsdb_jsonrpc_session_unlock__(struct ovsdb_lock_waiter *);
 
 /* Triggers. */
 static void ovsdb_jsonrpc_trigger_create(struct ovsdb_jsonrpc_session *,
+                                         struct ovsdb *,
                                          struct json *id, struct json *params);
 static struct ovsdb_jsonrpc_trigger *ovsdb_jsonrpc_trigger_find(
     struct ovsdb_jsonrpc_session *, const struct json *id, size_t hash);
@@ -76,7 +77,7 @@ static void ovsdb_jsonrpc_trigger_complete_done(
 
 /* Monitors. */
 static struct json *ovsdb_jsonrpc_monitor_create(
-    struct ovsdb_jsonrpc_session *, struct json *params);
+    struct ovsdb_jsonrpc_session *, struct ovsdb *, struct json *params);
 static struct jsonrpc_msg *ovsdb_jsonrpc_monitor_cancel(
     struct ovsdb_jsonrpc_session *,
     struct json_array *params,
@@ -98,6 +99,7 @@ struct ovsdb_jsonrpc_remote {
     struct ovsdb_jsonrpc_server *server;
     struct pstream *listener;   /* Listener, if passive. */
     struct list sessions;       /* List of "struct ovsdb_jsonrpc_session"s. */
+    uint8_t dscp;
 };
 
 static struct ovsdb_jsonrpc_remote *ovsdb_jsonrpc_server_add_remote(
@@ -106,16 +108,29 @@ static struct ovsdb_jsonrpc_remote *ovsdb_jsonrpc_server_add_remote(
 );
 static void ovsdb_jsonrpc_server_del_remote(struct shash_node *);
 
+/* Creates and returns a new server to provide JSON-RPC access to an OVSDB.
+ *
+ * The caller must call ovsdb_jsonrpc_server_add_db() for each database to
+ * which 'server' should provide access. */
 struct ovsdb_jsonrpc_server *
-ovsdb_jsonrpc_server_create(struct ovsdb *db)
+ovsdb_jsonrpc_server_create(void)
 {
     struct ovsdb_jsonrpc_server *server = xzalloc(sizeof *server);
-    ovsdb_server_init(&server->up, db);
+    ovsdb_server_init(&server->up);
     server->max_sessions = 64;
     shash_init(&server->remotes);
     return server;
 }
 
+/* Adds 'db' to the set of databases served out by 'svr'.  Returns true if
+ * successful, false if 'db''s name is the same as some database already in
+ * 'server'. */
+bool
+ovsdb_jsonrpc_server_add_db(struct ovsdb_jsonrpc_server *svr, struct ovsdb *db)
+{
+    return ovsdb_server_add_db(&svr->up, db);
+}
+
 void
 ovsdb_jsonrpc_server_destroy(struct ovsdb_jsonrpc_server *svr)
 {
@@ -192,6 +207,7 @@ ovsdb_jsonrpc_server_add_remote(struct ovsdb_jsonrpc_server *svr,
     remote->server = svr;
     remote->listener = listener;
     list_init(&remote->sessions);
+    remote->dscp = options->dscp;
     shash_add(&svr->remotes, name, remote);
 
     if (!listener) {
@@ -268,7 +284,8 @@ ovsdb_jsonrpc_server_run(struct ovsdb_jsonrpc_server *svr)
             error = pstream_accept(remote->listener, &stream);
             if (!error) {
                 struct jsonrpc_session *js;
-                js = jsonrpc_session_open_unreliably(jsonrpc_open(stream));
+                js = jsonrpc_session_open_unreliably(jsonrpc_open(stream),
+                                                     remote->dscp);
                 ovsdb_jsonrpc_session_create(remote, js);
             } else if (error != EAGAIN) {
                 VLOG_WARN_RL(&rl, "%s: accept failed: %s",
@@ -350,7 +367,7 @@ ovsdb_jsonrpc_session_create(struct ovsdb_jsonrpc_remote *remote,
     struct ovsdb_jsonrpc_session *s;
 
     s = xzalloc(sizeof *s);
-    ovsdb_session_init(&s->up, remote->server->up.db);
+    ovsdb_session_init(&s->up, &remote->server->up);
     s->remote = remote;
     list_push_back(&remote->sessions, &s->node);
     hmap_init(&s->triggers);
@@ -504,6 +521,22 @@ ovsdb_jsonrpc_session_set_all_options(
 {
     struct ovsdb_jsonrpc_session *s;
 
+    if (remote->listener) {
+        int error;
+
+        error = pstream_set_dscp(remote->listener, options->dscp);
+        if (error) {
+            VLOG_ERR("%s: set_dscp failed %s",
+                     pstream_get_name(remote->listener), strerror(error));
+        } else {
+            remote->dscp = options->dscp;
+        }
+        /*
+         * TODO:XXX race window between setting dscp to listening socket
+         * and accepting socket. Accepted socket may have old dscp value.
+         * Ignore this race window for now.
+         */
+    }
     LIST_FOR_EACH (s, node, &remote->sessions) {
         ovsdb_jsonrpc_session_set_options(s, options);
     }
@@ -558,21 +591,22 @@ ovsdb_jsonrpc_session_get_status(const struct ovsdb_jsonrpc_remote *remote,
     return true;
 }
 
-static const char *
-get_db_name(const struct ovsdb_jsonrpc_session *s)
-{
-    return s->remote->server->up.db->schema->name;
-}
-
-static struct jsonrpc_msg *
-ovsdb_jsonrpc_check_db_name(const struct ovsdb_jsonrpc_session *s,
-                            const struct jsonrpc_msg *request)
+/* Examines 'request' to determine the database to which it relates, and then
+ * searches 's' to find that database:
+ *
+ *    - If successful, returns the database and sets '*replyp' to NULL.
+ *
+ *    - If no such database exists, returns NULL and sets '*replyp' to an
+ *      appropriate JSON-RPC error reply, owned by the caller. */
+static struct ovsdb *
+ovsdb_jsonrpc_lookup_db(const struct ovsdb_jsonrpc_session *s,
+                        const struct jsonrpc_msg *request,
+                        struct jsonrpc_msg **replyp)
 {
     struct json_array *params;
-    const char *want_db_name;
-    const char *have_db_name;
     struct ovsdb_error *error;
-    struct jsonrpc_msg *reply;
+    const char *db_name;
+    struct ovsdb *db;
 
     params = json_array(request->params);
     if (!params->n || params->elems[0]->type != JSON_STRING) {
@@ -582,22 +616,23 @@ ovsdb_jsonrpc_check_db_name(const struct ovsdb_jsonrpc_session *s,
         goto error;
     }
 
-    want_db_name = params->elems[0]->u.string;
-    have_db_name = get_db_name(s);
-    if (strcmp(want_db_name, have_db_name)) {
+    db_name = params->elems[0]->u.string;
+    db = shash_find_data(&s->up.server->dbs, db_name);
+    if (!db) {
         error = ovsdb_syntax_error(
             request->params, "unknown database",
             "%s request specifies unknown database %s",
-            request->method, want_db_name);
+            request->method, db_name);
         goto error;
     }
 
-    return NULL;
+    *replyp = NULL;
+    return db;
 
 error:
-    reply = jsonrpc_create_reply(ovsdb_error_to_json(error), request->id);
+    *replyp = jsonrpc_create_reply(ovsdb_error_to_json(error), request->id);
     ovsdb_error_destroy(error);
-    return reply;
+    return NULL;
 }
 
 static struct ovsdb_error *
@@ -739,10 +774,10 @@ error:
 }
 
 static struct jsonrpc_msg *
-execute_transaction(struct ovsdb_jsonrpc_session *s,
+execute_transaction(struct ovsdb_jsonrpc_session *s, struct ovsdb *db,
                     struct jsonrpc_msg *request)
 {
-    ovsdb_jsonrpc_trigger_create(s, request->id, request->params);
+    ovsdb_jsonrpc_trigger_create(s, db, request->id, request->params);
     request->id = NULL;
     request->params = NULL;
     jsonrpc_msg_destroy(request);
@@ -756,30 +791,39 @@ ovsdb_jsonrpc_session_got_request(struct ovsdb_jsonrpc_session *s,
     struct jsonrpc_msg *reply;
 
     if (!strcmp(request->method, "transact")) {
-        reply = ovsdb_jsonrpc_check_db_name(s, request);
+        struct ovsdb *db = ovsdb_jsonrpc_lookup_db(s, request, &reply);
         if (!reply) {
-            reply = execute_transaction(s, request);
+            reply = execute_transaction(s, db, request);
         }
     } else if (!strcmp(request->method, "monitor")) {
-        reply = ovsdb_jsonrpc_check_db_name(s, request);
+        struct ovsdb *db = ovsdb_jsonrpc_lookup_db(s, request, &reply);
         if (!reply) {
             reply = jsonrpc_create_reply(
-                ovsdb_jsonrpc_monitor_create(s, request->params), request->id);
+                ovsdb_jsonrpc_monitor_create(s, db, request->params),
+                request->id);
         }
     } else if (!strcmp(request->method, "monitor_cancel")) {
         reply = ovsdb_jsonrpc_monitor_cancel(s, json_array(request->params),
                                              request->id);
     } else if (!strcmp(request->method, "get_schema")) {
-        reply = ovsdb_jsonrpc_check_db_name(s, request);
+        struct ovsdb *db = ovsdb_jsonrpc_lookup_db(s, request, &reply);
         if (!reply) {
-            reply = jsonrpc_create_reply(
-                ovsdb_schema_to_json(s->remote->server->up.db->schema),
-                request->id);
+            reply = jsonrpc_create_reply(ovsdb_schema_to_json(db->schema),
+                                         request->id);
         }
     } else if (!strcmp(request->method, "list_dbs")) {
-        reply = jsonrpc_create_reply(
-            json_array_create_1(json_string_create(get_db_name(s))),
-            request->id);
+        size_t n_dbs = shash_count(&s->up.server->dbs);
+        struct shash_node *node;
+        struct json **dbs;
+        size_t i;
+
+        dbs = xmalloc(n_dbs * sizeof *dbs);
+        i = 0;
+        SHASH_FOR_EACH (node, &s->up.server->dbs) {
+            dbs[i++] = json_string_create(node->name);
+        }
+        reply = jsonrpc_create_reply(json_array_create(dbs, n_dbs),
+                                     request->id);
     } else if (!strcmp(request->method, "lock")) {
         reply = ovsdb_jsonrpc_session_lock(s, request, OVSDB_LOCK_WAIT);
     } else if (!strcmp(request->method, "steal")) {
@@ -836,7 +880,7 @@ struct ovsdb_jsonrpc_trigger {
 };
 
 static void
-ovsdb_jsonrpc_trigger_create(struct ovsdb_jsonrpc_session *s,
+ovsdb_jsonrpc_trigger_create(struct ovsdb_jsonrpc_session *s, struct ovsdb *db,
                              struct json *id, struct json *params)
 {
     struct ovsdb_jsonrpc_trigger *t;
@@ -858,7 +902,7 @@ ovsdb_jsonrpc_trigger_create(struct ovsdb_jsonrpc_session *s,
 
     /* Insert into trigger table. */
     t = xmalloc(sizeof *t);
-    ovsdb_trigger_init(&s->up, &t->trigger, params, time_msec());
+    ovsdb_trigger_init(&s->up, db, &t->trigger, params, time_msec());
     t->id = id;
     hmap_insert(&s->triggers, &t->hmap_node, hash);
 
@@ -962,6 +1006,7 @@ struct ovsdb_jsonrpc_monitor_table {
 struct ovsdb_jsonrpc_monitor {
     struct ovsdb_replica replica;
     struct ovsdb_jsonrpc_session *session;
+    struct ovsdb *db;
     struct hmap_node node;      /* In ovsdb_jsonrpc_session's "monitors". */
 
     struct json *monitor_id;
@@ -1113,7 +1158,7 @@ ovsdb_jsonrpc_parse_monitor_request(struct ovsdb_jsonrpc_monitor_table *mt,
 }
 
 static struct json *
-ovsdb_jsonrpc_monitor_create(struct ovsdb_jsonrpc_session *s,
+ovsdb_jsonrpc_monitor_create(struct ovsdb_jsonrpc_session *s, struct ovsdb *db,
                              struct json *params)
 {
     struct ovsdb_jsonrpc_monitor *m = NULL;
@@ -1141,8 +1186,9 @@ ovsdb_jsonrpc_monitor_create(struct ovsdb_jsonrpc_session *s,
 
     m = xzalloc(sizeof *m);
     ovsdb_replica_init(&m->replica, &ovsdb_jsonrpc_replica_class);
-    ovsdb_add_replica(s->remote->server->up.db, &m->replica);
+    ovsdb_add_replica(db, &m->replica);
     m->session = s;
+    m->db = db;
     hmap_insert(&s->monitors, &m->node, json_hash(monitor_id, 0));
     m->monitor_id = json_clone(monitor_id);
     shash_init(&m->tables);
@@ -1154,7 +1200,7 @@ ovsdb_jsonrpc_monitor_create(struct ovsdb_jsonrpc_session *s,
         const struct json *mr_value;
         size_t i;
 
-        table = ovsdb_get_table(s->remote->server->up.db, node->name);
+        table = ovsdb_get_table(m->db, node->name);
         if (!table) {
             error = ovsdb_syntax_error(NULL, NULL,
                                        "no table named %s", node->name);
@@ -1203,7 +1249,7 @@ ovsdb_jsonrpc_monitor_create(struct ovsdb_jsonrpc_session *s,
 
 error:
     if (m) {
-        ovsdb_remove_replica(s->remote->server->up.db, &m->replica);
+        ovsdb_remove_replica(m->db, &m->replica);
     }
 
     json = ovsdb_error_to_json(error);
@@ -1227,7 +1273,7 @@ ovsdb_jsonrpc_monitor_cancel(struct ovsdb_jsonrpc_session *s,
             return jsonrpc_create_error(json_string_create("unknown monitor"),
                                         request_id);
         } else {
-            ovsdb_remove_replica(s->remote->server->up.db, &m->replica);
+            ovsdb_remove_replica(m->db, &m->replica);
             return jsonrpc_create_reply(json_object_create(), request_id);
         }
     }
@@ -1239,7 +1285,7 @@ ovsdb_jsonrpc_monitor_remove_all(struct ovsdb_jsonrpc_session *s)
     struct ovsdb_jsonrpc_monitor *m, *next;
 
     HMAP_FOR_EACH_SAFE (m, next, node, &s->monitors) {
-        ovsdb_remove_replica(s->remote->server->up.db, &m->replica);
+        ovsdb_remove_replica(m->db, &m->replica);
     }
 }
 
index 2dc0c78..bf2a2fc 100644 (file)
@@ -22,7 +22,9 @@ struct ovsdb;
 struct shash;
 struct simap;
 
-struct ovsdb_jsonrpc_server *ovsdb_jsonrpc_server_create(struct ovsdb *);
+struct ovsdb_jsonrpc_server *ovsdb_jsonrpc_server_create(void);
+bool ovsdb_jsonrpc_server_add_db(struct ovsdb_jsonrpc_server *,
+                                 struct ovsdb *);
 void ovsdb_jsonrpc_server_destroy(struct ovsdb_jsonrpc_server *);
 
 /* Options for a remote. */
index 1f5be03..242c98b 100644 (file)
@@ -10,7 +10,7 @@ ovsdb\-server \- Open vSwitch database server
 .
 .SH SYNOPSIS
 \fBovsdb\-server\fR
-[\fIdatabase\fR]
+[\fIdatabase\fR]\&...
 [\fB\-\-remote=\fIremote\fR]\&...
 [\fB\-\-run=\fIcommand\fR]
 .so lib/daemon-syn.man
@@ -21,13 +21,13 @@ ovsdb\-server \- Open vSwitch database server
 .so lib/common-syn.man
 .
 .SH DESCRIPTION
-The \fBovsdb\-server\fR program provides RPC interfaces to an Open
-vSwitch database (OVSDB).  It supports JSON-RPC client connections
-over active or passive TCP/IP or Unix domain sockets.
+The \fBovsdb\-server\fR program provides RPC interfaces to one or more
+Open vSwitch databases (OVSDBs).  It supports JSON-RPC client
+connections over active or passive TCP/IP or Unix domain sockets.
 .PP
-The OVSDB file may be specified on the command line as \fIdatabase\fR.
-The default is \fB@DBDIR@/conf.db\fR.  The database
-file must already have been created and initialized using, for
+Each OVSDB file may be specified on the command line as \fIdatabase\fR.
+If none is specified, the default is \fB@DBDIR@/conf.db\fR.  The database
+files must already have been created and initialized using, for
 example, \fBovsdb\-tool create\fR.
 .
 .SH OPTIONS
@@ -40,11 +40,12 @@ Adds \fIremote\fR as a connection method used by \fBovsdb\-server\fR.
 .so ovsdb/remote-passive.man
 .so ovsdb/remote-active.man
 .
-.IP "\fBdb:\fItable\fB,\fIcolumn\fR"
+.IP "\fBdb:\fR[\fIdb\fB,\fR]\fItable\fB,\fIcolumn\fR"
 Reads additional connection methods from \fIcolumn\fR in all of the
-rows in \fItable\fR.  As the contents of \fIcolumn\fR changes,
-\fBovsdb\-server\fR also adds and drops connection methods
-accordingly.
+rows in \fItable\fR within \fIdb\fR.  (If \fBovsdb\-server\fR is
+providing access to only one database, then \fIdb\fR is optional.)  As
+the contents of \fIcolumn\fR changes, \fBovsdb\-server\fR also adds
+and drops connection methods accordingly.
 .IP
 If \fIcolumn\fR's type is string or set of strings, then the
 connection methods are taken directly from the column.  The connection
@@ -61,7 +62,7 @@ is mandatory: if it is missing or empty then no connection method can
 be configured.
 .IP "\fBmax_backoff\fR (integer)"
 Maximum number of milliseconds to wait between connection attempts.
-.IP "\fBinactivity_probe\fR (integer)
+.IP "\fBinactivity_probe\fR (integer)"
 Maximum number of milliseconds of idle time on connection to
 client before sending an inactivity probe message.
 .RE
@@ -92,11 +93,11 @@ configured remotes.
 The options described below for configuring the SSL public key
 infrastructure accept a special syntax for obtaining their
 configuration from the database.  If any of these options is given
-\fBdb:\fItable\fB,\fIcolumn\fR as its argument, then the actual file
-name is read from the specified \fIcolumn\fR in \fItable\fR within the
-\fBovsdb\-server\fR database.  The \fIcolumn\fR must have type string
-or set of strings.  The first nonempty string in the table is taken as
-the file name.  (This means that ordinarily there should be at most
+\fBdb:\fR[\fIdb\fB,\fR]\fItable\fB,\fIcolumn\fR as its argument, then the
+actual file name is read from the specified \fIcolumn\fR in \fItable\fR
+within the \fBovsdb\-server\fR database.  The \fIcolumn\fR must have type
+string or set of strings.  The first nonempty string in the table is taken
+as the file name.  (This means that ordinarily there should be at most
 one row in \fItable\fR.)
 .so lib/ssl.man
 .so lib/ssl-bootstrap.man
@@ -111,9 +112,10 @@ described below.
 These commands are specific to \fBovsdb\-server\fR.
 .IP "\fBexit\fR"
 Causes \fBovsdb\-server\fR to gracefully terminate.
-.IP "\fBovsdb\-server/compact\fR"
-Compacts the database in-place.  The database is also automatically
-compacted occasionally.
+.IP "\fBovsdb\-server/compact\fR [\fIdb\fR]\&..."
+Compacts each database \fIdb\fR in-place.  If no \fIdb\fR is
+specified, compacts every database in-place.  Databases are also
+automatically compacted occasionally.
 .
 .IP "\fBovsdb\-server/reconnect\fR"
 Makes \fBovsdb\-server\fR drop all of the JSON\-RPC
index 1bf10d9..69548c2 100644 (file)
@@ -25,6 +25,8 @@
 #include "command-line.h"
 #include "daemon.h"
 #include "dirs.h"
+#include "dummy.h"
+#include "dynamic-string.h"
 #include "file.h"
 #include "hash.h"
 #include "json.h"
 
 VLOG_DEFINE_THIS_MODULE(ovsdb_server);
 
+struct db {
+    /* Initialized in main(). */
+    char *filename;
+    struct ovsdb_file *file;
+    struct ovsdb *db;
+
+    /* Only used by update_remote_status(). */
+    struct ovsdb_txn *txn;
+};
+
 /* SSL configuration. */
 static char *private_key_file;
 static char *certificate_file;
@@ -65,17 +77,18 @@ static unixctl_cb_func ovsdb_server_exit;
 static unixctl_cb_func ovsdb_server_compact;
 static unixctl_cb_func ovsdb_server_reconnect;
 
-static void parse_options(int argc, char *argv[], char **file_namep,
+static void parse_options(int *argc, char **argvp[],
                           struct sset *remotes, char **unixctl_pathp,
                           char **run_command);
 static void usage(void) NO_RETURN;
 
 static void reconfigure_from_db(struct ovsdb_jsonrpc_server *jsonrpc,
-                                const struct ovsdb *db, struct sset *remotes);
+                                const struct db dbs[], size_t n_dbs,
+                                struct sset *remotes);
 
 static void update_remote_status(const struct ovsdb_jsonrpc_server *jsonrpc,
                                  const struct sset *remotes,
-                                 struct ovsdb *db);
+                                 struct db dbs[], size_t n_dbs);
 
 int
 main(int argc, char *argv[])
@@ -85,34 +98,53 @@ main(int argc, char *argv[])
     struct unixctl_server *unixctl;
     struct ovsdb_jsonrpc_server *jsonrpc;
     struct sset remotes;
-    struct ovsdb_error *error;
-    struct ovsdb_file *file;
-    struct ovsdb *db;
     struct process *run_process;
-    char *file_name;
     bool exiting;
     int retval;
     long long int status_timer = LLONG_MIN;
 
+    struct db *dbs;
+    int n_dbs;
+    int i;
+
     proctitle_init(argc, argv);
     set_program_name(argv[0]);
     stress_init_command();
     signal(SIGPIPE, SIG_IGN);
     process_init();
 
-    parse_options(argc, argv, &file_name, &remotes, &unixctl_path,
-                  &run_command);
+    parse_options(&argc, &argv, &remotes, &unixctl_path, &run_command);
 
     daemonize_start();
 
-    error = ovsdb_file_open(file_name, false, &db, &file);
-    if (error) {
-        ovs_fatal(0, "%s", ovsdb_error_to_string(error));
+    n_dbs = MAX(1, argc);
+    dbs = xcalloc(n_dbs + 1, sizeof *dbs);
+    if (argc > 0) {
+        for (i = 0; i < argc; i++) {
+            dbs[i].filename = argv[i];
+        }
+    } else {
+        dbs[0].filename = xasprintf("%s/conf.db", ovs_dbdir());
+    }
+
+    for (i = 0; i < n_dbs; i++) {
+        struct ovsdb_error *error;
+
+        error = ovsdb_file_open(dbs[i].filename, false,
+                                &dbs[i].db, &dbs[i].file);
+        if (error) {
+            ovs_fatal(0, "%s", ovsdb_error_to_string(error));
+        }
     }
-    free(file_name);
 
-    jsonrpc = ovsdb_jsonrpc_server_create(db);
-    reconfigure_from_db(jsonrpc, db, &remotes);
+    jsonrpc = ovsdb_jsonrpc_server_create();
+    for (i = 0; i < n_dbs; i++) {
+        if (!ovsdb_jsonrpc_server_add_db(jsonrpc, dbs[i].db)) {
+            ovs_fatal(0, "%s: duplicate database name",
+                      dbs[i].db->schema->name);
+        }
+    }
+    reconfigure_from_db(jsonrpc, dbs, n_dbs, &remotes);
 
     retval = unixctl_server_create(unixctl_path, &unixctl);
     if (retval) {
@@ -145,28 +177,35 @@ main(int argc, char *argv[])
     }
 
     unixctl_command_register("exit", "", 0, 0, ovsdb_server_exit, &exiting);
-    unixctl_command_register("ovsdb-server/compact", "", 0, 0,
-                             ovsdb_server_compact, file);
+    unixctl_command_register("ovsdb-server/compact", "", 0, 1,
+                             ovsdb_server_compact, dbs);
     unixctl_command_register("ovsdb-server/reconnect", "", 0, 0,
                              ovsdb_server_reconnect, jsonrpc);
 
     exiting = false;
     while (!exiting) {
+        int i;
+
         memory_run();
         if (memory_should_report()) {
             struct simap usage;
 
             simap_init(&usage);
             ovsdb_jsonrpc_server_get_memory_usage(jsonrpc, &usage);
-            ovsdb_get_memory_usage(db, &usage);
+            for (i = 0; i < n_dbs; i++) {
+                ovsdb_get_memory_usage(dbs[i].db, &usage);
+            }
             memory_report(&usage);
             simap_destroy(&usage);
         }
 
-        reconfigure_from_db(jsonrpc, db, &remotes);
+        reconfigure_from_db(jsonrpc, dbs, n_dbs, &remotes);
         ovsdb_jsonrpc_server_run(jsonrpc);
         unixctl_server_run(unixctl);
-        ovsdb_trigger_run(db, time_msec());
+
+        for (i = 0; i < n_dbs; i++) {
+            ovsdb_trigger_run(dbs[i].db, time_msec());
+        }
         if (run_process && process_exited(run_process)) {
             exiting = true;
         }
@@ -174,13 +213,15 @@ main(int argc, char *argv[])
         /* update Manager status(es) every 5 seconds */
         if (time_msec() >= status_timer) {
             status_timer = time_msec() + 5000;
-            update_remote_status(jsonrpc, &remotes, db);
+            update_remote_status(jsonrpc, &remotes, dbs, n_dbs);
         }
 
         memory_wait();
         ovsdb_jsonrpc_server_wait(jsonrpc);
         unixctl_server_wait(unixctl);
-        ovsdb_trigger_wait(db, time_msec());
+        for (i = 0; i < n_dbs; i++) {
+            ovsdb_trigger_wait(dbs[i].db, time_msec());
+        }
         if (run_process) {
             process_wait(run_process);
         }
@@ -191,7 +232,9 @@ main(int argc, char *argv[])
         poll_block();
     }
     ovsdb_jsonrpc_server_destroy(jsonrpc);
-    ovsdb_destroy(db);
+    for (i = 0; i < n_dbs; i++) {
+        ovsdb_destroy(dbs[i].db);
+    }
     sset_destroy(&remotes);
     unixctl_server_destroy(unixctl);
 
@@ -206,26 +249,64 @@ main(int argc, char *argv[])
     return 0;
 }
 
+static const struct db *
+find_db(const struct db dbs[], size_t n_dbs, const char *db_name)
+{
+    size_t i;
+
+    for (i = 0; i < n_dbs; i++) {
+        if (!strcmp(dbs[i].db->schema->name, db_name)) {
+            return &dbs[i];
+        }
+    }
+
+    return NULL;
+}
+
 static void
-parse_db_column(const struct ovsdb *db,
+parse_db_column(const struct db dbs[], size_t n_dbs,
                 const char *name_,
+                const struct db **dbp,
                 const struct ovsdb_table **tablep,
                 const struct ovsdb_column **columnp)
 {
-    char *name, *table_name, *column_name;
+    const char *table_name, *column_name;
     const struct ovsdb_column *column;
     const struct ovsdb_table *table;
+    const char *tokens[3];
     char *save_ptr = NULL;
+    const struct db *db;
+    char *name;
 
     name = xstrdup(name_);
     strtok_r(name, ":", &save_ptr); /* "db:" */
-    table_name = strtok_r(NULL, ",", &save_ptr);
-    column_name = strtok_r(NULL, ",", &save_ptr);
-    if (!table_name || !column_name) {
+    tokens[0] = strtok_r(NULL, ",", &save_ptr);
+    tokens[1] = strtok_r(NULL, ",", &save_ptr);
+    tokens[2] = strtok_r(NULL, ",", &save_ptr);
+    if (!tokens[0] || !tokens[1]) {
         ovs_fatal(0, "\"%s\": invalid syntax", name_);
     }
+    if (tokens[2]) {
+        const char *db_name = tokens[0];
+        table_name = tokens[1];
+        column_name = tokens[2];
+
+        db = find_db(dbs, n_dbs, tokens[0]);
+        if (!db) {
+            ovs_fatal(0, "\"%s\": no database named %s", name_, db_name);
+        }
+    } else {
+        if (n_dbs > 1) {
+            ovs_fatal(0, "\"%s\": database name must be specified (because "
+                      "multiple databases are configured)", name_);
+        }
+
+        table_name = tokens[0];
+        column_name = tokens[1];
+        db = &dbs[0];
+    }
 
-    table = ovsdb_get_table(db, table_name);
+    table = ovsdb_get_table(db->db, table_name);
     if (!table) {
         ovs_fatal(0, "\"%s\": no table named %s", name_, table_name);
     }
@@ -237,20 +318,23 @@ parse_db_column(const struct ovsdb *db,
     }
     free(name);
 
+    *dbp = db;
     *columnp = column;
     *tablep = table;
 }
 
 static void
-parse_db_string_column(const struct ovsdb *db,
+parse_db_string_column(const struct db dbs[], size_t n_dbs,
                        const char *name,
+                       const struct db **dbp,
                        const struct ovsdb_table **tablep,
                        const struct ovsdb_column **columnp)
 {
     const struct ovsdb_column *column;
     const struct ovsdb_table *table;
+    const struct db *db;
 
-    parse_db_column(db, name, &table, &column);
+    parse_db_column(dbs, n_dbs, name, &db, &table, &column);
 
     if (column->type.key.type != OVSDB_TYPE_STRING
         || column->type.value.type != OVSDB_TYPE_VOID) {
@@ -259,12 +343,13 @@ parse_db_string_column(const struct ovsdb *db,
                   name, table->schema->name, column->name);
     }
 
+    *dbp = db;
     *columnp = column;
     *tablep = table;
 }
 
 static OVS_UNUSED const char *
-query_db_string(const struct ovsdb *db, const char *name)
+query_db_string(const struct db dbs[], size_t n_dbs, const char *name)
 {
     if (!name || strncmp(name, "db:", 3)) {
         return name;
@@ -272,8 +357,9 @@ query_db_string(const struct ovsdb *db, const char *name)
         const struct ovsdb_column *column;
         const struct ovsdb_table *table;
         const struct ovsdb_row *row;
+        const struct db *db;
 
-        parse_db_string_column(db, name, &table, &column);
+        parse_db_string_column(dbs, n_dbs, name, &db, &table, &column);
 
         HMAP_FOR_EACH (row, hmap_node, &table->rows) {
             const struct ovsdb_datum *datum;
@@ -404,12 +490,24 @@ read_string_column(const struct ovsdb_row *row, const char *column_name,
 static void
 write_bool_column(struct ovsdb_row *row, const char *column_name, bool value)
 {
-    struct ovsdb_datum *datum = get_datum(row, column_name, OVSDB_TYPE_BOOLEAN,
-                                          OVSDB_TYPE_VOID, 1);
+    const struct ovsdb_column *column;
+    struct ovsdb_datum *datum;
 
+    column = ovsdb_table_schema_get_column(row->table->schema, column_name);
+    datum = get_datum(row, column_name, OVSDB_TYPE_BOOLEAN,
+                      OVSDB_TYPE_VOID, 1);
     if (!datum) {
         return;
     }
+
+    if (datum->n != 1) {
+        ovsdb_datum_destroy(datum, &column->type);
+
+        datum->n = 1;
+        datum->keys = xmalloc(sizeof *datum->keys);
+        datum->values = NULL;
+    }
+
     datum->keys[0].boolean = value;
 }
 
@@ -480,14 +578,15 @@ add_manager_options(struct shash *remotes, const struct ovsdb_row *row)
 }
 
 static void
-query_db_remotes(const char *name, const struct ovsdb *db,
+query_db_remotes(const char *name, const struct db dbs[], size_t n_dbs,
                  struct shash *remotes)
 {
     const struct ovsdb_column *column;
     const struct ovsdb_table *table;
     const struct ovsdb_row *row;
+    const struct db *db;
 
-    parse_db_column(db, name, &table, &column);
+    parse_db_column(dbs, n_dbs, name, &db, &table, &column);
 
     if (column->type.key.type == OVSDB_TYPE_STRING
         && column->type.value.type == OVSDB_TYPE_VOID) {
@@ -581,19 +680,20 @@ update_remote_row(const struct ovsdb_row *row, struct ovsdb_txn *txn,
 }
 
 static void
-update_remote_rows(const struct ovsdb *db, struct ovsdb_txn *txn,
+update_remote_rows(const struct db dbs[], size_t n_dbs,
                    const char *remote_name,
                    const struct ovsdb_jsonrpc_server *jsonrpc)
 {
     const struct ovsdb_table *table, *ref_table;
     const struct ovsdb_column *column;
     const struct ovsdb_row *row;
+    const struct db *db;
 
     if (strncmp("db:", remote_name, 3)) {
         return;
     }
 
-    parse_db_column(db, remote_name, &table, &column);
+    parse_db_column(dbs, n_dbs, remote_name, &db, &table, &column);
 
     if (column->type.key.type != OVSDB_TYPE_UUID
         || !column->type.key.u.uuid.refTable
@@ -613,7 +713,7 @@ update_remote_rows(const struct ovsdb *db, struct ovsdb_txn *txn,
 
             ref_row = ovsdb_table_get_row(ref_table, &datum->keys[i].uuid);
             if (ref_row) {
-                update_remote_row(ref_row, txn, jsonrpc);
+                update_remote_row(ref_row, db->txn, jsonrpc);
             }
         }
     }
@@ -621,32 +721,36 @@ update_remote_rows(const struct ovsdb *db, struct ovsdb_txn *txn,
 
 static void
 update_remote_status(const struct ovsdb_jsonrpc_server *jsonrpc,
-                     const struct sset *remotes, struct ovsdb *db)
+                     const struct sset *remotes,
+                     struct db dbs[], size_t n_dbs)
 {
     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
-    struct ovsdb_txn *txn;
-    const bool durable_txn = false;
-    struct ovsdb_error *error;
     const char *remote;
+    size_t i;
 
-    txn = ovsdb_txn_create(db);
+    for (i = 0; i < n_dbs; i++) {
+        dbs[i].txn = ovsdb_txn_create(dbs[i].db);
+    }
 
     /* Iterate over --remote arguments given on command line. */
     SSET_FOR_EACH (remote, remotes) {
-        update_remote_rows(db, txn, remote, jsonrpc);
+        update_remote_rows(dbs, n_dbs, remote, jsonrpc);
     }
 
-    error = ovsdb_txn_commit(txn, durable_txn);
-    if (error) {
-        VLOG_ERR_RL(&rl, "Failed to update remote status: %s",
-                    ovsdb_error_to_string(error));
+    for (i = 0; i < n_dbs; i++) {
+        struct ovsdb_error *error = ovsdb_txn_commit(dbs[i].txn, false);
+        if (error) {
+            VLOG_ERR_RL(&rl, "Failed to update remote status: %s",
+                        ovsdb_error_to_string(error));
+            ovsdb_error_destroy(error);
+        }
     }
 }
 
 /* Reconfigures ovsdb-server based on information in the database. */
 static void
 reconfigure_from_db(struct ovsdb_jsonrpc_server *jsonrpc,
-                    const struct ovsdb *db, struct sset *remotes)
+                    const struct db dbs[], size_t n_dbs, struct sset *remotes)
 {
     struct shash resolved_remotes;
     const char *name;
@@ -655,7 +759,7 @@ reconfigure_from_db(struct ovsdb_jsonrpc_server *jsonrpc,
     shash_init(&resolved_remotes);
     SSET_FOR_EACH (name, remotes) {
         if (!strncmp(name, "db:", 3)) {
-            query_db_remotes(name, db, &resolved_remotes);
+            query_db_remotes(name, dbs, n_dbs, &resolved_remotes);
         } else {
             add_remote(&resolved_remotes, name);
         }
@@ -664,9 +768,9 @@ reconfigure_from_db(struct ovsdb_jsonrpc_server *jsonrpc,
     shash_destroy_free_data(&resolved_remotes);
 
     /* Configure SSL. */
-    stream_ssl_set_key_and_cert(query_db_string(db, private_key_file),
-                                query_db_string(db, certificate_file));
-    stream_ssl_set_ca_cert_file(query_db_string(db, ca_cert_file),
+    stream_ssl_set_key_and_cert(query_db_string(dbs, n_dbs, private_key_file),
+                                query_db_string(dbs, n_dbs, certificate_file));
+    stream_ssl_set_ca_cert_file(query_db_string(dbs, n_dbs, ca_cert_file),
                                 bootstrap_ca_cert);
 }
 
@@ -681,22 +785,42 @@ ovsdb_server_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
 }
 
 static void
-ovsdb_server_compact(struct unixctl_conn *conn, int argc OVS_UNUSED,
-                     const char *argv[] OVS_UNUSED, void *file_)
+ovsdb_server_compact(struct unixctl_conn *conn, int argc,
+                     const char *argv[], void *dbs_)
 {
-    struct ovsdb_file *file = file_;
-    struct ovsdb_error *error;
+    struct db *dbs = dbs_;
+    struct ds reply;
+    struct db *db;
+    int n = 0;
 
-    VLOG_INFO("compacting database by user request");
-    error = ovsdb_file_compact(file);
-    if (!error) {
-        unixctl_command_reply(conn, NULL);
+    ds_init(&reply);
+    for (db = dbs; db->filename != NULL; db++) {
+        const char *name = db->db->schema->name;
+
+        if (argc < 2 || !strcmp(argv[1], name)) {
+            struct ovsdb_error *error;
+
+            VLOG_INFO("compacting %s database by user request", name);
+
+            error = ovsdb_file_compact(db->file);
+            if (error) {
+                char *s = ovsdb_error_to_string(error);
+                ds_put_format(&reply, "%s\n", s);
+                free(s);
+            }
+
+            n++;
+        }
+    }
+
+    if (!n) {
+        unixctl_command_reply_error(conn, "no database by that name");
+    } else if (reply.length) {
+        unixctl_command_reply_error(conn, ds_cstr(&reply));
     } else {
-        char *s = ovsdb_error_to_string(error);
-        ovsdb_error_destroy(error);
-        unixctl_command_reply_error(conn, s);
-        free(s);
+        unixctl_command_reply(conn, NULL);
     }
+    ds_destroy(&reply);
 }
 
 /* "ovsdb-server/reconnect": makes ovsdb-server drop all of its JSON-RPC
@@ -712,16 +836,15 @@ ovsdb_server_reconnect(struct unixctl_conn *conn, int argc OVS_UNUSED,
 }
 
 static void
-parse_options(int argc, char *argv[], char **file_namep,
-              struct sset *remotes, char **unixctl_pathp,
-              char **run_command)
+parse_options(int *argcp, char **argvp[],
+              struct sset *remotes, char **unixctl_pathp, char **run_command)
 {
     enum {
-        OPT_DUMMY = UCHAR_MAX + 1,
-        OPT_REMOTE,
+        OPT_REMOTE = UCHAR_MAX + 1,
         OPT_UNIXCTL,
         OPT_RUN,
         OPT_BOOTSTRAP_CA_CERT,
+        OPT_ENABLE_DUMMY,
         VLOG_OPTION_ENUMS,
         LEAK_CHECKER_OPTION_ENUMS,
         DAEMON_OPTION_ENUMS
@@ -739,9 +862,12 @@ parse_options(int argc, char *argv[], char **file_namep,
         {"private-key", required_argument, NULL, 'p'},
         {"certificate", required_argument, NULL, 'c'},
         {"ca-cert",     required_argument, NULL, 'C'},
+        {"enable-dummy", optional_argument, NULL, OPT_ENABLE_DUMMY},
         {NULL, 0, NULL, 0},
     };
     char *short_options = long_options_to_short_options(long_options);
+    int argc = *argcp;
+    char **argv = *argvp;
 
     sset_init(remotes);
     for (;;) {
@@ -794,6 +920,10 @@ parse_options(int argc, char *argv[], char **file_namep,
             bootstrap_ca_cert = true;
             break;
 
+        case OPT_ENABLE_DUMMY:
+            dummy_enable(optarg && !strcmp(optarg, "override"));
+            break;
+
         case '?':
             exit(EXIT_FAILURE);
 
@@ -803,31 +933,18 @@ parse_options(int argc, char *argv[], char **file_namep,
     }
     free(short_options);
 
-    argc -= optind;
-    argv += optind;
-
-    switch (argc) {
-    case 0:
-        *file_namep = xasprintf("%s/conf.db", ovs_dbdir());
-        break;
-
-    case 1:
-        *file_namep = xstrdup(argv[0]);
-        break;
-
-    default:
-        ovs_fatal(0, "database file is only non-option argument; "
-                "use --help for usage");
-    }
+    *argcp -= optind;
+    *argvp += optind;
 }
 
 static void
 usage(void)
 {
     printf("%s: Open vSwitch database server\n"
-           "usage: %s [OPTIONS] DATABASE\n"
-           "where DATABASE is a database file in ovsdb format.\n",
-           program_name, program_name);
+           "usage: %s [OPTIONS] [DATABASE...]\n"
+           "where each DATABASE is a database file in ovsdb format.\n"
+           "The default DATABASE, if none is given, is\n%s/conf.db.\n",
+           program_name, program_name, ovs_dbdir());
     printf("\nJSON-RPC options (may be specified any number of times):\n"
            "  --remote=REMOTE         connect or listen to REMOTE\n");
     stream_usage("JSON-RPC", true, true, true);
index 7cd4263..ac2aa29 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011 Nicira, Inc.
+/* Copyright (c) 2011, 2012 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 <assert.h>
 
 #include "hash.h"
+#include "ovsdb.h"
 
-/* Initializes 'session' as a session that operates on 'db'. */
+/* Initializes 'session' as a session within 'server'. */
 void
-ovsdb_session_init(struct ovsdb_session *session, struct ovsdb *db)
+ovsdb_session_init(struct ovsdb_session *session, struct ovsdb_server *server)
 {
-    session->db = db;
+    session->server = server;
     list_init(&session->completions);
     hmap_init(&session->waiters);
 }
@@ -113,18 +114,31 @@ ovsdb_lock_waiter_is_owner(const struct ovsdb_lock_waiter *waiter)
     return waiter->lock && waiter == ovsdb_lock_get_owner(waiter->lock);
 }
 
-/* Initializes 'server' as a server that operates on 'db'. */
+/* Initializes 'server'.
+ *
+ * The caller must call ovsdb_server_add_db() for each database to which
+ * 'server' should provide access. */
 void
-ovsdb_server_init(struct ovsdb_server *server, struct ovsdb *db)
+ovsdb_server_init(struct ovsdb_server *server)
 {
-    server->db = db;
+    shash_init(&server->dbs);
     hmap_init(&server->locks);
 }
 
+/* Adds 'db' to the set of databases served out by 'server'.  Returns true if
+ * successful, false if 'db''s name is the same as some database already in
+ * 'server'. */
+bool
+ovsdb_server_add_db(struct ovsdb_server *server, struct ovsdb *db)
+{
+    return shash_add_once(&server->dbs, db->schema->name, db);
+}
+
 /* Destroys 'server'. */
 void
 ovsdb_server_destroy(struct ovsdb_server *server)
 {
+    shash_destroy(&server->dbs);
     hmap_destroy(&server->locks);
 }
 
index e073850..561f01e 100644 (file)
 
 #include "hmap.h"
 #include "list.h"
+#include "shash.h"
+
+struct ovsdb;
+struct ovsdb_server;
 
 /* Abstract representation of an OVSDB client connection, not tied to any
  * particular network protocol.  Protocol implementations
  * (e.g. jsonrpc-server.c) embed this in a larger data structure.  */
 struct ovsdb_session {
-    struct ovsdb *db;
+    struct ovsdb_server *server;
     struct list completions;    /* Completed triggers. */
     struct hmap waiters;        /* "ovsdb_lock_waiter *"s by lock name. */
 };
 
-void ovsdb_session_init(struct ovsdb_session *, struct ovsdb *);
+void ovsdb_session_init(struct ovsdb_session *, struct ovsdb_server *);
 void ovsdb_session_destroy(struct ovsdb_session *);
 
 struct ovsdb_lock_waiter *ovsdb_session_get_lock_waiter(
@@ -73,11 +77,12 @@ bool ovsdb_lock_waiter_is_owner(const struct ovsdb_lock_waiter *);
  * network protocol.  Protocol implementations (e.g. jsonrpc-server.c) embed
  * this in a larger data structure.  */
 struct ovsdb_server {
-    struct ovsdb *db;
+    struct shash dbs;      /* Maps from a db name to a "struct ovsdb *". */
     struct hmap locks;     /* Contains "struct ovsdb_lock"s indexed by name. */
 };
 
-void ovsdb_server_init(struct ovsdb_server *, struct ovsdb *);
+void ovsdb_server_init(struct ovsdb_server *);
+bool ovsdb_server_add_db(struct ovsdb_server *, struct ovsdb *);
 void ovsdb_server_destroy(struct ovsdb_server *);
 
 struct ovsdb_lock_waiter *ovsdb_server_lock(struct ovsdb_server *,
index 6ae1f51..a93b844 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -30,12 +30,13 @@ static bool ovsdb_trigger_try(struct ovsdb_trigger *, long long int now);
 static void ovsdb_trigger_complete(struct ovsdb_trigger *);
 
 void
-ovsdb_trigger_init(struct ovsdb_session *session,
+ovsdb_trigger_init(struct ovsdb_session *session, struct ovsdb *db,
                    struct ovsdb_trigger *trigger,
                    struct json *request, long long int now)
 {
     trigger->session = session;
-    list_push_back(&trigger->session->db->triggers, &trigger->node);
+    trigger->db = db;
+    list_push_back(&trigger->db->triggers, &trigger->node);
     trigger->request = request;
     trigger->result = NULL;
     trigger->created = now;
@@ -110,7 +111,7 @@ ovsdb_trigger_wait(struct ovsdb *db, long long int now)
 static bool
 ovsdb_trigger_try(struct ovsdb_trigger *t, long long int now)
 {
-    t->result = ovsdb_execute(t->session->db, t->session,
+    t->result = ovsdb_execute(t->db, t->session,
                               t->request, now - t->created, &t->timeout_msec);
     if (t->result) {
         ovsdb_trigger_complete(t);
index 1d47f3f..f686b15 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2011 Nicira, Inc.
+/* Copyright (c) 2009, 2011, 2012 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -22,7 +22,8 @@ struct ovsdb;
 
 struct ovsdb_trigger {
     struct ovsdb_session *session; /* Session that owns this trigger. */
-    struct list node;           /* !result: in session->db->triggers;
+    struct ovsdb *db;           /* Database on which trigger acts. */
+    struct list node;           /* !result: in db->triggers;
                                  * result: in session->completions. */
     struct json *request;       /* Database request. */
     struct json *result;        /* Result (null if none yet). */
@@ -30,7 +31,8 @@ struct ovsdb_trigger {
     long long int timeout_msec; /* Max wait duration. */
 };
 
-void ovsdb_trigger_init(struct ovsdb_session *, struct ovsdb_trigger *,
+void ovsdb_trigger_init(struct ovsdb_session *, struct ovsdb *,
+                        struct ovsdb_trigger *,
                         struct json *request, long long int now);
 void ovsdb_trigger_destroy(struct ovsdb_trigger *);
 
index 3a8dec2..9e9bf0f 100644 (file)
@@ -548,6 +548,9 @@ class Row(object):
 
         datum = self._changes.get(column_name)
         if datum is None:
+            if self._data is None:
+                raise AttributeError("%s instance has no attribute '%s'" %
+                                     (self.__class__.__name__, column_name))
             datum = self._data[column_name]
 
         return datum.to_python(_uuid_to_row)
index a978707..dd45fe4 100644 (file)
@@ -84,6 +84,41 @@ def check_connection_completion(sock):
         return errno.EAGAIN
 
 
+def inet_parse_active(target, default_port):
+    address = target.split(":")
+    host_name = address[0]
+    if not host_name:
+        raise ValueError("%s: bad peer name format" % target)
+    if len(address) >= 2:
+        port = int(address[1])
+    elif default_port:
+        port = default_port
+    else:
+        raise ValueError("%s: port number must be specified" % target)
+    return (host_name, port)
+
+
+def inet_open_active(style, target, default_port, dscp):
+    address = inet_parse_active(target, default_port)
+    try:
+        sock = socket.socket(socket.AF_INET, style, 0)
+    except socket.error, e:
+        return get_exception_errno(e), None
+
+    try:
+        set_nonblocking(sock)
+        set_dscp(sock, dscp)
+        try:
+            sock.connect(address)
+        except socket.error, e:
+            if get_exception_errno(e) != errno.EINPROGRESS:
+                raise
+        return 0, sock
+    except socket.error, e:
+        sock.close()
+        return get_exception_errno(e), None
+
+
 def get_socket_error(sock):
     """Returns the errno value associated with 'socket' (0 if no error) and
     resets the socket's error status."""
@@ -148,3 +183,10 @@ def set_nonblocking(sock):
     except socket.error, e:
         vlog.err("could not set nonblocking mode on socket: %s"
                  % os.strerror(get_socket_error(e)))
+
+
+def set_dscp(sock, dscp):
+    if dscp > 63:
+        raise ValueError("Invalid dscp %d" % dscp)
+    val = dscp << 2
+    sock.setsockopt(socket.IPPROTO_IP, socket.IP_TOS, val)
index 9c10612..dad6848 100644 (file)
@@ -51,12 +51,25 @@ class Stream(object):
     W_RECV = 1                  # Data received.
     W_SEND = 2                  # Send buffer room available.
 
+    _SOCKET_METHODS = {}
+
+    @staticmethod
+    def register_method(method, cls):
+        Stream._SOCKET_METHODS[method + ":"] = cls
+
+    @staticmethod
+    def _find_method(name):
+        for method, cls in Stream._SOCKET_METHODS.items():
+            if name.startswith(method):
+                return cls
+        return None
+
     @staticmethod
     def is_valid_name(name):
         """Returns True if 'name' is a stream name in the form "TYPE:ARGS" and
-        TYPE is a supported stream type (currently only "unix:"), otherwise
-        False."""
-        return name.startswith("unix:")
+        TYPE is a supported stream type (currently only "unix:" and "tcp:"),
+        otherwise False."""
+        return bool(Stream._find_method(name))
 
     def __init__(self, socket, name, status):
         self.socket = socket
@@ -70,12 +83,18 @@ class Stream(object):
 
         self.error = 0
 
+    # Default value of dscp bits for connection between controller and manager.
+    # Value of IPTOS_PREC_INTERNETCONTROL = 0xc0 which is defined
+    # in <netinet/ip.h> is used.
+    IPTOS_PREC_INTERNETCONTROL = 0xc0
+    DSCP_DEFAULT = IPTOS_PREC_INTERNETCONTROL >> 2
+
     @staticmethod
-    def open(name):
+    def open(name, dscp=DSCP_DEFAULT):
         """Attempts to connect a stream to a remote peer.  'name' is a
         connection name in the form "TYPE:ARGS", where TYPE is an active stream
         class's name and ARGS are stream class-specific.  Currently the only
-        supported TYPE is "unix".
+        supported TYPEs are "unix" and "tcp".
 
         Returns (error, stream): on success 'error' is 0 and 'stream' is the
         new Stream, on failure 'error' is a positive errno value and 'stream'
@@ -84,19 +103,22 @@ class Stream(object):
         Never returns errno.EAGAIN or errno.EINPROGRESS.  Instead, returns 0
         and a new Stream.  The connect() method can be used to check for
         successful connection completion."""
-        if not Stream.is_valid_name(name):
+        cls = Stream._find_method(name)
+        if not cls:
             return errno.EAFNOSUPPORT, None
 
-        connect_path = name[5:]
-        error, sock = ovs.socket_util.make_unix_socket(socket.SOCK_STREAM,
-                                                       True, None,
-                                                       connect_path)
+        suffix = name.split(":", 1)[1]
+        error, sock = cls._open(suffix, dscp)
         if error:
             return error, None
         else:
             status = ovs.socket_util.check_connection_completion(sock)
             return 0, Stream(sock, name, status)
 
+    @staticmethod
+    def _open(suffix, dscp):
+        raise NotImplementedError("This method must be overrided by subclass")
+
     @staticmethod
     def open_block((error, stream)):
         """Blocks until a Stream completes its connection attempt, either
@@ -313,6 +335,27 @@ def usage(name):
     return """
 Active %s connection methods:
   unix:FILE               Unix domain socket named FILE
+  tcp:IP:PORT             TCP socket to IP with port no of PORT
 
 Passive %s connection methods:
   punix:FILE              Listen on Unix domain socket FILE""" % (name, name)
+
+
+class UnixStream(Stream):
+    @staticmethod
+    def _open(suffix, dscp):
+        connect_path = suffix
+        return  ovs.socket_util.make_unix_socket(socket.SOCK_STREAM,
+                                                 True, None, connect_path)
+Stream.register_method("unix", UnixStream)
+
+
+class TCPStream(Stream):
+    @staticmethod
+    def _open(suffix, dscp):
+        error, sock = ovs.socket_util.inet_open_active(socket.SOCK_STREAM,
+                                                       suffix, 0, dscp)
+        if not error:
+            sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+        return error, sock
+Stream.register_method("tcp", TCPStream)
index 69e69b9..fa2554f 100644 (file)
@@ -1,3 +1,5 @@
 openvswitch-kmod-rhel5.spec
 openvswitch-kmod-rhel6.spec
+openvswitch-kmod-fedora.spec
 openvswitch.spec
+openvswitch-fedora.spec
index 4c1d782..3bdc4ce 100644 (file)
@@ -17,9 +17,14 @@ EXTRA_DIST += \
        rhel/openvswitch-kmod-rhel5.spec.in \
        rhel/openvswitch-kmod-rhel6.spec \
        rhel/openvswitch-kmod-rhel6.spec.in \
+       rhel/openvswitch-kmod-fedora.spec \
+       rhel/openvswitch-kmod-fedora.spec.in \
        rhel/openvswitch.spec \
        rhel/openvswitch.spec.in \
-       rhel/usr_share_openvswitch_scripts_sysconfig.template
+       rhel/openvswitch-fedora.spec \
+       rhel/openvswitch-fedora.spec.in \
+       rhel/usr_share_openvswitch_scripts_sysconfig.template \
+       rhel/usr_lib_systemd_system_openvswitch.service
 
 update_rhel_spec = \
   ($(ro_shell) && sed -e 's,[@]VERSION[@],$(VERSION),g') \
@@ -32,5 +37,11 @@ $(srcdir)/rhel/openvswitch-kmod-rhel5.spec: rhel/openvswitch-kmod-rhel5.spec.in
 $(srcdir)/rhel/openvswitch-kmod-rhel6.spec: rhel/openvswitch-kmod-rhel6.spec.in $(top_builddir)/config.status
        $(update_rhel_spec)
 
+$(srcdir)/rhel/openvswitch-kmod-fedora.spec: rhel/openvswitch-kmod-fedora.spec.in $(top_builddir)/config.status
+       $(update_rhel_spec)
+
 $(srcdir)/rhel/openvswitch.spec: rhel/openvswitch.spec.in $(top_builddir)/config.status
        $(update_rhel_spec)
+
+$(srcdir)/rhel/openvswitch-fedora.spec: rhel/openvswitch-fedora.spec.in $(top_builddir)/config.status
+       $(update_rhel_spec)
index ad7579c..af332c0 100755 (executable)
@@ -61,6 +61,15 @@ stop () {
     rm -f /var/lock/subsys/openvswitch
 }
 
+restart () {
+    if [ "$1" = "--save-flows=yes" ]; then
+        start restart
+    else
+        stop
+        start
+    fi
+}
+
 ovs_ctl=/usr/share/openvswitch/scripts/ovs-ctl
 case $1 in
     start)
@@ -70,8 +79,8 @@ case $1 in
         stop
         ;;
     restart)
-        stop
-        start
+        shift
+        restart "$@"
         ;;
     reload|force-reload)
         # Nothing to do.
diff --git a/rhel/openvswitch-fedora.spec.in b/rhel/openvswitch-fedora.spec.in
new file mode 100644 (file)
index 0000000..7918fd5
--- /dev/null
@@ -0,0 +1,199 @@
+# Spec file for Open vSwitch.
+
+# Copyright (C) 2009, 2010 Nicira Networks, Inc.
+#
+# Copying and distribution of this file, with or without modification,
+# are permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved.  This file is offered as-is,
+# without warranty of any kind.
+
+#%define kernel 2.6.40.4-5.fc15.x86_64
+
+Name: openvswitch
+Summary: Open vSwitch
+Group: System Environment/Daemons
+URL: http://www.openvswitch.org/
+Version: @VERSION@
+
+# The entire source code is ASL 2.0 except datapath/ which is GPLv2
+License: ASL 2.0
+Release: 1%{?dist}
+Source: openvswitch-%{version}.tar.gz
+#Source1: openvswitch-init
+Buildroot: /tmp/openvswitch-fedora-rpm
+
+Requires(post):  systemd-units
+Requires(preun): systemd-units
+Requires(postun): systemd-units
+
+%description
+Open vSwitch provides standard network bridging functions augmented with
+support for the OpenFlow protocol for remote per-flow control of
+traffic.
+
+%prep
+%setup -q -n openvswitch-%{version}
+
+%build
+./configure --prefix=/usr --sysconfdir=/etc --localstatedir=%{_localstatedir} --enable-ssl %{build_number}
+make %{_smp_mflags}
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make install DESTDIR=$RPM_BUILD_ROOT
+install -d -m 755 $RPM_BUILD_ROOT/etc
+install -d -m 755 $RPM_BUILD_ROOT/etc/openvswitch
+install -p -D -m 0644 rhel/usr_lib_systemd_system_openvswitch.service \
+        $RPM_BUILD_ROOT%{_unitdir}/openvswitch.service
+install -m 755 rhel/etc_init.d_openvswitch \
+        $RPM_BUILD_ROOT%{_datadir}/openvswitch/scripts/openvswitch.init
+install -d -m 755 $RPM_BUILD_ROOT/etc/sysconfig
+install -d -m 755 $RPM_BUILD_ROOT/etc/logrotate.d
+install -m 755 rhel/etc_logrotate.d_openvswitch \
+        $RPM_BUILD_ROOT/etc/logrotate.d/openvswitch
+install -d -m 755 $RPM_BUILD_ROOT/etc/profile.d
+install -m 644 vswitchd/vswitch.ovsschema \
+        $RPM_BUILD_ROOT/usr/share/openvswitch/vswitch.ovsschema
+install -d -m 755 $RPM_BUILD_ROOT/usr/share/openvswitch/scripts
+install -d -m 0755 $RPM_BUILD_ROOT/etc/sysconfig/network-scripts/
+install -p -m 0755 rhel/etc_sysconfig_network-scripts_ifdown-ovs \
+        $RPM_BUILD_ROOT/etc/sysconfig/network-scripts/ifdown-ovs
+install -p -m 0755 rhel/etc_sysconfig_network-scripts_ifup-ovs \
+        $RPM_BUILD_ROOT/etc/sysconfig/network-scripts/ifup-ovs
+install -p -D -m 0644 rhel/usr_share_openvswitch_scripts_sysconfig.template \
+        $RPM_BUILD_ROOT/etc/sysconfig/openvswitch
+install -d -m 755 $RPM_BUILD_ROOT/usr/share/openvswitch/scripts
+
+install python/compat/uuid.py $RPM_BUILD_ROOT/usr/share/openvswitch/python
+install python/compat/argparse.py $RPM_BUILD_ROOT/usr/share/openvswitch/python
+
+install -d -m 755 $RPM_BUILD_ROOT/var/lib/openvswitch
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%preun
+# Package removal, not upgrade
+systemctl stop openvswitch.service
+systemctl disable openvswitch.service
+
+%post
+if test ! -e /etc/openvswitch/conf.db; then
+    install -d -m 755 -o root -g root /etc/openvswitch
+
+    # Create ovs-vswitchd config database
+    ovsdb-tool -vANY:console:emer create /etc/openvswitch/conf.db \
+            /usr/share/openvswitch/vswitch.ovsschema
+
+    # Create initial table in config database
+    ovsdb-tool -vANY:console:emer transact /etc/openvswitch/conf.db \
+            '[{"op": "insert", "table": "Open_vSwitch", "row": {}}]' \
+            > /dev/null
+fi
+# Initial installation
+systemctl enable openvswitch.service
+systemctl start openvswitch.service
+
+%postun
+
+%files
+%defattr(-,root,root)
+%config /etc/sysconfig/openvswitch
+%config /etc/logrotate.d/openvswitch
+%{_unitdir}/openvswitch.service
+%{_datadir}/openvswitch/scripts/openvswitch.init
+%{_sysconfdir}/sysconfig/network-scripts/ifup-ovs
+%{_sysconfdir}/sysconfig/network-scripts/ifdown-ovs
+/usr/share/openvswitch/bugtool-plugins/
+/usr/share/openvswitch/python/ovs/__init__.py
+/usr/share/openvswitch/python/ovs/daemon.py
+/usr/share/openvswitch/python/ovs/db/__init__.py
+/usr/share/openvswitch/python/ovs/db/data.py
+/usr/share/openvswitch/python/ovs/db/error.py
+/usr/share/openvswitch/python/ovs/db/idl.py
+/usr/share/openvswitch/python/ovs/db/parser.py
+/usr/share/openvswitch/python/ovs/db/schema.py
+/usr/share/openvswitch/python/ovs/db/types.py
+/usr/share/openvswitch/python/ovs/dirs.py
+/usr/share/openvswitch/python/ovs/fatal_signal.py
+/usr/share/openvswitch/python/ovs/json.py
+/usr/share/openvswitch/python/ovs/jsonrpc.py
+/usr/share/openvswitch/python/ovs/ovsuuid.py
+/usr/share/openvswitch/python/ovs/poller.py
+/usr/share/openvswitch/python/ovs/process.py
+/usr/share/openvswitch/python/ovs/reconnect.py
+/usr/share/openvswitch/python/ovs/socket_util.py
+/usr/share/openvswitch/python/ovs/stream.py
+/usr/share/openvswitch/python/ovs/timeval.py
+/usr/share/openvswitch/python/ovs/util.py
+/usr/share/openvswitch/python/ovs/version.py
+/usr/share/openvswitch/python/ovs/unixctl/__init__.py
+/usr/share/openvswitch/python/ovs/unixctl/client.py
+/usr/share/openvswitch/python/ovs/unixctl/server.py
+/usr/share/openvswitch/python/uuid.py
+/usr/share/openvswitch/python/argparse.py
+/usr/share/openvswitch/python/ovs/vlog.py
+/usr/share/openvswitch/python/ovstest/__init__.py
+/usr/share/openvswitch/python/ovstest/args.py
+/usr/share/openvswitch/python/ovstest/rpcserver.py
+/usr/share/openvswitch/python/ovstest/tcp.py
+/usr/share/openvswitch/python/ovstest/udp.py
+/usr/share/openvswitch/python/ovstest/util.py
+/usr/share/openvswitch/python/ovstest/vswitch.py
+/usr/share/openvswitch/python/ovstest/tests.py
+/usr/share/openvswitch/scripts/ovs-bugtool-*
+/usr/share/openvswitch/scripts/ovs-check-dead-ifs
+/usr/share/openvswitch/scripts/ovs-lib
+%config /usr/share/openvswitch/vswitch.ovsschema
+/usr/sbin/ovs-brcompatd
+/usr/sbin/ovs-bugtool
+/usr/sbin/ovs-vswitchd
+/usr/sbin/ovsdb-server
+/usr/bin/ovs-appctl
+/usr/bin/ovs-dpctl
+/usr/bin/ovs-ofctl
+/usr/bin/ovs-vsctl
+/usr/bin/ovsdb-client
+/usr/bin/ovsdb-tool
+/usr/bin/ovs-controller
+/usr/bin/ovs-pki
+/usr/bin/ovs-test
+/usr/bin/ovs-l3ping
+%doc /usr/share/man/man8/ovs-controller.8.gz
+%doc /usr/share/man/man8/ovs-pki.8.gz
+%doc /usr/share/man/man1/ovsdb-client.1.gz
+%doc /usr/share/man/man1/ovsdb-server.1.gz
+%doc /usr/share/man/man1/ovsdb-tool.1.gz
+%doc /usr/share/man/man5/ovs-vswitchd.conf.db.5.gz
+%doc /usr/share/man/man8/ovs-appctl.8.gz
+%doc /usr/share/man/man8/ovs-bugtool.8.gz
+%doc /usr/share/man/man8/ovs-brcompatd.8.gz
+%doc /usr/share/man/man8/ovs-dpctl.8.gz
+%doc /usr/share/man/man8/ovs-ofctl.8.gz
+%doc /usr/share/man/man8/ovs-parse-backtrace.8.gz
+%doc /usr/share/man/man8/ovs-parse-leaks.8.gz
+%doc /usr/share/man/man8/ovs-vsctl.8.gz
+%doc /usr/share/man/man8/ovs-vswitchd.8.gz
+%doc /usr/share/man/man8/ovs-test.8.gz
+%doc /usr/share/man/man8/ovs-l3ping.8.gz
+/var/lib/openvswitch
+/usr/share/openvswitch/scripts/ovs-ctl
+%exclude /etc/openvswitch
+%exclude /usr/bin/ovs-benchmark
+%exclude /usr/bin/ovs-parse-backtrace
+%exclude /usr/bin/ovs-parse-leaks
+%exclude /usr/bin/ovs-pcap
+%exclude /usr/bin/ovs-tcpundump
+%exclude /usr/bin/ovs-vlan-test
+%exclude /usr/sbin/ovs-vlan-bug-workaround
+%exclude /usr/share/man/man1/ovs-benchmark.1.gz
+%exclude /usr/share/man/man1/ovs-pcap.1.gz
+%exclude /usr/share/man/man1/ovs-tcpundump.1.gz
+%exclude /usr/share/man/man8/ovs-ctl.8.gz
+%exclude /usr/share/man/man8/ovs-vlan-bug-workaround.8.gz
+%exclude /usr/share/man/man8/ovs-vlan-test.8.gz
+%exclude /usr/share/openvswitch/scripts/ovs-save
+
+%changelog
+* Wed Jan 12 2011 Ralf Spenneberg <ralf@os-s.net>
+- First build on F14
diff --git a/rhel/openvswitch-kmod-fedora.spec.in b/rhel/openvswitch-kmod-fedora.spec.in
new file mode 100644 (file)
index 0000000..af75ddd
--- /dev/null
@@ -0,0 +1,65 @@
+# Spec file for Open vSwitch.
+
+# Copyright (C) 2009, 2010 Nicira Networks, Inc.
+#
+# Copying and distribution of this file, with or without modification,
+# are permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved.  This file is offered as-is,
+# without warranty of any kind.
+
+#%define kernel 3.1.5-1.fc16.x86_64
+#define kernel %{kernel_source}
+%{?kversion:%define kernel %kversion}
+
+Name: openvswitch-kmod
+Summary: Open vSwitch Kernel Modules
+Group: System Environment/Daemons
+URL: http://www.openvswitch.org/
+Vendor: OpenSource Security Ralf Spenneberg <ralf@os-s.net>
+Version: @VERSION@
+
+# The entire source code is ASL 2.0 except datapath/ which is GPLv2
+License: GPLv2
+Release: 1%{?dist}
+Source: openvswitch-%{version}.tar.gz
+#Source1: openvswitch-init
+Buildroot: /tmp/openvswitch-xen-rpm
+
+%description
+Open vSwitch provides standard network bridging functions augmented with
+support for the OpenFlow protocol for remote per-flow control of
+traffic. This package contains the kernel modules.
+
+%prep
+%setup -q -n openvswitch-%{version}
+
+%build
+./configure --prefix=/usr --sysconfdir=/etc --localstatedir=%{_localstatedir} --with-linux=/lib/modules/%{kernel}/build --enable-ssl %{build_number}
+make %{_smp_mflags} -C datapath/linux
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make -C datapath/linux modules_install
+
+install -d -m 755 $RPM_BUILD_ROOT/lib/modules/%{kernel}/kernel/extra/openvswitch
+find datapath/linux -name *.ko -exec install -m 755  \{\} $RPM_BUILD_ROOT/lib/modules/%{kernel}/kernel/extra/openvswitch \;
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%preun
+
+%post
+# Ensure that modprobe will find our modules.
+depmod %{kernel}
+
+%files
+%defattr(-,root,root)
+/lib/modules/%{kernel}/kernel/extra/openvswitch/openvswitch.ko
+/lib/modules/%{kernel}/kernel/extra/openvswitch/brcompat.ko
+
+%changelog
+* Wed Sep 21 2011 Kyle Mestery <kmestery@cisco.com>
+- Updated for F15
+* Wed Jan 12 2011 Ralf Spenneberg <ralf@os-s.net>
+- First build on F14
index de22c86..ff598b9 100644 (file)
@@ -115,6 +115,7 @@ exit 0
 /usr/bin/ovs-benchmark
 /usr/bin/ovs-dpctl
 /usr/bin/ovs-ofctl
+/usr/bin/ovs-parse-backtrace
 /usr/bin/ovs-parse-leaks
 /usr/bin/ovs-pcap
 /usr/bin/ovs-pki
@@ -140,6 +141,7 @@ exit 0
 /usr/share/man/man8/ovs-ctl.8.gz
 /usr/share/man/man8/ovs-dpctl.8.gz
 /usr/share/man/man8/ovs-ofctl.8.gz
+/usr/share/man/man8/ovs-parse-backtrace.8.gz
 /usr/share/man/man8/ovs-parse-leaks.8.gz
 /usr/share/man/man8/ovs-pki.8.gz
 /usr/share/man/man8/ovs-vlan-test.8.gz
diff --git a/rhel/usr_lib_systemd_system_openvswitch.service b/rhel/usr_lib_systemd_system_openvswitch.service
new file mode 100644 (file)
index 0000000..f39d7e6
--- /dev/null
@@ -0,0 +1,12 @@
+[Unit]
+Description=Open vSwitch
+After=syslog.target network.target
+
+[Service]
+Type=oneshot
+ExecStart=/usr/share/openvswitch/scripts/openvswitch.init start
+ExecStop=/usr/share/openvswitch/scripts/openvswitch.init stop
+RemainAfterExit=yes
+
+[Install]
+WantedBy=multi-user.target
index 5360225..c736df4 100644 (file)
@@ -32,3 +32,23 @@ if test $HAVE_PYTHON = yes; then
         export PYTHONPATH
     fi
 fi
+
+# Enable malloc debugging features.
+case `uname` in
+Linux)
+    MALLOC_CHECK_=2
+    MALLOC_PERTURB_=165
+    export MALLOC_CHECK_
+    export MALLOC_PERTURB_
+    ;;
+FreeBSD)
+    case `uname -r` in
+    [789].*)
+        MALLOC_CONF=AJ
+        ;;
+    *)
+        MALLOC_CONF=abort:true,junk:true,redzone:true
+        ;;
+    esac
+    export MALLOC_CONF
+esac
index 20f9e82..2977f76 100644 (file)
@@ -146,7 +146,6 @@ check-valgrind: all tests/atconfig tests/atlocal $(TESTSUITE) \
 clean-local:
        test ! -f '$(TESTSUITE)' || $(SHELL) '$(TESTSUITE)' -C tests --clean
 
-AUTOM4TE = autom4te
 AUTOTEST = $(AUTOM4TE) --language=autotest
 $(TESTSUITE): package.m4 $(TESTSUITE_AT)
        $(AUTOTEST) -I '$(srcdir)' -o $@.tmp $@.at
index 7ba9277..e232435 100644 (file)
@@ -1,7 +1,7 @@
 AT_BANNER([OpenFlow actions])
 
 AT_SETUP([OpenFlow 1.0 action translation])
-AT_KEYWORDS([OF1.0])
+AT_KEYWORDS([ofp-actions OF1.0])
 AT_DATA([test-data], [dnl
 # actions=LOCAL
 0000 0008 fffe 04d2
@@ -69,6 +69,12 @@ ffff 0018 00002320 0009 000000000000 c426384d49c53d60
 # actions=set_tunnel64:0x885f3298
 ffff 0018 00002320 0009 000000000000 00000000885f3298
 
+# actions=write_metadata:0xfedcba9876543210
+ffff 0020 00002320 0016 000000000000 fedcba9876543210 ffffffffffffffff
+
+# actions=write_metadata:0xfedcba9876543210/0xffff0000ffff0000
+ffff 0020 00002320 0016 000000000000 fedcba9876543210 ffff0000ffff0000
+
 # actions=multipath(eth_src,50,modulo_n,1,0,NXM_NX_REG0[])
 ffff 0020 00002320 000a 0000 0032 0000 0000 0000 0000 0000 0000 001f 00010004
 
@@ -125,7 +131,7 @@ AT_CHECK(
 AT_CLEANUP
 
 AT_SETUP([OpenFlow 1.1 action translation])
-AT_KEYWORDS([OF1.1])
+AT_KEYWORDS([ofp-actions OF1.1])
 AT_DATA([test-data], [dnl
 # actions=LOCAL
 0000 0010 fffffffe 04d2 000000000000
@@ -160,6 +166,15 @@ AT_DATA([test-data], [dnl
 # actions=mod_tp_dst:443
 000a 0008 01bb 0000
 
+# actions=strip_vlan
+0012 0008 00000000
+
+dnl 802.1ad isn't supported at the moment
+dnl # actions=push_vlan:0x88a8
+dnl 0011 0008 88a8 0000
+# actions=push_vlan:0x8100
+0011 0008 8100 0000
+
 # actions=resubmit:5
 ffff 0010 00002320 0001 0005 00000000
 
@@ -187,6 +202,53 @@ ffff 0018 00002320 0009 000000000000 c426384d49c53d60
 # actions=set_tunnel64:0x885f3298
 ffff 0018 00002320 0009 000000000000 00000000885f3298
 
+dnl OpenFlow 1.1 uses OFPIT_WRITE_METADATA to express the NXAST_WRITE_METADATA
+dnl action instead, so parse-ofp11-actions will recognise and drop this action.
+# actions=write_metadata:0xfedcba9876543210
+#  0: ff -> (none)
+#  1: ff -> (none)
+#  2: 00 -> (none)
+#  3: 20 -> (none)
+#  4: 00 -> (none)
+#  5: 00 -> (none)
+#  6: 23 -> (none)
+#  7: 20 -> (none)
+#  8: 00 -> (none)
+#  9: 16 -> (none)
+# 10: 00 -> (none)
+# 11: 00 -> (none)
+# 12: 00 -> (none)
+# 13: 00 -> (none)
+# 14: 00 -> (none)
+# 15: 00 -> (none)
+# 16: fe -> (none)
+# 17: dc -> (none)
+# 18: ba -> (none)
+# 19: 98 -> (none)
+# 20: 76 -> (none)
+# 21: 54 -> (none)
+# 22: 32 -> (none)
+# 23: 10 -> (none)
+# 24: ff -> (none)
+# 25: ff -> (none)
+# 26: ff -> (none)
+# 27: ff -> (none)
+# 28: ff -> (none)
+# 29: ff -> (none)
+# 30: ff -> (none)
+# 31: ff -> (none)
+ffff 0020 00002320 0016 000000000000 fedcba9876543210 ffffffffffffffff
+
+dnl Write-Metadata duplicated.
+& ofp_actions|WARN|duplicate write_metadata instruction specified
+# bad OF1.1 actions: OFPBAC_UNSUPPORTED_ORDER
+ffff 0020 00002320 0016 000000000000 fedcba9876543210 ffffffffffffffff ffff 0020 00002320 0016 000000000000 fedcba9876543210 ffffffffffffffff
+
+dnl Write-Metadata in wrong position.
+& ofp_actions|WARN|write_metadata instruction must be specified after other instructions/actions
+# bad OF1.1 actions: OFPBAC_UNSUPPORTED_ORDER
+ffff 0020 00002320 0016 000000000000 fedcba9876543210 ffffffffffffffff ffff 0010 00002320 0002 0000 12345678
+
 # actions=multipath(eth_src,50,modulo_n,1,0,NXM_NX_REG0[])
 ffff 0020 00002320 000a 0000 0032 0000 0000 0000 0000 0000 0000 001f 00010004
 
@@ -218,9 +280,14 @@ ffff 0048 00002320 0010 000a 0014 0050 123456789abcdef0 0000 02 00 0002 0004 dnl
 # actions=exit
 ffff 0010 00002320 0011 000000000000
 
+dnl NXAST_DEC_TTL
 # actions=dec_ttl
 ffff 0010 00002320 0012 000000000000
 
+dnl OpenFlow 1.1 OFPAT_DEC_TTL
+# actions=dec_ttl
+0018 0008 00000000
+
 # actions=fin_timeout(idle_timeout=10,hard_timeout=20)
 ffff 0010 00002320 0013 000a 0014 0000
 
@@ -243,12 +310,24 @@ AT_CHECK(
 AT_CLEANUP
 
 AT_SETUP([OpenFlow 1.1 instruction translation])
-AT_KEYWORDS([OF1.1])
+AT_KEYWORDS([OF1.1 instruction ofp-actions])
 AT_DATA([test-data], [dnl
 # actions=LOCAL
 0004 0018 00000000 dnl
 0000 0010 fffffffe 04d2 000000000000
 
+dnl Apply-Actions non-zero padding
+# actions=drop
+#  0: 00 -> (none)
+#  1: 04 -> (none)
+#  2: 00 -> (none)
+#  3: 08 -> (none)
+#  4: 00 -> (none)
+#  5: 00 -> (none)
+#  6: 00 -> (none)
+#  7: 01 -> (none)
+0004 0008 00000001
+
 dnl Check that an empty Apply-Actions instruction gets dropped.
 # actions=drop
 #  0: 00 -> (none)
@@ -274,14 +353,23 @@ dnl Goto-Table instruction too long.
 # bad OF1.1 instructions: OFPBIC_BAD_LEN
 0001 0010 01 000000 0000000000000000
 
-dnl Goto-Table not supported yet.
-# bad OF1.1 instructions: OFPBIC_UNSUP_INST
+dnl Goto-Table 1 instruction non-zero padding
+# actions=goto_table:1
+#  7: 01 -> 00
+0001 0008 01 000001
+
+dnl Goto-Table 1
+# actions=goto_table:1
 0001 0008 01 000000
 
-dnl Write-Metadata not supported yet.
-# bad OF1.1 instructions: OFPBIC_UNSUP_INST
+dnl Write-Metadata.
+# actions=write_metadata:0xfedcba9876543210
 0002 0018 00000000 fedcba9876543210 ffffffffffffffff
 
+dnl Write-Metadata with mask.
+# actions=write_metadata:0xfedcba9876543210/0xff00ff00ff00ff00
+0002 0018 00000000 fedcba9876543210 ff00ff00ff00ff00
+
 dnl Write-Metadata too short.
 # bad OF1.1 instructions: OFPBIC_BAD_LEN
 0002 0010 00000000 fedcba9876543210
@@ -290,14 +378,37 @@ dnl Write-Metadata too long.
 # bad OF1.1 instructions: OFPBIC_BAD_LEN
 0002 0020 00000000 fedcba9876543210 ffffffffffffffff 0000000000000000
 
+dnl Write-Metadata duplicated.
+# bad OF1.1 instructions: OFPIT_BAD_INSTRUCTION
+0002 0018 00000000 fedcba9876543210 ff00ff00ff00ff00 0002 0018 00000000 fedcba9876543210 ff00ff00ff00ff00
+
+dnl Write-Metadata in wrong position.
+& ofp_actions|WARN|write_metadata instruction must be specified after other instructions/actions
+# bad OF1.1 instructions: OFPBAC_UNSUPPORTED_ORDER
+0001 0008 01 000000 0002 0018 00000000 fedcba9876543210 ffffffffffffffff
+
 dnl Write-Actions not supported yet.
 # bad OF1.1 instructions: OFPBIC_UNSUP_INST
 0003 0008 01 000000
 
-dnl Clear-Actions not supported yet.
-# bad OF1.1 instructions: OFPBIC_UNSUP_INST
+dnl Clear-Actions too-long
+# bad OF1.1 instructions: OFPBIC_BAD_LEN
+0005 0010 00000000 0000000000000000
+
+dnl Clear-Actions non-zero padding
+# actions=clear_actions
+#  7: 01 -> 00
+0005 0008 00000001
+
+dnl Clear-Actions non-zero padding
+# actions=clear_actions
+#  4: 01 -> 00
 0005 0008 01 000000
 
+dnl Clear-Actions
+# actions=clear_actions
+0005 0008 00000000
+
 dnl Experimenter actions not supported yet.
 # bad OF1.1 instructions: OFPBIC_BAD_EXPERIMENTER
 ffff 0008 01 000000
index 42b355b..6133fff 100644 (file)
@@ -337,7 +337,7 @@ c0 a8 00 02 27 2f 00 00 78 50 cc 5b 57 af 42 1e \
 50 00 02 00 26 e8 00 00 00 00 00 00 00 00 \
 "], [0], [dnl
 OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=3 (via no_match) data_len=60 buffer=0x00000111
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(50:54:00:00:00:05->50:54:00:00:00:06) type:0800 proto:6 tos:0 ttl:64 ip(192.168.0.1->192.168.0.2) port(10031->0) tcp_csum:26e8
+priority=0,tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=10031,tp_dst=0 tcp_csum:26e8
 ])
 AT_CLEANUP
 
@@ -351,7 +351,7 @@ AT_CHECK([ovs-ofctl ofp-print "\
 00 00 00 23 20 83 c1 5f 00 00 00 00 \
 "], [0], [dnl
 OFPT_PACKET_IN (OF1.2) (xid=0x0): total_len=42 in_port=LOCAL (via no_match) data_len=42 buffer=0xffffff00
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(00:23:20:83:c1:5f->ff:ff:ff:ff:ff:ff) type:8035
+priority=0,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,dl_type=0x8035
 ])
 AT_CLEANUP
 
@@ -365,7 +365,7 @@ AT_CHECK([ovs-ofctl ofp-print "\
 30 e0 35 00 00 05 00 00 00 00 00 00 00 00 00 01 \
 00 00 00 00 00 00 00 3c \
 "], [0], [dnl
-OFPT_FLOW_REMOVED (xid=0x0): priority=65535,arp,in_port=3,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,nw_src=192.168.0.1,nw_dst=192.168.0.2,arp_op=2,nw_tos=0,tp_src=0,tp_dst=0 reason=idle duration5.82s idle5 pkts1 bytes60
+OFPT_FLOW_REMOVED (xid=0x0): priority=65535,arp,in_port=3,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,arp_spa=192.168.0.1,arp_tpa=192.168.0.2,arp_op=2,nw_tos=0,tp_src=0,tp_dst=0 reason=idle duration5.82s idle5 pkts1 bytes60
 ])
 AT_CLEANUP
 
@@ -376,7 +376,7 @@ AT_CHECK([ovs-ofctl ofp-print "\
 80 00 01 05 00 00 00 01 00 98 96 80 00 3c 00 78 \
 00 00 00 00 00 12 d6 87 00 00 00 00 6f 68 ba 66 \
 00 01 00 0a 80 00 0c 02 10 09 00 00 00 00 00 00"], [0], [dnl
-OFPT_FLOW_REMOVED (OF1.2) (xid=0x0): dl_vlan=9 reason=hard cookie:0xfedcba9876543210 duration1.01s idle60 hard120 pkts1234567 bytes1869134438
+OFPT_FLOW_REMOVED (OF1.2) (xid=0x0): dl_vlan=9 reason=hard table_id=5 cookie:0xfedcba9876543210 duration1.01s idle60 hard120 pkts1234567 bytes1869134438
 ])
 AT_CLEANUP
 
@@ -452,11 +452,11 @@ AT_CHECK([ovs-ofctl '-vPATTERN:console:%c|%p|%m' ofp-print "\
 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 00 \
 00 00 01 0e 00 00 00 00 00 00 00 08 00 03 00 00 \
 " 2], [0], [dnl
-OFPT_FLOW_MOD (xid=0x0): ADD priority=65535,arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,arp_op=2 idle:5 buf:0x10e out_port:0 actions=output:3
+OFPT_FLOW_MOD (xid=0x0): ADD priority=65535,arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,arp_spa=192.168.0.2,arp_tpa=192.168.0.1,arp_op=2 idle:5 buf:0x10e out_port:0 actions=output:3
 ], [dnl
 ofp_util|INFO|normalization changed ofp_match, details:
-ofp_util|INFO| pre: arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,arp_op=2,nw_tos=0,tp_src=0,tp_dst=0
-ofp_util|INFO|post: arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,arp_op=2
+ofp_util|INFO| pre: arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,arp_spa=192.168.0.2,arp_tpa=192.168.0.1,arp_op=2,nw_tos=0,tp_src=0,tp_dst=0
+ofp_util|INFO|post: arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,arp_spa=192.168.0.2,arp_tpa=192.168.0.1,arp_op=2
 ])
 AT_CLEANUP
 
@@ -474,7 +474,7 @@ ff ff ff ff ff ff ff ff ff ff ff ff 00 00 00 00 \
 00 01 00 00 00 00 00 00 00 04 00 18 00 00 00 00 \
 00 00 00 10 00 00 00 03 00 00 00 00 00 00 00 00 \
 " 2], [0], [dnl
-OFPT_FLOW_MOD (OF1.2) (xid=0x2): ADD table:255 priority=65535,arp,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,arp_op=2 actions=output:3
+OFPT_FLOW_MOD (OF1.2) (xid=0x2): ADD table:255 priority=65535,arp,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,arp_spa=192.168.0.2,arp_tpa=192.168.0.1,arp_op=2 actions=output:3
 ], [dnl
 ])
 AT_CLEANUP
@@ -493,8 +493,8 @@ AT_CHECK([ovs-ofctl '-vPATTERN:console:%c|%p|%m' ofp-print "\
 OFPT_FLOW_MOD (xid=0x0): ADD arp,in_port=1,dl_vlan=65535,dl_vlan_pcp=0,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,arp_op=2,nw_tos=0,tp_src=0,tp_dst=0 idle:5 pri:65535 buf:0x10e out_port:0 actions=output:3
 ], [dnl
 ofp_util|INFO|normalization changed ofp_match, details:
-ofp_util|INFO| pre: arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,arp_op=2,nw_tos=0,tp_src=0,tp_dst=0
-ofp_util|INFO|post: arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,arp_op=2
+ofp_util|INFO| pre: arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,arp_spa=192.168.0.2,arp_tpa=192.168.0.1,arp_op=2,nw_tos=0,tp_src=0,tp_dst=0
+ofp_util|INFO|post: arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,arp_spa=192.168.0.2,arp_tpa=192.168.0.1,arp_op=2
 ])
 AT_CLEANUP
 
@@ -512,7 +512,71 @@ ff ff ff ff ff ff ff ff ff ff ff ff 00 00 00 00 \
 00 01 00 00 00 00 00 00 00 04 00 18 00 00 00 00 \
 00 00 00 10 00 00 00 03 00 00 00 00 00 00 00 00 \
 " 2], [0], [dnl
-OFPT_FLOW_MOD (OF1.2) (xid=0x2): ADD table:255 priority=65535,arp,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,arp_op=2 actions=output:3
+OFPT_FLOW_MOD (OF1.2) (xid=0x2): ADD table:255 priority=65535,arp,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,arp_spa=192.168.0.2,arp_tpa=192.168.0.1,arp_op=2 actions=output:3
+], [dnl
+])
+AT_CLEANUP
+
+AT_SETUP([OFPT_FLOW_MOD - OF1.2 - set-field ip_src])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl '-vPATTERN:console:%c|%p|%m' ofp-print "\
+03 0e 00 58 52 33 45 02 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff \
+ff ff ff ff ff ff ff ff ff ff ff ff 00 00 00 00 \
+00 01 00 0a 80 00 0a 02 08 00 00 00 00 00 00 00 \
+00 04 00 18 00 00 00 00 00 19 00 10 80 00 16 04 \
+c0 a8 03 5c 00 00 00 00                         \
+" 2], [0], [dnl
+OFPT_FLOW_MOD (OF1.2) (xid=0x52334502): ADD priority=255,ip actions=set_field:192.168.3.92->ip_src
+], [dnl
+])
+AT_CLEANUP
+
+AT_SETUP([OFPT_FLOW_MOD - OF1.2 - set-field ip_dst])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl '-vPATTERN:console:%c|%p|%m' ofp-print "\
+03 0e 00 58 52 33 45 07 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff \
+ff ff ff ff ff ff ff ff ff ff ff ff 00 00 00 00 \
+00 01 00 0a 80 00 0a 02 08 00 00 00 00 00 00 00 \
+00 04 00 18 00 00 00 00 00 19 00 10 80 00 18 04 \
+c0 a8 4a 7a 00 00 00 00                         \
+" 2], [0], [dnl
+OFPT_FLOW_MOD (OF1.2) (xid=0x52334507): ADD priority=255,ip actions=set_field:192.168.74.122->ip_dst
+], [dnl
+])
+AT_CLEANUP
+
+AT_SETUP([OFPT_FLOW reply - OF1.2 - set-field ip_src])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl '-vPATTERN:console:%c|%p|%m' ofp-print "\
+03 13 00 68 52 33 45 04 00 01 00 00 00 00 00 00 \
+00 58 00 00 00 00 00 00 00 00 00 00 00 ff 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 01 00 0a 80 00 0a 02 08 00 00 00 00 00 00 00 \
+00 04 00 18 00 00 00 00 00 19 00 10 80 00 16 04 \
+c0 a8 03 5c 00 00 00 00                         \
+" 2], [0], [dnl
+OFPST_FLOW reply (OF1.2) (xid=0x52334504):
+ cookie=0x0, duration=0s, table=0, n_packets=0, n_bytes=0, priority=255,ip actions=set_field:192.168.3.92->ip_src
+], [dnl
+])
+AT_CLEANUP
+
+AT_SETUP([OFPT_FLOW reply - OF1.2 - set-field ip_dst])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl '-vPATTERN:console:%c|%p|%m' ofp-print "\
+03 13 00 68 52 33 45 09 00 01 00 00 00 00 00 00 \
+00 58 00 00 00 00 00 00 00 00 00 00 00 ff 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 01 00 0a 80 00 0a 02 08 00 00 00 00 00 00 00 \
+00 04 00 18 00 00 00 00 00 19 00 10 80 00 18 04 \
+c0 a8 4a 7a 00 00 00 00                         \
+" 2], [0], [dnl
+OFPST_FLOW reply (OF1.2) (xid=0x52334509):
+ cookie=0x0, duration=0s, table=0, n_packets=0, n_bytes=0, priority=255,ip actions=set_field:192.168.74.122->ip_dst
 ], [dnl
 ])
 AT_CLEANUP
@@ -705,9 +769,9 @@ c0 a8 00 02 00 08 00 00 00 00 00 09 05 b8 d8 00 \
 00 00 00 00 00 00 00 00 \
 "], [0], [dnl
 OFPST_FLOW reply (xid=0x4):
- cookie=0x0, duration=4.2s, table=0, n_packets=1, n_bytes=60, idle_timeout=5, priority=65535,arp,in_port=3,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,nw_src=192.168.0.1,nw_dst=192.168.0.2,arp_op=2,nw_tos=0,tp_src=0,tp_dst=0 actions=output:1
+ cookie=0x0, duration=4.2s, table=0, n_packets=1, n_bytes=60, idle_timeout=5, priority=65535,arp,in_port=3,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,arp_spa=192.168.0.1,arp_tpa=192.168.0.2,arp_op=2,nw_tos=0,tp_src=0,tp_dst=0 actions=output:1
  cookie=0x0, duration=8.9s, table=0, n_packets=13, n_bytes=1274, idle_timeout=5, priority=65535,icmp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,nw_tos=0,icmp_type=0,icmp_code=0 actions=output:3
- cookie=0x0, duration=4.28s, table=0, n_packets=1, n_bytes=60, idle_timeout=5, priority=65535,arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,arp_op=1,nw_tos=0,icmp_type=0,icmp_code=0 actions=output:3
+ cookie=0x0, duration=4.28s, table=0, n_packets=1, n_bytes=60, idle_timeout=5, priority=65535,arp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,arp_spa=192.168.0.2,arp_tpa=192.168.0.1,arp_op=1,nw_tos=0,tp_src=0,tp_dst=0 actions=output:3
  cookie=0x0, duration=9.096s, table=0, n_packets=13, n_bytes=1274, idle_timeout=5, icmp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,icmp_type=8,icmp_code=0 actions=output:1
  cookie=0x0, duration=0s, table=2, n_packets=0, n_bytes=0, actions=drop
 ])
@@ -885,7 +949,7 @@ AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
 AT_CHECK([ovs-ofctl ofp-print "$(cat in)"], [0], [expout])
 AT_CLEANUP
 
-AT_SETUP([OFPST_PORT request])
+AT_SETUP([OFPST_PORT request - 1.0])
 AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
 AT_CHECK([ovs-ofctl ofp-print "\
 01 10 00 14 00 00 00 01 00 04 00 00 ff ff 00 00 \
@@ -895,7 +959,27 @@ OFPST_PORT request (xid=0x1): port_no=65535
 ])
 AT_CLEANUP
 
-AT_SETUP([OFPST_PORT reply])
+AT_SETUP([OFPST_PORT request - 1.1])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "\
+02 12 00 18 00 00 00 02 00 04 00 00 00 00 00 00 \
+ff ff ff ff 00 00 00 00 \
+"], [0], [dnl
+OFPST_PORT request (OF1.1) (xid=0x2): port_no=65535
+])
+AT_CLEANUP
+
+AT_SETUP([OFPST_PORT request - 1.2])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "\
+03 12 00 18 00 00 00 02 00 04 00 00 00 00 00 00 \
+ff ff ff ff 00 00 00 00 \
+"], [0], [dnl
+OFPST_PORT request (OF1.2) (xid=0x2): port_no=65535
+])
+AT_CLEANUP
+
+AT_SETUP([OFPST_PORT reply - OF1.0])
 AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
 AT_CHECK([ovs-ofctl ofp-print "\
 01 11 01 ac 00 00 00 01 00 04 00 00 00 03 00 00 \
@@ -938,7 +1022,42 @@ OFPST_PORT reply (xid=0x1): 4 ports
 ])
 AT_CLEANUP
 
-AT_SETUP([OFPST_QUEUE request])
+AT_SETUP([OFPST_PORT reply - OF1.2])
+AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
+AT_CHECK([ovs-ofctl ofp-print "\
+03 13 01 48 00 00 00 02 00 04 00 00 00 00 00 00 \
+00 00 00 02 00 00 00 00 00 00 00 00 00 01 95 56 \
+00 00 00 00 00 00 00 88 00 00 00 00 02 5d 08 98 \
+00 00 00 00 00 00 2c f8 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 ff ff ff fe 00 00 00 00 \
+00 00 00 00 00 00 00 44 00 00 00 00 00 00 9d 2c \
+00 00 00 00 00 00 16 7c 00 00 00 00 01 1e 36 44 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 44 \
+00 00 00 00 00 00 9d 2c 00 00 00 00 00 00 16 7c \
+00 00 00 00 01 1e 36 44 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 \
+"], [0], [dnl
+OFPST_PORT reply (OF1.2) (xid=0x2): 3 ports
+  port  2: rx pkts=103766, bytes=39651480, drop=0, errs=0, frame=0, over=0, crc=0
+           tx pkts=136, bytes=11512, drop=0, errs=0, coll=0
+  port 65534: rx pkts=68, bytes=5756, drop=0, errs=0, frame=0, over=0, crc=0
+           tx pkts=40236, bytes=18757188, drop=0, errs=0, coll=0
+  port  1: rx pkts=68, bytes=5756, drop=0, errs=0, frame=0, over=0, crc=0
+           tx pkts=40236, bytes=18757188, drop=0, errs=0, coll=0
+])
+AT_CLEANUP
+
+AT_SETUP([OFPST_QUEUE request - OF1.0])
 AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
 AT_CHECK([ovs-ofctl ofp-print "\
 01 10 00 14 00 00 00 01 00 05 00 00 ff fc 00 00 \
@@ -948,7 +1067,27 @@ OFPST_QUEUE request (xid=0x1):port=ALL queue=ALL
 ])
 AT_CLEANUP
 
-AT_SETUP([OFPST_QUEUE reply])
+AT_SETUP([OFPST_QUEUE request - OF1.1])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "\
+02 12 00 18 00 00 00 02 00 05 00 00 00 00 00 00 \
+ff ff ff fc ff ff ff ff \
+"], [0], [dnl
+OFPST_QUEUE request (OF1.1) (xid=0x2):port=ALL queue=ALL
+])
+AT_CLEANUP
+
+AT_SETUP([OFPST_QUEUE request - OF1.2])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "\
+03 12 00 18 00 00 00 02 00 05 00 00 00 00 00 00 \
+ff ff ff fc ff ff ff ff \
+"], [0], [dnl
+OFPST_QUEUE request (OF1.2) (xid=0x2):port=ALL queue=ALL
+])
+AT_CLEANUP
+
+AT_SETUP([OFPST_QUEUE reply - OF1.0])
 AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
 AT_CHECK([ovs-ofctl ofp-print "\
 01 11 00 cc 00 00 00 01 00 05 00 00 00 03 00 00 \
@@ -982,6 +1121,60 @@ OFPST_PORT_DESC request (xid=0x1):
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPST_QUEUE reply - OF1.1])
+AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
+AT_CHECK([ovs-ofctl ofp-print "\
+02 13 00 d0 00 00 00 01 00 05 00 00 00 00 00 00 \
+00 00 00 03 00 00 00 01 00 00 00 00 00 00 01 2e \
+00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 \
+00 00 00 03 00 00 00 02 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 02 00 00 00 01 00 00 00 00 00 00 08 34 \
+00 00 00 00 00 00 00 14 00 00 00 00 00 00 00 00 \
+00 00 00 02 00 00 00 02 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 01 00 00 00 02 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+"], [0], [dnl
+OFPST_QUEUE reply (OF1.1) (xid=0x1): 6 queues
+  port 3 queue 1: bytes=302, pkts=1, errors=0
+  port 3 queue 2: bytes=0, pkts=0, errors=0
+  port 2 queue 1: bytes=2100, pkts=20, errors=0
+  port 2 queue 2: bytes=0, pkts=0, errors=0
+  port 1 queue 1: bytes=0, pkts=0, errors=0
+  port 1 queue 2: bytes=0, pkts=0, errors=0
+])
+AT_CLEANUP
+
+AT_SETUP([OFPST_QUEUE reply - OF1.2])
+AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
+AT_CHECK([ovs-ofctl ofp-print "\
+03 13 00 d0 00 00 00 01 00 05 00 00 00 00 00 00 \
+00 00 00 03 00 00 00 01 00 00 00 00 00 00 01 2e \
+00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 \
+00 00 00 03 00 00 00 02 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 02 00 00 00 01 00 00 00 00 00 00 08 34 \
+00 00 00 00 00 00 00 14 00 00 00 00 00 00 00 00 \
+00 00 00 02 00 00 00 02 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 01 00 00 00 02 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+"], [0], [dnl
+OFPST_QUEUE reply (OF1.2) (xid=0x1): 6 queues
+  port 3 queue 1: bytes=302, pkts=1, errors=0
+  port 3 queue 2: bytes=0, pkts=0, errors=0
+  port 2 queue 1: bytes=2100, pkts=20, errors=0
+  port 2 queue 2: bytes=0, pkts=0, errors=0
+  port 1 queue 1: bytes=0, pkts=0, errors=0
+  port 1 queue 2: bytes=0, pkts=0, errors=0
+])
+AT_CLEANUP
+
 AT_SETUP([OFPST_PORT_DESC reply - OF1.0])
 AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
 AT_CHECK([ovs-ofctl ofp-print "\
@@ -1090,7 +1283,7 @@ ff ff ff ff ff ff 00 00 00 00 82 82 82 82 82 82 \
 31 6d 00 00 00 00 00 00 00 00 \
 "], [0], [dnl
 NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 metadata=0x5a5a5a5a5a5a5a5a reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(85->86) tcp_csum:316d
+priority=0,tcp,metadata=0,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 tcp_csum:316d
 ])
 AT_CLEANUP
 
@@ -1205,7 +1398,7 @@ AT_CHECK([ovs-ofctl ofp-print "\
 1e 02 00 02 00 00 20 04 c0 a8 00 01 00 00 22 04 \
 c0 a8 00 02 00 00 00 00 \
 "], [0], [dnl
-NXT_FLOW_REMOVED (xid=0x0): priority=65535,arp,in_port=3,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,nw_src=192.168.0.1,nw_dst=192.168.0.2,arp_op=2 reason=idle duration6.024s idle5 pkts1 bytes60
+NXT_FLOW_REMOVED (xid=0x0): priority=65535,arp,in_port=3,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,arp_spa=192.168.0.1,arp_tpa=192.168.0.2,arp_op=2 reason=idle duration6.024s idle5 pkts1 bytes60
 ])
 AT_CLEANUP
 
index de56ef8..bc2362d 100644 (file)
@@ -98,7 +98,7 @@ AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(1),eth(src=50:54:00:00:00:05,dst
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 NXT_PACKET_IN (xid=0x0): table_id=1 total_len=42 in_port=1 (via invalid_ttl) data_len=42 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(50:54:00:00:00:05->50:54:00:00:00:07) type:0800 proto:1 tos:0 ttl:1 ip(192.168.0.1->192.168.0.2)
+priority=0,icmp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=1,icmp_type=0,icmp_code=0
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -263,13 +263,13 @@ done
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(50:54:00:00:00:05->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->9) tcp_csum:0
+priority=0,tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=9 tcp_csum:0
 dnl
 OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(50:54:00:00:00:05->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->9) tcp_csum:0
+priority=0,tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=9 tcp_csum:0
 dnl
 OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(50:54:00:00:00:05->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->9) tcp_csum:0
+priority=0,tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=9 tcp_csum:0
 ])
 
 dnl Singleton controller action.
@@ -282,13 +282,13 @@ done
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(10:11:11:11:11:11->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->10) tcp_csum:0
+priority=0,tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=10 tcp_csum:0
 dnl
 OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(10:11:11:11:11:11->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->10) tcp_csum:0
+priority=0,tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=10 tcp_csum:0
 dnl
 OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(10:11:11:11:11:11->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->10) tcp_csum:0
+priority=0,tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=10 tcp_csum:0
 ])
 
 dnl Modified controller action.
@@ -301,13 +301,13 @@ done
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:15,pcp:0) mac(30:33:33:33:33:33->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->10) tcp_csum:0
+priority=0,tcp,metadata=0,in_port=0,dl_vlan=15,dl_vlan_pcp=0,dl_src=30:33:33:33:33:33,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=10 tcp_csum:0
 dnl
 OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:15,pcp:0) mac(30:33:33:33:33:33->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->10) tcp_csum:0
+priority=0,tcp,metadata=0,in_port=0,dl_vlan=15,dl_vlan_pcp=0,dl_src=30:33:33:33:33:33,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=10 tcp_csum:0
 dnl
 OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:15,pcp:0) mac(30:33:33:33:33:33->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->10) tcp_csum:0
+priority=0,tcp,metadata=0,in_port=0,dl_vlan=15,dl_vlan_pcp=0,dl_src=30:33:33:33:33:33,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=10 tcp_csum:0
 ])
 
 dnl Checksum TCP.
@@ -320,31 +320,31 @@ done
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 NXT_PACKET_IN (xid=0x0): cookie=0x1 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(20:22:22:22:22:22->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) tcp_csum:0
+priority=0,tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 tcp_csum:0
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x3 total_len=64 in_port=1 reg0=0x1 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) mac(20:22:22:22:22:22->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) tcp_csum:0
+priority=0,tcp,metadata=0,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 tcp_csum:0
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x4 total_len=64 in_port=1 reg0=0x1 reg1=0x2 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->50:54:00:00:00:07) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) tcp_csum:0
+priority=0,tcp,metadata=0,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 tcp_csum:0
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=3 cookie=0x5 total_len=64 in_port=1 reg0=0x1 reg1=0x2 reg2=0x3 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) tcp_csum:0
+priority=0,tcp,metadata=0,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 tcp_csum:0
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=4 cookie=0x6 total_len=64 in_port=1 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 ip(83.83.83.83->192.168.0.2) port(8->11) tcp_csum:1a03
+priority=0,tcp,metadata=0,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 tcp_csum:1a03
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=5 cookie=0x7 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(8->11) tcp_csum:3205
+priority=0,tcp,metadata=0,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 tcp_csum:3205
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=6 cookie=0x8 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(85->11) tcp_csum:31b8
+priority=0,tcp,metadata=0,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=11 tcp_csum:31b8
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(85->86) tcp_csum:316d
+priority=0,tcp,metadata=0,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 tcp_csum:316d
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:6 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(85->86) tcp_csum:316d
+priority=0,tcp,metadata=0,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 tcp_csum:316d
 ])
 
 dnl Checksum UDP.
@@ -357,31 +357,31 @@ done
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 NXT_PACKET_IN (xid=0x0): cookie=0x1 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(20:22:22:22:22:22->50:54:00:00:00:07) type:0800 proto:17 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) udp_csum:1234
+priority=0,udp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:1234
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x3 total_len=64 in_port=1 reg0=0x1 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) mac(20:22:22:22:22:22->50:54:00:00:00:07) type:0800 proto:17 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) udp_csum:1234
+priority=0,udp,metadata=0,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:1234
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x4 total_len=64 in_port=1 reg0=0x1 reg1=0x2 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->50:54:00:00:00:07) type:0800 proto:17 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) udp_csum:1234
+priority=0,udp,metadata=0,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:1234
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=3 cookie=0x5 total_len=64 in_port=1 reg0=0x1 reg1=0x2 reg2=0x3 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 ip(192.168.0.1->192.168.0.2) port(8->11) udp_csum:1234
+priority=0,udp,metadata=0,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:1234
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=4 cookie=0x6 total_len=64 in_port=1 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 ip(83.83.83.83->192.168.0.2) port(8->11) udp_csum:2c37
+priority=0,udp,metadata=0,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:2c37
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=5 cookie=0x7 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(8->11) udp_csum:4439
+priority=0,udp,metadata=0,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:4439
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=6 cookie=0x8 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(85->11) udp_csum:43ec
+priority=0,udp,metadata=0,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=11 udp_csum:43ec
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(85->86) udp_csum:43a1
+priority=0,udp,metadata=0,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 udp_csum:43a1
 dnl
 NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(vlan:80,pcp:0) mac(80:81:81:81:81:81->82:82:82:82:82:82) type:0800 proto:17 tos:0 ttl:0 ip(83.83.83.83->84.84.84.84) port(85->86) udp_csum:43a1
+priority=0,udp,metadata=0,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 udp_csum:43a1
 ])
 
 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
index af7b7ca..cbf07bc 100644 (file)
@@ -148,6 +148,17 @@ AT_CHECK([ovs-ofctl -F openflow10 dump-flows br0 | ofctl_strip], [0], [OFPST_FLO
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([ofproto - set-field flow_mod commands (NXM)])
+OVS_VSWITCHD_START
+AT_CHECK([ovs-ofctl add-flow br0 ipv6,table=1,in_port=3,actions=drop])
+AT_CHECK([ovs-ofctl add-flow br0 ipv6,table=1,in_port=3,actions=set_field:fe80:0123:4567:890a:a6ba:dbff:fefe:59fa-\>ipv6_src])
+AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+ table=1, ipv6,in_port=3 actions=load:0xa6badbfffefe59fa->NXM_NX_IPV6_SRC[[0..63]],load:0xfe8001234567890a->NXM_NX_IPV6_SRC[[64..127]]
+NXST_FLOW reply:
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_SETUP([ofproto - dump flows with cookie])
 OVS_VSWITCHD_START
 AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=1])
@@ -351,6 +362,38 @@ NXST_FLOW reply:
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([ofproto - del flows based on table id])
+OVS_VSWITCHD_START
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=1])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=2,table=1,actions=1])
+AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+ cookie=0x1, in_port=1 actions=output:1
+ cookie=0x2, table=1, in_port=2 actions=output:1
+NXST_FLOW reply:
+])
+AT_CHECK([ovs-ofctl del-flows br0 table=0])
+AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+ cookie=0x2, table=1, in_port=2 actions=output:1
+NXST_FLOW reply:
+])
+AT_CHECK([ovs-ofctl del-flows br0 table=1])
+AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+NXST_FLOW reply:
+])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=1])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=2,table=1,actions=1])
+AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+ cookie=0x1, in_port=1 actions=output:1
+ cookie=0x2, table=1, in_port=2 actions=output:1
+NXST_FLOW reply:
+])
+AT_CHECK([ovs-ofctl del-flows br0])
+AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+NXST_FLOW reply:
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_SETUP([ofproto - flow table configuration])
 OVS_VSWITCHD_START
 # Check the default configuration.
@@ -413,12 +456,12 @@ NXST_FLOW reply:
 # Adding another flow will be refused.
 AT_CHECK([ovs-ofctl add-flow br0 in_port=5,actions=drop], [1], [], [stderr])
 AT_CHECK([head -n 1 stderr | ofctl_strip], [0],
-  [OFPT_ERROR: OFPFMFC_ALL_TABLES_FULL
+  [OFPT_ERROR: OFPFMFC_TABLE_FULL
 ])
 # Also a mod-flow that would add a flow will be refused.
 AT_CHECK([ovs-ofctl mod-flows br0 in_port=5,actions=drop], [1], [], [stderr])
 AT_CHECK([head -n 1 stderr | ofctl_strip], [0],
-  [OFPT_ERROR: OFPFMFC_ALL_TABLES_FULL
+  [OFPT_ERROR: OFPFMFC_TABLE_FULL
 ])
 # Replacing or modifying an existing flow is allowed.
 AT_CHECK([ovs-ofctl add-flow br0 in_port=4,actions=normal])
@@ -479,7 +522,7 @@ NXST_FLOW reply:
 AT_CHECK([ovs-ofctl add-flow br0 in_port=7,actions=normal])
 AT_CHECK([ovs-ofctl add-flow br0 in_port=8,actions=drop], [1], [], [stderr])
 AT_CHECK([head -n 1 stderr | ofctl_strip], [0],
-  [OFPT_ERROR: OFPFMFC_ALL_TABLES_FULL
+  [OFPT_ERROR: OFPFMFC_TABLE_FULL
 ])
 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
  in_port=4 actions=NORMAL
@@ -588,21 +631,21 @@ check_async () {
     ovs-ofctl -v packet-out br0 none controller '0001020304050010203040501234'
     if test X"$1" = X"OFPR_ACTION"; then shift;
         echo >>expout "OFPT_PACKET_IN: total_len=14 in_port=NONE (via action) data_len=14 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234"
+priority=0,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
     fi
 
     # OFPT_PACKET_IN, OFPR_NO_MATCH (controller_id=123)
     ovs-ofctl -v packet-out br0 none 'controller(reason=no_match,id=123)' '0001020304050010203040501234'
     if test X"$1" = X"OFPR_NO_MATCH"; then shift;
         echo >>expout "OFPT_PACKET_IN: total_len=14 in_port=NONE (via no_match) data_len=14 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234"
+priority=0,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
     fi
 
     # OFPT_PACKET_IN, OFPR_INVALID_TTL (controller_id=0)
     ovs-ofctl packet-out br0 none dec_ttl '002583dfb4000026b98cb0f908004500003fb7e200000011339bac11370dac100002d7730035002b8f6d86fb0100000100000000000006626c702d7873066e696369726103636f6d00000f00'
     if test X"$1" = X"OFPR_INVALID_TTL"; then shift;
         echo >>expout "OFPT_PACKET_IN: total_len=76 in_port=NONE (via invalid_ttl) data_len=76 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(00:26:b9:8c:b0:f9->00:25:83:df:b4:00) type:0800 proto:17 tos:0 ttl:0 ip(172.17.55.13->172.16.0.2) port(55155->53) udp_csum:8f6d"
+priority=0,udp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=00:26:b9:8c:b0:f9,dl_dst=00:25:83:df:b4:00,nw_src=172.17.55.13,nw_dst=172.16.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=55155,tp_dst=53 udp_csum:8f6d"
     fi
 
     # OFPT_PORT_STATUS, OFPPR_ADD
@@ -700,9 +743,9 @@ ovs-appctl -t ovs-ofctl exit
 
 AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
 OFPT_PACKET_IN: total_len=14 in_port=NONE (via action) data_len=14 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234
+priority=0,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
 OFPT_PACKET_IN: total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(00:10:20:30:40:50->00:01:02:03:04:05) type:5678
+priority=0,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x5678
 OFPT_BARRIER_REPLY:
 ])
 
@@ -730,7 +773,7 @@ ovs-appctl -t ovs-ofctl exit
 
 AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
 NXT_PACKET_IN: total_len=14 in_port=NONE metadata=0xfafafafa5a5a5a5a (via action) data_len=14 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234
+priority=0,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
 OFPT_BARRIER_REPLY:
 ])
 
index 947f985..1fa1a34 100644 (file)
@@ -10,6 +10,8 @@ tcp,nw_src=192.168.0.3,tp_dst=80 actions=set_queue:37,output:1
 udp,nw_src=192.168.0.3,tp_dst=53 actions=pop_queue,output:1
 cookie=0x123456789abcdef hard_timeout=10 priority=60000 actions=controller
 actions=note:41.42.43,note:00.01.02.03.04.05.06.07,note
+actions=set_field:fe80:0123:4567:890a:a6ba:dbff:fefe:59fa->ipv6_src
+in_port=0 actions=resubmit:0
 ]])
 
 AT_CHECK([ovs-ofctl parse-flows flows.txt
@@ -24,6 +26,8 @@ OFPT_FLOW_MOD: ADD tcp,nw_src=192.168.0.3,tp_dst=80 actions=set_queue:37,output:
 OFPT_FLOW_MOD: ADD udp,nw_src=192.168.0.3,tp_dst=53 actions=pop_queue,output:1
 OFPT_FLOW_MOD: ADD priority=60000 cookie:0x123456789abcdef hard:10 actions=CONTROLLER:65535
 OFPT_FLOW_MOD: ADD actions=note:41.42.43.00.00.00,note:00.01.02.03.04.05.06.07.00.00.00.00.00.00,note:00.00.00.00.00.00
+OFPT_FLOW_MOD: ADD actions=load:0xa6badbfffefe59fa->NXM_NX_IPV6_SRC[0..63],load:0xfe8001234567890a->NXM_NX_IPV6_SRC[64..127]
+OFPT_FLOW_MOD: ADD in_port=0 actions=resubmit:0
 ]])
 AT_CLEANUP
 
@@ -836,20 +840,20 @@ xxxxxxxx c0a88055 xxxx xxxx
 003220ef xxxx xxxxxxxxxxxx xxxxxxxxxxxx xxxx xx xx 0800 xx xx xxxx dnl
 xxxxxxxx c0a88055 xxxx xxxx
 
-# arp,nw_src=192.168.128.85
+# arp,arp_spa=192.168.128.85
 003800ef xxxx xxxxxxxxxxxx xxxxxxxxxxxx xxxx xx xx 0806 xx xx xxxx dnl
 c0a88055 xxxxxxxx xxxx xxxx
 
-# arp,nw_src=192.168.128.0/24
+# arp,arp_spa=192.168.128.0/24
 # 31: 55 -> 00
 003808ef xxxx xxxxxxxxxxxx xxxxxxxxxxxx xxxx xx xx 0806 xx xx xxxx dnl
 c0a88055 xxxxxxxx xxxx xxxx
 
-# arp,nw_dst=192.168.128.85
+# arp,arp_tpa=192.168.128.85
 003020ef xxxx xxxxxxxxxxxx xxxxxxxxxxxx xxxx xx xx 0806 xx xx xxxx dnl
 xxxxxxxx c0a88055 xxxx xxxx
 
-# arp,nw_dst=192.168.128.0/24
+# arp,arp_tpa=192.168.128.0/24
 # 35: 55 -> 00
 003220ef xxxx xxxxxxxxxxxx xxxxxxxxxxxx xxxx xx xx 0806 xx xx xxxx dnl
 xxxxxxxx c0a88055 xxxx xxxx
@@ -1105,13 +1109,13 @@ dnl Try invalid TOS:
 0000 00 00 0800 00 00 00000000ffffffff c0a880005a5a5a5a 0000 0000 dnl
 00000000 00 000000 0000000000000000ffffffffffffffff
 
-# arp,nw_src=192.168.128.0/24
+# arp,arp_spa=192.168.128.0/24
 0000 0058 00000000 000003f7 dnl
 000000000000ffffffffffff 000000000000ffffffffffff dnl
 0000 00 00 0806 00 00 c0a88000000000ff 00000000ffffffff 0000 0000 dnl
 00000000 00 000000 0000000000000000ffffffffffffffff
 
-# arp,nw_dst=192.168.128.0/24
+# arp,arp_tpa=192.168.128.0/24
 0000 0058 00000000 000003f7 dnl
 000000000000ffffffffffff 000000000000ffffffffffff dnl
 0000 00 00 0806 00 00 00000000ffffffff c0a88000000000ff 0000 0000 dnl
index 68fe868..ce22010 100644 (file)
@@ -48,9 +48,29 @@ m4_define([OVSDB_CHECK_IDL_PY],
    OVSDB_SERVER_SHUTDOWN
    AT_CLEANUP])
 
+# same as OVSDB_CHECK_IDL but uses the Python IDL implementation with tcp
+m4_define([OVSDB_CHECK_IDL_TCP_PY],
+  [AT_SETUP([$1 - Python tcp])
+   AT_SKIP_IF([test $HAVE_PYTHON = no])
+   AT_KEYWORDS([ovsdb server idl positive Python with tcp socket $5])
+   AT_CHECK([ovsdb-tool create db $abs_srcdir/idltest.ovsschema],
+                  [0], [stdout], [ignore])
+   AT_CHECK([perl $srcdir/choose-port.pl], [0], [stdout])
+   TCP_PORT=`cat stdout`
+   AT_CHECK([ovsdb-server '-vPATTERN:console:ovsdb-server|%c|%m' --detach --no-chdir --pidfile="`pwd`"/pid --remote=ptcp:$TCP_PORT:127.0.0.1 --unixctl="`pwd`"/unixctl db], [0], [ignore], [ignore])
+   m4_if([$2], [], [],
+     [AT_CHECK([ovsdb-client transact tcp:127.0.0.1:$TCP_PORT $2], [0], [ignore], [ignore], [kill `cat pid`])])
+   AT_CHECK([$PYTHON $srcdir/test-ovsdb.py  -t10 idl $srcdir/idltest.ovsschema tcp:127.0.0.1:$TCP_PORT $3],
+            [0], [stdout], [ignore], [kill `cat pid`])
+   AT_CHECK([sort stdout | perl $srcdir/uuidfilt.pl]m4_if([$6],,, [[| $6]]),
+            [0], [$4], [], [kill `cat pid`])
+   OVSDB_SERVER_SHUTDOWN
+   AT_CLEANUP])
+
 m4_define([OVSDB_CHECK_IDL],
   [OVSDB_CHECK_IDL_C($@)
-   OVSDB_CHECK_IDL_PY($@)])
+   OVSDB_CHECK_IDL_PY($@)
+   OVSDB_CHECK_IDL_TCP_PY($@)])
 
 OVSDB_CHECK_IDL([simple idl, initially empty, no ops],
   [],
@@ -439,3 +459,12 @@ OVSDB_CHECK_IDL_PY([external-linking idl, insert ops],
 002: i=2 k=1 ka=[1 2] l2= uuid=<1>
 003: done
 ]])
+
+OVSDB_CHECK_IDL_PY([getattr idl, insert ops],
+  [],
+  [['getattrtest']],
+  [[000: empty
+001: commit, status=success
+002: i=2 k=2 ka=[] l2= uuid=<0>
+003: done
+]])
index b0a3377..6dcf2f5 100644 (file)
@@ -142,12 +142,15 @@ AT_CLEANUP
 
 AT_SETUP([database multiplexing implementation])
 AT_KEYWORDS([ovsdb server positive])
-ordinal_schema > schema
-AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
-AT_CHECK([ovsdb-server --detach --no-chdir --pidfile="`pwd`"/pid --unixctl="`pwd`"/unixctl --remote=punix:socket db], [0], [ignore], [ignore])
+ordinal_schema > schema1
+constraint_schema > schema2
+AT_CHECK([ovsdb-tool create db1 schema1], [0], [ignore], [ignore])
+AT_CHECK([ovsdb-tool create db2 schema2], [0], [ignore], [ignore])
+AT_CHECK([ovsdb-server --detach --no-chdir --pidfile="`pwd`"/pid --unixctl="`pwd`"/unixctl --remote=punix:socket db1 db2], [0], [ignore], [ignore])
 AT_CHECK(
   [[ovsdb-client list-dbs unix:socket]], 
-  [0], [ordinals
+  [0], [constraints
+ordinals
 ], [ignore], [test ! -e pid || kill `cat pid`])
 AT_CHECK(
   [[test-jsonrpc request unix:socket get_schema [\"nonexistent\"]]], [0],
@@ -158,37 +161,67 @@ AT_CLEANUP
 
 AT_SETUP([--remote=db: implementation])
 AT_KEYWORDS([ovsdb server positive])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
+OVS_LOGDIR=`pwd`; export OVS_LOGDIR
 AT_DATA([schema],
   [[{"name": "mydb",
      "tables": {
+       "Root": {
+         "columns": {
+           "managers": {
+             "type": {
+               "key": "string",
+               "min": 0,
+               "max": "unlimited"}},
+           "manager_options": {
+             "type": {
+               "key": {"type": "uuid", "refTable": "Manager"},
+               "min": 0,
+               "max": "unlimited"}}}},
        "Manager": {
          "columns": {
-           "manager": {"type": "string"}}}}}
+           "target": {
+             "type": "string"},
+           "is_connected": {
+             "type": {
+               "key": "boolean",
+               "min": 0,
+               "max": 1}}}}}}
 ]])
 AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
 AT_CHECK(
   [[ovsdb-tool transact db \
      '["mydb",
+       {"op": "insert",
+        "table": "Root",
+        "row": {
+          "managers": "punix:socket1",
+          "manager_options": ["set", [["named-uuid", "x"]]]}},
        {"op": "insert",
         "table": "Manager",
-        "row": {"manager": "punix:socket"}}]']], [0], [ignore], [ignore])
-AT_CHECK([ovsdb-server --detach --no-chdir --pidfile="`pwd`"/pid --remote=db:Manager,manager --unixctl="`pwd`"/unixctl db], [0], [ignore], [ignore])
+        "uuid-name": "x",
+        "row": {"target": "punix:socket2"}}]']], [0], [ignore], [ignore])
+ON_EXIT([kill `cat ovsdb-server.pid`])
+AT_CHECK([ovsdb-server --enable-dummy --detach --no-chdir --pidfile --remote=db:Root,managers --remote=db:Root,manager_options --log-file db], [0], [ignore], [ignore])
+for i in 1 2 3 4 5 6; do ovs-appctl -t ovsdb-server time/warp 1000; done
 AT_CHECK(
-  [[ovsdb-client transact unix:socket \
+  [[ovsdb-client transact unix:socket1 \
      '["mydb",
+       {"op": "select",
+        "table": "Root",
+        "where": [],
+        "columns": ["managers"]},
        {"op": "select",
         "table": "Manager",
         "where": [],
-        "columns": ["manager"]}]']], 
-  [0], [stdout], [ignore], [test ! -e pid || kill `cat pid`])
+        "columns": ["target", "is_connected"]}]']],
+  [0], [stdout], [ignore])
 AT_CHECK(
   [perl $srcdir/uuidfilt.pl stdout], 
   [0], 
-  [[[{"rows":[{"manager":"punix:socket"}]}]
+  [[[{"rows":[{"managers":"punix:socket1"}]},{"rows":[{"is_connected":false,"target":"punix:socket2"}]}]
 ]], 
-  [ignore], 
-  [test ! -e pid || kill `cat pid`])
-OVSDB_SERVER_SHUTDOWN
+  [ignore])
 AT_CLEANUP
 
 AT_SETUP([SSL db: implementation])
@@ -413,6 +446,55 @@ cat stdout >> output
    OVSDB_SERVER_SHUTDOWN
    AT_CLEANUP])
 
+EXECUTION_EXAMPLES
+
+AT_BANNER([OVSDB -- ovsdb-server transactions (TCP sockets)])
+
+AT_SETUP([ovsdb-client get-schema-version - tcp socket])
+AT_KEYWORDS([ovsdb server positive tcp])
+ordinal_schema > schema
+AT_CHECK([perl $srcdir/choose-port.pl], [0], [stdout])
+TCP_PORT=`cat stdout`
+AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
+AT_CHECK([ovsdb-server --detach --no-chdir --pidfile="`pwd`"/pid --unixctl="`pwd`"/unixctl --remote=ptcp:$TCP_PORT:127.0.0.1 db], [0], [ignore], [ignore])
+AT_CHECK([ovsdb-client get-schema-version tcp:127.0.0.1:$TCP_PORT ordinals], [0], [5.1.3
+])
+OVSDB_SERVER_SHUTDOWN
+AT_CLEANUP])
+
+# OVSDB_CHECK_EXECUTION(TITLE, SCHEMA, TRANSACTIONS, OUTPUT, [KEYWORDS])
+#
+# Creates a database with the given SCHEMA, starts an ovsdb-server on
+# that database, and runs each of the TRANSACTIONS (which should be a
+# quoted list of quoted strings) against it with ovsdb-client one at a
+# time.
+#
+# Checks that the overall output is OUTPUT, but UUIDs in the output
+# are replaced by markers of the form <N> where N is a number.  The
+# first unique UUID is replaced by <0>, the next by <1>, and so on.
+# If a given UUID appears more than once it is always replaced by the
+# same marker.
+#
+# TITLE is provided to AT_SETUP and KEYWORDS to AT_KEYWORDS.
+m4_define([OVSDB_CHECK_EXECUTION],
+  [AT_SETUP([$1])
+   AT_KEYWORDS([ovsdb server positive tcp $5])
+   $2 > schema
+   AT_CHECK([perl $srcdir/choose-port.pl], [0], [stdout])
+   TCP_PORT=`cat stdout`
+   PKIDIR=$abs_top_builddir/tests
+   AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
+   AT_CHECK([ovsdb-server --detach --no-chdir --pidfile="`pwd`"/pid --remote=ptcp:$TCP_PORT:127.0.0.1 --unixctl="`pwd`"/unixctl db], [0], [ignore], [ignore])
+   m4_foreach([txn], [$3],
+     [AT_CHECK([ovsdb-client transact tcp:127.0.0.1:$TCP_PORT 'txn'], [0], [stdout], [ignore],
+     [test ! -e pid || kill `cat pid`])
+cat stdout >> output
+])
+   AT_CHECK([perl $srcdir/uuidfilt.pl output], [0], [$4], [ignore],
+            [test ! -e pid || kill `cat pid`])
+   OVSDB_SERVER_SHUTDOWN
+   AT_CLEANUP])
+
 EXECUTION_EXAMPLES
 \f
 AT_BANNER([OVSDB -- transactions on transient ovsdb-server])
index a7daa94..79ca29c 100644 (file)
 
 /* Fields in a rule. */
 #define CLS_FIELDS                                                  \
-    /*        struct flow  all-caps */  \
-    /*        member name  name     */  \
-    /*        -----------  -------- */  \
-    CLS_FIELD(tun_id,      TUN_ID)      \
-    CLS_FIELD(metadata,    METADATA)    \
-    CLS_FIELD(nw_src,      NW_SRC)      \
-    CLS_FIELD(nw_dst,      NW_DST)      \
-    CLS_FIELD(in_port,     IN_PORT)     \
-    CLS_FIELD(vlan_tci,    VLAN_TCI)    \
-    CLS_FIELD(dl_type,     DL_TYPE)     \
-    CLS_FIELD(tp_src,      TP_SRC)      \
-    CLS_FIELD(tp_dst,      TP_DST)      \
-    CLS_FIELD(dl_src,      DL_SRC)      \
-    CLS_FIELD(dl_dst,      DL_DST)      \
-    CLS_FIELD(nw_proto,    NW_PROTO)    \
-    CLS_FIELD(nw_tos,      NW_DSCP)
+    /*        struct flow    all-caps */  \
+    /*        member name    name     */  \
+    /*        -----------    -------- */  \
+    CLS_FIELD(tunnel.tun_id, TUN_ID)      \
+    CLS_FIELD(metadata,      METADATA)    \
+    CLS_FIELD(nw_src,        NW_SRC)      \
+    CLS_FIELD(nw_dst,        NW_DST)      \
+    CLS_FIELD(in_port,       IN_PORT)     \
+    CLS_FIELD(vlan_tci,      VLAN_TCI)    \
+    CLS_FIELD(dl_type,       DL_TYPE)     \
+    CLS_FIELD(tp_src,        TP_SRC)      \
+    CLS_FIELD(tp_dst,        TP_DST)      \
+    CLS_FIELD(dl_src,        DL_SRC)      \
+    CLS_FIELD(dl_dst,        DL_DST)      \
+    CLS_FIELD(nw_proto,      NW_PROTO)    \
+    CLS_FIELD(nw_tos,        NW_DSCP)
 
 /* Field indexes.
  *
@@ -214,8 +214,8 @@ match(const struct cls_rule *wild_, const struct flow *fixed)
             eq = !((fixed->vlan_tci ^ wild.flow.vlan_tci)
                    & wild.wc.masks.vlan_tci);
         } else if (f_idx == CLS_F_IDX_TUN_ID) {
-            eq = !((fixed->tun_id ^ wild.flow.tun_id)
-                   & wild.wc.masks.tun_id);
+            eq = !((fixed->tunnel.tun_id ^ wild.flow.tunnel.tun_id)
+                   & wild.wc.masks.tunnel.tun_id);
         } else if (f_idx == CLS_F_IDX_METADATA) {
             eq = !((fixed->metadata ^ wild.flow.metadata)
                    & wild.wc.masks.metadata);
@@ -397,7 +397,7 @@ compare_classifiers(struct classifier *cls, struct tcls *tcls)
         memset(&flow, 0, sizeof flow);
         flow.nw_src = nw_src_values[get_value(&x, N_NW_SRC_VALUES)];
         flow.nw_dst = nw_dst_values[get_value(&x, N_NW_DST_VALUES)];
-        flow.tun_id = tun_id_values[get_value(&x, N_TUN_ID_VALUES)];
+        flow.tunnel.tun_id = tun_id_values[get_value(&x, N_TUN_ID_VALUES)];
         flow.metadata = metadata_values[get_value(&x, N_METADATA_VALUES)];
         flow.in_port = in_port_values[get_value(&x, N_IN_PORT_VALUES)];
         flow.vlan_tci = vlan_tci_values[get_value(&x, N_VLAN_TCI_VALUES)];
@@ -512,7 +512,7 @@ make_rule(int wc_fields, unsigned int priority, int value_pat)
         } else if (f_idx == CLS_F_IDX_VLAN_TCI) {
             match.wc.masks.vlan_tci = htons(UINT16_MAX);
         } else if (f_idx == CLS_F_IDX_TUN_ID) {
-            match.wc.masks.tun_id = htonll(UINT64_MAX);
+            match.wc.masks.tunnel.tun_id = htonll(UINT64_MAX);
         } else if (f_idx == CLS_F_IDX_METADATA) {
             match.wc.masks.metadata = htonll(UINT64_MAX);
         } else if (f_idx == CLS_F_IDX_NW_DSCP) {
index a4d7c09..a40709a 100644 (file)
@@ -68,7 +68,7 @@ main(int argc OVS_UNUSED, char *argv[])
             ovs_fatal(retval, "error reading pcap file");
         }
 
-        flow_extract(packet, 0, 0, 1, &flow);
+        flow_extract(packet, 0, NULL, 1, &flow);
         match_init_exact(&match, &flow);
         ofputil_match_to_ofp10_match(&match, &extracted_match);
 
index a1ad2cb..d448109 100644 (file)
@@ -1294,6 +1294,7 @@ do_trigger(int argc OVS_UNUSED, char *argv[])
 {
     struct ovsdb_schema *schema;
     struct ovsdb_session session;
+    struct ovsdb_server server;
     struct json *json;
     struct ovsdb *db;
     long long int now;
@@ -1306,7 +1307,9 @@ do_trigger(int argc OVS_UNUSED, char *argv[])
     json_destroy(json);
     db = ovsdb_create(schema);
 
-    ovsdb_session_init(&session, db);
+    ovsdb_server_init(&server);
+    ovsdb_server_add_db(&server, db);
+    ovsdb_session_init(&session, &server);
 
     now = 0;
     number = 0;
@@ -1321,7 +1324,7 @@ do_trigger(int argc OVS_UNUSED, char *argv[])
             json_destroy(params);
         } else {
             struct test_trigger *t = xmalloc(sizeof *t);
-            ovsdb_trigger_init(&session, &t->trigger, params, now);
+            ovsdb_trigger_init(&session, db, &t->trigger, params, now);
             t->number = number++;
             if (ovsdb_trigger_is_complete(&t->trigger)) {
                 do_trigger_dump(t, now, "immediate");
@@ -1342,6 +1345,7 @@ do_trigger(int argc OVS_UNUSED, char *argv[])
         poll_block();
     }
 
+    ovsdb_server_destroy(&server);
     ovsdb_destroy(db);
 }
 
index 170476d..392ed4b 100644 (file)
@@ -321,6 +321,14 @@ def idl_set(idl, commands, step):
             l1_1.i = 2
             l1_1.k = [l1_0]
             l1_1.ka = [l1_0, l1_1]
+        elif name == 'getattrtest':
+            l1 = txn.insert(idl.tables["link1"])
+            i = getattr(l1, 'i', 1)
+            assert i == 1
+            l1.i = 2
+            i = getattr(l1, 'i', 1)
+            assert i == 2
+            l1.k = [l1]
         else:
             sys.stderr.write("unknown command %s\n" % name)
             sys.exit(1)
index 5dd38f0..0b2b063 100644 (file)
@@ -159,8 +159,15 @@ test_refuse_connection(int argc OVS_UNUSED, char *argv[])
             ovs_fatal(0, "unexpected vconn_connect() return value %d (%s)",
                       error, strerror(error));
         }
+    } else if (!strcmp(type, "unix")) {
+        CHECK_ERRNO(error, EPIPE);
+    } else if (!strcmp(type, "ssl")) {
+        if (error != EPROTO && error != ECONNRESET) {
+            ovs_fatal(0, "unexpected vconn_connect() return value %d (%s)",
+                      error, strerror(error));
+        }
     } else {
-        CHECK_ERRNO(error, !strcmp(type, "unix") ? EPIPE : EPROTO);
+        ovs_fatal(0, "invalid connection type %s", type);
     }
 
     vconn_close(vconn);
index 4f96a4f..ad99dda 100644 (file)
@@ -18,6 +18,7 @@
 /ovs-lib
 /ovs-ofctl
 /ovs-ofctl.8
+/ovs-parse-backtrace
 /ovs-parse-leaks
 /ovs-pcap
 /ovs-pcap.1
index fdd26b8..ab8774a 100644 (file)
@@ -8,6 +8,7 @@ bin_SCRIPTS += utilities/ovs-pki utilities/ovs-parse-leaks
 if HAVE_PYTHON
 bin_SCRIPTS += \
        utilities/ovs-l3ping \
+       utilities/ovs-parse-backtrace \
        utilities/ovs-pcap \
        utilities/ovs-tcpundump \
        utilities/ovs-test \
@@ -24,6 +25,7 @@ EXTRA_DIST += \
        utilities/ovs-ctl.in \
        utilities/ovs-l3ping.in \
        utilities/ovs-lib.in \
+       utilities/ovs-parse-backtrace.in \
        utilities/ovs-parse-leaks.in \
        utilities/ovs-pcap.in \
        utilities/ovs-pki.in \
@@ -39,6 +41,7 @@ MAN_ROOTS += \
        utilities/ovs-dpctl.8.in \
        utilities/ovs-l3ping.8.in \
        utilities/ovs-ofctl.8.in \
+       utilities/ovs-parse-backtrace.8 \
        utilities/ovs-parse-leaks.8 \
        utilities/ovs-pcap.1.in \
        utilities/ovs-pki.8.in \
@@ -59,6 +62,7 @@ DISTCLEANFILES += \
        utilities/ovs-l3ping.8 \
        utilities/ovs-lib \
        utilities/ovs-ofctl.8 \
+       utilities/ovs-parse-backtrace \
        utilities/ovs-parse-leaks \
        utilities/ovs-pcap \
        utilities/ovs-pcap.1 \
@@ -80,6 +84,7 @@ man_MANS += \
        utilities/ovs-dpctl.8 \
        utilities/ovs-l3ping.8 \
        utilities/ovs-ofctl.8 \
+       utilities/ovs-parse-backtrace.8 \
        utilities/ovs-parse-leaks.8 \
        utilities/ovs-pcap.1 \
        utilities/ovs-pki.8 \
@@ -108,7 +113,7 @@ utilities_ovs_ofctl_LDADD = \
 utilities_ovs_vsctl_SOURCES = utilities/ovs-vsctl.c
 utilities_ovs_vsctl_LDADD = lib/libopenvswitch.a $(SSL_LIBS)
 
-if HAVE_NETLINK
+if LINUX_DATAPATH
 sbin_PROGRAMS += utilities/ovs-vlan-bug-workaround
 utilities_ovs_vlan_bug_workaround_SOURCES = utilities/ovs-vlan-bug-workaround.c
 utilities_ovs_vlan_bug_workaround_LDADD = lib/libopenvswitch.a $(SSL_LIBS)
index c730778..3092d46 100644 (file)
@@ -198,15 +198,21 @@ Run the daemon under \fBvalgrind\fR(1), if it is installed, logging to
 .IP "\fBstrace\fR"
 Run the daemon under \fBstrace\fR(1), if it is installed, logging to
 \fIdaemon\fB.strace.log.\fIpid\fR in the log directory.
+.
+.IP "\fBglibc\fR"
+Enable GNU C library features designed to find memory errors.
 .RE
 .
 .IP
 By default, no wrapper is used.
 .
 .IP
-Wrappers greatly slow daemon operations so they should not be used in
-production.  They also produce voluminous logs that can quickly fill
-small disk partitions.
+Each of the wrappers can expose bugs in Open vSwitch that lead to
+incorrect operation, including crashes.  The \fBvalgring\fR and
+\fBstrace\fR wrappers greatly slow daemon operations so they should
+not be used in production.  They also produce voluminous logs that can
+quickly fill small disk partitions.  The \fBglibc\fR wrapper is less
+resource-intensive but still somewhat slows the daemons.
 .
 .PP
 The following options control file locations.  They should only be
@@ -223,6 +229,12 @@ Overrides the file name for the Unix domain socket used to connect to
 .IP "\fB\-\-db\-schema=\fIschema\fR"
 Overrides the file name for the OVS database schema.
 .
+.IP "\fB\-\-extra-dbs=\fIfile\fR"
+Adds \fIfile\fR as an extra database for \fBovsdb\-server\fR to serve
+out.  Multiple space-separated file names may also be specified.
+\fIfile\fR should begin with \fB/\fR; if it does not, then it will be
+taken as relative to \fIdbdir\fR.
+.
 .SH "The ``stop'' command"
 .
 .PP
@@ -238,6 +250,14 @@ modules.
 This command does nothing and finishes successfully if the OVS daemons
 aren't running.
 .
+.SH "The ``restart'' command"
+.
+.PP
+The \fBrestart\fR command performs a \fBstop\fR followed by a \fBstart\fR
+command.  The command can take the same options as that of the \fBstart\fR
+command. In addition, it saves and restores Openflow flows for each
+individual bridge.
+.
 .SH "The ``status'' command"
 .
 .PP
@@ -267,27 +287,32 @@ implemented by Open vSwitch.  The most common examples of these are
 bridge ``local ports''.
 .
 .IP 2.
+Saves the Openflow flows of each bridge and the kernel datapath
+configuration for each of the kernel datapaths.
+.
+.IP 3.
 Stops the Open vSwitch daemons, as if by a call to \fBovs\-ctl
 stop\fR.
 .
-.IP 3.
+.IP 4.
 Saves the kernel configuration state of the OVS internal interfaces
 listed in step 1, including IP and IPv6 addresses and routing table
 entries.
 .
-.IP 4.
+.IP 5.
 Unloads the Open vSwitch kernel module (including the bridge
 compatibility module if it is loaded).
 .
-.IP 5.
-Starts OVS back up, as if by a call to \fBovs\-ctl start\fR.  This
-reloads the kernel module and restarts the OVS daemons (including
-\fBovs\-brcompatd\fR, if \fB\-\-brcompat\fR is specified).
-.
 .IP 6.
-Restores the kernel configuration state that was saved in step 3.
+Starts OVS back up, as if by a call to \fBovs\-ctl start\fR.  This
+reloads the kernel module, restores the saved kernel datapath configuration,
+restarts the OVS daemons (including \fBovs\-brcompatd\fR, if \fB\-\-brcompat\fR
+is specified) and finally restores the saved Openflow flows.
 .
 .IP 7.
+Restores the kernel configuration state that was saved in step 4.
+.
+.IP 8.
 Checks for daemons that may need to be restarted because they have
 packet sockets that are listening on old instances of Open vSwitch
 kernel interfaces and, if it finds any, prints a warning on stdout.
index 674c3c3..e8b72ba 100755 (executable)
@@ -30,13 +30,21 @@ done
 ## start ##
 ## ----- ##
 
+restore_datapaths () {
+    [ -n "${script_datapaths}" ] && \
+        action "Restoring datapath configuration" "${script_datapaths}"
+}
+
 insert_openvswitch_mod_if_required () {
     # If openvswitch is already loaded then we're done.
     test -e /sys/module/openvswitch -o -e /sys/module/openvswitch_mod && \
      return 0
 
     # Load openvswitch.  If that's successful then we're done.
-    action "Inserting openvswitch module" modprobe openvswitch && return 0
+    if action "Inserting openvswitch module" modprobe openvswitch; then
+        restore_datapaths
+        return 0
+    fi
 
     # If the bridge module is loaded, then that might be blocking
     # openvswitch.  Try to unload it, if there are no bridges.
@@ -50,6 +58,7 @@ insert_openvswitch_mod_if_required () {
 
     # Try loading openvswitch again.
     action "Inserting openvswitch module" modprobe openvswitch
+    restore_datapaths
 }
 
 insert_brcompat_mod_if_required () {
@@ -189,12 +198,26 @@ start_ovsdb () {
 
         # Start ovsdb-server.
         set ovsdb-server "$DB_FILE"
+        for db in $EXTRA_DBS; do
+            case $db in
+                /*) ;;
+                *) db=$dbdir/$db ;;
+            esac
+
+            if test ! -f "$db"; then
+                log_warning_msg "$db (from \$EXTRA_DBS) does not exist."
+            elif ovsdb-tool db-version "$db" >/dev/null; then
+                set "$@" "$db"
+            else
+                log_warning_msg "$db (from \$EXTRA_DBS) cannot be read as a database (see error message above)"
+            fi
+        done
         set "$@" -vconsole:emer -vsyslog:err -vfile:info
         set "$@" --remote=punix:"$DB_SOCK"
-        set "$@" --remote=db:Open_vSwitch,manager_options
-        set "$@" --private-key=db:SSL,private_key
-        set "$@" --certificate=db:SSL,certificate
-        set "$@" --bootstrap-ca-cert=db:SSL,ca_cert
+        set "$@" --remote=db:Open_vSwitch,Open_vSwitch,manager_options
+        set "$@" --private-key=db:Open_vSwitch,SSL,private_key
+        set "$@" --certificate=db:Open_vSwitch,SSL,certificate
+        set "$@" --bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert
         start_daemon "$OVSDB_SERVER_PRIORITY" "$OVSDB_SERVER_WRAPPER" "$@" \
             || return 1
 
@@ -279,14 +302,45 @@ internal_interfaces () {
     done
 }
 
+save_flows () {
+   if set X `ovs_vsctl list-br`; then
+        shift
+        if "$datadir/scripts/ovs-save" save-flows "$@" > "$script_flows"; then
+            chmod +x "$script_flows"
+            return 0
+        fi
+    fi
+    script_flows=
+    return 1
+}
+
 save_interfaces () {
-    "$datadir/scripts/ovs-save" $ifaces > "$script"
+    "$datadir/scripts/ovs-save" save-interfaces ${ifaces} \
+        > "${script_interfaces}"
+}
+
+save_datapaths () {
+    "$datadir/scripts/ovs-save" save-datapaths ${datapaths} \
+        > "${script_datapaths}"
+}
+
+restore_flows () {
+    [ -n "${script_flows}" ] && \
+        action "Restoring saved flows" "${script_flows}"
 }
 
 force_reload_kmod () {
     ifaces=`internal_interfaces`
     action "Detected internal interfaces: $ifaces" true
 
+    script_interfaces=`mktemp`
+    script_datapaths=`mktemp`
+    script_flows=`mktemp`
+    trap 'rm -f "${script_interfaces}" "${script_flows}" \
+        "${script_datapaths}"' 0 1 2 13 15
+
+    action "Saving flows" save_flows
+
     # Restart the database first, since a large database may take a
     # while to load, and we want to minimize forwarding disruption.
     stop_ovsdb
@@ -294,8 +348,6 @@ force_reload_kmod () {
 
     stop_forwarding
 
-    script=`mktemp`
-    trap 'rm -f "$script"' 0 1 2 13 15
     if action "Saving interface configuration" save_interfaces; then
         :
     else
@@ -303,9 +355,18 @@ force_reload_kmod () {
         start_forwarding
         exit 1
     fi
-    chmod +x "$script"
+    chmod +x "$script_interfaces"
+
+    datapaths=`ovs-dpctl dump-dps`
+    if action "Saving datapath configuration" save_datapaths; then
+        chmod +x "${script_datapaths}"
+    else
+        log_warning_msg "Failed to save datapath configuration. The port\
+                         numbers may change after the restart"
+        script_datapaths=""
+    fi
 
-    for dp in `ovs-dpctl dump-dps`; do
+    for dp in ${datapaths}; do
         action "Removing datapath: $dp" ovs-dpctl del-dp "$dp"
     done
 
@@ -323,7 +384,9 @@ force_reload_kmod () {
 
     start_forwarding
 
-    action "Restoring interface configuration" "$script"
+    restore_flows
+
+    action "Restoring interface configuration" "$script_interfaces"
     rc=$?
     if test $rc = 0; then
         level=debug
@@ -332,11 +395,34 @@ force_reload_kmod () {
     fi
     log="logger -p daemon.$level -t ovs-save"
     $log "force-reload-kmod interface restore script exited with status $rc:"
-    $log -f "$script"
+    $log -f "$script_interfaces"
 
     "$datadir/scripts/ovs-check-dead-ifs"
 }
 
+## ------- ##
+## restart ##
+## ------- ##
+
+restart () {
+    if daemon_is_running ovsdb-server && daemon_is_running ovs-vswitchd; then
+        script_flows=`mktemp`
+        trap 'rm -f "${script_flows}"' 0 1 2 13 15
+
+        action "Saving flows" save_flows
+    fi
+
+    # Restart the database first, since a large database may take a
+    # while to load, and we want to minimize forwarding disruption.
+    stop_ovsdb
+    start_ovsdb
+
+    stop_forwarding
+    start_forwarding
+
+    restore_flows
+}
+
 ## --------------- ##
 ## enable-protocol ##
 ## --------------- ##
@@ -406,6 +492,7 @@ set_defaults () {
     DB_FILE=$dbdir/conf.db
     DB_SOCK=$rundir/db.sock
     DB_SCHEMA=$datadir/vswitch.ovsschema
+    EXTRA_DBS=
 
     PROTOCOL=gre
     DPORT=
@@ -440,6 +527,7 @@ scripts.  System administrators should not normally invoke it directly.
 Commands:
   start              start Open vSwitch daemons
   stop               stop Open vSwitch daemons
+  restart            stop and start Open vSwitch daemons
   status             check whether Open vSwitch daemons are running
   version            print versions of Open vSwitch daemons
   load-kmod          insert modules if not already present
@@ -448,18 +536,18 @@ Commands:
   enable-protocol    enable protocol specified in options with iptables
   help               display this help message
 
-One of the following options is required for "start" and "force-reload-kmod":
+One of the following options is required for "start", "restart" and "force-reload-kmod":
   --system-id=UUID   set specific ID to uniquely identify this system
   --system-id=random  use a random but persistent UUID to identify this system
 
-Other important options for "start" and "force-reload-kmod":
+Other important options for "start", "restart" and "force-reload-kmod":
   --system-type=TYPE  set system type (e.g. "XenServer")
   --system-version=VERSION  set system version (e.g. "5.6.100-39265p")
   --external-id="key=value"
                      add given key-value pair to Open_vSwitch external-ids
   --delete-bridges   delete all bridges just before starting ovs-vswitchd
 
-Less important options for "start" and "force-reload-kmod":
+Less important options for "start", "restart" and "force-reload-kmod":
   --daemon-cwd=DIR               set working dir for OVS daemons (default: $DAEMON_CWD)
   --no-force-corefiles           do not force on core dumps for OVS daemons
   --no-mlockall                  do not lock all of ovs-vswitchd into memory
@@ -467,13 +555,13 @@ Less important options for "start" and "force-reload-kmod":
   --ovs-vswitchd-priority=NICE   set ovs-vswitchd's niceness (default: $OVS_VSWITCHD_PRIORITY)
   --ovs-brcompatd-priority=NICE  set ovs-brcompatd's niceness (default: $OVS_BRCOMPATD_PRIORITY)
 
-Debugging options for "start" and "force-reload-kmod":
+Debugging options for "start", "restart" and "force-reload-kmod":
   --ovsdb-server-wrapper=WRAPPER
   --ovs-vswitchd-wrapper=WRAPPER
   --ovs-vswitchd-wrapper=WRAPPER
      run specified daemon under WRAPPER (either 'valgrind' or 'strace')
 
-Options for "start", "force-reload-kmod", "load-kmod", "status", and "version":
+Options for "start", "restart", "force-reload-kmod", "load-kmod", "status", and "version":
   --brcompat         enable Linux bridge compatibility module and daemon
 
 File location options:
@@ -591,6 +679,9 @@ case $command in
         stop_forwarding
         stop_ovsdb
         ;;
+    restart)
+        restart
+        ;;
     status)
         rc=0
         for daemon in `daemons`; do
@@ -624,4 +715,3 @@ case $command in
         exit 1
         ;;
 esac
-
index 01f4ded..b787b1c 100644 (file)
@@ -140,6 +140,9 @@ start_daemon () {
                 log_failure_msg "strace not installed, running $daemon without it"
             fi
             ;;
+        glibc)
+            set env MALLOC_CHECK_=2 MALLOC_PERTURB_=165 "$@"
+            ;;
         '')
             ;;
         *)
index be71f18..9ea0973 100644 (file)
@@ -897,6 +897,12 @@ as necessary to match the value specified.  Valid values are between 0
 .IP \fBstrip_vlan\fR
 Strips the VLAN tag from a packet if it is present.
 .
+.IP \fBpush_vlan\fR:\fIethertype\fR
+Push a new VLAN tag onto the packet.  Ethertype is used as the the Ethertype
+for the tag. Only ethertype 0x8100 should be used. (0x88a8 which the spec
+allows isn't supported at the moment.)
+A priority of zero and the tag of zero are used for the new tag.
+.
 .IP \fBmod_dl_src\fB:\fImac\fR
 Sets the source Ethernet address to \fImac\fR.
 .
@@ -919,7 +925,6 @@ Sets the TCP or UDP destination port to \fIport\fR.
 Sets the IPv4 ToS/DSCP field to \fItos\fR.  Valid values are between 0 and
 255, inclusive.  Note that the two lower reserved bits are never
 modified.
-.
 .RE
 .IP
 The following actions are Nicira vendor extensions that, as of this writing, are
@@ -1005,6 +1010,15 @@ in field \fIdst\fR.
 Example: \fBload:55\->NXM_NX_REG2[0..5]\fR loads value 55 (bit pattern
 \fB110111\fR) into bits 0 through 5, inclusive, in register 2.
 .
+.IP "\fBset_field:\fIvalue\fB\->\fIdst"
+Writes the literal \fIvalue\fR into the field \fIdst\fR, which should
+be specified as a name used for matching.  (This is similar to
+\fBload\fR but more closely matches the set-field action defined in
+Open Flow 1.2 and above.)
+.
+.IP
+Example: \fBset_field:fe80:0123:4567:890a:a6ba:dbff:fefe:59fa\->ipv6_src\fR
+.
 .IP "\fBmultipath(\fIfields\fB, \fIbasis\fB, \fIalgorithm\fB, \fIn_links\fB, \fIarg\fB, \fIdst\fB[\fIstart\fB..\fIend\fB])\fR"
 Hashes \fIfields\fR using \fIbasis\fR as a universal hash parameter,
 then the applies multipath link selection \fIalgorithm\fR (with
@@ -1131,6 +1145,26 @@ possibly for a lowest-priority ``catch-all'' flow, that is, a flow
 with no match criteria.  (This is why the default \fBtable\fR is 1, to
 keep the learned flows separate from the primary flow table 0.)
 .
+.RS
+.IP \fBapply_actions(\fR[\fIaction\fR][\fB,\fIaction\fR...]\fB)
+Applies the specific action(s) immediately. The syntax of actions are same
+to \fBactions=\fR field.
+.
+.IP \fBclear_actions\fR
+Clears all the actions in the action set immediately.
+.
+.IP \fBwrite_metadata\fB:\fIvalue\fR[/\fImask\fR]
+Updates the metadata field for the flow. If \fImask\fR is omitted, the
+metadata field is set exactly to \fIvalue\fR; if \fImask\fR is specified, then
+a 1-bit in \fImask\fR indicates that the corresponding bit in the metadata
+field will be replaced with the corresponding bit from \fIvalue\fR. Both
+\fIvalue\fR and \fImask\fR are 64-bit values that are decimal by default; use
+a \fB0x\fR prefix to specify them in hexadecimal.
+.
+.IP \fBgoto_table\fR:\fItable\fR
+Indicates the next table in the process pipeline.
+.RE
+.
 .IP "\fBfin_timeout(\fIargument\fR[\fB,\fIargument\fR]\fB)"
 This action changes the idle timeout or hard timeout, or both, of this
 OpenFlow rule when the rule matches a TCP packet with the FIN or RST
index dea8878..a67a554 100644 (file)
@@ -741,8 +741,9 @@ fetch_ofputil_phy_port(const char *vconn_name, const char *port_name,
 static uint16_t
 str_to_port_no(const char *vconn_name, const char *port_name)
 {
-    uint16_t port_no = ofputil_port_from_string(port_name);
-    if (port_no) {
+    uint16_t port_no;
+
+    if (ofputil_port_from_string(port_name, &port_no)) {
         return port_no;
     } else {
         struct ofputil_phy_port pp;
@@ -948,28 +949,24 @@ ofctl_dump_aggregate(int argc, char *argv[])
 static void
 ofctl_queue_stats(int argc, char *argv[])
 {
-    struct ofp10_queue_stats_request *req;
     struct ofpbuf *request;
     struct vconn *vconn;
+    struct ofputil_queue_stats_request oqs;
 
     open_vconn(argv[1], &vconn);
-    request = ofpraw_alloc(OFPRAW_OFPST_QUEUE_REQUEST,
-                           vconn_get_version(vconn), 0);
-    req = ofpbuf_put_zeros(request, sizeof *req);
 
     if (argc > 2 && argv[2][0] && strcasecmp(argv[2], "all")) {
-        req->port_no = htons(str_to_port_no(argv[1], argv[2]));
+        oqs.port_no = str_to_port_no(argv[1], argv[2]);
     } else {
-        req->port_no = htons(OFPP_ALL);
+        oqs.port_no = OFPP_ALL;
     }
     if (argc > 3 && argv[3][0] && strcasecmp(argv[3], "all")) {
-        req->queue_id = htonl(atoi(argv[3]));
+        oqs.queue_id = atoi(argv[3]);
     } else {
-        req->queue_id = htonl(OFPQ_ALL);
+        oqs.queue_id = OFPQ_ALL;
     }
 
-    memset(req->pad, 0, sizeof req->pad);
-
+    request = ofputil_encode_queue_stats_request(vconn_get_version(vconn), &oqs);
     dump_stats_transaction(vconn, request);
     vconn_close(vconn);
 }
@@ -1085,7 +1082,10 @@ static void
 set_packet_in_format(struct vconn *vconn,
                      enum nx_packet_in_format packet_in_format)
 {
-    struct ofpbuf *spif = ofputil_make_set_packet_in_format(packet_in_format);
+    struct ofpbuf *spif;
+
+    spif = ofputil_make_set_packet_in_format(vconn_get_version(vconn),
+                                             packet_in_format);
     transact_noreply(vconn, spif);
     VLOG_DBG("%s: using user-specified packet in format %s",
              vconn_get_name(vconn),
@@ -1386,7 +1386,8 @@ ofctl_monitor(int argc, char *argv[])
     } else {
         struct ofpbuf *spif, *reply;
 
-        spif = ofputil_make_set_packet_in_format(NXPIF_NXM);
+        spif = ofputil_make_set_packet_in_format(vconn_get_version(vconn),
+                                                 NXPIF_NXM);
         run(vconn_transact_noreply(vconn, spif, &reply),
             "talking to %s", vconn_get_name(vconn));
         if (reply) {
@@ -1414,17 +1415,13 @@ ofctl_snoop(int argc OVS_UNUSED, char *argv[])
 static void
 ofctl_dump_ports(int argc, char *argv[])
 {
-    struct ofp10_port_stats_request *req;
     struct ofpbuf *request;
     struct vconn *vconn;
     uint16_t port;
 
     open_vconn(argv[1], &vconn);
-    request = ofpraw_alloc(OFPRAW_OFPST_PORT_REQUEST,
-                           vconn_get_version(vconn), 0);
-    req = ofpbuf_put_zeros(request, sizeof *req);
     port = argc > 2 ? str_to_port_no(argv[1], argv[2]) : OFPP_NONE;
-    req->port_no = htons(port);
+    request = ofputil_encode_dump_ports_request(vconn_get_version(vconn), port);
     dump_stats_transaction(vconn, request);
     vconn_close(vconn);
 }
diff --git a/utilities/ovs-parse-backtrace.8 b/utilities/ovs-parse-backtrace.8
new file mode 100644 (file)
index 0000000..2fa7c17
--- /dev/null
@@ -0,0 +1,28 @@
+.TH ovs\-parse\-backtrace 8 "October 2012" "Open vSwitch" "Open vSwitch Manual"
+.
+.SH NAME
+ovs\-parse\-backtrace \- parses ovs-appctl backtrace output
+.
+.SH SYNOPSIS
+\fBovs\-appctl backtrace\fR | \fBovs\-parse\-backtrace\fR [\fIbinary\fR]
+.P
+\fBovs\-parse\-backtrace\fR [\fIbinary\fR] < \fIbacktrace\fR
+.
+.SH DESCRIPTION
+In some configurations, many Open vSwitch daemons can produce a series of
+backtraces using the \fBovs\-appctl backtrace\fR command.  Users can analyze
+these backtraces to figure out what the given Open vSwitch daemon may be
+spending most of its time doing.  \fBovs\-parse\-backtrace\fR makes this output
+easier to interpret.
+.PP
+The \fBovs\-appctl backtrace\fR output must be supplied on standard input.  The
+binary that produced the output should be supplied as the sole non-option
+argument.  For best results, the binary should have debug symbols.
+.
+.SH OPTIONS
+.TP
+\fB\-\-help\fR
+Prints a usage message and exits.
+.P
+\fB\-\-version\fR
+Prints the version and exits.
diff --git a/utilities/ovs-parse-backtrace.in b/utilities/ovs-parse-backtrace.in
new file mode 100755 (executable)
index 0000000..350cbd9
--- /dev/null
@@ -0,0 +1,103 @@
+#! @PYTHON@
+#
+# Copyright (c) 2012 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.
+
+import optparse
+import os
+import re
+import subprocess
+import sys
+
+
+addr2line_cache = {}  # None if addr2line is missing or broken.
+
+
+def addr2line(binary, addr):
+    global addr2line_cache
+
+    if addr2line_cache is None:
+        return ""
+
+    if addr in addr2line_cache:
+        return addr2line_cache[addr]
+
+    cmd = ["addr2line", "-f", "-s", "-e", binary, addr]
+    try:
+        proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+                                stderr=subprocess.PIPE)
+        lines = proc.stdout.readlines()
+        failed = proc.returncode
+    except OSError:
+        failed = True
+
+    if failed:
+        addr2line_cache = None
+        return ""
+
+    lines = [l.strip() for l in lines]
+    return " ".join(lines)
+
+
+def main():
+    parser = optparse.OptionParser(version='@VERSION@',
+                                   usage="usage: %prog [binary]",
+                                   description="""\
+Parses the output of ovs-appctl backtrace producing a more human readable
+result.  Expected usage is for ovs-appctl backtrace to be piped in.""")
+    options, args = parser.parse_args()
+
+    if len(args) > 1:
+        parser.print_help()
+        sys.exit(1)
+
+    if len(args) == 1:
+        binary = args[0]
+    else:
+        binary = "@sbindir@/ovs-vswitchd"
+        debug = "/usr/lib/debug%s.debug" % binary
+        if os.path.exists(debug):
+            binary = debug
+
+    print "Binary: %s\n" % binary
+
+    stdin = sys.stdin.read()
+
+    traces = []
+    for trace in stdin.strip().split("\n\n"):
+        lines = trace.splitlines()
+        match = re.search(r'Count (\d+)', lines[0])
+        if match:
+            count = int(match.group(1))
+        else:
+            count = 0
+        traces.append((lines[1:], count))
+    traces = sorted(traces, key=(lambda x: x[1]), reverse=True)
+
+    for lines, count in traces:
+        longest = max(len(l) for l in lines)
+
+        print "Backtrace Count: %d" % count
+        for line in lines:
+            match = re.search(r'\[(0x.*)]', line)
+            if match:
+                print "%s %s" % (line.ljust(longest),
+                                 addr2line(binary, match.group(1)))
+            else:
+                print line
+        print
+
+
+if __name__ == "__main__":
+    main()
index 2a67d53..1f15410 100755 (executable)
@@ -429,6 +429,8 @@ make_request() {
     must_not_exist "$arg1-privkey.pem"
     must_not_exist "$arg1-req.pem"
     make_tmpdir
+    # Use uuidgen or date to create unique subject DNs.
+    unique=`(uuidgen) 2>/dev/null` || unique=`date +"%Y %b %d %T"`
     cat > "$TMP/req.cnf" <<EOF
 [ req ]
 prompt = no
@@ -440,7 +442,7 @@ ST = CA
 L = Palo Alto
 O = Open vSwitch
 OU = Open vSwitch certifier
-CN = Open vSwitch certificate for $arg1
+CN = $arg1 id:$unique
 EOF
     if test $keytype = rsa; then
         (umask 077 && openssl genrsa -out "$1-privkey.pem" $bits) 1>&3 2>&3 \
@@ -512,7 +514,7 @@ elif test "$command" = self-sign; then
     # Create both the private key and certificate with restricted permissions.
     (umask 077 && \
      openssl x509 -in "$arg1-req.pem" -out "$arg1-cert.pem.tmp" \
-        -signkey "$arg1-privkey.pem" -req -text) 2>&3 || exit $?
+        -signkey "$arg1-privkey.pem" -req -days 2191 -text) 2>&3 || exit $?
 
     # Reset the permissions on the certificate to the user's default.
     cat "$arg1-cert.pem.tmp" > "$arg1-cert.pem"
index 297c2fa..01e5791 100755 (executable)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-if test "X$1" = X--help; then
+usage() {
+    UTIL=$(basename $0)
     cat <<EOF
-$0: saves the kernel configuration of network interfaces
-usage: $0 NETDEV...
+${UTIL}: Provides helper functions to save Open vSwitch's configuration.
+usage: $0 COMMAND
 
-Outputs a shell script on stdout that will restore the current
-kernel configuration of the specified network interfaces, as
-well as the system iptables configuration.
+Commands:
+ save-interfaces        Outputs a shell script on stdout that will restore
+                        the current kernel configuration of the specified
+                        network interfaces, as well as the system iptables
+                        configuration.
+ save-flows             Outputs a shell script on stdout that will restore
+                        Openflow flows of each Open vSwitch bridge.
+ save-datapaths         Outputs a shell script on stdout that will restore
+                        the datapaths with the same port numbers as before.
 
-This script is meant as a helper for the Open vSwitch init
-script "force-reload-kmod" command.
+This script is meant as a helper for the Open vSwitch init script commands.
 EOF
-    exit 0
-fi
+}
 
 PATH=/sbin:/bin:/usr/sbin:/usr/bin
 
@@ -43,116 +48,237 @@ missing_program () {
     IFS=$save_IFS
     return 0
 }
-if missing_program ip; then 
-    echo "$0: ip not found in $PATH" >&2
-    exit 1
-fi
-
-if test "$#" = 0; then
-    echo "# $0: no parameters given (use \"$0 --help\" for help)"
-fi
-
-devs=$*
-for dev in $devs; do
-    state=`ip link show dev $dev` || continue
-
-    echo "# $dev"
-    # Link state (Ethernet addresses, up/down, ...)
-    linkcmd=
-    case $state in
-        *"state UP"* | *[,\<]"UP"[,\>]* )
-            linkcmd="$linkcmd up"
-            ;;
-        *"state DOWN"*)
-            linkcmd="$linkcmd down"
-            ;;
-    esac
-    if expr "$state" : '.*\bdynamic\b' > /dev/null; then
-        linkcmd="$linkcmd dynamic"
-    fi
-    if qlen=`expr "$state" : '.*qlen \([0-9]+\)'`; then
-        linkcmd="$linkcmd txqueuelen $qlen"
-    fi
-    if hwaddr=`expr "$state" : '.*link/ether \([^ ]*\)'`; then
-        linkcmd="$linkcmd address $hwaddr"
-    fi
-    if brd=`expr "$state" : '.*brd \([^ ]*\)'`; then
-        linkcmd="$linkcmd broadcast $brd"
-    fi
-    if mtu=`expr "$state" : '.*mtu \([0-9]+\)'`; then
-        linkcmd="$linkcmd mtu $mtu"
+
+save_interfaces () {
+    if missing_program ip; then
+        echo "$0: ip not found in $PATH" >&2
+        exit 1
     fi
-    if test -n "$linkcmd"; then
-        echo ip link set dev $dev down # Required to change hwaddr.
-        echo ip link set dev $dev $linkcmd
+
+    if test "$#" = 0; then
+        exit 0
     fi
 
-    # IP addresses (including IPv6).
-    echo "ip addr flush dev $dev 2>/dev/null" # Suppresses "Nothing to flush".
-    ip addr show dev $dev | while read addr; do
-        set -- $addr
-
-        # Check and trim family.
-        family=$1
-        shift
-        case $family in
-            inet | inet6) ;;
-            *) continue ;;
+    devs="$@"
+    for dev in $devs; do
+        state=`ip link show dev $dev` || continue
+
+        echo "# $dev"
+        # Link state (Ethernet addresses, up/down, ...)
+        linkcmd=
+        case $state in
+            *"state UP"* | *[,\<]"UP"[,\>]* )
+                linkcmd="$linkcmd up"
+                ;;
+            *"state DOWN"*)
+                linkcmd="$linkcmd down"
+                ;;
         esac
+        if expr "$state" : '.*\bdynamic\b' > /dev/null; then
+            linkcmd="$linkcmd dynamic"
+        fi
+        if qlen=`expr "$state" : '.*qlen \([0-9]+\)'`; then
+            linkcmd="$linkcmd txqueuelen $qlen"
+        fi
+        if hwaddr=`expr "$state" : '.*link/ether \([^ ]*\)'`; then
+            linkcmd="$linkcmd address $hwaddr"
+        fi
+        if brd=`expr "$state" : '.*brd \([^ ]*\)'`; then
+            linkcmd="$linkcmd broadcast $brd"
+        fi
+        if mtu=`expr "$state" : '.*mtu \([0-9]+\)'`; then
+            linkcmd="$linkcmd mtu $mtu"
+        fi
+        if test -n "$linkcmd"; then
+            echo ip link set dev $dev down # Required to change hwaddr.
+            echo ip link set dev $dev $linkcmd
+        fi
+
+        # IP addresses (including IPv6).
+        echo "ip addr flush dev $dev 2>/dev/null" # Suppresses "Nothing to flush".
+        ip addr show dev $dev | while read addr; do
+            set -- $addr
+
+            # Check and trim family.
+            family=$1
+            shift
+            case $family in
+                inet | inet6) ;;
+                *) continue ;;
+            esac
 
-        # Trim device off the end--"ip" insists on having "dev" precede it.
-        addrcmd=
-        while test $# != 0; do
-            case $1 in
-                dynamic)
-                    # Omit kernel-maintained route.
-                    continue 2
-                    ;;
-                scope)
-                    if test "$2" = link; then
-                        # Omit route derived from IP address, e.g.
-                        # 172.16.0.0/16 derived from 172.16.12.34.
+            # Trim device off the end--"ip" insists on having "dev" precede it.
+            addrcmd=
+            while test $# != 0; do
+                case $1 in
+                    dynamic)
+                        # Omit kernel-maintained route.
                         continue 2
-                    fi
-                    ;;
-                "$dev"|"$dev:"*)
-                    # Address label string
-                    addrcmd="$addrcmd label $1"
-                    shift
-                    continue
-                    ;;
+                        ;;
+                    scope)
+                        if test "$2" = link; then
+                            # Omit route derived from IP address, e.g.
+                            # 172.16.0.0/16 derived from 172.16.12.34.
+                            continue 2
+                        fi
+                        ;;
+                    "$dev"|"$dev:"*)
+                        # Address label string
+                        addrcmd="$addrcmd label $1"
+                        shift
+                        continue
+                        ;;
+                esac
+                addrcmd="$addrcmd $1"
+                shift
+            done
+            if test "$1" != "$dev"; then
+                addrcmd="$addrcmd $1"
+            fi
+
+            echo ip -f $family addr add $addrcmd dev $dev
+        done
+
+        # Routes.
+        echo "ip route flush dev $dev proto boot 2>/dev/null" # Suppresses "Nothing to flush".
+        ip route show dev $dev | while read route; do
+            # "proto kernel" routes are installed by the kernel automatically.
+            case $route in
+                *" proto kernel "*) continue ;;
             esac
-            addrcmd="$addrcmd $1"
-            shift
+
+            echo "ip route add $route dev $dev"
         done
-        if test "$1" != "$dev"; then
-            addrcmd="$addrcmd $1"
-        fi
 
-        echo ip -f $family addr add $addrcmd dev $dev
+        echo
     done
 
-    # Routes.
-    echo "ip route flush dev $dev proto boot 2>/dev/null" # Suppresses "Nothing to flush".
-    ip route show dev $dev | while read route; do
-        # "proto kernel" routes are installed by the kernel automatically.
-        case $route in
-            *" proto kernel "*) continue ;;
-        esac
+    if missing_program iptables-save; then
+        echo "# iptables-save not found in $PATH, not saving iptables state"
+    else
+        echo "# global"
+        echo "iptables-restore <<'EOF'"
+        iptables-save
+        echo "EOF"
+    fi
+}
 
-        echo "ip route add $route dev $dev"
+save_flows () {
+    if missing_program ovs-ofctl; then
+        echo "$0: ovs-ofctl not found in $PATH" >&2
+        exit 1
+    fi
+
+    for bridge in "$@"; do
+        echo "ovs-ofctl add-flows ${bridge} - << EOF"
+        ovs-ofctl dump-flows "${bridge}" | sed -e '/NXST_FLOW/d' \
+            -e 's/\(idle\|hard\)_age=[^,]*,//g'
+        echo "EOF"
     done
+}
 
-    echo
-done
+ovs_vsctl () {
+    ovs-vsctl --no-wait --timeout=5 "$@"
+}
+
+save_datapaths () {
+    if missing_program ovs-dpctl; then
+        echo "$0: ovs-dpctl not found in $PATH" >&2
+        exit 1
+    fi
+    if missing_program ovs-vsctl; then
+        echo "$0: ovs-vsctl not found in $PATH" >&2
+        exit 1
+    fi
+
+    for dp in "$@"; do
+        echo "ovs-dpctl add-dp ${dp}"
+        ovs-dpctl show $dp | while read line; do
+            # An example 'ovs-dpctl show' output looks like this:
+            # system@br1:
+            # lookups: hit:0 missed:0 lost:0
+            # flows: 0
+            # port 0: br1 (internal)
+            # port 2: gre2886795521 (ipsec_gre: key=flow, pmtud=false, remote_ip=172.17.1.1, tos=inherit)
+            # port 3: gre1 (ipsec_gre: remote_ip=192.168.113.1)
+            # port 14: gre2 (gre: remote_ip=192.168.115.1)
+            # port 15: gre3 (gre64: remote_ip=192.168.116.1)
+            # port 16: eth0
+            # port 17: br1- (patch: peer=br1+)
+
+            # Skip lines which do not have 'port'
+            if port_no=`expr "${line}" : '.*port \([0-9]\+\):'`; then :; else
+                continue
+            fi
+
+            netdev=`echo ${line} | awk '{print $3}'`
+
+            # Do not add port that has the same name as the datapath. It gets
+            # added by default.
+            [ "${dp#system@}" = "${netdev}" ] && continue
+
+            type=`echo ${line} | awk '{print $4}' | sed 's/[:)(]//g'`
+            [ ! -n "${type}" ] && type="system"
+
+            command="ovs-dpctl add-if ${dp}\
+                        ${netdev},type=${type},port_no=${port_no}"
+
+            options=`echo ${line} | awk -F: '{print $3}' | sed 's/[) ]//g'`
+            [ -n "${options}" ] && command="${command},${options}"
 
-if missing_program iptables-save; then
-    echo "# iptables-save not found in $PATH, not saving iptables state"
-else
-    echo "# global"
-    echo "iptables-restore <<'EOF'"
-    iptables-save
-    echo "EOF"
-fi
+            # For ipsec, ovs-dpctl does not show the key value pairs related
+            # to certificates. Get that information from ovs-vsctl.
+            if [ "${type}" = "ipsec_gre" ] ; then
+                if peer_cert=`ovs_vsctl get interface \
+                                "${netdev}" options:peer_cert 2>/dev/null`; then
+                    # The option peer_cert comes with an accompanying
+                    # "certificate" or "use_ssl_cert"
+                    if certificate=`ovs_vsctl get interface "${netdev}" \
+                            options:certificate 2>/dev/null` ; then
+                        command="${command},peer_cert=${peer_cert},certificate=${certificate}"
+                    else
+                        use_ssl_cert=`ovs_vsctl get interface "${netdev}" \
+                                        options:use_ssl_cert 2>/dev/null`
+                        command="${command},peer_cert=${peer_cert},use_ssl_cert=${use_ssl_cert}"
+                    fi
+                else
+                    psk=`ovs_vsctl get interface "${netdev}" \
+                            options:psk 2>/dev/null`
+                    command="${command},psk=${psk}"
+                fi
+            fi
+            echo ${command}
+        done
+    done
+}
+
+while [ $# -ne 0 ]
+do
+    case $1 in
+        "save-datapaths")
+            shift
+            save_datapaths "$@"
+            exit 0
+            ;;
+        "save-flows")
+            shift
+            save_flows "$@"
+            exit 0
+            ;;
+        "save-interfaces")
+            shift
+            save_interfaces "$@"
+            exit 0
+            ;;
+        -h | --help)
+            usage
+            exit 0
+            ;;
+        *)
+            echo >&2 "$0: unknown command \"$1\" (use --help for help)"
+            exit 1
+            ;;
+    esac
+done
 
 exit 0
index e6bd63b..fda3a89 100644 (file)
@@ -3995,7 +3995,7 @@ static const struct vsctl_command_syntax all_commands[] = {
 
     /* Manager commands. */
     {"get-manager", 0, 0, pre_manager, cmd_get_manager, NULL, "", RO},
-    {"del-manager", 0, INT_MAX, pre_manager, cmd_del_manager, NULL, "", RW},
+    {"del-manager", 0, 0, pre_manager, cmd_del_manager, NULL, "", RW},
     {"set-manager", 1, INT_MAX, pre_manager, cmd_set_manager, NULL, "", RW},
 
     /* SSL commands. */
index 9092129..fe513ac 100644 (file)
@@ -24,7 +24,7 @@ EXTRA_DIST += vswitchd/INTERNALS
 MAN_ROOTS += vswitchd/ovs-vswitchd.8.in
 
 if BUILD_BRCOMPAT
-if HAVE_NETLINK
+if LINUX_DATAPATH
 sbin_PROGRAMS += vswitchd/ovs-brcompatd
 vswitchd_ovs_brcompatd_SOURCES = \
        vswitchd/ovs-brcompatd.c
index 940e5e7..a481f06 100644 (file)
@@ -274,6 +274,7 @@ bridge_init(const char *remote)
     idl = ovsdb_idl_create(remote, &ovsrec_idl_class, true);
     idl_seqno = ovsdb_idl_get_seqno(idl);
     ovsdb_idl_set_lock(idl, "ovs_vswitchd");
+    ovsdb_idl_verify_write_only(idl);
 
     ovsdb_idl_omit_alert(idl, &ovsrec_open_vswitch_col_cur_cfg);
     ovsdb_idl_omit_alert(idl, &ovsrec_open_vswitch_col_statistics);
@@ -1416,7 +1417,7 @@ bridge_configure_flow_eviction_threshold(struct bridge *br)
     if (threshold_str) {
         threshold = strtoul(threshold_str, NULL, 10);
     } else {
-        threshold = OFPROTO_FLOW_EVICTON_THRESHOLD_DEFAULT;
+        threshold = OFPROTO_FLOW_EVICTION_THRESHOLD_DEFAULT;
     }
     ofproto_set_flow_eviction_threshold(br->ofproto, threshold);
 }
@@ -3311,12 +3312,24 @@ iface_configure_cfm(struct iface *iface)
     const char *opstate_str;
     const char *cfm_ccm_vlan;
     struct cfm_settings s;
+    struct smap netdev_args;
 
     if (!cfg->n_cfm_mpid) {
         ofproto_port_clear_cfm(iface->port->bridge->ofproto, iface->ofp_port);
         return;
     }
 
+    s.check_tnl_key = false;
+    smap_init(&netdev_args);
+    if (!netdev_get_config(iface->netdev, &netdev_args)) {
+        const char *key = smap_get(&netdev_args, "key");
+        const char *in_key = smap_get(&netdev_args, "in_key");
+
+        s.check_tnl_key = (key && !strcmp(key, "flow"))
+                           || (in_key && !strcmp(in_key, "flow"));
+    }
+    smap_destroy(&netdev_args);
+
     s.mpid = *cfg->cfm_mpid;
     s.interval = smap_get_int(&iface->cfg->other_config, "cfm_interval", 0);
     cfm_ccm_vlan = smap_get(&iface->cfg->other_config, "cfm_ccm_vlan");
index e0937a3..90446f2 100644 (file)
@@ -48,13 +48,12 @@ VLOG_DEFINE_THIS_MODULE(system_stats);
 
 /* #ifdefs make it a pain to maintain code: you have to try to build both ways.
  * Thus, this file tries to compile as much of the code as possible regardless
- * of the target, by writing "if (LINUX)" instead of "#ifdef __linux__" where
- * this is possible. */
-#ifdef __linux__
+ * of the target, by writing "if (LINUX_DATAPATH)" instead of "#ifdef
+ * __linux__" where this is possible. */
+#ifdef LINUX_DATAPATH
 #include <asm/param.h>
-#define LINUX 1
 #else
-#define LINUX 0
+#define LINUX_DATAPATH 0
 #endif
 
 static void
@@ -97,7 +96,7 @@ get_page_size(void)
 static void
 get_memory_stats(struct smap *stats)
 {
-    if (!LINUX) {
+    if (!LINUX_DATAPATH) {
         unsigned int pagesize = get_page_size();
         long int phys_pages = sysconf(_SC_PHYS_PAGES);
 #ifdef _SC_AVPHYS_PAGES
@@ -170,7 +169,7 @@ get_boot_time(void)
     static long long int cache_expiration = LLONG_MIN;
     static long long int boot_time;
 
-    assert(LINUX);
+    assert(LINUX_DATAPATH);
 
     if (time_msec() >= cache_expiration) {
         static const char stat_file[] = "/proc/stat";
@@ -202,7 +201,7 @@ get_boot_time(void)
 static unsigned long long int
 ticks_to_ms(unsigned long long int ticks)
 {
-    assert(LINUX);
+    assert(LINUX_DATAPATH);
 
 #ifndef USER_HZ
 #define USER_HZ 100
@@ -235,7 +234,7 @@ get_raw_process_info(pid_t pid, struct raw_process_info *raw)
     FILE *stream;
     int n;
 
-    assert(LINUX);
+    assert(LINUX_DATAPATH);
 
     sprintf(file_name, "/proc/%lu/stat", (unsigned long int) pid);
     stream = fopen(file_name, "r");
@@ -320,7 +319,7 @@ count_crashes(pid_t pid)
     int crashes = 0;
     FILE *stream;
 
-    assert(LINUX);
+    assert(LINUX_DATAPATH);
 
     sprintf(file_name, "/proc/%lu/cmdline", (unsigned long int) pid);
     stream = fopen(file_name, "r");
@@ -363,7 +362,7 @@ get_process_info(pid_t pid, struct process_info *pinfo)
 {
     struct raw_process_info child;
 
-    assert(LINUX);
+    assert(LINUX_DATAPATH);
     if (!get_raw_process_info(pid, &child)) {
         return false;
     }
@@ -428,7 +427,7 @@ get_process_stats(struct smap *stats)
         key = xasprintf("process_%.*s",
                         (int) (extension - de->d_name), de->d_name);
         if (!smap_get(stats, key)) {
-            if (LINUX && get_process_info(pid, &pinfo)) {
+            if (LINUX_DATAPATH && get_process_info(pid, &pinfo)) {
                 smap_add_format(stats, key, "%lu,%lu,%lld,%d,%lld,%lld",
                                 pinfo.vsz, pinfo.rss, pinfo.cputime,
                                 pinfo.crashes, pinfo.booted, pinfo.uptime);
index a1b99f8..0bc4ccd 100644 (file)
             IPsec tunnel.
           </dd>
 
+          <dt><code>gre64</code></dt>
+          <dd>
+            It is same as GRE, but it allows 64 bit key. To store higher 32-bits
+            of key, it uses GRE protocol sequence number field. This is non
+            standard use of GRE protocol since OVS does not increment
+            sequence number for every packet at time of encap as expected by
+            standard GRE implementation. See <ref group="Tunnel Options"/>
+            for information on configuring GRE tunnels.
+          </dd>
+
+          <dt><code>ipsec_gre64</code></dt>
+          <dd>
+            Same as IPSEC_GRE except 64 bit key.
+          </dd>
+
           <dt><code>capwap</code></dt>
           <dd>
             An Ethernet tunnel over the UDP transport portion of CAPWAP (RFC
     <group title="Tunnel Options">
       <p>
         These options apply to interfaces with <ref column="type"/> of
-        <code>gre</code>, <code>ipsec_gre</code>, and <code>capwap</code>.
+        <code>gre</code>, <code>ipsec_gre</code>, <code>gre64</code>,
+        <code>ipsec_gre64</code>, and <code>capwap</code>.
       </p>
 
       <p>
         of the tunnel headers.  Note that this option causes behavior that is
         typically reserved for routers and therefore is not entirely in
         compliance with the IEEE 802.1D specification for bridges.  Default is
-        enabled; set to <code>false</code> to disable.
+        disabled; set to <code>true</code> to enable.
       </column>
 
       <group title="Tunnel Options: gre only">
         faulted otherwise.
       </p>
 
+      <p>
+          When operating over tunnels which have no <code>in_key</code>, or an
+          <code>in_key</code> of <code>flow</code>.  CFM will only accept CCMs
+          with a tunnel key of zero.
+      </p>
+
       <column name="cfm_mpid">
         A Maintenance Point ID (MPID) uniquely identifies each endpoint within
         a Maintenance Association.  The MPID is used to identify this endpoint
       <column name="other_config" key="cfm_ccm_pcp"
         type='{"type": "integer", "minInteger": 1, "maxInteger": 7}'>
         When set, the CFM module will apply a VLAN tag to all CCMs it generates
-        with the given PCP value.  The VLAN ID of the tag is governed by the
+        with the given PCP value, the VLAN ID of the tag is governed by the
         value of <ref column="other_config" key="cfm_ccm_vlan"/>. If
         <ref column="other_config" key="cfm_ccm_vlan"/> is unset, a VLAN ID of
         zero is used.
index a199825..534451b 100755 (executable)
@@ -107,6 +107,16 @@ stop () {
     rm -f /var/lock/subsys/openvswitch
 }
 
+restart () {
+    if [ "$1" = "--save-flows=yes" ]; then
+        stop_daemon ovs-xapi-sync
+        start restart
+    else
+        stop
+        start
+    fi
+}
+
 ovs_ctl=/usr/share/openvswitch/scripts/ovs-ctl
 case $1 in
     start)
@@ -116,8 +126,8 @@ case $1 in
         stop
         ;;
     restart)
-        stop
-        start
+        shift
+        restart "$@"
         ;;
     reload|force-reload)
         # The main OVS daemons keep up-to-date, but ovs-xapi-sync needs help.
index c34c7db..18e421b 100644 (file)
@@ -428,6 +428,7 @@ exit 0
 /usr/bin/ovs-appctl
 /usr/bin/ovs-dpctl
 /usr/bin/ovs-ofctl
+/usr/bin/ovs-parse-backtrace
 /usr/bin/ovs-parse-leaks
 /usr/bin/ovs-pcap
 /usr/bin/ovs-tcpundump
@@ -444,6 +445,7 @@ exit 0
 /usr/share/man/man8/ovs-ctl.8.gz
 /usr/share/man/man8/ovs-dpctl.8.gz
 /usr/share/man/man8/ovs-ofctl.8.gz
+/usr/share/man/man8/ovs-parse-backtrace.8.gz
 /usr/share/man/man8/ovs-parse-leaks.8.gz
 /usr/share/man/man1/ovs-pcap.1.gz
 /usr/share/man/man1/ovs-tcpundump.1.gz