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 <b...@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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev