linux/net/netfilter/ipvs/ip_vs_ctl.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * IPVS         An implementation of the IP virtual server support for the
 *              LINUX operating system.  IPVS is now implemented as a module
 *              over the NetFilter framework. IPVS can be used to build a
 *              high-performance and highly available server based on a
 *              cluster of servers.
 *
 * Authors:     Wensong Zhang <[email protected]>
 *              Peter Kese <[email protected]>
 *              Julian Anastasov <[email protected]>
 *
 * Changes:
 */

#define KMSG_COMPONENT
#define pr_fmt(fmt)

#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/capability.h>
#include <linux/fs.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/workqueue.h>
#include <linux/seq_file.h>
#include <linux/slab.h>

#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/mutex.h>

#include <net/net_namespace.h>
#include <linux/nsproxy.h>
#include <net/ip.h>
#ifdef CONFIG_IP_VS_IPV6
#include <net/ipv6.h>
#include <net/ip6_route.h>
#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
#endif
#include <net/route.h>
#include <net/sock.h>
#include <net/genetlink.h>

#include <linux/uaccess.h>

#include <net/ip_vs.h>

MODULE_ALIAS_GENL_FAMILY();

DEFINE_MUTEX(); /* Serialize configuration with sockopt/netlink */

/* sysctl variables */

#ifdef CONFIG_IP_VS_DEBUG
static int sysctl_ip_vs_debug_level =;

int ip_vs_get_debug_level(void)
{}
#endif


/*  Protos */
static void __ip_vs_del_service(struct ip_vs_service *svc, bool cleanup);


#ifdef CONFIG_IP_VS_IPV6
/* Taken from rt6_fill_node() in net/ipv6/route.c, is there a better way? */
static bool __ip_vs_addr_is_local_v6(struct net *net,
				     const struct in6_addr *addr)
{}
#endif

#ifdef CONFIG_SYSCTL
/*
 *	update_defense_level is called from keventd and from sysctl,
 *	so it needs to protect itself from softirqs
 */
static void update_defense_level(struct netns_ipvs *ipvs)
{}

/* Handler for delayed work for expiring no
 * destination connections
 */
static void expire_nodest_conn_handler(struct work_struct *work)
{}

/*
 *	Timer for checking the defense
 */
#define DEFENSE_TIMER_PERIOD

static void defense_work_handler(struct work_struct *work)
{}
#endif

static void est_reload_work_handler(struct work_struct *work)
{}

int
ip_vs_use_count_inc(void)
{}

void
ip_vs_use_count_dec(void)
{}


/*
 *	Hash table: for virtual service lookups
 */
#define IP_VS_SVC_TAB_BITS
#define IP_VS_SVC_TAB_SIZE
#define IP_VS_SVC_TAB_MASK

/* the service table hashed by <protocol, addr, port> */
static struct hlist_head ip_vs_svc_table[IP_VS_SVC_TAB_SIZE];
/* the service table hashed by fwmark */
static struct hlist_head ip_vs_svc_fwm_table[IP_VS_SVC_TAB_SIZE];


/*
 *	Returns hash value for virtual service
 */
static inline unsigned int
ip_vs_svc_hashkey(struct netns_ipvs *ipvs, int af, unsigned int proto,
		  const union nf_inet_addr *addr, __be16 port)
{}

/*
 *	Returns hash value of fwmark for virtual service lookup
 */
static inline unsigned int ip_vs_svc_fwm_hashkey(struct netns_ipvs *ipvs, __u32 fwmark)
{}

/*
 *	Hashes a service in the ip_vs_svc_table by <netns,proto,addr,port>
 *	or in the ip_vs_svc_fwm_table by fwmark.
 *	Should be called with locked tables.
 */
static int ip_vs_svc_hash(struct ip_vs_service *svc)
{}


/*
 *	Unhashes a service from svc_table / svc_fwm_table.
 *	Should be called with locked tables.
 */
static int ip_vs_svc_unhash(struct ip_vs_service *svc)
{}


/*
 *	Get service by {netns, proto,addr,port} in the service table.
 */
static inline struct ip_vs_service *
__ip_vs_service_find(struct netns_ipvs *ipvs, int af, __u16 protocol,
		     const union nf_inet_addr *vaddr, __be16 vport)
{}


