diff options
author | vince <vince@36f5d8da-7431-0410-8ca5-ec586ed2521a> | 2008-09-16 20:05:13 +0000 |
---|---|---|
committer | Simon Horman <horms@verge.net.au> | 2013-05-22 15:04:54 +0900 |
commit | aa67eed57bf3edd79ed795b605ba7524e6c7de32 (patch) | |
tree | 6b0cdaf55c36c70eb8e8b32fe255d0faedcf9051 | |
parent | 0244758bed14cf8e4ab344d625f54b03766287b0 (diff) | |
download | ipvsadm-aa67eed57bf3edd79ed795b605ba7524e6c7de32.tar.gz |
More files to bring release up to 1.24 with IPv6 changes.
git-svn-id: http://svn.linuxvirtualserver.org/repos/ipvsadm/trunk@57 36f5d8da-7431-0410-8ca5-ec586ed2521a
-rw-r--r-- | contrib/popt-optional.diff | 25 | ||||
-rw-r--r-- | libipvs/Makefile | 32 | ||||
-rw-r--r-- | libipvs/ip_vs.h | 532 | ||||
-rw-r--r-- | libipvs/ip_vs_nl_policy.c | 70 | ||||
-rw-r--r-- | libipvs/libipvs.c | 1115 | ||||
-rw-r--r-- | libipvs/libipvs.h | 128 |
6 files changed, 1902 insertions, 0 deletions
diff --git a/contrib/popt-optional.diff b/contrib/popt-optional.diff new file mode 100644 index 0000000..00a085a --- /dev/null +++ b/contrib/popt-optional.diff @@ -0,0 +1,25 @@ +--- rpm-4.0.4/popt/popt.c~ Sat Jan 19 07:28:30 2002 ++++ rpm-4.0.4/popt/popt.c Fri Aug 9 17:08:15 2002 +@@ -840,12 +840,17 @@ + canstrip) { + poptStripArg(con, con->os->next); + } +- ++ + if (con->os->argv != NULL) { /* XXX can't happen */ +- /* XXX watchout: subtle side-effects live here. */ +- longArg = con->os->argv[con->os->next++]; +- longArg = expandNextArg(con, longArg); +- con->os->nextArg = longArg; ++ if (opt->argInfo & POPT_ARGFLAG_OPTIONAL && ++ con->os->argv[con->os->next][0] == '-') { ++ con->os->nextArg = NULL; ++ } else { ++ /* XXX watchout: subtle side-effects live here. */ ++ longArg = con->os->argv[con->os->next++]; ++ longArg = expandNextArg(con, longArg); ++ con->os->nextArg = longArg; ++ } + } + } + } diff --git a/libipvs/Makefile b/libipvs/Makefile new file mode 100644 index 0000000..ce4999d --- /dev/null +++ b/libipvs/Makefile @@ -0,0 +1,32 @@ +# Makefile for libipvs + +CC = gcc +CFLAGS = -Wall -Wunused -Wstrict-prototypes -g -fPIC +ifneq (0,$(HAVE_NL)) +CFLAGS += -DLIBIPVS_USE_NL +endif + +INCLUDE += $(shell if [ -f ../../ip_vs.h ]; then \ + echo "-I../../."; fi;) +DEFINES = $(shell if [ ! -f ../../ip_vs.h ]; then \ + echo "-DHAVE_NET_IP_VS_H"; fi;) + +.PHONY = all clean install dist distclean rpm rpms +STATIC_LIB = libipvs.a +SHARED_LIB = libipvs.so + +all: $(STATIC_LIB) $(SHARED_LIB) + +$(STATIC_LIB): libipvs.o ip_vs_nl_policy.o + ar rv $@ $^ + +$(SHARED_LIB): libipvs.o ip_vs_nl_policy.o + $(CC) -shared -Wl,-soname,$@ -o $@ $^ + +%.o: %.c + $(CC) $(CFLAGS) $(INCLUDE) $(DEFINES) -c -o $@ $< + +clean: + rm -f *.[ao] *~ *.orig *.rej core *.so + +distclean: clean diff --git a/libipvs/ip_vs.h b/libipvs/ip_vs.h new file mode 100644 index 0000000..e174424 --- /dev/null +++ b/libipvs/ip_vs.h @@ -0,0 +1,532 @@ +/* + * IP Virtual Server + * data structure and functionality definitions + */ + +#ifndef _IP_VS_H +#define _IP_VS_H + +#include <asm/types.h> /* For __uXX types */ +#include <linux/types.h> /* For __beXX types in userland */ + +#include <netinet/in.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> + +#ifdef LIBIPVS_USE_NL +#include <netlink/netlink.h> +#include <netlink/genl/genl.h> +#include <netlink/genl/ctrl.h> +#endif + +#define IP_VS_VERSION_CODE 0x010201 +#define NVERSION(version) \ + (version >> 16) & 0xFF, \ + (version >> 8) & 0xFF, \ + version & 0xFF + +/* + * Virtual Service Flags + */ +#define IP_VS_SVC_F_PERSISTENT 0x0001 /* persistent port */ +#define IP_VS_SVC_F_HASHED 0x0002 /* hashed entry */ + +/* + * Destination Server Flags + */ +#define IP_VS_DEST_F_AVAILABLE 0x0001 /* server is available */ +#define IP_VS_DEST_F_OVERLOAD 0x0002 /* server is overloaded */ + +/* + * IPVS sync daemon states + */ +#define IP_VS_STATE_NONE 0x0000 /* daemon is stopped */ +#define IP_VS_STATE_MASTER 0x0001 /* started as master */ +#define IP_VS_STATE_BACKUP 0x0002 /* started as backup */ + +/* + * IPVS socket options + */ +#define IP_VS_BASE_CTL (64+1024+64) /* base */ + +#define IP_VS_SO_SET_NONE IP_VS_BASE_CTL /* just peek */ +#define IP_VS_SO_SET_INSERT (IP_VS_BASE_CTL+1) +#define IP_VS_SO_SET_ADD (IP_VS_BASE_CTL+2) +#define IP_VS_SO_SET_EDIT (IP_VS_BASE_CTL+3) +#define IP_VS_SO_SET_DEL (IP_VS_BASE_CTL+4) +#define IP_VS_SO_SET_FLUSH (IP_VS_BASE_CTL+5) +#define IP_VS_SO_SET_LIST (IP_VS_BASE_CTL+6) +#define IP_VS_SO_SET_ADDDEST (IP_VS_BASE_CTL+7) +#define IP_VS_SO_SET_DELDEST (IP_VS_BASE_CTL+8) +#define IP_VS_SO_SET_EDITDEST (IP_VS_BASE_CTL+9) +#define IP_VS_SO_SET_TIMEOUT (IP_VS_BASE_CTL+10) +#define IP_VS_SO_SET_STARTDAEMON (IP_VS_BASE_CTL+11) +#define IP_VS_SO_SET_STOPDAEMON (IP_VS_BASE_CTL+12) +#define IP_VS_SO_SET_RESTORE (IP_VS_BASE_CTL+13) +#define IP_VS_SO_SET_SAVE (IP_VS_BASE_CTL+14) +#define IP_VS_SO_SET_ZERO (IP_VS_BASE_CTL+15) +#define IP_VS_SO_SET_MAX IP_VS_SO_SET_ZERO + +#define IP_VS_SO_GET_VERSION IP_VS_BASE_CTL +#define IP_VS_SO_GET_INFO (IP_VS_BASE_CTL+1) +#define IP_VS_SO_GET_SERVICES (IP_VS_BASE_CTL+2) +#define IP_VS_SO_GET_SERVICE (IP_VS_BASE_CTL+3) +#define IP_VS_SO_GET_DESTS (IP_VS_BASE_CTL+4) +#define IP_VS_SO_GET_DEST (IP_VS_BASE_CTL+5) /* not used now */ +#define IP_VS_SO_GET_TIMEOUT (IP_VS_BASE_CTL+6) +#define IP_VS_SO_GET_DAEMON (IP_VS_BASE_CTL+7) +#define IP_VS_SO_GET_MAX IP_VS_SO_GET_DAEMON + + +/* + * IPVS Connection Flags + */ +#define IP_VS_CONN_F_FWD_MASK 0x0007 /* mask for the fwd methods */ +#define IP_VS_CONN_F_MASQ 0x0000 /* masquerading/NAT */ +#define IP_VS_CONN_F_LOCALNODE 0x0001 /* local node */ +#define IP_VS_CONN_F_TUNNEL 0x0002 /* tunneling */ +#define IP_VS_CONN_F_DROUTE 0x0003 /* direct routing */ +#define IP_VS_CONN_F_BYPASS 0x0004 /* cache bypass */ +#define IP_VS_CONN_F_SYNC 0x0020 /* entry created by sync */ +#define IP_VS_CONN_F_HASHED 0x0040 /* hashed entry */ +#define IP_VS_CONN_F_NOOUTPUT 0x0080 /* no output packets */ +#define IP_VS_CONN_F_INACTIVE 0x0100 /* not established */ +#define IP_VS_CONN_F_OUT_SEQ 0x0200 /* must do output seq adjust */ +#define IP_VS_CONN_F_IN_SEQ 0x0400 /* must do input seq adjust */ +#define IP_VS_CONN_F_SEQ_MASK 0x0600 /* in/out sequence mask */ +#define IP_VS_CONN_F_NO_CPORT 0x0800 /* no client port set yet */ +#define IP_VS_CONN_F_TEMPLATE 0x1000 /* template, not connection */ + +/* Move it to better place one day, for now keep it unique */ +#define NFC_IPVS_PROPERTY 0x10000 + +#define IP_VS_SCHEDNAME_MAXLEN 16 +#define IP_VS_IFNAME_MAXLEN 16 + +union nf_inet_addr { + __u32 all[4]; + __be32 ip; + __be32 ip6[4]; + struct in_addr in; + struct in6_addr in6; +}; + +/* + * The struct ip_vs_service_user and struct ip_vs_dest_user are + * used to set IPVS rules through setsockopt. + */ +struct ip_vs_service_kern { + /* virtual service addresses */ + u_int16_t protocol; + __be32 addr; /* virtual ip address */ + __be16 port; + u_int32_t fwmark; /* firwall mark of service */ + + /* virtual service options */ + char sched_name[IP_VS_SCHEDNAME_MAXLEN]; + unsigned flags; /* virtual service flags */ + unsigned timeout; /* persistent timeout in sec */ + __be32 netmask; /* persistent netmask */ +}; + +struct ip_vs_service_user { + /* virtual service addresses */ + u_int16_t protocol; + __be32 __addr_v4; /* virtual ip address - internal use only */ + __be16 port; + u_int32_t fwmark; /* firwall mark of service */ + + /* virtual service options */ + char sched_name[IP_VS_SCHEDNAME_MAXLEN]; + unsigned flags; /* virtual service flags */ + unsigned timeout; /* persistent timeout in sec */ + __be32 netmask; /* persistent netmask */ + u_int16_t af; + union nf_inet_addr addr; +}; + +struct ip_vs_dest_kern { + /* destination server address */ + __be32 addr; + __be16 port; + + /* real server options */ + unsigned conn_flags; /* connection flags */ + int weight; /* destination weight */ + + /* thresholds for active connections */ + u_int32_t u_threshold; /* upper threshold */ + u_int32_t l_threshold; /* lower threshold */ +}; + +struct ip_vs_dest_user { + /* destination server address */ + __be32 __addr_v4; /* internal use only */ + __be16 port; + + /* real server options */ + unsigned conn_flags; /* connection flags */ + int weight; /* destination weight */ + + /* thresholds for active connections */ + u_int32_t u_threshold; /* upper threshold */ + u_int32_t l_threshold; /* lower threshold */ + u_int16_t af; + union nf_inet_addr addr; +}; + +/* + * IPVS statistics object (for user space) + */ +struct ip_vs_stats_user +{ + __u32 conns; /* connections scheduled */ + __u32 inpkts; /* incoming packets */ + __u32 outpkts; /* outgoing packets */ + __u64 inbytes; /* incoming bytes */ + __u64 outbytes; /* outgoing bytes */ + + __u32 cps; /* current connection rate */ + __u32 inpps; /* current in packet rate */ + __u32 outpps; /* current out packet rate */ + __u32 inbps; /* current in byte rate */ + __u32 outbps; /* current out byte rate */ +}; + + +/* The argument to IP_VS_SO_GET_INFO */ +struct ip_vs_getinfo { + /* version number */ + unsigned int version; + + /* size of connection hash table */ + unsigned int size; + + /* number of virtual services */ + unsigned int num_services; +}; + + +/* The argument to IP_VS_SO_GET_SERVICE */ +struct ip_vs_service_entry_kern { + /* which service: user fills in these */ + u_int16_t protocol; + __be32 addr; /* virtual address */ + __be16 port; + u_int32_t fwmark; /* firwall mark of service */ + + /* service options */ + char sched_name[IP_VS_SCHEDNAME_MAXLEN]; + unsigned flags; /* virtual service flags */ + unsigned timeout; /* persistent timeout */ + __be32 netmask; /* persistent netmask */ + + /* number of real servers */ + unsigned int num_dests; + + /* statistics */ + struct ip_vs_stats_user stats; +}; + +struct ip_vs_service_entry { + /* which service: user fills in these */ + u_int16_t protocol; + __be32 __addr_v4; /* virtual address - internal use only*/ + __be16 port; + u_int32_t fwmark; /* firwall mark of service */ + + /* service options */ + char sched_name[IP_VS_SCHEDNAME_MAXLEN]; + unsigned flags; /* virtual service flags */ + unsigned timeout; /* persistent timeout */ + __be32 netmask; /* persistent netmask */ + + /* number of real servers */ + unsigned int num_dests; + + /* statistics */ + struct ip_vs_stats_user stats; + + u_int16_t af; + union nf_inet_addr addr; + +}; + +struct ip_vs_dest_entry_kern { + __be32 addr; /* destination address */ + __be16 port; + unsigned conn_flags; /* connection flags */ + int weight; /* destination weight */ + + u_int32_t u_threshold; /* upper threshold */ + u_int32_t l_threshold; /* lower threshold */ + + u_int32_t activeconns; /* active connections */ + u_int32_t inactconns; /* inactive connections */ + u_int32_t persistconns; /* persistent connections */ + + /* statistics */ + struct ip_vs_stats_user stats; +}; + +struct ip_vs_dest_entry { + __be32 __addr_v4; /* destination address - internal use only */ + __be16 port; + unsigned conn_flags; /* connection flags */ + int weight; /* destination weight */ + + u_int32_t u_threshold; /* upper threshold */ + u_int32_t l_threshold; /* lower threshold */ + + u_int32_t activeconns; /* active connections */ + u_int32_t inactconns; /* inactive connections */ + u_int32_t persistconns; /* persistent connections */ + + /* statistics */ + struct ip_vs_stats_user stats; + u_int16_t af; + union nf_inet_addr addr; +}; + +/* The argument to IP_VS_SO_GET_DESTS */ +struct ip_vs_get_dests_kern { + /* which service: user fills in these */ + u_int16_t protocol; + __be32 addr; /* virtual address - internal use only */ + __be16 port; + u_int32_t fwmark; /* firwall mark of service */ + + /* number of real servers */ + unsigned int num_dests; + + /* the real servers */ + struct ip_vs_dest_entry_kern entrytable[0]; +}; + +struct ip_vs_get_dests { + /* which service: user fills in these */ + u_int16_t protocol; + __be32 __addr_v4; /* virtual address - internal use only */ + __be16 port; + u_int32_t fwmark; /* firwall mark of service */ + + /* number of real servers */ + unsigned int num_dests; + u_int16_t af; + union nf_inet_addr addr; + + /* the real servers */ + struct ip_vs_dest_entry entrytable[0]; +}; + +/* The argument to IP_VS_SO_GET_SERVICES */ +struct ip_vs_get_services { + /* number of virtual services */ + unsigned int num_services; + + /* service table */ + struct ip_vs_service_entry entrytable[0]; +}; + +struct ip_vs_get_services_kern { + /* number of virtual services */ + unsigned int num_services; + + /* service table */ + struct ip_vs_service_entry_kern entrytable[0]; +}; + +/* The argument to IP_VS_SO_GET_TIMEOUT */ +struct ip_vs_timeout_user { + int tcp_timeout; + int tcp_fin_timeout; + int udp_timeout; +}; + + +/* The argument to IP_VS_SO_GET_DAEMON */ +struct ip_vs_daemon_user { + /* sync daemon state (master/backup) */ + int state; + + /* multicast interface name */ + char mcast_ifn[IP_VS_IFNAME_MAXLEN]; + + /* SyncID we belong to */ + int syncid; +}; + + +/* + * + * IPVS Generic Netlink interface definitions + * + */ + +/* Generic Netlink family info */ + +#define IPVS_GENL_NAME "IPVS" +#define IPVS_GENL_VERSION 0x1 + +struct ip_vs_flags { + __be32 flags; + __be32 mask; +}; + +/* Generic Netlink command attributes */ +enum { + IPVS_CMD_UNSPEC = 0, + + IPVS_CMD_NEW_SERVICE, /* add service */ + IPVS_CMD_SET_SERVICE, /* modify service */ + IPVS_CMD_DEL_SERVICE, /* delete service */ + IPVS_CMD_GET_SERVICE, /* get info about specific service */ + + IPVS_CMD_NEW_DEST, /* add destination */ + IPVS_CMD_SET_DEST, /* modify destination */ + IPVS_CMD_DEL_DEST, /* delete destination */ + IPVS_CMD_GET_DEST, /* get list of all service dests */ + + IPVS_CMD_NEW_DAEMON, /* start sync daemon */ + IPVS_CMD_DEL_DAEMON, /* stop sync daemon */ + IPVS_CMD_GET_DAEMON, /* get sync daemon status */ + + IPVS_CMD_SET_TIMEOUT, /* set TCP and UDP timeouts */ + IPVS_CMD_GET_TIMEOUT, /* get TCP and UDP timeouts */ + + IPVS_CMD_SET_INFO, /* only used in GET_INFO reply */ + IPVS_CMD_GET_INFO, /* get general IPVS info */ + + IPVS_CMD_ZERO, /* zero all counters and stats */ + IPVS_CMD_FLUSH, /* flush services and dests */ + + __IPVS_CMD_MAX, +}; + +#define IPVS_CMD_MAX (__IPVS_CMD_MAX - 1) + +/* Attributes used in the first level of commands */ +enum { + IPVS_CMD_ATTR_UNSPEC = 0, + IPVS_CMD_ATTR_SERVICE, /* nested service attribute */ + IPVS_CMD_ATTR_DEST, /* nested destination attribute */ + IPVS_CMD_ATTR_DAEMON, /* nested sync daemon attribute */ + IPVS_CMD_ATTR_TIMEOUT_TCP, /* TCP connection timeout */ + IPVS_CMD_ATTR_TIMEOUT_TCP_FIN, /* TCP FIN wait timeout */ + IPVS_CMD_ATTR_TIMEOUT_UDP, /* UDP timeout */ + __IPVS_CMD_ATTR_MAX, +}; + +#define IPVS_CMD_ATTR_MAX (__IPVS_SVC_ATTR_MAX - 1) + +/* + * Attributes used to describe a service + * + * Used inside nested attribute IPVS_CMD_ATTR_SERVICE + */ +enum { + IPVS_SVC_ATTR_UNSPEC = 0, + IPVS_SVC_ATTR_AF, /* address family */ + IPVS_SVC_ATTR_PROTOCOL, /* virtual service protocol */ + IPVS_SVC_ATTR_ADDR, /* virtual service address */ + IPVS_SVC_ATTR_PORT, /* virtual service port */ + IPVS_SVC_ATTR_FWMARK, /* firewall mark of service */ + + IPVS_SVC_ATTR_SCHED_NAME, /* name of scheduler */ + IPVS_SVC_ATTR_FLAGS, /* virtual service flags */ + IPVS_SVC_ATTR_TIMEOUT, /* persistent timeout */ + IPVS_SVC_ATTR_NETMASK, /* persistent netmask */ + + IPVS_SVC_ATTR_STATS, /* nested attribute for service stats */ + __IPVS_SVC_ATTR_MAX, +}; + +#define IPVS_SVC_ATTR_MAX (__IPVS_SVC_ATTR_MAX - 1) + +/* + * Attributes used to describe a destination (real server) + * + * Used inside nested attribute IPVS_CMD_ATTR_DEST + */ +enum { + IPVS_DEST_ATTR_UNSPEC = 0, + IPVS_DEST_ATTR_ADDR, /* real server address */ + IPVS_DEST_ATTR_PORT, /* real server port */ + + IPVS_DEST_ATTR_FWD_METHOD, /* forwarding method */ + IPVS_DEST_ATTR_WEIGHT, /* destination weight */ + + IPVS_DEST_ATTR_U_THRESH, /* upper threshold */ + IPVS_DEST_ATTR_L_THRESH, /* lower threshold */ + + IPVS_DEST_ATTR_ACTIVE_CONNS, /* active connections */ + IPVS_DEST_ATTR_INACT_CONNS, /* inactive connections */ + IPVS_DEST_ATTR_PERSIST_CONNS, /* persistent connections */ + + IPVS_DEST_ATTR_STATS, /* nested attribute for dest stats */ + __IPVS_DEST_ATTR_MAX, +}; + +#define IPVS_DEST_ATTR_MAX (__IPVS_DEST_ATTR_MAX - 1) + +/* + * Attributes describing a sync daemon + * + * Used inside nested attribute IPVS_CMD_ATTR_DAEMON + */ +enum { + IPVS_DAEMON_ATTR_UNSPEC = 0, + IPVS_DAEMON_ATTR_STATE, /* sync daemon state (master/backup) */ + IPVS_DAEMON_ATTR_MCAST_IFN, /* multicast interface name */ + IPVS_DAEMON_ATTR_SYNC_ID, /* SyncID we belong to */ + __IPVS_DAEMON_ATTR_MAX, +}; + +#define IPVS_DAEMON_ATTR_MAX (__IPVS_DAEMON_ATTR_MAX - 1) + +/* + * Attributes used to describe service or destination entry statistics + * + * Used inside nested attributes IPVS_SVC_ATTR_STATS and IPVS_DEST_ATTR_STATS + */ +enum { + IPVS_STATS_ATTR_UNSPEC = 0, + IPVS_STATS_ATTR_CONNS, /* connections scheduled */ + IPVS_STATS_ATTR_INPKTS, /* incoming packets */ + IPVS_STATS_ATTR_OUTPKTS, /* outgoing packets */ + IPVS_STATS_ATTR_INBYTES, /* incoming bytes */ + IPVS_STATS_ATTR_OUTBYTES, /* outgoing bytes */ + + IPVS_STATS_ATTR_CPS, /* current connection rate */ + IPVS_STATS_ATTR_INPPS, /* current in packet rate */ + IPVS_STATS_ATTR_OUTPPS, /* current out packet rate */ + IPVS_STATS_ATTR_INBPS, /* current in byte rate */ + IPVS_STATS_ATTR_OUTBPS, /* current out byte rate */ + __IPVS_STATS_ATTR_MAX, +}; + +#define IPVS_STATS_ATTR_MAX (__IPVS_STATS_ATTR_MAX - 1) + +/* Attributes used in response to IPVS_CMD_GET_INFO command */ +enum { + IPVS_INFO_ATTR_UNSPEC = 0, + IPVS_INFO_ATTR_VERSION, /* IPVS version number */ + IPVS_INFO_ATTR_CONN_TAB_SIZE, /* size of connection hash table */ + __IPVS_INFO_ATTR_MAX, +}; + +#define IPVS_INFO_ATTR_MAX (__IPVS_INFO_ATTR_MAX - 1) + +#ifdef LIBIPVS_USE_NL +extern struct nla_policy ipvs_cmd_policy[IPVS_CMD_ATTR_MAX + 1]; +extern struct nla_policy ipvs_service_policy[IPVS_SVC_ATTR_MAX + 1]; +extern struct nla_policy ipvs_dest_policy[IPVS_DEST_ATTR_MAX + 1]; +extern struct nla_policy ipvs_stats_policy[IPVS_STATS_ATTR_MAX + 1]; +extern struct nla_policy ipvs_info_policy[IPVS_INFO_ATTR_MAX + 1]; +extern struct nla_policy ipvs_daemon_policy[IPVS_DAEMON_ATTR_MAX + 1]; +#endif + +/* End of Generic Netlink interface definitions */ + +#endif /* _IP_VS_H */ diff --git a/libipvs/ip_vs_nl_policy.c b/libipvs/ip_vs_nl_policy.c new file mode 100644 index 0000000..c80083e --- /dev/null +++ b/libipvs/ip_vs_nl_policy.c @@ -0,0 +1,70 @@ +#include "libipvs.h" + +#ifdef LIBIPVS_USE_NL +/* Policy definitions */ +struct nla_policy ipvs_cmd_policy[IPVS_CMD_ATTR_MAX + 1] = { + [IPVS_CMD_ATTR_SERVICE] = { .type = NLA_NESTED }, + [IPVS_CMD_ATTR_DEST] = { .type = NLA_NESTED }, + [IPVS_CMD_ATTR_DAEMON] = { .type = NLA_NESTED }, + [IPVS_CMD_ATTR_TIMEOUT_TCP] = { .type = NLA_U32 }, + [IPVS_CMD_ATTR_TIMEOUT_TCP_FIN] = { .type = NLA_U32 }, + [IPVS_CMD_ATTR_TIMEOUT_UDP] = { .type = NLA_U32 }, +}; + +struct nla_policy ipvs_service_policy[IPVS_SVC_ATTR_MAX + 1] = { + [IPVS_SVC_ATTR_AF] = { .type = NLA_U16 }, + [IPVS_SVC_ATTR_PROTOCOL] = { .type = NLA_U16 }, + [IPVS_SVC_ATTR_ADDR] = { .type = NLA_UNSPEC, + .maxlen = sizeof(struct in6_addr) }, + [IPVS_SVC_ATTR_PORT] = { .type = NLA_U16 }, + [IPVS_SVC_ATTR_FWMARK] = { .type = NLA_U32 }, + [IPVS_SVC_ATTR_SCHED_NAME] = { .type = NLA_STRING, + .maxlen = IP_VS_SCHEDNAME_MAXLEN }, + [IPVS_SVC_ATTR_FLAGS] = { .type = NLA_UNSPEC, + .minlen = sizeof(struct ip_vs_flags), + .maxlen = sizeof(struct ip_vs_flags) }, + [IPVS_SVC_ATTR_TIMEOUT] = { .type = NLA_U32 }, + [IPVS_SVC_ATTR_NETMASK] = { .type = NLA_U32 }, + [IPVS_SVC_ATTR_STATS] = { .type = NLA_NESTED }, +}; + +struct nla_policy ipvs_dest_policy[IPVS_DEST_ATTR_MAX + 1] = { + [IPVS_DEST_ATTR_ADDR] = { .type = NLA_UNSPEC, + .maxlen = sizeof(struct in6_addr) }, + [IPVS_DEST_ATTR_PORT] = { .type = NLA_U16 }, + [IPVS_DEST_ATTR_FWD_METHOD] = { .type = NLA_U32 }, + [IPVS_DEST_ATTR_WEIGHT] = { .type = NLA_U32 }, + [IPVS_DEST_ATTR_U_THRESH] = { .type = NLA_U32 }, + [IPVS_DEST_ATTR_L_THRESH] = { .type = NLA_U32 }, + [IPVS_DEST_ATTR_ACTIVE_CONNS] = { .type = NLA_U32 }, + [IPVS_DEST_ATTR_INACT_CONNS] = { .type = NLA_U32 }, + [IPVS_DEST_ATTR_PERSIST_CONNS] = { .type = NLA_U32 }, + [IPVS_DEST_ATTR_STATS] = { .type = NLA_NESTED }, +}; + +struct nla_policy ipvs_stats_policy[IPVS_STATS_ATTR_MAX + 1] = { + [IPVS_STATS_ATTR_CONNS] = { .type = NLA_U32 }, + [IPVS_STATS_ATTR_INPKTS] = { .type = NLA_U32 }, + [IPVS_STATS_ATTR_OUTPKTS] = { .type = NLA_U32 }, + [IPVS_STATS_ATTR_INBYTES] = { .type = NLA_U64 }, + [IPVS_STATS_ATTR_OUTBYTES] = { .type = NLA_U64 }, + [IPVS_STATS_ATTR_CPS] = { .type = NLA_U32 }, + [IPVS_STATS_ATTR_INPPS] = { .type = NLA_U32 }, + [IPVS_STATS_ATTR_OUTPPS] = { .type = NLA_U32 }, + [IPVS_STATS_ATTR_INBPS] = { .type = NLA_U32 }, + [IPVS_STATS_ATTR_OUTBPS] = { .type = NLA_U32 }, +}; + +struct nla_policy ipvs_info_policy[IPVS_INFO_ATTR_MAX + 1] = { + [IPVS_INFO_ATTR_VERSION] = { .type = NLA_U32 }, + [IPVS_INFO_ATTR_CONN_TAB_SIZE] = { .type = NLA_U32 }, +}; + +struct nla_policy ipvs_daemon_policy[IPVS_DAEMON_ATTR_MAX + 1] = { + [IPVS_DAEMON_ATTR_STATE] = { .type = NLA_U32 }, + [IPVS_DAEMON_ATTR_MCAST_IFN] = { .type = NLA_STRING, + .maxlen = IP_VS_IFNAME_MAXLEN }, + [IPVS_DAEMON_ATTR_SYNC_ID] = { .type = NLA_U32 }, +}; + +#endif /* LIBIPVS_USE_NL */ diff --git a/libipvs/libipvs.c b/libipvs/libipvs.c new file mode 100644 index 0000000..4f8944a --- /dev/null +++ b/libipvs/libipvs.c @@ -0,0 +1,1115 @@ +/* + * libipvs: Library for manipulating IPVS through [gs]etsockopt + * + * Version: $Id: libipvs.c,v 1.7 2003/06/08 09:31:39 wensong Exp $ + * + * Authors: Wensong Zhang <wensong@linuxvirtualserver.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <netinet/in.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> + +#include "libipvs.h" + +typedef struct ipvs_servicedest_s { + struct ip_vs_service_kern svc; + struct ip_vs_dest_kern dest; +} ipvs_servicedest_t; + +static int sockfd = -1; +static void* ipvs_func = NULL; +struct ip_vs_getinfo ipvs_info; + +#ifdef LIBIPVS_USE_NL +struct nl_handle *sock = NULL; +int family, try_nl = 1; +#endif + +#define CHECK_IPV4(s, ret) if (s->af && s->af != AF_INET) \ + { errno = EAFNOSUPPORT; return ret; } \ + s->__addr_v4 = s->addr.ip; \ + +#ifdef LIBIPVS_USE_NL +struct nl_msg *ipvs_nl_message(int cmd, int flags) { + struct nl_msg *msg; + + msg = nlmsg_alloc(); + if (!msg) + return NULL; + + genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, flags, + cmd, IPVS_GENL_VERSION); + + return msg; +} + +static int ipvs_nl_noop_cb(struct nl_msg *msg, void *arg) { + return NL_OK; +} + +int ipvs_nl_send_message(struct nl_msg *msg, nl_recvmsg_msg_cb_t func, void *arg) { + int err = EINVAL; + + sock = nl_handle_alloc(); + if (!sock) { + nlmsg_free(msg); + return -1; + } + + if (genl_connect(sock) < 0) + goto fail_genl; + + family = genl_ctrl_resolve(sock, IPVS_GENL_NAME); + if (family < 0) + goto fail_genl; + + /* To test connections and set the family */ + if (msg == NULL) { + nl_handle_destroy(sock); + sock = NULL; + return 0; + } + + if (nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, func, arg) != 0) + goto fail_genl; + + if (nl_send_auto_complete(sock, msg) < 0) + goto fail_genl; + + if ((err = -nl_recvmsgs_default(sock)) > 0) + goto fail_genl; + + nlmsg_free(msg); + + nl_handle_destroy(sock); + + return 0; + +fail_genl: + nl_handle_destroy(sock); + sock = NULL; + nlmsg_free(msg); + errno = err; + return -1; +} +#endif + +int ipvs_init(void) +{ + socklen_t len; + + ipvs_func = ipvs_init; + +#ifdef LIBIPVS_USE_NL + if (ipvs_nl_send_message(NULL, NULL, NULL) == 0) { + return ipvs_getinfo(); + } + + try_nl = 0; +#endif + + len = sizeof(ipvs_info); + if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) + return -1; + + if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_INFO, + (char *)&ipvs_info, &len)) + return -1; + + return 0; +} + +#ifdef LIBIPVS_USE_NL +static int ipvs_getinfo_parse_cb(struct nl_msg *msg, void *arg) +{ + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct nlattr *attrs[IPVS_INFO_ATTR_MAX + 1]; + + if (genlmsg_parse(nlh, 0, attrs, IPVS_INFO_ATTR_MAX, ipvs_info_policy) != 0) + return -1; + + if (!(attrs[IPVS_INFO_ATTR_VERSION] && + attrs[IPVS_INFO_ATTR_CONN_TAB_SIZE])) + return -1; + + ipvs_info.version = nla_get_u32(attrs[IPVS_INFO_ATTR_VERSION]); + ipvs_info.size = nla_get_u32(attrs[IPVS_INFO_ATTR_CONN_TAB_SIZE]); + + return NL_OK; +} +#endif + +int ipvs_getinfo(void) +{ + socklen_t len; + +#ifdef LIBIPVS_USE_NL + if (try_nl) { + struct nl_msg *msg; + msg = ipvs_nl_message(IPVS_CMD_GET_INFO, 0); + if (msg) + return ipvs_nl_send_message(msg, ipvs_getinfo_parse_cb, + NULL); + return -1; + } +#endif + + ipvs_func = ipvs_getinfo; + len = sizeof(ipvs_info); + return getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_INFO, + (char *)&ipvs_info, &len); +} + + +unsigned int ipvs_version(void) +{ + return ipvs_info.version; +} + + +int ipvs_flush(void) +{ +#ifdef LIBIPVS_USE_NL + if (try_nl) { + struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_FLUSH, 0); + if (msg && (ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL) == 0)) + return 0; + + return -1; + } +#endif + return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_FLUSH, NULL, 0); +} + +#ifdef LIBIPVS_USE_NL +static int ipvs_nl_fill_service_attr(struct nl_msg *msg, ipvs_service_t *svc) { + struct nlattr *nl_service; + struct ip_vs_flags flags = { .flags = svc->flags, + .mask = ~0 }; + + nl_service = nla_nest_start(msg, IPVS_CMD_ATTR_SERVICE); + if (!nl_service) + return -1; + + NLA_PUT_U16(msg, IPVS_SVC_ATTR_AF, svc->af); + + if (svc->fwmark) { + NLA_PUT_U32(msg, IPVS_SVC_ATTR_FWMARK, svc->fwmark); + } else { + NLA_PUT_U16(msg, IPVS_SVC_ATTR_PROTOCOL, svc->protocol); + NLA_PUT(msg, IPVS_SVC_ATTR_ADDR, sizeof(svc->addr), &(svc->addr)); + NLA_PUT_U16(msg, IPVS_SVC_ATTR_PORT, svc->port); + } + + NLA_PUT_STRING(msg, IPVS_SVC_ATTR_SCHED_NAME, svc->sched_name); + NLA_PUT(msg, IPVS_SVC_ATTR_FLAGS, sizeof(flags), &flags); + NLA_PUT_U32(msg, IPVS_SVC_ATTR_TIMEOUT, svc->timeout); + NLA_PUT_U32(msg, IPVS_SVC_ATTR_NETMASK, svc->netmask); + + nla_nest_end(msg, nl_service); + return 0; + +nla_put_failure: + return -1; +} +#endif + +int ipvs_add_service(ipvs_service_t *svc) +{ + ipvs_func = ipvs_add_service; +#ifdef LIBIPVS_USE_NL + if (try_nl) { + struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_NEW_SERVICE, 0); + if (!msg) return -1; + if (ipvs_nl_fill_service_attr(msg, svc)) { + nlmsg_free(msg); + return -1; + } + return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); + } +#endif + + CHECK_IPV4(svc, -1); + return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_ADD, (char *)svc, + sizeof(struct ip_vs_service_kern)); +} + + +int ipvs_update_service(ipvs_service_t *svc) +{ + ipvs_func = ipvs_update_service; +#ifdef LIBIPVS_USE_NL + if (try_nl) { + struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_SET_SERVICE, 0); + if (!msg) return -1; + if (ipvs_nl_fill_service_attr(msg, svc)) { + nlmsg_free(msg); + return -1; + } + return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); + } +#endif + CHECK_IPV4(svc, -1); + return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_EDIT, (char *)svc, + sizeof(struct ip_vs_service_kern)); +} + + +int ipvs_del_service(ipvs_service_t *svc) +{ + ipvs_func = ipvs_del_service; +#ifdef LIBIPVS_USE_NL + if (try_nl) { + struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_DEL_SERVICE, 0); + if (!msg) return -1; + if (ipvs_nl_fill_service_attr(msg, svc)) { + nlmsg_free(msg); + return -1; + } + return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); + } +#endif + CHECK_IPV4(svc, -1); + return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_DEL, (char *)svc, + sizeof(struct ip_vs_service_kern)); +} + + +int ipvs_zero_service(ipvs_service_t *svc) +{ + ipvs_func = ipvs_zero_service; +#ifdef LIBIPVS_USE_NL + if (try_nl) { + struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_ZERO, 0); + if (!msg) return -1; + + if (svc->fwmark + || memcmp(&in6addr_any, &svc->addr.in6, sizeof(struct in6_addr)) + || svc->port) { + if (ipvs_nl_fill_service_attr(msg, svc)) { + nlmsg_free(msg); + return -1; + } + } + return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); + } +#endif + CHECK_IPV4(svc, -1); + return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_ZERO, (char *)svc, + sizeof(struct ip_vs_service_kern)); +} + +#ifdef LIBIPVS_USE_NL +static int ipvs_nl_fill_dest_attr(struct nl_msg *msg, ipvs_dest_t *dst) { + struct nlattr *nl_dest; + + nl_dest = nla_nest_start(msg, IPVS_CMD_ATTR_DEST); + if (!nl_dest) + return -1; + + NLA_PUT(msg, IPVS_DEST_ATTR_ADDR, sizeof(dst->addr), &(dst->addr)); + NLA_PUT_U16(msg, IPVS_DEST_ATTR_PORT, dst->port); + NLA_PUT_U32(msg, IPVS_DEST_ATTR_FWD_METHOD, dst->conn_flags & IP_VS_CONN_F_FWD_MASK); + NLA_PUT_U32(msg, IPVS_DEST_ATTR_WEIGHT, dst->weight); + NLA_PUT_U32(msg, IPVS_DEST_ATTR_U_THRESH, dst->u_threshold); + NLA_PUT_U32(msg, IPVS_DEST_ATTR_L_THRESH, dst->l_threshold); + + nla_nest_end(msg, nl_dest); + return 0; + +nla_put_failure: + return -1; +} +#endif + +int ipvs_add_dest(ipvs_service_t *svc, ipvs_dest_t *dest) +{ + ipvs_servicedest_t svcdest; + +#ifdef LIBIPVS_USE_NL + ipvs_func = ipvs_add_dest; + if (try_nl) { + struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_NEW_DEST, 0); + if (!msg) return -1; + if (ipvs_nl_fill_service_attr(msg, svc)) + goto nla_put_failure; + if (ipvs_nl_fill_dest_attr(msg, dest)) + goto nla_put_failure; + return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); + +nla_put_failure: + nlmsg_free(msg); + return -1; + } +#endif + + CHECK_IPV4(svc, -1); + CHECK_IPV4(dest, -1); + memcpy(&svcdest.svc, svc, sizeof(svcdest.svc)); + memcpy(&svcdest.dest, dest, sizeof(svcdest.dest)); + return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_ADDDEST, + (char *)&svcdest, sizeof(svcdest)); +} + + +int ipvs_update_dest(ipvs_service_t *svc, ipvs_dest_t *dest) +{ + ipvs_servicedest_t svcdest; + + ipvs_func = ipvs_update_dest; +#ifdef LIBIPVS_USE_NL + if (try_nl) { + struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_SET_DEST, 0); + if (!msg) return -1; + if (ipvs_nl_fill_service_attr(msg, svc)) + goto nla_put_failure; + if (ipvs_nl_fill_dest_attr(msg, dest)) + goto nla_put_failure; + return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); + +nla_put_failure: + nlmsg_free(msg); + return -1; + } +#endif + CHECK_IPV4(svc, -1); + CHECK_IPV4(dest, -1); + memcpy(&svcdest.svc, svc, sizeof(svcdest.svc)); + memcpy(&svcdest.dest, dest, sizeof(svcdest.dest)); + return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_EDITDEST, + (char *)&svcdest, sizeof(svcdest)); +} + + +int ipvs_del_dest(ipvs_service_t *svc, ipvs_dest_t *dest) +{ + ipvs_servicedest_t svcdest; + + ipvs_func = ipvs_del_dest; +#ifdef LIBIPVS_USE_NL + if (try_nl) { + struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_DEL_DEST, 0); + if (!msg) return -1; + if (ipvs_nl_fill_service_attr(msg, svc)) + goto nla_put_failure; + if (ipvs_nl_fill_dest_attr(msg, dest)) + goto nla_put_failure; + return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); + +nla_put_failure: + nlmsg_free(msg); + return -1; + } +#endif + + CHECK_IPV4(svc, -1); + CHECK_IPV4(dest, -1); + memcpy(&svcdest.svc, svc, sizeof(svcdest.svc)); + memcpy(&svcdest.dest, dest, sizeof(svcdest.dest)); + return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_DELDEST, + (char *)&svcdest, sizeof(svcdest)); +} + + +int ipvs_set_timeout(ipvs_timeout_t *to) +{ + ipvs_func = ipvs_set_timeout; +#ifdef LIBIPVS_USE_NL + if (try_nl) { + struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_SET_TIMEOUT, 0); + if (!msg) return -1; + NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_TCP, to->tcp_timeout); + NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_TCP_FIN, to->tcp_fin_timeout); + NLA_PUT_U32(msg, IPVS_CMD_ATTR_TIMEOUT_UDP, to->udp_timeout); + return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); + +nla_put_failure: + nlmsg_free(msg); + return -1; + } +#endif + return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_TIMEOUT, (char *)to, + sizeof(*to)); +} + + +int ipvs_start_daemon(ipvs_daemon_t *dm) +{ + ipvs_func = ipvs_start_daemon; +#ifdef LIBIPVS_USE_NL + if (try_nl) { + struct nlattr *nl_daemon; + struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_NEW_DAEMON, 0); + if (!msg) return -1; + + nl_daemon = nla_nest_start(msg, IPVS_CMD_ATTR_DAEMON); + if (!nl_daemon) + goto nla_put_failure; + + NLA_PUT_U32(msg, IPVS_DAEMON_ATTR_STATE, dm->state); + NLA_PUT_STRING(msg, IPVS_DAEMON_ATTR_MCAST_IFN, dm->mcast_ifn); + NLA_PUT_U32(msg, IPVS_DAEMON_ATTR_SYNC_ID, dm->syncid); + + nla_nest_end(msg, nl_daemon); + + return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); + +nla_put_failure: + nlmsg_free(msg); + return -1; + } +#endif + return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_STARTDAEMON, + (char *)dm, sizeof(*dm)); +} + + +int ipvs_stop_daemon(ipvs_daemon_t *dm) +{ + ipvs_func = ipvs_stop_daemon; +#ifdef LIBIPVS_USE_NL + if (try_nl) { + struct nlattr *nl_daemon; + struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_DEL_DAEMON, 0); + if (!msg) return -1; + + nl_daemon = nla_nest_start(msg, IPVS_CMD_ATTR_DAEMON); + if (!nl_daemon) + goto nla_put_failure; + + NLA_PUT_U32(msg, IPVS_DAEMON_ATTR_STATE, dm->state); + NLA_PUT_STRING(msg, IPVS_DAEMON_ATTR_MCAST_IFN, dm->mcast_ifn); + NLA_PUT_U32(msg, IPVS_DAEMON_ATTR_SYNC_ID, dm->syncid); + + nla_nest_end(msg, nl_daemon); + + return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL); + +nla_put_failure: + nlmsg_free(msg); + return -1; + } +#endif + return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_STOPDAEMON, + (char *)dm, sizeof(*dm)); +} + +#ifdef LIBIPVS_USE_NL +static int ipvs_parse_stats(struct ip_vs_stats_user *stats, struct nlattr *nla) { + struct nlattr *attrs[IPVS_STATS_ATTR_MAX + 1]; + + if (nla_parse_nested(attrs, IPVS_STATS_ATTR_MAX, nla, ipvs_stats_policy)) + return -1; + + if (!(attrs[IPVS_STATS_ATTR_CONNS] && + attrs[IPVS_STATS_ATTR_INPKTS] && + attrs[IPVS_STATS_ATTR_OUTPKTS] && + attrs[IPVS_STATS_ATTR_INBYTES] && + attrs[IPVS_STATS_ATTR_OUTBYTES] && + attrs[IPVS_STATS_ATTR_CPS] && + attrs[IPVS_STATS_ATTR_INPPS] && + attrs[IPVS_STATS_ATTR_OUTPPS] && + attrs[IPVS_STATS_ATTR_INBPS] && + attrs[IPVS_STATS_ATTR_OUTBPS])) + return -1; + + stats->conns = nla_get_u32(attrs[IPVS_STATS_ATTR_CONNS]); + stats->inpkts = nla_get_u32(attrs[IPVS_STATS_ATTR_INPKTS]); + stats->outpkts = nla_get_u32(attrs[IPVS_STATS_ATTR_OUTPKTS]); + stats->inbytes = nla_get_u64(attrs[IPVS_STATS_ATTR_INBYTES]); + stats->outbytes = nla_get_u64(attrs[IPVS_STATS_ATTR_OUTBYTES]); + stats->cps = nla_get_u32(attrs[IPVS_STATS_ATTR_CPS]); + stats->inpps = nla_get_u32(attrs[IPVS_STATS_ATTR_INPPS]); + stats->outpps = nla_get_u32(attrs[IPVS_STATS_ATTR_OUTPPS]); + stats->inbps = nla_get_u32(attrs[IPVS_STATS_ATTR_INBPS]); + stats->outbps = nla_get_u32(attrs[IPVS_STATS_ATTR_OUTBPS]); + + return 0; + +} + +static int ipvs_services_parse_cb(struct nl_msg *msg, void *arg) +{ + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct nlattr *attrs[IPVS_CMD_ATTR_MAX + 1]; + struct nlattr *svc_attrs[IPVS_SVC_ATTR_MAX + 1]; + struct ip_vs_get_services **getp = (struct ip_vs_get_services **)arg; + struct ip_vs_get_services *get = (struct ip_vs_get_services *)*getp; + struct ip_vs_flags flags; + int i = get->num_services; + + if (genlmsg_parse(nlh, 0, attrs, IPVS_CMD_ATTR_MAX, ipvs_cmd_policy) != 0) + return -1; + + if (!attrs[IPVS_CMD_ATTR_SERVICE]) + return -1; + + if (nla_parse_nested(svc_attrs, IPVS_SVC_ATTR_MAX, attrs[IPVS_CMD_ATTR_SERVICE], ipvs_service_policy)) + return -1; + + memset(&(get->entrytable[i]), 0, sizeof(get->entrytable[i])); + + if (!(svc_attrs[IPVS_SVC_ATTR_AF] && + (svc_attrs[IPVS_SVC_ATTR_FWMARK] || + (svc_attrs[IPVS_SVC_ATTR_PROTOCOL] && + svc_attrs[IPVS_SVC_ATTR_ADDR] && + svc_attrs[IPVS_SVC_ATTR_PORT])) && + svc_attrs[IPVS_SVC_ATTR_SCHED_NAME] && + svc_attrs[IPVS_SVC_ATTR_NETMASK] && + svc_attrs[IPVS_SVC_ATTR_TIMEOUT] && + svc_attrs[IPVS_SVC_ATTR_FLAGS])) + return -1; + + get->entrytable[i].af = nla_get_u16(svc_attrs[IPVS_SVC_ATTR_AF]); + + if (svc_attrs[IPVS_SVC_ATTR_FWMARK]) + get->entrytable[i].fwmark = nla_get_u32(svc_attrs[IPVS_SVC_ATTR_FWMARK]); + else { + get->entrytable[i].protocol = nla_get_u16(svc_attrs[IPVS_SVC_ATTR_PROTOCOL]); + memcpy(&(get->entrytable[i].addr), nla_data(svc_attrs[IPVS_SVC_ATTR_ADDR]), + sizeof(get->entrytable[i].addr)); + get->entrytable[i].port = nla_get_u16(svc_attrs[IPVS_SVC_ATTR_PORT]); + } + + strncpy(get->entrytable[i].sched_name, + nla_get_string(svc_attrs[IPVS_SVC_ATTR_SCHED_NAME]), + IP_VS_SCHEDNAME_MAXLEN); + + get->entrytable[i].netmask = nla_get_u32(svc_attrs[IPVS_SVC_ATTR_NETMASK]); + get->entrytable[i].timeout = nla_get_u32(svc_attrs[IPVS_SVC_ATTR_TIMEOUT]); + nla_memcpy(&flags, svc_attrs[IPVS_SVC_ATTR_FLAGS], sizeof(flags)); + get->entrytable[i].flags = flags.flags & flags.mask; + + if (ipvs_parse_stats(&(get->entrytable[i].stats), + svc_attrs[IPVS_SVC_ATTR_STATS]) != 0) + return -1; + + get->entrytable[i].num_dests = 0; + + i++; + + get->num_services = i; + get = realloc(get, sizeof(*get) + + sizeof(ipvs_service_entry_t) * (get->num_services + 1)); + *getp = get; + return 0; +} +#endif + +struct ip_vs_get_services *ipvs_get_services(void) +{ + struct ip_vs_get_services *get; + struct ip_vs_get_services_kern *getk; + socklen_t len; + int i; + +#ifdef LIBIPVS_USE_NL + if (try_nl) { + struct nl_msg *msg; + len = sizeof(*get) + + sizeof(ipvs_service_entry_t); + if (!(get = malloc(len))) + return NULL; + get->num_services = 0; + + msg = ipvs_nl_message(IPVS_CMD_GET_SERVICE, NLM_F_DUMP); + if (msg && (ipvs_nl_send_message(msg, ipvs_services_parse_cb, &get) == 0)) + return get; + + free(get); + return NULL; + } +#endif + + len = sizeof(*get) + + sizeof(ipvs_service_entry_t) * ipvs_info.num_services; + if (!(get = malloc(len))) + return NULL; + len = sizeof(*getk) + + sizeof(struct ip_vs_service_entry_kern) * ipvs_info.num_services; + if (!(getk = malloc(len))) + return NULL; + + ipvs_func = ipvs_get_services; + getk->num_services = ipvs_info.num_services; + if (getsockopt(sockfd, IPPROTO_IP, + IP_VS_SO_GET_SERVICES, getk, &len) < 0) { + free(get); + free(getk); + return NULL; + } + memcpy(get, getk, sizeof(struct ip_vs_get_services)); + for (i = 0; i < getk->num_services; i++) { + memcpy(&get->entrytable[i], &getk->entrytable[i], + sizeof(struct ip_vs_service_entry_kern)); + get->entrytable[i].af = AF_INET; + get->entrytable[i].addr.ip = get->entrytable[i].__addr_v4; + } + free(getk); + return get; +} + + +typedef int (*qsort_cmp_t)(const void *, const void *); + +int +ipvs_cmp_services(ipvs_service_entry_t *s1, ipvs_service_entry_t *s2) +{ + int r, i; + + r = s1->fwmark - s2->fwmark; + if (r != 0) + return r; + + r = s1->af - s2->af; + if (r != 0) + return r; + + r = s1->protocol - s2->protocol; + if (r != 0) + return r; + + if (s1->af == AF_INET6) + for (i = 0; !r && (i < 4); i++) + r = ntohl(s1->addr.in6.s6_addr32[i]) - ntohl(s2->addr.in6.s6_addr32[i]); + else + r = ntohl(s1->addr.ip) - ntohl(s2->addr.ip); + if (r != 0) + return r; + + return ntohs(s1->port) - ntohs(s2->port); +} + + +void +ipvs_sort_services(struct ip_vs_get_services *s, ipvs_service_cmp_t f) +{ + qsort(s->entrytable, s->num_services, + sizeof(ipvs_service_entry_t), (qsort_cmp_t)f); +} + +#ifdef LIBIPVS_USE_NL +static int ipvs_dests_parse_cb(struct nl_msg *msg, void *arg) +{ + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct nlattr *attrs[IPVS_DEST_ATTR_MAX + 1]; + struct nlattr *dest_attrs[IPVS_SVC_ATTR_MAX + 1]; + struct ip_vs_get_dests **dp = (struct ip_vs_get_dests **)arg; + struct ip_vs_get_dests *d = (struct ip_vs_get_dests *)*dp; + int i = d->num_dests; + + if (genlmsg_parse(nlh, 0, attrs, IPVS_CMD_ATTR_MAX, ipvs_cmd_policy) != 0) + return -1; + + if (!attrs[IPVS_CMD_ATTR_DEST]) + return -1; + + if (nla_parse_nested(dest_attrs, IPVS_DEST_ATTR_MAX, attrs[IPVS_CMD_ATTR_DEST], ipvs_dest_policy)) + return -1; + + memset(&(d->entrytable[i]), 0, sizeof(d->entrytable[i])); + + if (!(dest_attrs[IPVS_DEST_ATTR_ADDR] && + dest_attrs[IPVS_DEST_ATTR_PORT] && + dest_attrs[IPVS_DEST_ATTR_FWD_METHOD] && + dest_attrs[IPVS_DEST_ATTR_WEIGHT] && + dest_attrs[IPVS_DEST_ATTR_U_THRESH] && + dest_attrs[IPVS_DEST_ATTR_L_THRESH] && + dest_attrs[IPVS_DEST_ATTR_ACTIVE_CONNS] && + dest_attrs[IPVS_DEST_ATTR_INACT_CONNS] && + dest_attrs[IPVS_DEST_ATTR_PERSIST_CONNS])) + return -1; + + memcpy(&(d->entrytable[i].addr), + nla_data(dest_attrs[IPVS_DEST_ATTR_ADDR]), + sizeof(d->entrytable[i].addr)); + d->entrytable[i].port = nla_get_u16(dest_attrs[IPVS_DEST_ATTR_PORT]); + d->entrytable[i].conn_flags = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_FWD_METHOD]); + d->entrytable[i].weight = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_WEIGHT]); + d->entrytable[i].u_threshold = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_U_THRESH]); + d->entrytable[i].l_threshold = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_L_THRESH]); + d->entrytable[i].activeconns = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_ACTIVE_CONNS]); + d->entrytable[i].inactconns = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_INACT_CONNS]); + d->entrytable[i].activeconns = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_PERSIST_CONNS]); + d->entrytable[i].af = d->af; + + if (ipvs_parse_stats(&(d->entrytable[i].stats), + dest_attrs[IPVS_DEST_ATTR_STATS]) != 0) + return -1; + + i++; + + d->num_dests = i; + d = realloc(d, sizeof(*d) + sizeof(ipvs_dest_entry_t) * (d->num_dests + 1)); + *dp = d; + return 0; +} +#endif + +struct ip_vs_get_dests *ipvs_get_dests(ipvs_service_entry_t *svc) +{ + struct ip_vs_get_dests *d; + struct ip_vs_get_dests_kern *dk; + socklen_t len; + int i; + + len = sizeof(*d) + sizeof(ipvs_dest_entry_t) * svc->num_dests; + if (!(d = malloc(len))) + return NULL; + + ipvs_func = ipvs_get_dests; + +#ifdef LIBIPVS_USE_NL + if (try_nl) { + struct nl_msg *msg; + struct nlattr *nl_service; + if (svc->num_dests == 0) + d = realloc(d,sizeof(*d) + sizeof(ipvs_dest_entry_t)); + d->fwmark = svc->fwmark; + d->protocol = svc->protocol; + d->addr = svc->addr; + d->port = svc->port; + d->num_dests = svc->num_dests; + d->af = svc->af; + + msg = ipvs_nl_message(IPVS_CMD_GET_DEST, NLM_F_DUMP); + if (!msg) + goto ipvs_nl_dest_failure; + + nl_service = nla_nest_start(msg, IPVS_CMD_ATTR_SERVICE); + if (!nl_service) + goto nla_put_failure; + + NLA_PUT_U16(msg, IPVS_SVC_ATTR_AF, svc->af); + + if (svc->fwmark) { + NLA_PUT_U32(msg, IPVS_SVC_ATTR_FWMARK, svc->fwmark); + } else { + NLA_PUT_U16(msg, IPVS_SVC_ATTR_PROTOCOL, svc->protocol); + NLA_PUT(msg, IPVS_SVC_ATTR_ADDR, sizeof(svc->addr), + &svc->addr); + NLA_PUT_U16(msg, IPVS_SVC_ATTR_PORT, svc->port); + } + + nla_nest_end(msg, nl_service); + if (ipvs_nl_send_message(msg, ipvs_dests_parse_cb, &d)) + goto ipvs_nl_dest_failure; + + return d; + +nla_put_failure: + nlmsg_free(msg); +ipvs_nl_dest_failure: + free(d); + return NULL; + } +#endif + + if (svc->af != AF_INET) { + errno = EAFNOSUPPORT; + free(d); + return NULL; + } + + len = sizeof(*dk) + sizeof(struct ip_vs_dest_entry_kern) * svc->num_dests; + if (!(dk = malloc(len))) + return NULL; + + dk->fwmark = svc->fwmark; + dk->protocol = svc->protocol; + dk->addr = svc->addr.ip; + dk->port = svc->port; + dk->num_dests = svc->num_dests; + + if (getsockopt(sockfd, IPPROTO_IP, + IP_VS_SO_GET_DESTS, dk, &len) < 0) { + free(d); + free(dk); + return NULL; + } + memcpy(d, dk, sizeof(struct ip_vs_get_dests_kern)); + d->af = AF_INET; + d->addr.ip = d->__addr_v4; + for (i = 0; i < dk->num_dests; i++) { + memcpy(&d->entrytable[i], &dk->entrytable[i], + sizeof(struct ip_vs_dest_entry_kern)); + d->entrytable[i].af = AF_INET; + d->entrytable[i].addr.ip = d->entrytable[i].__addr_v4; + } + free(dk); + return d; +} + + +int ipvs_cmp_dests(ipvs_dest_entry_t *d1, ipvs_dest_entry_t *d2) +{ + int r = 0, i; + + if (d1->af == AF_INET6) + for (i = 0; !r && (i < 4); i++) + r = ntohl(d1->addr.in6.s6_addr32[i]) - + ntohl(d2->addr.in6.s6_addr32[i]); + else + r = ntohl(d1->addr.ip) - ntohl(d2->addr.ip); + if (r != 0) + return r; + + return ntohs(d1->port) - ntohs(d2->port); +} + + +void ipvs_sort_dests(struct ip_vs_get_dests *d, ipvs_dest_cmp_t f) +{ + qsort(d->entrytable, d->num_dests, + sizeof(ipvs_dest_entry_t), (qsort_cmp_t)f); +} + + +ipvs_service_entry_t * +ipvs_get_service(__u32 fwmark, __u16 af, __u16 protocol, union nf_inet_addr addr, __u16 port) +{ + ipvs_service_entry_t *svc; + socklen_t len; + + len = sizeof(*svc); + if (!(svc = malloc(len))) + return NULL; + + ipvs_func = ipvs_get_service; + + svc->fwmark = fwmark; + svc->af = af; + svc->protocol = protocol; + svc->addr = addr; + svc->port = port; +#ifdef LIBIPVS_USE_NL + if (try_nl) { + struct ip_vs_get_services *get; + struct nl_msg *msg; + ipvs_service_t tsvc; + tsvc.fwmark = fwmark; + tsvc.af = af; + tsvc.protocol= protocol; + tsvc.addr = addr; + tsvc.port = port; + + if (!(get = malloc(sizeof(*get) + sizeof(ipvs_service_entry_t)))) + goto ipvs_get_service_err2; + + get->num_services = 0; + + msg = ipvs_nl_message(IPVS_CMD_GET_SERVICE, 0); + if (!msg) goto ipvs_get_service_err; + if (ipvs_nl_fill_service_attr(msg, &tsvc)) + goto nla_put_failure; + if (ipvs_nl_send_message(msg, ipvs_services_parse_cb, &get)) + goto ipvs_get_service_err; + + memcpy(svc, &(get->entrytable[0]), sizeof(*svc)); + free(get); + return svc; + +nla_put_failure: + nlmsg_free(msg); +ipvs_get_service_err: + free(get); +ipvs_get_service_err2: + free(svc); + return NULL; + } +#endif + + CHECK_IPV4(svc, NULL); + if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_SERVICE, + (char *)svc, &len)) { + free(svc); + return NULL; + } + svc->af = AF_INET; + svc->addr.ip = svc->__addr_v4; + return svc; +} + +#ifdef LIBIPVS_USE_NL +static int ipvs_timeout_parse_cb(struct nl_msg *msg, void *arg) +{ + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct nlattr *attrs[IPVS_CMD_ATTR_MAX + 1]; + ipvs_timeout_t *u = (ipvs_timeout_t *)arg; + + if (genlmsg_parse(nlh, 0, attrs, IPVS_CMD_ATTR_MAX, ipvs_cmd_policy) != 0) + return -1; + + if (attrs[IPVS_CMD_ATTR_TIMEOUT_TCP]) + u->tcp_timeout = nla_get_u32(attrs[IPVS_CMD_ATTR_TIMEOUT_TCP]); + if (attrs[IPVS_CMD_ATTR_TIMEOUT_TCP_FIN]) + u->tcp_fin_timeout = nla_get_u32(attrs[IPVS_CMD_ATTR_TIMEOUT_TCP_FIN]); + if (attrs[IPVS_CMD_ATTR_TIMEOUT_UDP]) + u->udp_timeout = nla_get_u32(attrs[IPVS_CMD_ATTR_TIMEOUT_UDP]); + + return NL_OK; +} +#endif + +ipvs_timeout_t *ipvs_get_timeout(void) +{ + ipvs_timeout_t *u; + socklen_t len; + + len = sizeof(*u); + if (!(u = malloc(len))) + return NULL; + + ipvs_func = ipvs_get_timeout; +#ifdef LIBIPVS_USE_NL + if (try_nl) { + struct nl_msg *msg; + memset(u, 0, sizeof(*u)); + msg = ipvs_nl_message(IPVS_CMD_GET_TIMEOUT, 0); + if (msg && (ipvs_nl_send_message(msg, ipvs_timeout_parse_cb, u) == 0)) + return u; + + free(u); + return NULL; + } +#endif + if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_TIMEOUT, + (char *)u, &len)) { + free(u); + return NULL; + } + return u; +} + +#ifdef LIBIPVS_USE_NL +static int ipvs_daemon_parse_cb(struct nl_msg *msg, void *arg) +{ + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct nlattr *attrs[IPVS_CMD_ATTR_MAX + 1]; + struct nlattr *daemon_attrs[IPVS_DAEMON_ATTR_MAX + 1]; + ipvs_daemon_t *u = (ipvs_daemon_t *)arg; + int i = 0; + + /* We may get two daemons. If we've already got one, this is the second */ + if (u[0].state) + i = 1; + + if (genlmsg_parse(nlh, 0, attrs, IPVS_CMD_ATTR_MAX, ipvs_cmd_policy) != 0) + return -1; + + if (nla_parse_nested(daemon_attrs, IPVS_DAEMON_ATTR_MAX, + attrs[IPVS_CMD_ATTR_DAEMON], ipvs_daemon_policy)) + return -1; + + if (!(daemon_attrs[IPVS_DAEMON_ATTR_STATE] && + daemon_attrs[IPVS_DAEMON_ATTR_MCAST_IFN] && + daemon_attrs[IPVS_DAEMON_ATTR_SYNC_ID])) + return -1; + + u[i].state = nla_get_u32(daemon_attrs[IPVS_DAEMON_ATTR_STATE]); + strncpy(u[i].mcast_ifn, + nla_get_string(daemon_attrs[IPVS_DAEMON_ATTR_MCAST_IFN]), + IP_VS_IFNAME_MAXLEN); + u[i].syncid = nla_get_u32(daemon_attrs[IPVS_DAEMON_ATTR_SYNC_ID]); + + return NL_OK; +} +#endif + +ipvs_daemon_t *ipvs_get_daemon(void) +{ + ipvs_daemon_t *u; + socklen_t len; + + /* note that we need to get the info about two possible + daemons, master and backup. */ + len = sizeof(*u) * 2; + if (!(u = malloc(len))) + return NULL; + + ipvs_func = ipvs_get_daemon; +#ifdef LIBIPVS_USE_NL + if (try_nl) { + struct nl_msg *msg; + memset(u, 0, len); + msg = ipvs_nl_message(IPVS_CMD_GET_DAEMON, NLM_F_DUMP); + if (msg && (ipvs_nl_send_message(msg, ipvs_daemon_parse_cb, u) == 0)) + return u; + + free(u); + return NULL; + } +#endif + if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_DAEMON, (char *)u, &len)) { + free(u); + return NULL; + } + return u; +} + + +void ipvs_close(void) +{ +#ifdef LIBIPVS_USE_NL + if (try_nl) { + return; + } +#endif + close(sockfd); +} + + +const char *ipvs_strerror(int err) +{ + unsigned int i; + struct table_struct { + void *func; + int err; + const char *message; + } table [] = { + { ipvs_add_service, EEXIST, "Service already exists" }, + { ipvs_add_service, ENOENT, "Scheduler not found" }, + { ipvs_update_service, ESRCH, "No such service" }, + { ipvs_update_service, ENOENT, "Scheduler not found" }, + { ipvs_del_service, ESRCH, "No such service" }, + { ipvs_zero_service, ESRCH, "No such service" }, + { ipvs_add_dest, ESRCH, "Service not defined" }, + { ipvs_add_dest, EEXIST, "Destination already exists" }, + { ipvs_update_dest, ESRCH, "Service not defined" }, + { ipvs_update_dest, ENOENT, "No such destination" }, + { ipvs_del_dest, ESRCH, "Service not defined" }, + { ipvs_del_dest, ENOENT, "No such destination" }, + { ipvs_start_daemon, EEXIST, "Daemon has already run" }, + { ipvs_stop_daemon, ESRCH, "No daemon is running" }, + { ipvs_get_services, ESRCH, "No such service" }, + { ipvs_get_dests, ESRCH, "No such service" }, + { ipvs_get_service, ESRCH, "No such service" }, + { 0, EPERM, "Permission denied (you must be root)" }, + { 0, EINVAL, "Invalid operation. Possibly wrong module version, address not unicast, ..." }, + { 0, ENOPROTOOPT, "Protocol not available" }, + { 0, ENOMEM, "Memory allocation problem" }, + { 0, EOPNOTSUPP, "Operation not supported with IPv6" }, + { 0, EAFNOSUPPORT, "Operation not supported with specified address family" }, + { 0, EMSGSIZE, "Module is wrong version" }, + }; + + for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) { + if ((!table[i].func || table[i].func == ipvs_func) + && table[i].err == err) + return table[i].message; + } + + return strerror(err); +} diff --git a/libipvs/libipvs.h b/libipvs/libipvs.h new file mode 100644 index 0000000..15b7d5d --- /dev/null +++ b/libipvs/libipvs.h @@ -0,0 +1,128 @@ +/* + * libipvs.h: header file for the library ipvs + * + * Version: $Id: libipvs.h,v 1.7 2003/06/08 09:31:39 wensong Exp $ + * + * Authors: Wensong Zhang <wensong@linuxvirtualserver.org> + * + */ + +#ifndef _LIBIPVS_H +#define _LIBIPVS_H + +#include "ip_vs.h" + + +#define MINIMUM_IPVS_VERSION_MAJOR 1 +#define MINIMUM_IPVS_VERSION_MINOR 1 +#define MINIMUM_IPVS_VERSION_PATCH 4 + +#ifndef IPVS_VERSION +#define IPVS_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) +#endif + +/* + * The default IPVS_SVC_PERSISTENT_TIMEOUT is a little larger than average + * connection time plus IPVS TCP FIN timeout (2*60 seconds). Because the + * connection template won't be released until its controlled connection + * entries are expired. + * If IPVS_SVC_PERSISTENT_TIMEOUT is too less, the template will expire + * soon and will be put in expire again and again, which causes additional + * overhead. If it is too large, the same will always visit the same + * server, which may make dynamic load imbalance worse. + */ +#define IPVS_SVC_PERSISTENT_TIMEOUT (6*60) + + +typedef struct ip_vs_service_user ipvs_service_t; +typedef struct ip_vs_dest_user ipvs_dest_t; +typedef struct ip_vs_timeout_user ipvs_timeout_t; +typedef struct ip_vs_daemon_user ipvs_daemon_t; +typedef struct ip_vs_service_entry ipvs_service_entry_t; +typedef struct ip_vs_dest_entry ipvs_dest_entry_t; + + +/* ipvs info variable */ +extern struct ip_vs_getinfo ipvs_info; + +/* init socket and get ipvs info */ +extern int ipvs_init(void); + +/* get ipvs info separately */ +extern int ipvs_getinfo(void); + +/* get the version number */ +extern unsigned int ipvs_version(void); + +/* flush all the rules */ +extern int ipvs_flush(void); + +/* add a virtual service */ +extern int ipvs_add_service(ipvs_service_t *svc); + +/* update a virtual service with new options */ +extern int ipvs_update_service(ipvs_service_t *svc); + +/* delete a virtual service */ +extern int ipvs_del_service(ipvs_service_t *svc); + +/* zero the counters of a service or all */ +extern int ipvs_zero_service(ipvs_service_t *svc); + +/* add a destination server into a service */ +extern int ipvs_add_dest(ipvs_service_t *svc, ipvs_dest_t *dest); + +/* update a destination server with new options */ +extern int ipvs_update_dest(ipvs_service_t *svc, ipvs_dest_t *dest); + +/* remove a destination server from a service */ +extern int ipvs_del_dest(ipvs_service_t *svc, ipvs_dest_t *dest); + +/* set timeout */ +extern int ipvs_set_timeout(ipvs_timeout_t *to); + +/* start a connection synchronizaiton daemon (master/backup) */ +extern int ipvs_start_daemon(ipvs_daemon_t *dm); + +/* stop a connection synchronizaiton daemon (master/backup) */ +extern int ipvs_stop_daemon(ipvs_daemon_t *dm); + + +/* get all the ipvs services */ +extern struct ip_vs_get_services *ipvs_get_services(void); + +/* sort the service entries */ +typedef int (*ipvs_service_cmp_t)(ipvs_service_entry_t *, + ipvs_service_entry_t *); +extern int ipvs_cmp_services(ipvs_service_entry_t *s1, + ipvs_service_entry_t *s2); +extern void ipvs_sort_services(struct ip_vs_get_services *s, + ipvs_service_cmp_t f); + +/* get the destination array of the specified service */ +extern struct ip_vs_get_dests *ipvs_get_dests(ipvs_service_entry_t *svc); + +/* sort the destination entries */ +typedef int (*ipvs_dest_cmp_t)(ipvs_dest_entry_t *, + ipvs_dest_entry_t *); +extern int ipvs_cmp_dests(ipvs_dest_entry_t *d1, + ipvs_dest_entry_t *d2); +extern void ipvs_sort_dests(struct ip_vs_get_dests *d, + ipvs_dest_cmp_t f); + +/* get an ipvs service entry */ +extern ipvs_service_entry_t * +ipvs_get_service(__u32 fwmark, __u16 af, __u16 protocol, union nf_inet_addr addr, __u16 port); + +/* get ipvs timeout */ +extern ipvs_timeout_t *ipvs_get_timeout(void); + +/* get ipvs daemon information */ +extern ipvs_daemon_t *ipvs_get_daemon(void); + +/* close the socket */ +extern void ipvs_close(void); + +extern const char *ipvs_strerror(int err); + +#endif /* _LIBIPVS_H */ |