From: "D. Wythe" <alibuda@xxxxxxxxxxxxxxxxx> smc_negotiation is a new way to describe the state of the SMC protocol, note that it will only be used by inet sock. It mainly describes the following states of SMC sock: TBD: Before TCP handshake is completed. PREPARE: TCP is established, and smc is establishing. SMC: smc handshake is established. NO_SMC: sock should act as TCP. Before this patch, it is determined that these conditions must be applied simultaneously to syn_smc/use_fallback/sk_state, synchronization of fields needs to be handled with care, while syn_smc field cannot be modified at any time. Based on these considerations, inet sock uses smc_negotiation to control the protocol state. Signed-off-by: D. Wythe <alibuda@xxxxxxxxxxxxxxxxx> --- net/smc/smc.h | 1 + net/smc/smc_inet.h | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/net/smc/smc.h b/net/smc/smc.h index 1675193..538920f 100644 --- a/net/smc/smc.h +++ b/net/smc/smc.h @@ -252,6 +252,7 @@ struct smc_sock { /* smc sock container */ }; struct socket *clcsock; /* internal tcp socket */ unsigned char smc_state; /* smc state used in smc via inet_sk */ + unsigned int isck_smc_negotiation; unsigned long smc_sk_flags; /* smc sock flags used for inet sock */ void (*clcsk_state_change)(struct sock *sk); /* original stat_change fct. */ diff --git a/net/smc/smc_inet.h b/net/smc/smc_inet.h index 68ecfa0..1f182c0 100644 --- a/net/smc/smc_inet.h +++ b/net/smc/smc_inet.h @@ -18,6 +18,9 @@ /* MUST after net/tcp.h or warning */ #include <net/transp_v6.h> +#include <net/smc.h> +#include "smc.h" + extern struct proto smc_inet_prot; extern struct proto smc_inet6_prot; @@ -27,6 +30,99 @@ extern struct inet_protosw smc_inet_protosw; extern struct inet_protosw smc_inet6_protosw; +enum smc_inet_sock_negotiation_state { + /* When creating an AF_SMC sock, the state field will be initialized to 0 by default, + * which is only for logical compatibility with that situation + * and will never be used. + */ + SMC_NEGOTIATION_COMPATIBLE_WITH_AF_SMC = 0, + + /* This connection is still uncertain whether it is an SMC connection or not, + * It always appears when actively open SMC connection, because it's unclear + * whether the server supports the SMC protocol and has willing to use SMC. + */ + SMC_NEGOTIATION_TBD = 0x10, + + /* This state indicates that this connection is definitely not an SMC connection. + * and it is absolutely impossible to become an SMC connection again. A fina + * state. + */ + SMC_NEGOTIATION_NO_SMC = 0x20, + + /* This state indicates that this connection is an SMC connection. and it is + * absolutely impossible to become an not-SMC connection again. A final state. + */ + SMC_NEGOTIATION_SMC = 0x40, + + /* This state indicates that this connection is in the process of SMC handshake. + * It is mainly used to eliminate the ambiguity of syn_smc, because when syn_smc is 1, + * It may represent remote has support for SMC, or it may just indicate that itself has + * supports for SMC. + */ + SMC_NEGOTIATION_PREPARE_SMC = 0x80, + + /* flags */ + SMC_NEGOTIATION_LISTEN_FLAG = 0x01, + SMC_NEGOTIATION_ABORT_FLAG = 0x02, +}; + +static __always_inline void isck_smc_negotiation_store(struct smc_sock *smc, + enum smc_inet_sock_negotiation_state state) +{ + WRITE_ONCE(smc->isck_smc_negotiation, + state | (READ_ONCE(smc->isck_smc_negotiation) & 0x0f)); +} + +static __always_inline int isck_smc_negotiation_load(struct smc_sock *smc) +{ + return READ_ONCE(smc->isck_smc_negotiation) & 0xf0; +} + +static __always_inline void isck_smc_negotiation_set_flags(struct smc_sock *smc, int flags) +{ + smc->isck_smc_negotiation = (smc->isck_smc_negotiation | (flags & 0x0f)); +} + +static __always_inline int isck_smc_negotiation_get_flags(struct smc_sock *smc) +{ + return smc->isck_smc_negotiation & 0x0f; +} + +static __always_inline bool smc_inet_sock_check_fallback_fast(struct sock *sk) +{ + return !tcp_sk(sk)->syn_smc; +} + +static __always_inline bool smc_inet_sock_check_fallback(struct sock *sk) +{ + return isck_smc_negotiation_load(smc_sk(sk)) == SMC_NEGOTIATION_NO_SMC; +} + +static __always_inline bool smc_inet_sock_check_smc(struct sock *sk) +{ + if (smc_inet_sock_check_fallback_fast(sk)) + return false; + + return isck_smc_negotiation_load(smc_sk(sk)) == SMC_NEGOTIATION_SMC; +} + +static __always_inline bool smc_inet_sock_is_active_open(struct sock *sk) +{ + return !(isck_smc_negotiation_get_flags(smc_sk(sk)) & SMC_NEGOTIATION_LISTEN_FLAG); +} + +static inline void smc_inet_sock_abort(struct sock *sk) +{ + write_lock_bh(&sk->sk_callback_lock); + if (isck_smc_negotiation_get_flags(smc_sk(sk)) & SMC_NEGOTIATION_ABORT_FLAG) { + write_unlock_bh(&sk->sk_callback_lock); + return; + } + isck_smc_negotiation_set_flags(smc_sk(sk), SMC_NEGOTIATION_ABORT_FLAG); + write_unlock_bh(&sk->sk_callback_lock); + sk->sk_error_report(sk); +} + /* obtain TCP proto via sock family */ static __always_inline struct proto *smc_inet_get_tcp_prot(int family) { -- 1.8.3.1