From f84e8fa05d0b778bb68fce68b10cfd1809ecfb2a Mon Sep 17 00:00:00 2001 From: xuanzhuo Date: Mon, 11 May 2020 19:39:21 +0800 Subject: [PATCH 1012/2944] alinux: add tcprt framework to kernel to #26353046 TcpRT: Instrument and Diagnostic Analysis System for Service Quality of Cloud Databases at Massive Scale in Real-time. It can also provide information for all request/response services. Such as HTTP request. This is the kernel framework for tcprt, more work needs tcprt module support. TcpRt module should call tcp_unregitsert_rt before rmmod. TcpRt hooks will be called when sock init, recv data, send data, packet acked and socket been destroy. The private data save to icsk->icsk_tcp_rt_priv. Reviewed-by: Cambda Zhu Acked-by: Dust Li Signed-off-by: xuanzhuo --- MAINTAINERS | 5 ++ include/net/inet_connection_sock.h | 7 ++- include/net/tcp.h | 1 + include/net/tcp_rt.h | 122 +++++++++++++++++++++++++++++++++++++ net/ipv4/Kconfig | 13 ++++ net/ipv4/Makefile | 2 + net/ipv4/tcp.c | 1 + net/ipv4/tcp_input.c | 4 ++ net/ipv4/tcp_ipv4.c | 2 + net/ipv4/tcp_output.c | 3 + net/ipv4/tcp_rt.c | 87 ++++++++++++++++++++++++++ 11 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 include/net/tcp_rt.h create mode 100644 net/ipv4/tcp_rt.c diff --git a/MAINTAINERS b/MAINTAINERS index 9db0336..3ac378a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -136,6 +136,11 @@ Maintainers List (try to look for most precise areas first) ----------------------------------- +TCP RT +M: xuanzhuo +S: Maintained +F: net/ipv4/tcp_rt.c + 3C59X NETWORK DRIVER M: Steffen Klassert L: netdev@vger.kernel.org diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index 371b3b4..0b18139 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h @@ -1,7 +1,7 @@ /* * NET Generic infrastructure for INET connection oriented protocols. * - * Definitions for inet_connection_sock + * Definitions for inet_connection_sock * * Authors: Many people, see the TCP sources * @@ -139,6 +139,11 @@ struct inet_connection_sock { } icsk_mtup; u32 icsk_user_timeout; +#ifdef CONFIG_TCP_RT + const struct tcp_rt_ops *icsk_tcp_rt_ops; + void *icsk_tcp_rt_priv; +#endif + u64 icsk_ca_priv[88 / sizeof(u64)]; #define ICSK_CA_PRIV_SIZE (11 * sizeof(u64)) }; diff --git a/include/net/tcp.h b/include/net/tcp.h index ac4ffe8..7ec5fa2 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -41,6 +41,7 @@ #include #include #include +#include #include #include diff --git a/include/net/tcp_rt.h b/include/net/tcp_rt.h new file mode 100644 index 0000000..de8c60a --- /dev/null +++ b/include/net/tcp_rt.h @@ -0,0 +1,122 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * TcpRT Instrument and Diagnostic Analysis System for Service Quality + * of Cloud Databases at Massive Scale in Real-time. + * + * It can also provide information for all request/response + * services. Such as HTTP request. + * + * This is the kernel framework, more work needs tcprt module + * support. + */ +#ifndef _TCP_RT_H +#define _TCP_RT_H + +#ifdef CONFIG_TCP_RT +struct tcp_rt_ops { + /* + * initialize private data (required) + * + * ret: + * 0: success alloc private data for this connection. + * -1: fail alloc private data or not care about this connection. + * Then this connection will not ref to tcp_rt. + */ + int (*init)(struct sock *sk); + + /* cleanup private data (required) */ + void (*release)(struct sock *sk); + + /* recv data */ + void (*recv_data)(struct sock *sk); + + /* send data */ + void (*send_data)(struct sock *sk); + + /* hook for packet ack accounting */ + void (*pkts_acked)(struct sock *sk); + + struct module *owner; +}; + +/* + * tcp_register_rt() - register tcp_rt ops to kernel + * @rt: tcp_rt_ops + * + * ret: + * -EINVAL: init or release of ops not init. + * -EBUSY: fail to get the moudle. + * -EEXIST: there exists one tcprt. + * 0: success + */ + +int tcp_register_rt(const struct tcp_rt_ops *rt); + +/* + * tcp_unregister_rt() - unregister the tcp_rt ops from kernel. + * + * After call this, the new connection will no ref to the tcp_rt, but + * the old connection still ref to the tcp_rt, you must wait for all + * old connection been released, then you can try to rmmod module. + * So, this function cannot been called inside the module_exit. + * You should call this by such as debugfs. such as: + * + * ---- + * static ssize_t tcp_rt_inactive(struct file *file, const char __user *buff, + * size_t count, loff_t *offset) + * { + * tcp_unregister_rt(&rt_ops); + * return count; + * } + * + * static struct file_operations fops = { + * .owner = THIS_MODULE, + * .write = tcp_rt_inactive, + * }; + * + * static int __init rt_register(void) + * { + * if (!debugfs_create_file("tcp-rt-no-active", 0600, NULL, NULL, fops)) { + * return -1; + * } + * + * ret = tcp_register_rt(&rt_ops); + * if (ret) { + * pr_err("tcp-rt register rt failed!\n"); + * tcp_rt_base_released(); + * return ret; + * } + * + * return 0; + * } + * + * static void __exit rt_unregister(void) + * { + * pr_info("tcp-rt: released\n"); + * } + * + * module_init(rt_register); + * module_exit(rt_unregister); + * ---- + * + * run this cmd before you want to rmmod module: + * echo 0 > /sys/kernel/debug/tcp-rt-no-active + * + */ +void tcp_unregister_rt(struct tcp_rt_ops *rt); +void tcp_init_rt(struct sock *sk); +void tcp_cleanup_rt(struct sock *sk); + +#define tcp_rt_call(sk, fun) \ + do { \ + if (inet_csk(sk)->icsk_tcp_rt_ops && \ + inet_csk(sk)->icsk_tcp_rt_ops->fun) \ + inet_csk(sk)->icsk_tcp_rt_ops->fun(sk); \ + } while (0) +#else +#define tcp_cleanup_rt(sk) +#define tcp_init_rt(sk) +#define tcp_rt_call(sk, fun) +#endif + +#endif /* _TCP_RT_H */ diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 32cae39..1a93cdf 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -753,3 +753,16 @@ config TCP_MD5SIG on the Internet. If unsure, say N. + +config TCP_RT + bool "TCP RT" + default n + help + TcpRT: Instrument and Diagnostic Analysis System for Service Quality + of Cloud Databases at Massive Scale in Real-time. + + It can also provide information for all request/response services. Such as + HTTP request. + + This is used for account opening kernel framework, more work needs + tcprt module support. diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 7446b98..e0d13d6 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile @@ -65,5 +65,7 @@ obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o obj-$(CONFIG_NETLABEL) += cipso_ipv4.o +obj-$(CONFIG_TCP_RT) += tcp_rt.o + obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \ xfrm4_output.o xfrm4_protocol.o diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index af66393..2dcbdd9 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -467,6 +467,7 @@ void tcp_init_transfer(struct sock *sk, int bpf_op) tcp_call_bpf(sk, bpf_op, 0, NULL); tcp_init_congestion_control(sk); tcp_init_buffer_space(sk); + tcp_init_rt(sk); } static void tcp_tx_timestamp(struct sock *sk, u16 tsflags) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index b259ed4..8fcf612 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -677,6 +677,8 @@ static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb) now = tcp_jiffies32; + tcp_rt_call(sk, recv_data); + if (!icsk->icsk_ack.ato) { /* The _first_ data packet received, initialize * delayed ACK engine. @@ -3217,6 +3219,8 @@ static int tcp_clean_rtx_queue(struct sock *sk, u32 prior_fack, flag |= FLAG_SET_XMIT_TIMER; /* set TLP or RTO timer */ } + tcp_rt_call(sk, pkts_acked); + if (icsk->icsk_ca_ops->pkts_acked) { struct ack_sample sample = { .pkts_acked = pkts_acked, .rtt_us = sack->rate->rtt_us, diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 6a3e2c8..fbb670f 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1971,6 +1971,8 @@ void tcp_v4_destroy_sock(struct sock *sk) tcp_cleanup_congestion_control(sk); + tcp_cleanup_rt(sk); + tcp_cleanup_ulp(sk); /* Cleanup up the write buffer. */ diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 8cc98a3..7ca9ceb 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2406,6 +2406,9 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, tcp_schedule_loss_probe(sk, false); is_cwnd_limited |= (tcp_packets_in_flight(tp) >= tp->snd_cwnd); tcp_cwnd_validate(sk, is_cwnd_limited); + + tcp_rt_call(sk, send_data); + return false; } return !tp->packets_out && !tcp_write_queue_empty(sk); diff --git a/net/ipv4/tcp_rt.c b/net/ipv4/tcp_rt.c new file mode 100644 index 0000000..d7caf5b --- /dev/null +++ b/net/ipv4/tcp_rt.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +static const struct tcp_rt_ops __rcu *tcp_rt; +static DEFINE_SPINLOCK(tcp_rt_lock); + +int tcp_register_rt(const struct tcp_rt_ops *rt) +{ + const struct tcp_rt_ops *ort; + int ret = 0; + + if (!rt->init || !rt->release) { + pr_err("tcp_rt does not implement required ops\n"); + return -EINVAL; + } + + spin_lock(&tcp_rt_lock); + ret = try_module_get(rt->owner); + if (unlikely(!ret)) { + ret = -EBUSY; + } else { + ort = rcu_dereference_protected(tcp_rt, true); + if (ort) { + ret = -EEXIST; + pr_err("tcp_rt already registered\n"); + module_put(rt->owner); + } else { + rcu_assign_pointer(tcp_rt, rt); + ret = 0; + } + } + spin_unlock(&tcp_rt_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(tcp_register_rt); + +void tcp_unregister_rt(struct tcp_rt_ops *rt) +{ + const struct tcp_rt_ops *ort = NULL; + + spin_lock(&tcp_rt_lock); + rcu_swap_protected(tcp_rt, ort, true); + if (ort) + module_put(ort->owner); + spin_unlock(&tcp_rt_lock); + + synchronize_rcu(); +} +EXPORT_SYMBOL_GPL(tcp_unregister_rt); + +void tcp_init_rt(struct sock *sk) +{ + struct inet_connection_sock *icsk = inet_csk(sk); + const struct tcp_rt_ops *ops; + + rcu_read_lock(); + ops = rcu_dereference(tcp_rt); + if (ops) + if (unlikely(!try_module_get(ops->owner))) + ops = NULL; + icsk->icsk_tcp_rt_ops = ops; + rcu_read_unlock(); + + ops = icsk->icsk_tcp_rt_ops; + + if (!ops) + return; + + if (ops->init(sk)) { + module_put(ops->owner); + icsk->icsk_tcp_rt_ops = NULL; + } +} + +void tcp_cleanup_rt(struct sock *sk) +{ + struct inet_connection_sock *icsk = inet_csk(sk); + + if (icsk->icsk_tcp_rt_ops) { + icsk->icsk_tcp_rt_ops->release(sk); + module_put(icsk->icsk_tcp_rt_ops->owner); + icsk->icsk_tcp_rt_ops = NULL; + } +} -- 1.8.3.1