[ovs-dev] [PATCH/RFC] ofproto: Drop packet if actions create unkown MPLS label stack

Simon Horman horms at verge.net.au
Thu Jan 9 06:57:55 UTC 2014


The patch "Implement OpenFlow support for MPLS, for up to 3 labels"
allows ovs-vswtichd to fully represent an MPLS label stack containing
up to three labels in a flow.

MPLS push and pop actions are not permitted by that patch in the case where
there are more than three labels present or more than three labels would be
present as the result of an MPLS push action as it is not possible to
accurately describe changes to the MPLS label stack using flows.

This patch alters the behaviour in such situations to drop the packet
rather than skipping to the next action. This avoids the danger of
subsequent actions making invalid assumptions about the packet as a result
of the skipped actions.

As suggested by Jesse Gross.

Cc: Jesse Gross <jesse at nicira.com>
Signed-off-by: Simon Horman <horms at verge.net.au>

---

This is an incremental patch for "Implement OpenFlow support for MPLS, for
up to 3 labels" intended to further discussion of an issue raised by Jesse
Gross. I am happy for it to be squashed into "Implement OpenFlow support
for MPLS, for up to 3 labels" if appropriate.
---
 ofproto/ofproto-dpif-xlate.c | 40 +++++++++++++++++++++++++++++++------
 tests/ofproto-dpif.at        | 47 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 81 insertions(+), 6 deletions(-)

diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index b56a746..79b136f 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -2098,7 +2098,7 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
     ofpbuf_delete(packet);
 }
 
-static void
+static bool
 compose_mpls_push_action(struct xlate_ctx *ctx, struct ofpact_push_mpls *mpls)
 {
     struct flow_wildcards *wc = &ctx->xout->wc;
@@ -2119,20 +2119,43 @@ compose_mpls_push_action(struct xlate_ctx *ctx, struct ofpact_push_mpls *mpls)
                                               &ctx->xout->odp_actions,
                                               &ctx->xout->wc);
     } else if (n >= ARRAY_SIZE(flow->mpls_lse)) {
-        return;
+        if (ctx->xin->packet != NULL) {
+            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+            VLOG_WARN_RL(&rl, "bridge %s: dropping packet which after an "
+                         "MPLS push action will have more MPLS LSEs than "
+                         "the %"PRIuSIZE" that can be handled.",
+                         ctx->xbridge->name, ARRAY_SIZE(flow->mpls_lse) - 1);
+        }
+        ofpbuf_clear(&ctx->xout->odp_actions);
+        return true;
     }
 
     flow_push_mpls(flow, mpls->ethertype, wc);
     flow->vlan_tci = vlan_tci;
+
+    return false;
 }
 
-static void
+static bool
 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;
 
-    flow_pop_mpls(flow, eth_type, wc);
+    if (!flow_pop_mpls(flow, eth_type, wc) &&
+        flow_count_mpls_labels(flow) >= ARRAY_SIZE(flow->mpls_lse)) {
+        if (ctx->xin->packet != NULL) {
+            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+            VLOG_WARN_RL(&rl, "bridge %s: dropping packet on which an "
+                         "MPLS pop action can't be performed as it has "
+                         "have more MPLS LSEs than the %"PRIuSIZE" "
+                         "that can be handled.",
+                         ctx->xbridge->name, ARRAY_SIZE(flow->mpls_lse) - 1);
+        }
+        return true;
+    }
+
+    return false;
 }
 
 static bool
@@ -2644,11 +2667,16 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             break;
 
         case OFPACT_PUSH_MPLS:
-            compose_mpls_push_action(ctx, ofpact_get_PUSH_MPLS(a));
+            if (compose_mpls_push_action(ctx, ofpact_get_PUSH_MPLS(a))) {
+                return;
+            }
             break;
 
         case OFPACT_POP_MPLS:
