2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 06:15:47 +00:00

ofproto-dpif: Introduce "slow path" datapath flows.

Most exact-match flows can be handled directly in the datapath, but
for various reasons, some cannot: every packet in these flows must
be sent separately to userspace.  Until now, flows that cannot be
handled entirely in the kernel have been allowed to miss each time
in the datapath.  This is generally OK, but it has a few
disadvantages:

    * It can make troubleshooting at the level where one must look
      at datapath flows a bit confusing in some cases, because
      datapath misses due to genuinely new flows are mixed in with
      datapath misses for known flows that cannot be set up.

    * It means that the kernel-to-userspace packets for a given
      input port always go to a single kernel-to-userspace queue,
      even if we'd like to segregate out some of the packets for
      known flows.  (An upcoming commit has examples.)

This commit therefore introduces the concept of a "slow path" flow,
one that is installed in the datapath with a single action that
sends the flow's packets to userspace.  To make troubleshooting
easier, the action includes a reason code (displayed by "ovs-dpctl
dump-flows") that explains why the flow has been slow-pathed.

Bug #7550.
Signed-off-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
Ben Pfaff
2012-05-04 14:52:36 -07:00
parent c57b22267b
commit 6a7e895f94
4 changed files with 441 additions and 131 deletions

View File

@@ -166,6 +166,52 @@ format_odp_sample_action(struct ds *ds, const struct nlattr *attr)
ds_put_format(ds, "))");
}
static const char *
slow_path_reason_to_string(enum slow_path_reason bit)
{
switch (bit) {
case SLOW_CFM:
return "cfm";
case SLOW_LACP:
return "lacp";
case SLOW_STP:
return "stp";
case SLOW_IN_BAND:
return "in_band";
case SLOW_CONTROLLER:
return "controller";
case SLOW_MATCH:
return "match";
default:
return NULL;
}
}
static void
format_slow_path_reason(struct ds *ds, uint32_t slow)
{
uint32_t bad = 0;
while (slow) {
uint32_t bit = rightmost_1bit(slow);
const char *s;
s = slow_path_reason_to_string(bit);
if (s) {
ds_put_format(ds, "%s,", s);
} else {
bad |= bit;
}
slow &= ~bit;
}
if (bad) {
ds_put_format(ds, "0x%"PRIx32",", bad);
}
ds_chomp(ds, ',');
}
static void
format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
{
@@ -191,13 +237,21 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
switch (cookie.type) {
case USER_ACTION_COOKIE_SFLOW:
ds_put_format(ds, ",sFlow,"
"vid=%"PRIu16",pcp=%"PRIu8",output=%"PRIu32,
ds_put_format(ds, ",sFlow("
"vid=%"PRIu16",pcp=%"PRIu8",output=%"PRIu32")",
vlan_tci_to_vid(cookie.sflow.vlan_tci),
vlan_tci_to_pcp(cookie.sflow.vlan_tci),
cookie.sflow.output);
break;
case USER_ACTION_COOKIE_SLOW_PATH:
ds_put_cstr(ds, ",slow_path(");
if (cookie.slow_path.reason) {
format_slow_path_reason(ds, cookie.slow_path.reason);
}
ds_put_char(ds, ')');
break;
case USER_ACTION_COOKIE_UNSPEC:
default:
ds_put_format(ds, ",userdata=0x%"PRIx64, userdata);
@@ -346,8 +400,8 @@ parse_odp_action(const char *s, const struct shash *port_names,
if (sscanf(s, "userspace(pid=%lli)%n", &pid, &n) > 0 && n > 0) {
odp_put_userspace_action(pid, NULL, actions);
return n;
} else if (sscanf(s, "userspace(pid=%lli,sFlow,vid=%i,"
"pcp=%i,output=%lli)%n",
} else if (sscanf(s, "userspace(pid=%lli,sFlow(vid=%i,"
"pcp=%i,output=%lli))%n",
&pid, &vid, &pcp, &output, &n) > 0 && n > 0) {
union user_action_cookie cookie;
uint16_t tci;
@@ -360,6 +414,42 @@ parse_odp_action(const char *s, const struct shash *port_names,
cookie.type = USER_ACTION_COOKIE_SFLOW;
cookie.sflow.vlan_tci = htons(tci);
cookie.sflow.output = output;
odp_put_userspace_action(pid, &cookie, actions);
return n;
} else if (sscanf(s, "userspace(pid=%lli,slow_path(%n", &pid, &n) > 0
&& n > 0) {
union user_action_cookie cookie;
cookie.type = USER_ACTION_COOKIE_SLOW_PATH;
cookie.slow_path.unused = 0;
cookie.slow_path.reason = 0;
while (s[n] != ')') {
uint32_t bit;
for (bit = 1; bit; bit <<= 1) {
const char *reason = slow_path_reason_to_string(bit);
size_t len = strlen(reason);
if (reason
&& !strncmp(s + n, reason, len)
&& (s[n + len] == ',' || s[n + len] == ')'))
{
cookie.slow_path.reason |= bit;
n += len + (s[n + len] == ',');
break;
}
}
if (!bit) {
return -EINVAL;
}
}
if (s[n + 1] != ')') {
return -EINVAL;
}
n += 2;
odp_put_userspace_action(pid, &cookie, actions);
return n;
} else if (sscanf(s, "userspace(pid=%lli,userdata="