This adds support for the OpenFlow 1.1+ set_mpls_ttl action.
And also adds an NX set_mpls_ttl action.

The handling of the TTL decrement is entirely handled in userspace.

Signed-off-by: Simon Horman <ho...@verge.net.au>
---
 include/openflow/nicira-ext.h |    1 +
 lib/flow.c                    |    8 ++++++++
 lib/ofp-actions.c             |   34 ++++++++++++++++++++++++++++++++++
 lib/ofp-actions.h             |    7 ++++---
 lib/ofp-parse.c               |   20 ++++++++++++++++++++
 lib/ofp-util.def              |    2 ++
 lib/packets.c                 |    2 +-
 lib/packets.h                 |    1 +
 ofproto/ofproto-dpif.c        |   34 ++++++++++++++++++++++++++++++++++
 tests/ofproto-dpif.at         |   10 +++++-----
 10 files changed, 110 insertions(+), 9 deletions(-)

diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
index 8199516..46ac0e1 100644
--- a/include/openflow/nicira-ext.h
+++ b/include/openflow/nicira-ext.h
@@ -305,6 +305,7 @@ enum nx_action_subtype {
     NXAST_DEC_TTL_CNT_IDS,      /* struct nx_action_cnt_ids */
     NXAST_PUSH_MPLS,            /* struct nx_action_push_mpls */
     NXAST_POP_MPLS,             /* struct nx_action_pop_mpls */
+    NXAST_DEC_MPLS_TTL,         /* struct nx_action_header */
 };
 
 /* Header for Nicira-defined actions. */
diff --git a/lib/flow.c b/lib/flow.c
index d88dd49..16aab3f 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -887,6 +887,14 @@ flow_set_mpls_label(struct flow *flow, ovs_be32 label)
     set_mpls_lse_label(&flow->mpls_lse, 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)
+{
+    set_mpls_lse_ttl(&flow->mpls_lse, ttl);
+}
+
 /* Sets the MPLS TC that 'flow' matches to 'tc', which should be in the
  * range 0...7. */
 void
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index 13eb367..d19d590 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -165,6 +165,20 @@ dec_ttl_from_openflow(struct ofpbuf *out)
 }
 
 static enum ofperr
