@@ -221,7 +221,8 @@ struct ofp13_table_features {
ovs_be16 length; /* Length is padded to 64 bits. */
uint8_t table_id; /* Identifier of table. Lower numbered tables
are consulted first. */
- uint8_t pad[5]; /* Align to 64-bits. */
+ uint8_t command; /* One of OFPTFC_* (OF1.5+). */
+ ovs_be32 features; /* Bitmap of OFPTFF_* values (OF1.5+). */
char name[OFP_MAX_TABLE_NAME_LEN];
ovs_be64 metadata_match; /* Bits of metadata table can match. */
ovs_be64 metadata_write; /* Bits of metadata table can write. */
@@ -149,4 +149,11 @@ struct ofp15_group_desc_stats {
};
OFP_ASSERT(sizeof(struct ofp15_group_desc_stats) == 16);
+/* Flags of features supported by the table. */
+enum ofp15_table_feature_flag {
+ OFPTFF_INGRESS_TABLE = 1 << 0, /* Can be configured as ingress table. */
+ OFPTFF_EGRESS_TABLE = 1 << 1, /* Can be configured as egress table. */
+ OFPTFF_FIRST_EGRESS = 1 << 4, /* Is the first egress table. */
+};
+
#endif /* openflow/openflow-1.5.h */
@@ -7789,3 +7789,26 @@ pad_ofpat(struct ofpbuf *openflow, size_t start_ofs)
oah->len = htons(openflow->size - start_ofs);
}
+/* If first egress table is set then flow tables used for egress
+ * processing must forbid the use of output action or group action in
+ * write-action instruction and must advertise the same in flow table
+ * features as mentioned in the specification.
+ *
+ * OFPAT_* values, i.e. 0 for OFPACT_OUTPUT and 22 for OFPACT_GROUP is
+ * used for comparison.
+ */
+
+void
+ofpact_put_ofp15_write_actions(uint64_t *ofpacts_bitmap,
+ enum ofp_version version)
+{
+ const struct ofpact_map *x;
+
+ for (x = get_ofpact_map(version); x->ofpat >= 0; x++) {
+ if (x->ofpact == OFPACT_OUTPUT || x->ofpact == OFPACT_GROUP) {
+ continue;
+ } else {
+ *ofpacts_bitmap |= (UINT64_C(1) << x->ofpact);
+ }
+ }
+}
@@ -1013,5 +1013,7 @@ enum ofperr ovs_instruction_type_from_inst_type(
ovs_be32 ovsinst_bitmap_to_openflow(uint32_t ovsinst_bitmap, enum ofp_version);
uint32_t ovsinst_bitmap_from_openflow(ovs_be32 ofpit_bitmap,
enum ofp_version);
-
+void
+ofpact_put_ofp15_write_actions(uint64_t *ofpacts_bitmap,
+ enum ofp_version version);
#endif /* ofp-actions.h */
@@ -374,7 +374,7 @@ enum ofpraw {
/* OFPST 1.3+ (11): struct ofp13_meter_features. */
OFPRAW_OFPST13_METER_FEATURES_REPLY,
- /* OFPST 1.3+ (12): void. */
+ /* OFPST 1.3+ (12): struct ofp13_table_features[]. */
OFPRAW_OFPST13_TABLE_FEATURES_REQUEST,
/* OFPST 1.3+ (12): struct ofp13_table_features, uint8_t[8][]. */
@@ -1704,3 +1704,28 @@ parse_ofp_tlv_table_mod_str(struct ofputil_tlv_table_mod *ttm,
return NULL;
}
+
+/* Convert 'table_id' and table feature flag 'OFPTFF_FIRST_EGRESS' into 'tf'
+ * for sending a set_table_features command to a switch.
+ *
+ * Stores a bitmap of the OpenFlow versions that are usable for 'tf' into
+ * '*usable_versions'.
+ *
+ * Returns NULL if successful, otherwise a malloc()'d string describing the
+ * error. The caller is responsible for freeing the returned string. */
+char * OVS_WARN_UNUSED_RESULT
+parse_ofp_table_features(struct ofputil_table_features *tf,
+ const char *table_id,
+ uint32_t *usable_versions)
+{
+ char *error = str_to_u8(table_id, "table_id", &tf->table_id);
+ if (error) {
+ return error;
+ }
+
+ *usable_versions = (1u << OFP15_VERSION);
+
+ tf->features |= OFPTFF_FIRST_EGRESS;
+
+ return NULL;
+}
@@ -36,6 +36,7 @@ struct ofputil_meter_mod;
struct ofputil_table_mod;
struct ofputil_tlv_table_mod;
struct simap;
+struct ofputil_table_features;
enum ofputil_protocol;
char *parse_ofp_str(struct ofputil_flow_mod *, int command, const char *str_,
@@ -52,6 +53,11 @@ char *parse_ofp_table_mod(struct ofputil_table_mod *,
uint32_t *usable_versions)
OVS_WARN_UNUSED_RESULT;
+char *parse_ofp_table_features(struct ofputil_table_features *tf,
+ const char *table_id,
+ uint32_t *usable_versions)
+ OVS_WARN_UNUSED_RESULT;
+
char *parse_ofp_flow_mod_file(const char *file_name, int command,
struct ofputil_flow_mod **fms, size_t *n_fms,
enum ofputil_protocol *usable_protocols)
@@ -2782,6 +2782,12 @@ ofp_print_table_features(struct ds *s,
}
+ if (features->features >= 0) {
+ ds_put_format(s, " features: %s\n",
+ (features->features & OFPTFF_FIRST_EGRESS) ?
+ "first egress table" : "none");
+ }
+
if (features->max_entries) {
ds_put_format(s, " max_entries=%"PRIu32"\n", features->max_entries);
}
@@ -4725,12 +4725,16 @@ ofputil_decode_table_features(struct ofpbuf *msg,
struct ofp13_table_features *otf;
struct ofpbuf properties;
unsigned int len;
+ enum ofpraw raw;
+ enum ofperr error;
- memset(tf, 0, sizeof *tf);
-
- if (!msg->header) {
- ofpraw_pull_assert(msg);
+ error = (msg->header ? ofpraw_decode(&raw, msg->header)
+ : ofpraw_pull(&raw, msg));
+ if (error) {
+ return error;
}
+
+ memset(tf, 0, sizeof *tf);
oh = msg->header;
if (!msg->size) {
@@ -4754,6 +4758,20 @@ ofputil_decode_table_features(struct ofpbuf *msg,
return OFPERR_OFPTFFC_BAD_TABLE;
}
+ if (oh->version >= OFP15_VERSION &&
+ raw == OFPRAW_OFPST13_TABLE_FEATURES_REQUEST) {
+
+ /* Return an error if TABLE_FEATURES_REQUEST attempts to set table 0
+ * as first egress table. */
+ if (tf->table_id == 0) {
+ return OFPERR_OFPTFFC_BAD_TABLE;
+ }
+
+ /* Return an error if TABLE_FEATURES_REQUEST contain properties. */
+ if (properties.size > 0) {
+ return OFPERR_OFPBPC_BAD_LEN;
+ }
+ }
ovs_strlcpy(tf->name, otf->name, OFP_MAX_TABLE_NAME_LEN);
tf->metadata_match = otf->metadata_match;
tf->metadata_write = otf->metadata_write;
@@ -4767,7 +4785,19 @@ ofputil_decode_table_features(struct ofpbuf *msg,
tf->supports_vacancy_events = -1;
}
tf->max_entries = ntohl(otf->max_entries);
-
+ if (oh->version >= OFP15_VERSION) {
+ /* Return an error if any flag other than OFPTFF_FIRST_EGRESS is set.
+ */
+ uint32_t features = ntohl(otf->features);
+ if ((features & OFPTFF_FIRST_EGRESS) != 0) {
+ tf->features |= OFPTFF_FIRST_EGRESS;
+ } else if ((features & OFPTFF_INGRESS_TABLE) != 0 ||
+ (features & OFPTFF_EGRESS_TABLE) != 0 ) {
+ return OFPERR_OFPBFC_BAD_FLAGS;
+ }
+ } else {
+ tf->features = -1;
+ }
while (properties.size > 0) {
struct ofpbuf payload;
enum ofperr error;
@@ -4869,7 +4899,8 @@ ofputil_decode_table_features(struct ofpbuf *msg,
/* Encodes and returns a request to obtain the table features of a switch.
* The message is encoded for OpenFlow version 'ofp_version'. */
struct ofpbuf *
-ofputil_encode_table_features_request(enum ofp_version ofp_version)
+ofputil_encode_table_features_request(const struct ofputil_table_features *tf,
+ enum ofp_version ofp_version)
{
struct ofpbuf *request = NULL;
@@ -4881,10 +4912,22 @@ ofputil_encode_table_features_request(enum ofp_version ofp_version)
"(\'-O OpenFlow13\')");
case OFP13_VERSION:
case OFP14_VERSION:
- case OFP15_VERSION:
request = ofpraw_alloc(OFPRAW_OFPST13_TABLE_FEATURES_REQUEST,
ofp_version, 0);
break;
+ case OFP15_VERSION: {
+ struct ofp13_table_features *otf;
+
+ request = ofpraw_alloc(OFPRAW_OFPST13_TABLE_FEATURES_REQUEST,
+ ofp_version, 0);
+ if (tf != NULL && (tf->features & OFPTFF_FIRST_EGRESS)) {
+ otf = ofpbuf_put_zeros(request, sizeof *otf);
+ otf->table_id = tf->table_id;
+ otf->features = htonl(tf->features);
+ otf->length = htons(sizeof *otf);
+ }
+ }
+ break;
default:
OVS_NOT_REACHED();
}
@@ -4973,7 +5016,11 @@ ofputil_append_table_features_reply(const struct ofputil_table_features *tf,
}
}
otf->max_entries = htonl(tf->max_entries);
-
+ if (version >= OFP15_VERSION) {
+ if ((tf->features & OFPTFF_FIRST_EGRESS) != 0) {
+ otf->features |= htonl(OFPTFF_FIRST_EGRESS);
+ }
+ }
put_table_instruction_features(reply, &tf->nonmiss, 0, version);
put_table_instruction_features(reply, &tf->miss, 1, version);
@@ -6075,6 +6122,7 @@ ofputil_decode_table_stats_reply(struct ofpbuf *msg,
memset(features, 0, sizeof *features);
features->supports_eviction = -1;
features->supports_vacancy_events = -1;
+ features->features = -1;
switch ((enum ofp_version) oh->version) {
case OFP10_VERSION:
@@ -9812,3 +9860,13 @@ ofputil_async_cfg_default(enum ofp_version version)
.slave[OAM_PORT_STATUS] = OFPPR_BITS,
};
}
+
+uint8_t ofputil_egress_table_id(uint8_t table_id)
+{
+ static uint8_t egress_table_id = 0;
+
+ if (table_id > 0) {
+ egress_table_id = table_id;
+ }
+ return egress_table_id;
+}
@@ -767,6 +767,15 @@ struct ofputil_table_features {
int supports_eviction; /* OF1.4+ only. */
int supports_vacancy_events; /* OF1.4+ only. */
+ /* The features field is a bitmap of OFPTFF_* values that defines how the
+ * flow table can be used and what are its basic features.
+ *
+ * 'features' is relevant only for Openflow 1.5 and later only. For 1.5,
+ * it will be OFPTFF_FIRST_EGRESS if first egress table is set, otherwise
+ * 0. For other versions, they are decoded as -1 and ignored for encoding.
+ */
+ int features; /* OF1.5+ only. */
+
/* Table features related to instructions. There are two instances:
*
* - 'miss' reports features available in the table miss flow.
@@ -823,7 +832,9 @@ int ofputil_decode_table_desc(struct ofpbuf *,
struct ofputil_table_desc *,
enum ofp_version);
-struct ofpbuf *ofputil_encode_table_features_request(enum ofp_version);
+struct ofpbuf *
+ofputil_encode_table_features_request(const struct ofputil_table_features *,
+ enum ofp_version);
struct ofpbuf *ofputil_encode_table_desc_request(enum ofp_version);
@@ -1356,4 +1367,6 @@ enum ofperr ofputil_decode_requestforward(const struct ofp_header *,
struct ofputil_requestforward *);
void ofputil_destroy_requestforward(struct ofputil_requestforward *);
+uint8_t ofputil_egress_table_id(uint8_t table_id);
+
#endif /* ofp-util.h */
@@ -95,6 +95,7 @@ struct ofproto {
int n_tables;
cls_version_t tables_version; /* Controls which rules are visible to
* table lookups. */
+ uint8_t first_egress_table_id; /* Contains first egress table id. */
/* Rules indexed on their cookie values, in all flow tables. */
struct hindex cookies OVS_GUARDED_BY(ofproto_mutex);
@@ -267,6 +268,10 @@ struct oftable {
atomic_ulong n_matched;
atomic_ulong n_missed;
+
+ /* The features field is a bitmap that defines how the flow table can be
+ * used and what are its basic features. */
+ enum ofp15_table_feature_flag features;
};
/* Assigns TABLE to each oftable, in turn, in OFPROTO.
@@ -3118,7 +3118,8 @@ handle_echo_request(struct ofconn *ofconn, const struct ofp_header *oh)
static void
query_tables(struct ofproto *ofproto,
struct ofputil_table_features **featuresp,
- struct ofputil_table_stats **statsp)
+ struct ofputil_table_stats **statsp,
+ enum ofp_version version)
{
struct mf_bitmap rw_fields = oxm_writable_fields();
struct mf_bitmap match = oxm_matchable_fields();
@@ -3150,7 +3151,12 @@ query_tables(struct ofproto *ofproto,
if (!more_tables) {
f->nonmiss.instructions &= ~(1u << OVSINST_OFPIT11_GOTO_TABLE);
}
- f->nonmiss.write.ofpacts = (UINT64_C(1) << N_OFPACTS) - 1;
+ if (version >= OFP15_VERSION && ofputil_egress_table_id(0) &&
+ f->table_id >= ofputil_egress_table_id(0)) {
+ ofpact_put_ofp15_write_actions(&f->nonmiss.write.ofpacts, version);
+ } else {
+ f->nonmiss.write.ofpacts = (UINT64_C(1) << N_OFPACTS) - 1;
+ }
f->nonmiss.write.set_fields = rw_fields;
f->nonmiss.apply = f->nonmiss.write;
f->miss = f->nonmiss;
@@ -3158,6 +3164,9 @@ query_tables(struct ofproto *ofproto,
f->match = match;
f->mask = mask;
f->wildcard = match;
+ if (ofproto->tables[i].features & OFPTFF_FIRST_EGRESS) {
+ f->features |= OFPTFF_FIRST_EGRESS;
+ }
}
if (statsp) {
@@ -3194,14 +3203,15 @@ query_tables(struct ofproto *ofproto,
static void
query_switch_features(struct ofproto *ofproto,
- bool *arp_match_ip, uint64_t *ofpacts)
+ bool *arp_match_ip, uint64_t *ofpacts,
+ enum ofp_version version)
{
struct ofputil_table_features *features, *f;
*arp_match_ip = false;
*ofpacts = 0;
- query_tables(ofproto, &features, NULL);
+ query_tables(ofproto, &features, NULL, version);
for (f = features; f < &features[ofproto->n_tables]; f++) {
*ofpacts |= f->nonmiss.apply.ofpacts | f->miss.apply.ofpacts;
if (bitmap_is_set(f->match.bm, MFF_ARP_SPA) ||
@@ -3224,7 +3234,8 @@ handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh)
bool arp_match_ip;
struct ofpbuf *b;
- query_switch_features(ofproto, &arp_match_ip, &features.ofpacts);
+ query_switch_features(ofproto, &arp_match_ip, &features.ofpacts,
+ oh->version);
features.datapath_id = ofproto->datapath_id;
features.n_buffers = pktbuf_capacity();
@@ -3531,7 +3542,7 @@ handle_table_stats_request(struct ofconn *ofconn,
struct ofpbuf *reply;
size_t i;
- query_tables(ofproto, &features, &stats);
+ query_tables(ofproto, &features, &stats, request->version);
reply = ofputil_encode_table_stats_reply(request);
for (i = 0; i < ofproto->n_tables; i++) {
@@ -3555,15 +3566,41 @@ handle_table_features_request(struct ofconn *ofconn,
struct ofputil_table_features *features;
struct ovs_list replies;
struct ofpbuf msg;
+ enum ofperr error = 0;
size_t i;
ofpbuf_use_const(&msg, request, ntohs(request->length));
ofpraw_pull_assert(&msg);
- if (msg.size || ofpmp_more(request)) {
- return OFPERR_OFPTFFC_EPERM;
+
+ if (request->version < OFP15_VERSION) {
+ if (msg.size || ofpmp_more(request)) {
+ return OFPERR_OFPTFFC_EPERM;
+ }
+ } else {
+ if (msg.size) {
+ struct ofputil_table_features tf;
+ error = ofputil_decode_table_features(&msg, &tf, false);
+ if (error) {
+ return error;
+ }
+ if ((tf.features & OFPTFF_FIRST_EGRESS) != 0) {
+ for (i = 0; i < ofproto->n_tables; i++) {
+ if (ofproto->tables[i].features & OFPTFF_FIRST_EGRESS) {
+ ofproto->tables[i].features &= ~OFPTFF_FIRST_EGRESS;
+ break;
+ }
+ }
+ ovs_mutex_lock(&ofproto_mutex);
+ ofproto->tables[tf.table_id].features |= OFPTFF_FIRST_EGRESS;
+ ofproto->first_egress_table_id = tf.table_id;
+ ofputil_egress_table_id(tf.table_id);
+ ovs_mutex_unlock(&ofproto_mutex);
+ }
+ return 0;
+ }
}
- query_tables(ofproto, &features, NULL);
+ query_tables(ofproto, &features, NULL, request->version);
ofpmp_init(&replies, request);
for (i = 0; i < ofproto->n_tables; i++) {
@@ -2475,6 +2475,228 @@ f5 f6 f7 f8 f9 fa fb fc fd 00 00 00 00 00 00 00 \
])
AT_CLEANUP
+AT_SETUP([OFPST_TABLE_FEATURES request - OF1.5])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "\
+06 13 09 40 00 00 00 d5 00 0c 00 01 00 00 00 00 \
+09 30 00 00 00 00 00 00 74 61 62 6c 65 30 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff \
+ff ff ff ff ff ff ff ff 00 00 00 03 00 0f 42 40 \
+00 00 00 2c 00 01 00 08 00 00 00 00 00 02 00 08 \
+00 00 00 00 00 03 00 08 00 00 00 00 00 04 00 08 \
+00 00 00 00 00 05 00 08 00 00 00 00 00 00 00 00 \
+00 01 00 2c 00 01 00 08 00 00 00 00 00 02 00 08 \
+00 00 00 00 00 03 00 08 00 00 00 00 00 04 00 08 \
+00 00 00 00 00 05 00 08 00 00 00 00 00 00 00 00 \
+00 02 01 01 01 02 03 04 05 06 07 08 09 0a 0b 0c \
+0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c \
+1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c \
+2d 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c \
+3d 3e 3f 40 41 42 43 44 45 46 47 48 49 4a 4b 4c \
+4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 5b 5c \
+5d 5e 5f 60 61 62 63 64 65 66 67 68 69 6a 6b 6c \
+6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 7b 7c \
+7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c \
+8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c \
+9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac \
+ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc \
+bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc \
+cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc \
+dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec \
+ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc \
+fd 00 00 00 00 00 00 00 00 03 01 01 01 02 03 04 \
+05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 \
+15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 \
+25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 \
+35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41 42 43 44 \
+45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 \
+55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61 62 63 64 \
+65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 \
+75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 \
+85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 \
+95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 \
+a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 \
+b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 \
+c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 \
+d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 \
+e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 \
+f5 f6 f7 f8 f9 fa fb fc fd 00 00 00 00 00 00 00 \
+00 04 00 84 00 00 00 08 00 00 00 00 00 0b 00 08 \
+00 00 00 00 00 0c 00 08 00 00 00 00 00 0f 00 08 \
+00 00 00 00 00 10 00 08 00 00 00 00 00 11 00 08 \
+00 00 00 00 00 12 00 08 00 00 00 00 00 13 00 08 \
+00 00 00 00 00 14 00 08 00 00 00 00 00 15 00 08 \
+00 00 00 00 00 16 00 08 00 00 00 00 00 17 00 08 \
+00 00 00 00 00 18 00 08 00 00 00 00 00 19 00 08 \
+00 00 00 00 00 1a 00 08 00 00 00 00 00 1b 00 08 \
+00 00 00 00 00 00 00 00 00 05 00 84 00 00 00 08 \
+00 00 00 00 00 0b 00 08 00 00 00 00 00 0c 00 08 \
+00 00 00 00 00 0f 00 08 00 00 00 00 00 10 00 08 \
+00 00 00 00 00 11 00 08 00 00 00 00 00 12 00 08 \
+00 00 00 00 00 13 00 08 00 00 00 00 00 14 00 08 \
+00 00 00 00 00 15 00 08 00 00 00 00 00 16 00 08 \
+00 00 00 00 00 17 00 08 00 00 00 00 00 18 00 08 \
+00 00 00 00 00 19 00 08 00 00 00 00 00 1a 00 08 \
+00 00 00 00 00 1b 00 08 00 00 00 00 00 00 00 00 \
+00 06 00 84 00 00 00 08 00 00 00 00 00 0b 00 08 \
+00 00 00 00 00 0c 00 08 00 00 00 00 00 0f 00 08 \
+00 00 00 00 00 10 00 08 00 00 00 00 00 11 00 08 \
+00 00 00 00 00 12 00 08 00 00 00 00 00 13 00 08 \
+00 00 00 00 00 14 00 08 00 00 00 00 00 15 00 08 \
+00 00 00 00 00 16 00 08 00 00 00 00 00 17 00 08 \
+00 00 00 00 00 18 00 08 00 00 00 00 00 19 00 08 \
+00 00 00 00 00 1a 00 08 00 00 00 00 00 1b 00 08 \
+00 00 00 00 00 00 00 00 00 07 00 84 00 00 00 08 \
+00 00 00 00 00 0b 00 08 00 00 00 00 00 0c 00 08 \
+00 00 00 00 00 0f 00 08 00 00 00 00 00 10 00 08 \
+00 00 00 00 00 11 00 08 00 00 00 00 00 12 00 08 \
+00 00 00 00 00 13 00 08 00 00 00 00 00 14 00 08 \
+00 00 00 00 00 15 00 08 00 00 00 00 00 16 00 08 \
+00 00 00 00 00 17 00 08 00 00 00 00 00 18 00 08 \
+00 00 00 00 00 19 00 08 00 00 00 00 00 1a 00 08 \
+00 00 00 00 00 1b 00 08 00 00 00 00 00 00 00 00 \
+00 08 00 dc 80 00 4c 08 00 01 3e 04 00 01 40 04 \
+80 00 04 08 00 00 00 02 80 00 00 04 00 01 42 04 \
+00 01 00 04 00 01 02 04 00 01 04 04 00 01 06 04 \
+00 01 08 04 00 01 0a 04 00 01 0c 04 00 01 0e 04 \
+80 00 08 06 80 00 06 06 80 00 0a 02 00 00 08 02 \
+80 00 0c 02 80 00 0e 01 80 00 44 04 80 00 46 01 \
+80 00 48 01 80 00 16 04 80 00 18 04 80 00 34 10 \
+80 00 36 10 80 00 38 04 80 00 14 01 00 00 0a 01 \
+80 00 10 01 80 00 12 01 00 01 3a 01 00 01 34 01 \
+80 00 2a 02 80 00 2c 04 80 00 2e 04 80 00 30 06 \
+80 00 32 06 80 00 1a 02 80 00 1c 02 00 01 44 02 \
+80 00 1e 02 80 00 20 02 80 00 22 02 80 00 24 02 \
+80 00 26 01 80 00 28 01 80 00 3a 01 80 00 3c 01 \
+80 00 3e 10 80 00 40 06 80 00 42 06 00 00 00 00 \
+00 0a 00 dc 80 00 4c 08 00 01 3e 04 00 01 40 04 \
+80 00 04 08 00 00 00 02 80 00 00 04 00 01 42 04 \
+00 01 00 04 00 01 02 04 00 01 04 04 00 01 06 04 \
+00 01 08 04 00 01 0a 04 00 01 0c 04 00 01 0e 04 \
+80 00 08 06 80 00 06 06 80 00 0a 02 00 00 08 02 \
+80 00 0c 02 80 00 0e 01 80 00 44 04 80 00 46 01 \
+80 00 48 01 80 00 16 04 80 00 18 04 80 00 34 10 \
+80 00 36 10 80 00 38 04 80 00 14 01 00 00 0a 01 \
+80 00 10 01 80 00 12 01 00 01 3a 01 00 01 34 01 \
+80 00 2a 02 80 00 2c 04 80 00 2e 04 80 00 30 06 \
+80 00 32 06 80 00 1a 02 80 00 1c 02 00 01 44 02 \
+80 00 1e 02 80 00 20 02 80 00 22 02 80 00 24 02 \
+80 00 26 01 80 00 28 01 80 00 3a 01 80 00 3c 01 \
+80 00 3e 10 80 00 40 06 80 00 42 06 00 00 00 00 \
+00 0c 00 a8 80 00 4c 08 00 01 3e 04 00 01 40 04 \
+80 00 04 08 00 00 00 02 80 00 00 04 00 01 42 04 \
+00 01 00 04 00 01 02 04 00 01 04 04 00 01 06 04 \
+00 01 08 04 00 01 0a 04 00 01 0c 04 00 01 0e 04 \
+80 00 08 06 80 00 06 06 00 00 08 02 80 00 0c 02 \
+80 00 0e 01 80 00 44 04 80 00 46 01 80 00 16 04 \
+80 00 18 04 80 00 34 10 80 00 36 10 00 00 0a 01 \
+80 00 10 01 80 00 12 01 00 01 3a 01 80 00 2a 02 \
+80 00 2c 04 80 00 2e 04 80 00 30 06 80 00 32 06 \
+80 00 1a 02 80 00 1c 02 80 00 1e 02 80 00 20 02 \
+80 00 22 02 80 00 24 02 00 0d 00 a8 80 00 4c 08 \
+00 01 3e 04 00 01 40 04 80 00 04 08 00 00 00 02 \
+80 00 00 04 00 01 42 04 00 01 00 04 00 01 02 04 \
+00 01 04 04 00 01 06 04 00 01 08 04 00 01 0a 04 \
+00 01 0c 04 00 01 0e 04 80 00 08 06 80 00 06 06 \
+00 00 08 02 80 00 0c 02 80 00 0e 01 80 00 44 04 \
+80 00 46 01 80 00 16 04 80 00 18 04 80 00 34 10 \
+80 00 36 10 00 00 0a 01 80 00 10 01 80 00 12 01 \
+00 01 3a 01 80 00 2a 02 80 00 2c 04 80 00 2e 04 \
+80 00 30 06 80 00 32 06 80 00 1a 02 80 00 1c 02 \
+80 00 1e 02 80 00 20 02 80 00 22 02 80 00 24 02 \
+00 0e 00 a8 80 00 4c 08 00 01 3e 04 00 01 40 04 \
+80 00 04 08 00 00 00 02 80 00 00 04 00 01 42 04 \
+00 01 00 04 00 01 02 04 00 01 04 04 00 01 06 04 \
+00 01 08 04 00 01 0a 04 00 01 0c 04 00 01 0e 04 \
+80 00 08 06 80 00 06 06 00 00 08 02 80 00 0c 02 \
+80 00 0e 01 80 00 44 04 80 00 46 01 80 00 16 04 \
+80 00 18 04 80 00 34 10 80 00 36 10 00 00 0a 01 \
+80 00 10 01 80 00 12 01 00 01 3a 01 80 00 2a 02 \
+80 00 2c 04 80 00 2e 04 80 00 30 06 80 00 32 06 \
+80 00 1a 02 80 00 1c 02 80 00 1e 02 80 00 20 02 \
+80 00 22 02 80 00 24 02 00 0f 00 a8 80 00 4c 08 \
+00 01 3e 04 00 01 40 04 80 00 04 08 00 00 00 02 \
+80 00 00 04 00 01 42 04 00 01 00 04 00 01 02 04 \
+00 01 04 04 00 01 06 04 00 01 08 04 00 01 0a 04 \
+00 01 0c 04 00 01 0e 04 80 00 08 06 80 00 06 06 \
+00 00 08 02 80 00 0c 02 80 00 0e 01 80 00 44 04 \
+80 00 46 01 80 00 16 04 80 00 18 04 80 00 34 10 \
+80 00 36 10 00 00 0a 01 80 00 10 01 80 00 12 01 \
+00 01 3a 01 80 00 2a 02 80 00 2c 04 80 00 2e 04 \
+80 00 30 06 80 00 32 06 80 00 1a 02 80 00 1c 02 \
+80 00 1e 02 80 00 20 02 80 00 22 02 80 00 24 02 \
+"], [0], [OFPST_TABLE_FEATURES reply (OF1.5) (xid=0xd5):
+ table 0 ("table0"):
+ metadata: match=0xffffffffffffffff write=0xffffffffffffffff
+ eviction: not supported
+ vacancy events: not supported
+ features: none
+ max_entries=1000000
+ instructions (table miss and others):
+ next tables: 1-253
+ instructions: apply_actions,clear_actions,write_actions,write_metadata,goto_table
+ Write-Actions and Apply-Actions features:
+ actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue
+ supported on Set-Field: tun_id tun_src tun_dst metadata in_port in_port_oxm pkt_mark reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 eth_src eth_dst vlan_tci vlan_vid vlan_pcp mpls_label mpls_tc ip_src ip_dst ipv6_src ipv6_dst nw_tos ip_dscp nw_ecn nw_ttl arp_op arp_spa arp_tpa arp_sha arp_tha tcp_src tcp_dst udp_src udp_dst sctp_src sctp_dst
+ matching:
+ tun_id: exact match or wildcard
+ tun_src: exact match or wildcard
+ tun_dst: exact match or wildcard
+ metadata: exact match or wildcard
+ in_port: exact match or wildcard
+ in_port_oxm: exact match or wildcard
+ pkt_mark: exact match or wildcard
+ reg0: exact match or wildcard
+ reg1: exact match or wildcard
+ reg2: exact match or wildcard
+ reg3: exact match or wildcard
+ reg4: exact match or wildcard
+ reg5: exact match or wildcard
+ reg6: exact match or wildcard
+ reg7: exact match or wildcard
+ eth_src: exact match or wildcard
+ eth_dst: exact match or wildcard
+ eth_type: exact match or wildcard
+ vlan_tci: exact match or wildcard
+ vlan_vid: exact match or wildcard
+ vlan_pcp: exact match or wildcard
+ mpls_label: exact match or wildcard
+ mpls_tc: exact match or wildcard
+ mpls_bos: exact match or wildcard
+ ip_src: exact match or wildcard
+ ip_dst: exact match or wildcard
+ ipv6_src: exact match or wildcard
+ ipv6_dst: exact match or wildcard
+ ipv6_label: exact match or wildcard
+ nw_proto: exact match or wildcard
+ nw_tos: exact match or wildcard
+ ip_dscp: exact match or wildcard
+ nw_ecn: exact match or wildcard
+ nw_ttl: exact match or wildcard
+ ip_frag: exact match or wildcard
+ arp_op: exact match or wildcard
+ arp_spa: exact match or wildcard
+ arp_tpa: exact match or wildcard
+ arp_sha: exact match or wildcard
+ arp_tha: exact match or wildcard
+ tcp_src: exact match or wildcard
+ tcp_dst: exact match or wildcard
+ tcp_flags: exact match or wildcard
+ udp_src: exact match or wildcard
+ udp_dst: exact match or wildcard
+ sctp_src: exact match or wildcard
+ sctp_dst: exact match or wildcard
+ icmp_type: exact match or wildcard
+ icmp_code: exact match or wildcard
+ icmpv6_type: exact match or wildcard
+ icmpv6_code: exact match or wildcard
+ nd_target: exact match or wildcard
+ nd_sll: exact match or wildcard
+ nd_tll: exact match or wildcard
+])
+AT_CLEANUP
+
AT_SETUP([OFPT_BARRIER_REQUEST - OF1.0])
AT_KEYWORDS([ofp-print])
AT_CHECK([ovs-ofctl ofp-print '01 12 00 08 00 00 00 01'], [0], [dnl
@@ -1975,6 +1975,236 @@ AT_CHECK([ovs-ofctl -O OpenFlow13 dump-table-features br0], [0], [expout])
OVS_VSWITCHD_STOP
AT_CLEANUP
+AT_SETUP([ofproto - table features (OpenFlow 1.5)])
+OVS_VSWITCHD_START
+head_table () {
+ printf ' table 0 ("%s"):
+ metadata: match=0xffffffffffffffff write=0xffffffffffffffff
+ eviction: not supported
+ vacancy events: not supported
+ features: none
+ max_entries=1000000
+ instructions (table miss and others):
+ next tables: 1-253
+ instructions: meter,apply_actions,clear_actions,write_actions,write_metadata,goto_table
+ Write-Actions and Apply-Actions features:
+ actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue
+ supported on Set-Field: tun_id tun_src tun_dst tun_ipv6_src tun_ipv6_dst tun_flags tun_gbp_id tun_gbp_flags tun_metadata0 tun_metadata1 tun_metadata2 tun_metadata3 tun_metadata4 tun_metadata5 tun_metadata6 tun_metadata7 tun_metadata8 tun_metadata9 tun_metadata10 tun_metadata11 tun_metadata12 tun_metadata13 tun_metadata14 tun_metadata15 tun_metadata16 tun_metadata17 tun_metadata18 tun_metadata19 tun_metadata20 tun_metadata21 tun_metadata22 tun_metadata23 tun_metadata24 tun_metadata25 tun_metadata26 tun_metadata27 tun_metadata28 tun_metadata29 tun_metadata30 tun_metadata31 tun_metadata32 tun_metadata33 tun_metadata34 tun_metadata35 tun_metadata36 tun_metadata37 tun_metadata38 tun_metadata39 tun_metadata40 tun_metadata41 tun_metadata42 tun_metadata43 tun_metadata44 tun_metadata45 tun_metadata46 tun_metadata47 tun_metadata48 tun_metadata49 tun_metadata50 tun_metadata51 tun_metadata52 tun_metadata53 tun_metadata54 tun_metadata55 tun_metadata56 tun_metadata57 tun_metadata5
8 tun_metadata59 tun_metadata60 tun_metadata61 tun_metadata62 tun_metadata63 metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 xreg0 xreg1 xreg2 xreg3 eth_src eth_dst vlan_tci vlan_vid vlan_pcp mpls_label mpls_tc ip_src ip_dst ipv6_src ipv6_dst ipv6_label nw_tos ip_dscp nw_ecn nw_ttl arp_op arp_spa arp_tpa arp_sha arp_tha tcp_src tcp_dst udp_src udp_dst sctp_src sctp_dst icmp_type icmp_code icmpv6_type icmpv6_code nd_target nd_sll nd_tll
+ matching:
+ dp_hash: arbitrary mask
+ recirc_id: exact match or wildcard
+ conj_id: exact match or wildcard
+ tun_id: arbitrary mask
+ tun_src: arbitrary mask
+ tun_dst: arbitrary mask
+ tun_ipv6_src: arbitrary mask
+ tun_ipv6_dst: arbitrary mask
+ tun_flags: arbitrary mask
+ tun_gbp_id: arbitrary mask
+ tun_gbp_flags: arbitrary mask
+ tun_metadata0: arbitrary mask
+ tun_metadata1: arbitrary mask
+ tun_metadata2: arbitrary mask
+ tun_metadata3: arbitrary mask
+ tun_metadata4: arbitrary mask
+ tun_metadata5: arbitrary mask
+ tun_metadata6: arbitrary mask
+ tun_metadata7: arbitrary mask
+ tun_metadata8: arbitrary mask
+ tun_metadata9: arbitrary mask
+ tun_metadata10: arbitrary mask
+ tun_metadata11: arbitrary mask
+ tun_metadata12: arbitrary mask
+ tun_metadata13: arbitrary mask
+ tun_metadata14: arbitrary mask
+ tun_metadata15: arbitrary mask
+ tun_metadata16: arbitrary mask
+ tun_metadata17: arbitrary mask
+ tun_metadata18: arbitrary mask
+ tun_metadata19: arbitrary mask
+ tun_metadata20: arbitrary mask
+ tun_metadata21: arbitrary mask
+ tun_metadata22: arbitrary mask
+ tun_metadata23: arbitrary mask
+ tun_metadata24: arbitrary mask
+ tun_metadata25: arbitrary mask
+ tun_metadata26: arbitrary mask
+ tun_metadata27: arbitrary mask
+ tun_metadata28: arbitrary mask
+ tun_metadata29: arbitrary mask
+ tun_metadata30: arbitrary mask
+ tun_metadata31: arbitrary mask
+ tun_metadata32: arbitrary mask
+ tun_metadata33: arbitrary mask
+ tun_metadata34: arbitrary mask
+ tun_metadata35: arbitrary mask
+ tun_metadata36: arbitrary mask
+ tun_metadata37: arbitrary mask
+ tun_metadata38: arbitrary mask
+ tun_metadata39: arbitrary mask
+ tun_metadata40: arbitrary mask
+ tun_metadata41: arbitrary mask
+ tun_metadata42: arbitrary mask
+ tun_metadata43: arbitrary mask
+ tun_metadata44: arbitrary mask
+ tun_metadata45: arbitrary mask
+ tun_metadata46: arbitrary mask
+ tun_metadata47: arbitrary mask
+ tun_metadata48: arbitrary mask
+ tun_metadata49: arbitrary mask
+ tun_metadata50: arbitrary mask
+ tun_metadata51: arbitrary mask
+ tun_metadata52: arbitrary mask
+ tun_metadata53: arbitrary mask
+ tun_metadata54: arbitrary mask
+ tun_metadata55: arbitrary mask
+ tun_metadata56: arbitrary mask
+ tun_metadata57: arbitrary mask
+ tun_metadata58: arbitrary mask
+ tun_metadata59: arbitrary mask
+ tun_metadata60: arbitrary mask
+ tun_metadata61: arbitrary mask
+ tun_metadata62: arbitrary mask
+ tun_metadata63: arbitrary mask
+ metadata: arbitrary mask
+ in_port: exact match or wildcard
+ in_port_oxm: exact match or wildcard
+ actset_output: exact match or wildcard
+ pkt_mark: arbitrary mask
+ ct_state: arbitrary mask
+ ct_zone: exact match or wildcard
+ ct_mark: arbitrary mask
+ ct_label: arbitrary mask
+ reg0: arbitrary mask
+ reg1: arbitrary mask
+ reg2: arbitrary mask
+ reg3: arbitrary mask
+ reg4: arbitrary mask
+ reg5: arbitrary mask
+ reg6: arbitrary mask
+ reg7: arbitrary mask
+ xreg0: arbitrary mask
+ xreg1: arbitrary mask
+ xreg2: arbitrary mask
+ xreg3: arbitrary mask
+ eth_src: arbitrary mask
+ eth_dst: arbitrary mask
+ eth_type: exact match or wildcard
+ vlan_tci: arbitrary mask
+ vlan_vid: arbitrary mask
+ vlan_pcp: exact match or wildcard
+ mpls_label: exact match or wildcard
+ mpls_tc: exact match or wildcard
+ mpls_bos: exact match or wildcard
+ ip_src: arbitrary mask
+ ip_dst: arbitrary mask
+ ipv6_src: arbitrary mask
+ ipv6_dst: arbitrary mask
+ ipv6_label: arbitrary mask
+ nw_proto: exact match or wildcard
+ nw_tos: exact match or wildcard
+ ip_dscp: exact match or wildcard
+ nw_ecn: exact match or wildcard
+ nw_ttl: exact match or wildcard
+ ip_frag: arbitrary mask
+ arp_op: exact match or wildcard
+ arp_spa: arbitrary mask
+ arp_tpa: arbitrary mask
+ arp_sha: arbitrary mask
+ arp_tha: arbitrary mask
+ tcp_src: arbitrary mask
+ tcp_dst: arbitrary mask
+ tcp_flags: arbitrary mask
+ udp_src: arbitrary mask
+ udp_dst: arbitrary mask
+ sctp_src: arbitrary mask
+ sctp_dst: arbitrary mask
+ icmp_type: exact match or wildcard
+ icmp_code: exact match or wildcard
+ icmpv6_type: exact match or wildcard
+ icmpv6_code: exact match or wildcard
+ nd_target: arbitrary mask
+ nd_sll: arbitrary mask
+ nd_tll: arbitrary mask
+
+' $1
+}
+ditto() {
+ printf ' table %d ("%s"):
+ metadata: match=0xffffffffffffffff write=0xffffffffffffffff
+ eviction: not supported
+ vacancy events: not supported
+ features: none
+ max_entries=%d
+ instructions (table miss and others):
+ next tables: %d-253
+ (same instructions)
+ (same actions)
+ (same matching)
+
+' $1 $2 $3 `expr $1 + 1`
+}
+tail_tables() {
+echo ' table 252 ("table252"):
+ metadata: match=0xffffffffffffffff write=0xffffffffffffffff
+ eviction: not supported
+ vacancy events: not supported
+ features: none
+ max_entries=1000000
+ instructions (table miss and others):
+ next tables: 253
+ (same instructions)
+ (same actions)
+ (same matching)
+
+ table 253 ("table253"):
+ metadata: match=0xffffffffffffffff write=0xffffffffffffffff
+ eviction: not supported
+ vacancy events: not supported
+ features: none
+ max_entries=1000000
+ instructions (table miss and others):
+ instructions: meter,apply_actions,clear_actions,write_actions,write_metadata
+ (same actions)
+ (same matching)
+'
+}
+first_egress_table() {
+echo ' table 251 ("table251"):
+ metadata: match=0xffffffffffffffff write=0xffffffffffffffff
+ eviction: not supported
+ vacancy events: not supported
+ features: first egress table
+ max_entries=1000000
+ instructions (table miss and others):
+ next tables: 252-253
+ (same instructions)
+ Write-Actions and Apply-Actions features:
+ actions: set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue
+ supported on Set-Field: tun_id tun_src tun_dst tun_ipv6_src tun_ipv6_dst tun_flags tun_gbp_id tun_gbp_flags tun_metadata0 tun_metadata1 tun_metadata2 tun_metadata3 tun_metadata4 tun_metadata5 tun_metadata6 tun_metadata7 tun_metadata8 tun_metadata9 tun_metadata10 tun_metadata11 tun_metadata12 tun_metadata13 tun_metadata14 tun_metadata15 tun_metadata16 tun_metadata17 tun_metadata18 tun_metadata19 tun_metadata20 tun_metadata21 tun_metadata22 tun_metadata23 tun_metadata24 tun_metadata25 tun_metadata26 tun_metadata27 tun_metadata28 tun_metadata29 tun_metadata30 tun_metadata31 tun_metadata32 tun_metadata33 tun_metadata34 tun_metadata35 tun_metadata36 tun_metadata37 tun_metadata38 tun_metadata39 tun_metadata40 tun_metadata41 tun_metadata42 tun_metadata43 tun_metadata44 tun_metadata45 tun_metadata46 tun_metadata47 tun_metadata48 tun_metadata49 tun_metadata50 tun_metadata51 tun_metadata52 tun_metadata53 tun_metadata54 tun_metadata55 tun_metadata56 tun_metadata57 tun_metadata5
8 tun_metadata59 tun_metadata60 tun_metadata61 tun_metadata62 tun_metadata63 metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 xreg0 xreg1 xreg2 xreg3 eth_src eth_dst vlan_tci vlan_vid vlan_pcp mpls_label mpls_tc ip_src ip_dst ipv6_src ipv6_dst ipv6_label nw_tos ip_dscp nw_ecn nw_ttl arp_op arp_spa arp_tpa arp_sha arp_tha tcp_src tcp_dst udp_src udp_dst sctp_src sctp_dst icmp_type icmp_code icmpv6_type icmpv6_code nd_target nd_sll nd_tll
+ (same matching)
+'
+}
+(head_table classifier
+ for i in `seq 1 251`; do
+ ditto $i table$i 1000000
+ done
+ tail_tables) > expout
+AT_CHECK([ovs-ofctl -O OpenFlow15 dump-table-features br0], [0], [expout])
+# Set first egress table.
+ovs-ofctl -O Openflow15 set-first-egress-table br0 251
+
+# Check that the configuration was updated.
+(head_table classifier
+ for i in `seq 1 250`; do
+ ditto $i table$i 1000000
+ done
+ first_egress_table
+ tail_tables) > expout
+AT_CHECK([ovs-ofctl -O OpenFlow15 dump-table-features br0], [0], [expout])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
AT_SETUP([ofproto - table description (OpenFlow 1.4)])
OVS_VSWITCHD_START
(x=0
@@ -343,6 +343,7 @@ usage(void)
" dump-desc SWITCH print switch description\n"
" dump-tables SWITCH print table stats\n"
" dump-table-features SWITCH print table features\n"
+ " set-first-egress-table SWITCH TABLE set first egress table\n"
" dump-table-desc SWITCH print table description (OF1.4+)\n"
" mod-port SWITCH IFACE ACT modify port behavior\n"
" mod-table SWITCH MOD modify flow table behavior\n"
@@ -713,9 +714,9 @@ ofctl_dump_table_features(struct ovs_cmdl_context *ctx)
{
struct ofpbuf *request;
struct vconn *vconn;
-
+ struct ofputil_table_features *tf = NULL;
open_vconn(ctx->argv[1], &vconn);
- request = ofputil_encode_table_features_request(vconn_get_version(vconn));
+ request = ofputil_encode_table_features_request(tf, vconn_get_version(vconn));
/* The following is similar to dump_trivial_transaction(), but it
* maintains the previous 'ofputil_table_features' from one stats reply
@@ -788,6 +789,35 @@ ofctl_dump_table_features(struct ovs_cmdl_context *ctx)
}
static void
+ofctl_set_first_egress_table(struct ovs_cmdl_context *ctx)
+{
+ uint32_t usable_versions;
+ struct ofputil_table_features tf;
+ struct vconn *vconn;
+ char *error;
+
+ error = parse_ofp_table_features(&tf, ctx->argv[2], &usable_versions);
+ if (error) {
+ ovs_fatal(0, "%s", error);
+ }
+
+ uint32_t allowed_versions = get_allowed_ofp_versions();
+ if (!(allowed_versions & usable_versions)) {
+ struct ds versions = DS_EMPTY_INITIALIZER;
+ ofputil_format_version_bitmap_names(&versions, usable_versions);
+ ovs_fatal(0, "set_first_egress_table '%s' requires one of the OpenFlow "
+ "versions %s (use -O)",
+ ctx->argv[2], ds_cstr(&versions));
+ }
+ mask_allowed_ofp_versions(usable_versions);
+
+ open_vconn(ctx->argv[1], &vconn);
+ transact_noreply(vconn, ofputil_encode_table_features_request(&tf,
+ vconn_get_version(vconn)));
+ vconn_close(vconn);
+}
+
+static void
ofctl_dump_table_desc(struct ovs_cmdl_context *ctx)
{
struct ofpbuf *request;
@@ -3875,6 +3905,8 @@ static const struct ovs_cmdl_command all_commands[] = {
1, 1, ofctl_dump_tables },
{ "dump-table-features", "switch",
1, 1, ofctl_dump_table_features },
+ { "set-first-egress-table", "switch table",
+ 2, 2, ofctl_set_first_egress_table },
{ "dump-table-desc", "switch",
1, 1, ofctl_dump_table_desc },
{ "dump-flows", "switch",