[ovs-dev] [patch v7 9/9] ipf: Add fragmentation status reporting.

Darrell Ball dlu998 at gmail.com
Mon Jul 9 16:32:25 UTC 2018


A new command "ovs-appctl dpctl/ipf-get-status" is added
for userspace datapath conntrack fragmentation support.
The command shows the configuration status, fragment counters and
ipf lists state.

Signed-off-by: Darrell Ball <dlu998 at gmail.com>
---
 NEWS                             |   2 +
 lib/ct-dpif.c                    |  45 ++++++++++++++++
 lib/ct-dpif.h                    |  10 ++++
 lib/dpctl.c                      | 107 ++++++++++++++++++++++++++++++++++++++
 lib/dpctl.man                    |   6 +++
 lib/dpif-netdev.c                |  58 +++++++++++++++++++++
 lib/dpif-netlink.c               |   4 ++
 lib/dpif-provider.h              |  17 ++++++
 lib/ipf.c                        | 107 ++++++++++++++++++++++++++++++++++++++
 lib/ipf.h                        |  10 ++++
 tests/system-kmod-macros.at      |  24 +++++++++
 tests/system-traffic.at          |  18 +++++++
 tests/system-userspace-macros.at | 109 +++++++++++++++++++++++++++++++++++++++
 13 files changed, 517 insertions(+)

diff --git a/NEWS b/NEWS
index 2b22a84..af8f9a8 100644
--- a/NEWS
+++ b/NEWS
@@ -24,6 +24,8 @@ Post-v2.9.0
        datapath conntrack fragmentation support.
      * New "ovs-appctl dpctl/ipf-set-max-nfrags" command for userspace datapath
        conntrack fragmentation support.
+     * New "ovs-appctl dpctl/ipf-get-status" command for userspace datapath
+       conntrack fragmentation support.
    - ovs-vsctl: New commands "add-bond-iface" and "del-bond-iface".
    - OpenFlow:
      * OFPT_ROLE_STATUS is now available in OpenFlow 1.3.
diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c
index ee23a4d..a59bc1e 100644
--- a/lib/ct-dpif.c
+++ b/lib/ct-dpif.c
@@ -188,6 +188,51 @@ ct_dpif_ipf_set_max_nfrags(struct dpif *dpif, uint32_t max_frags)
             : EOPNOTSUPP);
 }
 
+int ct_dpif_ipf_get_status(struct dpif *dpif, bool *ipf_v4_enabled,
+    unsigned int *min_v4_frag_size, unsigned int *nfrag_max,
+    unsigned int *nfrag, unsigned int *n4frag_accepted,
+    unsigned int *n4frag_completed_sent,
+    unsigned int *n4frag_expired_sent, unsigned int *n4frag_too_small,
+    unsigned int *n4frag_overlap, bool *ipf_v6_enabled,
+    unsigned int *min_v6_frag_size, unsigned int *n6frag_accepted,
+    unsigned int *n6frag_completed_sent,
+    unsigned int *n6frag_expired_sent, unsigned int *n6frag_too_small,
+    unsigned int *n6frag_overlap)
+{
+    return (dpif->dpif_class->ipf_get_status
+            ? dpif->dpif_class->ipf_get_status(dpif, ipf_v4_enabled,
+            min_v4_frag_size, nfrag_max, nfrag, n4frag_accepted,
+            n4frag_completed_sent, n4frag_expired_sent, n4frag_too_small,
+            n4frag_overlap, ipf_v6_enabled, min_v6_frag_size, n6frag_accepted,
+            n6frag_completed_sent, n6frag_expired_sent, n6frag_too_small,
+            n6frag_overlap)
+            : EOPNOTSUPP);
+}
+
+int
+ct_dpif_ipf_dump_start(struct dpif *dpif, struct ipf_dump_ctx **dump_ctx)
+{
+    return (dpif->dpif_class->ipf_dump_start
+           ? dpif->dpif_class->ipf_dump_start(dpif, dump_ctx)
+           : EOPNOTSUPP);
+}
+
+int
+ct_dpif_ipf_dump_next(struct dpif *dpif, void *dump_ctx,  char **dump)
+{
+    return (dpif->dpif_class->ipf_dump_next
+            ? dpif->dpif_class->ipf_dump_next(dpif, dump_ctx, dump)
+            : EOPNOTSUPP);
+}
+
+int
+ct_dpif_ipf_dump_done(struct dpif *dpif, void *dump_ctx)
+{
+    return (dpif->dpif_class->ipf_dump_done
+            ? dpif->dpif_class->ipf_dump_done(dpif, dump_ctx)
+            : EOPNOTSUPP);
+}
+
 void
 ct_dpif_entry_uninit(struct ct_dpif_entry *entry)
 {
diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h
index 2286dfb..2ff7e26 100644
--- a/lib/ct-dpif.h
+++ b/lib/ct-dpif.h
@@ -17,6 +17,7 @@
 #ifndef CT_DPIF_H
 #define CT_DPIF_H
 
+#include "ipf.h"
 #include "openvswitch/types.h"
 #include "packets.h"
 
@@ -203,6 +204,15 @@ int ct_dpif_get_nconns(struct dpif *dpif, uint32_t *nconns);
 int ct_dpif_ipf_set_enabled(struct dpif *, bool v6, bool enable);
 int ct_dpif_ipf_set_min_frag(struct dpif *, bool, uint32_t);
 int ct_dpif_ipf_set_max_nfrags(struct dpif *, uint32_t);
+int ct_dpif_ipf_get_status(struct dpif *dpif, bool *, unsigned int *,
+                           unsigned int *, unsigned int *, unsigned int *,
+                           unsigned int *, unsigned int *, unsigned int *,
+                           unsigned int *, bool *, unsigned int *,
+                           unsigned int *, unsigned int *, unsigned int *,
+                           unsigned int *, unsigned int *);
+int ct_dpif_ipf_dump_start(struct dpif *dpif, struct ipf_dump_ctx **);
+int ct_dpif_ipf_dump_next(struct dpif *dpif, void *, char **);
+int ct_dpif_ipf_dump_done(struct dpif *dpif, void *);
 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 ab0f60b..2b2a74a 100644
--- a/lib/dpctl.c
+++ b/lib/dpctl.c
@@ -1792,6 +1792,111 @@ dpctl_ipf_set_max_nfrags(int argc, const char *argv[],
     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, 3, &dpif);
+    if (!error) {
+        bool ipf_v4_enabled;
+        unsigned int min_v4_frag_size;
+        unsigned int nfrag_max;
+        unsigned int nfrag;
+        unsigned int n4frag_accepted;
+        unsigned int n4frag_completed_sent;
+        unsigned int n4frag_expired_sent;
+        unsigned int n4frag_too_small;
+        unsigned int n4frag_overlap;
+        unsigned int min_v6_frag_size;
+        bool ipf_v6_enabled;
+        unsigned int n6frag_accepted;
+        unsigned int n6frag_completed_sent;
+        unsigned int n6frag_expired_sent;
+        unsigned int n6frag_too_small;
+        unsigned int n6frag_overlap;
+        error = ct_dpif_ipf_get_status(dpif, &ipf_v4_enabled,
+            &min_v4_frag_size, &nfrag_max, &nfrag, &n4frag_accepted,
+            &n4frag_completed_sent, &n4frag_expired_sent, &n4frag_too_small,
+            &n4frag_overlap, &ipf_v6_enabled, &min_v6_frag_size,
+            &n6frag_accepted, &n6frag_completed_sent, &n6frag_expired_sent,
+            &n6frag_too_small, &n6frag_overlap);
+
+        if (!error) {
+            dpctl_print(dpctl_p, "        Fragmentation Module Status\n");
+            dpctl_print(dpctl_p, "        ---------------------------\n");
+            dpctl_print(dpctl_p, "        v4 enabled: %u\n", ipf_v4_enabled);
+            dpctl_print(dpctl_p, "        v6 enabled: %u\n", ipf_v6_enabled);
+            dpctl_print(dpctl_p, "        max num frags (v4/v6): %u\n",
+                        nfrag_max);
+            dpctl_print(dpctl_p, "        num frag: %u\n", nfrag);
+            dpctl_print(dpctl_p, "        min v4 frag size: %u\n",
+                        min_v4_frag_size);
+            dpctl_print(dpctl_p, "        v4 frags accepted: %u\n",
+                        n4frag_accepted);
+            dpctl_print(dpctl_p, "        v4 frags completed: %u\n",
+                        n4frag_completed_sent);
+            dpctl_print(dpctl_p, "        v4 frags expired: %u\n",
+                        n4frag_expired_sent);
+            dpctl_print(dpctl_p, "        v4 frags too small: %u\n",
+                        n4frag_too_small);
+            dpctl_print(dpctl_p, "        v4 frags overlapped: %u\n",
+                        n4frag_overlap);
+            dpctl_print(dpctl_p, "        min v6 frag size: %u\n",
+                        min_v6_frag_size);
+            dpctl_print(dpctl_p, "        v6 frags accepted: %u\n",
+                        n6frag_accepted);
+            dpctl_print(dpctl_p, "        v6 frags completed: %u\n",
+                        n6frag_completed_sent);
+            dpctl_print(dpctl_p, "        v6 frags expired: %u\n",
+                        n6frag_expired_sent);
+            dpctl_print(dpctl_p, "        v6 frags too small: %u\n",
+                        n6frag_too_small);
+            dpctl_print(dpctl_p, "        v6 frags overlapped: %u\n",
+                        n6frag_overlap);
+        } else {
+            dpctl_error(dpctl_p, error,
+                        "ipf status could not be retrieved");
+            return error;
+        }
+
+        if (argc > 0 && (!strncmp(argv[argc - 1], "-m", 2)
+            || !strncmp(argv[argc - 1], "--more", 6))) {
+            dpctl_dump_ipf(dpif, dpctl_p);
+        }
+
+        dpif_close(dpif);
+    }
+
+    return error;
+}
+
 /* Undocumented commands for unit testing. */
 
 static int
