X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fofp-print.c;h=67edc543f690cad3c0a5b8e084afae1846a08ad9;hb=ca261b65354f522ba43c823221763ca6f4604e2d;hp=4f4e33c51c750b5a1b80b9333d0fadddd67787e4;hpb=38f2e36072c9065cae3d4fbab4a70e4f502706cd;p=openvswitch diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 4f4e33c5..67edc543 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -26,10 +26,12 @@ #include #include +#include "bundle.h" #include "byte-order.h" #include "compiler.h" #include "dynamic-string.h" #include "flow.h" +#include "learn.h" #include "multipath.h" #include "nx-match.h" #include "ofp-util.h" @@ -42,151 +44,108 @@ #include "unaligned.h" #include "util.h" -static void ofp_print_port_name(struct ds *string, uint16_t port); static void ofp_print_queue_name(struct ds *string, uint32_t port); static void ofp_print_error(struct ds *, int error); /* 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=", 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)); + } + } - ds_put_format(string, " total_len=%"PRIu16" in_port=", - ntohs(op->total_len)); - ofp_print_port_name(string, ntohs(op->in_port)); + 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) + if (pin.reason == OFPR_ACTION) { ds_put_cstr(string, " (via action)"); - else if (op->reason != OFPR_NO_MATCH) - ds_put_format(string, " (***reason %"PRIu8"***)", op->reason); + } else if (pin.reason != OFPR_NO_MATCH) { + ds_put_format(string, " (***reason %"PRIu8"***)", pin.reason); + } - 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); } } -static void ofp_print_port_name(struct ds *string, uint16_t port) -{ - const char *name; - switch (port) { - case OFPP_IN_PORT: - name = "IN_PORT"; - break; - case OFPP_TABLE: - name = "TABLE"; - break; - case OFPP_NORMAL: - name = "NORMAL"; - break; - case OFPP_FLOOD: - name = "FLOOD"; - break; - case OFPP_ALL: - name = "ALL"; - break; - case OFPP_CONTROLLER: - name = "CONTROLLER"; - break; - case OFPP_LOCAL: - name = "LOCAL"; - break; - case OFPP_NONE: - name = "NONE"; - break; - default: - ds_put_format(string, "%"PRIu16, port); - return; - } - ds_put_cstr(string, name); -} - - static void print_note(struct ds *string, const struct nx_action_note *nan) { @@ -217,6 +176,7 @@ ofp_print_action(struct ds *s, const union ofp_action *a, const struct nx_action_reg_load *load; const struct nx_action_multipath *nam; const struct nx_action_autopath *naa; + const struct nx_action_output_reg *naor; uint16_t port; switch (code) { @@ -225,7 +185,7 @@ ofp_print_action(struct ds *s, const union ofp_action *a, if (port < OFPP_MAX) { ds_put_format(s, "output:%"PRIu16, port); } else { - ofp_print_port_name(s, port); + ofputil_format_port(port, s); if (port == OFPP_CONTROLLER) { if (a->output.max_len != htons(0)) { ds_put_format(s, ":%"PRIu16, ntohs(a->output.max_len)); @@ -239,7 +199,7 @@ ofp_print_action(struct ds *s, const union ofp_action *a, case OFPUTIL_OFPAT_ENQUEUE: oae = (const struct ofp_action_enqueue *) a; ds_put_format(s, "enqueue:"); - ofp_print_port_name(s, ntohs(oae->port)); + ofputil_format_port(ntohs(oae->port), s); ds_put_format(s, "q%"PRIu32, ntohl(oae->queue_id)); break; @@ -291,7 +251,20 @@ ofp_print_action(struct ds *s, const union ofp_action *a, case OFPUTIL_NXAST_RESUBMIT: nar = (struct nx_action_resubmit *)a; ds_put_format(s, "resubmit:"); - ofp_print_port_name(s, ntohs(nar->in_port)); + ofputil_format_port(ntohs(nar->in_port), s); + break; + + case OFPUTIL_NXAST_RESUBMIT_TABLE: + nar = (struct nx_action_resubmit *)a; + ds_put_format(s, "resubmit("); + if (nar->in_port != htons(OFPP_IN_PORT)) { + ofputil_format_port(ntohs(nar->in_port), s); + } + ds_put_char(s, ','); + if (nar->table != 255) { + ds_put_format(s, "%"PRIu8, nar->table); + } + ds_put_char(s, ')'); break; case OFPUTIL_NXAST_SET_TUNNEL: @@ -342,6 +315,27 @@ ofp_print_action(struct ds *s, const union ofp_action *a, ds_put_char(s, ')'); break; + case OFPUTIL_NXAST_BUNDLE: + case OFPUTIL_NXAST_BUNDLE_LOAD: + bundle_format((const struct nx_action_bundle *) a, s); + break; + + case OFPUTIL_NXAST_OUTPUT_REG: + naor = (const struct nx_action_output_reg *) a; + ds_put_cstr(s, "output:"); + nxm_format_field_bits(s, ntohl(naor->src), + nxm_decode_ofs(naor->ofs_nbits), + nxm_decode_n_bits(naor->ofs_nbits)); + break; + + case OFPUTIL_NXAST_LEARN: + learn_format((const struct nx_action_learn *) a, s); + break; + + case OFPUTIL_NXAST_EXIT: + ds_put_cstr(s, "exit"); + break; + default: break; } @@ -384,7 +378,7 @@ ofp_print_packet_out(struct ds *string, const struct ofp_packet_out *opo, size_t actions_len = ntohs(opo->actions_len); ds_put_cstr(string, " in_port="); - ofp_print_port_name(string, ntohs(opo->in_port)); + ofputil_format_port(ntohs(opo->in_port), string); ds_put_format(string, " actions_len=%zu ", actions_len); if (actions_len > (ntohs(opo->header.length) - sizeof *opo)) { @@ -403,7 +397,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); @@ -426,47 +420,108 @@ compare_ports(const void *a_, const void *b_) return ap < bp ? -1 : ap > bp; } -static void ofp_print_port_features(struct ds *string, uint32_t features) +struct bit_name { + uint32_t bit; + const char *name; +}; + +static void +ofp_print_bit_names(struct ds *string, uint32_t bits, + const struct bit_name bit_names[]) { - if (features == 0) { - ds_put_cstr(string, "Unsupported\n"); + int n = 0; + + if (!bits) { + ds_put_cstr(string, "0"); return; } - if (features & OFPPF_10MB_HD) { - ds_put_cstr(string, "10MB-HD "); - } - if (features & OFPPF_10MB_FD) { - ds_put_cstr(string, "10MB-FD "); - } - if (features & OFPPF_100MB_HD) { - ds_put_cstr(string, "100MB-HD "); - } - if (features & OFPPF_100MB_FD) { - ds_put_cstr(string, "100MB-FD "); - } - if (features & OFPPF_1GB_HD) { - ds_put_cstr(string, "1GB-HD "); - } - if (features & OFPPF_1GB_FD) { - ds_put_cstr(string, "1GB-FD "); - } - if (features & OFPPF_10GB_FD) { - ds_put_cstr(string, "10GB-FD "); - } - if (features & OFPPF_COPPER) { - ds_put_cstr(string, "COPPER "); - } - if (features & OFPPF_FIBER) { - ds_put_cstr(string, "FIBER "); - } - if (features & OFPPF_AUTONEG) { - ds_put_cstr(string, "AUTO_NEG "); + + for (; bits && bit_names->name; bit_names++) { + if (bits & bit_names->bit) { + if (n++) { + ds_put_char(string, ' '); + } + ds_put_cstr(string, bit_names->name); + bits &= ~bit_names->bit; + } } - if (features & OFPPF_PAUSE) { - ds_put_cstr(string, "AUTO_PAUSE "); + + if (bits) { + if (n++) { + ds_put_char(string, ' '); + } + ds_put_format(string, "0x%"PRIx32, bits); } - if (features & OFPPF_PAUSE_ASYM) { - ds_put_cstr(string, "AUTO_PAUSE_ASYM "); +} + +static void +ofp_print_port_features(struct ds *string, uint32_t features) +{ + static const struct bit_name feature_bits[] = { + { OFPPF_10MB_HD, "10MB-HD" }, + { OFPPF_10MB_FD, "10MB-FD" }, + { OFPPF_100MB_HD, "100MB-HD" }, + { OFPPF_100MB_FD, "100MB-FD" }, + { OFPPF_1GB_HD, "1GB-HD" }, + { OFPPF_1GB_FD, "1GB-FD" }, + { OFPPF_10GB_FD, "10GB-FD" }, + { OFPPF_COPPER, "COPPER" }, + { OFPPF_FIBER, "FIBER" }, + { OFPPF_AUTONEG, "AUTO_NEG" }, + { OFPPF_PAUSE, "AUTO_PAUSE" }, + { OFPPF_PAUSE_ASYM, "AUTO_PAUSE_ASYM" }, + { 0, NULL }, + }; + + ofp_print_bit_names(string, features, feature_bits); + ds_put_char(string, '\n'); +} + +static void +ofp_print_port_config(struct ds *string, uint32_t config) +{ + static const struct bit_name config_bits[] = { + { OFPPC_PORT_DOWN, "PORT_DOWN" }, + { OFPPC_NO_STP, "NO_STP" }, + { OFPPC_NO_RECV, "NO_RECV" }, + { OFPPC_NO_RECV_STP, "NO_RECV_STP" }, + { OFPPC_NO_FLOOD, "NO_FLOOD" }, + { OFPPC_NO_FWD, "NO_FWD" }, + { OFPPC_NO_PACKET_IN, "NO_PACKET_IN" }, + { 0, NULL }, + }; + + ofp_print_bit_names(string, config, config_bits); + ds_put_char(string, '\n'); +} + +static void +ofp_print_port_state(struct ds *string, uint32_t state) +{ + static const struct bit_name state_bits[] = { + { OFPPS_LINK_DOWN, "LINK_DOWN" }, + { 0, NULL }, + }; + uint32_t stp_state; + + /* The STP state is a 2-bit field so it doesn't fit in with the bitmask + * pattern. We have to special case it. + * + * OVS doesn't support STP, so this field will always be 0 if we are + * talking to OVS, so we'd always print STP_LISTEN in that case. + * Therefore, we don't print anything at all if the value is STP_LISTEN, to + * avoid confusing users. */ + stp_state = state & OFPPS_STP_MASK; + if (stp_state) { + ds_put_cstr(string, (stp_state == OFPPS_STP_LEARN ? "STP_LEARN" + : stp_state == OFPPS_STP_FORWARD ? "STP_FORWARD" + : "STP_BLOCK")); + state &= ~OFPPS_STP_MASK; + if (state) { + ofp_print_bit_names(string, state, state_bits); + } + } else { + ofp_print_bit_names(string, state, state_bits); } ds_put_char(string, '\n'); } @@ -486,10 +541,16 @@ ofp_print_phy_port(struct ds *string, const struct ofp_phy_port *port) name[j] = '\0'; ds_put_char(string, ' '); - ofp_print_port_name(string, ntohs(port->port_no)); - ds_put_format(string, "(%s): addr:"ETH_ADDR_FMT", config: %#x, state:%#x\n", - name, ETH_ADDR_ARGS(port->hw_addr), ntohl(port->config), - ntohl(port->state)); + ofputil_format_port(ntohs(port->port_no), string); + ds_put_format(string, "(%s): addr:"ETH_ADDR_FMT"\n", + name, ETH_ADDR_ARGS(port->hw_addr)); + + ds_put_cstr(string, " config: "); + ofp_print_port_config(string, ntohl(port->config)); + + ds_put_cstr(string, " state: "); + ofp_print_port_state(string, ntohl(port->state)); + if (port->curr) { ds_put_format(string, " current: "); ofp_print_port_features(string, ntohl(port->curr)); @@ -541,21 +602,9 @@ ofp_print_switch_config(struct ds *string, const struct ofp_switch_config *osc) flags = ntohs(osc->flags); - ds_put_cstr(string, " frags="); - switch (flags & OFPC_FRAG_MASK) { - case OFPC_FRAG_NORMAL: - ds_put_cstr(string, "normal"); - flags &= ~OFPC_FRAG_MASK; - break; - case OFPC_FRAG_DROP: - ds_put_cstr(string, "drop"); - flags &= ~OFPC_FRAG_MASK; - break; - case OFPC_FRAG_REASM: - ds_put_cstr(string, "reassemble"); - flags &= ~OFPC_FRAG_MASK; - break; - } + ds_put_format(string, " frags=%s", ofputil_frag_handling_to_string(flags)); + flags &= ~OFPC_FRAG_MASK; + if (flags) { ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***", flags); } @@ -676,9 +725,9 @@ ofp_match_to_string(const struct ofp_match *om, int verbosity) "%u", om->nw_tos); if (om->nw_proto == IPPROTO_ICMP) { print_wild(&f, "icmp_type=", w & OFPFW_ICMP_TYPE, verbosity, - "%d", ntohs(om->icmp_type)); + "%d", ntohs(om->tp_src)); print_wild(&f, "icmp_code=", w & OFPFW_ICMP_CODE, verbosity, - "%d", ntohs(om->icmp_code)); + "%d", ntohs(om->tp_dst)); } else { print_wild(&f, "tp_src=", w & OFPFW_TP_SRC, verbosity, "%d", ntohs(om->tp_src)); @@ -695,7 +744,7 @@ static void ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh, enum ofputil_msg_code code, int verbosity) { - struct flow_mod fm; + struct ofputil_flow_mod fm; bool need_priority; int error; @@ -884,15 +933,11 @@ ofp_print_error_msg(struct ds *string, const struct ofp_error_msg *oem) ds_put_printable(string, payload, payload_len); break; - case OFPET_BAD_REQUEST: + default: 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; } } @@ -930,7 +975,7 @@ static void ofp_print_flow_stats_request(struct ds *string, const struct ofp_stats_msg *osm) { - struct flow_stats_request fsr; + struct ofputil_flow_stats_request fsr; int error; error = ofputil_decode_flow_stats_request(&fsr, &osm->header); @@ -945,7 +990,7 @@ ofp_print_flow_stats_request(struct ds *string, if (fsr.out_port != OFPP_NONE) { ds_put_cstr(string, " out_port="); - ofp_print_port_name(string, fsr.out_port); + ofputil_format_port(fsr.out_port, string); } /* A flow stats request doesn't include a priority, but cls_rule_format() @@ -990,7 +1035,9 @@ ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh) } cls_rule_format(&fs.rule, string); - ds_put_char(string, ' '); + if (string->string[string->length - 1] != ' ') { + ds_put_char(string, ' '); + } ofp_print_actions(string, fs.actions, fs.n_actions); } } @@ -1114,7 +1161,7 @@ ofp_print_ofpst_queue_request(struct ds *string, const struct ofp_queue_stats_request *qsr) { ds_put_cstr(string, "port="); - ofp_print_port_name(string, ntohs(qsr->port_no)); + ofputil_format_port(ntohs(qsr->port_no), string); ds_put_cstr(string, " queue="); ofp_print_queue_name(string, ntohl(qsr->queue_id)); @@ -1133,7 +1180,7 @@ ofp_print_ofpst_queue_reply(struct ds *string, const struct ofp_header *oh, for (; n--; qs++) { ds_put_cstr(string, " port "); - ofp_print_port_name(string, ntohs(qs->port_no)); + ofputil_format_port(ntohs(qs->port_no), string); ds_put_cstr(string, " queue "); ofp_print_queue_name(string, ntohl(qs->queue_id)); ds_put_cstr(string, ": "); @@ -1225,6 +1272,20 @@ ofp_print_nxt_set_flow_format(struct ds *string, } } +static void +ofp_print_nxt_set_packet_in_format(struct ds *string, + const struct nxt_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, @@ -1272,6 +1333,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; @@ -1375,6 +1437,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; @@ -1539,12 +1605,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)); }