X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=utilities%2Fovs-ofctl.c;h=f82dedc497cf027f1085a93b1d0a56f59ee8e4ea;hb=6dc6ff914570fcbe770ed5a5e529229142c5b9c1;hp=04a869a2f5d8b0ab870fa13addc277836f0a12be;hpb=eaa71334348aa0d99abf5588e17b3e55d0db28ce;p=sliver-openvswitch.git diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 04a869a2f..f82dedc49 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009 Nicira Networks. + * Copyright (c) 2008, 2009, 2010 Nicira Networks. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,6 +48,7 @@ #include "util.h" #include "vconn-ssl.h" #include "vconn.h" +#include "xtoxll.h" #include "vlog.h" #define THIS_MODULE VLM_ofctl @@ -123,14 +124,15 @@ static void parse_options(int argc, char *argv[], struct settings *s) { enum { - OPT_STRICT = UCHAR_MAX + 1 + OPT_STRICT = UCHAR_MAX + 1, + VLOG_OPTION_ENUMS }; static struct option long_options[] = { {"timeout", required_argument, 0, 't'}, - {"verbose", optional_argument, 0, 'v'}, {"strict", no_argument, 0, OPT_STRICT}, {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, + VLOG_LONG_OPTIONS, VCONN_SSL_LONG_OPTIONS {0, 0, 0, 0}, }; @@ -166,14 +168,11 @@ parse_options(int argc, char *argv[], struct settings *s) OVS_PRINT_VERSION(OFP_VERSION, OFP_VERSION); exit(EXIT_SUCCESS); - case 'v': - vlog_set_verbosity(optarg); - break; - case OPT_STRICT: s->strict = true; break; + VLOG_OPTION_HANDLERS VCONN_SSL_OPTION_HANDLERS case '?': @@ -197,7 +196,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" - " dump-ports SWITCH print port statistics\n" + " dump-ports SWITCH [PORT] print port statistics\n" " dump-flows SWITCH print all flow entries\n" " dump-flows SWITCH FLOW print matching FLOWs\n" " dump-aggregate SWITCH print aggregate flow statistics\n" @@ -251,7 +250,7 @@ static void run(int retval, const char *message, ...) static void open_vconn(const char *name, struct vconn **vconnp) { - struct dpif dpif; + struct dpif *dpif; struct stat s; if (strstr(name, ":")) { @@ -268,9 +267,9 @@ open_vconn(const char *name, struct vconn **vconnp) char *socket_name; char *vconn_name; - run(dpif_get_name(&dpif, dpif_name, sizeof dpif_name), + run(dpif_port_get_name(dpif, ODPP_LOCAL, dpif_name, sizeof dpif_name), "obtaining name of %s", dpif_name); - dpif_close(&dpif); + dpif_close(dpif); if (strcmp(dpif_name, name)) { VLOG_INFO("datapath %s is named %s", name, dpif_name); } @@ -503,6 +502,48 @@ str_to_ip(const char *str_, uint32_t *ip) return n_wild; } +static uint16_t +str_to_port_no(const char *vconn_name, const char *str) +{ + struct ofpbuf *request, *reply; + struct ofp_switch_features *osf; + struct vconn *vconn; + int n_ports; + int port_idx; + unsigned int port_no; + + + /* Check if the argument is a port index. Otherwise, treat it as + * the port name. */ + if (str_to_uint(str, 10, &port_no)) { + return port_no; + } + + /* Send a "Features Request" to resolve the name into a number. */ + make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &request); + open_vconn(vconn_name, &vconn); + run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name); + + osf = reply->data; + n_ports = (reply->size - sizeof *osf) / sizeof *osf->ports; + + for (port_idx = 0; port_idx < n_ports; port_idx++) { + /* Check argument as an interface name */ + if (!strncmp((char *)osf->ports[port_idx].name, str, + sizeof osf->ports[0].name)) { + break; + } + } + if (port_idx == n_ports) { + ovs_fatal(0, "couldn't find monitored port: %s", str); + } + + ofpbuf_delete(reply); + vconn_close(vconn); + + return port_idx; +} + static void * put_action(struct ofpbuf *b, size_t size, uint16_t type) { @@ -599,6 +640,26 @@ str_to_action(char *str, struct ofpbuf *b) put_dl_addr_action(b, OFPAT_SET_DL_SRC, arg); } else if (!strcasecmp(act, "mod_dl_dst")) { put_dl_addr_action(b, OFPAT_SET_DL_DST, arg); + } else if (!strcasecmp(act, "mod_nw_src")) { + struct ofp_action_nw_addr *na; + na = put_action(b, sizeof *na, OFPAT_SET_NW_SRC); + str_to_ip(arg, &na->nw_addr); + } else if (!strcasecmp(act, "mod_nw_dst")) { + struct ofp_action_nw_addr *na; + na = put_action(b, sizeof *na, OFPAT_SET_NW_DST); + str_to_ip(arg, &na->nw_addr); + } else if (!strcasecmp(act, "mod_tp_src")) { + struct ofp_action_tp_port *ta; + ta = put_action(b, sizeof *ta, OFPAT_SET_TP_SRC); + ta->tp_port = htons(str_to_u32(arg)); + } else if (!strcasecmp(act, "mod_tp_dst")) { + struct ofp_action_tp_port *ta; + ta = put_action(b, sizeof *ta, OFPAT_SET_TP_DST); + ta->tp_port = htons(str_to_u32(arg)); + } else if (!strcasecmp(act, "mod_nw_tos")) { + struct ofp_action_nw_tos *nt; + nt = put_action(b, sizeof *nt, OFPAT_SET_NW_TOS); + nt->nw_tos = str_to_u32(arg); } else if (!strcasecmp(act, "output")) { put_output_action(b, str_to_u32(arg)); } else if (!strcasecmp(act, "drop")) { @@ -615,8 +676,10 @@ str_to_action(char *str, struct ofpbuf *b) /* Unless a numeric argument is specified, we send the whole * packet to the controller. */ - if (arg && (strspn(act, "0123456789") == strlen(act))) { + if (arg && (strspn(arg, "0123456789") == strlen(arg))) { oao->max_len = htons(str_to_u32(arg)); + } else { + oao->max_len = htons(UINT16_MAX); } } else if (parse_port_name(act, &port)) { put_output_action(b, port); @@ -670,6 +733,7 @@ parse_field(const char *name, const struct field **f_out) static const struct field fields[] = { { "in_port", OFPFW_IN_PORT, F_U16, F_OFS(in_port), 0 }, { "dl_vlan", OFPFW_DL_VLAN, F_U16, F_OFS(dl_vlan), 0 }, + { "dl_vlan_pcp", OFPFW_DL_VLAN_PCP, F_U8, F_OFS(dl_vlan_pcp), 0 }, { "dl_src", OFPFW_DL_SRC, F_MAC, F_OFS(dl_src), 0 }, { "dl_dst", OFPFW_DL_DST, F_MAC, F_OFS(dl_dst), 0 }, { "dl_type", OFPFW_DL_TYPE, F_U16, F_OFS(dl_type), 0 }, @@ -678,6 +742,7 @@ parse_field(const char *name, const struct field **f_out) { "nw_dst", OFPFW_NW_DST_MASK, F_IP, F_OFS(nw_dst), OFPFW_NW_DST_SHIFT }, { "nw_proto", OFPFW_NW_PROTO, F_U8, F_OFS(nw_proto), 0 }, + { "nw_tos", OFPFW_NW_TOS, F_U8, F_OFS(nw_tos), 0 }, { "tp_src", OFPFW_TP_SRC, F_U16, F_OFS(tp_src), 0 }, { "tp_dst", OFPFW_TP_DST, F_U16, F_OFS(tp_dst), 0 }, { "icmp_type", OFPFW_ICMP_TYPE, F_U16, F_OFS(icmp_type), 0 }, @@ -698,7 +763,8 @@ parse_field(const char *name, const struct field **f_out) static void str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions, uint8_t *table_idx, uint16_t *out_port, uint16_t *priority, - uint16_t *idle_timeout, uint16_t *hard_timeout) + uint16_t *idle_timeout, uint16_t *hard_timeout, + uint64_t *cookie) { char *save_ptr = NULL; char *name; @@ -719,6 +785,9 @@ str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions, if (hard_timeout) { *hard_timeout = OFP_FLOW_PERMANENT; } + if (cookie) { + *cookie = 0; + } if (actions) { char *act_str = strstr(string, "action"); if (!act_str) { @@ -767,6 +836,8 @@ str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions, *idle_timeout = atoi(value); } else if (hard_timeout && !strcmp(name, "hard_timeout")) { *hard_timeout = atoi(value); + } else if (cookie && !strcmp(name, "cookie")) { + *cookie = atoi(value); } else if (parse_field(name, &f)) { void *data = (char *) match + f->offset; if (!strcmp(value, "*") || !strcmp(value, "ANY")) { @@ -805,7 +876,7 @@ do_dump_flows(const struct settings *s UNUSED, int argc, char *argv[]) req = alloc_stats_request(sizeof *req, OFPST_FLOW, &request); str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL, - &req->table_id, &out_port, NULL, NULL, NULL); + &req->table_id, &out_port, NULL, NULL, NULL, NULL); memset(&req->pad, 0, sizeof req->pad); req->out_port = htons(out_port); @@ -821,7 +892,7 @@ do_dump_aggregate(const struct settings *s UNUSED, int argc, char *argv[]) req = alloc_stats_request(sizeof *req, OFPST_AGGREGATE, &request); str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL, - &req->table_id, &out_port, NULL, NULL, NULL); + &req->table_id, &out_port, NULL, NULL, NULL, NULL); memset(&req->pad, 0, sizeof req->pad); req->out_port = htons(out_port); @@ -835,21 +906,23 @@ do_add_flow(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) struct ofpbuf *buffer; struct ofp_flow_mod *ofm; uint16_t priority, idle_timeout, hard_timeout; + uint64_t cookie; struct ofp_match match; /* Parse and send. str_to_flow() will expand and reallocate the data in * 'buffer', so we can't keep pointers to across the str_to_flow() call. */ make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); str_to_flow(argv[2], &match, buffer, - NULL, NULL, &priority, &idle_timeout, &hard_timeout); + NULL, NULL, &priority, &idle_timeout, &hard_timeout, + &cookie); ofm = buffer->data; ofm->match = match; ofm->command = htons(OFPFC_ADD); + ofm->cookie = htonll(cookie); ofm->idle_timeout = htons(idle_timeout); ofm->hard_timeout = htons(hard_timeout); ofm->buffer_id = htonl(UINT32_MAX); ofm->priority = htons(priority); - ofm->reserved = htonl(0); open_vconn(argv[1], &vconn); send_openflow_buffer(vconn, buffer); @@ -873,6 +946,7 @@ do_add_flows(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) struct ofpbuf *buffer; struct ofp_flow_mod *ofm; uint16_t priority, idle_timeout, hard_timeout; + uint64_t cookie; struct ofp_match match; char *comment; @@ -893,15 +967,16 @@ do_add_flows(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) * call. */ ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); str_to_flow(line, &match, buffer, - NULL, NULL, &priority, &idle_timeout, &hard_timeout); + NULL, NULL, &priority, &idle_timeout, &hard_timeout, + &cookie); ofm = buffer->data; ofm->match = match; ofm->command = htons(OFPFC_ADD); + ofm->cookie = htonll(cookie); ofm->idle_timeout = htons(idle_timeout); ofm->hard_timeout = htons(hard_timeout); ofm->buffer_id = htonl(UINT32_MAX); ofm->priority = htons(priority); - ofm->reserved = htonl(0); send_openflow_buffer(vconn, buffer); } @@ -913,14 +988,20 @@ static void do_mod_flows(const struct settings *s, int argc UNUSED, char *argv[]) { uint16_t priority, idle_timeout, hard_timeout; + uint64_t cookie; struct vconn *vconn; struct ofpbuf *buffer; struct ofp_flow_mod *ofm; + struct ofp_match match; - /* Parse and send. */ - ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); - str_to_flow(argv[2], &ofm->match, buffer, - NULL, NULL, &priority, &idle_timeout, &hard_timeout); + /* Parse and send. str_to_flow() will expand and reallocate the data in + * 'buffer', so we can't keep pointers to across the str_to_flow() call. */ + make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); + str_to_flow(argv[2], &match, buffer, + NULL, NULL, &priority, &idle_timeout, &hard_timeout, + &cookie); + ofm = buffer->data; + ofm->match = match; if (s->strict) { ofm->command = htons(OFPFC_MODIFY_STRICT); } else { @@ -928,9 +1009,9 @@ do_mod_flows(const struct settings *s, int argc UNUSED, char *argv[]) } ofm->idle_timeout = htons(idle_timeout); ofm->hard_timeout = htons(hard_timeout); + ofm->cookie = htonll(cookie); ofm->buffer_id = htonl(UINT32_MAX); ofm->priority = htons(priority); - ofm->reserved = htonl(0); open_vconn(argv[1], &vconn); send_openflow_buffer(vconn, buffer); @@ -948,7 +1029,7 @@ static void do_del_flows(const struct settings *s, int argc, char *argv[]) /* Parse and send. */ ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer); str_to_flow(argc > 2 ? argv[2] : "", &ofm->match, NULL, NULL, - &out_port, &priority, NULL, NULL); + &out_port, &priority, NULL, NULL, NULL); if (s->strict) { ofm->command = htons(OFPFC_DELETE_STRICT); } else { @@ -959,7 +1040,6 @@ static void do_del_flows(const struct settings *s, int argc, char *argv[]) ofm->buffer_id = htonl(UINT32_MAX); ofm->out_port = htons(out_port); ofm->priority = htons(priority); - ofm->reserved = htonl(0); open_vconn(argv[1], &vconn); send_openflow_buffer(vconn, buffer); @@ -974,12 +1054,10 @@ do_monitor(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) open_vconn(argv[1], &vconn); if (argc > 2) { int miss_send_len = atoi(argv[2]); - int send_flow_exp = argc > 3 ? atoi(argv[3]) : 0; struct ofp_switch_config *osc; struct ofpbuf *buf; osc = make_openflow(sizeof *osc, OFPT_SET_CONFIG, &buf); - osc->flags = htons(send_flow_exp ? OFPC_SEND_FLOW_EXP : 0); osc->miss_send_len = htons(miss_send_len); send_openflow_buffer(vconn, buf); } @@ -992,9 +1070,16 @@ do_monitor(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) } static void -do_dump_ports(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) +do_dump_ports(const struct settings *s UNUSED, int argc, char *argv[]) { - dump_trivial_stats_transaction(argv[1], OFPST_PORT); + struct ofp_port_stats_request *req; + struct ofpbuf *request; + uint16_t port; + + req = alloc_stats_request(sizeof *req, OFPST_PORT, &request); + port = argc > 2 ? str_to_port_no(argv[1], argv[2]) : OFPP_NONE; + req->port_no = htons(port); + dump_stats_transaction(argv[1], request); } static void @@ -1131,7 +1216,7 @@ do_ping(const struct settings *s UNUSED, int argc, char *argv[]) printf("Reply:\n"); ofp_print(stdout, reply, reply->size, 2); } - printf("%d bytes from %s: xid=%08"PRIx32" time=%.1f ms\n", + printf("%zu bytes from %s: xid=%08"PRIx32" time=%.1f ms\n", reply->size - sizeof *rpy_hdr, argv[1], rpy_hdr->xid, (1000*(double)(end.tv_sec - start.tv_sec)) + (.001*(end.tv_usec - start.tv_usec))); @@ -1267,7 +1352,7 @@ static struct command all_commands[] = { { "add-flows", 2, 2, do_add_flows }, { "mod-flows", 2, 2, do_mod_flows }, { "del-flows", 1, 2, do_del_flows }, - { "dump-ports", 1, 1, do_dump_ports }, + { "dump-ports", 1, 2, do_dump_ports }, { "mod-port", 3, 3, do_mod_port }, { "probe", 1, 1, do_probe }, { "ping", 1, 2, do_ping },