/* Try connecting and sending a hello packet that has a bad version, which * should fail with EPROTO. */ static void test_send_invalid_version_hello(int argc OVS_UNUSED, char *argv[]) { const char *type = argv[1]; struct ofpbuf *hello; hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP13_VERSION, htonl(0x12345678), 0); ((struct ofp_header *) ofpbuf_data(hello))->version = 0; test_send_hello(type, ofpbuf_data(hello), ofpbuf_size(hello), EPROTO); 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(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; }
/* Returns a buffer owned by the caller that encodes 'features' in the format * required by 'protocol' with the given 'xid'. The caller should append port * information to the buffer with subsequent calls to * ofputil_put_switch_features_port(). */ struct ofpbuf * ofputil_encode_switch_features(const struct ofputil_switch_features *features, enum ofputil_protocol protocol, ovs_be32 xid) { struct ofp_switch_features *osf; struct ofpbuf *b; enum ofp_version version; enum ofpraw raw; version = ofputil_protocol_to_ofp_version(protocol); switch (version) { case OFP10_VERSION: raw = OFPRAW_OFPT10_FEATURES_REPLY; break; case OFP11_VERSION: case OFP12_VERSION: raw = OFPRAW_OFPT11_FEATURES_REPLY; break; case OFP13_VERSION: case OFP14_VERSION: case OFP15_VERSION: case OFP16_VERSION: raw = OFPRAW_OFPT13_FEATURES_REPLY; break; default: OVS_NOT_REACHED(); } b = ofpraw_alloc_xid(raw, version, xid, 0); osf = ofpbuf_put_zeros(b, sizeof *osf); osf->datapath_id = htonll(features->datapath_id); osf->n_buffers = htonl(features->n_buffers); osf->n_tables = features->n_tables; osf->capabilities = htonl(features->capabilities & ofputil_capabilities_mask(version)); switch (version) { case OFP10_VERSION: if (features->capabilities & OFPUTIL_C_STP) { osf->capabilities |= htonl(OFPC10_STP); } osf->actions = ofpact_bitmap_to_openflow(features->ofpacts, OFP10_VERSION); break; case OFP13_VERSION: case OFP14_VERSION: case OFP15_VERSION: case OFP16_VERSION: osf->auxiliary_id = features->auxiliary_id; /* fall through */ case OFP11_VERSION: case OFP12_VERSION: if (features->capabilities & OFPUTIL_C_GROUP_STATS) { osf->capabilities |= htonl(OFPC11_GROUP_STATS); } break; default: OVS_NOT_REACHED(); } return b; }