/*
 *	Get service by {fwmark} in the service table.
 */
static inline struct ip_vs_service *
__ip_vs_svc_fwm_find(struct netns_ipvs *ipvs, int af, __u32 fwmark)
{}

/* Find service, called under RCU lock */
struct ip_vs_service *
ip_vs_service_find(struct netns_ipvs *ipvs, int af, __u32 fwmark, __u16 protocol,
		   const union nf_inet_addr *vaddr, __be16 vport)
{}


static inline void
__ip_vs_bind_svc(struct ip_vs_dest *dest, struct ip_vs_service *svc)
{}

static void ip_vs_service_free(struct ip_vs_service *svc)
{}

static void ip_vs_service_rcu_free(struct rcu_head *head)
{}

static void __ip_vs_svc_put(struct ip_vs_service *svc)
{}


/*
 *	Returns hash value for real service
 */
static inline unsigned int ip_vs_rs_hashkey(int af,
					    const union nf_inet_addr *addr,
					    __be16 port)
{}

/* Hash ip_vs_dest in rs_table by <proto,addr,port>. */
static void ip_vs_rs_hash(struct netns_ipvs *ipvs, struct ip_vs_dest *dest)
{}

/* Unhash ip_vs_dest from rs_table. */
static void ip_vs_rs_unhash(struct ip_vs_dest *dest)
{}

/* Check if real service by <proto,addr,port> is present */
bool ip_vs_has_real_service(struct netns_ipvs *ipvs, int af, __u16 protocol,
			    const union nf_inet_addr *daddr, __be16 dport)
{}

/* Find real service record by <proto,addr,port>.
 * In case of multiple records with the same <proto,addr,port>, only
 * the first found record is returned.
 *
 * To be called under RCU lock.
 */
struct ip_vs_dest *ip_vs_find_real_service(struct netns_ipvs *ipvs, int af,
					   __u16 protocol,
					   const union nf_inet_addr *daddr,
					   __be16 dport)
{}

/* Find real service record by <af,addr,tun_port>.
 * In case of multiple records with the same <af,addr,tun_port>, only
 * the first found record is returned.
 *
 * To be called under RCU lock.
 */
struct ip_vs_dest *ip_vs_find_tunnel(struct netns_ipvs *ipvs, int af,
				     const union nf_inet_addr *daddr,
				     __be16 tun_port)
{}

/* Lookup destination by {addr,port} in the given service
 * Called under RCU lock.
 */
static struct ip_vs_dest *
ip_vs_lookup_dest(struct ip_vs_service *svc, int dest_af,
		  const union nf_inet_addr *daddr, __be16 dport)
{}

/*
 * Find destination by {daddr,dport,vaddr,protocol}
 * Created to be used in ip_vs_process_message() in
 * the backup synchronization daemon. It finds the
 * destination to be bound to the received connection
 * on the backup.
 * Called under RCU lock, no refcnt is returned.
 */
struct ip_vs_dest *ip_vs_find_dest(struct netns_ipvs *ipvs, int svc_af, int dest_af,
				   const union nf_inet_addr *daddr,
				   __be16 dport,
				   const union nf_inet_addr *vaddr,
				   __be16 vport, __u16 protocol, __u32 fwmark,
				   __u32 flags)
{}

void ip_vs_dest_dst_rcu_free(struct rcu_head *head)
{}

/* Release dest_dst and dst_cache for dest in user context */
static void __ip_vs_dst_cache_reset(struct ip_vs_dest *dest)
{}

/*
 *  Lookup dest by {svc,addr,port} in the destination trash.
 *  The destination trash is used to hold the destinations that are removed
 *  from the service table but are still referenced by some conn entries.
 *  The reason to add the destination trash is when the dest is temporary
 *  down (either by administrator or by monitor program), the dest can be
 *  picked back from the trash, the remaining connections to the dest can
 *  continue, and the counting information of the dest is also useful for
 *  scheduling.
 */
static struct ip_vs_dest *
ip_vs_trash_get_dest(struct ip_vs_service *svc, int dest_af,
		     const union nf_inet_addr *daddr, __be16 dport)
{}

static void ip_vs_dest_rcu_free(struct rcu_head *head)
{}

static void ip_vs_dest_free(struct ip_vs_dest *dest)
{}

/*
 *  Clean up all the destinations in the trash
 *  Called by the ip_vs_control_cleanup()
 *
 *  When the ip_vs_control_clearup is activated by ipvs module exit,
 *  the service tables must have been flushed and all the connections
 *  are expired, and the refcnt of each destination in the trash must
 *  be 1, so we simply release them here.
 */
static void ip_vs_trash_cleanup(struct netns_ipvs *ipvs)
{}

static void ip_vs_stats_rcu_free(struct rcu_head *head)
{}

static void
ip_vs_copy_stats(struct ip_vs_kstats *dst, struct ip_vs_stats *src)
{}

static void
ip_vs_export_stats_user(struct ip_vs_stats_user *dst, struct ip_vs_kstats *src)
{}

static void
ip_vs_zero_stats(struct ip_vs_stats *stats)
{}

/* Allocate fields after kzalloc */
int ip_vs_stats_init_alloc(struct ip_vs_stats *s)
{}

struct ip_vs_stats *ip_vs_stats_alloc(void)
{}

void ip_vs_stats_release(struct ip_vs_stats *stats)
{}

void ip_vs_stats_free(struct ip_vs_stats *stats)
{}

/*
 *	Update a destination in the given service
 */
static void
__ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
		    struct ip_vs_dest_user_kern *udest, int add)
{}


/*
 *	Create a destination for the given service
 */
static int
ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
{}


/*
 *	Add a destination into an existing service
 */
static int
ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
{}


/*
 *	Edit a destination in the given service
 */
static int
ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
{}

/*
 *	Delete a destination (must be already unlinked from the service)
 */
static void __ip_vs_del_dest(struct netns_ipvs *ipvs, struct ip_vs_dest *dest,
			     bool cleanup)
{}


/*
 *	Unlink a destination from the given service
 */
static void __ip_vs_unlink_dest(struct ip_vs_service *svc,
				struct ip_vs_dest *dest,
				int svcupd)
{}


/*
 *	Delete a destination server in the given service
 */
static int
ip_vs_del_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
{}

static void ip_vs_dest_trash_expire(struct timer_list *t)
{}

/*
 *	Add a service into the service hash table
 */
static int
ip_vs_add_service(struct netns_ipvs *ipvs, struct ip_vs_service_user_kern *u,
		  struct ip_vs_service **svc_p)
{}


/*
 *	Edit a service and bind it with a new scheduler
 */
static int
ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
{}

/*
 *	Delete a service from the service list
 *	- The service must be unlinked, unlocked and not referenced!
 *	- We are called under _bh lock
 */
static void __ip_vs_del_service(struct ip_vs_service *svc, bool cleanup)
{}

/*
 * Unlink a service from list and try to delete it if its refcnt reached 0
 */
static void ip_vs_unlink_service(struct ip_vs_service *svc, bool cleanup)
{}

/*
 *	Delete a service from the service list
 */
static int ip_vs_del_service(struct ip_vs_service *svc)
{}


/*
 *	Flush all the virtual services
 */
static int ip_vs_flush(struct netns_ipvs *ipvs, bool cleanup)
{}

/*
 *	Delete service by {netns} in the service table.
 *	Called by __ip_vs_batch_cleanup()
 */
void ip_vs_service_nets_cleanup(struct list_head *net_list)
{}

/* Put all references for device (dst_cache) */
static inline void
ip_vs_forget_dev(struct ip_vs_dest *dest, struct net_device *dev)
{}
/* Netdev event receiver
 * Currently only NETDEV_DOWN is handled to release refs to cached dsts
 */
static int ip_vs_dst_event(struct notifier_block *this, unsigned long event,
			   void *ptr)
{}

/*
 *	Zero counters in a service or all services
 */
static int ip_vs_zero_service(struct ip_vs_service *svc)
{}

static int ip_vs_zero_all(struct netns_ipvs *ipvs)
{}

#ifdef CONFIG_SYSCTL

static int
proc_do_defense_mode(const struct ctl_table *table, int write,
		     void *buffer, size_t *lenp, loff_t *ppos)
{}

static int
proc_do_sync_threshold(const struct ctl_table *table, int write,
		       void *buffer, size_t *lenp, loff_t *ppos)
{}

static int
proc_do_sync_ports(const struct ctl_table *table, int write,
		   void *buffer, size_t *lenp, loff_t *ppos)
{}

