[ovs-dev] [mpls v2 2/2] Add OpenFlow support for matching multiple MPLS labels at once.

Ben Pfaff blp at nicira.com
Sun Dec 29 07:50:45 UTC 2013


This is an OpenFlow extension that might be useful.  I don't know how MPLS
works in practice well enough to judge.

Signed-off-by: Ben Pfaff <blp at nicira.com>
---
 include/openflow/nicira-ext.h |   38 ++++++++++++++++++
 lib/meta-flow.c               |   86 ++++++++++++++++++++++++++++++++++++++++-
 lib/meta-flow.h               |    5 +++
 lib/nx-match.c                |   38 ++++++++++++++----
 4 files changed, 157 insertions(+), 10 deletions(-)

diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
index 22939f4..3746484 100644
--- a/include/openflow/nicira-ext.h
+++ b/include/openflow/nicira-ext.h
@@ -1803,6 +1803,44 @@ OFP_ASSERT(sizeof(struct nx_action_output_reg) == 24);
 #define NXM_NX_TCP_FLAGS   NXM_HEADER  (0x0001, 34, 2)
 #define NXM_NX_TCP_FLAGS_W NXM_HEADER_W(0x0001, 34, 2)
 
+/* MPLS LSEs.
+ *
+ * NXM_NX_MPLS_LSE0 is the outermost label.
+ *
+ * Prereqs:
+ *   NXM_OF_ETH_TYPE must be either 0x8847 or 0x8848.
+ *   For NXM_NX_MPLS_LSE1 and later, NXM_NX_MPLS_LSE0 must match a value of 0
+ *   in the BOS bit.
+ *   For NXM_NX_MPLS_LSE2 and later, NXM_NX_MPLS_LSE1 must match a value of 0
+ *   in the BOS bit.
+ *   For NXM_NX_MPLS_LSE3 and later, NXM_NX_MPLS_LSE2 must match a value of 0
+ *   in the BOS bit.
+ *   and so on...
+ *
+ * Format:
+ *   32-bit integer in network byte order.  Space is reserved for up to
+ *   8 labels, but switches may implement fewer.
+ *
+ * Masking: Fully maskable.
+ */
+#define NXM_NX_MPLS_LSE0   NXM_HEADER  (0x0001, 35, 4)
+#define NXM_NX_MPLS_LSE0_W NXM_HEADER_W(0x0001, 35, 4)
+#define NXM_NX_MPLS_LSE1   NXM_HEADER  (0x0001, 36, 4)
+#define NXM_NX_MPLS_LSE1_W NXM_HEADER_W(0x0001, 36, 4)
+#define NXM_NX_MPLS_LSE2   NXM_HEADER  (0x0001, 37, 4)
+#define NXM_NX_MPLS_LSE2_W NXM_HEADER_W(0x0001, 37, 4)
+#define NXM_NX_MPLS_LSE3   NXM_HEADER  (0x0001, 38, 4)
+#define NXM_NX_MPLS_LSE3_W NXM_HEADER_W(0x0001, 38, 4)
+#define NXM_NX_MPLS_LSE4   NXM_HEADER  (0x0001, 39, 4)
+#define NXM_NX_MPLS_LSE4_W NXM_HEADER_W(0x0001, 39, 4)
+#define NXM_NX_MPLS_LSE5   NXM_HEADER  (0x0001, 40, 4)
+#define NXM_NX_MPLS_LSE5_W NXM_HEADER_W(0x0001, 40, 4)
+#define NXM_NX_MPLS_LSE6   NXM_HEADER  (0x0001, 41, 4)
+#define NXM_NX_MPLS_LSE6_W NXM_HEADER_W(0x0001, 41, 4)
+#define NXM_NX_MPLS_LSE7   NXM_HEADER  (0x0001, 42, 4)
+#define NXM_NX_MPLS_LSE8_W NXM_HEADER_W(0x0001, 42, 4)
+
+
 /* ## --------------------- ## */
 /* ## Requests and replies. ## */
 /* ## --------------------- ## */
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
index a168222..a10492c 100644
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -370,6 +370,42 @@ const struct mf_field mf_fields[MFF_N_IDS] = {
         OFPUTIL_P_NXM_OXM_ANY,
         OFPUTIL_P_NONE,
         -1,
+    }, {
+        MFF_MPLS_LSE0, "mpls_lse0", NULL,
+        MF_FIELD_SIZES(be32),
+        MFM_FULLY,
+        MFS_HEXADECIMAL,
+        MFP_MPLS,
+        false,
+        NXM_NX_MPLS_LSE0, "NXM_NX_MPLS_LSE0",
+        NXM_NX_MPLS_LSE0, "NXM_NX_MPLS_LSE0",
+        OFPUTIL_P_NXM_OXM_ANY,
+        OFPUTIL_P_NONE,
+        -1,
+    }, {
+        MFF_MPLS_LSE1, "mpls_lse1", NULL,
+        MF_FIELD_SIZES(be32),
+        MFM_FULLY,
+        MFS_HEXADECIMAL,
+        MFP_MPLS1,
+        false,
+        NXM_NX_MPLS_LSE1, "NXM_NX_MPLS_LSE1",
+        NXM_NX_MPLS_LSE1, "NXM_NX_MPLS_LSE1",
+        OFPUTIL_P_NXM_OXM_ANY,
+        OFPUTIL_P_NONE,
+        -1,
+    }, {
+        MFF_MPLS_LSE2, "mpls_lse2", NULL,
+        MF_FIELD_SIZES(be32),
+        MFM_FULLY,
+        MFS_HEXADECIMAL,
+        MFP_MPLS2,
+        false,
+        NXM_NX_MPLS_LSE2, "NXM_NX_MPLS_LSE2",
+        NXM_NX_MPLS_LSE2, "NXM_NX_MPLS_LSE2",
+        OFPUTIL_P_NXM_OXM_ANY,
+        OFPUTIL_P_NONE,
+        -1,
     },
 
     /* ## -- ## */
