]> The Tcpdump Group git mirrors - tcpdump/commitdiff
OpenFlow: Process message types via declarations.
authorDenis Ovsienko <[email protected]>
Sun, 4 Oct 2020 23:54:33 +0000 (00:54 +0100)
committerDenis Ovsienko <[email protected]>
Thu, 8 Oct 2020 14:55:29 +0000 (15:55 +0100)
Introduce struct of_msgtypeinfo and convert all the case blocks in
of10_message_print() and of13_message_print() together with ofpt_str[]
and the associated wrapper functions into array elements of this type.

Convert the code remaining of both functions into a short generic
of_message_print() function.

Refer to the latest OpenFlow 1.3 PDF and update comments to use section
numbers from that document.

openflow.h
print-openflow-1.0.c
print-openflow-1.3.c
print-openflow.c

index 996835b57b8bcf75dd17648aaf4a71b8b5284745..2d56d154a2bad0b668476894c6d7dae5aeaacd79 100644 (file)
@@ -72,15 +72,19 @@ extern void of_data_print(netdissect_options *ndo,
 /*
  * Routines to handle various versions of OpenFlow.
  */
-extern void of10_message_print(netdissect_options *ndo,
-       const u_char *, uint16_t, const uint8_t);
-extern void of13_message_print(netdissect_options *ndo,
-       const u_char *, uint16_t, const uint8_t);
 
-/*
- * Use this instead of ofpt_str[] and OFPT_ constants because OpenFlow
- * specifications define protocol encoding in C syntax, and different
- * versions clash on many names, including the OFPT_ constants.
- */
-extern const char * of10_msgtype_str(const uint8_t);
-extern const char * of13_msgtype_str(const uint8_t);
+struct of_msgtypeinfo {
+       /* Should not be NULL. */
+       const char *name;
+       /* May be NULL to mean "message body printing is not implemented". */
+       void (*decoder)(netdissect_options *ndo, const u_char *, const u_int);
+       enum {
+               REQ_NONE,   /* Message body length may be anything. */
+               REQ_FIXLEN, /* Message body length must be == req_value. */
+               REQ_MINLEN, /* Message body length must be >= req_value. */
+       } req_what;
+       uint16_t req_value;
+};
+
+extern const struct of_msgtypeinfo *of10_identify_msgtype(const uint8_t);
+extern const struct of_msgtypeinfo *of13_identify_msgtype(const uint8_t);
index 9001476f01319068012d6bed9b86c3020474d90f..1d9bcdaf8a286ac0fc33c98ecb2a23286a1ad140 100644 (file)
 #define OFPT_BARRIER_REPLY            0x13
 #define OFPT_QUEUE_GET_CONFIG_REQUEST 0x14
 #define OFPT_QUEUE_GET_CONFIG_REPLY   0x15
-static const struct tok ofpt_str[] = {
-       { OFPT_HELLO,                    "HELLO"                    },
-       { OFPT_ERROR,                    "ERROR"                    },
-       { OFPT_ECHO_REQUEST,             "ECHO_REQUEST"             },
-       { OFPT_ECHO_REPLY,               "ECHO_REPLY"               },
-       { OFPT_VENDOR,                   "VENDOR"                   },
-       { OFPT_FEATURES_REQUEST,         "FEATURES_REQUEST"         },
-       { OFPT_FEATURES_REPLY,           "FEATURES_REPLY"           },
-       { OFPT_GET_CONFIG_REQUEST,       "GET_CONFIG_REQUEST"       },
-       { OFPT_GET_CONFIG_REPLY,         "GET_CONFIG_REPLY"         },
-       { OFPT_SET_CONFIG,               "SET_CONFIG"               },
-       { OFPT_PACKET_IN,                "PACKET_IN"                },
-       { OFPT_FLOW_REMOVED,             "FLOW_REMOVED"             },
-       { OFPT_PORT_STATUS,              "PORT_STATUS"              },
-       { OFPT_PACKET_OUT,               "PACKET_OUT"               },
-       { OFPT_FLOW_MOD,                 "FLOW_MOD"                 },
-       { OFPT_PORT_MOD,                 "PORT_MOD"                 },
-       { OFPT_STATS_REQUEST,            "STATS_REQUEST"            },
-       { OFPT_STATS_REPLY,              "STATS_REPLY"              },
-       { OFPT_BARRIER_REQUEST,          "BARRIER_REQUEST"          },
-       { OFPT_BARRIER_REPLY,            "BARRIER_REPLY"            },
-       { OFPT_QUEUE_GET_CONFIG_REQUEST, "QUEUE_GET_CONFIG_REQUEST" },
-       { OFPT_QUEUE_GET_CONFIG_REPLY,   "QUEUE_GET_CONFIG_REPLY"   },
-       { 0, NULL }
-};
+#define OFPT_MAX                      OFPT_QUEUE_GET_CONFIG_REPLY
 
 #define OFPPC_PORT_DOWN    (1U <<0)
 #define OFPPC_NO_STP       (1U <<1)
@@ -697,12 +673,6 @@ static const struct tok bsn_onoff_str[] = {
        { 0, NULL },
 };
 
-/* [OF10] Section 5.1 */
-const char * of10_msgtype_str(const uint8_t type)
-{
-       return tok2str(ofpt_str, "invalid (0x%02x)", type);
-}
-
 static const char *
 vlan_str(const uint16_t vid)
 {
@@ -2127,169 +2097,191 @@ of10_error_print(netdissect_options *ndo,
        of_data_print(ndo, cp, len);
 }
 
-void
-of10_message_print(netdissect_options *ndo,
-                   const u_char *cp, uint16_t len, const uint8_t type)
-{
+static const struct of_msgtypeinfo of10_msgtypeinfo[OFPT_MAX + 1] = {
        /*
-        * Here "cp" and "len" stand for the message part beyond the common
-        * OpenFlow 1.0 header, if any.
-        *
-        * Most message types are longer than just the header, and the length
-        * constraints may be complex. When possible, validate the constraint
-        * completely here, otherwise check that the message is long enough to
-        * begin the decoding and let the lower-layer function do any remaining
-        * validation.
+        * [OF10] Section 5.5.1
+        * Variable-size data.
         */
-       switch (type) {
-       /* OpenFlow header only. */
-       case OFPT_FEATURES_REQUEST: /* [OF10] Section 5.3.1 */
-       case OFPT_GET_CONFIG_REQUEST: /* [OF10] Section 5.3.2 */
-       case OFPT_BARRIER_REQUEST: /* [OF10] Section 5.3.7 */
-       case OFPT_BARRIER_REPLY: /* ibid */
-               if (len)
-                       goto invalid;
-               return;
-
-       /* OpenFlow header and fixed-size message body. */
-       case OFPT_SET_CONFIG: /* [OF10] Section 5.3.2 */
-       case OFPT_GET_CONFIG_REPLY: /* ibid */
-               if (len != OF_SWITCH_CONFIG_FIXLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of10_switch_config_msg_print(ndo, cp, len);
-               return;
-       case OFPT_PORT_MOD:
-               if (len != OF_PORT_MOD_FIXLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of10_port_mod_print(ndo, cp, len);
-               return;
-       case OFPT_QUEUE_GET_CONFIG_REQUEST: /* [OF10] Section 5.3.4 */
-               if (len != OF_QUEUE_GET_CONFIG_REQUEST_FIXLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of10_queue_get_config_request_print(ndo, cp, len);
-               return;
-       case OFPT_FLOW_REMOVED:
-               if (len != OF_FLOW_REMOVED_FIXLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of10_flow_removed_print(ndo, cp, len);
-               return;
-       case OFPT_PORT_STATUS: /* [OF10] Section 5.4.3 */
-               if (len != OF_PORT_STATUS_FIXLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of10_port_status_print(ndo, cp, len);
-               return;
-
-       /* OpenFlow header, fixed-size message body and n * fixed-size data units. */
-       case OFPT_FEATURES_REPLY:
-               if (len < OF_FEATURES_REPLY_MINLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of10_features_reply_print(ndo, cp, len);
-               return;
-
-       /* OpenFlow header and variable-size data. */
-       case OFPT_HELLO: /* [OF10] Section 5.5.1 */
-       case OFPT_ECHO_REQUEST: /* [OF10] Section 5.5.2 */
-       case OFPT_ECHO_REPLY: /* [OF10] Section 5.5.3 */
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of_data_print(ndo, cp, len);
-               return;
-
-       /* OpenFlow header, fixed-size message body and variable-size data. */
-       case OFPT_ERROR:
-               if (len < OF_ERROR_MSG_MINLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of10_error_print(ndo, cp, len);
-               return;
-       case OFPT_VENDOR:
-               /* [OF10] Section 5.5.4 */
-               if (len < OF_VENDOR_MINLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of10_vendor_message_print(ndo, cp, len);
-               return;
-       case OFPT_PACKET_IN:
-               /* 2 mock octets count in OF_PACKET_IN_MINLEN but not in len */
-               if (len < OF_PACKET_IN_MINLEN - 2)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of10_packet_in_print(ndo, cp, len);
-               return;
-
-       /* a. OpenFlow header. */
-       /* b. OpenFlow header and one of the fixed-size message bodies. */
-       /* c. OpenFlow header, fixed-size message body and variable-size data. */
-       case OFPT_STATS_REQUEST:
-               if (len < OF_STATS_REQUEST_MINLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of10_stats_request_print(ndo, cp, len);
-               return;
-
-       /* a. OpenFlow header and fixed-size message body. */
-       /* b. OpenFlow header and n * fixed-size data units. */
-       /* c. OpenFlow header and n * variable-size data units. */
-       /* d. OpenFlow header, fixed-size message body and variable-size data. */
-       case OFPT_STATS_REPLY:
-               if (len < OF_STATS_REPLY_MINLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of10_stats_reply_print(ndo, cp, len);
-               return;
-
-       /* OpenFlow header and n * variable-size data units and variable-size data. */
-       case OFPT_PACKET_OUT:
-               if (len < OF_PACKET_OUT_MINLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of10_packet_out_print(ndo, cp, len);
-               return;
-
-       /* OpenFlow header, fixed-size message body and n * variable-size data units. */
-       case OFPT_FLOW_MOD:
-               if (len < OF_FLOW_MOD_MINLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of10_flow_mod_print(ndo, cp, len);
-               return;
-
-       /* OpenFlow header, fixed-size message body and n * variable-size data units. */
-       case OFPT_QUEUE_GET_CONFIG_REPLY: /* [OF10] Section 5.3.4 */
-               if (len < OF_QUEUE_GET_CONFIG_REPLY_MINLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of10_queue_get_config_reply_print(ndo, cp, len);
-               return;
-       } /* switch (type) */
+       {
+               "HELLO",                    of_data_print,
+               REQ_MINLEN,                 0
+       },
        /*
-        * Not a recognised type or did not print the details, fall back to
-        * a bounds check.
+        * [OF10] Section 5.4.4
+        * A fixed-size message body and variable-size data.
         */
-       ND_TCHECK_LEN(cp, len);
-       return;
+       {
+               "ERROR",                    of10_error_print,
+               REQ_MINLEN,                 OF_ERROR_MSG_MINLEN
+       },
+       /*
+        * [OF10] Section 5.5.2
+        * Variable-size data.
+        */
+       {
+               "ECHO_REQUEST",             of_data_print,
+               REQ_MINLEN,                 0
+       },
+       /*
+        * [OF10] Section 5.5.3
+        * Variable-size data.
+        */
+       {
+               "ECHO_REPLY",               of_data_print,
+               REQ_MINLEN,                 0
+       },
+       /*
+        * [OF10] Section 5.5.4
+        * A fixed-size message body and variable-size data.
+        */
+       {
+               "VENDOR",                   of10_vendor_message_print,
+               REQ_MINLEN,                 OF_VENDOR_MINLEN
+       },
+       /*
+        * [OF10] Section 5.3.1
+        * No message body.
+        */
+       {
+               "FEATURES_REQUEST",         NULL,
+               REQ_FIXLEN,                 0
+       },
+       /*
+        * [OF10] Section 5.3.1
+        * A fixed-size message body and n * fixed-size data units.
+        */
+       {
+               "FEATURES_REPLY",           of10_features_reply_print,
+               REQ_MINLEN,                 OF_FEATURES_REPLY_MINLEN
+       },
+       /*
+        * [OF10] Section 5.3.2
+        * No message body.
+        */
+       {
+               "GET_CONFIG_REQUEST",       NULL,
+               REQ_FIXLEN,                 0
+       },
+       /*
+        * [OF10] Section 5.3.2
+        * A fixed-size message body.
+        */
+       {
+               "GET_CONFIG_REPLY",         of10_switch_config_msg_print,
+               REQ_FIXLEN,                 OF_SWITCH_CONFIG_FIXLEN
+       },
+       /*
+        * [OF10] Section 5.3.2
+        * A fixed-size message body.
+        */
+       {
+               "SET_CONFIG",               of10_switch_config_msg_print,
+               REQ_FIXLEN,                 OF_SWITCH_CONFIG_FIXLEN
+       },
+       /*
+        * [OF10] Section 5.4.1
+        * A fixed-size message body and variable-size data.
+        * (The 2 mock octets count in OF_PACKET_IN_MINLEN only.)
+        */
+       {
+               "PACKET_IN",                of10_packet_in_print,
+               REQ_MINLEN,                 OF_PACKET_IN_MINLEN - 2
+       },
+       /*
+        * [OF10] Section 5.4.2
+        * A fixed-size message body.
+        */
+       {
+               "FLOW_REMOVED",             of10_flow_removed_print,
+               REQ_FIXLEN,                 OF_FLOW_REMOVED_FIXLEN
+       },
+       /*
+        * [OF10] Section 5.4.3
+        * A fixed-size message body.
+        */
+       {
+               "PORT_STATUS",              of10_port_status_print,
+               REQ_FIXLEN,                 OF_PORT_STATUS_FIXLEN
+       },
+       /*
+        * [OF10] Section 5.3.6
+        * A fixed-size message body, n * variable-size data units and
+        * variable-size data.
+        */
+       {
+               "PACKET_OUT",               of10_packet_out_print,
+               REQ_MINLEN,                 OF_PACKET_OUT_MINLEN
+       },
+       /*
+        * [OF10] Section 5.3.3
+        * A fixed-size message body and n * variable-size data units.
+        */
+       {
+               "FLOW_MOD",                 of10_flow_mod_print,
+               REQ_MINLEN,                 OF_FLOW_MOD_MINLEN
+       },
+       /*
+        * [OF10] Section 5.3.3
+        * A fixed-size message body.
+        */
+       {
+               "PORT_MOD",                 of10_port_mod_print,
+               REQ_FIXLEN,                 OF_PORT_MOD_FIXLEN
+       },
+       /*
+        * [OF10] Section 5.3.5
+        * A fixed-size message body and possibly more data of varying size
+        * and structure.
+        */
+       {
+               "STATS_REQUEST",            of10_stats_request_print,
+               REQ_MINLEN,                 OF_STATS_REQUEST_MINLEN
+       },
+       /*
+        * [OF10] Section 5.3.5
+        * A fixed-size message body and possibly more data of varying size
+        * and structure.
+        */
+       {
+               "STATS_REPLY",              of10_stats_reply_print,
+               REQ_MINLEN,                 OF_STATS_REPLY_MINLEN
+       },
+       /*
+        * [OF10] Section 5.3.7
+        * No message body.
+        */
+       {
+               "BARRIER_REQUEST",          NULL,
+               REQ_FIXLEN,                 0
+       },
+       /*
+        * [OF10] Section 5.3.7
+        * No message body.
+        */
+       {
+               "BARRIER_REPLY",            NULL,
+               REQ_FIXLEN,                 0
+       },
+       /*
+        * [OF10] Section 5.3.4
+        * A fixed-size message body.
+        */
+       {
+               "QUEUE_GET_CONFIG_REQUEST", of10_queue_get_config_request_print,
+               REQ_FIXLEN,                 OF_QUEUE_GET_CONFIG_REQUEST_FIXLEN
+       },
+       /*
+        * [OF10] Section 5.3.4
+        * A fixed-size message body and n * variable-size data units.
+        */
+       {
+               "QUEUE_GET_CONFIG_REPLY",   of10_queue_get_config_reply_print,
+               REQ_MINLEN,                 OF_QUEUE_GET_CONFIG_REPLY_MINLEN
+       },
+};
 
-invalid: /* skip the message body */
-       nd_print_invalid(ndo);
-       ND_TCHECK_LEN(cp, len);
+const struct of_msgtypeinfo *
+of10_identify_msgtype(const uint8_t type)
+{
+       return type <= OFPT_MAX ? &of10_msgtypeinfo[type] : NULL;
 }
index 1f66d45f5d7e1db34c4bfdc1799710f206691edc..79de7d7b9999205bf3d9e86bc7fd584ed16e4eb5 100644 (file)
@@ -3,7 +3,7 @@
  * protocol 0x04). It is based on the implementation conventions explained in
  * print-openflow-1.0.c.
  *
- * [OF13] https://www.opennetworking.org/wp-content/uploads/2014/10/openflow-switch-v1.3.4.pdf
+ * [OF13] https://www.opennetworking.org/wp-content/uploads/2014/10/openflow-switch-v1.3.5.pdf
  *
  * Copyright (c) 2020 The TCPDUMP project
  * All rights reserved.
 #define OFPT_GET_ASYNC_REPLY          27U
 #define OFPT_SET_ASYNC                28U
 #define OFPT_METER_MOD                29U
-static const struct tok ofpt_str[] = {
-       { OFPT_HELLO,                    "HELLO"                    },
-       { OFPT_ERROR,                    "ERROR"                    },
-       { OFPT_ECHO_REQUEST,             "ECHO_REQUEST"             },
-       { OFPT_ECHO_REPLY,               "ECHO_REPLY"               },
-       { OFPT_EXPERIMENTER,             "EXPERIMENTER"             },
-       { OFPT_FEATURES_REQUEST,         "FEATURES_REQUEST"         },
-       { OFPT_FEATURES_REPLY,           "FEATURES_REPLY"           },
-       { OFPT_GET_CONFIG_REQUEST,       "GET_CONFIG_REQUEST"       },
-       { OFPT_GET_CONFIG_REPLY,         "GET_CONFIG_REPLY"         },
-       { OFPT_SET_CONFIG,               "SET_CONFIG"               },
-       { OFPT_PACKET_IN,                "PACKET_IN"                },
-       { OFPT_FLOW_REMOVED,             "FLOW_REMOVED"             },
-       { OFPT_PORT_STATUS,              "PORT_STATUS"              },
-       { OFPT_PACKET_OUT,               "PACKET_OUT"               },
-       { OFPT_FLOW_MOD,                 "FLOW_MOD"                 },
-       { OFPT_GROUP_MOD,                "GROUP_MOD"                },
-       { OFPT_PORT_MOD,                 "PORT_MOD"                 },
-       { OFPT_TABLE_MOD,                "TABLE_MOD"                },
-       { OFPT_MULTIPART_REQUEST,        "MULTIPART_REQUEST"        },
-       { OFPT_MULTIPART_REPLY,          "MULTIPART_REPLY"          },
-       { OFPT_BARRIER_REQUEST,          "BARRIER_REQUEST"          },
-       { OFPT_BARRIER_REPLY,            "BARRIER_REPLY"            },
-       { OFPT_QUEUE_GET_CONFIG_REQUEST, "QUEUE_GET_CONFIG_REQUEST" },
-       { OFPT_QUEUE_GET_CONFIG_REPLY,   "QUEUE_GET_CONFIG_REPLY"   },
-       { OFPT_ROLE_REQUEST,             "ROLE_REQUEST"             },
-       { OFPT_ROLE_REPLY,               "ROLE_REPLY"               },
-       { OFPT_GET_ASYNC_REQUEST,        "GET_ASYNC_REQUEST"        },
-       { OFPT_GET_ASYNC_REPLY,          "GET_ASYNC_REPLY"          },
-       { OFPT_SET_ASYNC,                "SET_ASYNC"                },
-       { OFPT_METER_MOD,                "METER_MOD"                },
-       { 0, NULL }
-};
+#define OFPT_MAX                      OFPT_METER_MOD
 
 #define OFPC_FLOW_STATS   (1U <<0)
 #define OFPC_TABLE_STATS  (1U <<1)
@@ -675,13 +643,6 @@ static const struct uint_tokary of13_ofpet2tokary[] = {
 /* miscellaneous constants from [OF13] */
 #define OFP_MAX_PORT_NAME_LEN                 16U
 
-/* [OF13] Section A.1 */
-const char *
-of13_msgtype_str(const uint8_t type)
-{
-       return tok2str(ofpt_str, "invalid (0x%02x)", type);
-}
-
 /* [OF13] Section 7.2.1 */
 static void
 of13_port_print(netdissect_options *ndo,
@@ -960,7 +921,7 @@ of13_experimenter_message_print(netdissect_options *ndo,
        of_data_print(ndo, cp, len);
 }
 
-/* [OF13] Section A.3.6 */
+/* [OF13] Section 7.3.6 */
 static void
 of13_queue_get_config_request_print(netdissect_options *ndo,
                                     const u_char *cp, u_int len _U_)
@@ -973,7 +934,7 @@ of13_queue_get_config_request_print(netdissect_options *ndo,
        ND_TCHECK_4(cp);
 }
 
-/* [OF13] Section A.4.4 */
+/* [OF13] Section 7.4.4 */
 static void
 of13_error_print(netdissect_options *ndo,
                  const u_char *cp, u_int len)
@@ -998,122 +959,251 @@ of13_error_print(netdissect_options *ndo,
        of_data_print(ndo, cp, len);
 }
 
-void
-of13_message_print(netdissect_options *ndo,
-                   const u_char *cp, uint16_t len, const uint8_t type)
-{
-       /* See the comment at the beginning of of10_message_print(). */
-       switch (type) {
-       /* OpenFlow header only. */
-       case OFPT_FEATURES_REQUEST: /* [OF13] Section A.3.1 */
-       case OFPT_GET_CONFIG_REQUEST: /* [OF13] Section A.3.2 */
-       case OFPT_BARRIER_REQUEST: /* [OF13] Section A.3.8 */
-       case OFPT_BARRIER_REPLY: /* ibid */
-       case OFPT_GET_ASYNC_REQUEST: /* [OF13] Section 7.3.10 */
-               if (len)
-                       goto invalid;
-               return;
-
-       /* OpenFlow header and fixed-size message body. */
-       case OFPT_FEATURES_REPLY:
-               if (len != OF_FEATURES_REPLY_FIXLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of13_features_reply_print(ndo, cp, len);
-               return;
-       case OFPT_QUEUE_GET_CONFIG_REQUEST: /* [OF13] Section A.3.6 */
-               if (len != OF_QUEUE_GET_CONFIG_REQUEST_FIXLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of13_queue_get_config_request_print(ndo, cp, len);
-               return;
-       case OFPT_GET_CONFIG_REPLY: /* [OF13] Section 7.3.2 */
-       case OFPT_SET_CONFIG: /* ibid */
-               if (len != OF_SWITCH_CONFIG_MSG_FIXLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of13_switch_config_msg_print(ndo, cp, len);
-               return;
-       case OFPT_PORT_MOD: /* [OF13] Section 7.3.4.3 */
-               if (len != OF_PORT_MOD_FIXLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of13_port_mod_print(ndo, cp, len);
-               return;
-       case OFPT_ROLE_REQUEST: /* [OF13] Section 7.3.9 */
-       case OFPT_ROLE_REPLY: /* ibid */
-               if (len != OF_ROLE_MSG_FIXLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of13_role_msg_print(ndo, cp, len);
-               return;
-       case OFPT_PORT_STATUS: /* [OF13] Section 7.4.3 */
-               if (len != OF_PORT_STATUS_FIXLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of13_port_status_print(ndo, cp, len);
-               return;
-       case OFPT_TABLE_MOD: /* [OF13] Section 7.3.3 */
-               if (len != OF_TABLE_MOD_FIXLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of13_table_mod_print(ndo, cp, len);
-               return;
-       case OFPT_SET_ASYNC: /* [OF13] Section 7.3.10 */
-       case OFPT_GET_ASYNC_REPLY: /* ibid */
-               if (len != OF_ASYNC_MSG_FIXLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of13_async_msg_print(ndo, cp, len);
-               return;
-
-       /* OpenFlow header and variable-size data. */
-       case OFPT_ECHO_REQUEST: /* [OF13] Section A.5.2 */
-       case OFPT_ECHO_REPLY: /* [OF13] Section A.5.3 */
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of_data_print(ndo, cp, len);
-               return;
-
-       /* OpenFlow header and n * variable-size data units. */
-       case OFPT_HELLO: /* [OF13] Section A.5.1 */
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of13_hello_elements_print(ndo, cp, len);
-               return;
-
-       /* OpenFlow header, fixed-size message body and variable-size data. */
-       case OFPT_ERROR:
-               if (len < OF_ERROR_MSG_MINLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of13_error_print(ndo, cp, len);
-               return;
-       case OFPT_EXPERIMENTER: /* [OF13] Section 7.5.4 */
-               if (len < OF_EXPERIMENTER_MSG_MINLEN)
-                       goto invalid;
-               if (ndo->ndo_vflag < 1)
-                       break;
-               of13_experimenter_message_print(ndo, cp, len);
-               return;
-       }
+static const struct of_msgtypeinfo of13_msgtypeinfo[OFPT_MAX + 1] = {
        /*
-        * Not a recognised type or did not print the details, fall back to
-        * a bounds check.
+        * [OF13] Section 7.5.1
+        * n * variable-size data units.
         */
-       ND_TCHECK_LEN(cp, len);
-       return;
+       {
+               "HELLO",                    of13_hello_elements_print,
+               REQ_MINLEN,                 0
+       },
+       /*
+        * [OF13] Section 7.4.4
+        * A fixed-size message body and variable-size data.
+        */
+       {
+               "ERROR",                    of13_error_print,
+               REQ_MINLEN,                 OF_ERROR_MSG_MINLEN
+       },
+       /*
+        * [OF13] Section 7.5.2
+        * Variable-size data.
+        */
+       {
+               "ECHO_REQUEST",             of_data_print,
+               REQ_MINLEN,                 0
+       },
+       /*
+        * [OF13] Section 7.5.3
+        * Variable-size data.
+        */
+       {
+               "ECHO_REPLY",               of_data_print,
+               REQ_MINLEN,                 0
+       },
+       /*
+        * [OF13] Section 7.5.4
+        * A fixed-size message body and variable-size data.
+        */
+       {
+               "EXPERIMENTER",             of13_experimenter_message_print,
+               REQ_MINLEN,                 OF_EXPERIMENTER_MSG_MINLEN
+       },
+       /*
+        * [OF13] Section 7.3.1
+        * No message body.
+        */
+       {
+               "FEATURES_REQUEST",         NULL,
+               REQ_FIXLEN,                 0
+       },
+       /*
+        * [OF13] Section 7.3.1
+        * A fixed-size message body.
+        */
+       {
+               "FEATURES_REPLY",           of13_features_reply_print,
+               REQ_FIXLEN,                 OF_FEATURES_REPLY_FIXLEN
+       },
+       /*
+        * [OF13] Section 7.3.2
+        * No message body.
+        */
+       {
+               "GET_CONFIG_REQUEST",       NULL,
+               REQ_FIXLEN,                 0
+       },
+       /*
+        * [OF13] Section 7.3.2
+        * A fixed-size message body.
+        */
+       {
+               "GET_CONFIG_REPLY",         of13_switch_config_msg_print,
+               REQ_FIXLEN,                 OF_SWITCH_CONFIG_MSG_FIXLEN
+       },
+       /*
+        * [OF13] Section 7.3.2
+        * A fixed-size message body.
+        */
+       {
+               "SET_CONFIG",               of13_switch_config_msg_print,
+               REQ_FIXLEN,                 OF_SWITCH_CONFIG_MSG_FIXLEN
+       },
+       /*
+        * [OF13] Section 7.4.1
+        * (to be done)
+        */
+       {
+               "PACKET_IN",                NULL,
+               REQ_NONE,                   0
+       },
+       /*
+        * [OF13] Section 7.4.2
+        * (to be done)
+        */
+       {
+               "FLOW_REMOVED",             NULL,
+               REQ_NONE,                   0
+       },
+       /*
+        * [OF13] Section 7.4.3
+        * A fixed-size message body.
+        */
+       {
+               "PORT_STATUS",              of13_port_status_print,
+               REQ_FIXLEN,                 OF_PORT_STATUS_FIXLEN
+       },
+       /*
+        * [OF13] Section 7.3.7
+        * (to be done)
+        */
+       {
+               "PACKET_OUT",               NULL,
+               REQ_NONE,                   0
+       },
+       /*
+        * [OF13] Section 7.3.4.1
+        * (to be done)
+        */
+       {
+               "FLOW_MOD",                 NULL,
+               REQ_NONE,                   0
+       },
+       /*
+        * [OF13] Section 7.3.4.2
+        * (to be done)
+        */
+       {
+               "GROUP_MOD",                NULL,
+               REQ_NONE,                   0
+       },
+       /*
+        * [OF13] Section 7.3.4.3
+        * A fixed-size message body.
+        */
+       {
+               "PORT_MOD",                 of13_port_mod_print,
+               REQ_FIXLEN,                 OF_PORT_MOD_FIXLEN
+       },
+       /*
+        * [OF13] Section 7.3.3
+        * A fixed-size message body.
+        */
+       {
+               "TABLE_MOD",                of13_table_mod_print,
+               REQ_FIXLEN,                 OF_TABLE_MOD_FIXLEN
+       },
+       /*
+        * [OF13] Section 7.3.5
+        * (to be done)
+        */
+       {
+               "MULTIPART_REQUEST",        NULL,
+               REQ_NONE,                   0
+       },
+       /*
+        * [OF13] Section 7.3.5
+        * (to be done)
+        */
+       {
+               "MULTIPART_REPLY",          NULL,
+               REQ_NONE,                   0
+       },
+       /*
+        * [OF13] Section 7.3.8
+        * No message body.
+        */
+       {
+               "BARRIER_REQUEST",          NULL,
+               REQ_FIXLEN,                 0
+       },
+       /*
+        * [OF13] Section 7.3.8
+        * No message body.
+        */
+       {
+               "BARRIER_REPLY",            NULL,
+               REQ_FIXLEN,                 0
+       },
+       /*
+        * [OF13] Section 7.3.6
+        * A fixed-size message body.
+        */
+       {
+               "QUEUE_GET_CONFIG_REQUEST", of13_queue_get_config_request_print,
+               REQ_FIXLEN,                 OF_QUEUE_GET_CONFIG_REQUEST_FIXLEN
+       },
+       /*
+        * [OF13] Section 7.3.6
+        * (to be done)
+        */
+       {
+               "QUEUE_GET_CONFIG_REPLY",   NULL,
+               REQ_NONE,                   0
+       },
+       /*
+        * [OF13] Section 7.3.9
+        * A fixed-size message body.
+        */
+       {
+               "ROLE_REQUEST",             of13_role_msg_print,
+               REQ_FIXLEN,                 OF_ROLE_MSG_FIXLEN
+       },
+       /*
+        * [OF13] Section 7.3.9
+        * A fixed-size message body.
+        */
+       {
+               "ROLE_REPLY",               of13_role_msg_print,
+               REQ_FIXLEN,                 OF_ROLE_MSG_FIXLEN
+       },
+       /*
+        * [OF13] Section 7.3.10
+        * No message body.
+        */
+       {
+               "GET_ASYNC_REQUEST",        NULL,
+               REQ_FIXLEN,                 0
+       },
+       /*
+        * [OF13] Section 7.3.10
+        * A fixed-size message body.
+        */
+       {
+               "GET_ASYNC_REPLY",          of13_async_msg_print,
+               REQ_FIXLEN,                 OF_ASYNC_MSG_FIXLEN
+       },
+       /*
+        * [OF13] Section 7.3.10
+        * A fixed-size message body.
+        */
+       {
+               "SET_ASYNC",                of13_async_msg_print,
+               REQ_FIXLEN,                 OF_ASYNC_MSG_FIXLEN
+       },
+       /*
+        * [OF13] Section 7.3.4.4
+        * (to be done)
+        */
+       {
+               "METER_MOD",                NULL,
+               REQ_NONE,                   0
+       },
+};
 
-invalid: /* skip the message body */
-       nd_print_invalid(ndo);
-       ND_TCHECK_LEN(cp, len);
+const struct of_msgtypeinfo *
+of13_identify_msgtype(const uint8_t type)
+{
+       return type <= OFPT_MAX ? &of13_msgtypeinfo[type] : NULL;
 }
index 935c65264f9979a906f2c0e6b2564aaf49d6e062..6024a215a133d593e22ba652575e6e6d0c8bb3e3 100644 (file)
@@ -103,6 +103,41 @@ of_data_print(netdissect_options *ndo,
                ND_TCHECK_LEN(cp, len);
 }
 
+static void
+of_message_print(netdissect_options *ndo,
+                 const u_char *cp, uint16_t len,
+                 const struct of_msgtypeinfo *mti)
+{
+       /*
+        * Here "cp" and "len" stand for the message part beyond the common
+        * OpenFlow 1.0 header, if any.
+        *
+        * Most message types are longer than just the header, and the length
+        * constraints may be complex. When possible, validate the constraint
+        * completely here (REQ_FIXLEN), otherwise check that the message is
+        * long enough to begin the decoding (REQ_MINLEN) and have the
+        * type-specific function do any remaining validation.
+        */
+
+       if (!mti)
+               goto tcheck_remainder;
+
+       if ((mti->req_what == REQ_FIXLEN && len != mti->req_value) ||
+           (mti->req_what == REQ_MINLEN && len <  mti->req_value))
+               goto invalid;
+
+       if (!ndo->ndo_vflag || !mti->decoder)
+               goto tcheck_remainder;
+
+       mti->decoder(ndo, cp, len);
+       return;
+
+invalid:
+       nd_print_invalid(ndo);
+tcheck_remainder:
+       ND_TCHECK_LEN(cp, len);
+}
+
 /* Print a TCP segment worth of OpenFlow messages presuming the segment begins
  * on a message boundary. */
 void
@@ -114,8 +149,7 @@ openflow_print(netdissect_options *ndo, const u_char *cp, u_int len)
                /* Print a single OpenFlow message. */
                uint8_t version, type;
                uint16_t length;
-               void (*decoder)(struct netdissect_options *,
-                               const u_char *, uint16_t, const uint8_t) = NULL;
+               const struct of_msgtypeinfo *mti;
 
                /* version */
                version = GET_U_1(cp);
@@ -127,18 +161,14 @@ openflow_print(netdissect_options *ndo, const u_char *cp, u_int len)
                        goto partial_header;
                type = GET_U_1(cp);
                OF_FWD(1);
-               switch (version) {
-               case OF_VER_1_0:
-                       ND_PRINT(", type %s", of10_msgtype_str(type));
-                       decoder = of10_message_print;
-                       break;
-               case OF_VER_1_3:
-                       ND_PRINT(", type %s", of13_msgtype_str(type));
-                       decoder = of13_message_print;
-                       break;
-               default:
+               mti =
+                       version == OF_VER_1_0 ? of10_identify_msgtype(type) :
+                       version == OF_VER_1_3 ? of13_identify_msgtype(type) :
+                       NULL;
+               if (mti && mti->name)
+                       ND_PRINT(", type %s", mti->name);
+               else
                        ND_PRINT(", type unknown (0x%02x)", type);
-               }
                /* length */
                if (len < 2)
                        goto partial_header;
@@ -181,10 +211,7 @@ openflow_print(netdissect_options *ndo, const u_char *cp, u_int len)
                if (length < OF_HEADER_FIXLEN)
                        goto invalid;
 
-               if (decoder != NULL)
-                       decoder(ndo, cp, length - OF_HEADER_FIXLEN, type);
-               else
-                       ND_TCHECK_LEN(cp, length - OF_HEADER_FIXLEN);
+               of_message_print(ndo, cp, length - OF_HEADER_FIXLEN, mti);
                if (length - OF_HEADER_FIXLEN > len)
                        break;
                OF_FWD(length - OF_HEADER_FIXLEN);