2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 09:58:01 +00:00

dpctl: Implement dpctl commands for conntrack per zone limit

This patch implments the following three commands on dpctl so that
users can use ovs-dpctl or ovs-appctl to set, delete, and get the
per zone limit.

For example,

$ ovs-appctl dpctl/ct-set-limits default=10 zone=0,limit=5 zone=1,limit=3
$ ovs-appctl dpct/ct-del-limits zone=0
$ ovs-appctl dpct/ct-get-limits zone=1,2,3

Signed-off-by: Yi-Hung Wei <yihung.wei@gmail.com>
Signed-off-by: Justin Pettit <jpettit@ovn.org>
This commit is contained in:
Yi-Hung Wei 2018-08-17 02:05:11 -07:00 committed by Justin Pettit
parent 7cfb862c3d
commit 4eeec031d4
6 changed files with 271 additions and 3 deletions

View File

@ -125,6 +125,7 @@ Q: Are all features available with all datapaths?
NIC Bonding YES YES YES YES NIC Bonding YES YES YES YES
Multiple VTEPs YES YES YES YES Multiple VTEPs YES YES YES YES
Meters 4.15 YES YES NO Meters 4.15 YES YES NO
Conntrack zone limit 4.18 YES NO NO
===================== ============== ============== ========= ======= ===================== ============== ============== ========= =======
Do note, however: Do note, however:

2
NEWS
View File

@ -23,6 +23,8 @@ v2.10.0 - xx xxx xxxx
default it always accepts names and in interactive use it displays them; default it always accepts names and in interactive use it displays them;
use --names or --no-names to override. See ovs-ofctl(8) for details. use --names or --no-names to override. See ovs-ofctl(8) for details.
- ovs-vsctl: New commands "add-bond-iface" and "del-bond-iface". - ovs-vsctl: New commands "add-bond-iface" and "del-bond-iface".
- ovs-dpctl:
* New commands "ct-set-limits", "ct-del-limits", and "ct-get-limits".
- OpenFlow: - OpenFlow:
* OFPT_ROLE_STATUS is now available in OpenFlow 1.3. * OFPT_ROLE_STATUS is now available in OpenFlow 1.3.
* OpenFlow 1.5 extensible statistics (OXS) now implemented. * OpenFlow 1.5 extensible statistics (OXS) now implemented.

View File

@ -619,3 +619,70 @@ ct_dpif_free_zone_limits(struct ovs_list *zone_limits)
free(cdzl); free(cdzl);
} }
} }
/* Parses a specification of a conntrack zone limit from 's' into '*pzone'
* and '*plimit'. Returns true on success. Otherwise, returns false and
* and puts the error message in 'ds'. */
bool
ct_dpif_parse_zone_limit_tuple(const char *s, uint16_t *pzone,
uint32_t *plimit, struct ds *ds)
{
char *pos, *key, *value, *copy, *err;
bool parsed_limit = false, parsed_zone = false;
pos = copy = xstrdup(s);
while (ofputil_parse_key_value(&pos, &key, &value)) {
if (!*value) {
ds_put_format(ds, "field %s missing value", key);
goto error;
}
if (!strcmp(key, "zone")) {
err = str_to_u16(value, key, pzone);
if (err) {
free(err);
goto error_with_msg;
}
parsed_zone = true;
} else if (!strcmp(key, "limit")) {
err = str_to_u32(value, plimit);
if (err) {
free(err);
goto error_with_msg;
}
parsed_limit = true;
} else {
ds_put_format(ds, "invalid zone limit field: %s", key);
goto error;
}
}
if (!parsed_zone || !parsed_limit) {
ds_put_format(ds, "failed to parse zone limit");
goto error;
}
free(copy);
return true;
error_with_msg:
ds_put_format(ds, "failed to parse field %s", key);
error:
free(copy);
return false;
}
void
ct_dpif_format_zone_limits(uint32_t default_limit,
const struct ovs_list *zone_limits, struct ds *ds)
{
struct ct_dpif_zone_limit *zone_limit;
ds_put_format(ds, "default limit=%"PRIu32, default_limit);
LIST_FOR_EACH (zone_limit, node, zone_limits) {
ds_put_format(ds, "\nzone=%"PRIu16, zone_limit->zone);
ds_put_format(ds, ",limit=%"PRIu32, zone_limit->limit);
ds_put_format(ds, ",count=%"PRIu32, zone_limit->count);
}
}

View File

