+v0.99.2 - 18 Feb 2010
+---------------------
+ - Bug fixes
+
v0.99.1 - 25 Jan 2010
---------------------
- Add support for sFlow(R)
# 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])
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;
}
#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
/* 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. */
#include <assert.h>
#include <errno.h>
#include <netinet/in.h>
+#include "dynamic-string.h"
#include "flow.h"
#include "hash.h"
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
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);
#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 */
#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>
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;
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:
#include <stddef.h>
#include <stdint.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct dpif;
struct ofpbuf;
struct svec;
void dpif_get_netflow_ids(const struct dpif *,
uint8_t *engine_type, uint8_t *engine_id);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* dpif.h */
#ifndef FLOW_H
#define FLOW_H 1
+#include <sys/types.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <stdint.h>
#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>
#include "packets.h"
#include "pcap.h"
#include "util.h"
+#include "xtoxll.h"
static void ofp_print_port_name(struct ds *string, uint16_t port);
#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
* 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;
}
/* 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);
}
{
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);
+}
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 *);
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
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 {
/*
- * 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.
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)
#include <poll.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct poll_waiter;
/* Schedule events to wake up the following poll_block(). */
/* Cancel a file descriptor callback or event. */
void poll_cancel(struct poll_waiter *);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* poll-loop.h */
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
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 *);
rconn_reconnect(struct rconn *rc)
{
if (rc->state & (S_ACTIVE | S_IDLE)) {
+ VLOG_INFO("%s: disconnecting", rc->name);
disconnect(rc, 0);
}
}
} 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;
}
} 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);
}
}
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);
}
}
return buffer;
} else if (error != EAGAIN) {
+ report_error(rc, error);
disconnect(rc, error);
}
}
{
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)
retval = vconn_send(rc->vconn, rc->txq.head);
if (retval) {
if (retval != EAGAIN) {
+ report_error(rc, retval);
disconnect(rc, retval);
}
return retval;
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);
/*
- * 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.
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 {
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;
+ }
}
/*_________________---------------------------------__________________
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;
* 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>
#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. */
#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.
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
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.
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
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:
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
"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;
/*
- * 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.
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 *);
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 *);
/*
- * 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.
#ifndef NETFLOW_H
#define NETFLOW_H 1
+#include <stdint.h>
#include "flow.h"
#include "svec.h"
free(p->serial_desc);
free(p->dp_desc);
+ port_array_destroy(&p->ports);
+
free(p);
}
#include "netflow.h"
#include "tag.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct odp_actions;
struct ofhooks;
struct ofproto;
void ofproto_revalidate(struct ofproto *, tag_type);
struct tag_set *ofproto_get_revalidate_set(struct ofproto *);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* ofproto.h */
/*
- * 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"
/*
- * 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.
* 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)
error = 0;
}
*bufferp = NULL;
- *in_port = -1;
+ *in_port = UINT16_MAX;
return error;
}