@@ -928,9 +964,13 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
     case MFF_MPLS_LABEL:
         return !(wc->masks.mpls_lse[0] & htonl(MPLS_LABEL_MASK));
     case MFF_MPLS_TC:
-        return !(wc->masks.mpls_lse[1] & htonl(MPLS_TC_MASK));
+        return !(wc->masks.mpls_lse[0] & htonl(MPLS_TC_MASK));
     case MFF_MPLS_BOS:
-        return !(wc->masks.mpls_lse[2] & htonl(MPLS_BOS_MASK));
+        return !(wc->masks.mpls_lse[0] & htonl(MPLS_BOS_MASK));
+    case MFF_MPLS_LSE0:
+    case MFF_MPLS_LSE1:
+    case MFF_MPLS_LSE2:
+        return !wc->masks.mpls_lse[mf->id - MFF_MPLS_LSE0];
 
     case MFF_IPV4_SRC:
         return !wc->masks.nw_src;
@@ -1052,6 +1092,13 @@ mf_are_prereqs_ok(const struct mf_field *mf, const struct flow *flow)
         return (flow->vlan_tci & htons(VLAN_CFI)) != 0;
     case MFP_MPLS:
         return eth_type_mpls(flow->dl_type);
+    case MFP_MPLS1:
+        return (eth_type_mpls(flow->dl_type)
+                && !(flow->mpls_lse[0] & htonl(MPLS_BOS_MASK)));
+    case MFP_MPLS2:
+        return (eth_type_mpls(flow->dl_type)
+                && !(flow->mpls_lse[0] & htonl(MPLS_BOS_MASK))
+                && !(flow->mpls_lse[1] & htonl(MPLS_BOS_MASK)));
     case MFP_IP_ANY:
         return is_ip_any(flow);
 
@@ -1115,6 +1162,15 @@ mf_mask_field_and_prereqs(const struct mf_field *mf, struct flow *mask)
     case MFP_IP_ANY:
         mask->dl_type = OVS_BE16_MAX;
         break;
+    case MFP_MPLS1:
+        mask->dl_type = OVS_BE16_MAX;
+        mask->mpls_lse[0] = htonl(MPLS_BOS_MASK);
+        break;
+    case MFP_MPLS2:
+        mask->dl_type = OVS_BE16_MAX;
+        mask->mpls_lse[0] = htonl(MPLS_BOS_MASK);
+        mask->mpls_lse[1] = htonl(MPLS_BOS_MASK);
+        break;
     case MFP_VLAN_VID:
         mask->vlan_tci |= htons(VLAN_CFI);
         break;
@@ -1153,6 +1209,9 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
     case MFF_ETH_DST:
     case MFF_ETH_TYPE:
     case MFF_VLAN_TCI:
+    case MFF_MPLS_LSE0:
+    case MFF_MPLS_LSE1:
+    case MFF_MPLS_LSE2:
     case MFF_IPV4_SRC:
     case MFF_IPV4_DST:
     case MFF_IPV6_SRC:
@@ -1312,6 +1371,11 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
     case MFF_MPLS_BOS:
         value->u8 = mpls_lse_to_bos(flow->mpls_lse[0]);
         break;
+
+    case MFF_MPLS_LSE0:
+    case MFF_MPLS_LSE1:
+    case MFF_MPLS_LSE2:
+        value->be32 = flow->mpls_lse[mf->id - MFF_MPLS_LSE0];
         break;
 
     case MFF_IPV4_SRC:
@@ -1509,6 +1573,11 @@ mf_set_value(const struct mf_field *mf,
     case MFF_MPLS_BOS:
         match_set_mpls_bos(match, 0, value->u8);
         break;
+
+    case MFF_MPLS_LSE0:
+    case MFF_MPLS_LSE1:
+    case MFF_MPLS_LSE2:
+        match_set_mpls_lse(match, mf->id - MFF_MPLS_LSE0, value->be32);
         break;
 
     case MFF_IPV4_SRC:
@@ -1723,6 +1792,11 @@ mf_set_flow_value(const struct mf_field *mf,
     case MFF_MPLS_BOS:
         flow_set_mpls_bos(flow, 0, value->u8);
         break;
+
+    case MFF_MPLS_LSE0:
+    case MFF_MPLS_LSE1:
+    case MFF_MPLS_LSE2:
+        flow->mpls_lse[mf->id - MFF_MPLS_LSE0] = value->be32;
         break;
 
     case MFF_IPV4_SRC:
@@ -1934,6 +2008,11 @@ mf_set_wild(const struct mf_field *mf, struct match *match)
     case MFF_MPLS_BOS:
         match_set_any_mpls_bos(match, 0);
         break;
+
+    case MFF_MPLS_LSE0:
+    case MFF_MPLS_LSE1:
+    case MFF_MPLS_LSE2:
+        match_set_any_mpls_lse(match, mf->id - MFF_MPLS_LSE0);
         break;
 
     case MFF_IPV4_SRC:
@@ -2074,6 +2153,9 @@ mf_set(const struct mf_field *mf,
     case MFF_MPLS_LABEL:
     case MFF_MPLS_TC:
     case MFF_MPLS_BOS:
+    case MFF_MPLS_LSE0:
+    case MFF_MPLS_LSE1:
+    case MFF_MPLS_LSE2:
     case MFF_IP_PROTO:
     case MFF_IP_TTL:
     case MFF_IP_DSCP:
diff --git a/lib/meta-flow.h b/lib/meta-flow.h
index cf92556..ea81a34 100644
--- a/lib/meta-flow.h
+++ b/lib/meta-flow.h
@@ -85,6 +85,9 @@ enum OVS_PACKED_ENUM mf_field_id {
     MFF_MPLS_LABEL,             /* be32 */
     MFF_MPLS_TC,                /* u8 */
     MFF_MPLS_BOS,               /* u8 */
+    MFF_MPLS_LSE0,              /* be32 */
+    MFF_MPLS_LSE1,              /* be32 */
+    MFF_MPLS_LSE2,              /* be32 */
 
     /* L3. */
     MFF_IPV4_SRC,               /* be32 */
@@ -193,6 +196,8 @@ enum OVS_PACKED_ENUM mf_prereqs {
 
     /* L2.5 requirements. */
     MFP_MPLS,
+    MFP_MPLS1,
+    MFP_MPLS2,
 
     /* L2+L3 requirements. */
     MFP_TCP,                    /* On IPv4 or IPv6. */
diff --git a/lib/nx-match.c b/lib/nx-match.c
index 437e85b..ffa0eb6 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -616,17 +616,39 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match *match,
 
     /* MPLS. */
     if (eth_type_mpls(flow->dl_type)) {
-        if (match->wc.masks.mpls_lse[0] & htonl(MPLS_TC_MASK)) {
-            nxm_put_8(b, OXM_OF_MPLS_TC, mpls_lse_to_tc(flow->mpls_lse[0]));
-        }
+        ovs_be32 mask0 = match->wc.masks.mpls_lse[0];
+        if (mask0) {
+            ovs_be32 lse0 = flow->mpls_lse[0];
+            ovs_be32 tc_mask = mask0 & htonl(MPLS_TC_MASK);
+            ovs_be32 bos_mask = mask0 & htonl(MPLS_BOS_MASK);
+            ovs_be32 label_mask = mask0 & htonl(MPLS_LABEL_MASK);
+            ovs_be32 ttl_mask = mask0 & htonl(MPLS_TTL_MASK);
+
+            if ((!tc_mask || tc_mask == htonl(MPLS_TC_MASK)) &&
+                (!bos_mask || bos_mask == htonl(MPLS_BOS_MASK)) &&
+                (!label_mask || label_mask == htonl(MPLS_LABEL_MASK)) &&
+                !ttl_mask)
+            {
+                if (tc_mask) {
+                    nxm_put_8(b, OXM_OF_MPLS_TC, mpls_lse_to_tc(lse0));
+                }
+
+                if (bos_mask) {
+                    nxm_put_8(b, OXM_OF_MPLS_BOS, mpls_lse_to_bos(lse0));
+                }
 
-        if (match->wc.masks.mpls_lse[0] & htonl(MPLS_BOS_MASK)) {
-            nxm_put_8(b, OXM_OF_MPLS_BOS, mpls_lse_to_bos(flow->mpls_lse[0]));
+                if (label_mask) {
+                    nxm_put_32(b, OXM_OF_MPLS_LABEL,
+                               htonl(mpls_lse_to_label(lse0)));
+                }
+            } else {
+                nxm_put_32m(b, NXM_NX_MPLS_LSE0, lse0, mask0);
+            }
         }
 
-        if (match->wc.masks.mpls_lse[0] & htonl(MPLS_LABEL_MASK)) {
-            nxm_put_32(b, OXM_OF_MPLS_LABEL,
-                       htonl(mpls_lse_to_label(flow->mpls_lse[0])));
+        for (i = 1; i < ARRAY_SIZE(flow->mpls_lse); i++) {
+            nxm_put_32m(b, NXM_NX_MPLS_LSE0 + i, flow->mpls_lse[i],
+                        match->wc.masks.mpls_lse[i]);
         }
     }
 
-- 
1.7.10.4




More information about the dev mailing list