#include "socket-util.h"
#include "openflow.h"
#include "ofp-print.h"
+#include "packets.h"
#include "random.h"
#include "timeval.h"
#include "vconn.h"
static const char* ifconfigbin = "/sbin/ifconfig";
+#define MOD_PORT_CMD_UP "up"
+#define MOD_PORT_CMD_DOWN "down"
+#define MOD_PORT_CMD_FLOOD "flood"
+#define MOD_PORT_CMD_NOFLOOD "noflood"
+
struct command {
const char *name;
int min_args;
" monitor nl:DP_ID print packets received\n"
#endif
"\nFor local datapaths and remote switches:\n"
- " show SWITCH show information\n"
+ " show SWITCH show basic information\n"
+ " status SWITCH [KEY] report statistics (about KEY)\n"
" dump-version SWITCH print version information\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-flows SWITCH print all flow entries\n"
" dump-flows SWITCH FLOW print matching FLOWs\n"
dump_trivial_transaction(argv[1], OFPT_GET_CONFIG_REQUEST);
}
+static void
+do_status(int argc, char *argv[])
+{
+ struct buffer *request;
+ alloc_stats_request(0, OFPST_SWITCH, &request);
+ if (argc > 2) {
+ buffer_put(request, argv[2], strlen(argv[2]));
+ }
+ dump_stats_transaction(argv[1], request);
+}
static void
do_dump_version(int argc, char *argv[])
*n_actions = i;
}
-static void
-str_to_flow(char *string, struct ofp_match *match,
- struct ofp_action *action, int *n_actions, uint8_t *table_idx,
- uint16_t *priority, uint16_t *idle_timeout, uint16_t *hard_timeout)
+struct protocol {
+ const char *name;
+ uint16_t dl_type;
+ uint8_t nw_proto;
+};
+
+static bool
+parse_protocol(const char *name, const struct protocol **p_out)
{
- struct field {
- const char *name;
- uint32_t wildcard;
- enum { F_U8, F_U16, F_MAC, F_IP } type;
- size_t offset, shift;
+ static const struct protocol protocols[] = {
+ { "ip", ETH_TYPE_IP },
+ { "arp", ETH_TYPE_ARP },
+ { "icmp", ETH_TYPE_IP, IP_TYPE_ICMP },
+ { "tcp", ETH_TYPE_IP, IP_TYPE_TCP },
+ { "udp", ETH_TYPE_IP, IP_TYPE_UDP },
};
+ const struct protocol *p;
+
+ for (p = protocols; p < &protocols[ARRAY_SIZE(protocols)]; p++) {
+ if (!strcmp(p->name, name)) {
+ *p_out = p;
+ return true;
+ }
+ }
+ *p_out = NULL;
+ return false;
+}
+struct field {
+ const char *name;
+ uint32_t wildcard;
+ enum { F_U8, F_U16, F_MAC, F_IP } type;
+ size_t offset, shift;
+};
+
+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[] = {
{ "in_port", OFPFW_IN_PORT, F_U16, F_OFS(in_port) },
{ "tp_src", OFPFW_TP_SRC, F_U16, F_OFS(tp_src) },
{ "tp_dst", OFPFW_TP_DST, F_U16, F_OFS(tp_dst) },
};
+ const struct field *f;
- char *name, *value;
+ for (f = fields; f < &fields[ARRAY_SIZE(fields)]; f++) {
+ if (!strcmp(f->name, name)) {
+ *f_out = f;
+ return true;
+ }
+ }
+ *f_out = NULL;
+ return false;
+}
+
+static void
+str_to_flow(char *string, struct ofp_match *match,
+ struct ofp_action *action, int *n_actions, uint8_t *table_idx,
+ uint16_t *priority, uint16_t *idle_timeout, uint16_t *hard_timeout)
+{
+
+ char *name;
uint32_t wildcards;
- char *act_str;
if (table_idx) {
*table_idx = 0xff;
*hard_timeout = OFP_FLOW_PERMANENT;
}
if (action) {
- act_str = strstr(string, "action");
+ char *act_str = strstr(string, "action");
if (!act_str) {
fatal(0, "must specify an action");
}
}
memset(match, 0, sizeof *match);
wildcards = OFPFW_ALL;
- for (name = strtok(string, "="), value = strtok(NULL, ", \t\r\n");
- name && value;
- name = strtok(NULL, "="), value = strtok(NULL, ", \t\r\n"))
- {
- const struct field *f;
- void *data;
-
- if (table_idx && !strcmp(name, "table")) {
- *table_idx = atoi(value);
- continue;
- }
-
- if (priority && !strcmp(name, "priority")) {
- *priority = atoi(value);
- continue;
- }
-
- if (idle_timeout && !strcmp(name, "idle_timeout")) {
- *idle_timeout = atoi(value);
- continue;
- }
-
- if (hard_timeout && !strcmp(name, "hard_timeout")) {
- *hard_timeout = atoi(value);
- continue;
- }
-
- for (f = fields; f < &fields[ARRAY_SIZE(fields)]; f++) {
- if (!strcmp(f->name, name)) {
- goto found;
- }
- }
- fprintf(stderr, "%s: unknown field %s (fields are",
- program_name, name);
- for (f = fields; f < &fields[ARRAY_SIZE(fields)]; f++) {
- if (f != fields) {
- putc(',', stderr);
+ for (name = strtok(string, "=, \t\r\n"); name;
+ name = strtok(NULL, "=, \t\r\n")) {
+ const struct protocol *p;
+
+ if (parse_protocol(name, &p)) {
+ wildcards &= ~OFPFW_DL_TYPE;
+ match->dl_type = htons(p->dl_type);
+ if (p->nw_proto) {
+ wildcards &= ~OFPFW_NW_PROTO;
+ match->nw_proto = p->nw_proto;
}
- fprintf(stderr, " %s", f->name);
- }
- fprintf(stderr, ")\n");
- exit(1);
-
- found:
- data = (char *) match + f->offset;
- if (!strcmp(value, "*") || !strcmp(value, "ANY")) {
- wildcards |= f->wildcard;
} else {
- wildcards &= ~f->wildcard;
- if (f->type == F_U8) {
- *(uint8_t *) data = str_to_int(value);
- } else if (f->type == F_U16) {
- *(uint16_t *) data = htons(str_to_int(value));
- } else if (f->type == F_MAC) {
- str_to_mac(value, data);
- } else if (f->type == F_IP) {
- wildcards |= str_to_ip(value, data) << f->shift;
+ const struct field *f;
+ char *value;
+
+ value = strtok(NULL, ", \t\r\n");
+ if (!value) {
+ fatal(0, "field %s missing value", name);
+ }
+
+ if (table_idx && !strcmp(name, "table")) {
+ *table_idx = atoi(value);
+ } else if (priority && !strcmp(name, "priority")) {
+ *priority = atoi(value);
+ } else if (idle_timeout && !strcmp(name, "idle_timeout")) {
+ *idle_timeout = atoi(value);
+ } else if (hard_timeout && !strcmp(name, "hard_timeout")) {
+ *hard_timeout = atoi(value);
+ } else if (parse_field(name, &f)) {
+ void *data = (char *) match + f->offset;
+ if (!strcmp(value, "*") || !strcmp(value, "ANY")) {
+ wildcards |= f->wildcard;
+ } else {
+ wildcards &= ~f->wildcard;
+ if (f->type == F_U8) {
+ *(uint8_t *) data = str_to_int(value);
+ } else if (f->type == F_U16) {
+ *(uint16_t *) data = htons(str_to_int(value));
+ } else if (f->type == F_MAC) {
+ str_to_mac(value, data);
+ } else if (f->type == F_IP) {
+ wildcards |= str_to_ip(value, data) << f->shift;
+ } else {
+ NOT_REACHED();
+ }
+ }
} else {
- NOT_REACHED();
+ fatal(0, "unknown keyword %s", name);
}
}
}
- if (name && !value) {
- fatal(0, "field %s missing value", name);
- }
match->wildcards = htonl(wildcards);
}
vconn_close(vconn);
}
+static void
+do_mod_port(int argc, char *argv[])
+{
+ struct buffer *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);
+ run(vconn_open_block(argv[1], &vconn), "connecting to %s", argv[1]);
+ 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) {
+ fatal(0, "couldn't find monitored port: %s", argv[2]);
+ }
+
+ opm = make_openflow(sizeof(struct ofp_port_mod), OFPT_PORT_MOD, &request);
+ memcpy(&opm->desc, &osf->ports[port_idx], sizeof osf->ports[0]);
+ opm->mask = 0;
+ opm->desc.flags = 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(OFPPFL_PORT_DOWN);
+ } else if (!strncasecmp(argv[3], MOD_PORT_CMD_DOWN,
+ sizeof MOD_PORT_CMD_DOWN)) {
+ opm->mask |= htonl(OFPPFL_PORT_DOWN);
+ opm->desc.flags |= htonl(OFPPFL_PORT_DOWN);
+ } else if (!strncasecmp(argv[3], MOD_PORT_CMD_FLOOD,
+ sizeof MOD_PORT_CMD_FLOOD)) {
+ opm->mask |= htonl(OFPPFL_NO_FLOOD);
+ } else if (!strncasecmp(argv[3], MOD_PORT_CMD_NOFLOOD,
+ sizeof MOD_PORT_CMD_NOFLOOD)) {
+ opm->mask |= htonl(OFPPFL_NO_FLOOD);
+ opm->desc.flags |= htonl(OFPPFL_NO_FLOOD);
+ } else {
+ fatal(0, "unknown mod-port command '%s'", argv[3]);
+ }
+
+ send_openflow_buffer(vconn, request);
+
+ buffer_delete(reply);
+ vconn_close(vconn);
+}
+
static void
do_ping(int argc, char *argv[])
{
#endif
{ "show", 1, 1, do_show },
+ { "status", 1, 2, do_status },
{ "help", 0, INT_MAX, do_help },
{ "monitor", 1, 1, do_monitor },
{ "add-flows", 2, 2, do_add_flows },
{ "del-flows", 1, 2, do_del_flows },
{ "dump-ports", 1, 1, do_dump_ports },
+ { "mod-port", 3, 3, do_mod_port },
{ "probe", 1, 1, do_probe },
{ "ping", 1, 2, do_ping },
{ "benchmark", 3, 3, do_benchmark },