Add Nicira vendor extension action NXAST_DEC_TTL_CNT_IDS.
authorMehak Mahajan <mmahajan@nicira.com>
Thu, 16 Aug 2012 21:25:07 +0000 (14:25 -0700)
committerMehak Mahajan <mmahajan@nicira.com>
Thu, 16 Aug 2012 21:52:04 +0000 (14:52 -0700)
Currently, if a controller having a nonzero 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(id1,id2)
where id1, id2 are valid controller ids.

Signed-off-by: Mehak Mahajan <mmahajan@nicira.com>
include/openflow/nicira-ext.h
lib/ofp-actions.c
lib/ofp-actions.h
lib/ofp-parse.c
lib/ofp-util.def
ofproto/ofproto-dpif.c
tests/ofp-actions.at
utilities/ovs-ofctl.8.in

index 4fc2049d15d19a9e12d5e6e6f80768b1bb864245..d1d3654e0224d70fc560c56bd69370df902bc2ff 100644 (file)
@@ -294,6 +294,7 @@ enum nx_action_subtype {
     NXAST_DEC_TTL,              /* struct nx_action_header */
     NXAST_FIN_TIMEOUT,          /* struct nx_action_fin_timeout */
     NXAST_CONTROLLER,           /* struct nx_action_controller */
+    NXAST_DEC_TTL_CNT_IDS,      /* struct nx_action_cnt_ids */
 };
 
 /* Header for Nicira-defined actions. */
@@ -1060,6 +1061,35 @@ enum nx_bd_algorithm {
      * Uses the 'fields' and 'basis' parameters. */
     NX_BD_ALG_HRW /* Highest Random Weight. */
 };
