X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/9eda8ebfdebae9a4809f8c24d16ff11a4da5b5e5..2e63bc0ec11f2b041ee53e2ed986c9d50f135700:/print-openflow.c diff --git a/print-openflow.c b/print-openflow.c index 5dbefac0..3b85dd7a 100644 --- a/print-openflow.c +++ b/print-openflow.c @@ -30,86 +30,129 @@ * POSSIBILITY OF SUCH DAMAGE. */ +/* \summary: version-independent OpenFlow printer */ + #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif -#include +#include "netdissect-stdinc.h" -#include "interface.h" +#include "netdissect.h" #include "extract.h" #include "openflow.h" +#include "oui.h" -#define OF_VER_1_0 0x01 -static void -of_header_print(const uint8_t version, const uint8_t type, - const uint16_t length, const uint32_t xid) { - printf("\n\tversion unknown (0x%02x), type 0x%02x, length %u, xid 0x%08x", - version, type, length, xid); -} +#define OF_VER_1_0 0x01 -/* Print a single OpenFlow message. */ -static const u_char * -of_header_body_print(const u_char *cp, const u_char *ep) { - uint8_t version, type; - uint16_t length; - uint32_t xid; +const struct tok onf_exp_str[] = { + { ONF_EXP_ONF, "ONF Extensions" }, + { ONF_EXP_BUTE, "Budapest University of Technology and Economics" }, + { ONF_EXP_NOVIFLOW, "NoviFlow" }, + { ONF_EXP_L3, "L3+ Extensions, Vendor Neutral" }, + { ONF_EXP_L4L7, "L4-L7 Extensions" }, + { ONF_EXP_WMOB, "Wireless and Mobility Extensions" }, + { ONF_EXP_FABS, "Forwarding Abstractions Extensions" }, + { ONF_EXP_OTRANS, "Optical Transport Extensions" }, + { 0, NULL } +}; - if (ep < cp + OF_HEADER_LEN) - goto corrupt; - /* version */ - TCHECK2(*cp, 1); - version = *cp; - cp += 1; - /* type */ - TCHECK2(*cp, 1); - type = *cp; - cp += 1; - /* length */ - TCHECK2(*cp, 2); - length = EXTRACT_16BITS(cp); - cp += 2; - /* xid */ - TCHECK2(*cp, 4); - xid = EXTRACT_32BITS(cp); - cp += 4; - /* Message length includes the header length and a message always includes - * the basic header. A message length underrun fails decoding of the rest of - * the current packet. At the same time, try decoding as much of the current - * message as possible even when it does not end within the current TCP - * segment. */ - if (length < OF_HEADER_LEN) { - of_header_print(version, type, length, xid); - goto corrupt; - } - /* Decode known protocol versions further without printing the header (the - * type decoding is version-specific. */ - switch (version) { - case OF_VER_1_0: - return of10_header_body_print(cp, ep, type, length, xid); - default: - of_header_print(version, type, length, xid); - TCHECK2(*cp, length - OF_HEADER_LEN); - return cp + length - OF_HEADER_LEN; /* done with current message */ - } +const char * +of_vendor_name(const uint32_t vendor) +{ + const struct tok *table = (vendor & 0xff000000) == 0 ? oui_values : onf_exp_str; + return tok2str(table, "unknown", vendor); +} -corrupt: /* fail current packet */ - printf(" (corrupt)"); - TCHECK2(*cp, ep - cp); - return ep; -trunc: - printf(" [|openflow]"); - return ep; +static void +of_header_print(netdissect_options *ndo, const uint8_t version, const uint8_t type, + const uint16_t length, const uint32_t xid) +{ + ND_PRINT("\n\tversion unknown (0x%02x), type 0x%02x, length %u, xid 0x%08x", + version, type, length, xid); } /* Print a TCP segment worth of OpenFlow messages presuming the segment begins * on a message boundary. */ void -openflow_print(const u_char *cp, const u_int len) { - const u_char *ep = cp + len; +openflow_print(netdissect_options *ndo, const u_char *cp, u_int len) +{ + ndo->ndo_protocol = "openflow"; + ND_PRINT(": OpenFlow"); + while (len) { + /* Print a single OpenFlow message. */ + uint8_t version, type; + uint16_t length; + uint32_t xid; + + if (len < OF_HEADER_FIXLEN) + goto invalid; + /* version */ + version = GET_U_1(cp); + OF_FWD(1); + /* type */ + type = GET_U_1(cp); + OF_FWD(1); + /* length */ + length = GET_BE_U_2(cp); + OF_FWD(2); + /* xid */ + xid = GET_BE_U_4(cp); + OF_FWD(4); + /* + * When a TCP packet can contain several protocol messages, + * and at the same time a protocol message can span several + * TCP packets, decoding an incomplete message at the end of + * a TCP packet requires attention to detail in this loop. + * + * Message length includes the header length and a message + * always includes the basic header. A message length underrun + * fails decoding of the rest of the current packet. At the + * same time, try decoding as much of the current message as + * possible even when it does not end within the current TCP + * segment. + * + * Specifically, to try to process the message body in this + * iteration do NOT require the header "length" to be small + * enough for the full declared OpenFlow message to fit into + * the remainder of the declared TCP segment, same as the full + * declared TCP segment is not required to fit into the + * captured packet buffer. + * + * But DO require the same at the end of this iteration to + * decrement "len" and to proceed to the next iteration. + * (Ideally the declared TCP payload end will be at or after + * the captured packet buffer end, but stay safe even when + * that's somehow not the case.) + */ + if (length < OF_HEADER_FIXLEN) { + of_header_print(ndo, version, type, length, xid); + goto invalid; + } + /* + * Decode known protocol versions further without printing the + * header (the type decoding is version-specific). + */ + switch (version) { + case OF_VER_1_0: + of10_header_body_print(ndo, cp, type, + length - OF_HEADER_FIXLEN, xid); + break; + default: + of_header_print(ndo, version, type, length, xid); + ND_TCHECK_LEN(cp, length - OF_HEADER_FIXLEN); + } + if (length - OF_HEADER_FIXLEN > len) + break; + OF_FWD(length - OF_HEADER_FIXLEN); + } /* while (len) */ + return; - printf(": OpenFlow"); - while (cp < ep) - cp = of_header_body_print(cp, ep); +invalid: /* fail the current packet */ + nd_print_invalid(ndo); + ND_TCHECK_LEN(cp, len); + return; +trunc: + nd_trunc(ndo); }