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 <[email protected]> --- NEWS | 2 + lib/ct-dpif.c | 34 +++++++- lib/ct-dpif.h | 9 +- lib/dpctl.c | 98 +++++++++++++++++++++- lib/dpctl.man | 7 ++ lib/dpif-netdev.c | 38 ++++++++- lib/dpif-netlink.c | 6 +- lib/dpif-provider.h | 41 ++++++++- lib/ipf.c | 114 +++++++++++++++++++++++++ lib/ipf.h | 24 ++++++ tests/system-kmod-macros.at | 44 +++++++++- tests/system-traffic.at | 41 ++++++--- tests/system-userspace-macros.at | 175 ++++++++++++++++++++++++++++++++++++--- 13 files changed, 601 insertions(+), 32 deletions(-) diff --git a/NEWS b/NEWS index a64e0a5..3f2b72f 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,8 @@ Post-v2.10.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. - 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 aa34feb..b2c9b43 100644 --- a/lib/ct-dpif.c +++ b/lib/ct-dpif.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Nicira, Inc. + * Copyright (c) 2015, 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. @@ -218,6 +218,38 @@ ct_dpif_ipf_set_max_nfrags(struct dpif *dpif, uint32_t max_frags) : EOPNOTSUPP); } +int ct_dpif_ipf_get_status(struct dpif *dpif, + struct dpif_ipf_status *dpif_ipf_status) +{ + return (dpif->dpif_class->ipf_get_status + ? dpif->dpif_class->ipf_get_status(dpif, dpif_ipf_status) + : 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 d104e8a..0151cfe 100644 --- a/lib/ct-dpif.h +++ b/lib/ct-dpif.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Nicira, Inc. + * Copyright (c) 2015, 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. @@ -186,6 +186,8 @@ enum { }; struct dpif; +struct dpif_ipf_status; +struct ipf_dump_ctx; struct ct_dpif_dump_state { struct dpif *dpif; @@ -215,6 +217,11 @@ 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); int ct_dpif_ipf_set_max_nfrags(struct dpif *, uint32_t max_frags); +int ct_dpif_ipf_get_status(struct dpif *dpif, + struct dpif_ipf_status *dpif_ipf_status); +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 e020234..f5a09b7 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" @@ -2028,6 +2029,99 @@ 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, 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 @@ -2339,6 +2433,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]", 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 }, diff --git a/lib/dpctl.man b/lib/dpctl.man index 43eb45f..16c6477 100644 --- a/lib/dpctl.man +++ b/lib/dpctl.man @@ -249,6 +249,13 @@ after 15 seconds. Memory pool sizing should be set accordingly when fragmentation is enabled. Only supported for userspace datapath. . .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 IP fragment lists. +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 221ce18..6e043d8 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2016, 2017 Nicira, Inc. + * Copyright (c) 2009-2014, 2016-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. @@ -6944,6 +6944,38 @@ dpif_netdev_ipf_set_max_nfrags(struct dpif *dpif OVS_UNUSED, return ipf_set_max_nfrags(max_frags); } +/* Adjust this function if 'dpif_ipf_status' and 'ipf_status' were to + * diverge. */ +static int +dpif_netdev_ipf_get_status(struct dpif *dpif OVS_UNUSED, + struct dpif_ipf_status *dpif_ipf_status) +{ + ipf_get_status((struct ipf_status *) dpif_ipf_status); + 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, @@ -6998,6 +7030,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 b08eea1..4edf4ab 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.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. @@ -3432,6 +3432,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 7cc7804..b2a4dff 100644 --- a/lib/dpif-provider.h +++ b/lib/dpif-provider.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. + * Copyright (c) 2009-2014, 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. @@ -42,6 +42,9 @@ struct dpif { long long int current_ms; }; +struct dpif_ipf_status; +struct ipf_dump_ctx; + void dpif_init(struct dpif *, const struct dpif_class *, const char *name, uint8_t netflow_engine_type, uint8_t netflow_engine_id); void dpif_uninit(struct dpif *dpif, bool close); @@ -78,6 +81,27 @@ struct ct_dpif_dump_state; struct ct_dpif_entry; struct ct_dpif_tuple; +/* 'dpif_ipf_proto_status' and 'dpif_ipf_status' are presently in + * sync with 'ipf_proto_status' and 'ipf_status', but more + * generally represent a superset of present and future support. */ +struct dpif_ipf_proto_status { + uint64_t nfrag_accepted; + uint64_t nfrag_completed_sent; + uint64_t nfrag_expired_sent; + uint64_t nfrag_too_small; + uint64_t nfrag_overlap; + uint64_t nfrag_purged; + unsigned int min_frag_size; + bool enabled; +}; + +struct dpif_ipf_status { + struct dpif_ipf_proto_status v4; + struct dpif_ipf_proto_status v6; + unsigned int nfrag; + unsigned int nfrag_max; +}; + /* Datapath interface class structure, to be defined by each implementation of * a datapath interface. * @@ -480,6 +504,21 @@ struct dpif_class { /* 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 *, + struct dpif_ipf_status *dpif_ipf_status); + + /* The following 3 apis find and print ipf lists by creating a string + * representation of the state of an ipf list, to which 'dump' is pointed + * to. 'ipf_dump_start()' allocates memory for 'ipf_dump_ctx'. + * 'ipf_dump_next()' finds the next ipf list and copies it's + * characteristics to a string, which is freed by the caller. + * 'ipf_dump_done()' frees the 'ipf_dump_ctx' that was allocated in + * 'ipf_dump_start'. */ + int (*ipf_dump_start)(struct dpif *, struct ipf_dump_ctx **ipf_dump_ctx); + int (*ipf_dump_next)(struct dpif *, void *ipf_dump_ctx, 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 b3f5045..631e7bc 100644 --- a/lib/ipf.c +++ b/lib/ipf.c @@ -54,6 +54,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, @@ -1401,3 +1405,113 @@ ipf_set_max_nfrags(uint32_t value) atomic_store_relaxed(&nfrag_max, value); return 0; } + +int +ipf_get_status(struct ipf_status *ipf_status) +{ + ipf_status->nfrag = atomic_count_get(&nfrag); + atomic_read_relaxed(&nfrag_max, &ipf_status->nfrag_max); + + atomic_read_relaxed(&ifp_v4_enabled, &ipf_status->v4.enabled); + atomic_read_relaxed(&min_v4_frag_size, &ipf_status->v4.min_frag_size); + atomic_read_relaxed(&n4frag_accepted, &ipf_status->v4.nfrag_accepted); + atomic_read_relaxed(&n4frag_completed_sent, + &ipf_status->v4.nfrag_completed_sent); + atomic_read_relaxed(&n4frag_expired_sent, + &ipf_status->v4.nfrag_expired_sent); + atomic_read_relaxed(&n4frag_too_small, &ipf_status->v4.nfrag_too_small); + atomic_read_relaxed(&n4frag_overlap, &ipf_status->v4.nfrag_overlap); + atomic_read_relaxed(&n4frag_purged, &ipf_status->v4.nfrag_purged); + + atomic_read_relaxed(&ifp_v6_enabled, &ipf_status->v6.enabled); + atomic_read_relaxed(&min_v6_frag_size, &ipf_status->v6.min_frag_size); + atomic_read_relaxed(&n6frag_accepted, &ipf_status->v6.nfrag_accepted); + atomic_read_relaxed(&n6frag_completed_sent, + &ipf_status->v6.nfrag_completed_sent); + atomic_read_relaxed(&n6frag_expired_sent, + &ipf_status->v6.nfrag_expired_sent); + atomic_read_relaxed(&n6frag_too_small, &ipf_status->v6.nfrag_too_small); + atomic_read_relaxed(&n6frag_overlap, &ipf_status->v6.nfrag_overlap); + atomic_read_relaxed(&n4frag_overlap, &ipf_status->v4.nfrag_overlap); + atomic_read_relaxed(&n6frag_purged, &ipf_status->v6.nfrag_purged); + return 0; +} + +struct ipf_dump_ctx { + struct hmap_position bucket_pos; +}; + +/* Allocates an 'ipf_dump_ctx' to keep track of an hmap position. The + * caller must call ipf_dump_done() when dumping is finished. */ +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. Returns EOF when there are no + * more ipf lists. */ +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 '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 6cf4d1e..fd0a19c 100644 --- a/lib/ipf.h +++ b/lib/ipf.h @@ -20,6 +20,24 @@ #include "dp-packet.h" #include "openvswitch/types.h" +struct ipf_proto_status { + uint64_t nfrag_accepted; + uint64_t nfrag_completed_sent; + uint64_t nfrag_expired_sent; + uint64_t nfrag_too_small; + uint64_t nfrag_overlap; + uint64_t nfrag_purged; + unsigned int min_frag_size; + bool enabled; +}; + +struct ipf_status { + struct ipf_proto_status v4; + struct ipf_proto_status v6; + unsigned int nfrag; + unsigned int nfrag_max; +}; + void ipf_preprocess_conntrack(struct dp_packet_batch *pb, long long now, ovs_be16 dl_type, uint16_t zone, uint32_t hash_basis); @@ -32,5 +50,11 @@ void ipf_destroy(void); int ipf_set_enabled(bool v6, bool enable); 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 3fbead8..1057e34 100644 --- a/tests/system-kmod-macros.at +++ b/tests/system-kmod-macros.at @@ -85,10 +85,6 @@ m4_define([CHECK_CONNTRACK_ALG]) # needed. m4_define([CHECK_CONNTRACK_LOCAL_STACK]) -# CHECK_CONNTRACK_SMALL_FRAG() -# -m4_define([CHECK_CONNTRACK_SMALL_FRAG]) - # CHECK_CONNTRACK_FRAG_OVERLAP() # # The kernel does not support overlapping fragments checking. @@ -138,6 +134,46 @@ m4_define([CHECK_CT_DPIF_GET_NCONNS], AT_SKIP_IF([:]) ]) +# DPCTL_SET_MIN_FRAG_SIZE() +# +# The kernel does not support this command. +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_V6_FRAGMENTATION_PASS() +# +# The kernel does not support this command. +m4_define([DPCTL_CHECK_V6_FRAGMENTATION_PASS], +[ + +]) + +# DPCTL_CHECK_FRAGMENTATION_FAIL() +# +# The kernel does not support this command. +m4_define([DPCTL_CHECK_FRAGMENTATION_FAIL], +[ + +]) + # OVS_CHECK_KERNEL([minversion], [minsublevel], [maxversion], [maxsublevel]) # # Check if kernel version falls between minversion.minsublevel and diff --git a/tests/system-traffic.at b/tests/system-traffic.at index c4f6e47..7229aab 100644 --- a/tests/system-traffic.at +++ b/tests/system-traffic.at @@ -2365,6 +2365,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 @@ -2375,6 +2378,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 @@ -2400,11 +2406,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 @@ -2430,6 +2442,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 @@ -2440,6 +2455,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 @@ -2498,6 +2516,8 @@ AT_CLEANUP AT_SETUP([conntrack - IPv4 fragmentation incomplete reassembled packet]) CHECK_CONNTRACK() OVS_TRAFFIC_VSWITCHD_START() +DPCTL_SET_MIN_FRAG_SIZE() + ADD_NAMESPACES(at_ns0, at_ns1) @@ -2519,8 +2539,8 @@ AT_CLEANUP dnl Uses same first fragment as above 'incomplete reassembled packet' test. AT_SETUP([conntrack - IPv4 fragmentation with fragments specified]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() OVS_TRAFFIC_VSWITCHD_START() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2543,8 +2563,8 @@ AT_CLEANUP AT_SETUP([conntrack - IPv4 fragmentation out of order]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() OVS_TRAFFIC_VSWITCHD_START() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2567,9 +2587,9 @@ AT_CLEANUP AT_SETUP([conntrack - IPv4 fragmentation overlapping fragments by 1 octet]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() CHECK_CONNTRACK_FRAG_OVERLAP() OVS_TRAFFIC_VSWITCHD_START() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2591,9 +2611,9 @@ AT_CLEANUP AT_SETUP([conntrack - IPv4 fragmentation overlapping fragments by 1 octet out of order]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() CHECK_CONNTRACK_FRAG_OVERLAP() OVS_TRAFFIC_VSWITCHD_START() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2790,6 +2810,7 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation incomplete reassembled packet]) CHECK_CONNTRACK() OVS_TRAFFIC_VSWITCHD_START() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2810,8 +2831,8 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation with fragments specified]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() OVS_TRAFFIC_VSWITCHD_START() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2834,8 +2855,8 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation out of order]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() OVS_TRAFFIC_VSWITCHD_START() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2858,9 +2879,9 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation, multiple extension headers]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() CHECK_CONNTRACK_FRAG_IPV6_MULT_EXTEN() OVS_TRAFFIC_VSWITCHD_START() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2884,9 +2905,9 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation, multiple extension headers + out of order]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() CHECK_CONNTRACK_FRAG_IPV6_MULT_EXTEN() OVS_TRAFFIC_VSWITCHD_START() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2910,9 +2931,9 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation, multiple extension headers 2]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() CHECK_CONNTRACK_FRAG_IPV6_MULT_EXTEN() OVS_TRAFFIC_VSWITCHD_START() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) @@ -2936,9 +2957,9 @@ AT_CLEANUP AT_SETUP([conntrack - IPv6 fragmentation, multiple extension headers 2 + out of order]) CHECK_CONNTRACK() -CHECK_CONNTRACK_SMALL_FRAG() CHECK_CONNTRACK_FRAG_IPV6_MULT_EXTEN() OVS_TRAFFIC_VSWITCHD_START() +DPCTL_SET_MIN_FRAG_SIZE() ADD_NAMESPACES(at_ns0, at_ns1) diff --git a/tests/system-userspace-macros.at b/tests/system-userspace-macros.at index 219c046..4ea55ea 100644 --- a/tests/system-userspace-macros.at +++ b/tests/system-userspace-macros.at @@ -84,20 +84,10 @@ m4_define([CHECK_CONNTRACK_LOCAL_STACK], AT_SKIP_IF([:]) ]) -# CHECK_CONNTRACK_SMALL_FRAG() -# -m4_define([CHECK_CONNTRACK_SMALL_FRAG], -[ - AT_SKIP_IF([:]) -]) - # CHECK_CONNTRACK_FRAG_OVERLAP() # -# The userspace datapath does not support fragments yet. -m4_define([CHECK_CONNTRACK_FRAG_OVERLAP], -[ - AT_SKIP_IF([:]) -]) +# The userspace datapath supports fragment overlap check. +m4_define([CHECK_CONNTRACK_FRAG_OVERLAP]) # CHECK_CONNTRACK_FRAG_IPV6_MULT_EXTEN # @@ -132,6 +122,167 @@ m4_define([CHECK_CT_DPIF_SET_GET_MAXCONNS]) # userspace datapath does support this feature. m4_define([CHECK_CT_DPIF_GET_NCONNS]) +# DPCTL_SET_MIN_FRAG_SIZE() +# +# The userspace datapath supports this command. +m4_define([DPCTL_SET_MIN_FRAG_SIZE], +[ +AT_CHECK([ovs-appctl dpctl/ipf-set-min-frag v4 400], [], [dnl +setting minimum fragment size successful +]) +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 + v4 frags purged: 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 + v6 frags purged: 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 + v4 frags purged: 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 + v6 frags purged: 0 + + Fragment Lists: + +]) +]) + +# DPCTL_CHECK_V6_FRAGMENTATION_PASS() +# +# Used to check fragmentation counters for some fragmentation tests using +# the userspace datapath. +m4_define([DPCTL_CHECK_V6_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): 1000 + num frag: 0 + min v4 frag size: 1200 + v4 frags accepted: 0 + v4 frags completed: 0 + v4 frags expired: 0 + v4 frags too small: 0 + v4 frags overlapped: 0 + v4 frags purged: 0 + min v6 frag size: 1280 + v6 frags accepted: 30 + v6 frags completed: 30 + v6 frags expired: 0 + v6 frags too small: 0 + v6 frags overlapped: 0 + v6 frags purged: 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 + v4 frags purged: 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 + v6 frags purged: 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) +]) +]) + # OVS_CHECK_KERNEL([minversion], [maxversion], [minsublevel], [maxsublevel]) # # The userspace skips all tests that check kernel version. -- 1.9.1 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
