X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fdpif.c;h=01e905d936cafa61db25d1608b17ae2bba67d70a;hb=refs%2Fheads%2Flts-1.0a;hp=0e83a9e2afaea4403284360cbd41974983be0e24;hpb=72865317a41d065fcc47a33fc68cdd2081cecb3d;p=sliver-openvswitch.git diff --git a/lib/dpif.c b/lib/dpif.c index 0e83a9e2a..01e905d93 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -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. @@ -33,17 +33,26 @@ #include "ofpbuf.h" #include "packets.h" #include "poll-loop.h" +#include "shash.h" +#include "svec.h" #include "util.h" #include "valgrind.h" - #include "vlog.h" -#define THIS_MODULE VLM_dpif -static const struct dpif_class *dpif_classes[] = { +VLOG_DEFINE_THIS_MODULE(dpif) + +static const struct dpif_class *base_dpif_classes[] = { +#ifdef HAVE_NETLINK &dpif_linux_class, +#endif &dpif_netdev_class, }; -enum { N_DPIF_CLASSES = ARRAY_SIZE(dpif_classes) }; + +struct registered_dpif_class { + struct dpif_class dpif_class; + int refcount; +}; +static struct shash dpif_classes = SHASH_INITIALIZER(&dpif_classes); /* Rate limit for individual messages going to or from the datapath, output at * DBG level. This is very high because, if these are enabled, it is because @@ -51,7 +60,7 @@ enum { N_DPIF_CLASSES = ARRAY_SIZE(dpif_classes) }; static struct vlog_rate_limit dpmsg_rl = VLOG_RATE_LIMIT_INIT(600, 600); /* Not really much point in logging many dpif errors. */ -static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(9999, 5); +static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(60, 5); static void log_operation(const struct dpif *, const char *operation, int error); @@ -62,89 +71,246 @@ static void log_flow_put(struct dpif *, int error, static bool should_log_flow_message(int error); static void check_rw_odp_flow(struct odp_flow *); +static void +dp_initialize(void) +{ + static int status = -1; + + if (status < 0) { + int i; + + status = 0; + for (i = 0; i < ARRAY_SIZE(base_dpif_classes); i++) { + dp_register_provider(base_dpif_classes[i]); + } + } +} + /* Performs periodic work needed by all the various kinds of dpifs. * - * If your program opens any dpifs, it must call this function within its main - * poll loop. */ + * If your program opens any dpifs, it must call both this function and + * netdev_run() within its main poll loop. */ void dp_run(void) { - int i; - for (i = 0; i < N_DPIF_CLASSES; i++) { - const struct dpif_class *class = dpif_classes[i]; - if (class->run) { - class->run(); + struct shash_node *node; + SHASH_FOR_EACH(node, &dpif_classes) { + const struct registered_dpif_class *registered_class = node->data; + if (registered_class->dpif_class.run) { + registered_class->dpif_class.run(); } } } /* Arranges for poll_block() to wake up when dp_run() needs to be called. * - * If your program opens any dpifs, it must call this function within its main - * poll loop. */ + * If your program opens any dpifs, it must call both this function and + * netdev_wait() within its main poll loop. */ void dp_wait(void) { - int i; - for (i = 0; i < N_DPIF_CLASSES; i++) { - const struct dpif_class *class = dpif_classes[i]; - if (class->wait) { - class->wait(); + struct shash_node *node; + SHASH_FOR_EACH(node, &dpif_classes) { + const struct registered_dpif_class *registered_class = node->data; + if (registered_class->dpif_class.wait) { + registered_class->dpif_class.wait(); } } } +/* Registers a new datapath provider. After successful registration, new + * datapaths of that type can be opened using dpif_open(). */ +int +dp_register_provider(const struct dpif_class *new_class) +{ + struct registered_dpif_class *registered_class; + + if (shash_find(&dpif_classes, new_class->type)) { + VLOG_WARN("attempted to register duplicate datapath provider: %s", + new_class->type); + return EEXIST; + } + + registered_class = xmalloc(sizeof *registered_class); + memcpy(®istered_class->dpif_class, new_class, + sizeof registered_class->dpif_class); + registered_class->refcount = 0; + + shash_add(&dpif_classes, new_class->type, registered_class); + + return 0; +} + +/* Unregisters a datapath provider. 'type' must have been previously + * registered and not currently be in use by any dpifs. After unregistration + * new datapaths of that type cannot be opened using dpif_open(). */ +int +dp_unregister_provider(const char *type) +{ + struct shash_node *node; + struct registered_dpif_class *registered_class; + + node = shash_find(&dpif_classes, type); + if (!node) { + VLOG_WARN("attempted to unregister a datapath provider that is not " + "registered: %s", type); + return EAFNOSUPPORT; + } + + registered_class = node->data; + if (registered_class->refcount) { + VLOG_WARN("attempted to unregister in use datapath provider: %s", type); + return EBUSY; + } + + shash_delete(&dpif_classes, node); + free(registered_class); + + return 0; +} + +/* Clears 'types' and enumerates the types of all currently registered datapath + * providers into it. The caller must first initialize the svec. */ +void +dp_enumerate_types(struct svec *types) +{ + struct shash_node *node; + + dp_initialize(); + svec_clear(types); + + SHASH_FOR_EACH(node, &dpif_classes) { + const struct registered_dpif_class *registered_class = node->data; + svec_add(types, registered_class->dpif_class.type); + } +} + +/* Clears 'names' and enumerates the names of all known created datapaths with + * the given 'type'. The caller must first initialize the svec. Returns 0 if + * successful, otherwise a positive errno value. + * + * Some kinds of datapaths might not be practically enumerable. This is not + * considered an error. */ +int +dp_enumerate_names(const char *type, struct svec *names) +{ + const struct registered_dpif_class *registered_class; + const struct dpif_class *dpif_class; + int error; + + dp_initialize(); + svec_clear(names); + + registered_class = shash_find_data(&dpif_classes, type); + if (!registered_class) { + VLOG_WARN("could not enumerate unknown type: %s", type); + return EAFNOSUPPORT; + } + + dpif_class = ®istered_class->dpif_class; + error = dpif_class->enumerate ? dpif_class->enumerate(names) : 0; + + if (error) { + VLOG_WARN("failed to enumerate %s datapaths: %s", dpif_class->type, + strerror(error)); + } + + return error; +} + +/* Parses 'datapath name', which is of the form type@name into its + * component pieces. 'name' and 'type' must be freed by the caller. */ +void +dp_parse_name(const char *datapath_name_, char **name, char **type) +{ + char *datapath_name = xstrdup(datapath_name_); + char *separator; + + separator = strchr(datapath_name, '@'); + if (separator) { + *separator = '\0'; + *type = datapath_name; + *name = xstrdup(separator + 1); + } else { + *name = datapath_name; + *type = NULL; + } +} + static int -do_open(const char *name_, bool create, struct dpif **dpifp) +do_open(const char *name, const char *type, bool create, struct dpif **dpifp) { - char *name = xstrdup(name_); - char *prefix, *suffix, *colon; struct dpif *dpif = NULL; int error; - int i; + struct registered_dpif_class *registered_class; - colon = strchr(name, ':'); - if (colon) { - *colon = '\0'; - prefix = name; - suffix = colon + 1; - } else { - prefix = ""; - suffix = name; + dp_initialize(); + + if (!type || *type == '\0') { + type = "system"; } - for (i = 0; i < N_DPIF_CLASSES; i++) { - const struct dpif_class *class = dpif_classes[i]; - if (!strcmp(prefix, class->prefix)) { - error = class->open(name_, suffix, create, &dpif); - goto exit; - } + registered_class = shash_find_data(&dpif_classes, type); + if (!registered_class) { + VLOG_WARN("could not create datapath %s of unknown type %s", name, + type); + error = EAFNOSUPPORT; + goto exit; + } + + error = registered_class->dpif_class.open(name, type, create, &dpif); + if (!error) { + registered_class->refcount++; } - error = EAFNOSUPPORT; exit: *dpifp = error ? NULL : dpif; return error; } -/* Tries to open an existing datapath named 'name'. Will fail if no datapath - * named 'name' exists. Returns 0 if successful, otherwise a positive errno - * value. On success stores a pointer to the datapath in '*dpifp', otherwise a - * null pointer. */ +/* Tries to open an existing datapath named 'name' and type 'type'. Will fail + * if no datapath with 'name' and 'type' exists. 'type' may be either NULL or + * the empty string to specify the default system type. Returns 0 if + * successful, otherwise a positive errno value. On success stores a pointer + * to the datapath in '*dpifp', otherwise a null pointer. */ +int +dpif_open(const char *name, const char *type, struct dpif **dpifp) +{ + return do_open(name, type, false, dpifp); +} + +/* Tries to create and open a new datapath with the given 'name' and 'type'. + * 'type' may be either NULL or the empty string to specify the default system + * type. Will fail if a datapath with 'name' and 'type' already exists. + * Returns 0 if successful, otherwise a positive errno value. On success + * stores a pointer to the datapath in '*dpifp', otherwise a null pointer. */ int -dpif_open(const char *name, struct dpif **dpifp) +dpif_create(const char *name, const char *type, struct dpif **dpifp) { - return do_open(name, false, dpifp); + return do_open(name, type, true, dpifp); } -/* Tries to create and open a new datapath with the given 'name'. Will fail if - * a datapath named 'name' already exists. Returns 0 if successful, otherwise - * a positive errno value. On success stores a pointer to the datapath in - * '*dpifp', otherwise a null pointer.*/ +/* Tries to open a datapath with the given 'name' and 'type', creating it if it + * does not exist. 'type' may be either NULL or the empty string to specify + * the default system type. Returns 0 if successful, otherwise a positive + * errno value. On success stores a pointer to the datapath in '*dpifp', + * otherwise a null pointer. */ int -dpif_create(const char *name, struct dpif **dpifp) +dpif_create_and_open(const char *name, const char *type, struct dpif **dpifp) { - return do_open(name, true, dpifp); + int error; + + error = dpif_create(name, type, dpifp); + if (error == EEXIST || error == EBUSY) { + error = dpif_open(name, type, dpifp); + if (error) { + VLOG_WARN("datapath %s already exists but cannot be opened: %s", + name, strerror(error)); + } + } else if (error) { + VLOG_WARN("failed to create datapath %s: %s", name, strerror(error)); + } + return error; } /* Closes and frees the connection to 'dpif'. Does not destroy the datapath @@ -153,17 +319,58 @@ void dpif_close(struct dpif *dpif) { if (dpif) { - char *name = dpif->name; - dpif->class->close(dpif); - free(name); + struct registered_dpif_class *registered_class; + + registered_class = shash_find_data(&dpif_classes, + dpif->dpif_class->type); + assert(registered_class); + assert(registered_class->refcount); + + registered_class->refcount--; + dpif_uninit(dpif, true); } } -/* Returns the name of datapath 'dpif' (for use in log messages). */ +/* Returns the name of datapath 'dpif' prefixed with the type + * (for use in log messages). */ const char * dpif_name(const struct dpif *dpif) { - return dpif->name; + return dpif->full_name; +} + +/* Returns the name of datapath 'dpif' without the type + * (for use in device names). */ +const char * +dpif_base_name(const struct dpif *dpif) +{ + return dpif->base_name; +} + +/* Enumerates all names that may be used to open 'dpif' into 'all_names'. The + * Linux datapath, for example, supports opening a datapath both by number, + * e.g. "dp0", and by the name of the datapath's local port. For some + * datapaths, this might be an infinite set (e.g. in a file name, slashes may + * be duplicated any number of times), in which case only the names most likely + * to be used will be enumerated. + * + * The caller must already have initialized 'all_names'. Any existing names in + * 'all_names' will not be disturbed. */ +int +dpif_get_all_names(const struct dpif *dpif, struct svec *all_names) +{ + if (dpif->dpif_class->get_all_names) { + int error = dpif->dpif_class->get_all_names(dpif, all_names); + if (error) { + VLOG_WARN_RL(&error_rl, + "failed to retrieve names for datpath %s: %s", + dpif_name(dpif), strerror(error)); + } + return error; + } else { + svec_add(all_names, dpif_base_name(dpif)); + return 0; + } } /* Destroys the datapath that 'dpif' is connected to, first removing all of its @@ -176,7 +383,7 @@ dpif_delete(struct dpif *dpif) COVERAGE_INC(dpif_destroy); - error = dpif->class->delete(dpif); + error = dpif->dpif_class->destroy(dpif); log_operation(dpif, "delete", error); return error; } @@ -186,7 +393,7 @@ dpif_delete(struct dpif *dpif) int dpif_get_dp_stats(const struct dpif *dpif, struct odp_stats *stats) { - int error = dpif->class->get_stats(dpif, stats); + int error = dpif->dpif_class->get_stats(dpif, stats); if (error) { memset(stats, 0, sizeof *stats); } @@ -202,7 +409,7 @@ dpif_get_dp_stats(const struct dpif *dpif, struct odp_stats *stats) int dpif_get_drop_frags(const struct dpif *dpif, bool *drop_frags) { - int error = dpif->class->get_drop_frags(dpif, drop_frags); + int error = dpif->dpif_class->get_drop_frags(dpif, drop_frags); if (error) { *drop_frags = false; } @@ -216,7 +423,7 @@ dpif_get_drop_frags(const struct dpif *dpif, bool *drop_frags) int dpif_set_drop_frags(struct dpif *dpif, bool drop_frags) { - int error = dpif->class->set_drop_frags(dpif, drop_frags); + int error = dpif->dpif_class->set_drop_frags(dpif, drop_frags); log_operation(dpif, "set_drop_frags", error); return error; } @@ -235,7 +442,7 @@ dpif_port_add(struct dpif *dpif, const char *devname, uint16_t flags, COVERAGE_INC(dpif_port_add); - error = dpif->class->port_add(dpif, devname, flags, &port_no); + error = dpif->dpif_class->port_add(dpif, devname, flags, &port_no); if (!error) { VLOG_DBG_RL(&dpmsg_rl, "%s: added %s as port %"PRIu16, dpif_name(dpif), devname, port_no); @@ -259,7 +466,7 @@ dpif_port_del(struct dpif *dpif, uint16_t port_no) COVERAGE_INC(dpif_port_del); - error = dpif->class->port_del(dpif, port_no); + error = dpif->dpif_class->port_del(dpif, port_no); log_operation(dpif, "port_del", error); return error; } @@ -271,7 +478,7 @@ int dpif_port_query_by_number(const struct dpif *dpif, uint16_t port_no, struct odp_port *port) { - int error = dpif->class->port_query_by_number(dpif, port_no, 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); @@ -290,7 +497,7 @@ int dpif_port_query_by_name(const struct dpif *dpif, const char *devname, struct odp_port *port) { - int error = dpif->class->port_query_by_name(dpif, devname, 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); @@ -342,7 +549,7 @@ dpif_port_list(const struct dpif *dpif, struct odp_port **portsp, size_t *n_portsp) { struct odp_port *ports; - size_t n_ports; + size_t n_ports = 0; int error; for (;;) { @@ -355,7 +562,7 @@ dpif_port_list(const struct dpif *dpif, } ports = xcalloc(stats.n_ports, sizeof *ports); - retval = dpif->class->port_list(dpif, ports, stats.n_ports); + retval = dpif->dpif_class->port_list(dpif, ports, stats.n_ports); if (retval < 0) { /* Hard error. */ error = -retval; @@ -403,7 +610,7 @@ exit: int dpif_port_poll(const struct dpif *dpif, char **devnamep) { - int error = dpif->class->port_poll(dpif, devnamep); + int error = dpif->dpif_class->port_poll(dpif, devnamep); if (error) { *devnamep = NULL; } @@ -415,7 +622,7 @@ dpif_port_poll(const struct dpif *dpif, char **devnamep) void dpif_port_poll_wait(const struct dpif *dpif) { - dpif->class->port_poll_wait(dpif); + dpif->dpif_class->port_poll_wait(dpif); } /* Retrieves a list of the port numbers in port group 'group' in 'dpif'. @@ -436,8 +643,8 @@ dpif_port_group_get(const struct dpif *dpif, uint16_t group, *ports = NULL; *n_ports = 0; for (;;) { - int retval = dpif->class->port_group_get(dpif, group, - *ports, *n_ports); + int retval = dpif->dpif_class->port_group_get(dpif, group, + *ports, *n_ports); if (retval < 0) { /* Hard error. */ error = -retval; @@ -475,7 +682,7 @@ dpif_port_group_set(struct dpif *dpif, uint16_t group, COVERAGE_INC(dpif_port_group_set); - error = dpif->class->port_group_set(dpif, group, ports, n_ports); + error = dpif->dpif_class->port_group_set(dpif, group, ports, n_ports); log_operation(dpif, "port_group_set", error); return error; } @@ -489,7 +696,7 @@ dpif_flow_flush(struct dpif *dpif) COVERAGE_INC(dpif_flow_flush); - error = dpif->class->flow_flush(dpif); + error = dpif->dpif_class->flow_flush(dpif); log_operation(dpif, "flow_flush", error); return error; } @@ -515,10 +722,15 @@ dpif_flow_get(const struct dpif *dpif, struct odp_flow *flow) COVERAGE_INC(dpif_flow_get); check_rw_odp_flow(flow); - error = dpif->class->flow_get(dpif, flow, 1); + error = dpif->dpif_class->flow_get(dpif, flow, 1); if (!error) { error = flow->stats.error; } + if (error) { + /* Make the results predictable on error. */ + memset(&flow->stats, 0, sizeof flow->stats); + flow->n_actions = 0; + } if (should_log_flow_message(error)) { log_flow_operation(dpif, "flow_get", error, flow); } @@ -565,7 +777,7 @@ dpif_flow_get_multiple(const struct dpif *dpif, check_rw_odp_flow(&flows[i]); } - error = dpif->class->flow_get(dpif, flows, n); + error = dpif->dpif_class->flow_get(dpif, flows, n); log_operation(dpif, "flow_get_multiple", error); return error; } @@ -593,7 +805,7 @@ dpif_flow_put(struct dpif *dpif, struct odp_flow_put *put) COVERAGE_INC(dpif_flow_put); - error = dpif->class->flow_put(dpif, put); + error = dpif->dpif_class->flow_put(dpif, put); if (should_log_flow_message(error)) { log_flow_put(dpif, error, put); } @@ -615,7 +827,7 @@ dpif_flow_del(struct dpif *dpif, struct odp_flow *flow) check_rw_odp_flow(flow); memset(&flow->stats, 0, sizeof flow->stats); - error = dpif->class->flow_del(dpif, flow); + error = dpif->dpif_class->flow_del(dpif, flow); if (should_log_flow_message(error)) { log_flow_operation(dpif, "delete flow", error, flow); } @@ -644,7 +856,7 @@ dpif_flow_list(const struct dpif *dpif, struct odp_flow flows[], size_t n, flows[i].n_actions = 0; } } - retval = dpif->class->flow_list(dpif, flows, n); + retval = dpif->dpif_class->flow_list(dpif, flows, n); if (retval < 0) { *n_out = 0; VLOG_WARN_RL(&error_rl, "%s: flow list failed (%s)", @@ -721,7 +933,8 @@ dpif_execute(struct dpif *dpif, uint16_t in_port, COVERAGE_INC(dpif_execute); if (n_actions > 0) { - error = dpif->class->execute(dpif, in_port, actions, n_actions, buf); + error = dpif->dpif_class->execute(dpif, in_port, actions, + n_actions, buf); } else { error = 0; } @@ -748,7 +961,7 @@ dpif_execute(struct dpif *dpif, uint16_t in_port, int dpif_recv_get_mask(const struct dpif *dpif, int *listen_mask) { - int error = dpif->class->recv_get_mask(dpif, listen_mask); + int error = dpif->dpif_class->recv_get_mask(dpif, listen_mask); if (error) { *listen_mask = 0; } @@ -762,14 +975,50 @@ dpif_recv_get_mask(const struct dpif *dpif, int *listen_mask) int dpif_recv_set_mask(struct dpif *dpif, int listen_mask) { - int error = dpif->class->recv_set_mask(dpif, listen_mask); + int error = dpif->dpif_class->recv_set_mask(dpif, listen_mask); log_operation(dpif, "recv_set_mask", error); return error; } +/* Retrieve the sFlow sampling probability. '*probability' is expressed as the + * number of packets out of UINT_MAX to sample, e.g. probability/UINT_MAX is + * the probability of sampling a given packet. + * + * Returns 0 if successful, otherwise a positive errno value. EOPNOTSUPP + * indicates that 'dpif' does not support sFlow sampling. */ +int +dpif_get_sflow_probability(const struct dpif *dpif, uint32_t *probability) +{ + int error = (dpif->dpif_class->get_sflow_probability + ? dpif->dpif_class->get_sflow_probability(dpif, probability) + : EOPNOTSUPP); + if (error) { + *probability = 0; + } + log_operation(dpif, "get_sflow_probability", error); + return error; +} + +/* Set the sFlow sampling probability. 'probability' is expressed as the + * number of packets out of UINT_MAX to sample, e.g. probability/UINT_MAX is + * the probability of sampling a given packet. + * + * Returns 0 if successful, otherwise a positive errno value. EOPNOTSUPP + * indicates that 'dpif' does not support sFlow sampling. */ +int +dpif_set_sflow_probability(struct dpif *dpif, uint32_t probability) +{ + int error = (dpif->dpif_class->set_sflow_probability + ? dpif->dpif_class->set_sflow_probability(dpif, probability) + : EOPNOTSUPP); + log_operation(dpif, "set_sflow_probability", error); + 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. Only messages of the types selected 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 * enabled and then later disabled, some stragglers might pop up). * @@ -778,10 +1027,12 @@ dpif_recv_set_mask(struct dpif *dpif, int listen_mask) int dpif_recv(struct dpif *dpif, struct ofpbuf **packetp) { - int error = dpif->class->recv(dpif, packetp); + 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 ofpbuf *buf = *packetp; struct odp_msg *msg = buf->data; void *payload = msg + 1; size_t payload_len = buf->size - sizeof *msg; @@ -790,6 +1041,7 @@ dpif_recv(struct dpif *dpif, struct ofpbuf **packetp) "%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); @@ -816,7 +1068,7 @@ dpif_recv_purge(struct dpif *dpif) return error; } - for (i = 0; i < stats.max_miss_queue + stats.max_action_queue; i++) { + 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) { @@ -832,7 +1084,7 @@ dpif_recv_purge(struct dpif *dpif) void dpif_recv_wait(struct dpif *dpif) { - dpif->class->recv_wait(dpif); + dpif->dpif_class->recv_wait(dpif); } /* Obtains the NetFlow engine type and engine ID for 'dpif' into '*engine_type' @@ -844,16 +1096,57 @@ dpif_get_netflow_ids(const struct dpif *dpif, *engine_type = dpif->netflow_engine_type; *engine_id = dpif->netflow_engine_id; } + +/* Translates OpenFlow queue ID 'queue_id' (in host byte order) into a priority + * value for use in the ODPAT_SET_PRIORITY action. On success, returns 0 and + * stores the priority into '*priority'. On failure, returns a positive errno + * value and stores 0 into '*priority'. */ +int +dpif_queue_to_priority(const struct dpif *dpif, uint32_t queue_id, + uint32_t *priority) +{ + int error = (dpif->dpif_class->queue_to_priority + ? dpif->dpif_class->queue_to_priority(dpif, queue_id, + priority) + : EOPNOTSUPP); + if (error) { + *priority = 0; + } + log_operation(dpif, "queue_to_priority", error); + return error; +} void -dpif_init(struct dpif *dpif, const struct dpif_class *class, const char *name, +dpif_init(struct dpif *dpif, const struct dpif_class *dpif_class, + const char *name, uint8_t netflow_engine_type, uint8_t netflow_engine_id) { - dpif->class = class; - dpif->name = xstrdup(name); + dpif->dpif_class = dpif_class; + dpif->base_name = xstrdup(name); + dpif->full_name = xasprintf("%s@%s", dpif_class->type, name); dpif->netflow_engine_type = netflow_engine_type; dpif->netflow_engine_id = netflow_engine_id; } + +/* Undoes the results of initialization. + * + * Normally this function only needs to be called from dpif_close(). + * However, it may be called by providers due to an error on opening + * that occurs after initialization. It this case dpif_close() would + * never be called. */ +void +dpif_uninit(struct dpif *dpif, bool close) +{ + char *base_name = dpif->base_name; + char *full_name = dpif->full_name; + + if (close) { + dpif->dpif_class->close(dpif); + } + + free(base_name); + free(full_name); +} static void log_operation(const struct dpif *dpif, const char *operation, int error)