ofp-msgs: Split OFPRAW_OFPST_FLOW_{REQUEST,REPLY}
[sliver-openvswitch.git] / lib / ofp-util.c
index 36f1c8a..0cf48e6 100644 (file)
@@ -1453,7 +1453,7 @@ ofputil_decode_flow_stats_request(struct ofputil_flow_stats_request *fsr,
     ofpbuf_use_const(&b, oh, ntohs(oh->length));
     raw = ofpraw_pull_assert(&b);
     switch ((int) raw) {
-    case OFPRAW_OFPST_FLOW_REQUEST:
+    case OFPRAW_OFPST10_FLOW_REQUEST:
         return ofputil_decode_ofpst_flow_request(fsr, b.data, false);
 
     case OFPRAW_OFPST_AGGREGATE_REQUEST:
@@ -1482,13 +1482,30 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
     enum ofpraw raw;
 
     switch (protocol) {
+    case OFPUTIL_P_OF12: {
+        struct ofp11_flow_stats_request *ofsr;
+
+        raw = (fsr->aggregate
+               ? OFPRAW_OFPST_AGGREGATE_REQUEST
+               : OFPRAW_OFPST11_FLOW_REQUEST);
+        msg = ofpraw_alloc(raw, OFP12_VERSION, NXM_TYPICAL_LEN);
+        ofsr = ofpbuf_put_zeros(msg, sizeof *ofsr);
+        ofsr->table_id = fsr->table_id;
+        ofsr->out_port = ofputil_port_to_ofp11(fsr->out_port);
+        ofsr->out_group = htonl(OFPG11_ANY);
+        ofsr->cookie = fsr->cookie;
+        ofsr->cookie_mask = fsr->cookie_mask;
+        oxm_put_match(msg, &fsr->match);
+        break;
+    }
+
     case OFPUTIL_P_OF10:
     case OFPUTIL_P_OF10_TID: {
         struct ofp10_flow_stats_request *ofsr;
 
         raw = (fsr->aggregate
                ? OFPRAW_OFPST_AGGREGATE_REQUEST
-               : OFPRAW_OFPST_FLOW_REQUEST);
+               : OFPRAW_OFPST10_FLOW_REQUEST);
         msg = ofpraw_alloc(raw, OFP10_VERSION, 0);
         ofsr = ofpbuf_put_zeros(msg, sizeof *ofsr);
         ofputil_cls_rule_to_ofp10_match(&fsr->match, &ofsr->match);
@@ -1505,7 +1522,7 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
         raw = (fsr->aggregate
                ? OFPRAW_NXST_AGGREGATE_REQUEST
                : OFPRAW_NXST_FLOW_REQUEST);
-        msg = ofpraw_alloc(raw, OFP10_VERSION, 0);
+        msg = ofpraw_alloc(raw, OFP10_VERSION, NXM_TYPICAL_LEN);
         ofpbuf_put_zeros(msg, sizeof *nfsr);
         match_len = nx_put_match(msg, &fsr->match,
                                  fsr->cookie, fsr->cookie_mask);
@@ -1517,7 +1534,6 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
         break;
     }
 
-    case OFPUTIL_P_OF12:
     default:
         NOT_REACHED();
     }
@@ -1580,7 +1596,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
 
     if (!msg->size) {
         return EOF;
-    } else if (raw == OFPRAW_OFPST_FLOW_REPLY) {
+    } else if (raw == OFPRAW_OFPST10_FLOW_REPLY) {
         const struct ofp10_flow_stats *ofs;
         size_t length;
 
@@ -1692,7 +1708,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
     enum ofpraw raw;
 
     ofpraw_decode_partial(&raw, reply->data, reply->size);
-    if (raw == OFPRAW_OFPST_FLOW_REPLY) {
+    if (raw == OFPRAW_OFPST10_FLOW_REPLY) {
         struct ofp10_flow_stats *ofs;
 
         ofpbuf_put_uninit(reply, sizeof *ofs);
@@ -1809,7 +1825,28 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
 
     ofpbuf_use_const(&b, oh, ntohs(oh->length));
     raw = ofpraw_pull_assert(&b);
-    if (raw == OFPRAW_OFPT10_FLOW_REMOVED) {
+    if (raw == OFPRAW_OFPT11_FLOW_REMOVED) {
+        const struct ofp12_flow_removed *ofr;
+        enum ofperr error;
+
+        ofr = ofpbuf_pull(&b, sizeof *ofr);
+
+        error = ofputil_pull_ofp11_match(&b, ntohs(ofr->priority),
+                                         &fr->rule, NULL);
+        if (error) {
+            return error;
+        }
+
+        fr->cookie = ofr->cookie;
+        fr->reason = ofr->reason;
+        /* XXX: ofr->table_id is ignored */
+        fr->duration_sec = ntohl(ofr->duration_sec);
+        fr->duration_nsec = ntohl(ofr->duration_nsec);
+        fr->idle_timeout = ntohs(ofr->idle_timeout);
+        fr->hard_timeout = ntohs(ofr->hard_timeout);
+        fr->packet_count = ntohll(ofr->packet_count);
+        fr->byte_count = ntohll(ofr->byte_count);
+    } else if (raw == OFPRAW_OFPT10_FLOW_REMOVED) {
         const struct ofp_flow_removed *ofr;
 
         ofr = ofpbuf_pull(&b, sizeof *ofr);
@@ -1821,6 +1858,7 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
         fr->duration_sec = ntohl(ofr->duration_sec);
         fr->duration_nsec = ntohl(ofr->duration_nsec);
         fr->idle_timeout = ntohs(ofr->idle_timeout);
+        fr->hard_timeout = 0;
         fr->packet_count = ntohll(ofr->packet_count);
         fr->byte_count = ntohll(ofr->byte_count);
     } else if (raw == OFPRAW_NXT_FLOW_REMOVED) {
@@ -1842,6 +1880,7 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
         fr->duration_sec = ntohl(nfr->duration_sec);
         fr->duration_nsec = ntohl(nfr->duration_nsec);
         fr->idle_timeout = ntohs(nfr->idle_timeout);
+        fr->hard_timeout = 0;
         fr->packet_count = ntohll(nfr->packet_count);
         fr->byte_count = ntohll(nfr->byte_count);
     } else {
@@ -1861,6 +1900,27 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
     struct ofpbuf *msg;
 
     switch (protocol) {
+    case OFPUTIL_P_OF12: {
+        struct ofp12_flow_removed *ofr;
+
+        msg = ofpraw_alloc_xid(OFPRAW_OFPT11_FLOW_REMOVED,
+                               ofputil_protocol_to_ofp_version(protocol),
+                               htonl(0), NXM_TYPICAL_LEN);
+        ofr = ofpbuf_put_zeros(msg, sizeof *ofr);
+        ofr->cookie = fr->cookie;
+        ofr->priority = htons(fr->rule.priority);
+        ofr->reason = fr->reason;
+        ofr->table_id = 0;
+        ofr->duration_sec = htonl(fr->duration_sec);
+        ofr->duration_nsec = htonl(fr->duration_nsec);
+        ofr->idle_timeout = htons(fr->idle_timeout);
+        ofr->hard_timeout = htons(fr->hard_timeout);
+        ofr->packet_count = htonll(fr->packet_count);
+        ofr->byte_count = htonll(fr->byte_count);
+        oxm_put_match(msg, &fr->rule);
+        break;
+    }
+
     case OFPUTIL_P_OF10:
     case OFPUTIL_P_OF10_TID: {
         struct ofp_flow_removed *ofr;
@@ -1903,7 +1963,6 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
         break;
     }
 
-    case OFPUTIL_P_OF12:
     default:
         NOT_REACHED();
     }
@@ -1911,6 +1970,26 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
     return msg;
 }
 
+static void
+ofputil_decode_packet_in_finish(struct ofputil_packet_in *pin,
+                                struct cls_rule *rule,
+                                struct ofpbuf *b)
+{
+    pin->packet = b->data;
+    pin->packet_len = b->size;
+
+    pin->fmd.in_port = rule->flow.in_port;
+
+    pin->fmd.tun_id = rule->flow.tun_id;
+    pin->fmd.tun_id_mask = rule->wc.tun_id_mask;
+
+    pin->fmd.metadata = rule->flow.metadata;
+    pin->fmd.metadata_mask = rule->wc.metadata_mask;
+
+    memcpy(pin->fmd.regs, rule->flow.regs, sizeof pin->fmd.regs);
+    memcpy(pin->fmd.reg_masks, rule->wc.reg_masks, sizeof pin->fmd.reg_masks);
+}
+
 enum ofperr
 ofputil_decode_packet_in(struct ofputil_packet_in *pin,
                          const struct ofp_header *oh)
@@ -1922,7 +2001,29 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin,
 
     ofpbuf_use_const(&b, oh, ntohs(oh->length));
     raw = ofpraw_pull_assert(&b);
-    if (raw == OFPRAW_OFPT10_PACKET_IN) {
+    if (raw == OFPRAW_OFPT12_PACKET_IN) {
+        const struct ofp12_packet_in *opi;
+        struct cls_rule rule;
+        int error;
+
+        opi = ofpbuf_pull(&b, sizeof *opi);
+        error = oxm_pull_match_loose(&b, 0, &rule);
+        if (error) {
+            return error;
+        }
+
+        if (!ofpbuf_try_pull(&b, 2)) {
+            return OFPERR_OFPBRC_BAD_LEN;
+        }
+
+        pin->reason = opi->reason;
+        pin->table_id = opi->table_id;
+
+        pin->buffer_id = ntohl(opi->buffer_id);
+        pin->total_len = ntohs(opi->total_len);
+
+        ofputil_decode_packet_in_finish(pin, &rule, &b);
+    } else if (raw == OFPRAW_OFPT10_PACKET_IN) {
         const struct ofp_packet_in *opi;
 
         opi = ofpbuf_pull(&b, offsetof(struct ofp_packet_in, data));
@@ -1950,26 +2051,14 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin,
             return OFPERR_OFPBRC_BAD_LEN;
         }
 
-        pin->packet = b.data;
-        pin->packet_len = b.size;
         pin->reason = npi->reason;
         pin->table_id = npi->table_id;
         pin->cookie = npi->cookie;
 
-        pin->fmd.in_port = rule.flow.in_port;
-
-        pin->fmd.tun_id = rule.flow.tun_id;
-        pin->fmd.tun_id_mask = rule.wc.tun_id_mask;
-
-        pin->fmd.metadata = rule.flow.metadata;
-        pin->fmd.metadata_mask = rule.wc.metadata_mask;
-
-        memcpy(pin->fmd.regs, rule.flow.regs, sizeof pin->fmd.regs);
-        memcpy(pin->fmd.reg_masks, rule.wc.reg_masks,
-               sizeof pin->fmd.reg_masks);
-
         pin->buffer_id = ntohl(npi->buffer_id);
         pin->total_len = ntohs(npi->total_len);
+
+        ofputil_decode_packet_in_finish(pin, &rule, &b);
     } else {
         NOT_REACHED();
     }
@@ -2119,29 +2208,54 @@ ofputil_decode_packet_out(struct ofputil_packet_out *po,
                           const struct ofp_header *oh,
                           struct ofpbuf *ofpacts)
 {
-    const struct ofp_packet_out *opo;
-    enum ofperr error;
+    enum ofperr bad_in_port_err;
     enum ofpraw raw;
     struct ofpbuf b;
 
     ofpbuf_use_const(&b, oh, ntohs(oh->length));
     raw = ofpraw_pull_assert(&b);
-    assert(raw == OFPRAW_OFPT10_PACKET_OUT);
 
-    opo = ofpbuf_pull(&b, sizeof *opo);
-    po->buffer_id = ntohl(opo->buffer_id);
-    po->in_port = ntohs(opo->in_port);
+    if (raw == OFPRAW_OFPT11_PACKET_OUT) {
+        enum ofperr error;
+        const struct ofp11_packet_out *opo = ofpbuf_pull(&b, sizeof *opo);
+
+        po->buffer_id = ntohl(opo->buffer_id);
+        error = ofputil_port_from_ofp11(opo->in_port, &po->in_port);
+        if (error) {
+            return error;
+        }
+
+        error = ofpacts_pull_openflow11_actions(&b, ntohs(opo->actions_len),
+                                                ofpacts);
+        if (error) {
+            return error;
+        }
+
+        bad_in_port_err = OFPERR_OFPBMC_BAD_VALUE;
+    } else if (raw == OFPRAW_OFPT10_PACKET_OUT) {
+        enum ofperr error;
+        const struct ofp_packet_out *opo = ofpbuf_pull(&b, sizeof *opo);
+
+        po->buffer_id = ntohl(opo->buffer_id);
+        po->in_port = ntohs(opo->in_port);
+
+        error = ofpacts_pull_openflow10(&b, ntohs(opo->actions_len), ofpacts);
+        if (error) {
+            return error;
+        }
+
+        bad_in_port_err = OFPERR_NXBRC_BAD_IN_PORT;
+    } else {
+        NOT_REACHED();
+    }
+
     if (po->in_port >= OFPP_MAX && po->in_port != OFPP_LOCAL
         && po->in_port != OFPP_NONE && po->in_port != OFPP_CONTROLLER) {
         VLOG_WARN_RL(&bad_ofmsg_rl, "packet-out has bad input port %#"PRIx16,
                      po->in_port);
-        return OFPERR_NXBRC_BAD_IN_PORT;
+        return bad_in_port_err;
     }
 
-    error = ofpacts_pull_openflow10(&b, ntohs(opo->actions_len), ofpacts);
-    if (error) {
-        return error;
-    }
     po->ofpacts = ofpacts->data;
     po->ofpacts_len = ofpacts->size;
 
@@ -2732,12 +2846,13 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm,
         break;
     }
 
-    case OFP11_VERSION: {
+    case OFP11_VERSION:
+    case OFP12_VERSION: {
         struct ofp11_port_mod *opm;
 
         b = ofpraw_alloc(OFPRAW_OFPT11_PORT_MOD, ofp_version, 0);
         opm = ofpbuf_put_zeros(b, sizeof *opm);
-        opm->port_no = htonl(pm->port_no);
+        opm->port_no = ofputil_port_to_ofp11(pm->port_no);
         memcpy(opm->hw_addr, pm->hw_addr, ETH_ADDR_LEN);
         opm->config = htonl(pm->config & OFPPC11_ALL);
         opm->mask = htonl(pm->mask & OFPPC11_ALL);
@@ -2745,7 +2860,6 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm,
         break;
     }
 
-    case OFP12_VERSION:
     default:
         NOT_REACHED();
     }
@@ -3013,10 +3127,10 @@ ofputil_append_flow_update(const struct ofputil_flow_update *update,
 }
 \f
 struct ofpbuf *
-ofputil_encode_packet_out(const struct ofputil_packet_out *po)
+ofputil_encode_packet_out(const struct ofputil_packet_out *po,
+                          enum ofputil_protocol protocol)
 {
-    struct ofp_packet_out *opo;
-    size_t actions_ofs;
+    enum ofp_version ofp_version = ofputil_protocol_to_ofp_version(protocol);
     struct ofpbuf *msg;
     size_t size;
 
@@ -3025,15 +3139,42 @@ ofputil_encode_packet_out(const struct ofputil_packet_out *po)
         size += po->packet_len;
     }
 
-    msg = ofpraw_alloc(OFPRAW_OFPT10_PACKET_OUT, OFP10_VERSION, size);
-    ofpbuf_put_zeros(msg, sizeof *opo);
-    actions_ofs = msg->size;
-    ofpacts_put_openflow10(po->ofpacts, po->ofpacts_len, msg);
+    switch (ofp_version) {
+    case OFP10_VERSION: {
+        struct ofp_packet_out *opo;
+        size_t actions_ofs;
+
+        msg = ofpraw_alloc(OFPRAW_OFPT10_PACKET_OUT, OFP10_VERSION, size);
+        ofpbuf_put_zeros(msg, sizeof *opo);
+        actions_ofs = msg->size;
+        ofpacts_put_openflow10(po->ofpacts, po->ofpacts_len, msg);
+
+        opo = msg->l3;
+        opo->buffer_id = htonl(po->buffer_id);
+        opo->in_port = htons(po->in_port);
+        opo->actions_len = htons(msg->size - actions_ofs);
+        break;
+    }
+
+    case OFP11_VERSION:
+    case OFP12_VERSION: {
+        struct ofp11_packet_out *opo;
+        size_t len;
 
-    opo = msg->l3;
-    opo->buffer_id = htonl(po->buffer_id);
-    opo->in_port = htons(po->in_port);
-    opo->actions_len = htons(msg->size - actions_ofs);
+        msg = ofpraw_alloc(OFPRAW_OFPT11_PACKET_OUT, ofp_version, size);
+        ofpbuf_put_zeros(msg, sizeof *opo);
+        len = ofpacts_put_openflow11_actions(po->ofpacts, po->ofpacts_len, msg);
+
+        opo = msg->l3;
+        opo->buffer_id = htonl(po->buffer_id);
+        opo->in_port = ofputil_port_to_ofp11(po->in_port);
+        opo->actions_len = htons(len);
+        break;
+    }
+
+    default:
+        NOT_REACHED();
+    }
 
     if (po->buffer_id == UINT32_MAX) {
         ofpbuf_put(msg, po->packet, po->packet_len);