mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 09:58:01 +00:00
dpctl: add CT Stats for Connections per protocol.
Adds CT stats to report number of connections grouped by protocol. By using utilities/ovs-appctl dpctl/ct-stats-show it can display something like: Connections Stats: Total: 1808 TCP: 1808 With the verbose options: utilities/ovs-appctl dpctl/ct-stats-show verbose it can display: Connections Stats: Total: 2671 TCP: 2671 Conn per TCP states: [ESTABLISHED]=1000 [CLOSING]=1 [TIME_WAIT]=1670 Signed-off-by: Antonio Fischetti <antonio.fischetti@intel.com> Signed-off-by: Bhanuprakash Bodireddy <bhanuprakash.bodireddy@intel.com> Co-authored-by: Bhanuprakash Bodireddy <bhanuprakash.bodireddy@intel.com> Signed-off-by: Ben Pfaff <blp@ovn.org>
This commit is contained in:
parent
1401f6deb6
commit
8a0d9d85b3
1
NEWS
1
NEWS
@ -5,6 +5,7 @@ Post-v2.7.0
|
|||||||
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-ofctl dump-flows" now accepts --no-stats to omit flow statistics.
|
* "ovs-ofctl dump-flows" now accepts --no-stats to omit flow statistics.
|
||||||
|
- New ovs-dpctl command "ct-stats-show" to show connection tracking stats.
|
||||||
- Tunnels:
|
- Tunnels:
|
||||||
* Added support to set packet mark for tunnel endpoint using
|
* Added support to set packet mark for tunnel endpoint using
|
||||||
`egress_pkt_mark` OVSDB option.
|
`egress_pkt_mark` OVSDB option.
|
||||||
|
@ -409,3 +409,17 @@ ct_dpif_format_helper(struct ds *ds, const char *title,
|
|||||||
ds_put_cstr(ds, helper->name);
|
ds_put_cstr(ds, helper->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
ct_dpif_coalesce_tcp_state(uint8_t state)
|
||||||
|
{
|
||||||
|
return coalesce_tcp_state(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ct_dpif_format_tcp_stat(struct ds * ds, int tcp_state, int conn_per_state)
|
||||||
|
{
|
||||||
|
ct_dpif_format_enum(ds, "\t [", tcp_state, ct_dpif_tcp_state_string);
|
||||||
|
ds_put_cstr(ds, "]");
|
||||||
|
ds_put_format(ds, "=%u", conn_per_state);
|
||||||
|
}
|
||||||
|
@ -70,7 +70,8 @@ struct ct_dpif_timestamp {
|
|||||||
CT_DPIF_TCP_STATE(CLOSING) \
|
CT_DPIF_TCP_STATE(CLOSING) \
|
||||||
CT_DPIF_TCP_STATE(LAST_ACK) \
|
CT_DPIF_TCP_STATE(LAST_ACK) \
|
||||||
CT_DPIF_TCP_STATE(FIN_WAIT_2) \
|
CT_DPIF_TCP_STATE(FIN_WAIT_2) \
|
||||||
CT_DPIF_TCP_STATE(TIME_WAIT)
|
CT_DPIF_TCP_STATE(TIME_WAIT) \
|
||||||
|
CT_DPIF_TCP_STATE(MAX_NUM)
|
||||||
|
|
||||||
enum ct_dpif_tcp_state {
|
enum ct_dpif_tcp_state {
|
||||||
#define CT_DPIF_TCP_STATE(STATE) CT_DPIF_TCPS_##STATE,
|
#define CT_DPIF_TCP_STATE(STATE) CT_DPIF_TCPS_##STATE,
|
||||||
@ -170,6 +171,19 @@ struct ct_dpif_entry {
|
|||||||
uint32_t mark;
|
uint32_t mark;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CT_STATS_UDP,
|
||||||
|
CT_STATS_TCP,
|
||||||
|
CT_STATS_SCTP,
|
||||||
|
CT_STATS_ICMP,
|
||||||
|
CT_STATS_ICMPV6,
|
||||||
|
CT_STATS_UDPLITE,
|
||||||
|
CT_STATS_DCCP,
|
||||||
|
CT_STATS_IGMP,
|
||||||
|
CT_STATS_OTHER,
|
||||||
|
CT_STATS_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
struct dpif;
|
struct dpif;
|
||||||
|
|
||||||
struct ct_dpif_dump_state {
|
struct ct_dpif_dump_state {
|
||||||
@ -185,5 +199,7 @@ void ct_dpif_entry_uninit(struct ct_dpif_entry *);
|
|||||||
void ct_dpif_format_entry(const struct ct_dpif_entry *, struct ds *,
|
void ct_dpif_format_entry(const struct ct_dpif_entry *, struct ds *,
|
||||||
bool verbose, bool print_stats);
|
bool verbose, bool print_stats);
|
||||||
void ct_dpif_format_tuple(struct ds *, const struct ct_dpif_tuple *);
|
void ct_dpif_format_tuple(struct ds *, const struct ct_dpif_tuple *);
|
||||||
|
uint8_t ct_dpif_coalesce_tcp_state(uint8_t state);
|
||||||
|
void ct_dpif_format_tcp_stat(struct ds *, int, int);
|
||||||
|
|
||||||
#endif /* CT_DPIF_H */
|
#endif /* CT_DPIF_H */
|
||||||
|
139
lib/dpctl.c
139
lib/dpctl.c
@ -1328,6 +1328,142 @@ dpctl_flush_conntrack(int argc, const char *argv[],
|
|||||||
dpif_close(dpif);
|
dpif_close(dpif);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dpctl_ct_stats_show(int argc, const char *argv[],
|
||||||
|
struct dpctl_params *dpctl_p)
|
||||||
|
{
|
||||||
|
struct dpif *dpif;
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
struct ct_dpif_dump_state *dump;
|
||||||
|
struct ct_dpif_entry cte;
|
||||||
|
uint16_t zone, *pzone = NULL;
|
||||||
|
bool verbose = false;
|
||||||
|
int lastargc = 0;
|
||||||
|
|
||||||
|
int proto_stats[CT_STATS_MAX];
|
||||||
|
int tcp_conn_per_states[CT_DPIF_TCPS_MAX_NUM];
|
||||||
|
int error;
|
||||||
|
|
||||||
|
while (argc > 1 && lastargc != argc) {
|
||||||
|
lastargc = argc;
|
||||||
|
if (!strncmp(argv[argc - 1], "verbose", 7)) {
|
||||||
|
verbose = true;
|
||||||
|
argc--;
|
||||||
|
} else if (!strncmp(argv[argc - 1], "zone=", 5)) {
|
||||||
|
if (ovs_scan(argv[argc - 1], "zone=%"SCNu16, &zone)) {
|
||||||
|
pzone = &zone;
|
||||||
|
argc--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
name = (argc > 1) ? xstrdup(argv[1]) : get_one_dp(dpctl_p);
|
||||||
|
if (!name) {
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = parsed_dpif_open(name, false, &dpif);
|
||||||
|
free(name);
|
||||||
|
if (error) {
|
||||||
|
dpctl_error(dpctl_p, error, "opening datapath");
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(proto_stats, 0, sizeof(proto_stats));
|
||||||
|
memset(tcp_conn_per_states, 0, sizeof(tcp_conn_per_states));
|
||||||
|
error = ct_dpif_dump_start(dpif, &dump, pzone);
|
||||||
|
if (error) {
|
||||||
|
dpctl_error(dpctl_p, error, "starting conntrack dump");
|
||||||
|
dpif_close(dpif);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tot_conn = 0;
|
||||||
|
while (!ct_dpif_dump_next(dump, &cte)) {
|
||||||
|
ct_dpif_entry_uninit(&cte);
|
||||||
|
tot_conn++;
|
||||||
|
switch (cte.tuple_orig.ip_proto) {
|
||||||
|
case IPPROTO_ICMP:
|
||||||
|
proto_stats[CT_STATS_ICMP]++;
|
||||||
|
break;
|
||||||
|
case IPPROTO_ICMPV6:
|
||||||
|
proto_stats[CT_STATS_ICMPV6]++;
|
||||||
|
break;
|
||||||
|
case IPPROTO_TCP:
|
||||||
|
proto_stats[CT_STATS_TCP]++;
|
||||||
|
uint8_t tcp_state;
|
||||||
|
/* We keep two separate tcp states, but we print just one. The
|
||||||
|
* Linux kernel connection tracker internally keeps only one state,
|
||||||
|
* so 'state_orig' and 'state_reply', will be the same. */
|
||||||
|
tcp_state = MAX(cte.protoinfo.tcp.state_orig,
|
||||||
|
cte.protoinfo.tcp.state_reply);
|
||||||
|
tcp_state = ct_dpif_coalesce_tcp_state(tcp_state);
|
||||||
|
tcp_conn_per_states[tcp_state]++;
|
||||||
|
break;
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
proto_stats[CT_STATS_UDP]++;
|
||||||
|
break;
|
||||||
|
case IPPROTO_SCTP:
|
||||||
|
proto_stats[CT_STATS_SCTP]++;
|
||||||
|
break;
|
||||||
|
case IPPROTO_UDPLITE:
|
||||||
|
proto_stats[CT_STATS_UDPLITE]++;
|
||||||
|
break;
|
||||||
|
case IPPROTO_DCCP:
|
||||||
|
proto_stats[CT_STATS_DCCP]++;
|
||||||
|
break;
|
||||||
|
case IPPROTO_IGMP:
|
||||||
|
proto_stats[CT_STATS_IGMP]++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
proto_stats[CT_STATS_OTHER]++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dpctl_print(dpctl_p, "Connections Stats:\n Total: %d\n", tot_conn);
|
||||||
|
if (proto_stats[CT_STATS_TCP]) {
|
||||||
|
dpctl_print(dpctl_p, "\tTCP: %d\n", proto_stats[CT_STATS_TCP]);
|
||||||
|
if (verbose) {
|
||||||
|
dpctl_print(dpctl_p, "\t Conn per TCP states:\n");
|
||||||
|
for (int i = 0; i < CT_DPIF_TCPS_MAX_NUM; i++) {
|
||||||
|
if (tcp_conn_per_states[i]) {
|
||||||
|
struct ds s = DS_EMPTY_INITIALIZER;
|
||||||
|
ct_dpif_format_tcp_stat(&s, i, tcp_conn_per_states[i]);
|
||||||
|
dpctl_print(dpctl_p, "%s\n", ds_cstr(&s));
|
||||||
|
ds_destroy(&s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (proto_stats[CT_STATS_UDP]) {
|
||||||
|
dpctl_print(dpctl_p, "\tUDP: %d\n", proto_stats[CT_STATS_UDP]);
|
||||||
|
}
|
||||||
|
if (proto_stats[CT_STATS_UDPLITE]) {
|
||||||
|
dpctl_print(dpctl_p, "\tUDPLITE: %d\n", proto_stats[CT_STATS_UDPLITE]);
|
||||||
|
}
|
||||||
|
if (proto_stats[CT_STATS_SCTP]) {
|
||||||
|
dpctl_print(dpctl_p, "\tSCTP: %d\n", proto_stats[CT_STATS_SCTP]);
|
||||||
|
}
|
||||||
|
if (proto_stats[CT_STATS_ICMP]) {
|
||||||
|
dpctl_print(dpctl_p, "\tICMP: %d\n", proto_stats[CT_STATS_ICMP]);
|
||||||
|
}
|
||||||
|
if (proto_stats[CT_STATS_DCCP]) {
|
||||||
|
dpctl_print(dpctl_p, "\tDCCP: %d\n", proto_stats[CT_STATS_DCCP]);
|
||||||
|
}
|
||||||
|
if (proto_stats[CT_STATS_IGMP]) {
|
||||||
|
dpctl_print(dpctl_p, "\tIGMP: %d\n", proto_stats[CT_STATS_IGMP]);
|
||||||
|
}
|
||||||
|
if (proto_stats[CT_STATS_OTHER]) {
|
||||||
|
dpctl_print(dpctl_p, "\tOther: %d\n", proto_stats[CT_STATS_OTHER]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ct_dpif_dump_done(dump);
|
||||||
|
dpif_close(dpif);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
/* Undocumented commands for unit testing. */
|
/* Undocumented commands for unit testing. */
|
||||||
|
|
||||||
@ -1622,6 +1758,8 @@ static const struct dpctl_command all_commands[] = {
|
|||||||
{ "del-flows", "[dp]", 0, 1, dpctl_del_flows, DP_RW },
|
{ "del-flows", "[dp]", 0, 1, dpctl_del_flows, DP_RW },
|
||||||
{ "dump-conntrack", "[dp] [zone=N]", 0, 2, dpctl_dump_conntrack, DP_RO },
|
{ "dump-conntrack", "[dp] [zone=N]", 0, 2, dpctl_dump_conntrack, DP_RO },
|
||||||
{ "flush-conntrack", "[dp] [zone=N]", 0, 2, dpctl_flush_conntrack, DP_RW },
|
{ "flush-conntrack", "[dp] [zone=N]", 0, 2, dpctl_flush_conntrack, DP_RW },
|
||||||
|
{ "ct-stats-show", "[dp] [zone=N] [verbose]",
|
||||||
|
0, 3, dpctl_ct_stats_show, 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 },
|
||||||
|
|
||||||
@ -1645,7 +1783,6 @@ int
|
|||||||
dpctl_run_command(int argc, const char *argv[], struct dpctl_params *dpctl_p)
|
dpctl_run_command(int argc, const char *argv[], struct dpctl_params *dpctl_p)
|
||||||
{
|
{
|
||||||
const struct dpctl_command *p;
|
const struct dpctl_command *p;
|
||||||
|
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
dpctl_error(dpctl_p, 0, "missing command name; use --help for help");
|
dpctl_error(dpctl_p, 0, "missing command name; use --help for help");
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
@ -221,3 +221,10 @@ added to the output.
|
|||||||
Flushes all the connection entries in the tracker used by \fIdp\fR.
|
Flushes all the connection entries in the tracker used by \fIdp\fR.
|
||||||
If \fBzone=\fIzone\fR is specified, only flushes the connections in
|
If \fBzone=\fIzone\fR is specified, only flushes the connections in
|
||||||
\fBzone\fR.
|
\fBzone\fR.
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
\*(DX\fBct\-stats\-show\fR [\fIdp\fR] [\fBzone=\fIzone\fR] [\fBverbose\fR]
|
||||||
|
Displays the number of connections grouped by protocol used by \fIdp\fR.
|
||||||
|
If \fBzone=\fIzone\fR is specified, numbers refer to the connections in
|
||||||
|
\fBzone\fR. The \fBverbose\fR option allows to group by connection state
|
||||||
|
for each protocol.
|
||||||
|
@ -200,6 +200,8 @@ usage(void *userdata OVS_UNUSED)
|
|||||||
"display conntrack entries for ZONE\n"
|
"display conntrack entries for ZONE\n"
|
||||||
" flush-conntrack [DP] [zone=ZONE] " \
|
" flush-conntrack [DP] [zone=ZONE] " \
|
||||||
"delete all conntrack entries in ZONE\n"
|
"delete all conntrack entries in ZONE\n"
|
||||||
|
" ct-stats-show [DP] [zone=ZONE] [verbose] " \
|
||||||
|
"CT connections grouped by protocol\n"
|
||||||
"Each IFACE on add-dp, add-if, and set-if may be followed by\n"
|
"Each IFACE on add-dp, add-if, and set-if may be followed by\n"
|
||||||
"comma-separated options. See ovs-dpctl(8) for syntax, or the\n"
|
"comma-separated options. See ovs-dpctl(8) for syntax, or the\n"
|
||||||
"Interface table in ovs-vswitchd.conf.db(5) for an options list.\n"
|
"Interface table in ovs-vswitchd.conf.db(5) for an options list.\n"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user