Introduce ofputil_protocol, to abstract the protocol in use on a connection.
[sliver-openvswitch.git] / ofproto / ofproto.c
index fe3b620..25303ad 100644 (file)
@@ -1953,17 +1953,13 @@ reject_slave_controller(struct ofconn *ofconn)
 }
 
 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);
 
@@ -1972,45 +1968,28 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh)
         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;
 }
@@ -3002,8 +2981,7 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh)
         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;
     }
@@ -3088,8 +3066,12 @@ handle_nxt_flow_mod_table_id(struct ofconn *ofconn,
 {
     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;
 }
 
@@ -3098,20 +3080,22 @@ handle_nxt_set_flow_format(struct ofconn *ofconn, const struct ofp_header *oh)
 {
     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;
 }
 
@@ -3138,6 +3122,41 @@ handle_nxt_set_packet_in_format(struct ofconn *ofconn,
     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)
 {
@@ -3180,7 +3199,7 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
         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);
@@ -3208,6 +3227,9 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
     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);
 
@@ -3215,6 +3237,9 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
         /* 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);
@@ -3963,7 +3988,7 @@ ofproto_unixctl_list(struct unixctl_conn *conn, int argc OVS_UNUSED,
     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);
 }