summaryrefslogtreecommitdiff
path: root/ofproto/ofproto-dpif-upcall.c
diff options
context:
space:
mode:
authorJustin Pettit <jpettit@ovn.org>2017-09-29 17:44:08 -0700
committerJustin Pettit <jpettit@ovn.org>2018-01-10 16:42:00 -0800
commitbcc81b297bd546f0a168ff624ddb1b3a4d28d5b3 (patch)
tree2805ac09ef6ce265a6082789d1b3a8a83bbb2c06 /ofproto/ofproto-dpif-upcall.c
parent911b4a7ea90a4e3710a92220427a4c6d3cdd79ce (diff)
downloadopenvswitch-bcc81b297bd546f0a168ff624ddb1b3a4d28d5b3.tar.gz
ofproto-dpif: Reorganize upcall handling.
- This reduces the number of times upcall cookies are processed. - It separate true miss calls from slow-path actions. The reorganization will also be useful for a future commit. Signed-off-by: Justin Pettit <jpettit@ovn.org> Acked-by: Ben Pfaff <blp@ovn.org>
Diffstat (limited to 'ofproto/ofproto-dpif-upcall.c')
-rw-r--r--ofproto/ofproto-dpif-upcall.c81
1 files changed, 36 insertions, 45 deletions
diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
index ddae02dab..83007d00b 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -183,6 +183,7 @@ struct udpif {
enum upcall_type {
BAD_UPCALL, /* Some kind of bug somewhere. */
MISS_UPCALL, /* A flow miss. */
+ SLOW_PATH_UPCALL, /* Slow path upcall. */
SFLOW_UPCALL, /* sFlow sample. */
FLOW_SAMPLE_UPCALL, /* Per-flow sampling. */
IPFIX_UPCALL /* Per-bridge sampling. */
@@ -210,8 +211,7 @@ struct upcall {
uint16_t mru; /* If !0, Maximum receive unit of
fragmented IP packet */
- enum dpif_upcall_type type; /* Datapath type of the upcall. */
- const struct nlattr *userdata; /* Userdata for DPIF_UC_ACTION Upcalls. */
+ enum upcall_type type; /* Type of the upcall. */
const struct nlattr *actions; /* Flow actions in DPIF_UC_ACTION Upcalls. */
bool xout_initialized; /* True if 'xout' must be uninitialized. */
@@ -235,6 +235,8 @@ struct upcall {
size_t key_len; /* Datapath flow key length. */
const struct nlattr *out_tun_key; /* Datapath output tunnel key. */
+ struct user_action_cookie cookie;
+
uint64_t odp_actions_stub[1024 / 8]; /* Stub for odp_actions. */
};
@@ -367,7 +369,8 @@ static int ukey_acquire(struct udpif *, const struct dpif_flow *,
static void ukey_delete__(struct udpif_key *);
static void ukey_delete(struct umap *, struct udpif_key *);
static enum upcall_type classify_upcall(enum dpif_upcall_type type,
- const struct nlattr *userdata);
+ const struct nlattr *userdata,
+ struct user_action_cookie *cookie);
static void put_op_init(struct ukey_op *op, struct udpif_key *ukey,
enum dpif_flow_put_flags flags);
@@ -969,7 +972,8 @@ udpif_revalidator(void *arg)
}
static enum upcall_type
-classify_upcall(enum dpif_upcall_type type, const struct nlattr *userdata)
+classify_upcall(enum dpif_upcall_type type, const struct nlattr *userdata,
+ struct user_action_cookie *cookie)
{
/* First look at the upcall type. */
switch (type) {
@@ -991,25 +995,24 @@ classify_upcall(enum dpif_upcall_type type, const struct nlattr *userdata)
return BAD_UPCALL;
}
- struct user_action_cookie cookie;
size_t userdata_len = nl_attr_get_size(userdata);
- if (userdata_len != sizeof cookie) {
+ if (userdata_len != sizeof *cookie) {
VLOG_WARN_RL(&rl, "action upcall cookie has unexpected size %"PRIuSIZE,
userdata_len);
return BAD_UPCALL;
}
- memcpy(&cookie, nl_attr_get(userdata), sizeof cookie);
- if (cookie.type == USER_ACTION_COOKIE_SFLOW) {
+ memcpy(cookie, nl_attr_get(userdata), sizeof *cookie);
+ if (cookie->type == USER_ACTION_COOKIE_SFLOW) {
return SFLOW_UPCALL;
- } else if (cookie.type == USER_ACTION_COOKIE_SLOW_PATH) {
- return MISS_UPCALL;
- } else if (cookie.type == USER_ACTION_COOKIE_FLOW_SAMPLE) {
+ } else if (cookie->type == USER_ACTION_COOKIE_SLOW_PATH) {
+ return SLOW_PATH_UPCALL;
+ } else if (cookie->type == USER_ACTION_COOKIE_FLOW_SAMPLE) {
return FLOW_SAMPLE_UPCALL;
- } else if (cookie.type == USER_ACTION_COOKIE_IPFIX) {
+ } else if (cookie->type == USER_ACTION_COOKIE_IPFIX) {
return IPFIX_UPCALL;
} else {
VLOG_WARN_RL(&rl, "invalid user cookie of type %"PRIu16
- " and size %"PRIuSIZE, cookie.type, userdata_len);
+ " and size %"PRIuSIZE, cookie->type, userdata_len);
return BAD_UPCALL;
}
}
@@ -1071,6 +1074,11 @@ upcall_receive(struct upcall *upcall, const struct dpif_backer *backer,
{
int error;
+ upcall->type = classify_upcall(type, userdata, &upcall->cookie);
+ if (upcall->type == BAD_UPCALL) {
+ return EAGAIN;
+ }
+
error = xlate_lookup(backer, flow, &upcall->ofproto, &upcall->ipfix,
&upcall->sflow, NULL, &upcall->in_port);
if (error) {
@@ -1083,8 +1091,6 @@ upcall_receive(struct upcall *upcall, const struct dpif_backer *backer,
upcall->packet = packet;
upcall->ufid = ufid;
upcall->pmd_id = pmd_id;
- upcall->type = type;
- upcall->userdata = userdata;
ofpbuf_use_stub(&upcall->odp_actions, upcall->odp_actions_stub,
sizeof upcall->odp_actions_stub);
ofpbuf_init(&upcall->put_actions, 0);
@@ -1120,7 +1126,7 @@ upcall_xlate(struct udpif *udpif, struct upcall *upcall,
upcall->flow, upcall->in_port, NULL,
stats.tcp_flags, upcall->packet, wc, odp_actions);
- if (upcall->type == DPIF_UC_MISS) {
+ if (upcall->type == MISS_UPCALL) {
xin.resubmit_stats = &stats;
if (xin.frozen_state) {
@@ -1169,7 +1175,7 @@ upcall_xlate(struct udpif *udpif, struct upcall *upcall,
/* This function is also called for slow-pathed flows. As we are only
* going to create new datapath flows for actual datapath misses, there is
* no point in creating a ukey otherwise. */
- if (upcall->type == DPIF_UC_MISS) {
+ if (upcall->type == MISS_UPCALL) {
upcall->ukey = ukey_create_from_upcall(upcall, wc);
}
}
@@ -1205,7 +1211,7 @@ should_install_flow(struct udpif *udpif, struct upcall *upcall)
{
unsigned int flow_limit;
- if (upcall->type != DPIF_UC_MISS) {
+ if (upcall->type != MISS_UPCALL) {
return false;
} else if (upcall->recirc && !upcall->have_recirc_ref) {
VLOG_DBG_RL(&rl, "upcall: no reference for recirc flow");
@@ -1318,6 +1324,7 @@ dpif_read_actions(struct udpif *udpif, struct upcall *upcall,
break;
case BAD_UPCALL:
case MISS_UPCALL:
+ case SLOW_PATH_UPCALL:
default:
break;
}
@@ -1329,57 +1336,46 @@ static int
process_upcall(struct udpif *udpif, struct upcall *upcall,
struct ofpbuf *odp_actions, struct flow_wildcards *wc)
{
- const struct nlattr *userdata = upcall->userdata;
const struct dp_packet *packet = upcall->packet;
const struct flow *flow = upcall->flow;
size_t actions_len = 0;
- enum upcall_type upcall_type = classify_upcall(upcall->type, userdata);
- switch (upcall_type) {
+ switch (upcall->type) {
case MISS_UPCALL:
+ case SLOW_PATH_UPCALL:
upcall_xlate(udpif, upcall, odp_actions, wc);
return 0;
case SFLOW_UPCALL:
if (upcall->sflow) {
- struct user_action_cookie cookie;
struct dpif_sflow_actions sflow_actions;
- if (nl_attr_get_size(userdata) != sizeof cookie) {
- return EINVAL;
- }
- memcpy(&cookie, nl_attr_get(userdata), sizeof cookie);
memset(&sflow_actions, 0, sizeof sflow_actions);
- actions_len = dpif_read_actions(udpif, upcall, flow, upcall_type,
- &sflow_actions);
+ actions_len = dpif_read_actions(udpif, upcall, flow,
+ upcall->type, &sflow_actions);
dpif_sflow_received(upcall->sflow, packet, flow,
- flow->in_port.odp_port, &cookie,
+ flow->in_port.odp_port, &upcall->cookie,
actions_len > 0 ? &sflow_actions : NULL);
}
break;
case IPFIX_UPCALL:
if (upcall->ipfix) {
- struct user_action_cookie cookie;
struct flow_tnl output_tunnel_key;
struct dpif_ipfix_actions ipfix_actions;
- if (nl_attr_get_size(userdata) != sizeof cookie) {
- return EINVAL;
- }
- memcpy(&cookie, nl_attr_get(userdata), sizeof cookie);
memset(&ipfix_actions, 0, sizeof ipfix_actions);
if (upcall->out_tun_key) {
odp_tun_key_from_attr(upcall->out_tun_key, &output_tunnel_key);
}
- actions_len = dpif_read_actions(udpif, upcall, flow, upcall_type,
- &ipfix_actions);
+ actions_len = dpif_read_actions(udpif, upcall, flow,
+ upcall->type, &ipfix_actions);
dpif_ipfix_bridge_sample(upcall->ipfix, packet, flow,
flow->in_port.odp_port,
- cookie.ipfix.output_odp_port,
+ upcall->cookie.ipfix.output_odp_port,
upcall->out_tun_key ?
&output_tunnel_key : NULL,
actions_len > 0 ? &ipfix_actions: NULL);
@@ -1388,26 +1384,21 @@ process_upcall(struct udpif *udpif, struct upcall *upcall,
case FLOW_SAMPLE_UPCALL:
if (upcall->ipfix) {
- struct user_action_cookie cookie;
struct flow_tnl output_tunnel_key;
struct dpif_ipfix_actions ipfix_actions;
- if (nl_attr_get_size(userdata) != sizeof cookie) {
- return EINVAL;
- }
- memcpy(&cookie, nl_attr_get(userdata), sizeof cookie);
memset(&ipfix_actions, 0, sizeof ipfix_actions);
if (upcall->out_tun_key) {
odp_tun_key_from_attr(upcall->out_tun_key, &output_tunnel_key);
}
- actions_len = dpif_read_actions(udpif, upcall, flow, upcall_type,
- &ipfix_actions);
+ actions_len = dpif_read_actions(udpif, upcall, flow,
+ upcall->type, &ipfix_actions);
/* The flow reflects exactly the contents of the packet.
* Sample the packet using it. */
dpif_ipfix_flow_sample(upcall->ipfix, packet, flow,
- &cookie, flow->in_port.odp_port,
+ &upcall->cookie, flow->in_port.odp_port,
upcall->out_tun_key ?
&output_tunnel_key : NULL,
actions_len > 0 ? &ipfix_actions: NULL);