[ovs-dev] [patch v9 09/11] ipf: Add set minimum fragment size command.
Darrell Ball
dlu998 at gmail.com
Mon Nov 19 19:09:28 UTC 2018
A new command "ovs-appctl dpctl/ipf-set-min-frag" is added
for userspace datapath conntrack v4/v6 fragmentation support.
Signed-off-by: Darrell Ball <dlu998 at gmail.com>
---
NEWS | 2 ++
lib/ct-dpif.c | 8 ++++++++
lib/ct-dpif.h | 1 +
lib/dpctl.c | 40 ++++++++++++++++++++++++++++++++++++++++
lib/dpctl.man | 11 +++++++++++
lib/dpif-netdev.c | 8 ++++++++
lib/dpif-netlink.c | 1 +
lib/dpif-provider.h | 3 +++
lib/ipf.c | 23 +++++++++++++++++++++++
lib/ipf.h | 1 +
10 files changed, 98 insertions(+)
diff --git a/NEWS b/NEWS
index cedc726..ea354a1 100644
--- a/NEWS
+++ b/NEWS
@@ -13,6 +13,8 @@ Post-v2.10.0
* Add v4/v6 fragmentation support for conntrack.
* New ovs-appctl "dpctl/ipf-set-enabled" and "dpctl/ipf-set-disabled"
commands for userspace datapath conntrack fragmentation support.
+ * New "ovs-appctl dpctl/ipf-set-min-frag" command for userspace
+ datapath conntrack fragmentation support.
- DPDK:
* Add option for simple round-robin based Rxq to PMD assignment.
It can be set with pmd-rxq-assign.
diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c
index edb14f8..d3dad70 100644
--- a/lib/ct-dpif.c
+++ b/lib/ct-dpif.c
@@ -202,6 +202,14 @@ ct_dpif_ipf_set_enabled(struct dpif *dpif, bool v6, bool enable)
: EOPNOTSUPP);
}
+int
+ct_dpif_ipf_set_min_frag(struct dpif *dpif, bool v6, uint32_t min_frag)
+{
+ return (dpif->dpif_class->ipf_set_min_frag
+ ? dpif->dpif_class->ipf_set_min_frag(dpif, v6, min_frag)
+ : EOPNOTSUPP);
+}
+
void
ct_dpif_entry_uninit(struct ct_dpif_entry *entry)
{
diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h
index d61cf71..dca75b7 100644
--- a/lib/ct-dpif.h
+++ b/lib/ct-dpif.h
@@ -213,6 +213,7 @@ int ct_dpif_get_limits(struct dpif *dpif, uint32_t *default_limit,
const struct ovs_list *, struct ovs_list *);
int ct_dpif_del_limits(struct dpif *dpif, const struct ovs_list *);
int ct_dpif_ipf_set_enabled(struct dpif *, bool v6, bool enable);
+int ct_dpif_ipf_set_min_frag(struct dpif *, bool v6, uint32_t min_frag);
void ct_dpif_entry_uninit(struct ct_dpif_entry *);
void ct_dpif_format_entry(const struct ct_dpif_entry *, struct ds *,
bool verbose, bool print_stats);
diff --git a/lib/dpctl.c b/lib/dpctl.c
index d6dac73..72d6c45 100644
--- a/lib/dpctl.c
+++ b/lib/dpctl.c
@@ -1962,6 +1962,44 @@ dpctl_ipf_set_disabled(int argc, const char *argv[],
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;
+}
+
/* Undocumented commands for unit testing. */
static int
@@ -2269,6 +2307,8 @@ static const struct dpctl_command all_commands[] = {
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 },
{ "help", "", 0, INT_MAX, dpctl_help, DP_RO },
{ "list-commands", "", 0, INT_MAX, dpctl_list_commands, DP_RO },
diff --git a/lib/dpctl.man b/lib/dpctl.man
index 32c8259..9bfc8a4 100644
--- a/lib/dpctl.man
+++ b/lib/dpctl.man
@@ -229,6 +229,17 @@ Both IPv4 and IPv6 fragment reassembly are enabled by default. Only
supported for the userspace datapath.
.
.TP
+\*(DX\fBipf\-set\-min\-frag\fR [\fIdp\fR] \fBv4\fR|\fBv6\fR \fIminfrag\fR
+Sets the minimum fragment size for non-final fragments to
+\fIminfrag\fR. Either \fBv4\fR or \fBv6\fR must be specified. For
+enhanced DOS security, higher minimum fragment sizes can usually be used.
+The default IPv4 value is 1200 and the clamped minimum is 400. The default
+IPv6 value is 1280, with a clamped minimum of 400, for testing
+flexibility. The maximum fragment size is not clamped, however, setting
+this value too high might result in valid fragments being dropped. Only
+supported for userspace datapath.
+.
+.TP
.DO "[\fB\-m\fR | \fB\-\-more\fR] [\fB\-s\fR | \fB\-\-statistics\fR]" "\*(DX\fBdump\-conntrack\fR" "[\fIdp\fR] [\fBzone=\fIzone\fR]"
Prints to the console all the connection entries in the tracker used by
\fIdp\fR. If \fBzone=\fIzone\fR is specified, only shows the connections
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 56fcd7e..ebb316c 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -6930,6 +6930,13 @@ dpif_netdev_ipf_set_enabled(struct dpif *dpif OVS_UNUSED, bool v6,
return ipf_set_enabled(v6, enable);
}
+static int
+dpif_netdev_ipf_set_min_frag(struct dpif *dpif OVS_UNUSED, bool v6,
+ uint32_t min_frag)
+{
+ return ipf_set_min_frag(v6, min_frag);
+}
+
const struct dpif_class dpif_netdev_class = {
"netdev",
dpif_netdev_init,
@@ -6982,6 +6989,7 @@ const struct dpif_class dpif_netdev_class = {
NULL, /* ct_get_limits */
NULL, /* ct_del_limits */
dpif_netdev_ipf_set_enabled,
+ dpif_netdev_ipf_set_min_frag,
dpif_netdev_meter_get_features,
dpif_netdev_meter_set,
dpif_netdev_meter_get,
diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index 1f452ff..30f5acf 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -3430,6 +3430,7 @@ const struct dpif_class dpif_netlink_class = {
dpif_netlink_ct_get_limits,
dpif_netlink_ct_del_limits,
NULL, /* ipf_set_enabled */
+ NULL, /* ipf_set_min_frag */
dpif_netlink_meter_get_features,
dpif_netlink_meter_set,
dpif_netlink_meter_get,
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index c379bec..28a6a97 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -474,6 +474,9 @@ struct dpif_class {
* setting is enabled. */
int (*ipf_set_enabled)(struct dpif *, bool v6, bool enabled);
+ /* Set minimum fragment allowed. */
+ int (*ipf_set_min_frag)(struct dpif *, bool v6, uint32_t min_frag);
+
/* Meters */
/* Queries 'dpif' for supported meter features.
diff --git a/lib/ipf.c b/lib/ipf.c
index c2f09be..f9d2de6 100644
--- a/lib/ipf.c
+++ b/lib/ipf.c
@@ -1368,3 +1368,26 @@ ipf_set_enabled(bool v6, bool enable)
atomic_store_relaxed(v6 ? &ifp_v6_enabled : &ifp_v4_enabled, enable);
return 0;
}
+
+int
+ipf_set_min_frag(bool v6, uint32_t value)
+{
+ /* If the user specifies an unreasonably large number, fragmentation
+ * will not work well but it will not blow up. */
+ if ((!v6 && value < IPF_V4_FRAG_SIZE_LBOUND) ||
+ (v6 && value < IPF_V6_FRAG_SIZE_LBOUND)) {
+ return 1;
+ }
+
+ ipf_lock_lock(&ipf_lock);
+ if (v6) {
+ atomic_store_relaxed(&min_v6_frag_size, value);
+ } else {
+ atomic_store_relaxed(&min_v4_frag_size, value);
+ max_v4_frag_list_size = DIV_ROUND_UP(
+ IPV4_PACKET_MAX_SIZE - IPV4_PACKET_MAX_HDR_SIZE,
+ min_v4_frag_size - IPV4_PACKET_MAX_HDR_SIZE);
+ }
+ ipf_lock_unlock(&ipf_lock);
+ return 0;
+}
diff --git a/lib/ipf.h b/lib/ipf.h
index a1673a6..cf221f1 100644
--- a/lib/ipf.h
+++ b/lib/ipf.h
@@ -30,5 +30,6 @@ void ipf_postprocess_conntrack(struct dp_packet_batch *pb, long long now,
void ipf_init(void);
void ipf_destroy(void);
int ipf_set_enabled(bool v6, bool enable);
+int ipf_set_min_frag(bool v6, uint32_t value);
#endif /* ipf.h */
--
1.9.1
More information about the dev
mailing list