diff --git a/code/linux/net/newip/tcp_nip_parameter.c b/code/linux/net/newip/tcp_nip_parameter.c new file mode 100644 index 0000000000000000000000000000000000000000..286ac3dad6958d75fd8f68ae1b63952230f40071 --- /dev/null +++ b/code/linux/net/newip/tcp_nip_parameter.c @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * + * NewIP INET + * An implementation of the TCP/IP protocol suite for the LINUX + * operating system. NewIP INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the NewIP parameter module. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +/*********************************************************************************************/ +/* Newip protocol name */ +/*********************************************************************************************/ +int g_af_ninet = AF_NINET; +module_param_named(af_ninet, g_af_ninet, int, 0444); + +/*********************************************************************************************/ +/* Rto timeout timer period (HZ/n) */ +/*********************************************************************************************/ +/* RTT RTO in the small-delay scenario */ +int g_nip_rto = 50; +module_param_named(nip_rto, g_nip_rto, int, 0644); + +/* RTT RTO of a large delay scenario */ +int g_nip_rto_up = 100; +module_param_named(nip_rto_up, g_nip_rto_up, int, 0644); + +/*********************************************************************************************/ +/* TCP sending and receiving buffer configuration */ +/*********************************************************************************************/ +int g_nip_sndbuf = 1050000; // 1M +module_param_named(nip_sndbuf, g_nip_sndbuf, int, 0644); + +int g_nip_rcvbuf = 3000000; // 3M +module_param_named(nip_rcvbuf, g_nip_rcvbuf, int, 0644); + +/*********************************************************************************************/ +/* Window configuration */ +/*********************************************************************************************/ +/* Maximum receiving window */ +int g_wscale_enable = 1; +module_param_named(wscale_enable, g_wscale_enable, int, 0644); + +/* Window scale configuration, 2^n */ +int g_wscale = 7; +module_param_named(wscale, g_wscale, int, 0644); + +/*********************************************************************************************/ +/* Enables the debugging of special scenarios */ +/*********************************************************************************************/ +/* After receiving n packets, an ACK packet is sent */ +int g_ack_num = 5; +module_param_named(ack_num, g_ack_num, int, 0644); + +/* Reset the packet sending window threshold after receiving n ACK packets */ +int g_nip_ssthresh_reset = 10000000; // 10M +module_param_named(nip_ssthresh_reset, g_nip_ssthresh_reset, int, 0644); + +/*********************************************************************************************/ +/* Enables the debugging of special scenarios */ +/*********************************************************************************************/ +/* Debugging of threshold change */ +int g_rtt_ssthresh_debug; +module_param_named(rtt_ssthresh_debug, g_rtt_ssthresh_debug, int, 0644); + +/* Debugging of packet retransmission after ACK */ +int g_ack_retrans_debug; +module_param_named(ack_retrans_debug, g_ack_retrans_debug, int, 0644); + +/*********************************************************************************************/ +/* Retransmission parameters after ACK */ +/*********************************************************************************************/ +/* Three DUP ACK packets indicates the number of retransmission packets */ +int g_dup_ack_retrans_num = 5; +module_param_named(dup_ack_retrans_num, g_dup_ack_retrans_num, int, 0644); + +/* Common ACK Indicates the number of retransmissions */ +int g_ack_retrans_num = 5; +module_param_named(ack_retrans_num, g_ack_retrans_num, int, 0644); + +/* Ack retransmission seg retransmission divisor */ +int g_retrans_seg_end_divisor = 1; +module_param_named(retrans_seg_end_divisor, g_retrans_seg_end_divisor, int, 0644); + +/*********************************************************************************************/ +/* RTT timestamp parameters */ +/*********************************************************************************************/ +int g_rtt_tstamp_rto_up = 100; // rtt_tstamp >= 100 ==> shorten rto +module_param_named(rtt_tstamp_rto_up, g_rtt_tstamp_rto_up, int, 0644); + +int g_rtt_tstamp_high = 30; // rtt_tstamp >= 30 ==> ssthresh = 100K +module_param_named(rtt_tstamp_high, g_rtt_tstamp_high, int, 0644); + +int g_rtt_tstamp_mid_high = 20; // rtt_tstamp >= 20 ==> ssthresh = 250K +module_param_named(rtt_tstamp_mid_high, g_rtt_tstamp_mid_high, int, 0644); + +/* rtt_tstamp >= 10 ==> ssthresh = 1M (500K ~ 1M) + * rtt_tstamp < 10 ==> ssthresh = 1.5M + */ +int g_rtt_tstamp_mid_low = 10; +module_param_named(rtt_tstamp_mid_low, g_rtt_tstamp_mid_low, int, 0644); + +int g_ack_to_nxt_snd_tstamp = 500; +module_param_named(ack_to_nxt_snd_tstamp, g_ack_to_nxt_snd_tstamp, int, 0644); + +/*********************************************************************************************/ +/* Window threshold parameters */ +/*********************************************************************************************/ +int g_ssthresh_enable = 1; +module_param_named(ssthresh_enable, g_ssthresh_enable, int, 0644); + +int g_nip_ssthresh_default = 300000; // 300K +module_param_named(nip_ssthresh_default, g_nip_ssthresh_default, int, 0644); + +int g_ssthresh_high = 1500000; // rtt_tstamp < 10 ==> ssthresh = 1.5M +module_param_named(ssthresh_high, g_ssthresh_high, int, 0644); + +int g_ssthresh_mid_high = 1000000; // rtt_tstamp >= 10 ==> ssthresh = 1M (500K ~ 1M) +module_param_named(ssthresh_mid_high, g_ssthresh_mid_high, int, 0644); + +int g_ssthresh_mid_low = 250000; // rtt_tstamp >= 20 ==> ssthresh = 250K +module_param_named(ssthresh_mid_low, g_ssthresh_mid_low, int, 0644); + +int g_ssthresh_low = 100000; // rtt_tstamp >= 30 ==> ssthresh = 100K +module_param_named(ssthresh_low, g_ssthresh_low, int, 0644); + +int g_ssthresh_low_min = 10000; // rtt_tstamp >= 100 ==> ssthresh = 10K +module_param_named(ssthresh_low_min, g_ssthresh_low_min, int, 0644); + +int g_ssthresh_high_step = 1; +module_param_named(ssthresh_high_step, g_ssthresh_high_step, int, 0644); + +int g_rcv_win_max = 512000; +module_param_named(rcv_win_max, g_rcv_win_max, int, 0644); + +/*********************************************************************************************/ +/* keepalive parameters */ +/*********************************************************************************************/ +int g_nip_idle_ka_probes_out = 200; +module_param_named(nip_idle_ka_probes_out, g_nip_idle_ka_probes_out, int, 0644); + +int g_nip_keepalive_time = 25; +module_param_named(nip_keepalive_time, g_nip_keepalive_time, int, 0644); + +int g_nip_keepalive_intvl = 25; +module_param_named(nip_keepalive_intvl, g_nip_keepalive_intvl, int, 0644); + +int g_nip_keepalive_probes = 255; +module_param_named(nip_keepalive_probes, g_nip_keepalive_probes, int, 0644); + +/*********************************************************************************************/ +/* zero probeparameters */ +/*********************************************************************************************/ +int g_nip_tcp_zero_probe = 20; +module_param_named(nip_tcp_zero_probe, g_nip_tcp_zero_probe, int, 0644); + +/*********************************************************************************************/ +/* window mode parameters */ +/*********************************************************************************************/ +bool g_nip_tcp_snd_win_enable; +module_param_named(nip_tcp_snd_win_enable, g_nip_tcp_snd_win_enable, bool, 0644); + +bool g_nip_tcp_rcv_win_enable = true; +module_param_named(nip_tcp_rcv_win_enable, g_nip_tcp_rcv_win_enable, bool, 0644); + diff --git a/code/linux/net/newip/tcp_nip_parameter.h b/code/linux/net/newip/tcp_nip_parameter.h new file mode 100644 index 0000000000000000000000000000000000000000..7467dde6fa742a2f9b972056dc0cc44ada39c2ec --- /dev/null +++ b/code/linux/net/newip/tcp_nip_parameter.h @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * + * NewIP INET + * An implementation of the TCP/IP protocol suite for the LINUX + * operating system. NewIP INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the NewIP parameter module. + */ +#ifndef _TCP_NIP_PARAMETER_H +#define _TCP_NIP_PARAMETER_H + +/*********************************************************************************************/ +/* Rto timeout timer period (HZ/n) */ +/*********************************************************************************************/ +extern int g_nip_rto; +extern int g_nip_rto_up; + +/*********************************************************************************************/ +/* TCP sending and receiving buffer configuration */ +/*********************************************************************************************/ +extern int g_nip_sndbuf; +extern int g_nip_rcvbuf; + +/*********************************************************************************************/ +/* Window configuration */ +/*********************************************************************************************/ +extern int g_wscale_enable; +extern int g_wscale; + +/*********************************************************************************************/ +/* Enables the debugging of special scenarios */ +/*********************************************************************************************/ +extern int g_ack_num; +extern int g_nip_ssthresh_reset; + +/*********************************************************************************************/ +/* Enables the debugging of special scenarios */ +/*********************************************************************************************/ +extern int g_rtt_ssthresh_debug; +#define SSTHRESH_DBG(fmt, ...) \ +do { \ + if (g_rtt_ssthresh_debug) \ + pr_crit(fmt, ##__VA_ARGS__); \ +} while (0) + +extern int g_ack_retrans_debug; +#define RETRANS_DBG(fmt, ...) \ +do { \ + if (g_ack_retrans_debug) \ + pr_crit(fmt, ##__VA_ARGS__); \ +} while (0) + +/*********************************************************************************************/ +/* Retransmission parameters after ACK */ +/*********************************************************************************************/ +extern int g_dup_ack_retrans_num; +extern int g_ack_retrans_num; +extern int g_retrans_seg_end_divisor; + +/*********************************************************************************************/ +/* RTT timestamp parameters */ +/*********************************************************************************************/ +extern int g_rtt_tstamp_rto_up; +extern int g_rtt_tstamp_high; +extern int g_rtt_tstamp_mid_high; +extern int g_rtt_tstamp_mid_low; +extern int g_ack_to_nxt_snd_tstamp; + +/*********************************************************************************************/ +/* Window threshold parameters */ +/*********************************************************************************************/ +extern int g_ssthresh_enable; +extern int g_nip_ssthresh_default; +extern int g_ssthresh_high; +extern int g_ssthresh_mid_high; +extern int g_ssthresh_mid_low; +extern int g_ssthresh_low; +extern int g_ssthresh_low_min; +extern int g_ssthresh_high_step; +extern int g_rcv_win_max; + +/*********************************************************************************************/ +/* keepalive parameters */ +/*********************************************************************************************/ +extern int g_nip_idle_ka_probes_out; +extern int g_nip_keepalive_time; +extern int g_nip_keepalive_intvl; +extern int g_nip_keepalive_probes; + +/*********************************************************************************************/ +/* zero probeparameters */ +/*********************************************************************************************/ +extern int g_nip_tcp_zero_probe; + +/*********************************************************************************************/ +/* window mode parameters */ +/*********************************************************************************************/ +extern bool g_nip_tcp_snd_win_enable; +extern bool g_nip_tcp_rcv_win_enable; + +#endif /* _TCP_NIP_PARAMETER_H */ diff --git a/code/linux/net/newip/tcp_nip_timer.c b/code/linux/net/newip/tcp_nip_timer.c new file mode 100644 index 0000000000000000000000000000000000000000..4f3c44cc182ae83e76b13d12206d7d8cc34cb0db --- /dev/null +++ b/code/linux/net/newip/tcp_nip_timer.c @@ -0,0 +1,381 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * + * NewIP INET + * An implementation of the TCP/IP protocol suite for the LINUX + * operating system. NewIP INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Implementation of the Transmission Control Protocol(TCP). + * + * Based on net/ipv4/tcp_timer.c + */ +#define pr_fmt(fmt) "NIP-TCP: " fmt + +#include +#include +#include "tcp_nip_parameter.h" + +/** + * tcp_nip_orphan_retries() - Returns maximal number of retries on an orphaned socket + * @sk: Pointer to the current socket. + * @alive: bool, socket alive state + */ +static int tcp_nip_orphan_retries(struct sock *sk, bool alive) +{ + int retries = sock_net(sk)->ipv4.sysctl_tcp_orphan_retries; /* May be zero. */ + + /* We know from an ICMP that something is wrong. */ + if (sk->sk_err_soft && !alive) + retries = 0; + + /* However, if socket sent something recently, select some safe + * number of retries. 8 corresponds to >100 seconds with minimal + * RTO of 200msec. + */ + if (retries == 0 && alive) + retries = 8; + return retries; +} + +void tcp_nip_delack_timer_handler(struct sock *sk) +{ + struct inet_connection_sock *icsk = inet_csk(sk); + + if (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) || + !(icsk->icsk_ack.pending & ICSK_ACK_TIMER)) + goto out; + + if (time_after(icsk->icsk_ack.timeout, jiffies)) { + sk_reset_timer(sk, &icsk->icsk_delack_timer, icsk->icsk_ack.timeout); + goto out; + } + icsk->icsk_ack.pending &= ~ICSK_ACK_TIMER; + + if (inet_csk_ack_scheduled(sk)) { + icsk->icsk_ack.ato = TCP_ATO_MIN; + tcp_mstamp_refresh(tcp_sk(sk)); + tcp_nip_send_ack(sk); + __NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKS); + } + +out:; +} + +static void tcp_nip_write_err(struct sock *sk) +{ + sk->sk_err = sk->sk_err_soft ? : ETIMEDOUT; + sk->sk_error_report(sk); + /* Releasing TCP Resources */ + tcp_nip_done(sk); + __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONTIMEOUT); +} + +static void tcp_nip_delack_timer(struct timer_list *t) +{ + struct inet_connection_sock *icsk = + from_timer(icsk, t, icsk_delack_timer); + struct sock *sk = &icsk->icsk_inet.sk; + + bh_lock_sock(sk); + if (!sock_owned_by_user(sk)) { + tcp_nip_delack_timer_handler(sk); + } else { + __NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED); + /* deleguate our work to tcp_release_cb() */ + if (!test_and_set_bit(TCP_NIP_DELACK_TIMER_DEFERRED, &sk->sk_tsq_flags)) + sock_hold(sk); + } + bh_unlock_sock(sk); + sock_put(sk); +} + +static bool retransmits_nip_timed_out(struct sock *sk, + unsigned int boundary, + unsigned int timeout, + bool syn_set) +{ + /* Newip does not support the calculation of the timeout period based on the timestamp. + * Currently, it determines whether the timeout period is based on + * the retransmission times + */ + DEBUG("%s: icsk->retransmits=%u\n", __func__, + inet_csk(sk)->icsk_retransmits); + return inet_csk(sk)->icsk_retransmits > boundary; +} + +static int tcp_nip_write_timeout(struct sock *sk) +{ + struct inet_connection_sock *icsk = inet_csk(sk); + struct net *net = sock_net(sk); + int retry_until; + bool syn_set = false; + + if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { + retry_until = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_syn_retries; + syn_set = true; + } else { + retry_until = net->ipv4.sysctl_tcp_retries2; + if (sock_flag(sk, SOCK_DEAD)) { + const bool alive = icsk->icsk_rto < TCP_RTO_MAX; + + /* In the case of SOCK_DEAD, the retry_until value is smaller */ + retry_until = tcp_nip_orphan_retries(sk, alive); + } + } + + if (retransmits_nip_timed_out(sk, retry_until, + syn_set ? 0 : icsk->icsk_user_timeout, syn_set)) { + DEBUG("%s: tcp retransmit time out!!!\n", __func__); + tcp_nip_write_err(sk); + return 1; + } + return 0; +} + +void tcp_nip_retransmit_timer(struct sock *sk) +{ + struct tcp_sock *tp = tcp_sk(sk); + struct inet_connection_sock *icsk = inet_csk(sk); + struct sk_buff *skb = tcp_write_queue_head(sk); + struct tcp_skb_cb *scb = TCP_SKB_CB(skb); + u32 icsk_rto_last; + + if (!tp->packets_out) + return; + + if (tcp_nip_write_queue_empty(sk)) + return; + + tp->tlp_high_seq = 0; + + if (tcp_nip_write_timeout(sk)) + return; + + if (tcp_nip_retransmit_skb(sk, skb, 1) > 0) { + if (!icsk->icsk_retransmits) + icsk->icsk_retransmits = 1; + inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, + min(icsk->icsk_rto, TCP_RESOURCE_PROBE_INTERVAL), + TCP_RTO_MAX); + + SSTHRESH_DBG("%s seq %u retransmit fail, win=%u, rto=%u, pkt_out=%u", + __func__, scb->seq, tp->nip_ssthresh, icsk->icsk_rto, tp->packets_out); + return; + } + icsk->icsk_backoff++; + icsk->icsk_retransmits++; + + icsk_rto_last = icsk->icsk_rto; + icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX); + + SSTHRESH_DBG("%s seq %u, reset win %u to %u, rto %u to %u, pkt_out=%u", + __func__, scb->seq, tp->nip_ssthresh, g_ssthresh_low, + icsk_rto_last, icsk->icsk_rto, tp->packets_out); + + tp->nip_ssthresh = g_ssthresh_low; + + inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, TCP_RTO_MAX); +} + +void tcp_nip_probe_timer(struct sock *sk) +{ + struct inet_connection_sock *icsk = inet_csk(sk); + struct tcp_sock *tp = tcp_sk(sk); + int max_probes; + + if (tp->packets_out || !tcp_nip_send_head(sk)) { + icsk->icsk_probes_out = 0; + DEBUG("[nip]%s packets_out!=0 or send_head=NULL, don't send probe packet.", + __func__); + return; + } + + max_probes = sock_net(sk)->ipv4.sysctl_tcp_retries2; + if (sock_flag(sk, SOCK_DEAD)) { + const bool alive = inet_csk_rto_backoff(icsk, TCP_RTO_MAX) < TCP_RTO_MAX; + + max_probes = tcp_nip_orphan_retries(sk, alive); + if (!alive && icsk->icsk_backoff >= max_probes) + goto abort; + } + + if (icsk->icsk_probes_out >= max_probes) { +abort: tcp_nip_write_err(sk); + } else { + /* Only send another probe if we didn't close things up. */ + tcp_nip_send_probe0(sk); + } +} + +void tcp_nip_write_timer_handler(struct sock *sk) +{ + struct inet_connection_sock *icsk = inet_csk(sk); + int event; + + if (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) || + !icsk->icsk_pending) + goto out; + + if (time_after(icsk->icsk_timeout, jiffies)) { + sk_reset_timer(sk, &icsk->icsk_retransmit_timer, icsk->icsk_timeout); + goto out; + } + tcp_mstamp_refresh(tcp_sk(sk)); + event = icsk->icsk_pending; + + switch (event) { + case ICSK_TIME_RETRANS: + icsk->icsk_pending = 0; + tcp_nip_retransmit_timer(sk); + break; + case ICSK_TIME_PROBE0: + icsk->icsk_pending = 0; + tcp_nip_probe_timer(sk); + break; + default: + break; + } + +out:; +} + +static void tcp_nip_write_timer(struct timer_list *t) +{ + struct inet_connection_sock *icsk = + from_timer(icsk, t, icsk_retransmit_timer); + struct sock *sk = &icsk->icsk_inet.sk; + + bh_lock_sock(sk); + if (!sock_owned_by_user(sk)) { + tcp_nip_write_timer_handler(sk); + } else { + /* delegate our work to tcp_release_cb() */ + if (!test_and_set_bit(TCP_NIP_WRITE_TIMER_DEFERRED, &sk->sk_tsq_flags)) + sock_hold(sk); + } + bh_unlock_sock(sk); + sock_put(sk); +} + +#define NIP_KA_TIMEOUT_SCALE_MAX 1000 +static void tcp_nip_keepalive_timeout(struct sock *sk) +{ + struct inet_connection_sock *icsk = inet_csk(sk); + struct tcp_sock *tp = tcp_sk(sk); + u32 keepalive_time = keepalive_time_when(tp); + + if (keepalive_time > HZ) { + pr_crit("%s keepalive timeout, disconnect sock.", __func__); + tcp_nip_write_err(sk); + return; + } + + tp->nip_keepalive_timeout_scale++; + if (tp->nip_keepalive_timeout_scale <= NIP_KA_TIMEOUT_SCALE_MAX) { + icsk->icsk_probes_out = 0; + inet_csk_reset_keepalive_timer(sk, keepalive_time); + + pr_crit("%s ms keepalive scale(%u) < thresh, connect sock continue.", + __func__, tp->nip_keepalive_timeout_scale); + } else { + pr_crit("%s ms keepalive timeout(scale=%u), disconnect sock.", + __func__, tp->nip_keepalive_timeout_scale); + tcp_nip_write_err(sk); + } +} + +static void tcp_nip_keepalive_timer(struct timer_list *t) +{ + struct sock *sk = from_timer(sk, t, sk_timer); + struct inet_connection_sock *icsk = inet_csk(sk); + struct tcp_sock *tp = tcp_sk(sk); + u32 elapsed; + + /* Only process if socket is not in use. */ + bh_lock_sock(sk); + if (sock_owned_by_user(sk)) { + /* Try again later. */ + inet_csk_reset_keepalive_timer(sk, HZ / TCP_NIP_KEEPALIVE_CYCLE_MS_DIVISOR); + goto out; + } + + if (sk->sk_state == TCP_LISTEN) { + pr_err("Hmm... keepalive on a LISTEN\n"); + goto out; + } + tcp_mstamp_refresh(tp); + /* 2022-02-18 + * NewIP TCP doesn't have TIME_WAIT state, so socket in TCP_CLOSING + * uses keepalive timer to release socket. + */ + if ((sk->sk_state == TCP_FIN_WAIT2 || sk->sk_state == TCP_CLOSING) && + sock_flag(sk, SOCK_DEAD)) { + DEBUG("%s: finish wait, close sock\n", __func__); + goto death; + } + + if (!sock_flag(sk, SOCK_KEEPOPEN) || + ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT))) + goto out; + + elapsed = keepalive_time_when(tp); + + /* It is alive without keepalive 8) */ + if (tp->packets_out || !tcp_write_queue_empty(sk)) + goto resched; + + elapsed = keepalive_time_elapsed(tp); + if (elapsed >= keepalive_time_when(tp)) { + /* If the TCP_USER_TIMEOUT option is enabled, use that + * to determine when to timeout instead. + */ + if ((icsk->icsk_user_timeout != 0 && + elapsed >= msecs_to_jiffies(icsk->icsk_user_timeout) && + icsk->icsk_probes_out > 0) || + (icsk->icsk_user_timeout == 0 && + icsk->icsk_probes_out >= keepalive_probes(tp))) { + tcp_nip_keepalive_timeout(sk); + goto out; + } + if (tcp_nip_write_wakeup(sk, LINUX_MIB_TCPKEEPALIVE) <= 0) { + icsk->icsk_probes_out++; + tp->idle_ka_probes_out++; + elapsed = keepalive_intvl_when(tp); + } else { + /* If keepalive was lost due to local congestion, + * try harder. + */ + elapsed = TCP_RESOURCE_PROBE_INTERVAL; + } + } else { + /* It is tp->rcv_tstamp + keepalive_time_when(tp) */ + elapsed = keepalive_time_when(tp) - elapsed; + } + + sk_mem_reclaim(sk); + +resched: + inet_csk_reset_keepalive_timer(sk, elapsed); + goto out; + +death: + tcp_nip_done(sk); + +out: + tcp_nip_keepalive_disable(sk); + bh_unlock_sock(sk); + sock_put(sk); +} + +void tcp_nip_init_xmit_timers(struct sock *sk) +{ + inet_csk_init_xmit_timers(sk, &tcp_nip_write_timer, &tcp_nip_delack_timer, + &tcp_nip_keepalive_timer); +} + +void tcp_nip_clear_xmit_timers(struct sock *sk) +{ + inet_csk_clear_xmit_timers(sk); +} diff --git a/patches/hispark_taurus.flag b/patches/hispark_taurus.flag new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/patches/rk3568.flag b/patches/rk3568.flag new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391