VLOG_DEFINE_THIS_MODULE(ofctl);
-
-#define MOD_PORT_CMD_UP "up"
-#define MOD_PORT_CMD_DOWN "down"
-#define MOD_PORT_CMD_FLOOD "flood"
-#define MOD_PORT_CMD_NOFLOOD "noflood"
-
/* Use strict matching for flow mod commands? */
static bool strict;
dump_stats_transaction(vconn_name, request);
}
+/* Sends 'request', which should be a request that only has a reply if an error
+ * occurs, and waits for it to succeed or fail. If an error does occur, prints
+ * it and exits with an error. */
+static void
+dump_noreply_transaction(struct vconn *vconn, struct ofpbuf *request)
+{
+ struct ofpbuf *reply;
+
+ update_openflow_length(request);
+ run(vconn_transact_noreply(vconn, request, &reply),
+ "talking to %s", vconn_get_name(vconn));
+ if (reply) {
+ ofp_print(stderr, reply->data, reply->size, 2);
+ exit(1);
+ }
+ ofpbuf_delete(reply);
+}
+
static void
do_show(int argc OVS_UNUSED, char *argv[])
{
dump_trivial_stats_transaction(argv[1], OFPST_TABLE);
}
-static uint16_t
-str_to_port_no(const char *vconn_name, const char *str)
+/* Opens a connection to 'vconn_name', fetches the ofp_phy_port structure for
+ * 'port_name' (which may be a port name or number), and copies it into
+ * '*oppp'. */
+static void
+fetch_ofp_phy_port(const char *vconn_name, const char *port_name,
+ struct ofp_phy_port *oppp)
{
struct ofpbuf *request, *reply;
struct ofp_switch_features *osf;
+ unsigned int port_no;
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;
+ /* Try to interpret the argument as a port number. */
+ if (!str_to_uint(port_name, 10, &port_no)) {
+ port_no = UINT_MAX;
}
- /* Send a "Features Request" to resolve the name into a number. */
+ /* Fetch the switch's ofp_switch_features. */
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;
+ if (reply->size < sizeof *osf) {
+ ovs_fatal(0, "%s: received too-short features reply (only %zu bytes)",
+ vconn_name, reply->size);
+ }
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;
+ const struct ofp_phy_port *opp = &osf->ports[port_idx];
+
+ if (port_no != UINT_MAX
+ ? htons(port_no) == opp->port_no
+ : !strncmp((char *) opp->name, port_name, sizeof opp->name)) {
+ *oppp = *opp;
+ ofpbuf_delete(reply);
+ vconn_close(vconn);
+ return;
}
}
- if (port_idx == n_ports) {
- ovs_fatal(0, "couldn't find monitored port: %s", str);
- }
+ ovs_fatal(0, "%s: couldn't find port `%s'", vconn_name, port_name);
+}
- ofpbuf_delete(reply);
- vconn_close(vconn);
+/* Returns the port number corresponding to 'port_name' (which may be a port
+ * name or number) within the switch 'vconn_name'. */
+static uint16_t
+str_to_port_no(const char *vconn_name, const char *port_name)
+{
+ unsigned int port_no;
- return ntohs(osf->ports[port_idx].port_no);
+ if (str_to_uint(port_name, 10, &port_no)) {
+ return port_no;
+ } else {
+ struct ofp_phy_port opp;
+
+ fetch_ofp_phy_port(vconn_name, port_name, &opp);
+ return ntohs(opp.port_no);
+ }
}
static void
do_add_flow(int argc OVS_UNUSED, char *argv[])
{
struct vconn *vconn;
- struct ofpbuf *buffer;
+ struct ofpbuf *request;
- buffer = parse_ofp_flow_mod_str(argv[2], OFPFC_ADD);
+ request = parse_ofp_flow_mod_str(argv[2], OFPFC_ADD);
open_vconn(argv[1], &vconn);
- send_openflow_buffer(vconn, buffer);
+ dump_noreply_transaction(vconn, request);
vconn_close(vconn);
}
open_vconn(argv[1], &vconn);
while ((b = parse_ofp_add_flow_file(file)) != NULL) {
- send_openflow_buffer(vconn, b);
+ dump_noreply_transaction(vconn, b);
}
vconn_close(vconn);
fclose(file);
command = strict ? OFPFC_MODIFY_STRICT : OFPFC_MODIFY;
buffer = parse_ofp_flow_mod_str(argv[2], command);
open_vconn(argv[1], &vconn);
- send_openflow_buffer(vconn, buffer);
+ dump_noreply_transaction(vconn, buffer);
vconn_close(vconn);
}
buffer = parse_ofp_flow_mod_str(argc > 2 ? argv[2] : "", command);
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_nxmsg(sizeof *tun_id_cookie, NXT_TUN_ID_FROM_COOKIE,
- &buffer);
- tun_id_cookie->set = !strcmp(argv[2], "true");
-
- open_vconn(argv[1], &vconn);
- send_openflow_buffer(vconn, buffer);
+ dump_noreply_transaction(vconn, buffer);
vconn_close(vconn);
}
osc = make_openflow(sizeof *osc, OFPT_SET_CONFIG, &buf);
osc->miss_send_len = htons(miss_send_len);
- send_openflow_buffer(vconn, buf);
+ dump_noreply_transaction(vconn, buf);
}
monitor_vconn(vconn);
}
static void
do_mod_port(int argc OVS_UNUSED, char *argv[])
{
- struct ofpbuf *request, *reply;
- struct ofp_switch_features *osf;
struct ofp_port_mod *opm;
+ struct ofp_phy_port opp;
+ struct ofpbuf *request;
struct vconn *vconn;
- char *endptr;
- int n_ports;
- int port_idx;
- int port_no;
-
- /* Check if the argument is a port index. Otherwise, treat it as
- * the port name. */
- port_no = strtol(argv[2], &endptr, 10);
- if (port_no == 0 && endptr == argv[2]) {
- port_no = -1;
- }
-
- /* Send a "Features Request" to get the information we need in order
- * to modify the port. */
- make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &request);
- open_vconn(argv[1], &vconn);
- run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]);
-
- osf = reply->data;
- n_ports = (reply->size - sizeof *osf) / sizeof *osf->ports;
-
- for (port_idx = 0; port_idx < n_ports; port_idx++) {
- if (port_no != -1) {
- /* Check argument as a port index */
- if (osf->ports[port_idx].port_no == htons(port_no)) {
- break;
- }
- } else {
- /* Check argument as an interface name */
- if (!strncmp((char *)osf->ports[port_idx].name, argv[2],
- sizeof osf->ports[0].name)) {
- break;
- }
-
- }
- }
- if (port_idx == n_ports) {
- ovs_fatal(0, "couldn't find monitored port: %s", argv[2]);
- }
+ fetch_ofp_phy_port(argv[1], argv[2], &opp);
opm = make_openflow(sizeof(struct ofp_port_mod), OFPT_PORT_MOD, &request);
- opm->port_no = osf->ports[port_idx].port_no;
- memcpy(opm->hw_addr, osf->ports[port_idx].hw_addr, sizeof opm->hw_addr);
+ opm->port_no = opp.port_no;
+ memcpy(opm->hw_addr, opp.hw_addr, sizeof opm->hw_addr);
opm->config = htonl(0);
opm->mask = htonl(0);
opm->advertise = htonl(0);
- printf("modifying port: %s\n", osf->ports[port_idx].name);
-
- if (!strncasecmp(argv[3], MOD_PORT_CMD_UP, sizeof MOD_PORT_CMD_UP)) {
+ if (!strcasecmp(argv[3], "up")) {
opm->mask |= htonl(OFPPC_PORT_DOWN);
- } else if (!strncasecmp(argv[3], MOD_PORT_CMD_DOWN,
- sizeof MOD_PORT_CMD_DOWN)) {
+ } else if (!strcasecmp(argv[3], "down")) {
opm->mask |= htonl(OFPPC_PORT_DOWN);
opm->config |= htonl(OFPPC_PORT_DOWN);
- } else if (!strncasecmp(argv[3], MOD_PORT_CMD_FLOOD,
- sizeof MOD_PORT_CMD_FLOOD)) {
+ } else if (!strcasecmp(argv[3], "flood")) {
opm->mask |= htonl(OFPPC_NO_FLOOD);
- } else if (!strncasecmp(argv[3], MOD_PORT_CMD_NOFLOOD,
- sizeof MOD_PORT_CMD_NOFLOOD)) {
+ } else if (!strcasecmp(argv[3], "noflood")) {
opm->mask |= htonl(OFPPC_NO_FLOOD);
opm->config |= htonl(OFPPC_NO_FLOOD);
} else {
ovs_fatal(0, "unknown mod-port command '%s'", argv[3]);
}
- send_openflow_buffer(vconn, request);
-
- ofpbuf_delete(reply);
+ open_vconn(argv[1], &vconn);
+ dump_noreply_transaction(vconn, request);
vconn_close(vconn);
}
{ "add-flows", 2, 2, do_add_flows },
{ "mod-flows", 2, 2, do_mod_flows },
{ "del-flows", 1, 2, do_del_flows },
- { "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 },