X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/78a0b1c982c67e11de5b3b4444397231ea807ef6..refs/pull/433/head:/print-openflow-1.0.c diff --git a/print-openflow-1.0.c b/print-openflow-1.0.c index c6ba6a93..6e50803b 100644 --- a/print-openflow-1.0.c +++ b/print-openflow-1.0.c @@ -8,6 +8,16 @@ * * [OF10] http://www.openflow.org/documents/openflow-spec-v1.0.0.pdf * + * Most functions in this file take 3 arguments into account: + * * cp -- the pointer to the first octet to decode + * * len -- the length of the current structure as declared on the wire + * * ep -- the pointer to the end of the captured frame + * They return either the pointer to the next not-yet-decoded part of the frame + * or the value of ep, which means the current frame processing is over as it + * has been fully decoded or is malformed or truncated. This way it is possible + * to chain and nest such functions uniformly to decode an OF1.0 message, which + * consists of several layers of nested structures. + * * Decoding of Ethernet frames nested in OFPT_PACKET_IN and OFPT_PACKET_OUT * messages is done only when the verbosity level set by command-line argument * is "-vvv" or higher. In that case the verbosity level is temporarily @@ -16,7 +26,8 @@ * the nested frames. * * Partial decoding of Big Switch Networks vendor extensions is done after the - * oftest (OpenFlow Testing Framework) source code. + * oftest (OpenFlow Testing Framework) and Loxigen (library generator) source + * code. * * * Copyright (c) 2013 The TCPDUMP project @@ -629,6 +640,9 @@ static const struct tok bsn_subtype_str[] = { { BSN_SET_MIRRORING, "SET_MIRRORING" }, { BSN_GET_MIRRORING_REQUEST, "GET_MIRRORING_REQUEST" }, { BSN_GET_MIRRORING_REPLY, "GET_MIRRORING_REPLY" }, + { BSN_SHELL_COMMAND, "SHELL_COMMAND" }, + { BSN_SHELL_OUTPUT, "SHELL_OUTPUT" }, + { BSN_SHELL_STATUS, "SHELL_STATUS" }, { BSN_GET_INTERFACES_REQUEST, "GET_INTERFACES_REQUEST" }, { BSN_GET_INTERFACES_REPLY, "GET_INTERFACES_REPLY" }, { BSN_SET_PKTIN_SUPPRESSION_REQUEST, "SET_PKTIN_SUPPRESSION_REQUEST" }, @@ -657,6 +671,29 @@ static const struct tok bsn_subtype_str[] = { { 0, NULL } }; +#define BSN_ACTION_MIRROR 1 +#define BSN_ACTION_SET_TUNNEL_DST 2 + /* 3 */ +#define BSN_ACTION_CHECKSUM 4 + +static const struct tok bsn_action_subtype_str[] = { + { BSN_ACTION_MIRROR, "MIRROR" }, + { BSN_ACTION_SET_TUNNEL_DST, "SET_TUNNEL_DST" }, + { BSN_ACTION_CHECKSUM, "CHECKSUM" }, + { 0, NULL } +}; + +static const struct tok bsn_mirror_copy_stage_str[] = { + { 0, "INGRESS" }, + { 1, "EGRESS" }, + { 0, NULL }, +}; + +static const struct tok bsn_onoff_str[] = { + { 0, "OFF" }, + { 1, "ON" }, + { 0, NULL }, +}; static const char * vlan_str(const uint16_t vid) { @@ -785,21 +822,25 @@ of10_bsn_message_print(netdissect_options *ndo, * +---------------+---------------+---------------+---------------+ * | subtype | * +---------------+---------------+---------------+---------------+ - * | ports | pad | + * | report m. p. | pad | * +---------------+---------------+---------------+---------------+ * */ if (len != 8) goto corrupt; - /* ports */ + /* report_mirror_ports */ ND_TCHECK2(*cp, 1); - ND_PRINT((ndo, ", ports %u", *cp)); + ND_PRINT((ndo, ", report_mirror_ports %s", tok2str(bsn_onoff_str, "bogus (%u)", *cp))); cp += 1; /* pad */ ND_TCHECK2(*cp, 3); cp += 3; break; case BSN_GET_INTERFACES_REQUEST: + case BSN_GET_L2_TABLE_REQUEST: + case BSN_BW_ENABLE_GET_REQUEST: + case BSN_BW_CLEAR_DATA_REQUEST: + case BSN_HYBRID_GET_REQUEST: /* * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 @@ -811,6 +852,92 @@ of10_bsn_message_print(netdissect_options *ndo, if (len != 4) goto corrupt; break; + case BSN_VIRTUAL_PORT_REMOVE_REQUEST: + /* + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +---------------+---------------+---------------+---------------+ + * | subtype | + * +---------------+---------------+---------------+---------------+ + * | vport_no | + * +---------------+---------------+---------------+---------------+ + * + */ + if (len != 8) + goto corrupt; + /* vport_no */ + ND_TCHECK2(*cp, 4); + ND_PRINT((ndo, ", vport_no %u", EXTRACT_32BITS(cp))); + cp += 4; + break; + case BSN_SHELL_COMMAND: + /* + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +---------------+---------------+---------------+---------------+ + * | subtype | + * +---------------+---------------+---------------+---------------+ + * | service | + * +---------------+---------------+---------------+---------------+ + * | data ... + * +---------------+---------------+-------- + * + */ + if (len < 8) + goto corrupt; + /* service */ + ND_TCHECK2(*cp, 4); + ND_PRINT((ndo, ", service %u", EXTRACT_32BITS(cp))); + cp += 4; + /* data */ + ND_PRINT((ndo, ", data '")); + if (fn_printn(ndo, cp, len - 8, ep)) { + ND_PRINT((ndo, "'")); + goto trunc; + } + ND_PRINT((ndo, "'")); + cp += len - 8; + break; + case BSN_SHELL_OUTPUT: + /* + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +---------------+---------------+---------------+---------------+ + * | subtype | + * +---------------+---------------+---------------+---------------+ + * | data ... + * +---------------+---------------+-------- + * + */ + if (len < 4) + goto corrupt; + /* data */ + ND_PRINT((ndo, ", data '")); + if (fn_printn(ndo, cp, len - 4, ep)) { + ND_PRINT((ndo, "'")); + goto trunc; + } + ND_PRINT((ndo, "'")); + cp += len - 4; + break; + case BSN_SHELL_STATUS: + /* + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +---------------+---------------+---------------+---------------+ + * | subtype | + * +---------------+---------------+---------------+---------------+ + * | status | + * +---------------+---------------+---------------+---------------+ + * + */ + if (len != 8) + goto corrupt; + /* status */ + ND_TCHECK2(*cp, 4); + ND_PRINT((ndo, ", status 0x%08x", EXTRACT_32BITS(cp))); + cp += 4; + break; default: ND_TCHECK2(*cp, len - 4); cp += len - 4; @@ -826,6 +953,107 @@ trunc: return ep; } +static const u_char * +of10_bsn_actions_print(netdissect_options *ndo, + const u_char *cp, const u_char *ep, const u_int len) { + const u_char *cp0 = cp; + uint32_t subtype, vlan_tag; + + if (len < 4) + goto corrupt; + /* subtype */ + ND_TCHECK2(*cp, 4); + subtype = EXTRACT_32BITS(cp); + cp += 4; + ND_PRINT((ndo, "\n\t subtype %s", tok2str(bsn_action_subtype_str, "unknown (0x%08x)", subtype))); + switch (subtype) { + case BSN_ACTION_MIRROR: + /* + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +---------------+---------------+---------------+---------------+ + * | subtype | + * +---------------+---------------+---------------+---------------+ + * | dest_port | + * +---------------+---------------+---------------+---------------+ + * | vlan_tag | + * +---------------+---------------+---------------+---------------+ + * | copy_stage | pad | + * +---------------+---------------+---------------+---------------+ + * + */ + if (len != 16) + goto corrupt; + /* dest_port */ + ND_TCHECK2(*cp, 4); + ND_PRINT((ndo, ", dest_port %u", EXTRACT_32BITS(cp))); + cp += 4; + /* vlan_tag */ + ND_TCHECK2(*cp, 4); + vlan_tag = EXTRACT_32BITS(cp); + cp += 4; + switch (vlan_tag >> 16) { + case 0: + ND_PRINT((ndo, ", vlan_tag none")); + break; + case ETHERTYPE_8021Q: + ND_PRINT((ndo, ", vlan_tag 802.1Q (%s)", ieee8021q_tci_string(vlan_tag & 0xffff))); + break; + default: + ND_PRINT((ndo, ", vlan_tag unknown (0x%04x)", vlan_tag >> 16)); + } + /* copy_stage */ + ND_TCHECK2(*cp, 1); + ND_PRINT((ndo, ", copy_stage %s", tok2str(bsn_mirror_copy_stage_str, "unknown (%u)", *cp))); + cp += 1; + /* pad */ + ND_TCHECK2(*cp, 3); + cp += 3; + break; + default: + ND_TCHECK2(*cp, len - 4); + cp += len - 4; + } + + return cp; + +corrupt: + ND_PRINT((ndo, "%s", cstr)); + ND_TCHECK2(*cp0, len); + return cp0 + len; +trunc: + ND_PRINT((ndo, "%s", tstr)); + return ep; +} + +static const u_char * +of10_vendor_action_print(netdissect_options *ndo, + const u_char *cp, const u_char *ep, const u_int len) { + uint32_t vendor; + const u_char *(*decoder)(netdissect_options *, const u_char *, const u_char *, const u_int); + + if (len < 4) + goto corrupt; + /* vendor */ + ND_TCHECK2(*cp, 4); + vendor = EXTRACT_32BITS(cp); + cp += 4; + ND_PRINT((ndo, ", vendor 0x%08x (%s)", vendor, of_vendor_name(vendor))); + /* data */ + decoder = + vendor == OUI_BSN ? of10_bsn_actions_print : + of10_data_print; + return decoder(ndo, cp, ep, len - 4); + +corrupt: /* skip the undersized data */ + ND_PRINT((ndo, "%s", cstr)); + ND_TCHECK2(*cp, len); + return cp + len; +trunc: + ND_PRINT((ndo, "%s", tstr)); + return ep; +} + static const u_char * of10_vendor_message_print(netdissect_options *ndo, const u_char *cp, const u_char *ep, const u_int len) { @@ -1342,7 +1570,7 @@ of10_actions_print(netdissect_options *ndo, cp += 4; break; case OFPAT_VENDOR: - if (ep == (cp = of10_vendor_data_print(ndo, cp, ep, alen - 4))) + if (ep == (cp = of10_vendor_action_print(ndo, cp, ep, alen - 4))) return ep; /* end of snapshot */ break; case OFPAT_STRIP_VLAN: