summaryrefslogtreecommitdiff
path: root/lib/dpctl.c
diff options
context:
space:
mode:
authorDarrell Ball <dlu998@gmail.com>2019-02-13 15:34:21 -0800
committerBen Pfaff <blp@ovn.org>2019-02-14 14:18:56 -0800
commit4ea96698f66792302b88b06c756862e24cc5b88e (patch)
tree3f4920fe570a2a9c48ee81f50160ebe95d925513 /lib/dpctl.c
parent9f17f104fe789b0ae803a2a45bba63057a73b116 (diff)
downloadopenvswitch-4ea96698f66792302b88b06c756862e24cc5b88e.tar.gz
Userspace datapath: Add fragmentation handling.
Fragmentation handling is added for supporting conntrack. Both v4 and v6 are supported. After discussion with several people, I decided to not store configuration state in the database to be more consistent with the kernel in future, similarity with other conntrack configuration which will not be in the database as well and overall simplicity. Accordingly, fragmentation handling is enabled by default. This patch enables fragmentation tests for the userspace datapath. Signed-off-by: Darrell Ball <dlu998@gmail.com> Signed-off-by: Ben Pfaff <blp@ovn.org>
Diffstat (limited to 'lib/dpctl.c')
-rw-r--r--lib/dpctl.c215
1 files changed, 214 insertions, 1 deletions
diff --git a/lib/dpctl.c b/lib/dpctl.c
index 59071cdba..f5a09b70f 100644
--- a/lib/dpctl.c
+++ b/lib/dpctl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2017 Nicira, Inc.
+ * Copyright (c) 2008-2018 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@
#include "dirs.h"
#include "dpctl.h"
#include "dpif.h"
+#include "dpif-provider.h"
#include "openvswitch/dynamic-string.h"
#include "flow.h"
#include "openvswitch/match.h"
@@ -1917,6 +1918,210 @@ out:
return error;
}
+static int
+ipf_set_enabled__(int argc, const char *argv[], struct dpctl_params *dpctl_p,
+ bool enabled)
+{
+ struct dpif *dpif;
+ int error = opt_dpif_open(argc, argv, dpctl_p, 4, &dpif);
+ if (!error) {
+ char v4_or_v6[3] = {0};
+ if (ovs_scan(argv[argc - 1], "%2s", v4_or_v6) &&
+ (!strncmp(v4_or_v6, "v4", 2) || !strncmp(v4_or_v6, "v6", 2))) {
+ error = ct_dpif_ipf_set_enabled(
+ dpif, !strncmp(v4_or_v6, "v6", 2), enabled);
+ if (!error) {
+ dpctl_print(dpctl_p,
+ "%s fragmentation reassembly successful",
+ enabled ? "enabling" : "disabling");
+ } else {
+ dpctl_error(dpctl_p, error,
+ "%s fragmentation reassembly failed",
+ enabled ? "enabling" : "disabling");
+ }
+ } else {
+ error = EINVAL;
+ dpctl_error(dpctl_p, error,
+ "parameter missing: 'v4' for IPv4 or 'v6' for IPv6");
+ }
+ dpif_close(dpif);
+ }
+ return error;
+}
+
+static int
+dpctl_ipf_set_enabled(int argc, const char *argv[],
+ struct dpctl_params *dpctl_p)
+{
+ return ipf_set_enabled__(argc, argv, dpctl_p, true);
+}
+
+static int
+dpctl_ipf_set_disabled(int argc, const char *argv[],
+ struct dpctl_params *dpctl_p)
+{
+ return ipf_set_enabled__(argc, argv, dpctl_p, false);
+}
+
+static int
+dpctl_ipf_set_min_frag(int argc, const char *argv[],
+ struct dpctl_params *dpctl_p)
+{
+ struct dpif *dpif;
+ int error = opt_dpif_open(argc, argv, dpctl_p, 4, &dpif);
+ if (!error) {
+ char v4_or_v6[3] = {0};
+ if (ovs_scan(argv[argc - 2], "%2s", v4_or_v6) &&
+ (!strncmp(v4_or_v6, "v4", 2) || !strncmp(v4_or_v6, "v6", 2))) {
+ uint32_t min_fragment;
+ if (ovs_scan(argv[argc - 1], "%"SCNu32, &min_fragment)) {
+ error = ct_dpif_ipf_set_min_frag(
+ dpif, !strncmp(v4_or_v6, "v6", 2), min_fragment);
+ if (!error) {
+ dpctl_print(dpctl_p,
+ "setting minimum fragment size successful");
+ } else {
+ dpctl_error(dpctl_p, error,
+ "requested minimum fragment size too small;"
+ " see documentation");
+ }
+ } else {
+ error = EINVAL;
+ dpctl_error(dpctl_p, error,
+ "parameter missing for minimum fragment size");
+ }
+ } else {
+ error = EINVAL;
+ dpctl_error(dpctl_p, error,
+ "parameter missing: v4 for IPv4 or v6 for IPv6");
+ }
+ dpif_close(dpif);
+ }
+
+ return error;
+}
+
+static int
+dpctl_ipf_set_max_nfrags(int argc, const char *argv[],
+ struct dpctl_params *dpctl_p)
+{
+ struct dpif *dpif;
+ int error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif);
+ if (!error) {
+ uint32_t nfrags_max;
+ if (ovs_scan(argv[argc - 1], "%"SCNu32, &nfrags_max)) {
+ error = ct_dpif_ipf_set_max_nfrags(dpif, nfrags_max);
+ if (!error) {
+ dpctl_print(dpctl_p,
+ "setting maximum fragments successful");
+ } else {
+ dpctl_error(dpctl_p, error,
+ "setting maximum fragments failed");
+ }
+ } else {
+ error = EINVAL;
+ dpctl_error(dpctl_p, error,
+ "parameter missing for maximum fragments");
+ }
+ dpif_close(dpif);
+ }
+
+ return error;
+}
+
+static void
+dpctl_dump_ipf(struct dpif *dpif, struct dpctl_params *dpctl_p)
+{
+ struct ipf_dump_ctx *dump_ctx;
+ char *dump;
+
+ int error = ct_dpif_ipf_dump_start(dpif, &dump_ctx);
+ if (error) {
+ dpctl_error(dpctl_p, error, "starting ipf list dump");
+ /* Nothing to clean up, just return. */
+ return;
+ }
+
+ dpctl_print(dpctl_p, "\n Fragment Lists:\n\n");
+ while (!(error = ct_dpif_ipf_dump_next(dpif, dump_ctx, &dump))) {
+ dpctl_print(dpctl_p, "%s\n", dump);
+ free(dump);
+ }
+
+ if (error && error != EOF) {
+ dpctl_error(dpctl_p, error, "dumping ipf lists failed");
+ }
+
+ ct_dpif_ipf_dump_done(dpif, dump_ctx);
+}
+
+static int
+dpctl_ct_ipf_get_status(int argc, const char *argv[],
+ struct dpctl_params *dpctl_p)
+{
+ struct dpif *dpif;
+ int error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif);
+
+ if (!error) {
+ struct dpif_ipf_status dpif_ipf_status;
+ error = ct_dpif_ipf_get_status(dpif, &dpif_ipf_status);
+
+ if (!error) {
+ dpctl_print(dpctl_p, " Fragmentation Module Status\n");
+ dpctl_print(dpctl_p, " ---------------------------\n");
+ dpctl_print(dpctl_p, " v4 enabled: %u\n",
+ dpif_ipf_status.v4.enabled);
+ dpctl_print(dpctl_p, " v6 enabled: %u\n",
+ dpif_ipf_status.v6.enabled);
+ dpctl_print(dpctl_p, " max num frags (v4/v6): %u\n",
+ dpif_ipf_status.nfrag_max);
+ dpctl_print(dpctl_p, " num frag: %u\n",
+ dpif_ipf_status.nfrag);
+ dpctl_print(dpctl_p, " min v4 frag size: %u\n",
+ dpif_ipf_status.v4.min_frag_size);
+ dpctl_print(dpctl_p, " v4 frags accepted: %"PRIu64"\n",
+ dpif_ipf_status.v4.nfrag_accepted);
+ dpctl_print(dpctl_p, " v4 frags completed: %"PRIu64"\n",
+ dpif_ipf_status.v4.nfrag_completed_sent);
+ dpctl_print(dpctl_p, " v4 frags expired: %"PRIu64"\n",
+ dpif_ipf_status.v4.nfrag_expired_sent);
+ dpctl_print(dpctl_p, " v4 frags too small: %"PRIu64"\n",
+ dpif_ipf_status.v4.nfrag_too_small);
+ dpctl_print(dpctl_p, " v4 frags overlapped: %"PRIu64"\n",
+ dpif_ipf_status.v4.nfrag_overlap);
+ dpctl_print(dpctl_p, " v4 frags purged: %"PRIu64"\n",
+ dpif_ipf_status.v4.nfrag_purged);
+
+ dpctl_print(dpctl_p, " min v6 frag size: %u\n",
+ dpif_ipf_status.v6.min_frag_size);
+ dpctl_print(dpctl_p, " v6 frags accepted: %"PRIu64"\n",
+ dpif_ipf_status.v6.nfrag_accepted);
+ dpctl_print(dpctl_p, " v6 frags completed: %"PRIu64"\n",
+ dpif_ipf_status.v6.nfrag_completed_sent);
+ dpctl_print(dpctl_p, " v6 frags expired: %"PRIu64"\n",
+ dpif_ipf_status.v6.nfrag_expired_sent);
+ dpctl_print(dpctl_p, " v6 frags too small: %"PRIu64"\n",
+ dpif_ipf_status.v6.nfrag_too_small);
+ dpctl_print(dpctl_p, " v6 frags overlapped: %"PRIu64"\n",
+ dpif_ipf_status.v6.nfrag_overlap);
+ dpctl_print(dpctl_p, " v6 frags purged: %"PRIu64"\n",
+ dpif_ipf_status.v6.nfrag_purged);
+ } else {
+ dpctl_error(dpctl_p, error,
+ "ipf status could not be retrieved");
+ return error;
+ }
+
+ if (dpctl_p->verbosity) {
+ dpctl_dump_ipf(dpif, dpctl_p);
+ }
+
+ dpif_close(dpif);
+ }
+
+ return error;
+}
+
/* Undocumented commands for unit testing. */
static int
@@ -2222,6 +2427,14 @@ static const struct dpctl_command all_commands[] = {
DP_RO },
{ "ct-get-limits", "[dp] [zone=N1[,N2]...]", 0, 2, dpctl_ct_get_limits,
DP_RO },
+ { "ipf-set-enabled", "[dp] v4|v6", 1, 2, dpctl_ipf_set_enabled, DP_RW },
+ { "ipf-set-disabled", "[dp] v4|v6", 1, 2, dpctl_ipf_set_disabled, DP_RW },
+ { "ipf-set-min-frag", "[dp] v4|v6 minfragment", 2, 3,
+ dpctl_ipf_set_min_frag, DP_RW },
+ { "ipf-set-max-nfrags", "[dp] maxfrags", 1, 2,
+ dpctl_ipf_set_max_nfrags, DP_RW },
+ { "ipf-get-status", "[dp]", 0, 1, dpctl_ct_ipf_get_status,
+ DP_RO },
{ "help", "", 0, INT_MAX, dpctl_help, DP_RO },
{ "list-commands", "", 0, INT_MAX, dpctl_list_commands, DP_RO },