Merge branch 'mainstream'
authorGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Tue, 10 Dec 2013 13:38:28 +0000 (14:38 +0100)
committerGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Tue, 10 Dec 2013 13:38:28 +0000 (14:38 +0100)
65 files changed:
DESIGN
NEWS
OPENFLOW-1.1+
PORTING
acinclude.m4
build-aux/cccl
configure.ac
datapath/datapath.c
datapath/datapath.h
datapath/flow.c
datapath/flow.h
datapath/flow_netlink.c
datapath/flow_netlink.h
datapath/flow_table.c
datapath/flow_table.h
datapath/linux/compat/flow_dissector.c
datapath/linux/compat/include/linux/net.h
datapath/linux/compat/include/linux/skbuff.h
datapath/linux/compat/include/net/flow_keys.h
datapath/linux/compat/include/net/genetlink.h
datapath/linux/compat/include/net/ipv6.h
datapath/linux/compat/utils.c
datapath/vport-lisp.c
include/openflow/openflow-1.1.h
include/openflow/openflow-common.h
lib/automake.mk
lib/bfd.c
lib/bfd.h
lib/byte-order.h
lib/flow.c
lib/flow.h
lib/match.c
lib/meta-flow.c
lib/meta-flow.h
lib/odp-util.c
lib/ofp-util.c
lib/ovs-thread.c
lib/ovs-thread.h
lib/packets.c
lib/packets.h
lib/pcap-file.c
lib/util.c
lib/util.h
lib/vlog.c
lib/vlog.h
lib/vlog.man
m4/openvswitch.m4
ofproto/automake.mk
ofproto/bond.c [moved from lib/bond.c with 100% similarity]
ofproto/bond.h [moved from lib/bond.h with 100% similarity]
ofproto/ofproto-dpif-xlate.c
ofproto/ofproto-dpif.c
ofproto/ofproto.c
rhel/openvswitch-fedora.spec.in
tests/bfd.at
tests/library.at
tests/ofp-print.at
tests/ofproto-dpif.at
tests/ofproto.at
tests/ovs-ofctl.at
tests/test-util.c
utilities/ovs-appctl.8.in
utilities/ovs-ofctl.8.in
vswitchd/bridge.c
vswitchd/system-stats.c

diff --git a/DESIGN b/DESIGN
index d36b025..4d654d0 100644 (file)
--- a/DESIGN
+++ b/DESIGN
@@ -266,6 +266,53 @@ OpenFlow 1.3 makes these changes:
 The table for 1.3 is the same as the one shown above for 1.2.
 
 
+OFPT_PACKET_IN
+==============
+
+The OpenFlow 1.1 specification for OFPT_PACKET_IN is confusing.  The
+definition in OF1.1 openflow.h is[*]:
+
+  /* Packet received on port (datapath -> controller). */
+  struct ofp_packet_in {
+      struct ofp_header header;
+      uint32_t buffer_id;     /* ID assigned by datapath. */
+      uint32_t in_port;       /* Port on which frame was received. */
+      uint32_t in_phy_port;   /* Physical Port on which frame was received. */
+      uint16_t total_len;     /* Full length of frame. */
+      uint8_t reason;         /* Reason packet is being sent (one of OFPR_*) */
+      uint8_t table_id;       /* ID of the table that was looked up */
+      uint8_t data[0];        /* Ethernet frame, halfway through 32-bit word,
+                                 so the IP header is 32-bit aligned.  The
+                                 amount of data is inferred from the length
+                                 field in the header.  Because of padding,
+                                 offsetof(struct ofp_packet_in, data) ==
+                                 sizeof(struct ofp_packet_in) - 2. */
+  };
+  OFP_ASSERT(sizeof(struct ofp_packet_in) == 24);
+
+The confusing part is the comment on the data[] member.  This comment
+is a leftover from OF1.0 openflow.h, in which the comment was correct:
+sizeof(struct ofp_packet_in) is 20 in OF1.0 and offsetof(struct
+ofp_packet_in, data) is 18.  When OF1.1 was written, the structure
+members were changed but the comment was carelessly not updated, and
+the comment became wrong: sizeof(struct ofp_packet_in) and
+offsetof(struct ofp_packet_in, data) are both 24 in OF1.1.
+
+That leaves the question of how to implement ofp_packet_in in OF1.1.
+The OpenFlow reference implementation for OF1.1 does not include any
+padding, that is, the first byte of the encapsulated frame immediately
+follows the 'table_id' member without a gap.  Open vSwitch therefore
+implements it the same way for compatibility.
+
+For an earlier discussion, please see the thread archived at:
+https://mailman.stanford.edu/pipermail/openflow-discuss/2011-August/002604.html
+
+[*] The quoted definition is directly from OF1.1.  Definitions used
+    inside OVS omit the 8-byte ofp_header members, so the sizes in
+    this discussion are 8 bytes larger than those declared in OVS
+    header files.
+
+
 VLAN Matching
 =============
 
diff --git a/NEWS b/NEWS
index 38e3d9d..8556083 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -23,6 +23,7 @@ Post-v2.0.0
      packaged or installed by default, because too many users assumed
      incorrectly that ovs-controller was a necessary or desirable part
      of an Open vSwitch deployment.
+   - Added vlog option to export to a UDP syslog sink.
 
 
 v2.0.0 - 15 Oct 2013
index e194ba7..eaf2ee9 100644 (file)
@@ -54,13 +54,6 @@ OpenFlow 1.1
 The list of remaining work items for OpenFlow 1.1 is below.  It is
 probably incomplete.
 
-    * The new in_phy_port field in OFPT_PACKET_IN needs some kind of
-      implementation.  It has a sensible interpretation for tunnels
-      but in general the physical port is not in the datapath for OVS
-      so the value is not necessarily meaningful.  We might have to
-      just fix it as the same as in_port.
-      [required for OF1.1; optional for OF1.2+]
-
     * OFPT_TABLE_MOD message.  This is new in OF1.1, so we need to
       implement it.  It should be implemented so that the default OVS
       behavior does not change.
@@ -86,11 +79,6 @@ additional work specific to Openflow 1.2 are complete.  (This is based
 on the change log at the end of the OF1.2 spec.  I didn't compare the
 specs carefully yet.)
 
-    * Action translation needs some work to transform OpenFlow 1.1
-      field modification actions into OpenFlow 1.2+ "set-field"
-      actions, because OpenFlow 1.2 dropped support for the OF1.1
-      actions.
-
 OpenFlow 1.3
 ------------
 
@@ -124,11 +112,6 @@ didn't compare the specs carefully yet.)
       is missing.  Support for the software switch is under review.
       [optional for OF1.3+]
 
-    * Per-connection event filtering.  OF1.3 adopted Open vSwitch's
-      existing design for this feature so implementation should be
-      easy.
-      [required for OF1.3+]
-
     * Auxiliary connections.  An implementation in generic code might
       be a week's worth of work.  The value of an implementation in
       generic code is questionable, though, since much of the benefit
diff --git a/PORTING b/PORTING
index 53c19d3..88694a4 100644 (file)
--- a/PORTING
+++ b/PORTING
@@ -18,7 +18,7 @@ is a concordance, indexed by the area of the source tree:
         datapath/       vport           ---
         vswitchd/       iface           port
         ofproto/        port            bundle
-        lib/bond.c      slave           bond
+        ofproto/bond.c  slave           bond
         lib/lacp.c      slave           lacp
         lib/netdev.c    netdev          ---
         database        Interface       Port
index f987fa0..94f9b61 100644 (file)
@@ -240,6 +240,7 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
   # quoting rules.
   OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [[[^@]]proto_data_valid],
                   [OVS_DEFINE([HAVE_PROTO_DATA_VALID])])
+  OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [rxhash])
   OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [skb_dst(],
                   [OVS_DEFINE([HAVE_SKB_DST_ACCESSOR_FUNCS])])
   OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], 
index c614ecb..f6972d4 100644 (file)
@@ -90,6 +90,7 @@ EOF
     -g[0-9] | -g)
         # cl only supports one debugging level
         clopt="$clopt ${slash}Zi"
+        linkopt="$linkopt ${slash}DEBUG"
         ;;
 
     -L*)
index 13d2d31..167cc71 100644 (file)
@@ -83,6 +83,7 @@ OVS_CHECK_XENSERVER_VERSION
 OVS_CHECK_GROFF
 OVS_CHECK_GNU_MAKE
 OVS_CHECK_TLS
+OVS_CHECK_ATOMIC_LIBS
 OVS_CHECK_GCC4_ATOMICS
 OVS_CHECK_ATOMIC_ALWAYS_LOCK_FREE(1)
 OVS_CHECK_ATOMIC_ALWAYS_LOCK_FREE(2)
index d0a8595..1808c36 100644 (file)
@@ -404,6 +404,13 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex,
        struct sk_buff *nskb = NULL;
        struct sk_buff *user_skb; /* to be queued to userspace */
        struct nlattr *nla;
+       struct genl_info info = {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
+               .dst_sk = net->genl_sock,
+#endif
+               .snd_portid = upcall_info->portid,
+       };
+       size_t len;
        int err;
 
        if (vlan_tx_tag_present(skb)) {
@@ -425,7 +432,8 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex,
                goto out;
        }
 
-       user_skb = genlmsg_new(upcall_msg_size(skb, upcall_info->userdata), GFP_ATOMIC);
+       len = upcall_msg_size(skb, upcall_info->userdata);
+       user_skb = genlmsg_new_unicast(len, &info, GFP_ATOMIC);
        if (!user_skb) {
                err = -ENOMEM;
                goto out;
@@ -494,7 +502,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
                packet->protocol = htons(ETH_P_802_2);
 
        /* Build an sw_flow for sending this packet. */
-       flow = ovs_flow_alloc();
+       flow = ovs_flow_alloc(false);
        err = PTR_ERR(flow);
        if (IS_ERR(flow))
                goto err_kfree_skb;
@@ -629,7 +637,9 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
 {
        const int skb_orig_len = skb->len;
        struct nlattr *start;
-       struct sw_flow_stats flow_stats;
+       struct ovs_flow_stats stats;
+       __be16 tcp_flags;
+       unsigned long used;
        struct ovs_header *ovs_header;
        struct nlattr *nla;
        int err;
@@ -660,25 +670,17 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
 
        nla_nest_end(skb, nla);
 
-       ovs_flow_stats_get(flow, &flow_stats);
-       if (flow_stats.used &&
-           nla_put_u64(skb, OVS_FLOW_ATTR_USED, ovs_flow_used_time(flow_stats.used)))
+       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;
 
-       if (flow_stats.packet_count) {
-               struct ovs_flow_stats stats = {
-                       .n_packets = flow_stats.packet_count,
-                       .n_bytes = flow_stats.byte_count,
-               };
-
-               if (nla_put(skb, OVS_FLOW_ATTR_STATS,
-                           sizeof(struct ovs_flow_stats), &stats))
-                       goto nla_put_failure;
-       }
+       if (stats.n_packets &&
+           nla_put(skb, OVS_FLOW_ATTR_STATS, sizeof(struct ovs_flow_stats), &stats))
+               goto nla_put_failure;
 
-       if ((u8)ntohs(flow_stats.tcp_flags) &&
-           nla_put_u8(skb, OVS_FLOW_ATTR_TCP_FLAGS,
-                      (u8)ntohs(flow_stats.tcp_flags)))
+       if ((u8)ntohs(tcp_flags) &&
+            nla_put_u8(skb, OVS_FLOW_ATTR_TCP_FLAGS, (u8)ntohs(tcp_flags)))
                goto nla_put_failure;
 
        /* If OVS_FLOW_ATTR_ACTIONS doesn't fit, skip dumping the actions if
@@ -695,8 +697,7 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
        if (start) {
                const struct sw_flow_actions *sf_acts;
 
-               sf_acts = rcu_dereference_check(flow->sf_acts,
-                                               lockdep_ovsl_is_held());
+               sf_acts = rcu_dereference_ovsl(flow->sf_acts);
 
                err = ovs_nla_put_actions(sf_acts->actions,
                                          sf_acts->actions_len, skb);
@@ -720,27 +721,30 @@ error:
        return err;
 }
 
-static struct sk_buff *ovs_flow_cmd_alloc_info(struct sw_flow *flow)
+static struct sk_buff *ovs_flow_cmd_alloc_info(struct sw_flow *flow,
+                                              struct genl_info *info)
 {
-       const struct sw_flow_actions *sf_acts;
+       size_t len;
 
-       sf_acts = ovsl_dereference(flow->sf_acts);
+       len = ovs_flow_cmd_msg_size(ovsl_dereference(flow->sf_acts));
 
-       return genlmsg_new(ovs_flow_cmd_msg_size(sf_acts), GFP_KERNEL);
+       return genlmsg_new_unicast(len, info, GFP_KERNEL);
 }
 
 static struct sk_buff *ovs_flow_cmd_build_info(struct sw_flow *flow,
                                               struct datapath *dp,
-                                              u32 portid, u32 seq, u8 cmd)
+                                              struct genl_info *info,
+                                              u8 cmd)
 {
        struct sk_buff *skb;
        int retval;
 
-       skb = ovs_flow_cmd_alloc_info(flow);
+       skb = ovs_flow_cmd_alloc_info(flow, info);
        if (!skb)
                return ERR_PTR(-ENOMEM);
 
-       retval = ovs_flow_cmd_fill_info(flow, dp, skb, portid, seq, 0, cmd);
+       retval = ovs_flow_cmd_fill_info(flow, dp, skb, info->snd_portid,
+                                       info->snd_seq, 0, cmd);
        BUG_ON(retval < 0);
        return skb;
 }
@@ -756,6 +760,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
        struct datapath *dp;
        struct sw_flow_actions *acts = NULL;
        struct sw_flow_match match;
+       bool exact_5tuple;
        int error;
 
        /* Extract key. */
@@ -764,7 +769,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
                goto error;
 
        ovs_match_init(&match, &key, &mask);
-       error = ovs_nla_get_match(&match,
+       error = ovs_nla_get_match(&match, &exact_5tuple,
                                  a[OVS_FLOW_ATTR_KEY], a[OVS_FLOW_ATTR_MASK]);
        if (error)
                goto error;
@@ -803,7 +808,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
                        goto err_unlock_ovs;
 
                /* Allocate flow. */
-               flow = ovs_flow_alloc();
+               flow = ovs_flow_alloc(!exact_5tuple);
                if (IS_ERR(flow)) {
                        error = PTR_ERR(flow);
                        goto err_unlock_ovs;
@@ -820,8 +825,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
                        goto err_flow_free;
                }
 
-               reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid,
-                                               info->snd_seq, OVS_FLOW_CMD_NEW);
+               reply = ovs_flow_cmd_build_info(flow, dp, info, OVS_FLOW_CMD_NEW);
        } else {
                /* We found a matching flow. */
                struct sw_flow_actions *old_acts;
@@ -849,8 +853,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
                rcu_assign_pointer(flow->sf_acts, acts);
                ovs_nla_free_flow_actions(old_acts);
 
-               reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid,
-                                              info->snd_seq, OVS_FLOW_CMD_NEW);
+               reply = ovs_flow_cmd_build_info(flow, dp, info, OVS_FLOW_CMD_NEW);
 
                /* Clear stats. */
                if (a[OVS_FLOW_ATTR_CLEAR])
@@ -892,7 +895,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
        }
 
        ovs_match_init(&match, &key, NULL);
-       err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL);
+       err = ovs_nla_get_match(&match, NULL, a[OVS_FLOW_ATTR_KEY], NULL);
        if (err)
                return err;
 
@@ -909,8 +912,7 @@ 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->snd_portid,
-                                       info->snd_seq, OVS_FLOW_CMD_NEW);
+       reply = ovs_flow_cmd_build_info(flow, dp, info, OVS_FLOW_CMD_NEW);
        if (IS_ERR(reply)) {
                err = PTR_ERR(reply);
                goto unlock;
@@ -947,7 +949,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
        }
 
        ovs_match_init(&match, &key, NULL);
-       err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL);
+       err = ovs_nla_get_match(&match, NULL, a[OVS_FLOW_ATTR_KEY], NULL);
        if (err)
                goto unlock;
 
@@ -957,7 +959,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
                goto unlock;
        }
 
-       reply = ovs_flow_cmd_alloc_info(flow);
+       reply = ovs_flow_cmd_alloc_info(flow, info);
        if (!reply) {
                err = -ENOMEM;
                goto unlock;
@@ -1109,17 +1111,17 @@ error:
        return -EMSGSIZE;
 }
 
-static struct sk_buff *ovs_dp_cmd_build_info(struct datapath *dp, u32 portid,
-                                            u32 seq, u8 cmd)
+static struct sk_buff *ovs_dp_cmd_build_info(struct datapath *dp,
+                                            struct genl_info *info, u8 cmd)
 {
        struct sk_buff *skb;
        int retval;
 
-       skb = genlmsg_new(ovs_dp_cmd_msg_size(), GFP_KERNEL);
+       skb = genlmsg_new_unicast(ovs_dp_cmd_msg_size(), info, GFP_KERNEL);
        if (!skb)
                return ERR_PTR(-ENOMEM);
 
-       retval = ovs_dp_cmd_fill_info(dp, skb, portid, seq, 0, cmd);
+       retval = ovs_dp_cmd_fill_info(dp, skb, info->snd_portid, info->snd_seq, 0, cmd);
        if (retval < 0) {
                kfree_skb(skb);
                return ERR_PTR(retval);
@@ -1208,8 +1210,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
                goto err_destroy_ports_array;
        }
 
-       reply = ovs_dp_cmd_build_info(dp, info->snd_portid,
-                                     info->snd_seq, OVS_DP_CMD_NEW);
+       reply = ovs_dp_cmd_build_info(dp, info, OVS_DP_CMD_NEW);
        err = PTR_ERR(reply);
        if (IS_ERR(reply))
                goto err_destroy_local_port;
@@ -1275,8 +1276,7 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info)
        if (IS_ERR(dp))
                goto unlock;
 
-       reply = ovs_dp_cmd_build_info(dp, info->snd_portid,
-                                     info->snd_seq, OVS_DP_CMD_DEL);
+       reply = ovs_dp_cmd_build_info(dp, info, OVS_DP_CMD_DEL);
        err = PTR_ERR(reply);
        if (IS_ERR(reply))
                goto unlock;
@@ -1304,8 +1304,7 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
        if (IS_ERR(dp))
                goto unlock;
 
-       reply = ovs_dp_cmd_build_info(dp, info->snd_portid,
-                                     info->snd_seq, OVS_DP_CMD_NEW);
+       reply = ovs_dp_cmd_build_info(dp, info, OVS_DP_CMD_NEW);
        if (IS_ERR(reply)) {
                err = PTR_ERR(reply);
                netlink_set_err(sock_net(skb->sk)->genl_sock, 0,
@@ -1336,8 +1335,7 @@ static int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info)
                goto unlock;
        }
 
