[ovs-dev] [PATCH] Adding Nicira vendor extension action NXAST_DEC_TTL_CNT_IDS.

Mehak Mahajan mmahajan at nicira.com
Tue Aug 14 04:51:01 UTC 2012


Currently, if a controller having a non zero id registers to get a
OFPR_INVALID_TTL async message, it will not receive it.  This is because
compose_dec_ttl() only sent the invalid ttl packets to the default controller
id.  NXAST_DEC_TTL_CNT_IDS is a new action that accepts a list of controller
ids, each separated by `:', to which the OFPR_INVALID_TTL packets must be sent.
The earlier requirement of the controller having to explicitly register to
receive these asynchronous messages is retained.
The syntax of this action is:
    dec_ttl_cnt_ids=id1:id2
where id1, id2 are valid controller ids.

Signed-off-by: Mehak Mahajan <mmahajan at nicira.com>
---
 include/openflow/nicira-ext.h |   23 ++++++++++
 lib/ofp-actions.c             |   90 +++++++++++++++++++++++++++++++++++++++++
 lib/ofp-actions.h             |   69 ++++++++++++++++++-------------
 lib/ofp-parse.c               |   28 +++++++++++++
 lib/ofp-util.def              |   39 +++++++++---------
 ofproto/ofproto-dpif.c        |   21 ++++++++-
 utilities/ovs-ofctl.8.in      |   13 ++++--
 7 files changed, 229 insertions(+), 54 deletions(-)

diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
index 4fc2049..c209ba1 100644
--- a/include/openflow/nicira-ext.h
+++ b/include/openflow/nicira-ext.h
@@ -292,6 +292,7 @@ enum nx_action_subtype {
     NXAST_LEARN,                /* struct nx_action_learn */
     NXAST_EXIT,                 /* struct nx_action_header */
     NXAST_DEC_TTL,              /* struct nx_action_header */
+    NXAST_DEC_TTL_CNT_IDS,      /* struct nx_action_controller_ids */
     NXAST_FIN_TIMEOUT,          /* struct nx_action_fin_timeout */
     NXAST_CONTROLLER,           /* struct nx_action_controller */
 };
@@ -1060,6 +1061,28 @@ enum nx_bd_algorithm {
      * Uses the 'fields' and 'basis' parameters. */
     NX_BD_ALG_HRW /* Highest Random Weight. */
 };
+
+
+ /* Action structure for NXAST_DEC_TTL_CNT_IDS.
+  *
+  * The NXAST_DEC_TTL_CNT_IDS is used to send the packet to one or more
+  * controllers that have registered to receive the packet.
+  */
+struct nx_action_controller_ids {
+    ovs_be16 type;              /* OFPAT_VENDOR. */
+    ovs_be16 len;               /* Length including slaves. */
+    ovs_be32 vendor;            /* NX_VENDOR_ID. */
+    ovs_be16 subtype;           /* NXAST_DEC_TTL_CNT_IDS. */
+
+    ovs_be16 n_controllers;     /* Number of controllers. */
+    uint8_t zeros[4];           /* Must be zero. */
+    /* Followed by 1 or more controller ids.
+     *
+     * uint16_t *controller_ids;
+     */
+};
+OFP_ASSERT(sizeof(struct nx_action_controller_ids) == 16);
+
 
 /* Action structure for NXAST_OUTPUT_REG.
  *
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index 0874cc4..516d9ee 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -149,6 +149,44 @@ note_from_openflow(const struct nx_action_note *nan, struct ofpbuf *out)
 }
 
 static enum ofperr
+dec_ttl_cnt_ids_from_openflow(const struct nx_action_controller_ids *nac_ids,
+                              struct ofpbuf *out)
+{
+    struct ofpact_controller_ids *ids;
+    size_t ids_size;
+    enum ofperr error = 0;
+    int i;
+
+    ids = ofpact_put_DEC_TTL_CNT_IDS(out);
+    ids->n_controllers = ntohs(nac_ids->n_controllers);
+    ids_size = ntohl(nac_ids->len) - sizeof *nac_ids;
+
+    if (!is_all_zeros(nac_ids->zeros, sizeof nac_ids->zeros)) {
+        VLOG_WARN_RL(&rl, "reserved field is nonzero");
+        error = OFPERR_OFPBAC_BAD_ARGUMENT;
+        VLOG_ERR("Came in here.\n");
+    }
+
+    if (ids_size < ids->n_controllers * sizeof(ovs_be16)) {
+        VLOG_WARN_RL(&rl, "Nicira action dec_ttl_cnt_ids only has %zu bytes "
+                     "allocated for controller ids.  %zu bytes are required for "
+                     "%"PRIu16" controllers.", ids_size,
+                     ids->n_controllers * sizeof(ovs_be16), ids->n_controllers);
+        error = OFPERR_OFPBAC_BAD_LEN;
+    }
+
+    for (i = 0; i < ids->n_controllers; i++) {
+        uint16_t id = ntohs(((ovs_be16 *)(nac_ids + 1))[i]);
+        ofpbuf_put(out, &id, sizeof id);
+    }
+
+    ids = out->l2;
+    ofpact_update_len(out, &ids->ofpact);
+
+    return error;
+}
+
+static enum ofperr
 decode_nxast_action(const union ofp_action *a, enum ofputil_action_code *code)
 {
     const struct nx_action_header *nah = (const struct nx_action_header *) a;
@@ -313,6 +351,11 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
         ofpact_put_DEC_TTL(out);
         break;
 
+    case OFPUTIL_NXAST_DEC_TTL_CNT_IDS:
+        error = dec_ttl_cnt_ids_from_openflow(
+                    (const struct nx_action_controller_ids *) a, out);
+        break;
+
     case OFPUTIL_NXAST_FIN_TIMEOUT:
         fin_timeout_from_openflow(
             (const struct nx_action_fin_timeout *) a, out);
@@ -951,6 +994,7 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports)
         return nxm_reg_load_check(ofpact_get_REG_LOAD(a), flow);
 
     case OFPACT_DEC_TTL:
+    case OFPACT_DEC_TTL_CNT_IDS:
     case OFPACT_SET_TUNNEL:
     case OFPACT_SET_QUEUE:
     case OFPACT_POP_QUEUE:
@@ -1074,6 +1118,25 @@ ofpact_controller_to_nxast(const struct ofpact_controller *oc,
 }
 
 static void
+ofpact_dec_ttl_cnt_ids_to_nxast(const struct ofpact_controller_ids *oc_ids,
+                                struct ofpbuf *out)
+{
+    struct nx_action_controller_ids *nac_ids;
+    int ids_len = ROUND_UP(oc_ids->n_controllers, OFP_ACTION_ALIGN);
+    ovs_be16 *ids;
+    size_t i;
+
+    nac_ids = ofputil_put_NXAST_DEC_TTL_CNT_IDS(out);
+    nac_ids->len = htons(ntohs(nac_ids->len) + ids_len);
+    nac_ids->n_controllers = htons(oc_ids->n_controllers);
+
+    ids = ofpbuf_put_zeros(out, ids_len);
+    for (i = 0; i < oc_ids->n_controllers; i++) {
+        ids[i] = htons(oc_ids->controller_ids[i]);
+    }
+}
+
+static void
 ofpact_fin_timeout_to_nxast(const struct ofpact_fin_timeout *fin_timeout,
                             struct ofpbuf *out)
 {
@@ -1110,6 +1173,10 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
         ofputil_put_NXAST_DEC_TTL(out);
         break;
 
+    case OFPACT_DEC_TTL_CNT_IDS:
+        ofpact_dec_ttl_cnt_ids_to_nxast(ofpact_get_DEC_TTL_CNT_IDS(a), out);
+        break;
+
     case OFPACT_SET_TUNNEL:
         ofpact_set_tunnel_to_nxast(ofpact_get_SET_TUNNEL(a), out);
         break;
@@ -1258,6 +1325,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_TTL_CNT_IDS:
     case OFPACT_SET_TUNNEL:
     case OFPACT_SET_QUEUE:
     case OFPACT_POP_QUEUE:
@@ -1366,6 +1434,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_TTL_CNT_IDS:
     case OFPACT_SET_TUNNEL:
     case OFPACT_SET_QUEUE:
     case OFPACT_POP_QUEUE:
@@ -1444,6 +1513,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_TTL_CNT_IDS:
     case OFPACT_SET_TUNNEL:
     case OFPACT_SET_QUEUE:
     case OFPACT_POP_QUEUE:
@@ -1500,6 +1570,22 @@ print_note(const struct ofpact_note *note, struct ds *string)
 }
 
 static void
+print_dec_ttl_cnt_ids(const struct ofpact_controller_ids *ids,
+                      struct ds *s)
+{
+    size_t i;
+
+    ds_put_cstr(s, "dec_ttl_cnt_ids (controller_ids:");
+    for (i = 0; i < ids->n_controllers; i++) {
+        if (i) {
+            ds_put_cstr(s, ",");
+        }
+        ds_put_format(s, "%"PRIu16, ids->controller_ids[i]);
+    }
+    ds_put_cstr(s,")");
+}
+
+static void
 print_fin_timeout(const struct ofpact_fin_timeout *fin_timeout,
                   struct ds *s)
 {
@@ -1638,6 +1724,10 @@ ofpact_format(const struct ofpact *a, struct ds *s)
         ds_put_cstr(s, "dec_ttl");
         break;
 
+    case OFPACT_DEC_TTL_CNT_IDS:
+        print_dec_ttl_cnt_ids(ofpact_get_DEC_TTL_CNT_IDS(a), s);
+        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 7c9cb05..0651971 100644
--- a/lib/ofp-actions.h
+++ b/lib/ofp-actions.h
@@ -50,44 +50,45 @@
  */
 #define OFPACTS                                                     \
     /* Output. */                                                   \
-    DEFINE_OFPACT(OUTPUT,          ofpact_output,        ofpact)    \
-    DEFINE_OFPACT(CONTROLLER,      ofpact_controller,    ofpact)    \
-    DEFINE_OFPACT(ENQUEUE,         ofpact_enqueue,       ofpact)    \
-    DEFINE_OFPACT(OUTPUT_REG,      ofpact_output_reg,    ofpact)    \
-    DEFINE_OFPACT(BUNDLE,          ofpact_bundle,        slaves)    \
+    DEFINE_OFPACT(OUTPUT,          ofpact_output,         ofpact)    \
+    DEFINE_OFPACT(CONTROLLER,      ofpact_controller,     ofpact)    \
+    DEFINE_OFPACT(ENQUEUE,         ofpact_enqueue,        ofpact)    \
+    DEFINE_OFPACT(OUTPUT_REG,      ofpact_output_reg,     ofpact)    \
+    DEFINE_OFPACT(BUNDLE,          ofpact_bundle,         slaves)    \
                                                                     \
     /* Header changes. */                                           \
-    DEFINE_OFPACT(SET_VLAN_VID,    ofpact_vlan_vid,      ofpact)    \
-    DEFINE_OFPACT(SET_VLAN_PCP,    ofpact_vlan_pcp,      ofpact)    \
-    DEFINE_OFPACT(STRIP_VLAN,      ofpact_null,          ofpact)    \
-    DEFINE_OFPACT(SET_ETH_SRC,     ofpact_mac,           ofpact)    \
-    DEFINE_OFPACT(SET_ETH_DST,     ofpact_mac,           ofpact)    \
-    DEFINE_OFPACT(SET_IPV4_SRC,    ofpact_ipv4,          ofpact)    \
-    DEFINE_OFPACT(SET_IPV4_DST,    ofpact_ipv4,          ofpact)    \
-    DEFINE_OFPACT(SET_IPV4_DSCP,   ofpact_dscp,          ofpact)    \
-    DEFINE_OFPACT(SET_L4_SRC_PORT, ofpact_l4_port,       ofpact)    \
-    DEFINE_OFPACT(SET_L4_DST_PORT, ofpact_l4_port,       ofpact)    \
-    DEFINE_OFPACT(REG_MOVE,        ofpact_reg_move,      ofpact)    \
-    DEFINE_OFPACT(REG_LOAD,        ofpact_reg_load,      ofpact)    \
-    DEFINE_OFPACT(DEC_TTL,         ofpact_null,          ofpact)    \
+    DEFINE_OFPACT(SET_VLAN_VID,    ofpact_vlan_vid,       ofpact)    \
+    DEFINE_OFPACT(SET_VLAN_PCP,    ofpact_vlan_pcp,       ofpact)    \
+    DEFINE_OFPACT(STRIP_VLAN,      ofpact_null,           ofpact)    \
+    DEFINE_OFPACT(SET_ETH_SRC,     ofpact_mac,            ofpact)    \
+    DEFINE_OFPACT(SET_ETH_DST,     ofpact_mac,            ofpact)    \
+    DEFINE_OFPACT(SET_IPV4_SRC,    ofpact_ipv4,           ofpact)    \
+    DEFINE_OFPACT(SET_IPV4_DST,    ofpact_ipv4,           ofpact)    \
+    DEFINE_OFPACT(SET_IPV4_DSCP,   ofpact_dscp,           ofpact)    \
+    DEFINE_OFPACT(SET_L4_SRC_PORT, ofpact_l4_port,        ofpact)    \
+    DEFINE_OFPACT(SET_L4_DST_PORT, ofpact_l4_port,        ofpact)    \
+    DEFINE_OFPACT(REG_MOVE,        ofpact_reg_move,       ofpact)    \
+    DEFINE_OFPACT(REG_LOAD,        ofpact_reg_load,       ofpact)    \
+    DEFINE_OFPACT(DEC_TTL,         ofpact_null,           ofpact)    \
                                                                     \
     /* Metadata. */                                                 \
-    DEFINE_OFPACT(SET_TUNNEL,      ofpact_tunnel,        ofpact)    \
-    DEFINE_OFPACT(SET_QUEUE,       ofpact_queue,         ofpact)    \
-    DEFINE_OFPACT(POP_QUEUE,       ofpact_null,          ofpact)    \
-    DEFINE_OFPACT(FIN_TIMEOUT,     ofpact_fin_timeout,   ofpact)    \
+    DEFINE_OFPACT(SET_TUNNEL,      ofpact_tunnel,         ofpact)    \
+    DEFINE_OFPACT(SET_QUEUE,       ofpact_queue,          ofpact)    \
+    DEFINE_OFPACT(POP_QUEUE,       ofpact_null,           ofpact)    \
+    DEFINE_OFPACT(FIN_TIMEOUT,     ofpact_fin_timeout,    ofpact)    \
                                                                     \
     /* Flow table interaction. */                                   \
-    DEFINE_OFPACT(RESUBMIT,        ofpact_resubmit,      ofpact)    \
-    DEFINE_OFPACT(LEARN,           ofpact_learn,         specs)     \
+    DEFINE_OFPACT(RESUBMIT,        ofpact_resubmit,       ofpact)    \
+    DEFINE_OFPACT(LEARN,           ofpact_learn,          specs)     \
                                                                     \
     /* Arithmetic. */                                               \
-    DEFINE_OFPACT(MULTIPATH,       ofpact_multipath,     ofpact)    \
-    DEFINE_OFPACT(AUTOPATH,        ofpact_autopath,      ofpact)    \
+    DEFINE_OFPACT(MULTIPATH,       ofpact_multipath,      ofpact)    \
+    DEFINE_OFPACT(AUTOPATH,        ofpact_autopath,       ofpact)    \
                                                                     \
     /* Other. */                                                    \
-    DEFINE_OFPACT(NOTE,            ofpact_note,          data)      \
-    DEFINE_OFPACT(EXIT,            ofpact_null,          ofpact)
+    DEFINE_OFPACT(DEC_TTL_CNT_IDS, ofpact_controller_ids, controller_ids)   \
+    DEFINE_OFPACT(NOTE,            ofpact_note,           data)      \
+    DEFINE_OFPACT(EXIT,            ofpact_null,           ofpact)
 
 /* enum ofpact_type, with a member OFPACT_<ENUM> for each action. */
 enum OVS_PACKED_ENUM ofpact_type {
@@ -380,6 +381,18 @@ struct ofpact_note {
     uint8_t data[];
 };
 
+/* OFPACT_DEC_TTL_CNT_IDS
+ *
+ * Used for NXAST_DEC_TTL_CNT_IDS. */
+struct ofpact_controller_ids {
+    struct ofpact ofpact;
+
+    /* Controller ids. */
+    unsigned int n_controllers;
+    uint16_t controller_ids[];
+
+};
+
 /* Converting OpenFlow to ofpacts. */
 enum ofperr ofpacts_pull_openflow10(struct ofpbuf *openflow,
                                     unsigned int actions_len,
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 32d3836..9415fa6 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -279,6 +279,30 @@ parse_controller(struct ofpbuf *b, char *arg)
 }
 
 static void
+parse_dec_ttl_cnt_ids(struct ofpbuf *b, char *arg)
+{
+    struct ofpact_controller_ids *ids;
+
+    if (*arg == '\0') {
+        ovs_fatal(0, "dec_ttl_cnt_ids: expected atleast one controler id.");
+    }
+
+    ids = ofpact_put_DEC_TTL_CNT_IDS(b);
+    while(*arg != '\0') {
+        char *cntr;
+        uint16_t id;
+
+        cntr = strtok_r(NULL, ": ", &arg);
+        id = atoi(cntr);
+        ofpbuf_put(b, &id, sizeof id);
+
+        ids = b->l2;
+        ids->n_controllers++;
+    }
+    ofpact_update_len(b, &ids->ofpact);
+}
+
+static void
 parse_named_action(enum ofputil_action_code code, const struct flow *flow,
                    char *arg, struct ofpbuf *ofpacts)
 {
@@ -427,6 +451,10 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
         ofpact_put_DEC_TTL(ofpacts);
         break;
 
+    case OFPUTIL_NXAST_DEC_TTL_CNT_IDS:
+        parse_dec_ttl_cnt_ids(ofpacts, arg);
+        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 974cd8f..6ae8a63 100644
--- a/lib/ofp-util.def
+++ b/lib/ofp-util.def
@@ -39,25 +39,26 @@ OFPAT11_ACTION(OFPAT11_SET_TP_DST,   ofp_action_tp_port,  "mod_tp_dst")
 #ifndef NXAST_ACTION
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)
 #endif
-NXAST_ACTION(NXAST_RESUBMIT,       nx_action_resubmit,     0, "resubmit")
-NXAST_ACTION(NXAST_SET_TUNNEL,     nx_action_set_tunnel,   0, "set_tunnel")
-NXAST_ACTION(NXAST_SET_QUEUE,      nx_action_set_queue,    0, "set_queue")
-NXAST_ACTION(NXAST_POP_QUEUE,      nx_action_pop_queue,    0, "pop_queue")
-NXAST_ACTION(NXAST_REG_MOVE,       nx_action_reg_move,     0, "move")
-NXAST_ACTION(NXAST_REG_LOAD,       nx_action_reg_load,     0, "load")
-NXAST_ACTION(NXAST_NOTE,           nx_action_note,         1, "note")
-NXAST_ACTION(NXAST_SET_TUNNEL64,   nx_action_set_tunnel64, 0, "set_tunnel64")
-NXAST_ACTION(NXAST_MULTIPATH,      nx_action_multipath,    0, "multipath")
-NXAST_ACTION(NXAST_AUTOPATH,       nx_action_autopath,     0, "autopath")
-NXAST_ACTION(NXAST_BUNDLE,         nx_action_bundle,       1, "bundle")
-NXAST_ACTION(NXAST_BUNDLE_LOAD,    nx_action_bundle,       1, "bundle_load")
-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")
-NXAST_ACTION(NXAST_FIN_TIMEOUT,    nx_action_fin_timeout,  0, "fin_timeout")
-NXAST_ACTION(NXAST_CONTROLLER,     nx_action_controller,   0, "controller")
+NXAST_ACTION(NXAST_RESUBMIT,        nx_action_resubmit,       0, "resubmit")
+NXAST_ACTION(NXAST_SET_TUNNEL,      nx_action_set_tunnel,     0, "set_tunnel")
+NXAST_ACTION(NXAST_SET_QUEUE,       nx_action_set_queue,      0, "set_queue")
+NXAST_ACTION(NXAST_POP_QUEUE,       nx_action_pop_queue,      0, "pop_queue")
+NXAST_ACTION(NXAST_REG_MOVE,        nx_action_reg_move,       0, "move")
+NXAST_ACTION(NXAST_REG_LOAD,        nx_action_reg_load,       0, "load")
+NXAST_ACTION(NXAST_NOTE,            nx_action_note,           1, "note")
+NXAST_ACTION(NXAST_SET_TUNNEL64,    nx_action_set_tunnel64,   0, "set_tunnel64")
+NXAST_ACTION(NXAST_MULTIPATH,       nx_action_multipath,      0, "multipath")
+NXAST_ACTION(NXAST_AUTOPATH,        nx_action_autopath,       0, "autopath")
+NXAST_ACTION(NXAST_BUNDLE,          nx_action_bundle,         1, "bundle")
+NXAST_ACTION(NXAST_BUNDLE_LOAD,     nx_action_bundle,         1, "bundle_load")
+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")
+NXAST_ACTION(NXAST_DEC_TTL_CNT_IDS, nx_action_controller_ids, 1, "dec_ttl_cnt_ids")
+NXAST_ACTION(NXAST_FIN_TIMEOUT,     nx_action_fin_timeout,    0, "fin_timeout")
+NXAST_ACTION(NXAST_CONTROLLER,      nx_action_controller,     0, "controller")
 
 #undef OFPAT10_ACTION
 #undef OFPAT11_ACTION
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 95195a3..309cb27 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -5134,7 +5134,7 @@ execute_controller_action(struct action_xlate_ctx *ctx, int len,
 }
 
 static bool
-compose_dec_ttl(struct action_xlate_ctx *ctx)
+compose_dec_ttl(struct action_xlate_ctx *ctx, struct ofpact_controller_ids *ids)
 {
     if (ctx->flow.dl_type != htons(ETH_TYPE_IP) &&
         ctx->flow.dl_type != htons(ETH_TYPE_IPV6)) {
@@ -5145,7 +5145,16 @@ compose_dec_ttl(struct action_xlate_ctx *ctx)
         ctx->flow.nw_ttl--;
         return false;
     } else {
-        execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, 0);
+        if (!ids) {
+            execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, 0);
+        } else {
+            size_t i;
+
+            for (i = 0; i < ids->n_controllers; i++) {
+                execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL,
+                                          ids->controller_ids[i]);
+            }
+        }
 
         /* Stop processing for current table. */
         return true;
@@ -5505,7 +5514,13 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             break;
 
         case OFPACT_DEC_TTL:
-            if (compose_dec_ttl(ctx)) {
+            if (compose_dec_ttl(ctx, NULL)) {
+                goto out;
+            }
+            break;
+
+        case OFPACT_DEC_TTL_CNT_IDS:
+          if (compose_dec_ttl(ctx, ofpact_get_DEC_TTL_CNT_IDS(a))) {
                 goto out;
             }
             break;
diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index 65fc6e8..76f2f74 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -945,12 +945,17 @@ actions were applied.
 Decrement TTL of IPv4 packet or hop limit of IPv6 packet.  If the
 TTL or hop limit is initially zero, no decrement occurs.  Instead,
 a ``packet-in'' message with reason code \fBOFPR_INVALID_TTL\fR is
-sent to each connected controller that has enabled receiving them,
-if any.  Processing the current set of actions then stops.
-However, if the current set of actions was reached through
-``resubmit'' then remaining actions in outer levels resume
+sent to each connected controller whose controller id is 0 and that
+has enabled receiving them, if any.  Processing the current set of
+actions then stops.  However, if the current set of actions was reached
+through ``resubmit'' then remaining actions in outer levels resume
 processing.
 .
+.IP \fBdec_ttl_cnt_ids\fB=\fIid1\fB:\fIid2\fR
+Same as dec_ttl, except it accepts a list of controller ids to whom
+the ``packet-in'' message with reason code \fBOFPR_INVALID_TTL\fR
+must be sent.
+.
 .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.2.5




More information about the dev mailing list