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

Allow OVS_USERSPACE_ATTR_USERDATA to be variable length.

Until now, the optional OVS_USERSPACE_ATTR_USERDATA attribute had to be
exactly 64 bits long, if it was present.  However, 64 bits is not enough
space to associate as much information with a flow as would be convenient
for some userspace features now under development.  This commit generalizes
the attribute, allowing it to be any length.

This generalization is backward-compatible: if userspace only uses 64-bit
attributes, then it will not see any change in behavior.

CC: Romain Lenglet <rlenglet@vmware.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Jesse Gross <jesse@nicira.com>
This commit is contained in:
Ben Pfaff
2013-02-15 16:48:32 -08:00
parent 7e2d8aeaf5
commit e995e3df57
10 changed files with 125 additions and 73 deletions

View File

@@ -374,8 +374,8 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex,
len = sizeof(struct ovs_header); len = sizeof(struct ovs_header);
len += nla_total_size(skb->len); len += nla_total_size(skb->len);
len += nla_total_size(FLOW_BUFSIZE); len += nla_total_size(FLOW_BUFSIZE);
if (upcall_info->cmd == OVS_PACKET_CMD_ACTION) if (upcall_info->userdata)
len += nla_total_size(8); len += NLA_ALIGN(upcall_info->userdata->nla_len);
user_skb = genlmsg_new(len, GFP_ATOMIC); user_skb = genlmsg_new(len, GFP_ATOMIC);
if (!user_skb) { if (!user_skb) {
@@ -392,8 +392,9 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex,
nla_nest_end(user_skb, nla); nla_nest_end(user_skb, nla);
if (upcall_info->userdata) if (upcall_info->userdata)
nla_put_u64(user_skb, OVS_PACKET_ATTR_USERDATA, __nla_put(user_skb, OVS_PACKET_ATTR_USERDATA,
nla_get_u64(upcall_info->userdata)); upcall_info->userdata->nla_len - NLA_HDRLEN,
nla_data(upcall_info->userdata));
nla = __nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, skb->len); nla = __nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, skb->len);
@@ -679,7 +680,7 @@ static int validate_userspace(const struct nlattr *attr)
{ {
static const struct nla_policy userspace_policy[OVS_USERSPACE_ATTR_MAX + 1] = { static const struct nla_policy userspace_policy[OVS_USERSPACE_ATTR_MAX + 1] = {
[OVS_USERSPACE_ATTR_PID] = {.type = NLA_U32 }, [OVS_USERSPACE_ATTR_PID] = {.type = NLA_U32 },
[OVS_USERSPACE_ATTR_USERDATA] = {.type = NLA_U64 }, [OVS_USERSPACE_ATTR_USERDATA] = {.type = NLA_UNSPEC },
}; };
struct nlattr *a[OVS_USERSPACE_ATTR_MAX + 1]; struct nlattr *a[OVS_USERSPACE_ATTR_MAX + 1];
int error; int error;

View File

@@ -120,7 +120,7 @@ struct ovs_skb_cb {
* struct dp_upcall - metadata to include with a packet to send to userspace * struct dp_upcall - metadata to include with a packet to send to userspace
* @cmd: One of %OVS_PACKET_CMD_*. * @cmd: One of %OVS_PACKET_CMD_*.
* @key: Becomes %OVS_PACKET_ATTR_KEY. Must be nonnull. * @key: Becomes %OVS_PACKET_ATTR_KEY. Must be nonnull.
* @userdata: If nonnull, its u64 value is extracted and passed to userspace as * @userdata: If nonnull, its variable-length value is passed to userspace as
* %OVS_PACKET_ATTR_USERDATA. * %OVS_PACKET_ATTR_USERDATA.
* @portid: Netlink PID to which packet should be sent. If @portid is 0 then no * @portid: Netlink PID to which packet should be sent. If @portid is 0 then no
* packet is sent and the packet is accounted in the datapath's @n_lost * packet is sent and the packet is accounted in the datapath's @n_lost

View File

@@ -148,7 +148,8 @@ enum ovs_packet_cmd {
* for %OVS_PACKET_CMD_EXECUTE. It has nested %OVS_ACTION_ATTR_* attributes. * for %OVS_PACKET_CMD_EXECUTE. It has nested %OVS_ACTION_ATTR_* attributes.
* @OVS_PACKET_ATTR_USERDATA: Present for an %OVS_PACKET_CMD_ACTION * @OVS_PACKET_ATTR_USERDATA: Present for an %OVS_PACKET_CMD_ACTION
* notification if the %OVS_ACTION_ATTR_USERSPACE action specified an * notification if the %OVS_ACTION_ATTR_USERSPACE action specified an
* %OVS_USERSPACE_ATTR_USERDATA attribute. * %OVS_USERSPACE_ATTR_USERDATA attribute, with the same length and content
* specified there.
* *
* These attributes follow the &struct ovs_header within the Generic Netlink * These attributes follow the &struct ovs_header within the Generic Netlink
* payload for %OVS_PACKET_* commands. * payload for %OVS_PACKET_* commands.
@@ -158,7 +159,7 @@ enum ovs_packet_attr {
OVS_PACKET_ATTR_PACKET, /* Packet data. */ OVS_PACKET_ATTR_PACKET, /* Packet data. */
OVS_PACKET_ATTR_KEY, /* Nested OVS_KEY_ATTR_* attributes. */ OVS_PACKET_ATTR_KEY, /* Nested OVS_KEY_ATTR_* attributes. */
OVS_PACKET_ATTR_ACTIONS, /* Nested OVS_ACTION_ATTR_* attributes. */ OVS_PACKET_ATTR_ACTIONS, /* Nested OVS_ACTION_ATTR_* attributes. */
OVS_PACKET_ATTR_USERDATA, /* u64 OVS_ACTION_ATTR_USERSPACE arg. */ OVS_PACKET_ATTR_USERDATA, /* OVS_ACTION_ATTR_USERSPACE arg. */
__OVS_PACKET_ATTR_MAX __OVS_PACKET_ATTR_MAX
}; };
@@ -448,13 +449,13 @@ enum ovs_sample_attr {
* enum ovs_userspace_attr - Attributes for %OVS_ACTION_ATTR_USERSPACE action. * enum ovs_userspace_attr - Attributes for %OVS_ACTION_ATTR_USERSPACE action.
* @OVS_USERSPACE_ATTR_PID: u32 Netlink PID to which the %OVS_PACKET_CMD_ACTION * @OVS_USERSPACE_ATTR_PID: u32 Netlink PID to which the %OVS_PACKET_CMD_ACTION
* message should be sent. Required. * message should be sent. Required.
* @OVS_USERSPACE_ATTR_USERDATA: If present, its u64 argument is copied to the * @OVS_USERSPACE_ATTR_USERDATA: If present, its variable-length argument is
* %OVS_PACKET_CMD_ACTION message as %OVS_PACKET_ATTR_USERDATA, * copied to the %OVS_PACKET_CMD_ACTION message as %OVS_PACKET_ATTR_USERDATA.
*/ */
enum ovs_userspace_attr { enum ovs_userspace_attr {
OVS_USERSPACE_ATTR_UNSPEC, OVS_USERSPACE_ATTR_UNSPEC,
OVS_USERSPACE_ATTR_PID, /* u32 Netlink PID to receive upcalls. */ OVS_USERSPACE_ATTR_PID, /* u32 Netlink PID to receive upcalls. */
OVS_USERSPACE_ATTR_USERDATA, /* u64 optional user-specified cookie. */ OVS_USERSPACE_ATTR_USERDATA, /* Optional user-specified cookie. */
__OVS_USERSPACE_ATTR_MAX __OVS_USERSPACE_ATTR_MAX
}; };

View File

@@ -1237,7 +1237,7 @@ parse_odp_packet(struct ofpbuf *buf, struct dpif_upcall *upcall,
[OVS_PACKET_ATTR_KEY] = { .type = NL_A_NESTED }, [OVS_PACKET_ATTR_KEY] = { .type = NL_A_NESTED },
/* OVS_PACKET_CMD_ACTION only. */ /* OVS_PACKET_CMD_ACTION only. */
[OVS_PACKET_ATTR_USERDATA] = { .type = NL_A_U64, .optional = true }, [OVS_PACKET_ATTR_USERDATA] = { .type = NL_A_UNSPEC, .optional = true },
}; };
struct ovs_header *ovs_header; struct ovs_header *ovs_header;
@@ -1275,9 +1275,7 @@ parse_odp_packet(struct ofpbuf *buf, struct dpif_upcall *upcall,
upcall->key = CONST_CAST(struct nlattr *, upcall->key = CONST_CAST(struct nlattr *,
nl_attr_get(a[OVS_PACKET_ATTR_KEY])); nl_attr_get(a[OVS_PACKET_ATTR_KEY]));
upcall->key_len = nl_attr_get_size(a[OVS_PACKET_ATTR_KEY]); upcall->key_len = nl_attr_get_size(a[OVS_PACKET_ATTR_KEY]);
upcall->userdata = (a[OVS_PACKET_ATTR_USERDATA] upcall->userdata = a[OVS_PACKET_ATTR_USERDATA];
? nl_attr_get_u64(a[OVS_PACKET_ATTR_USERDATA])
: 0);
*dp_ifindex = ovs_header->dp_ifindex; *dp_ifindex = ovs_header->dp_ifindex;
return 0; return 0;

View File

@@ -151,7 +151,7 @@ static int dpif_netdev_open(const struct dpif_class *, const char *name,
bool create, struct dpif **); bool create, struct dpif **);
static int dp_netdev_output_userspace(struct dp_netdev *, const struct ofpbuf *, static int dp_netdev_output_userspace(struct dp_netdev *, const struct ofpbuf *,
int queue_no, const struct flow *, int queue_no, const struct flow *,
uint64_t arg); const struct nlattr *userdata);
static void dp_netdev_execute_actions(struct dp_netdev *, static void dp_netdev_execute_actions(struct dp_netdev *,
struct ofpbuf *, struct flow *, struct ofpbuf *, struct flow *,
const struct nlattr *actions, const struct nlattr *actions,
@@ -1043,7 +1043,7 @@ dp_netdev_port_input(struct dp_netdev *dp, struct dp_netdev_port *port,
dp->n_hit++; dp->n_hit++;
} else { } else {
dp->n_missed++; dp->n_missed++;
dp_netdev_output_userspace(dp, packet, DPIF_UC_MISS, &key, 0); dp_netdev_output_userspace(dp, packet, DPIF_UC_MISS, &key, NULL);
} }
} }
@@ -1108,37 +1108,51 @@ dp_netdev_output_port(struct dp_netdev *dp, struct ofpbuf *packet,
static int static int
dp_netdev_output_userspace(struct dp_netdev *dp, const struct ofpbuf *packet, dp_netdev_output_userspace(struct dp_netdev *dp, const struct ofpbuf *packet,
int queue_no, const struct flow *flow, uint64_t arg) int queue_no, const struct flow *flow,
const struct nlattr *userdata)
{ {
struct dp_netdev_queue *q = &dp->queues[queue_no]; struct dp_netdev_queue *q = &dp->queues[queue_no];
struct dp_netdev_upcall *u; if (q->head - q->tail < MAX_QUEUE_LEN) {
struct dpif_upcall *upcall; struct dp_netdev_upcall *u = &q->upcalls[q->head++ & QUEUE_MASK];
struct ofpbuf *buf; struct dpif_upcall *upcall = &u->upcall;
size_t key_len; struct ofpbuf *buf = &u->buf;
size_t buf_size;
if (q->head - q->tail >= MAX_QUEUE_LEN) { upcall->type = queue_no;
/* Allocate buffer big enough for everything. */
buf_size = ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size;
if (userdata) {
buf_size += NLA_ALIGN(userdata->nla_len);
}
ofpbuf_init(buf, buf_size);
/* Put ODP flow. */
odp_flow_key_from_flow(buf, flow, flow->in_port);
upcall->key = buf->data;
upcall->key_len = buf->size;
/* Put userdata. */
if (userdata) {
upcall->userdata = ofpbuf_put(buf, userdata,
NLA_ALIGN(userdata->nla_len));
}
/* Put packet.
*
* We adjust 'data' and 'size' in 'buf' so that only the packet itself
* is visible in 'upcall->packet'. The ODP flow and (if present)
* userdata become part of the headroom. */
ofpbuf_put_zeros(buf, 2);
buf->data = ofpbuf_put(buf, packet->data, packet->size);
buf->size = packet->size;
upcall->packet = buf;
return 0;
} else {
dp->n_lost++; dp->n_lost++;
return ENOBUFS; return ENOBUFS;
} }
u = &q->upcalls[q->head++ & QUEUE_MASK];
buf = &u->buf;
ofpbuf_init(buf, ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size);
odp_flow_key_from_flow(buf, flow, flow->in_port);
key_len = buf->size;
ofpbuf_pull(buf, key_len);
ofpbuf_reserve(buf, 2);
ofpbuf_put(buf, packet->data, packet->size);
upcall = &u->upcall;
upcall->type = queue_no;
upcall->packet = buf;
upcall->key = buf->base;
upcall->key_len = key_len;
upcall->userdata = arg;
return 0;
} }
static void static void
@@ -1180,11 +1194,9 @@ dp_netdev_action_userspace(struct dp_netdev *dp,
struct ofpbuf *packet, struct flow *key, struct ofpbuf *packet, struct flow *key,
const struct nlattr *a) const struct nlattr *a)
{ {
const struct nlattr *userdata_attr; const struct nlattr *userdata;
uint64_t userdata;
userdata_attr = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA); userdata = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA);
userdata = userdata_attr ? nl_attr_get_u64(userdata_attr) : 0;
dp_netdev_output_userspace(dp, packet, DPIF_UC_ACTION, key, userdata); dp_netdev_output_userspace(dp, packet, DPIF_UC_ACTION, key, userdata);
} }

