Looks good to me. Ethan
On Thu, Oct 27, 2011 at 13:00, Ben Pfaff <b...@nicira.com> wrote: > Here's a revised version of this patch now that I've dropped 1/6. > > Please look it over. Thank you > > --8<--------------------------cut here-------------------------->8-- > > From: Ben Pfaff <b...@nicira.com> > Date: Thu, 27 Oct 2011 12:54:44 -0700 > Subject: [PATCH] ofp-util: New function ofputil_decode_msg_type_partial(). > > --- > lib/ofp-util.c | 201 > ++++++++++++++++++++++++++++++++++------------------ > lib/ofp-util.h | 2 + > tests/ofp-print.at | 2 +- > 3 files changed, 136 insertions(+), 69 deletions(-) > > diff --git a/lib/ofp-util.c b/lib/ofp-util.c > index 328d0df..99de3e3 100644 > --- a/lib/ofp-util.c > +++ b/lib/ofp-util.c > @@ -274,6 +274,11 @@ struct ofputil_msg_type { > unsigned int extra_multiple; > }; > > +/* Represents a malformed OpenFlow message. */ > +static const struct ofputil_msg_type ofputil_invalid_type = { > + OFPUTIL_MSG_INVALID, 0, "OFPUTIL_MSG_INVALID", 0, 0 > +}; > + > struct ofputil_msg_category { > const char *name; /* e.g. "OpenFlow message" */ > const struct ofputil_msg_type *types; > @@ -281,56 +286,51 @@ struct ofputil_msg_category { > int missing_error; /* ofp_mkerr() value for missing type. */ > }; > > -static bool > -ofputil_length_ok(const struct ofputil_msg_category *cat, > - const struct ofputil_msg_type *type, > - unsigned int size) > +static int > +ofputil_check_length(const struct ofputil_msg_type *type, unsigned int size) > { > switch (type->extra_multiple) { > case 0: > if (size != type->min_size) { > - VLOG_WARN_RL(&bad_ofmsg_rl, "received %s %s with incorrect " > + VLOG_WARN_RL(&bad_ofmsg_rl, "received %s with incorrect " > "length %u (expected length %u)", > - cat->name, type->name, size, type->min_size); > - return false; > + type->name, size, type->min_size); > + return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); > } > - return true; > + return 0; > > case 1: > if (size < type->min_size) { > - VLOG_WARN_RL(&bad_ofmsg_rl, "received %s %s with incorrect " > + VLOG_WARN_RL(&bad_ofmsg_rl, "received %s with incorrect " > "length %u (expected length at least %u bytes)", > - cat->name, type->name, size, type->min_size); > - return false; > + type->name, size, type->min_size); > + return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); > } > - return true; > + return 0; > > default: > if (size < type->min_size > || (size - type->min_size) % type->extra_multiple) { > - VLOG_WARN_RL(&bad_ofmsg_rl, "received %s %s with incorrect " > + VLOG_WARN_RL(&bad_ofmsg_rl, "received %s with incorrect " > "length %u (must be exactly %u bytes or longer " > "by an integer multiple of %u bytes)", > - cat->name, type->name, size, > + type->name, size, > type->min_size, type->extra_multiple); > - return false; > + return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); > } > - return true; > + return 0; > } > } > > static int > ofputil_lookup_openflow_message(const struct ofputil_msg_category *cat, > - uint32_t value, unsigned int size, > + uint32_t value, > const struct ofputil_msg_type **typep) > { > const struct ofputil_msg_type *type; > > for (type = cat->types; type < &cat->types[cat->n_types]; type++) { > if (type->value == value) { > - if (!ofputil_length_ok(cat, type, size)) { > - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); > - } > *typep = type; > return 0; > } > @@ -342,7 +342,7 @@ ofputil_lookup_openflow_message(const struct > ofputil_msg_category *cat, > } > > static int > -ofputil_decode_vendor(const struct ofp_header *oh, > +ofputil_decode_vendor(const struct ofp_header *oh, size_t length, > const struct ofputil_msg_type **typep) > { > static const struct ofputil_msg_type nxt_messages[] = { > @@ -380,6 +380,13 @@ ofputil_decode_vendor(const struct ofp_header *oh, > const struct ofp_vendor_header *ovh; > const struct nicira_header *nh; > > + if (length < sizeof(struct ofp_vendor_header)) { > + if (length == ntohs(oh->length)) { > + VLOG_WARN_RL(&bad_ofmsg_rl, "truncated vendor message"); > + } > + return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); > + } > + > ovh = (const struct ofp_vendor_header *) oh; > if (ovh->vendor != htonl(NX_VENDOR_ID)) { > VLOG_WARN_RL(&bad_ofmsg_rl, "received vendor message for unknown " > @@ -387,24 +394,34 @@ ofputil_decode_vendor(const struct ofp_header *oh, > return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR); > } > > - if (ntohs(ovh->header.length) < sizeof(struct nicira_header)) { > - VLOG_WARN_RL(&bad_ofmsg_rl, "received Nicira vendor message of " > - "length %u (expected at least %zu)", > - ntohs(ovh->header.length), sizeof(struct > nicira_header)); > + if (length < sizeof(struct nicira_header)) { > + if (length == ntohs(oh->length)) { > + VLOG_WARN_RL(&bad_ofmsg_rl, "received Nicira vendor message of " > + "length %u (expected at least %zu)", > + ntohs(ovh->header.length), > + sizeof(struct nicira_header)); > + } > return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); > } > > nh = (const struct nicira_header *) oh; > return ofputil_lookup_openflow_message(&nxt_category, ntohl(nh->subtype), > - ntohs(oh->length), typep); > + typep); > } > > static int > -check_nxstats_msg(const struct ofp_header *oh) > +check_nxstats_msg(const struct ofp_header *oh, size_t length) > { > const struct ofp_stats_msg *osm = (const struct ofp_stats_msg *) oh; > ovs_be32 vendor; > > + if (length < sizeof(struct ofp_vendor_stats_msg)) { > + if (length == ntohs(oh->length)) { > + VLOG_WARN_RL(&bad_ofmsg_rl, "truncated vendor stats message"); > + } > + return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); > + } > + > memcpy(&vendor, osm + 1, sizeof vendor); > if (vendor != htonl(NX_VENDOR_ID)) { > VLOG_WARN_RL(&bad_ofmsg_rl, "received vendor stats message for " > @@ -412,8 +429,10 @@ check_nxstats_msg(const struct ofp_header *oh) > return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR); > } > > - if (ntohs(osm->header.length) < sizeof(struct nicira_stats_msg)) { > - VLOG_WARN_RL(&bad_ofmsg_rl, "truncated Nicira stats message"); > + if (length < sizeof(struct nicira_stats_msg)) { > + if (length == ntohs(osm->header.length)) { > + VLOG_WARN_RL(&bad_ofmsg_rl, "truncated Nicira stats message"); > + } > return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); > } > > @@ -421,7 +440,7 @@ check_nxstats_msg(const struct ofp_header *oh) > } > > static int > -ofputil_decode_nxst_request(const struct ofp_header *oh, > +ofputil_decode_nxst_request(const struct ofp_header *oh, size_t length, > const struct ofputil_msg_type **typep) > { > static const struct ofputil_msg_type nxst_requests[] = { > @@ -443,19 +462,18 @@ ofputil_decode_nxst_request(const struct ofp_header *oh, > const struct nicira_stats_msg *nsm; > int error; > > - error = check_nxstats_msg(oh); > + error = check_nxstats_msg(oh, length); > if (error) { > return error; > } > > nsm = (struct nicira_stats_msg *) oh; > return ofputil_lookup_openflow_message(&nxst_request_category, > - ntohl(nsm->subtype), > - ntohs(oh->length), typep); > + ntohl(nsm->subtype), typep); > } > > static int > -ofputil_decode_nxst_reply(const struct ofp_header *oh, > +ofputil_decode_nxst_reply(const struct ofp_header *oh, size_t length, > const struct ofputil_msg_type **typep) > { > static const struct ofputil_msg_type nxst_replies[] = { > @@ -477,19 +495,31 @@ ofputil_decode_nxst_reply(const struct ofp_header *oh, > const struct nicira_stats_msg *nsm; > int error; > > - error = check_nxstats_msg(oh); > + error = check_nxstats_msg(oh, length); > if (error) { > return error; > } > > nsm = (struct nicira_stats_msg *) oh; > return ofputil_lookup_openflow_message(&nxst_reply_category, > - ntohl(nsm->subtype), > - ntohs(oh->length), typep); > + ntohl(nsm->subtype), typep); > +} > + > +static int > +check_stats_msg(const struct ofp_header *oh, size_t length) > +{ > + if (length < sizeof(struct ofp_stats_msg)) { > + if (length == ntohs(oh->length)) { > + VLOG_WARN_RL(&bad_ofmsg_rl, "truncated stats message"); > + } > + return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); > + } > + > + return 0; > } > > static int > -ofputil_decode_ofpst_request(const struct ofp_header *oh, > +ofputil_decode_ofpst_request(const struct ofp_header *oh, size_t length, > const struct ofputil_msg_type **typep) > { > static const struct ofputil_msg_type ofpst_requests[] = { > @@ -531,17 +561,21 @@ ofputil_decode_ofpst_request(const struct ofp_header > *oh, > const struct ofp_stats_msg *request = (const struct ofp_stats_msg *) oh; > int error; > > + error = check_stats_msg(oh, length); > + if (error) { > + return error; > + } > + > error = ofputil_lookup_openflow_message(&ofpst_request_category, > - ntohs(request->type), > - ntohs(oh->length), typep); > + ntohs(request->type), typep); > if (!error && request->type == htons(OFPST_VENDOR)) { > - error = ofputil_decode_nxst_request(oh, typep); > + error = ofputil_decode_nxst_request(oh, length, typep); > } > return error; > } > > static int > -ofputil_decode_ofpst_reply(const struct ofp_header *oh, > +ofputil_decode_ofpst_reply(const struct ofp_header *oh, size_t length, > const struct ofputil_msg_type **typep) > { > static const struct ofputil_msg_type ofpst_replies[] = { > @@ -583,28 +617,22 @@ ofputil_decode_ofpst_reply(const struct ofp_header *oh, > const struct ofp_stats_msg *reply = (const struct ofp_stats_msg *) oh; > int error; > > + error = check_stats_msg(oh, length); > + if (error) { > + return error; > + } > + > error = ofputil_lookup_openflow_message(&ofpst_reply_category, > - ntohs(reply->type), > - ntohs(oh->length), typep); > + ntohs(reply->type), typep); > if (!error && reply->type == htons(OFPST_VENDOR)) { > - error = ofputil_decode_nxst_reply(oh, typep); > + error = ofputil_decode_nxst_reply(oh, length, typep); > } > return error; > } > > -/* Decodes the message type represented by 'oh'. Returns 0 if successful or > - * an OpenFlow error code constructed with ofp_mkerr() on failure. Either > - * way, stores in '*typep' a type structure that can be inspected with the > - * ofputil_msg_type_*() functions. > - * > - * oh->length must indicate the correct length of the message (and must be at > - * least sizeof(struct ofp_header)). > - * > - * Success indicates that 'oh' is at least as long as the minimum-length > - * message of its type. */ > -int > -ofputil_decode_msg_type(const struct ofp_header *oh, > - const struct ofputil_msg_type **typep) > +static int > +ofputil_decode_msg_type__(const struct ofp_header *oh, size_t length, > + const struct ofputil_msg_type **typep) > { > static const struct ofputil_msg_type ofpt_messages[] = { > { OFPUTIL_OFPT_HELLO, > @@ -696,32 +724,69 @@ ofputil_decode_msg_type(const struct ofp_header *oh, > > int error; > > - error = ofputil_lookup_openflow_message(&ofpt_category, oh->type, > - ntohs(oh->length), typep); > + error = ofputil_lookup_openflow_message(&ofpt_category, oh->type, typep); > if (!error) { > switch (oh->type) { > case OFPT_VENDOR: > - error = ofputil_decode_vendor(oh, typep); > + error = ofputil_decode_vendor(oh, length, typep); > break; > > case OFPT_STATS_REQUEST: > - error = ofputil_decode_ofpst_request(oh, typep); > + error = ofputil_decode_ofpst_request(oh, length, typep); > break; > > case OFPT_STATS_REPLY: > - error = ofputil_decode_ofpst_reply(oh, typep); > + error = ofputil_decode_ofpst_reply(oh, length, typep); > > default: > break; > } > } > + return error; > +} > + > +/* Decodes the message type represented by 'oh'. Returns 0 if successful or > + * an OpenFlow error code constructed with ofp_mkerr() on failure. Either > + * way, stores in '*typep' a type structure that can be inspected with the > + * ofputil_msg_type_*() functions. > + * > + * oh->length must indicate the correct length of the message (and must be at > + * least sizeof(struct ofp_header)). > + * > + * Success indicates that 'oh' is at least as long as the minimum-length > + * message of its type. */ > +int > +ofputil_decode_msg_type(const struct ofp_header *oh, > + const struct ofputil_msg_type **typep) > +{ > + size_t length = ntohs(oh->length); > + int error; > + > + error = ofputil_decode_msg_type__(oh, length, typep); > + if (!error) { > + error = ofputil_check_length(*typep, length); > + } > if (error) { > - static const struct ofputil_msg_type ofputil_invalid_type = { > - OFPUTIL_MSG_INVALID, > - 0, "OFPUTIL_MSG_INVALID", > - 0, 0 > - }; > + *typep = &ofputil_invalid_type; > + } > + return error; > +} > > +/* Decodes the message type represented by 'oh', of which only the first > + * 'length' bytes are available. Returns 0 if successful or an OpenFlow > error > + * code constructed with ofp_mkerr() on failure. Either way, stores in > + * '*typep' a type structure that can be inspected with the > + * ofputil_msg_type_*() functions. */ > +int > +ofputil_decode_msg_type_partial(const struct ofp_header *oh, size_t length, > + const struct ofputil_msg_type **typep) > +{ > + int error; > + > + error = (length >= sizeof *oh > + ? ofputil_decode_msg_type__(oh, length, typep) > + : ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN)); > + if (error) { > *typep = &ofputil_invalid_type; > } > return error; > diff --git a/lib/ofp-util.h b/lib/ofp-util.h > index 5af9d2b..909467f 100644 > --- a/lib/ofp-util.h > +++ b/lib/ofp-util.h > @@ -90,6 +90,8 @@ enum ofputil_msg_code { > struct ofputil_msg_type; > int ofputil_decode_msg_type(const struct ofp_header *, > const struct ofputil_msg_type **); > +int ofputil_decode_msg_type_partial(const struct ofp_header *, size_t length, > + const struct ofputil_msg_type **); > enum ofputil_msg_code ofputil_msg_type_code(const struct ofputil_msg_type *); > const char *ofputil_msg_type_name(const struct ofputil_msg_type *); > > diff --git a/tests/ofp-print.at b/tests/ofp-print.at > index 4c190a1..0a6cdcc 100644 > --- a/tests/ofp-print.at > +++ b/tests/ofp-print.at > @@ -197,7 +197,7 @@ ff fe 50 54 00 00 00 01 62 72 30 00 00 00 00 00 \ > 000000d0 00 00 02 08 00 00 02 8f-00 00 02 8f |............ | > ], [stderr]) > AT_CHECK([sed 's/.*|//' stderr], [0], [dnl > -received OpenFlow message OFPT_FEATURES_REPLY with incorrect length 220 > (must be exactly 32 bytes or longer by an integer multiple of 48 bytes) > +received OFPT_FEATURES_REPLY with incorrect length 220 (must be exactly 32 > bytes or longer by an integer multiple of 48 bytes) > ]) > AT_CLEANUP > > -- > 1.7.4.4 > > _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev