Merge branch 'mainstream'
authorGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Thu, 10 Apr 2014 15:28:24 +0000 (17:28 +0200)
committerGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Thu, 10 Apr 2014 15:28:24 +0000 (17:28 +0200)
163 files changed:
AUTHORS
CONTRIBUTING [moved from SubmittingPatches with 100% similarity]
FAQ
Makefile.am
NEWS
OPENFLOW-1.1+
acinclude.m4
datapath/compat.h
datapath/datapath.c
datapath/datapath.h
datapath/dp_notify.c
datapath/flow.c
datapath/flow.h
datapath/flow_table.c
datapath/linux/compat/genetlink-openvswitch.c
datapath/linux/compat/include/linux/u64_stats_sync.h
datapath/linux/compat/include/net/genetlink.h
datapath/linux/compat/include/net/gre.h
datapath/linux/compat/include/net/ip.h
datapath/linux/compat/utils.c
datapath/vport-gre.c
datapath/vport-lisp.c
datapath/vport-vxlan.c
datapath/vport.c
debian/control
lib/bfd.c
lib/bundle.c
lib/cfm.c
lib/dpif-linux.c
lib/dpif-netdev.c
lib/dpif-netdev.h
lib/dpif.c
lib/flow.c
lib/flow.h
lib/json.c
lib/json.h
lib/jsonrpc.c
lib/lacp.c
lib/learn.c
lib/learning-switch.c
lib/lockfile.c
lib/match.c
lib/match.h
lib/netdev-bsd.c
lib/netdev-dpdk.c
lib/netdev-dummy.c
lib/netdev-linux.c
lib/netlink-socket.c
lib/netlink.c
lib/nx-match.c
lib/odp-execute.c
lib/odp-util.c
lib/ofp-actions.c
lib/ofp-errors.c
lib/ofp-msgs.c
lib/ofp-parse.c
lib/ofp-print.c
lib/ofp-util.c
lib/ofp-util.h
lib/ofpbuf.c
lib/ofpbuf.h
lib/ovsdb-data.c
lib/ovsdb-data.h
lib/packets.c
lib/packets.h
lib/pcap-file.c
lib/rconn.c
lib/route-table.c
lib/rtnetlink-link.c
lib/stp.c
lib/stream-ssl.c
lib/vconn-stream.c
lib/vconn.c
lib/vlandev.c
ofproto/bond.c
ofproto/bond.h
ofproto/connmgr.c
ofproto/connmgr.h
ofproto/fail-open.c
ofproto/in-band.c
ofproto/netflow.c
ofproto/ofproto-dpif-ipfix.c
ofproto/ofproto-dpif-sflow.c
ofproto/ofproto-dpif-upcall.c
ofproto/ofproto-dpif-xlate.c
ofproto/ofproto-dpif-xlate.h
ofproto/ofproto-dpif.c
ofproto/ofproto-dpif.h
ofproto/ofproto-provider.h
ofproto/ofproto.c
ofproto/ofproto.h
ofproto/tunnel.c
ovsdb/SPECS [deleted file]
ovsdb/automake.mk
ovsdb/jsonrpc-server.c
ovsdb/ovsdb-client.c
ovsdb/ovsdb-server.1.in
ovsdb/ovsdb-server.c
ovsdb/transaction.c
python/ovs/db/data.py
tests/.gitignore
tests/aes128.at
tests/automake.mk
tests/bundle.at
tests/classifier.at
tests/file_name.at
tests/json.at
tests/jsonrpc.at
tests/lacp.at
tests/learn.at
tests/library.at
tests/lockfile.at
tests/multipath.at
tests/odp.at
tests/ofproto-dpif.at
tests/ofproto.at
tests/ovsdb-monitor.at
tests/ovsdb-server.at
tests/ovsdb-tool.at
tests/ovstest.c
tests/ovstest.h
tests/reconnect.at
tests/stp.at
tests/test-aes128.c
tests/test-atomic.c
tests/test-bundle.c
tests/test-byte-order.c
tests/test-classifier.c
tests/test-csum.c
tests/test-file_name.c
tests/test-flows.c
tests/test-hash.c
tests/test-heap.c
tests/test-hindex.c
tests/test-hmap.c
tests/test-json.c
tests/test-jsonrpc.c
tests/test-list.c
tests/test-lockfile.c
tests/test-multipath.c
tests/test-netflow.c
tests/test-odp.c
tests/test-ovsdb.c
tests/test-packets.c
tests/test-random.c
tests/test-reconnect.c
tests/test-sflow.c
tests/test-sha1.c
tests/test-stp.c
tests/test-unix-socket.c
tests/test-util.c
tests/test-uuid.c
tests/test-vconn.c
tests/testsuite.at
tests/tunnel.at
tests/uuid.at
tests/vconn.at
utilities/ovs-dev.py
utilities/ovs-dpctl.c
utilities/ovs-ofctl.c
vswitchd/bridge.c
vtep/vtep-ctl.c
vtep/vtep.xml

diff --git a/AUTHORS b/AUTHORS
index 7c84c2b..78640b8 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -159,6 +159,7 @@ Brent Salisbury         brent.salisbury@gmail.com
 Bryan Fulton            bryan@nicira.com
 Bryan Osoro             bosoro@nicira.com
 Cedric Hobbs            cedric@nicira.com
+Chris Hydon             chydon@aristanetworks.com
 Christopher Paggen      cpaggen@cisco.com
 Dave Walker             DaveWalker@ubuntu.com
 David Palma             palma@onesource.pt
similarity index 100%
rename from SubmittingPatches
rename to CONTRIBUTING
diff --git a/FAQ b/FAQ
index eec2d4f..6b4be43 100644 (file)
--- a/FAQ
+++ b/FAQ
@@ -149,7 +149,7 @@ A: The following table lists the Linux kernel versions against which the
        1.11.x     2.6.18 to 3.8
        2.0.x      2.6.32 to 3.10
        2.1.x      2.6.32 to 3.11
-       2.2.x      2.6.32 to 3.12
+       2.2.x      2.6.32 to 3.13
 
    Open vSwitch userspace should also work with the Linux kernel module
    built into Linux 3.3 and later.
index a070ef4..382f420 100644 (file)
@@ -58,6 +58,7 @@ DISTCLEANFILES =
 PYCOV_CLEAN_FILES = build-aux/check-structs,cover
 EXTRA_DIST = \
        BUILD.Windows \
+       CONTRIBUTING \
        CodingStyle \
        DESIGN \
        FAQ \
@@ -78,7 +79,6 @@ EXTRA_DIST = \
        PORTING \
        README-lisp \
        REPORTING-BUGS \
-       SubmittingPatches \
        WHY-OVS \
        boot.sh \
        build-aux/cccl \
diff --git a/NEWS b/NEWS
index 4f88e3b..7925598 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,8 @@
 Post-v2.1.0
 ---------------------
+   - Internal ports are no longer brought up by default, because it
+     should be an administrator task to bring up devices as they are
+     configured properly.
    - ovs-vsctl now reports when ovs-vswitchd fails to create a new port or
      bridge.
    - The "ovsdbmonitor" graphical tool has been removed, because it was
@@ -10,8 +13,8 @@ Post-v2.1.0
    - Upon the receipt of a SIGHUP signal, ovs-vswitchd no longer reopens its
      log file (it will terminate instead). Please use 'ovs-appctl vlog/reopen'
      instead.
-   - Support for Linux kernels up to 3.12. On Kernel 3.12 OVS uses tunnel
-     API for GRE and VXLAN.
+   - Support for Linux kernels up to 3.13. From Kernel 3.12 onwards OVS uses
+     tunnel API for GRE and VXLAN.
    - Added DPDK support.
 
 
index 6fee77c..1789f17 100644 (file)
@@ -89,13 +89,6 @@ didn't compare the specs carefully yet.)
     * Add OFPMP_TABLE_FEATURES statistics.  Alexander Wu has posted a
       patch series.  [optional for OF1.3+]
 
-    * More flexible table miss support.
-      This requires the following.
-      - Change the default table-miss action (in the absense of table-miss
-        entry) from packet_in to drop for OF1.3+.  Decide what to do if
-        a switch is configured to support multiple OF versions.
-      [required for OF1.3+]
-
     * IPv6 extension header handling support.  Fully implementing this
       requires kernel support.  This likely will take some careful and
       probably time-consuming design work.  The actual coding, once
@@ -244,7 +237,7 @@ Please consider the following:
     * Coding style (see the CodingStyle file at the top of the source
       tree).
 
-    * The patch submission guidelines (see SubmittingPatches).  I
+    * The patch submission guidelines (see CONTRIBUTING).  I
       recommend using "git send-email", which automatically follows a
       lot of those guidelines.
 
index 1f52cf1..4269620 100644 (file)
@@ -134,10 +134,10 @@ AC_DEFUN([OVS_CHECK_LINUX], [
     AC_MSG_RESULT([$kversion])
 
     if test "$version" -ge 3; then
-       if test "$version" = 3 && test "$patchlevel" -le 12; then
+       if test "$version" = 3 && test "$patchlevel" -le 13; then
           : # Linux 3.x
        else
-         AC_ERROR([Linux kernel in $KBUILD is version $kversion, but version newer than 3.12.x is not supported])
+         AC_ERROR([Linux kernel in $KBUILD is version $kversion, but version newer than 3.13.x is not supported])
        fi
     else
        if test "$version" -le 1 || test "$patchlevel" -le 5 || test "$sublevel" -le 31; then
index bc7e880..f8f0469 100644 (file)
@@ -32,10 +32,10 @@ static inline void skb_clear_rxhash(struct sk_buff *skb)
 #endif
 }
 
-#ifdef HAVE_PARALLEL_OPS
-#define SET_PARALLEL_OPS       .parallel_ops = true,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,13,0)
+#define GROUP_ID(grp)  0
 #else
-#define SET_PARALLEL_OPS
+#define GROUP_ID(grp)  ((grp)->id)
 #endif
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
index 0c77045..25edd7d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2013 Nicira, Inc.
+ * Copyright (c) 2007-2014 Nicira, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 2 of the GNU General Public
 
 int ovs_net_id __read_mostly;
 
+static struct genl_family dp_packet_genl_family;
+static struct genl_family dp_flow_genl_family;
+static struct genl_family dp_datapath_genl_family;
+
+static struct genl_multicast_group ovs_dp_flow_multicast_group = {
+       .name = OVS_FLOW_MCGROUP
+};
+
+static struct genl_multicast_group ovs_dp_datapath_multicast_group = {
+       .name = OVS_DATAPATH_MCGROUP
+};
+
+struct genl_multicast_group ovs_dp_vport_multicast_group = {
+       .name = OVS_VPORT_MCGROUP
+};
+
 /* Check if need to build a reply message.
  * OVS userspace sets the NLM_F_ECHO flag if it needs the reply. */
 static bool ovs_must_notify(struct genl_info *info,
                            const struct genl_multicast_group *grp)
 {
        return info->nlhdr->nlmsg_flags & NLM_F_ECHO ||
-               netlink_has_listeners(genl_info_net(info)->genl_sock, grp->id);
+               netlink_has_listeners(genl_info_net(info)->genl_sock, GROUP_ID(grp));
 }
 
-static void ovs_notify(struct sk_buff *skb, struct genl_info *info,
-                      struct genl_multicast_group *grp)
+static void ovs_notify(struct genl_family *family, struct genl_multicast_group *grp,
+                      struct sk_buff *skb, struct genl_info *info)
 {
-       genl_notify(skb, genl_info_net(info), info->snd_portid,
-                   grp->id, info->nlhdr, GFP_KERNEL);
+       genl_notify(family, skb, genl_info_net(info),
+                   info->snd_portid, GROUP_ID(grp), info->nlhdr, GFP_KERNEL);
 }
 
 /**
@@ -262,7 +278,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb)
        OVS_CB(skb)->flow = flow;
        OVS_CB(skb)->pkt_key = &key;
 
-       ovs_flow_stats_update(OVS_CB(skb)->flow, skb);
+       ovs_flow_stats_update(OVS_CB(skb)->flow, key.tp.flags, skb);
        ovs_execute_actions(dp, skb);
        stats_counter = &stats->n_hit;
 
@@ -274,16 +290,6 @@ out:
        u64_stats_update_end(&stats->sync);
 }
 
-static struct genl_family dp_packet_genl_family = {
-       .id = GENL_ID_GENERATE,
-       .hdrsize = sizeof(struct ovs_header),
-       .name = OVS_PACKET_FAMILY,
-       .version = OVS_PACKET_VERSION,
-       .maxattr = OVS_PACKET_ATTR_MAX,
-       .netnsok = true,
-        SET_PARALLEL_OPS
-};
-
 int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb,
                  const struct dp_upcall_info *upcall_info)
 {
@@ -601,6 +607,18 @@ static struct genl_ops dp_packet_genl_ops[] = {
        }
 };
 
+static struct genl_family dp_packet_genl_family = {
+       .id = GENL_ID_GENERATE,
+       .hdrsize = sizeof(struct ovs_header),
+       .name = OVS_PACKET_FAMILY,
+       .version = OVS_PACKET_VERSION,
+       .maxattr = OVS_PACKET_ATTR_MAX,
+       .netnsok = true,
+       .parallel_ops = true,
+       .ops = dp_packet_genl_ops,
+       .n_ops = ARRAY_SIZE(dp_packet_genl_ops),
+};
+
 static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats,
                         struct ovs_dp_megaflow_stats *mega_stats)
 {
@@ -632,26 +650,6 @@ static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats,
        }
 }
 
-static const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = {
-       [OVS_FLOW_ATTR_KEY] = { .type = NLA_NESTED },
-       [OVS_FLOW_ATTR_ACTIONS] = { .type = NLA_NESTED },
-       [OVS_FLOW_ATTR_CLEAR] = { .type = NLA_FLAG },
-};
-
-static struct genl_family dp_flow_genl_family = {
-       .id = GENL_ID_GENERATE,
-       .hdrsize = sizeof(struct ovs_header),
-       .name = OVS_FLOW_FAMILY,
-       .version = OVS_FLOW_VERSION,
-       .maxattr = OVS_FLOW_ATTR_MAX,
-       .netnsok = true,
-        SET_PARALLEL_OPS
-};
-
-static struct genl_multicast_group ovs_dp_flow_multicast_group = {
-       .name = OVS_FLOW_MCGROUP
-};
-
 static size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts)
 {
        return NLMSG_ALIGN(sizeof(struct ovs_header))
@@ -664,7 +662,7 @@ static size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts)
 }
 
 /* Called with ovs_mutex or RCU read lock. */
-static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
+static int ovs_flow_cmd_fill_info(const struct sw_flow *flow, int dp_ifindex,
                                  struct sk_buff *skb, u32 portid,
                                  u32 seq, u32 flags, u8 cmd)
 {
@@ -681,7 +679,7 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
        if (!ovs_header)
                return -EMSGSIZE;
 
-       ovs_header->dp_ifindex = get_dpifindex(dp);
+       ovs_header->dp_ifindex = dp_ifindex;
 
        /* Fill flow key. */
        nla = nla_nest_start(skb, OVS_FLOW_ATTR_KEY);
@@ -704,6 +702,7 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
        nla_nest_end(skb, nla);
 
        ovs_flow_stats_get(flow, &stats, &used, &tcp_flags);
+
        if (used &&
            nla_put_u64(skb, OVS_FLOW_ATTR_USED, ovs_flow_used_time(used)))
                goto nla_put_failure;
@@ -731,9 +730,9 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
                const struct sw_flow_actions *sf_acts;
 
                sf_acts = rcu_dereference_ovsl(flow->sf_acts);
-
                err = ovs_nla_put_actions(sf_acts->actions,
                                          sf_acts->actions_len, skb);
+
                if (!err)
                        nla_nest_end(skb, start);
                else {
@@ -754,20 +753,17 @@ error:
        return err;
 }
 
-/* Must be called with ovs_mutex. */
-static struct sk_buff *ovs_flow_cmd_alloc_info(struct sw_flow *flow,
+/* May not be called with RCU read lock. */
+static struct sk_buff *ovs_flow_cmd_alloc_info(const struct sw_flow_actions *acts,
                                               struct genl_info *info,
                                               bool always)
 {
        struct sk_buff *skb;
-       size_t len;
 
        if (!always && !ovs_must_notify(info, &ovs_dp_flow_multicast_group))
                return NULL;
 
-       len = ovs_flow_cmd_msg_size(ovsl_dereference(flow->sf_acts));
-
-       skb = genlmsg_new_unicast(len, info, GFP_KERNEL);
+       skb = genlmsg_new_unicast(ovs_flow_cmd_msg_size(acts), info, GFP_KERNEL);
 
        if (!skb)
                return ERR_PTR(-ENOMEM);
@@ -775,35 +771,171 @@ static struct sk_buff *ovs_flow_cmd_alloc_info(struct sw_flow *flow,
        return skb;
 }
 
-/* Must be called with ovs_mutex. */
-static struct sk_buff *ovs_flow_cmd_build_info(struct sw_flow *flow,
-                                              struct datapath *dp,
-                                              struct genl_info *info,
-                                              u8 cmd, bool always)
+/* Called with ovs_mutex. */
+static struct sk_buff *ovs_flow_cmd_build_info(const struct sw_flow *flow,
+                                              int dp_ifindex,
+                                              struct genl_info *info, u8 cmd,
+                                              bool always)
 {
        struct sk_buff *skb;
        int retval;
 
-       skb = ovs_flow_cmd_alloc_info(flow, info, always);
+       skb = ovs_flow_cmd_alloc_info(ovsl_dereference(flow->sf_acts), info,
+                                     always);
        if (!skb || IS_ERR(skb))
                return skb;
 
-       retval = ovs_flow_cmd_fill_info(flow, dp, skb, info->snd_portid,
-                                       info->snd_seq, 0, cmd);
+       retval = ovs_flow_cmd_fill_info(flow, dp_ifindex, skb,
+                                       info->snd_portid, info->snd_seq, 0,
+                                       cmd);
        BUG_ON(retval < 0);
        return skb;
 }
 
-static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
+static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
 {
        struct nlattr **a = info->attrs;
        struct ovs_header *ovs_header = info->userhdr;
-       struct sw_flow_key key, masked_key;
-       struct sw_flow *flow = NULL;
+       struct sw_flow *flow, *new_flow;
        struct sw_flow_mask mask;
        struct sk_buff *reply;
        struct datapath *dp;
-       struct sw_flow_actions *acts = NULL;
+       struct sw_flow_actions *acts;
+       struct sw_flow_match match;
+       int error;
+
+       /* Must have key and actions. */
+       error = -EINVAL;
+       if (!a[OVS_FLOW_ATTR_KEY])
+               goto error;
+       if (!a[OVS_FLOW_ATTR_ACTIONS])
+               goto error;
+
+       /* Most of the time we need to allocate a new flow, do it before
+        * locking. */
+       new_flow = ovs_flow_alloc();
+       if (IS_ERR(new_flow)) {
+               error = PTR_ERR(new_flow);
+               goto error;
+       }
+
+       /* Extract key. */
+       ovs_match_init(&match, &new_flow->unmasked_key, &mask);
+       error = ovs_nla_get_match(&match,
+                                 a[OVS_FLOW_ATTR_KEY], a[OVS_FLOW_ATTR_MASK]);
+       if (error)
+               goto err_kfree_flow;
+
+       ovs_flow_mask_key(&new_flow->key, &new_flow->unmasked_key, &mask);
+
+       /* Validate actions. */
+       acts = ovs_nla_alloc_flow_actions(nla_len(a[OVS_FLOW_ATTR_ACTIONS]));
+       error = PTR_ERR(acts);
+       if (IS_ERR(acts))
+               goto err_kfree_flow;
+
+       error = ovs_nla_copy_actions(a[OVS_FLOW_ATTR_ACTIONS], &new_flow->key,
+                                    0, &acts);
+       if (error) {
+               OVS_NLERR("Flow actions may not be safe on all matching packets.\n");
+               goto err_kfree_acts;
+       }
+
+       reply = ovs_flow_cmd_alloc_info(acts, info, false);
+       if (IS_ERR(reply)) {
+               error = PTR_ERR(reply);
+               goto err_kfree_acts;
+       }
+
+       ovs_lock();
+       dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
+       if (unlikely(!dp)) {
+               error = -ENODEV;
+               goto err_unlock_ovs;
+       }
+       /* Check if this is a duplicate flow */
+       flow = ovs_flow_tbl_lookup(&dp->table, &new_flow->unmasked_key);
+       if (likely(!flow)) {
+               rcu_assign_pointer(new_flow->sf_acts, acts);
+
+               /* Put flow in bucket. */
+               error = ovs_flow_tbl_insert(&dp->table, new_flow, &mask);
+               if (unlikely(error)) {
+                       acts = NULL;
+                       goto err_unlock_ovs;
+               }
+
+               if (unlikely(reply)) {
+                       error = ovs_flow_cmd_fill_info(new_flow,
+                                                      ovs_header->dp_ifindex,
+                                                      reply, info->snd_portid,
+                                                      info->snd_seq, 0,
+                                                      OVS_FLOW_CMD_NEW);
+                       BUG_ON(error < 0);
+               }
+               ovs_unlock();
+       } else {
+               struct sw_flow_actions *old_acts;
+
+               /* Bail out if we're not allowed to modify an existing flow.
+                * We accept NLM_F_CREATE in place of the intended NLM_F_EXCL
+                * because Generic Netlink treats the latter as a dump
+                * request.  We also accept NLM_F_EXCL in case that bug ever
+                * gets fixed.
+                */
+               if (unlikely(info->nlhdr->nlmsg_flags & (NLM_F_CREATE
+                                                        | NLM_F_EXCL))) {
+                       error = -EEXIST;
+                       goto err_unlock_ovs;
+               }
+               /* The unmasked key has to be the same for flow updates. */
+               if (unlikely(!ovs_flow_cmp_unmasked_key(flow, &match))) {
+                       error = -EEXIST;
+                       goto err_unlock_ovs;
+               }
+               /* Update actions. */
+               old_acts = ovsl_dereference(flow->sf_acts);
+               rcu_assign_pointer(flow->sf_acts, acts);
+
+               if (unlikely(reply)) {
+                       error = ovs_flow_cmd_fill_info(flow,
+                                                      ovs_header->dp_ifindex,
+                                                      reply, info->snd_portid,
+                                                      info->snd_seq, 0,
+                                                      OVS_FLOW_CMD_NEW);
+                       BUG_ON(error < 0);
+               }
+               ovs_unlock();
+
+               ovs_nla_free_flow_actions(old_acts);
+               ovs_flow_free(new_flow, false);
+       }
+
+       if (reply)
+               ovs_notify(&dp_flow_genl_family, &ovs_dp_flow_multicast_group, reply, info);
+       return 0;
+
+err_unlock_ovs:
+       ovs_unlock();
+       kfree_skb(reply);
+err_kfree_acts:
+       kfree(acts);
+err_kfree_flow:
+       ovs_flow_free(new_flow, false);
+error:
+       return error;
+}
+
+static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
+{
+       struct nlattr **a = info->attrs;
+       struct ovs_header *ovs_header = info->userhdr;
+       struct sw_flow_key key, masked_key;
+       struct sw_flow *flow;
+       struct sw_flow_mask mask;
+       struct sk_buff *reply = NULL;
+       struct datapath *dp;
+       struct sw_flow_actions *old_acts = NULL, *acts = NULL;
        struct sw_flow_match match;
        int error;
 
@@ -830,97 +962,74 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
                                             &masked_key, 0, &acts);
                if (error) {
                        OVS_NLERR("Flow actions may not be safe on all matching packets.\n");
-                       goto err_kfree;
+                       goto err_kfree_acts;
+               }
+       }
+
+       /* Can allocate before locking if have acts. */
+       if (acts) {
+               reply = ovs_flow_cmd_alloc_info(acts, info, false);
+               if (IS_ERR(reply)) {
+                       error = PTR_ERR(reply);
+                       goto err_kfree_acts;
                }
-       } else if (info->genlhdr->cmd == OVS_FLOW_CMD_NEW) {
-               /* OVS_FLOW_CMD_NEW must have actions. */
-               error = -EINVAL;
-               goto error;
        }
 
        ovs_lock();
        dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
-       error = -ENODEV;
-       if (!dp)
+       if (unlikely(!dp)) {
+               error = -ENODEV;
                goto err_unlock_ovs;
-
-       /* Check if this is a duplicate flow */
+       }
+       /* Check that the flow exists. */
        flow = ovs_flow_tbl_lookup(&dp->table, &key);
-       if (!flow) {
-               /* Bail out if we're not allowed to create a new flow. */
+       if (unlikely(!flow)) {
                error = -ENOENT;
-               if (info->genlhdr->cmd == OVS_FLOW_CMD_SET)
-                       goto err_unlock_ovs;
-
-               /* Allocate flow. */
-               flow = ovs_flow_alloc();
-               if (IS_ERR(flow)) {
-                       error = PTR_ERR(flow);
-                       goto err_unlock_ovs;
-               }
-
-               flow->key = masked_key;
-               flow->unmasked_key = key;
+               goto err_unlock_ovs;
+       }
+       /* The unmasked key has to be the same for flow updates. */
+       if (unlikely(!ovs_flow_cmp_unmasked_key(flow, &match))) {
+               error = -EEXIST;
+               goto err_unlock_ovs;
+       }
+       /* Update actions, if present. */
+       if (likely(acts)) {
+               old_acts = ovsl_dereference(flow->sf_acts);
                rcu_assign_pointer(flow->sf_acts, acts);
 
-               /* Put flow in bucket. */
-               error = ovs_flow_tbl_insert(&dp->table, flow, &mask);
-               if (error) {
-                       acts = NULL;
-                       goto err_flow_free;
+               if (unlikely(reply)) {
+                       error = ovs_flow_cmd_fill_info(flow,
+                                                      ovs_header->dp_ifindex,
+                                                      reply, info->snd_portid,
+                                                      info->snd_seq, 0,
+                                                      OVS_FLOW_CMD_NEW);
+                       BUG_ON(error < 0);
                }
-
-               reply = ovs_flow_cmd_build_info(flow, dp, info,
-                                               OVS_FLOW_CMD_NEW, false);
        } else {
-               /* We found a matching flow. */
-               /* Bail out if we're not allowed to modify an existing flow.
-                * We accept NLM_F_CREATE in place of the intended NLM_F_EXCL
-                * because Generic Netlink treats the latter as a dump
-                * request.  We also accept NLM_F_EXCL in case that bug ever
-                * gets fixed.
-                */
-               error = -EEXIST;
-               if (info->genlhdr->cmd == OVS_FLOW_CMD_NEW &&
-                   info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL))
-                       goto err_unlock_ovs;
-
-               /* The unmasked key has to be the same for flow updates. */
-               if (!ovs_flow_cmp_unmasked_key(flow, &match))
+               /* Could not alloc without acts before locking. */
+               reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex,
+                                               info, OVS_FLOW_CMD_NEW, false);
+               if (unlikely(IS_ERR(reply))) {
+                       error = PTR_ERR(reply);
                        goto err_unlock_ovs;
-
-               /* Update actions, if present. */
-               if (acts) {
-                       struct sw_flow_actions *old_acts;
-
-                       old_acts = ovsl_dereference(flow->sf_acts);
-                       rcu_assign_pointer(flow->sf_acts, acts);
-                       ovs_nla_free_flow_actions(old_acts);
                }
-               reply = ovs_flow_cmd_build_info(flow, dp, info,
-                                               OVS_FLOW_CMD_NEW, false);
-
-               /* Clear stats. */
-               if (a[OVS_FLOW_ATTR_CLEAR])
-                       ovs_flow_stats_clear(flow);
        }
+
+       /* Clear stats. */
+       if (a[OVS_FLOW_ATTR_CLEAR])
+               ovs_flow_stats_clear(flow);
        ovs_unlock();
 
-       if (reply) {
-               if (!IS_ERR(reply))
-                       ovs_notify(reply, info, &ovs_dp_flow_multicast_group);
-               else
-                       netlink_set_err(sock_net(skb->sk)->genl_sock, 0,
-                                       ovs_dp_flow_multicast_group.id,
-                                       PTR_ERR(reply));
-       }
+       if (reply)
+               ovs_notify(&dp_flow_genl_family, &ovs_dp_flow_multicast_group, reply, info);
+       if (old_acts)
+               ovs_nla_free_flow_actions(old_acts);
        return 0;
 
-err_flow_free:
-       ovs_flow_free(flow, false);
 err_unlock_ovs:
        ovs_unlock();
-err_kfree:
+       kfree_skb(reply);
+err_kfree_acts:
        kfree(acts);
 error:
        return error;
@@ -960,7 +1069,8 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
                goto unlock;
        }
 
-       reply = ovs_flow_cmd_build_info(flow, dp, info, OVS_FLOW_CMD_NEW, true);
+       reply = ovs_flow_cmd_build_info(flow, ovs_header->dp_ifindex, info,
+                                       OVS_FLOW_CMD_NEW, true);
        if (IS_ERR(reply)) {
                err = PTR_ERR(reply);
                goto unlock;
@@ -984,49 +1094,54 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
        struct sw_flow_match match;
        int err;
 
+       if (likely(a[OVS_FLOW_ATTR_KEY])) {
+               ovs_match_init(&match, &key, NULL);
+               err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL);
+               if (unlikely(err))
+                       return err;
+       }
+
        ovs_lock();
        dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
-       if (!dp) {
+       if (unlikely(!dp)) {
                err = -ENODEV;
                goto unlock;
        }
-
-       if (!a[OVS_FLOW_ATTR_KEY]) {
+       if (unlikely(!a[OVS_FLOW_ATTR_KEY])) {
                err = ovs_flow_tbl_flush(&dp->table);
                goto unlock;
        }
-
-       ovs_match_init(&match, &key, NULL);
-       err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL);
-       if (err)
-               goto unlock;
-
        flow = ovs_flow_tbl_lookup(&dp->table, &key);
-       if (!flow || !ovs_flow_cmp_unmasked_key(flow, &match)) {
+       if (unlikely(!flow || !ovs_flow_cmp_unmasked_key(flow, &match))) {
                err = -ENOENT;
                goto unlock;
        }
 
-       reply = ovs_flow_cmd_alloc_info(flow, info, false);
-       if (IS_ERR(reply)) {
-               err = PTR_ERR(reply);
-               goto unlock;
-       }
-
        ovs_flow_tbl_remove(&dp->table, flow);
+       ovs_unlock();
 
-       if (reply) {
-               err = ovs_flow_cmd_fill_info(flow, dp, reply, info->snd_portid,
-                                            info->snd_seq, 0,
-                                            OVS_FLOW_CMD_DEL);
-               BUG_ON(err < 0);
+       reply = ovs_flow_cmd_alloc_info((const struct sw_flow_actions __force *)flow->sf_acts,
+                                       info, false);
+
+       if (likely(reply)) {
+               if (likely(!IS_ERR(reply))) {
+                       rcu_read_lock(); /* Keep RCU checker happy. */
+                       err = ovs_flow_cmd_fill_info(flow,
+                                                    ovs_header->dp_ifindex,
+                                                    reply, info->snd_portid,
+                                                    info->snd_seq, 0,
+                                                    OVS_FLOW_CMD_DEL);
+                       rcu_read_unlock();
+                       BUG_ON(err < 0);
+                       ovs_notify(&dp_flow_genl_family, &ovs_dp_flow_multicast_group, reply, info);
+               } else {
+                       genl_set_err(&dp_flow_genl_family, sock_net(skb->sk), 0,
+                                    GROUP_ID(&ovs_dp_flow_multicast_group), PTR_ERR(reply));
+
+               }
        }
 
        ovs_flow_free(flow, true);
-       ovs_unlock();
-
-       if (reply)
-               ovs_notify(reply, info, &ovs_dp_flow_multicast_group);
        return 0;
 unlock:
        ovs_unlock();
@@ -1057,7 +1172,7 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
                if (!flow)
                        break;
 
-               if (ovs_flow_cmd_fill_info(flow, dp, skb,
+               if (ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex, skb,
                                           NETLINK_CB(cb->skb).portid,
                                           cb->nlh->nlmsg_seq, NLM_F_MULTI,
                                           OVS_FLOW_CMD_NEW) < 0)
@@ -1070,11 +1185,17 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
        return skb->len;
 }
 
+static const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = {
+       [OVS_FLOW_ATTR_KEY] = { .type = NLA_NESTED },
+       [OVS_FLOW_ATTR_ACTIONS] = { .type = NLA_NESTED },
+       [OVS_FLOW_ATTR_CLEAR] = { .type = NLA_FLAG },
+};
+
 static struct genl_ops dp_flow_genl_ops[] = {
        { .cmd = OVS_FLOW_CMD_NEW,
          .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
          .policy = flow_policy,
-         .doit = ovs_flow_cmd_new_or_set
+         .doit = ovs_flow_cmd_new
        },
        { .cmd = OVS_FLOW_CMD_DEL,
          .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
@@ -1090,28 +1211,22 @@ static struct genl_ops dp_flow_genl_ops[] = {
        { .cmd = OVS_FLOW_CMD_SET,
          .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
          .policy = flow_policy,
-         .doit = ovs_flow_cmd_new_or_set,
+         .doit = ovs_flow_cmd_set,
        },
 };
 
-static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = {
-       [OVS_DP_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
-       [OVS_DP_ATTR_UPCALL_PID] = { .type = NLA_U32 },
-       [OVS_DP_ATTR_USER_FEATURES] = { .type = NLA_U32 },
-};
-
-static struct genl_family dp_datapath_genl_family = {
+static struct genl_family dp_flow_genl_family = {
        .id = GENL_ID_GENERATE,
        .hdrsize = sizeof(struct ovs_header),
-       .name = OVS_DATAPATH_FAMILY,
-       .version = OVS_DATAPATH_VERSION,
-       .maxattr = OVS_DP_ATTR_MAX,
+       .name = OVS_FLOW_FAMILY,
+       .version = OVS_FLOW_VERSION,
+       .maxattr = OVS_FLOW_ATTR_MAX,
        .netnsok = true,
-        SET_PARALLEL_OPS
-};
-
-static struct genl_multicast_group ovs_dp_datapath_multicast_group = {
-       .name = OVS_DATAPATH_MCGROUP
+       .parallel_ops = true,
+       .ops = dp_flow_genl_ops,
+       .n_ops = ARRAY_SIZE(dp_flow_genl_ops),
+       .mcgrps = &ovs_dp_flow_multicast_group,
+       .n_mcgrps = 1,
 };
 
 static size_t ovs_dp_cmd_msg_size(void)
@@ -1244,6 +1359,12 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
                goto err_destroy_table;
        }
 
+       for_each_possible_cpu(i) {
+               struct dp_stats_percpu *dpath_stats;
+               dpath_stats = per_cpu_ptr(dp->stats_percpu, i);
+               u64_stats_init(&dpath_stats->sync);
+       }
+
        dp->ports = kmalloc(DP_VPORT_HASH_BUCKETS * sizeof(struct hlist_head),
                            GFP_KERNEL);
        if (!dp->ports) {
@@ -1294,7 +1415,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
 
        ovs_unlock();
 
-       ovs_notify(reply, info, &ovs_dp_datapath_multicast_group);
+       ovs_notify(&dp_datapath_genl_family, &ovs_dp_datapath_multicast_group, reply, info);
        return 0;
 
 err_destroy_ports_array:
@@ -1363,7 +1484,7 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info)
        __dp_destroy(dp);
 
        ovs_unlock();
-       ovs_notify(reply, info, &ovs_dp_datapath_multicast_group);
+       ovs_notify(&dp_datapath_genl_family, &ovs_dp_datapath_multicast_group, reply, info);
        return 0;
 
 err_unlock_free:
@@ -1395,7 +1516,7 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
        BUG_ON(err < 0);
 
        ovs_unlock();
-       ovs_notify(reply, info, &ovs_dp_datapath_multicast_group);
+       ovs_notify(&dp_datapath_genl_family, &ovs_dp_datapath_multicast_group, reply, info);
        return 0;
 
 err_unlock_free:
@@ -1456,6 +1577,12 @@ static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
        return skb->len;
 }
 
+static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = {
+       [OVS_DP_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
+       [OVS_DP_ATTR_UPCALL_PID] = { .type = NLA_U32 },
+       [OVS_DP_ATTR_USER_FEATURES] = { .type = NLA_U32 },
+};
+
 static struct genl_ops dp_datapath_genl_ops[] = {
        { .cmd = OVS_DP_CMD_NEW,
          .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
@@ -1480,27 +1607,18 @@ static struct genl_ops dp_datapath_genl_ops[] = {
        },
 };
 
-static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = {
-       [OVS_VPORT_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
-       [OVS_VPORT_ATTR_STATS] = { .len = sizeof(struct ovs_vport_stats) },
-       [OVS_VPORT_ATTR_PORT_NO] = { .type = NLA_U32 },
-       [OVS_VPORT_ATTR_TYPE] = { .type = NLA_U32 },
-       [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NLA_U32 },
-       [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED },
-};
-
-static struct genl_family dp_vport_genl_family = {
+static struct genl_family dp_datapath_genl_family = {
        .id = GENL_ID_GENERATE,
        .hdrsize = sizeof(struct ovs_header),
-       .name = OVS_VPORT_FAMILY,
-       .version = OVS_VPORT_VERSION,
-       .maxattr = OVS_VPORT_ATTR_MAX,
+       .name = OVS_DATAPATH_FAMILY,
+       .version = OVS_DATAPATH_VERSION,
+       .maxattr = OVS_DP_ATTR_MAX,
        .netnsok = true,
-        SET_PARALLEL_OPS
-};
-
-struct genl_multicast_group ovs_dp_vport_multicast_group = {
-       .name = OVS_VPORT_MCGROUP
+       .parallel_ops = true,
+       .ops = dp_datapath_genl_ops,
+       .n_ops = ARRAY_SIZE(dp_datapath_genl_ops),
+       .mcgrps = &ovs_dp_datapath_multicast_group,
+       .n_mcgrps = 1,
 };
 
 /* Called with ovs_mutex or RCU read lock. */
@@ -1666,7 +1784,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
        BUG_ON(err < 0);
        ovs_unlock();
 
-       ovs_notify(reply, info, &ovs_dp_vport_multicast_group);
+       ovs_notify(&dp_vport_genl_family, &ovs_dp_vport_multicast_group, reply, info);
        return 0;
 
 exit_unlock_free:
@@ -1715,7 +1833,7 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
        BUG_ON(err < 0);
        ovs_unlock();
 
-       ovs_notify(reply, info, &ovs_dp_vport_multicast_group);
+       ovs_notify(&dp_vport_genl_family, &ovs_dp_vport_multicast_group, reply, info);
        return 0;
 
 exit_unlock_free:
@@ -1752,7 +1870,7 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
        ovs_dp_detach_port(vport);
        ovs_unlock();
 
-       ovs_notify(reply, info, &ovs_dp_vport_multicast_group);
+       ovs_notify(&dp_vport_genl_family, &ovs_dp_vport_multicast_group, reply, info);
        return 0;
 
 exit_unlock_free:
@@ -1830,6 +1948,15 @@ out:
        return skb->len;
 }
 
+static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = {
+       [OVS_VPORT_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
+       [OVS_VPORT_ATTR_STATS] = { .len = sizeof(struct ovs_vport_stats) },
+       [OVS_VPORT_ATTR_PORT_NO] = { .type = NLA_U32 },
+       [OVS_VPORT_ATTR_TYPE] = { .type = NLA_U32 },
+       [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NLA_U32 },
+       [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED },
+};
+
 static struct genl_ops dp_vport_genl_ops[] = {
        { .cmd = OVS_VPORT_CMD_NEW,
          .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
@@ -1854,26 +1981,25 @@ static struct genl_ops dp_vport_genl_ops[] = {
        },
 };
 
-struct genl_family_and_ops {
-       struct genl_family *family;
-       struct genl_ops *ops;
-       int n_ops;
-       struct genl_multicast_group *group;
+struct genl_family dp_vport_genl_family = {
+       .id = GENL_ID_GENERATE,
+       .hdrsize = sizeof(struct ovs_header),
+       .name = OVS_VPORT_FAMILY,
+       .version = OVS_VPORT_VERSION,
+       .maxattr = OVS_VPORT_ATTR_MAX,
+       .netnsok = true,
+       .parallel_ops = true,
+       .ops = dp_vport_genl_ops,
+       .n_ops = ARRAY_SIZE(dp_vport_genl_ops),
+       .mcgrps = &ovs_dp_vport_multicast_group,
+       .n_mcgrps = 1,
 };
 
-static const struct genl_family_and_ops dp_genl_families[] = {
-       { &dp_datapath_genl_family,
-         dp_datapath_genl_ops, ARRAY_SIZE(dp_datapath_genl_ops),
-         &ovs_dp_datapath_multicast_group },
-       { &dp_vport_genl_family,
-         dp_vport_genl_ops, ARRAY_SIZE(dp_vport_genl_ops),
-         &ovs_dp_vport_multicast_group },
-       { &dp_flow_genl_family,
-         dp_flow_genl_ops, ARRAY_SIZE(dp_flow_genl_ops),
-         &ovs_dp_flow_multicast_group },
-       { &dp_packet_genl_family,
-         dp_packet_genl_ops, ARRAY_SIZE(dp_packet_genl_ops),
-         NULL },
+static struct genl_family *dp_genl_families[] = {
+       &dp_datapath_genl_family,
+       &dp_vport_genl_family,
+       &dp_flow_genl_family,
+       &dp_packet_genl_family,
 };
 
 static void dp_unregister_genl(int n_families)
@@ -1881,36 +2007,25 @@ static void dp_unregister_genl(int n_families)
        int i;
 
        for (i = 0; i < n_families; i++)
-               genl_unregister_family(dp_genl_families[i].family);
+               genl_unregister_family(dp_genl_families[i]);
 }
 
 static int dp_register_genl(void)
 {
-       int n_registered;
        int err;
        int i;
 
-       n_registered = 0;
        for (i = 0; i < ARRAY_SIZE(dp_genl_families); i++) {
-               const struct genl_family_and_ops *f = &dp_genl_families[i];
 
-               err = genl_register_family_with_ops(f->family, f->ops,
-                                                   f->n_ops);
+               err = genl_register_family(dp_genl_families[i]);
                if (err)
                        goto error;
-               n_registered++;
-
-               if (f->group) {
-                       err = genl_register_mc_group(f->family, f->group);
-                       if (err)
-                               goto error;
-               }
        }
 
        return 0;
 
 error:
-       dp_unregister_genl(n_registered);
+       dp_unregister_genl(i);
        return err;
 }
 
index d81e05c..40e0f90 100644 (file)
@@ -184,6 +184,7 @@ static inline struct vport *ovs_vport_ovsl(const struct datapath *dp, int port_n
 }
 
 extern struct notifier_block ovs_dp_device_notifier;
+extern struct genl_family dp_vport_genl_family;
 extern struct genl_multicast_group ovs_dp_vport_multicast_group;
 
 void ovs_dp_process_received_packet(struct vport *, struct sk_buff *);
index 0b22d0c..f9a0375 100644 (file)
@@ -31,18 +31,18 @@ static void dp_detach_port_notify(struct vport *vport)
        struct datapath *dp;
 
        dp = vport->dp;
-       notify = ovs_vport_cmd_build_info(vport, 0, 0,
-                                         OVS_VPORT_CMD_DEL);
+       notify = ovs_vport_cmd_build_info(vport, 0, 0, OVS_VPORT_CMD_DEL);
        ovs_dp_detach_port(vport);
        if (IS_ERR(notify)) {
-               netlink_set_err(ovs_dp_get_net(dp)->genl_sock, 0,
-                               ovs_dp_vport_multicast_group.id,
-                               PTR_ERR(notify));
+               genl_set_err(&dp_vport_genl_family, ovs_dp_get_net(dp), 0,
+                            GROUP_ID(&ovs_dp_vport_multicast_group),
+                            PTR_ERR(notify));
                return;
        }
 
-       genlmsg_multicast_netns(ovs_dp_get_net(dp), notify, 0,
-                               ovs_dp_vport_multicast_group.id,
+       genlmsg_multicast_netns(&dp_vport_genl_family,
+                               ovs_dp_get_net(dp), notify, 0,
+                               GROUP_ID(&ovs_dp_vport_multicast_group),
                                GFP_KERNEL);
 }
 
index 5d1d2f2..c52081b 100644 (file)
@@ -62,10 +62,10 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies)
 
 #define TCP_FLAGS_BE16(tp) (*(__be16 *)&tcp_flag_word(tp) & htons(0x0FFF))
 
-void ovs_flow_stats_update(struct sw_flow *flow, struct sk_buff *skb)
+void ovs_flow_stats_update(struct sw_flow *flow, __be16 tcp_flags,
+                          struct sk_buff *skb)
 {
        struct flow_stats *stats;
-       __be16 tcp_flags = flow->key.tp.flags;
        int node = numa_node_id();
 
        stats = rcu_dereference(flow->stats[node]);
@@ -123,8 +123,9 @@ unlock:
        spin_unlock(&stats->lock);
 }
 
-/* Called with ovs_mutex. */
-void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *ovs_stats,
+/* Must be called with rcu_read_lock or ovs_mutex. */
+void ovs_flow_stats_get(const struct sw_flow *flow,
+                       struct ovs_flow_stats *ovs_stats,
                        unsigned long *used, __be16 *tcp_flags)
 {
        int node;
@@ -134,7 +135,7 @@ void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *ovs_stats,
        memset(ovs_stats, 0, sizeof(*ovs_stats));
 
        for_each_node(node) {
-               struct flow_stats *stats = ovsl_dereference(flow->stats[node]);
+               struct flow_stats *stats = rcu_dereference_ovsl(flow->stats[node]);
 
                if (stats) {
                        /* Local CPU may write on non-local stats, so we must
@@ -151,12 +152,13 @@ void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *ovs_stats,
        }
 }
 
+/* Called with ovs_mutex. */
 void ovs_flow_stats_clear(struct sw_flow *flow)
 {
        int node;
 
        for_each_node(node) {
-               struct flow_stats *stats = rcu_dereference(flow->stats[node]);
+               struct flow_stats *stats = ovsl_dereference(flow->stats[node]);
 
                if (stats) {
                        spin_lock_bh(&stats->lock);
index 5587577..1bb6ce0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2013 Nicira, Inc.
+ * Copyright (c) 2007-2014 Nicira, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 2 of the GNU General Public
@@ -182,10 +182,11 @@ struct arp_eth_header {
        unsigned char       ar_tip[4];          /* target IP address        */
 } __packed;
 
-void ovs_flow_stats_update(struct sw_flow *flow, struct sk_buff *skb);
-void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *stats,
+void ovs_flow_stats_update(struct sw_flow *, __be16 tcp_flags,
+                          struct sk_buff *);
+void ovs_flow_stats_get(const struct sw_flow *, struct ovs_flow_stats *,
                        unsigned long *used, __be16 *tcp_flags);
-void ovs_flow_stats_clear(struct sw_flow *flow);
+void ovs_flow_stats_clear(struct sw_flow *);
 u64 ovs_flow_used_time(unsigned long flow_jiffies);
 
 int ovs_flow_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *);
index a680895..159572b 100644 (file)
@@ -141,7 +141,7 @@ static void flow_free(struct sw_flow *flow)
 {
        int node;
 
-       kfree((struct sf_flow_acts __force *)flow->sf_acts);
+       kfree((struct sw_flow_actions __force *)flow->sf_acts);
        for_each_node(node)
                if (flow->stats[node])
                        kmem_cache_free(flow_stats_cache,
index 359f916..08f0fab 100644 (file)
@@ -1,12 +1,15 @@
 #include <net/genetlink.h>
 #include <linux/version.h>
 
-/* This is analogous to rtnl_notify() but uses genl_sock instead of rtnl.
- *
- * This is not (yet) in any upstream kernel. */
-void genl_notify(struct sk_buff *skb, struct net *net, u32 portid, u32 group,
-                struct nlmsghdr *nlh, gfp_t flags)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0)
+
+#undef genl_notify
+
+void rpl_genl_notify(struct rpl_genl_family *family, struct sk_buff *skb,
+                    struct net *net, u32 portid, u32 group,
+                    struct nlmsghdr *nlh, gfp_t flags)
 {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0)
        struct sock *sk = net->genl_sock;
        int report = 0;
 
@@ -14,4 +17,39 @@ void genl_notify(struct sk_buff *skb, struct net *net, u32 portid, u32 group,
                report = nlmsg_report(nlh);
 
        nlmsg_notify(sk, skb, portid, group, report, flags);
+#else
+       genl_notify(skb, net, portid, group, nlh, flags);
+#endif
+}
+
+int rpl___genl_register_family(struct rpl_genl_family *f)
+{
+       int err;
+
+       f->compat_family.id = f->id;
+       f->compat_family.hdrsize = f->hdrsize;
+       strncpy(f->compat_family.name, f->name, GENL_NAMSIZ);
+       f->compat_family.version = f->version;
+       f->compat_family.maxattr = f->maxattr;
+       f->compat_family.netnsok = f->netnsok;
+#ifdef HAVE_PARALLEL_OPS
+       f->compat_family.parallel_ops = f->parallel_ops;
+#endif
+       err = genl_register_family_with_ops(&f->compat_family,
+                                           (struct genl_ops *) f->ops, f->n_ops);
+       if (err)
+               goto error;
+
+       if (f->mcgrps) {
+               /* Need to Fix GROUP_ID() for more than one group. */
+               BUG_ON(f->n_mcgrps > 1);
+               err = genl_register_mc_group(&f->compat_family,
+                                            (struct genl_multicast_group *) f->mcgrps);
+               if (err)
+                       goto error;
+       }
+error:
+       return err;
+
 }
+#endif /* kernel version < 3.13.0 */
index 45b617a..234fd91 100644 (file)
@@ -144,4 +144,15 @@ static inline bool u64_stats_fetch_retry_bh(const struct u64_stats_sync *syncp,
 }
 
 #endif /* Linux kernel < 2.6.36 */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0)
+
+#if BITS_PER_LONG == 32 && defined(CONFIG_SMP)
+# define u64_stats_init(syncp)  seqcount_init(syncp.seq)
+#else
+# define u64_stats_init(syncp)  do { } while (0)
+#endif
+
+#endif
+
 #endif /* _LINUX_U64_STATS_SYNC_WRAPPER_H */
index 09ee23b..9f425e5 100644 (file)
 #define portid pid
 #endif
 
-extern void genl_notify(struct sk_buff *skb, struct net *net, u32 portid,
-                       u32 group, struct nlmsghdr *nlh, gfp_t flags);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0)
+struct rpl_genl_family {
+       struct genl_family      compat_family;
+       unsigned int            id;
+       unsigned int            hdrsize;
+       char                    name[GENL_NAMSIZ];
+       unsigned int            version;
+       unsigned int            maxattr;
+       bool                    netnsok;
+       bool                    parallel_ops;
+       int                     (*pre_doit)(const struct genl_ops *ops,
+                                           struct sk_buff *skb,
+                                           struct genl_info *info);
+       void                    (*post_doit)(const struct genl_ops *ops,
+                                            struct sk_buff *skb,
+                                            struct genl_info *info);
+       struct nlattr **        attrbuf;        /* private */
+       const struct genl_ops * ops;            /* private */
+       const struct genl_multicast_group *mcgrps; /* private */
+       unsigned int            n_ops;          /* private */
+       unsigned int            n_mcgrps;       /* private */
+       unsigned int            mcgrp_offset;   /* private */
+       struct list_head        family_list;    /* private */
+       struct module           *module;
+};
+
+#define genl_family rpl_genl_family
+#define genl_notify rpl_genl_notify
+void genl_notify(struct genl_family *family,
+                struct sk_buff *skb, struct net *net, u32 portid, u32 group,
+                struct nlmsghdr *nlh, gfp_t flags);
+
+static inline void *rpl_genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
+                                   struct genl_family *family, int flags, u8 cmd)
+{
+       return genlmsg_put(skb, portid, seq, &family->compat_family, flags, cmd);
+}
+
+#define genlmsg_put rpl_genlmsg_put
+
+static inline int rpl_genl_unregister_family(struct genl_family *family)
+{
+       return genl_unregister_family(&family->compat_family);
+}
+#define genl_unregister_family rpl_genl_unregister_family
+
+#define genl_set_err rpl_genl_set_err
+static inline int genl_set_err(struct genl_family *family, struct net *net,
+                              u32 portid, u32 group, int code)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
+       netlink_set_err(net->genl_sock, portid, group, code);
+       return 0;
+#else
+       return netlink_set_err(net->genl_sock, portid, group, code);
+#endif
+}
+
+#define genlmsg_multicast_netns rpl_genlmsg_multicast_netns
+static inline int genlmsg_multicast_netns(struct genl_family *family,
+                                         struct net *net, struct sk_buff *skb,
+                                         u32 portid, unsigned int group, gfp_t flags)
+{
+       return nlmsg_multicast(net->genl_sock, skb, portid, group, flags);
+}
+
+
+#define __genl_register_family rpl___genl_register_family
+int rpl___genl_register_family(struct genl_family *family);
+
+#define genl_register_family rpl_genl_register_family
+static inline int rpl_genl_register_family(struct genl_family *family)
+{
+       family->module = THIS_MODULE;
+       return rpl___genl_register_family(family);
+}
+
+#endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
 static inline struct sk_buff *genlmsg_new_unicast(size_t payload,
index 6268655..dc03535 100644 (file)
@@ -17,6 +17,8 @@
 
 struct gre_cisco_protocol {
        int (*handler)(struct sk_buff *skb, const struct tnl_ptk_info *tpi);
+       int (*err_handler)(struct sk_buff *skb, u32 info,
+                          const struct tnl_ptk_info *tpi);
        u8 priority;
 };
 
index 4193d32..c819e4d 100644 (file)
@@ -12,4 +12,14 @@ static inline bool ip_is_fragment(const struct iphdr *iph)
 }
 #endif
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0)
+static inline void rpl_inet_get_local_port_range(struct net *net, int *low,
+                                            int *high)
+{
+       inet_get_local_port_range(low, high);
+}
+#define inet_get_local_port_range rpl_inet_get_local_port_range
+
+#endif
+
 #endif
index dc4df2a..9404e20 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/mm.h>
 #include <linux/net.h>
 #include <net/checksum.h>
+#include <net/ip.h>
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/percpu.h>
@@ -38,6 +39,7 @@ void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
 }
 #endif
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0)
 bool __net_get_random_once(void *buf, int nbytes, bool *done,
                           atomic_t *done_key)
 {
@@ -58,3 +60,4 @@ bool __net_get_random_once(void *buf, int nbytes, bool *done,
 
        return true;
 }
+#endif
index 5ba5b8e..5d5090c 100644 (file)
@@ -116,6 +116,25 @@ static int gre_rcv(struct sk_buff *skb,
        return PACKET_RCVD;
 }
 
+/* Called with rcu_read_lock and BH disabled. */
+static int gre_err(struct sk_buff *skb, u32 info,
+                  const struct tnl_ptk_info *tpi)
+{
+       struct ovs_net *ovs_net;
+       struct vport *vport;
+
+       ovs_net = net_generic(dev_net(skb->dev), ovs_net_id);
+       if ((tpi->flags & TUNNEL_KEY) && (tpi->flags & TUNNEL_SEQ))
+               vport = rcu_dereference(ovs_net->vport_net.gre64_vport);
+       else
+               vport = rcu_dereference(ovs_net->vport_net.gre_vport);
+
+       if (unlikely(!vport))
+               return PACKET_REJECT;
+       else
+               return PACKET_RCVD;
+}
+
 static int __send(struct vport *vport, struct sk_buff *skb,
                  int tunnel_hlen,
                  __be32 seq, __be16 gre64_flag)
@@ -187,6 +206,7 @@ error:
 
 static struct gre_cisco_protocol gre_protocol = {
        .handler        = gre_rcv,
+       .err_handler    = gre_err,
        .priority       = 1,
 };
 
index e33cffe..8e3ff69 100644 (file)
@@ -163,7 +163,7 @@ static __be64 instance_id_to_tunnel_id(__u8 *iid)
 /* Compute source UDP port for outgoing packet.
  * Currently we use the flow hash.
  */
-static u16 get_src_port(struct sk_buff *skb)
+static u16 get_src_port(struct net *net, struct sk_buff *skb)
 {
        u32 hash = skb_get_rxhash(skb);
        unsigned int range;
@@ -177,7 +177,7 @@ static u16 get_src_port(struct sk_buff *skb)
                            sizeof(*pkt_key) / sizeof(u32), 0);
        }
 
-       inet_get_local_port_range(&low, &high);
+       inet_get_local_port_range(net, &low, &high);
        range = (high - low) + 1;
        return (((u64) hash * range) >> 32) + low;
 }
@@ -185,13 +185,14 @@ static u16 get_src_port(struct sk_buff *skb)
 static void lisp_build_header(const struct vport *vport,
                              struct sk_buff *skb)
 {
+       struct net *net = ovs_dp_get_net(vport->dp);
        struct lisp_port *lisp_port = lisp_vport(vport);
        struct udphdr *udph = udp_hdr(skb);
        struct lisphdr *lisph = (struct lisphdr *)(udph + 1);
        const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key;
 
        udph->dest = lisp_port->dst_port;
-       udph->source = htons(get_src_port(skb));
+       udph->source = htons(get_src_port(net, skb));
        udph->check = 0;
        udph->len = htons(skb->len - skb_transport_offset(skb));
 
index d264785..cc9477d 100644 (file)
@@ -139,6 +139,7 @@ error:
 
 static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
 {
+       struct net *net = ovs_dp_get_net(vport->dp);
        struct vxlan_port *vxlan_port = vxlan_vport(vport);
        __be16 dst_port = inet_sport(vxlan_port->vs->sock->sk);
        struct rtable *rt;
@@ -172,7 +173,7 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
 
        skb->local_df = 1;
 
-       inet_get_local_port_range(&port_min, &port_max);
+       inet_get_local_port_range(net, &port_min, &port_max);
        src_port = vxlan_src_port(port_min, port_max, skb);
 
        err = vxlan_xmit_skb(vxlan_port->vs, rt, skb,
index 7f12acc..2673b81 100644 (file)
@@ -122,6 +122,7 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
 {
        struct vport *vport;
        size_t alloc_size;
+       int i;
 
        alloc_size = sizeof(struct vport);
        if (priv_size) {
@@ -145,6 +146,12 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
                return ERR_PTR(-ENOMEM);
        }
 
+       for_each_possible_cpu(i) {
+               struct pcpu_tstats *vport_stats;
+               vport_stats = per_cpu_ptr(vport->percpu_stats, i);
+               u64_stats_init(&vport_stats->syncp);
+       }
+
        spin_lock_init(&vport->stats_lock);
 
        return vport;
index 1aed8e7..af4af4e 100644 (file)
@@ -65,7 +65,7 @@ Description: Open vSwitch common components
 Package: openvswitch-switch
 Architecture: linux-any
 Suggests: openvswitch-datapath-module
-Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}, openvswitch-common (= ${binary:Version}), kmod, procps, uuid-runtime, netbase, python-argparse
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}, openvswitch-common (= ${binary:Version}), kmod | module-init-tools, procps, uuid-runtime, netbase, python-argparse
 Description: Open vSwitch switch implementations
  Open vSwitch is a production quality, multilayer, software-based,
  Ethernet virtual switch. It is designed to enable massive network
index cc9e453..8bfe385 100644 (file)
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -673,7 +673,7 @@ bfd_process_packet(struct bfd *bfd, const struct flow *flow,
         goto out;
     }
 
-    msg = ofpbuf_at(p, l7 - (uint8_t *)p->data, BFD_PACKET_LEN);
+    msg = ofpbuf_at(p, l7 - (uint8_t *)ofpbuf_data(p), BFD_PACKET_LEN);
     if (!msg) {
         VLOG_INFO_RL(&rl, "%s: Received too-short BFD control message (only "
                      "%"PRIdPTR" bytes long, at least %d required).",
index 4a40a6a..60a360e 100644 (file)
@@ -177,7 +177,7 @@ bundle_from_openflow(const struct nx_action_bundle *nab,
         ofpbuf_put(ofpacts, &ofp_port, sizeof ofp_port);
     }
 
-    bundle = ofpacts->l2;
+    bundle = ofpacts->frame;
     ofpact_update_len(ofpacts, &bundle->ofpact);
 
     if (!error) {
@@ -288,7 +288,7 @@ bundle_parse__(const char *s, char **save_ptr,
         }
         ofpbuf_put(ofpacts, &slave_port, sizeof slave_port);
 
-        bundle = ofpacts->l2;
+        bundle = ofpacts->frame;
         bundle->n_slaves++;
     }
     ofpact_update_len(ofpacts, &bundle->ofpact);
index dcdaa0e..ce0c471 100644 (file)
--- a/lib/cfm.c
+++ b/lib/cfm.c
@@ -557,7 +557,7 @@ cfm_compose_ccm(struct cfm *cfm, struct ofpbuf *packet,
         eth_push_vlan(packet, htons(ETH_TYPE_VLAN), htons(tci));
     }
 
-    ccm = ofpbuf_get_l3(packet);
+    ccm = ofpbuf_l3(packet);
     ccm->mdlevel_version = 0;
     ccm->opcode = CCM_OPCODE;
     ccm->tlv_offset = 70;
@@ -718,8 +718,8 @@ cfm_process_heartbeat(struct cfm *cfm, const struct ofpbuf *p)
 
     ovs_mutex_lock(&mutex);
 
-    eth = p->l2;
-    ccm = ofpbuf_at(p, (uint8_t *)ofpbuf_get_l3(p) - (uint8_t *)p->data,
+    eth = ofpbuf_l2(p);
+    ccm = ofpbuf_at(p, (uint8_t *)ofpbuf_l3(p) - (uint8_t *)ofpbuf_data(p),
                     CCM_ACCEPT_LEN);
 
     if (!ccm) {
index 779f764..e8efdac 100644 (file)
@@ -542,8 +542,8 @@ dpif_linux_port_add__(struct dpif *dpif_, struct netdev *netdev,
         ofpbuf_use_stack(&options, options_stub, sizeof options_stub);
         nl_msg_put_u16(&options, OVS_TUNNEL_ATTR_DST_PORT,
                        ntohs(tnl_cfg->dst_port));
-        request.options = options.data;
-        request.options_len = options.size;
+        request.options = ofpbuf_data(&options);
+        request.options_len = ofpbuf_size(&options);
     }
 
     request.port_no = *port_nop;
@@ -906,8 +906,8 @@ dpif_linux_flow_get(const struct dpif *dpif_,
             dpif_linux_flow_get_stats(&reply, stats);
         }
         if (actionsp) {
-            buf->data = CONST_CAST(struct nlattr *, reply.actions);
-            buf->size = reply.actions_len;
+            ofpbuf_set_data(buf, CONST_CAST(struct nlattr *, reply.actions));
+            ofpbuf_set_size(buf, reply.actions_len);
             *actionsp = buf;
         } else {
             ofpbuf_delete(buf);
@@ -1110,7 +1110,7 @@ dpif_linux_flow_dump_next_may_destroy_keys(void *state_)
 {
     struct dpif_linux_flow_state *state = state_;
 
-    return state->buffer.size ? false : true;
+    return ofpbuf_size(&state->buffer) ? false : true;
 }
 
 static int
@@ -1133,7 +1133,7 @@ dpif_linux_encode_execute(int dp_ifindex, const struct dpif_execute *d_exec,
     size_t key_ofs;
 
     ofpbuf_prealloc_tailroom(buf, (64
-                                   + d_exec->packet->size
+                                   + ofpbuf_size(d_exec->packet)
                                    + ODP_KEY_METADATA_SIZE
                                    + d_exec->actions_len));
 
@@ -1144,7 +1144,8 @@ dpif_linux_encode_execute(int dp_ifindex, const struct dpif_execute *d_exec,
     k_exec->dp_ifindex = dp_ifindex;
 
     nl_msg_put_unspec(buf, OVS_PACKET_ATTR_PACKET,
-                      d_exec->packet->data, d_exec->packet->size);
+                      ofpbuf_data(d_exec->packet),
+                      ofpbuf_size(d_exec->packet));
 
     key_ofs = nl_msg_start_nested(buf, OVS_PACKET_ATTR_KEY);
     odp_key_from_pkt_metadata(buf, &d_exec->md);
@@ -1500,7 +1501,7 @@ parse_odp_packet(struct ofpbuf *buf, struct dpif_upcall *upcall,
     struct ofpbuf b;
     int type;
 
-    ofpbuf_use_const(&b, buf->data, buf->size);
+    ofpbuf_use_const(&b, ofpbuf_data(buf), ofpbuf_size(buf));
 
     nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
     genl = ofpbuf_try_pull(&b, sizeof *genl);
@@ -1532,8 +1533,9 @@ parse_odp_packet(struct ofpbuf *buf, struct dpif_upcall *upcall,
                                nl_attr_get(a[OVS_PACKET_ATTR_PACKET])) - 1,
                     nl_attr_get_size(a[OVS_PACKET_ATTR_PACKET]) +
                     sizeof(struct nlattr));
-    upcall->packet.data = (char *)upcall->packet.data + sizeof(struct nlattr);
-    upcall->packet.size = nl_attr_get_size(a[OVS_PACKET_ATTR_PACKET]);
+    ofpbuf_set_data(&upcall->packet,
+                    (char *)ofpbuf_data(&upcall->packet) + sizeof(struct nlattr));
+    ofpbuf_set_size(&upcall->packet, nl_attr_get_size(a[OVS_PACKET_ATTR_PACKET]));
 
     *dp_ifindex = ovs_header->dp_ifindex;
 
@@ -1778,7 +1780,7 @@ dpif_linux_vport_from_ofpbuf(struct dpif_linux_vport *vport,
 
     dpif_linux_vport_init(vport);
 
-    ofpbuf_use_const(&b, buf->data, buf->size);
+    ofpbuf_use_const(&b, ofpbuf_data(buf), ofpbuf_size(buf));
     nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
     genl = ofpbuf_try_pull(&b, sizeof *genl);
     ovs_header = ofpbuf_try_pull(&b, sizeof *ovs_header);
@@ -1941,7 +1943,7 @@ dpif_linux_dp_from_ofpbuf(struct dpif_linux_dp *dp, const struct ofpbuf *buf)
 
     dpif_linux_dp_init(dp);
 
-    ofpbuf_use_const(&b, buf->data, buf->size);
+    ofpbuf_use_const(&b, ofpbuf_data(buf), ofpbuf_size(buf));
     nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
     genl = ofpbuf_try_pull(&b, sizeof *genl);
     ovs_header = ofpbuf_try_pull(&b, sizeof *ovs_header);
@@ -2103,7 +2105,7 @@ dpif_linux_flow_from_ofpbuf(struct dpif_linux_flow *flow,
 
     dpif_linux_flow_init(flow);
 
-    ofpbuf_use_const(&b, buf->data, buf->size);
+    ofpbuf_use_const(&b, ofpbuf_data(buf), ofpbuf_size(buf));
     nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
     genl = ofpbuf_try_pull(&b, sizeof *genl);
     ovs_header = ofpbuf_try_pull(&b, sizeof *ovs_header);
index b467a22..42af2ff 100644 (file)
@@ -68,6 +68,9 @@ VLOG_DEFINE_THIS_MODULE(dpif_netdev);
 #define NETDEV_RULE_PRIORITY 0x8000
 
 #define NR_THREADS 1
+/* Use per thread recirc_depth to prevent recirculation loop. */
+#define MAX_RECIRC_DEPTH 5
+DEFINE_STATIC_PER_THREAD_DATA(uint32_t, recirc_depth, 0)
 
 /* Configuration parameters. */
 enum { MAX_FLOWS = 65536 };     /* Maximum number of flows in flow table. */
@@ -1144,8 +1147,6 @@ dpif_netdev_mask_from_nlattrs(const struct nlattr *key, uint32_t key_len,
 
             return EINVAL;
         }
-        /* Force unwildcard the in_port. */
-        mask->in_port.odp_port = u32_to_odp(UINT32_MAX);
     } else {
         enum mf_field_id id;
         /* No mask key, unwildcard everything except fields whose
@@ -1164,6 +1165,14 @@ dpif_netdev_mask_from_nlattrs(const struct nlattr *key, uint32_t key_len,
         }
     }
 
+    /* Force unwildcard the in_port.
+     *
+     * We need to do this even in the case where we unwildcard "everything"
+     * above because "everything" only includes the 16-bit OpenFlow port number
+     * mask->in_port.ofp_port, which only covers half of the 32-bit datapath
+     * port number mask->in_port.odp_port. */
+    mask->in_port.odp_port = u32_to_odp(UINT32_MAX);
+
     return 0;
 }
 
@@ -1470,8 +1479,8 @@ dpif_netdev_flow_dump_next(const struct dpif *dpif, void *iter_, void *state_,
         odp_flow_key_from_flow(&buf, &netdev_flow->flow,
                                netdev_flow->flow.in_port.odp_port);
 
-        *key = buf.data;
-        *key_len = buf.size;
+        *key = ofpbuf_data(&buf);
+        *key_len = ofpbuf_size(&buf);
     }
 
     if (key && mask) {
@@ -1484,8 +1493,8 @@ dpif_netdev_flow_dump_next(const struct dpif *dpif, void *iter_, void *state_,
                                odp_to_u32(wc.masks.in_port.odp_port),
                                SIZE_MAX);
 
-        *mask = buf.data;
-        *mask_len = buf.size;
+        *mask = ofpbuf_data(&buf);
+        *mask_len = ofpbuf_size(&buf);
     }
 
     if (actions || stats) {
@@ -1523,8 +1532,8 @@ dpif_netdev_execute(struct dpif *dpif, struct dpif_execute *execute)
     struct pkt_metadata *md = &execute->md;
     struct flow key;
 
-    if (execute->packet->size < ETH_HEADER_LEN ||
-        execute->packet->size > UINT16_MAX) {
+    if (ofpbuf_size(execute->packet) < ETH_HEADER_LEN ||
+        ofpbuf_size(execute->packet) > UINT16_MAX) {
         return EINVAL;
     }
 
@@ -1974,7 +1983,7 @@ dp_netdev_flow_used(struct dp_netdev_flow *netdev_flow,
     ovs_mutex_lock(&bucket->mutex);
     bucket->used = MAX(now, bucket->used);
     bucket->packet_count++;
-    bucket->byte_count += packet->size;
+    bucket->byte_count += ofpbuf_size(packet);
     bucket->tcp_flags |= tcp_flags;
     ovs_mutex_unlock(&bucket->mutex);
 }
@@ -1999,13 +2008,14 @@ dp_netdev_count_packet(struct dp_netdev *dp, enum dp_stat_type type)
 }
 
 static void
-dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet,
-                     struct pkt_metadata *md)
+dp_netdev_input(struct dp_netdev *dp, struct ofpbuf *packet,
+                struct pkt_metadata *md)
+    OVS_REQ_RDLOCK(dp->port_rwlock)
 {
     struct dp_netdev_flow *netdev_flow;
     struct flow key;
 
-    if (packet->size < ETH_HEADER_LEN) {
+    if (ofpbuf_size(packet) < ETH_HEADER_LEN) {
         ofpbuf_delete(packet);
         return;
     }
@@ -2029,6 +2039,17 @@ dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet,
     }
 }
 
+static void
+dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet,
+                     struct pkt_metadata *md)
+    OVS_REQ_RDLOCK(dp->port_rwlock)
+{
+    uint32_t *recirc_depth = recirc_depth_get();
+
+    *recirc_depth = 0;
+    dp_netdev_input(dp, packet, md);
+}
+
 static int
 dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet,
                            int queue_no, int type, const struct flow *flow,
@@ -2053,13 +2074,13 @@ dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet,
         if (userdata) {
             buf_size += NLA_ALIGN(userdata->nla_len);
         }
-        buf_size += packet->size;
+        buf_size += ofpbuf_size(packet);
         ofpbuf_init(buf, buf_size);
 
         /* Put ODP flow. */
         odp_flow_key_from_flow(buf, flow, flow->in_port.odp_port);
-        upcall->key = buf->data;
-        upcall->key_len = buf->size;
+        upcall->key = ofpbuf_data(buf);
+        upcall->key_len = ofpbuf_size(buf);
 
         /* Put userdata. */
         if (userdata) {
@@ -2067,8 +2088,9 @@ dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet,
                                           NLA_ALIGN(userdata->nla_len));
         }
 
-        upcall->packet.data = ofpbuf_put(buf, packet->data, packet->size);
-        upcall->packet.size = packet->size;
+        ofpbuf_set_data(&upcall->packet,
+                        ofpbuf_put(buf, ofpbuf_data(packet), ofpbuf_size(packet)));
+        ofpbuf_set_size(&upcall->packet, ofpbuf_size(packet));
 
         seq_change(q->seq);
 
@@ -2097,6 +2119,7 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet,
     struct dp_netdev_execute_aux *aux = aux_;
     int type = nl_attr_type(a);
     struct dp_netdev_port *p;
+    uint32_t *depth = recirc_depth_get();
 
     switch ((enum ovs_action_attr)type) {
     case OVS_ACTION_ATTR_OUTPUT:
@@ -2123,23 +2146,35 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet,
         break;
     }
 
-    case OVS_ACTION_ATTR_RECIRC: {
-        const struct ovs_action_recirc *act;
+    case OVS_ACTION_ATTR_RECIRC:
+        if (*depth < MAX_RECIRC_DEPTH) {
+            struct pkt_metadata recirc_md = *md;
+            struct ofpbuf *recirc_packet;
+            const struct ovs_action_recirc *act;
 
-        act = nl_attr_get(a);
-        md->recirc_id = act->recirc_id;
-        md->dp_hash = 0;
+            recirc_packet = may_steal ? packet : ofpbuf_clone(packet);
 
-        if (act->hash_alg == OVS_RECIRC_HASH_ALG_L4) {
-            struct flow flow;
+            act = nl_attr_get(a);
+            recirc_md.recirc_id = act->recirc_id;
+            recirc_md.dp_hash = 0;
 
-            flow_extract(packet, md, &flow);
-            md->dp_hash = flow_hash_symmetric_l4(&flow, act->hash_bias);
-        }
+            if (act->hash_alg == OVS_RECIRC_HASH_ALG_L4) {
+                recirc_md.dp_hash = flow_hash_symmetric_l4(aux->key,
+                                                           act->hash_bias);
+                if (!recirc_md.dp_hash) {
+                    recirc_md.dp_hash = 1;  /* 0 is not valid */
+                }
+            }
 
-        dp_netdev_port_input(aux->dp, packet, md);
+            (*depth)++;
+            dp_netdev_input(aux->dp, recirc_packet, &recirc_md);
+            (*depth)--;
+
+            break;
+        } else {
+            VLOG_WARN("Packet dropped. Max recirculation depth exceeded.");
+        }
         break;
-    }
 
     case OVS_ACTION_ATTR_PUSH_VLAN:
     case OVS_ACTION_ATTR_POP_VLAN:
@@ -2151,7 +2186,6 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet,
     case __OVS_ACTION_ATTR_MAX:
         OVS_NOT_REACHED();
     }
-
 }
 
 static void
index 4096785..af4a969 100644 (file)
@@ -34,8 +34,8 @@ enum { DP_NETDEV_HEADROOM = 2 + VLAN_HEADER_LEN };
 
 static inline void dp_packet_pad(struct ofpbuf *b)
 {
-    if (b->size < ETH_TOTAL_MIN) {
-        ofpbuf_put_zeros(b, ETH_TOTAL_MIN - b->size);
+    if (ofpbuf_size(b) < ETH_TOTAL_MIN) {
+        ofpbuf_put_zeros(b, ETH_TOTAL_MIN - ofpbuf_size(b));
     }
 }
 
index 25deea8..711792f 100644 (file)
@@ -789,7 +789,7 @@ dpif_flow_stats_extract(const struct flow *flow, const struct ofpbuf *packet,
                         long long int used, struct dpif_flow_stats *stats)
 {
     stats->tcp_flags = ntohs(flow->tcp_flags);
-    stats->n_bytes = packet->size;
+    stats->n_bytes = ofpbuf_size(packet);
     stats->n_packets = 1;
     stats->used = used;
 }
@@ -862,8 +862,8 @@ dpif_flow_get(const struct dpif *dpif,
         size_t actions_len;
 
         if (!error && actionsp) {
-            actions = (*actionsp)->data;
-            actions_len = (*actionsp)->size;
+            actions = ofpbuf_data(*actionsp);
+            actions_len = ofpbuf_size(*actionsp);
         } else {
             actions = NULL;
             actions_len = 0;
@@ -1360,8 +1360,8 @@ dpif_recv(struct dpif *dpif, uint32_t handler_id, struct dpif_upcall *upcall,
         struct ds flow;
         char *packet;
 
-        packet = ofp_packet_to_string(upcall->packet.data,
-                                      upcall->packet.size);
+        packet = ofp_packet_to_string(ofpbuf_data(&upcall->packet),
+                                      ofpbuf_size(&upcall->packet));
 
         ds_init(&flow);
         odp_flow_key_format(upcall->key, upcall->key_len, &flow);
@@ -1564,8 +1564,8 @@ log_execute_message(struct dpif *dpif, const struct dpif_execute *execute,
         struct ds ds = DS_EMPTY_INITIALIZER;
         char *packet;
 
-        packet = ofp_packet_to_string(execute->packet->data,
-                                      execute->packet->size);
+        packet = ofp_packet_to_string(ofpbuf_data(execute->packet),
+                                      ofpbuf_size(execute->packet));
         ds_put_format(&ds, "%s: execute ", dpif_name(dpif));
         format_odp_actions(&ds, execute->actions, execute->actions_len);
         if (error) {
index 314c1c7..6c6978d 100644 (file)
@@ -59,10 +59,10 @@ pull_arp(struct ofpbuf *packet)
 static struct ip_header *
 pull_ip(struct ofpbuf *packet)
 {
-    if (packet->size >= IP_HEADER_LEN) {
-        struct ip_header *ip = packet->data;
+    if (ofpbuf_size(packet) >= IP_HEADER_LEN) {
+        struct ip_header *ip = ofpbuf_data(packet);
         int ip_len = IP_IHL(ip->ip_ihl_ver) * 4;
-        if (ip_len >= IP_HEADER_LEN && packet->size >= ip_len) {
+        if (ip_len >= IP_HEADER_LEN && ofpbuf_size(packet) >= ip_len) {
             return ofpbuf_pull(packet, ip_len);
         }
     }
@@ -88,10 +88,11 @@ parse_mpls(struct ofpbuf *b, struct flow *flow)
     int idx = 0;
 
     while ((mh = ofpbuf_try_pull(b, sizeof *mh))) {
+        ovs_be32 mpls_lse = get_16aligned_be32(&mh->mpls_lse);
         if (idx < FLOW_MAX_MPLS_LABELS) {
-            flow->mpls_lse[idx++] = mh->mpls_lse;
+            flow->mpls_lse[idx++] = mpls_lse;
         }
-        if (mh->mpls_lse & htonl(MPLS_BOS_MASK)) {
+        if (mpls_lse & htonl(MPLS_BOS_MASK)) {
             break;
         }
     }
@@ -105,7 +106,7 @@ parse_vlan(struct ofpbuf *b, struct flow *flow)
         ovs_be16 tci;
     };
 
-    if (b->size >= sizeof(struct qtag_prefix) + sizeof(ovs_be16)) {
+    if (ofpbuf_size(b) >= sizeof(struct qtag_prefix) + sizeof(ovs_be16)) {
         struct qtag_prefix *qp = ofpbuf_pull(b, sizeof *qp);
         flow->vlan_tci = qp->tci | htons(VLAN_CFI);
     }
@@ -122,11 +123,11 @@ parse_ethertype(struct ofpbuf *b)
         return proto;
     }
 
-    if (b->size < sizeof *llc) {
+    if (ofpbuf_size(b) < sizeof *llc) {
         return htons(FLOW_DL_TYPE_NONE);
     }
 
-    llc = b->data;
+    llc = ofpbuf_data(b);
     if (llc->llc.llc_dsap != LLC_DSAP_SNAP
         || llc->llc.llc_ssap != LLC_SSAP_SNAP
         || llc->llc.llc_cntl != LLC_CNTL_SNAP
@@ -184,7 +185,7 @@ parse_ipv6(struct ofpbuf *packet, struct flow *flow)
          * accesses within the extension header are within those first 8
          * bytes. All extension headers are required to be at least 8
          * bytes. */
-        if (packet->size < 8) {
+        if (ofpbuf_size(packet) < 8) {
             return EINVAL;
         }
 
@@ -193,7 +194,7 @@ parse_ipv6(struct ofpbuf *packet, struct flow *flow)
                 || (nexthdr == IPPROTO_DSTOPTS)) {
             /* These headers, while different, have the fields we care about
              * in the same location and with the same interpretation. */
-            const struct ip6_ext *ext_hdr = packet->data;
+            const struct ip6_ext *ext_hdr = ofpbuf_data(packet);
             nexthdr = ext_hdr->ip6e_nxt;
             if (!ofpbuf_try_pull(packet, (ext_hdr->ip6e_len + 1) * 8)) {
                 return EINVAL;
@@ -203,13 +204,13 @@ parse_ipv6(struct ofpbuf *packet, struct flow *flow)
              * we care about are in the same location as the generic
              * option header--only the header length is calculated
              * differently. */
-            const struct ip6_ext *ext_hdr = packet->data;
+            const struct ip6_ext *ext_hdr = ofpbuf_data(packet);
             nexthdr = ext_hdr->ip6e_nxt;
             if (!ofpbuf_try_pull(packet, (ext_hdr->ip6e_len + 2) * 4)) {
                return EINVAL;
             }
         } else if (nexthdr == IPPROTO_FRAGMENT) {
-            const struct ovs_16aligned_ip6_frag *frag_hdr = packet->data;
+            const struct ovs_16aligned_ip6_frag *frag_hdr = ofpbuf_data(packet);
 
             nexthdr = frag_hdr->ip6f_nxt;
             if (!ofpbuf_try_pull(packet, sizeof *frag_hdr)) {
@@ -235,8 +236,8 @@ parse_ipv6(struct ofpbuf *packet, struct flow *flow)
 static void
 parse_tcp(struct ofpbuf *b, struct flow *flow)
 {
-    if (b->size >= TCP_HEADER_LEN) {
-        const struct tcp_header *tcp = b->data;
+    if (ofpbuf_size(b) >= TCP_HEADER_LEN) {
+        const struct tcp_header *tcp = ofpbuf_data(b);
 
         flow->tp_src = tcp->tcp_src;
         flow->tp_dst = tcp->tcp_dst;
@@ -247,8 +248,8 @@ parse_tcp(struct ofpbuf *b, struct flow *flow)
 static void
 parse_udp(struct ofpbuf *b, struct flow *flow)
 {
-    if (b->size >= UDP_HEADER_LEN) {
-        const struct udp_header *udp = b->data;
+    if (ofpbuf_size(b) >= UDP_HEADER_LEN) {
+        const struct udp_header *udp = ofpbuf_data(b);
 
         flow->tp_src = udp->udp_src;
         flow->tp_dst = udp->udp_dst;
@@ -258,8 +259,8 @@ parse_udp(struct ofpbuf *b, struct flow *flow)
 static void
 parse_sctp(struct ofpbuf *b, struct flow *flow)
 {
-    if (b->size >= SCTP_HEADER_LEN) {
-        const struct sctp_header *sctp = b->data;
+    if (ofpbuf_size(b) >= SCTP_HEADER_LEN) {
+        const struct sctp_header *sctp = ofpbuf_data(b);
 
         flow->tp_src = sctp->sctp_src;
         flow->tp_dst = sctp->sctp_dst;
@@ -291,13 +292,13 @@ parse_icmpv6(struct ofpbuf *b, struct flow *flow)
         }
         flow->nd_target = *nd_target;
 
-        while (b->size >= 8) {
+        while (ofpbuf_size(b) >= 8) {
             /* The minimum size of an option is 8 bytes, which also is
              * the size of Ethernet link-layer options. */
-            const struct nd_opt_hdr *nd_opt = b->data;
+            const struct nd_opt_hdr *nd_opt = ofpbuf_data(b);
             int opt_len = nd_opt->nd_opt_len * 8;
 
-            if (!opt_len || opt_len > b->size) {
+            if (!opt_len || opt_len > ofpbuf_size(b)) {
                 goto invalid;
             }
 
@@ -369,19 +370,18 @@ flow_extract(struct ofpbuf *packet, const struct pkt_metadata *md,
         flow->in_port = md->in_port;
         flow->skb_priority = md->skb_priority;
         flow->pkt_mark = md->pkt_mark;
+        flow->recirc_id = md->recirc_id;
+        flow->dp_hash = md->dp_hash;
     }
 
-    packet->l2   = b.data;
-    ofpbuf_set_l2_5(packet, NULL);
-    ofpbuf_set_l3(packet, NULL);
-    ofpbuf_set_l4(packet, NULL);
+    ofpbuf_set_frame(packet, ofpbuf_data(packet));
 
-    if (b.size < sizeof *eth) {
+    if (ofpbuf_size(&b) < sizeof *eth) {
         return;
     }
 
     /* Link layer. */
-    eth = b.data;
+    eth = ofpbuf_data(&b);
     memcpy(flow->dl_src, eth->eth_src, ETH_ADDR_LEN);
     memcpy(flow->dl_dst, eth->eth_dst, ETH_ADDR_LEN);
 
@@ -394,16 +394,16 @@ flow_extract(struct ofpbuf *packet, const struct pkt_metadata *md,
 
     /* Parse mpls, copy l3 ttl. */
     if (eth_type_mpls(flow->dl_type)) {
-        ofpbuf_set_l2_5(packet, b.data);
+        ofpbuf_set_l2_5(packet, ofpbuf_data(&b));
         parse_mpls(&b, flow);
     }
 
     /* Network layer. */
-    ofpbuf_set_l3(packet, b.data);
+    ofpbuf_set_l3(packet, ofpbuf_data(&b));
     if (flow->dl_type == htons(ETH_TYPE_IP)) {
         const struct ip_header *nh = pull_ip(&b);
         if (nh) {
-            ofpbuf_set_l4(packet, b.data);
+            ofpbuf_set_l4(packet, ofpbuf_data(&b));
 
             flow->nw_src = get_16aligned_be32(&nh->ip_src);
             flow->nw_dst = get_16aligned_be32(&nh->ip_dst);
@@ -439,7 +439,7 @@ flow_extract(struct ofpbuf *packet, const struct pkt_metadata *md,
             return;
         }
 
-        ofpbuf_set_l4(packet, b.data);
+        ofpbuf_set_l4(packet, ofpbuf_data(&b));
         if (flow->nw_proto == IPPROTO_TCP) {
             parse_tcp(&b, flow);
         } else if (flow->nw_proto == IPPROTO_UDP) {
@@ -1330,8 +1330,8 @@ flow_compose(struct ofpbuf *b, const struct flow *flow)
     /* eth_compose() sets l3 pointer and makes sure it is 32-bit aligned. */
     eth_compose(b, flow->dl_dst, flow->dl_src, ntohs(flow->dl_type), 0);
     if (flow->dl_type == htons(FLOW_DL_TYPE_NONE)) {
-        struct eth_header *eth = b->l2;
-        eth->eth_type = htons(b->size);
+        struct eth_header *eth = ofpbuf_l2(b);
+        eth->eth_type = htons(ofpbuf_size(b));
         return;
     }
 
index a6f45c9..d6dc308 100644 (file)
@@ -97,17 +97,13 @@ union flow_in_port {
  * be looked at.  This enables better wildcarding for datapath flows.
  */
 struct flow {
-    /* Recirculation */
-    uint32_t dp_hash;           /* Datapath computed hash value. The exact
-                                   computation is opaque to the user space.*/
-    uint32_t recirc_id;         /* Must be exact match. */
-
     /* L1 */
     struct flow_tnl tunnel;     /* Encapsulating tunnel parameters. */
     ovs_be64 metadata;          /* OpenFlow Metadata. */
     uint32_t regs[FLOW_N_REGS]; /* Registers. */
     uint32_t skb_priority;      /* Packet priority for QoS. */
     uint32_t pkt_mark;          /* Packet mark. */
+    uint32_t recirc_id;         /* Must be exact match. */
     union flow_in_port in_port; /* Input port.*/
 
     /* L2 */
@@ -134,6 +130,8 @@ struct flow {
     ovs_be16 pad;               /* Padding. */
 
     /* L4 */
+    uint32_t dp_hash;           /* Datapath computed hash value. The exact
+                                   computation is opaque to the user space.*/
     ovs_be16 tp_src;            /* TCP/UDP/SCTP source port. */
     ovs_be16 tp_dst;            /* TCP/UDP/SCTP destination port.
                                  * Keep last for the BUILD_ASSERT_DECL below */
@@ -156,7 +154,7 @@ BUILD_ASSERT_DECL(offsetof(struct flow, tp_dst) + 2
 enum {
     FLOW_SEGMENT_1_ENDS_AT = offsetof(struct flow, dl_src),
     FLOW_SEGMENT_2_ENDS_AT = offsetof(struct flow, ipv6_src),
-    FLOW_SEGMENT_3_ENDS_AT = offsetof(struct flow, tp_src),
+    FLOW_SEGMENT_3_ENDS_AT = offsetof(struct flow, dp_hash),
 };
 BUILD_ASSERT_DECL(FLOW_SEGMENT_1_ENDS_AT % 4 == 0);
 BUILD_ASSERT_DECL(FLOW_SEGMENT_2_ENDS_AT % 4 == 0);
index db0e09e..58b248a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013 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.
@@ -1640,116 +1640,3 @@ json_serialize_string(const char *string, struct ds *ds)
     }
     ds_put_char(ds, '"');
 }
-\f
-static size_t
-json_string_serialized_length(const char *string)
-{
-    size_t length;
-    uint8_t c;
-
-    length = strlen("\"\"");
-
-    while ((c = *string++) != '\0') {
-        switch (c) {
-        case '"':
-        case '\\':
-        case '\b':
-        case '\f':
-        case '\n':
-        case '\r':
-        case '\t':
-            length += 2;
-            break;
-
-        default:
-            if (c >= 32) {
-                length++;
-            } else {
-                /* \uXXXX */
-                length += 6;
-            }
-            break;
-        }
-    }
-
-    return length;
-}
-
-static size_t
-json_object_serialized_length(const struct shash *object)
-{
-    size_t length = strlen("{}");
-
-    if (!shash_is_empty(object)) {
-        struct shash_node *node;
-
-        /* Commas and colons. */
-        length += 2 * shash_count(object) - 1;
-
-        SHASH_FOR_EACH (node, object) {
-            const struct json *value = node->data;
-
-            length += json_string_serialized_length(node->name);
-            length += json_serialized_length(value);
-        }
-    }
-
-    return length;
-}
-
-static size_t
-json_array_serialized_length(const struct json_array *array)
-{
-    size_t length = strlen("[]");
-
-    if (array->n) {
-        size_t i;
-
-        /* Commas. */
-        length += array->n - 1;
-
-        for (i = 0; i < array->n; i++) {
-            length += json_serialized_length(array->elems[i]);
-        }
-    }
-
-    return length;
-}
-
-/* Returns strlen(json_to_string(json, 0)), that is, the number of bytes in the
- * JSON output by json_to_string() for 'json' when JSSF_PRETTY is not
- * requested.  (JSSF_SORT does not affect the length of json_to_string()'s
- * output.) */
-size_t
-json_serialized_length(const struct json *json)
-{
-    switch (json->type) {
-    case JSON_NULL:
-        return strlen("null");
-
-    case JSON_FALSE:
-        return strlen("false");
-
-    case JSON_TRUE:
-        return strlen("true");
-
-    case JSON_OBJECT:
-        return json_object_serialized_length(json->u.object);
-
-    case JSON_ARRAY:
-        return json_array_serialized_length(&json->u.array);
-
-    case JSON_INTEGER:
-        return snprintf(NULL, 0, "%lld", json->u.integer);
-
-    case JSON_REAL:
-        return snprintf(NULL, 0, "%.*g", DBL_DIG, json->u.real);
-
-    case JSON_STRING:
-        return json_string_serialized_length(json->u.string);
-
-    case JSON_N_TYPES:
-    default:
-        OVS_NOT_REACHED();
-    }
-}
index ef23124..cfe9457 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -127,8 +127,6 @@ enum {
 };
 char *json_to_string(const struct json *, int flags);
 void json_to_ds(const struct json *, int flags, struct ds *);
-
-size_t json_serialized_length(const struct json *);
 \f
 /* JSON string formatting operations. */
 
index 643a3c5..842d117 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -44,7 +44,6 @@ struct jsonrpc {
     struct byteq input;
     uint8_t input_buffer[512];
     struct json_parser *parser;
-    struct jsonrpc_msg *received;
 
     /* Output. */
     struct list output;         /* Contains "struct ofpbuf"s. */
@@ -54,7 +53,7 @@ struct jsonrpc {
 /* Rate limit for error messages. */
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
 
-static void jsonrpc_received(struct jsonrpc *);
+static struct jsonrpc_msg *jsonrpc_parse_received_message(struct jsonrpc *);
 static void jsonrpc_cleanup(struct jsonrpc *);
 static void jsonrpc_error(struct jsonrpc *, int error);
 
@@ -119,11 +118,11 @@ jsonrpc_run(struct jsonrpc *rpc)
         struct ofpbuf *buf = ofpbuf_from_list(rpc->output.next);
         int retval;
 
-        retval = stream_send(rpc->stream, buf->data, buf->size);
+        retval = stream_send(rpc->stream, ofpbuf_data(buf), ofpbuf_size(buf));
         if (retval >= 0) {
             rpc->backlog -= retval;
             ofpbuf_pull(buf, retval);
-            if (!buf->size) {
+            if (!ofpbuf_size(buf)) {
                 list_remove(&buf->list_node);
                 ofpbuf_delete(buf);
             }
@@ -256,7 +255,7 @@ jsonrpc_send(struct jsonrpc *rpc, struct jsonrpc_msg *msg)
 
     buf = xmalloc(sizeof *buf);
     ofpbuf_use(buf, s, length);
-    buf->size = length;
+    ofpbuf_set_size(buf, length);
     list_push_back(&rpc->output, &buf->list_node);
     rpc->backlog += length;
 
@@ -293,11 +292,10 @@ jsonrpc_recv(struct jsonrpc *rpc, struct jsonrpc_msg **msgp)
     }
 
     for (i = 0; i < 50; i++) {
-        if (rpc->received) {
-            *msgp = rpc->received;
-            rpc->received = NULL;
-            return 0;
-        } else if (byteq_is_empty(&rpc->input)) {
+        size_t n, used;
+
+        /* Fill our input buffer if it's empty. */
+        if (byteq_is_empty(&rpc->input)) {
             size_t chunk;
             int retval;
 
@@ -317,27 +315,31 @@ jsonrpc_recv(struct jsonrpc *rpc, struct jsonrpc_msg **msgp)
                 return EOF;
             }
             byteq_advance_head(&rpc->input, retval);
-        } else {
-            size_t n, used;
+        }
 
-            if (!rpc->parser) {
-                rpc->parser = json_parser_create(0);
+        /* We have some input.  Feed it into the JSON parser. */
+        if (!rpc->parser) {
+            rpc->parser = json_parser_create(0);
+        }
+        n = byteq_tailroom(&rpc->input);
+        used = json_parser_feed(rpc->parser,
+                                (char *) byteq_tail(&rpc->input), n);
+        byteq_advance_tail(&rpc->input, used);
+
+        /* If we have complete JSON, attempt to parse it as JSON-RPC. */
+        if (json_parser_is_done(rpc->parser)) {
+            *msgp = jsonrpc_parse_received_message(rpc);
+            if (*msgp) {
+                return 0;
             }
-            n = byteq_tailroom(&rpc->input);
-            used = json_parser_feed(rpc->parser,
-                                    (char *) byteq_tail(&rpc->input), n);
-            byteq_advance_tail(&rpc->input, used);
-            if (json_parser_is_done(rpc->parser)) {
-                jsonrpc_received(rpc);
-                if (rpc->status) {
-                    const struct byteq *q = &rpc->input;
-                    if (q->head <= q->size) {
-                        stream_report_content(q->buffer, q->head,
-                                              STREAM_JSONRPC,
-                                              THIS_MODULE, rpc->name);
-                    }
-                    return rpc->status;
+
+            if (rpc->status) {
+                const struct byteq *q = &rpc->input;
+                if (q->head <= q->size) {
+                    stream_report_content(q->buffer, q->head, STREAM_JSONRPC,
+                                          THIS_MODULE, rpc->name);
                 }
+                return rpc->status;
             }
         }
     }
@@ -350,7 +352,7 @@ jsonrpc_recv(struct jsonrpc *rpc, struct jsonrpc_msg **msgp)
 void
 jsonrpc_recv_wait(struct jsonrpc *rpc)
 {
-    if (rpc->status || rpc->received || !byteq_is_empty(&rpc->input)) {
+    if (rpc->status || !byteq_is_empty(&rpc->input)) {
         poll_immediate_wake_at(rpc->name);
     } else {
         stream_recv_wait(rpc->stream);
@@ -440,8 +442,11 @@ jsonrpc_transact_block(struct jsonrpc *rpc, struct jsonrpc_msg *request,
     return error;
 }
 
-static void
-jsonrpc_received(struct jsonrpc *rpc)
+/* Attempts to parse the content of 'rpc->parser' (which is complete JSON) as a
+ * JSON-RPC message.  If successful, returns the JSON-RPC message.  On failure,
+ * signals an error on 'rpc' with jsonrpc_error() and returns NULL. */
+static struct jsonrpc_msg *
+jsonrpc_parse_received_message(struct jsonrpc *rpc)
 {
     struct jsonrpc_msg *msg;
     struct json *json;
@@ -454,7 +459,7 @@ jsonrpc_received(struct jsonrpc *rpc)
                      rpc->name, json_string(json));
         jsonrpc_error(rpc, EPROTO);
         json_destroy(json);
-        return;
+        return NULL;
     }
 
     error = jsonrpc_msg_from_json(json, &msg);
@@ -463,11 +468,11 @@ jsonrpc_received(struct jsonrpc *rpc)
                      rpc->name, error);
         free(error);
         jsonrpc_error(rpc, EPROTO);
-        return;
+        return NULL;
     }
 
     jsonrpc_log_msg(rpc, "received", msg);
-    rpc->received = msg;
+    return msg;
 }
 
 static void
@@ -489,9 +494,6 @@ jsonrpc_cleanup(struct jsonrpc *rpc)
     json_parser_abort(rpc->parser);
     rpc->parser = NULL;
 
-    jsonrpc_msg_destroy(rpc->received);
-    rpc->received = NULL;
-
     ofpbuf_list_delete(&rpc->output);
     rpc->backlog = 0;
 }
index 711d7ec..4aee64f 100644 (file)
@@ -181,7 +181,7 @@ parse_lacp_packet(const struct ofpbuf *b)
 {
     const struct lacp_pdu *pdu;
 
-    pdu = ofpbuf_at(b, (uint8_t *)ofpbuf_get_l3(b) - (uint8_t *)b->data,
+    pdu = ofpbuf_at(b, (uint8_t *)ofpbuf_l3(b) - (uint8_t *)ofpbuf_data(b),
                     LACP_PDU_LEN);
 
     if (pdu && pdu->subtype == 1
index 61799c9..8727a55 100644 (file)
@@ -127,7 +127,7 @@ learn_from_openflow(const struct nx_action_learn *nal, struct ofpbuf *ofpacts)
         }
 
         spec = ofpbuf_put_zeros(ofpacts, sizeof *spec);
-        learn = ofpacts->l2;
+        learn = ofpacts->frame;
         learn->n_specs++;
 
         spec->src_type = header & NX_LEARN_SRC_MASK;
@@ -255,7 +255,7 @@ learn_to_nxast(const struct ofpact_learn *learn, struct ofpbuf *openflow)
     struct nx_action_learn *nal;
     size_t start_ofs;
 
-    start_ofs = openflow->size;
+    start_ofs = ofpbuf_size(openflow);
     nal = ofputil_put_NXAST_LEARN(openflow);
     nal->idle_timeout = htons(learn->idle_timeout);
     nal->hard_timeout = htons(learn->hard_timeout);
@@ -287,12 +287,12 @@ learn_to_nxast(const struct ofpact_learn *learn, struct ofpbuf *openflow)
         }
     }
 
-    if ((openflow->size - start_ofs) % 8) {
-        ofpbuf_put_zeros(openflow, 8 - (openflow->size - start_ofs) % 8);
+    if ((ofpbuf_size(openflow) - start_ofs) % 8) {
+        ofpbuf_put_zeros(openflow, 8 - (ofpbuf_size(openflow) - start_ofs) % 8);
     }
 
     nal = ofpbuf_at_assert(openflow, start_ofs, sizeof *nal);
-    nal->len = htons(openflow->size - start_ofs);
+    nal->len = htons(ofpbuf_size(openflow) - start_ofs);
 }
 
 /* Composes 'fm' so that executing it will implement 'learn' given that the
@@ -382,8 +382,8 @@ learn_execute(const struct ofpact_learn *learn, const struct flow *flow,
     }
     ofpact_pad(ofpacts);
 
-    fm->ofpacts = ofpacts->data;
-    fm->ofpacts_len = ofpacts->size;
+    fm->ofpacts = ofpbuf_data(ofpacts);
+    fm->ofpacts_len = ofpbuf_size(ofpacts);
 }
 
 /* Perform a bitwise-OR on 'wc''s fields that are relevant as sources in
@@ -585,7 +585,7 @@ learn_parse__(char *orig, char *arg, struct ofpbuf *ofpacts)
             char *error;
 
             spec = ofpbuf_put_zeros(ofpacts, sizeof *spec);
-            learn = ofpacts->l2;
+            learn = ofpacts->frame;
             learn->n_specs++;
 
             error = learn_parse_spec(orig, name, value, spec);
index 5620990..c818a32 100644 (file)
@@ -315,12 +315,12 @@ lswitch_process_packet(struct lswitch *sw, const struct ofpbuf *msg)
 
     switch (type) {
     case OFPTYPE_ECHO_REQUEST:
-        process_echo_request(sw, msg->data);
+        process_echo_request(sw, ofpbuf_data(msg));
         break;
 
     case OFPTYPE_FEATURES_REPLY:
         if (sw->state == S_FEATURES_REPLY) {
-            if (!process_switch_features(sw, msg->data)) {
+            if (!process_switch_features(sw, ofpbuf_data(msg))) {
                 sw->state = S_SWITCHING;
             } else {
                 rconn_disconnect(sw->rconn);
@@ -329,7 +329,7 @@ lswitch_process_packet(struct lswitch *sw, const struct ofpbuf *msg)
         break;
 
     case OFPTYPE_PACKET_IN:
-        process_packet_in(sw, msg->data);
+        process_packet_in(sw, ofpbuf_data(msg));
         break;
 
     case OFPTYPE_FLOW_REMOVED:
@@ -400,7 +400,7 @@ lswitch_process_packet(struct lswitch *sw, const struct ofpbuf *msg)
     case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
     default:
         if (VLOG_IS_DBG_ENABLED()) {
-            char *s = ofp_to_string(msg->data, msg->size, 2);
+            char *s = ofp_to_string(ofpbuf_data(msg), ofpbuf_size(msg), 2);
             VLOG_DBG_RL(&rl, "%016llx: OpenFlow packet ignored: %s",
                         sw->datapath_id, s);
             free(s);
@@ -598,15 +598,15 @@ process_packet_in(struct lswitch *sw, const struct ofp_header *oh)
     /* Prepare packet_out in case we need one. */
     po.buffer_id = pi.buffer_id;
     if (po.buffer_id == UINT32_MAX) {
-        po.packet = pkt.data;
-        po.packet_len = pkt.size;
+        po.packet = ofpbuf_data(&pkt);
+        po.packet_len = ofpbuf_size(&pkt);
     } else {
         po.packet = NULL;
         po.packet_len = 0;
     }
     po.in_port = pi.fmd.in_port;
-    po.ofpacts = ofpacts.data;
-    po.ofpacts_len = ofpacts.size;
+    po.ofpacts = ofpbuf_data(&ofpacts);
+    po.ofpacts_len = ofpbuf_size(&ofpacts);
 
     /* Send the packet, and possibly the whole flow, to the output port. */
     if (sw->max_idle >= 0 && (!sw->ml || out_port != OFPP_FLOOD)) {
@@ -624,8 +624,8 @@ process_packet_in(struct lswitch *sw, const struct ofp_header *oh)
         fm.idle_timeout = sw->max_idle;
         fm.buffer_id = pi.buffer_id;
         fm.out_port = OFPP_NONE;
-        fm.ofpacts = ofpacts.data;
-        fm.ofpacts_len = ofpacts.size;
+        fm.ofpacts = ofpbuf_data(&ofpacts);
+        fm.ofpacts_len = ofpbuf_size(&ofpacts);
         buffer = ofputil_encode_flow_mod(&fm, sw->protocol);
 
         queue_tx(sw, buffer);
index c83f469..d157bc6 100644 (file)
@@ -122,7 +122,10 @@ lockfile_lock(const char *file, struct lockfile **lockfilep)
         if (error == EACCES) {
             error = EAGAIN;
         }
-        if (pid) {
+        if (pid == getpid()) {
+            VLOG_WARN("%s: cannot lock file because this process has already "
+                      "locked it", lock_name);
+        } else if (pid) {
             VLOG_WARN("%s: cannot lock file because it is already locked by "
                       "pid %ld", lock_name, (long int) pid);
         } else {
@@ -307,6 +310,7 @@ lockfile_try_lock(const char *name, pid_t *pidp, struct lockfile **lockfilep)
     /* Check whether we've already got a lock on that file. */
     if (!stat(name, &s)) {
         if (lockfile_find(s.st_dev, s.st_ino)) {
+            *pidp = getpid();
             return EDEADLK;
         }
     } else if (errno != ENOENT) {
index 2969972..514e7f9 100644 (file)
@@ -788,6 +788,34 @@ match_hash(const struct match *match, uint32_t basis)
     return flow_wildcards_hash(&match->wc, flow_hash(&match->flow, basis));
 }
 
+static bool
+match_has_default_recirc_id(const struct match *m)
+{
+    return m->flow.recirc_id == 0 && (m->wc.masks.recirc_id == UINT32_MAX ||
+                                      m->wc.masks.recirc_id == 0);
+}
+
+static bool
+match_has_default_dp_hash(const struct match *m)
+{
+    return ((m->flow.dp_hash | m->wc.masks.dp_hash) == 0);
+}
+
+/* Return true if the hidden fields of the match are set to the default values.
+ * The default values equals to those set up by match_init_hidden_fields(). */
+bool
+match_has_default_hidden_fields(const struct match *m)
+{
+    return match_has_default_recirc_id(m) && match_has_default_dp_hash(m);
+}
+
+void
+match_init_hidden_fields(struct match *m)
+{
+    match_set_recirc_id(m, 0);
+    match_set_dp_hash_masked(m, 0, 0);
+}
+
 static void
 format_eth_masked(struct ds *s, const char *name, const uint8_t eth[6],
                   const uint8_t mask[6])
index 95c8e67..2422fb1 100644 (file)
@@ -134,6 +134,9 @@ void match_set_nd_target_masked(struct match *, const struct in6_addr *,
 bool match_equal(const struct match *, const struct match *);
 uint32_t match_hash(const struct match *, uint32_t basis);
 
+void match_init_hidden_fields(struct match *);
+bool match_has_default_hidden_fields(const struct match *);
+
 void match_format(const struct match *, struct ds *, unsigned int priority);
 char *match_to_string(const struct match *, unsigned int priority);
 void match_print(const struct match *);
index 9952aef..cb4f5e8 100644 (file)
@@ -577,13 +577,13 @@ netdev_rxq_bsd_recv_pcap(struct netdev_rxq_bsd *rxq, struct ofpbuf *buffer)
 
     /* prepare the pcap argument to store the packet */
     arg.size = ofpbuf_tailroom(buffer);
-    arg.data = buffer->data;
+    arg.data = ofpbuf_data(buffer);
 
     for (;;) {
         ret = pcap_dispatch(rxq->pcap_handle, 1, proc_pkt, (u_char *) &arg);
 
         if (ret > 0) {
-            buffer->size += arg.retval;
+            ofpbuf_set_size(buffer, ofpbuf_size(buffer) + arg.retval);
             return 0;
         }
         if (ret == -1) {
@@ -607,9 +607,9 @@ netdev_rxq_bsd_recv_tap(struct netdev_rxq_bsd *rxq, struct ofpbuf *buffer)
     size_t size = ofpbuf_tailroom(buffer);
 
     for (;;) {
-        ssize_t retval = read(rxq->fd, buffer->data, size);
+        ssize_t retval = read(rxq->fd, ofpbuf_data(buffer), size);
         if (retval >= 0) {
-            buffer->size += retval;
+            ofpbuf_set_size(buffer, ofpbuf_size(buffer) + retval);
             return 0;
         } else if (errno != EINTR) {
             if (errno != EAGAIN) {
@@ -687,8 +687,8 @@ netdev_bsd_send(struct netdev *netdev_, struct ofpbuf *pkt, bool may_steal)
 {
     struct netdev_bsd *dev = netdev_bsd_cast(netdev_);
     const char *name = netdev_get_name(netdev_);
-    const void *data = pkt->data;
-    size_t size = pkt->size;
+    const void *data = ofpbuf_data(pkt);
+    size_t size = ofpbuf_size(pkt);
     int error;
 
     ovs_mutex_lock(&dev->mutex);
index f6adf87..4b36f52 100644 (file)
@@ -209,16 +209,53 @@ dpdk_rte_mzalloc(size_t sz)
 void
 free_dpdk_buf(struct ofpbuf *b)
 {
-    struct rte_mbuf *pkt;
-
-    pkt = b->private_p;
-    if (!pkt) {
-        return;
-    }
+    struct rte_mbuf *pkt = (struct rte_mbuf *) b;
 
     rte_mempool_put(pkt->pool, pkt);
 }
 
+static void
+__rte_pktmbuf_init(struct rte_mempool *mp,
+                   void *opaque_arg OVS_UNUSED,
+                   void *_m,
+                   unsigned i OVS_UNUSED)
+{
+    struct rte_mbuf *m = _m;
+    uint32_t buf_len = mp->elt_size - sizeof(struct ofpbuf);
+
+    RTE_MBUF_ASSERT(mp->elt_size >= sizeof(struct ofpbuf));
+
+    memset(m, 0, mp->elt_size);
+
+    /* start of buffer is just after mbuf structure */
+    m->buf_addr = (char *)m + sizeof(struct ofpbuf);
+    m->buf_physaddr = rte_mempool_virt2phy(mp, m) +
+                    sizeof(struct ofpbuf);
+    m->buf_len = (uint16_t)buf_len;
+
+    /* keep some headroom between start of buffer and data */
+    m->pkt.data = (char*) m->buf_addr + RTE_MIN(RTE_PKTMBUF_HEADROOM, m->buf_len);
+
+    /* init some constant fields */
+    m->type = RTE_MBUF_PKT;
+    m->pool = mp;
+    m->pkt.nb_segs = 1;
+    m->pkt.in_port = 0xff;
+}
+
+static void
+ovs_rte_pktmbuf_init(struct rte_mempool *mp,
+                     void *opaque_arg OVS_UNUSED,
+                     void *_m,
+                     unsigned i OVS_UNUSED)
+{
+    struct rte_mbuf *m = _m;
+
+    __rte_pktmbuf_init(mp, opaque_arg, _m, i);
+
+    ofpbuf_init_dpdk((struct ofpbuf *) m, m->buf_len);
+}
+
 static struct dpdk_mp *
 dpdk_mp_get(int socket_id, int mtu) OVS_REQUIRES(dpdk_mutex)
 {
@@ -242,7 +279,7 @@ dpdk_mp_get(int socket_id, int mtu) OVS_REQUIRES(dpdk_mutex)
                                  MP_CACHE_SZ,
                                  sizeof(struct rte_pktmbuf_pool_private),
                                  rte_pktmbuf_pool_init, NULL,
-                                 rte_pktmbuf_init, NULL,
+                                 ovs_rte_pktmbuf_init, NULL,
                                  socket_id, 0);
 
     if (dmp->mp == NULL) {
@@ -550,47 +587,22 @@ dpdk_queue_flush(struct netdev_dpdk *dev, int qid)
     rte_spinlock_unlock(&txq->tx_lock);
 }
 
-inline static struct ofpbuf *
-build_ofpbuf(struct rte_mbuf *pkt)
-{
-    struct ofpbuf *b;
-
-    b = ofpbuf_new(0);
-    b->private_p = pkt;
-
-    b->data = pkt->pkt.data;
-    b->base = (char *)b->data - DP_NETDEV_HEADROOM - VLAN_ETH_HEADER_LEN;
-    b->allocated = pkt->buf_len;
-    b->source = OFPBUF_DPDK;
-    b->size = rte_pktmbuf_data_len(pkt);
-
-    dp_packet_pad(b);
-
-    return b;
-}
-
 static int
-netdev_dpdk_rxq_recv(struct netdev_rxq *rxq_, struct ofpbuf **packet, int *c)
+netdev_dpdk_rxq_recv(struct netdev_rxq *rxq_, struct ofpbuf **packets, int *c)
 {
     struct netdev_rxq_dpdk *rx = netdev_rxq_dpdk_cast(rxq_);
     struct netdev *netdev = rx->up.netdev;
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
-    struct rte_mbuf *burst_pkts[MAX_RX_QUEUE_LEN];
     int nb_rx;
-    int i;
 
     dpdk_queue_flush(dev, rxq_->queue_id);
 
     nb_rx = rte_eth_rx_burst(rx->port_id, rxq_->queue_id,
-                             burst_pkts, MAX_RX_QUEUE_LEN);
+                             (struct rte_mbuf **) packets, MAX_RX_QUEUE_LEN);
     if (!nb_rx) {
         return EAGAIN;
     }
 
-    for (i = 0; i < nb_rx; i++) {
-        packet[i] = build_ofpbuf(burst_pkts[i]);
-    }
-
     *c = nb_rx;
 
     return 0;
@@ -665,9 +677,9 @@ netdev_dpdk_send(struct netdev *netdev,
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
     int ret;
 
-    if (ofpbuf->size > dev->max_packet_len) {
+    if (ofpbuf_size(ofpbuf) > dev->max_packet_len) {
         VLOG_WARN_RL(&rl, "Too big size %d max_packet_len %d",
-                     (int)ofpbuf->size , dev->max_packet_len);
+                     (int)ofpbuf_size(ofpbuf) , dev->max_packet_len);
 
         ovs_mutex_lock(&dev->mutex);
         dev->stats.tx_dropped++;
@@ -677,32 +689,23 @@ netdev_dpdk_send(struct netdev *netdev,
         goto out;
     }
 
-    rte_prefetch0(&ofpbuf->private_p);
-    if (!may_steal ||
-        !ofpbuf->private_p || ofpbuf->source != OFPBUF_DPDK) {
-        dpdk_do_tx_copy(netdev, (char *) ofpbuf->data, ofpbuf->size);
+    if (!may_steal || ofpbuf->source != OFPBUF_DPDK) {
+        dpdk_do_tx_copy(netdev, (char *) ofpbuf_data(ofpbuf), ofpbuf_size(ofpbuf));
+
+        if (may_steal) {
+            ofpbuf_delete(ofpbuf);
+        }
     } else {
-        struct rte_mbuf *pkt;
         int qid;
 
-        pkt = ofpbuf->private_p;
-        ofpbuf->private_p = NULL;
-        rte_pktmbuf_data_len(pkt) = ofpbuf->size;
-        rte_pktmbuf_pkt_len(pkt) = ofpbuf->size;
-
         qid = rte_lcore_id() % NR_QUEUE;
 
-        dpdk_queue_pkt(dev, qid, pkt);
+        dpdk_queue_pkt(dev, qid, (struct rte_mbuf *)ofpbuf);
 
-        ofpbuf->private_p = NULL;
     }
     ret = 0;
 
 out:
-    if (may_steal) {
-        ofpbuf_delete(ofpbuf);
-    }
-
     return ret;
 }
 
index 784eff4..995e923 100644 (file)
@@ -198,11 +198,11 @@ dummy_packet_stream_run(struct netdev_dummy *dev, struct dummy_packet_stream *s)
         int retval;
 
         txbuf = ofpbuf_from_list(list_front(&s->txq));
-        retval = stream_send(s->stream, txbuf->data, txbuf->size);
+        retval = stream_send(s->stream, ofpbuf_data(txbuf), ofpbuf_size(txbuf));
 
         if (retval > 0) {
             ofpbuf_pull(txbuf, retval);
-            if (!txbuf->size) {
+            if (!ofpbuf_size(txbuf)) {
                 list_remove(&txbuf->list_node);
                 ofpbuf_delete(txbuf);
             }
@@ -212,17 +212,17 @@ dummy_packet_stream_run(struct netdev_dummy *dev, struct dummy_packet_stream *s)
     }
 
     if (!error) {
-        if (s->rxbuf.size < 2) {
-            n = 2 - s->rxbuf.size;
+        if (ofpbuf_size(&s->rxbuf) < 2) {
+            n = 2 - ofpbuf_size(&s->rxbuf);
         } else {
             uint16_t frame_len;
 
-            frame_len = ntohs(get_unaligned_be16(s->rxbuf.data));
+            frame_len = ntohs(get_unaligned_be16(ofpbuf_data(&s->rxbuf)));
             if (frame_len < ETH_HEADER_LEN) {
                 error = EPROTO;
                 n = 0;
             } else {
-                n = (2 + frame_len) - s->rxbuf.size;
+                n = (2 + frame_len) - ofpbuf_size(&s->rxbuf);
             }
         }
     }
@@ -233,8 +233,8 @@ dummy_packet_stream_run(struct netdev_dummy *dev, struct dummy_packet_stream *s)
         retval = stream_recv(s->stream, ofpbuf_tail(&s->rxbuf), n);
 
         if (retval > 0) {
-            s->rxbuf.size += retval;
-            if (retval == n && s->rxbuf.size > 2) {
+            ofpbuf_set_size(&s->rxbuf, ofpbuf_size(&s->rxbuf) + retval);
+            if (retval == n && ofpbuf_size(&s->rxbuf) > 2) {
                 ofpbuf_pull(&s->rxbuf, 2);
                 netdev_dummy_queue_packet(dev,
                                           ofpbuf_clone(&s->rxbuf));
@@ -242,7 +242,7 @@ dummy_packet_stream_run(struct netdev_dummy *dev, struct dummy_packet_stream *s)
             }
         } else if (retval != -EAGAIN) {
             error = (retval < 0 ? -retval
-                     : s->rxbuf.size ? EPROTO
+                     : ofpbuf_size(&s->rxbuf) ? EPROTO
                      : EOF);
         }
     }
@@ -776,7 +776,7 @@ netdev_dummy_rxq_recv(struct netdev_rxq *rxq_, struct ofpbuf **arr, int *c)
     }
     ovs_mutex_lock(&netdev->mutex);
     netdev->stats.rx_packets++;
-    netdev->stats.rx_bytes += packet->size;
+    netdev->stats.rx_bytes += ofpbuf_size(packet);
     ovs_mutex_unlock(&netdev->mutex);
 
     dp_packet_pad(packet);
@@ -821,8 +821,8 @@ static int
 netdev_dummy_send(struct netdev *netdev, struct ofpbuf *pkt, bool may_steal)
 {
     struct netdev_dummy *dev = netdev_dummy_cast(netdev);
-    const void *buffer = pkt->data;
-    size_t size = pkt->size;
+    const void *buffer = ofpbuf_data(pkt);
+    size_t size = ofpbuf_size(pkt);
 
     if (size < ETH_HEADER_LEN) {
         return EMSGSIZE;
@@ -1082,7 +1082,7 @@ eth_from_packet_or_flow(const char *s)
     }
 
     /* Convert odp_key to flow. */
-    fitness = odp_flow_key_to_flow(odp_key.data, odp_key.size, &flow);
+    fitness = odp_flow_key_to_flow(ofpbuf_data(&odp_key), ofpbuf_size(&odp_key), &flow);
     if (fitness == ODP_FIT_ERROR) {
         ofpbuf_uninit(&odp_key);
         return NULL;
index 6848850..f9634b6 100644 (file)
@@ -919,7 +919,7 @@ netdev_linux_rxq_recv_sock(int fd, struct ofpbuf *buffer)
     ofpbuf_reserve(buffer, VLAN_HEADER_LEN);
     size = ofpbuf_tailroom(buffer);
 
-    iov.iov_base = buffer->data;
+    iov.iov_base = ofpbuf_data(buffer);
     iov.iov_len = size;
     msgh.msg_name = NULL;
     msgh.msg_namelen = 0;
@@ -939,7 +939,7 @@ netdev_linux_rxq_recv_sock(int fd, struct ofpbuf *buffer)
         return EMSGSIZE;
     }
 
-    buffer->size += retval;
+    ofpbuf_set_size(buffer, ofpbuf_size(buffer) + retval);
 
     for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg; cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
         const struct tpacket_auxdata *aux;
@@ -972,7 +972,7 @@ netdev_linux_rxq_recv_tap(int fd, struct ofpbuf *buffer)
     size_t size = ofpbuf_tailroom(buffer);
 
     do {
-        retval = read(fd, buffer->data, size);
+        retval = read(fd, ofpbuf_data(buffer), size);
     } while (retval < 0 && errno == EINTR);
 
     if (retval < 0) {
@@ -981,7 +981,7 @@ netdev_linux_rxq_recv_tap(int fd, struct ofpbuf *buffer)
         return EMSGSIZE;
     }
 
-    buffer->size += retval;
+    ofpbuf_set_size(buffer, ofpbuf_size(buffer) + retval);
     return 0;
 }
 
@@ -1056,8 +1056,8 @@ netdev_linux_rxq_drain(struct netdev_rxq *rxq_)
 static int
 netdev_linux_send(struct netdev *netdev_, struct ofpbuf *pkt, bool may_steal)
 {
-    const void *data = pkt->data;
-    size_t size = pkt->size;
+    const void *data = ofpbuf_data(pkt);
+    size_t size = ofpbuf_size(pkt);
 
     for (;;) {
         ssize_t retval;
index 8c8d16b..e4cc4ad 100644 (file)
@@ -250,15 +250,15 @@ nl_sock_send__(struct nl_sock *sock, const struct ofpbuf *msg,
     struct nlmsghdr *nlmsg = nl_msg_nlmsghdr(msg);
     int error;
 
-    nlmsg->nlmsg_len = msg->size;
+    nlmsg->nlmsg_len = ofpbuf_size(msg);
     nlmsg->nlmsg_seq = nlmsg_seq;
     nlmsg->nlmsg_pid = sock->pid;
     do {
         int retval;
-        retval = send(sock->fd, msg->data, msg->size, wait ? 0 : MSG_DONTWAIT);
+        retval = send(sock->fd, ofpbuf_data(msg), ofpbuf_size(msg), wait ? 0 : MSG_DONTWAIT);
         error = retval < 0 ? errno : 0;
     } while (error == EINTR);
-    log_nlmsg(__func__, error, msg->data, msg->size, sock->protocol);
+    log_nlmsg(__func__, error, ofpbuf_data(msg), ofpbuf_size(msg), sock->protocol);
     if (!error) {
         COVERAGE_INC(netlink_sent);
     }
@@ -266,7 +266,7 @@ nl_sock_send__(struct nl_sock *sock, const struct ofpbuf *msg,
 }
 
 /* Tries to send 'msg', which must contain a Netlink message, to the kernel on
- * 'sock'.  nlmsg_len in 'msg' will be finalized to match msg->size, nlmsg_pid
+ * 'sock'.  nlmsg_len in 'msg' will be finalized to match ofpbuf_size(msg), nlmsg_pid
  * will be set to 'sock''s pid, and nlmsg_seq will be initialized to a fresh
  * sequence number, before the message is sent.
  *
@@ -280,7 +280,7 @@ nl_sock_send(struct nl_sock *sock, const struct ofpbuf *msg, bool wait)
 }
 
 /* Tries to send 'msg', which must contain a Netlink message, to the kernel on
- * 'sock'.  nlmsg_len in 'msg' will be finalized to match msg->size, nlmsg_pid
+ * 'sock'.  nlmsg_len in 'msg' will be finalized to match ofpbuf_size(msg), nlmsg_pid
  * will be set to 'sock''s pid, and nlmsg_seq will be initialized to
  * 'nlmsg_seq', before the message is sent.
  *
@@ -314,7 +314,7 @@ nl_sock_recv__(struct nl_sock *sock, struct ofpbuf *buf, bool wait)
     ovs_assert(buf->allocated >= sizeof *nlmsghdr);
     ofpbuf_clear(buf);
 
-    iov[0].iov_base = buf->base;
+    iov[0].iov_base = ofpbuf_base(buf);
     iov[0].iov_len = buf->allocated;
     iov[1].iov_base = tail;
     iov[1].iov_len = sizeof tail;
@@ -343,7 +343,7 @@ nl_sock_recv__(struct nl_sock *sock, struct ofpbuf *buf, bool wait)
         return E2BIG;
     }
 
-    nlmsghdr = buf->data;
+    nlmsghdr = ofpbuf_data(buf);
     if (retval < sizeof *nlmsghdr
         || nlmsghdr->nlmsg_len < sizeof *nlmsghdr
         || nlmsghdr->nlmsg_len > retval) {
@@ -352,13 +352,13 @@ nl_sock_recv__(struct nl_sock *sock, struct ofpbuf *buf, bool wait)
         return EPROTO;
     }
 
-    buf->size = MIN(retval, buf->allocated);
+    ofpbuf_set_size(buf, MIN(retval, buf->allocated));
     if (retval > buf->allocated) {
         COVERAGE_INC(netlink_recv_jumbo);
         ofpbuf_put(buf, tail, retval - buf->allocated);
     }
 
-    log_nlmsg(__func__, 0, buf->data, buf->size, sock->protocol);
+    log_nlmsg(__func__, 0, ofpbuf_data(buf), ofpbuf_size(buf), sock->protocol);
     COVERAGE_INC(netlink_received);
 
     return 0;
@@ -424,12 +424,12 @@ nl_sock_transact_multiple__(struct nl_sock *sock,
         struct nl_transaction *txn = transactions[i];
         struct nlmsghdr *nlmsg = nl_msg_nlmsghdr(txn->request);
 
-        nlmsg->nlmsg_len = txn->request->size;
+        nlmsg->nlmsg_len = ofpbuf_size(txn->request);
         nlmsg->nlmsg_seq = base_seq + i;
         nlmsg->nlmsg_pid = sock->pid;
 
-        iovs[i].iov_base = txn->request->data;
-        iovs[i].iov_len = txn->request->size;
+        iovs[i].iov_base = ofpbuf_data(txn->request);
+        iovs[i].iov_len = ofpbuf_size(txn->request);
     }
 
     memset(&msg, 0, sizeof msg);
@@ -442,7 +442,7 @@ nl_sock_transact_multiple__(struct nl_sock *sock,
     for (i = 0; i < n; i++) {
         struct nl_transaction *txn = transactions[i];
 
-        log_nlmsg(__func__, error, txn->request->data, txn->request->size,
+        log_nlmsg(__func__, error, ofpbuf_data(txn->request), ofpbuf_size(txn->request),
                   sock->protocol);
     }
     if (!error) {
@@ -579,12 +579,12 @@ nl_sock_transact_multiple(struct nl_sock *sock,
 #else
         enum { MAX_BATCH_BYTES = 4096 - 512 };
 #endif
-        bytes = transactions[0]->request->size;
+        bytes = ofpbuf_size(transactions[0]->request);
         for (count = 1; count < n && count < max_batch_count; count++) {
-            if (bytes + transactions[count]->request->size > MAX_BATCH_BYTES) {
+            if (bytes + ofpbuf_size(transactions[count]->request) > MAX_BATCH_BYTES) {
                 break;
             }
-            bytes += transactions[count]->request->size;
+            bytes += ofpbuf_size(transactions[count]->request);
         }
 
         error = nl_sock_transact_multiple__(sock, transactions, count, &done);
@@ -609,7 +609,7 @@ nl_sock_transact_multiple(struct nl_sock *sock,
  * reply, if any, is discarded.
  *
  * Before the message is sent, nlmsg_len in 'request' will be finalized to
- * match msg->size, nlmsg_pid will be set to 'sock''s pid, and nlmsg_seq will
+ * match ofpbuf_size(msg), nlmsg_pid will be set to 'sock''s pid, and nlmsg_seq will
  * be initialized, NLM_F_ACK will be set in nlmsg_flags.
  *
  * The caller is responsible for destroying 'request'.
@@ -709,12 +709,12 @@ nl_dump_start(struct nl_dump *dump, int protocol, const struct ofpbuf *request)
  * have been initialized with nl_dump_start(), and 'buffer' must have been
  * initialized. 'buffer' should be at least NL_DUMP_BUFSIZE bytes long.
  *
- * If successful, returns true and points 'reply->data' and 'reply->size' to
+ * If successful, returns true and points 'reply->data' and 'ofpbuf_size(reply)' to
  * the message that was retrieved. The caller must not modify 'reply' (because
  * it points within 'buffer', which will be used by future calls to this
  * function).
  *
- * On failure, returns false and sets 'reply->data' to NULL and 'reply->size'
+ * On failure, returns false and sets 'reply->data' to NULL and 'ofpbuf_size(reply)'
  * to 0.  Failure might indicate an actual error or merely the end of replies.
  * An error status for the entire dump operation is provided when it is
  * completed by calling nl_dump_done().
@@ -731,11 +731,11 @@ nl_dump_next(struct nl_dump *dump, struct ofpbuf *reply, struct ofpbuf *buffer)
     struct nlmsghdr *nlmsghdr;
     int error = 0;
 
-    reply->data = NULL;
-    reply->size = 0;
+    ofpbuf_set_data(reply, NULL);
+    ofpbuf_set_size(reply, 0);
 
     /* If 'buffer' is empty, fetch another batch of nlmsgs. */
-    while (!buffer->size) {
+    while (!ofpbuf_size(buffer)) {
         unsigned int status;
         int retval, seq;
 
index 96abe46..bbd6b6d 100644 (file)
@@ -67,7 +67,7 @@ nl_msg_nlmsgerr(const struct ofpbuf *msg, int *errorp)
         int code = EPROTO;
         if (!err) {
             VLOG_ERR_RL(&rl, "received invalid nlmsgerr (%"PRIu32"d bytes < %"PRIuSIZE"d)",
-                        msg->size, NLMSG_HDRLEN + sizeof *err);
+                        ofpbuf_size(msg), NLMSG_HDRLEN + sizeof *err);
         } else if (err->error <= 0 && err->error > INT_MIN) {
             code = -err->error;
         }
@@ -113,7 +113,7 @@ nl_msg_put_nlmsghdr(struct ofpbuf *msg,
 {
     struct nlmsghdr *nlmsghdr;
 
-    ovs_assert(msg->size == 0);
+    ovs_assert(ofpbuf_size(msg) == 0);
 
     nl_msg_reserve(msg, NLMSG_HDRLEN + expected_payload);
     nlmsghdr = nl_msg_put_uninit(msg, NLMSG_HDRLEN);
@@ -152,7 +152,7 @@ nl_msg_put_genlmsghdr(struct ofpbuf *msg, size_t expected_payload,
     struct genlmsghdr *genlmsghdr;
 
     nl_msg_put_nlmsghdr(msg, GENL_HDRLEN + expected_payload, family, flags);
-    ovs_assert(msg->size == NLMSG_HDRLEN);
+    ovs_assert(ofpbuf_size(msg) == NLMSG_HDRLEN);
     genlmsghdr = nl_msg_put_uninit(msg, GENL_HDRLEN);
     genlmsghdr->cmd = cmd;
     genlmsghdr->version = version;
@@ -432,7 +432,7 @@ nl_msg_push_string(struct ofpbuf *msg, uint16_t type, const char *value)
 size_t
 nl_msg_start_nested(struct ofpbuf *msg, uint16_t type)
 {
-    size_t offset = msg->size;
+    size_t offset = ofpbuf_size(msg);
     nl_msg_put_unspec(msg, type, NULL, 0);
     return offset;
 }
@@ -443,7 +443,7 @@ void
 nl_msg_end_nested(struct ofpbuf *msg, size_t offset)
 {
     struct nlattr *attr = ofpbuf_at_assert(msg, offset, sizeof *attr);
-    attr->nla_len = msg->size - offset;
+    attr->nla_len = ofpbuf_size(msg) - offset;
 }
 
 /* Appends a nested Netlink attribute of the given 'type', with the 'size'
@@ -459,25 +459,25 @@ nl_msg_put_nested(struct ofpbuf *msg,
 
 /* If 'buffer' begins with a valid "struct nlmsghdr", pulls the header and its
  * payload off 'buffer', stores header and payload in 'msg->data' and
- * 'msg->size', and returns a pointer to the header.
+ * 'ofpbuf_size(msg)', and returns a pointer to the header.
  *
  * If 'buffer' does not begin with a "struct nlmsghdr" or begins with one that
  * is invalid, returns NULL without modifying 'buffer'. */
 struct nlmsghdr *
 nl_msg_next(struct ofpbuf *buffer, struct ofpbuf *msg)
 {
-    if (buffer->size >= sizeof(struct nlmsghdr)) {
+    if (ofpbuf_size(buffer) >= sizeof(struct nlmsghdr)) {
         struct nlmsghdr *nlmsghdr = nl_msg_nlmsghdr(buffer);
         size_t len = nlmsghdr->nlmsg_len;
-        if (len >= sizeof *nlmsghdr && len <= buffer->size) {
+        if (len >= sizeof *nlmsghdr && len <= ofpbuf_size(buffer)) {
             ofpbuf_use_const(msg, nlmsghdr, len);
             ofpbuf_pull(buffer, len);
             return nlmsghdr;
         }
     }
 
-    msg->data = NULL;
-    msg->size = 0;
+    ofpbuf_set_data(msg, NULL);
+    ofpbuf_set_size(msg, 0);
     return NULL;
 }
 
@@ -728,13 +728,13 @@ nl_policy_parse(const struct ofpbuf *msg, size_t nla_offset,
 
     memset(attrs, 0, n_attrs * sizeof *attrs);
 
-    if (msg->size < nla_offset) {
+    if (ofpbuf_size(msg) < nla_offset) {
         VLOG_DBG_RL(&rl, "missing headers in nl_policy_parse");
         return false;
     }
 
     NL_ATTR_FOR_EACH (nla, left, ofpbuf_at(msg, nla_offset, 0),
-                      msg->size - nla_offset)
+                      ofpbuf_size(msg) - nla_offset)
     {
         uint16_t type = nl_attr_type(nla);
         if (type < n_attrs && policy[type].type != NL_A_NO_ATTR) {
@@ -798,7 +798,7 @@ nl_attr_find__(const struct nlattr *attrs, size_t size, uint16_t type)
 const struct nlattr *
 nl_attr_find(const struct ofpbuf *buf, size_t hdr_len, uint16_t type)
 {
-    return nl_attr_find__(ofpbuf_at(buf, hdr_len, 0), buf->size - hdr_len,
+    return nl_attr_find__(ofpbuf_at(buf, hdr_len, 0), ofpbuf_size(buf) - hdr_len,
                           type);
 }
 
index cd3bf08..ed491ef 100644 (file)
@@ -215,7 +215,7 @@ nx_pull_match__(struct ofpbuf *b, unsigned int match_len, bool strict,
         if (!p) {
             VLOG_DBG_RL(&rl, "nx_match length %u, rounded up to a "
                         "multiple of 8, is longer than space in message (max "
-                        "length %"PRIu32")", match_len, b->size);
+                        "length %"PRIu32")", match_len, ofpbuf_size(b));
             return OFPERR_OFPBMC_BAD_LEN;
         }
     }
@@ -251,11 +251,11 @@ nx_pull_match_loose(struct ofpbuf *b, unsigned int match_len,
 static enum ofperr
 oxm_pull_match__(struct ofpbuf *b, bool strict, struct match *match)
 {
-    struct ofp11_match_header *omh = b->data;
+    struct ofp11_match_header *omh = ofpbuf_data(b);
     uint8_t *p;
     uint16_t match_len;
 
-    if (b->size < sizeof *omh) {
+    if (ofpbuf_size(b) < sizeof *omh) {
         return OFPERR_OFPBMC_BAD_LEN;
     }
 
@@ -272,7 +272,7 @@ oxm_pull_match__(struct ofpbuf *b, bool strict, struct match *match)
     if (!p) {
         VLOG_DBG_RL(&rl, "oxm length %u, rounded up to a "
                     "multiple of 8, is longer than space in message (max "
-                    "length %"PRIu32")", match_len, b->size);
+                    "length %"PRIu32")", match_len, ofpbuf_size(b));
         return OFPERR_OFPBMC_BAD_LEN;
     }
 
@@ -568,7 +568,7 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match *match,
            ovs_be64 cookie, ovs_be64 cookie_mask)
 {
     const struct flow *flow = &match->flow;
-    const size_t start_len = b->size;
+    const size_t start_len = ofpbuf_size(b);
     int match_len;
     int i;
 
@@ -723,7 +723,7 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match *match,
     /* Cookie. */
     nxm_put_64m(b, NXM_NX_COOKIE, cookie, cookie_mask);
 
-    match_len = b->size - start_len;
+    match_len = ofpbuf_size(b) - start_len;
     return match_len;
 }
 
@@ -761,7 +761,7 @@ oxm_put_match(struct ofpbuf *b, const struct match *match)
 {
     int match_len;
     struct ofp11_match_header *omh;
-    size_t start_len = b->size;
+    size_t start_len = ofpbuf_size(b);
     ovs_be64 cookie = htonll(0), cookie_mask = htonll(0);
 
     ofpbuf_put_uninit(b, sizeof *omh);
@@ -833,7 +833,7 @@ nx_match_to_string(const uint8_t *p, unsigned int match_len)
 char *
 oxm_match_to_string(const struct ofpbuf *p, unsigned int match_len)
 {
-    const struct ofp11_match_header *omh = p->data;
+    const struct ofp11_match_header *omh = ofpbuf_data(p);
     uint16_t match_len_;
     struct ds s;
 
@@ -948,10 +948,10 @@ static int
 nx_match_from_string_raw(const char *s, struct ofpbuf *b)
 {
     const char *full_s = s;
-    const size_t start_len = b->size;
+    const size_t start_len = ofpbuf_size(b);
 
     if (!strcmp(s, "<any>")) {
-        /* Ensure that 'b->data' isn't actually null. */
+        /* Ensure that 'ofpbuf_data(b)' isn't actually null. */
         ofpbuf_prealloc_tailroom(b, 1);
         return 0;
     }
@@ -1000,7 +1000,7 @@ nx_match_from_string_raw(const char *s, struct ofpbuf *b)
         s++;
     }
 
-    return b->size - start_len;
+    return ofpbuf_size(b) - start_len;
 }
 
 int
@@ -1016,7 +1016,7 @@ oxm_match_from_string(const char *s, struct ofpbuf *b)
 {
     int match_len;
     struct ofp11_match_header *omh;
-    size_t start_len = b->size;
+    size_t start_len = ofpbuf_size(b);
 
     ofpbuf_put_uninit(b, sizeof *omh);
     match_len = nx_match_from_string_raw(s, b) + sizeof *omh;
@@ -1385,8 +1385,9 @@ nx_stack_pop(struct ofpbuf *stack)
 {
     union mf_subvalue *v = NULL;
 
-    if (stack->size) {
-        stack->size -= sizeof *v;
+    if (ofpbuf_size(stack)) {
+
+        ofpbuf_set_size(stack, ofpbuf_size(stack) - sizeof *v);
         v = (union mf_subvalue *) ofpbuf_tail(stack);
     }
 
index e5aa0ce..37e44e3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  * Copyright (c) 2013 Simon Horman
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -33,10 +33,12 @@ static void
 odp_eth_set_addrs(struct ofpbuf *packet,
                   const struct ovs_key_ethernet *eth_key)
 {
-    struct eth_header *eh = packet->l2;
+    struct eth_header *eh = ofpbuf_l2(packet);
 
-    memcpy(eh->eth_src, eth_key->eth_src, sizeof eh->eth_src);
-    memcpy(eh->eth_dst, eth_key->eth_dst, sizeof eh->eth_dst);
+    if (eh) {
+        memcpy(eh->eth_src, eth_key->eth_src, sizeof eh->eth_src);
+        memcpy(eh->eth_dst, eth_key->eth_dst, sizeof eh->eth_dst);
+    }
 }
 
 static void
@@ -51,7 +53,7 @@ odp_set_tunnel_action(const struct nlattr *a, struct flow_tnl *tun_key)
 static void
 set_arp(struct ofpbuf *packet, const struct ovs_key_arp *arp_key)
 {
-    struct arp_eth_header *arp = ofpbuf_get_l3(packet);
+    struct arp_eth_header *arp = ofpbuf_l3(packet);
 
     arp->ar_op = arp_key->arp_op;
     memcpy(arp->ar_sha, arp_key->arp_sha, ETH_ADDR_LEN);
@@ -207,10 +209,11 @@ odp_execute_actions__(void *dp, struct ofpbuf *packet, bool steal,
         case OVS_ACTION_ATTR_USERSPACE:
         case OVS_ACTION_ATTR_RECIRC:
             if (dp_execute_action) {
-                bool may_steal;
                 /* Allow 'dp_execute_action' to steal the packet data if we do
                  * not need it any more. */
-                may_steal = steal && (!more_actions && left <= NLA_ALIGN(a->nla_len));
+                bool may_steal = steal && (!more_actions
+                                           && left <= NLA_ALIGN(a->nla_len)
+                                           && type != OVS_ACTION_ATTR_RECIRC);
                 dp_execute_action(dp, packet, md, a, may_steal);
             }
             break;
index 956fef1..b58f1c0 100644 (file)
@@ -605,7 +605,7 @@ parse_odp_action(const char *s, const struct simap *port_names,
             ofpbuf_init(&buf, 16);
             end = ofpbuf_put_hex(&buf, &s[n], NULL);
             if (end[0] == ')' && end[1] == ')') {
-                odp_put_userspace_action(pid, buf.data, buf.size, actions);
+                odp_put_userspace_action(pid, ofpbuf_data(&buf), ofpbuf_size(&buf), actions);
                 ofpbuf_uninit(&buf);
                 return (end + 2) - s;
             }
@@ -715,7 +715,7 @@ odp_actions_from_string(const char *s, const struct simap *port_names,
         return 0;
     }
 
-    old_size = actions->size;
+    old_size = ofpbuf_size(actions);
     for (;;) {
         int retval;
 
@@ -726,7 +726,7 @@ odp_actions_from_string(const char *s, const struct simap *port_names,
 
         retval = parse_odp_action(s, port_names, actions);
         if (retval < 0 || !strchr(delimiters, s[retval])) {
-            actions->size = old_size;
+            ofpbuf_set_size(actions, old_size);
             return -retval;
         }
         s += retval;
@@ -1442,7 +1442,7 @@ generate_all_wildcard_mask(struct ofpbuf *ofp, const struct nlattr *key)
         nl_msg_end_nested(ofp, nested_mask);
     }
 
-    return ofp->base;
+    return ofpbuf_base(ofp);
 }
 
 /* Appends to 'ds' a string representation of the 'key_len' bytes of
@@ -2430,7 +2430,7 @@ int
 odp_flow_from_string(const char *s, const struct simap *port_names,
                      struct ofpbuf *key, struct ofpbuf *mask)
 {
-    const size_t old_size = key->size;
+    const size_t old_size = ofpbuf_size(key);
     for (;;) {
         int retval;
 
@@ -2441,7 +2441,7 @@ odp_flow_from_string(const char *s, const struct simap *port_names,
 
         retval = parse_odp_key_mask_attr(s, port_names, key, mask);
         if (retval < 0) {
-            key->size = old_size;
+            ofpbuf_set_size(key, old_size);
             return -retval;
         }
         s += retval;
@@ -3448,7 +3448,7 @@ odp_put_userspace_action(uint32_t pid,
     offset = nl_msg_start_nested(odp_actions, OVS_ACTION_ATTR_USERSPACE);
     nl_msg_put_u32(odp_actions, OVS_USERSPACE_ATTR_PID, pid);
     if (userdata) {
-        userdata_ofs = odp_actions->size + NLA_HDRLEN;
+        userdata_ofs = ofpbuf_size(odp_actions) + NLA_HDRLEN;
 
         /* The OVS kernel module before OVS 1.11 and the upstream Linux kernel
          * module before Linux 3.10 required the userdata to be exactly 8 bytes
index 23d89d3..ce14004 100644 (file)
@@ -225,7 +225,7 @@ dec_ttl_from_openflow(struct ofpbuf *out, enum ofputil_action_code compat)
     ids->ofpact.compat = compat;
     ids->n_controllers = 1;
     ofpbuf_put(out, &id, sizeof id);
-    ids = out->l2;
+    ids = out->frame;
     ofpact_update_len(out, &ids->ofpact);
     return error;
 }
@@ -258,7 +258,7 @@ dec_ttl_cnt_ids_from_openflow(const struct nx_action_cnt_ids *nac_ids,
     for (i = 0; i < ids->n_controllers; i++) {
         uint16_t id = ntohs(((ovs_be16 *)(nac_ids + 1))[i]);
         ofpbuf_put(out, &id, sizeof id);
-        ids = out->l2;
+        ids = out->frame;
     }
 
     ofpact_update_len(out, &ids->ofpact);
@@ -711,7 +711,7 @@ ofpacts_pull_openflow_actions(struct ofpbuf *openflow,
     if (actions == NULL) {
         VLOG_WARN_RL(&rl, "OpenFlow message actions length %u exceeds "
                      "remaining message length (%"PRIu32")",
-                     actions_len, openflow->size);
+                     actions_len, ofpbuf_size(openflow));
         return OFPERR_OFPBRC_BAD_LEN;
     }
 
@@ -722,7 +722,7 @@ ofpacts_pull_openflow_actions(struct ofpbuf *openflow,
         return error;
     }
 
-    error = ofpacts_verify(ofpacts->data, ofpacts->size);
+    error = ofpacts_verify(ofpbuf_data(ofpacts), ofpbuf_size(ofpacts));
     if (error) {
         ofpbuf_clear(ofpacts);
     }
@@ -1077,7 +1077,7 @@ static void
 set_field_to_openflow(const struct ofpact_set_field *sf,
                       struct ofpbuf *openflow)
 {
-    struct ofp_header *oh = (struct ofp_header *)openflow->l2;
+    struct ofp_header *oh = (struct ofp_header *)openflow->frame;
 
     if (oh->version >= OFP12_VERSION) {
         set_field_to_openflow12(sf, openflow);
@@ -1420,7 +1420,7 @@ ofpacts_copy_last(struct ofpbuf *out, const struct ofpbuf *in,
     const struct ofpact *a;
 
     target = NULL;
-    OFPACT_FOR_EACH (a, in->data, in->size) {
+    OFPACT_FOR_EACH (a, ofpbuf_data(in), ofpbuf_size(in)) {
         if (a->type == filter) {
             target = a;
         }
@@ -1439,7 +1439,7 @@ ofpacts_copy_all(struct ofpbuf *out, const struct ofpbuf *in,
 {
     const struct ofpact *a;
 
-    OFPACT_FOR_EACH (a, in->data, in->size) {
+    OFPACT_FOR_EACH (a, ofpbuf_data(in), ofpbuf_size(in)) {
         if (filter(a)) {
             ofpact_copy(out, a);
         }
@@ -1497,7 +1497,7 @@ ofpacts_from_openflow11_for_action_set(const union ofp_action *in,
 {
     enum ofperr error;
     struct ofpact *a;
-    size_t start = out->size;
+    size_t start = ofpbuf_size(out);
 
     error = ofpacts_from_openflow(in, n_in, version, out);
 
@@ -1505,7 +1505,7 @@ ofpacts_from_openflow11_for_action_set(const union ofp_action *in,
         return error;
     }
 
-    OFPACT_FOR_EACH (a, ofpact_end(out->data, start), out->size - start) {
+    OFPACT_FOR_EACH (a, ofpact_end(ofpbuf_data(out), start), ofpbuf_size(out) - start) {
         if (!ofpact_is_allowed_in_actions_set(a)) {
             VLOG_WARN_RL(&rl, "disallowed action in action set");
             return OFPERR_OFPBAC_BAD_TYPE;
@@ -1769,7 +1769,7 @@ ofpacts_pull_openflow_instructions(struct ofpbuf *openflow,
     if (instructions == NULL) {
         VLOG_WARN_RL(&rl, "OpenFlow message instructions length %u exceeds "
                      "remaining message length (%"PRIu32")",
-                     instructions_len, openflow->size);
+                     instructions_len, ofpbuf_size(openflow));
         error = OFPERR_OFPBIC_BAD_LEN;
         goto exit;
     }
@@ -1814,7 +1814,7 @@ ofpacts_pull_openflow_instructions(struct ofpbuf *openflow,
         size_t start;
 
         ofpact_pad(ofpacts);
-        start = ofpacts->size;
+        start = ofpbuf_size(ofpacts);
         on = ofpact_put(ofpacts, OFPACT_WRITE_ACTIONS,
                         offsetof(struct ofpact_nest, actions));
         get_actions_from_instruction(insts[OVSINST_OFPIT11_WRITE_ACTIONS],
@@ -1825,7 +1825,7 @@ ofpacts_pull_openflow_instructions(struct ofpbuf *openflow,
             goto exit;
         }
         on = ofpbuf_at_assert(ofpacts, start, sizeof *on);
-        on->ofpact.len = ofpacts->size - start;
+        on->ofpact.len = ofpbuf_size(ofpacts) - start;
     }
     if (insts[OVSINST_OFPIT11_WRITE_METADATA]) {
         const struct ofp11_instruction_write_metadata *oiwm;
@@ -1848,7 +1848,7 @@ ofpacts_pull_openflow_instructions(struct ofpbuf *openflow,
         ogt->table_id = oigt->table_id;
     }
 
-    error = ofpacts_verify(ofpacts->data, ofpacts->size);
+    error = ofpacts_verify(ofpbuf_data(ofpacts), ofpbuf_size(ofpacts));
 exit:
     if (error) {
         ofpbuf_clear(ofpacts);
@@ -2288,23 +2288,23 @@ ofpact_write_metadata_to_nxast(const struct ofpact_metadata *om,
 static void
 ofpact_note_to_nxast(const struct ofpact_note *note, struct ofpbuf *out)
 {
-    size_t start_ofs = out->size;
+    size_t start_ofs = ofpbuf_size(out);
     struct nx_action_note *nan;
     unsigned int remainder;
     unsigned int len;
 
     nan = ofputil_put_NXAST_NOTE(out);
-    out->size -= sizeof nan->note;
+    ofpbuf_set_size(out, ofpbuf_size(out) - sizeof nan->note);
 
     ofpbuf_put(out, note->data, note->length);
 
-    len = out->size - start_ofs;
+    len = ofpbuf_size(out) - start_ofs;
     remainder = len % OFP_ACTION_ALIGN;
     if (remainder) {
         ofpbuf_put_zeros(out, OFP_ACTION_ALIGN - remainder);
     }
     nan = ofpbuf_at(out, start_ofs, sizeof *nan);
-    nan->len = htons(out->size - start_ofs);
+    nan->len = htons(ofpbuf_size(out) - start_ofs);
 }
 
 static void
@@ -2589,6 +2589,8 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out)
          * follow this action. */
         break;
 
+    case OFPACT_SET_IP_ECN:
+    case OFPACT_SET_IP_TTL:
     case OFPACT_CLEAR_ACTIONS:
     case OFPACT_WRITE_ACTIONS:
     case OFPACT_GOTO_TABLE:
@@ -2611,8 +2613,6 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_STACK_PUSH:
     case OFPACT_STACK_POP:
     case OFPACT_DEC_TTL:
-    case OFPACT_SET_IP_ECN:
-    case OFPACT_SET_IP_TTL:
     case OFPACT_SET_MPLS_LABEL:
     case OFPACT_SET_MPLS_TC:
     case OFPACT_SET_MPLS_TTL:
@@ -2981,7 +2981,7 @@ ofpacts_put_openflow_actions(const struct ofpact ofpacts[], size_t ofpacts_len,
                              enum ofp_version ofp_version)
 {
     const struct ofpact *a;
-    size_t start_size = openflow->size;
+    size_t start_size = ofpbuf_size(openflow);
 
     void (*translate)(const struct ofpact *a, struct ofpbuf *out) =
         (ofp_version == OFP10_VERSION) ? ofpact_to_openflow10 :
@@ -2991,7 +2991,7 @@ ofpacts_put_openflow_actions(const struct ofpact ofpacts[], size_t ofpacts_len,
     OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
         translate(a, openflow);
     }
-    return openflow->size - start_size;
+    return ofpbuf_size(openflow) - start_size;
 }
 
 static void
@@ -3001,10 +3001,10 @@ ofpacts_update_instruction_actions(struct ofpbuf *openflow, size_t ofs)
 
     /* Update the instruction's length (or, if it's empty, delete it). */
     oia = ofpbuf_at_assert(openflow, ofs, sizeof *oia);
-    if (openflow->size > ofs + sizeof *oia) {
-        oia->len = htons(openflow->size - ofs);
+    if (ofpbuf_size(openflow) > ofs + sizeof *oia) {
+        oia->len = htons(ofpbuf_size(openflow) - ofs);
     } else {
-        openflow->size = ofs;
+        ofpbuf_set_size(openflow, ofs);
     }
 }
 
@@ -3055,7 +3055,7 @@ ofpacts_put_openflow_instructions(const struct ofpact ofpacts[],
             break;
 
         case OVSINST_OFPIT11_APPLY_ACTIONS: {
-            const size_t ofs = openflow->size;
+            const size_t ofs = ofpbuf_size(openflow);
             const size_t ofpacts_len_left =
                 (uint8_t*)ofpact_end(ofpacts, ofpacts_len) - (uint8_t*)a;
             const struct ofpact *action;
@@ -3080,7 +3080,7 @@ ofpacts_put_openflow_instructions(const struct ofpact ofpacts[],
         }
 
         case OVSINST_OFPIT11_WRITE_ACTIONS: {
-            const size_t ofs = openflow->size;
+            const size_t ofs = ofpbuf_size(openflow);
             const struct ofpact_nest *on;
 
             on = ofpact_get_WRITE_ACTIONS(a);
@@ -3608,7 +3608,7 @@ ofpact_put(struct ofpbuf *ofpacts, enum ofpact_type type, size_t len)
     struct ofpact *ofpact;
 
     ofpact_pad(ofpacts);
-    ofpact = ofpacts->l2 = ofpbuf_put_uninit(ofpacts, len);
+    ofpact = ofpacts->frame = ofpbuf_put_uninit(ofpacts, len);
     ofpact_init(ofpact, type, len);
     return ofpact;
 }
@@ -3631,7 +3631,7 @@ ofpact_init(struct ofpact *ofpact, enum ofpact_type type, size_t len)
 void
 ofpact_update_len(struct ofpbuf *ofpacts, struct ofpact *ofpact)
 {
-    ovs_assert(ofpact == ofpacts->l2);
+    ovs_assert(ofpact == ofpacts->frame);
     ofpact->len = (char *) ofpbuf_tail(ofpacts) - (char *) ofpact;
 }
 
@@ -3648,7 +3648,7 @@ ofpact_update_len(struct ofpbuf *ofpacts, struct ofpact *ofpact)
 void
 ofpact_pad(struct ofpbuf *ofpacts)
 {
-    unsigned int pad = PAD_SIZE(ofpacts->size, OFPACT_ALIGNTO);
+    unsigned int pad = PAD_SIZE(ofpbuf_size(ofpacts), OFPACT_ALIGNTO);
     if (pad) {
         ofpbuf_put_zeros(ofpacts, pad);
     }
index a8c5c31..bd4e43a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -272,8 +272,10 @@ ofperr_get_code(enum ofperr error, enum ofp_version version)
 /* Tries to decode 'oh', which should be an OpenFlow OFPT_ERROR message.
  * Returns an OFPERR_* constant on success, 0 on failure.
  *
- * If 'payload' is nonnull, on success '*payload' is initialized to the
- * error's payload, and on failure it is cleared. */
+ * If 'payload' is nonnull, on success '*payload' is initialized with a copy of
+ * the error's payload (copying is required because the payload is not properly
+ * aligned).  The caller must free the payload (with ofpbuf_uninit()) when it
+ * is no longer needed.  On failure, '*payload' is cleared. */
 enum ofperr
 ofperr_decode_msg(const struct ofp_header *oh, struct ofpbuf *payload)
 {
@@ -323,7 +325,8 @@ ofperr_decode_msg(const struct ofp_header *oh, struct ofpbuf *payload)
     /* Translate the error type and code into an ofperr. */
     error = ofperr_decode(oh->version, vendor, type, code);
     if (error && payload) {
-        ofpbuf_use_const(payload, b.data, b.size);
+        ofpbuf_init(payload, ofpbuf_size(&b));
+        ofpbuf_push(payload, ofpbuf_data(&b), ofpbuf_size(&b));
     }
     return error;
 }
index 677d359..b67e47a 100644 (file)
@@ -371,18 +371,18 @@ ofpraw_decode_assert(const struct ofp_header *oh)
 }
 
 /* Determines the OFPRAW_* type of the OpenFlow message in 'msg', which starts
- * at 'msg->data' and has length 'msg->size' bytes.  On success, returns 0 and
- * stores the type into '*rawp'.  On failure, returns an OFPERR_* error code
- * and zeros '*rawp'.
+ * at 'ofpbuf_data(msg)' and has length 'ofpbuf_size(msg)' bytes.  On success,
+ * returns 0 and stores the type into '*rawp'.  On failure, returns an OFPERR_*
+ * error code and zeros '*rawp'.
  *
  * This function checks that the message has a valid length for its particular
  * type of message, and returns an error if not.
  *
  * In addition to setting '*rawp', this function pulls off the OpenFlow header
  * (including the stats headers, vendor header, and any subtype header) with
- * ofpbuf_pull().  It also sets 'msg->l2' to the start of the OpenFlow header
- * and 'msg->l3' just beyond the headers (that is, to the final value of
- * msg->data). */
+ * ofpbuf_pull().  It also sets 'msg->frame' to the start of the OpenFlow
+ * header and 'msg->l3' just beyond the headers (that is, to the final value of
+ * ofpbuf_data(msg)). */
 enum ofperr
 ofpraw_pull(enum ofpraw *rawp, struct ofpbuf *msg)
 {
@@ -399,12 +399,12 @@ ofpraw_pull(enum ofpraw *rawp, struct ofpbuf *msg)
     enum ofpraw raw;
 
     /* Set default outputs. */
-    msg->l2 = msg->data;
-    ofpbuf_set_l3(msg, msg->data);
+    msg->frame = ofpbuf_data(msg);
+    ofpbuf_set_l3(msg, msg->frame);
     *rawp = 0;
 
-    len = msg->size;
-    error = ofphdrs_decode(&hdrs, msg->data, len);
+    len = ofpbuf_size(msg);
+    error = ofphdrs_decode(&hdrs, ofpbuf_data(msg), len);
     if (error) {
         return error;
     }
@@ -416,8 +416,8 @@ ofpraw_pull(enum ofpraw *rawp, struct ofpbuf *msg)
 
     info = raw_info_get(raw);
     instance = raw_instance_get(info, hdrs.version);
-    msg->l2 = ofpbuf_pull(msg, instance->hdrs_len);
-    ofpbuf_set_l3(msg, msg->data);
+    msg->frame = ofpbuf_pull(msg, instance->hdrs_len);
+    ofpbuf_set_l3(msg, ofpbuf_data(msg));
 
     min_len = instance->hdrs_len + info->min_body;
     switch (info->extra_multiple) {
@@ -511,10 +511,10 @@ static void ofpraw_put__(enum ofpraw, uint8_t version, ovs_be32 xid,
  * Each 'raw' value is valid only for certain OpenFlow versions.  The caller
  * must specify a valid (raw, version) pair.
  *
- * In the returned ofpbuf, 'l2' points to the beginning of the OpenFlow header
- * and 'l3' points just after it, to where the message's body will start.  The
- * caller must actually allocate the body into the space reserved for it,
- * e.g. with ofpbuf_put_uninit().
+ * In the returned ofpbuf, 'frame' points to the beginning of the
+ * OpenFlow header and 'l3' points just after it, to where the
+ * message's body will start.  The caller must actually allocate the
+ * body into the space reserved for it, e.g. with ofpbuf_put_uninit().
  *
  * The caller owns the returned ofpbuf and must free it when it is no longer
  * needed, e.g. with ofpbuf_delete(). */
@@ -558,10 +558,10 @@ ofpraw_alloc_reply(enum ofpraw raw, const struct ofp_header *request,
  * value.  Every stats request has a corresponding reply, so the (raw, version)
  * pairing pitfalls of the other ofpraw_alloc_*() functions don't apply here.
  *
- * In the returned ofpbuf, 'l2' points to the beginning of the OpenFlow header
- * and 'l3' points just after it, to where the message's body will start.  The
- * caller must actually allocate the body into the space reserved for it,
- * e.g. with ofpbuf_put_uninit().
+ * In the returned ofpbuf, 'frame' points to the beginning of the
+ * OpenFlow header and 'l3' points just after it, to where the
+ * message's body will start.  The caller must actually allocate the
+ * body into the space reserved for it, e.g. with ofpbuf_put_uninit().
  *
  * The caller owns the returned ofpbuf and must free it when it is no longer
  * needed, e.g. with ofpbuf_delete(). */
@@ -591,7 +591,7 @@ ofpraw_alloc_stats_reply(const struct ofp_header *request,
  * Each 'raw' value is valid only for certain OpenFlow versions.  The caller
  * must specify a valid (raw, version) pair.
  *
- * Upon return, 'buf->l2' points to the beginning of the OpenFlow header and
+ * Upon return, 'buf->frame' points to the beginning of the OpenFlow header and
  * 'buf->l3' points just after it, to where the message's body will start.  The
  * caller must actually allocating the body into the space reserved for it,
  * e.g. with ofpbuf_put_uninit(). */
@@ -631,10 +631,10 @@ ofpraw_put_reply(enum ofpraw raw, const struct ofp_header *request,
  * value.  Every stats request has a corresponding reply, so the (raw, version)
  * pairing pitfalls of the other ofpraw_alloc_*() functions don't apply here.
  *
- * In the returned ofpbuf, 'l2' points to the beginning of the OpenFlow header
- * and 'l3' points just after it, to where the message's body will start.  The
- * caller must actually allocate the body into the space reserved for it,
- * e.g. with ofpbuf_put_uninit().
+ * In the returned ofpbuf, 'frame' points to the beginning of the
+ * OpenFlow header and 'l3' points just after it, to where the
+ * message's body will start.  The caller must actually allocate the
+ * body into the space reserved for it, e.g. with ofpbuf_put_uninit().
  *
  * The caller owns the returned ofpbuf and must free it when it is no longer
  * needed, e.g. with ofpbuf_delete(). */
@@ -664,17 +664,17 @@ ofpraw_put__(enum ofpraw raw, uint8_t version, ovs_be32 xid,
 
     ofpbuf_prealloc_tailroom(buf, (instance->hdrs_len + info->min_body
                                    + extra_tailroom));
-    buf->l2 = ofpbuf_put_uninit(buf, instance->hdrs_len);
+    buf->frame = ofpbuf_put_uninit(buf, instance->hdrs_len);
     ofpbuf_set_l3(buf, ofpbuf_tail(buf));
 
-    oh = buf->l2;
+    oh = buf->frame;
     oh->version = version;
     oh->type = hdrs->type;
-    oh->length = htons(buf->size);
+    oh->length = htons(ofpbuf_size(buf));
     oh->xid = xid;
 
     if (hdrs->type == OFPT_VENDOR) {
-        struct nicira_header *nh = buf->l2;
+        struct nicira_header *nh = buf->frame;
 
         ovs_assert(hdrs->vendor == NX_VENDOR_ID);
         nh->vendor = htonl(hdrs->vendor);
@@ -682,17 +682,17 @@ ofpraw_put__(enum ofpraw raw, uint8_t version, ovs_be32 xid,
     } else if (version == OFP10_VERSION
                && (hdrs->type == OFPT10_STATS_REQUEST ||
                    hdrs->type == OFPT10_STATS_REPLY)) {
-        struct ofp10_stats_msg *osm = buf->l2;
+        struct ofp10_stats_msg *osm = buf->frame;
 
         osm->type = htons(hdrs->stat);
         osm->flags = htons(0);
 
         if (hdrs->stat == OFPST_VENDOR) {
-            struct ofp10_vendor_stats_msg *ovsm = buf->l2;
+            struct ofp10_vendor_stats_msg *ovsm = buf->frame;
 
             ovsm->vendor = htonl(hdrs->vendor);
             if (hdrs->vendor == NX_VENDOR_ID) {
-                struct nicira10_stats_msg *nsm = buf->l2;
+                struct nicira10_stats_msg *nsm = buf->frame;
 
                 nsm->subtype = htonl(hdrs->subtype);
                 memset(nsm->pad, 0, sizeof nsm->pad);
@@ -703,18 +703,18 @@ ofpraw_put__(enum ofpraw raw, uint8_t version, ovs_be32 xid,
     } else if (version != OFP10_VERSION
                && (hdrs->type == OFPT11_STATS_REQUEST ||
                    hdrs->type == OFPT11_STATS_REPLY)) {
-        struct ofp11_stats_msg *osm = buf->l2;
+        struct ofp11_stats_msg *osm = buf->frame;
 
         osm->type = htons(hdrs->stat);
         osm->flags = htons(0);
         memset(osm->pad, 0, sizeof osm->pad);
 
         if (hdrs->stat == OFPST_VENDOR) {
-            struct ofp11_vendor_stats_msg *ovsm = buf->l2;
+            struct ofp11_vendor_stats_msg *ovsm = buf->frame;
 
             ovsm->vendor = htonl(hdrs->vendor);
             if (hdrs->vendor == NX_VENDOR_ID) {
-                struct nicira11_stats_msg *nsm = buf->l2;
+                struct nicira11_stats_msg *nsm = buf->frame;
 
                 nsm->subtype = htonl(hdrs->subtype);
             } else {
@@ -790,18 +790,18 @@ ofptype_decode(enum ofptype *typep, const struct ofp_header *oh)
 }
 
 /* Determines the OFPTYPE_* type of the OpenFlow message in 'msg', which starts
- * at 'msg->data' and has length 'msg->size' bytes.  On success, returns 0 and
- * stores the type into '*typep'.  On failure, returns an OFPERR_* error code
- * and zeros '*typep'.
+ * at 'ofpbuf_data(msg)' and has length 'ofpbuf_size(msg)' bytes.  On success,
+ * returns 0 and stores the type into '*typep'.  On failure, returns an
+ * OFPERR_* error code and zeros '*typep'.
  *
  * This function checks that the message has a valid length for its particular
  * type of message, and returns an error if not.
  *
  * In addition to setting '*typep', this function pulls off the OpenFlow header
  * (including the stats headers, vendor header, and any subtype header) with
- * ofpbuf_pull().  It also sets 'msg->l2' to the start of the OpenFlow header
- * and 'msg->l3' just beyond the headers (that is, to the final value of
- * msg->data). */
+ * ofpbuf_pull().  It also sets 'msg->frame' to the start of the OpenFlow
+ * header and 'msg->l3' just beyond the headers (that is, to the final value of
+ * ofpbuf_data(msg)). */
 enum ofperr
 ofptype_pull(enum ofptype *typep, struct ofpbuf *buf)
 {
@@ -824,12 +824,12 @@ ofptype_from_ofpraw(enum ofpraw raw)
 }
 \f
 /* Updates the 'length' field of the OpenFlow message in 'buf' to
- * 'buf->size'. */
+ * 'ofpbuf_size(buf)'. */
 void
 ofpmsg_update_length(struct ofpbuf *buf)
 {
     struct ofp_header *oh = ofpbuf_at_assert(buf, 0, sizeof *oh);
-    oh->length = htons(buf->size);
+    oh->length = htons(ofpbuf_size(buf));
 }
 
 /* Returns just past the Openflow header (including the stats headers, vendor
@@ -880,7 +880,7 @@ ofpmp_reserve(struct list *replies, size_t len)
 {
     struct ofpbuf *msg = ofpbuf_from_list(list_back(replies));
 
-    if (msg->size + len <= UINT16_MAX) {
+    if (ofpbuf_size(msg) + len <= UINT16_MAX) {
         ofpbuf_prealloc_tailroom(msg, len);
         return msg;
     } else {
@@ -888,16 +888,16 @@ ofpmp_reserve(struct list *replies, size_t len)
         struct ofpbuf *next;
         struct ofphdrs hdrs;
 
-        ofphdrs_decode_assert(&hdrs, msg->data, msg->size);
+        ofphdrs_decode_assert(&hdrs, ofpbuf_data(msg), ofpbuf_size(msg));
         hdrs_len = ofphdrs_len(&hdrs);
 
         next = ofpbuf_new(MAX(1024, hdrs_len + len));
-        ofpbuf_put(next, msg->data, hdrs_len);
-        next->l2 = next->data;
+        ofpbuf_put(next, ofpbuf_data(msg), hdrs_len);
+        next->frame = ofpbuf_data(next);
         ofpbuf_set_l3(next, ofpbuf_tail(next));
         list_push_back(replies, &next->list_node);
 
-        *ofpmp_flags__(msg->data) |= htons(OFPSF_REPLY_MORE);
+        *ofpmp_flags__(ofpbuf_data(msg)) |= htons(OFPSF_REPLY_MORE);
 
         return next;
     }
@@ -927,11 +927,11 @@ ofpmp_postappend(struct list *replies, size_t start_ofs)
     struct ofpbuf *msg = ofpbuf_from_list(list_back(replies));
 
     ovs_assert(start_ofs <= UINT16_MAX);
-    if (msg->size > UINT16_MAX) {
-        size_t len = msg->size - start_ofs;
+    if (ofpbuf_size(msg) > UINT16_MAX) {
+        size_t len = ofpbuf_size(msg) - start_ofs;
         memcpy(ofpmp_append(replies, len),
-               (const uint8_t *) msg->data + start_ofs, len);
-        msg->size = start_ofs;
+               (const uint8_t *) ofpbuf_data(msg) + start_ofs, len);
+        ofpbuf_set_size(msg, start_ofs);
     }
 }
 
index 5c5bb06..d250042 100644 (file)
@@ -291,7 +291,7 @@ parse_note(const char *arg, struct ofpbuf *ofpacts)
         }
         ofpbuf_put(ofpacts, &byte, 1);
 
-        note = ofpacts->l2;
+        note = ofpacts->frame;
         note->length++;
 
         arg += 2;
@@ -400,7 +400,7 @@ parse_noargs_dec_ttl(struct ofpbuf *b)
 
     ids = ofpact_put_DEC_TTL(b);
     ofpbuf_put(b, &id, sizeof id);
-    ids = b->l2;
+    ids = b->frame;
     ids->n_controllers++;
     ofpact_update_len(b, &ids->ofpact);
 }
@@ -426,7 +426,7 @@ parse_dec_ttl(struct ofpbuf *b, char *arg)
             uint16_t id = atoi(cntr);
 
             ofpbuf_put(b, &id, sizeof id);
-            ids = b->l2;
+            ids = b->frame;
             ids->n_controllers++;
         }
         if (!ids->n_controllers) {
@@ -632,7 +632,7 @@ parse_named_action(enum ofputil_action_code code,
                    char *arg, struct ofpbuf *ofpacts,
                    enum ofputil_protocol *usable_protocols)
 {
-    size_t orig_size = ofpacts->size;
+    size_t orig_size = ofpbuf_size(ofpacts);
     struct ofpact_tunnel *tunnel;
     struct ofpact_vlan_vid *vlan_vid;
     struct ofpact_vlan_pcp *vlan_pcp;
@@ -929,7 +929,7 @@ parse_named_action(enum ofputil_action_code code,
     }
 
     if (error) {
-        ofpacts->size = orig_size;
+        ofpbuf_set_size(ofpacts, orig_size);
     }
     return error;
 }
@@ -978,7 +978,7 @@ static char * WARN_UNUSED_RESULT
 str_to_ofpacts__(char *str, struct ofpbuf *ofpacts,
                  enum ofputil_protocol *usable_protocols)
 {
-    size_t orig_size = ofpacts->size;
+    size_t orig_size = ofpbuf_size(ofpacts);
     char *pos, *act, *arg;
     int n_actions;
 
@@ -988,7 +988,7 @@ str_to_ofpacts__(char *str, struct ofpbuf *ofpacts,
         char *error = str_to_ofpact__(pos, act, arg, ofpacts, n_actions,
                                       usable_protocols);
         if (error) {
-            ofpacts->size = orig_size;
+            ofpbuf_set_size(ofpacts, orig_size);
             return error;
         }
         n_actions++;
@@ -1007,7 +1007,7 @@ static char * WARN_UNUSED_RESULT
 str_to_ofpacts(char *str, struct ofpbuf *ofpacts,
                enum ofputil_protocol *usable_protocols)
 {
-    size_t orig_size = ofpacts->size;
+    size_t orig_size = ofpbuf_size(ofpacts);
     char *error_s;
     enum ofperr error;
 
@@ -1016,9 +1016,9 @@ str_to_ofpacts(char *str, struct ofpbuf *ofpacts,
         return error_s;
     }
 
-    error = ofpacts_verify(ofpacts->data, ofpacts->size);
+    error = ofpacts_verify(ofpbuf_data(ofpacts), ofpbuf_size(ofpacts));
     if (error) {
-        ofpacts->size = orig_size;
+        ofpbuf_set_size(ofpacts, orig_size);
         return xstrdup("Incorrect action ordering");
     }
 
@@ -1050,16 +1050,16 @@ parse_named_instruction(enum ovs_instruction_type type,
         size_t ofs;
 
         ofpact_pad(ofpacts);
-        ofs = ofpacts->size;
+        ofs = ofpbuf_size(ofpacts);
         on = ofpact_put(ofpacts, OFPACT_WRITE_ACTIONS,
                         offsetof(struct ofpact_nest, actions));
         error_s = str_to_ofpacts__(arg, ofpacts, usable_protocols);
 
         on = ofpbuf_at_assert(ofpacts, ofs, sizeof *on);
-        on->ofpact.len = ofpacts->size - ofs;
+        on->ofpact.len = ofpbuf_size(ofpacts) - ofs;
 
         if (error_s) {
-            ofpacts->size = ofs;
+            ofpbuf_set_size(ofpacts, ofs);
         }
         break;
     }
@@ -1095,7 +1095,7 @@ parse_named_instruction(enum ovs_instruction_type type,
 
     /* If write_metadata is specified as an action AND an instruction, ofpacts
        could be invalid. */
-    error = ofpacts_verify(ofpacts->data, ofpacts->size);
+    error = ofpacts_verify(ofpbuf_data(ofpacts), ofpbuf_size(ofpacts));
     if (error) {
         return xstrdup("Incorrect instruction ordering");
     }
@@ -1110,7 +1110,7 @@ static char * WARN_UNUSED_RESULT
 str_to_inst_ofpacts(char *str, struct ofpbuf *ofpacts,
                     enum ofputil_protocol *usable_protocols)
 {
-    size_t orig_size = ofpacts->size;
+    size_t orig_size = ofpbuf_size(ofpacts);
     char *pos, *inst, *arg;
     int type;
     const char *prev_inst = NULL;
@@ -1124,7 +1124,7 @@ str_to_inst_ofpacts(char *str, struct ofpbuf *ofpacts,
             char *error = str_to_ofpact__(pos, inst, arg, ofpacts, n_actions,
                                           usable_protocols);
             if (error) {
-                ofpacts->size = orig_size;
+                ofpbuf_set_size(ofpacts, orig_size);
                 return error;
             }
 
@@ -1134,20 +1134,20 @@ str_to_inst_ofpacts(char *str, struct ofpbuf *ofpacts,
                 continue;
             }
         } else if (type == OVSINST_OFPIT11_APPLY_ACTIONS) {
-            ofpacts->size = orig_size;
+            ofpbuf_set_size(ofpacts, orig_size);
             return xasprintf("%s isn't supported. Just write actions then "
                              "it is interpreted as apply_actions", inst);
         } else {
             char *error = parse_named_instruction(type, arg, ofpacts,
                                                   usable_protocols);
             if (error) {
-                ofpacts->size = orig_size;
+                ofpbuf_set_size(ofpacts, orig_size);
                 return error;
             }
         }
 
         if (type <= prev_type) {
-            ofpacts->size = orig_size;
+            ofpbuf_set_size(ofpacts, orig_size);
             if (type == prev_type) {
                 return xasprintf("instruction %s may be specified only once",
                                  inst);
@@ -1326,6 +1326,9 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string,
         } else if (fields & F_FLAGS && !strcmp(name, "no_byte_counts")) {
             fm->flags |= OFPUTIL_FF_NO_BYT_COUNTS;
             *usable_protocols &= OFPUTIL_P_OF13_UP;
+        } else if (!strcmp(name, "no_readonly_table")
+                   || !strcmp(name, "allow_hidden_fields")) {
+             /* ignore these fields. */
         } else {
             char *value;
 
@@ -1433,7 +1436,7 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string,
         if (!error) {
             enum ofperr err;
 
-            err = ofpacts_check(ofpacts.data, ofpacts.size, &fm->match.flow,
+            err = ofpacts_check(ofpbuf_data(&ofpacts), ofpbuf_size(&ofpacts), &fm->match.flow,
                                 OFPP_MAX, fm->table_id, 255, usable_protocols);
             if (!err && !usable_protocols) {
                 err = OFPERR_OFPBAC_MATCH_INCONSISTENT;
@@ -1449,7 +1452,7 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string,
             return error;
         }
 
-        fm->ofpacts_len = ofpacts.size;
+        fm->ofpacts_len = ofpbuf_size(&ofpacts);
         fm->ofpacts = ofpbuf_steal_data(&ofpacts);
     } else {
         fm->ofpacts_len = 0;
@@ -2130,8 +2133,8 @@ parse_bucket_str(struct ofputil_bucket *bucket, char *str_,
     }
 
     ofpact_pad(&ofpacts);
-    bucket->ofpacts = ofpacts.data;
-    bucket->ofpacts_len = ofpacts.size;
+    bucket->ofpacts = ofpbuf_data(&ofpacts);
+    bucket->ofpacts_len = ofpbuf_size(&ofpacts);
 
     return NULL;
 }
index b88d1e7..9091b1b 100644 (file)
@@ -68,17 +68,18 @@ ofp_packet_to_string(const void *data, size_t len)
     flow_extract(&buf, &md, &flow);
     flow_format(&ds, &flow);
 
-    l4_size = ofpbuf_get_l4_size(&buf);
+    l4_size = ofpbuf_l4_size(&buf);
 
     if (flow.nw_proto == IPPROTO_TCP && l4_size >= TCP_HEADER_LEN) {
-        struct tcp_header *th = ofpbuf_get_l4(&buf);
+        struct tcp_header *th = ofpbuf_l4(&buf);
         ds_put_format(&ds, " tcp_csum:%"PRIx16, ntohs(th->tcp_csum));
     } else if (flow.nw_proto == IPPROTO_UDP && l4_size >= UDP_HEADER_LEN) {
-        struct udp_header *uh = ofpbuf_get_l4(&buf);
+        struct udp_header *uh = ofpbuf_l4(&buf);
         ds_put_format(&ds, " udp_csum:%"PRIx16, ntohs(uh->udp_csum));
     } else if (flow.nw_proto == IPPROTO_SCTP && l4_size >= SCTP_HEADER_LEN) {
-        struct sctp_header *sh = ofpbuf_get_l4(&buf);
-        ds_put_format(&ds, " sctp_csum:%"PRIx32, ntohl(sh->sctp_csum));
+        struct sctp_header *sh = ofpbuf_l4(&buf);
+        ds_put_format(&ds, " sctp_csum:%"PRIx32,
+                      ntohl(get_16aligned_be32(&sh->sctp_csum)));
     }
 
     ds_put_char(&ds, '\n');
@@ -742,6 +743,12 @@ ofp_print_flow_flags(struct ds *s, enum ofputil_flow_mod_flags flags)
     if (flags & OFPUTIL_FF_NO_BYT_COUNTS) {
         ds_put_cstr(s, "no_byte_counts ");
     }
+    if (flags & OFPUTIL_FF_HIDDEN_FIELDS) {
+        ds_put_cstr(s, "allow_hidden_fields ");
+    }
+    if (flags & OFPUTIL_FF_NO_READONLY) {
+        ds_put_cstr(s, "no_readonly_table ");
+    }
 }
 
 static void
@@ -1361,12 +1368,13 @@ ofp_print_error_msg(struct ds *string, const struct ofp_header *oh)
     ds_put_format(string, " %s\n", ofperr_get_name(error));
 
     if (error == OFPERR_OFPHFC_INCOMPATIBLE || error == OFPERR_OFPHFC_EPERM) {
-        ds_put_printable(string, payload.data, payload.size);
+        ds_put_printable(string, ofpbuf_data(&payload), ofpbuf_size(&payload));
     } else {
-        s = ofp_to_string(payload.data, payload.size, 1);
+        s = ofp_to_string(ofpbuf_data(&payload), ofpbuf_size(&payload), 1);
         ds_put_cstr(string, s);
         free(s);
     }
+    ofpbuf_uninit(&payload);
 }
 
 static void
@@ -1663,7 +1671,7 @@ ofp_print_ofpst_table_reply13(struct ds *string, const struct ofp_header *oh,
     ofpbuf_use_const(&b, oh, ntohs(oh->length));
     ofpraw_pull_assert(&b);
 
-    n = b.size / sizeof *ts;
+    n = ofpbuf_size(&b) / sizeof *ts;
     ds_put_format(string, " %"PRIuSIZE" tables\n", n);
     if (verbosity < 1) {
         return;
@@ -1693,7 +1701,7 @@ ofp_print_ofpst_table_reply12(struct ds *string, const struct ofp_header *oh,
     ofpbuf_use_const(&b, oh, ntohs(oh->length));
     ofpraw_pull_assert(&b);
 
-    n = b.size / sizeof *ts;
+    n = ofpbuf_size(&b) / sizeof *ts;
     ds_put_format(string, " %"PRIuSIZE" tables\n", n);
     if (verbosity < 1) {
         return;
@@ -1720,7 +1728,7 @@ ofp_print_ofpst_table_reply11(struct ds *string, const struct ofp_header *oh,
     ofpbuf_use_const(&b, oh, ntohs(oh->length));
     ofpraw_pull_assert(&b);
 
-    n = b.size / sizeof *ts;
+    n = ofpbuf_size(&b) / sizeof *ts;
     ds_put_format(string, " %"PRIuSIZE" tables\n", n);
     if (verbosity < 1) {
         return;
@@ -1760,7 +1768,7 @@ ofp_print_ofpst_table_reply10(struct ds *string, const struct ofp_header *oh,
     ofpbuf_use_const(&b, oh, ntohs(oh->length));
     ofpraw_pull_assert(&b);
 
-    n = b.size / sizeof *ts;
+    n = ofpbuf_size(&b) / sizeof *ts;
     ds_put_format(string, " %"PRIuSIZE" tables\n", n);
     if (verbosity < 1) {
         return;
index d0002d5..b3d86e9 100644 (file)
@@ -265,10 +265,10 @@ enum ofperr
 ofputil_pull_ofp11_match(struct ofpbuf *buf, struct match *match,
                          uint16_t *padded_match_len)
 {
-    struct ofp11_match_header *omh = buf->data;
+    struct ofp11_match_header *omh = ofpbuf_data(buf);
     uint16_t match_len;
 
-    if (buf->size < sizeof *omh) {
+    if (ofpbuf_size(buf) < sizeof *omh) {
         return OFPERR_OFPBMC_BAD_LEN;
     }
 
@@ -278,7 +278,7 @@ ofputil_pull_ofp11_match(struct ofpbuf *buf, struct match *match,
     case OFPMT_STANDARD: {
         struct ofp11_match *om;
 
-        if (match_len != sizeof *om || buf->size < sizeof *om) {
+        if (match_len != sizeof *om || ofpbuf_size(buf) < sizeof *om) {
             return OFPERR_OFPBMC_BAD_LEN;
         }
         om = ofpbuf_pull(buf, sizeof *om);
@@ -1234,15 +1234,15 @@ ofputil_decode_hello(const struct ofp_header *oh, uint32_t *allowed_versions)
     ofpbuf_pull(&msg, sizeof *oh);
 
     *allowed_versions = version_bitmap_from_version(oh->version);
-    while (msg.size) {
+    while (ofpbuf_size(&msg)) {
         const struct ofp_hello_elem_header *oheh;
         unsigned int len;
 
-        if (msg.size < sizeof *oheh) {
+        if (ofpbuf_size(&msg) < sizeof *oheh) {
             return false;
         }
 
-        oheh = msg.data;
+        oheh = ofpbuf_data(&msg);
         len = ntohs(oheh->length);
         if (len < sizeof *oheh || !ofpbuf_try_pull(&msg, ROUND_UP(len, 8))) {
             return false;
@@ -1543,7 +1543,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
             return error;
         }
 
-        error = ofpacts_pull_openflow_instructions(&b, b.size, oh->version,
+        error = ofpacts_pull_openflow_instructions(&b, ofpbuf_size(&b), oh->version,
                                                    ofpacts);
         if (error) {
             return error;
@@ -1610,7 +1610,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
             ofputil_normalize_match(&fm->match);
 
             /* Now get the actions. */
-            error = ofpacts_pull_openflow_actions(&b, b.size, oh->version,
+            error = ofpacts_pull_openflow_actions(&b, ofpbuf_size(&b), oh->version,
                                                   ofpacts);
             if (error) {
                 return error;
@@ -1644,7 +1644,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
             if (error) {
                 return error;
             }
-            error = ofpacts_pull_openflow_actions(&b, b.size, oh->version,
+            error = ofpacts_pull_openflow_actions(&b, ofpbuf_size(&b), oh->version,
                                                   ofpacts);
             if (error) {
                 return error;
@@ -1679,8 +1679,8 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
         }
     }
 
-    fm->ofpacts = ofpacts->data;
-    fm->ofpacts_len = ofpacts->size;
+    fm->ofpacts = ofpbuf_data(ofpacts);
+    fm->ofpacts_len = ofpbuf_size(ofpacts);
 
     error = ofputil_decode_flow_mod_flags(raw_flags, fm->command,
                                           oh->version, &fm->flags);
@@ -1778,9 +1778,9 @@ ofputil_decode_meter_mod(const struct ofp_header *oh,
             mm->meter.flags & OFPMF13_PKTPS) {
             return OFPERR_OFPMMFC_BAD_FLAGS;
         }
-        mm->meter.bands = bands->data;
+        mm->meter.bands = ofpbuf_data(bands);
 
-        error = ofputil_pull_bands(&b, b.size, &mm->meter.n_bands, bands);
+        error = ofputil_pull_bands(&b, ofpbuf_size(&b), &mm->meter.n_bands, bands);
         if (error) {
             return error;
         }
@@ -1856,14 +1856,14 @@ ofputil_append_meter_config(struct list *replies,
                             const struct ofputil_meter_config *mc)
 {
     struct ofpbuf *msg = ofpbuf_from_list(list_back(replies));
-    size_t start_ofs = msg->size;
+    size_t start_ofs = ofpbuf_size(msg);
     struct ofp13_meter_config *reply = ofpbuf_put_uninit(msg, sizeof *reply);
     reply->flags = htons(mc->flags);
     reply->meter_id = htonl(mc->meter_id);
 
     ofputil_put_bands(mc->n_bands, mc->bands, msg);
 
-    reply->length = htons(msg->size - start_ofs);
+    reply->length = htons(ofpbuf_size(msg) - start_ofs);
 
     ofpmp_postappend(replies, start_ofs);
 }
@@ -1918,11 +1918,11 @@ ofputil_decode_meter_config(struct ofpbuf *msg,
     enum ofperr err;
 
     /* Pull OpenFlow headers for the first call. */
-    if (!msg->l2) {
+    if (!msg->frame) {
         ofpraw_pull_assert(msg);
     }
 
-    if (!msg->size) {
+    if (!ofpbuf_size(msg)) {
         return EOF;
     }
 
@@ -1930,7 +1930,7 @@ ofputil_decode_meter_config(struct ofpbuf *msg,
     if (!omc) {
         VLOG_WARN_RL(&bad_ofmsg_rl,
                      "OFPMP_METER_CONFIG reply has %"PRIu32" leftover bytes at end",
-                     msg->size);
+                     ofpbuf_size(msg));
         return OFPERR_OFPBRC_BAD_LEN;
     }
 
@@ -1942,7 +1942,7 @@ ofputil_decode_meter_config(struct ofpbuf *msg,
     }
     mc->meter_id = ntohl(omc->meter_id);
     mc->flags = ntohs(omc->flags);
-    mc->bands = bands->data;
+    mc->bands = ofpbuf_data(bands);
 
     return 0;
 }
@@ -1994,11 +1994,11 @@ ofputil_decode_meter_stats(struct ofpbuf *msg,
     enum ofperr err;
 
     /* Pull OpenFlow headers for the first call. */
-    if (!msg->l2) {
+    if (!msg->frame) {
         ofpraw_pull_assert(msg);
     }
 
-    if (!msg->size) {
+    if (!ofpbuf_size(msg)) {
         return EOF;
     }
 
@@ -2006,7 +2006,7 @@ ofputil_decode_meter_stats(struct ofpbuf *msg,
     if (!oms) {
         VLOG_WARN_RL(&bad_ofmsg_rl,
                      "OFPMP_METER reply has %"PRIu32" leftover bytes at end",
-                     msg->size);
+                     ofpbuf_size(msg));
         return OFPERR_OFPBRC_BAD_LEN;
     }
 
@@ -2022,7 +2022,7 @@ ofputil_decode_meter_stats(struct ofpbuf *msg,
     ms->byte_in_count = ntohll(oms->byte_in_count);
     ms->duration_sec = ntohl(oms->duration_sec);
     ms->duration_nsec = ntohl(oms->duration_nsec);
-    ms->bands = bands->data;
+    ms->bands = ofpbuf_data(bands);
 
     return 0;
 }
@@ -2176,7 +2176,7 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
         nfm->command = ofputil_tid_command(fm, protocol);
         nfm->cookie = fm->new_cookie;
         match_len = nx_put_match(msg, &fm->match, fm->cookie, fm->cookie_mask);
-        nfm = ofpbuf_get_l3(msg);
+        nfm = ofpbuf_l3(msg);
         nfm->idle_timeout = htons(fm->idle_timeout);
         nfm->hard_timeout = htons(fm->hard_timeout);
         nfm->priority = htons(fm->priority);
@@ -2250,7 +2250,7 @@ ofputil_decode_nxst_flow_request(struct ofputil_flow_stats_request *fsr,
     if (error) {
         return error;
     }
-    if (b->size) {
+    if (ofpbuf_size(b)) {
         return OFPERR_OFPBRC_BAD_LEN;
     }
 
@@ -2306,12 +2306,12 @@ ofputil_decode_queue_get_config_request(const struct ofp_header *oh,
 
     switch ((int) raw) {
     case OFPRAW_OFPT10_QUEUE_GET_CONFIG_REQUEST:
-        qgcr10 = b.data;
+        qgcr10 = ofpbuf_data(&b);
         *port = u16_to_ofp(ntohs(qgcr10->port));
         return 0;
 
     case OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST:
-        qgcr11 = b.data;
+        qgcr11 = ofpbuf_data(&b);
         return ofputil_port_from_ofp11(qgcr11->port, port);
     }
 
@@ -2380,36 +2380,36 @@ void
 ofputil_append_queue_get_config_reply(struct ofpbuf *reply,
                                       const struct ofputil_queue_config *oqc)
 {
-    const struct ofp_header *oh = reply->data;
+    const struct ofp_header *oh = ofpbuf_data(reply);
     size_t start_ofs, len_ofs;
     ovs_be16 *len;
 
-    start_ofs = reply->size;
+    start_ofs = ofpbuf_size(reply);
     if (oh->version < OFP12_VERSION) {
         struct ofp10_packet_queue *opq10;
 
         opq10 = ofpbuf_put_zeros(reply, sizeof *opq10);
         opq10->queue_id = htonl(oqc->queue_id);
-        len_ofs = (char *) &opq10->len - (char *) reply->data;
+        len_ofs = (char *) &opq10->len - (char *) ofpbuf_data(reply);
     } else {
         struct ofp11_queue_get_config_reply *qgcr11;
         struct ofp12_packet_queue *opq12;
         ovs_be32 port;
 
-        qgcr11 = ofpbuf_get_l3(reply);
+        qgcr11 = ofpbuf_l3(reply);
         port = qgcr11->port;
 
         opq12 = ofpbuf_put_zeros(reply, sizeof *opq12);
         opq12->port = port;
         opq12->queue_id = htonl(oqc->queue_id);
-        len_ofs = (char *) &opq12->len - (char *) reply->data;
+        len_ofs = (char *) &opq12->len - (char *) ofpbuf_data(reply);
     }
 
     put_queue_rate(reply, OFPQT_MIN_RATE, oqc->min_rate);
     put_queue_rate(reply, OFPQT_MAX_RATE, oqc->max_rate);
 
     len = ofpbuf_at(reply, len_ofs, sizeof *len);
-    *len = htons(reply->size - start_ofs);
+    *len = htons(ofpbuf_size(reply) - start_ofs);
 }
 
 /* Decodes the initial part of an OFPT_QUEUE_GET_CONFIG_REPLY from 'reply' and
@@ -2468,14 +2468,14 @@ ofputil_pull_queue_get_config_reply(struct ofpbuf *reply,
     unsigned int opq_len;
     unsigned int len;
 
-    if (!reply->size) {
+    if (!ofpbuf_size(reply)) {
         return EOF;
     }
 
     queue->min_rate = UINT16_MAX;
     queue->max_rate = UINT16_MAX;
 
-    oh = reply->l2;
+    oh = reply->frame;
     if (oh->version < OFP12_VERSION) {
         const struct ofp10_packet_queue *opq10;
 
@@ -2498,7 +2498,7 @@ ofputil_pull_queue_get_config_reply(struct ofpbuf *reply,
         opq_len = sizeof *opq12;
     }
 
-    if (len < opq_len || len > reply->size + opq_len || len % 8) {
+    if (len < opq_len || len > ofpbuf_size(reply) + opq_len || len % 8) {
         return OFPERR_OFPBRC_BAD_LEN;
     }
     len -= opq_len;
@@ -2511,7 +2511,7 @@ ofputil_pull_queue_get_config_reply(struct ofpbuf *reply,
 
         hdr = ofpbuf_at_assert(reply, 0, sizeof *hdr);
         prop_len = ntohs(hdr->len);
-        if (prop_len < sizeof *hdr || prop_len > reply->size || prop_len % 8) {
+        if (prop_len < sizeof *hdr || prop_len > ofpbuf_size(reply) || prop_len % 8) {
             return OFPERR_OFPBRC_BAD_LEN;
         }
 
@@ -2553,10 +2553,10 @@ ofputil_decode_flow_stats_request(struct ofputil_flow_stats_request *fsr,
     raw = ofpraw_pull_assert(&b);
     switch ((int) raw) {
     case OFPRAW_OFPST10_FLOW_REQUEST:
-        return ofputil_decode_ofpst10_flow_request(fsr, b.data, false);
+        return ofputil_decode_ofpst10_flow_request(fsr, ofpbuf_data(&b), false);
 
     case OFPRAW_OFPST10_AGGREGATE_REQUEST:
-        return ofputil_decode_ofpst10_flow_request(fsr, b.data, true);
+        return ofputil_decode_ofpst10_flow_request(fsr, ofpbuf_data(&b), true);
 
     case OFPRAW_OFPST11_FLOW_REQUEST:
         return ofputil_decode_ofpst11_flow_request(fsr, &b, false);
@@ -2636,7 +2636,7 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
         match_len = nx_put_match(msg, &fsr->match,
                                  fsr->cookie, fsr->cookie_mask);
 
-        nfsr = ofpbuf_get_l3(msg);
+        nfsr = ofpbuf_l3(msg);
         nfsr->out_port = htons(ofp_to_u16(fsr->out_port));
         nfsr->match_len = htons(match_len);
         nfsr->table_id = fsr->table_id;
@@ -2680,15 +2680,15 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
     enum ofperr error;
     enum ofpraw raw;
 
-    error = (msg->l2
-             ? ofpraw_decode(&raw, msg->l2)
+    error = (msg->frame
+             ? ofpraw_decode(&raw, msg->frame)
              : ofpraw_pull(&raw, msg));
     if (error) {
         return error;
     }
-    oh = msg->l2;
+    oh = msg->frame;
 
-    if (!msg->size) {
+    if (!ofpbuf_size(msg)) {
         return EOF;
     } else if (raw == OFPRAW_OFPST11_FLOW_REPLY
                || raw == OFPRAW_OFPST13_FLOW_REPLY) {
@@ -2699,7 +2699,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
         ofs = ofpbuf_try_pull(msg, sizeof *ofs);
         if (!ofs) {
             VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply has %"PRIu32" leftover "
-                         "bytes at end", msg->size);
+                         "bytes at end", ofpbuf_size(msg));
             return EINVAL;
         }
 
@@ -2749,7 +2749,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
         ofs = ofpbuf_try_pull(msg, sizeof *ofs);
         if (!ofs) {
             VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply has %"PRIu32" leftover "
-                         "bytes at end", msg->size);
+                         "bytes at end", ofpbuf_size(msg));
             return EINVAL;
         }
 
@@ -2785,7 +2785,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
         nfs = ofpbuf_try_pull(msg, sizeof *nfs);
         if (!nfs) {
             VLOG_WARN_RL(&bad_ofmsg_rl, "NXST_FLOW reply has %"PRIu32" leftover "
-                         "bytes at end", msg->size);
+                         "bytes at end", ofpbuf_size(msg));
             return EINVAL;
         }
 
@@ -2830,8 +2830,8 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
         OVS_NOT_REACHED();
     }
 
-    fs->ofpacts = ofpacts->data;
-    fs->ofpacts_len = ofpacts->size;
+    fs->ofpacts = ofpbuf_data(ofpacts);
+    fs->ofpacts_len = ofpbuf_size(ofpacts);
 
     return 0;
 }
@@ -2854,11 +2854,11 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
                                 struct list *replies)
 {
     struct ofpbuf *reply = ofpbuf_from_list(list_back(replies));
-    size_t start_ofs = reply->size;
+    size_t start_ofs = ofpbuf_size(reply);
     enum ofpraw raw;
-    enum ofp_version version = ((struct ofp_header *)reply->data)->version;
+    enum ofp_version version = ((struct ofp_header *)ofpbuf_data(reply))->version;
 
-    ofpraw_decode_partial(&raw, reply->data, reply->size);
+    ofpraw_decode_partial(&raw, ofpbuf_data(reply), ofpbuf_size(reply));
     if (raw == OFPRAW_OFPST11_FLOW_REPLY || raw == OFPRAW_OFPST13_FLOW_REPLY) {
         struct ofp11_flow_stats *ofs;
 
@@ -2868,7 +2868,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
                                           version);
 
         ofs = ofpbuf_at_assert(reply, start_ofs, sizeof *ofs);
-        ofs->length = htons(reply->size - start_ofs);
+        ofs->length = htons(ofpbuf_size(reply) - start_ofs);
         ofs->table_id = fs->table_id;
         ofs->pad = 0;
         ofs->duration_sec = htonl(fs->duration_sec);
@@ -2892,7 +2892,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
         ofpacts_put_openflow_actions(fs->ofpacts, fs->ofpacts_len, reply,
                                      version);
         ofs = ofpbuf_at_assert(reply, start_ofs, sizeof *ofs);
-        ofs->length = htons(reply->size - start_ofs);
+        ofs->length = htons(ofpbuf_size(reply) - start_ofs);
         ofs->table_id = fs->table_id;
         ofs->pad = 0;
         ofputil_match_to_ofp10_match(&fs->match, &ofs->match);
@@ -2916,7 +2916,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
         ofpacts_put_openflow_actions(fs->ofpacts, fs->ofpacts_len, reply,
                                      version);
         nfs = ofpbuf_at_assert(reply, start_ofs, sizeof *nfs);
-        nfs->length = htons(reply->size - start_ofs);
+        nfs->length = htons(ofpbuf_size(reply) - start_ofs);
         nfs->table_id = fs->table_id;
         nfs->pad = 0;
         nfs->duration_sec = htonl(fs->duration_sec);
@@ -2982,7 +2982,7 @@ ofputil_decode_aggregate_stats_reply(struct ofputil_aggregate_stats *stats,
     ofpbuf_use_const(&msg, reply, ntohs(reply->length));
     ofpraw_pull_assert(&msg);
 
-    asr = ofpbuf_get_l3(&msg);
+    asr = ofpbuf_l3(&msg);
     stats->packet_count = ntohll(get_32aligned_be64(&asr->packet_count));
     stats->byte_count = ntohll(get_32aligned_be64(&asr->byte_count));
     stats->flow_count = ntohl(asr->flow_count);
@@ -3049,7 +3049,7 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
         if (error) {
             return error;
         }
-        if (b.size) {
+        if (ofpbuf_size(&b)) {
             return OFPERR_OFPBRC_BAD_LEN;
         }
 
@@ -3134,7 +3134,7 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
         nfr = ofpbuf_put_zeros(msg, sizeof *nfr);
         match_len = nx_put_match(msg, &fr->match, 0, 0);
 
-        nfr = ofpbuf_get_l3(msg);
+        nfr = ofpbuf_l3(msg);
         nfr->cookie = fr->cookie;
         nfr->priority = htons(fr->priority);
         nfr->reason = fr->reason;
@@ -3159,8 +3159,8 @@ static void
 ofputil_decode_packet_in_finish(struct ofputil_packet_in *pin,
                                 struct match *match, struct ofpbuf *b)
 {
-    pin->packet = b->data;
-    pin->packet_len = b->size;
+    pin->packet = ofpbuf_data(b);
+    pin->packet_len = ofpbuf_size(b);
 
     pin->fmd.in_port = match->flow.in_port.ofp_port;
     pin->fmd.tun_id = match->flow.tunnel.tun_id;
@@ -3221,7 +3221,7 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin,
         opi = ofpbuf_pull(&b, offsetof(struct ofp10_packet_in, data));
 
         pin->packet = opi->data;
-        pin->packet_len = b.size;
+        pin->packet_len = ofpbuf_size(&b);
 
         pin->fmd.in_port = u16_to_ofp(ntohs(opi->in_port));
         pin->reason = opi->reason;
@@ -3233,8 +3233,8 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin,
 
         opi = ofpbuf_pull(&b, sizeof *opi);
 
-        pin->packet = b.data;
-        pin->packet_len = b.size;
+        pin->packet = ofpbuf_data(&b);
+        pin->packet_len = ofpbuf_size(&b);
 
         pin->buffer_id = ntohl(opi->buffer_id);
         error = ofputil_port_from_ofp11(opi->in_port, &pin->fmd.in_port);
@@ -3346,7 +3346,7 @@ ofputil_encode_nx_packet_in(const struct ofputil_packet_in *pin)
     ofpbuf_put_zeros(packet, 2);
     ofpbuf_put(packet, pin->packet, pin->packet_len);
 
-    npi = ofpbuf_get_l3(packet);
+    npi = ofpbuf_l3(packet);
     npi->buffer_id = htonl(pin->buffer_id);
     npi->total_len = htons(pin->total_len);
     npi->reason = pin->reason;
@@ -3410,7 +3410,7 @@ ofputil_encode_ofp12_packet_in(const struct ofputil_packet_in *pin,
     ofpbuf_put_zeros(packet, 2);
     ofpbuf_put(packet, pin->packet, pin->packet_len);
 
-    opi = ofpbuf_get_l3(packet);
+    opi = ofpbuf_l3(packet);
     opi->pi.buffer_id = htonl(pin->buffer_id);
     opi->pi.total_len = htons(pin->total_len);
     opi->pi.reason = pin->reason;
@@ -3559,12 +3559,12 @@ ofputil_decode_packet_out(struct ofputil_packet_out *po,
         return OFPERR_OFPBRC_BAD_PORT;
     }
 
-    po->ofpacts = ofpacts->data;
-    po->ofpacts_len = ofpacts->size;
+    po->ofpacts = ofpbuf_data(ofpacts);
+    po->ofpacts_len = ofpbuf_size(ofpacts);
 
     if (po->buffer_id == UINT32_MAX) {
-        po->packet = b.data;
-        po->packet_len = b.size;
+        po->packet = ofpbuf_data(&b);
+        po->packet_len = ofpbuf_size(&b);
     } else {
         po->packet = NULL;
         po->packet_len = 0;
@@ -3750,7 +3750,7 @@ ofputil_put_phy_port(enum ofp_version ofp_version,
     switch (ofp_version) {
     case OFP10_VERSION: {
         struct ofp10_phy_port *opp;
-        if (b->size + sizeof *opp <= UINT16_MAX) {
+        if (ofpbuf_size(b) + sizeof *opp <= UINT16_MAX) {
             opp = ofpbuf_put_uninit(b, sizeof *opp);
             ofputil_encode_ofp10_phy_port(pp, opp);
         }
@@ -3761,7 +3761,7 @@ ofputil_put_phy_port(enum ofp_version ofp_version,
     case OFP12_VERSION:
     case OFP13_VERSION: {
         struct ofp11_port *op;
-        if (b->size + sizeof *op <= UINT16_MAX) {
+        if (ofpbuf_size(b) + sizeof *op <= UINT16_MAX) {
             op = ofpbuf_put_uninit(b, sizeof *op);
             ofputil_encode_ofp11_port(pp, op);
         }
@@ -3902,7 +3902,7 @@ ofputil_decode_switch_features(const struct ofp_header *oh,
     features->capabilities = ntohl(osf->capabilities) &
         ofputil_capabilities_mask(oh->version);
 
-    if (b->size % ofputil_get_phy_port_size(oh->version)) {
+    if (ofpbuf_size(b) % ofputil_get_phy_port_size(oh->version)) {
         return OFPERR_OFPBRC_BAD_LEN;
     }
 
@@ -3945,12 +3945,12 @@ max_ports_in_features(const struct ofp_header *oh)
 bool
 ofputil_switch_features_ports_trunc(struct ofpbuf *b)
 {
-    struct ofp_header *oh = b->data;
+    struct ofp_header *oh = ofpbuf_data(b);
 
     if (max_ports_in_features(oh)) {
         /* Remove all the ports. */
-        b->size = (sizeof(struct ofp_header)
-                   + sizeof(struct ofp_switch_features));
+        ofpbuf_set_size(b, (sizeof(struct ofp_header) +
+                            sizeof(struct ofp_switch_features)));
         ofpmsg_update_length(b);
 
         return true;
@@ -4043,7 +4043,7 @@ void
 ofputil_put_switch_features_port(const struct ofputil_phy_port *pp,
                                  struct ofpbuf *b)
 {
-    const struct ofp_header *oh = b->data;
+    const struct ofp_header *oh = ofpbuf_data(b);
 
     if (oh->version < OFP13_VERSION) {
         ofputil_put_phy_port(oh->version, pp, b);
@@ -4130,7 +4130,7 @@ ofputil_decode_port_mod(const struct ofp_header *oh,
     raw = ofpraw_pull_assert(&b);
 
     if (raw == OFPRAW_OFPT10_PORT_MOD) {
-        const struct ofp10_port_mod *opm = b.data;
+        const struct ofp10_port_mod *opm = ofpbuf_data(&b);
 
         pm->port_no = u16_to_ofp(ntohs(opm->port_no));
         memcpy(pm->hw_addr, opm->hw_addr, ETH_ADDR_LEN);
@@ -4138,7 +4138,7 @@ ofputil_decode_port_mod(const struct ofp_header *oh,
         pm->mask = ntohl(opm->mask) & OFPPC10_ALL;
         pm->advertise = netdev_port_features_from_ofp10(opm->advertise);
     } else if (raw == OFPRAW_OFPT11_PORT_MOD) {
-        const struct ofp11_port_mod *opm = b.data;
+        const struct ofp11_port_mod *opm = ofpbuf_data(&b);
         enum ofperr error;
 
         error = ofputil_port_from_ofp11(opm->port_no, &pm->port_no);
@@ -4218,19 +4218,19 @@ ofputil_pull_property(struct ofpbuf *msg, struct ofpbuf *payload,
     struct ofp_prop_header *oph;
     unsigned int len;
 
-    if (msg->size < sizeof *oph) {
+    if (ofpbuf_size(msg) < sizeof *oph) {
         return OFPERR_OFPTFFC_BAD_LEN;
     }
 
-    oph = msg->data;
+    oph = ofpbuf_data(msg);
     len = ntohs(oph->len);
-    if (len < sizeof *oph || ROUND_UP(len, 8) > msg->size) {
+    if (len < sizeof *oph || ROUND_UP(len, 8) > ofpbuf_size(msg)) {
         return OFPERR_OFPTFFC_BAD_LEN;
     }
 
     *typep = ntohs(oph->type);
     if (payload) {
-        ofpbuf_use_const(payload, msg->data, len);
+        ofpbuf_use_const(payload, ofpbuf_data(msg), len);
         ofpbuf_pull(payload, sizeof *oph);
     }
     ofpbuf_pull(msg, ROUND_UP(len, 8));
@@ -4256,7 +4256,7 @@ parse_table_ids(struct ofpbuf *payload, uint32_t *ids)
     uint16_t type;
 
     *ids = 0;
-    while (payload->size > 0) {
+    while (ofpbuf_size(payload) > 0) {
         enum ofperr error = ofputil_pull_property(payload, NULL, &type);
         if (error) {
             return error;
@@ -4272,7 +4272,7 @@ static enum ofperr
 parse_instruction_ids(struct ofpbuf *payload, bool loose, uint32_t *insts)
 {
     *insts = 0;
-    while (payload->size > 0) {
+    while (ofpbuf_size(payload) > 0) {
         enum ovs_instruction_type inst;
         enum ofperr error;
         uint16_t ofpit;
@@ -4299,8 +4299,8 @@ parse_table_features_next_table(struct ofpbuf *payload,
     size_t i;
 
     memset(next_tables, 0, bitmap_n_bytes(255));
-    for (i = 0; i < payload->size; i++) {
-        uint8_t id = ((const uint8_t *) payload->data)[i];
+    for (i = 0; i < ofpbuf_size(payload); i++) {
+        uint8_t id = ((const uint8_t *) ofpbuf_data(payload))[i];
         if (id >= 255) {
             return OFPERR_OFPTFFC_BAD_ARGUMENT;
         }
@@ -4348,7 +4348,7 @@ parse_oxms(struct ofpbuf *payload, bool loose,
     uint64_t exact, masked;
 
     exact = masked = 0;
-    while (payload->size > 0) {
+    while (ofpbuf_size(payload) > 0) {
         const struct mf_field *field;
         enum ofperr error;
         bool hasmask;
@@ -4400,22 +4400,21 @@ ofputil_decode_table_features(struct ofpbuf *msg,
     struct ofp13_table_features *otf;
     unsigned int len;
 
-    if (!msg->l2) {
-        msg->l2 = msg->data;
+    if (!msg->frame) {
         ofpraw_pull_assert(msg);
     }
 
-    if (!msg->size) {
+    if (!ofpbuf_size(msg)) {
         return EOF;
     }
 
-    if (msg->size < sizeof *otf) {
+    if (ofpbuf_size(msg) < sizeof *otf) {
         return OFPERR_OFPTFFC_BAD_LEN;
     }
 
-    otf = msg->data;
+    otf = ofpbuf_data(msg);
     len = ntohs(otf->length);
-    if (len < sizeof *otf || len % 8 || len > msg->size) {
+    if (len < sizeof *otf || len % 8 || len > ofpbuf_size(msg)) {
         return OFPERR_OFPTFFC_BAD_LEN;
     }
     ofpbuf_pull(msg, sizeof *otf);
@@ -4431,7 +4430,7 @@ ofputil_decode_table_features(struct ofpbuf *msg,
     tf->config = ntohl(otf->config);
     tf->max_entries = ntohl(otf->max_entries);
 
-    while (msg->size > 0) {
+    while (ofpbuf_size(msg) > 0) {
         struct ofpbuf payload;
         enum ofperr error;
         uint16_t type;
@@ -4564,7 +4563,7 @@ ofputil_decode_table_mod(const struct ofp_header *oh,
     raw = ofpraw_pull_assert(&b);
 
     if (raw == OFPRAW_OFPT11_TABLE_MOD) {
-        const struct ofp11_table_mod *otm = b.data;
+        const struct ofp11_table_mod *otm = ofpbuf_data(&b);
 
         pm->table_id = otm->table_id;
         pm->config = ntohl(otm->config);
@@ -4629,7 +4628,7 @@ ofputil_decode_role_message(const struct ofp_header *oh,
 
     if (raw == OFPRAW_OFPT12_ROLE_REQUEST ||
         raw == OFPRAW_OFPT12_ROLE_REPLY) {
-        const struct ofp12_role_request *orr = ofpbuf_get_l3(&b);
+        const struct ofp12_role_request *orr = ofpbuf_l3(&b);
 
         if (orr->role != htonl(OFPCR12_ROLE_NOCHANGE) &&
             orr->role != htonl(OFPCR12_ROLE_EQUAL) &&
@@ -4650,7 +4649,7 @@ ofputil_decode_role_message(const struct ofp_header *oh,
         }
     } else if (raw == OFPRAW_NXT_ROLE_REQUEST ||
                raw == OFPRAW_NXT_ROLE_REPLY) {
-        const struct nx_role_request *nrr = ofpbuf_get_l3(&b);
+        const struct nx_role_request *nrr = ofpbuf_l3(&b);
 
         BUILD_ASSERT(NX_ROLE_OTHER + 1 == OFPCR12_ROLE_EQUAL);
         BUILD_ASSERT(NX_ROLE_MASTER + 1 == OFPCR12_ROLE_MASTER);
@@ -4739,7 +4738,7 @@ ofputil_decode_role_status(const struct ofp_header *oh,
     raw = ofpraw_pull_assert(&b);
     ovs_assert(raw == OFPRAW_OFPT14_ROLE_STATUS);
 
-    r = ofpbuf_get_l3(&b);
+    r = ofpbuf_l3(&b);
     if (r->role != htonl(OFPCR12_ROLE_NOCHANGE) &&
         r->role != htonl(OFPCR12_ROLE_EQUAL) &&
         r->role != htonl(OFPCR12_ROLE_MASTER) &&
@@ -4942,19 +4941,18 @@ ofputil_decode_flow_monitor_request(struct ofputil_flow_monitor_request *rq,
     struct nx_flow_monitor_request *nfmr;
     uint16_t flags;
 
-    if (!msg->l2) {
-        msg->l2 = msg->data;
+    if (!msg->frame) {
         ofpraw_pull_assert(msg);
     }
 
-    if (!msg->size) {
+    if (!ofpbuf_size(msg)) {
         return EOF;
     }
 
     nfmr = ofpbuf_try_pull(msg, sizeof *nfmr);
     if (!nfmr) {
         VLOG_WARN_RL(&bad_ofmsg_rl, "NXST_FLOW_MONITOR request has %"PRIu32" "
-                     "leftover bytes at end", msg->size);
+                     "leftover bytes at end", ofpbuf_size(msg));
         return OFPERR_OFPBRC_BAD_LEN;
     }
 
@@ -4987,11 +4985,11 @@ ofputil_append_flow_monitor_request(
     size_t start_ofs;
     int match_len;
 
-    if (!msg->size) {
+    if (!ofpbuf_size(msg)) {
         ofpraw_put(OFPRAW_NXST_FLOW_MONITOR_REQUEST, OFP10_VERSION, msg);
     }
 
-    start_ofs = msg->size;
+    start_ofs = ofpbuf_size(msg);
     ofpbuf_put_zeros(msg, sizeof *nfmr);
     match_len = nx_put_match(msg, &rq->match, htonll(0), htonll(0));
 
@@ -5027,25 +5025,24 @@ ofputil_decode_flow_update(struct ofputil_flow_update *update,
     unsigned int length;
     struct ofp_header *oh;
 
-    if (!msg->l2) {
-        msg->l2 = msg->data;
+    if (!msg->frame) {
         ofpraw_pull_assert(msg);
     }
 
-    if (!msg->size) {
+    if (!ofpbuf_size(msg)) {
         return EOF;
     }
 
-    if (msg->size < sizeof(struct nx_flow_update_header)) {
+    if (ofpbuf_size(msg) < sizeof(struct nx_flow_update_header)) {
         goto bad_len;
     }
 
-    oh = msg->l2;
+    oh = msg->frame;
 
-    nfuh = msg->data;
+    nfuh = ofpbuf_data(msg);
     update->event = ntohs(nfuh->event);
     length = ntohs(nfuh->length);
-    if (length > msg->size || length % 8) {
+    if (length > ofpbuf_size(msg) || length % 8) {
         goto bad_len;
     }
 
@@ -5096,8 +5093,8 @@ ofputil_decode_flow_update(struct ofputil_flow_update *update,
             return error;
         }
 
-        update->ofpacts = ofpacts->data;
-        update->ofpacts_len = ofpacts->size;
+        update->ofpacts = ofpbuf_data(ofpacts);
+        update->ofpacts_len = ofpbuf_size(ofpacts);
         return 0;
     } else {
         VLOG_WARN_RL(&bad_ofmsg_rl,
@@ -5108,7 +5105,7 @@ ofputil_decode_flow_update(struct ofputil_flow_update *update,
 
 bad_len:
     VLOG_WARN_RL(&bad_ofmsg_rl, "NXST_FLOW_MONITOR reply has %"PRIu32" "
-                 "leftover bytes at end", msg->size);
+                 "leftover bytes at end", ofpbuf_size(msg));
     return OFPERR_OFPBRC_BAD_LEN;
 }
 
@@ -5154,8 +5151,8 @@ ofputil_append_flow_update(const struct ofputil_flow_update *update,
     enum ofp_version version;
 
     msg = ofpbuf_from_list(list_back(replies));
-    start_ofs = msg->size;
-    version = ((struct ofp_header *)msg->l2)->version;
+    start_ofs = ofpbuf_size(msg);
+    version = ((struct ofp_header *)msg->frame)->version;
 
     if (update->event == NXFME_ABBREV) {
         struct nx_flow_update_abbrev *nfua;
@@ -5181,7 +5178,7 @@ ofputil_append_flow_update(const struct ofputil_flow_update *update,
     }
 
     nfuh = ofpbuf_at_assert(msg, start_ofs, sizeof *nfuh);
-    nfuh->length = htons(msg->size - start_ofs);
+    nfuh->length = htons(ofpbuf_size(msg) - start_ofs);
     nfuh->event = htons(update->event);
 
     ofpmp_postappend(replies, start_ofs);
@@ -5207,14 +5204,14 @@ ofputil_encode_packet_out(const struct ofputil_packet_out *po,
 
         msg = ofpraw_alloc(OFPRAW_OFPT10_PACKET_OUT, OFP10_VERSION, size);
         ofpbuf_put_zeros(msg, sizeof *opo);
-        actions_ofs = msg->size;
+        actions_ofs = ofpbuf_size(msg);
         ofpacts_put_openflow_actions(po->ofpacts, po->ofpacts_len, msg,
                                      ofp_version);
 
-        opo = ofpbuf_get_l3(msg);
+        opo = ofpbuf_l3(msg);
         opo->buffer_id = htonl(po->buffer_id);
         opo->in_port = htons(ofp_to_u16(po->in_port));
-        opo->actions_len = htons(msg->size - actions_ofs);
+        opo->actions_len = htons(ofpbuf_size(msg) - actions_ofs);
         break;
     }
 
@@ -5229,7 +5226,7 @@ ofputil_encode_packet_out(const struct ofputil_packet_out *po,
         ofpbuf_put_zeros(msg, sizeof *opo);
         len = ofpacts_put_openflow_actions(po->ofpacts, po->ofpacts_len, msg,
                                            ofp_version);
-        opo = ofpbuf_get_l3(msg);
+        opo = ofpbuf_l3(msg);
         opo->buffer_id = htonl(po->buffer_id);
         opo->in_port = ofputil_port_to_ofp11(po->in_port);
         opo->actions_len = htons(len);
@@ -5268,8 +5265,8 @@ make_echo_reply(const struct ofp_header *rq)
     ofpbuf_use_const(&rq_buf, rq, ntohs(rq->length));
     ofpraw_pull_assert(&rq_buf);
 
-    reply = ofpraw_alloc_reply(OFPRAW_OFPT_ECHO_REPLY, rq, rq_buf.size);
-    ofpbuf_put(reply, rq_buf.data, rq_buf.size);
+    reply = ofpraw_alloc_reply(OFPRAW_OFPT_ECHO_REPLY, rq, ofpbuf_size(&rq_buf));
+    ofpbuf_put(reply, ofpbuf_data(&rq_buf), ofpbuf_size(&rq_buf));
     return reply;
 }
 
@@ -5572,7 +5569,7 @@ ofputil_pull_phy_port(enum ofp_version ofp_version, struct ofpbuf *b,
  * 'ofp_version', returns the number of elements. */
 size_t ofputil_count_phy_ports(uint8_t ofp_version, struct ofpbuf *b)
 {
-    return b->size / ofputil_get_phy_port_size(ofp_version);
+    return ofpbuf_size(b) / ofputil_get_phy_port_size(ofp_version);
 }
 
 /* ofp-util.def lists the mapping from names to action. */
@@ -5982,7 +5979,7 @@ 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;
+    struct ofp_header *oh = ofpbuf_data(msg);
 
     switch ((enum ofp_version)oh->version) {
     case OFP13_VERSION: {
@@ -6107,7 +6104,7 @@ ofputil_count_port_stats(const struct ofp_header *oh)
     ofpbuf_use_const(&b, oh, ntohs(oh->length));
     ofpraw_pull_assert(&b);
 
-    return b.size / ofputil_get_port_stats_size(oh->version);
+    return ofpbuf_size(&b) / ofputil_get_port_stats_size(oh->version);
 }
 
 /* Converts an OFPST_PORT_STATS reply in 'msg' into an abstract
@@ -6126,14 +6123,14 @@ 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)
+    error = (msg->frame
+             ? ofpraw_decode(&raw, msg->frame)
              : ofpraw_pull(&raw, msg));
     if (error) {
         return error;
     }
 
-    if (!msg->size) {
+    if (!ofpbuf_size(msg)) {
         return EOF;
     } else if (raw == OFPRAW_OFPST13_PORT_REPLY) {
         const struct ofp13_port_stats *ps13;
@@ -6165,7 +6162,7 @@ ofputil_decode_port_stats(struct ofputil_port_stats *ps, struct ofpbuf *msg)
 
  bad_len:
     VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_PORT reply has %"PRIu32" leftover "
-                 "bytes at end", msg->size);
+                 "bytes at end", ofpbuf_size(msg));
     return OFPERR_OFPBRC_BAD_LEN;
 }
 
@@ -6321,7 +6318,7 @@ ofputil_append_group_stats(struct list *replies,
                            const struct ofputil_group_stats *ogs)
 {
     struct ofpbuf *msg = ofpbuf_from_list(list_back(replies));
-    struct ofp_header *oh = msg->data;
+    struct ofp_header *oh = ofpbuf_data(msg);
 
     switch ((enum ofp_version)oh->version) {
     case OFP11_VERSION:
@@ -6451,14 +6448,14 @@ ofputil_decode_group_stats_reply(struct ofpbuf *msg,
     size_t i;
 
     gs->bucket_stats = NULL;
-    error = (msg->l2
-             ? ofpraw_decode(&raw, msg->l2)
+    error = (msg->frame
+             ? ofpraw_decode(&raw, msg->frame)
              : ofpraw_pull(&raw, msg));
     if (error) {
         return error;
     }
 
-    if (!msg->size) {
+    if (!ofpbuf_size(msg)) {
         return EOF;
     }
 
@@ -6484,7 +6481,7 @@ ofputil_decode_group_stats_reply(struct ofpbuf *msg,
 
     if (!ogs11) {
         VLOG_WARN_RL(&bad_ofmsg_rl, "%s reply has %"PRIu32" leftover bytes at end",
-                     ofpraw_get_name(raw), msg->size);
+                     ofpraw_get_name(raw), ofpbuf_size(msg));
         return OFPERR_OFPBRC_BAD_LEN;
     }
     length = ntohs(ogs11->length);
@@ -6503,7 +6500,7 @@ ofputil_decode_group_stats_reply(struct ofpbuf *msg,
     obc = ofpbuf_try_pull(msg, gs->n_buckets * sizeof *obc);
     if (!obc) {
         VLOG_WARN_RL(&bad_ofmsg_rl, "%s reply has %"PRIu32" leftover bytes at end",
-                     ofpraw_get_name(raw), msg->size);
+                     ofpraw_get_name(raw), ofpbuf_size(msg));
         return OFPERR_OFPBRC_BAD_LEN;
     }
 
@@ -6528,26 +6525,26 @@ ofputil_append_group_desc_reply(const struct ofputil_group_desc *gds,
     struct ofp11_group_desc_stats *ogds;
     struct ofputil_bucket *bucket;
     size_t start_ogds;
-    enum ofp_version version = ((struct ofp_header *)reply->data)->version;
+    enum ofp_version version = ((struct ofp_header *)ofpbuf_data(reply))->version;
 
-    start_ogds = reply->size;
+    start_ogds = ofpbuf_size(reply);
     ofpbuf_put_zeros(reply, sizeof *ogds);
     LIST_FOR_EACH (bucket, list_node, buckets) {
         struct ofp11_bucket *ob;
         size_t start_ob;
 
-        start_ob = reply->size;
+        start_ob = ofpbuf_size(reply);
         ofpbuf_put_zeros(reply, sizeof *ob);
         ofpacts_put_openflow_actions(bucket->ofpacts, bucket->ofpacts_len,
                                      reply, version);
         ob = ofpbuf_at_assert(reply, start_ob, sizeof *ob);
-        ob->len = htons(reply->size - start_ob);
+        ob->len = htons(ofpbuf_size(reply) - start_ob);
         ob->weight = htons(bucket->weight);
         ob->watch_port = ofputil_port_to_ofp11(bucket->watch_port);
         ob->watch_group = htonl(bucket->watch_group);
     }
     ogds = ofpbuf_at_assert(reply, start_ogds, sizeof *ogds);
-    ogds->length = htons(reply->size - start_ogds);
+    ogds->length = htons(ofpbuf_size(reply) - start_ogds);
     ogds->type = gds->type;
     ogds->group_id = htonl(gds->group_id);
 
@@ -6607,7 +6604,7 @@ ofputil_pull_buckets(struct ofpbuf *msg, size_t buckets_length,
         }
         bucket->watch_group = ntohl(ob->watch_group);
         bucket->ofpacts = ofpbuf_steal_data(&ofpacts);
-        bucket->ofpacts_len = ofpacts.size;
+        bucket->ofpacts_len = ofpbuf_size(&ofpacts);
         list_push_back(buckets, &bucket->list_node);
     }
 
@@ -6631,25 +6628,25 @@ ofputil_decode_group_desc_reply(struct ofputil_group_desc *gd,
     struct ofp11_group_desc_stats *ogds;
     size_t length;
 
-    if (!msg->l2) {
+    if (!msg->frame) {
         ofpraw_pull_assert(msg);
     }
 
-    if (!msg->size) {
+    if (!ofpbuf_size(msg)) {
         return EOF;
     }
 
     ogds = ofpbuf_try_pull(msg, sizeof *ogds);
     if (!ogds) {
         VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST11_GROUP_DESC reply has %"PRIu32" "
-                     "leftover bytes at end", msg->size);
+                     "leftover bytes at end", ofpbuf_size(msg));
         return OFPERR_OFPBRC_BAD_LEN;
     }
     gd->type = ogds->type;
     gd->group_id = ntohl(ogds->group_id);
 
     length = ntohs(ogds->length);
-    if (length < sizeof *ogds || length - sizeof *ogds > msg->size) {
+    if (length < sizeof *ogds || length - sizeof *ogds > ofpbuf_size(msg)) {
         VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST11_GROUP_DESC reply claims invalid "
                      "length %"PRIuSIZE, length);
         return OFPERR_OFPBRC_BAD_LEN;
@@ -6691,11 +6688,11 @@ ofputil_encode_group_mod(enum ofp_version ofp_version,
     case OFP13_VERSION:
     case OFP14_VERSION:
         b = ofpraw_alloc(OFPRAW_OFPT11_GROUP_MOD, ofp_version, 0);
-        start_ogm = b->size;
+        start_ogm = ofpbuf_size(b);
         ofpbuf_put_zeros(b, sizeof *ogm);
 
         LIST_FOR_EACH (bucket, list_node, &gm->buckets) {
-            start_bucket = b->size;
+            start_bucket = ofpbuf_size(b);
             ofpbuf_put_zeros(b, sizeof *ob);
             if (bucket->ofpacts && bucket->ofpacts_len) {
                 ofpacts_put_openflow_actions(bucket->ofpacts,
@@ -6703,7 +6700,7 @@ ofputil_encode_group_mod(enum ofp_version ofp_version,
                                              ofp_version);
             }
             ob = ofpbuf_at_assert(b, start_bucket, sizeof *ob);
-            ob->len = htons(b->size - start_bucket);;
+            ob->len = htons(ofpbuf_size(b) - start_bucket);;
             ob->weight = htons(bucket->weight);
             ob->watch_port = ofputil_port_to_ofp11(bucket->watch_port);
             ob->watch_group = htonl(bucket->watch_group);
@@ -6741,7 +6738,7 @@ ofputil_decode_group_mod(const struct ofp_header *oh,
     gm->type = ogm->type;
     gm->group_id = ntohl(ogm->group_id);
 
-    err = ofputil_pull_buckets(&msg, msg.size, oh->version, &gm->buckets);
+    err = ofputil_pull_buckets(&msg, ofpbuf_size(&msg), oh->version, &gm->buckets);
     if (err) {
         return err;
     }
@@ -6868,7 +6865,7 @@ ofputil_count_queue_stats(const struct ofp_header *oh)
     ofpbuf_use_const(&b, oh, ntohs(oh->length));
     ofpraw_pull_assert(&b);
 
-    return b.size / ofputil_get_queue_stats_size(oh->version);
+    return ofpbuf_size(&b) / ofputil_get_queue_stats_size(oh->version);
 }
 
 static enum ofperr
@@ -6934,14 +6931,14 @@ 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)
+    error = (msg->frame
+             ? ofpraw_decode(&raw, msg->frame)
              : ofpraw_pull(&raw, msg));
     if (error) {
         return error;
     }
 
-    if (!msg->size) {
+    if (!ofpbuf_size(msg)) {
         return EOF;
     } else if (raw == OFPRAW_OFPST13_QUEUE_REPLY) {
         const struct ofp13_queue_stats *qs13;
@@ -6973,7 +6970,7 @@ ofputil_decode_queue_stats(struct ofputil_queue_stats *qs, struct ofpbuf *msg)
 
  bad_len:
     VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_QUEUE reply has %"PRIu32" leftover "
-                 "bytes at end", msg->size);
+                 "bytes at end", ofpbuf_size(msg));
     return OFPERR_OFPBRC_BAD_LEN;
 }
 
@@ -7020,7 +7017,7 @@ 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;
+    struct ofp_header *oh = ofpbuf_data(msg);
 
     switch ((enum ofp_version)oh->version) {
     case OFP13_VERSION: {
index 298d595..245cc4e 100644 (file)
@@ -246,6 +246,13 @@ enum ofputil_flow_mod_flags {
     OFPUTIL_FF_CHECK_OVERLAP = 1 << 3, /* All versions. */
     OFPUTIL_FF_EMERG         = 1 << 4, /* OpenFlow 1.0 only. */
     OFPUTIL_FF_RESET_COUNTS  = 1 << 5, /* OpenFlow 1.2+. */
+
+    /* Flags that are only set by OVS for its internal use.  Cannot be set via
+     * OpenFlow. */
+    OFPUTIL_FF_HIDDEN_FIELDS = 1 << 6, /* Allow hidden match fields to be
+                                          set or modified. */
+    OFPUTIL_FF_NO_READONLY   = 1 << 7, /* Allow rules within read only tables
+                                          to be modified */
 };
 
 /* Protocol-independent flow_mod.
index 56e1ec6..1f4b61d 100644 (file)
 #include "util.h"
 
 static void
-ofpbuf_use__(struct ofpbuf *b, void *base, size_t allocated,
-             enum ofpbuf_source source)
+ofpbuf_init__(struct ofpbuf *b, size_t allocated, enum ofpbuf_source source)
 {
-    b->base = b->data = base;
     b->allocated = allocated;
     b->source = source;
-    b->size = 0;
-    b->l2 = NULL;
+    b->frame = NULL;
     b->l2_5_ofs = b->l3_ofs = b->l4_ofs = UINT16_MAX;
     list_poison(&b->list_node);
 }
 
+static void
+ofpbuf_use__(struct ofpbuf *b, void *base, size_t allocated,
+             enum ofpbuf_source source)
+{
+    ofpbuf_set_base(b, base);
+    ofpbuf_set_data(b, base);
+    ofpbuf_set_size(b, 0);
+
+    ofpbuf_init__(b, allocated, source);
+}
+
 /* Initializes 'b' as an empty ofpbuf that contains the 'allocated' bytes of
  * memory starting at 'base'.  'base' should be the first byte of a region
  * obtained from malloc().  It will be freed (with free()) if 'b' is resized or
@@ -96,7 +104,19 @@ void
 ofpbuf_use_const(struct ofpbuf *b, const void *data, size_t size)
 {
     ofpbuf_use__(b, CONST_CAST(void *, data), size, OFPBUF_STACK);
-    b->size = size;
+    ofpbuf_set_size(b, size);
+}
+
+/* Initializes 'b' as an empty ofpbuf that contains the 'allocated' bytes of
+ * memory starting at 'base'.  DPDK allocated ofpbuf and *data is allocated
+ * from one continous memory region, so in memory data start right after
+ * ofpbuf.  Therefore there is special method to free this type of
+ * buffer.  ofpbuf base, data and size are initialized by dpdk rcv() so no
+ * need to initialize those fields. */
+void
+ofpbuf_init_dpdk(struct ofpbuf *b, size_t allocated)
+{
+    ofpbuf_init__(b, allocated, OFPBUF_DPDK);
 }
 
 /* Initializes 'b' as an empty ofpbuf with an initial capacity of 'size'
@@ -113,11 +133,9 @@ ofpbuf_uninit(struct ofpbuf *b)
 {
     if (b) {
         if (b->source == OFPBUF_MALLOC) {
-            free(b->base);
-        }
-        if (b->source == OFPBUF_DPDK) {
-            free_dpdk_buf(b);
+            free(ofpbuf_base(b));
         }
+        ovs_assert(b->source != OFPBUF_DPDK);
     }
 }
 
@@ -150,7 +168,7 @@ ofpbuf_new_with_headroom(size_t size, size_t headroom)
 }
 
 /* Creates and returns a new ofpbuf that initially contains a copy of the
- * 'buffer->size' bytes of data starting at 'buffer->data' with no headroom or
+ * 'ofpbuf_size(buffer)' bytes of data starting at 'buffer->data' with no headroom or
  * tailroom. */
 struct ofpbuf *
 ofpbuf_clone(const struct ofpbuf *buffer)
@@ -165,12 +183,14 @@ ofpbuf_clone_with_headroom(const struct ofpbuf *buffer, size_t headroom)
 {
     struct ofpbuf *new_buffer;
 
-    new_buffer = ofpbuf_clone_data_with_headroom(buffer->data, buffer->size,
+    new_buffer = ofpbuf_clone_data_with_headroom(ofpbuf_data(buffer),
+                                                 ofpbuf_size(buffer),
                                                  headroom);
-    if (buffer->l2) {
-        uintptr_t data_delta = (char *)new_buffer->data - (char *)buffer->data;
+    if (buffer->frame) {
+        uintptr_t data_delta
+            = (char *)ofpbuf_data(new_buffer) - (char *)ofpbuf_data(buffer);
 
-        new_buffer->l2 = (char *) buffer->l2 + data_delta;
+        new_buffer->frame = (char *) buffer->frame + data_delta;
     }
     new_buffer->l2_5_ofs = buffer->l2_5_ofs;
     new_buffer->l3_ofs = buffer->l3_ofs;
@@ -202,7 +222,7 @@ static void
 ofpbuf_copy__(struct ofpbuf *b, uint8_t *new_base,
               size_t new_headroom, size_t new_tailroom)
 {
-    const uint8_t *old_base = b->base;
+    const uint8_t *old_base = ofpbuf_base(b);
     size_t old_headroom = ofpbuf_headroom(b);
     size_t old_tailroom = ofpbuf_tailroom(b);
     size_t copy_headroom = MIN(old_headroom, new_headroom);
@@ -210,7 +230,7 @@ ofpbuf_copy__(struct ofpbuf *b, uint8_t *new_base,
 
     memcpy(&new_base[new_headroom - copy_headroom],
            &old_base[old_headroom - copy_headroom],
-           copy_headroom + b->size + copy_tailroom);
+           copy_headroom + ofpbuf_size(b) + copy_tailroom);
 }
 
 /* Reallocates 'b' so that it has exactly 'new_headroom' and 'new_tailroom'
@@ -221,7 +241,7 @@ ofpbuf_resize__(struct ofpbuf *b, size_t new_headroom, size_t new_tailroom)
     void *new_base, *new_data;
     size_t new_allocated;
 
-    new_allocated = new_headroom + b->size + new_tailroom;
+    new_allocated = new_headroom + ofpbuf_size(b) + new_tailroom;
 
     switch (b->source) {
     case OFPBUF_DPDK:
@@ -229,11 +249,11 @@ ofpbuf_resize__(struct ofpbuf *b, size_t new_headroom, size_t new_tailroom)
 
     case OFPBUF_MALLOC:
         if (new_headroom == ofpbuf_headroom(b)) {
-            new_base = xrealloc(b->base, new_allocated);
+            new_base = xrealloc(ofpbuf_base(b), new_allocated);
         } else {
             new_base = xmalloc(new_allocated);
             ofpbuf_copy__(b, new_base, new_headroom, new_tailroom);
-            free(b->base);
+            free(ofpbuf_base(b));
         }
         break;
 
@@ -251,16 +271,16 @@ ofpbuf_resize__(struct ofpbuf *b, size_t new_headroom, size_t new_tailroom)
     }
 
     b->allocated = new_allocated;
-    b->base = new_base;
+    ofpbuf_set_base(b, new_base);
 
     new_data = (char *) new_base + new_headroom;
-    if (b->data != new_data) {
-        uintptr_t data_delta = (char *) new_data - (char *) b->data;
+    if (ofpbuf_data(b) != new_data) {
+        if (b->frame) {
+            uintptr_t data_delta = (char *) new_data - (char *) ofpbuf_data(b);
 
-        b->data = new_data;
-        if (b->l2) {
-            b->l2 = (char *) b->l2 + data_delta;
+            b->frame = (char *) b->frame + data_delta;
         }
+        ofpbuf_set_data(b, new_data);
     }
 }
 
@@ -307,8 +327,8 @@ ofpbuf_trim(struct ofpbuf *b)
 void
 ofpbuf_padto(struct ofpbuf *b, size_t length)
 {
-    if (b->size < length) {
-        ofpbuf_put_zeros(b, length - b->size);
+    if (ofpbuf_size(b) < length) {
+        ofpbuf_put_zeros(b, length - ofpbuf_size(b));
     }
 }
 
@@ -324,9 +344,9 @@ ofpbuf_shift(struct ofpbuf *b, int delta)
                : true);
 
     if (delta != 0) {
-        char *dst = (char *) b->data + delta;
-        memmove(dst, b->data, b->size);
-        b->data = dst;
+        char *dst = (char *) ofpbuf_data(b) + delta;
+        memmove(dst, ofpbuf_data(b), ofpbuf_size(b));
+        ofpbuf_set_data(b, dst);
     }
 }
 
@@ -339,7 +359,7 @@ ofpbuf_put_uninit(struct ofpbuf *b, size_t size)
     void *p;
     ofpbuf_prealloc_tailroom(b, size);
     p = ofpbuf_tail(b);
-    b->size += size;
+    ofpbuf_set_size(b, ofpbuf_size(b) + size);
     return p;
 }
 
@@ -373,7 +393,7 @@ ofpbuf_put(struct ofpbuf *b, const void *p, size_t size)
 char *
 ofpbuf_put_hex(struct ofpbuf *b, const char *s, size_t *n)
 {
-    size_t initial_size = b->size;
+    size_t initial_size = ofpbuf_size(b);
     for (;;) {
         uint8_t byte;
         bool ok;
@@ -382,7 +402,7 @@ ofpbuf_put_hex(struct ofpbuf *b, const char *s, size_t *n)
         byte = hexits_value(s, 2, &ok);
         if (!ok) {
             if (n) {
-                *n = b->size - initial_size;
+                *n = ofpbuf_size(b) - initial_size;
             }
             return CONST_CAST(char *, s);
         }
@@ -397,9 +417,9 @@ ofpbuf_put_hex(struct ofpbuf *b, const char *s, size_t *n)
 void
 ofpbuf_reserve(struct ofpbuf *b, size_t size)
 {
-    ovs_assert(!b->size);
+    ovs_assert(!ofpbuf_size(b));
     ofpbuf_prealloc_tailroom(b, size);
-    b->data = (char*)b->data + size;
+    ofpbuf_set_data(b, (char*)ofpbuf_data(b) + size);
 }
 
 /* Reserves 'size' bytes of headroom so that they can be later allocated with
@@ -408,9 +428,9 @@ void
 ofpbuf_reserve_with_tailroom(struct ofpbuf *b, size_t headroom,
                              size_t tailroom)
 {
-    ovs_assert(!b->size);
+    ovs_assert(!ofpbuf_size(b));
     ofpbuf_prealloc_tailroom(b, headroom + tailroom);
-    b->data = (char*)b->data + headroom;
+    ofpbuf_set_data(b, (char*)ofpbuf_data(b) + headroom);
 }
 
 /* Prefixes 'size' bytes to the head end of 'b', reallocating and copying its
@@ -420,9 +440,9 @@ void *
 ofpbuf_push_uninit(struct ofpbuf *b, size_t size)
 {
     ofpbuf_prealloc_headroom(b, size);
-    b->data = (char*)b->data - size;
-    b->size += size;
-    return b->data;
+    ofpbuf_set_data(b, (char*)ofpbuf_data(b) - size);
+    ofpbuf_set_size(b, ofpbuf_size(b) + size);
+    return ofpbuf_data(b);
 }
 
 /* Prefixes 'size' zeroed bytes to the head end of 'b', reallocating and
@@ -456,15 +476,16 @@ ofpbuf_steal_data(struct ofpbuf *b)
     void *p;
     ovs_assert(b->source != OFPBUF_DPDK);
 
-    if (b->source == OFPBUF_MALLOC && b->data == b->base) {
-        p = b->data;
+    if (b->source == OFPBUF_MALLOC && ofpbuf_data(b) == ofpbuf_base(b)) {
+        p = ofpbuf_data(b);
     } else {
-        p = xmemdup(b->data, b->size);
+        p = xmemdup(ofpbuf_data(b), ofpbuf_size(b));
         if (b->source == OFPBUF_MALLOC) {
-            free(b->base);
+            free(ofpbuf_base(b));
         }
     }
-    b->base = b->data = NULL;
+    ofpbuf_set_base(b, NULL);
+    ofpbuf_set_data(b, NULL);
     return p;
 }
 
@@ -477,9 +498,9 @@ ofpbuf_to_string(const struct ofpbuf *b, size_t maxbytes)
 
     ds_init(&s);
     ds_put_format(&s, "size=%"PRIu32", allocated=%"PRIu32", head=%"PRIuSIZE", tail=%"PRIuSIZE"\n",
-                  b->size, b->allocated,
+                  ofpbuf_size(b), b->allocated,
                   ofpbuf_headroom(b), ofpbuf_tailroom(b));
-    ds_put_hex_dump(&s, b->data, MIN(b->size, maxbytes), 0, false);
+    ds_put_hex_dump(&s, ofpbuf_data(b), MIN(ofpbuf_size(b), maxbytes), 0, false);
     return ds_cstr(&s);
 }
 
@@ -516,12 +537,12 @@ ofpbuf_resize_l2_5(struct ofpbuf *b, int increment)
         ofpbuf_pull(b, -increment);
     }
 
-    b->l2 = b->data;
+    b->frame = ofpbuf_data(b);
     /* Adjust layer offsets after l2_5. */
     ofpbuf_adjust_layer_offset(&b->l3_ofs, increment);
     ofpbuf_adjust_layer_offset(&b->l4_ofs, increment);
 
-    return b->l2;
+    return b->frame;
 }
 
 /* Adjust the size of the l2 portion of the ofpbuf, updating the l2
@@ -532,5 +553,5 @@ ofpbuf_resize_l2(struct ofpbuf *b, int increment)
 {
     ofpbuf_resize_l2_5(b, increment);
     ofpbuf_adjust_layer_offset(&b->l2_5_ofs, increment);
-    return b->l2;
+    return b->frame;
 }
index 8d1cb11..85be899 100644 (file)
@@ -22,6 +22,7 @@
 #include "list.h"
 #include "packets.h"
 #include "util.h"
+#include "netdev-dpdk.h"
 
 #ifdef  __cplusplus
 extern "C" {
@@ -36,33 +37,65 @@ enum OVS_PACKED_ENUM ofpbuf_source {
 };
 
 /* Buffer for holding arbitrary data.  An ofpbuf is automatically reallocated
- * as necessary if it grows too large for the available memory. */
+ * as necessary if it grows too large for the available memory.
+ *
+ * 'frame' and offset conventions:
+ *
+ * Network frames (aka "packets"): 'frame' MUST be set to the start of the
+ *    packet, layer offsets MAY be set as appropriate for the packet.
+ *    Additionally, we assume in many places that the 'frame' and 'data' are
+ *    the same for packets.
+ *
+ * OpenFlow messages: 'frame' points to the start of the OpenFlow
+ *    header, while 'l3_ofs' is the length of the OpenFlow header.
+ *    When parsing, the 'data' will move past these, as data is being
+ *    pulled from the OpenFlow message.
+ *
+ * Actions: When encoding OVS action lists, the 'frame' is used
+ *    as a pointer to the beginning of the current action (see ofpact_put()).
+ *
+ * rconn: Reuses 'frame' as a private pointer while queuing.
+ */
 struct ofpbuf {
-    void *base;                 /* First byte of allocated space. */
+#ifdef DPDK_NETDEV
+    struct rte_mbuf mbuf;       /* DPDK mbuf */
+#else
+    void *base_;                 /* First byte of allocated space. */
+    void *data_;                 /* First byte actually in use. */
+    uint32_t size_;              /* Number of bytes in use. */
+#endif
     uint32_t allocated;         /* Number of bytes allocated. */
-    uint32_t size;              /* Number of bytes in use. */
-    void *data;                 /* First byte actually in use. */
 
-    void *l2;                   /* Link-level header. */
-    uint16_t l2_5_ofs;          /* MPLS label stack offset from l2, or
+    void *frame;                /* Packet frame start, or NULL. */
+    uint16_t l2_5_ofs;          /* MPLS label stack offset from 'frame', or
                                  * UINT16_MAX */
-    uint16_t l3_ofs;            /* Network-level header offset from l2, or
-                                 * UINT16_MAX. */
-    uint16_t l4_ofs;            /* Transport-level header offset from l2, or
-                                   UINT16_MAX. */
+    uint16_t l3_ofs;            /* Network-level header offset from 'frame',
+                                   or UINT16_MAX. */
+    uint16_t l4_ofs;            /* Transport-level header offset from 'frame',
+                                   or UINT16_MAX. */
     enum ofpbuf_source source;  /* Source of memory allocated as 'base'. */
     struct list list_node;      /* Private list element for use by owner. */
 };
 
+static inline void * ofpbuf_data(const struct ofpbuf *);
+static inline void ofpbuf_set_data(struct ofpbuf *, void *);
+static inline void * ofpbuf_base(const struct ofpbuf *);
+static inline void ofpbuf_set_base(struct ofpbuf *, void *);
+
+static inline uint32_t ofpbuf_size(const struct ofpbuf *);
+static inline void ofpbuf_set_size(struct ofpbuf *, uint32_t);
+
 void * ofpbuf_resize_l2(struct ofpbuf *, int increment);
 void * ofpbuf_resize_l2_5(struct ofpbuf *, int increment);
-static inline void * ofpbuf_get_l2_5(const struct ofpbuf *);
+static inline void * ofpbuf_l2(const struct ofpbuf *);
+static inline void ofpbuf_set_frame(struct ofpbuf *, void *);
+static inline void * ofpbuf_l2_5(const struct ofpbuf *);
 static inline void ofpbuf_set_l2_5(struct ofpbuf *, void *);
-static inline void * ofpbuf_get_l3(const struct ofpbuf *);
+static inline void * ofpbuf_l3(const struct ofpbuf *);
 static inline void ofpbuf_set_l3(struct ofpbuf *, void *);
-static inline void * ofpbuf_get_l4(const struct ofpbuf *);
+static inline void * ofpbuf_l4(const struct ofpbuf *);
 static inline void ofpbuf_set_l4(struct ofpbuf *, void *);
-static inline size_t ofpbuf_get_l4_size(const struct ofpbuf *);
+static inline size_t ofpbuf_l4_size(const struct ofpbuf *);
 static inline const void *ofpbuf_get_tcp_payload(const struct ofpbuf *);
 static inline const void *ofpbuf_get_udp_payload(const struct ofpbuf *);
 static inline const void *ofpbuf_get_sctp_payload(const struct ofpbuf *);
@@ -73,6 +106,8 @@ void ofpbuf_use_stack(struct ofpbuf *, void *, size_t);
 void ofpbuf_use_stub(struct ofpbuf *, void *, size_t);
 void ofpbuf_use_const(struct ofpbuf *, const void *, size_t);
 
+void ofpbuf_init_dpdk(struct ofpbuf *b, size_t allocated);
+
 void ofpbuf_init(struct ofpbuf *, size_t);
 void ofpbuf_uninit(struct ofpbuf *);
 static inline void *ofpbuf_get_uninit_pointer(struct ofpbuf *);
@@ -132,13 +167,18 @@ static inline bool ofpbuf_equal(const struct ofpbuf *, const struct ofpbuf *);
 static inline void *ofpbuf_get_uninit_pointer(struct ofpbuf *b)
 {
     /* XXX: If 'source' is OFPBUF_DPDK memory gets leaked! */
-    return b && b->source == OFPBUF_MALLOC ? b->base : NULL;
+    return b && b->source == OFPBUF_MALLOC ? ofpbuf_base(b) : NULL;
 }
 
 /* Frees memory that 'b' points to, as well as 'b' itself. */
 static inline void ofpbuf_delete(struct ofpbuf *b)
 {
     if (b) {
+        if (b->source == OFPBUF_DPDK) {
+            free_dpdk_buf(b);
+            return;
+        }
+
         ofpbuf_uninit(b);
         free(b);
     }
@@ -149,7 +189,7 @@ static inline void ofpbuf_delete(struct ofpbuf *b)
 static inline void *ofpbuf_at(const struct ofpbuf *b, size_t offset,
                               size_t size)
 {
-    return offset + size <= b->size ? (char *) b->data + offset : NULL;
+    return offset + size <= ofpbuf_size(b) ? (char *) ofpbuf_data(b) + offset : NULL;
 }
 
 /* Returns a pointer to byte 'offset' in 'b', which must contain at least
@@ -157,21 +197,21 @@ static inline void *ofpbuf_at(const struct ofpbuf *b, size_t offset,
 static inline void *ofpbuf_at_assert(const struct ofpbuf *b, size_t offset,
                                      size_t size)
 {
-    ovs_assert(offset + size <= b->size);
-    return ((char *) b->data) + offset;
+    ovs_assert(offset + size <= ofpbuf_size(b));
+    return ((char *) ofpbuf_data(b)) + offset;
 }
 
 /* Returns the byte following the last byte of data in use in 'b'. */
 static inline void *ofpbuf_tail(const struct ofpbuf *b)
 {
-    return (char *) b->data + b->size;
+    return (char *) ofpbuf_data(b) + ofpbuf_size(b);
 }
 
 /* Returns the byte following the last byte allocated for use (but not
  * necessarily in use) by 'b'. */
 static inline void *ofpbuf_end(const struct ofpbuf *b)
 {
-    return (char *) b->base + b->allocated;
+    return (char *) ofpbuf_base(b) + b->allocated;
 }
 
 /* Returns the number of bytes of headroom in 'b', that is, the number of bytes
@@ -180,7 +220,7 @@ static inline void *ofpbuf_end(const struct ofpbuf *b)
  * headroom is 0.) */
 static inline size_t ofpbuf_headroom(const struct ofpbuf *b)
 {
-    return (char*)b->data - (char*)b->base;
+    return (char*)ofpbuf_data(b) - (char*)ofpbuf_base(b);
 }
 
 /* Returns the number of bytes that may be appended to the tail end of ofpbuf
@@ -193,18 +233,18 @@ static inline size_t ofpbuf_tailroom(const struct ofpbuf *b)
 /* Clears any data from 'b'. */
 static inline void ofpbuf_clear(struct ofpbuf *b)
 {
-    b->data = b->base;
-    b->size = 0;
+    ofpbuf_set_data(b, ofpbuf_base(b));
+    ofpbuf_set_size(b, 0);
 }
 
 /* Removes 'size' bytes from the head end of 'b', which must contain at least
  * 'size' bytes of data.  Returns the first byte of data removed. */
 static inline void *ofpbuf_pull(struct ofpbuf *b, size_t size)
 {
-    void *data = b->data;
-    ovs_assert(b->size >= size);
-    b->data = (char*)b->data + size;
-    b->size -= size;
+    void *data = ofpbuf_data(b);
+    ovs_assert(ofpbuf_size(b) >= size);
+    ofpbuf_set_data(b, (char*)ofpbuf_data(b) + size);
+    ofpbuf_set_size(b, ofpbuf_size(b) - size);
     return data;
 }
 
@@ -213,7 +253,7 @@ static inline void *ofpbuf_pull(struct ofpbuf *b, size_t size)
  * null pointer without modifying 'b'. */
 static inline void *ofpbuf_try_pull(struct ofpbuf *b, size_t size)
 {
-    return b->size >= size ? ofpbuf_pull(b, size) : NULL;
+    return ofpbuf_size(b) >= size ? ofpbuf_pull(b, size) : NULL;
 }
 
 static inline struct ofpbuf *ofpbuf_from_list(const struct list *list)
@@ -223,51 +263,69 @@ static inline struct ofpbuf *ofpbuf_from_list(const struct list *list)
 
 static inline bool ofpbuf_equal(const struct ofpbuf *a, const struct ofpbuf *b)
 {
-    return a->size == b->size && memcmp(a->data, b->data, a->size) == 0;
+    return ofpbuf_size(a) == ofpbuf_size(b) &&
+           memcmp(ofpbuf_data(a), ofpbuf_data(b), ofpbuf_size(a)) == 0;
+}
+
+/* Get the start if the Ethernet frame.  'l3_ofs' marks the end of the l2
+ * headers, so return NULL if it is not set. */
+static inline void * ofpbuf_l2(const struct ofpbuf *b)
+{
+    return (b->l3_ofs != UINT16_MAX) ? b->frame : NULL;
+}
+
+/* Sets the packet frame start pointer and resets all layer offsets.
+ * l3 offset must be set before 'l2' can be retrieved. */
+static inline void ofpbuf_set_frame(struct ofpbuf *b, void *packet)
+{
+    b->frame = packet;
+    b->l2_5_ofs = UINT16_MAX;
+    b->l3_ofs = UINT16_MAX;
+    b->l4_ofs = UINT16_MAX;
 }
 
-static inline void * ofpbuf_get_l2_5(const struct ofpbuf *b)
+static inline void * ofpbuf_l2_5(const struct ofpbuf *b)
 {
-    return b->l2_5_ofs != UINT16_MAX ? (char *)b->l2 + b->l2_5_ofs : NULL;
+    return b->l2_5_ofs != UINT16_MAX ? (char *)b->frame + b->l2_5_ofs : NULL;
 }
 
 static inline void ofpbuf_set_l2_5(struct ofpbuf *b, void *l2_5)
 {
-    b->l2_5_ofs = l2_5 ? (char *)l2_5 - (char *)b->l2 : UINT16_MAX;
+    b->l2_5_ofs = l2_5 ? (char *)l2_5 - (char *)b->frame : UINT16_MAX;
 }
 
-static inline void * ofpbuf_get_l3(const struct ofpbuf *b)
+static inline void * ofpbuf_l3(const struct ofpbuf *b)
 {
-    return b->l3_ofs != UINT16_MAX ? (char *)b->l2 + b->l3_ofs : NULL;
+    return b->l3_ofs != UINT16_MAX ? (char *)b->frame + b->l3_ofs : NULL;
 }
 
 static inline void ofpbuf_set_l3(struct ofpbuf *b, void *l3)
 {
-    b->l3_ofs = l3 ? (char *)l3 - (char *)b->l2 : UINT16_MAX;
+    b->l3_ofs = l3 ? (char *)l3 - (char *)b->frame : UINT16_MAX;
 }
 
-static inline void * ofpbuf_get_l4(const struct ofpbuf *b)
+static inline void * ofpbuf_l4(const struct ofpbuf *b)
 {
-    return b->l4_ofs != UINT16_MAX ? (char *)b->l2 + b->l4_ofs : NULL;
+    return b->l4_ofs != UINT16_MAX ? (char *)b->frame + b->l4_ofs : NULL;
 }
 
 static inline void ofpbuf_set_l4(struct ofpbuf *b, void *l4)
 {
-    b->l4_ofs = l4 ? (char *)l4 - (char *)b->l2 : UINT16_MAX;
+    b->l4_ofs = l4 ? (char *)l4 - (char *)b->frame : UINT16_MAX;
 }
 
-static inline size_t ofpbuf_get_l4_size(const struct ofpbuf *b)
+static inline size_t ofpbuf_l4_size(const struct ofpbuf *b)
 {
     return b->l4_ofs != UINT16_MAX
-        ? (const char *)ofpbuf_tail(b) - (const char *)ofpbuf_get_l4(b) : 0;
+        ? (const char *)ofpbuf_tail(b) - (const char *)ofpbuf_l4(b) : 0;
 }
 
 static inline const void *ofpbuf_get_tcp_payload(const struct ofpbuf *b)
 {
-    size_t l4_size = ofpbuf_get_l4_size(b);
+    size_t l4_size = ofpbuf_l4_size(b);
 
     if (OVS_LIKELY(l4_size >= TCP_HEADER_LEN)) {
-        struct tcp_header *tcp = ofpbuf_get_l4(b);
+        struct tcp_header *tcp = ofpbuf_l4(b);
         int tcp_len = TCP_OFFSET(tcp->tcp_ctl) * 4;
 
         if (OVS_LIKELY(tcp_len >= TCP_HEADER_LEN && tcp_len <= l4_size)) {
@@ -279,22 +337,87 @@ static inline const void *ofpbuf_get_tcp_payload(const struct ofpbuf *b)
 
 static inline const void *ofpbuf_get_udp_payload(const struct ofpbuf *b)
 {
-    return OVS_LIKELY(ofpbuf_get_l4_size(b) >= UDP_HEADER_LEN)
-        ? (const char *)ofpbuf_get_l4(b) + UDP_HEADER_LEN : NULL;
+    return OVS_LIKELY(ofpbuf_l4_size(b) >= UDP_HEADER_LEN)
+        ? (const char *)ofpbuf_l4(b) + UDP_HEADER_LEN : NULL;
 }
 
 static inline const void *ofpbuf_get_sctp_payload(const struct ofpbuf *b)
 {
-    return OVS_LIKELY(ofpbuf_get_l4_size(b) >= SCTP_HEADER_LEN)
-        ? (const char *)ofpbuf_get_l4(b) + SCTP_HEADER_LEN : NULL;
+    return OVS_LIKELY(ofpbuf_l4_size(b) >= SCTP_HEADER_LEN)
+        ? (const char *)ofpbuf_l4(b) + SCTP_HEADER_LEN : NULL;
 }
 
 static inline const void *ofpbuf_get_icmp_payload(const struct ofpbuf *b)
 {
-    return OVS_LIKELY(ofpbuf_get_l4_size(b) >= ICMP_HEADER_LEN)
-        ? (const char *)ofpbuf_get_l4(b) + ICMP_HEADER_LEN : NULL;
+    return OVS_LIKELY(ofpbuf_l4_size(b) >= ICMP_HEADER_LEN)
+        ? (const char *)ofpbuf_l4(b) + ICMP_HEADER_LEN : NULL;
+}
+
+#ifdef DPDK_NETDEV
+static inline void * ofpbuf_data(const struct ofpbuf *b)
+{
+    return b->mbuf.pkt.data;
 }
 
+static inline void ofpbuf_set_data(struct ofpbuf *b, void *d)
+{
+    b->mbuf.pkt.data = d;
+}
+
+static inline void * ofpbuf_base(const struct ofpbuf *b)
+{
+    return b->mbuf.buf_addr;
+}
+
+static inline void ofpbuf_set_base(struct ofpbuf *b, void *d)
+{
+    b->mbuf.buf_addr = d;
+}
+
+static inline uint32_t ofpbuf_size(const struct ofpbuf *b)
+{
+    return b->mbuf.pkt.pkt_len;
+}
+
+static inline void ofpbuf_set_size(struct ofpbuf *b, uint32_t v)
+{
+    b->mbuf.pkt.data_len = v;    /* Current seg length. */
+    b->mbuf.pkt.pkt_len = v;     /* Total length of all segments linked to
+                                  * this segment. */
+}
+
+#else
+static inline void * ofpbuf_data(const struct ofpbuf *b)
+{
+    return b->data_;
+}
+
+static inline void ofpbuf_set_data(struct ofpbuf *b, void *d)
+{
+    b->data_ = d;
+}
+
+static inline void * ofpbuf_base(const struct ofpbuf *b)
+{
+    return b->base_;
+}
+
+static inline void ofpbuf_set_base(struct ofpbuf *b, void *d)
+{
+    b->base_ = d;
+}
+
+static inline uint32_t ofpbuf_size(const struct ofpbuf *b)
+{
+    return b->size_;
+}
+
+static inline void ofpbuf_set_size(struct ofpbuf *b, uint32_t v)
+{
+    b->size_ = v;
+}
+#endif
+
 #ifdef  __cplusplus
 }
 #endif
index b4b28db..0706dd0 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -41,7 +41,7 @@ wrap_json(const char *name, struct json *wrapped)
 
 /* Initializes 'atom' with the default value of the given 'type'.
  *
- * The default value for an atom is as defined in ovsdb/SPECS:
+ * The default value for an atom is as defined in RFC 7047:
  *
  *      - "integer" or "real": 0
  *
@@ -409,10 +409,9 @@ ovsdb_atom_from_json__(union ovsdb_atom *atom,
  * Violations of constraints expressed by 'base' are treated as errors.
  *
  * If 'symtab' is nonnull, then named UUIDs in 'symtab' are accepted.  Refer to
- * ovsdb/SPECS for information about this, and for the syntax that this
- * function accepts.  If 'base' is a reference and a symbol is parsed, then the
- * symbol's 'strong_ref' or 'weak_ref' member is set to true, as
- * appropriate. */
+ * RFC 7047 for information about this, and for the syntax that this function
+ * accepts.  If 'base' is a reference and a symbol is parsed, then the symbol's
+ * 'strong_ref' or 'weak_ref' member is set to true, as appropriate. */
 struct ovsdb_error *
 ovsdb_atom_from_json(union ovsdb_atom *atom,
                      const struct ovsdb_base_type *base,
@@ -436,8 +435,7 @@ ovsdb_atom_from_json(union ovsdb_atom *atom,
 /* Converts 'atom', of the specified 'type', to JSON format, and returns the
  * JSON.  The caller is responsible for freeing the returned JSON.
  *
- * Refer to ovsdb/SPECS for the format of the JSON that this function
- * produces. */
+ * Refer to RFC 7047 for the format of the JSON that this function produces. */
 struct json *
 ovsdb_atom_to_json(const union ovsdb_atom *atom, enum ovsdb_atomic_type type)
 {
@@ -467,47 +465,6 @@ ovsdb_atom_to_json(const union ovsdb_atom *atom, enum ovsdb_atomic_type type)
     }
 }
 
-/* Returns strlen(json_to_string(ovsdb_atom_to_json(atom, type), 0)). */
-size_t
-ovsdb_atom_json_length(const union ovsdb_atom *atom,
-                       enum ovsdb_atomic_type type)
-{
-    struct json json;
-
-    switch (type) {
-    case OVSDB_TYPE_VOID:
-        OVS_NOT_REACHED();
-
-    case OVSDB_TYPE_INTEGER:
-        json.type = JSON_INTEGER;
-        json.u.integer = atom->integer;
-        break;
-
-    case OVSDB_TYPE_REAL:
-        json.type = JSON_REAL;
-        json.u.real = atom->real;
-        break;
-
-    case OVSDB_TYPE_BOOLEAN:
-        json.type = atom->boolean ? JSON_TRUE : JSON_FALSE;
-        break;
-
-    case OVSDB_TYPE_STRING:
-        json.type = JSON_STRING;
-        json.u.string = atom->string;
-        break;
-
-    case OVSDB_TYPE_UUID:
-        return strlen("[\"uuid\",\"00000000-0000-0000-0000-000000000000\"]");
-
-    case OVSDB_N_TYPES:
-    default:
-        OVS_NOT_REACHED();
-    }
-
-    return json_serialized_length(&json);
-}
-
 static char *
 ovsdb_atom_from_string__(union ovsdb_atom *atom,
                          const struct ovsdb_base_type *base, const char *s,
@@ -884,7 +841,7 @@ ovsdb_datum_init_empty(struct ovsdb_datum *datum)
 
 /* Initializes 'datum' as a datum that has the default value for 'type'.
  *
- * The default value for a particular type is as defined in ovsdb/SPECS:
+ * The default value for a particular type is as defined in RFC 7047:
  *
  *    - If n_min is 0, then the default value is the empty set (or map).
  *
@@ -1289,8 +1246,8 @@ ovsdb_datum_from_json__(struct ovsdb_datum *datum,
  * Violations of constraints expressed by 'type' are treated as errors.
  *
  * If 'symtab' is nonnull, then named UUIDs in 'symtab' are accepted.  Refer to
- * ovsdb/SPECS for information about this, and for the syntax that this
- * function accepts. */
+ * RFC 7047 for information about this, and for the syntax that this function
+ * accepts. */
 struct ovsdb_error *
 ovsdb_datum_from_json(struct ovsdb_datum *datum,
                       const struct ovsdb_type *type,
@@ -1316,8 +1273,7 @@ ovsdb_datum_from_json(struct ovsdb_datum *datum,
  *
  * 'type' constraints on datum->n are ignored.
  *
- * Refer to ovsdb/SPECS for the format of the JSON that this function
- * produces. */
+ * Refer to RFC 7047 for the format of the JSON that this function produces. */
 struct json *
 ovsdb_datum_to_json(const struct ovsdb_datum *datum,
                     const struct ovsdb_type *type)
@@ -1349,56 +1305,6 @@ ovsdb_datum_to_json(const struct ovsdb_datum *datum,
     }
 }
 
-/* Returns strlen(json_to_string(ovsdb_datum_to_json(datum, type), 0)). */
-size_t
-ovsdb_datum_json_length(const struct ovsdb_datum *datum,
-                        const struct ovsdb_type *type)
-{
-    if (ovsdb_type_is_map(type)) {
-        size_t length;
-
-        /* ["map",[...]]. */
-        length = 10;
-        if (datum->n > 0) {
-            size_t i;
-
-            /* Commas between pairs in the inner [...] */
-            length += datum->n - 1;
-
-            /* [,] in each pair. */
-            length += datum->n * 3;
-
-            /* Data. */
-            for (i = 0; i < datum->n; i++) {
-                length += ovsdb_atom_json_length(&datum->keys[i],
-                                                 type->key.type);
-                length += ovsdb_atom_json_length(&datum->values[i],
-                                                 type->value.type);
-            }
-        }
-        return length;
-    } else if (datum->n == 1) {
-        return ovsdb_atom_json_length(&datum->keys[0], type->key.type);
-    } else {
-        size_t length;
-        size_t i;
-
-        /* ["set",[...]]. */
-        length = 10;
-        if (datum->n > 0) {
-            /* Commas between elements in the inner [...]. */
-            length += datum->n - 1;
-
-            /* Data. */
-            for (i = 0; i < datum->n; i++) {
-                length += ovsdb_atom_json_length(&datum->keys[i],
-                                                 type->key.type);
-            }
-        }
-        return length;
-    }
-}
-
 static const char *
 skip_spaces(const char *p)
 {
index ece1672..2e31cc5 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012, 2013 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.
@@ -88,8 +88,6 @@ struct ovsdb_error *ovsdb_atom_from_json(union ovsdb_atom *,
     WARN_UNUSED_RESULT;
 struct json *ovsdb_atom_to_json(const union ovsdb_atom *,
                                 enum ovsdb_atomic_type);
-size_t ovsdb_atom_json_length(const union ovsdb_atom *,
-                              enum ovsdb_atomic_type);
 
 char *ovsdb_atom_from_string(union ovsdb_atom *,
                              const struct ovsdb_base_type *, const char *,
@@ -165,8 +163,6 @@ struct ovsdb_error *ovsdb_datum_from_json(struct ovsdb_datum *,
     WARN_UNUSED_RESULT;
 struct json *ovsdb_datum_to_json(const struct ovsdb_datum *,
                                  const struct ovsdb_type *);
-size_t ovsdb_datum_json_length(const struct ovsdb_datum *,
-                               const struct ovsdb_type *);
 
 char *ovsdb_datum_from_string(struct ovsdb_datum *,
                               const struct ovsdb_type *, const char *,
index 3366089..6244c3f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -168,13 +168,15 @@ compose_rarp(struct ofpbuf *b, const uint8_t eth_src[ETH_ADDR_LEN])
     put_16aligned_be32(&arp->ar_spa, htonl(0));
     memcpy(arp->ar_tha, eth_src, ETH_ADDR_LEN);
     put_16aligned_be32(&arp->ar_tpa, htonl(0));
+
+    ofpbuf_set_frame(b, eth);
+    ofpbuf_set_l3(b, arp);
 }
 
 /* Insert VLAN header according to given TCI. Packet passed must be Ethernet
  * packet.  Ignores the CFI bit of 'tci' using 0 instead.
  *
- * Also sets 'packet->l2' to point to the new Ethernet header and adjusts
- * the layer offsets accordingly. */
+ * Also adjusts the layer offsets accordingly. */
 void
 eth_push_vlan(struct ofpbuf *packet, ovs_be16 tpid, ovs_be16 tci)
 {
@@ -194,9 +196,9 @@ eth_push_vlan(struct ofpbuf *packet, ovs_be16 tpid, ovs_be16 tci)
 void
 eth_pop_vlan(struct ofpbuf *packet)
 {
-    struct vlan_eth_header *veh = packet->l2;
+    struct vlan_eth_header *veh = ofpbuf_l2(packet);
 
-    if (packet->size >= sizeof *veh
+    if (veh && ofpbuf_size(packet) >= sizeof *veh
         && veh->veth_type == htons(ETH_TYPE_VLAN)) {
 
         memmove((char *)veh + VLAN_HEADER_LEN, veh, 2 * ETH_ADDR_LEN);
@@ -208,14 +210,18 @@ eth_pop_vlan(struct ofpbuf *packet)
 static void
 set_ethertype(struct ofpbuf *packet, ovs_be16 eth_type)
 {
-    struct eth_header *eh = packet->l2;
+    struct eth_header *eh = ofpbuf_l2(packet);
+
+    if (!eh) {
+        return;
+    }
 
     if (eh->eth_type == htons(ETH_TYPE_VLAN)) {
         ovs_be16 *p;
-        char *l2_5 = ofpbuf_get_l2_5(packet);
+        char *l2_5 = ofpbuf_l2_5(packet);
 
         p = ALIGNED_CAST(ovs_be16 *,
-                         (l2_5 ? l2_5 : (char *)ofpbuf_get_l3(packet)) - 2);
+                         (l2_5 ? l2_5 : (char *)ofpbuf_l3(packet)) - 2);
         *p = eth_type;
     } else {
         eh->eth_type = eth_type;
@@ -279,10 +285,10 @@ set_mpls_lse(struct ofpbuf *packet, ovs_be32 mpls_lse)
 {
     /* Packet type should be MPLS to set label stack entry. */
     if (is_mpls(packet)) {
-        struct mpls_hdr *mh = ofpbuf_get_l2_5(packet);
+        struct mpls_hdr *mh = ofpbuf_l2_5(packet);
 
         /* Update mpls label stack entry. */
-        mh->mpls_lse = mpls_lse;
+        put_16aligned_be32(&mh->mpls_lse, mpls_lse);
     }
 }
 
@@ -321,15 +327,15 @@ void
 pop_mpls(struct ofpbuf *packet, ovs_be16 ethtype)
 {
     if (is_mpls(packet)) {
-        struct mpls_hdr *mh = ofpbuf_get_l2_5(packet);
+        struct mpls_hdr *mh = ofpbuf_l2_5(packet);
         size_t len = packet->l2_5_ofs;
 
         set_ethertype(packet, ethtype);
-        if (mh->mpls_lse & htonl(MPLS_BOS_MASK)) {
+        if (get_16aligned_be32(&mh->mpls_lse) & htonl(MPLS_BOS_MASK)) {
             ofpbuf_set_l2_5(packet, NULL);
         }
         /* Shift the l2 header forward. */
-        memmove((char*)packet->data + MPLS_HLEN, packet->data, len);
+        memmove((char*)ofpbuf_data(packet) + MPLS_HLEN, ofpbuf_data(packet), len);
         ofpbuf_resize_l2_5(packet, -MPLS_HLEN);
     }
 }
@@ -353,7 +359,7 @@ eth_from_hex(const char *hex, struct ofpbuf **packetp)
         return "Trailing garbage in packet data";
     }
 
-    if (packet->size < ETH_HEADER_LEN) {
+    if (ofpbuf_size(packet) < ETH_HEADER_LEN) {
         ofpbuf_delete(packet);
         *packetp = NULL;
         return "Packet data too short for Ethernet";
@@ -545,8 +551,8 @@ ipv6_is_cidr(const struct in6_addr *netmask)
 /* Populates 'b' with an Ethernet II packet headed with the given 'eth_dst',
  * 'eth_src' and 'eth_type' parameters.  A payload of 'size' bytes is allocated
  * in 'b' and returned.  This payload may be populated with appropriate
- * information by the caller.  Sets 'b''s 'l2' pointer and 'l3' offset to the
- * Ethernet header and payload respectively.  Aligns b->l3 on a 32-bit
+ * information by the caller.  Sets 'b''s 'frame' pointer and 'l3' offset to
+ * the Ethernet header and payload respectively.  Aligns b->l3 on a 32-bit
  * boundary.
  *
  * The returned packet has enough headroom to insert an 802.1Q VLAN header if
@@ -572,7 +578,7 @@ eth_compose(struct ofpbuf *b, const uint8_t eth_dst[ETH_ADDR_LEN],
     memcpy(eth->eth_src, eth_src, ETH_ADDR_LEN);
     eth->eth_type = htons(eth_type);
 
-    b->l2 = eth;
+    ofpbuf_set_frame(b, eth);
     ofpbuf_set_l3(b, data);
 
     return data;
@@ -582,16 +588,16 @@ static void
 packet_set_ipv4_addr(struct ofpbuf *packet,
                      ovs_16aligned_be32 *addr, ovs_be32 new_addr)
 {
-    struct ip_header *nh = ofpbuf_get_l3(packet);
+    struct ip_header *nh = ofpbuf_l3(packet);
     ovs_be32 old_addr = get_16aligned_be32(addr);
-    size_t l4_size = ofpbuf_get_l4_size(packet);
+    size_t l4_size = ofpbuf_l4_size(packet);
 
     if (nh->ip_proto == IPPROTO_TCP && l4_size >= TCP_HEADER_LEN) {
-        struct tcp_header *th = ofpbuf_get_l4(packet);
+        struct tcp_header *th = ofpbuf_l4(packet);
 
         th->tcp_csum = recalc_csum32(th->tcp_csum, old_addr, new_addr);
     } else if (nh->ip_proto == IPPROTO_UDP && l4_size >= UDP_HEADER_LEN ) {
-        struct udp_header *uh = ofpbuf_get_l4(packet);
+        struct udp_header *uh = ofpbuf_l4(packet);
 
         if (uh->udp_csum) {
             uh->udp_csum = recalc_csum32(uh->udp_csum, old_addr, new_addr);
@@ -615,7 +621,7 @@ packet_rh_present(struct ofpbuf *packet)
     int nexthdr;
     size_t len;
     size_t remaining;
-    uint8_t *data = ofpbuf_get_l3(packet);
+    uint8_t *data = ofpbuf_l3(packet);
 
     remaining = packet->l4_ofs - packet->l3_ofs;
 
@@ -693,14 +699,14 @@ static void
 packet_update_csum128(struct ofpbuf *packet, uint8_t proto,
                      ovs_16aligned_be32 addr[4], const ovs_be32 new_addr[4])
 {
-    size_t l4_size = ofpbuf_get_l4_size(packet);
+    size_t l4_size = ofpbuf_l4_size(packet);
 
     if (proto == IPPROTO_TCP && l4_size >= TCP_HEADER_LEN) {
-        struct tcp_header *th = ofpbuf_get_l4(packet);
+        struct tcp_header *th = ofpbuf_l4(packet);
 
         th->tcp_csum = recalc_csum128(th->tcp_csum, addr, new_addr);
     } else if (proto == IPPROTO_UDP && l4_size >= UDP_HEADER_LEN) {
-        struct udp_header *uh = ofpbuf_get_l4(packet);
+        struct udp_header *uh = ofpbuf_l4(packet);
 
         if (uh->udp_csum) {
             uh->udp_csum = recalc_csum128(uh->udp_csum, addr, new_addr);
@@ -746,7 +752,7 @@ void
 packet_set_ipv4(struct ofpbuf *packet, ovs_be32 src, ovs_be32 dst,
                 uint8_t tos, uint8_t ttl)
 {
-    struct ip_header *nh = ofpbuf_get_l3(packet);
+    struct ip_header *nh = ofpbuf_l3(packet);
 
     if (get_16aligned_be32(&nh->ip_src) != src) {
         packet_set_ipv4_addr(packet, &nh->ip_src, src);
@@ -782,7 +788,7 @@ packet_set_ipv6(struct ofpbuf *packet, uint8_t proto, const ovs_be32 src[4],
                 const ovs_be32 dst[4], uint8_t key_tc, ovs_be32 key_fl,
                 uint8_t key_hl)
 {
-    struct ovs_16aligned_ip6_hdr *nh = ofpbuf_get_l3(packet);
+    struct ovs_16aligned_ip6_hdr *nh = ofpbuf_l3(packet);
 
     if (memcmp(&nh->ip6_src, src, sizeof(ovs_be32[4]))) {
         packet_set_ipv6_addr(packet, proto, nh->ip6_src.be32, src, true);
@@ -815,7 +821,7 @@ packet_set_port(ovs_be16 *port, ovs_be16 new_port, ovs_be16 *csum)
 void
 packet_set_tcp_port(struct ofpbuf *packet, ovs_be16 src, ovs_be16 dst)
 {
-    struct tcp_header *th = ofpbuf_get_l4(packet);
+    struct tcp_header *th = ofpbuf_l4(packet);
 
     packet_set_port(&th->tcp_src, src, &th->tcp_csum);
     packet_set_port(&th->tcp_dst, dst, &th->tcp_csum);
@@ -827,7 +833,7 @@ packet_set_tcp_port(struct ofpbuf *packet, ovs_be16 src, ovs_be16 dst)
 void
 packet_set_udp_port(struct ofpbuf *packet, ovs_be16 src, ovs_be16 dst)
 {
-    struct udp_header *uh = ofpbuf_get_l4(packet);
+    struct udp_header *uh = ofpbuf_l4(packet);
 
     if (uh->udp_csum) {
         packet_set_port(&uh->udp_src, src, &uh->udp_csum);
@@ -848,19 +854,19 @@ packet_set_udp_port(struct ofpbuf *packet, ovs_be16 src, ovs_be16 dst)
 void
 packet_set_sctp_port(struct ofpbuf *packet, ovs_be16 src, ovs_be16 dst)
 {
-    struct sctp_header *sh = ofpbuf_get_l4(packet);
+    struct sctp_header *sh = ofpbuf_l4(packet);
     ovs_be32 old_csum, old_correct_csum, new_csum;
-    uint16_t tp_len = packet->size - ((uint8_t*)sh - (uint8_t*)packet->data);
+    uint16_t tp_len = ofpbuf_l4_size(packet);
 
-    old_csum = sh->sctp_csum;
-    sh->sctp_csum = 0;
+    old_csum = get_16aligned_be32(&sh->sctp_csum);
+    put_16aligned_be32(&sh->sctp_csum, 0);
     old_correct_csum = crc32c((void *)sh, tp_len);
 
     sh->sctp_src = src;
     sh->sctp_dst = dst;
 
     new_csum = crc32c((void *)sh, tp_len);
-    sh->sctp_csum = old_csum ^ old_correct_csum ^ new_csum;
+    put_16aligned_be32(&sh->sctp_csum, old_csum ^ old_correct_csum ^ new_csum);
 }
 
 const char *
index 22817af..eca24d5 100644 (file)
@@ -363,7 +363,7 @@ BUILD_ASSERT_DECL(VLAN_ETH_HEADER_LEN == sizeof(struct vlan_eth_header));
 #define MPLS_HLEN           4
 
 struct mpls_hdr {
-    ovs_be32 mpls_lse;
+    ovs_16aligned_be32 mpls_lse;
 };
 BUILD_ASSERT_DECL(MPLS_HLEN == sizeof(struct mpls_hdr));
 
@@ -510,8 +510,8 @@ BUILD_ASSERT_DECL(ICMP_HEADER_LEN == sizeof(struct icmp_header));
 struct sctp_header {
     ovs_be16 sctp_src;
     ovs_be16 sctp_dst;
-    ovs_be32 sctp_vtag;
-    ovs_be32 sctp_csum;
+    ovs_16aligned_be32 sctp_vtag;
+    ovs_16aligned_be32 sctp_csum;
 };
 BUILD_ASSERT_DECL(SCTP_HEADER_LEN == sizeof(struct sctp_header));
 
index a92e7d3..191e690 100644 (file)
@@ -198,10 +198,10 @@ ovs_pcap_write(FILE *file, struct ofpbuf *buf)
     xgettimeofday(&tv);
     prh.ts_sec = tv.tv_sec;
     prh.ts_usec = tv.tv_usec;
-    prh.incl_len = buf->size;
-    prh.orig_len = buf->size;
+    prh.incl_len = ofpbuf_size(buf);
+    prh.orig_len = ofpbuf_size(buf);
     ignore(fwrite(&prh, sizeof prh, 1, file));
-    ignore(fwrite(buf->data, buf->size, 1, file));
+    ignore(fwrite(ofpbuf_data(buf), ofpbuf_size(buf), 1, file));
 }
 \f
 struct tcp_key {
@@ -310,7 +310,7 @@ tcp_reader_run(struct tcp_reader *r, const struct flow *flow,
         || !l7) {
         return NULL;
     }
-    tcp = ofpbuf_get_l4(packet);
+    tcp = ofpbuf_l4(packet);
     flags = TCP_FLAGS(tcp->tcp_ctl);
     l7_length = (char *) ofpbuf_tail(packet) - l7;
     seq = ntohl(get_16aligned_be32(&tcp->tcp_seq));
@@ -346,7 +346,7 @@ tcp_reader_run(struct tcp_reader *r, const struct flow *flow,
         /* Shift all of the existing payload to the very beginning of the
          * allocated space, so that we reuse allocated space instead of
          * continually expanding it. */
-        ofpbuf_shift(payload, (char *) payload->base - (char *) payload->data);
+        ofpbuf_shift(payload, (char *) ofpbuf_base(payload) - (char *) ofpbuf_data(payload));
 
         ofpbuf_put(payload, l7, l7_length);
         stream->seq_no += l7_length;
index a5368d5..cb3cdd5 100644 (file)
@@ -718,12 +718,11 @@ rconn_send__(struct rconn *rc, struct ofpbuf *b,
         copy_to_monitor(rc, b);
 
         if (counter) {
-            rconn_packet_counter_inc(counter, b->size);
+            rconn_packet_counter_inc(counter, ofpbuf_size(b));
         }
 
-        /* Use 'l2' as a private pointer while 'b' is in txq. */
-        ovs_assert(b->l2 == b->data);
-        b->l2 = counter;
+        /* Reuse 'frame' as a private pointer while 'b' is in txq. */
+        ofpbuf_set_frame(b, counter);
 
         list_push_back(&rc->txq, &b->list_node);
 
@@ -1107,19 +1106,19 @@ try_send(struct rconn *rc)
     OVS_REQUIRES(rc->mutex)
 {
     struct ofpbuf *msg = ofpbuf_from_list(rc->txq.next);
-    unsigned int n_bytes = msg->size;
-    struct rconn_packet_counter *counter = msg->l2;
+    unsigned int n_bytes = ofpbuf_size(msg);
+    struct rconn_packet_counter *counter = msg->frame;
     int retval;
 
     /* Eagerly remove 'msg' from the txq.  We can't remove it from the list
      * after sending, if sending is successful, because it is then owned by the
      * vconn, which might have freed it already. */
     list_remove(&msg->list_node);
-    msg->l2 = msg->data; /* Restore 'l2'. */
+    ofpbuf_set_frame(msg, NULL);
 
     retval = vconn_send(rc->vconn, msg);
     if (retval) {
-        msg->l2 = counter; /* 'l2' is a private pointer while msg is in txq. */
+        ofpbuf_set_frame(msg, counter);
         list_push_front(&rc->txq, &msg->list_node);
         if (retval != EAGAIN) {
             report_error(rc, retval);
@@ -1212,9 +1211,9 @@ flush_queue(struct rconn *rc)
     }
     while (!list_is_empty(&rc->txq)) {
         struct ofpbuf *b = ofpbuf_from_list(list_pop_front(&rc->txq));
-        struct rconn_packet_counter *counter = b->l2;
+        struct rconn_packet_counter *counter = b->frame;
         if (counter) {
-            rconn_packet_counter_dec(counter, b->size);
+            rconn_packet_counter_dec(counter, ofpbuf_size(b));
         }
         COVERAGE_INC(rconn_discarded);
         ofpbuf_delete(b);
@@ -1324,7 +1323,7 @@ is_admitted_msg(const struct ofpbuf *b)
     enum ofptype type;
     enum ofperr error;
 
-    error = ofptype_decode(&type, b->data);
+    error = ofptype_decode(&type, ofpbuf_data(b));
     if (error) {
         return false;
     }
index fdc21e8..8f5b733 100644 (file)
@@ -272,7 +272,7 @@ route_table_parse(struct ofpbuf *buf, struct route_table_msg *change)
         const struct rtmsg *rtm;
         const struct nlmsghdr *nlmsg;
 
-        nlmsg = buf->data;
+        nlmsg = ofpbuf_data(buf);
         rtm = ofpbuf_at(buf, NLMSG_HDRLEN, sizeof *rtm);
 
         if (rtm->rtm_family != AF_INET) {
index 308338f..1c12562 100644 (file)
@@ -58,7 +58,7 @@ rtnetlink_link_parse(struct ofpbuf *buf,
         const struct nlmsghdr *nlmsg;
         const struct ifinfomsg *ifinfo;
 
-        nlmsg  = buf->data;
+        nlmsg  = ofpbuf_data(buf);
         ifinfo = ofpbuf_at(buf, NLMSG_HDRLEN, sizeof *ifinfo);
 
         change->nlmsg_type     = nlmsg->nlmsg_type;
index 78dacb3..dbe48e8 100644 (file)
--- a/lib/stp.c
+++ b/lib/stp.c
@@ -1535,14 +1535,15 @@ stp_send_bpdu(struct stp_port *p, const void *bpdu, size_t bpdu_size)
 
     /* Skeleton. */
     pkt = ofpbuf_new(ETH_HEADER_LEN + LLC_HEADER_LEN + bpdu_size);
-    pkt->l2 = eth = ofpbuf_put_zeros(pkt, sizeof *eth);
+    eth = ofpbuf_put_zeros(pkt, sizeof *eth);
     llc = ofpbuf_put_zeros(pkt, sizeof *llc);
+    ofpbuf_set_frame(pkt, eth);
     ofpbuf_set_l3(pkt, ofpbuf_put(pkt, bpdu, bpdu_size));
 
     /* 802.2 header. */
     memcpy(eth->eth_dst, eth_addr_stp, ETH_ADDR_LEN);
     /* p->stp->send_bpdu() must fill in source address. */
-    eth->eth_type = htons(pkt->size - ETH_HEADER_LEN);
+    eth->eth_type = htons(ofpbuf_size(pkt) - ETH_HEADER_LEN);
 
     /* LLC header. */
     llc->llc_dsap = STP_LLC_DSAP;
index 14d62c4..7a0d218 100644 (file)
@@ -650,14 +650,15 @@ ssl_do_tx(struct stream *stream)
 
     for (;;) {
         int old_state = SSL_get_state(sslv->ssl);
-        int ret = SSL_write(sslv->ssl, sslv->txbuf->data, sslv->txbuf->size);
+        int ret = SSL_write(sslv->ssl,
+                            ofpbuf_data(sslv->txbuf), ofpbuf_size(sslv->txbuf));
         if (old_state != SSL_get_state(sslv->ssl)) {
             sslv->rx_want = SSL_NOTHING;
         }
         sslv->tx_want = SSL_NOTHING;
         if (ret > 0) {
             ofpbuf_pull(sslv->txbuf, ret);
-            if (sslv->txbuf->size == 0) {
+            if (ofpbuf_size(sslv->txbuf) == 0) {
                 return 0;
             }
         } else {
index d169840..9347b5e 100644 (file)
@@ -103,7 +103,7 @@ vconn_stream_close(struct vconn *vconn)
     struct vconn_stream *s = vconn_stream_cast(vconn);
 
     if ((vconn->error == EPROTO || s->n_packets < 1) && s->rxbuf) {
-        stream_report_content(s->rxbuf->data, s->rxbuf->size, STREAM_OPENFLOW,
+        stream_report_content(ofpbuf_data(s->rxbuf), ofpbuf_size(s->rxbuf), STREAM_OPENFLOW,
                               THIS_MODULE, vconn_get_name(vconn));
     }
 
@@ -126,14 +126,14 @@ vconn_stream_recv__(struct vconn_stream *s, int rx_len)
     struct ofpbuf *rx = s->rxbuf;
     int want_bytes, retval;
 
-    want_bytes = rx_len - rx->size;
+    want_bytes = rx_len - ofpbuf_size(rx);
     ofpbuf_prealloc_tailroom(rx, want_bytes);
     retval = stream_recv(s->stream, ofpbuf_tail(rx), want_bytes);
     if (retval > 0) {
-        rx->size += retval;
+        ofpbuf_set_size(rx, ofpbuf_size(rx) + retval);
         return retval == want_bytes ? 0 : EAGAIN;
     } else if (retval == 0) {
-        if (rx->size) {
+        if (ofpbuf_size(rx)) {
             VLOG_ERR_RL(&rl, "connection dropped mid-packet");
             return EPROTO;
         }
@@ -156,7 +156,7 @@ vconn_stream_recv(struct vconn *vconn, struct ofpbuf **bufferp)
     }
 
     /* Read ofp_header. */
-    if (s->rxbuf->size < sizeof(struct ofp_header)) {
+    if (ofpbuf_size(s->rxbuf) < sizeof(struct ofp_header)) {
         int retval = vconn_stream_recv__(s, sizeof(struct ofp_header));
         if (retval) {
             return retval;
@@ -164,12 +164,12 @@ vconn_stream_recv(struct vconn *vconn, struct ofpbuf **bufferp)
     }
 
     /* Read payload. */
-    oh = s->rxbuf->data;
+    oh = ofpbuf_data(s->rxbuf);
     rx_len = ntohs(oh->length);
     if (rx_len < sizeof(struct ofp_header)) {
         VLOG_ERR_RL(&rl, "received too-short ofp_header (%d bytes)", rx_len);
         return EPROTO;
-    } else if (s->rxbuf->size < rx_len) {
+    } else if (ofpbuf_size(s->rxbuf) < rx_len) {
         int retval = vconn_stream_recv__(s, rx_len);
         if (retval) {
             return retval;
@@ -199,8 +199,8 @@ vconn_stream_send(struct vconn *vconn, struct ofpbuf *buffer)
         return EAGAIN;
     }
 
-    retval = stream_send(s->stream, buffer->data, buffer->size);
-    if (retval == buffer->size) {
+    retval = stream_send(s->stream, ofpbuf_data(buffer), ofpbuf_size(buffer));
+    if (retval == ofpbuf_size(buffer)) {
         ofpbuf_delete(buffer);
         return 0;
     } else if (retval >= 0 || retval == -EAGAIN) {
@@ -225,7 +225,7 @@ vconn_stream_run(struct vconn *vconn)
         return;
     }
 
-    retval = stream_send(s->stream, s->txbuf->data, s->txbuf->size);
+    retval = stream_send(s->stream, ofpbuf_data(s->txbuf), ofpbuf_size(s->txbuf));
     if (retval < 0) {
         if (retval != -EAGAIN) {
             VLOG_ERR_RL(&rl, "send: %s", ovs_strerror(-retval));
@@ -234,7 +234,7 @@ vconn_stream_run(struct vconn *vconn)
         }
     } else if (retval > 0) {
         ofpbuf_pull(s->txbuf, retval);
-        if (!s->txbuf->size) {
+        if (!ofpbuf_size(s->txbuf)) {
             vconn_stream_clear_txbuf(s);
             return;
         }
index d6d239f..c24e87d 100644 (file)
@@ -456,16 +456,16 @@ vcs_recv_hello(struct vconn *vconn)
         enum ofptype type;
         enum ofperr error;
 
-        error = ofptype_decode(&type, b->data);
+        error = ofptype_decode(&type, ofpbuf_data(b));
         if (!error && type == OFPTYPE_HELLO) {
             char *peer_s, *local_s;
             uint32_t common_versions;
 
-            if (!ofputil_decode_hello(b->data, &vconn->peer_versions)) {
+            if (!ofputil_decode_hello(ofpbuf_data(b), &vconn->peer_versions)) {
                 struct ds msg = DS_EMPTY_INITIALIZER;
                 ds_put_format(&msg, "%s: unknown data in hello:\n",
                               vconn->name);
-                ds_put_hex_dump(&msg, b->data, b->size, 0, true);
+                ds_put_hex_dump(&msg, ofpbuf_data(b), ofpbuf_size(b), 0, true);
                 VLOG_WARN_RL(&bad_ofmsg_rl, "%s", ds_cstr(&msg));
                 ds_destroy(&msg);
             }
@@ -495,7 +495,7 @@ vcs_recv_hello(struct vconn *vconn)
             ofpbuf_delete(b);
             return;
         } else {
-            char *s = ofp_to_string(b->data, b->size, 1);
+            char *s = ofp_to_string(ofpbuf_data(b), ofpbuf_size(b), 1);
             VLOG_WARN_RL(&bad_ofmsg_rl,
                          "%s: received message while expecting hello: %s",
                          vconn->name, s);
@@ -598,11 +598,11 @@ vconn_recv(struct vconn *vconn, struct ofpbuf **msgp)
         retval = do_recv(vconn, &msg);
     }
     if (!retval && !vconn->recv_any_version) {
-        const struct ofp_header *oh = msg->data;
+        const struct ofp_header *oh = ofpbuf_data(msg);
         if (oh->version != vconn->version) {
             enum ofptype type;
 
-            if (ofptype_decode(&type, msg->data)
+            if (ofptype_decode(&type, ofpbuf_data(msg))
                 || (type != OFPTYPE_HELLO &&
                     type != OFPTYPE_ERROR &&
                     type != OFPTYPE_ECHO_REQUEST &&
@@ -641,7 +641,7 @@ do_recv(struct vconn *vconn, struct ofpbuf **msgp)
     if (!retval) {
         COVERAGE_INC(vconn_received);
         if (VLOG_IS_DBG_ENABLED()) {
-            char *s = ofp_to_string((*msgp)->data, (*msgp)->size, 1);
+            char *s = ofp_to_string(ofpbuf_data(*msgp), ofpbuf_size(*msgp), 1);
             VLOG_DBG_RL(&ofmsg_rl, "%s: received: %s", vconn->name, s);
             free(s);
         }
@@ -674,14 +674,14 @@ do_send(struct vconn *vconn, struct ofpbuf *msg)
 {
     int retval;
 
-    ovs_assert(msg->size >= sizeof(struct ofp_header));
+    ovs_assert(ofpbuf_size(msg) >= sizeof(struct ofp_header));
 
     ofpmsg_update_length(msg);
     if (!VLOG_IS_DBG_ENABLED()) {
         COVERAGE_INC(vconn_sent);
         retval = (vconn->class->send)(vconn, msg);
     } else {
-        char *s = ofp_to_string(msg->data, msg->size, 1);
+        char *s = ofp_to_string(ofpbuf_data(msg), ofpbuf_size(msg), 1);
         retval = (vconn->class->send)(vconn, msg);
         if (retval != EAGAIN) {
             VLOG_DBG_RL(&ofmsg_rl, "%s: sent (%s): %s",
@@ -763,7 +763,7 @@ vconn_recv_xid(struct vconn *vconn, ovs_be32 xid, struct ofpbuf **replyp)
             *replyp = NULL;
             return error;
         }
-        recv_xid = ((struct ofp_header *) reply->data)->xid;
+        recv_xid = ((struct ofp_header *) ofpbuf_data(reply))->xid;
         if (xid == recv_xid) {
             *replyp = reply;
             return 0;
@@ -790,7 +790,7 @@ int
 vconn_transact(struct vconn *vconn, struct ofpbuf *request,
                struct ofpbuf **replyp)
 {
-    ovs_be32 send_xid = ((struct ofp_header *) request->data)->xid;
+    ovs_be32 send_xid = ((struct ofp_header *) ofpbuf_data(request))->xid;
     int error;
 
     *replyp = NULL;
@@ -824,7 +824,7 @@ vconn_transact_noreply(struct vconn *vconn, struct ofpbuf *request,
     *replyp = NULL;
 
     /* Send request. */
-    request_xid = ((struct ofp_header *) request->data)->xid;
+    request_xid = ((struct ofp_header *) ofpbuf_data(request))->xid;
     error = vconn_send_block(vconn, request);
     if (error) {
         ofpbuf_delete(request);
@@ -833,7 +833,7 @@ vconn_transact_noreply(struct vconn *vconn, struct ofpbuf *request,
 
     /* Send barrier. */
     barrier = ofputil_encode_barrier_request(vconn_get_version(vconn));
-    barrier_xid = ((struct ofp_header *) barrier->data)->xid;
+    barrier_xid = ((struct ofp_header *) ofpbuf_data(barrier))->xid;
     error = vconn_send_block(vconn, barrier);
     if (error) {
         ofpbuf_delete(barrier);
@@ -852,7 +852,7 @@ vconn_transact_noreply(struct vconn *vconn, struct ofpbuf *request,
             return error;
         }
 
-        msg_xid = ((struct ofp_header *) msg->data)->xid;
+        msg_xid = ((struct ofp_header *) ofpbuf_data(msg))->xid;
         if (msg_xid == request_xid) {
             if (*replyp) {
                 VLOG_WARN_RL(&bad_ofmsg_rl, "%s: duplicate replies with "
index 382487c..d2f5a37 100644 (file)
@@ -374,7 +374,7 @@ static int
 vlandev_del__(const char *vlan_dev)
 {
     struct shash_node *vd_node = shash_find(&vlan_devs, vlan_dev);
-    if (!vd_node) {
+    if (vd_node) {
         struct vlan_dev *vd = vd_node->data;
         struct vlan_real_dev *vrd = vd->real_dev;
 
index 6812330..49dd49e 100644 (file)
 #include <stdlib.h>
 #include <math.h>
 
+#include "ofp-util.h"
+#include "ofp-actions.h"
+#include "ofpbuf.h"
+#include "ofproto/ofproto-provider.h"
+#include "ofproto/ofproto-dpif.h"
 #include "connectivity.h"
 #include "coverage.h"
 #include "dynamic-string.h"
@@ -36,6 +41,7 @@
 #include "packets.h"
 #include "poll-loop.h"
 #include "seq.h"
+#include "match.h"
 #include "shash.h"
 #include "timeval.h"
 #include "unixctl.h"
@@ -50,6 +56,7 @@ static struct hmap *const all_bonds OVS_GUARDED_BY(rwlock) = &all_bonds__;
 /* Bit-mask for hashing a flow down to a bucket.
  * There are (BOND_MASK + 1) buckets. */
 #define BOND_MASK 0xff
+#define RECIRC_RULE_PRIORITY 20   /* Priority level for internal rules */
 
 /* A hash bucket for mapping a flow to a slave.
  * "struct bond" has an array of (BOND_MASK + 1) of these. */
@@ -57,6 +64,12 @@ struct bond_entry {
     struct bond_slave *slave;   /* Assigned slave, NULL if unassigned. */
     uint64_t tx_bytes;          /* Count of bytes recently transmitted. */
     struct list list_node;      /* In bond_slave's 'entries' list. */
+
+    /* Recirculation. */
+    struct rule *pr_rule;       /* Post recirculation rule for this entry.*/
+    uint64_t pr_tx_bytes;       /* Record the rule tx_bytes to figure out
+                                   the delta to update the tx_bytes entry
+                                   above.*/
 };
 
 /* A bond slave, that is, one of the links comprising a bond. */
@@ -68,6 +81,7 @@ struct bond_slave {
 
     struct netdev *netdev;      /* Network device, owned by the client. */
     unsigned int change_seq;    /* Tracks changes in 'netdev'. */
+    ofp_port_t  ofp_port;       /* Open flow port number */
     char *name;                 /* Name (a copy of netdev_get_name(netdev)). */
 
     /* Link status. */
@@ -86,6 +100,7 @@ struct bond_slave {
 struct bond {
     struct hmap_node hmap_node; /* In 'all_bonds' hmap. */
     char *name;                 /* Name provided by client. */
+    struct ofproto_dpif *ofproto; /* The bridge this bond belongs to. */
 
     /* Slaves. */
     struct hmap slaves;
@@ -111,6 +126,8 @@ struct bond {
     int rebalance_interval;      /* Interval between rebalances, in ms. */
     long long int next_rebalance; /* Next rebalancing time. */
     bool send_learning_packets;
+    uint32_t recirc_id;          /* Non zero if recirculation can be used.*/
+    struct hmap pr_rule_ops;     /* Helps to maintain post recirculation rules.*/
 
     /* Legacy compatibility. */
     long long int next_fake_iface_update; /* LLONG_MAX if disabled. */
@@ -119,6 +136,21 @@ struct bond {
     struct ovs_refcount ref_cnt;
 };
 
+/* What to do with an bond_recirc_rule. */
+enum bond_op {
+    ADD,        /* Add the rule to ofproto's flow table. */
+    DEL,        /* Delete the rule from the ofproto's flow table. */
+};
+
+/* A rule to add to or delete from ofproto's internal flow table. */
+struct bond_pr_rule_op {
+    struct hmap_node hmap_node;
+    struct match match;
+    ofp_port_t out_ofport;
+    enum bond_op op;
+    struct rule *pr_rule;
+};
+
 static void bond_entry_reset(struct bond *) OVS_REQ_WRLOCK(rwlock);
 static struct bond_slave *bond_slave_lookup(struct bond *, const void *slave_)
     OVS_REQ_RDLOCK(rwlock);
@@ -185,17 +217,21 @@ bond_mode_to_string(enum bond_mode balance) {
  * The caller should register each slave on the new bond by calling
  * bond_slave_register().  */
 struct bond *
-bond_create(const struct bond_settings *s)
+bond_create(const struct bond_settings *s, struct ofproto_dpif *ofproto)
 {
     struct bond *bond;
 
     bond = xzalloc(sizeof *bond);
+    bond->ofproto = ofproto;
     hmap_init(&bond->slaves);
     list_init(&bond->enabled_slaves);
     ovs_mutex_init(&bond->mutex);
     bond->next_fake_iface_update = LLONG_MAX;
     ovs_refcount_init(&bond->ref_cnt);
 
+    bond->recirc_id = 0;
+    hmap_init(&bond->pr_rule_ops);
+
     bond_reconfigure(bond, s);
     return bond;
 }
@@ -216,6 +252,7 @@ void
 bond_unref(struct bond *bond)
 {
     struct bond_slave *slave, *next_slave;
+    struct bond_pr_rule_op *pr_op, *next_op;
 
     if (!bond || ovs_refcount_unref(&bond->ref_cnt) != 1) {
         return;
@@ -236,9 +273,124 @@ bond_unref(struct bond *bond)
     ovs_mutex_destroy(&bond->mutex);
     free(bond->hash);
     free(bond->name);
+
+    HMAP_FOR_EACH_SAFE(pr_op, next_op, hmap_node, &bond->pr_rule_ops) {
+        hmap_remove(&bond->pr_rule_ops, &pr_op->hmap_node);
+        free(pr_op);
+    }
+    hmap_destroy(&bond->pr_rule_ops);
+
+    if (bond->recirc_id) {
+        ofproto_dpif_free_recirc_id(bond->ofproto, bond->recirc_id);
+    }
+
     free(bond);
 }
 
+static void
+add_pr_rule(struct bond *bond, const struct match *match,
+            ofp_port_t out_ofport, struct rule *rule)
+{
+    uint32_t hash = match_hash(match, 0);
+    struct bond_pr_rule_op *pr_op;
+
+    HMAP_FOR_EACH_WITH_HASH(pr_op, hmap_node, hash, &bond->pr_rule_ops) {
+        if (match_equal(&pr_op->match, match)) {
+            pr_op->op = ADD;
+            pr_op->out_ofport = out_ofport;
+            pr_op->pr_rule = rule;
+            return;
+        }
+    }
+
+    pr_op = xmalloc(sizeof *pr_op);
+    pr_op->match = *match;
+    pr_op->op = ADD;
+    pr_op->out_ofport = out_ofport;
+    pr_op->pr_rule = rule;
+    hmap_insert(&bond->pr_rule_ops, &pr_op->hmap_node, hash);
+}
+
+static void
+update_recirc_rules(struct bond *bond)
+{
+    struct match match;
+    struct bond_pr_rule_op *pr_op, *next_op;
+    uint64_t ofpacts_stub[128 / 8];
+    struct ofpbuf ofpacts;
+    int i;
+
+    ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
+
+    HMAP_FOR_EACH(pr_op, hmap_node, &bond->pr_rule_ops) {
+        pr_op->op = DEL;
+    }
+
+    if ((bond->hash == NULL) || (!bond->recirc_id)) {
+        return;
+    }
+
+    for (i = 0; i < BOND_MASK + 1; i++) {
+        struct bond_slave *slave = bond->hash[i].slave;
+
+        if (slave) {
+            match_init_catchall(&match);
+            match_set_recirc_id(&match, bond->recirc_id);
+            /* recirc_id -> metadata to speed up look ups. */
+            match_set_metadata(&match, htonll(bond->recirc_id));
+            match_set_dp_hash_masked(&match, i, BOND_MASK);
+
+            add_pr_rule(bond, &match, slave->ofp_port,
+                            bond->hash[i].pr_rule);
+        }
+    }
+
+    HMAP_FOR_EACH_SAFE(pr_op, next_op, hmap_node, &bond->pr_rule_ops) {
+        int error;
+        struct rule *rule;
+        switch (pr_op->op) {
+        case ADD:
+            ofpbuf_clear(&ofpacts);
+            ofpact_put_OUTPUT(&ofpacts)->port = pr_op->out_ofport;
+            error = ofproto_dpif_add_internal_flow(bond->ofproto,
+                                                   &pr_op->match,
+                                                   RECIRC_RULE_PRIORITY,
+                                                   &ofpacts, &rule);
+            if (error) {
+                char *err_s = match_to_string(&pr_op->match,
+                                              RECIRC_RULE_PRIORITY);
+
+                VLOG_ERR("failed to add post recirculation flow %s", err_s);
+                free(err_s);
+                pr_op->pr_rule = NULL;
+            } else {
+                pr_op->pr_rule = rule;
+            }
+            break;
+
+        case DEL:
+            error = ofproto_dpif_delete_internal_flow(bond->ofproto,
+                                                      &pr_op->match,
+                                                      RECIRC_RULE_PRIORITY);
+            if (error) {
+                char *err_s = match_to_string(&pr_op->match,
+                                              RECIRC_RULE_PRIORITY);
+
+                VLOG_ERR("failed to remove post recirculation flow %s", err_s);
+                free(err_s);
+            }
+
+            hmap_remove(&bond->pr_rule_ops, &pr_op->hmap_node);
+            pr_op->pr_rule = NULL;
+            free(pr_op);
+            break;
+        }
+    }
+
+    ofpbuf_uninit(&ofpacts);
+}
+
+
 /* Updates 'bond''s overall configuration to 's'.
  *
  * The caller should register each slave on 'bond' by calling
@@ -299,6 +451,15 @@ bond_reconfigure(struct bond *bond, const struct bond_settings *s)
         bond->bond_revalidate = false;
     }
 
+    if (bond->balance != BM_AB) {
+        if (!bond->recirc_id) {
+            bond->recirc_id = ofproto_dpif_alloc_recirc_id(bond->ofproto);
+        }
+    } else if (bond->recirc_id) {
+        ofproto_dpif_free_recirc_id(bond->ofproto, bond->recirc_id);
+        bond->recirc_id = 0;
+    }
+
     if (bond->balance == BM_AB || !bond->hash || revalidate) {
         bond_entry_reset(bond);
     }
@@ -327,7 +488,8 @@ bond_slave_set_netdev__(struct bond_slave *slave, struct netdev *netdev)
  * 'slave_' or destroying 'bond'.
  */
 void
-bond_slave_register(struct bond *bond, void *slave_, struct netdev *netdev)
+bond_slave_register(struct bond *bond, void *slave_,
+                    ofp_port_t ofport, struct netdev *netdev)
 {
     struct bond_slave *slave;
 
@@ -339,6 +501,7 @@ bond_slave_register(struct bond *bond, void *slave_, struct netdev *netdev)
         hmap_insert(&bond->slaves, &slave->hmap_node, hash_pointer(slave_, 0));
         slave->bond = bond;
         slave->aux = slave_;
+        slave->ofp_port = ofport;
         slave->delay_expires = LLONG_MAX;
         slave->name = xstrdup(netdev_get_name(netdev));
         bond->bond_revalidate = true;
@@ -688,6 +851,84 @@ bond_choose_output_slave(struct bond *bond, const struct flow *flow,
     return aux;
 }
 \f
+/* Recirculation. */
+static void
+bond_entry_account(struct bond_entry *entry, uint64_t rule_tx_bytes)
+    OVS_REQ_RDLOCK(rwlock)
+{
+    if (entry->slave) {
+        uint64_t delta;
+
+        delta = rule_tx_bytes - entry->pr_tx_bytes;
+        entry->tx_bytes += delta;
+        entry->pr_tx_bytes = rule_tx_bytes;
+    }
+}
+
+/* Maintain bond stats using post recirculation rule byte counters.*/
+void
+bond_recirculation_account(struct bond *bond)
+{
+    int i;
+
+    ovs_rwlock_rdlock(&rwlock);
+    for (i=0; i<=BOND_MASK; i++) {
+        struct bond_entry *entry = &bond->hash[i];
+        struct rule *rule = entry->pr_rule;
+
+        if (rule) {
+            uint64_t n_packets OVS_UNUSED;
+            long long int used OVS_UNUSED;
+            uint64_t n_bytes;
+
+            rule->ofproto->ofproto_class->rule_get_stats(
+                rule, &n_packets, &n_bytes, &used);
+            bond_entry_account(entry, n_bytes);
+        }
+    }
+    ovs_rwlock_unlock(&rwlock);
+}
+
+bool
+bond_may_recirc(const struct bond *bond, uint32_t *recirc_id,
+                uint32_t *hash_bias)
+{
+    if (bond->balance == BM_TCP) {
+        if (recirc_id) {
+            *recirc_id = bond->recirc_id;
+        }
+        if (hash_bias) {
+            *hash_bias = bond->basis;
+        }
+        return true;
+    } else {
+        return false;
+    }
+}
+
+void
+bond_update_post_recirc_rules(struct bond* bond, const bool force)
+{
+   struct bond_entry *e;
+   bool update_rules = force;  /* Always update rules if caller forces it. */
+
+   /* Make sure all bond entries are populated */
+   for (e = bond->hash; e <= &bond->hash[BOND_MASK]; e++) {
+       if (!e->slave || !e->slave->enabled) {
+            update_rules = true;
+            e->slave = CONTAINER_OF(hmap_random_node(&bond->slaves),
+                                    struct bond_slave, hmap_node);
+            if (!e->slave->enabled) {
+                e->slave = bond->active_slave;
+            }
+        }
+   }
+
+   if (update_rules) {
+        update_recirc_rules(bond);
+   }
+}
+\f
 /* Rebalancing. */
 
 static bool
@@ -845,19 +1086,22 @@ reinsert_bal(struct list *bals, struct bond_slave *slave)
 
 /* If 'bond' needs rebalancing, does so.
  *
- * The caller should have called bond_account() for each active flow, to ensure
- * that flow data is consistently accounted at this point. */
-void
+ * The caller should have called bond_account() for each active flow, or in case
+ * of recirculation is used, have called bond_recirculation_account(bond),
+ * to ensure that flow data is consistently accounted at this point.
+ *
+ * Return whether rebalancing took place.*/
+bool
 bond_rebalance(struct bond *bond)
 {
     struct bond_slave *slave;
     struct bond_entry *e;
     struct list bals;
+    bool rebalanced = false;
 
     ovs_rwlock_wrlock(&rwlock);
     if (!bond_is_balanced(bond) || time_msec() < bond->next_rebalance) {
-        ovs_rwlock_unlock(&rwlock);
-        return;
+        goto done;
     }
     bond->next_rebalance = time_msec() + bond->rebalance_interval;
 
@@ -916,6 +1160,7 @@ bond_rebalance(struct bond *bond)
             /* Re-sort 'bals'. */
             reinsert_bal(&bals, from);
             reinsert_bal(&bals, to);
+           rebalanced = true;
         } else {
             /* Can't usefully migrate anything away from 'from'.
              * Don't reconsider it. */
@@ -932,7 +1177,10 @@ bond_rebalance(struct bond *bond)
             e->slave = NULL;
         }
     }
+
+done:
     ovs_rwlock_unlock(&rwlock);
+    return rebalanced;
 }
 \f
 /* Bonding unixctl user interface functions. */
@@ -972,15 +1220,15 @@ bond_unixctl_list(struct unixctl_conn *conn,
     struct ds ds = DS_EMPTY_INITIALIZER;
     const struct bond *bond;
 
-    ds_put_cstr(&ds, "bond\ttype\tslaves\n");
+    ds_put_cstr(&ds, "bond\ttype\trecircID\tslaves\n");
 
     ovs_rwlock_rdlock(&rwlock);
     HMAP_FOR_EACH (bond, hmap_node, all_bonds) {
         const struct bond_slave *slave;
         size_t i;
 
-        ds_put_format(&ds, "%s\t%s\t",
-                      bond->name, bond_mode_to_string(bond->balance));
+        ds_put_format(&ds, "%s\t%s\t%d\t", bond->name,
+                      bond_mode_to_string(bond->balance), bond->recirc_id);
 
         i = 0;
         HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
@@ -1003,12 +1251,18 @@ bond_print_details(struct ds *ds, const struct bond *bond)
     struct shash slave_shash = SHASH_INITIALIZER(&slave_shash);
     const struct shash_node **sorted_slaves = NULL;
     const struct bond_slave *slave;
+    bool may_recirc;
+    uint32_t recirc_id;
     int i;
 
     ds_put_format(ds, "---- %s ----\n", bond->name);
     ds_put_format(ds, "bond_mode: %s\n",
                   bond_mode_to_string(bond->balance));
 
+    may_recirc = bond_may_recirc(bond, &recirc_id, NULL);
+    ds_put_format(ds, "bond may use recirculation: %s, Recirc-ID : %d\n",
+                  may_recirc ? "yes" : "no", may_recirc ? recirc_id: -1);
+
     ds_put_format(ds, "bond-hash-basis: %"PRIu32"\n", bond->basis);
 
     ds_put_format(ds, "updelay: %d ms\n", bond->updelay);
index 5b3814e..e5ceb45 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 #include <stdbool.h>
 #include <stdint.h>
-
+#include "ofproto-provider.h"
 #include "packets.h"
 
 struct flow;
 struct netdev;
 struct ofpbuf;
+struct ofproto_dpif;
 enum lacp_status;
 
 /* How flows are balanced among bond slaves. */
@@ -60,12 +61,13 @@ struct bond_settings {
 void bond_init(void);
 
 /* Basics. */
-struct bond *bond_create(const struct bond_settings *);
+struct bond *bond_create(const struct bond_settings *,
+                         struct ofproto_dpif *ofproto);
 void bond_unref(struct bond *);
 struct bond *bond_ref(const struct bond *);
 
 bool bond_reconfigure(struct bond *, const struct bond_settings *);
-void bond_slave_register(struct bond *, void *slave_, struct netdev *);
+void bond_slave_register(struct bond *, void *slave_, ofp_port_t ofport, struct netdev *);
 void bond_slave_set_netdev(struct bond *, void *slave_, struct netdev *);
 void bond_slave_unregister(struct bond *, const void *slave);
 
@@ -94,6 +96,27 @@ void *bond_choose_output_slave(struct bond *, const struct flow *,
 /* Rebalancing. */
 void bond_account(struct bond *, const struct flow *, uint16_t vlan,
                   uint64_t n_bytes);
-void bond_rebalance(struct bond *);
+bool bond_rebalance(struct bond *);
 
+/* Recirculation
+ *
+ * Only balance_tcp mode uses recirculation.
+ *
+ * When recirculation is used, each bond port is assigned with a unique
+ * recirc_id. The output action to the bond port will be replaced by
+ * a RECIRC action.
+ *
+ *   ... actions= ... RECIRC(L4_HASH, recirc_id) ....
+ *
+ * On handling first output packet, 256 post recirculation flows are installed:
+ *
+ *  recirc_id=<bond_recirc_id>, dp_hash=<[0..255]>/0xff, actions: output<slave>
+ *
+ * Bond module pulls stats from those post recirculation rules. If rebalancing
+ * is needed, those rules are updated with new output actions.
+*/
+void bond_update_post_recirc_rules(struct bond *, const bool force);
+bool bond_may_recirc(const struct bond *, uint32_t *recirc_id,
+                     uint32_t *hash_bias);
+void bond_recirculation_account(struct bond *);
 #endif /* bond.h */
index 9bc1897..383fbda 100644 (file)
@@ -1410,6 +1410,65 @@ ofconn_receives_async_msg(const struct ofconn *ofconn,
     return true;
 }
 
+/* The default "table-miss" behaviour for OpenFlow1.3+ is to drop the
+ * packet rather than to send the packet to the controller.
+ *
+ * This function returns false to indicate the packet should be dropped if
+ * the controller action was the result of the default table-miss behaviour
+ * and the controller is using OpenFlow1.3+.
+ *
+ * Otherwise true is returned to indicate the packet should be forwarded to
+ * the controller */
+static bool
+ofconn_wants_packet_in_on_miss(struct ofconn *ofconn,
+                               const struct ofproto_packet_in *pin)
+{
+    if (pin->miss_type == OFPROTO_PACKET_IN_MISS_WITHOUT_FLOW) {
+        enum ofputil_protocol protocol = ofconn_get_protocol(ofconn);
+
+        if (protocol != OFPUTIL_P_NONE
+            && ofputil_protocol_to_ofp_version(protocol) >= OFP13_VERSION) {
+            enum ofproto_table_config config;
+
+            config = ofproto_table_get_config(ofconn->connmgr->ofproto,
+                                              pin->up.table_id);
+            if (config == OFPROTO_TABLE_MISS_DEFAULT) {
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+/* The default "table-miss" behaviour for OpenFlow1.3+ is to drop the
+ * packet rather than to send the packet to the controller.
+ *
+ * This function returns false to indicate that a packet_in message
+ * for a "table-miss" should be sent to at least one controller.
+ * That is there is at least one controller with controller_id 0
+ * which connected using an OpenFlow version earlier than OpenFlow1.3.
+ *
+ * False otherwise.
+ *
+ * This logic assumes that "table-miss" packet_in messages
+ * are always sent to controller_id 0. */
+bool
+connmgr_wants_packet_in_on_miss(struct connmgr *mgr)
+{
+    struct ofconn *ofconn;
+
+    LIST_FOR_EACH (ofconn, node, &mgr->all_conns) {
+        enum ofputil_protocol protocol = ofconn_get_protocol(ofconn);
+
+        if (ofconn->controller_id == 0 &&
+            (protocol == OFPUTIL_P_NONE ||
+             ofputil_protocol_to_ofp_version(protocol) < OFP13_VERSION)) {
+            return true;
+        }
+    }
+    return false;
+}
+
 /* Returns a human-readable name for an OpenFlow connection between 'mgr' and
  * 'target', suitable for use in log messages for identifying the connection.
  *
@@ -1559,7 +1618,8 @@ connmgr_send_packet_in(struct connmgr *mgr,
     LIST_FOR_EACH (ofconn, node, &mgr->all_conns) {
         enum ofp_packet_in_reason reason = wire_reason(ofconn, pin);
 
-        if (ofconn_receives_async_msg(ofconn, OAM_PACKET_IN, reason)
+        if (ofconn_wants_packet_in_on_miss(ofconn, pin)
+            && ofconn_receives_async_msg(ofconn, OAM_PACKET_IN, pin->up.reason)
             && ofconn->controller_id == pin->controller_id) {
             schedule_packet_in(ofconn, *pin, reason);
         }
@@ -1823,7 +1883,8 @@ connmgr_flushed(struct connmgr *mgr)
         ofpact_pad(&ofpacts);
 
         match_init_catchall(&match);
-        ofproto_add_flow(mgr->ofproto, &match, 0, ofpacts.data, ofpacts.size);
+        ofproto_add_flow(mgr->ofproto, &match, 0, ofpbuf_data(&ofpacts),
+                                                  ofpbuf_size(&ofpacts));
 
         ofpbuf_uninit(&ofpacts);
     }
index c4cfd83..20c8160 100644 (file)
@@ -162,6 +162,7 @@ void ofconn_remove_opgroup(struct ofconn *, struct list *,
                            const struct ofp_header *request, int error);
 
 /* Sending asynchronous messages. */
+bool connmgr_wants_packet_in_on_miss(struct connmgr *mgr);
 void connmgr_send_port_status(struct connmgr *, struct ofconn *source,
                               const struct ofputil_phy_port *, uint8_t reason);
 void connmgr_send_flow_removed(struct connmgr *,
index 467cafa..b29e5af 100644 (file)
@@ -125,11 +125,11 @@ send_bogus_packet_ins(struct fail_open *fo)
     compose_rarp(&b, mac);
 
     memset(&pin, 0, sizeof pin);
-    pin.up.packet = b.data;
-    pin.up.packet_len = b.size;
+    pin.up.packet = ofpbuf_data(&b);
+    pin.up.packet_len = ofpbuf_size(&b);
     pin.up.reason = OFPR_NO_MATCH;
     pin.up.fmd.in_port = OFPP_LOCAL;
-    pin.send_len = b.size;
+    pin.send_len = ofpbuf_size(&b);
     pin.miss_type = OFPROTO_PACKET_IN_NO_MISS;
     connmgr_send_packet_in(fo->connmgr, &pin);
 
@@ -230,7 +230,7 @@ fail_open_flushed(struct fail_open *fo)
 
         match_init_catchall(&match);
         ofproto_add_flow(fo->ofproto, &match, FAIL_OPEN_PRIORITY,
-                         ofpacts.data, ofpacts.size);
+                         ofpbuf_data(&ofpacts), ofpbuf_size(&ofpacts));
 
         ofpbuf_uninit(&ofpacts);
     }
index 416043e..42b3efb 100644 (file)
@@ -382,7 +382,7 @@ in_band_run(struct in_band *ib)
         switch (rule->op) {
         case ADD:
             ofproto_add_flow(ib->ofproto, &rule->match, rule->priority,
-                             ofpacts.data, ofpacts.size);
+                             ofpbuf_data(&ofpacts), ofpbuf_size(&ofpacts));
             break;
 
         case DEL:
index a093749..7729906 100644 (file)
@@ -110,7 +110,7 @@ gen_netflow_rec(struct netflow *nf, struct netflow_flow *nf_flow,
     struct netflow_v5_header *nf_hdr;
     struct netflow_v5_record *nf_rec;
 
-    if (!nf->packet.size) {
+    if (!ofpbuf_size(&nf->packet)) {
         struct timespec now;
 
         time_wall_timespec(&now);
@@ -127,7 +127,7 @@ gen_netflow_rec(struct netflow *nf, struct netflow_flow *nf_flow,
         nf_hdr->sampling_interval = htons(0);
     }
 
-    nf_hdr = nf->packet.data;
+    nf_hdr = ofpbuf_data(&nf->packet);
     nf_hdr->count = htons(ntohs(nf_hdr->count) + 1);
 
     nf_rec = ofpbuf_put_zeros(&nf->packet, sizeof *nf_rec);
@@ -313,9 +313,9 @@ netflow_run__(struct netflow *nf) OVS_REQUIRES(mutex)
     long long int now = time_msec();
     struct netflow_flow *nf_flow, *next;
 
-    if (nf->packet.size) {
-        collectors_send(nf->collectors, nf->packet.data, nf->packet.size);
-        nf->packet.size = 0;
+    if (ofpbuf_size(&nf->packet)) {
+        collectors_send(nf->collectors, ofpbuf_data(&nf->packet), ofpbuf_size(&nf->packet));
+        ofpbuf_set_size(&nf->packet, 0);
     }
 
     if (!nf->active_timeout || now < nf->next_timeout) {
@@ -354,7 +354,7 @@ netflow_wait(struct netflow *nf) OVS_EXCLUDED(mutex)
     if (nf->active_timeout) {
         poll_timer_wait_until(nf->next_timeout);
     }
-    if (nf->packet.size) {
+    if (ofpbuf_size(&nf->packet)) {
         poll_immediate_wake();
     }
     ovs_mutex_unlock(&mutex);
index c8fb3d7..08a3fca 100644 (file)
@@ -724,11 +724,11 @@ ipfix_send_msg(const struct collectors *collectors, struct ofpbuf *msg)
     struct ipfix_header *hdr;
 
     /* Adjust the length in the header. */
-    hdr = msg->data;
-    hdr->length = htons(msg->size);
+    hdr = ofpbuf_data(msg);
+    hdr->length = htons(ofpbuf_size(msg));
 
-    collectors_send(collectors, msg->data, msg->size);
-    msg->size = 0;
+    collectors_send(collectors, ofpbuf_data(msg), ofpbuf_size(msg));
+    ofpbuf_set_size(msg, 0);
 }
 
 static uint16_t
@@ -852,7 +852,7 @@ ipfix_send_template_msg(struct dpif_ipfix_exporter *exporter,
 
     ipfix_init_header(export_time_sec, exporter->seq_number, obs_domain_id,
                       &msg);
-    set_hdr_offset = msg.size;
+    set_hdr_offset = ofpbuf_size(&msg);
 
     /* Add a Template Set. */
     set_hdr = ofpbuf_put_zeros(&msg, sizeof *set_hdr);
@@ -867,20 +867,20 @@ ipfix_send_template_msg(struct dpif_ipfix_exporter *exporter,
                     l4 != IPFIX_PROTO_L4_UNKNOWN) {
                     continue;
                 }
-                tmpl_hdr_offset = msg.size;
+                tmpl_hdr_offset = ofpbuf_size(&msg);
                 tmpl_hdr = ofpbuf_put_zeros(&msg, sizeof *tmpl_hdr);
                 tmpl_hdr->template_id = htons(
                     ipfix_get_template_id(l2, l3, l4));
                 field_count = ipfix_define_template_fields(l2, l3, l4, &msg);
                 tmpl_hdr = (struct ipfix_template_record_header*)
-                    ((uint8_t*)msg.data + tmpl_hdr_offset);
+                    ((uint8_t*)ofpbuf_data(&msg) + tmpl_hdr_offset);
                 tmpl_hdr->field_count = htons(field_count);
             }
         }
     }
 
-    set_hdr = (struct ipfix_set_header*)((uint8_t*)msg.data + set_hdr_offset);
-    set_hdr->length = htons(msg.size - set_hdr_offset);
+    set_hdr = (struct ipfix_set_header*)((uint8_t*)ofpbuf_data(&msg) + set_hdr_offset);
+    set_hdr->length = htons(ofpbuf_size(&msg) - set_hdr_offset);
 
     /* XXX: Add Options Template Sets, at least to define a Flow Keys
      * Option Template. */
@@ -1084,7 +1084,7 @@ ipfix_cache_entry_init(struct ipfix_flow_cache_entry *entry,
 
     ethernet_header_length = (l2 == IPFIX_PROTO_L2_VLAN)
         ? VLAN_ETH_HEADER_LEN : ETH_HEADER_LEN;
-    ethernet_total_length = packet->size;
+    ethernet_total_length = ofpbuf_size(packet);
 
     /* Common Ethernet entities. */
     {
@@ -1154,7 +1154,7 @@ ipfix_cache_entry_init(struct ipfix_flow_cache_entry *entry,
         data_icmp->icmp_code = ntohs(flow->tp_dst) & 0xff;
     }
 
-    flow_key->flow_key_msg_part_size = msg.size;
+    flow_key->flow_key_msg_part_size = ofpbuf_size(&msg);
 
     {
         struct timeval now;
@@ -1205,7 +1205,7 @@ ipfix_put_data_set(uint32_t export_time_sec,
     size_t set_hdr_offset;
     struct ipfix_set_header *set_hdr;
 
-    set_hdr_offset = msg->size;
+    set_hdr_offset = ofpbuf_size(msg);
 
     /* Put a Data Set. */
     set_hdr = ofpbuf_put_zeros(msg, sizeof *set_hdr);
@@ -1259,8 +1259,8 @@ ipfix_put_data_set(uint32_t export_time_sec,
             entry->maximum_ip_total_length);
     }
 
-    set_hdr = (struct ipfix_set_header*)((uint8_t*)msg->data + set_hdr_offset);
-    set_hdr->length = htons(msg->size - set_hdr_offset);
+    set_hdr = (struct ipfix_set_header*)((uint8_t*)ofpbuf_data(msg) + set_hdr_offset);
+    set_hdr->length = htons(ofpbuf_size(msg) - set_hdr_offset);
 }
 
 /* Send an IPFIX message with a single data record. */
index eeff13f..cb1f830 100644 (file)
@@ -602,12 +602,12 @@ dpif_sflow_received(struct dpif_sflow *ds, struct ofpbuf *packet,
     header->header_protocol = SFLHEADER_ETHERNET_ISO8023;
     /* The frame_length should include the Ethernet FCS (4 bytes),
      * but it has already been stripped,  so we need to add 4 here. */
-    header->frame_length = packet->size + 4;
+    header->frame_length = ofpbuf_size(packet) + 4;
     /* Ethernet FCS stripped off. */
     header->stripped = 4;
-    header->header_length = MIN(packet->size,
+    header->header_length = MIN(ofpbuf_size(packet),
                                 sampler->sFlowFsMaximumHeaderSize);
-    header->header_bytes = packet->data;
+    header->header_bytes = ofpbuf_data(packet);
 
     /* Add extended switch element. */
     memset(&switchElem, 0, sizeof(switchElem));
index 5b5fb6e..938cfde 100644 (file)
@@ -1043,7 +1043,7 @@ handle_upcalls(struct handler *handler, struct list *upcalls)
                 miss = existing_miss;
             }
             miss->stats.tcp_flags |= ntohs(miss->flow.tcp_flags);
-            miss->stats.n_bytes += packet->size;
+            miss->stats.n_bytes += ofpbuf_size(packet);
             miss->stats.n_packets++;
 
             upcall->flow_miss = miss;
@@ -1164,7 +1164,7 @@ handle_upcalls(struct handler *handler, struct list *upcalls)
              * the packet contained no VLAN.  So, we must remove the
              * VLAN header from the packet before trying to execute the
              * actions. */
-            if (miss->xout.odp_actions.size) {
+            if (ofpbuf_size(&miss->xout.odp_actions)) {
                 eth_pop_vlan(packet);
             }
 
@@ -1204,21 +1204,21 @@ handle_upcalls(struct handler *handler, struct list *upcalls)
             op->u.flow_put.flags = DPIF_FP_CREATE | DPIF_FP_MODIFY;
             op->u.flow_put.key = miss->key;
             op->u.flow_put.key_len = miss->key_len;
-            op->u.flow_put.mask = mask.data;
-            op->u.flow_put.mask_len = mask.size;
+            op->u.flow_put.mask = ofpbuf_data(&mask);
+            op->u.flow_put.mask_len = ofpbuf_size(&mask);
             op->u.flow_put.stats = NULL;
 
             if (!miss->xout.slow) {
-                op->u.flow_put.actions = miss->xout.odp_actions.data;
-                op->u.flow_put.actions_len = miss->xout.odp_actions.size;
+                op->u.flow_put.actions = ofpbuf_data(&miss->xout.odp_actions);
+                op->u.flow_put.actions_len = ofpbuf_size(&miss->xout.odp_actions);
             } else {
                 struct ofpbuf buf;
 
                 ofpbuf_use_stack(&buf, miss->slow_path_buf,
                                  sizeof miss->slow_path_buf);
                 compose_slow_path(udpif, &miss->xout, miss->odp_in_port, &buf);
-                op->u.flow_put.actions = buf.data;
-                op->u.flow_put.actions_len = buf.size;
+                op->u.flow_put.actions = ofpbuf_data(&buf);
+                op->u.flow_put.actions_len = ofpbuf_size(&buf);
             }
         }
 
@@ -1228,15 +1228,15 @@ handle_upcalls(struct handler *handler, struct list *upcalls)
          * upcall. */
         miss->flow.vlan_tci = flow_vlan_tci;
 
-        if (miss->xout.odp_actions.size) {
+        if (ofpbuf_size(&miss->xout.odp_actions)) {
 
             op = &ops[n_ops++];
             op->type = DPIF_OP_EXECUTE;
             op->u.execute.packet = packet;
             odp_key_to_pkt_metadata(miss->key, miss->key_len,
                                     &op->u.execute.md);
-            op->u.execute.actions = miss->xout.odp_actions.data;
-            op->u.execute.actions_len = miss->xout.odp_actions.size;
+            op->u.execute.actions = ofpbuf_data(&miss->xout.odp_actions);
+            op->u.execute.actions_len = ofpbuf_size(&miss->xout.odp_actions);
             op->u.execute.needs_help = (miss->xout.slow & SLOW_ACTION) != 0;
         }
     }
@@ -1257,8 +1257,8 @@ handle_upcalls(struct handler *handler, struct list *upcalls)
             struct ofproto_packet_in *pin;
 
             pin = xmalloc(sizeof *pin);
-            pin->up.packet = xmemdup(packet->data, packet->size);
-            pin->up.packet_len = packet->size;
+            pin->up.packet = xmemdup(ofpbuf_data(packet), ofpbuf_size(packet));
+            pin->up.packet_len = ofpbuf_size(packet);
             pin->up.reason = OFPR_NO_MATCH;
             pin->up.table_id = 0;
             pin->up.cookie = OVS_BE64_MAX;
@@ -1332,6 +1332,7 @@ revalidate_ukey(struct udpif *udpif, struct udpif_flow_dump *udump,
     struct ofpbuf xout_actions, *actions;
     uint64_t slow_path_buf[128 / 8];
     struct xlate_out xout, *xoutp;
+    struct netflow *netflow;
     struct flow flow, udump_mask;
     struct ofproto_dpif *ofproto;
     struct dpif_flow_stats push;
@@ -1345,6 +1346,7 @@ revalidate_ukey(struct udpif *udpif, struct udpif_flow_dump *udump,
     ok = false;
     xoutp = NULL;
     actions = NULL;
+    netflow = NULL;
 
     /* If we don't need to revalidate, we can simply push the stats contained
      * in the udump, otherwise we'll have to get the actions so we can check
@@ -1372,7 +1374,7 @@ revalidate_ukey(struct udpif *udpif, struct udpif_flow_dump *udump,
     }
 
     error = xlate_receive(udpif->backer, NULL, ukey->key, ukey->key_len, &flow,
-                          &ofproto, NULL, NULL, NULL, &odp_in_port);
+                          &ofproto, NULL, NULL, &netflow, &odp_in_port);
     if (error) {
         goto exit;
     }
@@ -1390,8 +1392,8 @@ revalidate_ukey(struct udpif *udpif, struct udpif_flow_dump *udump,
     }
 
     if (!xout.slow) {
-        ofpbuf_use_const(&xout_actions, xout.odp_actions.data,
-                         xout.odp_actions.size);
+        ofpbuf_use_const(&xout_actions, ofpbuf_data(&xout.odp_actions),
+                         ofpbuf_size(&xout.odp_actions));
     } else {
         ofpbuf_use_stack(&xout_actions, slow_path_buf, sizeof slow_path_buf);
         compose_slow_path(udpif, &xout, odp_in_port, &xout_actions);
@@ -1421,6 +1423,13 @@ revalidate_ukey(struct udpif *udpif, struct udpif_flow_dump *udump,
     ok = true;
 
 exit:
+    if (netflow) {
+        if (!ok) {
+            netflow_expire(netflow, &flow);
+            netflow_flow_clear(netflow, &flow);
+        }
+        netflow_unref(netflow);
+    }
     ofpbuf_delete(actions);
     xlate_out_uninit(xoutp);
     return ok;
index e26b7c9..91ce7b7 100644 (file)
@@ -58,6 +58,8 @@ VLOG_DEFINE_THIS_MODULE(ofproto_dpif_xlate);
 /* Maximum depth of flow table recursion (due to resubmit actions) in a
  * flow translation. */
 #define MAX_RESUBMIT_RECURSION 64
+#define MAX_INTERNAL_RESUBMITS 1   /* Max resbmits allowed using rules in
+                                      internal table. */
 
 /* Maximum number of resubmit actions in a flow translation, whether they are
  * recursive or not. */
@@ -89,6 +91,9 @@ struct xbridge {
     bool has_in_band;             /* Bridge has in band control? */
     bool forward_bpdu;            /* Bridge forwards STP BPDUs? */
 
+    /* True if the datapath supports recirculation. */
+    bool enable_recirc;
+
     /* True if the datapath supports variable-length
      * OVS_USERSPACE_ATTR_USERDATA in OVS_ACTION_ATTR_USERSPACE actions.
      * False if the datapath supports only 8-byte (or shorter) userdata. */
@@ -226,8 +231,8 @@ static void do_xlate_actions(const struct ofpact *, size_t ofpacts_len,
                              struct xlate_ctx *);
 static void xlate_actions__(struct xlate_in *, struct xlate_out *)
     OVS_REQ_RDLOCK(xlate_rwlock);
-    static void xlate_normal(struct xlate_ctx *);
-    static void xlate_report(struct xlate_ctx *, const char *);
+static void xlate_normal(struct xlate_ctx *);
+static void xlate_report(struct xlate_ctx *, const char *);
 static void xlate_table_action(struct xlate_ctx *, ofp_port_t in_port,
                                uint8_t table_id, bool may_packet_in,
                                bool honor_table_miss);
@@ -257,6 +262,7 @@ xlate_ofproto_set(struct ofproto_dpif *ofproto, const char *name,
                   const struct dpif_ipfix *ipfix,
                   const struct netflow *netflow, enum ofp_config_flags frag,
                   bool forward_bpdu, bool has_in_band,
+                  bool enable_recirc,
                   bool variable_length_userdata,
                   size_t max_mpls_depth)
 {
@@ -310,6 +316,7 @@ xlate_ofproto_set(struct ofproto_dpif *ofproto, const char *name,
     xbridge->frag = frag;
     xbridge->miss_rule = miss_rule;
     xbridge->no_packet_in_rule = no_packet_in_rule;
+    xbridge->enable_recirc = enable_recirc;
     xbridge->variable_length_userdata = variable_length_userdata;
     xbridge->max_mpls_depth = max_mpls_depth;
 }
@@ -703,7 +710,7 @@ stp_process_packet(const struct xport *xport, const struct ofpbuf *packet)
 {
     struct stp_port *sp = xport_get_stp_port(xport);
     struct ofpbuf payload = *packet;
-    struct eth_header *eth = payload.data;
+    struct eth_header *eth = ofpbuf_data(&payload);
 
     /* Sink packets on ports that have STP disabled when the bridge has
      * STP enabled. */
@@ -712,12 +719,12 @@ stp_process_packet(const struct xport *xport, const struct ofpbuf *packet)
     }
 
     /* Trim off padding on payload. */
-    if (payload.size > ntohs(eth->eth_type) + ETH_HEADER_LEN) {
-        payload.size = ntohs(eth->eth_type) + ETH_HEADER_LEN;
+    if (ofpbuf_size(&payload) > ntohs(eth->eth_type) + ETH_HEADER_LEN) {
+        ofpbuf_set_size(&payload, ntohs(eth->eth_type) + ETH_HEADER_LEN);
     }
 
     if (ofpbuf_try_pull(&payload, ETH_HEADER_LEN + LLC_HEADER_LEN)) {
-        stp_received_bpdu(sp, payload.data, payload.size);
+        stp_received_bpdu(sp, ofpbuf_data(&payload), ofpbuf_size(&payload));
     }
 }
 
@@ -1131,13 +1138,30 @@ output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle,
         /* Partially configured bundle with no slaves.  Drop the packet. */
         return;
     } else if (!out_xbundle->bond) {
+        ctx->xout->use_recirc = false;
         xport = CONTAINER_OF(list_front(&out_xbundle->xports), struct xport,
                              bundle_node);
     } else {
         struct ofport_dpif *ofport;
+        struct xlate_recirc *xr = &ctx->xout->recirc;
+        struct flow_wildcards *wc = &ctx->xout->wc;
+
+        if (ctx->xbridge->enable_recirc) {
+            ctx->xout->use_recirc = bond_may_recirc(
+                out_xbundle->bond, &xr->recirc_id, &xr->hash_bias);
+
+            if (ctx->xout->use_recirc) {
+                /* Only TCP mode uses recirculation. */
+                xr->hash_alg = OVS_RECIRC_HASH_ALG_L4;
+                bond_update_post_recirc_rules(out_xbundle->bond, false);
+
+                /* Recirculation does not require unmasking hash fields. */
+                wc = NULL;
+            }
+        }
 
-        ofport = bond_choose_output_slave(out_xbundle->bond, &ctx->xin->flow,
-                                          &ctx->xout->wc, vid);
+        ofport = bond_choose_output_slave(out_xbundle->bond,
+                                          &ctx->xin->flow, wc, vid);
         xport = xport_lookup(ofport);
 
         if (!xport) {
@@ -1742,12 +1766,12 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
                 /* Forwarding is disabled by STP.  Let OFPP_NORMAL and the
                  * learning action look at the packet, then drop it. */
                 struct flow old_base_flow = ctx->base_flow;
-                size_t old_size = ctx->xout->odp_actions.size;
+                size_t old_size = ofpbuf_size(&ctx->xout->odp_actions);
                 mirror_mask_t old_mirrors = ctx->xout->mirrors;
                 xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, true);
                 ctx->xout->mirrors = old_mirrors;
                 ctx->base_flow = old_base_flow;
-                ctx->xout->odp_actions.size = old_size;
+                ofpbuf_set_size(&ctx->xout->odp_actions, old_size);
             }
         }
 
@@ -1770,7 +1794,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
     flow_nw_tos = flow->nw_tos;
 
     if (dscp_from_skb_priority(xport, flow->skb_priority, &dscp)) {
-        wc->masks.nw_tos |= IP_ECN_MASK;
+        wc->masks.nw_tos |= IP_DSCP_MASK;
         flow->nw_tos &= ~IP_DSCP_MASK;
         flow->nw_tos |= dscp;
     }
@@ -1817,8 +1841,20 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
         ctx->xout->slow |= commit_odp_actions(flow, &ctx->base_flow,
                                               &ctx->xout->odp_actions,
                                               &ctx->xout->wc);
-        nl_msg_put_odp_port(&ctx->xout->odp_actions, OVS_ACTION_ATTR_OUTPUT,
-                            out_port);
+
+        if (ctx->xout->use_recirc) {
+            struct ovs_action_recirc *act_recirc;
+            struct xlate_recirc *xr = &ctx->xout->recirc;
+
+            act_recirc = nl_msg_put_unspec_uninit(&ctx->xout->odp_actions,
+                               OVS_ACTION_ATTR_RECIRC, sizeof *act_recirc);
+            act_recirc->recirc_id = xr->recirc_id;
+            act_recirc->hash_alg = xr->hash_alg;
+            act_recirc->hash_bias = xr->hash_bias;
+        } else {
+            nl_msg_put_odp_port(&ctx->xout->odp_actions, OVS_ACTION_ATTR_OUTPUT,
+                                out_port);
+        }
 
         ctx->sflow_odp_port = odp_port;
         ctx->sflow_n_outputs++;
@@ -1862,14 +1898,14 @@ xlate_resubmit_resource_check(struct xlate_ctx *ctx)
 {
     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
 
-    if (ctx->recurse >= MAX_RESUBMIT_RECURSION) {
+    if (ctx->recurse >= MAX_RESUBMIT_RECURSION + MAX_INTERNAL_RESUBMITS) {
         VLOG_ERR_RL(&rl, "resubmit actions recursed over %d times",
                     MAX_RESUBMIT_RECURSION);
-    } else if (ctx->resubmits >= MAX_RESUBMITS) {
+    } else if (ctx->resubmits >= MAX_RESUBMITS + MAX_INTERNAL_RESUBMITS) {
         VLOG_ERR_RL(&rl, "over %d resubmit actions", MAX_RESUBMITS);
-    } else if (ctx->xout->odp_actions.size > UINT16_MAX) {
+    } else if (ofpbuf_size(&ctx->xout->odp_actions) > UINT16_MAX) {
         VLOG_ERR_RL(&rl, "resubmits yielded over 64 kB of actions");
-    } else if (ctx->stack.size >= 65536) {
+    } else if (ofpbuf_size(&ctx->stack) >= 65536) {
         VLOG_ERR_RL(&rl, "resubmits yielded over 64 kB of stack");
     } else {
         return true;
@@ -1924,6 +1960,11 @@ xlate_table_action(struct xlate_ctx *ctx, ofp_port_t in_port, uint8_t table_id,
         case RULE_DPIF_LOOKUP_VERDICT_DROP:
             config = OFPUTIL_PC_NO_PACKET_IN;
             break;
+        case RULE_DPIF_LOOKUP_VERDICT_DEFAULT:
+            if (!ofproto_dpif_wants_packet_in_on_miss(ctx->xbridge->ofproto)) {
+                config = OFPUTIL_PC_NO_PACKET_IN;
+            }
+            break;
         default:
             OVS_NOT_REACHED();
         }
@@ -1955,7 +1996,7 @@ xlate_group_bucket(struct xlate_ctx *ctx, const struct ofputil_bucket *bucket)
 
     ofpacts_execute_action_set(&action_list, &action_set);
     ctx->recurse++;
-    do_xlate_actions(action_list.data, action_list.size, ctx);
+    do_xlate_actions(ofpbuf_data(&action_list), ofpbuf_size(&action_list), ctx);
     ctx->recurse--;
 
     ofpbuf_uninit(&action_set);
@@ -2081,6 +2122,15 @@ xlate_ofpact_resubmit(struct xlate_ctx *ctx,
 {
     ofp_port_t in_port;
     uint8_t table_id;
+    bool may_packet_in = false;
+    bool honor_table_miss = false;
+
+    if (ctx->rule && rule_dpif_is_internal(ctx->rule)) {
+        /* Still allow missed packets to be sent to the controller
+         * if resubmitting from an internal table. */
+        may_packet_in = true;
+        honor_table_miss = true;
+    }
 
     in_port = resubmit->in_port;
     if (in_port == OFPP_IN_PORT) {
@@ -2092,7 +2142,8 @@ xlate_ofpact_resubmit(struct xlate_ctx *ctx,
         table_id = ctx->table_id;
     }
 
-    xlate_table_action(ctx, in_port, table_id, false, false);
+    xlate_table_action(ctx, in_port, table_id, may_packet_in,
+                       honor_table_miss);
 }
 
 static void
@@ -2135,11 +2186,12 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
                                           &ctx->xout->odp_actions,
                                           &ctx->xout->wc);
 
-    odp_execute_actions(NULL, packet, false, &md, ctx->xout->odp_actions.data,
-                        ctx->xout->odp_actions.size, NULL);
+    odp_execute_actions(NULL, packet, false, &md,
+                        ofpbuf_data(&ctx->xout->odp_actions),
+                        ofpbuf_size(&ctx->xout->odp_actions), NULL);
 
     pin = xmalloc(sizeof *pin);
-    pin->up.packet_len = packet->size;
+    pin->up.packet_len = ofpbuf_size(packet);
     pin->up.packet = ofpbuf_steal_data(packet);
     pin->up.reason = reason;
     pin->up.table_id = ctx->table_id;
@@ -2551,7 +2603,7 @@ xlate_action_set(struct xlate_ctx *ctx)
 
     ofpbuf_use_stub(&action_list, action_list_stub, sizeof action_list_stub);
     ofpacts_execute_action_set(&action_list, &ctx->action_set);
-    do_xlate_actions(action_list.data, action_list.size, ctx);
+    do_xlate_actions(ofpbuf_data(&action_list), ofpbuf_size(&action_list), ctx);
     ofpbuf_uninit(&action_list);
 }
 
@@ -2719,15 +2771,22 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
         case OFPACT_SET_FIELD:
             set_field = ofpact_get_SET_FIELD(a);
             mf = set_field->field;
-            mf_mask_field_and_prereqs(mf, &wc->masks);
 
             /* Set field action only ever overwrites packet's outermost
              * applicable header fields.  Do nothing if no header exists. */
-            if ((mf->id != MFF_VLAN_VID || flow->vlan_tci & htons(VLAN_CFI))
-                && ((mf->id != MFF_MPLS_LABEL && mf->id != MFF_MPLS_TC)
-                    || eth_type_mpls(flow->dl_type))) {
-                mf_set_flow_value(mf, &set_field->value, flow);
+            if (mf->id == MFF_VLAN_VID) {
+                wc->masks.vlan_tci |= htons(VLAN_CFI);
+                if (!(flow->vlan_tci & htons(VLAN_CFI))) {
+                    break;
+                }
+            } else if ((mf->id == MFF_MPLS_LABEL || mf->id == MFF_MPLS_TC)
+                       /* 'dl_type' is already unwildcarded. */
+                       && !eth_type_mpls(flow->dl_type)) {
+                break;
             }
+
+            mf_mask_field_and_prereqs(mf, &wc->masks);
+            mf_set_flow_value(mf, &set_field->value, flow);
             break;
 
         case OFPACT_STACK_PUSH:
@@ -2897,8 +2956,8 @@ xlate_out_copy(struct xlate_out *dst, const struct xlate_out *src)
 
     ofpbuf_use_stub(&dst->odp_actions, dst->odp_actions_stub,
                     sizeof dst->odp_actions_stub);
-    ofpbuf_put(&dst->odp_actions, src->odp_actions.data,
-               src->odp_actions.size);
+    ofpbuf_put(&dst->odp_actions, ofpbuf_data(&src->odp_actions),
+               ofpbuf_size(&src->odp_actions));
 }
 \f
 static struct skb_priority_to_dscp *
@@ -2943,8 +3002,8 @@ actions_output_to_local_port(const struct xlate_ctx *ctx)
     const struct nlattr *a;
     unsigned int left;
 
-    NL_ATTR_FOR_EACH_UNSAFE (a, left, ctx->xout->odp_actions.data,
-                             ctx->xout->odp_actions.size) {
+    NL_ATTR_FOR_EACH_UNSAFE (a, left, ofpbuf_data(&ctx->xout->odp_actions),
+                             ofpbuf_size(&ctx->xout->odp_actions)) {
         if (nl_attr_type(a) == OVS_ACTION_ATTR_OUTPUT
             && nl_attr_get_odp_port(a) == local_odp_port) {
             return true;
@@ -3063,6 +3122,7 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout)
         ctx.rule = rule;
     }
     xout->fail_open = ctx.rule && rule_dpif_is_fail_open(ctx.rule);
+    xout->use_recirc = false;
 
     if (xin->ofpacts) {
         ofpacts = xin->ofpacts;
@@ -3131,7 +3191,7 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout)
 
         add_sflow_action(&ctx);
         add_ipfix_action(&ctx);
-        sample_actions_len = ctx.xout->odp_actions.size;
+        sample_actions_len = ofpbuf_size(&ctx.xout->odp_actions);
 
         if (tnl_may_send && (!in_port || may_receive(in_port, &ctx))) {
             do_xlate_actions(ofpacts, ofpacts_len, &ctx);
@@ -3139,11 +3199,11 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout)
             /* We've let OFPP_NORMAL and the learning action look at the
              * packet, so drop it now if forwarding is disabled. */
             if (in_port && !xport_stp_forward_state(in_port)) {
-                ctx.xout->odp_actions.size = sample_actions_len;
+                ofpbuf_set_size(&ctx.xout->odp_actions, sample_actions_len);
             }
         }
 
-        if (ctx.action_set.size) {
+        if (ofpbuf_size(&ctx.action_set)) {
             xlate_action_set(&ctx);
         }
 
@@ -3160,7 +3220,7 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout)
         }
     }
 
-    if (nl_attr_oversized(ctx.xout->odp_actions.size)) {
+    if (nl_attr_oversized(ofpbuf_size(&ctx.xout->odp_actions))) {
         /* These datapath actions are too big for a Netlink attribute, so we
          * can't hand them to the kernel directly.  dpif_execute() can execute
          * them one by one with help, so just mark the result as SLOW_ACTION to
index 8b01d4e..8b53e10 100644 (file)
@@ -32,6 +32,12 @@ struct dpif_ipfix;
 struct dpif_sflow;
 struct mac_learning;
 
+struct xlate_recirc {
+    uint32_t recirc_id;  /* !0 Use recirculation instead of output. */
+    uint8_t  hash_alg;   /* !0 Compute hash for recirc before. */
+    uint32_t hash_bias;  /* Compute hash for recirc before. */
+};
+
 struct xlate_out {
     /* Wildcards relevant in translation.  Any fields that were used to
      * calculate the action must be set for caching and kernel
@@ -50,6 +56,9 @@ struct xlate_out {
     ofp_port_t nf_output_iface; /* Output interface index for NetFlow. */
     mirror_mask_t mirrors;      /* Bitmap of associated mirrors. */
 
+    bool use_recirc;            /* Should generate recirc? */
+    struct xlate_recirc recirc; /* Information used for generating
+                                 * recirculation actions */
     uint64_t odp_actions_stub[256 / 8];
     struct ofpbuf odp_actions;
 };
@@ -129,7 +138,8 @@ void xlate_ofproto_set(struct ofproto_dpif *, const char *name,
                        const struct mbridge *, const struct dpif_sflow *,
                        const struct dpif_ipfix *, const struct netflow *,
                        enum ofp_config_flags, bool forward_bpdu,
-                       bool has_in_band, bool variable_length_userdata,
+                       bool has_in_band, bool enable_recirc,
+                       bool variable_length_userdata,
                        size_t mpls_label_stack_length)
     OVS_REQ_WRLOCK(xlate_rwlock);
 void xlate_remove_ofproto(struct ofproto_dpif *) OVS_REQ_WRLOCK(xlate_rwlock);
@@ -161,8 +171,8 @@ int xlate_receive(const struct dpif_backer *, struct ofpbuf *packet,
 void xlate_actions(struct xlate_in *, struct xlate_out *)
     OVS_EXCLUDED(xlate_rwlock);
 void xlate_in_init(struct xlate_in *, struct ofproto_dpif *,
-                   const struct flow *, struct rule_dpif *, uint16_t tcp_flags,
-                   const struct ofpbuf *packet);
+                   const struct flow *, struct rule_dpif *,
+                   uint16_t tcp_flags, const struct ofpbuf *packet);
 void xlate_out_uninit(struct xlate_out *);
 void xlate_actions_for_side_effects(struct xlate_in *);
 void xlate_out_copy(struct xlate_out *dst, const struct xlate_out *src);
index 7172cb2..a92fe81 100644 (file)
@@ -253,7 +253,9 @@ struct dpif_backer {
 
     bool recv_set_enable; /* Enables or disables receiving packets. */
 
+    /* Recirculation. */
     struct recirc_id_pool *rid_pool;       /* Recirculation ID pool. */
+    bool enable_recirc;   /* True if the datapath supports recirculation */
 
     /* True if the datapath supports variable-length
      * OVS_USERSPACE_ATTR_USERDATA in OVS_ACTION_ATTR_USERSPACE actions.
@@ -332,9 +334,15 @@ ofproto_dpif_get_max_mpls_depth(const struct ofproto_dpif *ofproto)
     return ofproto->backer->max_mpls_depth;
 }
 
+bool
+ofproto_dpif_get_enable_recirc(const struct ofproto_dpif *ofproto)
+{
+    return ofproto->backer->enable_recirc;
+}
+
 static struct ofport_dpif *get_ofp_port(const struct ofproto_dpif *ofproto,
                                         ofp_port_t ofp_port);
-static void ofproto_trace(struct ofproto_dpif *, const struct flow *,
+static void ofproto_trace(struct ofproto_dpif *, struct flow *,
                           const struct ofpbuf *packet,
                           const struct ofpact[], size_t ofpacts_len,
                           struct ds *);
@@ -366,6 +374,18 @@ ofproto_dpif_send_packet_in(struct ofproto_dpif *ofproto,
         free(pin);
     }
 }
+
+/* The default "table-miss" behaviour for OpenFlow1.3+ is to drop the
+ * packet rather than to send the packet to the controller.
+ *
+ * This function returns false to indicate that a packet_in message
+ * for a "table-miss" should be sent to at least one controller.
+ * False otherwise. */
+bool
+ofproto_dpif_wants_packet_in_on_miss(struct ofproto_dpif *ofproto)
+{
+    return connmgr_wants_packet_in_on_miss(ofproto->up.connmgr);
+}
 \f
 /* Factory functions. */
 
@@ -571,6 +591,7 @@ type_run(const char *type)
                               ofproto->netflow, ofproto->up.frag_handling,
                               ofproto->up.forward_bpdu,
                               connmgr_has_in_band(ofproto->up.connmgr),
+                              ofproto->backer->enable_recirc,
                               ofproto->backer->variable_length_userdata,
                               ofproto->backer->max_mpls_depth);
 
@@ -796,6 +817,7 @@ struct odp_garbage {
 
 static bool check_variable_length_userdata(struct dpif_backer *backer);
 static size_t check_max_mpls_depth(struct dpif_backer *backer);
+static bool check_recirc(struct dpif_backer *backer);
 
 static int
 open_dpif_backer(const char *type, struct dpif_backer **backerp)
@@ -896,6 +918,7 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp)
         close_dpif_backer(backer);
         return error;
     }
+    backer->enable_recirc = check_recirc(backer);
     backer->variable_length_userdata = check_variable_length_userdata(backer);
     backer->max_mpls_depth = check_max_mpls_depth(backer);
     backer->rid_pool = recirc_id_pool_create();
@@ -907,6 +930,61 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp)
     return error;
 }
 
+/* Tests whether 'backer''s datapath supports recirculation Only newer datapath
+ * supports OVS_KEY_ATTR in OVS_ACTION_ATTR_USERSPACE actions.  We need to
+ * disable some features on older datapaths that don't support this feature.
+ *
+ * Returns false if 'backer' definitely does not support recirculation, true if
+ * it seems to support recirculation or if at least the error we get is
+ * ambiguous. */
+static bool
+check_recirc(struct dpif_backer *backer)
+{
+    struct flow flow;
+    struct odputil_keybuf keybuf;
+    struct ofpbuf key;
+    int error;
+    bool enable_recirc = false;
+
+    memset(&flow, 0, sizeof flow);
+    flow.recirc_id = 1;
+    flow.dp_hash = 1;
+
+    ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
+    odp_flow_key_from_flow(&key, &flow, 0);
+
+    error = dpif_flow_put(backer->dpif, DPIF_FP_CREATE | DPIF_FP_MODIFY,
+                          ofpbuf_data(&key), ofpbuf_size(&key), NULL, 0, NULL,
+                          0, NULL);
+    if (error && error != EEXIST) {
+        if (error != EINVAL) {
+            VLOG_WARN("%s: Reciculation flow probe failed (%s)",
+                      dpif_name(backer->dpif), ovs_strerror(error));
+        }
+        goto done;
+    }
+
+    error = dpif_flow_del(backer->dpif, ofpbuf_data(&key), ofpbuf_size(&key),
+                          NULL);
+    if (error) {
+        VLOG_WARN("%s: failed to delete recirculation feature probe flow",
+                  dpif_name(backer->dpif));
+    }
+
+    enable_recirc = true;
+
+done:
+    if (enable_recirc) {
+        VLOG_INFO("%s: Datapath supports recirculation",
+                  dpif_name(backer->dpif));
+    } else {
+        VLOG_INFO("%s: Datapath does not support recirculation",
+                  dpif_name(backer->dpif));
+    }
+
+    return enable_recirc;
+}
+
 /* Tests whether 'backer''s datapath supports variable-length
  * OVS_USERSPACE_ATTR_USERDATA in OVS_ACTION_ATTR_USERSPACE actions.  We need
  * to disable some features on older datapaths that don't support this
@@ -946,8 +1024,8 @@ check_variable_length_userdata(struct dpif_backer *backer)
 
     /* Execute the actions.  On older datapaths this fails with ERANGE, on
      * newer datapaths it succeeds. */
-    execute.actions = actions.data;
-    execute.actions_len = actions.size;
+    execute.actions = ofpbuf_data(&actions);
+    execute.actions_len = ofpbuf_size(&actions);
     execute.packet = &packet;
     execute.md = PKT_METADATA_INITIALIZER(0);
     execute.needs_help = false;
@@ -1009,7 +1087,7 @@ check_max_mpls_depth(struct dpif_backer *backer)
         odp_flow_key_from_flow(&key, &flow, 0);
 
         error = dpif_flow_put(backer->dpif, DPIF_FP_CREATE | DPIF_FP_MODIFY,
-                              key.data, key.size, NULL, 0, NULL, 0, NULL);
+                              ofpbuf_data(&key), ofpbuf_size(&key), NULL, 0, NULL, 0, NULL);
         if (error && error != EEXIST) {
             if (error != EINVAL) {
                 VLOG_WARN("%s: MPLS stack length feature probe failed (%s)",
@@ -1018,7 +1096,7 @@ check_max_mpls_depth(struct dpif_backer *backer)
             break;
         }
 
-        error = dpif_flow_del(backer->dpif, key.data, key.size, NULL);
+        error = dpif_flow_del(backer->dpif, ofpbuf_data(&key), ofpbuf_size(&key), NULL);
         if (error) {
             VLOG_WARN("%s: failed to delete MPLS feature probe flow",
                       dpif_name(backer->dpif));
@@ -1090,51 +1168,27 @@ construct(struct ofproto *ofproto_)
 
     ofproto_init_tables(ofproto_, N_TABLES);
     error = add_internal_flows(ofproto);
+
     ofproto->up.tables[TBL_INTERNAL].flags = OFTABLE_HIDDEN | OFTABLE_READONLY;
 
     return error;
 }
 
 static int
-add_internal_flow(struct ofproto_dpif *ofproto, int id,
+add_internal_miss_flow(struct ofproto_dpif *ofproto, int id,
                   const struct ofpbuf *ofpacts, struct rule_dpif **rulep)
 {
-    struct ofputil_flow_mod fm;
-    struct classifier *cls;
+    struct match match;
     int error;
+    struct rule *rule;
 
-    match_init_catchall(&fm.match);
-    fm.priority = 0;
-    match_set_reg(&fm.match, 0, id);
-    fm.new_cookie = htonll(0);
-    fm.cookie = htonll(0);
-    fm.cookie_mask = htonll(0);
-    fm.modify_cookie = false;
-    fm.table_id = TBL_INTERNAL;
-    fm.command = OFPFC_ADD;
-    fm.idle_timeout = 0;
-    fm.hard_timeout = 0;
-    fm.buffer_id = 0;
-    fm.out_port = 0;
-    fm.flags = 0;
-    fm.ofpacts = ofpacts->data;
-    fm.ofpacts_len = ofpacts->size;
+    match_init_catchall(&match);
+    match_set_reg(&match, 0, id);
 
-    error = ofproto_flow_mod(&ofproto->up, &fm);
-    if (error) {
-        VLOG_ERR_RL(&rl, "failed to add internal flow %d (%s)",
-                    id, ofperr_to_string(error));
-        return error;
-    }
-
-    cls = &ofproto->up.tables[TBL_INTERNAL].cls;
-    fat_rwlock_rdlock(&cls->rwlock);
-    *rulep = rule_dpif_cast(rule_from_cls_rule(
-                                classifier_lookup(cls, &fm.match.flow, NULL)));
-    ovs_assert(*rulep != NULL);
-    fat_rwlock_unlock(&cls->rwlock);
+    error = ofproto_dpif_add_internal_flow(ofproto, &match, 0, ofpacts, &rule);
+    *rulep = error ? NULL : rule_dpif_cast(rule);
 
-    return 0;
+    return error;
 }
 
 static int
@@ -1143,6 +1197,9 @@ add_internal_flows(struct ofproto_dpif *ofproto)
     struct ofpact_controller *controller;
     uint64_t ofpacts_stub[128 / 8];
     struct ofpbuf ofpacts;
+    struct rule *unused_rulep OVS_UNUSED;
+    struct ofpact_resubmit *resubmit;
+    struct match match;
     int error;
     int id;
 
@@ -1155,20 +1212,53 @@ add_internal_flows(struct ofproto_dpif *ofproto)
     controller->reason = OFPR_NO_MATCH;
     ofpact_pad(&ofpacts);
 
-    error = add_internal_flow(ofproto, id++, &ofpacts, &ofproto->miss_rule);
+    error = add_internal_miss_flow(ofproto, id++, &ofpacts,
+                                   &ofproto->miss_rule);
     if (error) {
         return error;
     }
 
     ofpbuf_clear(&ofpacts);
-    error = add_internal_flow(ofproto, id++, &ofpacts,
+    error = add_internal_miss_flow(ofproto, id++, &ofpacts,
                               &ofproto->no_packet_in_rule);
     if (error) {
         return error;
     }
 
-    error = add_internal_flow(ofproto, id++, &ofpacts,
+    error = add_internal_miss_flow(ofproto, id++, &ofpacts,
                               &ofproto->drop_frags_rule);
+    if (error) {
+        return error;
+    }
+
+    /* Continue non-recirculation rule lookups from table 0.
+     *
+     * (priority=2), recirc=0, actions=resubmit(, 0)
+     */
+    resubmit = ofpact_put_RESUBMIT(&ofpacts);
+    resubmit->ofpact.compat = 0;
+    resubmit->in_port = OFPP_IN_PORT;
+    resubmit->table_id = 0;
+
+    match_init_catchall(&match);
+    match_set_recirc_id(&match, 0);
+
+    error = ofproto_dpif_add_internal_flow(ofproto, &match, 2,  &ofpacts,
+                                           &unused_rulep);
+    if (error) {
+        return error;
+    }
+
+    /* Drop any run away recirc rule lookups. Recirc_id has to be
+     * non-zero when reaching this rule.
+     *
+     * (priority=1), *, actions=drop
+     */
+    ofpbuf_clear(&ofpacts);
+    match_init_catchall(&match);
+    error = ofproto_dpif_add_internal_flow(ofproto, &match, 1,  &ofpacts,
+                                           &unused_rulep);
+
     return error;
 }
 
@@ -1236,6 +1326,7 @@ run(struct ofproto *ofproto_)
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
     uint64_t new_seq, new_dump_seq;
+    const bool enable_recirc = ofproto_dpif_get_enable_recirc(ofproto);
 
     if (mbridge_need_revalidate(ofproto->mbridge)) {
         ofproto->backer->need_revalidate = REV_RECONFIGURE;
@@ -1313,12 +1404,17 @@ run(struct ofproto *ofproto_)
 
         /* All outstanding data in existing flows has been accounted, so it's a
          * good time to do bond rebalancing. */
-        if (ofproto->has_bonded_bundles) {
+        if (enable_recirc && ofproto->has_bonded_bundles) {
             struct ofbundle *bundle;
 
             HMAP_FOR_EACH (bundle, hmap_node, &ofproto->bundles) {
-                if (bundle->bond) {
-                    bond_rebalance(bundle->bond);
+                struct bond *bond = bundle->bond;
+
+                if (bond && bond_may_recirc(bond, NULL, NULL)) {
+                    bond_recirculation_account(bond);
+                    if (bond_rebalance(bundle->bond)) {
+                        bond_update_post_recirc_rules(bond, true);
+                    }
                 }
             }
         }
@@ -1768,7 +1864,7 @@ send_bpdu_cb(struct ofpbuf *pkt, int port_num, void *ofproto_)
         VLOG_WARN_RL(&rl, "%s: cannot send BPDU on unknown port %d",
                      ofproto->up.name, port_num);
     } else {
-        struct eth_header *eth = pkt->l2;
+        struct eth_header *eth = ofpbuf_l2(pkt);
 
         netdev_get_etheraddr(ofport->up.netdev, eth->eth_src);
         if (eth_addr_is_zero(eth->eth_src)) {
@@ -2336,12 +2432,13 @@ bundle_set(struct ofproto *ofproto_, void *aux,
                 ofproto->backer->need_revalidate = REV_RECONFIGURE;
             }
         } else {
-            bundle->bond = bond_create(s->bond);
+            bundle->bond = bond_create(s->bond, ofproto);
             ofproto->backer->need_revalidate = REV_RECONFIGURE;
         }
 
         LIST_FOR_EACH (port, bundle_node, &bundle->ports) {
-            bond_slave_register(bundle->bond, port, port->up.netdev);
+            bond_slave_register(bundle->bond, port,
+                                port->up.ofp_port, port->up.netdev);
         }
     } else {
         bond_unref(bundle->bond);
@@ -2419,9 +2516,9 @@ bundle_send_learning_packets(struct ofbundle *bundle)
             learning_packet = bond_compose_learning_packet(bundle->bond,
                                                            e->mac, e->vlan,
                                                            &port_void);
-            /* Temporarily use l2 as a private pointer (see below). */
-            ovs_assert(learning_packet->l2 == learning_packet->data);
-            learning_packet->l2 = port_void;
+            /* Temporarily use 'frame' as a private pointer (see below). */
+            ovs_assert(learning_packet->frame == ofpbuf_data(learning_packet));
+            learning_packet->frame = port_void;
             list_push_back(&packets, &learning_packet->list_node);
         }
     }
@@ -2430,10 +2527,10 @@ bundle_send_learning_packets(struct ofbundle *bundle)
     error = n_packets = n_errors = 0;
     LIST_FOR_EACH (learning_packet, list_node, &packets) {
         int ret;
-        void *port_void = learning_packet->l2;
+        void *port_void = learning_packet->frame;
 
-        /* Restore l2. */
-        learning_packet->l2 = learning_packet->data;
+        /* Restore 'frame'. */
+        learning_packet->frame = ofpbuf_data(learning_packet);
         ret = ofproto_dpif_send_packet(port_void, learning_packet);
         if (ret) {
             error = ret;
@@ -2991,6 +3088,7 @@ ofproto_dpif_execute_actions(struct ofproto_dpif *ofproto,
     ovs_assert((rule != NULL) != (ofpacts != NULL));
 
     dpif_flow_stats_extract(flow, packet, time_msec(), &stats);
+
     if (rule) {
         rule_dpif_credit_stats(rule, &stats);
     }
@@ -3005,8 +3103,8 @@ ofproto_dpif_execute_actions(struct ofproto_dpif *ofproto,
     if (in_port == OFPP_NONE) {
         in_port = OFPP_LOCAL;
     }
-    execute.actions = xout.odp_actions.data;
-    execute.actions_len = xout.odp_actions.size;
+    execute.actions = ofpbuf_data(&xout.odp_actions);
+    execute.actions_len = ofpbuf_size(&xout.odp_actions);
     execute.packet = packet;
     execute.md.tunnel = flow->tunnel;
     execute.md.skb_priority = flow->skb_priority;
@@ -3073,20 +3171,13 @@ rule_dpif_get_actions(const struct rule_dpif *rule)
     return rule_get_actions(&rule->up);
 }
 
-/* Lookup 'flow' in table 0 of 'ofproto''s classifier.
- * If 'wc' is non-null, sets the fields that were relevant as part of
- * the lookup. Returns the table_id where a match or miss occurred.
- *
- * The return value will be zero unless there was a miss and
- * OFPTC_TABLE_MISS_CONTINUE is in effect for the sequence of tables
- * where misses occur. */
-uint8_t
-rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow,
-                 struct flow_wildcards *wc, struct rule_dpif **rule)
+static uint8_t
+rule_dpif_lookup__ (struct ofproto_dpif *ofproto, const struct flow *flow,
+                    struct flow_wildcards *wc, struct rule_dpif **rule)
 {
     enum rule_dpif_lookup_verdict verdict;
     enum ofputil_port_config config = 0;
-    uint8_t table_id = 0;
+    uint8_t table_id = TBL_INTERNAL;
 
     verdict = rule_dpif_lookup_from_table(ofproto, flow, wc, true,
                                           &table_id, rule);
@@ -3108,6 +3199,11 @@ rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow,
     case RULE_DPIF_LOOKUP_VERDICT_DROP:
         config = OFPUTIL_PC_NO_PACKET_IN;
         break;
+    case RULE_DPIF_LOOKUP_VERDICT_DEFAULT:
+        if (!connmgr_wants_packet_in_on_miss(ofproto->up.connmgr)) {
+            config = OFPUTIL_PC_NO_PACKET_IN;
+        }
+        break;
     default:
         OVS_NOT_REACHED();
     }
@@ -3117,6 +3213,23 @@ rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow,
     return table_id;
 }
 
+/* Lookup 'flow' in table 0 of 'ofproto''s classifier.
+ * If 'wc' is non-null, sets the fields that were relevant as part of
+ * the lookup. Returns the table_id where a match or miss occurred.
+ *
+ * The return value will be zero unless there was a miss and
+ * O!-TC_TABLE_MISS_CONTINUE is in effect for the sequence of tables
+ * where misses occur. */
+uint8_t
+rule_dpif_lookup(struct ofproto_dpif *ofproto, struct flow *flow,
+                 struct flow_wildcards *wc, struct rule_dpif **rule)
+{
+    /* Set metadata to the value of recirc_id to speed up internal
+     * rule lookup. */
+    flow->metadata = htonll(flow->recirc_id);
+    return rule_dpif_lookup__(ofproto, flow, wc, rule);
+}
+
 static struct rule_dpif *
 rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto, uint8_t table_id,
                           const struct flow *flow, struct flow_wildcards *wc)
@@ -3177,12 +3290,17 @@ rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto, uint8_t table_id,
  *
  *    - RULE_DPIF_LOOKUP_VERDICT_MATCH if a rule (in '*rule') was found.
  *
- *    - RULE_DPIF_LOOKUP_VERDICT_DROP if no rule was found and a table miss
- *      configuration specified that the packet should be dropped in this
- *      case.  (This occurs only if 'honor_table_miss' is true, because only in
- *      this case does the table miss configuration matter.)
+ *    - RULE_OFPTC_TABLE_MISS_CONTROLLER if no rule was found and either:
+ *      + 'honor_table_miss' is false
+ *      + a table miss configuration specified that the packet should be
+ *
+ *    - RULE_DPIF_LOOKUP_VERDICT_DROP if no rule was found, 'honor_table_miss'
+ *      is true and a table miss configuration specified that the packet
+ *      should be dropped in this case.
  *
- *    - RULE_DPIF_LOOKUP_VERDICT_CONTROLLER if no rule was found otherwise. */
+ *    - RULE_DPIF_LOOKUP_VERDICT_DEFAULT if no rule was found,
+ *      'honor_table_miss' is true and a table miss configuration has
+ *      not been specified in this case. */
 enum rule_dpif_lookup_verdict
 rule_dpif_lookup_from_table(struct ofproto_dpif *ofproto,
                             const struct flow *flow,
@@ -3203,16 +3321,18 @@ rule_dpif_lookup_from_table(struct ofproto_dpif *ofproto,
         } else if (!honor_table_miss) {
             return RULE_DPIF_LOOKUP_VERDICT_CONTROLLER;
         } else {
-            switch (table_get_config(&ofproto->up, *table_id)
-                    & OFPTC11_TABLE_MISS_MASK) {
-            case OFPTC11_TABLE_MISS_CONTINUE:
+            switch (ofproto_table_get_config(&ofproto->up, *table_id)) {
+            case OFPROTO_TABLE_MISS_CONTINUE:
                 break;
 
-            case OFPTC11_TABLE_MISS_CONTROLLER:
+            case OFPROTO_TABLE_MISS_CONTROLLER:
                 return RULE_DPIF_LOOKUP_VERDICT_CONTROLLER;
 
-            case OFPTC11_TABLE_MISS_DROP:
+            case OFPROTO_TABLE_MISS_DROP:
                 return RULE_DPIF_LOOKUP_VERDICT_DROP;
+
+            case OFPROTO_TABLE_MISS_DEFAULT:
+                return RULE_DPIF_LOOKUP_VERDICT_DEFAULT;
             }
         }
     }
@@ -3517,7 +3637,7 @@ ofproto_dpif_send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet
 
     ovs_mutex_lock(&ofproto->stats_mutex);
     ofproto->stats.tx_packets++;
-    ofproto->stats.tx_bytes += packet->size;
+    ofproto->stats.tx_bytes += ofpbuf_size(packet);
     ovs_mutex_unlock(&ofproto->stats_mutex);
     return error;
 }
@@ -3660,6 +3780,7 @@ ofproto_unixctl_fdb_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
 struct trace_ctx {
     struct xlate_out xout;
     struct xlate_in xin;
+    const struct flow *key;
     struct flow flow;
     struct flow_wildcards wc;
     struct ds *result;
@@ -3700,7 +3821,9 @@ trace_format_flow(struct ds *result, int level, const char *title,
 {
     ds_put_char_multiple(result, '\t', level);
     ds_put_format(result, "%s: ", title);
-    if (flow_equal(&trace->xin.flow, &trace->flow)) {
+    /* Do not report unchanged flows for resubmits. */
+    if ((level > 0 && flow_equal(&trace->xin.flow, &trace->flow))
+        || (level == 0 && flow_equal(&trace->xin.flow, trace->key))) {
         ds_put_cstr(result, "unchanged");
     } else {
         flow_format(result, &trace->xin.flow);
@@ -3731,7 +3854,8 @@ trace_format_odp(struct ds *result, int level, const char *title,
 
     ds_put_char_multiple(result, '\t', level);
     ds_put_format(result, "%s: ", title);
-    format_odp_actions(result, odp_actions->data, odp_actions->size);
+    format_odp_actions(result, ofpbuf_data(odp_actions),
+                               ofpbuf_size(odp_actions));
     ds_put_char(result, '\n');
 }
 
@@ -3744,7 +3868,7 @@ trace_format_megaflow(struct ds *result, int level, const char *title,
     ds_put_char_multiple(result, '\t', level);
     ds_put_format(result, "%s: ", title);
     flow_wildcards_or(&trace->wc, &trace->xout.wc, &trace->wc);
-    match_init(&match, &trace->flow, &trace->wc);
+    match_init(&match, trace->key, &trace->wc);
     match_format(&match, result, OFP_DEFAULT_PRIORITY);
     ds_put_char(result, '\n');
 }
@@ -3855,7 +3979,8 @@ parse_flow_and_packet(int argc, const char *argv[],
             goto exit;
         }
 
-        if (xlate_receive(backer, NULL, odp_key.data, odp_key.size, flow,
+        if (xlate_receive(backer, NULL, ofpbuf_data(&odp_key),
+                          ofpbuf_size(&odp_key), flow,
                           ofprotop, NULL, NULL, NULL, NULL)) {
             error = "Invalid datapath flow";
             goto exit;
@@ -3883,7 +4008,7 @@ parse_flow_and_packet(int argc, const char *argv[],
 
     /* Generate a packet, if requested. */
     if (packet) {
-        if (!packet->size) {
+        if (!ofpbuf_size(packet)) {
             flow_compose(packet, flow);
         } else {
             struct pkt_metadata md = pkt_metadata_from_flow(flow);
@@ -3996,11 +4121,11 @@ ofproto_unixctl_trace_actions(struct unixctl_conn *conn, int argc,
         goto exit;
     }
     if (enforce_consistency) {
-        retval = ofpacts_check_consistency(ofpacts.data, ofpacts.size, &flow,
-                                           u16_to_ofp(ofproto->up.max_ports),
+        retval = ofpacts_check_consistency(ofpbuf_data(&ofpacts), ofpbuf_size(&ofpacts),
+                                           &flow, u16_to_ofp(ofproto->up.max_ports),
                                            0, 0, usable_protocols);
     } else {
-        retval = ofpacts_check(ofpacts.data, ofpacts.size, &flow,
+        retval = ofpacts_check(ofpbuf_data(&ofpacts), ofpbuf_size(&ofpacts), &flow,
                                u16_to_ofp(ofproto->up.max_ports), 0, 0,
                                &usable_protocols);
     }
@@ -4012,7 +4137,8 @@ ofproto_unixctl_trace_actions(struct unixctl_conn *conn, int argc,
         goto exit;
     }
 
-    ofproto_trace(ofproto, &flow, packet, ofpacts.data, ofpacts.size, &result);
+    ofproto_trace(ofproto, &flow, packet,
+                  ofpbuf_data(&ofpacts), ofpbuf_size(&ofpacts), &result);
     unixctl_command_reply(conn, ds_cstr(&result));
 
 exit:
@@ -4031,7 +4157,7 @@ exit:
  * If 'ofpacts' is nonnull then its 'ofpacts_len' bytes specify the actions to
  * trace, otherwise the actions are determined by a flow table lookup. */
 static void
-ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
+ofproto_trace(struct ofproto_dpif *ofproto, struct flow *flow,
               const struct ofpbuf *packet,
               const struct ofpact ofpacts[], size_t ofpacts_len,
               struct ds *ds)
@@ -4064,7 +4190,8 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
 
     if (rule || ofpacts) {
         trace.result = ds;
-        trace.flow = *flow;
+        trace.key = flow; /* Original flow key, used for megaflow. */
+        trace.flow = *flow; /* May be modified by actions. */
         xlate_in_init(&trace.xin, ofproto, flow, rule, ntohs(flow->tcp_flags),
                       packet);
         if (ofpacts) {
@@ -4081,8 +4208,8 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
         trace_format_megaflow(ds, 0, "Megaflow", &trace);
 
         ds_put_cstr(ds, "Datapath actions: ");
-        format_odp_actions(ds, trace.xout.odp_actions.data,
-                           trace.xout.odp_actions.size);
+        format_odp_actions(ds, ofpbuf_data(&trace.xout.odp_actions),
+                           ofpbuf_size(&trace.xout.odp_actions));
 
         if (trace.xout.slow) {
             enum slow_path_reason slow;
@@ -4383,7 +4510,7 @@ set_realdev(struct ofport *ofport_, ofp_port_t realdev_ofp_port, int vid)
     if (realdev_ofp_port && ofport->bundle) {
         /* vlandevs are enslaved to their realdevs, so they are not allowed to
          * themselves be part of a bundle. */
-        bundle_set(ofport->up.ofproto, ofport->bundle, NULL);
+        bundle_set(ofport_->ofproto, ofport->bundle, NULL);
     }
 
     ofport->realdev_ofp_port = realdev_ofp_port;
@@ -4634,6 +4761,78 @@ ofproto_dpif_free_recirc_id(struct ofproto_dpif *ofproto, uint32_t recirc_id)
     recirc_id_free(backer->rid_pool, recirc_id);
 }
 
+int
+ofproto_dpif_add_internal_flow(struct ofproto_dpif *ofproto,
+                               struct match *match, int priority,
+                               const struct ofpbuf *ofpacts,
+                               struct rule **rulep)
+{
+    struct ofputil_flow_mod fm;
+    struct rule_dpif *rule;
+    int error;
+
+    fm.match = *match;
+    fm.priority = priority;
+    fm.new_cookie = htonll(0);
+    fm.cookie = htonll(0);
+    fm.cookie_mask = htonll(0);
+    fm.modify_cookie = false;
+    fm.table_id = TBL_INTERNAL;
+    fm.command = OFPFC_ADD;
+    fm.idle_timeout = 0;
+    fm.hard_timeout = 0;
+    fm.buffer_id = 0;
+    fm.out_port = 0;
+    fm.flags = OFPUTIL_FF_HIDDEN_FIELDS | OFPUTIL_FF_NO_READONLY;
+    fm.ofpacts = ofpbuf_data(ofpacts);
+    fm.ofpacts_len = ofpbuf_size(ofpacts);
+
+    error = ofproto_flow_mod(&ofproto->up, &fm);
+    if (error) {
+        VLOG_ERR_RL(&rl, "failed to add internal flow (%s)",
+                    ofperr_to_string(error));
+        *rulep = NULL;
+        return error;
+    }
+
+    rule = rule_dpif_lookup_in_table(ofproto, TBL_INTERNAL, &match->flow,
+                                     &match->wc);
+    if (rule) {
+        rule_dpif_unref(rule);
+        *rulep = &rule->up;
+    } else {
+        OVS_NOT_REACHED();
+    }
+    return 0;
+}
+
+int
+ofproto_dpif_delete_internal_flow(struct ofproto_dpif *ofproto,
+                                  struct match *match, int priority)
+{
+    struct ofputil_flow_mod fm;
+    int error;
+
+    fm.match = *match;
+    fm.priority = priority;
+    fm.new_cookie = htonll(0);
+    fm.cookie = htonll(0);
+    fm.cookie_mask = htonll(0);
+    fm.modify_cookie = false;
+    fm.table_id = TBL_INTERNAL;
+    fm.flags = OFPUTIL_FF_HIDDEN_FIELDS | OFPUTIL_FF_NO_READONLY;
+    fm.command = OFPFC_DELETE_STRICT;
+
+    error = ofproto_flow_mod(&ofproto->up, &fm);
+    if (error) {
+        VLOG_ERR_RL(&rl, "failed to delete internal flow (%s)",
+                    ofperr_to_string(error));
+        return error;
+    }
+
+    return 0;
+}
+
 const struct ofproto_class ofproto_dpif_class = {
     init,
     enumerate_types,
index 088ff89..ed0aa90 100644 (file)
@@ -21,6 +21,7 @@
 #include "odp-util.h"
 #include "ofp-util.h"
 #include "ovs-thread.h"
+#include "ofproto-provider.h"
 #include "timer.h"
 #include "util.h"
 #include "ovs-thread.h"
@@ -42,6 +43,13 @@ enum rule_dpif_lookup_verdict {
                                              * the controller. */
     RULE_DPIF_LOOKUP_VERDICT_DROP,          /* A miss occurred and the packet
                                              * should be dropped. */
+    RULE_DPIF_LOOKUP_VERDICT_DEFAULT,       /* A miss occurred and the packet
+                                             * should handled by the default
+                                             * miss behaviour.
+                                             * For pre-OF1.3 it should be
+                                             * forwarded to the controller.
+                                             * For OF1.3+ it should be
+                                             * dropped. */
 };
 
 /* For lock annotation below only. */
@@ -76,9 +84,10 @@ extern struct ovs_rwlock xlate_rwlock;
  *   actions into datapath actions. */
 
 size_t ofproto_dpif_get_max_mpls_depth(const struct ofproto_dpif *);
+bool ofproto_dpif_get_enable_recirc(const struct ofproto_dpif *);
 
-uint8_t rule_dpif_lookup(struct ofproto_dpif *, const struct flow *,
-                         struct flow_wildcards *, struct rule_dpif **rule);
+uint8_t rule_dpif_lookup(struct ofproto_dpif *, struct flow *,
+                      struct flow_wildcards *, struct rule_dpif **rule);
 
 enum rule_dpif_lookup_verdict rule_dpif_lookup_from_table(struct ofproto_dpif *,
                                                           const struct flow *,
@@ -96,6 +105,7 @@ void rule_dpif_credit_stats(struct rule_dpif *rule ,
 bool rule_dpif_is_fail_open(const struct rule_dpif *);
 bool rule_dpif_is_table_miss(const struct rule_dpif *);
 bool rule_dpif_is_internal(const struct rule_dpif *);
+uint8_t rule_dpif_get_table(const struct rule_dpif *);
 
 struct rule_actions *rule_dpif_get_actions(const struct rule_dpif *);
 
@@ -130,6 +140,7 @@ int ofproto_dpif_execute_actions(struct ofproto_dpif *, const struct flow *,
     OVS_EXCLUDED(xlate_rwlock);
 void ofproto_dpif_send_packet_in(struct ofproto_dpif *,
                                  struct ofproto_packet_in *);
+bool ofproto_dpif_wants_packet_in_on_miss(struct ofproto_dpif *);
 int ofproto_dpif_send_packet(const struct ofport_dpif *, struct ofpbuf *);
 void ofproto_dpif_flow_mod(struct ofproto_dpif *, struct ofputil_flow_mod *);
 
@@ -199,4 +210,11 @@ struct ofport_dpif *odp_port_to_ofport(const struct dpif_backer *, odp_port_t);
 
 uint32_t ofproto_dpif_alloc_recirc_id(struct ofproto_dpif *ofproto);
 void ofproto_dpif_free_recirc_id(struct ofproto_dpif *ofproto, uint32_t recirc_id);
+int ofproto_dpif_add_internal_flow(struct ofproto_dpif *,
+                                   struct match *, int priority,
+                                   const struct ofpbuf *ofpacts,
+                                   struct rule **rulep);
+int ofproto_dpif_delete_internal_flow(struct ofproto_dpif *, struct match *,
+                                      int priority);
+
 #endif /* ofproto-dpif.h */
index a7bf4df..bfa0235 100644 (file)
@@ -205,7 +205,8 @@ void ofproto_port_set_state(struct ofport *, enum ofputil_port_state);
  */
 enum oftable_flags {
     OFTABLE_HIDDEN = 1 << 0,   /* Hide from most OpenFlow operations. */
-    OFTABLE_READONLY = 1 << 1  /* Don't allow OpenFlow to change this table. */
+    OFTABLE_READONLY = 1 << 1  /* Don't allow OpenFlow controller to change
+                                  this table. */
 };
 
 /* A flow table within a "struct ofproto".
@@ -262,7 +263,7 @@ struct oftable {
     struct hmap eviction_groups_by_id;
     struct heap eviction_groups_by_size;
 
-    /* Table config: contains enum ofp_table_config; accessed atomically. */
+    /* Table config: contains enum ofproto_table_config; accessed atomically. */
     atomic_uint config;
 };
 
index b2d6526..a517264 100644 (file)
@@ -261,7 +261,8 @@ struct ofport_usage {
 /* rule. */
 static void ofproto_rule_destroy__(struct rule *);
 static void ofproto_rule_send_removed(struct rule *, uint8_t reason);
-static bool rule_is_modifiable(const struct rule *);
+static bool rule_is_modifiable(const struct rule *rule,
+                               enum ofputil_flow_mod_flags flag);
 
 /* OpenFlow. */
 static enum ofperr add_flow(struct ofproto *, struct ofconn *,
@@ -1143,6 +1144,24 @@ ofproto_get_n_tables(const struct ofproto *ofproto)
     return ofproto->n_tables;
 }
 
+/* Returns the number of Controller visible OpenFlow tables
+ * in 'ofproto'. This number will exclude Hidden tables.
+ * This funtion's return value should be less or equal to that of
+ * ofproto_get_n_tables() . */
+uint8_t
+ofproto_get_n_visible_tables(const struct ofproto *ofproto)
+{
+    uint8_t n = ofproto->n_tables;
+
+    /* Count only non-hidden tables in the number of tables.  (Hidden tables,
+     * if present, are always at the end.) */
+    while(n && (ofproto->tables[n - 1].flags & OFTABLE_HIDDEN)) {
+        n--;
+    }
+
+    return n;
+}
+
 /* Configures the OpenFlow table in 'ofproto' with id 'table_id' with the
  * settings from 's'.  'table_id' must be in the range 0 through the number of
  * OpenFlow tables in 'ofproto' minus 1, inclusive.
@@ -2741,19 +2760,27 @@ destroy_rule_executes(struct ofproto *ofproto)
 static bool
 ofproto_rule_is_hidden(const struct rule *rule)
 {
-    return rule->cr.priority > UINT16_MAX;
+    return (rule->cr.priority > UINT16_MAX);
 }
 
-static enum oftable_flags
-rule_get_flags(const struct rule *rule)
+static bool
+oftable_is_modifiable(const struct oftable *table,
+                      enum ofputil_flow_mod_flags flags)
 {
-    return rule->ofproto->tables[rule->table_id].flags;
+    if (flags & OFPUTIL_FF_NO_READONLY) {
+        return true;
+    }
+
+    return !(table->flags & OFTABLE_READONLY);
 }
 
 static bool
-rule_is_modifiable(const struct rule *rule)
+rule_is_modifiable(const struct rule *rule, enum ofputil_flow_mod_flags flags)
 {
-    return !(rule_get_flags(rule) & OFTABLE_READONLY);
+    const struct oftable *rule_table;
+
+    rule_table = &rule->ofproto->tables[rule->table_id];
+    return oftable_is_modifiable(rule_table, flags);
 }
 \f
 static enum ofperr
@@ -2771,26 +2798,14 @@ handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh)
     struct ofport *port;
     bool arp_match_ip;
     struct ofpbuf *b;
-    int n_tables;
-    int i;
 
     ofproto->ofproto_class->get_features(ofproto, &arp_match_ip,
                                          &features.actions);
     ovs_assert(features.actions & OFPUTIL_A_OUTPUT); /* sanity check */
 
-    /* Count only non-hidden tables in the number of tables.  (Hidden tables,
-     * if present, are always at the end.) */
-    n_tables = ofproto->n_tables;
-    for (i = 0; i < ofproto->n_tables; i++) {
-        if (ofproto->tables[i].flags & OFTABLE_HIDDEN) {
-            n_tables = i;
-            break;
-        }
-    }
-
     features.datapath_id = ofproto->datapath_id;
     features.n_buffers = pktbuf_capacity();
-    features.n_tables = n_tables;
+    features.n_tables = ofproto_get_n_visible_tables(ofproto);
     features.capabilities = (OFPUTIL_C_FLOW_STATS | OFPUTIL_C_TABLE_STATS |
                              OFPUTIL_C_PORT_STATS | OFPUTIL_C_QUEUE_STATS);
     if (arp_match_ip) {
@@ -3968,10 +3983,18 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
 
     table = &ofproto->tables[table_id];
 
-    if (table->flags & OFTABLE_READONLY) {
+    if (!oftable_is_modifiable(table, fm->flags)) {
         return OFPERR_OFPBRC_EPERM;
     }
 
+    if (!(fm->flags & OFPUTIL_FF_HIDDEN_FIELDS)) {
+        if (!match_has_default_hidden_fields(&fm->match)) {
+            VLOG_WARN_RL(&rl, "%s: (add_flow) only internal flows can set "
+                         "non-default values to hidden fields", ofproto->name);
+            return OFPERR_OFPBRC_EPERM;
+        }
+    }
+
     cls_rule_init(&cr, &fm->match, fm->priority);
 
     /* Transform "add" into "modify" if there's an existing identical flow. */
@@ -3980,7 +4003,7 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
     fat_rwlock_unlock(&table->cls.rwlock);
     if (rule) {
         cls_rule_destroy(&cr);
-        if (!rule_is_modifiable(rule)) {
+        if (!rule_is_modifiable(rule, fm->flags)) {
             return OFPERR_OFPBRC_EPERM;
         } else if (rule->pending) {
             return OFPROTO_POSTPONE;
@@ -4108,7 +4131,7 @@ modify_flows__(struct ofproto *ofproto, struct ofconn *ofconn,
 
         /* FIXME: Implement OFPFUTIL_FF_RESET_COUNTS */
 
-        if (rule_is_modifiable(rule)) {
+        if (rule_is_modifiable(rule, fm->flags)) {
             /* At least one rule is modifiable, don't report EPERM error. */
             error = 0;
         } else {
@@ -5786,12 +5809,12 @@ handle_group_mod(struct ofconn *ofconn, const struct ofp_header *oh)
     }
 }
 
-enum ofp_table_config
-table_get_config(const struct ofproto *ofproto, uint8_t table_id)
+enum ofproto_table_config
+ofproto_table_get_config(const struct ofproto *ofproto, uint8_t table_id)
 {
     unsigned int value;
     atomic_read(&ofproto->tables[table_id].config, &value);
-    return (enum ofp_table_config)value;
+    return (enum ofproto_table_config)value;
 }
 
 static enum ofperr
@@ -5842,7 +5865,7 @@ static enum ofperr
 handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
     OVS_EXCLUDED(ofproto_mutex)
 {
-    const struct ofp_header *oh = msg->data;
+    const struct ofp_header *oh = ofpbuf_data(msg);
     enum ofptype type;
     enum ofperr error;
 
@@ -6015,7 +6038,7 @@ handle_openflow(struct ofconn *ofconn, const struct ofpbuf *ofp_msg)
 {
     int error = handle_openflow__(ofconn, ofp_msg);
     if (error && error != OFPROTO_POSTPONE) {
-        ofconn_send_error(ofconn, ofp_msg->data, error);
+        ofconn_send_error(ofconn, ofpbuf_data(ofp_msg), error);
     }
     COVERAGE_INC(ofproto_recv_openflow);
     return error != OFPROTO_POSTPONE;
@@ -6678,7 +6701,7 @@ oftable_init(struct oftable *table)
     memset(table, 0, sizeof *table);
     classifier_init(&table->cls, flow_segment_u32s);
     table->max_flows = UINT_MAX;
-    atomic_init(&table->config, (unsigned int)OFPTC11_TABLE_MISS_CONTROLLER);
+    atomic_init(&table->config, (unsigned int)OFPROTO_TABLE_MISS_DEFAULT);
 }
 
 /* Destroys 'table', including its classifier and eviction groups.
index 309511c..ab51365 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -382,6 +382,7 @@ struct ofproto_table_settings {
 };
 
 int ofproto_get_n_tables(const struct ofproto *);
+uint8_t ofproto_get_n_visible_tables(const struct ofproto *);
 void ofproto_configure_table(struct ofproto *, int table_id,
                              const struct ofproto_table_settings *);
 
@@ -436,8 +437,24 @@ int ofproto_port_set_realdev(struct ofproto *, ofp_port_t vlandev_ofp_port,
 \f
 /* Table configuration */
 
-enum ofp_table_config table_get_config(const struct ofproto *,
-                                       uint8_t table_id);
+enum ofproto_table_config {
+    /* Send to controller. */
+    OFPROTO_TABLE_MISS_CONTROLLER = OFPTC11_TABLE_MISS_CONTROLLER,
+
+    /* Continue to the next table in the pipeline (OpenFlow 1.0 behavior). */
+    OFPROTO_TABLE_MISS_CONTINUE   = OFPTC11_TABLE_MISS_CONTINUE,
+
+    /* Drop the packet. */
+    OFPROTO_TABLE_MISS_DROP       = OFPTC11_TABLE_MISS_DROP,
+
+    /* The default miss behaviour for the OpenFlow version of the controller a
+     * packet_in message would be sent to..  For pre-OF1.3 controllers, send
+     * packet_in to controller.  For OF1.3+ controllers, drop. */
+    OFPROTO_TABLE_MISS_DEFAULT    = 3,
+};
+
+enum ofproto_table_config ofproto_table_get_config(const struct ofproto *,
+                                                   uint8_t table_id);
 
 #ifdef  __cplusplus
 }
index 001045a..336b810 100644 (file)
@@ -298,17 +298,20 @@ out:
 }
 
 static bool
-tnl_ecn_ok(const struct flow *base_flow, struct flow *flow)
+tnl_ecn_ok(const struct flow *base_flow, struct flow *flow,
+           struct flow_wildcards *wc)
 {
-    if (is_ip_any(base_flow)
-        && (flow->tunnel.ip_tos & IP_ECN_MASK) == IP_ECN_CE) {
-        if ((base_flow->nw_tos & IP_ECN_MASK) == IP_ECN_NOT_ECT) {
-            VLOG_WARN_RL(&rl, "dropping tunnel packet marked ECN CE"
-                         " but is not ECN capable");
-            return false;
-        } else {
-            /* Set the ECN CE value in the tunneled packet. */
-            flow->nw_tos |= IP_ECN_CE;
+    if (is_ip_any(base_flow)) {
+        wc->masks.nw_tos |= IP_ECN_MASK;
+        if ((flow->tunnel.ip_tos & IP_ECN_MASK) == IP_ECN_CE) {
+            if ((base_flow->nw_tos & IP_ECN_MASK) == IP_ECN_NOT_ECT) {
+                VLOG_WARN_RL(&rl, "dropping tunnel packet marked ECN CE"
+                             " but is not ECN capable");
+                return false;
+            } else {
+                /* Set the ECN CE value in the tunneled packet. */
+                flow->nw_tos |= IP_ECN_CE;
+            }
         }
     }
 
@@ -335,7 +338,7 @@ tnl_xlate_init(const struct flow *base_flow, struct flow *flow,
 
         memset(&wc->masks.pkt_mark, 0xff, sizeof wc->masks.pkt_mark);
 
-        if (!tnl_ecn_ok(base_flow, flow)) {
+        if (!tnl_ecn_ok(base_flow, flow, wc)) {
             return false;
         }
 
@@ -392,7 +395,7 @@ tnl_port_send(const struct ofport_dpif *ofport, struct flow *flow,
     }
 
     if (cfg->tos_inherit && is_ip_any(flow)) {
-        wc->masks.nw_tos = 0xff;
+        wc->masks.nw_tos = IP_DSCP_MASK;
         flow->tunnel.ip_tos = flow->nw_tos & IP_DSCP_MASK;
     } else {
         flow->tunnel.ip_tos = cfg->tos;
@@ -401,12 +404,12 @@ tnl_port_send(const struct ofport_dpif *ofport, struct flow *flow,
     /* ECN fields are always inherited. */
     if (is_ip_any(flow)) {
         wc->masks.nw_tos |= IP_ECN_MASK;
-    }
 
-    if ((flow->nw_tos & IP_ECN_MASK) == IP_ECN_CE) {
-        flow->tunnel.ip_tos |= IP_ECN_ECT_0;
-    } else {
-        flow->tunnel.ip_tos |= flow->nw_tos & IP_ECN_MASK;
+        if ((flow->nw_tos & IP_ECN_MASK) == IP_ECN_CE) {
+            flow->tunnel.ip_tos |= IP_ECN_ECT_0;
+        } else {
+            flow->tunnel.ip_tos |= flow->nw_tos & IP_ECN_MASK;
+        }
     }
 
     flow->tunnel.flags = (cfg->dont_fragment ? FLOW_TNL_F_DONT_FRAGMENT : 0)
diff --git a/ovsdb/SPECS b/ovsdb/SPECS
deleted file mode 100644 (file)
index 5656b9d..0000000
+++ /dev/null
@@ -1,1320 +0,0 @@
-         ===================================================
-          Open vSwitch Configuration Database Specification
-         ===================================================
-
-Basic Notation
---------------
-
-OVSDB uses JSON, as defined by RFC 4627, for its schema format and its
-wire protocol format.  The JSON implementation in Open vSwitch has the
-following limitations:
-
-     - Null bytes (\u0000) are not allowed in strings.
-
-     - Only UTF-8 encoding is supported.  (RFC 4627 also mentions
-       UTF-16BE, UTF-16LE, and UTF-32.)
-
-     - RFC 4627 says that names within a JSON object should be unique.
-       The Open vSwitch JSON parser discards all but the last value
-       for a name that is specified more than once.
-
-The descriptions below use the following shorthand notations for JSON
-values.  Additional notation is presented later.
-
-<string>
-
-    A JSON string.  Any Unicode string is allowed, as specified by RFC
-    4627.  Implementations may disallow null bytes.
-
-<id>
-
-    A JSON string matching [a-zA-Z_][a-zA-Z0-9_]*.
-
-    <id>s that begin with _ are reserved to the implementation and may
-    not be used by the user.
-
-<version>
-
-    A JSON string that contains a version number that matches
-    [0-9]+\.[0-9]+\.[0-9]+
-
-<boolean>
-
-    A JSON true or false value.
-
-<number>
-
-    A JSON number.
-
-<integer>
-
-    A JSON number with an integer value, within a certain range
-    (currently -2**63...+2**63-1).
-
-<json-value>
-
-    Any JSON value.
-
-<nonnull-json-value>
-
-    Any JSON value except null.
-
-<error>
-
-    A JSON object with the following members:
-
-        "error": <string>                       required
-        "details": <string>                     optional
-
-    The value of the "error" member is a short string, specified in
-    this document, that broadly indicates the class of the error.
-    Most "error" strings are specific to contexts described elsewhere
-    in this document, but the following "error" strings may appear in
-    any context where an <error> is permitted:
-
-    "error": "resources exhausted"
-
-        The operation requires more resources (memory, disk, CPU,
-        etc.) than are currently available to the database server.
-
-    "error": "I/O error"
-
-        Problems accessing the disk, network, or other required
-        resources prevented the operation from completing.
-
-    Database implementations may use "error" strings not specified
-    in this document to indicate errors that do not fit into any of
-    the specified categories.
-
-    Optionally, an <error> may include a "details" member, whose value
-    is a string that describes the error in more detail for the
-    benefit of a human user or administrator.  This document does not
-    specify the format or content of the "details" string.
-
-    An <error> may also have other members that describe the error in
-    more detail.  This document does not specify the names or values
-    of these members.
-
-Schema Format
--------------
-
-An Open vSwitch configuration database consists of a set of tables,
-each of which has a number of columns and zero or more rows.  A schema
-is represented by <database-schema>, as described below.
-
-<database-schema>
-
-    A JSON object with the following members:
-
-        "name": <id>                            required
-        "version": <version>                    required
-        "cksum": <string>                       optional
-        "tables": {<id>: <table-schema>, ...}   required
-
-    The "name" identifies the database as a whole.  It must be
-    provided to most JSON-RPC requests to identify the database being
-    operated on.  The value of "tables" is a JSON object whose names
-    are table names and whose values are <table-schema>s.
-
-    The "version" reports the version of the database schema.  Because
-    this is a recent addition to the schema format, OVSDB permits it
-    to be omitted, but future versions of OVSDB will require it to be
-    present.  Open vSwitch semantics for "version" are described in
-    ovs-vswitchd.conf.db(5).
-
-    The "cksum" optionally reports an implementation-defined checksum
-    for the database schema.
-
-<table-schema>
-
-    A JSON object with the following members:
-
-        "columns": {<id>: <column-schema>, ...}   required
-        "maxRows": <integer>                      optional
-        "isRoot": <boolean>                       optional
-        "indexes": [<column-set>*]                optional
-
-    The value of "columns" is a JSON object whose names are column
-    names and whose values are <column-schema>s.
-
-    Every table has the following columns whose definitions are not
-    included in the schema:
-
-        "_uuid": This column, which contains exactly one UUID value,
-        is initialized to a random value by the database engine when
-        it creates a row.  It is read-only, and its value never
-        changes during the lifetime of a row.
-
-        "_version": Like "_uuid", this column contains exactly one
-        UUID value, initialized to a random value by the database
-        engine when it creates a row, and it is read-only.  However,
-        its value changes to a new random value whenever any other
-        field in the row changes.  Furthermore, its value is
-        ephemeral: when the database is closed and reopened, or when
-        the database process is stopped and then started again, each
-        "_version" also changes to a new random value.
-
-    If "isRoot" is omitted or specified as false, then any given row
-    in the table may exist only when there is at least one reference
-    to it, with refType "strong", from a different row (in the same
-    table or a different table).  This is a "deferred" action:
-    unreferenced rows in the table are deleted just before transaction
-    commit.  If "isRoot" is specified as true, then rows in the table
-    exist independent of any references (they can be thought of as
-    part of the "root set" in a garbage collector).
-
-    For compatibility with schemas created before "isRoot" was
-    introduced, if "isRoot" is omitted or false in every
-    <table-schema> in a given <database-schema>, then every table is
-    part of the root set.
-
-    If "maxRows" is specified, as a positive integer, it limits the
-    maximum number of rows that may be present in the table.  This is
-    a "deferred" constraint, enforced only at transaction commit time
-    (see the "transact" request below).  If "maxRows" is not
-    specified, the size of the table is limited only by the resources
-    available to the database server.  "maxRows" constraints are
-    enforced after unreferenced rows are deleted from tables with a
-    false "isRoot".
-
-    If "indexes" is specified, it must be an array of zero or more
-    <column-set>s.  A <column-set> is an array of one or more strings,
-    each of which names a column.  Each <column-set> is a set of
-    columns whose values, taken together within any given row, must be
-    unique within the table.  This is a "deferred" constraint,
-    enforced only at transaction commit time, after unreferenced rows
-    are deleted and dangling weak references are removed.  Ephemeral
-    columns may not be part of indexes.
-
-<column-schema>
-
-    A JSON object with the following members:
-
-        "type": <type>                            required
-        "ephemeral": <boolean>                    optional
-        "mutable": <boolean>                      optional
-
-    The "type" specifies the type of data stored in this column.
-
-    If "ephemeral" is specified as true, then this column's values are
-    not guaranteed to be durable; they may be lost when the database
-    restarts.  A column whose type (either key or value) is a strong
-    reference to a table that is not part of the root set is always
-    durable, regardless of this value.  (Otherwise, restarting the
-    database could lose entire rows.)
-
-    If "mutable" is specified as false, then this column's values may
-    not be modified after they are initially set with the "insert"
-    operation.
-
-<type>
-
-    The type of a database column.  Either an <atomic-type> or a JSON
-    object that describes the type of a database column, with the
-    following members:
-
-        "key": <base-type>                 required
-        "value": <base-type>               optional
-        "min": <integer>                   optional
-        "max": <integer> or "unlimited"    optional
-
-    If "min" or "max" is not specified, each defaults to 1.  If "max"
-    is specified as "unlimited", then there is no specified maximum
-    number of elements, although the implementation will enforce some
-    limit.  After considering defaults, "min" must be exactly 0 or
-    exactly 1, "max" must be at least 1, and "max" must be greater
-    than or equal to "min".
-
-    If "min" and "max" are both 1 and "value" is not specified, the
-    type is the scalar type specified by "key".
-
-    If "min" is not 1 or "max" is not 1, or both, and "value" is not
-    specified, the type is a set of scalar type "key".
-
-    If "value" is specified, the type is a map from type "key" to type
-    "value".
-
-<base-type>
-
-    The type of a key or value in a database column.  Either an
-    <atomic-type> or a JSON object with the following members:
-
-        "type": <atomic-type>              required
-        "enum": <value>                    optional
-        "minInteger": <integer>            optional, integers only
-        "maxInteger": <integer>            optional, integers only
-        "minReal": <real>                  optional, reals only
-        "maxReal": <real>                  optional, reals only
-        "minLength": <integer>             optional, strings only
-        "maxLength": <integer>             optional, strings only
-        "refTable": <id>                   optional, uuids only
-        "refType": "strong" or "weak"      optional, only with "refTable"
-
-    An <atomic-type> by itself is equivalent to a JSON object with a
-    single member "type" whose value is the <atomic-type>.
-
-    "enum" may be specified as a <value> whose type is a set of one
-    or more values specified for the member "type".  If "enum" is
-    specified, then the valid values of the <base-type> are limited to
-    those in the <value>.
-
-    "enum" is mutually exclusive with the following constraints.
-
-    If "type" is "integer", then "minInteger" or "maxInteger" or both
-    may also be specified, restricting the valid integer range.  If
-    both are specified, then the maxInteger must be greater than or
-    equal to minInteger.
-
-    If "type" is "real", then "minReal" or "maxReal" or both may also
-    be specified, restricting the valid real range.  If both are
-    specified, then the maxReal must be greater than or equal to
-    minReal.
-
-    If "type" is "string", then "minLength" and "maxLength" or both
-    may be specified, restricting the valid length of value strings.
-    If both are specified, then maxLength must be greater than or
-    equal to minLength.  String length is measured in characters (not
-    bytes or UTF-16 code units).
-
-    If "type" is "uuid", then "refTable", if present, must be the name
-    of a table within this database.  If "refTable" is specified, then
-    "refType" may also be specified.  If "refTable" is set, the effect
-    depends on "refType":
-
-        - If "refType" is "strong" or if "refType" is omitted, the
-          allowed UUIDs are limited to UUIDs for rows in the named
-          table.
-
-        - If "refType" is "weak", then any UUIDs are allowed, but
-          UUIDs that do not correspond to rows in the named table will
-          be automatically deleted.
-
-    "refTable" constraints are "deferred" constraints: they are
-    enforced only at transaction commit time (see the "transact"
-    request below).  The other contraints on <base-type> are
-    "immediate", enforced immediately by each operation.
-
-<atomic-type>
-
-    One of the strings "integer", "real", "boolean", "string", or
-    "uuid", representing the specified scalar type.
-
-Wire Protocol
--------------
-
-The database wire protocol is implemented in JSON-RPC 1.0.  We
-encourage use of JSON-RPC over stream connections instead of JSON-RPC
-over HTTP, for these reasons:
-
-    * JSON-RPC is a peer-to-peer protocol, but HTTP is a client-server
-      protocol, which is a poor match.  Thus, JSON-RPC over HTTP
-      requires the client to periodically poll the server to receive
-      server requests.
-
-    * HTTP is more complicated than stream connections and doesn't
-      provide any corresponding advantage.
-
-    * The JSON-RPC specification for HTTP transport is incomplete.
-
-We are currently using TCP port 6632 for the database JSON-RPC
-connection, but future versions will switch to using IANA-assigned TCP
-port 6640.
-
-The database wire protocol consists of the following JSON-RPC methods:
-
-list_dbs
-........
-
-Request object members:
-
-    "method": "list_dbs"              required
-    "params": []                      required
-    "id": <nonnull-json-value>        required
-
-Response object members:
-
-    "result": [<db-name>, ...]
-    "error": null
-    "id": same "id" as request
-
-This operation retrieves an array whose elements are <db-name>s
-that name the databases that can be accessed over this JSON-RPC
-connection.
-
-get_schema
-..........
-
-Request object members:
-
-    "method": "get_schema"            required
-    "params": [<db-name>]             required
-    "id": <nonnull-json-value>        required
-
-Response object members:
-
-    "result": <database-schema>
-    "error": null
-    "id": same "id" as request
-
-This operation retrieves a <database-schema> that describes hosted
-database <db-name>.
-
-transact
-........
-
-Request object members:
-
-    "method": "transact"                  required
-    "params": [<db-name>, <operation>*]   required
-    "id": <nonnull-json-value>            required
-
-Response object members:
-
-    "result": [<object>*]
-    "error": null
-    "id": same "id" as request
-
-The "params" array for this method consists of a <db-name> that
-identifies the database to which the transaction applies, followed by
-zero or more JSON objects, each of which represents a single database
-operation.  The "Operations" section below describes the valid
-operations.
-
-The value of "id" must be unique among all in-flight transactions
-within the current JSON-RPC session.  Otherwise, the server may return
-a JSON-RPC error.
-
-The database server executes each of the specified operations in the
-specified order, except that if an operation fails, then the remaining
-operations are not executed.
-
-The set of operations is executed as a single atomic, consistent,
-isolated transaction.  The transaction is committed only if every
-operation succeeds.  Durability of the commit is not guaranteed unless
-the "commit" operation, with "durable" set to true, is included in the
-operation set (see below).
-
-Regardless of whether errors occur, the response is always a JSON-RPC
-response with null "error" and a "result" member that is an array with
-the same number of elements as "params".  Each element of the "result"
-array corresponds to the same element of the "params" array.  The
-"result" array elements may be interpreted as follows:
-
-    - A JSON object that does not contain an "error" member indicates
-      that the operation completed successfully.  The specific members
-      of the object are specified below in the descriptions of
-      individual operations.  Some operations do not produce any
-      results, in which case the object will have no members.
-
-    - An <error>, which indicates that the operation completed with an
-      error.
-
-    - A JSON null value indicates that the operation was not attempted
-      because a prior operation failed.
-
-In general, "result" contains some number of successful results,
-possibly followed by an error, in turn followed by enough JSON null
-values to match the number of elements in "params".  There is one
-exception: if all of the operations succeed, but the results cannot be
-committed, then "result" will have one more element than "params",
-with the additional element an <error>.  The possible "error" strings
-include at least the following:
-
-    "error": "referential integrity violation"
-
-        When the commit was attempted, a column's value referenced the
-        UUID for a row that did not exist in the table named by the
-        column's <base-type> key or value "refTable" that has a
-        "refType" of "strong".  (This can be caused by inserting a row
-        that references a nonexistent row, by deleting a row that is
-        still referenced by another row, by specifying the UUID for a
-        row in the wrong table, and other ways.)
-
-    "error": "constraint violation"
-
-        A column with a <base-type> key or value "refTable" whose
-        "refType" is "weak" became empty due to deletion(s) caused
-        because the rows that it referenced were deleted (or never
-        existed, if the column's row was inserted within the
-        transaction), and this column is not allowed to be empty
-        because its <type> has a "min" of 1.
-
-    "error": "constraint violation"
-
-        The number of rows in a table exceeds the maximum number
-        permitted by the table's "maxRows" value (see <table-schema>).
-
-    "error": "constraint violation"
-
-        Two or more rows in a table had the same values in the columns
-        that comprise an index.
-
-    "error": "resources exhausted"
-    "error": "I/O error"
-
-        As described in the definition of <error> above.
-
-If "params" contains one or more "wait" operations, then the
-transaction may take an arbitrary amount of time to complete.  The
-database implementation must be capable of accepting, executing, and
-replying to other transactions and other JSON-RPC requests while a
-transaction or transactions containing "wait" operations are
-outstanding on the same or different JSON-RPC sessions.
-
-The section "Notation for the Wire Protocol" below describes
-additional notation for use with the wire protocol.  After that, the
-"Operations" section describes each operation.
-
-cancel
-......
-
-Request object members:
-
-    "method": "cancel"                              required
-    "params": [the "id" for an outstanding request] required
-    "id": null                                      required
-
-Response object members:
-
-    <no response>
-
-This JSON-RPC notification instructs the database server to
-immediately complete or cancel the "transact" request whose "id" is
-the same as the notification's "params" value.
-
-If the "transact" request can be completed immediately, then the
-server sends a response in the form described for "transact", above.
-Otherwise, the server sends a JSON-RPC error response of the following
-form:
-
-    "result": null
-    "error": "canceled"
-    "id": the request "id" member
-
-The "cancel" notification itself has no reply.
-
-monitor
-.......
-
-Request object members:
-
-    "method": "monitor"                                       required
-    "params": [<db-name>, <json-value>, <monitor-requests>]   required
-    "id": <nonnull-json-value>                                required
-
-<monitor-requests> is an object that maps from a table name to an
-array of <monitor-request> objects.  For backward compatibility, a
-single <monitor-request> may be used instead of an array; it is
-treated as a single-element array.
-
-Each <monitor-request> is an object with the following members:
-
-    "columns": [<column>*]            optional
-    "select": <monitor-select>        optional
-
-<monitor-select> is an object with the following members:
-
-    "initial": <boolean>              optional
-    "insert": <boolean>               optional
-    "delete": <boolean>               optional
-    "modify": <boolean>               optional
-
-Response object members:
-
-    "result": <table-updates>
-    "error": null
-    "id": same "id" as request
-
-This JSON-RPC request enables a client to replicate tables or subsets
-of tables within database <db-name>.  Each element of
-<monitor-requests> specifies a table to be replicated.  The JSON-RPC
-response to the "monitor" includes the initial contents of each table,
-unless disabled (see below).  Afterward, when changes to those tables
-are committed, the changes are automatically sent to the client using
-the "update" monitor notification.  This monitoring persists until the
-JSON-RPC session terminates or until the client sends a
-"monitor_cancel" JSON-RPC request.
-
-Each <monitor-request> describes how to monitor columns in a table:
-
-    The circumstances in which an "update" notification is sent for a
-    row within the table are determined by <monitor-select>:
-
-        If "initial" is omitted or true, every row in the table is
-        sent as part of the reply to the "monitor" request.
-
-        If "insert" is omitted or true, "update" notifications are
-        sent for rows newly inserted into the table.
-
-        If "delete" is omitted or true, "update" notifications are
-        sent for rows deleted from the table.
-
-        If "modify" is omitted or true, "update" notifications are
-        sent whenever when a row in the table is modified.
-
-    The "columns" member specifies the columns whose values are
-    monitored.  It must not contain duplicates.  If "columns" is
-    omitted, all columns in the table, except for "_uuid", are
-    monitored.
-
-If there is more than one <monitor-request> in an array of them, then
-each <monitor-request> in the array should specify both "columns" and
-"select", and the "columns" must be non-overlapping sets.
-
-The "result" in the JSON-RPC response to the "monitor" request is a
-<table-updates> object (see below) that contains the contents of the
-tables for which "initial" rows are selected.  If no tables' initial
-contents are requested, then "result" is an empty object.
-
-update
-......
-
-Notification object members:
-
-    "method": "update"
-    "params": [<json-value>, <table-updates>]
-    "id": null
-
-The <json-value> in "params" is the same as the value passed as the
-<json-value> in "params" for the "monitor" request.
-
-<table-updates> is an object that maps from a table name to a
-<table-update>.
-
-A <table-update> is an object that maps from the row's UUID (as a
-36-byte string) to a <row-update> object.
-
-A <row-update> is an object with the following members:
-
-    "old": <row>         present for "delete" and "modify" updates
-    "new": <row>         present for "initial", "insert", and "modify" updates
-
-This JSON-RPC notification is sent from the server to the client to
-tell it about changes to a monitored table (or the initial state of a
-modified table).  Each table in which one or more rows has changed (or
-whose initial view is being presented) is represented in "updates".
-Each row that has changed (or whose initial view is being presented)
-is represented in its <table-update> as a member with its name taken
-from the row's _uuid member.  The corresponding value is a
-<row-update>:
-
-    The "old" member is present for "delete" and "modify" updates.
-    For "delete" updates, each monitored column is included.  For
-    "modify" updates, the prior value of each monitored column whose
-    value has changed is included (monitored columns that have not
-    changed are represented in "new").
-
-    The "new" member is present for "initial", "insert", and "modify"
-    updates.  For "initial" and "insert" updates, each monitored
-    column is included.  For "modify" updates, the new value of each
-    monitored column is included.
-
-monitor_cancel
-..............
-
-Request object members:
-
-    "method": "monitor_cancel"                              required
-    "params": [<json-value>]                                required
-    "id": <nonnull-json-value>                              required
-
-Response object members:
-
-    "result": {}
-    "error": null
-    "id": the request "id" member
-
-Cancels the ongoing table monitor request, identified by the
-<json-value> in "params" matching the <json-value> in "params" for an
-ongoing "monitor" request.  No more "update" messages will be sent for
-this table monitor.
-
-lock operations
-...............
-
-Request object members:
-
-    "method": "lock", "steal", or "unlock"          required
-    "params": [<id>]                                required
-    "id": <nonnull-json-value>                      required
-
-Response object members:
-
-    "result": {"locked": <boolean>}     for "lock"
-    "result": {"locked": true}          for "steal"
-    "result": {}                        for "unlock"
-    "error": null
-    "id": same "id" as request
-
-Performs an operation on a "lock" object.  The database server
-supports an arbitrary number of locks, each of which is identified by
-a client-defined id (given in "params").  At any given time, each lock
-may have at most one owner.
-
-The locking operation depends on "method":
-
-    - "lock": The database will assign this client ownership of the
-      lock as soon as it becomes available.  When multiple clients
-      request the same lock, they will receive it in first-come, first
-      served order.
-
-    - "steal": The database immediately assigns this client ownership
-      of the lock.  If there is an existing owner, it loses ownership.
-
-    - "unlock": If the client owns the lock, releases it.  If the
-      client is waiting to obtain the lock, cancels the request and
-      stops waiting.
-
-      (Closing or otherwise disconnecting a database client connection
-      unlocks all of its locks.)
-
-For any given lock, the client must alternate "lock" or "steal"
-operations with "unlock" operations.  That is, if the previous
-operation on a lock was "lock" or "steal", it must be followed by an
-"unlock" operation, and vice versa.
-
-For a "lock" operation, the "locked" member in the response object is
-true if the lock has already been acquired, false if another client
-holds the lock and the client's request for it was queued.  In the
-latter case, the client will be notified later with a "locked" message
-when acquisition succeeds.
-
-These requests complete and send a response quickly, without waiting.
-The "locked" and "stolen" notifications (see below) report
-asynchronous changes to ownership.
-
-The scope of a lock is a database server, not a database hosted by
-that server.  A naming convention, such as "<db-name>__<lock-name>",
-can effectively limit the scope of a lock to a particular database.
-
-locked
-......
-
-Notification object members:
-
-    "method": "locked"
-    "params": [<id>]
-    "id": null
-
-Notifies the client that a "lock" operation that it previously
-requested has succeeded.  The client now owns the lock named in
-"params".
-
-The database server sends this notification after the reply to the
-corresponding "lock" request (but only if the "locked" member of the
-response was false), and before the reply to the client's subsequent
-"unlock" request.
-
-stolen
-......
-
-Notification object members:
-
-    "method": "stolen"
-    "params": [<id>]
-    "id": null
-
-Notifies the client that owns a lock that another database client has
-stolen ownership of the lock.  The client no longer owns the lock
-named in "params".  The client must still issue an "unlock" request
-before performing any subsequent "lock" or "steal" operation on the
-lock.
-
-If the client originally obtained the lock through a "lock" request,
-then it will automatically regain the lock later after the client that
-stole it releases it.  (The database server will send the client a
-"locked" notification at that point to let it know.)
-
-If the client originally obtained the lock through a "steal" request,
-the database server won't automatically reassign it ownership of the
-lock when it later becomes available.  To regain ownership, the client
-must "unlock" and then "lock" or "steal" the lock again.
-
-echo
-....
-
-Request object members:
-
-    "method": "echo"                                required
-    "params": JSON array with any contents          required
-    "id": <json-value>                              required
-
-Response object members:
-
-    "result": same as "params"
-    "error": null
-    "id": the request "id" member
-
-Both the JSON-RPC client and the server must implement this request.
-
-This JSON-RPC request and response can be used to implement connection
-keepalives, by allowing the server to check that the client is still
-there or vice versa.
-
-
-Notation for the Wire Protocol
-------------------------------
-
-<db-name>
-
-    An <id> that names a database.  The valid <db-name>s can be
-    obtained using a "list-db" request.  The <db-name> is taken from
-    the "name" member of <database-schema>.
-
-<table>
-
-    An <id> that names a table.
-
-<column>
-
-    An <id> that names a table column.
-
-<row>
-
-    A JSON object that describes a table row or a subset of a table
-    row.  Each member is the name of a table column paired with the
-    <value> of that column.
-
-<value>
-
-    A JSON value that represents the value of a column in a table row,
-    one of <atom>, a <set>, or a <map>.
-
-<atom>
-
-    A JSON value that represents a scalar value for a column, one of
-    <string>, <number>, <boolean>, <uuid>, <named-uuid>.
-
-<set>
-
-    Either an <atom>, representing a set with exactly one element, or
-    a 2-element JSON array that represents a database set value.  The
-    first element of the array must be the string "set" and the second
-    element must be an array of zero or more <atom>s giving the values
-    in the set.  All of the <atom>s must have the same type.
-
-<map>
-
-    A 2-element JSON array that represents a database map value.  The
-    first element of the array must be the string "map" and the second
-    element must be an array of zero or more <pair>s giving the values
-    in the map.  All of the <pair>s must have the same key and value
-    types.
-
-    (JSON objects are not used to represent <map> because JSON only
-    allows string names in an object.)
-
-<pair>
-
-    A 2-element JSON array that represents a pair within a database
-    map.  The first element is an <atom> that represents the key, the
-    second element is an <atom> that represents the value.
-
-<uuid>
-
-    A 2-element JSON array that represents a UUID.  The first element
-    of the array must be the string "uuid" and the second element must
-    be a 36-character string giving the UUID in the format described
-    by RFC 4122.  For example, the following <uuid> represents the
-    UUID 550e8400-e29b-41d4-a716-446655440000:
-
-        ["uuid", "550e8400-e29b-41d4-a716-446655440000"]
-
-<named-uuid>
-
-    A 2-element JSON array that represents the UUID of a row inserted
-    in an "insert" operation within the same transaction.  The first
-    element of the array must be the string "named-uuid" and the
-    second element should be the <id> specified as the "uuid-name"
-    for an "insert" operation within the same transaction.  For
-    example, if an "insert" operation within this transaction
-    specifies a "uuid-name" of "myrow", the following <named-uuid>
-    represents the UUID created by that operation:
-
-        ["named-uuid", "myrow"]
-
-    A <named-uuid> may be used anywhere a <uuid> is valid.
-
-<condition>
-
-    A 3-element JSON array of the form [<column>, <function>,
-    <value>] that represents a test on a column value.
-
-    Except as otherwise specified below, <value> must have the same
-    type as <column>.
-
-    The meaning depends on the type of <column>:
-
-        integer
-        real
-
-            <function> must be "<", "<=", "==", "!=", ">=", ">",
-            "includes", or "excludes".
-
-            The test is true if the column's value satisfies the
-            relation <function> <value>, e.g. if the column has value
-            1 and <value> is 2, the test is true if <function> is "<",
-            "<=" or "!=", but not otherwise.
-
-            "includes" is equivalent to "=="; "excludes" is equivalent
-            to "!=".
-
-        boolean
-        string
-        uuid
-
-            <function> must be "!=", "==", "includes", or "excludes".
-
-            If <function> is "==" or "includes", the test is true if
-            the column's value equals <value>.  If <function> is "!="
-            or "excludes", the test is inverted.
-
-        set
-        map
-
-            <function> must be "!=", "==", "includes", or "excludes".
-
-            If <function> is "==", the test is true if the column's
-            value contains exactly the same values (for sets) or pairs
-            (for maps).  If <function> is "!=", the test is inverted.
-
-            If <function> is "includes", the test is true if the
-            column's value contains all of the values (for sets) or
-            pairs (for maps) in <value>.  The column's value may also
-            contain other values or pairs.
-
-            If <function> is "excludes", the test is true if the
-            column's value does not contain any of the values (for
-            sets) or pairs (for maps) in <value>.  The column's value
-            may contain other values or pairs not in <value>.
-
-            If <function> is "includes" or "excludes", then the
-            required type of <value> is slightly relaxed, in that it
-            may have fewer than the minimum number of elements
-            specified by the column's type.  If <function> is
-            "excludes", then the required type is additionally relaxed
-            in that <value> may have more than the maximum number of
-            elements specified by the column's type.
-
-<function>
-
-    One of "<", "<=", "==", "!=", ">=", ">", "includes", "excludes".
-
-<mutation>
-
-    A 3-element JSON array of the form [<column>, <mutator>, <value>]
-    that represents a change to a column value.
-
-    Except as otherwise specified below, <value> must have the same
-    type as <column>.
-
-    The meaning depends on the type of <column>:
-
-        integer
-        real
-
-            <mutator> must be "+=", "-=", "*=", "/=" or (integer only)
-            "%=".  The value of <column> is changed to the sum,
-            difference, product, quotient, or remainder, respectively,
-            of <column> and <value>.
-
-            Constraints on <column> are ignored when parsing <value>.
-
-        boolean
-        string
-        uuid
-
-            No valid <mutator>s are currently defined for these types.
-
-        set
-
-            Any <mutator> valid for the set's element type may be
-            applied to the set, in which case the mutation is applied
-            to each member of the set individually.  <value> must be a
-            scalar value of the same type as the set's element type,
-            except that contraints are ignored.
-
-            If <mutator> is "insert", then each of the values in the
-            set in <value> is added to <column> if it is not already
-            present.  The required type of <value> is slightly
-            relaxed, in that it may have fewer than the minimum number
-            of elements specified by the column's type.
-
-            If <mutator> is "delete", then each of the values in the
-            set in <value> is removed from <column> if it is present
-            there.  The required type is slightly relaxed in that
-            <value> may have more or less than the maximum number of
-            elements specified by the column's type.
-
-        map
-
-            <mutator> must be "insert" or "delete".
-
-            If <mutator> is "insert", then each of the key-value pairs
-            in the map in <value> is added to <column> only if its key
-            is not already present.  The required type of <value> is
-            slightly relaxed, in that it may have fewer than the
-            minimum number of elements specified by the column's type.
-
-            If <mutator> is "delete", then <value> may have the same
-            type as <column> (a map type) or it may be a set whose
-            element type is the same as <column>'s key type:
-
-                - If <value> is a map, the mutation deletes each
-                  key-value pair in <column> whose key and value equal
-                  one of the key-value pairs in <value>.
-
-                - If <value> is a set, the mutation deletes each
-                  key-value pair in <column> whose key equals one of
-                  the values in <value>.
-
-            For "delete", <value> may have any number of elements,
-            regardless of restrictions on the number of elements in
-            <column>.
-
-<mutator>
-
-    One of "+=", "-=", "*=", "/=", "%=", "insert", "delete".
-
-Operations
-----------
-
-Each of the available operations is described below.
-
-insert
-......
-
-Request object members:
-
-    "op": "insert"          required
-    "table": <table>        required
-    "row": <row>            required
-    "uuid-name": <id>       optional
-
-Result object members:
-
-    "uuid": <uuid>
-
-Semantics:
-
-    Inserts "row" into "table".
-
-    If "row" does not specify values for all the columns in "table",
-    those columns receive default values.  The default value for a
-    column depends on its type.  The default for a column whose <type>
-    specifies a "min" of 0 is an empty set or empty map.  Otherwise,
-    the default is a single value or a single key-value pair, whose
-    value(s) depend on its <atomic-type>:
-
-        - "integer" or "real": 0
-
-        - "boolean": false
-
-        - "string": "" (the empty string)
-
-        - "uuid": 00000000-0000-0000-0000-000000000000
-
-    The new row receives a new, randomly generated UUID.
-
-    If "uuid-name" is supplied, then it is an error if <id> is not
-    unique among the "uuid-name"s supplied on all the "insert"
-    operations within this transaction.
-
-    The UUID for the new row is returned as the "uuid" member of the
-    result.
-
-Errors:
-
-    "error": "duplicate uuid-name"
-
-        The same "uuid-name" appears on another "insert" operation
-        within this transaction.
-
-    "error": "constraint violation"
-
-        One of the values in "row" does not satisfy the immediate
-        constraints for its column's <base-type>.  This error will
-        occur for columns that are not explicitly set by "row" if the
-        default value does not satisfy the column's constraints.
-
-select
-......
-
-Request object members:
-
-    "op": "select"                required
-    "table": <table>              required
-    "where": [<condition>*]       required
-    "columns": [<column>*]        optional
-
-Result object members:
-
-    "rows": [<row>*]
-
-Semantics:
-
-    Searches "table" for rows that match all the conditions specified
-    in "where".  If "where" is an empty array, every row in "table" is
-    selected.
-
-    The "rows" member of the result is an array of objects.  Each
-    object corresponds to a matching row, with each column
-    specified in "columns" as a member, the column's name as the
-    member name and its value as the member value.  If "columns"
-    is not specified, all the table's columns are included.  If
-    two rows of the result have the same values for all included
-    columns, only one copy of that row is included in "rows".
-    Specifying "_uuid" within "columns" will avoid dropping
-    duplicates, since every row has a unique UUID.
-
-    The ordering of rows within "rows" is unspecified.
-
-update
-......
-
-Request object members:
-
-    "op": "update"                required
-    "table": <table>              required
-    "where": [<condition>*]       required
-    "row": <row>                  required
-
-Result object members:
-
-    "count": <integer>
-
-Semantics:
-
-    Updates rows in a table.
-
-    Searches "table" for rows that match all the conditions
-    specified in "where".  For each matching row, changes the
-    value of each column specified in "row" to the value for that
-    column specified in "row".
-
-    The "_uuid" and "_version" columns of a table may not be directly
-    updated with this operation.  Columns designated read-only in the
-    schema also may not be updated.
-
-    The "count" member of the result specifies the number of rows
-    that matched.
-
-Errors:
-
-    "error": "constraint violation"
-
-        One of the values in "row" does not satisfy the immediate
-        constraints for its column's <base-type>.
-mutate
-......
-
-Request object members:
-
-    "op": "mutate"                required
-    "table": <table>              required
-    "where": [<condition>*]       required
-    "mutations": [<mutation>*]    required
-
-Result object members:
-
-    "count": <integer>
-
-Semantics:
-
-    Mutates rows in a table.
-
-    Searches "table" for rows that match all the conditions specified
-    in "where".  For each matching row, mutates its columns as
-    specified by each <mutation> in "mutations", in the order
-    specified.
-
-    The "_uuid" and "_version" columns of a table may not be directly
-    modified with this operation.  Columns designated read-only in the
-    schema also may not be updated.
-
-    The "count" member of the result specifies the number of rows
-    that matched.
-
-Errors:
-
-    "error": "domain error"
-
-        The result of the mutation is not mathematically defined,
-        e.g. division by zero.
-
-    "error": "range error"
-
-        The result of the mutation is not representable within the
-        database's format, e.g. an integer result outside the range
-        INT64_MIN...INT64_MAX or a real result outside the range
-        -DBL_MAX...DBL_MAX.
-
-    "error": "constraint violation"
-
-        The mutation caused the column's value to violate a
-        constraint, e.g. it caused a column to have more or fewer
-        values than are allowed, an arithmetic operation caused a set
-        or map to have duplicate elements, or it violated a constraint
-        specified by a column's <base-type>.
-
-delete
-......
-
-Request object members:
-
-    "op": "delete"                required
-    "table": <table>              required
-    "where": [<condition>*]       required
-
-Result object members:
-
-    "count": <integer>
-
-Semantics:
-
-    Deletes all the rows from "table" that match all the conditions
-    specified in "where".
-
-    The "count" member of the result specifies the number of deleted
-    rows.
-
-wait
-....
-
-Request object members:
-
-    "op": "wait"                        required
-    "timeout": <integer>                optional
-    "table": <table>                    required
-    "where": [<condition>*]             required
-    "columns": [<column>*]              required
-    "until": "==" or "!="               required
-    "rows": [<row>*]                    required
-
-Result object members:
-
-    none
-
-Semantics:
-
-    Waits until a condition becomes true.
-
-    If "until" is "==", checks whether the query on "table" specified
-    by "where" and "columns", which is evaluated in the same way as
-    specified for "select", returns the result set specified by
-    "rows".  If it does, then the operation completes successfully.
-    Otherwise, the entire transaction rolls back.  It is automatically
-    restarted later, after a change in the database makes it possible
-    for the operation to succeed.  The client will not receive a
-    response until the operation permanently succeeds or fails.
-
-    If "until" is "!=", the sense of the test is negated.  That is, as
-    long as the query on "table" specified by "where" and "columns"
-    returns "rows", the transaction will be rolled back and restarted
-    later.
-
-    If "timeout" is specified, then the transaction aborts after the
-    specified number of milliseconds.  The transaction is guaranteed
-    to be attempted at least once before it aborts.  A "timeout" of 0
-    will abort the transaction on the first mismatch.
-
-Errors:
-
-    "error": "not supported"
-
-        One or more of the columns in this table do not support
-        triggers.  This error will not occur if "timeout" is 0.
-
-    "error": "timed out"
-
-        The "timeout" was reached before the transaction was able to
-        complete.
-
-commit
-......
-
-Request object members:
-
-    "op": "commit"                      required
-    "durable": <boolean>                required
-
-Result object members:
-
-    none
-
-Semantics:
-
-    If "durable" is specified as true, then the transaction, if it
-    commits, will be stored durably (to disk) before the reply is sent
-    to the client.
-
-Errors:
-
-    "error": "not supported"
-
-        When "durable" is true, this database implementation does not
-        support durable commits.
-
-abort
-.....
-
-Request object members:
-
-    "op": "abort"                      required
-
-Result object members:
-
-    (never succeeds)
-
-Semantics:
-
-    Aborts the transaction with an error.  This may be useful for
-    testing.
-
-Errors:
-
-    "error": "aborted"
-
-        This operation always fails with this error.
-
-comment
-.......
-
-
-Request object members:
-
-    "op": "comment"                    required
-    "comment": <string>                required
-
-Result object members:
-
-    none
-
-Semantics:
-
-    Provides information to a database administrator on the purpose of
-    a transaction.  The OVSDB server, for example, adds comments in
-    transactions that modify the database to the database journal.
-
-assert
-......
-
-Request object members:
-
-    "op": "assert"                     required
-    "lock": <id>                       required
-
-Result object members:
-
-    none
-
-Semantics:
-
-    If the client does not own the lock named <string>, aborts the
-    transaction.
-
-Errors:
-
-    "error": "not owner"
-
-        The client does not own the named lock.
index dfb900a..404848e 100644 (file)
@@ -65,7 +65,6 @@ DISTCLEANFILES += ovsdb/ovsdb-server.1
 MAN_ROOTS += ovsdb/ovsdb-server.1.in
 
 # ovsdb-idlc
-EXTRA_DIST += ovsdb/SPECS
 noinst_SCRIPTS += ovsdb/ovsdb-idlc
 EXTRA_DIST += ovsdb/ovsdb-idlc.in
 MAN_ROOTS += ovsdb/ovsdb-idlc.1
index 4758442..cfaa656 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@
 #include "ovsdb-error.h"
 #include "ovsdb-parser.h"
 #include "ovsdb.h"
+#include "poll-loop.h"
 #include "reconnect.h"
 #include "row.h"
 #include "server.h"
@@ -62,6 +63,8 @@ static bool ovsdb_jsonrpc_session_get_status(
     struct ovsdb_jsonrpc_remote_status *);
 static void ovsdb_jsonrpc_session_unlock_all(struct ovsdb_jsonrpc_session *);
 static void ovsdb_jsonrpc_session_unlock__(struct ovsdb_lock_waiter *);
+static void ovsdb_jsonrpc_session_send(struct ovsdb_jsonrpc_session *,
+                                       struct jsonrpc_msg *);
 
 /* Triggers. */
 static void ovsdb_jsonrpc_trigger_create(struct ovsdb_jsonrpc_session *,
@@ -82,8 +85,8 @@ static struct jsonrpc_msg *ovsdb_jsonrpc_monitor_cancel(
     struct json_array *params,
     const struct json *request_id);
 static void ovsdb_jsonrpc_monitor_remove_all(struct ovsdb_jsonrpc_session *);
-static size_t ovsdb_jsonrpc_monitor_json_length_all(
-    struct ovsdb_jsonrpc_session *);
+static void ovsdb_jsonrpc_monitor_flush_all(struct ovsdb_jsonrpc_session *);
+static bool ovsdb_jsonrpc_monitor_needs_flush(struct ovsdb_jsonrpc_session *);
 \f
 /* JSON-RPC database server. */
 
@@ -364,8 +367,6 @@ struct ovsdb_jsonrpc_session {
     struct list node;           /* Element in remote's sessions list. */
     struct ovsdb_session up;
     struct ovsdb_jsonrpc_remote *remote;
-    size_t backlog_threshold;   /* See ovsdb_jsonrpc_session_run(). */
-    size_t reply_backlog;
 
     /* Triggers. */
     struct hmap triggers;       /* Hmap of "struct ovsdb_jsonrpc_trigger"s. */
@@ -402,8 +403,6 @@ ovsdb_jsonrpc_session_create(struct ovsdb_jsonrpc_remote *remote,
     list_push_back(&remote->sessions, &s->node);
     hmap_init(&s->triggers);
     hmap_init(&s->monitors);
-    s->reply_backlog = 0;
-    s->backlog_threshold = 1024 * 1024;
     s->js = js;
     s->js_seqno = jsonrpc_session_get_seqno(js);
 
@@ -432,8 +431,6 @@ ovsdb_jsonrpc_session_close(struct ovsdb_jsonrpc_session *s)
 static int
 ovsdb_jsonrpc_session_run(struct ovsdb_jsonrpc_session *s)
 {
-    size_t backlog;
-
     jsonrpc_session_run(s->js);
     if (s->js_seqno != jsonrpc_session_get_seqno(s->js)) {
         s->js_seqno = jsonrpc_session_get_seqno(s->js);
@@ -444,9 +441,12 @@ ovsdb_jsonrpc_session_run(struct ovsdb_jsonrpc_session *s)
 
     ovsdb_jsonrpc_trigger_complete_done(s);
 
-    backlog = jsonrpc_session_get_backlog(s->js);
-    if (!backlog) {
-        struct jsonrpc_msg *msg = jsonrpc_session_recv(s->js);
+    if (!jsonrpc_session_get_backlog(s->js)) {
+        struct jsonrpc_msg *msg;
+
+        ovsdb_jsonrpc_monitor_flush_all(s);
+
+        msg = jsonrpc_session_recv(s->js);
         if (msg) {
             if (msg->type == JSONRPC_REQUEST) {
                 ovsdb_jsonrpc_session_got_request(s, msg);
@@ -460,39 +460,6 @@ ovsdb_jsonrpc_session_run(struct ovsdb_jsonrpc_session *s)
                 jsonrpc_msg_destroy(msg);
             }
         }
-        s->reply_backlog = jsonrpc_session_get_backlog(s->js);
-    } else if (backlog > s->reply_backlog + s->backlog_threshold) {
-        /* We have a lot of data queued to send to the client.  The data is
-         * likely to be mostly monitor updates.  It is unlikely that the
-         * monitor updates are due to transactions by 's', because we will not
-         * let 's' make any more transactions until it drains its backlog to 0
-         * (see previous 'if' case).  So the monitor updates are probably due
-         * to transactions made by database clients other than 's'.  We can't
-         * fix that by preventing 's' from executing more transactions.  We
-         * could fix it by preventing every client from executing transactions,
-         * but then one slow or hung client could prevent other clients from
-         * doing useful work.
-         *
-         * Our solution is to cap the maximum backlog to O(1) in the amount of
-         * data in the database.  If the backlog exceeds that amount, then we
-         * disconnect the client.  When it reconnects, it can fetch the entire
-         * contents of the database using less data than was previously
-         * backlogged. */
-        size_t monitor_length;
-
-        monitor_length = ovsdb_jsonrpc_monitor_json_length_all(s);
-        if (backlog > s->reply_backlog + monitor_length * 2) {
-            VLOG_INFO("%s: %"PRIuSIZE" bytes backlogged but a complete replica "
-                      "would only take %"PRIuSIZE" bytes, disconnecting",
-                      jsonrpc_session_get_name(s->js),
-                      backlog - s->reply_backlog, monitor_length);
-            jsonrpc_session_force_reconnect(s->js);
-        } else {
-            /* The backlog is not unreasonably big.  Only check again after it
-             * becomes much bigger. */
-            s->backlog_threshold = 2 * MAX(s->backlog_threshold * 2,
-                                           monitor_length);
-        }
     }
     return jsonrpc_session_is_alive(s->js) ? 0 : ETIMEDOUT;
 }
@@ -524,7 +491,11 @@ ovsdb_jsonrpc_session_wait(struct ovsdb_jsonrpc_session *s)
 {
     jsonrpc_session_wait(s->js);
     if (!jsonrpc_session_get_backlog(s->js)) {
-        jsonrpc_session_recv_wait(s->js);
+        if (ovsdb_jsonrpc_monitor_needs_flush(s)) {
+            poll_immediate_wake();
+        } else {
+            jsonrpc_session_recv_wait(s->js);
+        }
     }
 }
 
@@ -740,7 +711,7 @@ ovsdb_jsonrpc_session_notify(struct ovsdb_session *session,
 
     s = CONTAINER_OF(session, struct ovsdb_jsonrpc_session, up);
     params = json_array_create_1(json_string_create(lock_name));
-    jsonrpc_session_send(s->js, jsonrpc_create_notify(method, params));
+    ovsdb_jsonrpc_session_send(s, jsonrpc_create_notify(method, params));
 }
 
 static struct jsonrpc_msg *
@@ -915,7 +886,7 @@ ovsdb_jsonrpc_session_got_request(struct ovsdb_jsonrpc_session *s,
 
     if (reply) {
         jsonrpc_msg_destroy(request);
-        jsonrpc_session_send(s->js, reply);
+        ovsdb_jsonrpc_session_send(s, reply);
     }
 }
 
@@ -943,6 +914,14 @@ ovsdb_jsonrpc_session_got_notify(struct ovsdb_jsonrpc_session *s,
     }
     jsonrpc_msg_destroy(request);
 }
+
+static void
+ovsdb_jsonrpc_session_send(struct ovsdb_jsonrpc_session *s,
+                           struct jsonrpc_msg *msg)
+{
+    ovsdb_jsonrpc_monitor_flush_all(s);
+    jsonrpc_session_send(s->js, msg);
+}
 \f
 /* JSON-RPC database server triggers.
  *
@@ -970,7 +949,7 @@ ovsdb_jsonrpc_trigger_create(struct ovsdb_jsonrpc_session *s, struct ovsdb *db,
 
         msg = jsonrpc_create_error(json_string_create("duplicate request ID"),
                                    id);
-        jsonrpc_session_send(s->js, msg);
+        ovsdb_jsonrpc_session_send(s, msg);
         json_destroy(id);
         json_destroy(params);
         return;
@@ -1021,7 +1000,7 @@ ovsdb_jsonrpc_trigger_complete(struct ovsdb_jsonrpc_trigger *t)
             reply = jsonrpc_create_error(json_string_create("canceled"),
                                          t->id);
         }
-        jsonrpc_session_send(s->js, reply);
+        ovsdb_jsonrpc_session_send(s, reply);
     }
 
     json_destroy(t->id);
@@ -1065,6 +1044,14 @@ struct ovsdb_jsonrpc_monitor_column {
     enum ovsdb_jsonrpc_monitor_selection select;
 };
 
+/* A row that has changed in a monitored table. */
+struct ovsdb_jsonrpc_monitor_row {
+    struct hmap_node hmap_node; /* In ovsdb_jsonrpc_monitor_table.changes. */
+    struct uuid uuid;           /* UUID of row that changed. */
+    struct ovsdb_datum *old;    /* Old data, NULL for an inserted row. */
+    struct ovsdb_datum *new;    /* New data, NULL for a deleted row. */
+};
+
 /* A particular table being monitored. */
 struct ovsdb_jsonrpc_monitor_table {
     const struct ovsdb_table *table;
@@ -1076,6 +1063,10 @@ struct ovsdb_jsonrpc_monitor_table {
     /* Columns being monitored. */
     struct ovsdb_jsonrpc_monitor_column *columns;
     size_t n_columns;
+
+    /* Contains 'struct ovsdb_jsonrpc_monitor_row's for rows that have been
+     * updated but not yet flushed to the jsonrpc connection. */
+    struct hmap changes;
 };
 
 /* A collection of tables being monitored. */
@@ -1096,8 +1087,6 @@ struct ovsdb_jsonrpc_monitor *ovsdb_jsonrpc_monitor_find(
 static void ovsdb_jsonrpc_monitor_destroy(struct ovsdb_replica *);
 static struct json *ovsdb_jsonrpc_monitor_get_initial(
     const struct ovsdb_jsonrpc_monitor *);
-static size_t ovsdb_jsonrpc_monitor_json_length(
-    const struct ovsdb_jsonrpc_monitor *);
 
 static bool
 parse_bool(struct ovsdb_parser *parser, const char *name, bool default_value)
@@ -1287,6 +1276,7 @@ ovsdb_jsonrpc_monitor_create(struct ovsdb_jsonrpc_session *s, struct ovsdb *db,
 
         mt = xzalloc(sizeof *mt);
         mt->table = table;
+        hmap_init(&mt->changes);
         shash_add(&m->tables, table->schema->name, mt);
 
         /* Parse columns. */
@@ -1367,22 +1357,6 @@ ovsdb_jsonrpc_monitor_remove_all(struct ovsdb_jsonrpc_session *s)
     }
 }
 
-/* Returns an overestimate of the number of bytes of JSON data required to
- * report the current contents of the database over all the monitors currently
- * configured in 's'.  */
-static size_t
-ovsdb_jsonrpc_monitor_json_length_all(struct ovsdb_jsonrpc_session *s)
-{
-    struct ovsdb_jsonrpc_monitor *m;
-    size_t length;
-
-    length = 0;
-    HMAP_FOR_EACH (m, node, &s->monitors) {
-        length += ovsdb_jsonrpc_monitor_json_length(m);
-    }
-    return length;
-}
-
 static struct ovsdb_jsonrpc_monitor *
 ovsdb_jsonrpc_monitor_cast(struct ovsdb_replica *replica)
 {
@@ -1391,189 +1365,347 @@ ovsdb_jsonrpc_monitor_cast(struct ovsdb_replica *replica)
 }
 
 struct ovsdb_jsonrpc_monitor_aux {
-    bool initial;               /* Sending initial contents of table? */
     const struct ovsdb_jsonrpc_monitor *monitor;
-    struct json *json;          /* JSON for the whole transaction. */
-
-    /* Current table.  */
     struct ovsdb_jsonrpc_monitor_table *mt;
-    struct json *table_json;    /* JSON for table's transaction. */
 };
 
-static bool
-any_reportable_change(const struct ovsdb_jsonrpc_monitor_table *mt,
-                      const unsigned long int *changed)
+/* Finds and returns the ovsdb_jsonrpc_monitor_row in 'mt->changes' for the
+ * given 'uuid', or NULL if there is no such row. */
+static struct ovsdb_jsonrpc_monitor_row *
+ovsdb_jsonrpc_monitor_row_find(const struct ovsdb_jsonrpc_monitor_table *mt,
+                               const struct uuid *uuid)
 {
+    struct ovsdb_jsonrpc_monitor_row *row;
+
+    HMAP_FOR_EACH_WITH_HASH (row, hmap_node, uuid_hash(uuid), &mt->changes) {
+        if (uuid_equals(uuid, &row->uuid)) {
+            return row;
+        }
+    }
+    return NULL;
+}
+
+/* Allocates an array of 'mt->n_columns' ovsdb_datums and initializes them as
+ * copies of the data in 'row' drawn from the columns represented by
+ * mt->columns[].  Returns the array.
+ *
+ * If 'row' is NULL, returns NULL. */
+static struct ovsdb_datum *
+clone_monitor_row_data(const struct ovsdb_jsonrpc_monitor_table *mt,
+                       const struct ovsdb_row *row)
+{
+    struct ovsdb_datum *data;
     size_t i;
 
+    if (!row) {
+        return NULL;
+    }
+
+    data = xmalloc(mt->n_columns * sizeof *data);
     for (i = 0; i < mt->n_columns; i++) {
-        const struct ovsdb_jsonrpc_monitor_column *c = &mt->columns[i];
-        unsigned int idx = c->column->index;
+        const struct ovsdb_column *c = mt->columns[i].column;
+        const struct ovsdb_datum *src = &row->fields[c->index];
+        struct ovsdb_datum *dst = &data[i];
+        const struct ovsdb_type *type = &c->type;
+
+        ovsdb_datum_clone(dst, src, type);
+    }
+    return data;
+}
+
+/* Replaces the mt->n_columns ovsdb_datums in row[] by copies of the data from
+ * in 'row' drawn from the columns represented by mt->columns[]. */
+static void
+update_monitor_row_data(const struct ovsdb_jsonrpc_monitor_table *mt,
+                        const struct ovsdb_row *row,
+                        struct ovsdb_datum *data)
+{
+    size_t i;
 
-        if (c->select & OJMS_MODIFY && bitmap_is_set(changed, idx)) {
-            return true;
+    for (i = 0; i < mt->n_columns; i++) {
+        const struct ovsdb_column *c = mt->columns[i].column;
+        const struct ovsdb_datum *src = &row->fields[c->index];
+        struct ovsdb_datum *dst = &data[i];
+        const struct ovsdb_type *type = &c->type;
+
+        if (!ovsdb_datum_equals(src, dst, type)) {
+            ovsdb_datum_destroy(dst, type);
+            ovsdb_datum_clone(dst, src, type);
         }
     }
+}
 
-    return false;
+/* Frees all of the mt->n_columns ovsdb_datums in data[], using the types taken
+ * from mt->columns[], plus 'data' itself. */
+static void
+free_monitor_row_data(const struct ovsdb_jsonrpc_monitor_table *mt,
+                      struct ovsdb_datum *data)
+{
+    if (data) {
+        size_t i;
+
+        for (i = 0; i < mt->n_columns; i++) {
+            const struct ovsdb_column *c = mt->columns[i].column;
+
+            ovsdb_datum_destroy(&data[i], &c->type);
+        }
+        free(data);
+    }
+}
+
+/* Frees 'row', which must have been created from 'mt'. */
+static void
+ovsdb_jsonrpc_monitor_row_destroy(const struct ovsdb_jsonrpc_monitor_table *mt,
+                                  struct ovsdb_jsonrpc_monitor_row *row)
+{
+    if (row) {
+        free_monitor_row_data(mt, row->old);
+        free_monitor_row_data(mt, row->new);
+        free(row);
+    }
 }
 
 static bool
 ovsdb_jsonrpc_monitor_change_cb(const struct ovsdb_row *old,
                                 const struct ovsdb_row *new,
-                                const unsigned long int *changed,
+                                const unsigned long int *changed OVS_UNUSED,
                                 void *aux_)
 {
     struct ovsdb_jsonrpc_monitor_aux *aux = aux_;
     const struct ovsdb_jsonrpc_monitor *m = aux->monitor;
     struct ovsdb_table *table = new ? new->table : old->table;
-    enum ovsdb_jsonrpc_monitor_selection type;
-    struct json *old_json, *new_json;
-    struct json *row_json;
-    char uuid[UUID_LEN + 1];
-    size_t i;
+    const struct uuid *uuid = ovsdb_row_get_uuid(new ? new : old);
+    struct ovsdb_jsonrpc_monitor_row *change;
+    struct ovsdb_jsonrpc_monitor_table *mt;
 
     if (!aux->mt || table != aux->mt->table) {
         aux->mt = shash_find_data(&m->tables, table->schema->name);
-        aux->table_json = NULL;
         if (!aux->mt) {
             /* We don't care about rows in this table at all.  Tell the caller
              * to skip it.  */
             return false;
         }
     }
+    mt = aux->mt;
 
-    type = (aux->initial ? OJMS_INITIAL
-            : !old ? OJMS_INSERT
-            : !new ? OJMS_DELETE
+    change = ovsdb_jsonrpc_monitor_row_find(mt, uuid);
+    if (!change) {
+        change = xmalloc(sizeof *change);
+        hmap_insert(&mt->changes, &change->hmap_node, uuid_hash(uuid));
+        change->uuid = *uuid;
+        change->old = clone_monitor_row_data(mt, old);
+        change->new = clone_monitor_row_data(mt, new);
+    } else {
+        if (new) {
+            update_monitor_row_data(mt, new, change->new);
+        } else {
+            free_monitor_row_data(mt, change->new);
+            change->new = NULL;
+
+            if (!change->old) {
+                /* This row was added then deleted.  Forget about it. */
+                hmap_remove(&mt->changes, &change->hmap_node);
+                free(change);
+            }
+        }
+    }
+    return true;
+}
+
+/* Returns JSON for a <row-update> (as described in RFC 7047) for 'row' within
+ * 'mt', or NULL if no row update should be sent.
+ *
+ * The caller should specify 'initial' as true if the returned JSON is going to
+ * be used as part of the initial reply to a "monitor" request, false if it is
+ * going to be used as part of an "update" notification.
+ *
+ * 'changed' must be a scratch buffer for internal use that is at least
+ * bitmap_n_bytes(mt->n_columns) bytes long. */
+static struct json *
+ovsdb_jsonrpc_monitor_compose_row_update(
+    const struct ovsdb_jsonrpc_monitor_table *mt,
+    const struct ovsdb_jsonrpc_monitor_row *row,
+    bool initial, unsigned long int *changed)
+{
+    enum ovsdb_jsonrpc_monitor_selection type;
+    struct json *old_json, *new_json;
+    struct json *row_json;
+    size_t i;
+
+    type = (initial ? OJMS_INITIAL
+            : !row->old ? OJMS_INSERT
+            : !row->new ? OJMS_DELETE
             : OJMS_MODIFY);
-    if (!(aux->mt->select & type)) {
-        /* We don't care about this type of change (but do want to be called
-         * back for changes to other rows in the same table). */
-        return true;
+    if (!(mt->select & type)) {
+        return NULL;
     }
 
-    if (type == OJMS_MODIFY && !any_reportable_change(aux->mt, changed)) {
-        /* Nothing of interest changed. */
-        return true;
+    if (type == OJMS_MODIFY) {
+        size_t n_changes;
+
+        n_changes = 0;
+        memset(changed, 0, bitmap_n_bytes(mt->n_columns));
+        for (i = 0; i < mt->n_columns; i++) {
+            const struct ovsdb_column *c = mt->columns[i].column;
+            if (!ovsdb_datum_equals(&row->old[i], &row->new[i], &c->type)) {
+                bitmap_set1(changed, i);
+                n_changes++;
+            }
+        }
+        if (!n_changes) {
+            /* No actual changes: presumably a row changed and then
+             * changed back later. */
+            return NULL;
+        }
     }
 
+    row_json = json_object_create();
     old_json = new_json = NULL;
     if (type & (OJMS_DELETE | OJMS_MODIFY)) {
         old_json = json_object_create();
+        json_object_put(row_json, "old", old_json);
     }
     if (type & (OJMS_INITIAL | OJMS_INSERT | OJMS_MODIFY)) {
         new_json = json_object_create();
+        json_object_put(row_json, "new", new_json);
     }
-    for (i = 0; i < aux->mt->n_columns; i++) {
-        const struct ovsdb_jsonrpc_monitor_column *c = &aux->mt->columns[i];
-        const struct ovsdb_column *column = c->column;
-        unsigned int idx = c->column->index;
+    for (i = 0; i < mt->n_columns; i++) {
+        const struct ovsdb_jsonrpc_monitor_column *c = &mt->columns[i];
 
         if (!(type & c->select)) {
-            /* We don't care about this type of change for this particular
-             * column (but we will care about it for some other column). */
+            /* We don't care about this type of change for this
+             * particular column (but we will care about it for some
+             * other column). */
             continue;
         }
 
-        if ((type == OJMS_MODIFY && bitmap_is_set(changed, idx))
+        if ((type == OJMS_MODIFY && bitmap_is_set(changed, i))
             || type == OJMS_DELETE) {
-            json_object_put(old_json, column->name,
-                            ovsdb_datum_to_json(&old->fields[idx],
-                                                &column->type));
+            json_object_put(old_json, c->column->name,
+                            ovsdb_datum_to_json(&row->old[i],
+                                                &c->column->type));
         }
         if (type & (OJMS_INITIAL | OJMS_INSERT | OJMS_MODIFY)) {
-            json_object_put(new_json, column->name,
-                            ovsdb_datum_to_json(&new->fields[idx],
-                                                &column->type));
+            json_object_put(new_json, c->column->name,
+                            ovsdb_datum_to_json(&row->new[i],
+                                                &c->column->type));
         }
     }
 
-    /* Create JSON object for transaction overall. */
-    if (!aux->json) {
-        aux->json = json_object_create();
-    }
+    return row_json;
+}
 
-    /* Create JSON object for transaction on this table. */
-    if (!aux->table_json) {
-        aux->table_json = json_object_create();
-        json_object_put(aux->json, aux->mt->table->schema->name,
-                        aux->table_json);
-    }
+/* Constructs and returns JSON for a <table-updates> object (as described in
+ * RFC 7047) for all the outstanding changes within 'monitor', and deletes all
+ * the outstanding changes from 'monitor'.  Returns NULL if no update needs to
+ * be sent.
+ *
+ * The caller should specify 'initial' as true if the returned JSON is going to
+ * be used as part of the initial reply to a "monitor" request, false if it is
+ * going to be used as part of an "update" notification. */
+static struct json *
+ovsdb_jsonrpc_monitor_compose_table_update(
+    const struct ovsdb_jsonrpc_monitor *monitor, bool initial)
+{
+    struct shash_node *node;
+    unsigned long int *changed;
+    struct json *json;
+    size_t max_columns;
 
-    /* Create JSON object for transaction on this row. */
-    row_json = json_object_create();
-    if (old_json) {
-        json_object_put(row_json, "old", old_json);
+    max_columns = 0;
+    SHASH_FOR_EACH (node, &monitor->tables) {
+        struct ovsdb_jsonrpc_monitor_table *mt = node->data;
+
+        max_columns = MAX(max_columns, mt->n_columns);
     }
-    if (new_json) {
-        json_object_put(row_json, "new", new_json);
+    changed = xmalloc(bitmap_n_bytes(max_columns));
+
+    json = NULL;
+    SHASH_FOR_EACH (node, &monitor->tables) {
+        struct ovsdb_jsonrpc_monitor_table *mt = node->data;
+        struct ovsdb_jsonrpc_monitor_row *row, *next;
+        struct json *table_json = NULL;
+
+        HMAP_FOR_EACH_SAFE (row, next, hmap_node, &mt->changes) {
+            struct json *row_json;
+
+            row_json = ovsdb_jsonrpc_monitor_compose_row_update(
+                mt, row, initial, changed);
+            if (row_json) {
+                char uuid[UUID_LEN + 1];
+
+                /* Create JSON object for transaction overall. */
+                if (!json) {
+                    json = json_object_create();
+                }
+
+                /* Create JSON object for transaction on this table. */
+                if (!table_json) {
+                    table_json = json_object_create();
+                    json_object_put(json, mt->table->schema->name, table_json);
+                }
+
+                /* Add JSON row to JSON table. */
+                snprintf(uuid, sizeof uuid, UUID_FMT, UUID_ARGS(&row->uuid));
+                json_object_put(table_json, uuid, row_json);
+            }
+
+            hmap_remove(&mt->changes, &row->hmap_node);
+            ovsdb_jsonrpc_monitor_row_destroy(mt, row);
+        }
     }
 
-    /* Add JSON row to JSON table. */
-    snprintf(uuid, sizeof uuid,
-             UUID_FMT, UUID_ARGS(ovsdb_row_get_uuid(new ? new : old)));
-    json_object_put(aux->table_json, uuid, row_json);
+    free(changed);
 
-    return true;
+    return json;
 }
 
-/* Returns an overestimate of the number of bytes of JSON data required to
- * report the current contents of the database over monitor 'm'. */
-static size_t
-ovsdb_jsonrpc_monitor_json_length(const struct ovsdb_jsonrpc_monitor *m)
+static bool
+ovsdb_jsonrpc_monitor_needs_flush(struct ovsdb_jsonrpc_session *s)
 {
-    const struct shash_node *node;
-    size_t length;
+    struct ovsdb_jsonrpc_monitor *m;
 
-    /* Top-level overhead of monitor JSON. */
-    length = 256;
+    HMAP_FOR_EACH (m, node, &s->monitors) {
+        struct shash_node *node;
 
-    SHASH_FOR_EACH (node, &m->tables) {
-        const struct ovsdb_jsonrpc_monitor_table *mt = node->data;
-        const struct ovsdb_table *table = mt->table;
-        const struct ovsdb_row *row;
-        size_t i;
+        SHASH_FOR_EACH (node, &m->tables) {
+            struct ovsdb_jsonrpc_monitor_table *mt = node->data;
 
-        /* Per-table JSON overhead: "<table>":{...}. */
-        length += strlen(table->schema->name) + 32;
+            if (!hmap_is_empty(&mt->changes)) {
+                return true;
+            }
+        }
+    }
 
-        /* Per-row JSON overhead: ,"<uuid>":{"old":{...},"new":{...}} */
-        length += hmap_count(&table->rows) * (UUID_LEN + 32);
+    return false;
+}
 
-        /* Per-row, per-column JSON overhead: ,"<column>": */
-        for (i = 0; i < mt->n_columns; i++) {
-            const struct ovsdb_jsonrpc_monitor_column *c = &mt->columns[i];
-            const struct ovsdb_column *column = c->column;
+static void
+ovsdb_jsonrpc_monitor_flush_all(struct ovsdb_jsonrpc_session *s)
+{
+    struct ovsdb_jsonrpc_monitor *m;
 
-            length += hmap_count(&table->rows) * (8 + strlen(column->name));
-        }
+    HMAP_FOR_EACH (m, node, &s->monitors) {
+        struct json *json;
 
-        /* Data. */
-        HMAP_FOR_EACH (row, hmap_node, &table->rows) {
-            for (i = 0; i < mt->n_columns; i++) {
-                const struct ovsdb_jsonrpc_monitor_column *c = &mt->columns[i];
-                const struct ovsdb_column *column = c->column;
+        json = ovsdb_jsonrpc_monitor_compose_table_update(m, false);
+        if (json) {
+            struct jsonrpc_msg *msg;
+            struct json *params;
 
-                length += ovsdb_datum_json_length(&row->fields[column->index],
-                                                  &column->type);
-            }
+            params = json_array_create_2(json_clone(m->monitor_id), json);
+            msg = jsonrpc_create_notify("update", params);
+            jsonrpc_session_send(s->js, msg);
         }
     }
-
-    return length;
 }
 
 static void
 ovsdb_jsonrpc_monitor_init_aux(struct ovsdb_jsonrpc_monitor_aux *aux,
-                               const struct ovsdb_jsonrpc_monitor *m,
-                               bool initial)
+                               const struct ovsdb_jsonrpc_monitor *m)
 {
-    aux->initial = initial;
     aux->monitor = m;
-    aux->json = NULL;
     aux->mt = NULL;
-    aux->table_json = NULL;
 }
 
 static struct ovsdb_error *
@@ -1584,17 +1716,8 @@ ovsdb_jsonrpc_monitor_commit(struct ovsdb_replica *replica,
     struct ovsdb_jsonrpc_monitor *m = ovsdb_jsonrpc_monitor_cast(replica);
     struct ovsdb_jsonrpc_monitor_aux aux;
 
-    ovsdb_jsonrpc_monitor_init_aux(&aux, m, false);
+    ovsdb_jsonrpc_monitor_init_aux(&aux, m);
     ovsdb_txn_for_each_change(txn, ovsdb_jsonrpc_monitor_change_cb, &aux);
-    if (aux.json) {
-        struct jsonrpc_msg *msg;
-        struct json *params;
-
-        params = json_array_create_2(json_clone(aux.monitor->monitor_id),
-                                     aux.json);
-        msg = jsonrpc_create_notify("update", params);
-        jsonrpc_session_send(aux.monitor->session->js, msg);
-    }
 
     return NULL;
 }
@@ -1604,8 +1727,9 @@ ovsdb_jsonrpc_monitor_get_initial(const struct ovsdb_jsonrpc_monitor *m)
 {
     struct ovsdb_jsonrpc_monitor_aux aux;
     struct shash_node *node;
+    struct json *json;
 
-    ovsdb_jsonrpc_monitor_init_aux(&aux, m, true);
+    ovsdb_jsonrpc_monitor_init_aux(&aux, m);
     SHASH_FOR_EACH (node, &m->tables) {
         struct ovsdb_jsonrpc_monitor_table *mt = node->data;
 
@@ -1617,7 +1741,8 @@ ovsdb_jsonrpc_monitor_get_initial(const struct ovsdb_jsonrpc_monitor *m)
             }
         }
     }
-    return aux.json ? aux.json : json_object_create();
+    json = ovsdb_jsonrpc_monitor_compose_table_update(m, true);
+    return json ? json : json_object_create();
 }
 
 static void
@@ -1629,6 +1754,14 @@ ovsdb_jsonrpc_monitor_destroy(struct ovsdb_replica *replica)
     json_destroy(m->monitor_id);
     SHASH_FOR_EACH (node, &m->tables) {
         struct ovsdb_jsonrpc_monitor_table *mt = node->data;
+        struct ovsdb_jsonrpc_monitor_row *row, *next;
+
+        HMAP_FOR_EACH_SAFE (row, next, hmap_node, &mt->changes) {
+            hmap_remove(&mt->changes, &row->hmap_node);
+            ovsdb_jsonrpc_monitor_row_destroy(mt, row);
+        }
+        hmap_destroy(&mt->changes);
+
         free(mt->columns);
         free(mt);
     }
index d60d7ca..2942953 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -166,14 +166,15 @@ parse_options(int argc, char *argv[])
     enum {
         OPT_BOOTSTRAP_CA_CERT = UCHAR_MAX + 1,
         OPT_TIMESTAMP,
+        VLOG_OPTION_ENUMS,
         DAEMON_OPTION_ENUMS,
         TABLE_OPTION_ENUMS
     };
     static const struct option long_options[] = {
-        {"verbose", optional_argument, NULL, 'v'},
         {"help", no_argument, NULL, 'h'},
         {"version", no_argument, NULL, 'V'},
         {"timestamp", no_argument, NULL, OPT_TIMESTAMP},
+        VLOG_LONG_OPTIONS,
         DAEMON_LONG_OPTIONS,
 #ifdef HAVE_OPENSSL
         {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT},
@@ -200,14 +201,9 @@ parse_options(int argc, char *argv[])
             ovs_print_version(0, 0);
             exit(EXIT_SUCCESS);
 
-        case 'v':
-            vlog_set_verbosity(optarg);
-            break;
-
+        VLOG_OPTION_HANDLERS
         DAEMON_OPTION_HANDLERS
-
         TABLE_OPTION_HANDLERS(&table_style)
-
         STREAM_SSL_OPTION_HANDLERS
 
         case OPT_BOOTSTRAP_CA_CERT:
index a4cf344..15382b4 100644 (file)
@@ -183,6 +183,54 @@ the command line or through the \fBovsdb\-server/add\-db\fR command.
 .so lib/vlog-unixctl.man
 .so lib/memory-unixctl.man
 .so lib/coverage-unixctl.man
+.SH "SPECIFICATIONS"
+.
+.PP
+\fBovsdb\-server\fR implements the Open vSwitch Database (OVSDB)
+protocol specified in RFC 7047, with the following clarifications:
+.
+.IP "3.1. JSON Usage"
+RFC 4627 says that names within a JSON object should be unique.
+The Open vSwitch JSON parser discards all but the last value
+for a name that is specified more than once.
+.
+.IP "3.2. Schema Format"
+RFC 7047 requires the "version" field in <database-schema>.  Current
+versions of \fBovsdb\-server\fR allow it to be omitted (future
+versions are likely to require it).
+.
+.IP "4. Wire Protocol"
+The original OVSDB specifications included the following reason,
+omitted from RFC 7047, to operate JSON-RPC directly over a stream
+instead of over HTTP:
+.
+.RS
+.IP \(bu
+JSON-RPC is a peer-to-peer protocol, but HTTP is a client-server
+protocol, which is a poor match.  Thus, JSON-RPC over HTTP requires
+the client to periodically poll the server to receive server requests.
+.IP \(bu
+HTTP is more complicated than stream connections and doesn't provide
+any corresponding advantage.
+.IP \(bu
+The JSON-RPC specification for HTTP transport is incomplete.
+.RE
+.
+.IP "4.1.5. Monitor"
+For backward compatibility, \fBovsdb\-server\fR currently permits a
+single <monitor-request> to be used instead of an array; it is treated
+as a single-element array.  Future versions of \fBovsdb\-server\fR
+might remove this compatibility feature.
+.IP
+Because the <json-value> parameter is used to match subsequent update
+notifications (see below) to the request, it must be unique among all
+active monitors.  \fBovsdb\-server\fR rejects attempt to create two
+monitors with the same identifier.
+.
+.IP "6. IANA Considerations"
+\fBovsdb\-server\fR currently defaults to its historical port number
+6632.  Future versions will adopt IANA-assigned port 6640 as default.
+
 .SH "SEE ALSO"
 .
 .BR ovsdb\-tool (1).
index 6de77e4..a85a672 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
 #include <getopt.h>
 #include <inttypes.h>
 #include <signal.h>
+#include <sys/stat.h>
 #include <unistd.h>
 
 #include "column.h"
@@ -328,6 +329,36 @@ main(int argc, char *argv[])
     return 0;
 }
 
+/* Returns true if 'filename' is known to be already open as a database,
+ * false if not.
+ *
+ * "False negatives" are possible. */
+static bool
+is_already_open(struct server_config *config OVS_UNUSED,
+                const char *filename OVS_UNUSED)
+{
+#ifndef _WIN32
+    struct stat s;
+
+    if (!stat(filename, &s)) {
+        struct shash_node *node;
+
+        SHASH_FOR_EACH (node, config->all_dbs) {
+            struct db *db = node->data;
+            struct stat s2;
+
+            if (!stat(db->filename, &s2)
+                && s.st_dev == s2.st_dev
+                && s.st_ino == s2.st_ino) {
+                return true;
+            }
+        }
+    }
+#endif  /* !_WIN32 */
+
+    return false;
+}
+
 static char *
 open_db(struct server_config *config, const char *filename)
 {
@@ -335,6 +366,13 @@ open_db(struct server_config *config, const char *filename)
     struct db *db;
     char *error;
 
+    /* If we know that the file is already open, return a good error message.
+     * Otherwise, if the file is open, we'll fail later on with a harder to
+     * interpret file locking error. */
+    if (is_already_open(config, filename)) {
+        return xasprintf("%s: already open", filename);
+    }
+
     db = xzalloc(sizeof *db);
     db->filename = xstrdup(filename);
 
index 98a7a3f..be40df9 100644 (file)
@@ -533,6 +533,7 @@ assess_weak_refs(struct ovsdb_txn *txn, struct ovsdb_txn_row *txn_row)
         }
 
         if (datum->n != orig_n) {
+            bitmap_set1(txn_row->changed, OVSDB_COL_VERSION);
             bitmap_set1(txn_row->changed, column->index);
             ovsdb_datum_sort_assert(datum, column->type.key.type);
             if (datum->n < column->type.n_min) {
index e21a1cc..6baff38 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2009, 2010, 2011 Nicira, Inc.
+# Copyright (c) 2009, 2010, 2011, 2014 Nicira, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -307,7 +307,7 @@ class Datum(object):
         Violations of constraints expressed by 'type' are treated as errors.
 
         If 'symtab' is nonnull, then named UUIDs in 'symtab' are accepted.
-        Refer to ovsdb/SPECS for information about this, and for the syntax
+        Refer to RFC 7047 for information about this, and for the syntax
         that this function accepts."""
         is_map = type_.is_map()
         if (is_map or
index 34187c4..793258f 100644 (file)
@@ -6,6 +6,7 @@
 /idltest.c
 /idltest.h
 /idltest.ovsidl
+/ovstest
 /ovs-pki.log
 /pki/
 /test-aes128
index 4818f5c..6876dd2 100644 (file)
@@ -3,7 +3,7 @@ AT_BANNER([AES-128 unit tests])
 m4_define([AES128_CHECK], 
   [AT_SETUP([$1])
    AT_KEYWORDS([aes128])
-   AT_CHECK([test-aes128 $2 $3], [0], [$4
+   AT_CHECK([ovstest test-aes128 $2 $3], [0], [$4
 ], [])
    AT_CLEANUP])
 
index 6c59c6e..bf80702 100644 (file)
@@ -179,22 +179,6 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
          echo 'm4_define([AT_PACKAGE_BUGREPORT], [$(PACKAGE_BUGREPORT)])'; \
        } >'$(srcdir)/package.m4'
 
-noinst_PROGRAMS += tests/test-aes128
-tests_test_aes128_SOURCES = tests/test-aes128.c
-tests_test_aes128_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-atomic
-tests_test_atomic_SOURCES = tests/test-atomic.c
-tests_test_atomic_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-bundle
-tests_test_bundle_SOURCES = tests/test-bundle.c
-tests_test_bundle_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-classifier
-tests_test_classifier_SOURCES = tests/test-classifier.c
-tests_test_classifier_LDADD = lib/libopenvswitch.la
-
 noinst_PROGRAMS += tests/test-controller
 MAN_ROOTS += tests/test-controller.8.in
 DISTCLEANFILES += tests/test-controller.8
@@ -202,79 +186,6 @@ noinst_man_MANS += tests/test-controller.8
 tests_test_controller_SOURCES = tests/test-controller.c
 tests_test_controller_LDADD = lib/libopenvswitch.la
 
-noinst_PROGRAMS += tests/test-csum
-tests_test_csum_SOURCES = tests/test-csum.c
-tests_test_csum_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-file_name
-tests_test_file_name_SOURCES = tests/test-file_name.c
-tests_test_file_name_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-flows
-tests_test_flows_SOURCES = tests/test-flows.c
-tests_test_flows_LDADD = lib/libopenvswitch.la
-dist_check_SCRIPTS = tests/flowgen.pl
-
-noinst_PROGRAMS += tests/test-hash
-tests_test_hash_SOURCES = tests/test-hash.c
-tests_test_hash_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-hindex
-tests_test_hindex_SOURCES = tests/test-hindex.c
-tests_test_hindex_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-hmap
-tests_test_hmap_SOURCES = tests/test-hmap.c
-tests_test_hmap_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-json
-tests_test_json_SOURCES = tests/test-json.c
-tests_test_json_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-jsonrpc
-tests_test_jsonrpc_SOURCES = tests/test-jsonrpc.c
-tests_test_jsonrpc_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-list
-tests_test_list_SOURCES = tests/test-list.c
-tests_test_list_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-lockfile
-tests_test_lockfile_SOURCES = tests/test-lockfile.c
-tests_test_lockfile_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-multipath
-tests_test_multipath_SOURCES = tests/test-multipath.c
-tests_test_multipath_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-packets
-tests_test_packets_SOURCES = tests/test-packets.c
-tests_test_packets_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-random
-tests_test_random_SOURCES = tests/test-random.c
-tests_test_random_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-stp
-tests_test_stp_SOURCES = tests/test-stp.c
-tests_test_stp_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-sflow
-tests_test_sflow_SOURCES = tests/test-sflow.c
-tests_test_sflow_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-netflow
-tests_test_netflow_SOURCES = tests/test-netflow.c
-tests_test_netflow_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-unix-socket
-tests_test_unix_socket_SOURCES = tests/test-unix-socket.c
-tests_test_unix_socket_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-odp
-tests_test_odp_SOURCES = tests/test-odp.c
-tests_test_odp_LDADD = lib/libopenvswitch.la
-
 noinst_PROGRAMS += tests/test-ovsdb
 tests_test_ovsdb_SOURCES = \
        tests/test-ovsdb.c \
@@ -294,18 +205,40 @@ tests/idltest.ovsidl: $(IDLTEST_IDL_FILES)
 tests/idltest.c: tests/idltest.h
 
 noinst_PROGRAMS += tests/ovstest
-tests_ovstest_SOURCES = tests/ovstest.c \
-        tests/ovstest.h \
-        tests/test-heap.c
+tests_ovstest_SOURCES = \
+       tests/ovstest.c \
+       tests/ovstest.h \
+       tests/test-aes128.c \
+       tests/test-atomic.c \
+       tests/test-bundle.c \
+       tests/test-byte-order.c \
+       tests/test-classifier.c \
+       tests/test-csum.c \
+       tests/test-file_name.c \
+       tests/test-flows.c \
+       tests/test-hash.c \
+       tests/test-heap.c \
+       tests/test-hindex.c \
+       tests/test-hmap.c \
+       tests/test-json.c \
+       tests/test-jsonrpc.c \
+       tests/test-list.c \
+       tests/test-lockfile.c \
+       tests/test-multipath.c \
+       tests/test-netflow.c \
+       tests/test-odp.c \
+       tests/test-packets.c \
+       tests/test-random.c \
+       tests/test-reconnect.c \
+       tests/test-sflow.c \
+       tests/test-sha1.c \
+       tests/test-stp.c \
+       tests/test-unix-socket.c \
+       tests/test-util.c \
+       tests/test-uuid.c \
+       tests/test-vconn.c
 tests_ovstest_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-reconnect
-tests_test_reconnect_SOURCES = tests/test-reconnect.c
-tests_test_reconnect_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-sha1
-tests_test_sha1_SOURCES = tests/test-sha1.c
-tests_test_sha1_LDADD = lib/libopenvswitch.la
+dist_check_SCRIPTS = tests/flowgen.pl
 
 noinst_PROGRAMS += tests/test-strtok_r
 tests_test_strtok_r_SOURCES = tests/test-strtok_r.c
@@ -313,22 +246,6 @@ tests_test_strtok_r_SOURCES = tests/test-strtok_r.c
 noinst_PROGRAMS += tests/test-type-props
 tests_test_type_props_SOURCES = tests/test-type-props.c
 
-noinst_PROGRAMS += tests/test-util
-tests_test_util_SOURCES = tests/test-util.c
-tests_test_util_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-uuid
-tests_test_uuid_SOURCES = tests/test-uuid.c
-tests_test_uuid_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-vconn
-tests_test_vconn_SOURCES = tests/test-vconn.c
-tests_test_vconn_LDADD = lib/libopenvswitch.la
-
-noinst_PROGRAMS += tests/test-byte-order
-tests_test_byte_order_SOURCES = tests/test-byte-order.c
-tests_test_byte_order_LDADD = lib/libopenvswitch.la
-
 # Python tests.
 CHECK_PYFILES = \
        tests/appctl.py \
index 8a3c291..bf62b2c 100644 (file)
@@ -8,7 +8,7 @@ AT_BANNER([bundle link selection])
 # if the test does fail.
 
 AT_SETUP([hrw bundle link selection])
-AT_CHECK([[test-bundle 'symmetric_l4,60,hrw,ofport,NXM_NX_REG0[],slaves:1,2,3,4,5']],
+AT_CHECK([[ovstest test-bundle 'symmetric_l4,60,hrw,ofport,NXM_NX_REG0[],slaves:1,2,3,4,5']],
   [0], [ignore])
 # 100000: disruption=1.00 (perfect=1.00) 1.00 0.00 0.00 0.00 0.00 0.00
 # 110000: disruption=0.50 (perfect=0.50) 0.50 0.50 0.00 0.00 0.00 0.00
@@ -78,7 +78,7 @@ AT_CHECK([[test-bundle 'symmetric_l4,60,hrw,ofport,NXM_NX_REG0[],slaves:1,2,3,4,
 AT_CLEANUP
 
 AT_SETUP([active_backup bundle link selection])
-AT_CHECK([[test-bundle 'symmetric_l4,60,active_backup,ofport,NXM_NX_REG0[],slaves:1,2,3,4,5,6']],
+AT_CHECK([[ovstest test-bundle 'symmetric_l4,60,active_backup,ofport,NXM_NX_REG0[],slaves:1,2,3,4,5,6']],
   [0],
 [100000: disruption=1.00 (perfect=1.00) 1.00 0.00 0.00 0.00 0.00 0.00
 110000: disruption=0.00 (perfect=0.00) 1.00 0.00 0.00 0.00 0.00 0.00
@@ -149,7 +149,7 @@ AT_CHECK([[test-bundle 'symmetric_l4,60,active_backup,ofport,NXM_NX_REG0[],slave
 AT_CLEANUP
 
 AT_SETUP([hrw bundle single link selection])
-AT_CHECK([[test-bundle 'symmetric_l4,60,hrw,ofport,NXM_NX_REG0[],slaves:1']],
+AT_CHECK([[ovstest test-bundle 'symmetric_l4,60,hrw,ofport,NXM_NX_REG0[],slaves:1']],
   [0], [ignore])
 # 1: disruption=1.00 (perfect=1.00) 1.00
 # 0: disruption=1.00 (perfect=1.00) 0.00
@@ -157,7 +157,7 @@ AT_CHECK([[test-bundle 'symmetric_l4,60,hrw,ofport,NXM_NX_REG0[],slaves:1']],
 AT_CLEANUP
 
 AT_SETUP([hrw bundle no link selection])
-AT_CHECK([[test-bundle 'symmetric_l4,60,hrw,ofport,NXM_NX_REG0[],slaves:']],
+AT_CHECK([[ovstest test-bundle 'symmetric_l4,60,hrw,ofport,NXM_NX_REG0[],slaves:']],
   [0], [ignore])
 AT_CLEANUP
 #: disruption=0.00 (perfect=0.00)
index a46c526..b6c9352 100644 (file)
@@ -10,7 +10,7 @@ m4_foreach(
    [many-rules-in-two-tables],
    [many-rules-in-five-tables]],
   [AT_SETUP([flow classifier - m4_bpatsubst(testname, [-], [ ])])
-   AT_CHECK([test-classifier testname], [0], [], [])
+   AT_CHECK([ovstest test-classifier testname], [0], [], [])
    AT_CLEANUP])])
 
 AT_BANNER([miniflow unit tests])
@@ -20,7 +20,7 @@ m4_foreach(
    [minimask_has_extra],
    [minimask_combine]],
   [AT_SETUP([miniflow - m4_bpatsubst(testname, [-], [ ])])
-   AT_CHECK([test-classifier testname], [0], [], [])
+   AT_CHECK([ovstest test-classifier testname], [0], [], [])
    AT_CLEANUP])])
 
 AT_BANNER([flow classifier lookup segmentation])
@@ -40,22 +40,22 @@ table=0 in_port=3 priority=0,ip,action=drop
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=2,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
-  [Megaflow: skb_priority=0,tcp,in_port=2,nw_dst=192.168.0.0/16,nw_frag=no
+  [Megaflow: recirc_id=0,skb_priority=0,tcp,in_port=2,nw_dst=192.168.0.0/16,nw_frag=no
 Datapath actions: 1
 ])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
-  [Megaflow: skb_priority=0,tcp,in_port=1,nw_dst=192.168.0.2,nw_frag=no
+  [Megaflow: recirc_id=0,skb_priority=0,tcp,in_port=1,nw_dst=192.168.0.2,nw_frag=no
 Datapath actions: drop
 ])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=10.1.2.15,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
-  [Megaflow: skb_priority=0,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_dst=80
+  [Megaflow: recirc_id=0,skb_priority=0,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_dst=80
 Datapath actions: drop
 ])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=10.1.2.15,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=79'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
-  [Megaflow: skb_priority=0,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_dst=79
+  [Megaflow: recirc_id=0,skb_priority=0,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_dst=79
 Datapath actions: 2
 ])
 OVS_VSWITCHD_STOP
@@ -87,22 +87,22 @@ table=0 in_port=3 priority=0,ip,action=drop
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
-  [Megaflow: skb_priority=0,tcp,in_port=1,nw_dst=192.168.0.0/16,nw_frag=no
+  [Megaflow: recirc_id=0,skb_priority=0,tcp,in_port=1,nw_dst=192.168.0.0/16,nw_frag=no
 Datapath actions: drop
 ])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=2,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
-  [Megaflow: skb_priority=0,tcp,in_port=2,nw_dst=192.168.0.0/16,nw_frag=no
+  [Megaflow: recirc_id=0,skb_priority=0,tcp,in_port=2,nw_dst=192.168.0.0/16,nw_frag=no
 Datapath actions: 1
 ])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=10.1.2.15,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
-  [Megaflow: skb_priority=0,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_dst=80
+  [Megaflow: recirc_id=0,skb_priority=0,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_dst=80
 Datapath actions: drop
 ])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=10.1.2.15,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=79'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
-  [Megaflow: skb_priority=0,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_src=8,tp_dst=79
+  [Megaflow: recirc_id=0,skb_priority=0,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_src=8,tp_dst=79
 Datapath actions: 3
 ])
 OVS_VSWITCHD_STOP(["/'prefixes' with incompatible field: ipv6_label/d"])
index aee4070..3d48b85 100644 (file)
@@ -3,7 +3,7 @@ AT_BANNER([test dir_name and base_name functions])
 m4_define([CHECK_FILE_NAME],
   [AT_SETUP([components of "$1" are "$2", "$3"])
    AT_KEYWORDS([dir_name base_name])
-   AT_CHECK([test-file_name "AS_ESCAPE($1)"], [0], [$2
+   AT_CHECK([ovstest test-file_name "AS_ESCAPE($1)"], [0], [$2
 $3
 ])
    AT_CLEANUP])
@@ -29,7 +29,7 @@ AT_BANNER([test follow_symlinks function])
 
 m4_define([CHECK_FOLLOW],
   [echo "check $1 -> $2"
-   AT_CHECK_UNQUOTED([test-util follow-symlinks "$1"], [0], [$2
+   AT_CHECK_UNQUOTED([ovstest test-util follow-symlinks "$1"], [0], [$2
 ])
    echo])
 
@@ -115,7 +115,7 @@ AT_SKIP_IF([test ! -h b])
 ln -s b a
 AT_SKIP_IF([test ! -h a])
 
-AT_CHECK([test-util follow-symlinks a], [0], [a
+AT_CHECK([ovstest test-util follow-symlinks a], [0], [a
 ], [stderr])
 AT_CHECK([sed 's/^[[^|]]*|//' stderr], [0],
   [00001|util|WARN|a: too many levels of symlinks
index 3962da1..86ae5fa 100644 (file)
@@ -3,7 +3,7 @@ m4_define([JSON_CHECK_POSITIVE_C],
    AT_KEYWORDS([json positive])
    AT_CHECK([printf %s "AS_ESCAPE([$2])" > input])
    AT_CAPTURE_FILE([input])
-   AT_CHECK([test-json $4 input], [0], [stdout], [])
+   AT_CHECK([ovstest test-json $4 input], [0], [stdout], [])
    AT_CHECK([cat stdout], [0], [$3
 ])
    AT_CLEANUP])
@@ -40,7 +40,7 @@ m4_define([JSON_CHECK_NEGATIVE_C],
    AT_KEYWORDS([json negative])
    AT_CHECK([printf %s "AS_ESCAPE([$2])" > input])
    AT_CAPTURE_FILE([input])
-   AT_CHECK([test-json $4 input], [1], [stdout], [])
+   AT_CHECK([ovstest test-json $4 input], [1], [stdout], [])
    AT_CHECK([[sed 's/^error: [^:]*:/error:/' < stdout]], [0], [$3
 ])
    AT_CLEANUP])
@@ -123,7 +123,7 @@ JSON_CHECK_NEGATIVE([null bytes not allowed],
 
 AT_SETUP([end of input in quoted string - C])
 AT_KEYWORDS([json negative])
-AT_CHECK([printf '"xxx' | test-json -], [1],
+AT_CHECK([printf '"xxx' | ovstest test-json -], [1],
   [error: line 0, column 4, byte 4: unexpected end of input in quoted string
 ])
 AT_CLEANUP
@@ -328,7 +328,7 @@ JSON_CHECK_NEGATIVE([objects nesting too deep],
 
 AT_SETUP([input may not be empty])
 AT_KEYWORDS([json negative])
-AT_CHECK([test-json /dev/null], [1], [error: line 0, column 0, byte 0: empty input stream
+AT_CHECK([ovstest test-json /dev/null], [1], [error: line 0, column 0, byte 0: empty input stream
 ])
 AT_CLEANUP
 
index 664debe..e06b5b6 100644 (file)
@@ -2,11 +2,11 @@ AT_BANNER([JSON-RPC - C])
 
 AT_SETUP([JSON-RPC request and successful reply])
 OVS_RUNDIR=`pwd`; export OVS_RUNDIR
-AT_CHECK([test-jsonrpc --detach --no-chdir --pidfile="`pwd`"/pid listen punix:socket])
+AT_CHECK([ovstest test-jsonrpc --detach --no-chdir --pidfile="`pwd`"/pid listen punix:socket])
 AT_CHECK([test -s pid])
 AT_CHECK([kill -0 `cat pid`])
 AT_CHECK(
-  [[test-jsonrpc request unix:socket echo '[{"a": "b", "x": null}]']], [0],
+  [[ovstest test-jsonrpc request unix:socket echo '[{"a": "b", "x": null}]']], [0],
   [[{"error":null,"id":0,"result":[{"a":"b","x":null}]}
 ]], [], [test ! -e pid || kill `cat pid`])
 AT_CHECK([kill `cat pid`])
@@ -14,11 +14,11 @@ AT_CLEANUP
 
 AT_SETUP([JSON-RPC request and error reply])
 OVS_RUNDIR=`pwd`; export OVS_RUNDIR
-AT_CHECK([test-jsonrpc --detach --no-chdir --pidfile="`pwd`"/pid listen punix:socket])
+AT_CHECK([ovstest test-jsonrpc --detach --no-chdir --pidfile="`pwd`"/pid listen punix:socket])
 AT_CHECK([test -s pid])
 AT_CHECK([kill -0 `cat pid`])
 AT_CHECK(
-  [[test-jsonrpc request unix:socket bad-request '[]']], [0],
+  [[ovstest test-jsonrpc request unix:socket bad-request '[]']], [0],
   [[{"error":{"error":"unknown method"},"id":0,"result":null}
 ]], [], [test ! -e pid || kill `cat pid`])
 AT_CHECK([kill `cat pid`])
@@ -26,12 +26,12 @@ AT_CLEANUP
 
 AT_SETUP([JSON-RPC notification])
 OVS_RUNDIR=`pwd`; export OVS_RUNDIR
-AT_CHECK([test-jsonrpc --detach --no-chdir --pidfile="`pwd`"/pid listen punix:socket])
+AT_CHECK([ovstest test-jsonrpc --detach --no-chdir --pidfile="`pwd`"/pid listen punix:socket])
 AT_CHECK([test -s pid])
 # When a daemon dies it deletes its pidfile, so make a copy.
 AT_CHECK([cp pid pid2])
 AT_CHECK([kill -0 `cat pid2`])
-AT_CHECK([[test-jsonrpc notify unix:socket shutdown '[]']], [0], [], 
+AT_CHECK([[ovstest test-jsonrpc notify unix:socket shutdown '[]']], [0], [],
   [], [kill `cat pid2`])
 AT_CHECK(
   [pid=`cat pid2`
index d44bee0..0db2077 100644 (file)
@@ -1,5 +1,10 @@
 AT_BANNER([lacp])
 
+# Strips out Reciulation ID information since it may change over time.
+m4_define([STRIP_RECIRC_ID], [[sed '
+    s/Recirc-ID.*$/<del>/
+' ]])
+
 AT_SETUP([lacp - config])
 OVS_VSWITCHD_START([\
         add-port br0 p1 --\
@@ -113,6 +118,7 @@ slave: p2: expired attached
 AT_CHECK([ovs-appctl bond/show], [0], [dnl
 ---- bond ----
 bond_mode: active-backup
+bond may use recirculation: no, Recirc-ID : -1
 bond-hash-basis: 0
 updelay: 0 ms
 downdelay: 0 ms
@@ -182,8 +188,8 @@ done
 AT_CHECK(
   [ovs-appctl lacp/show bond0
 ovs-appctl lacp/show bond1
-ovs-appctl bond/show bond0
-ovs-appctl bond/show bond1], [0], [stdout])
+ovs-appctl bond/show bond0 | STRIP_RECIRC_ID
+ovs-appctl bond/show bond1 | STRIP_RECIRC_ID ], [0], [stdout])
 AT_CHECK([sed '/active slave/d' stdout], [0], [dnl
 ---- bond0 ----
        status: active negotiated
@@ -275,6 +281,7 @@ slave: p3: current attached
        partner state: activity timeout aggregation synchronized collecting distributing
 ---- bond0 ----
 bond_mode: balance-tcp
+bond may use recirculation: yes, <del>
 bond-hash-basis: 0
 updelay: 0 ms
 downdelay: 0 ms
@@ -288,6 +295,7 @@ slave p1: enabled
 
 ---- bond1 ----
 bond_mode: balance-tcp
+bond may use recirculation: yes, <del>
 bond-hash-basis: 0
 updelay: 0 ms
 downdelay: 0 ms
@@ -316,8 +324,8 @@ for i in `seq 0 40`; do ovs-appctl time/warp 100; done
 AT_CHECK(
   [ovs-appctl lacp/show bond0
 ovs-appctl lacp/show bond1
-ovs-appctl bond/show bond0
-ovs-appctl bond/show bond1], [0], [dnl
+ovs-appctl bond/show bond0 | STRIP_RECIRC_ID
+ovs-appctl bond/show bond1 | STRIP_RECIRC_ID ], [0], [dnl
 ---- bond0 ----
        status: active negotiated
        sys_id: aa:55:aa:55:00:00
@@ -408,6 +416,7 @@ slave: p3: current attached
        partner state: activity timeout aggregation synchronized collecting distributing
 ---- bond0 ----
 bond_mode: balance-tcp
+bond may use recirculation: yes, <del>
 bond-hash-basis: 0
 updelay: 0 ms
 downdelay: 0 ms
@@ -422,6 +431,7 @@ slave p1: enabled
 
 ---- bond1 ----
 bond_mode: balance-tcp
+bond may use recirculation: yes, <del>
 bond-hash-basis: 0
 updelay: 0 ms
 downdelay: 0 ms
@@ -442,8 +452,8 @@ for i in `seq 0 40`; do ovs-appctl time/warp 100; done
 AT_CHECK(
   [ovs-appctl lacp/show bond0
 ovs-appctl lacp/show bond1
-ovs-appctl bond/show bond0
-ovs-appctl bond/show bond1], [0], [dnl
+ovs-appctl bond/show bond0 | STRIP_RECIRC_ID
+ovs-appctl bond/show bond1 | STRIP_RECIRC_ID ], [0], [dnl
 ---- bond0 ----
        status: active negotiated
        sys_id: aa:55:aa:55:00:00
@@ -534,6 +544,7 @@ slave: p3: current attached
        partner state: activity timeout aggregation synchronized collecting distributing
 ---- bond0 ----
 bond_mode: balance-tcp
+bond may use recirculation: yes, <del>
 bond-hash-basis: 0
 updelay: 0 ms
 downdelay: 0 ms
@@ -548,6 +559,7 @@ slave p1: enabled
 
 ---- bond1 ----
 bond_mode: balance-tcp
+bond may use recirculation: yes, <del>
 bond-hash-basis: 0
 updelay: 0 ms
 downdelay: 0 ms
index cae401f..7245295 100644 (file)
@@ -216,7 +216,8 @@ done
 ovs-appctl time/warp 5000
 ovs-appctl time/warp 5000
 ovs-appctl time/warp 5000
-    AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
+sleep 1
+AT_CHECK([ovs-ofctl dump-flows br0 table=1 | ofctl_strip | sort], [0], [dnl
  table=1, priority=0 actions=FLOOD
 NXST_FLOW reply:
 ])
@@ -345,7 +346,13 @@ done
 for i in `seq 1 10`; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:06,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'
     ovs-appctl time/warp 1000
-    if [[ $i -eq 1 ]]; then
+    # Note: netdev-dummy/receive merely queues the packet.
+    # We need to wait for other thread to process the packet
+    # and update the flow's 'used' for the packet.
+    # (i % 3 == 0) below is somehow arbitrary but chosen to ensure
+    # that we update the flow's 'used' frequently enough to prevent
+    # idle_timeout.
+    if [[ $i -eq 1 -o $((i % 3)) -eq 0 ]]; then
         sleep 1
     fi
 done
@@ -402,10 +409,38 @@ for i in `seq 1 10`; do
     # it's difficult to predict the exact timing of rule expiry
     # because it's affected by flow dumper thread via udpif_dump_seq.
     # hard_timeout value for this test was chosen to overcome the uncertainty.
-    if [[ $i -eq 1 -o $i -eq 6 -o $i -eq 7 ]]; then
+    #
+    # receive #1  learn, install flow with hard_timeout=10
+    #  sleep to ensure the flow installation
+    #  (warp, timeout left 8s)
+    # receive #2   the learned flow
+    #  (warp, timeout left 6s)
+    # receive #3
+    #  (warp, timeout left 4s)
+    # receive #4
+    #  (warp, timeout left 2s)
+    # receive #5
+    #  (warp, timeout left 0s)
+    #  NOTE: OVS does not consider this expired yet.  cf. rule_expire()
+    # receive #6
+    #  (warp, timeout left -2s)
+    #  sleep to ensure flow expiration
+    # receive #7  learn, install flow with hard_timeout=10
+    #  sleep to ensure the flow installation
+    #  (warp, timeout left 8s)
+    # receive #8
+    #  (warp, timeout left 6s)
+    # receive #9
+    #  (warp, timeout left 4s)
+    # receive #10
+    #  (warp, timeout left 2s)
+    if [[ $i -eq 1 -o $i -eq 7 ]]; then
         sleep 1
     fi
     ovs-appctl time/warp 2000
+    if [[ $i -eq 6 ]]; then
+        sleep 1
+    fi
 done
 
 # Check that the first packet of each flow went out port 2 and the rest out
index b0ccd40..8aeec48 100644 (file)
@@ -2,44 +2,44 @@ AT_BANNER([library unit tests])
 
 AT_SETUP([test flow extractor])
 AT_CHECK([$PERL `which flowgen.pl` >/dev/null 3>flows 4>pcap])
-AT_CHECK([test-flows <flows 3<pcap], [0], [checked 247 packets, 0 errors
+AT_CHECK([ovstest test-flows <flows 3<pcap], [0], [checked 247 packets, 0 errors
 ])
 AT_CLEANUP
 
 AT_SETUP([test TCP/IP checksumming])
-AT_CHECK([test-csum], [0], [....#....#....###................................#................................#
+AT_CHECK([ovstest test-csum], [0], [....#....#....###................................#................................#
 ])
 AT_CLEANUP
 
 AT_SETUP([test hash functions])
-AT_CHECK([test-hash])
+AT_CHECK([ovstest test-hash])
 AT_CLEANUP
 
 AT_SETUP([test hash map])
-AT_CHECK([test-hmap], [0], [.........
+AT_CHECK([ovstest test-hmap], [0], [.........
 ])
 AT_CLEANUP
 
 AT_SETUP([test hash index])
-AT_CHECK([test-hindex], [0], [.....................
+AT_CHECK([ovstest test-hindex], [0], [.....................
 ])
 AT_CLEANUP
 
 AT_SETUP([test atomic operations])
-AT_CHECK([test-atomic])
+AT_CHECK([ovstest test-atomic])
 AT_CLEANUP
 
 AT_SETUP([test linked lists])
-AT_CHECK([test-list], [0], [..
+AT_CHECK([ovstest test-list], [0], [..
 ])
 AT_CLEANUP
 
 AT_SETUP([test packet library])
-AT_CHECK([test-packets])
+AT_CHECK([ovstest test-packets])
 AT_CLEANUP
 
 AT_SETUP([test SHA-1])
-AT_CHECK([test-sha1], [0], [.........
+AT_CHECK([ovstest test-sha1], [0], [.........
 ])
 AT_CLEANUP
 
@@ -54,11 +54,11 @@ AT_CLEANUP
 
 AT_SETUP([test byte order conversion])
 AT_KEYWORDS([byte order])
-AT_CHECK([test-byte-order])
+AT_CHECK([ovstest test-byte-order])
 AT_CLEANUP
 
 AT_SETUP([test random number generator])
-AT_CHECK([test-random], [0], [dnl
+AT_CHECK([ovstest test-random], [0], [dnl
 average=7fa2014f
 
 bit      0     1
@@ -124,11 +124,11 @@ m4_foreach(
    [ovs_scan]],
   [AT_SETUP([testname[()] function])
    AT_KEYWORDS([testname])
-   AT_CHECK([test-util testname], [0], [], [])
+   AT_CHECK([ovstest test-util testname], [0], [], [])
    AT_CLEANUP])
 
 AT_SETUP([test unix socket, short pathname - C])
-AT_CHECK([test-unix-socket x])
+AT_CHECK([ovstest test-unix-socket x])
 AT_CLEANUP
 
 dnl Unix sockets with long names are problematic because the name has to
@@ -141,7 +141,7 @@ dnl Linux has a 108 byte limit; this is 150 bytes long.
 longname=012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
 mkdir $longname
 cd $longname
-AT_CHECK([test-unix-socket ../$longname/socket socket])
+AT_CHECK([ovstest test-unix-socket ../$longname/socket socket])
 AT_CLEANUP
 
 AT_SETUP([test unix socket, short pathname - Python])
@@ -165,7 +165,7 @@ AT_CLEANUP
 
 AT_SETUP([ovs_assert])
 OVS_LOGDIR=`pwd`; export OVS_LOGDIR
-AT_CHECK([test-util -voff -vfile:info '-vPATTERN:file:%c|%p|%m' --log-file assert || kill -l $?],
+AT_CHECK([ovstest test-util -voff -vfile:info '-vPATTERN:file:%c|%p|%m' --log-file assert || kill -l $?],
   [0], [ABRT
 ], [stderr])
 
@@ -183,5 +183,5 @@ AT_CHECK([sed 's/.*: //
 AT_CLEANUP
 
 AT_SETUP([snprintf])
-AT_CHECK([test-util snprintf])
+AT_CHECK([ovstest test-util snprintf])
 AT_CLEANUP
index 2644d3f..2e2a74b 100644 (file)
@@ -3,7 +3,7 @@ AT_BANNER([lockfile unit tests])
 m4_define([CHECK_LOCKFILE],
   [AT_SETUP([m4_translit([$1], [_], [ ])])
    AT_KEYWORDS([lockfile])
-   AT_CHECK([test-lockfile $1], [0], [$1: success (m4_if(
+   AT_CHECK([ovstest test-lockfile $1], [0], [$1: success (m4_if(
      [$2], [1], [$2 child], [$2 children]))
 ], [stderr])
    AT_CHECK([sed 's/pid [[0-9]]*/pid <pid>/' stderr], [0], [$3])
@@ -14,12 +14,12 @@ CHECK_LOCKFILE([lock_and_unlock], [0])
 CHECK_LOCKFILE([lock_and_unlock_twice], [0])
 
 CHECK_LOCKFILE([lock_blocks_same_process], [0],
-  [lockfile|WARN|.file.~lock~: failed to lock file: Resource deadlock avoided
+  [lockfile|WARN|.file.~lock~: cannot lock file because this process has already locked it
 ])
 
 CHECK_LOCKFILE([lock_blocks_same_process_twice], [0],
-  [lockfile|WARN|.file.~lock~: failed to lock file: Resource deadlock avoided
-lockfile|WARN|.file.~lock~: failed to lock file: Resource deadlock avoided
+  [lockfile|WARN|.file.~lock~: cannot lock file because this process has already locked it
+lockfile|WARN|.file.~lock~: cannot lock file because this process has already locked it
 ])
 
 CHECK_LOCKFILE([lock_blocks_other_process], [1],
@@ -28,7 +28,7 @@ lockfile|WARN|.file.~lock~: cannot lock file because it is already locked by pid
 ])
 
 CHECK_LOCKFILE([lock_twice_blocks_other_process], [1],
-  [lockfile|WARN|.file.~lock~: failed to lock file: Resource deadlock avoided
+  [lockfile|WARN|.file.~lock~: cannot lock file because this process has already locked it
 lockfile|WARN|.file.~lock~: child does not inherit lock
 lockfile|WARN|.file.~lock~: cannot lock file because it is already locked by pid <pid>
 ])
@@ -36,16 +36,16 @@ lockfile|WARN|.file.~lock~: cannot lock file because it is already locked by pid
 CHECK_LOCKFILE([lock_and_unlock_allows_other_process], [1])
 
 CHECK_LOCKFILE([lock_multiple], [0],
-  [lockfile|WARN|.a.~lock~: failed to lock file: Resource deadlock avoided
+  [lockfile|WARN|.a.~lock~: cannot lock file because this process has already locked it
 ])
 
 CHECK_LOCKFILE([lock_symlink], [0],
-  [lockfile|WARN|.a.~lock~: failed to lock file: Resource deadlock avoided
-lockfile|WARN|.b.~lock~: failed to lock file: Resource deadlock avoided
-lockfile|WARN|.b.~lock~: failed to lock file: Resource deadlock avoided
-lockfile|WARN|.a.~lock~: failed to lock file: Resource deadlock avoided
+  [lockfile|WARN|.a.~lock~: cannot lock file because this process has already locked it
+lockfile|WARN|.b.~lock~: cannot lock file because this process has already locked it
+lockfile|WARN|.b.~lock~: cannot lock file because this process has already locked it
+lockfile|WARN|.a.~lock~: cannot lock file because this process has already locked it
 ])
 
 CHECK_LOCKFILE([lock_symlink_to_dir], [0],
-  [lockfile|WARN|dir/.b.~lock~: failed to lock file: Resource deadlock avoided
+  [lockfile|WARN|dir/.b.~lock~: cannot lock file because this process has already locked it
 ])
index 361c2c4..b5a3099 100644 (file)
@@ -8,7 +8,7 @@ AT_BANNER([multipath link selection])
 # if the test does fail.
 
 AT_SETUP([modulo_n multipath link selection])
-AT_CHECK([[test-multipath 'eth_src,50,modulo_n,1,0,NXM_NX_REG0[]']],
+AT_CHECK([[ovstest test-multipath 'eth_src,50,modulo_n,1,0,NXM_NX_REG0[]']],
   [0], [ignore])
 # 1 ->  2: disruption=0.50 (perfect=0.50); stddev/expected=0.0000
 # 2 ->  3: disruption=0.66 (perfect=0.33); stddev/expected=0.0023
@@ -76,7 +76,7 @@ AT_CHECK([[test-multipath 'eth_src,50,modulo_n,1,0,NXM_NX_REG0[]']],
 AT_CLEANUP
 
 AT_SETUP([hash_threshold multipath link selection])
-AT_CHECK([[test-multipath 'eth_src,50,hash_threshold,1,0,NXM_NX_REG0[]']],
+AT_CHECK([[ovstest test-multipath 'eth_src,50,hash_threshold,1,0,NXM_NX_REG0[]']],
   [0], [ignore])
 # 1 ->  2: disruption=0.50 (perfect=0.50); stddev/expected=0.0000
 # 2 ->  3: disruption=0.50 (perfect=0.33); stddev/expected=0.0056
@@ -144,7 +144,7 @@ AT_CHECK([[test-multipath 'eth_src,50,hash_threshold,1,0,NXM_NX_REG0[]']],
 AT_CLEANUP
 
 AT_SETUP([hrw multipath link selection])
-AT_CHECK([[test-multipath 'eth_src,50,hrw,1,0,NXM_NX_REG0[]']],
+AT_CHECK([[ovstest test-multipath 'eth_src,50,hrw,1,0,NXM_NX_REG0[]']],
   [0], [ignore])
 # 1 ->  2: disruption=0.50 (perfect=0.50); stddev/expected=0.0000
 # 2 ->  3: disruption=0.33 (perfect=0.33); stddev/expected=0.0033
@@ -212,7 +212,7 @@ AT_CHECK([[test-multipath 'eth_src,50,hrw,1,0,NXM_NX_REG0[]']],
 AT_CLEANUP
 
 AT_SETUP([iter_hash multipath link selection])
-AT_CHECK([[test-multipath 'eth_src,50,iter_hash,1,0,NXM_NX_REG0[]']],
+AT_CHECK([[ovstest test-multipath 'eth_src,50,iter_hash,1,0,NXM_NX_REG0[]']],
   [0], [ignore])
 # 1 ->  2: disruption=0.50 (perfect=0.50); stddev/expected=0.0000
 # 2 ->  3: disruption=0.42 (perfect=0.33); stddev/expected=0.0034
index a968dd3..34bc187 100644 (file)
@@ -91,7 +91,7 @@ s/mpls(label=100,tc=7,ttl=100,bos=0)/mpls(lse0=0x64e64,lse1=0,lse2=0)/
 s/mpls(label=1000,tc=4,ttl=200,bos=0)/mpls(lse0=0x3e88c8,lse1=0,lse2=0)/
 }' < odp-in.txt > odp-out.txt
 
-AT_CHECK_UNQUOTED([test-odp parse-keys < odp-in.txt], [0], [`cat odp-out.txt`
+AT_CHECK_UNQUOTED([ovstest test-odp parse-keys < odp-in.txt], [0], [`cat odp-out.txt`
 ])
 AT_CLEANUP
 
@@ -157,7 +157,7 @@ sed -n 's/,frag=no),/,frag=first),/p' odp-base.txt
  echo '# Valid forms with IP later fragment.'
 sed -n 's/,frag=no),.*/,frag=later)/p' odp-base.txt) > odp.txt
 AT_CAPTURE_FILE([odp.txt])
-AT_CHECK_UNQUOTED([test-odp parse-wc-keys < odp.txt], [0], [`cat odp.txt`
+AT_CHECK_UNQUOTED([ovstest test-odp parse-wc-keys < odp.txt], [0], [`cat odp.txt`
 ])
 AT_CLEANUP
 
@@ -204,25 +204,25 @@ AT_DATA([odp-tcp6.txt], [dnl
 in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1/::255,dst=::2/::255,label=0/0xf0,proto=10/0xf0,tclass=0x70/0xf0,hlimit=128/0xf0,frag=no/0xf0)
 in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=6,tclass=0,hlimit=128,frag=no),tcp(src=80/0xff00,dst=8080/0xff)
 ])
-AT_CHECK_UNQUOTED([test-odp parse-filter filter='dl_type=0x1235' < odp-base.txt], [0], [`cat odp-eth-type.txt`
+AT_CHECK_UNQUOTED([ovstest test-odp parse-filter filter='dl_type=0x1235' < odp-base.txt], [0], [`cat odp-eth-type.txt`
 ])
-AT_CHECK_UNQUOTED([test-odp parse-filter filter='dl_vlan=99' < odp-vlan-base.txt], [0], [`cat odp-vlan.txt`
+AT_CHECK_UNQUOTED([ovstest test-odp parse-filter filter='dl_vlan=99' < odp-vlan-base.txt], [0], [`cat odp-vlan.txt`
 ])
-AT_CHECK_UNQUOTED([test-odp parse-filter filter='dl_vlan=99,ip' < odp-vlan-base.txt], [0], [`cat odp-vlan.txt`
+AT_CHECK_UNQUOTED([ovstest test-odp parse-filter filter='dl_vlan=99,ip' < odp-vlan-base.txt], [0], [`cat odp-vlan.txt`
 ])
-AT_CHECK_UNQUOTED([test-odp parse-filter filter='ip,nw_src=35.8.2.199' < odp-base.txt], [0], [`cat odp-ipv4.txt`
+AT_CHECK_UNQUOTED([ovstest test-odp parse-filter filter='ip,nw_src=35.8.2.199' < odp-base.txt], [0], [`cat odp-ipv4.txt`
 ])
-AT_CHECK_UNQUOTED([test-odp parse-filter filter='ip,nw_dst=172.16.0.199' < odp-base.txt], [0], [`cat odp-ipv4.txt`
+AT_CHECK_UNQUOTED([ovstest test-odp parse-filter filter='ip,nw_dst=172.16.0.199' < odp-base.txt], [0], [`cat odp-ipv4.txt`
 ])
-AT_CHECK_UNQUOTED([test-odp parse-filter filter='dl_type=0x0800,nw_src=35.8.2.199,nw_dst=172.16.0.199' < odp-base.txt], [0], [`cat odp-ipv4.txt`
+AT_CHECK_UNQUOTED([ovstest test-odp parse-filter filter='dl_type=0x0800,nw_src=35.8.2.199,nw_dst=172.16.0.199' < odp-base.txt], [0], [`cat odp-ipv4.txt`
 ])
-AT_CHECK_UNQUOTED([test-odp parse-filter filter='icmp,nw_src=35.8.2.199' < odp-base.txt], [0], [`cat odp-icmp.txt`
+AT_CHECK_UNQUOTED([ovstest test-odp parse-filter filter='icmp,nw_src=35.8.2.199' < odp-base.txt], [0], [`cat odp-icmp.txt`
 ])
-AT_CHECK_UNQUOTED([test-odp parse-filter filter='arp,arp_spa=1.2.3.5' < odp-base.txt], [0], [`cat odp-arp.txt`
+AT_CHECK_UNQUOTED([ovstest test-odp parse-filter filter='arp,arp_spa=1.2.3.5' < odp-base.txt], [0], [`cat odp-arp.txt`
 ])
-AT_CHECK_UNQUOTED([test-odp parse-filter filter='tcp,tp_src=90' < odp-base.txt], [0], [`cat odp-tcp.txt`
+AT_CHECK_UNQUOTED([ovstest test-odp parse-filter filter='tcp,tp_src=90' < odp-base.txt], [0], [`cat odp-tcp.txt`
 ])
-AT_CHECK_UNQUOTED([test-odp parse-filter filter='tcp6,tp_src=90' < odp-base.txt], [0], [`cat odp-tcp6.txt`
+AT_CHECK_UNQUOTED([ovstest test-odp parse-filter filter='tcp6,tp_src=90' < odp-base.txt], [0], [`cat odp-tcp6.txt`
 ])
 AT_CLEANUP
 
@@ -254,7 +254,7 @@ sample(sample=9.7%,actions(1,2,3,push_vlan(vid=1,pcp=2)))
 set(tunnel(tun_id=0xabcdef1234567890,src=1.1.1.1,dst=2.2.2.2,tos=0x0,ttl=64,flags(df,csum,key)))
 set(tunnel(tun_id=0xabcdef1234567890,src=1.1.1.1,dst=2.2.2.2,tos=0x0,ttl=64,flags(key)))
 ])
-AT_CHECK_UNQUOTED([test-odp parse-actions < actions.txt], [0],
+AT_CHECK_UNQUOTED([ovstest test-odp parse-actions < actions.txt], [0],
   [`cat actions.txt`
 ])
 AT_CLEANUP
index af5fd8f..b12b4fe 100644 (file)
@@ -11,6 +11,15 @@ m4_define([STRIP_XOUT], [[sed '
     s/packets:[0-9]*/packets:0/
     s/bytes:[0-9]*/bytes:0/
 ' | sort]])
+m4_define([FILTER_FLOW_INSTALL], [[
+grep ' put' | sed '
+    s/.*put\[create\]\[modify\] //
+' | sort | uniq]])
+m4_define([FILTER_FLOW_DUMP], [[
+grep 'flow_dump ' | sed '
+    s/.*flow_dump //
+    s/used:[0-9]*\.[0-9]*/used:0.0/
+' | sort | uniq]])
 
 AT_SETUP([ofproto-dpif - dummy interface])
 # Create br0 with interfaces p1 and p7
@@ -25,6 +34,7 @@ OVS_VSWITCHD_START(
                   fail-mode=secure -- \
    add-port br1 p2 -- set interface p2 type=dummy options:stream=unix:$OVS_RUNDIR/p0.sock ofport_request=2 -- \
    add-port br1 p8 -- set interface p8 ofport_request=8 type=dummy --])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 
 AT_CHECK([ovs-ofctl add-flow br0 action=normal])
 AT_CHECK([ovs-ofctl add-flow br1 action=normal])
@@ -35,18 +45,158 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p8 'in_port(8),eth(src=50:54:00:00:00:
 ovs-appctl time/warp 100
 sleep 1  # wait for forwarders process packets
 
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3/0.0.0.0,dst=10.0.0.4/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
-skb_priority(0),in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3/0.0.0.0,dst=10.0.0.4/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(2),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3/0.0.0.0,dst=10.0.0.4/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
 ])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([ofproto-dpif, active-backup bonding])
+# Create br0 with interfaces p1, p2 and p7, creating bond0 with p1 and p2
+#    and br1 with interfaces p3, p4 and p8.
+# toggle p1,p2 of bond0 up and down to test bonding in active-backup mode.
+OVS_VSWITCHD_START(
+  [add-bond br0 bond0 p1 p2 bond_mode=active-backup --\
+   set interface p1 type=dummy options:pstream=punix:$OVS_RUNDIR/p1.sock ofport_request=1 -- \
+   set interface p2 type=dummy options:pstream=punix:$OVS_RUNDIR/p2.sock ofport_request=2 -- \
+   add-port br0 p7 -- set interface p7 ofport_request=7 type=dummy -- \
+   add-br br1 -- \
+   set bridge br1 other-config:hwaddr=aa:66:aa:66:00:00 -- \
+   set bridge br1 datapath-type=dummy other-config:datapath-id=1234 \
+                  fail-mode=secure -- \
+   add-port br1 p3 -- set interface p3 type=dummy options:stream=unix:$OVS_RUNDIR/p1.sock ofport_request=3 -- \
+   add-port br1 p4 -- set interface p4 type=dummy options:stream=unix:$OVS_RUNDIR/p2.sock ofport_request=4 -- \
+   add-port br1 p8 -- set interface p8 ofport_request=8 type=dummy --])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 
-AT_CHECK([ovs-appctl dpif/dump-flows br1 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(2),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
-skb_priority(0),in_port(8),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3/0.0.0.0,dst=10.0.0.4/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
+AT_CHECK([ovs-ofctl add-flow br0 action=normal])
+AT_CHECK([ovs-ofctl add-flow br1 action=normal])
+ovs-appctl netdev-dummy/set-admin-state up
+ovs-appctl time/warp 100
+ovs-appctl netdev-dummy/set-admin-state p2 down
+ovs-appctl time/stop
+ovs-appctl time/warp 100
+AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
+AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(7),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
+ovs-appctl time/warp 100
+ovs-appctl netdev-dummy/set-admin-state p2 up
+ovs-appctl netdev-dummy/set-admin-state p1 down
+ovs-appctl time/warp 100
+AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0d),eth_type(0x0800),ipv4(src=10.0.0.5,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
+AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0e),eth_type(0x0800),ipv4(src=10.0.0.6,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
+ovs-appctl time/warp 100
+ovs-appctl time/warp 100
+AT_CHECK([cat ovs-vswitchd.log | grep 'in_port([[348]])' | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(3),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(3),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.3/0.0.0.0,dst=10.0.0.4/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(4),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0d),eth_type(0x0800),ipv4(src=10.0.0.5/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(4),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0e),eth_type(0x0800),ipv4(src=10.0.0.6/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(4),eth(src=50:54:00:00:00:09,dst=ff:ff:ff:ff:ff:ff),eth_type(0x8035),arp(sip=0.0.0.0/0.0.0.0,tip=0.0.0.0/0.0.0.0,op=3/0,sha=50:54:00:00:00:09/00:00:00:00:00:00,tha=50:54:00:00:00:09/00:00:00:00:00:00), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(4),eth(src=50:54:00:00:00:0b,dst=ff:ff:ff:ff:ff:ff),eth_type(0x8035),arp(sip=0.0.0.0/0.0.0.0,tip=0.0.0.0/0.0.0.0,op=3/0,sha=50:54:00:00:00:0b/00:00:00:00:00:00,tha=50:54:00:00:00:0b/00:00:00:00:00:00), actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([ofproto-dpif, balance-slb bonding])
+# Create br0 with interfaces bond0(p1, p2, p3) and p7,
+#    and br1 with interfaces p4, p5, p6 and p8.
+#    p1 <-> p4, p2 <-> p5, p3 <-> p6
+# Send some traffic, make sure the traffic are spread based on source mac.
+OVS_VSWITCHD_START(
+  [add-bond br0 bond0 p1 p2 p3 bond_mode=balance-slb --\
+   set interface p1 type=dummy options:pstream=punix:$OVS_RUNDIR/p1.sock ofport_request=1 -- \
+   set interface p2 type=dummy options:pstream=punix:$OVS_RUNDIR/p2.sock ofport_request=2 -- \
+   set interface p3 type=dummy options:pstream=punix:$OVS_RUNDIR/p3.sock ofport_request=3 -- \
+   add-port br0 p7 -- set interface p7 ofport_request=7 type=dummy -- \
+   add-br br1 -- \
+   set bridge br1 other-config:hwaddr=aa:66:aa:66:00:00 -- \
+   set bridge br1 datapath-type=dummy other-config:datapath-id=1234 \
+                  fail-mode=secure -- \
+   add-port br1 p4 -- set interface p4 type=dummy options:stream=unix:$OVS_RUNDIR/p1.sock ofport_request=4 -- \
+   add-port br1 p5 -- set interface p5 type=dummy options:stream=unix:$OVS_RUNDIR/p2.sock ofport_request=5 -- \
+   add-port br1 p6 -- set interface p6 type=dummy options:stream=unix:$OVS_RUNDIR/p3.sock ofport_request=6 -- \
+   add-port br1 p8 -- set interface p8 ofport_request=8 type=dummy --])
+
+AT_CHECK([ovs-ofctl add-flow br0 action=normal])
+AT_CHECK([ovs-ofctl add-flow br1 action=normal])
+AT_CHECK([ovs-appctl netdev-dummy/set-admin-state up], 0, [OK
+])
+ovs-appctl netdev-dummy/set-admin-state up
+ovs-appctl time/stop
+ovs-appctl time/warp 100
+(
+for i in `seq 0 100 |xargs printf '%02x\n'`;
+    do
+    pkt="in_port(7),eth(src=50:54:00:00:00:$i,dst=50:54:00:00:01:00),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)"
+    AT_CHECK([ovs-appctl netdev-dummy/receive p7 $pkt])
+    done
+)
+ovs-appctl time/warp 100
+AT_CHECK([ovs-appctl dpif/dump-flows br1 > br1_flows.txt])
+# Make sure there is resonable distribution to all three ports.
+# We don't want to make this check precise, in case hash function changes.
+AT_CHECK([test `egrep 'in_port\(4\)' br1_flows.txt |wc -l` -gt 3])
+AT_CHECK([test `egrep 'in_port\(5\)' br1_flows.txt |wc -l` -gt 3])
+AT_CHECK([test `egrep 'in_port\(6\)' br1_flows.txt |wc -l` -gt 3])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([ofproto-dpif, balance-tcp bonding])
+# Create br0 with interfaces bond0(p1, p2, p3) and p7,
+#    and br1 with interfaces bond1(p4, p5, p6) and p8.
+#    bond0 <-> bond1
+# Send some traffic, make sure the traffic are spread based on L4 headers.
+OVS_VSWITCHD_START(
+  [add-bond br0 bond0 p1 p2 p3 bond_mode=balance-tcp lacp=active \
+        other-config:lacp-time=fast other-config:bond-rebalance-interval=0 --\
+   set interface p1 type=dummy options:pstream=punix:$OVS_RUNDIR/p1.sock ofport_request=1 -- \
+   set interface p2 type=dummy options:pstream=punix:$OVS_RUNDIR/p2.sock ofport_request=2 -- \
+   set interface p3 type=dummy options:pstream=punix:$OVS_RUNDIR/p3.sock ofport_request=3 -- \
+   add-port br0 p7 -- set interface p7 ofport_request=7 type=dummy -- \
+   add-br br1 -- \
+   set bridge br1 other-config:hwaddr=aa:66:aa:66:00:00 -- \
+   set bridge br1 datapath-type=dummy other-config:datapath-id=1234 \
+                  fail-mode=secure -- \
+   add-bond br1 bond1 p4 p5 p6 bond_mode=balance-tcp lacp=active \
+        other-config:lacp-time=fast other-config:bond-rebalance-interval=0 --\
+   set interface p4 type=dummy options:stream=unix:$OVS_RUNDIR/p1.sock ofport_request=4 -- \
+   set interface p5 type=dummy options:stream=unix:$OVS_RUNDIR/p2.sock ofport_request=5 -- \
+   set interface p6 type=dummy options:stream=unix:$OVS_RUNDIR/p3.sock ofport_request=6 -- \
+   add-port br1 p8 -- set interface p8 ofport_request=8 type=dummy --])
+AT_CHECK([ovs-appctl netdev-dummy/set-admin-state up], 0, [OK
+])
+AT_CHECK([ovs-ofctl add-flow br0 action=normal])
+AT_CHECK([ovs-ofctl add-flow br1 action=normal])
+AT_CHECK([ovs-appctl upcall/disable-megaflows], [0], [megaflows disabled
+], [])
+sleep 1;
+ovs-appctl time/stop
+ovs-appctl time/warp 100
+ovs-appctl lacp/show > lacp.txt
+ovs-appctl bond/show > bond.txt
+(
+for i in `seq 10 100` ;
+    do
+    pkt="in_port(7),eth(src=50:54:00:00:00:05,dst=50:54:00:00:01:00),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=$i),tcp_flags(0x010)"
+    AT_CHECK([ovs-appctl netdev-dummy/receive p7 $pkt])
+    done
+)
+ovs-appctl time/warp 100
+ovs-appctl time/warp 100
+ovs-appctl time/warp 100
+AT_CHECK([ovs-appctl dpif/dump-flows br0 |grep tcp > br0_flows.txt])
+AT_CHECK([ovs-appctl dpif/dump-flows br1 |grep tcp > br1_flows.txt])
+# Make sure there is resonable distribution to all three ports.
+# We don't want to make this check precise, in case hash function changes.
+AT_CHECK([test `grep in_port.4 br1_flows.txt |wc -l` -gt 7])
+AT_CHECK([test `grep in_port.5 br1_flows.txt |wc -l` -gt 7])
+AT_CHECK([test `grep in_port.6 br1_flows.txt |wc -l` -gt 7])
+OVS_VSWITCHD_STOP()
+AT_CLEANUP
+
 AT_SETUP([ofproto-dpif - resubmit])
 OVS_VSWITCHD_START
 ADD_OF_PORTS([br0], [1], [10], [11], [12], [13], [14], [15],
@@ -91,8 +241,9 @@ table=2 ip actions=set_field:192.168.3.91->ip_src,output(11)
 ])
 AT_CHECK([ovs-ofctl -O OpenFlow12 add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=1,nw_tos=0,nw_ttl=128,icmp_type=8,icmp_code=0'], [0], [stdout])
-AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: 10,set(ipv4(src=192.168.3.91,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no)),11,set(ipv4(src=192.168.3.90,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no)),13
+AT_CHECK([tail -2 stdout], [0],
+  [Megaflow: recirc_id=0,skb_priority=0,icmp,in_port=1,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=128
+Datapath actions: 10,set(ipv4(src=192.168.3.91,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no)),11,set(ipv4(src=192.168.3.90,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no)),13
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -102,12 +253,13 @@ OVS_VSWITCHD_START
 ADD_OF_PORTS([br0], [1], [10], [11], [12])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1,ip actions=output(10),write_actions(set_field:192.168.3.90->ip_src,output(12)),goto_table(1)
-table=1 ip actions=set_field:192.168.3.91->ip_src,output(11),clear_actions
+table=1 tcp actions=set_field:91->tp_src,output(11),clear_actions
 ])
 AT_CHECK([ovs-ofctl -O OpenFlow12 add-flows br0 flows.txt])
-AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=1,nw_tos=0,nw_ttl=128,icmp_type=8,icmp_code=0'], [0], [stdout])
-AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: 10,set(ipv4(src=192.168.3.91,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no)),11
+AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=9'], [0], [stdout])
+AT_CHECK([tail -2 stdout], [0],
+  [Megaflow: recirc_id=0,skb_priority=0,tcp,in_port=1,nw_frag=no,tp_src=8,tp_dst=9
+Datapath actions: 10,set(tcp(src=91,dst=9)),11
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -129,8 +281,9 @@ ADD_OF_PORTS([br0], [1], [10], [11])
 AT_CHECK([ovs-ofctl -O OpenFlow12 add-group br0 'group_id=1234,type=all,bucket=output:10,set_field:192.168.3.90->ip_src,bucket=output:11'])
 AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 'ip actions=group:1234'])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=1,nw_tos=0,nw_ttl=128,icmp_type=8,icmp_code=0'], [0], [stdout])
-AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: set(ipv4(src=192.168.3.90,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no)),10,set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no)),11
+AT_CHECK([tail -2 stdout], [0],
+  [Megaflow: recirc_id=0,skb_priority=0,icmp,in_port=1,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=128
+Datapath actions: set(ipv4(src=192.168.3.90,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no)),10,set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no)),11
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -153,8 +306,9 @@ ADD_OF_PORTS([br0], [1], [10], [11])
 AT_CHECK([ovs-ofctl -O OpenFlow12 add-group br0 'group_id=1234,type=all,bucket=output:10,set_field:192.168.3.90->ip_src,bucket=output:11'])
 AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 'ip actions=write_actions(group:1234)'])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=1,nw_tos=0,nw_ttl=128,icmp_type=8,icmp_code=0'], [0], [stdout])
-AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: set(ipv4(src=192.168.3.90,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no)),10,set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no)),11
+AT_CHECK([tail -2 stdout], [0],
+  [Megaflow: recirc_id=0,skb_priority=0,icmp,in_port=1,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=128
+Datapath actions: set(ipv4(src=192.168.3.90,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no)),10,set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no)),11
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -311,18 +465,21 @@ table=1 in_port=1 action=dec_ttl,output:3
 ])
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=111,tos=0,ttl=2,frag=no)' -generate], [0], [stdout])
-AT_CHECK([tail -3 stdout], [0],
-  [Datapath actions: set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=111,tos=0,ttl=1,frag=no)),2,4
+AT_CHECK([tail -4 stdout], [0],
+  [Megaflow: recirc_id=0,skb_priority=0,ip,in_port=1,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=111,nw_tos=0,nw_ecn=0,nw_ttl=2
+Datapath actions: set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=111,tos=0,ttl=1,frag=no)),2,4
 This flow is handled by the userspace slow path because it:
        - Sends "packet-in" messages to the OpenFlow controller.
 ])
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=111,tos=0,ttl=3,frag=no)'], [0], [stdout])
-AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=111,tos=0,ttl=2,frag=no)),2,set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=111,tos=0,ttl=1,frag=no)),3,4
+AT_CHECK([tail -2 stdout], [0],
+  [Megaflow: recirc_id=0,skb_priority=0,ip,in_port=1,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=111,nw_tos=0,nw_ecn=0,nw_ttl=3
+Datapath actions: set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=111,tos=0,ttl=2,frag=no)),2,set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=111,tos=0,ttl=1,frag=no)),3,4
 ])
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=128,frag=no)'], [0], [stdout])
-AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: set(ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=127,frag=no)),2,set(ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=126,frag=no)),3,4
+AT_CHECK([tail -2 stdout], [0],
+  [Megaflow: recirc_id=0,skb_priority=0,ipv6,in_port=1,ipv6_src=::1,ipv6_dst=::2,ipv6_label=0x00000,nw_proto=10,nw_tos=112,nw_ecn=0,nw_ttl=128
+Datapath actions: set(ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=127,frag=no)),2,set(ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=126,frag=no)),3,4
 ])
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
@@ -336,6 +493,56 @@ ip,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+dnl A dec_ttl action at offset 32 in ofpacts will cause the ofpacts
+dnl buffer to be resized just before pushing the id of the dec_ttl action.
+dnl Thus the implementation must account for this by using the
+dnl reallocated buffer rather than the original buffer.
+dnl
+dnl A number of similar rules are added to try and exercise
+dnl xrealloc sufficiently that it returns a different base pointer
+AT_SETUP([ofproto-dpif - dec_ttl without arguments at offset 32 in ofpacts])
+OVS_VSWITCHD_START
+ADD_OF_PORTS([br0], [1])
+(for i in `seq 0 255`; do
+  printf "dl_src=10:11:11:11:11:%02x actions=output:1,output:1,output:1,dec_ttl,controller\n" $i
+ done) > flows.txt
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+dnl A dec_ttl action at offset 32 in ofpacts will cause the ofpacts
+dnl buffer to be resized just before pushing the id of the dec_ttl action.
+dnl Thus the implementation must account for this by using the
+dnl reallocated buffer rather than the original buffer.
+dnl
+dnl A number of similar rules are added to try and exercise
+dnl xrealloc sufficiently that it returns a different base pointer
+AT_SETUP([ofproto-dpif - dec_ttl with arguments at offset 32 in ofpacts])
+OVS_VSWITCHD_START
+ADD_OF_PORTS([br0], [1])
+(for i in `seq 0 255`; do
+  printf "dl_src=10:11:11:11:11:%02x actions=output:1,output:1,output:1,dec_ttl(1),controller\n" $i
+ done) > flows.txt
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+dnl A note action at offset 24 in ofpacts will cause the ofpacts
+dnl buffer to be resized just before pushing the id of the dec_ttl action.
+dnl Thus the implementation must account for this by using the
+dnl reallocated buffer rather than the original buffer.
+dnl
+dnl A number of similar rules are added to try and exercise
+dnl xrealloc sufficiently that it returns a different base pointer
+AT_SETUP([ofproto-dpif - note at offset 24 in ofpacts])
+OVS_VSWITCHD_START
+ADD_OF_PORTS([br0], [1])
+(for i in `seq 0 255`; do
+  printf "dl_src=10:11:11:11:11:%02x actions=output:1,output:1,note:ff,controller\n" $i
+ done) > flows.txt
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
 
 AT_SETUP([ofproto-dpif - output, OFPP_NONE ingress port])
 OVS_VSWITCHD_START
@@ -368,8 +575,9 @@ AT_CHECK([ovs-vsctl -- \
         --id=@q1 create Queue dscp=1 --\
         --id=@q2 create Queue dscp=2], [0], [ignore])
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(9),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=1.1.1.1,dst=2.2.2.2,proto=1,tos=0xff,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
-AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: dnl
+AT_CHECK([tail -2 stdout], [0],
+  [Megaflow: recirc_id=0,skb_priority=0,icmp,in_port=9,nw_src=1.1.1.1,nw_dst=2.2.2.2,nw_tos=252,nw_ecn=3,nw_ttl=128
+Datapath actions: dnl
 100,dnl
 set(ipv4(src=1.1.1.1,dst=2.2.2.2,proto=1,tos=0x7,ttl=128,frag=no)),set(skb_priority(0x1)),1,dnl
 set(ipv4(src=1.1.1.1,dst=2.2.2.2,proto=1,tos=0xb,ttl=128,frag=no)),set(skb_priority(0x2)),1,dnl
@@ -440,7 +648,7 @@ AT_CHECK([tail -1 stdout], [0],
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
-AT_SETUP([ofproto-dpif - Table Miss - OFPTC_TABLE_MISS_CONTROLLER])
+AT_SETUP([ofproto-dpif - Default Table Miss - OF1.0 (OFPTC_TABLE_MISS_CONTROLLER)])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
@@ -453,7 +661,7 @@ AT_CHECK([ovs-ofctl monitor br0 65534 --detach --no-chdir --pidfile 2> ofctl_mon
 for i in 1 2 3 ; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
 done
-
+OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
@@ -474,6 +682,34 @@ NXST_FLOW reply:
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([ofproto-dpif - Default Table Miss - OF1.3 (OFPTC_TABLE_MISS_DROP)])
+OVS_VSWITCHD_START([dnl
+   add-port br0 p1 -- set Interface p1 type=dummy
+])
+ON_EXIT([kill `cat ovs-ofctl.pid`])
+
+AT_CAPTURE_FILE([ofctl_monitor.log])
+AT_CHECK([ovs-ofctl del-flows br0])
+
+AT_CHECK([ovs-ofctl monitor -OOpenFlow13 -P openflow10 br0 65534 --detach --no-chdir --pidfile 2> ofctl_monitor.log])
+
+dnl Test that missed packets are droped
+for i in 1 2 3 ; do
+    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
+done
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+])
+
+AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
+AT_CHECK([ovs-ofctl -OOpenFlow13 dump-flows br0 | ofctl_strip | sort], [0], [dnl
+OFPST_FLOW reply (OF1.3):
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_SETUP([ofproto-dpif - Table Miss - goto table and OFPTC_TABLE_MISS_CONTROLLER])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
@@ -488,7 +724,7 @@ AT_CHECK([ovs-ofctl monitor -P openflow10 br0 65534 --detach --no-chdir --pidfil
 for i in 1 2 3 ; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
 done
-
+OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
 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)
@@ -502,6 +738,7 @@ tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:0
 ])
 
 AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
+sleep 1  # wait for revalidator to update stats
 AT_CHECK([ovs-ofctl -OOpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
  n_packets=3, n_bytes=180, actions=goto_table:1
 OFPST_FLOW reply (OF1.2):
@@ -530,6 +767,7 @@ AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 ])
 
 AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
+sleep 1  # wait for revalidator to update stats
 AT_CHECK([ovs-ofctl -OOpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
  n_packets=3, n_bytes=180, actions=resubmit(1,1)
 OFPST_FLOW reply (OF1.2):
@@ -554,6 +792,7 @@ AT_CHECK([ovs-ofctl monitor br0 65534 --detach --no-chdir --pidfile 2> ofctl_mon
 for i in 1 2 3 ; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=10:11:11:11:11:11,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
 done
+OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
 
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
@@ -573,6 +812,7 @@ AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --no-chdir --pidfile 2> of
 for i in 1 2 3 ; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
 done
+OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
 
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
@@ -587,6 +827,7 @@ tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:0
 ])
 
 AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
+sleep 1  # wait for revalidator to update stats
 AT_CHECK([ovs-ofctl -OOpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
  table=1, n_packets=3, n_bytes=180, dl_src=10:11:11:11:11:11 actions=CONTROLLER:65535
 OFPST_FLOW reply (OF1.2):
@@ -615,7 +856,8 @@ AT_CHECK([ovs-ofctl monitor br0 65534 --detach --no-chdir --pidfile 2> ofctl_mon
 for i in 1 2 3 ; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=10:11:11:11:11:11,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
 done
-OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
@@ -634,6 +876,7 @@ AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --no-chdir --pidfile 2> of
 for i in 1 2 3 ; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
 done
+OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
 
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
@@ -648,6 +891,7 @@ tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:0
 ])
 
 AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
+sleep 1  # wait for revalidator to update stats
 AT_CHECK([ovs-ofctl -OOpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
  n_packets=6, n_bytes=360, actions=goto_table:1
  table=2, n_packets=3, n_bytes=180, dl_src=10:11:11:11:11:11 actions=CONTROLLER:65535
@@ -677,7 +921,7 @@ AT_CHECK([ovs-ofctl monitor br0 65534 --detach --no-chdir --pidfile 2> ofctl_mon
 for i in 1 2 3 ; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=10:11:11:11:11:11,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
 done
-OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 ])
@@ -694,6 +938,7 @@ AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 ])
 
 AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
+sleep 1  # wait for revalidator to update stats
 AT_CHECK([ovs-ofctl -OOpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
  n_packets=6, n_bytes=360, actions=resubmit(1,1)
  table=2, dl_src=10:11:11:11:11:11 actions=CONTROLLER:65535
@@ -754,6 +999,7 @@ AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 ])
 
 AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
+sleep 1  # wait for revalidator to update stats
 AT_CHECK([ovs-ofctl -OOpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
  n_packets=3, n_bytes=180, actions=goto_table:1
 OFPST_FLOW reply (OF1.2):
@@ -785,6 +1031,7 @@ AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 ])
 
 AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
+sleep 1  # wait for revalidator to update stats
 AT_CHECK([ovs-ofctl -OOpenFlow12 dump-flows br0 | ofctl_strip | sort], [0], [dnl
  n_packets=3, n_bytes=180, actions=resubmit(1,1)
 OFPST_FLOW reply (OF1.2):
@@ -835,7 +1082,7 @@ for i in 1 2 3 ; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9),tcp_flags(0x010)'
 done
 OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
-ovs-appctl -t ovs-ofctl exit
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 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)
@@ -855,7 +1102,7 @@ for i in 1 2 3 ; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=10:11:11:11:11:11,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=10),tcp_flags(0x002)'
 done
 OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
-ovs-appctl -t ovs-ofctl exit
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 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)
@@ -875,7 +1122,7 @@ for i in 1 2 3 ; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=30:33:33:33:33:33,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=10),tcp_flags(0x001)'
 done
 OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
-ovs-appctl -t ovs-ofctl exit
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 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)
@@ -895,7 +1142,7 @@ for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:41,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=16,tos=0,ttl=64,frag=no)'
 done
 OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
-ovs-appctl -t ovs-ofctl exit
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
@@ -915,7 +1162,7 @@ for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:42,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=16,tos=0,ttl=64,frag=no)'
 done
 OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
-ovs-appctl -t ovs-ofctl exit
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
@@ -935,7 +1182,7 @@ for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=41:44:44:44:44:42,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=16,tos=0,ttl=64,frag=no)'
 done
 OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
-ovs-appctl -t ovs-ofctl exit
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
@@ -956,8 +1203,9 @@ dnl in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x8847)
 for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:43,dst=50:54:00:00:00:07),eth_type(0x8847),mpls(label=11,tc=3,ttl=64,bos=1)'
 done
+OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
-OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
 mpls,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:43,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=46912
@@ -976,7 +1224,7 @@ for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:44,dst=50:54:00:00:00:07),eth_type(0x8100),vlan(vid=99,pcp=7),encap(eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=16,tos=0,ttl=64,frag=no))'
 done
 OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
-ovs-appctl -t ovs-ofctl exit
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
@@ -996,7 +1244,7 @@ for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:45,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=16,tos=0,ttl=64,frag=no)'
 done
 OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
-ovs-appctl -t ovs-ofctl exit
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
@@ -1016,7 +1264,7 @@ for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:46,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=16,tos=0,ttl=64,frag=no)'
 done
 OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
-ovs-appctl -t ovs-ofctl exit
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
@@ -1036,7 +1284,7 @@ for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:47,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=16,tos=0,ttl=64,frag=no)'
 done
 OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
-ovs-appctl -t ovs-ofctl exit
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
@@ -1056,7 +1304,7 @@ for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:48,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=16,tos=0,ttl=64,frag=no)'
 done
 OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
-ovs-appctl -t ovs-ofctl exit
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
@@ -1076,7 +1324,7 @@ for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:55:55:55:55:55,dst=50:54:00:00:00:07),eth_type(0x8847),mpls(label=100,tc=7,ttl=64,bos=1)'
 done
 OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
-ovs-appctl -t ovs-ofctl exit
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 NXT_PACKET_IN (xid=0x0): cookie=0xb total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
@@ -1096,7 +1344,7 @@ for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=70:77:77:77:77:77,dst=50:54:00:00:00:07),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=128,frag=no)'
 done
 OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
-ovs-appctl -t ovs-ofctl exit
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 NXT_PACKET_IN (xid=0x0): cookie=0xc total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
@@ -1124,7 +1372,7 @@ done
 #    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=60:66:66:66:66:66,dst=50:54:00:00:00:07),eth_type(0x8847),mpls(label=10,tc=3,ttl=100,bos=1)'
 #done
 OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
-ovs-appctl -t ovs-ofctl exit
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
@@ -1144,7 +1392,7 @@ for i in 1 ; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=20:22:22:22:22:22,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=11),tcp_flags(0x001)'
 done
 OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 18])
-ovs-appctl -t ovs-ofctl exit
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 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)
@@ -1182,7 +1430,7 @@ for i in 1 ; do
     ovs-appctl netdev-dummy/receive p1 '50 54 00 00 00 07 20 22 22 22 22 22 08 00 45 00 00 1C 00 00 00 00 00 11 00 00 C0 A8 00 01 C0 A8 00 02 00 08 00 0B 00 00 12 34 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
 done
 OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 18])
-ovs-appctl -t ovs-ofctl exit
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 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)
@@ -1221,7 +1469,7 @@ for i in 1 2 3; do
 done
 
 OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 9])
-OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
 arp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.0.1,arp_tpa=192.168.0.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=00:00:00:00:00:00
@@ -1580,8 +1828,8 @@ AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 65534 -m -P nxm --detach
 for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:00:00,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
 done
-sleep 1
-OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+OVS_WAIT_UNTIL([test `grep OFPT_PACKET_IN ofctl_monitor.log | wc -l` -ge 3])
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
 OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
@@ -1613,8 +1861,8 @@ AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 65534 -m -P nxm --detach
 for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:00:01,dst=50:54:00:00:00:07),eth_type(0x8847),mpls(label=10,tc=0,ttl=64,bos=1)'
 done
-sleep 1
-OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+OVS_WAIT_UNTIL([test `grep OFPT_PACKET_IN ofctl_monitor.log | wc -l` -ge 3])
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
 OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
@@ -1648,7 +1896,7 @@ AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 65534 -m -P nxm --detach
 for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:00:02,dst=50:54:00:00:00:07),eth_type(0x8847),mpls(label=10,tc=0,ttl=64,bos=1)'
 done
-sleep 1
+OVS_WAIT_UNTIL([test `grep OFPT_PACKET_IN ofctl_monitor.log | wc -l` -ge 3])
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
 
 AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
@@ -1706,8 +1954,8 @@ AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 65534 -m -P nxm --detach
 for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:54:50,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
 done
-sleep 1
-OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+OVS_WAIT_UNTIL([test `grep OFPT_PACKET_IN ofctl_monitor.log | wc -l` -ge 3])
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
 OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
@@ -1743,8 +1991,8 @@ AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 65534 -m -P nxm --detach
 for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:54:51,dst=50:54:00:00:00:07),eth_type(0x8100),vlan(vid=88,pcp=7),encap(eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no))'
 done
-OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
-ovs-appctl -t ovs-ofctl exit
+OVS_WAIT_UNTIL([test `grep OFPT_PACKET_IN ofctl_monitor.log | wc -l` -ge 3])
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
 OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
@@ -1777,7 +2025,8 @@ AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 65534 -m -P nxm --detach
 for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:54:52,dst=52:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
 done
-OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+OVS_WAIT_UNTIL([test `grep OFPT_PACKET_IN ofctl_monitor.log | wc -l` -ge 3])
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
 OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
@@ -1813,8 +2062,8 @@ AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 65534 -m -P nxm --detach
 for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:54:53,dst=50:54:00:00:00:07),eth_type(0x8100),vlan(vid=88,pcp=7),encap(eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no))'
 done
-OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
-ovs-appctl -t ovs-ofctl exit
+OVS_WAIT_UNTIL([test `grep OFPT_PACKET_IN ofctl_monitor.log | wc -l` -ge 3])
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
 OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
@@ -1847,8 +2096,8 @@ AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 65534 -m -P nxm --detach
 for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:54:54,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
 done
-OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
-ovs-appctl -t ovs-ofctl exit
+OVS_WAIT_UNTIL([test `grep OFPT_PACKET_IN ofctl_monitor.log | wc -l` -ge 3])
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
 OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
@@ -1884,7 +2133,7 @@ AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 65534 -m -P nxm --detach
 for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:54:55,dst=50:54:00:00:00:07),eth_type(0x8100),vlan(vid=88,pcp=7),encap(eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no))'
 done
-OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
+OVS_WAIT_UNTIL([test `grep OFPT_PACKET_IN ofctl_monitor.log | wc -l` -ge 3])
 ovs-appctl -t ovs-ofctl exit
 
 AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
@@ -1918,8 +2167,8 @@ AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 65534 -m -P nxm --detach
 for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:54:56,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
 done
-OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
-ovs-appctl -t ovs-ofctl exit
+OVS_WAIT_UNTIL([test `grep OFPT_PACKET_IN ofctl_monitor.log | wc -l` -ge 3])
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
 OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
@@ -1955,8 +2204,8 @@ AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 -m 65534 -P nxm --detach
 for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:54:57,dst=50:54:00:00:00:07),eth_type(0x8100),vlan(vid=88,pcp=7),encap(eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no))'
 done
-OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
-ovs-appctl -t ovs-ofctl exit
+OVS_WAIT_UNTIL([test `grep OFPT_PACKET_IN ofctl_monitor.log | wc -l` -ge 3])
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
 OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
@@ -1989,8 +2238,8 @@ AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 65534 -m -P nxm --detach
 for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:54:58,dst=50:54:00:00:00:07),eth_type(0x8100),vlan(vid=88,pcp=7),encap(eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no))'
 done
-OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
-ovs-appctl -t ovs-ofctl exit
+OVS_WAIT_UNTIL([test `grep OFPT_PACKET_IN ofctl_monitor.log | wc -l` -ge 3])
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
 
 AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
 OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
@@ -2023,7 +2272,7 @@ AT_CHECK([ovs-ofctl --protocols=OpenFlow12 monitor br0 65534 -m -P nxm --detach
 for i in 1 2 3; do
     ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:54:59,dst=50:54:00:00:00:07),eth_type(0x8100),vlan(vid=88,pcp=7),encap(eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no))'
 done
-OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
+OVS_WAIT_UNTIL([test `grep OFPT_PACKET_IN ofctl_monitor.log | wc -l` -ge 3])
 ovs-appctl -t ovs-ofctl exit
 
 AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
@@ -2359,7 +2608,7 @@ in_port=2 actions=output:1
 ])
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 
-odp_flow="in_port(p1)"
+odp_flow="in_port(1)"
 br_flow="in_port=1"
 # Test command: ofproto/trace odp_flow with in_port as a name.
 AT_CHECK([ovs-appctl ofproto/trace "$odp_flow"], [0], [stdout])
@@ -2795,7 +3044,7 @@ m4_define([CHECK_SFLOW_SAMPLING_PACKET],
   OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone])
 
   ON_EXIT([kill `cat test-sflow.pid`])
-  AT_CHECK([test-sflow --log-file --detach --no-chdir --pidfile 0:$1 > sflow.log], [0], [], [ignore])
+  AT_CHECK([ovstest test-sflow --log-file --detach --no-chdir --pidfile 0:$1 > sflow.log], [0], [], [ignore])
   AT_CAPTURE_FILE([sflow.log])
   SFLOW_PORT=`parse_listening_port < test-sflow.log`
   ovs-appctl time/stop
@@ -2950,7 +3199,7 @@ IFCOUNTERS
        type=6
        ifspeed=100000000
        direction=0
-       status=3
+       status=0
        in_octets=0
        in_unicasts=0
        in_multicasts=0
@@ -3019,7 +3268,7 @@ IFCOUNTERS
        type=6
        ifspeed=100000000
        direction=0
-       status=3
+       status=0
        in_octets=0
        in_unicasts=0
        in_multicasts=0
@@ -3102,7 +3351,7 @@ m4_define([CHECK_NETFLOW_EXPIRATION],
 
   ovs-appctl time/stop
   ON_EXIT([kill `cat test-netflow.pid`])
-  AT_CHECK([test-netflow --log-file --detach --no-chdir --pidfile 0:$1 > netflow.log], [0], [], [ignore])
+  AT_CHECK([ovstest test-netflow --log-file --detach --no-chdir --pidfile 0:$1 > netflow.log], [0], [], [ignore])
   AT_CAPTURE_FILE([netflow.log])
   NETFLOW_PORT=`parse_listening_port < test-netflow.log`
 
@@ -3113,6 +3362,7 @@ m4_define([CHECK_NETFLOW_EXPIRATION],
 
   for delay in 1000 30000; do
       ovs-appctl netdev-dummy/receive p1 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'
+      sleep 1  # ensure the order in which these two packets are processed
       ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0)'
 
       ovs-appctl time/warp $delay
@@ -3148,7 +3398,7 @@ m4_define([CHECK_NETFLOW_ACTIVE_EXPIRATION],
   ADD_OF_PORTS([br0], 1, 2)
 
   ON_EXIT([kill `cat test-netflow.pid`])
-  AT_CHECK([test-netflow --log-file --detach --no-chdir --pidfile 0:$1 > netflow.log], [0], [], [ignore])
+  AT_CHECK([ovstest test-netflow --log-file --detach --no-chdir --pidfile 0:$1 > netflow.log], [0], [], [ignore])
   AT_CAPTURE_FILE([netflow.log])
   NETFLOW_PORT=`parse_listening_port < test-netflow.log`
 
@@ -3232,6 +3482,7 @@ for i in `seq 1 10`; do
 done
 
 ovs-appctl time/warp 1000
+sleep 1  # wait for revalidator to update stats
 
 AT_CHECK([ovs-ofctl dump-flows br0], [0], [stdout])
 AT_CHECK([STRIP_XIDS stdout | sed -n 's/duration=[[0-9]]*\.[[0-9]]*s/duration=0.0s/p' | sort], [0], [dnl
@@ -3320,6 +3571,7 @@ ovs-appctl netdev-dummy/receive br0 'in_port(0),eth(src=50:54:00:00:00:07,dst=50
 ovs-appctl time/warp 1000
 ovs-appctl time/warp 1000
 ovs-appctl time/warp 1000
+sleep 1
 get_ages duration4 hard4 idle4
 
 printf "duration: %4s => %4s => %4s => %4s\n" $duration1 $duration2 $duration3 $duration4
@@ -3361,13 +3613,13 @@ AT_DATA([flows.txt], [dnl
 in_port=1 actions=output:2
 in_port=2 actions=mod_vlan_vid:17,output:1
 ])
+ovs-appctl time/stop
 AT_CHECK([ovs-ofctl add-flow br0 'idle_timeout=60,actions=fin_timeout(idle_timeout=5)'])
 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip], [0],
 [NXST_FLOW reply:
  idle_timeout=60, actions=fin_timeout(idle_timeout=5)
 ])
 
-ovs-appctl time/stop
 # Check that a TCP SYN packet does not change the timeout.  (Because
 # flow stats updates are mainly what implements the fin_timeout
 # feature, we warp forward a couple of times to ensure that flow stats
@@ -3376,6 +3628,7 @@ AT_CHECK([ovs-appctl netdev-dummy/receive br0 0021853763af0026b98cb0f90800450000
 AT_CHECK([ovs-appctl time/warp 1000 && ovs-appctl time/warp 1000], [0], [warped
 warped
 ])
+sleep 1
 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip], [0],
 [NXST_FLOW reply:
  n_packets=1, n_bytes=74, idle_timeout=60, actions=fin_timeout(idle_timeout=5)
@@ -3433,30 +3686,31 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p2 'in_port(2),eth(src=50:54:00:00:00:
 AT_CHECK([ovs-appctl netdev-dummy/receive p3 'in_port(3),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 
 AT_CHECK([ovs-appctl dpif/dump-flows br0 | sort | STRIP_USED], [0], [dnl
-skb_priority(0),in_port(1),eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(controller))
-skb_priority(0),in_port(2),eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(controller))
+skb_priority(0),in_port(1),eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions:drop
+skb_priority(0),in_port(2),eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions:drop
 ])
 
 AT_CHECK([ovs-appctl dpif/dump-flows br1 | sort | STRIP_USED], [0], [dnl
-skb_priority(0),in_port(3),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(controller))
+skb_priority(0),in_port(3),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions:drop
 ])
 
 AT_CHECK([ovs-appctl dpif/dump-flows -m br0 | sort | STRIP_USED], [0], [dnl
-skb_priority(0),skb_mark(0/0),in_port(p1),eth(src=50:54:00:00:00:05/00:00:00:00:00:00,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(controller))
-skb_priority(0),skb_mark(0/0),in_port(p2),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=0/0,code=0/0), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(controller))
+skb_priority(0),skb_mark(0/0),in_port(p1),eth(src=50:54:00:00:00:05/00:00:00:00:00:00,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop
+skb_priority(0),skb_mark(0/0),in_port(p2),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=0/0,code=0/0), packets:0, bytes:0, used:never, actions:drop
 ])
 
 AT_CHECK([ovs-appctl dpif/dump-flows -m br1 | sort | STRIP_USED], [0], [dnl
-skb_priority(0),skb_mark(0/0),in_port(p3),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(controller))
+skb_priority(0),skb_mark(0/0),in_port(p3),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop
 ])
 
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
-AT_SETUP([ofproto-dpif - ovs-appctl dpif/dump-flows - MPLS actions that result in a userspace action])
+AT_SETUP([ofproto-dpif - MPLS actions that result in a userspace action])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 ON_EXIT([kill `cat ovs-ofctl.pid`])
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
@@ -3477,9 +3731,11 @@ dnl     192.168.0.1.80 > 192.168.0.2.0: Flags [none], cksum 0x7744 (correct), se
 
 for dl_src in 00 01; do
     AT_CHECK([ovs-appctl netdev-dummy/receive p1 "505400000007 6066666666$dl_src 8847 00014020 00014120 45 00 00 2c 00 00 00 00 40 06 3b 78 c0 a8 00 01 c0 a8 00 02 00 50 00 00 00 00 00 2a 00 00 00 2a 50 00 27 10 77 44 00 00 48 4f 47 45"])
-
-    AT_CHECK_UNQUOTED([ovs-appctl dpif/dump-flows br0 | grep ":$dl_src/" | STRIP_USED], [0], [dnl
-skb_priority(0),in_port(1),eth(src=60:66:66:66:66:$dl_src/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x8847),mpls(lse0=0x14020,lse1=0x14120), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(controller))
+done
+sleep 1  # wait for the datapath flow installed
+for dl_src in 00 01; do
+    AT_CHECK_UNQUOTED([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | grep ":$dl_src/" | STRIP_USED], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=60:66:66:66:66:$dl_src/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x8847),mpls(lse0=0x14020,lse1=0x14120), actions:userspace(pid=0,slow_path(controller))
 ])
 done
 
@@ -3487,10 +3743,11 @@ OVS_VSWITCHD_STOP
 AT_CLEANUP
 
 
-AT_SETUP([ofproto-dpif - ovs-appctl dpif/dump-flows - MPLS actions that result in a drop])
+AT_SETUP([ofproto-dpif - MPLS actions that result in a drop])
 OVS_VSWITCHD_START([dnl
    add-port br0 p1 -- set Interface p1 type=dummy
 ])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 ON_EXIT([kill `cat ovs-ofctl.pid`])
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
@@ -3514,9 +3771,11 @@ dnl     192.168.0.1.80 > 192.168.0.2.0: Flags [none], cksum 0x7744 (correct), se
 
 for dl_src in 00 01; do
     AT_CHECK([ovs-appctl netdev-dummy/receive p1 "505400000007 6066666666$dl_src 8847 00014020 00014120 45 00 00 2c 00 00 00 00 40 06 3b 78 c0 a8 00 01 c0 a8 00 02 00 50 00 00 00 00 00 2a 00 00 00 2a 50 00 27 10 77 44 00 00 48 4f 47 45"])
-
-    AT_CHECK_UNQUOTED([ovs-appctl dpif/dump-flows br0 | grep ":$dl_src/" | STRIP_USED], [0], [dnl
-skb_priority(0),in_port(1),eth(src=60:66:66:66:66:$dl_src/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x8847),mpls(lse0=0x14020,lse1=0x14120), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(controller))
+done
+sleep 1  # wait for the datapath flow installed
+for dl_src in 00 01; do
+    AT_CHECK_UNQUOTED([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | grep ":$dl_src/" | STRIP_USED], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=60:66:66:66:66:$dl_src/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x8847),mpls(lse0=0x14020,lse1=0x14120), actions:userspace(pid=0,slow_path(controller))
 ])
 done
 
@@ -3533,6 +3792,7 @@ ADD_OF_PORTS([br0], [2])
 ADD_OF_PORTS([br1], [3])
 
 AT_CHECK([ovs-appctl time/stop])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 
 AT_CHECK([ovs-ofctl add-flow br0 actions=LOCAL,output:1,output:2])
 AT_CHECK([ovs-ofctl add-flow br1 actions=LOCAL,output:1,output:3])
@@ -3567,11 +3827,16 @@ dummy@ovs-dummy: hit:13 missed:2
                pbr1 1/none: (patch: peer=pbr0)
 ])
 
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_USED], [0], [dnl
-skb_priority(0),in_port(100),eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:9, bytes:540, used:0.0s, actions:101,3,2
-]),
-AT_CHECK([ovs-appctl dpif/dump-flows br1 | STRIP_USED], [0], [dnl
-skb_priority(0),in_port(101),eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:4, bytes:240, used:0.0s, actions:100,2,3
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_USED], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(100),eth(src=50:54:00:00:00:05/00:00:00:00:00:00,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions:101,3,2
+skb_priority(0),skb_mark(0/0),in_port(101),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions:100,2,3
+])
+
+AT_CHECK([cat ovs-vswitchd.log | grep -e 'in_port(100).*packets:9' | FILTER_FLOW_DUMP], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(100),eth(src=50:54:00:00:00:05/00:00:00:00:00:00,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), packets:9, bytes:540, used:0.0s
+])
+AT_CHECK([cat ovs-vswitchd.log | grep -e 'in_port(101).*packets:4' | FILTER_FLOW_DUMP], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(101),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), packets:4, bytes:240, used:0.0s
 ])
 
 AT_CHECK([ovs-ofctl dump-ports br0 pbr0], [0], [dnl
@@ -3611,6 +3876,7 @@ AT_BANNER([ofproto-dpif -- megaflows])
 
 AT_SETUP([ofproto-dpif megaflow - port classification])
 OVS_VSWITCHD_START
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1 actions=output(2)
@@ -3619,14 +3885,15 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 sleep 1
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:0.0s, actions: <del>
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - L2 classification])
 OVS_VSWITCHD_START
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1,dl_src=50:54:00:00:00:09 actions=output(2)
@@ -3635,15 +3902,16 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 sleep 1
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:09/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:0b/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0c/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:09/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:0b/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0c/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - L3 classification])
 OVS_VSWITCHD_START
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_CHECK([ovs-vsctl set Bridge br0 flow_tables:0=@N1 -- --id=@N1 create Flow_Table name=t0 prefixes=nw_dst,nw_src], [0], [ignore], [])
 AT_DATA([flows.txt], [dnl
@@ -3653,15 +3921,16 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 sleep 1
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.2/255.255.255.252,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
-skb_priority(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.4/255.255.255.255,dst=10.0.0.3/0.0.0.0,proto=1/0xff,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/255.255.255.252,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:0b/00:00:00:00:00:00,dst=50:54:00:00:00:0c/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.4/255.255.255.255,dst=10.0.0.3/0.0.0.0,proto=1/0xff,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - IPv6 classification])
 OVS_VSWITCHD_START
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_CHECK([ovs-vsctl set Bridge br0 flow_tables:0=@N1 -- --id=@N1 create Flow_Table name=t0 prefixes=ipv6_dst,ipv6_src], [0], [ignore], [])
 AT_DATA([flows.txt], [dnl
@@ -3671,15 +3940,16 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x86dd),ipv6(src=2001:db8:3c4d:1:2:3:4:5,dst=fe80::2,label=0,proto=10,tclass=0x70,hlimit=128,frag=no)'])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x86dd),ipv6(src=2001:db8:3c4d:5:4:3:2:1,dst=2001:db8:3c4d:1:2:3:4:1,label=0,proto=99,tclass=0x70,hlimit=64,frag=no)'])
 sleep 1
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(1),eth_type(0x86dd),ipv6(src=2001:db8:3c4d:1:2:3:4:5/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff,dst=fe80::2/::,label=0/0,proto=10/0,tclass=0x70/0,hlimit=128/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
-skb_priority(0),in_port(1),eth_type(0x86dd),ipv6(src=2001:db8:3c4d:5:4:3:2:1/ffff:ffff:ffff:fffc::,dst=2001:db8:3c4d:1:2:3:4:1/::,label=0/0,proto=99/0,tclass=0x70/0,hlimit=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00),eth_type(0x86dd),ipv6(src=2001:db8:3c4d:1:2:3:4:5/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff,dst=fe80::2/::,label=0/0,proto=10/0,tclass=0x70/0,hlimit=128/0,frag=no/0xff), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x86dd),ipv6(src=2001:db8:3c4d:5:4:3:2:1/ffff:ffff:ffff:fffc::,dst=2001:db8:3c4d:1:2:3:4:1/::,label=0/0,proto=99/0,tclass=0x70/0,hlimit=64/0,frag=no/0xff), actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - L4 classification])
 OVS_VSWITCHD_START
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1,icmp,icmp_type=8 actions=output(2)
@@ -3687,28 +3957,30 @@ table=0 in_port=1,icmp,icmp_type=8 actions=output(2)
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0xff,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0xff,code=0/0), packets:0, bytes:0, used:0.0s, actions: <del>
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0xff,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0xff,code=0/0), actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - normal])
 OVS_VSWITCHD_START
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_CHECK([ovs-ofctl add-flow br0 action=normal])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 sleep 1
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - mpls])
 OVS_VSWITCHD_START
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 dl_src=50:54:00:00:00:09 actions=push_mpls:0x8847,2
@@ -3718,9 +3990,9 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x8847),mpls(label=11,tc=3,ttl=64,bos=1)'])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0a),eth_type(0x8847),mpls(label=11,tc=3,ttl=64,bos=1)'])
 sleep 1
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:09/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x8847),mpls(label=11,tc=3,ttl=64,bos=1), packets:0, bytes:0, used:never, actions: <del>
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:0b/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x8847),mpls(label=11,tc=3,ttl=64,bos=1), packets:0, bytes:0, used:never, actions: <del>
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:09/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x8847),mpls(label=11,tc=3,ttl=64,bos=1), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:0b/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x8847),mpls(label=11,tc=3,ttl=64,bos=1), actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -3731,11 +4003,12 @@ AT_CLEANUP
 m4_define([CHECK_MEGAFLOW_NETFLOW],
   [AT_SETUP([ofproto-dpif megaflow - netflow - $2 collector])
   OVS_VSWITCHD_START
+  AT_CHECK([ovs-appctl vlog/set dpif:dbg])
   ADD_OF_PORTS([br0], [1], [2])
 
   dnl NetFlow configuration disables wildcarding relevant fields
   ON_EXIT([kill `cat test-netflow.pid`])
-  AT_CHECK([test-netflow --log-file --detach --no-chdir --pidfile 0:$1 > netflow.log], [0], [], [ignore])
+  AT_CHECK([ovstest test-netflow --log-file --detach --no-chdir --pidfile 0:$1 > netflow.log], [0], [], [ignore])
   AT_CAPTURE_FILE([netflow.log])
   NETFLOW_PORT=`parse_listening_port < test-netflow.log`
   ovs-vsctl \
@@ -3747,9 +4020,9 @@ m4_define([CHECK_MEGAFLOW_NETFLOW],
   AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
   AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
   sleep 1
-  AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/255.255.255.255,dst=10.0.0.1/255.255.255.255,proto=1/0xff,tos=0/0xfc,ttl=64/0,frag=no/0xff),icmp(type=8,code=0), packets:0, bytes:0, used:never, actions: <del>
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4/255.255.255.255,dst=10.0.0.3/255.255.255.255,proto=1/0xff,tos=0/0xfc,ttl=64/0,frag=no/0xff),icmp(type=8,code=0), packets:0, bytes:0, used:never, actions: <del>
+  AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/255.255.255.255,dst=10.0.0.1/255.255.255.255,proto=1/0xff,tos=0/0xfc,ttl=64/0,frag=no/0xff),icmp(type=8,code=0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4/255.255.255.255,dst=10.0.0.3/255.255.255.255,proto=1/0xff,tos=0/0xfc,ttl=64/0,frag=no/0xff),icmp(type=8,code=0), actions: <del>
 ])
   OVS_VSWITCHD_STOP
   AT_CLEANUP])
@@ -3765,14 +4038,15 @@ OVS_VSWITCHD_START(
    set interface p3 type=dummy ofport_request=3])
 AT_CHECK([ovs-appctl netdev-dummy/set-admin-state up], 0, [OK
 ])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 
 AT_CHECK([ovs-ofctl add-flow br0 action=normal])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 sleep 1
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -3785,14 +4059,15 @@ OVS_VSWITCHD_START(
    set interface p3 type=dummy ofport_request=3])
 AT_CHECK([ovs-appctl netdev-dummy/set-admin-state up], 0, [OK
 ])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 
 AT_CHECK([ovs-ofctl add-flow br0 action=normal])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 sleep 1
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -3819,6 +4094,7 @@ OVS_VSWITCHD_START(
 
 AT_CHECK([ovs-appctl netdev-dummy/set-admin-state up], 0, [OK
 ])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 ADD_OF_PORTS([br0], [7])
 AT_CHECK([ovs-ofctl add-flow br0 action=normal])
 AT_CHECK([ovs-ofctl add-flow br1 action=normal])
@@ -3826,16 +4102,17 @@ ovs-appctl time/stop
 ovs-appctl time/warp 5000
 AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
-sleep 1
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/255.255.255.255,dst=10.0.0.1/255.255.255.255,proto=1/0xff,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8,code=0), packets:0, bytes:0, used:never, actions: <del>
-skb_priority(0),in_port(7),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4/255.255.255.255,dst=10.0.0.3/255.255.255.255,proto=1/0xff,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8,code=0), packets:0, bytes:0, used:never, actions: <del>
+
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(7),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(7),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - resubmit port action])
 OVS_VSWITCHD_START
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1,ip actions=resubmit(90)
@@ -3845,15 +4122,16 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 sleep 1
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:09/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:0b/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0c/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:09/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:0b/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0c/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - resubmit table action])
 OVS_VSWITCHD_START
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1,ip actions=resubmit(,1)
@@ -3864,15 +4142,16 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=
 1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 sleep 1
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:09/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:0b/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0c/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:09/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:0b/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0c/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - goto_table action])
 OVS_VSWITCHD_START
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1,ip actions=goto_table(1)
@@ -3882,15 +4161,16 @@ AT_CHECK([ovs-ofctl -O OpenFlow12 add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 sleep 1
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:09/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:0b/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0c/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:09/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:0b/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0c/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - mirroring, select_all])
 OVS_VSWITCHD_START
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 ADD_OF_PORTS([br0], [1], [2], [3])
 ovs-vsctl \
         set Bridge br0 mirrors=@m --\
@@ -3904,14 +4184,15 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 sleep 1
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:0.0s, actions: <del>
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - mirroring, select_vlan])
 OVS_VSWITCHD_START
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 ADD_OF_PORTS([br0], [1], [2], [3])
 ovs-vsctl \
         set Bridge br0 mirrors=@m --\
@@ -3925,15 +4206,16 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x8100),vlan(vid=11,pcp=7),encap(eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0))'])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 sleep 1
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
-skb_priority(0),in_port(1),eth_type(0x8100),vlan(vid=11/0xfff,pcp=7/0x0,cfi=1/1),encap(eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff)), packets:0, bytes:0, used:never, actions: <del>
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x8100),vlan(vid=11/0xfff,pcp=7/0x0,cfi=1/1),encap(eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0)), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:0b/00:00:00:00:00:00,dst=50:54:00:00:00:0c/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - move action])
 OVS_VSWITCHD_START
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1 ip,actions=move:NXM_OF_IP_SRC[[]]->NXM_NX_REG0[[]],resubmit(90)
@@ -3944,15 +4226,16 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 sleep 1
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.2/255.255.255.255,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
-skb_priority(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.4/255.255.255.255,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/255.255.255.255,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:0b/00:00:00:00:00:00,dst=50:54:00:00:00:0c/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.4/255.255.255.255,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - push action])
 OVS_VSWITCHD_START
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1 ip,actions=push:NXM_OF_IP_SRC[[]],output(2)
@@ -3961,15 +4244,16 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 sleep 1
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.2/255.255.255.255,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
-skb_priority(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.4/255.255.255.255,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/255.255.255.255,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:0b/00:00:00:00:00:00,dst=50:54:00:00:00:0c/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.4/255.255.255.255,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - learning])
 OVS_VSWITCHD_START
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1 actions=load:2->NXM_NX_REG0[[0..15]],learn(table=1,priority=65535,NXM_OF_ETH_SRC[[]],NXM_OF_VLAN_TCI[[0..11]],output:NXM_NX_REG0[[0..15]]),output:2
@@ -3987,9 +4271,9 @@ for i in 1 2; do
 done
 sleep 1
 dnl The original flow is missing due to a revalidation.
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:09/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:0.0s, actions: <del>
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:0b/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0c/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:0.0s, actions: <del>
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:09/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:0b/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:0c/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -3997,6 +4281,7 @@ AT_CLEANUP
 AT_SETUP([ofproto-dpif megaflow - tunnels])
 OVS_VSWITCHD_START(
   [add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1])
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 AT_CHECK([ovs-vsctl add-port br0 p2 -- set Interface p2 type=gre \
      options:remote_ip=1.1.1.1 ofport_request=2 options:key=flow])
 AT_CHECK([ovs-vsctl add-port br0 p3 -- set Interface p3 type=dummy \
@@ -4016,16 +4301,17 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
 AT_CHECK([ovs-appctl netdev-dummy/receive p3 'in_port(3),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0xfd,ttl=128,frag=no),icmp(type=8,code=0)'])
 AT_CHECK([ovs-appctl netdev-dummy/receive p3 'in_port(3),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0x1,ttl=64,frag=no),icmp(type=8,code=0)'])
 sleep 1
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0xfd/0x3,ttl=128/0,frag=no/0xff), packets:0, bytes:0, used:0.0s, actions: <del>
-skb_priority(0),in_port(3),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0xfd/0xff,ttl=128/0xff,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
-skb_priority(0),in_port(3),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0x1/0xff,ttl=64/0xff,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0xfd/0x3,ttl=128/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(3),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0xfd/0xff,ttl=128/0xff,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(3),eth(src=50:54:00:00:00:0b/00:00:00:00:00:00,dst=50:54:00:00:00:0c/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0x1/0xff,ttl=64/0xff,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - dec_ttl])
 OVS_VSWITCHD_START
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_CHECK([ovs-vsctl set Bridge br0 flow_tables:0=@N1 -- --id=@N1 create Flow_Table name=t0 prefixes=nw_dst,nw_src], [0], [ignore], [])
 AT_DATA([flows.txt], [dnl
@@ -4035,15 +4321,16 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 sleep 1
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_XOUT], [0], [dnl
-skb_priority(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.2/255.255.255.252,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions: <del>
-skb_priority(0),in_port(1),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no), packets:0, bytes:0, used:never, actions: <del>
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_XOUT], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/255.255.255.252,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions: <del>
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:0b/00:00:00:00:00:00,dst=50:54:00:00:00:0c/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8/0,code=0/0), actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - set dl_dst])
 OVS_VSWITCHD_START
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1 actions=mod_dl_dst(50:54:00:00:00:0a),output(2)
@@ -4062,15 +4349,16 @@ dnl ofproto-dpif).  The second entry actually updates the destination
 dnl MAC, so both the source and destination MAC addresses are
 dnl un-wildcarded, since the ODP commit functions update both the source
 dnl and destination MAC addresses.
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_USED], [0], [dnl
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/ff:ff:ff:ff:ff:ff),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions:2
-skb_priority(0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff), packets:0, bytes:0, used:never, actions:set(eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0a)),2
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_USED], [0], [dnl
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/ff:ff:ff:ff:ff:ff),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions:2
+skb_priority(0),skb_mark(0/0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4/0.0.0.0,dst=10.0.0.3/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no/0xff),icmp(type=8/0,code=0/0), actions:set(eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0a)),2
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
 AT_SETUP([ofproto-dpif megaflow - disabled])
 OVS_VSWITCHD_START
+AT_CHECK([ovs-appctl vlog/set dpif:dbg])
 ADD_OF_PORTS([br0], [1], [2])
 AT_DATA([flows.txt], [dnl
 table=0 in_port=1,ip,nw_dst=10.0.0.1 actions=output(2)
@@ -4085,9 +4373,15 @@ for i in 1 2 3 4; do
     AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 done
 sleep 1
-AT_CHECK([ovs-appctl dpif/dump-flows br0 | STRIP_USED], [0], [dnl
-skb_priority(0),skb_mark(0),in_port(1/0xffff),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:180, used:0.0s, actions:2
-skb_priority(0),skb_mark(0),in_port(1/0xffff),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:180, used:0.0s, actions:drop
+AT_CHECK([cat ovs-vswitchd.log | FILTER_FLOW_INSTALL | STRIP_USED], [0], [dnl
+skb_priority(0),skb_mark(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), actions:2
+skb_priority(0),skb_mark(0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), actions:drop
+])
+AT_CHECK([cat ovs-vswitchd.log | grep '00:09.*packets:3' | FILTER_FLOW_DUMP], [0], [dnl
+skb_priority(0),skb_mark(0),in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:180, used:0.0s
+])
+AT_CHECK([cat ovs-vswitchd.log | grep '00:0b.*packets:3' | FILTER_FLOW_DUMP], [0], [dnl
+skb_priority(0),skb_mark(0),in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:180, used:0.0s
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
index 8656d98..7838db7 100644 (file)
@@ -38,8 +38,8 @@ n_tables:254, n_buffers:256
 capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
 actions: OUTPUT SET_VLAN_VID SET_VLAN_PCP STRIP_VLAN SET_DL_SRC SET_DL_DST SET_NW_SRC SET_NW_DST SET_NW_TOS SET_TP_SRC SET_TP_DST ENQUEUE
  LOCAL(br0): addr:aa:55:aa:55:00:00
-     config:     0
-     state:      0
+     config:     PORT_DOWN
+     state:      LINK_DOWN
      speed: 0 Mbps now, 0 Mbps max
 OFPT_GET_CONFIG_REPLY: frags=normal miss_send_len=0
 ])
@@ -68,8 +68,8 @@ actions: OUTPUT SET_VLAN_VID SET_VLAN_PCP STRIP_VLAN SET_DL_SRC SET_DL_DST SET_N
      state:      LINK_DOWN
      speed: 0 Mbps now, 0 Mbps max
  LOCAL(br0): addr:aa:55:aa:55:00:0x
-     config:     0
-     state:      0
+     config:     PORT_DOWN
+     state:      LINK_DOWN
      speed: 0 Mbps now, 0 Mbps max
 OFPT_GET_CONFIG_REPLY: frags=normal miss_send_len=0
 ])
@@ -109,8 +109,8 @@ AT_CHECK([ovs-ofctl -vwarn dump-ports-desc br0], [0], [stdout])
 AT_CHECK([STRIP_XIDS stdout], [0], [dnl
 OFPST_PORT_DESC reply:
  LOCAL(br0): addr:aa:55:aa:55:00:00
-     config:     0
-     state:      0
+     config:     PORT_DOWN
+     state:      LINK_DOWN
      speed: 0 Mbps now, 0 Mbps max
 ])
 OVS_VSWITCHD_STOP
@@ -124,8 +124,8 @@ AT_CHECK([ovs-ofctl -O OpenFlow12 -vwarn dump-ports-desc br0], [0], [stdout])
 AT_CHECK([STRIP_XIDS stdout], [0], [dnl
 OFPST_PORT_DESC reply (OF1.2):
  LOCAL(br0): addr:aa:55:aa:55:00:00
-     config:     0
-     state:      0
+     config:     PORT_DOWN
+     state:      LINK_DOWN
      speed: 0 Mbps now, 0 Mbps max
 ])
 OVS_VSWITCHD_STOP
@@ -1375,27 +1375,34 @@ AT_CHECK(
    | ${PERL} $srcdir/uuidfilt.pl],
   [0], [<0>
 ])
+ovs-appctl time/stop
 # Add 4 flows.
 for in_port in 4 3 2 1; do
-    ovs-ofctl add-flow br0 hard_timeout=1${in_port},in_port=$in_port,actions=drop
+    ovs-ofctl add-flow br0 hard_timeout=$((10 + in_port * 3)),in_port=$in_port,actions=drop
 done
 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
- hard_timeout=11, in_port=1 actions=drop
- hard_timeout=12, in_port=2 actions=drop
- hard_timeout=13, in_port=3 actions=drop
- hard_timeout=14, in_port=4 actions=drop
+ hard_timeout=13, in_port=1 actions=drop
+ hard_timeout=16, in_port=2 actions=drop
+ hard_timeout=19, in_port=3 actions=drop
+ hard_timeout=22, in_port=4 actions=drop
 NXST_FLOW reply:
 ])
 # Sleep and modify the one that expires soonest
-sleep 2
+ovs-appctl time/warp 5000
 AT_CHECK([ovs-ofctl mod-flows br0 in_port=1,actions=drop])
-sleep 2
+# At this point the table would looks like:
+#  in_port   seconds to expire
+#     1            13
+#     2            11
+#     3            14
+#     4            17
+ovs-appctl time/warp 2000
 # Adding another flow will cause the one that expires soonest to be evicted.
 AT_CHECK([ovs-ofctl add-flow br0 in_port=5,actions=drop])
 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
- hard_timeout=11, in_port=1 actions=drop
- hard_timeout=13, in_port=3 actions=drop
- hard_timeout=14, in_port=4 actions=drop
+ hard_timeout=13, in_port=1 actions=drop
+ hard_timeout=19, in_port=3 actions=drop
+ hard_timeout=22, in_port=4 actions=drop
  in_port=5 actions=drop
 NXST_FLOW reply:
 ])
@@ -1414,26 +1421,33 @@ AT_CHECK(
 ])
 # Add 4 flows.
 for in_port in 4 3 2 1; do
-    ovs-ofctl add-flow br0 idle_timeout=1${in_port},in_port=$in_port,actions=drop
+    ovs-ofctl add-flow br0 idle_timeout=$((10 + in_port * 3)),in_port=$in_port,actions=drop
 done
+ovs-appctl time/stop
 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
- idle_timeout=11, in_port=1 actions=drop
- idle_timeout=12, in_port=2 actions=drop
- idle_timeout=13, in_port=3 actions=drop
- idle_timeout=14, in_port=4 actions=drop
+ idle_timeout=13, in_port=1 actions=drop
+ idle_timeout=16, in_port=2 actions=drop
+ idle_timeout=19, in_port=3 actions=drop
+ idle_timeout=22, in_port=4 actions=drop
 NXST_FLOW reply:
 ])
 # Sleep and receive on the flow that expires soonest
-sleep 2
+ovs-appctl time/warp 5000
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1)'])
-sleep 2
+# At this point the table would looks like:
+#  in_port   seconds to expire
+#     1            13
+#     2            11
+#     3            14
+#     4            17
+ovs-appctl time/warp 2000
 # Adding another flow will cause the one that expires soonest to be evicted.
 AT_CHECK([ovs-ofctl add-flow br0 in_port=5,actions=drop])
 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
- idle_timeout=13, in_port=3 actions=drop
- idle_timeout=14, in_port=4 actions=drop
+ idle_timeout=19, in_port=3 actions=drop
+ idle_timeout=22, in_port=4 actions=drop
  in_port=5 actions=drop
- n_packets=1, n_bytes=60, idle_timeout=11, in_port=1 actions=drop
+ n_packets=1, n_bytes=60, idle_timeout=13, in_port=1 actions=drop
 NXST_FLOW reply:
 ])
 OVS_VSWITCHD_STOP
@@ -2168,7 +2182,12 @@ AT_CHECK([ovs-ofctl mod-flows br0 in_port=2,cookie=2,actions=output:2])
 AT_CHECK([ovs-ofctl del-flows br0 cookie=1/-1])
 
 ovs-appctl -t ovs-ofctl ofctl/unblock
-ovs-appctl -t ovs-ofctl ofctl/barrier
+
+# Wait for the connection resumed.
+# A barrier doesn't work for this purpose.
+#    https://www.mail-archive.com/dev@openvswitch.org/msg27013.html
+#    https://www.mail-archive.com/dev@openvswitch.org/msg27675.html
+OVS_WAIT_UNTIL([grep NXT_FLOW_MONITOR_RESUMED monitor.log])
 
 ovs-appctl -t ovs-ofctl exit
 
index df0157a..d24ae91 100644 (file)
@@ -213,7 +213,7 @@ OVSDB_CHECK_MONITOR([monitor weak reference change],
 
 row,action,a,a2a,a2a1,a2b,_version
 <0>,delete,0,"[""set"",[]]","[""uuid"",""<0>""]","[""uuid"",""<1>""]","[""uuid"",""<2>""]"
-<3>,old,,"[""uuid"",""<0>""]",,,
+<3>,old,,"[""uuid"",""<0>""]",,,"[""uuid"",""<4>""]"
 ,new,1,"[""set"",[]]","[""uuid"",""<3>""]","[""uuid"",""<1>""]","[""uuid"",""<5>""]"
 ]])
 
index 0cc4375..7e9d9fd 100644 (file)
@@ -160,7 +160,7 @@ AT_CHECK(
 ordinals
 ], [ignore], [test ! -e pid || kill `cat pid`])
 AT_CHECK(
-  [[test-jsonrpc request unix:socket get_schema [\"nonexistent\"]]], [0],
+  [[ovstest test-jsonrpc request unix:socket get_schema [\"nonexistent\"]]], [0],
   [[{"error":null,"id":0,"result":{"details":"get_schema request specifies unknown database nonexistent","error":"unknown database","syntax":"[\"nonexistent\"]"}}
 ]], [], [test ! -e pid || kill `cat pid`])
 OVSDB_SERVER_SHUTDOWN
@@ -194,9 +194,8 @@ AT_CHECK([ovsdb-client list-tables unix:socket constraints], [0], [ignore], [ign
 AT_CHECK([ovsdb-client list-tables unix:socket ordinals], [0], [ignore], [ignore])
 
 # Add an already added database.
-AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-db db2], 2, [], [stderr])
-AT_CHECK([sed 's/(.*)/(...)/' stderr], [0],
-  [I/O error: db2: failed to lock lockfile (...)
+AT_CHECK([ovs-appctl -t ovsdb-server ovsdb-server/add-db db2], 2, [],
+  [db2: already open
 ovs-appctl: ovsdb-server: server returned an error
 ])
 
@@ -575,7 +574,7 @@ AT_CHECK(
     done]],
   [0], [stdout], [ignore], [test ! -e pid || kill `cat pid`])
 dnl Check that all the crap is in fact in the database log.
-AT_CHECK([[${PERL} $srcdir/uuidfilt.pl db | grep -v ^OVSDB | sed 's/"_date":[0-9]*/"_date":0/' | test-json --multiple -]], [0],
+AT_CHECK([[${PERL} $srcdir/uuidfilt.pl db | grep -v ^OVSDB | sed 's/"_date":[0-9]*/"_date":0/' | ovstest test-json --multiple -]], [0],
   [[{"cksum":"12345678 9","name":"ordinals","tables":{"ordinals":{"columns":{"name":{"type":"string"},"number":{"type":"integer"}},"indexes":[["number"]]}},"version":"5.1.3"}
 {"_comment":"add row for zero 0","_date":0,"ordinals":{"<0>":{"name":"zero"}}}
 {"_comment":"delete row for 0","_date":0,"ordinals":{"<0>":null}}
@@ -665,7 +664,7 @@ _uuid                                name  number
 OVSDB_SERVER_SHUTDOWN
 AT_CLEANUP
 
-AT_SETUP([ovsdb-server connection queue limits])
+AT_SETUP([ovsdb-server combines updates on backlogged connections])
 OVS_LOGDIR=`pwd`; export OVS_LOGDIR
 OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 ON_EXIT([kill `cat *.pid`])
@@ -676,34 +675,42 @@ if test -e /proc/sys/net/core/rmem_max; then
     # Linux
     rmem_max=`cat /proc/sys/net/core/rmem_max`
 elif rmem_max=`sysctl -n net.inet.tcp.recvbuf_max 2>/dev/null`; then
-    : # FreeBSD
+    : # FreeBSD, NetBSD
 else
     # Don't know how to get maximum socket receive buffer on this OS
     AT_SKIP_IF([:])
 fi
-# Calculate the total amount of data we need to queue: rmem_max in the
-# kernel plus 1024 kB in jsonrpc-server sending userspace (see default
-# backlog_threshold in ovsdb_jsonrpc_session_create() in
-# jsonrpc-server.c).
-queue_size=`expr $rmem_max + 1024 \* 1024`
-echo rmem_max=$rmem_max queue_size=$queue_size
-
-# Each flow update message takes up at least 48 bytes of space in queues
-# and in practice more than that.
-n_msgs=`expr $queue_size / 48`
-echo n_msgs=$n_msgs
+
+# Calculate the number of iterations we need to queue.  Each of the
+# iterations we execute, by itself, yields a monitor update of about
+# 25 kB, so fill up that much space plus a few for luck.
+n_iterations=`expr $rmem_max / 25000 + 5`
+echo rmem_max=$rmem_max n_iterations=$n_iterations
+
+# Calculate the exact number of monitor updates expected for $n_iterations,
+# assuming no updates are combined.  The "extra" update is for the initial
+# contents of the database.
+n_updates=`expr $n_iterations \* 3 + 1`
 
 # Start an ovsdb-server with the vswitchd schema.
 OVSDB_INIT([db])
-AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --log-file --remote=punix:socket db],
+AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --log-file --remote=punix:db.sock db],
   [0], [ignore], [ignore])
 
-# Executes a pair of transactions that add a bridge with 100 ports,
-# and then deletes that bridge.  Each of these transactions yields
-# a monitor update about 25 kB in size.
+# Executes a set of transactions that add a bridge with 100 ports, and
+# then deletes that bridge.  This yields three monitor updates that
+# add up to about 25 kB in size.
+#
+# The update also increments a counter held in the database so that we can
+# verify that the overall effect of the transactions took effect (e.g.
+# monitor updates at the end weren't just dropped).  We add an arbitrary
+# string to the counter to make grepping for it more reliable.
+counter=0
 trigger_big_update () {
-    ovs-vsctl --db=unix:socket --no-wait -- add-br br0 $add
-    ovs-vsctl --db=unix:socket --no-wait -- del-br br0
+    counter=`expr $counter + 1`
+    ovs-vsctl --no-wait -- set open_vswitch . system_version=xyzzy$counter
+    ovs-vsctl --no-wait -- add-br br0 $add
+    ovs-vsctl --no-wait -- del-br br0
 }
 add_ports () {
     for j in `seq 1 100`; do
@@ -712,40 +719,34 @@ add_ports () {
 }
 add=`add_ports`
 
-AT_CAPTURE_FILE([ovsdb-client.out])
 AT_CAPTURE_FILE([ovsdb-client.err])
 
 # Start an ovsdb-client monitoring all changes to the database,
 # make it block to force the buffers to fill up, and then execute
-# enough transactions that ovsdb-server disconnects it.
-AT_CHECK([ovsdb-client --detach --no-chdir --pidfile monitor unix:socket ALL >ovsdb-client.out 2>ovsdb-client.err])
+# enough iterations that ovsdb-server starts combining updates.
+AT_CHECK([ovsdb-client --detach --no-chdir --pidfile monitor ALL >ovsdb-client.out 2>ovsdb-client.err])
 AT_CHECK([ovs-appctl -t ovsdb-client ovsdb-client/block])
-for i in `seq 1 100`; do
-    echo "blocked update ($i of 100)"
-    trigger_big_update
+for i in `seq 1 $n_iterations`; do
+    echo "blocked update ($i of $n_iterations)"
+    trigger_big_update $i
 done
 AT_CHECK([ovs-appctl -t ovsdb-client ovsdb-client/unblock])
-
-# Make sure that ovsdb-server disconnected the client and
-# that the client exited as a result.
-if grep "bytes backlogged but a complete replica would only take [[0-9]]* bytes, disconnecting" ovsdb-server.log; then
-    :
-else
-    AT_FAIL_IF([:])
-fi
+OVS_WAIT_UNTIL([grep "\"xyzzy$counter\"" ovsdb-client.out])
+AT_CHECK([ovs-appctl -t ovsdb-client exit])
 OVS_WAIT_WHILE([test -e ovsdb-client.pid])
 
-# Start an ovsdb-client monitoring all changes to the database,
-# without making it block, and then execute the same transactions that
-# we did before.  This time the client should not get disconnected.
-AT_CHECK([ovsdb-client --detach --no-chdir --pidfile monitor unix:socket ALL >ovsdb-client.out 2>ovsdb-client.err])
-for i in `seq 1 100`; do
-    echo "unblocked update ($i of 100)"
-    trigger_big_update
-
-    # Make sure that ovsdb-client gets enough CPU time to process the updates.
-    ovs-appctl -t ovsdb-client version > /dev/null
-done
+# Count the number of updates in the ovsdb-client output, by counting
+# the number of changes to the Open_vSwitch table.  (All of our
+# transactions modify the Open_vSwitch table.)  It should be less than
+# $n_updates updates.
+#
+# Check that the counter is what we expect.
+logged_updates=`grep -c '^Open_vSwitch' ovsdb-client.out`
+echo "logged_updates=$logged_updates (expected less than $n_updates)"
+AT_CHECK([test $logged_updates -lt $n_updates])
+AT_CHECK_UNQUOTED([ovs-vsctl get open_vswitch . system_version], [0],
+  ["xyzzy$counter"
+])
 AT_CLEANUP
 \f
 AT_BANNER([OVSDB -- ovsdb-server transactions (SSL IPv4 sockets)])
index 3282e0e..f1dfc11 100644 (file)
@@ -91,7 +91,7 @@ AT_CHECK(
     done]],
   [0], [stdout], [ignore])
 dnl Check that all the crap is in fact in the database log.
-AT_CHECK([[${PERL} $srcdir/uuidfilt.pl db | grep -v ^OVSDB | sed 's/"_date":[0-9]*/"_date":0/' | test-json --multiple -]], [0],
+AT_CHECK([[${PERL} $srcdir/uuidfilt.pl db | grep -v ^OVSDB | sed 's/"_date":[0-9]*/"_date":0/' | ovstest test-json --multiple -]], [0],
   [[{"cksum":"12345678 9","name":"ordinals","tables":{"ordinals":{"columns":{"name":{"type":"string"},"number":{"type":"integer"}},"indexes":[["number"]]}},"version":"5.1.3"}
 {"_comment":"add row for zero 0","_date":0,"ordinals":{"<0>":{"name":"zero"}}}
 {"_comment":"delete row for 0","_date":0,"ordinals":{"<0>":null}}
index b8f5bfa..dbb4555 100644 (file)
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 #include "command-line.h"
 #include "ovstest.h"
+#include "dynamic-string.h"
 #include "util.h"
 
 static struct command *commands = NULL;
@@ -43,45 +44,60 @@ add_command(struct command *cmd)
     n_commands++;
 }
 
+#define OVSTEST_USAGE \
+"TEST [TESTARGS] where 'TEST' is a string, 'TESTARGS' are optional \n"\
+"arguments of the TEST"
+
+static void
+flush_help_string(struct ds *ds)
+{
+    if (ds->length > 2 ) {
+        ds->length -= 2;
+        printf ("%s\n", ds_cstr(ds));
+        ds_clear(ds);
+    }
+}
+
 static void
-list(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+help(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     const struct command *p;
+    struct ds test_names = DS_EMPTY_INITIALIZER;
+    const int linesize = 70;
+
+    printf("%s: the big test executable\n"
+           "usage: %s TEST [TESTARGS]\n"
+           "where TEST is one of the following. \n\n",
+           program_name, program_name);
 
     for(p = commands; p->name != NULL; p++) {
-        printf("%s, %d, %d\n", p->name,p->min_args, p->max_args);
+        if (*p->name != '-') { /* Skip internal commands */
+            ds_put_format(&test_names, "%s, ", p->name);
+            if ((test_names.length) >= linesize) {
+                flush_help_string(&test_names);
+            }
+        }
     }
+    flush_help_string(&test_names);
+    ds_destroy(&test_names);
 }
 
 static void
 add_top_level_commands(void)
 {
-    struct command help_cmd = {"--help", 0, 0, list};
+    struct command help_cmd = {"--help", 0, 0, help};
 
     add_command(&help_cmd);
 }
 
 void
-ovstest_register(const char *test_name, ovstest_func f,
-                  const struct command *sub_commands)
+ovstest_register(const char *test_name, ovstest_func f)
 {
     struct command test_cmd;
-    int max_args = 0;
-
-    if (sub_commands) {
-        const struct command *p;
-
-        for(p = sub_commands; p->name != NULL; p++) {
-            if (p->max_args > max_args) {
-                max_args = p->max_args;
-            }
-        }
-    }
-    max_args++;  /* adding in the sub program */
 
     test_cmd.name = test_name;
-    test_cmd.min_args = 1;
-    test_cmd.max_args = max_args;
+    test_cmd.min_args = 0;
+    test_cmd.max_args = INT_MAX;
     test_cmd.handler = f;
 
     add_command(&test_cmd);
@@ -100,6 +116,11 @@ main(int argc, char *argv[])
 {
     set_program_name(argv[0]);
 
+    if (argc < 2) {
+        ovs_fatal(0, "expect test program to be specified; "
+                  "use --help for usage");
+    }
+
     add_top_level_commands();
     if (argc > 1) {
         run_command(argc - 1, argv + 1, commands);
index 6d10a5d..b4aad1b 100644 (file)
@@ -17,6 +17,8 @@
 #ifndef OVSTEST_H
 #define OVSTEST_H
 
+#include "compiler.h"
+
 /* Overview
  * ========
  *
  * the number of test programs, linking will be done only once to produce
  * ovstest.
  *
- * With ovs-test, each test programs now becomes a sub program of ovstest.
+ * With ovstest, each test programs now becomes a sub program of ovstest.
  * For example, 'mytest' program, can now be invoked as 'ovs mytest'.
  *
  * 'ovstest --help' will list all test programs can be invoked.
  *
- * The Usage comment section below documents how a new test program can
- * be added to ovs-test.
+ * The 'Usage' section below documents how to add a new sub program
+ * to ovstest using OVSTEST_REIGSTER macros.
  */
 
 typedef void (*ovstest_func)(int argc, char *argv[]);
-
-void
-ovstest_register(const char *test_name, ovstest_func f,
-                  const struct command * sub_commands);
+void ovstest_register(const char *test_name, ovstest_func f);
 
 /* Usage
  * =====
  *
- * For each test sub program, its 'main' program should be named as
+ * For each sub test program, its 'main' program should be named as
  * '<test_name>_main()'.
  *
- * OVSTEST_REGISTER register the sub program with ovs-test top level
- * command line parser. <test_name> is expected as argv[1] when invoking
- * ovs-test.
+ * The 'main' programs should be registered with ovstest as a sub program.
+ *    OVSTEST_REGISTER(name, function)
+ *
+ * 'name' will be name of the test program. It is expected as argv[1] when
+ * invoking with ovstest.
  *
- * In case the test program has sub commands, its command array can be
- * passed in  as <sub_command>. Otherwise, NULL can be used instead.
+ * 'function' is the 'main' program mentioned above.
  *
  * Example:
  * ----------
@@ -69,16 +69,11 @@ ovstest_register(const char *test_name, ovstest_func f,
  *   ....
  * }
  *
- * // The last parameter is NULL in case my-test.c does
- * // not have sub commands. Otherwise, its command
- * // array can replace the NULL here.
- *
- * OVSTEST_REGISTER("my-test", my_test_main, NULL);
+ * OVSTEST_REGISTER("my-test", my_test_main);
  */
-
-#define OVSTEST_REGISTER(name, function, sub_commands) \
+#define OVSTEST_REGISTER(name, function) \
     OVS_CONSTRUCTOR(register_##function) { \
-        ovstest_register(name, function, sub_commands); \
+        ovstest_register(name, function); \
     }
 
 #endif
index 551e8a3..9ebe183 100644 (file)
@@ -13,7 +13,7 @@ m4_define([RECONNECT_CHECK],
      [$1 - C],
      [],
      [$2],
-     [test-reconnect < input],
+     [ovstest test-reconnect < input],
      [$3])
    __RECONNECT_CHECK(
      [$1 - Python],
index 741957d..20c231f 100644 (file)
@@ -15,7 +15,7 @@ check 2 = F:10 B
 check 3 = F:5 F
 check 4 = F:5 B
 ])
-AT_CHECK([test-stp test-stp-ieee802.1d-1998], [0], [], [dnl
+AT_CHECK([ovstest test-stp test-stp-ieee802.1d-1998], [0], [], [dnl
 stp|INFO|stp42: detected topology change.
 stp|INFO|stp42: detected topology change.
 stp|INFO|stp97: detected topology change.
@@ -58,7 +58,7 @@ check 5 = F:20 B F F
 check 6 = F:20 B F F
 check 7 = F:20 B F B
 ])
-AT_CHECK([test-stp test-stp-ieee802.1d-2004-fig17.4], [0], [], [dnl
+AT_CHECK([ovstest test-stp test-stp-ieee802.1d-2004-fig17.4], [0], [], [dnl
 stp|INFO|stp111: detected topology change.
 stp|INFO|stp111: detected topology change.
 stp|INFO|stp111: detected topology change.
@@ -84,7 +84,7 @@ check 3 = F:30 F B
 check 4 = F:20 F F
 check 5 = F:10 F F
 ])
-AT_CHECK([test-stp test-stp-ieee802.1d-2004-fig17.6], [0], [], [dnl
+AT_CHECK([ovstest test-stp test-stp-ieee802.1d-2004-fig17.6], [0], [], [dnl
 stp|INFO|stp111: detected topology change.
 stp|INFO|stp111: detected topology change.
 stp|INFO|stp111: detected topology change.
@@ -113,7 +113,7 @@ check 0 = root
 check 1 = F F:10 F F F F F F
 check 2 = F:20 D F F F F F F
 ])
-AT_CHECK([test-stp test-stp-ieee802.1d-2004-fig17.7], [0], [], [dnl
+AT_CHECK([ovstest test-stp test-stp-ieee802.1d-2004-fig17.7], [0], [], [dnl
 stp|INFO|stpaa: detected topology change.
 stp|INFO|stp111: detected topology change.
 stp|INFO|stp111: detected topology change.
@@ -152,7 +152,7 @@ run 1000
 check 0 = root
 check 1 = D D F:10
 ])
-AT_CHECK([test-stp test-stp-iol-io-1.1], [0], [], [dnl
+AT_CHECK([ovstest test-stp test-stp-iol-io-1.1], [0], [], [dnl
 stp|INFO|stp111: detected topology change.
 stp|INFO|stp111: detected topology change.
 stp|INFO|stp111: detected topology change.
@@ -178,7 +178,7 @@ run 1000
 check 0 = rootid:0x111 F B
 check 1 = rootid:0x111 B F:10
 ])
-AT_CHECK([test-stp test-stp-iol-io-1.2], [0], [], [dnl
+AT_CHECK([ovstest test-stp test-stp-iol-io-1.2], [0], [], [dnl
 stp|INFO|stp111: detected topology change.
 stp|INFO|stp222: detected topology change.
 stp|INFO|stp111: detected topology change.
@@ -202,7 +202,7 @@ check 1 = F:10 F F
 check 2 = F:10 B F
 check 3 = F:10 B B
 ])
-AT_CHECK([test-stp test-stp-iol-io-1.4], [0], [], [dnl
+AT_CHECK([ovstest test-stp test-stp-iol-io-1.4], [0], [], [dnl
 stp|INFO|stp111: detected topology change.
 stp|INFO|stp111: detected topology change.
 stp|INFO|stp111: detected topology change.
@@ -255,7 +255,7 @@ check 1 = F:10 B F F
 check 2 = B F:10 F F
 check 3 = B F:20 B B
 ])
-AT_CHECK([test-stp test-stp-iol-io-1.5], [0], [], [dnl
+AT_CHECK([ovstest test-stp test-stp-iol-io-1.5], [0], [], [dnl
 stp|INFO|stp111: detected topology change.
 stp|INFO|stp111: detected topology change.
 stp|INFO|stp111: detected topology change.
@@ -275,7 +275,7 @@ AT_DATA([test-stp-iol-op-1.1],
 bridge 0 0x123 =
 check 0 = root
 ])
-AT_CHECK([test-stp test-stp-iol-op-1.1])
+AT_CHECK([ovstest test-stp test-stp-iol-op-1.1])
 AT_CLEANUP
 
 AT_SETUP([STP.op.1.4: All Ports Initialized to Designated Ports])
@@ -290,7 +290,7 @@ check 0 = Li Li Li Li Li Li
 run 1000
 check 0 = F F F F F F
 ])
-AT_CHECK([test-stp test-stp-iol-op-1.4], [0], [], [dnl
+AT_CHECK([ovstest test-stp test-stp-iol-op-1.4], [0], [], [dnl
 stp|INFO|stp123: detected topology change.
 stp|INFO|stp123: detected topology change.
 stp|INFO|stp123: detected topology change.
@@ -314,7 +314,7 @@ run 1000
 check 0 = rootid:0x111 root
 check 1 = rootid:0x111 F:10
 ])
-AT_CHECK([test-stp test-stp-iol-op-3.1], [0], [], [dnl
+AT_CHECK([ovstest test-stp test-stp-iol-op-3.1], [0], [], [dnl
 stp|INFO|stp111: detected topology change.
 ])
 AT_CLEANUP
@@ -334,7 +334,7 @@ check 0 = rootid:0x333^0x6000 root
 check 1 = rootid:0x333^0x6000 F:20
 check 2 = rootid:0x333^0x6000 F:10 F
 ])
-AT_CHECK([test-stp test-stp-iol-op-3.3], [0], [], [dnl
+AT_CHECK([ovstest test-stp test-stp-iol-op-3.3], [0], [], [dnl
 stp|INFO|stp333: detected topology change.
 stp|INFO|stp111: detected topology change.
 stp|INFO|stp111: detected topology change.
@@ -357,7 +357,7 @@ check 0 = rootid:0x333^0x6000 root
 check 1 = rootid:0x333^0x6000 F:20
 check 2 = rootid:0x333^0x6000 F:10 F
 ])
-AT_CHECK([test-stp test-stp-iol-op-3.4], [0], [], [dnl
+AT_CHECK([ovstest test-stp test-stp-iol-op-3.4], [0], [], [dnl
 stp|INFO|stp333: detected topology change.
 stp|INFO|stp111: detected topology change.
 stp|INFO|stp111: detected topology change.
index 642c05e..86f5521 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
 #include <ctype.h>
 #include "aes128.h"
 #include "util.h"
+#include "ovstest.h"
 
 static void
 hex_to_uint8(const char *input, uint8_t *output, size_t n)
@@ -41,8 +42,8 @@ error:
     ovs_fatal(0, "\"%s\" is not exactly %"PRIuSIZE" hex digits", input, n * 2);
 }
 
-int
-main(int argc, char *argv[])
+static void
+test_aes128_main(int argc, char *argv[])
 {
     struct aes128 aes;
     uint8_t plaintext[16];
@@ -64,6 +65,6 @@ main(int argc, char *argv[])
         printf("%02x", ciphertext[i]);
     }
     putchar('\n');
-
-    return 0;
 }
+
+OVSTEST_REGISTER("test-aes128", test_aes128_main);
index 887789b..b1a5d9d 100644 (file)
@@ -18,6 +18,7 @@
 
 #include "ovs-atomic.h"
 #include "util.h"
+#include "ovstest.h"
 
 #define TEST_ATOMIC_TYPE(ATOMIC_TYPE, BASE_TYPE)        \
     {                                                   \
@@ -71,8 +72,9 @@ test_atomic_flag(void)
     ovs_assert(atomic_flag_test_and_set(&flag) == false);
 }
 
-int
-main(void)
+
+static void
+test_atomic_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     TEST_ATOMIC_TYPE(atomic_char, char);
     TEST_ATOMIC_TYPE(atomic_uchar, unsigned char);
@@ -101,6 +103,6 @@ main(void)
     TEST_ATOMIC_TYPE(atomic_int64_t, int64_t);
 
     test_atomic_flag();
-
-    return 0;
 }
+
+OVSTEST_REGISTER("test-atomic", test_atomic_main);
index 5e5ef52..9a65839 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, 2012, 2013 Nicira, Inc.
+/* Copyright (c) 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
 #include "ofpbuf.h"
 
 #include "util.h"
+#include "ovstest.h"
 
 #define N_FLOWS  50000
 #define MAX_SLAVES 8 /* Maximum supported by this test framework. */
@@ -78,7 +79,7 @@ parse_bundle_actions(char *actions)
         ovs_fatal(0, "%s", error);
     }
 
-    action = ofpacts.data;
+    action = ofpbuf_data(&ofpacts);
     bundle = ofpact_get_BUNDLE(xmemdup(action, action->len));
     ofpbuf_uninit(&ofpacts);
 
@@ -104,8 +105,8 @@ mask_str(uint8_t mask, size_t n_bits)
     return str;
 }
 
-int
-main(int argc, char *argv[])
+static void
+test_bundle_main(int argc, char *argv[])
 {
     bool ok = true;
     struct ofpact_bundle *bundle;
@@ -264,5 +265,7 @@ main(int argc, char *argv[])
 
     free(bundle);
     free(flows);
-    return ok ? 0 : 1;
+    exit(ok ? 0 : 1);
 }
+
+OVSTEST_REGISTER("test-bundle", test_bundle_main);
index ab39627..4af765e 100644 (file)
 #include "byte-order.h"
 #include <assert.h>
 #include <inttypes.h>
+#include "ovstest.h"
 
-int
-main(void)
+static void
+test_byte_order_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
 #ifndef __CHECKER__
     /* I picked some random numbers. */
@@ -48,6 +49,6 @@ main(void)
 #else  /* __CHECKER__ */
 /* Making sparse happy with this code makes it unreadable, so don't bother. */
 #endif
-
-    return 0;
 }
+
+OVSTEST_REGISTER("test-byte-order", test_byte_order_main);
index 4282fd4..10b1967 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -36,7 +36,7 @@
 #include "packets.h"
 #include "random.h"
 #include "unaligned.h"
-
+#include "ovstest.h"
 #undef NDEBUG
 #include <assert.h>
 
@@ -1340,17 +1340,18 @@ static const struct command commands[] = {
 
     /* Miniflow and minimask tests. */
     {"miniflow", 0, 0, test_miniflow},
-       {"minimask_has_extra", 0, 0, test_minimask_has_extra},
-       {"minimask_combine", 0, 0, test_minimask_combine},
+    {"minimask_has_extra", 0, 0, test_minimask_has_extra},
+    {"minimask_combine", 0, 0, test_minimask_combine},
 
     {NULL, 0, 0, NULL},
 };
 
-int
-main(int argc, char *argv[])
+static void
+test_classifier_main(int argc, char *argv[])
 {
     set_program_name(argv[0]);
     init_values();
     run_command(argc - 1, argv + 1, commands);
-    return 0;
 }
+
+OVSTEST_REGISTER("test-classifier", test_classifier_main);
index ef126de..c74133a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
 #include "random.h"
 #include "unaligned.h"
 #include "util.h"
+#include "ovstest.h"
 
 #undef NDEBUG
 #include <assert.h>
@@ -175,8 +176,9 @@ test_crc32c(void)
     mark('#');
 }
 
-int
-main(void)
+
+static void
+test_csum_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     const struct test_case *tc;
     int i;
@@ -280,6 +282,6 @@ main(void)
     mark('#');
 
     putchar('\n');
-
-    return 0;
 }
+
+OVSTEST_REGISTER("test-csum", test_csum_main);
index 3d4eaf1..9d2aca1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include <config.h>
 #include "util.h"
 #include <stdlib.h>
+#include "ovstest.h"
 
-int
-main(int argc, char *argv[])
+static void
+test_filename_main(int argc, char *argv[])
 {
     int i;
 
@@ -34,6 +35,6 @@ main(int argc, char *argv[])
         puts(base);
         free(base);
     }
-
-    return 0;
 }
+
+OVSTEST_REGISTER("test-file_name", test_filename_main);
index a498142..522fa44 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include "pcap-file.h"
 #include "util.h"
 #include "vlog.h"
+#include "ovstest.h"
 
 #undef NDEBUG
 #include <assert.h>
 
-int
-main(int argc OVS_UNUSED, char *argv[])
+static void
+test_flows_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     struct ofp10_match expected_match;
     FILE *flows, *pcap;
@@ -79,8 +80,8 @@ main(int argc OVS_UNUSED, char *argv[])
             errors++;
             printf("mismatch on packet #%d (1-based).\n", n);
             printf("Packet:\n");
-            ofp_print_packet(stdout, packet->data, packet->size);
-            ovs_hex_dump(stdout, packet->data, packet->size, 0, true);
+            ofp_print_packet(stdout, ofpbuf_data(packet), ofpbuf_size(packet));
+            ovs_hex_dump(stdout, ofpbuf_data(packet), ofpbuf_size(packet), 0, true);
             match_print(&match);
             printf("Expected flow:\n%s\n", exp_s);
             printf("Actually extracted flow:\n%s\n", got_s);
@@ -94,6 +95,7 @@ main(int argc OVS_UNUSED, char *argv[])
         ofpbuf_delete(packet);
     }
     printf("checked %d packets, %d errors\n", n, errors);
-    return errors != 0;
+    exit(errors != 0);
 }
 
+OVSTEST_REGISTER("test-flows", test_flows_main);
index 0b7b87a..081e723 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012 Nicira, Inc.
+ * Copyright (c) 2009, 2012, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
 #include <string.h>
 #include "hash.h"
 #include "jhash.h"
+#include "ovstest.h"
 
 #undef NDEBUG
 #include <assert.h>
@@ -111,8 +112,8 @@ check_3word_hash(uint32_t (*hash)(const uint32_t[], size_t, uint32_t),
     }
 }
 
-int
-main(void)
+static void
+test_hash_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     /* Check that all hashes computed with hash_words with one 1-bit (or no
      * 1-bits) set within a single 32-bit word have different values in all
@@ -167,6 +168,6 @@ main(void)
      * function.
      */
     check_word_hash(hash_int_cb, "hash_int", 12);
-
-    return 0;
 }
+
+OVSTEST_REGISTER("test-hash", test_hash_main);
index 3e0940c..3a0afa5 100644 (file)
@@ -485,4 +485,4 @@ test_heap_main(int argc, char *argv[])
     run_command(argc - 1, argv + 1, commands);
 }
 
-OVSTEST_REGISTER("test-heap", test_heap_main, commands);
+OVSTEST_REGISTER("test-heap", test_heap_main);
index eb63d9d..4c4fdf2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
 #include "hash.h"
 #include "random.h"
 #include "util.h"
+#include "ovstest.h"
 
 #undef NDEBUG
 #include <assert.h>
@@ -315,13 +316,13 @@ run_test(void (*function)(hash_func *))
     }
 }
 
-int
-main(void)
+static void
+test_hindex_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     run_test(test_hindex_insert_delete);
     run_test(test_hindex_for_each_safe);
     run_test(test_hindex_reserve_shrink);
     printf("\n");
-    return 0;
 }
 
+OVSTEST_REGISTER("test-hindex", test_hindex_main);
index dd79dc9..0c103e9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
 #include "hash.h"
 #include "random.h"
 #include "util.h"
+#include "ovstest.h"
 
 #undef NDEBUG
 #include <assert.h>
@@ -285,13 +286,13 @@ run_test(void (*function)(hash_func *))
     }
 }
 
-int
-main(void)
+static void
+test_hmap_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     run_test(test_hmap_insert_delete);
     run_test(test_hmap_for_each_safe);
     run_test(test_hmap_reserve_shrink);
     printf("\n");
-    return 0;
 }
 
+OVSTEST_REGISTER("test-hmap", test_hmap_main);
index 24bc745..43cb9fa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
 #include <stdio.h>
 
 #include "util.h"
-
+#include "ovstest.h"
 /* --pretty: If set, the JSON output is pretty-printed, instead of printed as
  * compactly as possible.  */
 static int pretty = 0;
@@ -42,7 +42,6 @@ print_and_free_json(struct json *json)
         ok = false;
     } else {
         char *s = json_to_string(json, JSSF_SORT | (pretty ? JSSF_PRETTY : 0));
-        ovs_assert(pretty || json_serialized_length(json) == strlen(s));
         puts(s);
         free(s);
         ok = true;
@@ -104,8 +103,8 @@ parse_multiple(FILE *stream)
     return ok;
 }
 
-int
-main(int argc, char *argv[])
+static void
+test_json_main(int argc, char *argv[])
 {
     const char *input_file;
     FILE *stream;
@@ -155,5 +154,7 @@ main(int argc, char *argv[])
 
     fclose(stream);
 
-    return !ok;
+    exit(!ok);
 }
+
+OVSTEST_REGISTER("test-json", test_json_main);
index 616ff2e..7251265 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include "timeval.h"
 #include "util.h"
 #include "vlog.h"
-
-static struct command all_commands[];
+#include "ovstest.h"
 
 static void usage(void) NO_RETURN;
 static void parse_options(int argc, char *argv[]);
+static struct command *get_all_commands(void);
 
-int
-main(int argc, char *argv[])
+static void
+test_jsonrpc_main(int argc, char *argv[])
 {
     proctitle_init(argc, argv);
     set_program_name(argv[0]);
     parse_options(argc, argv);
-    run_command(argc - optind, argv + optind, all_commands);
-    return 0;
+    run_command(argc - optind, argv + optind, get_all_commands());
 }
 
 static void
@@ -336,3 +335,11 @@ static struct command all_commands[] = {
     { "help", 0, INT_MAX, do_help },
     { NULL, 0, 0, NULL },
 };
+
+static struct command *
+get_all_commands(void)
+{
+    return all_commands;
+}
+
+OVSTEST_REGISTER("test-jsonrpc", test_jsonrpc_main);
index 5074818..5cba959 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
 #include <config.h>
 #include "list.h"
 #include <string.h>
+#include "ovstest.h"
 
 #undef NDEBUG
 #include <assert.h>
@@ -166,12 +167,12 @@ run_test(void (*function)(void))
     printf(".");
 }
 
-int
-main(void)
+static void
+test_list_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     run_test(test_list_construction);
     run_test(test_list_for_each_safe);
     printf("\n");
-    return 0;
 }
 
+OVSTEST_REGISTER("test-list", test_list_main);
index 99f6879..0bf3fe6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include "timeval.h"
 #include "util.h"
 #include "vlog.h"
+#include "ovstest.h"
 
 struct test {
     const char *name;
     void (*function)(void);
 };
 
-static const struct test tests[];
+static void run_help(void);
 
 #define CHECK(A, B) check(A, B, #A, #B, __FILE__, __LINE__)
 static void
@@ -236,19 +237,6 @@ run_lock_symlink_to_dir(void)
     lockfile_unlock(a);
 }
 
-static void
-run_help(void)
-{
-    size_t i;
-
-    printf("usage: %s TESTNAME\n"
-           "where TESTNAME is one of the following:\n",
-           program_name);
-    for (i = 0; tests[i].name; i++) {
-        fprintf(stderr, "\t%s\n", tests[i].name);
-    }
-}
-
 static const struct test tests[] = {
 #define TEST(NAME) { #NAME, run_##NAME }
     TEST(lock_and_unlock),
@@ -266,8 +254,21 @@ static const struct test tests[] = {
 #undef TEST
 };
 
-int
-main(int argc, char *argv[])
+static void
+run_help(void)
+{
+    size_t i;
+
+    printf("usage: %s TESTNAME\n"
+           "where TESTNAME is one of the following:\n",
+           program_name);
+    for (i = 0; tests[i].name; i++) {
+        fprintf(stderr, "\t%s\n", tests[i].name);
+    }
+}
+
+static void
+test_lockfile_main(int argc, char *argv[])
 {
     size_t i;
 
@@ -278,7 +279,6 @@ main(int argc, char *argv[])
     if (argc != 2) {
         ovs_fatal(0, "exactly one argument required; use \"%s help\" for help",
                   program_name);
-        return 1;
     }
 
     for (i = 0; tests[i].name; i++) {
@@ -310,3 +310,4 @@ main(int argc, char *argv[])
               argv[1], program_name);
 }
 
+OVSTEST_REGISTER("test-lockfile", test_lockfile_main);
index 7a89779..50747d9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2010, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include "flow.h"
 #include "ofp-actions.h"
 #include "util.h"
+#include "ovstest.h"
 
-int
-main(int argc, char *argv[])
+static void
+test_multipath_main(int argc, char *argv[])
 {
     enum { MP_MAX_LINKS = 63 };
     struct ofpact_multipath mp;
@@ -132,5 +133,7 @@ main(int argc, char *argv[])
         }
     }
 
-    return ok ? 0 : 1;
+    exit(ok ? 0 : 1);
 }
+
+OVSTEST_REGISTER("test-multipath", test_multipath_main);
index 392c6ec..a727f53 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@
 #include "unixctl.h"
 #include "util.h"
 #include "vlog.h"
+#include "ovstest.h"
 
 static void usage(void) NO_RETURN;
 static void parse_options(int argc, char *argv[]);
@@ -161,13 +162,13 @@ print_netflow(struct ofpbuf *buf)
         putchar('\n');
     }
 
-    if (buf->size) {
-        printf("%"PRIu32" extra bytes after last record\n", buf->size);
+    if (ofpbuf_size(buf)) {
+        printf("%"PRIu32" extra bytes after last record\n", ofpbuf_size(buf));
     }
 }
 
-int
-main(int argc, char *argv[])
+static void
+test_netflow_main(int argc, char *argv[])
 {
     struct unixctl_server *server;
     enum { MAX_RECV = 1500 };
@@ -213,7 +214,7 @@ main(int argc, char *argv[])
 
         ofpbuf_clear(&buf);
         do {
-            retval = read(sock, buf.data, buf.allocated);
+            retval = read(sock, ofpbuf_data(&buf), buf.allocated);
         } while (retval < 0 && errno == EINTR);
         if (retval > 0) {
             ofpbuf_put_uninit(&buf, retval);
@@ -232,8 +233,6 @@ main(int argc, char *argv[])
         unixctl_server_wait(server);
         poll_block();
     }
-
-    return 0;
 }
 
 static void
@@ -298,3 +297,5 @@ test_netflow_exit(struct unixctl_conn *conn,
     *exiting = true;
     unixctl_command_reply(conn, NULL);
 }
+
+OVSTEST_REGISTER("test-netflow", test_netflow_main);
index d41db84..c68353e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@
 #include "ofpbuf.h"
 #include "util.h"
 #include "vlog.h"
+#include "ovstest.h"
 
 static int
 parse_keys(bool wc_keys)
@@ -55,7 +56,7 @@ parse_keys(bool wc_keys)
 
         if (!wc_keys) {
             /* Convert odp_key to flow. */
-            fitness = odp_flow_key_to_flow(odp_key.data, odp_key.size, &flow);
+            fitness = odp_flow_key_to_flow(ofpbuf_data(&odp_key), ofpbuf_size(&odp_key), &flow);
             switch (fitness) {
                 case ODP_FIT_PERFECT:
                     break;
@@ -77,9 +78,9 @@ parse_keys(bool wc_keys)
             ofpbuf_init(&odp_key, 0);
             odp_flow_key_from_flow(&odp_key, &flow, flow.in_port.odp_port);
 
-            if (odp_key.size > ODPUTIL_FLOW_KEY_BYTES) {
+            if (ofpbuf_size(&odp_key) > ODPUTIL_FLOW_KEY_BYTES) {
                 printf ("too long: %"PRIu32" > %d\n",
-                        odp_key.size, ODPUTIL_FLOW_KEY_BYTES);
+                        ofpbuf_size(&odp_key), ODPUTIL_FLOW_KEY_BYTES);
                 exit_code = 1;
             }
         }
@@ -87,10 +88,10 @@ parse_keys(bool wc_keys)
         /* Convert odp_key to string. */
         ds_init(&out);
         if (wc_keys) {
-            odp_flow_format(odp_key.data, odp_key.size,
-                            odp_mask.data, odp_mask.size, NULL, &out, false);
+            odp_flow_format(ofpbuf_data(&odp_key), ofpbuf_size(&odp_key),
+                            ofpbuf_data(&odp_mask), ofpbuf_size(&odp_mask), NULL, &out, false);
         } else {
-            odp_flow_key_format(odp_key.data, odp_key.size, &out);
+            odp_flow_key_format(ofpbuf_data(&odp_key), ofpbuf_size(&odp_key), &out);
         }
         puts(ds_cstr(&out));
         ds_destroy(&out);
@@ -125,7 +126,7 @@ parse_actions(void)
 
         /* Convert odp_actions back to string. */
         ds_init(&out);
-        format_odp_actions(&out, odp_actions.data, odp_actions.size);
+        format_odp_actions(&out, ofpbuf_data(&odp_actions), ofpbuf_size(&odp_actions));
         puts(ds_cstr(&out));
         ds_destroy(&out);
 
@@ -183,8 +184,8 @@ parse_filter(char *filter_parse)
             struct match match, match_filter;
             struct minimatch minimatch;
 
-            odp_flow_key_to_flow(odp_key.data, odp_key.size, &flow);
-            odp_flow_key_to_mask(odp_mask.data, odp_mask.size, &wc.masks,
+            odp_flow_key_to_flow(ofpbuf_data(&odp_key), ofpbuf_size(&odp_key), &flow);
+            odp_flow_key_to_mask(ofpbuf_data(&odp_mask), ofpbuf_size(&odp_mask), &wc.masks,
                                  &flow);
             match_init(&match, &flow, &wc);
 
@@ -200,8 +201,8 @@ parse_filter(char *filter_parse)
         }
         /* Convert odp_key to string. */
         ds_init(&out);
-        odp_flow_format(odp_key.data, odp_key.size,
-                        odp_mask.data, odp_mask.size, NULL, &out, false);
+        odp_flow_format(ofpbuf_data(&odp_key), ofpbuf_size(&odp_key),
+                        ofpbuf_data(&odp_mask), ofpbuf_size(&odp_mask), NULL, &out, false);
         puts(ds_cstr(&out));
         ds_destroy(&out);
 
@@ -215,19 +216,25 @@ parse_filter(char *filter_parse)
     return 0;
 }
 
-int
-main(int argc, char *argv[])
+static void
+test_odp_main(int argc, char *argv[])
 {
+    int exit_code = 0;
+
     set_program_name(argv[0]);
     if (argc == 2 &&!strcmp(argv[1], "parse-keys")) {
-        return parse_keys(false);
+        exit_code =parse_keys(false);
     } else if (argc == 2 &&!strcmp(argv[1], "parse-wc-keys")) {
-        return parse_keys(true);
+        exit_code =parse_keys(true);
     } else if (argc == 2 && !strcmp(argv[1], "parse-actions")) {
-        return parse_actions();
+        exit_code = parse_actions();
     } else if (argc == 3 && !strcmp(argv[1], "parse-filter")) {
-        return parse_filter(argv[2]);
+        exit_code =parse_filter(argv[2]);
     } else {
         ovs_fatal(0, "usage: %s parse-keys | parse-wc-keys | parse-actions", argv[0]);
     }
+
+    exit(exit_code);
 }
+
+OVSTEST_REGISTER("test-odp", test_odp_main);
index 3b48778..29d7542 100644 (file)
 #include "util.h"
 #include "vlog.h"
 
-static struct command all_commands[];
-
 static void usage(void) NO_RETURN;
 static void parse_options(int argc, char *argv[]);
+static struct command *get_all_commands(void);
 
 int
 main(int argc, char *argv[])
 {
     set_program_name(argv[0]);
     parse_options(argc, argv);
-    run_command(argc - optind, argv + optind, all_commands);
+    run_command(argc - optind, argv + optind, get_all_commands());
     return 0;
 }
 
@@ -218,16 +217,13 @@ unbox_json(struct json *json)
     }
 }
 
-static size_t
+static void
 print_and_free_json(struct json *json)
 {
     char *string = json_to_string(json, JSSF_SORT);
-    size_t length = strlen(string);
     json_destroy(json);
     puts(string);
     free(string);
-
-    return length;
 }
 
 static void
@@ -445,10 +441,7 @@ do_parse_atoms(int argc, char *argv[])
         if (error) {
             print_and_free_ovsdb_error(error);
         } else {
-            size_t length;
-
-            length = print_and_free_json(ovsdb_atom_to_json(&atom, base.type));
-            ovs_assert(length == ovsdb_atom_json_length(&atom, base.type));
+            print_and_free_json(ovsdb_atom_to_json(&atom, base.type));
             ovsdb_atom_destroy(&atom, base.type);
         }
     }
@@ -500,14 +493,12 @@ do_parse_data__(int argc, char *argv[],
 
     for (i = 2; i < argc; i++) {
         struct ovsdb_datum datum;
-        size_t length;
 
         json = unbox_json(parse_json(argv[i]));
         check_ovsdb_error(parse(&datum, &type, json, NULL));
         json_destroy(json);
 
-        length = print_and_free_json(ovsdb_datum_to_json(&datum, &type));
-        ovs_assert(length == ovsdb_datum_json_length(&datum, &type));
+        print_and_free_json(ovsdb_datum_to_json(&datum, &type));
 
         ovsdb_datum_destroy(&datum, &type);
     }
@@ -2001,3 +1992,9 @@ static struct command all_commands[] = {
     { "help", 0, INT_MAX, do_help },
     { NULL, 0, 0, NULL },
 };
+
+static struct command *
+get_all_commands(void)
+{
+    return all_commands;
+}
index e60e463..a9fafd5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 Nicira, Inc.
+ * Copyright (c) 2011, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include "ovstest.h"
 
 #undef NDEBUG
 #include <assert.h>
@@ -152,13 +153,13 @@ test_ipv6_masking(void)
     assert(ipv6_count_cidr_bits(&dest) == 128);
 }
 
-int
-main(void)
+static void
+test_packets_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     test_ipv4_cidr();
     test_ipv6_static_masks();
     test_ipv6_cidr();
     test_ipv6_masking();
-
-    return 0;
 }
+
+OVSTEST_REGISTER("test-packets", test_packets_main);
index 7b1c2ac..39bd85a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include <config.h>
 
 #include "random.h"
-
+#include "ovstest.h"
 #include <stdio.h>
 #include <string.h>
 
-int
-main(void)
+static void
+test_random_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     enum { N_ROUNDS = 10000 };
     unsigned long long int total;
@@ -74,6 +74,6 @@ main(void)
         printf("\n");
     }
     printf("(expected values are %d)\n", N_ROUNDS / 16);
-
-    return 0;
 }
+
+OVSTEST_REGISTER("test-random", test_random_main);
index 9d1897f..35d5f41 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include "svec.h"
 #include "util.h"
 #include "vlog.h"
+#include "ovstest.h"
 
 static struct reconnect *reconnect;
 static int now;
 
-static const struct command commands[];
-
 static void diff_stats(const struct reconnect_stats *old,
                        const struct reconnect_stats *new,
                        int delta);
+static const struct command *get_all_commands(void);
 
-int
-main(void)
+static void
+test_reconnect_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     extern struct vlog_module VLM_reconnect;
     struct reconnect_stats prev;
@@ -69,7 +69,7 @@ main(void)
         svec_parse_words(&args, line);
         svec_terminate(&args);
         if (!svec_is_empty(&args)) {
-            run_command(args.n, args.names, commands);
+            run_command(args.n, args.names, get_all_commands());
         }
         svec_destroy(&args);
 
@@ -87,8 +87,6 @@ main(void)
 
         old_time = now;
     }
-
-    return 0;
 }
 
 static void
@@ -272,7 +270,7 @@ do_listen_error(int argc OVS_UNUSED, char *argv[])
     reconnect_listen_error(reconnect, now, atoi(argv[1]));
 }
 
-static const struct command commands[] = {
+static const struct command all_commands[] = {
     { "enable", 0, 0, do_enable },
     { "disable", 0, 0, do_disable },
     { "force-reconnect", 0, 0, do_force_reconnect },
@@ -290,3 +288,11 @@ static const struct command commands[] = {
     { "listen-error", 1, 1, do_listen_error },
     { NULL, 0, 0, NULL },
 };
+
+static const struct command *
+get_all_commands(void)
+{
+    return all_commands;
+}
+
+OVSTEST_REGISTER("test-reconnect", test_reconnect_main);
index deebd82..e992bb5 100644 (file)
@@ -35,6 +35,7 @@
 #include "unixctl.h"
 #include "util.h"
 #include "vlog.h"
+#include "ovstest.h"
 
 static void usage(void) NO_RETURN;
 static void parse_options(int argc, char *argv[]);
@@ -468,13 +469,13 @@ static void
 print_sflow(struct ofpbuf *buf)
 {
     char *dgram_buf;
-    int dgram_len = buf->size;
+    int dgram_len = ofpbuf_size(buf);
     struct sflow_xdr xdrDatagram;
     struct sflow_xdr *x = &xdrDatagram;
 
     memset(x, 0, sizeof *x);
     if (SFLOWXDR_try(x)) {
-        SFLOWXDR_assert(x, (dgram_buf = ofpbuf_try_pull(buf, buf->size)));
+        SFLOWXDR_assert(x, (dgram_buf = ofpbuf_try_pull(buf, ofpbuf_size(buf))));
         sflowxdr_init(x, dgram_buf, dgram_len);
         SFLOWXDR_assert(x, dgram_len >= SFLOW_MIN_LEN);
         process_datagram(x);
@@ -484,8 +485,8 @@ print_sflow(struct ofpbuf *buf)
     }
 }
 
-int
-main(int argc, char *argv[])
+static void
+test_sflow_main(int argc, char *argv[])
 {
     struct unixctl_server *server;
     enum { MAX_RECV = 1500 };
@@ -529,7 +530,7 @@ main(int argc, char *argv[])
 
         ofpbuf_clear(&buf);
         do {
-            retval = read(sock, buf.data, buf.allocated);
+            retval = read(sock, ofpbuf_data(&buf), buf.allocated);
         } while (retval < 0 && errno == EINTR);
         if (retval > 0) {
             ofpbuf_put_uninit(&buf, retval);
@@ -545,8 +546,6 @@ main(int argc, char *argv[])
         unixctl_server_wait(server);
         poll_block();
     }
-
-    return 0;
 }
 
 static void
@@ -612,3 +611,5 @@ test_sflow_exit(struct unixctl_conn *conn,
     *exiting = true;
     unixctl_command_reply(conn, NULL);
 }
+
+OVSTEST_REGISTER("test-sflow", test_sflow_main);
index 2be7942..1896c0f 100644 (file)
@@ -22,6 +22,7 @@
 #include <string.h>
 #include "random.h"
 #include "util.h"
+#include "ovstest.h"
 
 #undef NDEBUG
 #include <assert.h>
@@ -137,8 +138,8 @@ test_big_vector(void)
     free(vec.data);
 }
 
-int
-main(void)
+static void
+test_shar1_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     int i;
 
@@ -149,6 +150,6 @@ main(void)
     test_big_vector();
 
     putchar('\n');
-
-    return 0;
 }
+
+OVSTEST_REGISTER("test-sha1", test_shar1_main);
index 9d17745..9ca9c6c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@
 #include "ofpbuf.h"
 #include "packets.h"
 #include "vlog.h"
+#include "ovstest.h"
 
 struct bpdu {
     int port_no;
@@ -92,7 +93,7 @@ send_bpdu(struct ofpbuf *pkt, int port_no, void *b_)
     assert(port_no < b->n_ports);
     lan = b->ports[port_no];
     if (lan) {
-        const void *data = ofpbuf_get_l3(pkt);
+        const void *data = ofpbuf_l3(pkt);
         size_t size = (char *) ofpbuf_tail(pkt) - (char *) data;
         int i;
 
@@ -434,8 +435,8 @@ must_match(const char *want)
     }
 }
 
-int
-main(int argc, char *argv[])
+static void
+test_stp_main(int argc, char *argv[])
 {
     struct test_case *tc;
     FILE *input_file;
@@ -665,6 +666,6 @@ main(int argc, char *argv[])
         free(bridge);
     }
     free(tc);
-
-    return 0;
 }
+
+OVSTEST_REGISTER("test-stp", test_stp_main);
index c5c6a2b..037cfae 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2012 Nicira, Inc.
+ * Copyright (c) 2010, 2012, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 #include "util.h"
 #include "socket-util.h"
+#include "ovstest.h"
 
-int
-main(int argc, char *argv[])
+static void
+test_unix_socket_main(int argc, char *argv[])
 {
     const char *sockname1;
     const char *sockname2;
@@ -59,6 +60,6 @@ main(int argc, char *argv[])
 
     close(sock1);
     close(sock2);
-
-    return 0;
 }
+
+OVSTEST_REGISTER("test-unix-socket", test_unix_socket_main);
index 363abb1..ffd4dce 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@
 #include "random.h"
 #include "util.h"
 #include "vlog.h"
+#include "ovstest.h"
 
 #undef NDEBUG
 #include <assert.h>
@@ -1080,11 +1081,12 @@ parse_options(int argc, char *argv[])
     free(short_options);
 }
 
-int
-main(int argc, char *argv[])
+static void
+test_util_main(int argc, char *argv[])
 {
     set_program_name(argv[0]);
     parse_options(argc, argv);
     run_command(argc - optind, argv + optind, commands);
-    return 0;
 }
+
+OVSTEST_REGISTER("test-util", test_util_main);
index a13d779..2c1da90 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009 Nicira, Inc.
+ * Copyright (c) 2009, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include <config.h>
 #include "uuid.h"
 #include <stdio.h>
+#include "ovstest.h"
 
-int
-main(int argc, char *argv[])
+static void
+test_uuid_main(int argc, char *argv[])
 {
     struct uuid uuid;
 
@@ -34,6 +35,6 @@ main(int argc, char *argv[])
     }
 
     printf(UUID_FMT"\n", UUID_ARGS(&uuid));
-
-    return 0;
 }
+
+OVSTEST_REGISTER("test-uuid", test_uuid_main);
index 76757f4..8b24bd8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@
 #include "timeval.h"
 #include "util.h"
 #include "vlog.h"
+#include "ovstest.h"
 
 #undef NDEBUG
 #include <assert.h>
@@ -356,7 +357,7 @@ test_send_plain_hello(int argc OVS_UNUSED, char *argv[])
 
     hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP10_VERSION,
                              htonl(0x12345678), 0);
-    test_send_hello(type, hello->data, hello->size, 0);
+    test_send_hello(type, ofpbuf_data(hello), ofpbuf_size(hello), 0);
     ofpbuf_delete(hello);
 }
 
@@ -374,7 +375,7 @@ test_send_long_hello(int argc OVS_UNUSED, char *argv[])
                              htonl(0x12345678), EXTRA_BYTES);
     ofpbuf_put_zeros(hello, EXTRA_BYTES);
     ofpmsg_update_length(hello);
-    test_send_hello(type, hello->data, hello->size, 0);
+    test_send_hello(type, ofpbuf_data(hello), ofpbuf_size(hello), 0);
     ofpbuf_delete(hello);
 }
 
@@ -388,7 +389,7 @@ test_send_echo_hello(int argc OVS_UNUSED, char *argv[])
 
     echo = ofpraw_alloc_xid(OFPRAW_OFPT_ECHO_REQUEST, OFP10_VERSION,
                              htonl(0x12345678), 0);
-    test_send_hello(type, echo->data, echo->size, EPROTO);
+    test_send_hello(type, ofpbuf_data(echo), ofpbuf_size(echo), EPROTO);
     ofpbuf_delete(echo);
 }
 
@@ -414,8 +415,8 @@ test_send_invalid_version_hello(int argc OVS_UNUSED, char *argv[])
 
     hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP10_VERSION,
                              htonl(0x12345678), 0);
-    ((struct ofp_header *) hello->data)->version = 0;
-    test_send_hello(type, hello->data, hello->size, EPROTO);
+    ((struct ofp_header *) ofpbuf_data(hello))->version = 0;
+    test_send_hello(type, ofpbuf_data(hello), ofpbuf_size(hello), EPROTO);
     ofpbuf_delete(hello);
 }
 
@@ -431,8 +432,8 @@ static const struct command commands[] = {
     {NULL, 0, 0, NULL},
 };
 
-int
-main(int argc, char *argv[])
+static void
+test_vconn_main(int argc, char *argv[])
 {
     set_program_name(argv[0]);
     vlog_set_levels(NULL, VLF_ANY_FACILITY, VLL_EMER);
@@ -442,6 +443,6 @@ main(int argc, char *argv[])
     time_alarm(10);
 
     run_command(argc - 1, argv + 1, commands);
-
-    return 0;
 }
+
+OVSTEST_REGISTER("test-vconn", test_vconn_main);
index 772a7eb..a569436 100644 (file)
@@ -53,6 +53,14 @@ m4_define([OVS_WAIT_UNTIL], [OVS_WAIT([$1], [$2])])
 m4_define([OVS_WAIT_WHILE],
   [OVS_WAIT([if $1; then return 1; else return 0; fi], [$2])])
 
+dnl OVS_APP_EXIT_AND_WAIT(DAEMON)
+dnl
+dnl Ask the daemon named DAEMON to exit, via ovs-appctl, and then waits for it
+dnl to exit.
+m4_define([OVS_APP_EXIT_AND_WAIT],
+  [ovs-appctl -t $1 exit
+   OVS_WAIT_WHILE([test -e $1.pid])])
+
 dnl ON_EXIT([COMMANDS])
 dnl
 dnl Adds the shell COMMANDS to a collection executed when the current test
index 8bfa94c..aa16d58 100644 (file)
@@ -80,26 +80,30 @@ AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
 
 dnl Tunnel CE and encapsulated packet CE
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=3,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
-AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: 2
+AT_CHECK([tail -2 stdout], [0],
+  [Megaflow: pkt_mark=0,recirc_id=0,skb_priority=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=3,tun_ttl=64,,in_port=1,nw_ecn=3,nw_frag=no
+Datapath actions: 2
 ])
 
 dnl Tunnel CE and encapsulated packet ECT(1)
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=1,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
-AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0x3,ttl=64,frag=no)),2
+AT_CHECK([tail -2 stdout], [0],
+  [Megaflow: pkt_mark=0,recirc_id=0,skb_priority=0,tcp,tun_id=0,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=3,tun_ttl=64,,in_port=1,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=1,nw_ttl=64
+Datapath actions: set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0x3,ttl=64,frag=no)),2
 ])
 
 dnl Tunnel CE and encapsulated packet ECT(2)
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=2,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
-AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0x3,ttl=64,frag=no)),2
+AT_CHECK([tail -2 stdout], [0],
+  [Megaflow: pkt_mark=0,recirc_id=0,skb_priority=0,tcp,tun_id=0,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=3,tun_ttl=64,,in_port=1,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=2,nw_ttl=64
+Datapath actions: set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0x3,ttl=64,frag=no)),2
 ])
 
 dnl Tunnel CE and encapsulated packet Non-ECT
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
-AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: drop
+AT_CHECK([tail -2 stdout], [0],
+  [Megaflow: pkt_mark=0,recirc_id=0,skb_priority=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=3,tun_ttl=64,,in_port=1,nw_ecn=0,nw_frag=no
+Datapath actions: drop
 ])
 OVS_VSWITCHD_STOP(["/dropping tunnel packet marked ECN CE but is not ECN capable/d"])
 AT_CLEANUP
@@ -300,7 +304,7 @@ Datapath actions: 4,3,5
 
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,tos=0x0,ttl=64,flags(key)),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0], [dnl
-       - Sends "packet-in" messages to the OpenFlow controller.
+Datapath actions: drop
 ])
 
 OVS_VSWITCHD_STOP
index 2a82fb1..da64dd4 100644 (file)
@@ -18,7 +18,7 @@ AT_CHECK([
   uuids=
   for i in m4_for([count], [1], [100], [1], [count ]); do
      # Generate random UUID and check that it is in the expected format.
-     uuid=`test-uuid`
+     uuid=`ovstest test-uuid`
      CHECK_UUID
 
      # Verify that $uuid does not duplicate any UUID generated so far.
@@ -30,7 +30,7 @@ AT_CHECK([
      uuids="$uuids $uuid"
 
      # Verify that test-uuid parses and re-serializes this UUID correctly.
-     serialized=`test-uuid $uuid`
+     serialized=`ovstest test-uuid $uuid`
      if test "$uuid" != "$serialized"; then
        echo "$uuid: test-uuid serialized this as $serialized"
        exit 1
index 359f97a..4e91ed8 100644 (file)
@@ -15,7 +15,7 @@ m4_define([TEST_VCONN_CLASS],
       m4_if([$1], [ssl], [
         AT_SKIP_IF([test "$HAVE_OPENSSL" = no])
         AT_CHECK([cp $abs_top_builddir/tests/testpki*.pem .])])
-      AT_CHECK([test-vconn testname $1], [0], [], [ignore])
+      AT_CHECK([ovstest test-vconn testname $1], [0], [], [ignore])
       AT_CLEANUP])])
 
 TEST_VCONN_CLASS([unix])
index 3f32e58..f73899b 100755 (executable)
@@ -1,5 +1,5 @@
 #!/usr/bin/python
-# Copyright (c) 2013 Nicira, Inc.
+# Copyright (c) 2013, 2014 Nicira, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -275,7 +275,7 @@ Basic Configuration:
             libssl-dev gdb linux-headers-`uname -r`
 
     # Next clone the Open vSwitch source.
-    git clone git://git.openvswitch.org/openvswitch %(ovs)s
+    git clone https://github.com/openvswitch/ovs.git %(ovs)s
 
     # Setup environment variables.
     `%(v)s env`
index 4b00118..ccc55b5 100644 (file)
@@ -883,9 +883,10 @@ dpctl_put_flow(int argc, char *argv[], enum dpif_flow_put_flags flags)
     run(odp_actions_from_string(actions_s, NULL, &actions), "parsing actions");
 
     run(dpif_flow_put(dpif, flags,
-                      key.data, key.size,
-                      mask.size == 0 ? NULL : mask.data, mask.size,
-                      actions.data, actions.size,
+                      ofpbuf_data(&key), ofpbuf_size(&key),
+                      ofpbuf_size(&mask) == 0 ? NULL : ofpbuf_data(&mask),
+                      ofpbuf_size(&mask),
+                      ofpbuf_data(&actions), ofpbuf_size(&actions),
                       print_statistics ? &stats : NULL),
         "updating flow table");
 
@@ -952,7 +953,7 @@ dpctl_del_flow(int argc, char *argv[])
     run(odp_flow_from_string(key_s, &port_names, &key, &mask), "parsing flow key");
 
     run(dpif_flow_del(dpif,
-                      key.data, key.size,
+                      ofpbuf_data(&key), ofpbuf_size(&key),
                       print_statistics ? &stats : NULL), "deleting flow");
 
     simap_destroy(&port_names);
@@ -1005,7 +1006,7 @@ dpctl_parse_actions(int argc, char *argv[])
             "odp_actions_from_string");
 
         ds_init(&s);
-        format_odp_actions(&s, actions.data, actions.size);
+        format_odp_actions(&s, ofpbuf_data(&actions), ofpbuf_size(&actions));
         puts(ds_cstr(&s));
         ds_destroy(&s);
 
@@ -1141,10 +1142,10 @@ dpctl_normalize_actions(int argc, char *argv[])
         "odp_flow_key_from_string");
 
     ds_clear(&s);
-    odp_flow_format(keybuf.data, keybuf.size, NULL, 0, NULL, &s, verbosity);
+    odp_flow_format(ofpbuf_data(&keybuf), ofpbuf_size(&keybuf), NULL, 0, NULL, &s, verbosity);
     printf("input flow: %s\n", ds_cstr(&s));
 
-    run(odp_flow_key_to_flow(keybuf.data, keybuf.size, &flow),
+    run(odp_flow_key_to_flow(ofpbuf_data(&keybuf), ofpbuf_size(&keybuf), &flow),
         "odp_flow_key_to_flow");
     ofpbuf_uninit(&keybuf);
 
@@ -1156,12 +1157,12 @@ dpctl_normalize_actions(int argc, char *argv[])
 
     if (verbosity) {
         ds_clear(&s);
-        format_odp_actions(&s, odp_actions.data, odp_actions.size);
+        format_odp_actions(&s, ofpbuf_data(&odp_actions), ofpbuf_size(&odp_actions));
         printf("input actions: %s\n", ds_cstr(&s));
     }
 
     hmap_init(&actions_per_flow);
-    NL_ATTR_FOR_EACH (a, left, odp_actions.data, odp_actions.size) {
+    NL_ATTR_FOR_EACH (a, left, ofpbuf_data(&odp_actions), ofpbuf_size(&odp_actions)) {
         const struct ovs_action_push_vlan *push;
         switch(nl_attr_type(a)) {
         case OVS_ACTION_ATTR_POP_VLAN:
@@ -1192,7 +1193,7 @@ dpctl_normalize_actions(int argc, char *argv[])
     for (i = 0; i < n_afs; i++) {
         const struct actions_for_flow *af = afs[i];
 
-        sort_output_actions(af->actions.data, af->actions.size);
+        sort_output_actions(ofpbuf_data(&af->actions), ofpbuf_size(&af->actions));
 
         if (af->flow.vlan_tci != htons(0)) {
             printf("vlan(vid=%"PRIu16",pcp=%d): ",
@@ -1212,7 +1213,7 @@ dpctl_normalize_actions(int argc, char *argv[])
         }
 
         ds_clear(&s);
-        format_odp_actions(&s, af->actions.data, af->actions.size);
+        format_odp_actions(&s, ofpbuf_data(&af->actions), ofpbuf_size(&af->actions));
         puts(ds_cstr(&s));
     }
     ds_destroy(&s);
index 1294247..8be8626 100644 (file)
@@ -468,7 +468,7 @@ dump_transaction(struct vconn *vconn, struct ofpbuf *request)
     ofpmsg_update_length(request);
     run(vconn_transact(vconn, request, &reply), "talking to %s",
         vconn_get_name(vconn));
-    ofp_print(stdout, reply->data, reply->size, verbosity + 1);
+    ofp_print(stdout, ofpbuf_data(reply), ofpbuf_size(reply), verbosity + 1);
     ofpbuf_delete(reply);
 }
 
@@ -487,13 +487,13 @@ dump_trivial_transaction(const char *vconn_name, enum ofpraw raw)
 static void
 dump_stats_transaction(struct vconn *vconn, struct ofpbuf *request)
 {
-    const struct ofp_header *request_oh = request->data;
+    const struct ofp_header *request_oh = ofpbuf_data(request);
     ovs_be32 send_xid = request_oh->xid;
     enum ofpraw request_raw;
     enum ofpraw reply_raw;
     bool done = false;
 
-    ofpraw_decode_partial(&request_raw, request->data, request->size);
+    ofpraw_decode_partial(&request_raw, ofpbuf_data(request), ofpbuf_size(request));
     reply_raw = ofpraw_stats_request_to_reply(request_raw,
                                               request_oh->version);
 
@@ -503,20 +503,20 @@ dump_stats_transaction(struct vconn *vconn, struct ofpbuf *request)
         struct ofpbuf *reply;
 
         run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed");
-        recv_xid = ((struct ofp_header *) reply->data)->xid;
+        recv_xid = ((struct ofp_header *) ofpbuf_data(reply))->xid;
         if (send_xid == recv_xid) {
             enum ofpraw raw;
 
-            ofp_print(stdout, reply->data, reply->size, verbosity + 1);
+            ofp_print(stdout, ofpbuf_data(reply), ofpbuf_size(reply), verbosity + 1);
 
-            ofpraw_decode(&raw, reply->data);
+            ofpraw_decode(&raw, ofpbuf_data(reply));
             if (ofptype_from_ofpraw(raw) == OFPTYPE_ERROR) {
                 done = true;
             } else if (raw == reply_raw) {
-                done = !ofpmp_more(reply->data);
+                done = !ofpmp_more(ofpbuf_data(reply));
             } else {
                 ovs_fatal(0, "received bad reply: %s",
-                          ofp_to_string(reply->data, reply->size,
+                          ofp_to_string(ofpbuf_data(reply), ofpbuf_size(reply),
                                         verbosity + 1));
             }
         } else {
@@ -556,7 +556,7 @@ transact_multiple_noreply(struct vconn *vconn, struct list *requests)
     run(vconn_transact_multiple_noreply(vconn, requests, &reply),
         "talking to %s", vconn_get_name(vconn));
     if (reply) {
-        ofp_print(stderr, reply->data, reply->size, verbosity + 2);
+        ofp_print(stderr, ofpbuf_data(reply), ofpbuf_size(reply), verbosity + 2);
         exit(1);
     }
     ofpbuf_delete(reply);
@@ -626,7 +626,7 @@ ofctl_show(int argc OVS_UNUSED, char *argv[])
     run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
 
     trunc = ofputil_switch_features_ports_trunc(reply);
-    ofp_print(stdout, reply->data, reply->size, verbosity + 1);
+    ofp_print(stdout, ofpbuf_data(reply), ofpbuf_size(reply), verbosity + 1);
 
     ofpbuf_delete(reply);
 
@@ -689,8 +689,8 @@ fetch_port_by_features(const char *vconn_name,
     run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
     vconn_close(vconn);
 
-    oh = reply->data;
-    if (ofptype_decode(&type, reply->data)
+    oh = ofpbuf_data(reply);
+    if (ofptype_decode(&type, ofpbuf_data(reply))
         || type != OFPTYPE_FEATURES_REPLY) {
         ovs_fatal(0, "%s: received bad features reply", vconn_name);
     }
@@ -733,7 +733,7 @@ fetch_port_by_stats(const char *vconn_name,
     bool found = false;
 
     request = ofpraw_alloc(OFPRAW_OFPST_PORT_DESC_REQUEST, OFP10_VERSION, 0);
-    send_xid = ((struct ofp_header *) request->data)->xid;
+    send_xid = ((struct ofp_header *) ofpbuf_data(request))->xid;
 
     open_vconn(vconn_name, &vconn);
     send_openflow_buffer(vconn, request);
@@ -742,9 +742,9 @@ fetch_port_by_stats(const char *vconn_name,
         struct ofpbuf *reply;
 
         run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed");
-        recv_xid = ((struct ofp_header *) reply->data)->xid;
+        recv_xid = ((struct ofp_header *) ofpbuf_data(reply))->xid;
         if (send_xid == recv_xid) {
-            struct ofp_header *oh = reply->data;
+            struct ofp_header *oh = ofpbuf_data(reply);
             enum ofptype type;
             struct ofpbuf b;
             uint16_t flags;
@@ -753,7 +753,7 @@ fetch_port_by_stats(const char *vconn_name,
             if (ofptype_pull(&type, &b)
                 || type != OFPTYPE_PORT_DESC_STATS_REPLY) {
                 ovs_fatal(0, "received bad reply: %s",
-                          ofp_to_string(reply->data, reply->size,
+                          ofp_to_string(ofpbuf_data(reply), ofpbuf_size(reply),
                                         verbosity + 1));
             }
 
@@ -858,7 +858,7 @@ try_set_protocol(struct vconn *vconn, enum ofputil_protocol want,
         run(vconn_transact_noreply(vconn, request, &reply),
             "talking to %s", vconn_get_name(vconn));
         if (reply) {
-            char *s = ofp_to_string(reply->data, reply->size, 2);
+            char *s = ofp_to_string(ofpbuf_data(reply), ofpbuf_size(reply), 2);
             VLOG_DBG("%s: failed to set protocol, switch replied: %s",
                      vconn_get_name(vconn), s);
             free(s);
@@ -991,7 +991,7 @@ ofctl_dump_flows(int argc, char *argv[])
         size_t i;
 
         vconn = prepare_dump_flows(argc, argv, false, &request);
-        send_xid = ((struct ofp_header *) request->data)->xid;
+        send_xid = ((struct ofp_header *) ofpbuf_data(request))->xid;
         send_openflow_buffer(vconn, request);
 
         fses = NULL;
@@ -1261,13 +1261,13 @@ openflow_from_hex(const char *hex, struct ofpbuf **msgp)
         return "Trailing garbage in hex data";
     }
 
-    if (msg->size < sizeof(struct ofp_header)) {
+    if (ofpbuf_size(msg) < sizeof(struct ofp_header)) {
         ofpbuf_delete(msg);
         return "Message too short for OpenFlow";
     }
 
-    oh = msg->data;
-    if (msg->size != ntohs(oh->length)) {
+    oh = ofpbuf_data(msg);
+    if (ofpbuf_size(msg) != ntohs(oh->length)) {
         ofpbuf_delete(msg);
         return "Message size does not match length in OpenFlow header";
     }
@@ -1300,7 +1300,7 @@ ofctl_send(struct unixctl_conn *conn, int argc,
         }
 
         fprintf(stderr, "send: ");
-        ofp_print(stderr, msg->data, msg->size, verbosity);
+        ofp_print(stderr, ofpbuf_data(msg), ofpbuf_size(msg), verbosity);
 
         error = vconn_send_block(vconn, msg);
         if (error) {
@@ -1449,8 +1449,8 @@ monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests)
                 free(s);
             }
 
-            ofptype_decode(&type, b->data);
-            ofp_print(stderr, b->data, b->size, verbosity + 2);
+            ofptype_decode(&type, ofpbuf_data(b));
+            ofp_print(stderr, ofpbuf_data(b), ofpbuf_size(b), verbosity + 2);
 
             switch ((int) type) {
             case OFPTYPE_BARRIER_REPLY:
@@ -1464,7 +1464,7 @@ monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests)
                 if (reply_to_echo_requests) {
                     struct ofpbuf *reply;
 
-                    reply = make_echo_reply(b->data);
+                    reply = make_echo_reply(ofpbuf_data(b));
                     retval = vconn_send_block(vconn, reply);
                     if (retval) {
                         ovs_fatal(retval, "failed to send echo reply");
@@ -1543,7 +1543,7 @@ ofctl_monitor(int argc, char *argv[])
             run(vconn_transact_noreply(vconn, spif, &reply),
                 "talking to %s", vconn_get_name(vconn));
             if (reply) {
-                char *s = ofp_to_string(reply->data, reply->size, 2);
+                char *s = ofp_to_string(ofpbuf_data(reply), ofpbuf_size(reply), 2);
                 VLOG_DBG("%s: failed to set packet in format to nxm, controller"
                         " replied: %s. Falling back to the switch default.",
                         vconn_get_name(vconn), s);
@@ -1604,7 +1604,7 @@ ofctl_probe(int argc OVS_UNUSED, char *argv[])
     open_vconn(argv[1], &vconn);
     request = make_echo_request(vconn_get_version(vconn));
     run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]);
-    if (reply->size != sizeof(struct ofp_header)) {
+    if (ofpbuf_size(reply) != sizeof(struct ofp_header)) {
         ovs_fatal(0, "reply does not match request");
     }
     ofpbuf_delete(reply);
@@ -1630,8 +1630,8 @@ ofctl_packet_out(int argc, char *argv[])
 
     po.buffer_id = UINT32_MAX;
     po.in_port = str_to_port_no(argv[1], argv[2]);
-    po.ofpacts = ofpacts.data;
-    po.ofpacts_len = ofpacts.size;
+    po.ofpacts = ofpbuf_data(&ofpacts);
+    po.ofpacts_len = ofpbuf_size(&ofpacts);
 
     protocol = open_vconn(argv[1], &vconn);
     for (i = 4; i < argc; i++) {
@@ -1643,8 +1643,8 @@ ofctl_packet_out(int argc, char *argv[])
             ovs_fatal(0, "%s", error_msg);
         }
 
-        po.packet = packet->data;
-        po.packet_len = packet->size;
+        po.packet = ofpbuf_data(packet);
+        po.packet_len = ofpbuf_size(packet);
         opo = ofputil_encode_packet_out(&po, protocol);
         transact_noreply(vconn, opo);
         ofpbuf_delete(packet);
@@ -1835,7 +1835,7 @@ ofctl_ofp_parse(int argc OVS_UNUSED, char *argv[])
             ovs_fatal(0, "%s: unexpected end of file mid-message", filename);
         }
 
-        ofp_print(stdout, b.data, b.size, verbosity + 2);
+        ofp_print(stdout, ofpbuf_data(&b), ofpbuf_size(&b), verbosity + 2);
     }
     ofpbuf_uninit(&b);
 
@@ -1894,16 +1894,17 @@ ofctl_ofp_parse_pcap(int argc OVS_UNUSED, char *argv[])
                 is_openflow_port(flow.tp_dst, argv + 2))) {
             struct ofpbuf *payload = tcp_reader_run(reader, &flow, packet);
             if (payload) {
-                while (payload->size >= sizeof(struct ofp_header)) {
+                while (ofpbuf_size(payload) >= sizeof(struct ofp_header)) {
                     const struct ofp_header *oh;
+                    void *data = ofpbuf_data(payload);
                     int length;
 
                     /* Align OpenFlow on 8-byte boundary for safe access. */
-                    ofpbuf_shift(payload, -((intptr_t) payload->data & 7));
+                    ofpbuf_shift(payload, -((intptr_t) data & 7));
 
-                    oh = payload->data;
+                    oh = ofpbuf_data(payload);
                     length = ntohs(oh->length);
-                    if (payload->size < length) {
+                    if (ofpbuf_size(payload) < length) {
                         break;
                     }
 
@@ -1921,7 +1922,7 @@ ofctl_ofp_parse_pcap(int argc OVS_UNUSED, char *argv[])
                     printf(IP_FMT".%"PRIu16" > "IP_FMT".%"PRIu16":\n",
                            IP_ARGS(flow.nw_src), ntohs(flow.tp_src),
                            IP_ARGS(flow.nw_dst), ntohs(flow.tp_dst));
-                    ofp_print(stdout, payload->data, length, verbosity + 1);
+                    ofp_print(stdout, ofpbuf_data(payload), length, verbosity + 1);
                     ofpbuf_pull(payload, length);
                 }
             }
@@ -1959,18 +1960,18 @@ ofctl_ping(int argc, char *argv[])
         run(vconn_transact(vconn, ofpbuf_clone(request), &reply), "transact");
         xgettimeofday(&end);
 
-        rpy_hdr = reply->data;
+        rpy_hdr = ofpbuf_data(reply);
         if (ofptype_pull(&type, reply)
             || type != OFPTYPE_ECHO_REPLY
-            || reply->size != payload
-            || memcmp(ofpbuf_get_l3(request), ofpbuf_get_l3(reply), payload)) {
+            || ofpbuf_size(reply) != payload
+            || memcmp(ofpbuf_l3(request), ofpbuf_l3(reply), payload)) {
             printf("Reply does not match request.  Request:\n");
-            ofp_print(stdout, request, request->size, verbosity + 2);
+            ofp_print(stdout, request, ofpbuf_size(request), verbosity + 2);
             printf("Reply:\n");
-            ofp_print(stdout, reply, reply->size, verbosity + 2);
+            ofp_print(stdout, reply, ofpbuf_size(reply), verbosity + 2);
         }
         printf("%"PRIu32" bytes from %s: xid=%08"PRIx32" time=%.1f ms\n",
-               reply->size, argv[1], ntohl(rpy_hdr->xid),
+               ofpbuf_size(reply), argv[1], ntohl(rpy_hdr->xid),
                    (1000*(double)(end.tv_sec - start.tv_sec))
                    + (.001*(end.tv_usec - start.tv_usec)));
         ofpbuf_delete(request);
@@ -2377,12 +2378,12 @@ recv_flow_stats_reply(struct vconn *vconn, ovs_be32 send_xid,
             do {
                 run(vconn_recv_block(vconn, &reply),
                     "OpenFlow packet receive failed");
-            } while (((struct ofp_header *) reply->data)->xid != send_xid);
+            } while (((struct ofp_header *) ofpbuf_data(reply))->xid != send_xid);
 
-            error = ofptype_decode(&type, reply->data);
+            error = ofptype_decode(&type, ofpbuf_data(reply));
             if (error || type != OFPTYPE_FLOW_STATS_REPLY) {
                 ovs_fatal(0, "received bad reply: %s",
-                          ofp_to_string(reply->data, reply->size,
+                          ofp_to_string(ofpbuf_data(reply), ofpbuf_size(reply),
                                         verbosity + 1));
             }
         }
@@ -2395,7 +2396,7 @@ recv_flow_stats_reply(struct vconn *vconn, ovs_be32 send_xid,
             return true;
 
         case EOF:
-            more = ofpmp_more(reply->l2);
+            more = ofpmp_more(reply->frame);
             ofpbuf_delete(reply);
             reply = NULL;
             if (!more) {
@@ -2432,7 +2433,7 @@ read_flows_from_switch(struct vconn *vconn,
     fsr.table_id = 0xff;
     fsr.cookie = fsr.cookie_mask = htonll(0);
     request = ofputil_encode_flow_stats_request(&fsr, protocol);
-    send_xid = ((struct ofp_header *) request->data)->xid;
+    send_xid = ((struct ofp_header *) ofpbuf_data(request))->xid;
     send_openflow_buffer(vconn, request);
 
     reply = NULL;
@@ -2735,7 +2736,7 @@ ofctl_parse_flows__(struct ofputil_flow_mod *fms, size_t n_fms,
         struct ofpbuf *msg;
 
         msg = ofputil_encode_flow_mod(fm, protocol);
-        ofp_print(stdout, msg->data, msg->size, verbosity);
+        ofp_print(stdout, ofpbuf_data(msg), ofpbuf_size(msg), verbosity);
         ofpbuf_delete(msg);
 
         free(fm->ofpacts);
@@ -2828,7 +2829,7 @@ ofctl_parse_nxm__(bool oxm)
             } else {
                 match_len = nx_put_match(&nx_match, &match,
                                          cookie, cookie_mask);
-                out = nx_match_to_string(nx_match.data, match_len);
+                out = nx_match_to_string(ofpbuf_data(&nx_match), match_len);
             }
 
             puts(out);
@@ -2910,8 +2911,8 @@ ofctl_parse_ofp10_actions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 
         /* Convert to ofpacts. */
         ofpbuf_init(&ofpacts, 0);
-        size = of10_in.size;
-        error = ofpacts_pull_openflow_actions(&of10_in, of10_in.size,
+        size = ofpbuf_size(&of10_in);
+        error = ofpacts_pull_openflow_actions(&of10_in, ofpbuf_size(&of10_in),
                                               OFP10_VERSION, &ofpacts);
         if (error) {
             printf("bad OF1.1 actions: %s\n\n", ofperr_get_name(error));
@@ -2924,17 +2925,17 @@ ofctl_parse_ofp10_actions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         /* Print cls_rule. */
         ds_init(&s);
         ds_put_cstr(&s, "actions=");
-        ofpacts_format(ofpacts.data, ofpacts.size, &s);
+        ofpacts_format(ofpbuf_data(&ofpacts), ofpbuf_size(&ofpacts), &s);
         puts(ds_cstr(&s));
         ds_destroy(&s);
 
         /* Convert back to ofp10 actions and print differences from input. */
         ofpbuf_init(&of10_out, 0);
-        ofpacts_put_openflow_actions(ofpacts.data, ofpacts.size, &of10_out,
+        ofpacts_put_openflow_actions(ofpbuf_data(&ofpacts), ofpbuf_size(&ofpacts), &of10_out,
                                      OFP10_VERSION);
 
-        print_differences("", of10_in.data, of10_in.size,
-                          of10_out.data, of10_out.size);
+        print_differences("", ofpbuf_data(&of10_in), ofpbuf_size(&of10_in),
+                          ofpbuf_data(&of10_out), ofpbuf_size(&of10_out));
         putchar('\n');
 
         ofpbuf_uninit(&ofpacts);
@@ -2980,9 +2981,9 @@ ofctl_parse_ofp10_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         if (ofpbuf_put_hex(&match_expout, ds_cstr(&expout), NULL)[0] != '\0') {
             ovs_fatal(0, "Trailing garbage in hex data");
         }
-        if (match_expout.size != sizeof(struct ofp10_match)) {
+        if (ofpbuf_size(&match_expout) != sizeof(struct ofp10_match)) {
             ovs_fatal(0, "Input is %"PRIu32" bytes, expected %"PRIuSIZE,
-                      match_expout.size, sizeof(struct ofp10_match));
+                      ofpbuf_size(&match_expout), sizeof(struct ofp10_match));
         }
 
         /* Parse hex bytes for input. */
@@ -2995,18 +2996,18 @@ ofctl_parse_ofp10_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         if (ofpbuf_put_hex(&match_in, ds_cstr(&in), NULL)[0] != '\0') {
             ovs_fatal(0, "Trailing garbage in hex data");
         }
-        if (match_in.size != sizeof(struct ofp10_match)) {
+        if (ofpbuf_size(&match_in) != sizeof(struct ofp10_match)) {
             ovs_fatal(0, "Input is %"PRIu32" bytes, expected %"PRIuSIZE,
-                      match_in.size, sizeof(struct ofp10_match));
+                      ofpbuf_size(&match_in), sizeof(struct ofp10_match));
         }
 
         /* Convert to cls_rule and print. */
-        ofputil_match_from_ofp10_match(match_in.data, &match);
+        ofputil_match_from_ofp10_match(ofpbuf_data(&match_in), &match);
         match_print(&match);
 
         /* Convert back to ofp10_match and print differences from input. */
         ofputil_match_to_ofp10_match(&match, &match_out);
-        print_differences("", match_expout.data, match_expout.size,
+        print_differences("", ofpbuf_data(&match_expout), ofpbuf_size(&match_expout),
                           &match_out, sizeof match_out);
 
         /* Normalize, then convert and compare again. */
@@ -3044,13 +3045,13 @@ ofctl_parse_ofp11_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         if (ofpbuf_put_hex(&match_in, ds_cstr(&in), NULL)[0] != '\0') {
             ovs_fatal(0, "Trailing garbage in hex data");
         }
-        if (match_in.size != sizeof(struct ofp11_match)) {
+        if (ofpbuf_size(&match_in) != sizeof(struct ofp11_match)) {
             ovs_fatal(0, "Input is %"PRIu32" bytes, expected %"PRIuSIZE,
-                      match_in.size, sizeof(struct ofp11_match));
+                      ofpbuf_size(&match_in), sizeof(struct ofp11_match));
         }
 
         /* Convert to match. */
-        error = ofputil_match_from_ofp11_match(match_in.data, &match);
+        error = ofputil_match_from_ofp11_match(ofpbuf_data(&match_in), &match);
         if (error) {
             printf("bad ofp11_match: %s\n\n", ofperr_get_name(error));
             ofpbuf_uninit(&match_in);
@@ -3063,7 +3064,7 @@ ofctl_parse_ofp11_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         /* Convert back to ofp11_match and print differences from input. */
         ofputil_match_to_ofp11_match(&match, &match_out);
 
-        print_differences("", match_in.data, match_in.size,
+        print_differences("", ofpbuf_data(&match_in), ofpbuf_size(&match_in),
                           &match_out, sizeof match_out);
         putchar('\n');
 
@@ -3098,8 +3099,8 @@ ofctl_parse_ofp11_actions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 
         /* Convert to ofpacts. */
         ofpbuf_init(&ofpacts, 0);
-        size = of11_in.size;
-        error = ofpacts_pull_openflow_actions(&of11_in, of11_in.size,
+        size = ofpbuf_size(&of11_in);
+        error = ofpacts_pull_openflow_actions(&of11_in, ofpbuf_size(&of11_in),
                                               OFP11_VERSION, &ofpacts);
         if (error) {
             printf("bad OF1.1 actions: %s\n\n", ofperr_get_name(error));
@@ -3112,17 +3113,17 @@ ofctl_parse_ofp11_actions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         /* Print cls_rule. */
         ds_init(&s);
         ds_put_cstr(&s, "actions=");
-        ofpacts_format(ofpacts.data, ofpacts.size, &s);
+        ofpacts_format(ofpbuf_data(&ofpacts), ofpbuf_size(&ofpacts), &s);
         puts(ds_cstr(&s));
         ds_destroy(&s);
 
         /* Convert back to ofp11 actions and print differences from input. */
         ofpbuf_init(&of11_out, 0);
-        ofpacts_put_openflow_actions(ofpacts.data, ofpacts.size, &of11_out,
+        ofpacts_put_openflow_actions(ofpbuf_data(&ofpacts), ofpbuf_size(&ofpacts), &of11_out,
                                      OFP11_VERSION);
 
-        print_differences("", of11_in.data, of11_in.size,
-                          of11_out.data, of11_out.size);
+        print_differences("", ofpbuf_data(&of11_in), ofpbuf_size(&of11_in),
+                          ofpbuf_data(&of11_out), ofpbuf_size(&of11_out));
         putchar('\n');
 
         ofpbuf_uninit(&ofpacts);
@@ -3168,14 +3169,14 @@ ofctl_parse_ofp11_instructions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 
         /* Convert to ofpacts. */
         ofpbuf_init(&ofpacts, 0);
-        size = of11_in.size;
-        error = ofpacts_pull_openflow_instructions(&of11_in, of11_in.size,
+        size = ofpbuf_size(&of11_in);
+        error = ofpacts_pull_openflow_instructions(&of11_in, ofpbuf_size(&of11_in),
                                                    OFP11_VERSION, &ofpacts);
         if (!error) {
             /* Verify actions, enforce consistency. */
             struct flow flow;
             memset(&flow, 0, sizeof flow);
-            error = ofpacts_check_consistency(ofpacts.data, ofpacts.size,
+            error = ofpacts_check_consistency(ofpbuf_data(&ofpacts), ofpbuf_size(&ofpacts),
                                               &flow, OFPP_MAX,
                                               table_id ? atoi(table_id) : 0,
                                               255, OFPUTIL_P_OF11_STD);
@@ -3191,18 +3192,18 @@ ofctl_parse_ofp11_instructions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         /* Print cls_rule. */
         ds_init(&s);
         ds_put_cstr(&s, "actions=");
-        ofpacts_format(ofpacts.data, ofpacts.size, &s);
+        ofpacts_format(ofpbuf_data(&ofpacts), ofpbuf_size(&ofpacts), &s);
         puts(ds_cstr(&s));
         ds_destroy(&s);
 
         /* Convert back to ofp11 instructions and print differences from
          * input. */
         ofpbuf_init(&of11_out, 0);
-        ofpacts_put_openflow_instructions(ofpacts.data, ofpacts.size,
+        ofpacts_put_openflow_instructions(ofpbuf_data(&ofpacts), ofpbuf_size(&ofpacts),
                                           &of11_out, OFP13_VERSION);
 
-        print_differences("", of11_in.data, of11_in.size,
-                          of11_out.data, of11_out.size);
+        print_differences("", ofpbuf_data(&of11_in), ofpbuf_size(&of11_in),
+                          ofpbuf_data(&of11_out), ofpbuf_size(&of11_out));
         putchar('\n');
 
         ofpbuf_uninit(&ofpacts);
@@ -3289,7 +3290,7 @@ ofctl_check_vlan(int argc OVS_UNUSED, char *argv[])
     /* Convert to and from NXM. */
     ofpbuf_init(&nxm, 0);
     nxm_match_len = nx_put_match(&nxm, &match, htonll(0), htonll(0));
-    nxm_s = nx_match_to_string(nxm.data, nxm_match_len);
+    nxm_s = nx_match_to_string(ofpbuf_data(&nxm), nxm_match_len);
     error = nx_pull_match(&nxm, nxm_match_len, &nxm_match, NULL, NULL);
     printf("NXM: %s -> ", nxm_s);
     if (error) {
@@ -3395,19 +3396,19 @@ ofctl_encode_error_reply(int argc OVS_UNUSED, char *argv[])
     if (ofpbuf_put_hex(&request, argv[2], NULL)[0] != '\0') {
         ovs_fatal(0, "Trailing garbage in hex data");
     }
-    if (request.size < sizeof(struct ofp_header)) {
+    if (ofpbuf_size(&request) < sizeof(struct ofp_header)) {
         ovs_fatal(0, "Request too short");
     }
 
-    oh = request.data;
-    if (request.size != ntohs(oh->length)) {
+    oh = ofpbuf_data(&request);
+    if (ofpbuf_size(&request) != ntohs(oh->length)) {
         ovs_fatal(0, "Request size inconsistent");
     }
 
-    reply = ofperr_encode_reply(error, request.data);
+    reply = ofperr_encode_reply(error, ofpbuf_data(&request));
     ofpbuf_uninit(&request);
 
-    ovs_hex_dump(stdout, reply->data, reply->size, 0, false);
+    ovs_hex_dump(stdout, ofpbuf_data(reply), ofpbuf_size(reply), 0, false);
     ofpbuf_delete(reply);
 }
 
@@ -3423,7 +3424,7 @@ ofctl_ofp_print(int argc, char *argv[])
     if (ofpbuf_put_hex(&packet, argv[1], NULL)[0] != '\0') {
         ovs_fatal(0, "trailing garbage following hex bytes");
     }
-    ofp_print(stdout, packet.data, packet.size, argc > 2 ? atoi(argv[2]) : 2);
+    ofp_print(stdout, ofpbuf_data(&packet), ofpbuf_size(&packet), argc > 2 ? atoi(argv[2]) : 2);
     ofpbuf_uninit(&packet);
 }
 
@@ -3436,8 +3437,8 @@ ofctl_encode_hello(int argc OVS_UNUSED, char *argv[])
     struct ofpbuf *hello;
 
     hello = ofputil_encode_hello(bitmap);
-    ovs_hex_dump(stdout, hello->data, hello->size, 0, false);
-    ofp_print(stdout, hello->data, hello->size, verbosity);
+    ovs_hex_dump(stdout, ofpbuf_data(hello), ofpbuf_size(hello), 0, false);
+    ofp_print(stdout, ofpbuf_data(hello), ofpbuf_size(hello), verbosity);
     ofpbuf_delete(hello);
 }
 
index db85856..f46d002 100644 (file)
@@ -839,15 +839,16 @@ port_configure(struct port *port)
             s.vlan_mode = PORT_VLAN_NATIVE_UNTAGGED;
         } else {
             /* This "can't happen" because ovsdb-server should prevent it. */
-            VLOG_ERR("unknown VLAN mode %s", cfg->vlan_mode);
+            VLOG_WARN("port %s: unknown VLAN mode %s, falling "
+                      "back to trunk mode", port->name, cfg->vlan_mode);
             s.vlan_mode = PORT_VLAN_TRUNK;
         }
     } else {
         if (s.vlan >= 0) {
             s.vlan_mode = PORT_VLAN_ACCESS;
             if (cfg->n_trunks) {
-                VLOG_ERR("port %s: ignoring trunks in favor of implicit vlan",
-                         port->name);
+                VLOG_WARN("port %s: ignoring trunks in favor of implicit vlan",
+                          port->name);
             }
         } else {
             s.vlan_mode = PORT_VLAN_TRUNK;
@@ -1446,8 +1447,7 @@ iface_do_create(const struct bridge *br,
     VLOG_INFO("bridge %s: added interface %s on port %d",
               br->name, iface_cfg->name, *ofp_portp);
 
-    if ((port_cfg->vlan_mode && !strcmp(port_cfg->vlan_mode, "splinter"))
-        || iface_is_internal(iface_cfg, br->cfg)) {
+    if (port_cfg->vlan_mode && !strcmp(port_cfg->vlan_mode, "splinter")) {
         netdev_turn_flags_on(netdev, NETDEV_UP, NULL);
     }
 
@@ -3650,8 +3650,8 @@ iface_configure_qos(struct iface *iface, const struct ovsrec_qos *qos)
     }
 
     if (iface->ofp_port != OFPP_NONE) {
-        const struct ofproto_port_queue *port_queues = queues_buf.data;
-        size_t n_queues = queues_buf.size / sizeof *port_queues;
+        const struct ofproto_port_queue *port_queues = ofpbuf_data(&queues_buf);
+        size_t n_queues = ofpbuf_size(&queues_buf) / sizeof *port_queues;
 
         ofproto_port_set_queues(iface->port->bridge->ofproto, iface->ofp_port,
                                 port_queues, n_queues);
index 25470ff..0b9463a 100644 (file)
@@ -115,9 +115,6 @@ static int timeout;
 /* Format for table output. */
 static struct table_style table_style = TABLE_STYLE_DEFAULT;
 
-/* All supported commands. */
-static const struct vtep_ctl_command_syntax all_commands[];
-
 /* The IDL we're using and the current transaction, if any.
  * This is for use by vtep_ctl_exit() only, to allow it to clean up.
  * Other code should use its context arguments. */
@@ -155,6 +152,7 @@ static bool is_condition_satisfied(const struct vtep_ctl_table_class *,
 static struct vtep_ctl_lswitch *find_lswitch(struct vtep_ctl_context *,
                                              const char *name,
                                              bool must_exist);
+static const struct vtep_ctl_command_syntax *get_all_commands(void);
 
 int
 main(int argc, char *argv[])
@@ -285,7 +283,7 @@ parse_options(int argc, char *argv[], struct shash *local_options)
     options = xmemdup(global_long_options, sizeof global_long_options);
     allocated_options = ARRAY_SIZE(global_long_options);
     n_options = n_global_long_options;
-    for (p = all_commands; p->name; p++) {
+    for (p = get_all_commands(); p->name; p++) {
         if (p->options[0]) {
             char *save_ptr = NULL;
             char *name;
@@ -544,7 +542,7 @@ find_command(const char *name)
     if (shash_is_empty(&commands)) {
         const struct vtep_ctl_command_syntax *p;
 
-        for (p = all_commands; p->name; p++) {
+        for (p = get_all_commands(); p->name; p++) {
             shash_add_assert(&commands, p->name, p);
         }
     }
@@ -3890,3 +3888,8 @@ static const struct vtep_ctl_command_syntax all_commands[] = {
     {NULL, 0, 0, NULL, NULL, NULL, NULL, RO},
 };
 
+static const struct vtep_ctl_command_syntax *
+get_all_commands(void)
+{
+    return all_commands;
+}
index 39cbba1..8ae6af7 100644 (file)
           expected as destination for received BFD packets.  The default is
           <code>00:23:20:00:00:01</code>.
         </column>
+
+       <column name="bfd" key="bfd_src_ip">
+          Set to an IPv4 address to set the IP address used as source for
+          transmitted BFD packets.  The default is <code>169.254.1.0</code>.
+       </column>
+
+       <column name="bfd" key="bfd_dst_ip">
+          Set to an IPv4 address to set the IP address used as destination
+          for transmitted BFD packets.  The default is <code>169.254.1.1</code>.
+       </column>
       </group>
 
       <group title="BFD Status">