[ovs-dev] [PATCH] ofproto: New action TTL decrement.

Pravin B Shelar pshelar at nicira.com
Thu Jan 12 03:25:52 UTC 2012


Following patch implements dec_ttl as vendor action with similar
semantics as OpenFlow 1.2. If TTL reaches zero while procession actions
in current table, the remaining actions in previous tables are
processed. An configuration parameter is added to make TTL decrement
to zero generate packet in.

Feature #8758
---
 include/openflow/nicira-ext.h |    3 +-
 include/openflow/openflow.h   |    9 ++++++-
 lib/ofp-parse.c               |    4 +++
 lib/ofp-print.c               |    4 +++
 lib/ofp-util.c                |    1 +
 lib/ofp-util.def              |    1 +
 ofproto/connmgr.c             |   47 ++++++++++++++++++++++++++++++++++++----
 ofproto/connmgr.h             |    3 ++
 ofproto/ofproto-dpif.c        |   38 ++++++++++++++++++++++++++++++--
 ofproto/ofproto.c             |    9 +++++++-
 tests/ofproto-dpif.at         |   25 +++++++++++++++++++++
 utilities/ovs-ofctl.8.in      |    5 ++++
 12 files changed, 137 insertions(+), 12 deletions(-)

diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
index bb0fb3a..417d16a 100644
--- a/include/openflow/nicira-ext.h
+++ b/include/openflow/nicira-ext.h
@@ -361,7 +361,8 @@ enum nx_action_subtype {
     NXAST_RESUBMIT_TABLE,       /* struct nx_action_resubmit */
     NXAST_OUTPUT_REG,           /* struct nx_action_output_reg */
     NXAST_LEARN,                /* struct nx_action_learn */
-    NXAST_EXIT                  /* struct nx_action_header */
+    NXAST_EXIT,                 /* struct nx_action_header */
+    NXAST_DEC_TTL,              /* struct nx_action_header */
 };
 
 /* Header for Nicira-defined actions. */
diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h
index cee62e8..d4d3056 100644
--- a/include/openflow/openflow.h
+++ b/include/openflow/openflow.h
@@ -135,7 +135,11 @@ enum ofp_config_flags {
     OFPC_FRAG_DROP     = 1,  /* Drop fragments. */
     OFPC_FRAG_REASM    = 2,  /* Reassemble (only if OFPC_IP_REASM set). */
     OFPC_FRAG_NX_MATCH = 3,  /* Make first fragments available for matching. */
-    OFPC_FRAG_MASK     = 3
+    OFPC_FRAG_MASK     = 3,
+
+    /* TTL processing - applicable for IP and MPLS packets. */
+    OFPC_INVALID_TTL_TO_CONTROLLER = 1 << 2, /* Send packets with invalid TTL
+                                                to the controller. */
 };
 
 /* Switch configuration. */
@@ -288,7 +292,8 @@ OFP_ASSERT(sizeof(struct ofp_port_mod) == 32);
 /* Why is this packet being sent to the controller? */
 enum ofp_packet_in_reason {
     OFPR_NO_MATCH,          /* No matching flow. */
-    OFPR_ACTION             /* Action explicitly output to controller. */
+    OFPR_ACTION,            /* Action explicitly output to controller. */
+    OFPR_INVALID_TTL        /* Packet has invalid TTL. */
 };
 
 /* Packet received on port (datapath -> controller). */
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 38c3dab..5321364 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -364,6 +364,10 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
     case OFPUTIL_NXAST_EXIT:
         ofputil_put_NXAST_EXIT(b);
         break;
