[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