#include "rt_names.h"
#include "ll_map.h"
#include "libnetlink.h"
-#include "tcp_diag.h"
#include "SNAPSHOT.h"
+#include <asm/byteorder.h>
#include <linux/tcp.h>
+#include <linux/tcp_diag.h>
int resolve_hosts = 0;
int resolve_services = 1;
#define ALL_DB ((1<<MAX_DB)-1)
enum {
- SS_UNKNOWN,
- SS_ESTABLISHED,
- SS_SYN_SENT,
- SS_SYN_RECV,
- SS_FIN_WAIT1,
- SS_FIN_WAIT2,
- SS_TIME_WAIT,
- SS_CLOSE,
- SS_CLOSE_WAIT,
- SS_LAST_ACK,
- SS_LISTEN,
- SS_CLOSING,
- SS_MAX
+ SS_UNKNOWN,
+ SS_ESTABLISHED,
+ SS_SYN_SENT,
+ SS_SYN_RECV,
+ SS_FIN_WAIT1,
+ SS_FIN_WAIT2,
+ SS_TIME_WAIT,
+ SS_CLOSE,
+ SS_CLOSE_WAIT,
+ SS_LAST_ACK,
+ SS_LISTEN,
+ SS_CLOSING,
+ SS_MAX
};
#define SS_ALL ((1<<SS_MAX)-1)
return 0;
}
-
-
-
-char *sstate_name[] = {
- "UNKNOWN",
- "ESTAB",
- "SYN-SENT",
- "SYN-RECV",
- "FIN-WAIT-1",
- "FIN-WAIT-2",
- "TIME-WAIT",
- "UNCONN",
- "CLOSE-WAIT",
- "LAST-ACK",
- "LISTEN",
- "CLOSING",
+static const char *sstate_name[] = {
+ "UNKNOWN",
+ [TCP_ESTABLISHED] = "ESTAB",
+ [TCP_SYN_SENT] = "SYN-SENT",
+ [TCP_SYN_RECV] = "SYN-RECV",
+ [TCP_FIN_WAIT1] = "FIN-WAIT-1",
+ [TCP_FIN_WAIT2] = "FIN-WAIT-2",
+ [TCP_TIME_WAIT] = "TIME-WAIT",
+ [TCP_CLOSE] = "UNCONN",
+ [TCP_CLOSE_WAIT] = "CLOSE-WAIT",
+ [TCP_LAST_ACK] = "LAST-ACK",
+ [TCP_LISTEN] = "LISTEN",
+ [TCP_CLOSING] = "CLOSING",
};
-char *sstate_namel[] = {
- "UNKNOWN",
- "established",
- "syn-sent",
- "syn-recv",
- "fin-wait-1",
- "fin-wait-2",
- "time-wait",
- "unconnected",
- "close-wait",
- "last-ack",
- "listening",
- "closing",
+static const char *sstate_namel[] = {
+ "UNKNOWN",
+ [TCP_ESTABLISHED] = "established",
+ [TCP_SYN_SENT] = "syn-sent",
+ [TCP_SYN_RECV] = "syn-recv",
+ [TCP_FIN_WAIT1] = "fin-wait-1",
+ [TCP_FIN_WAIT2] = "fin-wait-2",
+ [TCP_TIME_WAIT] = "time-wait",
+ [TCP_CLOSE] = "unconnected",
+ [TCP_CLOSE_WAIT] = "close-wait",
+ [TCP_LAST_ACK] = "last-ack",
+ [TCP_LISTEN] = "listening",
+ [TCP_CLOSING] = "closing",
};
struct tcpstat
int rto, ato, qack, cwnd, ssthresh;
};
-char *tmr_name[] = {
+static const char *tmr_name[] = {
"off",
"on",
"keepalive",
return buf;
}
-void formatted_print(inet_prefix *a, int port)
+void formatted_print(const inet_prefix *a, int port)
{
char buf[1024];
const char *ap = buf;
struct aafilter *next;
};
-int inet2_addr_match(inet_prefix *a, inet_prefix *p, int plen)
+int inet2_addr_match(const inet_prefix *a, const inet_prefix *p, int plen)
{
if (!inet_addr_match(a, p, plen))
return 0;
+
/* Cursed "v4 mapped" addresses: v4 mapped socket matches
* pure IPv4 rule, but v4-mapped rule selects only v4-mapped
* sockets. Fair? */
return 1;
}
-int unix_match(inet_prefix *a, inet_prefix *p)
+int unix_match(const inet_prefix *a, const inet_prefix *p)
{
char *addr, *pattern;
memcpy(&addr, a->data, sizeof(addr));
return -1;
}
+void tcp_show_info(struct nlmsghdr *nlh, struct tcpdiagmsg *r)
+{
+ struct rtattr * tb[TCPDIAG_MAX+1];
+ const struct tcpdiag_meminfo *minfo = NULL;
+ const struct tcp_info *info = NULL;
+ const struct tcpvegas_info *vinfo = NULL;
+
+ memset(tb, 0, sizeof(tb));
+ parse_rtattr(tb, TCPDIAG_MAX, (struct rtattr*)(r+1),
+ nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
+
+ if (tb[TCPDIAG_MEMINFO])
+ minfo = RTA_DATA(tb[TCPDIAG_MEMINFO]);
+ if (tb[TCPDIAG_INFO])
+ info = RTA_DATA(tb[TCPDIAG_INFO]);
+
+#ifdef TCPDIAG_VEGASINFO
+ if (tb[TCPDIAG_VEGASINFO])
+ vinfo = RTA_DATA(tb[TCPDIAG_VEGASINFO]);
+#endif
+
+ if (minfo) {
+ printf(" mem:(r%u,w%u,f%u,t%u)",
+ minfo->tcpdiag_rmem,
+ minfo->tcpdiag_wmem,
+ minfo->tcpdiag_fmem,
+ minfo->tcpdiag_tmem);
+ }
+
+ if (info) {
+#ifdef TCP_INFO
+ if (info->tcpi_rto && info->tcpi_rto != 3000000)
+ printf(" rto:%g", (double)info->tcpi_rto/1000);
+ if (info->tcpi_rtt)
+ printf(" rtt:%g/%g", (double)info->tcpi_rtt/1000,
+ (double)info->tcpi_rttvar/1000);
+ if (info->tcpi_ato)
+ printf(" ato:%g", (double)info->tcpi_ato/1000);
+ if (info->tcpi_snd_cwnd != 2)
+ printf(" cwnd:%d", info->tcpi_snd_cwnd);
+ if (info->tcpi_snd_ssthresh < 0xFFFF)
+ printf(" ssthresh:%d", info->tcpi_snd_ssthresh);
+
+
+#ifdef TCPDIAG_VEGASINFO
+ if (vinfo) {
+ if (vinfo->tcpv_enabled)
+ printf(" vegas");
+ if (vinfo->tcpv_rtt &&
+ vinfo->tcpv_rtt != 0x7fffffff &&
+ info->tcpi_snd_mss &&
+ info->tcpi_snd_cwnd) {
+ printf(" bw:%g",
+ (double) info->tcpi_snd_cwnd *
+ (double) info->tcpi_snd_mss *
+ 8000000. / (double) vinfo->tcpv_rtt);
+ }
+ }
+#endif
+ }
+#else
+#warning No TCP_INFO. Please, do not repeat this experiment, use right kernel.
+ printf(" MORE_INFO_PROVIDED_YOU_COMPILED_SS_RIGHT");
+#endif
+}
int tcp_show_sock(struct nlmsghdr *nlh, struct filter *f)
{
printf("%08x", r->id.tcpdiag_cookie[1]);
}
if (show_mem || show_tcpinfo) {
- struct rtattr * tb[TCPDIAG_MAX+1];
- struct tcpdiag_meminfo *minfo = NULL;
- struct tcp_info *info = NULL;
-
- memset(tb, 0, sizeof(tb));
- parse_rtattr(tb, TCPDIAG_MAX, (struct rtattr*)(r+1),
- nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
- if (tb[TCPDIAG_MEMINFO])
- minfo = RTA_DATA(tb[TCPDIAG_MEMINFO]);
- if (tb[TCPDIAG_INFO])
- info = RTA_DATA(tb[TCPDIAG_INFO]);
- if (minfo) {
- printf(" mem:(r%u,w%u,f%u,t%u)",
- minfo->tcpdiag_rmem,
- minfo->tcpdiag_wmem,
- minfo->tcpdiag_fmem,
- minfo->tcpdiag_tmem);
- }
- if (info) {
-#ifdef TCP_INFO
- if (info->tcpi_rto && info->tcpi_rto != 3000000)
- printf(" rto:%g", (double)info->tcpi_rto/1000);
- if (info->tcpi_rtt)
- printf(" rtt:%g/%g", (double)info->tcpi_rtt/1000,
- (double)info->tcpi_rttvar/1000);
- if (info->tcpi_ato)
- printf(" ato:%g", (double)info->tcpi_ato/1000);
- if (info->tcpi_snd_cwnd != 2)
- printf(" cwnd:%d", info->tcpi_snd_cwnd);
- if (info->tcpi_snd_ssthresh < 0xFFFF)
- printf(" ssthresh:%d", info->tcpi_snd_ssthresh);
-#else
-#warning No TCP_INFO. Please, do not repeat this experiment, use right kernel.
- printf(" MORE_INFO_PROVIDED_YOU_COMPILED_SS_RIGHT");
-#endif
- }
+ printf("\n\t");
+ tcp_show_info(nlh, r);
}
+
printf("\n");
return 0;
req.r.tcpdiag_states = f->states;
if (show_mem)
req.r.tcpdiag_ext |= (1<<(TCPDIAG_MEMINFO-1));
- if (show_tcpinfo)
+ if (show_tcpinfo) {
req.r.tcpdiag_ext |= (1<<(TCPDIAG_INFO-1));
+#ifdef TCPDIAG_VEGASINFO
+ req.r.tcpdiag_ext |= (1<<(TCPDIAG_VEGASINFO-1));
+#endif
+ }
iov[0] = (struct iovec){ &req, sizeof(req) };
if (f->f) {
" ss [ OPTIONS ] [ FILTER ]\n"
"where OPTIONS := { -h[elp] | -V[ersion] | -n[umeric] | -r[esolve] |\n"
" -a[ll] -l[istening] -o[ptions] -e[xtended] -p[rocesses]\n"
-" -A QUERY } -s[ummary]\n"
+" -A QUERY -i[nfo] } -s[ummary]\n"
" -f[amily] { inet | inet6 | link | unix } }\n"
" QUERY := {all|inet|tcp|udp|raw|unix|packet|netlink}[,QUERY]\n"
" FILTER := [ state TCP-STATE ] [ EXPRESSION ]\n"
}
-int scan_state(char *state)
+int scan_state(const char *state)
{
int i;
if (strcasecmp(state, "close") == 0 ||
return 0;
}
-
int main(int argc, char *argv[])
{
int do_default = 1;
int saw_states = 0;
int saw_query = 0;
int do_summary = 0;
- char *dump_tcpdiag = NULL;
+ const char *dump_tcpdiag = NULL;
FILE *filter_fp = NULL;
int ch;
current_filter.states = default_filter.states;
- while ((ch = getopt(argc, argv, "h?aletuwxnro460spfmiA:D:F:vV")) != EOF) {
+ while ((ch = getopt(argc, argv, "h?aletuwxnro460spf:miA:D:F:vV")) != EOF) {
switch(ch) {
case 'n':
resolve_services = 0;