18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Kernel Connection Multiplexor
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2016 Tom Herbert <tom@herbertland.com>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#ifndef __NET_KCM_H_
98c2ecf20Sopenharmony_ci#define __NET_KCM_H_
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
128c2ecf20Sopenharmony_ci#include <net/sock.h>
138c2ecf20Sopenharmony_ci#include <net/strparser.h>
148c2ecf20Sopenharmony_ci#include <uapi/linux/kcm.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ciextern unsigned int kcm_net_id;
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define KCM_STATS_ADD(stat, count) ((stat) += (count))
198c2ecf20Sopenharmony_ci#define KCM_STATS_INCR(stat) ((stat)++)
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistruct kcm_psock_stats {
228c2ecf20Sopenharmony_ci	unsigned long long tx_msgs;
238c2ecf20Sopenharmony_ci	unsigned long long tx_bytes;
248c2ecf20Sopenharmony_ci	unsigned long long reserved;
258c2ecf20Sopenharmony_ci	unsigned long long unreserved;
268c2ecf20Sopenharmony_ci	unsigned int tx_aborts;
278c2ecf20Sopenharmony_ci};
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistruct kcm_mux_stats {
308c2ecf20Sopenharmony_ci	unsigned long long rx_msgs;
318c2ecf20Sopenharmony_ci	unsigned long long rx_bytes;
328c2ecf20Sopenharmony_ci	unsigned long long tx_msgs;
338c2ecf20Sopenharmony_ci	unsigned long long tx_bytes;
348c2ecf20Sopenharmony_ci	unsigned int rx_ready_drops;
358c2ecf20Sopenharmony_ci	unsigned int tx_retries;
368c2ecf20Sopenharmony_ci	unsigned int psock_attach;
378c2ecf20Sopenharmony_ci	unsigned int psock_unattach_rsvd;
388c2ecf20Sopenharmony_ci	unsigned int psock_unattach;
398c2ecf20Sopenharmony_ci};
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistruct kcm_stats {
428c2ecf20Sopenharmony_ci	unsigned long long rx_msgs;
438c2ecf20Sopenharmony_ci	unsigned long long rx_bytes;
448c2ecf20Sopenharmony_ci	unsigned long long tx_msgs;
458c2ecf20Sopenharmony_ci	unsigned long long tx_bytes;
468c2ecf20Sopenharmony_ci};
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistruct kcm_tx_msg {
498c2ecf20Sopenharmony_ci	unsigned int sent;
508c2ecf20Sopenharmony_ci	unsigned int fragidx;
518c2ecf20Sopenharmony_ci	unsigned int frag_offset;
528c2ecf20Sopenharmony_ci	unsigned int msg_flags;
538c2ecf20Sopenharmony_ci	struct sk_buff *frag_skb;
548c2ecf20Sopenharmony_ci	struct sk_buff *last_skb;
558c2ecf20Sopenharmony_ci};
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci/* Socket structure for KCM client sockets */
588c2ecf20Sopenharmony_cistruct kcm_sock {
598c2ecf20Sopenharmony_ci	struct sock sk;
608c2ecf20Sopenharmony_ci	struct kcm_mux *mux;
618c2ecf20Sopenharmony_ci	struct list_head kcm_sock_list;
628c2ecf20Sopenharmony_ci	int index;
638c2ecf20Sopenharmony_ci	u32 done : 1;
648c2ecf20Sopenharmony_ci	struct work_struct done_work;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	struct kcm_stats stats;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	/* Transmit */
698c2ecf20Sopenharmony_ci	struct kcm_psock *tx_psock;
708c2ecf20Sopenharmony_ci	struct work_struct tx_work;
718c2ecf20Sopenharmony_ci	struct list_head wait_psock_list;
728c2ecf20Sopenharmony_ci	struct sk_buff *seq_skb;
738c2ecf20Sopenharmony_ci	u32 tx_stopped : 1;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	/* Don't use bit fields here, these are set under different locks */
768c2ecf20Sopenharmony_ci	bool tx_wait;
778c2ecf20Sopenharmony_ci	bool tx_wait_more;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	/* Receive */
808c2ecf20Sopenharmony_ci	struct kcm_psock *rx_psock;
818c2ecf20Sopenharmony_ci	struct list_head wait_rx_list; /* KCMs waiting for receiving */
828c2ecf20Sopenharmony_ci	bool rx_wait;
838c2ecf20Sopenharmony_ci	u32 rx_disabled : 1;
848c2ecf20Sopenharmony_ci};
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistruct bpf_prog;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci/* Structure for an attached lower socket */
898c2ecf20Sopenharmony_cistruct kcm_psock {
908c2ecf20Sopenharmony_ci	struct sock *sk;
918c2ecf20Sopenharmony_ci	struct strparser strp;
928c2ecf20Sopenharmony_ci	struct kcm_mux *mux;
938c2ecf20Sopenharmony_ci	int index;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	u32 tx_stopped : 1;
968c2ecf20Sopenharmony_ci	u32 done : 1;
978c2ecf20Sopenharmony_ci	u32 unattaching : 1;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	void (*save_state_change)(struct sock *sk);
1008c2ecf20Sopenharmony_ci	void (*save_data_ready)(struct sock *sk);
1018c2ecf20Sopenharmony_ci	void (*save_write_space)(struct sock *sk);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	struct list_head psock_list;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	struct kcm_psock_stats stats;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	/* Receive */
1088c2ecf20Sopenharmony_ci	struct list_head psock_ready_list;
1098c2ecf20Sopenharmony_ci	struct bpf_prog *bpf_prog;
1108c2ecf20Sopenharmony_ci	struct kcm_sock *rx_kcm;
1118c2ecf20Sopenharmony_ci	unsigned long long saved_rx_bytes;
1128c2ecf20Sopenharmony_ci	unsigned long long saved_rx_msgs;
1138c2ecf20Sopenharmony_ci	struct sk_buff *ready_rx_msg;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	/* Transmit */
1168c2ecf20Sopenharmony_ci	struct kcm_sock *tx_kcm;
1178c2ecf20Sopenharmony_ci	struct list_head psock_avail_list;
1188c2ecf20Sopenharmony_ci	unsigned long long saved_tx_bytes;
1198c2ecf20Sopenharmony_ci	unsigned long long saved_tx_msgs;
1208c2ecf20Sopenharmony_ci};
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci/* Per net MUX list */
1238c2ecf20Sopenharmony_cistruct kcm_net {
1248c2ecf20Sopenharmony_ci	struct mutex mutex;
1258c2ecf20Sopenharmony_ci	struct kcm_psock_stats aggregate_psock_stats;
1268c2ecf20Sopenharmony_ci	struct kcm_mux_stats aggregate_mux_stats;
1278c2ecf20Sopenharmony_ci	struct strp_aggr_stats aggregate_strp_stats;
1288c2ecf20Sopenharmony_ci	struct list_head mux_list;
1298c2ecf20Sopenharmony_ci	int count;
1308c2ecf20Sopenharmony_ci};
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci/* Structure for a MUX */
1338c2ecf20Sopenharmony_cistruct kcm_mux {
1348c2ecf20Sopenharmony_ci	struct list_head kcm_mux_list;
1358c2ecf20Sopenharmony_ci	struct rcu_head rcu;
1368c2ecf20Sopenharmony_ci	struct kcm_net *knet;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	struct list_head kcm_socks;	/* All KCM sockets on MUX */
1398c2ecf20Sopenharmony_ci	int kcm_socks_cnt;		/* Total KCM socket count for MUX */
1408c2ecf20Sopenharmony_ci	struct list_head psocks;	/* List of all psocks on MUX */
1418c2ecf20Sopenharmony_ci	int psocks_cnt;		/* Total attached sockets */
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	struct kcm_mux_stats stats;
1448c2ecf20Sopenharmony_ci	struct kcm_psock_stats aggregate_psock_stats;
1458c2ecf20Sopenharmony_ci	struct strp_aggr_stats aggregate_strp_stats;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	/* Receive */
1488c2ecf20Sopenharmony_ci	spinlock_t rx_lock ____cacheline_aligned_in_smp;
1498c2ecf20Sopenharmony_ci	struct list_head kcm_rx_waiters; /* KCMs waiting for receiving */
1508c2ecf20Sopenharmony_ci	struct list_head psocks_ready;	/* List of psocks with a msg ready */
1518c2ecf20Sopenharmony_ci	struct sk_buff_head rx_hold_queue;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	/* Transmit */
1548c2ecf20Sopenharmony_ci	spinlock_t  lock ____cacheline_aligned_in_smp;	/* TX and mux locking */
1558c2ecf20Sopenharmony_ci	struct list_head psocks_avail;	/* List of available psocks */
1568c2ecf20Sopenharmony_ci	struct list_head kcm_tx_waiters; /* KCMs waiting for a TX psock */
1578c2ecf20Sopenharmony_ci};
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS
1608c2ecf20Sopenharmony_ciint kcm_proc_init(void);
1618c2ecf20Sopenharmony_civoid kcm_proc_exit(void);
1628c2ecf20Sopenharmony_ci#else
1638c2ecf20Sopenharmony_cistatic inline int kcm_proc_init(void) { return 0; }
1648c2ecf20Sopenharmony_cistatic inline void kcm_proc_exit(void) { }
1658c2ecf20Sopenharmony_ci#endif
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic inline void aggregate_psock_stats(struct kcm_psock_stats *stats,
1688c2ecf20Sopenharmony_ci					 struct kcm_psock_stats *agg_stats)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	/* Save psock statistics in the mux when psock is being unattached. */
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci#define SAVE_PSOCK_STATS(_stat) (agg_stats->_stat += stats->_stat)
1738c2ecf20Sopenharmony_ci	SAVE_PSOCK_STATS(tx_msgs);
1748c2ecf20Sopenharmony_ci	SAVE_PSOCK_STATS(tx_bytes);
1758c2ecf20Sopenharmony_ci	SAVE_PSOCK_STATS(reserved);
1768c2ecf20Sopenharmony_ci	SAVE_PSOCK_STATS(unreserved);
1778c2ecf20Sopenharmony_ci	SAVE_PSOCK_STATS(tx_aborts);
1788c2ecf20Sopenharmony_ci#undef SAVE_PSOCK_STATS
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic inline void aggregate_mux_stats(struct kcm_mux_stats *stats,
1828c2ecf20Sopenharmony_ci				       struct kcm_mux_stats *agg_stats)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	/* Save psock statistics in the mux when psock is being unattached. */
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci#define SAVE_MUX_STATS(_stat) (agg_stats->_stat += stats->_stat)
1878c2ecf20Sopenharmony_ci	SAVE_MUX_STATS(rx_msgs);
1888c2ecf20Sopenharmony_ci	SAVE_MUX_STATS(rx_bytes);
1898c2ecf20Sopenharmony_ci	SAVE_MUX_STATS(tx_msgs);
1908c2ecf20Sopenharmony_ci	SAVE_MUX_STATS(tx_bytes);
1918c2ecf20Sopenharmony_ci	SAVE_MUX_STATS(rx_ready_drops);
1928c2ecf20Sopenharmony_ci	SAVE_MUX_STATS(psock_attach);
1938c2ecf20Sopenharmony_ci	SAVE_MUX_STATS(psock_unattach_rsvd);
1948c2ecf20Sopenharmony_ci	SAVE_MUX_STATS(psock_unattach);
1958c2ecf20Sopenharmony_ci#undef SAVE_MUX_STATS
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci#endif /* __NET_KCM_H_ */
199