/*
- * Copyright (c) 2008, 2009, 2010 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
return error;
}
+/* Makes a deep copy of 'src' into 'dst'. */
+void
+dpif_port_clone(struct dpif_port *dst, const struct dpif_port *src)
+{
+ dst->name = xstrdup(src->name);
+ dst->type = xstrdup(src->type);
+ dst->port_no = src->port_no;
+}
+
+/* Frees memory allocated to members of 'dpif_port'.
+ *
+ * Do not call this function on a dpif_port obtained from
+ * dpif_port_dump_next(): that function retains ownership of the data in the
+ * dpif_port. */
+void
+dpif_port_destroy(struct dpif_port *dpif_port)
+{
+ free(dpif_port->name);
+ free(dpif_port->type);
+}
+
/* Looks up port number 'port_no' in 'dpif'. On success, returns 0 and
* initializes '*port' appropriately; on failure, returns a positive errno
- * value. */
+ * value.
+ *
+ * The caller owns the data in 'port' and must free it with
+ * dpif_port_destroy() when it is no longer needed. */
int
dpif_port_query_by_number(const struct dpif *dpif, uint16_t port_no,
- struct odp_port *port)
+ struct dpif_port *port)
{
int error = dpif->dpif_class->port_query_by_number(dpif, port_no, port);
if (!error) {
VLOG_DBG_RL(&dpmsg_rl, "%s: port %"PRIu16" is device %s",
- dpif_name(dpif), port_no, port->devname);
+ dpif_name(dpif), port_no, port->name);
} else {
memset(port, 0, sizeof *port);
VLOG_WARN_RL(&error_rl, "%s: failed to query port %"PRIu16": %s",
/* Looks up port named 'devname' in 'dpif'. On success, returns 0 and
* initializes '*port' appropriately; on failure, returns a positive errno
- * value. */
+ * value.
+ *
+ * The caller owns the data in 'port' and must free it with
+ * dpif_port_destroy() when it is no longer needed. */
int
dpif_port_query_by_name(const struct dpif *dpif, const char *devname,
- struct odp_port *port)
+ struct dpif_port *port)
{
int error = dpif->dpif_class->port_query_by_name(dpif, devname, port);
if (!error) {
VLOG_DBG_RL(&dpmsg_rl, "%s: device %s is on port %"PRIu16,
- dpif_name(dpif), devname, port->port);
+ dpif_name(dpif), devname, port->port_no);
} else {
memset(port, 0, sizeof *port);
return error;
}
+/* Returns one greater than the maximum port number accepted in flow
+ * actions. */
+int
+dpif_get_max_ports(const struct dpif *dpif)
+{
+ return dpif->dpif_class->get_max_ports(dpif);
+}
+
/* Looks up port number 'port_no' in 'dpif'. On success, returns 0 and copies
* the port's name into the 'name_size' bytes in 'name', ensuring that the
* result is null-terminated. On failure, returns a positive errno value and
dpif_port_get_name(struct dpif *dpif, uint16_t port_no,
char *name, size_t name_size)
{
- struct odp_port port;
+ struct dpif_port port;
int error;
assert(name_size > 0);
error = dpif_port_query_by_number(dpif, port_no, &port);
if (!error) {
- ovs_strlcpy(name, port.devname, name_size);
+ ovs_strlcpy(name, port.name, name_size);
+ dpif_port_destroy(&port);
} else {
*name = '\0';
}
return error;
}
-/* Obtains a list of all the ports in 'dpif'.
+/* Initializes 'dump' to begin dumping the ports in a dpif.
+ *
+ * This function provides no status indication. An error status for the entire
+ * dump operation is provided when it is completed by calling
+ * dpif_port_dump_done().
+ */
+void
+dpif_port_dump_start(struct dpif_port_dump *dump, const struct dpif *dpif)
+{
+ dump->dpif = dpif;
+ dump->error = dpif->dpif_class->port_dump_start(dpif, &dump->state);
+ log_operation(dpif, "port_dump_start", dump->error);
+}
+
+/* Attempts to retrieve another port from 'dump', which must have been
+ * initialized with dpif_port_dump_start(). On success, stores a new dpif_port
+ * into 'port' and returns true. On failure, returns false.
*
- * If successful, returns 0 and sets '*portsp' to point to an array of
- * appropriately initialized port structures and '*n_portsp' to the number of
- * ports in the array. The caller is responsible for freeing '*portp' by
- * calling free().
+ * Failure might indicate an actual error or merely that the last port has been
+ * dumped. An error status for the entire dump operation is provided when it
+ * is completed by calling dpif_port_dump_done().
*
- * On failure, returns a positive errno value and sets '*portsp' to NULL and
- * '*n_portsp' to 0. */
-int
-dpif_port_list(const struct dpif *dpif,
- struct odp_port **portsp, size_t *n_portsp)
+ * The dpif owns the data stored in 'port'. It will remain valid until at
+ * least the next time 'dump' is passed to dpif_port_dump_next() or
+ * dpif_port_dump_done(). */
+bool
+dpif_port_dump_next(struct dpif_port_dump *dump, struct dpif_port *port)
{
- struct odp_port *ports;
- size_t n_ports = 0;
- int error;
+ const struct dpif *dpif = dump->dpif;
- for (;;) {
- struct odp_stats stats;
- int retval;
+ if (dump->error) {
+ return false;
+ }
- error = dpif_get_dp_stats(dpif, &stats);
- if (error) {
- goto exit;
- }
+ dump->error = dpif->dpif_class->port_dump_next(dpif, dump->state, port);
+ if (dump->error == EOF) {
+ VLOG_DBG_RL(&dpmsg_rl, "%s: dumped all ports", dpif_name(dpif));
+ } else {
+ log_operation(dpif, "port_dump_next", dump->error);
+ }
- ports = xcalloc(stats.n_ports, sizeof *ports);
- retval = dpif->dpif_class->port_list(dpif, ports, stats.n_ports);
- if (retval < 0) {
- /* Hard error. */
- error = -retval;
- free(ports);
- goto exit;
- } else if (retval <= stats.n_ports) {
- /* Success. */
- error = 0;
- n_ports = retval;
- goto exit;
- } else {
- /* Soft error: port count increased behind our back. Try again. */
- free(ports);
- }
+ if (dump->error) {
+ dpif->dpif_class->port_dump_done(dpif, dump->state);
+ return false;
}
+ return true;
+}
-exit:
- if (error) {
- *portsp = NULL;
- *n_portsp = 0;
- } else {
- *portsp = ports;
- *n_portsp = n_ports;
+/* Completes port table dump operation 'dump', which must have been initialized
+ * with dpif_port_dump_start(). Returns 0 if the dump operation was
+ * error-free, otherwise a positive errno value describing the problem. */
+int
+dpif_port_dump_done(struct dpif_port_dump *dump)
+{
+ const struct dpif *dpif = dump->dpif;
+ if (!dump->error) {
+ dump->error = dpif->dpif_class->port_dump_done(dpif, dump->state);
+ log_operation(dpif, "port_dump_done", dump->error);
}
- log_operation(dpif, "port_list", error);
- return error;
+ return dump->error == EOF ? 0 : dump->error;
}
/* Polls for changes in the set of ports in 'dpif'. If the set of ports in
return error;
}
-/* Attempts to receive a message from 'dpif'. If successful, stores the
- * message into '*packetp'. The message, if one is received, will begin with
- * 'struct odp_msg' as a header, and will have at least DPIF_RECV_MSG_PADDING
- * bytes of headroom. Only messages of the types selected with
- * dpif_set_listen_mask() will ordinarily be received (but if a message type is
+/* Polls for an upcall from 'dpif'. If successful, stores the upcall into
+ * '*upcall'. Only upcalls of the types selected with the set_listen_mask
+ * member function will ordinarily be received (but if a message type is
* enabled and then later disabled, some stragglers might pop up).
*
+ * The caller takes ownership of the data that 'upcall' points to.
+ * 'upcall->key' and 'upcall->actions' (if nonnull) point into data owned by
+ * 'upcall->packet', so their memory cannot be freed separately. (This is
+ * hardly a great way to do things but it works out OK for the dpif providers
+ * and clients that exist so far.)
+ *
* Returns 0 if successful, otherwise a positive errno value. Returns EAGAIN
- * if no message is immediately available. */
+ * if no upcall is immediately available. */
int
-dpif_recv(struct dpif *dpif, struct ofpbuf **packetp)
+dpif_recv(struct dpif *dpif, struct dpif_upcall *upcall)
{
- int error = dpif->dpif_class->recv(dpif, packetp);
- if (!error) {
- struct ofpbuf *buf = *packetp;
-
- assert(ofpbuf_headroom(buf) >= DPIF_RECV_MSG_PADDING);
- if (VLOG_IS_DBG_ENABLED()) {
- struct odp_msg *msg = buf->data;
- void *payload = msg + 1;
- size_t payload_len = buf->size - sizeof *msg;
- char *s = ofp_packet_to_string(payload, payload_len, payload_len);
- VLOG_DBG_RL(&dpmsg_rl, "%s: received %s message of length "
- "%zu on port %"PRIu16": %s", dpif_name(dpif),
- (msg->type == _ODPL_MISS_NR ? "miss"
- : msg->type == _ODPL_ACTION_NR ? "action"
- : msg->type == _ODPL_SFLOW_NR ? "sFlow"
- : "<unknown>"),
- payload_len, msg->port, s);
- free(s);
- }
- } else {
- *packetp = NULL;
+ int error = dpif->dpif_class->recv(dpif, upcall);
+ if (!error && !VLOG_DROP_DBG(&dpmsg_rl)) {
+ struct flow flow;
+ char *s;
+
+ s = ofp_packet_to_string(upcall->packet->data,
+ upcall->packet->size, upcall->packet->size);
+ odp_flow_key_to_flow(upcall->key, upcall->key_len, &flow);
+
+ VLOG_DBG("%s: %s upcall on port %"PRIu16": %s", dpif_name(dpif),
+ (upcall->type == _ODPL_MISS_NR ? "miss"
+ : upcall->type == _ODPL_ACTION_NR ? "action"
+ : upcall->type == _ODPL_SFLOW_NR ? "sFlow"
+ : "<unknown>"),
+ flow.in_port, s);
+ free(s);
}
return error;
}
/* Discards all messages that would otherwise be received by dpif_recv() on
- * 'dpif'. Returns 0 if successful, otherwise a positive errno value. */
-int
+ * 'dpif'. */
+void
dpif_recv_purge(struct dpif *dpif)
{
- struct odp_stats stats;
- unsigned int i;
- int error;
-
COVERAGE_INC(dpif_purge);
-
- error = dpif_get_dp_stats(dpif, &stats);
- if (error) {
- return error;
- }
-
- for (i = 0; i < stats.max_miss_queue + stats.max_action_queue + stats.max_sflow_queue; i++) {
- struct ofpbuf *buf;
- error = dpif_recv(dpif, &buf);
- if (error) {
- return error == EAGAIN ? 0 : error;
- }
- ofpbuf_delete(buf);
+ if (dpif->dpif_class->recv_purge) {
+ dpif->dpif_class->recv_purge(dpif);
}
- return 0;
}
/* Arranges for the poll loop to wake up when 'dpif' has a message queued to be