-       reply = ovs_dp_cmd_build_info(dp, info->snd_portid,
-                                     info->snd_seq, OVS_DP_CMD_NEW);
+       reply = ovs_dp_cmd_build_info(dp, info, OVS_DP_CMD_NEW);
        if (IS_ERR(reply)) {
                err = PTR_ERR(reply);
                goto unlock;
index 879a830..89ba80f 100644 (file)
@@ -148,6 +148,8 @@ int lockdep_ovsl_is_held(void);
 #define ASSERT_OVSL()          WARN_ON(unlikely(!lockdep_ovsl_is_held()))
 #define ovsl_dereference(p)                                    \
        rcu_dereference_protected(p, lockdep_ovsl_is_held())
+#define rcu_dereference_ovsl(p)                                        \
+       rcu_dereference_check(p, lockdep_ovsl_is_held())
 
 static inline struct net *ovs_dp_get_net(struct datapath *dp)
 {
index 57eb6b5..9b3d3a7 100644 (file)
@@ -64,9 +64,14 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies)
 
 void ovs_flow_stats_update(struct sw_flow *flow, struct sk_buff *skb)
 {
-       struct sw_flow_stats *stats = &flow->stats[smp_processor_id()];
+       struct flow_stats *stats;
        __be16 tcp_flags = 0;
 
+       if (!flow->stats.is_percpu)
+               stats = flow->stats.stat;
+       else
+               stats = this_cpu_ptr(flow->stats.cpu_stats);
+
        if ((flow->key.eth.type == htons(ETH_P_IP) ||
             flow->key.eth.type == htons(ETH_P_IPV6)) &&
            flow->key.ip.proto == IPPROTO_TCP &&
@@ -82,56 +87,79 @@ void ovs_flow_stats_update(struct sw_flow *flow, struct sk_buff *skb)
        spin_unlock(&stats->lock);
 }
 
-void ovs_flow_stats_get(struct sw_flow *flow, struct sw_flow_stats *res)
+static void stats_read(struct flow_stats *stats,
+                      struct ovs_flow_stats *ovs_stats,
+                      unsigned long *used, __be16 *tcp_flags)
 {
-       int cpu, cur_cpu;
+       spin_lock(&stats->lock);
+       if (time_after(stats->used, *used))
+               *used = stats->used;
+       *tcp_flags |= stats->tcp_flags;
+       ovs_stats->n_packets += stats->packet_count;
+       ovs_stats->n_bytes += stats->byte_count;
+       spin_unlock(&stats->lock);
+}
 
-       memset(res, 0, sizeof(*res));
+void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *ovs_stats,
+                       unsigned long *used, __be16 *tcp_flags)
+{
+       int cpu, cur_cpu;
 
-       cur_cpu = get_cpu();
-       for_each_possible_cpu(cpu) {
-               struct sw_flow_stats *stats = &flow->stats[cpu];
+       *used = 0;
+       *tcp_flags = 0;
+       memset(ovs_stats, 0, sizeof(*ovs_stats));
 
-               if (cpu == cur_cpu)
-                       local_bh_disable();
+       if (!flow->stats.is_percpu) {
+               stats_read(flow->stats.stat, ovs_stats, used, tcp_flags);
+       } else {
+               cur_cpu = get_cpu();
+               for_each_possible_cpu(cpu) {
+                       struct flow_stats *stats;
 
-               spin_lock(&stats->lock);
-               if (time_after(stats->used, res->used))
-                       res->used = stats->used;
-               res->packet_count += stats->packet_count;
-               res->byte_count += stats->byte_count;
-               res->tcp_flags |= stats->tcp_flags;
-               spin_unlock(&stats->lock);
+                       if (cpu == cur_cpu)
+                               local_bh_disable();
 
-               if (cpu == cur_cpu)
-                       local_bh_enable();
+                       stats = per_cpu_ptr(flow->stats.cpu_stats, cpu);
+                       stats_read(stats, ovs_stats, used, tcp_flags);
 
+                       if (cpu == cur_cpu)
+                               local_bh_enable();
+               }
+               put_cpu();
        }
-       put_cpu();
+}
+
+static void stats_reset(struct flow_stats *stats)
+{
+       spin_lock(&stats->lock);
+       stats->used = 0;
+       stats->packet_count = 0;
+       stats->byte_count = 0;
+       stats->tcp_flags = 0;
+       spin_unlock(&stats->lock);
 }
 
 void ovs_flow_stats_clear(struct sw_flow *flow)
 {
        int cpu, cur_cpu;
 
-       cur_cpu = get_cpu();
-       for_each_possible_cpu(cpu) {
-               struct sw_flow_stats *stats = &flow->stats[cpu];
+       if (!flow->stats.is_percpu) {
+               stats_reset(flow->stats.stat);
+       } else {
+               cur_cpu = get_cpu();
+
+               for_each_possible_cpu(cpu) {
 
-               if (cpu == cur_cpu)
-                       local_bh_disable();
+                       if (cpu == cur_cpu)
+                               local_bh_disable();
 
-               spin_lock(&stats->lock);
-               stats->used = 0;
-               stats->packet_count = 0;
-               stats->byte_count = 0;
-               stats->tcp_flags = 0;
-               spin_unlock(&stats->lock);
+                       stats_reset(per_cpu_ptr(flow->stats.cpu_stats, cpu));
 
-               if (cpu == cur_cpu)
-                       local_bh_enable();
+                       if (cpu == cur_cpu)
+                               local_bh_enable();
+               }
+               put_cpu();
        }
-       put_cpu();
 }
 
 static int check_header(struct sk_buff *skb, int len)
index 6b68cf1..eafcfd8 100644 (file)
@@ -149,13 +149,21 @@ struct sw_flow_actions {
        struct nlattr actions[];
 };
 
-struct sw_flow_stats {
+struct flow_stats {
        u64 packet_count;               /* Number of packets matched. */
        u64 byte_count;                 /* Number of bytes matched. */
        unsigned long used;             /* Last used time (in jiffies). */
        spinlock_t lock;                /* Lock for atomic stats update. */
        __be16 tcp_flags;               /* Union of seen TCP flags. */
-} ____cacheline_aligned_in_smp;
+};
+
+struct sw_flow_stats {
+       bool is_percpu;
+       union {
+               struct flow_stats *stat;
+               struct flow_stats __percpu *cpu_stats;
+       };
+};
 
 struct sw_flow {
        struct rcu_head rcu;
@@ -166,7 +174,7 @@ struct sw_flow {
        struct sw_flow_key unmasked_key;
        struct sw_flow_mask *mask;
        struct sw_flow_actions __rcu *sf_acts;
-       struct sw_flow_stats stats[];
+       struct sw_flow_stats stats;
 };
 
 struct arp_eth_header {
@@ -184,7 +192,8 @@ struct arp_eth_header {
 } __packed;
 
 void ovs_flow_stats_update(struct sw_flow *flow, struct sk_buff *skb);
-void ovs_flow_stats_get(struct sw_flow *flow, struct sw_flow_stats *res);
+void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *stats,
+                       unsigned long *used, __be16 *tcp_flags);
 void ovs_flow_stats_clear(struct sw_flow *flow);
 u64 ovs_flow_used_time(unsigned long flow_jiffies);
 
index 75c72b3..9b26528 100644 (file)
@@ -266,6 +266,20 @@ static bool is_all_zero(const u8 *fp, size_t size)
        return true;
 }
 
+static bool is_all_set(const u8 *fp, size_t size)
+{
+       int i;
+
+       if (!fp)
+               return false;
+
+       for (i = 0; i < size; i++)
+               if (fp[i] != 0xff)
+                       return false;
+
+       return true;
+}
+
 static int __parse_flow_nlattrs(const struct nlattr *attr,
                                const struct nlattr *a[],
                                u64 *attrsp, bool nz)
@@ -487,8 +501,9 @@ static int metadata_from_nlattrs(struct sw_flow_match *match,  u64 *attrs,
        return 0;
 }
 
-static int ovs_key_from_nlattrs(struct sw_flow_match *match,  u64 attrs,
-                               const struct nlattr **a, bool is_mask)
+static int ovs_key_from_nlattrs(struct sw_flow_match *match,  bool *exact_5tuple,
+                               u64 attrs, const struct nlattr **a,
+                               bool is_mask)
 {
        int err;
        u64 orig_attrs = attrs;
@@ -545,6 +560,11 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match,  u64 attrs,
                SW_FLOW_KEY_PUT(match, eth.type, htons(ETH_P_802_2), is_mask);
        }
 
+       if (is_mask && exact_5tuple) {
+               if (match->mask->key.eth.type != htons(0xffff))
+                       *exact_5tuple = false;
+       }
+
        if (attrs & (1ULL << OVS_KEY_ATTR_IPV4)) {
                const struct ovs_key_ipv4 *ipv4_key;
 
@@ -567,6 +587,13 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match,  u64 attrs,
                SW_FLOW_KEY_PUT(match, ipv4.addr.dst,
                                ipv4_key->ipv4_dst, is_mask);
                attrs &= ~(1ULL << OVS_KEY_ATTR_IPV4);
+
+               if (is_mask && exact_5tuple && *exact_5tuple) {
+                       if (ipv4_key->ipv4_proto != 0xff ||
+                           ipv4_key->ipv4_src != htonl(0xffffffff) ||
+                           ipv4_key->ipv4_dst != htonl(0xffffffff))
+                               *exact_5tuple = false;
+               }
        }
 
        if (attrs & (1ULL << OVS_KEY_ATTR_IPV6)) {
@@ -598,6 +625,13 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match,  u64 attrs,
                                is_mask);
 
                attrs &= ~(1ULL << OVS_KEY_ATTR_IPV6);
+
+               if (is_mask && exact_5tuple && *exact_5tuple) {
+                       if (ipv6_key->ipv6_proto != 0xff ||
+                           !is_all_set((u8 *)ipv6_key->ipv6_src, sizeof(match->key->ipv6.addr.src)) ||
+                           !is_all_set((u8 *)ipv6_key->ipv6_dst, sizeof(match->key->ipv6.addr.dst)))
+                               *exact_5tuple = false;
+               }
        }
 
        if (attrs & (1ULL << OVS_KEY_ATTR_ARP)) {
@@ -640,6 +674,11 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match,  u64 attrs,
                                        tcp_key->tcp_dst, is_mask);
                }
                attrs &= ~(1ULL << OVS_KEY_ATTR_TCP);
+
+               if (is_mask && exact_5tuple && *exact_5tuple &&
+                   (tcp_key->tcp_src != htons(0xffff) ||
+                    tcp_key->tcp_dst != htons(0xffff)))
+                       *exact_5tuple = false;
        }
 
        if (attrs & (1ULL << OVS_KEY_ATTR_TCP_FLAGS)) {
@@ -671,6 +710,11 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match,  u64 attrs,
                                        udp_key->udp_dst, is_mask);
                }
                attrs &= ~(1ULL << OVS_KEY_ATTR_UDP);
+
+               if (is_mask && exact_5tuple && *exact_5tuple &&
+                   (udp_key->udp_src != htons(0xffff) ||
+                    udp_key->udp_dst != htons(0xffff)))
+                       *exact_5tuple = false;
        }
 
        if (attrs & (1ULL << OVS_KEY_ATTR_SCTP)) {
@@ -756,6 +800,7 @@ static void sw_flow_mask_set(struct sw_flow_mask *mask,
  * attribute specifies the mask field of the wildcarded flow.
  */
 int ovs_nla_get_match(struct sw_flow_match *match,
+                     bool *exact_5tuple,
                      const struct nlattr *key,
                      const struct nlattr *mask)
 {
@@ -803,10 +848,13 @@ int ovs_nla_get_match(struct sw_flow_match *match,
                }
        }
 
-       err = ovs_key_from_nlattrs(match, key_attrs, a, false);
+       err = ovs_key_from_nlattrs(match, NULL, key_attrs, a, false);
        if (err)
                return err;
 
+       if (exact_5tuple)
+               *exact_5tuple = true;
+
        if (mask) {
                err = parse_flow_mask_nlattrs(mask, a, &mask_attrs);
                if (err)
@@ -844,7 +892,7 @@ int ovs_nla_get_match(struct sw_flow_match *match,
                        }
                }
 
-               err = ovs_key_from_nlattrs(match, mask_attrs, a, true);
+               err = ovs_key_from_nlattrs(match, exact_5tuple, mask_attrs, a, true);
                if (err)
                        return err;
        } else {
index 4401510..b31fbe2 100644 (file)
@@ -45,6 +45,7 @@ int ovs_nla_put_flow(const struct sw_flow_key *,
 int ovs_nla_get_flow_metadata(struct sw_flow *flow,
                              const struct nlattr *attr);
 int ovs_nla_get_match(struct sw_flow_match *match,
+                     bool *exact_5tuple,
                      const struct nlattr *,
                      const struct nlattr *);
 
index 29cfcbe..6bb68d8 100644 (file)
@@ -73,7 +73,7 @@ void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src,
                *d++ = *s++ & *m++;
 }
 
-struct sw_flow *ovs_flow_alloc(void)
+struct sw_flow *ovs_flow_alloc(bool percpu_stats)
 {
        struct sw_flow *flow;
        int cpu;
@@ -85,11 +85,30 @@ struct sw_flow *ovs_flow_alloc(void)
        flow->sf_acts = NULL;
        flow->mask = NULL;
 
-       memset(flow->stats, 0, num_possible_cpus() * sizeof(struct sw_flow_stats));
-       for_each_possible_cpu(cpu)
-               spin_lock_init(&flow->stats[cpu].lock);
+       flow->stats.is_percpu = percpu_stats;
 
+       if (!percpu_stats) {
+               flow->stats.stat = kzalloc(sizeof(*flow->stats.stat), GFP_KERNEL);
+               if (!flow->stats.stat)
+                       goto err;
+
+               spin_lock_init(&flow->stats.stat->lock);
+       } else {
+               flow->stats.cpu_stats = alloc_percpu(struct flow_stats);
+               if (!flow->stats.cpu_stats)
+                       goto err;
+
+               for_each_possible_cpu(cpu) {
+                       struct flow_stats *cpu_stats;
+
+                       cpu_stats = per_cpu_ptr(flow->stats.cpu_stats, cpu);
+                       spin_lock_init(&cpu_stats->lock);
+               }
+       }
        return flow;
+err:
+       kfree(flow);
+       return ERR_PTR(-ENOMEM);
 }
 
 int ovs_flow_tbl_count(struct flow_table *table)
@@ -123,6 +142,10 @@ static struct flex_array *alloc_buckets(unsigned int n_buckets)
 static void flow_free(struct sw_flow *flow)
 {
        kfree((struct sf_flow_acts __force *)flow->sf_acts);
+       if (flow->stats.is_percpu)
+               free_percpu(flow->stats.cpu_stats);
+       else
+               kfree(flow->stats.stat);
        kmem_cache_free(flow_cache, flow);
 }
 
@@ -438,7 +461,7 @@ struct sw_flow *ovs_flow_tbl_lookup_stats(struct flow_table *tbl,
                                    const struct sw_flow_key *key,
                                    u32 *n_mask_hit)
 {
-       struct table_instance *ti = rcu_dereference(tbl->ti);
+       struct table_instance *ti = rcu_dereference_ovsl(tbl->ti);
        struct sw_flow_mask *mask;
        struct sw_flow *flow;
 
@@ -583,15 +606,11 @@ int ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow,
  * Returns zero if successful or a negative error code. */
 int ovs_flow_init(void)
 {
-       int flow_size;
-
        BUILD_BUG_ON(__alignof__(struct sw_flow_key) % __alignof__(long));
        BUILD_BUG_ON(sizeof(struct sw_flow_key) % sizeof(long));
 
-       flow_size = sizeof(struct sw_flow) +
-                   (num_possible_cpus() * sizeof(struct sw_flow_stats));
-
-       flow_cache = kmem_cache_create("sw_flow", flow_size, 0, 0, NULL);
+       flow_cache = kmem_cache_create("sw_flow", sizeof(struct sw_flow), 0,
+                                       0, NULL);
        if (flow_cache == NULL)
                return -ENOMEM;
 
index f54aa82..1996e34 100644 (file)
@@ -55,7 +55,7 @@ struct flow_table {
 int ovs_flow_init(void);
 void ovs_flow_exit(void);
 
-struct sw_flow *ovs_flow_alloc(void);
+struct sw_flow *ovs_flow_alloc(bool percpu_stats);
 void ovs_flow_free(struct sw_flow *, bool deferred);
 
 int ovs_flow_tbl_init(struct flow_table *);
index 8592ca9..7a0d09b 100644 (file)
@@ -19,7 +19,7 @@
  */
 
 #include <linux/version.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <linux/if_vlan.h>
@@ -46,9 +46,25 @@ static void iph_to_flow_copy_addrs(struct flow_keys *flow, const struct iphdr *i
        memcpy(&flow->src, &iph->saddr, sizeof(flow->src) + sizeof(flow->dst));
 }
 
+__be32 skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto)
+{
+       int poff = proto_ports_offset(ip_proto);
+
+       if (poff >= 0) {
+               __be32 *ports, _ports;
+
+               ports = skb_header_pointer(skb, thoff + poff,
+                               sizeof(_ports), &_ports);
+               if (ports)
+                       return *ports;
+       }
+
+       return 0;
+}
+
 static bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow)
 {
-       int poff, nhoff = skb_network_offset(skb);
+       int nhoff = skb_network_offset(skb);
        u8 ip_proto;
        __be16 proto = skb->protocol;
 
@@ -86,6 +102,7 @@ ipv6:
                nhoff += sizeof(struct ipv6hdr);
                break;
        }
+       case __constant_htons(ETH_P_8021AD):
        case __constant_htons(ETH_P_8021Q): {
                const struct vlan_hdr *vlan;
                struct vlan_hdr _vlan;
@@ -161,33 +178,30 @@ ipv6:
        }
        case IPPROTO_IPIP:
                goto again;
+       case IPPROTO_IPV6:
+               proto = htons(ETH_P_IPV6);
+               goto ipv6;
        default:
                break;
        }
 
        flow->ip_proto = ip_proto;
-       poff = proto_ports_offset(ip_proto);
-       if (poff >= 0) {
-               __be32 *ports, _ports;
-
-               nhoff += poff;
-               ports = skb_header_pointer(skb, nhoff, sizeof(_ports), &_ports);
-               if (ports)
-                       flow->ports = *ports;
-       }
-
+       flow->ports = skb_flow_get_ports(skb, nhoff, ip_proto);
        flow->thoff = (u16) nhoff;
 
        return true;
 }
 
 static u32 hashrnd __read_mostly;
+static __always_inline void __flow_hash_secret_init(void)
+{
+       net_get_random_once(&hashrnd, sizeof(hashrnd));
+}
 
-static void init_hashrnd(void)
+static __always_inline u32 __flow_hash_3words(u32 a, u32 b, u32 c)
 {
-       if (likely(hashrnd))
-               return;
-       get_random_bytes(&hashrnd, sizeof(hashrnd));
+       __flow_hash_secret_init();
+       return jhash_3words(a, b, c, hashrnd);
 }
 
 u32 __skb_get_rxhash(struct sk_buff *skb)
@@ -206,15 +220,13 @@ u32 __skb_get_rxhash(struct sk_buff *skb)
                swap(keys.port16[0], keys.port16[1]);
        }
 
-       init_hashrnd();
-
-       hash = jhash_3words((__force u32)keys.dst,
-                           (__force u32)keys.src,
-                           (__force u32)keys.ports, hashrnd);
+       hash = __flow_hash_3words((__force u32)keys.dst,
+                                 (__force u32)keys.src,
+                                 (__force u32)keys.ports);
        if (!hash)
                hash = 1;
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34)
+#ifdef HAVE_RXHASH
        skb->rxhash = hash;
 #endif
        return hash;
index 5665e2e..d8bf621 100644 (file)
@@ -2,6 +2,7 @@
 #define __LINUX_NET_WRAPPER_H 1
 
 #include_next <linux/net.h>
+#include <linux/types.h>
 
 #ifndef net_ratelimited_function
 #define net_ratelimited_function(function, ...)                        \
@@ -28,4 +29,26 @@ do {                                                         \
        net_ratelimited_function(pr_debug, fmt, ##__VA_ARGS__)
 #endif
 
+#ifndef net_get_random_once
+bool __net_get_random_once(void *buf, int nbytes, bool *done,
+                          atomic_t *done_key);
+
+#define ___NET_RANDOM_STATIC_KEY_INIT  ATOMIC_INIT(0)
+
+
+#define net_get_random_once(buf, nbytes)                       \
+({                                                             \
+       bool ___ret = false;                                    \
+       static bool ___done = false;                            \
+       static atomic_t ___done_key =                           \
+                       ___NET_RANDOM_STATIC_KEY_INIT;          \
+       if (!atomic_read(&___done_key))                         \
+               ___ret = __net_get_random_once(buf,             \
+                                              nbytes,          \
+                                              &___done,        \
+                                              &___done_key);   \
+       ___ret;                                                 \
+})
+#endif
+
 #endif
index 9868a98..4f22600 100644 (file)
@@ -213,12 +213,16 @@ static inline int skb_unclone(struct sk_buff *skb, gfp_t pri)
 }
 #endif
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
+#define __skb_get_rxhash rpl__skb_get_rxhash
+#define skb_get_rxhash rpl_skb_get_rxhash
+
 extern u32 __skb_get_rxhash(struct sk_buff *skb);
 static inline __u32 skb_get_rxhash(struct sk_buff *skb)
 {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34)
-       if (!skb->rxhash)
+#ifdef HAVE_RXHASH
+       if (skb->rxhash)
+               return skb->rxhash;
 #endif
        return __skb_get_rxhash(skb);
 }
index 4de17d1..766b4b3 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <linux/version.h>
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
 #include_next <net/flow_keys.h>
 #else
 struct flow_keys {
index 91be168..09ee23b 100644 (file)
 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,14,0)
+static inline struct sk_buff *genlmsg_new_unicast(size_t payload,
+                                                 struct genl_info *info,
+                                                 gfp_t flags)
+{
+       return genlmsg_new(payload, flags);
+}
+#endif
+
 #endif /* genetlink.h */
index 71f4708..eebb1fe 100644 (file)
@@ -27,7 +27,7 @@ enum {
 extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
                         int target, unsigned short *fragoff, int *fragflg);
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)
 static inline u32 ipv6_addr_hash(const struct in6_addr *a)
 {
 #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
index 844d372..dc4df2a 100644 (file)
@@ -37,3 +37,24 @@ void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
                                        csum_unfold(*sum)));
 }
 #endif
+
+bool __net_get_random_once(void *buf, int nbytes, bool *done,
+                          atomic_t *done_key)
+{
+       static DEFINE_SPINLOCK(lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&lock, flags);
+       if (*done) {
+               spin_unlock_irqrestore(&lock, flags);
+               return false;
+       }
+
+       get_random_bytes(buf, nbytes);
+       *done = true;
+       spin_unlock_irqrestore(&lock, flags);
+
+       atomic_set(done_key, 1);
+
+       return true;
+}
index e4e603f..c2698ae 100644 (file)
@@ -165,12 +165,17 @@ static __be64 instance_id_to_tunnel_id(__u8 *iid)
  */
 static u16 get_src_port(struct sk_buff *skb)
 {
-       int low;
-       int high;
+       u32 hash = skb_get_rxhash(skb);
        unsigned int range;
-       struct sw_flow_key *pkt_key = OVS_CB(skb)->pkt_key;
-       u32 hash = jhash2((const u32 *)pkt_key,
-                         sizeof(*pkt_key) / sizeof(u32), 0);
+       int high;
+       int low;
+
+       if (!hash) {
+               struct sw_flow_key *pkt_key = OVS_CB(skb)->pkt_key;
+
+               hash = jhash2((const u32 *)pkt_key,
+                           sizeof(*pkt_key) / sizeof(u32), 0);
+       }
 
        inet_get_local_port_range(&low, &high);
        range = (high - low) + 1;
index 4ee9c5c..92dd3c5 100644 (file)
@@ -443,18 +443,6 @@ struct ofp11_table_mod {
 };
 OFP_ASSERT(sizeof(struct ofp11_table_mod) == 8);
 
-/* Flags to indicate behavior of the flow table for unmatched packets.
-   These flags are used in ofp_table_stats messages to describe the current
-   configuration and in ofp_table_mod messages to configure table behavior.  */
-enum ofp11_table_config {
-    OFPTC11_TABLE_MISS_CONTROLLER = 0 << 0, /* Send to controller. */
-    OFPTC11_TABLE_MISS_CONTINUE = 1 << 0, /* Continue to the next table in the
-                                             pipeline (OpenFlow 1.0
-                                             behavior). */
-    OFPTC11_TABLE_MISS_DROP = 2 << 0,     /* Drop the packet. */
-#define OFPTC11_TABLE_MISS_MASK (3 << 0)
-};
-
 /* Flow setup and teardown (controller -> datapath). */
 struct ofp11_flow_mod {
     ovs_be64 cookie;             /* Opaque controller-issued identifier. */
@@ -753,12 +741,7 @@ struct ofp11_packet_in {
     ovs_be16 total_len;     /* Full length of frame. */
     uint8_t reason;         /* Reason packet is being sent (one of OFPR_*) */
     uint8_t table_id;       /* ID of the table that was looked up */
-    /* uint8_t data[0];        Ethernet frame, halfway through 32-bit word,
-                               so the IP header is 32-bit aligned. The
-                               amount of data is inferred from the length
-                               field in the header. Because of padding,
-                               offsetof(struct ofp_packet_in, data) ==
-                               sizeof(struct ofp_packet_in) - 2. */
+    /* Followed by Ethernet frame. */
 };
 OFP_ASSERT(sizeof(struct ofp11_packet_in) == 16);
 
index ef9409f..bf16d59 100644 (file)
@@ -476,11 +476,17 @@ enum ofp_table {
 };
 
 enum ofp_table_config {
-    OFPTC_TABLE_MISS_CONTROLLER = 0 << 0, /* Send to controller. */
-    OFPTC_TABLE_MISS_CONTINUE = 1 << 0, /* Continue to the next table in the
-                                           pipeline (OpenFlow 1.0 behavior). */
-    OFPTC_TABLE_MISS_DROP = 2 << 0, /* Drop the packet. */
-    OFPTC_TABLE_MISS_MASK = 3 << 0
+    /* OpenFlow 1.1 and 1.2 defined this field as shown.
+     * OpenFlow 1.3 and later mark this field as deprecated, but have not
+     * reused it for any new purpose. */
+    OFPTC11_TABLE_MISS_CONTROLLER = 0 << 0, /* Send to controller. */
+    OFPTC11_TABLE_MISS_CONTINUE   = 1 << 0, /* Go to next table, like OF1.0. */
+    OFPTC11_TABLE_MISS_DROP       = 2 << 0, /* Drop the packet. */
+    OFPTC11_TABLE_MISS_MASK       = 3 << 0,
+
+    /* OpenFlow 1.4. */
+    OFPTC14_EVICTION              = 1 << 2, /* Allow table to evict flows. */
+    OFPTC14_VACANCY_EVENTS        = 1 << 3, /* Enable vacancy events. */
 };
 
 #endif /* openflow/openflow-common.h */
index 4d7c1c6..75608a8 100644 (file)
@@ -17,8 +17,6 @@ lib_libopenvswitch_a_SOURCES = \
        lib/bfd.h \
        lib/bitmap.c \
        lib/bitmap.h \
-       lib/bond.c \
-       lib/bond.h \
        lib/bundle.c \
        lib/bundle.h \
        lib/byte-order.h \
index 25129c9..1df5acd 100644 (file)
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -187,7 +187,7 @@ struct bfd {
     long long int next_tx;        /* Next TX time. */
     long long int detect_time;    /* RFC 5880 6.8.4 Detection time. */
 
-    bool forwarding;              /* Interface capability of packet I/O. */
+    bool last_forwarding;         /* Last calculation of forwarding flag. */
     int forwarding_override;      /* Manual override of 'forwarding' status. */
 
     atomic_bool check_tnl_key;    /* Verify tunnel key of inbound packets? */
@@ -234,7 +234,7 @@ static void bfd_put_details(struct ds *, const struct bfd *)
 static uint64_t bfd_rx_packets(const struct bfd *) OVS_REQUIRES(mutex);
 static void bfd_try_decay(struct bfd *) OVS_REQUIRES(mutex);
 static void bfd_decay_update(struct bfd *) OVS_REQUIRES(mutex);
-static void bfd_check_rx(struct bfd *) OVS_REQUIRES(mutex);
+
 static void bfd_forwarding_if_rx_update(struct bfd *) OVS_REQUIRES(mutex);
 static void bfd_unixctl_show(struct unixctl_conn *, int argc,
                              const char *argv[], void *aux OVS_UNUSED);
@@ -259,6 +259,20 @@ bfd_forwarding(struct bfd *bfd) OVS_EXCLUDED(mutex)
     return ret;
 }
 
+/* When forwarding_if_rx is enabled, if there are packets received,
+ * updates forwarding_if_rx_detect_time. */
+void
+bfd_account_rx(struct bfd *bfd, const struct dpif_flow_stats *stats)
+{
+    if (stats->n_packets && bfd->forwarding_if_rx) {
+        ovs_mutex_lock(&mutex);
+        bfd_forwarding__(bfd);
+        bfd_forwarding_if_rx_update(bfd);
+        bfd_forwarding__(bfd);
+        ovs_mutex_unlock(&mutex);
+    }
+}
+
 /* Returns a 'smap' of key value pairs representing the status of 'bfd'
  * intended for the OVS database. */
 void
@@ -266,7 +280,9 @@ bfd_get_status(const struct bfd *bfd, struct smap *smap)
     OVS_EXCLUDED(mutex)
 {
     ovs_mutex_lock(&mutex);
-    smap_add(smap, "forwarding", bfd->forwarding ? "true" : "false");
+    smap_add(smap, "forwarding",
+             bfd_forwarding__(CONST_CAST(struct bfd *, bfd))
+             ? "true" : "false");
     smap_add(smap, "state", bfd_state_str(bfd->state));
     smap_add(smap, "diagnostic", bfd_diag_str(bfd->diag));
     smap_add_format(smap, "flap_count", "%"PRIu64, bfd->flap_count);
@@ -316,7 +332,6 @@ bfd_configure(struct bfd *bfd, const char *name, const struct smap *cfg,
     if (!bfd) {
         bfd = xzalloc(sizeof *bfd);
         bfd->name = xstrdup(name);
-        bfd->forwarding = false;
         bfd->forwarding_override = -1;
         bfd->disc = generate_discriminator();
         hmap_insert(all_bfds, &bfd->node, bfd->disc);
@@ -490,6 +505,7 @@ bfd_run(struct bfd *bfd) OVS_EXCLUDED(mutex)
 
     if (bfd->state > STATE_DOWN && now >= bfd->detect_time) {
         bfd_set_state(bfd, STATE_DOWN, DIAG_EXPIRED);
+        bfd_forwarding__(bfd);
     }
 
     /* Decay may only happen when state is STATE_UP, bfd->decay_min_rx is
@@ -499,9 +515,6 @@ bfd_run(struct bfd *bfd) OVS_EXCLUDED(mutex)
         bfd_try_decay(bfd);
     }
 
-    /* Always checks the reception of any packet. */
-    bfd_check_rx(bfd);
-
     if (bfd->min_tx != bfd->cfg_min_tx
         || (bfd->min_rx != bfd->cfg_min_rx && bfd->min_rx != bfd->decay_min_rx)
         || bfd->in_decay != old_in_decay) {
@@ -638,6 +651,8 @@ bfd_process_packet(struct bfd *bfd, const struct flow *flow,
     /* Increments the decay rx counter. */
     bfd->decay_rx_ctl++;
 
+    bfd_forwarding__(bfd);
+
     if (flow->nw_ttl != 255) {
         /* XXX Should drop in the kernel to prevent DOS. */
         goto out;
@@ -787,6 +802,7 @@ bfd_process_packet(struct bfd *bfd, const struct flow *flow,
     /* XXX: RFC 5880 Section 6.8.6 Demand mode related calculations here. */
 
 out:
+    bfd_forwarding__(bfd);
     ovs_mutex_unlock(&mutex);
 }
 
@@ -812,27 +828,31 @@ bfd_set_netdev(struct bfd *bfd, const struct netdev *netdev)
 
 \f
 /* Updates the forwarding flag.  If override is not configured and
- * the forwarding flag value changes, increments the flap count. */
+ * the forwarding flag value changes, increments the flap count.
+ *
+ * Note this function may be called multiple times in a function
+ * (e.g. bfd_account_rx) before and after the bfd state or status
+ * change.  This is to capture any forwarding flag flap. */
 static bool
 bfd_forwarding__(struct bfd *bfd) OVS_REQUIRES(mutex)
 {
     long long int time;
-    bool forwarding_old = bfd->forwarding;
+    bool last_forwarding = bfd->last_forwarding;
 
     if (bfd->forwarding_override != -1) {
         return bfd->forwarding_override == 1;
     }
 
     time = bfd->forwarding_if_rx_detect_time;
-    bfd->forwarding = (bfd->state == STATE_UP
-                       || (bfd->forwarding_if_rx && time > time_msec()))
-                       && bfd->rmt_diag != DIAG_PATH_DOWN
-                       && bfd->rmt_diag != DIAG_CPATH_DOWN
-                       && bfd->rmt_diag != DIAG_RCPATH_DOWN;
-    if (bfd->forwarding != forwarding_old) {
+    bfd->last_forwarding = (bfd->state == STATE_UP
+                            || (bfd->forwarding_if_rx && time > time_msec()))
+                            && bfd->rmt_diag != DIAG_PATH_DOWN
+                            && bfd->rmt_diag != DIAG_CPATH_DOWN
+                            && bfd->rmt_diag != DIAG_RCPATH_DOWN;
+    if (bfd->last_forwarding != last_forwarding) {
         bfd->flap_count++;
     }
-    return bfd->forwarding;
+    return bfd->last_forwarding;
 }
 
 /* Helpers. */
@@ -1033,9 +1053,6 @@ bfd_set_state(struct bfd *bfd, enum state state, enum diag diag)
             bfd_decay_update(bfd);
         }
     }
-
-    /* Updates the forwarding flag. */
-    bfd_forwarding__(bfd);
 }
 
 static uint64_t
@@ -1081,32 +1098,11 @@ bfd_decay_update(struct bfd * bfd) OVS_REQUIRES(mutex)
     bfd->decay_detect_time = MAX(bfd->decay_min_rx, 2000) + time_msec();
 }
 
-/* Checks if there are packets received during the time since last call.
- * If forwarding_if_rx is enabled and packets are received, updates the
- * forwarding_if_rx_detect_time. */
-static void
-bfd_check_rx(struct bfd *bfd) OVS_REQUIRES(mutex)
-{
-    uint64_t rx_packets = bfd_rx_packets(bfd);
-    int64_t diff;
-
-    diff = rx_packets - bfd->rx_packets;
-    bfd->rx_packets = rx_packets;
-    if (diff < 0) {
-        VLOG_INFO_RL(&rl, "rx_packets count is smaller than last time.");
-    }
-    if (bfd->forwarding_if_rx && diff > 0) {
-        bfd_forwarding_if_rx_update(bfd);
-    }
-}
-
-/* Updates the forwarding_if_rx_detect_time and the forwarding flag. */
 static void
 bfd_forwarding_if_rx_update(struct bfd *bfd) OVS_REQUIRES(mutex)
 {
     int64_t incr = bfd_rx_interval(bfd) * bfd->mult;
     bfd->forwarding_if_rx_detect_time = MAX(incr, 2000) + time_msec();
-    bfd_forwarding__(bfd);
 }
 
 static uint32_t
@@ -1152,7 +1148,9 @@ bfd_find_by_name(const char *name) OVS_REQUIRES(mutex)
 static void
 bfd_put_details(struct ds *ds, const struct bfd *bfd) OVS_REQUIRES(mutex)
 {
-    ds_put_format(ds, "\tForwarding: %s\n", bfd->forwarding ? "true" : "false");
+    ds_put_format(ds, "\tForwarding: %s\n",
+                  bfd_forwarding__(CONST_CAST(struct bfd *, bfd))
+                  ? "true" : "false");
     ds_put_format(ds, "\tDetect Multiplier: %d\n", bfd->mult);
     ds_put_format(ds, "\tConcatenated Path Down: %s\n",
                   bfd->cpath_down ? "true" : "false");
index 0ad86e9..4e7d4cb 100644 (file)
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -22,6 +22,7 @@
 #include <inttypes.h>
 
 struct bfd;
+struct dpif_flow_stats;
 struct flow;
 struct flow_wildcards;
 struct netdev;
@@ -46,6 +47,7 @@ struct bfd *bfd_configure(struct bfd *, const char *name,
 struct bfd *bfd_ref(const struct bfd *);
 void bfd_unref(struct bfd *);
 
+void bfd_account_rx(struct bfd *, const struct dpif_flow_stats *);
 bool bfd_forwarding(struct bfd *);
 void bfd_get_status(const struct bfd *, struct smap *);
 void bfd_set_netdev(struct bfd *, const struct netdev *);
index f9be78b..352f91e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2010, 2011 Nicira, Inc.
+ * Copyright (c) 2008, 2010, 2011, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -40,7 +40,6 @@ ovs_be64 htonll(uint64_t);
 uint64_t ntohll(ovs_be64);
 #endif
 
-#if defined(WORDS_BIGENDIAN)
 static inline uint32_t
 uint32_byteswap(uint32_t crc) {
     return (((crc & 0x000000ff) << 24) |
@@ -48,7 +47,6 @@ uint32_byteswap(uint32_t crc) {
             ((crc & 0x00ff0000) >>  8) |
             ((crc & 0xff000000) >> 24));
 }
-#endif
 
 /* These macros may substitute for htons(), htonl(), and htonll() in contexts
  * where function calls are not allowed, such as case labels.  They should not
index c6683a5..0dfd01f 100644 (file)
@@ -586,6 +586,24 @@ format_flags(struct ds *ds, const char *(*bit_to_string)(uint32_t),
     ds_chomp(ds, del);
 }
 
+void
+format_flags_masked(struct ds *ds, const char *name,
+                    const char *(*bit_to_string)(uint32_t), uint32_t flags,
+                    uint32_t mask)
+{
+    if (name) {
+        ds_put_format(ds, "%s=", name);
+    }
+    while (mask) {
+        uint32_t bit = rightmost_1bit(mask);
+        const char *s = bit_to_string(bit);
+
+        ds_put_format(ds, "%s%s", (flags & bit) ? "+" : "-",
+                      s ? s : "[Unknown]");
+        mask &= ~bit;
+    }
+}
+
 void
 flow_format(struct ds *ds, const struct flow *flow)
 {
@@ -1040,6 +1058,78 @@ flow_set_mpls_bos(struct flow *flow, uint8_t bos)
     set_mpls_lse_bos(&flow->mpls_lse, bos);
 }
 
+
+static void
+flow_compose_l4(struct ofpbuf *b, const struct flow *flow)
+{
+    if (!(flow->nw_frag & FLOW_NW_FRAG_ANY)
+        || !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
+        if (flow->nw_proto == IPPROTO_TCP) {
+            struct tcp_header *tcp;
+
+            tcp = ofpbuf_put_zeros(b, sizeof *tcp);
+            tcp->tcp_src = flow->tp_src;
+            tcp->tcp_dst = flow->tp_dst;
+            tcp->tcp_ctl = TCP_CTL(ntohs(flow->tcp_flags), 5);
+            b->l7 = ofpbuf_tail(b);
+        } else if (flow->nw_proto == IPPROTO_UDP) {
+            struct udp_header *udp;
+
+            udp = ofpbuf_put_zeros(b, sizeof *udp);
+            udp->udp_src = flow->tp_src;
+            udp->udp_dst = flow->tp_dst;
+            b->l7 = ofpbuf_tail(b);
+        } else if (flow->nw_proto == IPPROTO_SCTP) {
+            struct sctp_header *sctp;
+
+            sctp = ofpbuf_put_zeros(b, sizeof *sctp);
+            sctp->sctp_src = flow->tp_src;
+            sctp->sctp_dst = flow->tp_dst;
+            b->l7 = ofpbuf_tail(b);
+        } else if (flow->nw_proto == IPPROTO_ICMP) {
+            struct icmp_header *icmp;
+
+            icmp = ofpbuf_put_zeros(b, sizeof *icmp);
+            icmp->icmp_type = ntohs(flow->tp_src);
+            icmp->icmp_code = ntohs(flow->tp_dst);
+            icmp->icmp_csum = csum(icmp, ICMP_HEADER_LEN);
+            b->l7 = ofpbuf_tail(b);
+        } else if (flow->nw_proto == IPPROTO_ICMPV6) {
+            struct icmp6_hdr *icmp;
+
+            icmp = ofpbuf_put_zeros(b, sizeof *icmp);
+            icmp->icmp6_type = ntohs(flow->tp_src);
+            icmp->icmp6_code = ntohs(flow->tp_dst);
+
+            if (icmp->icmp6_code == 0 &&
+                (icmp->icmp6_type == ND_NEIGHBOR_SOLICIT ||
+                 icmp->icmp6_type == ND_NEIGHBOR_ADVERT)) {
+                struct in6_addr *nd_target;
+                struct nd_opt_hdr *nd_opt;
+
+                nd_target = ofpbuf_put_zeros(b, sizeof *nd_target);
+                *nd_target = flow->nd_target;
+
+                if (!eth_addr_is_zero(flow->arp_sha)) {
+                    nd_opt = ofpbuf_put_zeros(b, 8);
+                    nd_opt->nd_opt_len = 1;
+                    nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
+                    memcpy(nd_opt + 1, flow->arp_sha, ETH_ADDR_LEN);
+                }
+                if (!eth_addr_is_zero(flow->arp_tha)) {
+                    nd_opt = ofpbuf_put_zeros(b, 8);
+                    nd_opt->nd_opt_len = 1;
+                    nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
+                    memcpy(nd_opt + 1, flow->arp_tha, ETH_ADDR_LEN);
+                }
+            }
+            icmp->icmp6_cksum = (OVS_FORCE uint16_t)
+                csum(icmp, (char *)ofpbuf_tail(b) - (char *)icmp);
+            b->l7 = ofpbuf_tail(b);
+        }
+    }
+}
+
 /* Puts into 'b' a packet that flow_extract() would parse as having the given
  * 'flow'.
  *
@@ -1049,6 +1139,7 @@ flow_set_mpls_bos(struct flow *flow, uint8_t bos)
 void
 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;
@@ -1063,7 +1154,7 @@ flow_compose(struct ofpbuf *b, const struct flow *flow)
     if (flow->dl_type == htons(ETH_TYPE_IP)) {
         struct ip_header *ip;
 
-        b->l3 = ip = ofpbuf_put_zeros(b, sizeof *ip);
+        ip = ofpbuf_put_zeros(b, sizeof *ip);
         ip->ip_ihl_ver = IP_IHL_VER(5, 4);
         ip->ip_tos = flow->nw_tos;
         ip->ip_ttl = flow->nw_ttl;
@@ -1077,44 +1168,32 @@ flow_compose(struct ofpbuf *b, const struct flow *flow)
                 ip->ip_frag_off |= htons(100);
             }
         }
-        if (!(flow->nw_frag & FLOW_NW_FRAG_ANY)
-            || !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
-            if (flow->nw_proto == IPPROTO_TCP) {
-                struct tcp_header *tcp;
-
-                b->l4 = tcp = ofpbuf_put_zeros(b, sizeof *tcp);
-                tcp->tcp_src = flow->tp_src;
-                tcp->tcp_dst = flow->tp_dst;
-                tcp->tcp_ctl = TCP_CTL(ntohs(flow->tcp_flags), 5);
-            } else if (flow->nw_proto == IPPROTO_UDP) {
-                struct udp_header *udp;
-
-                b->l4 = udp = ofpbuf_put_zeros(b, sizeof *udp);
-                udp->udp_src = flow->tp_src;
-                udp->udp_dst = flow->tp_dst;
-            } else if (flow->nw_proto == IPPROTO_SCTP) {
-                struct sctp_header *sctp;
-
-                b->l4 = sctp = ofpbuf_put_zeros(b, sizeof *sctp);
-                sctp->sctp_src = flow->tp_src;
-                sctp->sctp_dst = flow->tp_dst;
-            } else if (flow->nw_proto == IPPROTO_ICMP) {
-                struct icmp_header *icmp;
-
-                b->l4 = icmp = ofpbuf_put_zeros(b, sizeof *icmp);
-                icmp->icmp_type = ntohs(flow->tp_src);
-                icmp->icmp_code = ntohs(flow->tp_dst);
-                icmp->icmp_csum = csum(icmp, ICMP_HEADER_LEN);
-            }
-            b->l7 = ofpbuf_tail(b);
-        }
 
-        ip = b->l3;
+        b->l4 = ofpbuf_tail(b);
+
+        flow_compose_l4(b, flow);
+
         ip->ip_tot_len = htons((uint8_t *) b->data + b->size
                                - (uint8_t *) b->l3);
         ip->ip_csum = csum(ip, sizeof *ip);
     } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
-        /* XXX */
+        struct ovs_16aligned_ip6_hdr *nh;
+
+        nh = ofpbuf_put_zeros(b, sizeof *nh);
+        put_16aligned_be32(&nh->ip6_flow, htonl(6 << 28) |
+                           htonl(flow->nw_tos << 20) | flow->ipv6_label);
+        nh->ip6_hlim = flow->nw_ttl;
+        nh->ip6_nxt = flow->nw_proto;
+
+        memcpy(&nh->ip6_src, &flow->ipv6_src, sizeof(nh->ip6_src));
+        memcpy(&nh->ip6_dst, &flow->ipv6_dst, sizeof(nh->ip6_dst));
+
+        b->l4 = ofpbuf_tail(b);
+
+        flow_compose_l4(b, flow);
+
+        nh->ip6_plen =
+            b->l7 ? htons((uint8_t *) b->l7 - (uint8_t *) b->l4) : htons(0);
     } else if (flow->dl_type == htons(ETH_TYPE_ARP) ||
                flow->dl_type == htons(ETH_TYPE_RARP)) {
         struct arp_eth_header *arp;
index 5e78073..5c0007d 100644 (file)
@@ -179,6 +179,9 @@ void flow_get_metadata(const struct flow *, struct flow_metadata *);
 char *flow_to_string(const struct flow *);
 void format_flags(struct ds *ds, const char *(*bit_to_string)(uint32_t),
                   uint32_t flags, char del);
+void format_flags_masked(struct ds *ds, const char *name,
+                         const char *(*bit_to_string)(uint32_t),
+                         uint32_t flags, uint32_t mask);
 
 void flow_format(struct ds *, const struct flow *);
 void flow_print(FILE *, const struct flow *);
index 71d86be..9e5da13 100644 (file)
@@ -779,7 +779,6 @@ format_ipv6_netmask(struct ds *s, const char *name,
     }
 }
 
-
 static void
 format_be16_masked(struct ds *s, const char *name,
                    ovs_be16 value, ovs_be16 mask)
@@ -796,24 +795,39 @@ format_be16_masked(struct ds *s, const char *name,
     }
 }
 
+static void
+format_uint32_masked(struct ds *s, const char *name,
+                   uint32_t value, uint32_t mask)
+{
+    if (mask) {
+        ds_put_format(s, "%s=%#"PRIx32, name, value);
+        if (mask != UINT32_MAX) {
+            ds_put_format(s, "/%#"PRIx32, mask);
+        }
+        ds_put_char(s, ',');
+    }
+}
+
+static void
+format_be64_masked(struct ds *s, const char *name,
+                   ovs_be64 value, ovs_be64 mask)
+{
+    if (mask != htonll(0)) {
+        ds_put_format(s, "%s=%#"PRIx64, name, ntohll(value));
+        if (mask != OVS_BE64_MAX) {
+            ds_put_format(s, "/%#"PRIx64, ntohll(mask));
+        }
+        ds_put_char(s, ',');
+    }
+}
+
 static void
 format_flow_tunnel(struct ds *s, const struct match *match)
 {
     const struct flow_wildcards *wc = &match->wc;
     const struct flow_tnl *tnl = &match->flow.tunnel;
 
-    switch (wc->masks.tunnel.tun_id) {
-    case 0:
-        break;
-    case OVS_BE64_MAX:
-        ds_put_format(s, "tun_id=%#"PRIx64",", ntohll(tnl->tun_id));
-        break;
-    default:
-        ds_put_format(s, "tun_id=%#"PRIx64"/%#"PRIx64",",
-                      ntohll(tnl->tun_id),
-                      ntohll(wc->masks.tunnel.tun_id));
-        break;
-    }
+    format_be64_masked(s, "tun_id", tnl->tun_id, wc->masks.tunnel.tun_id);
     format_ip_netmask(s, "tun_src", tnl->ip_src, wc->masks.tunnel.ip_src);
     format_ip_netmask(s, "tun_dst", tnl->ip_dst, wc->masks.tunnel.ip_dst);
 
@@ -848,17 +862,7 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
         ds_put_format(s, "priority=%u,", priority);
     }
 
-    switch (wc->masks.pkt_mark) {
-    case 0:
-        break;
-    case UINT32_MAX:
-        ds_put_format(s, "pkt_mark=%#"PRIx32",", f->pkt_mark);
-        break;
-    default:
-        ds_put_format(s, "pkt_mark=%#"PRIx32"/%#"PRIx32",",
-                      f->pkt_mark, wc->masks.pkt_mark);
-        break;
-    }
+    format_uint32_masked(s, "pkt_mark", f->pkt_mark, wc->masks.pkt_mark);
 
     if (wc->masks.skb_priority) {
         ds_put_format(s, "skb_priority=%#"PRIx32",", f->skb_priority);
@@ -915,32 +919,18 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
         }
     }
     for (i = 0; i < FLOW_N_REGS; i++) {
-        switch (wc->masks.regs[i]) {
-        case 0:
-            break;
-        case UINT32_MAX:
-            ds_put_format(s, "reg%d=0x%"PRIx32",", i, f->regs[i]);
-            break;
-        default:
-            ds_put_format(s, "reg%d=0x%"PRIx32"/0x%"PRIx32",",
-                          i, f->regs[i], wc->masks.regs[i]);
-            break;
+        #define REGNAME_LEN 20
+        char regname[REGNAME_LEN];
+        if (snprintf(regname, REGNAME_LEN, "reg%d", i) >= REGNAME_LEN) {
+            strcpy(regname, "reg?");
         }
+        format_uint32_masked(s, regname, f->regs[i], wc->masks.regs[i]);
     }
 
     format_flow_tunnel(s, match);
 
-    switch (wc->masks.metadata) {
-    case 0:
-        break;
-    case OVS_BE64_MAX:
-        ds_put_format(s, "metadata=%#"PRIx64",", ntohll(f->metadata));
-        break;
-    default:
-        ds_put_format(s, "metadata=%#"PRIx64"/%#"PRIx64",",
-                      ntohll(f->metadata), ntohll(wc->masks.metadata));
-        break;
-    }
+    format_be64_masked(s, "metadata", f->metadata, wc->masks.metadata);
+
     if (wc->masks.in_port.ofp_port) {
         ds_put_cstr(s, "in_port=");
         ofputil_format_port(f->in_port.ofp_port, s);
@@ -1069,11 +1059,12 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
         format_be16_masked(s, "tp_dst", f->tp_dst, wc->masks.tp_dst);
     }
     if (is_ip_any(f) && f->nw_proto == IPPROTO_TCP && wc->masks.tcp_flags) {
-        if (wc->masks.tcp_flags == htons(UINT16_MAX)) {
+        uint16_t mask = TCP_FLAGS(wc->masks.tcp_flags);
+        if (mask == TCP_FLAGS(OVS_BE16_MAX)) {
             ds_put_format(s, "tcp_flags=0x%03"PRIx16",", ntohs(f->tcp_flags));
         } else {
-            ds_put_format(s, "tcp_flags=0x%03"PRIx16"/0x%03"PRIx16",",
-                          ntohs(f->tcp_flags), ntohs(wc->masks.tcp_flags));
+            format_flags_masked(s, "tcp_flags", packet_tcp_flag_to_string,
+                                ntohs(f->tcp_flags), mask);
         }
     }
 
index b37f781..bc972b0 100644 (file)
@@ -565,7 +565,7 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         MFF_TCP_FLAGS, "tcp_flags", NULL,
         2, 12,
         MFM_FULLY,
-        MFS_HEXADECIMAL,
+        MFS_TCP_FLAGS,
         MFP_TCP,
         false,
         NXM_NX_TCP_FLAGS, "NXM_NX_TCP_FLAGS",
@@ -2215,115 +2215,6 @@ mf_get(const struct mf_field *mf, const struct match *match,
     mf_get_mask(mf, &match->wc, mask);
 }
 
-/* Assigns a random value for field 'mf' to 'value'. */
-void
-mf_random_value(const struct mf_field *mf, union mf_value *value)
-{
-    random_bytes(value, mf->n_bytes);
-
-    switch (mf->id) {
-    case MFF_TUN_ID:
-    case MFF_TUN_SRC:
-    case MFF_TUN_DST:
-    case MFF_TUN_TOS:
-    case MFF_TUN_TTL:
-    case MFF_TUN_FLAGS:
-    case MFF_METADATA:
-    case MFF_IN_PORT:
-    case MFF_PKT_MARK:
-    case MFF_SKB_PRIORITY:
-    CASE_MFF_REGS:
-    case MFF_ETH_SRC:
-    case MFF_ETH_DST:
-    case MFF_ETH_TYPE:
-    case MFF_VLAN_TCI:
-    case MFF_IPV4_SRC:
-    case MFF_IPV4_DST:
-    case MFF_IPV6_SRC:
-    case MFF_IPV6_DST:
-    case MFF_IP_PROTO:
-    case MFF_IP_TTL:
-    case MFF_ARP_SPA:
-    case MFF_ARP_TPA:
-    case MFF_ARP_SHA:
-    case MFF_ARP_THA:
-    case MFF_TCP_SRC:
-    case MFF_TCP_DST:
-    case MFF_UDP_SRC:
-    case MFF_UDP_DST:
-    case MFF_SCTP_SRC:
-    case MFF_SCTP_DST:
-    case MFF_ICMPV4_TYPE:
-    case MFF_ICMPV4_CODE:
-    case MFF_ICMPV6_TYPE:
-    case MFF_ICMPV6_CODE:
-    case MFF_ND_TARGET:
-    case MFF_ND_SLL:
-    case MFF_ND_TLL:
-        break;
-
-    case MFF_TCP_FLAGS:
-        value->be16 &= htons(0x0fff);
-        break;
-
-    case MFF_IN_PORT_OXM:
-        value->be32 = ofputil_port_to_ofp11(u16_to_ofp(ntohs(value->be16)));
-        break;
-
-    case MFF_IPV6_LABEL:
-        value->be32 &= htonl(IPV6_LABEL_MASK);
-        break;
-
-    case MFF_IP_DSCP:
-        value->u8 &= IP_DSCP_MASK;
-        break;
-
-    case MFF_IP_DSCP_SHIFTED:
-        value->u8 &= IP_DSCP_MASK >> 2;
-        break;
-
-    case MFF_IP_ECN:
-        value->u8 &= IP_ECN_MASK;
-        break;
-
-    case MFF_IP_FRAG:
-        value->u8 &= FLOW_NW_FRAG_MASK;
-        break;
-
-    case MFF_ARP_OP:
-        value->be16 &= htons(0xff);
-        break;
-
-    case MFF_DL_VLAN:
-        value->be16 &= htons(VLAN_VID_MASK);
-        break;
-    case MFF_VLAN_VID:
-        value->be16 &= htons(VLAN_VID_MASK | VLAN_CFI);
-        break;
-
-    case MFF_DL_VLAN_PCP:
-    case MFF_VLAN_PCP:
-        value->u8 &= 0x07;
-        break;
-
-    case MFF_MPLS_LABEL:
-        value->be32 &= htonl(MPLS_LABEL_MASK >> MPLS_LABEL_SHIFT);
-        break;
-
-    case MFF_MPLS_TC:
-        value->u8 &= MPLS_TC_MASK >> MPLS_TC_SHIFT;
-        break;
-
-    case MFF_MPLS_BOS:
-        value->u8 &= MPLS_BOS_MASK >> MPLS_BOS_SHIFT;
-        break;
-
-    case MFF_N_IDS:
-    default:
-        NOT_REACHED();
-    }
-}
-
 static char *
 mf_from_integer_string(const struct mf_field *mf, const char *s,
                        uint8_t *valuep, uint8_t *maskp)
@@ -2595,6 +2486,81 @@ mf_from_tun_flags_string(const char *s, ovs_be16 *valuep, ovs_be16 *maskp)
                      "\"csum\", \"key\")", s);
 }
 
+static char *
+mf_from_tcp_flags_string(const char *s, ovs_be16 *flagsp, ovs_be16 *maskp)
+{
+    uint16_t flags = 0;
+    uint16_t mask = 0;
+    uint16_t bit;
+    int n;
+
+    if (ovs_scan(s, "%"SCNi16"/%"SCNi16"%n", &flags, &mask, &n) && !s[n]) {
+        *flagsp = htons(flags);
+        *maskp = htons(mask);
+        return NULL;
+    }
+    if (ovs_scan(s, "%"SCNi16"%n", &flags, &n) && !s[n]) {
+        *flagsp = htons(flags);
+        *maskp = OVS_BE16_MAX;
+        return NULL;
+    }
+
+    while (*s != '\0') {
+        bool set;
+        int name_len;
+
+        switch (*s) {
+        case '+':
+            set = true;
+            break;
+        case '-':
+            set = false;
+            break;
+        default:
+            return xasprintf("%s: TCP flag must be preceded by '+' (for SET) "
+                             "or '-' (NOT SET)", s);
+        }
+        s++;
+
+        name_len = strcspn(s,"+-");
+
+        for (bit = 1; bit; bit <<= 1) {
+            const char *fname = packet_tcp_flag_to_string(bit);
+            size_t len;
+
+            if (!fname) {
+                continue;
+            }
+
+            len = strlen(fname);
+            if (len != name_len) {
+                continue;
+            }
+            if (!strncmp(s, fname, len)) {
+                if (mask & bit) {
+                    return xasprintf("%s: Each TCP flag can be specified only "
+                                     "once", s);
+                }
+                if (set) {
+                    flags |= bit;
+                }
+                mask |= bit;
+                break;
+            }
+        }
+
+        if (!bit) {
+            return xasprintf("%s: unknown TCP flag(s)", s);
+        }
+        s += name_len;
+    }
+
+    *flagsp = htons(flags);
+    *maskp = htons(mask);
+    return NULL;
+}
+
+
 /* Parses 's', a string value for field 'mf', into 'value' and 'mask'.  Returns
  * NULL if successful, otherwise a malloc()'d string describing the error. */
 char *
@@ -2645,6 +2611,11 @@ mf_parse(const struct mf_field *mf, const char *s,
         error = mf_from_tun_flags_string(s, &value->be16, &mask->be16);
         break;
 
+    case MFS_TCP_FLAGS:
+        ovs_assert(mf->n_bytes == sizeof(ovs_be16));
+        error = mf_from_tcp_flags_string(s, &value->be16, &mask->be16);
+        break;
+
     default:
         NOT_REACHED();
     }
@@ -2731,6 +2702,13 @@ mf_format_tnl_flags_string(const ovs_be16 *valuep, struct ds *s)
     format_flags(s, flow_tun_flag_to_string, ntohs(*valuep), '|');
 }
 
+static void
+mf_format_tcp_flags_string(ovs_be16 value, ovs_be16 mask, struct ds *s)
+{
+    format_flags_masked(s, NULL, packet_tcp_flag_to_string, ntohs(value),
+                        TCP_FLAGS(mask));
+}
+
 /* Appends to 's' a string representation of field 'mf' whose value is in
  * 'value' and 'mask'.  'mask' may be NULL to indicate an exact match. */
 void
@@ -2787,6 +2765,11 @@ mf_format(const struct mf_field *mf,
         mf_format_tnl_flags_string(&value->be16, s);
         break;
 
+    case MFS_TCP_FLAGS:
+        mf_format_tcp_flags_string(value->be16,
+                                   mask ? mask->be16 : OVS_BE16_MAX, s);
+        break;
+
     default:
         NOT_REACHED();
     }
index c2b0bbc..2c5616f 100644 (file)
@@ -232,6 +232,7 @@ enum OVS_PACKED_ENUM mf_string {
     MFS_OFP_PORT_OXM,           /* An OpenFlow port number or name (32-bit). */
     MFS_FRAG,                   /* no, yes, first, later, not_later */
     MFS_TNL_FLAGS,              /* FLOW_TNL_F_* flags */
+    MFS_TCP_FLAGS,              /* TCP_* flags */
 };
 
 struct mf_field {
@@ -378,8 +379,6 @@ enum ofputil_protocol mf_set(const struct mf_field *,
 
 void mf_set_wild(const struct mf_field *, struct match *);
 
-void mf_random_value(const struct mf_field *, union mf_value *value);
-
 /* Subfields. */
 void mf_write_subfield_flow(const struct mf_subfield *,
                             const union mf_subvalue *, struct flow *);
index 0fd1c51..6dbc213 100644 (file)
@@ -2871,7 +2871,7 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
     } else {
         goto done;
     }
-    if (is_mask) {
+    if (check_len > 0) { /* Happens only when 'is_mask'. */
         if (!is_all_zeros(check_start, check_len) &&
             flow->dl_type != htons(0xffff)) {
             return ODP_FIT_ERROR;
index 92e0767..7fc4c7c 100644 (file)
@@ -3196,6 +3196,23 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin,
         pin->reason = opi->reason;
         pin->buffer_id = ntohl(opi->buffer_id);
         pin->total_len = ntohs(opi->total_len);
+    } else if (raw == OFPRAW_OFPT11_PACKET_IN) {
+        const struct ofp11_packet_in *opi;
+        enum ofperr error;
+
+        opi = ofpbuf_pull(&b, sizeof *opi);
+
+        pin->packet = b.data;
+        pin->packet_len = b.size;
+
+        pin->buffer_id = ntohl(opi->buffer_id);
+        error = ofputil_port_from_ofp11(opi->in_port, &pin->fmd.in_port);
+        if (error) {
+            return error;
+        }
+        pin->total_len = ntohs(opi->total_len);
+        pin->reason = opi->reason;
+        pin->table_id = opi->table_id;
     } else if (raw == OFPRAW_NXT_PACKET_IN) {
         const struct nx_packet_in *npi;
         struct match match;
@@ -3260,6 +3277,120 @@ ofputil_packet_in_to_match(const struct ofputil_packet_in *pin,
     match_set_in_port(match, pin->fmd.in_port);
 }
 
+static struct ofpbuf *
+ofputil_encode_ofp10_packet_in(const struct ofputil_packet_in *pin)
+{
+    struct ofp10_packet_in *opi;
+    struct ofpbuf *packet;
+
+    packet = ofpraw_alloc_xid(OFPRAW_OFPT10_PACKET_IN, OFP10_VERSION,
+                              htonl(0), pin->packet_len);
+    opi = ofpbuf_put_zeros(packet, offsetof(struct ofp10_packet_in, data));
+    opi->total_len = htons(pin->total_len);
+    opi->in_port = htons(ofp_to_u16(pin->fmd.in_port));
+    opi->reason = pin->reason;
+    opi->buffer_id = htonl(pin->buffer_id);
+
+    ofpbuf_put(packet, pin->packet, pin->packet_len);
+
+    return packet;
+}
+
+static struct ofpbuf *
+ofputil_encode_nx_packet_in(const struct ofputil_packet_in *pin)
+{
+    struct nx_packet_in *npi;
+    struct ofpbuf *packet;
+    struct match match;
+    size_t match_len;
+
+    ofputil_packet_in_to_match(pin, &match);
+
+    /* The final argument is just an estimate of the space required. */
+    packet = ofpraw_alloc_xid(OFPRAW_NXT_PACKET_IN, OFP10_VERSION,
+                              htonl(0), (sizeof(struct flow_metadata) * 2
+                                         + 2 + pin->packet_len));
+    ofpbuf_put_zeros(packet, sizeof *npi);
+    match_len = nx_put_match(packet, &match, 0, 0);
+    ofpbuf_put_zeros(packet, 2);
+    ofpbuf_put(packet, pin->packet, pin->packet_len);
+
+    npi = packet->l3;
+    npi->buffer_id = htonl(pin->buffer_id);
+    npi->total_len = htons(pin->total_len);
+    npi->reason = pin->reason;
+    npi->table_id = pin->table_id;
+    npi->cookie = pin->cookie;
+    npi->match_len = htons(match_len);
+
+    return packet;
+}
+
+static struct ofpbuf *
+ofputil_encode_ofp11_packet_in(const struct ofputil_packet_in *pin)
+{
+    struct ofp11_packet_in *opi;
+    struct ofpbuf *packet;
+
+    packet = ofpraw_alloc_xid(OFPRAW_OFPT11_PACKET_IN, OFP11_VERSION,
+                              htonl(0), pin->packet_len);
+    opi = ofpbuf_put_zeros(packet, sizeof *opi);
+    opi->buffer_id = htonl(pin->buffer_id);
+    opi->in_port = ofputil_port_to_ofp11(pin->fmd.in_port);
+    opi->in_phy_port = opi->in_port;
+    opi->total_len = htons(pin->total_len);
+    opi->reason = pin->reason;
+    opi->table_id = pin->table_id;
+
+    ofpbuf_put(packet, pin->packet, pin->packet_len);
+
+    return packet;
+}
+
+static struct ofpbuf *
+ofputil_encode_ofp12_packet_in(const struct ofputil_packet_in *pin,
+                               enum ofputil_protocol protocol)
+{
+    struct ofp13_packet_in *opi;
+    struct match match;
+    enum ofpraw packet_in_raw;
+    enum ofp_version packet_in_version;
+    size_t packet_in_size;
+    struct ofpbuf *packet;
+
+    if (protocol == OFPUTIL_P_OF12_OXM) {
+        packet_in_raw = OFPRAW_OFPT12_PACKET_IN;
+        packet_in_version = OFP12_VERSION;
+        packet_in_size = sizeof (struct ofp12_packet_in);
+    } else {
+        packet_in_raw = OFPRAW_OFPT13_PACKET_IN;
+        packet_in_version = OFP13_VERSION;
+        packet_in_size = sizeof (struct ofp13_packet_in);
+    }
+
+    ofputil_packet_in_to_match(pin, &match);
+
+    /* The final argument is just an estimate of the space required. */
+    packet = ofpraw_alloc_xid(packet_in_raw, packet_in_version,
+                              htonl(0), (sizeof(struct flow_metadata) * 2
+                                         + 2 + pin->packet_len));
+    ofpbuf_put_zeros(packet, packet_in_size);
+    oxm_put_match(packet, &match);
+    ofpbuf_put_zeros(packet, 2);
+    ofpbuf_put(packet, pin->packet, pin->packet_len);
+
+    opi = packet->l3;
+    opi->pi.buffer_id = htonl(pin->buffer_id);
+    opi->pi.total_len = htons(pin->total_len);
+    opi->pi.reason = pin->reason;
+    opi->pi.table_id = pin->table_id;
+    if (protocol == OFPUTIL_P_OF13_OXM) {
+        opi->cookie = pin->cookie;
+    }
+
+    return packet;
+}
+
 /* Converts abstract ofputil_packet_in 'pin' into a PACKET_IN message
  * in the format specified by 'packet_in_format'.  */
 struct ofpbuf *
@@ -3269,83 +3400,30 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin,
 {
     struct ofpbuf *packet;
 
-    /* Add OFPT_PACKET_IN. */
-    if (protocol == OFPUTIL_P_OF13_OXM || protocol == OFPUTIL_P_OF12_OXM) {
-        struct ofp13_packet_in *opi;
-        struct match match;
-        enum ofpraw packet_in_raw;
-        enum ofp_version packet_in_version;
-        size_t packet_in_size;
+    switch (protocol) {
+    case OFPUTIL_P_OF10_STD:
+    case OFPUTIL_P_OF10_STD_TID:
+    case OFPUTIL_P_OF10_NXM:
+    case OFPUTIL_P_OF10_NXM_TID:
+        packet = (packet_in_format == NXPIF_NXM
+                  ? ofputil_encode_nx_packet_in(pin)
+                  : ofputil_encode_ofp10_packet_in(pin));
+        break;
 
-        if (protocol == OFPUTIL_P_OF12_OXM) {
-            packet_in_raw = OFPRAW_OFPT12_PACKET_IN;
-            packet_in_version = OFP12_VERSION;
-            packet_in_size = sizeof (struct ofp12_packet_in);
-        } else {
-            packet_in_raw = OFPRAW_OFPT13_PACKET_IN;
-            packet_in_version = OFP13_VERSION;
-            packet_in_size = sizeof (struct ofp13_packet_in);
-        }
+    case OFPUTIL_P_OF11_STD:
+        packet = ofputil_encode_ofp11_packet_in(pin);
+        break;
 
-        ofputil_packet_in_to_match(pin, &match);
-
-        /* The final argument is just an estimate of the space required. */
-        packet = ofpraw_alloc_xid(packet_in_raw, packet_in_version,
-                                  htonl(0), (sizeof(struct flow_metadata) * 2
-                                             + 2 + pin->packet_len));
-        ofpbuf_put_zeros(packet, packet_in_size);
-        oxm_put_match(packet, &match);
-        ofpbuf_put_zeros(packet, 2);
-        ofpbuf_put(packet, pin->packet, pin->packet_len);
-
-        opi = packet->l3;
-        opi->pi.buffer_id = htonl(pin->buffer_id);
-        opi->pi.total_len = htons(pin->total_len);
-        opi->pi.reason = pin->reason;
-        opi->pi.table_id = pin->table_id;
-        if (protocol == OFPUTIL_P_OF13_OXM) {
-            opi->cookie = pin->cookie;
-        }
-    } else if (packet_in_format == NXPIF_OPENFLOW10) {
-        struct ofp10_packet_in *opi;
-
-        packet = ofpraw_alloc_xid(OFPRAW_OFPT10_PACKET_IN, OFP10_VERSION,
-                                  htonl(0), pin->packet_len);
-        opi = ofpbuf_put_zeros(packet, offsetof(struct ofp10_packet_in, data));
-        opi->total_len = htons(pin->total_len);
-        opi->in_port = htons(ofp_to_u16(pin->fmd.in_port));
-        opi->reason = pin->reason;
-        opi->buffer_id = htonl(pin->buffer_id);
-
-        ofpbuf_put(packet, pin->packet, pin->packet_len);
-    } else if (packet_in_format == NXPIF_NXM) {
-        struct nx_packet_in *npi;
-        struct match match;
-        size_t match_len;
-
-        ofputil_packet_in_to_match(pin, &match);
-
-        /* The final argument is just an estimate of the space required. */
-        packet = ofpraw_alloc_xid(OFPRAW_NXT_PACKET_IN, OFP10_VERSION,
-                                  htonl(0), (sizeof(struct flow_metadata) * 2
-                                             + 2 + pin->packet_len));
-        ofpbuf_put_zeros(packet, sizeof *npi);
-        match_len = nx_put_match(packet, &match, 0, 0);
-        ofpbuf_put_zeros(packet, 2);
-        ofpbuf_put(packet, pin->packet, pin->packet_len);
-
-        npi = packet->l3;
-        npi->buffer_id = htonl(pin->buffer_id);
-        npi->total_len = htons(pin->total_len);
-        npi->reason = pin->reason;
-        npi->table_id = pin->table_id;
-        npi->cookie = pin->cookie;
-        npi->match_len = htons(match_len);
-    } else {
+    case OFPUTIL_P_OF12_OXM:
+    case OFPUTIL_P_OF13_OXM:
+        packet = ofputil_encode_ofp12_packet_in(pin, protocol);
+        break;
+
+    default:
         NOT_REACHED();
     }
-    ofpmsg_update_length(packet);
 
+    ofpmsg_update_length(packet);
     return packet;
 }
 
index b3a87bb..1a633cf 100644 (file)
@@ -309,4 +309,82 @@ may_fork(void)
 {
     return !must_not_fork;
 }
+\f
+/* Parses /proc/cpuinfo for the total number of physical cores on this system
+ * across all CPU packages, not counting hyper-threads.
+ *
+ * Sets *n_cores to the total number of cores on this system, or 0 if the
+ * number cannot be determined. */
+static void
+parse_cpuinfo(long int *n_cores)
+{
+    static const char file_name[] = "/proc/cpuinfo";
+    char line[128];
+    uint64_t cpu = 0; /* Support up to 64 CPU packages on a single system. */
+    long int cores = 0;
+    FILE *stream;
+
+    stream = fopen(file_name, "r");
+    if (!stream) {
+        VLOG_WARN("%s: open failed (%s)", file_name, ovs_strerror(errno));
+        return;
+    }
+
+    while (fgets(line, sizeof line, stream)) {
+        unsigned int id;
+
+        /* Find the next CPU package. */
+        if (ovs_scan(line, "physical id%*[^:]: %u", &id)) {
+            if (id > 63) {
+                VLOG_WARN("Counted over 64 CPU packages on this system. "
+                          "Parsing %s for core count may be inaccurate.",
+                          file_name);
+                cores = 0;
+                break;
+            }
+
+            if (cpu & (1 << id)) {
+                /* We've already counted this package's cores. */
+                continue;
+            }
+            cpu |= 1 << id;
+
+            /* Find the number of cores for this package. */
+            while (fgets(line, sizeof line, stream)) {
+                int count;
+
+                if (ovs_scan(line, "cpu cores%*[^:]: %u", &count)) {
+                    cores += count;
+                    break;
+                }
+            }
+        }
+    }
+    fclose(stream);
+
+    *n_cores = cores;
+}
+
+/* Returns the total number of cores on this system, or 0 if the number cannot
+ * be determined.
+ *
+ * Tries not to count hyper-threads, but may be inaccurate - particularly on
+ * platforms that do not provide /proc/cpuinfo, but also if /proc/cpuinfo is
+ * formatted different to the layout that parse_cpuinfo() expects. */
+unsigned int
+count_cpu_cores(void)
+{
+    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
+    static long int n_cores;
+
+    if (ovsthread_once_start(&once)) {
+        parse_cpuinfo(&n_cores);
+        if (!n_cores) {
+            n_cores = sysconf(_SC_NPROCESSORS_ONLN);
+        }
+        ovsthread_once_done(&once);
+    }
+
+    return n_cores > 0 ? n_cores : 0;
+}
 #endif
index 7f3195d..c6a7142 100644 (file)
@@ -496,5 +496,9 @@ pid_t xfork_at(const char *where);
 
 void forbid_forking(const char *reason);
 bool may_fork(void);
+\f
+/* Useful functions related to threading. */
+
+unsigned int count_cpu_cores(void);
 
 #endif /* ovs-thread.h */
index 4bec4d1..d87aa8e 100644 (file)
@@ -425,7 +425,7 @@ eth_addr_bitand(const uint8_t src[ETH_ADDR_LEN],
 int
 ip_count_cidr_bits(ovs_be32 netmask)
 {
-    return 32 - ctz(ntohl(netmask));
+    return 32 - ctz32(ntohl(netmask));
 }
 
 void
@@ -909,6 +909,39 @@ packet_get_tcp_flags(const struct ofpbuf *packet, const struct flow *flow)
     }
 }
 
+const char *
+packet_tcp_flag_to_string(uint32_t flag)
+{
+    switch (flag) {
+    case TCP_FIN:
+        return "fin";
+    case TCP_SYN:
+        return "syn";
+    case TCP_RST:
+        return "rst";
+    case TCP_PSH:
+        return "psh";
+    case TCP_ACK:
+        return "ack";
+    case TCP_URG:
+        return "urg";
+    case TCP_ECE:
+        return "ece";
+    case TCP_CWR:
+        return "cwr";
+    case TCP_NS:
+        return "ns";
+    case 0x200:
+        return "[200]";
+    case 0x400:
+        return "[400]";
+    case 0x800:
+        return "[800]";
+    default:
+        return NULL;
+    }
+}
+
 /* Appends a string representation of the TCP flags value 'tcp_flags'
  * (e.g. obtained via packet_get_tcp_flags() or TCP_FLAGS) to 's', in the
  * format used by tcpdump. */
index ef8c00c..d291c14 100644 (file)
@@ -643,5 +643,6 @@ void packet_set_sctp_port(struct ofpbuf *, ovs_be16 src, ovs_be16 dst);
 
 uint16_t packet_get_tcp_flags(const struct ofpbuf *, const struct flow *);
 void packet_format_tcp_flags(struct ds *, uint16_t);
+const char *packet_tcp_flag_to_string(uint32_t flag);
 
 #endif /* packets.h */
index 9091a72..ac68716 100644 (file)
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
+#include "byte-order.h"
 #include "compiler.h"
 #include "ofpbuf.h"
 #include "vlog.h"
@@ -151,10 +152,7 @@ pcap_read(FILE *file, struct ofpbuf **bufp)
     /* Calculate length. */
     len = prh.incl_len;
     if (len > 0xffff) {
-        uint32_t swapped_len = (((len & 0xff000000) >> 24) |
-                                ((len & 0x00ff0000) >>  8) |
-                                ((len & 0x0000ff00) <<  8) |
-                                ((len & 0x000000ff) << 24));
+        uint32_t swapped_len = uint32_byteswap(len);
         if (swapped_len > 0xffff) {
             VLOG_WARN("bad packet length %"PRIuSIZE" or %"PRIu32" "
                       "reading pcap file",
index faa2cab..13d41a7 100644 (file)
@@ -346,7 +346,7 @@ ovs_strerror(int error)
          * is too short).  We don't check the actual failure reason because
          * POSIX requires strerror_r() to return the error but old glibc
          * (before 2.13) returns -1 and sets errno. */
-        snprintf(buffer, BUFSIZE, "Unknown error %"PRIuSIZE, error);
+        snprintf(buffer, BUFSIZE, "Unknown error %d", error);
     }
 #endif
 
@@ -848,50 +848,11 @@ english_list_delimiter(size_t index, size_t total)
             : " and ");
 }
 
-/* Given a 32 bit word 'n', calculates floor(log_2('n')).  This is equivalent
- * to finding the bit position of the most significant one bit in 'n'.  It is
- * an error to call this function with 'n' == 0. */
-int
-log_2_floor(uint32_t n)
-{
-    ovs_assert(n);
-
-#if !defined(UINT_MAX) || !defined(UINT32_MAX)
-#error "Someone screwed up the #includes."
-#elif __GNUC__ >= 4 && UINT_MAX == UINT32_MAX
-    return 31 - __builtin_clz(n);
-#else
-    {
-        int log = 0;
-
-#define BIN_SEARCH_STEP(BITS)                   \
-        if (n >= (1 << BITS)) {                 \
-            log += BITS;                        \
-            n >>= BITS;                         \
-        }
-        BIN_SEARCH_STEP(16);
-        BIN_SEARCH_STEP(8);
-        BIN_SEARCH_STEP(4);
-        BIN_SEARCH_STEP(2);
-        BIN_SEARCH_STEP(1);
-#undef BIN_SEARCH_STEP
-        return log;
-    }
-#endif
-}
-
-/* Given a 32 bit word 'n', calculates ceil(log_2('n')).  It is an error to
- * call this function with 'n' == 0. */
-int
-log_2_ceil(uint32_t n)
-{
-    return log_2_floor(n) + !is_pow2(n);
-}
-
 /* Returns the number of trailing 0-bits in 'n'.  Undefined if 'n' == 0. */
 #if __GNUC__ >= 4
 /* Defined inline in util.h. */
 #else
+/* Returns the number of trailing 0-bits in 'n'.  Undefined if 'n' == 0. */
 int
 raw_ctz(uint64_t n)
 {
@@ -914,16 +875,33 @@ raw_ctz(uint64_t n)
 
     return count;
 }
-#endif
 
-/* Returns the number of 1-bits in 'x', between 0 and 32 inclusive. */
-static unsigned int
-count_1bits_32(uint32_t x)
+/* Returns the number of leading 0-bits in 'n'.  Undefined if 'n' == 0. */
+int
+raw_clz64(uint64_t n)
 {
-    /* In my testing, this implementation is over twice as fast as any other
-     * portable implementation that I tried, including GCC 4.4
-     * __builtin_popcount(), although nonportable asm("popcnt") was over 50%
-     * faster. */
+    uint64_t k;
+    int count = 63;
+
+#define CLZ_STEP(X)                             \
+    k = n >> (X);                               \
+    if (k) {                                    \
+        count -= X;                             \
+        n = k;                                  \
+    }
+    CLZ_STEP(32);
+    CLZ_STEP(16);
+    CLZ_STEP(8);
+    CLZ_STEP(4);
+    CLZ_STEP(2);
+    CLZ_STEP(1);
+#undef CLZ_STEP
+
+    return count;
+}
+#endif
+
+#if !(__GNUC__ >= 4 && defined(__corei7))
 #define INIT1(X)                                \
     ((((X) & (1 << 0)) != 0) +                  \
      (((X) & (1 << 1)) != 0) +                  \
@@ -940,22 +918,10 @@ count_1bits_32(uint32_t x)
 #define INIT32(X) INIT16(X), INIT16((X) + 16)
 #define INIT64(X) INIT32(X), INIT32((X) + 32)
 
-    static const uint8_t count_1bits_8[256] = {
-        INIT64(0), INIT64(64), INIT64(128), INIT64(192)
-    };
-
-    return (count_1bits_8[x & 0xff] +
-            count_1bits_8[(x >> 8) & 0xff] +
-            count_1bits_8[(x >> 16) & 0xff] +
-            count_1bits_8[x >> 24]);
-}
-
-/* Returns the number of 1-bits in 'x', between 0 and 64 inclusive. */
-unsigned int
-count_1bits(uint64_t x)
-{
-    return count_1bits_32(x) + count_1bits_32(x >> 32);
-}
+const uint8_t count_1bits_8[256] = {
+    INIT64(0), INIT64(64), INIT64(128), INIT64(192)
+};
+#endif
 
 /* Returns true if the 'n' bytes starting at 'p' are zeros. */
 bool
index fbab74c..7c5eacb 100644 (file)
@@ -302,10 +302,6 @@ void ignore(bool x OVS_UNUSED);
 \f
 /* Bitwise tests. */
 
-int log_2_floor(uint32_t);
-int log_2_ceil(uint32_t);
-unsigned int count_1bits(uint64_t);
-
 /* Returns the number of trailing 0-bits in 'n'.  Undefined if 'n' == 0. */
 #if __GNUC__ >= 4
 static inline int
@@ -318,14 +314,21 @@ raw_ctz(uint64_t n)
             ? __builtin_ctz(n)
             : __builtin_ctzll(n));
 }
+
+static inline int
+raw_clz64(uint64_t n)
+{
+    return __builtin_clzll(n);
+}
 #else
 /* Defined in util.c. */
 int raw_ctz(uint64_t n);
+int raw_clz64(uint64_t n);
 #endif
 
 /* Returns the number of trailing 0-bits in 'n', or 32 if 'n' is 0. */
 static inline int
-ctz(uint32_t n)
+ctz32(uint32_t n)
 {
     return n ? raw_ctz(n) : 32;
 }
@@ -337,6 +340,80 @@ ctz64(uint64_t n)
     return n ? raw_ctz(n) : 64;
 }
 
+/* Returns the number of leading 0-bits in 'n', or 32 if 'n' is 0. */
+static inline int
+clz32(uint32_t n)
+{
+    return n ? raw_clz64(n) - 32 : 32;
+}
+
+/* Returns the number of leading 0-bits in 'n', or 64 if 'n' is 0. */
+static inline int
+clz64(uint64_t n)
+{
+    return n ? raw_clz64(n) : 64;
+}
+
+/* Given a word 'n', calculates floor(log_2('n')).  This is equivalent
+ * to finding the bit position of the most significant one bit in 'n'.  It is
+ * an error to call this function with 'n' == 0. */
+static inline int
+log_2_floor(uint64_t n)
+{
+    return 63 - raw_clz64(n);
+}
+
+/* Given a word 'n', calculates ceil(log_2('n')).  It is an error to
+ * call this function with 'n' == 0. */
+static inline int
+log_2_ceil(uint64_t n)
+{
+    return log_2_floor(n) + !is_pow2(n);
+}
+
+/* Returns the number of 1-bits in 'x', between 0 and 32 inclusive. */
+static inline unsigned int
+count_1bits_32(uint32_t x)
+{
+#if __GNUC__ >= 4 && defined(__corei7)
+    /* __builtin_popcount() is fast only when supported by the CPU. */
+    return __builtin_popcount(x);
+#else
+    extern const uint8_t count_1bits_8[256];
+    /* This portable implementation is the fastest one we know of for 32 bits,
+     * and faster than GCC __builtin_popcount(). */
+    return (count_1bits_8[x & 0xff] +
+            count_1bits_8[(x >> 8) & 0xff] +
+            count_1bits_8[(x >> 16) & 0xff] +
+            count_1bits_8[x >> 24]);
+#endif
+}
+
+/* Returns the number of 1-bits in 'x', between 0 and 64 inclusive. */
+static inline unsigned int
+count_1bits(uint64_t x)
+{
+    if (sizeof(void *) == 8) { /* 64-bit CPU */
+#if __GNUC__ >= 4 && defined(__corei7)
+        /* __builtin_popcountll() is fast only when supported by the CPU. */
+        return __builtin_popcountll(x);
+#else
+        /* This portable implementation is the fastest one we know of for 64
+         * bits, and about 3x faster than GCC 4.7 __builtin_popcountll(). */
+        const uint64_t h55 = UINT64_C(0x5555555555555555);
+        const uint64_t h33 = UINT64_C(0x3333333333333333);
+        const uint64_t h0F = UINT64_C(0x0F0F0F0F0F0F0F0F);
+        const uint64_t h01 = UINT64_C(0x0101010101010101);
+        x -= (x >> 1) & h55;               /* Count of each 2 bits in-place. */
+        x = (x & h33) + ((x >> 2) & h33);  /* Count of each 4 bits in-place. */
+        x = (x + (x >> 4)) & h0F;          /* Count of each 8 bits in-place. */
+        return (x * h01) >> 56;            /* Sum of all bytes. */
+#endif
+    } else { /* 32-bit CPU */
+        return count_1bits_32(x) + count_1bits_32(x >> 32);
+    }
+}
+
 /* Returns the rightmost 1-bit in 'x' (e.g. 01011000 => 00001000), or 0 if 'x'
  * is 0. */
 static inline uintmax_t
@@ -361,10 +438,10 @@ zero_rightmost_1bit(uintmax_t x)
 static inline uint32_t
 rightmost_1bit_idx(uint32_t x)
 {
-    return x ? ctz(x) : 32;
+    return ctz32(x);
 }
 
-/* Returns the index of the rightmost 1-bit in 'x' (e.g. 01011000 => 6), or 32
+/* Returns the index of the leftmost 1-bit in 'x' (e.g. 01011000 => 6), or 32
  * if 'x' is 0.
  *
  * This function only works with 32-bit integers. */
index b1ca158..0fa1ab2 100644 (file)
@@ -35,6 +35,7 @@
 #include "ofpbuf.h"
 #include "ovs-thread.h"
 #include "sat-math.h"
+#include "socket-util.h"
 #include "svec.h"
 #include "timeval.h"
 #include "unixctl.h"
@@ -49,18 +50,30 @@ VLOG_DEFINE_THIS_MODULE(vlog);
 
 /* Name for each logging level. */
 static const char *const level_names[VLL_N_LEVELS] = {
-#define VLOG_LEVEL(NAME, SYSLOG_LEVEL) #NAME,
+#define VLOG_LEVEL(NAME, SYSLOG_LEVEL, RFC5424) #NAME,
     VLOG_LEVELS
 #undef VLOG_LEVEL
 };
 
 /* Syslog value for each logging level. */
 static const int syslog_levels[VLL_N_LEVELS] = {
-#define VLOG_LEVEL(NAME, SYSLOG_LEVEL) SYSLOG_LEVEL,
+#define VLOG_LEVEL(NAME, SYSLOG_LEVEL, RFC5424) SYSLOG_LEVEL,
     VLOG_LEVELS
 #undef VLOG_LEVEL
 };
 
+/* RFC 5424 defines specific values for each syslog level.  Normally LOG_* use
+ * the same values.  Verify that in fact they're the same.  If we get assertion
+ * failures here then we need to define a separate rfc5424_levels[] array. */
+#define VLOG_LEVEL(NAME, SYSLOG_LEVEL, RFC5424) \
+    BUILD_ASSERT_DECL(SYSLOG_LEVEL == RFC5424);
+VLOG_LEVELS
+#undef VLOG_LEVELS
+
+/* Similarly, RFC 5424 defines the local0 facility with the value ordinarily
+ * used for LOG_LOCAL0. */
+BUILD_ASSERT_DECL(LOG_LOCAL0 == (16 << 3));
+
 /* The log modules. */
 #if USE_LINKER_SECTIONS
 extern struct vlog_module *__start_vlog_modules[];
@@ -111,10 +124,13 @@ static int log_fd OVS_GUARDED_BY(log_file_mutex) = -1;
 static struct async_append *log_writer OVS_GUARDED_BY(log_file_mutex);
 static bool log_async OVS_GUARDED_BY(log_file_mutex);
 
+/* Syslog export configuration. */
+static int syslog_fd OVS_GUARDED_BY(pattern_rwlock) = -1;
+
 static void format_log_message(const struct vlog_module *, enum vlog_level,
-                               enum vlog_facility,
+                               const char *pattern,
                                const char *message, va_list, struct ds *)
-    PRINTF_FORMAT(4, 0) OVS_REQ_RDLOCK(&pattern_rwlock);
+    PRINTF_FORMAT(4, 0);
 
 /* Searches the 'n_names' in 'names'.  Returns the index of a match for
  * 'target', or 'n_names' if no name matches. */
@@ -480,6 +496,22 @@ vlog_set_verbosity(const char *arg)
     }
 }
 
+/* Set the vlog udp syslog target. */
+void
+vlog_set_syslog_target(const char *target)
+{
+    int new_fd;
+
+    inet_open_active(SOCK_DGRAM, target, 0, NULL, &new_fd, 0);
+
+    ovs_rwlock_wrlock(&pattern_rwlock);
+    if (syslog_fd >= 0) {
+        close(syslog_fd);
+    }
+    syslog_fd = new_fd;
+    ovs_rwlock_unlock(&pattern_rwlock);
+}
+
 static void
 vlog_unixctl_set(struct unixctl_conn *conn, int argc, const char *argv[],
                  void *aux OVS_UNUSED)
@@ -700,15 +732,15 @@ fetch_braces(const char *p, const char *def, char *out, size_t out_size)
 
 static void
 format_log_message(const struct vlog_module *module, enum vlog_level level,
-                   enum vlog_facility facility,
-                   const char *message, va_list args_, struct ds *s)
+                   const char *pattern, const char *message,
+                   va_list args_, struct ds *s)
 {
     char tmp[128];
     va_list args;
     const char *p;
 
     ds_clear(s);
-    for (p = facilities[facility].pattern; *p != '\0'; ) {
+    for (p = pattern; *p != '\0'; ) {
         const char *subprogram_name;
         enum { LEFT, RIGHT } justify = RIGHT;
         int pad = '0';
@@ -739,6 +771,9 @@ format_log_message(const struct vlog_module *module, enum vlog_level level,
         case 'A':
             ds_put_cstr(s, program_name);
             break;
+        case 'B':
+            ds_put_format(s, "%d", LOG_LOCAL0 + syslog_levels[level]);
+            break;
         case 'c':
             p = fetch_braces(p, "", tmp, sizeof tmp);
             ds_put_cstr(s, vlog_get_module_name(module));
@@ -751,6 +786,11 @@ format_log_message(const struct vlog_module *module, enum vlog_level level,
             p = fetch_braces(p, "%Y-%m-%d %H:%M:%S.###", tmp, sizeof tmp);
             ds_put_strftime_msec(s, tmp, time_wall_msec(), true);
             break;
+        case 'E':
+            gethostname(tmp, sizeof tmp);
+            tmp[sizeof tmp - 1] = '\0';
+            ds_put_cstr(s, tmp);
+            break;
         case 'm':
             /* Format user-supplied log message and trim trailing new-lines. */
             length = s->length;
@@ -804,6 +844,20 @@ format_log_message(const struct vlog_module *module, enum vlog_level level,
     }
 }
 
+/* Exports the given 'syslog_message' to the configured udp syslog sink. */
+static void
+send_to_syslog_fd(const char *s, size_t length)
+    OVS_REQ_RDLOCK(pattern_rwlock)
+{
+    static size_t max_length = SIZE_MAX;
+    size_t send_len = MIN(length, max_length);
+
+    while (write(syslog_fd, s, send_len) < 0 && errno == EMSGSIZE) {
+        send_len -= send_len / 20;
+        max_length = send_len;
+    }
+}
+
 /* Writes 'message' to the log at the given 'level' and as coming from the
  * given 'module'.
  *
@@ -831,7 +885,8 @@ vlog_valist(const struct vlog_module *module, enum vlog_level level,
 
         ovs_rwlock_rdlock(&pattern_rwlock);
         if (log_to_console) {
-            format_log_message(module, level, VLF_CONSOLE, message, args, &s);
+            format_log_message(module, level, facilities[VLF_CONSOLE].pattern,
+                               message, args, &s);
             ds_put_char(&s, '\n');
             fputs(ds_cstr(&s), stderr);
         }
@@ -841,15 +896,25 @@ vlog_valist(const struct vlog_module *module, enum vlog_level level,
             char *save_ptr = NULL;
             char *line;
 
-            format_log_message(module, level, VLF_SYSLOG, message, args, &s);
+            format_log_message(module, level, facilities[VLF_SYSLOG].pattern,
+                               message, args, &s);
             for (line = strtok_r(s.string, "\n", &save_ptr); line;
                  line = strtok_r(NULL, "\n", &save_ptr)) {
                 syslog(syslog_level, "%s", line);
             }
+
+            if (syslog_fd >= 0) {
+                format_log_message(module, level,
+                                   "<%B>1 %D{%Y-%m-%dT%H:%M:%S.###Z} "
+                                   "%E %A %P %c - \xef\xbb\xbf%m",
+                                   message, args, &s);
+                send_to_syslog_fd(ds_cstr(&s), s.length);
+            }
         }
 
         if (log_to_file) {
-            format_log_message(module, level, VLF_FILE, message, args, &s);
+            format_log_message(module, level, facilities[VLF_FILE].pattern,
+                               message, args, &s);
             ds_put_char(&s, '\n');
 
             ovs_mutex_lock(&log_file_mutex);
@@ -1012,10 +1077,12 @@ vlog_rate_limit(const struct vlog_module *module, enum vlog_level level,
 void
 vlog_usage(void)
 {
-    printf("\nLogging options:\n"
-           "  -v, --verbose=[SPEC]    set logging levels\n"
-           "  -v, --verbose           set maximum verbosity level\n"
-           "  --log-file[=FILE]       enable logging to specified FILE\n"
-           "                          (default: %s/%s.log)\n",
+    printf("\n\
+Logging options:\n\
+  -vSPEC, --verbose=SPEC   set logging levels\n\
+  -v, --verbose            set maximum verbosity level\n\
+  --log-file[=FILE]        enable logging to specified FILE\n\
+                           (default: %s/%s.log)\n\
+  --syslog-target=HOST:PORT  also send syslog msgs to HOST:PORT via UDP\n",
            ovs_logdir(), program_name);
 }
index d7d63bf..da55405 100644 (file)
@@ -44,14 +44,14 @@ extern "C" {
  *
  * ovs-appctl(8) defines each of the log levels. */
 #define VLOG_LEVELS                             \
-    VLOG_LEVEL(OFF, LOG_ALERT)                  \
-    VLOG_LEVEL(EMER, LOG_ALERT)                 \
-    VLOG_LEVEL(ERR, LOG_ERR)                    \
-    VLOG_LEVEL(WARN, LOG_WARNING)               \
-    VLOG_LEVEL(INFO, LOG_NOTICE)                \
-    VLOG_LEVEL(DBG, LOG_DEBUG)
+    VLOG_LEVEL(OFF,  LOG_ALERT,   1)            \
+    VLOG_LEVEL(EMER, LOG_ALERT,   1)            \
+    VLOG_LEVEL(ERR,  LOG_ERR,     3)            \
+    VLOG_LEVEL(WARN, LOG_WARNING, 4)            \
+    VLOG_LEVEL(INFO, LOG_NOTICE,  5)            \
+    VLOG_LEVEL(DBG,  LOG_DEBUG,   7)
 enum vlog_level {
-#define VLOG_LEVEL(NAME, SYSLOG_LEVEL) VLL_##NAME,
+#define VLOG_LEVEL(NAME, SYSLOG_LEVEL, RFC5424_LEVEL) VLL_##NAME,
     VLOG_LEVELS
 #undef VLOG_LEVEL
     VLL_N_LEVELS
@@ -62,7 +62,7 @@ enum vlog_level vlog_get_level_val(const char *name);
 
 /* Facilities that we can log to. */
 #define VLOG_FACILITIES                                                 \
-    VLOG_FACILITY(SYSLOG, "ovs|%05N|%c%T|%p|%m")                            \
+    VLOG_FACILITY(SYSLOG, "ovs|%05N|%c%T|%p|%m")                        \
     VLOG_FACILITY(CONSOLE, "%D{%Y-%m-%dT%H:%M:%SZ}|%05N|%c%T|%p|%m")    \
     VLOG_FACILITY(FILE, "%D{%Y-%m-%dT%H:%M:%S.###Z}|%05N|%c%T|%p|%m")
 enum vlog_facility {
@@ -139,6 +139,9 @@ void vlog_set_pattern(enum vlog_facility, const char *pattern);
 int vlog_set_log_file(const char *file_name);
 int vlog_reopen_log_file(void);
 
+/* Configure syslog target. */
+void vlog_set_syslog_target(const char *target);
+
 /* Initialization. */
 void vlog_init(void);
 void vlog_enable_async(void);
@@ -213,17 +216,26 @@ void vlog_rate_limit(const struct vlog_module *, enum vlog_level,
 #define VLOG_DBG_ONCE(...) VLOG_ONCE(VLL_DBG, __VA_ARGS__)
 
 /* Command line processing. */
-#define VLOG_OPTION_ENUMS OPT_LOG_FILE
-#define VLOG_LONG_OPTIONS                                   \
-        {"verbose",     optional_argument, NULL, 'v'},         \
-        {"log-file",    optional_argument, NULL, OPT_LOG_FILE}
+#define VLOG_OPTION_ENUMS                       \
+        OPT_LOG_FILE,                           \
+        OPT_SYSLOG_TARGET
+
+#define VLOG_LONG_OPTIONS                                               \
+        {"verbose",       optional_argument, NULL, 'v'},                \
+        {"log-file",      optional_argument, NULL, OPT_LOG_FILE},       \
+        {"syslog-target", optional_argument, NULL, OPT_SYSLOG_TARGET}
+
 #define VLOG_OPTION_HANDLERS                    \
         case 'v':                               \
             vlog_set_verbosity(optarg);         \
             break;                              \
         case OPT_LOG_FILE:                      \
             vlog_set_log_file(optarg);          \
+            break;                              \
+        case OPT_SYSLOG_TARGET:                 \
+            vlog_set_syslog_target(optarg);     \
             break;
+
 void vlog_usage(void);
 
 /* Implementation details. */
index 39edaee..f675a4b 100644 (file)
@@ -60,3 +60,8 @@ Sets the log pattern for \fIfacility\fR to \fIpattern\fR.  Refer to
 Enables logging to a file.  If \fIfile\fR is specified, then it is
 used as the exact name for the log file.  The default log file name
 used if \fIfile\fR is omitted is \fB@LOGDIR@/\*(PN.log\fR.
+.
+.IP "\fB\-\-syslog\-target=\fIhost\fB:\fIport\fR"
+Send syslog messages to UDP \fIport\fR on \fIhost\fR, in addition to
+the system syslog.  The \fIhost\fR must be a numerical IP address, not
+a hostname.
index 7c37985..e7281ad 100644 (file)
@@ -118,7 +118,7 @@ OpenFlow connections over SSL will not be supported.
 dnl Checks for libraries needed by lib/socket-util.c.
 AC_DEFUN([OVS_CHECK_SOCKET_LIBS],
   [AC_CHECK_LIB([socket], [connect])
-   AC_SEARCH_LIBS([gethostbyname], [resolv], [RESOLVER_LIBS=-lresolv])])
+   AC_SEARCH_LIBS([gethostbyname], [resolv])])
 
 dnl Checks for the directory in which to store the PKI.
 AC_DEFUN([OVS_CHECK_PKIDIR],
@@ -432,6 +432,12 @@ static thread_local int var;], [return var;])],
      fi
    fi])
 
+dnl OVS_CHECK_ATOMIC_LIBS
+dnl
+dnl Check to see if -latomic is need for GCC atomic built-ins.
+AC_DEFUN([OVS_CHECK_ATOMIC_LIBS],
+   [AC_SEARCH_LIBS([__atomic_load_8], [atomic])])
+
 dnl OVS_CHECK_GCC4_ATOMICS
 dnl
 dnl Checks whether the compiler and linker support GCC 4.0+ atomic built-ins.
index 432f083..218a5b1 100644 (file)
@@ -7,6 +7,8 @@
 
 noinst_LIBRARIES += ofproto/libofproto.a
 ofproto_libofproto_a_SOURCES = \
+       ofproto/bond.c \
+       ofproto/bond.h \
        ofproto/collectors.c \
        ofproto/collectors.h \
        ofproto/connmgr.c \
similarity index 100%
rename from lib/bond.c
rename to ofproto/bond.c
similarity index 100%
rename from lib/bond.h
rename to ofproto/bond.h
index a331c0b..b0f61ca 100644 (file)
@@ -1718,6 +1718,9 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
         if (ctx->xin->resubmit_stats) {
             netdev_vport_inc_tx(xport->netdev, ctx->xin->resubmit_stats);
             netdev_vport_inc_rx(peer->netdev, ctx->xin->resubmit_stats);
+            if (peer->bfd) {
+                bfd_account_rx(peer->bfd, ctx->xin->resubmit_stats);
+            }
         }
 
         return;
@@ -1868,10 +1871,10 @@ xlate_table_action(struct xlate_ctx *ctx,
 
             /* XXX
              * check if table configuration flags
-             * OFPTC_TABLE_MISS_CONTROLLER, default.
-             * OFPTC_TABLE_MISS_CONTINUE,
-             * OFPTC_TABLE_MISS_DROP
-             * When OF1.0, OFPTC_TABLE_MISS_CONTINUE is used. What to do? */
+             * OFPTC11_TABLE_MISS_CONTROLLER, default.
+             * OFPTC11_TABLE_MISS_CONTINUE,
+             * OFPTC11_TABLE_MISS_DROP
+             * When OF1.0, OFPTC11_TABLE_MISS_CONTINUE is used. What to do? */
             xport = get_ofp_port(ctx->xbridge, ctx->xin->flow.in_port.ofp_port);
             choose_miss_rule(xport ? xport->config : 0,
                              ctx->xbridge->miss_rule,
index 7df0450..5e0a7f0 100644 (file)
@@ -213,7 +213,8 @@ struct subfacet {
 
 #define SUBFACET_DESTROY_MAX_BATCH 50
 
-static struct subfacet *subfacet_create(struct facet *, struct flow_miss *);
+static struct subfacet *subfacet_create(struct facet *, struct flow_miss *,
+                                        uint32_t key_hash);
 static struct subfacet *subfacet_find(struct dpif_backer *,
                                       const struct nlattr *key, size_t key_len,
                                       uint32_t key_hash);
@@ -3222,13 +3223,32 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet,
 {
     enum subfacet_path want_path;
     struct subfacet *subfacet;
+    uint32_t key_hash;
 
+    /* Update facet stats. */
     facet->packet_count += miss->stats.n_packets;
     facet->prev_packet_count += miss->stats.n_packets;
     facet->byte_count += miss->stats.n_bytes;
     facet->prev_byte_count += miss->stats.n_bytes;
 
-    want_path = facet->xout.slow ? SF_SLOW_PATH : SF_FAST_PATH;
+    /* Look for an existing subfacet.  If we find one, update its used time. */
+    key_hash = odp_flow_key_hash(miss->key, miss->key_len);
+    if (!list_is_empty(&facet->subfacets)) {
+        subfacet = subfacet_find(miss->ofproto->backer,
+                                 miss->key, miss->key_len, key_hash);
+        if (subfacet) {
+            if (subfacet->facet == facet) {
+                subfacet->used = MAX(subfacet->used, miss->stats.used);
+            } else {
+                /* This shouldn't happen. */
+                VLOG_ERR_RL(&rl, "subfacet with wrong facet");
+                subfacet_destroy(subfacet);
+                subfacet = NULL;
+            }
+        }
+    } else {
+        subfacet = NULL;
+    }
 
     /* Don't install the flow if it's the result of the "userspace"
      * action for an already installed facet.  This can occur when a
@@ -3240,7 +3260,13 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet,
         return;
     }
 
-    subfacet = subfacet_create(facet, miss);
+    /* Create a subfacet, if we don't already have one. */
+    if (!subfacet) {
+        subfacet = subfacet_create(facet, miss, key_hash);
+    }
+
+    /* Install the subfacet, if it's not already installed. */
+    want_path = facet->xout.slow ? SF_SLOW_PATH : SF_FAST_PATH;
     if (subfacet->path != want_path) {
         struct flow_miss_op *op = &ops[(*n_ops)++];
         struct dpif_flow_put *put = &op->dpif_op.u.flow_put;
@@ -4247,6 +4273,9 @@ flow_push_stats(struct ofproto_dpif *ofproto, struct flow *flow,
     in_port = get_ofp_port(ofproto, flow->in_port.ofp_port);
     if (in_port && in_port->is_tunnel) {
         netdev_vport_inc_rx(in_port->up.netdev, stats);
+        if (in_port->bfd) {
+            bfd_account_rx(in_port->bfd, stats);
+        }
     }
 
     xlate_in_init(&xin, ofproto, flow, NULL, stats->tcp_flags, NULL);
@@ -4382,37 +4411,20 @@ subfacet_find(struct dpif_backer *backer, const struct nlattr *key,
     return NULL;
 }
 
-/* Searches 'facet' (within 'ofproto') for a subfacet with the specified
- * 'key_fitness', 'key', and 'key_len' members in 'miss'.  Returns the
- * existing subfacet if there is one, otherwise creates and returns a
- * new subfacet. */
+/* Creates and returns a new subfacet within 'facet' for the flow in 'miss'.
+ * 'key_hash' must be a hash over miss->key.  The caller must have already
+ * ensured that no subfacet subfacet already exists. */
 static struct subfacet *
-subfacet_create(struct facet *facet, struct flow_miss *miss)
+subfacet_create(struct facet *facet, struct flow_miss *miss, uint32_t key_hash)
 {
     struct dpif_backer *backer = miss->ofproto->backer;
     const struct nlattr *key = miss->key;
     size_t key_len = miss->key_len;
-    uint32_t key_hash;
     struct subfacet *subfacet;
 
-    key_hash = odp_flow_key_hash(key, key_len);
-
-    if (list_is_empty(&facet->subfacets)) {
-        subfacet = &facet->one_subfacet;
-    } else {
-        subfacet = subfacet_find(backer, key, key_len, key_hash);
-        if (subfacet) {
-            if (subfacet->facet == facet) {
-                return subfacet;
-            }
-
-            /* This shouldn't happen. */
-            VLOG_ERR_RL(&rl, "subfacet with wrong facet");
-            subfacet_destroy(subfacet);
-        }
-
-        subfacet = xmalloc(sizeof *subfacet);
-    }
+    subfacet = (list_is_empty(&facet->subfacets)
+                ? &facet->one_subfacet
+                : xmalloc(sizeof *subfacet));
 
     COVERAGE_INC(subfacet_create);
     hmap_insert(&backer->subfacets, &subfacet->hmap_node, key_hash);
index c4ce8a2..b282abe 100644 (file)
@@ -738,7 +738,7 @@ ofproto_set_n_handler_threads(unsigned limit)
     if (limit) {
         n_handler_threads = limit;
     } else {
-        int n_proc = sysconf(_SC_NPROCESSORS_ONLN);
+        int n_proc = count_cpu_cores();
         n_handler_threads = n_proc > 2 ? n_proc - 2 : 1;
     }
 }
index 6ce08af..5384c32 100644 (file)
@@ -105,42 +105,42 @@ systemctl start openvswitch.service
 %{_sysconfdir}/sysconfig/network-scripts/ifup-ovs
 %{_sysconfdir}/sysconfig/network-scripts/ifdown-ovs
 /usr/share/openvswitch/bugtool-plugins/
-/usr/share/openvswitch/python/ovs/__init__.py
-/usr/share/openvswitch/python/ovs/daemon.py
-/usr/share/openvswitch/python/ovs/db/__init__.py
-/usr/share/openvswitch/python/ovs/db/data.py
-/usr/share/openvswitch/python/ovs/db/error.py
-/usr/share/openvswitch/python/ovs/db/idl.py
-/usr/share/openvswitch/python/ovs/db/parser.py
-/usr/share/openvswitch/python/ovs/db/schema.py
-/usr/share/openvswitch/python/ovs/db/types.py
-/usr/share/openvswitch/python/ovs/dirs.py
-/usr/share/openvswitch/python/ovs/fatal_signal.py
-/usr/share/openvswitch/python/ovs/json.py
-/usr/share/openvswitch/python/ovs/jsonrpc.py
-/usr/share/openvswitch/python/ovs/ovsuuid.py
-/usr/share/openvswitch/python/ovs/poller.py
-/usr/share/openvswitch/python/ovs/process.py
-/usr/share/openvswitch/python/ovs/reconnect.py
-/usr/share/openvswitch/python/ovs/socket_util.py
-/usr/share/openvswitch/python/ovs/stream.py
-/usr/share/openvswitch/python/ovs/timeval.py
-/usr/share/openvswitch/python/ovs/util.py
-/usr/share/openvswitch/python/ovs/version.py
-/usr/share/openvswitch/python/ovs/unixctl/__init__.py
-/usr/share/openvswitch/python/ovs/unixctl/client.py
-/usr/share/openvswitch/python/ovs/unixctl/server.py
-/usr/share/openvswitch/python/uuid.py
-/usr/share/openvswitch/python/argparse.py
-/usr/share/openvswitch/python/ovs/vlog.py
-/usr/share/openvswitch/python/ovstest/__init__.py
-/usr/share/openvswitch/python/ovstest/args.py
-/usr/share/openvswitch/python/ovstest/rpcserver.py
-/usr/share/openvswitch/python/ovstest/tcp.py
-/usr/share/openvswitch/python/ovstest/udp.py
-/usr/share/openvswitch/python/ovstest/util.py
-/usr/share/openvswitch/python/ovstest/vswitch.py
-/usr/share/openvswitch/python/ovstest/tests.py
+/usr/share/openvswitch/python/ovs/__init__.py*
+/usr/share/openvswitch/python/ovs/daemon.py*
+/usr/share/openvswitch/python/ovs/db/__init__.py*
+/usr/share/openvswitch/python/ovs/db/data.py*
+/usr/share/openvswitch/python/ovs/db/error.py*
+/usr/share/openvswitch/python/ovs/db/idl.py*
+/usr/share/openvswitch/python/ovs/db/parser.py*
+/usr/share/openvswitch/python/ovs/db/schema.py*
+/usr/share/openvswitch/python/ovs/db/types.py*
+/usr/share/openvswitch/python/ovs/dirs.py*
+/usr/share/openvswitch/python/ovs/fatal_signal.py*
+/usr/share/openvswitch/python/ovs/json.py*
+/usr/share/openvswitch/python/ovs/jsonrpc.py*
+/usr/share/openvswitch/python/ovs/ovsuuid.py*
+/usr/share/openvswitch/python/ovs/poller.py*
+/usr/share/openvswitch/python/ovs/process.py*
+/usr/share/openvswitch/python/ovs/reconnect.py*
+/usr/share/openvswitch/python/ovs/socket_util.py*
+/usr/share/openvswitch/python/ovs/stream.py*
+/usr/share/openvswitch/python/ovs/timeval.py*
+/usr/share/openvswitch/python/ovs/util.py*
+/usr/share/openvswitch/python/ovs/version.py*
+/usr/share/openvswitch/python/ovs/unixctl/__init__.py*
+/usr/share/openvswitch/python/ovs/unixctl/client.py*
+/usr/share/openvswitch/python/ovs/unixctl/server.py*
+/usr/share/openvswitch/python/uuid.py*
+/usr/share/openvswitch/python/argparse.py*
+/usr/share/openvswitch/python/ovs/vlog.py*
+/usr/share/openvswitch/python/ovstest/__init__.py*
+/usr/share/openvswitch/python/ovstest/args.py*
+/usr/share/openvswitch/python/ovstest/rpcserver.py*
+/usr/share/openvswitch/python/ovstest/tcp.py*
+/usr/share/openvswitch/python/ovstest/udp.py*
+/usr/share/openvswitch/python/ovstest/util.py*
+/usr/share/openvswitch/python/ovstest/vswitch.py*
+/usr/share/openvswitch/python/ovstest/tests.py*
 /usr/share/openvswitch/scripts/ovs-bugtool-*
 /usr/share/openvswitch/scripts/ovs-check-dead-ifs
 /usr/share/openvswitch/scripts/ovs-lib
index 15d2b1a..ccb62b5 100644 (file)
@@ -476,8 +476,14 @@ OVS_VSWITCHD_STOP
 AT_CLEANUP
 
 # Tests below are for bfd forwarding_if_rx feature.
-# forwarding_if_rx Test1: bfd is enabled on one end of link.
-AT_SETUP([bfd - bfd forwarding_if_rx 1])
+
+# forwarding_if_rx Test1
+# Test1 tests the case when bfd is only enabled on one end of the link.
+# Under this situation, the bfd state should be DOWN and the forwarding
+# flag should be FALSE by default.  However, if forwarding_if_rx is
+# enabled, as long as there is packet received, the bfd forwarding flag
+# should be TRUE.
+AT_SETUP([bfd - bfd forwarding_if_rx - bfd on one side])
 OVS_VSWITCHD_START([add-br br1 -- set bridge br1 datapath-type=dummy -- \
                     add-port br1 p1 -- set Interface p1 type=patch \
                     options:peer=p0 ofport_request=2 -- \
@@ -503,22 +509,6 @@ do
     BFD_CHECK([p0], [false], [false], [none], [down], [No Diagnostic], [none], [down], [No Diagnostic])
 done
 
-# receive one packet.
-AT_CHECK([ovs-ofctl packet-out br1 3 2  "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
-             [0], [stdout], [])
-# wait for 1000ms
-for i in `seq 0 14`; do ovs-appctl time/warp 100; done
-# the forwarding flag should turn to true sometime in this 1000ms, since there is data received.
-BFD_CHECK([p0], [true], [false], [none], [down], [No Diagnostic], [none], [down], [No Diagnostic])
-BFD_CHECK_TX([p0], [1000ms], [1000ms], [0ms])
-BFD_CHECK_RX([p0], [500ms], [500ms], [1ms])
-
-# Stop sending packets for 2000ms.
-for i in `seq 0 19`; do ovs-appctl time/warp 100; done
-BFD_CHECK([p0], [false], [false], [none], [down], [No Diagnostic], [none], [down], [No Diagnostic])
-BFD_CHECK_TX([p0], [1000ms], [1000ms], [0ms])
-BFD_CHECK_RX([p0], [500ms], [500ms], [1ms])
-
 # receive packet at 1/100ms rate for 2000ms.
 for i in `seq 0 19`
 do
@@ -528,8 +518,6 @@ do
 done
 # the forwarding flag should be true, since there is data received.
 BFD_CHECK([p0], [true], [false], [none], [down], [No Diagnostic], [none], [down], [No Diagnostic])
-BFD_CHECK_TX([p0], [1000ms], [1000ms], [0ms])
-BFD_CHECK_RX([p0], [500ms], [500ms], [1ms])
 
 # reset bfd forwarding_if_rx.
 AT_CHECK([ovs-vsctl set Interface p0 bfd:forwarding_if_rx=false], [0])
@@ -541,8 +529,12 @@ BFD_CHECK_RX([p0], [500ms], [500ms], [1ms])
 AT_CHECK([ovs-vsctl del-br br1], [0], [ignore])
 AT_CLEANUP
 
-# forwarding_if_rx Test2: bfd is enabled on both ends of link.
-AT_SETUP([bfd - bfd forwarding_if_rx 2])
+
+# forwarding_if_rx Test2
+# Test2 is for testing that the enable of forwarding_if_rx will not
+# affect the normal bfd communication.  bfd is enabled on both ends of
+# the link.
+AT_SETUP([bfd - bfd forwarding_if_rx - bfd on both sides])
 OVS_VSWITCHD_START([add-br br1 -- set bridge br1 datapath-type=dummy -- \
                     add-port br1 p1 -- set Interface p1 type=patch \
                     options:peer=p0 ofport_request=2 -- \
@@ -587,22 +579,10 @@ done
 ovs-appctl time/warp 500
 BFD_CHECK([p0], [true], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
 
-# receive packet at 1/100ms rate for 1000ms.
-for i in `seq 0 9`
-do
-    AT_CHECK([ovs-ofctl packet-out br1 3 2  "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
-             [0], [stdout], [])
-    ovs-appctl time/warp 100
-    # the forwarding flag should always be true during this time.
-    BFD_CHECK([p0], [true], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
-done
-
 # reset bfd forwarding_if_rx.
 AT_CHECK([ovs-vsctl set Interface p0 bfd:forwarding_if_rx=false], [0])
 # forwarding flag should turn to false since the STATE is DOWN.
 BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
-BFD_CHECK_TX([p0], [1000ms], [1000ms], [0ms])
-BFD_CHECK_RX([p0], [500ms], [500ms], [1ms])
 
 # re-enable bfd on the other end. the states should be up.
 AT_CHECK([ovs-vsctl set Interface p1 bfd:enable=true bfd:min_tx=300 bfd:min_rx=300])
@@ -616,8 +596,10 @@ BFD_CHECK_RX([p0], [500ms], [500ms], [300ms])
 AT_CHECK([ovs-vsctl del-br br1], [0], [ignore])
 AT_CLEANUP
 
-# forwarding_if_rx Test3: bfd is enabled on both ends of link and decay is enabled.
-AT_SETUP([bfd - bfd forwarding_if_rx 3])
+# forwarding_if_rx Test3
+# Test3 is for testing that the enable of forwarding_if_rx will not
+# affect the bfd decay feature.  bfd is enabled on both ends of the link.
+AT_SETUP([bfd - bfd forwarding_if_rx - with bfd decay])
 OVS_VSWITCHD_START([add-br br1 -- set bridge br1 datapath-type=dummy -- \
                     add-port br1 p1 -- set Interface p1 type=patch \
                     options:peer=p0 ofport_request=2 -- \
@@ -652,6 +634,7 @@ BFD_CHECK_RX([p0], [500ms], [300ms], [500ms])
 
 # wait for 5000ms to decay.
 for i in `seq 0 9`; do ovs-appctl time/warp 500; done
+BFD_CHECK([p0], [true], [false], [none], [up], [No Diagnostic], [none], [up], [No Diagnostic])
 BFD_CHECK_TX([p0], [500ms], [300ms], [500ms])
 BFD_CHECK_RX([p0], [1000ms], [1000ms], [500ms])
 
@@ -679,23 +662,16 @@ do
     BFD_CHECK([p0], [true], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
 done
 
-# stop receiving for 3000ms.
-for i in `seq 0 29`; do ovs-appctl time/warp 100; done
+# stop receiving for 5000ms.
+for i in `seq 0 49`; do ovs-appctl time/warp 100; done
 BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
 
 # reset bfd forwarding_if_rx.
 AT_CHECK([ovs-vsctl set Interface p0 bfd:forwarding_if_rx=false])
-# forwarding flag should turn to false since the STATE is DOWN.
 BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
-BFD_CHECK_TX([p0], [1000ms], [1000ms], [0ms])
-BFD_CHECK_RX([p0], [300ms], [300ms], [1ms])
-
 # re-enable bfd forwarding_if_rx.
 AT_CHECK([ovs-vsctl set Interface p0 bfd:forwarding_if_rx=true])
-# there should be no change.
 BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
-BFD_CHECK_TX([p0], [1000ms], [1000ms], [0ms])
-BFD_CHECK_RX([p0], [300ms], [300ms], [1ms])
 
 # re-enable bfd on the other end. the states should be up.
 AT_CHECK([ovs-vsctl set Interface p1 bfd:enable=true bfd:min_tx=300 bfd:min_rx=300])
@@ -710,6 +686,10 @@ AT_CHECK([ovs-vsctl del-br br1], [0], [ignore])
 AT_CLEANUP
 
 # test bfd:flap_count.
+# This test contains three part:
+# part 1. tests the flap_count on normal bfd monitored link.
+# part 2. tests the flap_count when forwarding override is used.
+# part 3. tests the flap_count when forwarding_if_rx is enabled.
 AT_SETUP([bfd - flap_count])
 #Create 2 bridges connected by patch ports and enable bfd
 OVS_VSWITCHD_START([add-br br1 -- \
@@ -736,7 +716,7 @@ BFD_VSCTL_LIST_IFACE([p1], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["1"]
 
 # turn bfd on p1 off, should increment the bfd:flap_count on p0.
 AT_CHECK([ovs-vsctl set interface p1 bfd:enable=false])
-for i in `seq 0 10`; do ovs-appctl time/warp 100; done
+for i in `seq 0 49`; do ovs-appctl time/warp 100; done
 BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
 BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["2"])
 AT_CHECK([ovs-vsctl list interface p1 | sed -n "s/^.*flap_count=\(.*\), forwarding.*$/\1/p"])
@@ -744,7 +724,7 @@ AT_CHECK([ovs-vsctl list interface p1 | sed -n "s/^.*flap_count=\(.*\), forwardi
 # turn bfd on p1 on again, should increment the bfd:flap_count on p0.
 # p1 should still have flap_count = "1", since it is reset.
 AT_CHECK([ovs-vsctl set interface p1 bfd:enable=true])
-for i in `seq 0 10`; do ovs-appctl time/warp 100; done
+for i in `seq 0 49`; do ovs-appctl time/warp 100; done
 BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["3"])
 BFD_VSCTL_LIST_IFACE([p1], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["1"])
 
@@ -756,7 +736,7 @@ OK
 
 # turn bfd on p1 off, should not increment the bfd:flap_count on p0, since forwarding_override is on.
 AT_CHECK([ovs-vsctl set interface p1 bfd:enable=false])
-for i in `seq 0 10`; do ovs-appctl time/warp 100; done
+for i in `seq 0 49`; do ovs-appctl time/warp 100; done
 BFD_CHECK([p0], [true], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
 BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["3"])
 AT_CHECK([ovs-vsctl list interface p1 | sed -n "s/^.*flap_count=\(.*\), forwarding.*$/\1/p"])
@@ -764,7 +744,7 @@ AT_CHECK([ovs-vsctl list interface p1 | sed -n "s/^.*flap_count=\(.*\), forwardi
 # turn bfd on p1 on again, should not increment the bfd:flap_count on p0, since forwarding override is on.
 # p1 should still have flap_count = "1", since it is reset.
 AT_CHECK([ovs-vsctl set interface p1 bfd:enable=true])
-for i in `seq 0 10`; do ovs-appctl time/warp 100; done
+for i in `seq 0 49`; do ovs-appctl time/warp 100; done
 BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["3"])
 BFD_VSCTL_LIST_IFACE([p1], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["1"])
 
@@ -775,9 +755,9 @@ OK
 
 # turn bfd on p1 off and on, should increment the bfd:flap_count on p0.
 AT_CHECK([ovs-vsctl set interface p1 bfd:enable=false])
-for i in `seq 0 10`; do ovs-appctl time/warp 100; done
+for i in `seq 0 49`; do ovs-appctl time/warp 100; done
 AT_CHECK([ovs-vsctl set interface p1 bfd:enable=true])
-for i in `seq 0 10`; do ovs-appctl time/warp 100; done
+for i in `seq 0 49`; do ovs-appctl time/warp 100; done
 BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["5"])
 BFD_VSCTL_LIST_IFACE([p1], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["1"])
 
@@ -824,7 +804,7 @@ BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["8"]
 
 # turn on the bfd on p1.
 AT_CHECK([ovs-vsctl set interface p1 bfd:enable=true])
-for i in `seq 0 10`; do ovs-appctl time/warp 100; done
+for i in `seq 0 49`; do ovs-appctl time/warp 100; done
 # even though there is no data traffic, since p1 bfd is on again, should increment the flap_count.
 BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["9"])
 BFD_VSCTL_LIST_IFACE([p1], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["1"])
index 6e28573..57cdd6c 100644 (file)
@@ -112,6 +112,7 @@ AT_CLEANUP
 m4_foreach(
   [testname],
   [[ctz],
+   [clz],
    [round_up_pow2],
    [round_down_pow2],
    [count_1bits],
index 82e8c3d..2f09c1b 100644 (file)
@@ -469,6 +469,21 @@ tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:0
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPT_PACKET_IN - OF1.1])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+02 0a 00 54 00 00 00 00 00 00 01 11 00 00 00 03 \
+00 00 00 03 00 3c 00 00 \
+50 54 00 00 00 06 50 54 00 00 00 05 08 00 \
+45 00 00 28 bd 12 00 00 40 06 3c 6a c0 a8 00 01 \
+c0 a8 00 02 27 2f 00 00 78 50 cc 5b 57 af 42 1e \
+50 02 02 00 26 e8 00 00 00 00 00 00 00 00 \
+"], [0], [dnl
+OFPT_PACKET_IN (OF1.1) (xid=0x0): total_len=60 in_port=3 (via no_match) data_len=60 buffer=0x00000111
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=10031,tp_dst=0,tcp_flags=0x002 tcp_csum:26e8
+])
+AT_CLEANUP
+
 AT_SETUP([OFPT_PACKET_IN - OF1.2])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print "\
index b78e156..4d8d460 100644 (file)
@@ -252,15 +252,15 @@ table=0 in_port=1 action=dec_ttl,output:2,resubmit(1,1),output:4
 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=1,tos=0,ttl=2,frag=no)' -generate], [0], [stdout])
+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=1,tos=0,ttl=1,frag=no)),2,4
+  [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=1,tos=0,ttl=3,frag=no)'], [0], [stdout])
+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=1,tos=0,ttl=2,frag=no)),2,set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=1,frag=no)),3,4
+  [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],
@@ -269,11 +269,11 @@ AT_CHECK([tail -1 stdout], [0],
 
 AT_CAPTURE_FILE([ofctl_monitor.log])
 AT_CHECK([ovs-ofctl monitor br0 65534 invalid_ttl --detach --no-chdir --pidfile 2> ofctl_monitor.log])
-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=1,tos=0,ttl=2,frag=no)' -generate], [0], [stdout])
+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])
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=42 in_port=1 (via invalid_ttl) data_len=42 (unbuffered)
-icmp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=1,icmp_type=0,icmp_code=0
+NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=34 in_port=1 (via invalid_ttl) data_len=34 (unbuffered)
+ip,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=111,nw_tos=0,nw_ecn=0,nw_ttl=1
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -481,27 +481,27 @@ dnl Modified VLAN controller action.
 AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
 
 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=6,tos=0,ttl=64,frag=no)'
+    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
 
 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)
-tcp,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tcp_flags=0x000 tcp_csum:0
+ip,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
 dnl
 NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-tcp,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tcp_flags=0x000 tcp_csum:0
+ip,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
 dnl
 NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-tcp,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tcp_flags=0x000 tcp_csum:0
+ip,metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
 ])
 
 dnl Modified MPLS controller action.
 AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
 
 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=6,tos=0,ttl=64,frag=no)'
+    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
@@ -521,20 +521,20 @@ dnl Modified MPLS controller action.
 AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
 
 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=6,tos=0,ttl=64,frag=no)'
+    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
 
 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)
-tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tcp_flags=0x000 tcp_csum:0
+ip,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
 dnl
 NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tcp_flags=0x000 tcp_csum:0
+ip,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
 dnl
 NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tcp_flags=0x000 tcp_csum:0
+ip,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
 ])
 
 dnl Modified MPLS controller action.
@@ -562,7 +562,7 @@ dnl Modified MPLS controller action.
 AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
 
 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=6,tos=0,ttl=64,frag=no))'
