[RFC PATCHv2 09/13] utilities: Add ovs-bpfctl utility.


William Tu
 

From: Joe Stringer <joe@...>

This new utility is used for standalone probing of BPF datapath state.

Signed-off-by: Joe Stringer <joe@...>
Signed-off-by: William Tu <u9012063@...>
Signed-off-by: Yifeng Sun <pkusunyifeng@...>
Co-authored-by: William Tu <u9012063@...>
Co-authored-by: Yifeng Sun <pkusunyifeng@...>
---
utilities/automake.mk | 9 ++
utilities/ovs-bpfctl.8.xml | 45 ++++++++
utilities/ovs-bpfctl.c | 248 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 302 insertions(+)
create mode 100644 utilities/ovs-bpfctl.8.xml
create mode 100644 utilities/ovs-bpfctl.c

diff --git a/utilities/automake.mk b/utilities/automake.mk
index 1636cb93e677..9de28eb1eb7d 100644
--- a/utilities/automake.mk
+++ b/utilities/automake.mk
@@ -39,6 +39,7 @@ utilities/ovs-lib: $(top_builddir)/config.status

EXTRA_DIST += \
utilities/ovs-appctl-bashcomp.bash \
+ utilities/ovs-bpfctl.8.xml \
utilities/ovs-check-dead-ifs.in \
utilities/ovs-ctl.in \
utilities/ovs-dev.py \
@@ -103,6 +104,7 @@ CLEANFILES += \

man_MANS += \
utilities/ovs-appctl.8 \
+ utilities/ovs-bpfctl.8 \
utilities/ovs-ctl.8 \
utilities/ovs-testcontroller.8 \
utilities/ovs-dpctl.8 \
@@ -148,4 +150,11 @@ FLAKE8_PYFILES += utilities/ovs-pcap.in \
utilities/checkpatch.py utilities/ovs-dev.py \
utilities/ovs-tcpdump.in

