+static void do_mod_flows(const struct settings *s, int argc, char *argv[])
+{
+ uint16_t priority, idle_timeout, hard_timeout;
+ struct vconn *vconn;
+ struct ofpbuf *buffer;
+ struct ofp_flow_mod *ofm;
+ size_t size;
+ size_t actions_len = MAX_ACT_LEN;
+
+ /* Parse and send. */
+ size = sizeof *ofm + actions_len;
+ ofm = make_openflow(size, OFPT_FLOW_MOD, &buffer);
+ str_to_flow(argv[2], &ofm->match, &ofm->actions[0], &actions_len,
+ NULL, &priority, &idle_timeout, &hard_timeout);
+ if (s->strict) {
+ ofm->command = htons(OFPFC_MODIFY_STRICT);
+ } else {
+ ofm->command = htons(OFPFC_MODIFY);
+ }
+ 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);
+
+ /* xxx Should we use the buffer library? */
+ buffer->size -= MAX_ACT_LEN - actions_len;
+
+ open_vconn(argv[1], &vconn);
+ send_openflow_buffer(vconn, buffer);
+ vconn_close(vconn);
+}
+
+static void do_del_flows(const struct settings *s, int argc, char *argv[])
+{
+ struct vconn *vconn;
+ uint16_t priority;
+ struct ofpbuf *buffer;
+ struct ofp_flow_mod *ofm;
+ size_t size;
+
+ /* Parse and send. */
+ size = sizeof *ofm;
+ ofm = make_openflow(size, OFPT_FLOW_MOD, &buffer);
+ str_to_flow(argc > 2 ? argv[2] : "", &ofm->match, NULL, 0, NULL,
+ &priority, NULL, NULL);
+ if (s->strict) {
+ ofm->command = htons(OFPFC_DELETE_STRICT);
+ } else {
+ ofm->command = htons(OFPFC_DELETE);
+ }
+ ofm->idle_timeout = htons(0);
+ ofm->hard_timeout = htons(0);
+ ofm->buffer_id = htonl(UINT32_MAX);
+ ofm->priority = htons(priority);
+ ofm->reserved = htonl(0);
+
+ open_vconn(argv[1], &vconn);
+ send_openflow_buffer(vconn, buffer);
+ vconn_close(vconn);
+}
+
+static void
+do_monitor(const struct settings *s, int argc UNUSED, char *argv[])
+{
+ struct vconn *vconn;
+ const char *name;
+
+ /* If the user specified, e.g., "nl:0", append ":1" to it to ensure that
+ * the connection will subscribe to listen for asynchronous messages, such
+ * as packet-in messages. */
+ if (!strncmp(argv[1], "nl:", 3) && strrchr(argv[1], ':') == &argv[1][2]) {
+ name = xasprintf("%s:1", argv[1]);
+ } else {
+ name = argv[1];
+ }
+ open_vconn(argv[1], &vconn);
+ for (;;) {
+ struct ofpbuf *b;
+ run(vconn_recv_block(vconn, &b), "vconn_recv");
+ ofp_print(stderr, b->data, b->size, 2);
+ ofpbuf_delete(b);
+ }
+}
+
+static void
+do_dump_ports(const struct settings *s, int argc, char *argv[])
+{
+ dump_trivial_stats_transaction(argv[1], OFPST_PORT);
+}
+
+static void
+do_probe(const struct settings *s, int argc, char *argv[])
+{
+ struct ofpbuf *request;
+ struct vconn *vconn;
+ struct ofpbuf *reply;
+
+ make_openflow(sizeof(struct ofp_header), OFPT_ECHO_REQUEST, &request);
+ open_vconn(argv[1], &vconn);
+ run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]);
+ if (reply->size != request->size) {
+ ofp_fatal(0, "reply does not match request");
+ }
+ ofpbuf_delete(reply);
+ vconn_close(vconn);
+}
+
+static void
+do_mod_port(const struct settings *s, int argc, char *argv[])
+{
+ struct ofpbuf *request, *reply;
+ struct ofp_switch_features *osf;
+ struct ofp_port_mod *opm;
+ 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) {
+ ofp_fatal(0, "couldn't find monitored port: %s", argv[2]);
+ }
+
+ 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->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)) {
+ opm->mask |= htonl(OFPPC_PORT_DOWN);
+ } else if (!strncasecmp(argv[3], MOD_PORT_CMD_DOWN,
+ sizeof MOD_PORT_CMD_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)) {
+ opm->mask |= htonl(OFPPC_NO_FLOOD);
+ } else if (!strncasecmp(argv[3], MOD_PORT_CMD_NOFLOOD,
+ sizeof MOD_PORT_CMD_NOFLOOD)) {
+ opm->mask |= htonl(OFPPC_NO_FLOOD);
+ opm->config |= htonl(OFPPC_NO_FLOOD);
+ } else {
+ ofp_fatal(0, "unknown mod-port command '%s'", argv[3]);
+ }
+
+ send_openflow_buffer(vconn, request);
+
+ ofpbuf_delete(reply);
+ vconn_close(vconn);
+}
+
+static void
+do_ping(const struct settings *s, int argc, char *argv[])
+{
+ size_t max_payload = 65535 - sizeof(struct ofp_header);
+ unsigned int payload;
+ struct vconn *vconn;
+ int i;
+
+ payload = argc > 2 ? atoi(argv[2]) : 64;
+ if (payload > max_payload) {
+ ofp_fatal(0, "payload must be between 0 and %zu bytes", max_payload);
+ }
+
+ open_vconn(argv[1], &vconn);
+ for (i = 0; i < 10; i++) {
+ struct timeval start, end;
+ struct ofpbuf *request, *reply;
+ struct ofp_header *rq_hdr, *rpy_hdr;
+
+ rq_hdr = make_openflow(sizeof(struct ofp_header) + payload,
+ OFPT_ECHO_REQUEST, &request);
+ random_bytes(rq_hdr + 1, payload);
+
+ gettimeofday(&start, NULL);
+ run(vconn_transact(vconn, ofpbuf_clone(request), &reply), "transact");
+ gettimeofday(&end, NULL);
+
+ rpy_hdr = reply->data;
+ if (reply->size != request->size
+ || memcmp(rpy_hdr + 1, rq_hdr + 1, payload)
+ || rpy_hdr->xid != rq_hdr->xid
+ || rpy_hdr->type != OFPT_ECHO_REPLY) {
+ printf("Reply does not match request. Request:\n");
+ ofp_print(stdout, request, request->size, 2);
+ printf("Reply:\n");
+ ofp_print(stdout, reply, reply->size, 2);
+ }
+ printf("%d 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)));
+ ofpbuf_delete(request);
+ ofpbuf_delete(reply);
+ }
+ vconn_close(vconn);
+}
+