[ovs-dev] [PATCH] Add Nicira vendor extension action NXAST_DEC_TTL_CNT_IDS.
Mehak Mahajan
mmahajan at nicira.com
Thu Aug 16 20:36:47 UTC 2012
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 at nicira.com>
---
include/openflow/nicira-ext.h | 30 ++++++++++++
lib/ofp-actions.c | 105 +++++++++++++++++++++++++++++++++++++++-
lib/ofp-actions.h | 16 ++++++-
lib/ofp-parse.c | 38 ++++++++++++++-
lib/ofp-util.def | 39 ++++++++-------
ofproto/ofproto-dpif.c | 11 +++-
tests/ofp-actions.at | 6 ++
utilities/ovs-ofctl.8.in | 14 ++++--
8 files changed, 227 insertions(+), 32 deletions(-)
diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
index 4fc2049..d1d3654 100644
--- a/include/openflow/nicira-ext.h
+++ b/include/openflow/nicira-ext.h
@@ -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. */
};
+
+
+/* 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);
+
/* Action structure for NXAST_OUTPUT_REG.
*
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index 6503f61..db603b6 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -149,6 +149,58 @@ note_from_openflow(const struct nx_action_note *nan, struct ofpbuf *out)
}
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)
{
const struct nx_action_header *nah = (const struct nx_action_header *) a;
@@ -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:
@@ -1083,6 +1140,29 @@ ofpact_controller_to_nxast(const struct ofpact_controller *oc,
}
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:
@@ -1512,6 +1592,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:
diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
index 2e02181..2003668 100644
--- a/lib/ofp-actions.h
+++ b/lib/ofp-actions.h
@@ -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)
/* 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,
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 32d3836..e5f5ea0 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -279,6 +279,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:
diff --git a/lib/ofp-util.def b/lib/ofp-util.def
index 974cd8f..619bb88 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_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
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index cf34e92..20701e4 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -5147,7 +5147,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)) {
@@ -5158,7 +5158,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;
@@ -5518,7 +5523,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;
diff --git a/tests/ofp-actions.at b/tests/ofp-actions.at
index ba8d309..45e9bd5 100644
--- a/tests/ofp-actions.at
+++ b/tests/ofp-actions.at
@@ -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)
+ffff 0018 00002320 0015 000100000000 8000000000000000
+
])
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)
+ffff 0018 00002320 0015 000100000000 8000000000000000
+
])
sed '/^[[#&]]/d' < test-data > input.txt
sed -n 's/^# //p; /^$/p' < test-data > expout
diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index 65fc6e8..705036f 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -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
--
1.7.2.5
More information about the dev
mailing list