Merge "master" into "next".
authorBen Pfaff <blp@nicira.com>
Wed, 24 Feb 2010 21:47:09 +0000 (13:47 -0800)
committerBen Pfaff <blp@nicira.com>
Wed, 24 Feb 2010 21:47:09 +0000 (13:47 -0800)
30 files changed:
ChangeLog
configure.ac
datapath/actions.c
include/openflow/openflow.h
include/openvswitch/datapath-protocol.h
lib/classifier.c
lib/classifier.h
lib/compiler.h
lib/dpif-netdev.c
lib/dpif.h
lib/flow.h
lib/ofp-print.c
lib/ofpbuf.c
lib/ofpbuf.h
lib/packets.h
lib/pcap.c
lib/poll-loop.h
lib/rconn.c
lib/rconn.h
lib/sflow_poller.c
lib/sflow_sampler.c
lib/stp.c
lib/util.h
lib/vconn.c
lib/vconn.h
ofproto/netflow.h
ofproto/ofproto.c
ofproto/ofproto.h
ofproto/pinsched.c
ofproto/pktbuf.c

index 88653d3..1acda09 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+v0.99.2 - 18 Feb 2010
+---------------------
+    - Bug fixes
+
 v0.99.1 - 25 Jan 2010
 ---------------------
     - Add support for sFlow(R)
index 6a8a1ea..ac85450 100644 (file)
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 AC_PREREQ(2.63)
-AC_INIT(openvswitch, 0.99.1, ovs-bugs@openvswitch.org)
+AC_INIT(openvswitch, 0.99.2, ovs-bugs@openvswitch.org)
 NX_BUILDNR
 AC_CONFIG_SRCDIR([datapath/datapath.c])
 AC_CONFIG_MACRO_DIR([m4])
index ab39222..b39d830 100644 (file)
@@ -93,7 +93,7 @@ modify_vlan_tci(struct datapath *dp, struct sk_buff *skb,
                mask = VLAN_VID_MASK;
                key->dl_vlan = htons(tci & mask);
        } else {
-               tci = a->vlan_pcp.vlan_pcp << 13;
+               tci = a->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT;
                mask = VLAN_PCP_MASK;
        }
 
index 27dae8f..b77cd70 100644 (file)
 #define OFP_ASSERT BOOST_STATIC_ASSERT
 #endif /* __cplusplus */
 
-#ifndef SWIG
-#define OFP_PACKED __attribute__((packed))
-#else
-#define OFP_PACKED              /* SWIG doesn't understand __attribute. */
-#endif
-
 /* Version number:
  * Non-experimental versions released: 0x01
  * Experimental versions released: 0x81 -- 0x99
index 84646c2..6c53545 100644 (file)
@@ -107,6 +107,7 @@ struct odp_stats {
 /* Logical ports. */
 #define ODPP_LOCAL      ((__u16)0)
 #define ODPP_NONE       ((__u16)-1)
+#define ODPP_NORMAL     ((__u16)-2)
 
 /* Listening channels. */
 #define _ODPL_MISS_NR   0       /* Packet missed in flow table. */
index 036c372..cdad9c9 100644 (file)
@@ -19,6 +19,7 @@
 #include <assert.h>
 #include <errno.h>
 #include <netinet/in.h>
+#include "dynamic-string.h"
 #include "flow.h"
 #include "hash.h"
 
@@ -77,6 +78,18 @@ cls_rule_from_match(struct cls_rule *rule, const struct ofp_match *match,
     rule->table_idx = table_idx_from_wildcards(rule->wc.wildcards);
 }
 
+/* Converts 'rule' to a string and returns the string.  The caller must free
+ * the string (with free()). */
+char *
+cls_rule_to_string(const struct cls_rule *rule)
+{
+    struct ds s = DS_EMPTY_INITIALIZER;
+    ds_put_format(&s, "wildcards=%x priority=%u ",
+                  rule->wc.wildcards, rule->priority);
+    flow_format(&s, &rule->flow);
+    return ds_cstr(&s);
+}
+
 /* Prints cls_rule 'rule', for debugging.
  *
  * (The output could be improved and expanded, but this was good enough to
index f6cc93b..126d149 100644 (file)
@@ -125,6 +125,7 @@ void cls_rule_from_flow(struct cls_rule *, const flow_t *, uint32_t wildcards,
                         unsigned int priority);
 void cls_rule_from_match(struct cls_rule *, const struct ofp_match *,
                          unsigned int priority);
+char *cls_rule_to_string(const struct cls_rule *);
 void cls_rule_print(const struct cls_rule *);
 void cls_rule_moved(struct classifier *,
                     struct cls_rule *old, struct cls_rule *new);
index 6c0db0f..6bf5144 100644 (file)
 #ifndef COMPILER_H
 #define COMPILER_H 1
 
+#ifdef __GNUC__
 #define NO_RETURN __attribute__((__noreturn__))
 #define OVS_UNUSED __attribute__((__unused__))
-#define PACKED __attribute__((__packed__))
 #define PRINTF_FORMAT(FMT, ARG1) __attribute__((__format__(printf, FMT, ARG1)))
 #define STRFTIME_FORMAT(FMT) __attribute__((__format__(__strftime__, FMT, 0)))
 #define MALLOC_LIKE __attribute__((__malloc__))
 #define ALWAYS_INLINE __attribute__((always_inline))
-#define likely(x) __builtin_expect((x),1)
-#define unlikely(x) __builtin_expect((x),0)
 #define WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
+#else
+#define NO_RETURN
+#define OVS_UNUSED
+#define PRINTF_FORMAT(FMT, ARG1)
+#define STRFTIME_FORMAT(FMT)
+#define MALLOC_LIKE
+#define ALWAYS_INLINE
+#define WARN_UNUSED_RESULT
+#endif
 
 #endif /* compiler.h */
index ca5e8eb..ac0a8ca 100644 (file)
@@ -22,8 +22,8 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
-#include <net/if.h>
 #include <netinet/in.h>
