X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=utilities%2Fovs-ofctl.c;h=c1876fd3e462961a5ecaa6182600b7af607c96f4;hb=968eec593cc61690c9e0ed97450c4889258381af;hp=4dbd4ed01a34d4850b621cc9ecefc94210183227;hpb=182b2eef208fff46d51c640e3002979e4a0ae7f7;p=cascardo%2Fovs.git diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 4dbd4ed01..c1876fd3e 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -846,7 +846,6 @@ port_iterator_fetch_features(struct port_iterator *pi) run(vconn_transact(pi->vconn, rq, &pi->reply), "talking to %s", vconn_get_name(pi->vconn)); - const struct ofp_header *oh = pi->reply->data; enum ofptype type; if (ofptype_decode(&type, pi->reply->data) || type != OFPTYPE_FEATURES_REPLY) { @@ -865,8 +864,7 @@ port_iterator_fetch_features(struct port_iterator *pi) } struct ofputil_switch_features features; - enum ofperr error = ofputil_decode_switch_features(oh, &features, - pi->reply); + enum ofperr error = ofputil_pull_switch_features(pi->reply, &features); if (error) { ovs_fatal(0, "%s: failed to decode features reply (%s)", vconn_get_name(pi->vconn), ofperr_to_string(error)); @@ -1232,12 +1230,14 @@ static void ofctl_queue_get_config(struct ovs_cmdl_context *ctx) { const char *vconn_name = ctx->argv[1]; - const char *port_name = ctx->argc >= 3 ? ctx->argv[2] : NULL; - ofp_port_t port = (port_name - ? str_to_port_no(vconn_name, port_name) - : OFPP_ANY); - + const char *port_name = ctx->argc > 2 ? ctx->argv[2] : "any"; + ofp_port_t port = str_to_port_no(vconn_name, port_name); + const char *queue_name = ctx->argc > 3 ? ctx->argv[3] : "all"; + uint32_t queue = (!strcasecmp(queue_name, "all") + ? OFPQ_ALL + : atoi(queue_name)); struct vconn *vconn; + enum ofputil_protocol protocol = open_vconn(vconn_name, &vconn); enum ofp_version version = ofputil_protocol_to_ofp_version(protocol); if (port == OFPP_ANY && version == OFP10_VERSION) { @@ -1257,14 +1257,14 @@ ofctl_queue_get_config(struct ovs_cmdl_context *ctx) if (ofp_to_u16(pp.port_no) < ofp_to_u16(OFPP_MAX)) { dump_transaction(vconn2, ofputil_encode_queue_get_config_request( - version2, pp.port_no)); + version2, pp.port_no, queue)); } } port_iterator_destroy(&pi); vconn_close(vconn2); } else { dump_transaction(vconn, ofputil_encode_queue_get_config_request( - version, port)); + version, port, queue)); } vconn_close(vconn); } @@ -1424,18 +1424,38 @@ ofctl_del_flows(struct ovs_cmdl_context *ctx) ofctl_flow_mod(ctx->argc, ctx->argv, strict ? OFPFC_DELETE_STRICT : OFPFC_DELETE); } -static void +static bool set_packet_in_format(struct vconn *vconn, - enum nx_packet_in_format packet_in_format) + enum nx_packet_in_format packet_in_format, + bool must_succeed) { struct ofpbuf *spif; spif = ofputil_make_set_packet_in_format(vconn_get_version(vconn), packet_in_format); - transact_noreply(vconn, spif); - VLOG_DBG("%s: using user-specified packet in format %s", - vconn_get_name(vconn), - ofputil_packet_in_format_to_string(packet_in_format)); + if (must_succeed) { + transact_noreply(vconn, spif); + } else { + struct ofpbuf *reply; + + run(vconn_transact_noreply(vconn, spif, &reply), + "talking to %s", vconn_get_name(vconn)); + if (reply) { + char *s = ofp_to_string(reply->data, reply->size, 2); + VLOG_DBG("%s: failed to set packet in format to nx_packet_in, " + "controller replied: %s.", + vconn_get_name(vconn), s); + free(s); + ofpbuf_delete(reply); + + return false; + } else { + VLOG_DBG("%s: using user-specified packet in format %s", + vconn_get_name(vconn), + ofputil_packet_in_format_to_string(packet_in_format)); + } + } + return true; } static int @@ -1613,9 +1633,13 @@ ofctl_unblock(struct unixctl_conn *conn, int argc OVS_UNUSED, /* Prints to stdout all of the messages received on 'vconn'. * * Iff 'reply_to_echo_requests' is true, sends a reply to any echo request - * received on 'vconn'. */ + * received on 'vconn'. + * + * If 'resume_continuations' is true, sends an NXT_RESUME in reply to any + * NXT_PACKET_IN2 that includes a continuation. */ static void -monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests) +monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests, + bool resume_continuations) { struct barrier_aux barrier_aux = { vconn, NULL }; struct unixctl_server *server; @@ -1643,6 +1667,10 @@ monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests) daemonize_complete(); + enum ofp_version version = vconn_get_version(vconn); + enum ofputil_protocol protocol + = ofputil_protocol_from_ofp_version(version); + for (;;) { struct ofpbuf *b; int retval; @@ -1688,6 +1716,36 @@ monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests) } } break; + + case OFPTYPE_PACKET_IN: + if (resume_continuations) { + struct ofputil_packet_in pin; + struct ofpbuf continuation; + + error = ofputil_decode_packet_in(b->data, true, &pin, + NULL, NULL, + &continuation); + if (error) { + fprintf(stderr, "decoding packet-in failed: %s", + ofperr_to_string(error)); + } else if (continuation.size) { + struct ofpbuf *reply; + + reply = ofputil_encode_resume(&pin, &continuation, + protocol); + + fprintf(stderr, "send: "); + ofp_print(stderr, reply->data, reply->size, + verbosity + 2); + fflush(stderr); + + retval = vconn_send_block(vconn, reply); + if (retval) { + ovs_fatal(retval, "failed to send NXT_RESUME"); + } + } + } + break; } ofpbuf_delete(b); } @@ -1738,6 +1796,7 @@ ofctl_monitor(struct ovs_cmdl_context *ctx) } open_vconn(ctx->argv[1], &vconn); + bool resume_continuations = false; for (i = 2; i < ctx->argc; i++) { const char *arg = ctx->argv[i]; @@ -1764,46 +1823,38 @@ ofctl_monitor(struct ovs_cmdl_context *ctx) ofputil_append_flow_monitor_request(&fmr, msg); dump_transaction(vconn, msg); fflush(stdout); + } else if (!strcmp(arg, "resume")) { + /* This option is intentionally undocumented because it is meant + * only for testing. */ + resume_continuations = true; + + /* Set miss_send_len to ensure that we get packet-ins. */ + struct ofputil_switch_config config; + fetch_switch_config(vconn, &config); + config.miss_send_len = UINT16_MAX; + set_switch_config(vconn, &config); } else { ovs_fatal(0, "%s: unsupported \"monitor\" argument", arg); } } if (preferred_packet_in_format >= 0) { - set_packet_in_format(vconn, preferred_packet_in_format); + /* A particular packet-in format was requested, so we must set it. */ + set_packet_in_format(vconn, preferred_packet_in_format, true); } else { - enum ofp_version version = vconn_get_version(vconn); - - switch (version) { - case OFP10_VERSION: { - struct ofpbuf *spif, *reply; - - spif = ofputil_make_set_packet_in_format(vconn_get_version(vconn), - NXPIF_NXM); - run(vconn_transact_noreply(vconn, spif, &reply), - "talking to %s", vconn_get_name(vconn)); - if (reply) { - char *s = ofp_to_string(reply->data, reply->size, 2); - VLOG_DBG("%s: failed to set packet in format to nxm, controller" - " replied: %s. Falling back to the switch default.", - vconn_get_name(vconn), s); - free(s); - ofpbuf_delete(reply); + /* Otherwise, we always prefer NXT_PACKET_IN2. */ + if (!set_packet_in_format(vconn, NXPIF_NXT_PACKET_IN2, false)) { + /* We can't get NXT_PACKET_IN2. For OpenFlow 1.0 only, request + * NXT_PACKET_IN. (Before 2.6, Open vSwitch will accept a request + * for NXT_PACKET_IN with OF1.1+, but even after that it still + * sends packet-ins in the OpenFlow native format.) */ + if (vconn_get_version(vconn) == OFP10_VERSION) { + set_packet_in_format(vconn, NXPIF_NXT_PACKET_IN, false); } - break; - } - case OFP11_VERSION: - case OFP12_VERSION: - case OFP13_VERSION: - case OFP14_VERSION: - case OFP15_VERSION: - break; - default: - OVS_NOT_REACHED(); } } - monitor_vconn(vconn, true); + monitor_vconn(vconn, true, resume_continuations); } static void @@ -1812,7 +1863,7 @@ ofctl_snoop(struct ovs_cmdl_context *ctx) struct vconn *vconn; open_vconn__(ctx->argv[1], SNOOP, &vconn); - monitor_vconn(vconn, false); + monitor_vconn(vconn, false, false); } static void @@ -1987,18 +2038,16 @@ fetch_table_desc(struct vconn *vconn, struct ofputil_table_mod *tm, recv_xid = ((struct ofp_header *) reply->data)->xid; if (send_xid == recv_xid) { struct ofp_header *oh = reply->data; - enum ofptype type; - struct ofpbuf b; - uint16_t flags; + struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length)); - ofpbuf_use_const(&b, oh, ntohs(oh->length)); + enum ofptype type; if (ofptype_pull(&type, &b) || type != OFPTYPE_TABLE_DESC_REPLY) { ovs_fatal(0, "received bad reply: %s", ofp_to_string(reply->data, reply->size, verbosity + 1)); } - flags = ofpmp_flags(oh); + uint16_t flags = ofpmp_flags(oh); done = !(flags & OFPSF_REPLY_MORE); if (found) { /* We've already found the table desc consisting of current @@ -3610,35 +3659,43 @@ ofctl_parse_ofp11_match(struct ovs_cmdl_context *ctx OVS_UNUSED) ds_destroy(&in); } -/* "parse-pcap PCAP": read packets from PCAP and print their flows. */ +/* "parse-pcap PCAP...": read packets from each PCAP file and print their + * flows. */ static void ofctl_parse_pcap(struct ovs_cmdl_context *ctx) { - FILE *pcap; + int error = 0; + for (int i = 1; i < ctx->argc; i++) { + const char *filename = ctx->argv[i]; + FILE *pcap = ovs_pcap_open(filename, "rb"); + if (!pcap) { + error = errno; + ovs_error(error, "%s: open failed", filename); + continue; + } - pcap = ovs_pcap_open(ctx->argv[1], "rb"); - if (!pcap) { - ovs_fatal(errno, "%s: open failed", ctx->argv[1]); - } + for (;;) { + struct dp_packet *packet; + struct flow flow; + int retval; - for (;;) { - struct dp_packet *packet; - struct flow flow; - int error; + retval = ovs_pcap_read(pcap, &packet, NULL); + if (retval == EOF) { + break; + } else if (retval) { + error = retval; + ovs_error(error, "%s: read failed", filename); + } - error = ovs_pcap_read(pcap, &packet, NULL); - if (error == EOF) { - break; - } else if (error) { - ovs_fatal(error, "%s: read failed", ctx->argv[1]); + pkt_metadata_init(&packet->md, ODPP_NONE); + flow_extract(packet, &flow); + flow_print(stdout, &flow); + putchar('\n'); + dp_packet_delete(packet); } - - pkt_metadata_init(&packet->md, ODPP_NONE); - flow_extract(packet, &flow); - flow_print(stdout, &flow); - putchar('\n'); - dp_packet_delete(packet); + fclose(pcap); } + exit(error); } /* "check-vlan VLAN_TCI VLAN_TCI_MASK": converts the specified vlan_tci and @@ -3883,8 +3940,8 @@ static const struct ovs_cmdl_command all_commands[] = { 1, 2, ofctl_dump_aggregate }, { "queue-stats", "switch [port [queue]]", 1, 3, ofctl_queue_stats }, - { "queue-get-config", "switch [port]", - 1, 2, ofctl_queue_get_config }, + { "queue-get-config", "switch [port [queue]]", + 1, 3, ofctl_queue_get_config }, { "add-flow", "switch flow", 2, 2, ofctl_add_flow }, { "add-flows", "switch file", @@ -3976,7 +4033,7 @@ static const struct ovs_cmdl_command all_commands[] = { { "parse-instructions", NULL, 1, 1, ofctl_parse_instructions }, { "parse-ofp10-match", NULL, 0, 0, ofctl_parse_ofp10_match }, { "parse-ofp11-match", NULL, 0, 0, ofctl_parse_ofp11_match }, - { "parse-pcap", NULL, 1, 1, ofctl_parse_pcap }, + { "parse-pcap", NULL, 1, INT_MAX, ofctl_parse_pcap }, { "check-vlan", NULL, 2, 2, ofctl_check_vlan }, { "print-error", NULL, 1, 1, ofctl_print_error }, { "encode-error-reply", NULL, 2, 2, ofctl_encode_error_reply },