X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=utilities%2Fovs-ofctl.c;h=d9ee607b349435b7e9ffdac3c3ae6b13cb637060;hb=659586efcf6f9539282da9447007897907c41112;hp=2a171533e3863479027492a2969555318baa4b39;hpb=c69ee87c10818267f991236201150b1fa51ae519;p=openvswitch diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 2a171533..d9ee607b 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -48,6 +48,7 @@ #include "timeval.h" #include "util.h" #include "vconn.h" +#include "xtoxll.h" #include "vlog.h" #define THIS_MODULE VLM_ofctl @@ -152,7 +153,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" @@ -404,6 +405,20 @@ str_to_u32(const char *str) return value; } +static uint64_t +str_to_u64(const char *str) +{ + char *tail; + uint64_t value; + + errno = 0; + value = strtoull(str, &tail, 0); + if (errno == EINVAL || errno == ERANGE || *tail) { + ovs_fatal(0, "invalid numeric format %s", str); + } + return value; +} + static void str_to_mac(const char *str, uint8_t mac[6]) { @@ -468,6 +483,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) { @@ -580,6 +637,22 @@ str_to_action(char *str, struct ofpbuf *b) 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, "resubmit")) { + struct nx_action_resubmit *nar; + nar = put_action(b, sizeof *nar, OFPAT_VENDOR); + nar->vendor = htonl(NX_VENDOR_ID); + nar->subtype = htons(NXAST_RESUBMIT); + nar->in_port = htons(str_to_u32(arg)); + } else if (!strcasecmp(act, "set_tunnel")) { + struct nx_action_set_tunnel *nast; + nast = put_action(b, sizeof *nast, OFPAT_VENDOR); + nast->vendor = htonl(NX_VENDOR_ID); + nast->subtype = htons(NXAST_SET_TUNNEL); + nast->tun_id = htonl(str_to_u32(arg)); } else if (!strcasecmp(act, "output")) { put_output_action(b, str_to_u32(arg)); } else if (!strcasecmp(act, "drop")) { @@ -596,7 +669,7 @@ 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); @@ -650,9 +723,10 @@ static bool parse_field(const char *name, const struct field **f_out) { #define F_OFS(MEMBER) offsetof(struct ofp_match, MEMBER) - static const struct field fields[] = { + 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 }, @@ -661,6 +735,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 }, @@ -681,7 +756,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; @@ -702,14 +778,17 @@ 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) { ovs_fatal(0, "must specify an action"); } - *(act_str-1) = '\0'; + *act_str = '\0'; - act_str = strchr(act_str, '='); + act_str = strchr(act_str + 1, '='); if (!act_str) { ovs_fatal(0, "must specify an action"); } @@ -750,6 +829,10 @@ 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 = str_to_u64(value); + } else if (!strcmp(name, "tun_id_wild")) { + wildcards |= NXFW_TUN_ID; } else if (parse_field(name, &f)) { void *data = (char *) match + f->offset; if (!strcmp(value, "*") || !strcmp(value, "ANY")) { @@ -788,7 +871,7 @@ do_dump_flows(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); @@ -804,7 +887,7 @@ do_dump_aggregate(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); @@ -818,21 +901,23 @@ do_add_flow(int argc OVS_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); @@ -856,6 +941,7 @@ do_add_flows(int argc OVS_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; @@ -876,15 +962,16 @@ do_add_flows(int argc OVS_UNUSED, char *argv[]) * call. */ 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); } @@ -896,6 +983,7 @@ static void do_mod_flows(int argc OVS_UNUSED, char *argv[]) { uint16_t priority, idle_timeout, hard_timeout; + uint64_t cookie; struct vconn *vconn; struct ofpbuf *buffer; struct ofp_flow_mod *ofm; @@ -905,7 +993,8 @@ do_mod_flows(int argc OVS_UNUSED, char *argv[]) * '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; if (strict) { @@ -915,9 +1004,9 @@ do_mod_flows(int argc OVS_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); @@ -935,7 +1024,7 @@ static void do_del_flows(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 (strict) { ofm->command = htons(OFPFC_DELETE_STRICT); } else { @@ -946,7 +1035,24 @@ static void do_del_flows(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); + vconn_close(vconn); +} + +static void +do_tun_cookie(int argc OVS_UNUSED, char *argv[]) +{ + struct nxt_tun_id_cookie *tun_id_cookie; + struct ofpbuf *buffer; + struct vconn *vconn; + + tun_id_cookie = make_openflow(sizeof *tun_id_cookie, OFPT_VENDOR, &buffer); + + tun_id_cookie->vendor = htonl(NX_VENDOR_ID); + tun_id_cookie->subtype = htonl(NXT_TUN_ID_FROM_COOKIE); + tun_id_cookie->set = !strcmp(argv[2], "true"); open_vconn(argv[1], &vconn); send_openflow_buffer(vconn, buffer); @@ -961,12 +1067,10 @@ do_monitor(int argc OVS_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); } @@ -979,9 +1083,16 @@ do_monitor(int argc OVS_UNUSED, char *argv[]) } static void -do_dump_ports(int argc OVS_UNUSED, char *argv[]) +do_dump_ports(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 @@ -1189,7 +1300,8 @@ static const 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 }, + { "tun-cookie", 2, 2, do_tun_cookie }, + { "dump-ports", 1, 2, do_dump_ports }, { "mod-port", 3, 3, do_mod_port }, { "probe", 1, 1, do_probe }, { "ping", 1, 2, do_ping },