/*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*/
#include <config.h>
-#include <arpa/inet.h>
#include <errno.h>
#include <getopt.h>
#include <inttypes.h>
#include <net/if.h>
-#include <netinet/in.h>
#include <signal.h>
-#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "compiler.h"
#include "dirs.h"
#include "dpif.h"
-#include "dynamic-string.h"
-#include "netdev.h"
#include "netlink.h"
#include "odp-util.h"
+#include "ofp-parse.h"
#include "ofp-print.h"
+#include "ofp-util.h"
#include "ofpbuf.h"
#include "openflow/nicira-ext.h"
#include "openflow/openflow.h"
-#include "packets.h"
#include "random.h"
-#include "socket-util.h"
#include "stream-ssl.h"
#include "timeval.h"
#include "util.h"
#include "vconn.h"
-
#include "vlog.h"
-#define THIS_MODULE VLM_ofctl
+#include "xtoxll.h"
+
+VLOG_DEFINE_THIS_MODULE(ofctl)
-#define DEFAULT_IDLE_TIMEOUT 60
#define MOD_PORT_CMD_UP "up"
#define MOD_PORT_CMD_DOWN "down"
main(int argc, char *argv[])
{
set_program_name(argv[0]);
- time_init();
- vlog_init();
parse_options(argc, argv);
signal(SIGPIPE, SIG_IGN);
run_command(argc - optind, argv + optind, all_commands);
parse_options(int argc, char *argv[])
{
enum {
- OPT_STRICT = UCHAR_MAX + 1
+ OPT_STRICT = UCHAR_MAX + 1,
+ VLOG_OPTION_ENUMS
};
static struct option long_options[] = {
{"timeout", required_argument, 0, 't'},
- {"verbose", optional_argument, 0, 'v'},
{"strict", no_argument, 0, OPT_STRICT},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
+ VLOG_LONG_OPTIONS,
STREAM_SSL_LONG_OPTIONS
{0, 0, 0, 0},
};
OVS_PRINT_VERSION(OFP_VERSION, OFP_VERSION);
exit(EXIT_SUCCESS);
- case 'v':
- vlog_set_verbosity(optarg);
- break;
-
case OPT_STRICT:
strict = true;
break;
+ VLOG_OPTION_HANDLERS
STREAM_SSL_OPTION_HANDLERS
case '?':
" 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"
" add-flows SWITCH FILE add flows from FILE\n"
" mod-flows SWITCH FLOW modify actions of matching FLOWs\n"
" del-flows SWITCH [FLOW] delete matching FLOWs\n"
- " monitor SWITCH MISSLEN EXP print packets received from SWITCH\n"
+ " monitor SWITCH [MISSLEN] print packets received from SWITCH\n"
"\nFor OpenFlow switches and controllers:\n"
" probe VCONN probe whether VCONN is up\n"
" ping VCONN [N] latency of N-byte echos\n"
/* Generic commands. */
static void
-open_vconn(const char *name, struct vconn **vconnp)
+open_vconn_socket(const char *name, struct vconn **vconnp)
+{
+ char *vconn_name = xasprintf("unix:%s", name);
+ VLOG_INFO("connecting to %s", vconn_name);
+ run(vconn_open_block(vconn_name, OFP_VERSION, vconnp),
+ "connecting to %s", vconn_name);
+ free(vconn_name);
+}
+
+static void
+open_vconn__(const char *name, const char *default_suffix,
+ struct vconn **vconnp)
{
struct dpif *dpif;
struct stat s;
+ char *bridge_path, *datapath_name, *datapath_type;
+
+ bridge_path = xasprintf("%s/%s.%s", ovs_rundir, name, default_suffix);
+ dp_parse_name(name, &datapath_name, &datapath_type);
if (strstr(name, ":")) {
run(vconn_open_block(name, OFP_VERSION, vconnp),
"connecting to %s", name);
} else if (!stat(name, &s) && S_ISSOCK(s.st_mode)) {
- char *vconn_name = xasprintf("unix:%s", name);
- VLOG_INFO("connecting to %s", vconn_name);
- run(vconn_open_block(vconn_name, OFP_VERSION, vconnp),
- "connecting to %s", vconn_name);
- free(vconn_name);
- } else if (!dpif_open(name, &dpif)) {
+ open_vconn_socket(name, vconnp);
+ } else if (!stat(bridge_path, &s) && S_ISSOCK(s.st_mode)) {
+ open_vconn_socket(bridge_path, vconnp);
+ } else if (!dpif_open(datapath_name, datapath_type, &dpif)) {
char dpif_name[IF_NAMESIZE + 1];
char *socket_name;
- char *vconn_name;
run(dpif_port_get_name(dpif, ODPP_LOCAL, dpif_name, sizeof dpif_name),
"obtaining name of %s", dpif_name);
VLOG_INFO("datapath %s is named %s", name, dpif_name);
}
- socket_name = xasprintf("%s/%s.mgmt", ovs_rundir, dpif_name);
+ socket_name = xasprintf("%s/%s.%s",
+ 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);
name, socket_name);
}
- vconn_name = xasprintf("unix:%s", socket_name);
- VLOG_INFO("connecting to %s", vconn_name);
- run(vconn_open_block(vconn_name, OFP_VERSION, vconnp),
- "connecting to %s", vconn_name);
+ open_vconn_socket(socket_name, vconnp);
free(socket_name);
- free(vconn_name);
} else {
ovs_fatal(0, "%s is not a valid connection method", name);
}
+
+ free(datapath_name);
+ free(datapath_type);
+ free(bridge_path);
+}
+
+static void
+open_vconn(const char *name, struct vconn **vconnp)
+{
+ return open_vconn__(name, "mgmt", vconnp);
}
static void *
}
static void
-do_show(int argc UNUSED, char *argv[])
+do_show(int argc OVS_UNUSED, char *argv[])
{
dump_trivial_transaction(argv[1], OFPT_FEATURES_REQUEST);
dump_trivial_transaction(argv[1], OFPT_GET_CONFIG_REQUEST);
}
static void
-do_dump_desc(int argc UNUSED, char *argv[])
+do_dump_desc(int argc OVS_UNUSED, char *argv[])
{
dump_trivial_stats_transaction(argv[1], OFPST_DESC);
}
static void
-do_dump_tables(int argc UNUSED, char *argv[])
+do_dump_tables(int argc OVS_UNUSED, char *argv[])
{
dump_trivial_stats_transaction(argv[1], OFPST_TABLE);
}
-
-static uint32_t
-str_to_u32(const char *str)
-{
- char *tail;
- uint32_t value;
-
- errno = 0;
- value = strtoul(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])
-{
- if (sscanf(str, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))
- != ETH_ADDR_SCAN_COUNT) {
- ovs_fatal(0, "invalid mac address %s", str);
- }
-}
-
-static uint32_t
-str_to_ip(const char *str_, uint32_t *ip)
+static uint16_t
+str_to_port_no(const char *vconn_name, const char *str)
{
- char *str = xstrdup(str_);
- char *save_ptr = NULL;
- const char *name, *netmask;
- struct in_addr in_addr;
- int n_wild, retval;
-
- name = strtok_r(str, "/", &save_ptr);
- retval = name ? lookup_ip(name, &in_addr) : EINVAL;
- if (retval) {
- ovs_fatal(0, "%s: could not convert to IP address", str);
- }
- *ip = in_addr.s_addr;
-
- netmask = strtok_r(NULL, "/", &save_ptr);
- if (netmask) {
- uint8_t o[4];
- if (sscanf(netmask, "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8,
- &o[0], &o[1], &o[2], &o[3]) == 4) {
- uint32_t nm = (o[0] << 24) | (o[1] << 16) | (o[2] << 8) | o[3];
- int i;
-
- /* Find first 1-bit. */
- for (i = 0; i < 32; i++) {
- if (nm & (1u << i)) {
- break;
- }
- }
- n_wild = i;
-
- /* Verify that the rest of the bits are 1-bits. */
- for (; i < 32; i++) {
- if (!(nm & (1u << i))) {
- ovs_fatal(0, "%s: %s is not a valid netmask",
- str, netmask);
- }
- }
- } else {
- int prefix = atoi(netmask);
- if (prefix <= 0 || prefix > 32) {
- ovs_fatal(0, "%s: network prefix bits not between 1 and 32",
- str);
- }
- n_wild = 32 - prefix;
- }
- } else {
- n_wild = 0;
- }
-
- free(str);
- return n_wild;
-}
-
-static void *
-put_action(struct ofpbuf *b, size_t size, uint16_t type)
-{
- struct ofp_action_header *ah = ofpbuf_put_zeros(b, size);
- ah->type = htons(type);
- ah->len = htons(size);
- return ah;
-}
-
-static struct ofp_action_output *
-put_output_action(struct ofpbuf *b, uint16_t port)
-{
- struct ofp_action_output *oao = put_action(b, sizeof *oao, OFPAT_OUTPUT);
- oao->port = htons(port);
- return oao;
-}
-
-static void
-put_dl_addr_action(struct ofpbuf *b, uint16_t type, const char *addr)
-{
- struct ofp_action_dl_addr *oada = put_action(b, sizeof *oada, type);
- str_to_mac(addr, oada->dl_addr);
-}
-
-
-static bool
-parse_port_name(const char *name, uint16_t *port)
-{
- struct pair {
- const char *name;
- uint16_t value;
- };
- static const struct pair pairs[] = {
-#define DEF_PAIR(NAME) {#NAME, OFPP_##NAME}
- DEF_PAIR(IN_PORT),
- DEF_PAIR(TABLE),
- DEF_PAIR(NORMAL),
- DEF_PAIR(FLOOD),
- DEF_PAIR(ALL),
- DEF_PAIR(CONTROLLER),
- DEF_PAIR(LOCAL),
- DEF_PAIR(NONE),
-#undef DEF_PAIR
- };
- static const int n_pairs = ARRAY_SIZE(pairs);
- size_t i;
-
- for (i = 0; i < n_pairs; i++) {
- if (!strcasecmp(name, pairs[i].name)) {
- *port = pairs[i].value;
- return true;
- }
- }
- return false;
-}
-
-static void
-str_to_action(char *str, struct ofpbuf *b)
-{
- char *act, *arg;
- char *saveptr = NULL;
- bool drop = false;
- int n_actions;
-
- for (act = strtok_r(str, ", \t\r\n", &saveptr), n_actions = 0; act;
- act = strtok_r(NULL, ", \t\r\n", &saveptr), n_actions++)
- {
- uint16_t port;
-
- if (drop) {
- ovs_fatal(0, "Drop actions must not be followed by other actions");
- }
-
- /* Arguments are separated by colons */
- arg = strchr(act, ':');
- if (arg) {
- *arg = '\0';
- arg++;
- }
-
- if (!strcasecmp(act, "mod_vlan_vid")) {
- struct ofp_action_vlan_vid *va;
- va = put_action(b, sizeof *va, OFPAT_SET_VLAN_VID);
- va->vlan_vid = htons(str_to_u32(arg));
- } else if (!strcasecmp(act, "mod_vlan_pcp")) {
- struct ofp_action_vlan_pcp *va;
- va = put_action(b, sizeof *va, OFPAT_SET_VLAN_PCP);
- va->vlan_pcp = str_to_u32(arg);
- } else if (!strcasecmp(act, "strip_vlan")) {
- struct ofp_action_header *ah;
- ah = put_action(b, sizeof *ah, OFPAT_STRIP_VLAN);
- ah->type = htons(OFPAT_STRIP_VLAN);
- } else if (!strcasecmp(act, "mod_dl_src")) {
- put_dl_addr_action(b, OFPAT_SET_DL_SRC, arg);
- } else if (!strcasecmp(act, "mod_dl_dst")) {
- put_dl_addr_action(b, OFPAT_SET_DL_DST, arg);
- } else if (!strcasecmp(act, "mod_nw_src")) {
- struct ofp_action_nw_addr *na;
- na = put_action(b, sizeof *na, OFPAT_SET_NW_SRC);
- str_to_ip(arg, &na->nw_addr);
- } else if (!strcasecmp(act, "mod_nw_dst")) {
- struct ofp_action_nw_addr *na;
- na = put_action(b, sizeof *na, OFPAT_SET_NW_DST);
- str_to_ip(arg, &na->nw_addr);
- } else if (!strcasecmp(act, "mod_tp_src")) {
- struct ofp_action_tp_port *ta;
- ta = put_action(b, sizeof *ta, OFPAT_SET_TP_SRC);
- ta->tp_port = htons(str_to_u32(arg));
- } else if (!strcasecmp(act, "mod_tp_dst")) {
- 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, "output")) {
- put_output_action(b, str_to_u32(arg));
- } else if (!strcasecmp(act, "drop")) {
- /* A drop action in OpenFlow occurs by just not setting
- * an action. */
- drop = true;
- if (n_actions) {
- ovs_fatal(0, "Drop actions must not be preceded by other "
- "actions");
- }
- } else if (!strcasecmp(act, "CONTROLLER")) {
- struct ofp_action_output *oao;
- oao = put_output_action(b, OFPP_CONTROLLER);
-
- /* Unless a numeric argument is specified, we send the whole
- * packet to the controller. */
- if (arg && (strspn(act, "0123456789") == strlen(act))) {
- oao->max_len = htons(str_to_u32(arg));
- } else {
- oao->max_len = htons(UINT16_MAX);
- }
- } else if (parse_port_name(act, &port)) {
- put_output_action(b, port);
- } else if (strspn(act, "0123456789") == strlen(act)) {
- put_output_action(b, str_to_u32(act));
- } else {
- ovs_fatal(0, "Unknown action: %s", act);
- }
- }
-}
+ struct ofpbuf *request, *reply;
+ struct ofp_switch_features *osf;
+ struct vconn *vconn;
+ int n_ports;
+ int port_idx;
+ unsigned int port_no;
-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)
-{
- static const struct protocol protocols[] = {
- { "ip", ETH_TYPE_IP, 0 },
- { "arp", ETH_TYPE_ARP, 0 },
- { "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;
- }
+ /* 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;
}
- *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;
-};
+ /* 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);
-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), 0 },
- { "dl_vlan", OFPFW_DL_VLAN, F_U16, F_OFS(dl_vlan), 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 },
- { "nw_src", OFPFW_NW_SRC_MASK, F_IP,
- F_OFS(nw_src), OFPFW_NW_SRC_SHIFT },
- { "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 },
- { "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 },
- { "icmp_code", OFPFW_ICMP_CODE, F_U16, F_OFS(icmp_code), 0 }
- };
- const struct field *f;
+ osf = reply->data;
+ n_ports = (reply->size - sizeof *osf) / sizeof *osf->ports;
- for (f = fields; f < &fields[ARRAY_SIZE(fields)]; f++) {
- if (!strcmp(f->name, name)) {
- *f_out = f;
- return true;
+ 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;
}
}
- *f_out = NULL;
- return false;
-}
-
-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)
-{
- char *save_ptr = NULL;
- char *name;
- uint32_t wildcards;
-
- if (table_idx) {
- *table_idx = 0xff;
- }
- if (out_port) {
- *out_port = OFPP_NONE;
- }
- if (priority) {
- *priority = OFP_DEFAULT_PRIORITY;
- }
- if (idle_timeout) {
- *idle_timeout = DEFAULT_IDLE_TIMEOUT;
- }
- if (hard_timeout) {
- *hard_timeout = OFP_FLOW_PERMANENT;
+ if (port_idx == n_ports) {
+ ovs_fatal(0, "couldn't find monitored port: %s", str);
}
- if (actions) {
- char *act_str = strstr(string, "action");
- if (!act_str) {
- ovs_fatal(0, "must specify an action");
- }
- *(act_str-1) = '\0';
-
- act_str = strchr(act_str, '=');
- if (!act_str) {
- ovs_fatal(0, "must specify an action");
- }
-
- act_str++;
- str_to_action(act_str, actions);
- }
- memset(match, 0, sizeof *match);
- wildcards = OFPFW_ALL;
- for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name;
- name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) {
- 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;
- }
- } else {
- const struct field *f;
- char *value;
+ ofpbuf_delete(reply);
+ vconn_close(vconn);
- value = strtok_r(NULL, ", \t\r\n", &save_ptr);
- if (!value) {
- ovs_fatal(0, "field %s missing value", name);
- }
-
- if (table_idx && !strcmp(name, "table")) {
- *table_idx = atoi(value);
- } else if (out_port && !strcmp(name, "out_port")) {
- *out_port = 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->wildcard == OFPFW_IN_PORT
- && parse_port_name(value, (uint16_t *) data)) {
- /* Nothing to do. */
- } else if (f->type == F_U8) {
- *(uint8_t *) data = str_to_u32(value);
- } else if (f->type == F_U16) {
- *(uint16_t *) data = htons(str_to_u32(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 {
- ovs_fatal(0, "unknown keyword %s", name);
- }
- }
- }
- match->wildcards = htonl(wildcards);
+ return port_idx;
}
static void
struct ofpbuf *request;
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);
+ parse_ofp_str(argc > 2 ? argv[2] : "", &req->match, NULL,
+ &req->table_id, &out_port, NULL, NULL, NULL, NULL);
memset(&req->pad, 0, sizeof req->pad);
req->out_port = htons(out_port);
uint16_t out_port;
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);
+ parse_ofp_str(argc > 2 ? argv[2] : "", &req->match, NULL,
+ &req->table_id, &out_port, NULL, NULL, NULL, NULL);
memset(&req->pad, 0, sizeof req->pad);
req->out_port = htons(out_port);
}
static void
-do_add_flow(int argc UNUSED, char *argv[])
+do_add_flow(int argc OVS_UNUSED, char *argv[])
{
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. str_to_flow() will expand and reallocate the data in
- * 'buffer', so we can't keep pointers to across the str_to_flow() call. */
+ /* 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);
- str_to_flow(argv[2], &match, buffer,
- NULL, NULL, &priority, &idle_timeout, &hard_timeout);
+ 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);
- ofm->reserved = htonl(0);
open_vconn(argv[1], &vconn);
send_openflow_buffer(vconn, buffer);
}
static void
-do_add_flows(int argc UNUSED, char *argv[])
+do_add_flows(int argc OVS_UNUSED, char *argv[])
{
struct vconn *vconn;
FILE *file;
struct ofpbuf *buffer;
struct ofp_flow_mod *ofm;
uint16_t priority, idle_timeout, hard_timeout;
+ uint64_t cookie;
struct ofp_match match;
char *comment;
continue;
}
- /* 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. */
- ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
- str_to_flow(line, &match, buffer,
- NULL, NULL, &priority, &idle_timeout, &hard_timeout);
+ /* 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(line, &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);
- ofm->reserved = htonl(0);
send_openflow_buffer(vconn, buffer);
}
}
static void
-do_mod_flows(int argc UNUSED, char *argv[])
+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. str_to_flow() will expand and reallocate the data in
- * 'buffer', so we can't keep pointers to across the str_to_flow() call. */
+ /* 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);
- str_to_flow(argv[2], &match, buffer,
- NULL, NULL, &priority, &idle_timeout, &hard_timeout);
+ parse_ofp_str(argv[2], &match, buffer,
+ NULL, NULL, &priority, &idle_timeout, &hard_timeout,
+ &cookie);
ofm = buffer->data;
ofm->match = match;
if (strict) {
}
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);
/* 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);
+ 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->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);
}
static void
-do_monitor(int argc UNUSED, char *argv[])
+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);
+ vconn_close(vconn);
+}
+
+static void
+monitor_vconn(struct vconn *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_monitor(int argc, char *argv[])
{
struct vconn *vconn;
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);
}
- for (;;) {
- struct ofpbuf *b;
- run(vconn_recv_block(vconn, &b), "vconn_recv");
- ofp_print(stderr, b->data, b->size, 2);
- ofpbuf_delete(b);
- }
+ monitor_vconn(vconn);
}
static void
-do_dump_ports(int argc UNUSED, char *argv[])
+do_snoop(int argc OVS_UNUSED, char *argv[])
{
- dump_trivial_stats_transaction(argv[1], OFPST_PORT);
+ struct vconn *vconn;
+
+ open_vconn__(argv[1], "snoop", &vconn);
+ monitor_vconn(vconn);
}
static void
-do_probe(int argc UNUSED, char *argv[])
+do_dump_ports(int argc, char *argv[])
+{
+ 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
+do_probe(int argc OVS_UNUSED, char *argv[])
{
struct ofpbuf *request;
struct vconn *vconn;
}
static void
-do_mod_port(int argc UNUSED, char *argv[])
+do_mod_port(int argc OVS_UNUSED, char *argv[])
{
struct ofpbuf *request, *reply;
struct ofp_switch_features *osf;
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 = -1;
}
- /* Send a "Features Request" to get the information we need in order
+ /* 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);
}
} else {
/* Check argument as an interface name */
- if (!strncmp((char *)osf->ports[port_idx].name, argv[2],
+ if (!strncmp((char *)osf->ports[port_idx].name, argv[2],
sizeof osf->ports[0].name)) {
break;
}
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,
+ } 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,
+ } 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,
+ } 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);
}
static void
-do_benchmark(int argc UNUSED, char *argv[])
+do_benchmark(int argc OVS_UNUSED, char *argv[])
{
size_t max_payload = 65535 - sizeof(struct ofp_header);
struct timeval start, end;
}
static void
-do_help(int argc UNUSED, char *argv[] UNUSED)
+do_help(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
{
usage();
}
static const struct command all_commands[] = {
{ "show", 1, 1, do_show },
{ "status", 1, 2, do_status },
- { "monitor", 1, 3, do_monitor },
+ { "monitor", 1, 2, do_monitor },
+ { "snoop", 1, 1, do_snoop },
{ "dump-desc", 1, 1, do_dump_desc },
{ "dump-tables", 1, 1, do_dump_tables },
{ "dump-flows", 1, 2, do_dump_flows },
{ "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 },