#include "packets.h"
#include "poll-loop.h"
#include "shash.h"
-#include "svec.h"
+#include "sset.h"
#include "timeval.h"
#include "util.h"
#include "valgrind.h"
}
}
-/* Performs periodic work needed by all the various kinds of dpifs.
- *
- * If your program opens any dpifs, it must call both this function and
- * netdev_run() within its main poll loop. */
-void
-dp_run(void)
-{
- 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 both this function and
- * netdev_wait() within its main poll loop. */
-void
-dp_wait(void)
-{
- 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
}
/* Clears 'types' and enumerates the types of all currently registered datapath
- * providers into it. The caller must first initialize the svec. */
+ * providers into it. The caller must first initialize the sset. */
void
-dp_enumerate_types(struct svec *types)
+dp_enumerate_types(struct sset *types)
{
struct shash_node *node;
dp_initialize();
- svec_clear(types);
+ sset_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);
+ sset_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
+ * the given 'type'. The caller must first initialize the sset. 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)
+dp_enumerate_names(const char *type, struct sset *names)
{
const struct registered_dpif_class *registered_class;
const struct dpif_class *dpif_class;
int error;
dp_initialize();
- svec_clear(names);
+ sset_clear(names);
registered_class = shash_find_data(&dpif_classes, type);
if (!registered_class) {
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. */
+/* Parses 'datapath_name_', which is of the form [type@]name into its
+ * component pieces. 'name' and 'type' must be freed by the caller.
+ *
+ * The returned 'type' is normalized, as if by dpif_normalize_type(). */
void
dp_parse_name(const char *datapath_name_, char **name, char **type)
{
if (separator) {
*separator = '\0';
*type = datapath_name;
- *name = xstrdup(separator + 1);
+ *name = xstrdup(dpif_normalize_type(separator + 1));
} else {
*name = datapath_name;
- *type = NULL;
+ *type = xstrdup(dpif_normalize_type(NULL));
}
}
dp_initialize();
- if (!type || *type == '\0') {
- type = "system";
- }
+ type = dpif_normalize_type(type);
registered_class = shash_find_data(&dpif_classes, type);
if (!registered_class) {
}
}
+/* Performs periodic work needed by 'dpif'. */
+void
+dpif_run(struct dpif *dpif)
+{
+ if (dpif->dpif_class->run) {
+ dpif->dpif_class->run(dpif);
+ }
+}
+
+/* Arranges for poll_block() to wake up when dp_run() needs to be called for
+ * 'dpif'. */
+void
+dpif_wait(struct dpif *dpif)
+{
+ if (dpif->dpif_class->wait) {
+ dpif->dpif_class->wait(dpif);
+ }
+}
+
/* Returns the name of datapath 'dpif' prefixed with the type
* (for use in log messages). */
const char *
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.
+/* Returns the fully spelled out name for the given datapath 'type'.
*
- * 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)
+ * Normalized type string can be compared with strcmp(). Unnormalized type
+ * string might be the same even if they have different spellings. */
+const char *
+dpif_normalize_type(const char *type)
{
- 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;
- }
+ return type && type[0] ? type : "system";
}
-
/* Destroys the datapath that 'dpif' is connected to, first removing all of its
* ports. After calling this function, it does not make sense to pass 'dpif'
* to any functions other than dpif_name() or dpif_close(). */
/* Retrieves statistics for 'dpif' into 'stats'. Returns 0 if successful,
* otherwise a positive errno value. */
int
-dpif_get_dp_stats(const struct dpif *dpif, struct odp_stats *stats)
+dpif_get_dp_stats(const struct dpif *dpif, struct ovs_dp_stats *stats)
{
int error = dpif->dpif_class->get_stats(dpif, stats);
if (error) {
} else {
memset(port, 0, sizeof *port);
- /* Log level is DBG here because all the current callers are interested
- * in whether 'dpif' actually has a port 'devname', so that it's not an
- * issue worth logging if it doesn't. */
- VLOG_DBG_RL(&error_rl, "%s: failed to query port %s: %s",
- dpif_name(dpif), devname, strerror(error));
+ /* For ENOENT or ENODEV we use DBG level because the caller is probably
+ * interested in whether 'dpif' actually has a port 'devname', so that
+ * it's not an issue worth logging if it doesn't. Other errors are
+ * uncommon and more likely to indicate a real problem. */
+ VLOG_RL(&error_rl,
+ error == ENOENT || error == ENODEV ? VLL_DBG : VLL_WARN,
+ "%s: failed to query port %s: %s",
+ dpif_name(dpif), devname, strerror(error));
}
return error;
}
}
/* Queries 'dpif' for a flow entry. The flow is specified by the Netlink
- * attributes with types ODP_KEY_ATTR_* in the 'key_len' bytes starting at
+ * attributes with types OVS_KEY_ATTR_* in the 'key_len' bytes starting at
* 'key'.
*
* Returns 0 if successful. If no flow matches, returns ENOENT. On other
}
/* Adds or modifies a flow in 'dpif'. The flow is specified by the Netlink
- * attributes with types ODP_KEY_ATTR_* in the 'key_len' bytes starting at
+ * attributes with types OVS_KEY_ATTR_* in the 'key_len' bytes starting at
* 'key'. The associated actions are specified by the Netlink attributes with
- * types ODPAT_* in the 'actions_len' bytes starting at 'actions'.
+ * types OVS_ACTION_ATTR_* in the 'actions_len' bytes starting at 'actions'.
*
* - If the flow's key does not exist in 'dpif', then the flow will be added if
* 'flags' includes DPIF_FP_CREATE. Otherwise the operation will fail with
/* Deletes a flow from 'dpif' and returns 0, or returns ENOENT if 'dpif' does
* not contain such a flow. The flow is specified by the Netlink attributes
- * with types ODP_KEY_ATTR_* in the 'key_len' bytes starting at 'key'.
+ * with types OVS_KEY_ATTR_* in the 'key_len' bytes starting at 'key'.
*
* If the operation succeeds, then 'stats', if nonnull, will be set to the
* flow's statistics before its deletion. */
* completed by calling dpif_flow_dump_done().
*
* On success, if 'key' and 'key_len' are nonnull then '*key' and '*key_len'
- * will be set to Netlink attributes with types ODP_KEY_ATTR_* representing the
+ * will be set to Netlink attributes with types OVS_KEY_ATTR_* representing the
* dumped flow's key. If 'actions' and 'actions_len' are nonnull then they are
- * set to Netlink attributes with types ODPAT_* representing the dumped flow's
- * actions. If 'stats' is nonnull then it will be set to the dumped flow's
- * statistics.
+ * set to Netlink attributes with types OVS_ACTION_ATTR_* representing the
+ * dumped flow's actions. If 'stats' is nonnull then it will be set to the
+ * dumped flow's statistics.
*
* All of the returned data is owned by 'dpif', not by the caller, and the
* caller must not modify or free it. 'dpif' guarantees that it remains
}
/* Causes 'dpif' to perform the 'actions_len' bytes of actions in 'actions' on
- * the Ethernet frame specified in 'packet'.
+ * the Ethernet frame specified in 'packet' taken from the flow specified in
+ * the 'key_len' bytes of 'key'. ('key' is mostly redundant with 'packet', but
+ * it contains some metadata that cannot be recovered from 'packet', such as
+ * tun_id and in_port.)
*
* Returns 0 if successful, otherwise a positive errno value. */
int
dpif_execute(struct dpif *dpif,
+ const struct nlattr *key, size_t key_len,
const struct nlattr *actions, size_t actions_len,
const struct ofpbuf *buf)
{
COVERAGE_INC(dpif_execute);
if (actions_len > 0) {
- error = dpif->dpif_class->execute(dpif, actions, actions_len, buf);
+ error = dpif->dpif_class->execute(dpif, key, key_len,
+ actions, actions_len, buf);
} else {
error = 0;
}
return error;
}
-/* Retrieves 'dpif''s "listen mask" into '*listen_mask'. Each ODPL_* bit set
- * in '*listen_mask' indicates that dpif_recv() will receive messages of that
- * type. Returns 0 if successful, otherwise a positive errno value. */
-int
-dpif_recv_get_mask(const struct dpif *dpif, int *listen_mask)
+/* Returns a string that represents 'type', for use in log messages. */
+const char *
+dpif_upcall_type_to_string(enum dpif_upcall_type type)
{
- int error = dpif->dpif_class->recv_get_mask(dpif, listen_mask);
- if (error) {
- *listen_mask = 0;
+ switch (type) {
+ case DPIF_UC_MISS: return "miss";
+ case DPIF_UC_ACTION: return "action";
+ case DPIF_N_UC_TYPES: default: return "<unknown>";
}
- log_operation(dpif, "recv_get_mask", error);
- return error;
}
-/* Sets 'dpif''s "listen mask" to 'listen_mask'. Each ODPL_* bit set in
- * '*listen_mask' requests that dpif_recv() receive messages of that type.
- * Returns 0 if successful, otherwise a positive errno value. */
-int
-dpif_recv_set_mask(struct dpif *dpif, int listen_mask)
+static bool OVS_UNUSED
+is_valid_listen_mask(int listen_mask)
{
- int error = dpif->dpif_class->recv_set_mask(dpif, listen_mask);
- log_operation(dpif, "recv_set_mask", error);
- return error;
+ return !(listen_mask & ~((1u << DPIF_UC_MISS) |
+ (1u << DPIF_UC_ACTION)));
}
-/* 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. */
+/* Retrieves 'dpif''s "listen mask" into '*listen_mask'. A 1-bit of value 2**X
+ * set in '*listen_mask' indicates that dpif_recv() will receive messages of
+ * the type (from "enum dpif_upcall_type") with value X. Returns 0 if
+ * successful, otherwise a positive errno value. */
int
-dpif_get_sflow_probability(const struct dpif *dpif, uint32_t *probability)
+dpif_recv_get_mask(const struct dpif *dpif, int *listen_mask)
{
- int error = (dpif->dpif_class->get_sflow_probability
- ? dpif->dpif_class->get_sflow_probability(dpif, probability)
- : EOPNOTSUPP);
+ int error = dpif->dpif_class->recv_get_mask(dpif, listen_mask);
if (error) {
- *probability = 0;
+ *listen_mask = 0;
}
- log_operation(dpif, "get_sflow_probability", error);
+ assert(is_valid_listen_mask(*listen_mask));
+ log_operation(dpif, "recv_get_mask", 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. */
+/* Sets 'dpif''s "listen mask" to 'listen_mask'. A 1-bit of value 2**X set in
+ * '*listen_mask' requests that dpif_recv() will receive messages of the type
+ * (from "enum dpif_upcall_type") with value X. Returns 0 if successful,
+ * otherwise a positive errno value. */
int
-dpif_set_sflow_probability(struct dpif *dpif, uint32_t probability)
+dpif_recv_set_mask(struct dpif *dpif, int listen_mask)
{
- int error = (dpif->dpif_class->set_sflow_probability
- ? dpif->dpif_class->set_sflow_probability(dpif, probability)
- : EOPNOTSUPP);
- log_operation(dpif, "set_sflow_probability", error);
+ int error;
+
+ assert(is_valid_listen_mask(listen_mask));
+
+ error = dpif->dpif_class->recv_set_mask(dpif, listen_mask);
+ log_operation(dpif, "recv_set_mask", error);
return error;
}
/* Polls for an upcall from 'dpif'. If successful, stores the upcall into
- * '*upcall'. Only upcalls of the types selected with the set_listen_mask
+ * '*upcall'. Only upcalls of the types selected with dpif_recv_set_mask()
* member function will ordinarily be received (but if a message type is
* enabled and then later disabled, some stragglers might pop up).
*
{
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);
+ struct ds flow;
+ char *packet;
+
+ packet = ofp_packet_to_string(upcall->packet->data,
+ upcall->packet->size,
+ upcall->packet->size);
+
+ ds_init(&flow);
+ odp_flow_key_format(upcall->key, upcall->key_len, &flow);
+
+ VLOG_DBG("%s: %s upcall:\n%s\n%s",
+ dpif_name(dpif), dpif_upcall_type_to_string(upcall->type),
+ ds_cstr(&flow), packet);
+
+ ds_destroy(&flow);
+ free(packet);
}
return error;
}
}
/* 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'. */
+ * value for use in the OVS_ACTION_ATTR_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)