+    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
@@ -582,7 +582,7 @@ dnl Modified MPLS controller action.
 AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
 
 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=6,tos=0,ttl=64,frag=no)'
+    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
@@ -602,7 +602,7 @@ dnl Modified MPLS controller action.
 AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
 
 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=6,tos=0,ttl=64,frag=no)'
+    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
@@ -622,7 +622,7 @@ dnl Modified MPLS controller action.
 AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
 
 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=6,tos=0,ttl=64,frag=no)'
+    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
@@ -642,7 +642,7 @@ dnl Modified MPLS controller action.
 AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
 
 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=6,tos=0,ttl=64,frag=no)'
+    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
@@ -689,13 +689,13 @@ ovs-appctl -t ovs-ofctl exit
 
 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)
-mplsm,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=64,mpls_bos=1
+mplsm,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=128,mpls_bos=1
 dnl
 NXT_PACKET_IN (xid=0x0): cookie=0xc total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mplsm,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=64,mpls_bos=1
+mplsm,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=128,mpls_bos=1
 dnl
 NXT_PACKET_IN (xid=0x0): cookie=0xc total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mplsm,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=64,mpls_bos=1
+mplsm,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=128,mpls_bos=1
 ])
 
 
@@ -1924,7 +1924,7 @@ HEADER
        pkt_len=64
        stripped=4
        hdr_len=60
