}
static const char *
-slow_path_reason_to_string(enum slow_path_reason reason)
+slow_path_reason_to_string(uint32_t reason)
{
- switch (reason) {
- case SLOW_CFM:
- return "cfm";
- case SLOW_LACP:
- return "lacp";
- case SLOW_STP:
- return "stp";
- case SLOW_BFD:
- return "bfd";
- case SLOW_CONTROLLER:
- return "controller";
- case __SLOW_MAX:
- default:
- return NULL;
+ switch ((enum slow_path_reason) reason) {
+#define SPR(ENUM, STRING, EXPLANATION) case ENUM: return STRING;
+ SLOW_PATH_REASONS
+#undef SPR
}
+
+ return NULL;
}
-static enum slow_path_reason
-string_to_slow_path_reason(const char *string)
+const char *
+slow_path_reason_to_explanation(enum slow_path_reason reason)
{
- enum slow_path_reason i;
-
- for (i = 1; i < __SLOW_MAX; i++) {
- if (!strcmp(string, slow_path_reason_to_string(i))) {
- return i;
- }
+ switch (reason) {
+#define SPR(ENUM, STRING, EXPLANATION) case ENUM: return EXPLANATION;
+ SLOW_PATH_REASONS
+#undef SPR
}
- return 0;
+ return "<unknown>";
}
static int
cookie.sflow.output);
} else if (userdata_len == sizeof cookie.slow_path
&& cookie.type == USER_ACTION_COOKIE_SLOW_PATH) {
- const char *reason;
- reason = slow_path_reason_to_string(cookie.slow_path.reason);
- reason = reason ? reason : "";
- ds_put_format(ds, ",slow_path(%s)", reason);
+ ds_put_cstr(ds, ",slow_path(");
+ format_flags(ds, slow_path_reason_to_string,
+ cookie.slow_path.reason, ',');
+ ds_put_format(ds, ")");
} else if (userdata_len == sizeof cookie.flow_sample
&& cookie.type == USER_ACTION_COOKIE_FLOW_SAMPLE) {
ds_put_format(ds, ",flow_sample(probability=%"PRIu16
odp_put_userspace_action(pid, &cookie, sizeof cookie.sflow,
actions);
return n;
- } else if (sscanf(s, "userspace(pid=%lli,slow_path(%n", &pid, &n) > 0
+ } else if (sscanf(s, "userspace(pid=%lli,slow_path%n", &pid, &n) > 0
&& n > 0) {
union user_action_cookie cookie;
- char reason[32];
-
- if (s[n] == ')' && s[n + 1] == ')') {
- reason[0] = '\0';
- n += 2;
- } else if (sscanf(s + n, "%31[^)]))", reason) > 0) {
- n += strlen(reason) + 2;
- } else {
- return -EINVAL;
- }
+ int res;
cookie.type = USER_ACTION_COOKIE_SLOW_PATH;
cookie.slow_path.unused = 0;
- cookie.slow_path.reason = string_to_slow_path_reason(reason);
+ cookie.slow_path.reason = 0;
- if (reason[0] && !cookie.slow_path.reason) {
+ res = parse_flags(&s[n], slow_path_reason_to_string,
+ &cookie.slow_path.reason);
+ if (res < 0) {
+ return res;
+ }
+ n += res;
+ if (s[n] != ')') {
return -EINVAL;
}
+ n++;
odp_put_userspace_action(pid, &cookie, sizeof cookie.slow_path,
actions);
void odp_put_pkt_mark_action(const uint32_t pkt_mark,
struct ofpbuf *odp_actions);
-/* Reasons why a subfacet might not be fast-pathable. */
+#define SLOW_PATH_REASONS \
+ /* These reasons are mutually exclusive. */ \
+ SPR(SLOW_CFM, "cfm", "Consists of CFM packets") \
+ SPR(SLOW_BFD, "bfd", "Consists of BFD packets") \
+ SPR(SLOW_LACP, "lacp", "Consists of LACP packets") \
+ SPR(SLOW_STP, "stp", "Consists of STP packets") \
+ SPR(SLOW_CONTROLLER, "controller", \
+ "Sends \"packet-in\" messages to the OpenFlow controller")
+
+/* Indexes for slow-path reasons. Client code uses "enum slow_path_reason"
+ * values instead of these, these are just a way to construct those. */
+enum {
+#define SPR(ENUM, STRING, EXPLANATION) ENUM##_INDEX,
+ SLOW_PATH_REASONS
+#undef SPR
+};
+
+/* Reasons why a subfacet might not be fast-pathable.
+ *
+ * Each reason is a separate bit to allow reasons to be combined. */
enum slow_path_reason {
- SLOW_CFM = 1, /* CFM packets need per-packet processing. */
- SLOW_LACP, /* LACP packets need per-packet processing. */
- SLOW_STP, /* STP packets need per-packet processing. */
- SLOW_BFD, /* BFD packets need per-packet processing. */
- SLOW_CONTROLLER, /* Packets must go to OpenFlow controller. */
- __SLOW_MAX
+#define SPR(ENUM, STRING, EXPLANATION) ENUM = 1 << ENUM##_INDEX,
+ SLOW_PATH_REASONS
+#undef SPR
};
+const char *slow_path_reason_to_explanation(enum slow_path_reason);
+
#endif /* odp-util.h */
special = process_special(ctx, &ctx->xin->flow, peer,
ctx->xin->packet);
if (special) {
- ctx->xout->slow = special;
+ ctx->xout->slow |= special;
} else if (may_receive(peer, ctx)) {
if (xport_stp_forward_state(peer)) {
xlate_table_action(ctx, flow->in_port.ofp_port, 0, true);
struct ofpbuf *packet;
struct flow key;
- ovs_assert(!ctx->xout->slow || ctx->xout->slow == SLOW_CONTROLLER);
- ctx->xout->slow = SLOW_CONTROLLER;
+ ctx->xout->slow |= SLOW_CONTROLLER;
if (!ctx->xin->packet) {
return;
}
in_port = get_ofp_port(ctx.xbridge, flow->in_port.ofp_port);
special = process_special(&ctx, flow, in_port, ctx.xin->packet);
if (special) {
- ctx.xout->slow = special;
+ ctx.xout->slow |= special;
} else {
size_t sample_actions_len;
trace.xout.odp_actions.size);
if (trace.xout.slow) {
+ enum slow_path_reason slow;
+
ds_put_cstr(ds, "\nThis flow is handled by the userspace "
"slow path because it:");
- switch (trace.xout.slow) {
- case SLOW_CFM:
- ds_put_cstr(ds, "\n\t- Consists of CFM packets.");
- break;
- case SLOW_LACP:
- ds_put_cstr(ds, "\n\t- Consists of LACP packets.");
- break;
- case SLOW_STP:
- ds_put_cstr(ds, "\n\t- Consists of STP packets.");
- break;
- case SLOW_BFD:
- ds_put_cstr(ds, "\n\t- Consists of BFD packets.");
- break;
- case SLOW_CONTROLLER:
- ds_put_cstr(ds, "\n\t- Sends \"packet-in\" messages "
- "to the OpenFlow controller.");
- break;
- case __SLOW_MAX:
- NOT_REACHED();
+
+ slow = trace.xout.slow;
+ while (slow) {
+ enum slow_path_reason bit = rightmost_1bit(slow);
+
+ ds_put_format(ds, "\n\t- %s.",
+ slow_path_reason_to_explanation(bit));
+
+ slow &= ~bit;
}
}