@ -222,5 +222,9 @@ bool ct_dpif_parse_tuple(struct ct_dpif_tuple *, const char *s, struct ds *);
void ct_dpif_push_zone_limit(struct ovs_list *, uint16_t zone, uint32_t limit, void ct_dpif_push_zone_limit(struct ovs_list *, uint16_t zone, uint32_t limit,
uint32_t count); uint32_t count);
void ct_dpif_free_zone_limits(struct ovs_list *); void ct_dpif_free_zone_limits(struct ovs_list *);
bool ct_dpif_parse_zone_limit_tuple(const char *s, uint16_t *pzone,
uint32_t *plimit, struct ds *);
void ct_dpif_format_zone_limits(uint32_t default_limit,
const struct ovs_list *, struct ds *);
#endif /* CT_DPIF_H */ #endif /* CT_DPIF_H */

View File

@ -1697,6 +1697,169 @@ dpctl_ct_get_nconns(int argc, const char *argv[],
return error; return error;
} }
static int
dpctl_ct_set_limits(int argc, const char *argv[],
struct dpctl_params *dpctl_p)
{
struct dpif *dpif;
struct ds ds = DS_EMPTY_INITIALIZER;
int i = 1;
uint32_t default_limit, *p_default_limit = NULL;
struct ovs_list zone_limits = OVS_LIST_INITIALIZER(&zone_limits);
int error = opt_dpif_open(argc, argv, dpctl_p, INT_MAX, &dpif, &i);
if (error) {
return error;
}
/* Parse default limit */
if (!strncmp(argv[i], "default=", 8)) {
if (ovs_scan(argv[i], "default=%"SCNu32, &default_limit)) {
p_default_limit = &default_limit;
i++;
} else {
ds_put_cstr(&ds, "invalid default limit");
error = EINVAL;
goto error;
}
}
/* Parse ct zone limit tuples */
while (i < argc) {
uint16_t zone;
uint32_t limit;
if (!ct_dpif_parse_zone_limit_tuple(argv[i++], &zone, &limit, &ds)) {
error = EINVAL;
goto error;
}
ct_dpif_push_zone_limit(&zone_limits, zone, limit, 0);
}
error = ct_dpif_set_limits(dpif, p_default_limit, &zone_limits);
if (!error) {
ct_dpif_free_zone_limits(&zone_limits);
dpif_close(dpif);
return 0;
} else {
ds_put_cstr(&ds, "failed to set conntrack limit");
}
error:
dpctl_error(dpctl_p, error, "%s", ds_cstr(&ds));
ds_destroy(&ds);
ct_dpif_free_zone_limits(&zone_limits);
dpif_close(dpif);
return error;
}
static int
parse_ct_limit_zones(const char *argv, struct ovs_list *zone_limits,
struct ds *ds)
{
char *save_ptr = NULL, *argcopy, *next_zone;
uint16_t zone;
if (strncmp(argv, "zone=", 5)) {
ds_put_format(ds, "invalid argument %s", argv);
return EINVAL;
}
argcopy = xstrdup(argv + 5);
next_zone = strtok_r(argcopy, ",", &save_ptr);
do {
if (ovs_scan(next_zone, "%"SCNu16, &zone)) {
ct_dpif_push_zone_limit(zone_limits, zone, 0, 0);
} else {
ds_put_cstr(ds, "invalid zone");
free(argcopy);
return EINVAL;
}
} while ((next_zone = strtok_r(NULL, ",", &save_ptr)) != NULL);
free(argcopy);
return 0;
}
static int
dpctl_ct_del_limits(int argc, const char *argv[],
struct dpctl_params *dpctl_p)
{
struct dpif *dpif;
struct ds ds = DS_EMPTY_INITIALIZER;
int error, i = 1;
struct ovs_list zone_limits = OVS_LIST_INITIALIZER(&zone_limits);
error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif, &i);
if (error) {
return error;
}
error = parse_ct_limit_zones(argv[i], &zone_limits, &ds);
if (error) {
goto error;
}
error = ct_dpif_del_limits(dpif, &zone_limits);
if (!error) {
goto out;
} else {
ds_put_cstr(&ds, "failed to delete conntrack limit");
}
error:
dpctl_error(dpctl_p, error, "%s", ds_cstr(&ds));
ds_destroy(&ds);
out:
ct_dpif_free_zone_limits(&zone_limits);
dpif_close(dpif);
return error;
}
static int
dpctl_ct_get_limits(int argc, const char *argv[],
struct dpctl_params *dpctl_p)
{
struct dpif *dpif;
struct ds ds = DS_EMPTY_INITIALIZER;
uint32_t default_limit;
int i = 1;
struct ovs_list list_query = OVS_LIST_INITIALIZER(&list_query);
struct ovs_list list_reply = OVS_LIST_INITIALIZER(&list_reply);
int error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif, &i);
if (error) {
return error;
}
if (argc > i) {
error = parse_ct_limit_zones(argv[i], &list_query, &ds);
if (error) {
goto error;
}
}
error = ct_dpif_get_limits(dpif, &default_limit, &list_query,
&list_reply);
if (!error) {
ct_dpif_format_zone_limits(default_limit, &list_reply, &ds);
dpctl_print(dpctl_p, "%s\n", ds_cstr(&ds));
goto out;
} else {
ds_put_format(&ds, "failed to get conntrack limit %s",
ovs_strerror(error));
}
error:
dpctl_error(dpctl_p, error, "%s", ds_cstr(&ds));
out:
ds_destroy(&ds);
ct_dpif_free_zone_limits(&list_query);
ct_dpif_free_zone_limits(&list_reply);
dpif_close(dpif);
return error;
}
/* Undocumented commands for unit testing. */ /* Undocumented commands for unit testing. */
static int static int
@ -1996,6 +2159,12 @@ static const struct dpctl_command all_commands[] = {
{ "ct-set-maxconns", "[dp] maxconns", 1, 2, dpctl_ct_set_maxconns, DP_RW }, { "ct-set-maxconns", "[dp] maxconns", 1, 2, dpctl_ct_set_maxconns, DP_RW },
{ "ct-get-maxconns", "[dp]", 0, 1, dpctl_ct_get_maxconns, DP_RO }, { "ct-get-maxconns", "[dp]", 0, 1, dpctl_ct_get_maxconns, DP_RO },
{ "ct-get-nconns", "[dp]", 0, 1, dpctl_ct_get_nconns, DP_RO }, { "ct-get-nconns", "[dp]", 0, 1, dpctl_ct_get_nconns, DP_RO },
{ "ct-set-limits", "[dp] [default=L] [zone=N,limit=L]...", 1, INT_MAX,
dpctl_ct_set_limits, DP_RO },
{ "ct-del-limits", "[dp] zone=N1[,N2]...", 1, 2, dpctl_ct_del_limits,
DP_RO },
{ "ct-get-limits", "[dp] [zone=N1[,N2]...]", 0, 2, dpctl_ct_get_limits,
DP_RO },
{ "help", "", 0, INT_MAX, dpctl_help, DP_RO }, { "help", "", 0, INT_MAX, dpctl_help, DP_RO },
{ "list-commands", "", 0, INT_MAX, dpctl_list_commands, DP_RO }, { "list-commands", "", 0, INT_MAX, dpctl_list_commands, DP_RO },

View File

@ -196,9 +196,9 @@ Fetches the flow from \fIdp\fR's flow table with unique identifier \fIufid\fR.
. .
.IP "\*(DX\fBdel\-flows\fR [\fIdp\fR]" .IP "\*(DX\fBdel\-flows\fR [\fIdp\fR]"
Deletes all flow entries from datapath \fIdp\fR's flow table. Deletes all flow entries from datapath \fIdp\fR's flow table.
.SS "CONNECTION TRACKING TABLE DEBUGGING COMMANDS" .SS "CONNECTION TRACKING TABLE COMMANDS"
The following commands are primarily useful for debugging the connection The following commands are useful for debugging and configuring
tracking entries in the datapath. the connection tracking table in the datapath.
. .
.PP .PP
The \fIdp\fR argument to each of these commands is optional when The \fIdp\fR argument to each of these commands is optional when
@ -272,3 +272,28 @@ Only supported for userspace datapath.
\*(DX\fBct\-get\-nconns\fR [\fIdp\fR] \*(DX\fBct\-get\-nconns\fR [\fIdp\fR]
Prints the current number of connection tracker entries on \fIdp\fR. Prints the current number of connection tracker entries on \fIdp\fR.
Only supported for userspace datapath. Only supported for userspace datapath.
.
.TP
\*(DX\fBct\-set\-limits\fR [\fIdp\fR] [\fBdefault=\fIdefault_limit\fR] [\fBzone=\fIzone\fR,\fBlimit=\fIlimit\fR]...
Sets the maximum allowed number of connections in a connection tracking
zone. A specific \fIzone\fR may be set to \fIlimit\fR, and multiple zones
may be specified with a comma-separated list. If a per-zone limit for a
particular zone is not specified in the datapath, it defaults to the
default per-zone limit. A default zone may be specified with the
\fBdefault=\fIdefault_limit\fR argument. Initially, the default
per-zone limit is unlimited. An unlimited number of entries may be set
with \fB0\fR limit. Only supported for Linux kernel datapath.
.
.TP
\*(DX\fBct\-del\-limits\fR [\fIdp\fR] \fBzone=\fIzone[,zone]\fR...
Deletes the connection tracking limit for \fIzone\fR. Multiple zones may
be specified with a comma-separated list. Only supported for Linux
kernel datapath.
.
.TP
\*(DX\fBct\-get\-limits\fR [\fIdp\fR] [\fBzone=\fIzone\fR[\fB,\fIzone\fR]...]
Retrieves the maximum allowed number of connections and current
counts per-zone. If \fIzone\fR is given, only the specified zone(s) are
printed. If no zones are specified, all the zone limits and counts are
provided. The command always displays the default zone limit. Only
supported for Linux kernel datapath.