}
static enum ofperr
-handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh)
+handle_packet_out(struct ofconn *ofconn, const struct ofp_packet_out *opo)
{
struct ofproto *p = ofconn_get_ofproto(ofconn);
- struct ofp_packet_out *opo;
- struct ofpbuf payload, *buffer;
- union ofp_action *ofp_actions;
- struct ofpbuf request;
+ struct ofputil_packet_out po;
+ struct ofpbuf *payload;
struct flow flow;
- size_t n_ofp_actions;
enum ofperr error;
- uint16_t in_port;
COVERAGE_INC(ofproto_packet_out);
return error;
}
- /* Get ofp_packet_out. */
- ofpbuf_use_const(&request, oh, ntohs(oh->length));
- opo = ofpbuf_pull(&request, offsetof(struct ofp_packet_out, actions));
-
- /* Get actions. */
- error = ofputil_pull_actions(&request, ntohs(opo->actions_len),
- &ofp_actions, &n_ofp_actions);
+ /* Decode message. */
+ error = ofputil_decode_packet_out(&po, opo);
if (error) {
return error;
}
/* Get payload. */
- if (opo->buffer_id != htonl(UINT32_MAX)) {
- error = ofconn_pktbuf_retrieve(ofconn, ntohl(opo->buffer_id),
- &buffer, NULL);
- if (error || !buffer) {
+ if (po.buffer_id != UINT32_MAX) {
+ error = ofconn_pktbuf_retrieve(ofconn, po.buffer_id, &payload, NULL);
+ if (error || !payload) {
return error;
}
- payload = *buffer;
} else {
- payload = request;
- buffer = NULL;
- }
-
- /* Get in_port and partially validate it.
- *
- * We don't know what range of ports the ofproto actually implements, but
- * we do know that only certain reserved ports (numbered OFPP_MAX and
- * above) are valid. */
- in_port = ntohs(opo->in_port);
- if (in_port >= OFPP_MAX && in_port != OFPP_LOCAL && in_port != OFPP_NONE) {
- return OFPERR_NXBRC_BAD_IN_PORT;
+ payload = xmalloc(sizeof *payload);
+ ofpbuf_use_const(payload, po.packet, po.packet_len);
}
/* Send out packet. */
- flow_extract(&payload, 0, 0, in_port, &flow);
- error = p->ofproto_class->packet_out(p, &payload, &flow,
- ofp_actions, n_ofp_actions);
- ofpbuf_delete(buffer);
+ flow_extract(payload, 0, 0, po.in_port, &flow);
+ error = p->ofproto_class->packet_out(p, payload, &flow,
+ po.actions, po.n_actions);
+ ofpbuf_delete(payload);
return error;
}
}
static void
-calc_flow_duration__(long long int start, uint32_t *sec, uint32_t *nsec)
+calc_flow_duration__(long long int start, long long int now,
+ uint32_t *sec, uint32_t *nsec)
{
- long long int msecs = time_msec() - start;
+ long long int msecs = now - start;
*sec = msecs / 1000;
*nsec = (msecs % 1000) * (1000 * 1000);
}
return 0;
}
+/* Returns 'age_ms' (a duration in milliseconds), converted to seconds and
+ * forced into the range of a uint16_t. */
+static int
+age_secs(long long int age_ms)
+{
+ return (age_ms < 0 ? 0
+ : age_ms >= UINT16_MAX * 1000 ? UINT16_MAX
+ : (unsigned int) age_ms / 1000);
+}
+
static enum ofperr
handle_flow_stats_request(struct ofconn *ofconn,
const struct ofp_stats_msg *osm)
ofputil_start_stats_reply(osm, &replies);
LIST_FOR_EACH (rule, ofproto_node, &rules) {
+ long long int now = time_msec();
struct ofputil_flow_stats fs;
fs.rule = rule->cr;
fs.cookie = rule->flow_cookie;
fs.table_id = rule->table_id;
- calc_flow_duration__(rule->created, &fs.duration_sec,
+ calc_flow_duration__(rule->created, now, &fs.duration_sec,
&fs.duration_nsec);
fs.idle_timeout = rule->idle_timeout;
fs.hard_timeout = rule->hard_timeout;
+ fs.idle_age = age_secs(now - rule->used);
+ fs.hard_age = age_secs(now - rule->modified);
ofproto->ofproto_class->rule_get_stats(rule, &fs.packet_count,
&fs.byte_count);
fs.actions = rule->actions;
ofproto->ofproto_class->get_netflow_ids(ofproto, engine_type, engine_id);
}
-/* Checks the fault status of CFM for 'ofp_port' within 'ofproto'. Returns 1
- * if CFM is faulted (generally indiciating a connectivity problem), 0 if CFM
- * is not faulted, and -1 if CFM is not enabled on 'ofp_port'. */
+/* Checks the fault status of CFM for 'ofp_port' within 'ofproto'. Returns a
+ * bitmask of 'cfm_fault_reason's to indicate a CFM fault (generally
+ * indicating a connectivity problem). Returns zero if CFM is not faulted,
+ * and -1 if CFM is not enabled on 'port'. */
int
ofproto_port_get_cfm_fault(const struct ofproto *ofproto, uint16_t ofp_port)
{
fr.rule = rule->cr;
fr.cookie = rule->flow_cookie;
fr.reason = reason;
- calc_flow_duration__(rule->created, &fr.duration_sec, &fr.duration_nsec);
+ calc_flow_duration__(rule->created, time_msec(),
+ &fr.duration_sec, &fr.duration_nsec);
fr.idle_timeout = rule->idle_timeout;
rule->ofproto->ofproto_class->rule_get_stats(rule, &fr.packet_count,
&fr.byte_count);
return error;
}
- error = ofputil_decode_flow_mod(&fm, oh,
- ofconn_get_flow_mod_table_id(ofconn));
+ error = ofputil_decode_flow_mod(&fm, oh, ofconn_get_protocol(ofconn));
if (error) {
return error;
}
struct ofpbuf *buf;
uint32_t role;
- if (ofconn_get_type(ofconn) != OFCONN_PRIMARY) {
- return OFPERR_OFPBRC_EPERM;
- }
-
role = ntohl(nrr->role);
if (role != NX_ROLE_OTHER && role != NX_ROLE_MASTER
&& role != NX_ROLE_SLAVE) {
{
const struct nx_flow_mod_table_id *msg
= (const struct nx_flow_mod_table_id *) oh;
+ enum ofputil_protocol cur, next;
+
+ cur = ofconn_get_protocol(ofconn);
+ next = ofputil_protocol_set_tid(cur, msg->set != 0);
+ ofconn_set_protocol(ofconn, next);
- ofconn_set_flow_mod_table_id(ofconn, msg->set != 0);
return 0;
}
{
const struct nx_set_flow_format *msg
= (const struct nx_set_flow_format *) oh;
- uint32_t format;
+ enum ofputil_protocol cur, next;
+ enum ofputil_protocol next_base;
- format = ntohl(msg->format);
- if (format != NXFF_OPENFLOW10 && format != NXFF_NXM) {
+ next_base = ofputil_nx_flow_format_to_protocol(ntohl(msg->format));
+ if (!next_base) {
return OFPERR_OFPBRC_EPERM;
}
- if (format != ofconn_get_flow_format(ofconn)
- && ofconn_has_pending_opgroups(ofconn)) {
- /* Avoid sending async messages in surprising flow format. */
+ cur = ofconn_get_protocol(ofconn);
+ next = ofputil_protocol_set_base(cur, next_base);
+ if (cur != next && ofconn_has_pending_opgroups(ofconn)) {
+ /* Avoid sending async messages in surprising protocol. */
return OFPROTO_POSTPONE;
}
- ofconn_set_flow_format(ofconn, format);
+ ofconn_set_protocol(ofconn, next);
return 0;
}
return 0;
}
+static enum ofperr
+handle_nxt_set_async_config(struct ofconn *ofconn, const struct ofp_header *oh)
+{
+ const struct nx_async_config *msg = (const struct nx_async_config *) oh;
+ uint32_t master[OAM_N_TYPES];
+ uint32_t slave[OAM_N_TYPES];
+
+ master[OAM_PACKET_IN] = ntohl(msg->packet_in_mask[0]);
+ master[OAM_PORT_STATUS] = ntohl(msg->port_status_mask[0]);
+ master[OAM_FLOW_REMOVED] = ntohl(msg->flow_removed_mask[0]);
+
+ slave[OAM_PACKET_IN] = ntohl(msg->packet_in_mask[1]);
+ slave[OAM_PORT_STATUS] = ntohl(msg->port_status_mask[1]);
+ slave[OAM_FLOW_REMOVED] = ntohl(msg->flow_removed_mask[1]);
+
+ ofconn_set_async_config(ofconn, master, slave);
+
+ return 0;
+}
+
+static enum ofperr
+handle_nxt_set_controller_id(struct ofconn *ofconn,
+ const struct ofp_header *oh)
+{
+ const struct nx_controller_id *nci;
+
+ nci = (const struct nx_controller_id *) oh;
+ if (!is_all_zeros(nci->zero, sizeof nci->zero)) {
+ return OFPERR_NXBRC_MUST_BE_ZERO;
+ }
+
+ ofconn_set_controller_id(ofconn, ntohs(nci->controller_id));
+ return 0;
+}
+
static enum ofperr
handle_barrier_request(struct ofconn *ofconn, const struct ofp_header *oh)
{
return handle_set_config(ofconn, msg->data);
case OFPUTIL_OFPT_PACKET_OUT:
- return handle_packet_out(ofconn, oh);
+ return handle_packet_out(ofconn, msg->data);
case OFPUTIL_OFPT_PORT_MOD:
return handle_port_mod(ofconn, oh);
case OFPUTIL_NXT_SET_PACKET_IN_FORMAT:
return handle_nxt_set_packet_in_format(ofconn, oh);
+ case OFPUTIL_NXT_SET_CONTROLLER_ID:
+ return handle_nxt_set_controller_id(ofconn, oh);
+
case OFPUTIL_NXT_FLOW_MOD:
return handle_flow_mod(ofconn, oh);
+ case OFPUTIL_NXT_FLOW_AGE:
+ /* Nothing to do. */
+ return 0;
+
+ case OFPUTIL_NXT_SET_ASYNC_CONFIG:
+ return handle_nxt_set_async_config(ofconn, oh);
+
/* Statistics requests. */
case OFPUTIL_OFPST_DESC_REQUEST:
return handle_desc_stats_request(ofconn, msg->data);
HMAP_FOR_EACH (ofproto, hmap_node, &all_ofprotos) {
ds_put_format(&results, "%s\n", ofproto->name);
}
- unixctl_command_reply(conn, 200, ds_cstr(&results));
+ unixctl_command_reply(conn, ds_cstr(&results));
ds_destroy(&results);
}