From: Mehak Mahajan Date: Thu, 16 Aug 2012 21:25:07 +0000 (-0700) Subject: Add Nicira vendor extension action NXAST_DEC_TTL_CNT_IDS. X-Git-Tag: sliver-openvswitch-1.8.90-0~48^2~38 X-Git-Url: http://git.onelab.eu/?p=sliver-openvswitch.git;a=commitdiff_plain;h=c2d967a562aaa57b679c302a5041d5a941154143 Add Nicira vendor extension action NXAST_DEC_TTL_CNT_IDS. 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 --- diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index 4fc2049d1..d1d3654e0 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 6503f61ca..db603b6e5 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -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: diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h index 2e021819d..200366826 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 32d383689..e5f5ea03a 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -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: diff --git a/lib/ofp-util.def b/lib/ofp-util.def index 974cd8f87..619bb88cd 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 3d6885547..d66c500e6 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -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; diff --git a/tests/ofp-actions.at b/tests/ofp-actions.at index ba8d309d0..36c67f106 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,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 diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index 65fc6e8e6..705036f9c 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