summaryrefslogtreecommitdiff
path: root/usr.sbin/switchd
diff options
context:
space:
mode:
authorRafael Zalamena <rzalamena@cvs.openbsd.org>2016-09-29 13:04:51 +0000
committerRafael Zalamena <rzalamena@cvs.openbsd.org>2016-09-29 13:04:51 +0000
commit0f398856b6123062f8b3b594645ae3b325d99e3c (patch)
tree555e1013f6d1ac9eca0801f8276a66bc7312248c /usr.sbin/switchd
parent3feef6b165120bcfdb80f977dcd5770af982dfea (diff)
Teach switchd(8) some multipart table properties request/parse code to
handle basic display.
Diffstat (limited to 'usr.sbin/switchd')
-rw-r--r--usr.sbin/switchd/ofp.h64
-rw-r--r--usr.sbin/switchd/ofp13.c403
-rw-r--r--usr.sbin/switchd/ofp_map.h7
3 files changed, 436 insertions, 38 deletions
diff --git a/usr.sbin/switchd/ofp.h b/usr.sbin/switchd/ofp.h
index 7a526d0314e..4e2201366dc 100644
--- a/usr.sbin/switchd/ofp.h
+++ b/usr.sbin/switchd/ofp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ofp.h,v 1.5 2016/09/28 20:17:58 rzalamena Exp $ */
+/* $OpenBSD: ofp.h,v 1.6 2016/09/29 13:04:50 rzalamena Exp $ */
/*
* Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
@@ -654,21 +654,21 @@ struct ofp_multipart {
#define OFP_MP_FLAG_REPLY_MORE 1
/* Multipart types */
-#define OFP_MP_T_DESC 0
-#define OFP_MP_T_FLOW 1
-#define OFP_MP_T_AGGREGATE 2
-#define OFP_MP_T_TABLE 3
-#define OFP_MP_T_PORT_STATS 4
-#define OFP_MP_T_QUEUE 5
-#define OFP_MP_T_GROUP 6
-#define OFP_MP_T_GROUP_DESC 7
-#define OFP_MP_T_GROUP_FEATURES 8
-#define OFP_MP_T_METER 9
-#define OFP_MP_T_METER_CONFIG 10
-#define OFP_MP_T_METER_FEATURES 11
-#define OFP_MP_T_TABLE_FEATURES 12
-#define OFP_MP_T_PORT_DESC 13
-#define OFP_MP_T_EXPERIMENTER 0xffff
+#define OFP_MP_T_DESC 0 /* Description of the switch */
+#define OFP_MP_T_FLOW 1 /* Individual flow statistics */
+#define OFP_MP_T_AGGREGATE 2 /* Aggregate flow statistics */
+#define OFP_MP_T_TABLE 3 /* Flow table statistics */
+#define OFP_MP_T_PORT_STATS 4 /* Port statistics */
+#define OFP_MP_T_QUEUE 5 /* Queue statistics for a port */
+#define OFP_MP_T_GROUP 6 /* Group counter statistics */
+#define OFP_MP_T_GROUP_DESC 7 /* Group description */
+#define OFP_MP_T_GROUP_FEATURES 8 /* Group features */
+#define OFP_MP_T_METER 9 /* Meter statistics */
+#define OFP_MP_T_METER_CONFIG 10 /* Meter configuration */
+#define OFP_MP_T_METER_FEATURES 11 /* Meter features */
+#define OFP_MP_T_TABLE_FEATURES 12 /* Table features */
+#define OFP_MP_T_PORT_DESC 13 /* Port description */
+#define OFP_MP_T_EXPERIMENTER 0xffff /* Experimenter extension */
#define OFP_DESC_STR_LEN 256
#define OFP_SERIAL_NUM_LEN 32
@@ -742,22 +742,22 @@ struct ofp_table_stats {
} __packed;
/* Table features */
-#define OFP_TABLE_FEATPROP_INSTRUCTION 0
-#define OFP_TABLE_FEATPROP_INSTRUCTION_MISS 1
-#define OFP_TABLE_FEATPROP_NEXT_TABLES 2
-#define OFP_TABLE_FEATPROP_NEXT_TABLES_MISS 3
-#define OFP_TABLE_FEATPROP_WRITE_ACTIONS 4
-#define OFP_TABLE_FEATPROP_WRITE_ACTIONS_MISS 5
-#define OFP_TABLE_FEATPROP_APPLY_ACTIONS 6
-#define OFP_TABLE_FEATPROP_APPLY_ACTIONS_MISS 7
-#define OFP_TABLE_FEATPROP_MATCH 8
-#define OFP_TABLE_FEATPROP_WILDCARDS 10
-#define OFP_TABLE_FEATPROP_WRITE_SETFIELD 12
-#define OFP_TABLE_FEATPROP_WRITE_SETFIELD_MISS 13
-#define OFP_TABLE_FEATPROP_APPLY_SETFIELD 14
-#define OFP_TABLE_FEATPROP_APPLY_SETFIELD_MISS 15
-#define OFP_TABLE_FEATPROP_EXPERIMENTER 0xfffe
-#define OFP_TABLE_FEATPROP_EXPERIMENTER_MISS 0xffff
+#define OFP_TABLE_FEATPROP_INSTRUCTION 0 /* Instruction property */
+#define OFP_TABLE_FEATPROP_INSTRUCTION_MISS 1 /* Instruction for table-miss */
+#define OFP_TABLE_FEATPROP_NEXT_TABLES 2 /* Next table property */
+#define OFP_TABLE_FEATPROP_NEXT_TABLES_MISS 3 /* Next table for table-miss */
+#define OFP_TABLE_FEATPROP_WRITE_ACTIONS 4 /* Write actions property */
+#define OFP_TABLE_FEATPROP_WRITE_ACTIONS_MISS 5 /* Write actions for table-miss */
+#define OFP_TABLE_FEATPROP_APPLY_ACTIONS 6 /* Apply actions property */
+#define OFP_TABLE_FEATPROP_APPLY_ACTIONS_MISS 7 /* Apply actions for table-miss */
+#define OFP_TABLE_FEATPROP_MATCH 8 /* Match property */
+#define OFP_TABLE_FEATPROP_WILDCARDS 10 /* Wildcards property */
+#define OFP_TABLE_FEATPROP_WRITE_SETFIELD 12 /* Write set-field property */
+#define OFP_TABLE_FEATPROP_WRITE_SETFIELD_MISS 13 /* Write set-field for table-miss */
+#define OFP_TABLE_FEATPROP_APPLY_SETFIELD 14 /* Apply set-field property */
+#define OFP_TABLE_FEATPROP_APPLY_SETFIELD_MISS 15 /* Apply set-field for table-miss */
+#define OFP_TABLE_FEATPROP_EXPERIMENTER 0xfffe /* Experimenter property */
+#define OFP_TABLE_FEATPROP_EXPERIMENTER_MISS 0xffff /* Experimenter for table-miss */
#define OFP_TABLE_MAX_NAME_LEN 32
diff --git a/usr.sbin/switchd/ofp13.c b/usr.sbin/switchd/ofp13.c
index c939fbd4688..5b14341ab94 100644
--- a/usr.sbin/switchd/ofp13.c
+++ b/usr.sbin/switchd/ofp13.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ofp13.c,v 1.10 2016/09/28 17:48:35 rzalamena Exp $ */
+/* $OpenBSD: ofp13.c,v 1.11 2016/09/29 13:04:50 rzalamena Exp $ */
/*
* Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
@@ -65,10 +65,29 @@ int ofp13_packet_in(struct switchd *, struct switch_connection *,
struct ofp_header *, struct ibuf *);
int ofp13_flow_removed(struct switchd *, struct switch_connection *,
struct ofp_header *, struct ibuf *);
+int ofp13_parse_instruction(struct ibuf *, struct ofp_instruction *);
+int ofp13_parse_action(struct ibuf *, struct ofp_action_header *);
+int ofp13_parse_oxm(struct ibuf *, struct ofp_ox_match *);
+int ofp13_parse_tableproperties(struct ibuf *, struct ofp_table_features *);
+int ofp13_multipart_reply(struct switchd *, struct switch_connection *,
+ struct ofp_header *, struct ibuf *);
+int ofp13_multipart_reply_validate(struct switchd *,
+ struct sockaddr_storage *, struct sockaddr_storage *,
+ struct ofp_header *, struct ibuf *);
int ofp13_validate_packet_out(struct switchd *,
struct sockaddr_storage *, struct sockaddr_storage *,
struct ofp_header *, struct ibuf *);
+struct ofp_multipart *
+ ofp13_multipart_request(struct switch_connection *, struct ibuf *,
+ uint16_t, uint16_t);
+int ofp13_multipart_request_validate(struct switchd *,
+ struct sockaddr_storage *, struct sockaddr_storage *,
+ struct ofp_header *, struct ibuf *);
+
+int ofp13_table_features(struct switchd *, struct switch_connection *,
+ uint8_t);
+
struct ofp_group_mod *
ofp13_group(struct switch_connection *, struct ibuf *,
uint32_t, uint16_t, uint8_t);
@@ -140,8 +159,10 @@ struct ofp_callback ofp13_callbacks[] = {
{ OFP_T_GROUP_MOD, NULL, NULL },
{ OFP_T_PORT_MOD, NULL, NULL },
{ OFP_T_TABLE_MOD, NULL, NULL },
- { OFP_T_MULTIPART_REQUEST, NULL, NULL },
- { OFP_T_MULTIPART_REPLY, NULL, NULL },
+ { OFP_T_MULTIPART_REQUEST, NULL,
+ ofp13_multipart_request_validate },
+ { OFP_T_MULTIPART_REPLY, ofp13_multipart_reply,
+ ofp13_multipart_reply_validate },
{ OFP_T_BARRIER_REQUEST, NULL, NULL },
{ OFP_T_BARRIER_REPLY, NULL, NULL },
{ OFP_T_QUEUE_GET_CONFIG_REQUEST, NULL, NULL },
@@ -195,7 +216,7 @@ ofp13_validate_oxm(struct switchd *sc, struct ofp_ox_match *oxm,
class = ntohs(oxm->oxm_class);
log_debug("\tox match class %s type %s length %u",
- print_map(class, ofp_oxm_map),
+ print_map(class, ofp_oxm_c_map),
print_map(type, ofp_xm_t_map),
oxm->oxm_length);
@@ -416,6 +437,8 @@ ofp13_hello(struct switchd *sc, struct switch_connection *con,
return (-1);
ofp_send(con, oh, NULL);
+ ofp13_table_features(sc, con, 0);
+
return (0);
}
@@ -668,6 +691,378 @@ ofp13_flow_removed(struct switchd *sc, struct switch_connection *con,
return (0);
}
+int
+ofp13_parse_instruction(struct ibuf *ibuf, struct ofp_instruction *i)
+{
+ int type;
+ int len;
+
+ type = ntohs(i->i_type);
+ len = ntohs(i->i_len);
+
+ log_debug("\t\t%s", print_map(type, ofp_instruction_t_map));
+
+ return (len);
+}
+
+int
+ofp13_parse_action(struct ibuf *ibuf, struct ofp_action_header *ah)
+{
+ int len, type;
+
+ len = htons(ah->ah_len);
+ type = htons(ah->ah_type);
+
+ log_debug("\t\t%s", print_map(type, ofp_action_map));
+
+ return (len);
+}
+
+int
+ofp13_parse_oxm(struct ibuf *ibuf, struct ofp_ox_match *oxm)
+{
+ int length, type, class, hasmask;
+
+ class = ntohs(oxm->oxm_class);
+ type = OFP_OXM_GET_FIELD(oxm);
+ hasmask = OFP_OXM_GET_HASMASK(oxm);
+ /*
+ * XXX the OpenFlow 1.3.5 specification says this field is only
+ * 4 bytes long, however the experimental type is 8 bytes.
+ */
+ length = sizeof(*oxm);
+
+ log_debug("\t\t%s hasmask %s type %s",
+ print_map(class, ofp_oxm_c_map), hasmask ? "yes" : "no",
+ print_map(type, ofp_xm_t_map));
+
+ if (class == OFP_OXM_C_OPENFLOW_EXPERIMENTER) {
+ /* Get the last bytes. */
+ if (ibuf_getdata(ibuf, 4) == NULL)
+ return (-1);
+
+ return (8);
+ }
+
+ return (length);
+}
+
+int
+ofp13_parse_tableproperties(struct ibuf *ibuf, struct ofp_table_features *tf)
+{
+ struct ofp_table_feature_property *tp;
+ struct ofp_instruction *i;
+ struct ofp_action_header *ah;
+ struct ofp_ox_match *oxm;
+ uint8_t *next_table;
+ int remaining, type, length;
+ int totallen, padsize, rv;
+
+ log_debug("Table %s (%d): max_entries %u config %u",
+ tf->tf_name, tf->tf_tableid, ntohl(tf->tf_max_entries),
+ ntohl(tf->tf_config));
+ totallen = htons(tf->tf_length);
+ remaining = totallen - sizeof(*tf);
+
+ next_table_property:
+ if ((tp = ibuf_getdata(ibuf, sizeof(*tp))) == NULL)
+ return (-1);
+
+ type = ntohs(tp->tp_type);
+ length = ntohs(tp->tp_length);
+
+ /* Calculate the padding. */
+ padsize = OFP_ALIGN(length) - length;
+ remaining -= OFP_ALIGN(length);
+ length -= sizeof(*tp);
+
+ log_debug("\t%s:", print_map(type, ofp_table_featprop_map));
+ if (length == 0)
+ log_debug("\t\tNONE");
+
+ switch (type) {
+ case OFP_TABLE_FEATPROP_INSTRUCTION:
+ case OFP_TABLE_FEATPROP_INSTRUCTION_MISS:
+ while (length) {
+ if ((i = ibuf_getdata(ibuf, sizeof(*i))) == NULL)
+ return (-1);
+ if ((rv = ofp13_parse_instruction(ibuf, i)) == -1)
+ return (-1);
+ length -= rv;
+ }
+ break;
+
+ case OFP_TABLE_FEATPROP_NEXT_TABLES:
+ case OFP_TABLE_FEATPROP_NEXT_TABLES_MISS:
+ while (length) {
+ if ((next_table = ibuf_getdata(ibuf,
+ sizeof(*next_table))) == NULL)
+ return (-1);
+
+ log_debug("\t\t%d", *next_table);
+ length -= sizeof(*next_table);
+ }
+ break;
+
+ case OFP_TABLE_FEATPROP_WRITE_ACTIONS:
+ case OFP_TABLE_FEATPROP_WRITE_ACTIONS_MISS:
+ case OFP_TABLE_FEATPROP_APPLY_ACTIONS:
+ case OFP_TABLE_FEATPROP_APPLY_ACTIONS_MISS:
+ while (length) {
+ /*
+ * XXX the OpenFlow 1.3.5 specs says that we only
+ * get 4 bytes here instead of the full OXM.
+ */
+ if ((ah = ibuf_getdata(ibuf, 4)) == NULL)
+ return (-1);
+ if ((rv = ofp13_parse_action(ibuf, ah)) == -1)
+ return (-1);
+ length -= rv;
+ }
+ break;
+
+ case OFP_TABLE_FEATPROP_MATCH:
+ case OFP_TABLE_FEATPROP_WILDCARDS:
+ case OFP_TABLE_FEATPROP_WRITE_SETFIELD:
+ case OFP_TABLE_FEATPROP_WRITE_SETFIELD_MISS:
+ case OFP_TABLE_FEATPROP_APPLY_SETFIELD:
+ case OFP_TABLE_FEATPROP_APPLY_SETFIELD_MISS:
+ while (length) {
+ if ((oxm = ibuf_getdata(ibuf, sizeof(*oxm))) == NULL)
+ return (-1);
+ if ((rv = ofp13_parse_oxm(ibuf, oxm)) == -1)
+ return (-1);
+ length -= rv;
+ }
+ break;
+
+ default:
+ log_debug("%s: unsupported property type: %d", __func__, type);
+
+ /* Skip this field and try to continue otherwise fail. */
+ if (ibuf_getdata(ibuf, length) == NULL)
+ return (-1);
+
+ break;
+ }
+
+ /* Skip the padding and read the next property if any. */
+ if (padsize && ibuf_getdata(ibuf, padsize) == NULL)
+ return (-1);
+ if (remaining)
+ goto next_table_property;
+
+ return (totallen);
+}
+
+int
+ofp13_multipart_reply(struct switchd *sc, struct switch_connection *con,
+ struct ofp_header *oh, struct ibuf *ibuf)
+{
+ struct ofp_multipart *mp;
+ struct ofp_table_features *tf;
+ int readlen, type;
+ int remaining;
+
+ if ((mp = ibuf_getdata(ibuf, sizeof(*mp))) == NULL)
+ return (-1);
+
+ if (mp->mp_flags & OFP_MP_FLAG_REPLY_MORE) {
+ /* TODO support multiple fragments. */
+ return (-1);
+ }
+
+ type = ntohs(mp->mp_type);
+ remaining = ntohs(oh->oh_length) - sizeof(*mp);
+
+ switch (type) {
+ case OFP_MP_T_TABLE_FEATURES:
+ read_next_table:
+ if ((tf = ibuf_getdata(ibuf, sizeof(*tf))) == NULL)
+ return (-1);
+ if ((readlen = ofp13_parse_tableproperties(ibuf, tf)) == -1)
+ return (-1);
+
+ remaining -= readlen;
+ if (remaining)
+ goto read_next_table;
+ break;
+ }
+
+ return (0);
+}
+
+int
+ofp13_multipart_reply_validate(struct switchd *sc,
+ struct sockaddr_storage *src, struct sockaddr_storage *dst,
+ struct ofp_header *oh, struct ibuf *ibuf)
+{
+ struct ofp_multipart *mp;
+ struct ofp_table_features *tf;
+ int mptype, mpflags, hlen;
+ int remaining;
+ off_t off;
+
+ remaining = ntohs(oh->oh_length);
+
+ off = 0;
+ if ((mp = ibuf_seek(ibuf, off, sizeof(*mp))) == NULL)
+ return (-1);
+
+ mptype = ntohs(mp->mp_type);
+ mpflags = ntohs(mp->mp_flags);
+ log_debug("\ttype %s flags %#04x",
+ print_map(mptype, ofp_mp_t_map), mpflags);
+
+ off += sizeof(*mp);
+ remaining -= sizeof(*mp);
+ if (remaining == 0) {
+ log_debug("\tEmpty reply");
+ return (0);
+ }
+
+ switch (mptype) {
+ case OFP_MP_T_DESC:
+ case OFP_MP_T_FLOW:
+ case OFP_MP_T_AGGREGATE:
+ case OFP_MP_T_TABLE:
+ case OFP_MP_T_PORT_STATS:
+ case OFP_MP_T_QUEUE:
+ case OFP_MP_T_GROUP:
+ case OFP_MP_T_GROUP_DESC:
+ case OFP_MP_T_GROUP_FEATURES:
+ case OFP_MP_T_METER:
+ case OFP_MP_T_METER_CONFIG:
+ case OFP_MP_T_METER_FEATURES:
+ break;
+
+ case OFP_MP_T_TABLE_FEATURES:
+ read_next_table:
+ if ((tf = ibuf_seek(ibuf, off, sizeof(*tf))) == NULL)
+ return (-1);
+
+ hlen = ntohs(tf->tf_length);
+ log_debug("\ttable features length %d tableid %d name \"%s\" "
+ "metadata match %llu write %llu config %u max_entries %u",
+ hlen, tf->tf_tableid, tf->tf_name,
+ be64toh(tf->tf_metadata_match),
+ be64toh(tf->tf_metadata_write), ntohl(tf->tf_config),
+ ntohl(tf->tf_max_entries));
+ remaining -= hlen;
+ off += hlen;
+ if (remaining)
+ goto read_next_table;
+ break;
+
+ case OFP_MP_T_PORT_DESC:
+ case OFP_MP_T_EXPERIMENTER:
+ break;
+
+ default:
+ return (-1);
+ }
+
+ return (0);
+}
+
+/* Don't forget to update mp->mp_oh.oh_length */
+struct ofp_multipart *
+ofp13_multipart_request(struct switch_connection *con, struct ibuf *ibuf,
+ uint16_t type, uint16_t flags)
+{
+ struct ofp_multipart *mp;
+ struct ofp_header *oh;
+
+ if ((mp = ibuf_advance(ibuf, sizeof(*mp))) == NULL)
+ return (NULL);
+
+ oh = &mp->mp_oh;
+ oh->oh_version = OFP_V_1_3;
+ oh->oh_type = OFP_T_MULTIPART_REQUEST;
+ oh->oh_xid = htonl(con->con_xidnxt++);
+ mp->mp_type = htons(type);
+ mp->mp_flags = htons(flags);
+ return (mp);
+}
+
+int
+ofp13_multipart_request_validate(struct switchd *sc,
+ struct sockaddr_storage *src, struct sockaddr_storage *dst,
+ struct ofp_header *oh, struct ibuf *ibuf)
+{
+ struct ofp_multipart *mp;
+ off_t off;
+ int type, flags, totallen;
+
+ off = 0;
+ if ((mp = ibuf_seek(ibuf, off, sizeof(*mp))) == NULL)
+ return (-1);
+
+ type = ntohs(mp->mp_type);
+ flags = ntohs(mp->mp_flags);
+ log_debug("\ttype %s flags %#04x", print_map(type, ofp_mp_t_map), flags);
+
+ totallen = ntohs(oh->oh_length);
+ off += sizeof(*mp);
+
+ switch (type) {
+ case OFP_MP_T_DESC:
+ case OFP_MP_T_FLOW:
+ case OFP_MP_T_AGGREGATE:
+ case OFP_MP_T_TABLE:
+ case OFP_MP_T_PORT_STATS:
+ case OFP_MP_T_QUEUE:
+ case OFP_MP_T_GROUP:
+ case OFP_MP_T_GROUP_DESC:
+ case OFP_MP_T_GROUP_FEATURES:
+ case OFP_MP_T_METER:
+ case OFP_MP_T_METER_CONFIG:
+ case OFP_MP_T_METER_FEATURES:
+ break;
+
+ case OFP_MP_T_TABLE_FEATURES:
+ if (totallen == sizeof(*mp)) {
+ log_debug("\tEmpty table properties request");
+ break;
+ }
+ break;
+
+ case OFP_MP_T_PORT_DESC:
+ case OFP_MP_T_EXPERIMENTER:
+ break;
+
+ default:
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+ofp13_table_features(struct switchd *sc, struct switch_connection *con,
+ uint8_t tableid)
+{
+ struct ofp_header *oh;
+ struct ofp_multipart *mp;
+ struct ibuf *ibuf;
+
+ if ((ibuf = ibuf_static()) == NULL)
+ return (-1);
+
+ if ((mp = ofp13_multipart_request(con, ibuf,
+ OFP_MP_T_TABLE_FEATURES, 0)) == NULL)
+ return (-1);
+
+ oh = &mp->mp_oh;
+ oh->oh_length = htons(sizeof(*mp));
+ if (ofp13_validate(sc, &con->con_local, &con->con_peer, oh, ibuf) != 0)
+ return (-1);
+
+ ofp_send(con, NULL, ibuf);
+ ibuf_release(ibuf);
+ return (0);
+}
+
/*
* The valid commands for groups are:
* OFP_GROUPCMD_{ADD,MODIFY,DELETE}
diff --git a/usr.sbin/switchd/ofp_map.h b/usr.sbin/switchd/ofp_map.h
index 3af2756c5b1..04db3b72a78 100644
--- a/usr.sbin/switchd/ofp_map.h
+++ b/usr.sbin/switchd/ofp_map.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ofp_map.h,v 1.4 2016/09/26 08:46:00 rzalamena Exp $ */
+/* $OpenBSD: ofp_map.h,v 1.5 2016/09/29 13:04:50 rzalamena Exp $ */
/*
* Copyright (c) 2013-2016 Reyk Floeter <reyk@openbsd.org>
@@ -39,14 +39,16 @@ extern struct constmap ofp_v_map[];
extern struct constmap ofp_t_map[];
extern struct constmap ofp_pktin_map[];
extern struct constmap ofp_port_map[];
-extern struct constmap ofp_oxm_map[];
+extern struct constmap ofp_oxm_c_map[];
extern struct constmap ofp_xm_t_map[];
extern struct constmap ofp_config_map[];
+extern struct constmap ofp_instruction_t_map[];
extern struct constmap ofp_portstate_map[];
extern struct constmap ofp_portconfig_map[];
extern struct constmap ofp_portmedia_map[];
extern struct constmap ofp_swcap_map[];
extern struct constmap ofp_match_map[];
+extern struct constmap ofp_mp_t_map[];
extern struct constmap ofp_action_map[];
extern struct constmap ofp_flowcmd_map[];
extern struct constmap ofp_flowflag_map[];
@@ -55,5 +57,6 @@ extern struct constmap ofp_errflowmod_map[];
extern struct constmap ofp_errmatch_map[];
extern struct constmap ofp_errinst_map[];
extern struct constmap ofp_errreq_map[];
+extern struct constmap ofp_table_featprop_map[];
#endif /* _SWITCHD_OFP_MAP_H */