X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=utilities%2Fovs-ofctl.c;h=da0a54b6cea59805d82de60614388bb185ad1c84;hb=44a7e26dcc2a68c0293b38c03048f938f318f0fd;hp=547d50c5ba4dafa50680e0311644b1bd315d78d1;hpb=db0b6c2913dfda237f07881b059ba267f3388600;p=sliver-openvswitch.git diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 547d50c5b..da0a54b6c 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -50,6 +50,7 @@ #include "openflow/nicira-ext.h" #include "openflow/openflow.h" #include "packets.h" +#include "pcap-file.h" #include "poll-loop.h" #include "random.h" #include "stream-ssl.h" @@ -281,6 +282,7 @@ usage(void) " dump-desc SWITCH print switch description\n" " dump-tables SWITCH print table stats\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" " set-frags SWITCH FRAG_MODE set fragment handling behavior\n" " dump-ports SWITCH [PORT] print port statistics\n" @@ -301,6 +303,22 @@ usage(void) " monitor SWITCH [MISSLEN] [invalid_ttl] [watch:[...]]\n" " print packets received from SWITCH\n" " snoop SWITCH snoop on SWITCH and its controller\n" + " add-group SWITCH GROUP add group described by GROUP\n" + " add-group SWITCH FILE add group from FILE\n" + " mod-group SWITCH GROUP modify specific group\n" + " del-groups SWITCH [GROUP] delete matching GROUPs\n" + " 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" + " del-meters SWITCH delete all meters\n" + " dump-meter SWITCH METER print METER configuration\n" + " dump-meters SWITCH print all meter configuration\n" + " meter-stats SWITCH [METER] print meter statistics\n" + " meter-features SWITCH print meter features\n" "\nFor OpenFlow switches and controllers:\n" " probe TARGET probe whether TARGET is up\n" " ping TARGET [N] latency of N-byte echos\n" @@ -872,7 +890,9 @@ prepare_dump_flows(int argc, char *argv[], bool aggregate, error = parse_ofp_flow_stats_request_str(&fsr, aggregate, argc > 2 ? argv[2] : "", - &usable_protocols); + &usable_protocols, + !(allowed_protocols + & OFPUTIL_P_OF10_ANY)); if (error) { ovs_fatal(0, "%s", error); } @@ -1029,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) @@ -1094,7 +1134,8 @@ 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); + &usable_protocols, + !(allowed_protocols & OFPUTIL_P_OF10_ANY)); if (error) { ovs_fatal(0, "%s", error); } @@ -1105,16 +1146,17 @@ ofctl_flow_mod_file(int argc OVS_UNUSED, char *argv[], uint16_t command) static void ofctl_flow_mod(int argc, char *argv[], uint16_t command) { - enum ofputil_protocol usable_protocols; - if (argc > 2 && !strcmp(argv[2], "-")) { ofctl_flow_mod_file(argc, argv, command); } else { struct ofputil_flow_mod fm; char *error; + enum ofputil_protocol usable_protocols; error = parse_ofp_flow_mod_str(&fm, argc > 2 ? argv[2] : "", command, - &usable_protocols); + &usable_protocols, + !(allowed_protocols + & OFPUTIL_P_OF10_ANY)); if (error) { ovs_fatal(0, "%s", error); } @@ -1388,7 +1430,8 @@ monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests) run(retval, "vconn_recv"); if (timestamp) { - char *s = xastrftime("%Y-%m-%d %H:%M:%S: ", time_wall(), true); + char *s = xastrftime_msec("%Y-%m-%d %H:%M:%S.###: ", + time_wall_msec(), true); fputs(s, stderr); free(s); } @@ -1656,6 +1699,42 @@ found: vconn_close(vconn); } +static void +ofctl_mod_table(int argc OVS_UNUSED, char *argv[]) +{ + enum ofputil_protocol protocol, usable_protocols; + struct ofputil_table_mod tm; + struct vconn *vconn; + char *error; + int i; + + error = parse_ofp_table_mod(&tm, argv[2], argv[3], &usable_protocols); + if (error) { + ovs_fatal(0, "%s", error); + } + + protocol = open_vconn(argv[1], &vconn); + if (!(protocol & usable_protocols)) { + for (i = 0; i < sizeof(enum ofputil_protocol) * CHAR_BIT; i++) { + enum ofputil_protocol f = 1 << i; + if (f != protocol + && f & usable_protocols + && try_set_protocol(vconn, f, &protocol)) { + protocol = f; + break; + } + } + } + + if (!(protocol & usable_protocols)) { + char *usable_s = ofputil_protocols_to_string(usable_protocols); + ovs_fatal(0, "Switch does not support table mod message(%s)", usable_s); + } + + transact_noreply(vconn, ofputil_encode_table_mod(&tm, protocol)); + vconn_close(vconn); +} + static void ofctl_get_frags(int argc OVS_UNUSED, char *argv[]) { @@ -1842,6 +1921,153 @@ ofctl_benchmark(int argc OVS_UNUSED, char *argv[]) count * message_size / (duration / 1000.0)); } +static void +ofctl_group_mod__(const char *remote, struct ofputil_group_mod *gms, + size_t n_gms) +{ + struct ofputil_group_mod *gm; + struct ofpbuf *request; + + struct vconn *vconn; + size_t i; + + open_vconn(remote, &vconn); + + for (i = 0; i < n_gms; i++) { + gm = &gms[i]; + request = ofputil_encode_group_mod(vconn_get_version(vconn), gm); + if (request) { + transact_noreply(vconn, request); + } + } + + vconn_close(vconn); + +} + + +static void +ofctl_group_mod_file(int argc OVS_UNUSED, char *argv[], uint16_t command) +{ + struct ofputil_group_mod *gms = NULL; + enum ofputil_protocol usable_protocols; + size_t n_gms = 0; + char *error; + + error = parse_ofp_group_mod_file(argv[2], command, &gms, &n_gms, + &usable_protocols); + if (error) { + ovs_fatal(0, "%s", error); + } + ofctl_group_mod__(argv[1], gms, n_gms); + free(gms); +} + +static void +ofctl_group_mod(int argc, char *argv[], uint16_t command) +{ + if (argc > 2 && !strcmp(argv[2], "-")) { + ofctl_group_mod_file(argc, argv, command); + } else { + enum ofputil_protocol usable_protocols; + struct ofputil_group_mod gm; + char *error; + + error = parse_ofp_group_mod_str(&gm, command, argc > 2 ? argv[2] : "", + &usable_protocols); + if (error) { + ovs_fatal(0, "%s", error); + } + ofctl_group_mod__(argv[1], &gm, 1); + } +} + +static void +ofctl_add_group(int argc, char *argv[]) +{ + ofctl_group_mod(argc, argv, OFPGC11_ADD); +} + +static void +ofctl_add_groups(int argc, char *argv[]) +{ + ofctl_group_mod_file(argc, argv, OFPGC11_ADD); +} + +static void +ofctl_mod_group(int argc, char *argv[]) +{ + ofctl_group_mod(argc, argv, OFPGC11_MODIFY); +} + +static void +ofctl_del_groups(int argc, char *argv[]) +{ + ofctl_group_mod(argc, argv, OFPGC11_DELETE); +} + +static void +ofctl_dump_group_stats(int argc, char *argv[]) +{ + enum ofputil_protocol usable_protocols; + struct ofputil_group_mod gm; + struct ofpbuf *request; + struct vconn *vconn; + uint32_t group_id; + char *error; + + memset(&gm, 0, sizeof gm); + + error = parse_ofp_group_mod_str(&gm, OFPGC11_DELETE, + argc > 2 ? argv[2] : "", + &usable_protocols); + if (error) { + ovs_fatal(0, "%s", error); + } + + group_id = gm.group_id; + + open_vconn(argv[1], &vconn); + request = ofputil_encode_group_stats_request(vconn_get_version(vconn), + group_id); + if (request) { + dump_stats_transaction(vconn, request); + } + + vconn_close(vconn); +} + +static void +ofctl_dump_group_desc(int argc OVS_UNUSED, char *argv[]) +{ + struct ofpbuf *request; + struct vconn *vconn; + + open_vconn(argv[1], &vconn); + + request = ofputil_encode_group_desc_request(vconn_get_version(vconn)); + if (request) { + dump_stats_transaction(vconn, request); + } + + vconn_close(vconn); +} + +static void +ofctl_dump_group_features(int argc OVS_UNUSED, char *argv[]) +{ + struct ofpbuf *request; + struct vconn *vconn; + + open_vconn(argv[1], &vconn); + request = ofputil_encode_group_features_request(vconn_get_version(vconn)); + if (request) { + dump_stats_transaction(vconn, request); + } + + vconn_close(vconn); +} + static void ofctl_help(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) { @@ -1913,7 +2139,7 @@ fte_version_format(const struct fte *fte, int index, struct ds *s) ds_put_format(s, " hard_timeout=%"PRIu16, version->hard_timeout); } - ds_put_char(s, ' '); + ds_put_cstr(s, " actions="); ofpacts_format(version->ofpacts, version->ofpacts_len, s); ds_put_char(s, '\n'); @@ -2005,7 +2231,8 @@ 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); + error = parse_ofp_str(&fm, OFPFC_ADD, ds_cstr(&s), &usable, + !(allowed_protocols & OFPUTIL_P_OF10_ANY)); if (error) { ovs_fatal(0, "%s:%d: %s", filename, line_number, error); } @@ -2279,6 +2506,102 @@ ofctl_diff_flows(int argc OVS_UNUSED, char *argv[]) exit(2); } } + +static void +ofctl_meter_mod__(const char *bridge, const char *str, int command) +{ + struct ofputil_meter_mod mm; + struct vconn *vconn; + enum ofputil_protocol protocol; + enum ofputil_protocol usable_protocols; + enum ofp_version version; + + if (str) { + char *error; + error = parse_ofp_meter_mod_str(&mm, str, command, &usable_protocols); + if (error) { + ovs_fatal(0, "%s", error); + } + } else { + usable_protocols = OFPUTIL_P_OF13_UP; + mm.command = command; + mm.meter.meter_id = OFPM13_ALL; + } + + protocol = open_vconn_for_flow_mod(bridge, &vconn, usable_protocols); + version = ofputil_protocol_to_ofp_version(protocol); + transact_noreply(vconn, ofputil_encode_meter_mod(version, &mm)); + vconn_close(vconn); +} + +static void +ofctl_meter_request__(const char *bridge, const char *str, + enum ofputil_meter_request_type type) +{ + struct ofputil_meter_mod mm; + struct vconn *vconn; + enum ofputil_protocol usable_protocols; + enum ofputil_protocol protocol; + enum ofp_version version; + + if (str) { + char *error; + error = parse_ofp_meter_mod_str(&mm, str, -1, &usable_protocols); + if (error) { + ovs_fatal(0, "%s", error); + } + } else { + usable_protocols = OFPUTIL_P_OF13_UP; + mm.meter.meter_id = OFPM13_ALL; + } + + protocol = open_vconn_for_flow_mod(bridge, &vconn, usable_protocols); + version = ofputil_protocol_to_ofp_version(protocol); + transact_noreply(vconn, ofputil_encode_meter_request(version, + type, + mm.meter.meter_id)); + vconn_close(vconn); +} + + +static void +ofctl_add_meter(int argc OVS_UNUSED, char *argv[]) +{ + ofctl_meter_mod__(argv[1], argv[2], OFPMC13_ADD); +} + +static void +ofctl_mod_meter(int argc OVS_UNUSED, char *argv[]) +{ + ofctl_meter_mod__(argv[1], argv[2], OFPMC13_MODIFY); +} + +static void +ofctl_del_meters(int argc, char *argv[]) +{ + ofctl_meter_mod__(argv[1], argc > 2 ? argv[2] : NULL, OFPMC13_DELETE); +} + +static void +ofctl_dump_meters(int argc, char *argv[]) +{ + ofctl_meter_request__(argv[1], argc > 2 ? argv[2] : NULL, + OFPUTIL_METER_CONFIG); +} + +static void +ofctl_meter_stats(int argc, char *argv[]) +{ + ofctl_meter_request__(argv[1], argc > 2 ? argv[2] : NULL, + OFPUTIL_METER_STATS); +} + +static void +ofctl_meter_features(int argc OVS_UNUSED, char *argv[]) +{ + ofctl_meter_request__(argv[1], NULL, OFPUTIL_METER_FEATURES); +} + /* Undocumented commands for unit testing. */ @@ -2328,7 +2651,8 @@ 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); + error = parse_ofp_flow_mod_str(&fm, argv[1], OFPFC_ADD, &usable_protocols, + !(allowed_protocols & OFPUTIL_P_OF10_ANY)); if (error) { ovs_fatal(0, "%s", error); } @@ -2346,7 +2670,8 @@ 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); + &usable_protocols, + !(allowed_protocols & OFPUTIL_P_OF10_ANY)); if (error) { ovs_fatal(0, "%s", error); } @@ -2499,6 +2824,7 @@ 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); puts(ds_cstr(&s)); ds_destroy(&s); @@ -2673,8 +2999,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, of11_in.size, - &ofpacts); + error = ofpacts_pull_openflow11_actions(&of11_in, OFP11_VERSION, + of11_in.size, &ofpacts); if (error) { printf("bad OF1.1 actions: %s\n\n", ofperr_get_name(error)); ofpbuf_uninit(&ofpacts); @@ -2685,6 +3011,7 @@ 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); puts(ds_cstr(&s)); ds_destroy(&s); @@ -2741,14 +3068,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_openflow11_instructions(&of11_in, of11_in.size, - &ofpacts); + error = ofpacts_pull_openflow11_instructions(&of11_in, OFP11_VERSION, + of11_in.size, &ofpacts); if (!error) { - /* Verify actions. */ + /* 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); + table_id ? atoi(table_id) : 0, true); } if (error) { printf("bad OF1.1 instructions: %s\n\n", ofperr_get_name(error)); @@ -2760,6 +3087,7 @@ 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); puts(ds_cstr(&s)); ds_destroy(&s); @@ -2781,6 +3109,36 @@ ofctl_parse_ofp11_instructions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) ds_destroy(&in); } +/* "parse-pcap PCAP": read packets from PCAP and print their flows. */ +static void +ofctl_parse_pcap(int argc OVS_UNUSED, char *argv[]) +{ + FILE *pcap; + + pcap = pcap_open(argv[1], "rb"); + if (!pcap) { + ovs_fatal(errno, "%s: open failed", argv[1]); + } + + for (;;) { + struct ofpbuf *packet; + struct flow flow; + int error; + + error = pcap_read(pcap, &packet); + if (error == EOF) { + break; + } else if (error) { + ovs_fatal(error, "%s: read failed", argv[1]); + } + + flow_extract(packet, 0, 0, NULL, NULL, &flow); + flow_print(stdout, &flow); + putchar('\n'); + ofpbuf_delete(packet); + } +} + /* "check-vlan VLAN_TCI VLAN_TCI_MASK": converts the specified vlan_tci and * mask values to and from various formats and prints the results. */ static void @@ -2815,7 +3173,8 @@ 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); + error_s = parse_ofp_str(&fm, -1, string_s, &usable_protocols, + !(allowed_protocols & OFPUTIL_P_OF10_ANY)); if (error_s) { ovs_fatal(0, "%s", error_s); } @@ -2988,22 +3347,40 @@ 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 }, { "del-flows", 1, 2, ofctl_del_flows }, { "replace-flows", 2, 2, ofctl_replace_flows }, { "diff-flows", 2, 2, ofctl_diff_flows }, + { "add-meter", 2, 2, ofctl_add_meter }, + { "mod-meter", 2, 2, ofctl_mod_meter }, + { "del-meter", 2, 2, ofctl_del_meters }, + { "del-meters", 1, 1, ofctl_del_meters }, + { "dump-meter", 2, 2, ofctl_dump_meters }, + { "dump-meters", 1, 1, ofctl_dump_meters }, + { "meter-stats", 1, 2, ofctl_meter_stats }, + { "meter-features", 1, 1, ofctl_meter_features }, { "packet-out", 4, INT_MAX, ofctl_packet_out }, { "dump-ports", 1, 2, ofctl_dump_ports }, { "dump-ports-desc", 1, 1, ofctl_dump_ports_desc }, { "mod-port", 3, 3, ofctl_mod_port }, + { "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 }, + + { "add-group", 1, 2, ofctl_add_group }, + { "add-groups", 1, 2, ofctl_add_groups }, + { "mod-group", 1, 2, ofctl_mod_group }, + { "del-groups", 1, 2, ofctl_del_groups }, + { "dump-groups", 1, 1, ofctl_dump_group_desc }, + { "dump-group-stats", 1, 2, ofctl_dump_group_stats }, + { "dump-group-features", 1, 1, ofctl_dump_group_features }, { "help", 0, INT_MAX, ofctl_help }, /* Undocumented commands for testing. */ @@ -3017,6 +3394,7 @@ static const struct command all_commands[] = { { "parse-ofp11-match", 0, 0, ofctl_parse_ofp11_match }, { "parse-ofp11-actions", 0, 0, ofctl_parse_ofp11_actions }, { "parse-ofp11-instructions", 0, 0, ofctl_parse_ofp11_instructions }, + { "parse-pcap", 1, 1, ofctl_parse_pcap }, { "check-vlan", 2, 2, ofctl_check_vlan }, { "print-error", 1, 1, ofctl_print_error }, { "encode-error-reply", 2, 2, ofctl_encode_error_reply },