X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=utilities%2Fovs-ofctl.c;h=e62e646912de9f543be4cdc4ebbb7617d7f05a6e;hb=7685b7a9e5b3f6db6832e52e111000ff36d3acb4;hp=1a1d4236c4e3a44a8ca9bba1115e935f77f4f6c4;hpb=8621547cc94ad91018ac0b662427a6fa20165a8d;p=sliver-openvswitch.git diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 1a1d4236c..e62e64691 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -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; } @@ -310,6 +311,7 @@ usage(void) " dump-group-features SWITCH print group features\n" " dump-groups SWITCH print group description\n" " dump-group-stats SWITCH [GROUP] print group statistics\n" + " queue-get-config SWITCH PORT print queue information for port\n" " add-meter SWITCH METER add meter described by METER\n" " mod-meter SWITCH METER modify specific METER\n" " del-meter SWITCH METER delete METER\n" @@ -324,7 +326,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(); @@ -889,9 +892,7 @@ prepare_dump_flows(int argc, char *argv[], bool aggregate, error = parse_ofp_flow_stats_request_str(&fsr, aggregate, argc > 2 ? argv[2] : "", - &usable_protocols, - !(allowed_protocols - & OFPUTIL_P_OF10_ANY)); + &usable_protocols); if (error) { ovs_fatal(0, "%s", error); } @@ -1048,6 +1049,26 @@ ofctl_queue_stats(int argc, char *argv[]) vconn_close(vconn); } +static void +ofctl_queue_get_config(int argc OVS_UNUSED, char *argv[]) +{ + const char *vconn_name = argv[1]; + const char *port_name = argv[2]; + enum ofputil_protocol protocol; + enum ofp_version version; + struct ofpbuf *request; + struct vconn *vconn; + ofp_port_t port; + + port = str_to_port_no(vconn_name, port_name); + + protocol = open_vconn(vconn_name, &vconn); + version = ofputil_protocol_to_ofp_version(protocol); + request = ofputil_encode_queue_get_config_request(version, port); + dump_transaction(vconn, request); + vconn_close(vconn); +} + static enum ofputil_protocol open_vconn_for_flow_mod(const char *remote, struct vconn **vconnp, enum ofputil_protocol usable_protocols) @@ -1113,8 +1134,7 @@ ofctl_flow_mod_file(int argc OVS_UNUSED, char *argv[], uint16_t command) char *error; error = parse_ofp_flow_mod_file(argv[2], command, &fms, &n_fms, - &usable_protocols, - !(allowed_protocols & OFPUTIL_P_OF10_ANY)); + &usable_protocols); if (error) { ovs_fatal(0, "%s", error); } @@ -1133,9 +1153,7 @@ ofctl_flow_mod(int argc, char *argv[], uint16_t command) enum ofputil_protocol usable_protocols; error = parse_ofp_flow_mod_str(&fm, argc > 2 ? argv[2] : "", command, - &usable_protocols, - !(allowed_protocols - & OFPUTIL_P_OF10_ANY)); + &usable_protocols); if (error) { ovs_fatal(0, "%s", error); } @@ -1523,7 +1541,7 @@ ofctl_monitor(int argc, char *argv[]) case OFP13_VERSION: break; default: - NOT_REACHED(); + OVS_NOT_REACHED(); } } @@ -1585,7 +1603,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); @@ -1789,7 +1807,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); } @@ -1809,6 +1827,93 @@ 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 (payload->size >= sizeof(struct ofp_header)) { + const struct ofp_header *oh; + int length; + + /* Align OpenFlow on 8-byte boundary for safe access. */ + ofpbuf_shift(payload, -((intptr_t) payload->data & 7)); + + oh = payload->data; + length = ntohs(oh->length); + if (payload->size < 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, payload->data, length, verbosity + 1); + ofpbuf_pull(payload, length); + } + } + } + ofpbuf_delete(packet); + } + tcp_reader_close(reader); +} + static void ofctl_ping(int argc, char *argv[]) { @@ -1819,7 +1924,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); @@ -1847,7 +1952,7 @@ ofctl_ping(int argc, char *argv[]) printf("Reply:\n"); ofp_print(stdout, reply, reply->size, verbosity + 2); } - printf("%zu bytes from %s: xid=%08"PRIx32" time=%.1f ms\n", + printf("%"PRIuSIZE" bytes from %s: xid=%08"PRIx32" time=%.1f ms\n", reply->size, argv[1], ntohl(rpy_hdr->xid), (1000*(double)(end.tv_sec - start.tv_sec)) + (.001*(end.tv_usec - start.tv_usec))); @@ -1870,7 +1975,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; @@ -2149,13 +2254,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); } @@ -2174,9 +2279,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]; @@ -2210,8 +2315,7 @@ read_flows_from_file(const char *filename, struct classifier *cls, int index) char *error; enum ofputil_protocol usable; - error = parse_ofp_str(&fm, OFPFC_ADD, ds_cstr(&s), &usable, - !(allowed_protocols & OFPUTIL_P_OF10_ANY)); + error = parse_ofp_str(&fm, OFPFC_ADD, ds_cstr(&s), &usable); if (error) { ovs_fatal(0, "%s:%d: %s", filename, line_number, error); } @@ -2377,7 +2481,7 @@ ofctl_replace_flows(int argc OVS_UNUSED, char *argv[]) struct vconn *vconn; struct fte *fte; - classifier_init(&cls); + classifier_init(&cls, NULL); usable_protocols = read_flows_from_file(argv[2], &cls, FILE_IDX); protocol = open_vconn(argv[1], &vconn); @@ -2388,7 +2492,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]; @@ -2412,7 +2516,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); @@ -2447,14 +2551,14 @@ ofctl_diff_flows(int argc OVS_UNUSED, char *argv[]) struct ds a_s, b_s; struct fte *fte; - classifier_init(&cls); + classifier_init(&cls, NULL); read_flows_from_source(argv[1], &cls, 0); read_flows_from_source(argv[2], &cls, 1); 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]; @@ -2474,7 +2578,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); @@ -2630,8 +2734,7 @@ ofctl_parse_flow(int argc OVS_UNUSED, char *argv[]) struct ofputil_flow_mod fm; char *error; - error = parse_ofp_flow_mod_str(&fm, argv[1], OFPFC_ADD, &usable_protocols, - !(allowed_protocols & OFPUTIL_P_OF10_ANY)); + error = parse_ofp_flow_mod_str(&fm, argv[1], OFPFC_ADD, &usable_protocols); if (error) { ovs_fatal(0, "%s", error); } @@ -2649,8 +2752,7 @@ ofctl_parse_flows(int argc OVS_UNUSED, char *argv[]) char *error; error = parse_ofp_flow_mod_file(argv[1], OFPFC_ADD, &fms, &n_fms, - &usable_protocols, - !(allowed_protocols & OFPUTIL_P_OF10_ANY)); + &usable_protocols); if (error) { ovs_fatal(0, "%s", error); } @@ -2753,15 +2855,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]); } } @@ -2792,7 +2894,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_openflow10(&of10_in, of10_in.size, &ofpacts); + error = ofpacts_pull_openflow_actions(&of10_in, of10_in.size, + OFP10_VERSION, &ofpacts); if (error) { printf("bad OF1.1 actions: %s\n\n", ofperr_get_name(error)); ofpbuf_uninit(&ofpacts); @@ -2810,7 +2913,8 @@ ofctl_parse_ofp10_actions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) /* Convert back to ofp10 actions and print differences from input. */ ofpbuf_init(&of10_out, 0); - ofpacts_put_openflow10(ofpacts.data, ofpacts.size, &of10_out); + ofpacts_put_openflow_actions(ofpacts.data, ofpacts.size, &of10_out, + OFP10_VERSION); print_differences("", of10_in.data, of10_in.size, of10_out.data, of10_out.size); @@ -2860,7 +2964,7 @@ ofctl_parse_ofp10_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) 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", + ovs_fatal(0, "Input is %"PRIuSIZE" bytes, expected %"PRIuSIZE, match_expout.size, sizeof(struct ofp10_match)); } @@ -2875,7 +2979,7 @@ ofctl_parse_ofp10_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) 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", + ovs_fatal(0, "Input is %"PRIuSIZE" bytes, expected %"PRIuSIZE, match_in.size, sizeof(struct ofp10_match)); } @@ -2924,7 +3028,7 @@ ofctl_parse_ofp11_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) 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", + ovs_fatal(0, "Input is %"PRIuSIZE" bytes, expected %"PRIuSIZE, match_in.size, sizeof(struct ofp11_match)); } @@ -2978,8 +3082,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_openflow11_actions(&of11_in, OFP11_VERSION, - of11_in.size, &ofpacts); + error = ofpacts_pull_openflow_actions(&of11_in, of11_in.size, + OFP11_VERSION, &ofpacts); if (error) { printf("bad OF1.1 actions: %s\n\n", ofperr_get_name(error)); ofpbuf_uninit(&ofpacts); @@ -2997,7 +3101,8 @@ ofctl_parse_ofp11_actions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) /* Convert back to ofp11 actions and print differences from input. */ ofpbuf_init(&of11_out, 0); - ofpacts_put_openflow11_actions(ofpacts.data, ofpacts.size, &of11_out); + ofpacts_put_openflow_actions(ofpacts.data, ofpacts.size, &of11_out, + OFP11_VERSION); print_differences("", of11_in.data, of11_in.size, of11_out.data, of11_out.size); @@ -3047,14 +3152,16 @@ 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_openflow11_instructions(&of11_in, OFP11_VERSION, - of11_in.size, &ofpacts); + error = ofpacts_pull_openflow_instructions(&of11_in, of11_in.size, + OFP11_VERSION, &ofpacts); if (!error) { /* Verify actions, enforce consistency. */ struct flow flow; memset(&flow, 0, sizeof flow); - error = ofpacts_check(ofpacts.data, ofpacts.size, &flow, OFPP_MAX, - table_id ? atoi(table_id) : 0, true); + error = ofpacts_check_consistency(ofpacts.data, ofpacts.size, + &flow, OFPP_MAX, + table_id ? atoi(table_id) : 0, + 255, OFPUTIL_P_OF11_STD); } if (error) { printf("bad OF1.1 instructions: %s\n\n", ofperr_get_name(error)); @@ -3074,8 +3181,8 @@ ofctl_parse_ofp11_instructions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) /* Convert back to ofp11 instructions and print differences from * input. */ ofpbuf_init(&of11_out, 0); - ofpacts_put_openflow11_instructions(ofpacts.data, ofpacts.size, - &of11_out); + ofpacts_put_openflow_instructions(ofpacts.data, ofpacts.size, + &of11_out, OFP13_VERSION); print_differences("", of11_in.data, of11_in.size, of11_out.data, of11_out.size); @@ -3094,7 +3201,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]); } @@ -3102,16 +3209,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); @@ -3152,8 +3260,7 @@ ofctl_check_vlan(int argc OVS_UNUSED, char *argv[]) string_s = match_to_string(&match, OFP_DEFAULT_PRIORITY); printf("%s -> ", string_s); fflush(stdout); - error_s = parse_ofp_str(&fm, -1, string_s, &usable_protocols, - !(allowed_protocols & OFPUTIL_P_OF10_ANY)); + error_s = parse_ofp_str(&fm, -1, string_s, &usable_protocols); if (error_s) { ovs_fatal(0, "%s", error_s); } @@ -3326,6 +3433,7 @@ static const struct command all_commands[] = { { "dump-flows", 1, 2, ofctl_dump_flows }, { "dump-aggregate", 1, 2, ofctl_dump_aggregate }, { "queue-stats", 1, 3, ofctl_queue_stats }, + { "queue-get-config", 2, 2, ofctl_queue_get_config }, { "add-flow", 2, 2, ofctl_add_flow }, { "add-flows", 2, 2, ofctl_add_flows }, { "mod-flows", 2, 2, ofctl_mod_flows }, @@ -3347,11 +3455,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 },