static int ipvs_proc_est_cpumask_set(const struct ctl_table *table,
				     void *buffer)
{}

static int ipvs_proc_est_cpumask_get(const struct ctl_table *table,
				     void *buffer, size_t size)
{}

static int ipvs_proc_est_cpulist(const struct ctl_table *table, int write,
				 void *buffer, size_t *lenp, loff_t *ppos)
{}

static int ipvs_proc_est_nice(const struct ctl_table *table, int write,
			      void *buffer, size_t *lenp, loff_t *ppos)
{}

static int ipvs_proc_run_estimation(const struct ctl_table *table, int write,
				    void *buffer, size_t *lenp, loff_t *ppos)
{}

/*
 *	IPVS sysctl table (under the /proc/sys/net/ipv4/vs/)
 *	Do not change order or insert new entries without
 *	align with netns init in ip_vs_control_net_init()
 */

static struct ctl_table vs_vars[] =;

#endif

#ifdef CONFIG_PROC_FS

struct ip_vs_iter {};

/*
 *	Write the contents of the VS rule table to a PROCfs file.
 *	(It is kept just for backward compatibility)
 */
static inline const char *ip_vs_fwd_name(unsigned int flags)
{}


/* Get the Nth entry in the two lists */
static struct ip_vs_service *ip_vs_info_array(struct seq_file *seq, loff_t pos)
{}

static void *ip_vs_info_seq_start(struct seq_file *seq, loff_t *pos)
	__acquires(RCU)
{}


static void *ip_vs_info_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{}

static void ip_vs_info_seq_stop(struct seq_file *seq, void *v)
	__releases(RCU)
{}


static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
{}

static const struct seq_operations ip_vs_info_seq_ops =;

static int ip_vs_stats_show(struct seq_file *seq, void *v)
{}

static int ip_vs_stats_percpu_show(struct seq_file *seq, void *v)
{}
#endif

/*
 *	Set timeout values for tcp tcpfin udp in the timeout_table.
 */
static int ip_vs_set_timeout(struct netns_ipvs *ipvs, struct ip_vs_timeout_user *u)
{}

#define CMDID(cmd)

struct ip_vs_svcdest_user {};

static const unsigned char set_arglen[CMDID(IP_VS_SO_SET_MAX) + 1] =;

ip_vs_set_arglen;

#define MAX_SET_ARGLEN

static void ip_vs_copy_usvc_compat(struct ip_vs_service_user_kern *usvc,
				  struct ip_vs_service_user *usvc_compat)
{}

static void ip_vs_copy_udest_compat(struct ip_vs_dest_user_kern *udest,
				   struct ip_vs_dest_user *udest_compat)
{}

static int
do_ip_vs_set_ctl(struct sock *sk, int cmd, sockptr_t ptr, unsigned int len)
{}


static void
ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src)
{}

static inline int
__ip_vs_get_service_entries(struct netns_ipvs *ipvs,
			    const struct ip_vs_get_services *get,
			    struct ip_vs_get_services __user *uptr)
{}

static inline int
__ip_vs_get_dest_entries(struct netns_ipvs *ipvs, const struct ip_vs_get_dests *get,
			 struct ip_vs_get_dests __user *uptr)
{}

static inline void
__ip_vs_get_timeouts(struct netns_ipvs *ipvs, struct ip_vs_timeout_user *u)
{}

static const unsigned char get_arglen[CMDID(IP_VS_SO_GET_MAX) + 1] =;

ip_vs_get_arglen;

#define MAX_GET_ARGLEN

static int
do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
{}


static struct nf_sockopt_ops ip_vs_sockopts =;

/*
 * Generic Netlink interface
 */

/* IPVS genetlink family */
static struct genl_family ip_vs_genl_family;

/* Policy used for first-level command attributes */
static const struct nla_policy ip_vs_cmd_policy[IPVS_CMD_ATTR_MAX + 1] =;

/* Policy used for attributes in nested attribute IPVS_CMD_ATTR_DAEMON */
static const struct nla_policy ip_vs_daemon_policy[IPVS_DAEMON_ATTR_MAX + 1] =;

/* Policy used for attributes in nested attribute IPVS_CMD_ATTR_SERVICE */
static const struct nla_policy ip_vs_svc_policy[IPVS_SVC_ATTR_MAX + 1] =;