@@ -2099,6 +2204,8 @@ static const struct dpctl_command all_commands[] = {
        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] [-m | --more]", 0, 2, 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 },
 
diff --git a/lib/dpctl.man b/lib/dpctl.man
index c6c4a87..fb66b58 100644
--- a/lib/dpctl.man
+++ b/lib/dpctl.man
@@ -304,3 +304,9 @@ connection tracker.  The default value is 1000 and the clamped maximum
 is 5000.  Note that packet buffers can be held by the fragmentation
 module while fragments are incomplete, but will timeout after 15 seconds.
 Memory pool sizing should be set accordingly when fragmentation is enabled.
+.
+.TP
+.DO "[\fB\-m\fR | \fB\-\-more\fR]" "\*(DX\fBipf\-get\-status\fR [\fIdp\fR]"
+Gets the configuration settings and fragment counters associated with the
+fragmentation handling of the userspace datapath connection tracker.  With
+\fB\-m\fR or \fB\-\-more\fR, also dumps the ipf lists.
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 76bc1d9..db551ea 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -6553,6 +6553,60 @@ dpif_netdev_ipf_set_max_nfrags(struct dpif *dpif OVS_UNUSED,
     return ipf_set_max_nfrags(max_frags);
 }
 
+static int
+dpif_netdev_ipf_get_status(struct dpif *dpif OVS_UNUSED,
+    bool *ipf_v4_enabled, unsigned int *min_v4_frag_size,
+    unsigned int *nfrag_max, unsigned int *nfrag,
+    unsigned int *n4frag_accepted, unsigned int *n4frag_completed_sent,
+    unsigned int *n4frag_expired_sent, unsigned int *n4frag_too_small,
+    unsigned int *n4frag_overlap, bool *ipf_v6_enabled,
+    unsigned int *min_v6_frag_size, unsigned int *n6frag_accepted,
+    unsigned int *n6frag_completed_sent, unsigned int *n6frag_expired_sent,
+    unsigned int *n6frag_too_small, unsigned int *n6frag_overlap)
+{
+    struct ipf_status ipf_status;
+    ipf_get_status(&ipf_status);
+    *ipf_v4_enabled = ipf_status.ifp_v4_enabled;
+    *min_v4_frag_size = ipf_status.min_v4_frag_size;
+    *nfrag_max = ipf_status.nfrag_max;
+    *nfrag = ipf_status.nfrag;
+    *n4frag_accepted = ipf_status.n4frag_accepted;
+    *n4frag_completed_sent = ipf_status.n4frag_completed_sent;
+    *n4frag_expired_sent = ipf_status.n4frag_expired_sent;
+    *n4frag_too_small = ipf_status.n4frag_too_small;
+    *n4frag_overlap = ipf_status.n4frag_overlap;
+    *ipf_v6_enabled = ipf_status.ifp_v6_enabled;
+    *min_v6_frag_size = ipf_status.min_v6_frag_size;
+    *n6frag_accepted = ipf_status.n6frag_accepted;
+    *n6frag_completed_sent = ipf_status.n6frag_completed_sent;
+    *n6frag_expired_sent = ipf_status.n6frag_expired_sent;
+    *n6frag_too_small = ipf_status.n6frag_too_small;
+    *n6frag_overlap = ipf_status.n6frag_overlap;
+    return 0;
+}
+
+static int
+dpif_netdev_ipf_dump_start(struct dpif *dpif OVS_UNUSED,
+                           struct ipf_dump_ctx **ipf_dump_ctx)
+{
+    return ipf_dump_start(ipf_dump_ctx);
+}
+
+static int
+dpif_netdev_ipf_dump_next(struct dpif *dpif OVS_UNUSED,
+                          void *ipf_dump_ctx, char **dump)
+{
+    return ipf_dump_next(ipf_dump_ctx, dump);
+}
+
+static int
+dpif_netdev_ipf_dump_done(struct dpif *dpif OVS_UNUSED,
+                          void *ipf_dump_ctx)
+{
+    return ipf_dump_done(ipf_dump_ctx);
+
+}
+
 const struct dpif_class dpif_netdev_class = {
     "netdev",
     dpif_netdev_init,
@@ -6604,6 +6658,10 @@ const struct dpif_class dpif_netdev_class = {
     dpif_netdev_ipf_set_enabled,
     dpif_netdev_ipf_set_min_frag,
     dpif_netdev_ipf_set_max_nfrags,
+    dpif_netdev_ipf_get_status,
+    dpif_netdev_ipf_dump_start,
+    dpif_netdev_ipf_dump_next,
+    dpif_netdev_ipf_dump_done,
     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 80c54f5..42ac01d 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -3009,6 +3009,10 @@ const struct dpif_class dpif_netlink_class = {
     NULL,                       /* ipf_set_enabled */
     NULL,                       /* ipf_set_min_frag */
     NULL,                       /* ipf_set_max_nfrags */
+    NULL,                       /* ipf_get_status */
+    NULL,                       /* ipf_dump_start */
+    NULL,                       /* ipf_dump_next */
+    NULL,                       /* ipf_dump_done */
     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 10b39ca..2e0d596 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -24,6 +24,7 @@
 
 #include "openflow/openflow.h"
 #include "dpif.h"
+#include "ipf.h"
 #include "util.h"
 
 #ifdef  __cplusplus
@@ -450,6 +451,22 @@ struct dpif_class {
     int (*ipf_set_min_frag)(struct dpif *, bool v6, uint32_t min_frag);
     /* Set maximum number of fragments tracked. */
     int (*ipf_set_max_nfrags)(struct dpif *, uint32_t max_nfrags);
+    /* Get fragmentation configuration status and counters. */
+    int (*ipf_get_status)(struct dpif *, bool *ipf_v4_enabled,
+        unsigned int *min_v4_frag_size,
+        unsigned int *nfrag_max, unsigned int *nfrag,
+        unsigned int *n4frag_accepted, unsigned int *n4frag_completed_sent,
+        unsigned int *n4frag_expired_sent, unsigned int *n4frag_too_small,
+        unsigned int *n4frag_overlap, bool *ipf_v6_enabled,
+        unsigned int *min_v6_frag_size, unsigned int *n6frag_accepted,
+        unsigned int *n6frag_completed_sent,
+        unsigned int *n6frag_expired_sent, unsigned int *n6frag_too_small,
+        unsigned int *n6frag_overlap);
+    int (*ipf_dump_start)(struct dpif *, struct ipf_dump_ctx **ipf_dump_ctx);
+    /* Finds the next ipf list and creates a string representation of the
+     * state of an ipf list, to which 'dump' is pointed to. */
+    int (*ipf_dump_next)(struct dpif *, void *, char **dump);
+    int (*ipf_dump_done)(struct dpif *, void *ipf_dump_ctx);
 
     /* Meters */
     /* Queries 'dpif' for supported meter features.
diff --git a/lib/ipf.c b/lib/ipf.c
index ef3236a..9beaaa1 100644
--- a/lib/ipf.c
+++ b/lib/ipf.c
@@ -52,6 +52,10 @@ enum ipf_list_state {
     IPF_LIST_STATE_NUM,
 };
 
+static char *ipf_state_name[IPF_LIST_STATE_NUM] =
+    {"unused", "reassemble fail", "other frag", "first frag", "last frag",
+     "first/last frag", "complete"};
+
 enum ipf_list_type {
     IPF_FRAG_COMPLETED_LIST,
     IPF_FRAG_EXPIRY_LIST,
@@ -1304,3 +1308,106 @@ ipf_set_max_nfrags(uint32_t value)
     atomic_store_relaxed(&nfrag_max, value);
     return 0;
 }
+
+int
+ipf_get_status(struct ipf_status *ipf_status)
+{
+    atomic_read_relaxed(&ifp_v4_enabled, &ipf_status->ifp_v4_enabled);
+    atomic_read_relaxed(&min_v4_frag_size, &ipf_status->min_v4_frag_size);
+    atomic_read_relaxed(&nfrag_max, &ipf_status->nfrag_max);
+    ipf_status->nfrag = atomic_count_get(&nfrag);
+    ipf_status->n4frag_accepted = atomic_count_get(&n4frag_accepted);
+    ipf_status->n4frag_completed_sent =
+        atomic_count_get(&n4frag_completed_sent);
+    ipf_status->n4frag_expired_sent =
+        atomic_count_get(&n4frag_expired_sent);
+    ipf_status->n4frag_too_small = atomic_count_get(&n4frag_too_small);
+    ipf_status->n4frag_overlap = atomic_count_get(&n4frag_overlap);
+    atomic_read_relaxed(&ifp_v6_enabled, &ipf_status->ifp_v6_enabled);
+    atomic_read_relaxed(&min_v6_frag_size, &ipf_status->min_v6_frag_size);
+    ipf_status->n6frag_accepted = atomic_count_get(&n6frag_accepted);
+    ipf_status->n6frag_completed_sent =
+        atomic_count_get(&n6frag_completed_sent);
+    ipf_status->n6frag_expired_sent =
+        atomic_count_get(&n6frag_expired_sent);
+    ipf_status->n6frag_too_small = atomic_count_get(&n6frag_too_small);
+    ipf_status->n6frag_overlap = atomic_count_get(&n6frag_overlap);
+    return 0;
+}
+
+struct ipf_dump_ctx {
+    struct hmap_position bucket_pos;
+};
+
+/* Allocates an 'ipf_dump_ctx' to keep track of an hmap position. */
+int
+ipf_dump_start(struct ipf_dump_ctx **ipf_dump_ctx)
+{
+    *ipf_dump_ctx = xzalloc(sizeof **ipf_dump_ctx);
+    return 0;
+}
+
+/* Creates a string representation of the state of an 'ipf_list' and puts
+ * it in  'ds'. */
+static void
+ipf_dump_create(const struct ipf_list *ipf_list, struct ds *ds)
+{
+
+    ds_put_cstr(ds, "(");
+    if (ipf_list->key.dl_type == htons(ETH_TYPE_IP)) {
+        ds_put_format(ds, "src="IP_FMT",dst="IP_FMT",",
+                      IP_ARGS(ipf_list->key.src_addr.ipv4_aligned),
+                      IP_ARGS(ipf_list->key.dst_addr.ipv4_aligned));
+    } else {
+        ds_put_cstr(ds, "src=");
+        ipv6_format_addr(&ipf_list->key.src_addr.ipv6_aligned, ds);
+        ds_put_cstr(ds, ",dst=");
+        ipv6_format_addr(&ipf_list->key.dst_addr.ipv6_aligned, ds);
+        ds_put_cstr(ds, ",");
+    }
+
+    ds_put_format(ds, "recirc_id=%u,ip_id=%u,dl_type=0x%x,zone=%u,nw_proto=%u",
+                  ipf_list->key.recirc_id, ntohl(ipf_list->key.ip_id),
+                  ntohs(ipf_list->key.dl_type), ipf_list->key.zone,
+                  ipf_list->key.nw_proto);
+
+    ds_put_format(ds, ",num_fragments=%u,state=%s",
+                  ipf_list->last_inuse_idx + 1,
+                  ipf_state_name[ipf_list->state]);
+
+    ds_put_cstr(ds, ")");
+}
+
+/* Finds the next ipf list starting from 'ipf_dump_ctx->bucket_pos' and uses
+ * ipf_dump_create() to create a string representation of the state of an
+ * ipf list, to which 'dump' is pointed to. */
+int
+ipf_dump_next(struct ipf_dump_ctx *ipf_dump_ctx, char **dump)
+{
+    ipf_lock_lock(&ipf_lock);
+
+    struct hmap_node *node = hmap_at_position(&frag_lists,
+                                              &ipf_dump_ctx->bucket_pos);
+    if (!node) {
+        ipf_lock_unlock(&ipf_lock);
+        return EOF;
+    } else {
+        struct ipf_list *ipf_list_;
+        INIT_CONTAINER(ipf_list_, node, node);
+        struct ipf_list ipf_list = *ipf_list_;
+        ipf_lock_unlock(&ipf_lock);
+        struct ds ds = DS_EMPTY_INITIALIZER;
+        ipf_dump_create(&ipf_list, &ds);
+        *dump = xstrdup(ds.string);
+        ds_destroy(&ds);
+        return 0;
+    }
+}
+
+/* Frees an ipf_dump_ctx allocated by ipf_dump_start. */
+int
+ipf_dump_done(struct ipf_dump_ctx *ipf_dump_ctx)
+{
+    free(ipf_dump_ctx);
+    return 0;
+}
diff --git a/lib/ipf.h b/lib/ipf.h
index 4289e5e..36a182a 100644
--- a/lib/ipf.h
+++ b/lib/ipf.h
@@ -63,4 +63,14 @@ int ipf_set_min_frag(bool v6, uint32_t value);
 
 int ipf_set_max_nfrags(uint32_t value);
 
+int ipf_get_status(struct ipf_status *ipf_status);
+
+struct ipf_dump_ctx;
+
+int ipf_dump_start(struct ipf_dump_ctx **ipf_dump_ctx);
+
+int ipf_dump_next(struct ipf_dump_ctx *ipf_dump_ctx, char **dump);
+
+int ipf_dump_done(struct ipf_dump_ctx *ipf_dump_ctx);
+
 #endif /* ipf.h */
diff --git a/tests/system-kmod-macros.at b/tests/system-kmod-macros.at
index f1bf27a..736a643 100644
--- a/tests/system-kmod-macros.at
+++ b/tests/system-kmod-macros.at
@@ -138,3 +138,27 @@ m4_define([DPCTL_SET_MIN_FRAG_SIZE],
 [
 
 ])
+
+# DPCTL_MODIFY_FRAGMENTATION()
+#
+# The kernel does not support this command.
+m4_define([DPCTL_MODIFY_FRAGMENTATION],
+[
+
+])
+
+# DPCTL_CHECK_FRAGMENTATION_PASS()
+#
+# The kernel does not support this command.
+m4_define([DPCTL_CHECK_FRAGMENTATION_PASS],
+[
+
+])
+
+# DPCTL_CHECK_FRAGMENTATION_FAIL()
+#
+# The kernel does not support this command.
+m4_define([DPCTL_CHECK_FRAGMENTATION_FAIL],
+[
+
+])
diff --git a/tests/system-traffic.at b/tests/system-traffic.at
index 3f44904..f727825 100644
--- a/tests/system-traffic.at
+++ b/tests/system-traffic.at
@@ -1923,6 +1923,9 @@ priority=100,in_port=2,ct_state=+trk+est-new,icmp,action=1
 
 AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
 
+dnl Modify userspace conntrack fragmentation handling.
+DPCTL_MODIFY_FRAGMENTATION()
+
 dnl Ipv4 fragmentation connectivity check.
 NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl
 3 packets transmitted, 3 received, 0% packet loss, time 0ms
@@ -1933,6 +1936,9 @@ NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -w 2 10.1.1.2 | FORMAT_PING
 3 packets transmitted, 3 received, 0% packet loss, time 0ms
 ])
 
+dnl Check userspace conntrack fragmentation counters.
+DPCTL_CHECK_FRAGMENTATION_PASS()
+
 OVS_TRAFFIC_VSWITCHD_STOP
 AT_CLEANUP
 
@@ -1958,11 +1964,17 @@ priority=100,in_port=2,ct_state=+trk+est-new,icmp,action=1
 
 AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
 
+dnl Modify userspace conntrack fragmentation handling.
+DPCTL_MODIFY_FRAGMENTATION()
+
 dnl Ipv4 fragmentation connectivity check.
 NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 1 -i 0.3 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl
 7 packets transmitted, 0 received, 100% packet loss, time 0ms
 ])
 
+dnl Check userspace conntrack fragmentation counters.
+DPCTL_CHECK_FRAGMENTATION_FAIL()
+
 OVS_TRAFFIC_VSWITCHD_STOP
 AT_CLEANUP
 
@@ -1988,6 +2000,9 @@ priority=100,in_port=2,ct_state=+trk+est-new,icmp,action=1
 
 AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
 
+dnl Modify userspace conntrack fragmentation handling.
+DPCTL_MODIFY_FRAGMENTATION()
+
 dnl Ipv4 fragmentation connectivity check.
 NS_CHECK_EXEC([at_ns0], [ping -s 1600 -q -c 3 -i 0.3 -w 2 10.2.2.2 | FORMAT_PING], [0], [dnl
 3 packets transmitted, 3 received, 0% packet loss, time 0ms
@@ -1998,6 +2013,9 @@ NS_CHECK_EXEC([at_ns0], [ping -s 3200 -q -c 3 -i 0.3 -w 2 10.2.2.2 | FORMAT_PING
 3 packets transmitted, 3 received, 0% packet loss, time 0ms
 ])
 
+dnl Check userspace conntrack fragmentation counters.
+DPCTL_CHECK_FRAGMENTATION_PASS()
+
 OVS_TRAFFIC_VSWITCHD_STOP
 AT_CLEANUP
 
diff --git a/tests/system-userspace-macros.at b/tests/system-userspace-macros.at
index 6986bcb..fcae3cc 100644
--- a/tests/system-userspace-macros.at
+++ b/tests/system-userspace-macros.at
@@ -132,3 +132,112 @@ AT_CHECK([ovs-appctl dpctl/ipf-set-min-frag v6 400], [], [dnl
 setting minimum fragment size successful
 ])
 ])
