ofp-util: Add OFPUTIL_ACTION_INVALID to enum ofputil_action_code.
[sliver-openvswitch.git] / lib / ofp-util.c
index 4af7a1f..3329ed7 100644 (file)
@@ -64,8 +64,11 @@ ofputil_wcbits_to_netmask(int wcbits)
 }
 
 /* Given the IP netmask 'netmask', returns the number of bits of the IP address
- * that it wildcards, that is, the number of 0-bits in 'netmask'.  'netmask'
- * must be a CIDR netmask (see ip_is_cidr()). */
+ * that it wildcards, that is, the number of 0-bits in 'netmask', a number
+ * between 0 and 32 inclusive.
+ *
+ * If 'netmask' is not a CIDR netmask (see ip_is_cidr()), the return value will
+ * still be in the valid range but isn't otherwise meaningful. */
 int
 ofputil_netmask_to_wcbits(ovs_be32 netmask)
 {
@@ -100,7 +103,7 @@ static const flow_wildcards_t WC_INVARIANTS = 0
 void
 ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc)
 {
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12);
 
     /* Initialize most of rule->wc. */
     flow_wildcards_init_catchall(wc);
@@ -348,11 +351,6 @@ ofputil_cls_rule_from_ofp11_match(const struct ofp11_match *match,
         if (!(wc & OFPFW11_NW_PROTO)) {
             cls_rule_set_nw_proto(rule, match->nw_proto);
         }
-
-        if (!ip_is_cidr(~match->nw_src_mask) ||
-            !ip_is_cidr(~match->nw_dst_mask)) {
-            return OFPERR_OFPBMC_BAD_NW_ADDR_MASK;
-        }
         cls_rule_set_nw_src_masked(rule, match->nw_src, ~match->nw_src_mask);
         cls_rule_set_nw_dst_masked(rule, match->nw_dst, ~match->nw_dst_mask);
     }
@@ -418,9 +416,8 @@ ofputil_cls_rule_from_ofp11_match(const struct ofp11_match *match,
     }
 
     if (match->metadata_mask != htonll(UINT64_MAX)) {
-        /* Metadata field not yet supported because we haven't decided how to
-         * map it onto our existing fields (or whether to add a new field). */
-        return OFPERR_OFPBMC_BAD_FIELD;
+        cls_rule_set_metadata_masked(rule, match->metadata,
+                                     ~match->metadata_mask);
     }
 
     return 0;
@@ -514,8 +511,8 @@ ofputil_cls_rule_to_ofp11_match(const struct cls_rule *rule,
     wc |= OFPFW11_MPLS_LABEL;
     wc |= OFPFW11_MPLS_TC;
 
-    /* Metadata field not yet supported */
-    match->metadata_mask = htonll(UINT64_MAX);
+    match->metadata = rule->flow.metadata;
+    match->metadata_mask = ~rule->wc.metadata_mask;
 
     match->wildcards = htonl(wc);
 }
@@ -1009,11 +1006,11 @@ ofputil_decode_msg_type__(const struct ofp_header *oh, size_t length,
           sizeof(struct ofp_port_status) + sizeof(struct ofp11_port), 0 },
 
         { OFPUTIL_OFPT_PACKET_OUT, OFP10_VERSION,
-          OFPT10_PACKET_OUT, "OFPT_PACKET_OUT",
+          OFPT_PACKET_OUT, "OFPT_PACKET_OUT",
           sizeof(struct ofp_packet_out), 1 },
 
         { OFPUTIL_OFPT_FLOW_MOD, OFP10_VERSION,
-          OFPT10_FLOW_MOD, "OFPT_FLOW_MOD",
+          OFPT_FLOW_MOD, "OFPT_FLOW_MOD",
           sizeof(struct ofp_flow_mod), 1 },
 
         { OFPUTIL_OFPT_PORT_MOD, OFP10_VERSION,
@@ -1444,7 +1441,7 @@ ofputil_usable_protocols(const struct cls_rule *rule)
 {
     const struct flow_wildcards *wc = &rule->wc;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 11);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 12);
 
     /* NXM and OF1.1+ supports bitwise matching on ethernet addresses. */
     if (!eth_mask_is_exact(wc->dl_src_mask)
@@ -1456,6 +1453,11 @@ ofputil_usable_protocols(const struct cls_rule *rule)
         return OFPUTIL_P_NXM_ANY;
     }
 
+    /* NXM and OF1.1+ support matching metadata. */
+    if (wc->metadata_mask != htonll(0)) {
+        return OFPUTIL_P_NXM_ANY;
+    }
+
     /* Only NXM supports matching ARP hardware addresses. */
     if (!(wc->wildcards & FWW_ARP_SHA) || !(wc->wildcards & FWW_ARP_THA)) {
         return OFPUTIL_P_NXM_ANY;
@@ -1497,6 +1499,11 @@ ofputil_usable_protocols(const struct cls_rule *rule)
         return OFPUTIL_P_NXM_ANY;
     }
 