-            compose_mpls_pop_action(ctx, ofpact_get_POP_MPLS(a)->ethertype);
+            if (compose_mpls_pop_action(ctx,
+                                        ofpact_get_POP_MPLS(a)->ethertype)) {
+                return;
+            }
             break;
 
         case OFPACT_SET_MPLS_LABEL:
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index de6397a..9eaaaa3 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -2380,6 +2380,53 @@ skb_priority(0),skb_mark(0/0),in_port(p3),eth(src=50:54:00:00:00:09/00:00:00:00:
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([ofproto-dpif - ovs-appctl dpif/dump-flows - MPLS actions that result in a drop])
+OVS_VSWITCHD_START([dnl
+   add-port br0 p1 -- set Interface p1 type=dummy
+])
+ON_EXIT([kill `cat ovs-ofctl.pid`])
+
+AT_CAPTURE_FILE([ofctl_monitor.log])
+AT_DATA([flows.txt], [dnl
+dl_src=60:66:66:66:66:00 actions=push_mpls:0x8847,controller
+dl_src=60:66:66:66:66:01 actions=pop_mpls:0x8849,controller
+])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+
+dnl Packet is dropped because an MPLS POP action is applied to a packet with
+dnl 4 MPLS LSEs but ovs-vswtichd can only handle up to 3 MPLS LSEs and thus
+dnl can't determine the resulting MPLS label after an MPLS POP action.
+dnl
+dnl The input is a frame with two MPLS headers which tcpdump -vve shows as:
+dnl 60:66:66:66:66:00 > 50:54:00:00:00:07, ethertype MPLS unicast (0x8847), length 74: MPLS (label 20, exp 0, ttl 32)
+dnl         (label 20, exp 0, ttl 32)
+dnl         (label 20, exp 0, ttl 32)
+dnl         (label 20, exp 0, [S], ttl 32)
+dnl         (tos 0x0, ttl 64, id 0, offset 0, flags [none], proto TCP (6), length 44, bad cksum 3b78 (->f978)!)
+dnl     192.168.0.1.80 > 192.168.0.2.0: Flags [none], cksum 0x7744 (correct), seq 42:46, win 10000, length 4
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 '50 54 00 00 00 07 60 66 66 66 66 00 88 47 00 01 40 20 00 01 40 20 00 01 40 20 00 01 41 20 45 00 00 2c 00 00 00 00 40 06 3b 78 c0 a8 00 01 c0 a8 00 02 00 50 00 00 00 00 00 2a 00 00 00 2a 50 00 27 10 77 44 00 00 48 4f 47 45'])
+
+dnl Packet is dropped because an MPLS PUSH action is applied to a packet with
+dnl 4 MPLS LSEs but ovs-vswtichd can only handle up to 3 MPLS LSEs and thus
+dnl can't determine the resulting MPLS label after an MPLS PUSH action.
+dnl
+dnl The input is a frame with two MPLS headers which tcpdump -vve shows as:
+dnl 60:66:66:66:66:01 > 50:54:00:00:00:07, ethertype MPLS unicast (0x8847), length 74: MPLS (label 20, exp 0, ttl 32)
+dnl         (label 20, exp 0, ttl 32)
+dnl         (label 20, exp 0, ttl 32)
+dnl         (label 20, exp 0, [S], ttl 32)
+dnl         (tos 0x0, ttl 64, id 0, offset 0, flags [none], proto TCP (6), length 44, bad cksum 3b78 (->f978)!)
+dnl     192.168.0.1.80 > 192.168.0.2.0: Flags [none], cksum 0x7744 (correct), seq 42:46, win 10000, length 4
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 '50 54 00 00 00 07 60 66 66 66 66 01 88 47 00 01 40 20 00 01 40 20 00 01 40 20 00 01 41 20 45 00 00 2c 00 00 00 00 40 06 3b 78 c0 a8 00 01 c0 a8 00 02 00 50 00 00 00 00 00 2a 00 00 00 2a 50 00 27 10 77 44 00 00 48 4f 47 45'])
+
+AT_CHECK([ovs-appctl dpif/dump-flows br0 | sort | STRIP_USED], [0], [dnl
+skb_priority(0),in_port(1),eth(src=60:66:66:66:66:00/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x8847),mpls(lse0=0x140200,lse1=0x140200,lse2=0x140200), packets:0, bytes:0, used:never, actions:drop
+skb_priority(0),in_port(1),eth(src=60:66:66:66:66:01/ff:ff:ff:ff:ff:ff,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x8847),mpls(lse0=0x140200,lse1=0x140200,lse2=0x140200), packets:0, bytes:0, used:never, actions:drop
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_SETUP([ofproto-dpif - patch ports])
 OVS_VSWITCHD_START([add-br br1 \
 -- set bridge br1 datapath-type=dummy fail-mode=secure \
-- 
1.8.4




More information about the dev mailing list