+#include <net/if.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/ioctl.h>
@@ -751,7 +751,7 @@ dpif_netdev_validate_actions(const union odp_action *actions, int n_actions,
 
                case ODPAT_SET_VLAN_PCP:
             *mutates = true;
-                       if (a->vlan_pcp.vlan_pcp & ~VLAN_PCP_MASK) {
+                       if (a->vlan_pcp.vlan_pcp & ~(VLAN_PCP_MASK >> VLAN_PCP_SHIFT)) {
                                return EINVAL;
             }
                        break;
@@ -1290,8 +1290,9 @@ dp_netdev_execute_actions(struct dp_netdev *dp,
             break;
 
                case ODPAT_SET_VLAN_PCP:
-                       dp_netdev_modify_vlan_tci(packet, key, a->vlan_pcp.vlan_pcp << 13,
-                                      VLAN_PCP_MASK);
+                       dp_netdev_modify_vlan_tci(
+                packet, key, a->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT,
+                VLAN_PCP_MASK);
             break;
 
                case ODPAT_STRIP_VLAN:
index b171793..4789284 100644 (file)
 #include <stddef.h>
 #include <stdint.h>
 
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
 struct dpif;
 struct ofpbuf;
 struct svec;
@@ -97,4 +101,8 @@ void dpif_recv_wait(struct dpif *);
 void dpif_get_netflow_ids(const struct dpif *,
                           uint8_t *engine_type, uint8_t *engine_id);
 
+#ifdef  __cplusplus
+}
+#endif
+
 #endif /* dpif.h */
index b1292ce..ca140af 100644 (file)
@@ -16,6 +16,7 @@
 #ifndef FLOW_H
 #define FLOW_H 1
 
+#include <sys/types.h>
 #include <netinet/in.h>
 #include <stdbool.h>
 #include <stdint.h>
index b392d83..683fd98 100644 (file)
 
 #include <config.h>
 #include "ofp-print.h"
-#include "xtoxll.h"
 
 #include <errno.h>
 #include <inttypes.h>
+#include <sys/types.h>
 #include <netinet/in.h>
 #include <sys/wait.h>
 #include <stdarg.h>
@@ -35,6 +35,7 @@
 #include "packets.h"
 #include "pcap.h"
 #include "util.h"
+#include "xtoxll.h"
 
 static void ofp_print_port_name(struct ds *string, uint16_t port);
 
index bb21679..9cb2ceb 100644 (file)
@@ -19,6 +19,7 @@
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
+#include "dynamic-string.h"
 #include "util.h"
 
 /* Initializes 'b' as an empty ofpbuf that contains the 'allocated' bytes of
@@ -103,7 +104,7 @@ ofpbuf_delete(struct ofpbuf *b)
  * commonly, the data in a ofpbuf is at its beginning, and thus the ofpbuf's
  * headroom is 0.) */
 size_t
-ofpbuf_headroom(struct ofpbuf *b) 
+ofpbuf_headroom(const struct ofpbuf *b)
 {
     return (char*)b->data - (char*)b->base;
 }
@@ -111,7 +112,7 @@ ofpbuf_headroom(struct ofpbuf *b)
 /* Returns the number of bytes that may be appended to the tail end of ofpbuf
  * 'b' before the ofpbuf must be reallocated. */
 size_t
-ofpbuf_tailroom(struct ofpbuf *b) 
+ofpbuf_tailroom(const struct ofpbuf *b)
 {
     return (char*)ofpbuf_end(b) - (char*)ofpbuf_tail(b);
 }
@@ -286,3 +287,18 @@ ofpbuf_try_pull(struct ofpbuf *b, size_t size)
 {
     return b->size >= size ? ofpbuf_pull(b, size) : NULL;
 }
+
+/* Returns a string that describes some of 'b''s metadata plus a hex dump of up
+ * to 'maxbytes' from the start of the buffer. */
+char *
+ofpbuf_to_string(const struct ofpbuf *b, size_t maxbytes)
+{
+    struct ds s;
+
+    ds_init(&s);
+    ds_put_format(&s, "size=%zu, allocated=%zu, head=%zu, tail=%zu\n",
+                  b->size, b->allocated,
+                  ofpbuf_headroom(b), ofpbuf_tailroom(b));
+    ds_put_hex_dump(&s, b->data, MIN(b->size, maxbytes), 0, false);
+    return ds_cstr(&s);
+}
index 259e703..9072cc4 100644 (file)
@@ -64,8 +64,8 @@ void ofpbuf_reserve(struct ofpbuf *, size_t);
 void *ofpbuf_push_uninit(struct ofpbuf *b, size_t);
 void *ofpbuf_push(struct ofpbuf *b, const void *, size_t);
 
-size_t ofpbuf_headroom(struct ofpbuf *);
-size_t ofpbuf_tailroom(struct ofpbuf *);
+size_t ofpbuf_headroom(const struct ofpbuf *);
+size_t ofpbuf_tailroom(const struct ofpbuf *);
 void ofpbuf_prealloc_headroom(struct ofpbuf *, size_t);
 void ofpbuf_prealloc_tailroom(struct ofpbuf *, size_t);
 void ofpbuf_trim(struct ofpbuf *);
@@ -74,6 +74,8 @@ void ofpbuf_clear(struct ofpbuf *);
 void *ofpbuf_pull(struct ofpbuf *, size_t);
 void *ofpbuf_try_pull(struct ofpbuf *, size_t);
 
+char *ofpbuf_to_string(const struct ofpbuf *, size_t maxbytes);
+
 #ifdef  __cplusplus
 }
 #endif
index 7651495..7ea462b 100644 (file)
@@ -190,7 +190,10 @@ struct llc_snap_header {
 BUILD_ASSERT_DECL(LLC_SNAP_HEADER_LEN == sizeof(struct llc_snap_header));
 
 #define VLAN_VID_MASK 0x0fff
+#define VLAN_VID_SHIFT 0
+
 #define VLAN_PCP_MASK 0xe000
+#define VLAN_PCP_SHIFT 13
 
 #define VLAN_HEADER_LEN 4
 struct vlan_header {
index 967bb5c..028dd0c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009 Nicira Networks.
+ * Copyright (c) 2009, 2010 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -34,14 +34,16 @@ struct pcap_hdr {
     uint32_t sigfigs;        /* accuracy of timestamps */
     uint32_t snaplen;        /* max length of captured packets */
     uint32_t network;        /* data link type */
-} PACKED;
+};
+BUILD_ASSERT_DECL(sizeof(struct pcap_hdr) == 24);
 
 struct pcaprec_hdr {
     uint32_t ts_sec;         /* timestamp seconds */
     uint32_t ts_usec;        /* timestamp microseconds */
     uint32_t incl_len;       /* number of octets of packet saved in file */
     uint32_t orig_len;       /* actual length of packet */
-} PACKED;
+};
+BUILD_ASSERT_DECL(sizeof(struct pcaprec_hdr) == 16);
 
 FILE *
 pcap_open(const char *file_name, const char *mode)
index 89c8e57..adb88d4 100644 (file)
 
 #include <poll.h>
 
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
 struct poll_waiter;
 
 /* Schedule events to wake up the following poll_block(). */
@@ -47,4 +51,8 @@ void poll_block(void);
 /* Cancel a file descriptor callback or event. */
 void poll_cancel(struct poll_waiter *);
 
+#ifdef  __cplusplus
+}
+#endif
+
 #endif /* poll-loop.h */
