From f486d9b98b68595375a3bec5cd2f1a6da0bd712e Mon Sep 17 00:00:00 2001 From: Xuan Zhuo Date: Thu, 21 May 2020 12:03:56 +0800 Subject: [PATCH 1719/2944] alinux: tcp_rt module: support ports_range to #27804112 ports_range configured as '1000,2000,4000,6000', that means port range 1000-2000 or 4000-6000 will be monitored. If the user uses ports_range then the real function will have too many ports to count. If we apply space for all ports at once when loading the module, this is a waste of space, so we use a two-dimensional array to solve this problem. A continuous space is allocated as needed to save a certain amount of statistical information. Signed-off-by: Xuan Zhuo Acked-by: Dust Li Reviewed-by: Ya Zhao Reviewed-by: Cambda Zhu --- net/ipv4/tcp_rt/core.c | 33 ++++++++++++--- net/ipv4/tcp_rt/output.c | 107 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 114 insertions(+), 26 deletions(-) diff --git a/net/ipv4/tcp_rt/core.c b/net/ipv4/tcp_rt/core.c index a6313ef..f323b8a 100644 --- a/net/ipv4/tcp_rt/core.c +++ b/net/ipv4/tcp_rt/core.c @@ -4,9 +4,11 @@ static int ports_number; static int ports_peer_number; +static int ports_range_number; static int ports[PORT_MAX_NUM]; static int ports_peer[PORT_MAX_NUM]; +static int ports_range[PORT_MAX_NUM]; static int log_buf_num = 8; static int real_buf_num = 2; @@ -21,10 +23,13 @@ MODULE_PARM_DESC(check_interval, "how many seconds later do stats"); module_param_array(ports, int, &ports_number, 0644); -MODULE_PARM_DESC(ports, "port array of port_number size"); +MODULE_PARM_DESC(ports, "local port array. config: ports=80,3306."); + +module_param_array(ports_range, int, &ports_range_number, 0644); +MODULE_PARM_DESC(ports_range, "local port range array. config: ports_range=1000,2000,3500,4000. means: 1000-2000 or 3500-4000"); module_param_array(ports_peer, int, &ports_peer_number, 0644); -MODULE_PARM_DESC(ports_peer, "peer ports array"); +MODULE_PARM_DESC(ports_peer, "peer port array. config: ports_peer=80,3306"); module_param(log_buf_num, int, 0644); MODULE_PARM_DESC(log_buf_num, "the num of buffers for every cpu log buffer. unit is 256k. just work when module load."); @@ -36,10 +41,17 @@ static void tcp_rt_timer_handler(struct timer_list *t) { if (check) { - int i = 0; + int i, port; for (i = 0; i < ports_number; i++) - tcp_rt_timer_output(i, ports[i], "L"); + tcp_rt_timer_output(0, ports[i], "L"); + + for (i = 0; i < ports_range_number / 2; ++i) { + for (port = ports_range[i * 2]; + port <= ports_range[i * 2 + 1]; ++port) { + tcp_rt_timer_output(PORT_MAX_NUM, port, "L"); + } + } for (i = 0; i < ports_peer_number; i++) tcp_rt_timer_output(i, ports_peer[i], "P"); @@ -281,6 +293,17 @@ static int tcp_rt_sk_init(struct sock *sk) } } + for (i = 0; i < ports_range_number / 2; ++i) { + if (port < ports_range[i * 2]) + continue; + + if (port > ports_range[i * 2 + 1]) + continue; + + type = TCPRT_TYPE_LOCAL_PORT_RANG; + goto ok; + } + port = ntohs(inet_sk(sk)->inet_dport); for (i = 0; i < ports_peer_number; i++) { @@ -292,7 +315,7 @@ static int tcp_rt_sk_init(struct sock *sk) return -1; ok: - rt = kmalloc(sizeof(*rt), GFP_KERNEL); + rt = kmalloc(sizeof(*rt), GFP_ATOMIC); if (!rt) return -1; diff --git a/net/ipv4/tcp_rt/output.c b/net/ipv4/tcp_rt/output.c index b163c88..0540b5e 100644 --- a/net/ipv4/tcp_rt/output.c +++ b/net/ipv4/tcp_rt/output.c @@ -3,21 +3,28 @@ #include #include "tcp_rt.h" +#define CHUNK_SIZE (4096) +#define PORTS_PER_CHUNK (CHUNK_SIZE / sizeof(struct tcp_rt_real)) +#define PORT_TOTAL_NUM (U16_MAX + 1) +#define CHUNK_COUNT (PORT_TOTAL_NUM / PORTS_PER_CHUNK + 1) + static struct rchan *relay_log; static struct rchan *relay_stats; static struct dentry *tcprt_dir; -static struct tcp_rt_real statis_local[PORT_MAX_NUM]; +static struct tcp_rt_real *statis_local[CHUNK_COUNT]; static struct tcp_rt_real statis_peer[PORT_MAX_NUM]; -#define get_statis_local(rt) (statis_local[(rt)->index]) -#define get_statis_peer(rt) (statis_peer[(rt)->index]) -#define statis_local_inc(rt, item) atomic64_inc(&statis_local[(rt)->index].item) -#define statis_peer_inc(rt, item) atomic64_inc(&statis_peer[(rt)->index].item) -#define statis_local_add(rt, item, val) \ - atomic64_add(val, &statis_local[(rt)->index].item) +#define statis_local_inc(item) atomic64_inc(&(item)) +#define statis_local_add(item, val) atomic64_add(val, &(item)) + +#define statis_peer_inc(rt, item) \ + atomic64_inc(&statis_peer[(rt)->index].item) #define statis_peer_add(rt, item, val) \ atomic64_add(val, &statis_peer[(rt)->index].item) +#define tcp_rt_get_local_statis_sk(sk) \ + tcp_rt_get_local_statis(ntohs(inet_sk(sk)->inet_sport), true) + static int64_t timespec64_dec(struct timespec64 tv1, struct timespec64 tv2) { return (tv1.tv_sec - tv2.tv_sec) * 1000000 + @@ -69,6 +76,34 @@ static int ip_format2(char *buf, u32 addr, char end) return idx; } +static struct tcp_rt_real *tcp_rt_get_local_statis(int port, bool alloc) +{ + int chunkid; + struct tcp_rt_real *p; + + chunkid = port / PORTS_PER_CHUNK; + + p = statis_local[chunkid]; + + if (unlikely(!p)) { + if (!alloc) + return NULL; + + p = kmalloc(CHUNK_SIZE, GFP_ATOMIC); + if (!p) + return NULL; + + memset(p, 0, CHUNK_SIZE); + + if (cmpxchg(&statis_local[chunkid], NULL, p)) { + vfree(p); + p = READ_ONCE(statis_local[chunkid]); + } + } + + return p + (port - chunkid * PORTS_PER_CHUNK); +} + #define bufappend(buf, size, v) \ ulong_format2((buf) + (size), (unsigned long)(v)) @@ -98,6 +133,7 @@ void tcp_rt_log_printk(const struct sock *sk, char flag, bool fin, bool check) { #define MAX_BUF_SIZE 512 + struct tcp_rt_real *r; struct tcp_sock *tp = tcp_sk(sk); struct tcp_rt *rt = TCP_SK_RT(sk); char buf[MAX_BUF_SIZE]; @@ -141,16 +177,20 @@ void tcp_rt_log_printk(const struct sock *sk, char flag, bool fin, bool check) buf[size++] = '\n'; if (check && t_seq > 0) { - statis_local_inc(rt, number); + r = tcp_rt_get_local_statis_sk(sk); + if (!r) + break; - statis_local_add(rt, rt, t_rt); - statis_local_add(rt, bytes, t_seq); - statis_local_add(rt, drop, t_retrans); - statis_local_add(rt, packets, + statis_local_inc(r->number); + + statis_local_add(r->rt, t_rt); + statis_local_add(r->bytes, t_seq); + statis_local_add(r->drop, t_retrans); + statis_local_add(r->packets, t_seq / tp->mss_cache + 1); - statis_local_add(rt, server_time, rt->server_time); - statis_local_add(rt, upload_time, rt->upload_time); - statis_local_add(rt, upload_data, rt->upload_data); + statis_local_add(r->server_time, rt->server_time); + statis_local_add(r->upload_time, rt->upload_time); + statis_local_add(r->upload_data, rt->upload_data); } break; @@ -173,8 +213,13 @@ void tcp_rt_log_printk(const struct sock *sk, char flag, bool fin, bool check) size += bufappend(buf, size, tp->mss_cache); buf[size++] = '\n'; - if (check && t_rt > HZ / 10) - statis_local_inc(rt, fail); + if (check && t_rt > HZ / 10) { + r = tcp_rt_get_local_statis_sk(sk); + if (!r) + break; + + statis_local_inc(r->fail); + } break; case LOG_STATUS_N: @@ -203,8 +248,12 @@ void tcp_rt_log_printk(const struct sock *sk, char flag, bool fin, bool check) buf[size++] = '\n'; if (mrtt > 0) { - statis_local_inc(rt, con_num); - statis_local_add(rt, rtt, mrtt); + r = tcp_rt_get_local_statis_sk(sk); + if (!r) + break; + + statis_local_inc(r->con_num); + statis_local_add(r->rtt, mrtt); } break; @@ -246,14 +295,24 @@ void tcp_rt_timer_output(int index, int port, char *flag) char buf[MAX_BUF_SIZE]; if (*flag == 'L') { - r = statis_local + index; + if (index == PORT_MAX_NUM) + r = tcp_rt_get_local_statis(port, false); + else + r = tcp_rt_get_local_statis(port, true); + + if (!r) + return; + flag = ""; } else { r = statis_peer + index; } + t.number = atomic64_read(&r->number); + if (!t.number && index == PORT_MAX_NUM) + return; + t.rt = atomic64_read(&r->rt); - t.number = atomic64_read(&r->number); t.bytes = atomic64_read(&r->bytes); t.drop = atomic64_read(&r->drop); t.fail = atomic64_read(&r->fail); @@ -361,8 +420,14 @@ int tcp_rt_output_init(int log_buf_num, int real_buf_num, void tcp_rt_output_released(void) { + int i; + relay_close(relay_log); relay_close(relay_stats); debugfs_remove_recursive(tcprt_dir); + + for (i = 0; i < ARRAY_SIZE(statis_local); ++i) + kfree(statis_local[i]); + pr_info("tcp-rt: output released\n"); } -- 1.8.3.1