+
+\f
+/* Action structure for NXAST_DEC_TTL_CNT_IDS.
+ *
+ * If the packet is not IPv4 or IPv6, does nothing.  For IPv4 or IPv6, if the
+ * TTL or hop limit is at least 2, decrements it by 1.  Otherwise, if TTL or
+ * hop limit is 0 or 1, sends a packet-in to the controllers with each of the
+ * 'n_controllers' controller IDs specified in 'cnt_ids'.
+ *
+ * (This differs from NXAST_DEC_TTL in that for NXAST_DEC_TTL the packet-in is
+ * sent only to controllers with id 0.)
+ */
+struct nx_action_cnt_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 cnt_ids[];        // Controller ids.
+     * uint8_t pad[];           // Must be 0 to 8-byte align cnt_ids[].
+     */
+};
+OFP_ASSERT(sizeof(struct nx_action_cnt_ids) == 16);
+
 \f
 /* Action structure for NXAST_OUTPUT_REG.
  *
index 6503f61ca56561c7ce61583635417d707a31d7ab..db603b6e5e06fe5ef59d1d43a68cddaedb044e28 100644 (file)
@@ -148,6 +148,58 @@ note_from_openflow(const struct nx_action_note *nan, struct ofpbuf *out)
     memcpy(note->data, nan->note, length);
 }
 
+static enum ofperr
+dec_ttl_from_openflow(struct ofpbuf *out)
+{
+    uint16_t id = 0;
+    struct ofpact_cnt_ids *ids;
+    enum ofperr error = 0;
+
+    ids = ofpact_put_DEC_TTL(out);
+    ids->ofpact.compat = OFPUTIL_NXAST_DEC_TTL;
+    ids->n_controllers = 1;
+    ofpbuf_put(out, &id, sizeof id);
+    ids = out->l2;
+    ofpact_update_len(out, &ids->ofpact);
+    return error;
+}
+
+static enum ofperr
+dec_ttl_cnt_ids_from_openflow(const struct nx_action_cnt_ids *nac_ids,
+                      struct ofpbuf *out)
+{
+    struct ofpact_cnt_ids *ids;
+    size_t ids_size;
+    int i;
+
+    ids = ofpact_put_DEC_TTL(out);
+    ids->ofpact.compat = OFPUTIL_NXAST_DEC_TTL_CNT_IDS;
+    ids->n_controllers = ntohs(nac_ids->n_controllers);
+    ids_size = ntohs(nac_ids->len) - sizeof *nac_ids;
+
+    if (!is_all_zeros(nac_ids->zeros, sizeof nac_ids->zeros)) {
+        return OFPERR_NXBRC_MUST_BE_ZERO;
+    }
+
+    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);
+        return 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 0;
+}
+
 static enum ofperr
 decode_nxast_action(const union ofp_action *a, enum ofputil_action_code *code)
 {
@@ -310,7 +362,12 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
         break;
 
     case OFPUTIL_NXAST_DEC_TTL:
-        ofpact_put_DEC_TTL(out);
+        error = dec_ttl_from_openflow(out);
+        break;
+
+    case OFPUTIL_NXAST_DEC_TTL_CNT_IDS:
+        error = dec_ttl_cnt_ids_from_openflow(
+                    (const struct nx_action_cnt_ids *) a, out);
         break;
 
     case OFPUTIL_NXAST_FIN_TIMEOUT:
@@ -1082,6 +1139,29 @@ ofpact_controller_to_nxast(const struct ofpact_controller *oc,
     nac->reason = oc->reason;
 }
 
+static void
+ofpact_dec_ttl_to_nxast(const struct ofpact_cnt_ids *oc_ids,
+                        struct ofpbuf *out)
+{
+    if (oc_ids->ofpact.compat == OFPUTIL_NXAST_DEC_TTL) {
+        ofputil_put_NXAST_DEC_TTL(out);
+    } else {
+        struct nx_action_cnt_ids *nac_ids =
+            ofputil_put_NXAST_DEC_TTL_CNT_IDS(out);
+        int ids_len = ROUND_UP(2 * oc_ids->n_controllers, OFP_ACTION_ALIGN);
+        ovs_be16 *ids;
+        size_t i;
+
+        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->cnt_ids[i]);
+        }
+    }
+}
+
 static void
 ofpact_fin_timeout_to_nxast(const struct ofpact_fin_timeout *fin_timeout,
                             struct ofpbuf *out)
@@ -1116,7 +1196,7 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
         break;
 
     case OFPACT_DEC_TTL:
-        ofputil_put_NXAST_DEC_TTL(out);
+        ofpact_dec_ttl_to_nxast(ofpact_get_DEC_TTL(a), out);
         break;
 
     case OFPACT_SET_TUNNEL:
@@ -1511,6 +1591,25 @@ print_note(const struct ofpact_note *note, struct ds *string)
     }
 }
 
+static void
+print_dec_ttl(const struct ofpact_cnt_ids *ids,
+              struct ds *s)
+{
+    size_t i;
+
+    ds_put_cstr(s, "dec_ttl");
+    if (ids->ofpact.compat == OFPUTIL_NXAST_DEC_TTL_CNT_IDS) {
+        ds_put_cstr(s, "(");
+        for (i = 0; i < ids->n_controllers; i++) {
+            if (i) {
+                ds_put_cstr(s, ",");
+            }
+            ds_put_format(s, "%"PRIu16, ids->cnt_ids[i]);
+        }
+        ds_put_cstr(s, ")");
+    }
+}
+
 static void
 print_fin_timeout(const struct ofpact_fin_timeout *fin_timeout,
                   struct ds *s)
@@ -1647,7 +1746,7 @@ ofpact_format(const struct ofpact *a, struct ds *s)
         break;
 
     case OFPACT_DEC_TTL:
-        ds_put_cstr(s, "dec_ttl");
+        print_dec_ttl(ofpact_get_DEC_TTL(a), s);
         break;
 
     case OFPACT_SET_TUNNEL:
index 2e021819d4464d71bfe9c7085d9960d21d50e0d3..2003668262e82ae312ee143accb1785e35d7afb7 100644 (file)
@@ -69,7 +69,7 @@
     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(DEC_TTL,         ofpact_cnt_ids,       cnt_ids)   \
                                                                     \
     /* Metadata. */                                                 \
     DEFINE_OFPACT(SET_TUNNEL,      ofpact_tunnel,        ofpact)    \
@@ -145,7 +145,7 @@ ofpact_end(const struct ofpact *ofpacts, size_t ofpacts_len)
 \f
 /* Action structure for each OFPACT_*. */
 
-/* OFPACT_STRIP_VLAN, OFPACT_DEC_TTL, OFPACT_POP_QUEUE, OFPACT_EXIT.
+/* OFPACT_STRIP_VLAN, OFPACT_POP_QUEUE, OFPACT_EXIT.
  *
  * Used for OFPAT10_STRIP_VLAN, NXAST_DEC_TTL, NXAST_POP_QUEUE, NXAST_EXIT.
  *
@@ -380,6 +380,18 @@ struct ofpact_note {
     uint8_t data[];
 };
 
+/* OFPACT_DEC_TTL.
+ *
+ * Used for NXAST_DEC_TTL and NXAST_DEC_TTL_CNT_IDS. */
+struct ofpact_cnt_ids {
+    struct ofpact ofpact;
+
+    /* Controller ids. */
+    unsigned int n_controllers;
+    uint16_t cnt_ids[];
+
+};
+
 /* Converting OpenFlow to ofpacts. */
 enum ofperr ofpacts_pull_openflow10(struct ofpbuf *openflow,
                                     unsigned int actions_len,
index 32d38368908bed37a6f271e639ba7d317e4788f1..e5f5ea03adea611f1ee570ae5bfe60f1b088e95b 100644 (file)
@@ -278,6 +278,41 @@ parse_controller(struct ofpbuf *b, char *arg)
     }
 }
 
