From: Ben Pfaff <b...@nicira.com> I've been a little frustrated with the current approach to MPLS, because it seems quite difficult to understand. One particularly difficult bit for me is the variables used during translation, e.g. mpls_depth_delta and pre_push_mpls_lse. And what we end up with is support for a single MPLS label, which I don't think is going to make any real-world users happy.
I think that we can do something easier to understand and more powerful by just keeping track of all the labels in struct flow. This patch is a first stab at that. It's incomplete--in particular I have not implemented commit_mpls_action() because it seems slightly tricky and it's very late at night here--and obviously untested, but I'd appreciate feedback on the approach. I think that if this works out then it would obviate the need for patches "odp: Allow VLAN actions after MPLS actions" and "lib: Support pushing of MPLS LSE before or after VLAN tag". CC: Simon Horman <ho...@verge.net.au> Signed-off-by: Simon Horman <ho...@verge.net.au> --- include/openflow/nicira-ext.h | 38 +++++++ lib/flow.c | 96 ++++++++++++++--- lib/flow.h | 21 ++-- lib/match.c | 74 ++++++------- lib/match.h | 15 +-- lib/meta-flow.c | 116 ++++++++++++++++++--- lib/meta-flow.h | 5 + lib/nx-match.c | 40 +++++-- lib/odp-util.c | 126 +++++++++++----------- lib/odp-util.h | 3 +- lib/ofp-util.c | 17 +-- ofproto/ofproto-dpif-xlate.c | 237 ++++++++++-------------------------------- utilities/ovs-dpctl.c | 6 +- 13 files changed, 450 insertions(+), 344 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/flow.c b/lib/flow.c index f1d2cad..320cb55 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -109,12 +109,11 @@ static void parse_mpls(struct ofpbuf *b, struct flow *flow) { struct mpls_hdr *mh; - bool top = true; + int idx = 0; while ((mh = ofpbuf_try_pull(b, sizeof *mh))) { - if (top) { - top = false; - flow->mpls_lse = mh->mpls_lse; + if (idx < ARRAY_SIZE(flow->mpls_lse)) { + flow->mpls_lse[idx++] = mh->mpls_lse; } if (mh->mpls_lse & htonl(MPLS_BOS_MASK)) { break; @@ -535,7 +534,7 @@ flow_unwildcard_tp_ports(const struct flow *flow, struct flow_wildcards *wc) void flow_get_metadata(const struct flow *flow, struct flow_metadata *fmd) { - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 23); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 24); fmd->tun_id = flow->tunnel.tun_id; fmd->tun_src = flow->tunnel.ip_src; @@ -1047,35 +1046,95 @@ flow_set_vlan_pcp(struct flow *flow, uint8_t pcp) flow->vlan_tci |= htons((pcp << VLAN_PCP_SHIFT) | VLAN_CFI); } +void +flow_push_mpls(struct flow *flow, ovs_be32 mpls_eth_type, + struct flow_wildcards *wc) +{ + int n = flow_count_mpls_labels(flow); + + ovs_assert(n < ARRAY_SIZE(flow->mpls_lse)); + + memset(wc->masks.mpls_lse, 0xff, sizeof wc->masks.mpls_lse); + if (n) { + int i; + + for (i = n; i >= 1; i--) { + flow->mpls_lse[i] = flow->mpls_lse[i - 1]; + } + flow->mpls_lse[0] = (flow->mpls_lse[1] + & htonl(MPLS_TTL_MASK | MPLS_TC_MASK)); + } else { + ovs_be32 label; + uint8_t tc, ttl; + + if (flow->dl_type == htons(ETH_TYPE_IPV6)) { + label = htonl(0x2); /* IPV6 Explicit Null. */ + } else { + label = htonl(0x0); /* IPV4 Explicit Null. */ + } + wc->masks.nw_tos |= IP_DSCP_MASK; + wc->masks.nw_ttl = 0xff; + tc = (flow->nw_tos & IP_DSCP_MASK) >> 2; + ttl = flow->nw_ttl ? flow->nw_ttl : 0x40; + flow->mpls_lse[0] = set_mpls_lse_values(ttl, tc, 1, label); + flow->nw_proto = 0; /* XXX clear everything else L3+ also */ + } + flow->dl_type = mpls_eth_type; +} + +bool +flow_pop_mpls(struct flow *flow, ovs_be32 eth_type, struct flow_wildcards *wc) +{ + int n = flow_count_mpls_labels(flow); + int i; + + if (n == 0) { + /* Nothing to pop. */ + return false; + } else if (n == ARRAY_SIZE(flow->mpls_lse) + && !(flow->mpls_lse[n - 1] & htonl(MPLS_BOS_MASK))) { + /* Can't pop because we don't know what to fill in mpls_lse[n - 1]. */ + return false; + } + + memset(wc->masks.mpls_lse, 0xff, sizeof wc->masks.mpls_lse); + for (i = 1; i < n; i++) { + flow->mpls_lse[i - 1] = flow->mpls_lse[i]; + } + flow->mpls_lse[n - 1] = 0; + flow->dl_type = eth_type; + return true; +} + /* Sets the MPLS Label that 'flow' matches to 'label', which is interpreted * as an OpenFlow 1.1 "mpls_label" value. */ void -flow_set_mpls_label(struct flow *flow, ovs_be32 label) +flow_set_mpls_label(struct flow *flow, int idx, ovs_be32 label) { - set_mpls_lse_label(&flow->mpls_lse, label); + set_mpls_lse_label(&flow->mpls_lse[idx], label); } /* Sets the MPLS TTL that 'flow' matches to 'ttl', which should be in the * range 0...255. */ void -flow_set_mpls_ttl(struct flow *flow, uint8_t ttl) +flow_set_mpls_ttl(struct flow *flow, int idx, uint8_t ttl) { - set_mpls_lse_ttl(&flow->mpls_lse, ttl); + set_mpls_lse_ttl(&flow->mpls_lse[idx], ttl); } /* Sets the MPLS TC that 'flow' matches to 'tc', which should be in the * range 0...7. */ void -flow_set_mpls_tc(struct flow *flow, uint8_t tc) +flow_set_mpls_tc(struct flow *flow, int idx, uint8_t tc) { - set_mpls_lse_tc(&flow->mpls_lse, tc); + set_mpls_lse_tc(&flow->mpls_lse[idx], tc); } /* Sets the MPLS BOS bit that 'flow' matches to which should be 0 or 1. */ void -flow_set_mpls_bos(struct flow *flow, uint8_t bos) +flow_set_mpls_bos(struct flow *flow, int idx, uint8_t bos) { - set_mpls_lse_bos(&flow->mpls_lse, bos); + set_mpls_lse_bos(&flow->mpls_lse[idx], bos); } @@ -1235,8 +1294,17 @@ flow_compose(struct ofpbuf *b, const struct flow *flow) } if (eth_type_mpls(flow->dl_type)) { + int n; + b->l2_5 = b->l3; - push_mpls(b, flow->dl_type, flow->mpls_lse); + for (n = 1; n < ARRAY_SIZE(flow->mpls_lse); n++) { + if (flow->mpls_lse[n - 1] & htonl(MPLS_BOS_MASK)) { + break; + } + } + while (n > 0) { + push_mpls(b, flow->dl_type, flow->mpls_lse[--n]); + } } } diff --git a/lib/flow.h b/lib/flow.h index 9e8549d..091d5f4 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -36,7 +36,7 @@ struct ofpbuf; /* This sequence number should be incremented whenever anything involving flows * or the wildcarding of flows changes. This will cause build assertion * failures in places which likely need to be updated. */ -#define FLOW_WC_SEQ 23 +#define FLOW_WC_SEQ 24 #define FLOW_N_REGS 8 BUILD_ASSERT_DECL(FLOW_N_REGS <= NXM_NX_MAX_REGS); @@ -108,7 +108,7 @@ struct flow { ovs_be16 vlan_tci; /* If 802.1Q, TCI | VLAN_CFI; otherwise 0. */ /* L3 */ - ovs_be32 mpls_lse; /* MPLS label stack entry. */ + ovs_be32 mpls_lse[3]; /* MPLS label stack entry. */ struct in6_addr ipv6_src; /* IPv6 source address. */ struct in6_addr ipv6_dst; /* IPv6 destination address. */ struct in6_addr nd_target; /* IPv6 neighbor discovery (ND) target. */ @@ -123,6 +123,7 @@ struct flow { uint8_t arp_tha[6]; /* ARP/ND target hardware address. */ ovs_be16 tcp_flags; /* TCP flags. With L3 to avoid matching L4. */ ovs_be16 pad; /* Padding. */ + /* L4 */ ovs_be16 tp_src; /* TCP/UDP/SCTP source port. */ ovs_be16 tp_dst; /* TCP/UDP/SCTP destination port. @@ -134,8 +135,8 @@ BUILD_ASSERT_DECL(sizeof(struct flow) % 4 == 0); /* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */ BUILD_ASSERT_DECL(offsetof(struct flow, tp_dst) + 2 - == sizeof(struct flow_tnl) + 156 - && FLOW_WC_SEQ == 23); + == sizeof(struct flow_tnl) + 164 + && FLOW_WC_SEQ == 24); /* Incremental points at which flow classification may be performed in * segments. @@ -194,10 +195,14 @@ void flow_set_dl_vlan(struct flow *, ovs_be16 vid); void flow_set_vlan_vid(struct flow *, ovs_be16 vid); void flow_set_vlan_pcp(struct flow *, uint8_t pcp); -void flow_set_mpls_label(struct flow *flow, ovs_be32 label); -void flow_set_mpls_ttl(struct flow *flow, uint8_t ttl); -void flow_set_mpls_tc(struct flow *flow, uint8_t tc); -void flow_set_mpls_bos(struct flow *flow, uint8_t stack); +int flow_count_mpls_labels(const struct flow *); +void flow_push_mpls(struct flow *, ovs_be32 mpls_eth_type, + struct flow_wildcards *); +bool flow_pop_mpls(struct flow *, ovs_be32 eth_type, struct flow_wildcards *); +void flow_set_mpls_label(struct flow *, int idx, ovs_be32 label); +void flow_set_mpls_ttl(struct flow *, int idx, uint8_t ttl); +void flow_set_mpls_tc(struct flow *, int idx, uint8_t tc); +void flow_set_mpls_bos(struct flow *, int idx, uint8_t stack); void flow_compose(struct ofpbuf *, const struct flow *); diff --git a/lib/match.c b/lib/match.c index cc18a6a..97216f3 100644 --- a/lib/match.c +++ b/lib/match.c @@ -460,53 +460,53 @@ match_set_dl_vlan_pcp(struct match *match, uint8_t dl_vlan_pcp) /* Modifies 'match' so that the MPLS label is wildcarded. */ void -match_set_any_mpls_label(struct match *match) +match_set_any_mpls_label(struct match *match, int idx) { - match->wc.masks.mpls_lse &= ~htonl(MPLS_LABEL_MASK); - flow_set_mpls_label(&match->flow, htonl(0)); + match->wc.masks.mpls_lse[idx] &= ~htonl(MPLS_LABEL_MASK); + flow_set_mpls_label(&match->flow, idx, htonl(0)); } /* Modifies 'match' so that it matches only packets with an MPLS header whose * label equals the low 20 bits of 'mpls_label'. */ void -match_set_mpls_label(struct match *match, ovs_be32 mpls_label) +match_set_mpls_label(struct match *match, int idx, ovs_be32 mpls_label) { - match->wc.masks.mpls_lse |= htonl(MPLS_LABEL_MASK); - flow_set_mpls_label(&match->flow, mpls_label); + match->wc.masks.mpls_lse[idx] |= htonl(MPLS_LABEL_MASK); + flow_set_mpls_label(&match->flow, idx, mpls_label); } /* Modifies 'match' so that the MPLS TC is wildcarded. */ void -match_set_any_mpls_tc(struct match *match) +match_set_any_mpls_tc(struct match *match, int idx) { - match->wc.masks.mpls_lse &= ~htonl(MPLS_TC_MASK); - flow_set_mpls_tc(&match->flow, 0); + match->wc.masks.mpls_lse[idx] &= ~htonl(MPLS_TC_MASK); + flow_set_mpls_tc(&match->flow, idx, 0); } /* Modifies 'match' so that it matches only packets with an MPLS header whose * Traffic Class equals the low 3 bits of 'mpls_tc'. */ void -match_set_mpls_tc(struct match *match, uint8_t mpls_tc) +match_set_mpls_tc(struct match *match, int idx, uint8_t mpls_tc) { - match->wc.masks.mpls_lse |= htonl(MPLS_TC_MASK); - flow_set_mpls_tc(&match->flow, mpls_tc); + match->wc.masks.mpls_lse[idx] |= htonl(MPLS_TC_MASK); + flow_set_mpls_tc(&match->flow, idx, mpls_tc); } /* Modifies 'match' so that the MPLS stack flag is wildcarded. */ void -match_set_any_mpls_bos(struct match *match) +match_set_any_mpls_bos(struct match *match, int idx) { - match->wc.masks.mpls_lse &= ~htonl(MPLS_BOS_MASK); - flow_set_mpls_bos(&match->flow, 0); + match->wc.masks.mpls_lse[idx] &= ~htonl(MPLS_BOS_MASK); + flow_set_mpls_bos(&match->flow, idx, 0); } /* Modifies 'match' so that it matches only packets with an MPLS header whose * Stack Flag equals the lower bit of 'mpls_bos' */ void -match_set_mpls_bos(struct match *match, uint8_t mpls_bos) +match_set_mpls_bos(struct match *match, int idx, uint8_t mpls_bos) { - match->wc.masks.mpls_lse |= htonl(MPLS_BOS_MASK); - flow_set_mpls_bos(&match->flow, mpls_bos); + match->wc.masks.mpls_lse[idx] |= htonl(MPLS_BOS_MASK); + flow_set_mpls_bos(&match->flow, idx, mpls_bos); } void @@ -796,6 +796,22 @@ format_be16_masked(struct ds *s, const char *name, } static void +format_be32_masked(struct ds *s, const char *name, + ovs_be32 value, ovs_be32 mask) +{ + if (mask != htonl(0)) { + ds_put_format(s, "%s=", name); + if (mask == OVS_BE32_MAX) { + ds_put_format(s, "%"PRIu32, ntohl(value)); + } else { + ds_put_format(s, "0x%"PRIx32"/0x%"PRIx32, + ntohl(value), ntohl(mask)); + } + ds_put_char(s, ','); + } +} + +static void format_uint32_masked(struct ds *s, const char *name, uint32_t value, uint32_t mask) { @@ -856,7 +872,7 @@ match_format(const struct match *match, struct ds *s, unsigned int priority) int i; - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 23); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 24); if (priority != OFP_DEFAULT_PRIORITY) { ds_put_format(s, "priority=%u,", priority); @@ -1008,22 +1024,10 @@ match_format(const struct match *match, struct ds *s, unsigned int priority) if (wc->masks.nw_ttl) { ds_put_format(s, "nw_ttl=%"PRIu8",", f->nw_ttl); } - if (wc->masks.mpls_lse & htonl(MPLS_LABEL_MASK)) { - ds_put_format(s, "mpls_label=%"PRIu32",", - mpls_lse_to_label(f->mpls_lse)); - } - if (wc->masks.mpls_lse & htonl(MPLS_TC_MASK)) { - ds_put_format(s, "mpls_tc=%"PRIu8",", - mpls_lse_to_tc(f->mpls_lse)); - } - if (wc->masks.mpls_lse & htonl(MPLS_TTL_MASK)) { - ds_put_format(s, "mpls_ttl=%"PRIu8",", - mpls_lse_to_ttl(f->mpls_lse)); - } - if (wc->masks.mpls_lse & htonl(MPLS_BOS_MASK)) { - ds_put_format(s, "mpls_bos=%"PRIu8",", - mpls_lse_to_bos(f->mpls_lse)); - } + format_be32_masked(s, "mpls_lse0", f->mpls_lse[0], wc->masks.mpls_lse[0]); + format_be32_masked(s, "mpls_lse1", f->mpls_lse[1], wc->masks.mpls_lse[1]); + format_be32_masked(s, "mpls_lse2", f->mpls_lse[2], wc->masks.mpls_lse[2]); + switch (wc->masks.nw_frag) { case FLOW_NW_FRAG_ANY | FLOW_NW_FRAG_LATER: ds_put_format(s, "nw_frag=%s,", diff --git a/lib/match.h b/lib/match.h index ee01acd..7a8ae68 100644 --- a/lib/match.h +++ b/lib/match.h @@ -78,13 +78,16 @@ void match_set_vlan_vid(struct match *, ovs_be16); void match_set_vlan_vid_masked(struct match *, ovs_be16 vid, ovs_be16 mask); void match_set_any_pcp(struct match *); void match_set_dl_vlan_pcp(struct match *, uint8_t); -void match_set_any_mpls_label(struct match *); -void match_set_mpls_label(struct match *, ovs_be32); -void match_set_any_mpls_tc(struct match *); -void match_set_mpls_tc(struct match *, uint8_t); -void match_set_any_mpls_bos(struct match *); -void match_set_mpls_bos(struct match *, uint8_t); +void match_set_any_mpls_lse(struct match *, int idx); +void match_set_mpls_lse(struct match *, int idx, ovs_be32); +void match_set_any_mpls_label(struct match *, int idx); +void match_set_mpls_label(struct match *, int idx, ovs_be32); +void match_set_any_mpls_tc(struct match *, int idx); +void match_set_mpls_tc(struct match *, int idx, uint8_t); +void match_set_any_mpls_bos(struct match *, int idx); +void match_set_mpls_bos(struct match *, int idx, uint8_t); void match_set_tp_src(struct match *, ovs_be16); +void match_set_mpls_lse(struct match *, int idx, ovs_be32 lse); void match_set_tp_src_masked(struct match *, ovs_be16 port, ovs_be16 mask); void match_set_tp_dst(struct match *, ovs_be16); void match_set_tp_dst_masked(struct match *, ovs_be16 port, ovs_be16 mask); diff --git a/lib/meta-flow.c b/lib/meta-flow.c index 96e0efe..96eb82b 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, }, /* ## -- ## */ @@ -926,11 +962,15 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc) return !(wc->masks.vlan_tci & htons(VLAN_PCP_MASK)); case MFF_MPLS_LABEL: - return !(wc->masks.mpls_lse & htonl(MPLS_LABEL_MASK)); + return !(wc->masks.mpls_lse[0] & htonl(MPLS_LABEL_MASK)); case MFF_MPLS_TC: - return !(wc->masks.mpls_lse & htonl(MPLS_TC_MASK)); + return !(wc->masks.mpls_lse[1] & htonl(MPLS_TC_MASK)); case MFF_MPLS_BOS: - return !(wc->masks.mpls_lse & htonl(MPLS_BOS_MASK)); + return !(wc->masks.mpls_lse[2] & 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: @@ -1302,15 +1361,21 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow, break; case MFF_MPLS_LABEL: - value->be32 = htonl(mpls_lse_to_label(flow->mpls_lse)); + value->be32 = htonl(mpls_lse_to_label(flow->mpls_lse[0])); break; case MFF_MPLS_TC: - value->u8 = mpls_lse_to_tc(flow->mpls_lse); + value->u8 = mpls_lse_to_tc(flow->mpls_lse[0]); break; case MFF_MPLS_BOS: - value->u8 = mpls_lse_to_bos(flow->mpls_lse); + 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: @@ -1498,15 +1563,21 @@ mf_set_value(const struct mf_field *mf, break; case MFF_MPLS_LABEL: - match_set_mpls_label(match, value->be32); + match_set_mpls_label(match, 0, value->be32); break; case MFF_MPLS_TC: - match_set_mpls_tc(match, value->u8); + match_set_mpls_tc(match, 0, value->u8); break; case MFF_MPLS_BOS: - match_set_mpls_bos(match, value->u8); + 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: @@ -1711,15 +1782,21 @@ mf_set_flow_value(const struct mf_field *mf, break; case MFF_MPLS_LABEL: - flow_set_mpls_label(flow, value->be32); + flow_set_mpls_label(flow, 0, value->be32); break; case MFF_MPLS_TC: - flow_set_mpls_tc(flow, value->u8); + flow_set_mpls_tc(flow, 0, value->u8); break; case MFF_MPLS_BOS: - flow_set_mpls_bos(flow, value->u8); + 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: @@ -1921,15 +1998,21 @@ mf_set_wild(const struct mf_field *mf, struct match *match) break; case MFF_MPLS_LABEL: - match_set_any_mpls_label(match); + match_set_any_mpls_label(match, 0); break; case MFF_MPLS_TC: - match_set_any_mpls_tc(match); + match_set_any_mpls_tc(match, 0); break; case MFF_MPLS_BOS: - match_set_any_mpls_bos(match); + 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: @@ -2070,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 983fd7d..b8b2753 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -572,7 +572,7 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match *match, int match_len; int i; - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 23); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 24); /* Metadata. */ if (match->wc.masks.in_port.ofp_port) { @@ -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 & htonl(MPLS_TC_MASK)) { - nxm_put_8(b, OXM_OF_MPLS_TC, mpls_lse_to_tc(flow->mpls_lse)); - } + uint32_t mask0 = match->wc.masks.mpls_lse[0]; + if (mask0) { + ovs_be32 lse0 = flow->mpls_lse[0]; + uint32_t tc_mask = mask0 & htonl(MPLS_TC_MASK); + uint32_t bos_mask = mask0 & htonl(MPLS_BOS_MASK); + uint32_t label_mask = mask0 & htonl(MPLS_LABEL_MASK); + uint32_t 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 & htonl(MPLS_BOS_MASK)) { - nxm_put_8(b, OXM_OF_MPLS_BOS, mpls_lse_to_bos(flow->mpls_lse)); + 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 & htonl(MPLS_LABEL_MASK)) { - nxm_put_32(b, OXM_OF_MPLS_LABEL, - htonl(mpls_lse_to_label(flow->mpls_lse))); + 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]); } } diff --git a/lib/odp-util.c b/lib/odp-util.c index f44c7d4..0cb1250 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -352,20 +352,33 @@ format_mpls_lse(struct ds *ds, ovs_be32 mpls_lse) static void format_mpls(struct ds *ds, const struct ovs_key_mpls *mpls_key, - const struct ovs_key_mpls *mpls_mask) + const struct ovs_key_mpls *mpls_mask, int n) { - ovs_be32 key = mpls_key->mpls_lse; + if (n == 1) { + ovs_be32 key = mpls_key->mpls_lse; - if (mpls_mask == NULL) { - format_mpls_lse(ds, key); + if (mpls_mask == NULL) { + format_mpls_lse(ds, key); + } else { + ovs_be32 mask = mpls_mask->mpls_lse; + + ds_put_format(ds, "label=%"PRIu32"/0x%x,tc=%d/%x,ttl=%d/0x%x,bos=%d/%x", + mpls_lse_to_label(key), mpls_lse_to_label(mask), + mpls_lse_to_tc(key), mpls_lse_to_tc(mask), + mpls_lse_to_ttl(key), mpls_lse_to_ttl(mask), + mpls_lse_to_bos(key), mpls_lse_to_bos(mask)); + } } else { - ovs_be32 mask = mpls_mask->mpls_lse; + int i; - ds_put_format(ds, "label=%"PRIu32"/0x%x,tc=%d/%x,ttl=%d/0x%x,bos=%d/%x", - mpls_lse_to_label(key), mpls_lse_to_label(mask), - mpls_lse_to_tc(key), mpls_lse_to_tc(mask), - mpls_lse_to_ttl(key), mpls_lse_to_ttl(mask), - mpls_lse_to_bos(key), mpls_lse_to_bos(mask)); + for (i = 0; i < n; i++) { + ds_put_format(ds, "lse%d=%#"PRIx32, i, mpls_key[i].mpls_lse); + if (mpls_mask) { + ds_put_format(ds, "%#"PRIx32, mpls_mask[i].mpls_lse); + } + ds_put_char(ds, ','); + } + ds_chomp(ds, ','); } } @@ -721,7 +734,7 @@ odp_flow_key_attr_len(uint16_t type) case OVS_KEY_ATTR_ETHERNET: return sizeof(struct ovs_key_ethernet); case OVS_KEY_ATTR_VLAN: return sizeof(ovs_be16); case OVS_KEY_ATTR_ETHERTYPE: return 2; - case OVS_KEY_ATTR_MPLS: return sizeof(struct ovs_key_mpls); + case OVS_KEY_ATTR_MPLS: return -2; case OVS_KEY_ATTR_IPV4: return sizeof(struct ovs_key_ipv4); case OVS_KEY_ATTR_IPV6: return sizeof(struct ovs_key_ipv6); case OVS_KEY_ATTR_TCP: return sizeof(struct ovs_key_tcp); @@ -1115,10 +1128,23 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma, case OVS_KEY_ATTR_MPLS: { const struct ovs_key_mpls *mpls_key = nl_attr_get(a); const struct ovs_key_mpls *mpls_mask = NULL; + size_t size = nl_attr_get_size(a); + + if (!size || size % sizeof *mpls_key) { + ds_put_format(ds, "(bad key length %"PRIuSIZE")", + nl_attr_get_size(a)); + return; + } if (!is_exact) { mpls_mask = nl_attr_get(ma); + if (nl_attr_get_size(a) != nl_attr_get_size(ma)) { + ds_put_format(ds, "(key length %"PRIuSIZE" != " + "mask length %"PRIuSIZE")", + nl_attr_get_size(a), nl_attr_get_size(ma)); + return; + } } - format_mpls(ds, mpls_key, mpls_mask); + format_mpls(ds, mpls_key, mpls_mask, size / sizeof *mpls_key); break; } @@ -2493,10 +2519,14 @@ odp_flow_key_from_flow__(struct ofpbuf *buf, const struct flow *data, memcpy(arp_key->arp_tha, data->arp_tha, ETH_ADDR_LEN); } else if (eth_type_mpls(flow->dl_type)) { struct ovs_key_mpls *mpls_key; + int i, n; + n = flow_count_mpls_labels(flow); mpls_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_MPLS, - sizeof *mpls_key); - mpls_key->mpls_lse = data->mpls_lse; + n * sizeof *mpls_key); + for (i = 0; i < n; i++) { + mpls_key[i].mpls_lse = data->mpls_lse[i]; + } } if (is_ip_any(flow) && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) { @@ -2781,21 +2811,34 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], enum ovs_key_attr expected_bit = 0xff; if (eth_type_mpls(src_flow->dl_type)) { + size_t size = nl_attr_get_size(attrs[OVS_KEY_ATTR_MPLS]); + const ovs_be32 *mpls_lse = nl_attr_get(attrs[OVS_KEY_ATTR_MPLS]); + int n = size / sizeof(ovs_be32); + int i; + + if (!size || size % sizeof(ovs_be32)) { + return ODP_FIT_ERROR; + } + if (!is_mask) { expected_attrs |= (UINT64_C(1) << OVS_KEY_ATTR_MPLS); if (!(present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_MPLS))) { return ODP_FIT_TOO_LITTLE; } - flow->mpls_lse = nl_attr_get_be32(attrs[OVS_KEY_ATTR_MPLS]); } else if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_MPLS)) { - flow->mpls_lse = nl_attr_get_be32(attrs[OVS_KEY_ATTR_MPLS]); - if (flow->mpls_lse != 0 && flow->dl_type != htons(0xffff)) { return ODP_FIT_ERROR; } expected_attrs |= (UINT64_C(1) << OVS_KEY_ATTR_MPLS); } + + for (i = 0; i < n && i < ARRAY_SIZE(flow->mpls_lse); i++) { + flow->mpls_lse[i] = mpls_lse[i]; + } + if (n > ARRAY_SIZE(flow->mpls_lse)) { + return ODP_FIT_TOO_MUCH; + } goto done; } else if (src_flow->dl_type == htons(ETH_TYPE_IP)) { if (!is_mask) { @@ -3352,43 +3395,9 @@ commit_vlan_action(ovs_be16 vlan_tci, struct flow *base, static void commit_mpls_action(const struct flow *flow, struct flow *base, - struct ofpbuf *odp_actions, struct flow_wildcards *wc, - int *mpls_depth_delta) + struct ofpbuf *odp_actions, struct flow_wildcards *wc) { - if (flow->mpls_lse == base->mpls_lse && !*mpls_depth_delta) { - return; - } - - memset(&wc->masks.mpls_lse, 0xff, sizeof wc->masks.mpls_lse); - - switch (*mpls_depth_delta) { - case -1: - nl_msg_put_be16(odp_actions, OVS_ACTION_ATTR_POP_MPLS, flow->dl_type); - break; - case 1: { - struct ovs_action_push_mpls *mpls; - - mpls = nl_msg_put_unspec_zero(odp_actions, OVS_ACTION_ATTR_PUSH_MPLS, - sizeof *mpls); - mpls->mpls_ethertype = flow->dl_type; - mpls->mpls_lse = flow->mpls_lse; - break; - } - case 0: { - struct ovs_key_mpls mpls_key; - - mpls_key.mpls_lse = flow->mpls_lse; - commit_set_action(odp_actions, OVS_KEY_ATTR_MPLS, - &mpls_key, sizeof(mpls_key)); - break; - } - default: - OVS_NOT_REACHED(); - } - - base->dl_type = flow->dl_type; - base->mpls_lse = flow->mpls_lse; - *mpls_depth_delta = 0; + /* XXX need to fill this in */ } static void @@ -3609,20 +3618,15 @@ commit_set_pkt_mark_action(const struct flow *flow, struct flow *base, * slow path, if there is one, otherwise 0. */ enum slow_path_reason commit_odp_actions(const struct flow *flow, struct flow *base, - struct ofpbuf *odp_actions, struct flow_wildcards *wc, - int *mpls_depth_delta) + struct ofpbuf *odp_actions, struct flow_wildcards *wc) { enum slow_path_reason slow; commit_set_ether_addr_action(flow, base, odp_actions, wc); - commit_vlan_action(flow->vlan_tci, base, odp_actions, wc); slow = commit_set_nw_action(flow, base, odp_actions, wc); commit_set_port_action(flow, base, odp_actions, wc); - /* Committing MPLS actions should occur after committing nw and port - * actions. This is because committing MPLS actions may alter a packet so - * that it is no longer IP and thus nw and port actions are no longer valid. - */ - commit_mpls_action(flow, base, odp_actions, wc, mpls_depth_delta); + commit_mpls_action(flow, base, odp_actions, wc); + commit_vlan_action(flow->vlan_tci, base, odp_actions, wc); commit_set_priority_action(flow, base, odp_actions, wc); commit_set_pkt_mark_action(flow, base, odp_actions, wc); diff --git a/lib/odp-util.h b/lib/odp-util.h index 821b2c4..a222a35 100644 --- a/lib/odp-util.h +++ b/lib/odp-util.h @@ -174,8 +174,7 @@ void commit_odp_tunnel_action(const struct flow *, struct flow *base, enum slow_path_reason commit_odp_actions(const struct flow *, struct flow *base, struct ofpbuf *odp_actions, - struct flow_wildcards *wc, - int *mpls_depth_delta); + struct flow_wildcards *wc); /* ofproto-dpif interface. * diff --git a/lib/ofp-util.c b/lib/ofp-util.c index a0a372f..98cd41d 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -84,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 == 23); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 24); /* Initialize most of wc. */ flow_wildcards_init_catchall(wc); @@ -437,10 +437,10 @@ ofputil_match_from_ofp11_match(const struct ofp11_match *ofmatch, if (eth_type_mpls(match->flow.dl_type)) { if (!(wc & OFPFW11_MPLS_LABEL)) { - match_set_mpls_label(match, ofmatch->mpls_label); + match_set_mpls_label(match, 0, ofmatch->mpls_label); } if (!(wc & OFPFW11_MPLS_TC)) { - match_set_mpls_tc(match, ofmatch->mpls_tc); + match_set_mpls_tc(match, 0, ofmatch->mpls_tc); } } @@ -533,16 +533,17 @@ ofputil_match_to_ofp11_match(const struct match *match, ofmatch->tp_dst = match->flow.tp_dst; } - if (!(match->wc.masks.mpls_lse & htonl(MPLS_LABEL_MASK))) { + if (!(match->wc.masks.mpls_lse[0] & htonl(MPLS_LABEL_MASK))) { wc |= OFPFW11_MPLS_LABEL; } else { - ofmatch->mpls_label = htonl(mpls_lse_to_label(match->flow.mpls_lse)); + ofmatch->mpls_label = htonl(mpls_lse_to_label( + match->flow.mpls_lse[0])); } - if (!(match->wc.masks.mpls_lse & htonl(MPLS_TC_MASK))) { + if (!(match->wc.masks.mpls_lse[0] & htonl(MPLS_TC_MASK))) { wc |= OFPFW11_MPLS_TC; } else { - ofmatch->mpls_tc = mpls_lse_to_tc(match->flow.mpls_lse); + ofmatch->mpls_tc = mpls_lse_to_tc(match->flow.mpls_lse[0]); } ofmatch->metadata = match->flow.metadata; @@ -5346,7 +5347,7 @@ ofputil_normalize_match__(struct match *match, bool may_log) wc.masks.nd_target = in6addr_any; } if (!(may_match & MAY_MPLS)) { - wc.masks.mpls_lse = htonl(0); + memset(wc.masks.mpls_lse, 0, sizeof wc.masks.mpls_lse); } /* Log any changes. */ diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 848c778..b56a746 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -165,13 +165,6 @@ struct xlate_ctx { /* The rule that we are currently translating, or NULL. */ struct rule_dpif *rule; - int mpls_depth_delta; /* Delta of the mpls stack depth since - * actions were last committed. - * Must be between -1 and 1 inclusive. */ - ovs_be32 pre_push_mpls_lse; /* Used to record the top-most MPLS LSE - * prior to an mpls_push so that it may be - * used for a subsequent mpls_pop. */ - /* Resubmit statistics, via xlate_table_action(). */ int recurse; /* Current resubmit nesting depth. */ int resubmits; /* Total number of resubmits. */ @@ -1687,7 +1680,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, /* If 'struct flow' gets additional metadata, we'll need to zero it out * before traversing a patch port. */ - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 23); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 24); if (!xport) { xlate_report(ctx, "Nonexistent output port"); @@ -1802,8 +1795,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, if (out_port != ODPP_NONE) { ctx->xout->slow |= commit_odp_actions(flow, &ctx->base_flow, &ctx->xout->odp_actions, - &ctx->xout->wc, - &ctx->mpls_depth_delta); + &ctx->xout->wc); nl_msg_put_odp_port(&ctx->xout->odp_actions, OVS_ACTION_ATTR_OUTPUT, out_port); @@ -2082,8 +2074,7 @@ execute_controller_action(struct xlate_ctx *ctx, int len, ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow, &ctx->xout->odp_actions, - &ctx->xout->wc, - &ctx->mpls_depth_delta); + &ctx->xout->wc); odp_execute_actions(NULL, packet, &key, ctx->xout->odp_actions.data, ctx->xout->odp_actions.size, NULL, NULL); @@ -2107,99 +2098,41 @@ execute_controller_action(struct xlate_ctx *ctx, int len, ofpbuf_delete(packet); } -static bool -compose_mpls_push_action(struct xlate_ctx *ctx, ovs_be16 eth_type) +static void +compose_mpls_push_action(struct xlate_ctx *ctx, struct ofpact_push_mpls *mpls) { struct flow_wildcards *wc = &ctx->xout->wc; struct flow *flow = &ctx->xin->flow; + ovs_be16 vlan_tci = flow->vlan_tci; + int n; - ovs_assert(eth_type_mpls(eth_type)); - - /* If mpls_depth_delta is negative then an MPLS POP action has been - * composed and the resulting MPLS label stack is unknown. This means - * an MPLS PUSH action can't be composed as it needs to know either the - * top-most MPLS LSE to use as a template for the new MPLS LSE, or that - * there is no MPLS label stack present. Thus, stop processing. - * - * If mpls_depth_delta is positive then an MPLS PUSH action has been - * composed and no further MPLS PUSH action may be performed without - * losing MPLS LSE and ether type information held in xtx->xin->flow. - * Thus, stop processing. - * - * If the MPLS LSE of the flow and base_flow differ then the MPLS LSE - * has been updated. Performing a MPLS PUSH action may be would result in - * losing MPLS LSE and ether type information held in xtx->xin->flow. - * Thus, stop processing. - * - * It is planned that in the future this case will be handled - * by recirculation */ - if (ctx->mpls_depth_delta || - ctx->xin->flow.mpls_lse != ctx->base_flow.mpls_lse) { - return true; - } - - memset(&wc->masks.mpls_lse, 0xff, sizeof wc->masks.mpls_lse); - - ctx->pre_push_mpls_lse = ctx->xin->flow.mpls_lse; + ovs_assert(eth_type_mpls(mpls->ethertype)); - if (eth_type_mpls(ctx->xin->flow.dl_type)) { - flow->mpls_lse &= ~htonl(MPLS_BOS_MASK); - } else { - ovs_be32 label; - uint8_t tc, ttl; - - if (flow->dl_type == htons(ETH_TYPE_IPV6)) { - label = htonl(0x2); /* IPV6 Explicit Null. */ + n = flow_count_mpls_labels(flow); + if (!n) { + if (mpls->position == OFPACT_MPLS_BEFORE_VLAN) { + vlan_tci = 0; } else { - label = htonl(0x0); /* IPV4 Explicit Null. */ + flow->vlan_tci = 0; } - wc->masks.nw_tos |= IP_DSCP_MASK; - wc->masks.nw_ttl = 0xff; - tc = (flow->nw_tos & IP_DSCP_MASK) >> 2; - ttl = flow->nw_ttl ? flow->nw_ttl : 0x40; - flow->mpls_lse = set_mpls_lse_values(ttl, tc, 1, label); + ctx->xout->slow |= commit_odp_actions(flow, &ctx->base_flow, + &ctx->xout->odp_actions, + &ctx->xout->wc); + } else if (n >= ARRAY_SIZE(flow->mpls_lse)) { + return; } - flow->dl_type = eth_type; - ctx->mpls_depth_delta++; - return false; + flow_push_mpls(flow, mpls->ethertype, wc); + flow->vlan_tci = vlan_tci; } -static bool +static void compose_mpls_pop_action(struct xlate_ctx *ctx, ovs_be16 eth_type) { struct flow_wildcards *wc = &ctx->xout->wc; + struct flow *flow = &ctx->xin->flow; - if (!eth_type_mpls(ctx->xin->flow.dl_type)) { - return true; - } - - /* If mpls_depth_delta is negative then an MPLS POP action has been - * composed. Performing another MPLS POP action - * would result in losing ether type that results from - * the already composed MPLS POP. Thus, stop processing. - * - * It is planned that in the future this case will be handled - * by recirculation */ - if (ctx->mpls_depth_delta < 0) { - return true; - } - - memset(&wc->masks.mpls_lse, 0xff, sizeof wc->masks.mpls_lse); - - /* If mpls_depth_delta is positive then an MPLS PUSH action has been - * executed and the previous MPLS LSE saved in ctx->pre_push_mpls_lse. The - * flow's MPLS LSE should be restored to that value to allow any - * subsequent actions that update of the LSE to be executed correctly. - */ - if (ctx->mpls_depth_delta > 0) { - ctx->xin->flow.mpls_lse = ctx->pre_push_mpls_lse; - } - - ctx->xin->flow.dl_type = eth_type; - ctx->mpls_depth_delta--; - - return false; + flow_pop_mpls(flow, eth_type, wc); } static bool @@ -2228,99 +2161,53 @@ compose_dec_ttl(struct xlate_ctx *ctx, struct ofpact_cnt_ids *ids) } } -static bool +static void compose_set_mpls_label_action(struct xlate_ctx *ctx, ovs_be32 label) { - if (!eth_type_mpls(ctx->xin->flow.dl_type)) { - return true; - } - - /* If mpls_depth_delta is negative then an MPLS POP action has been - * executed and the resulting MPLS label stack is unknown. This means - * a SET MPLS LABEL action can't be executed as it needs to manipulate - * the top-most MPLS LSE. Thus, stop processing. - * - * It is planned that in the future this case will be handled - * by recirculation. - */ - if (ctx->mpls_depth_delta < 0) { - return true; + if (eth_type_mpls(ctx->xin->flow.dl_type)) { + ctx->xout->wc.masks.mpls_lse[0] |= htonl(MPLS_LABEL_MASK); + set_mpls_lse_label(&ctx->xin->flow.mpls_lse[0], label); } - - ctx->xout->wc.masks.mpls_lse |= htonl(MPLS_LABEL_MASK); - set_mpls_lse_label(&ctx->xin->flow.mpls_lse, label); - return false; } -static bool +static void compose_set_mpls_tc_action(struct xlate_ctx *ctx, uint8_t tc) { - if (!eth_type_mpls(ctx->xin->flow.dl_type)) { - return true; - } - - /* If mpls_depth_delta is negative then an MPLS POP action has been - * executed and the resulting MPLS label stack is unknown. This means - * a SET MPLS TC action can't be executed as it needs to manipulate - * the top-most MPLS LSE. Thus, stop processing. - * - * It is planned that in the future this case will be handled - * by recirculation. - */ - if (ctx->mpls_depth_delta < 0) { - return true; + if (eth_type_mpls(ctx->xin->flow.dl_type)) { + ctx->xout->wc.masks.mpls_lse[0] |= htonl(MPLS_TC_MASK); + set_mpls_lse_tc(&ctx->xin->flow.mpls_lse[0], tc); } - - ctx->xout->wc.masks.mpls_lse |= htonl(MPLS_TC_MASK); - set_mpls_lse_tc(&ctx->xin->flow.mpls_lse, tc); - return false; } -static bool +static void compose_set_mpls_ttl_action(struct xlate_ctx *ctx, uint8_t ttl) { - if (!eth_type_mpls(ctx->xin->flow.dl_type)) { - return true; - } - - /* If mpls_depth_delta is negative then an MPLS POP action has been - * executed and the resulting MPLS label stack is unknown. This means - * a SET MPLS TTL push action can't be executed as it needs to manipulate - * the top-most MPLS LSE. Thus, stop processing. - * - * It is planned that in the future this case will be handled - * by recirculation. - */ - if (ctx->mpls_depth_delta < 0) { - return true; + if (eth_type_mpls(ctx->xin->flow.dl_type)) { + ctx->xout->wc.masks.mpls_lse[0] |= htonl(MPLS_TTL_MASK); + set_mpls_lse_ttl(&ctx->xin->flow.mpls_lse[0], ttl); } - - ctx->xout->wc.masks.mpls_lse |= htonl(MPLS_TTL_MASK); - set_mpls_lse_ttl(&ctx->xin->flow.mpls_lse, ttl); - return false; } static bool compose_dec_mpls_ttl_action(struct xlate_ctx *ctx) { struct flow *flow = &ctx->xin->flow; - uint8_t ttl = mpls_lse_to_ttl(flow->mpls_lse); + uint8_t ttl = mpls_lse_to_ttl(flow->mpls_lse[0]); struct flow_wildcards *wc = &ctx->xout->wc; memset(&wc->masks.mpls_lse, 0xff, sizeof wc->masks.mpls_lse); + if (eth_type_mpls(flow->dl_type)) { + if (ttl > 1) { + ttl--; + set_mpls_lse_ttl(&flow->mpls_lse[0], ttl); + return false; + } else { + execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, 0); - if (!eth_type_mpls(flow->dl_type)) { - return false; - } - - if (ttl > 1) { - ttl--; - set_mpls_lse_ttl(&flow->mpls_lse, ttl); - return false; + /* Stop processing for current table. */ + return true; + } } else { - execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, 0); - - /* Stop processing for current table. */ return true; } } @@ -2523,8 +2410,7 @@ xlate_sample_action(struct xlate_ctx *ctx, ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow, &ctx->xout->odp_actions, - &ctx->xout->wc, - &ctx->mpls_depth_delta); + &ctx->xout->wc); compose_flow_sample_cookie(os->probability, os->collector_set_id, os->obs_domain_id, os->obs_point_id, &cookie); @@ -2758,38 +2644,24 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_PUSH_MPLS: - if (compose_mpls_push_action(ctx, - ofpact_get_PUSH_MPLS(a)->ethertype)) { - return; - } + compose_mpls_push_action(ctx, ofpact_get_PUSH_MPLS(a)); break; case OFPACT_POP_MPLS: - if (compose_mpls_pop_action(ctx, - ofpact_get_POP_MPLS(a)->ethertype)) { - return; - } + compose_mpls_pop_action(ctx, ofpact_get_POP_MPLS(a)->ethertype); break; case OFPACT_SET_MPLS_LABEL: - if (compose_set_mpls_label_action(ctx, - ofpact_get_SET_MPLS_LABEL(a)->label)) { - return; - } - break; + compose_set_mpls_label_action( + ctx, ofpact_get_SET_MPLS_LABEL(a)->label); + break; case OFPACT_SET_MPLS_TC: - if (compose_set_mpls_tc_action(ctx, - ofpact_get_SET_MPLS_TC(a)->tc)) { - return; - } + compose_set_mpls_tc_action(ctx, ofpact_get_SET_MPLS_TC(a)->tc); break; case OFPACT_SET_MPLS_TTL: - if (compose_set_mpls_ttl_action(ctx, - ofpact_get_SET_MPLS_TTL(a)->ttl)) { - return; - } + compose_set_mpls_ttl_action(ctx, ofpact_get_SET_MPLS_TTL(a)->ttl); break; case OFPACT_DEC_MPLS_TTL: @@ -3077,7 +2949,6 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout) ctx.orig_skb_priority = flow->skb_priority; ctx.table_id = 0; ctx.exit = false; - ctx.mpls_depth_delta = 0; if (!xin->ofpacts && !ctx.rule) { rule_dpif_lookup(ctx.xbridge->ofproto, flow, diff --git a/utilities/ovs-dpctl.c b/utilities/ovs-dpctl.c index 09db084..3b1dff1 100644 --- a/utilities/ovs-dpctl.c +++ b/utilities/ovs-dpctl.c @@ -1192,9 +1192,9 @@ dpctl_normalize_actions(int argc, char *argv[]) if (eth_type_mpls(af->flow.dl_type)) { printf("mpls(label=%"PRIu32",tc=%d,ttl=%d): ", - mpls_lse_to_label(af->flow.mpls_lse), - mpls_lse_to_tc(af->flow.mpls_lse), - mpls_lse_to_ttl(af->flow.mpls_lse)); + mpls_lse_to_label(af->flow.mpls_lse[0]), + mpls_lse_to_tc(af->flow.mpls_lse[0]), + mpls_lse_to_ttl(af->flow.mpls_lse[0])); } else { printf("no mpls: "); } -- 1.8.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev