Remove encal_dl_type from struct flow
[sliver-openvswitch.git] / lib / ofp-util.c
index f772551..6b78f84 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,7 +23,6 @@
 #include <netinet/in.h>
 #include <netinet/icmp6.h>
 #include <stdlib.h>
-#include "autopath.h"
 #include "bundle.h"
 #include "byte-order.h"
 #include "classifier.h"
@@ -85,7 +84,7 @@ ofputil_netmask_to_wcbits(ovs_be32 netmask)
 void
 ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc)
 {
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
 
     /* Initialize most of wc. */
     flow_wildcards_init_catchall(wc);
@@ -440,8 +439,7 @@ ofputil_match_from_ofp11_match(const struct ofp11_match *ofmatch,
         }
     }
 
-    if (match->flow.dl_type == htons(ETH_TYPE_MPLS) ||
-        match->flow.dl_type == htons(ETH_TYPE_MPLS_MCAST)) {
+    if (eth_type_mpls(match->flow.dl_type)) {
         enum { OFPFW11_MPLS_ALL = OFPFW11_MPLS_LABEL | OFPFW11_MPLS_TC };
 
         if ((wc & OFPFW11_MPLS_ALL) != OFPFW11_MPLS_ALL) {
@@ -807,7 +805,7 @@ ofputil_protocols_to_string(enum ofputil_protocol protocols)
 {
     struct ds s;
 
-    assert(!(protocols & ~OFPUTIL_P_ANY));
+    ovs_assert(!(protocols & ~OFPUTIL_P_ANY));
     if (protocols == 0) {
         return xstrdup("none");
     }
@@ -1060,13 +1058,18 @@ ofputil_usable_protocols(const struct match *match)
 {
     const struct flow_wildcards *wc = &match->wc;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
 
     /* tunnel params other than tun_id can't be sent in a flow_mod */
     if (!tun_parms_fully_wildcarded(wc)) {
         return OFPUTIL_P_NONE;
     }
 
+    /* skb_mark and skb_priority can't be sent in a flow_mod */
+    if (wc->masks.skb_mark || wc->masks.skb_priority) {
+        return OFPUTIL_P_NONE;
+    }
+
     /* NXM, OXM, and OF1.1 support bitwise matching on ethernet addresses. */
     if (!eth_mask_is_exact(wc->masks.dl_src)
         && !eth_addr_is_zero(wc->masks.dl_src)) {
@@ -1147,6 +1150,26 @@ ofputil_usable_protocols(const struct match *match)
             | OFPUTIL_P_OF13_OXM;
     }
 
+    /* NXM and OF1.1+ support matching MPLS label */
+    if (wc->masks.mpls_lse & htonl(MPLS_LABEL_MASK)) {
+        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
+            | OFPUTIL_P_OF13_OXM;
+    }
+
+    /* NXM and OF1.1+ support matching MPLS TC */
+    if (wc->masks.mpls_lse & htonl(MPLS_TC_MASK)) {
+        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
+            | OFPUTIL_P_OF13_OXM;
+    }
+
+    /* NXM and OF1.3+ support matching MPLS stack flag */
+    /* Allow for OF1.2 as there doesn't seem to be a
+     * particularly good reason not to */
+    if (wc->masks.mpls_lse & htonl(MPLS_BOS_MASK)) {
+        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
+            | OFPUTIL_P_OF13_OXM;
+    }
+
     /* Other formats can express this rule. */
     return OFPUTIL_P_ANY;
 }
@@ -1362,7 +1385,7 @@ ofputil_encode_set_protocol(enum ofputil_protocol current,
         return ofputil_make_flow_mod_table_id(want_tid);
     }
 
-    assert(current == want);
+    ovs_assert(current == want);
 
     *next = current;
     return NULL;
@@ -1376,7 +1399,7 @@ ofputil_encode_nx_set_flow_format(enum nx_flow_format nxff)
     struct nx_set_flow_format *sff;
     struct ofpbuf *msg;
 
-    assert(ofputil_nx_flow_format_is_valid(nxff));
+    ovs_assert(ofputil_nx_flow_format_is_valid(nxff));
 
     msg = ofpraw_alloc(OFPRAW_NXT_SET_FLOW_FORMAT, OFP10_VERSION, 0);
     sff = ofpbuf_put_zeros(msg, sizeof *sff);
@@ -2322,7 +2345,7 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
         fr->priority = ntohs(nfr->priority);
         fr->cookie = nfr->cookie;
         fr->reason = nfr->reason;
-        fr->table_id = 255;
+        fr->table_id = nfr->table_id ? nfr->table_id - 1 : 255;
         fr->duration_sec = ntohl(nfr->duration_sec);
         fr->duration_nsec = ntohl(nfr->duration_nsec);
         fr->idle_timeout = ntohs(nfr->idle_timeout);
@@ -2401,6 +2424,7 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
         nfr->cookie = fr->cookie;
         nfr->priority = htons(fr->priority);
         nfr->reason = fr->reason;
+        nfr->table_id = fr->table_id + 1;
         nfr->duration_sec = htonl(fr->duration_sec);
         nfr->duration_nsec = htonl(fr->duration_nsec);
         nfr->idle_timeout = htons(fr->idle_timeout);
@@ -3192,7 +3216,9 @@ ofputil_put_switch_features_port(const struct ofputil_phy_port *pp,
 {
     const struct ofp_header *oh = b->data;
 
-    ofputil_put_phy_port(oh->version, pp, b);
+    if (oh->version < OFP13_VERSION) {
+        ofputil_put_phy_port(oh->version, pp, b);
+    }
 }
 \f
 /* ofputil_port_status */
@@ -3219,7 +3245,7 @@ ofputil_decode_port_status(const struct ofp_header *oh,
     ps->reason = ops->reason;
 
     retval = ofputil_pull_phy_port(oh->version, &b, &ps->desc);
-    assert(retval != EOF);
+    ovs_assert(retval != EOF);
     return retval;
 }
 
@@ -3348,6 +3374,103 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm,
     return b;
 }
 \f
+/* ofputil_role_request */
+
+/* Decodes the OpenFlow "role request" or "role reply" message in '*oh' into
+ * an abstract form in '*rr'.  Returns 0 if successful, otherwise an
+ * OFPERR_* value. */
+enum ofperr
+ofputil_decode_role_message(const struct ofp_header *oh,
+                            struct ofputil_role_request *rr)
+{
+    struct ofpbuf b;
+    enum ofpraw raw;
+
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
+    raw = ofpraw_pull_assert(&b);
+
+    if (raw == OFPRAW_OFPT12_ROLE_REQUEST ||
+        raw == OFPRAW_OFPT12_ROLE_REPLY) {
+        const struct ofp12_role_request *orr = b.l3;
+
+        if (orr->role != htonl(OFPCR12_ROLE_NOCHANGE) &&
+            orr->role != htonl(OFPCR12_ROLE_EQUAL) &&
+            orr->role != htonl(OFPCR12_ROLE_MASTER) &&
+            orr->role != htonl(OFPCR12_ROLE_SLAVE)) {
+            return OFPERR_OFPRRFC_BAD_ROLE;
+        }
+
+        rr->role = ntohl(orr->role);
+        if (raw == OFPRAW_OFPT12_ROLE_REQUEST
+            ? orr->role == htonl(OFPCR12_ROLE_NOCHANGE)
+            : orr->generation_id == htonll(UINT64_MAX)) {
+            rr->have_generation_id = false;
+            rr->generation_id = 0;
+        } else {
+            rr->have_generation_id = true;
+            rr->generation_id = ntohll(orr->generation_id);
+        }
+    } else if (raw == OFPRAW_NXT_ROLE_REQUEST ||
+               raw == OFPRAW_NXT_ROLE_REPLY) {
+        const struct nx_role_request *nrr = b.l3;
+
+        BUILD_ASSERT(NX_ROLE_OTHER + 1 == OFPCR12_ROLE_EQUAL);
+        BUILD_ASSERT(NX_ROLE_MASTER + 1 == OFPCR12_ROLE_MASTER);
+        BUILD_ASSERT(NX_ROLE_SLAVE + 1 == OFPCR12_ROLE_SLAVE);
+
+        if (nrr->role != htonl(NX_ROLE_OTHER) &&
+            nrr->role != htonl(NX_ROLE_MASTER) &&
+            nrr->role != htonl(NX_ROLE_SLAVE)) {
+            return OFPERR_OFPRRFC_BAD_ROLE;
+        }
+
+        rr->role = ntohl(nrr->role) + 1;
+        rr->have_generation_id = false;
+        rr->generation_id = 0;
+    } else {
+        NOT_REACHED();
+    }
+
+    return 0;
+}
+
+/* Returns an encoded form of a role reply suitable for the "request" in a
+ * buffer owned by the caller. */
+struct ofpbuf *
+ofputil_encode_role_reply(const struct ofp_header *request,
+                          const struct ofputil_role_request *rr)
+{
+    struct ofpbuf *buf;
+    enum ofpraw raw;
+
+    raw = ofpraw_decode_assert(request);
+    if (raw == OFPRAW_OFPT12_ROLE_REQUEST) {
+        struct ofp12_role_request *orr;
+
+        buf = ofpraw_alloc_reply(OFPRAW_OFPT12_ROLE_REPLY, request, 0);
+        orr = ofpbuf_put_zeros(buf, sizeof *orr);
+
+        orr->role = htonl(rr->role);
+        orr->generation_id = htonll(rr->have_generation_id
+                                    ? rr->generation_id
+                                    : UINT64_MAX);
+    } else if (raw == OFPRAW_NXT_ROLE_REQUEST) {
+        struct nx_role_request *nrr;
+
+        BUILD_ASSERT(NX_ROLE_OTHER == OFPCR12_ROLE_EQUAL - 1);
+        BUILD_ASSERT(NX_ROLE_MASTER == OFPCR12_ROLE_MASTER - 1);
+        BUILD_ASSERT(NX_ROLE_SLAVE == OFPCR12_ROLE_SLAVE - 1);
+
+        buf = ofpraw_alloc_reply(OFPRAW_NXT_ROLE_REPLY, request, 0);
+        nrr = ofpbuf_put_zeros(buf, sizeof *nrr);
+        nrr->role = htonl(rr->role - 1);
+    } else {
+        NOT_REACHED();
+    }
+
+    return buf;
+}
+\f
 /* Table stats. */
 
 static void
@@ -3377,9 +3500,9 @@ ofputil_put_ofp10_table_stats(const struct ofp12_table_stats *in,
     struct ofp10_table_stats *out;
     const struct wc_map *p;
 
-    out = ofpbuf_put_uninit(buf, sizeof *out);
+    out = ofpbuf_put_zeros(buf, sizeof *out);
     out->table_id = in->table_id;
-    strcpy(out->name, in->name);
+    ovs_strlcpy(out->name, in->name, sizeof out->name);
     out->wildcards = 0;
     for (p = wc_map; p < &wc_map[ARRAY_SIZE(wc_map)]; p++) {
         if (in->wildcards & htonll(1ULL << p->mf12)) {
@@ -3437,9 +3560,9 @@ ofputil_put_ofp11_table_stats(const struct ofp12_table_stats *in,
 {
     struct ofp11_table_stats *out;
 
-    out = ofpbuf_put_uninit(buf, sizeof *out);
+    out = ofpbuf_put_zeros(buf, sizeof *out);
     out->table_id = in->table_id;
-    strcpy(out->name, in->name);
+    ovs_strlcpy(out->name, in->name, sizeof out->name);
     out->wildcards = oxm12_to_ofp11_flow_match_fields(in->wildcards);
     out->match = oxm12_to_ofp11_flow_match_fields(in->match);
     out->instructions = in->instructions;
@@ -4010,14 +4133,14 @@ ofputil_port_from_string(const char *s, uint16_t *portp)
             *portp = port32;
             return true;
         } else if (port32 <= OFPP_LAST_RESV) {
-            struct ds s;
+            struct ds msg;
 
-            ds_init(&s);
-            ofputil_format_port(port32, &s);
+            ds_init(&msg);
+            ofputil_format_port(port32, &msg);
             VLOG_WARN_ONCE("referring to port %s as %u is deprecated for "
                            "compatibility with future versions of OpenFlow",
-                           ds_cstr(&s), port32);
-            ds_destroy(&s);
+                           ds_cstr(&msg), port32);
+            ds_destroy(&msg);
 
             *portp = port32;
             return true;
@@ -4202,7 +4325,8 @@ ofputil_normalize_match__(struct match *match, bool may_log)
         MAY_ARP_SHA     = 1 << 4, /* arp_sha */
         MAY_ARP_THA     = 1 << 5, /* arp_tha */
         MAY_IPV6        = 1 << 6, /* ipv6_src, ipv6_dst, ipv6_label */
-        MAY_ND_TARGET   = 1 << 7  /* nd_target */
+        MAY_ND_TARGET   = 1 << 7, /* nd_target */
+        MAY_MPLS        = 1 << 8, /* mpls label and tc */
     } may_match;
 
     struct flow_wildcards wc;
@@ -4231,6 +4355,8 @@ ofputil_normalize_match__(struct match *match, bool may_log)
     } else if (match->flow.dl_type == htons(ETH_TYPE_ARP) ||
                match->flow.dl_type == htons(ETH_TYPE_RARP)) {
         may_match = MAY_NW_PROTO | MAY_NW_ADDR | MAY_ARP_SHA | MAY_ARP_THA;
+    } else if (eth_type_mpls(match->flow.dl_type)) {
+        may_match = MAY_MPLS;
     } else {
         may_match = 0;
     }
@@ -4263,6 +4389,10 @@ ofputil_normalize_match__(struct match *match, bool may_log)
     if (!(may_match & MAY_ND_TARGET)) {
         wc.masks.nd_target = in6addr_any;
     }
+    if (!(may_match & MAY_MPLS)) {
+        wc.masks.mpls_lse = htonl(0);
+        wc.masks.mpls_depth = 0;
+    }
 
     /* Log any changes. */
     if (!flow_wildcards_equal(&wc, &match->wc)) {