View File

@@ -540,10 +540,10 @@ const char *dpif_upcall_type_to_string(enum dpif_upcall_type);
/* A packet passed up from the datapath to userspace. /* A packet passed up from the datapath to userspace.
* *
* If 'key' or 'actions' is nonnull, then it points into data owned by * If 'key', 'actions', or 'userdata' is nonnull, then it points into data
* 'packet', so their memory cannot be freed separately. (This is hardly a * owned by 'packet', so their memory cannot be freed separately. (This is
* great way to do things but it works out OK for the dpif providers and * hardly a great way to do things but it works out OK for the dpif providers
* clients that exist so far.) * and clients that exist so far.)
*/ */
struct dpif_upcall { struct dpif_upcall {
/* All types. */ /* All types. */
@@ -553,7 +553,7 @@ struct dpif_upcall {
size_t key_len; /* Length of 'key' in bytes. */ size_t key_len; /* Length of 'key' in bytes. */
/* DPIF_UC_ACTION only. */ /* DPIF_UC_ACTION only. */
uint64_t userdata; /* Argument to OVS_ACTION_ATTR_USERSPACE. */ struct nlattr *userdata; /* Argument to OVS_ACTION_ATTR_USERSPACE. */
}; };
int dpif_recv_set(struct dpif *, bool enable); int dpif_recv_set(struct dpif *, bool enable);

View File

@@ -248,9 +248,11 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
{ {
static const struct nl_policy ovs_userspace_policy[] = { static const struct nl_policy ovs_userspace_policy[] = {
[OVS_USERSPACE_ATTR_PID] = { .type = NL_A_U32 }, [OVS_USERSPACE_ATTR_PID] = { .type = NL_A_U32 },
[OVS_USERSPACE_ATTR_USERDATA] = { .type = NL_A_U64, .optional = true }, [OVS_USERSPACE_ATTR_USERDATA] = { .type = NL_A_UNSPEC,
.optional = true },
}; };
struct nlattr *a[ARRAY_SIZE(ovs_userspace_policy)]; struct nlattr *a[ARRAY_SIZE(ovs_userspace_policy)];
const struct nlattr *userdata_attr;
if (!nl_parse_nested(attr, ovs_userspace_policy, a, ARRAY_SIZE(a))) { if (!nl_parse_nested(attr, ovs_userspace_policy, a, ARRAY_SIZE(a))) {
ds_put_cstr(ds, "userspace(error)"); ds_put_cstr(ds, "userspace(error)");
@@ -260,7 +262,8 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
ds_put_format(ds, "userspace(pid=%"PRIu32, ds_put_format(ds, "userspace(pid=%"PRIu32,
nl_attr_get_u32(a[OVS_USERSPACE_ATTR_PID])); nl_attr_get_u32(a[OVS_USERSPACE_ATTR_PID]));
if (a[OVS_USERSPACE_ATTR_USERDATA]) { userdata_attr = a[OVS_USERSPACE_ATTR_USERDATA];
if (userdata_attr && nl_attr_get_size(userdata_attr) == sizeof(uint64_t)) {
uint64_t userdata = nl_attr_get_u64(a[OVS_USERSPACE_ATTR_USERDATA]); uint64_t userdata = nl_attr_get_u64(a[OVS_USERSPACE_ATTR_USERDATA]);
union user_action_cookie cookie; union user_action_cookie cookie;
@@ -287,6 +290,16 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
ds_put_format(ds, ",userdata=0x%"PRIx64, userdata); ds_put_format(ds, ",userdata=0x%"PRIx64, userdata);
break; break;
} }
} else if (userdata_attr) {
const uint8_t *userdata = nl_attr_get(userdata_attr);
size_t len = nl_attr_get_size(userdata_attr);
size_t i;
ds_put_format(ds, ",userdata(");
for (i = 0; i < len; i++) {
ds_put_format(ds, "%02x", userdata[i]);
}
ds_put_char(ds, ')');
} }
ds_put_char(ds, ')'); ds_put_char(ds, ')');
@@ -449,7 +462,7 @@ parse_odp_action(const char *s, const struct simap *port_names,
int n = -1; int n = -1;
if (sscanf(s, "userspace(pid=%lli)%n", &pid, &n) > 0 && n > 0) { if (sscanf(s, "userspace(pid=%lli)%n", &pid, &n) > 0 && n > 0) {
odp_put_userspace_action(pid, NULL, actions); odp_put_userspace_action(pid, NULL, 0, actions);
return n; return n;
} else if (sscanf(s, "userspace(pid=%lli,sFlow(vid=%i," } else if (sscanf(s, "userspace(pid=%lli,sFlow(vid=%i,"
"pcp=%i,output=%lli))%n", "pcp=%i,output=%lli))%n",
@@ -465,7 +478,7 @@ parse_odp_action(const char *s, const struct simap *port_names,
cookie.type = USER_ACTION_COOKIE_SFLOW; cookie.type = USER_ACTION_COOKIE_SFLOW;
cookie.sflow.vlan_tci = htons(tci); cookie.sflow.vlan_tci = htons(tci);
cookie.sflow.output = output; cookie.sflow.output = output;
odp_put_userspace_action(pid, &cookie, actions); odp_put_userspace_action(pid, &cookie, sizeof cookie, actions);
return n; 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) { && n > 0) {
@@ -487,18 +500,29 @@ parse_odp_action(const char *s, const struct simap *port_names,
} }
n++; n++;
odp_put_userspace_action(pid, &cookie, actions); odp_put_userspace_action(pid, &cookie, sizeof cookie, actions);
return n; return n;
} else if (sscanf(s, "userspace(pid=%lli,userdata=" } else if (sscanf(s, "userspace(pid=%lli,userdata="
"%31[x0123456789abcdefABCDEF])%n", &pid, userdata_s, "%31[x0123456789abcdefABCDEF])%n", &pid, userdata_s,
&n) > 0 && n > 0) { &n) > 0 && n > 0) {
union user_action_cookie cookie;
uint64_t userdata; uint64_t userdata;
userdata = strtoull(userdata_s, NULL, 0); userdata = strtoull(userdata_s, NULL, 0);
memcpy(&cookie, &userdata, sizeof cookie); odp_put_userspace_action(pid, &userdata, sizeof(userdata),
odp_put_userspace_action(pid, &cookie, actions); actions);
return n; return n;
} else if (sscanf(s, "userspace(pid=%lli,userdata(%n", &pid, &n) > 0
&& n > 0) {
struct ofpbuf buf;
char *end;
ofpbuf_init(&buf, 16);
end = ofpbuf_put_hex(&buf, &s[n], NULL);
if (end[0] == ')' && end[1] == ')') {
odp_put_userspace_action(pid, buf.data, buf.size, actions);
ofpbuf_uninit(&buf);
return (end + 2) - s;
}
} }
} }
@@ -2113,25 +2137,30 @@ odp_key_fitness_to_string(enum odp_key_fitness fitness)
} }
/* Appends an OVS_ACTION_ATTR_USERSPACE action to 'odp_actions' that specifies /* Appends an OVS_ACTION_ATTR_USERSPACE action to 'odp_actions' that specifies
* Netlink PID 'pid'. If 'cookie' is nonnull, adds a userdata attribute whose * Netlink PID 'pid'. If 'userdata' is nonnull, adds a userdata attribute
* contents contains 'cookie' and returns the offset within 'odp_actions' of * whose contents are the 'userdata_size' bytes at 'userdata' and returns the
* the start of the cookie. (If 'cookie' is null, then the return value is not * offset within 'odp_actions' of the start of the cookie. (If 'userdata' is
* meaningful.) */ * null, then the return value is not meaningful.) */
size_t size_t
odp_put_userspace_action(uint32_t pid, const union user_action_cookie *cookie, odp_put_userspace_action(uint32_t pid,
const void *userdata, size_t userdata_size,
struct ofpbuf *odp_actions) struct ofpbuf *odp_actions)
{ {
size_t userdata_ofs;
size_t offset; size_t offset;
offset = nl_msg_start_nested(odp_actions, OVS_ACTION_ATTR_USERSPACE); offset = nl_msg_start_nested(odp_actions, OVS_ACTION_ATTR_USERSPACE);
nl_msg_put_u32(odp_actions, OVS_USERSPACE_ATTR_PID, pid); nl_msg_put_u32(odp_actions, OVS_USERSPACE_ATTR_PID, pid);
if (cookie) { if (userdata) {
userdata_ofs = odp_actions->size + NLA_HDRLEN;
nl_msg_put_unspec(odp_actions, OVS_USERSPACE_ATTR_USERDATA, nl_msg_put_unspec(odp_actions, OVS_USERSPACE_ATTR_USERDATA,
cookie, sizeof *cookie); userdata, userdata_size);
} else {
userdata_ofs = 0;
} }
nl_msg_end_nested(odp_actions, offset); nl_msg_end_nested(odp_actions, offset);
return cookie ? odp_actions->size - NLA_ALIGN(sizeof *cookie) : 0; return userdata_ofs;
} }
void void

View File

@@ -152,7 +152,7 @@ union user_action_cookie {
BUILD_ASSERT_DECL(sizeof(union user_action_cookie) == 8); BUILD_ASSERT_DECL(sizeof(union user_action_cookie) == 8);
size_t odp_put_userspace_action(uint32_t pid, size_t odp_put_userspace_action(uint32_t pid,
const union user_action_cookie *, const void *userdata, size_t userdata_size,
struct ofpbuf *odp_actions); struct ofpbuf *odp_actions);
void odp_put_tunnel_action(const struct flow_tnl *tunnel, void odp_put_tunnel_action(const struct flow_tnl *tunnel,
struct ofpbuf *odp_actions); struct ofpbuf *odp_actions);

View File

@@ -3888,7 +3888,16 @@ classify_upcall(const struct dpif_upcall *upcall)
} }
/* "action" upcalls need a closer look. */ /* "action" upcalls need a closer look. */
memcpy(&cookie, &upcall->userdata, sizeof(cookie)); if (!upcall->userdata) {
VLOG_WARN_RL(&rl, "action upcall missing cookie");
return BAD_UPCALL;
}
if (nl_attr_get_size(upcall->userdata) != sizeof(cookie)) {
VLOG_WARN_RL(&rl, "action upcall cookie has unexpected size %zu",
nl_attr_get_size(upcall->userdata));
return BAD_UPCALL;
}
memcpy(&cookie, nl_attr_get(upcall->userdata), sizeof(cookie));
switch (cookie.type) { switch (cookie.type) {
case USER_ACTION_COOKIE_SFLOW: case USER_ACTION_COOKIE_SFLOW:
return SFLOW_UPCALL; return SFLOW_UPCALL;
@@ -3898,7 +3907,8 @@ classify_upcall(const struct dpif_upcall *upcall)
case USER_ACTION_COOKIE_UNSPEC: case USER_ACTION_COOKIE_UNSPEC:
default: default:
VLOG_WARN_RL(&rl, "invalid user cookie : 0x%"PRIx64, upcall->userdata); VLOG_WARN_RL(&rl, "invalid user cookie : 0x%"PRIx64,
nl_attr_get_u64(upcall->userdata));
return BAD_UPCALL; return BAD_UPCALL;
} }
} }
@@ -3918,7 +3928,7 @@ handle_sflow_upcall(struct dpif_backer *backer,
return; return;
} }
memcpy(&cookie, &upcall->userdata, sizeof(cookie)); memcpy(&cookie, nl_attr_get(upcall->userdata), sizeof(cookie));
dpif_sflow_received(ofproto->sflow, upcall->packet, &flow, dpif_sflow_received(ofproto->sflow, upcall->packet, &flow,
odp_in_port, &cookie); odp_in_port, &cookie);
} }
@@ -5578,7 +5588,7 @@ compose_slow_path(const struct ofproto_dpif *ofproto, const struct flow *flow,
ofpbuf_use_stack(&buf, stub, stub_size); ofpbuf_use_stack(&buf, stub, stub_size);
if (slow & (SLOW_CFM | SLOW_LACP | SLOW_STP)) { if (slow & (SLOW_CFM | SLOW_LACP | SLOW_STP)) {
uint32_t pid = dpif_port_get_pid(ofproto->backer->dpif, UINT32_MAX); uint32_t pid = dpif_port_get_pid(ofproto->backer->dpif, UINT32_MAX);
odp_put_userspace_action(pid, &cookie, &buf); odp_put_userspace_action(pid, &cookie, sizeof cookie, &buf);
} else { } else {
put_userspace_action(ofproto, &buf, flow, &cookie); put_userspace_action(ofproto, &buf, flow, &cookie);
} }
@@ -5597,7 +5607,7 @@ put_userspace_action(const struct ofproto_dpif *ofproto,
pid = dpif_port_get_pid(ofproto->backer->dpif, pid = dpif_port_get_pid(ofproto->backer->dpif,
ofp_port_to_odp_port(ofproto, flow->in_port)); ofp_port_to_odp_port(ofproto, flow->in_port));
return odp_put_userspace_action(pid, cookie, odp_actions); return odp_put_userspace_action(pid, cookie, sizeof *cookie, odp_actions);
} }
static void static void

View File

@@ -89,6 +89,7 @@ userspace(pid=9765,slow_path())
userspace(pid=9765,slow_path(cfm)) userspace(pid=9765,slow_path(cfm))
userspace(pid=9765,slow_path(cfm,match)) userspace(pid=9765,slow_path(cfm,match))
userspace(pid=9123,userdata=0x815309) userspace(pid=9123,userdata=0x815309)
userspace(pid=1234567,userdata(0102030405060708090a0b0c0d0e0f))
set(tun_id(0x7f10354)) set(tun_id(0x7f10354))
set(in_port(2)) set(in_port(2))
set(eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15)) set(eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15))