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 <mmaha...@nicira.com> --- include/openflow/nicira-ext.h | 40 ++++++++++++++- lib/ofp-actions.c | 115 +++++++++++++++++++++++++++++++++++++++- lib/ofp-actions.h | 16 +++++- lib/ofp-parse.c | 42 +++++++++++++++- lib/ofp-util.def | 39 +++++++------- ofproto/ofproto-dpif.c | 11 +++- tests/ofp-actions.at | 18 ++++-- utilities/ovs-ofctl.8.in | 14 ++++-- 8 files changed, 256 insertions(+), 39 deletions(-) diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index 4fc2049..50a0eae 100644 --- a/include/openflow/nicira-ext.h +++ b/include/openflow/nicira-ext.h @@ -291,7 +291,8 @@ enum nx_action_subtype { NXAST_OUTPUT_REG, /* struct nx_action_output_reg */ NXAST_LEARN, /* struct nx_action_learn */ NXAST_EXIT, /* struct nx_action_header */ - NXAST_DEC_TTL, /* struct nx_action_header */ + NXAST_DEC_TTL, /* struct nx_action_cnt_ids */ + NXAST_DEC_TTL_CNT_IDS, /* struct nx_action_cnt_ids */ NXAST_FIN_TIMEOUT, /* struct nx_action_fin_timeout */ NXAST_CONTROLLER, /* struct nx_action_controller */ }; @@ -1060,6 +1061,43 @@ enum nx_bd_algorithm { * Uses the 'fields' and 'basis' parameters. */ NX_BD_ALG_HRW /* Highest Random Weight. */ }; + + + /* Action structure for NXAST_DEC_TTL and NXAST_DEC_TTL_CNT_IDS. + * + * The NXAST_DEC_TTL is used to forward the packet_in having reason code + * OFPR_INVALID_TTL to all controllers having a zero controller id. The + * syntax for the same is `dec_ttl'. The controller (having a zero id) + * must have explicitly registered to receive these asynchronous messages. + * Though the action does not explicitly have any controllers specified, + * the n_controllers will be set to 1 and cnt_ids will contain controller + * id 0. + * + * The NXAST_DEC_TTL_CNT_IDS is used to forward the packet_in having reason + * code OFPR_INVALID_TTL to a list of controllers. The syntax for specifying + * the same is `dec_ttl(id1, id2) where id1, id2 are valid controller ids + * (please note that 0 is a valid controller id). Similar to NXAST_DEC_TTL, + * the controllers having the ids specified in the list must have explicitly + * registered to receive these asynchronous messages. The n_controllers will + * be set to the number of controllers in the list and cnt_ids will contain + * specified controller ids. */ +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..505c8bb 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -149,6 +149,66 @@ note_from_openflow(const struct nx_action_note *nan, struct ofpbuf *out) } static enum ofperr +dec_ttl_from_openflow(const struct nx_action_cnt_ids *nac_ids, + 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; + + if (!is_all_zeros(nac_ids->zeros, sizeof nac_ids->zeros)) { + error = OFPERR_NXBRC_MUST_BE_ZERO; + } + + ids = out->l2; + 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; + enum ofperr error = 0; + 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 = ntohl(nac_ids->len) - sizeof *nac_ids; + + if (!is_all_zeros(nac_ids->zeros, sizeof nac_ids->zeros)) { + error = 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 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; @@ -310,7 +370,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((const struct nx_action_cnt_ids *) a, 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 +1148,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) +{ + struct nx_action_cnt_ids *nac_ids; + int ids_len = ROUND_UP(2 * oc_ids->n_controllers, OFP_ACTION_ALIGN); + ovs_be16 *ids; + size_t i; + + if (oc_ids->ofpact.compat == OFPUTIL_NXAST_DEC_TTL) { + nac_ids = ofputil_put_NXAST_DEC_TTL(out); + } else { + 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->cnt_ids[i]); + } +} + +static void ofpact_fin_timeout_to_nxast(const struct ofpact_fin_timeout *fin_timeout, struct ofpbuf *out) { @@ -1116,7 +1204,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 +1600,27 @@ 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) { + if (ids->n_controllers) { + 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 +1756,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..f9dc0ca 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -279,6 +279,45 @@ 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 *idstr, *string; + char *cntr; + + ids->ofpact.compat = OFPUTIL_NXAST_DEC_TTL_CNT_IDS; + string = xstrdup(arg); + cntr = strtok_r(string, ", ", &idstr); + + for (;;) { + uint16_t id; + + id = atoi(cntr); + ofpbuf_put(b, &id, sizeof id); + ids = b->l2; + ids->n_controllers++; + + if (*idstr == '\0') { + break; + } + cntr = strtok_r(NULL, ", ", &idstr); + } + } + 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 +452,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 +464,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..4d1d1a0 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_cnt_ids, 1, "dec_ttl") +NXAST_ACTION(NXAST_DEC_TTL_CNT_IDS, nx_action_cnt_ids, 1, NULL) +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 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..d72d8f6 100644 --- a/tests/ofp-actions.at +++ b/tests/ofp-actions.at @@ -100,13 +100,16 @@ ffff 0048 00002320 0010 000a 0014 0050 123456789abcdef0 0000 02 00 0002 0004 dnl ffff 0010 00002320 0011 000000000000 # actions=dec_ttl -ffff 0010 00002320 0012 000000000000 +ffff 0018 00002320 0012 000100000000 0000000000000000 + +# actions=dec_ttl(32768) +ffff 0018 00002320 0013 000100000000 8000000000000000 # actions=fin_timeout(idle_timeout=10,hard_timeout=20) -ffff 0010 00002320 0013 000a 0014 0000 +ffff 0010 00002320 0014 000a 0014 0000 # actions=controller(reason=invalid_ttl,max_len=1234,id=5678) -ffff 0010 00002320 0014 04d2 162e 02 00 +ffff 0010 00002320 0015 04d2 162e 02 00 ]) sed '/^[[#&]]/d' < test-data > input.txt @@ -214,13 +217,16 @@ ffff 0048 00002320 0010 000a 0014 0050 123456789abcdef0 0000 02 00 0002 0004 dnl ffff 0010 00002320 0011 000000000000 # actions=dec_ttl -ffff 0010 00002320 0012 000000000000 +ffff 0018 00002320 0012 000100000000 0000000000000000 + +# actions=dec_ttl(32768) +ffff 0018 00002320 0013 000100000000 8000000000000000 # actions=fin_timeout(idle_timeout=10,hard_timeout=20) -ffff 0010 00002320 0013 000a 0014 0000 +ffff 0010 00002320 0014 000a 0014 0000 # actions=controller(reason=invalid_ttl,max_len=1234,id=5678) -ffff 0010 00002320 0014 04d2 162e 02 00 +ffff 0010 00002320 0015 04d2 162e 02 00 ]) sed '/^[[#&]]/d' < test-data > input.txt 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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev