void dump_message(const char *name, struct ofpbuf *buf) { ofpmsg_update_length(buf); dump_ofpbuf(name, buf); }
/* In OpenFlow 1.0, 1.1, and 1.2, an OFPT_FEATURES_REPLY message lists all the * switch's ports, unless there are too many to fit. In OpenFlow 1.3 and * later, an OFPT_FEATURES_REPLY does not list ports at all. * * Given a buffer 'b' that contains a Features Reply message, this message * checks if it contains a complete list of the switch's ports. Returns true, * if so. Returns false if the list is missing (OF1.3+) or incomplete * (OF1.0/1.1/1.2), and in the latter case removes all of the ports from the * message. * * When this function returns false, the caller should send an OFPST_PORT_DESC * stats request to get the ports. */ bool ofputil_switch_features_has_ports(struct ofpbuf *b) { struct ofp_header *oh = b->data; size_t phy_port_size; if (oh->version >= OFP13_VERSION) { /* OpenFlow 1.3+ never has ports in the feature reply. */ return false; } phy_port_size = (oh->version == OFP10_VERSION ? sizeof(struct ofp10_phy_port) : sizeof(struct ofp11_port)); if (ntohs(oh->length) + phy_port_size <= UINT16_MAX) { /* There's room for additional ports in the feature reply. * Assume that the list is complete. */ return true; } /* The feature reply has no room for more ports. Probably the list is * truncated. Drop the ports and tell the caller to retrieve them with * OFPST_PORT_DESC. */ b->size = sizeof *oh + sizeof(struct ofp_switch_features); ofpmsg_update_length(b); return false; }
/* Try connecting and sending an extra-long hello, which should succeed (since * the specification says that implementations must accept and ignore extra * data). */ static void test_send_long_hello(struct ovs_cmdl_context *ctx) { const char *type = ctx->argv[1]; struct ofpbuf *hello; enum { EXTRA_BYTES = 8 }; hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP13_VERSION, htonl(0x12345678), EXTRA_BYTES); ofpbuf_put_zeros(hello, EXTRA_BYTES); ofpmsg_update_length(hello); test_send_hello(type, hello->data, hello->size, 0); ofpbuf_delete(hello); }
/* Try connecting and sending an extra-long hello, which should succeed (since * the specification says that implementations must accept and ignore extra * data). */ static void test_send_long_hello(int argc OVS_UNUSED, char *argv[]) { const char *type = argv[1]; struct ofpbuf *hello; enum { EXTRA_BYTES = 8 }; hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP13_VERSION, htonl(0x12345678), EXTRA_BYTES); ofpbuf_put_zeros(hello, EXTRA_BYTES); ofpmsg_update_length(hello); test_send_hello(type, ofpbuf_data(hello), ofpbuf_size(hello), 0); ofpbuf_delete(hello); }
struct ofpbuf * ofputil_encode_bundle_add(enum ofp_version ofp_version, struct ofputil_bundle_add_msg *msg) { struct ofpbuf *request; struct ofp14_bundle_ctrl_msg *m; /* Must use the same xid as the embedded message. */ request = ofpraw_alloc_xid(ofp_version == OFP13_VERSION ? OFPRAW_ONFT13_BUNDLE_ADD_MESSAGE : OFPRAW_OFPT14_BUNDLE_ADD_MESSAGE, ofp_version, msg->msg->xid, ntohs(msg->msg->length)); m = ofpbuf_put_zeros(request, sizeof *m); m->bundle_id = htonl(msg->bundle_id); m->flags = htons(msg->flags); ofpbuf_put(request, msg->msg, ntohs(msg->msg->length)); ofpmsg_update_length(request); return request; }
static struct ofpbuf * ofperr_encode_msg__(enum ofperr error, enum ofp_version ofp_version, ovs_be32 xid, const void *data, size_t data_len) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); const struct ofperr_domain *domain; const struct triplet *triplet; struct ofp_error_msg *oem; struct ofpbuf *buf; /* Get the error domain for 'ofp_version', or fall back to OF1.0. */ domain = ofperr_domain_from_version(ofp_version); if (!domain) { VLOG_ERR_RL(&rl, "cannot encode error for unknown OpenFlow " "version 0x%02x", ofp_version); domain = &ofperr_of10; } /* Make sure 'error' is valid in 'domain', or use a fallback error. */ if (!ofperr_is_valid(error)) { /* 'error' seems likely to be a system errno value. */ VLOG_ERR_RL(&rl, "invalid OpenFlow error code %d (%s)", error, ovs_strerror(error)); error = OFPERR_NXBRC_UNENCODABLE_ERROR; } else if (domain->errors[error - OFPERR_OFS].code < 0) { VLOG_ERR_RL(&rl, "cannot encode %s for %s", ofperr_get_name(error), domain->name); error = OFPERR_NXBRC_UNENCODABLE_ERROR; } triplet = ofperr_get_triplet__(error, domain); if (!triplet->vendor) { buf = ofpraw_alloc_xid(OFPRAW_OFPT_ERROR, domain->version, xid, sizeof *oem + data_len); oem = ofpbuf_put_uninit(buf, sizeof *oem); oem->type = htons(triplet->type); oem->code = htons(triplet->code); } else if (ofp_version <= OFP11_VERSION) { struct nx_vendor_error *nve; buf = ofpraw_alloc_xid(OFPRAW_OFPT_ERROR, domain->version, xid, sizeof *oem + sizeof *nve + data_len); oem = ofpbuf_put_uninit(buf, sizeof *oem); oem->type = htons(NXET_VENDOR); oem->code = htons(NXVC_VENDOR_ERROR); nve = ofpbuf_put_uninit(buf, sizeof *nve); nve->vendor = htonl(triplet->vendor); nve->type = htons(triplet->type); nve->code = htons(triplet->code); } else { ovs_be32 vendor = htonl(triplet->vendor); buf = ofpraw_alloc_xid(OFPRAW_OFPT_ERROR, domain->version, xid, sizeof *oem + sizeof(uint32_t) + data_len); oem = ofpbuf_put_uninit(buf, sizeof *oem); oem->type = htons(OFPET12_EXPERIMENTER); oem->code = htons(triplet->type); ofpbuf_put(buf, &vendor, sizeof vendor); } ofpbuf_put(buf, data, MIN(data_len, UINT16_MAX - buf->size)); ofpmsg_update_length(buf); return buf; }