X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fofp-print.c;h=7bc26c9ddc3541c91a8d285fc5faf93399332cf0;hb=153e54814d81cafa89bae451dbfa92a31910e5a6;hp=7bdbc220dccaba4e94328a1bda94fd1bd64df849;hpb=7257b535ab8e5fafd811c5f6788205eefdd44948;p=openvswitch diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 7bdbc220..7bc26c9d 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks. + * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira Networks. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ #include "learn.h" #include "multipath.h" #include "nx-match.h" +#include "ofp-errors.h" #include "ofp-util.h" #include "ofpbuf.h" #include "openflow/openflow.h" @@ -45,108 +46,111 @@ #include "util.h" static void ofp_print_queue_name(struct ds *string, uint32_t port); -static void ofp_print_error(struct ds *, int error); +static void ofp_print_error(struct ds *, enum ofperr); /* Returns a string that represents the contents of the Ethernet frame in the - * 'len' bytes starting at 'data' to 'stream' as output by tcpdump. - * 'total_len' specifies the full length of the Ethernet frame (of which 'len' - * bytes were captured). - * - * The caller must free the returned string. - * - * This starts and kills a tcpdump subprocess so it's quite expensive. */ + * 'len' bytes starting at 'data'. The caller must free the returned string.*/ char * -ofp_packet_to_string(const void *data, size_t len, size_t total_len OVS_UNUSED) +ofp_packet_to_string(const void *data, size_t len) { struct ds ds = DS_EMPTY_INITIALIZER; struct ofpbuf buf; - - char command[128]; - FILE *pcap; - FILE *tcpdump; - int status; - int c; + struct flow flow; ofpbuf_use_const(&buf, data, len); - - pcap = tmpfile(); - if (!pcap) { - ovs_error(errno, "tmpfile"); - return xstrdup(""); - } - pcap_write_header(pcap); - pcap_write(pcap, &buf); - fflush(pcap); - if (ferror(pcap)) { - ovs_error(errno, "error writing temporary file"); - } - rewind(pcap); - - snprintf(command, sizeof command, "/usr/sbin/tcpdump -t -e -n -r /dev/fd/%d 2>/dev/null", - fileno(pcap)); - tcpdump = popen(command, "r"); - fclose(pcap); - if (!tcpdump) { - ovs_error(errno, "exec(\"%s\")", command); - return xstrdup(""); + flow_extract(&buf, 0, 0, 0, &flow); + flow_format(&ds, &flow); + + if (buf.l7) { + if (flow.nw_proto == IPPROTO_TCP) { + struct tcp_header *th = buf.l4; + ds_put_format(&ds, " tcp_csum:%"PRIx16, + ntohs(th->tcp_csum)); + } else if (flow.nw_proto == IPPROTO_UDP) { + struct udp_header *uh = buf.l4; + ds_put_format(&ds, " udp_csum:%"PRIx16, + ntohs(uh->udp_csum)); + } } - while ((c = getc(tcpdump)) != EOF) { - ds_put_char(&ds, c); - } + ds_put_char(&ds, '\n'); - status = pclose(tcpdump); - if (WIFEXITED(status)) { - if (WEXITSTATUS(status)) - ovs_error(0, "tcpdump exited with status %d", WEXITSTATUS(status)); - } else if (WIFSIGNALED(status)) { - ovs_error(0, "tcpdump exited with signal %d", WTERMSIG(status)); - } return ds_cstr(&ds); } static void -ofp_print_packet_in(struct ds *string, const struct ofp_packet_in *op, +ofp_print_packet_in(struct ds *string, const struct ofp_header *oh, int verbosity) { - size_t len = ntohs(op->header.length); - size_t data_len; + struct ofputil_packet_in pin; + int error; + int i; + + error = ofputil_decode_packet_in(&pin, oh); + if (error) { + ofp_print_error(string, error); + return; + } + + if (pin.table_id) { + ds_put_format(string, " table_id=%"PRIu8, pin.table_id); + } + + if (pin.cookie) { + ds_put_format(string, " cookie=0x%"PRIx64, ntohll(pin.cookie)); + } - ds_put_format(string, " total_len=%"PRIu16" in_port=", - ntohs(op->total_len)); - ofputil_format_port(ntohs(op->in_port), string); + ds_put_format(string, " total_len=%"PRIu16" in_port=", pin.total_len); + ofputil_format_port(pin.fmd.in_port, string); + + if (pin.fmd.tun_id_mask) { + ds_put_format(string, " tun_id=0x%"PRIx64, ntohll(pin.fmd.tun_id)); + if (pin.fmd.tun_id_mask != htonll(UINT64_MAX)) { + ds_put_format(string, "/0x%"PRIx64, ntohll(pin.fmd.tun_id_mask)); + } + } + + for (i = 0; i < FLOW_N_REGS; i++) { + if (pin.fmd.reg_masks[i]) { + ds_put_format(string, " reg%d=0x%"PRIx32, i, pin.fmd.regs[i]); + if (pin.fmd.reg_masks[i] != UINT32_MAX) { + ds_put_format(string, "/0x%"PRIx32, pin.fmd.reg_masks[i]); + } + } + } - if (op->reason == OFPR_ACTION) + switch (pin.reason) { + case OFPR_NO_MATCH: + ds_put_cstr(string, " (via no_match)"); + break; + case OFPR_ACTION: ds_put_cstr(string, " (via action)"); - else if (op->reason != OFPR_NO_MATCH) - ds_put_format(string, " (***reason %"PRIu8"***)", op->reason); + break; + case OFPR_INVALID_TTL: + ds_put_cstr(string, " (via invalid_ttl)"); + break; + default: + ds_put_format(string, " (***reason %"PRIu8"***)", pin.reason); + break; + } - data_len = len - offsetof(struct ofp_packet_in, data); - ds_put_format(string, " data_len=%zu", data_len); - if (op->buffer_id == htonl(UINT32_MAX)) { + ds_put_format(string, " data_len=%zu", pin.packet_len); + if (pin.buffer_id == UINT32_MAX) { ds_put_format(string, " (unbuffered)"); - if (ntohs(op->total_len) != data_len) + if (pin.total_len != pin.packet_len) { ds_put_format(string, " (***total_len != data_len***)"); + } } else { - ds_put_format(string, " buffer=0x%08"PRIx32, ntohl(op->buffer_id)); - if (ntohs(op->total_len) < data_len) + ds_put_format(string, " buffer=0x%08"PRIx32, pin.buffer_id); + if (pin.total_len < pin.packet_len) { ds_put_format(string, " (***total_len < data_len***)"); + } } ds_put_char(string, '\n'); if (verbosity > 0) { - struct flow flow; - struct ofpbuf packet; - - ofpbuf_use_const(&packet, op->data, data_len); - flow_extract(&packet, 0, ntohs(op->in_port), &flow); - flow_format(string, &flow); - ds_put_char(string, '\n'); - } - if (verbosity > 1) { - char *packet = ofp_packet_to_string(op->data, data_len, - ntohs(op->total_len)); + char *packet = ofp_packet_to_string(pin.packet, pin.packet_len); ds_put_cstr(string, packet); free(packet); } @@ -338,6 +342,14 @@ ofp_print_action(struct ds *s, const union ofp_action *a, learn_format((const struct nx_action_learn *) a, s); break; + case OFPUTIL_NXAST_DEC_TTL: + ds_put_cstr(s, "dec_ttl"); + break; + + case OFPUTIL_NXAST_EXIT: + ds_put_cstr(s, "exit"); + break; + default: break; } @@ -399,7 +411,7 @@ ofp_print_packet_out(struct ds *string, const struct ofp_packet_out *opo, ds_put_format(string, " data_len=%d", data_len); if (verbosity > 0 && len > sizeof *opo) { char *packet = ofp_packet_to_string( - (uint8_t *)opo->actions + actions_len, data_len, data_len); + (uint8_t *) opo->actions + actions_len, data_len); ds_put_char(string, '\n'); ds_put_cstr(string, packet); free(packet); @@ -600,13 +612,18 @@ ofp_print_switch_features(struct ds *string, static void ofp_print_switch_config(struct ds *string, const struct ofp_switch_config *osc) { - uint16_t flags; + enum ofp_config_flags flags; flags = ntohs(osc->flags); ds_put_format(string, " frags=%s", ofputil_frag_handling_to_string(flags)); flags &= ~OFPC_FRAG_MASK; + if (flags & OFPC_INVALID_TTL_TO_CONTROLLER) { + ds_put_format(string, " invalid_ttl_to_controller"); + flags &= ~OFPC_INVALID_TTL_TO_CONTROLLER; + } + if (flags) { ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***", flags); } @@ -748,7 +765,7 @@ ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh, { struct ofputil_flow_mod fm; bool need_priority; - int error; + enum ofperr error; error = ofputil_decode_flow_mod(&fm, oh, true); if (error) { @@ -847,7 +864,7 @@ static void ofp_print_flow_removed(struct ds *string, const struct ofp_header *oh) { struct ofputil_flow_removed fr; - int error; + enum ofperr error; error = ofputil_decode_flow_removed(&fr, oh); if (error) { @@ -898,14 +915,12 @@ ofp_print_port_mod(struct ds *string, const struct ofp_port_mod *opm) } static void -ofp_print_error(struct ds *string, int error) +ofp_print_error(struct ds *string, enum ofperr error) { if (string->length) { ds_put_char(string, ' '); } - ds_put_cstr(string, "***decode error: "); - ofputil_format_error(string, error); - ds_put_cstr(string, "***\n"); + ds_put_format(string, "***decode error: %s***\n", ofperr_get_name(error)); } static void @@ -914,36 +929,26 @@ ofp_print_error_msg(struct ds *string, const struct ofp_error_msg *oem) size_t len = ntohs(oem->header.length); size_t payload_ofs, payload_len; const void *payload; - int error; + enum ofperr error; char *s; - error = ofputil_decode_error_msg(&oem->header, &payload_ofs); - if (!is_ofp_error(error)) { - ofp_print_error(string, error); + error = ofperr_decode_msg(&oem->header, &payload_ofs); + if (!error) { + ds_put_cstr(string, "***decode error***"); ds_put_hex_dump(string, oem->data, len - sizeof *oem, 0, true); return; } - ds_put_char(string, ' '); - ofputil_format_error(string, error); - ds_put_char(string, '\n'); + ds_put_format(string, " %s\n", ofperr_get_name(error)); payload = (const uint8_t *) oem + payload_ofs; payload_len = len - payload_ofs; - switch (get_ofp_err_type(error)) { - case OFPET_HELLO_FAILED: + if (error == OFPERR_OFPHFC_INCOMPATIBLE || error == OFPERR_OFPHFC_EPERM) { ds_put_printable(string, payload, payload_len); - break; - - case OFPET_BAD_REQUEST: + } else { s = ofp_to_string(payload, payload_len, 1); ds_put_cstr(string, s); free(s); - break; - - default: - ds_put_hex_dump(string, payload, payload_len, 0, true); - break; } } @@ -982,7 +987,7 @@ ofp_print_flow_stats_request(struct ds *string, const struct ofp_stats_msg *osm) { struct ofputil_flow_stats_request fsr; - int error; + enum ofperr error; error = ofputil_decode_flow_stats_request(&fsr, &osm->header); if (error) { @@ -1259,14 +1264,14 @@ ofp_print_nxt_role_message(struct ds *string, static void ofp_print_nxt_flow_mod_table_id(struct ds *string, - const struct nxt_flow_mod_table_id *nfmti) + const struct nx_flow_mod_table_id *nfmti) { ds_put_format(string, " %s", nfmti->set ? "enable" : "disable"); } static void ofp_print_nxt_set_flow_format(struct ds *string, - const struct nxt_set_flow_format *nsff) + const struct nx_set_flow_format *nsff) { uint32_t format = ntohl(nsff->format); @@ -1278,6 +1283,20 @@ ofp_print_nxt_set_flow_format(struct ds *string, } } +static void +ofp_print_nxt_set_packet_in_format(struct ds *string, + const struct nx_set_packet_in_format *nspf) +{ + uint32_t format = ntohl(nspf->format); + + ds_put_cstr(string, " format="); + if (ofputil_packet_in_format_is_valid(format)) { + ds_put_cstr(string, ofputil_packet_in_format_to_string(format)); + } else { + ds_put_format(string, "%"PRIu32, format); + } +} + static void ofp_to_string__(const struct ofp_header *oh, const struct ofputil_msg_type *type, struct ds *string, @@ -1325,6 +1344,7 @@ ofp_to_string__(const struct ofp_header *oh, break; case OFPUTIL_OFPT_PACKET_IN: + case OFPUTIL_NXT_PACKET_IN: ofp_print_packet_in(string, msg, verbosity); break; @@ -1428,6 +1448,10 @@ ofp_to_string__(const struct ofp_header *oh, ofp_print_nxt_set_flow_format(string, msg); break; + case OFPUTIL_NXT_SET_PACKET_IN_FORMAT: + ofp_print_nxt_set_packet_in_format(string, msg); + break; + case OFPUTIL_NXT_FLOW_MOD: ofp_print_flow_mod(string, msg, code, verbosity); break; @@ -1454,9 +1478,6 @@ ofp_to_string(const void *oh_, size_t len, int verbosity) } else if (len < sizeof(struct ofp_header)) { ds_put_format(&string, "OpenFlow packet too short (only %zu bytes):\n", len); - } else if (oh->version != OFP_VERSION) { - ds_put_format(&string, "Bad OpenFlow version %"PRIu8":\n", - oh->version); } else if (ntohs(oh->length) > len) { ds_put_format(&string, "(***truncated to %zu bytes from %"PRIu16"***)\n", @@ -1467,7 +1488,7 @@ ofp_to_string(const void *oh_, size_t len, int verbosity) ntohs(oh->length), len); } else { const struct ofputil_msg_type *type; - int error; + enum ofperr error; error = ofputil_decode_msg_type(oh, &type); if (!error) { @@ -1592,12 +1613,9 @@ ofp_print(FILE *stream, const void *oh, size_t len, int verbosity) } /* Dumps the contents of the Ethernet frame in the 'len' bytes starting at - * 'data' to 'stream' using tcpdump. 'total_len' specifies the full length of - * the Ethernet frame (of which 'len' bytes were captured). - * - * This starts and kills a tcpdump subprocess so it's quite expensive. */ + * 'data' to 'stream'. */ void -ofp_print_packet(FILE *stream, const void *data, size_t len, size_t total_len) +ofp_print_packet(FILE *stream, const void *data, size_t len) { - print_and_free(stream, ofp_packet_to_string(data, len, total_len)); + print_and_free(stream, ofp_packet_to_string(data, len)); }