diff options
author | Darrell Ball <dlu998@gmail.com> | 2019-02-13 15:34:21 -0800 |
---|---|---|
committer | Ben Pfaff <blp@ovn.org> | 2019-02-14 14:18:56 -0800 |
commit | 4ea96698f66792302b88b06c756862e24cc5b88e (patch) | |
tree | 3f4920fe570a2a9c48ee81f50160ebe95d925513 /lib/dpctl.c | |
parent | 9f17f104fe789b0ae803a2a45bba63057a73b116 (diff) | |
download | openvswitch-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.c | 215 |
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 }, |