diff options
author | Denis Ovsienko <denis@ovsienko.info> | 2020-10-05 00:54:33 +0100 |
---|---|---|
committer | Denis Ovsienko <denis@ovsienko.info> | 2020-10-08 15:55:29 +0100 |
commit | e379a5690f6db797179fa5e0845ff731db2a7af7 (patch) | |
tree | 34e1dd0bcd653494e5c7a711c65f2e569eb405bb | |
parent | 140fac9cf1cc24d15f47d8edf06277781301e8cd (diff) | |
download | tcpdump-e379a5690f6db797179fa5e0845ff731db2a7af7.tar.gz |
OpenFlow: Process message types via declarations.
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.
-rw-r--r-- | openflow.h | 26 | ||||
-rw-r--r-- | print-openflow-1.0.c | 374 | ||||
-rw-r--r-- | print-openflow-1.3.c | 406 | ||||
-rw-r--r-- | print-openflow.c | 61 |
4 files changed, 490 insertions, 377 deletions
@@ -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); diff --git a/print-openflow-1.0.c b/print-openflow-1.0.c index 9001476f..1d9bcdaf 100644 --- a/print-openflow-1.0.c +++ b/print-openflow-1.0.c @@ -97,31 +97,7 @@ #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; } diff --git a/print-openflow-1.3.c b/print-openflow-1.3.c index 1f66d45f..79de7d7b 100644 --- a/print-openflow-1.3.c +++ b/print-openflow-1.3.c @@ -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. @@ -75,39 +75,7 @@ #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; } diff --git a/print-openflow.c b/print-openflow.c index 935c6526..6024a215 100644 --- a/print-openflow.c +++ b/print-openflow.c @@ -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); |