+if HAVE_BPF
+bin_PROGRAMS += \
+ utilities/ovs-bpfctl
+utilities_ovs_bpfctl_SOURCES = utilities/ovs-bpfctl.c
+utilities_ovs_bpfctl_LDADD = lib/libopenvswitch.la
+endif
+
include utilities/bugtool/automake.mk
diff --git a/utilities/ovs-bpfctl.8.xml b/utilities/ovs-bpfctl.8.xml
new file mode 100644
index 000000000000..6160d5eb06aa
--- /dev/null
+++ b/utilities/ovs-bpfctl.8.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manpage program="ovs-bpfctl" section="8" title="ovs-bpfctl">
+ <h1>Name</h1>
+ <p>ovs-bpfctl -- administer Open vSwitch BPF state</p>
+
+ <h1>Synopsis</h1>
+ <p><code>ovs-bpfctl</code> [<var>options</var>] <var>command</var> [<var>arg</var>...]</p>
+
+ <h1>Description</h1>
+ <p>This utility can be used to probe and manage OVS BPF state.</p>
+
+ <h1>Commands</h1>
+ <dl>
+ <dt><code>show</code></dt>
+ <dd>
+ Prints a brief overview of the current BPF configuration state.
+ </dd>
+
+ <dt><code>load-dp</code> <var>filename</var></dt>
+ <dd>
+ Loads a BPF datapath implementation from <var>filename</var> into the
+ kernel, and pins it to the filesystem.
+ </dd>
+ </dl>
+
+ <h1>Options</h1>
+ <xi:include href="lib/common.xml" xmlns:xi="http://www.w3.org/2003/XInclude"/>
+
+ <h1>Exit Status</h1>
+ <dl>
+ <dt>0</dt>
+ <dd>Successful program execution.</dd>
+ <dt>1</dt>
+ <dd>Usage or syntax error.</dd>
+ </dl>
+
+ <h1>See also</h1>
+ <p><code>tc</code>(8), <code>tc-bpf</code>(8)</p>
+
+ <h1>Authors</h1>
+ <p>Manpage written by Joe Stringer.</p>
+ <p>Please report corrections or improvements to
+ <code>&lt;bugs@...&gt;</code></p>
+
+</manpage>
diff --git a/utilities/ovs-bpfctl.c b/utilities/ovs-bpfctl.c
new file mode 100644
index 000000000000..10b238a3d79e
--- /dev/null
+++ b/utilities/ovs-bpfctl.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2016 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include <errno.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/stat.h>
+
+#include "bpf.h"
+#include "command-line.h"
+#include "fatal-signal.h"
+#include "util.h"
+#include "openvswitch/dynamic-string.h"
+#include "openvswitch/vlog.h"
+
+static int verbosity = 0;
+static bool read_only = false;
+
+typedef int bpfctl_command_handler(int argc, const char *argv[]);
+struct bpfctl_command {
+ const char *name;
+ const char *usage;
+ int min_args;
+ int max_args;
+ bpfctl_command_handler *handler;
+ enum { DP_RO, DP_RW} mode;
+};
+
+OVS_NO_RETURN static void usage(void *userdata OVS_UNUSED);
+static void parse_options(int argc, char *argv[]);
+static int bpfctl_run_command(int argc, const char *argv[]);
+
+static void
+bpfctl_print(void *userdata OVS_UNUSED, bool error, const char *msg)
+{
+ FILE *outfile = error ? stderr : stdout;
+ fputs(msg, outfile);
+}
+
+static void
+bpfctl_error(int err_no, const char *fmt, ...)
+{
+ const char *subprogram_name = get_subprogram_name();
+ struct ds ds = DS_EMPTY_INITIALIZER;
+ int save_errno = errno;
+ va_list args;
+
+ if (subprogram_name[0]) {
+ ds_put_format(&ds, "%s(%s): ", program_name,subprogram_name);
+ } else {
+ ds_put_format(&ds, "%s: ", program_name);
+ }
+
+ va_start(args, fmt);
+ ds_put_format_valist(&ds, fmt, args);
+ va_end(args);
+
+ if (err_no != 0) {
+ ds_put_format(&ds, " (%s)", ovs_retval_to_string(err_no));
+ }
+ ds_put_cstr(&ds, "\n");
+
+ bpfctl_print(NULL, true, ds_cstr(&ds));
+
+ ds_destroy(&ds);
+
+ errno = save_errno;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int error;
+ set_program_name(argv[0]);
+ parse_options(argc, argv);
+ fatal_ignore_sigpipe();
+
+ error = bpfctl_run_command(argc - optind, (const char **) argv + optind);
+ return error ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+static void
+parse_options(int argc, char *argv[])
+{
+ enum {
+ OPT_CLEAR = UCHAR_MAX + 1,
+ OPT_MAY_CREATE,
+ OPT_READ_ONLY,
+ VLOG_OPTION_ENUMS
+ };
+ static const struct option long_options[] = {
+ {"read-only", no_argument, NULL, OPT_READ_ONLY},
+ {"help", no_argument, NULL, 'h'},
+ {"option", no_argument, NULL, 'o'},
+ {"version", no_argument, NULL, 'V'},
+ VLOG_LONG_OPTIONS,
+ {NULL, 0, NULL, 0},
+ };
+ char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
+
+ for (;;) {
+ int c;
+
+ c = getopt_long(argc, argv, short_options, long_options, NULL);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case OPT_READ_ONLY:
+ read_only = true;
+ break;
+
+ case 'm':
+ verbosity++;
+ break;
+
+ case 'h':
+ usage(NULL);
+
+ case 'o':
+ ovs_cmdl_print_options(long_options);
+ exit(EXIT_SUCCESS);
+
+ case 'V':
+ ovs_print_version(0, 0);
+ exit(EXIT_SUCCESS);
+
+ VLOG_OPTION_HANDLERS
+
+ case '?':
+ exit(EXIT_FAILURE);
+
+ default:
+ abort();
+ }
+ }
+ free(short_options);
+}
+
+static void
+usage(void *userdata OVS_UNUSED)
+{
+ printf("%s: Open vSwitch bpf management utility\n"
+ "usage: %s [OPTIONS] COMMAND [ARG...]\n"
+ " show show basic info on bpf datapaths\n"
+ " load-dp FILENAME load datapath from FILENAME\n",
+ program_name, program_name);
+ vlog_usage();
+ printf(" -m, --more increase verbosity of output\n"
+ " -h, --help display this help message\n"
+ " -V, --version display version information\n");
+ exit(EXIT_SUCCESS);
+}
+
+static int
+bpfctl_show(int argc OVS_UNUSED, const char *argv[] OVS_UNUSED)
+{
+ struct bpf_state bpf;
+
+ if (!bpf_get(&bpf, verbosity)) {
+ struct ds ds = DS_EMPTY_INITIALIZER;
+
+ bpf_format_state(&ds, &bpf);
+ printf("%s", ds_cstr(&ds));
+ ds_destroy(&ds);
+ bpf_put(&bpf);
+ }
+ return 0;
+}
+
+static int
+bpfctl_load_dp(int argc OVS_UNUSED, const char *argv[])
+{
+ int error;
+
+ error = bpf_init();
+ if (error) {
+ return error;
+ }
+ return bpf_load(argv[1]);
+}
+
+static const struct bpfctl_command all_commands[] = {
+ { "load-dp", "[file]", 1, 1, bpfctl_load_dp, DP_RW },
+ { "show", "", 0, 0, bpfctl_show, DP_RO },
+ { NULL, NULL, 0, 0, NULL, DP_RO },
+};
+
+/* Runs the command designated by argv[0] within the command table specified by
+ * 'commands', which must be terminated by a command whose 'name' member is a
+ * null pointer. */
+static int
+bpfctl_run_command(int argc, const char *argv[])
+{
+ const struct bpfctl_command *p;
+
+ if (argc < 1) {
+ bpfctl_error(0, "missing command name; use --help for help");
+ return EINVAL;
+ }
+
+ for (p = all_commands; p->name != NULL; p++) {
+ if (!strcmp(p->name, argv[0])) {
+ int n_arg = argc - 1;
+ if (n_arg < p->min_args) {
+ bpfctl_error(0, "'%s' command requires at least %d arguments",
+ p->name, p->min_args);
+ return EINVAL;
+ } else if (n_arg > p->max_args) {
+ bpfctl_error(0, "'%s' command takes at most %d arguments",
+ p->name, p->max_args);
+ return EINVAL;
+ } else {
+ if (p->mode == DP_RW && read_only) {
+ bpfctl_error(0,
+ "'%s' command does not work in read only mode",
+ p->name);
+ return EINVAL;
+ }
+ return p->handler(argc, argv);
+ }
+ }
+ }
+
+ bpfctl_error(0, "unknown command '%s'; use --help for help",
+ argv[0]);
+ return EINVAL;
+}
--
2.7.4