+    /* Only NXM supports non-CIDR IPv4 address masks. */
+    if (!ip_is_cidr(wc->nw_src_mask) || !ip_is_cidr(wc->nw_dst_mask)) {
+        return OFPUTIL_P_NXM_ANY;
+    }
+
     /* Only NXM supports bitwise matching on transport port. */
     if ((wc->tp_src_mask && wc->tp_src_mask != htons(UINT16_MAX)) ||
         (wc->tp_dst_mask && wc->tp_dst_mask != htons(UINT16_MAX))) {
@@ -1752,7 +1759,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, OFPT10_FLOW_MOD, msg);
+        ofm = put_openflow(sizeof *ofm, OFPT_FLOW_MOD, msg);
         ofputil_cls_rule_to_ofp10_match(&fm->cr, &ofm->match);
         ofm->cookie = fm->new_cookie;
         ofm->command = htons(command);
@@ -1773,6 +1780,7 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
         nfm->cookie = fm->new_cookie;
         match_len = nx_put_match(msg, false, &fm->cr,
                                  fm->cookie, fm->cookie_mask);
+        nfm = msg->data;
         nfm->idle_timeout = htons(fm->idle_timeout);
         nfm->hard_timeout = htons(fm->hard_timeout);
         nfm->priority = htons(fm->cr.priority);
@@ -2315,7 +2323,7 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
     return msg;
 }
 
-int
+enum ofperr
 ofputil_decode_packet_in(struct ofputil_packet_in *pin,
                          const struct ofp_header *oh)
 {
@@ -2367,6 +2375,9 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin,
         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);
@@ -2419,6 +2430,9 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin,
         cls_rule_init_catchall(&rule, 0);
         cls_rule_set_tun_id_masked(&rule, pin->fmd.tun_id,
                                    pin->fmd.tun_id_mask);
+        cls_rule_set_metadata_masked(&rule, pin->fmd.metadata,
+                                   pin->fmd.metadata_mask);
+
 
         for (i = 0; i < FLOW_N_REGS; i++) {
             cls_rule_set_reg_masked(&rule, i, pin->fmd.regs[i],
@@ -3067,7 +3081,7 @@ ofputil_encode_packet_out(const struct ofputil_packet_out *po)
     }
 
     msg = ofpbuf_new(size);
-    opo = put_openflow(sizeof *opo, OFPT10_PACKET_OUT, msg);
+    opo = put_openflow(sizeof *opo, OFPT_PACKET_OUT, msg);
     opo->buffer_id = htonl(po->buffer_id);
     opo->in_port = htons(po->in_port);
     opo->actions_len = htons(actions_len);
@@ -3389,7 +3403,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 = OFPT10_FLOW_MOD;
+    ofm->header.type = OFPT_FLOW_MOD;
     ofm->header.length = htons(size);
     ofm->cookie = 0;
     ofm->priority = htons(MIN(rule->priority, UINT16_MAX));
@@ -3410,32 +3424,6 @@ make_add_flow(const struct cls_rule *rule, uint32_t buffer_id,
     return out;
 }
 
-struct ofpbuf *
-make_del_flow(const struct cls_rule *rule)
-{
-    struct ofpbuf *out = make_flow_mod(OFPFC_DELETE_STRICT, rule, 0);
-    struct ofp_flow_mod *ofm = out->data;
-    ofm->out_port = htons(OFPP_NONE);
-    return out;
-}
-
-struct ofpbuf *
-make_add_simple_flow(const struct cls_rule *rule,
-                     uint32_t buffer_id, uint16_t out_port,
-                     uint16_t idle_timeout)
-{
-    if (out_port != OFPP_NONE) {
-        struct ofp_action_output *oao;
-        struct ofpbuf *buffer;
-
-        buffer = make_add_flow(rule, buffer_id, idle_timeout, sizeof *oao);
-        ofputil_put_OFPAT10_OUTPUT(buffer)->port = htons(out_port);
-        return buffer;
-    } else {
-        return make_add_flow(rule, buffer_id, idle_timeout, 0);
-    }
-}
-
 struct ofpbuf *
 make_packet_in(uint32_t buffer_id, uint16_t in_port, uint8_t reason,
                const struct ofpbuf *payload, int max_send_len)
@@ -3723,6 +3711,9 @@ validate_actions(const union ofp_action *actions, size_t n_actions,
 
         error = 0;
         switch ((enum ofputil_action_code) code) {
+        case OFPUTIL_ACTION_INVALID:
+            NOT_REACHED();
+
         case OFPUTIL_OFPAT10_OUTPUT:
             error = ofputil_check_output_port(ntohs(a->output.port),
                                               max_ports);
@@ -3953,6 +3944,7 @@ int
 ofputil_action_code_from_name(const char *name)
 {
     static const char *names[OFPUTIL_N_ACTIONS] = {
+        NULL,
 #define OFPAT10_ACTION(ENUM, STRUCT, NAME)             NAME,
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME,
 #include "ofp-util.def"
@@ -3977,6 +3969,9 @@ void *
 ofputil_put_action(enum ofputil_action_code code, struct ofpbuf *buf)
 {
     switch (code) {
+    case OFPUTIL_ACTION_INVALID:
+        NOT_REACHED();
+
 #define OFPAT10_ACTION(ENUM, STRUCT, NAME)                    \
     case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf);
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)        \