Merge 'master' into 'next'.
[sliver-openvswitch.git] / lib / ofp-util.c
index ddac772..3487cba 100644 (file)
@@ -138,8 +138,7 @@ ofputil_cls_rule_from_match(const struct ofp_match *match,
     /* Initialize most of rule->flow. */
     rule->flow.nw_src = match->nw_src;
     rule->flow.nw_dst = match->nw_dst;
-    rule->flow.in_port = (match->in_port == htons(OFPP_LOCAL) ? ODPP_LOCAL
-                     : ntohs(match->in_port));
+    rule->flow.in_port = ntohs(match->in_port);
     rule->flow.dl_type = ofputil_dl_type_from_openflow(match->dl_type);
     rule->flow.tp_src = match->tp_src;
     rule->flow.tp_dst = match->tp_dst;
@@ -234,8 +233,7 @@ ofputil_cls_rule_to_match(const struct cls_rule *rule, struct ofp_match *match)
 
     /* Compose most of the match structure. */
     match->wildcards = htonl(ofpfw);
-    match->in_port = htons(rule->flow.in_port == ODPP_LOCAL ? OFPP_LOCAL
-                           : rule->flow.in_port);
+    match->in_port = htons(rule->flow.in_port);
     memcpy(match->dl_src, rule->flow.dl_src, ETH_ADDR_LEN);
     memcpy(match->dl_dst, rule->flow.dl_dst, ETH_ADDR_LEN);
     match->dl_type = ofputil_dl_type_to_openflow(rule->flow.dl_type);
@@ -341,16 +339,27 @@ ofputil_lookup_openflow_message(const struct ofputil_msg_category *cat,
                                 const struct ofputil_msg_type **typep)
 {
     const struct ofputil_msg_type *type;
+    bool found;
 
+    found = false;
     for (type = cat->types; type < &cat->types[cat->n_types]; type++) {
         if (type->value == value) {
-            if (!ofputil_length_ok(cat, type, size)) {
-                return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
+            if (ofputil_length_ok(cat, type, size)) {
+                *typep = type;
+                return 0;
             }
-            *typep = type;
-            return 0;
+
+            /* We found a matching command type but it had the wrong length.
+             * Probably this is just an error.  However, a screwup means that
+             * NXT_SET_FLOW_FORMAT and NXT_FLOW_MOD_TABLE_ID have the same
+             * value.  They do have different lengths, so we can distinguish
+             * them that way. */
+            found = true;
         }
     }
+    if (found) {
+        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
+    }
 
     VLOG_WARN_RL(&bad_ofmsg_rl, "received %s of unknown type %"PRIu32,
                  cat->name, value);
@@ -361,6 +370,9 @@ static int
 ofputil_decode_vendor(const struct ofp_header *oh,
                       const struct ofputil_msg_type **typep)
 {
+    BUILD_ASSERT_DECL(sizeof(struct nxt_set_flow_format)
+                      != sizeof(struct nxt_flow_mod_table_id));
+
     static const struct ofputil_msg_type nxt_messages[] = {
         { OFPUTIL_NXT_ROLE_REQUEST,
           NXT_ROLE_REQUEST, "NXT_ROLE_REQUEST",
@@ -374,6 +386,10 @@ ofputil_decode_vendor(const struct ofp_header *oh,
           NXT_SET_FLOW_FORMAT, "NXT_SET_FLOW_FORMAT",
           sizeof(struct nxt_set_flow_format), 0 },
 
+        { OFPUTIL_NXT_FLOW_MOD_TABLE_ID,
+          NXT_FLOW_MOD_TABLE_ID, "NXT_FLOW_MOD_TABLE_ID",
+          sizeof(struct nxt_flow_mod_table_id), 0 },
+
         { OFPUTIL_NXT_FLOW_MOD,
           NXT_FLOW_MOD, "NXT_FLOW_MOD",
           sizeof(struct nx_flow_mod), 8 },
@@ -852,15 +868,33 @@ ofputil_make_set_flow_format(enum nx_flow_format flow_format)
     return msg;
 }
 
+/* Returns an OpenFlow message that can be used to turn the flow_mod_table_id
+ * extension on or off (according to 'flow_mod_table_id'). */
+struct ofpbuf *
+ofputil_make_flow_mod_table_id(bool flow_mod_table_id)
+{
+    struct nxt_flow_mod_table_id *nfmti;
+    struct ofpbuf *msg;
+
+    nfmti = make_nxmsg(sizeof *nfmti, NXT_FLOW_MOD_TABLE_ID, &msg);
+    nfmti->set = flow_mod_table_id;
+    return msg;
+}
+
 /* Converts an OFPT_FLOW_MOD or NXT_FLOW_MOD message 'oh' into an abstract
  * flow_mod in 'fm'.  Returns 0 if successful, otherwise an OpenFlow error
  * code.
  *
+ * 'flow_mod_table_id' should be true if the NXT_FLOW_MOD_TABLE_ID extension is
+ * enabled, false otherwise.
+ *
  * Does not validate the flow_mod actions. */
 int
-ofputil_decode_flow_mod(struct flow_mod *fm, const struct ofp_header *oh)
+ofputil_decode_flow_mod(struct flow_mod *fm, const struct ofp_header *oh,
+                        bool flow_mod_table_id)
 {
     const struct ofputil_msg_type *type;
+    uint16_t command;
     struct ofpbuf b;
 
     ofpbuf_use_const(&b, oh, ntohs(oh->length));
@@ -900,7 +934,7 @@ ofputil_decode_flow_mod(struct flow_mod *fm, const struct ofp_header *oh)
         /* Translate the message. */
         ofputil_cls_rule_from_match(&match, ntohs(ofm->priority), &fm->cr);
         fm->cookie = ofm->cookie;
-        fm->command = ntohs(ofm->command);
+        command = ntohs(ofm->command);
         fm->idle_timeout = ntohs(ofm->idle_timeout);
         fm->hard_timeout = ntohs(ofm->hard_timeout);
         fm->buffer_id = ntohl(ofm->buffer_id);
@@ -925,7 +959,7 @@ ofputil_decode_flow_mod(struct flow_mod *fm, const struct ofp_header *oh)
 
         /* Translate the message. */
         fm->cookie = nfm->cookie;
-        fm->command = ntohs(nfm->command);
+        command = ntohs(nfm->command);
         fm->idle_timeout = ntohs(nfm->idle_timeout);
         fm->hard_timeout = ntohs(nfm->hard_timeout);
         fm->buffer_id = ntohl(nfm->buffer_id);
@@ -935,17 +969,34 @@ ofputil_decode_flow_mod(struct flow_mod *fm, const struct ofp_header *oh)
         NOT_REACHED();
     }
 
+    if (flow_mod_table_id) {
+        fm->command = command & 0xff;
+        fm->table_id = command >> 8;
+    } else {
+        fm->command = command;
+        fm->table_id = 0xff;
+    }
+
     return 0;
 }
 
 /* Converts 'fm' into an OFPT_FLOW_MOD or NXT_FLOW_MOD message according to
- * 'flow_format' and returns the message. */
+ * 'flow_format' and returns the message.
+ *
+ * 'flow_mod_table_id' should be true if the NXT_FLOW_MOD_TABLE_ID extension is
+ * enabled, false otherwise. */
 struct ofpbuf *
 ofputil_encode_flow_mod(const struct flow_mod *fm,
-                        enum nx_flow_format flow_format)
+                        enum nx_flow_format flow_format,
+                        bool flow_mod_table_id)
 {
     size_t actions_len = fm->n_actions * sizeof *fm->actions;
     struct ofpbuf *msg;
+    uint16_t command;
+
+    command = (flow_mod_table_id
+               ? (fm->command & 0xff) | (fm->table_id << 8)
+               : fm->command);
 
     if (flow_format == NXFF_OPENFLOW10) {
         struct ofp_flow_mod *ofm;
@@ -953,7 +1004,6 @@ ofputil_encode_flow_mod(const struct flow_mod *fm,
         msg = ofpbuf_new(sizeof *ofm + actions_len);
         ofm = put_openflow(sizeof *ofm, OFPT_FLOW_MOD, msg);
         ofputil_cls_rule_to_match(&fm->cr, &ofm->match);
-        ofm->cookie = fm->cookie;
         ofm->command = htons(fm->command);
         ofm->idle_timeout = htons(fm->idle_timeout);
         ofm->hard_timeout = htons(fm->hard_timeout);
@@ -971,7 +1021,7 @@ ofputil_encode_flow_mod(const struct flow_mod *fm,
 
         nfm = msg->data;
         nfm->cookie = fm->cookie;
-        nfm->command = htons(fm->command);
+        nfm->command = htons(command);
         nfm->idle_timeout = htons(fm->idle_timeout);
         nfm->hard_timeout = htons(fm->hard_timeout);
         nfm->priority = htons(fm->cr.priority);
@@ -1725,19 +1775,6 @@ make_echo_reply(const struct ofp_header *rq)
     return out;
 }
 
-/* Converts the members of 'opp' from host to network byte order. */
-void
-hton_ofp_phy_port(struct ofp_phy_port *opp)
-{
-    opp->port_no = htons(opp->port_no);
-    opp->config = htonl(opp->config);
-    opp->state = htonl(opp->state);
-    opp->curr = htonl(opp->curr);
-    opp->advertised = htonl(opp->advertised);
-    opp->supported = htonl(opp->supported);
-    opp->peer = htonl(opp->peer);
-}
-
 static int
 check_action_exact_len(const union ofp_action *a, unsigned int len,
                        unsigned int required_len)
@@ -1989,10 +2026,9 @@ validate_actions(const union ofp_action *actions, size_t n_actions,
     return 0;
 }
 
-/* Returns true if 'action' outputs to 'port' (which must be in network byte
- * order), false otherwise. */
+/* Returns true if 'action' outputs to 'port', false otherwise. */
 bool
-action_outputs_to_port(const union ofp_action *action, uint16_t port)
+action_outputs_to_port(const union ofp_action *action, ovs_be16 port)
 {
     switch (ntohs(action->type)) {
     case OFPAT_OUTPUT: