]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-openflow-1.0.c
OpenFlow: Have a function for each message type.
[tcpdump] / print-openflow-1.0.c
index 6e659b30c9a6cece38a8b171136edf4dc5188278..99b0d1de1bfc2b9320673975cd3ddfd91174e4c2 100644 (file)
@@ -144,14 +144,18 @@ static const struct tok ofppc_bm[] = {
                    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" },
@@ -456,7 +460,6 @@ static const struct tok ofpet_str[] = {
        { 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
@@ -544,6 +547,16 @@ static const struct tok ofpqofc_str[] = {
        { 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
@@ -978,6 +991,7 @@ invalid: /* skip the undersized data */
        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)
@@ -985,8 +999,6 @@ of10_vendor_message_print(netdissect_options *ndo,
        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);
@@ -996,11 +1008,6 @@ of10_vendor_message_print(netdissect_options *ndo,
                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. */
@@ -1045,59 +1052,59 @@ of10_packet_data_print(netdissect_options *ndo,
 
 /* [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 */
@@ -1477,7 +1484,30 @@ of10_features_reply_print(netdissect_options *ndo,
        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 */
@@ -1556,6 +1586,34 @@ of10_port_mod_print(netdissect_options *ndo,
        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,
@@ -2026,20 +2084,29 @@ of10_flow_removed_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);
@@ -2048,9 +2115,10 @@ of10_error_print(netdissect_options *ndo,
        /* 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 */
@@ -2091,13 +2159,7 @@ of10_message_print(netdissect_options *ndo,
                        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)
@@ -2111,13 +2173,7 @@ of10_message_print(netdissect_options *ndo,
                        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)
@@ -2131,15 +2187,7 @@ of10_message_print(netdissect_options *ndo,
                        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. */
@@ -2232,15 +2280,7 @@ of10_message_print(netdissect_options *ndo,
                        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) */
        /*