From 9f15ba211376c0d6e867da7bba3afcf927e3b71e Mon Sep 17 00:00:00 2001 From: Glen Gibb Date: Tue, 13 Oct 2009 13:33:47 -0700 Subject: [PATCH] Remove remote command execution support --- secchan/automake.mk | 2 - secchan/executer.c | 520 ---------------------------------------- secchan/executer.h | 42 ---- secchan/ofprotocol.8.in | 28 --- secchan/secchan.c | 25 +- secchan/secchan.h | 4 - utilities/dpctl.8.in | 10 - utilities/dpctl.c | 67 ------ 8 files changed, 1 insertion(+), 697 deletions(-) delete mode 100644 secchan/executer.c delete mode 100644 secchan/executer.h diff --git a/secchan/automake.mk b/secchan/automake.mk index 14ece8e..6a9f204 100644 --- a/secchan/automake.mk +++ b/secchan/automake.mk @@ -4,8 +4,6 @@ man_MANS += secchan/ofprotocol.8 secchan_ofprotocol_SOURCES = \ secchan/discovery.c \ secchan/discovery.h \ - secchan/executer.c \ - secchan/executer.h \ secchan/emerg-flow.c \ secchan/emerg-flow.h \ secchan/fail-open.c \ diff --git a/secchan/executer.c b/secchan/executer.c deleted file mode 100644 index 964a8b9..0000000 --- a/secchan/executer.c +++ /dev/null @@ -1,520 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "executer.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "dynamic-string.h" -#include "fatal-signal.h" -#include "openflow/nicira-ext.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "poll-loop.h" -#include "rconn.h" -#include "secchan.h" -#include "socket-util.h" -#include "util.h" -#include "vconn.h" - -#define THIS_MODULE VLM_executer -#include "vlog.h" - -#define MAX_CHILDREN 8 - -struct child { - /* Information about child process. */ - char *name; /* argv[0] passed to child. */ - pid_t pid; /* Child's process ID. */ - - /* For sending a reply to the controller when the child dies. */ - struct relay *relay; - uint32_t xid; /* Transaction ID used by controller. */ - - /* We read up to MAX_OUTPUT bytes of output and send them back to the - * controller when the child dies. */ -#define MAX_OUTPUT 4096 - int output_fd; /* FD from which to read child's output. */ - uint8_t *output; /* Output data. */ - size_t output_size; /* Number of bytes of output data so far. */ -}; - -struct executer { - const struct settings *s; - - /* Children. */ - struct child children[MAX_CHILDREN]; - size_t n_children; - - /* File descriptors. */ - int wait_fd; /* Pipe FD for wakeup when on SIGCHLD. */ - int null_fd; /* FD for /dev/null. */ -}; - -static void send_child_status(struct relay *, uint32_t xid, uint32_t status, - const void *data, size_t size); -static void send_child_message(struct relay *, uint32_t xid, uint32_t status, - const char *message); - -/* Returns true if 'cmd' is allowed by 'acl', which is a command-separated - * access control list in the format described for --command-acl in - * secchan(8). */ -static bool -executer_is_permitted(const char *acl_, const char *cmd) -{ - char *acl, *save_ptr, *pattern; - bool allowed, denied; - - /* Verify that 'cmd' consists only of alphanumerics plus _ or -. */ - if (cmd[strspn(cmd, "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-")] != '\0') { - VLOG_WARN("rejecting command name \"%s\" that contain forbidden " - "characters", cmd); - return false; - } - - /* Check 'cmd' against 'acl'. */ - acl = xstrdup(acl_); - save_ptr = acl; - allowed = denied = false; - while ((pattern = strsep(&save_ptr, ",")) != NULL && !denied) { - if (pattern[0] != '!' && !fnmatch(pattern, cmd, 0)) { - allowed = true; - } else if (pattern[0] == '!' && !fnmatch(pattern + 1, cmd, 0)) { - denied = true; - } - } - free(acl); - - /* Check the command white/blacklisted state. */ - if (allowed && !denied) { - VLOG_INFO("permitting command execution: \"%s\" is whitelisted", cmd); - } else if (allowed && denied) { - VLOG_WARN("denying command execution: \"%s\" is both blacklisted " - "and whitelisted", cmd); - } else if (!allowed) { - VLOG_WARN("denying command execution: \"%s\" is not whitelisted", cmd); - } else if (denied) { - VLOG_WARN("denying command execution: \"%s\" is blacklisted", cmd); - } - return allowed && !denied; -} - -static bool -executer_remote_packet_cb(struct relay *r, void *e_) -{ - struct executer *e = e_; - struct ofpbuf *msg = r->halves[HALF_REMOTE].rxbuf; - struct nicira_header *request; - char **argv; - char *args; - char *exec_file = NULL; - int max_fds; - struct stat s; - size_t args_size; - size_t argc; - size_t i; - pid_t pid; - int output_fds[2]; - - /* Check for NXT_COMMAND_REQUEST vendor extension. */ - if (msg->size < sizeof(struct nicira_header)) { - return false; - } - request = msg->data; - if (request->header.type != OFPT_VENDOR - || request->vendor != htonl(NX_VENDOR_ID) - || request->subtype != htonl(NXT_COMMAND_REQUEST)) { - return false; - } - - /* Verify limit on children not exceeded. - * XXX should probably kill children when the connection drops? */ - if (e->n_children >= MAX_CHILDREN) { - send_child_message(r, request->header.xid, NXT_STATUS_ERROR, - "too many child processes"); - VLOG_WARN("limit of %d child processes reached, dropping request", - MAX_CHILDREN); - return false; - } - - /* Copy argument buffer, adding a null terminator at the end. Now every - * argument is null-terminated, instead of being merely null-delimited. */ - args_size = msg->size - sizeof *request; - args = xmemdup0((const void *) (request + 1), args_size); - - /* Count arguments. */ - argc = 0; - for (i = 0; i <= args_size; i++) { - argc += args[i] == '\0'; - } - - /* Set argv[*] to point to each argument. */ - argv = xmalloc((argc + 1) * sizeof *argv); - argv[0] = args; - for (i = 1; i < argc; i++) { - argv[i] = strchr(argv[i - 1], '\0') + 1; - } - argv[argc] = NULL; - - /* Check permissions. */ - if (!executer_is_permitted(e->s->command_acl, argv[0])) { - send_child_message(r, request->header.xid, NXT_STATUS_ERROR, - "command not allowed"); - goto done; - } - - /* Find the executable. */ - exec_file = xasprintf("%s/%s", e->s->command_dir, argv[0]); - if (stat(exec_file, &s)) { - VLOG_WARN("failed to stat \"%s\": %s", exec_file, strerror(errno)); - send_child_message(r, request->header.xid, NXT_STATUS_ERROR, - "command not allowed"); - goto done; - } - if (!S_ISREG(s.st_mode)) { - VLOG_WARN("\"%s\" is not a regular file", exec_file); - send_child_message(r, request->header.xid, NXT_STATUS_ERROR, - "command not allowed"); - goto done; - } - argv[0] = exec_file; - - /* Arrange to capture output. */ - if (pipe(output_fds)) { - VLOG_WARN("pipe failed: %s", strerror(errno)); - send_child_message(r, request->header.xid, NXT_STATUS_ERROR, - "internal error (pipe)"); - goto done; - } - - pid = fork(); - if (!pid) { - /* Running in child. - * XXX should run in new process group so that we can signal all - * subprocesses at once? Would also want to catch fatal signals and - * kill them at the same time though. */ - fatal_signal_fork(); - dup2(e->null_fd, 0); - dup2(output_fds[1], 1); - dup2(e->null_fd, 2); - max_fds = get_max_fds(); - for (i = 3; i < max_fds; i++) { - close(i); - } - if (chdir(e->s->command_dir)) { - printf("could not change directory to \"%s\": %s", - e->s->command_dir, strerror(errno)); - exit(EXIT_FAILURE); - } - execv(argv[0], argv); - printf("failed to start \"%s\": %s\n", argv[0], strerror(errno)); - exit(EXIT_FAILURE); - } else if (pid > 0) { - /* Running in parent. */ - struct child *child; - - VLOG_INFO("started \"%s\" subprocess", argv[0]); - send_child_status(r, request->header.xid, NXT_STATUS_STARTED, NULL, 0); - child = &e->children[e->n_children++]; - child->name = xstrdup(argv[0]); - child->pid = pid; - child->relay = r; - child->xid = request->header.xid; - child->output_fd = output_fds[0]; - child->output = xmalloc(MAX_OUTPUT); - child->output_size = 0; - set_nonblocking(output_fds[0]); - close(output_fds[1]); - } else { - VLOG_WARN("fork failed: %s", strerror(errno)); - send_child_message(r, request->header.xid, NXT_STATUS_ERROR, - "internal error (fork)"); - close(output_fds[0]); - close(output_fds[1]); - } - -done: - free(exec_file); - free(args); - free(argv); - return true; -} - -static void -send_child_status(struct relay *relay, uint32_t xid, uint32_t status, - const void *data, size_t size) -{ - if (relay) { - struct nx_command_reply *r; - struct ofpbuf *buffer; - - r = make_openflow_xid(sizeof *r, OFPT_VENDOR, xid, &buffer); - r->nxh.vendor = htonl(NX_VENDOR_ID); - r->nxh.subtype = htonl(NXT_COMMAND_REPLY); - r->status = htonl(status); - ofpbuf_put(buffer, data, size); - update_openflow_length(buffer); - if (rconn_send(relay->halves[HALF_REMOTE].rconn, buffer, NULL)) { - ofpbuf_delete(buffer); - } - } -} - -static void -send_child_message(struct relay *relay, uint32_t xid, uint32_t status, - const char *message) -{ - send_child_status(relay, xid, status, message, strlen(message)); -} - -/* 'child' died with 'status' as its return code. Deal with it. */ -static void -child_terminated(struct child *child, int status) -{ - struct ds ds; - uint32_t ofp_status; - - /* Log how it terminated. */ - ds_init(&ds); - if (WIFEXITED(status)) { - ds_put_format(&ds, "normally with status %d", WEXITSTATUS(status)); - } else if (WIFSIGNALED(status)) { - const char *name = NULL; -#ifdef HAVE_STRSIGNAL - name = strsignal(WTERMSIG(status)); -#endif - ds_put_format(&ds, "by signal %d", WTERMSIG(status)); - if (name) { - ds_put_format(&ds, " (%s)", name); - } - } - if (WCOREDUMP(status)) { - ds_put_cstr(&ds, " (core dumped)"); - } - VLOG_INFO("child process \"%s\" with pid %ld terminated %s", - child->name, (long int) child->pid, ds_cstr(&ds)); - ds_destroy(&ds); - - /* Send a status message back to the controller that requested the - * command. */ - if (WIFEXITED(status)) { - ofp_status = WEXITSTATUS(status) | NXT_STATUS_EXITED; - } else if (WIFSIGNALED(status)) { - ofp_status = WTERMSIG(status) | NXT_STATUS_SIGNALED; - } else { - ofp_status = NXT_STATUS_UNKNOWN; - } - if (WCOREDUMP(status)) { - ofp_status |= NXT_STATUS_COREDUMP; - } - send_child_status(child->relay, child->xid, ofp_status, - child->output, child->output_size); -} - -/* Read output from 'child' and append it to its output buffer. */ -static void -poll_child(struct child *child) -{ - ssize_t n; - - if (child->output_fd < 0) { - return; - } - - do { - n = read(child->output_fd, child->output + child->output_size, - MAX_OUTPUT - child->output_size); - } while (n < 0 && errno == EINTR); - if (n > 0) { - child->output_size += n; - if (child->output_size < MAX_OUTPUT) { - return; - } - } else if (n < 0 && errno == EAGAIN) { - return; - } - close(child->output_fd); - child->output_fd = -1; -} - -static void -executer_periodic_cb(void *e_) -{ - struct executer *e = e_; - char buffer[MAX_CHILDREN]; - size_t i; - - if (!e->n_children) { - return; - } - - /* Read output from children. */ - for (i = 0; i < e->n_children; i++) { - struct child *child = &e->children[i]; - poll_child(child); - } - - /* If SIGCHLD was received, reap dead children. */ - if (read(e->wait_fd, buffer, sizeof buffer) <= 0) { - return; - } - for (;;) { - int status; - pid_t pid; - - /* Get dead child in 'pid' and its return code in 'status'. */ - pid = waitpid(WAIT_ANY, &status, WNOHANG); - if (pid < 0 && errno == EINTR) { - continue; - } else if (pid <= 0) { - return; - } - - /* Find child with given 'pid' and drop it from the list. */ - for (i = 0; i < e->n_children; i++) { - struct child *child = &e->children[i]; - if (child->pid == pid) { - poll_child(child); - child_terminated(child, status); - free(child->name); - free(child->output); - *child = e->children[--e->n_children]; - goto found; - } - } - VLOG_WARN("child with unknown pid %ld terminated", (long int) pid); - found:; - } - -} - -static void -executer_wait_cb(void *e_) -{ - struct executer *e = e_; - if (e->n_children) { - size_t i; - - /* Wake up on SIGCHLD. */ - poll_fd_wait(e->wait_fd, POLLIN); - - /* Wake up when we get output from a child. */ - for (i = 0; i < e->n_children; i++) { - struct child *child = &e->children[i]; - if (child->output_fd >= 0) { - poll_fd_wait(e->wait_fd, POLLIN); - } - } - } -} - -static void -executer_closing_cb(struct relay *r, void *e_) -{ - struct executer *e = e_; - size_t i; - - /* If any of our children was connected to 'r', then disconnect it so we - * don't try to reference a dead connection when the process terminates - * later. - * XXX kill the children started by 'r'? */ - for (i = 0; i < e->n_children; i++) { - if (e->children[i].relay == r) { - e->children[i].relay = NULL; - } - } -} - -static int child_fd; - -static void -sigchld_handler(int signr UNUSED) -{ - write(child_fd, "", 1); -} - -static struct hook_class executer_hook_class = { - NULL, /* local_packet_cb */ - executer_remote_packet_cb, /* remote_packet_cb */ - executer_periodic_cb, /* periodic_cb */ - executer_wait_cb, /* wait_cb */ - executer_closing_cb, /* closing_cb */ -}; - -void -executer_start(struct secchan *secchan, const struct settings *settings) -{ - struct executer *e; - struct sigaction sa; - int fds[2], null_fd; - - /* Create pipe for notifying us that SIGCHLD was invoked. */ - if (pipe(fds)) { - ofp_fatal(errno, "pipe failed"); - } - set_nonblocking(fds[0]); - set_nonblocking(fds[1]); - child_fd = fds[1]; - - /* Open /dev/null. */ - null_fd = open("/dev/null", O_RDWR); - if (null_fd < 0) { - ofp_fatal(errno, "could not open /dev/null"); - } - - /* Set up signal handler. */ - memset(&sa, 0, sizeof sa); - sa.sa_handler = sigchld_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_NOCLDSTOP | SA_RESTART; - if (sigaction(SIGCHLD, &sa, NULL)) { - ofp_fatal(errno, "sigaction(SIGCHLD) failed"); - } - - /* Add hook. */ - e = xcalloc(1, sizeof *e); - e->s = settings; - e->n_children = 0; - e->wait_fd = fds[0]; - e->null_fd = null_fd; - add_hook(secchan, &executer_hook_class, e); -} diff --git a/secchan/executer.h b/secchan/executer.h deleted file mode 100644 index 8e9ad3d..0000000 --- a/secchan/executer.h +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef EXECUTER_H -#define EXECUTER_H 1 - -struct secchan; -struct settings; - -void executer_start(struct secchan *, const struct settings *); - -#endif /* executer.h */ diff --git a/secchan/ofprotocol.8.in b/secchan/ofprotocol.8.in index bf7621e..4aae44a 100644 --- a/secchan/ofprotocol.8.in +++ b/secchan/ofprotocol.8.in @@ -405,34 +405,6 @@ specified on \fB--rate-limit\fR. This option takes effect only when \fB--rate-limit\fR is also specified. -.SS "Remote Command Execution Options" - -.TP -\fB--command-acl=\fR[\fB!\fR]\fIglob\fR[\fB,\fR[\fB!\fR]\fIglob\fR...] -Configures the commands that remote OpenFlow connections are allowed -to invoke using (e.g.) \fBdpctl execute\fR. The argument is a -comma-separated sequence of shell glob patterns. A glob pattern -specified without a leading \fB!\fR is a ``whitelist'' that specifies -a set of commands that are that may be invoked, whereas a pattern that -does begin with \fB!\fR is a ``blacklist'' that specifies commands -that may not be invoked. To be permitted, a command name must be -whitelisted and must not be blacklisted; -e.g. \fB--command-acl=up*,!upgrade\fR would allow any command whose name -begins with \fBup\fR except for the command named \fBupgrade\fR. -Command names that include characters other than upper- and lower-case -English letters, digits, and the underscore and hyphen characters are -unconditionally disallowed. - -When the whitelist and blacklist permit a command name, \fBofprotocol\fR -looks for a program with the same name as the command in the commands -directory (see below). Other directories are not searched. - -.TP -\fB--command-dir=\fIdirectory\fR -Sets the directory searched for remote command execution to -\fBdirectory\fR. The default directory is -\fB@pkgdatadir@/commands\fR. - .SS "Daemon Options" .so lib/daemon.man diff --git a/secchan/secchan.c b/secchan/secchan.c index 29aa665..15c7b69 100644 --- a/secchan/secchan.c +++ b/secchan/secchan.c @@ -46,7 +46,6 @@ #include "daemon.h" #include "dirs.h" #include "discovery.h" -#include "executer.h" #include "emerg-flow.h" #include "fail-open.h" #include "failover.h" @@ -229,9 +228,6 @@ main(int argc, char *argv[]) if (s.rate_limit) { rate_limit_start(&secchan, &s, switch_status, remote_rconn); } - if (s.command_acl[0]) { - executer_start(&secchan, &s); - } if (s.emerg_flow) { emerg_flow_start(&secchan, &s, switch_status, local_rconn, remote_rconn); } @@ -592,8 +588,6 @@ parse_options(int argc, char *argv[], struct settings *s) OPT_NO_STP, OPT_OUT_OF_BAND, OPT_IN_BAND, - OPT_COMMAND_ACL, - OPT_COMMAND_DIR, OPT_EMERG_FLOW, VLOG_OPTION_ENUMS, LEAK_CHECKER_OPTION_ENUMS @@ -613,8 +607,6 @@ parse_options(int argc, char *argv[], struct settings *s) {"no-stp", no_argument, 0, OPT_NO_STP}, {"out-of-band", no_argument, 0, OPT_OUT_OF_BAND}, {"in-band", no_argument, 0, OPT_IN_BAND}, - {"command-acl", required_argument, 0, OPT_COMMAND_ACL}, - {"command-dir", required_argument, 0, OPT_COMMAND_DIR}, {"emerg-flow", no_argument, 0, OPT_EMERG_FLOW}, {"verbose", optional_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, @@ -644,8 +636,6 @@ parse_options(int argc, char *argv[], struct settings *s) s->burst_limit = 0; s->enable_stp = false; s->in_band = true; - s->command_acl = ""; - s->command_dir = xasprintf("%s/commands", ofp_pkgdatadir); s->emerg_flow = false; for (;;) { int c; @@ -737,16 +727,6 @@ parse_options(int argc, char *argv[], struct settings *s) s->in_band = true; break; - case OPT_COMMAND_ACL: - s->command_acl = (s->command_acl[0] - ? xasprintf("%s,%s", s->command_acl, optarg) - : optarg); - break; - - case OPT_COMMAND_DIR: - s->command_dir = optarg; - break; - case OPT_EMERG_FLOW: s->emerg_flow = true; break; @@ -890,10 +870,7 @@ usage(void) " --emerg-flow enable emergency flow protection/restoration\n" "\nRate-limiting of \"packet-in\" messages to the controller:\n" " --rate-limit[=PACKETS] max rate, in packets/s (default: 1000)\n" - " --burst-limit=BURST limit on packet credit for idle time\n" - "\nRemote command execution options:\n" - " --command-acl=[!]GLOB[,[!]GLOB...] set allowed/denied commands\n" - " --command-dir=DIR set command dir (default: %s/commands)\n", + " --burst-limit=BURST limit on packet credit for idle time\n", ofp_pkgdatadir); daemon_usage(); vlog_usage(); diff --git a/secchan/secchan.h b/secchan/secchan.h index 749fddf..7f89e2e 100644 --- a/secchan/secchan.h +++ b/secchan/secchan.h @@ -85,10 +85,6 @@ struct settings { /* Spanning tree protocol. */ bool enable_stp; - /* Remote command execution. */ - char *command_acl; /* Command white/blacklist, as shell globs. */ - char *command_dir; /* Directory that contains commands. */ - /* Emergency flow protection/restoration behavior. */ bool emerg_flow; }; diff --git a/utilities/dpctl.8.in b/utilities/dpctl.8.in index b2b388e..8f92230 100644 --- a/utilities/dpctl.8.in +++ b/utilities/dpctl.8.in @@ -215,16 +215,6 @@ messages), but it will not print any messages sent to the kernel by \fBofprotocol\fR and other processes, nor will it print replies sent by the kernel in response to those messages. -.TP -\fBexecute \fIswitch command \fR[\fIarg\fR...] - -Sends a request to \fIswitch\fR to execute \fIcommand\fR along with -each \fIarg\fR, if any, then waits for the command to complete and -reports its completion status on \fBstderr\fR and its output, if any, -on \fBstdout\fR. The set of available commands and their argument is -switch-dependent. (This command uses a Nicira extension to OpenFlow -that may not be available on all switches.) - .PP The following commands can be used regardless of the connection method. They apply to OpenFlow switches and controllers. diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 57ddbc5..cd344f5 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -240,7 +240,6 @@ usage(void) " mod-flows SWITCH FLOW modify actions of matching FLOWs\n" " del-flows SWITCH [FLOW] delete matching FLOWs\n" " monitor SWITCH print packets received from SWITCH\n" - " execute SWITCH CMD [ARG...] execute CMD with ARGS on SWITCH\n" "\nFor local datapaths, remote switches, and controllers:\n" " probe VCONN probe whether VCONN is up\n" " ping VCONN [N] latency of N-byte echos\n" @@ -1436,71 +1435,6 @@ do_benchmark(const struct settings *s UNUSED, int argc UNUSED, char *argv[]) count * message_size / (duration / 1000.0)); } -static void -do_execute(const struct settings *s UNUSED, int argc, char *argv[]) -{ - struct vconn *vconn; - struct ofpbuf *request; - struct nicira_header *nicira; - struct nx_command_reply *ncr; - uint32_t xid; - int i; - - nicira = make_openflow(sizeof *nicira, OFPT_VENDOR, &request); - xid = nicira->header.xid; - nicira->vendor = htonl(NX_VENDOR_ID); - nicira->subtype = htonl(NXT_COMMAND_REQUEST); - ofpbuf_put(request, argv[2], strlen(argv[2])); - for (i = 3; i < argc; i++) { - ofpbuf_put_zeros(request, 1); - ofpbuf_put(request, argv[i], strlen(argv[i])); - } - update_openflow_length(request); - - open_vconn(argv[1], &vconn); - run(vconn_send_block(vconn, request), "send"); - - for (;;) { - struct ofpbuf *reply; - uint32_t status; - - run(vconn_recv_xid(vconn, xid, &reply), "recv_xid"); - if (reply->size < sizeof *ncr) { - ofp_fatal(0, "reply is too short (%zu bytes < %zu bytes)", - reply->size, sizeof *ncr); - } - ncr = reply->data; - if (ncr->nxh.header.type != OFPT_VENDOR - || ncr->nxh.vendor != htonl(NX_VENDOR_ID) - || ncr->nxh.subtype != htonl(NXT_COMMAND_REPLY)) { - ofp_fatal(0, "reply is invalid"); - } - - status = ntohl(ncr->status); - if (status & NXT_STATUS_STARTED) { - /* Wait for a second reply. */ - continue; - } else if (status & NXT_STATUS_EXITED) { - fprintf(stderr, "process terminated normally with exit code %d", - status & NXT_STATUS_EXITSTATUS); - } else if (status & NXT_STATUS_SIGNALED) { - fprintf(stderr, "process terminated by signal %d", - status & NXT_STATUS_TERMSIG); - } else if (status & NXT_STATUS_ERROR) { - fprintf(stderr, "error executing command"); - } else { - fprintf(stderr, "process terminated for unknown reason"); - } - if (status & NXT_STATUS_COREDUMP) { - fprintf(stderr, " (core dumped)"); - } - putc('\n', stderr); - - fwrite(ncr + 1, reply->size - sizeof *ncr, 1, stdout); - break; - } -} - static void do_help(const struct settings *s UNUSED, int argc UNUSED, char *argv[] UNUSED) { @@ -1536,6 +1470,5 @@ static struct command all_commands[] = { { "probe", 1, 1, do_probe }, { "ping", 1, 2, do_ping }, { "benchmark", 3, 3, do_benchmark }, - { "execute", 2, INT_MAX, do_execute }, { NULL, 0, 0, NULL }, };