+dec_mpls_ttl_from_openflow(struct ofpbuf *out)
+{
+    uint16_t id = 0;
+    struct ofpact_cnt_ids *ids;
+
+    ids = ofpact_put_DEC_MPLS_TTL(out);
+    ids->n_controllers = 1;
+    ofpbuf_put(out, &id, sizeof id);
+    ids = out->l2;
+    ofpact_update_len(out, &ids->ofpact);
+    return 0;
+}
+
+static enum ofperr
 dec_ttl_cnt_ids_from_openflow(const struct nx_action_cnt_ids *nac_ids,
                       struct ofpbuf *out)
 {
@@ -389,6 +403,10 @@ ofpact_from_nxast(const union ofp_action *a, enum 
ofputil_action_code code,
         break;
     }
 
+    case OFPUTIL_NXAST_DEC_MPLS_TTL:
+        error = dec_mpls_ttl_from_openflow(out);
+        break;
+
     case OFPUTIL_NXAST_POP_MPLS: {
         struct nx_action_pop_mpls *nxapm = (struct nx_action_pop_mpls *)a;
         if (nxapm->ethertype == htons(ETH_TYPE_MPLS) ||
@@ -742,6 +760,10 @@ ofpact_from_openflow11(const union ofp_action *a, struct 
ofpbuf *out)
         return nxm_reg_load_from_openflow12_set_field(
             (const struct ofp12_action_set_field *)a, out);
 
+    case OFPUTIL_OFPAT11_DEC_MPLS_TTL:
+        ofpact_put_DEC_MPLS_TTL(out);
+        break;
+
     case OFPUTIL_OFPAT11_PUSH_MPLS: {
         struct ofp11_action_push *oap = (struct ofp11_action_push *)a;
         if (oap->ethertype != htons(ETH_TYPE_MPLS) &&
@@ -1074,6 +1096,7 @@ ofpact_check__(const struct ofpact *a, int max_ports)
         return nxm_reg_load_check(ofpact_get_REG_LOAD(a));
 
     case OFPACT_DEC_TTL:
+    case OFPACT_DEC_MPLS_TTL:
     case OFPACT_SET_TUNNEL:
     case OFPACT_SET_QUEUE:
     case OFPACT_POP_QUEUE:
@@ -1261,6 +1284,10 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf 
*out)
         ofpact_dec_ttl_to_nxast(ofpact_get_DEC_TTL(a), out);
         break;
 
+    case OFPACT_DEC_MPLS_TTL:
+        ofputil_put_NXAST_DEC_MPLS_TTL(out);
+        break;
+
     case OFPACT_SET_TUNNEL:
         ofpact_set_tunnel_to_nxast(ofpact_get_SET_TUNNEL(a), out);
         break;
@@ -1426,6 +1453,7 @@ ofpact_to_openflow10(const struct ofpact *a, struct 
ofpbuf *out)
     case OFPACT_REG_MOVE:
     case OFPACT_REG_LOAD:
     case OFPACT_DEC_TTL:
+    case OFPACT_DEC_MPLS_TTL:
     case OFPACT_SET_TUNNEL:
     case OFPACT_SET_QUEUE:
     case OFPACT_POP_QUEUE:
@@ -1550,6 +1578,7 @@ ofpact_to_openflow11(const struct ofpact *a, struct 
ofpbuf *out)
     case OFPACT_REG_MOVE:
     case OFPACT_REG_LOAD:
     case OFPACT_DEC_TTL:
+    case OFPACT_DEC_MPLS_TTL:
     case OFPACT_SET_TUNNEL:
     case OFPACT_SET_QUEUE:
     case OFPACT_POP_QUEUE:
@@ -1663,6 +1692,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, 
uint16_t port)
     case OFPACT_REG_MOVE:
     case OFPACT_REG_LOAD:
     case OFPACT_DEC_TTL:
+    case OFPACT_DEC_MPLS_TTL:
     case OFPACT_SET_TUNNEL:
     case OFPACT_SET_QUEUE:
     case OFPACT_POP_QUEUE:
@@ -1880,6 +1910,10 @@ ofpact_format(const struct ofpact *a, struct ds *s)
         print_dec_ttl(ofpact_get_DEC_TTL(a), s);
         break;
 
+    case OFPACT_DEC_MPLS_TTL:
+        ds_put_cstr(s, "dec_mpls_ttl");
+        break;
+
     case OFPACT_SET_TUNNEL:
         tunnel = ofpact_get_SET_TUNNEL(a);
         ds_put_format(s, "set_tunnel%s:%#"PRIx64,
diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
index 4c7ae7e..bfbaf5b 100644
--- a/lib/ofp-actions.h
+++ b/lib/ofp-actions.h
@@ -70,6 +70,7 @@
     DEFINE_OFPACT(REG_MOVE,        ofpact_reg_move,      ofpact)    \
     DEFINE_OFPACT(REG_LOAD,        ofpact_reg_load,      ofpact)    \
     DEFINE_OFPACT(DEC_TTL,         ofpact_cnt_ids,       cnt_ids)   \
+    DEFINE_OFPACT(DEC_MPLS_TTL,    ofpact_cnt_ids,       cnt_ids)   \
     DEFINE_OFPACT(PUSH_MPLS,       ofpact_push,          ofpact)    \
     DEFINE_OFPACT(POP_MPLS,        ofpact_pop_mpls,      ofpact)    \
                                                                     \
@@ -178,8 +179,8 @@ ofpact_end(const struct ofpact *ofpacts, size_t ofpacts_len)
 
 /* OFPACT_STRIP_VLAN, OFPACT_POP_QUEUE, OFPACT_EXIT, OFPACT_CLEAR_ACTIONS.
  *
- * Used for OFPAT10_STRIP_VLAN, NXAST_DEC_TTL, NXAST_POP_QUEUE, NXAST_EXIT,
- * OFPIT11_CLEAR_ACTIONS.
+ * Used for OFPAT10_STRIP_VLAN, NXAST_DEC_TTL, NXAST_DEC_MPLS_TTL,
+ * NXAST_POP_QUEUE, NXAST_EXIT, OFPIT11_CLEAR_ACTIONS.
  *
  * Action structure for actions that do not have any extra data beyond the
  * action type. */
@@ -430,7 +431,7 @@ struct ofpact_note {
 
 /* OFPACT_DEC_TTL.
  *
- * Used for NXAST_DEC_TTL and NXAST_DEC_TTL_CNT_IDS. */
+ * Used for NXAST_DEC_TTL, NXAST_DEC_MPLS_TTL and NXAST_DEC_TTL_CNT_IDS. */
 struct ofpact_cnt_ids {
     struct ofpact ofpact;
 
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 339739c..21e62a0 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -315,6 +315,18 @@ parse_dec_ttl(struct ofpbuf *b, char *arg)
 }
 
 static void
+parse_dec_mpls_ttl(struct ofpbuf *b)
+{
+    struct ofpact_cnt_ids *ids = ofpact_put_DEC_MPLS_TTL(b);
+    uint16_t id = 0;
+
+    ofpbuf_put(b, &id, sizeof id);
+    ids = b->l2;
+    ids->n_controllers++;
+    ofpact_update_len(b, &ids->ofpact);
+}
+
+static void
 set_field_parse(const char *arg, struct ofpbuf *ofpacts)
 {
     char *orig = xstrdup(arg);
@@ -510,6 +522,14 @@ parse_named_action(enum ofputil_action_code code, const 
struct flow *flow,
         parse_dec_ttl(ofpacts, arg);
         break;
 
+    case OFPUTIL_NXAST_DEC_MPLS_TTL:
+        parse_dec_mpls_ttl(ofpacts);
+        break;
+
+    case OFPUTIL_OFPAT11_DEC_MPLS_TTL:
+        parse_dec_mpls_ttl(ofpacts);
+        break;
+
     case OFPUTIL_NXAST_FIN_TIMEOUT:
         parse_fin_timeout(ofpacts, arg);
         break;
diff --git a/lib/ofp-util.def b/lib/ofp-util.def
index 2fc22d1..5c82d84 100644
--- a/lib/ofp-util.def
+++ b/lib/ofp-util.def
@@ -30,6 +30,7 @@ OFPAT11_ACTION(OFPAT11_SET_NW_TOS,   ofp_action_nw_tos,   0, 
"mod_nw_tos")
 //OFPAT11_ACTION(OFPAT11_SET_NW_ECN,   ofp11_action_nw_ecn, "0, mod_nw_ecn")
 OFPAT11_ACTION(OFPAT11_SET_TP_SRC,   ofp_action_tp_port,  0, "mod_tp_src")
 OFPAT11_ACTION(OFPAT11_SET_TP_DST,   ofp_action_tp_port,  0, "mod_tp_dst")
+OFPAT11_ACTION(OFPAT11_DEC_MPLS_TTL, ofp_action_header,   0, "dec_mpls_ttl")
 //OFPAT11_ACTION(OFPAT11_PUSH_VLAN,    ofp11_action_push,   0, "push_vlan")
 //OFPAT11_ACTION(OFPAT11_POP_VLAN,     ofp_action_header,   0, "pop_vlan")
 OFPAT11_ACTION(OFPAT11_PUSH_MPLS,    ofp11_action_push,   0, "push_mpls")
@@ -62,6 +63,7 @@ NXAST_ACTION(NXAST_DEC_TTL,         nx_action_header,       
0, "dec_ttl")
 NXAST_ACTION(NXAST_FIN_TIMEOUT,     nx_action_fin_timeout,  0, "fin_timeout")
 NXAST_ACTION(NXAST_CONTROLLER,      nx_action_controller,   0, "controller")
 NXAST_ACTION(NXAST_DEC_TTL_CNT_IDS, nx_action_cnt_ids,      1, NULL)
+NXAST_ACTION(NXAST_DEC_MPLS_TTL,    nx_action_header,       0, "dec_mpls_ttl")
 NXAST_ACTION(NXAST_PUSH_MPLS,       nx_action_push,         0, "push_mpls")
 NXAST_ACTION(NXAST_POP_MPLS,        nx_action_pop_mpls,     0, "pop_mpls")
 
diff --git a/lib/packets.c b/lib/packets.c
index 363749f..18a8633 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -263,7 +263,7 @@ get_ethertype(struct ofpbuf *packet)
 }
 
 /* Set MPLS tag time-to-live. */
-static void
+void
 set_mpls_lse_ttl(ovs_be32 *tag, uint8_t ttl)
 {
     *tag &= ~htonl(MPLS_TTL_MASK);
diff --git a/lib/packets.h b/lib/packets.h
index 172f1a6..8160fbc 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -155,6 +155,7 @@ void set_mpls_lse(struct ofpbuf *, ovs_be32 label);
 void push_mpls(struct ofpbuf *packet, ovs_be16 ethtype);
 void pop_mpls(struct ofpbuf *, ovs_be16 ethtype);
 
+void set_mpls_lse_ttl(ovs_be32 *tag, uint8_t ttl);
 void set_mpls_lse_tc(ovs_be32 *tag, uint8_t tc);
 void set_mpls_lse_label(ovs_be32 *tag, ovs_be32 label);
 void set_mpls_lse_bos(ovs_be32 *tag, uint8_t bos);
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 46da68a..b6affa5 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -5253,6 +5253,34 @@ compose_mpls_pop_action(struct action_xlate_ctx *ctx, 
ovs_be16 eth_type)
 }
 
 static bool
+compose_dec_mpls_ttl_action(struct action_xlate_ctx *ctx,
+                            struct ofpact_cnt_ids *ids)
+{
+    uint8_t ttl = mpls_lse_to_ttl(ctx->flow.mpls_lse);
+
+    if (ctx->flow.dl_type != htons(ETH_TYPE_MPLS) &&
+        ctx->flow.dl_type != htons(ETH_TYPE_MPLS_MCAST)) {
+        return false;
+    }
+
+    if (ttl > 1) {
+        ttl--;
+        set_mpls_lse_ttl(&ctx->flow.mpls_lse, ttl);
+        return false;
+    } else {
+        size_t i;
+
+        for (i = 0; i < ids->n_controllers; i++) {
+            execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL,
+                                      ids->cnt_ids[i]);
+        }
+
+        /* Stop processing for current table. */
+        return true;
+    }
+}
+
+static bool
 compose_dec_ttl(struct action_xlate_ctx *ctx, struct ofpact_cnt_ids *ids)
 {
     if (ctx->flow.dl_type != htons(ETH_TYPE_IP) &&
@@ -5638,6 +5666,12 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t 
ofpacts_len,
             compose_mpls_pop_action(ctx, ofpact_get_POP_MPLS(a)->ethertype);
             break;
 
+        case OFPACT_DEC_MPLS_TTL:
+            if (compose_dec_mpls_ttl_action(ctx, ofpact_get_DEC_MPLS_TTL(a))) {
+                goto out;
+            }
+            break;
+
         case OFPACT_DEC_TTL:
             if (compose_dec_ttl(ctx, ofpact_get_DEC_TTL(a))) {
                 goto out;
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 545a838..aa84b45 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -250,7 +250,7 @@ cookie=0x6 table=4 in_port=83 
actions=load:4->NXM_NX_REG3[[]],mod_nw_src:83.83.8
 cookie=0x7 table=5 in_port=84 
actions=load:5->NXM_NX_REG4[[]],load:6->NXM_NX_TUN_ID[[]],mod_nw_dst:84.84.84.84,controller,resubmit(85,6)
 cookie=0x8 table=6 in_port=85 actions=mod_tp_src:85,controller,resubmit(86,7)
 cookie=0x9 table=7 in_port=86 actions=mod_tp_dst:86,controller,controller
-cookie=0xa dl_src=40:44:44:44:44:44 
actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],load:3->OXM_OF_MPLS_TC[[]],controller
+cookie=0xa dl_src=40:44:44:44:44:44 
actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],load:3->OXM_OF_MPLS_TC[[]],dec_mpls_ttl,controller
 cookie=0xb dl_src=50:55:55:55:55:55 
actions=load:1000->OXM_OF_MPLS_LABEL[[]],controller
 cookie=0xd dl_src=60:66:66:66:66:66 actions=pop_mpls:0x0800,controller
 cookie=0xc dl_src=70:77:77:77:77:77 
actions=push_mpls:0x8848,load:1000->OXM_OF_MPLS_LABEL[[]],load:7->OXM_OF_MPLS_TC[[]],controller
@@ -324,13 +324,13 @@ done
 OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
 AT_CHECK([cat ofctl_monitor.log], [0], [dnl
 NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) 
data_len=64 (unbuffered)
-priority:0,metadata:0,in_port:0000,tci(0) 
mac(40:44:44:44:44:44->50:54:00:00:00:07) 
type:8847,mpls(label:10,tc:3,ttl:64,bos:1)
+priority:0,metadata:0,in_port:0000,tci(0) 
mac(40:44:44:44:44:44->50:54:00:00:00:07) 
type:8847,mpls(label:10,tc:3,ttl:63,bos:1)
 dnl
 NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) 
data_len=64 (unbuffered)
-priority:0,metadata:0,in_port:0000,tci(0) 
mac(40:44:44:44:44:44->50:54:00:00:00:07) 
type:8847,mpls(label:10,tc:3,ttl:64,bos:1)
+priority:0,metadata:0,in_port:0000,tci(0) 
mac(40:44:44:44:44:44->50:54:00:00:00:07) 
type:8847,mpls(label:10,tc:3,ttl:63,bos:1)
 dnl
 NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) 
data_len=64 (unbuffered)
-priority:0,metadata:0,in_port:0000,tci(0) 
mac(40:44:44:44:44:44->50:54:00:00:00:07) 
type:8847,mpls(label:10,tc:3,ttl:64,bos:1)
+priority:0,metadata:0,in_port:0000,tci(0) 
mac(40:44:44:44:44:44->50:54:00:00:00:07) 
type:8847,mpls(label:10,tc:3,ttl:63,bos:1)
 ])
 
 dnl Modified MPLS actions.
@@ -475,7 +475,7 @@ AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], 
[0], [dnl
  cookie=0x7, table=5, n_packets=2, n_bytes=120, in_port=84 
actions=load:0x5->NXM_NX_REG4[[]],load:0x6->NXM_NX_TUN_ID[[]],mod_nw_dst:84.84.84.84,CONTROLLER:65535,resubmit(85,6)
  cookie=0x8, table=6, n_packets=2, n_bytes=120, in_port=85 
actions=mod_tp_src:85,CONTROLLER:65535,resubmit(86,7)
  cookie=0x9, table=7, n_packets=2, n_bytes=120, in_port=86 
actions=mod_tp_dst:86,CONTROLLER:65535,CONTROLLER:65535
- cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:44 
actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],CONTROLLER:65535
+ cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:44 
actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],dec_mpls_ttl,CONTROLLER:65535
  cookie=0xb, n_packets=3, n_bytes=180, dl_src=50:55:55:55:55:55 
actions=load:0x3e8->OXM_OF_MPLS_LABEL[[]],CONTROLLER:65535
  cookie=0xc, n_packets=3, n_bytes=180, dl_src=70:77:77:77:77:77 
actions=push_mpls:0x8848,load:0x3e8->OXM_OF_MPLS_LABEL[[]],load:0x7->OXM_OF_MPLS_TC[[]],CONTROLLER:65535
  cookie=0xd, n_packets=3, n_bytes=180, dl_src=60:66:66:66:66:66 
actions=pop_mpls:0x0800,CONTROLLER:65535
-- 
1.7.10.4

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to