+
+# DPCTL_MODIFY_FRAGMENTATION()
+#
+# The userspace datapath supports this command.
+m4_define([DPCTL_MODIFY_FRAGMENTATION],
+[
+AT_CHECK([ovs-appctl dpctl/ipf-set-min-frag v4 1000], [], [dnl
+setting minimum fragment size successful
+])
+AT_CHECK([ovs-appctl dpctl/ipf-set-max-nfrags 500], [], [dnl
+setting maximum fragments successful
+])
+AT_CHECK([ovs-appctl dpctl/ipf-get-status], [], [dnl
+        Fragmentation Module Status
+        ---------------------------
+        v4 enabled: 1
+        v6 enabled: 1
+        max num frags (v4/v6): 500
+        num frag: 0
+        min v4 frag size: 1000
+        v4 frags accepted: 0
+        v4 frags completed: 0
+        v4 frags expired: 0
+        v4 frags too small: 0
+        v4 frags overlapped: 0
+        min v6 frag size: 1280
+        v6 frags accepted: 0
+        v6 frags completed: 0
+        v6 frags expired: 0
+        v6 frags too small: 0
+        v6 frags overlapped: 0
+])
+])
+
+# DPCTL_CHECK_FRAGMENTATION_PASS()
+#
+# Used to check fragmentation counters for some fragmentation tests using
+# the userspace datapath.
+m4_define([DPCTL_CHECK_FRAGMENTATION_PASS],
+[
+AT_CHECK([ovs-appctl dpctl/ipf-get-status --more], [], [dnl
+        Fragmentation Module Status
+        ---------------------------
+        v4 enabled: 1
+        v6 enabled: 1
+        max num frags (v4/v6): 500
+        num frag: 0
+        min v4 frag size: 1000
+        v4 frags accepted: 30
+        v4 frags completed: 30
+        v4 frags expired: 0
+        v4 frags too small: 0
+        v4 frags overlapped: 0
+        min v6 frag size: 1280
+        v6 frags accepted: 0
+        v6 frags completed: 0
+        v6 frags expired: 0
+        v6 frags too small: 0
+        v6 frags overlapped: 0
+
+        Fragment Lists:
+
+])
+])
+
+# FORMAT_FRAG_LIST([])
+#
+# Strip content from the piped input which can differ from test to test; recirc_id
+# and ip_id fields in an ipf_list vary from test to test and hence are cleared.
+m4_define([FORMAT_FRAG_LIST],
+    [[sed -e 's/ip_id=[0-9]*/ip_id=<cleared>/g' -e 's/recirc_id=[0-9]*/recirc_id=<cleared>/g']])
+
+# DPCTL_CHECK_FRAGMENTATION_FAIL()
+#
+# Used to check fragmentation counters for some fragmentation tests using
+# the userspace datapath, when failure to transmit fragments is expected.
+m4_define([DPCTL_CHECK_FRAGMENTATION_FAIL],
+[
+AT_CHECK([ovs-appctl dpctl/ipf-get-status -m | FORMAT_FRAG_LIST()], [], [dnl
+        Fragmentation Module Status
+        ---------------------------
+        v4 enabled: 1
+        v6 enabled: 1
+        max num frags (v4/v6): 500
+        num frag: 7
+        min v4 frag size: 1000
+        v4 frags accepted: 7
+        v4 frags completed: 0
+        v4 frags expired: 0
+        v4 frags too small: 0
+        v4 frags overlapped: 0
+        min v6 frag size: 1280
+        v6 frags accepted: 0
+        v6 frags completed: 0
+        v6 frags expired: 0
+        v6 frags too small: 0
+        v6 frags overlapped: 0
+
+        Fragment Lists:
+
+(src=10.1.1.1,dst=10.1.1.2,recirc_id=<cleared>,ip_id=<cleared>,dl_type=0x800,zone=9,nw_proto=1,num_fragments=1,state=first frag)
+(src=10.1.1.1,dst=10.1.1.2,recirc_id=<cleared>,ip_id=<cleared>,dl_type=0x800,zone=9,nw_proto=1,num_fragments=1,state=first frag)
+(src=10.1.1.1,dst=10.1.1.2,recirc_id=<cleared>,ip_id=<cleared>,dl_type=0x800,zone=9,nw_proto=1,num_fragments=1,state=first frag)
+(src=10.1.1.1,dst=10.1.1.2,recirc_id=<cleared>,ip_id=<cleared>,dl_type=0x800,zone=9,nw_proto=1,num_fragments=1,state=first frag)
+(src=10.1.1.1,dst=10.1.1.2,recirc_id=<cleared>,ip_id=<cleared>,dl_type=0x800,zone=9,nw_proto=1,num_fragments=1,state=first frag)
+(src=10.1.1.1,dst=10.1.1.2,recirc_id=<cleared>,ip_id=<cleared>,dl_type=0x800,zone=9,nw_proto=1,num_fragments=1,state=first frag)
+(src=10.1.1.1,dst=10.1.1.2,recirc_id=<cleared>,ip_id=<cleared>,dl_type=0x800,zone=9,nw_proto=1,num_fragments=1,state=first frag)
+])
+])
-- 
1.9.1



More information about the dev mailing list