-       hdr=50-54-00-00-00-05-50-54-00-00-00-07-86-DD-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
+       hdr=50-54-00-00-00-05-50-54-00-00-00-07-86-DD-67-00-00-00-00-00-0A-80-FE-80-00-00-00-00-00-00-00-00-00-00-00-00-00-01-FE-80-00-00-00-00-00-00-00-00-00-00-00-00-00-02-00-00-00-00-00-00
 ])
 
 AT_CHECK([[sort sflow.log | $EGREP 'IFCOUNTERS|ERROR' | head -6 | sed 's/ /\
@@ -1961,7 +1961,7 @@ IFCOUNTERS
        ifspeed=100000000
        direction=0
        status=0
-       in_octets=98
+       in_octets=138
        in_unicasts=3
        in_multicasts=0
        in_broadcasts=4294967295
@@ -2030,7 +2030,7 @@ IFCOUNTERS
        ifspeed=100000000
        direction=0
        status=0
-       in_octets=98
+       in_octets=138
        in_unicasts=3
        in_multicasts=0
        in_broadcasts=4294967295
index 27b6b34..be7387d 100644 (file)
@@ -1757,6 +1757,39 @@ OFPT_BARRIER_REPLY (OF1.2):
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+dnl This test checks that OFPT_PACKET_OUT accepts both OFPP_NONE (as
+dnl specified by OpenFlow 1.1) and OFPP_CONTROLLER (used by some
+dnl controllers despite the spec) as meaning a packet that was generated
+dnl by the controller.
+AT_SETUP([ofproto - packet-out from controller (OpenFlow 1.1)])
+OVS_VSWITCHD_START
+
+# Start a monitor listening for packet-ins.
+AT_CHECK([ovs-ofctl -O OpenFlow11 monitor br0 --detach --no-chdir --pidfile])
+ovs-appctl -t ovs-ofctl ofctl/send 0209000c0123456700000080
+ovs-appctl -t ovs-ofctl ofctl/barrier
+ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
+AT_CAPTURE_FILE([monitor.log])
+
+# Send some packet-outs with OFPP_NONE and OFPP_CONTROLLER (65533) as in_port.
+AT_CHECK([ovs-ofctl -O OpenFlow11 packet-out br0 none controller '0001020304050010203040501234'])
+AT_CHECK([ovs-ofctl -O OpenFlow11 packet-out br0 4294967293 controller '0001020304050010203040505678'])
+
+# Stop the monitor and check its output.
+ovs-appctl -t ovs-ofctl ofctl/barrier
+ovs-appctl -t ovs-ofctl exit
+
+AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
+OFPT_PACKET_IN (OF1.1): total_len=14 in_port=ANY (via action) data_len=14 (unbuffered)
+metadata=0,in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
+OFPT_PACKET_IN (OF1.1): total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered)
+metadata=0,in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x5678
+OFPT_BARRIER_REPLY (OF1.1):
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 dnl This test checks that metadata is encoded in packet_in structures,
 dnl supported by NXAST.
 AT_SETUP([ofproto - packet-out with metadata (NXM)])
index 3434592..6e6461b 100644 (file)
@@ -2470,23 +2470,27 @@ AT_SETUP([tcp flags - filtering])
 OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 \
                     -- add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2])
 AT_DATA([flows.txt], [dnl
-       in_port=1,tcp,tp_dst=80,tcp_flags=0x02/0x17,action=2  # Allow outbound web traffic bare-SYN
-       in_port=1,tcp,tp_dst=80,tcp_flags=0x10/0x10,action=2  # Allow outbound web traffic with ACK bit
-       in_port=1,tcp,tp_dst=80,tcp_flags=0x04/0x04,action=2  # Allow outbound web traffic with RST bit
-       in_port=2,tcp,tp_src=80,tcp_flags=0x10/0x10,action=1  # Allow inbound web traffic with ACK bit
-       in_port=2,tcp,tp_src=80,tcp_flags=0x04/0x04,action=1  # Allow inbound web traffic with RST bit
+       in_port=1,tcp,tp_dst=80,tcp_flags=+syn-rst-ack-fin,action=2  # Allow outbound web traffic bare-SYN
+       in_port=1,tcp,tp_dst=80,tcp_flags=+ack,action=2  # Allow outbound web traffic with ACK bit
+       in_port=1,tcp,tp_dst=80,tcp_flags=+rst,action=2  # Allow outbound web traffic with RST bit
+       in_port=2,tcp,tp_src=80,tcp_flags=+ack,action=1  # Allow inbound web traffic with ACK bit
+       in_port=2,tcp,tp_src=80,tcp_flags=+rst,action=1  # Allow inbound web traffic with RST bit
        priority=0,in_port=1,action=drop  # Default drop outbound
        priority=0,in_port=2,action=drop  # Default drop inbound
 ])
 
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 
+AT_CHECK([ovs-ofctl add-flow br0 "tcp,tcp_flags=+ack-ack,action="], [1], [],
+  [ovs-ofctl: ack: Each TCP flag can be specified only once
+])
+
 AT_CHECK([ovs-appctl dpif/show | tail -n +5], [0], [dnl
                p1 1/1: (dummy)
                p2 2/2: (dummy)
 ])
 
