COVERAGE_DEFINE(dpif_execute_with_help);
static const struct dpif_class *base_dpif_classes[] = {
-#ifdef __linux__
- &dpif_linux_class,
+#if defined(__linux__) || defined(_WIN32)
+ &dpif_netlink_class,
#endif
&dpif_netdev_class,
};
int error);
static void log_execute_message(struct dpif *, const struct dpif_execute *,
bool subexecute, int error);
+static void log_flow_get_message(const struct dpif *,
+ const struct dpif_flow_get *, int error);
static void
dp_initialize(void)
return error;
}
-/* Queries 'dpif' for a flow entry. The flow is specified by the Netlink
- * 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
- * failure, returns a positive errno value.
- *
- * On success, '*bufp' will be set to an ofpbuf owned by the caller that
- * contains the response for 'flow->mask' and 'flow->actions'. The caller must
- * supply a valid pointer, and must free the ofpbuf (with ofpbuf_delete()) when
- * it is no longer needed.
- *
- * On success, 'flow' will be populated with the mask, actions and stats for
- * the datapath flow corresponding to 'key'. The mask and actions will point
- * within '*bufp'.
- *
- * Implementations may opt to point 'flow->mask' and/or 'flow->actions' at
- * RCU-protected data rather than making a copy of them. Therefore, callers
- * that wish to hold these over quiescent periods must make a copy of these
- * fields before quiescing. */
+/* A dpif_operate() wrapper for performing a single DPIF_OP_FLOW_GET. */
int
-dpif_flow_get(const struct dpif *dpif,
+dpif_flow_get(struct dpif *dpif,
const struct nlattr *key, size_t key_len,
- struct ofpbuf **bufp, struct dpif_flow *flow)
+ struct ofpbuf *buf, struct dpif_flow *flow)
{
- int error;
- struct nlattr *mask, *actions;
- size_t mask_len, actions_len;
- struct dpif_flow_stats stats;
+ struct dpif_op *opp;
+ struct dpif_op op;
- COVERAGE_INC(dpif_flow_get);
+ op.type = DPIF_OP_FLOW_GET;
+ op.u.flow_get.key = key;
+ op.u.flow_get.key_len = key_len;
+ op.u.flow_get.buffer = buf;
+ op.u.flow_get.flow = flow;
+ op.u.flow_get.flow->key = key;
+ op.u.flow_get.flow->key_len = key_len;
- *bufp = NULL;
- error = dpif->dpif_class->flow_get(dpif, key, key_len, bufp,
- &mask, &mask_len,
- &actions, &actions_len, &stats);
- if (error) {
- memset(flow, 0, sizeof *flow);
- ofpbuf_delete(*bufp);
- *bufp = NULL;
- } else {
- flow->mask = mask;
- flow->mask_len = mask_len;
- flow->actions = actions;
- flow->actions_len = actions_len;
- flow->stats = stats;
- }
- if (should_log_flow_message(error)) {
- log_flow_message(dpif, error, "flow_get", key, key_len,
- NULL, 0, &flow->stats,
- flow->actions, flow->actions_len);
- }
- return error;
+ opp = &op;
+ dpif_operate(dpif, &opp, 1);
+
+ return op.error;
}
/* A dpif_operate() wrapper for performing a single DPIF_OP_FLOW_PUT. */
* meaningful. */
static void
dpif_execute_helper_cb(void *aux_, struct dpif_packet **packets, int cnt,
- struct pkt_metadata *md,
const struct nlattr *action, bool may_steal OVS_UNUSED)
{
struct dpif_execute_helper_aux *aux = aux_;
int type = nl_attr_type(action);
- struct ofpbuf * packet = &packets[0]->ofpbuf;
+ struct ofpbuf *packet = &packets[0]->ofpbuf;
+ struct pkt_metadata *md = &packets[0]->md;
ovs_assert(cnt == 1);
execute.packet = packet;
execute.md = *md;
execute.needs_help = false;
+ execute.probe = false;
aux->error = dpif_execute(aux->dpif, &execute);
log_execute_message(aux->dpif, &execute, true, aux->error);
case OVS_ACTION_ATTR_PUSH_MPLS:
case OVS_ACTION_ATTR_POP_MPLS:
case OVS_ACTION_ATTR_SET:
+ case OVS_ACTION_ATTR_SET_MASKED:
case OVS_ACTION_ATTR_SAMPLE:
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
COVERAGE_INC(dpif_execute_with_help);
packet.ofpbuf = *execute->packet;
+ packet.md = execute->md;
pp = &packet;
- odp_execute_actions(&aux, &pp, 1, false, &execute->md, execute->actions,
+ odp_execute_actions(&aux, &pp, 1, false, execute->actions,
execute->actions_len, dpif_execute_helper_cb);
/* Even though may_steal is set to false, some actions could modify or
* reallocate the ofpbuf memory. We need to pass those changes to the
* caller */
*execute->packet = packet.ofpbuf;
+ execute->md = packet.md;
return aux.error;
}
break;
}
+ case DPIF_OP_FLOW_GET: {
+ struct dpif_flow_get *get = &op->u.flow_get;
+
+ COVERAGE_INC(dpif_flow_get);
+ log_flow_get_message(dpif, get, error);
+
+ if (error) {
+ memset(get->flow, 0, sizeof *get->flow);
+ }
+ break;
+ }
+
case DPIF_OP_FLOW_DEL: {
struct dpif_flow_del *del = &op->u.flow_del;
}
void
-dpif_register_upcall_cb(struct dpif *dpif, exec_upcall_cb *cb)
+dpif_register_upcall_cb(struct dpif *dpif, upcall_callback *cb, void *aux)
{
if (dpif->dpif_class->register_upcall_cb) {
- dpif->dpif_class->register_upcall_cb(dpif, cb);
+ dpif->dpif_class->register_upcall_cb(dpif, cb, aux);
}
}
}
}
+/* If 'dpif' creates its own I/O polling threads, refreshes poll threads
+ * configuration. */
+int
+dpif_poll_threads_set(struct dpif *dpif, unsigned int n_rxqs,
+ const char *cmask)
+{
+ int error = 0;
+
+ if (dpif->dpif_class->poll_threads_set) {
+ error = dpif->dpif_class->poll_threads_set(dpif, n_rxqs, cmask);
+ if (error) {
+ log_operation(dpif, "poll_threads_set", error);
+ }
+ }
+
+ return error;
+}
+
/* Polls for an upcall from 'dpif' for an upcall handler. Since there
* there can be multiple poll loops, 'handler_id' is needed as index to
* identify the corresponding poll loop. If successful, stores the upcall
log_flow_put_message(struct dpif *dpif, const struct dpif_flow_put *put,
int error)
{
- if (should_log_flow_message(error)) {
+ if (should_log_flow_message(error) && !(put->flags & DPIF_FP_PROBE)) {
struct ds s;
ds_init(&s);
* called after the dpif_provider's '->execute' function, which is allowed to
* modify execute->packet and execute->md. In practice, though:
*
- * - dpif-linux doesn't modify execute->packet or execute->md.
+ * - dpif-netlink doesn't modify execute->packet or execute->md.
*
* - dpif-netdev does modify them but it is less likely to have problems
* because it is built into ovs-vswitchd and cannot have version skew,
log_execute_message(struct dpif *dpif, const struct dpif_execute *execute,
bool subexecute, int error)
{
- if (!(error ? VLOG_DROP_WARN(&error_rl) : VLOG_DROP_DBG(&dpmsg_rl))) {
+ if (!(error ? VLOG_DROP_WARN(&error_rl) : VLOG_DROP_DBG(&dpmsg_rl))
+ && !execute->probe) {
struct ds ds = DS_EMPTY_INITIALIZER;
char *packet;
free(packet);
}
}
+
+static void
+log_flow_get_message(const struct dpif *dpif, const struct dpif_flow_get *get,
+ int error)
+{
+ if (should_log_flow_message(error)) {
+ log_flow_message(dpif, error, "flow_get",
+ get->key, get->key_len,
+ get->flow->mask, get->flow->mask_len,
+ &get->flow->stats,
+ get->flow->actions, get->flow->actions_len);
+ }
+}