ofp-util: Update Capabilities for Open Flow 1.2
[sliver-openvswitch.git] / lib / ofp-util.c
index a943b4e..ac12b1b 100644 (file)
@@ -1266,11 +1266,8 @@ struct ofpbuf *
 ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
                         enum ofputil_protocol protocol)
 {
-    struct ofp10_flow_mod *ofm;
-    struct nx_flow_mod *nfm;
     struct ofpbuf *msg;
     uint16_t command;
-    int match_len;
 
     command = (protocol & OFPUTIL_P_TID
                ? (fm->command & 0xff) | (fm->table_id << 8)
@@ -1278,7 +1275,9 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
 
     switch (protocol) {
     case OFPUTIL_P_OF10:
-    case OFPUTIL_P_OF10_TID:
+    case OFPUTIL_P_OF10_TID: {
+        struct ofp10_flow_mod *ofm;
+
         msg = ofpraw_alloc(OFPRAW_OFPT10_FLOW_MOD, OFP10_VERSION,
                            fm->ofpacts_len);
         ofm = ofpbuf_put_zeros(msg, sizeof *ofm);
@@ -1292,9 +1291,13 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
         ofm->out_port = htons(fm->out_port);
         ofm->flags = htons(fm->flags);
         break;
+    }
 
     case OFPUTIL_P_NXM:
-    case OFPUTIL_P_NXM_TID:
+    case OFPUTIL_P_NXM_TID: {
+        struct nx_flow_mod *nfm;
+        int match_len;
+
         msg = ofpraw_alloc(OFPRAW_NXT_FLOW_MOD, OFP10_VERSION,
                            NXM_TYPICAL_LEN + fm->ofpacts_len);
         nfm = ofpbuf_put_zeros(msg, sizeof *nfm);
@@ -1311,6 +1314,7 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
         nfm->flags = htons(fm->flags);
         nfm->match_len = htons(match_len);
         break;
+    }
 
     case OFPUTIL_P_OF12:
     default:
@@ -2309,7 +2313,7 @@ ofputil_append_port_desc_stats_reply(enum ofp_version ofp_version,
 /* ofputil_switch_features */
 
 #define OFPC_COMMON (OFPC_FLOW_STATS | OFPC_TABLE_STATS | OFPC_PORT_STATS | \
-                     OFPC_IP_REASM | OFPC_QUEUE_STATS | OFPC_ARP_MATCH_IP)
+                     OFPC_IP_REASM | OFPC_QUEUE_STATS)
 BUILD_ASSERT_DECL((int) OFPUTIL_C_FLOW_STATS == OFPC_FLOW_STATS);
 BUILD_ASSERT_DECL((int) OFPUTIL_C_TABLE_STATS == OFPC_TABLE_STATS);
 BUILD_ASSERT_DECL((int) OFPUTIL_C_PORT_STATS == OFPC_PORT_STATS);
@@ -2367,6 +2371,23 @@ static const struct ofputil_action_bit_translation of11_action_bits[] = {
     { 0, 0 },
 };
 
+static const struct ofputil_action_bit_translation of12_action_bits[] = {
+    { OFPUTIL_A_OUTPUT,         OFPAT12_OUTPUT },
+    { OFPUTIL_A_COPY_TTL_OUT,   OFPAT12_COPY_TTL_OUT },
+    { OFPUTIL_A_COPY_TTL_IN,    OFPAT12_COPY_TTL_IN },
+    { OFPUTIL_A_SET_MPLS_TTL,   OFPAT12_SET_MPLS_TTL },
+    { OFPUTIL_A_DEC_MPLS_TTL,   OFPAT12_DEC_MPLS_TTL },
+    { OFPUTIL_A_PUSH_VLAN,      OFPAT12_PUSH_VLAN },
+    { OFPUTIL_A_POP_VLAN,       OFPAT12_POP_VLAN },
+    { OFPUTIL_A_PUSH_MPLS,      OFPAT12_PUSH_MPLS },
+    { OFPUTIL_A_POP_MPLS,       OFPAT12_POP_MPLS },
+    { OFPUTIL_A_SET_QUEUE,      OFPAT12_SET_QUEUE },
+    { OFPUTIL_A_GROUP,          OFPAT12_GROUP },
+    { OFPUTIL_A_SET_NW_TTL,     OFPAT12_SET_NW_TTL },
+    { OFPUTIL_A_DEC_NW_TTL,     OFPAT12_DEC_NW_TTL },
+    { 0, 0 },
+};
+
 static enum ofputil_action_bitmap
 decode_action_bits(ovs_be32 of_actions,
                    const struct ofputil_action_bit_translation *x)
@@ -2382,6 +2403,22 @@ decode_action_bits(ovs_be32 of_actions,
     return ofputil_actions;
 }
 
+static uint32_t
+ofputil_capabilities_mask(enum ofp_version ofp_version)
+{
+    /* Handle capabilities whose bit is unique for all Open Flow versions */
+    switch (ofp_version) {
+    case OFP10_VERSION:
+    case OFP11_VERSION:
+        return OFPC_COMMON | OFPC_ARP_MATCH_IP;
+    case OFP12_VERSION:
+        return OFPC_COMMON | OFPC12_PORT_BLOCKED;
+    default:
+        /* Caller needs to check osf->header.version itself */
+        return 0;
+    }
+}
+
 /* Decodes an OpenFlow 1.0 or 1.1 "switch_features" structure 'osf' into an
  * abstract representation in '*features'.  Initializes '*b' to iterate over
  * the OpenFlow port structures following 'osf' with later calls to
@@ -2403,7 +2440,8 @@ ofputil_decode_switch_features(const struct ofp_header *oh,
     features->n_buffers = ntohl(osf->n_buffers);
     features->n_tables = osf->n_tables;
 
-    features->capabilities = ntohl(osf->capabilities) & OFPC_COMMON;
+    features->capabilities = ntohl(osf->capabilities) &
+        ofputil_capabilities_mask(oh->version);
 
     if (b->size % ofputil_get_phy_port_size(oh->version)) {
         return OFPERR_OFPBRC_BAD_LEN;
@@ -2418,7 +2456,19 @@ ofputil_decode_switch_features(const struct ofp_header *oh,
         if (osf->capabilities & htonl(OFPC11_GROUP_STATS)) {
             features->capabilities |= OFPUTIL_C_GROUP_STATS;
         }
-        features->actions = decode_action_bits(osf->actions, of11_action_bits);
+        switch ((enum ofp_version)oh->version) {
+        case OFP11_VERSION:
+            features->actions = decode_action_bits(htonl(UINT32_MAX),
+                                                   of11_action_bits);
+            break;
+        case OFP12_VERSION:
+            features->actions = decode_action_bits(htonl(UINT32_MAX),
+                                                   of12_action_bits);
+            break;
+        case OFP10_VERSION:
+        default:
+            NOT_REACHED();
+        }
     } else {
         return OFPERR_OFPBRC_BAD_VERSION;
     }
@@ -2505,6 +2555,8 @@ ofputil_encode_switch_features(const struct ofputil_switch_features *features,
     osf->n_tables = features->n_tables;
 
     osf->capabilities = htonl(features->capabilities & OFPC_COMMON);
+    osf->capabilities = htonl(features->capabilities &
+                              ofputil_capabilities_mask(version));
     switch (version) {
     case OFP10_VERSION:
         if (features->capabilities & OFPUTIL_C_STP) {
@@ -2517,7 +2569,6 @@ ofputil_encode_switch_features(const struct ofputil_switch_features *features,
         if (features->capabilities & OFPUTIL_C_GROUP_STATS) {
             osf->capabilities |= htonl(OFPC11_GROUP_STATS);
         }
-        osf->actions = encode_action_bits(features->actions, of11_action_bits);
         break;
     default:
         NOT_REACHED();