+
+    case OFPUTIL_NXAST_DEC_TTL:
+        ofputil_put_NXAST_DEC_TTL(b);
+        break;
     }
 }
 
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 67edc54..055fb43 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -332,6 +332,10 @@ ofp_print_action(struct ds *s, const union ofp_action *a,
         learn_format((const struct nx_action_learn *) a, s);
         break;
 
+    case OFPUTIL_NXAST_DEC_TTL:
+        ds_put_cstr(s, "dec_ttl");
+        break;
+
     case OFPUTIL_NXAST_EXIT:
         ds_put_cstr(s, "exit");
         break;
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 1c9ceaf..edf4aff 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -2438,6 +2438,7 @@ validate_actions(const union ofp_action *actions, size_t n_actions,
         case OFPUTIL_NXAST_NOTE:
         case OFPUTIL_NXAST_SET_TUNNEL64:
         case OFPUTIL_NXAST_EXIT:
+        case OFPUTIL_NXAST_DEC_TTL:
             break;
         }
 
diff --git a/lib/ofp-util.def b/lib/ofp-util.def
index 2958eb6..d05ec9d 100644
--- a/lib/ofp-util.def
+++ b/lib/ofp-util.def
@@ -36,4 +36,5 @@ NXAST_ACTION(NXAST_RESUBMIT_TABLE, nx_action_resubmit,     0, NULL)
 NXAST_ACTION(NXAST_OUTPUT_REG,     nx_action_output_reg,   0, NULL)
 NXAST_ACTION(NXAST_LEARN,          nx_action_learn,        1, "learn")
 NXAST_ACTION(NXAST_EXIT,           nx_action_header,       0, "exit")
+NXAST_ACTION(NXAST_DEC_TTL,        nx_action_header,       0, "dec_ttl")
 #undef NXAST_ACTION
diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c
index 46d6d79..01c19e9 100644
--- a/ofproto/connmgr.c
+++ b/ofproto/connmgr.c
@@ -71,6 +71,8 @@ struct ofconn {
 
     /* type == OFCONN_PRIMARY only. */
     enum nx_role role;           /* Role. */
+    bool invalid_ttl_to_controller; /* Send packets with invalid TTL
+                                       to the controller. */
     struct hmap_node hmap_node;  /* In struct connmgr's "controllers" map. */
     enum ofproto_band band;      /* In-band or out-of-band? */
 };
@@ -754,6 +756,18 @@ ofconn_set_role(struct ofconn *ofconn, enum nx_role role)
     ofconn->role = role;
 }
 
+void
+ofconn_set_invalid_ttl_to_controller(struct ofconn *ofconn, bool val)
+{
+    ofconn->invalid_ttl_to_controller = val;
+}
+
+bool
+ofconn_get_invalid_ttl_to_controller(struct ofconn *ofconn)
+{
+    return ofconn->invalid_ttl_to_controller;
+}
+
 /* Returns the currently configured flow format for 'ofconn', one of NXFF_*.
  *
  * The default, if no other format has been set, is NXFF_OPENFLOW10. */
@@ -934,6 +948,7 @@ ofconn_create(struct connmgr *mgr, struct rconn *rconn, enum ofconn_type type)
     ofconn->pktbuf = NULL;
     ofconn->miss_send_len = 0;
     ofconn->reply_counter = rconn_packet_counter_create ();
+    ofconn->invalid_ttl_to_controller = false;
     return ofconn;
 }
 
@@ -1057,11 +1072,9 @@ ofconn_wait(struct ofconn *ofconn, bool handling_openflow)
 
 /* Returns true if 'ofconn' should receive asynchronous messages. */
 static bool
