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

William Tu u9012063 at gmail.com
Sat Jul 14 11:39:01 UTC 2018


From: Joe Stringer <joe at ovn.org>

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

Signed-off-by: Joe Stringer <joe at ovn.org>
Signed-off-by: William Tu <u9012063 at gmail.com>
Signed-off-by: Yifeng Sun <pkusunyifeng at gmail.com>
Co-authored-by: William Tu <u9012063 at gmail.com>
Co-authored-by: Yifeng Sun <pkusunyifeng at gmail.com>
---
 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 at openvswitch.org&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



More information about the dev mailing list