/* Policy used for attributes in nested attribute IPVS_CMD_ATTR_DEST */
static const struct nla_policy ip_vs_dest_policy[IPVS_DEST_ATTR_MAX + 1] =;

static int ip_vs_genl_fill_stats(struct sk_buff *skb, int container_type,
				 struct ip_vs_kstats *kstats)
{}

static int ip_vs_genl_fill_stats64(struct sk_buff *skb, int container_type,
				   struct ip_vs_kstats *kstats)
{}

static int ip_vs_genl_fill_service(struct sk_buff *skb,
				   struct ip_vs_service *svc)
{}

static int ip_vs_genl_dump_service(struct sk_buff *skb,
				   struct ip_vs_service *svc,
				   struct netlink_callback *cb)
{}

static int ip_vs_genl_dump_services(struct sk_buff *skb,
				    struct netlink_callback *cb)
{}

static bool ip_vs_is_af_valid(int af)
{}

static int ip_vs_genl_parse_service(struct netns_ipvs *ipvs,
				    struct ip_vs_service_user_kern *usvc,
				    struct nlattr *nla, bool full_entry,
				    struct ip_vs_service **ret_svc)
{}

static struct ip_vs_service *ip_vs_genl_find_service(struct netns_ipvs *ipvs,
						     struct nlattr *nla)
{}

static int ip_vs_genl_fill_dest(struct sk_buff *skb, struct ip_vs_dest *dest)
{}

static int ip_vs_genl_dump_dest(struct sk_buff *skb, struct ip_vs_dest *dest,
				struct netlink_callback *cb)
{}

static int ip_vs_genl_dump_dests(struct sk_buff *skb,
				 struct netlink_callback *cb)
{}

static int ip_vs_genl_parse_dest(struct ip_vs_dest_user_kern *udest,
				 struct nlattr *nla, bool full_entry)
{}

static int ip_vs_genl_fill_daemon(struct sk_buff *skb, __u32 state,
				  struct ipvs_sync_daemon_cfg *c)
{}

static int ip_vs_genl_dump_daemon(struct sk_buff *skb, __u32 state,
				  struct ipvs_sync_daemon_cfg *c,
				  struct netlink_callback *cb)
{}

static int ip_vs_genl_dump_daemons(struct sk_buff *skb,
				   struct netlink_callback *cb)
{}

static int ip_vs_genl_new_daemon(struct netns_ipvs *ipvs, struct nlattr **attrs)
{}

static int ip_vs_genl_del_daemon(struct netns_ipvs *ipvs, struct nlattr **attrs)
{}

static int ip_vs_genl_set_config(struct netns_ipvs *ipvs, struct nlattr **attrs)
{}

static int ip_vs_genl_set_daemon(struct sk_buff *skb, struct genl_info *info)
{}

static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
{}

static int ip_vs_genl_get_cmd(struct sk_buff *skb, struct genl_info *info)
{}


static const struct genl_small_ops ip_vs_genl_ops[] =;

static struct genl_family ip_vs_genl_family __ro_after_init =;

static int __init ip_vs_genl_register(void)
{}

static void ip_vs_genl_unregister(void)
{}

/* End of Generic Netlink interface definitions */

/*
 * per netns intit/exit func.
 */
#ifdef CONFIG_SYSCTL
static int __net_init ip_vs_control_net_init_sysctl(struct netns_ipvs *ipvs)
{}

static void __net_exit ip_vs_control_net_cleanup_sysctl(struct netns_ipvs *ipvs)
{}

#else

static int __net_init ip_vs_control_net_init_sysctl(struct netns_ipvs *ipvs) { return 0; }
static void __net_exit ip_vs_control_net_cleanup_sysctl(struct netns_ipvs *ipvs) { }

#endif

static struct notifier_block ip_vs_dst_notifier =;

int __net_init ip_vs_control_net_init(struct netns_ipvs *ipvs)
{}

void __net_exit ip_vs_control_net_cleanup(struct netns_ipvs *ipvs)
{}

int __init ip_vs_register_nl_ioctl(void)
{}

void ip_vs_unregister_nl_ioctl(void)
{}

int __init ip_vs_control_init(void)
{}


void ip_vs_control_cleanup(void)
{}