-ofconn_receives_async_msgs(const struct ofconn *ofconn)
+ofconn_receives_async_msgs__(const struct ofconn *ofconn)
 {
-    if (!rconn_is_connected(ofconn->rconn)) {
-        return false;
-    } else if (ofconn->type == OFCONN_PRIMARY) {
+    if (ofconn->type == OFCONN_PRIMARY) {
         /* Primary controllers always get asynchronous messages unless they
          * have configured themselves as "slaves".  */
         return ofconn->role != NX_ROLE_SLAVE;
@@ -1072,6 +1085,29 @@ ofconn_receives_async_msgs(const struct ofconn *ofconn)
     }
 }
 
+static bool
+ofconn_receives_async_msgs(const struct ofconn *ofconn)
+{
+    if (!rconn_is_connected(ofconn->rconn)) {
+        return false;
+    } else {
+        return ofconn_receives_async_msgs__(ofconn);
+    }
+}
+
+static bool
+ofconn_interested_in_packet(const struct ofconn *ofconn,
+                            const struct ofputil_packet_in *pin)
+{
+    if (!rconn_is_connected(ofconn->rconn)) {
+        return false;
+    } else if (pin->reason == OFPR_INVALID_TTL) {
+        return ofconn->invalid_ttl_to_controller;
+    } else {
+        return ofconn_receives_async_msgs__(ofconn);
+    }
+}
+
 /* Returns a human-readable name for an OpenFlow connection between 'mgr' and
  * 'target', suitable for use in log messages for identifying the connection.
  *
@@ -1181,7 +1217,8 @@ connmgr_send_packet_in(struct connmgr *mgr,
     struct ofconn *ofconn;
 
     LIST_FOR_EACH (ofconn, node, &mgr->all_conns) {
-        if (ofconn_receives_async_msgs(ofconn)) {
+        if (ofconn_interested_in_packet(ofconn, pin)) {
+
             schedule_packet_in(ofconn, *pin, flow);
         }
     }
diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h
index 0df840b..eff4e47 100644
--- a/ofproto/connmgr.h
+++ b/ofproto/connmgr.h
@@ -91,6 +91,9 @@ void ofconn_set_packet_in_format(struct ofconn *, enum nx_packet_in_format);
 bool ofconn_get_flow_mod_table_id(const struct ofconn *);
 void ofconn_set_flow_mod_table_id(struct ofconn *, bool enable);
 
+void ofconn_set_invalid_ttl_to_controller(struct ofconn *, bool);
+bool ofconn_get_invalid_ttl_to_controller(struct ofconn *);
+
 int ofconn_get_miss_send_len(const struct ofconn *);
 void ofconn_set_miss_send_len(struct ofconn *, int miss_send_len);
 
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 60f8175..b4117c7 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -4293,7 +4293,8 @@ flood_packets(struct action_xlate_ctx *ctx, bool all)
 }
 
 static void
-execute_controller_action(struct action_xlate_ctx *ctx, int len)
+execute_controller_action(struct action_xlate_ctx *ctx, int len,
+                          enum ofp_packet_in_reason reason)
 {
     struct ofputil_packet_in pin;
     struct ofpbuf *packet;
@@ -4338,7 +4339,7 @@ execute_controller_action(struct action_xlate_ctx *ctx, int len)
 
     pin.packet = packet->data;
     pin.packet_len = packet->size;
-    pin.reason = OFPR_ACTION;
+    pin.reason = reason;
     pin.table_id = ctx->table_id;
     pin.cookie = ctx->cookie;
 
@@ -4351,6 +4352,25 @@ execute_controller_action(struct action_xlate_ctx *ctx, int len)
     ofpbuf_delete(packet);
 }
 
+static bool
+compose_dec_ttl(struct action_xlate_ctx *ctx)
+{
+    if (ctx->flow.dl_type != htons(ETH_TYPE_IP) &&
+        ctx->flow.dl_type != htons(ETH_TYPE_IPV6)) {
+        return false;
+    }
+
+    if (ctx->flow.nw_ttl > 1) {
+        ctx->flow.nw_ttl--;
+        return false;
+    } else {
+        execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL);
+
+        /* Stop processing for current table. */
+        return true;
+    }
+}
+
 static void
 xlate_output_action__(struct action_xlate_ctx *ctx,
                       uint16_t port, uint16_t max_len)
@@ -4376,7 +4396,7 @@ xlate_output_action__(struct action_xlate_ctx *ctx,
         flood_packets(ctx, true);
         break;
     case OFPP_CONTROLLER:
-        execute_controller_action(ctx, max_len);
+        execute_controller_action(ctx, max_len, OFPR_ACTION);
         break;
     case OFPP_LOCAL:
         compose_output_action(ctx, OFPP_LOCAL);
@@ -4588,6 +4608,7 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
         const struct nx_action_bundle *nab;
         const struct nx_action_output_reg *naor;
         enum ofputil_action_code code;
+        bool exit_resubmit = false;
         ovs_be64 tun_id;
 
         if (ctx->exit) {
@@ -4733,10 +4754,18 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
             }
             break;
 
+        case OFPUTIL_NXAST_DEC_TTL:
+            exit_resubmit = compose_dec_ttl(ctx);
+            break;
+
         case OFPUTIL_NXAST_EXIT:
             ctx->exit = true;
             break;
         }
