/* Returns an OpenFlow message that, sent on an OpenFlow connection whose * protocol is 'current', at least partly transitions the protocol to 'want'. * Stores in '*next' the protocol that will be in effect on the OpenFlow * connection if the switch processes the returned message correctly. (If * '*next != want' then the caller will have to iterate.) * * If 'current == want', or if it is not possible to transition from 'current' * to 'want' (because, for example, 'current' and 'want' use different OpenFlow * protocol versions), returns NULL and stores 'current' in '*next'. */ struct ofpbuf * ofputil_encode_set_protocol(enum ofputil_protocol current, enum ofputil_protocol want, enum ofputil_protocol *next) { enum ofp_version cur_version, want_version; enum ofputil_protocol cur_base, want_base; bool cur_tid, want_tid; cur_version = ofputil_protocol_to_ofp_version(current); want_version = ofputil_protocol_to_ofp_version(want); if (cur_version != want_version) { *next = current; return NULL; } cur_base = ofputil_protocol_to_base(current); want_base = ofputil_protocol_to_base(want); if (cur_base != want_base) { *next = ofputil_protocol_set_base(current, want_base); switch (want_base) { case OFPUTIL_P_OF10_NXM: case OFPUTIL_P_OF10_STD: return ofputil_encode_nx_set_flow_format(want_base); case OFPUTIL_P_OF11_STD: case OFPUTIL_P_OF12_OXM: case OFPUTIL_P_OF13_OXM: case OFPUTIL_P_OF14_OXM: case OFPUTIL_P_OF15_OXM: case OFPUTIL_P_OF16_OXM: /* There is only one variant of each OpenFlow 1.1+ protocol, and we * verified above that we're not trying to change versions. */ OVS_NOT_REACHED(); case OFPUTIL_P_OF10_STD_TID: case OFPUTIL_P_OF10_NXM_TID: OVS_NOT_REACHED(); } } cur_tid = (current & OFPUTIL_P_TID) != 0; want_tid = (want & OFPUTIL_P_TID) != 0; if (cur_tid != want_tid) { *next = ofputil_protocol_set_tid(current, want_tid); return ofputil_encode_nx_flow_mod_table_id(want_tid); } ovs_assert(current == want); *next = current; return NULL; }
struct ofpbuf * port_stats_request(enum ofputil_protocol proto) { uint32_t port_no = 0xffffffff; return ofputil_encode_dump_ports_request( ofputil_protocol_to_ofp_version(proto), port_no); }
struct ofpbuf * meter_mod(enum ofputil_protocol proto) { const int N_BANDS = 2; struct ofputil_meter_mod mm; struct ofputil_meter_band bands[N_BANDS]; memset(bands, 0, sizeof(*bands)*2); bands[0].type = 1; // OFPMBT_DROP bands[0].rate = 1000; bands[0].burst_size = 10; bands[1].type = 2; // OFPMBT_DSCP_REMARK bands[1].prec_level = 1; bands[1].rate = 1000; bands[1].burst_size = 10; memset(&mm, 0, sizeof(mm)); mm.command = 0; // OFPMC_ADD mm.meter.meter_id = 100; mm.meter.flags = 14; // OFPMF_PKTPS, OFPMF_BURST, OFPMF_STATS mm.meter.n_bands = N_BANDS; mm.meter.bands = bands; return ofputil_encode_meter_mod( ofputil_protocol_to_ofp_version(proto), &mm); }
struct ofpbuf * group_mod(enum ofputil_protocol proto) { struct ofputil_group_mod gm; struct ofpbuf acts; struct ofpact_ipv4 *a_set_field; struct ofpact_goto_table *a_goto; struct ofputil_bucket bckt; memset(&gm, 0, sizeof(gm)); gm.command = OFPGC15_INSERT_BUCKET; gm.type = OFPGT11_SELECT; gm.group_id = 0xaaaaaaaa; gm.command_bucket_id = 0xbbbbbbbb; ofpbuf_init(&acts, 0x18); ofpact_put_STRIP_VLAN(&acts); a_set_field = ofpact_put_SET_IPV4_DST(&acts); a_set_field->ipv4 = inet_addr("192.168.2.9"); bckt.weight = 0xcccc; bckt.watch_port = 0xdddd; bckt.watch_group = 0xeeeeeeee; bckt.bucket_id = 0x12345678; bckt.ofpacts = acts.data; bckt.ofpacts_len = acts.size; list_init(&(gm.buckets)); list_push_back(&(gm.buckets), &(bckt.list_node)); return ofputil_encode_group_mod( ofputil_protocol_to_ofp_version(proto), &gm); }
struct ofpbuf * group_stats_request(enum ofputil_protocol proto) { uint32_t group_id = 0xfffffffc; return ofputil_encode_group_stats_request( ofputil_protocol_to_ofp_version(proto), group_id); }
void ofputil_encode_bundle_msgs(const struct ofputil_bundle_msg *bms, size_t n_bms, struct ovs_list *requests, enum ofputil_protocol protocol) { enum ofp_version version = ofputil_protocol_to_ofp_version(protocol); for (size_t i = 0; i < n_bms; i++) { struct ofpbuf *request = NULL; switch ((int)bms[i].type) { case OFPTYPE_FLOW_MOD: request = ofputil_encode_flow_mod(&bms[i].fm, protocol); break; case OFPTYPE_GROUP_MOD: request = ofputil_encode_group_mod(version, &bms[i].gm, NULL, -1); break; case OFPTYPE_PACKET_OUT: request = ofputil_encode_packet_out(&bms[i].po, protocol); break; default: break; } if (request) { ovs_list_push_back(requests, &request->list_node); } } }
/* 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: 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: 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; }
struct ofpbuf * port_desc_request(enum ofputil_protocol proto) { uint32_t port_no = 0xbcda; return ofputil_encode_port_desc_stats_request( ofputil_protocol_to_ofp_version(proto), port_no); }
struct ofpbuf * meter_stats_request(enum ofputil_protocol proto) { uint32_t meter_id = 0xffffffff; return ofputil_encode_meter_request( ofputil_protocol_to_ofp_version(proto), OFPUTIL_METER_STATS, meter_id); }
struct ofpbuf * queue_stats_request(enum ofputil_protocol proto) { struct ofputil_queue_stats_request oqsr; memset(&oqsr, 0, sizeof(oqsr)); oqsr.port_no = 0xabcd; oqsr.queue_id = 0xffffffff; return ofputil_encode_queue_stats_request( ofputil_protocol_to_ofp_version(proto), &oqsr); }
/* Returns a bitmap of OpenFlow versions that are supported by at * least one of the 'protocols'. */ uint32_t ofputil_protocols_to_version_bitmap(enum ofputil_protocol protocols) { uint32_t bitmap = 0; for (; protocols; protocols = zero_rightmost_1bit(protocols)) { enum ofputil_protocol protocol = rightmost_1bit(protocols); bitmap |= 1u << ofputil_protocol_to_ofp_version(protocol); } return bitmap; }
struct ofpbuf * set_config(enum ofputil_protocol proto) { struct ofputil_switch_config sc; memset(&sc, 0, sizeof(sc)); sc.frag = OFPUTIL_FRAG_NORMAL; // sc.invalid_ttl_to_controller is for only OFP11 and OFP12 sc.miss_send_len = 128; // The default of OpenFlow Spec return ofputil_encode_set_config( &sc, ofputil_protocol_to_ofp_version(proto)); }
struct ofpbuf * echo_reply(enum ofputil_protocol proto) { struct ofp_header oh; memset(&oh, 0, sizeof(oh)); oh.version = ofputil_protocol_to_ofp_version(proto); oh.type = 3; // OFPT_ECHO_REPLY oh.length = htons(8); // lenght of ofp_header oh.xid = 0; return make_echo_reply(&oh); }
struct ofpbuf * bundle_ctrl(enum ofputil_protocol proto) { struct ofputil_bundle_ctrl_msg msg; struct ofp_header oh; memset(&oh, 0, sizeof(oh)); oh.xid = 0; oh.version = ofputil_protocol_to_ofp_version(proto); memset(&msg, 0, sizeof(msg)); msg.bundle_id = 99999999; msg.type = OFPBCT_OPEN_REPLY; msg.flags = OFPBF_ATOMIC; return ofputil_encode_bundle_ctrl_reply(&oh, &msg); }
struct ofpbuf * get_config_reply(enum ofputil_protocol proto) { struct ofputil_switch_config sc; struct ofp_header oh; memset(&oh, 0, sizeof(oh)); oh.xid = 0; oh.version = ofputil_protocol_to_ofp_version(proto); memset(&sc, 0, sizeof(sc)); sc.frag = OFPUTIL_FRAG_NORMAL; // sc.invalid_ttl_to_controller is for only OFP11 and OFP12 sc.miss_send_len = 128; // The default of OpenFlow Spec return ofputil_encode_get_config_reply(&oh, &sc); }
struct ofpbuf * error_msg(enum ofputil_protocol proto) { struct ofp_header oh; memset(&oh, 0, sizeof(oh)); oh.version = ofputil_protocol_to_ofp_version(proto); oh.type = 14; // OFPT_FLOW_MOD oh.length = htons(8); // lenght of ofp_header oh.xid = 0; // OFPERR_OFPBMC_BAD_FIELD means // "Unsupported field in the match." // - type: OFPET_BAD_MATCH = 4 // - code: OFPBMC_BAD_FIELD = 6 return ofperr_encode_reply(OFPERR_OFPBMC_BAD_FIELD, &oh); }
struct ofpbuf * bundle_add(enum ofputil_protocol proto) { struct ofputil_bundle_add_msg msg; struct ofpbuf *fm; struct ofpbuf *add; memset(&msg, 0, sizeof(msg)); msg.bundle_id = 99999999; msg.flags = OFPBF_ATOMIC; fm = flow_mod(proto); clear_xid(fm); msg.msg = fm->data; add = ofputil_encode_bundle_add( ofputil_protocol_to_ofp_version(proto), &msg); ofpbuf_delete(fm); return add; }
struct ofpbuf * echo_request(enum ofputil_protocol proto) { return make_echo_request(ofputil_protocol_to_ofp_version(proto)); }
struct ofpbuf * barrier_request(enum ofputil_protocol proto) { return ofputil_encode_barrier_request( ofputil_protocol_to_ofp_version(proto)); }
struct ofpbuf * table_desc_request(enum ofputil_protocol proto) { return ofputil_encode_table_desc_request( ofputil_protocol_to_ofp_version(proto)); }
struct ofpbuf * group_features_request(enum ofputil_protocol proto) { return ofputil_encode_group_features_request( ofputil_protocol_to_ofp_version(proto)); }