Reviewed by Justin Pettit.
[ODP_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED },
};
-static int execute_packet(const struct odp_upcall __user *uodp_upcall)
+static int execute_packet(const struct odp_packet __user *uodp_packet)
{
struct nlattr *a[ODP_PACKET_ATTR_MAX + 1];
- struct odp_upcall *odp_upcall;
+ struct odp_packet *odp_packet;
struct sk_buff *skb, *packet;
unsigned int actions_len;
struct nlattr *actions;
u32 len;
int err;
- if (get_user(len, &uodp_upcall->len))
+ if (get_user(len, &uodp_packet->len))
return -EFAULT;
- if (len < sizeof(struct odp_upcall))
+ if (len < sizeof(struct odp_packet))
return -EINVAL;
skb = alloc_skb(len, GFP_KERNEL);
return -ENOMEM;
err = -EFAULT;
- if (copy_from_user(__skb_put(skb, len), uodp_upcall, len))
+ if (copy_from_user(__skb_put(skb, len), uodp_packet, len))
goto exit_free_skb;
- odp_upcall = (struct odp_upcall *)skb->data;
+ odp_packet = (struct odp_packet *)skb->data;
err = -EINVAL;
- if (odp_upcall->len != len)
+ if (odp_packet->len != len)
goto exit_free_skb;
- __skb_pull(skb, sizeof(struct odp_upcall));
+ __skb_pull(skb, sizeof(struct odp_packet));
err = nla_parse(a, ODP_PACKET_ATTR_MAX, (struct nlattr *)skb->data,
skb->len, execute_policy);
if (err)
goto exit_free_skb;
rcu_read_lock();
- dp = get_dp(odp_upcall->dp_idx);
+ dp = get_dp(odp_packet->dp_idx);
err = -ENODEV;
if (dp)
err = execute_actions(dp, packet, &key, actions, actions_len);
goto exit;
case ODP_EXECUTE:
- err = execute_packet((struct odp_upcall __user *)argp);
+ err = execute_packet((struct odp_packet __user *)argp);
goto exit;
}
#define ODP_FLOW_DUMP _IOWR('O', 17, struct odp_flow)
#define ODP_FLOW_FLUSH _IO('O', 19)
-#define ODP_EXECUTE _IOR('O', 18, struct odp_upcall)
+#define ODP_EXECUTE _IOR('O', 18, struct odp_packet)
/**
* struct odp_datapath - header with basic information about a datapath.
const struct ofpbuf *packet)
{
struct dpif_linux *dpif = dpif_linux_cast(dpif_);
- struct odp_upcall *execute;
+ struct odp_packet *execute;
struct ofpbuf *buf;
int error;
struct odp_packet *odp_packet = buf->data;
struct nlattr *a[ARRAY_SIZE(odp_packet_policy)];
+ uint32_t type;
if (!nl_policy_parse(buf, sizeof *odp_packet, odp_packet_policy,
a, ARRAY_SIZE(odp_packet_policy))) {
}
memset(upcall, 0, sizeof *upcall);
- upcall->type = nl_attr_get_u32(a[ODP_PACKET_ATTR_TYPE]);
+
+ type = nl_attr_get_u32(a[ODP_PACKET_ATTR_TYPE]);
+ upcall->type = (type == _ODPL_MISS_NR ? DPIF_UC_MISS
+ : type == _ODPL_ACTION_NR ? DPIF_UC_ACTION
+ : type == _ODPL_SFLOW_NR ? DPIF_UC_SAMPLE
+ : -1);
+
upcall->packet = buf;
upcall->packet->data = (void *) nl_attr_get(a[ODP_PACKET_ATTR_PACKET]);
upcall->packet->size = nl_attr_get_size(a[ODP_PACKET_ATTR_PACKET]);
dpif_netdev_recv_set_mask(struct dpif *dpif, int listen_mask)
{
struct dpif_netdev *dpif_netdev = dpif_netdev_cast(dpif);
- if (!(listen_mask & ~ODPL_ALL)) {
- dpif_netdev->listen_mask = listen_mask;
- return 0;
- } else {
- return EINVAL;
- }
+ dpif_netdev->listen_mask = listen_mask;
+ return 0;
}
static struct dp_netdev_queue *
dp->n_hit++;
} else {
dp->n_missed++;
- dp_netdev_output_control(dp, packet, _ODPL_MISS_NR, &key, 0);
+ dp_netdev_output_control(dp, packet, DPIF_UC_MISS, &key, 0);
}
}
break;
case ODPAT_CONTROLLER:
- dp_netdev_output_control(dp, packet, _ODPL_ACTION_NR,
+ dp_netdev_output_control(dp, packet, DPIF_UC_ACTION,
key, nl_attr_get_u64(a));
break;
int (*execute)(struct dpif *dpif, const struct nlattr *actions,
size_t actions_len, const struct ofpbuf *packet);
- /* Retrieves 'dpif''s "listen mask" into '*listen_mask'. Each ODPL_* bit
- * set in '*listen_mask' indicates the 'dpif' will receive messages of the
- * corresponding type when it calls the recv member function. */
+ /* Retrieves 'dpif''s "listen mask" into '*listen_mask'. A 1-bit of value
+ * 2**X set in '*listen_mask' indicates that 'dpif' will receive messages
+ * of the type (from "enum dpif_upcall_type") with value X when its 'recv'
+ * function is called. */
int (*recv_get_mask)(const struct dpif *dpif, int *listen_mask);
- /* Sets 'dpif''s "listen mask" to 'listen_mask'. Each ODPL_* bit set in
- * 'listen_mask' indicates the 'dpif' will receive messages of the
- * corresponding type when it calls the recv member function. */
+ /* Sets 'dpif''s "listen mask" to 'listen_mask'. A 1-bit of value 2**X set
+ * in '*listen_mask' requests that 'dpif' will receive messages of the type
+ * (from "enum dpif_upcall_type") with value X when its 'recv' function is
+ * called. */
int (*recv_set_mask)(struct dpif *dpif, int listen_mask);
/* Retrieves 'dpif''s sFlow sampling probability into '*probability'.
return error;
}
-/* Retrieves 'dpif''s "listen mask" into '*listen_mask'. Each ODPL_* bit set
- * in '*listen_mask' indicates that dpif_recv() will receive messages of that
- * type. Returns 0 if successful, otherwise a positive errno value. */
+static bool OVS_UNUSED
+is_valid_listen_mask(int listen_mask)
+{
+ return !(listen_mask & ~((1u << DPIF_UC_MISS) |
+ (1u << DPIF_UC_ACTION) |
+ (1u << DPIF_UC_SAMPLE)));
+}
+
+/* Retrieves 'dpif''s "listen mask" into '*listen_mask'. A 1-bit of value 2**X
+ * set in '*listen_mask' indicates that dpif_recv() will receive messages of
+ * the type (from "enum dpif_upcall_type") with value X. Returns 0 if
+ * successful, otherwise a positive errno value. */
int
dpif_recv_get_mask(const struct dpif *dpif, int *listen_mask)
{
if (error) {
*listen_mask = 0;
}
+ assert(is_valid_listen_mask(*listen_mask));
log_operation(dpif, "recv_get_mask", error);
return error;
}
-/* Sets 'dpif''s "listen mask" to 'listen_mask'. Each ODPL_* bit set in
- * '*listen_mask' requests that dpif_recv() receive messages of that type.
- * Returns 0 if successful, otherwise a positive errno value. */
+/* Sets 'dpif''s "listen mask" to 'listen_mask'. A 1-bit of value 2**X set in
+ * '*listen_mask' requests that dpif_recv() will receive messages of the type
+ * (from "enum dpif_upcall_type") with value X. Returns 0 if successful,
+ * otherwise a positive errno value. */
int
dpif_recv_set_mask(struct dpif *dpif, int listen_mask)
{
- int error = dpif->dpif_class->recv_set_mask(dpif, listen_mask);
+ int error;
+
+ assert(is_valid_listen_mask(listen_mask));
+
+ error = dpif->dpif_class->recv_set_mask(dpif, listen_mask);
log_operation(dpif, "recv_set_mask", error);
return error;
}
}
/* Polls for an upcall from 'dpif'. If successful, stores the upcall into
- * '*upcall'. Only upcalls of the types selected with the set_listen_mask
+ * '*upcall'. Only upcalls of the types selected with dpif_recv_set_mask()
* member function will ordinarily be received (but if a message type is
* enabled and then later disabled, some stragglers might pop up).
*
odp_flow_key_to_flow(upcall->key, upcall->key_len, &flow);
VLOG_DBG("%s: %s upcall on port %"PRIu16": %s", dpif_name(dpif),
- (upcall->type == _ODPL_MISS_NR ? "miss"
- : upcall->type == _ODPL_ACTION_NR ? "action"
- : upcall->type == _ODPL_SFLOW_NR ? "sFlow"
+ (upcall->type == DPIF_UC_MISS ? "miss"
+ : upcall->type == DPIF_UC_ACTION ? "action"
+ : upcall->type == DPIF_UC_SAMPLE ? "sample"
: "<unknown>"),
flow.in_port, s);
free(s);
int dpif_execute(struct dpif *, const struct nlattr *actions,
size_t actions_len, const struct ofpbuf *);
+enum dpif_upcall_type {
+ DPIF_UC_MISS, /* Miss in flow table. */
+ DPIF_UC_ACTION, /* ODPAT_CONTROLLER action. */
+ DPIF_UC_SAMPLE /* Packet sampling. */
+};
+
/* A packet passed up from the datapath to userspace.
*
* If 'key' or 'actions' is nonnull, then it points into data owned by
* clients that exist so far.)
*/
struct dpif_upcall {
- uint32_t type; /* One of _ODPL_*_NR. */
-
/* All types. */
+ enum dpif_upcall_type type;
struct ofpbuf *packet; /* Packet data. */
struct nlattr *key; /* Flow key. */
size_t key_len; /* Length of 'key' in bytes. */
- /* _ODPL_ACTION_NR only. */
+ /* DPIF_UC_ACTION only. */
uint64_t userdata; /* Argument to ODPAT_CONTROLLER. */
- /* _ODPL_SFLOW_NR only. */
+ /* DPIF_UC_SAMPLE only. */
uint32_t sample_pool; /* # of sampling candidate packets so far. */
struct nlattr *actions; /* Associated flow actions. */
size_t actions_len;
/* OFPT_PACKET_IN related data. */
struct rconn_packet_counter *packet_in_counter; /* # queued on 'rconn'. */
- struct pinsched *schedulers[2]; /* Indexed by reason code; see below. */
+#define N_SCHEDULERS 2
+ struct pinsched *schedulers[N_SCHEDULERS];
struct pktbuf *pktbuf; /* OpenFlow packet buffers. */
int miss_send_len; /* Bytes to send of buffered packets. */
enum ofproto_band band; /* In-band or out-of-band? */
};
-/* We use OFPR_NO_MATCH and OFPR_ACTION as indexes into struct ofconn's
- * "schedulers" array. Their values are 0 and 1, and their meanings and values
- * coincide with _ODPL_MISS_NR and _ODPL_ACTION_NR, so this is convenient. In
- * case anything ever changes, check their values here. */
-#define N_SCHEDULERS 2
-BUILD_ASSERT_DECL(OFPR_NO_MATCH == 0);
-BUILD_ASSERT_DECL(OFPR_NO_MATCH == _ODPL_MISS_NR);
-BUILD_ASSERT_DECL(OFPR_ACTION == 1);
-BUILD_ASSERT_DECL(OFPR_ACTION == _ODPL_ACTION_NR);
static struct ofconn *ofconn_create(struct ofproto *, struct rconn *,
enum ofconn_type);
VLOG_ERR("failed to open datapath %s: %s", datapath, strerror(error));
return error;
}
- error = dpif_recv_set_mask(dpif, ODPL_MISS | ODPL_ACTION | ODPL_SFLOW);
+ error = dpif_recv_set_mask(dpif,
+ ((1u << DPIF_UC_MISS) |
+ (1u << DPIF_UC_ACTION) |
+ (1u << DPIF_UC_SAMPLE)));
if (error) {
VLOG_ERR("failed to listen on datapath %s: %s",
datapath, strerror(error));
* buffers along the way. */
struct dpif_upcall upcall;
- upcall.type = _ODPL_ACTION_NR;
+ upcall.type = DPIF_UC_ACTION;
upcall.packet = packet;
upcall.key = NULL;
upcall.key_len = 0;
struct flow flow;
switch (upcall->type) {
- case _ODPL_ACTION_NR:
+ case DPIF_UC_ACTION:
COVERAGE_INC(ofproto_ctlr_action);
odp_flow_key_to_flow(upcall->key, upcall->key_len, &flow);
send_packet_in(p, upcall, &flow, false);
break;
- case _ODPL_SFLOW_NR:
+ case DPIF_UC_SAMPLE:
if (p->sflow) {
odp_flow_key_to_flow(upcall->key, upcall->key_len, &flow);
ofproto_sflow_received(p->sflow, upcall, &flow);
ofpbuf_delete(upcall->packet);
break;
- case _ODPL_MISS_NR:
+ case DPIF_UC_MISS:
handle_miss_upcall(p, upcall);
break;
int total_len, send_len;
struct ofpbuf *packet;
uint32_t buffer_id;
+ int idx;
/* Get OpenFlow buffer_id. */
- if (upcall->type == _ODPL_ACTION_NR) {
+ if (upcall->type == DPIF_UC_ACTION) {
buffer_id = UINT32_MAX;
} else if (ofproto->fail_open && fail_open_is_active(ofproto->fail_open)) {
buffer_id = pktbuf_get_null();
if (buffer_id != UINT32_MAX) {
send_len = MIN(send_len, ofconn->miss_send_len);
}
- if (upcall->type == _ODPL_ACTION_NR) {
+ if (upcall->type == DPIF_UC_ACTION) {
send_len = MIN(send_len, upcall->userdata);
}
opi->header.type = OFPT_PACKET_IN;
opi->total_len = htons(total_len);
opi->in_port = htons(odp_port_to_ofp_port(flow->in_port));
- opi->reason = upcall->type == _ODPL_MISS_NR ? OFPR_NO_MATCH : OFPR_ACTION;
+ opi->reason = upcall->type == DPIF_UC_MISS ? OFPR_NO_MATCH : OFPR_ACTION;
opi->buffer_id = htonl(buffer_id);
update_openflow_length(packet);
/* Hand over to packet scheduler. It might immediately call into
* do_send_packet_in() or it might buffer it for a while (until a later
* call to pinsched_run()). */
- pinsched_send(ofconn->schedulers[opi->reason], flow->in_port,
+ idx = upcall->type == DPIF_UC_MISS ? 0 : 1;
+ pinsched_send(ofconn->schedulers[idx], flow->in_port,
packet, do_send_packet_in, ofconn);
}
-/* Given 'upcall', of type _ODPL_ACTION_NR or _ODPL_MISS_NR, sends an
+/* Given 'upcall', of type DPIF_UC_ACTION or DPIF_UC_MISS, sends an
* OFPT_PACKET_IN message to each OpenFlow controller as necessary according to
* their individual configurations.
*