+
+        if (exit_resubmit) {
+            break;
+        }
     }
 
     /* We've let OFPP_NORMAL and the learning action look at the packet,
@@ -4802,6 +4831,9 @@ xlate_actions(struct action_xlate_ctx *ctx,
         case OFPC_FRAG_NX_MATCH:
             /* Nothing to do. */
             break;
+
+        case OFPC_INVALID_TTL_TO_CONTROLLER:
+            NOT_REACHED();
         }
     }
 
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 8f3c158..a9f1774 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -1746,11 +1746,16 @@ handle_get_config_request(struct ofconn *ofconn, const struct ofp_header *oh)
 {
     struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
     struct ofp_switch_config *osc;
+    enum ofp_config_flags flags;
     struct ofpbuf *buf;
 
     /* Send reply. */
     osc = make_openflow_xid(sizeof *osc, OFPT_GET_CONFIG_REPLY, oh->xid, &buf);
-    osc->flags = htons(ofproto->frag_handling);
+    flags = ofproto->frag_handling;
+    if (ofconn_get_invalid_ttl_to_controller(ofconn)) {
+        flags |= OFPC_INVALID_TTL_TO_CONTROLLER;
+    }
+    osc->flags = htons(flags);
     osc->miss_send_len = htons(ofconn_get_miss_send_len(ofconn));
     ofconn_send_reply(ofconn, buf);
 
@@ -1779,6 +1784,8 @@ handle_set_config(struct ofconn *ofconn, const struct ofp_switch_config *osc)
             }
         }
     }
+    ofconn_set_invalid_ttl_to_controller(ofconn,
+			 (flags & OFPC_INVALID_TTL_TO_CONTROLLER));
 
     ofconn_set_miss_send_len(ofconn, ntohs(osc->miss_send_len));
 
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 615eb57..537cc3d 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -62,6 +62,31 @@ AT_CHECK([tail -1 stdout], [0],
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([ofproto-dpif - dec_ttl])
+OVS_VSWITCHD_START
+AT_DATA([flows.txt], [dnl
+table=0 in_port=1 action=dec_ttl,output:2,resubmit(1,1),output:4
+table=1 in_port=1 action=dec_ttl,output:3
+])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=2,frag=no)' -generate], [0], [stdout])
+AT_CHECK([tail -2 stdout], [0],
+  [Datapath actions: set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=1,frag=no)),2,4
+This flow is not cachable.
+])
+AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=3,frag=no)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=2,frag=no)),2,set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=1,frag=no)),3,4
+])
+AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=128,frag=no)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: set(ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=127,frag=no)),2,set(ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=126,frag=no)),3,4
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+
 AT_SETUP([ofproto-dpif - output, OFPP_NONE ingress port])
 OVS_VSWITCHD_START(
        [add-port br0 p1 -- set Interface p1 type=dummy --\
diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index 4bfd543..a46815b 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -778,6 +778,11 @@ OpenFlow implementations do not support queuing at all.
 Restores the queue to the value it was before any \fBset_queue\fR
 actions were applied.
 .
+.IP \fBdec_ttl\fR
+Decrements \fITTL\fR of IP packet. By default, if the TTL hits zero when
+doing a decrement packet processing will stop. The remaining actions
+in previous tables should continue to be processed.
+.
 .IP \fBnote:\fR[\fIhh\fR]...
 Does nothing at all.  Any number of bytes represented as hex digits
 \fIhh\fR may be included.  Pairs of hex digits may be separated by
-- 
1.7.1




More information about the dev mailing list