4795
4772
return request;
4776
put_fields_property(struct ofpbuf *reply,
4777
const struct mf_bitmap *fields,
4778
const struct mf_bitmap *masks,
4779
enum ofp13_table_feature_prop_type property,
4780
enum ofp_version version)
4785
start_ofs = start_property(reply, property);
4786
BITMAP_FOR_EACH_1 (field, MFF_N_IDS, fields->bm) {
4787
nx_put_header(reply, field, version,
4788
masks && bitmap_is_set(masks->bm, field));
4790
end_property(reply, start_ofs);
4794
put_table_action_features(struct ofpbuf *reply,
4795
const struct ofputil_table_action_features *taf,
4796
enum ofp13_table_feature_prop_type actions_type,
4797
enum ofp13_table_feature_prop_type set_fields_type,
4798
int miss_offset, enum ofp_version version)
4802
start_ofs = start_property(reply, actions_type + miss_offset);
4803
put_bitmap_properties(reply,
4804
ntohl(ofpact_bitmap_to_openflow(taf->ofpacts,
4806
end_property(reply, start_ofs);
4808
put_fields_property(reply, &taf->set_fields, NULL,
4809
set_fields_type + miss_offset, version);
4813
put_table_instruction_features(
4814
struct ofpbuf *reply, const struct ofputil_table_instruction_features *tif,
4815
int miss_offset, enum ofp_version version)
4820
start_ofs = start_property(reply, OFPTFPT13_INSTRUCTIONS + miss_offset);
4821
put_bitmap_properties(reply,
4822
ntohl(ovsinst_bitmap_to_openflow(tif->instructions,
4824
end_property(reply, start_ofs);
4826
start_ofs = start_property(reply, OFPTFPT13_NEXT_TABLES + miss_offset);
4827
BITMAP_FOR_EACH_1 (table_id, 255, tif->next) {
4828
ofpbuf_put(reply, &table_id, 1);
4830
end_property(reply, start_ofs);
4832
put_table_action_features(reply, &tif->write,
4833
OFPTFPT13_WRITE_ACTIONS,
4834
OFPTFPT13_WRITE_SETFIELD, miss_offset, version);
4835
put_table_action_features(reply, &tif->apply,
4836
OFPTFPT13_APPLY_ACTIONS,
4837
OFPTFPT13_APPLY_SETFIELD, miss_offset, version);
4841
ofputil_append_table_features_reply(const struct ofputil_table_features *tf,
4842
struct ovs_list *replies)
4844
struct ofpbuf *reply = ofpbuf_from_list(list_back(replies));
4845
enum ofp_version version = ofpmp_version(replies);
4846
size_t start_ofs = reply->size;
4847
struct ofp13_table_features *otf;
4849
otf = ofpbuf_put_zeros(reply, sizeof *otf);
4850
otf->table_id = tf->table_id;
4851
ovs_strlcpy(otf->name, tf->name, sizeof otf->name);
4852
otf->metadata_match = tf->metadata_match;
4853
otf->metadata_write = tf->metadata_write;
4854
otf->config = ofputil_table_miss_to_config(tf->miss_config, version);
4855
otf->max_entries = htonl(tf->max_entries);
4857
put_table_instruction_features(reply, &tf->nonmiss, 0, version);
4858
put_table_instruction_features(reply, &tf->miss, 1, version);
4860
put_fields_property(reply, &tf->match, &tf->mask,
4861
OFPTFPT13_MATCH, version);
4862
put_fields_property(reply, &tf->wildcard, NULL,
4863
OFPTFPT13_WILDCARDS, version);
4865
otf = ofpbuf_at_assert(reply, start_ofs, sizeof *otf);
4866
otf->length = htons(reply->size - start_ofs);
4867
ofpmp_postappend(replies, start_ofs);
4798
4870
/* ofputil_table_mod */
4872
/* Given 'config', taken from an OpenFlow 'version' message that specifies
4873
* table configuration (a table mod, table stats, or table features message),
4874
* returns the table miss configuration that it specifies. */
4875
static enum ofputil_table_miss
4876
ofputil_table_miss_from_config(ovs_be32 config_, enum ofp_version version)
4878
uint32_t config = ntohl(config_);
4880
if (version < OFP13_VERSION) {
4881
switch (config & OFPTC11_TABLE_MISS_MASK) {
4882
case OFPTC11_TABLE_MISS_CONTROLLER:
4883
return OFPUTIL_TABLE_MISS_CONTROLLER;
4885
case OFPTC11_TABLE_MISS_CONTINUE:
4886
return OFPUTIL_TABLE_MISS_CONTINUE;
4888
case OFPTC11_TABLE_MISS_DROP:
4889
return OFPUTIL_TABLE_MISS_DROP;
4892
VLOG_WARN_RL(&bad_ofmsg_rl, "bad table miss config %d", config);
4893
return OFPUTIL_TABLE_MISS_CONTROLLER;
4896
return OFPUTIL_TABLE_MISS_DEFAULT;
4900
/* Given a table miss configuration, returns the corresponding OpenFlow table
4901
* configuration for use in an OpenFlow message of the given 'version'. */
4903
ofputil_table_miss_to_config(enum ofputil_table_miss miss,
4904
enum ofp_version version)
4906
if (version < OFP13_VERSION) {
4908
case OFPUTIL_TABLE_MISS_CONTROLLER:
4909
case OFPUTIL_TABLE_MISS_DEFAULT:
4910
return htonl(OFPTC11_TABLE_MISS_CONTROLLER);
4912
case OFPUTIL_TABLE_MISS_CONTINUE:
4913
return htonl(OFPTC11_TABLE_MISS_CONTINUE);
4915
case OFPUTIL_TABLE_MISS_DROP:
4916
return htonl(OFPTC11_TABLE_MISS_DROP);
4800
4926
/* Decodes the OpenFlow "table mod" message in '*oh' into an abstract form in
4801
4927
* '*pm'. Returns 0 if successful, otherwise an OFPERR_* value. */
5026
5156
/* Table stats. */
5158
/* OpenFlow 1.0 and 1.1 don't distinguish between a field that cannot be
5159
* matched and a field that must be wildcarded. This function returns a bitmap
5160
* that contains both kinds of fields. */
5161
static struct mf_bitmap
5162
wild_or_nonmatchable_fields(const struct ofputil_table_features *features)
5164
struct mf_bitmap wc = features->match;
5165
bitmap_not(wc.bm, MFF_N_IDS);
5166
bitmap_or(wc.bm, features->wildcard.bm, MFF_N_IDS);
5170
struct ofp10_wc_map {
5171
enum ofp10_flow_wildcards wc10;
5172
enum mf_field_id mf;
5175
static const struct ofp10_wc_map ofp10_wc_map[] = {
5176
{ OFPFW10_IN_PORT, MFF_IN_PORT },
5177
{ OFPFW10_DL_VLAN, MFF_VLAN_VID },
5178
{ OFPFW10_DL_SRC, MFF_ETH_SRC },
5179
{ OFPFW10_DL_DST, MFF_ETH_DST},
5180
{ OFPFW10_DL_TYPE, MFF_ETH_TYPE },
5181
{ OFPFW10_NW_PROTO, MFF_IP_PROTO },
5182
{ OFPFW10_TP_SRC, MFF_TCP_SRC },
5183
{ OFPFW10_TP_DST, MFF_TCP_DST },
5184
{ OFPFW10_NW_SRC_MASK, MFF_IPV4_SRC },
5185
{ OFPFW10_NW_DST_MASK, MFF_IPV4_DST },
5186
{ OFPFW10_DL_VLAN_PCP, MFF_VLAN_PCP },
5187
{ OFPFW10_NW_TOS, MFF_IP_DSCP },
5191
mf_bitmap_to_of10(const struct mf_bitmap *fields)
5193
const struct ofp10_wc_map *p;
5196
for (p = ofp10_wc_map; p < &ofp10_wc_map[ARRAY_SIZE(ofp10_wc_map)]; p++) {
5197
if (bitmap_is_set(fields->bm, p->mf)) {
5204
static struct mf_bitmap
5205
mf_bitmap_from_of10(ovs_be32 wc10_)
5207
struct mf_bitmap fields = MF_BITMAP_INITIALIZER;
5208
const struct ofp10_wc_map *p;
5209
uint32_t wc10 = ntohl(wc10_);
5211
for (p = ofp10_wc_map; p < &ofp10_wc_map[ARRAY_SIZE(ofp10_wc_map)]; p++) {
5212
if (wc10 & p->wc10) {
5213
bitmap_set1(fields.bm, p->mf);
5029
ofputil_put_ofp10_table_stats(const struct ofp12_table_stats *in,
5220
ofputil_put_ofp10_table_stats(const struct ofputil_table_stats *stats,
5221
const struct ofputil_table_features *features,
5030
5222
struct ofpbuf *buf)
5033
enum ofp10_flow_wildcards wc10;
5034
enum oxm12_ofb_match_fields mf12;
5037
static const struct wc_map wc_map[] = {
5038
{ OFPFW10_IN_PORT, OFPXMT12_OFB_IN_PORT },
5039
{ OFPFW10_DL_VLAN, OFPXMT12_OFB_VLAN_VID },
5040
{ OFPFW10_DL_SRC, OFPXMT12_OFB_ETH_SRC },
5041
{ OFPFW10_DL_DST, OFPXMT12_OFB_ETH_DST},
5042
{ OFPFW10_DL_TYPE, OFPXMT12_OFB_ETH_TYPE },
5043
{ OFPFW10_NW_PROTO, OFPXMT12_OFB_IP_PROTO },
5044
{ OFPFW10_TP_SRC, OFPXMT12_OFB_TCP_SRC },
5045
{ OFPFW10_TP_DST, OFPXMT12_OFB_TCP_DST },
5046
{ OFPFW10_NW_SRC_MASK, OFPXMT12_OFB_IPV4_SRC },
5047
{ OFPFW10_NW_DST_MASK, OFPXMT12_OFB_IPV4_DST },
5048
{ OFPFW10_DL_VLAN_PCP, OFPXMT12_OFB_VLAN_PCP },
5049
{ OFPFW10_NW_TOS, OFPXMT12_OFB_IP_DSCP },
5224
struct mf_bitmap wc = wild_or_nonmatchable_fields(features);
5052
5225
struct ofp10_table_stats *out;
5053
const struct wc_map *p;
5055
5227
out = ofpbuf_put_zeros(buf, sizeof *out);
5056
out->table_id = in->table_id;
5057
ovs_strlcpy(out->name, in->name, sizeof out->name);
5059
for (p = wc_map; p < &wc_map[ARRAY_SIZE(wc_map)]; p++) {
5060
if (in->wildcards & htonll(1ULL << p->mf12)) {
5061
out->wildcards |= htonl(p->wc10);
5064
out->max_entries = in->max_entries;
5065
out->active_count = in->active_count;
5066
put_32aligned_be64(&out->lookup_count, in->lookup_count);
5067
put_32aligned_be64(&out->matched_count, in->matched_count);
5228
out->table_id = features->table_id;
5229
ovs_strlcpy(out->name, features->name, sizeof out->name);
5230
out->wildcards = mf_bitmap_to_of10(&wc);
5231
out->max_entries = htonl(features->max_entries);
5232
out->active_count = htonl(stats->active_count);
5233
put_32aligned_be64(&out->lookup_count, htonll(stats->lookup_count));
5234
put_32aligned_be64(&out->matched_count, htonll(stats->matched_count));
5237
struct ofp11_wc_map {
5238
enum ofp11_flow_match_fields wc11;
5239
enum mf_field_id mf;
5242
static const struct ofp11_wc_map ofp11_wc_map[] = {
5243
{ OFPFMF11_IN_PORT, MFF_IN_PORT },
5244
{ OFPFMF11_DL_VLAN, MFF_VLAN_VID },
5245
{ OFPFMF11_DL_VLAN_PCP, MFF_VLAN_PCP },
5246
{ OFPFMF11_DL_TYPE, MFF_ETH_TYPE },
5247
{ OFPFMF11_NW_TOS, MFF_IP_DSCP },
5248
{ OFPFMF11_NW_PROTO, MFF_IP_PROTO },
5249
{ OFPFMF11_TP_SRC, MFF_TCP_SRC },
5250
{ OFPFMF11_TP_DST, MFF_TCP_DST },
5251
{ OFPFMF11_MPLS_LABEL, MFF_MPLS_LABEL },
5252
{ OFPFMF11_MPLS_TC, MFF_MPLS_TC },
5253
/* I don't know what OFPFMF11_TYPE means. */
5254
{ OFPFMF11_DL_SRC, MFF_ETH_SRC },
5255
{ OFPFMF11_DL_DST, MFF_ETH_DST },
5256
{ OFPFMF11_NW_SRC, MFF_IPV4_SRC },
5257
{ OFPFMF11_NW_DST, MFF_IPV4_DST },
5258
{ OFPFMF11_METADATA, MFF_METADATA },
5070
5261
static ovs_be32
5071
oxm12_to_ofp11_flow_match_fields(ovs_be64 oxm12)
5074
enum ofp11_flow_match_fields fmf11;
5075
enum oxm12_ofb_match_fields mf12;
5078
static const struct map map[] = {
5079
{ OFPFMF11_IN_PORT, OFPXMT12_OFB_IN_PORT },
5080
{ OFPFMF11_DL_VLAN, OFPXMT12_OFB_VLAN_VID },
5081
{ OFPFMF11_DL_VLAN_PCP, OFPXMT12_OFB_VLAN_PCP },
5082
{ OFPFMF11_DL_TYPE, OFPXMT12_OFB_ETH_TYPE },
5083
{ OFPFMF11_NW_TOS, OFPXMT12_OFB_IP_DSCP },
5084
{ OFPFMF11_NW_PROTO, OFPXMT12_OFB_IP_PROTO },
5085
{ OFPFMF11_TP_SRC, OFPXMT12_OFB_TCP_SRC },
5086
{ OFPFMF11_TP_DST, OFPXMT12_OFB_TCP_DST },
5087
{ OFPFMF11_MPLS_LABEL, OFPXMT12_OFB_MPLS_LABEL },
5088
{ OFPFMF11_MPLS_TC, OFPXMT12_OFB_MPLS_TC },
5089
/* I don't know what OFPFMF11_TYPE means. */
5090
{ OFPFMF11_DL_SRC, OFPXMT12_OFB_ETH_SRC },
5091
{ OFPFMF11_DL_DST, OFPXMT12_OFB_ETH_DST },
5092
{ OFPFMF11_NW_SRC, OFPXMT12_OFB_IPV4_SRC },
5093
{ OFPFMF11_NW_DST, OFPXMT12_OFB_IPV4_DST },
5094
{ OFPFMF11_METADATA, OFPXMT12_OFB_METADATA },
5097
const struct map *p;
5101
for (p = map; p < &map[ARRAY_SIZE(map)]; p++) {
5102
if (oxm12 & htonll(1ULL << p->mf12)) {
5106
return htonl(fmf11);
5262
mf_bitmap_to_of11(const struct mf_bitmap *fields)
5264
const struct ofp11_wc_map *p;
5267
for (p = ofp11_wc_map; p < &ofp11_wc_map[ARRAY_SIZE(ofp11_wc_map)]; p++) {
5268
if (bitmap_is_set(fields->bm, p->mf)) {
5275
static struct mf_bitmap
5276
mf_bitmap_from_of11(ovs_be32 wc11_)
5278
struct mf_bitmap fields = MF_BITMAP_INITIALIZER;
5279
const struct ofp11_wc_map *p;
5280
uint32_t wc11 = ntohl(wc11_);
5282
for (p = ofp11_wc_map; p < &ofp11_wc_map[ARRAY_SIZE(ofp11_wc_map)]; p++) {
5283
if (wc11 & p->wc11) {
5284
bitmap_set1(fields.bm, p->mf);
5110
ofputil_put_ofp11_table_stats(const struct ofp12_table_stats *in,
5291
ofputil_put_ofp11_table_stats(const struct ofputil_table_stats *stats,
5292
const struct ofputil_table_features *features,
5111
5293
struct ofpbuf *buf)
5295
struct mf_bitmap wc = wild_or_nonmatchable_fields(features);
5113
5296
struct ofp11_table_stats *out;
5115
5298
out = ofpbuf_put_zeros(buf, sizeof *out);
5116
out->table_id = in->table_id;
5117
ovs_strlcpy(out->name, in->name, sizeof out->name);
5118
out->wildcards = oxm12_to_ofp11_flow_match_fields(in->wildcards);
5119
out->match = oxm12_to_ofp11_flow_match_fields(in->match);
5120
out->instructions = in->instructions;
5121
out->write_actions = in->write_actions;
5122
out->apply_actions = in->apply_actions;
5123
out->config = in->config;
5124
out->max_entries = in->max_entries;
5125
out->active_count = in->active_count;
5126
out->lookup_count = in->lookup_count;
5127
out->matched_count = in->matched_count;
5299
out->table_id = features->table_id;
5300
ovs_strlcpy(out->name, features->name, sizeof out->name);
5301
out->wildcards = mf_bitmap_to_of11(&wc);
5302
out->match = mf_bitmap_to_of11(&features->match);
5303
out->instructions = ovsinst_bitmap_to_openflow(
5304
features->nonmiss.instructions, OFP11_VERSION);
5305
out->write_actions = ofpact_bitmap_to_openflow(
5306
features->nonmiss.write.ofpacts, OFP11_VERSION);
5307
out->apply_actions = ofpact_bitmap_to_openflow(
5308
features->nonmiss.apply.ofpacts, OFP11_VERSION);
5309
out->config = htonl(features->miss_config);
5310
out->max_entries = htonl(features->max_entries);
5311
out->active_count = htonl(stats->active_count);
5312
out->lookup_count = htonll(stats->lookup_count);
5313
out->matched_count = htonll(stats->matched_count);
5131
ofputil_put_ofp12_table_stats(const struct ofp12_table_stats *in,
5317
ofputil_put_ofp12_table_stats(const struct ofputil_table_stats *stats,
5318
const struct ofputil_table_features *features,
5132
5319
struct ofpbuf *buf)
5134
struct ofp12_table_stats *out = ofpbuf_put(buf, in, sizeof *in);
5321
struct ofp12_table_stats *out;
5136
/* Trim off OF1.3-only capabilities. */
5137
out->match &= htonll(OFPXMT12_MASK);
5138
out->wildcards &= htonll(OFPXMT12_MASK);
5139
out->write_setfields &= htonll(OFPXMT12_MASK);
5140
out->apply_setfields &= htonll(OFPXMT12_MASK);
5323
out = ofpbuf_put_zeros(buf, sizeof *out);
5324
out->table_id = features->table_id;
5325
ovs_strlcpy(out->name, features->name, sizeof out->name);
5326
out->match = oxm_bitmap_from_mf_bitmap(&features->match, OFP12_VERSION);
5327
out->wildcards = oxm_bitmap_from_mf_bitmap(&features->wildcard,
5329
out->write_actions = ofpact_bitmap_to_openflow(
5330
features->nonmiss.write.ofpacts, OFP12_VERSION);
5331
out->apply_actions = ofpact_bitmap_to_openflow(
5332
features->nonmiss.apply.ofpacts, OFP12_VERSION);
5333
out->write_setfields = oxm_bitmap_from_mf_bitmap(
5334
&features->nonmiss.write.set_fields, OFP12_VERSION);
5335
out->apply_setfields = oxm_bitmap_from_mf_bitmap(
5336
&features->nonmiss.apply.set_fields, OFP12_VERSION);
5337
out->metadata_match = features->metadata_match;
5338
out->metadata_write = features->metadata_write;
5339
out->instructions = ovsinst_bitmap_to_openflow(
5340
features->nonmiss.instructions, OFP12_VERSION);
5341
out->config = ofputil_table_miss_to_config(features->miss_config,
5343
out->max_entries = htonl(features->max_entries);
5344
out->active_count = htonl(stats->active_count);
5345
out->lookup_count = htonll(stats->lookup_count);
5346
out->matched_count = htonll(stats->matched_count);
5144
ofputil_put_ofp13_table_stats(const struct ofp12_table_stats *in,
5350
ofputil_put_ofp13_table_stats(const struct ofputil_table_stats *stats,
5145
5351
struct ofpbuf *buf)
5147
5353
struct ofp13_table_stats *out;
5149
/* OF 1.3 splits table features off the ofp_table_stats,
5150
* so there is not much here. */
5152
out = ofpbuf_put_uninit(buf, sizeof *out);
5153
out->table_id = in->table_id;
5154
out->active_count = in->active_count;
5155
out->lookup_count = in->lookup_count;
5156
out->matched_count = in->matched_count;
5355
out = ofpbuf_put_zeros(buf, sizeof *out);
5356
out->table_id = stats->table_id;
5357
out->active_count = htonl(stats->active_count);
5358
out->lookup_count = htonll(stats->lookup_count);
5359
out->matched_count = htonll(stats->matched_count);
5159
5362
struct ofpbuf *
5160
ofputil_encode_table_stats_reply(const struct ofp12_table_stats stats[], int n,
5161
const struct ofp_header *request)
5163
struct ofpbuf *reply;
5166
reply = ofpraw_alloc_stats_reply(request, n * sizeof *stats);
5168
for (i = 0; i < n; i++) {
5169
switch ((enum ofp_version) request->version) {
5171
ofputil_put_ofp10_table_stats(&stats[i], reply);
5175
ofputil_put_ofp11_table_stats(&stats[i], reply);
5179
ofputil_put_ofp12_table_stats(&stats[i], reply);
5185
ofputil_put_ofp13_table_stats(&stats[i], reply);
5363
ofputil_encode_table_stats_reply(const struct ofp_header *request)
5365
return ofpraw_alloc_stats_reply(request, 0);
5369
ofputil_append_table_stats_reply(struct ofpbuf *reply,
5370
const struct ofputil_table_stats *stats,
5371
const struct ofputil_table_features *features)
5373
struct ofp_header *oh = reply->header;
5375
ovs_assert(stats->table_id == features->table_id);
5377
switch ((enum ofp_version) oh->version) {
5379
ofputil_put_ofp10_table_stats(stats, features, reply);
5383
ofputil_put_ofp11_table_stats(stats, features, reply);
5387
ofputil_put_ofp12_table_stats(stats, features, reply);
5393
ofputil_put_ofp13_table_stats(stats, reply);
5402
ofputil_decode_ofp10_table_stats(struct ofpbuf *msg,
5403
struct ofputil_table_stats *stats,
5404
struct ofputil_table_features *features)
5406
struct ofp10_table_stats *ots;
5408
ots = ofpbuf_try_pull(msg, sizeof *ots);
5410
return OFPERR_OFPBRC_BAD_LEN;
5413
features->table_id = ots->table_id;
5414
ovs_strlcpy(features->name, ots->name, sizeof features->name);
5415
features->max_entries = ntohl(ots->max_entries);
5416
features->match = features->wildcard = mf_bitmap_from_of10(ots->wildcards);
5418
stats->table_id = ots->table_id;
5419
stats->active_count = ntohl(ots->active_count);
5420
stats->lookup_count = ntohll(get_32aligned_be64(&ots->lookup_count));
5421
stats->matched_count = ntohll(get_32aligned_be64(&ots->matched_count));
5427
ofputil_decode_ofp11_table_stats(struct ofpbuf *msg,
5428
struct ofputil_table_stats *stats,
5429
struct ofputil_table_features *features)
5431
struct ofp11_table_stats *ots;
5433
ots = ofpbuf_try_pull(msg, sizeof *ots);
5435
return OFPERR_OFPBRC_BAD_LEN;
5438
features->table_id = ots->table_id;
5439
ovs_strlcpy(features->name, ots->name, sizeof features->name);
5440
features->max_entries = ntohl(ots->max_entries);
5441
features->nonmiss.instructions = ovsinst_bitmap_from_openflow(
5442
ots->instructions, OFP11_VERSION);
5443
features->nonmiss.write.ofpacts = ofpact_bitmap_from_openflow(
5444
ots->write_actions, OFP11_VERSION);
5445
features->nonmiss.apply.ofpacts = ofpact_bitmap_from_openflow(
5446
ots->write_actions, OFP11_VERSION);
5447
features->miss = features->nonmiss;
5448
features->miss_config = ofputil_table_miss_from_config(ots->config,
5450
features->match = mf_bitmap_from_of11(ots->match);
5451
features->wildcard = mf_bitmap_from_of11(ots->wildcards);
5452
bitmap_or(features->match.bm, features->wildcard.bm, MFF_N_IDS);
5454
stats->table_id = ots->table_id;
5455
stats->active_count = ntohl(ots->active_count);
5456
stats->lookup_count = ntohll(ots->lookup_count);
5457
stats->matched_count = ntohll(ots->matched_count);
5463
ofputil_decode_ofp12_table_stats(struct ofpbuf *msg,
5464
struct ofputil_table_stats *stats,
5465
struct ofputil_table_features *features)
5467
struct ofp12_table_stats *ots;
5469
ots = ofpbuf_try_pull(msg, sizeof *ots);
5471
return OFPERR_OFPBRC_BAD_LEN;
5474
features->table_id = ots->table_id;
5475
ovs_strlcpy(features->name, ots->name, sizeof features->name);
5476
features->metadata_match = ots->metadata_match;
5477
features->metadata_write = ots->metadata_write;
5478
features->miss_config = ofputil_table_miss_from_config(ots->config,
5480
features->max_entries = ntohl(ots->max_entries);
5482
features->nonmiss.instructions = ovsinst_bitmap_from_openflow(
5483
ots->instructions, OFP12_VERSION);
5484
features->nonmiss.write.ofpacts = ofpact_bitmap_from_openflow(
5485
ots->write_actions, OFP12_VERSION);
5486
features->nonmiss.apply.ofpacts = ofpact_bitmap_from_openflow(
5487
ots->apply_actions, OFP12_VERSION);
5488
features->nonmiss.write.set_fields = oxm_bitmap_to_mf_bitmap(
5489
ots->write_setfields, OFP12_VERSION);
5490
features->nonmiss.apply.set_fields = oxm_bitmap_to_mf_bitmap(
5491
ots->apply_setfields, OFP12_VERSION);
5492
features->miss = features->nonmiss;
5494
features->match = oxm_bitmap_to_mf_bitmap(ots->match, OFP12_VERSION);
5495
features->wildcard = oxm_bitmap_to_mf_bitmap(ots->wildcards,
5497
bitmap_or(features->match.bm, features->wildcard.bm, MFF_N_IDS);
5499
stats->table_id = ots->table_id;
5500
stats->active_count = ntohl(ots->active_count);
5501
stats->lookup_count = ntohll(ots->lookup_count);
5502
stats->matched_count = ntohll(ots->matched_count);
5508
ofputil_decode_ofp13_table_stats(struct ofpbuf *msg,
5509
struct ofputil_table_stats *stats,
5510
struct ofputil_table_features *features)
5512
struct ofp13_table_stats *ots;
5514
ots = ofpbuf_try_pull(msg, sizeof *ots);
5516
return OFPERR_OFPBRC_BAD_LEN;
5519
features->table_id = ots->table_id;
5521
stats->table_id = ots->table_id;
5522
stats->active_count = ntohl(ots->active_count);
5523
stats->lookup_count = ntohll(ots->lookup_count);
5524
stats->matched_count = ntohll(ots->matched_count);
5530
ofputil_decode_table_stats_reply(struct ofpbuf *msg,
5531
struct ofputil_table_stats *stats,
5532
struct ofputil_table_features *features)
5534
const struct ofp_header *oh;
5537
ofpraw_pull_assert(msg);
5545
memset(stats, 0, sizeof *stats);
5546
memset(features, 0, sizeof *features);
5548
switch ((enum ofp_version) oh->version) {
5550
return ofputil_decode_ofp10_table_stats(msg, stats, features);
5553
return ofputil_decode_ofp11_table_stats(msg, stats, features);
5556
return ofputil_decode_ofp12_table_stats(msg, stats, features);
5561
return ofputil_decode_ofp13_table_stats(msg, stats, features);
5196
5568
/* ofputil_flow_monitor_request */
5838
6211
case OFP14_VERSION:
5839
6212
case OFP15_VERSION:
5840
return ofpbuf_size(b) ? ofputil_pull_ofp14_port(pp, b) : EOF;
5846
/* ofp-util.def lists the mapping from names to action. */
5847
static const char *const names[OFPUTIL_N_ACTIONS] = {
5849
#define OFPAT10_ACTION(ENUM, STRUCT, NAME) NAME,
5850
#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME,
5851
#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME,
5852
#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME,
5853
#include "ofp-util.def"
5856
/* Returns the 'enum ofputil_action_code' corresponding to 'name' (e.g. if
5857
* 'name' is "output" then the return value is OFPUTIL_OFPAT10_OUTPUT), or -1
5858
* if 'name' is not the name of any action. */
5860
ofputil_action_code_from_name(const char *name)
5862
const char *const *p;
5864
for (p = names; p < &names[ARRAY_SIZE(names)]; p++) {
5865
if (*p && !strcasecmp(name, *p)) {
5872
/* Returns name corresponding to the 'enum ofputil_action_code',
5873
* or "Unkonwn action", if the name is not available. */
5875
ofputil_action_name_from_code(enum ofputil_action_code code)
5877
return code < (int)OFPUTIL_N_ACTIONS && names[code] ? names[code]
5881
enum ofputil_action_code
5882
ofputil_action_code_from_ofp13_action(enum ofp13_action_type type)
5886
#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
5888
return OFPUTIL_##ENUM;
5889
#include "ofp-util.def"
5892
return OFPUTIL_ACTION_INVALID;
5896
/* Appends an action of the type specified by 'code' to 'buf' and returns the
5897
* action. Initializes the parts of 'action' that identify it as having type
5898
* <ENUM> and length 'sizeof *action' and zeros the rest. For actions that
5899
* have variable length, the length used and cleared is that of struct
5902
ofputil_put_action(enum ofputil_action_code code, struct ofpbuf *buf)
5905
case OFPUTIL_ACTION_INVALID:
5906
#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
5907
#include "ofp-util.def"
5910
#define OFPAT10_ACTION(ENUM, STRUCT, NAME) \
5911
case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf);
5912
#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
5913
case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf);
5914
#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
5915
case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf);
5916
#include "ofp-util.def"
5921
#define OFPAT10_ACTION(ENUM, STRUCT, NAME) \
5923
ofputil_init_##ENUM(struct STRUCT *s) \
5925
memset(s, 0, sizeof *s); \
5926
s->type = htons(ENUM); \
5927
s->len = htons(sizeof *s); \
5931
ofputil_put_##ENUM(struct ofpbuf *buf) \
5933
struct STRUCT *s = ofpbuf_put_uninit(buf, sizeof *s); \
5934
ofputil_init_##ENUM(s); \
5937
#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
5938
OFPAT10_ACTION(ENUM, STRUCT, NAME)
5939
#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
5940
OFPAT10_ACTION(ENUM, STRUCT, NAME)
5941
#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
5943
ofputil_init_##ENUM(struct STRUCT *s) \
5945
memset(s, 0, sizeof *s); \
5946
s->type = htons(OFPAT10_VENDOR); \
5947
s->len = htons(sizeof *s); \
5948
s->vendor = htonl(NX_VENDOR_ID); \
5949
s->subtype = htons(ENUM); \
5953
ofputil_put_##ENUM(struct ofpbuf *buf) \
5955
struct STRUCT *s = ofpbuf_put_uninit(buf, sizeof *s); \
5956
ofputil_init_##ENUM(s); \
5959
#include "ofp-util.def"
6213
return b->size ? ofputil_pull_ofp14_port(pp, b) : EOF;
5962
6220
ofputil_normalize_match__(struct match *match, bool may_log)
7293
ofputil_put_ofp11_bucket(const struct ofputil_bucket *bucket,
7294
struct ofpbuf *openflow, enum ofp_version ofp_version)
7296
struct ofp11_bucket *ob;
7299
start = openflow->size;
7300
ofpbuf_put_zeros(openflow, sizeof *ob);
7301
ofpacts_put_openflow_actions(bucket->ofpacts, bucket->ofpacts_len,
7302
openflow, ofp_version);
7303
ob = ofpbuf_at_assert(openflow, start, sizeof *ob);
7304
ob->len = htons(openflow->size - start);
7305
ob->weight = htons(bucket->weight);
7306
ob->watch_port = ofputil_port_to_ofp11(bucket->watch_port);
7307
ob->watch_group = htonl(bucket->watch_group);
7311
ofputil_put_ofp15_group_bucket_prop_weight(ovs_be16 weight,
7312
struct ofpbuf *openflow)
7315
struct ofp15_group_bucket_prop_weight *prop;
7317
start_ofs = start_property(openflow, OFPGBPT15_WEIGHT);
7318
ofpbuf_put_zeros(openflow, sizeof *prop - sizeof(struct ofp_prop_header));
7319
prop = ofpbuf_at_assert(openflow, start_ofs, sizeof *prop);
7320
prop->weight = weight;
7321
end_property(openflow, start_ofs);
7325
ofputil_put_ofp15_group_bucket_prop_watch(ovs_be32 watch, uint16_t type,
7326
struct ofpbuf *openflow)
7329
struct ofp15_group_bucket_prop_watch *prop;
7331
start_ofs = start_property(openflow, type);
7332
ofpbuf_put_zeros(openflow, sizeof *prop - sizeof(struct ofp_prop_header));
7333
prop = ofpbuf_at_assert(openflow, start_ofs, sizeof *prop);
7334
prop->watch = watch;
7335
end_property(openflow, start_ofs);
7339
ofputil_put_ofp15_bucket(const struct ofputil_bucket *bucket,
7340
uint32_t bucket_id, enum ofp11_group_type group_type,
7341
struct ofpbuf *openflow, enum ofp_version ofp_version)
7343
struct ofp15_bucket *ob;
7344
size_t start, actions_start, actions_len;
7346
start = openflow->size;
7347
ofpbuf_put_zeros(openflow, sizeof *ob);
7349
actions_start = openflow->size;
7350
ofpacts_put_openflow_actions(bucket->ofpacts, bucket->ofpacts_len,
7351
openflow, ofp_version);
7352
actions_len = openflow->size - actions_start;
7354
if (group_type == OFPGT11_SELECT) {
7355
ofputil_put_ofp15_group_bucket_prop_weight(htons(bucket->weight),
7358
if (bucket->watch_port != OFPP_ANY) {
7359
ovs_be32 port = ofputil_port_to_ofp11(bucket->watch_port);
7360
ofputil_put_ofp15_group_bucket_prop_watch(port,
7361
OFPGBPT15_WATCH_PORT,
7364
if (bucket->watch_group != OFPG_ANY) {
7365
ovs_be32 group = htonl(bucket->watch_group);
7366
ofputil_put_ofp15_group_bucket_prop_watch(group,
7367
OFPGBPT15_WATCH_GROUP,
7371
ob = ofpbuf_at_assert(openflow, start, sizeof *ob);
7372
ob->len = htons(openflow->size - start);
7373
ob->action_array_len = htons(actions_len);
7374
ob->bucket_id = htonl(bucket_id);
7378
ofputil_put_group_prop_ntr_selection_method(enum ofp_version ofp_version,
7379
const struct ofputil_group_props *gp,
7380
struct ofpbuf *openflow)
7382
struct ntr_group_prop_selection_method *prop;
7385
start = openflow->size;
7386
ofpbuf_put_zeros(openflow, sizeof *prop);
7387
oxm_put_field_array(openflow, &gp->fields, ofp_version);
7388
prop = ofpbuf_at_assert(openflow, start, sizeof *prop);
7389
prop->type = htons(OFPGPT15_EXPERIMENTER);
7390
prop->experimenter = htonl(NTR_VENDOR_ID);
7391
prop->exp_type = htonl(NTRT_SELECTION_METHOD);
7392
strcpy(prop->selection_method, gp->selection_method);
7393
prop->selection_method_param = htonll(gp->selection_method_param);
7394
end_property(openflow, start);
7398
ofputil_append_ofp11_group_desc_reply(const struct ofputil_group_desc *gds,
7399
const struct ovs_list *buckets,
7400
struct ovs_list *replies,
7401
enum ofp_version version)
7403
struct ofpbuf *reply = ofpbuf_from_list(list_back(replies));
7404
struct ofp11_group_desc_stats *ogds;
7405
struct ofputil_bucket *bucket;
7408
start_ogds = reply->size;
7409
ofpbuf_put_zeros(reply, sizeof *ogds);
7410
LIST_FOR_EACH (bucket, list_node, buckets) {
7411
ofputil_put_ofp11_bucket(bucket, reply, version);
7413
ogds = ofpbuf_at_assert(reply, start_ogds, sizeof *ogds);
7414
ogds->length = htons(reply->size - start_ogds);
7415
ogds->type = gds->type;
7416
ogds->group_id = htonl(gds->group_id);
7418
ofpmp_postappend(replies, start_ogds);
7422
ofputil_append_ofp15_group_desc_reply(const struct ofputil_group_desc *gds,
7423
const struct ovs_list *buckets,
7424
struct ovs_list *replies,
7425
enum ofp_version version)
7427
struct ofpbuf *reply = ofpbuf_from_list(list_back(replies));
7428
struct ofp15_group_desc_stats *ogds;
7429
struct ofputil_bucket *bucket;
7430
size_t start_ogds, start_buckets;
7432
start_ogds = reply->size;
7433
ofpbuf_put_zeros(reply, sizeof *ogds);
7434
start_buckets = reply->size;
7435
LIST_FOR_EACH (bucket, list_node, buckets) {
7436
ofputil_put_ofp15_bucket(bucket, bucket->bucket_id,
7437
gds->type, reply, version);
7439
ogds = ofpbuf_at_assert(reply, start_ogds, sizeof *ogds);
7440
ogds->length = htons(reply->size - start_ogds);
7441
ogds->type = gds->type;
7442
ogds->group_id = htonl(gds->group_id);
7443
ogds->bucket_list_len = htons(reply->size - start_buckets);
7445
/* Add group properties */
7446
if (gds->props.selection_method[0]) {
7447
ofputil_put_group_prop_ntr_selection_method(version, &gds->props,
7451
ofpmp_postappend(replies, start_ogds);
6933
7454
/* Appends a group stats reply that contains the data in 'gds' to those already
6934
7455
* present in the list of ofpbufs in 'replies'. 'replies' should have been
6935
7456
* initialized with ofpmp_init(). */
6937
7458
ofputil_append_group_desc_reply(const struct ofputil_group_desc *gds,
6938
struct list *buckets,
6939
struct list *replies)
7459
const struct ovs_list *buckets,
7460
struct ovs_list *replies)
6941
struct ofpbuf *reply = ofpbuf_from_list(list_back(replies));
6942
7462
enum ofp_version version = ofpmp_version(replies);
6943
struct ofp11_group_desc_stats *ogds;
6944
struct ofputil_bucket *bucket;
6947
start_ogds = ofpbuf_size(reply);
6948
ofpbuf_put_zeros(reply, sizeof *ogds);
6949
LIST_FOR_EACH (bucket, list_node, buckets) {
6950
struct ofp11_bucket *ob;
6953
start_ob = ofpbuf_size(reply);
6954
ofpbuf_put_zeros(reply, sizeof *ob);
6955
ofpacts_put_openflow_actions(bucket->ofpacts, bucket->ofpacts_len,
6957
ob = ofpbuf_at_assert(reply, start_ob, sizeof *ob);
6958
ob->len = htons(ofpbuf_size(reply) - start_ob);
6959
ob->weight = htons(bucket->weight);
6960
ob->watch_port = ofputil_port_to_ofp11(bucket->watch_port);
6961
ob->watch_group = htonl(bucket->watch_group);
7470
ofputil_append_ofp11_group_desc_reply(gds, buckets, replies, version);
7474
ofputil_append_ofp15_group_desc_reply(gds, buckets, replies, version);
6963
ogds = ofpbuf_at_assert(reply, start_ogds, sizeof *ogds);
6964
ogds->length = htons(ofpbuf_size(reply) - start_ogds);
6965
ogds->type = gds->type;
6966
ogds->group_id = htonl(gds->group_id);
6968
ofpmp_postappend(replies, start_ogds);
6971
7483
static enum ofperr
6972
ofputil_pull_buckets(struct ofpbuf *msg, size_t buckets_length,
6973
enum ofp_version version, struct list *buckets)
7484
ofputil_pull_ofp11_buckets(struct ofpbuf *msg, size_t buckets_length,
7485
enum ofp_version version, struct ovs_list *buckets)
6975
7487
struct ofp11_bucket *ob;
7488
uint32_t bucket_id = 0;
6977
7490
list_init(buckets);
6978
7491
while (buckets_length > 0) {
7021
7534
return OFPERR_OFPGMFC_BAD_WATCH;
7023
7536
bucket->watch_group = ntohl(ob->watch_group);
7024
bucket->ofpacts = ofpbuf_steal_data(&ofpacts);
7025
bucket->ofpacts_len = ofpbuf_size(&ofpacts);
7026
list_push_back(buckets, &bucket->list_node);
7537
bucket->bucket_id = bucket_id++;
7539
bucket->ofpacts = ofpbuf_steal_data(&ofpacts);
7540
bucket->ofpacts_len = ofpacts.size;
7541
list_push_back(buckets, &bucket->list_node);
7548
parse_ofp15_group_bucket_prop_weight(const struct ofpbuf *payload,
7551
struct ofp15_group_bucket_prop_weight *prop = payload->data;
7553
if (payload->size != sizeof *prop) {
7554
log_property(false, "OpenFlow bucket weight property length "
7555
"%u is not valid", payload->size);
7556
return OFPERR_OFPBPC_BAD_LEN;
7559
*weight = prop->weight;
7565
parse_ofp15_group_bucket_prop_watch(const struct ofpbuf *payload,
7568
struct ofp15_group_bucket_prop_watch *prop = payload->data;
7570
if (payload->size != sizeof *prop) {
7571
log_property(false, "OpenFlow bucket watch port or group "
7572
"property length %u is not valid", payload->size);
7573
return OFPERR_OFPBPC_BAD_LEN;
7576
*watch = prop->watch;
7582
ofputil_pull_ofp15_buckets(struct ofpbuf *msg, size_t buckets_length,
7583
enum ofp_version version, uint8_t group_type,
7584
struct ovs_list *buckets)
7586
struct ofp15_bucket *ob;
7589
while (buckets_length > 0) {
7590
struct ofputil_bucket *bucket = NULL;
7591
struct ofpbuf ofpacts;
7592
enum ofperr err = OFPERR_OFPGMFC_BAD_BUCKET;
7593
struct ofpbuf properties;
7594
size_t ob_len, actions_len, properties_len;
7595
ovs_be32 watch_port = ofputil_port_to_ofp11(OFPP_ANY);
7596
ovs_be32 watch_group = htonl(OFPG_ANY);
7597
ovs_be16 weight = htons(group_type == OFPGT11_SELECT ? 1 : 0);
7599
ofpbuf_init(&ofpacts, 0);
7601
ob = ofpbuf_try_pull(msg, sizeof *ob);
7603
VLOG_WARN_RL(&bad_ofmsg_rl, "buckets end with %"PRIuSIZE
7604
" leftover bytes", buckets_length);
7608
ob_len = ntohs(ob->len);
7609
actions_len = ntohs(ob->action_array_len);
7611
if (ob_len < sizeof *ob) {
7612
VLOG_WARN_RL(&bad_ofmsg_rl, "OpenFlow message bucket length "
7613
"%"PRIuSIZE" is not valid", ob_len);
7615
} else if (ob_len > buckets_length) {
7616
VLOG_WARN_RL(&bad_ofmsg_rl, "OpenFlow message bucket length "
7617
"%"PRIuSIZE" exceeds remaining buckets data size %"
7618
PRIuSIZE, ob_len, buckets_length);
7620
} else if (actions_len > ob_len - sizeof *ob) {
7621
VLOG_WARN_RL(&bad_ofmsg_rl, "OpenFlow message bucket actions "
7622
"length %"PRIuSIZE" exceeds remaining bucket "
7623
"data size %"PRIuSIZE, actions_len,
7624
ob_len - sizeof *ob);
7627
buckets_length -= ob_len;
7629
err = ofpacts_pull_openflow_actions(msg, actions_len, version,
7635
properties_len = ob_len - sizeof *ob - actions_len;
7636
ofpbuf_use_const(&properties, ofpbuf_pull(msg, properties_len),
7639
while (properties.size > 0) {
7640
struct ofpbuf payload;
7643
err = ofputil_pull_property(&properties, &payload, &type);
7649
case OFPGBPT15_WEIGHT:
7650
err = parse_ofp15_group_bucket_prop_weight(&payload, &weight);
7653
case OFPGBPT15_WATCH_PORT:
7654
err = parse_ofp15_group_bucket_prop_watch(&payload,
7658
case OFPGBPT15_WATCH_GROUP:
7659
err = parse_ofp15_group_bucket_prop_watch(&payload,
7664
log_property(false, "unknown group bucket property %"PRIu16,
7666
err = OFPERR_OFPBPC_BAD_TYPE;
7675
bucket = xzalloc(sizeof *bucket);
7677
bucket->weight = ntohs(weight);
7678
err = ofputil_port_from_ofp11(watch_port, &bucket->watch_port);
7680
err = OFPERR_OFPGMFC_BAD_WATCH;
7683
bucket->watch_group = ntohl(watch_group);
7684
bucket->bucket_id = ntohl(ob->bucket_id);
7685
if (bucket->bucket_id > OFPG15_BUCKET_MAX) {
7686
VLOG_WARN_RL(&bad_ofmsg_rl, "bucket id (%u) is out of range",
7688
err = OFPERR_OFPGMFC_BAD_BUCKET;
7692
bucket->ofpacts = ofpbuf_steal_data(&ofpacts);
7693
bucket->ofpacts_len = ofpacts.size;
7694
list_push_back(buckets, &bucket->list_node);
7700
ofpbuf_uninit(&ofpacts);
7701
ofputil_bucket_list_destroy(buckets);
7705
if (ofputil_bucket_check_duplicate_id(buckets)) {
7706
VLOG_WARN_RL(&bad_ofmsg_rl, "Duplicate bucket id");
7707
ofputil_bucket_list_destroy(buckets);
7708
return OFPERR_OFPGMFC_BAD_BUCKET;
7715
ofputil_init_group_properties(struct ofputil_group_props *gp)
7717
memset(gp, 0, sizeof *gp);
7721
parse_group_prop_ntr_selection_method(struct ofpbuf *payload,
7722
enum ofp11_group_type group_type,
7723
enum ofp15_group_mod_command group_cmd,
7724
struct ofputil_group_props *gp)
7726
struct ntr_group_prop_selection_method *prop = payload->data;
7727
size_t fields_len, method_len;
7730
switch (group_type) {
7731
case OFPGT11_SELECT:
7734
case OFPGT11_INDIRECT:
7736
log_property(false, "ntr selection method property is only allowed "
7737
"for select groups");
7738
return OFPERR_OFPBPC_BAD_VALUE;
7743
switch (group_cmd) {
7745
case OFPGC15_MODIFY:
7747
case OFPGC15_DELETE:
7748
case OFPGC15_INSERT_BUCKET:
7749
case OFPGC15_REMOVE_BUCKET:
7750
log_property(false, "ntr selection method property is only allowed "
7751
"for add and delete group modifications");
7752
return OFPERR_OFPBPC_BAD_VALUE;
7757
if (payload->size < sizeof *prop) {
7758
log_property(false, "ntr selection method property length "
7759
"%u is not valid", payload->size);
7760
return OFPERR_OFPBPC_BAD_LEN;
7763
method_len = strnlen(prop->selection_method, NTR_MAX_SELECTION_METHOD_LEN);
7765
if (method_len == NTR_MAX_SELECTION_METHOD_LEN) {
7766
log_property(false, "ntr selection method is not null terminated");
7767
return OFPERR_OFPBPC_BAD_VALUE;
7770
if (strcmp("hash", prop->selection_method)) {
7771
log_property(false, "ntr selection method '%s' is not supported",
7772
prop->selection_method);
7773
return OFPERR_OFPBPC_BAD_VALUE;
7776
strcpy(gp->selection_method, prop->selection_method);
7777
gp->selection_method_param = ntohll(prop->selection_method_param);
7779
if (!method_len && gp->selection_method_param) {
7780
log_property(false, "ntr selection method parameter is non-zero but "
7781
"selection method is empty");
7782
return OFPERR_OFPBPC_BAD_VALUE;
7785
ofpbuf_pull(payload, sizeof *prop);
7787
fields_len = ntohs(prop->length) - sizeof *prop;
7788
if (!method_len && fields_len) {
7789
log_property(false, "ntr selection method parameter is zero "
7790
"but fields are provided");
7791
return OFPERR_OFPBPC_BAD_VALUE;
7794
error = oxm_pull_field_array(payload->data, fields_len,
7797
log_property(false, "ntr selection method fields are invalid");
7805
parse_group_prop_ntr(struct ofpbuf *payload, uint32_t exp_type,
7806
enum ofp11_group_type group_type,
7807
enum ofp15_group_mod_command group_cmd,
7808
struct ofputil_group_props *gp)
7813
case NTRT_SELECTION_METHOD:
7814
error = parse_group_prop_ntr_selection_method(payload, group_type,
7819
log_property(false, "unknown group property ntr experimenter type "
7820
"%"PRIu32, exp_type);
7821
error = OFPERR_OFPBPC_BAD_TYPE;
7829
parse_ofp15_group_prop_exp(struct ofpbuf *payload,
7830
enum ofp11_group_type group_type,
7831
enum ofp15_group_mod_command group_cmd,
7832
struct ofputil_group_props *gp)
7834
struct ofp_prop_experimenter *prop = payload->data;
7835
uint16_t experimenter;
7839
if (payload->size < sizeof *prop) {
7840
return OFPERR_OFPBPC_BAD_LEN;
7843
experimenter = ntohl(prop->experimenter);
7844
exp_type = ntohl(prop->exp_type);
7846
switch (experimenter) {
7848
error = parse_group_prop_ntr(payload, exp_type, group_type,
7853
log_property(false, "unknown group property experimenter %"PRIu16,
7855
error = OFPERR_OFPBPC_BAD_EXPERIMENTER;
7863
parse_ofp15_group_properties(struct ofpbuf *msg,
7864
enum ofp11_group_type group_type,
7865
enum ofp15_group_mod_command group_cmd,
7866
struct ofputil_group_props *gp,
7867
size_t properties_len)
7869
struct ofpbuf properties;
7871
ofpbuf_use_const(&properties, ofpbuf_pull(msg, properties_len),
7874
while (properties.size > 0) {
7875
struct ofpbuf payload;
7879
error = ofputil_pull_property(&properties, &payload, &type);
7885
case OFPGPT15_EXPERIMENTER:
7886
error = parse_ofp15_group_prop_exp(&payload, group_type,
7891
log_property(false, "unknown group property %"PRIu16, type);
7892
error = OFPERR_OFPBPC_BAD_TYPE;
7905
ofputil_decode_ofp11_group_desc_reply(struct ofputil_group_desc *gd,
7907
enum ofp_version version)
7909
struct ofp11_group_desc_stats *ogds;
7913
ofpraw_pull_assert(msg);
7920
ogds = ofpbuf_try_pull(msg, sizeof *ogds);
7922
VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST11_GROUP_DESC reply has %"PRIu32" "
7923
"leftover bytes at end", msg->size);
7924
return OFPERR_OFPBRC_BAD_LEN;
7926
gd->type = ogds->type;
7927
gd->group_id = ntohl(ogds->group_id);
7929
length = ntohs(ogds->length);
7930
if (length < sizeof *ogds || length - sizeof *ogds > msg->size) {
7931
VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST11_GROUP_DESC reply claims invalid "
7932
"length %"PRIuSIZE, length);
7933
return OFPERR_OFPBRC_BAD_LEN;
7936
return ofputil_pull_ofp11_buckets(msg, length - sizeof *ogds, version,
7941
ofputil_decode_ofp15_group_desc_reply(struct ofputil_group_desc *gd,
7943
enum ofp_version version)
7945
struct ofp15_group_desc_stats *ogds;
7946
uint16_t length, bucket_list_len;
7950
ofpraw_pull_assert(msg);
7957
ogds = ofpbuf_try_pull(msg, sizeof *ogds);
7959
VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST11_GROUP_DESC reply has %"PRIu32" "
7960
"leftover bytes at end", msg->size);
7961
return OFPERR_OFPBRC_BAD_LEN;
7963
gd->type = ogds->type;
7964
gd->group_id = ntohl(ogds->group_id);
7966
length = ntohs(ogds->length);
7967
if (length < sizeof *ogds || length - sizeof *ogds > msg->size) {
7968
VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST11_GROUP_DESC reply claims invalid "
7969
"length %u", length);
7970
return OFPERR_OFPBRC_BAD_LEN;
7973
bucket_list_len = ntohs(ogds->bucket_list_len);
7974
if (length < bucket_list_len + sizeof *ogds) {
7975
VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST11_GROUP_DESC reply claims invalid "
7976
"bucket list length %u", bucket_list_len);
7977
return OFPERR_OFPBRC_BAD_LEN;
7979
error = ofputil_pull_ofp15_buckets(msg, bucket_list_len, version, gd->type,
7985
/* By definition group desc messages don't have a group mod command.
7986
* However, parse_group_prop_ntr_selection_method() checks to make sure
7987
* that the command is OFPGC15_ADD or OFPGC15_DELETE to guard
7988
* against group mod messages with other commands supplying
7989
* a NTR selection method group experimenter property.
7990
* Such properties are valid for group desc replies so
7991
* claim that the group mod command is OFPGC15_ADD to
7992
* satisfy the check in parse_group_prop_ntr_selection_method() */
7993
return parse_ofp15_group_properties(msg, gd->type, OFPGC15_ADD, &gd->props,
7032
7997
/* Converts a group description reply in 'msg' into an abstract
7043
8008
ofputil_decode_group_desc_reply(struct ofputil_group_desc *gd,
7044
8009
struct ofpbuf *msg, enum ofp_version version)
7046
struct ofp11_group_desc_stats *ogds;
7050
ofpraw_pull_assert(msg);
7053
if (!ofpbuf_size(msg)) {
7057
ogds = ofpbuf_try_pull(msg, sizeof *ogds);
7059
VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST11_GROUP_DESC reply has %"PRIu32" "
7060
"leftover bytes at end", ofpbuf_size(msg));
7061
return OFPERR_OFPBRC_BAD_LEN;
7063
gd->type = ogds->type;
7064
gd->group_id = ntohl(ogds->group_id);
7066
length = ntohs(ogds->length);
7067
if (length < sizeof *ogds || length - sizeof *ogds > ofpbuf_size(msg)) {
7068
VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST11_GROUP_DESC reply claims invalid "
7069
"length %"PRIuSIZE, length);
7070
return OFPERR_OFPBRC_BAD_LEN;
7073
return ofputil_pull_buckets(msg, length - sizeof *ogds, version,
8011
ofputil_init_group_properties(&gd->props);
8019
return ofputil_decode_ofp11_group_desc_reply(gd, msg, version);
8022
return ofputil_decode_ofp15_group_desc_reply(gd, msg, version);
8031
ofputil_uninit_group_mod(struct ofputil_group_mod *gm)
8033
ofputil_bucket_list_destroy(&gm->buckets);
8036
static struct ofpbuf *
8037
ofputil_encode_ofp11_group_mod(enum ofp_version ofp_version,
8038
const struct ofputil_group_mod *gm)
8041
struct ofp11_group_mod *ogm;
8043
struct ofputil_bucket *bucket;
8045
b = ofpraw_alloc(OFPRAW_OFPT11_GROUP_MOD, ofp_version, 0);
8046
start_ogm = b->size;
8047
ofpbuf_put_zeros(b, sizeof *ogm);
8049
LIST_FOR_EACH (bucket, list_node, &gm->buckets) {
8050
ofputil_put_ofp11_bucket(bucket, b, ofp_version);
8052
ogm = ofpbuf_at_assert(b, start_ogm, sizeof *ogm);
8053
ogm->command = htons(gm->command);
8054
ogm->type = gm->type;
8055
ogm->group_id = htonl(gm->group_id);
8060
static struct ofpbuf *
8061
ofputil_encode_ofp15_group_mod(enum ofp_version ofp_version,
8062
const struct ofputil_group_mod *gm)
8065
struct ofp15_group_mod *ogm;
8067
struct ofputil_bucket *bucket;
8068
struct id_pool *bucket_ids = NULL;
8070
b = ofpraw_alloc(OFPRAW_OFPT15_GROUP_MOD, ofp_version, 0);
8071
start_ogm = b->size;
8072
ofpbuf_put_zeros(b, sizeof *ogm);
8074
LIST_FOR_EACH (bucket, list_node, &gm->buckets) {
8077
/* Generate a bucket id if none was supplied */
8078
if (bucket->bucket_id > OFPG15_BUCKET_MAX) {
8080
const struct ofputil_bucket *bkt;
8082
bucket_ids = id_pool_create(0, OFPG15_BUCKET_MAX + 1);
8084
/* Mark all bucket_ids that are present in gm
8085
* as used in the pool. */
8086
LIST_FOR_EACH_REVERSE (bkt, list_node, &gm->buckets) {
8087
if (bkt == bucket) {
8090
if (bkt->bucket_id <= OFPG15_BUCKET_MAX) {
8091
id_pool_add(bucket_ids, bkt->bucket_id);
8096
if (!id_pool_alloc_id(bucket_ids, &bucket_id)) {
8100
bucket_id = bucket->bucket_id;
8103
ofputil_put_ofp15_bucket(bucket, bucket_id, gm->type, b, ofp_version);
8105
ogm = ofpbuf_at_assert(b, start_ogm, sizeof *ogm);
8106
ogm->command = htons(gm->command);
8107
ogm->type = gm->type;
8108
ogm->group_id = htonl(gm->group_id);
8109
ogm->command_bucket_id = htonl(gm->command_bucket_id);
8110
ogm->bucket_array_len = htons(b->size - start_ogm - sizeof *ogm);
8112
/* Add group properties */
8113
if (gm->props.selection_method[0]) {
8114
ofputil_put_group_prop_ntr_selection_method(ofp_version, &gm->props, b);
8117
id_pool_destroy(bucket_ids);
8122
bad_group_cmd(enum ofp15_group_mod_command cmd)
8124
const char *opt_version;
8125
const char *version;
8126
const char *cmd_str;
8130
case OFPGC15_MODIFY:
8131
case OFPGC15_DELETE:
8136
case OFPGC15_INSERT_BUCKET:
8137
case OFPGC15_REMOVE_BUCKET:
8148
cmd_str = "add-group";
8151
case OFPGC15_MODIFY:
8152
cmd_str = "mod-group";
8155
case OFPGC15_DELETE:
8156
cmd_str = "del-group";
8159
case OFPGC15_INSERT_BUCKET:
8160
cmd_str = "insert-bucket";
8163
case OFPGC15_REMOVE_BUCKET:
8164
cmd_str = "remove-bucket";
8171
ovs_fatal(0, "%s needs OpenFlow %s or later (\'-O OpenFlow%s\')",
8172
cmd_str, version, opt_version);
7077
8176
/* Converts abstract group mod 'gm' into a message for OpenFlow version
7080
8179
ofputil_encode_group_mod(enum ofp_version ofp_version,
7081
8180
const struct ofputil_group_mod *gm)
7084
struct ofp11_group_mod *ogm;
7086
size_t start_bucket;
7087
struct ofputil_bucket *bucket;
7088
struct ofp11_bucket *ob;
7090
8183
switch (ofp_version) {
7091
case OFP10_VERSION: {
7092
if (gm->command == OFPGC11_ADD) {
7093
ovs_fatal(0, "add-group needs OpenFlow 1.1 or later "
7094
"(\'-O OpenFlow11\')");
7095
} else if (gm->command == OFPGC11_MODIFY) {
7096
ovs_fatal(0, "mod-group needs OpenFlow 1.1 or later "
7097
"(\'-O OpenFlow11\')");
7099
ovs_fatal(0, "del-groups needs OpenFlow 1.1 or later "
7100
"(\'-O OpenFlow11\')");
8185
bad_group_cmd(gm->command);
7104
8187
case OFP11_VERSION:
7105
8188
case OFP12_VERSION:
7106
8189
case OFP13_VERSION:
7107
8190
case OFP14_VERSION:
8191
if (gm->command > OFPGC11_DELETE) {
8192
bad_group_cmd(gm->command);
8194
return ofputil_encode_ofp11_group_mod(ofp_version, gm);
7108
8196
case OFP15_VERSION:
7109
b = ofpraw_alloc(OFPRAW_OFPT11_GROUP_MOD, ofp_version, 0);
7110
start_ogm = ofpbuf_size(b);
7111
ofpbuf_put_zeros(b, sizeof *ogm);
7113
LIST_FOR_EACH (bucket, list_node, &gm->buckets) {
7114
start_bucket = ofpbuf_size(b);
7115
ofpbuf_put_zeros(b, sizeof *ob);
7116
if (bucket->ofpacts && bucket->ofpacts_len) {
7117
ofpacts_put_openflow_actions(bucket->ofpacts,
7118
bucket->ofpacts_len, b,
7121
ob = ofpbuf_at_assert(b, start_bucket, sizeof *ob);
7122
ob->len = htons(ofpbuf_size(b) - start_bucket);;
7123
ob->weight = htons(bucket->weight);
7124
ob->watch_port = ofputil_port_to_ofp11(bucket->watch_port);
7125
ob->watch_group = htonl(bucket->watch_group);
7127
ogm = ofpbuf_at_assert(b, start_ogm, sizeof *ogm);
7128
ogm->command = htons(gm->command);
7129
ogm->type = gm->type;
7130
ogm->group_id = htonl(gm->group_id);
8197
return ofputil_encode_ofp15_group_mod(ofp_version, gm);
7135
8200
OVS_NOT_REACHED();
8205
ofputil_pull_ofp11_group_mod(struct ofpbuf *msg, enum ofp_version ofp_version,
8206
struct ofputil_group_mod *gm)
8208
const struct ofp11_group_mod *ogm;
8211
ogm = ofpbuf_pull(msg, sizeof *ogm);
8212
gm->command = ntohs(ogm->command);
8213
gm->type = ogm->type;
8214
gm->group_id = ntohl(ogm->group_id);
8215
gm->command_bucket_id = OFPG15_BUCKET_ALL;
8217
error = ofputil_pull_ofp11_buckets(msg, msg->size, ofp_version,
8220
/* OF1.3.5+ prescribes an error when an OFPGC_DELETE includes buckets. */
8222
&& ofp_version >= OFP13_VERSION
8223
&& gm->command == OFPGC11_DELETE
8224
&& !list_is_empty(&gm->buckets)) {
8225
error = OFPERR_OFPGMFC_INVALID_GROUP;
8232
ofputil_pull_ofp15_group_mod(struct ofpbuf *msg, enum ofp_version ofp_version,
8233
struct ofputil_group_mod *gm)
8235
const struct ofp15_group_mod *ogm;
8236
uint16_t bucket_list_len;
8237
enum ofperr error = OFPERR_OFPGMFC_BAD_BUCKET;
8239
ogm = ofpbuf_pull(msg, sizeof *ogm);
8240
gm->command = ntohs(ogm->command);
8241
gm->type = ogm->type;
8242
gm->group_id = ntohl(ogm->group_id);
8244
gm->command_bucket_id = ntohl(ogm->command_bucket_id);
8245
switch (gm->command) {
8246
case OFPGC15_REMOVE_BUCKET:
8247
if (gm->command_bucket_id == OFPG15_BUCKET_ALL) {
8251
case OFPGC15_INSERT_BUCKET:
8252
if (gm->command_bucket_id <= OFPG15_BUCKET_MAX ||
8253
gm->command_bucket_id == OFPG15_BUCKET_FIRST
8254
|| gm->command_bucket_id == OFPG15_BUCKET_LAST) {
8260
case OFPGC11_MODIFY:
8261
case OFPGC11_DELETE:
8263
if (gm->command_bucket_id == OFPG15_BUCKET_ALL) {
8269
VLOG_WARN_RL(&bad_ofmsg_rl,
8270
"group command bucket id (%u) is out of range",
8271
gm->command_bucket_id);
8272
return OFPERR_OFPGMFC_BAD_BUCKET;
8275
bucket_list_len = ntohs(ogm->bucket_array_len);
8276
error = ofputil_pull_ofp15_buckets(msg, bucket_list_len, ofp_version,
8277
gm->type, &gm->buckets);
8282
return parse_ofp15_group_properties(msg, gm->type, gm->command, &gm->props,
7141
8286
/* Converts OpenFlow group mod message 'oh' into an abstract group mod in