[ovs-dev] [PATCH/RFC 09/11] flow: Add an implementation of commit_mpls_action()
Simon Horman
horms at verge.net.au
Wed Dec 25 06:43:52 UTC 2013
This is my interpretation of a
missing piece of "Alternate approach to MPLS"
Signed-off-by: Simon Horman <horms at verge.net.au>
---
lib/flow.c | 32 ++++++++++++++++++++++++++++
lib/flow.h | 2 ++
lib/odp-util.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 99 insertions(+), 1 deletion(-)
diff --git a/lib/flow.c b/lib/flow.c
index e04ce07..2fef1b6 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -1072,6 +1072,38 @@ flow_count_mpls_labels(const struct flow *flow)
}
}
+/* Returns the number consecutive of MPLS LSEs, starting at the
+ * outermost LSE, that are common in 'flow_a' and 'flow_b'
+ */
+int
+flow_count_common_mpls_labels(const struct flow *flow_a,
+ const struct flow *flow_b)
+{
+ int flow_a_n = flow_count_mpls_labels(flow_a);
+ int flow_b_n = flow_count_mpls_labels(flow_b);
+ int min_n = MIN(flow_a_n, flow_b_n);
+
+ if (min_n == 0) {
+ return 0;
+ } else {
+ int common_n = 0;
+ int a_last = flow_a_n - 1;
+ int b_last = flow_b_n - 1;
+ int i;
+
+ for (i = 0; i < min_n; i++) {
+ if (flow_a->mpls_lse[a_last - i] !=
+ flow_b->mpls_lse[b_last - i]) {
+ break;
+ } else {
+ common_n++;
+ }
+ }
+
+ return common_n;
+ }
+}
+
void
flow_push_mpls(struct flow *flow, ovs_be32 mpls_eth_type,
struct flow_wildcards *wc)
diff --git a/lib/flow.h b/lib/flow.h
index 55581ac..3ad7a2c 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -196,6 +196,8 @@ void flow_set_vlan_vid(struct flow *, ovs_be16 vid);
void flow_set_vlan_pcp(struct flow *, uint8_t pcp);
int flow_count_mpls_labels(const struct flow *);
+int flow_count_common_mpls_labels(const struct flow *flow_a,
+ const struct flow *flow_b);
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 *);
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 9bf53c6..0ba603b 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -3397,7 +3397,71 @@ static void
commit_mpls_action(const struct flow *flow, struct flow *base,
struct ofpbuf *odp_actions, struct flow_wildcards *wc)
{
- /* XXX need to fill this in */
+ int base_n = flow_count_mpls_labels(base);
+ int flow_n = flow_count_mpls_labels(flow);
+ int common_n = flow_count_common_mpls_labels(flow, base);
+
+ if (flow_n == base_n && flow_n == common_n) {
+ /* The MPLS LSEs are the same in flow and base, nothing to do */
+ return;
+ } else {
+ while (base_n > common_n) {
+ if (base_n - 1 == common_n && flow_n > common_n) {
+ /* If there is only one more LSE in base than there
+ * are common between base and flow; and flow has
+ * at least one more LSE than is common then the topmost
+ * LSE of base may be updated using set */
+ struct ovs_key_mpls mpls_key;
+
+ mpls_key.mpls_lse = flow->mpls_lse[flow_n - base_n];
+ commit_set_action(odp_actions, OVS_KEY_ATTR_MPLS,
+ &mpls_key, sizeof mpls_key);
+ flow_set_mpls_lse(base, 0, mpls_key.mpls_lse);
+ common_n++;
+ } else {
+ /* Otherwise, if there more LSEs in base than are
+ * common between base and flow then pop the topmost one. */
+ ovs_be16 dl_type;
+ bool popped;
+
+ /* If all the LSEs are to be popped and this is not
+ * the outermost LSE then use ETH_TYPE_MPLS as the ethertype
+ * parameter of the POP_MPLS action instead of * flow->dl_type.
+ *
+ * This is because the POP_MPLS action requires its ethertype
+ * argument to be an MPLS ethernet type but in this case
+ * flow->dl_type will be a non-MPLS ethernet type.
+ *
+ * When the final POP_MPLS action occurs it use
+ * flow->dl_type and the and the resulting packet will
+ * have the desired dl_type. */
+ if ((!eth_type_mpls(flow->dl_type)) && base_n > 1) {
+ dl_type = htons(ETH_TYPE_MPLS);
+ } else {
+ dl_type = flow->dl_type;
+ }
+ nl_msg_put_be16(odp_actions, OVS_ACTION_ATTR_POP_MPLS, dl_type);
+ popped = flow_pop_mpls(base, flow->dl_type, wc);
+ ovs_assert(popped);
+ base_n--;
+ }
+ }
+
+ /* If, after the above popping and setting, there are more LSEs
+ * in flow than base then some LSEs need to be pushed */
+ while (base_n < flow_n) {
+ 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[flow_n - base_n - 1];
+ flow_push_mpls(base, mpls->mpls_ethertype, wc);
+ flow_set_mpls_lse(base, 0, mpls->mpls_lse);
+ base_n++;
+ }
+ }
}
static void
--
1.8.4
More information about the dev
mailing list