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:
parent
7cfb862c3d
commit
4eeec031d4
@ -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
2
NEWS
@ -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.
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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 */
|
||||||
|
169
lib/dpctl.c
169
lib/dpctl.c
@ -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 },
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user