index 6bd4394..ea45134 100644 (file)
@@ -76,6 +76,7 @@ struct rconn {
     time_t last_connected;
     unsigned int packets_sent;
     unsigned int seqno;
+    int last_error;
 
     /* In S_ACTIVE and S_IDLE, probably_admitted reports whether we believe
      * that the peer has made a (positive) admission control decision on our
@@ -136,6 +137,7 @@ static void state_transition(struct rconn *, enum state);
 static void set_vconn_name(struct rconn *, const char *name);
 static int try_send(struct rconn *);
 static int reconnect(struct rconn *);
+static void report_error(struct rconn *, int error);
 static void disconnect(struct rconn *, int error);
 static void flush_queue(struct rconn *);
 static void question_connectivity(struct rconn *);
@@ -272,6 +274,7 @@ void
 rconn_reconnect(struct rconn *rc)
 {
     if (rc->state & (S_ACTIVE | S_IDLE)) {
+        VLOG_INFO("%s: disconnecting", rc->name);
         disconnect(rc, 0);
     }
 }
@@ -341,7 +344,7 @@ reconnect(struct rconn *rc)
     } else {
         VLOG_WARN("%s: connection failed (%s)", rc->name, strerror(retval));
         rc->backoff_deadline = TIME_MAX; /* Prevent resetting backoff. */
-        disconnect(rc, 0);
+        disconnect(rc, retval);
     }
     return retval;
 }
@@ -381,7 +384,7 @@ run_CONNECTING(struct rconn *rc)
     } else if (timed_out(rc)) {
         VLOG_INFO("%s: connection timed out", rc->name);
         rc->backoff_deadline = TIME_MAX; /* Prevent resetting backoff. */
-        disconnect(rc, 0);
+        disconnect(rc, ETIMEDOUT);
     }
 }
 
@@ -446,7 +449,7 @@ run_IDLE(struct rconn *rc)
         VLOG_ERR("%s: no response to inactivity probe after %u "
                  "seconds, disconnecting",
                  rc->name, elapsed_in_this_state(rc));
-        disconnect(rc, 0);
+        disconnect(rc, ETIMEDOUT);
     } else {
         do_tx_work(rc);
     }
@@ -530,6 +533,7 @@ rconn_recv(struct rconn *rc)
             }
             return buffer;
         } else if (error != EAGAIN) {
+            report_error(rc, error);
             disconnect(rc, error);
         }
     }
@@ -808,6 +812,22 @@ rconn_get_connection_seqno(const struct rconn *rc)
 {
     return rc->seqno;
 }
+
+/* Returns a value that explains why 'rc' last disconnected:
+ *
+ *   - 0 means that the last disconnection was caused by a call to
+ *     rconn_disconnect(), or that 'rc' is new and has not yet completed its
+ *     initial connection or connection attempt.
+ *
+ *   - EOF means that the connection was closed in the normal way by the peer.
+ *
+ *   - A positive integer is an errno value that represents the error.
+ */
+int
+rconn_get_last_error(const struct rconn *rc)
+{
+    return rc->last_error;
+}
 \f
 struct rconn_packet_counter *
 rconn_packet_counter_create(void)
@@ -868,6 +888,7 @@ try_send(struct rconn *rc)
     retval = vconn_send(rc->vconn, rc->txq.head);
     if (retval) {
         if (retval != EAGAIN) {
+            report_error(rc, retval);
             disconnect(rc, retval);
         }
         return retval;
@@ -881,26 +902,41 @@ try_send(struct rconn *rc)
     return 0;
 }
 
