#include <sys/stat.h>
#include <sys/time.h>
+#include "byte-order.h"
+#include "classifier.h"
#include "command-line.h"
#include "compiler.h"
#include "dirs.h"
#include "dpif.h"
+#include "dynamic-string.h"
#include "netlink.h"
+#include "nx-match.h"
#include "odp-util.h"
#include "ofp-parse.h"
#include "ofp-print.h"
#include "util.h"
#include "vconn.h"
#include "vlog.h"
-#include "xtoxll.h"
-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"
+VLOG_DEFINE_THIS_MODULE(ofctl);
/* Use strict matching for flow mod commands? */
static bool strict;
struct stat s;
char *bridge_path, *datapath_name, *datapath_type;
- bridge_path = xasprintf("%s/%s.%s", ovs_rundir, name, default_suffix);
+ bridge_path = xasprintf("%s/%s.%s", ovs_rundir(), name, default_suffix);
dp_parse_name(name, &datapath_name, &datapath_type);
if (strstr(name, ":")) {
}
socket_name = xasprintf("%s/%s.%s",
- ovs_rundir, dpif_name, default_suffix);
+ ovs_rundir(), dpif_name, default_suffix);
if (stat(socket_name, &s)) {
ovs_fatal(errno, "cannot connect to %s: stat failed on %s",
name, socket_name);
static void
dump_stats_transaction(const char *vconn_name, struct ofpbuf *request)
{
- uint32_t send_xid = ((struct ofp_header *) request->data)->xid;
+ ovs_be32 send_xid = ((struct ofp_header *) request->data)->xid;
struct vconn *vconn;
bool done = false;
struct vconn *vconn;
struct ofpbuf *b;
- request = make_openflow(sizeof *request, OFPT_VENDOR, &b);
- request->vendor = htonl(NX_VENDOR_ID);
- request->subtype = htonl(NXT_STATUS_REQUEST);
+ request = make_nxmsg(sizeof *request, NXT_STATUS_REQUEST, &b);
if (argc > 2) {
ofpbuf_put(b, argv[2], strlen(argv[2]));
update_openflow_length(b);
ofpbuf_delete(reply);
vconn_close(vconn);
- return port_idx;
+ return ntohs(osf->ports[port_idx].port_no);
}
static void
do_dump_flows(int argc, char *argv[])
{
struct ofp_flow_stats_request *req;
- uint16_t out_port;
+ struct parsed_flow pf;
struct ofpbuf *request;
req = alloc_stats_request(sizeof *req, OFPST_FLOW, &request);
- parse_ofp_str(argc > 2 ? argv[2] : "", &req->match, NULL,
- &req->table_id, &out_port, NULL, NULL, NULL, NULL);
+ parse_ofp_str(&pf, NULL, argc > 2 ? argv[2] : "");
+ ofputil_cls_rule_to_match(&pf.rule, NXFF_OPENFLOW10, &req->match);
memset(&req->pad, 0, sizeof req->pad);
- req->out_port = htons(out_port);
+ req->out_port = htons(pf.out_port);
dump_stats_transaction(argv[1], request);
}
{
struct ofp_aggregate_stats_request *req;
struct ofpbuf *request;
- uint16_t out_port;
+ struct parsed_flow pf;
req = alloc_stats_request(sizeof *req, OFPST_AGGREGATE, &request);
- parse_ofp_str(argc > 2 ? argv[2] : "", &req->match, NULL,
- &req->table_id, &out_port, NULL, NULL, NULL, NULL);
+ parse_ofp_str(&pf, NULL, argc > 2 ? argv[2] : "");
+ ofputil_cls_rule_to_match(&pf.rule, NXFF_OPENFLOW10, &req->match);
memset(&req->pad, 0, sizeof req->pad);
- req->out_port = htons(out_port);
+ req->out_port = htons(pf.out_port);
dump_stats_transaction(argv[1], request);
}
{
struct vconn *vconn;
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. parse_ofp_str() will expand and reallocate the
- * data in 'buffer', so we can't keep pointers to across the
- * parse_ofp_str() call. */
- make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
- parse_ofp_str(argv[2], &match, buffer,
- 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);
+
+ buffer = parse_ofp_flow_mod_str(argv[2], OFPFC_ADD);
open_vconn(argv[1], &vconn);
send_openflow_buffer(vconn, buffer);
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;
- struct ofp_match match;
-
- /* Parse and send. parse_ofp_str() will expand and reallocate the
- * data in 'buffer', so we can't keep pointers to across the
- * parse_ofp_str() call. */
- make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
- parse_ofp_str(argv[2], &match, buffer,
- NULL, NULL, &priority, &idle_timeout, &hard_timeout,
- &cookie);
- ofm = buffer->data;
- ofm->match = match;
- if (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->cookie = htonll(cookie);
- ofm->buffer_id = htonl(UINT32_MAX);
- ofm->priority = htons(priority);
+ uint16_t command;
+ 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);
vconn_close(vconn);
static void do_del_flows(int argc, char *argv[])
{
struct vconn *vconn;
- uint16_t priority;
- uint16_t out_port;
struct ofpbuf *buffer;
- struct ofp_flow_mod *ofm;
-
- /* Parse and send. */
- ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
- parse_ofp_str(argc > 2 ? argv[2] : "", &ofm->match, NULL, NULL,
- &out_port, &priority, NULL, NULL, NULL);
- if (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->out_port = htons(out_port);
- ofm->priority = htons(priority);
+ uint16_t command;
+
+ command = strict ? OFPFC_DELETE_STRICT : OFPFC_DELETE;
+ buffer = parse_ofp_flow_mod_str(argc > 2 ? argv[2] : "", command);
open_vconn(argv[1], &vconn);
send_openflow_buffer(vconn, buffer);
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 = 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);
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 {
ofp_print(stdout, reply, reply->size, 2);
}
printf("%zu bytes from %s: xid=%08"PRIx32" time=%.1f ms\n",
- reply->size - sizeof *rpy_hdr, argv[1], rpy_hdr->xid,
+ reply->size - sizeof *rpy_hdr, argv[1], ntohl(rpy_hdr->xid),
(1000*(double)(end.tv_sec - start.tv_sec))
+ (.001*(end.tv_usec - start.tv_usec)));
ofpbuf_delete(request);
count * message_size / (duration / 1000.0));
}
-/* This command is really only useful for testing the flow parser (ofp_parse),
- * so it is undocumented. */
+static void
+do_help(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+{
+ usage();
+}
+\f
+/* Undocumented commands for unit testing. */
+
static void
do_parse_flows(int argc OVS_UNUSED, char *argv[])
{
}
static void
-do_help(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
-{
- usage();
+do_parse_nx_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+{
+ struct ds in;
+
+ ds_init(&in);
+ while (!ds_get_line(&in, stdin)) {
+ struct ofpbuf nx_match;
+ struct cls_rule rule;
+ int match_len;
+ int error;
+ char *s;
+
+ /* Delete comments, skip blank lines. */
+ s = ds_cstr(&in);
+ if (*s == '#') {
+ puts(s);
+ continue;
+ }
+ if (strchr(s, '#')) {
+ *strchr(s, '#') = '\0';
+ }
+ if (s[strspn(s, " ")] == '\0') {
+ putchar('\n');
+ continue;
+ }
+
+ /* Convert string to nx_match. */
+ ofpbuf_init(&nx_match, 0);
+ match_len = nx_match_from_string(ds_cstr(&in), &nx_match);
+
+ /* Convert nx_match to cls_rule. */
+ error = nx_pull_match(&nx_match, match_len, 0, &rule);
+ if (!error) {
+ char *out;
+
+ /* Convert cls_rule back to nx_match. */
+ ofpbuf_uninit(&nx_match);
+ ofpbuf_init(&nx_match, 0);
+ match_len = nx_put_match(&nx_match, &rule);
+
+ /* Convert nx_match to string. */
+ out = nx_match_to_string(nx_match.data, match_len);
+ puts(out);
+ free(out);
+ } else {
+ printf("nx_pull_match() returned error %x\n", error);
+ }
+
+ ofpbuf_uninit(&nx_match);
+ }
+ ds_destroy(&in);
}
static const struct command all_commands[] = {
{ "probe", 1, 1, do_probe },
{ "ping", 1, 2, do_ping },
{ "benchmark", 3, 3, do_benchmark },
- { "parse-flows", 1, 1, do_parse_flows },
{ "help", 0, INT_MAX, do_help },
+
+ /* Undocumented commands for testing. */
+ { "parse-flows", 1, 1, do_parse_flows },
+ { "parse-nx-match", 0, 0, do_parse_nx_match },
+
{ NULL, 0, 0, NULL },
};