X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=lib%2Fdpif.c;h=1fff27f9003250ca0e2780f7eb72d57924f740c7;hb=ea7bd5973fb426f3a6ea66b0953c6000980e77ec;hp=73c92cc0c466fd2b5e0a04cb9eabe5a97be934c2;hpb=36956a7d33c9ee204fcb184484a5aaacbd9ecef8;p=openvswitch diff --git a/lib/dpif.c b/lib/dpif.c index 73c92cc0..1fff27f9 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -1,5 +1,5 @@ /* - * 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. @@ -492,17 +492,41 @@ dpif_port_del(struct dpif *dpif, uint16_t port_no) 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", @@ -513,15 +537,18 @@ dpif_port_query_by_number(const struct dpif *dpif, uint16_t port_no, /* 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); @@ -542,74 +569,81 @@ int 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 @@ -959,39 +993,38 @@ dpif_set_sflow_probability(struct dpif *dpif, uint32_t probability) 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" - : ""), - 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" + : ""), + flow.in_port, s); + free(s); } return error; } @@ -1013,12 +1046,12 @@ dpif_recv_purge(struct dpif *dpif) } 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); + struct dpif_upcall upcall; + error = dpif_recv(dpif, &upcall); if (error) { return error == EAGAIN ? 0 : error; } - ofpbuf_delete(buf); + ofpbuf_delete(upcall.packet); } return 0; }