+const char *
+ofputil_async_msg_type_to_string(enum ofputil_async_msg_type type)
+{
+ switch (type) {
+ case OAM_PACKET_IN: return "PACKET_IN";
+ case OAM_PORT_STATUS: return "PORT_STATUS";
+ case OAM_FLOW_REMOVED: return "FLOW_REMOVED";
+ case OAM_ROLE_STATUS: return "ROLE_STATUS";
+ case OAM_TABLE_STATUS: return "TABLE_STATUS";
+ case OAM_REQUESTFORWARD: return "REQUESTFORWARD";
+
+ case OAM_N_TYPES:
+ default:
+ OVS_NOT_REACHED();
+ }
+}
+
+struct ofp14_async_prop {
+ uint64_t prop_type;
+ enum ofputil_async_msg_type oam;
+ bool master;
+ uint32_t allowed10, allowed14;
+};
+
+#define AP_PAIR(SLAVE_PROP_TYPE, OAM, A10, A14) \
+ { SLAVE_PROP_TYPE, OAM, false, A10, (A14) ? (A14) : (A10) }, \
+ { (SLAVE_PROP_TYPE + 1), OAM, true, A10, (A14) ? (A14) : (A10) }
+
+static const struct ofp14_async_prop async_props[] = {
+ AP_PAIR( 0, OAM_PACKET_IN, OFPR10_BITS, OFPR14_BITS),
+ AP_PAIR( 2, OAM_PORT_STATUS, (1 << OFPPR_N_REASONS) - 1, 0),
+ AP_PAIR( 4, OAM_FLOW_REMOVED, (1 << OVS_OFPRR_NONE) - 1, 0),
+ AP_PAIR( 6, OAM_ROLE_STATUS, (1 << OFPCRR_N_REASONS) - 1, 0),
+ AP_PAIR( 8, OAM_TABLE_STATUS, OFPTR_BITS, 0),
+ AP_PAIR(10, OAM_REQUESTFORWARD, (1 << OFPRFR_N_REASONS) - 1, 0),
+};
+
+#define FOR_EACH_ASYNC_PROP(VAR) \
+ for (const struct ofp14_async_prop *VAR = async_props; \
+ VAR < &async_props[ARRAY_SIZE(async_props)]; VAR++)
+
+static const struct ofp14_async_prop *
+get_ofp14_async_config_prop_by_prop_type(uint64_t prop_type)
+{
+ FOR_EACH_ASYNC_PROP (ap) {
+ if (prop_type == ap->prop_type) {
+ return ap;
+ }
+ }
+ return NULL;
+}
+
+static const struct ofp14_async_prop *
+get_ofp14_async_config_prop_by_oam(enum ofputil_async_msg_type oam,
+ bool master)
+{
+ FOR_EACH_ASYNC_PROP (ap) {
+ if (ap->oam == oam && ap->master == master) {
+ return ap;
+ }
+ }
+ return NULL;
+}
+
+static uint32_t
+ofp14_async_prop_allowed(const struct ofp14_async_prop *prop,
+ enum ofp_version version)
+{
+ return version >= OFP14_VERSION ? prop->allowed14 : prop->allowed10;
+}
+
+static ovs_be32
+encode_async_mask(const struct ofputil_async_cfg *src,
+ const struct ofp14_async_prop *ap,
+ enum ofp_version version)
+{
+ uint32_t mask = ap->master ? src->master[ap->oam] : src->slave[ap->oam];
+ return htonl(mask & ofp14_async_prop_allowed(ap, version));
+}
+
+static enum ofperr
+decode_async_mask(ovs_be32 src,
+ const struct ofp14_async_prop *ap, enum ofp_version version,
+ bool loose, struct ofputil_async_cfg *dst)
+{
+ uint32_t mask = ntohl(src);
+ uint32_t allowed = ofp14_async_prop_allowed(ap, version);
+ if (mask & ~allowed) {
+ OFPPROP_LOG(&bad_ofmsg_rl, loose,
+ "bad value %#x for %s (allowed mask %#x)",
+ mask, ofputil_async_msg_type_to_string(ap->oam),
+ allowed);
+ mask &= allowed;
+ if (!loose) {
+ return OFPERR_OFPACFC_INVALID;
+ }
+ }
+
+ if (ap->oam == OAM_PACKET_IN) {
+ if (mask & (1u << OFPR_NO_MATCH)) {
+ mask |= 1u << OFPR_EXPLICIT_MISS;
+ if (version < OFP13_VERSION) {
+ mask |= 1u << OFPR_IMPLICIT_MISS;
+ }
+ }
+ }
+
+ uint32_t *array = ap->master ? dst->master : dst->slave;
+ array[ap->oam] = mask;
+ return 0;
+}
+
+static enum ofperr
+parse_async_tlv(const struct ofpbuf *property,
+ const struct ofp14_async_prop *ap,
+ struct ofputil_async_cfg *ac,
+ enum ofp_version version, bool loose)
+{
+ enum ofperr error;
+ ovs_be32 mask;
+
+ error = ofpprop_parse_be32(property, &mask);
+ if (error) {
+ return error;
+ }
+
+ if (ofpprop_is_experimenter(ap->prop_type)) {
+ /* For experimenter properties, whether a property is for the master or
+ * slave role is indicated by both 'type' and 'exp_type' in struct
+ * ofp_prop_experimenter. Check that these are consistent. */
+ const struct ofp_prop_experimenter *ope = property->data;
+ bool should_be_master = ope->type == htons(0xffff);
+ if (should_be_master != ap->master) {
+ VLOG_WARN_RL(&bad_ofmsg_rl, "async property type %#"PRIx16" "
+ "indicates %s role but exp_type %"PRIu32" indicates "
+ "%s role",
+ ntohs(ope->type),
+ should_be_master ? "master" : "slave",
+ ntohl(ope->exp_type),
+ ap->master ? "master" : "slave");
+ return OFPERR_OFPBPC_BAD_EXP_TYPE;
+ }
+ }
+
+ return decode_async_mask(mask, ap, version, loose, ac);
+}
+
+static void
+decode_legacy_async_masks(const ovs_be32 masks[2],
+ enum ofputil_async_msg_type oam,
+ enum ofp_version version,
+ struct ofputil_async_cfg *dst)
+{
+ for (int i = 0; i < 2; i++) {
+ bool master = i == 0;
+ const struct ofp14_async_prop *ap
+ = get_ofp14_async_config_prop_by_oam(oam, master);
+ decode_async_mask(masks[i], ap, version, true, dst);
+ }
+}
+