-dnl Outbound web traffic with base-SYN
+dnl Outbound web traffic with bare-SYN
 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=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=80),tcp_flags(0x002)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
   [Datapath actions: 2
index 7183f46..9152562 100644 (file)
@@ -61,11 +61,11 @@ test_log_2_floor(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 }
 
 static void
-check_ctz(uint32_t x, int n)
+check_ctz32(uint32_t x, int n)
 {
-    if (ctz(x) != n) {
-        fprintf(stderr, "ctz(%"PRIu32") is %d but should be %d\n",
-                x, ctz(x), n);
+    if (ctz32(x) != n) {
+        fprintf(stderr, "ctz32(%"PRIu32") is %d but should be %d\n",
+                x, ctz32(x), n);
         abort();
     }
 }
@@ -87,13 +87,13 @@ test_ctz(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 
     for (n = 0; n < 32; n++) {
         /* Check minimum x such that f(x) == n. */
-        check_ctz(1 << n, n);
+        check_ctz32(1 << n, n);
 
         /* Check maximum x such that f(x) == n. */
-        check_ctz(UINT32_MAX << n, n);
+        check_ctz32(UINT32_MAX << n, n);
 
         /* Check a random value in the middle. */
-        check_ctz((random_uint32() | 1) << n, n);
+        check_ctz32((random_uint32() | 1) << n, n);
     }
 
 
@@ -109,10 +109,62 @@ test_ctz(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
     }
 
     /* Check ctz(0). */
-    check_ctz(0, 32);
+    check_ctz32(0, 32);
     check_ctz64(0, 64);
 }
 
+static void
+check_clz32(uint32_t x, int n)
+{
+    if (clz32(x) != n) {
+        fprintf(stderr, "clz32(%"PRIu32") is %d but should be %d\n",
+                x, clz32(x), n);
+        abort();
+    }
+}
+
+static void
+check_clz64(uint64_t x, int n)
+{
+    if (clz64(x) != n) {
+        fprintf(stderr, "clz64(%"PRIu64") is %d but should be %d\n",
+                x, clz64(x), n);
+        abort();
+    }
+}
+
+static void
+test_clz(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+{
+    int n;
+
+    for (n = 0; n < 32; n++) {
+        /* Check minimum x such that f(x) == n. */
+        check_clz32((1u << 31) >> n, n);
+
+        /* Check maximum x such that f(x) == n. */
+        check_clz32(UINT32_MAX >> n, n);
+
+        /* Check a random value in the middle. */
+        check_clz32((random_uint32() | 1u << 31) >> n, n);
+    }
+
+    for (n = 0; n < 64; n++) {
+        /* Check minimum x such that f(x) == n. */
+        check_clz64((UINT64_C(1) << 63) >> n, n);
+
+        /* Check maximum x such that f(x) == n. */
+        check_clz64(UINT64_MAX >> n, n);
+
+        /* Check a random value in the middle. */
+        check_clz64((random_uint64() | UINT64_C(1) << 63) >> n, n);
+    }
+
+    /* Check clz(0). */
+    check_clz32(0, 32);
+    check_clz64(0, 64);
+}
+
 /* Returns a random number in the range 'min'...'max' inclusive. */
 static uint32_t
 random_in_range(uint32_t min, uint32_t max)
@@ -964,6 +1016,7 @@ test_ovs_scan(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 \f
 static const struct command commands[] = {
     {"ctz", 0, 0, test_ctz},
+    {"clz", 0, 0, test_clz},
     {"round_up_pow2", 0, 0, test_round_up_pow2},
     {"round_down_pow2", 0, 0, test_round_down_pow2},
     {"count_1bits", 0, 0, test_count_1bits},
index 1cf888d..e381b2b 100644 (file)
@@ -148,6 +148,9 @@ expanded as follows:
 .IP \fB%A\fR
 The name of the application logging the message, e.g. \fBovs\-vswitchd\fR.
 .
+.IP \fB%B\fR
+The RFC5424 syslog PRI of the message.
+.
 .IP \fB%c\fR
 The name of the module (as shown by \fBovs\-appctl \-\-list\fR) logging
 the message.
@@ -173,6 +176,9 @@ takes the same format as the \fItemplate\fR argument to
 \fBstrftime\fR(3).  Supports the same extension for sub-second
 resolution as \fB%d{\fR...\fB}\fR.
 .
+.IP \fB%E\fR
+The hostname of the node running the application.
+.
 .IP \fB%m\fR
 The message being logged.
 .
index e5e488a..6f2382b 100644 (file)
@@ -728,33 +728,41 @@ above, the bitwise match forms apply only when \fBdl_type\fR and
 \fBnw_proto\fR specify TCP or UDP or SCTP.
 .
 .IP \fBtcp_flags=\fIflags\fB/\fImask\fR
+.IQ \fBtcp_flags=\fR[\fB+\fIflag\fR...][\fB-\fIflag\fR...]
 Bitwise match on TCP flags.  The \fIflags\fR and \fImask\fR are 16-bit
 numbers written in decimal or in hexadecimal prefixed by \fB0x\fR.
 Each 1-bit in \fImask\fR requires that the corresponding bit in
 \fIflags\fR must match.  Each 0-bit in \fImask\fR causes the corresponding
 bit to be ignored.
 .IP
+Alternatively, the flags can be specified by their symbolic names
+(listed below), each preceded by either \fB+\fR for a flag that must
+be set, or \fB\-\fR for a flag that must be unset, without any other
+delimiters between the flags.  Flags not mentioned are wildcarded.
+For example, \fBtcp,tcp_flags=+syn\-ack\fR matches TCP SYNs that are
+not ACKs.
+.IP
 TCP protocol currently defines 9 flag bits, and additional 3 bits are
 reserved (must be transmitted as zero), see RFCs 793, 3168, and 3540.
 The flag bits are, numbering from the least significant bit:
 .RS
-.IP "\fB0: FIN\fR"
+.IP "\fB0: fin\fR"
 No more data from sender.
-.IP "\fB1: SYN\fR"
+.IP "\fB1: syn\fR"
 Synchronize sequence numbers.
-.IP "\fB2: RST\fR"
+.IP "\fB2: rst\fR"
 Reset the connection.
-.IP "\fB3: PSH\fR"
+.IP "\fB3: psh\fR"
 Push function.
-.IP "\fB4: ACK\fR"
+.IP "\fB4: ack\fR"
 Acknowledgement field significant.
-.IP "\fB5: URG\fR"
+.IP "\fB5: urg\fR"
 Urgent pointer field significant.
-.IP "\fB6: ECE\fR"
+.IP "\fB6: ece\fR"
 ECN Echo.
-.IP "\fB7: CWR\fR"
+.IP "\fB7: cwr\fR"
 Congestion Windows Reduced.
-.IP "\fB8: NS\fR"
+.IP "\fB8: ns\fR"
 Nonce Sum.
 .IP "\fB9-11:\fR"
 Reserved.
index 6ce7d2b..c2307be 100644 (file)
@@ -21,7 +21,6 @@
 #include "async-append.h"
 #include "bfd.h"
 #include "bitmap.h"
-#include "bond.h"
 #include "cfm.h"
 #include "coverage.h"
 #include "daemon.h"
@@ -39,6 +38,7 @@
 #include "ofp-print.h"
 #include "ofp-util.h"
 #include "ofpbuf.h"
+#include "ofproto/bond.h"
 #include "ofproto/ofproto.h"
 #include "poll-loop.h"
 #include "sha1.h"
@@ -3594,10 +3594,9 @@ iface_set_mac(struct iface *iface)
 static void
 iface_set_ofport(const struct ovsrec_interface *if_cfg, ofp_port_t ofport)
 {
-    int64_t port_;
-    port_ = (ofport == OFPP_NONE) ? -1 : ofp_to_u16(ofport);
     if (if_cfg && !ovsdb_idl_row_is_synthetic(&if_cfg->header_)) {
-        ovsrec_interface_set_ofport(if_cfg, &port_, 1);
+        int64_t port = ofport == OFPP_NONE ? -1 : ofp_to_u16(ofport);
+        ovsrec_interface_set_ofport(if_cfg, &port, 1);
     }
 }
 
index 2960b87..1d9cb78 100644 (file)
@@ -59,7 +59,7 @@ VLOG_DEFINE_THIS_MODULE(system_stats);
 static void
 get_cpu_cores(struct smap *stats)
 {
-    long int n_cores = sysconf(_SC_NPROCESSORS_ONLN);
+    long int n_cores = count_cpu_cores();
     if (n_cores > 0) {
         smap_add_format(stats, "cpu", "%ld", n_cores);
     }