netdev: Abstract "features" interface away from OpenFlow 1.0.
[sliver-openvswitch.git] / lib / ofp-util.c
index db95422..4e28b51 100644 (file)
@@ -30,6 +30,7 @@
 #include "learn.h"
 #include "multipath.h"
 #include "meta-flow.h"
+#include "netdev.h"
 #include "nx-match.h"
 #include "ofp-errors.h"
 #include "ofp-util.h"
@@ -724,31 +725,31 @@ ofputil_decode_msg_type__(const struct ofp_header *oh, size_t length,
           sizeof(struct ofp_port_status), 0 },
 
         { OFPUTIL_OFPT_PACKET_OUT, OFP10_VERSION,
-          OFPT_PACKET_OUT, "OFPT_PACKET_OUT",
+          OFPT10_PACKET_OUT, "OFPT_PACKET_OUT",
           sizeof(struct ofp_packet_out), 1 },
 
         { OFPUTIL_OFPT_FLOW_MOD, OFP10_VERSION,
-          OFPT_FLOW_MOD, "OFPT_FLOW_MOD",
+          OFPT10_FLOW_MOD, "OFPT_FLOW_MOD",
           sizeof(struct ofp_flow_mod), 1 },
 
         { OFPUTIL_OFPT_PORT_MOD, OFP10_VERSION,
-          OFPT_PORT_MOD, "OFPT_PORT_MOD",
+          OFPT10_PORT_MOD, "OFPT_PORT_MOD",
           sizeof(struct ofp_port_mod), 0 },
 
         { 0, OFP10_VERSION,
-          OFPT_STATS_REQUEST, "OFPT_STATS_REQUEST",
+          OFPT10_STATS_REQUEST, "OFPT_STATS_REQUEST",
           sizeof(struct ofp_stats_msg), 1 },
 
         { 0, OFP10_VERSION,
-          OFPT_STATS_REPLY, "OFPT_STATS_REPLY",
+          OFPT10_STATS_REPLY, "OFPT_STATS_REPLY",
           sizeof(struct ofp_stats_msg), 1 },
 
         { OFPUTIL_OFPT_BARRIER_REQUEST, OFP10_VERSION,
-          OFPT_BARRIER_REQUEST, "OFPT_BARRIER_REQUEST",
+          OFPT10_BARRIER_REQUEST, "OFPT_BARRIER_REQUEST",
           sizeof(struct ofp_header), 0 },
 
         { OFPUTIL_OFPT_BARRIER_REPLY, OFP10_VERSION,
-          OFPT_BARRIER_REPLY, "OFPT_BARRIER_REPLY",
+          OFPT10_BARRIER_REPLY, "OFPT_BARRIER_REPLY",
           sizeof(struct ofp_header), 0 },
 
         { 0, 0,
@@ -767,16 +768,19 @@ ofputil_decode_msg_type__(const struct ofp_header *oh, size_t length,
     error = ofputil_lookup_openflow_message(&ofpt_category, oh->version,
                                             oh->type, typep);
     if (!error) {
-        switch (oh->type) {
-        case OFPT_VENDOR:
+        switch ((oh->version << 8) | oh->type) {
+        case (OFP10_VERSION << 8) | OFPT_VENDOR:
+        case (OFP11_VERSION << 8) | OFPT_VENDOR:
             error = ofputil_decode_vendor(oh, length, typep);
             break;
 
-        case OFPT_STATS_REQUEST:
+        case (OFP10_VERSION << 8) | OFPT10_STATS_REQUEST:
+        case (OFP11_VERSION << 8) | OFPT11_STATS_REQUEST:
             error = ofputil_decode_ofpst_request(oh, length, typep);
             break;
 
-        case OFPT_STATS_REPLY:
+        case (OFP10_VERSION << 8) | OFPT10_STATS_REPLY:
+        case (OFP11_VERSION << 8) | OFPT11_STATS_REPLY:
             error = ofputil_decode_ofpst_reply(oh, length, typep);
 
         default:
@@ -1447,7 +1451,7 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
     case OFPUTIL_P_OF10:
     case OFPUTIL_P_OF10_TID:
         msg = ofpbuf_new(sizeof *ofm + actions_len);
-        ofm = put_openflow(sizeof *ofm, OFPT_FLOW_MOD, msg);
+        ofm = put_openflow(sizeof *ofm, OFPT10_FLOW_MOD, msg);
         ofputil_cls_rule_to_match(&fm->cr, &ofm->match);
         ofm->cookie = fm->cookie;
         ofm->command = htons(command);
@@ -2220,6 +2224,37 @@ ofputil_decode_packet_out(struct ofputil_packet_out *po,
 
     return 0;
 }
+\f
+/* ofputil_phy_port */
+
+/* NETDEV_F_* to and from OFPPF_* and OFPPF10_*. */
+BUILD_ASSERT_DECL((int) NETDEV_F_10MB_HD    == OFPPF_10MB_HD);  /* bit 0 */
+BUILD_ASSERT_DECL((int) NETDEV_F_10MB_FD    == OFPPF_10MB_FD);  /* bit 1 */
+BUILD_ASSERT_DECL((int) NETDEV_F_100MB_HD   == OFPPF_100MB_HD); /* bit 2 */
+BUILD_ASSERT_DECL((int) NETDEV_F_100MB_FD   == OFPPF_100MB_FD); /* bit 3 */
+BUILD_ASSERT_DECL((int) NETDEV_F_1GB_HD     == OFPPF_1GB_HD);   /* bit 4 */
+BUILD_ASSERT_DECL((int) NETDEV_F_1GB_FD     == OFPPF_1GB_FD);   /* bit 5 */
+BUILD_ASSERT_DECL((int) NETDEV_F_10GB_FD    == OFPPF_10GB_FD);  /* bit 6 */
+
+/* NETDEV_F_ bits 11...15 are OFPPF10_ bits 7...11: */
+BUILD_ASSERT_DECL((int) NETDEV_F_COPPER == (OFPPF_COPPER << 4));
+BUILD_ASSERT_DECL((int) NETDEV_F_FIBER == (OFPPF_FIBER << 4));
+BUILD_ASSERT_DECL((int) NETDEV_F_AUTONEG == (OFPPF_AUTONEG << 4));
+BUILD_ASSERT_DECL((int) NETDEV_F_PAUSE == (OFPPF_PAUSE << 4));
+BUILD_ASSERT_DECL((int) NETDEV_F_PAUSE_ASYM == (OFPPF_PAUSE_ASYM << 4));
+
+enum netdev_features
+ofputil_netdev_port_features_from_ofp10(ovs_be32 ofp10_)
+{
+    uint32_t ofp10 = ntohl(ofp10_);
+    return (ofp10 & 0x7f) | ((ofp10 & 0xf80) << 4);
+}
+
+ovs_be32
+ofputil_netdev_port_features_to_ofp10(enum netdev_features features)
+{
+    return htonl((features & 0x7f) | ((features & 0xf800) >> 4));
+}
 
 struct ofpbuf *
 ofputil_encode_packet_out(const struct ofputil_packet_out *po)
@@ -2236,7 +2271,7 @@ ofputil_encode_packet_out(const struct ofputil_packet_out *po)
     }
 
     msg = ofpbuf_new(size);
-    opo = put_openflow(sizeof *opo, OFPT_PACKET_OUT, msg);
+    opo = put_openflow(sizeof *opo, OFPT10_PACKET_OUT, msg);
     opo->buffer_id = htonl(po->buffer_id);
     opo->in_port = htons(po->in_port);
     opo->actions_len = htons(actions_len);
@@ -2427,7 +2462,7 @@ ofputil_make_stats_request(size_t openflow_len, uint16_t ofpst_type,
     struct ofpbuf *msg;
 
     msg = *bufferp = ofpbuf_new(openflow_len);
-    put_stats__(alloc_xid(), OFPT_STATS_REQUEST,
+    put_stats__(alloc_xid(), OFPT10_STATS_REQUEST,
                 htons(ofpst_type), htonl(nxst_subtype), msg);
     ofpbuf_padto(msg, openflow_len);
 
@@ -2437,9 +2472,9 @@ ofputil_make_stats_request(size_t openflow_len, uint16_t ofpst_type,
 static void
 put_stats_reply__(const struct ofp_stats_msg *request, struct ofpbuf *msg)
 {
-    assert(request->header.type == OFPT_STATS_REQUEST ||
-           request->header.type == OFPT_STATS_REPLY);
-    put_stats__(request->header.xid, OFPT_STATS_REPLY, request->type,
+    assert(request->header.type == OFPT10_STATS_REQUEST ||
+           request->header.type == OFPT10_STATS_REPLY);
+    put_stats__(request->header.xid, OFPT10_STATS_REPLY, request->type,
                 (request->type != htons(OFPST_VENDOR)
                  ? htonl(0)
                  : ((const struct nicira_stats_msg *) request)->subtype),
@@ -2521,7 +2556,7 @@ ofputil_append_stats_reply(size_t len, struct list *replies)
 const void *
 ofputil_stats_body(const struct ofp_header *oh)
 {
-    assert(oh->type == OFPT_STATS_REQUEST || oh->type == OFPT_STATS_REPLY);
+    assert(oh->type == OFPT10_STATS_REQUEST || oh->type == OFPT10_STATS_REPLY);
     return (const struct ofp_stats_msg *) oh + 1;
 }
 
@@ -2529,7 +2564,7 @@ ofputil_stats_body(const struct ofp_header *oh)
 size_t
 ofputil_stats_body_len(const struct ofp_header *oh)
 {
-    assert(oh->type == OFPT_STATS_REQUEST || oh->type == OFPT_STATS_REPLY);
+    assert(oh->type == OFPT10_STATS_REQUEST || oh->type == OFPT10_STATS_REPLY);
     return ntohs(oh->length) - sizeof(struct ofp_stats_msg);
 }
 
@@ -2537,7 +2572,7 @@ ofputil_stats_body_len(const struct ofp_header *oh)
 const void *
 ofputil_nxstats_body(const struct ofp_header *oh)
 {
-    assert(oh->type == OFPT_STATS_REQUEST || oh->type == OFPT_STATS_REPLY);
+    assert(oh->type == OFPT10_STATS_REQUEST || oh->type == OFPT10_STATS_REPLY);
     return ((const struct nicira_stats_msg *) oh) + 1;
 }
 
@@ -2545,7 +2580,7 @@ ofputil_nxstats_body(const struct ofp_header *oh)
 size_t
 ofputil_nxstats_body_len(const struct ofp_header *oh)
 {
-    assert(oh->type == OFPT_STATS_REQUEST || oh->type == OFPT_STATS_REPLY);
+    assert(oh->type == OFPT10_STATS_REQUEST || oh->type == OFPT10_STATS_REPLY);
     return ntohs(oh->length) - sizeof(struct nicira_stats_msg);
 }
 
@@ -2558,7 +2593,7 @@ make_flow_mod(uint16_t command, const struct cls_rule *rule,
     struct ofpbuf *out = ofpbuf_new(size);
     ofm = ofpbuf_put_zeros(out, sizeof *ofm);
     ofm->header.version = OFP10_VERSION;
-    ofm->header.type = OFPT_FLOW_MOD;
+    ofm->header.type = OFPT10_FLOW_MOD;
     ofm->header.length = htons(size);
     ofm->cookie = 0;
     ofm->priority = htons(MIN(rule->priority, UINT16_MAX));
@@ -2658,7 +2693,7 @@ ofputil_encode_barrier_request(void)
 {
     struct ofpbuf *msg;
 
-    make_openflow(sizeof(struct ofp_header), OFPT_BARRIER_REQUEST, &msg);
+    make_openflow(sizeof(struct ofp_header), OFPT10_BARRIER_REQUEST, &msg);
     return msg;
 }
 
@@ -2692,6 +2727,44 @@ ofputil_frag_handling_from_string(const char *s, enum ofp_config_flags *flags)
     return true;
 }
 
+/* Converts the OpenFlow 1.1+ port number 'ofp11_port' into an OpenFlow 1.0
+ * port number and stores the latter in '*ofp10_port', for the purpose of
+ * decoding OpenFlow 1.1+ protocol messages.  Returns 0 if successful,
+ * otherwise an OFPERR_* number.
+ *
+ * See the definition of OFP11_MAX for an explanation of the mapping. */
+enum ofperr
+ofputil_port_from_ofp11(ovs_be32 ofp11_port, uint16_t *ofp10_port)
+{
+    uint32_t ofp11_port_h = ntohl(ofp11_port);
+
+    if (ofp11_port_h < OFPP_MAX) {
+        *ofp10_port = ofp11_port_h;
+        return 0;
+    } else if (ofp11_port_h >= OFPP11_MAX) {
+        *ofp10_port = ofp11_port_h - OFPP11_OFFSET;
+        return 0;
+    } else {
+        VLOG_WARN_RL(&bad_ofmsg_rl, "port %"PRIu32" is outside the supported "
+                     "range 0 through %d or 0x%"PRIx32" through 0x%"PRIx32,
+                     ofp11_port_h, OFPP_MAX - 1,
+                     (uint32_t) OFPP11_MAX, UINT32_MAX);
+        return OFPERR_OFPBAC_BAD_OUT_PORT;
+    }
+}
+
+/* Returns the OpenFlow 1.1+ port number equivalent to the OpenFlow 1.0 port
+ * number 'ofp10_port', for encoding OpenFlow 1.1+ protocol messages.
+ *
+ * See the definition of OFP11_MAX for an explanation of the mapping. */
+ovs_be32
+ofputil_port_to_ofp11(uint16_t ofp10_port)
+{
+    return htonl(ofp10_port < OFPP_MAX
+                 ? ofp10_port
+                 : ofp10_port + OFPP11_OFFSET);
+}
+
 /* Checks that 'port' is a valid output port for the OFPAT_OUTPUT action, given
  * that the switch will never have more than 'max_ports' ports.  Returns 0 if
  * 'port' is valid, otherwise an OpenFlow return code. */