desc->features = 0;
desc->speed = 0;
- if (p->port_no < 255) {
- /* FIXME: this is a layering violation and should really be
- * done in the secchan, as with OFPC_STP in
- * OFP_SUPPORTED_CAPABILITIES. */
- desc->features |= OFPPF_STP;
- }
-
spin_lock_irqsave(&p->lock, flags);
desc->flags = htonl(p->flags | p->status);
spin_unlock_irqrestore(&p->lock, flags);
return send_openflow_skb(skb, sender);
}
+int
+dp_send_hello(struct datapath *dp, const struct sender *sender,
+ const struct ofp_header *request)
+{
+ if (request->version < OFP_VERSION) {
+ char err[64];
+ sprintf(err, "Only version 0x%02x supported", OFP_VERSION);
+ dp_send_error_msg(dp, sender, OFPET_HELLO_FAILED,
+ OFPHFC_INCOMPATIBLE, err, strlen(err));
+ return -EINVAL;
+ } else {
+ struct sk_buff *skb;
+ struct ofp_header *reply;
+
+ reply = alloc_openflow_skb(dp, sizeof *reply,
+ OFPT_HELLO, sender, &skb);
+ if (!reply)
+ return -ENOMEM;
+
+ return send_openflow_skb(skb, sender);
+ }
+}
+
/* Callback function for a workqueue to disable an interface */
static void
down_port_cb(struct work_struct *work)
int
dp_send_error_msg(struct datapath *dp, const struct sender *sender,
- uint16_t type, uint16_t code, const uint8_t *data, size_t len)
+ uint16_t type, uint16_t code, const void *data, size_t len)
{
struct sk_buff *skb;
struct ofp_error_msg *oem;
- oem = alloc_openflow_skb(dp, sizeof(*oem)+len, OFPT_ERROR_MSG,
+ oem = alloc_openflow_skb(dp, sizeof(*oem)+len, OFPT_ERROR,
sender, &skb);
if (!oem)
return -ENOMEM;
static int flow_stats_dump_callback(struct sw_flow *flow, void *private)
{
+ struct sw_flow_actions *sf_acts = rcu_dereference(flow->sf_acts);
struct flow_stats_state *s = private;
struct ofp_flow_stats *ofs;
int actions_length;
int length;
- actions_length = sizeof *ofs->actions * flow->n_actions;
- length = sizeof *ofs + sizeof *ofs->actions * flow->n_actions;
+ actions_length = sizeof *ofs->actions * sf_acts->n_actions;
+ length = sizeof *ofs + actions_length;
if (length + s->bytes_used > s->bytes_allocated)
return 1;
memset(ofs->pad2, 0, sizeof ofs->pad2);
ofs->packet_count = cpu_to_be64(flow->packet_count);
ofs->byte_count = cpu_to_be64(flow->byte_count);
- memcpy(ofs->actions, flow->actions, actions_length);
+ memcpy(ofs->actions, sf_acts->actions, actions_length);
s->bytes_used += length;
return 0;
memset(ots->pad, 0, sizeof ots->pad);
ots->max_entries = htonl(stats.max_flows);
ots->active_count = htonl(stats.n_flows);
+ ots->lookup_count = cpu_to_be64(stats.n_lookup);
ots->matched_count = cpu_to_be64(stats.n_matched);
}
return 0;
* struct genl_ops. This kluge supports earlier versions also. */
cb->done = dp_genl_openflow_done;
+ sender.pid = NETLINK_CB(cb->skb).pid;
+ sender.seq = cb->nlh->nlmsg_seq;
if (!cb->args[0]) {
struct nlattr *attrs[DP_GENL_A_MAX + 1];
struct ofp_stats_request *rq;
return -EINVAL;
rq = nla_data(va);
+ sender.xid = rq->header.xid;
type = ntohs(rq->type);
- if (rq->header.version != OFP_VERSION
- || rq->header.type != OFPT_STATS_REQUEST
- || ntohs(rq->header.length) != len
- || type >= ARRAY_SIZE(stats)
- || !stats[type].dump)
+ if (rq->header.version != OFP_VERSION) {
+ dp_send_error_msg(dp, &sender, OFPET_BAD_REQUEST,
+ OFPBRC_BAD_VERSION, rq, len);
+ return -EINVAL;
+ }
+ if (rq->header.type != OFPT_STATS_REQUEST
+ || ntohs(rq->header.length) != len)
+ return -EINVAL;
+
+ if (type >= ARRAY_SIZE(stats) || !stats[type].dump) {
+ dp_send_error_msg(dp, &sender, OFPET_BAD_REQUEST,
+ OFPBRC_BAD_STAT, rq, len);
return -EINVAL;
+ }
s = &stats[type];
body_len = len - offsetof(struct ofp_stats_request, body);
cb->args[4] = (long) state;
}
} else if (cb->args[0] == 1) {
+ sender.xid = cb->args[3];
dp_idx = cb->args[1];
s = &stats[cb->args[2]];
return 0;
}
- sender.xid = cb->args[3];
- sender.pid = NETLINK_CB(cb->skb).pid;
- sender.seq = cb->nlh->nlmsg_seq;
-
osr = put_openflow_headers(dp, skb, OFPT_STATS_REPLY, &sender,
&max_openflow_len);
if (IS_ERR(osr))