-/* Disconnects 'rc'.  'error' is used only for logging purposes.  If it is
- * nonzero, then it should be EOF to indicate the connection was closed by the
- * peer in a normal fashion or a positive errno value. */
+/* Reports that 'error' caused 'rc' to disconnect.  'error' may be a positive
+ * errno value, or it may be EOF to indicate that the connection was closed
+ * normally. */
+static void
+report_error(struct rconn *rc, int error)
+{
+    if (error == EOF) {
+        /* If 'rc' isn't reliable, then we don't really expect this connection
+         * to last forever anyway (probably it's a connection that we received
+         * via accept()), so use DBG level to avoid cluttering the logs. */
+        enum vlog_level level = rc->reliable ? VLL_INFO : VLL_DBG;
+        VLOG(level, "%s: connection closed by peer", rc->name);
+    } else {
+        VLOG_WARN("%s: connection dropped (%s)", rc->name, strerror(error));
+    }
+}
+
+/* Disconnects 'rc' and records 'error' as the error that caused 'rc''s last
+ * disconnection:
+ *
+ *   - 0 means that this disconnection is due to a request by 'rc''s client,
+ *     not due to any kind of network error.
+ *
+ *   - EOF means that the connection was closed in the normal way by the peer.
+ *
+ *   - A positive integer is an errno value that represents the error.
+ */
 static void
 disconnect(struct rconn *rc, int error)
 {
+    rc->last_error = error;
     if (rc->reliable) {
         time_t now = time_now();
 
         if (rc->state & (S_CONNECTING | S_ACTIVE | S_IDLE)) {
-            if (error > 0) {
-                VLOG_WARN("%s: connection dropped (%s)",
-                          rc->name, strerror(error));
-            } else if (error == EOF) {
-                if (rc->reliable) {
-                    VLOG_INFO("%s: connection closed by peer", rc->name);
-                }
-            } else {
-                VLOG_INFO("%s: connection dropped", rc->name);
-            }
             vconn_close(rc->vconn);
             rc->vconn = NULL;
             flush_queue(rc);
index ef4e16c..765e88c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -88,6 +88,7 @@ unsigned long int rconn_get_total_time_connected(const struct rconn *);
 int rconn_get_backoff(const struct rconn *);
 unsigned int rconn_get_state_elapsed(const struct rconn *);
 unsigned int rconn_get_connection_seqno(const struct rconn *);
+int rconn_get_last_error(const struct rconn *);
 
 /* Counts the number of packets queued into an rconn by a given source. */
 struct rconn_packet_counter {
index ffd09d3..e7dc2b1 100644 (file)
@@ -68,10 +68,29 @@ u_int32_t sfl_poller_get_sFlowCpInterval(SFLPoller *poller) {
 
 void sfl_poller_set_sFlowCpInterval(SFLPoller *poller, u_int32_t sFlowCpInterval) {
     poller->sFlowCpInterval = sFlowCpInterval;
-    /* Set the countersCountdown to be a randomly selected value between 1 and
-       sFlowCpInterval. That way the counter polling would be desynchronised
-       (on a 200-port switch, polling all the counters in one second could be harmful). */
-    poller->countersCountdown = 1 + (random() % sFlowCpInterval);
+    if(sFlowCpInterval) {
+        /* Set the countersCountdown to be a randomly selected value between 1 and
+          sFlowCpInterval. That way the counter polling will be desynchronised
+          (on a 200-port switch, polling all the counters in one second could be harmful).
+          In a large network, even this might not be ideal if time-synchroniziation
+          between devices is close and counters are always polled on second boundaries. If
+          1000 different devices all send an sFlow datagram on the same second boundary
+          it could result in an antisocial burst.
+          However when counter-samples are packed into the export datagram they do not
+          always result in that datagram being sent immediately. It is more likely that
+          a subsequent packet-sample will be the one that triggers the datagram to be sent.
+          The packet-sample events are not sychronized to any clock, so that results in
+          excellent desynchronization (http://blog.sflow.com/2009/05/measurement-traffic.html).
+          Another smoothing factor is that the tick() function called here is usually
+          driven from a fairly "soft" polling loop rather than a hard real-time event.
+       */
+        poller->countersCountdown = 1 + (random() % sFlowCpInterval);
+    }
+    else {
+        /* Setting sFlowCpInterval to 0 disables counter polling altogether.  Thanks to
+          Andy Kitchingman for spotting this ommission. */
+        poller->countersCountdown = 0;
+    }
 }
 
 /*_________________---------------------------------__________________
index 759b5a2..c2b4556 100644 (file)
@@ -16,14 +16,17 @@ void sfl_sampler_init(SFLSampler *sampler, SFLAgent *agent, SFLDataSource_instan
     SFLDataSource_instance dsi = *pdsi;
 
     /* preserve the *nxt pointer too, in case we are resetting this poller and it is
-       already part of the agent's linked list (thanks to Matt Woodly for pointing this out) */
+       already part of the agent's linked list (thanks to Matt Woodly for pointing this out,
+       and to Andy Kitchingman for pointing out that it applies to the hash_nxt ptr too) */
     SFLSampler *nxtPtr = sampler->nxt;
+    SFLSampler *hashPtr = sampler->hash_nxt;
   
     /* clear everything */
     memset(sampler, 0, sizeof(*sampler));
   
-    /* restore the linked list ptr */
+    /* restore the linked list and hash-table ptr */
     sampler->nxt = nxtPtr;
+    sampler->hash_nxt = hashPtr;
   
     /* now copy in the parameters */
     sampler->agent = agent;
index 6fad3a0..38885c0 100644 (file)
--- a/lib/stp.c
+++ b/lib/stp.c
@@ -18,6 +18,8 @@
  * applies to all modifications. */
 
 #include "stp.h"
+#include <sys/types.h>
+#include <netinet/in.h>
 #include <arpa/inet.h>
 #include <assert.h>
 #include <inttypes.h>
index 562f7e0..a9d5048 100644 (file)
@@ -76,8 +76,6 @@ extern const char *program_name;
 #endif
 
 #define NOT_REACHED() abort()
-#define NOT_IMPLEMENTED() abort()
-#define NOT_TESTED() ((void) 0) /* XXX should print a message. */
 
 /* Given POINTER, the address of the given MEMBER in a STRUCT object, returns
    the STRUCT object. */
index f8d3beb..d8807fd 100644 (file)
@@ -164,6 +164,42 @@ vconn_usage(bool active, bool passive, bool bootstrap OVS_UNUSED)
 #endif
 }
 
+/* Given 'name', a connection name in the form "TYPE:ARGS", stores the class
+ * named "TYPE" into '*classp' and returns 0.  Returns EAFNOSUPPORT and stores
+ * a null pointer into '*classp' if 'name' is in the wrong form or if no such
+ * class exists. */
+static int
+vconn_lookup_class(const char *name, struct vconn_class **classp)
+{
+    size_t prefix_len;
+
+    prefix_len = strcspn(name, ":");
+    if (name[prefix_len] != '\0') {
+        size_t i;
+
+        for (i = 0; i < ARRAY_SIZE(vconn_classes); i++) {
+            struct vconn_class *class = vconn_classes[i];
+            if (strlen(class->name) == prefix_len
+                && !memcmp(class->name, name, prefix_len)) {
+                *classp = class;
+                return 0;
+            }
+        }
+    }
+
+    *classp = NULL;
+    return EAFNOSUPPORT;
+}
+
+/* Returns 0 if 'name' is a connection name in the form "TYPE:ARGS" and TYPE is
+ * a supported connection type, otherwise EAFNOSUPPORT.  */
+int
+vconn_verify_name(const char *name)
+{
+    struct vconn_class *class;
+    return vconn_lookup_class(name, &class);
+}
+
 /* Attempts to connect to an OpenFlow device.  'name' is a connection name in
  * the form "TYPE:ARGS", where TYPE is an active vconn class's name and ARGS
  * are vconn class-specific.
@@ -178,35 +214,37 @@ vconn_usage(bool active, bool passive, bool bootstrap OVS_UNUSED)
 int
 vconn_open(const char *name, int min_version, struct vconn **vconnp)
 {
-    size_t prefix_len;
-    size_t i;
+    struct vconn_class *class;
+    struct vconn *vconn;
+    char *suffix_copy;
+    int error;
 
     COVERAGE_INC(vconn_open);
     check_vconn_classes();
 
-    *vconnp = NULL;
-    prefix_len = strcspn(name, ":");
-    if (prefix_len == strlen(name)) {
-        return EAFNOSUPPORT;
+    /* Look up the class. */
+    error = vconn_lookup_class(name, &class);
+    if (!class) {
+        goto error;
     }
-    for (i = 0; i < ARRAY_SIZE(vconn_classes); i++) {
-        struct vconn_class *class = vconn_classes[i];
-        if (strlen(class->name) == prefix_len
-            && !memcmp(class->name, name, prefix_len)) {
-            struct vconn *vconn;
-            char *suffix_copy = xstrdup(name + prefix_len + 1);
-            int retval = class->open(name, suffix_copy, &vconn);
-            free(suffix_copy);
-            if (!retval) {
-                assert(vconn->state != VCS_CONNECTING
-                       || vconn->class->connect);
-                vconn->min_version = min_version;
-                *vconnp = vconn;
-            }
-            return retval;
-        }
+
+    /* Call class's "open" function. */
+    suffix_copy = xstrdup(strchr(name, ':') + 1);
+    error = class->open(name, suffix_copy, &vconn);
+    free(suffix_copy);
+    if (error) {
+        goto error;
     }
-    return EAFNOSUPPORT;
+
+    /* Success. */
+    assert(vconn->state != VCS_CONNECTING || vconn->class->connect);
+    vconn->min_version = min_version;
+    *vconnp = vconn;
+    return 0;
+
+error:
+    *vconnp = NULL;
+    return error;
 }
 
 /* Allows 'vconn' to perform maintenance activities, such as flushing output
@@ -691,6 +729,42 @@ vconn_send_wait(struct vconn *vconn)
     vconn_wait(vconn, WAIT_SEND);
 }
 
+/* Given 'name', a connection name in the form "TYPE:ARGS", stores the class
+ * named "TYPE" into '*classp' and returns 0.  Returns EAFNOSUPPORT and stores
+ * a null pointer into '*classp' if 'name' is in the wrong form or if no such
+ * class exists. */
+static int
+pvconn_lookup_class(const char *name, struct pvconn_class **classp)
+{
+    size_t prefix_len;
+
+    prefix_len = strcspn(name, ":");
+    if (name[prefix_len] != '\0') {
+        size_t i;
+
+        for (i = 0; i < ARRAY_SIZE(pvconn_classes); i++) {
+            struct pvconn_class *class = pvconn_classes[i];
+            if (strlen(class->name) == prefix_len
+                && !memcmp(class->name, name, prefix_len)) {
+                *classp = class;
+                return 0;
+            }
+        }
+    }
+
+    *classp = NULL;
+    return EAFNOSUPPORT;
+}
+
+/* Returns 0 if 'name' is a connection name in the form "TYPE:ARGS" and TYPE is
+ * a supported connection type, otherwise EAFNOSUPPORT.  */
+int
+pvconn_verify_name(const char *name)
+{
+    struct pvconn_class *class;
+    return pvconn_lookup_class(name, &class);
+}
+
 /* Attempts to start listening for OpenFlow connections.  'name' is a
  * connection name in the form "TYPE:ARGS", where TYPE is an passive vconn
  * class's name and ARGS are vconn class-specific.
@@ -701,30 +775,34 @@ vconn_send_wait(struct vconn *vconn)
 int
 pvconn_open(const char *name, struct pvconn **pvconnp)
 {
-    size_t prefix_len;
-    size_t i;
+    struct pvconn_class *class;
+    struct pvconn *pvconn;
+    char *suffix_copy;
+    int error;
 
     check_vconn_classes();
 
-    *pvconnp = NULL;
-    prefix_len = strcspn(name, ":");
-    if (prefix_len == strlen(name)) {
-        return EAFNOSUPPORT;
+    /* Look up the class. */
+    error = pvconn_lookup_class(name, &class);
+    if (!class) {
+        goto error;
     }
-    for (i = 0; i < ARRAY_SIZE(pvconn_classes); i++) {
-        struct pvconn_class *class = pvconn_classes[i];
-        if (strlen(class->name) == prefix_len
-            && !memcmp(class->name, name, prefix_len)) {
-            char *suffix_copy = xstrdup(name + prefix_len + 1);
-            int retval = class->listen(name, suffix_copy, pvconnp);
-            free(suffix_copy);
-            if (retval) {
-                *pvconnp = NULL;
-            }
-            return retval;
-        }
+
+    /* Call class's "open" function. */
+    suffix_copy = xstrdup(strchr(name, ':') + 1);
+    error = class->listen(name, suffix_copy, &pvconn);
+    free(suffix_copy);
+    if (error) {
+        goto error;
     }
-    return EAFNOSUPPORT;
+
+    /* Success. */
+    *pvconnp = pvconn;
+    return 0;
+
+error:
+    *pvconnp = NULL;
+    return error;
 }
 
 /* Returns the name that was used to open 'pvconn'.  The caller must not
@@ -1285,10 +1363,7 @@ check_action(const union ofp_action *a, unsigned int len, int max_ports)
     switch (ntohs(a->type)) {
     case OFPAT_OUTPUT:
         error = check_action_port(ntohs(a->output.port), max_ports);
-        if (error) {
-            return error;
-        }
-        return check_action_exact_len(a, len, 8);
+        return error ? error : check_action_exact_len(a, len, 8);
 
     case OFPAT_SET_VLAN_VID:
     case OFPAT_SET_VLAN_PCP:
@@ -1305,29 +1380,15 @@ check_action(const union ofp_action *a, unsigned int len, int max_ports)
         return check_action_exact_len(a, len, 16);
 
     case OFPAT_VENDOR:
-        if (a->vendor.vendor == htonl(NX_VENDOR_ID)) {
-            return check_nicira_action(a, len);
-        } else {
-            return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR);
-        }
-        break;
+        return (a->vendor.vendor == htonl(NX_VENDOR_ID)
+                ? check_nicira_action(a, len)
+                : ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR));
 
     default:
         VLOG_WARN_RL(&bad_ofmsg_rl, "unknown action type %"PRIu16,
                 ntohs(a->type));
         return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE);
     }
-
-    if (!len) {
-        VLOG_DBG_RL(&bad_ofmsg_rl, "action has invalid length 0");
-        return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
-    }
-    if (len % ACTION_ALIGNMENT) {
-        VLOG_DBG_RL(&bad_ofmsg_rl, "action length %u is not a multiple of %d",
-                    len, ACTION_ALIGNMENT);
-        return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
-    }
-    return 0;
 }
 
 int
@@ -1347,7 +1408,15 @@ validate_actions(const union ofp_action *actions, size_t n_actions,
                         "action requires %u slots but only %u remain",
                         n_slots, slots_left);
             return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
+        } else if (!len) {
+            VLOG_DBG_RL(&bad_ofmsg_rl, "action has invalid length 0");
+            return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
+        } else if (len % ACTION_ALIGNMENT) {
+            VLOG_DBG_RL(&bad_ofmsg_rl, "action length %u is not a multiple "
+                        "of %d", len, ACTION_ALIGNMENT);
+            return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
         }
+
         error = check_action(a, len, max_ports);
         if (error) {
             return error;
index 9bd235a..1426c1d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -35,6 +35,7 @@ struct vconn;
 void vconn_usage(bool active, bool passive, bool bootstrap);
 
 /* Active vconns: virtual connections to OpenFlow devices. */
+int vconn_verify_name(const char *name);
 int vconn_open(const char *name, int min_version, struct vconn **);
 void vconn_close(struct vconn *);
 const char *vconn_get_name(const struct vconn *);
@@ -66,6 +67,7 @@ void vconn_recv_wait(struct vconn *);
 void vconn_send_wait(struct vconn *);
 
 /* Passive vconns: virtual listeners for incoming OpenFlow connections. */
+int pvconn_verify_name(const char *name);
 int pvconn_open(const char *name, struct pvconn **);
 const char *pvconn_get_name(const struct pvconn *);
 void pvconn_close(struct pvconn *);
index 7f48ddd..701ffd4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
 #ifndef NETFLOW_H
 #define NETFLOW_H 1
 
+#include <stdint.h>
 #include "flow.h"
 #include "svec.h"
 
index 0e42214..189aa2c 100644 (file)
@@ -760,6 +760,8 @@ ofproto_destroy(struct ofproto *p)
     free(p->serial_desc);
     free(p->dp_desc);
 
+    port_array_destroy(&p->ports);
+
     free(p);
 }
 
index e735cc6..d9e71d7 100644 (file)
 #include "netflow.h"
 #include "tag.h"
 
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
 struct odp_actions;
 struct ofhooks;
 struct ofproto;
@@ -127,4 +131,8 @@ struct ofhooks {
 void ofproto_revalidate(struct ofproto *, tag_type);
 struct tag_set *ofproto_get_revalidate_set(struct ofproto *);
 
+#ifdef  __cplusplus
+}
+#endif
+
 #endif /* ofproto.h */
index a4f5bfa..b9c6371 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 #include <config.h>
 #include "pinsched.h"
+#include <sys/types.h>
+#include <netinet/in.h>
 #include <arpa/inet.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include "ofpbuf.h"
 #include "openflow/openflow.h"
index 495a1ee..c103c7f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -151,9 +151,9 @@ pktbuf_get_null(void)
  * datapath port number on which the packet was received in '*in_port'.  The
  * caller becomes responsible for freeing the buffer.  However, if 'id'
  * identifies a "null" packet buffer (created with pktbuf_get_null()), stores
- * NULL in '*bufferp' and -1 in '*in_port'.
+ * NULL in '*bufferp' and UINT16_max in '*in_port'.
  *
- * On failure, stores NULL in in '*bufferp' and -1 in '*in_port'. */
+ * On failure, stores NULL in in '*bufferp' and UINT16_MAX in '*in_port'. */
 int
 pktbuf_retrieve(struct pktbuf *pb, uint32_t id, struct ofpbuf **bufferp,
                 uint16_t *in_port)
@@ -194,7 +194,7 @@ pktbuf_retrieve(struct pktbuf *pb, uint32_t id, struct ofpbuf **bufferp,
         error = 0;
     }
     *bufferp = NULL;
-    *in_port = -1;
+    *in_port = UINT16_MAX;
     return error;
 }