+static void
+parse_dec_ttl(struct ofpbuf *b, char *arg)
+{
+    struct ofpact_cnt_ids *ids;
+
+    ids = ofpact_put_DEC_TTL(b);
+
+    if (*arg == '\0') {
+        uint16_t id = 0;
+
+        ids->ofpact.compat = OFPUTIL_NXAST_DEC_TTL;
+        ofpbuf_put(b, &id, sizeof id);
+        ids = b->l2;
+        ids->n_controllers++;
+    } else {
+        char *cntr;
+
+        ids->ofpact.compat = OFPUTIL_NXAST_DEC_TTL_CNT_IDS;
+        for (cntr = strtok_r(arg, ", ", &arg); cntr != NULL;
+             cntr = strtok_r(NULL, ", ", &arg)) {
+            uint16_t id = atoi(cntr);
+
+            ofpbuf_put(b, &id, sizeof id);
+            ids = b->l2;
+            ids->n_controllers++;
+        }
+        if (!ids->n_controllers) {
+            ovs_fatal(0, "dec_ttl_cnt_ids: expected at least one controller "
+                      "id.");
+        }
+
+    }
+    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)
@@ -413,6 +448,7 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
 
     case OFPUTIL_NXAST_RESUBMIT_TABLE:
     case OFPUTIL_NXAST_OUTPUT_REG:
+    case OFPUTIL_NXAST_DEC_TTL_CNT_IDS:
         NOT_REACHED();
 
     case OFPUTIL_NXAST_LEARN:
@@ -424,7 +460,7 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
         break;
 
     case OFPUTIL_NXAST_DEC_TTL:
-        ofpact_put_DEC_TTL(ofpacts);
+        parse_dec_ttl(ofpacts, arg);
         break;
 
     case OFPUTIL_NXAST_FIN_TIMEOUT:
index 974cd8f874f5b7caed575b6e88b281ed8b24c271..619bb88cdf519de86902d1d9493d62956a80f861 100644 (file)
@@ -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_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)
 
 #undef OFPAT10_ACTION
 #undef OFPAT11_ACTION
index 3d68855477422b76cd42e1ca41b3717a417a87dc..d66c500e6a62f4d40e9626465f9ee35d37895a0f 100644 (file)
@@ -5159,7 +5159,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_cnt_ids *ids)
 {
     if (ctx->flow.dl_type != htons(ETH_TYPE_IP) &&
         ctx->flow.dl_type != htons(ETH_TYPE_IPV6)) {
@@ -5170,7 +5170,12 @@ 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);
+        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;
@@ -5530,7 +5535,7 @@ 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, ofpact_get_DEC_TTL(a))) {
                 goto out;
             }
             break;
index ba8d309d06475659dd8fedd02eee62cd008ca84b..36c67f106ead4c21d6e3a3e78fe7534ab604df54 100644 (file)
@@ -108,6 +108,9 @@ ffff 0010 00002320 0013 000a 0014 0000
 # actions=controller(reason=invalid_ttl,max_len=1234,id=5678)
 ffff 0010 00002320 0014 04d2 162e 02 00
 
+# actions=dec_ttl(32768,12345,90,765,1024)
+ffff 0020 00002320 0015 000500000000 80003039005A02fd 0400000000000000
+
 ])
 sed '/^[[#&]]/d' < test-data > input.txt
 sed -n 's/^# //p; /^$/p' < test-data > expout
@@ -222,6 +225,9 @@ ffff 0010 00002320 0013 000a 0014 0000
 # actions=controller(reason=invalid_ttl,max_len=1234,id=5678)
 ffff 0010 00002320 0014 04d2 162e 02 00
 
+# actions=dec_ttl(32768,12345,90,765,1024)
+ffff 0020 00002320 0015 000500000000 80003039005A02fd 0400000000000000
+
 ])
 sed '/^[[#&]]/d' < test-data > input.txt
 sed -n 's/^# //p; /^$/p' < test-data > expout
index 65fc6e8e6dedbb05d9dfe5e3a4e1066a30a850d8..705036f9c4bcd52ddab7c9b7f9137b6ff8e6cf3c 100644 (file)
@@ -942,14 +942,20 @@ Restores the queue to the value it was before any \fBset_queue\fR
 actions were applied.
 .
 .IP \fBdec_ttl\fR
+.IQ \fBdec_ttl\fB[\fR(\fIid1,id2\fI)\fR]\fR
 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
-processing.
+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.  This action
+also optionally supports the ability to specify a list of valid
+controller ids.  Each of controllers in the list will receive the
+``packet_in'' message only if they have registered to receive the
+invalid ttl packets.  If controller ids are not specified, the
+``packet_in'' message will be sent only to the controllers having
+controller id zero which have registered for the invalid ttl packets.
 .
 .IP \fBnote:\fR[\fIhh\fR]...
 Does nothing at all.  Any number of bytes represented as hex digits