OFPPC_NO_RECV_STP | OFPPC_NO_FLOOD | OFPPC_NO_FWD | \
OFPPC_NO_PACKET_IN))
-#define OFPPS_LINK_DOWN (1U << 0)
-#define OFPPS_STP_LISTEN (0U << 8)
-#define OFPPS_STP_LEARN (1U << 8)
-#define OFPPS_STP_FORWARD (2U << 8)
-#define OFPPS_STP_BLOCK (3U << 8)
-#define OFPPS_STP_MASK (3U << 8)
-static const struct tok ofpps_bm[] = {
- { OFPPS_LINK_DOWN, "LINK_DOWN" },
+/*
+ * [OF10] lists all FPPS_ constants in one enum, but they mean a 1-bit bitmap
+ * in the least significant octet and a 2-bit code point in the next octet.
+ * Remember to mix or to separate these two parts as the context requires.
+ */
+#define OFPPS_LINK_DOWN (1U << 0) /* bitmap */
+#define OFPPS_STP_LISTEN (0U << 8) /* code point */
+#define OFPPS_STP_LEARN (1U << 8) /* code point */
+#define OFPPS_STP_FORWARD (2U << 8) /* code point */
+#define OFPPS_STP_BLOCK (3U << 8) /* code point */
+#define OFPPS_STP_MASK (3U << 8) /* code point bitmask */
+static const struct tok ofpps_stp_str[] = {
{ OFPPS_STP_LISTEN, "STP_LISTEN" },
{ OFPPS_STP_LEARN, "STP_LEARN" },
{ OFPPS_STP_FORWARD, "STP_FORWARD" },
{ OFPET_QUEUE_OP_FAILED, "QUEUE_OP_FAILED" },
{ 0, NULL }
};
-#define OFPET_MAX OFPET_QUEUE_OP_FAILED /* for of10_error_print() */
#define OFPHFC_INCOMPATIBLE 0x0000U
#define OFPHFC_EPERM 0x0001U
{ 0, NULL }
};
+static const struct uint_tokary of10_ofpet2tokary[] = {
+ { OFPET_HELLO_FAILED, ofphfc_str },
+ { OFPET_BAD_REQUEST, ofpbrc_str },
+ { OFPET_BAD_ACTION, ofpbac_str },
+ { OFPET_FLOW_MOD_FAILED, ofpfmfc_str },
+ { OFPET_PORT_MOD_FAILED, ofppmfc_str },
+ { OFPET_QUEUE_OP_FAILED, ofpqofc_str },
+ /* uint2tokary() does not use array termination. */
+};
+
/* lengths (fixed or minimal) of particular protocol structures */
#define OF_SWITCH_CONFIG_FIXLEN 12
#define OF_PHY_PORT_FIXLEN 48
ND_TCHECK_LEN(cp, len);
}
+/* [OF10] Section 5.5.4 */
static void
of10_vendor_message_print(netdissect_options *ndo,
const u_char *cp, u_int len)
uint32_t vendor;
void (*decoder)(netdissect_options *, const u_char *, u_int);
- if (len < 4)
- goto invalid;
/* vendor */
vendor = GET_BE_U_4(cp);
OF_FWD(4);
vendor == OUI_BSN ? of10_bsn_message_print :
of_data_print;
decoder(ndo, cp, len);
- return;
-
-invalid: /* skip the undersized data */
- nd_print_invalid(ndo);
- ND_TCHECK_LEN(cp, len);
}
/* Vendor ID is mandatory, data is optional. */
/* [OF10] Section 5.2.1 */
static void
-of10_phy_ports_print(netdissect_options *ndo,
- const u_char *cp, u_int len)
+of10_phy_port_print(netdissect_options *ndo,
+ const u_char *cp)
{
- while (len) {
- if (len < OF_PHY_PORT_FIXLEN)
- goto invalid;
- /* port_no */
- ND_PRINT("\n\t port_no %s",
- tok2str(ofpp_str, "%u", GET_BE_U_2(cp)));
- OF_FWD(2);
- /* hw_addr */
- ND_PRINT(", hw_addr %s", GET_ETHERADDR_STRING(cp));
- OF_FWD(MAC_ADDR_LEN);
- /* name */
- ND_PRINT(", name '");
- (void)nd_print(ndo, cp, cp + OFP_MAX_PORT_NAME_LEN);
- ND_PRINT("'");
- OF_FWD(OFP_MAX_PORT_NAME_LEN);
+ uint32_t state;
- if (ndo->ndo_vflag < 2) {
- OF_CHK_FWD(24);
- continue;
- }
- /* config */
- ND_PRINT("\n\t config 0x%08x", GET_BE_U_4(cp));
- of_bitmap_print(ndo, ofppc_bm, GET_BE_U_4(cp), OFPPC_U);
- OF_FWD(4);
- /* state */
- ND_PRINT("\n\t state 0x%08x", GET_BE_U_4(cp));
- of_bitmap_print(ndo, ofpps_bm, GET_BE_U_4(cp), OFPPS_U);
- OF_FWD(4);
- /* curr */
- ND_PRINT("\n\t curr 0x%08x", GET_BE_U_4(cp));
- of_bitmap_print(ndo, ofppf_bm, GET_BE_U_4(cp), OFPPF_U);
- OF_FWD(4);
- /* advertised */
- ND_PRINT("\n\t advertised 0x%08x", GET_BE_U_4(cp));
- of_bitmap_print(ndo, ofppf_bm, GET_BE_U_4(cp), OFPPF_U);
- OF_FWD(4);
- /* supported */
- ND_PRINT("\n\t supported 0x%08x", GET_BE_U_4(cp));
- of_bitmap_print(ndo, ofppf_bm, GET_BE_U_4(cp), OFPPF_U);
- OF_FWD(4);
- /* peer */
- ND_PRINT("\n\t peer 0x%08x", GET_BE_U_4(cp));
- of_bitmap_print(ndo, ofppf_bm, GET_BE_U_4(cp), OFPPF_U);
- OF_FWD(4);
- } /* while */
- return;
+ /* port_no */
+ ND_PRINT("\n\t port_no %s",
+ tok2str(ofpp_str, "%u", GET_BE_U_2(cp)));
+ cp += 2;
+ /* hw_addr */
+ ND_PRINT(", hw_addr %s", GET_ETHERADDR_STRING(cp));
+ cp += MAC_ADDR_LEN;
+ /* name */
+ ND_PRINT(", name '");
+ (void)nd_print(ndo, cp, cp + OFP_MAX_PORT_NAME_LEN);
+ ND_PRINT("'");
+ cp += OFP_MAX_PORT_NAME_LEN;
-invalid: /* skip the undersized trailing data */
- nd_print_invalid(ndo);
- ND_TCHECK_LEN(cp, len);
+ if (ndo->ndo_vflag < 2) {
+ ND_TCHECK_LEN(cp, 24);
+ return;
+ }
+ /* config */
+ ND_PRINT("\n\t config 0x%08x", GET_BE_U_4(cp));
+ of_bitmap_print(ndo, ofppc_bm, GET_BE_U_4(cp), OFPPC_U);
+ cp += 4;
+ /* state */
+ state = GET_BE_U_4(cp);
+ /*
+ * Decode the code point and the single bit separately, but
+ * format the result as a single sequence of comma-separated
+ * strings (see the comments at the OFPPS_ props).
+ */
+ ND_PRINT("\n\t state 0x%08x (%s%s)%s", state,
+ tok2str(ofpps_stp_str, "", state & OFPPS_STP_MASK),
+ state & OFPPS_LINK_DOWN ? ", LINK_DOWN" : "",
+ state & OFPPS_U ? " (bogus)" : "");
+ cp += 4;
+ /* curr */
+ ND_PRINT("\n\t curr 0x%08x", GET_BE_U_4(cp));
+ of_bitmap_print(ndo, ofppf_bm, GET_BE_U_4(cp), OFPPF_U);
+ cp += 4;
+ /* advertised */
+ ND_PRINT("\n\t advertised 0x%08x", GET_BE_U_4(cp));
+ of_bitmap_print(ndo, ofppf_bm, GET_BE_U_4(cp), OFPPF_U);
+ cp += 4;
+ /* supported */
+ ND_PRINT("\n\t supported 0x%08x", GET_BE_U_4(cp));
+ of_bitmap_print(ndo, ofppf_bm, GET_BE_U_4(cp), OFPPF_U);
+ cp += 4;
+ /* peer */
+ ND_PRINT("\n\t peer 0x%08x", GET_BE_U_4(cp));
+ of_bitmap_print(ndo, ofppf_bm, GET_BE_U_4(cp), OFPPF_U);
}
/* [OF10] Section 5.2.2 */
of_bitmap_print(ndo, ofpat_bm, GET_BE_U_4(cp), OFPAT_U);
OF_FWD(4);
/* ports */
- of10_phy_ports_print(ndo, cp, len);
+ while (len) {
+ if (len < OF_PHY_PORT_FIXLEN)
+ goto invalid;
+ of10_phy_port_print(ndo, cp);
+ OF_FWD(OF_PHY_PORT_FIXLEN);
+ }
+ return;
+
+invalid: /* skip the undersized trailing data */
+ nd_print_invalid(ndo);
+ ND_TCHECK_LEN(cp, len);
+}
+
+/* [OF10] Section 5.3.2 */
+static void
+of10_switch_config_msg_print(netdissect_options *ndo,
+ const u_char *cp)
+{
+ /* flags */
+ ND_PRINT("\n\t flags %s",
+ tok2str(ofp_config_str, "invalid (0x%04x)", GET_BE_U_2(cp)));
+ cp += 2;
+ /* miss_send_len */
+ ND_PRINT(", miss_send_len %u", GET_BE_U_2(cp));
}
/* [OF10] Section 5.3.3 */
ND_TCHECK_4(cp);
}
+/* [OF10] Section 5.3.4 */
+static void
+of10_queue_get_config_request_print(netdissect_options *ndo,
+ const u_char *cp)
+{
+ /* port */
+ ND_PRINT("\n\t port %s", tok2str(ofpp_str, "%u", GET_BE_U_2(cp)));
+ cp += 2;
+ /* pad */
+ /* Always the last field, check bounds. */
+ ND_TCHECK_2(cp);
+}
+
+/* ibid */
+static void
+of10_queue_get_config_reply_print(netdissect_options *ndo,
+ const u_char *cp, u_int len)
+{
+ /* port */
+ ND_PRINT("\n\t port %s", tok2str(ofpp_str, "%u", GET_BE_U_2(cp)));
+ OF_FWD(2);
+ /* pad */
+ /* Sometimes the last field, check bounds. */
+ OF_CHK_FWD(6);
+ /* queues */
+ of10_queues_print(ndo, cp, len);
+}
+
/* [OF10] Section 5.3.5 */
static void
of10_stats_request_print(netdissect_options *ndo,
ND_PRINT(", byte_count %" PRIu64, GET_BE_U_8(cp));
}
+/* [OF10] Section 5.4.3 */
+static void
+of10_port_status_print(netdissect_options *ndo,
+ const u_char *cp)
+{
+ /* reason */
+ ND_PRINT("\n\t reason %s",
+ tok2str(ofppr_str, "invalid (0x%02x)", GET_U_1(cp)));
+ cp += 1;
+ /* pad */
+ /* No need to check bounds, more data follows. */
+ cp += 7;
+ /* desc */
+ of10_phy_port_print(ndo, cp);
+}
+
/* [OF10] Section 5.4.4 */
static void
of10_error_print(netdissect_options *ndo,
const u_char *cp, u_int len)
{
uint16_t type, code;
- const struct tok *code_str[OFPET_MAX + 1] = {
- /* [OFPET_HELLO_FAILED ] = */ ofphfc_str,
- /* [OFPET_BAD_REQUEST ] = */ ofpbrc_str,
- /* [OFPET_BAD_ACTION ] = */ ofpbac_str,
- /* [OFPET_FLOW_MOD_FAILED] = */ ofpfmfc_str,
- /* [OFPET_PORT_MOD_FAILED] = */ ofppmfc_str,
- /* [OFPET_QUEUE_OP_FAILED] = */ ofpqofc_str,
- };
+ const struct tok *code_str;
/* type */
type = GET_BE_U_2(cp);
/* code */
code = GET_BE_U_2(cp);
OF_FWD(2);
- if (type <= OFPET_MAX && code_str[type] != NULL)
+ code_str = uint2tokary(of10_ofpet2tokary, type);
+ if (code_str != NULL)
ND_PRINT(", code %s",
- tok2str(code_str[type], "invalid (0x%04x)", code));
+ tok2str(code_str, "invalid (0x%04x)", code));
else
ND_PRINT(", code invalid (0x%04x)", code);
/* data */
goto invalid;
if (ndo->ndo_vflag < 1)
break;
- /* flags */
- ND_PRINT("\n\t flags %s",
- tok2str(ofp_config_str, "invalid (0x%04x)",
- GET_BE_U_2(cp)));
- OF_FWD(2);
- /* miss_send_len */
- ND_PRINT(", miss_send_len %u", GET_BE_U_2(cp));
+ of10_switch_config_msg_print(ndo, cp);
return;
case OFPT_PORT_MOD:
if (len != OF_PORT_MOD_FIXLEN - OF_HEADER_FIXLEN)
goto invalid;
if (ndo->ndo_vflag < 1)
break;
- /* port */
- ND_PRINT("\n\t port %s",
- tok2str(ofpp_str, "%u", GET_BE_U_2(cp)));
- OF_FWD(2);
- /* pad */
- /* Always the last field, check bounds. */
- ND_TCHECK_2(cp);
+ of10_queue_get_config_request_print(ndo, cp);
return;
case OFPT_FLOW_REMOVED:
if (len != OF_FLOW_REMOVED_FIXLEN - OF_HEADER_FIXLEN)
goto invalid;
if (ndo->ndo_vflag < 1)
break;
- /* reason */
- ND_PRINT("\n\t reason %s",
- tok2str(ofppr_str, "invalid (0x%02x)", GET_U_1(cp)));
- OF_FWD(1);
- /* pad */
- /* No need to check bounds, more data follows. */
- OF_FWD(7);
- /* desc */
- of10_phy_ports_print(ndo, cp, len);
+ of10_port_status_print(ndo, cp);
return;
/* OpenFlow header, fixed-size message body and n * fixed-size data units. */
goto invalid;
if (ndo->ndo_vflag < 1)
break;
- /* port */
- ND_PRINT("\n\t port %s",
- tok2str(ofpp_str, "%u", GET_BE_U_2(cp)));
- OF_FWD(2);
- /* pad */
- /* Sometimes the last field, check bounds. */
- OF_CHK_FWD(6);
- /* queues */
- of10_queues_print(ndo, cp, len);
+ of10_queue_get_config_reply_print(ndo, cp, len);
return;
} /* switch (type) */
/*