Skip to content

Commit

Permalink
dpctl: Implement dpctl commands for conntrack per zone limit
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Justin Pettit <[email protected]>
  • Loading branch information
YiHungWei authored and justinpettit committed Aug 17, 2018
1 parent 7cfb862 commit 4eeec03
Show file tree
Hide file tree
Showing 6 changed files with 271 additions and 3 deletions.
1 change: 1 addition & 0 deletions Documentation/faq/releases.rst
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ Q: Are all features available with all datapaths?
NIC Bonding YES YES YES YES
Multiple VTEPs YES YES YES YES
Meters 4.15 YES YES NO
Conntrack zone limit 4.18 YES NO NO
===================== ============== ============== ========= =======

Do note, however:
Expand Down
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ v2.10.0 - xx xxx xxxx
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.
- 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:
* OFPT_ROLE_STATUS is now available in OpenFlow 1.3.
* OpenFlow 1.5 extensible statistics (OXS) now implemented.
Expand Down
67 changes: 67 additions & 0 deletions lib/ct-dpif.c
Original file line number Diff line number Diff line change
Expand Up @@ -619,3 +619,70 @@ ct_dpif_free_zone_limits(struct ovs_list *zone_limits)
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);
}
}
4 changes: 4 additions & 0 deletions lib/ct-dpif.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
uint32_t count);
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 */
169 changes: 169 additions & 0 deletions lib/dpctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1697,6 +1697,169 @@ dpctl_ct_get_nconns(int argc, const char *argv[],
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. */

static int
Expand Down Expand Up @@ -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-get-maxconns", "[dp]", 0, 1, dpctl_ct_get_maxconns, 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 },
{ "list-commands", "", 0, INT_MAX, dpctl_list_commands, DP_RO },

Expand Down
31 changes: 28 additions & 3 deletions lib/dpctl.man
Original file line number Diff line number Diff line change
Expand Up @@ -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]"
Deletes all flow entries from datapath \fIdp\fR's flow table.
.SS "CONNECTION TRACKING TABLE DEBUGGING COMMANDS"
The following commands are primarily useful for debugging the connection
tracking entries in the datapath.
.SS "CONNECTION TRACKING TABLE COMMANDS"
The following commands are useful for debugging and configuring
the connection tracking table in the datapath.
.
.PP
The \fIdp\fR argument to each of these commands is optional when
Expand Down Expand Up @@ -272,3 +272,28 @@ Only supported for userspace datapath.
\*(DX\fBct\-get\-nconns\fR [\fIdp\fR]
Prints the current number of connection tracker entries on \fIdp\fR.
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.

0 comments on commit 4eeec03

Please sign in to comment.