#include <poll.h>
#include <stdlib.h>
#include <string.h>
-#include "buffer.h"
#include "dynamic-string.h"
#include "flow.h"
#include "ofp-print.h"
-#include "openflow.h"
+#include "ofpbuf.h"
+#include "openflow/openflow.h"
#include "poll-loop.h"
#include "random.h"
#include "util.h"
* really need to see them. */
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(600, 600);
-static int do_recv(struct vconn *, struct buffer **);
-static int do_send(struct vconn *, struct buffer *);
+static int do_recv(struct vconn *, struct ofpbuf **);
+static int do_send(struct vconn *, struct ofpbuf *);
/* Check the validity of the vconn class structures. */
static void
}
/* Prints information on active (if 'active') and passive (if 'passive')
- * connection methods supported by the vconn. */
+ * connection methods supported by the vconn. If 'bootstrap' is true, also
+ * advertises options to bootstrap the CA certificate. */
void
-vconn_usage(bool active, bool passive)
+vconn_usage(bool active, bool passive, bool bootstrap UNUSED)
{
/* Really this should be implemented via callbacks into the vconn
* providers, but that seems too heavy-weight to bother with at the
" -p, --private-key=FILE file with private key\n"
" -c, --certificate=FILE file with certificate for private key\n"
" -C, --ca-cert=FILE file with peer CA certificate\n");
+ if (bootstrap) {
+ printf(" --bootstrap-ca-cert=FILE file with peer CA certificate "
+ "to read or create\n");
+ }
#endif
}
static void
vcs_send_hello(struct vconn *vconn)
{
- struct buffer *b;
+ struct ofpbuf *b;
int retval;
make_openflow(sizeof(struct ofp_header), OFPT_HELLO, &b);
if (!retval) {
vconn->state = VCS_RECV_HELLO;
} else {
- buffer_delete(b);
+ ofpbuf_delete(b);
if (retval != EAGAIN) {
vconn->state = VCS_DISCONNECTED;
vconn->error = retval;
static void
vcs_recv_hello(struct vconn *vconn)
{
- struct buffer *b;
+ struct ofpbuf *b;
int retval;
retval = do_recv(vconn, &b);
struct ds msg = DS_EMPTY_INITIALIZER;
ds_put_format(&msg, "%s: extra-long hello:\n", vconn->name);
ds_put_hex_dump(&msg, b->data, b->size, 0, true);
- VLOG_WARN_RL(&rl, ds_cstr(&msg));
+ VLOG_WARN_RL(&rl, "%s", ds_cstr(&msg));
ds_destroy(&msg);
}
OFP_VERSION, oh->version);
vconn->state = VCS_CONNECTED;
}
- buffer_delete(b);
+ ofpbuf_delete(b);
return;
} else {
char *s = ofp_to_string(b->data, b->size, 1);
vconn->name, s);
free(s);
retval = EPROTO;
- buffer_delete(b);
+ ofpbuf_delete(b);
}
}
vcs_send_error(struct vconn *vconn)
{
struct ofp_error_msg *error;
- struct buffer *b;
+ struct ofpbuf *b;
char s[128];
int retval;
error = make_openflow(sizeof *error, OFPT_ERROR, &b);
error->type = htons(OFPET_HELLO_FAILED);
error->code = htons(OFPHFC_INCOMPATIBLE);
- buffer_put(b, s, strlen(s));
+ ofpbuf_put(b, s, strlen(s));
+ update_openflow_length(b);
retval = do_send(vconn, b);
if (retval) {
- buffer_delete(b);
+ ofpbuf_delete(b);
}
if (retval != EAGAIN) {
vconn->state = VCS_DISCONNECTED;
/* Tries to receive an OpenFlow message from 'vconn', which must be an active
* vconn. If successful, stores the received message into '*msgp' and returns
* 0. The caller is responsible for destroying the message with
- * buffer_delete(). On failure, returns a positive errno value and stores a
+ * ofpbuf_delete(). On failure, returns a positive errno value and stores a
* null pointer into '*msgp'. On normal connection close, returns EOF.
*
* vconn_recv will not block waiting for a packet to arrive. If no packets
* have been received, it returns EAGAIN immediately. */
int
-vconn_recv(struct vconn *vconn, struct buffer **msgp)
+vconn_recv(struct vconn *vconn, struct ofpbuf **msgp)
{
int retval = vconn_connect(vconn);
if (!retval) {
}
static int
-do_recv(struct vconn *vconn, struct buffer **msgp)
+do_recv(struct vconn *vconn, struct ofpbuf **msgp)
{
int retval;
free(s);
}
- oh = buffer_at_assert(*msgp, 0, sizeof *oh);
+ oh = ofpbuf_at_assert(*msgp, 0, sizeof *oh);
if (oh->version != vconn->version
&& oh->type != OFPT_HELLO
&& oh->type != OFPT_ERROR
&& oh->type != OFPT_VENDOR)
{
if (vconn->version < 0) {
- VLOG_ERR_RL(&rl, "%s: received OpenFlow version %02"PRIx8" "
+ VLOG_ERR_RL(&rl, "%s: received OpenFlow message type %"PRIu8" "
"before version negotiation complete",
- vconn->name, oh->version);
+ vconn->name, oh->type);
} else {
- VLOG_ERR_RL(&rl, "%s: received OpenFlow version %02"PRIx8" "
+ VLOG_ERR_RL(&rl, "%s: received OpenFlow version 0x%02"PRIx8" "
"!= expected %02x",
vconn->name, oh->version, vconn->version);
}
- buffer_delete(*msgp);
+ ofpbuf_delete(*msgp);
retval = EPROTO;
}
}
* vconn_send will not block. If 'msg' cannot be immediately accepted for
* transmission, it returns EAGAIN immediately. */
int
-vconn_send(struct vconn *vconn, struct buffer *msg)
+vconn_send(struct vconn *vconn, struct ofpbuf *msg)
{
int retval = vconn_connect(vconn);
if (!retval) {
}
static int
-do_send(struct vconn *vconn, struct buffer *msg)
+do_send(struct vconn *vconn, struct ofpbuf *msg)
{
int retval;
/* Same as vconn_send, except that it waits until 'msg' can be transmitted. */
int
-vconn_send_block(struct vconn *vconn, struct buffer *msg)
+vconn_send_block(struct vconn *vconn, struct ofpbuf *msg)
{
int retval;
while ((retval = vconn_send(vconn, msg)) == EAGAIN) {
/* Same as vconn_recv, except that it waits until a message is received. */
int
-vconn_recv_block(struct vconn *vconn, struct buffer **msgp)
+vconn_recv_block(struct vconn *vconn, struct ofpbuf **msgp)
{
int retval;
while ((retval = vconn_recv(vconn, msgp)) == EAGAIN) {
return retval;
}
-/* Sends 'request' to 'vconn' and blocks until it receives a reply with a
- * matching transaction ID. Returns 0 if successful, in which case the reply
- * is stored in '*replyp' for the caller to examine and free. Otherwise
- * returns a positive errno value, or EOF, and sets '*replyp' to null.
+/* Waits until a message with a transaction ID matching 'xid' is recived on
+ * 'vconn'. Returns 0 if successful, in which case the reply is stored in
+ * '*replyp' for the caller to examine and free. Otherwise returns a positive
+ * errno value, or EOF, and sets '*replyp' to null.
*
* 'request' is always destroyed, regardless of the return value. */
int
-vconn_transact(struct vconn *vconn, struct buffer *request,
- struct buffer **replyp)
+vconn_recv_xid(struct vconn *vconn, uint32_t xid, struct ofpbuf **replyp)
{
- uint32_t send_xid = ((struct ofp_header *) request->data)->xid;
- int error;
-
- *replyp = NULL;
- error = vconn_send_block(vconn, request);
- if (error) {
- buffer_delete(request);
- return error;
- }
for (;;) {
uint32_t recv_xid;
- struct buffer *reply;
+ struct ofpbuf *reply;
+ int error;
error = vconn_recv_block(vconn, &reply);
if (error) {
+ *replyp = NULL;
return error;
}
recv_xid = ((struct ofp_header *) reply->data)->xid;
- if (send_xid == recv_xid) {
+ if (xid == recv_xid) {
*replyp = reply;
return 0;
}
VLOG_DBG_RL(&rl, "%s: received reply with xid %08"PRIx32" != expected "
- "%08"PRIx32, vconn->name, recv_xid, send_xid);
- buffer_delete(reply);
+ "%08"PRIx32, vconn->name, recv_xid, xid);
+ ofpbuf_delete(reply);
}
}
+/* Sends 'request' to 'vconn' and blocks until it receives a reply with a
+ * matching transaction ID. Returns 0 if successful, in which case the reply
+ * is stored in '*replyp' for the caller to examine and free. Otherwise
+ * returns a positive errno value, or EOF, and sets '*replyp' to null.
+ *
+ * 'request' is always destroyed, regardless of the return value. */
+int
+vconn_transact(struct vconn *vconn, struct ofpbuf *request,
+ struct ofpbuf **replyp)
+{
+ uint32_t send_xid = ((struct ofp_header *) request->data)->xid;
+ int error;
+
+ *replyp = NULL;
+ error = vconn_send_block(vconn, request);
+ if (error) {
+ ofpbuf_delete(request);
+ }
+ return error ? error : vconn_recv_xid(vconn, send_xid, replyp);
+}
+
void
vconn_wait(struct vconn *vconn, enum vconn_wait_type wait)
{
* id. Stores the new buffer in '*bufferp'. The caller must free the buffer
* when it is no longer needed. */
void *
-make_openflow(size_t openflow_len, uint8_t type, struct buffer **bufferp)
+make_openflow(size_t openflow_len, uint8_t type, struct ofpbuf **bufferp)
{
return make_openflow_xid(openflow_len, type, random_uint32(), bufferp);
}
* buffer when it is no longer needed. */
void *
make_openflow_xid(size_t openflow_len, uint8_t type, uint32_t xid,
- struct buffer **bufferp)
+ struct ofpbuf **bufferp)
{
- struct buffer *buffer;
+ struct ofpbuf *buffer;
struct ofp_header *oh;
assert(openflow_len >= sizeof *oh);
assert(openflow_len <= UINT16_MAX);
- buffer = *bufferp = buffer_new(openflow_len);
- oh = buffer_put_uninit(buffer, openflow_len);
- memset(oh, 0, openflow_len);
+ buffer = *bufferp = ofpbuf_new(openflow_len);
+ oh = ofpbuf_put_zeros(buffer, openflow_len);
oh->version = OFP_VERSION;
oh->type = type;
oh->length = htons(openflow_len);
/* Updates the 'length' field of the OpenFlow message in 'buffer' to
* 'buffer->size'. */
void
-update_openflow_length(struct buffer *buffer)
+update_openflow_length(struct ofpbuf *buffer)
{
- struct ofp_header *oh = buffer_at_assert(buffer, 0, sizeof *oh);
+ struct ofp_header *oh = ofpbuf_at_assert(buffer, 0, sizeof *oh);
oh->length = htons(buffer->size);
}
-struct buffer *
+struct ofpbuf *
make_add_flow(const struct flow *flow, uint32_t buffer_id,
- uint16_t idle_timeout, size_t n_actions)
+ uint16_t idle_timeout, size_t actions_len)
{
struct ofp_flow_mod *ofm;
- size_t size = sizeof *ofm + n_actions * sizeof ofm->actions[0];
- struct buffer *out = buffer_new(size);
- ofm = buffer_put_uninit(out, size);
- memset(ofm, 0, size);
+ size_t size = sizeof *ofm + actions_len;
+ struct ofpbuf *out = ofpbuf_new(size);
+ ofm = ofpbuf_put_zeros(out, size);
ofm->header.version = OFP_VERSION;
ofm->header.type = OFPT_FLOW_MOD;
ofm->header.length = htons(size);
return out;
}
-struct buffer *
+struct ofpbuf *
make_add_simple_flow(const struct flow *flow,
uint32_t buffer_id, uint16_t out_port,
uint16_t idle_timeout)
{
- struct buffer *buffer = make_add_flow(flow, buffer_id, idle_timeout, 1);
+ struct ofp_action_output *oao;
+ struct ofpbuf *buffer = make_add_flow(flow, buffer_id, idle_timeout,
+ sizeof *oao);
struct ofp_flow_mod *ofm = buffer->data;
- ofm->actions[0].type = htons(OFPAT_OUTPUT);
- ofm->actions[0].arg.output.max_len = htons(0);
- ofm->actions[0].arg.output.port = htons(out_port);
+ oao = (struct ofp_action_output *)&ofm->actions[0];
+ oao->type = htons(OFPAT_OUTPUT);
+ oao->len = htons(sizeof *oao);
+ oao->port = htons(out_port);
return buffer;
}
-struct buffer *
-make_unbuffered_packet_out(const struct buffer *packet,
+struct ofpbuf *
+make_unbuffered_packet_out(const struct ofpbuf *packet,
uint16_t in_port, uint16_t out_port)
{
struct ofp_packet_out *opo;
- size_t size = sizeof *opo + sizeof opo->actions[0];
- struct buffer *out = buffer_new(size + packet->size);
- opo = buffer_put_uninit(out, size);
- memset(opo, 0, size);
+ struct ofp_action_output *oao;
+ size_t size = sizeof *opo + sizeof *oao;
+ struct ofpbuf *out = ofpbuf_new(size + packet->size);
+
+ opo = ofpbuf_put_zeros(out, size);
opo->header.version = OFP_VERSION;
opo->header.type = OFPT_PACKET_OUT;
opo->buffer_id = htonl(UINT32_MAX);
opo->in_port = htons(in_port);
- opo->n_actions = htons(1);
- opo->actions[0].type = htons(OFPAT_OUTPUT);
- opo->actions[0].arg.output.max_len = htons(0);
- opo->actions[0].arg.output.port = htons(out_port);
- buffer_put(out, packet->data, packet->size);
+
+ oao = (struct ofp_action_output *)&opo->actions[0];
+ oao->type = htons(OFPAT_OUTPUT);
+ oao->len = htons(sizeof *oao);
+ oao->port = htons(out_port);
+
+ opo->actions_len = htons(sizeof *oao);
+
+ ofpbuf_put(out, packet->data, packet->size);
update_openflow_length(out);
return out;
}
-struct buffer *
+struct ofpbuf *
make_buffered_packet_out(uint32_t buffer_id,
uint16_t in_port, uint16_t out_port)
{
struct ofp_packet_out *opo;
- size_t size = sizeof *opo + sizeof opo->actions[0];
- struct buffer *out = buffer_new(size);
- opo = buffer_put_uninit(out, size);
- memset(opo, 0, size);
+ struct ofp_action_output *oao;
+ size_t size = sizeof *opo + sizeof *oao;
+ struct ofpbuf *out = ofpbuf_new(size);
+ opo = ofpbuf_put_zeros(out, size);
opo->header.version = OFP_VERSION;
opo->header.type = OFPT_PACKET_OUT;
opo->header.length = htons(size);
opo->buffer_id = htonl(buffer_id);
opo->in_port = htons(in_port);
- opo->n_actions = htons(1);
- opo->actions[0].type = htons(OFPAT_OUTPUT);
- opo->actions[0].arg.output.max_len = htons(0);
- opo->actions[0].arg.output.port = htons(out_port);
+
+ oao = (struct ofp_action_output *)&opo->actions[0];
+ oao->type = htons(OFPAT_OUTPUT);
+ oao->len = htons(sizeof *oao);
+ oao->port = htons(out_port);
+
+ opo->actions_len = htons(sizeof *oao);
return out;
}
/* Creates and returns an OFPT_ECHO_REQUEST message with an empty payload. */
-struct buffer *
+struct ofpbuf *
make_echo_request(void)
{
struct ofp_header *rq;
- struct buffer *out = buffer_new(sizeof *rq);
- rq = buffer_put_uninit(out, sizeof *rq);
+ struct ofpbuf *out = ofpbuf_new(sizeof *rq);
+ rq = ofpbuf_put_uninit(out, sizeof *rq);
rq->version = OFP_VERSION;
rq->type = OFPT_ECHO_REQUEST;
rq->length = htons(sizeof *rq);
/* Creates and returns an OFPT_ECHO_REPLY message matching the
* OFPT_ECHO_REQUEST message in 'rq'. */
-struct buffer *
+struct ofpbuf *
make_echo_reply(const struct ofp_header *rq)
{
size_t size = ntohs(rq->length);
- struct buffer *out = buffer_new(size);
- struct ofp_header *reply = buffer_put(out, rq, size);
+ struct ofpbuf *out = ofpbuf_new(size);
+ struct ofp_header *reply = ofpbuf_put(out, rq, size);
reply->type = OFPT_ECHO_REPLY;
return out;
}