X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=utilities%2Fovs-ofctl.c;h=91c7f28fed5935df2d388f39cfef3448b2c647e8;hb=dc723c447a797e555d400594133a35b9841eb1de;hp=1d1b47f95cc0898248d5c03a7b7852c37e995146;hpb=ba2fe8e9f17602a260a626c6a823584975dbe757;p=sliver-openvswitch.git diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 1d1b47f95..91c7f28fe 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include @@ -36,6 +36,7 @@ #include "compiler.h" #include "dirs.h" #include "dynamic-string.h" +#include "fatal-signal.h" #include "nx-match.h" #include "odp-util.h" #include "ofp-actions.h" @@ -113,7 +114,7 @@ main(int argc, char *argv[]) { set_program_name(argv[0]); parse_options(argc, argv); - signal(SIGPIPE, SIG_IGN); + fatal_ignore_sigpipe(); run_command(argc - optind, argv + optind, get_all_commands()); return 0; } @@ -281,6 +282,7 @@ usage(void) " show SWITCH show OpenFlow information\n" " dump-desc SWITCH print switch description\n" " dump-tables SWITCH print table stats\n" + " dump-table-features SWITCH print table features\n" " mod-port SWITCH IFACE ACT modify port behavior\n" " mod-table SWITCH MOD modify flow table behavior\n" " get-frags SWITCH print fragment handling behavior\n" @@ -325,7 +327,8 @@ usage(void) " benchmark TARGET N COUNT bandwidth of COUNT N-byte echos\n" "SWITCH or TARGET is an active OpenFlow connection method.\n" "\nOther commands:\n" - " ofp-parse FILE print messages read from FILE\n", + " ofp-parse FILE print messages read from FILE\n" + " ofp-parse-pcap PCAP print OpenFlow read from PCAP\n", program_name, program_name); vconn_usage(true, false, false); daemon_usage(); @@ -465,7 +468,7 @@ dump_transaction(struct vconn *vconn, struct ofpbuf *request) ofpmsg_update_length(request); run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_get_name(vconn)); - ofp_print(stdout, reply->data, reply->size, verbosity + 1); + ofp_print(stdout, ofpbuf_data(reply), ofpbuf_size(reply), verbosity + 1); ofpbuf_delete(reply); } @@ -484,13 +487,13 @@ dump_trivial_transaction(const char *vconn_name, enum ofpraw raw) static void dump_stats_transaction(struct vconn *vconn, struct ofpbuf *request) { - const struct ofp_header *request_oh = request->data; + const struct ofp_header *request_oh = ofpbuf_data(request); ovs_be32 send_xid = request_oh->xid; enum ofpraw request_raw; enum ofpraw reply_raw; bool done = false; - ofpraw_decode_partial(&request_raw, request->data, request->size); + ofpraw_decode_partial(&request_raw, ofpbuf_data(request), ofpbuf_size(request)); reply_raw = ofpraw_stats_request_to_reply(request_raw, request_oh->version); @@ -500,20 +503,20 @@ dump_stats_transaction(struct vconn *vconn, struct ofpbuf *request) struct ofpbuf *reply; run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed"); - recv_xid = ((struct ofp_header *) reply->data)->xid; + recv_xid = ((struct ofp_header *) ofpbuf_data(reply))->xid; if (send_xid == recv_xid) { enum ofpraw raw; - ofp_print(stdout, reply->data, reply->size, verbosity + 1); + ofp_print(stdout, ofpbuf_data(reply), ofpbuf_size(reply), verbosity + 1); - ofpraw_decode(&raw, reply->data); + ofpraw_decode(&raw, ofpbuf_data(reply)); if (ofptype_from_ofpraw(raw) == OFPTYPE_ERROR) { done = true; } else if (raw == reply_raw) { - done = !ofpmp_more(reply->data); + done = !ofpmp_more(ofpbuf_data(reply)); } else { ovs_fatal(0, "received bad reply: %s", - ofp_to_string(reply->data, reply->size, + ofp_to_string(ofpbuf_data(reply), ofpbuf_size(reply), verbosity + 1)); } } else { @@ -553,7 +556,7 @@ transact_multiple_noreply(struct vconn *vconn, struct list *requests) run(vconn_transact_multiple_noreply(vconn, requests, &reply), "talking to %s", vconn_get_name(vconn)); if (reply) { - ofp_print(stderr, reply->data, reply->size, verbosity + 2); + ofp_print(stderr, ofpbuf_data(reply), ofpbuf_size(reply), verbosity + 2); exit(1); } ofpbuf_delete(reply); @@ -623,7 +626,7 @@ ofctl_show(int argc OVS_UNUSED, char *argv[]) run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name); trunc = ofputil_switch_features_ports_trunc(reply); - ofp_print(stdout, reply->data, reply->size, verbosity + 1); + ofp_print(stdout, ofpbuf_data(reply), ofpbuf_size(reply), verbosity + 1); ofpbuf_delete(reply); @@ -650,6 +653,21 @@ ofctl_dump_tables(int argc OVS_UNUSED, char *argv[]) dump_trivial_stats_transaction(argv[1], OFPRAW_OFPST_TABLE_REQUEST); } +static void +ofctl_dump_table_features(int argc OVS_UNUSED, char *argv[]) +{ + struct ofpbuf *request; + struct vconn *vconn; + + open_vconn(argv[1], &vconn); + request = ofputil_encode_table_features_request(vconn_get_version(vconn)); + if (request) { + dump_stats_transaction(vconn, request); + } + + vconn_close(vconn); +} + static bool fetch_port_by_features(const char *vconn_name, const char *port_name, ofp_port_t port_no, @@ -671,8 +689,8 @@ fetch_port_by_features(const char *vconn_name, run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name); vconn_close(vconn); - oh = reply->data; - if (ofptype_decode(&type, reply->data) + oh = ofpbuf_data(reply); + if (ofptype_decode(&type, ofpbuf_data(reply)) || type != OFPTYPE_FEATURES_REPLY) { ovs_fatal(0, "%s: received bad features reply", vconn_name); } @@ -715,7 +733,7 @@ fetch_port_by_stats(const char *vconn_name, bool found = false; request = ofpraw_alloc(OFPRAW_OFPST_PORT_DESC_REQUEST, OFP10_VERSION, 0); - send_xid = ((struct ofp_header *) request->data)->xid; + send_xid = ((struct ofp_header *) ofpbuf_data(request))->xid; open_vconn(vconn_name, &vconn); send_openflow_buffer(vconn, request); @@ -724,9 +742,9 @@ fetch_port_by_stats(const char *vconn_name, struct ofpbuf *reply; run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed"); - recv_xid = ((struct ofp_header *) reply->data)->xid; + recv_xid = ((struct ofp_header *) ofpbuf_data(reply))->xid; if (send_xid == recv_xid) { - struct ofp_header *oh = reply->data; + struct ofp_header *oh = ofpbuf_data(reply); enum ofptype type; struct ofpbuf b; uint16_t flags; @@ -735,7 +753,7 @@ fetch_port_by_stats(const char *vconn_name, if (ofptype_pull(&type, &b) || type != OFPTYPE_PORT_DESC_STATS_REPLY) { ovs_fatal(0, "received bad reply: %s", - ofp_to_string(reply->data, reply->size, + ofp_to_string(ofpbuf_data(reply), ofpbuf_size(reply), verbosity + 1)); } @@ -840,7 +858,7 @@ try_set_protocol(struct vconn *vconn, enum ofputil_protocol want, run(vconn_transact_noreply(vconn, request, &reply), "talking to %s", vconn_get_name(vconn)); if (reply) { - char *s = ofp_to_string(reply->data, reply->size, 2); + char *s = ofp_to_string(ofpbuf_data(reply), ofpbuf_size(reply), 2); VLOG_DBG("%s: failed to set protocol, switch replied: %s", vconn_get_name(vconn), s); free(s); @@ -973,7 +991,7 @@ ofctl_dump_flows(int argc, char *argv[]) size_t i; vconn = prepare_dump_flows(argc, argv, false, &request); - send_xid = ((struct ofp_header *) request->data)->xid; + send_xid = ((struct ofp_header *) ofpbuf_data(request))->xid; send_openflow_buffer(vconn, request); fses = NULL; @@ -1008,7 +1026,7 @@ ofctl_dump_flows(int argc, char *argv[]) ds_destroy(&s); for (i = 0; i < n_fses; i++) { - free(fses[i].ofpacts); + free(CONST_CAST(struct ofpact *, fses[i].ofpacts)); } free(fses); @@ -1118,7 +1136,7 @@ ofctl_flow_mod__(const char *remote, struct ofputil_flow_mod *fms, struct ofputil_flow_mod *fm = &fms[i]; transact_noreply(vconn, ofputil_encode_flow_mod(fm, protocol)); - free(fm->ofpacts); + free(CONST_CAST(struct ofpact *, fm->ofpacts)); } vconn_close(vconn); } @@ -1243,13 +1261,13 @@ openflow_from_hex(const char *hex, struct ofpbuf **msgp) return "Trailing garbage in hex data"; } - if (msg->size < sizeof(struct ofp_header)) { + if (ofpbuf_size(msg) < sizeof(struct ofp_header)) { ofpbuf_delete(msg); return "Message too short for OpenFlow"; } - oh = msg->data; - if (msg->size != ntohs(oh->length)) { + oh = ofpbuf_data(msg); + if (ofpbuf_size(msg) != ntohs(oh->length)) { ofpbuf_delete(msg); return "Message size does not match length in OpenFlow header"; } @@ -1282,7 +1300,7 @@ ofctl_send(struct unixctl_conn *conn, int argc, } fprintf(stderr, "send: "); - ofp_print(stderr, msg->data, msg->size, verbosity); + ofp_print(stderr, ofpbuf_data(msg), ofpbuf_size(msg), verbosity); error = vconn_send_block(vconn, msg); if (error) { @@ -1431,8 +1449,8 @@ monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests) free(s); } - ofptype_decode(&type, b->data); - ofp_print(stderr, b->data, b->size, verbosity + 2); + ofptype_decode(&type, ofpbuf_data(b)); + ofp_print(stderr, ofpbuf_data(b), ofpbuf_size(b), verbosity + 2); switch ((int) type) { case OFPTYPE_BARRIER_REPLY: @@ -1446,7 +1464,7 @@ monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests) if (reply_to_echo_requests) { struct ofpbuf *reply; - reply = make_echo_reply(b->data); + reply = make_echo_reply(ofpbuf_data(b)); retval = vconn_send_block(vconn, reply); if (retval) { ovs_fatal(retval, "failed to send echo reply"); @@ -1525,7 +1543,7 @@ ofctl_monitor(int argc, char *argv[]) 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); + char *s = ofp_to_string(ofpbuf_data(reply), ofpbuf_size(reply), 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); @@ -1537,9 +1555,10 @@ ofctl_monitor(int argc, char *argv[]) case OFP11_VERSION: case OFP12_VERSION: case OFP13_VERSION: + case OFP14_VERSION: break; default: - NOT_REACHED(); + OVS_NOT_REACHED(); } } @@ -1585,7 +1604,7 @@ ofctl_probe(int argc OVS_UNUSED, char *argv[]) open_vconn(argv[1], &vconn); request = make_echo_request(vconn_get_version(vconn)); run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]); - if (reply->size != sizeof(struct ofp_header)) { + if (ofpbuf_size(reply) != sizeof(struct ofp_header)) { ovs_fatal(0, "reply does not match request"); } ofpbuf_delete(reply); @@ -1601,7 +1620,7 @@ ofctl_packet_out(int argc, char *argv[]) struct vconn *vconn; char *error; int i; - enum ofputil_protocol usable_protocols; /* TODO: Use in proto selection */ + enum ofputil_protocol usable_protocols; /* XXX: Use in proto selection */ ofpbuf_init(&ofpacts, 64); error = parse_ofpacts(argv[3], &ofpacts, &usable_protocols); @@ -1611,8 +1630,8 @@ ofctl_packet_out(int argc, char *argv[]) po.buffer_id = UINT32_MAX; po.in_port = str_to_port_no(argv[1], argv[2]); - po.ofpacts = ofpacts.data; - po.ofpacts_len = ofpacts.size; + po.ofpacts = ofpbuf_data(&ofpacts); + po.ofpacts_len = ofpbuf_size(&ofpacts); protocol = open_vconn(argv[1], &vconn); for (i = 4; i < argc; i++) { @@ -1624,8 +1643,8 @@ ofctl_packet_out(int argc, char *argv[]) ovs_fatal(0, "%s", error_msg); } - po.packet = packet->data; - po.packet_len = packet->size; + po.packet = ofpbuf_data(packet); + po.packet_len = ofpbuf_size(packet); opo = ofputil_encode_packet_out(&po, protocol); transact_noreply(vconn, opo); ofpbuf_delete(packet); @@ -1805,7 +1824,7 @@ ofctl_ofp_parse(int argc OVS_UNUSED, char *argv[]) length = ntohs(oh->length); if (length < sizeof *oh) { - ovs_fatal(0, "%s: %zu-byte message is too short for OpenFlow", + ovs_fatal(0, "%s: %"PRIuSIZE"-byte message is too short for OpenFlow", filename, length); } @@ -1816,7 +1835,7 @@ ofctl_ofp_parse(int argc OVS_UNUSED, char *argv[]) ovs_fatal(0, "%s: unexpected end of file mid-message", filename); } - ofp_print(stdout, b.data, b.size, verbosity + 2); + ofp_print(stdout, ofpbuf_data(&b), ofpbuf_size(&b), verbosity + 2); } ofpbuf_uninit(&b); @@ -1825,6 +1844,94 @@ ofctl_ofp_parse(int argc OVS_UNUSED, char *argv[]) } } +static bool +is_openflow_port(ovs_be16 port_, char *ports[]) +{ + uint16_t port = ntohs(port_); + if (ports[0]) { + int i; + + for (i = 0; ports[i]; i++) { + if (port == atoi(ports[i])) { + return true; + } + } + return false; + } else { + return port == OFP_PORT || port == OFP_OLD_PORT; + } +} + +static void +ofctl_ofp_parse_pcap(int argc OVS_UNUSED, char *argv[]) +{ + struct tcp_reader *reader; + FILE *file; + int error; + bool first; + + file = ovs_pcap_open(argv[1], "rb"); + if (!file) { + ovs_fatal(errno, "%s: open failed", argv[1]); + } + + reader = tcp_reader_open(); + first = true; + for (;;) { + struct ofpbuf *packet; + long long int when; + struct flow flow; + const struct pkt_metadata md = PKT_METADATA_INITIALIZER(ODPP_NONE); + + error = ovs_pcap_read(file, &packet, &when); + if (error) { + break; + } + flow_extract(packet, &md, &flow); + if (flow.dl_type == htons(ETH_TYPE_IP) + && flow.nw_proto == IPPROTO_TCP + && (is_openflow_port(flow.tp_src, argv + 2) || + is_openflow_port(flow.tp_dst, argv + 2))) { + struct ofpbuf *payload = tcp_reader_run(reader, &flow, packet); + if (payload) { + while (ofpbuf_size(payload) >= sizeof(struct ofp_header)) { + const struct ofp_header *oh; + void *data = ofpbuf_data(payload); + int length; + + /* Align OpenFlow on 8-byte boundary for safe access. */ + ofpbuf_shift(payload, -((intptr_t) data & 7)); + + oh = ofpbuf_data(payload); + length = ntohs(oh->length); + if (ofpbuf_size(payload) < length) { + break; + } + + if (!first) { + putchar('\n'); + } + first = false; + + if (timestamp) { + char *s = xastrftime_msec("%H:%M:%S.### ", when, true); + fputs(s, stdout); + free(s); + } + + printf(IP_FMT".%"PRIu16" > "IP_FMT".%"PRIu16":\n", + IP_ARGS(flow.nw_src), ntohs(flow.tp_src), + IP_ARGS(flow.nw_dst), ntohs(flow.tp_dst)); + ofp_print(stdout, ofpbuf_data(payload), length, verbosity + 1); + ofpbuf_pull(payload, length); + } + } + } + ofpbuf_delete(packet); + } + tcp_reader_close(reader); +} + static void ofctl_ping(int argc, char *argv[]) { @@ -1835,7 +1942,7 @@ ofctl_ping(int argc, char *argv[]) payload = argc > 2 ? atoi(argv[2]) : 64; if (payload > max_payload) { - ovs_fatal(0, "payload must be between 0 and %zu bytes", max_payload); + ovs_fatal(0, "payload must be between 0 and %"PRIuSIZE" bytes", max_payload); } open_vconn(argv[1], &vconn); @@ -1853,18 +1960,18 @@ ofctl_ping(int argc, char *argv[]) run(vconn_transact(vconn, ofpbuf_clone(request), &reply), "transact"); xgettimeofday(&end); - rpy_hdr = reply->data; + rpy_hdr = ofpbuf_data(reply); if (ofptype_pull(&type, reply) || type != OFPTYPE_ECHO_REPLY - || reply->size != payload - || memcmp(request->l3, reply->l3, payload)) { + || ofpbuf_size(reply) != payload + || memcmp(ofpbuf_l3(request), ofpbuf_l3(reply), payload)) { printf("Reply does not match request. Request:\n"); - ofp_print(stdout, request, request->size, verbosity + 2); + ofp_print(stdout, request, ofpbuf_size(request), verbosity + 2); printf("Reply:\n"); - ofp_print(stdout, reply, reply->size, verbosity + 2); + ofp_print(stdout, reply, ofpbuf_size(reply), verbosity + 2); } - printf("%zu bytes from %s: xid=%08"PRIx32" time=%.1f ms\n", - reply->size, argv[1], ntohl(rpy_hdr->xid), + printf("%"PRIu32" bytes from %s: xid=%08"PRIx32" time=%.1f ms\n", + ofpbuf_size(reply), argv[1], ntohl(rpy_hdr->xid), (1000*(double)(end.tv_sec - start.tv_sec)) + (.001*(end.tv_usec - start.tv_usec))); ofpbuf_delete(request); @@ -1886,7 +1993,7 @@ ofctl_benchmark(int argc OVS_UNUSED, char *argv[]) payload_size = atoi(argv[2]); if (payload_size > max_payload) { - ovs_fatal(0, "payload must be between 0 and %zu bytes", max_payload); + ovs_fatal(0, "payload must be between 0 and %"PRIuSIZE" bytes", max_payload); } message_size = sizeof(struct ofp_header) + payload_size; @@ -2092,7 +2199,7 @@ static void fte_version_free(struct fte_version *version) { if (version) { - free(version->ofpacts); + free(CONST_CAST(struct ofpact *, version->ofpacts)); free(version); } } @@ -2165,13 +2272,13 @@ fte_free_all(struct classifier *cls) struct cls_cursor cursor; struct fte *fte, *next; - ovs_rwlock_wrlock(&cls->rwlock); + fat_rwlock_wrlock(&cls->rwlock); cls_cursor_init(&cursor, cls, NULL); CLS_CURSOR_FOR_EACH_SAFE (fte, next, rule, &cursor) { classifier_remove(cls, &fte->rule); fte_free(fte); } - ovs_rwlock_unlock(&cls->rwlock); + fat_rwlock_unlock(&cls->rwlock); classifier_destroy(cls); } @@ -2190,9 +2297,9 @@ fte_insert(struct classifier *cls, const struct match *match, cls_rule_init(&fte->rule, match, priority); fte->versions[index] = version; - ovs_rwlock_wrlock(&cls->rwlock); + fat_rwlock_wrlock(&cls->rwlock); old = fte_from_cls_rule(classifier_replace(cls, &fte->rule)); - ovs_rwlock_unlock(&cls->rwlock); + fat_rwlock_unlock(&cls->rwlock); if (old) { fte_version_free(old->versions[index]); fte->versions[!index] = old->versions[!index]; @@ -2271,12 +2378,12 @@ recv_flow_stats_reply(struct vconn *vconn, ovs_be32 send_xid, do { run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed"); - } while (((struct ofp_header *) reply->data)->xid != send_xid); + } while (((struct ofp_header *) ofpbuf_data(reply))->xid != send_xid); - error = ofptype_decode(&type, reply->data); + error = ofptype_decode(&type, ofpbuf_data(reply)); if (error || type != OFPTYPE_FLOW_STATS_REPLY) { ovs_fatal(0, "received bad reply: %s", - ofp_to_string(reply->data, reply->size, + ofp_to_string(ofpbuf_data(reply), ofpbuf_size(reply), verbosity + 1)); } } @@ -2289,7 +2396,7 @@ recv_flow_stats_reply(struct vconn *vconn, ovs_be32 send_xid, return true; case EOF: - more = ofpmp_more(reply->l2); + more = ofpmp_more(reply->frame); ofpbuf_delete(reply); reply = NULL; if (!more) { @@ -2326,7 +2433,7 @@ read_flows_from_switch(struct vconn *vconn, fsr.table_id = 0xff; fsr.cookie = fsr.cookie_mask = htonll(0); request = ofputil_encode_flow_stats_request(&fsr, protocol); - send_xid = ((struct ofp_header *) request->data)->xid; + send_xid = ((struct ofp_header *) ofpbuf_data(request))->xid; send_openflow_buffer(vconn, request); reply = NULL; @@ -2403,7 +2510,7 @@ ofctl_replace_flows(int argc OVS_UNUSED, char *argv[]) list_init(&requests); /* Delete flows that exist on the switch but not in the file. */ - ovs_rwlock_rdlock(&cls.rwlock); + fat_rwlock_rdlock(&cls.rwlock); cls_cursor_init(&cursor, &cls, NULL); CLS_CURSOR_FOR_EACH (fte, rule, &cursor) { struct fte_version *file_ver = fte->versions[FILE_IDX]; @@ -2427,7 +2534,7 @@ ofctl_replace_flows(int argc OVS_UNUSED, char *argv[]) fte_make_flow_mod(fte, FILE_IDX, OFPFC_ADD, protocol, &requests); } } - ovs_rwlock_unlock(&cls.rwlock); + fat_rwlock_unlock(&cls.rwlock); transact_multiple_noreply(vconn, &requests); vconn_close(vconn); @@ -2469,7 +2576,7 @@ ofctl_diff_flows(int argc OVS_UNUSED, char *argv[]) ds_init(&a_s); ds_init(&b_s); - ovs_rwlock_rdlock(&cls.rwlock); + fat_rwlock_rdlock(&cls.rwlock); cls_cursor_init(&cursor, &cls, NULL); CLS_CURSOR_FOR_EACH (fte, rule, &cursor) { struct fte_version *a = fte->versions[0]; @@ -2489,7 +2596,7 @@ ofctl_diff_flows(int argc OVS_UNUSED, char *argv[]) } } } - ovs_rwlock_unlock(&cls.rwlock); + fat_rwlock_unlock(&cls.rwlock); ds_destroy(&a_s); ds_destroy(&b_s); @@ -2629,10 +2736,10 @@ ofctl_parse_flows__(struct ofputil_flow_mod *fms, size_t n_fms, struct ofpbuf *msg; msg = ofputil_encode_flow_mod(fm, protocol); - ofp_print(stdout, msg->data, msg->size, verbosity); + ofp_print(stdout, ofpbuf_data(msg), ofpbuf_size(msg), verbosity); ofpbuf_delete(msg); - free(fm->ofpacts); + free(CONST_CAST(struct ofpact *, fm->ofpacts)); } } @@ -2722,7 +2829,7 @@ ofctl_parse_nxm__(bool oxm) } else { match_len = nx_put_match(&nx_match, &match, cookie, cookie_mask); - out = nx_match_to_string(nx_match.data, match_len); + out = nx_match_to_string(ofpbuf_data(&nx_match), match_len); } puts(out); @@ -2766,15 +2873,15 @@ print_differences(const char *prefix, for (i = 0; i < MIN(a_len, b_len); i++) { if (a[i] != b[i]) { - printf("%s%2zu: %02"PRIx8" -> %02"PRIx8"\n", + printf("%s%2"PRIuSIZE": %02"PRIx8" -> %02"PRIx8"\n", prefix, i, a[i], b[i]); } } for (i = a_len; i < b_len; i++) { - printf("%s%2zu: (none) -> %02"PRIx8"\n", prefix, i, b[i]); + printf("%s%2"PRIuSIZE": (none) -> %02"PRIx8"\n", prefix, i, b[i]); } for (i = b_len; i < a_len; i++) { - printf("%s%2zu: %02"PRIx8" -> (none)\n", prefix, i, a[i]); + printf("%s%2"PRIuSIZE": %02"PRIx8" -> (none)\n", prefix, i, a[i]); } } @@ -2804,8 +2911,8 @@ ofctl_parse_ofp10_actions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) /* Convert to ofpacts. */ ofpbuf_init(&ofpacts, 0); - size = of10_in.size; - error = ofpacts_pull_openflow_actions(&of10_in, of10_in.size, + size = ofpbuf_size(&of10_in); + error = ofpacts_pull_openflow_actions(&of10_in, ofpbuf_size(&of10_in), OFP10_VERSION, &ofpacts); if (error) { printf("bad OF1.1 actions: %s\n\n", ofperr_get_name(error)); @@ -2818,17 +2925,17 @@ ofctl_parse_ofp10_actions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) /* Print cls_rule. */ ds_init(&s); ds_put_cstr(&s, "actions="); - ofpacts_format(ofpacts.data, ofpacts.size, &s); + ofpacts_format(ofpbuf_data(&ofpacts), ofpbuf_size(&ofpacts), &s); puts(ds_cstr(&s)); ds_destroy(&s); /* Convert back to ofp10 actions and print differences from input. */ ofpbuf_init(&of10_out, 0); - ofpacts_put_openflow_actions(ofpacts.data, ofpacts.size, &of10_out, + ofpacts_put_openflow_actions(ofpbuf_data(&ofpacts), ofpbuf_size(&ofpacts), &of10_out, OFP10_VERSION); - print_differences("", of10_in.data, of10_in.size, - of10_out.data, of10_out.size); + print_differences("", ofpbuf_data(&of10_in), ofpbuf_size(&of10_in), + ofpbuf_data(&of10_out), ofpbuf_size(&of10_out)); putchar('\n'); ofpbuf_uninit(&ofpacts); @@ -2874,9 +2981,9 @@ ofctl_parse_ofp10_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) if (ofpbuf_put_hex(&match_expout, ds_cstr(&expout), NULL)[0] != '\0') { ovs_fatal(0, "Trailing garbage in hex data"); } - if (match_expout.size != sizeof(struct ofp10_match)) { - ovs_fatal(0, "Input is %zu bytes, expected %zu", - match_expout.size, sizeof(struct ofp10_match)); + if (ofpbuf_size(&match_expout) != sizeof(struct ofp10_match)) { + ovs_fatal(0, "Input is %"PRIu32" bytes, expected %"PRIuSIZE, + ofpbuf_size(&match_expout), sizeof(struct ofp10_match)); } /* Parse hex bytes for input. */ @@ -2889,18 +2996,18 @@ ofctl_parse_ofp10_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) if (ofpbuf_put_hex(&match_in, ds_cstr(&in), NULL)[0] != '\0') { ovs_fatal(0, "Trailing garbage in hex data"); } - if (match_in.size != sizeof(struct ofp10_match)) { - ovs_fatal(0, "Input is %zu bytes, expected %zu", - match_in.size, sizeof(struct ofp10_match)); + if (ofpbuf_size(&match_in) != sizeof(struct ofp10_match)) { + ovs_fatal(0, "Input is %"PRIu32" bytes, expected %"PRIuSIZE, + ofpbuf_size(&match_in), sizeof(struct ofp10_match)); } /* Convert to cls_rule and print. */ - ofputil_match_from_ofp10_match(match_in.data, &match); + ofputil_match_from_ofp10_match(ofpbuf_data(&match_in), &match); match_print(&match); /* Convert back to ofp10_match and print differences from input. */ ofputil_match_to_ofp10_match(&match, &match_out); - print_differences("", match_expout.data, match_expout.size, + print_differences("", ofpbuf_data(&match_expout), ofpbuf_size(&match_expout), &match_out, sizeof match_out); /* Normalize, then convert and compare again. */ @@ -2938,13 +3045,13 @@ ofctl_parse_ofp11_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) if (ofpbuf_put_hex(&match_in, ds_cstr(&in), NULL)[0] != '\0') { ovs_fatal(0, "Trailing garbage in hex data"); } - if (match_in.size != sizeof(struct ofp11_match)) { - ovs_fatal(0, "Input is %zu bytes, expected %zu", - match_in.size, sizeof(struct ofp11_match)); + if (ofpbuf_size(&match_in) != sizeof(struct ofp11_match)) { + ovs_fatal(0, "Input is %"PRIu32" bytes, expected %"PRIuSIZE, + ofpbuf_size(&match_in), sizeof(struct ofp11_match)); } /* Convert to match. */ - error = ofputil_match_from_ofp11_match(match_in.data, &match); + error = ofputil_match_from_ofp11_match(ofpbuf_data(&match_in), &match); if (error) { printf("bad ofp11_match: %s\n\n", ofperr_get_name(error)); ofpbuf_uninit(&match_in); @@ -2957,7 +3064,7 @@ ofctl_parse_ofp11_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) /* Convert back to ofp11_match and print differences from input. */ ofputil_match_to_ofp11_match(&match, &match_out); - print_differences("", match_in.data, match_in.size, + print_differences("", ofpbuf_data(&match_in), ofpbuf_size(&match_in), &match_out, sizeof match_out); putchar('\n'); @@ -2992,8 +3099,8 @@ ofctl_parse_ofp11_actions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) /* Convert to ofpacts. */ ofpbuf_init(&ofpacts, 0); - size = of11_in.size; - error = ofpacts_pull_openflow_actions(&of11_in, of11_in.size, + size = ofpbuf_size(&of11_in); + error = ofpacts_pull_openflow_actions(&of11_in, ofpbuf_size(&of11_in), OFP11_VERSION, &ofpacts); if (error) { printf("bad OF1.1 actions: %s\n\n", ofperr_get_name(error)); @@ -3006,17 +3113,17 @@ ofctl_parse_ofp11_actions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) /* Print cls_rule. */ ds_init(&s); ds_put_cstr(&s, "actions="); - ofpacts_format(ofpacts.data, ofpacts.size, &s); + ofpacts_format(ofpbuf_data(&ofpacts), ofpbuf_size(&ofpacts), &s); puts(ds_cstr(&s)); ds_destroy(&s); /* Convert back to ofp11 actions and print differences from input. */ ofpbuf_init(&of11_out, 0); - ofpacts_put_openflow_actions(ofpacts.data, ofpacts.size, &of11_out, + ofpacts_put_openflow_actions(ofpbuf_data(&ofpacts), ofpbuf_size(&ofpacts), &of11_out, OFP11_VERSION); - print_differences("", of11_in.data, of11_in.size, - of11_out.data, of11_out.size); + print_differences("", ofpbuf_data(&of11_in), ofpbuf_size(&of11_in), + ofpbuf_data(&of11_out), ofpbuf_size(&of11_out)); putchar('\n'); ofpbuf_uninit(&ofpacts); @@ -3062,14 +3169,14 @@ ofctl_parse_ofp11_instructions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) /* Convert to ofpacts. */ ofpbuf_init(&ofpacts, 0); - size = of11_in.size; - error = ofpacts_pull_openflow_instructions(&of11_in, of11_in.size, + size = ofpbuf_size(&of11_in); + error = ofpacts_pull_openflow_instructions(&of11_in, ofpbuf_size(&of11_in), OFP11_VERSION, &ofpacts); if (!error) { /* Verify actions, enforce consistency. */ struct flow flow; memset(&flow, 0, sizeof flow); - error = ofpacts_check_consistency(ofpacts.data, ofpacts.size, + error = ofpacts_check_consistency(ofpbuf_data(&ofpacts), ofpbuf_size(&ofpacts), &flow, OFPP_MAX, table_id ? atoi(table_id) : 0, 255, OFPUTIL_P_OF11_STD); @@ -3085,18 +3192,18 @@ ofctl_parse_ofp11_instructions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) /* Print cls_rule. */ ds_init(&s); ds_put_cstr(&s, "actions="); - ofpacts_format(ofpacts.data, ofpacts.size, &s); + ofpacts_format(ofpbuf_data(&ofpacts), ofpbuf_size(&ofpacts), &s); puts(ds_cstr(&s)); ds_destroy(&s); /* Convert back to ofp11 instructions and print differences from * input. */ ofpbuf_init(&of11_out, 0); - ofpacts_put_openflow_instructions(ofpacts.data, ofpacts.size, + ofpacts_put_openflow_instructions(ofpbuf_data(&ofpacts), ofpbuf_size(&ofpacts), &of11_out, OFP13_VERSION); - print_differences("", of11_in.data, of11_in.size, - of11_out.data, of11_out.size); + print_differences("", ofpbuf_data(&of11_in), ofpbuf_size(&of11_in), + ofpbuf_data(&of11_out), ofpbuf_size(&of11_out)); putchar('\n'); ofpbuf_uninit(&ofpacts); @@ -3112,7 +3219,7 @@ ofctl_parse_pcap(int argc OVS_UNUSED, char *argv[]) { FILE *pcap; - pcap = pcap_open(argv[1], "rb"); + pcap = ovs_pcap_open(argv[1], "rb"); if (!pcap) { ovs_fatal(errno, "%s: open failed", argv[1]); } @@ -3120,16 +3227,17 @@ ofctl_parse_pcap(int argc OVS_UNUSED, char *argv[]) for (;;) { struct ofpbuf *packet; struct flow flow; + const struct pkt_metadata md = PKT_METADATA_INITIALIZER(ODPP_NONE); int error; - error = pcap_read(pcap, &packet); + error = ovs_pcap_read(pcap, &packet, NULL); if (error == EOF) { break; } else if (error) { ovs_fatal(error, "%s: read failed", argv[1]); } - flow_extract(packet, 0, 0, NULL, NULL, &flow); + flow_extract(packet, &md, &flow); flow_print(stdout, &flow); putchar('\n'); ofpbuf_delete(packet); @@ -3182,7 +3290,7 @@ ofctl_check_vlan(int argc OVS_UNUSED, char *argv[]) /* Convert to and from NXM. */ ofpbuf_init(&nxm, 0); nxm_match_len = nx_put_match(&nxm, &match, htonll(0), htonll(0)); - nxm_s = nx_match_to_string(nxm.data, nxm_match_len); + nxm_s = nx_match_to_string(ofpbuf_data(&nxm), nxm_match_len); error = nx_pull_match(&nxm, nxm_match_len, &nxm_match, NULL, NULL); printf("NXM: %s -> ", nxm_s); if (error) { @@ -3288,19 +3396,19 @@ ofctl_encode_error_reply(int argc OVS_UNUSED, char *argv[]) if (ofpbuf_put_hex(&request, argv[2], NULL)[0] != '\0') { ovs_fatal(0, "Trailing garbage in hex data"); } - if (request.size < sizeof(struct ofp_header)) { + if (ofpbuf_size(&request) < sizeof(struct ofp_header)) { ovs_fatal(0, "Request too short"); } - oh = request.data; - if (request.size != ntohs(oh->length)) { + oh = ofpbuf_data(&request); + if (ofpbuf_size(&request) != ntohs(oh->length)) { ovs_fatal(0, "Request size inconsistent"); } - reply = ofperr_encode_reply(error, request.data); + reply = ofperr_encode_reply(error, ofpbuf_data(&request)); ofpbuf_uninit(&request); - ovs_hex_dump(stdout, reply->data, reply->size, 0, false); + ovs_hex_dump(stdout, ofpbuf_data(reply), ofpbuf_size(reply), 0, false); ofpbuf_delete(reply); } @@ -3316,7 +3424,7 @@ ofctl_ofp_print(int argc, char *argv[]) if (ofpbuf_put_hex(&packet, argv[1], NULL)[0] != '\0') { ovs_fatal(0, "trailing garbage following hex bytes"); } - ofp_print(stdout, packet.data, packet.size, argc > 2 ? atoi(argv[2]) : 2); + ofp_print(stdout, ofpbuf_data(&packet), ofpbuf_size(&packet), argc > 2 ? atoi(argv[2]) : 2); ofpbuf_uninit(&packet); } @@ -3329,8 +3437,8 @@ ofctl_encode_hello(int argc OVS_UNUSED, char *argv[]) struct ofpbuf *hello; hello = ofputil_encode_hello(bitmap); - ovs_hex_dump(stdout, hello->data, hello->size, 0, false); - ofp_print(stdout, hello->data, hello->size, verbosity); + ovs_hex_dump(stdout, ofpbuf_data(hello), ofpbuf_size(hello), 0, false); + ofp_print(stdout, ofpbuf_data(hello), ofpbuf_size(hello), verbosity); ofpbuf_delete(hello); } @@ -3340,6 +3448,7 @@ static const struct command all_commands[] = { { "snoop", 1, 1, ofctl_snoop }, { "dump-desc", 1, 1, ofctl_dump_desc }, { "dump-tables", 1, 1, ofctl_dump_tables }, + { "dump-table-features", 1, 1, ofctl_dump_table_features }, { "dump-flows", 1, 2, ofctl_dump_flows }, { "dump-aggregate", 1, 2, ofctl_dump_aggregate }, { "queue-stats", 1, 3, ofctl_queue_stats }, @@ -3365,11 +3474,13 @@ static const struct command all_commands[] = { { "mod-table", 3, 3, ofctl_mod_table }, { "get-frags", 1, 1, ofctl_get_frags }, { "set-frags", 2, 2, ofctl_set_frags }, - { "ofp-parse", 1, 1, ofctl_ofp_parse }, { "probe", 1, 1, ofctl_probe }, { "ping", 1, 2, ofctl_ping }, { "benchmark", 3, 3, ofctl_benchmark }, + { "ofp-parse", 1, 1, ofctl_ofp_parse }, + { "ofp-parse-pcap", 1, INT_MAX, ofctl_ofp_parse_pcap }, + { "add-group", 1, 2, ofctl_add_group }, { "add-groups", 1, 2, ofctl_add_groups }, { "mod-group", 1, 2, ofctl_mod_group },